Tagging version 1.7.1Beta2 of Ant, fixes license issues raised by Stefan

git-svn-id: https://svn.apache.org/repos/asf/ant/core/tags/ANT_170_B1@638185 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/trunk/CONTRIBUTORS b/trunk/CONTRIBUTORS
new file mode 100644
index 0000000..9ca02b1
--- /dev/null
+++ b/trunk/CONTRIBUTORS
@@ -0,0 +1,290 @@
+Amongst other, the following people contributed to ant:
+
+Aleksandr Ishutin
+Alexey Panchenko
+Alexey Solofnenko
+Andreas Ames
+Andreas Mross
+Andrew Everitt
+Andrey Urazov
+Andy Wood
+Anil K. Vijendran
+Anli Shundi
+Anthony Goubard
+Anthony Green
+Antoine Baudoux
+Antoine Levy-Lambert
+Anton Mazkovoi
+Arnaud Vandyck
+Arnout J. Kuiper
+Aslak Hellesôy
+Atsuhiko Yamanaka
+Avik Sengupta
+Balazs Fejes 2
+Benjamin Burgess
+Ben Galbraith
+Benoit Moussaud
+Bernd Dutkowski
+Brad Clark
+Brant Langer Gurganus
+Brian Deitte
+Brian Felder
+Bruce Atherton
+Cedomir Igaly
+Charles Hudak
+Charlie Hubbard
+Chris Povirk
+Christian Knorr
+Christoph Wilhelms
+Christophe Labouisse
+Christopher A. Longo
+Christopher Charlier
+Conor MacNeill
+Craeg Strong
+Craig Cottingham
+Craig R. McClanahan
+Craig Ryan
+Curtis White
+Cyrille Morvan
+D'Arcy Smith
+Dale Anson
+Dan Armbrust
+Daniel Ribagnac
+Daniel Spilker
+Danno Ferrin
+Davanum Srinivas
+Dave Brondsema
+Dave Brosius
+David A. Herman
+David Crossley
+David Gärtner
+David Kavanagh
+David Maclean
+David Rees
+Denis Hennessy
+Derek Slager
+Diane Holt
+dIon Gillard
+Dominique Devienne
+Donal Quinlan
+Don Brown
+Don Ferguson
+Don Jeffery
+Drew Sudell
+Edwin Woudt
+Eli Tucker
+Emmanuel Bourg
+Eric Olsen
+Eric Pugh
+Erik Hatcher
+Erik Langenbach
+Erik Meade
+Ernst de Haan
+Frank Harnack
+Frank Somers
+Frank Zeyda
+Frederic Bothamy
+Frederic Lavigne
+Gary S. Weaver
+Gautam Guliani
+Georges-Etienne Legendre
+Gero Vermaas
+Gerrit Riessen
+Glenn McAllister
+Glenn Twiggs
+Greg Nelson
+Harish Prabandham
+Haroon Rafique
+Hiroaki Nakamura
+Holger Engels
+Ignacio Coloma
+Ingenonsya France
+Ingmar Stein
+Irene Rusman
+Ivan Ivanov
+Jack J. Woehr
+James Duncan Davidson
+Jan Cumps
+Jan Matèrne
+Jan Mynarik
+Jason Hunter
+Jason Pettiss
+Jason Salter
+Jason Yip
+Jay Dickon Glanville
+Jay Peck
+Jay van der Meer
+JC Mann
+J D Glanville
+Jean-Francois Brousseau
+Jeff Gettle
+Jeff Martin
+Jeff Tulley
+Jeff Turner
+Jene Jasper
+Jeremy Mawson
+Jerome Lacoste
+Jesse Glick
+Jesse Stockall
+Jim Allers
+Joerg Wassmer
+John Sisson
+Jon Dickinson
+Jon S. Stevens
+Jose Alberto Fernandez
+Joseph Walton
+Josh Lucas
+Juerg Wanner
+Julian Simpson
+Justin Vallon
+Keiron Liddle
+Keith Visco
+Kevin Greiner
+Kevin Jackson
+Kevin Ross
+Kevin Z Grey
+Kirk Wylie
+Kyle Adams
+Larry Shatzer
+Larry Streepy
+Les Hughes
+Levi Cook
+lucas
+Ludovic Claude
+Maarten Coene
+Magesh Umasankar
+Maneesh Sahu
+Marcel Schutte
+Marcus Börger
+Mariusz Nowostawski
+Mark Hecker
+Mark R. Diggory
+Martijn Kruithof
+Martin Landers
+Martin Poeschl
+Martin van den Bemt
+Mathieu Champlon
+Mathieu Peltier
+Matt Albrecht
+Matt Benson
+Matt Bishop
+Matt Foemmel
+Matt Grosso
+Matt Humphrey
+Matt Small
+Matthew Hawthorne
+Matthew Inger
+Matthew Kuperus Heun
+Matthew Watson
+Michael Davey
+Michael J. Sikorsky
+Michael McCallum
+Michael Montuori
+Michael Newcomb
+Micheal Nygard
+Michael Saunders
+Miha
+Mike Roberts
+mnowostawski
+Nick Chalko
+Nick Fortescue
+Nick Crossley
+Nick Pellow
+Nicola Ken Barozzi
+Nico Seessle
+Nigel Magnay
+Oliver Merkel
+Oliver Rossmueller
+Oystein Gisnas
+Patrick C. Beard
+Patrick Chanezon
+Patrick G. Heck (Gus Heck)
+Patrick Martin
+Paul Austin
+Paul Christmann
+Paul Galbraith
+Paul King
+Paulo Gaspar
+Peter B. West
+Peter Donald
+Peter Doornbosch
+Peter Hulst
+Peter Reilly
+Phillip Wells
+Pierre Delisle
+Pierre Dittgen
+R Handerson
+Rami Ojares
+Randy Watler
+Raphael Pierquin
+Ray Waldin
+Richard Evans
+Rick Beton
+Robert Anderson
+Robert Shaw
+Robert Watkins
+Roberto Scaramuzzi
+Robin Green
+Rob Oxspring
+Rob van Oostrum
+Roger Vaughn
+Roman Ivashin
+Ronen Mashal
+Russell Gold
+Sam Ruby
+Scott Carlson
+Scott Ellsworth
+Scott M. Stirling
+Sean Egan
+Sean P. Kane
+Sebastien Arod
+Shiraz Kanga
+Sebastian Kantha
+Simon Law
+Stefan Bodewig
+Stefano Mazzocchi
+Stephan Strittmatter
+Stephane Bailliez
+stephan
+Stephan Michels
+Stephen Chin
+Stephen Goetze
+Steve Cohen
+Steve Loughran
+Steve Morin
+Steve Wadsworth
+Steven E. Newton
+Takashi Okamoto
+Taoufik Romdhane
+Tariq Master
+Trejkaz Xaoza
+Thomas Butz
+Thomas Christen
+Thomas Christensen
+Thomas Haas
+Thomas Quas
+Tim Drury
+Tim Fennell
+Timothy Gerard Endres
+Tim Stephenson
+Tom Ball
+Tom Brus
+Tom Cunningham
+Tom Dimock
+Tom Eugelink
+Ulrich Schmidt
+Victor Toni
+Waldek Herka
+Will Wang
+William Ferguson
+Wolf Siberski
+Wolfgang Baer
+Wolfgang Frech
+Wolfgang Werner
+Xavier Hanin
+Xavier Witdouck
+Yohann Roussel
+Yuji Yamano
+Yves Martin
+Zach Garner
+Zdenek Wagner
diff --git a/trunk/INSTALL b/trunk/INSTALL
new file mode 100644
index 0000000..83c1167
--- /dev/null
+++ b/trunk/INSTALL
@@ -0,0 +1,2 @@
+For installation instructions see the manual in the docs subdirectory
+or online at <http://ant.apache.org/manual/index.html>.
diff --git a/trunk/KEYS b/trunk/KEYS
new file mode 100644
index 0000000..a008750
--- /dev/null
+++ b/trunk/KEYS
@@ -0,0 +1,921 @@
+This file contains the PGP keys of various developers.
+
+Users: pgp < KEYS
+       gpg --import KEYS
+Developers: 
+        pgp -kxa <your name> and append it to this file.
+        (pgpk -ll <your name> && pgpk -xa <your name>) >> this file.
+        (gpg --list-sigs <your name>
+             && gpg --armor --export <your name>) >> this file.
+
+Type Bits/KeyID    Date       User ID
+pub  1024/FEECAAED 1998/11/11 Stefan Bodewig <bodewig@bost.de>
+                              Stefan Bodewig <bodewig@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: 2.6.3i
+
+mQCNAzZJoiMAAAEEAMzhUxTOC20Nprp6K4nLTiARt+EXii/dovNWWcfzZcYXi/lX
+r3zpUTTZxlKQpd4RaHjFmGgoOraZE4jCRFARVcFJgYmGUKpcWJZO7YKL36WUizTM
++dyB2ycOtzlty1W5VmRL3FGqo67pKA9F/QHg3NSu9hY1W9xPPK7Kq3f+7KrtAAUR
+tCBTdGVmYW4gQm9kZXdpZyA8Ym9kZXdpZ0Bib3N0LmRlPokAlQIFEDZSrGXHcgyK
+jiW9zQEBshEEAMlG4qVjKp4/agdJG56M6izx9oaKecFLXHQJrFUy3w2PvZHFYtXc
+osXKorX6bPrE8uB57MxbY2WapKeVRodlG0+j39vAf501duK8q2rktfWt9Cl4JjJ4
+DbWhSWfV1ci62u2gCxwYQe22F9Wh+vhOR5NK9RTbSKhupdlFsnrk/i7xiQCVAwUQ
+NkmiI67Kq3f+7KrtAQGdxQQAlcFOzSv7G6M4uGbgvw7IGgrhx7rawtIyv9hLXgVC
+7ua9xaZV8G0Fl9gh8RnbdcZ4R/aT+KIiAFaslfZ3t6hlC4MTbnAJqvdS/NO98ZkJ
+YvnzZSKHflAbd5gyE7IVxBC9/xRlF/Wls5sYNwb6RjoRCaOjxN/y3WCLa3Va101v
+zNy0I1N0ZWZhbiBCb2Rld2lnIDxib2Rld2lnQGFwYWNoZS5vcmc+iQCVAwUQOxIo
+BK7Kq3f+7KrtAQGn6gP/SBACdHakA4H//otpyESSrk4PmyOaYF0Kyok43Gee2mT+
+m9+jZ3jLcC0oav6iH+otL/lhk9t/JDM8LjD2kAkdWWoIvvuPyCx97gOzojIo0Ve2
+1wuxJTF/VIjwyOtE8FzE7p4tkc6EubVpeZkV9Pq9HFRBCUcyKJDLnF4tbstScLU=
+=OBLe
+-----END PGP PUBLIC KEY BLOCK-----
+
+
+pub  1024D/51898504 2001-05-29 Conor MacNeill <conor@cortexebusiness.com.au>
+sig 3       51898504 2001-05-29   Conor MacNeill <conor@cortexebusiness.com.au>
+sig         5F6B8B72 2002-01-11   Stefan Bodewig <bodewig@apache.org>
+uid                            Conor MacNeill <conor@apache.org>
+sig 3       51898504 2001-05-29   Conor MacNeill <conor@cortexebusiness.com.au>
+sig         5F6B8B72 2002-01-11   Stefan Bodewig <bodewig@apache.org>
+sub  1024g/D1ECBA5D 2001-05-29
+sig         51898504 2001-05-29   Conor MacNeill <conor@cortexebusiness.com.au>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.0 (GNU/Linux)
+
+mQGiBDsTqygRBACiZckNdclTlQFonLaIKBFGhMy0KKByw0x8XA4iwdbCXuF6xNIc
+HIFHajJ74AHchQ4d8xtomBy6b8yvFgWVeaZensvn69BlLeqGdyeJRzfPt6TgRnzZ
+2eWhb0HXdG3JwxL/2BabDhHfs4YJOrgB/vhRFQku6oCMRiBPtJj2werD6wCg0/zp
+jacYTw6+CR+sVvneCNyySFED/R3j10c4RnR8djgv1jKT8CKPuHYraupI9INEe+I6
+7qWjtJ02GzvMO6TElAtUsf4aysu45GgwkwEBnuG6mYb3Pq0V2c5tJc2A3Tj3DrdR
+i3HUNwurbus76I0sPyyENPu12QPeC6mvWLEsxVJ9o0hRKFayGvYUmrwWK9UFLjvp
+p9cXBACDHgLn7MAVLqUdYhRrUj/M+GOUpvBikEgoJJrEUmb5X4+++dffMh5HBIO4
+5LA11qEKuM2xnKqOilP7NLYXz1Fe0ocqv0jsHB4SprFTTai7ma31uwuRQvCQXVv1
+yJ5CLqYda64h/UA2kmmR2dfopmvDogYEMz/HU5voozxe7BEI7bQhQ29ub3IgTWFj
+TmVpbGwgPGNvbm9yQGFwYWNoZS5vcmc+iFcEExECABcFAjsTqygFCwcKAwQDFQMC
+AxYCAQIXgAAKCRCBBGRPUYmFBDgIAKCZztXqKhK6kXOnoGy7opCNmWU0lwCgsPDa
+4m+ruW3ch0rfbqtR75S52R+IRgQQEQIABgUCPD6eTgAKCRCiEVrhX2uLcqCcAKCr
+1Wylqju9YjBi5Twej9ze69JFBQCeOaMgo6yjnkcV3PnVInLlaMwPr5q0LUNvbm9y
+IE1hY05laWxsIDxjb25vckBjb3J0ZXhlYnVzaW5lc3MuY29tLmF1PohXBBMRAgAX
+BQI7E6xMBQsHCgMEAxUDAgMWAgECF4AACgkQgQRkT1GJhQTY0ACgmZmKheHzjPJs
+5hybpyvnvEiPYqYAn2+ryxdtz8XyOMExGRmHNlhG7svsiEYEEBECAAYFAjw+nlUA
+CgkQohFa4V9ri3JYYACg1WN+NCptfKVP1mbrIa+0ajztsiIAnAn+m70iwRRFZCxr
+jcULoY5SjyTLuQENBDsTqy0QBACfsCxJ6iCtgX8zjlVtMsMfDqu72x5sYatWKn8c
+u+4Oj5mi0x6azZIhwCa+K3ihLVOyG1mCRnzztGTIxWYRhq3TESIVOfgm+NgLGrmA
+XUTFyCT+21TExLCpuVZKmUHsWXLxDtfQ1diPeQpiQ8+Fvb/4jLGFjFIrQ2VjtFQn
+kumkSwADBgP9H0bF4hdMuVEcSJ9imxSoJshcOOA3Vd2+YiCTZhBygWM49wY5jNos
+/DArIjNCE53IlOu/UtHB2jqkSqjF0soGYsUjeCWouiTP9hLuMKPjnqj9ryJPTDKz
+nTCZ4TuB5CtzrKTlWLmPCPpFsGqe4KjMeKg/mqGqjPKl97xgStK9N9GIRgQYEQIA
+BgUCOxOrLQAKCRCBBGRPUYmFBMM6AJsF3FFyZGEmbt9aGG1W/u0oI9mcLgCfQyJ+
+aalbspazea4J9zgi59SSwOM=
+=cBdR
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024R/697ECEDD 2000-04-06 Henri Gomez <hgomez@slib.fr>
+sig         697ECEDD 2000-04-06   Henri Gomez <hgomez@slib.fr>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.0 (GNU/Linux)
+
+mQCNAzjsydwAAAEEAMpwFU/ci3/wR3ryCGp9Exr+Rx/hTQ7hWAJcVw8ejlBXlT4T
+yITlRUs0HGfRWxME2J55PuXXsIEPZzjfozNtvOyq8WlLlJ7iaiyWxVRoPJ25sSEj
+C9etm6wjj4E66ZgzuElZkm1m69uEsCHPPNuz1oQ/g1O+SmIVxIYirlxpfs7dAAUR
+tBxIZW5yaSBHb21leiA8aGdvbWV6QHNsaWIuZnI+iQCVAwUQOOzJ3IYirlxpfs7d
+AQFQyQQAj0D9G0hEL7SQGaSCkkoXwvamQw42N8+tNm+jfWHWdE4HAiVlhJmI2GyD
+sdcXVAcR8R7ILIRB5AY7a3bF+qMk0r+vO6oR878RKKn9AvtaAIOnrh6tr0tiPwf5
+XDUMySxIWJEF3SmJAy9Lq3bAl5GMzZCFHiS0NW2gtWgmr/u1RuM=
+=6l+I
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024R/397DCAD5 2002-07-03 Henri Gomez <hgomez@users.sourceforge.net>
+sig         397DCAD5 2002-07-03   Henri Gomez <hgomez@users.sourceforge.net>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.0 (GNU/Linux)
+
+mQCNAz0i0UUAAAEEALXePN6IHne0W96YRMnR+4EXB6402QY5f8ZLcnSUZUH55Fb1
+qcZGBc3WRKlPiUvwBD+eVYgCpNSXF/H+oV1mawxNJN5XwqBEpfYmY8MRIPcqa61h
+bJc3LBSm1qNf05G5Cwxeed+OgVm0r1HBy6DAgDHAqNlkC8DZ/BVgqMA5fcrVAAUR
+tCpIZW5yaSBHb21leiA8aGdvbWV6QHVzZXJzLnNvdXJjZWZvcmdlLm5ldD6JAJUD
+BRA9ItFFFWCowDl9ytUBASNyA/458T84LUVhqq6Y9fPBAfcFMWY2kehuDWsQEXkO
+46XoK+AnFZCkKuyDLqPHchVUO5pK/gZYsDK/xJkfh3u4FTDTsecb9wFmIeyayVIN
+SI8o6l8EZzDX/PGwqEwzxHrbQkIgIktNn5ApIoazvdBpbkQfNj1vr2wWoMYPLAWM
+8xzecA==
+=UmZ8
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/307A10A5 2002-07-18 Henri Gomez <hgomez@users.sourceforge.net>
+sig 3       307A10A5 2002-07-18   Henri Gomez <hgomez@users.sourceforge.net>
+sub  2048g/862B8F70 2002-07-18
+sig         307A10A5 2002-07-18   Henri Gomez <hgomez@users.sourceforge.net>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.0 (GNU/Linux)
+
+mQGiBD02vbERBAC1v8fR6gjERpaz4UMfdy0hRVWCPSbOdF+Swm/IenjVzErco6zb
+MTa13umUNrDPBy/tTWiCCZrOnqi7fgDzWqPEqrXJjKAFVLEWE6MmKylPPEPG1/bm
+idkNGERSAZduvhKv777PzvEJJ/8eGe3wy/O8NbgIjCPtr4UklwCZS8cFuwCg8oMO
+UdT8qZRtzdxdAyu1m5fUb+MD/3IKJYWXsdtb6iBphCU4f/BoyjVC9EZJ1ywLuiVM
+siKbuaDUaXU9nWcbNKv+fx8uZ1NaadpfLokqqhnWcpnSiqw8HNR7SwsF1D33rkXK
+O4FSuVss/tIoqGdWFcJyPkP4yP5shxqR335narVw2vDa0+BiWkALbA2qVsSIdZDB
+LeFZA/47AMBS0U2BRk2rQT8LmMuFl7mR+wNBM4n7FUGdxsGn3TcYd4pXTNrEQPrV
+YNdooKlikgGk4hgFnIFX09Spmimqgq0goFue81rttVdZZ4uep8dTghY6gwmvcOxX
+jATbhWStBhdu9B35kzfHc+1QihD5Z94u4uyWIVBIzikcdiY8LbQqSGVucmkgR29t
+ZXogPGhnb21lekB1c2Vycy5zb3VyY2Vmb3JnZS5uZXQ+iFcEExECABcFAj02vbEF
+CwcKAwQDFQMCAxYCAQIXgAAKCRAZMdaEMHoQpYijAKCCP68ndU/kTXR9XAKLvibC
+3S8+1QCfUFQYte3Jo+MHKaWjsu9JGptRzo+5Ag0EPTa93RAIAKlsRJ5gOGTFsmaR
+W9k6MIh4c/MCy7J7HUxT5xTdHROa+3zUh+FAE/JaOx9ZtZtH863DFHA8cP4L+tpi
+PjBT6g2E94dwGcuH/OiSSCT4JSBukbGbOuLLdmFXqUl8+4gsL90Xal67FtNLwyLG
+1n7geLir0byD+OT7VLA5w+6G0NOpJEveV/FIa2qLgdRZ8vz73ybgMh18hBUrUmro
+jncp0rln2VU7VCH1C2aClKm7kK4mGAjIFIzKbguK+kM3b8NDHmXKpT6syyCtIM3h
+prkV1TUCAFqLI32aSdlTN79lpeA2zDga9k4/4X/RDHsFpRN2neRFGTNUtuUgYpQQ
+E5zWBmMAAwUH/RiGxyeBsad923IwE1+GAjxFl2tqF9xWk0J6yTnSK4nfhYAE9evV
+jwDEok9jRl4ILCcXx6YN/d/lWNuSbARKHz/3hLiTouPpwd3SSJ8is2x9PgpJz5JX
+cD0y1SkbPLvs3jH3ZmdcxZpuAmJeI/typqFKK5pWP44oXIH+XH/8nWDtmLEBkgKQ
+/ATQWenMTmZ6MIJ6aWKWGkO9QS6iYRz3PPPGQ1O8W02CeprM2wBtlb8J1Z3RxNhM
+rZcg/1Qi3V3D1HI4zw6tAFmDeBb8J4PaBQzqlhzx2EBTbfwNPhV8AlPvpxHEeGGn
+v+O1yhZr33SnyZdINNoNDn+owVMdmkobe9GIRgQYEQIABgUCPTa93QAKCRAZMdaE
+MHoQpRsTAJ4qst3MhLm48fBAEnzuzi/BIKr+AgCfYaCB/AvPoncQbHc8BcNGRimR
+P9A=
+=hQhz
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/EDF62C35 2002-04-10 Magesh Umasankar <umagesh@apache.org>
+sig 3       EDF62C35 2002-04-10   Magesh Umasankar <umagesh@apache.org>
+sig 3       5F6B8B72 2003-03-07   Stefan Bodewig <bodewig@apache.org>
+sub  1024g/B5FFC53F 2002-04-10
+sig         EDF62C35 2002-04-10   Magesh Umasankar <umagesh@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.0 (GNU/Linux)
+
+mQGiBDy0ebgRBADuKIKD8PuJ4wKEV1h2AprwJjxCRx8vn48XNwfLZuvhw8cpArtK
+rZwhoGPPUPEEXgtTNerlKq4VwpAwcnvRz7oC/7aWkUbcR2sAyhfe2scohwPgw7Xv
++isWC0NDPdrxvXG/PUOG/cnELunr51ymybBqBxUd2gMhYIxPo67D+YPYLwCgwcZp
+yc/6kJa116ESWHrti342GD8D/1srpnRs9CiS1DQF1uZ1wW4vzj4VD61tKsjdWD8D
+V573R22iMDLSj4oMB536WxUH7snz8XsAKm/peqJ6G9m0smtmWA1ago5yzQj70WqF
+xzWBhHn2I/YfAQ8pb2s9q1lClj8elnCxT65L27ydBAZteejb2VqjtQ6iGy86PUT2
+wRUvBADZmoV1eIZJEM5NnxBv1EtvRYZtIQEzZ8dO2A1LOS7qlVr8IypljNPLGhzX
+VHNvVsjC9QMUSWeBsDedvQHQ3hJpIMnTI32XE1V4gX06gfVTZdhf2fLTtwnsHZp0
+oumqshGDVRhNJJdDYLikxWOxOfkNveKEqJFvtuBR+ZqqluQKebQlTWFnZXNoIFVt
+YXNhbmthciA8dW1hZ2VzaEBhcGFjaGUub3JnPohXBBMRAgAXBQI8tHm4BQsHCgME
+AxUDAgMWAgECF4AACgkQ76Pnee32LDWSRwCfeASWXvpdt7bSFPMtszU/7uPEktsA
+n23mYUN5WKJA1ZreW+0CcZ2ESnOviEYEExECAAYFAj5ogYgACgkQohFa4V9ri3IW
+YACgsxGig0PL0M86rJsA/IpXjBdg3ysAoJzsoUZ/7s2BxDfzF/FRTVIzS+TMuQEN
+BDy0eb8QBACBVb9YDJRp9Irzmq71Jf9FIPw+4g/cWpF3t/Eb7eSzMcOvTAXyNIWz
+aaOjHre7lFctHfq8ls/6gR7uqajiAnfQcfTcu7pp+F5KsU0Embt83SFzZ3aoJwET
+mB/LqUyrrGDiue3lU+flJO7UmcsRvtk0+BDkyCeB9HgfdpXbBLCyuwADBQP+PNxX
+4e1tg3ZJo/xNEnD2Re3HjmQRrr0RYJLUGjgQrAEONSgowx3IW8/JssmNJVjnYm0q
+jSKsb8rergCFJhPNZ8Dd/k00pKcrq+IN6j7WTYLqPce87zrGAZUtmDwDSp5mxy5E
+xWJJxsgBPk4YBQLzJt21A3BgK/i24Sze2VLbaZuIRgQYEQIABgUCPLR5vwAKCRDv
+o+d57fYsNa8xAJ4mLfonZbd64+YY9rfvhIh3Vsl3AACeLPPKtma2K6XCfhTBEDnj
+hzSr4vo=
+=lBfF
+-----END PGP PUBLIC KEY BLOCK-----
+pub  1024D/265B4C63 2003-08-18 Antoine Levy-Lambert (Apache Ant Committer) <antoine@apache.org>
+sig 3       265B4C63 2003-12-06   Antoine Levy-Lambert (Apache Ant Committer) <antoine@apache.org>
+sig 3       5F6B8B72 2003-12-12   Stefan Bodewig <bodewig@apache.org>
+uid                            Antoine Levy-Lambert (Apache Ant Committer) <antoine@antbuild.com>
+sig 3       265B4C63 2003-08-18   Antoine Levy-Lambert (Apache Ant Committer) <antoine@apache.org>
+sig 3       5F6B8B72 2003-12-12   Stefan Bodewig <bodewig@apache.org>
+sub  1024g/A3060393 2003-08-18
+sig         265B4C63 2003-08-18   Antoine Levy-Lambert (Apache Ant Committer) <antoine@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.2 (MingW32)
+
+mQGiBD9AzmcRBACMqgb7IFvC/nLxw7mUAgHENeZXY3JOQJ8wVBevIbbMEeFvzHE2
+diFydqUXocPexduYr0ahkf033WvWdAiNqDLfVW/HFOsc1TpjbHkqPUHtJ62Ya5tg
+nH4UGN9BYZfMbfVDOSz41lYwmfK5HYgpZN/sBQBSKf2qgoFB+LxYaae8YwCgrWlu
+fYhf7fkKbbdSf3BGS67ggNkD/0VvkXkw1SEnPaqrkKGkPKomCTb2auGxcYYI3/rP
+1m+SGRf0gE1NtocmIEitiR6WvfKUjoMAXSCp5KdnUXmO9rwzkM002KCA7K5CY+e/
+2bLDuiQ3rNiD4mFfG6M+UnmZ+GMFba1p9Cp4PqLNLsCHz67t7hEsscTZQ8mZ9xKM
++GCsA/9P+XFM7JDn9MLhYab9qo1CkceBkthUP6jWGjuAZ00elmBCkpkzNv5aIzss
+xih2GpaU/tmcMjw8FGp0dTwzqdpmbZBLjunRnuBTir4m4l5G9rwl4JbfK1PVqk4a
+VKkh9W7/yqBcEfNcsfJO9cqaQ+PzcnCoDiD9UHEBYzUhrCKwhLRCQW50b2luZSBM
+ZXZ5LUxhbWJlcnQgKEFwYWNoZSBBbnQgQ29tbWl0dGVyKSA8YW50b2luZUBhbnRi
+dWlsZC5jb20+iFsEExECABsFAj9AzmcGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQ
+hhTWqyZbTGMnOgCeJV2gI+1CIxMR7dcIhXjPkiusreIAn2SGOsPS0o89l0EIVuc9
+J2F03aB+iEYEExECAAYFAj/ZwioACgkQohFa4V9ri3J8CACgiGlh+td0BAnJPq19
+ovEQR2DJ02MAoLP203EF+BLPpykeTcGp8UEWmeGQtEBBbnRvaW5lIExldnktTGFt
+YmVydCAoQXBhY2hlIEFudCBDb21taXR0ZXIpIDxhbnRvaW5lQGFwYWNoZS5vcmc+
+iF4EExECAB4FAj/SSwYCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQhhTWqyZb
+TGOh/QCfbrSoipMlizyGT6c8BOPEd9zzfi0AnRRTqTDzXzsGk4CG/BJME9CCm7Ts
+iEYEExECAAYFAj/ZwiMACgkQohFa4V9ri3IOVACgh2QHS1+cVjvM4eLjls1bJwWi
+o5IAoLtAszHrwHS5qrhvr2rtnlyyyV2guQENBD9AzmkQBACNpBfqi2PweozCtxoX
+PqzKdRDKqCw7TOrDR6lbP3z/ov/1SN5Vc0XqNzBSGqwBcmGWtneABkX7n4uzJrC5
+wvX/TZ/DkMvypPyeNVMu+/ZMlzdbx06OUDKr6Fy/NtaI7cN1rw+Igyv22Q8ilhhg
+s/5Rdj84EtJkWQjVRml6wXSAZwADBwP/TqyhOC4sA5YrePYGH8i46h0SU9dXjfEF
+JijC8vXZ+BNQHQVK3fjEXedZL8Zvvp1bsMu7Muz9SMnqygM1unp2NGxLRd/9315p
+Qh0VStYKn0xq13ybOKr0Gsyx5yyl3Nzlu/1qAR0es/zN4jV7/IQi3R2GOvezcpHX
+mkbsYiZAhu2IRgQYEQIABgUCP0DOaQAKCRCGFNarJltMYxcsAKCSJJUABlXYnLBj
+b+WtmAzu0JjZNACdFJ4KIATJDK/5ajFq5+irOpodoHc=
+=UomR
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub   1024D/5F6B8B72 2001-05-28
+uid                  Stefan Bodewig <bodewig@apache.org>
+sig 3        5F6B8B72 2001-05-28  Stefan Bodewig <bodewig@apache.org>
+sig          51898504 2002-01-11  Conor MacNeill <conor@codefeed.com>
+sig 3        F88341D9 2003-03-17  Lars Eilebrecht <lars@eilebrecht.org>
+sig 3        2261D073 2003-03-17  Astrid Kessler (Kess) <kess@kess-net.de>
+sig          21D0A71B 2003-03-17  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig          75A67692 2003-03-18  Erik Abele <erik@codefaktor.de>
+sig          B3B2A12C 2003-05-20  ct magazine CERTIFICATE <pgpCA@ct.heise.de>
+sig 3        8103A37E 2003-04-04  Andre Malo <nd@apache.org>
+sig 3        5F6B8B72 2001-05-28  Stefan Bodewig <bodewig@apache.org>
+sig          D6298F01 2003-04-27  Paulo Henrique Gaspar Jorge <pjorge@asatnet.com.br>
+sig          0CAA68B4 2004-11-11  Patrick Rentsch <patrick.rentsch@suissimage.ch>
+sig          2FE28BCF 2005-07-01  Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
+sig          5793498F 2005-07-21  Tim Ellison <tim@ellison.name>
+sig          E4136392 2005-07-21  Noel J. Bergman <noel@apache.org>
+sig          8408F755 2005-07-21  Christian Geisert <chrisg@apache.org>
+sig 2        FC243F3C 2005-07-20  Henk P. Penning <penning@cs.uu.nl>
+sig 3        EC140B81 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        EE65E321 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        A99F75DD 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        3642CB4B 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        302DA568 2005-07-21  Rodent of Unusual Size (DSA) <coar@Apache.Org>
+sig 3        2C312D2F 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        CC78C893 2005-07-22  Rich Bowen <rbowen@rcbowen.com>
+sig 3        E2D774DF 2005-07-22  Sylvain Wallez <sylvain@apache.org>
+sig 3        E04F9A89 2005-07-22  Roy T. Fielding <fielding@gbiv.com>
+sig 3        015AFC8A 2005-07-22  Bertrand Delacretaz <bdelacretaz@apache.org>
+sig 3        87315C31 2005-07-23  Raphaël Luta <raphael.luta@aptiwan.com>
+sig 3        E41EDC7E 2005-07-24  Carsten Ziegeler <cziegeler@apache.org>
+sig 3        F39B3750 2005-07-24  Colm MacCarthaigh <colm@stdlib.net>
+sig          1CD4861F 2005-07-25  Eran Chinthaka <chinthaka@apache.org>
+sig          EA1BA38D 2005-07-25  Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
+sig          333E4E84 2005-07-26  Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
+sig          152924AF 2005-07-29  Sander Temme <sander@temme.net>
+sig 3        9C85222B 2005-07-24  Henning Schmiedehausen <hps@intermeta.de>
+sig 3        9978AF86 2005-07-25  [User ID not found]
+sig 3        2A623F72 2005-07-25  [User ID not found]
+sig 3        F8EA2967 2005-07-26  [User ID not found]
+sig 3        C152431A 2005-07-27  Steve Loughran <stevel@apache.org>
+sig          DE885DD3 2005-11-25  Sander Striker <striker@apache.org>
+sig          CE419C8F 2007-01-05  Upayavira <upayavira@odoko.co.uk>
+sig          E222DE4F 2007-05-02  Mathias Herberts <Mathias.Herberts@iroise.net>
+sig          911203E4 2007-05-02  [User ID not found]
+sig          F12F6072 2007-05-05  [User ID not found]
+sig 3        990ED4AA 2007-05-02  Knut Anders Hatlen <kahatlen@apache.org>
+sig 3        311A3DE5 2007-05-05  Ruediger Pluem <rpluem@apache.org>
+sig 3        88817402 2007-05-06  Thomas Vandahl <thomas@vandahl.org>
+sig          5F298824 2007-05-06  Simon Pepping <spepping@leverkruid.eu>
+sig          4CEED75F 2007-05-06  Nick Burch <nick@gagravarr.org>
+sig          4358C584 2007-05-06  Vincent Hennebert <vhennebert@apache.org>
+sig          0B7E6CFA 2007-05-06  Sami Siren <siren@apache.org>
+sig        3 01530235 2007-05-02  Luc Maisonobe (SpaceRoots) <luc@spaceroots.org>
+sig          40581837 2007-05-08  Nick Kew <nick@webthing.com>
+uid                  Stefan Bodewig <stefan.bodewig@freenet.de>
+sig 3        5F6B8B72 2003-03-07  Stefan Bodewig <bodewig@apache.org>
+sig 3        F88341D9 2003-03-17  Lars Eilebrecht <lars@eilebrecht.org>
+sig 3        2261D073 2003-03-17  Astrid Kessler (Kess) <kess@kess-net.de>
+sig          21D0A71B 2003-03-17  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig          75A67692 2003-03-18  Erik Abele <erik@codefaktor.de>
+sig          B3B2A12C 2003-05-20  ct magazine CERTIFICATE <pgpCA@ct.heise.de>
+sig 3        8103A37E 2003-04-04  Andre Malo <nd@apache.org>
+sig          51898504 2005-06-21  Conor MacNeill <conor@codefeed.com>
+sig          0CAA68B4 2004-11-11  Patrick Rentsch <patrick.rentsch@suissimage.ch>
+sig          2FE28BCF 2005-07-01  Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
+sig          5793498F 2005-07-21  Tim Ellison <tim@ellison.name>
+sig          8408F755 2005-07-21  Christian Geisert <chrisg@apache.org>
+sig 3        EC140B81 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        EE65E321 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        A99F75DD 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        3642CB4B 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        302DA568 2005-07-21  Rodent of Unusual Size (DSA) <coar@Apache.Org>
+sig 3        2C312D2F 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        CC78C893 2005-07-22  Rich Bowen <rbowen@rcbowen.com>
+sig 3        E2D774DF 2005-07-22  Sylvain Wallez <sylvain@apache.org>
+sig 3        E04F9A89 2005-07-22  Roy T. Fielding <fielding@gbiv.com>
+sig 3        87315C31 2005-07-23  Raphaël Luta <raphael.luta@aptiwan.com>
+sig 3        E41EDC7E 2005-07-24  Carsten Ziegeler <cziegeler@apache.org>
+sig 3        F39B3750 2005-07-24  Colm MacCarthaigh <colm@stdlib.net>
+sig          1CD4861F 2005-07-25  Eran Chinthaka <chinthaka@apache.org>
+sig          EA1BA38D 2005-07-25  Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
+sig          333E4E84 2005-07-26  Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
+sig          152924AF 2005-07-29  Sander Temme <sander@temme.net>
+sig 3        9C85222B 2005-07-24  Henning Schmiedehausen <hps@intermeta.de>
+sig 3        9978AF86 2005-07-25  [User ID not found]
+sig 3        2A623F72 2005-07-25  [User ID not found]
+sig 3        F8EA2967 2005-07-26  [User ID not found]
+sig 3        C152431A 2005-07-27  Steve Loughran <stevel@apache.org>
+sig          DE885DD3 2005-11-25  Sander Striker <striker@apache.org>
+sig          E222DE4F 2007-05-02  Mathias Herberts <Mathias.Herberts@iroise.net>
+sig          911203E4 2007-05-02  [User ID not found]
+sig          F12F6072 2007-05-05  [User ID not found]
+sig 3        990ED4AA 2007-05-02  Knut Anders Hatlen <kahatlen@apache.org>
+sig 3        311A3DE5 2007-05-05  Ruediger Pluem <rpluem@apache.org>
+sig 3        88817402 2007-05-06  Thomas Vandahl <thomas@vandahl.org>
+sig          4CEED75F 2007-05-06  Nick Burch <nick@gagravarr.org>
+sig          4358C584 2007-05-06  Vincent Hennebert <vhennebert@apache.org>
+sig          0B7E6CFA 2007-05-06  Sami Siren <siren@apache.org>
+sig 3        DE8884A0 2007-05-07  Xavier Hanin <xavier.hanin@gmail.com>
+sig        3 01530235 2007-05-02  Luc Maisonobe (SpaceRoots) <luc@spaceroots.org>
+sig          40581837 2007-05-08  Nick Kew <nick@webthing.com>
+uid                  Stefan Bodewig <stefan@samaflost.de>
+sig 3        5F6B8B72 2005-05-31  Stefan Bodewig <bodewig@apache.org>
+sig          51898504 2005-06-21  Conor MacNeill <conor@codefeed.com>
+sig          2FE28BCF 2005-07-01  Harald Wilhelm (HAWI) <Harald.Wilhelm@hawi.de>
+sig          5793498F 2005-07-21  Tim Ellison <tim@ellison.name>
+sig 3        EC140B81 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        EE65E321 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        A99F75DD 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        21D0A71B 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        3642CB4B 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        302DA568 2005-07-21  Rodent of Unusual Size (DSA) <coar@Apache.Org>
+sig 3        2C312D2F 2005-07-21  Rodent of Unusual Size <coar@php.net>
+sig 3        CC78C893 2005-07-22  Rich Bowen <rbowen@rcbowen.com>
+sig 3        E2D774DF 2005-07-22  Sylvain Wallez <sylvain@apache.org>
+sig 3        E04F9A89 2005-07-22  Roy T. Fielding <fielding@gbiv.com>
+sig 3        87315C31 2005-07-23  Raphaël Luta <raphael.luta@aptiwan.com>
+sig 3        E41EDC7E 2005-07-24  Carsten Ziegeler <cziegeler@apache.org>
+sig 3        F39B3750 2005-07-24  Colm MacCarthaigh <colm@stdlib.net>
+sig          1CD4861F 2005-07-25  Eran Chinthaka <chinthaka@apache.org>
+sig          EA1BA38D 2005-07-25  Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
+sig          333E4E84 2005-07-26  Chathura Kamalanath Herath (Apachecon Europe 2005) <chathura@apache.org>
+sig          152924AF 2005-07-29  Sander Temme <sander@temme.net>
+sig 3        9C85222B 2005-07-24  Henning Schmiedehausen <hps@intermeta.de>
+sig 3        9978AF86 2005-07-25  [User ID not found]
+sig 3        2A623F72 2005-07-25  [User ID not found]
+sig 3        F8EA2967 2005-07-26  [User ID not found]
+sig 3        C152431A 2005-07-27  Steve Loughran <stevel@apache.org>
+sig          DE885DD3 2005-11-25  Sander Striker <striker@apache.org>
+sig          E222DE4F 2007-05-02  Mathias Herberts <Mathias.Herberts@iroise.net>
+sig          911203E4 2007-05-02  [User ID not found]
+sig          F12F6072 2007-05-05  [User ID not found]
+sig 3        990ED4AA 2007-05-02  Knut Anders Hatlen <kahatlen@apache.org>
+sig 3        311A3DE5 2007-05-05  Ruediger Pluem <rpluem@apache.org>
+sig 3        88817402 2007-05-06  Thomas Vandahl <thomas@vandahl.org>
+sig          4CEED75F 2007-05-06  Nick Burch <nick@gagravarr.org>
+sig          4358C584 2007-05-06  Vincent Hennebert <vhennebert@apache.org>
+sig          0B7E6CFA 2007-05-06  Sami Siren <siren@apache.org>
+sig        3 01530235 2007-05-02  Luc Maisonobe (SpaceRoots) <luc@spaceroots.org>
+sig          40581837 2007-05-08  Nick Kew <nick@webthing.com>
+sub   1024g/24774157 2001-05-28
+sig          5F6B8B72 2001-05-28  Stefan Bodewig <bodewig@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.2 (GNU/Linux)
+
+mQGiBDsSIk4RBADSCj6rUjV64tYCGT1DYKYR7GthyWpNdGHSYLbETBcDatAe1dzQ
+5NsCgfrlybfyeY+y1lxr3T9bqf6zJWDw/718wff96qmmv1qzexSYtmIrj+h53V82
+EXwWOFuYMJisuxdT940iQzosm3GOv4MJdEg3oI2SgfEyRQQ6vO4Ob5rHDwCg5taZ
+nrHOrXx2dIGHxpxRZ0SUl30D/jmtttFjYOQ3LBMriikz5mh2sK3ZnoSRF4o5O0zW
+Ve6e2SFXOEjVjImKsH6KCbdQNelrAdgiyOoXClyQKsQ27pncbdWo6bO0E3POJZVm
+XaeW7iudHVr63rU5PViXObIQrdQl0D59j5brKj4vdlTyUw8kaHPvbKPDEOwvZq4Y
+LJQ5BACA1YilTeXRJqwFsNlpcxCHwlULD4QUVP496prQWf1B7Z6g0KvLGrQsO0Vn
+Jcn+fEqukysTJixSXCPebosltd4RalJIupVYkp4w6MJ7biaDAlLuNhDcI/AiXTmV
+dXUedVXIaM8I3Ne23gucwbAyc0Hvb+3cSAKRhl/azFQhuHBvlrQjU3RlZmFuIEJv
+ZGV3aWcgPGJvZGV3aWdAYXBhY2hlLm9yZz6IYgQTEQIAGgULBwoDBAMVAwIDFgIB
+AheAAhkBBQI7EiJPABIHZUdQRwABAQkQohFa4V9ri3KPOACfdr6cV41veYBlBHiV
+FxfLcX7x5OEAniK4u3g2jpNQH3E0ROubdj/RO+RTiEYEEBECAAYFAjw+1Y8ACgkQ
+gQRkT1GJhQSdkgCeM6RDHUF/E334TtiLPgw7GpmNJSkAoNCLQCW/9VHrV+ZHsodn
+XUnaD4dIiJkEEwECAAYFAj513wwACgkQPo+38viDQdknZAPlHNiMnR+LUavo2yOY
+iJT+W9+8+qNs2grYDZ+WSYujaWT2NJrUCYXQRM6gKDyFlkcJvHI9lF2yYMkVetll
+ZVN1TJkeEdtbHncNHcdq+ZUQR0NkFKTF9d1K7UI2rfWxt1y6a13TcUjpJXzbtw/O
+XX9EZSI6QQt4rSFlvci9J3mIRgQTEQIABgUCPnXawQAKCRDu0eo5ImHQc0W4AJ9v
+uq4wlkc6TmmmZPF/gZVLluHcTgCeItrnvzyS11xkIETk6v4b7K4gaiiIPwMFED51
+qhr9b4jGIdCnGxECRAUAoOaVZW5CdZ9oYr3PwI/i8RJN+JfJAKCmd/XIlYOCpa9Q
+c4C855pM8NFw6YhGBBARAgAGBQI+d6QQAAoJEBU/oM11pnaSL+sAn1DTHmbhITeE
+w0ZSgyBLQw2ZhcM5AJ0ZrRBbZ9lbgHXBKOJQiLpWBj4XsYhGBBARAgAGBQI+yi6W
+AAoJENvSRfyzsqEsF/AAoNXq7Cp/0AwEmWvhoTjmtY6eVYB5AKCMFhBUdYWNXVya
+lPTq8ThswNUnr4hGBBMRAgAGBQI+jc4sAAoJEMppOXSBA6N+kUoAn1Nj6YqarQg0
+sL2KrFsQROM3A6fSAKCyl40SpfVJSO33fYuPci9dHp+QCIhXBBMRAgAXBQI7EiJO
+BQsHCgMEAxUDAgMWAgECF4AACgkQohFa4V9ri3IsngCfbIpJDWj6UgXY7rBH8To1
+2BgB+RIAn3jw72WJzplAtShVTmuMlRFS+FUNiEYEEBECAAYFAj6sazwACgkQqywx
+6dYpjwFkeQCeOkJrnO5r2hWDhX4ACPPLObZvXLIAnR0VHAgkEH1W/t7B4zdDYdBB
+Zrd5iEYEEBECAAYFAkGS8mMACgkQ5BNhMwyqaLQs9ACgio5zJcieYLppigvSYLBf
+ubUVrXUAnRKZJ6MACpH6fpoz2vkc2dh69tbSiEYEEBECAAYFAkLFMoEACgkQm/Ij
+RS/ii88aCQCfd1cIawDqpkYU86f3JEjcN85ntFcAni0m8WR6s+bkh3fd+EIrSRsr
+u3uQiEYEEBECAAYFAkLfRQIACgkQQeoJoFeTSY8XxQCdFd+XEWqyDkCx37gaIQAG
+4dHpwiUAoOZ/K5OHyTJCNFaBUDtpCh7hL8TPiEYEEBECAAYFAkLfkncACgkQAQVm
+vOQTY5L3SgCgiEi5/1vYvJrKoAdl0hRWU57ieUIAn2n08BQfMZJQ439aNW/CnIK8
+jPBPiEYEEBECAAYFAkLgNdAACgkQc84u+4QI91XdNQCgoBB1ebohIflinAPlvI37
+pFHuu0MAoJ4yMtbKZMaq0xIBnxV9c5uu99tGiEYEEhECAAYFAkLerWMACgkQi5Yp
+Q/wkPzxD7ACgqKnyeb/fjVS8vov4FePxeLju4msAn1SCGaiF9gEf+qIaZUnjcT7J
+DJ96iJwEEwECAAYFAkLerG8ACgkQMaY9luwUC4Ea9gP/WON+0xIWOvWP7mKkg/+X
+0ukW+mbjE426qKtG/B0vNrTKpElmz8ttR+oajqbg20LazoEUuA9ZXjLPfsdWA+vF
+kxgV6qIdtxYPMamPm7ytEBOmgMowYXUftGteqM5fxLlceHiwdUlynG2fmtMqvPnd
+2OCezSFRx3W6nvAiIjoLZpCInAQTAQIABgUCQt7H0wAKCRA34/Rf7mXjIcAUA/4n
+DlQbnToSSDOZkFj1CoGL8TjsVgzrO3r3S3x38uQQTFAE/AGBY4mtHgNcYmiJaC2h
+N1Y+mlEGu/80Rjv185ZfJsFEerU6Y/9tRJJ1So9AAe5AmvGpD9ysXae5geB+k+ep
+IMSuf9WMeTRUCbQs9ufGZLV5a8jqstv+btcrzNaY9oicBBMBAgAGBQJC32x4AAoJ
+EJrNPMCpn3XdRBkD/iNi0Y6A3afDG9ZL/K4JrOPgHUFWC/DgAEBme4AY62agUsT0
+uXlz+Mu1Ps2E0t26ejScuVMMvqpXg7iJ2+3yKzsnX0ySEXW6/696XEpe3TFn1iVO
+mMElPKxakn3t/jr6SDepo9jqD5P5CJR4GsDsG3iKIisWdDf81ZXpf86y7A5eiEYE
+ExECAAYFAkLeuuUACgkQMsnkzjZCy0vmSQCdHGC6jOEVo96yyospTq7bL+EEeioA
+oNMKIZy5qFLXXZbSNvsj7mDRg2c8iEYEExECAAYFAkLfbHoACgkQUI6uxTAtpWhY
+hQCaAvqVBsTX5s4c+sTOo06BNMdzHIUAoIwpThAKq936Szy/3Gfv8K3gs5NOiEYE
+ExECAAYFAkLfbHwACgkQ3bpkuiwxLS9z8ACfYeocOK4J204xwbXgEdUJQyvHK2UA
+oKz2AF1I2b8Ebu7vTUZLNFV1QMtwiEYEExECAAYFAkLgyTgACgkQXP03+sx4yJNb
+EgCfRcj6QKHVHQtYVXdCYKUbrj97wAoAnimqV15cvz1siDjUK9K/aTskGwajiEYE
+ExECAAYFAkLg7MsACgkQybWm7OLXdN8UoQCdFfqef8My1xhn6mLd9WTLLaIewTQA
+nRXGh/Af4hVG0KwtZcJEA464nCoJiEYEExECAAYFAkLg7TwACgkQW5aAEOBPmol+
+JwCeLxZjKNisjgP4AxV5BCKR+5SU9NoAoIwPF/7B2NmGNR0t3EZze8wpNhQ0iEYE
+ExECAAYFAkLg7V8ACgkQN/aP9QFa/IqerACfafKJi4s8LYV2JxNfQKHgmRXzeIIA
+oNBHOzukDCdxIvmYJfamItnCP45giEYEExECAAYFAkLiYm8ACgkQbZiNF4cxXDH8
+HwCgq8P29CwMX7PKhRmY3T32APsOaMEAnjdd/WvzVBFtTcJFWkH6iF4L8EQpiEYE
+ExECAAYFAkLjVb4ACgkQEy5J1OQe3H56DACcDPfWLO5cDkeKFCvIP8mc4p4KkfkA
+oJITROldIRxXqUiML1oTJxieuHJfiEYEExECAAYFAkLjZNoACgkQdcqio/ObN1CI
+tACgsJhqBxeZTaSrRVNk3aj6ciAJrgEAoIxPXYTvIpnWBr4/WMbN0jpV0TGEiEYE
+EBECAAYFAkLkbxIACgkQjON2uBzUhh/gZQCbBpIqkCEuIbd6tqChz3PzcIGiZbgA
+njluBFHl4l1/NHtP9fEYCgl8nbCviEYEEBECAAYFAkLkkr4ACgkQBJE0Quobo42f
++QCgjtO6EOdDRiruCi6gKvwM1a2eRwcAn0XUELm5AZezL5E0rEfIM2FBiMi5iEYE
+EBECAAYFAkLlwh0ACgkQYRlqLjM+ToS9pwCfUEgO834XY/clWzkw/VLBfe7MLZQA
+mwdz0nleOHYWFBrnYgEz53d4MxUPiEYEEBECAAYFAkLqY/QACgkQsr68QBUpJK/o
+MQCfc7M9KpApCWW7eE22PlLoN1sPK+4AoJdwE8TsDM2Pmehk9K+uHIx6FoRviEYE
+ExECAAYFAkLj7WcACgkQMoZOQZyFIitClACfWpH0+V/N6vuucWZ7bsMm2BcmM3oA
+n3fF5qqovlog4/PcgvKCToNEF8uWiEYEExECAAYFAkLlELcACgkQUnkvr5l4r4YU
+ZwCgg7vJpDpUXnuNvgc5RHgG7UYhRQYAoIEKHsrswh6XzVn5yQRkfjdB/A0OiEYE
+ExECAAYFAkLlEaQACgkQa3OhBipiP3JA4QCffb8NgQssOQXaVR0dSwPCeU2nQPUA
+n15EAjykVZsUi2tZWqEM08SNOKI9iEYEExECAAYFAkLmmWIACgkQaOuMdvjqKWd7
+AQCbBpwyitQ77kd9KIT6y95Im1vmWt8AnAnkNTBctVtMfwddYTG+xLkaOllOiEYE
+ExECAAYFAkLnYVAACgkQbpR1lMFSQxqIRACffQqUXTgOa4hyHYQBUwrlGEqmWt4A
+nRMXVGhd47loS27MmiEiWwDlkNjJiEYEEBECAAYFAkOHn54ACgkQZjW2wN6IXdOr
+9gCgh2fn26W0DSL5WZATvvQkwZeJNiMAnR6+0AlUK8uFSFIVhl+RZMnY+XFwiEYE
+EBECAAYFAkWdnk0ACgkQIYJJVs5BnI/0SgCeKCw39INy9ISFunlAojYgSInHfokA
+n2vU8q4JNjg13qNeclZN9kmN9mbWiEYEEBECAAYFAkY44sMACgkQFUWz/uIi3k+q
+vACffppBpoY82MEvDV7c4/6cjw544CQAoJAPCdZA/LRqICJm0iFbDrwhsSb6iEYE
+EBECAAYFAkY4558ACgkQY9CtrpESA+QrAACglRB/VdEmovbyWdMDmsTdyw4kha4A
+n0uKwZeKHfBR3cC2s7MvqqmMoz9jiEUEEBECAAYFAkY8kyoACgkQmHDv8/EvYHIk
+CgCYgXQZTJ8VmHwSX3pXOxnMhp7mbACeIPXwcPvmfP709nfgQ8/GpT2z9ISIRgQT
+EQIABgUCRjkasQAKCRDh4fKwmQ7UqhZKAJ9iraDBstzeXPMtst3x+ZXdLQm7cgCf
+WDDgaQOa8CoM5/+7WCtkyasP6BiIRgQTEQIABgUCRjxQRwAKCRBMBCgYMRo95eP4
+AKCuEQU6fjPy/cPEiqhGH23J2YEr7gCfS8vBTEU4sRbOomTEuINPxb96OZmIRgQT
+EQIABgUCRj2gkgAKCRAuuUaCiIF0AgOBAJ0bJmFzA9WkG5FmfaP4ieG9+SCbXACg
+w+2wcOA/B94LKRtjhJT6j6zSiDmIRgQQEQIABgUCRj4VvwAKCRA+Km/CXymIJIvc
+AJ9QSE4mCQldVnpbYwLTCk+xHDqhcQCggT9P3/rHIzIvv1tJ+A1ZJPvXOcqIRgQQ
+EQIABgUCRj3WeAAKCRD1wmAWTO7XXwpbAJ4mr2IxFtx0ppkefxx0l0TJ6cFkrQCd
+EFbc+aMxRKhK9SCAWi3mq1UqEWiIRgQQEQIABgUCRj31AAAKCRCgctTQQ1jFhByK
+AJ9SIielTuD3StxPQpBkAkYP6Ld88ACgg1oPX9ryJA7YuhMD7byXQsETzD+IRgQQ
+EQIABgUCRj4FxQAKCRACpaYFC35s+k/GAJ9/VDyw2vNzk1xjcu/QZCa3gGI2zgCf
+eG8klJ78bAGknzxBlK3XtmoNqASISgQQEQIACgUCRjj3hAMFAzwACgkQc92MFgFT
+AjVJogCeL+3FTTVR5snJx9qbGQsgv23ZaT0An2Hy1CcXVklcYBF7LbnbAgbe1Hpf
+iEYEEBECAAYFAkZAtkMACgkQbQvHOkBYGDePegCbBe6rmz9/kYDV7w5pvwnugVsv
+biEAniTfLW7NW8z1SRBWf6lMH3clGAs8tCBTdGVmYW4gQm9kZXdpZyA8Ym9kZXdp
+Z0Bib3N0LmRlPohfBBMRAgAXBQI7EjmBBQsHCgMEAxUDAgMWAgECF4AAEgkQohFa
+4V9ri3IHZUdQRwABAcm6AKDaA//SYJv2pcXwGBC89OSzGvxy3gCg1kx6qu6zJKaW
+aE1L9oFqVc65OUSIRgQQEQIABgUCPD7VlQAKCRCBBGRPUYmFBNCzAJ9tv7tNS6Nw
+aOZQ8cR0pGslJGKtuQCgpttMmhhRrUwyVuEXc+dKX7rdQMKImQQTAQIABgUCPnXf
+DwAKCRA+j7fy+INB2Vm6A+IDxiYtMvd/mad+7hRoKXvD5AddB1SwnvQdJe0ewStF
+BYZxZdNOLXdkVngCwAJziPGZcQmocEHVMrN+Mxe+3OX0PEZ+3KOOsAUi+fTov2xv
+f8EWKgX9d0li9iEytVA4M0c52a3bPTC0Kki/KAY3m8oNvAmTwWB9dBSooFFDMIhG
+BBMRAgAGBQI+ddrHAAoJEO7R6jkiYdBzruYAnAzvTrvDQNvoAoaDQJ+o/ydqMA8Z
+AJwNEOQDHsz+6ynbMPoQmKmUqfEISIg/AwUQPnWqIf1viMYh0KcbEQIkpwCeInf4
+o3C5Ykh/xBodVImrp2Cvcy8AoMn3me5p4Sl2rm2tjVxTJZt2sUr7iEYEEBECAAYF
+Aj53pBoACgkQFT+gzXWmdpIpGgCgiTARP6Cf+JKOxUaVFr0L9DC5oUcAoIxF7D5m
+OVK/AFcp1cxNk3BLtdq3iEYEEBECAAYFAj7KLjIACgkQ29JF/LOyoSwAbACglNp7
+V2Pw4U575IuooM677bZf8pwAn2U2TcHj7PYprU+qYRkyJ3pa7FyyiEYEExECAAYF
+Aj6NzjUACgkQymk5dIEDo35YPwCeJIU/monN96nP4jJjAuflEXMbemUAoJXq7oVC
+YuOCqWr/T3VW0DM3W+dniEYEEBECAAYFAkGS8+sACgkQ5BNhMwyqaLQ2RwCeMcDf
+4bb+OMjRUJwAk2LHN9th42QAn03fVqMUZEVmOrVXfWILpjXNLMDIiEYEEBECAAYF
+AkLFMoYACgkQm/IjRS/ii8/gpQCffXXRCeZf1Vv5ih70yE2ZXg0r/rsAoJYKsdx0
+K5aqfoEzyiBCj5I46JvhiGoEMBECACoFAkLhOBAjHSBUaGlzIHdhcyBhIGpvYiBh
+ZGRyZXNzIGFuZCBJIHF1aXQACgkQohFa4V9ri3LxGACgiQ+wlaa9iMOue5DuhtyL
+PMSmuiIAoIkrciYFOf3VBBD0HLWfGVWUqxzRiEYEEBECAAYFAkLfRQwACgkQQeoJ
+oFeTSY/ndgCfUEQl4Rc5nnu3G4ZX3o4OywbF7DEAn3Htv1s/on+ei+1mmS6Z/Pdw
+gM7viJwEEwECAAYFAkLerHEACgkQMaY9luwUC4F1JAP/epJYDZX4flU0sa8AlFtS
+ROY/O6g3iVq5zeYm1WD3e0xOOYTXlkIntkYFhqbBzZQ3pFYfWmbhzCW/Tc0RigAC
+dmroEELrwyrfLIHvsnUTF7C5AL6SuFQZqG6qoMjtHFd6KDMos2sDEZ3VXDG1buW+
+hpHY9rWRJKPzb/SgSetTCeuInAQTAQIABgUCQt7H2QAKCRA34/Rf7mXjIaxmBACi
+YCwxZLtxnaRfwSOBkASqmnS8oBdyIKvTad9dLE3CziNgEW+AdfE76vQskeDxL3ZV
+QubhKWiaM4B7YU2nYxk4INVpok1qht9bN1Psy+TS3SvpPKqq8Ri8xc4ZPDwdcCcC
+JiXLy5iR5tx3iBsnHRM5+LMIJg+LiOqd/ZnBsggjjYicBBMBAgAGBQJC32x5AAoJ
+EJrNPMCpn3XdrMQD/3vFtnKssqT6mB7NOZ08Tcw+cC5e9gAVr5Y33X+ZgPe7BJd6
+uPNt+I97FDdVJOnNtTZSvnkQZ/C79Yoci0yZAAoHYlzRb4tXguLy4UDBjj3BlvPs
+COKJZrKn7bxvtoTbeHgjHmneiIwCuyzSoA1hAYxiPliDrwuVCQTudHDVxjl1iEYE
+ExECAAYFAkLeuu0ACgkQMsnkzjZCy0sSYACfX2gis4g5jep0HjKABAk31byHU0QA
+oI5294fLHOeIHKLCIdvKm+7gVLn+iEYEExECAAYFAkLfbHsACgkQUI6uxTAtpWg6
+BwCfVQtdTRbNPgQGFqGQSUlBJ459xfYAoLKhj68YUwZB5VgIeIorpqt9bWR2iEYE
+ExECAAYFAkLfbH0ACgkQ3bpkuiwxLS94SQCghB4+5RwGR0ZOyy2xUA4e6ImO6ZQA
+oIjkWwYRd1Vp9SQoJW5OdSquYSctiEYEExECAAYFAkLgyTsACgkQXP03+sx4yJOs
+AACeKo39hTRNVVyvj5y9ohT9Ye3/C+MAn27aEKrGgxNbwq50qGxFE+p36j7fiEYE
+ExECAAYFAkLg7MwACgkQybWm7OLXdN8i0ACgs+aW41FnchB0K/OUdB3t0Lg4i5IA
+oM+l0PyxS3XJsAwI+JbCm0aR3VA8iEYEExECAAYFAkLg7UAACgkQW5aAEOBPmokb
+qACcC3in6U+mqjSwb67rB5zTY0ThYucAoI4V7qe0XHTDUwwWOgRo/NzR7k1OiEYE
+ExECAAYFAkLiYm8ACgkQbZiNF4cxXDGcDgCgi5CrpyZ1Dcu0IKML05Ffvw8lPhYA
+n0nL0BczEo9RpNVYg2ytJ+YtjKUFiEYEExECAAYFAkLjVcAACgkQEy5J1OQe3H7q
+9gCfV5xTyo5SD7G62VSUbjYfeqcuxXwAoKAuchsMkavYWCt0jBhgLuTJkFqUiEYE
+ExECAAYFAkLjZNsACgkQdcqio/ObN1AdZACgpUgi5qnnDUpVXhTsJUoo4U485sYA
+oOXmMbhyaOMH9g9ndYFm5aHPMbf9iEYEEBECAAYFAkLkbxQACgkQjON2uBzUhh9S
+cwCgqFELgIdNWky221EuFgjKzgEG5WoAn3cBZbE+PMFhAZyUhQIl2hHEbVJIiEYE
+EBECAAYFAkLkkscACgkQBJE0Quobo43EoQCfRCtbvMHoTGmS7dmZ3sRyAj4W7WoA
+oJDfouy1wZ5tSMJT+XBm5oFtwSUSiEYEEBECAAYFAkLlwiAACgkQYRlqLjM+ToRA
+HwCbBxMHNYyvbYmAb1kTEt8ydF660oYAn3zsrmZawTXrjvbPE/VpC+/7wpzpiEYE
+EBECAAYFAkLqY/gACgkQsr68QBUpJK8VgwCfaCR45JtzFnz0v4jCuooqaFGgH80A
+n2BcoE/psLPTECGRDKE4v7JNADnCiEYEExECAAYFAkLj7WoACgkQMoZOQZyFIisb
+BgCeJjAXLGfz5ahDdgozqDYrbOzxWG8Ani7hFwwxHFAIe42+OsL6xweRD46fiEYE
+ExECAAYFAkLlELcACgkQUnkvr5l4r4ZbzQCeMBjFzDvBIFmK5VNIvvcK3ejdDPwA
+oLzg1ytKCg3A0OebfMX9nr5iQOxwiEYEExECAAYFAkLlEaUACgkQa3OhBipiP3Je
+vgCeJGjwezorOSri8IWxMJqTt3tOzkEAoMNZCTo3AmcKICFhtdttgcuOZNWAiEYE
+ExECAAYFAkLmmWIACgkQaOuMdvjqKWfg8QCfdYdGhkb7pBqgFhGn3uJ50+sY/QgA
+n1PdZCfRtVgdk/JVv35F7fJp5a1CiEYEExECAAYFAkLnYVcACgkQbpR1lMFSQxoJ
+ggCfQ7Du5ZKb7ooJj6CF+ne77nxVuYgAnjLF1tZ19A1n+hPaT4A2nmfnW2tRiEYE
+EBECAAYFAkOHn54ACgkQZjW2wN6IXdPfvgCfRhYzSFLrXLaM7hTa3iHktsQE1iUA
+n01MLep3eEdd3+VNPojrE8FlV+odiEYEEBECAAYFAkOHn54ACgkQZjW2wN6IXdOr
+9gCgh2fn26W0DSL5WZATvvQkwZeJNiMAnR6+0AlUK8uFSFIVhl+RZMnY+XFwtCpT
+dGVmYW4gQm9kZXdpZyA8c3RlZmFuLmJvZGV3aWdAZnJlZW5ldC5kZT6IXAQTEQIA
+HAUCPmiBXAIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQohFa4V9ri3JPKACfXhFO
+r4gMMIQwEGvUb6J/X4asuzIAnje2H9T1r/jSVi1NbIEtQfbpmyQXiJkEEwECAAYF
+Aj513w8ACgkQPo+38viDQdmGkgPnUYJfHlDrQ2jYJWuPDve9n4pV9OvyIllKyLdf
+ULjsLWXw4Jm+fMQJgWr2GEov1ZYIyS2+rGDZpbz/vxaBVbgqM8TPdiXzxwU8AFq4
+k+Em4fKXR58ByLSJjvLLza61spNHJennEUFp3tTpEsr4bNuuaoRYhtiKzTqNuoC+
+0x+IRgQTEQIABgUCPnXaxwAKCRDu0eo5ImHQc5lcAJ9FOoAL4uHMuqHXrrxsEVPJ
+vEJ2/ACggaOR62EziUqcqpdm/1Zy3P4T22iIPwMFED51qjj9b4jGIdCnGxECWssA
+oKnkR63bWGCFDB5YJtfZJ+nQq3TAAKD1bzG/kITQpIHsT2vCY1yBmlWbBYhGBBAR
+AgAGBQI+d6QaAAoJEBU/oM11pnaS+9IAn0kFlXAzOhhu4r5fglMVuw5bTAd0AKCt
+YRX2ESU/+tsE8vuXWtsMCGeI5YhGBBARAgAGBQI+yi67AAoJENvSRfyzsqEsSccA
+oKqG39X2y6xoQa56nviF5iCj/oTFAJwLKx9GyKEUbSM9f/IQ7AsZPhHT54hGBBMR
+AgAGBQI+jc41AAoJEMppOXSBA6N+xYgAn1HbGamcXTDYSFjn3U5ik2vQa8nuAKC/
+uUM01gsdn+71EiAkmrjlH6H9MIhGBBARAgAGBQJCuAqrAAoJEIEEZE9RiYUE0MUA
+n3cWFVW03CDuMuA7TSUqTf/eWARWAKC/GjQnPZ0+g7NbDw68ZSY3k8WuuohGBBAR
+AgAGBQJBkvP5AAoJEOQTYTMMqmi0GIQAn1mpdHz/wV++rSU2Qn7R32slfNdpAKDJ
+PqpnmcN4MUmk90yZEeHAdJmrhIhGBBARAgAGBQJCxTKGAAoJEJvyI0Uv4ovP3YUA
+n1z8L1EnLdIYttWrT1zs0E89Lz4BAJ4sFzcSq2NO3OZsEQfh9F6CrUe3UohGBBAR
+AgAGBQJC30UMAAoJEEHqCaBXk0mPIUgAoOF/OCzco+n/3sGJ57m0+aqGLOwjAJ9b
+C86B2hRvkaZlGm/ne3TzCgFGnohGBBARAgAGBQJC4DXTAAoJEHPOLvuECPdVsEoA
+n2hq8w0JUtfJpu3SmMUkFZLBFm3+AJ48pxmjHXjoBJGpokXw4i9Cfb56BoibBBMB
+AgAGBQJC3qxxAAoJEDGmPZbsFAuBGDUD93nHzcDWR6AuDxDvaDp1xR8oJZHojeZ9
+sWSRQffiNJKF07vvdjGbygqiWbQmtTM9qBnAxEiBpSpJemBhvGTKivPkb9H88KQe
+2jqowDO3IJorIVMT+eUFB+4pn5c+kFLD/IhG7ohZ2rBIc47L62FFuD19esxvMcVe
+lrBFq67ZV4KInAQTAQIABgUCQt7H2QAKCRA34/Rf7mXjIY9vBADqrguzlNOJFkWv
+EkgdVXCCH2TP3OUuPZ9JQtbJfbkg1nn1hCnMITapNJlEE3yyjB7kEpBkmUtyKv3V
+SwODspfis/ps6zJRIne/2R5xqtT38Hf/sYucoMZUceipFAoCLYOqkKJKwTpYM040
+1dUpuxp1y8Lq5N0SDtTW9fKMNs9jioicBBMBAgAGBQJC32x5AAoJEJrNPMCpn3Xd
+ek0EANLj3wh2FCukydsfSzqgjFDpkVjiBxbTtCep86flaLMrF3H0idckGCjMUf/J
+ostBsjwCpL2VlCtvhwl5ZgIzm8luceHupq2iC5hvUN0IjKuIXMLbZP7DE+Lfcvw8
+2nKt8JNPpjosXiMhysQZms2XfuNP6f/Ey8J5jaB2Z2JCYWJBiEYEExECAAYFAkLe
+uu0ACgkQMsnkzjZCy0vBrgCglfCttIxFGqVTLTq/nhPnRFMHX9YAoM4Z05oTuPFx
+GWS4RzxCzCb3vpsAiEYEExECAAYFAkLfbHsACgkQUI6uxTAtpWgipACfTBzbyb7V
+c0jr2FZDiXJFUSBCoEYAnR+ySWmedkcJWESStqRstD8T72mOiEYEExECAAYFAkLf
+bH0ACgkQ3bpkuiwxLS/5RACgm88lpYDxy0bYF9/ubFbvqCw6i9YAnjrQoOLRBtQ4
+QmIPR+T/9HReOeSciEYEExECAAYFAkLgyTwACgkQXP03+sx4yJNXxQCffoccUBWO
+51YIEM0mbsqpnKHtawoAn2xTiDgo3TjtbRJskADuw+QnATQLiEYEExECAAYFAkLg
+7MwACgkQybWm7OLXdN8bPwCfeKtfQWKm8i+KuFJTIoMTvAN65QQAn2A9G1wtEN4V
+zg6HfnTvtgus32rRiEYEExECAAYFAkLg7UAACgkQW5aAEOBPmonAkwCfeF3l1lE2
+WijQF0BmPMfqvkyA2UcAnRQzuc7PWyP0nydGoJvfEUHByVs7iEYEExECAAYFAkLi
+Ym8ACgkQbZiNF4cxXDEC6gCgqICh/djzt1i6uadJAOztZc/zxl0AnjR1OaM2JxR+
+wqK3loSTEKX1uOpBiEYEExECAAYFAkLjVcAACgkQEy5J1OQe3H7rRwCeJWLmLyPz
+pg3nr65j7AxqGRJeDfUAnRT2Oa85dAM02wgdYlj3FejPuNFziEYEExECAAYFAkLj
+ZNsACgkQdcqio/ObN1DA+gCeOaeMarEJDPbZjaN3y/Pf5PB/Cv0AoMGPjPSTGt/i
+HJ2aArfyd0ME/R52iEYEEBECAAYFAkLkbxQACgkQjON2uBzUhh+lnQCfVbPGF5UW
+lzFbxK+xKmY2DbKXb5wAnjpoAxffSRO1PZlQUHgWlS+NaeCziEYEEBECAAYFAkLk
+kscACgkQBJE0Quobo40fbACgo9YCJXu5Hpoc/SVp3rHCYmTuEMYAoIt2q6rPL/Jb
+bkikbRqausEnFstziEYEEBECAAYFAkLlwiAACgkQYRlqLjM+ToRP8wCeOVAIpaG+
+q9G7uJgVCyDZ0JbjjfIAoJgg+NrBfhNeOBuu5mS1PSGDztQ+iEYEEBECAAYFAkLq
+Y/gACgkQsr68QBUpJK8HfwCfWgNlYNLBWmn/nejlx0m6NstT2CsAnRdhsusv6Rbc
+KNoVUudxGG4Xm3nGiEYEExECAAYFAkLj7WoACgkQMoZOQZyFIiv6jQCeMior8Tg4
+msrRc+FfXfj5Uln03d4An3RTaHKU+Sv4SgEecXlW0RYlVa6eiEYEExECAAYFAkLl
+ELcACgkQUnkvr5l4r4ZC9gCbB5X0rL/DtpGptiNO12DdTQqzsMMAoOWpJFg3W7zA
+r7alVjqlx0t1vS4KiEYEExECAAYFAkLlEaUACgkQa3OhBipiP3LYawCgiuQqhVay
+7FE8e05Za69seQwF4CYAnAxBVNyvXu/1aeAuSi3iC6tywvFoiEYEExECAAYFAkLm
+mWIACgkQaOuMdvjqKWfdbQCdHfDneYM+nWXT/oYOqohamLvk8iQAn1LLJhkLiCMO
+a9/biF24zKt+MjaHiEYEExECAAYFAkLnYVcACgkQbpR1lMFSQxog0ACgp/m7d/Nd
+NP0w605VyrJWCdogeG8An2E+FpFBQgyvJaD6klzDRNNYLc71iEYEEBECAAYFAkOH
+n54ACgkQZjW2wN6IXdNgDgCfUVMGJZV/D1QEdnwrTkRmMb37KR4AnRLDWMsKtq4q
+KXQjYbmuLNdHa1EQiEYEEBECAAYFAkY44sgACgkQFUWz/uIi3k8H/ACgmKEdToiB
+aw1wAMXXKjj+8PTU880AnjTWDVjV2fZnj8iXaOK7MTx01gMRiEYEEBECAAYFAkY4
+56IACgkQY9CtrpESA+QXcACcCFtUvEcmTT5ezAsMsWPbRJAqtwoAnjFdqKAoBDkP
+r85/VI89GhfttMRdiEYEEBECAAYFAkY8kyoACgkQmHDv8/EvYHLdewCgo42arxjK
+Fiq+lp9b11fuTqvimDkAn1KOSLRaqubUBhfEBgZzx9kh6wh/iEYEExECAAYFAkY5
+GrkACgkQ4eHysJkO1KqIOgCdHwUD/IZcQB3qA/QCiKjIwePp7QoAoIB2fFdQH95L
+A33wSR5XBI+mIEsbiEYEExECAAYFAkY8UEcACgkQTAQoGDEaPeX5dgCfY6TPlbpJ
+psrKKtQaMXfSWv0E/xUAoIGqw9ZHnQ7y9wbSUMuSnW25b7rdiEYEExECAAYFAkY9
+oJIACgkQLrlGgoiBdAJMWQCgirz2diHoCbFyrBAV5iKWgP4Ua/QAnjWVrS+SKzUl
+QgMzcU07zHDlVs1kiEYEEBECAAYFAkY91ngACgkQ9cJgFkzu119zGQCcCwwCeGu9
+A1U9Amz8/nKxBModdnsAoIavFQWLkVD3egS5YEarD/Edwx9UiEYEEBECAAYFAkY9
+9QUACgkQoHLU0ENYxYRKfgCeMfNpqkkRohgWFz/f2EhGbmfR2X0An2UBeqbP5hBK
+okpD9xyF0pst2FIZiEYEEBECAAYFAkY+BcUACgkQAqWmBQt+bPrGDwCfUQUaIJ4j
+UL7sFQOojnGU+mzpYHkAn1xSgTyDWKkT9C0JVhw5SEPnfLFjiEYEExECAAYFAkY/
+BjEACgkQA/aMvd6IhKCNuwCgvN28t3l3yYAMxkMUuL3LA8uTikEAoK3bfHFYDA1K
+Plb648YsvpHQgRvoiEoEEBECAAoFAkY494cDBQM8AAoJEHPdjBYBUwI1PekAnR36
+SmoXYYegiEUSKxHCjHQnnYnbAJ9zmdCCloaaDIyqh2qr5x2jJscjHYhGBBARAgAG
+BQJGQLZMAAoJEG0LxzpAWBg3YX4An2XrLaazjvwgpUwVEj9KCHAq9FYBAJ4khHqE
+JHjpBjQioqGQfL2Z/NqI9rQkU3RlZmFuIEJvZGV3aWcgPHN0ZWZhbkBzYW1hZmxv
+c3QuZGU+iF4EExECAB4FAkKcaeUCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQ
+ohFa4V9ri3LJLQCfV5FgLLtMydvd3RmvmG2p/ma9VfQAoN2/T3rXbOnm6kGaIh0a
+KXJG2zi6iEYEEBECAAYFAkK4CqsACgkQgQRkT1GJhQT9FQCgjx9G+0vk8pVdbgbm
+HGJ1iG/0Sc8Anib0UzD51jY1c/glTr1cyUx+KJeZiEYEEBECAAYFAkLFMoYACgkQ
+m/IjRS/ii894qgCgl0WVnRowVW49yARZd5L4d8RdoLIAnA9x+/Zm1Q0TTMaRgKxU
+NYakBc5XiEYEEBECAAYFAkLfRQwACgkQQeoJoFeTSY8x0ACfSH5IypIhLhcVIc57
+IIQEPG7AVpwAoKE9JFkgd4lHqSyA6FoYRrQyEuRUiJwEEwECAAYFAkLerHEACgkQ
+MaY9luwUC4HmzgQAgBRaRChEzt2R24zJz6IAAja+hGQkMcxkyF610slkLOvFXB+e
+MFDgOMpN3BqXx9qYAMWI2h3o0yUbwyrxqzxpSh4AmRcuPsB86Ne6VvSdWipNrFFp
+U+u7Jw1XTLp/4vFsQ/cs9vfXF0eogsT3z9hyDBKm7MViWlyE6O3a1kozt+WInAQT
+AQIABgUCQt7H2QAKCRA34/Rf7mXjIUWsBADPcH5/bASLBc0EUGwDvpZfN3/JIvvg
+OAJ4+g10OMUZgpVMamoS9QY8cXkIRPkKJqtSHmwya9Ent+FwdINye286/4vUJhMB
+KpwyX1laG79VII8vtY8xK5WQYZvIZwiPsz561ii5NJ+/L8yeUa51Wk01fjlua+K3
+VWfOsimB7aVUqIicBBMBAgAGBQJC32x5AAoJEJrNPMCpn3XdBw0D/Aww/tRUFPDz
+z3virn9myTju2HK3o+CRdSPxm7Nhx98V4DmbEb+lieNTP6L8SS2K6VakANmBfxsc
+ILsK3+JT5PuLKRXWm4LoiStHdvymQLZy7IyM3WHKGNNSChk98ZD8CAxKzRUpsV+m
+yglHj3BTR2GenQwRxRXGFU7HaP8GwHumiEYEExECAAYFAkLesLIACgkQ/W+IxiHQ
+pxt9FACgwsbD2ZLCiHL4+7Wx0BMJvj1efg8AoOz6K1AoCL0yFpyA/M0VgwRuAAl2
+iEYEExECAAYFAkLeuu0ACgkQMsnkzjZCy0v3dgCcDOwUCEIKiwNKgO+UdhIxxV0C
+mVgAoKO4mgDR8SEXPzcNfY/AsTW1iUSeiEYEExECAAYFAkLfbHsACgkQUI6uxTAt
+pWiMdwCbBdB465uDdtRMHa5oUvTxykC9inYAoI5brNhsrgs2n4G/SR1YQQ64XpZJ
+iEYEExECAAYFAkLfbH0ACgkQ3bpkuiwxLS+zFgCguq0FOmY0kuoFZ8LMLrWqgcH8
+Lb8AoL9pjBiX9oZ2FWjTaleViBQLsnJjiEYEExECAAYFAkLgyTsACgkQXP03+sx4
+yJPU5QCfXWzNh6MCOaA+oRkpwA4SNnSnwa0AoODvVrRYkcy6gtU4AgLG4oKsviQ4
+iEYEExECAAYFAkLg7MwACgkQybWm7OLXdN9daQCfS98lHuxlHg6jM3d1i1mrXJX+
+67kAnjnpwPZ4cioBwEnhCv2V0FwwwVtLiEYEExECAAYFAkLg7UAACgkQW5aAEOBP
+momzVQCeMJwH3AP67VLN/h7vZzZ/Gq/9kOcAn3ulvpPch43e4WVp2B3ZwpAGZDjH
+iEYEExECAAYFAkLiYm8ACgkQbZiNF4cxXDHs0ACgp5PkqNAJ5uJCw8JfrKx7yAe2
++owAoKkTgTeTHhBl0Jvhmp9lUrfp702fiEYEExECAAYFAkLjVcAACgkQEy5J1OQe
+3H5UdACgkwJX4TxcBz15waPuSETqKcDUJ7EAoIdrx0vVUWUbeSPYrDQ2jX9W4gkJ
+iEYEExECAAYFAkLjZNsACgkQdcqio/ObN1CvVwCghC4u8psbS8XcGH3X1d3cXet5
+ldsAoI4GlJUKhV48eZl50bIMuEunEvcriEYEEBECAAYFAkLkbxQACgkQjON2uBzU
+hh+f7ACfSVRzFcAcBw/Dzdw0KvIRxLpp/LcAn1UEl6KDWNj++OCvvJOpSzvJzh+h
+iEYEEBECAAYFAkLkkscACgkQBJE0Quobo42/qgCdGfgKBg2HtdtsEQDmACmspfX/
+XtEAninraJZejWfkZvzSmxSRj+n2MsCLiEYEEBECAAYFAkLlwiAACgkQYRlqLjM+
+ToQ3ewCeNJd+3C2XEsXz7dzO/2jj4FRqWucAn3ImhMp87hw3yEA/77V62W9ptPjX
+iEYEEBECAAYFAkLqY/gACgkQsr68QBUpJK8ELACcDPCKrV0JP0wYkIuhcqvxx5uf
+87wAoOWrWVfBfq+41UYU9UifhWlbGkA4iEYEExECAAYFAkLj7WoACgkQMoZOQZyF
+IisLsgCcDpYy9vvn1UNAUikbxUr0vn0rtygAnicbDoW8gnd6N66sGlXmORRYvhZv
+iEYEExECAAYFAkLlELcACgkQUnkvr5l4r4b9DgCdEoP1BJwfyAKKox8yqAYrwjGA
+7a0An1WNyAykR22yzX1gUgxEVgk6R17YiEYEExECAAYFAkLlEaUACgkQa3OhBipi
+P3KhgQCgxIE3sM7ek45gpCPUa2IxeOmvR+MAniT4eG5k8pnH8ERp+tIdGvTM9Zim
+iEYEExECAAYFAkLmmWIACgkQaOuMdvjqKWd5RACfcOBFgIEVDMX9FHdc6MoGA0Hn
+QIEAniTx0m5OthI9dTZYzRjdc3cM0R7kiEYEExECAAYFAkLnYVcACgkQbpR1lMFS
+QxpDnwCgoEDPudHU5LSQ2g3fIFThgSkYkiIAoJE/YHbQ2nNJvbNiBwKpLZNJnNFP
+iEYEEBECAAYFAkOHn54ACgkQZjW2wN6IXdObrwCgozJ5+BqZ2YY1hUu4jdCyF4MZ
+uT8An2KHYyhec0myETse/XSeNRoNP1cViEYEEBECAAYFAkY44sgACgkQFUWz/uIi
+3k85zwCgmiFCnYskmq4bv/8xFZ+u8vav7MwAnA1KG9S9mnNUdRRwfVxOH03/z1dS
+iEYEEBECAAYFAkY456IACgkQY9CtrpESA+RZVQCaA4XNHYo1Lz5jiiC5F+nxuYO9
+w7oAnj7Dq41vmCHOfk/anlTMx8n5tqKbiEYEEBECAAYFAkY8kyoACgkQmHDv8/Ev
+YHLZyQCgnOw2eyc14GgeCJosAdnchjBVAvEAoIrThShMNcuPldXTTd5GWC+D/zP7
+iEYEExECAAYFAkY5GrkACgkQ4eHysJkO1Kr1WACfQYxyw8hpkeesSpShd6latfow
+JoMAn0EftKm1VmkiGlUtQwoPMlK9rcTniEYEExECAAYFAkY8UEcACgkQTAQoGDEa
+PeVTtQCgnsBMALHH4/VX08bMBegS+szY/KwAn1v95Bu8zyNnUo1icxmD0GDwGtLJ
+iEYEExECAAYFAkY9oJIACgkQLrlGgoiBdAI8UQCgrvZIkH71Zkq1WW/RyvDGs4br
+focAn2OYLkjs/eih+XSdufOXJucD8k+ZiEYEEBECAAYFAkY91ngACgkQ9cJgFkzu
+119OMgCeP2bzn7HsQoCEEbqERINfw/W54ioAn03CofXSxZD45Q98iMPzQnNS9P67
+iEYEEBECAAYFAkY99QUACgkQoHLU0ENYxYSZgQCdEz2ZSJLKtRJwGLU00m/7R6V8
+TVAAn3f5t42kx3SZY0VxiO1AbFR5y9J1iEYEEBECAAYFAkY+BcUACgkQAqWmBQt+
+bPokJwCdHhswezSELVyxIMrqYcltJwaaVa0AnA4+rZtTAilwO3+M1dUdLt9I61Hg
+iEoEEBECAAoFAkY494cDBQM8AAoJEHPdjBYBUwI1fdkAniPtNsi5EqpnSZTAVX1R
+PY6E/6QQAJ4yZcsKLd/D0vBbaHZYgnzb6p+lSIhGBBARAgAGBQJGQLZMAAoJEG0L
+xzpAWBg3H1cAn20um0ttFdRJZ7kAQKH7JotMo286AJ93s7aw0CK4fvwZFyCaOyBd
+DcvoFbQoU3RlZmFuIEJvZGV3aWcgPHN0ZWZhbi5ib2Rld2lnQGVwb3N0LmRlPoh3
+BDARAgA3BQJCxUrqMB0gSSBubyBsb25nZXIgaGF2ZSBhY2Nlc3MgdG8gdGhhdCBl
+bWFpbCBhZGRyZXNzLgAKCRCiEVrhX2uLctbvAJ0RzqF0KvT3hrwsb5yFN347MbF8
+VQCdHcW+24byy/frsqeTTJsyek4z/iGIRgQQEQIABgUCPnekGgAKCRAVP6DNdaZ2
+kvV7AJ45J7uU65+FzeZ9Nezt5K+oQK3z2gCfRUz5iBAdt91WnfZgTse3o3oY9/SI
+mQQTAQIABgUCPnXfDwAKCRA+j7fy+INB2Q/tA+Y9lc+LubrBGIuh+xOUcJsGtH56
+FahJKoKYdCM3UMZG1qYYTpfxBswi20P40un65PHyP8TSwZR0+daSTLp/C3V/cBh6
+gCAJc28+h7CwLqZmfcUx0Sjq8lzjcWaGxR+6Y626e8Y0Gdd0zwZIIn5EFL8BIyNG
+sQIXXb/XjHCDLIhXBBMRAgAXBQI8Pto2BQsHCgMEAxUDAgMWAgECF4AACgkQohFa
+4V9ri3Kz/gCg0PlCER3JUjKkG8JQe/lIJoApx38AoMW2G1lOuMX54RiWS08tG0j3
+ON4TiEYEExECAAYFAj6NzjUACgkQymk5dIEDo36MAgCghwB4Igq3ZAE+cC2GdSTg
+OGWYzsUAoIDQjP1m61cZvaX6nyzuGEXf5j0viEYEExECAAYFAj512scACgkQ7tHq
+OSJh0HOLzgCdF128HK4Oh2XkpoJJ2l7qT1piQuoAmgL+53bxfQzjvwqWZpxVWNv4
++rMEiD8DBRA+daou/W+IxiHQpxsRAnoPAJ9/3XwtGKAVTIS9iPTgLXayjzsk1QCf
+RE0XD4/X9JH0yv8lCY7MlWGXB2uIRgQQEQIABgUCQsUyhgAKCRCb8iNFL+KLz7Bn
+AJ9G99bo3IGgCnuhL0gtEc1iHYZuGwCdFgazWFJoYrisbGb9+arGP4O+oja5AQ0E
+OxIiVBAEAM1SlkvEK5MrMnW0ybtv9eMCG89gqIvd2gBnpcAsF0sX+dCaWHWNy5HL
+3dBak/G3BJ8+NzAksfL5Srm0LVKcfVjBiG+IsbUoSyeJQGuhSZXYcnIc/3Z8Ujcs
++TfFurG8uHU1cWnNK5aMYwDrqxmp4Ru0zLYHw4tHBBKF0cgFaCsjAAMFA/49aSZu
+DaatppSaBOzCt7wIYCsGBxX5ZibrJqr0gLUbhXU9eaWzCawOWwCvpQN0lTjoYVkw
+iLZaYUkdqsSQgHAU3jjKlIuaIRXApEkTb8Jg7R/vNAdwXoZRLBCjZPGd5qGtnIez
+sZ2+lxFx+bRieUL8fUInemXwWl8e23PMisgm+IhOBBgRAgAGBQI7EiJUABIJEKIR
+WuFfa4tyB2VHUEcAAQENMgCgnc22kj8TfjktU6u4SUUqud25ZZcAn0B2b0zPjKjG
+uiwdKSnkFbNcFS3g
+=1whY
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub   1024D/C152431A 2005-07-18 [expires: 2010-07-17]
+uid                  Steve Loughran <stevel@apache.org>
+sig 3        C152431A 2005-07-18  Steve Loughran <stevel@apache.org>
+sig 2        FC243F3C 2005-07-20  Henk P. Penning <penning@cs.uu.nl>
+sig 3        302DA568 2005-07-21  Rodent of Unusual Size (DSA) <coar@Apache.Org>
+sig 3        2C312D2F 2005-07-21  Rodent of Unusual Size <coar@OpenSource.Org>
+sig 3        E04F9A89 2005-07-22  Roy T. Fielding <fielding@gbiv.com>
+sig          8103A37E 2005-07-20  Andre Malo <nd@apache.org>
+sig          5793498F 2005-07-21  Tim Ellison <tim@ellison.name>
+sig          E4136392 2005-07-21  Noel J. Bergman <noel@apache.org>
+sig          1CD4861F 2005-07-25  Eran Chinthaka <chinthaka@apache.org>
+sig          EA1BA38D 2005-07-25  Ajith Harshana Ranabahu (Made at Apachecon 2005) <ajith@apache.org>
+sig 3        21D0A71B 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        3642CB4B 2005-07-20  Martin Kraemer <martin@apache.org>
+sig 3        2261D073 2005-07-20  Astrid Kessler (Kess) <kess@kess-net.de>
+sig 3        E2D774DF 2005-07-22  Sylvain Wallez <sylvain@apache.org>
+sig 3        015AFC8A 2005-07-22  Bertrand Delacretaz <bdelacretaz@apache.org>
+sig 3        E41EDC7E 2005-07-24  Carsten Ziegeler <cziegeler@apache.org>
+sig 3        F39B3750 2005-07-24  Colm MacCarthaigh <colm@stdlib.net>
+sig 3        9C85222B 2005-07-24  Henning Schmiedehausen <hps@intermeta.de>
+sig 3        9978AF86 2005-07-25  Christoph Probst <chris@netzpunkt.org>
+sig 3        2A623F72 2005-07-25  Christoph Probst <chris@netzpunkt.org>
+sig 3        F8EA2967 2005-07-26  Brian McCallister <brianm@apache.org>
+sig 3        A99F75DD 2005-07-21  Rodent of Unusual Size <coar@OpenSource.Org>
+sig 3        EC140B81 2005-07-20  Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) <dirkx@anywi.com>
+sig 3        EE65E321 2005-07-20  Martin Kraemer <martin@apache.org>
+sig          152924AF 2005-07-29  Sander Temme <sander@temme.net>
+sig 3        87315C31 2005-07-23  Raphaël Luta <raphael.luta@aptiwan.com>
+sub   2048g/59066D7B 2005-07-18 [expires: 2010-07-17]
+sig          C152431A 2005-07-18  Steve Loughran <stevel@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.2 (GNU/Linux)
+
+mQGiBELb2+oRBADhgEV29jhAMg4dFJN9fjeIjN7+J0Lj3rcLBWc5RTlM33DTOCFM
+BCIE9B/RXJuVhGgi7fUuB+WsHz7XMgZRn+5nqIKGecIxwEUtZCfwsaV6Id3abt30
+wccyYDTSV95gQie+bbwWF44ao7n/CaR1WUU/Nx5b26nY2EzOrQcgP1qYEwCgynnc
+NU1N3zd1cIYr5hQVqvdazKsEAMbYAm5WsjBlLBrolxs/smx4vxZYJaA3gUqTz9WY
+D08rDsotVIMoosYF0b4b3WxcePJ68N1pkF3U+zo8bIZJThT91nAfMh29ZAcSyRqg
+Mkd25OcrrjykeF7OavuFSwhvYoDdlwsvkuijHY3weXyhpjvzi+GzvZoONo3zSl4g
+aWncA/4vu6k7XZUZ6B9DbJLJ4Xqq8uhD7uT4417uCQdozIWgKE4ThM2WffhV2IgY
+W6IXg+o6AqY1qiMLSYYdeRsVkQ/GVss+sR++cbsO5ijDGfvlWPfGxIcA+P+alAwf
+KY9M45IB8E92DUDru6ImrDHMeOrlDNPRusxRyZ4SiSJYNcgBtLQiU3RldmUgTG91
+Z2hyYW4gPHN0ZXZlbEBhcGFjaGUub3JnPohhBBMRAgAhBQJC29vqBQkJZgGABgsJ
+CAcDAgMVAgMDFgIBAh4BAheAAAoJEG6UdZTBUkMaZugAnjJVyMa1FYEm/9811Whm
+K06kGzXbAJ4rgRTBOcuyVbmbOAeYCgqloOxky4hGBBIRAgAGBQJC3rlGAAoJEIuW
+KUP8JD88RewAn3LmpnmnLlYnlQW7+byITmKLO9gwAKCi0GGQz0QUq9tFG4YeF7Rp
+UCl8ZIhGBBMRAgAGBQJC32y8AAoJEFCOrsUwLaVof1cAoLX3ROO9ufH+QXYlBuy6
+HA5SgofAAJ9aON/jC3WmrxT9Lz/DlIBKVI9TZohGBBMRAgAGBQJC32zBAAoJEN26
+ZLosMS0vCycAnjFhGc63FoWHwzpfVoocrBm8yQTHAJ47Kle1Tr+fBnlkYsAg0xY6
+12VZ9YhGBBMRAgAGBQJC4PEqAAoJEFuWgBDgT5qJY6IAnj2jxdReXh3eBRr+easP
+bboH9Lu0AKCSoT0Gt+pM+G7XM8vQbZjsyjDhrohMBBARAgAMBQJC3t+3BYMJYv2z
+AAoJEMppOXSBA6N+4VAAnRfGDGvU4qDop0EdApmHCExFDHFDAJ9/3xZDnJjEeSGr
+l2JyOPJfbv/k0YhMBBARAgAMBQJC30/tBYMJYo19AAoJEEHqCaBXk0mPRKwAoI0M
+FDyhr2PON57N4614Po16a9ZNAJ0SGKJtMOIxgoDHSf6SYuFy+8sBLYhMBBARAgAM
+BQJC35MFBYMJYkplAAoJEAEFZrzkE2OSgcsAnjKv4POPmFUYhDGH+GCcxSyM9LPo
+AJ0TPnoLf74lUroWD5+rlhTPD9eMHYhMBBARAgAMBQJC5HvtBYMJXWF9AAoJEIzj
+drgc1IYfdCAAoIKybYLGd4yGE8NcrvnGaPSXx6NXAJ4zrIPA9tQu23tOHarZxSqg
+7AWGh4hMBBARAgAMBQJC5JCBBYMJXUzpAAoJEASRNELqG6ONWZsAniJvvMiDR61N
+rV5Y7xx/3/id/ekWAJ9MNUUQAXTES1dkywQVHVp6C8QFvohMBBMRAgAMBQJC3rR1
+BYMJYyj1AAoJEP1viMYh0Kcb26oAn2JuF355Lq6PIEvnhEr+SA3noxS8AJ9msBXz
+nHsORsz8mB4WZ4DMAYEH0YhMBBMRAgAMBQJC3rvoBYMJYyGCAAoJEDLJ5M42QstL
+Cu0An2vCOimm9iyRJekvlh7IcsrXVDksAJ9S1iVXBgyRuWBkbcuRk9OLs/TnwohM
+BBMRAgAMBQJC3twlBYMJYwFFAAoJEO7R6jkiYdBz3gkAn3b48pHpjPG5DCbfp0oT
+/WN9IqYlAJ47CLk2xg7e8N53WTmYfL+F/c/ZrohMBBMRAgAMBQJC4O0jBYMJYPBH
+AAoJEMm1puzi13Tf+KgAnjviBj4kvC9ABiWR70t4BU3y8kgJAJ9qmj71qWjrek/L
+Cb3+fAmlASx82IhMBBMRAgAMBQJC4O20BYMJYO+2AAoJEDf2j/UBWvyKJywAnjSC
+smaB18utPgHthVW0qDQ+DDmNAJ9a64uKqcDI7u1cDEbi3nL5ELztCohMBBMRAgAM
+BQJC41snBYMJXoJDAAoJEBMuSdTkHtx+SyUAn19MjVdnPdxKdiXjpMRWwOs5fhTL
+AJ9AGh+TvyOt877cfLVaywPK+GhN0ohMBBMRAgAMBQJC42UQBYMJXnhaAAoJEHXK
+oqPzmzdQe9gAoL7BugDd1NniX/ZNqs0aD7Y1uUfhAJ0b4p34ZYPWFg1CyUduwYlx
+MAOqo4hMBBMRAgAMBQJC4+3gBYMJXe+KAAoJEDKGTkGchSIrHl8An0ERlWCCDHYy
+0jlbsVcQ4FOS9qe6AJ4sLF02AltG01bK1kpvnKXxHFVYoIhMBBMRAgAMBQJC5RDw
+BYMJXMx6AAoJEFJ5L6+ZeK+GWEkAoIl+GM1cgJosSMsMG0NqXog9yqeKAJ9aJ0Xr
+j7JP5abRyjROroIUCUcc4ohMBBMRAgAMBQJC5RHdBYMJXMuNAAoJEGtzoQYqYj9y
+IawAn3TzgRnJPfl4gg2kwIlJtD/a4ql5AJ43+Bbg3EWh2RVaLB7QpA1pAsRFB4hM
+BBMRAgAMBQJC5pnVBYMJW0OVAAoJEGjrjHb46ilnWz8An1WpumoYARq3Le1VG0vu
+SkQcdg8SAJ488MHNQRq2fyQFk9uIstWriQfa7YicBBMBAgAGBQJC32y2AAoJEJrN
+PMCpn3Xdsl0D/j7J+/vobH/4+pmWCWv3okqBbbd9PH/NJTC3B7KU+p8bFdIIZWYh
+n9SPXRdLoUlbKnqYw6+x0Ktn/9oWqwTM2b1bOHoMEUy/hPDM1ZK2gGDU11BFbfC4
+zkXowbq2xCHLyaQXqj5Wju01PT/wj8bw5A0E2rzv2iUA2ilXJE1vQdx+iKIEEwEC
+AAwFAkLerQ0FgwljMF0ACgkQMaY9luwUC4H6jAP+L3lvntIdecj0QlnD4gTkdLn+
+nbOPT0G9MPSjA3ML9Bqeoh/uD2TeHS0dqb67DpIzhKV/zu6vrOhsXHXNiCjR4lxR
+YHBg0PoxLJkggpjdAduk5vcM2ZgRJZQojsQ9CunxnmA/YCRCEEUPFeKj/5p1aFGm
+uPsl2zwggHxbdOBY1maIogQTAQIADAUCQt7IywWDCWMUnwAKCRA34/Rf7mXjITNS
+A/9YB8srHD2WbpZy5P/cN6WjPshYgx0lVFOifFdXgD4AUzgJ3VmtH1NI0Rkgadcw
+8PdJYAynH/Hdz4PJ8wIEkmMFEe6TKB3BCjCGY8+Ti6R/VrlkizIGL0HzAUzNc+g2
+D1NI8725Idx+XNSOSBcOBZ3mwPVo1k67X1rF8BoYAeo8TohMBBARAgAMBQJC6mYn
+BYMJV3dDAAoJELK+vEAVKSSv8BwAniQzr7l/ihVvAhvNUnpJzFWfr6tfAJ93Mama
+D+Fz4kgEVjnO5j8MrM6JtIhMBBMRAgAMBQJC4mNBBYMJX3opAAoJEG2YjReHMVwx
+Pr4AmQGWlApW3C1VbkuRgVs8pj6/ejXqAKC1z3D5mMpj83yyejnBjxDjXTLsUbkC
+DQRC29vxEAgA05PNdXcVOSTsYuizTCbdBU9i3qUBkAyqPmDE6hkWI+7fnr8KAUUo
+UghWwhxqBngpv48o3mE+bC+l/cTH+DuHIOsszpSK5ydufyitXi7piYk4RS+UNbyl
+b4BU5qGodwWwXC9wKBIjXL5rK2KjKh4Ovh0WogtZ1fwc5NzQkjcfbner9WsAmjtd
+nmVV2vZhJdDlxf3BBM9ai2R2IRvfhF61QFZcr2ehqAdsiDix8p0ugpC/oQS8h8pg
+GQebz7aNeSjh/Vb3dsdo8CaLvHp1nM5aVCDRqoCfoeKUbRfwwwKxtc1cyYzOHD1f
+KG9BuvtL4y4JQ/gDCsQVKdAAoiktu8Ks9wADBQf/fGkVYIh7w0+8xSIvez1DKirX
+rl1J3XNvOYIa1qlBk65hllXnFXeXqoOLQpvygcwNRfil3AGcpwzwlNloem3ozjnt
+IFvYJYzB6q4SMl1/a5uLrcc2frq8tbG0RhU+ZEhWR6sIEOBQhkKZ9LZbJ1tK9buJ
+M0meaIt5gVLAVbI5vf+2Lvmlv0+E/a4Zn2exl1RcBYATNZT1gC55m0z5PMzG6Bc4
+tOAhPEo3WpfNjIrFeXcB0ksk4mfDIWKlA0mc8A+faKSSMdiDpeU4H4uZy5pE/hVv
+2VyE3Ej5PoA3DajRzgQ69YlojTYnfnPyJErCBZhtZXTtRY7aDm9/xBT7FZ06RIhM
+BBgRAgAMBQJC29vxBQkJZgGAAAoJEG6UdZTBUkMakjEAoINKV6yLAdbBhXhvMsqK
+0N6XOghJAJ4mSgdwgv+sIOaPKQqCm+PL2M0lPw==
+=4TlI
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub   1024D/AA0077B0 2006-06-13
+uid                  Kev Jackson (apache key) <kevj@apache.org>
+sig 3        AA0077B0 2006-06-13  Kev Jackson (apache key) <kevj@apache.org>
+sub   2048g/8A6DD738 2006-06-13
+sig          AA0077B0 2006-06-13  Kev Jackson (apache key) <kevj@apache.org>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.1 (Darwin)
+
+mQGiBESOfuoRBADiCLjvY8EG8cDrfNvPaVJr1/8d8GDoLjBCeJWl50M7j1IQDB+r
+rzBPXOzhoqiNRbZMkpjv8ofa5hVOQitVS4B69FA07RbuiQNTKg142h8ogtJeAI1g
+eXuTZtmGE47TOpj7FMG8bHOmoJdQMkzUsdOhEAyqRu4noknuuIKgsE1kYwCgnhaH
+9KBlpKaRG7Bb2BH6da+wmKUEAIaBeZ1aSQodUzDqnGjCd4hZbpzjyWg7O5BylNhK
+ogMY95BvwFRD8WFdSvhvH9VKBtSuNqg/6gIkqAljRRESVxL4QrzlYSqF513kK1ds
+lUTmqU9Dvaf7dkH+MYnkPVTP5tMZVCT7HEt4F6HcqlaZKlz5jsu3R53KBx6XZATc
+SEGbA/wOournJ64We8sXTJGHFupvSLBy3nh68mPLaplzTnH2al1DLBnoF2giC32v
+ZGG+e12kWE+fyyQ3pdAIRHgVjZ/ckPmcmxnVcYrhzbgV99fo2+JRh2SVrLrmvw+G
+CKiUtNHn0HS1klBKSj+3ML1AQQlbyfrcVSf0Fefug51BqoqU+rQqS2V2IEphY2tz
+b24gKGFwYWNoZSBrZXkpIDxrZXZqQGFwYWNoZS5vcmc+iF4EExECAB4FAkSOfuoC
+GwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQoL/5PaoAd7BnTACff9f8Y2RFB7O7
+Wjncyb1XbEwJB/gAninrR0isW9jGx49GmSnQCjtO9k34uQINBESOfzMQCACP+GP2
+x2nE2JxjUUjj16ftOxUivbL8L9ksplx41n7yeRvu+RzOXcjlonuld0LYxprNsHGv
+mbAoZj93QozHQIMfC2kfnia+hxCcBPMbev9RPCqgogpb90BtV0f9HGyWXs2QTgWG
+R2hyjq/RpwtA3obSXw3pb1CnXW4stV65WAdd72KDc66wRR1gmjxKQx6b1dGcC+E4
+HyOgu2CDtr1ULPeI5U4BA4y8FLgDfYwkxp6vj5ViegGP7GlMa3bSgNRGsYX7VwgZ
+pmI8WY4B5k3/Pyv2Toe6/5zTmKH8WlyZd00ede/tbFTqQLg+EylAcWJ8c3asood+
+SjCwTuD8l8a0wpO3AAMHB/9GXkbBUE8cbMTaS4yj7UL5iWRVhSPo9IzMSrzaXmZN
+8ykX96ud35BCEfmYgty3USMk90Rs/PbwB4Mh3h1ZTXqRWcfOXzJ8kMabm2RANyf2
+H2DvGKoFPtpX/9I13vo9qRLRHVRENNg+3JCa1ii8cq7h8bWvTT0VxX/rOG0cl8nO
+XkHTUARR19cGPf6XkHEcl+u1pAxIJGqY/gVowjyFGZs+RXFl/q/Vrgu+lvvxmryd
+yEdeGdsBvQ9M0KKr98w1RiJnDUkSqI711xwlVk14Uu6Xke0oB3bbpe4UxD52avAC
+yEzYY7vbpe6XS2+dOcZxWE3eur6SfsucAkj4Ib72mchhiEkEGBECAAkFAkSOfzMC
+GwwACgkQoL/5PaoAd7BQAwCeJFb9yZvOWfdf73A7t2MvPXn1y6kAnRquMmA5eVdh
+HbAUXWyYuT2OHOSD
+=F2q3
+-----END PGP PUBLIC KEY BLOCK-----
+
+pub  1024D/DE8884A0 2007-04-27 Xavier Hanin <xavier.hanin@gmail.com>
+sig 3       DE8884A0 2007-04-27   Xavier Hanin <xavier.hanin@gmail.com>
+sig         5F298824 2007-05-06   Simon Pepping <spepping@leverkruid.eu>
+sig         A99F75DD 2007-05-03   Rodent of Unusual Size <coar@OpenSource.Org>
+sig         E222DE4F 2007-05-02   Mathias Herberts <Mathias.Herberts@iroise.net>
+sig         911203E4 2007-05-02   [User id not found]
+sig         302DA568 2007-05-03   Rodent of Unusual Size (DSA) <coar@Apache.Org>
+sig         2C312D2F 2007-05-03   Rodent of Unusual Size <coar@OpenSource.Org>
+sig         F12F6072 2007-05-05   Fred Vos <fred.vos@mokolo.org>
+sig 3       311A3DE5 2007-05-05   Ruediger Pluem <rpluem@apache.org>
+sig 3       88817402 2007-05-06   Thomas Vandahl <thomas@vandahl.org>
+sig         01530235 2007-05-02   Luc Maisonobe (SpaceRoots) <luc@spaceroots.org>
+sig         5F6B8B72 2007-05-12   Stefan Bodewig <bodewig@apache.org>
+sig         9C85222B 2007-05-14   Henning Schmiedehausen <hps@intermeta.de>
+sig         4358C584 2007-05-06   Vincent Hennebert <vhennebert@apache.org>
+sig         0B7E6CFA 2007-05-06   Sami Siren <siren@apache.org>
+sig         4CEED75F 2007-05-07   Nick Burch <nick@gagravarr.org>
+sig         40581837 2007-05-08   Nick Kew <nick@webthing.com>
+sig         6BD872A0 2007-05-17   Michael Busch (Lucene Committer) <buschmi@apache.org>
+sig         6210BFC0 2007-05-17   Jean-Frederic Clere <jfclere@apache.org>
+sig 3       990ED4AA 2007-05-06   Knut Anders Hatlen <kahatlen@apache.org>
+sig         0F143BC1 2007-05-22   Matt Hogstrom <matt@hogstrom.org>
+sig         A46C4CA1 2007-05-22   Matt Hogstrom <hogstrom@apache.org>
+sig         152924AF 2007-05-23   Sander Temme <sander@temme.net>
+sub  1024g/A5EB8D3D 2007-04-27
+sig         DE8884A0 2007-04-27   Xavier Hanin <xavier.hanin@gmail.com>
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.3 (MingW32)
+
+mQGiBEYxng4RBACQpDi0ebPGdHVAdV14aK47MzFkFJEbCisBgcZ2OT/pyPjVTN+9
+Q3NtIusVuY/yEeO4+tb+YTbBiwNsx5p91Rder0prBBVPr9TGN8bV81hnSHfVCR+O
+oqrLj2Onv1qsMslOuZR2m1d/i6cFIKV0CV9EWOcEJZ6UEP9CXP29ZzjdRwCg5NgW
+YfergzvpVtON0E5UvjFnGmUD/AoWhJ0CRxw8xj/EAGS4xXO83Ydf6ucu2PwqUOSZ
+N2mMWyBpr12sQH+iMjWJW25GNobwJBKzfvrojujvlU4uyNIyD40sPeH0UrTwLbL/
+Kek9zp9NxZ9wawjzZvdp8sdrOZ54o59/7flAjL3iqJRtLQSeyQsfZaOSNRxsAUiI
+obn3A/9SEtJdF6HM6C7V57WdKIHv6uVocdZNN3zig2T9uP2Uq1VMIEYtllRNX/4V
+9Vq+2KdV72DnlMuZIA++o1n57d/LgUmbDd72AAZGNJaFq39CV9YElXziO7BVOjAg
+MH9kNxCywcjcw8EFa3NCFcOKMESBn5sHu1nw/Iu1Z9TtagnJwrQlWGF2aWVyIEhh
+bmluIDx4YXZpZXIuaGFuaW5AZ21haWwuY29tPoheBBMRAgAeBQJGMZ4OAhsDBgsJ
+CAcDAgMVAgMDFgIBAh4BAheAAAoJEAP2jL3eiISgw0gAoKcAgjjfQWlqnQNRJQ+8
+A7H5ioIZAJ9qApxb1iH8ulGHjiBOjiSgQq0SNohGBBARAgAGBQJGPhhDAAoJED4q
+b8JfKYgkB8AAn28euVJz8OQZvoSw89voHvcVzewGAJ4lm2R0FCSIRfmHCl+5aSYw
+TazeNYicBBABAgAGBQJGOgiqAAoJEJrNPMCpn3Xd8Z8D/1Z/ml/qcIf1yDiYQTu8
+O+/so0ZlfTYlEF6XrW6WjZDIhNVAAT+Rk1E3q+FvZfMq1BV1mubsCXRtcwt1Br3z
+MWIuJ7lBZl+T1Nu2sxH9H7FAvY7Bk8p5WecIaVdNyFxC98vGYAFs0aRRGSeCFbEu
+oW5XXxUAkkWpIT/aG2y3t4G3iEYEEBECAAYFAkY45CgACgkQFUWz/uIi3k/mCwCf
+WUNeKG4a3hgDhMOyZ1FGFpDnle0AnR1yXWaEazJD5wyTtnnSE/Ajk4L3iEYEEBEC
+AAYFAkY46MoACgkQY9CtrpESA+SOtgCeMIh7BKJeSezB+h1JQmUyg6EuNWMAn3pN
+aMYYEj1LL8R/2ZxBNbU9njNXiEYEEBECAAYFAkY6CKoACgkQUI6uxTAtpWhrvwCf
+c2uhmeog5475d9hTQg94MqEo8cEAoJOp95BdZ7xd9ayJwL4LmBVYaIMAiEYEEBEC
+AAYFAkY6CKoACgkQ3bpkuiwxLS9rvwCffwzrqfIJghWUoXhJsa/m/PSLiogAoM3j
+x2xt5sG1sQQbzM+U4VHhRmWAiEYEEBECAAYFAkY8xoUACgkQmHDv8/EvYHKBZgCe
+PkYoQsESFkBkVyiSVueICUvg4G0An3rqc8/Beip9a2YF+7UYsKKJ1e5OiEYEExEC
+AAYFAkY8UYgACgkQTAQoGDEaPeVNwQCdE4UB1RW+mjtYEbgxkZSjdaV3IKgAn1Sy
+hoOrn3S20OhaZht5Y0EksVVEiEYEExECAAYFAkY9o64ACgkQLrlGgoiBdAKz3ACf
+RkJXrvpQVQlk9//+O0W4BvggGxMAoPyvjRXm+Ie+nPAII74kL7croRWsiEYEEBEC
+AAYFAkY4+5AACgkQc92MFgFTAjXIMgCfXfRlxPUwlzLWotr0BGQVK39JXyEAnRht
+cgH/yscqbkvi2JvaVWkV/T9JiEYEEBECAAYFAkZGEjgACgkQohFa4V9ri3KpJwCg
+4v63DT9Ll4+mqnAC1/HWIgSfQ8sAoN+EQ15zUuI0nuSyG6UCw/UUZX82iHEEEBEC
+ADEFAkZIxWEqHEhlbm5pbmcgU2NobWllZGVoYXVzZW4gPGhwc0BpbnRlcm1ldGEu
+ZGU+AAoJEDKGTkGchSIrkUgAnjI6jBaidqIjKhusVm6ihmG6LEIdAJwJnc6YRNyY
+88MWtd0XRghD6ST174hGBBARAgAGBQJGPfdgAAoJEKBy1NBDWMWEYEYAn0RS69vJ
+1EVod7WxAecb0F4tyJcBAJsEnTiTRMoNmJmRe6w3WqhqdLQUeYhGBBARAgAGBQJG
+PhN/AAoJEAKlpgULfmz6aJIAmwcQI5XDWrLDzSFRJFuW3F1zl7P0AJ9GQYDvu4mI
+c9ZCcaLdukbY2e6FGIhGBBARAgAGBQJGPyoEAAoJEPXCYBZM7tdfbQ8AoJVSPa3g
+Cmc5ghLz1X12r/QBHPPKAJsH6g/0hcAou2ZUfVhOE7VJhpeGkohGBBARAgAGBQJG
+QLz1AAoJEG0LxzpAWBg3cXAAoI2rKauHeIDRwh05S8iNGKTtEaPMAKCMHrqbLsbl
+0P7XxTpZ4EKSvOkQ6IhGBBARAgAGBQJGTEaDAAoJEB8hI8Nr2HKgtRoAnReqmHxs
+MbATTtCEF+WbTqREe1+JAJ9pM5VmM/Apfh1hPM8i55Q96BP1h4hGBBARAgAGBQJG
+TIFwAAoJEA9FCiZiEL/A4j0AnAsAjAu6nDTd73TM3S80JtbuatX8AJ0WBRJk5ZZI
+TmnMyz2yp6k57tyeRohGBBMRAgAGBQJGPbLbAAoJEOHh8rCZDtSqCOQAn0SVan9j
+r55MJrDGk8D3M5pQvTd8AJ9uU45i0OQUP+zY5LSacNtOzSy6MIhGBBARAgAGBQJG
+Una1AAoJEDLB1u8PFDvBK+EAoMjrujpsE1XQs3YxDwz5HHSWv9E7AKCJLU0W2MbF
+OIgs9Smxz2LbuYH7lIhGBBARAgAGBQJGUnbGAAoJEMuuvjmkbEyh9uMAoJ2fBgZo
+2kl+jOzhQnXHHDHzyLyAAKCR8Z6tloKXkhPRIV/N/OjwIW0i54ipBBARAgBpBQJG
+U8qkIBxTYW5kZXIgVGVtbWUgPHNhbmRlckB0ZW1tZS5uZXQ+IhxTYW5kZXIgVGVt
+bWUgPHNjdGVtbWVAYXBhY2hlLm9yZz4eHFNhbmRlciBUZW1tZSA8c2FuZGVyQG1h
+Yy5jb20+AAoJELK+vEAVKSSveJAAniq8wB4b/DdGTK9Ygmu5Y76tqsw/AJsHGkn3
+5JyiHbXCvVujWmPtY1/OZbkBDQRGMZ4PEAQA+T0YRtd2aeXU+AOJnrhChy0dptVt
+CE6PW9LrwZGqeV4THNWhdYuWRWlyzgU4HSfuk1Svu3WKMbnwp+Fv8fU6MmidOvEJ
+p9IV1l4DidIXyhAacwpCN11hXvj5cHdF4KhJr/NG9oedin6nQoQFRQ7EfkUjAXOf
+MCZnSps9XBJdy3cAAwUEAIGrITayVmWfUgjPvQg8L+4R2i31XQ70HIELQtYDs0Ln
+iWrwZuO+aLI6Jw1RbZii6DM2QsVdZj+v36S2KJTvXeJVyb51d0uXYFxre1uCZrb2
+I1Lle8v3GVQvlrTpmZIPhOTotskKFWUCh2jqgLaEvJPpRWgIRXPF4g12nBXcLLXE
+iEkEGBECAAkFAkYxng8CGwwACgkQA/aMvd6IhKDVtQCeKdUGQS0lD0nAJsGiSbKg
+gLwEM0sAn0dUIIsbxE0fTHQVIQK4bII82UhZ
+=jwNf
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/trunk/LICENSE b/trunk/LICENSE
new file mode 100644
index 0000000..cdf6ff8
--- /dev/null
+++ b/trunk/LICENSE
@@ -0,0 +1,272 @@
+/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+
+W3C® SOFTWARE NOTICE AND LICENSE
+http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+This work (and included software, documentation such as READMEs, or other
+related items) is being provided by the copyright holders under the following
+license. By obtaining, using and/or copying this work, you (the licensee) agree
+that you have read, understood, and will comply with the following terms and
+conditions.
+
+Permission to copy, modify, and distribute this software and its documentation,
+with or without modification, for any purpose and without fee or royalty is
+hereby granted, provided that you include the following on ALL copies of the
+software and documentation or portions thereof, including modifications:
+
+  1. The full text of this NOTICE in a location viewable to users of the
+     redistributed or derivative work. 
+  2. Any pre-existing intellectual property disclaimers, notices, or terms
+     and conditions. If none exist, the W3C Software Short Notice should be
+     included (hypertext is preferred, text is permitted) within the body
+     of any redistributed or derivative code.
+  3. Notice of any changes or modifications to the files, including the date
+     changes were made. (We recommend you provide URIs to the location from
+     which the code is derived.)
+     
+THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE
+NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT
+THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
+PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
+
+COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENTATION.
+
+The name and trademarks of copyright holders may NOT be used in advertising or
+publicity pertaining to the software without specific, written prior permission.
+Title to copyright in this software and any associated documentation will at
+all times remain with copyright holders.
+
+____________________________________
+
+This formulation of W3C's notice and license became active on December 31 2002.
+This version removes the copyright ownership notice such that this license can
+be used with materials other than those owned by the W3C, reflects that ERCIM
+is now a host of the W3C, includes references to this specific dated version of
+the license, and removes the ambiguous grant of "use". Otherwise, this version
+is the same as the previous version and is written so as to preserve the Free
+Software Foundation's assessment of GPL compatibility and OSI's certification
+under the Open Source Definition. Please see our Copyright FAQ for common
+questions about using materials from our site, including specific terms and
+conditions for packages like libwww, Amaya, and Jigsaw. Other questions about
+this notice can be directed to site-policy@w3.org.
+ 
+Joseph Reagle <site-policy@w3.org> 
+
+This license came from: http://www.megginson.com/SAX/copying.html
+  However please note future versions of SAX may be covered 
+  under http://saxproject.org/?selected=pd
+
+SAX2 is Free!
+
+I hereby abandon any property rights to SAX 2.0 (the Simple API for
+XML), and release all of the SAX 2.0 source code, compiled code, and
+documentation contained in this distribution into the Public Domain.
+SAX comes with NO WARRANTY or guarantee of fitness for any
+purpose.
+
+David Megginson, david@megginson.com
+2000-05-05
diff --git a/trunk/NOTICE b/trunk/NOTICE
new file mode 100644
index 0000000..4c88cc6
--- /dev/null
+++ b/trunk/NOTICE
@@ -0,0 +1,26 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Ant distribution.                      ==
+   =========================================================================
+
+   Apache Ant
+   Copyright 1999-2008 The Apache Software Foundation
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   This product includes also software developed by :
+     - the W3C consortium (http://www.w3c.org) ,
+     - the SAX project (http://www.saxproject.org)
+
+   The <sync> task is based on code Copyright (c) 2002, Landmark
+   Graphics Corp that has been kindly donated to the Apache Software
+   Foundation.
+
+   Portions of this software were originally based on the following:
+     - software copyright (c) 1999, IBM Corporation., http://www.ibm.com.
+     - software copyright (c) 1999, Sun Microsystems., http://www.sun.com.
+     - voluntary contributions made by Paul Eng on behalf of the 
+       Apache Software Foundation that were originally developed at iClick, Inc.,
+       software copyright (c) 1999.
diff --git a/trunk/README b/trunk/README
new file mode 100644
index 0000000..9510941
--- /dev/null
+++ b/trunk/README
@@ -0,0 +1,97 @@
+
+                                 A     N     T
+ 
+
+  What is it? 
+  -----------
+  
+  Ant is a Java based build tool. In theory it is kind of like "make" 
+  without makes wrinkles and with the full portability of pure java code.
+
+  
+  Why?
+  ----
+  
+  Why another build tool when there is already make, gnumake, nmake, jam, 
+  and others? Because all of those tools have limitations that its original 
+  author couldn't live with when developing software across multiple platforms. 
+  
+  Make-like tools are inherently shell based. They evaluate a set of 
+  dependencies and then execute commands not unlike what you would issue on a 
+  shell. This means that you can easily extend these tools by using or writing 
+  any program for the OS that you are working on. However, this also means that 
+  you limit yourself to the OS, or at least the OS type such as Unix, that you 
+  are working on.
+  
+  Makefiles are inherently evil as well. Anybody who has worked on them for any 
+  time has run into the dreaded tab problem. "Is my command not executing 
+  because I have a space in front of my tab!!!" said the original author of Ant 
+  way too many times. Tools like Jam took care of this to a great degree, but 
+  still use yet another format to use and remember.
+  
+  Ant is different. Instead a model where it is extended with shell based 
+  commands, it is extended using Java classes. Instead of writing shell 
+  commands, the configuration files are XML based calling out a target tree 
+  where various tasks get executed. Each task is run by an object which 
+  implements a particular Task interface.
+  
+  Granted, this removes some of the expressive power that is inherent by being 
+  able to construct a shell command such as `find . -name foo -exec rm {}` but 
+  it gives you the ability to be cross platform. To work anywhere and 
+  everywhere. And hey, if you really need to execute a shell command, Ant has 
+  an exec rule that allows different commands to be executed based on the OS 
+  that it is executing on.
+
+  The Latest Version
+  ------------------
+
+  Details of the latest version can be found on the Apache Ant
+  Project web site <http://ant.apache.org/>.
+
+
+  Documentation
+  -------------
+
+  Documentation is available in HTML format, in the docs/ directory.
+  For information about building and installing Ant, see
+  docs/manual/index.html
+
+
+  Licensing
+  ---------
+
+  This software is licensed under the terms you may find in the file 
+  named "LICENSE" in this directory.
+  
+  This distribution includes cryptographic software.  The country in 
+  which you currently reside may have restrictions on the import, 
+  possession, use, and/or re-export to another country, of 
+  encryption software.  BEFORE using any encryption software, please 
+  check your country's laws, regulations and policies concerning the
+  import, possession, or use, and re-export of encryption software, to 
+  see if this is permitted.  See <http://www.wassenaar.org/> for more
+  information.
+
+  The U.S. Government Department of Commerce, Bureau of Industry and
+  Security (BIS), has classified this software as Export Commodity 
+  Control Number (ECCN) 5D002.C.1, which includes information security
+  software using or performing cryptographic functions with asymmetric
+  algorithms.  The form and manner of this Apache Software Foundation
+  distribution makes it eligible for export under the License Exception
+  ENC Technology Software Unrestricted (TSU) exception (see the BIS 
+  Export Administration Regulations, Section 740.13) for both object 
+  code and source code.
+
+  The following provides more details on the included cryptographic
+  software:
+
+  For the SSH family of tasks (<sshexec> and <scp>) Ant requires the
+  JSch <http://www.jcraft.com/jsch/index.html> library as well as the
+  Java Cryptography extensions
+  <http://java.sun.com/javase/technologies/security/>.  Ant does not
+  include these libraries itself, but is designed to use them.
+
+  Thanks for using Ant.
+
+                                          The Apache Ant Project
+                                         <http://ant.apache.org/>
diff --git a/trunk/ReleaseInstructions b/trunk/ReleaseInstructions
new file mode 100644
index 0000000..1442770
--- /dev/null
+++ b/trunk/ReleaseInstructions
@@ -0,0 +1,265 @@
+Instructions for making a Release:
+
+Authors: Conor MacNeill
+         Stefan Bodewig
+         Magesh Umasankar
+         Antoine Levy-Lambert
+
+Note: This document was updated in the context of releasing Ant 1.7.
+      Please interpret the branch names, tags, etc. according to
+      your context.
+
+1.  Propose a release plan for vote.  This should set out the timetable for
+    the release under ideal circumstances.  
+
+    The issue of whether to create a branch for the release should be discussed
+    in the release vote.
+
+    The level of bugs reported  can delay things. Generally, give a few weeks to 
+    "close" the source tree to further changes so people can finalise 
+    contributions, etc. At this time, the first beta will be cut and there will be 
+    then a period of beta testing, usually 1 month but this should be flexible.
+
+2.  Note that any mention of a deadline causes a flood of bug fixes, new tasks,
+    etc.  This needs to be managed as best it can. Some fixes will be applied,
+    others held over. Make this clear in the release plan. The committers and
+    particularly the release manager will need to make judgement calls here.
+    Anything too "big" is likely to be held over.
+
+3.  Once the freeze date arrives, create a branch for the release builds,
+    if this was decided in the release vote. This was done for Ant 1.6, 
+    but not for Ant 1.7. 
+
+    You will need to be comfortable in handling SVN branches with multiple
+    merge-backs to the main branch and even selected merges from the the main
+    branch to the release branch.
+
+    For more information on performing branching and merging, please visit
+    http://svnbook.red-bean.com/nightly/en/svn-book.html
+
+    Label such branches ANT_16_BRANCH.
+
+4.  Once the branch is setup, the version numbers in SVN are changed. On the
+    branch, the project.version property in build.xml becomes 1.7Beta.
+
+    If there were a main branch, its build.xml would have 1.8alpha.
+
+    [[ TODO: Check if the documentation files also need to be updated to point
+    to the right areas of Ant's website. ]]
+
+5.  Before a build :
+
+    the first beta on the 1.7 branch has been called 1.7.0Beta1, ...
+
+    the project.version property in build.xml governs the output of ant -version and
+    the naming of the distribution files.
+
+    Update the following files for version number:
+
+        On the branch only :
+
+            * docs/manual/cover.html
+            * docs/manual/credits.html
+            * build.xml (version property & manifest-version property)
+
+        Commit your changes.
+
+        On the branch and on the main trunk (*):
+
+            * WHATSNEW
+            * xdocs/antnews.xml (Announcement)
+            * xdocs/faq.xml (Ant's history details - not for betas)
+            * xdocs/index.xml (Announcement, latest release details, link to
+            manual under "Documentation")
+            * xdocs/srcdownload.xml
+            * xdocs/bindownload.xml
+
+        Generate the html files by invoking ant on docs.xml
+        (use -projecthelp for instructions).
+        Commit the modified/generated files
+
+6.  Ensure you have all the external libraries that Ant uses in your
+    lib/optional directory.  To find out what libraries you need, execute
+    the build with -verbose option and scan for lines beginning with
+    "Unable to load...".
+
+7.  Make sure that your directory tree is clean by running svn status.
+    Some tests leave behind leftovers which end up in the source distribution otherwise.
+
+8.   Next bootstrap, build and run the tests.  Then build the distribution
+    on the branch. It is important that this be a clean build. Label this with
+    a tag ANT_170_B1.
+
+    C:\dev\asf\ant-core>
+    svn copy https://svn.apache.org/repos/asf/ant/core/trunk \
+    https://svn.apache.org/repos/asf/ant/core/tags/ANT_170_B1 \
+    -m "Tagging version 1.7.0Beta1 of Ant"
+
+    Revision 437509 ?\195?\188bertragen.
+
+9.  Sign the distribution files using the following simple script
+    #!/bin/sh
+    for i in `/usr/bin/find distribution \( -name "*.bz2" -o -name  "*.zip" -o -name "*.gz" \)`
+    do
+         echo "Signing " $i
+         gpg -a -b --force-v3-sigs $i
+    done
+
+    The --force-v3-sigs will improve the interoperability with PGP 5.x,
+    see <http://www.gnupg.org/(en)/documentation/faqs.html#q5.5>.
+
+    Before you do that, ensure that the key you use is inside the KEYS
+    file in Ant's SVN repository - and that you perform a svn update on
+    the KEYS file in /www/www.apache.org/dist/ant/
+
+    Also make sure you have sent the key that you use to a public
+    keyserver.
+
+10. The beta distribution is now ready to go. Bundle it up into a tar.gz file
+    and scp to your apache account.
+
+11. Meanwhile, convert the part of the WHATSNEW file covering the changes
+    since the last release into HTML for the README file on the
+    website. See the previous release directories for examples of these files.
+    Add instructions and warnings (GNU tar format issues, etc).
+
+    You may choose to use the text2html convertor present at
+    http://txt2html.sourceforge.net/#test
+
+    Name the generated file RELEASE-NOTES-x.y.z.html.
+
+    Change the title to something like "Release Notes of Apache Ant 1.7.0Beta2" (from the default txt2html)
+
+    [[ TODO: This must perhaps be an Ant task. ]]
+
+12. Once this is uploaded, unpack things, create the release directory,
+    something like v1.7.0Beta1, push the release and RELEASE-NOTES files
+    into this directory.  Create a symbolic link named README.html
+    that points to the RELEASE-NOTES.
+
+    The files should go to /www/people.apache.org/dist/ant/ on people.apache.org.
+
+13. Address the available release tags in BugZilla. Create a new tag 1.7.0Beta1.
+    If there is a separate main branch, create a 1.8alpha tag.
+    Assign all existing 1.7 alpha bugs to 1.7.0Beta1.
+    Note that such massive changes can be done at once by choosing the
+    link "Change several bugs at once" at the bottom of the bug list
+    displaying the 1.7alpha bugs.
+
+14. Once that is done, do a test download to make sure everything is OK. A
+    common problem may be:
+    * the file's mime type is not recognized and is interpreted as
+      text/plain.  Fix it by using some .htaccess magic (AddEncoding stuff)
+    * Your gz.asc files are not being displayed properly (RemoveEncoing stuff)
+
+    If it looks OK, announce it on dev@ant and user@ant. After a few
+    days pass and there are no major problems, a wider announcement is
+    made (ant website, main jakarta website, announcements@jakarta.apache.org,
+    etc).
+
+    and also perform a svn update on files in people.apache.org's
+    /www/ant.apache.org/
+
+    you also need to checkout parallel to ant-core https://svn.apache.org/repos/asf/ant/site
+    then go to the subdirectory generated
+    svn propedit svn:externals to change the location of the manual
+
+    Announce beta releases at freshmeat.net (Stefan Bodewig is the
+    owner of Ant's project entry - bug him ;-).
+
+15. As problems in the beta are discovered, there may be a need for
+    one or more subsequent betas. The release manager makes this
+    call. Each time, the versions are updated and the above process is
+    repeated. Try not to have too many betas.
+
+16. Try to advertise the need for testing of the betas as much as possible.
+    This would eliminate the need to release minor patch versions like
+    we had to do when releasing Ant 1.4.
+
+    To monitor the number of downloads, look at the access_log
+    file under /usr/local/apache2/logs
+
+17. When the final beta is considered OK, propose a vote on dev@ant to
+    officially adopt the latest beta as the Ant 1.6 release. If it is passed,
+    (it usually does,) this would be labelled ANT_16 and built in a similar
+    fashion to the above process.
+
+18. BUT
+
+    This time the directory you upload the files to is different and
+    you'll have to do some house-keeping for the old release:
+
+    * upload the new release files to
+
+      from distribution
+      to   /www/www.apache.org/dist/ant/[source|binaries].
+      
+      and 
+
+      from java-repository/org.apache.ant
+      to   /www/people.apache.org/repo/m1-ibiblio-rsync-repository/org.apache.ant
+
+      this can be done using the target upload of the build.xml
+
+    * remove the symbolic links from /www/www.apache.org/dist/ant.
+
+    * Create proper -current symlinks in /www/www.apache.org/dist/ant/
+
+    * Make sure that the symbolic link README.html points to the new
+      RELEASE-NOTES.
+
+    (**)
+
+19. Update the ant.apache.org site :
+
+    running svn update *.html under /www/ant.apache.org should update the
+    files regenerated and committed in point 5 above (index.html, faq.html,
+    antnews.html, srcdownload.html, bindownload.html).
+
+    Update the online manual too.
+
+20. Clean up.
+
+    * remove the remaining files of the previous release from
+      /www/www.apache.org/dist/ant/[source|binaries].
+      This includes the old release notes.
+
+21. Now and perhaps during previous betas any changes on the branch must
+    be merged back into the tree.
+
+22. At this point in time, the release is done and announcements are made.
+    PGP-sign your announcement posts.
+
+    [[TODO: Identify the mailing lists where announcements are to be made.
+      Also identify the webpages to which the announcements must go. ]]
+
+    Apache mailing lists that should get the announcements:
+    announcements@jakarta.apache.org, announcements@xml.apache.org,
+    announce@apache.org, dev@ant and user@ant.
+
+    Announce release at freshmeat.net
+    (Stefan Bodewig is the owner of Ant's project entry - bug him ;-).
+
+    Announce release in the usenet groups comp.lang.java.softwaretools
+    and comp.lang.java.announce.
+
+23. You can now reacquaint yourself with your family and friends.
+
+(*)  the xdocs need to be updated on both the branch and the HEAD revision
+     because traditionally the ant.apache.org web site reflects the HEAD
+     revision of the xdocs, but the users downloading a distribution will get
+     the xdocs and the generated html from the branch and will complain if there
+     are discrepancies in version numbers.
+
+(**) Mirrors : the srcdownload.html and bindownload.html each list a number of
+     mirrors. For ant 1.6.0 the mirrors picked up the new version in 8 hours
+     or less, the release having been done at midnight on Dec 18th, the
+     mirrors had it on Dec 19th at 8 am. The srcdownload/bindownload pages both
+     contain a note advising users to be patient immediately after the release.
+
+Related Information
+
+http://www.apache.org/dev/release-publishing.html
+http://jakarta.apache.org/commons/releases/
+http://wiki.apache.org/jakarta-commons/SigningReleases
+
diff --git a/trunk/STATUS b/trunk/STATUS
new file mode 100644
index 0000000..edaed93
--- /dev/null
+++ b/trunk/STATUS
@@ -0,0 +1,24 @@
+Apache Ant Status
+Last modified at 2007-08-03
+
+Release:
+    Current:        1.7.0  (in SVN ANT_17_BRANCH)
+    Maintenance:    -
+    Development:    1.7.1  (in SVN ANT_17_BRANCH)
+                    1.8    (in SVN HEAD)
+
+Assets:
+    DNS:                ant.apache.org
+
+    Mailing lists:      dev@ant.apache.org
+                        user@ant.apache.org
+
+    Web site:           http://ant.apache.org/
+
+    Repositories:       ant
+
+PMC Members
+ see http://ant.apache.org/contributors.html
+
+Committers:
+ see http://ant.apache.org/contributors.html
diff --git a/trunk/WHATSNEW b/trunk/WHATSNEW
new file mode 100644
index 0000000..5836e81
--- /dev/null
+++ b/trunk/WHATSNEW
@@ -0,0 +1,4004 @@
+Changes from Ant 1.7.x TO current SVN version
+=============================================
+
+Changes that could break older environments:
+-------------------------------------------
+
+* Improved handling of InterruptException (lets suppose someone/thing is
+  trying to kill the thread when we receive an InterruptException),
+  when an InterruptException is received, we do not wait anymore in a while
+  loop till the end time has been reached. Bugzilla report 42924.
+
+* Refactor PropertyHelper and introspection APIs to make extension more
+  granular and support setting task/type attribute values to objects
+  decoded by custom PropertyEvaluator delegates. Also add <propertyhelper>
+  task for registering delegates and/or replacing the registered PropertyHelper
+  instance.  Bugzilla report 42736.
+
+* Added a restricted form of typedef called <componentdef>. This allows
+  definition of elements that can only be within tasks or types. This
+  method is now used to define conditions, selectors and selectors. This
+  means that tasks may now have nested conditions just by implementing
+  the Condition interface, rather than extending ConditionBase. It also
+  means that the use of namespaces for some of the selectors introduced
+  in Ant 1.7.0 is no longer necessary.
+  Implementing this means that the DynamicElement work-around introduced
+  in Ant 1.7.0 has been removed.
+  Bugzilla report 40511.
+
+* In the <touch> task when a <mapper> is used, the millis and datetime
+  attributes now override the time of the source resource if provisioned. 
+  Bugzilla report 43235.
+
+* Remove fall-back mechanism for references that are not resolved
+  during normal runtime execution.
+
+* FileUtils.createTempFile now actually creates the file.
+  The TempFile task still does not create the file by default, can be instructed
+  to do so however using a new parameter.
+  Bugzilla report 33969.
+  
+Fixed bugs:
+-----------
+
+ * <symlink> task couldn't overwrite existing symlinks that pointed to nonexistent files
+   Bugzilla report 38199.
+
+ * <symlink> task couldn't overwrite files that were in the way of the symlink.
+   Bugzilla report 43426.
+   
+ * <symlink> task failonerror="false" does not stop build from failing when 'ln' 
+   command returns non-zero. Bugzilla report 43624  
+
+ * <touch> task couldn't differentiate between "no resources specified" and "no resources
+   matched."  Bugzilla report 43799.
+   
+Other changes:
+--------------
+
+ * There is now a FileProvider interface for resources that act as a source
+   of filenames. This should be used by tasks that require resources
+   to provide filenames, rather than require that all resources
+   are instances or subclasses of FileResource
+   Bugzilla report 43348
+   
+ * Fixcrlf now gives better error messages on bad directory attributes.
+   Bugzilla report 43936
+   
+
+
+Changes from Ant 1.7.0 TO Ant 1.7.1
+=============================================
+
+Changes that could break older environments:
+-------------------------------------------
+
+* String resources only have properties single expanded. If you relied on
+  <string> resources being expanded more than once, it no longer happens.
+  Bugzilla report 42277.
+
+* A String resource's encoding attribute was only taken into account when
+  set from the resource's OutputStream; the InputStream provided the String's
+  binary content according to the platform's default encoding. Behavior has
+  been modified to encode outgoing (InputStream) content as well as encoding
+  incoming (OutputStream) content.
+
+* <scriptcondition> now prefers evaluation result/return value over value property.
+
+* <java> with fork now returns gives -1 instead of 0 as result when failonerror
+  is false and some exception (including timeout) occurs. Br 42377. 
+
+* ant-type attribute has been marked as deprecated and a warning has been
+  issued if it is encountered in the build file.
+
+Fixed bugs:
+-----------
+
+* The default logger was failing to print complete stack traces for exceptions
+  other than BuildException, thus omitting often important diagnostic
+  information. Bugzilla 43398.
+
+* Error in FTP task
+  Bugzilla report 41724
+
+* Regression: Locator fails with URI encoding problem when spaces in path
+  Bugzilla report 42222
+
+* Regression in Locator: running Ant off a network share does not work:
+  message "URI has authority component" appears
+  Bugzilla report 42275
+
+* Improvements in AntClassLoader Speed.
+  Bugzilla report 42259
+
+* Error in handling of some permissions, most notably the AllPermission on
+  jdk 1.5
+  Bugzilla report 41776
+
+* Replace task summary output incorrect.
+  Bugzilla report 41544
+
+* Dependset crashes ant when timestamp on files change during Dependset
+  execution.
+  Bugzilla report 41284
+
+* Bug in org.apache.tools.ant.types.resources.comparators.Date
+  Bugzilla report 41411
+
+* <junit> in Ant 1.7.0 could throw NPE if no <classpath> was defined.
+  Bugzilla report 41422.
+
+* In Ant 1.7.0, <fileset> in <javadoc> does not by default include only
+  **/*.java as the documentation claims and earlier revisions did.
+  Bugzilla report 41264.
+
+* SPI support in jar was broken.
+  Bugzilla report 41201.
+  
+* jsch-0.1.30 causes SCP task to hang
+  Bugzilla report 41090.
+
+* Target from imported file listed twice in projecthelp.
+  Bugzilla report 41226.
+
+* <sql> task double-expands properties if expandproperties is true,
+  and expands properties if expandproperties is false.
+  Bugzilla report 41204.
+
+* Rolling back Bugzilla 32927 (set a default description for a javadoc tag
+  if not set) as it caused a BC problem.
+  Bugzilla report 41268.
+
+* <apt> forks properly and so memory settings are picked up.
+  Bug report 41280.
+
+* Regression: NPE was thrown when using <pathconvert> against a
+  (third-party instantiated) fileset with null Project reference.
+
+* Strip out all -J arguments to non forking rmic adapters, specifically
+  the Sun and Weblogic compilers.
+  Bug report 41349
+
+* Synchonization issues in PropertyHelper.  Bugzilla 41353.
+
+* <concat binary="true" append="true"> did not append.  Bugzilla 41399.
+ 
+* -autoproxy turns Java1.5+ automatic proxy support on. Bugzilla 41904
+
+* Handle null result of system getProperty(). Bugzilla 42334.
+
+* Regression: concat fixlastline="true" should not have applied to
+  nested text, but did in Ant 1.7.0. Bugzilla 42369.
+
+* Regression: ant.version was not passed down in <subant>.
+  This worked in Ant1.6.5, but not in 1.7.0. Bugzilla bug 42263
+
+* Regression: bzip2 task created corrupted output files for some inputs.
+  Bugzilla bug 41596.
+
+* Regression: <available> with <filepath> did not work.
+  Bugzilla 42735.
+
+* ant script, cd may output to stdout.
+  Bugzilla 42739.
+
+* Modified selector doesn't update the cache if only one file has changed.
+  Bugzilla 42802.
+
+* Regression: Path subclasses that overrode list() stopped working in
+  resourceCollection contexts in Ant 1.7.0. Bugzilla 42967.
+
+* <property> supports loading from xml based property definition.
+  Bugzilla 42946
+
+* <junit> supports collecting and rerunning failed test cases
+  (textXXX methods). Bugzilla 42984.  
+
+* War task failed with "No WEB-INF/web.xml file was added" when called
+  a second time. Bugzilla 43121.
+
+* FilterMapper could throw an NPE.
+  Bugzilla 43292.
+
+* Regession nested macrodefs with elements could cause StackOverFlow.
+  Bugzilla 43324.
+
+* Some changes to <junit> broke third party tasks that extend it (like
+  Apache Cactus' Ant task).  The changes have been modified so that
+  subclases should now work again - without any changes to the
+  subclass.
+
+Other changes:
+--------------
+
+* Various small optimizations speed up common tasks such as <javac> on large
+  filesets, reducing both I/O and CPU usage.
+
+* Profiling logger has been added with basic profiling capabilities.
+
+* <script> now has basic support for JavaFX scripts
+
+* SSH task can now take a command parameter containing the commands to execute.
+  This allows you to connect to a server and execute a number of commands
+  without constantly reconnecting for each command.
+
+* Upgraded XML API to XML commons version 1.3.04.
+
+* Upgraded to Xerces 2.9.0
+
+* <script> can now work with bsf.jar and js.jar in its <classpath>.
+
+* add errorProperty and updatedProperty to <javac>
+  Bugzilla 35637 and 28941.
+
+* add classpathref attribute to <whichresource>
+  Bugzilla 41158.
+
+* reduce logging noise of <apply skipemptyfilesets="true">
+  Bugzilla 29154
+
+* Show Previous Revision in the tagdiff.xsl stylesheet
+  Bugzilla 29143
+
+* Allow <mapper refid> to refer directly to a FileNameMapper instance.
+
+* If you try and use a type in a namespace (or an antlib), and the type is not
+  recognized but there are other definitions in that namespace, Ant lists what
+  the known definitions are. This helps you find spelling errors.
+
+* Add a <last> resource collection, corresponding to <first>.
+
+* Add new <truncate> task.
+
+* <junitreport> xsl stylesheets allow setting the title used in <title> and <h1> tags by
+  using <report><param> element.  Bugzilla 41742.
+
+* Add IgnoreDependenciesExecutor for weird cases when the user wants to run
+  only the targets explicitly specified.
+
+* Patternset allows nested inverted patternsets using <invert>.
+
+* <manifest> checks for validity of attribute names.
+
+* JUnitVersionHelper.getTestCaseClassName is now public. Bugzilla 42231
+
+* <string> resource supports nested text. Bugzilla bug 42276
+
+* <scriptdef> now sources scripts from nested resources/resource collections. This lets you
+  define scripts in JARs, remote URLs, or any other supported resource. Bugzilla report 41597.
+
+* <concat> is now usable as a single-element ResourceCollection.
+
+* It is now possible to provide the value of a <striplinecomments> filter's
+  <comment> nested element as nested text instead of using the 'value'
+  attribute.
+
+* A new logger, BigProjectLogger, lists the project name with every target   
+
+* Default text added to macrodef. Bugzilla report 42301.
+
+* "rawblobs" attribute added to SQL task.
+
+* Add new retry task container.
+
+* <jar> has a new strict attribute that checks if the jar complies with
+  the jar packaging version specification.
+
+* <javac> has a new attribute - includeDestClasses.
+  Bugzilla 40776.
+
+* <fileset> has a new attribute - errorOnMissingDir.
+  Bugzilla 11270.
+
+* <javac> handles package-info.java files, there were repeatedly compiled.
+  Bugzilla 43114.
+
+Changes from Ant 1.6.5 to Ant 1.7.0
+===================================
+
+Changes that could break older environments:
+-------------------------------------------
+
+* Initial support for JDK 6 (JSR 223) scripting.
+  <*script*> tasks will now use javax.scripting if BSF is
+  not available, or if explicitly requested by using
+  a "manager" attribute.
+
+* Removed launcher classes from nodeps jar.
+
+* <classconstants> filter reader uses ISO-8859-1 encoding to read
+  the java class file. Bugzilla report 33604.
+
+* Defer reference process. Bugzilla 36955, 34458, 37688.
+  This may break build files in which a reference was set in a target which was
+  never executed. Historically, Ant would set the reference early on, during parse
+  time, so the datatype would be defined. Now it requires the reference to have
+  been in a bit of the build file which was actually executed. If you get
+  an error about an undefined reference, locate the reference and move it somewhere
+  where it is used, or fix the depends attribute of the target in question to
+  depend on the target which defines the reference/datatype.
+  As a result of testing on real live build scripts, a fall-back mechanism
+  was put it place to allow references that are out-of-band to be resolved. If
+  this happens a big warning message is logged. This fall-back mechanism will
+  be removed in Ant 1.8.0.
+
+* <script> and <scriptdef> now set the current thread context.
+
+* Unrestrict the dbvendor names in the websphere element of the ejbjar task.
+  Bugzilla Report 40475.
+
+* <env> nested element in <java>, <exec> and others is now case-insensitive
+  for windows OS. Bugzilla Report 28874.
+
+* Removed support for xalan1 completely. Users of Xalan1 for Ant builds will
+  have to stay at ant 1.6.5 or upgrade to xalan2.
+
+* Use org.apache.log4j.Logger instead of org.apache.log4j.Category.
+  Category has been deprecated for ~2 years and has been removed from
+  the log4j code.  Logger was introduced in log4j 1.2 so users of
+  log4j 1.1 and log4j 1.0 need to upgrade to a newer version of log4j.
+  Bugzilla Report 31951.
+
+* build.sysclasspath now also affects the bootclasspath handling of
+  spawned Java VMs.  If you set build.sysclasspath to anything other
+  than "ignore" (or leave it unset, since "ignore" is the default when
+  it comes to bootclasspath handling), then the bootclasspath of the
+  VM running Ant will be added to the bootclasspath you've specified.
+
+* The <java fork="false"> now as per default installs a security manager
+  using the default permissions. This is now independent of the
+  failonerror attribute.  Bugzilla report 33361.
+
+* <signjar> now notices when the jar and signedjar are equal, and switches
+  to the same dependency logic as when signedjar is omitted. This may break
+  something that depended upon signing in this situation. However, since
+  invoking the JDK jarsigner program with -signedjar set to the source jar
+  actually crashes the JVM on our (Java1.5) systems, we don't think any
+  build files which actually worked will be affected by the change.
+
+* <signjar> used to ignore a nested fileset when a jar was also provided as an
+  attribute, printing a warning message; now it signs files in the fileset.
+
+* An improved method of handling timestamp granularity differences between
+  client and server was added to the <ftp> task.  FTP servers typically
+  have HH:mm timestamps whereas local filesystems have HH:mm:ss timestamps.
+  Previously, this required tweaking with the timediffmillis attribute
+  which also was used to handle timezone differences.  Now, there is a new
+  timestampgranularity attribute.  The default value for get operations is 0
+  since the user has the more powerful preservelastmodified attribute to work
+  with.  Since this is not available on put operations the default value
+  adds a minute to the server timestamp in order to account for this,
+  Scripts which previously used timediffmillis to do this compensation may
+  need to be rewritten.  timediffmillis has now been deprecated.
+
+* Support for the XSL:P XML parser has been removed.
+  Bugzilla Report 23455.
+
+* Visual Age for Java optional tasks removed as the required library is no
+  longer available.
+
+* Testlet (test) optional task removed as the required library is no
+  longer available.
+
+* IContract optional task removed as the required library is no
+  longer available.
+
+* Metamata (maudit, mmetrics, and mparse tasks) removed as the required 
+  library is no longer available.
+
+* Sitraka (jpcoverage, jpcovmerge, jpcovreport) tasks suppressed as the 
+  required library is no longer available.
+
+* <fixcrlf> used \r (Mac) line endings on OS X, whose proper line separator
+  is \n (Unix).  Bugzilla report 39585.
+
+* <scp> now optionally supports the sftp protocol, you may need a
+  newer jsch.jar.  Bugzilla Report 39373.
+
+* Ant launcher program prints errors to stderr, and exits with a 2 exit code
+  value if, for any reason, it cannot actually start Ant proper. This will only
+  affect programs/scripts that called the launcher and which did not want to
+  receive an error if Ant itself would not start
+
+* All .NET tasks are now deprecated in favor of the new .NET Antlib:
+  http://ant.apache.org/antlibs/dotnet/index.html
+
+Fixed bugs:
+-----------
+* Directory deletion did not work properly.
+  Bugzilla 40972.
+
+* docletpath attribute of javadoc was ignored.
+  Bugzilla 40900.
+
+* Fixed incorrect recursion in DOMUtil.listChildNodes().
+  Bugzilla 40918.
+
+* CompressedResource.compareTo() did not
+  take comparison with another CompressedResource into account.
+  Bugzilla 40949.
+
+* Avoid possible NPE in Jar.java.
+  Bugzilla 40847.
+
+* regression in attribute prefix (+ others) for refid in zipfileset and tarfileset.
+  Bugzilla 41004, 30498.
+
+* dependset failed if the basedir of a target fileset did not exist.
+  Bugzilla 40916.
+
+* Recursive filtering encountered NullPointerExceptions under certain
+  circumstances.  Bugzilla 41086.
+
+* XmlProperty overrides previously set property value when handling duplicate
+  elements. Bugzilla 41080.
+
+* Having many tasks causes OOM.  Bugzilla 41049.
+
+* Regression: <path> was evaluating nested content only once, so that it could
+  not e.g. pick up files that didn't exist the first time through.
+  Bugzilla 41151.
+
+* OOM caused by IH holding on to classes and thus their classloaders.
+  Bugzilla 28283 and 33061.
+
+* <delete> doesnt delete when defaultexcludes="false" and no includes is set
+  fixed. Bugzilla 40313.
+
+* Behavior change of DirectoryScanner/AbstractFileset when conditional include
+  patterns are used. Bugzilla 40722.
+
+* <javac> fails with NPE when compiling with eclipse ecj 3.1.x.
+  Bugzilla 40839.
+
+* JUnitTestRunner had a NPE when unable to create parser, the exception
+  containing the error did not get reported. Bugzilla 36733.
+
+* <checksum> with file and todir option failed. Bugzilla report 37386.
+
+* <path location="loc"> was broken (Regression from beta1).
+  Bugzilla report 40547.
+
+* Nested fileset in <cab> did not work. Bugzilla report 39439.
+
+* The ant wrapper script should now correctly locate the java
+  executable in more recent IBM JDKs for AIX as well.
+
+* URLResource did not close jar files, and also did not disconnect HTTPConnection (s).
+
+* Error calling junitreport. Bugzilla 40595.
+
+* <junittask/> created junitvmwatcher*.properties files but did not close and delete them.
+
+* <xmlproperty> did not create properties for empty leaf elements.
+  Bugzilla report 26286.
+
+* UnknownElement.maybeConfigure always configured.
+  Bugzilla report 40641.
+
+* No check for refid when prefix attribute is set in zipfileset.
+  Bugzilla report 30498.
+
+* Fix for junit4 issue introduced since beta2.
+  Bugzilla report 40682.
+
+* Error in duplicate project name with <import> and <antcall>.
+  Bugzilla report 39920.
+
+* junit4 did not work with fork=no and junit4 in $ANT_HOME/lib.
+  Bugzilla report 40697.
+
+* PathConvert on Windows should process forward and back slashes equivalently.
+  Bugzilla report 32884.
+
+* ant.bat now looks in %USERPROFILE% and %HOMEDRIVE%%HOMEPATH% in addition to
+  %HOME% for pre/post batch files. Bugzilla report 39298.
+
+* The inheritance hierarchy of the legacy <path> type was changed; code built
+  against Ant 1.7 would therefore no longer execute on older versions of Ant.
+  Since <path> is historically heavily used this was undesirable, and since it
+  is also avoidable, the change to <path>'s taxonomy was reverted.
+
+* <zip filesonly="true"> included empty directories.  Bugzilla report 40258.
+
+* Invalid hash code of Target causes XmlLogger to fail.
+  Bugzilla report 40207.
+
+* Macro element did not include top level Text. Bugzilla report 36803.
+
+* AntClassLoader did not isolate resources when isolate was set. Bugzilla report 38747.
+
+* Diagnostics broken when using java 1.4. Bugzilla report 40395.
+
+* Exception reporting in <copy> was broken. Bugzilla report 40300.
+
+* Handling of corrupt tar files, TarInputStream.read() never returns EOF.
+  Bugzilla report 39924.
+
+* Some bugs in ReaderInputStream. Bugzilla report 39635.
+
+* <antlr> did not recognise whether the target is up-to-date for html option.
+  Bugzilla report 38451.
+
+* Documented minimal version of jsch now 0.1.29.
+  Bugzilla report 40333.
+
+* <available> searched parent directories for files.
+  Bugzilla report 37148.
+
+* The build could be halted if a file path contained more ".." components than
+  the actual depth of the preceding path. Now such paths are left
+  alone (meaning they will likely be treated as nonexistent
+  files). Bugzilla Report 40281.
+
+* Converting a <dirset> to a string was broken. Bugzilla Report 39683.
+
+* Manifests have improved line length handling, taking care of encoding.
+  Bug reports 37548 / 34425.
+
+* <manifest> now closes the inputstream explicitly. Bug report 39628.
+
+* <rpm> now also correctly searches the first element of the path.
+  Bug report 39345.
+
+* ant.bat now handles classpath set to "". Bug report 38914.
+
+* <junit> now supports JUnit 4. Bugzilla Report 38811.
+
+* <junit> can now work with junit.jar in its <classpath>. Bugzilla
+  Report 38799.
+
+* Some potential NullPointerExceptions, Bugzilla Reports 37765 and 38056.
+
+* Problem when adding multiple filter files, Bugzilla Report 37341.
+
+* Problem referencing jars specified by Class-Path attribute in manifest
+  of a ant task jar file, when this ant task jar file is located in
+  a directory with space, Bugzilla Report 37085.
+
+* Backward incompatible change in ZipFileSet, Bugzilla Report 35824.
+
+* Wrong replacement of file separator chars prevens junitbatchtest
+  from running correctly on files from a zipfileset. Bugzilla Report 35499.
+
+* Calling close twice on ReaderInputStream gave a nullpointer exception.
+  Bugzilla Report 35544.
+
+* Memory leak from IntrospectionHelper.getHelper(Class) in embedded
+  environments. Bugzilla Report 30162.
+
+* Translate task does not remove tokens when a key is not found.
+  It logs a verbose message.  Bugzilla Report 13936.
+
+* Incorrect task name with invalid "javac" task after a "presetdef".
+  Bugzilla reports 31389 and 29499.
+
+* <manifest> was not printing warnings about invalid manifest elements.
+  Bugzilla report 32190.
+
+* <replace> got out of memory on large files (part of report 32566).
+  <replace> can now handle files as long as there is enough disk space
+  available.
+
+* Commandline.describeCommand() methods would attempt to describe
+  arguments even when none, other than the executable name, were present.
+
+* Create signjar's helper ExecTask instance directly rather than by
+  typedef discovery mechanisms. Bugzilla report 33433.
+
+* FileUtils.resolveFile() promised to return absolute files but
+  did not always do so.
+
+* <ftp> failed to retrieve a file when the path towards the file contained
+  an element starting with . Bugzilla report 33770.
+
+* "<rmic> always compiles on Java1.5" bugzilla report=33862. Fixed default
+  stub version to always be "compat", even on Java1.5+.
+
+* The .NET compilation tasks failed if filenames given as references
+  contained spaces.  Bugzilla Report 27170.
+
+* SQL task would try access result sets of statements that didn't
+  return any, causing problems with Informix IDS 9.2 and IBM DB2 8.1
+  FixPak 6 (or later). Bugzilla Reports 27162 and 29954.
+
+* Task.init() was called twice for most tasks.  Bugzilla Report 34411.
+
+* JavaTest testcases sometimes fail on windows. Bugzilla Report 34502.
+
+* Targets with identical name work in imported project. Bugzilla Report 34566.
+
+* DemuxOutputStream now uses a WeakHashMap to store the thread-stream mapping,
+  to avoid holding on to thread references after they terminate.
+
+* <xmlvalidate> and <schemavalidate> create a new parser for every file in a
+  fileset, and so validate multiple files properly. Bugzilla Report 32791.
+
+* <tar> / <untar> now accepts files upto 8GB, <tar> gives an error if larger
+  files are to be included. This is the POSIX size limit.
+
+* <junitreport> removed line-breaks from stack-traces.  Bugzilla
+  Report 34963.
+
+* Off-by-one error in environment setup for execution under OpenVMS fixed.
+
+* Bugzilla report 36171: -noclasspath crashes ant if no system
+  classpath is set.
+
+* <pvcs> used wrong switch for retrieving revisions by label.
+  Bugzilla Report 36359.
+
+* <sshexec> closed System.out, disabling output on second and subsequent
+  invocations.  Bugzilla report 36302.
+
+* <cvschangelog> was crashing with CVS versions >= 1.12.x due to change in
+  the date format. Bugzilla report 30962.
+
+* The same IntrospectionHelper instance was continuously added as a listener
+  to project. Bugzilla report 37184.
+
+* FileUtils.toURI() was not encoding non-ASCII characters to ASCII,
+  causing impossibility to process XML entities referenced by XML
+  documents in non ASCII paths. Bugzilla report 37348.
+
+* > 1 ssh invocations to a given host would fail. Bugzilla report 36207.
+
+* EmailTask was eating SMTP error messages. Bugzilla report 37547.
+
+* PropertySet API setMapper(...) didn't properly set up the Mapper.
+  Bugzilla report 37760.
+
+* Proper return code for ant.bat. Bugzilla report 13655.
+
+* Project not set on ChainReaderHelpers used by the Redirector.
+  Bugzilla report 37958.
+
+* Copy task would fail on locked (or otherwise uncopyable) files even if
+  failonerror set to false. Bugzilla report 38175.
+
+* <junit> task did not print all the Test names when using forkmode='once'.
+  Bugzilla report 37426.
+
+* <available> could leak resources, Bugzilla Report 38260.
+
+* Redirector called Thread.sleep in a synchronized block. Bugzilla
+  report 37767.
+
+* CCUnlock's objselect attribute could exhibit unpredictable behavior;
+  standardized improperly included objselect and objsel property accessors to
+  delegate to the inherited objSelect property accessor. Bugzilla report 37766.
+
+* <unzip> and <untar> now correctly merge multiple nested patternsets.
+  Bugzilla Report 38973.
+
+* On case-insensitive filesystems, a <move> to change filename case
+  erroneously deleted the "destination" file before attempting to rename
+  the source file.  Bugzilla 37701.
+
+* <scp> can now handle uris with @s other than the final one denoting the
+  domain.  Bugzilla 38082.
+
+* If the class invoked by the <java> task threw a ClassNotFoundException,
+  this was misinterpreted as the specified class itself not being found.
+
+* <echoproperties> setPrefix javadoc claimed null or empty prefix would be
+  ignored; instead an error was thrown.  Bugzilla report 39954.
+
+* <get> would fetch files that were up to date, because it used > in a
+  remote/local timestamp comparison, not >=. Bugzilla 35607.
+
+* <xslt> passes the current file (name + directory) to the
+  stylesheet/transformation.  xsl-parameter name is configurable.
+  Bugzilla report 21042.
+
+* The <zip> API allowed creation of directories in file-only archives; a
+  habitual offender was the subclassed <jar>, which included META-INF/ in
+  the destination file regardless of whether filesonly was set to true.
+
+* <rmic> has a new adapter, xnew, to use the -XNew back end on java1.5+.
+  By forking rmic, this works on java1.6+. Bugzilla report 38732.
+
+* Copy of UnknownElement in macroinstance was not recursive.
+  Bugzilla report 40238.
+
+* Mixing of add and addConfigured methods in Mapper/ChainedMapper
+  causes incorrect chaining. Bugzilla report 40228.
+
+Other changes:
+--------------
+
+* Warn user when a reference in the form "${refid}" cannot be resolved as this
+  is a sign they probably meant "refid" (misuse of property expansion syntax).
+
+* Add dtd to javadoc for junit.
+  Bugzilla 40754.
+
+* Add quiet attribute to loadfile/resource.
+  Bugzilla 38249.
+
+* Make Locator#fromURI also append the drive letter when running under Windows
+  with JDK 1.3 or 1.2.
+
+* Do not uppercase the drive letters systematically in FileUtils#normalize.
+
+* Java 5 enumerations may now be used as values in XML attributes in place of
+  EnumeratedAttribute. Bugzilla 41058.
+
+* Create a pom file for ant-testutil and add ant-testutil.jar to the ant
+  distribution. Bugzilla 40980.
+
+* Roll back automatic proxy enabling on Java 1.5. It broke things like
+  Oracle JDBC drivers, and Ant itself on IBM's JVM on AIX, and didnt
+  seem to work to well the rest of the time.
+  To enable the feature, use the -autoproxy command line option.
+
+* Upgraded XML API and parser to Xerces 2.8.1
+
+* A code review of some threaded logic has tightened up the synchronization
+  of Watchdog, ExecuteWatchdog and ExecuteJava, which could reduce the occurence
+  of race conditions here, especially on Java1.5+.
+
+* Allow broken reference build files. The defer reference processing would
+  break too many files - so allow them with a warning.
+
+* Removed dependency on sun.misc.UUEncoder for UUMailer.
+
+* Added regex attribute to the echoproperties task.
+  Bugzilla 40019.
+
+* <war> task now allows you to omit the web.xml file. as this is optional
+  in the servlet 2.5 and Java EE 5 APIs. set needxmlfile="false" to
+  avoid a missing web.xml file from halting the build.
+
+* Diagnostics catches and logs security exceptions when accessing system properties.
+
+* <javadoc> useexternalfile now applies to all command line arguments
+  of javadoc. Bugzilla report 40852.
+
+* javadoc/tag@description is now set to the name if description is
+  not specified. Bugzill report 32927.
+
+* Some performance improvements, including Bugzilla report 25778.
+
+* Add <matches> condition. Bugzilla report 28883.
+
+* Extending JAR-Task for SPI. Bugzilla report 31520.
+
+* Added <tokens> resource collection for convenient creation of string
+  resources from other resources' content. Inspired by Bugzilla 40504.
+
+* Added <compare> resource selector to select resources based on the
+  results of their comparison to other resources.
+
+* Added outputtoformatters attribute to <junit> to allow suppression
+  of noisey tests. Bugzilla report 12817.
+
+* Log level of message 'Overriding previous definition of reference to'
+  set to Verbose. Bugzilla report 17240.
+
+* Added setbeans attribute to <script> to allow <script>'s to be
+  run without referencing all references.
+  Bugzilla report 37688.
+
+* Added classpath attribute and nested element to <script> to allow
+  the language jars to be specified in the build script.
+  Bugzilla report 29676.
+
+* Trim the driver attribute on the <sql> task. Bugzilla report 21228.
+
+* Allow (jar) files as well as directories to be given to jdepend.
+  Bugzilla report 28865.
+
+* Convert SplashTask to use NOT sun internal classes.
+  Bugzilla report 35619.
+
+* Made PatternSet#hasPatterns public to allow custom filesets access.
+  Bugzilla report 36772.
+
+* Added searchparents attribute to <available>. Bugzilla report 39549.
+
+* Tasks that don't extend Ant's Task class will now get the build file
+  location reflected into a method of the signature void setLocation(Location)
+  - if such a method exists.
+
+* Remove needless synchronization in DirectoryScanner.
+  Bugzilla report 40237.
+
+* Improved recursion detection for lines with multiple matches of same token
+  on a single line.  Bugzilla report 38456.
+
+* Task will now log correctly even if no project is set.
+  Bugzilla report 38458.
+
+* Use alternative names for the command line arguments in javac. Bugzilla
+  Report 37546.
+
+* The Reference class now has a project field that will get
+  used (if set) in preference to the passed in project, when
+  dereferencing the reference. Bugzilla Report 25777.
+
+* On DOS and Netware, filenames beginning with a drive letter
+  and followed by a colon but with no directory separator following
+  the colon are no longer (incorrectly) accepted as absolute pathnames
+  by FileUtils.normalize() and FileUtils.isAbsolutePath().  Netware
+  volumes can still be specified without an intervening separator.
+  UNC pathnames on Windows must include a server and share name, i.e.
+  "\\a\b" to be considered valid absolute paths.
+
+* A bug in SQLExec would prevent the execution of trailing,
+  non-semicolon-delimited statements.  Bugzilla Report 37764.
+
+* InputHandler implementations may now call InputRequest.getDefaultValue()
+  if they wish. The default handler uses this also. Bugzilla report 28621.
+
+* Took in bugzilla report 39320, "Simple code cleanups"
+
+* Improve compatibility with GNU Classpath and java versions prior to
+  1.5. Bugzilla 39027.
+
+* ${ant.core.lib} may now be used to refer to the library containing the
+  Ant classes, for instance useful when compiling tasks.
+
+* Minor performance improvements Bugzilla report 37777
+
+* New task <manifestclasspath> converts a path into a property
+  suitable as the value for a manifest's Class-Path attribute.
+
+* Fixed references to obsoleted CVS web site. Bugzilla Report 36854.
+
+* Log fine-grained events at verbose level from JUnit. Bugzilla report 31885.
+
+* <WsdlToDotnet> and <style> are now deprecated in favor of <wsdltodotnet> and
+  <xslt>, respectively. Bugzilla report 25832.
+
+* <echoproperties> now (alphanumerically) sorts the property list
+  before echoing. Bugzilla report 18976.
+
+* A new base class DispatchTask has been added to facilitate elegant
+  creation of tasks with multiple actions.
+
+* Major revision of <wsdltodotnet>. Supports mono wsdl and the microsoft
+  wsdl run on mono, as well as most of the .NET WSE2.0 options. Extra
+  schemas (files or urls) can be named in the <schema> element.
+  Compilers can be selected using the compiler attribute, which defaults
+  to "microsoft" on windows, and "mono" on everything else.
+
+* It is now possible to specify the pattern created/parsed by <checksum>.
+  Bugzilla Report 16539.
+
+* Added a new "failall" value for the onerror attribute of <typedef>.
+  Bugzilla report 31685.
+
+* unzip/unwar/unjar/untar now supports a nested mapper, which lets you unzip
+  in useful ways.
+
+* Junit task -- display suite first.
+  Bugzilla report 31962.
+
+* Added isSigned condition and signedselector selector
+  Bugzilla report 32126.
+
+* Added preserveLastModified attribute to signjar task.
+  Bugzilla report 30987.
+
+* Added <scriptcondition> condition, for inline scripted conditions
+
+* Added <xor> condition for exclusive-or combining of nested conditions.
+
+* Added <scriptselector> selector for scripted file selection
+
+* ant -diagnostics lists contents of ${user.home}/.ant/lib , and
+  checks that the java.io.tmpdir directory exists and is writeable.
+
+* mail task accepts nested header element.  Bugzilla report 24713.
+
+* zip/jar/war/ear supports level attribute for deflate compression level.
+  Bugzilla report 25513.
+
+* Added loginputstring attribute to the redirector type.
+
+* Tighten security by sending storepass and keypass to signjar
+  via the input stream of the forked process.
+
+* New task <schemavalidate> extends <xmlvalidate> with extra support
+  for XML Schema (XSD) files.
+
+* <fixcrlf> supports a file attribute for easy fixup of a single file.
+
+* New condition <parsersupports> which can look for XML parser feature or
+  property support in the parser Ant is using.
+
+* fixcrlf can be used in a filterchain.
+
+* <sync> has a new nested element <preserveInTarget> that can be used
+  to protect extra-content in the target directory.  Bugzilla Report
+  21832.
+
+* <signjar> now supports:
+  -nested filesets at the same time as the jar attribute
+  -a destDir attribute with the appropriate dependency logic, which
+   can be used with the jar attribute or nested filesets
+  -a mapper to permit filename remapping on signing
+  -tsaurl and tsacert attributes for timestamped JAR signing
+  -nested <sysproperty> elements, which can be used for proxy setup
+  and the like
+
+* The linecontains and linecontainsregexp filterreaders now support a
+  negate attribute to select lines -not- containing specified text.
+  Bugzilla Report 34374.
+
+* <os> condition adds "winnt" as a family which can be tested. This is
+  all windows platforms other than the Win9x line or Windows CE.
+
+* <exec> (and hence, <apply> and any other derived classes) have an OsFamily
+  attribute, which can restrict execution to a single OS family.
+
+* Added "backtrace" attribute to macrodef. Bugzilla report 27219.
+
+* Ant main provides some diagnostics if it ever sees a -cp or -lib option,
+  as this is indicative of a script mismatch. Bugzilla report 34860
+
+* <junitreport> prints a special message if supplied an empty XML File. This
+  can be caused by the test JVM exiting during a test, either via a
+  System.exit() call or a JVM crash.
+
+* Project name is now used for *all* targets so one can write consistent import
+  build files. Bugzilla report 28444.
+
+* New condition <typefound> that can be used to probe for the declaration
+  and implementation of a task, type, preset, macro, scriptdef, whatever.
+  As it tests for the implementation, it can be used to check for optional
+  tasks being available.
+
+* Check for 1.5.* Ant main class. (weblogic.jar in classpath reports)
+
+* New condition <isfailure> that tests the return-code of an executable. This
+  contains platform-specific logic and is better than comparing the result with
+  "0".
+
+* Added initial support for Resource Collections, including the
+  resourcecount task.
+
+* property attribute of pathconvert is now optional. If omitted the
+  result will be written to the log.
+
+* New mapper, <scriptmapper>, supports scripted mapping of source files/strings
+  to destination strings.
+
+* Add the echoxml task. This will echo nested XML to a file, with
+  the normal <?xml ?> processor instruction. UTF-8 encoding only; no-namespace
+  support.
+
+* Try to make subprojects of custom Project subclasses instances of the
+  same type. Bugzilla report 17901.
+
+* <ssh> and <scp> support keyboard-interactive authentication now.
+
+* <javadoc> now supports -breakiterator for custom doclets if Ant is
+  running on JSE 5.0 or higher.  Bugzilla Report: 34580.
+
+* New logger, TimestampedLogger, that prints the wall time that a build
+  finished/failed. Use with
+  -logger org.apache.tools.ant.listener.TimestampedLogger
+
+* <junitreport> now generates pages alltests-errors.html and
+  alltests-fails.html, that list only the errors and failures, respectively.
+  Bugzilla Report: 36226
+
+* New task <makeurl> that can turn a file reference into an absolute file://
+  url; and nested filesets/paths into a (space, comma, whatever) separated
+  list of URLs. Useful for RMI classpath setup, amongst other things.
+
+* <xslt> now accepts nested FileNameMappers e.g. <globmapper>.
+  Bugzilla report 37604.
+
+* New task <loadresource> that accompanies <loadfile> for non file resources.
+
+* <echo> now supports an encoding when saving to a file.
+
+* New GreedyInputHandler added.
+
+* Add textfile attribute to the <filesmatch> condition. When true, the text
+  contents of the two files are compared, ignoring line ending differences.
+
+* New <resourcesmatch> condition.
+
+* Added the onmissingfiltersfile attribute to filterset. Bugzilla report 19845.
+
+* Added the inline handler element to the input task.
+
+* <sql> supports property expansion if you set the expandProperties
+  attribute. By default it does not expand properties, something we
+  dare not change for fear of breaking complex SQL operations in
+  existing files.
+
+* <javadoc>'s packagenames attribute is now optional and defaults to "*".
+
+* <javac>'s source and target attributes as well as <javadoc>'s source
+  attribute will read default values from the properties
+  ant.build.javac.source and ant.build.javac.target.
+
+* Handling of ' ', '#' in CLASSPATH and '#' in -lib (cannot use ' '
+  in -lib on UNIX at the moment). Bugzilla Report 39295.
+
+* <scp> now optionally supports the sftp protocol.  Bugzilla Report 39373.
+
+* Resources can now be used to indicate the location of the stylesheet to use
+  in <xslt>. Bugzilla Report 39407.
+
+* New <antversion> condition. Bugzilla report 32804.
+
+* ReplaceTokens should allow properties files. Bugzilla report 39688.
+
+* FTP Account could not be specified in ant FTP task. Bugzilla report 39720.
+
+* Minor performance updates. Bugzilla report 39565.
+
+* New deleteonexit attribute for the <tempfile> task. Bugzilla report 39842.
+  Remember that the exit of the JVM can be a long time coming,
+  especially under an IDE. Don't rely on this being called.
+
+* <scriptdef>-created scripts have support for nested text. All text
+  passed to a scripted task can be accessed via self.text.
+
+* <fixcrlf> now supports an outputencoding attribute.  Bugzilla report 39697.
+
+* <junitreport> now supports nested XSL parameters. Bugzilla report 39708.
+
+* <javacc> has a jdkversion attribute to pass the desired JDK version
+  down to javacc.  Bugzilla report 38715.
+
+* <cvs> prints passfile info at -verbose level instead of -info. Bugzilla
+  report 35268
+
+* When <javac> can't find the compiler class, it prints out java.home for
+  immediate diagnostics
+
+* Ant launcher now supports a -main attribute so that you can specify
+  an extension class to the built in org.apache.tools.ant.Main
+  class. This class must implement the interface AntMain
+
+Changes from Ant 1.6.4 to Ant 1.6.5
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+Fixed bugs:
+-----------
+
+* <move> was unable to replace existing files or write into
+  existing directories.  Bugzilla report 34962.
+
+* <macrodef> with redefined default values was incorrect. (Fix for
+   31215 had a bug). Bugzilla report 35109.
+
+* <javadoc> will convert backslashes to forwardslashes when generating file
+  list by useexternalfile. Bugzilla report 27814.
+
+Changes from Ant 1.6.3 to Ant 1.6.4
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+* <ftp> task has had a number of changes.  Uptodate calculation previously
+  did not call a file uptodate if the source timestamp and the destination
+  timestamp were equal. Bugzilla report 34941.  Any script that attempted
+  to compensate for this by using the timediffmillis attribute might need
+  to be tweaked.
+
+
+Fixed bugs:
+-----------
+
+* Sun javah failed with java.lang.NoClassDefFoundError.
+  Bugzilla report 34681.
+
+* DirectoryScanner.slowScan() was broken. Bugzilla report 34722.
+
+* DirectoryScanner.scan() could throw a NullPointerException on
+  case-insensitive filesystems (read Windows or MacOS X).
+
+* Get w/authentication failed with ArrayOutOfBoundsExceptions.
+  Bugzilla report 34734.
+
+* Granularity attribute for <sync> task was undocumented.
+  Bugzilla report 34871.
+
+* <unzip> and <untar> could leave file handles open on invalid
+  archives.  Bugzilla report 34893.
+
+* propertyset threw NPE with nested, mapped propertysets.
+
+Other changes:
+--------------
+
+* AntXMLContext.setCurrentTargets() is now public. Bugzilla report 34680.
+
+Changes from Ant 1.6.2 to Ant 1.6.3
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* The subant task used the canonical version of a file path. This
+  has been changed to use the absolute path. Bugzilla 30438.
+
+* Tar now writes two EOF blocks rather than one.
+  Bugzilla report 28776
+
+* The Reference object now has a project field which it uses in preference
+  to the project passed in. This allows composite references to be
+  handled to nested projects.
+  Bugzilla report 25777
+
+* <junit> with filtertrace="true" will now also swallow lines for the
+  sun.reflect package.  If you need to see them in your stack trace,
+  you must set filtertrace to false.
+  Bugzilla Report 22758
+
+* The jikes compiler adapter now supports -bootclasspath, -extdirs and
+  -sourcepath and also uses the same logic for debug flags as javac.
+  This means, the jikes compiler adapter now requires Jikes 1.15 or later.
+  Bugzilla Reports 25868, 26404 and 32609.
+
+* The gcj compiler adapter used to include the Java runtime classes
+  even if includeJavaRuntime was set to false, unless the
+  bootclasspath has been specified as well.  It will now always adhere
+  to includeJavaRuntime, you may need to set it to true explicitly now
+  if you relied on the old behavior.
+
+Other changes:
+--------------
+
+* <javadoc> can now take an attribute 'executable'. Bugzilla report 30606.
+
+* New attribute ignorecontents for <different> selector
+
+* Javadoc fixes for Location, Project, and RuntimeConfigurable
+  Bugzilla 30160.
+
+* Enable to choose the regexp implementation without system property.
+  Bugzilla Report 15390.
+
+* Expose objects and methods in IntrospectionHelper. Bugzilla Report 30794.
+
+* Allow file attribute of <move> to rename a directory.
+  Bugzilla Report 22863.
+
+* Add xmlcatalog nested element to XmlProperty. Bugzilla report 27053.
+
+* New attribute alwayslog for <redirector> type.
+
+* Added <target> nested elements to <ant> and <antcall> to allow
+  specification of multiple sub-build targets, which are executed
+  with a single dependency analysis.
+
+* Refactored Target invocation into org.apache.tools.ant.Executor
+  implementations.  Bugzilla Reports 21421, 29248.
+
+* <rmic> now also supports Kaffe's rmic version shipping with Kaffe
+  1.1.2 and above.
+
+* added casesensitive attribute to <globmapper> and <regexpmapper>
+  Bugzilla report 16686
+
+* added handledirsep attribute to <globmapper> and <regexpmapper>
+  Bugzilla report 32487
+
+* added a new mapper <filtermapper>
+
+* When a BuildListener tried to access System.err or System.out, Ant
+  would have thrown an exception - this has been changed.  Ant now
+  silently ignores the message.  BuildListeners still should avoid
+  accessing either stream.
+
+* Added a comment attribute to the zip task.
+  Bugzilla report 22793.
+
+* Overloaded FileUtils.createNewFile with a boolean mkdirs attribute
+  to create nonexistent parent directories.
+
+* <apply> has a new "force" attribute that, when true, disables
+  checking of target files.
+
+* Made the dest attribute of the apply task optional; mapped target
+  filenames will be interpreted as absolute pathnames when dest is omitted.
+
+* Changed default tempdir for <javac> from user.dir to java.io.tmpdir.
+
+* Added searchpath attribute to <exec> for searching path variable(s)
+  when resolveexecutable = true.
+
+* Added revision and userid attributes to <pvcs> documentation.
+
+* Added support to the touch task for a mkdirs attribute to create
+  nonexistent parent directories before touching new files.
+
+* Added support to the touch task for a pattern attribute to allow
+  alternate datetime formats.
+
+* Added support to the touch task to map touched files using a nested
+  mapper element.
+
+* Added support to the touch task for a verbose attribute to suppress
+  logging of new file creation.
+
+* bad link in docs to the enhancement page in bugzilla.
+  Bugzilla report 33252.
+
+* Added length task to get strings' and files' lengths.
+
+* <native2ascii> and <javah> now also support Kaffe's versions.
+
+* Recursive token expansion in a filterset can now be disabled by
+  setting its recurse attribute to false.
+
+* Pathconvert no longer requires that one of (targetos|pathsep|dirsep)
+  be set; platform defaults are used when this is the case.
+
+* Added preservelastmodified attribute to fixcrlf task. Bugzilla 25770.
+
+* Added isfileselected condition.
+
+* Added verbose="true|false" attribute to <subant>. When verbose is enabled,
+  the directory name is logged on entry and exit of the sub-build.
+  Bugzilla 33787.
+
+* Added -nouserlib option to allow running ant without automatically loading
+  up ${user.home}/.lib/ant. This is useful when compiling ant, and antlibs.
+  Modified the build.sh and build.bat to use the option.
+
+* Added -noclasspath option to allow running ant WITHOUT using CLASSPATH env
+  variable. Modified ant.bat to do this so that %CLASSPATH% is not looked at.
+
+* Add else attribute to the condition task, which specifies an
+  optional alternate value to set the property to if the nested
+  condition evaluates to false. Bugzilla report 33074.
+
+* Ant generated jar files should now be detected as jar files by
+  Solaris.  Bugzilla Report 32649.
+
+* <rexec> with a single command should now work with unusal login
+  dialogs without special read/write pairs.  Bugzilla Report 26632.
+
+* <csc>'s extraoptions can now contain multiple arguments.
+  Bugzilla Report 23599.
+
+* <macrodef> with default values set by properties would be
+  seen as new definitions when called twice with different properties.
+  This was confusing so the definitions are now treated as similar.
+  Bugzilla Report 31215.
+
+* <javadoc> has a new attribute "includenosourcepackages" that can be
+  used to document packages that don't hold source files but a
+  package.html file.  Bugzilla Report 25339.
+
+* <rpm> has new attributes failonerror and quiet.
+
+* Added two tutorials
+  - beginner: introduction into Ant
+  - task developers: using path, fileset etc
+
+* a number of new attributes that allow the user to handle non-standard
+  server listing formats and time zone differences have been added in
+  the <ftp> task.
+
+
+Fixed bugs:
+-----------
+
+* Do not pass on ThreadDeath when halting <java fork="false">. Bugzilla
+  32941.
+
+* Killing a thread running <java fork="true"> (e.g. from an IDE) would
+  not stop the forked process. Bugzilla 31928.
+
+* Programs run with <java fork="true"> can now accept standard input
+  from the Ant console.  (Programs run with <java fork="false"> could
+  already do so.)  Bugzilla 24918.
+
+* AbstractCvsTask prematurely closed its outputStream and errorStream.
+  Bugzilla 30097.
+
+* Impossible to use implicit classpath for <taskdef>
+  when Ant core loader != Java application loader and
+  Path.systemClassPath taken from ${java.class.path} Bugzilla 30161.
+
+* MacroInstance did not clean up nested elements correctly in the execute
+  method, causing multiple use of the same macro instance with nested
+  elements to fail.
+
+* checksum fileext property doc wrong. Bugzilla 30787.
+
+* FTP task, getTimeDiff method was returning wrong value. Bugzilla 30595.
+
+* make sure that Zip and its derivates call the createEmptyZip method when
+ there are no resources to zip/jar/...
+
+* Zip task was not zipping when only empty directories were found.
+  Bugzilla 30365.
+
+* Jar task was not including manifest files when duplicate="preserve" was
+  chosen. Bugzilla 32802.
+
+* ant.bat was missing runAntNoClasspath label for goto.
+  Bugzilla 34510.
+
+* Classpath was treated in the same way as -lib options. Bugzilla 28046.
+
+* Manual page for cvsversion contained incorrect attributes and did not
+  say since 1.6.1. Bugzilla 31408.
+
+* Typo in definition of <cvsversion> task causing it not to be defined.
+  Bugzilla 31403.
+
+* Execution of top level tasks in imported files get delayed by targets.
+  Bugzilla report 31487.
+
+* ExecTask executes checkConfiguration() even though os does not match.
+  Bugzilla report 31805.
+
+* Concat task instance could not be run twice.
+  Bugzilla report 31814.
+
+* NPE using XmlLogger and antlib.
+  Bugzilla report 31840.
+
+* Properties.propertyNames() should be used instead of .keys().
+  Bugzilla report 27261.
+
+* Target location is not set for default target.
+  Bugzilla report 32267.
+
+* Incorrect classloader parent in junittask when using with
+  ant-junit.jar and junit.jar not in the project classloader. Bugzilla
+  report 28474.
+
+* getResources() on the classloader returned by ClasspathUtils would
+  see each resource twice - if the resource is in the project
+  classpath and if the classloader is requested with a null path.
+
+* XMLValidate used URL#getFile rather than the ant method FileUtils#fromURI
+  Bugzilla report 32508
+
+* fixed Regexp-Mapper docs which gave outdated instructions (optional.jar)
+  Bugzilla report 28584
+
+* <scp> using <fileset> didn't work with OpenSSH 3.9 and later.
+  Bugzilla report 31939
+
+* <setproxy> failed to set user/password on some JDKs.
+  Bugzilla report 32667
+
+* untar would go into infinite loop for some invalid tar files.
+  Bugzilla report 29877
+
+* forked <javac> won't pass -source to a JDK 1.1 or 1.2 javac anymore.
+  Bugzilla report 32948
+
+* propertyset references did not handle nested propertyset references.
+
+* oata.types.Description.getDescription(Project) would throw a
+  NullPointerException when the "ant.targets" reference was unset.
+
+* Wrapper scripts did not detect WINNT value of dynamic OS environment
+  variable when logged into workstations using Novell authentication.
+  Bugzilla Report 30366.
+
+* DependScanner.getResource() always returned nonexistent resources,
+  even when the resource actually existed.  Bugzilla Report 30558.
+
+* <apply> was broken with classfilesets.  Bugzilla Report 30567.
+
+* <available> returned false positives when checking a file
+  passed in with the current basedir leading twice:
+  e.g. ${basedir}${file.separator}${basedir}${file.separator}foo .
+
+* The first file open that took place when using input files with the
+  <exec>, <apply>, or <java> tasks was always logged to System.out
+  instead of to the managing Task.
+
+* <telnet> and <rexec> would try to disconnect from servers they never
+  connetced to, potentially leading to exceptions in commons-net.
+  Bugzilla Report 33618.
+
+* <zip> would drop files matched by defaultexcludes during updates.
+  Bugzilla Report 33412.
+
+* <zip> couldn't store files with size between 2GB and 4GB (the
+  upper limit set by the ZIP format itself).  Bugzilla Report 33310.
+
+* NPE when when <presetdef> tries to configure a task that
+  cannot be instantiated. Bugzilla Report 33689.
+
+* <javac debug="false"> created an invalid command line when running
+  the Symantec Java compiler.
+
+* Get with usetimestamp did not work on Java 1.2.
+
+* Get with usetimestamp did not work when local timestamp roughly >= now.
+
+* The framed JUnit report now handles multiple reports for the same
+  testcase properly.  Bugzilla Report 32745.
+
+* <cab> didn't work for files with spaces in their names on Windows.
+  Bugzilla Report 17182.
+
+* The VAJ tasks could fail if the project name contained characters
+  that need to get URL encoded.  Bugzilla Report 23322.
+
+* TarInputStream#read() wasn't implemented correctly.  Bugzilla Report
+  34097.
+
+* <xslt> failed to process file-hierarchies of more than one level if
+  scanincludeddirectories was true.  Bugzilla Report 24866.
+
+* forkmode="perBatch" or "once" would ignore extension attributes that
+  had been specified for <formatter>s.  Bugzilla Report 32973.
+
+* The refid attribute of the I/O redirector was not functional.
+
+Changes from Ant 1.6.1 to Ant 1.6.2
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* The import task used the canonical version of a file path. This
+  has been changed to use the absolute path. Bugzilla 28505.
+
+* ant-xalan2.jar has been removed since the only class contained in it
+  didn't depend on Xalan-J 2 at all.  Its sole dependency has always
+  been TraX and so it has been merged into ant-trax.jar.
+
+* All exceptions thrown by tasks are now wrapped in a buildexception
+  giving the location in the buildfile of the task.
+
+* Nested elements for namespaced tasks and types may belong to the
+  Ant default namespace as well as the task's or type's namespace.
+
+* <junitreport> will very likely no longer work with Xalan-J 1.
+
+  Note that Xalan-J 1 has been deprecated for a very long time and we
+  highly recommend that you upgrade.
+
+  If you really need to continue using Xalan-J 1, please copy the
+  junit-frames-xalan1.xsl from the distribution's etc directory as
+  junit-frames.xsl into a new directory and use the task's styledir
+  attribute to point to.  This is the last version of the XSLT
+  stylesheet that is expected to be compatible with Xalan-J 1.
+
+Fixed bugs:
+-----------
+
+* eliminate memory leak in AntClassLoader. Bugzilla Report 8689.
+
+* subant haltonfailure=false did not catch all failures. Bugzilla Report 27007.
+
+* macrodef @@ escaping was broken.  Bugzilla Report 27069.
+
+* MacroDef did not allow attributes named 'description'. Bugzilla Report 27175.
+
+* Throw build exception if name attribute missing from patternset#NameEntry.
+  Bugzilla Report 25982.
+
+* Throw build exception if target repeated in build file, but allow targets
+  to be repeated in imported files.
+
+* <apply> didn't compare timestamps of source and targetfiles when
+  using a nested <filelist>.  Bugzilla Report 26985.
+
+* tagdiff.xml was broken in ant 1.6.1. Bugzilla Report 27057.
+
+* if the basedir contained .. or . dirs, and the build file name contained
+  .. or ., the basedir was set incorrectly. Bugzilla Report 26765.
+
+* regression from ant 1.5, exec task outputted two redundant trailing newlines.
+  Bugzilla Report 27546.
+
+* NPE when running commons listener. Bugzilla Report 27373.
+
+* <java> swallowed the stack trace of exceptions thrown by the
+  executed program if run in the same VM.
+
+* -projecthelp swallowed (configuration) errors silently.
+  Bugzilla report 27732.
+
+* filterset used by filtertask doesn't respect loglevel. Bugzilla Report 27568.
+
+* wrong compare used in ProjectComponent for logging. Bugzilla Report 28070.
+
+* failOnAny attribute for <parallel> was broken. Bugzilla Report 28122.
+
+* If <javac> uses gcj and any of the nested <compilerarg>s implies
+  compilation to native code (like -o or --main), Ant will not pass
+  the -C switch to gcj.  This means you can now compile to native code
+  with gcj which has been impossible in Ant < 1.6.2.
+
+* <import optional="false"> and <import optional="true">
+  behaved identically.
+
+* <xslt> now sets the context classloader if you've specified a nested
+  <classpath>.  Bugzilla Report 24802.
+
+* <zip> and friends would delete the original file when trying to update
+  a read-only archive.  Bugzilla Report 28419.
+
+* <junit> and <assertions> are working together. Bugzilla report 27218
+
+* AntClassLoader#getResource could return invalid URLs.  Bugzilla
+  Report 28060.
+
+* Ant failed to locate tools.jar if the jre directory name wasn't all
+  lowercase.  Bugzilla Report 25798.
+
+* Redirector exhibited inconsistent behavior with regard to split
+  output.  When sent to file only, files would be created in all
+  cases; when split file-property, files were only created if
+  writes were performed.
+
+* fixed case handling of scriptdef attributes and elements.
+
+* UNC pathnames did not work for ANT_HOME or -lib locations on Windows.
+  Bugzilla report 27922.
+
+* replacestring tokenfilter only replaced the first occurrence.
+
+* AntLikeTasksAtTopLevelTest failed on cygwin.
+
+* I/O-intensive processes hung when executed via <exec spawn="true">.
+  Bugzilla reports 23893/26852.
+
+* JDependTask did not close an output file. Bugzilla Report 28557.
+
+* Using <macrodef> could break XmlLogger. Bugzilla Report 28993.
+
+* <genkey> no longer requires keytool to be in your PATH.  Bugzilla
+  Report 29382.
+
+* <symlink> could create cyclic links.  Bugzilla Report 25181.
+
+* <zip whenempty="skip"> didn't work in a common situation.  Bugzilla
+  Report 22865.
+
+* <scp> now properly handles remote files and directories with spaces
+  in their names.  Bugzilla Report 26097.
+
+* <scp> now has (local|remote)tofile attributes to rename files on the
+  fly.  Bugzilla Report 26758.
+
+* <telnet> and <rexec> didn't close the session.  Bugzilla Report 25935.
+
+* <subant> and XmlLogger didn't play nicley together.
+
+Other changes:
+--------------
+* doc fix concerning the dependencies of the ftp task
+  Bugzilla Report 29334.
+
+* <xmlvalidate> has now a property nested element,
+  allowing to set string properties for the parser
+  Bugzilla Report 23395.
+
+* Docs fixes for xmlvalidate.html, javadoc.html, starteam.
+  Bugzilla Reports 27092, 27284, 27554.
+
+* <pathconvert> now accepts nested <mapper>s.  Bugzilla Report 26364.
+
+* Shipped XML parser is now Xerces-J 2.6.2.
+
+* Added nested file element to filelist.
+
+* spelling fixes, occurred. Bugzilla Report 27282.
+
+* add uid and gid to tarfileset. Bugzilla Report 19120.
+
+* <scp> has a verbose attribute to get some feedback during the
+  transfer and new [local|remote][File|Todir] alternatives to file and
+  todir that explicitly state the direction of the transfer.
+
+* The OS/2 wrapper scripts have been adapted to use the new launcher.
+  Bugzilla Report 28226.
+
+* <sshexec> now also captures stderr output.  Bugzilla Report 28349.
+
+* <xslt> now supports a nested <mapper>.  Bugzilla Report 11249.
+
+* <touch> has filelist support.
+
+* <nice> task lets you set the priority of the current thread; non-forking
+  <java> code will inherit this priority in their main thread.
+
+* New attribute "negate" on <propertyset> to invert selection criteria.
+
+* Target now supports a Location member.  Bugzilla Report 28599.
+
+* New "pattern" attribute for <date> selector.
+
+* <junit> has a new forkmode attribute that controls the number of
+  Java VMs that get created when forking tests.  This allows you to
+  run all tests in a single forked JVM reducing the overhead of VM
+  creation a lot.  Bugzilla Report 24697.
+
+* <jar> can now optionally create an index for jars different than the
+  one it currently builds as well.  See the new <indexjars> element
+  for details.  Bugzilla Report 14255.
+
+* Permit building under JDK 1.5. Bugzilla Report 28996.
+
+* minor Javadoc changes. Bugzilla Report 28998.
+
+* Misc. corrections in SignJar.java. Bugzilla Report 28999.
+
+* Remove redundant <hr> from javah.html. Bugzilla Report 28995.
+
+* Ignore built distributions. Bugzilla Report 28997.
+
+* A new roundup attribute on <zip> and related task can be used to
+  control whether the file modification times inside the archive will
+  be rounded up or down (since zips only store modification times with
+  a granularity of two seconds).  The default remains to round up.
+  Bugzilla Report 17934.
+
+* A binary option has been added to <concat>. Bugzilla Report 26312.
+
+* Added DynamicConfiguratorNS, an namespace aware version of
+  DynamicConfigurator. Bugzilla Report 28436.
+
+* Add implicit nested element to <macrodef>. Bugzilla Report 25633.
+
+* Add deleteonexit attribute to <delete>.
+
+* Added Target.getIf/Unless().  Bugzilla Report 29320.
+
+* <fail> has a status attribute that can be used to pass an exit
+  status back to the command line.
+
+* <fail> accepts a nested <condition>.
+
+* <loadproperties> supports loading from a resource.
+  Bugzilla Report 28340.
+
+* Nested file mappers and a container mapper implementation have been
+  introduced.  Additionally, the <mapper> element now accepts "defined"
+  nested FileNameMapper implementations directly, allowing a usage
+  comparable to those of <condition>, <filter>, and <selector>.
+
+* New <redirector> type introduced to provide extreme I/O flexibility.
+  Initial support for <exec>, <apply>, and <java> tasks.
+
+* <apply> has a new ignoremissing attribute (default true for BC)
+  which will allow nonexistent files specified via <filelist>s to
+  be passed to the executable.  Bugzilla Report 29585.
+
+* <junitreport> now also works with Xalan XSLTC and/or JDK 1.5.
+  Bugzilla Report 27541.
+
+* <jspc> doesn't work properly with Tomcat 5.x.  We've implemented a
+  work-around but don't intend to support future changes in Tomcat
+  5.x.  Please use the jspc task that ships with Tomcat instead of
+  Ant's.
+
+Changes from Ant 1.6.0 to Ant 1.6.1
+=============================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* License is now Apache Software License 2.0
+  see http://www.apache.org/licenses/ for more information
+
+Fixed bugs:
+-----------
+* Remove a recursive template call in the junit xsls that could trigger a stack
+  overflow. It now uses Xalan extensions to call a Java class directly.
+  Bugzilla Report 19301
+
+* Fix spurious infinite loop detection for filters (introduced in ant 1.6.0).
+  Bugzilla Report 23154.
+
+* Fix handling of default ant namespace for nested elements.
+
+* Fix jboss element of ejb task (introduced in ant 1.6.0).
+
+* <whichresource> failed to load classes correctly.
+
+* Ant could fail to start with a NullPointerException if
+  ANT_HOME/lib/ant-launcher.jar was part of the system CLASSPATH.
+
+* presetdef'ed types did not work with the ant-type attribute
+
+* fixed case handling of macrodef attributes and elements. Bugzilla
+  Reports 25687 and 26225.
+
+* <java> ignored the append attribute, Bugzilla Report 26137.
+
+* The gcj compiler adapter for <javac> failed if the destination
+  directory didn't exist.  Bugzilla Report 25856.
+
+* Ant now fails with a more useful message if a new process will be
+  forked in a directory and that directory doesn't exist.
+
+* <splash> used to break the build on non-GUI environments.  Bugzilla
+  report 11482.
+
+* Ant 1.6.0 cannot run build scripts in directories with non-ASCII names.
+  Bugzilla Report 26642.
+
+Other changes:
+--------------
+* Shipped XML parser is now Xerces-J 2.6.1
+
+* Translate task logs a debug message specifying the number of files
+  that it processed.  Bugzilla Report 13938.
+
+* <fixcrlf> has a new attribute - fixlast. Bugzilla Report 23262.
+
+* <p4submit> has 2 new attributes, needsresolveproperty and changeproperty.
+  Bugzilla Report 25711.
+
+* add description attributes to macrodef attributes and elements.
+  Bugzilla Report 24711.
+
+* Extending ClearCase Tasks :
+ - Added an extra option to 'failonerr' to each ClearCase task/command.
+ - Extended the functionality of cccheckout. It can check (notco) to see if
+  the desired element is already checked out to the current view. Thus it
+   won't attempt to check it out again.
+ - Added three new ClearCase commands: ccmkattr, ccmkdir, ccmkelem
+  Bugzilla Report 26253.
+
+* added nested text support to <macrodef>
+
+* added initial support for Java 1.5.  Java 1.5 is now correctly
+  detected by Ant and treated just like Java 1.4.  You can now specify
+  source="1.5" in the <javac> task.
+
+* created new task <cvsversion>
+
+* added support for branch logging via the tag attribute in <cvschangelog>
+  Bugzilla Report 13510.
+
+* added support the groovy language in the script and scriptdef tasks
+
+Changes from Ant 1.5.4 to Ant 1.6.0
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* This version of Ant can not be built with JDK 1.1 and requires at
+  least Java 1.2 at runtime as well.  Compiling for a 1.1 target is
+  still supported.
+
+* Targets cannot have the empty string as their name any longer.
+
+* ant.jar's manifest does no longer include a Class-Path entry, so it
+  is no longer possible to run Ant via "java -jar ant.jar" without
+  manually altering the CLASSPATH.  Instead of that a file
+  ant-bootstrap.jar is included in the etc directory of the binary
+  distribution, copy this to the lib directory and use
+  "java -jar ant-bootstrap.jar" instead if you want to run Ant without
+  the wrapper script (not recommended).
+
+* The <script> task now requires Apache BSF instead of the older IBM
+  version.  See <http://jakarta.apache.org/bsf/>
+
+* <xmlproperty> will no longer fail if the file to be loaded doesn't exist.
+
+* XML namespaces are now enabled in the XML parser, meaning XML namespace
+  declarations no longer cause errors. However task names containing colons
+  will cause errors unless there is a corresponding namespace uri.
+
+* The <ftp> and <telnet> tasks now require Jakarta Commons Net instead
+  of the older ORO Netcomponents version.  See
+  <http://jakarta.apache.org/commons/net/index.html>.
+
+* <input> will no longer prompt the user and wait for input if the
+  addproperty attribute is set to a property that has already been
+  defined in the project.  If you rely on the task waiting for input,
+  don't use the addproperty attribute.
+
+* The Class-Path attribute in manifests will no longer merge the
+  entries of all manifests found, but will be treated like all other
+  manifest attributes - the most recent attribute(s) will be used.
+
+* New Launch mechanism implemented. This moves some functionality from
+  the batch files / shell scripts into Java. This removes environment
+  limitations, for command issues, directory depth issues on Windows. Also
+  allows a per-user library location to be used if the main Ant install
+  is locked down.
+
+* The Entry nested element of PropertyFile will not any more have its value
+  attribute (actually increment) overwritten with the new value of the entry
+  after execution.
+
+* Output stored from a <java> or <exec> task is now exactly as generated. No
+  conversion to platform end-of-line characters is performed.
+
+* <translate> will now preserve line endings.
+
+* <ftp> followsymlinks="false" in nested fileset definitions is explicitly
+  required in order to exclude remote symbolic links (when doing a get, chmod,
+  delete, rmdir).
+
+* The values of the Copy#fileCopyMap variable has changed from String to
+  String[]. (In java 1.5 terms it was Hashtable<String, String> and
+  is now Hashtable<String, String[]>). This will affect third party code
+  that extend Copy and override Copy#doFileOperations.
+
+* <loadproperties> didn't expand properties while <property file="..."/>
+  does, so they were not equivalent.  This has been fixed, which means
+  that propetries may get expanded twice if you use an
+  <expandproperties> filterreader.  Bugzilla Report 17782.
+
+* User defined tasks and typedefs are now handled internally in the
+  same way as predefined tasks and typedefs. Also tasks and typedefs
+  are resolved at a later stage. This causes some
+  differences especially for user defined task containers.
+
+* <checksum> log message "Calculating checksum ..." has been degraded
+  from INFO to VERBOSE.
+
+Fixed bugs:
+-----------
+* Filter readers were not handling line endings properly.  Bugzilla
+  Report 18476.
+
+* Filtersets were also not handling line endings properly.
+
+* Expand tasks did not behave as expected with PatternSets.
+
+* <property environment=... /> now works on OS/400.
+
+* <cab> could hang listcab on large <fileset>s.
+
+* The starteam stcheckout, stcheckin tasks now correctly compute
+  status of files against whatever local tree they are run against
+  and, optionally, will not process a file if it is current.
+  Previously you had to process everything unless you ran against the
+  default folder which wasn't the normal use-case for ant-starteam.
+  The stlist task now similarly displays that status correctly making
+  it a more generally useful tool.
+
+* entity includes would cause exceptions if path names included spaces.
+
+* addConfiguredXXX would not work for TaskAdapter wrapped tasks
+
+* Fix <ilasm> outputfile testing so that the output file does not need
+  to exist beforehand.
+
+* Ant will now exit with a return code of 1 if it encounters problems
+  with the command line arguments.
+
+* ClassLoader creation changes to use a factory method in Project. A new
+  class AntClassLoader2 implemented for 1.2+ specific features including
+  Package information and addition of classes specified in the Class-Path
+  element of a Jar's manifest.
+
+* It is now possible in <exec> to resolve the executable to a project
+  basedir or execution dir relative executable. The resolveExecutable
+  must be used to pick up such executables.
+
+* splash screen wouldn't disappear when build was finished.
+
+* <exec> output and error streams can now be redirected independently
+  to either a property or a file (or both)
+
+* TarEntry's File-arg constructor would fail with a
+  StringIndexOutOfBoundsException on all OSes where os.name is shorter
+  than seven characters.  Bugzilla Report 18105.
+
+* <copy> and <move>'s failonerror didn't apply to filesets pointing to
+  non-existant directories.  Bugzilla Report 18414.
+
+* The <stripjavacomments> filter sometimes removed parts of string
+  constants.  Bugzilla Report 17441.
+
+* <antlr> will now recompile your grammar if the supergrammar has
+  changed.  Bugzilla Report 12691.
+
+* <property env> will now work on Unices with /bin/env instead of
+  /usr/bin/env.  Bugzilla Report 17642.
+
+* <jar index="on"> could include multiple index lists.  Bugzilla 10262.
+
+* The index created by <jar> didn't conform to the spec as it didn't
+  include the top-level entries.  Bugzilla Report 16972.
+
+* <tar> and <zip> didn't honor the defaultexcludes attribute for the
+  implicit fileset.  Bugzilla Report 18637.
+
+* The <replacetokens> filter would throw an exception if the token's
+  value was an empty string.  Bugzilla Report 18625.
+
+* Perforce tasks relying on output from the server such as <p4change>
+  and <p4label> were hanging. Bugzilla Reports 18129 and 18956.
+
+* Improve exception and logging behavior of Perforce tasks.
+  Bugzilla report 18154.
+
+* build.sh install had a problem on cygwin (with REALANTHOME).
+  Bugzilla Report 17257
+
+* <replaceregexp> didn't work for multi-byte encodings if byline was false.
+  Bugzilla Report 19187.
+
+* <replaceregexp> was altering unnecessarily the timestamp of the directories
+  containing the files to process
+  Bugzilla Report 22541.
+
+* file names that include spaces need to be quoted inside the @argfile
+  argument using forked <javac> and (all JDKS).  Bugzilla Report 10499.
+  NB : a first correction was only introducing quotes for JDK 1.4
+  It has been changed to quote for all external compilers when paths
+  contain spaces.
+  Also the backslashes need to be converted to forward slashes
+  Bugzilla Report 17683.
+
+* Setting filesonly to true in <zip> and related tasks would cause the
+  archives to be always recreated.  Bugzilla Report 19449.
+
+* file names that include spaces need to be quoted inside the @argfile
+  argument using <javadoc> and JDK 1.4.  Bugzilla Report 16871.
+
+* <junit> didn't work with custom formatters that were only available
+  on the user specified classpath when a timeout occurred.  Bugzilla
+  Report 19953.
+
+* <different> selector : make ignoreFileTimes effectively default to true
+  and fix a bug in the comparison of timestamps. Bugzilla Report 20205.
+
+* <different> selector can now be nested directly under a fileset
+  Bugzilla Report 20220.
+
+* <cvstagdiff> had a problem with "dd-MM-yy hh:mm:ss" formats
+  Bugzilla Report 15995.
+
+* <cvstagdiff> cvsroot and package attributes added to the root
+  element tagdiff of the xml output
+  Bugzilla Report 16081.
+
+* <cvstagdiff> had a problem with aliased modules and with requests for
+  multiple modules. Bugzilla Reports 21373 and 22877.
+
+* <cvstagdiff> could not parse properly the revision number of new files with
+  CVS 1.11.9 or higher. Bugzilla Report 24406.
+
+* <fixcrlf> make fixcrlf create its temporary files in the default directory
+  of FileUtils#createTempFile instead of the destination dir of fixcrlf.
+  Bugzilla Report 20870.
+
+* <ejbjar> implementation for Borland.
+  Prevent the task from being blocked by error messages coming from java2iiop.
+  Bugzilla Report 19385.
+
+* <unzip>'s and <untar>'s nested patternsets didn't work as documented
+  when the pattern ended in a slash or backslash.  Bugzilla Report 20969.
+
+* <fixcrlf> will now create the parent directories for the destination
+  files if necessary.  Bugzilla Report 20840.
+
+* <xmlproperty> now handles CDATA sections. BugZilla Report 17195
+
+* <translate> now translate tokens that are placed close together.
+  Bugzilla Report 17297
+
+* Nested websphere element for ejbjar does not support spaces in file name.
+  Bugzilla Report 21298
+
+* Don't multiply Class-Path attributes when updating jars.  Bugzilla
+  Report 21170.
+
+* Do not overwrite the value (increment) attribute of PropertyFile nested
+  Entry element. Bugzilla Report 21505.
+
+* Prevent sysproperties with no key or no value from being added in <junit>.
+  Bugzilla Report 21684.
+
+* Allow references to be properly inherited via antcall
+  Bugzilla Report 21724.
+
+* ftp chmod failed when the remote system was UNIX and local system Windows
+  Bugzilla Report 21865.
+
+* ftp put with chmod failed when the remote system was UNIX and local system
+  Windows. Bugzilla Report 23143.
+
+* ftp did not set the ascii mode explicity, causing problems with ftp servers
+  having binary as default
+
+* ftp was not able to download files when they were pointed to by symbolic
+  links. Bugzilla Report 14063.
+
+* ftp is able to download also directories pointed to by symbolic links.
+
+* replace would change \r\n into \r\r\n under Windows.
+
+* junitreport with frames did not display a link for classes without a package
+  or in the top package.
+  Bugzilla Report 21915.
+
+* Project.toBoolean(String) now handles null as argument and does not throw a
+  NullPointerException any more.
+
+* The socket condition will now close the socket created to test.
+  Bugzilla Report 23040.
+
+* <junit includeantruntime="true" fork="true"> replaced the CLASSPATH instead
+  of adding to it.  Bugzilla Report 14971.
+
+* <splash> could fail on JVMs that use null to indicate the system classloader.
+  Bugzilla Report 23320.
+
+* <xmlcatalog>s only worked when defined inside of tasks.  Bugzilla
+  Report 20965.
+
+* <csc> and siblings (<vbc> <jsharpc>) handle large filesets by
+automatic use of response files.  Bugzilla report #19630
+
+Other changes:
+--------------
+
+* Shipped XML parser is now Xerces 2.6.0
+
+* All tasks can be used outside of <target>s.  Note that some tasks
+  will not work at all outside of targets as they would cause infinite
+  loops (<antcall> as well as <ant> and <subant> if they invoke the
+  current build file).
+
+* Six new Clearcase tasks added.
+
+* A new filter reader namely tokenfilter has been added.  Bugzilla
+  Report 18312.
+
+* A new attribute named skip is added to the TailFilter and
+  HeadFilter filter readers.
+
+* The filesetmanifest attribute of <jar> has been reenabled.
+
+* The start and end tokens for <translate> may now be longer than a
+  single character.
+
+* <setproxy> lets you set the username and password for proxies that
+  want authentication
+
+* <loadproperties> has a new encoding attribute.
+
+* <echoproperties> can now create XML output.
+
+* <echoproperties> has a new srcfile attribute that can make it read
+  properties files and output them instead of Ant's properties.
+
+* <filterset> will now resolve filters recursively.
+
+* <input> has a new attribute that allows you to specify a default value.
+
+* Added <image> task (requires JAI).
+
+* <image> task has now proportions attribute in the <scale/> nested element
+  instead of keepproportions (bringing in more functionality)
+
+* New condition <isreference>
+
+* <ftp> now has a preservelastmodified attribute to preserve the
+  timestamp of a downloaded file.
+
+* new rmdir action for <ftp> that removes directories from a fileset.
+
+* <ftp> has attributes timediffauto and timediffmillis to use together
+  with the newer attribute to tell ant to take into account a time difference
+  between client and remote side.
+  Bugzilla Report 19358.
+
+* <ftp> has been optimized to go directly to the include patterns.
+  This reduces scanning time under UNIX when followsymlinks="true"
+  and casesensitive="true" (the default)
+  Bugzilla Report 20103.
+
+* The SOS and VSS tasks will no longer unconditionally prepend a $ to
+  vsspath or projectpath.
+
+* OS/400 now gets detected by the os condition.
+
+* <arg> has a new attribute pathref that can be used to reference
+  previously defined paths.
+
+* <xmlproperty> has been improved, you can now expand ${properties},
+  define ids or paths and use Ant's location magic for filename resolutions
+  in the XML file.
+
+* <xmlcatalog> will now support external catalogs according to the
+  OASIS "Open Catalog" standard - if resolver.jar (newer than version
+  1.0) from Apache's xml-commons is in your CLASSPATH.
+
+* Starteam tasks now have support for revision labels and build labels.
+  Checkouts now have the option of using repository timestamps, instead
+  of current.
+
+* new task <symlink> that creates and maintains symbolic links.
+
+* new tasks <chown> and <chgrp> which are wrappers of the Unix commands.
+
+* new task <attrib> to change file attributes on Windows systems.
+
+* <style> has a new attribute reloadstylesheet to work around a
+  bug in widespread Xalan versions.
+
+* <tarfileset> has a new dirmode attribute to specify the permissions
+  for directories.
+
+* <fixcrlf>'s eol attribute now also understands "mac", "unix" and "dos".
+
+* <classfileset> now picks up dependencies of the form MyClass.class. This
+  works for the code generated by the Sun java compiler. It may not work for
+  all compilers.
+
+* a new attribute "globalopts" can be added to all Perforce tasks.
+  You can put in it all the strings described by p4 help usage. Refer to
+  the docs for more information.
+
+* new Perforce tasks <p4integrate> , <p4resolve>, and <p4labelsync>
+
+* <p4submit> will change the property p4.change if the Perforce server
+  renumbers the change list.
+  It will set the property p4.needsresolve if the submit fails,
+  and the message says that file(s) need to be resolved.
+
+* <replaceregexp> now has an optional encoding attribute to support
+  replacing in files that are in a different encoding than the
+  platform's default.
+
+* The <exec> task may now have its input redirected from either a file
+  or a string from the build file. The error output can be separated
+  to a different file when outut is redirected. standard error may be
+  logged to the Ant log when redirecting output to a file
+
+* The <java> task also supports the input redirection and separate
+  error streams introduced to the <exec> task. In addition, it is now
+  possible to save the output into a property for use within the build
+  file as was possible with <exec> in Ant 1.5
+
+* The <javadoc> task <tag> subelement has been enhanced to allow files
+  with tag mappings to be used.
+
+* New tasks: <scp> supports file transfers, <sshexec> executes a
+  command over SSH.  They require jsch, a BSD licensed SSH library that
+  can be found at http://www.jcraft.com/jsch/index.html
+
+* New filterreader <escapeunicode/>.
+
+* Support for HP's NonStop Kernel (Tandem) OS has been added.
+
+* <cab>'s basedir attribute is now optional if you specify nested
+  filesets.  Bugzilla Report 18046.
+
+* New task <sync> that synchronizes two directory trees.
+
+* <apply> has new forwardslash attribute that can force filenames to
+  use forward slashes (/) as file separators even on platforms with a
+  different separator.  This is useful if you want to run certain
+  ported Unix tools.
+
+* Copy has a new outputencoding attribute that can be used to change
+  the encoding while copying files.  Bugzilla Report 18217.
+
+* The xml formatter for JUnit will now honor test case names set with
+  setName.  Bugzilla Report 17040.
+
+* JUnit now has an attribute reloading, which, when set to false,
+  makes the task reuse the same class loader for a series of tests.
+
+* <concat> now supports filtering and can check timestamps before
+  overriding a file.  Bugzilla Report 18166.
+
+* <junit> has a new attribute tempdir that controls the placement of
+  temporary files.  Bugzilla Report 15454.
+
+* <jdepend> now supports a new nested element <classespath> which is
+  the same as <sourcespath> but point to compiled classes (the
+  prefered mode of operation for JDepend > 2.5).  Additionally, nested
+  <exclude> elements can be used to exclude certain packages from
+  being parsed.  Bugzilla Report 17134.
+
+* The JProbe tasks now also work with JProbe 4.x.  Bugzilla Report 14849.
+
+* <javacc> and <jjtree> will now autodetect JavaCC 3.x and can use it.
+
+* <sql> has a new attribute to control escape processing.
+
+* <sql> is able to display properly several resultsets if you are
+  running a compound sql statement. Bugzilla Report 21594.
+
+* A new <containsregexp> selector has been added, that selects files
+  if their content matches a certain regular expression.
+
+* <antlr>'s debug attribute has been enabled.  Bugzilla Report 19051.
+
+* <mail> has a new attribute charset. Bugzilla Report 15434.
+
+* <mail> has new attributes user and password for SMTP auth.
+  maillogger can also use this.
+  The implementation only works with JavaMail (encoding="MIME").
+  Implementation with plain mail remains to do.
+  Bugzilla Report 5969.
+
+* <mail> and mailloger support SMTP over TLS/SSL
+  Bugzilla Report 19180.
+
+* <mail> the attributes from, replyto ,tolist, cclist, bcclist
+  can now contain email addresses of the form name <address@xyz.com>
+  or (name) address@xyz.com
+  Bugzilla Report 22474.
+
+* <mail> (version PlainMail)
+  prevent blank headers from being sent,
+  make the order of the headers of plain mail messages predictable
+  Bugzilla Report 22088.
+
+* <zipfileset> can now be defined in the main body of a project
+  and referred to with refid="xyz". Bugzilla Report 17007.
+
+* A wrapper script for OS/2 has been added.
+
+* <unzip> will now detect and successfully extract self-extracting
+  archives.  Bugzilla Report 16213.
+
+* <stcheckout> has a new attribute "converteol" that can be used to
+  control the automatic line-end conversion performed on ASCII files.
+  Bugzilla Report 18884.
+
+* Users can now modify the list of default excludes using the new
+  defaultexcludes task.  Bugzilla Report 12700.
+
+* There is a new data type <propertyset> that can be used to collect
+  properties.  It is supported by <ant>, <antcall>, <subant>, <java>,
+  <echoproperties> and <junit>.
+
+* <concat> can now control the encoding of the output as well and optionally
+  add new-line characters at the end of files that get concatenated but
+  don't end in newlines.  Bugzilla Report 12511.
+
+* <rpm> will detect the rpmbuild executable of RedHat 8.0 and newer
+  and use that if it is on your PATH.  Bugzilla Report 14650.
+
+* A new task <rexec> has been added that requires commons-net to work.
+  Bugzilla Report 19541.
+
+* <javadoc> now supports a nested <arg> element in addition to the
+  additionalparams attribute.
+
+* You can now determine the order of standard tags in <javadoc> via
+  <tag> elements - you must not use the description attribute for them.
+  Bugzilla Report 18912.
+
+* <javadoc> now supports the -noqualifier switch.  Bugzilla Report 19288.
+
+* <javac>'s executable attribute can now also be used to specify the
+  executable for jikes, jvc, sj or gcj.  Bugzilla Report 13814.
+
+* <javac> has a new attribute tempdir that can control the placement
+  of temporary files.  Bugzilla Report 19765.
+
+* A new magic property build.compiler.jvc.extensions has been added
+  that can be used to turn of Microsoft extensions while using the jvc
+  compiler.  Bugzilla Report 19826.
+
+* You can now limit the parallelism of <apply> and <chmod> by using the new
+  maxparallel attribute.
+
+* With the new addsourcefile attribute, you can make <apply> ommit the
+  source file names from the command line.  Bugzilla Report 13654.
+
+* <apply> and <chmod> now support nested <filelist>s as well as <dirset>s.
+  Bugzilla Reports 15929 and 20687.
+
+* <apply> and <chmod> will display a summary if you set the new
+  verbose attribute to true.  Bugzilla Report 19883.
+
+* <copy>/<move>'s failonerror attribute can now also be used to
+  continue the build if an I/O error caused a problem.  Bugzilla
+  Report 12999.
+
+* new selector <type/> allowing to select only files or only directories.
+  Bugzilla Report 20222.
+
+* <java> and <junit> now support a nested <bootclasspath> element that
+  will be ignored if not forking a new VM.
+
+* <junit>'s nested <formatter> elements now support if/unless clauses.
+
+* <ejbjar>
+  cmpversion attribute added
+  jboss element will look for jbosscmp-jdbc.xml descriptor
+  if ejbjar has cmpversion="2.0" set
+  Bugzilla Reports 14707 and 14709.
+
+* <pvcs> config attribute added to set the location of a specific PVCS
+  .cfg file
+  Bugzilla Report 9752
+
+* <mapper> has an "unpackage" mapper
+  Bugzilla Report 18908
+
+* Added <scriptdef> task allowing tasks to be defined using any BSF-supported
+  scripting language.
+
+* <touch>'s datetime attribute can now accept time with a granularity
+  of seconds as well.  Bugzilla Report 21014.
+
+* <checksum> has two new properties: totalproperty and todir.
+
+* FileUtils#createTempFile will now create temporary files in the
+  directory pointed to by the property java.io.tmpdir
+
+* <unzip> and friends now supports an optional encoding attribute to
+  enable it to expand archives created with filenames using an encoding
+  other than UTF8.  Bugzilla Report 10504.
+
+* <patch> has a new attribute destfile that can be used to create a new
+  file instead of patching files in place.
+
+* OpenVMS is detected as a valid OS family.
+
+* DirectoryScanner has been optimized for cases where include patterns do not
+  start with wildcards.  Bugzilla Report 20103.
+
+* DirectoryScanner begins to be optimized not to scan excluded directories.
+  Bugzilla Report 21941.
+
+* Added keep-going feature. Bugzilla Report 21144
+
+* The archives generated by <zip> and friends will now contain CRC and
+  size information in the "local file header", thereby providing this
+  information to applications that read the archives using
+  java.util.ZipInputStream.  Bugzilla Report 19195.
+
+* <copy> and <move> can now handle mappers that return multiple
+  mappings per source path. This behaviour is enabled by using
+  an enablemultiplemapping attribute. Bugzilla Report 21320.
+
+* <exec> will now work on OpenVMS (please read the notes in
+  <exec>'s manual page).  Bugzilla Report 21877.
+
+* <exec> will now have a new attribute spawn (default false).
+  If set to true, the process will be spawned. Bugzilla Report 5907.
+
+* <java> will now have a new attribute spawn (default false).
+  If set to true, the process will be spawned. Bugzilla Report 5907.
+
+* <parallel> now supports a timeout which can be used to recover
+  from deadlocks, etc in the parallel threads. <parallel> also
+  now supports a <daemons> nested element. This can be used to
+  run tasks in daemon threads which the parallel task will not
+  wait for before completing. A new attribute failonany will cause
+  <parallel> to throw an exception if any thread fails without
+  waiting for all other threads to complete.
+
+* <zip> and friends will consume far less memory than they used to
+  when run with compress="false".  Bugzilla Report 21899.
+
+* <if/> and <unless/> attributes added to <param/> element of <style>
+   Bugzilla Report 22044
+
+* <zip> and friends have a new attribute "keepcompression" that can be
+  used to incrementally build an archive mixing compressed and uncompressed
+  entries.
+
+* <junit>'s XML formatter adds a new classname attribute to the <testcase>
+  elements.
+
+* new <permissions> type add permission handling to the code
+  this type can be nested in the <java> and <junit> tasks.
+  Bugzilla Report 22533.
+
+* additional shortcuts for ant options (-d --> -debug, -e --> -emacs,
+  -h --> -help, -p --> -projecthelp, -s --> -find).
+
+* new selector <modified>. "cache" was renamed to "modified".
+  Bugzilla Report 20474.
+
+* <stcheckout> and <stlist> have a new asofdate attribute that can be
+  used to checkout/list files based on a date instead of a label.
+  Bugzilla Report 20578.
+
+* New filter <concatfilter>. Adds the content of file at the beginning
+  or end of a file. Discussion started at
+  http://marc.theaimsgroup.com/?l=ant-user&m=106366791228585&w=2
+
+* New task <import>
+
+* New task <macrodef>
+
+* New task <presetdef>
+
+* Ant libraries that can make use of namespaces to avoid name
+  clashes of custom tasks
+
+* <java> and <junit> now support <assertions>, which let you enable
+  and disable Java1.4 assertions on a package or class basis. These
+  only work when fork=true, currently.
+
+* .NET tasks expanded with VB support <vbc> and J#, via <jsharp>,
+  <importtypelib> and <ilasm>. <csc> supports nested <src> types,
+  <defines> for (potentially conditional) definitions, <reference>
+  filesets for references. The executable attribute lets you switch to
+  mono or other implementations -<csc> has been tested with Mono on
+  Linux and OSX.
+
+
+Changes from Ant 1.5.3 to Ant 1.5.4
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* If the Visual Age tasks used to work for you, they may stop doing so
+  now - and we'd like to know about it.  The current set of tasks is
+  supposed to work with any version of VAJ starting with 3.0.
+
+Fixed bugs:
+-----------
+
+* The Visual Age for Java tasks didn't work (at least for versions 3.0
+  and higher).  Bugzilla Report 10016.
+
+* URL-encoding in <vaj*port> didn't work properly.
+
+* VAJRemoteUtil called getAbsolutePath instead of getPath
+  causing problems when using a Windows VAJ server from a UNIX server.
+  Bugzilla Report 20457.
+
+* VAJImport task failed with NullPointerException when using DirectoryScanner.
+  Bugzilla Report 22080.
+
+Other changes:
+--------------
+
+* Shipped XML parser is now Xerces 2.5.0
+
+* <javah> will invoke oldjavah on JDK 1.4.2.  Bugzilla Report 18667.
+
+* The VAJ tasks now support a haltonfailure attribute to conditionally
+  keep building even if they fail.
+
+* It is now possible to use the latest (versioned or unversioned) edition
+  in <vajload> by using special wildcard characters.  Also fixes
+  Bugzilla Report 2236.
+
+Changes from Ant 1.5.2 to Ant 1.5.3
+===================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* The <zip> task and friends have again changed a method signature
+  (sorry, was necessary to fix bug 17780).  The return type of
+  getResourcesToAdd has changed.
+
+Fixed bugs:
+-----------
+
+* <zipfileset>'s filemode would get ignored and the dirmode was used
+  for the included files as well.  As a side effect, WinZIP was unable
+  to extract or display the files, so they seemed to be missing from
+  the archive.  Bugzilla Report 17648.
+
+* <ftp> could use the wrong path separator when trying to change the
+  remote working directory.  Bugzilla Report 17735.
+
+* <jar update="true"> would loose all original files if you didn't
+  specify any nested <(zip)fileset>s and the manifest had changed.
+  Bugzilla Report 17780.
+
+* If you used a value starting with \ on Windows for the appxml
+  attribute of <ear> or the webxml attribute of <war>, it would be
+  ignored.  Bugzilla Report 17871.
+
+* Ant will no longer implicitly add Sun's rt.jar in <javac> when you
+  use jvc and don't specify a bootclasspath.  Bugzilla Report 18055.
+
+* The prefix attribute of <zipfileset> would not generate directory
+  entries for the prefix itself.  Bugzilla Report 18403.
+
+* starteam checkout can now handle deleted labels.  Bugzilla Report 17646.
+
+* The Unix wrapper script failed if you invoked it as a relative
+  symlink and ANT_HOME has not been set.  Bugzilla Report 17721.
+
+Other Changes:
+--------------
+* Added ability to specify manifest encoding for the <jar> and
+  <manifest> tasks
+
+Changes from Ant 1.5.1 to Ant 1.5.2
+=============================================
+
+Changes that could break older environments:
+--------------------------------------------
+* ANT_OPTS environment variable is now applied at the start of the
+  Java command line, allowing position specific parameters of some
+  JVMs, such as -classic to be specified.
+
+* ZipScanner#getIncludedFiles will now return the names of the ZipEntries
+  that have been matched instead of the name of the archive.
+
+* The <zip> task and friends have been heavily modified, almost every
+  method signature of the Zip class has changed.  If you have subclassed
+  Zip (or one of its subclasses), your class will most likely not
+  compile against the current code base.  If it still compiles, it will
+  probably not work as in Ant 1.5.1.
+
+Fixed bugs:
+-----------
+* <translate> was not ignoring comment lines.
+
+* <manifest> wouldn't update an existing manifest if only an attribute
+  of an existing section changed.
+
+* ant.bat now supports the ANT_ARGS and JAVACMD environment variables
+  again (like Ant 1.5 did).
+
+* The "plain" <junit> <formatter> could throw a NullPointerException
+  if an error occurred in setUp.
+
+* <junit> will now produce output when a test times out as well.
+
+* <replace> would count some internal character replacements when
+  reporting the number of replaced tokens.
+
+* <concat> would cause an exception if a <filelist> pointed to files
+  that do not exist.
+
+* <javadoc> will now pass -source to custom doclets as well.
+
+* <cvstagdiff> would throw a NullPointException if there had been no
+  differences.
+
+* <cvschangelog> could miss today's changes.
+
+* <concat> could append newline characters between concatenated files.
+
+* <xmlvalidate> ignored the specified encoding of the files to
+  validate.
+
+* the errorsbeginat attribute of the <http> condition didn't work.
+
+* Ant will try to force loading of certain packages like com.sun.*
+  from the system classloader.  The packages are determined by the
+  version of the JVM running Ant.
+
+* Ant didn't find the runtime libraries on IBM's JDK 1.4 for Linux.
+
+* random component of temporary files is now always a positive integer.
+
+* Ant could incorrectly try to use the 1.4 regexp implementation even
+  if it isn't available if you run the JVM with -Xverify:none.
+
+* Ant would die with an exception if you used nested <reference>
+  elements in Ant and the refid attribute didn't point to an existing
+  project reference.
+
+* The <get> task can now be compiled (and Ant thus bootstrapped) using
+  Kaffee.
+
+* build.sysclasspath will now be honored by more tasks.
+
+* The signjar keystore attribute has been reverted to a String allowing
+  it to once again accept URLs. This should not affect current File based usage
+  unless you are extending the Signjar task.
+
+* <jar update="true"> would remove the original manifest.
+
+* fix up folder creation in PVCS task
+
+* <tar>'s up-to-date check didn't work for nested <(tar)fileset>s.
+
+* Corrected a problem in XMLLogger where it would not associated
+  messages with a taskdef'd task
+
+* <uptodate> now works when using attributes (i.e. not filesets) and pointing
+  to the same file
+
+* Java task (and output system) now stores output which doos not end
+  with a line feed.
+
+* splash screen wouldn't disappear when build was finished.
+
+* <exec> now supports OS/2.
+
+* <zip> and friends would only update/recreate existing archives if
+  the files to add/update have been newer than the archive.
+
+* <javadoc>'s <link> element could fail for offline="true" on some JDKs.
+
+Other changes:
+--------------
+
+* MailLogger now sets the Date header correctly.
+
+* Shipped XML parser is now Xerces 2.3.0
+
+* signjar now accepts a maxmemory attribute to allow the memory allocated to the
+  jarsigner tool to be specified. The jarsigner from the JDK's JAVA_HOME bin
+  dir is now used rather than the first jarsigner on the path.
+
+* **/.DS_Store has been added to the list of default pattern excludes.
+
+* The Created-By header in the default manifest now contains the JVM
+  vendor and version according to the jar specification. A new header,
+  Ant-Version provides the Ant version used to create the jar.
+
+* <zip> can now store Unix permissions in a way that can be
+  reconstructed by Info-Zip's unzip command.
+
+Changes from Ant 1.5.1Beta1 to 1.5.1
+====================================
+
+Fixed bugs:
+-----------
+
+* <tstamp>'s prefix attribute failed to apply to nested <format> elements.
+
+* <junitreport> created an empty junit-noframes.html if no format had
+  been specified.
+
+* <basename> would remove more than it should if the file name
+  contained more than one dot.
+
+* <filterset>s nested into <filterset>s didn't work.
+
+Other changes:
+--------------
+
+* Shipped XML parser is now Xerces 2.2.0
+
+* Filesets now support a 'file' attribute, allowing a single-file
+  fileset to be constructed without having to specify its parent
+  directory separately.
+
+* <junit> will now return the result of a call to getName instead of
+  "unknown" for Test implementations that don't extend TestCase but have
+  a public String getName() method.
+
+Changes from Ant 1.5 to 1.5.1Beta1
+==================================
+
+Fixed bugs:
+-----------
+* Date/time in CvsChangeLog was in local timezone and 12 hour format leading
+  to a problem when sorting by time. It is now UTC (GMT) and in 24-hour
+  format as per cvs 'specifications'.
+
+* CvsTagDiff now supports ampersand modules or modules that have a different
+  root directory than their name.
+
+* EjbJar threw NPEs for the Websphere element. The property 'websphere.home'
+  was not documented.
+
+* Mail example in the documentation was not correct.
+
+* Checksum was broken in the following scenario:
+  (using verifyproperty OR in a condition) AND using filesets
+  with multiple files.
+
+* The ExpandProperties filter threw NPEs when defined using
+  the <filterreader> format.
+
+* The sh wrapper script didn't work under Cygwin if ANT_HOME wasn't
+  set with a Unix style filename.
+
+* The sh wrapper script could fail if you started Ant from a directory
+  with whitespace in its name.
+
+* ant -diagnostics was not working properly when the task dependency
+  was missing and was just printing the missing dependency.
+
+* If a task got redefined via <taskdef>, it lost its child elements.
+
+* <property>'s classpathref attribute was broken.
+
+* <arg line="''" /> would result in no command line argument, will now
+  be a single empty argument.  Use <arg value="''"/> if you need the
+  quotes literally.
+
+* <replaceregexp> could append a newline character at the end of the
+  file.
+
+Other changes:
+--------------
+
+* Appendix E of Java Development with Ant (Loughran/Hatcher) was
+  contributed to the docs.
+
+* <available> will only print deprecration warnings if it is actually
+  used to change the value of a property.
+
+Changes from Ant 1.5beta3 to Ant 1.5
+====================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* The filesetmanifest attribute added to <jar> after the 1.4.1
+  release has been removed for now.  This change may affect only
+  the 1.5Beta/1.6Alpha users.  An attempt will be made to add this
+  feature back into Ant 1.6.
+
+Fixed bugs:
+-----------
+
+* <zip> and friends would always update existing archive if you set
+  the update attribute to true.
+
+* To support backward compatibility with older versions, <pathconvert>
+  will once again set the property, even if the result is the empty
+  string, unless the new 'setonempty' attribute is set to false|no|off
+  (default is "true").
+
+* The manifest task would crash XmlLogger
+
+Other changes:
+--------------
+
+* added **/.svn and **/.svn/** to the default excludes
+
+Changes from Ant 1.5beta2 to Ant 1.5beta3
+=========================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* <pvcs> default filenameformat has been different from Ant 1.4.1.
+  Now it is different from 1.5beta1 and 1.5beta2.
+
+* <pathconvert> won't set the property if the result is the empty string.
+
+Fixed bugs:
+-----------
+
+* <available> could fail to find files or directories that happen to
+  start with the name of the project's basedir but are not children of
+  the basedir.
+
+* Nested <property>'s inside <ant> can now be overriden by subsequent
+  <ant> and <antcall> tasks.
+
+* <xslt>'s outputtype attribute wouldn't do anything.
+
+* <linecontains> filterreader could swallow lines.
+
+* <sequential> used to configure the tasks (set their attributes)
+  before the first task has been executed.  This means that properties
+  that have been set by nested task seemed to be unset for the other
+  tasks in the same <sequential> element.
+
+* <javac>'s sourcepath setting has been ignored by some compiler
+  implementations.
+
+* <javadoc>'s packagelist attribute didn't work.
+
+* the plain mailer would always use port 25 in <mail>.
+
+* Ant's default logger could swallow empty lines.
+
+* ejbjar's iPlanet nested element now can process multiple descriptors.
+
+* IPlanetEjbc was looking in the wrong place for four iiop files.
+
+* <javac> would pass the -source switch to JDK 1.3's javac, even
+  though it doesn't support it.
+
+Other changes:
+--------------
+
+* <checksum> now uses a buffer (of configurable size).
+
+* The "Trying to override task definition" warning has been degraded
+  to verbose level if the two task definitions only differ in the class
+  loader instance that has loaded the definition.
+
+* Add a jvmargs to the ejbjar's weblogic element to allow additional
+  arguments to be provided to the VM runnign ejbc. Document the
+  jvmdebuglevel attribute which can be used to avoid warnings about
+  interface classess being found on the classpath. Document the new
+  <sysproperty> element which allows JVM properties to be defined.
+  Added an outputdir attribute to allow the destination to be a
+  directory into which the exploded jar is written.
+
+* ejbjar now supports Borland Enterprise Server 5 and Jonas 2.5
+
+Changes from Ant 1.5beta1 to Ant 1.5beta2
+=========================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* Properties will now be expanded in mail message bodies.  This means
+  that one $ sign will be stripped if your mail message contains the text $$.
+
+* org.apache.tools.ant.taskdefs.Expand no longer extends MatchingTask.
+
+* Available#setFile now again uses a File argument as it did in 1.4,
+  this may break environments that have been adapted to the String
+  argument version present in 1.5beta1.
+
+Fixed bugs:
+-----------
+* When <move> attempts a rename, it deletes the destination file, if it
+  exists, before renaming the source file.  However, <move> was not
+  checking if the destination file was actually a directory before
+  trying to delete it.
+
+* Make CVS Tasks to work under Cygwin.
+
+* Fix LineContains to handle huge files elegantly without causing
+  Stack Overflows.
+
+* if you ask for the "classic" compiler on Java1.4, you get upgraded to
+  "modern" because there is no classic compiler any more.
+
+* the <http> condition was viewing 404 'not found' exceptions as success. Now
+  it defaults to viewing any response >=400 as an error, and has an
+  errorsBeginAt attribute you can use if you want a higher or lower value.
+
+* <get> throws a build exception on an http authorization error, unless you
+  have set ignoreerrors to true.
+
+* <wsdltodotnet> was spelt in Wintel case: <WsdlToDotnet>. It is now lower
+  case, though the old spelling is retained for anyone who used it.
+
+* Merging of Manifests in jar now works as documented.
+
+* paths that have been separated by colons would be incorrectly parsed
+  on NetWare.
+
+* runant.pl now supports NetWare.
+
+* <tempfile> and <setproxy> tasks were in beta1, but not defined by
+  default; They now are. <tempfile> fills a property with the name of a
+  temporary file; <setproxy> lets you set the JVM's http, ftp and socks proxy
+  settings.
+
+* <available classname="foo" ignoresystemclasses="true"> failed for
+  JDK 1.1 and 1.2, even if the class could be found on the
+  user-specified classpath.
+
+* <property environment=... /> now works on z/OS.
+
+* forked <javac> failed for the wrong reason on JDK 1.1 - Ant would
+  use a temporary file to hold the names of the files to compile under
+  some conditons, but 1.1 doesn't support this feature.  Ant will no
+  longer try this, but you may run into problems with the length of the
+  command line now.
+
+* the refid attribute for <property>s nested into <ant> or <param>s
+  nested into <antcall> didn't work.
+
+* <replaceregexp> didn't work for nested <fileset>s.
+
+* <javadoc> dropped sourcepath entries if no "interesting" .java
+  source files  could be found below them.  This has been backwards
+  incompatible and caused problems with custom doclets like xdoclet.
+
+* Using the doclet, docletpath or docletpathref attributes of
+  <javadoc> may have caused NullPointerExceptions.
+
+* nested <filesets> of <javadoc> would include too much.
+
+* <dependset> will no longer choke on <targetfileset>s that point to
+  non-existing directories.
+
+* <patch> didn't work at all.
+
+* <replace> and <replaceregexp> now fail if the file they are working
+  on is locked.
+
+* <javadoc> would pick up the wrong executable in the combination JDK
+  1.2 and AIX.
+
+Other changes:
+--------------
+
+* z/OS now gets detected by the os condition.
+
+* <fileset> and <dirset> now have an optional followsymlink attribute
+  that can prevent Ant from following symbolic links on some platforms.
+
+* BeanShell is now supported in the <script> task.
+
+* <ejbjar> under Weblogic attempts to use the ejbc20 compiler for 2.0 beans
+  based on the deployment descriptor's DTD reference. Under weblogic 7.00 Beta
+  this ejbc class has been deprecated. To avoid the deprecation warning use
+  ejbcclass="weblogic.ejbc".
+
+* <ejbjar> will add a manifest to the generated jar based on the naming
+  convention in use. This overrides the manifest specified in the
+  <ejbjar> attribute
+
+
+Changes from Ant 1.4.1 to 1.5beta1
+==================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* Important: Single $ signs are no longer silently stripped!
+  Before you panic that we have broken all your build files, we have kept
+  the old "$$" -> "$" behaviour. So only build files which accidentally had
+  a $ sign in a string that was being silently stripped may break.
+  We added this fix to stop newbie confusion; if you want to write a
+  build file which works on ant versions 1.4.1 or earlier, stay with
+  the double $$ sign rule.
+
+* Project.getBuildListeners now returns a clone of the listener
+  list. Changes to the returned list will not affect the listeners
+  currently attached to the Project. It also means that it is safe to
+  iterate over the returned list if listeners are added or removed
+  during the traversal.
+
+* <pvcs> default filenameformat has been different from Ant 1.4.1.
+
+* Some messages that are printed during startup will not be
+  written to the logfile specified via -logfile as they might destroy
+  the format of the file for special BuildLoggers (like XmlLogger).
+
+* The filesetmanifest attribute added to <jar> after the 1.4.1
+  release has been removed for now.  This change may affect only
+  the 1.5Beta/1.6Alpha users.  An attempt will be made to add this
+  feature back into Ant 1.6.
+* Shipped XML parser is now Xerces 2.0.1 along with the XML Parser APIs.
+  XML Parser APIs is a separate jar that contains the necessary
+  JAXP/DOM/SAX classes.
+
+* <telnet> was fixed to expand properties inside nested <read> and
+  <write> elements; before this only happened when you assigned the text
+  to the string attribute. If you had $ signs in the string, they may
+  need escaping.
+
+* the RegexpMatcher interface has been extended to support case
+  insensitive matches and other options - custom implementations of
+  this interface won't work any longer.  We recommend to use the new
+  Regexp interface that also supports substitution instead of the
+  RegexpMatcher interface in the future.
+
+* <gzip> will throw an exception if your src attribute points to a directory.
+
+* Unjar, Unzip and Unwar will throw an exception if the Src attribute
+  represents a directory.  Support for nested filesets is provided
+  instead.
+
+* It is no longer possible to overwrite a property using tasks like
+  <condition>, <exec>, <pathconvert>, or <tstamp>. In some exceptional
+  cases it will generate a warning if you attempt to overwrite an
+  existing property.
+
+* Taskwriters please note: Whenever tasks had any overloaded set* methods,
+  Ant's introspection mechanism would select the last overloaded method
+  provided to it by the Java Runtime.  A modification has now been made such
+  that when the Java Runtime provides a method with a String as its argument,
+  a check is made to see if there is another overloaded method that takes in
+  some other type of argument.  If there is one such method, then the method
+  that takes in String as an argument is not selected by the Introspector.
+
+* The pattern definition **/._* has been included into the Default
+  Excludes list.
+
+* <propertyfile>'s <entry> element was modified to remove "never" as a value
+  as its behavior was undocumented and flakey.
+
+* The -projecthelp flag now only prints out targets that include the
+  'description' attribute, unless the -verbose or -debug flag is included
+  on the Ant command line.
+
+* Ant's testcases now require JUnit 3.7 or above, as they now use the new
+  assertTrue method instead of assert.
+
+* If the 'output' attribute of <ant> is set to a simple filename or a
+  relative path, the file is created relative to ${basedir}, not ${user.dir}.
+
+* The default value for build.compiler is now javac1.x with x
+  depending on the JDK that is running Ant instead of classic/modern.
+
+Fixed bugs:
+-----------
+
+* <available> could fail to find files or directories that happen to
+  start with the name of the project's basedir but are not children of
+  the basedir.
+
+* Nested <property>'s inside <ant> can now be overriden by subsequent
+  <ant> and <antcall> tasks.
+
+* <xslt>'s outputtype attribute wouldn't do anything.
+
+* <linecontains> filterreader could swallow lines.
+
+* <sequential> used to configure the tasks (set their attributes)
+  before the first task has been executed.  This means that properties
+  that have been set by nested task seemed to be unset for the other
+  tasks in the same <sequential> element.
+
+* <javac>'s sourcepath setting has been ignored by some compiler
+  implementations.
+
+* <javadoc>'s packagelist attribute didn't work.
+
+* the plain mailer would always use port 25 in <mail>.
+
+* Ant's default logger could swallow empty lines.
+
+* ejbjar's iPlanet nested element now can process multiple descriptors.
+
+* IPlanetEjbc was looking in the wrong place for four iiop files.
+
+* <javac> would pass the -source switch to JDK 1.3's javac, even
+  though it doesn't support it.
+
+* <zip> and friends would always update existing archive if you set
+  the update attribute to true.
+
+* To support backward compatibility with older versions, <pathconvert>
+  will once again set the property, even if the result is the empty
+  string, unless the new 'setonempty' attribute is set to false|no|off
+  (default is "true").
+
+* The manifest task would crash XmlLogger
+
+* A bug existed that prevented generated log files from being deleted as
+  part of the build process itself.  This has now been fixed.
+
+* Fixed bug where <move> ignored <filterset>s.
+
+* Ant works properly with the combination of Java1.4/WindowsXP.
+
+* Fixed bug where <java> used to sometimes invoke class constructors twice.
+
+* Fixed bug with 4NT shell support.
+
+* Fixed bug where ant would not perform ftp without remotedir being
+  specified even though this was not mandatory.
+
+* Fixed bug where ant would not copy system properties into new Project
+  in ant/antcall tasks when inheritall="false" is set.
+
+* <propertyfile> would not close the original property file.
+
+* <ant> will no longer override a subbuild's basedir with inheritall="true".
+
+* Fixed problem with the built-in <junit> formatters which assumed
+  that only one test could be running at the same time - this is not
+  necessarily true, see junit.extensions.ActiveTestSuite.
+
+* <jar>'s whenEmpty attribute is useless as JARs are never empty, they
+  contain at least a manifest file, therefore it will now print a
+  warning and do nothing.
+
+* <typedef> hasn't been all that useful as it couldn't be used outside
+  of targets (it can now) and nested "unknown" elements have always
+  been considered to be tasks (changed as well).
+
+* <fixcrlf> would fail for files that contained lines longer than 8kB.
+
+* Some junit formatters incorrectly assumed that all testcases would
+  inherit from junit.framework.TestCase.
+
+* <fixcrlf> dropped the first characters from Mac files.
+
+Other changes:
+--------------
+
+* <checksum> now uses a buffer (of configurable size).
+
+* The "Trying to override task definition" warning has been degraded
+  to verbose level if the two task definitions only differ in the class
+  loader instance that has loaded the definition.
+
+* Add a jvmargs to the ejbjar's weblogic element to allow additional
+  arguments to be provided to the VM runnign ejbc. Document the
+  jvmdebuglevel attribute which can be used to avoid warnings about
+  interface classess being found on the classpath. Document the new
+  <sysproperty> element which allows JVM properties to be defined.
+  Added an outputdir attribute to allow the destination to be a
+  directory into which the exploded jar is written.
+
+* ejbjar now supports Borland Enterprise Server 5 and Jonas 2.5
+
+* added **/.svn and **/.svn/** to the default excludes.
+
+* Selector Elements now provide a way to create filesets based on
+  sophisticated selection criteria.
+
+* Gzip and Bzip2 files can now be constructed in the fly when using
+  the tar task without having to create the intermediate tar file on
+  disk.  The Untar task can also untar GZip and BZip2 files on the fly
+  without creating the intermediate tar file.
+
+* New optional type, <classfileset> added.
+
+* <ejbjar> now allows control over which additional classes and interfaces
+  are added to the generated EJB jars. A new attribute "dependency" can be
+  defined which controls what classes are added. The addition of classes now
+  uses the Jakarta-BCEL library rather than reflection, meaning bean classes are
+  no longer loaded into Ant's JVM. The default dependency analyzer is known as
+  the ancestor analyzer. It provides the same behaviour as the 1.4.1 version of
+  <ejbjar>. If the BCEL library is not present, a warning will be issued stating
+  the ancestor analyzer is not available. In this case <ejbjar> will continue
+  to function but will not add super classes to the jar.
+
+* <available> has a new attribute named ignoreSystemClasses.
+
+* New task <cvschangelog/> generates an XML report of changes that occur
+  on CVS repository.
+
+* New filter readers: ClassConstants, ExpandProperties, HeadFilter,
+  LineContains, LineContainsRegExp, PrefixLines, ReplaceTokens,
+  StripJavaComments, StripLineBreaks, StripLineComments, TabsToSpaces,
+  TailFilter.
+
+* <copy>, <loadfile>, <loadproperties>, <move> support FilterChains
+  of FilterReaders.
+
+* New task <loadproperties> to load contents of file as Ant properties,
+  with nested <filterchain> elements.
+
+* New task <loadfile> to load a whole file into a property.
+
+* New task <echoproperties> to list your current properties to the screen
+  or a file.
+
+* New tasks <bzip2> and <bunzip2> to pack and unpack files using the
+  BZip2 alogrithm.
+
+* New tasks <replaceregexp>, <checksum>, <translate>, <waitfor>,
+  <manifest>, <vsscp>, <vssadd>, <vsscreate>, <splash>, <basename>, <dirname>,
+  <concat>, <sourceoffsite>, <jarlib-available>, <jarlib-display>,
+  <jarlib-manifest>, <jarlib-resolve>.
+
+* A new combined <mail> task, which replaces the old <mail> and
+  <mimemail> tasks, has been added.  The <mimemail> task, and
+  old SendEmail and MimeMail classes have been deprecated.
+
+* Mail task allows specification of port number.
+
+* Users can control what <zip> and <jar> must do when duplicate files
+  are found.  A new element <zipgroupfileset> allows for multiple zip
+  files to be merged into the archive.  In addition, <jar> also has
+  another new attribute: filesetmanifest.  The existing manifest
+  attribute of <jar> now also accepts the name of a jar added through
+  a fileset.
+
+* gzip now checks that the zipfile is older than the source file
+  before rebuilding the zipfile.
+
+* TarFileset takes in three new attributes - fullpath, prefix
+  and preserveLeadingSlashes.
+
+* <move> attempts to rename the directory, if everything inside it is
+  included, before performing file-by-file moves.  This attempt will
+  be done only if filtering is off and if mappers are not used.  This
+  is a performance improvement and there is no change otherwise in
+  the funtionality of this task.
+
+* Exec task has extra attribute "resultproperty" to get the return code
+  into a property.
+
+* Exec task prints a message when a timed-out process is killed.
+
+* Added optional attributes - name, arch and version to the <os> task.
+
+* Unjar, Untar, Unwar and Unzip now support patternsets to
+  select files from an archive for extraction.  Filesets may be
+  used to select archived files for unarchival.
+
+* Javac task allows debug levels to be specified.  Debug levels
+  will have an effect only when the modern compiler or the
+  classic compiler (version 1.2 and higher) is used and debugging
+  is enabled.
+
+* Added support for specifying CVS_RSH in the <cvs/> task
+
+* The attributes zipfile, jarfile, warfile and earfile (from the Zip,
+  Jar, War and Ear tasks) have been deprecated and superseded by a
+  new attribute "destfile".
+
+* Added new conditions <isset>, <checksum>, <http>, <socket>, <contains>,
+  <filesmatch>.
+
+* <taskdef> and <typedef> will now emit a warning if a task/type of
+  the given name already exists.
+
+* A new revision of VAJ tasks: The most important new feature
+  is the ability to execute VAJ tasks from the command line by
+  exploiting the Remote Tool Access feature of VAJ.
+
+* Improved support for Novell NetWare.
+
+* Added an optional encoding attribute to <fixcrlf>.
+
+* <apply> has a new attribute relative that allows users to pass the
+  filenames as relative instead of absolute paths on the command line.
+
+* References can now be copied into the child build by <ant> and
+  <antcall> using nested <reference> elements or the new inheritRefs
+  attribute.
+
+* <fail> now supports builds to fail based on conditions via if and
+  unless attributes.
+
+* Ant now comes with two new BuildLogger implementations - one that
+  can send emails containing a log of the build process (MailLogger),
+  and one that colorizes the output based on message levels, using
+  ANSI color code escape sequences (AnsiColorLogger).
+
+* A "package" mapper type has been added to allow package directory
+  names replaced with the dotted form.
+
+* You can now specify environment variables in the <java> and <junit> tasks
+  if the fork attribute has been set to true.
+
+* -propertyfile command-line option has been added to load an entire
+  property file just as -D properties are declared (as user properties).
+  -D properties take precedence over -propertyfile specified ones.
+
+* You can now set an ANT_ARGS environment variable to hold arguments you
+  always want passed to the 'ant' command -- for example, if you always
+  want to use a different logger or the -find flag.
+
+* <tstamp> now supports a new "prefix" attribute to prefix properties set.
+
+* You can now specify the -sourcepath for <javac> explicitly.
+
+* <javac> now supports a new "listfiles" attribute to list the source
+  files it's handing off to the compiler.
+
+* The compiler implementation for <javac> can now be chosen on a task by
+  task basis.  The new "compiler" attribute of <javac> can be used to override
+  the value of the build.compiler property, if set.
+
+* <javac> has a new nested element, <compilerarg>, which allows you
+  to specify additional args for the specific compiler you're using.
+
+* <javac>'s "source" attribute is now enabled for jikes as well.
+
+* <propertyfile>'s <entry> now has a 'unit' attribute to specify the
+  increment/decrement unit on date operations.
+
+* <property> now supports a 'prefix' attribute when loading from a file
+  or resource.
+
+* In Ant 1.4, a feature has been added to the <junit> task that would
+  add ant.jar, optional.jar and junit.jar implicitly to the classpath -
+  this feature can now be disabled by setting the new includeantruntime
+  attribute to false.
+
+* <style> behaves differently from any other directory-based task, as it
+  processes all files that it finds in included directories in
+  addition to the files matched by your patterns.  There is now a new
+  attribute, 'scanincludeddirectories', to suppress this behavior.
+
+* <javadoc> now supports a <tag> nested element to provide the -tag option
+  to the standard Java 1.4 doclet. The element is ignored when not running
+  on Java 1.4.
+
+* <ftp> can now chmod files on a remote server that supports
+  "site chmod", as well as set the umask before transferring files, if
+  the server supports "site umask".
+
+* New <serverdeploy> "optional" task.
+
+* <patternset> now supports nested patternsets.
+
+* Perforce tasks now support a "failonerror" attribute (defaults to "true").
+
+* Open Source application server JOnAS support:
+    EJB hot deploy and deploy with <serverdeploy> and <ejbjar>
+
+* Added new DirSet (<dirset>) datatype.
+
+* <path> now supports nested <dirset> and <filelist> elements.
+
+* <pathconvert> now supports nested <dirset> and <filelist> elements.
+
+* <pathconvert>'s "dirsep" and "pathsep" attributes now accept
+  multi-character values.
+
+* <copy> task now has a 'failonerror' attribute to allow keep-going
+  behaviour when the file to be copied is not found (defaults to "true").
+
+* <uptodate> now has a 'srcfile' attribute to allow specifying a
+  full-path filename.
+
+* <exec>, <sql> and <java> now support append attributes to allow
+  appending the output to an existing file.
+
+* <java> now supports a timeout attribute analog to <exec> - it is
+  highly recommended to only use it together with fork="true".
+
+* <javadoc> now supports a source attribute to enable javadoc to
+  handle assertions present in JDK 1.4 source code.
+
+* <replace> supports a new replacefilterfile attribute that
+  automatically turns all properties of a given file into
+  replacefilters.
+
+* An alias of <xslt> has been added to refer to the <style> task.
+
+* The compiler implementation for <rmic> can now be chosen on a task by
+  task basis.  The new "compiler" attribute of <rmic> can be used to override
+  the value of the build.rmic property, if set.
+
+* <rmic> has a new nested element, <compilerarg>, which allows you
+  to specify additional args for the specific compiler you're using.
+
+* org.apache.tools.ant.XmlLogger now is a BuildLogger, rather than just
+  a BuildListener. It can operate in either mode successfully.
+
+* <junit> has a new attribute "showoutput".  If set to true, output
+  generated by tests will be sent to Ant's logging system as well as
+  to the formatters (instead of sending it to the formatters
+  exclusively).
+
+* Ant has now a pluggable way to prompt users for input, which is used
+  by the new <input> task.  IDE integrators can provide an
+  implementation of the InputHandler interface to decouple Ant's input
+  from the console.  An implementation that gets its input from a file
+  for unattended builds is part of Ant's distribution.
+
+  For more details see docs/manual/inputhandler.html.
+
+* <patch> has a new attribute that selects the directory in which to
+  run the command.
+
+* <javadoc> now supports two new nested elements, <fileset> and <packageset>.
+
+
+Changes from Ant 1.4 to Ant 1.4.1
+===========================================
+
+Fixed bugs:
+-----------
+
+* <ant>'s antfile attribute will now also be considered an absolute path on
+  Windows systems, if it starts with a \ and no drive specifier.
+
+* The fullpath attribute of <zipfileset> has been ignored if you used
+  the src attribute at the same time.
+
+* The manifest file is now always placed as the second entry (after /META-INF)
+  in generated jars. This allows the manifest to be read by JarInputStreams
+
+* Fixed bug in depend task which would fail with a NullPointerException if no
+  dependency cache was specified.
+
+* sql task now handles REM statements correctly so that lines starying with rem
+  but which are not comments are actually processed.
+
+* XMLLogger now uses the task's name rather than the classname
+
+* <mapper>s will now work as expected if the to pattern expands to an
+  absolute pathname.
+
+* <javac> didn't ignore memory settings in non-fork mode
+
+* <cab> didn't split the options attribute into several command line
+  arguments correctly.
+
+Other changes:
+--------------
+
+* New source attribute for <javac> to enable assertion in JDK 1.4
+
+* XmlLogger and <antstructure> now add an encoding declaration to the
+  XML files they generate.
+
+* <fileset> has a new attribute "casesensitive" to make it match
+  filenames in a case insensitive way (if you set it to false) - by
+  default filesets remain case sensitive.
+
+Changes from Ant 1.3 to Ant 1.4
+===========================================
+
+Changes that could break older environments:
+--------------------------------------------
+* JUnitReport now uses the xalan redirect extension for multi-output.
+  With Xalan 1.2.2 it forces the use of bsf.jar in the classpath.
+  (Available in the xalan distribution). It is recommended to switch
+  to Xalan 2.x that do not need it.
+
+* Zip.setWhenempty() has changed its signature.
+
+* <rmic> is now implemented using a factory. This makes extending
+  rmic to use a new compiler a lot easier but may break custom
+  versions of this task that rely on the old implementation.
+
+* several Zip methods have changed their signature as we now use a Zip
+  package of our own that handles Unix permissions for directories.
+  Furthermore <zip> will now use the platform's default character
+  encoding for filenames - this is consistent with the command line
+  ZIP tools, but causes problems if you try to open them from within
+  Java and your filenames contain non US-ASCII characters. Use the new
+  encoding attribute of the task and set it to UTF8 to get the old
+  behavior.
+
+* The <pvcs> task has been moved to a package of its own.
+
+* JUnitResultFormater has two additional methods that must be
+  implemented by custom formatters.
+
+* Ant will no longer use the canonical version of a path internally -
+  this may yield different results on filesystems that support
+  symbolic links.
+
+* The output generated by the xml formatter for <junit> has changed
+  again, it doesn't format the numeric value in the time attribute anymore.
+
+* Pattern matching rules have changes slightly, the pattern foo*
+  doesn't match files contained in a directory named foo - use foo/*
+  instead.
+
+* <fixcrlf> will not remove trailing whitespace at the end of lines anymore.
+
+* The Classloader usage has been changed for the taskdef, property, available
+  and sql tasks so that it delegates to the parent classloader. This may cause
+  ClassNotFoundExceptions to be thrown if a system class attempts to load a
+  class in the taskdef's classpath (typically factory objects).
+
+* Ant now allows multithreading of tasks and the containment of tasks within
+  other tasks. This can break customer listeners which do not expect messages
+  from a task before the previous task has finished.
+
+* Ant now installs its own ouput stream into System.out to route output to the
+  task currently executing on the current thread. This also means that all
+  output is now routed as Ant message events. Customer listeners and loggers
+  should not call System.out at any time. This has always been true but such
+  usage now will cause problems due to possible recursion.
+
+* Invalid manifest files will now cause build failures in the <jar> task.
+
+* Ant Introspection now looks for methods with method names starting with
+  addConfigured. When called these methods are passed an argument after it has
+  been configured from the build file. Custom tasks supporting nested elements
+  starting with the name configured will no longer function.
+
+* The environment variable JAVACMD that can be used to specify the
+  java executable to Ant's wrapper scripts must not contain additional
+  command line parameters any longer - please use the environment
+  variable ANT_OPTS for such parameters now.
+
+* Ant's wrapper scripts now quote the CLASSPATH environment variable, thus
+  supporting classpaths which refer to directories containing spaces. This means
+  that the CLASSPATH environment variable cannot have quotes. Any quotes should
+  be removed. This will not affect the operation of the CLASSPATH environment
+  variable in other contexts.
+
+* A delete task like
+  <delete includeEmptyFilesets="true">
+    <fileset dir="somedir" />
+  </delete>
+  will now remove "somedir" as well, unless there are still files left
+  in it (matched by the default excludes).
+
+* The copy task will now fail if the file to be copied is not found.
+
+* Ant properties defined in properties files now behave the same way as
+  properties defined in the build file. In particular the $ character needs
+  to be escaped in property values by doubling it to $$. So, to define a
+  property with the value $hello, you need to define it in a properties file
+  as
+    test.prop=$$hello
+  This was not the case in Ant 1.3
+
+Other changes:
+--------------
+
+* New tasks: ear, p4counter, record, cvspass, vsscheckin, vsscheckout,
+  typedef, sleep, mimemail, set of tasks for Continuus/Synergy, dependset,
+  condition, maudit, mmetrics, jpcoverage, jpcovreport, jpcovmerge
+
+* Ant now uses JAXP 1.1
+
+* rmic now supports Kaffe's and Weblogic's version of rmic.
+
+* new magic property build.rmic to chose the rmic implementation
+
+* <tar> will now add empty directories as well
+
+* you can now specify a description for <p4change>
+
+* <touch> can now work on <fileset>s
+
+* <uptodate> now supports a value attribute
+
+* <fail> supports nested text
+
+* <fixcrlf> won't override files that are already in the correct
+   format.
+
+* <sql> now supports REM comments as well as // and --
+
+* <jar> now has a nested <metainf> element following the same idea as
+  <war>'s <webinf>.
+
+* <pvcs> can now handle multiple projects.
+
+* <available> now has a "type" attribute you can use in conjunction
+  with the "file" attribute to specify whether the "file" you're
+  looking for is a file or a directory.
+
+* New <junit> formatter named "brief"
+
+* <ejbjar> changes
+  * Add support for Borland Application Server to the <ejbjar> task using
+    a <borland> nested element.
+  * Add support for iPlanet Application Server to the <ejbjar> task. Also
+    includes some iPlanet utility tasks
+  * Add support for JBoss Application Server to the <ejbjar> task.
+  * Add a naming attribute to control the naming scheme that
+    ejbjar uses to name the generated EJB jars.
+  * Weblogic element now sets the compiler class for EJB 2.0 beans
+  * <dtd> elements can be specified at the <ejbjar> level for building generic
+    beans
+  * <dtd> elements can now be URLs
+  * Allow the manifest to be specified for the generated jars
+  * The weblogic element now supprts an attribte noEJBC to skip the processing
+    of the jar by ejbc. The ejbc step will then occur at deployment
+  * weblogic will tell ejbc to use Jikes compiler if build.compiler is set to
+    jikes. It can be restored to the default, javac, operation if desired.
+
+* Allow the <sql> Delimiter to be set in the so that Oracle stored procs may be
+  entered
+
+* <execon> and <apply> can now optionally skip empty filesets.
+
+* <javadoc> has a new useexternalfile attribute that makes it use a
+  temporary file for sourcefile and package names - helps to defeat
+  command line length limitations.
+
+* Data types like <path> can now be defined inside of <target>s
+
+* you can now specify a classpath for <style> - the XSLZ processor
+  will be loaded from this path
+
+* added a force attribute to <style> to support dependencies that the
+  task cannot determine itself (dependency on parameters, not file
+  modification times for example)
+
+* added vmlauncher attribute to exec tasks. This defaults to true. If
+  it is set to false, the VM's ability to launch commands in bypassed
+  and the OS shell, either directly or through the auxillary antRun
+  scripts is used.
+
+* regexp mapper now supports the java.util.regex package of JDK 1.4.
+
+* New filesonly attribute for <zip> and friends to suppress directory
+  entries.
+
+* New update attribute for <zip> and friends - update an existing
+  archive instead of creating a new one.
+
+* <apply> and <execon> have been merged into a single task.
+
+* added vssver.scc to the default excludes
+
+* <available> has a new filepath attribute/nested element that allows
+  you top search for a file in a given path.
+
+* <junit> can now optionally set a property on test failure.
+
+* <taskdef> can now define several tasks at once, reading the
+  name/classname pairs from a property file or resource.
+
+* <unzip/unjar/unwar> and <untar> now have an overwrite attribute that
+  defaults to true.  If set to false, files that are newer than the
+  files in the archive will not be replaced.
+
+* <patternset> and <fileset> now support nested <in/excludesfile>
+  elements - using these you can have more than one in/excludes file
+  per <patternset>.
+
+* Three new supported compilers for javac: kjc for kopi, gcj for the
+  gcc frontend and sj for Symantec's compiler.
+  In addition extJavac or the new fork attribute can be
+  used to run the JDK's javac in a JVM separate from Ant.
+
+* <fixrlf> can now with CR only line-ends and can use an arbitraty
+  between 2 and 80.
+
+* The .NET tasks have been adapted to the beta2 release of the framework.
+
+* <move> will now try to rename() files before copying them byte by
+  byte - only if filtering is of, of course.
+
+* <ant> and <antcall> tasks now support a new attribute inheritAll. When set to
+  false, only user properties are passed through to the target Ant instance.
+  This includes properties set on the command line and properties explicitly
+  passed
+
+* <javadoc> now skips off line links if the package list cannot be found.
+
+* <wlrun> now allows the security policy file to exist outside the weblogic
+  directory.
+
+* <java> task will set the Thread contextClassLoader under JDKs 1.2+ to the
+  classloader for the class being executed.
+
+* Introduce the concept of a TaskContainer - a task or element which can contain
+  Ant Tasks.
+
+* Add new tasks implementing the TaskContainer interface <parallel> and
+  <sequential> which allow parallel execution of tasks to be specified.
+
+* <depend> task will now take into account dependencies on jar files and class
+  files from a given classpath.
+
+* <jar> manifest entries may now be specified in the build file either
+  completely or to be merged with a manifest file.
+
+* <tstamp> task custom formats now support locales.
+
+* Added a listner which will forward events to Log4J. The log4j configuration
+  file should be in the directory from which Ant is run or passed as a system
+  property using a JVM argument.
+
+* Introduced the concept of <filtersets> to allow for more control in which
+  filters get applied in a <copy> or <move> operation.
+
+* Added nowarn attribute to javac and deprecated the Jikes-magic property
+  build.compiler.warnings.
+
+* The <depend> task cache format has changed and all dependency information is
+  now stored in a single file.
+
+Fixed bugs:
+-----------
+
+* Testcases have been made independent of current working directory.
+
+* Input ZIP-Files will be closed when using a <zipfileset>.
+
+* p4 tasks now don't fail if user, port or client have been omitted
+  (and this is acceptable for the context of the command).
+
+* <javah>'s outputfile attribute will be resolved as relative to the
+  projects basedir.
+
+* <antstructure> should create a valid DTD for propertyfile.operation.entry
+  and omit tasks it fails to load.
+
+* won't try to pass a -bootclasspath flag to javac 1.1 anymore
+
+* <style>'s style attribute no handles absolute paths correctly.
+
+* <delete includeemptydirs="true"> now deletes more than just the leaf
+  directories.
+
+* You can now specify a <fileset> for a directory that doesn't exist at
+  declaration time but will created before the fileset gets used for the
+  first time.
+
+* If the quiet attribute has been set, <delete> will handle <fileset>s
+  with non-existing directories gracefully.
+
+* Output written by testcases will now be captured by the <junit> task
+  and passed to the formatters.
+
+* Quote the -group parameter to Javadoc as per the specification
+
+* Initialise classes when loaded through the AntClassLoader - that is, run
+  static initializers
+
+* Implement getResource() and getResources() in AntClassLoader
+
+* Create the <ejbjar> weblogic command line as a set of arguments rather than
+  as a single line. Avoids problems with paths which contain spaces.
+
+* <ejbjar> now fails when the weblogic ejbc compiler reports an error.
+
+* Make the AntClassLoader load resources in the same order as it currently
+  loads classes.
+
+* Handle classpaths with spaces
+
+* Make sure XSLT processors close their output files in <style>.
+
+* perform proper uptodate check in <rmic> when compiling for IIOP.
+
+* <jjtree>'s uptodate test works even if outputdirectory is not the
+  parent dir of target
+
+* <copy> will remove target file (if it exists) before writing to it -
+  this avoids problems with links on filesystems that support them.
+
+* <ftp> now properly recurses remote directories.
+
+* <ftp> closes remote connection when it's done.
+
+* <junit> tries to include all necessary classes for the task itself
+  to the classpath when running in fork mode - doesn't work for JDK 1.1
+
+* <apply> and <execon> do now execute the command only once, if you
+  specify the parallel attribute - instead of once per fileset.
+
+* directory based tasks and fileset could miss some included files in
+  directories that have been excluded
+
+* <fixcrlf> failed for large files.
+
+* <move> removed files you tried to move to themselves.
+
+* <sql> task will not trty to print the result set unless the query succeeded.
+
+* Ant classloader will now ignore paths which are invalid relative to the
+  project base
+
+* <ejbjar> weblogic elements check for jar file changes has been fixed.
+  Previously some changes would not be included.
+
+* properties loaded from properties files are now resolved internally. This
+  removes the spurious warnings about usage of properties which have not been
+  set.
+
+* <jar> task and friends now process the JAR manifest to ensure it is valid.
+
+* The task finished event now includes any exception thrown by the task.
+
+* <java> task now supports a jvmVersion attribute so that if another JVM is
+  being used, Ant can determine which options to use for features such as the
+  VM memory limits
+
+
+Changes from Ant 1.2 to Ant 1.3
+===========================================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* Ant doesn't search for the buildfile anymore, unless you use the new
+  -find argument.
+
+* <perforce> has been replaced by a number of new tasks.
+
+* <javac> is now implemented using a factory. This makes extending
+  javac to use a new compiler a lot easier but may break custom
+  versions of this task that rely on the old implementation.
+
+* The output generated by the xml formatter for <junit> has changed a
+  little, it doesn't append " sec" in the time attribute anymore.
+
+Other changes:
+--------------
+
+* A GUI Frontend: Antidote. This is currently in development. At this
+  time, this is not part of the Ant release, although the source is
+  included if you are interested.
+
+* New tasks: stylebook, propertyfile, depend, antlr, telnet, csc,
+  ilasm, apply, javah, several clearcase tasks, junitreport, sound
+
+* Added output attribute to <java>.
+
+* Added nested zipfileset element to <zip>
+
+* Changed <sql> so that printing is at the task level rather than
+  the statement level.
+
+* javadoc task will pass -d flag to any doclet if the destDir attribute is
+  given. If the doclet does not accept the -d flag then omit the destdir
+  attribute.
+
+* <cab> can work on non-Windows platforms with the help of libcabinet.
+  See http://trill.cis.fordham.edu/~barbacha/cabinet_library/.
+
+* <ftp> now supports passive mode.
+
+* New <mapper> data type that can be used to get influence on the
+  target files for some tasks like <copy> or enable new types of tasks
+  like <apply>.
+
+* <execon> provides more control over the command line now, the names
+  of the source files are no longer required to be at the end of the
+  command.
+
+* Style tasks will now support TraX compliant XSL processors if one is present
+  in your classpath.
+
+* Added a failonerror to the javac task. If set to false, the build will
+  continue even if there are compilation errors.
+
+* Added nested format elements to the tstamp task allowing additional time
+  formats to be defined for arbitrary properties.
+
+* Added classpath attribute and nested classpath element to <property>
+  to make the resource attribute more powerful.
+
+* ${} property expansion will now be performed on the patterns read
+  from files specified as includesfile or excludesfile attributes.
+
+* The <tar> and <untar> tasks now support GNU format for handling paths
+  which are greater than 100 characters in length. In addition the <tar>
+  task now supports nested filesets through which the file permissions
+  may be controlled.
+
+* wlrun, wlstop and ejbjar now support Weblogic 6.0
+
+* The MPasre task has been updated to work with MParse 2.0
+
+* The documentation has been significantly updated.
+
+
+Fixed bugs:
+-----------
+
+* <signjar> no longer uses deprecated methods.
+
+* javadoc's failonerror attribute works again
+
+* javadoc's additionalparam attribute will now be split into separate
+  parameters (on spaces) to allow for more than one parameter.
+
+* Changed <sql> task so that printing result sets works on Oracle
+
+* Changes to ddcreator and ejbc helper to respect the descriptor hierarchy
+  keppgenerated in ejbc can now be turned off
+
+* ejbjar now correctly ignores <ejb-ref> elements in the deployment descriptor.
+  CMP files are included by parsing the weblogic deployment descriptor rather
+  than relying on the naming convention used in ant 1.2
+
+* ejbjar includes super classes and super interfaces into the generated ejb
+  jar files. The <support> nested element allows support classes to be
+  included in the EJB jar. The toplink element should now correctly locate
+  the toplink descriptor.
+
+* <vssget> now correctly deals with spaces in arguments
+
+* <jar> fails early if a given manifest file doesn't exist
+
+* <rmic> doesn't search for the _Skel file anymore when stubversion is
+  set to 1.2.
+
+* <rmic> uses the the same classpath to verify a class can be rmic'd
+  as it passes to the compiler.
+
+* org.apache.tools.mail.MailMessage (and therefore <mail>) can now
+  handle SMTP servers sending multi line responses.
+
+* nested <classpath> elements of <taskdef> now work for <taskdef>s not
+  nested into <target> as well.
+
+* <property> and <available> will search for the resource "foo" instead
+  of "/org/apache/tools/ant/taskdefs/foo" when given a relative resource
+  name foo.
+
+* Handle build files in directories whose name contained a "#" character
+
+* <junit> can now log to files whose name contains a comma as well.
+
+* The AntClassLoader now refers to the loader which loaded it, any
+  requests it does not handle itself. Previously these went to the
+  primordial loader.
+
+Changes from Ant 1.1 to Ant 1.2
+===============================
+
+Changes that could break older environments:
+--------------------------------------------
+
+* Semantics of <property> has changed again in the hope to be more
+  intuitive. ${} expansion now happens at runtime and <property> tags
+  living inside of targets only take effect if they are visited at
+  runtime.
+
+  As a side effect of this change, task's attributes get set at runtime
+  not at parser time as well, which might change the results of
+  <script>s or other custom tasks that reference other tasks by their id
+  attribute.
+
+* copying of support files in <javac> has been removed - as well as
+  the filtering attribute.
+
+* the <expand> and <keysubst> tasks have been removed.
+
+* the ignore and items attributes of directory based tasks have been removed.
+
+* the command line switches _not_ starting with - have been removed.
+
+* Path and EnumeratedAttribute have been moved from
+  org.apache.tools.ant to org.apache.tools.ant.types.
+
+* the class attributes of <available>, <java>, <rmic> and <taskdef>
+  have been removed.
+
+* the src attribute of <chmod> has been removed.
+
+* <patch> and <javadoc> have lost some of their attributes.
+
+* <java> and <cvs> have lost some undocumented attributes.
+
+* the Unix antRun script would search for command.sh in the directory
+  it changed to and invoke this instead of command if present. This
+  behavior has been dropped.
+
+* <ejbjar> task syntax has been changed significantly
+
+* <exec> is no longer implemented by org.apache.tool.ant.taskdefs.Exec.
+  Custom tasks that rely on Project.createTask("exec") to return an
+  instance of this class are going to fail.
+
+* nested <include> and <exclude> elements expect the value of their
+  name attribute to be a single pattern, they don't accept multiple
+  patterns anymore. Split them into multiple elements of the same type.
+
+* <delete dir="somedir" /> will now delete the directory itself as
+  well as all included files. If you just want to clean out the
+  directory and keep the empty one, use a nested fileset.
+
+Other changes:
+--------------
+
+* New tasks: antstructure, cab, execon, fail, ftp, genkey, jlink,
+  junit, sql, javacc, jjtree, starteam, war, unwar, uptodate,
+  native2ascii, copy, move, mparse.
+
+* copydir, copyfile, deltree and rename are now deprecated. They
+  should be replaced with the new copy, delete and move tasks.
+
+* <java> uses a ClassLoader of its own in no-fork mode if a classpath is
+  specified.
+
+* <style> will create the necessary target directories and reprocess
+  all files if the stylesheet changes.
+
+* New data types fileset and patternset - expected to get a broader use.
+  They, as well as PATH like structures, can now be defined on a global
+  level and later be referenced by their id attribute.
+
+* You can specify environment variables to <exec>.
+
+* <get> can check whether a remote file is actually newer than a local
+  copy before it starts a download (HTTP only).
+
+* Added a -logger option to allow the class which performs logging to be
+  specified on the command line.
+
+* Added a -emacs option to tell the logger to leave out taskname adornments
+  on log output.
+
+* <chmod> works on all files in parallel and supports multiple filesets.
+
+* <replace> can now use tokens and/or values that cross line boundaries.
+
+* build.compiler supports now jvc as well.
+
+* project specific help can now be obtained with the -projecthelp option.
+
+* Added a -debug option to make -verbose less verbose (and more useful)
+
+* Ant will now search for a file named build.xml in the parent directory
+  and above (towards the root of the filesystem) if you didn't specify
+  -buildfile and there is no build.xml in the current directory.
+
+* <echo> can now write to a file and accepts nested text.
+
+Fixed bugs:
+-----------
+
+* <chmod> didn't work when used as a directory based task.
+
+* Path, Available, Property didn't resolve relative filenames with
+  respect to the Project's basedir.
+
+* Project didn't interpret the basedir attribute correctly in all
+  cases.
+
+* Nested <src> in <javac> caused NullPointerException.
+
+* Corrupt Zip- and Jar-files ar now deleted if the task fails.
+
+* many more fixes we've forgotten to document here ...
+
+* The packagelistloc attribute of <javadoc>'s <link> child will be
+  resolved as a file (i.e. it is either absolute or relative to
+  basedir).
diff --git a/trunk/ant.properties.sample b/trunk/ant.properties.sample
new file mode 100644
index 0000000..1930ca7
--- /dev/null
+++ b/trunk/ant.properties.sample
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This file is a sample .ant.properties file used for building ant.
+# Modify it for your own needs and copy it to .ant.properties 
+#
+# <-- starts a comment
+
+# If you wanted to use the better than average jikes compiler uncomment next line
+# build.compiler=jikes
+# build.compiler.warnings=true
+# build.compiler.pedantic=true
+# build.compiler.depend=true
+
+# If you want to use non-standard jars then edit following lines
+# jar.junit=/path/to/my/junit.jar
+
diff --git a/trunk/bootstrap.bat b/trunk/bootstrap.bat
new file mode 100755
index 0000000..218554c
--- /dev/null
+++ b/trunk/bootstrap.bat
@@ -0,0 +1,137 @@
+@echo off
+
+REM You will need to specify JAVA_HOME if compiling with 1.2 or later.
+
+REM  Licensed to the Apache Software Foundation (ASF) under one or more
+REM  contributor license agreements.  See the NOTICE file distributed with
+REM  this work for additional information regarding copyright ownership.
+REM  The ASF licenses this file to You under the Apache License, Version 2.0
+REM  (the "License"); you may not use this file except in compliance with
+REM  the License.  You may obtain a copy of the License at
+REM
+REM      http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM  Unless required by applicable law or agreed to in writing, software
+REM  distributed under the License is distributed on an "AS IS" BASIS,
+REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM  See the License for the specific language governing permissions and
+REM  limitations under the License.
+
+set OLDJAVA=%JAVA%
+set OLDJAVAC=%JAVAC%
+set BOOTOLDCLASSPATH=%CLASSPATH%
+set OLDANTHOME=%ANT_HOME%
+
+set ANT_HOME=.
+
+if "" == "%JAVA%"  if "" == "%JAVA_HOME%" set JAVA=java
+if "" == "%JAVA%"                         set JAVA=%JAVA_HOME%\bin\java
+
+if "" == "%JAVAC%" if "" == "%JAVA_HOME%" set JAVAC=javac
+if "" == "%JAVAC%"                        set JAVAC=%JAVA_HOME%\bin\javac
+
+echo.
+echo ... Bootstrapping Ant Distribution
+
+if     "%OS%" == "Windows_NT" if exist bootstrap\nul rmdir/s/q bootstrap
+if not "%OS%" == "Windows_NT" if exist bootstrap\nul deltree/y bootstrap
+if     "%OS%" == "Windows_NT" if exist build\nul rmdir/s/q build
+if not "%OS%" == "Windows_NT" if exist build\nul deltree/y build
+
+SET LOCALCLASSPATH=lib\xercesImpl.jar;lib\xml-apis.jar
+for %%i in (lib\optional\*.jar) do call src\script\lcp.bat %%i
+if exist "%JAVA_HOME%\lib\tools.jar" call src\script\lcp.bat %JAVA_HOME%\lib\tools.jar
+if exist "%JAVA_HOME%\lib\classes.zip" call src\script\lcp.bat %JAVA_HOME%\lib\classes.zip
+
+set TOOLS=src\main\org\apache\tools
+set CLASSDIR=build\classes
+
+SET CLASSPATH=%LOCALCLASSPATH%;%CLASSDIR%;src\main;%CLASSPATH%
+
+echo JAVA_HOME=%JAVA_HOME%
+echo JAVA=%JAVA%
+echo JAVAC=%JAVAC%
+echo CLASSPATH=%CLASSPATH%
+
+if     "%OS%" == "Windows_NT" if exist %CLASSDIR%\nul rmdir/s/q %CLASSDIR%
+if not "%OS%" == "Windows_NT" if exist %CLASSDIR%\nul deltree/y %CLASSDIR%
+
+if not exist build\nul mkdir build
+if not exist build\classes\nul mkdir build\classes
+
+echo.
+echo ... Compiling Ant Classes
+
+"%JAVAC%" %BOOTJAVAC_OPTS% -d %CLASSDIR% %TOOLS%\bzip2\*.java %TOOLS%\tar\*.java %TOOLS%\zip\*.java %TOOLS%\ant\*.java %TOOLS%\ant\types\*.java %TOOLS%\ant\taskdefs\*.java %TOOLS%\ant\util\regexp\RegexpMatcher.java %TOOLS%\ant\util\regexp\RegexpMatcherFactory.java %TOOLS%\ant\taskdefs\condition\*.java %TOOLS%\ant\taskdefs\compilers\*.java %TOOLS%\ant\types\resources\*.java %TOOLS%\ant\property\*.java
+
+if ERRORLEVEL 1 goto mainend
+
+echo.
+echo ... Copying Required Files
+
+copy %TOOLS%\ant\taskdefs\*.properties %CLASSDIR%\org\apache\tools\ant\taskdefs
+copy %TOOLS%\ant\types\*.properties %CLASSDIR%\org\apache\tools\ant\types
+
+echo.
+echo ... Building Ant Distribution
+
+if not "%OS%"=="Windows_NT" goto win9xStart
+:winNTStart
+@setlocal
+
+REM parse command line arguments
+rem Need to check if we are using the 4NT shell...
+if "%eval[2+2]" == "4" goto setup4NT
+
+rem On NT/2K grab all arguments at once
+set ANT_CMD_LINE_ARGS=%*
+goto doneStart
+
+:setup4NT
+set ANT_CMD_LINE_ARGS=%$
+goto doneStart
+
+:win9xStart
+rem Slurp the command line arguments.  This loop allows for an unlimited number of
+rem agruments (up to the command line limit, anyway).
+
+set ANT_CMD_LINE_ARGS=
+
+:setupArgs
+if %1a==a goto doneStart
+set ANT_CMD_LINE_ARGS=%ANT_CMD_LINE_ARGS% %1
+shift
+goto setupArgs
+
+:doneStart
+rem This label provides a place for the argument list loop to break out
+rem and for NT handling to skip to.
+
+"%JAVA%" %ANT_OPTS% org.apache.tools.ant.Main -emacs %ANT_CMD_LINE_ARGS% bootstrap
+
+set ANT_CMD_LINE_ARGS=
+if not "%OS%"=="Windows_NT" goto mainEnd
+:winNTend
+@endlocal
+
+:mainEnd
+
+echo.
+echo ... Cleaning Up Build Directories
+
+if     "%OS%" == "Windows_NT" if exist %CLASSDIR%\nul rmdir/s/q %CLASSDIR%
+if not "%OS%" == "Windows_NT" if exist %CLASSDIR%\nul deltree/y %CLASSDIR%
+
+echo.
+echo ... Done Bootstrapping Ant Distribution
+
+set JAVA=%OLDJAVA%
+set JAVAC=%OLDJAVAC%
+set CLASSPATH=%BOOTOLDCLASSPATH%
+set ANT_HOME=%OLDANTHOME%
+set OLDJAVA=
+set OLDJAVAC=
+set BOOTOLDCLASSPATH=
+set LOCALCLASSPATH=
+set OLDANTHOME=
+set TOOLS=
diff --git a/trunk/bootstrap.sh b/trunk/bootstrap.sh
new file mode 100755
index 0000000..22e550d
--- /dev/null
+++ b/trunk/bootstrap.sh
@@ -0,0 +1,169 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  Darwin*) darwin=true
+           if [ -z "$JAVA_HOME" ] ; then
+             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
+           fi
+           ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# You will need to specify JAVA_HOME if compiling with 1.2 or later.
+
+if [ -n "$JAVA_HOME" ] ; then
+  if [ -f "$JAVA_HOME/lib/tools.jar" ] ; then
+    CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/tools.jar
+  fi
+
+  if [ -f "$JAVA_HOME/lib/classes.zip" ] ; then
+    CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/classes.zip
+  fi
+else
+  echo "Warning: JAVA_HOME environment variable not set."
+  echo "  If build fails because sun.* classes could not be found"
+  echo "  you will need to set the JAVA_HOME environment variable"
+  echo "  to the installation directory of java."
+fi
+
+# IBM's JDK on AIX uses strange locations for the executables:
+# JAVA_HOME/jre/sh for java and rmid
+# JAVA_HOME/sh for javac and rmic
+if [ -z "$JAVAC" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/sh/javac" ] ; then
+      JAVAC=${JAVA_HOME}/sh/javac;
+    else
+      JAVAC=${JAVA_HOME}/bin/javac;
+    fi
+  else
+    JAVAC=javac
+  fi
+fi
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+      JAVACMD=$JAVA_HOME/bin/java
+    fi
+  else
+    JAVACMD=java
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly."
+  echo "  We cannot execute $JAVACMD"
+  exit
+fi
+
+ANT_HOME=.
+export ANT_HOME
+
+echo ... Bootstrapping Ant Distribution
+
+if [ -d "bootstrap" ] ; then
+  rm -r bootstrap
+fi
+
+if [ -d "build" ] ; then
+  rm -r build
+fi
+
+CLASSPATH=lib/xercesImpl.jar:lib/xml-apis.jar:${CLASSPATH}
+
+DIRLIBS=lib/optional/*.jar
+for i in ${DIRLIBS}
+do
+    # if the directory is empty, then it will return the input string
+    # this is stupid, so case for it
+    if [ "$i" != "${DIRLIBS}" ] ; then
+        CLASSPATH=$CLASSPATH:"$i"
+    fi
+done
+
+TOOLS=src/main/org/apache/tools
+CLASSDIR=build/classes
+
+CLASSPATH=${CLASSDIR}:src/main:${CLASSPATH}
+
+# For Cygwin, switch to Windows format before running java
+if $cygwin; then
+  CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+fi
+
+export CLASSPATH
+
+mkdir -p build
+mkdir -p ${CLASSDIR}
+mkdir -p bin
+
+echo ... Compiling Ant Classes
+
+"${JAVAC}" $BOOTJAVAC_OPTS -d ${CLASSDIR} ${TOOLS}/bzip2/*.java ${TOOLS}/tar/*.java ${TOOLS}/zip/*.java \
+    ${TOOLS}/ant/util/regexp/RegexpMatcher.java \
+    ${TOOLS}/ant/util/regexp/RegexpMatcherFactory.java \
+    ${TOOLS}/ant/property/*.java \
+    ${TOOLS}/ant/types/*.java \
+    ${TOOLS}/ant/types/resources/*.java \
+    ${TOOLS}/ant/*.java ${TOOLS}/ant/taskdefs/*.java \
+    ${TOOLS}/ant/taskdefs/compilers/*.java \
+    ${TOOLS}/ant/taskdefs/condition/*.java
+ret=$?
+if [ $ret != 0 ]; then
+  echo ... Failed compiling Ant classes !
+  exit $ret
+fi
+
+echo ... Copying Required Files
+
+cp src/main/org/apache/tools/ant/taskdefs/defaults.properties \
+    ${CLASSDIR}/org/apache/tools/ant/taskdefs
+cp src/main/org/apache/tools/ant/types/defaults.properties \
+    ${CLASSDIR}/org/apache/tools/ant/types
+cp src/script/antRun bin
+chmod +x bin/antRun
+
+echo ... Building Ant Distribution
+
+"${JAVACMD}" -classpath "${CLASSPATH}" -Dant.home=. $ANT_OPTS org.apache.tools.ant.Main -emacs "$@" bootstrap
+ret=$?
+if [ $ret != 0 ]; then
+  echo ... Failed Building Ant Distribution !
+  exit $ret
+fi
+
+
+echo ... Cleaning Up Build Directories
+
+rm -rf ${CLASSDIR}
+rm -rf bin
+
+echo ... Done Bootstrapping Ant Distribution
\ No newline at end of file
diff --git a/trunk/build.bat b/trunk/build.bat
new file mode 100755
index 0000000..0f1a52d
--- /dev/null
+++ b/trunk/build.bat
@@ -0,0 +1,40 @@
+@echo off
+
+REM  Licensed to the Apache Software Foundation (ASF) under one or more
+REM  contributor license agreements.  See the NOTICE file distributed with
+REM  this work for additional information regarding copyright ownership.
+REM  The ASF licenses this file to You under the Apache License, Version 2.0
+REM  (the "License"); you may not use this file except in compliance with
+REM  the License.  You may obtain a copy of the License at
+REM 
+REM      http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM  Unless required by applicable law or agreed to in writing, software
+REM  distributed under the License is distributed on an "AS IS" BASIS,
+REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM  See the License for the specific language governing permissions and
+REM  limitations under the License.
+
+set REAL_ANT_HOME=%ANT_HOME%
+set ANT_HOME=%~dp0\bootstrap
+if exist bootstrap\lib\ant.jar if exist bootstrap\bin\ant.bat if exist bootstrap\bin\lcp.bat if exist bootstrap\bin\antRun.bat goto runAnt
+call bootstrap.bat
+if exist bootstrap\lib\ant.jar if exist bootstrap\bin\ant.bat if exist bootstrap\bin\lcp.bat if exist bootstrap\bin\antRun.bat goto runAnt
+echo Bootstrap FAILED
+REM set the error code
+color 00
+goto cleanup
+
+:runAnt
+if not "%REAL_ANT_HOME%" == "" goto install_ant
+call bootstrap\bin\ant.bat -lib lib/optional %1 %2 %3 %4 %5 %6 %7 %8 %9
+goto cleanup
+
+:install_ant
+call bootstrap\bin\ant.bat -nouserlib -lib lib/optional -Dant.install="%REAL_ANT_HOME%" %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+rem clean up
+:cleanup
+set ANT_HOME=%REAL_ANT_HOME%
+set REAL_ANT_HOME=
+
diff --git a/trunk/build.sh b/trunk/build.sh
new file mode 100755
index 0000000..080562d
--- /dev/null
+++ b/trunk/build.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  Darwin*) darwin=true
+           if [ -z "$JAVA_HOME" ] ; then
+             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
+           fi
+           ;;
+esac
+
+REALANTHOME=$ANT_HOME
+if [ -z "$PWD" ]; then
+    ANT_HOME=./bootstrap
+else
+    ANT_HOME="$PWD"/bootstrap
+fi
+export ANT_HOME
+
+if test ! -f bootstrap/lib/ant.jar -o  ! -x bootstrap/bin/ant -o ! -x bootstrap/bin/antRun ; then
+  /bin/sh ./bootstrap.sh
+fi
+
+if test ! -f bootstrap/lib/ant.jar -o  ! -x bootstrap/bin/ant -o ! -x bootstrap/bin/antRun ; then
+  echo Bootstrap FAILED
+  exit 1
+fi
+
+if [ "$REALANTHOME" != "" ] ; then
+  if $cygwin; then
+     REALANTHOME=`cygpath --windows "$REALANTHOME"`
+  fi
+  ANT_INSTALL="-Dant.install=$REALANTHOME"
+else
+  ANT_INSTALL="-emacs"
+fi
+
+bootstrap/bin/ant -nouserlib -lib lib/optional "$ANT_INSTALL" $*
+
diff --git a/trunk/build.xml b/trunk/build.xml
new file mode 100644
index 0000000..cc0fffd
--- /dev/null
+++ b/trunk/build.xml
@@ -0,0 +1,1984 @@
+<?xml version="1.0"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="apache-ant" default="main" basedir=".">
+
+  <!-- Give user a chance to override without editing this file
+       (and without typing -D on each invocation) -->
+  <property file=".ant.properties"/>
+  <property file="${user.home}/.ant.properties"/>
+  <property environment="env"/>
+
+
+  <!--
+       ===================================================================
+         Set the properties that control names and versions
+       ===================================================================
+  -->
+  <property name="Name" value="Apache Ant"/>
+  <property name="name" value="ant"/>
+  <!-- this is the groupId of ant in the Maven repository -->
+  <property name="groupid" value="org.apache.ant"/>
+  <property name="project.version" value="1.8.0alpha"/>
+  <!-- pom.version is used when doing a distribution and must match with what is checked in under src/etc/poms -->
+  <property name="pom.version" value="1.8.0-SNAPSHOT"/>
+  <property name="manifest-version" value="1.8.0"/>
+  <property name="bootstrap.jar" value="ant-bootstrap.jar"/>
+
+  <property name="ant.package" value="org/apache/tools/ant"/>
+  <property name="taskdefs.package" value="${ant.package}/taskdefs"/>
+  <property name="condition.package" value="${taskdefs.package}/condition"/>
+  <property name="optional.package" value="${taskdefs.package}/optional"/>
+  <property name="optional.condition.package" value="${optional.package}/condition"/>
+  <property name="type.package" value="${ant.package}/types"/>
+  <property name="optional.type.package" value="${type.package}/optional"/>
+  <property name="apache.resolver.type.package" value="${ant.package}/types/resolver"/>
+  <property name="util.package" value="${ant.package}/util"/>
+  <property name="regexp.package" value="${util.package}/regexp"/>
+
+  <property name="optional.jars.prefix" value="ant"/>
+  <property name="optional.jars.whenmanifestonly" value="skip"/>
+
+  <!--
+       ===================================================================
+         Set the properties related to the source tree
+       ===================================================================
+  -->
+  <property name="src.dir" value="src"/>
+  <property name="java.dir" value="${src.dir}/main"/>
+  <property name="script.dir" value="${src.dir}/script"/>
+  <property name="lib.dir" value="lib"/>
+  <property name="docs.dir" value="docs"/>
+  <property name="etc.dir" value="${src.dir}/etc"/>
+  <property name="src.junit" value="${src.dir}/tests/junit"/>
+  <property name="src.antunit" value="${src.dir}/tests/antunit"/>
+  <property name="tests.etc.dir" value="${src.dir}/etc/testcases"/>
+  <property name="manifest" value="${src.dir}/etc/manifest"/>
+  <property name="resource.dir" value="${src.dir}/resources"/>
+
+  <!--
+       ===================================================================
+         Set the properties for the build area
+       ===================================================================
+  -->
+  <property name="build.dir" value="build"/>
+  <property name="bootstrap.dir" value="bootstrap"/>
+  <property name="build.classes" value="${build.dir}/classes"/>
+  <property name="build.lib" value="${build.dir}/lib"/>
+  <property name="build.javadocs" value="${build.dir}/javadocs"/>
+  <property name="build.tests" value="${build.dir}/testcases"/>
+  <property name="build.tests.javadocs" value="${build.dir}/javadocs.test/"/>
+  <property name="build.junit.xml" location="${build.tests}/xml"/>
+  <property name="antunit.xml" location="${build.dir}/antunit/xml"/>
+  <property name="antunit.reports" location="${build.dir}/antunit/reports"/>
+  <property name="build.junit.reports" location="${build.tests}/reports"/>
+  <property name="manifest.tmp" value="${build.dir}/optional.manifest"/>
+  <!-- the absolute path -->
+  <property name="build.tests.value" location="${build.tests}"/>
+
+  <!--
+       ===================================================================
+         Set the properties that control various build options
+       ===================================================================
+  -->
+  <property name="debug" value="true"/>
+  <property name="chmod.fail" value="true"/>
+  <property name="chmod.maxparallel" value="250"/>
+  <property name="deprecation" value="false"/>
+  <property name="optimize" value="true"/>
+  <property name="javac.target" value="1.2"/>
+  <property name="javac.source" value="1.2"/>
+  <property name="junit.fork" value="false"/>
+  <property name="junit.filtertrace" value="off"/>
+  <property name="junit.summary" value="no"/>
+  <property name="test.haltonfailure" value="false"/>
+  <property name="junit.forkmode" value="once"/>
+  <property name="unfiltered.files" value="**/*.gif,**/*.jpg,**/*.ico,**/*.pdf,**/*.zip"/>
+  <property name="junit.collector.dir" value="${build.dir}/failingTests"/>
+  <property name="junit.collector.class" value="FailedTests"/>
+
+  <!--
+       ===================================================================
+         Set the paths used in the build
+       ===================================================================
+  -->
+  <path id="classpath">
+  </path>
+
+  <path id="tests-classpath">
+    <pathelement location="${build.classes}"/>
+    <pathelement location="${build.tests}"/>
+    <!--
+        include the test source and test data dirs
+        so that we can pick resources via getResource(AsStream)
+     -->
+    <pathelement location="${src.junit}"/>
+    <pathelement location="${tests.etc.dir}"/>
+    <path refid="classpath"/>
+  </path>
+
+  <!-- turn this path into a string which is passed to the tests -->
+  <property name="tests-classpath.value"
+    refid="tests-classpath"/>
+
+  <!--
+        ===================================================================
+          Set up properties for the distribution area
+        ===================================================================
+   -->
+  <property name="dist.name" value="apache-${name}-${project.version}"/>
+  <property name="dist.base" value="distribution"/>
+  <property name="dist.base.source" value="${dist.base}/source"/>
+  <property name="dist.base.binaries" value="${dist.base}/binaries"/>
+  <property name="dist.dir" value="dist"/>
+  <property name="dist.bin" value="${dist.dir}/bin"/>
+  <property name="dist.lib" value="${dist.dir}/lib"/>
+  <property name="dist.docs" value="${dist.dir}/docs"/>
+  <property name="dist.etc" value="${dist.dir}/etc"/>
+  <property name="dist.javadocs" value="${dist.dir}/docs/manual/api"/>
+
+  <property name="src.dist.dir" value="dist-src"/>
+  <property name="src.dist.src" value="${src.dist.dir}/src"/>
+  <property name="src.dist.docs" value="${src.dist.dir}/docs"/>
+  <property name="src.dist.lib" value="${src.dist.dir}/lib"/>
+
+  <property name="java-repository.dir" value="java-repository/${groupid}"/>
+  <property name="java-repository.jars.dir" value="${java-repository.dir}/jars"/>
+  <property name="java-repository.poms.dir" value="${java-repository.dir}/poms"/>
+
+  <!--
+       ===================================================================
+         Set up selectors to be used by javac, junit and jar to exclude
+         files that have dependencies that are not available
+       ===================================================================
+  -->
+  <!-- depends on JDK version -->
+  <selector id="needs.jdk1.3+">
+    <or>
+      <filename name="${ant.package}/taskdefs/TestProcess*"/>
+      <filename name="${optional.package}/extension/**"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jdk1.4+">
+    <or>
+      <filename name="${regexp.package}/Jdk14Regexp*"/>
+      <filename name="${ant.package}/types/AssertionsTest.java"/>
+      <filename name="${ant.package}/launch/LocatorTest*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jdk1.5+">
+    <or>
+      <filename name="${taskdefs.package}/AptTest*"/>
+      <filename name="${util.package}/java15/*"/>
+    </or>
+  </selector>
+
+  <!-- Kaffe has some JDK 1.5 features including java.lang.Readable,
+       but not all of them -->
+  <selector id="not.in.kaffe">
+    <or>
+      <filename name="${condition.package}/IsReachable*"/>
+    </or>
+  </selector>
+
+  <!-- depends on external libraries -->
+  <selector id="needs.trax">
+    <or>
+      <filename name="${optional.package}/TraXLiaison*"/>
+      <filename name="${optional.package}/XsltTest*"/>
+      <filename name="${type.package}/XMLCatalogBuildFileTest*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.apache-resolver">
+    <filename name="${apache.resolver.type.package}/**"/>
+  </selector>
+
+  <selector id="needs.junit">
+    <filename name="${optional.package}/junit/**"/>
+  </selector>
+
+  <selector id="needs.apache-regexp">
+    <filename name="${regexp.package}/JakartaRegexp*"/>
+  </selector>
+
+  <selector id="needs.apache-oro">
+    <or>
+      <filename name="${regexp.package}/JakartaOro*"/>
+      <filename name="${optional.package}/perforce/*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.apache-bcel">
+    <or>
+      <filename name="${ant.package}/filters/util/JavaClassHelper*"/>
+      <filename name="${util.package}/depend/bcel/*"/>
+      <filename name="${optional.type.package}/depend/ClassFileSetTest*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.apache-log4j">
+    <filename name="${ant.package}/listener/Log4jListener*"/>
+  </selector>
+
+  <selector id="needs.commons-logging">
+    <filename name="${ant.package}/listener/CommonsLoggingListener*"/>
+  </selector>
+
+  <selector id="needs.apache-bsf">
+    <or>
+      <filename name="${util.package}/ScriptRunner.*"/>
+      <filename name="${util.package}/optional/ScriptRunner*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.stylebook">
+    <filename name="${optional.package}/StyleBook*"/>
+  </selector>
+
+  <selector id="needs.javamail">
+    <or>
+      <filename name="${ant.package}/taskdefs/email/MimeMailer*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.netrexx">
+    <filename name="${optional.package}/NetRexxC*"/>
+  </selector>
+
+  <selector id="needs.commons-net">
+    <or>
+      <filename name="${optional.package}/net/FTP*"/>
+      <filename name="${optional.package}/net/RExec*"/>
+      <filename name="${optional.package}/net/TelnetTask*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.antlr">
+    <filename name="${optional.package}/ANTLR*"/>
+  </selector>
+
+  <selector id="needs.jmf">
+    <filename name="${optional.package}/sound/*"/>
+  </selector>
+
+  <selector id="needs.jai">
+    <or>
+      <filename name="${optional.package}/image/*"/>
+      <filename name="${optional.type.package}/image/*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jdepend">
+    <filename name="${optional.package}/jdepend/*"/>
+  </selector>
+
+  <selector id="needs.swing">
+    <filename name="${optional.package}/splash/*"/>
+  </selector>
+
+  <selector id="needs.jsch">
+    <filename name="${optional.package}/ssh/*"/>
+  </selector>
+
+  <selector id="ant.launcher">
+    <filename name="${ant.package}/launch/**/*"/>
+  </selector>
+
+  <patternset id="onlinetests">
+    <exclude name="**/GetTest.java" if="offline"/>
+  </patternset>
+
+  <patternset id="teststhatfail">
+    <!-- Property 'run.failing.tests' should force Ant to run these tests. -->
+    <!-- Because the whole patternset can not be excluded, you have to add -->
+    <!-- an unless-attribute on each exclude-element.                      -->
+    <exclude unless="run.failing.tests" name="${optional.package}/BeanShellScriptTest.java"/>
+    <exclude unless="run.failing.tests" name="${optional.package}/jdepend/JDependTest.java"/>
+    <exclude unless="run.failing.tests" name="${optional.package}/DotnetTest.java"/>
+    <exclude unless="run.failing.tests" name="${optional.package}/WsdlToDotnetTest.java"/>
+  </patternset>
+
+  <!--tests that need an XML Schema-supporting parser to work-->
+  <selector id="needs.xmlschema">
+    <or>
+      <filename name="${optional.package}/SchemaValidateTest.*"/>
+      <filename name="${optional.package}/XmlValidateTest.*"/>
+    </or>
+  </selector>
+
+  <!--
+       ===================================================================
+         Set up a patternsets that matches the parts of our JUnit testsuite
+         that may be useful for task developers.
+       ===================================================================
+  -->
+  <patternset id="useful.tests">
+    <include name="${ant.package}/BuildFileTest*"/>
+    <include name="${regexp.package}/RegexpMatcherTest*"/>
+    <include name="${regexp.package}/RegexpTest*"/>
+    <include name="${optional.package}/AbstractXSLTLiaisonTest*"/>
+    <include name="${ant.package}/types/AbstractFileSetTest*"/>
+  </patternset>
+
+  <!--
+       ===================================================================
+         Set up a patternsets that matches the parts of our site that
+         should not be part of the distribution.
+       ===================================================================
+  -->
+  <patternset id="site.excludes">
+    <exclude name="bindownload.html"/>
+    <exclude name="srcdownload.html"/>
+    <exclude name="*.cgi"/>
+  </patternset>
+
+  <!--
+       ===================================================================
+         Check to see what optional dependencies are available
+       ===================================================================
+  -->
+  <target name="check_for_optional_packages">
+    <available property="jdk1.3+" classname="java.lang.StrictMath"/>
+    <available property="jdk1.4+" classname="java.lang.CharSequence"/>
+    <available property="jdk1.5+" classname="java.net.Proxy"/>
+    <available property="jdk1.6+" classname="java.util.ServiceLoader"/>
+    <available property="kaffe" classname="kaffe.util.NotImplemented"/>
+    <available property="bsf.present"
+      classname="org.apache.bsf.BSFManager"
+      classpathref="classpath"/>
+    <available property="netrexx.present"
+      classname="netrexx.lang.Rexx"
+      classpathref="classpath"/>
+    <available property="trax.present"
+      classname="javax.xml.transform.Transformer"
+      classpathref="classpath"/>
+    <condition property="trax.impl.present">
+      <or>
+        <and>
+          <isset property="javax.xml.transform.TransformerFactory"/>
+          <available classname="${javax.xml.transform.TransformerFactory}"
+            classpathref="classpath"/>
+        </and>
+        <available resource="META-INF/services/javax.xml.transform.TransformerFactory"/>
+      </or>
+    </condition>
+    <available property="apache.resolver.present"
+      classname="org.apache.xml.resolver.tools.CatalogResolver"
+      classpathref="classpath"/>
+    <available property="xalan2.present"
+      classname="org.apache.xalan.transformer.TransformerImpl"
+      classpathref="classpath"/>
+    <available property="junit.present"
+      classname="junit.framework.TestCase"
+      classpathref="classpath"/>
+    <available property="antunit.present"
+      classname="org.apache.ant.antunit.AntUnit"
+      classpathref="classpath"/>
+    <available property="commons.net.present"
+      classname="org.apache.commons.net.ftp.FTPClient"
+      classpathref="classpath"/>
+    <available property="antlr.present" 
+      classname="antlr.Tool" 
+      classpathref="classpath"/>
+    <available property="stylebook.present"
+      classname="org.apache.stylebook.Engine"
+      classpathref="classpath"/>
+    <available property="apache.regexp.present"
+      classname="org.apache.regexp.RE"
+      classpathref="classpath"/>
+    <available property="apache.oro.present"
+      classname="org.apache.oro.text.regex.Perl5Matcher"
+      classpathref="classpath"/>
+    <available property="jmf.present"
+      classname="javax.sound.sampled.Clip"
+      classpathref="classpath"/>
+    <available property="jai.present"
+      classname="javax.media.jai.JAI"
+      classpathref="classpath"/>
+    <available property="jdepend.present"
+      classname="jdepend.framework.JDepend"
+      classpathref="classpath"/>
+    <available property="log4j.present"
+      classname="org.apache.log4j.Logger"
+      classpathref="classpath"/>
+    <available property="commons.logging.present"
+      classname="org.apache.commons.logging.LogFactory"
+      classpathref="classpath"/>
+    <available property="xalan.envcheck"
+      classname="org.apache.xalan.xslt.EnvironmentCheck"
+      classpathref="classpath"/>
+    <available property="which.present"
+      classname="org.apache.env.Which"
+      classpathref="classpath"/>
+
+    <available property="xerces.present"
+      classname="org.apache.xerces.parsers.SAXParser"
+      classpathref="classpath"/>
+    <available property="bcel.present"
+      classname="org.apache.bcel.Constants"
+      classpathref="classpath"/>
+
+    <condition property="javamail.complete">
+      <and>
+        <available classname="javax.activation.DataHandler"
+          classpathref="classpath"/>
+        <available classname="javax.mail.Transport"
+          classpathref="classpath"/>
+      </and>
+    </condition>
+
+    <condition property="some.regexp.support">
+      <or>
+        <isset property="jdk1.4+"/>
+        <isset property="apache.regexp.present"/>
+        <isset property="apache.oro.present"/>
+      </or>
+    </condition>
+
+    <condition property="tests.and.ant.share.classloader">
+      <or>
+        <equals arg1="${junit.fork}" arg2="true"/>
+        <equals arg1="${build.sysclasspath}" arg2="only"/>
+      </or>
+    </condition>
+
+    <condition property="sun.tools.present">
+      <and>
+        <available classname="sun.tools.native2ascii.Main"/>
+        <available classname="com.sun.tools.javah.Main"/>
+      </and>
+    </condition>
+
+    <condition property="tests.are.on.system.classpath">
+      <or>
+        <resourcecount count="1">
+          <intersect>
+            <path path="${java.class.path}" />
+            <file file="${build.tests}" />
+          </intersect>
+        </resourcecount>
+        <istrue value="${junit.fork}"/>
+      </or>
+    </condition>
+
+    <echo level="verbose"> tests.are.on.system.classpath=${tests.are.on.system.classpath}</echo>
+
+    <condition property="jasper.present">
+      <and>
+        <available classname="org.apache.jasper.compiler.Compiler"/>
+        <available classname="org.apache.jasper.JasperException"/>
+      </and>
+    </condition>
+
+    <condition property="swing.present">
+      <or>
+        <not>
+          <isset property="kaffe"/>
+        </not>
+        <available classname="javax.swing.ImageIcon"
+          classpathref="classpath"/>
+      </or>
+    </condition>
+
+    <!-- http client needs commons logging -->
+    <condition property="apache-httpclient.present">
+      <and>
+        <available
+          classname="org.apache.commons.httpclient.HttpClient"
+          classpathref="classpath"/>
+        <isset property="commons.logging.present"/>
+      </and>
+    </condition>
+
+    <condition property="wsdl.found">
+      <or>
+        <available file="wsdl" filepath="${env.PATH}"/>
+        <available file="wsdl.exe" filepath="${env.PATH}"/>
+        <available file="wsdl.exe" filepath="${env.Path}"/>
+      </or>
+    </condition>
+    <echo level="verbose"> wsdl.found=${wsdl.found}</echo>
+    <condition property="csc.found">
+      <or>
+        <available file="mcs" filepath="${env.PATH}"/>
+        <available file="csc" filepath="${env.PATH}"/>
+        <available file="csc.exe" filepath="${env.PATH}"/>
+        <available file="csc.exe" filepath="${env.Path}"/>
+      </or>
+    </condition>
+    <echo level="verbose"> csc.found=${csc.found}</echo>
+    <condition property="dotnetapps.found">
+      <and>
+        <isset property="csc.found"/>
+        <isset property="wsdl.found"/>
+      </and>
+    </condition>
+    <echo level="verbose"> dotnetapps.found=${dotnetapps.found}</echo>
+
+    <available property="rhino.present"
+      classname="org.mozilla.javascript.Scriptable"
+      classpathref="classpath"/>
+    <available property="beanshell.present"
+      classname="bsh.StringUtil"
+      classpathref="classpath"/>
+    <available property="xerces1.present"
+      classname="org.apache.xerces.framework.XMLParser"
+      classpathref="classpath"/>
+    <available property="jsch.present"
+      classname="com.jcraft.jsch.Session"
+      classpathref="classpath"/>
+
+    <condition property="build.compiler" value="classic">
+      <not>
+        <isset property="jdk1.3+"/>
+      </not>
+    </condition>
+    <property name="build.compiler" value="modern"/>
+
+    <!--check for XSD support in the parser-->
+    <condition property="xmlschema.present">
+      <or>
+        <parsersupports
+          feature="http://apache.org/xml/features/validation/schema"/>
+        <parsersupports
+          feature="http://java.sun.com/xml/jaxp/properties/schemaSource"/>
+      </or>
+    </condition>
+
+  </target>
+
+
+  <!--
+       ===================================================================
+         Prepare the build
+       ===================================================================
+  -->
+  <target name="prepare">
+    <tstamp>
+      <format property="year" pattern="yyyy"/>
+    </tstamp>
+    <filterchain id="ant.filters">
+       <expandproperties/>
+    </filterchain>
+  </target>
+
+  <!--
+       ===================================================================
+         Build the code
+       ===================================================================
+  -->
+  <target name="build"
+    depends="prepare, check_for_optional_packages"
+    description="--> compiles the source code">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${build.classes}"/>
+    <mkdir dir="${build.lib}"/>
+
+    <javac srcdir="${java.dir}"
+      destdir="${build.classes}"
+      debug="${debug}"
+      deprecation="${deprecation}"
+      target="${javac.target}"
+      source="${javac.source}"
+      optimize="${optimize}">
+      <classpath refid="classpath"/>
+
+      <selector id="conditional-patterns">
+        <not>
+          <or>
+            <selector refid="needs.jdk1.3+" unless="jdk1.3+"/>
+            <selector refid="needs.jdk1.4+" unless="jdk1.4+"/>
+            <selector refid="needs.jdk1.5+" unless="jdk1.5+"/>
+            <selector refid="not.in.kaffe" if="kaffe"/>
+
+            <selector refid="needs.trax" unless="trax.present"/>
+            <selector refid="needs.apache-resolver" unless="apache.resolver.present"/>
+            <selector refid="needs.junit" unless="junit.present"/>
+            <selector refid="needs.apache-regexp"
+              unless="apache.regexp.present"/>
+            <selector refid="needs.apache-oro" unless="apache.oro.present"/>
+            <selector refid="needs.apache-bcel" unless="bcel.present"/>
+            <selector refid="needs.apache-log4j" unless="log4j.present"/>
+            <selector refid="needs.commons-logging"
+              unless="commons.logging.present"/>
+            <selector refid="needs.apache-bsf" unless="bsf.present"/>
+            <selector refid="needs.stylebook" unless="stylebook.present"/>
+            <selector refid="needs.javamail" unless="javamail.complete"/>
+            <selector refid="needs.netrexx" unless="netrexx.present"/>
+            <selector refid="needs.commons-net" unless="commons.net.present"/>
+            <selector refid="needs.antlr" unless="antlr.present"/>
+            <selector refid="needs.jmf" unless="jmf.present"/>
+            <selector refid="needs.jai" unless="jai.present"/>
+            <selector refid="needs.jdepend" unless="jdepend.present"/>
+            <selector refid="needs.swing" unless="swing.present"/>
+            <selector refid="needs.jsch" unless="jsch.present"/>
+            <selector refid="needs.xmlschema" unless="xmlschema.present"/>
+          </or>
+        </not>
+      </selector>
+    </javac>
+
+    <copy todir="${build.classes}">
+      <fileset dir="${java.dir}">
+        <include name="**/*.properties"/>
+        <include name="**/*.dtd"/>
+        <include name="**/*.xml"/>
+      </fileset>
+      <fileset dir="${resource.dir}" />
+    </copy>
+
+    <copy todir="${build.classes}"
+      overwrite="true" encoding="UTF-8">
+      <fileset dir="${java.dir}">
+        <include name="**/version.txt"/>
+        <include name="**/defaultManifest.mf"/>
+      </fileset>
+      <filterchain refid="ant.filters"/>
+    </copy>
+
+    <copy todir="${build.classes}/${optional.package}/junit/xsl">
+      <fileset dir="${etc.dir}">
+        <include name="junit-frames.xsl"/>
+        <include name="junit-noframes.xsl"/>
+      </fileset>
+    </copy>
+  </target>
+
+  <!--
+       ===================================================================
+         Create the all of the Apache Ant jars
+       ===================================================================
+  -->
+  <target name="jars"
+    depends="build"
+    description="--> creates the Apache Ant jars">
+
+    <copy todir="${build.dir}">
+      <fileset dir="${basedir}">
+        <include name="LICENSE"/>
+        <include name="LICENSE.xerces"/>
+        <include name="LICENSE.dom"/>
+        <include name="LICENSE.sax"/>
+        <include name="NOTICE"/>
+      </fileset>
+      <mapper type="glob" from="*" to="*.txt"/>
+    </copy>
+
+    <copy file="${manifest}" tofile="${manifest.tmp}"/>
+    <manifest file="${manifest.tmp}">
+      <section name="${optional.package}/">
+        <attribute name="Extension-name"
+          value="org.apache.tools.ant"/>
+        <attribute name="Specification-Title"
+          value="Apache Ant"/>
+        <attribute name="Specification-Version"
+          value="${manifest-version}"/>
+        <attribute name="Specification-Vendor"
+          value="Apache Software Foundation"/>
+        <attribute name="Implementation-Title"
+          value="org.apache.tools.ant"/>
+        <attribute name="Implementation-Version"
+          value="${manifest-version}"/>
+        <attribute name="Implementation-Vendor"
+          value="Apache Software Foundation"/>
+      </section>
+    </manifest>
+
+    <jar destfile="${build.lib}/${name}-launcher.jar"
+      basedir="${build.classes}"
+      whenmanifestonly="fail">
+      <selector refid="ant.launcher"/>
+      <manifest>
+        <attribute name="Main-Class" value="org.apache.tools.ant.launch.Launcher"/>
+      </manifest>
+    </jar>
+
+    <jar destfile="${build.lib}/${name}.jar"
+      basedir="${build.classes}"
+      manifest="${manifest}"
+      whenmanifestonly="fail">
+      <not>
+        <selector id="non-core">
+          <or>
+            <filename name="${optional.package}/**"/>
+            <filename name="${optional.type.package}/**"/>
+            <filename name="${util.package}/depend/**"/>
+            <filename name="${util.package}/optional/**"/>
+            <selector refid="needs.apache-log4j"/>
+            <selector refid="needs.commons-logging"/>
+            <selector refid="needs.apache-bcel"/>
+            <selector refid="needs.apache-bsf"/>
+            <selector refid="needs.apache-regexp"/>
+            <selector refid="needs.apache-resolver"/>
+            <selector refid="needs.apache-oro"/>
+            <selector refid="needs.jdk1.4+"/>
+            <selector refid="needs.jdk1.5+"/>
+            <selector refid="needs.javamail"/>
+            <selector refid="ant.launcher"/>
+          </or>
+        </selector>
+      </not>
+      <metainf dir="${build.dir}">
+        <include name="LICENSE.txt"/>
+        <include name="NOTICE.txt"/>
+      </metainf>
+
+      <manifest>
+        <section name="${ant.package}/">
+          <attribute name="Extension-name"
+            value="org.apache.tools.ant"/>
+          <attribute name="Specification-Title"
+            value="Apache Ant"/>
+          <attribute name="Specification-Version"
+            value="${manifest-version}"/>
+          <attribute name="Specification-Vendor"
+            value="Apache Software Foundation"/>
+          <attribute name="Implementation-Title"
+            value="org.apache.tools.ant"/>
+          <attribute name="Implementation-Version"
+            value="${manifest-version}"/>
+          <attribute name="Implementation-Vendor"
+            value="Apache Software Foundation"/>
+        </section>
+      </manifest>
+
+      <fileset dir="${docs.dir}">
+        <include name="images/ant_logo_large.gif"/>
+      </fileset>
+    </jar>
+
+    <jar destfile="${build.lib}/${bootstrap.jar}"
+      basedir="${build.classes}"
+      manifest="${manifest}"
+      whenmanifestonly="fail">
+      <include name="${ant.package}/Main.class"/>
+      <metainf dir="${build.dir}">
+        <include name="LICENSE.txt"/>
+        <include name="NOTICE.txt"/>
+      </metainf>
+      <manifest>
+        <attribute name="Class-Path"
+          value="ant.jar xml-apis.jar xercesImpl.jar xalan.jar"/>
+      </manifest>
+    </jar>
+
+    <jar destfile="${build.lib}/ant-nodeps.jar"
+      basedir="${build.classes}"
+      manifest="${manifest.tmp}"
+      whenmanifestonly="${optional.jars.whenmanifestonly}">
+      <and>
+        <selector refid="non-core"/>
+        <not>
+          <or>
+            <selector refid="ant.launcher"/>
+            <selector refid="needs.trax"/>
+            <selector refid="needs.apache-resolver"/>
+            <selector refid="needs.junit"/>
+            <selector refid="needs.apache-regexp"/>
+            <selector refid="needs.apache-oro"/>
+            <selector refid="needs.apache-bcel"/>
+            <selector refid="needs.apache-log4j"/>
+            <selector refid="needs.commons-logging"/>
+            <selector refid="needs.apache-bsf"/>
+            <selector refid="needs.stylebook"/>
+            <selector refid="needs.javamail"/>
+            <selector refid="needs.netrexx"/>
+            <selector refid="needs.commons-net"/>
+            <selector refid="needs.antlr"/>
+            <selector refid="needs.jmf"/>
+            <selector refid="needs.jai"/>
+            <selector refid="needs.jdepend"/>
+            <selector refid="needs.swing"/>
+            <selector refid="needs.jsch"/>
+          </or>
+        </not>
+      </and>
+      <metainf dir="${build.dir}">
+        <include name="LICENSE.txt"/>
+        <include name="NOTICE.txt"/>
+      </metainf>
+    </jar>
+
+    <macrodef name="optional-jar">
+      <attribute name="dep"/>
+      <sequential>
+        <jar destfile="${build.lib}/${optional.jars.prefix}-@{dep}.jar"
+          basedir="${build.classes}"
+          manifest="${manifest.tmp}"
+          whenmanifestonly="${optional.jars.whenmanifestonly}">
+          <selector refid="needs.@{dep}"/>
+        </jar>
+      </sequential>
+    </macrodef>
+
+    <optional-jar dep="trax"/>
+    <optional-jar dep="apache-resolver"/>
+    <optional-jar dep="junit"/>
+    <optional-jar dep="apache-regexp"/>
+    <optional-jar dep="apache-oro"/>
+    <optional-jar dep="apache-bcel"/>
+    <optional-jar dep="apache-log4j"/>
+    <optional-jar dep="commons-logging"/>
+    <optional-jar dep="apache-bsf"/>
+    <optional-jar dep="stylebook"/>
+    <optional-jar dep="javamail"/>
+    <optional-jar dep="netrexx"/>
+    <optional-jar dep="commons-net"/>
+    <optional-jar dep="antlr"/>
+    <optional-jar dep="jmf"/>
+    <optional-jar dep="jai"/>
+    <optional-jar dep="swing"/>
+    <optional-jar dep="jsch"/>
+    <optional-jar dep="jdepend"/>
+
+  </target>
+
+  <!--   Creates jar of test utility classes -->
+  <target name="test-jar"
+    depends="compile-tests"
+    description="--> creates the Apache Ant Test Utilities jar">
+
+    <fail unless="junit.present">
+      We cannot build the test jar unless JUnit is present,
+      as JUnit is needed to compile the test classes.
+    </fail>
+    <jar destfile="${build.lib}/${name}-testutil.jar"
+      basedir="${build.tests}">
+      <patternset refid="useful.tests"/>
+    </jar>
+  </target>
+
+  <!--
+       ===================================================================
+         Create the essential distribution that can run Apache Ant
+       ===================================================================
+  -->
+  <target name="dist-lite"
+    depends="jars,test-jar"
+    description="--> creates a minimum distribution to run Apache Ant">
+
+    <mkdir dir="${dist.dir}"/>
+    <mkdir dir="${dist.bin}"/>
+    <mkdir dir="${dist.lib}"/>
+
+    <copy todir="${dist.lib}">
+      <fileset dir="${build.lib}">
+        <exclude name="${bootstrap.jar}"/>
+      </fileset>
+    </copy>
+
+    <copy todir="${dist.lib}">
+      <fileset dir="${lib.dir}">
+        <include name="*.jar"/>
+        <include name="*.zip"/>
+      </fileset>
+    </copy>
+
+    <copy todir="${dist.bin}">
+      <fileset dir="${script.dir}"/>
+    </copy>
+
+    <fixcrlf srcdir="${dist.bin}" eol="dos" includes="*.bat,*.cmd"/>
+    <fixcrlf srcdir="${dist.bin}" eol="unix">
+      <include name="ant"/>
+      <include name="antRun"/>
+      <include name="*.pl"/>
+    </fixcrlf>
+
+    <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**"
+      failonerror="${chmod.fail}"/>
+    <chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**"
+      failonerror="${chmod.fail}" maxparallel="${chmod.maxparallel}"/>
+    <chmod perm="ugo+x" type="file" failonerror="${chmod.fail}">
+      <fileset dir="${dist.bin}">
+        <include name="**/ant"/>
+        <include name="**/antRun"/>
+        <include name="**/*.pl"/>
+        <include name="**/*.py"/>
+      </fileset>
+    </chmod>
+
+  </target>
+
+  <!--
+        ===================================================================
+          Create the complete distribution
+        ===================================================================
+   -->
+  <target name="dist" description="--> creates a complete distribution">
+    <antcall inheritAll="false" target="internal_dist">
+      <param name="dist.dir" value="${dist.name}"/>
+    </antcall>
+  </target>
+
+  <target name="dist_javadocs" depends="javadocs">
+    <mkdir dir="${dist.javadocs}"/>
+    <copy todir="${dist.javadocs}" overwrite="true">
+      <fileset dir="${build.javadocs}"/>
+    </copy>
+  </target>
+
+
+  <target name="internal_dist" depends="dist-lite,dist_javadocs">
+    <mkdir dir="${dist.docs}"/>
+    <mkdir dir="${dist.etc}"/>
+
+    <copy todir="${dist.lib}" file="${lib.dir}/README"/>
+    <copy todir="${dist.lib}" file="${lib.dir}/libraries.properties"/>
+
+    <copy todir="${dist.lib}">
+        <fileset dir="${src.dir}/etc/poms">
+            <include name="*/pom.xml"/>
+        </fileset>
+        <mapper type="regexp" from="^(.*)[/\\]pom.xml" to="\1-${project.version}.pom"/>
+        <filterchain>
+            <tokenfilter>
+                <replaceregex pattern="${pom.version}" replace="${project.version}"/>
+            </tokenfilter>
+        </filterchain>
+    </copy>
+    <copy todir="${dist.lib}">
+        <fileset dir="${src.dir}/etc/poms">
+            <include name="pom.xml"/>
+        </fileset>
+        <mapper type="glob" from="pom.xml" to="ant-parent-${project.version}.pom"/>
+        <filterchain>
+            <tokenfilter>
+                <replaceregex pattern="${pom.version}" replace="${project.version}"/>
+            </tokenfilter>
+        </filterchain>
+    </copy>
+    <checksum algorithm="md5">
+        <fileset dir="${dist.lib}">
+            <include name="*.pom"/>
+        </fileset>
+    </checksum>
+    <checksum algorithm="sha1">
+        <fileset dir="${dist.lib}">
+            <include name="*.pom"/>
+        </fileset>
+    </checksum>
+
+    <copy todir="${dist.docs}">
+      <fileset dir="${docs.dir}" excludes="${unfiltered.files}">
+        <patternset refid="site.excludes"/>
+      </fileset>
+      <filterchain refid="ant.filters"/>
+    </copy>
+
+    <copy todir="${dist.docs}" filtering="false">
+      <fileset dir="${docs.dir}" includes="${unfiltered.files}">
+        <patternset refid="site.excludes"/>
+      </fileset>
+    </copy>
+
+    <copy todir="${dist.dir}">
+      <fileset dir="${basedir}">
+        <include name="README"/>
+        <include name="INSTALL"/>
+        <include name="LICENSE"/>
+        <include name="LICENSE.xerces"/>
+        <include name="LICENSE.dom"/>
+        <include name="LICENSE.sax"/>
+        <include name="NOTICE"/>
+        <include name="TODO"/>
+        <include name="WHATSNEW"/>
+        <include name="KEYS"/>
+        <include name="fetch.xml"/>
+	<include name="get-m2.xml"/>
+      </fileset>
+    </copy>
+
+    <chmod perm="ugo+rx" dir="${dist.dir}" type="dir" includes="**"
+      failonerror="${chmod.fail}"/>
+    <chmod perm="ugo+r" dir="${dist.dir}" type="file" includes="**"
+      failonerror="${chmod.fail}" maxparallel="${chmod.maxparallel}"/>
+    <chmod perm="ugo+x" type="file" failonerror="${chmod.fail}">
+      <fileset dir="${dist.bin}">
+        <include name="**/ant"/>
+        <include name="**/antRun"/>
+        <include name="**/*.pl"/>
+        <include name="**/*.py"/>
+      </fileset>
+    </chmod>
+
+    <!-- publish some useful stylesheets -->
+    <copy todir="${dist.etc}">
+      <fileset dir="${etc.dir}">
+        <include name="junit-frames.xsl"/>
+        <include name="junit-noframes.xsl"/>
+        <include name="junit-frames-xalan1.xsl"/>
+        <include name="coverage-frames.xsl"/>
+        <include name="maudit-frames.xsl"/>
+        <include name="mmetrics-frames.xsl"/>
+        <include name="changelog.xsl"/>
+        <include name="jdepend.xsl"/>
+        <include name="jdepend-frames.xsl"/>
+        <include name="checkstyle/*.xsl"/>
+        <include name="log.xsl"/>
+        <include name="tagdiff.xsl"/>
+      </fileset>
+      <fileset dir="${build.lib}">
+        <include name="${bootstrap.jar}"/>
+      </fileset>
+    </copy>
+
+  </target>
+
+
+  <!--
+       ===================================================================
+         Target to create bootstrap build
+       ===================================================================
+  -->
+  <target name="bootstrap" description="--> creates a bootstrap build">
+    <antcall inheritAll="false" target="dist-lite">
+      <param name="dist.dir" value="${bootstrap.dir}"/>
+    </antcall>
+  </target>
+
+
+  <!--
+       ===================================================================
+         Create the source distribution
+       ===================================================================
+  -->
+  <target name="src-dist"
+    description="--> creates a source distribution">
+
+    <mkdir dir="${src.dist.dir}"/>
+
+    <copy todir="${src.dist.lib}">
+      <fileset dir="${lib.dir}">
+        <include name="*.jar"/>
+        <include name="*.zip"/>
+        <include name="README"/>
+        <include name="libraries.properties"/>
+      </fileset>
+    </copy>
+
+    <copy todir="${src.dist.src}">
+      <fileset dir="${src.dir}"/>
+    </copy>
+
+    <copy todir="${src.dist.docs}">
+      <fileset dir="${docs.dir}">
+        <exclude name="manual/api/**"/>
+        <patternset refid="site.excludes"/>
+      </fileset>
+    </copy>
+
+    <copy todir="${src.dist.dir}">
+      <fileset dir="${basedir}">
+        <include name="README"/>
+        <include name="INSTALL"/>
+        <include name="LICENSE"/>
+        <include name="LICENSE.xerces"/>
+        <include name="LICENSE.dom"/>
+        <include name="LICENSE.sax"/>
+        <include name="NOTICE"/>
+        <include name="TODO"/>
+        <include name="WHATSNEW"/>
+        <include name="KEYS"/>
+        <include name="build.bat"/>
+        <include name="build.sh"/>
+        <include name="bootstrap.bat"/>
+        <include name="bootstrap.sh"/>
+        <include name="build.xml"/>
+        <include name="fetch.xml"/>
+	<include name="get-m2.xml"/>
+      </fileset>
+    </copy>
+
+    <fixcrlf srcdir="${src.dist.dir}" eol="dos" includes="*.bat,*.cmd"/>
+    <fixcrlf srcdir="${src.dist.dir}" eol="unix">
+      <include name="**/*.sh"/>
+      <include name="**/*.pl"/>
+      <include name="**/ant"/>
+      <include name="**/antRun"/>
+    </fixcrlf>
+    <fixcrlf srcdir="${src.dist.dir}">
+      <include name="**/*.java"/>
+      <exclude name="${tests.etc.dir}/taskdefs/fixcrlf/expected/Junk?.java"/>
+      <exclude name="${tests.etc.dir}/taskdefs/fixcrlf/input/Junk?.java"/>
+    </fixcrlf>
+
+    <chmod perm="ugo+x" dir="${src.dist.dir}" type="dir"
+      failonerror="${chmod.fail}"/>
+    <chmod perm="ugo+r" dir="${src.dist.dir}" failonerror="${chmod.fail}"/>
+    <chmod perm="ugo+x" failonerror="${chmod.fail}">
+      <fileset dir="${src.dist.dir}">
+        <include name="**/.sh"/>
+        <include name="**/.pl"/>
+        <include name="**/.py"/>
+        <include name="**/ant"/>
+        <include name="**/antRun"/>
+      </fileset>
+    </chmod>
+
+  </target>
+
+  <!--
+       ===================================================================
+         Create the binary distribution
+       ===================================================================
+  -->
+  <target name="main_distribution"
+    description="--> creates the zip and tar distributions">
+    <delete dir="${dist.base}"/>
+    <delete dir="${dist.name}"/>
+    <delete dir="${java-repository.dir}"/>
+    <mkdir dir="${dist.base}"/>
+    <mkdir dir="${dist.base.source}"/>
+    <mkdir dir="${dist.base.binaries}"/>
+    <mkdir dir="${java-repository.jars.dir}"/>
+    <mkdir dir="${java-repository.poms.dir}"/>
+    <antcall inheritAll="false" target="internal_dist">
+      <param name="dist.dir" value="${dist.name}"/>
+    </antcall>
+    <zip destfile="${dist.base.binaries}/${dist.name}-bin.zip">
+      <zipfileset dir="${dist.name}/.." filemode="755">
+        <include name="${dist.name}/bin/ant"/>
+        <include name="${dist.name}/bin/antRun"/>
+        <include name="${dist.name}/bin/*.pl"/>
+        <include name="${dist.name}/bin/*.py"/>
+      </zipfileset>
+      <fileset dir="${dist.name}/..">
+        <include name="${dist.name}/**"/>
+        <exclude name="${dist.name}/bin/ant"/>
+        <exclude name="${dist.name}/bin/antRun"/>
+        <exclude name="${dist.name}/bin/*.pl"/>
+        <exclude name="${dist.name}/bin/*.py"/>
+      </fileset>
+    </zip>
+    <tar longfile="gnu"
+      destfile="${dist.base.binaries}/${dist.name}-bin.tar">
+      <!-- removes redundant definition of permissions, but seems to
+           drop dirs (and to be slow)
+      <zipfileset src="${dist.base.binaries}/${dist.name}-bin.zip"/>
+      -->
+      <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant">
+        <include name="${dist.name}/bin/ant"/>
+        <include name="${dist.name}/bin/antRun"/>
+        <include name="${dist.name}/bin/*.pl"/>
+        <include name="${dist.name}/bin/*.py"/>
+      </tarfileset>
+      <tarfileset dir="${dist.name}/.." username="ant" group="ant">
+        <include name="${dist.name}/**"/>
+        <exclude name="${dist.name}/bin/ant"/>
+        <exclude name="${dist.name}/bin/antRun"/>
+        <exclude name="${dist.name}/bin/*.pl"/>
+        <exclude name="${dist.name}/bin/*.py"/>
+      </tarfileset>
+    </tar>
+    <gzip destfile="${dist.base.binaries}/${dist.name}-bin.tar.gz"
+      src="${dist.base.binaries}/${dist.name}-bin.tar"/>
+    <bzip2 destfile="${dist.base.binaries}/${dist.name}-bin.tar.bz2"
+      src="${dist.base.binaries}/${dist.name}-bin.tar"/>
+    <delete file="${dist.base.binaries}/${dist.name}-bin.tar"/>
+
+    <copy todir="${java-repository.jars.dir}">
+      <fileset dir="${dist.name}/lib">
+        <include name="ant*.jar"/>
+      </fileset>
+      <mapper type="glob" from="*.jar" to="*-${project.version}.jar"/>
+    </copy>
+    <copy todir="${java-repository.poms.dir}">
+      <fileset dir="${dist.name}/lib">
+        <include name="*.pom"/>
+        <include name="*.sha1"/>
+        <include name="*.md5"/>
+      </fileset>
+      <mapper>
+        <mapper type="glob" from="*.pom" to="*.pom"/>
+        <mapper type="glob" from="*.pom.sha1" to="*.pom.sha1"/>
+        <mapper type="glob" from="*.pom.md5" to="*.pom.md5"/>
+      </mapper>
+    </copy>
+    <checksum fileext=".md5">
+      <fileset dir="${java-repository.jars.dir}" includes="*${project.version}.jar"/>
+    </checksum>
+    <checksum fileext=".sha1" algorithm="SHA">
+      <fileset dir="${java-repository.jars.dir}" includes="*${project.version}.jar"/>
+    </checksum>
+    <delete dir="${dist.name}"/>
+    <checksum fileext=".md5">
+      <fileset dir="${dist.base.binaries}/">
+        <include name="**/*"/>
+        <exclude name="**/*.asc"/>
+        <exclude name="**/*.md5"/>
+      </fileset>
+    </checksum>
+    <checksum fileext=".sha1" algorithm="SHA">
+      <fileset dir="${dist.base.binaries}/">
+        <include name="**/*"/>
+        <exclude name="**/*.asc"/>
+        <exclude name="**/*.md5"/>
+      </fileset>
+    </checksum>
+
+    <antcall inheritAll="false" target="src-dist">
+      <param name="src.dist.dir" value="${dist.name}"/>
+    </antcall>
+    <zip destfile="${dist.base.source}/${dist.name}-src.zip">
+      <zipfileset dir="${dist.name}/.." filemode="755">
+        <include name="${dist.name}/bootstrap.sh"/>
+        <include name="${dist.name}/build.sh"/>
+      </zipfileset>
+      <fileset dir="${dist.name}/..">
+        <include name="${dist.name}/**"/>
+        <exclude name="${dist.name}/bootstrap.sh"/>
+        <exclude name="${dist.name}/build.sh"/>
+      </fileset>
+    </zip>
+    <tar longfile="gnu"
+      destfile="${dist.base.source}/${dist.name}-src.tar">
+      <!--
+      <zipfileset src="${dist.base.source}/${dist.name}-src.zip"/>
+      -->
+      <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant">
+        <include name="${dist.name}/bootstrap.sh"/>
+        <include name="${dist.name}/build.sh"/>
+      </tarfileset>
+      <tarfileset dir="${dist.name}/.." username="ant" group="ant">
+        <include name="${dist.name}/**"/>
+        <exclude name="${dist.name}/bootstrap.sh"/>
+        <exclude name="${dist.name}/build.sh"/>
+      </tarfileset>
+    </tar>
+    <gzip destfile="${dist.base.source}/${dist.name}-src.tar.gz"
+      src="${dist.base.source}/${dist.name}-src.tar"/>
+    <bzip2 destfile="${dist.base.source}/${dist.name}-src.tar.bz2"
+      src="${dist.base.source}/${dist.name}-src.tar"/>
+    <delete file="${dist.base.source}/${dist.name}-src.tar"/>
+    <delete dir="${dist.name}"/>
+    <checksum fileext=".md5">
+      <fileset dir="${dist.base.source}/">
+        <include name="**/*"/>
+        <exclude name="**/*.asc"/>
+        <exclude name="**/*.md5"/>
+      </fileset>
+    </checksum>
+    <checksum fileext=".sha1" algorithm="SHA">
+      <fileset dir="${dist.base.source}/">
+        <include name="**/*"/>
+        <exclude name="**/*.asc"/>
+        <exclude name="**/*.md5"/>
+      </fileset>
+    </checksum>
+  </target>
+
+  <target name="distribution" depends="main_distribution"
+    description="--> creates the full Apache Ant distribution">
+  </target>
+
+  <!--
+       ===================================================================
+         Upload the distribution to cvs.apache.org for final releases
+       ===================================================================
+  -->
+
+  <target name="init-upload" >
+    <fail unless="apache.user" message="set a property apache.user with your apache user"/>
+    <fail unless="ssh.passphrase" message="set a property with your ssh passphrase"/>
+    <fail unless="ssh.keyfile" message="set a property with your ssh keyfile"/>
+    <property name="ssh.knownhosts" location="${user.home}/.ssh/known_hosts" />
+    <property name="ssh.host" value="cvs.apache.org"/>
+    <property name="ssh.verbose" value="false"/>
+    <property name="ssh.base.directory" value="/www/www.apache.org/dist"/>
+    <property name="ssh.dist.directory" value="${ssh.base.directory}/ant"/>
+    <property name="ssh.java-repository.directory" value="/www/people.apache.org/repo/m1-ibiblio-rsync-repository/ant"/>
+    <echo >
+      Uploading Ant version ${project.version}
+      to host ${ssh.host} as ${apache.user}
+      distribution to ${ssh.dist.directory}
+      JAR files to ${ssh.java-repository.directory}/jars
+      POM files to ${ssh.java-repository.directory}/poms
+      Known hosts = ${ssh.knownhosts}
+    </echo>
+  </target>
+
+  <!-- create the directories if absent-->
+  <target name="ssh-mkdirs"
+    depends="init-upload">
+    <sshexec username="${apache.user}" host="${ssh.host}"
+      keyfile="${ssh.keyfile}" passphrase="${ssh.passphrase}"
+      knownhosts="${ssh.knownhosts}"
+      command="mkdir -p ${ssh.dist.directory}" />
+    <sshexec username="${apache.user}" host="${ssh.host}"
+      keyfile="${ssh.keyfile}" passphrase="${ssh.passphrase}"
+      knownhosts="${ssh.knownhosts}"
+      command="mkdir -p ${ssh.java-repository.directory}/jars"/>
+    <sshexec username="${apache.user}" host="${ssh.host}"
+      keyfile="${ssh.keyfile}" passphrase="${ssh.passphrase}"
+      knownhosts="${ssh.knownhosts}"
+      command="mkdir -p ${ssh.java-repository.directory}/poms"/>
+  </target>
+
+  <target name="upload" description="--> uploads the distribution"
+      depends="init-upload,ssh-mkdirs">
+    <scp todir="${apache.user}@${ssh.host}:${ssh.dist.directory}"
+      keyfile="${ssh.keyfile}" passphrase="${ssh.passphrase}"
+      knownhosts="${ssh.knownhosts}"
+      verbose="${ssh.verbose}" >
+      <fileset dir="${dist.base}">
+        <include name="**/*${project.version}*"/>
+      </fileset>
+     </scp>
+    <scp todir="${apache.user}@${ssh.host}:${ssh.java-repository.directory}"
+      keyfile="${ssh.keyfile}" passphrase="${ssh.passphrase}"
+      knownhosts="${ssh.knownhosts}"
+      verbose="${ssh.verbose}">
+      <fileset dir="java-repository/ant">
+        <include name="*/*${project.version}*"/>
+      </fileset>
+     </scp>
+  </target>
+
+  <!--
+       ===================================================================
+         Cleans up build and distribution directories
+       ===================================================================
+  -->
+  <target name="clean"
+    description="--> cleans up build and dist directories">
+    <delete dir="${build.dir}"/>
+    <delete dir="${dist.base}"/>
+    <delete dir="${dist.dir}"/>
+    <delete>
+      <fileset dir="." includes="**/*~" defaultexcludes="no"/>
+    </delete>
+  </target>
+
+  <!--
+       ===================================================================
+         Cleans everything
+       ===================================================================
+  -->
+  <target name="allclean"
+    depends="clean"
+    description="--> cleans up everything">
+    <delete file="${bootstrap.dir}/bin/antRun"/>
+    <delete file="${bootstrap.dir}/bin/antRun.bat"/>
+    <delete file="${bootstrap.dir}/bin/*.pl"/>
+    <delete file="${bootstrap.dir}/bin/*.py"/>
+  </target>
+
+  <!--
+       ===================================================================
+         Installs Apache Ant
+       ===================================================================
+  -->
+  <target name="install">
+    <fail message="You must set the property ant.install=/where/to/install" unless="ant.install"/>
+    <antcall inheritAll="false" target="internal_dist">
+      <param name="dist.dir" value="${ant.install}"/>
+    </antcall>
+  </target>
+
+  <target name="install-lite">
+    <fail message="You must set the property ant.install=/where/to/install" unless="ant.install"/>
+    <antcall inheritAll="false" target="dist-lite">
+      <param name="dist.dir" value="${ant.install}"/>
+    </antcall>
+  </target>
+
+  <!--
+       ===================================================================
+         Creates the API documentation
+       ===================================================================
+  -->
+  <target name="javadoc_check">
+    <uptodate property="javadoc.notrequired"
+      targetfile="${build.javadocs}/packages.html">
+      <srcfiles dir="${java.dir}" includes="**/*.java"/>
+    </uptodate>
+    <uptodate property="tests.javadoc.notrequired"
+      targetfile="${build.tests.javadocs}/packages.html">
+      <srcfiles dir="${src.junit}">
+        <patternset refid="useful.tests"/>
+      </srcfiles>
+    </uptodate>
+  </target>
+
+  <target name="javadocs" depends="prepare, javadoc_check"
+    unless="javadoc.notrequired"
+    description="--> creates the API documentation">
+    <mkdir dir="${build.javadocs}"/>
+    <javadoc useexternalfile="yes"
+      destdir="${build.javadocs}"
+      author="true"
+      version="true"
+      locale="en"
+      windowtitle="${Name} API"
+      doctitle="${Name}"
+      verbose="${javadoc.verbose}">
+
+      <packageset dir="${java.dir}"/>
+
+      <!-- hide some meta information for javadoc -->
+      <tag name="todo" description="To do:" scope="all"/>
+      <tag name="ant.task" enabled="false" description="Task:" scope="types"/>
+      <tag name="ant.datatype" enabled="false" description="Data type:" scope="types"/>
+      <tag name="ant.attribute" enabled="false" description="Attribute:" scope="types"/>
+      <tag name="ant.attribute.group" enabled="false" description="Attribute group:" scope="types"/>
+      <tag name="ant.element" enabled="false" description="Nested element:" scope="types"/>
+      <group title="Apache Ant Core" packages="org.apache.tools.ant*"/>
+      <group title="Core Tasks" packages="org.apache.tools.ant.taskdefs*"/>
+      <group title="Core Types" packages="org.apache.tools.ant.types*"/>
+      <group title="Optional Tasks" packages="org.apache.tools.ant.taskdefs.optional*"/>
+      <group title="Optional Types" packages="org.apache.tools.ant.types.optional*"/>
+      <group title="Ant Utilities" packages="org.apache.tools.ant.util*"/>
+
+    </javadoc>
+  </target>
+
+  <target name="test-javadocs" depends="prepare, javadoc_check"
+    unless="tests.javadoc.notrequired"
+    description="--> creates the API documentation for test utilities">
+    <mkdir dir="${build.tests.javadocs}"/>
+    <javadoc useexternalfile="yes"
+      destdir="${build.tests.javadocs}"
+      author="true"
+      version="true"
+      locale="en"
+      windowtitle="${Name} Test Utilities"
+      doctitle="${Name}">
+
+      <!-- hide some meta information for javadoc -->
+      <tag name="pre" description="Precondition:" scope="all"/>
+
+      <fileset dir="${src.junit}">
+        <patternset refid="useful.tests"/>
+      </fileset>
+
+    </javadoc>
+  </target>
+
+  <!--
+       ===================================================================
+         Compile testcases
+       ===================================================================
+  -->
+  <target name="compile-tests" depends="build" if="junit.present">
+    <mkdir dir="${build.tests}"/>
+
+    <javac srcdir="${src.junit}"
+      destdir="${build.tests}"
+      debug="${debug}"
+      target="${javac.target}"
+      source="${javac.source}"
+      deprecation="${deprecation}">
+      <classpath refid="tests-classpath"/>
+
+      <selector refid="conditional-patterns"/>
+    </javac>
+
+    <!-- Used by AntlibTest.testAntlibResource: -->
+    <jar jarfile="${build.tests}/org/apache/tools/ant/taskdefs/test2-antlib.jar">
+      <manifest>
+        <attribute name="Extension-name"
+          value="org.apache.tools.ant"/>
+        <attribute name="Specification-Title"
+          value="Apache Ant"/>
+        <attribute name="Specification-Version"
+          value="${manifest-version}"/>
+        <attribute name="Specification-Vendor"
+          value="Apache Software Foundation"/>
+        <attribute name="Implementation-Title"
+          value="org.apache.tools.ant"/>
+        <attribute name="Implementation-Version"
+          value="${manifest-version}"/>
+        <attribute name="Implementation-Vendor"
+          value="Apache Software Foundation"/>
+      </manifest>
+      <zipfileset dir="${tests.etc.dir}" fullpath="taskdefs/test.antlib.xml">
+        <include name="taskdefs/test2.antlib.xml"/>
+      </zipfileset>
+    </jar>
+  </target>
+
+  <target name="dump-info" depends="dump-sys-properties,run-which"/>
+
+  <target name="dump-sys-properties" unless="which.present"
+    depends="xml-check">
+    <echo message="java.vm.info=${java.vm.info}"/>
+    <echo message="java.vm.name=${java.vm.name}"/>
+    <echo message="java.vm.vendor=${java.vm.vendor}"/>
+    <echo message="java.vm.version=${java.vm.version}"/>
+    <echo message="os.arch=${os.arch}"/>
+    <echo message="os.name=${os.name}"/>
+    <echo message="os.version=${os.version}"/>
+    <echo message="file.encoding=${file.encoding}"/>
+    <echo message="user.language=${user.language}"/>
+  	<echo message="ant.version=${ant.version}"/>
+  </target>
+
+  <!-- helper class from Xalan2 to check for jar versioning of xml/xsl processors -->
+  <target name="xml-check" depends="check_for_optional_packages"
+    if="xalan.envcheck" unless="which.present">
+    <java classname="org.apache.xalan.xslt.EnvironmentCheck"/>
+  </target>
+
+  <target name="run-which" depends="check_for_optional_packages"
+    if="which.present">
+    <java classname="org.apache.env.Which" taskname="which"/>
+  </target>
+
+  <!-- test to see if we are online or not. can take a while when we are off line, so
+    setting the property is a good shortcut-->
+  <target name="probe-offline">
+    <condition property="offline">
+      <or>
+        <isset property="offline"/>
+        <not>
+          <http url="http://www.apache.org/"/>
+        </not>
+      </or>
+    </condition>
+    <echo level="verbose"> offline=${offline}</echo>
+  </target>
+
+  <!--
+       ===================================================================
+         Run testcase
+       ===================================================================
+  -->
+
+  <target name="check-failed">
+    <condition property="tests.failed">
+      <or>
+        <isset property="junit.failed" />
+        <isset property="antunit.failed" />
+      </or>
+    </condition>
+  </target>
+
+  <target name="test" description="--> run unit tests and reports"
+          depends="dump-info,junit-report,antunit-report,check-failed">
+    <fail if="tests.failed" unless="ignore.tests.failed">Unit tests failed;
+see ${build.junit.reports} / ${antunit.reports}
+    </fail>
+  </target>
+
+  <target name="run-tests" depends="dump-info,junit-tests,antunit-tests,check-failed"
+          description="--> run unit tests without reports">
+    <fail if="tests.failed" message="Unit tests failed" />
+  </target>
+
+  <target name="test-init" depends="probe-offline,check_for_optional_packages">
+    <macrodef name="test-junit">
+      <element name="junit-nested" implicit="true" />
+      <sequential>
+        <!-- Delete 'old' collector classes -->
+        <delete failonerror="false">
+          <fileset dir="${junit.collector.dir}" includes="${junit.collector.class}*.class"/>
+        </delete>
+        <!-- compile the FailedTests class if present -->
+        <mkdir dir="${junit.collector.dir}"/>
+        <javac srcdir="${junit.collector.dir}" destdir="${junit.collector.dir}">
+          <classpath id="failure.cp">
+            <pathelement location="${build.classes}"/>
+            <pathelement location="${build.tests}"/>
+          </classpath>
+        </javac>
+        <available file="${junit.collector.dir}/${junit.collector.class}.class"
+                   property="hasFailingTests"/>
+        <!-- run the tests -->
+        <mkdir dir="${build.junit.xml}" />
+        <property name="test.junit.vmargs" value=""/>
+        <property name="ant.junit.failureCollector"
+                  value="${junit.collector.dir}/${junit.collector.class}"/>
+        <junit printsummary="${junit.summary}"
+               haltonfailure="${test.haltonfailure}"
+               fork="${junit.fork}"
+               forkmode="${junit.forkmode}"
+               failureproperty="junit.failed"
+               errorproperty="junit.failed"
+               filtertrace="${junit.filtertrace}">
+          <sysproperty key="ant.home" value="${ant.home}"/>
+          <sysproperty key="build.tests" file="${build.tests}"/>
+          <sysproperty key="build.tests.value" value="${build.tests.value}"/>
+          <sysproperty key="offline" value="${offline}"/>
+          <sysproperty key="tests-classpath.value"
+                       value="${tests-classpath.value}"/>
+          <sysproperty key="root" file="${basedir}"/>
+          <sysproperty key="build.compiler" value="${build.compiler}"/>
+          <sysproperty key="tests.and.ant.share.classloader"
+                       value="${tests.and.ant.share.classloader}"/>
+          <classpath>
+            <path refid="tests-classpath"/>
+            <pathelement location="${junit.collector.dir}"/>
+            <path refid="failure.cp"/>
+          </classpath>
+          <formatter type="failure" usefile="false"/>
+          <formatter type="xml"/>
+          <jvmarg line="${test.junit.vmargs}"/>
+          <test name="${junit.collector.class}" if="hasFailingTests"/>
+          
+          <junit-nested />
+        </junit>
+      </sequential>
+    </macrodef>
+
+    <fail>"testcase" cannot be specified with "junit.testcase" or "antunit.testcase".
+      <condition>
+        <and>
+          <isset property="testcase" />
+          <or>
+            <isset property="antunit.testcase" />
+            <isset property="junit.testcase" />
+          </or>
+        </and>
+      </condition>
+    </fail>
+
+    <condition property="antunit.testcase" value="${testcase}">
+      <available file="${src.antunit}/${testcase}" />
+    </condition>
+
+    <condition property="junit.testcase" value="${testcase}">
+      <available classname="${testcase}" classpathref="tests-classpath" />
+    </condition>
+
+    <fail>Cannot locate test ${testcase}
+      <condition>
+        <and>
+          <isset property="testcase" />
+          <not>
+            <or>
+              <isset property="antunit.testcase" />
+              <isset property="junit.testcase" />
+            </or>
+          </not>
+        </and>
+      </condition>
+    </fail>
+
+    <condition property="run.junit">
+      <and>
+        <not><equals arg1="${testcase}" arg2="${antunit.testcase}" /></not>
+        <isset property="junit.present" />
+        <available file="${src.junit}" />
+      </and>
+    </condition>
+
+    <condition property="junit.single">
+      <and>
+        <isset property="junit.testcase" />
+        <isset property="run.junit" />
+      </and>
+    </condition>
+
+    <condition property="junit.batch">
+      <and>
+        <not><isset property="junit.testcase" /></not>
+        <isset property="run.junit" />
+      </and>
+    </condition>
+
+    <condition property="run.antunit">
+      <and>
+        <not><equals arg1="${testcase}" arg2="${junit.testcase}" /></not>
+        <isset property="antunit.present" />
+        <available file="${src.antunit}" />
+      </and>
+    </condition>
+
+    <condition property="run.antunit.report">
+      <and>
+        <isset property="run.antunit" />
+        <isset property="trax.impl.present" />
+      </and>
+    </condition>
+
+    <condition property="run.junit.report">
+      <and>
+        <isset property="run.junit" />
+        <isset property="trax.impl.present" />
+      </and>
+    </condition>
+  </target>
+
+  <target name="junit-report" depends="junit-tests,junit-report-only" />
+
+  <target name="junit-report-only" depends="test-init" if="run.junit.report">
+    <mkdir dir="${build.junit.reports}" />
+    <junitreport todir="${build.junit.reports}">
+      <fileset dir="${build.junit.xml}">
+        <include name="TEST-*.xml"/>
+      </fileset>
+      <report format="frames" todir="${build.junit.reports}"/>
+    </junitreport>
+  </target>
+
+  <target name="junit-tests" depends="junit-batch,junit-single-test" />
+
+  <target name="junit-batch" depends="compile-tests,test-init"
+      if="junit.batch">
+
+    <property name="junit.includes" value="**/*Test*" />
+    <property name="junit.excludes" value="" />
+
+    <test-junit>
+      <formatter type="brief" usefile="false"/>
+
+      <batchtest todir="${build.junit.xml}" unless="hasFailingTests">
+        <fileset dir="${src.junit}"
+                 includes="${junit.includes}" excludes="${junit.excludes}">
+
+          <!-- abstract classes, not testcases -->
+          <exclude name="${taskdefs.package}/TaskdefsTest.java"/>
+          <exclude name="${ant.package}/BuildFileTest.java"/>
+          <exclude name="${regexp.package}/RegexpMatcherTest.java"/>
+          <exclude name="${regexp.package}/RegexpTest.java"/>
+          <exclude name="${optional.package}/AbstractXSLTLiaisonTest.java"/>
+          <exclude name="${ant.package}/types/AbstractFileSetTest.java"/>
+          <exclude name="${ant.package}/types/selectors/BaseSelectorTest.java"/>
+
+          <!-- helper classes, not testcases -->
+          <exclude name="org/example/**"/>
+          <exclude name="${taskdefs.package}/TaskdefTest*Task.java"/>
+          <exclude name="${optional.package}/junit/TestFormatter.java"/>
+
+          <!-- interactive tests -->
+          <exclude name="${taskdefs.package}/TestProcess.java"/>
+          <exclude name="${optional.package}/splash/SplashScreenTest.java"/>
+
+          <!-- only run these tests if their required libraries are
+               installed -->
+          <selector refid="conditional-patterns"/>
+
+          <!-- tests excluded if the test is run in offline mode -->
+          <patternset refid="onlinetests"/>
+
+          <!-- failing tests excluded unless run.failing.tests is set -->
+          <patternset refid="teststhatfail"/>
+
+          <!-- runtime dependencies that are different from compile
+               time dependencies -->
+          <exclude name="${optional.package}/ReplaceRegExpTest.java"
+            unless="some.regexp.support"/>
+          <exclude name="${ant.package}/types/selectors/ContainsRegexpTest.java"
+            unless="some.regexp.support"/>
+          <exclude name="${ant.package}/types/mappers/RegexpPatternMapperTest.java"
+            unless="some.regexp.support"/>
+
+          <!-- needs BSF to work -->
+          <exclude name="${optional.package}/Rhino*.java"
+            unless="bsf.present"/>
+          <exclude name="${optional.package}/Rhino*.java"
+            unless="rhino.present"/>
+          <exclude name="${optional.package}/script/*.java"
+            unless="bsf.present"/>
+          <exclude name="${optional.package}/script/*.java"
+            unless="rhino.present"/>
+          <exclude name="${optional.package}/BeanShellScriptTest.java"
+            unless="bsf.present"/>
+          <exclude name="${optional.package}/BeanShellScriptTest.java"
+            unless="beanshell.present"/>
+          <exclude name="${optional.type.package}/Script*.java"
+            unless="bsf.present"/>
+          <exclude name="${optional.type.package}/Script*.java"
+            unless="rhino.present"/>
+
+          <!-- fail if testcases can be loaded from the system classloader -->
+          <exclude name="${ant.package}/AntClassLoaderDelegationTest.java"
+            if="tests.are.on.system.classpath"/>
+          <exclude name="${optional.package}/junit/JUnitClassLoaderTest.java"
+            if="tests.are.on.system.classpath"/>
+
+          <!-- these tests need to be localised before being ran???? -->
+          <exclude name="${optional.package}/PvcsTest.java"/>
+
+          <!-- These tests need a TraX implementation like xalan2 or saxon -->
+          <exclude name="${optional.package}/TraXLiaisonTest.java"
+            unless="trax.impl.present"/>
+          <exclude name="${optional.package}/XsltTest.java"
+            unless="trax.impl.present"/>
+          <exclude name="${ant.package}/types/XMLCatalogBuildFileTest.java"
+            unless="trax.impl.present"/>
+          <exclude name="${optional.package}/junit/JUnitReportTest.java"
+            unless="run.junitreport"/>
+          <exclude name="${taskdefs.package}/StyleTest.java"
+            unless="trax.impl.present"/>
+
+          <!-- needs xerces to work -->
+          <exclude name="${ant.package}/IncludeTest.java"
+            unless="xerces1.present"/>
+          <exclude name="${type.package}/selectors/ModifiedSelectorTest.java"
+            unless="xerces1.present"/>
+
+          <!-- needs resolver.jar to work -->
+          <exclude name="${optional.package}/XmlValidateCatalogTest.java"
+            unless="apache.resolver.present"/>
+
+          <!-- needs jasperc -->
+          <exclude name="${optional.package}/JspcTest.java"
+            unless="jasper.present"/>
+
+          <!-- misc oneoff tests -->
+          <exclude name="${optional.package}/WsdlToDotnetTest.java"
+            unless="dotnetapps.found"/>
+          <exclude name="${optional.package}/DotnetTest.java"
+            unless="dotnetapps.found"/>
+
+          <!--  These tests only passes if testcases and Ant classes have
+          been loaded by the same classloader - will throw
+          IllegalAccessExceptions otherwise.  -->
+          <exclude name="${taskdefs.package}/SQLExecTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${taskdefs.package}/cvslib/ChangeLogWriterTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${taskdefs.package}/cvslib/ChangeLogParserTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${optional.package}/sos/SOSTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${optional.package}/vss/MSVSSTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${optional.package}/TraXLiaisonTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${taskdefs.package}/ProcessDestroyerTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${taskdefs.package}/ProtectedJarMethodsTest.java"
+            unless="tests.and.ant.share.classloader"/>
+          <exclude name="${ant.package}/launch/LocatorTest.java"
+            unless="tests.and.ant.share.classloader"/>
+
+          <!-- can only run if cvs is installed on your machine
+               enable by setting the property have.cvs
+          -->
+          <exclude name="${taskdefs.package}/AbstractCvsTaskTest.java"
+            unless="have.cvs"/>
+
+          <!-- needs a local ftp server and the entry of a user/password combination -->
+          <exclude name="${optional.package}/net/FTPTest.java"/>
+
+          <!-- test needs special setup -->
+          <exclude name="${optional.package}/ssh/ScpTest.java"/>
+
+          <!-- test fails if build/classes and ant.jar are using the same
+               classloader  -->
+          <exclude name="${ant.package}/util/ClasspathUtilsTest.java"
+            if="tests.and.ant.share.classloader"/>
+        </fileset>
+      </batchtest>
+    </test-junit>
+  </target>
+
+  <target name="junit-single-test" depends="compile-tests,junit-single-test-only"
+    description="--> runs the single unit test at $${junit.testcase}" />
+
+  <target name="junit-single-test-only" depends="test-init" if="junit.single"
+    description="--> runs the single unit test at $${junit.testcase} (no compile)">
+    <test-junit>
+      <formatter type="plain" usefile="false"/>
+      <test name="${junit.testcase}" todir="${build.junit.xml}"/>
+    </test-junit>
+  </target>
+
+  <target name="interactive-tests" description="--> runs interactive tests"
+    depends="compile-tests"
+    if="jdk1.3+">
+    <java classpathref="tests-classpath"
+      classname="org.apache.tools.ant.taskdefs.TestProcess"
+      fork="true"/>
+  </target>
+
+  <target name="antunit-tests" depends="dump-info,build,test-init"
+          if="run.antunit" description="--> run the antunit tests">
+
+    <condition property="antunit.includes" value="${antunit.testcase}"
+               else="**/test.xml,**/*-test.xml">
+      <isset property="antunit.testcase" />
+    </condition>
+
+    <property name="antunit.excludes" value="" />
+
+    <mkdir dir="${antunit.xml}" />
+    <au:antunit xmlns:au="antlib:org.apache.ant.antunit"
+                failonerror="false" errorproperty="antunit.failed">
+      <fileset dir="${src.antunit}" includes="${antunit.includes}"
+               excludes="${antunit.excludes}" />
+      <au:plainlistener />
+      <au:xmllistener todir="${antunit.xml}" />
+    </au:antunit>
+  </target>
+
+  <target name="antunit-report" depends="antunit-tests,antunit-report-only" />
+
+  <target name="antunit-report-only" depends="test-init" if="run.antunit.report">
+    <length>
+      <fileset dir="${antunit.xml}" includes="TEST-*.xml" />
+    </length>
+    <mkdir dir="${antunit.reports}" />
+    <junitreport todir="${antunit.reports}">
+      <fileset dir="${antunit.xml}" includes="TEST-*.xml" />
+      <report styledir="${src.antunit}" format="frames"
+              todir="${antunit.reports}"/>
+    </junitreport>
+    <length>
+      <fileset dir="${antunit.xml}" includes="TEST-*.xml" />
+    </length>
+  </target>
+
+  <!--
+       ===================================================================
+         Main target - runs dist-lite by default
+       ===================================================================
+  -->
+  <target name="main"
+    description="--> creates a minimum distribution in ./dist"
+    depends="dist-lite"/>
+
+
+  <!--
+       ===================================================================
+         MSI target - creates an MSI installer file with the help of
+                      the WiX toolset and the dotnet Antlib.
+       ===================================================================
+  -->
+  <target name="msi"
+    description="--> creates an MSI file for Ant, requires WiX and the dotnet Antlib"
+    depends="internal_dist"
+    xmlns:dn="antlib:org.apache.ant.dotnet">
+
+    <property name="msi.dir" value="${build.dir}"/>
+    <property name="msi.name" value="${name}-${project.version}.msi"/>
+    <property name="msi.file" value="${msi.dir}/${msi.name}"/>
+    <property name="wix.home" value="${user.home}/wix"/>
+    <property name="wixobj.dir" value="${build.dir}/wix"/>
+
+    <property name="dist.dir.resolved" location="${dist.dir}"/>
+
+    <mkdir dir="${wixobj.dir}"/>
+
+    <dn:wix target="${msi.file}"
+      mode="both" wixHome="${wix.home}" wixobjDestDir="${wixobj.dir}">
+      <sources dir="${etc.dir}" includes="*.wxs"/>
+      <moresources dir="${dist.dir}"/>
+
+      <candleParameter name="dist.dir" value="${dist.dir.resolved}"/>
+      <candleParameter name="version" value="${manifest-version}"/>
+    </dn:wix>
+  </target>
+
+</project>
diff --git a/trunk/check.xml b/trunk/check.xml
new file mode 100755
index 0000000..67ff9f1
--- /dev/null
+++ b/trunk/check.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="checkstyle" name="CheckAnt">
+
+  <description>
+    Check Ants codebase against certain code styleguide rules using
+    checkstyle and simian.
+
+    Checkstyle uses an abstract syntax tree (AST) for doing checks
+    against java sources. It is available at http://checkstyle.sourceforge.net/
+    under GPL 2.1 license.
+
+    "Simian (Similarity Analyser) identifies duplication in Java, C#, C,
+    CPP, COBOL, JSP, HTML source code and even plain text files."
+    It is available at http://www.redhillconsulting.com.au/products/simian/
+    and is for free use in open source projects.
+
+    See external task page and homepages for more information.
+  </description>
+
+  <import file="build.xml"/>
+  <property name="config.dir" location="${etc.dir}/checkstyle"/>
+
+  <property name="checkstyle.reportdir" location="${build.dir}/reports/checkstyle"/>
+  <property name="checkstyle.raw" location="${checkstyle.reportdir}/raw.xml"/>
+  <property name="stylesheet.html" location="${config.dir}/checkstyle-frames.xsl"/>
+  <property name="stylesheet.text" location="${config.dir}/checkstyle-text.xsl"/>
+  <property name="stylesheet.xdoc" location="${config.dir}/checkstyle-xdoc.xsl"/>
+
+  <property name="checkstyle.basedir" location="${java.dir}"/>
+
+  <!-- Ant Checkstyle report -->
+  <property name="tocheck" value="**/*.java"/>
+  <property name="javadoc.scope" value="public"/>
+
+  <taskdef resource="simiantask.properties"/>
+  <taskdef resource="checkstyletask.properties"/>
+
+  <target name="checkstyle" description="--> checks Ant codebase according to ${config.dir}/checkstyle-config">
+    <mkdir dir="${checkstyle.reportdir}"/>
+    <checkstyle config="${config.dir}/checkstyle-config" failOnViolation="false">
+      <formatter type="xml" toFile="${checkstyle.raw}"/>
+      <fileset dir="${java.dir}">
+        <include name="${tocheck}"/>
+        <exclude name="**/bzip2/*.java"/>
+        <exclude name="**/CVSPass.java"/>
+      </fileset>
+    </checkstyle>
+  </target>
+
+  <target name="htmlreport" description="--> generates a html checkstyle report">
+    <mkdir dir="${checkstyle.reportdir}"/>
+    <xslt in="${checkstyle.raw}" style="${stylesheet.html}"
+           out="${checkstyle.reportdir}/html/output.txt">
+      <param name="basedir" expression="${checkstyle.basedir}"/>
+    </xslt>
+  </target>
+
+  <target name="textreport" description="--> generates a text checkstyle report">
+    <xslt in="${checkstyle.raw}" style="${stylesheet.text}"
+           out="${checkstyle.reportdir}/report.txt">
+    </xslt>
+  </target>
+
+  <target name="textreport-display" depends="textreport" description="--> generates a text checkstyle report and displays it immediately">
+      <loadfile property="report" srcfile="${checkstyle.reportdir}/report.txt"/>
+      <echo>${report}</echo>
+  </target>
+
+  <target name="xdocreport" description="--> generates a xdoc checkstyle report">
+    <xslt in="${checkstyle.raw}" style="${stylesheet.xdoc}"
+           out="${checkstyle.reportdir}/xdocs/index.xml">
+      <param name="basedir" expression="${checkstyle.basedir}"/>
+    </xslt>
+  </target>
+
+  <target name="dumphtml" depends="checkstyle, htmlreport" description="--> runs the checkstyle and generates a html report"/>
+  <target name="dumptext" depends="checkstyle, textreport" description="--> runs the checkstyle and displays result as text">
+    <concat>
+      <filelist dir="${checkstyle.reportdir}" files="report.txt"/>
+    </concat>
+  </target>
+
+  <target name="simiancheck" description="--> runs the check for duplicates">
+    <simian>
+        <fileset dir="${java.dir}" />
+    </simian>
+  </target>
+	
+  <target name="fixTS" description="--> fix checkstyle errors 'Line has trailing spaces'">
+    <fail message="Define path to java file 'path'">
+      <condition><not><isset property="path"/></not></condition>
+    </fail>
+    <replaceregexp match="\s+$" replace="" flags="g" byline="true">
+      <fileset dir="src/main" includes="${path}"/>
+    </replaceregexp>
+  </target>
+
+  <target name="fixTab" description="--> fix checkstyle errors 'Line contains TAB sign'">
+    <fail message="Define path to java file 'path'">
+      <condition><not><isset property="path"/></not></condition>
+    </fail>
+  	<fixcrlf srcdir="src/main" includes="${path}" javafiles="yes" tab="remove" tablength="4"/>
+  </target>	
+	
+</project>
\ No newline at end of file
diff --git a/trunk/contributors.xml b/trunk/contributors.xml
new file mode 100644
index 0000000..7459e64
--- /dev/null
+++ b/trunk/contributors.xml
@@ -0,0 +1,1157 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE contributors
+[
+<!ELEMENT name (first?, middle?, last)>
+<!ELEMENT contributors (introduction, name+)>
+<!ELEMENT first (#PCDATA)>
+<!ELEMENT introduction (#PCDATA)>
+<!ELEMENT middle (#PCDATA)>
+<!ELEMENT last (#PCDATA)>
+]
+>
+
+<contributors>
+  <introduction>
+  These are some of the many people who have helped Ant become so successful.
+  </introduction>
+  <name>
+    <first>Aleksandr</first>
+    <last>Ishutin</last>
+  </name>
+  <name>
+    <first>Alexey</first>
+    <last>Panchenko</last>
+  </name>
+  <name>
+    <first>Alexey</first>
+    <last>Solofnenko</last>
+  </name>
+  <name>
+    <first>Andreas</first>
+    <last>Ames</last>
+  </name>
+  <name>
+    <first>Andrew</first>
+    <last>Everitt</last>
+  </name>
+  <name>
+    <first>Andrey</first>
+    <last>Urazov</last>
+  </name>
+  <name>
+    <first>Andy</first>
+    <last>Wood</last>
+  </name>
+  <name>
+    <first>Anil</first>
+    <middle>K.</middle>
+    <last>Vijendran</last>
+  </name>
+  <name>
+    <first>Anli</first>
+    <last>Shundi</last>
+  </name>
+  <name>
+    <first>Anthony</first>
+    <last>Green</last>
+  </name>
+  <name>
+    <first>Antoine</first>
+    <last>Baudoux</last>
+  </name>
+  <name>
+    <first>Antoine</first>
+    <last>Levy-Lambert</last>
+  </name>
+  <name>
+    <first>Anton</first>
+    <last>Mazkovoi</last>
+  </name>
+  <name>
+    <first>Arnaud</first>
+    <last>Vandyck</last>
+  </name>
+  <name>
+    <first>Arnout</first>
+    <middle>J.</middle>
+    <last>Kuiper</last>
+  </name>
+  <name>
+    <first>Aslak</first>
+    <last>Helles&#244;y</last>
+  </name>
+  <name>
+    <first>Atsuhiko</first>
+    <last>Yamanaka</last>
+  </name>
+  <name>
+    <first>Avik</first>
+    <last>Sengupta</last>
+  </name>
+  <name>
+    <first>Balazs</first>
+    <last>Fejes 2</last>
+  </name>
+  <name>
+    <first>Benjamin</first>
+    <last>Burgess</last>
+  </name>
+  <name>
+    <first>Ben</first>
+    <last>Galbraith</last>
+  </name>
+  <name>
+    <first>Benoit</first>
+    <last>Moussaud</last>
+  </name>
+  <name>
+    <first>Bernd</first>
+    <last>Dutkowski</last>
+  </name>
+  <name>
+    <first>Brad</first>
+    <last>Clark</last>
+  </name>
+  <name>
+    <first>Brant</first>
+    <middle>Langer</middle>
+    <last>Gurganus</last>
+  </name>
+  <name>
+    <first>Brian</first>
+    <last>Deitte</last>
+  </name>
+  <name>
+    <first>Brian</first>
+    <last>Felder</last>
+  </name>
+  <name>
+    <first>Bruce</first>
+    <last>Atherton</last>
+  </name>
+  <name>
+    <first>Charles</first>
+    <last>Hudak</last>
+  </name>
+  <name>
+    <first>Charlie</first>
+    <last>Hubbard</last>
+  </name>
+  <name>
+    <first>Chris</first>
+    <last>Povirk</last>
+  </name>
+  <name>
+    <first>Christian</first>
+    <last>Knorr</last>
+  </name>
+  <name>
+    <first>Christoph</first>
+    <last>Wilhelms</last>
+  </name>
+  <name>
+    <first>Christophe</first>
+    <last>Labouisse</last>
+  </name>
+  <name>
+    <first>Christopher</first>
+    <middle>A.</middle>
+    <last>Longo</last>
+  </name>
+  <name>
+    <first>Christopher</first>
+    <last>Charlier</last>
+  </name>
+  <name>
+    <first>Conor</first>
+    <last>MacNeill</last>
+  </name>
+  <name>
+    <first>Craeg</first>
+    <last>Strong</last>
+  </name>
+  <name>
+    <first>Craig</first>
+    <last>Cottingham</last>
+  </name>
+  <name>
+    <first>Craig</first>
+    <middle>R.</middle>
+    <last>McClanahan</last>
+  </name>
+  <name>
+    <first>Craig</first>
+    <last>Ryan</last>
+  </name>
+  <name>
+    <first>Curtis</first>
+    <last>White</last>
+  </name>
+  <name>
+    <first>Cyrille</first>
+    <last>Morvan</last>
+  </name>
+  <name>
+    <first>D'Arcy</first>
+    <last>Smith</last>
+  </name>
+  <name>
+    <first>Dale</first>
+    <last>Anson</last>
+  </name>
+  <name>
+    <first>Dan</first>
+    <last>Armbrust</last>
+  </name>
+  <name>
+    <first>Daniel</first>
+    <last>Ribagnac</last>
+  </name>
+  <name>
+    <first>Daniel</first>
+    <last>Spilker</last>
+  </name>
+  <name>
+    <first>Danno</first>
+    <last>Ferrin</last>
+  </name>
+  <name>
+    <first>Davanum</first>
+    <last>Srinivas</last>
+  </name>
+  <name>
+    <first>Dave</first>
+    <last>Brondsema</last>
+  </name>
+  <name>
+    <first>Dave</first>
+    <last>Brosius</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>A.</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>Crossley</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>G&#228;rtner</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>Kavanagh</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>Maclean</last>
+  </name>
+  <name>
+    <first>David</first>
+    <last>Rees</last>
+  </name>
+  <name>
+    <first>Denis</first>
+    <last>Hennessy</last>
+  </name>
+  <name>
+    <first>Derek</first>
+    <last>Slager</last>
+  </name>
+  <name>
+    <first>Diane</first>
+    <last>Holt</last>
+  </name>
+  <name>
+    <first>dIon</first>
+    <last>Gillard</last>
+  </name>
+  <name>
+    <first>Dominique</first>
+    <last>Devienne</last>
+  </name>
+  <name>
+    <first>Donal</first>
+    <last>Quinlan</last>
+  </name>
+  <name>
+    <first>Don</first>
+    <last>Bnamen</last>
+  </name>
+  <name>
+    <first>Don</first>
+    <last>Ferguson</last>
+  </name>
+  <name>
+    <first>Don</first>
+    <last>Jeffery</last>
+  </name>
+  <name>
+    <first>Drew</first>
+    <last>Sudell</last>
+  </name>
+  <name>
+    <first>Edwin</first>
+    <last>Woudt</last>
+  </name>
+  <name>
+    <first>Eli</first>
+    <last>Tucker</last>
+  </name>
+  <name>
+    <first>Emmanuel</first>
+    <last>Bourg</last>
+  </name>
+  <name>
+    <first>Eric</first>
+    <last>Olsen</last>
+  </name>
+  <name>
+    <first>Eric</first>
+    <last>Pugh</last>
+  </name>
+  <name>
+    <first>Erik</first>
+    <last>Hatcher</last>
+  </name>
+  <name>
+    <first>Erik</first>
+    <last>Langenbach</last>
+  </name>
+  <name>
+    <first>Erik</first>
+    <last>Meade</last>
+  </name>
+  <name>
+    <first>Ernst</first>
+    <last>de Haan</last>
+  </name>
+  <name>
+    <first>Frank</first>
+    <last>Harnack</last>
+  </name>
+  <name>
+    <first>Frank</first>
+    <last>Somers</last>
+  </name>
+  <name>
+    <first>Frank</first>
+    <last>Zeyda</last>
+  </name>
+  <name>
+    <first>Frédéric</first>
+    <last>Bothamy</last>
+  </name>
+  <name>
+    <first>Frederic</first>
+    <last>Lavigne</last>
+  </name>
+  <name>
+    <first>Gary</first>
+    <middle>S.</middle>
+    <last>Weaver</last>
+  </name>
+  <name>
+    <first>Gautam</first>
+    <last>Guliani</last>
+  </name>
+  <name>
+    <first>Gero</first>
+    <last>Vermaas</last>
+  </name>
+  <name>
+    <first>Gerrit</first>
+    <last>Riessen</last>
+  </name>
+  <name>
+    <first>Glenn</first>
+    <last>McAllister</last>
+  </name>
+  <name>
+    <first>Glenn</first>
+    <last>Twiggs</last>
+  </name>
+  <name>
+    <first>Greg</first>
+    <last>Nelson</last>
+  </name>
+  <name>
+    <first>Harish</first>
+    <last>Prabandham</last>
+  </name>
+  <name>
+    <first>Haroon</first>
+    <last>Rafique</last>
+  </name>
+  <name>
+    <first>Hiroaki</first>
+    <last>Nakamura</last>
+  </name>
+  <name>
+    <first>Holger</first>
+    <last>Engels</last>
+  </name>
+  <name>
+    <first>Ignacio</first>
+    <last>Coloma</last>
+  </name>
+  <name>
+    <first>Ingenonsya</first>
+    <last>France</last>
+  </name>
+  <name>
+    <first>Ingmar</first>
+    <last>Stein</last>
+  </name>
+  <name>
+    <first>Irene</first>
+    <last>Rusman</last>
+  </name>
+  <name>
+    <first>Ivan</first>
+    <last>Ivanov</last>
+  </name>
+  <name>
+    <first>Jack</first>
+    <middle>J.</middle>
+    <last>Woehr</last>
+  </name>
+  <name>
+    <first>James</first>
+    <middle>Duncan</middle>
+    <last>Davidson</last>
+  </name>
+  <name>
+    <first>Jan</first>
+    <last>Mat&#232;rne</last>
+  </name>
+    <name>
+      <first>Jan</first>
+      <last>Cumps</last>
+    </name>
+  <name>
+    <first>Jan</first>
+    <last>Mynarik</last>
+  </name>
+  <name>
+    <first>Jason</first>
+    <last>Hunter</last>
+  </name>
+  <name>
+    <first>Jason</first>
+    <last>Pettiss</last>
+  </name>
+  <name>
+    <first>Jason</first>
+    <last>Salter</last>
+  </name>
+  <name>
+    <first>Jason</first>
+    <last>Yip</last>
+  </name>
+  <name>
+    <first>Jay</first>
+    <middle>Dickon</middle>
+    <last>Glanville</last>
+  </name>
+  <name>
+    <first>Jay</first>
+    <last>Peck</last>
+  </name>
+  <name>
+    <first>Jay</first>
+    <last>van der Meer</last>
+  </name>
+  <name>
+    <first>JC</first>
+    <last>Mann</last>
+  </name>
+  <name>
+    <first>J</first>
+    <last>D</last>
+  </name>
+  <name>
+    <first>Jean-Francois</first>
+    <last>Brousseau</last>
+  </name>
+  <name>
+    <first>Jeff</first>
+    <last>Gettle</last>
+  </name>
+  <name>
+    <first>Jeff</first>
+    <last>Martin</last>
+  </name>
+  <name>
+    <first>Jeff</first>
+    <last>Tulley</last>
+  </name>
+  <name>
+    <first>Jeff</first>
+    <last>Turner</last>
+  </name>
+  <name>
+    <first>Jene</first>
+    <last>Jasper</last>
+  </name>
+  <name>
+    <first>Jeremy</first>
+    <last>Mawson</last>
+  </name>
+  <name>
+    <first>Jerome</first>
+    <last>Lacoste</last>
+  </name>
+  <name>
+    <first>Jesse</first>
+    <last>Glick</last>
+  </name>
+  <name>
+    <first>Jesse</first>
+    <last>Stockall</last>
+  </name>
+  <name>
+    <first>Jim</first>
+    <last>Allers</last>
+  </name>
+  <name>
+    <first>Joerg</first>
+    <last>Wassmer</last>
+  </name>
+  <name>
+    <first>Jon</first>
+    <last>Dickinson</last>
+  </name>
+  <name>
+    <first>Jon</first>
+    <middle>S.</middle>
+    <last>Stevens</last>
+  </name>
+  <name>
+    <first>Jose</first>
+    <middle>Alberto</middle>
+    <last>Fernandez</last>
+  </name>
+  <name>
+    <first>Josh</first>
+    <last>Lucas</last>
+  </name>
+  <name>
+    <first>Joseph</first>
+    <last>Walton</last>
+  </name>
+  <name>
+    <first>Juerg</first>
+    <last>Wanner</last>
+  </name>
+  <name>
+    <first>Julian</first>
+    <last>Simpson</last>
+  </name>
+  <name>
+    <first>Justin</first>
+    <last>Vallon</last>
+  </name>
+  <name>
+    <first>Keiron</first>
+    <last>Liddle</last>
+  </name>
+  <name>
+    <first>Keith</first>
+    <last>Visco</last>
+  </name>
+  <name>
+    <first>Kevin</first>
+    <last>Greiner</last>
+  </name>
+  <name>
+    <first>Kevin</first>
+    <last>Jackson</last>
+  </name>
+  <name>
+    <first>Kevin</first>
+    <last>Ross</last>
+  </name>
+  <name>
+    <first>Kevin</first>
+    <middle>Z</middle>
+    <last>Grey</last>
+  </name>
+  <name>
+    <first>Kirk</first>
+    <last>Wylie</last>
+  </name>
+  <name>
+    <first>Kyle</first>
+    <last>Adams</last>
+  </name>
+  <name>
+    <first>Larry</first>
+    <last>Shatzer</last>
+  </name>
+  <name>
+    <first>Larry</first>
+    <last>Streepy</last>
+  </name>
+  <name>
+    <first>Les</first>
+    <last>Hughes</last>
+  </name>
+  <name>
+    <first>Levi</first>
+    <last>Cook</last>
+  </name>
+  <name>
+    <last>lucas</last>
+  </name>
+  <name>
+    <first>Ludovic</first>
+    <last>Claude</last>
+  </name>
+  <name>
+    <first>Magesh</first>
+    <last>Umasankar</last>
+  </name>
+  <name>
+    <first>Maneesh</first>
+    <last>Sahu</last>
+  </name>
+  <name>
+    <first>Marcel</first>
+    <last>Schutte</last>
+  </name>
+  <name>
+    <first>Marcus</first>
+    <last>B&amp;ouml;rger</last>
+  </name>
+  <name>
+    <first>Mariusz</first>
+    <last>Nowostawski</last>
+  </name>
+  <name>
+    <first>Mark</first>
+    <last>Hecker</last>
+  </name>
+  <name>
+    <first>Mark</first>
+    <middle>R.</middle>
+    <last>Diggory</last>
+  </name>
+  <name>
+    <first>Martijn</first>
+    <last>Kruithof</last>
+  </name>
+  <name>
+    <first>Martin</first>
+    <last>Landers</last>
+  </name>
+  <name>
+    <first>Martin</first>
+    <last>Poeschl</last>
+  </name>
+  <name>
+    <first>Martin</first>
+    <last>van den Bemt</last>
+  </name>
+  <name>
+    <first>Mathieu</first>
+    <last>Champlon</last>
+  </name>
+  <name>
+    <first>Mathieu</first>
+    <last>Peltier</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Albrecht</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Benson</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Bishop</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Foemmel</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Grosso</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Humphrey</last>
+  </name>
+  <name>
+    <first>Matt</first>
+    <last>Small</last>
+  </name>
+  <name>
+    <first>Matthew</first>
+    <last>Hawthorne</last>
+  </name>
+  <name>
+    <first>Matthew</first>
+    <last>Inger</last>
+  </name>
+  <name>
+    <first>Matthew</first>
+    <middle>Kuperus</middle>
+    <last>Heun</last>
+  </name>
+  <name>
+    <first>Matthew</first>
+    <last>Watson</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <last>Davey</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <middle>J.</middle>
+    <last>Sikorsky</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <last>McCallum</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <last>Newcomb</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <last>Nygard</last>
+  </name>
+  <name>
+    <first>Michael</first>
+    <last>Saunders</last>
+  </name>
+  <name>
+    <last>Miha</last>
+  </name>
+  <name>
+    <first>Mike</first>
+    <last>Roberts</last>
+  </name>
+  <name>
+    <last>mnowostawski</last>
+  </name>
+  <name>
+    <first>Nick</first>
+    <last>Chalko</last>
+  </name>
+  <name>
+    <first>Nick</first>
+    <last>Crossley</last>
+  </name>
+  <name>
+    <first>Nick</first>
+    <last>Fortescue</last>
+  </name>
+  <name>
+    <first>Nick</first>
+    <last>Pellow</last>
+  </name>
+  <name>
+    <first>Nicola</first>
+    <last>Ken</last>
+  </name>
+  <name>
+    <first>Nico</first>
+    <last>Seessle</last>
+  </name>
+  <name>
+    <first>Nigel</first>
+    <last>Magnay</last>
+  </name>
+  <name>
+    <first>Oliver</first>
+    <last>Merkel</last>
+  </name>
+  <name>
+    <first>Oliver</first>
+    <last>Rossmueller</last>
+  </name>
+  <name>
+    <first>&#216;ystein</first>
+    <last>Gisn&#229;s</last>
+  </name>
+  <name>
+    <first>Patrick</first>
+    <last>C.</last>
+  </name>
+  <name>
+    <first>Patrick</first>
+    <last>Chanezon</last>
+  </name>
+  <name>
+    <first>Patrick</first>
+    <last>Gus</last>
+  </name>
+  <name>
+    <first>Paul</first>
+    <last>Austin</last>
+  </name>
+  <name>
+    <first>Paul</first>
+    <last>Christmann</last>
+  </name>
+  <name>
+    <first>Paul</first>
+    <last>Galbraith</last>
+  </name>
+  <name>
+    <first>Paul</first>
+    <last>King</last>
+  </name>
+  <name>
+    <first>Paulo</first>
+    <last>Gaspar</last>
+  </name>
+  <name>
+    <first>Peter</first>
+    <middle>B.</middle>
+    <last>West</last>
+  </name>
+  <name>
+    <first>Peter</first>
+    <last>Donald</last>
+  </name>
+  <name>
+    <first>Peter</first>
+    <last>Doornbosch</last>
+  </name>
+  <name>
+    <first>Peter</first>
+    <last>Hulst</last>
+  </name>
+  <name>
+    <first>Peter</first>
+    <last>Reilly</last>
+  </name>
+  <name>
+    <first>Phillip</first>
+    <last>Wells</last>
+  </name>
+  <name>
+    <first>Pierre</first>
+    <last>Delisle</last>
+  </name>
+  <name>
+    <first>Pierre</first>
+    <last>Dittgen</last>
+  </name>
+  <name>
+    <first>R</first>
+    <last>Handerson</last>
+  </name>
+  <name>
+    <first>Rami</first>
+    <last>Ojares</last>
+  </name>
+  <name>
+    <first>Randy</first>
+    <last>Watler</last>
+  </name>
+  <name>
+    <first>Raphael</first>
+    <last>Pierquin</last>
+  </name>
+  <name>
+    <first>Ray</first>
+    <last>Waldin</last>
+  </name>
+  <name>
+    <first>Richard</first>
+    <last>Evans</last>
+  </name>
+  <name>
+    <first>Rick</first>
+    <last>Beton</last>
+  </name>
+  <name>
+    <first>Robert</first>
+    <last>Anderson</last>
+  </name>
+  <name>
+    <first>Robert</first>
+    <last>Shaw</last>
+  </name>
+  <name>
+    <first>Robert</first>
+    <last>Watkins</last>
+  </name>
+  <name>
+    <first>Roberto</first>
+    <last>Scaramuzzi</last>
+  </name>
+  <name>
+    <first>Robin</first>
+    <last>Green</last>
+  </name>
+  <name>
+    <first>Rob</first>
+    <last>Oxspring</last>
+  </name>
+  <name>
+    <first>Rob</first>
+    <last>van Oostrum</last>
+  </name>
+  <name>
+    <first>Roger</first>
+    <last>Vaughn</last>
+  </name>
+  <name>
+    <first>Roman</first>
+    <last>Ivashin</last>
+  </name>
+  <name>
+    <first>Ronen</first>
+    <last>Mashal</last>
+  </name>
+  <name>
+    <first>Russell</first>
+    <last>Gold</last>
+  </name>
+  <name>
+    <first>Sam</first>
+    <last>Ruby</last>
+  </name>
+  <name>
+    <first>Scott</first>
+    <last>Carlson</last>
+  </name>
+  <name>
+    <first>Scott</first>
+    <last>Ellsworth</last>
+  </name>
+  <name>
+    <first>Scott</first>
+    <middle>M.</middle>
+    <last>Stirling</last>
+  </name>
+  <name>
+    <first>Sean</first>
+    <last>Egan</last>
+  </name>
+  <name>
+    <first>Sean</first>
+    <middle>P.</middle>
+    <last>Kane</last>
+  </name>
+  <name>
+    <first>Sebastien</first>
+    <last>Arod</last>
+  </name>
+  <name>
+    <first>Shiraz</first>
+    <last>Kanga</last>
+  </name>
+  <name>
+    <first>Sebastian</first>
+    <last>Kantha</last>
+  </name>
+  <name>
+      <first>Simon</first>
+      <last>Law</last>
+  </name>
+  <name>
+    <first>Stefan</first>
+    <last>Bodewig</last>
+  </name>
+  <name>
+    <first>Stefano</first>
+    <last>Mazzocchi</last>
+  </name>
+  <name>
+    <first>Stephan</first>
+    <last>Strittmatter</last>
+  </name>
+  <name>
+    <first>Stephane</first>
+    <last>Bailliez</last>
+  </name>
+  <name>
+    <last>stephan</last>
+  </name>
+  <name>
+    <first>Stephan</first>
+    <last>Michels</last>
+  </name>
+  <name>
+    <first>Stephen</first>
+    <last>Chin</last>
+  </name>
+  <name>
+    <first>Steve</first>
+    <last>Cohen</last>
+  </name>
+  <name>
+    <first>Steve</first>
+    <last>Loughran</last>
+  </name>
+  <name>
+    <first>Steve</first>
+    <last>Morin</last>
+  </name>
+  <name>
+    <first>Steve</first>
+    <last>Wadsworth</last>
+  </name>
+  <name>
+    <first>Steven</first>
+    <middle>E.</middle>
+    <last>Newton</last>
+  </name>
+  <name>
+    <first>Takashi</first>
+    <last>Okamoto</last>
+  </name>
+  <name>
+    <first>Taoufik</first>
+    <last>Romdhane</last>
+  </name>
+  <name>
+    <first>Tariq</first>
+    <last>Master</last>
+  </name>
+  <name>
+    <first>Thomas</first>
+    <last>Butz</last>
+  </name>
+  <name>
+    <first>Thomas</first>
+    <last>Christen</last>
+  </name>
+  <name>
+    <first>Thomas</first>
+    <last>Christensen</last>
+  </name>
+  <name>
+    <first>Thomas</first>
+    <last>Haas</last>
+  </name>
+  <name>
+    <first>Thomas</first>
+    <last>Quas</last>
+  </name>
+  <name>
+    <first>Tim</first>
+    <last>Drury</last>
+  </name>
+  <name>
+    <first>Tim</first>
+    <last>Fennell</last>
+  </name>
+  <name>
+    <first>Timothy</first>
+    <middle>Gerard</middle>
+    <last>Endres</last>
+  </name>
+  <name>
+    <first>Tim</first>
+    <last>Stephenson</last>
+  </name>
+  <name>
+    <first>Tom</first>
+    <last>Ball</last>
+  </name>
+  <name>
+    <first>Tom</first>
+    <last>Cunningham</last>
+  </name>
+  <name>
+    <first>Tom</first>
+    <last>Dimock</last>
+  </name>
+  <name>
+    <first>Tom</first>
+    <last>Eugelink</last>
+  </name>
+  <name>
+    <first>Trejkaz</first>
+    <last>Xaoz</last>
+  </name>
+  <name>
+    <first>Ulrich</first>
+    <last>Schmidt</last>
+  </name>
+  <name>
+    <first>Victor</first>
+    <last>Toni</last>
+  </name>
+  <name>
+    <first>Will</first>
+    <last>Wang</last>
+  </name>
+  <name>
+    <first>William</first>
+    <last>Ferguson</last>
+  </name>
+  <name>
+    <first>Wolf</first>
+    <last>Siberski</last>
+  </name>
+  <name>
+    <first>Wolfgang</first>
+    <last>Baer</last>
+  </name>
+  <name>
+    <first>Wolfgang</first>
+    <last>Frech</last>
+  </name>
+  <name>
+    <first>Wolfgang</first>
+    <last>Werner</last>
+  </name>
+  <name>
+    <first>Xavier</first>
+    <last>Hanin</last>
+  </name>
+  <name>
+    <first>Xavier</first>
+    <last>Witdouck</last>
+  </name>
+  <name>
+    <first>Yohann</first>
+    <last>Roussel</last>
+  </name>
+  <name>
+    <first>Yuji</first>
+    <last>Yamano</last>
+  </name>
+  <name>
+    <first>Yves</first>
+    <last>Martin</last>
+  </name>
+  <name>
+    <first>Zach</first>
+    <last>Garner</last>
+  </name>
+  <name>
+    <first>Zdenek</first>
+    <last>Wagner</last>
+  </name>
+</contributors>
diff --git a/trunk/doap_Ant.rdf b/trunk/doap_Ant.rdf
new file mode 100644
index 0000000..64cbf9c
--- /dev/null
+++ b/trunk/doap_Ant.rdf
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<rdf:RDF xml:lang="en"
+         xmlns="http://usefulinc.com/ns/doap#" 
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
+         xmlns:asfext="http://projects.apache.org/ns/asfext#">
+  <Project rdf:about="http://ant.apache.org/">
+    <created>2006-02-17</created>
+    <license rdf:resource="http://usefulinc.com/doap/licenses/asl20" />
+    <name>Apache Ant</name>
+    <homepage rdf:resource="http://ant.apache.org" />
+    <asfext:pmc rdf:resource="http://ant.apache.org" />
+    <shortdesc>Java-based build tool</shortdesc>
+    <description>Apache Ant is a Java-based build tool. In theory, it is kind of like Make, but without Make's wrinkles.</description>
+    <bug-database rdf:resource="http://issues.apache.org/bugzilla/buglist.cgi?product=Ant" />
+    <mailing-list rdf:resource="http://ant.apache.org/mail.html" />
+    <download-page rdf:resource="http://ant.apache.org/bindownload.cgi" />
+    <programming-language>Java</programming-language>
+    <category rdf:resource="http://projects.apache.org/category/build-management" />
+    <release>
+      <Version>
+        <name>Apache Ant 1.7.0</name>
+        <created>2006-12-13</created>
+        <revision>1.7.0</revision>
+      </Version>
+    </release>
+    <repository>
+      <SVNRepository>
+        <location rdf:resource="http://svn.apache.org/repos/asf/ant"/>
+        <browse rdf:resource="http://svn.apache.org/viewcvs.cgi/ant"/>
+      </SVNRepository>
+    </repository>
+  </Project>
+</rdf:RDF>
diff --git a/trunk/docs.xml b/trunk/docs.xml
new file mode 100644
index 0000000..1e62f51
--- /dev/null
+++ b/trunk/docs.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="build-site" default="docs" basedir=".">
+
+    <description>
+        Build documentation - XDocs and Javadoc.
+        For building XDocs, edit xdocs/**/*.xml first.
+        If ../jakarta-site2 does not exist, set -Dsite.dir=... for it,
+        or just use -Dvelocity.dir=.../velocity-4.x if you have downloaded Velocity somewhere.
+
+        XXX for no apparent reason, your CWD must be the main Ant source dir, or this will fail:
+        .../docs.xml:64: org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource './site.vsl'
+    </description>
+
+    <!-- Initialization properties -->
+    <property name="project.name" value="ant"/>
+    <property name="docs.src"     location="xdocs"/>
+    <property name="docs.dest"    location="docs"/>
+    <property name="project.file" value="stylesheets/project.xml" />
+    <property name="templ.path"   location="xdocs/stylesheets" />
+    <property name="velocity.props"   location="${docs.src}/velocity.properties" />
+    <property name="include.xml"  value="**/*.xml" />
+
+    <target name="setup-explicit-classpath" if="velocity.dir">
+        <path id="anakia.classpath">
+            <fileset dir="${velocity.dir}">
+                <include name="velocity-dep-*.jar"/>
+                <!-- XXX why is this needed separately? -->
+                <include name="build/lib/jdom-*.jar"/>
+            </fileset>
+        </path>
+    </target>
+
+    <target name="setup-implicit-classpath" unless="velocity.dir">
+        <property name="site.dir" location="../jakarta-site2"/>
+        <path id="anakia.classpath">
+            <fileset dir="${site.dir}/lib">
+                <include name="*.jar"/>
+            </fileset>
+        </path>
+    </target>
+
+    <target name="prepare" depends="setup-explicit-classpath,setup-implicit-classpath">
+        <available classname="org.apache.velocity.anakia.AnakiaTask"
+                   property="AnakiaTask.present">
+            <classpath refid="anakia.classpath"/>
+        </available>
+        <condition property="onwindows">
+            <os family="windows"/>
+        </condition>
+    </target>
+
+    <target depends="prepare" name="prepare-error" unless="AnakiaTask.present">
+        <echo>
+            AnakiaTask is not present! Please check to make sure that
+            velocity.jar is in your classpath.
+        </echo>
+    </target>
+
+    <target name="anakia" if="AnakiaTask.present" depends="prepare-error">
+        <taskdef name="anakia" classname="org.apache.velocity.anakia.AnakiaTask">
+            <classpath refid="anakia.classpath"/>
+        </taskdef>
+
+        <anakia basedir="${docs.src}" destdir="${docs.dest}/"
+             extension=".html" style="./site.vsl"
+             projectFile="${project.file}"
+             excludes="**/stylesheets/**"
+             includes="${include.xml}"
+             lastModifiedCheck="true"
+             templatePath="${templ.path}"
+             velocityPropertiesFile="${velocity.props}">
+        </anakia>
+        <fixcrlf srcdir="${docs.dest}" includes="**/*.html"/>
+    </target>
+
+    <target name="fixcrlf" if="onwindows">
+        <fixcrlf srcDir="${docs.dest}" eol="dos" includes="*.html"/>
+    </target>
+
+    <target name="docs" if="AnakiaTask.present" depends="anakia,fixcrlf" description="Create XDocs.">
+    </target>
+    <target name="javadocs" description="Create Javadoc.">
+      <ant antfile="build.xml" target="dist_javadocs">
+        <property name="dist.javadocs" value="${docs.dest}/manual/api" />
+      </ant>
+    </target>
+
+    <target name="all" depends="docs,javadocs" description="Create both XDocs and Javadoc."/>
+
+</project>
diff --git a/trunk/docs/.htaccess b/trunk/docs/.htaccess
new file mode 100644
index 0000000..01572cb
--- /dev/null
+++ b/trunk/docs/.htaccess
@@ -0,0 +1 @@
+AddOutputFilter INCLUDES .html
\ No newline at end of file
diff --git a/trunk/docs/LICENSE b/trunk/docs/LICENSE
new file mode 100644
index 0000000..f820d4b
--- /dev/null
+++ b/trunk/docs/LICENSE
@@ -0,0 +1,203 @@
+/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
diff --git a/trunk/docs/ant2/FunctionalRequirements.html b/trunk/docs/ant2/FunctionalRequirements.html
new file mode 100644
index 0000000..78d5dd8
--- /dev/null
+++ b/trunk/docs/ant2/FunctionalRequirements.html
@@ -0,0 +1,70 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
+  <title>Ant Functional Requirements Document</title>
+</head>
+<body>
+<h2>Ant Functional Requirements</h2>
+<h3>Roles</h3>
+<p><b>User: </b>runs Ant with a complete build specification and/or
+writes Ant build specifications.</p>
+<p><b>Task Developer: </b>writes/modifies Ant tasks.</p>
+<p><b>Extensions Developer: </b>develops extensions like a GUI, IDE plugin,
+ (scripting extension?)</p>
+<p><b>Core Developer: </b>works on the Ant core</p>
+<h3>Requirements from the Ant User perspective</h3>
+<p>It should be easy to write a build file for small Java programs. It should
+ be possible to write a build file set for large Java systems. Maintenance
+ of such a set should be easy (e.g. no duplication of information).</p>
+<p>Every build process contains dependencies (e.g. item A needs B to be available
+ before its own build can start). It should be possible to specify these
+ dependencies in a declarative way.</p>
+<p>Suppose a working build specification for system A is available. It should
+ be possible for system B to declare dependencies to <i>(modules of?)</i> system
+ A without touching the build specification of A. Ant should be able to handle
+ dependencies between modules which form a DAG.</p>
+<p>It should be possible to modify details of the actual build (e.g. classpath,
+ used compiler) without the need to change the build specification. This
+ feature is needed when starting Ant (e.g. configuration with command line
+ parameters) and for a subproject build driven by the build of a dependent
+ project.</p>
+<p>Often similar items have to be built. Therefore it should be possible
+ to provide general <i>(template?)</i> build specifications, and to declare for
+ a concrete item that it should be built according to such a general specification.</p>
+<p>One result of the build process should be a log which shows what has been done.</p>
+<h3>Requirements from the task developer perspective</h3>
+<p>A task should not need to know the structure of a build specification.
+ It would have to provide an interface (not necessarily in the Java language
+ sense) for the Ant core to input the necessary configuration attributes
+ and to execute the task). There should be a standard functionality to allow
+ a task doing log output.</p>
+<p>An interface (again not necessarily in the Java language sense) should
+ be provided which allows a task to get <i>(and set?)</i> information about it's
+ context in the build process.</p>
+<h3>Requirements from the extensions developer perspective</h3>
+<p>The Ant core should be independent from a specific representation of the
+ build specification. It should be possible to create a specification programmatically
+ (thereby allowing the introduction of new representations). The core should
+ do no in- or output itself. Build errors should always lead to throwing
+ an Exception.</p>
+<p>Access to the current state of a build should be available, and its modification
+ possible.</p>
+</body>
+</html>
+
diff --git a/trunk/docs/ant2/VFS.txt b/trunk/docs/ant2/VFS.txt
new file mode 100644
index 0000000..029fe25
--- /dev/null
+++ b/trunk/docs/ant2/VFS.txt
@@ -0,0 +1,253 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+From: "Adam Murdoch" <adammurdoch_ml@yahoo.com>
+Subject: RE: Virtual FileSystem Layer
+Date: Sat, 22 Dec 2001 12:06:37 +1000
+
+Hi,
+
+I've also been doing a bit of work on the VFS.  No code yet - instead, I've
+done a survey of the Ant 1 code, to help get a better idea of what we need
+the VFS to actually do.
+
+I've put together a rough list of the sort of features the current tasks
+require from the file system.  This list is entirely from the task writer's
+POV.  I've ignored the build file writer completely - though, the action
+list is a good summary of the build file writer's concerns.  I've tried to
+steer clear of assumptions about what is actually going to provide each
+feature to the tasks, or what the API will look like to the tasks.
+
+The goal for doing up this list, was to help identify the features we want
+to support, and the API that the tasks will use to get at them.  This should
+be largely independent of how we decide to represent the file system in the
+build files.  In addition, it doesn't matter too much whether the list below
+is complete (I'm sure it isn't), or that the VFS provide every single one of
+the features.  Whatever it doesn't provide, can stay up in the tasks, and be
+refactored down later.
+
+The assumption here is that we do actually want to put together a file
+system API.  I think it's a good idea to at least put together some
+interfaces, even if the implementation is stolen from somewhere else.
+Without a doubt, the file system is the most widely used "service" in the
+current crop of tasks.  The API that we choose has to have a good semantic
+match with what the tasks need to do, so that writing the tasks is easy.
+The API also has to be general enough to deal with stuff we haven't thought
+of yet.  On that note, I personally think that JNDI might be a touch too
+general for what we need.
+
+So, the features.  Note that many of these will be optional - not every
+feature will be available for every node in the file system.  I've used the
+term "node" to mean both directories and files.  I'm not suggesting we
+actually call them "nodes" in the API.  I've used the term "root node" to
+mean the root of a file system.
+
+* Naming
+
+- Locate a node by absolute name.
+- Get the absolute name for a node.
+- Resolve a name to a node, relative to some base node - like
+FileUtils.resolveFile().
+- Get the relative name of a node, relative to some base node.
+- Determine the base name (with and without the extension), and extension of
+the node.
+- Deal with file systems that are case sensitive, and case insentitive.
+
+* Properties
+
+- Determine what properties are available on the node.
+- Determine if the node exists.
+- Determine the type of node (file vs. directory, could be "has-content" vs
+"has-children").
+- Determine if the node is readable.
+- Determine if the node is writeable.
+- Get/set the permissions on the node.  This covers things like chmod &
+chown, making read-only, making executable, etc.
+
+* Content
+
+- Determine if the node can/does have content.
+- Get the size of the node.
+- Get/set the last-modified time of the node.
+- Get/set the mime-type of the node.
+- Get/set the encoding of the node.
+- Get a checksum of the node.
+- Get content as InputStream.
+- Get content as Reader.
+- Set content as an OutputStream.
+- Set content as a Writer.
+- Implicit creation of node and its ancestors when content is written.
+- Compare nodes for equality (last modified timestamp, checksum, bytewise
+compare).
+
+* Hierarchy
+
+- Get the parent node of a node.
+- Get the child nodes of a node.
+- Iterate over (or visit) the descendants of a node.
+  - With or without a selector.
+  - In various orders - depthwise, etc.
+  - Be able to modify the nodes during traversal.
+
+* Modification
+
+- Create a new node of a particular type.  Create all missing ancestors.
+- Move, copy, delete a node.
+  - All descendants.
+  - Optional selector. E.g. ignore empty dirs, ignore default excludes, etc.
+  - Optional filter.
+
+* Conversion
+
+- Convert the node to a java.net.URL.
+- Make the node content available as a local file (to hand off to external
+commands).
+- Get the OS specific *filename* for a node.
+- Resolve an OS specific *filename* to a node.
+
+* File System Types
+
+- Local file.
+- HTTP.
+- FTP.
+- Classloader, uses Classloader.getResource().
+- Temporary files.
+- etc ...
+
+- Compound file system.  Made up of a bunch of mount points.  The VFS
+itself.
+
+- Layered file systems (that sit on top of another file system or node):
+  - zip, bzip, jar, tar
+  - filtering - token replacement, etc
+
+- Factories for creating and configuring file system root nodes.
+- Ability to easily add new file system implementations.
+
+* Task Container
+
+- A mechanism for a task to get hold of the project's root node.
+
+- A mechanism that allows a task to create its own private root nodes,
+without letting it mess with the project's file system, or the file systems
+of other tasks.
+
+- A mechanism for cleaning up all the node InputStream, OutputStream, Reader
+and Writers opened by a task during its execute() method.  Cleaning up files
+is one thing the current tasks don't do very well at all.  Something like
+this would take care of anything the task did not explictly close.  Would
+include root nodes it created.
+
+* Other things
+
+- Maybe some way to explicitly close a node and release all resources used
+by it.
+
+- Maybe detection of concurrent updates, in the case of parallel tasks.
+
+- Netbeans has an event model in its VFS.  Something like this might be
+useful in dependency management.
+
+- nodesets.  The replacement for, or generalisation of, FileSet, Path,
+FileList, etc
+  - A nodeset that contains the descendents of a node that match a selector
+(like the current FileSet implementation).
+  - A nodeset that contains arbitrary nodes.
+  - An aggregating nodeset.
+  - Custom nodeset implementations.
+
+- Reimplement the Ant 1 Fileset, Path and Filelist as adaptors sitting on
+top of the VFS.
+
+- A classloader that can load classes from a node.
+
+- etc ..
+
+What's missing?  What shouldn't be on the list?
+
+
+Adam
+
+> -----Original Message-----
+> From: Magesh Umasankar
+> Sent: Saturday, 22 December 2001 10:44 AM
+> To: ant-dev@jakarta.apache.org
+> Subject: Virtual FileSystem Layer
+>
+>
+> I have been spending some time now on the VFS
+> layer...  Nothing major to report yet, but I just wanted
+> to sound off so that if I am going down the wrong
+> route, I correct it right away.
+>
+> I evaluated at WebNFS, NetBeansFS (NBFS) and
+> JNDI.
+>
+> 1.  WebNFS seems to be going nowhere.  It has
+> been dormant for quite sometime now.  Licensing
+> is rigid.  Technically, it doesn't look so bad as it
+> closely replicates java.io.File's API.  But then,
+> that really gives us very little.
+>
+> 2.  NBFS looks OK.  It has got a few filesystems
+> already built.  There may be some licensing issues,
+> I don't know, but that shouldn't concern us too
+> much as, according to Peter, it is Mozilla (I haven't
+> really check the license out, sorry).  But, as far as I
+> can see, it seems to lack in sophisticated API features
+> like searching based on attributes, etc., which
+> we will definitely be needing for the Selector APIs.
+>
+> 3.  JNDI, by far, beats the above to, in my
+> evaluation.  It is generic enough.  We don't have
+> any licensing issues.  It has also become part of
+> the core JRE (1.4 onwards).  Technically, it fits to a T
+> what we are looking for - virtual file system that
+> provides search controls, access attributes,
+> url mounting, etc.  Furthermore, there's been
+> some ground work already done for us at Jakarta/Apache
+> (Catalina).  I have written a SPI for a FTPFileSystem
+> - though it is in a real crude stage right now.  I believe
+> this is the way to go because Ant's code would be
+> operating at the (Dir)Context level and we can keep
+> adding SPIs as we need them.  Furthermore,
+> JNDI has been stable for quite sometime now and
+> we can depend on a widely used API.
+>
+> I don't think JNDI is a heavyweight API for our needs.
+> It seems to be the only one, so far, which encompasses
+> at the APIP level, all the new functionalities that we
+> desire to introduce.
+>
+> Let me know if my approach, so far, to go the JNDI
+> route seems reasonable.
+>
+> Cheers,
+> Magesh
+>
+>
+>
+>
+> --
+> To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
+> For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>
+
+
+--
+To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
+For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>
+
+
diff --git a/trunk/docs/ant2/actionlist.html b/trunk/docs/ant2/actionlist.html
new file mode 100644
index 0000000..61392a8
--- /dev/null
+++ b/trunk/docs/ant2/actionlist.html
@@ -0,0 +1,492 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head><title>Ant1.9 Action List</title></head>
+  <body bgcolor="#ffffff">
+  <center>
+    <h1>Ant1.9 Action List</h1>
+    <h2>Precursor to Ant2</h2>
+    <i>Peter Donald [<a href="mailto:peter at apache.org">peter at apache.org</a>]</i>
+  </center>
+
+  <div align="center">
+  <table width="80%"><tr><td>
+    <blockquote>
+    <p>
+      This document aims to contain a list of actions that people can take
+      to produce Ant1.9. Ant1.9 is a refactoring of the Ant1.x line and a jump
+      point for Ant2. Some changes will be backported to Ant1.x over time when 
+      they have proven themselves while other changes may only become available
+      via Ant2.0. Ant1.9 is our melting pot where we can experiment and refactor 
+      without a thought to backwards compatability but only to the "right" way 
+      of doing things.
+    </p>
+    </blockquote></td></tr>
+  </table>
+  </div>
+
+  <h2>Introduction</h2>
+
+  <blockquote>
+    <p>
+      This document will list a bunch of actions that will guide us in the evolution 
+      of Ant1.x and provide a solid basis on which to launch Ant2.0. Feel free to add to 
+      this list of actions as our vision of Ant2 solidifies. Associated with each action
+      is a list of victims who have "volunteered" to have a go at the action and a status.
+      The status just tells us where they are at while the victim column will tell us exactly
+      who is doing what. It is fine for a group of people to work on a single area.
+    </p>
+    <br />
+    <br />
+    <br />
+    <div align="center">
+    <table cellspacing="2" cellpadding="5" width="80%">
+      <tr>
+        <td bgcolor="#eeeeee" align="center">Action</td>
+        <td bgcolor="#eeeeee" align="center">Victims</td>
+        <td bgcolor="#eeeeee" align="center">Status</td>
+      </tr>
+      <tr>
+        <td><a href="#vfs">Create a Virtual Filesystem layer</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#naming">Formalize a naming scheme for task attributes/elements</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#selector">Design and implement s Selector API for Filesets and other Itemsets</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#coloring">Develope the infrastructure for coloring (or "environmental" dependency analysis)</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#structural">Develope the infrastructure for structural dependency analysis</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#exec">Refactor the Exec infrastructure into JavaBeans</a></td>
+        <td>Peter Donald</td>
+        <td>80%</td>
+      </tr>
+      <tr>
+        <td><a href="#java">Refactor the Java infrastructure into JavaBeans</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#facade">Design and implement a generic solution for creating Task facades</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#packaging">Sketch out a basic way of separating all the tasks into type libraries</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#mapperext">Design and implement an API that allows mapping of file attributes during copy/move/etc tasks</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#filters">Design and implement an API so that Filters could be implemented as FilteredOutputStreams</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#catalog">Design and implement a XML "catalog" so the snippets of XML can be injected based on URI rather than relative location</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#i18n">Look at the feasability of i18n'ing tasks and the runtime</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#doco">Write a document describing the way that tasks should be written in context of Ant2</a></td>
+        <td>Peter Donald<br />(peter at apache.org)</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#embeddor">Design an API to embed Ant into other applications</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#info">Design a TypeInfo system similar to BeanInfo to describe Tasks</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+      <tr>
+        <td><a href="#antdoc">Design Antdoc to generate manual from .java files</a></td>
+        <td>None</td>
+        <td>Not Started</td>
+      </tr>
+    </table>
+    </div>
+  </blockquote>
+
+  <h3>Virtual File System</h3>
+  <a name="vfs" />
+  <blockquote>
+    <p>
+      There has long been a recognition that it would be nice if ant supported some 
+      notion of a virtual filesystem layer. This layer would allow you to treat 
+      resources located and retrieved from different mechanisms in a uniform way.
+      For instance it would allow the copy task to copy from a http server, a cvs server,
+      a ftp server or the local filesystem using a uniform mechanism. So instead of
+      having separate tasks to operate on each different resource type we would use
+      just one task that plugged into multiple filesystems.
+    </p>
+    <p>
+      When we are talking about a virtual filesystem or VFS, one of the concerns we must 
+      address is how to "name" the resource. In most cases a URL or URI style access will 
+      be sufficient but in other cases we may need to consider other options. So 
+      "cvs://localhost:/home/cvs/jakarta-avalon/README.txt?version=1.1", 
+      "ftp://some.server.com/dir/file.zip" and "file://C/WINDOWS/Desktop/MyFile.txt"
+      are all examples of referring to different resources.
+    </p>
+    <p>
+      Another concern that must be addressed is capabilities of both the resources and
+      the filesystem. For instance it is possible to both read and write to resources
+      using the "file" protocol but only possible to write resources using "mailto".
+      The act of copying a file to a "mailto" url would actuall post the files as 
+      resources while copying to a "file" would duplicate the resource somewhere on 
+      the local filesystem. 
+    </p>
+    <p>
+      So we need to determine a list of capabilities. Some examples would be "read", 
+      "write", "list" (can you list dirs), "type" (can you get mime type), 
+      "access permissions" (can you tell if resource has permissions), 
+      "modify permissions" (can you modify permissions) etc. Some of these capabilities
+      can be associated with the particular reosurces, while others may need to be 
+      associated with a whole filesystem/protocol (ie there is no standard mechanism
+      to perform "list" on general "http" URLs). Thus a list of all these capabilities
+      and mapping to various protocols will need to be established.
+    </p>
+    <p>
+      Next we need to determine if we are going to support the notion of "mounting"
+      URLs. For instance if we need to copy files from a FTP server do we allways
+      need to specify the full URL - no matter how convoluted it is (ie
+      "ftp://fred:secret@some.server.com:28763/home/fred/project2/dir/file.zip")
+      or can we mount this on a VFS and access it via that shorter url. ie We could 
+      mount "ftp://fred:secret@some.server.com:28763/home/fred/" onto "vfs:/home" 
+      and then just access the resources via "vfs:/home/project2/dir/file.zip".
+      This would make dealing with large urls easier and more uniform.
+    </p>
+    <p>
+      So after we have decided what our options are we need to actually go about
+      implementing the solution. It may be the case that existing VFS solutions
+      could be reused with minor changes and thus we could save ourselves a lot of 
+      work. Candidates would be the Netbeans VFS, Suns XFile API or other 
+      available directory APIs (like JNDI). If none of them suit then we will need 
+      to write our own layer.
+    </p>
+  </blockquote>
+
+  <h3>Naming</h3>
+  <a name="naming" />
+  <blockquote>
+    <p>
+      Currently Ant has a mixture of tasks from various stages it's evolution, with different
+      authors and each utilizing different naming patterns. Some tasks use names such as
+      "src" and "dest" while others use "file" and "tofile". It would be preferrable if 
+      consistent naming patterns were used. It is recomended that we come up with a "best
+      practices" document to document our recomended naming patterns.
+    </p>
+    <p>
+      Before we can come up with such a document we need to identify common patterns through
+      out the tasks. Several tasks have the notion of transforming input from a "source"
+      to a "destination". So we should have consistent naming schemes for these attributes and 
+      elements. Analysis of existing tasks will likely bring out other similar patterns. Once
+      we have identified and documented these similarities then we can establish conventions.
+    </p>
+  </blockquote>
+
+  <h3>Selector API</h3>
+  <a name="selector" />
+  <blockquote>
+    <p>
+      Currently our filesets allow us to select a set of files based on name patterns.
+      For instance we could create a set of all the files that end with ".java". However
+      there are cases when you wish to select files based on their other attributes, such as 
+      if they are read only or if they are older than a specified date etc.
+    </p>
+    <p>
+      The selector API is one such mechanism to do this. The selector API will allow you to 
+      build file sets based on criteria other than name. Some possible criteria would be
+    </p>
+    <ul>
+      <li>Is the file readable?</li> 
+      <li>Is the file writeable?</li> 
+      <li>What date was the file modified on?</li> 
+      <li>What size is the file?</li> 
+      <li>Does the contents contain the string "magic"?</li> 
+    </ul>
+    <p>
+      If we end up supporting a VFS then we could expand the number of selectors 
+      considerably. A mock representation that has been proposed before is the following. 
+      Of course this is subject to change as soon as someone wants to tackle this action ;)
+    </p>
+<pre> 
+ &lt;include&gt;
+   &lt;selector type="name" value="**/*.java"/&gt;
+   &lt;selector type="permission" value="r"/&gt;
+
+   &lt;!-- could optionally be directory/or some other system specific features --&gt;
+   &lt;selector type="type" value="file"/&gt; 
+   &lt;selector type="modify-time" 
+             operation="greater-than" 
+             value="29th Feb 2003"/&gt;
+ &lt;/include&gt;
+</pre>
+  </blockquote>
+
+  <h3>Coloring API</h3>
+  <a name="coloring" />
+  <blockquote>
+    <p>
+      When you execute a task such as "javac" there is two types of dependency information
+      that is important to analyze before we determine if we need to recompile a file. Say
+      we are compiling <code>Foo.java</code>, it may depend on the <code>Bar.java</code>
+      file. We call this "structural" dependency information - the structure of the source file 
+      determines what other files it depend upon. However there is also "environmental" 
+      dependency information. For instance if the <code>Foo.java</code> file was compiled with 
+      <code>debug="true"</code> last run and this time needs to be compiled with 
+      <code>debug="false"</code> then it is out of date and needs to be recompiled. We call this 
+      "environmental" dependency information "coloring".
+    </p>
+    <p>
+      So we need to create an infrastructure that allows tasks to manage "coloring". So a task
+      should be able to add coloring information for each resource processed. When the task
+      comes to process the resource again it will detect if the coloring has changed and if it
+      has will force a recompile.
+    </p>
+    <p>
+      An API for such a bean has yet to be established but an example API would be.
+    </p>
+    <pre>
+ColoringManager cm = ...;
+cm.addColor( "debug", "true" );
+cm.addColor( "optimize", "false" );
+cm.setFileSet( myFileSet );
+File[] files = cm.getOutOfDate();
+    </pre>
+  </blockquote>
+
+  <h3>Structural Dependency Utils</h3>
+  <a name="structural" />
+  <blockquote>
+    <p>
+      In the present ant, it is required that each task manage dependency separately. 
+      This makes it a lot of work to implement even simple dependency checking. To this
+      day many of the core tasks do not implement it correctly. I am specifically
+      talking about "structural" dependency information. The main reason is that it is
+      painful to implement.
+    </p>
+    <p>
+      Some tasks do no dependency checking and will recompile/transform/etc everytime. 
+      Others may perform a simple dependency checking (ie if source file is newer than 
+      destination file then recompile). Ideally a dependency system would actually
+      calculate the dependencies correctly. So we need to have some mechanism to determine
+      that <code>foo.c</code> actually depends upon <code>foo.h</code>, <code>bar.h</code> 
+      and <code>baz.h</code>. As this information is particular to each different task
+      we need to allow tasks to implement this behaviour. Possibly by supplying an interface
+      of the form;
+    </p>
+    <pre>
+public interface DependencyGenerator
+{
+  File[] generateDependencies( File file );
+}
+    </pre>
+    <p>
+      Generating the dependency information is a costly operation and thus we do not want to
+      be doing it everytime you run ant. We want to generate it on the initial build and then 
+      persist somewhere. Everytime a file is out of date, it's dependency information would
+      be regenerated and stored in the dependency cache. Ideally this cache would also store the
+      above mentioned coloring information. So the entry for <code>foo.c</code> may declare that 
+      it is dependent upon <code>foo.h</code>, <code>bar.h</code> and <code>baz.h</code>, aswell 
+      as being compiled with -O2 flag. If any of the dependencies have changed or are out of date 
+      then foo.c would need to be recompiled.
+    </p>
+    <p>
+      A possible API would be
+    </p>
+    <pre>
+DependencyManager dm = ...;
+dm.setFileSet( myFileSet );
+dm.setDependencyCache( myDependencyCacheFile );
+File[] files = cm.getOutOfDate();
+    </pre>
+  </blockquote>
+
+  <h3>Refactor &lt;exec&gt; infrastructure into Beans</h3>
+  <a name="exec" />
+  <blockquote>
+    <p>
+      Exec and its related classes have currently evolved through several iterations and thus
+      it is not as cleanly designed and as reusable as it could be. Someone needs to pull apart
+      exec and analyze which parts can be turned into JavaBeans and decouple them from the Ant 
+      infrastructure. Once that is done it will make these beans much easier to reuse from other
+      tasks without relying on gaining access to the other task instance.
+    </p>
+  </blockquote>
+
+  <h3>Refactor &lt;java&gt; infrastructure into Beans</h3>
+  <a name="java" />
+  <blockquote>
+    <p>
+      Much like Exec should be decoupled from Ant runtime, so should classes to implement java 
+      task for the same benefits.
+    </p>
+  </blockquote>
+
+  <h3>Generic Task Facades</h3>
+  <a name="facade" />
+  <blockquote>
+    <p>
+      Currently we have a few tasks that have multiple implementations. For instance Javac task
+      can actually call jikes, jvc, classic javac or modern javac. Similar things will be seen
+      with the jspc task and the cc task (if it ever gets written). We need to examine this 
+      pattern and see if there is a way to generalize this and make it easier to write such tasks.
+    </p>
+  </blockquote>
+
+  <h3>Task Packaging</h3>
+  <a name="packaging" />
+  <blockquote>
+    <p>
+      We have already decided that we are going to package Ant tasks in separate jars and
+      have some sort of descriptor that to describe the contents of the jar. However we have 
+      not yet decided how we will break up the tasks. Do we break up the tasks up into 
+      related tasks or into groups that ar elikely to be used together or what? A possible
+      breakdown would be
+    </p>
+    <ul>
+      <li>jdk tasks: javac, javadoc, rmic etc</li>
+      <li>text tasks: regex replace, fixcrlf etc</li>
+      <li>unix tasks: chmod, etc</li>
+      <li>file tasks: copy, move, etc</li>
+    </ul>
+  </blockquote>
+
+  <h3>Mapping File Attributes during transformation</h3>
+  <a name="mapperext" />
+  <blockquote>
+    <p>
+      When we are copying files from one location to another it is currently possible
+      to rename them using a mapper. So we could rename <code>Foo.java</code> to 
+      <code>Foo.java.bak</code>. On occasion it is useful to modify file attributes
+      other than its name in such operations. So we could copy the files to another
+      location and make them read-only in one operation.
+    </p>
+  </blockquote>
+
+  <h3>Filters extensions</h3>
+  <a name="filters" />
+  <blockquote>
+    <p>
+      This is partially related to the above action. Filters could be seen as a way 
+      to modify the content attribute of a file during a copy/move. It would be 
+      preferrable if filtering could be abstracted to use <code>FilteredOutputStream</code>s
+      to perform the content modification. That way new Filter types could be constructed
+      and used during file copy (ie an example would be a Perl FilterOutputStream that 
+      allowed you to use perl expressions to transform input).
+    </p>
+  </blockquote>
+
+  <h3>XML Catalog to load XML Fragments</h3>
+  <a name="catalog" />
+  <blockquote>
+    <p>
+      When including fragments of XML we are currently forced to use relative paths.
+      However this is sometimes undesirable when a single fragment needs to be used
+      across several projects in several different locations. Instead we could use
+      a Catalog to name the fragment and then each developer would only need to install
+      the fragment once and it would be accessible from all the projects.
+    </p>
+  </blockquote>
+
+  <h3>i18n the Runtime and tasks</h3>
+  <a name="i18n" />
+  <blockquote>
+    <p>
+      Look at the feasability of performing i18n on Ant runtime and core tasks. Look at
+      how much work it will be and how useful it would be. Look at utilizing i18n from 
+      existing projects such as Avalon.
+    </p>
+  </blockquote>
+
+  <h3>Embeddor API for Ant</h3>
+  <a name="embeddor" />
+  <blockquote>
+    <p>
+      Identify different environments in which it would be useful to embed Ant or an Ant-like 
+      tool. Identify what these environments are likely to demand in terms of API and support
+      and then design a system that works in these environments without compromising ants 
+      core goal (ie a build system). Some suggestions for such an API include;
+    </p>
+    <ul>
+      <li>Pluggable ProjectBuilders to allow building of project from a variety of sources,
+       file, URL, InputStream, SAX etc</li>
+      <li>Pluggable ClassLoader arrangement</li>
+      <li>Ability to set User Properties</li>
+      <li>Ability to add Task/Data/Type definitions</li>
+      <li>Ability to add/remove Listeners</li>
+      <li>Ability to add/remove Loggers</li>
+      <li>Ability to get meta-information about targets (such as name and description)</li>
+      <li>The ability to execute a task and/or targets</li>
+      <li>The ability to add tasklibs</li>
+      <li>The ability to add VFS mount points</li>
+      <li>The ability to manipulate ProjectModel and build it from GUIs</li>
+      <li>A general task engine API</li>
+    </ul>
+  </blockquote>
+
+  <h3>TypeInfo system</h3>
+  <a name="info" />
+  <blockquote>
+    <p>
+      Add in the ability to represent tasks using specified meta-info, This would allow 
+      generation and manipulation of information such as what attributes are available, 
+      what elements are supported etc. 
+    </p>
+  </blockquote>
+
+  <h3>Antdoc</h3>
+  <a name="antdoc" />
+  <blockquote>
+    <p>
+      This is partially based on the above TypeInfo system. It involves the ability to 
+      take the TypeInfo made available and generate documentation for the tasks. This 
+      would allow multiple formats of documentaiton to be easily maintained and reduce 
+      the chance that documentation gets out of whack.
+    </p>
+  </blockquote>
+
+  </body>
+</html>
diff --git a/trunk/docs/ant2/features.html b/trunk/docs/ant2/features.html
new file mode 100644
index 0000000..0cb8314
--- /dev/null
+++ b/trunk/docs/ant2/features.html
@@ -0,0 +1,381 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us">
+    <title>Ant2 feature list</title>
+
+      <style type="text/css">
+        .comment {
+          COLOR: #900000;
+	  BACKGROUND: #ffa;
+        }
+      </style>
+
+  </head>
+
+  <body bgcolor="#FFFFFF">
+
+    <p class="comment">If something looks like this, this is either a
+    request for input or a &quot;REVISIT&quot; marker or similar.</p>
+
+    <h1>Ant2 Goals</h1>
+
+    <p>Even though Ant2 is expected to be incompatible with the
+    current Ant1 series, it still has the same goals. Ant is a Java
+    based build tool and this remains the main focus of it. The
+    original goals of simplicity, understandability and extensibility
+    still stand and Ant2 will try to achieve them even better than
+    Ant1 does.</p>
+
+    <h2>Simplicity and Understandability</h2>
+
+    <p>These two goals are closely related. Ant build files shall be
+    easy to read and understand - at the same time it should be easy
+    to write a custom Ant task and to use the utility classes that
+    Ant2 provides.</p>
+
+    <p>Ant2 shall be more consistent than Ant1 is - this means:</p>
+
+    <ul>
+
+      <li>core tasks will use the same attribute names for common
+      functionality</li>
+
+      <li>similar tasks will be unified to use similar forms.</li>
+
+      <li>different implementations for the same functionality will be
+      hidden behind facade tasks.</li>
+
+      <li>properties and data types will be unified so that they share
+      the same namespace and inheritance rules. <i
+      class="comment">Need to talk about how ${} expansion works for
+      filesets and so on.</i></li>
+
+    </ul>
+
+    <p>Furthermore some things will have to become more explicit:</p>
+
+    <ul>
+
+      <li>remove all magic properties</li>
+
+      <li>make build file writers explicitly state which
+      filters/filtersets a copy task will use</li>
+
+      <li>add scoping rules for properties so that not all of them
+      will be inherited by sub-builds, only those that have been
+      specified explicitly. <i class="comment">Fill in details once
+      they've been sorted out.</i></li>
+
+    </ul>
+
+    <p>The front-ends for Ant2 shall be smart enough to automatically
+    detect the required libraries (like <code>tools.jar</code>), the
+    use of native scripts shall be kept to a minimum.</p>
+
+    <p>Build file writers can attach a message to targets that will be
+    presented to the user if that target is going to be skipped (based
+    on the if/unless attribute of the target).</p>
+
+    <p>Even though Ant installation already is quite simple in Ant1
+    (extract the archive and set two environment variables),
+    alternative ways to install Ant like using 
+    <a href="http://java.sun.com/products/javawebstart/">Webstart</a> or
+    a "self-extracting" JAR file will be explored.</p>
+
+    <h2>Extensibility</h2>
+
+    <p>Ant2 like Ant1 uses build files written in XML as its main
+    input, but it will not be restricted to it. The core of Ant2 will
+    work on an object model of Project/Target/Task that is independent
+    of any external representation.</p> 
+
+    <p>As an extension of the current <code>&lt;taskdef&gt;</code>
+    concept, tasks can be bundled into task libraries (together with
+    data types and other utility classes). These task libraries are
+    special JAR archives that somehow describe the contained tasks to
+    Ant. Ant will automatically know all tasks contained in task
+    libraries that have been placed into a special directory - in
+    addition task libraries can be referenced and used in a build file
+    explicitly. <i class="comment">Fill in details once they've been
+    sorted out.</i></p>
+
+    <p>It has become apparent, that several &quot;aspects&quot; of
+    tasks are so common that task writers find themselves duplicating
+    code all over again - things like classpath handling or &quot;do
+    we stop the build if this task fails?&quot; functionality for
+    example. Ant2 will provide a way to let the user attach an
+    &quot;aspect handler&quot; to a project - all attributes that live
+    in a certain namespace are going to be passed to this handler. <i
+    class="comment">Need to talk about TaskContext here.</i></p>
+
+    <p>Ant2 will farm out common functionality from tasks into utility
+    classes so that task writers can benefit from a tested and stable
+    framework - they shouldn't need to deal with existing tasks
+    directly (like some tasks &quot;abuse&quot; the
+    <code>&lt;touch&gt;</code> task in Ant1).</p>
+
+    <p>Ant2 will provide a way to define tasks that itself can have
+    tasks as child elements without knowing all defined tasks at
+    compile time.  Discussions on ant-dev usually talk about
+    &quot;container tasks&quot; in this context.</p>
+
+    <p>The only way to &quot;include&quot; common XML snippets so far
+    has been the usage of external SYSTEM entities, a mechanism that
+    is tied to DTDs and doesn't mix well with alternative
+    approaches like XML Schema.  Ant2 will provide a built-in include
+    mechanism.</p>
+
+    <h1>New/Modified Features</h1>
+
+    <p>Ant2 will run the build process fully dynamically, which means
+    that task won't be instantiated before they are actually being run
+    and <code>${}</code> expansion will see the very latest value of a
+    property. It will be possible to reassign values of properties via
+    a built-in task.</p>
+
+    <h2>Compatibility with Ant1</h2>
+
+    <p>Ant2 is going to break Ant1 in several ways:</p>
+
+    <ul>
+
+      <li>Tasks written for Ant1 won't work in Ant2 as the API of
+      Ant's core and the names of utility classes are going to
+      change. There will probably be adaptors and utility classes to
+      ease the transition for task writers.</li>
+
+      <li>Build files written for Ant1 will probably not be valid in
+      Ant2 or at least not yield the same results. It is expected that
+      Ant2 will come with a tool to translate Ant1 build files into
+      equivalent Ant2 versions</li>
+
+      <li>magic properties like <code>build.compiler</code> may
+      disappear and be replaced by a different customization
+      concept.</li>
+
+      <li>Ant2 is going to require a JDK version 1.2 or above and a
+      JAXP compliant parser version 1.1 or above.</li>
+
+      <li>If you specify more than one target in another target's
+      depends attribute, Ant1 will execute these targets from left to
+      right (as long as the dependency tree permits it) - Ant2 will
+      not guarantee this behavior but will allow build file writers to
+      specify the order explicitly.</li>
+
+      <li>Dereferencing a non existent property a via ${a} will result
+      in a build failure.</li>
+
+    </ul>
+
+    <h2>Support Integration of Ant Into Other Tools</h2>
+
+    <p>Ant2 will have a clear separation between the front-end that is
+    responsible for user interactions, the object model that
+    represents the project to build and the part of Ant that runs the
+    build process itself <i class="comment">Name that TaskEngine,
+    ProjectEngine, ExecutionEngine or what?</i>. This separation is
+    expected to ease the integration of Ant (or parts of it) into
+    other products.</p>
+
+    <p>Ant2 itself will include a command line front-end and Antidote
+    will become the GUI front-end to it. Other front-ends like a
+    servlet front-end are expected <i class="comment">outside of
+    Ant's core</i> as well.</p>
+
+    <p>In addition to this separation, the following features should
+    help people who want to integrate Ant into their products:</p>
+
+    <ul>
+
+      <li>It will be possible to cancel a running build process.</li>
+
+      <li>Ant will detach from <code>System.err/.out/.in</code>
+      completely and communicate with the front-end via a well defined
+      API.  The front-end will have to handle user input for tasks
+      that need it (tasks that ask for a password for example).</li>
+
+      <li>Tasks will provide some way to identify their attributes
+      from the outside. <i class="default">fill in details</i></li>
+
+    </ul>
+
+    <h2>More Control for Users and Build File Writers</h2>
+
+    <p>Ant2 will use a <code>BuildListener</code> concept similar to
+    the one of Ant1 but may provide a richer set of events. It will be
+    possible to attach and detach listeners to a build process from
+    within the build file and to modify the behavior of attached
+    listeners.</p>
+
+    <p>In Ant1 users have little control over how things work.  There
+    are a couple of magic properties to make Ant chose a preferred
+    compiler or modify the CLASSPATH, but they are barely documented.
+    If users want to set these properties for every build process,
+    they have to learn the undocumented tricks of the
+    <code>ANT_OPTS</code> environment variable or the
+    <code>~/.antrc</code> file.</p>
+
+    <p>Ant2 will have a well defined system to specify user
+    preferences.  This system will not only let user chose their
+    compiler but also give them a chance to provide default values for
+    attributes (say you always want the <code>debug</code> attribute
+    of the <code>javac</code> task to be true - unless it has been
+    disabled explicitly). <i class="comment">Need to give details once
+    they've been sorted out.</i></p>
+
+    <h2>Documentation System</h2>
+
+    <p>All tasks will be documented in XML files using a common DTD <i
+    class="comment">Still need to define it</i> - task libraries are
+    expected to include the documentation using this DTD inside the
+    library itself.</p>
+
+    <h2>Better Subbuild Handling</h2>
+
+    <p class="comment">Is there something beyond &quot;should become
+    better&quot; right now?</p>
+
+    <h2>Data Types</h2>
+
+    <p>Ant1 supports a limited set of data types (fileset, patternset
+    and path) and at least up to Ant 1.3 it is not possible to
+    register custom data types without writing a task that does this.
+    Ant2 will provide a built-in mechanism to define new data
+    types.</p>
+
+    <p>Existing data-types will be improved, the files in a fileset
+    can be chosen based on more than just pattern matching for example
+    (modification time or permissions for example).  Ant2 will have
+    built-in tasks for set operations.</p>
+
+    <p>Data types and properties will share the same name space and
+    follow the same scoping and precedence rules. 
+    <i class="comment">${} again.</i></p>
+
+    <h2>Multi-Threading of Tasks Within a Target</h2>
+
+    <p>It will be possible to run several tasks in parallel - these
+    tasks will belong to the same target and all tasks will be joined
+    at the end of the target.</p>
+
+    <h2>Internationalization</h2>
+
+    <p>Ant2 itself will provide internationalized (error) messages and
+    provide utility classes to help task writers to do the same.  
+    <i class="comment">These utility classes may very well come from a
+    different (Jakarta) project</i>.</p>
+
+    <p>Ant's primary language and the language of the build file
+    will continue to be English.</p>
+
+    <h1>Rejected Features</h1>
+
+    <p>This is list is not complete, it just highlights some of the
+    rejected features and tries to explain why they've been
+    rejected.  Two very common reasons to reject something were, that
+    the request has been too vague or the same functionality could
+    already be provided by some other accepted new feature.</p>
+
+    <p>For a complete listing of all requested features, see <a
+    href="requested-features.html">requested-features.html</a>. The
+    discussion on all topics can be followed in the <a
+    href="http://marc.theaimsgroup.com/?l=ant-dev&r=1&w=2">archives
+    for ant-dev</a> in threads starting from 2001-03-21 - the subject
+    lines contained either <code>[VOTE]</code> or
+    <code>[DISC]</code>.</p>
+
+    <h2>Simple Flow-Control</h2>
+
+    <p>People asking for these kind of things have often heard the
+    standard "Ant shall not become yet another scripting language, Ant
+    shall not fall into the same traps make/Perl did ..." response
+    from the committers and some long-term ant-dev people.</p>
+
+    <p>The long version of that answer is:</p>
+
+    <ul>
+      <li>There are lots of open source scripting languages, there is
+      no need to define a new one.</li>
+
+      <li>Ant has been created to be a build tool.  While you can use
+      it for a whole lot of other things, this is not Ant's primary
+      focus (and it shouldn't be).  Most use-cases that ask for
+      flow-control are out of Ant's scope.</li>
+
+      <li>Ant already provides the requested functionality for many
+      common situations.  The execon and apply tasks can be used to
+      iterate over a set of files as the (planed for Ant2) javaon and
+      anton tasks will do.</li>
+
+      <li>Providing flow-control inside Ant's core would increase the
+      complexity of this core.  This would make it difficult for new
+      contributors to understand how Ant works and increase the
+      maintenance cost for Ant at the same time.  The goal of the Ant
+      developers is to push as much complexity and functionality out
+      of Ant's core into the tasks as possible.</li>
+    </ul>
+
+    <p>That being said, Ant2 will make it easy to write iteration or
+    conditional tasks via the new container task concept.  We expect
+    foreach, switch and if tasks to be written, but they will probably
+    not become core parts of the Ant distribution.</p>
+
+    <h2>Advanced Conditionals for if/unless Attributes</h2>
+
+    <p>The argument here is the same as for flow-control.  We are
+    talking about complexity that can be pushed from the core to tasks
+    - and that is what will be done.  Instead of additional power for
+    the if/unless attributes, Ant2 will have a new task that can set
+    properties based on the values of other properties or logical
+    combinations of other conditions, something like (making up
+    syntax):</p>
+
+<pre>
+&lt;condition name=&quot;javamail-complete&quot;&gt;
+  &lt;and&gt;
+    &lt;available class=&quot;javax.mail.Transport&quot;/&gt;
+    &lt;available class=&quot;javax.activation.DataHandler&quot;/&gt;
+  &lt;/and&gt;
+&lt;/condition&gt;
+</pre>
+
+    <p>will become possible</p>
+
+    <h2>Multi-Threaded Execution of Targets</h2>
+
+    <p>The general feeling was, that the combination of target
+    dependencies and multi-threading would soon become too complex,
+    especially since Ant2 will allow people to explicitly enforce the
+    order in which (independent) targets will be executed.</p>
+
+    <p>This issue will be explored again later, it has not been
+    rejected for all time being, but it is out of scope for
+    Ant&nbsp;2.0</p>
+
+    <h1>Ideas for New Tasks and Tools</h1>
+
+    <p>Please refer to <a
+    href="requested-features.html">requested-features.html</a> in the
+    section &quot;I. Things that don't affect the core but are
+    requests for new tasks or enhancements to existing tasks.&quot;
+    for this.</p>
+
+  </body>
+</html>
diff --git a/trunk/docs/ant2/original-specification.html b/trunk/docs/ant2/original-specification.html
new file mode 100644
index 0000000..9c13e9c
--- /dev/null
+++ b/trunk/docs/ant2/original-specification.html
@@ -0,0 +1,294 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "strict.dtd">
+<HTML> 
+  <HEAD> 
+	 <TITLE>Ant Specification, version 0.5</TITLE> 
+  </HEAD> 
+  <BODY> 
+	 <H1>Ant Specification</H1> 
+	 <P>Version 0.5 (2000/04/20)</P> 
+	 <P>This document specifies the behavior of Ant. At this time, this is a
+		working document with no implementation. It is hoped that this specification
+		will lead to a simplier and more consistent implementation of Ant.</P> 
+	 <P>This document is not intended to be used as an end user manual or user
+		guide to Ant. To adequatly explain the concepts herein in a way appropriate to
+		such a use would potentially complicate this document.</P> 
+	 <H2>Design Goals</H2> 
+	 <P>The following are the overall design goals of Ant:</P> 
+	 <UL> 
+		<LI>Simplicity</LI> 
+		<LI>Understandability</LI> 
+		<LI>Extensibility</LI> 
+	 </UL> 
+	 <H3>Simplicity</H3> 
+	 <P>Ant must be simple to use. Of course, as the definition of simple varies
+		according to the audience of the program. For Ant, since it is a build tool
+		aimed at programmers, the goal is to be simple to use for a competent
+		programmer.</P> 
+	 <H3>Understandability</H3> 
+	 <P>Ant must be clearly understandible for a first time as well as a veteran
+		user. This means that a new user should be able to use Ant comfortably the
+		first time and understand how to modify a build file by looking at it. And it
+		should not require much experience with Ant to understand how it works and how
+		to configure it for particular situtations.</P> 
+	 <H3>Extensibility</H3> 
+	 <P>Ant must be easy to extend. The API used to extend Ant must be easy to
+		use and the way in which these extensions are located and used by the core
+		runtime should be clear.</P> 
+	 <H2>Conceptual Overview</H2> 
+	 <P>This is a conceptual overview of the components used by Ant. Full APIs
+		will be defined later.</P> 
+	 <H3>Project</H3> 
+	 <P>The base unit of work in Ant is the <STRONG>Project</STRONG>. A Project
+		is defined by an editable text file and is represented by an object of type
+		<CODE>org.apache.ant.Project</CODE> at runtime.</P> 
+	 <P>A Project is a collection of <STRONG>Properties</STRONG> and
+		<STRONG>Targets</STRONG>.</P> 
+	 <H3>Properties</H3> 
+	 <P>Properties are mutable name-value pairs that are scoped to the Project
+		and held in a table. Only one pair is allowed per name. It is anticipated that
+		this data structure would be of type <CODE>java.util.Properties</CODE> or a type that has approximatly
+		the same contract.</P> 
+	 <P>Properties can be defined in a hierarchical manner. The order of
+		precidence in this hiearchy is:</P> 
+	 <UL> 
+		<LI>Properties defined on the command line or via a GUI tool</LI> 
+		<LI>Properties defined in the text file which defines the project.</LI> 
+		<LI>Properties defined in a file in the users <CODE>user.home</CODE> directory</LI> 
+		<LI>Properties defined in the installation directory that can be shared
+		  by multiple users.</LI> 
+	 </UL> 
+	 <P>Note: The current version of Ant allows the System property list to be
+		consulted for a return value if the property list doesn't satisfy the requested
+		property name. As all Java code has access to the system property list via the
+		<CODE>java.lang.System</CODE> class, this functionality is considered to be confusing and to be
+		removed.</P> 
+	 <P>Note: The current version of Ant allows property substitution to be
+		performed in the project file. This functionality is being removed.</P> 
+	 <H3>Targets</H3> 
+	 <P>Targets are ordered collections of <STRONG>Tasks</STRONG>, units of work
+		to be performed if a Target is executed. </P> 
+	 <P>Targets can define dependancies on other Targets within the Project. If
+		a Target is deemed to be executed, either directly on the command line, or via
+		a dependancy from some other Target, then all of its dependencies must first be
+		executed. Circular depenancies are resolved by examination of the dependancy
+		stack when a Target is evaluated. If a dependancy is already on the stack of
+		targets to be executed, then the dependancy is considered to have been
+		satisfied.</P> 
+	 <P>After all dependancies of a Target have been satisfied, all of the Tasks
+		contained by the target are configured and executed in sequential order. </P> 
+	 <H3>Tasks</H3> 
+	 <P>A Task is a unit of work. When a Task is to be executed, an instance of
+		the class that defines the behavior of the particular task specified is
+		instantiated and then configured. This class implements the <CODE>org.apache.ant.Task</CODE> interface.
+		It is then executed so that it may be able to perform its function. It is
+		important to note that this configuration occurs just before execution of the
+		task, and after execution of any previous tasks, so that configuration
+		information that was modified by any other Task can be properly set.</P> 
+	 <P>When a Task is executed, it is provided access to the object
+		representing the Project it is running in allowing it to examine the Property
+		list of the project and access to various methods needed to operate.</P> 
+	 <H2>Task Jar Layout</H2> 
+	 <P>Tasks are defined within Java Archive files. The name of the JAR
+		determines the name under which the task is known by in the system. For
+		example, if a Task JAR is named mvdir.jar, the task is known to the system as
+		<CODE>&quot;mvdir&quot;</CODE>.</P> 
+	 <P><EM>Question: Should we say that tasks belong in a JAR file with the
+		.tsk extension?</EM></P> 
+	 <P>The class within the Jar file that implements the <CODE>org.apache.ant.Task</CODE> interface is
+		specified by a manifest attribute named <CODE>Ant-Task-Class</CODE> in the Jar manifest. An example
+		manifest would look like:</P> 
+	 <PRE>    Manifest-Version: 1.0
+    Ant-Task-Class: org.apache.ant.task.javac.JavacTask</PRE> 
+	 <P>When the task is used by Ant, a class loader is created that reads
+		classes from the JAR file. This ensures that there is no chance of namespace
+		collision in the classes of various task JAR files.</P> 
+	 <H2>Installation</H2> 
+	 <P>When Ant is installed on a user system, it installs a directory
+		structure with the following form:</P> 
+	 <PRE>&lt;installdir&gt;/ant      (unix shell script)
+            /ant.bat
+            /ant.jar
+            /ant.properties
+            /tasks/[task jar files]
+            /docs/[documentation]
+            /README</PRE> 
+	 <P>Note: Current Jakarta practice is to name the Unix shell script with a
+		.sh extension. This goes against Unix conventions and is unecessary. Testing
+		has shown that the leaving the extension off on Unix will not interfere with
+		the working of the Windows batch file.</P>
+	 <P>Note: The ant.jar file has been moved from the lib/ directory and placed
+		alongside the shell startup scripts (which have also been moved out of the bin/
+		directory). This is because on windows platforms, the .jar file is an
+		executable file of sorts.</P> 
+	 <H3>Ant Properties</H3> 
+	 <P>The <CODE>ant.properties</CODE> file contains a list of all the properties that should be
+		set by default when ant is run. In addition there are a few special properties
+		that are used directly by ant. An example of these properties in use is:</P> 
+	 <PRE>    system.taskdir=tasks/
+    user.taskdir=anttasks/</PRE> 
+	 <P>The <CODE>system.taskdir</CODE> property sets where the system looks for Java ARchive files
+		containing tasks. If this property defines a relative path, then the path is
+		taken as relative from the installation directory.</P> 
+	 <P>The <CODE>user.taskdir</CODE> property defines where users can locate Java Archive files
+		containing tasks. If this property defines a realtive path, then the path is
+		taken as relative from the users home directory (as defined by the <CODE>user.home</CODE>
+		system property). Task JAR files in this directory take precendence of those in
+		the system directory.</P>
+	 <P>Note: <EM>It has been suggested to add a properties file hook to the
+		command line to roll in props. Pending investigation.</EM></P> 
+	 <H3>User Preferences</H3> 
+	 <P>In addition to the Ant installation directory, an <CODE>ant.properties</CODE> file can be
+		located in the user's home directory (as found by the system property <CODE>user.home</CODE>)
+		which can define user preferences such as the location of a user tasks
+		directory. Properties defined in this file take precidence over those set in
+		the installation's <CODE>ant.properties</CODE> file. Such a file could look like:</P> 
+	 <PRE>    user.taskdir=anttasks/
+    javac.debug=off</PRE> 
+	 <P>Properties starting with <CODE>&quot;system.&quot;</CODE> in the user's <CODE>ant.properties</CODE> file are not
+		allowed and must cause a warning to be thrown.</P> 
+	 <H2>Project Configuration</H2> 
+	 <P>Ant's Project text file is structured using XML and reflects the
+		structure of the various components described in the Conceptual Overview.</P> 
+	 <P>A sample Project file:</P> 
+	 <PRE>&lt;project name=&quot;projectname&quot; defaulttarget=&quot;main&quot; taskdir=&quot;tasks/&quot;&gt;
+  &lt;property name=&quot;javac.debug&quot; value=&quot;on&quot;/&gt;
+  &lt;target name=&quot;main&quot;&gt;
+    &lt;taskimpl ...&gt;
+       ...
+    &lt;/taskimpl&gt;
+  &lt;/target&gt;
+&lt;/project&gt;</PRE> 
+	 <H3>The Project Element</H3> 
+	 <P>The <CODE>project</CODE> element has the following required attributes:</P> 
+	 <UL> 
+		<LI><CODE><STRONG>defaulttarget</STRONG></CODE> defining the default target to be executed if no other target
+		  is specified when Ant is run</LI> 
+	 </UL> 
+	 <P>It also has the following optional allowed attributes:</P> 
+	 <UL> 
+		<LI><CODE><CODE><STRONG>name</STRONG></CODE></CODE> defining a name for this project</LI> 
+		<LI><CODE><STRONG>taskdir</STRONG></CODE> defining a directory in which project specific tasks can be
+		  located. Tasks in this directory take precedence over those in the either the
+		  user taskdir or the installation taskdir.</LI> 
+	 </UL> 
+	 <P>The following elements are allowed as children of the project
+		element:</P> 
+	 <UL> 
+		<LI><CODE><STRONG>property</STRONG></CODE> defining a property scoped to the project</LI> 
+		<LI><CODE><STRONG>target</STRONG></CODE> defining a target</LI>
+	 </UL>
+	 <H3>The Property Element</H3>
+	 <P>asdf</P>
+	 <H3>The Target Element</H3>
+	 <P>asfd</P> 
+	 <H2>Configuration of Tasks</H2> 
+	 <P>The Task section of the configuration file is structured as such:</P> 
+	 <PRE>  &lt;[taskname] [attname=value] [attname=value]...]&gt;
+    [&lt;[elementname] [attname=value] ...&gt; ... &lt;/[elementname]&gt;]
+  &lt;/[taskname]&gt;</PRE> 
+	 <P>The taskname is used to find the class of the Task. Once the class has
+		been located and an instance of it created, all of the attributes of the Task
+		are reflected into the task instance using bean patterns. For example, if a
+		Task contains an attribute named &quot;directory&quot;, the method named
+		setDirectory would be called with the attribute value cast to the appropriate
+		type desired by the method. <EM>(What to do if the type isn't a file or a
+		simple type, look for the class and see if it has a setString method?)</EM></P>
+	 
+	 <P>Text blocks contained by the element are added to task using an addText
+		method. <EM>Place an example...</EM></P> 
+	 <P>For each element contained in the Task definition, an addElementname
+		method is found on the task. The parameter type of the method defines an object
+		that will be loaded and instantiated. The attributes of the element are
+		reflected into the object using bean methods. Any text is set using the addText
+		method. Any elements are recursed in the same fashion.</P>
+	 <P>Search order of tasks.... project/user/system</P> 
+	 <H2>Command Line</H2> 
+	 <P>The command line utility provided with Ant must support the following
+		allowable syntax:</P> 
+	 <P><CODE>ant projectfile [prop=value [prop=value...]] [target]</CODE></P>
+	 <P>Internally, the command line shell scripts should call the <CODE>org.apache.ant.Main</CODE> class
+		with the following arguments:</P>
+	 <PRE>java -Dant.home=installdir org.apache.ant.Main $*</PRE>
+	 <P>or its equivalent on the host platform. Note that the ant installation
+		directory is a System property. The above syntax results in ant.home being
+		placed in the System property list.</P>
+	 <P>Note: <EM>On unix, finding the directory of the script that was launched
+		is relatively easy. However on Windows, I'm not sure the best way of handling
+		this.</EM></P> 
+	 <H2>File Naming Conventions</H2> 
+	 <P>File naming in a cross platform tool is tricky. For maximum portability
+		and understandiblity it is recommended that project files use the following
+		conventions:</P> 
+	 <UL> 
+		<LI>The '/' character is used as a directory seperator</LI> 
+		<LI>The ':' character is used as a path seperator</LI> 
+		<LI>Only relative paths are used</LI> 
+	 </UL> 
+	 <P>However, to allow for maximum flexibility and to allow project authors
+		to use conventions that make sense on their native platform, Ant allows for a
+		representation of file names which has the following rules:</P> 
+	 <UL> 
+		<LI>Directories are seperated by the forward slash ('/') or backwards
+		  slash ('\') character.</LI> 
+		<LI>File names starting with either of the above directory seperators are
+		  considered to be absolute paths.</LI> 
+		<LI>On systems that support multiple file roots (e.g. Windows), a file
+		  name that starts with a single alphabetical character followed by a colon (':')
+		  followed by a directory seperator defines an absolute path where the letter
+		  corresponds with a directory root.</LI> 
+		<LI>File names starting with any other character are considered to be
+		  relative paths. In project files, all relative paths are resolved relative to
+		  the directory in which the project file is located.</LI> 
+	 </UL> 
+	 <P>Absolute paths are not recommended for build files as they reduce the
+		ability to share a project between u sers or machines.</P> 
+	 <P>In situtations where a set of filenames need to be specified, such as
+		defining a classpath, both the colon (':') andsemicolon (';') are allowable
+		characters to seperate each filename. The only case that has to be
+		disambiguated is if a user specifies paths that contain windows style absolute
+		paths. In this case, the colon is not treated as a path seperator if the
+		following rules are met:</P> 
+	 <UL> 
+		<LI>The character two places before the colon is either of the allowable
+		  path seperators (':' or ';') or if the colon is the second character of the
+		  string.</LI> 
+		<LI>The character immediately before the colon is a alphabetic character
+		  in the range a-z or A-Z.</LI> 
+		<LI>The character immediately after the colon is either of the allowable
+		  directory seperators ('/' or '\').</LI> 
+	 </UL> 
+	 <H2>Scripting Model</H2> 
+	 <P>Sam, I'm leaving this to you. </P>
+	 <H2>Runtime Requirements</H2>
+	 <P>The following requirements are system requirements that Ant should have
+		in order to run correctly. We should not bundle in any of these into the
+		distribution of ant.</P>
+	 <UL>
+		<LI>JDK 1.1 or greater</LI>
+		<LI>A JAXP compliant parser on the classpath</LI>
+	 </UL>
+	 <P>Note: <EM>When running on JDK 1.2 or greater, the tools.jar isn't on the
+		classpath by default. There's a few different ways we can take care of this.
+		One is to put it on the classpath in the execute script (I don't like this
+		one). Another is to find the location of tools.jar at runtime and put it on the
+		classpath of class loaders that load in task.jars so that, at least in the
+		scope of the Tasks, the relevant classes are there. </EM></P>
+	 <P></P> 
+	 <P></P> </BODY>
+</HTML>
diff --git a/trunk/docs/ant2/requested-features.html b/trunk/docs/ant2/requested-features.html
new file mode 100644
index 0000000..b6aa8ab
--- /dev/null
+++ b/trunk/docs/ant2/requested-features.html
@@ -0,0 +1,1106 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<body>
+
+<h2>
+<center>Requested Features for Ant2</center>
+</h2>
+
+<h4>
+I. Things that don't affect the core but are requests for new tasks or
+enhancements to existing tasks.
+</h4>
+
+&quot;Accepted&quot; for a task doesn't mean that
+task will be a core task (or even be supplied by a voter), just that having
+it (as an optional task) would be acceptable.
+<p>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Add a new datatype filterset to group token-filters.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make usage of particular filters/filtersets explicit in copy tasks.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make facade tasks for things like <code>&lt;javac&gt;</code>
+(JikesImpl, ModernImpl, etc.).
+(One candidate is <code>&lt;jar&gt;</code>, with implementations for
+a <code>&lt;fastjar&gt;</code>, for example.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Unify multiple similar tasks to use similar forms (eg., all the
+<code>&lt;javacc&gt;</code>-type
+tools).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Obfuscating task.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Better scripting/notification support so the hooks are available to
+send notifications at certain times.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Add an <code>&lt;ant&gt;</code> task that will find build files according
+to a fileset and invoke a common target in them. (<code>&lt;anton&gt;</code>?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Add a JavaApply task that executes a given class with files from a
+fileset as arguments (similar to <code>&lt;apply&gt;</code>).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Include some more sophisticated loggers with the Ant distribution &#150;
+especially for sending emails. Make the existing one more flexible
+(stylesheet used by XmlLogger). (Could be part of the same module tasks
+would be developed in?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Better docs (eg., more examples, tutorials, beginner documents, reference
+sheets for tasks, printable version, etc.).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+RPM task.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Task for splitting files (head/tail/split-like functionality).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Task to create XMI from Java.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Socksified networking tasks, SSH tasks.
+(Peter Donald expressed some legal concerns that might need to be overcome, 
+depending on the implementation.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+A reachable task that works much like <code>&lt;available&gt;</code>,
+for network URLs.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Task to extract classes from a jar-file that a given class depends on.
+(Based on <code>&lt;depend&gt;</code> or IBM's JAX, for example.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Unify <code>&lt;available&gt;</code> and <code>&lt;uptodate&gt;</code>
+into a more general
+<code>&lt;condition&gt;</code> task &#150; support
+<code>AND</code>/<code>OR</code> of
+several tests here.
+(Will need more discussion because of vote by Peter Donald.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+JSP-compilation task. (Sounds like a candidate for a facade task.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+URL-spider task that checks links for missing content or server errors.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+<blockquote>
+<ul><li>
+Make the default logger's output clear, informative, and terse. (Rejectors
+think it already is.)
+</blockquote>
+</li></ul>
+
+<blockquote>
+<ul><li>
+Add an attribute to <code>&lt;property&gt;</code> to read in an entire file
+as the value of a property.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make PATH-handling consistent. Every task that has a PATH attribute
+must also accept references to PATHs.
+</li></ul>
+</blockquote>
+
+<br>
+<h4>
+II. Goals that need to be abstract until we get into design
+decisions.
+</h4>
+
+During the discussion it became obvious that some things from this list
+are goals for Ant and some should be guidelines for developers.
+Therefore, there are two flavors, &quot;Accepted&quot; and
+&quot;Accepted As Guideline&quot;.
+<p>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Provide a clear mission statement for Ant.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Main goals<b>:</b> simplicity, understandability, extensibility.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Remove magic properties if at all humanly possible.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Remove as much dependency on native scripts as possible.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Clean object model (ie., Project/Target/Task).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Good event model to integrate well with IDE/GUI/etc.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Use a consistent naming scheme for attributes across all tasks.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Keep build-file syntax as compatible to Ant1 as possible
+(ie., don't break something just because we can).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Keep the interface for tasks as similar to that of Ant1 as
+possible (ie., don't break something just because we can).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Ant should be cancelable.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted As Guideline</b>
+</font>
+
+<blockquote>
+<ul><li>
+No commit of new features without documentation.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+No commit of new features without test-cases.
+</li></ul>
+</blockquote>
+
+<br>
+<h4>
+III. Things that are simple and easy to implement, where we expect the
+committers to agree.
+</h4>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Namespace support so different concerns can occupy different namespaces
+from Ant (thus, SAX2/JAXP1.1).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Java2
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Remove all deprecated methods, attributes, tasks.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow all datatypes to be defined anywhere (ie., as children of
+project as well as of target).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make properties fully dynamic (ie., allow their value to be reassigned).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Unify the namespace of all data types (ie., properties + filesets +
+patternsets + filtersets).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Add a user-defined message if a target will be skipped as a
+result of the specified <code>if/unless</code>.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow user datatypes to be defined via a <code>&lt;typedef&gt;</code>
+similar to <code>&lt;taskdef&gt;</code>.
+</li></ul>
+</blockquote>
+
+<br>
+<h4>
+IV. Things we probably agree on but need to discuss the details or
+decide between several possible options.
+</h4>
+
+&quot;Accepted&quot; means the goal/idea is fine, not that a decision on a
+particular implementation has been made.
+<p>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+The ability for GUI/IDE tools to integrate easily with object model
+without reinventing the wheel and writing their own parser (which
+Antidote was forced to do). 
+(Two suggested solutions were allowing GUI developers to extend
+the object model (ie., GUITask extends Task) or to have Task as an
+interface (ie., GUITask implements Task). This way, the GUI tasks could
+be W3C DOM elements, have property vetoers/listeners, etc.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Support for numerous front-ends &#150; from command-line over GUI to servlets.
+(Corollary of the above?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Fully interpreted at run-time. (This almost requires some form of
+abstraction/proxy that stands in place of tasks till it is
+interpreted. This can be hash-tables/simple DOM-like model/whatever.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide utility classes to aid in building tasks (ie., like
+<code>&lt;uptodate&gt;</code> functionality abstracted).
+(Need to become more specific here.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make ant-call a low-cost operation so it can do certain
+optional/template-like operations.
+(Corollary of "fully interpreted at run-time"?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow facilities to build projects from multiple sources (ie., CSS+XML,
+XSLT+XML, Velocity+text or database, from inside jars or normal 
+<code>build.xml</code> files, etc.)
+(Allow the project tree to be built dynamically.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Move to a system that allows docs to be generated &#150; doc snippets
+should be included with the tasks they document.
+(Which DTD? Which tools for generation?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow tasks to be loaded from jars. (Use
+either an XML file in <code>TSK-INF/taskdefs.xml</code> or a
+manifest file.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow documentation to be stored in <code>.tsk</code> jars.
+(Corollary of the above two points?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Separate tasks into <code>.tsk</code> jars somehow.
+(Decide on categories.
+Probably via function &#150; ie., java tasks, file tasks, EJB tasks, etc.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make having separate build-files easy (<i>&#224; la</i> AntFarm) and importing different
+projects a breeze.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide support for user-defined task configurations &#150; (ie., give
+users the ability to specify a default value for attributes (eg., always
+use <code>debug="true"</code> in <code>&lt;javac&gt;</code> unless
+something else has been specified). 
+(Three ideas so far<b>:</b> a CSS-like language,
+a <code>&lt;taskconfig&gt;</code> element, or
+properties following a specific naming scheme.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Support more control over the properties that are going to be passed
+to subprojects (modules).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Task to prompt for user input.
+(Does affect core, as we need a means to request input from the front-end.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Add CVS login feature.
+(Requires handling of user input.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Easier installation process. GUI, maybe webstart from the homepage.
+This includes asking the user whether he wants to use optional tasks
+and downloads the required libs, automatic upgrades and so on.
+
+Self-extracting jar installer<b>:</b>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<code>java -jar jakarta-ant-1.3-bin.jar</code>
+<br>
+Prompts for destination directory, extracts archive, fixes all 
+text files with <code>&lt;fixCRLF&gt;</code> task<b>;</b> on UNIX,
+makes scripts executable.  
+Could also modify ant scripts with the location of <code>ANT_HOME</code>.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Logo for Ant.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Detach Ant from <code>System.err</code>/<code>.in</code>/<code>.out</code>.
+(Beware of problems with spawned processes.)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Build-files should be declarative in nature.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+<blockquote>
+<ul><li>
+It should be possible to modify details of the actual build (e.g. classpath,
+compiler used, etc.) without the need to change the build specification.
+(Do <code>build.compiler</code> and <code>build.sysclasspath</code>
+cover everything, or do we need to add more stuff like this?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Better sub-project handling
+(whatever that means in detail).
+</li></ul>
+</blockquote>
+
+<br>
+<h4>
+V. Things we probably don't agree on. 
+</h4>
+<i><b>Datatypes</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Allow <code>&lt;include&gt;/&lt;exclude&gt;</code>
+to work with multiple characteristerics of a file
+(ie., include into fileset if file is readable, modified after 29th of Feb,
+has a name that matches the pattern <code>&quot;**/*.java&quot;</code> and
+the property <code>foo.present</code> is set. Something similar to<b>:</b>
+<pre>
+  &lt;include&gt;
+    &lt;item-filter type="name" value="**/*.java"/&gt;
+    &lt;item-filter type="permission" value="r"/&gt;
+    &lt;!-- could optionally be directory or some other system specific features --&gt;
+    &lt;item-filter type="type" value="file"/&gt;
+    &lt;item-filter type="modify-time"
+                 operation="greater-than" 
+                 value="29th Feb 2003"/&gt;
+  &lt;/include&gt;
+</pre>
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide support for non-hardwired (ie., loadable) low-level 
+components (mappers/itemset-filters/converters). Allow them to be 
+loaded in either globally or via a new classloader.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide support for non-hardwired (ie., loadable) converters.
+<br>
+Q<b>:</b> What is a converter? Is this an implementation detail?
+<br>
+A<b>:</b> Not an implementation detail, but a way to extend the engine
+to convert more datatypes. Currently, we have a fixed set that is 
+expanded on occasion (ie., includes primitive types + File). Instead
+of spreading converting code throughout the tasks, it can be centralized 
+into one component and used by the engine. This becomes particularly 
+relevent if you build Ant-based testing systems and use Ant in certain
+web-related areas.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Set-arithmetic for fileset/patternset/*set.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Inheritance of Ant properties/datatypes/context/etc. in project hierarchy.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Allow mappers to be genericized so that particular features can be modified 
+during mapping. Something similar to<b>:</b>
+<pre>
+  &lt;fileset ...&gt;
+    &lt;include name="*.sh"/&gt;
+    &lt;mapper type="unix-permissions"&gt;
+      &lt;param name="user" value="ant"/&gt;
+      &lt;param name="group" value="ant"/&gt;
+      &lt;param name="mod" value="755"/&gt;
+    &lt;/mapper&gt;
+  &lt;/fileset&gt;
+</pre>
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide datatypes through property tag and remove need for separate
+free-standing entities. That is<b>:</b><br>
+<pre>
+  &lt;property name="foo"&gt;
+    &lt;fileset dir="blah"&gt;
+      &lt;include name="*/**.java" /&gt;
+    &lt;/fileset&gt;
+  &lt;/property&gt;
+</pre>
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make all datatypes interfaces to allow them to be customized in many
+ways.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Inheritance between Ant datatypes (ie., fileset A inherits from
+fileset B (includes all entries in A).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Homogenize notion of PATHs and filesets.
+</li></ul>
+</blockquote>
+
+<i><b>Ant's goals</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Provide support for CJAN.
+<br>
+Q: In what way?<br>
+A: Probably by supplying a set of tasks that download versioned 
+binaries and their associated dependencies, caching the downloads
+in a known place and updating binaries when required.
+(&quot;When required&quot; being indicated by a change in property values).
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b> (as a primary goal)
+</font>
+
+<blockquote>
+<ul><li>
+Make it possible to re-use the task engine for other things
+(ie., Installshield-type app, Peter's cron-server, and other task-based
+operations).
+</li></ul>
+</blockquote>
+
+<i><b>Class-loading</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Force resolution of classes on loading, to identify class-loader 
+issues early (at least in global classloader).
+</li></ul>
+</blockquote>
+
+
+<blockquote>
+<ul><li>
+Ignore any classes contained in the damned ext dirs of a
+JVM &#150; possibly by launching with something like<b>:</b>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<code>jar -Djava.ext.dir=foo -jar ant.jar</code>
+<br>
+(Accepted if optional.)
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Workspace/sub-build issues</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Create the concept of workspace so that projects can be built in a
+DAG and thus enable projects like Catalina/Tomcat to have an easy
+build process. It also helps CJAN to a lesser degree and would
+partially solve the jars-in-CVS thing.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow a target to depend on a target in another build-file.  
+</li></ul>
+</blockquote>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Project inheritance. (What's this?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Target inheritance. That is, the ability to include targets from other 
+project files, overriding them as necessary (so, cascading project
+files).
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Add an attribute to <code>&lt;ant&gt;</code> to feed back the environment
+(properties and taskdefs) from the child build to the parent.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow a target to reference properties defined in another build-file.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Documentation system</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b> (with no decision on which system to use)
+</font>
+
+<blockquote>
+<ul><li>
+Generate docs by Anakia/XSLT.
+(Corollary of "move to a system that allows docs to be generated"?)
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Task API</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Tasks provide some way to identify their attributes from the outside. 
+
+Possible solutions include a special method like <code>getProperties()</code>,
+an external describing file shipping with the task class or special
+Javadoc comments parsed by a custom doclet. Whatever the method, it
+should not impose any cost on run-time, as it is only used a small 
+percentage of the time (design-time).  
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide <code>&quot;failonerror&quot;</code>-like functionality to all tasks.
+(Provide this as an aspect?? Much like logging aspect or classloader aspect).
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Tasks should have access to its own XML representation.
+</blockquote>
+</li></ul>
+
+<blockquote>
+<ul><li>
+Task level if and unless attributes.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow tasks to find out, whether another task has completed successfully.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Logging</b></i>
+
+<blockquote>
+<ul><li>
+Allow build-file writers to modify logging (verbosity, for example)
+on a target-by-target or task-by-task basis.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make loggers configurable via build.xml.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Multi-threading</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Multi-threaded execution of tasks within the same target.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Multithreaded execution of targets.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Procedural versus purely declarative</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Simple flow-control (<code>if-then-else</code>, <code>for</code>)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Targets should be like methods, including a return value.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Build-files should be purely declarative.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Properties</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Ability to manage scoping of properties in general
+(ie., target/project/workspace).
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Templates</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+It should be possible to provide general/(template?) build
+specifications, and to declare, for a concrete item, that it should be
+built according to such a general specification.
+</ul></li>
+</blockquote>
+
+<p>
+<i><b>XML issues</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+A built-in mechanism to include build-file fragments &#150; something
+that doesn't use <code>SYSTEM</code> entities at all and therefore is
+XSchema-friendly, allows for property expansions, etc.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Allow Ant to farm out attributes and elements that are <i>not</i>
+in the Ant namespace to other components (ie., hand <code>doc:</code> elements
+to the Documentation component or <code>log:</code> attributes to the Log
+policy component, etc.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Let Ant ignore &#150; but warn &#150; if unknown XML elements or attributes
+occur in a build-file.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Core extensions</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Allow sequence to be specified in <code>&quot;depends&quot;</code> attribute,
+or enhance <code>&lt;antcall&gt;</code> to work with current list of executed
+targets.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Provide a way to define the order in which targets that a given target
+depends upon get executed. (Same as above?)
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Support nesting tasks into other elements &#150; not just as children of
+target &#150; as proposed by Thomas Christen in
+<a href http://marc.theaimsgroup.com/?l=ant-dev&m=98130655812010&w=2>
+his mail message</a>.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Define task contexts that define various common aspects (logging,
+failure handling, etc.), and assign them to tasks.
+</li></ul>
+</blockquote>
+
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Allow named tasks to be defined by <code>&lt;script&gt;</code> elements.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Specify an OnFail task or target that runs in case of a build
+failure.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Make <code>if/unless</code> attributes check for the value of a property, not
+only its existance.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Check for more than one condition in <code>if/unless</code> attributes.
+</li></ul>
+</blockquote>
+
+<p>
+<i><b>Organization</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Separate CVSes and code hierarchies for<b>:</b>
+</li></ul>
+<ul type="circle">
+<li>task engine [org.apache.task.*]</li>
+<li>project engine (ie., model of targets/projects/workspaces) +
+support/utility classes [org.apache.ant.*]</li>
+<li>core tasks (ie., tasks supported by Ant contributors) [org.apache.???]</li>
+</ul>
+</blockquote>
+
+<p>
+<i><b>Miscellaneous</b></i>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Accepted</b>
+</font>
+
+<blockquote>
+<ul><li>
+Internationalization.
+</li></ul>
+</blockquote>
+
+<p>
+<h4>
+VI. Things that were submitted late
+</h4>
+
+<p>
+<font face="Arial, Helvetica, sans-serif" size="-1">
+&nbsp;&nbsp;<b>Rejected</b>
+</font>
+
+<blockquote>
+<ul><li>
+Integration of the <code>&lt;depend&gt;</code> and <code>&lt;javac&gt;</code>
+tasks.
+</li></ul>
+</blockquote>
+
+<blockquote>
+<ul><li>
+Recursive property resolution (ie., resolving <code>${dist.${name}.dir}</code>)
+</li></ul>
+</blockquote>
+
+</body>
+</html>
+
diff --git a/trunk/docs/ant2/requested-features.txt b/trunk/docs/ant2/requested-features.txt
new file mode 100644
index 0000000..ba8d855
--- /dev/null
+++ b/trunk/docs/ant2/requested-features.txt
@@ -0,0 +1,782 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+Status:
+=======
+
+The committers have cast votes on all items (except those that came in
+too late) and the results are listed below - the next step will be a
+design phase.
+
+This list of items will be summarized into an Ant2 specification soon.
+
+I. Things that don't affect the core but are requests for new tasks or
+enhancements of existing tasks.
+======================================================================
+
+[ACCEPTED] for a task doesn't mean that task will be core tasks (or
+even be supplied by a voter), just that having them (as optional
+tasks) would be acceptable.
+
+* Add a new datatype filterset to group token-filters 
+
+  [ACCEPTED]
+
+* make usage of particular filters/filtersets explicit in copy tasks
+
+  [ACCEPTED]
+
+* make facade tasks for things like javac (JikesImpl, ModernImpl etc)
+
+  One candidate is jar with implementations for fastjar
+  for example.
+
+  [ACCEPTED]
+
+* unify multiple similar tasks to use similar forms (ie all the javacc
+  type tools)
+
+  [ACCEPTED]
+
+* Obfuscating task
+
+  [ACCEPTED]
+
+* Add an <ant> task that will find build files according to a fileset
+  and invokes a common target in them.
+
+  <anton>?
+
+  [will need more discussion because of votes by Peter Donald and
+                                                 Stefan Bodewig]
+
+  [finally ACCEPTED]
+
+* Add a JavaApply task that executes a given class with files from a
+  fileset as arguments - similar to <apply>.
+
+  [will need more discussion because of votes by Peter Donald and
+                                                 Stefan Bodewig]
+
+  [finally ACCEPTED]
+
+* Include some more sophisticated loggers with the Ant distribution -
+  especially for sending emails. Make the existing one more flexible
+  (stylesheet used by XmlLogger).
+
+  Could be part of the same module tasks would be developed in?
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [finally ACCEPTED]
+
+* make the default logger's output clear, informative, and terse.
+
+  Actually, this is a little bit abstract, but doesn't apply to the
+  core either.
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [REJECTED - vetoes by Conot MacNeill and Stefan Bodewig]
+
+* Better docs.
+
+  More examples. Tutorials, beginner documents, reference sheets for
+  tasks, printable version.
+
+  [ACCEPTED]
+
+* RPM task.
+
+  [ACCEPTED]
+
+* add an attribute to <property> to read in an entire file as the
+  value of a property.
+
+  [will need more discussion because of vote by Peter Donald]
+
+  [REJECTED - veto by Peter Donald]
+
+* Task for splitting files (head/tail/split like functionality).
+
+  [ACCEPTED]
+
+* Task to create XMI from Java.
+
+  [ACCEPTED]
+
+* socksified networking tasks, SSH tasks.
+
+  [Peter Donald expressed some legal concerns that might be overcome, 
+                depending on the implementation]
+
+* a reachable task that works much like available for network URLs.
+
+  [ACCEPTED]
+
+* make PATH handling consistent. Every task that has a PATH attribute
+  must also accept references to PATHs.
+
+  [will need more discussion because of vote by Stefan Bodewig]
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister and Stefan Bodewig]
+
+* Task to extract classes from a JAR file that a given class depends
+  on.
+
+  Based on <depend> or IBM's JAX for example.
+
+  [ACCEPTED]
+
+* Unify <available> and <uptodate> into a more general <condition>
+  task, support AND/OR of several tests here.
+
+  [will need more discussion because of vote by Peter Donald]
+
+* jsp-compilation task
+
+  Sounds like a candidate for a facade task.
+
+  [ACCEPTED]
+
+* URL-spider task that checks links for missing content or server errors
+
+  [ACCEPTED]
+
+II. Abstract goals that need to be abstract until we get into design
+decisions.
+======================================================================
+
+During discussion it became obvious, that some things from this list
+are goals for Ant and some should be guidelines for developers,
+therefore there are two flavors, [ACCEPTED] and [ACCEPTED AS GUIDELINE].
+
+* Provide a clear mission statement for Ant.
+
+  [ACCEPTED]
+
+* Main goals: Simplicity, Understandability, Extensibility
+
+  [ACCEPTED]
+
+* remove magic properties if at all humanly possible
+
+  [ACCEPTED]
+
+* remove as much dependency on native scripts as possible.
+
+  [ACCEPTED]
+
+* clean object model (ie Project/Target/Task)
+
+  [ACCEPTED]
+
+* good event model to integrate well with IDE/GUI/whatever
+
+  [ACCEPTED]
+
+* use a consistent naming scheme for attributes across all tasks
+
+  [ACCEPTED]
+
+* keep build file syntax as compatible to Ant1 as possible -
+  i.e. don't break something just because we can.
+
+  [ACCEPTED]
+
+* keep the interface for Tasks as similar to the one of Ant1 as
+  possible - i.e. don't break something just because we can.
+
+  [ACCEPTED]
+
+* Ant should be cancelable
+
+  [ACCEPTED]
+
+* no commit of new features without documentation
+
+  [ACCEPTED AS GUIDELINE]
+
+* no commit of new features without testcases
+
+  [ACCEPTED AS GUIDELINE]
+
+III. Things that are simple, easy to implement, where we expect the
+committers to agree
+======================================================================
+
+* namespace support so different concerns can occupy different namespaces
+  from ant (thus SAX2/JAXP1.1)
+
+  [ACCEPTED]
+
+* Java2
+
+  [ACCEPTED]
+
+* remove all deprecated methods, attributes, tasks
+
+  [ACCEPTED]
+
+* allow all datatypes to be defined anywhere - i.e. as children of
+  project as well as of target.
+
+  [ACCEPTED]
+
+* make properties fully dynamic, i.e. allow their value to be reassigned
+
+  [will need more discussion because of vote by Glenn McAllister and
+                                                Conor MacNeill]
+
+  [finally ACCEPTED]
+
+* unify the namespace of all data types (ie properties + filesets +
+  patternset + filtersets).
+
+  [ACCEPTED]
+
+* add a user defined message if a target will be skipped because the
+  if/unless attribute says so.
+
+  [ACCEPTED]
+
+* allow user-datatypes to be defined via a <typedef> similar to <taskdef>.
+
+  [ACCEPTED]
+
+IV. Things we probably agree upon but need to discuss the details or
+decide between several possible options.
+======================================================================
+
+[ACCEPTED] means, the goal/idea is fine, not that a decission on a
+particular implementation has been made.
+
+* The ability for GUI/IDE tools to integrate easily with object model
+  without reinventing the wheel and writing their own parser (which
+  antidote was forced to do). 
+
+  Two suggested solutions were allowing GUI developers to extend
+  object model (ie GUITask extends Task) or to have Task as interface
+  (ie GUITask implements Task). This way the GUI tasks could be W3C
+  DOM Elements, have property vetoers/listeners etc.
+
+  [ACCEPTED]
+
+* support for numerous frontends - from command line over GUI to servlets
+
+  corollary of the above?
+
+  [ACCEPTED]
+
+* Fully interpreted at runtime. This almost requires some form of
+  abstraction/proxy that stands in place of tasks till it is
+  interpreted.  This can be hashtables/simple dom-like model/whatever
+
+  [ACCEPTED]
+
+* provide utility classes to aid in building tasks. ie like up-to-date
+  functionality abstracted
+
+  Need to become more specific here.
+
+  [ACCEPTED]
+
+* make ant-call a low cost operations so it can certain
+  optional/template-like operations
+
+  corollary of "fully interpreted at runtime"?
+
+  [ACCEPTED]
+
+* allow facilities to build projects from multiple sources. ie CSS+xml
+  or XSLT+ XML or Velocity+text or database or from inside jars or normal 
+  build.xmls etc.
+
+  allow the project tree to be built dynamically.
+
+  [ACCEPTED]
+
+* move to a system that allows docs to be generated - doc snippets
+  should be included with the tasks they document.
+
+  Which DTD? Which tools for generation?
+
+  [ACCEPTED]
+
+* allow tasks to be loaded from jars. tasks should be indicated by
+  either xml file in TSK-INF/taskdefs.xml or manifest file.
+
+  [ACCEPTED]
+
+* allow documentation to be stored in .tsk jars
+
+  corollary of the two points above?
+
+  [ACCEPTED]
+
+* better scripting/notification support so the hooks are available to
+  send notifications at certain times.
+
+  Which hooks and where?
+
+  [will need more discussion because of vote by Peter Donald and
+                                                Simeon Fitch]
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Simeon Fitch]
+
+* separate tasks into .tsk jars somehow. (Probably via function - ie
+  java tasks, file tasks, ejb tasks).
+
+  Decide on categories.
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [finally ACCEPTED]
+
+* make separate build files easy (ala AntFarm) and importing different
+  projects a breeze
+
+  [ACCEPTED]
+
+* provide support for user defined task configurations - i.e. give
+  users the ability to specify a default value for attributes (always
+  use debug="true" in <javac> unless something else has been
+  specified). 
+
+  Three ideas so far: a CSS like language, a <taskconfig> element,
+  properties following a specific naming scheme.
+
+  [ACCEPTED]
+
+* support more control over the properties that are going to be passed
+  to subprojects (modules)
+
+  [ACCEPTED]
+
+* Ask for a new CVS module for Ant tasks.
+
+  We need to define rules for this to work - maybe the rules proposed
+  for the commons project could give us a start.
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [REJECTED - vetoes by Conor MacNeill and Glenn McAllister]
+
+* It should be possible to modify details of the actual build (e.g. classpath,
+  used compiler) without the need to change the build specification.
+
+  Do build.compiler and build.sysclasspath cover everything or do we
+  need to add more stuff like this?
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [REJECTED - veto by Conor MacNeill]
+
+* Task to prompt for user input.
+
+  Does affect core as we need a means to request input from the Frontend.
+
+  [ACCEPTED]
+
+* Add cvs login feature.
+
+  Requires handling of user input.
+
+  [ACCEPTED]
+
+* Easier installation process. GUI - maybe webstart from the homepage.
+
+  This includes asking the user whether he wants to use optional tasks
+  and downloads the required libs. Automatic upgrades and so on.
+
+  Self-extracting jar installer: java -jar jakarta-ant-1.3-bin.jar. 
+  Prompts for destination directory, extracts archive, fixes all 
+  text files with fixCRLF task; on UNIX, makes scripts executable.  
+  Could also modify ant scripts with the location of ANT_HOME.
+
+  [ACCEPTED]
+
+* Logo for Ant.
+
+  [ACCEPTED]
+
+* detach Ant from System.err/.in/.out.
+
+  Beware of problems with spawned processes.
+
+  [ACCEPTED]
+
+* better subproject handling
+
+  Whatever that means in detail.
+
+  [will need more discussion because of vote by Conor MacNeill]
+
+  [REJECTED - vetoes by Conor MacNeill and Stefan Bodewig]
+
+* build files should be declarative in nature
+
+  [ACCEPTED]
+
+V. Things we probably don't agree on. 
+======================================================================
+
+[DISC] Datatypes
+----------------
+
+ * Allow mappers to be genericised so that particular features can be modified 
+ during mapping. Something similar to 
+ 
+ <fileset ...>
+   <include name="*.sh"/>
+   <mapper type="unix-permissions">
+     <param name="user" value="ant"/>
+     <param name="group" value="ant"/>
+     <param name="mod" value="755"/>
+   </mapper>
+ </fileset>
+
+ [REJECTED - vetoes by Stefan Bodewig and Conor MacNeill, not enough
+             positive votes anyway.]
+
+ * Allow include/exclude tow work with multiple characteristerics of a file.
+ ie include into fileset if file is readable, modified after 29th of Feb,
+ has a name that matches patter "**/*.java" and the property "foo.present"
+ is set. Something similar to 
+ 
+ <include>
+   <item-filter type="name" value="**/*.java"/>
+   <item-filter type="permission" value="r"/>
+
+   <!-- could optionally be directory/or some other system specific features -->
+   <item-filter type="type" value="file"/> 
+   <item-filter type="modify-time" 
+                operation="greater-than" 
+                value="29th Feb 2003"/>
+ </include>
+
+ [ACCEPTED]
+
+* provide datatypes through property tag and remove need for separate free
+  standing entities. ie
+  <property name="foo">
+    <fileset dir="blah">
+     <include name="*/**.java" />
+    </fileset>
+  </property>
+
+  [REJECTED - only one +1 vote]
+
+* provide support for non-hardwired (ie loadable) low-level 
+ components (mappers/itemset-filters/converters). Allow them to be 
+ loaded in either global or a new classloader.
+
+  [ACCEPTED]
+
+* provide support for non-hardwired (ie loadable) converters.
+
+  Q: What is a converter? Is this an implementation detail?
+  A: Not an implementation detail but a way to extend the engine
+  to convert more data types. Currently we have fixed set that is 
+  expanded on occasion (ie includes primitive types + File). Instead
+  of spreading converting code through out tasks it can be centralized 
+  into one component and used by engine. This becomes particularly 
+  relevent if you build ant based testing systems and use ant in certain
+  web-related areas.
+
+  [ACCEPTED]
+
+* Make all datatypes interfaces to allow them to be customized in many
+  ways.
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Stefan Bodewig]
+
+* Set arithmetic for fileset/patternset/*set
+
+  [ACCEPTED]
+
+* inheritance of ant properties/datatypes/context etc in project hierarchy
+
+  [ACCEPTED]
+
+* inheritance of between ant datatypes. ie fileset A inherits from fileset B (includes 
+  all entries in A).
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Stefan Bodewig]
+
+* Homogenize notion of PATHs and filesets.
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Stefan Bodewig]
+
+[DISC] Ant's goals
+------------------
+
+* make it possible to reuse taskengine for other things. ie
+  Installshield type app, Peter's cron-server and other task based
+  operations. 
+
+  [REJECTED as a primary goal - only two +1 votes]
+
+* provide support for CJAN
+
+  Q: In what way?
+  A: Probably by supplying a set of tasks that download versioned 
+  binaries and their associated dependencies, caching the downloads
+  in a known place and updating binaries when required. ("When required"
+  being indicated by a change in property values).
+
+  [REJECTED as part of Ant's core - veto by Conor MacNeill, no single +1]
+
+[DISC] class loading
+--------------------
+
+ * force resolution of classes on loading to identify classloader 
+ issues early. (At least in global classloader).
+
+  [REJECTED - only one +1 vote]
+
+* Ignore any classes contained in the damned ext dirs of a JVM - possibly by launching
+  with something like jar -Djava.ext.dir=foo -jar ant.jar
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister and Stefan
+              Bodewig, ACCEPTED if optional]
+
+
+[DISC] workspace/subbuild issues
+--------------------------------
+
+* create the concept of workspace so that projects can be built in a
+  DAG and thus enable projects like catalina/tomcat to have an easy
+  build process. It also helps CJAN to a lesser degree and would
+  partially solve the JARs in CVS thing.
+
+  [ACCEPTED]
+
+* Project inheritance
+
+  What's this?
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Stefan Bodewig]
+
+* Target inheritance. ie The ability to include targets from other 
+  project files overidining them as necessary (so cascading project
+  files).
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald and Stefan Bodewig]
+
+* Add an attribute to <ant> to feed back the environment (properties and
+  taskdefs) from the child build to the parent.
+
+  [REJECTED - vetoes by Conor MacNeill, Peter Donald, Simeon Fitch and
+              Stefan Bodewig]
+
+* Allow a target to depend on a target which is in another buildfile.  
+
+  [ACCEPTED]
+
+* Allow a target to reference properties defined in another buildfile.
+
+  [REJECTED - only one +1 vote]
+
+[DISC] documentation system
+---------------------------
+
+* generate docs by anakia/XSLT
+
+  Corollary of "move to a system that allows docs to be generated"?
+
+  [ACCEPTED - with no decision on which system to use]
+
+[DISC] Task API
+---------------
+
+* tasks provide some way to identify their attributes from the
+  outside. 
+
+  Possible solutions include a special method like getProperties(), an
+  external describing file shipping with the task class or special
+  javadoc comments parsed by a custom doclet. Whatever the method it
+  should not impose any cost on runtime as it is only used a small 
+  proportion of the time (design-time).  
+
+  [ACCEPTED]
+
+* tasks should have access to its own XML representation.
+
+  [REJECTED - vetoes by Christoph Wilhelms, Conor MacNeill and Simeon Fitch]
+
+* Task level if and unless attributes.
+
+  [REJECTED - no single +1 vote]
+
+* Allow tasks to find out, whether another task has completed successfully.
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald
+              and Stefan Bodewig]
+
+* provide failonerror like functionality to all tasks. (Provide this as an aspect??
+  much like logging aspect or classloader aspect).
+
+  [ACCEPTED]
+
+[DISC] logging
+--------------
+
+* allow build file writers to modify logging (verbosity for example)
+  on a target by target or task by task basis.
+
+  [ACCEPTED]
+
+* Make loggers configurable via build.xml.
+
+  [ACCEPTED]
+
+[DISC] multithrading
+--------------------
+
+* Multithreaded execution of tasks within the same target.
+
+  [ACCEPTED]
+
+* Multithreaded execution of targets.
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister and Stefan Bodewig]
+
+[DISC] procedural versus purely declarative
+-------------------------------------------
+
+* Simple flow control (if-then-else, for)
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald
+              and Stefan Bodewig]
+
+* targets should be like methods including a return value
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald,
+              Simeon Fitch and Stefan Bodewig]
+
+* build files should be purely declarative
+
+  [REJECTED - veto by Stefan Bodewig]
+
+[DISC] Properties
+-----------------
+
+* Ability to manage scopping of properties in general (ie target/project/workspace).
+
+  [ACCEPTED]
+
+[DISC] Templates
+----------------
+
+* it should be possible to provide general /(template?)/ build
+  specifications, and to declare for a concrete item that it should be
+  built according to such a general specification.
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald
+              and Stefan Bodewig]
+
+[DISC] XML issues
+-----------------
+
+* a built-in mechanism to include build-file fragments - something
+  that doesn't use SYSTEM entities at all and therefore is XSchema
+  friendly, allows for property expansions ...
+
+  [ACCEPTED]
+
+* Let Ant ignore - but warn - if unknown XML elements or attributes
+  occur in a build file.
+
+  [REJECTED - vetoes by Conor MacNeill, Glenn McAllister, Peter Donald
+              and Stefan Bodewig]
+
+* Allow ant to farm out attributes and elements that are NOT in the ant 
+  namespace to other components. ie hand doc: elements to the Documentation
+  component or log: attributes to Log policy component etc
+
+  [ACCEPTED]
+
+[DISC] core extensions
+----------------------
+
+* Allow named tasks to be defined by <script> elements.
+
+  [REJECTED - only one +1 vote]
+
+* specify an onfail task or target that runs in case of a build
+  failure.
+
+  [REJECTED - vetoes by Glenn McAllister, Peter Donald and Stefan Bodewig]
+
+* allow sequence to be specified in depends attribute or enhance
+  antcall to work with current list of executed targets
+
+  [ACCEPTED]
+
+* Support nesting tasks into other elements - not just as children of
+  target - as proposed by Thomas Christen in
+  <http://marc.theaimsgroup.com/?l=ant-dev&m=98130655812010&w=2>.
+
+  [ACCEPTED]
+
+* Make if/unless attributes to check for the value of a property, not
+  only its existance.
+
+  [REJECTED - vetoes by Glenn McAllister and Stefan Bodewig]
+
+* check for more than one condition in if/unless attributes.
+
+  [REJECTED - vetoes by Glenn McAllister, Peter Donald and Stefan Bodewig]
+
+* provide a way to define the order in which targets a given target
+  depends upon get executed.
+
+  [ACCEPTED]
+
+* define task contexts that define various common aspects (logging,
+  failure handling ...) and assign them to tasks.
+
+  [ACCEPTED]
+
+[DISC] organization
+-------------------
+
+* separate CVSes and code hierarchies for
+  - task engine [ org.apache.task.* ]
+  - project engine (ie model of targets/projects/workspaces) + support/utility classes 
+    [ org.apache.ant.* ]
+  - core tasks (ie tasks supported by ant contributors) [ org.apache.??? ]
+
+  [REJECTED - vetoes by Conor MacNeill and Glenn McAllister]
+
+[DISC] misc
+-----------
+
+* internationalization
+
+  [ACCEPTED]
+
+VI. entries that have been submitted too late
+=============================================
+
+* Integration of the depends task and javac tasks
+
+  [REJECTED - only two +1 votes]
+
+* recursive property resolution( ie resolving ${dist.${name}.dir} )
+
+  [REJECTED - veto by Peter Donald]
diff --git a/trunk/docs/ant_in_anger.html b/trunk/docs/ant_in_anger.html
new file mode 100644
index 0000000..0044b01
--- /dev/null
+++ b/trunk/docs/ant_in_anger.html
@@ -0,0 +1,1115 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<head>
+<title>
+    Ant in Anger
+</title>
+</head>
+
+<body bgcolor="#FFFFFF" text="#000000">
+<h1 align="center">Ant in Anger:
+</h1>
+<h2 align="center">
+        Using Apache Ant in a Production Development System
+</h2>
+
+<h4  align="center">
+Steve Loughran<br>
+Last updated 2005-03-16
+</h4>
+
+<a name="introduction">
+
+<h2>Introduction</h2>
+</a>
+
+<a href="http://ant.apache.org/">Apache Ant</a>
+ can be an invaluable tool in a team development process - or it can
+be yet another source of problems in that ongoing crises we call
+development . This
+document contains some strategies and tactics for making the most of
+Ant. It is moderately frivolous in places, and lacks almost any actual
+examples of Ant XML. The lack of examples is entirely deliberate - it
+keeps document maintenance costs down. Most of the concepts covered
+don't need the detail provided by XML representations, as it is the processes we
+are concerned about, not the syntax. Finally, please be aware that the
+comments here are only suggestions which need to be customised to meet
+your own needs, not strict rules about what should and should not be
+done.
+
+<p>
+Firstly, here are some assumptions about the projects which this
+document covers:
+<ul>
+<li> Pretty much pure Java, maybe with some legacy cruft on the edges.
+
+<li> Team efforts, usually with the petulant prima-donnas all us Java
+programmers become once we realise how much in demand we are.
+
+<li> A fairly distributed development team - spread across locations and
+maybe time zones.
+
+<li> Separate sub projects - from separate beans in a big
+enterprise application to separate enterprise applications which need to
+be vaguely aware of each other.
+
+<li> Significant mismatch between expectations and time available to
+deliver. 'Last Week' is the ideal delivery date handed down from above,
+late next century the date coming up from below.
+
+<li> Everyone is struggling to keep up with platform and tool evolution.
+
+<li> Extensive use of external libraries, both open and closed source.
+</ul>
+
+What that all means is that there is no time to spend getting things
+right, you don't have that tight control on how the rest of the team
+works and the development process is often more one of chaos minimisation
+than anything else. The role of Ant in such projects is to ensure that
+the build, test and deploy processes run smoothly, leaving you with all
+the other problems.
+
+<a name="core">
+<h2>Core Practices</h2>
+</a>
+<h3>
+Clarify what you want Ant to do</h3>
+
+Ant is not a silver bullet. It is just another rusty bullet in the armory of
+development tools available at your disposal. Its primary purpose is to
+accelerate the construction and deployment of Java projects. You could certainly
+extend Ant to do anything Java makes possible: it is easy to imagine writing an
+image processing task to help in web site deployment by shrinking and
+recompressing jpeg files, for example. But that would be pushing the boundary of
+what Ant is really intended to do - so should be considered with care.
+
+<p>
+Ant is also a great adjunct to an IDE; a way of doing all the housekeeping of
+deployment and for clean, automated builds. But a good modern IDE is a
+productivity tool in its own right - one you should continue to use. Ant
+just lets you give the teams somewhat more freedom in IDE choice - &quot;you can
+use whatever you want in development, but Ant for the deployment
+builds&quot; Now that many modern open source and commercial IDEs
+include Ant support (including jEdit, Forte, Eclipse and IDEA),
+developers can use a great IDE, with Ant providing a rigorous and portable 
+build process integrated into the tool. 
+
+<h3>
+Define standard targets
+</h3>
+
+When you have multiple sub projects, define a standard set of targets.
+Projects with a split between interface and implementation jar files
+could consider <b>impl</b> and <b>intf</b> targets - with separate
+<b>debug-impl</b> and <b>debug-intf</b> targets for the debug version.
+And of course, the ubiquitous <b>clean</b> target.
+
+<p>
+
+With standard target names, it is easy to build encompassing Ant build
+files which just hand off the work to the classes below using the
+<a href="manual/CoreTasks/ant.html">ant</a>
+task. For example. the clean target could be handed down to the <tt>intf</tt> and
+<tt>impl</tt> subdirectories from a parent directory
+
+<pre>&lt;target name=&quot;clean&quot;  depends=&quot;clean-intf, clean-impl&quot;&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;clean-intf&quot; &gt;
+    &lt;ant dir=&quot;intf&quot; target=&quot;clean&quot; /&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;clean-impl&quot;&gt;
+    &lt;ant dir=&quot;impl&quot; target=&quot;clean&quot; /&gt;
+&lt;/target&gt;  </pre>
+
+If you give targets a <tt>description</tt> tag, then calling <tt>ant
+-projecthelp</tt> will list all tasks with their description as 'main targets', and 
+all tasks without a description as subtargets. Describing all your
+entry points is therefore very useful, even before a project becomes big and complicated.
+  
+<h3>
+    Extend Ant through new tasks
+</h3>
+
+If Ant does not do what you want, you can use the
+<a href="manual/CoreTasks/exec.html">exec</a> and
+<a href="manual/CoreTasks/java.html">java</a> tasks or
+<a href="manual/OptionalTasks/script.html">inline scripting</a> to extend it. In a
+project with many <tt>build.xml</tt> files, you soon find that having a single
+central place for implementing the functionality keeps maintenance
+overhead down. Implementing task extensions through Java code seems
+extra effort at first, but gives extra benefits:-
+
+<ul>
+<li>Cross platform support can be added later without changing any
+<tt>build.xml</tt> files</li>
+
+<li>The code can be submitted to the Ant project itself, for other
+people to use and maintain</li>
+
+<li>It keeps the build files simpler</li>
+</ul>
+
+In a way, it is this decoupling of functionality, "the tasks", from
+the declaration of use, "the build file", that has helped Ant succeed.
+If you have to get something complex done in Make or an IDE, you have a
+hairy makefile that everyone is scared of, or an IDE configuration that
+is invariably very brittle. But an Ant task is reusable and shareable
+among all Ant users. Many of the core and optional tasks in Ant today,
+tasks you do or will come to depend on, were written by people trying to
+solve their own pressing problems.
+
+<h3>
+Embrace Automated Testing
+</h3>
+
+<b>(alternatively "recriminate early, recriminate often")</b>
+<p>
+Ant lets you call <a href="manual/OptionalTasks/junit.html">JUnit</a>
+tasks, which unit test the code your team has written. Automated testing
+may seem like extra work at first, but JUnit makes writing unit tests so
+easy that you have almost no reason not to. Invest the time in learning
+how to use JUnit, write the test cases, and integrate them in a 'test'
+target from Ant so that your daily or hourly team build can have the
+tests applied automatically. One of the free to download chapters of
+<a href="http://manning.com/hatcher">Java Development with Ant</a>
+shows you how to use JUnit from inside Ant.  
+
+<p>
+Once you add a way to fetch code from the SCM system, either as an Ant
+task, in some shell script or batch file or via some continuous
+integration tool. the integration test code can be a pure Ant task run
+on any box dedicated to the task. This is ideal for verifying that the
+build and unit tests work on different targets from the usual
+development machines. For example, a Win95/Java1.1 combination could be
+used even though no developer would willingly use that configuration
+given the choice.
+
+<p>
+System tests are harder to automate than unit tests, but if you can
+write java code to stress large portions of the system - even if the code
+can not run as JUnit tasks - then the <a href= "manual/CoreTasks/java.html">java</a>
+task can be used to invoke them. It is best to specify that you want a
+new JVM for these tests, so that a significant crash does not break the
+full build. The Junit extensions such as 
+<a href="http://httpunit.sourceforge.net/">HttpUnit</a> for web pages, and 
+<a href="http://jakarta.apache.org/cactus/">Cactus</a> for J2EE and servlet 
+testing help to expand the testing framework. To test properly you will still
+need to invest a lot of effort in getting these to work with your project, and 
+deriving great unit, system and regression tests - but your customers will love 
+you for shipping software that works.   
+
+<h3>Learn to Use and love the add-ons to Ant</h3>
+The Ant distribution is not the limit of the Ant universe, it is only
+the beginning. Look at the 
+<a href="http://ant.apache.org/external.html">
+External Tools and Tasks page
+</a> for an up to date list. Here are some of them that .
+
+<ul>
+<li>
+<a href="http://checkstyle.sourceforge.net/">Checkstyle</a><br>
+This tool audits your code and generates HTML reports of wherever any
+style rule gets broken. Nobody can hide from the code police now! tip:
+start using this early, so there's less to correct.</li>
+<li>
+<a href="http://ant-contrib.sf.net/">Ant-contrib</a><br>
+This sourceforge project contains helper tasks that are kept separate
+from core Ant for ideological purity; the foreach and trycatch tasks in
+particular. These give you iteration and extra error handling. Also on
+the site is the &lt;cc&gt; task suite, that compile and link native code
+on a variety of platforms.</li>
+<li>
+<a href="http://xdoclet.sourceforge.net/">XDoclet</a>
+XDoclet adds attributed oriented programming to Java. By adding javadoc
+tags to your code you can have XDoclet automatically generate <tt>web.xml</tt>
+descriptors, taglib descriptors, EJB interfaces, JMX interface classes,
+Castor XML/SQL bindings, and many more. The key here is that all those
+fiddly little XML files you need to create, and those interfaces EJB and
+JMX requires to implement, all can be autogenerated from your Java
+code with a few helper attributes. This reduces
+errors and means you can change your code and have the rest of the app
+take its cue from the source. Never do EJB, JMX or webapps without it!
+</li>
+</ul>
+
+<a name="crossplatform">
+<h2>
+Cross Platform Ant
+</h2>
+</a>
+Ant is the best foundation for cross platform Java development and
+testing to date. But if you are not paying attention, it is possible to
+produce build files which only work on one platform - or indeed, one
+single workstation.
+
+<p>
+The common barriers to cross-platform Ant are the use of command line
+tools (exec tasks) which are not portable, path issues, and hard coding
+in the location of things.
+
+<h3>Command Line apps: <a href="manual/CoreTasks/exec.html">Exec</a> /
+ <a href= "manual/CoreTasks/apply.html">Apply</a></h3>
+
+The trouble with external invocation is that not all functions are found
+cross platform, and those that are often have different names - DOS
+descendants often expect <tt>.exe</tt> or <tt>.bat</tt> at the end of files. That can be
+bad if you explicitly include the extension in the naming of the command
+(don't!), good when it lets you keep the unix and DOS versions of an
+executable in the same bin directory of the project without name
+clashes arising.
+
+<p>
+Both the command line invocation tasks let you specify which platform
+you want the code to run on, so you could write different tasks for each
+platform you are targeting. Alternatively, the platform differences
+could be handled inside some external code which Ant calls. This can be
+some compiled down java in a new task, or an external script file.
+
+<h3>Cross platform paths</h3>
+
+Unix paths use forward slashes between directories and a colon to
+split entries. Thus
+<i>"/bin/java/lib/xerces.jar:/bin/java/lib/ant.jar"</i> is
+a path in unix. In Windows the path must use semicolon separators,
+colons being used to specify disk drives, and backslash separators
+<i>"c:\bin\java\lib\xerces.jar;c:\bin\java\lib\ant.jar"</i>.
+<p>
+This difference between platforms (indeed, the whole java classpath
+paradigm) can cause hours of fun.
+
+<p>
+Ant reduces path problems; but does not eliminate them entirely. You
+need to put in some effort too. The rules for handling path names are
+that 'DOS-like pathnames are handled', 'Unix like paths are handled'.
+Disk drives -'C:'- are handled on DOS-based boxes, but placing them in
+the <tt>build.xml</tt> file ruins all chances of portability. Relative file paths
+are much more portable. Semicolons work as path separators - a fact which
+is useful if your Ant invocation wrapper includes a list of jars as a
+defined property in the command line. In the build files you may find it
+better to build a classpath by listing individual files (using location=
+attributes), or by including a fileset of <tt>*.jar</tt> in the classpath
+definition.
+<p>
+There is also the <a
+href="manual/CoreTasks/pathconvert.html">PathConvert</a> task which
+can put a fully resolved path into a property. Why do that? Because then 
+you can use that path in other ways - such as pass it as a parameter to 
+some application you are calling, or use the replace task to patch it
+into a localised shell script or batch file.
+<p>
+Note that DOS descended file systems are case insensitive (apart from
+the obscure aberration of the WinNT POSIX subsystem run against NTFS),
+and that Windows pretends that all file extensions with four or more
+letters are also three letter extensions (try <tt>DELETE *.jav</tt> in your java
+directories to see a disastrous example of this).
+
+<p>
+Ant's policy on case sensitivity is whatever the underlying file system
+implements, and its handling of file extensions is that <tt>*.jav</tt> does not
+find any <tt>.java</tt> files. The Java compiler is of course case sensitive - you can
+not have a class 'ExampleThree' implemented in "examplethree.java".
+
+<p>
+Some tasks only work on one platform - <a href= "manual/CoreTasks/chmod.html">
+Chmod</a> being a classic example. These tasks usually result in just a
+warning message on an unsupported platform - the rest of the target's
+tasks will still be called. Other tasks degrade their functionality on
+platforms or Java versions. In particular, any task which adjusts the
+timestamp of files can not do so properly on Java 1.1. Tasks which can
+do that - <a href="manual/CoreTasks/get.html">Get</a>, <a
+href="manual/CoreTasks/touch.html">Touch</a> and <A href="manual/CoreTasks/unzip.html">
+Unjar/Unwar/Unzip</a> for example, degrade their functionality on
+Java1.1, usually resorting to the current timestamp instead.
+
+<p>
+Finally, Perl makes a good place to wrap up Java invocations cross
+platform, rather than batch files. It is included in most Unix
+distributions, and is a simple download for <a href=
+"http://www.activestate.com/Products/ActivePerl/">Win32 platforms from
+ActiveState</a>. A Perl file with <tt>.pl</tt> extension, the usual Unix
+path to perl on the line 1 comment and marked as executable can be run
+on Windows, OS/2 and Unix and hence called from Ant without issues. The
+perl code can be left to resolve its own platform issues. Don't forget to
+set the line endings of the file to the appropriate platform when you
+redistribute Perl code; <a
+href="manual/CoreTasks/fixcrlf.html">fixCRLF</a> 
+can do that for you.
+
+<a name="team">
+<h2>Team Development Processes</h2>
+</a>
+Even if each team member is allowed their choice of IDE/editor, or even
+OS, you need to set a baseline of functionality on each box. In
+particular, the JDKs and jars need to be in perfect sync. Ideally pick
+the latest stable Java/JDK version available on all developer/target
+systems and stick with it for a while. Consider assigning one person to
+be the contact point for all tools coming in - particularly open source
+tools when a new build is available on a nightly basis. Unless needed,
+these tools should only really be updated monthly, or when a formal
+release is made.
+
+<p>
+Another good tactic is to use a unified directory tree, and add on extra
+tools inside that tree. All references can be made relative to the tree.
+If team members are expected to add a directory in the project to their
+path, then command line tools can be included there - including those
+invoked by Ant exec tasks. Put everything under source code control and
+you have a one stop shop for getting a build/execute environment purely
+from CVS or your equivalent.
+
+<a name="deploying">
+<h2>Deploying with Ant</h2>
+</a>
+One big difference between Ant and older tools such as Make is that the
+processes for deploying Java to remote sites are reasonably well
+evolved in Ant. That is because we all have to do it these days, so
+many people have put in the effort to make the tasks easier.
+<p>
+Ant can <a href="manual/CoreTasks/jar.html">Jar</a>, <a href=
+"manual/CoreTasks/tar.html">Tar</a> or <a
+href="manual/CoreTasks/zip.html">Zip</a> files for deployment, while the
+<a href="manual/CoreTasks/war.html">War</a> task extends the jar task
+for better servlet deployment. 
+<a href ="manual/OptionalTasks/jlink.html">Jlink</a> is a
+jar generation file which lets you merge multiple sub jars. This is
+ideal for a build process in which separate jars are generated by sub
+projects, yet the final output is a merged jar. <a href=
+"manual/OptionalTasks/cab.html">Cab</a> can be used on Win32 boxes to
+build a cab file which is useful if you still have to target IE deployment.
+
+<p>
+The <a href="index.html#ftp">ftp</a> task lets you move stuff up to a
+server. Beware of putting the ftp password in the build file - a property
+file with tight access control is slightly better. The <a href=
+"manual/CoreTasks/fixcrlf.html">FixCRLF</a> task is often a useful interim step if
+you need to to adjust the line endings of files. A
+WebDav task has long been discussed, which would provide a more secure
+upload to web servers, but it is still in the todo list. Rumour has it
+that there is such a task in the jakarta-slide libraries. With MacOS X,
+Linux and Windows XP all supporting WebDAV file systems, you may even be able
+to use <a href="manual/CoreTasks/copy.html">copy</a> to deploy
+though a firewall. 
+
+<p>
+EJB deployment is aided by the <a href="manual/OptionalTasks/ejb.html">ejb</a> tasks,
+while the 
+<a
+href="manual/OptionalTasks/serverdeploy.html">serverdeploy</a>
+suite can deploy to multiple servers. The popularity of Ant has
+encouraged vendors to produce their own deployment tasks which they
+redistribute with their servers. For example, the Tomcat4.1 installation
+includes tasks to deploy, undeploy and reload web applications.
+
+<p>
+Finally, there are of course the fallbacks of just copying files to a
+destination using <a href="manual/CoreTasks/copy.html">Copy</a> and <a href="index.html#copydir">Copydir</a> , or just sending them to a person or
+process using <a href="manual/CoreTasks/mail.html">Mail</a> or the attachment
+aware <a href= "manual/OptionalTasks/mimemail.html">MimeMail</a>.
+In one project our team even used Ant to build CD images through a build followed
+by a long set of Copy tasks, which worked surprisingly well, certainly
+easier than when we mailed them to the free email service on
+myrealbox.com, then pulled them down from the far end's web browser, which we
+were running over WinNT remote desktop connection, that being tunneled
+through SSH.
+
+<a name="directories">
+<h2> Directory Structures</h2>
+</a>
+
+How you structure your directory tree is very dependent upon the
+project. Here are some directory layout patterns which can be used as
+starting points. All the jakarta projects follow a roughly similar
+style, which makes it easy to navigate around one from one project to
+another, and easy to clean up when desired. 
+
+<h3>Simple Project</h3>
+
+The project contains sub directories
+<table width="100%">
+<tr>
+    <td><b>bin</b>
+    </td>
+    <td>common binaries, scripts - put this on the path.
+    </td>
+</tr>
+
+<tr>
+    <td><b>build</b>
+    </td>
+    <td>This is the tree for building; Ant creates it and can empty it
+    in the 'clean' project.
+    </td>
+</tr>
+<tr>
+    <td><b>dist</b>
+    </td>
+    <td>Distribution outputs go in here; the directory is created in Ant
+    and clean empties it out
+    </td>
+</tr>
+<tr>
+    <td><b>doc</b>
+    </td>
+    <td>Hand crafted documentation
+    </td>
+</tr>
+<tr>
+    <td><b>lib</b>
+    </td>
+    <td>Imported Java libraries go in to this directory
+    </td>
+</tr>
+<tr>
+    <td><b>src</b>
+    </td>
+    <td>source goes in under this tree <i>in a hierarchy which matches
+    the package names<i>. The dependency rules of &lt;javac&gt; requires this.  
+    </td>
+</tr>
+</table>
+
+The bin, lib, doc and src directories should be under source code control.
+Slight variations include an extra tree of content to be included in the
+distribution jars - inf files, images, etc. These can go under source
+too, with a <tt>metadata</tt> directory for <tt>web.xml</tt> and similar
+manifests, and a <tt>web</tt> folder for web content - JSP, html, images
+and so on. Keeping the content in this folder (or sub hierarchy)
+together makes it easier to test links before deployment. The actual
+production of a deployment image, such as a war file, can be left to the
+appropriate Ant task: there is no need to completely model your source tree 
+upon the deployment hierarchy. 
+<p> 
+Javadoc output can be
+directed to a <tt>doc/</tt> folder beneath <tt>build/</tt>, or to <tt>doc/javadoc</tt>.
+
+<h3>Interface and Implementation split</h3>
+
+If the interface is split from the implementation code then this can be
+supported with minor changes just by having a separate build path for
+the interface directory - or better still just in the jar construction:
+one jar for interface and one jar for implementation.
+
+<h3>Loosely Coupled Sub Projects</h3>
+
+In the loosely coupled approach multiple projects can have their own
+copy of the tree, with their own source code access rights.
+One difference to consider is only having one instance of the bin and
+lib directories across all projects. This is sometimes good - it helps
+keep copies of xerces.jar in sync, and sometimes bad - it can update
+foundational jar files before unit testing is complete.
+
+<p>
+To still have a single build across the sub projects, use parent
+<tt>build.xml</tt> files which call down into the sub projects.
+<p>
+This style works well if different teams have different code
+access/commitment rights. The risk is that by giving extra leeway to the
+sub projects, you can end up with incompatible source, libraries, build
+processes and just increase your workload and integration grief all round.
+<p>
+The only way to retain control over a fairly loosely integrated
+collection of projects is to have a fully automated  build 
+and test process which verifies that everything is still compatible. Sam
+Ruby runs one for all the apache java libraries and emails everyone when
+something breaks; your own project may be able to make use of 
+<A href="http://cruisecontrol.sourceforge.net/">Cruise Control</a> for
+an automated, continuous, background build process. 
+
+<h3>Integrated sub projects</h3>
+
+Tightly coupled projects have all the source in the same tree; different
+projects own different subdirectories. Build files can be moved down to
+those subdirectories (say <tt>src/com/iseran/core</tt> and <tt>src/com/iseran/extras</tt>),
+or kept at the top - with independent build files named <tt>core.xml</tt> and
+<tt>extras.xml</tt>.
+
+<p>
+This project style works well if everyone trusts each other and the
+sub projects are not too huge or complex. The risk is that a split to a
+more loosely coupled design will become a requirement as the projects
+progress - but by the time this is realised schedule pressure and
+intertwined build files make executing the split well nigh impossible.
+If that happens then just keep with it until there is the time to
+refactor the project directory structures. 
+
+<a name="antupdate">
+<h2>
+    Ant Update Policies
+</h2>
+</a>
+
+Once you start using Ant, you should have a policy on when and how the
+team updates their copies. A simple policy is &quot;every official release
+after whatever high stress milestone has pushed all unimportant tasks
+(like sleep and seeing daylight) on the back burner&quot;. This insulates you
+from the changes and occasional instabilities that Ant goes through
+during development. Its main disadvantage is that it isolates you from
+the new tasks and features that Ant is constantly adding.
+
+<p>
+Often an update will require changes to the <tt>build.xml</tt> files. Most
+changes are intended to be backwards compatible, but sometimes an
+incompatible change turns out to be
+necessary. That is why doing the update in the lull after a big
+milestone is important. It is also why including <tt>ant.jar</tt> and related
+files in the CVS tree helps ensure that old versions of your software
+can be still be built.
+
+<p>
+The most aggressive strategy is to get a weekly or daily snapshot of the
+ant source, build it up and use it. This forces you to tweak the
+<tt>build.xml</tt> files more regularly, as new tasks and attributes can take
+while to stabilise. You really have to want the new features, enjoy
+gratuitous extra work or take pleasure in upsetting your colleagues to
+take this approach.
+
+<p>
+Once you start extending Ant with new tasks, it suddenly becomes much
+more tempting to pull down regular builds. The most recent Ant builds
+are invariably the best platform for writing your extensions, as you
+can take advantage of the regular enhancements to the foundational
+classes. It also prevents you from wasting time working on something
+which has already been done. A newly submitted task to do something
+complex such as talk to EJB engines, SOAP servers or just convert a text
+file to uppercase may be almost exactly what you need - so take it,
+enhance it and offer up the enhancements to the rest of the world. This
+is certainly better than starting work on your 'text case converter'
+task on Ant 0.8 in isolation, announcing its existence six months later
+and discovering that instead of adulation all you get are helpful
+pointers to the existing implementation. The final benefit of being
+involved with the process is that it makes it easier for your tasks to 
+be added with the Ant CVS tree, bringing forward the date when Ant has
+taken on all the changes you needed to make to get your project to work.
+If that happens you can revert to an official Ant release, and get on
+with all the other crises. 
+
+<p>
+You should also get on the <a href =
+"mailto:dev-subscribe@ant.apache.org">dev mailing list
+</a>, as it is where the other developers post their work, problems and
+experience. The volume can be quite high: 40+ messages a day, so
+consider routing it to an email address you don't use for much else. And
+don't make everyone on the team subscribe; it can be too much of a
+distraction.
+
+<a name="install">
+<h2>
+Installing with Ant.
+</h2>
+</a>
+Because Ant can read environment variables, copy, unzip and delete files
+and make java and OS calls, it can be used for simple installation
+tasks. For example, an installer for tomcat could extract the
+environment variable <tt>TOMCAT_HOME</tt>, stop tomcat running, and copy a war
+file to <tt>TOMCAT_HOME/webapps</tt>. It could even start tomcat again, but the
+build wouldn't complete until tomcat exited, which is probably not what
+was wanted. 
+
+<p>
+The advantage of using Ant is firstly that the same install targets
+can be used from your local build files (via an <tt>ant</tt> invocation
+of the <tt>install.xml</tt> file), and secondly that a basic install target is
+quite easy to write. The disadvantages of this approach are that the
+destination must have an up to date version of Ant correctly
+pre-installed, and Ant doesn't allow you to handle failures well - and a
+good installer is all about handling when things go wrong, from files
+being in use to jar versions being different. This means that Ant is not
+suited for shrink wrapped software, but it does work for deployment and
+installation to your local servers.
+
+<p>
+One major build project I was involved in had an Ant install build file
+for the bluestone application server, which would shutdown all four
+instances of the app server on a single machine, copy the new version of
+the war file (with datestamp and buildstamp) to an archive directory,
+clean up the current deployed version of the war and then install the
+new version. Because bluestone restarted JVMs on demand, this script was
+all you needed for web service deployment. On the systems behind the
+firewall, we upped the ante in the deployment process by using the ftp
+task to copy out the war and build files, then the telnet task to
+remotely invoke the build file. The result was we had automated
+recompile and redeploy to local servers from inside our IDE (Jedit) or
+the command line, which was simply invaluable. Imagine pressing a button
+on your IDE toolbar to build, unit test, deploy and then functional test
+your webapp. 
+
+<p>
+One extra trick I added later was a junit test case to run through the
+install check list. With tests to verify access permissions on network
+drives, approximate clock synchronisation between servers, DNS
+functionality, ability to spawn executables and all the other trouble
+spots, the install script could automatically do a system health test
+during install time and report problems. [The same tests could also be
+invoked from a JMX MBean, but that's another story]. 
+
+<p>
+So, Ant is not a substitute for a real installer tool, except in the
+special case of servers you control, but in that context it does let
+you integrate remote installation with your build. 
+
+
+<a name="tips">
+<h2>
+Tips and Tricks</h2>
+</a>
+<dl>
+<dt><b>
+    get
+</b><dd>
+
+The <a href="manual/CoreTasks/get.html">get</a> task can fetch any URL, so be used
+to trigger remote server side code during the build process, from remote
+server restarts to sending SMS/pager messages to the developer
+cellphones.
+
+<dt><b>
+i18n
+</b><dd>
+
+Internationalisation is always trouble. Ant helps here with the <a href=
+"manual/OptionalTasks/native2ascii.html">native2ascii</a> task which can escape out all non
+ascii characters into unicode. You can use this to write java files
+which include strings (and indeed comments) in your own non-ASCII
+language and then use native2ascii to convert to ascii prior to feeding
+through javac. The rest of i18n and l12n is left to you...
+
+<dt><b>
+Use Property Files
+</b><dd>
+
+Use external property files to keep per-user settings out the build
+files - especially passwords. Property files can also be used to
+dynamically set a number of properties based on the value of a single
+property, simply by dynamically generating the property filename from the
+source property. They can also be used as a source of constants across
+multiple build files.
+
+<dt><b>
+Faster compiles with Jikes
+</b><dd>
+
+The <a href="http://jikes.sourceforge.net/">jikes compiler</a> is usually much
+faster than javac, does dependency checking and has better error
+messages (usually). Get it. Then set
+<tt>build.compiler</tt> to "jikes" for it to be used in your build files.
+Doing this explicitly in your build files is a bit dubious as it requires the
+whole team (and sub projects) to be using jikes too - something you can only
+control in small, closed source projects. But if you set 
+<tt>ANT_OPTS&nbsp;=&nbsp;-Dbuild.compiler=jikes</tt>
+in your environment, then all your builds on your system will use 
+Jikes automatically, while others can choose their own compiler, or let
+ant choose whichever is appropriate for the current version of Java.   
+
+<dt><b>
+#include targets to simplify multi <tt>build.xml</tt> projects
+</b><dd>
+
+You can import XML files into a build file using the XML parser itself.
+This lets a multi-project development program share code through reference,
+rather than cut and paste re-use. It also lets one build up a file of
+standard tasks which can be reused over time. Because the import
+mechanism is at a level below which Ant is aware, treat it as
+equivalent to the #include mechanism of the 'legacy' languages C and
+C++.
+
+<p>
+There are two inclusion mechanisms, an ugly one for all parsers and a
+clean one. The ugly method is the only one that was available on Ant1.5 and
+earlier:-
+<pre>
+    &lt;!DOCTYPE project [
+      &lt;!ENTITY propertiesAndPaths SYSTEM &quot;propertiesAndPaths.xml&quot;&gt;
+      &lt;!ENTITY taskdefs SYSTEM &quot;taskdefs.xml&quot;&gt;
+    ]&gt;  
+    
+        &amp;propertiesAndPaths;
+        &amp;taskdefs;
+</pre>
+The cleaner method in Ant1.6 is the <tt>&lt;import&gt;</tt> task that imports
+whole build files into other projects. The entity inclusion example
+could <i>almost</i> be replaced by two import statements:-
+<pre>
+ &lt;import file="propertiesAndPaths.xml"&gt;
+ &lt;import file="taskdefs.xml"&gt;
+</pre>
+
+We say almost as top level declarations (properties and taskdefs) 
+do not get inserted into the XML file exactly where the import statement
+goes, but added to the end of the file. This is because the import process
+takes place after the main build file is parsed, during execution, whereas
+XML entity expansion is handled during the parsing process.
+
+<p>
+The <tt>&lt;import&gt;</tt> task does powerful things, such as let you override targets,
+and use ant properties to name the location of the file to import. Consult the
+<a href="manual/CoreTasks/import.html">documentation</a> for the specifics of
+these features.  
+
+<p>
+Before you go overboard with using XML inclusion, note that the
+<tt>ant</tt> task lets you call any target in any other build
+file - with all your property settings propagating down to that target.
+So you can actually have a suite of utility targets
+- "<tt>deploy-to-stack-a</tt>", "<tt>email-to-team</tt>", "<tt>cleanup-installation</tt>" which can
+be called from any of your main build files, perhaps with subtly changed
+parameters. Indeed, after a couple of projects you may be able to create
+a re-usable core build file which contains the core targets of a basic
+Java development project - compile, debug, deploy - which project specific
+build files call with their own settings. If you can achieve this then
+you are definitely making your way up the software maturity ladder. With
+a bit of work you may progress from being a SEI CMM Level 0 organisation
+&quot;Individual Heroics are not enough&quot; to SEI CMM Level 1, &quot;Projects only
+succeed due to individual heroics&quot;
+
+<p>
+NB, <tt>ant</tt> copies all your properties unless the
+<i>inheritall</i> attribute is set to false. Before that attribute
+existed you had to carefully name all property definitions in all build
+files to prevent unintentional overwriting of the invoked property by
+that of the caller, now you just have to remember to set
+<tt>inheritall="false"</tt> on all uses of the &lt;ant&gt; task.
+
+    
+<dt><b>
+Implement complex Ant builds through XSL
+</b><dd>
+
+XSLT can be used to dynamically generate build.xml files from a source
+xml file, with the <a href="manual/CoreTasks/style.html">xslt</a> task controlling
+the transform. This is the current recommended strategy for creating
+complex build files dynamically. However, its use is still apparently
+quite rare - which means you will be on the bleeding edge of technology.
+
+
+<dt><b>
+Change the invocation scripts
+</b><dd>
+
+By writing your own invocation script - using the DOS, Unix or Perl
+script as a starting point - you can modify Ant's settings and behavior for an
+individual project. For example, you can use an alternate variable to
+<tt>ANT_HOME</tt> as the base, extend the classpath differently, or dynamically
+create a new command line property &quot;<tt>project.interfaces</tt>&quot; from all <tt>.jar</tt>
+files in an interfaces directory.
+
+<p>
+Having a custom invocation script which runs off a CVS controlled
+library tree under <tt>PROJECT_HOME</tt> also lets you control Ant versions
+across the team - developers can have other copies of Ant if they want,
+but the CVS tree always contains the jar set used to build your project.
+
+<p>
+You can also write wrapper scripts which invoke the existing Ant
+scripts. This is an easy way to extend them. The wrapper scripts can add
+extra definitions and name explicit targets, redefine <tt>ANT_HOME</tt> and
+generally make development easier. Note that &quot;ant&quot; in Windows is really
+&quot;ant.bat&quot;, so should be invoked from another batch file with a "CALL
+ant" statement - otherwise it never returns to your wrapper.
+
+
+<dt><b>
+Write all code so that it can be called from Ant
+</b><dd>
+This seems a bit strange and idealistic, but what it means is that you should
+write all your java code as if it may be called as a library at some point in
+future. So do not place calls to <tt>System.exit()</tt> deep in the code - if you
+want to exit a few functions in, raise an exception instead and have
+<tt>main()</tt> deal with it.
+
+<p>
+Moving one step further, consider proving an Ant Task interface to the
+code as a secondary, primary or even sole interface to the
+functionality. Ant actually makes a great bootloader for Java apps as it
+handles classpath setup, and you can re-use all the built in tasks for
+preamble and postamble work. Some projects, such as 
+<a href="http://xdoclet.sf.net">XDoclet</a> only run under Ant, because
+that is the right place to be.
+
+<dt><b>
+Use the replace task to programmatic modify text files in your project.  
+</b><dd>
+Imagine your project has some source files - BAT files, ASPX pages(!), anything
+which needs to be statically customised at compile time for particular
+installations, such driven from some properties of the project such as JVM options, or the URL
+to direct errors too. The replace task can be used to modify files, substituting text and creating
+versions customised for that build or destination. Of course, per-destination customisation
+should be delayed until installation, but if you are using Ant for the remote installation
+that suddenly becomes feasible.     
+
+<dt><b>
+Use the mailing lists
+</b><dd>
+There are two 
+<a href="http://ant.apache.org/mail.html">mailing lists</a> 
+related to Ant, user and developer. Ant user is where <i>all</i>
+questions related to using Ant should go. Installation, syntax, code
+samples, etc - post your questions there or search the archives for 
+whether the query has been posted and answered before. Ant-developer
+is where Ant development takes place - so it is <i>not</i> the place to
+post things like &quot;I get a compilation error when I build my project&quot; or
+&quot;how do I make a zip file&quot;. If you are actually extending Ant, on the other
+hand, it is the ideal place to ask questions about how to add new tasks, make
+changes to existing ones - and to post the results of your work, if you want them
+incorporated into the Ant source tree.  
+</dl>
+
+<a name="puttingtogether">
+    <h2>
+        Putting it all together
+    </h2>
+</a>
+
+What does an Ant build process look like in this world? Assuming a
+single directory structure for simplicity, the build file
+should contain a number of top level targets
+<ul>
+<li>build - do an (incremental) build
+<li>test - run the junit tests
+<li>clean - clean out the output directories
+<li>deploy - ship the jars, wars, whatever to the execution system
+<li>publish - output the source and binaries to any distribution site
+<li>fetch - get the latest source from the cvs tree
+<li>docs/javadocs - do the documentation
+<li>all - clean, fetch, build, test, docs, deploy
+<li>main - the default build process (usually build or build &amp; test)
+</ul>
+Sub projects &quot;web&quot;, &quot;bean-1&quot;, &quot;bean-2&quot; can be given their own build
+files - <tt>web.xml</tt>, <tt>bean-1.xml</tt>, <tt>bean-2.xml</tt> - with the same entry points.
+Extra toplevel tasks related to databases, web site images and the like
+should be considered if they are part of the process.
+
+<p>
+Debug/release switching can be handled with separate initialisation
+targets called before the compile tasks which define the appropriate
+properties. Antcall is the trick here, as it allows you to have two paths
+of property initialisation in a build file.   
+
+<p>
+Internal targets should be used to structure the process
+<ul>
+<li> init - initialise properties, extra-tasks, read in per-user
+property files.
+<li> init-release - initialise release properties
+<li> compile - do the actual compilation
+<li> link/jar - make the jars or equivalent
+<li> staging - any pre-deployment process in which the output is dropped
+    off then tested before being moved to the production site.
+</ul>
+
+The switching between debug and release can be done by making
+init-release conditional on a property, such as <tt>release.build</tt> 
+being set :-
+
+<pre>&lt;target name=&quot;init-release&quot; if=&quot;release.build&quot;&gt;
+    &lt;property name=&quot;build.debuglevel&quot; value=&quot;lines,source&quot;/&gt;    
+  &lt;/target&gt;
+</pre>
+
+You then have dependent targets, such as &quot;compile&quot;, depend on this
+conditional target; there the &quot;default&quot; properties are set, and then the
+property is actually used. Because Ant properties are <i>immutable</i>,
+if the release target was executed its settings will override the
+default values:
+
+<pre>&lt;target name=&quot;compile&quot; depends=&quot;init,init-release&quot;&gt;
+    &lt;property name=&quot;build.debuglevel&quot; value=&quot;lines,vars,source&quot;/&gt; 
+    &lt;echo&gt;debug level=${build.debuglevel}&lt;/echo&gt;
+    &lt;javac destdir=&quot;${build.classes.dir}&quot;
+       debug=&quot;true&quot;
+       debuglevel=&quot;${build.debuglevel}&quot;
+       includeAntRuntime=&quot;false&quot;
+       srcdir=&quot;src&quot;&gt;
+      &lt;classpath refid=&quot;compile.classpath&quot;/&gt;
+    &lt;/javac&gt;
+  &lt;/target&gt;
+</pre>
+
+As a result, we now have a build where the release mode only includes
+the filename and line debug information (useful for bug reports), while
+the development system included variables too. 
+<p>
+It is useful to define a project name property which can be echoed in
+the init task. This lets you work out which Ant file is breaking in a
+multi file build.
+
+<p>
+What goes in to the internal Ant tasks depends on your own projects. One
+very important tactic is &quot;keep path redefinition down through
+references&quot; - you can reuse paths by giving them an ID and then
+referring to them via the &quot;refid&quot; attribute you should only need to
+define a shared classpath once in the file; filesets can be reused
+similarly.
+
+<p>
+Once you have set up the directory structures, and defined the Ant tasks
+it is time to start coding. An early priority must be to set up the
+automated test process, as that not only helps ensures that the code
+works, it verifies that the build process is working.
+
+<p>
+And that's it. The build file shouldn't need changing as new source
+files get added, only when you want to change the deliverables or part
+of the build process. At some point you may want to massively
+restructure the entire build process, restructuring projects and the
+like, but even then the build file you have should act as a foundation
+for a split build file process -just pull out the common properties into
+a properties file all build files read in, keep the target names unified
+and keep going with the project. Restructuring the source code control
+system is often much harder work.
+
+<h2>The Limits of Ant</h2>
+
+Before you start adopting Ant as the sole mechanism for the build
+process, you need to be aware of what it doesn't do.
+<p>
+
+<h3>It's not a scripting language</h3>
+
+Ant lets you declare what you want done, with a bit of testing of the
+platform and class libraries first to enable some platform specific
+builds to take place. It does not let you specify how to handle things
+going wrong (a listener class can do that), or support complex
+conditional statements.
+
+<p>
+If your build needs to handle exceptions then look at the sound listener
+as a simple example of how to write your own listener class. Complex
+conditional statements can be handled by having something else do the
+tests and then build the appropriate Ant task. XSLT can be used for
+this.
+
+<h3>It's not Make</h3>
+
+Some of the features of make, specifically inference rules and
+dependency checking are not included in Ant. That's because they are
+&quot;different&quot; ways of doing a build. Make requires you to state
+dependencies and the build steps, Ant wants you to state tasks and the
+order between them, the tasks themselves can do dependency checking or
+not. A full java build using Jikes is so fast that dependency checking
+is relatively moot, while many of the other tasks (but not all), compare
+the timestamp of the source file with that of the destination file
+before acting.
+
+<h3>It's not meant to be a nice language for humans</h3>
+
+XML isn't a nice representation of information for humans. It's a
+reasonable representation for programs, and text editors and source code
+management systems can all handle it nicely. But a complex Ant file can
+get ugly because XML is a bit ugly, and a complex build is, well,
+complicated. Use XML comments so that the file you wrote last month
+still makes sense when you get back to it, and use proper xml editors to edit the
+files if you prefer it. 
+
+<h3>Big projects still get complicated fast</h3>
+
+Large software projects create their own complexity, with inter-dependent
+libraries, long test cycles, hard deployment processes and a multitude of
+people each working on their own bit of the solution. That's even before
+the deadlines loom close, the integration problems become insurmountable,
+weekends become indistinguishable from weekdays in terms of workload and 
+half the team stops talking to the other half. Ant may simplify the
+build and test process, and can eliminate the full time &quot;makefile engineer&quot;
+role, but that doesn't mean that someone can stop &quot;owning the build&quot;. 
+Being in charge of the build has to mean more than they type &quot;<tt>ant all</tt>&quot; on
+their system, it means they need to set the standards of what build tools to
+use, what the common targets, what property names and files should be
+and generally oversee the sub projects build processes. On a small project,
+you don't need to do that - but remember: small projects become big projects
+when you aren't looking. If you start off with a little bit of process, then
+you can scale it if needed. If you start with none, by the time you need 
+it will be too late.   
+
+<h3>You still need all the other foundational bits of a software
+project</h3>
+
+If you don't have an source code management system, you are going to end
+up hosed. If you don't have everything under SCM, including web pages,
+dependent jars, installation files, you are still going to end up hosed,
+it's just a question of when it's going to happen.
+CVS is effectively free and works well with Ant, but Sourcesafe, Perforce,
+Clearcase and StarTeam also have Ant tasks. These tasks
+let you have auto-incrementing build counters, and automated file
+update processes. 
+
+<p>
+You also need some kind of change control process, to resist
+uncontrolled feature creep. Bugzilla is a simple and low cost tool for
+this, using Ant and a continuous test process enables a rapid evolution of code
+to adapt to those changes which are inevitable.  
+
+<h2>End piece</h2>
+
+Software development is meant to be fun. Being in the maelstrom of a
+tight project with the stress of integration and trying to code
+everything up for an insane deadline can be fun - it is certainly
+exhilarating. Adding a bit of automation to the process may make things
+less chaotic, and bit less entertaining, but it is a start to putting
+you in control of your development process. You can still have fun, you
+should just have less to worry about, a shorter build/test/deploy cycle
+and more time to spend on feature creep or important things like skiing.
+So get out there and have fun!
+
+<a name="reading">
+<h2>Further Reading</h2>
+</a>
+<ul>
+<li>
+<a
+href="http://www.martinfowler.com/articles/continuousIntegration.html">
+<i>Continuous Integration</i></a>; Martin Fowler. <br>
+A paper on using Ant within a software project
+running a continuous integration/testing process.
+<li><i> Refactoring</i>; Martin Fowler, ISBN: 0201485672 <br>
+    Covers JUnit as well as tactics for making some headway with the mess of
+    code you will soon have.
+
+<li><a href="http://manning.com/hatcher"><i>Java Development with
+Ant</i></a>;
+    Erik Hatcher and Steve Loughran. 
+
+    
+<li>
+<a href="http://www.iseran.com/Steve/papers/when_web_services_go_bad.html">
+    <i>When Web Services Go Bad</i></a>; Steve Loughran.<br>
+    One of the projects this paper is based on.    
+    
+    
+</ul>
+
+<a name="author">
+<h3>About the Author</h3>
+</a>
+
+Steve Loughran is a research scientist at a corporate R&amp;D lab,
+currently on a sabbatical building production web services against
+implausible deadlines for the fun of it. He is also a committer on
+Apache Ant and Apache Axis, and co-author of 
+<a href="http://manning.com/hatcher"><i>Java Development with Ant</i></a>. 
+He thinks that if you liked this document you'll love that book because
+it doesn't just explain Ant, it goes into processes, deployment and best practices
+and other corners of stuff that really make Ant useful. (It would 
+have been easier to just rehash the manual, but that wouldn't have been
+so useful or as much fun).  
+
+<p>
+For questions related to this document, use the Ant mailing list.
+
+
+</body>
+</html>
diff --git a/trunk/docs/ant_task_guidelines.html b/trunk/docs/ant_task_guidelines.html
new file mode 100644
index 0000000..077a2ce
--- /dev/null
+++ b/trunk/docs/ant_task_guidelines.html
@@ -0,0 +1,508 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html><head>
+<title>
+Apache Ant Task Design Guidelines
+</title>
+</head><body>
+
+<h1>Apache Ant Task Design Guidelines</h1>
+
+This document covers how to write Ant tasks to a standard required to be
+incorporated into the Ant distribution. You may find it useful when
+writing tasks for personal use as the issues it addresses are still
+there in such a case.
+
+<h2>Don't break existing builds</h2>
+
+Even if you find some really hideous problem with Ant, one that is easy to fix,
+if your fix breaks an existing build file then we have problems. Making sure
+that every build file out there still works is one of the goals of all changes.
+As an example of this, Ant 1.5 passes the single dollar sign &quot;$&quot;
+through in strings; Ant 1.4 and before would strip it. To get this fix in we
+first had to write the test suite to expose current behaviour, then change
+something so that single &quot;$&quot; was passed through, but double
+&quot;$$&quot; got mapped to &quot;$&quot; for backwards compatibility.
+
+<h2>Don't break the Java API</h2>
+
+Ant's tasks can be used by third party programs and tasks.
+We cannot make changes that break the API. This includes:
+<ol>
+<li>Moving classes without leaving a backwards-compatible facade.
+<li>Deleting classes.
+<li>Deleting methods or fields, or reducing their accessibility.
+<li>Changing the signature of a <tt>setAttribute(Type)</tt> method. If you need
+to add a restrictive type, add a new attribute, and place it in the source
+<i>above</i> the original. The XML mapper will get the restricted type, old programs
+can still use the old type.
+<li>Don't change semantics. At least, not drastically. All bug fixes are
+implicit changes of semantics, after all.
+</ol>
+
+<h2>Use built in helper classes</h2>
+
+Ant includes helper tasks to simplify much of your work. It is much better to
+use them than roll your own, for development, maintenance and code size reasons.
+
+<h4>Execute</h4>
+
+Execute will spawn off separate programs under all the platforms which
+Ant supports, dealing with Java version issues as well as platform
+issues. Always use this class to invoke other programs.
+
+<h4>Java, ExecuteJava</h4>
+
+These classes can be used to spawn Java programs in a separate VM (they
+use execute) or in the same VM--with or without a different classloader.
+When deriving tasks from this, it often benefits users to permit the
+classpath to be specified, and for forking to be an optional attribute.
+
+<h4>Project and related classes</h4>
+
+Project, FileUtils, JavaEnvUtils all have helper functions to do things like
+touch a file, copy a file and the like. Use these instead of coding them
+yourself or trying to use tasks which may be less stable and fiddlier to use.
+
+<h2>Obey the Sun/Java style guidelines</h2>
+
+The Ant codebase aims to have a single unified coding standard, and that
+standard is the
+<a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">
+Sun Java coding guidelines
+</a>
+<p>
+
+It's not that they are better than any alternatives, but they are a
+standard and they are what is consistently used in the rest of the
+tasks. Code will not be incorporated into the database until it complies
+with these.
+
+<p>
+
+If you are writing a task for your personal or organisational use, you
+are free to use whatever style you like. But using the Sun Java style
+will help you to become comfortable with the rest of the Ant source,
+which may be important.
+
+<p>
+
+One important rule is 'no tabs'. Use four spaces instead. Not two,
+not eight, four. Even if your editor is configured to have a tab of four
+spaces, lots of others aren't. Spaces have more consistency across
+editors and platforms. Some IDEs (JEdit) can highlight tabs, to stop you
+accidentally inserting them.
+<p>
+There is an Ant build file check.xml in the main ant directory with runs 
+  <a href="http://checkstyle.sourceforge.net">checkstyle</a> over
+  Ant's source code.
+
+<h2>Attributes and elements</h2>
+Use the Ant introspection-based mapping of attributes into Java datatypes,
+rather than implementing all your attributes as setFoo(String) and doing
+the mapping to int, boolean or File yourself. This saves work on your part,
+lets Java callers use you in a typesafe manner, and will let the Xdocs
+documentation generator work out what the parameters are.
+
+<p>
+The Ant 1.x tasks are very inconsistent regarding naming of attributes--some
+tasks use <tt>source</tt>, others <tt>src</tt>.
+Here is a list of preferred attribute names:
+<p>
+<table cellpadding="5">
+<tr>
+<td>
+    failonerror
+</td>
+<td>
+    boolean to control whether failure to execute should throw a
+    <tt>BuildException</tt> or just print an error.
+    Parameter validation failures should always throw an error, regardless
+    of this flag.
+</td>
+</tr>
+<tr>
+<td>
+    destdir
+</td>
+<td>
+    destination directory for output
+</td>
+</tr>
+<tr>    
+<td>
+    destfile
+</td>
+<td>
+    destination file for output
+</td>
+</tr>
+<tr>
+<td>
+    srcdir
+</td>
+<td>
+    source directory
+</td>
+</tr>
+<tr>
+<td>
+    srcfile
+</td>
+<td>
+    source file
+</td>
+</tr>
+</table>
+<p>
+Yes, this is a very short list. Try and be vaguely consistent with the core
+tasks, at the very least.
+
+<h2>Support classpaths</h2>
+
+Try and make it possible for people to supply a classpath to your task,
+if you need external libraries, rather than make them add everything to
+the ANT_HOME/lib directory. This lets people keep the external libraries
+in their Ant-based project, rather than force all users to make changes
+to their Ant system configuration.
+
+<h2>Design for controlled re-use</h2>
+
+Keep member variables private. If read access by subclasses is required,
+add accessor methods rather than change the accessiblity of the member.
+This enables subclasses to access the contents, yet still be decoupled 
+from the actual implementation.
+<p>
+
+The other common re-use mechanism in Ant is for one task to create and
+configure another. This is fairly simple. There are facilities available in
+Ant's API to have the tasks instantiated by their familiar names
+(&quot;java&quot;, &quot;exec&quot;, etc.). It is recommended that you
+<b>not</b> use this approach because of the entirely real possibility that a
+user has overridden the name to point to a different class entirely. Use direct
+constructor calls (or reflection) to instantiate your subtask. Since Ant 1.6.3,
+you can call <code>org.apache.tools.ant.Task#bindToOwner()</code>
+to &quot;mask&quot; a helper task as its parent.
+
+<h2>Do your own Dependency Checking</h2>
+
+Make has the edge over Ant in its integrated dependency checking; the
+command line apps make invokes don't need to do their own work. Ant tasks
+do have to do their own dependency work, but if this can be done then
+it can be done well. A good dependency-aware task can work out the dependencies
+without explicit dependency information in the build file, and be smart
+enough to work out the real dependencies, perhaps through a bit of file parsing.
+The <tt>depends</tt> task is the best example of this. Some of the zip/jar
+tasks are pretty good too, as they can update the archive when needed.
+Most tasks just compare source and destination timestamps and work from there.
+Tasks which don't do any dependency checking do not help users as much as
+they can, because their needless work can trickle through the entire build, test
+and deploy process.
+
+<h2>Support Java 1.2 through Java 1.5+</h2>
+
+Ant 1.5 and lower was designed to support Java 1.1. Ant 1.6 and higher
+is designed to support Java 1.2: to build on it, to run on it. Sometimes
+functionality of tasks have to degrade in that environment--usually due to
+library limitations; such behaviour change must always be noted in the
+documentation.
+<p>
+What is problematic is code which is dependent on Java 1.3 features;
+e.g. java.lang.reflect.Proxy, or Java 1.4 features; e.g. java.io.nio.
+Be also aware of extra methods in older classes;
+e.g. StringBuffer#append(StringBuffer). These cannot be used directly
+by any code and still be able to compile and run on a Java 1.2 system.
+If a new method in an existing class is to be used, it must be used via
+reflection and the <tt>NoSuchMethodException</tt> handled somehow.
+<p>
+What if code simply does not work on Java 1.2? It can happen. It will
+probably be OK to have the task as an optional task, with compilation
+restricted to Java 1.3 or later through build.xml modifications.
+Better still, use reflection to link to the classes at run time.
+<p>
+Java 1.4 adds a new optional change to the language itself, the
+<tt>assert</tt> keyword, which is only enabled if the compiler is told
+to compile 1.4 version source. Clearly with the 1.2 compatibility requirement,
+Ant tasks cannot use this keyword. They also need to move away from
+using the JUnit <tt>assert()</tt> method and call <tt>assertTrue()</tt>
+instead.
+<p>
+Java 1.5 adds the <tt>enum</tt> type; again, this must not be used.
+
+<h2>Explicitly Expand properties in nested text</h2>
+
+For historical reasons, <tt>addText(String text)</tt> is called to
+set the task's nested text, without any property expansion taking place.
+Call <tt>Project.replaceProperties()</tt> to do this manually.
+If you forget, you create a problem that is impossible to fix
+without breaking users' build files.
+
+<h2>Refactor</h2>
+
+If the changes made to a task are making it too unwieldy, split it up
+into a cleaner design, refactor the code and submit not just feature
+creep but cleaner tasks. A common design pattern which tends to occur in
+the Ant process is the adoption of the adapter pattern, in which a base
+class (say Javac or Rmic) starts off simply, then gets convoluted with
+support for multiple back ends:  javac, jikes, jvc. A refactoring to
+split the programmable front end from the classes which provide the back
+end cleans up the design and makes it much easier to add new back ends.
+But to carry this off one needs to keep the interface and behaviour of
+the front end identical, and to be sure that no subclasses have been
+accessing data members directly, because these data members may not
+exist in the refactored design. This is why having private data members
+is so important.
+
+<p>
+
+One thing we must not do is move existing tasks around or delete them.
+Remember that Ant has a Java API as well as an XML language. We don't want
+to break that API, or anything that subclasses existing Ant tasks. When
+refactoring, you need to leave facades where the original classes were. so
+existing code does not break.
+
+<h2>Test</h2>
+
+Look in <tt>ant/src/testcases</tt> and you will find JUnit tests for the
+shipping Ant tasks, to see how it is done and what is expected of a new
+task. Most of them are rudimentary, and no doubt you could do better for
+your task--feel free to do so!
+
+<p>
+
+A well written set of test cases will break the Ant task while it is in
+development, until the code is actually complete. And every bug which
+surfaces later should have a test case added to demonstrate the problem,
+and to fix it.
+
+<p>
+
+The test cases are a great way of testing your task during development.
+A simple call to 'build run-test' in the ant source tree will run all ant
+tests, to verify that your changes don't break anything.
+To test a single task, use the one shot <code>ant run-single-test
+-Dtestcase=${testname}</code> where <code>${testname}</code>
+is the name of your test class.
+
+<p>
+
+The test cases are also used by the committers to verify that changes
+and patches do what they say. If you've got test cases it increases your
+credibility significantly. To be precise, we hate submissions without
+test cases, as it means we have to write them ourselves. This is
+something that only gets done if we need the task or it is perceived as
+utterly essential to many users.
+
+<p>
+
+Remember also that Ant 1.x is designed to compile and run on Java 1.2, so
+you should test on Java 1.2 as well as any later version which you use.
+You ought to be able to download an old SDK from Sun for this purpose.
+<p>
+Finally, run a full <code>build test</code> before and after you start
+developing your project, to make sure you haven't broken anything else by
+accident.
+
+<h2>Document</h2>
+
+Without documentation, the task can't be used. So remember to provide a
+succinct and clear html (soon, xml) page describing the task in a similar
+style to that of existing tasks. It should include a list of attributes
+and elements, and at least one working example of the task. Many users
+cut and paste the examples into their build files as a starting point,
+so make the examples practical and test them too.
+<p>
+You can use the xdocs stuff in proposal/xdocs to autogenerate your
+documentation page from the javadocs of the source; this makes life
+easier and will make the transition to a full xdoclet generated
+documentation build process trivial.
+
+<h2>Licensing and Copyright</h2>
+
+Any code submitted to the Apache project must be compatible with the
+Apache Software License, and the act of submission must be viewed as
+an implicit license of the submitted code to the Apache Software
+Foundation.
+
+<p>
+This is important.
+
+<p>
+
+The fairly laissez-faire license of Apache is not currently considered
+compatible with
+either the GPL or the Lesser GPL of the Free Software Foundation--the
+Gnu project. These licenses have stricter terms, &quot;copyleft&quot;,
+which are not in the Apache Software Foundation license.
+This permits people and organisations to build
+commercial and closed source applications atop the Apache libraries and source.
+
+<p>
+
+Because the Gnu GPL license immediately extends to cover any larger
+application (or library, in the case of LGPL) into which it is
+incorporated, the Ant team cannot incorporate any task based upon GPL
+or LGPL source into the Ant codebase. You are free to submit it, but it
+will be politely and firmly rejected.
+
+<p>
+If you link to a GPL or LGPL library, by <code>import</code> or
+reflection, your task must be licensed under the same terms. So tasks
+linking to (L)GPL code can't go into the Apache managed codebase.
+Tasks calling such code can use the 'exec' or 'java' tasks to run the
+programs, as you are just executing them at this point, not linking to
+them.
+<p>
+Even if we cannot include your task into the Apache codebase, we can
+still point to where you host it; just submit a diff to
+xdocs/external.html pointing to your task.
+<p>
+If your task links directly to proprietary code, we have a different
+problem: it is really hard to build the tasks. Please use reflection.
+
+<h3>Don't re-invent the wheel</h3>
+
+We've all done it: written and submitted a task only to discover it
+was already implemented in a small corner of another task, or it has
+been submitted by someone else and not committed. You can avoid this
+by being aware of what is in the latest CVS tree; keep getting the daily
+source updates, look at manual changes and subscribe to the dev
+mailing list.
+
+<p>
+
+If you are thinking of writing a task, posting a note on your thoughts
+to the list can be informative--you will get other peoples' insights and
+maybe some half-written task to do the basics, all without writing a
+line of code.
+
+<h2>Submitting to Ant</h2>
+
+The basic mechanism for submitting an Ant task is to mail it to the
+dev mailing list. It helps to be on this list, as you will see other
+submissions, and any debate about your own submission.
+<p>
+You may create your patch file using either of the following approaches
+(the committers recommend the first):
+<p>
+<ul>
+<li><h3>Approach 1 - The Ant Way</h3>
+<p>
+Use Ant to generate a patch file to Ant:
+<pre class="code">
+ant -f patch.xml
+</pre>
+This will create a file named patch.tar.gz that will contain a unified
+diff of files that have been modified and also include files that have
+been added.  Review the file for completeness and correctness.  This approach
+is recommended because it standardizes the way in which patch files are
+constructed.  It also eliminates the chance of you missing to submit new files
+that constitute part of the patch.
+<p>
+<li><h3>Approach 2 - The Manual Way</h3>
+<p>
+Patches to existing files should be generated with
+<code>svn diff -u filename</code>
+ and save the output to a file. If you want to get
+the changes made to multiple files in a directory , just use <code>cvs
+diff -u</code>.  Then, Tar and GZip the patch file as well as any new files
+that you have added.
+</ul>
+<p>
+The patches should be sent as an attachment to a message titled [PATCH]
+and distinctive one-line summary in the subject of the patch. The
+filename/task and the change usually suffices. It's important to include
+the changes as an attachment, as too many mailers reformat the text
+pasted in, which breaks the patch.
+<p>
+Then you wait for one of the committers to commit the patch, if it is
+felt appropriate to do so. Bug fixes go in quickly, other changes
+often spark a bit of discussion before a (perhaps revised) commit is
+made.
+<p>
+
+New submissions should be proceeded with [SUBMIT]. The mailer-daemon
+will reject any messages over 100KB, so any large update should be
+zipped up. If your submission is bigger than that, why not break it up
+into separate tasks.
+<p>
+
+We also like submissions to be added to
+<a href="http://issues.apache.org/bugzilla/">bugzilla</a>, so that they dont get lost. Please submit them by first filing the report with a
+meaningful name, then adding files as attachments. Use CVS diff files
+please!
+<p>
+
+If you hear nothing after a couple of weeks, remind the mailing list.
+Sometimes really good submissions get lost in the noise of other issues.
+This is particularly the case just prior to a new point release of
+the product. At that time anything other than bug fixes will tend
+to be neglected.
+
+<h2>Checklists</h2>
+
+These are the things you should verify before submitting patches and new
+tasks. Things don't have to be perfect; it may take a couple of
+iterations before a patch or submission is committed, and these items
+can be addressed in the process. But by the time the code is committed,
+everything including the documentation and some test cases will have
+been done, so getting them out the way up front can save time.
+The committers look more favourably on patches and submissions with test
+cases, while documentation helps sell the reason for a task.
+
+<h3>Checklist before submitting a patch</h3>
+<ul>
+<li>Added code complies with style guidelines
+<li>Code compiles and runs on Java 1.2
+<li>New member variables are private, and provide public accessor methods
+	if access is actually needed.
+<li>Existing test cases succeed.
+<li>New test cases written and succeed.
+<li>Documentation page extended as appropriate.
+<li>Example task declarations in the documentation tested.
+<li>Diff files generated using svn diff -u
+<li>Message to dev contains [PATCH], task name and patch reason in
+subject.
+<li>Message body contains a rationale for the patch.
+<li>Message attachment contains the patch file(s).
+</ul>
+
+<h3>Checklist before submitting a new task</h3>
+<ul>
+<li>Java file begins with Apache copyright and license statement.
+<li>Task does not depend on GPL or LGPL code.
+<li>Source code complies with style guidelines
+<li>Code compiles and runs on Java 1.2
+<li>Member variables are private, and provide public accessor methods
+	if access is actually needed.
+<li><i>Maybe</i> Task has failonerror attribute to control failure behaviour
+<li>New test cases written and succeed
+<li>Documentation page written
+<li>Example task declarations in the documentation tested.
+<li>Patch files generated using svn diff -u
+<li>patch files include a patch to defaults.properties to register the
+tasks
+<li>patch files include a patch to coretasklist.html or
+optionaltasklist.html to link to the new task page
+<li>Message to dev contains [SUBMIT] and task name in subject
+<li>Message body contains a rationale for the task
+<li>Message attachments contain the required files -source, documentation,
+test and patches zipped up to escape the HTML filter.
+</ul>
+
+
+</body></html>
diff --git a/trunk/docs/antlibs/antunit/index.html b/trunk/docs/antlibs/antunit/index.html
new file mode 100755
index 0000000..e04a0aa
--- /dev/null
+++ b/trunk/docs/antlibs/antunit/index.html
@@ -0,0 +1,366 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - AntUnit</title>
+        <link type="text/css" href="../../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">AntUnit</h1>
+            <h3 class="section">
+      <a name="AntUnit 1.0"></a>
+      AntUnit 1.0
+    </h3>
+                        <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+                                <p>Apache AntUnit 1.0 is now available for download as <a href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
+      or <a href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
+      release.</p>
+                        <h3 class="section">
+      <a name="Idea"></a>
+      Idea
+    </h3>
+                        <p>Initially all tests for Ant tasks were written as individual
+      <a href="http://www.junit.org/">JUnit</a> test cases.  Pretty
+      soon it was clear that most tests needed to perform common tasks
+      like reading a build file, initializing a project instance with
+      it and executing a target.  At this point <a href="http://svn.apache.org/viewcvs.cgi/ant/core/trunk/src/testcases/org/apache/tools/ant/BuildFileTest.java">BuildFileTest</a>
+      was invented, a base class for almost all task test cases.</p>
+                                <p>BuildFileTest works fine and in fact has been picked up by <a href="http://ant-contrib.sf.net/">the Ant-Contrib Project</a>
+      and others as well.</p>
+                                <p>Over time a new pattern evolved, more and more tests only
+      executed a target and didn't check any effects.  Instead that
+      target contained the assertions as a <code>&lt;fail&gt;</code>
+      task.  This is an example taken from the build file for the
+      ANTLR task (using Ant 1.7 features):</p>
+                                <pre class="code">
+  &lt;target name=&quot;test3&quot; depends=&quot;setup&quot;&gt;
+    &lt;antlr target=&quot;antlr.g&quot; outputdirectory=&quot;${tmp.dir}&quot;/&gt;
+    &lt;fail&gt;
+      &lt;condition&gt;
+        &lt;!-- to prove each of these files exists;
+             ANTLR &gt;= 2.7.6 leaves behind new (.smap) files as well. --&gt;
+        &lt;resourcecount when=&quot;ne&quot; count=&quot;5&quot;&gt;
+          &lt;fileset dir=&quot;${tmp.dir}&quot;&gt;
+            &lt;include name=&quot;CalcParserTokenTypes.txt&quot; /&gt;
+            &lt;include name=&quot;CalcParserTokenTypes.java&quot; /&gt;
+            &lt;include name=&quot;CalcLexer.java&quot; /&gt;
+            &lt;include name=&quot;CalcParser.java&quot; /&gt;
+            &lt;include name=&quot;CalcTreeWalker.java&quot; /&gt;
+          &lt;/fileset&gt;
+        &lt;/resourcecount&gt;
+      &lt;/condition&gt;
+    &lt;/fail&gt;
+  &lt;/target&gt;
+</pre>
+                                <p>where the corresponding JUnit testcase has been reduced
+      to</p>
+                                <pre class="code">
+...
+public class ANTLRTest extends BuildFileTest {
+
+    private final static String TASKDEFS_DIR = &quot;src/etc/testcases/taskdefs/optional/antlr/&quot;;
+
+    public ANTLRTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + &quot;antlr.xml&quot;);
+    }
+
+    public void tearDown() {
+        executeTarget(&quot;cleanup&quot;);
+    }
+
+    public void test3() {
+        executeTarget(&quot;test3&quot;);
+    }
+...
+}
+</pre>
+                                <p>This approach has a couple of advantages, one of them is that
+      it is very easy to translate an example build file from a bug
+      report into a test case.  If you ask a user for a testcase for a
+      given bug in Ant, he now doesn't need to understand JUnit or how
+      to fit a test into Ant's existing tests any more.</p>
+                                <p>AntUnit takes this approach to testing even further, it
+      removes JUnit completely and it comes with a set of predefined
+      <code>&lt;assert&gt;</code> tasks in order to reuse common kind
+      of checks.</p>
+                                <p>It turns out that AntUnit lends itself as a solution to other
+      problems as well.  The assertions are an easy way to validate a
+      setup before even starting the build process, for example.
+      AntUnit could also be used for functional and integration tests
+      outside of the scope of Ant tasks (assert contents of databases
+      after running an application, assert contents of HTTP responses
+      ...).  This is an area that will need more research.</p>
+                        <h3 class="section">
+      <a name="Concepts"></a>
+      Concepts
+    </h3>
+                              <h4 class="subsection">
+        <a name="antunit Task"></a>
+        antunit Task
+      </h4>
+                        <p>The &lt;antunit&gt; task drives the tests much like
+        &lt;junit&gt; does for JUnit tests.</p>
+                                <p>When called on a build file, the task will start a new Ant
+        project for that build file and scan for targets with names
+        that start with "test".  For each such target it then will</p>
+                                <ol>
+          <li>Execute the target named setUp, if there is one.</li>
+          <li>Execute the target itself - if this target depends on
+          other targets the normal Ant rules apply and the dependent
+          targets are executed first.</li>
+          <li>Execute the target names tearDown, if there is one.</li>
+        </ol>
+                                                          <h4 class="subsection">
+        <a name="Assertions"></a>
+        Assertions
+      </h4>
+                        <p>The base task is <code>&lt;assertTrue&gt;</code>.  It
+        accepts a single nested condition and throws a subclass of
+        BuildException named AssertionFailedException if that
+        condition evaluates to false.</p>
+                                <p>This task could have been implemented using
+        <code>&lt;macrodef&gt;</code> and <code>&lt;fail&gt;</code>,
+        but in fact it is a "real" task so that it is possible to
+        throw a subclass of BuildException.  The
+        <code>&lt;antunit&gt;</code> task catches this exception and
+        marks the target as failed, any other type of Exception
+        (including other BuildException) are test errors.</p>
+                                <p>Together with <code>&lt;assertTrue&gt;</code> there are
+        many predefined assertions for common conditions, most of
+        these are only macros.</p>
+                                                          <h4 class="subsection">
+        <a name="Other Tasks"></a>
+        Other Tasks
+      </h4>
+                        <p>The <code>&lt;logcapturer&gt;</code> captures all messages
+        that pass Ant's logging system and provides them via a
+        reference inside of the project.  If you want to assert
+        certain log messages, you need to start this task (prior to
+        your target under test) and use the
+        <code>&lt;assertLogContains&gt;</code> assertion.</p>
+                                <p><code>&lt;expectFailure&gt;</code> is a task container that
+        catches any BuildException thrown by tasks nested into it.  If
+        no exception has been thrown it will cause a test failure (by
+        throwing an AssertionFailedException).</p>
+                                                          <h4 class="subsection">
+        <a name="AntUnitListener"></a>
+        AntUnitListener
+      </h4>
+                        <p>Part of the library is the <code>AntUnitListener</code>
+        interface that can be used to record test results.  The
+        &lt;antunit&gt; task accepts arbitrary many listeners and
+        relays test results to them.</p>
+                                <p>Currently two implementations -
+        <code>&lt;plainlistener&gt;</code> and <code>xmllistener</code> 
+        modelled after the "plain" and "xml"
+        JUnit listeners - are bundled with the library.</p>
+                                            <h3 class="section">
+      <a name="Examples"></a>
+      Examples
+    </h3>
+                        <p>This is a way to test that <code>&lt;touch&gt;</code>
+      actually creates a file if it doesn't exist:</p>
+                                <pre class="code">
+&lt;project xmlns:au=&quot;antlib:org.apache.ant.antunit&quot;&gt;
+  &lt;!-- is called prior to the test --&gt;
+  &lt;target name=&quot;setUp&quot;&gt;
+    &lt;property name=&quot;foo&quot; value=&quot;foo&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;!-- is called after the test, even if that caused an error --&gt;
+  &lt;target name=&quot;tearDown&quot;&gt;
+    &lt;delete file=&quot;${foo}&quot; quiet=&quot;true&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;!-- the actual test case --&gt;
+  &lt;target name=&quot;testTouchCreatesFile&quot;&gt;
+    &lt;au:assertFileDoesntExist file=&quot;${foo}&quot;/&gt;
+    &lt;touch file=&quot;${foo}&quot;/&gt;
+    &lt;au:assertFileExists file=&quot;${foo}&quot;/&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre>
+                                <p>When running a task like</p>
+                                <pre class="code">
+    &lt;au:antunit&gt;
+      &lt;fileset dir=&quot;.&quot; includes=&quot;touch.xml&quot;/&gt;
+      &lt;au:plainlistener/&gt;
+    &lt;/au:antunit&gt;
+</pre>
+                                <p>from a buildfile of its own you'll get a result that looks like</p>
+                                <pre class="code">
+[au:antunit] Build File: /tmp/touch.xml
+[au:antunit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.249 sec
+[au:antunit] Target: testTouchCreatesFile took 0.183 sec
+
+BUILD SUCCESSFUL
+Total time: 1 second
+</pre>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/bindownload.cgi b/trunk/docs/antlibs/bindownload.cgi
new file mode 100755
index 0000000..4324f76
--- /dev/null
+++ b/trunk/docs/antlibs/bindownload.cgi
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/www.apache.org/dyn/mirrors
+/www/www.apache.org/dyn/mirrors/mirrors.cgi $*
diff --git a/trunk/docs/antlibs/bindownload.html b/trunk/docs/antlibs/bindownload.html
new file mode 100644
index 0000000..7defa62
--- /dev/null
+++ b/trunk/docs/antlibs/bindownload.html
@@ -0,0 +1,309 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Binary Distributions</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                              <span class="sel">Binary Distributions</span>
+                              </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Binary Distributions</h1>
+            <h3 class="section">
+      <a name="Downloading Antlibs"></a>
+      Downloading Antlibs
+    </h3>
+                        <p>Use the links below to download a binary distribution of Antlibs from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>.</p>
+                                <p>Antlibs are distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+                                <p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/antlibs/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/antlibs/">mirror</a>.</p>
+                        <h3 class="section">
+      <a name="Mirror"></a>
+      Mirror
+    </h3>
+                        <p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+                                <form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+                        <h3 class="section">
+      <a name="Current Antlib Releases"></a>
+      Current Antlib Releases
+    </h3>
+                        <div class="warning">
+<div class="label">Note</div>
+<div class="content">Very recent releases may not be available on all
+mirrors for a few days.</div>
+</div>
+                                <br />
+                                <div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+                                <ul>
+<li>Apache .NET Ant Library 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip">apache-ant-dotnet-1.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz">apache-ant-dotnet-1.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2">apache-ant-dotnet-1.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+
+<li>Apache AntUnit 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip">apache-ant-antunit-1.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz">apache-ant-antunit-1.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2">apache-ant-antunit-1.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+</ul>
+                        <h3 class="section">
+      <a name="Verify Releases"></a>
+      Verify Releases
+    </h3>
+                        <p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+                                <p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+                                <p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-dotnet-1.0-bin.tar.gz.asc
+</code></p>
+                                <p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a href="http://www.fourmilab.ch/md5/">here</a>, <a href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+                                <p>We highly recommend to verify the PGP signature, though.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/charter.html b/trunk/docs/antlibs/charter.html
new file mode 100644
index 0000000..d7d73d0
--- /dev/null
+++ b/trunk/docs/antlibs/charter.html
@@ -0,0 +1,345 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Ant Libraries - Charter</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Ant Libraries - Charter</h1>
+            <h3 class="section">
+      <a name="Charter"></a>
+      Charter
+    </h3>
+                        <p>Below is the text of the proposal that has been accepted by
+      the Ant PMC.  Further amendments are expected.</p>
+                                <pre class="code">
+Proposal to Create a Ant-Libraries Sub-Project in Apache Ant
+============================================================
+
+(0) rationale
+
+Ant itself has accumulated lots and lots of tasks over time. So many,
+that Ant developers have become reluctant to adding new
+task. Furthermore any new task in Ant would be tied to Ant's release
+schedule which is too slow for a thriving, fresh piece of code.
+
+The proposal allows Ant tasks and types to be developed under the Ant
+umbrella by Ant developers but have much shorter release cycles than
+Ant itself. In addition it would new committers who would have commit
+access to a single Ant library instead of the whole of Ant.
+
+(1) scope of the subproject
+
+The subproject shall create and maintain libraries of Ant tasks and
+types. Each library will be managed in the same manner as the Ant
+project itself, the PMC is ultimately responsible for it.
+
+Common Java libraries that only happen to provide Ant tasks as well
+are out of scope of the subproject. Providing the tasks or types has
+to be the primary goal of the library.
+
+To further this goal, the subproject shall also host a workplace for
+Ant committers.
+
+(1.5) interaction with other subprojects
+
+(1.5.1) the sandbox
+
+The subproject will host a SVN repository available to all Ant
+committers as a workplace for new Ant libraries.
+
+Before a library can have a public release it has to get promoted to
+the &quot;proper&quot; Ant libraries subproject. This also means it has to match
+the requirements of an Ant library as defined in section (4) under
+Guidelines below.
+
+The status of any library developed in the sandbox shall be reviewed
+after six months and the library gets either promoted or removed - or
+it has to be re-evaluated after another six months.
+
+(2) identify the initial source from which the subproject is to be populated
+
+Some Ant committers have developed tasks or libraries inside of the
+Ant CVS module under the proposal/sandbox directory. Committers are
+free to move them over to the new sandbox subproject or remove them
+completely.
+
+Libraries expected to move to the sandbox subproject initially are
+
+* the .NET tasks under proposal/sandbox/dotnet
+
+* the Subversion support tasks under proposal/sandbox/svn
+
+(3) identify the initial Apache resources to be created
+
+(3.1) mailing list(s)
+
+None. At least at the beginning we don't expect too much traffic and
+the existing mailing lists of the Ant projects will be used.
+
+(3.2) SVN repositories
+
+Create &lt;http://svn.apache.org/repos/asf/ant/&gt;
+
+Expected are sub-directories
+
+antlibs/
+   |
+   -----&gt; proper/
+   |        |
+   |        -----&gt; library1
+   |        |        |
+   |        |        -----------&gt; trunk
+   |        |        -----------&gt; tags
+   |        |        -----------&gt; branches
+   |        -----&gt; library2
+   |                 |
+   |                 -----------&gt; trunk
+   |                 -----------&gt; tags
+   |                 -----------&gt; branches
+   |
+   -----&gt; sandbox/
+            |
+            -----&gt; library1
+            |        |
+            |        -----------&gt; trunk
+            |        -----------&gt; tags
+            |        -----------&gt; branches
+            -----&gt; library2
+                     |
+                     -----------&gt; trunk
+                     -----------&gt; tags
+                     -----------&gt; branches
+
+And potentially collections of all-trunks using svn:external as shown
+by the current Jakarta Commons structure.
+
+(3.3) Bugzilla
+
+New components under product &quot;Ant&quot; for each new library.
+
+(4) identify the initial set of committers
+
+All current Ant PMC members plus the active Ant committers who are not
+PMC members yet.
+
+Guidelines
+----------
+
+Note:
+
+* is, has, will, shall, must - required.
+
+* may, should, are encouraged - optional but recommended.
+
+(1) The primary unit of reuse and release is the Ant library.
+
+(2) The library is not a framework or a general library but a
+    collection of Ant tasks and types.
+
+(3) Each library must have a clearly defined purpose, scope, and API.
+
+(4) Each library is treated as a product in its own right.
+
+(4.1) Each library has its own status file, release schedule, version
+      number, QA tests, documentation, bug category, and individual
+      JAR.
+
+(4.2) Each library must clearly specify any external dependencies,
+      including any other libraries, and the earliest JDK version
+      required.
+
+(4.3) Each library must maintain a list of its active committers in
+      its status file.
+
+(4.4) The libraries should use a standard scheme for versioning, QA
+      tests, and directory layouts, and a common format for
+      documentation and Ant build files.
+
+(4.4) Each library will be hosted on its own page on the subproject
+      Web site, and will also be indexed in a master directory.
+
+(4.5) Volunteers become committers to this subproject in the same way
+      they are entered to any Apache subproject.
+
+      Once the required infrastructure is in place, volunteers may
+      become committers for a single Ant library only.
+
+(4.6) New libraries may be proposed to the Ant dev mailing list. To be
+      accepted, a library proposal must receive majority approval of
+      the Ant PMC. Proposals are to identify the rationale for the
+      library, its scope, the initial source from which the library is
+      to be created, and the initial set of committers.
+
+(4.7) As stated in the Ant guidelines, an action requiring majority
+      approval must receive at least 3 binding +1 votes and more +1
+      votes than -1 votes.
+
+(4.8) Each Ant library needs at least three committers, at least one
+      of them has to be an Ant PMC member.
+      </pre>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/dotnet/index.html b/trunk/docs/antlibs/dotnet/index.html
new file mode 100755
index 0000000..6a1ff39
--- /dev/null
+++ b/trunk/docs/antlibs/dotnet/index.html
@@ -0,0 +1,309 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - .NET Ant Library</title>
+        <link type="text/css" href="../../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">.NET Ant Library</h1>
+            <h3 class="section">
+      <a name=".NET Ant Library 1.0"></a>
+      .NET Ant Library 1.0
+    </h3>
+                        <h3>November 6, 2006 - Apache .NET Ant Library 1.0
+      Available</h3>
+                                <p>Apache .NET Ant Library 1.0 is now available for
+      download as <a href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
+      or <a href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
+      release.</p>
+                        <h3 class="section">
+      <a name="Idea"></a>
+      Idea
+    </h3>
+                        <p>This library doesn't strive to replace NAnt or MSBuild, its
+      main purpose is to help those of us who work on projects
+      crossing platform boundaries.  With this library you can use Ant
+      to build and test the Java as well as the .NET parts of your
+      project.</p>
+                                <p>This library provides a special version of the
+      <code>&lt;exec&gt;</code> task tailored to run .NET executables.
+      On Windows it will assume the Microsoft framework is around and
+      run the executable directly, while it will invoke Mono on any
+      other platform.  Of course you can override these
+      assumptions.</p>
+                                <p>Based on this a few tasks to run well known .NET utilities
+      from within Ant are provided, namely tasks to run <a href="http://www.nunit.org/">NUnit</a>, <a href="http://nant.sf.net/">NAnt</a>, <a href="http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=27&amp;SiteID=1">MSBuild</a>
+      and the <a href="http://wix.sf.net/">Wix</a> toolkit.</p>
+                                <p>The initial .NET tasks of Ant (compiler tasks for C#, J# and VB.NET
+      for example) have also been moved to this Antlib and will see further
+      development here.</p>
+                        <h3 class="section">
+      <a name="Tasks"></a>
+      Tasks
+    </h3>
+                              <h4 class="subsection">
+        <a name="dotnetexec"></a>
+        dotnetexec
+      </h4>
+                        <p>Runs a .NET executable.</p>
+                                                          <h4 class="subsection">
+        <a name="nunit"></a>
+        nunit
+      </h4>
+                        <p>Runs NUnit tests.</p>
+                                                          <h4 class="subsection">
+        <a name="nant"></a>
+        nant
+      </h4>
+                        <p>Invokes NAnt, either on an external file or a build file
+        snippet contained inside your Ant build file.</p>
+                                                          <h4 class="subsection">
+        <a name="msbuild"></a>
+        msbuild
+      </h4>
+                        <p>Invokes MSBuild, either on an external file or a build file
+        snippet contained inside your Ant build file.</p>
+                                                          <h4 class="subsection">
+        <a name="wix"></a>
+        wix
+      </h4>
+                        <p>Invokes the candle and light executables of the WiX toolkit
+          in order to create MSI installers from within Ant.</p>
+                                            <h3 class="section">
+      <a name="Examples"></a>
+      Examples
+    </h3>
+                              <h4 class="subsection">
+        <a name="nant"></a>
+        nant
+      </h4>
+                        <pre class="code">
+&lt;project xmlns:dn=&quot;antlib:org.apache.ant.dotnet&quot;&gt;
+  &lt;dn:nant&gt;
+    &lt;build&gt;
+      &lt;echo message=&quot;Hello world&quot;/&gt;
+    &lt;/build&gt;
+  &lt;/dn:nant&gt;
+&lt;/project&gt;
+</pre>
+                                <p>runs NAnt on the embedded <code>&lt;echo&gt;</code>
+        task, output looks like</p>
+                                <pre class="code">
+Buildfile: test.xml
+[dn:nant] NAnt 0.85 (Build 0.85.1932.0; rc3; 16.04.2005)
+[dn:nant] Copyright (C) 2001-2005 Gerry Shaw
+[dn:nant] http://nant.sourceforge.net
+[dn:nant] 
+[dn:nant] Buildfile: file:///c:/DOKUME~1/STEFAN~1.BOD/LOKALE~1/Temp/build1058451555.xml
+[dn:nant] Target framework: Microsoft .NET Framework 1.1
+[dn:nant] 
+[dn:nant]      [echo] Hello world
+[dn:nant] 
+[dn:nant] BUILD SUCCEEDED
+[dn:nant] 
+[dn:nant] Total time: 0.2 seconds.
+
+BUILD SUCCESSFUL
+Total time: 2 seconds</pre>
+                                                          <h4 class="subsection">
+        <a name="msbuild"></a>
+        msbuild
+      </h4>
+                        <pre class="code">
+&lt;project xmlns:dn=&quot;antlib:org.apache.ant.dotnet&quot;&gt;
+  &lt;dn:msbuild&gt;
+    &lt;build&gt;
+      &lt;Message Text=&quot;Hello world&quot;
+        xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;/&gt;
+    &lt;/build&gt;
+  &lt;/dn:msbuild&gt;
+&lt;/project&gt;</pre>
+                                <p>runs MSBuild on the embedded <code>&lt;Message&gt;</code>
+        task, output looks like</p>
+                                <pre class="code">
+Buildfile: test.xml
+[dn:msbuild] Microsoft (R) Build Engine Version 2.0.50727.42
+[dn:msbuild] [Microsoft .NET Framework, Version 2.0.50727.42]
+[dn:msbuild] Copyright (C) Microsoft Corporation 2005. All rights reserved.
+
+[dn:msbuild] Build started 15.12.2005 20:21:56.
+[dn:msbuild] __________________________________________________
+[dn:msbuild] Project &quot;c:\Dokumente und Einstellungen\stefan.bodewig\Lokale Einstellungen\Temp\build1543310185.xml&quot; (default targets):
+
+[dn:msbuild] Target generated-by-ant:
+[dn:msbuild]     Hello world
+
+[dn:msbuild] Build succeeded.
+[dn:msbuild]     0 Warning(s)
+[dn:msbuild]     0 Error(s)
+
+[dn:msbuild] Time Elapsed 00:00:00.10
+
+BUILD SUCCESSFUL
+Total time: 0 seconds
+</pre>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/index.html b/trunk/docs/antlibs/index.html
new file mode 100644
index 0000000..71bf937
--- /dev/null
+++ b/trunk/docs/antlibs/index.html
@@ -0,0 +1,188 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - The Ant Libraries Subproject</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">The Ant Libraries Subproject</h1>
+            <h3 class="section">
+      <a name="The Ant Libraries Subproject"></a>
+      The Ant Libraries Subproject
+    </h3>
+                        <h3>Ant Libraries - or Antlibs for short</h3>
+                                <p>With Ant 1.6.0 and the ant libraries concept creating
+      libraries of Ant tasks that are easy to get dropped into an
+      existing Ant installation has become far easier.</p>
+                                <p>The Ant Libraries subproject was started as a place to
+      develop small libraries of tasks that can get released
+      independent of Ant's release schedule - which is necessary for
+      nascent Ant tasks since Ant's own release schedule has become
+      rather slow over time.</p>
+                                <p>The subproject also offers a sandbox as playground for Ant
+      committers to try new ideas for tasks.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/proper.html b/trunk/docs/antlibs/proper.html
new file mode 100644
index 0000000..ca31732
--- /dev/null
+++ b/trunk/docs/antlibs/proper.html
@@ -0,0 +1,421 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Ant Libraries</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                              <span class="sel">Ant Libraries</span>
+                              </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Ant Libraries</h1>
+            <h3 class="section">
+      <a name="Ant Libraries"></a>
+      Ant Libraries
+    </h3>
+                        <a name="antunit" />
+                                      <h4 class="subsection">
+        <a name="AntUnit - Unit Test Framework for Ant Tasks"></a>
+        AntUnit - Unit Test Framework for Ant Tasks
+      </h4>
+                        <p>AntUnit borrows ideas from JUnit 3.x and the &lt;junit&gt;
+        task.  It provides a task that runs build files as unit tests
+        as well as a number of assertion tasks to support the
+        idea.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Homepage:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="./antunit/index.html">http://ant.apache.org/antlibs/antunit/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-04-15
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Promoted from sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-11-22
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Latest Release:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.0 released on January 8, 2007
+      </td>
+      </tr>
+          </table>
+                                                    <a name="dotnet" />
+                                      <h4 class="subsection">
+        <a name="DotNet - Improved Support for .NET projects"></a>
+        DotNet - Improved Support for .NET projects
+      </h4>
+                        <p>Provides a simple infrastructure to execute .NET
+        applications from within Ant for different VMs so that the
+        user doesn't have to change the build file when she wants to
+        run Mono on Linux and Microsoft's VM on Windows.</p>
+                                <p>Also contains &lt;nant&gt;, &lt;nunit&gt; and
+        &lt;msbuild&gt; tasks and an untested &lt;wix&gt; tasks.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Homepage:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="./dotnet/index.html">http://ant.apache.org/antlibs/dotnet/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-04-15
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Promoted from sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-11-22
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Latest Release:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.0 released on November 6, 2006
+      </td>
+      </tr>
+          </table>
+                                                    <a name="svn" />
+                                      <h4 class="subsection">
+        <a name="SVN - Subversion Support"></a>
+        SVN - Subversion Support
+      </h4>
+                        <p>Contains tasks that correspond to Ant's &lt;cvs&gt;,
+        &lt;cvschangelog&gt; and &lt;cvstagdiff&gt; tasks.  Requires
+        Subversion's command line client.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Homepage:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="./svn/index.html">http://ant.apache.org/antlibs/svn/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-04-15
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Promoted from sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-11-22
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Latest Release:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          None
+      </td>
+      </tr>
+          </table>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/sandbox.html b/trunk/docs/antlibs/sandbox.html
new file mode 100644
index 0000000..e5b959d
--- /dev/null
+++ b/trunk/docs/antlibs/sandbox.html
@@ -0,0 +1,543 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Ant Libraries - The Sandbox</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Ant Libraries - The Sandbox</h1>
+            <h3 class="section">
+      <a name="Ant Libraries - The Sandbox"></a>
+      Ant Libraries - The Sandbox
+    </h3>
+                        <p>The sandbox is the place where new Ant Libraries start their
+      life, it is a playground for Ant committers and other
+      contributors who find committers to sponsor their ideas.</p>
+                                <p>The sandbox is no dumping ground.  If a Sandbox Ant Library
+      fails to attract interest within a reasonable amount of time, it
+      gets removed from the sandbox.</p>
+                        <h3 class="section">
+      <a name="Current Sandbox Ant Libraries"></a>
+      Current Sandbox Ant Libraries
+    </h3>
+                              <h4 class="subsection">
+        <a name="Debian - Debian related tasks"></a>
+        Debian - Debian related tasks
+      </h4>
+                        <p>Debian provides tasks for generating Debian packages.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://svn.apache.org/repos/asf/ant/sandbox/antlibs/debian/trunk/">https://svn.apache.org/repos/asf/ant/sandbox/antlibs/debian/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/debian/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/debian/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2007-05-18
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Kevin Jackson
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="GenDoc - Generate the manual for Ant Tasks from their sources"></a>
+        GenDoc - Generate the manual for Ant Tasks from their sources
+      </h4>
+                        <p>Most of the information needed for writing the manual is inside the sources: attributes, nested elements (especially
+        inherited one). GenDoc collects these information and generates the manual as xml page. Following steps transform this
+        xml into the final format (HTML in the first step, PDF may follow).</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/gendoc/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/gendoc/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/gendoc/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/gendoc/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2005-04-15
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+           
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="HTTP - tasks for handling HTTP requests"></a>
+        HTTP - tasks for handling HTTP requests
+      </h4>
+                        <p>This antlib contains tasks to make the basic HTTP requests: get, post, head, put, with Basicauthentication.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/http/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/http/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2006-06-27
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+            
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Manual4Eclipse - Generate an Eclipse Help PlugIn from Ant's manual"></a>
+        Manual4Eclipse - Generate an Eclipse Help PlugIn from Ant's manual
+      </h4>
+                        <p>This AntLib provides tasks for generating an Eclipse Help PlugIn from Ant's manual.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/manual4eclipse/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/manual4eclipse/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/manual4eclipse/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/manual4eclipse/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Java compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Java 1.5+
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2007-03-01
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+           
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Props - additional Property Resolver"></a>
+        Props - additional Property Resolver
+      </h4>
+                        <p>This is a library of supplementary handlers for Ant properties resolution.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://svn.apache.org/repos/asf/ant/sandbox/antlibs/props/trunk/">https://svn.apache.org/repos/asf/ant/sandbox/antlibs/props/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/props/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/props/trunk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.8.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2007-07-25
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Matt Benson
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="VSS - Microsoft Visual SourceSafe Tasks"></a>
+        VSS - Microsoft Visual SourceSafe Tasks
+      </h4>
+                        <p>This antlib provides an interface to the Microsoft Visual SourceSafe SCM. The original tasks 
+        (org.apache.tools.ant.taskdefs.optional.vss) have been expanded upon in this antlib. 
+        Some fixes to issues in the original tasks have also been incorporated.</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          SVN URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/vss/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/vss/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          ViewSVN:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/vss/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/vss/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Added to sandbox:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2006-04-26  
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sponsoring Committers
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+            
+      </td>
+      </tr>
+          </table>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/srcdownload.cgi b/trunk/docs/antlibs/srcdownload.cgi
new file mode 100755
index 0000000..4324f76
--- /dev/null
+++ b/trunk/docs/antlibs/srcdownload.cgi
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/www.apache.org/dyn/mirrors
+/www/www.apache.org/dyn/mirrors/mirrors.cgi $*
diff --git a/trunk/docs/antlibs/srcdownload.html b/trunk/docs/antlibs/srcdownload.html
new file mode 100644
index 0000000..d0b9701
--- /dev/null
+++ b/trunk/docs/antlibs/srcdownload.html
@@ -0,0 +1,309 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Source Distributions</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                              <span class="sel">Source Distributions</span>
+                              </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Source Distributions</h1>
+            <h3 class="section">
+      <a name="Downloading Antlibs"></a>
+      Downloading Antlibs
+    </h3>
+                        <p>Use the links below to download a source distribution of Antlibs from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>.</p>
+                                <p>Antlibs are distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+                                <p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/antlibs/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/antlibs/">mirror</a>.</p>
+                        <h3 class="section">
+      <a name="Mirror"></a>
+      Mirror
+    </h3>
+                        <p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+                                <form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+                        <h3 class="section">
+      <a name="Current Antlib Releases"></a>
+      Current Antlib Releases
+    </h3>
+                        <div class="warning">
+<div class="label">Note</div>
+<div class="content">Very recent releases may not be available on all
+mirrors for a few days.</div>
+</div>
+                                <br />
+                                <div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+                                <ul>
+<li>Apache .NET Ant Library 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip">apache-ant-dotnet-1.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz">apache-ant-dotnet-1.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2">apache-ant-dotnet-1.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+
+<li>Apache AntUnit 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip">apache-ant-antunit-1.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz">apache-ant-antunit-1.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2">apache-ant-antunit-1.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+</ul>
+                        <h3 class="section">
+      <a name="Verify Releases"></a>
+      Verify Releases
+    </h3>
+                        <p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+                                <p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+                                <p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-dotnet-1.0-bin.tar.gz.asc
+</code></p>
+                                <p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a href="http://www.fourmilab.ch/md5/">here</a>, <a href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+                                <p>We highly recommend to verify the PGP signature, though.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antlibs/svn/index.html b/trunk/docs/antlibs/svn/index.html
new file mode 100755
index 0000000..53df306
--- /dev/null
+++ b/trunk/docs/antlibs/svn/index.html
@@ -0,0 +1,215 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Subversion Ant Library</title>
+        <link type="text/css" href="../../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Subversion Ant Library</h1>
+            <h3 class="section">
+      <a name="Idea"></a>
+      Idea
+    </h3>
+                        <p>The main purpose of this Ant library is to provide the same
+      level of support that Ant provides for CVS.  This means the
+      tasks are wrappers on top of the command line client (read: you
+      still need to install an svn client) and there is not much more
+      than running the executable and creating some reports.</p>
+                                <p>If you are looking for projects that aim at more, there are
+      better alternatives, for example <a href="http://subclipse.tigris.org/svnant.html">Subclipse's Ant
+      task</a> or <a href="http://tmate.org/svn/ant.html">JavaSVN</a>.</p>
+                        <h3 class="section">
+      <a name="Tasks"></a>
+      Tasks
+    </h3>
+                              <h4 class="subsection">
+        <a name="svn"></a>
+        svn
+      </h4>
+                        <p>A very thin layer on top of the command line executable,
+        comparable to <a href="http://ant.apache.org/manual/CoreTasks/cvs.html">the CVS
+        task</a>.</p>
+                                                          <h4 class="subsection">
+        <a name="changelog"></a>
+        changelog
+      </h4>
+                        <p>Creates a log of change comments between two revisions,
+        comparable to <a href="http://ant.apache.org/manual/CoreTasks/changelog.html">CvsChangeLog</a>.</p>
+                                                          <h4 class="subsection">
+        <a name="*diff"></a>
+        *diff
+      </h4>
+                        <p><code>&lt;tagdiff&gt;</code> creates a differences report
+        for the changes between two tags or branches.</p>
+                                <p><code>&lt;revisiondiff&gt;</code> creates a differences report
+        for the changes between two revisions.</p>
+                                <p>Together comparable to <a href="http://ant.apache.org/manual/CoreTasks/cvstagdiff.html">CvsTagDiff</a>.</p>
+                                            <h3 class="section">
+      <a name="Examples"></a>
+      Examples
+    </h3>
+        
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/antnews.html b/trunk/docs/antnews.html
new file mode 100644
index 0000000..c4c43fc
--- /dev/null
+++ b/trunk/docs/antnews.html
@@ -0,0 +1,584 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - News</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Conor MacNeill">
+  <meta name="email" content="">
+        <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="">
+        <meta name="author" content="Magesh Umasankar">
+  <meta name="email" content="">
+        <meta name="author" content="Antoine Levy-Lambert">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                              <span class="sel">News</span>
+                              </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">News</h1>
+            <h3 class="section">
+      <a name="Apache Ivy is an Ant Sub-Project Now!"></a>
+      Apache Ivy is an Ant Sub-Project Now!
+    </h3>
+                        <h3>October 11, 2007 - Apache Ivy is an Ant Sub-Project Now!</h3>
+                                <p>Apache Ivy, "A Java based tool for tracking, resolving and
+    managing project dependencies.", just finished <a href="http://incubator.apache.org/">Incubation</a> and has joined
+    the Ant project.  More information will be available from the Ant
+    site soon.</p>
+                                <p>Until we've finished the migration, you can learn more about
+    Ivy from its <a href="http://incubator.apache.org/ivy/">Incubator
+    website</a>.</p>
+                        <h3 class="section">
+      <a name="AntUnit 1.0"></a>
+      AntUnit 1.0
+    </h3>
+                        <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+                                <p>Apache AntUnit 1.0 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a href="antlibs/antunit/">AntUnit home page</a>.</p>
+                        <h3 class="section">
+      <a name="Ant 1.7.0"></a>
+      Ant 1.7.0
+    </h3>
+                        <h3>December 19, 2006 - Ant 1.7.0 Available</h3>
+                                <p>Apache Ant 1.7.0 is now available for <a href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+                                <p> Ant 1.7 introduces a resource framework. Some of the core ant 
+    tasks such as &lt;copy/&gt; are now able to process not only file 
+    system resources but also zip entries, tar entries, paths, ... 
+    Resource collections group resources, and can be further 
+    combined with operators such as union and intersection. This 
+    can be extended by custom resources and custom tasks using resources.</p>
+                                <p>
+    Ant 1.7 starts outsourcing of optional tasks to Antlibs. 
+    The .NET antlib in preparation will replace the .NET optional tasks which ship in Ant.
+    Support for the version control system Subversion will be only provided as an antlib to
+    be released shortly. 
+    </p>
+                                <p>Ant 1.7 fixes also a large number of bugs.</p>
+                                <p>Ant 1.7 has some initial support for Java6 features.</p>
+                        <h3 class="section">
+      <a name=".NET Ant Library 1.0Beta1"></a>
+      .NET Ant Library 1.0Beta1
+    </h3>
+                        <h3>November 6, 2006 - Apache .NET Ant Library 1.0 Available</h3>
+                                <p>Apache .NET Ant Library 1.0 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+                                <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+                        <h3 class="section">
+      <a name="AntUnit 1.0Beta2"></a>
+      AntUnit 1.0Beta2
+    </h3>
+                        <h3>October 29, 2006 - Apache AntUnit 1.0Beta2 Available</h3>
+                                <p>Apache AntUnit 1.0Beta1 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a href="antlibs/antunit/">AntUnit home page</a>.</p>
+                        <h3 class="section">
+      <a name="AntUnit 1.0Beta1"></a>
+      AntUnit 1.0Beta1
+    </h3>
+                        <h3>September 22, 2006 - Apache AntUnit 1.0Beta1 Available</h3>
+                                <p>Apache AntUnit 1.0Beta1 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a href="antlibs/antunit/">AntUnit home page</a>.</p>
+                        <h3 class="section">
+      <a name=".NET Ant Library 1.0Beta1"></a>
+      .NET Ant Library 1.0Beta1
+    </h3>
+                        <h3>September 13, 2006 - Apache .NET Ant Library 1.0Beta1 Available</h3>
+                                <p>Apache .NET Ant Library 1.0Beta1 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+                                <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+                        <h3 class="section">
+      <a name="Ant 1.6.5"></a>
+      Ant 1.6.5
+    </h3>
+                        <h3>June 2, 2005 - Ant 1.6.5 Available</h3>
+                                <p>Apache Ant 1.6.5 is now available for <a href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+                                <p>This is a bug fix release.</p>
+                        <h3 class="section">
+      <a name="Ant 1.6.4"></a>
+      Ant 1.6.4
+    </h3>
+                        <h3>May 19, 2005 - Ant 1.6.4 Available</h3>
+                                <p>Apache Ant 1.6.4 is now available for <a href="http://archive.apache.org/dist/ant/">download</a>.</p>
+                                <p>This is a bug fix release.</p>
+                        <h3 class="section">
+      <a name="Ant 1.6.3"></a>
+      Ant 1.6.3
+    </h3>
+                        <h3>April 28, 2005 - Ant 1.6.3 Available</h3>
+                                <p>Apache Ant 1.6.3 is now available for <a href="http://archive.apache.org/dist/ant/">download</a>.</p>
+                                <p>There is a large list of fixed bugs and enhancements.</p>
+                                <p>Some of the bugs affecting the embedded use of Ant are fixed.</p>
+                        <h3 class="section">
+      <a name="Antidote Retired"></a>
+      Antidote Retired
+    </h3>
+                        <h3>April 4th, 2005 - The Apache Ant Project Retires Antidote, the
+    Ant GUI</h3>
+                                <p>The Antidote subproject was once started to provide a GUI for
+    Ant at a time where IDE support for Ant was far from usable.
+    Unfortunately it never attracted a developer community of its
+    own.</p>
+                                <p>At the same time IDE support for Ant has become ubiquitous by
+    now and there is little reason to have a GUI just for Ant.  This
+    makes it even less likely that volunteers will start to spend time
+    working on it.</p>
+                                <p>Antidote's development has been stalled for years now, despite
+    some efforts to rejuvenate it by single developers.  Therefore the
+    Ant developers have chosen to retire Antidote.</p>
+                                <p>Antidote will no longer be developed by the Ant project; its
+    CVS module will be shut down.</p>
+                                <p>If you are interested in Antidote's sources to learn from or
+    build on it, you can find snapshots at <a href="http://archive.apache.org/ant/antidote/">http://archive.apache.org/ant/antidote/</a>.</p>
+                        <h3 class="section">
+      <a name="Ant 1.6.2"></a>
+      Ant 1.6.2
+    </h3>
+                        <h3>July 16, 2004 - Ant 1.6.2 Available</h3>
+                                <p>Apache Ant 1.6.2 available for <a href="http://archive.apache.org/dist/ant/">download</a>.</p>
+                                <p>Nested elements for namespaced tasks and types may belong to the
+Ant default namespace as well as the task's or type's namespace.</p>
+                                <p>All exceptions thrown by tasks are now wrapped in a
+buildexception giving the location in the buildfile of the task.</p>
+                                <p>Ant 1.6.2 fixes a large number of bugs and adds a number of
+features which were asked for by users on Bugzilla.</p>
+                        <h3 class="section">
+      <a name="Wiki Migration"></a>
+      Wiki Migration
+    </h3>
+                        <h3>February 29, 2004</h3>
+                                <p>The Ant Wiki pages have been migrated to their 
+      <a href="http://wiki.apache.org/ant/">new home</a> on the Apache
+      Wiki farm.
+    </p>
+                        <h3 class="section">
+      <a name="Ant 1.6.1"></a>
+      Ant 1.6.1
+    </h3>
+                        <h3>February 12, 2004 - Ant 1.6.1 Available</h3>
+                                <p>Apache Ant 1.6.1 is still available for
+      <a href="http://archive.apache.org/dist/ant/">download</a>.
+     </p>
+                                <p>The ASF Board has approved the new Apache License 2.0.
+    For a copy of that license, please see
+    <a href="http://www.apache.org/licenses/">
+    http://www.apache.org/licenses/</a>.</p>
+                                <p>The Ant 1.6.1 release is delivered with the
+    Apache License 2.0.</p>
+                                <p>Ant 1.6.1 fixes several bugs, most notably the handling
+    of the default namespace for nested elements.</p>
+                                <p>Ant 1.6.1 also introduces initial support for compiling with
+    Java 1.5.</p>
+                        <h3 class="section">
+      <a name="Ant 1.6.0"></a>
+      Ant 1.6.0
+    </h3>
+                        <h3>December 18, 2003 - Ant 1.6.0 Available</h3>
+                                <p>Apache Ant 1.6.0 is still available for
+      <a href="http://archive.apache.org/dist/ant/">download</a>.
+     </p>
+                                <p>As
+    we've already said in the announcements of Ant 1.5.4, this release
+    requires JDK 1.2 or later to run.</p>
+                                <p>Ant 1.6.0 adds a lot of new features, most prominently support
+    for XML namespaces as well as a new concept of Ant libraries that
+    makes use of namespaces to avoid name clashes of custom tasks.
+    For a longer list of fixed bugs and new features see the release
+    notes.</p>
+                                <p>If you find anything that hasn't been covered in the manual (I bet you
+did) or could be explained better, feel free to help us out in the
+<a href="http://wiki.apache.org/ant/NewAntFeaturesInDetail">Wiki</a>.</p>
+                        <h3 class="section">
+      <a name="Ant 1.5.4"></a>
+      Ant 1.5.4
+    </h3>
+                        <h3>August 12, 2003 - Ant 1.5.4 Available</h3>
+                                <p>Apache Ant 1.5.4 is still available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+    </p>
+                                <p>This is a minor bugfix release that fixes a problem with the
+    <code>javah</code> task on JDK 1.4.2 and a couple of bugs in the
+    Visual Age for Java intergration tasks.  If you don't use javah or
+    VAJ, there is no reason to upgrade.</p>
+                                <div class="warning">
+    <div class="label">Note</div>
+    <div class="content">Ant 1.5.4 is the last release that supports
+      JDK 1.1. Ant 1.6.0 requires JDK 1.2 or
+      later.
+    </div>
+    </div>
+                        <h3 class="section">
+      <a name="Java Pro 2003 Readers Choice Award"></a>
+      Java Pro 2003 Readers Choice Award
+    </h3>
+                        <a href="http://www.ftponline.com/javapro/">
+      <img style="padding: 5px" src="images/jp_rcwinner_2003.gif" alt="" border="0" height="80" width="139" align="right" /></a>
+                                <h3>June 11th, 2003: Ant wins a Java Pro readers' choice award</h3>
+                                <p>
+      Ant has won the Java Pro 2003 Readers' Choice Award for 
+    </p>
+                                <p>
+      <strong>Most Valuable Java Deployment Technology</strong>.
+    </p>
+                                <p>
+      Thanks to Java Pro and all its readers. You can read about
+      these 
+      <a href="http://www.ftponline.com/reports/javaone/2003/awards/">awards</a>
+      at the Java Pro website.
+    </p>
+                        <h3 class="section">
+      <a name="JDJ Editors Choice Award"></a>
+      JDJ Editors Choice Award
+    </h3>
+                        <a href="http://sys-con.com/java/article2a.cfm?id=2059&amp;count=1734&amp;tot=6&amp;page=2"><img src="images/JDJEditorsChoiceAward.jpg" alt="" border="0" align="right" /></a>
+                                <h3>June 2003: Ant wins JDJ Editors' Choice Award</h3>
+                                <p>
+"Ant is the hammer of the Java world: without it, civilization might have progressed, but much more slowly than it has. Ant is one of the most useful build tools I have ever had the pleasure to use." - Joe Ottinger
+    </p>
+                        <h3 class="section">
+      <a name="Ant keeps on winning!"></a>
+      Ant keeps on winning!
+    </h3>
+                        <a href="http://www.javaworld.com/"><img src="images/jw_ec_logo_winner2003.gif" alt="" border="0" height="108" width="252" align="right" /></a>
+                                <h3>June 9th, 2003: Ant wins the JavaWorld Editors' Choice Award</h3>
+                                <p>
+    Ant has won the JavaWorld Editors' Choice Award for
+    </p>
+                                <p>
+    <strong>Most Useful Java Community-Developed Technology</strong>
+    </p>
+                                <p>
+    for the second time in a row! Read the
+    <a href="http://www.javaworld.com/javaworld/jw-06-2003/jw-0609-eca.html"> full article</a> -- or jump directly to the bit about
+    <a href="http://www.javaworld.com/javaworld/jw-06-2003/jw-0609-eca-p4.html"> our award</a> <code>:)</code></p>
+                        <h3 class="section">
+      <a name="Ant 1.5.3"></a>
+      Ant 1.5.3
+    </h3>
+                        <h3>April 9, 2003 - Ant 1.5.3 Available</h3>
+                                <p>Apache Ant 1.5.3 is still available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+    </p>
+                        <h3 class="section">
+      <a name="Ant 1.5.2"></a>
+      Ant 1.5.2
+    </h3>
+                        <h3>March 3, 2003 - Ant 1.5.2 Available!</h3>
+                                <p>The final version of Ant 1.5.2 is available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+     If you have any feedback on this release, feel free to join the 
+     discussion on the dev and user mailing lists.
+     </p>
+                        <h3 class="section">
+      <a name="Ant Top Level Project"></a>
+      Ant Top Level Project
+    </h3>
+                        <h3>November 18, 2002</h3>
+                                <p>The Apache board <a href="mission.html">created</a>
+       the Apache Ant top level project. Ant has now migrated from the Jakarta
+       project into an Apache project of its own. This is primarily an
+       organizational change and will not affect the technical aspects of
+       the project. Ant retains a strong association with the Apache
+       Jakarta project. One effect of this change is that the Ant webpage
+       is now located at <a href="http://ant.apache.org/">http://ant.apache.org/</a>
+     </p>
+                        <h3 class="section">
+      <a name="Ant 1.5.1"></a>
+      Ant 1.5.1
+    </h3>
+                        <h3>October 3, 2002 - Ant 1.5.1 Available !</h3>
+                                <p>The final version of Ant 1.5.1 is still available for
+     <a href="http://archive.apache.org/dist/ant/">
+     download</a>. If you have any feedback on this release, feel free to join the 
+     discussion on the ant-dev and ant-user mailing lists.
+     </p>
+                        <h3 class="section">
+      <a name="Ant 1.5"></a>
+      Ant 1.5
+    </h3>
+                        <h3>July 15, 2002 - Fix for Cygwin problem in wrapper script available</h3>
+                                <p>The wrapper script of Ant 1.5 needs to be replaced with a new
+      version for Cygwin users.  See the <a href="faq.html#1.5-cygwin-sh">FAQ</a> for details.</p>
+                                <h3>July 10, 2002 - Ant 1.5 Released!</h3>
+                                <p>The final version of Ant 1.5 is now available for 
+     <a href="http://archive.apache.org/dist/ant/">
+     download</a>. If you have any feedback on this release, feel free to join the 
+     discussion on the ant-dev and ant-user mailing lists.
+     </p>
+                        <h3 class="section">
+      <a name="Ant wins again!"></a>
+      Ant wins again!
+    </h3>
+                        <a href="http://www.sdmagazine.com/"><img src="images/sdm_productivity_award.gif" alt="" border="0" height="108" width="181" align="right" /></a>
+                                <h3>Apr 29, 2002: Ant wins <em>Software Development</em> magazine's
+    2002 Productivity Award.</h3>
+                                <p>
+    Ant has been awarded a <strong>2002 Productivity Award</strong> by
+    <a href="http://www.sdmagazine.com/"><em>Software Development</em></a>
+    magazine.  Read the
+    <a href="http://www.sdmagazine.com/jolts/press_release_4-26-02.htm">
+    press release</a> for more information and the full list of winners.
+    </p>
+                        <h3 class="section">
+      <a name="Ant has won!"></a>
+      Ant has won!
+    </h3>
+                        <a href="http://www.javaworld.com/"><img src="images/jw_ec_logo_winner2002.gif" alt="" border="0" height="108" width="252" align="right" /></a>
+                                <h3>Mar 26, 2002: Ant wins the JavaWorld Editors' Choice
+    Award</h3>
+                                <p>
+    Ant has won the JavaWorld Editors' Choice Award for
+    <strong>Most Useful Java Community-Developed Technology</strong>.
+    Read the
+    <a href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html "> full article</a> -- or jump directly to the bit about
+    <a href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards-p3.html"> our award</a> <code>:)</code></p>
+                        <h3 class="section">
+      <a name="Java 1.4 Support"></a>
+      Java 1.4 Support
+    </h3>
+                        <h3>Feb 15, 2002: Java 1.4 Support</h3>
+                                <p>
+      Java 1.4 has now been released by Sun. The latest Ant source supports 
+      the new <tt>assert</tt> statement in the compiler task via the <tt>source</tt> 
+      attribute. It also contains a compatibility fix needed for some ant tasks
+      on Java 1.4 over Windows XP. If you have problems running Ant 1.4.1 on WinXP/Java 1.4,
+      please use a recent build or compile your own version from the source tree. 
+    </p>
+                        <h3 class="section">
+      <a name="See our new logo!"></a>
+      See our new logo!
+    </h3>
+                        <h3>Have a look at our new cool logo!</h3>
+                        <h3 class="section">
+      <a name="Ant 1.4.1"></a>
+      Ant 1.4.1
+    </h3>
+                        <h3>11 October 2001 Ant 1.4.1 released !</h3>
+                                <p>Please visit the 
+     <a href="http://archive.apache.org/dist/ant/">
+     download area</a>. 
+     </p>
+                        <h3 class="section">
+      <a name="Best-Practices Profile of Ant at Sun's Dot-Com Builder"></a>
+      Best-Practices Profile of Ant at Sun's Dot-Com Builder
+    </h3>
+                        <p>Sun has released an introductory article on Ant on their
+      Dot-Com Builder site on May 30 2001. See <a href="http://dcb.sun.com/practices/profiles/ant.jsp">http://dcb.sun.com/practices/profiles/ant.jsp</a></p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/appendix_e.pdf b/trunk/docs/appendix_e.pdf
new file mode 100644
index 0000000..81e5aa8
--- /dev/null
+++ b/trunk/docs/appendix_e.pdf
Binary files differ
diff --git a/trunk/docs/bindownload.cgi b/trunk/docs/bindownload.cgi
new file mode 100755
index 0000000..4324f76
--- /dev/null
+++ b/trunk/docs/bindownload.cgi
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/www.apache.org/dyn/mirrors
+/www/www.apache.org/dyn/mirrors/mirrors.cgi $*
diff --git a/trunk/docs/bindownload.html b/trunk/docs/bindownload.html
new file mode 100644
index 0000000..d075dbf
--- /dev/null
+++ b/trunk/docs/bindownload.html
@@ -0,0 +1,347 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Binary Distributions</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                              <span class="sel">Binary Distributions</span>
+                              </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Binary Distributions</h1>
+            <h3 class="section">
+      <a name="Downloading Ant"></a>
+      Downloading Ant
+    </h3>
+                        <p>Use the links below to download a binary distribution of Ant from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>.</p>
+                                <p>Ant is distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+                                <p>In addition the <a href="http://www.jpackage.org">JPackage
+project</a> provides RPMs at their own distribution site.</p>
+                                <p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/">mirror</a>.</p>
+                        <h3 class="section">
+      <a name="Mirror"></a>
+      Mirror
+    </h3>
+                        <p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+                                <form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+                        <h3 class="section">
+      <a name="Current Release of Ant"></a>
+      Current Release of Ant
+    </h3>
+                        <p>Currently, Apache Ant 1.7.0 is the best available version, see the
+<a href="[preferred]/ant/README.html">release notes</a>.</p>
+                                <div class="warning">
+<div class="label">Note</div>
+<div class="content">Ant 1.7.0 has been released on 19-Dec-2006 and
+may not be available on all mirrors for a few days.</div>
+</div>
+                                <br />
+                                <div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+                                <ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.zip">apache-ant-1.7.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.tar.gz">apache-ant-1.7.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.tar.bz2">apache-ant-1.7.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+                        <h3 class="section">
+      <a name="Old Ant Releases"></a>
+      Old Ant Releases
+    </h3>
+                        <p>Older releases of Ant can be found <a href="http://archive.apache.org/dist/ant/binaries/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a href="[location]#Current Release of Ant">latest</a> release.</p>
+                        <h3 class="section">
+      <a name="Verify Releases"></a>
+      Verify Releases
+    </h3>
+                        <p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+                                <p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+                                <p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-1.7.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-1.7.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-1.7.0-bin.tar.gz.asc
+</code></p>
+                                <p>A command line version of <a href="http://www.gnupg.org/download/">GnuPG</a> 
+is also available for Windows users.  Follow the 
+<a href="http://www.gnupg.org/(en)/documentation/faqs.html#q4.19">instructions</a> 
+to verify the package.</p>
+                                <p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a href="http://www.fourmilab.ch/md5/">here</a>, <a href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+                                <p>We highly recommend to verify the PGP signature, though.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/breadcrumbs.js b/trunk/docs/breadcrumbs.js
new file mode 100644
index 0000000..8e172c8
--- /dev/null
+++ b/trunk/docs/breadcrumbs.js
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/**
+ * This script, when included in a html file, builds a neat breadcrumb trail
+ * based on its url. That is, if it doesn't contains bugs (I'm relatively
+ * sure it does).
+ *
+ * Typical usage:
+ * <script type="text/javascript" language="JavaScript" src="breadcrumbs.js"></script>
+ *
+ *@author     <a href="mailto:leosimons@apache.org">Leo Simons</a> (main author)
+ *@author     <a href="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a> (integration in skin)
+ *@created    July 12, 2002
+ *@version    1.0
+ */
+
+/**
+ * IE 5 on Mac doesn't know Array.push.
+ *
+ * Implement it - courtesy to fritz.
+ */
+var abc	= new Array();
+if (!abc.push) {
+  Array.prototype.push	= function(what){this[this.length]=what}
+}
+
+/* ========================================================================
+	CONSTANTS
+   ======================================================================== */
+
+/**
+ * Two-dimensional array containing extra crumbs to place at the front of
+ * the trail. Specify first the name of the crumb, then the URI that belongs
+ * to it. You'll need to modify this for every domain or subdomain where
+ * you use this script (you can leave it as an empty array if you wish)
+ */
+var PREPREND_CRUMBS = new Array();
+   if(!("apache"=="")){
+     PREPREND_CRUMBS.push( new Array( "apache", "http://www.apache.org/" ) );
+   }
+   if(!("xml.apache"=="")){
+     PREPREND_CRUMBS.push( new Array( "ant.apache", "http://ant.apache.org/" ) );
+   }
+   if(!(""=="")){
+     PREPREND_CRUMBS.push( new Array( "", "" ) );
+   }
+
+/**
+ * String to include between crumbs:
+ */
+var DISPLAY_SEPARATOR = " &gt; ";
+/**
+ * String to include at the beginning of the trail
+ */
+var DISPLAY_PREPREND = "";
+/**
+ * String to include at the end of the trail
+ */
+var DISPLAY_POSTPREND = "";
+
+/**
+ * CSS Class to use for a single crumb:
+ */
+var CSS_CLASS_CRUMB = "breadcrumb";
+
+/**
+ * CSS Class to use for the complete trail:
+ */
+var CSS_CLASS_TRAIL = "breadcrumbTrail";
+
+/**
+ * CSS Class to use for crumb separator:
+ */
+var CSS_CLASS_SEPARATOR = "crumbSeparator";
+
+/**
+ * Array of strings containing common file extensions. We use this to
+ * determine what part of the url to ignore (if it contains one of the
+ * string specified here, we ignore it).
+ */
+var FILE_EXTENSIONS = new Array( ".html", ".htm", ".jsp", ".php", ".php3", ".php4" );
+
+/**
+ * String that separates parts of the breadcrumb trail from each other.
+ * When this is no longer a slash, I'm sure I'll be old and grey.
+ */
+var PATH_SEPARATOR = "/";
+
+/* ========================================================================
+	UTILITY FUNCTIONS
+   ======================================================================== */
+/**
+ * Capitalize first letter of the provided string and return the modified
+ * string.
+ */
+function sentenceCase( string )
+{
+	var lower = string.toLowerCase();
+	return lower.substr(0,1).toUpperCase() + lower.substr(1);
+}
+
+/**
+ * Returns an array containing the names of all the directories in the
+ * current document URL
+ */
+function getDirectoriesInURL()
+{
+	var trail = document.location.pathname.split( PATH_SEPARATOR );
+
+	// check whether last section is a file or a directory
+	var lastcrumb = trail[trail.length-1];
+	for( var i = 0; i < FILE_EXTENSIONS.length; i++ )
+	{
+		if( lastcrumb.indexOf( FILE_EXTENSIONS[i] ) )
+		{
+			// it is, remove it and send results
+			return trail.slice( 1, trail.length-1 );
+		}
+	}
+
+	// it's not; send the trail unmodified
+	return trail.slice( 1, trail.length );
+}
+
+/* ========================================================================
+	BREADCRUMB FUNCTIONALITY
+   ======================================================================== */
+/**
+ * Return a two-dimensional array describing the breadcrumbs based on the
+ * array of directories passed in.
+ */
+function getBreadcrumbs( dirs )
+{
+	var prefix = "/";
+	var postfix = "/";
+
+	// the array we will return
+	var crumbs = new Array();
+
+	if( dirs != null )
+	{
+		for( var i = 0; i < dirs.length; i++ )
+		{
+			prefix += dirs[i] + postfix;
+			crumbs.push( new Array( dirs[i], prefix ) );
+		}
+	}
+
+	// preprend the PREPREND_CRUMBS
+	if(PREPREND_CRUMBS.length > 0 )
+	{
+		return PREPREND_CRUMBS.concat( crumbs );
+	}
+
+	return crumbs;
+}
+
+/**
+ * Return a string containing a simple text breadcrumb trail based on the
+ * two-dimensional array passed in.
+ */
+function getCrumbTrail( crumbs )
+{
+	var xhtml = DISPLAY_PREPREND;
+
+	for( var i = 0; i < crumbs.length; i++ )
+	{
+		xhtml += '<a href="' + crumbs[i][1] + '" >';
+		xhtml += sentenceCase( crumbs[i][0] ) + '</a>';
+		if( i != (crumbs.length-1) )
+		{
+			xhtml += DISPLAY_SEPARATOR;
+		}
+	}
+
+	xhtml += DISPLAY_POSTPREND;
+
+	return xhtml;
+}
+
+/**
+ * Return a string containing an XHTML breadcrumb trail based on the
+ * two-dimensional array passed in.
+ */
+function getCrumbTrailXHTML( crumbs )
+{
+	var xhtml = '<span class="' + CSS_CLASS_TRAIL  + '">';
+	xhtml += DISPLAY_PREPREND;
+
+	for( var i = 0; i < crumbs.length; i++ )
+	{
+		xhtml += '<a href="' + crumbs[i][1] + '" class="' + CSS_CLASS_CRUMB + '">';
+		xhtml += sentenceCase( crumbs[i][0] ) + '</a>';
+		if( i != (crumbs.length-1) )
+		{
+			xhtml += '<span class="' + CSS_CLASS_SEPARATOR + '">' + DISPLAY_SEPARATOR + '</span>';
+		}
+	}
+
+	xhtml += DISPLAY_POSTPREND;
+	xhtml += '</span>';
+
+	return xhtml;
+}
+
+/* ========================================================================
+	PRINT BREADCRUMB TRAIL
+   ======================================================================== */
+
+// check if we're local; if so, only print the PREPREND_CRUMBS
+if( document.location.href.toLowerCase().indexOf( "http://" ) == -1 )
+{
+	document.write( getCrumbTrail( getBreadcrumbs() ) );
+}
+else
+{
+	document.write( getCrumbTrail( getBreadcrumbs( getDirectoriesInURL() ) ) );
+}
+
diff --git a/trunk/docs/bugs.html b/trunk/docs/bugs.html
new file mode 100644
index 0000000..ff96ff7
--- /dev/null
+++ b/trunk/docs/bugs.html
@@ -0,0 +1,372 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Bug database</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Antoine Levy-Lambert">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Bug database</h1>
+            <h3 class="section">
+      <a name="Bug Database"></a>
+      Bug Database
+    </h3>
+                        <p>
+           This page gives you some bookmarks to use the Bugzilla <a href="http://issues.apache.org/bugzilla/">
+            Apache Bug Database</a>.
+         </p>
+                                <p>
+           This link <a href="http://issues.apache.org/">issues.apache.org</a> connects you
+           to the complete list of Apache Bug Database systems.
+         </p>
+                                      <h4 class="subsection">
+        <a name="Has It Been Reported?"></a>
+        Has It Been Reported?
+      </h4>
+                        <p>
+            If the current nightly build doesn't resolve your problem, it is
+            possible that someone else has reported the issue. It is time to
+            look at the bug database. This system is easy to use, and it will
+            let you search the <a href="http://issues.apache.org/bugzilla/buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;email1=&amp;emailtype1=substring&amp;emailassigned_to1=1&amp;email2=&amp;emailtype2=substring&amp;emailreporter2=1&amp;bugidtype=include&amp;bug_id=&amp;changedin=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;product=Ant&amp;short_desc=&amp;short_desc_type=substring&amp;long_desc=&amp;long_desc_type=substring&amp;bug_file_loc=&amp;bug_file_loc_type=substring&amp;keywords=&amp;keywords_type=anywords&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;order=bugs.bug_id">
+            currently open</a> and resolved bugs to see if your problem has
+            already been reported. If your problem has been reported, you can
+            see whether any of the developers have commented, suggesting
+            workarounds, or the reason for the bug, etc. Or you may have
+            information to add (see about creating and modifying bug reports
+            below), in which case, go right ahead and add the information.
+            If you don't have any additional information, you may just want
+            to vote for this bug, and perhaps
+            add yourself to the <code>CC</code> list to follow the progress
+            of this bug.
+         </p>
+                                <p><a href="http://issues.apache.org/bugzilla/buglist.cgi?query_format=advanced&amp;short_desc_type=allwordssubstr&amp;short_desc=&amp;product=Ant&amp;long_desc_type=substring&amp;long_desc=&amp;bug_file_loc_type=allwordssubstr&amp;bug_file_loc=&amp;keywords_type=allwords&amp;keywords=&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailtype1=substring&amp;email1=&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailtype2=substring&amp;email2=&amp;bugidtype=include&amp;bug_id=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=">Open Ant bugs by order of priority</a>.</p>
+                                <p><a href="http://issues.apache.org/bugzilla/buglist.cgi?query_format=advanced&amp;short_desc_type=allwordssubstr&amp;short_desc=&amp;product=Ant&amp;long_desc_type=substring&amp;long_desc=&amp;bug_file_loc_type=allwordssubstr&amp;bug_file_loc=&amp;keywords_type=allwords&amp;keywords=&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailtype1=substring&amp;email1=&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailtype2=substring&amp;email2=&amp;bugidtype=include&amp;bug_id=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;order=bugs.votes,bugs.priority%2Cbugs.bug_severity&amp;query_based_on=">Open Ant bugs by number of votes</a>.</p>
+                                                          <h4 class="subsection">
+        <a name="Filing a Bug Report"></a>
+        Filing a Bug Report
+      </h4>
+                        <p>
+            Please read our document about <a href="problems.html">problems</a>
+            before deciding that there is an unreported
+            bug in Ant.
+        </p>
+                                <p>
+            You have a few choices at this point. You can send
+            an email to the <code>user</code> mailing list
+            to see if
+            others have encountered your issue and find out how they may
+            have worked around it. If after some discussion, you feel it
+            is time to create
+            a bug report, this is a simple operation in the bug database.
+            Please try to provide as much information as possible in order
+            to assist the developers in resolving the bug. Please try to enter
+            correct values for the various inputs when creating the bug, such
+            as which version of Ant you are running, and on which platform,
+            etc. Once the bug is created, you can also add attachments to
+            the bug report.
+         </p>
+                                <p>
+            What information should you include in your bug report? The
+            easiest bugs to fix are those that are most easily reproducible,
+            so it is really helpful if you can produce a small test case that
+            exhibits the problem. In this case, you would attach the build file
+            and any other files necessary to reproduce the problem, probably
+            packed together in an archive. If you can't produce a test case,
+            you should try to include a snippet from your build file and the
+            relevant sections from the verbose or debug output from Ant. Try
+            to include the header information where Ant states the version,
+            the OS and VM information, etc. As debug output is likely to be
+            very large, it's best to remove any output that is not
+            relevant. Once the bug is entered into the bug database, you
+            will be kept informed by email about progress on the bug. If
+            you receive email asking for further information, please try to
+            respond, as it will aid in the resolution of your bug.
+         </p>
+                                <p>
+            To create the bug report hit this
+            <a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Ant">
+            link</a>.
+         </p>
+                                                          <h4 class="subsection">
+        <a name="Asking for an Enhancement"></a>
+        Asking for an Enhancement
+      </h4>
+                        <p>
+            Sometimes, you may find that Ant just doesn't do what you need it
+            to. It isn't a bug, as such, since Ant is working the way it is
+            supposed to work. Perhaps it is some additional functionality for
+            a task that hasn't been thought of yet, or maybe a completely new
+            task. For these situations, you will
+            want to raise an <i>enhancement request</i>. Enhancement requests
+            are managed using the same Apache Bug Database described above.
+            These are just a different type of bug report. If you look in the
+            bug database, you will see that one of the severity settings for
+            a bug is "Enhancement". Just fill the bug report in,
+            set the severity of the bug to "Enhancement", and
+            state in the description how you would like to have Ant enhanced.
+            Again, you should first check whether there are any existing
+            enhancment requests that cover your needs. If so, just add your
+            vote to these.
+         </p>
+                                <p>
+          <a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Ant&amp;bug_severity=enhancement">
+          Create an enhancement report</a>
+
+        </p>
+                                                          <h4 class="subsection">
+        <a name="Fixing the Bug"></a>
+        Fixing the Bug
+      </h4>
+                        <p>
+            If you aren't satisfied with just filing a bug report, you can
+            try to find the cause of the problem and provide a fix yourself.
+            The best way to do that is by working with the latest code from Subversion.
+            Alternatively, you can work with the source code available from the
+            <a href="http://ant.apache.org/srcdownload.cgi">
+            source distributions</a>. If you
+            are going to tackle the problem at this level, you may want to
+            discuss some details first on the <code>dev</code>
+            mailing list. Once you have a fix for the problem, you may submit
+            the fix as a <i>patch</i> to either the
+            <code>dev</code> mailing
+            list, or enter the bug database as described above and attach the
+            patch to the bug report. Using the bug database has the advantage
+            of being able to track the progress of your patch.
+         </p>
+                                <p>
+            If you have a patch to submit and are sending it to the
+            <code>dev</code> mailing list,
+            prefix "[PATCH]"
+            to your message subject (this is also a good idea for
+            a subject line in the bug database).
+            Please include any relevant bug numbers.
+            Patch files should be created with the <code>-u</code>
+            option of the
+            <code>diff</code> or <code>svn diff</code> command. For
+            example:<br /><br />
+            <font face="verdana" size="-1">
+            diff -u Javac.java.orig Javac.java &gt; javac.diffs<br /><br />
+            </font>
+            or, if you have source from Subversion:<br /><br />
+            <font face="verdana" size="-1">
+            svn diff Javac.java &gt; javac.diffs<br /><br />
+            </font>
+
+           Note: You should give your patch files meaningful names.
+           This makes it easier for developers who need to apply a number
+           of different patch files.
+        </p>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/bylaws.html b/trunk/docs/bylaws.html
new file mode 100644
index 0000000..256db36
--- /dev/null
+++ b/trunk/docs/bylaws.html
@@ -0,0 +1,823 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Project Bylaws</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Apache Ant PMC">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                              <span class="sel">Project Bylaws</span>
+                              </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Project Bylaws</h1>
+            <h3 class="section">
+      <a name="Apache Ant Project Bylaws"></a>
+      Apache Ant Project Bylaws
+    </h3>
+                        <p>
+      This document defines the bylaws under which the Apache Ant project
+      operates. It defines the roles and responsibilities of the
+      project, who may vote, how voting works, how conflicts are resolved,
+      etc.
+    </p>
+                                <p>
+      Ant is a project of the
+      <a href="http://www.apache.org/foundation/">Apache Software
+      Foundation</a>.  The foundation holds the copyright on Apache
+      code including the code in the  Ant codebase. The
+      <a href="http://www.apache.org/foundation/faq.html">foundation FAQ</a>
+      explains the operation and background of the foundation.
+    </p>
+                                <p>
+      Ant is typical of Apache projects in that it operates under a set of
+      principles, known collectively as the "Apache Way". If you are
+      new to Apache development, please refer to the
+      <a href="http://incubator.apache.org">Incubator project</a>
+      for more information on how Apache projects operate. <b>Note:</b> the
+      incubator project has only been recently set up and does not yet explain
+      the Apache Way in great detail.
+    </p>
+                                <ul>
+        <li><a href="#Roles and Responsibilities">Roles and Responsibilities</a></li>
+        <li><a href="#Decision Making">How decisions are made</a></li>
+    </ul>
+                        <h3 class="section">
+      <a name="Roles and Responsibilities"></a>
+      Roles and Responsibilities
+    </h3>
+                        <p>
+      Apache projects define a set of roles with associated rights and
+      responsibilities. These roles govern what tasks an individual may perform
+      within the project. The roles are defined in the following sections
+    </p>
+                                <ul>
+      <li><a href="#Users">Users</a></li>
+      <li><a href="#Developers">Developers</a></li>
+      <li><a href="#Committers">Committers</a></li>
+      <li><a href="#Project Management Committee">
+        Project Management Committee (PMC)</a>
+      </li>
+    </ul>
+                                      <h4 class="subsection">
+        <a name="Users"></a>
+        Users
+      </h4>
+                        <p>
+        The most important participants in the project are people who use our
+        software. The majority of our developers start out as users and guide
+        their development efforts from the user's perspective.
+      </p>
+                                <p>
+        Users contribute to the Apache projects by providing feedback to
+        developers in the form of bug reports and feature suggestions. As
+        well, users participate in the Apache community by helping other users
+        on mailing lists and user support forums.
+      </p>
+                                                          <h4 class="subsection">
+        <a name="Developers"></a>
+        Developers
+      </h4>
+                        <p>
+        All of the volunteers who are contributing time, code, documentation,
+        or resources to the Ant Project. A developer that makes sustained,
+        welcome contributions to the project may be invited to become a
+        Committer, though the exact timing of such invitations depends on many
+        factors.
+      </p>
+                                                          <h4 class="subsection">
+        <a name="Committers"></a>
+        Committers
+      </h4>
+                        <p>
+        The project's Committers are responsible for the project's technical
+        management. All committers have write access to the project's source
+        repositories. Committers may cast binding votes on any technical
+        discussion regarding the project.
+      </p>
+                                <p>
+        Committer access is by invitation only and must be approved by lazy
+        consensus of the active PMC members. A Committer is considered emeritus
+        by their own declaration or by not contributing in any form to the
+        project for over six months. An emeritus committer may request
+        reinstatement of commit access from the PMC. Such reinstatement is
+        subject to lazy consensus of active PMC members.
+      </p>
+                                <p>
+        Commit access can be revoked by a unanimous vote of all the active
+        PMC members (except the committer in question if they are also a PMC member).
+      </p>
+                                <p>
+        All Apache committers are required to have a signed Contributor License
+        Agreement (CLA) on file with the Apache Software Foundation. There is a
+        <a href="http://www.apache.org/dev/committers.html">Committer FAQ</a>
+        which provides more details on the requirements for Committers
+      </p>
+                                <p>
+        A committer who makes a sustained contribution to the project may be
+        invited to become a member of the PMC. The form of contribution is
+        not limited to code. It can also include code review, helping out
+        users on the mailing lists, documentation, etc.
+      </p>
+                                                          <h4 class="subsection">
+        <a name="Project Management Committee"></a>
+        Project Management Committee
+      </h4>
+                        <p>
+        The Project Management Committee (PMC) for Apache Ant was created by a
+        <a href="mission.html">resolution</a> of the board of the Apache
+        Software Foundation on 18<sup>th</sup> November 2002. The PMC is
+        responsible to the board and the ASF for the management and oversight
+        of the Apache Ant codebase. The responsibilities of the PMC include
+      </p>
+                                <ul>
+        <li>Deciding what is distributed as products of the Apache Ant project.
+            In particular all releases must be approved by the PMC
+        </li>
+        <li>Maintaining the project's shared resources, including the codebase
+            repository, mailing lists, websites.
+        </li>
+        <li>Speaking on behalf of the project.
+        </li>
+        <li>Resolving license disputes regarding products of the project
+        </li>
+        <li>Nominating new PMC members and committers
+        </li>
+        <li>Maintaining these bylaws and other guidelines of the project
+        </li>
+      </ul>
+                                <p>
+        Membership of the PMC is by invitation only and must be approved by a
+        lazy consensus of active PMC members. A PMC member is considered
+        "emeritus" by their own declaration or by not contributing in
+        any form to the project for over six months. An emeritus member may
+        request reinstatement to the PMC. Such reinstatement is subject to lazy
+        consensus of the active PMC members. Membership of the PMC can be
+        revoked by an unanimous vote of all the active PMC members other than
+        the member in question.
+      </p>
+                                <p>
+        The chair of the PMC is appointed by the ASF board. The chair is an
+        office holder of the Apache Software Foundation (Vice President,
+        Apache Ant) and has primary responsibility to the board for the
+        management of the projects within the scope of the Ant PMC. The chair
+        reports to the board quarterly on developments within the Ant project.
+        The PMC may consider the position of PMC chair annually and if
+        supported by 2/3 Majority may recommend a new chair to the board.
+        Ultimately, however, it is the board's responsibility who it chooses
+        to appoint as the PMC chair.
+      </p>
+                                            <h3 class="section">
+      <a name="Decision Making"></a>
+      Decision Making
+    </h3>
+                        <p>
+      Within the Ant project, different types of decisions require different
+      forms of approval. For example, the
+      <a href="#Roles and Responsibilities">previous section</a> describes
+      several decisions which require "lazy consensus" approval. This
+      section defines how voting is performed, the types of approvals, and which
+      types of decision require which type of approval.
+    </p>
+                                      <h4 class="subsection">
+        <a name="Voting"></a>
+        Voting
+      </h4>
+                        <p>
+        Decisions regarding the project are made by votes on the primary project
+        development mailing list (dev@ant.apache.org). Where necessary,
+        PMC voting may take place on the private Ant PMC mailing list.
+        Votes are clearly indicated by subject line starting with [VOTE] or
+        [PMC-VOTE]. Votes may contain multiple items for approval and these
+        should be clearly separated. Voting is carried out by replying to the
+        vote mail. Voting may take four flavours
+      </p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>+1</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            "Yes," "Agree," or "the action should be
+            performed." In general, this vote also indicates a willingness
+            on the behalf of the voter in "making it happen"
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>+0</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            This vote indicates a willingness for the action under
+            consideration to go ahead. The voter, however will not be able
+            to help.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>-0</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            This vote indicates that the voter does not, in general, agree with
+            the proposed action but is not concerned enough to prevent the
+            action going ahead.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>-1</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            This is a negative vote. On issues where consensus is required,
+            this vote counts as a <strong>veto</strong>. All vetoes must
+            contain an explanation of why the veto is appropriate. Vetoes with
+            no explanation are void. It may also be appropriate for a -1 vote
+            to include an alternative course of action.
+          
+      </td>
+      </tr>
+          </table>
+                                <p>
+        All participants in the Ant project are encouraged to show their
+        agreement with or against a particular action by voting. For technical
+        decisions, only the votes of active committers are binding. Non binding
+        votes are still useful for those with binding votes to understand the
+        perception of an action in the wider Ant community. For PMC decisions,
+        only the votes of PMC members are binding.
+      </p>
+                                <p>
+        Voting can also be applied to changes made to the Ant codebase. These
+        typically take the form of a veto (-1) in reply to the commit message
+        sent when the commit is made.
+      </p>
+                                                          <h4 class="subsection">
+        <a name="Approvals"></a>
+        Approvals
+      </h4>
+                        <p>
+        These are the types of approvals that can be sought. Different actions
+        require different types of approvals
+      </p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Consensus</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            For this to pass, all voters with binding votes must vote and there
+            can be no binding vetoes (-1). Consensus votes are rarely required
+            due to the impracticality of getting all eligible voters to cast a
+            vote.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Lazy Consensus</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy consensus requires 3 binding +1 votes and no binding vetoes.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Lazy Majority</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            A lazy majority vote requires 3 binding +1 votes and more binding +1
+            votes that -1 votes.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Lazy Approval</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            An action with lazy approval is implicitly allowed unless a -1 vote
+            is received, at which time, depending on the type of action, either
+            lazy majority or lazy consensus approval must be obtained.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>2/3 Majority</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Some actions require a 2/3 majority of active committers or PMC
+            members to pass. Such actions typically affect the foundation
+            of the project (e.g. adopting a new codebase to replace an existing
+            product). The higher threshold is designed to ensure such changes
+            are strongly supported. To pass this vote requires at least 2/3 of
+            binding vote holders to vote +1
+          
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Vetoes"></a>
+        Vetoes
+      </h4>
+                        <p>
+        A valid, binding veto cannot be overruled. If a veto is cast, it must be
+        accompanied by a valid reason explaining the reasons for the veto. The
+        validity of a veto, if challenged, can be confirmed by anyone who has
+        a binding vote. This does not necessarily  signify agreement with the
+        veto - merely that the veto is valid.
+      </p>
+                                <p>
+        If you disagree with a valid veto, you must lobby the person casting
+        the veto to withdraw their veto. If a veto is not withdrawn, the action
+        that has been vetoed must be reversed in a timely manner.
+      </p>
+                                                          <h4 class="subsection">
+        <a name="Actions"></a>
+        Actions
+      </h4>
+                        <p>
+        This section describes the various actions which are undertaken within
+        the project, the corresponding approval required for that action and
+        those who have binding votes over the action.
+      </p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Action
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Description
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Approval
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Binding Votes
+      </th>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Code Change</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            A change made to a codebase of the project and committed
+            by a committer. This includes source code, documentation, website
+            content, etc.
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy approval and then lazy consensus.
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active committers.
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Release Plan</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Defines the timetable and actions for a release. The plan also
+            nominates a Release Manager.
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy majority
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active committers
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Product Release</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            When a release of one of the project's products is ready, a vote is
+            required to accept the release as an official release of the
+            project.
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy Majority
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active PMC members
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Adoption of New Codebase</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            <p>
+            When the codebase for an existing, released product is to be
+            replaced with an alternative codebase. If such a vote fails to
+            gain approval, the existing code base will continue.
+            </p>
+
+            <p>
+            This also covers the creation of new sub-projects
+            within the project
+            </p>
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            2/3 majority
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active committers
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>New Committer</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            When a new committer is proposed for the project
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy consensus
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active PMC members
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>New PMC Member</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            When a committer is proposed for the PMC
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Lazy consensus
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active PMC members
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>Committer Removal</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            <p>When removal of commit privileges is sought.</p>
+            <p><b>Note: </b> Such actions will also be referred to the ASF
+            board by the PMC chair</p>
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Consensus
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active PMC members (excluding the committer in question if a
+            member of the PMC).
+          
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>PMC Member Removal</strong>
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            <p>When removal of a PMC member is sought.</p>
+            <p><b>Note: </b> Such actions will also be referred to the
+            ASF board by the PMC chair</p>
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Consensus
+          
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            Active PMC members (excluding the member in question).
+          
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Voting Timeframes"></a>
+        Voting Timeframes
+      </h4>
+                        <p>
+        Votes are open for a period of 1 week to allow all active voters
+        time to consider the vote. Votes relating to code changes are not
+        subject to a strict timetable but should be made as timely as possible.
+      </p>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/contributors.html b/trunk/docs/contributors.html
new file mode 100644
index 0000000..0e9fce8
--- /dev/null
+++ b/trunk/docs/contributors.html
@@ -0,0 +1,543 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Contributors</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Apache Ant PMC">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                              <span class="sel">Contributors</span>
+                              </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Contributors</h1>
+            <h3 class="section">
+      <a name="Project Management Committee"></a>
+      Project Management Committee
+    </h3>
+                              <h4 class="subsection">
+        <a name="Active Members"></a>
+        Active Members
+      </h4>
+                        <p>
+                <b>Bruce Atherton</b> (bruce at callenish.com - <a href="http://www.callenish.com/~bruce">http://www.callenish.com/~bruce</a>)
+<br />
+Currently a Systems Architect with Avue Technologies, Bruce has been
+working with Java since version 1.0a2. He also claims to be one of the first
+people to mark up a FAQ with HTML, for a web browser of the distant past
+called Cello.
+            </p>
+                                <p>
+                <b>Stephane Bailliez</b><br />
+            </p>
+                                <p>
+                <b>Matt Benson</b><br />
+            </p>
+                                <p>
+                <b>Stefan Bodewig</b> (stefan.bodewig at freenet.de -
+          <a href="http://stefan.samaflost.de/">http://stefan.samaflost.de/</a>)
+<br />
+</p>
+                                <p>
+                <b>Dominique Devienne</b> (ddevienne at apache.org)
+<br />
+Dominique has been involved non-stop with the Ant user community since
+the 1.4 days, trying without success to answer posts as well or as often
+as Diane Holt after she left the user list. He is opinionated, always
+striving for the best possible design. While at Landmark Graphics, he
+designed and implemented large Ant/CppTasks builds for mixed Java/C++ projects.
+            </p>
+                                <p>
+                <b>Erik Hatcher</b> (ehatcher at apache.org)
+<br />
+Erik is the co-author of <a href="http://www.manning.com/hatcher">
+Java Development with Ant</a> and speaks on Ant and other topics at
+<a href="http://www.nofluffjuststuff.com">No Fluff, Just Stuff
+symposiums</a> as well as other venues.  Erik is the President of
+<a href="http://www.ehatchersolutions.com">eHatcher Solutions, Inc</a>.
+</p>
+                                <p>
+                <b>Martijn (J.M.) Kruithof</b> (ant at kruithof xs4all nl)
+<br />
+Martijn Kruithof is a system engineer working with and on Java products
+in a telecommunication network setting.
+</p>
+                                <p>
+                <b>Antoine Levy-Lambert</b> (antoine at apache.org)
+<br />
+Antoine is working as a software engineer for 
+<a href="http://www.arielpartners.com">Ariel Partners</a>.
+He is specialized in builds and automation of deployment processes.
+
+            </p>
+                                <p>
+                <b>Steve Loughran</b><br />
+            </p>
+                                <p>
+                <b>Conor MacNeill</b> (conor at cortexebusiness.com.au)
+<br />
+Conor is a senior developer at Cortex eBusiness, where he develops
+J2EE based systems. In his spare time he helps with the development of
+the Ant build tool.  He is also serving as the Chairman of this PMC.
+</p>
+                                <p>
+				<b>Jan Matèrne</b> (jhm at apache.org)
+<br />
+Jan is consultant for OOA/D in the computer centre of the government
+of Northrhine Westfalia / Germany.
+            </p>
+                                <p>
+                <b>Peter Reilly</b><br />
+            </p>
+                                <p>
+                <b>
+                    <a href="http://www.intertwingly.net/">Sam Ruby</a>
+                </b>
+                (rubys at us.ibm.com)
+<br />
+Sam takes a perverse pleasure in integrating disparate things.  He is
+a member of the <a href="http://www.php.net/credits.php">PHP group</a>, Apache
+<a href="http://xml.apache.org/whoweare.html">XML PMC</a>, Apache
+sponsor for the <a href="http://xml.apache.org/soap">xml-soap</a> subproject
+and convener of <a href="http://www.ecma.ch">ECMA</a> TC39 TG3.
+</p>
+                                <p>
+                <b>Magesh Umasankar</b> (umagesh at apache.org)
+<br />
+Magesh, President of <a href="http://www.metamachsolutions.com">Metamach Solutions</a>, 
+an Atlanta-based technology-management consultancy, has recently launched 
+<a href="http://www.winedin.com">WinedIn.com</a> for wine-lovers to pair food and wine. 
+</p>
+                                <p>
+                <b>Christoph Wilhelms</b> (christoph.wilhelms at t-online.de)
+<br />
+Christoph works as software engineer at the world's biggest travel company
+<a href="http://www.tui.com">TUI</a>. His passion are all UI related things so
+at the Ant-Project he takes care of Antidote - the Ant GUI.
+            </p>
+                                <p>
+  <b>Kevin Jackson</b> (foamdino at gmail.com)<br />
+</p>
+                                                          <h4 class="subsection">
+        <a name="Emeritus Members"></a>
+        Emeritus Members
+      </h4>
+                        <p>
+                <b>James Duncan Davidson</b> (duncan at x180.net - <a href="http://x180.net/">http://x180.net/</a>)
+<br />
+
+By day, Duncan works in the Open Source Program Office at Sun
+Microsystems where he helps various Open Source efforts within Sun
+"do the right thing". Previously at Sun he was responsible
+for the Servlet API Specifications 2.1 and 2.2 as well as the Java API
+for XML Parsing 1.0 and was the original author of Tomcat and Ant. He
+was one of the rabble-rousers within Sun that helped make the Jakarta
+Project a reality and served as the first Chairman of the Jakarta PMC.
+</p>
+                                <p>
+                <b>Diane Holt</b><br />
+            </p>
+                                <p>
+                <b>Donald Leslie</b><br />
+            </p>
+                                <p>
+                <b>Costin Monolache</b><br />
+            </p>
+                                <p>
+                <b>Jon Skeet</b><br />
+            </p>
+                                            <h3 class="section">
+      <a name="Committers"></a>
+      Committers
+    </h3>
+                              <h4 class="subsection">
+        <a name="Active Committers"></a>
+        Active Committers
+      </h4>
+                        <p>
+                <b>Steve Cohen</b>
+            </p>
+                                <p>
+                <b>Jose Alberto Fernandez</b>
+            </p>
+                                <p>
+                <b>Jesse Glick</b> (jesse dot glick at sun dot com)
+<br />
+Jesse has been using Java since 1998 and joined Sun Microsystems as
+part of the company that produced the NetBeans IDE. After discovering
+Ant in the 1.2 days, he wrote most of NetBeans' Ant integration.
+Recently he has worked on the NetBeans 4.0 project system, based heavily
+on Ant as a build tool.
+</p>
+                                <p>
+   <b>Alexey Solofnenko</b> (trelony at gmail.com)<br />
+</p>
+                                                          <h4 class="subsection">
+        <a name="Emeritus Committers"></a>
+        Emeritus Committers
+      </h4>
+                        <p>
+                <b>Preston Bannister</b><br />
+            </p>
+                                <p>
+                <b>Nick Davis</b><br />
+            </p>
+                                <p>
+                <b>Darrell DeBoer</b><br />
+            </p>
+                                <p>
+                <b>Peter Donald</b> (peter at apache.org)
+<br />
+
+Peter is an avid java developer who is active in the
+<a href="http://jakarta.apache.org/avalon/">Avalon</a> and
+<a href="http://ant.apache.org/">Ant</a> projects.
+In his spare time he develops a distributed virtual environment
+(ie military simulator or 3D game) using java technologies.
+</p>
+                                <p>
+                <b>Danno Ferrin</b> (shemnon at yahoo.com)
+<br />
+Danno has been programming in Java since Summer 96. Danno wrote a JSP
+engine on his own and released it the very same day Jakarta was
+announced at JavaOne. Since then, he decided to join the Jakarta
+project in a spirit of co-operation over competition.
+</p>
+                                <p>
+                <b>Simeon H.K. Fitch</b> (simeon.fitch at mseedsoft.com)
+<br />
+Simeon is owner of Mustard Seed Software, which specializes in developing
+distributed applications and user interfaces for the science, engineering,
+and research oriented clients. He is the lead architect and developer for
+Antidote, the GUI for Ant.
+</p>
+                                <p>
+                <b>Thomas Haas</b> (tha at whitestein.com)
+<br />
+Tom is interested in distributed systems, Java middleware and worked on an
+implementation of the JMS specification. At Whitestein Technologies he is
+working on bringing software agent technology and J2EE together.
+</p>
+                                <p>
+
+                <b>Jason Hunter</b> (jh at servlets.com)
+<br />
+Jason is author of "Java Servlet Programming" (O'Reilly) and publisher
+of <a href="http://www.servlets.com/">http://www.servlets.com/</a>.
+He works at <a href="http://www.collab.net">CollabNet</a>.
+</p>
+                                <p>
+                <b>Justyna Horwat</b> (horwat at apache.org)
+<br />
+</p>
+                                <p>
+                <b>Arun Jamwal</b>
+<br />
+</p>
+                                <p>
+                <b>Arnout J. Kuiper</b> (ajkuiper at planet.nl)
+<br />
+
+Arnout J. Kuiper is a Java Architect with the Sun Java Center at Sun
+Microsystems. His main focus is web-related technologies on the Java
+platform (J2EE, XML, ...).
+</p>
+                                <p>
+                <b>Stefano Mazzocchi</b> (stefano at apache.org)
+<br />
+Stefano is addicted to software design, Java programming and
+open development. In the last 4 years, he has contributed way too much
+time to Apache, expecially on JServ, JMeter, Avalon, JAMES, Ant, Cocoon
+and helping to bring more projects into Apache-land, such as FOP, Batik,
+POI and Xindice. The problem is that he's too picky to be satisfied :-)
+</p>
+                                <p>
+                <b>Glenn McAllister</b> (glenn at somanetworks.com)
+<br />
+Glenn McAllister is a software developer at SOMA Networks, was formerly
+the same at IBM (plus tech writer plus build guy), and does some writing
+on the side for the VADD Technical Journal.
+</p>
+                                <p>
+                <b>Craig McClanahan</b> (Craig.McClanahan at eng.sun.com)
+<br />
+Craig was involved in the Apache JServ project, focused on implementing
+a next generation architecture and feature set for the core servlet
+engine.  He has recently joined Sun as technical lead for the servlet
+and JSP reference implementation.
+          </p>
+                                <p>
+                <b>Adam Murdoch</b>
+<br />
+</p>
+                                <p>
+                <b>Harish Prabhandham</b> (harishp at onebox.com)
+<br />
+Harish is an engineer with the J2EE team at Sun, primarily responsible
+for implementing security in the J2EE Reference Implementation
+(RI). He integrated various technologies including servlet/JSP
+implementations from Tomcat into the J2EE RI. These days, he hacks PHP
+code during the day.
+</p>
+                                <p>
+                <b>Nico Seessle</b><br />
+            </p>
+                                <p>
+                <b>Gal Shachor</b> (shachor at il.ibm.com)
+<br />
+Gal Shachor is a research staff member at IBM. He wrote his first
+Servlet container (ServletExpress) at the beginning of 1997. Later on
+ServletExpress (and Gal) merged into WebSphere, and Gal participated
+in the development of WebSphere 1, 2 and 3.
+</p>
+                                <p>
+                <b>Jon S. Stevens</b> (jon at collab.net)
+<br />
+
+Jon is a Co-Founder of <a href="http://www.clearink.com/">Clear Ink
+Corp</a> and recently left to work on <a href="http://scarab.tigris.org/">Scarab</a> a next generation Open
+Source Java Servlet based Issue/Bug tracking system for <a href="http://www.collab.net/">CollabNet</a>. He is an active developer
+of the <a href="http://java.apache.org/jserv/">Apache JServ Servlet
+Engine</a> for the Apache Web Server and Co-Author of the <a href="http://java.apache.org/ecs/">Element Construction Set</a> as
+well as the web application framework, <a href="http://java.apache.org/turbine/">Turbine</a>.
+</p>
+                                <p>
+                <b>Jesse Stockall</b><br />
+            </p>
+                                <p>
+                <b>James Todd</b> (jwtodd at pacbell.net)
+<br />
+James has developed real time customer oriented apps for roughly 10
+years the last 5 of which have predominately been fully integrated,
+front and back, extraNet implementations which have been based on
+Apache, Java and Tcl.
+</p>
+                                <p>
+                <b>Anil Vijendran</b> (akv at eng.sun.com)
+<br />
+Anil Vijendran is the principal developer of the JSP engine in
+Tomcat. He's done some pretty scary things in his past life --
+implementing the CORBA IDL to C++ 2.0 mapping, skydiving, IDL to Java
+compilers, Object Databases (SIGSEV, you da man!) for C++, Java ORB
+and EJB runtime environments -- in that order.
+</p>
+                                            <h3 class="section">
+      <a name="Logo"></a>
+      Logo
+    </h3>
+                        <p>Ant's logo is the result of a logo contest, it has been
+        designed by</p>
+                                <p>
+                <b>Nick King</b>
+<br />
+</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/external.html b/trunk/docs/external.html
new file mode 100644
index 0000000..d5be202
--- /dev/null
+++ b/trunk/docs/external.html
@@ -0,0 +1,7322 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - External Tools and Tasks</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="bodewig@apache.org">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                              <span class="sel">External Tools and Tasks</span>
+                              </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">External Tools and Tasks</h1>
+            <h3 class="section">
+      <a name="External Tools and Tasks"></a>
+      External Tools and Tasks
+    </h3>
+                        <p>This page lists external resources for Apache Ant: <a href="#Tasks">Tasks</a>, <a href="#Compiler%20Implementations">Compiler Implementations</a>,
+      <a href="#IDE%20and%20Editor%20Integration">IDE integration
+      tools</a>, <a href="#Source%20Control%20ystems">Source Control
+      Systems</a>, loggers, you name it. If you've written
+      something that should be included, please post all relevant
+      information to one of the mailing lists.  For details, see the
+      <a href="faq.html#adding-external-tasks">FAQ</a>.</p>
+                                <p>Nothing listed here is directly supported by the Ant
+      developers (therefore '<i>external</i> tools and tasks'),
+      if you encounter any problems with them, please use
+      the contact information.</p>
+                        <h3 class="section">
+      <a name="Tasks"></a>
+      Tasks
+    </h3>
+                              <h4 class="subsection">
+        <a name="AJC"></a>
+        AJC
+      </h4>
+                        <p><a href="http://www.eclipse.org/aspectj/">AspectJ</a> is an
+          aspect-oriented extension to Java.  This task compiles a
+          source tree using the AspectJ compiler -- AJC.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.eclipse.org/aspectj/">http://www.eclipse.org/aspectj/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.eclipse.org/aspectj/">project mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Anakia"></a>
+        Anakia
+      </h4>
+                        <p>Actually, Anakia is more than just an Ant task, it is a an
+        XML transformation tool based on JDOM, Velocity and Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jakarta.apache.org/velocity/anakia.html">http://jakarta.apache.org/velocity/anakia.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jakarta.apache.org/site/mail2.html">Velocity mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Andariel"></a>
+        Andariel
+      </h4>
+                        <p>Andariel is a set of tasks designed to help the generation of HTML
+        (and other markup languages) pages from Ant. Includes a XPath processor,
+        an image information retriever, and others.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.4 and newer
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://andariel.uworks.net/">http://andariel.uworks.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          josep DOT rio AT uworks DOT net
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License 1.1
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant2Svg"></a>
+        Ant2Svg
+      </h4>
+                        <p>Ant2Svg creates a graphical representation of an Ant build file.
+        The graphical representation is in the form of a Scalable Vector
+        Graphics (SVG) file that can be displayed in a web browser. This
+        simplified SVG depiction helps the developer understand build file
+        structure and identify extraneous or missing dependencies.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.1 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.spiritedsw.com/ant2svg/">http://www.spiritedsw.com/ant2svg/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          loney &lt;at&gt; spiritedsw &lt;dot&gt; com
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          The Apache Software License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="ant4eclipse"></a>
+        ant4eclipse
+      </h4>
+                        <p>ant4eclipse provides a set of Ant tasks to make several
+                configurations from the Eclipse IDE available in Ant
+                buildscripts. The tasks are aimed to avoid redundancy between
+                Eclipse and Ant configurations in order to build small but
+                powerful build systems for the continuous integration
+                process</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.1 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ant4eclipse.sf.net">http://ant4eclipse.sf.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=137377">
+              ant4eclipse user mailing list</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Sun Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antcount"></a>
+        Antcount
+      </h4>
+                        <p>Antcount is a set of filters that can be used to gather statistics
+           from files or resources. It is mainly used for log files analysis.
+           It allows to:<ul>
+             <li>count inputs (lines, strings)</li>
+             <li>count occurrences of each input</li>
+             <li>calculate average, max and min values of floats in input</li>
+           </ul>
+           Antcount also includes some useful filters to:<ul>
+             <li>stop filtering: read everything but write nothing</li>
+             <li>echo input to the console or to a file. This allows users to create
+                 several files at once</li>
+             <li>split the stream in two for parallel processing</li>
+           </ul>
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.2 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antcount.sourceforge.net/">http://antcount.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antcount.sourceforge.net/contacts.html">Patrick Martin</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntDoc"></a>
+        AntDoc
+      </h4>
+                        <p>AntDoc is a tool that generates HTML documentation from Ant
+        buildfiles; the generated HTML is inspired from what javadoc
+        yields.  AntDocGUI offers a simple Ant target launcher named
+        AntDoc GUI. Ant targets may be launched from the generated
+        AntDoc HTML pages. Integration to various IDEs is in
+        progress.</p>
+                                <p>AntDoc can be run via an Ant task, AntDoc GUI can be run
+        via an Ant task, or via a JVM launch.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antdoc.free.fr/">http://antdoc.free.fr/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Edouard Mercier
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          The Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntDoclet"></a>
+        AntDoclet
+      </h4>
+                        <p>AntDoclet is a tool to automatically generate documentation out of
+        your Ant Tasks' source code.</p>
+                                <p>It is implemented as a Javadoc doclet, and generates reference
+        documentation and other deliverables from the source code of your
+        custom Ant Tasks/Types.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6+ (not tested on earlier versions)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antdoclet.neuroning.com/">http://antdoclet.neuroning.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://neuroning.com/">Fernando Dobladez</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Anteater"></a>
+        Anteater
+      </h4>
+                        <p>Anteater is a set of Ant tasks for the functional testing of websites
+          and web services (functional testing being; hit a URL and ensure the
+          response meets certain criteria). Can test HTTP params, response
+          codes, XPath, regexp and Relax NG expressions. Includes HTML reporting
+          (based on junitreport) and a hierarchical grouping system for quickly
+          configuring large test scripts.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://aft.sourceforge.net/">http://aft.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://lists.sourceforge.net/lists/listinfo/aft-devel">developer
+                mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntForm"></a>
+        AntForm
+      </h4>
+                        <p>Provides a java/swing form-based input scheme for
+        configuring ant properties and launching ant targets.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.2.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antforms.sourceforge.net/">http://antforms.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:rene_ghosh@yahoo.com">René Ghosh</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antmerge"></a>
+        Antmerge
+      </h4>
+                        <p>Provides simple inheritance between ant files</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.5. Should work with all versions.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.russet.org.uk/antmerge.html">http://www.russet.org.uk/antmerge.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:antmerge@russet.org.uk">Phillip Lord</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antomology"></a>
+        Antomology
+      </h4>
+                        <p>Antomology is an analysis tool suite for Ant. It includes:<ul>
+          <li><b>StatisticsListener</b> - an Ant BuildListener which can be used to gather
+              statistics while an Ant build is executed. Statistics on the targets
+              and tasks executed are written to the console after the build completes. </li>
+        </ul></p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+           <i>unknown</i> 
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antomology.codehaus.org">http://antomology.codehaus.org</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://xircles.codehaus.org/projects/antomology/lists">contact page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License V2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntPrettyBuild"></a>
+        AntPrettyBuild
+      </h4>
+                        <p>
+          Ant Pretty Build is a tool to easily show and run Ant buildfiles directly from
+        within a browser window. It consists of a single XSL file that will generate,
+        on the fly, in the browser, from the .xml buildfile, a pretty interface showing
+        project name, description, properties and targets, etc. sorted or unsorted,
+          allowing to load/modify/add properties, run the whole project, or run selected
+        set of targets in a specific order, with the ability to modify logger/logfile,
+        mode and add more libs or command line arguments.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          All Ant versions
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antprettybuild.sourceforge.net/">Ant Pretty Build Homepage</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antprettybuild.sourceforge.net">Charbel BITAR</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License V2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntSpaces"></a>
+        AntSpaces
+      </h4>
+                        <p>AntSpaces provides Ant integration with JavaSpaces. This
+        allows you to coordinate Ant tasks via JavaSpaces, pull out
+        work units from a JavaSpace for distributed Ant tasks to work
+        on, and so forth.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.oopsconsultancy.com/software/antspaces/">http://www.oopsconsultancy.com/software/antspaces/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          antspaces at oopsconsultancy.com
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntTimerTask"></a>
+        AntTimerTask
+      </h4>
+                        <p><a href="http://www.jeckle.de/freeStuff/AntTimerTask/index.html">Timer</a>
+        is task for measuring the time elapsed to complete other
+        tasks</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.jeckle.de/freeStuff/AntTimerTask/index.html">http://www.jeckle.de/freeStuff/AntTimerTask/index.html</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:mario@jeckle.de">mario@jeckle.de</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Lesser GNU Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant Web Start Task"></a>
+        Ant Web Start Task
+      </h4>
+                        <p>Ant Web Start Task is an Ant task allowing developers to
+        package a desktop application as a WAR (Web Application
+        Archive) to be distributed over the net via Java Web Start</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ant-jnlp-war.sourceforge.net/">http://ant-jnlp-war.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntXtras"></a>
+        AntXtras
+      </h4>
+                        <p>A collection of powerful Ant extensions components
+        organized into five categories: fixture-control,
+        execution-rules, flow-control, feedback, and helpers.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antxtras.sourceforge.net/">AntXtras Home</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antxtras.sourceforge.net">SSMC</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License (LGPL 2.1)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Build Number"></a>
+        Build Number
+      </h4>
+                        <p> Build Number is a tool to track software artifacts such as files and automatically assign
+        proper version/build numbers to them. It ensures that two different artifacts will have different
+        version/build numbers, but identical artifacts/builds will be assigned the same number. It doesn't
+        take version management away from you and doesn't replace your build process, but rather plugs
+        into the process and introduces version/build number governance by defining who is in charge of
+        which part of version number. With Build Number you are still in charge of the head of the version
+        number. E.g. you may decide to have 4 numbers in your version (major, minor, interface, implementation)
+        and you want to manage the two first numbers (major and minor). Build Number will take care of the
+        tedium of managing the last two numbers (interface and implementation). </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.5.4 and 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/products/buildnumber">http://www.hammurapi.biz/products/buildnumber</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Checkstyle"></a>
+        Checkstyle
+      </h4>
+                        <p>Checkstyle is a development tool to help programmers write
+        Java code that adheres to a coding standard. Its purpose is to
+        automate the process of checking Java code, and to spare
+        humans of this boring (but important) task.</p>
+                                <p>Checkstyle can be run via an Ant task or a command line
+        utility.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://checkstyle.sourceforge.net/">http://checkstyle.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:checkstyle@puppycrawl.com">Oliver Burn</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Starting with release 2.0 the license is the GNU
+            Lesser General Public License.  Prior releases were under
+            the GNU General Public License.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="ChownTask"></a>
+        ChownTask
+      </h4>
+                        <p>ChownTask is an Ant task to change ownership of files on
+        Unix.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3 and up
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://sourceforge.net/projects/chowntask/">http://sourceforge.net/projects/chowntask/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:chowntask-users@lists.sourceforge.net">Wilfred Springer</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="CleanImports"></a>
+        CleanImports
+      </h4>
+                        <p>Removes unneeded imports. Formats your import
+        sections. Flags ambiguous imports.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3 and up
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.cleanimports.tombrus.nl">http://www.cleanimports.tombrus.nl</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:cleanimports@tombrus.nl">Tom Brus</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Clover"></a>
+        Clover
+      </h4>
+                        <p>Clover is an Ant-based Code Coverage tool. It can be used
+        seamlessly with Ant-based projects. It provides method,
+        statement, and branch coverage analysis, and has rich
+        reporting in XML, HTML or via a Swing GUI.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 or greater
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.cenqua.com/clover/">http://www.cenqua.com/clover/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:clover-support@cenqua.com">clover-support@cenqua.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial, free licenses available for open source
+            projects.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="CMSDeploy"></a>
+        CMSDeploy
+      </h4>
+                        <p><a href="http://cmsdeploy.sourceforge.net">CMSDeploy</a> is
+        an Apache Ant Task to submit files and templates to Vignette
+        CMS.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cmsdeploy.sourceforge.net">http://cmsdeploy.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:masogato@users.sourceforge.net">masogato@users.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Cocoon Task"></a>
+        Cocoon Task
+      </h4>
+                        <p>This task allows the generation of static web pages and
+        sites using Apache Cocoon in off-line mode.</p>
+                                <p>It allows the configuration information for Cocoon to be
+        included within the Ant build file, and is thus
+        able to take advantage of Ant properties.</p>
+                                <p>The task shares its code with the Cocoon Command Line, which
+        means that this task will instantly take
+        advantage of any new functionality added there.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.3 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cocoon.apache.org/2.1/">http://cocoon.apache.org/2.1/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Documentation:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cocoon.apache.org/2.1/userdocs/offiline/ant.html">http://cocoon.apache.org/2.1/userdocs/offline/ant.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:users.at.cocoon.apache.org">users at cocoon.apache.org</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Configure"></a>
+        Configure
+      </h4>
+                        <p>Recursive build support (call ant on every package level,
+        and only build files in that package or in that package and
+        everything below) with seperation of source and output.</p>
+                                <p>The task generates build files in any subdirectory (except
+        for CVS-directories) for you. Only place one build.xml file in
+        the top and call target 'setup' or
+        'rescan'.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.dsdelft.nl/~lemval/ant/">http://www.dsdelft.nl/~lemval/ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:lemval@dsdelft.nl">M.J.P. van Leeuwen</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          License derived from Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="CVSGrab"></a>
+        CVSGrab
+      </h4>
+                        <p>A little CVS client that can be useful when people are
+        behind corporate firewall that blocks any cvs
+        communications. It uses the ViewCVS web interface to access
+        the CVS repository via standard http, and downloads all the
+        files present in it.</p>
+                                <p>It works from the command line or as an Ant task.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cvsgrab.sourceforge.net/">http://cvsgrab.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:cvsgrab-users@lists.sourceforge.net">CVSGrab
+            user mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Dependencies"></a>
+        Dependencies
+      </h4>
+                        <p>The dependencies task manages a set of external dependencies which
+            may be downloaded from a remote repository,
+             such as ibiblio.org. Uses a local cache to avoid repeated
+            downloads.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.5.1, should work with 1.4+.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.httpunit.org/doc/dependencies.html">http://www.httpunit.org/doc/dependencies.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:russgold@httpunit.org">Russell Gold</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          MIT License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Dependency Finder"></a>
+        Dependency Finder
+      </h4>
+                        <p>Dependency Finder extracts dependencies and OO metrics from
+        Java class files produced by most Java compilers. It can compute
+        API differences between versions;  no sources needed. It includes
+        Ant tasks, web, Swing, and command-line interfaces, with XSL
+        stylesheets for formatting output.</p>
+                                <p>You can use it to extract dependencies between packages, classes,
+        or even methods, or any combination thereof.  You can use Perl
+        regular expressions to filter the information and pinpoint only
+        what you need.  There is even a Web Application version (WAR file)
+        so a whole group of developers can share a common view.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.5.3, should work with 1.4+.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://depfind.sourceforge.net/">http://depfind.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jeantessier@users.sourceforge.net">Jean Tessier</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD-like License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Doxygen task"></a>
+        Doxygen task
+      </h4>
+                        <p>There are two Ant tasks for running the Doxygen
+        documentation system.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.bgw.org/projects/java/ant/">http://www.bgw.org/projects/java/ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:mortis@voicenet.com">Kyle R. Burton</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                <p>and</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ant-doxygen.sourceforge.net/">http://ant-doxygen.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:akkumar@users.sourceforge.net">Karthik A Kumar</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="DTDDoc"></a>
+        DTDDoc
+      </h4>
+                        <p>DTDDoc is here to help you to document your DTD's efficiently. It is a
+        straightforward extension of the javadoc concept to the DTD file format.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://dtddoc.sourceforge.net/">http://dtddoc.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=53704">Project Mailing List</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          X11 (Open Source)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="EnvGen"></a>
+        EnvGen
+      </h4>
+                        <p>
+          <a href="http://www.basilv.com/psd/software">EnvGen</a> is an Ant task for generating 
+          different versions of the same file parameterized for different environments (i.e. 
+          development, test, and production). File generation is done using 
+          <a href="http://freemarker.org/">FreeMarker</a>, a template engine with a full-featured 
+          templating language.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5 or higher (not tested on earlier versions)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.basilv.com/psd/software">http://www.basilv.com/software</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.basilv.com/psd/software/feedback">EnvGen Feedback Page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="EMMA"></a>
+        EMMA
+      </h4>
+                        <p>EMMA is an open-source toolkit for measuring and reporting
+        Java code coverage. EMMA distinguishes itself from other tools
+        by going after a unique feature combination: support large-scale
+        enterprise software development while keeping individual developers
+        work fast and iterative at the same time.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://emma.sourceforge.net/">http://emma.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:emma-users@lists.sourceforge.net">Mailinglist</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Common Public License 1.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="FMPP"></a>
+        FMPP
+      </h4>
+                        <p>FMPP is a general-purpose text file preprocessor tool that
+        uses FreeMarker templates. It is particularly designed for
+        HTML preprocessor, for the generation of complete (static)
+        homepages: directory structure that contains HTML-s, image
+        files, etc. But of course it can be used to generate source
+        code or whatever text files. FMPP is extendable with Java
+        classes to pull data from any data sources (XML file,
+        database, etc.) and embed the data into the generated
+        files.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://fmpp.sourceforge.net/">http://fmpp.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="GenJar"></a>
+        GenJar
+      </h4>
+                        <p>Builds a JAR file based on class dependencies rather than simply the contents of a directory</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 alpha (built after 2001/08/04) and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://genjar.sourceforge.net/">http://genjar.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jesse_dev@yahoo.com">Jesse Stockall</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Grand"></a>
+        Grand
+      </h4>
+                        <p>Grand is a set of tools to create a visual representation of Ant target
+          dependencies. It works by taking an Ant build file and creating a "dot" file. It
+          differs from the existing tools by relying on the Ant API rather than XML parsing to
+          get the dependencies. It includes many advanced features such as filtering or
+          rendering depending on the target's nature. Also features a SWT based GUI.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ggtools.net/grand/">http://www.ggtools.net/grand/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Christophe Labouisse
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Greebo"></a>
+        Greebo
+      </h4>
+                        <p>Greebo is an Ant-task for downloading dependency files
+        (currently only jars) from a network to a specified directory,
+        much like Maven. It supports multiple local and remote
+        repositories with either flat or maven-like structures. It can
+        read the dependency list from a Maven project file, a
+        maven-like dependency file, or directly from the build.xml
+        file.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://greebo.sourceforge.net/">http://greebo.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=73733">project mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="GroboUtils CodeCoverage"></a>
+        GroboUtils CodeCoverage
+      </h4>
+                        <p>The CodeCoverage sub-project of GroboUtils provides a 100%
+        pure Java code coverage tool.  It uses pre-execution class file
+        recompilation, and generates XML files containing the coverage
+        statistics.  It does not require any advanced VM setup to generate
+        coverage numbers.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://groboutils.sourceforge.net/codecoverage/">http://groboutils.sourceforge.net/codecoverage/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=22594">project mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          MIT License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Hammurapi"></a>
+        Hammurapi
+      </h4>
+                        <p>Java code review tool. Performs automated code
+        review. Contains 111 inspectors which check different aspects
+        of code quality including coding standards, EJB, threading,
+        ...</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.5.x and 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/products/hammurapi">http://www.hammurapi.biz/products/hammurapi</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="HelpStudioAnt"></a>
+        HelpStudioAnt
+      </h4>
+                        <p>This task allows for HelpStudio projects to be created via Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.0 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://helpstudioant.sourceforge.net">http://helpstudioant.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="IDLDepend"></a>
+        IDLDepend
+      </h4>
+                        <p>idldepend is a task that (re)generates Java sources to be
+        created from CORBA/IDL files.</p>
+                                <p>It parses the IDL file and determines the Java files that
+        must be generated, taking in account the modifications that
+        can happen due to command line parameters.  If any of the Java
+        files are missing or older than the source IDL specification,
+        it launches the specified compiler.  The compilers of Orbacus,
+        Jacorb, OpenORB, Orbix2k and Sun'JDK distributions are
+        supported.</p>
+                                <p>To speed up the process and avoid unnecesary re-parsing, it
+        keeps the dependencies in intermediate files.  This task does
+        not launch the javac compiler as well, that is, its output are
+        Java files and not the final bytecode.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 or later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.byteslooser.com/idldepend/">http://www.byteslooser.com/idldepend</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:byteslooser@gmail.com">byteslooser@gmail.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          free source, no license restrictions
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Image"></a>
+        Image
+      </h4>
+                        <p>Image task generates and transforms images. It exposes the
+        imaging capability available in Java2D, Java Advanced Imaging,
+        ImageIO, etc., as set of nested elements.</p>
+                                <p>Image transformations such as "resize"
+        (scale),"overlay" (one image on another),
+        "border" (add a border), "text" (text on
+        image), "crop" (a sub-image of a bigger image),
+        "rotate", "grayscale" (change a color
+        image to shades of gray).<br />
+        Now it supports transparency (making images translucent), a
+        bestfit option for Resize, simple support for images within
+        a security-constraint, a preliminary support (if pjatools.jar
+        is available) for saving files as GIF and some other fixes.</p>
+                                <p>IMPORTANT: You will need the PMIW (Poor Man's Imaging Wrapper) jar
+        for all the operations and the pjatools jar for GIF encoding/ saving
+        support.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.mullassery.com/software/ANT/">http://www.mullassery.com/software/ANT/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          pmiw jar
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.mullassery.com/software/PMIW/">http://www.mullassery.com/software/PMIW/</a>
+                (Poor Man's Imaging Wrapper)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          pjatools jar
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.eteks.com/pja/en/">http://www.eteks.com/pja/en/</a>
+                (pjatools for GIF encoding support)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.mullassery.com">Abey Mullassery</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Importscrubber"></a>
+        Importscrubber
+      </h4>
+                        <p>Removes unnecessary import statements from a Java source code file.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://importscrubber.sourceforge.net/">http://importscrubber.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:tomcopeland@users.sourceforge.net">Tom Copeland</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="ImTask"></a>
+        ImTask
+      </h4>
+                        <p>ImTask is a task to allow one to send an Instant
+        Message. Currently supports yahoo!, AIM, and Jabber</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://imtask.sourceforge.net/">http://imtask.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:djallstar@users.sourceforge.net">Jon Madison</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Incanto"></a>
+        Incanto
+      </h4>
+                        <p>Ant tasks to provide support for Oracle database tools
+        (such as SQL*Plus, Import, Export)</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://incanto.sourceforge.net/">http://incanto.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:alexrk@users.sourceforge.net">Alexander Karnstedt</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License, Version 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="IsDirValidator"></a>
+        IsDirValidator
+      </h4>
+                        <p>Checks whether a given directory structure conforms to
+        certain rules that are defined via nested elements of the
+        task.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://isvalidator.sourceforge.net/en/isDirValidator.htm">http://isvalidator.sourceforge.net/en/isDirValidator.htm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:news@inigoserrano.com">Iñigo Serrano</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ivy"></a>
+        Ivy
+      </h4>
+                        <p>Ivy is a simple yet powerful dependency manager featuring
+        continuous integration, dependencies of dependencies
+        management, multiple repositories including ibiblio and high
+        performance (use of a local cache).</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.1 (1.6.5 or 1.7.0 recommended)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://incubator.apache.org/ivy/">http://incubator.apache.org/ivy/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          ivy-user (at) incubator (dot) apache (dot) org [User Mailinglist]
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="J2ME Ant Tasks"></a>
+        J2ME Ant Tasks
+      </h4>
+                        <p>There are different sets of tasks to help build <a href="http://java.sun.com/j2me/">Java 2 Platform, Micro
+        Edition</a> (J2ME) applications.</p>
+                                      <h5 class="subsection">
+        <a name="Antenna"></a>
+        *** Antenna ***
+      </h5>
+                        <p>Antenna provides a set of Ant tasks suitable for developing
+          wireless Java applications targeted at the Mobile Information
+          Device Profile (MIDP). With Antenna, you can compile,
+          preverify, package, obfuscate, and run your MIDP applications
+          (aka MIDlets), manipulate Java Application Descriptor (JAD)
+          files, as well as convert JAR files to PRC files designed to
+          run on MIDP for Palm OS. Deployment is supported via a
+          deployment task and a corresponding HTTP servlet for
+          Over-the-Air (OTA) provisioning. A small preprocessor allows
+          to generate different variants of a MIDlet from a single
+          source.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 or later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antenna.sourceforge.net/">http://antenna.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:joerg@pleumann.de">Jörg Pleumann</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                                    <h5 class="subsection">
+        <a name="Antic"></a>
+        *** Antic ***
+      </h5>
+                        <p>Antic is a freely available task for packaging J2ME
+          applications. It produces both the Jar and Jad files in a
+          single step. This allows *all* entries to be correclty set in
+          the jad file, including the size of the jar file that is
+          produced. This task has been used and tested extensively with
+          Sun's Wireless Toolkit and also the Nokia SDK and
+          emulators.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.smartkey.co.uk/tools/antic/antic.html">http://www.smartkey.co.uk/tools/antic/antic.html</a>
+              
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@smartkey.co.uk">smartkey.co.uk</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                    <h5 class="subsection">
+        <a name="Dave's J2ME Tasks"></a>
+        *** Dave's J2ME Tasks ***
+      </h5>
+                        <p>This set supports CLDC and the K Virtual Machine (KVM):</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.dribin.org/dave/j2me_ant/">http://www.dribin.org/dave/j2me_ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:drib@enteract.com">Dave Dribin</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                    <h5 class="subsection">
+        <a name="J2ME Polish"></a>
+        *** J2ME Polish ***
+      </h5>
+                        <p>J2ME Polish is an Ant-based tool for the creation of
+          MIDP applications. It covers the whole circle of preprocessing, compiling,
+          obfuscation, preverifying, packaging and JAD-creation. J2ME Polish is
+          ideal for creating device optimized applications with its powerful
+          preprocessing capabilities and the integrated device database.
+          With J2ME Polish no hardcoded values are needed and the portability of an
+          application is not sacrificed, even though highly optimized applications are
+          created from a single source.
+          <br />
+          It contains a logging framework and an optional MIDP-compatible GUI
+          which can be designed using the web-standard CSS. With the J2ME Polish GUI
+          you can even use MIDP/2.0 features on MIDP/1.0 phones.
+          </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 or later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.j2mepolish.org/">http://www.j2mepolish.org/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:j2mepolish@enough.de">Enough Software</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License; commercial licenses available
+      </td>
+      </tr>
+          </table>
+                                                    <h5 class="subsection">
+        <a name="Stampysoft's J2ME Tasks"></a>
+        *** Stampysoft's J2ME Tasks ***
+      </h5>
+                        <p>And this set works with the J2ME Wireless Toolkit and MIDP
+          for PalmOS:</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.stampysoft.com/ant/">http://www.stampysoft.com/ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jeckels@stampysoft.com">Josh Eckels</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          MIT License
+      </td>
+      </tr>
+          </table>
+                                                                        <h4 class="subsection">
+        <a name="Jacson"></a>
+        Jacson
+      </h4>
+                        <p>Jacson is a configurable and plugable tool (much like Ant
+        itself) to create filters for text (line based) files without
+        programming.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Jacson has been used and tested with 1.5.1, should
+            work with 1.4+
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jacson.sourceforge.net/">http://jacson.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jacson-user@lists.sourceforge.de">jacson-user@lists.sourceforge.de</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Library or Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Jalopy"></a>
+        Jalopy
+      </h4>
+                        <p>An Ant Plug-in for the Java Source Code Formatter
+        Jalopy.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 (or higher)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jalopy.sourceforge.net/">http://jalopy.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jalopy.sf.net/contact.html">http://jalopy.sf.net/contact.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Starting with release 1.0 Beta 6 the license is the
+            BSD License.  Prior releases were under the GNU General
+            Public License.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JarBundler"></a>
+        JarBundler
+      </h4>
+                        <p>JarBundler is a task that generates Mac OS X native Java
+        Application Bundles.  It is fully configurable and can be used
+        to generate Mac OS X application bundles from any supported
+        Java platform, making it ideal for targeting multiple
+        platforms with one build.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.loomcom.com/jarbundler/">http://www.loomcom.com/jarbundler/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:sethm@loomcom.com">Seth Morabito</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JarPatch"></a>
+        JarPatch
+      </h4>
+                        <p>JarPatch is a task that generates a zip file resulting of
+        the diff between the content of 2 jar files.</p>
+                                <p>The resulting diff file can be use as a patch for a
+        previous installation (just ensure that the generated
+        patch.zip file is located on the CLASSPATH before the patched
+        oldJar jar file)</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://perso.club-internet.fr/sjobic/ant/">http://perso.club-internet.fr/sjobic/ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:norbert.barbosa@laposte.net">Norbert Barbosa</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Java+ Precompile Task"></a>
+        Java+ Precompile Task
+      </h4>
+                        <p>Java+ is an open source Java preprocessor that adds these
+        features to any Java compiler:</p>
+                                <ul>
+          <li>Multi-line strings with executable inclusions like Perl
+          and Ruby. It eliminates the need for JSP or ASP and their
+          need for Java compilers on deployment servers (a security
+          concern) while adding no overhead in either space or
+          time. </li>
+
+          <li>Optionally supports localization by segregating Java+
+          strings into ResourceBundle files with invarient keys based
+          on the hash code of the strings's value. This is handled
+          automatically and transparently; no intervention is
+          required.</li>
+
+          <li>Fast. Negligible impact on build times. By default,
+          skips inputs whose outputs are up to date to avoid
+          triggering recompilations.</li>
+
+          <li>Pure Java code, portable to any platform, with
+          graphical, shell and ant interfaces.</li>
+
+          <li>Simple, general, recursive, digraph-driven string
+          syntax. Digraph characters are user-selectable.</li>
+        </ul>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://virtualschool.edu/java+/">http://virtualschool.edu/java+/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:bcox@virtualschool.edu">Brad Cox</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD-like License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Java2Html"></a>
+        Java2Html
+      </h4>
+                        <p>There are two different tools both named Java2HTML that
+        process Java source code and generate syntax highlighted
+        documentation from it.  Both include Ant tasks to run
+        them.</p>
+                                <p>Java2Html library for converting java source files
+        or snipplets to syntax highlighted html, rtf, tex and
+        others.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.java2html.de/">http://www.java2html.de/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:java2html@jave.de">java2html@jave.de</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                <p>Java2HTML is a simple-to-use tool which converts a bunch of
+        Java Source Code into a colourized and browsable HTML
+        representation.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.1 onwards
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.java2html.com/java2html_ant_task.html">http://www.java2html.com/java2html_ant_task.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@java2html.com">support@java2html.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          FreeWare
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Javamake"></a>
+        Javamake
+      </h4>
+                        <p>A task to compile Java sources and manage class file
+        dependencies. Functionality is equivalent to that of standard
+        Javac and Depend tasks combined, with improved dependency
+        checking.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.experimentalstuff.com/Technologies/JavaMake/index.html">http://www.experimentalstuff.com/Technologies/JavaMake/index.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:Mikhail.Dmitriev@eng.sun.com">Mikhail Dmitriev</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD-like License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="javarec"></a>
+        javarec
+      </h4>
+                        <p>Ant tasks that generate record classes for VisualAge for
+        Java from Cobol copy books.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://glezen.org/javarec/">http://glezen.org/javarec/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:pglezen@us.ibm.com">Paul Glezen</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JCSC"></a>
+        JCSC
+      </h4>
+                        <p>JCSC is a Java Coding Standard Checker which also features
+        the generation of some code metrics. It is a command line tool
+        with an Ant task to scan whole package trees. The result can
+        viewed in an JavaDoc style web page.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant &gt;= 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jcsc.sourceforge.net/">http://jcsc.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:rjocham72@netscape.net">Ralph Jocham</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Jdiff"></a>
+        Jdiff
+      </h4>
+                        <p>A task that generates an HTML report of all the packages, classes,
+        constructors, methods, and fields which have been removed, added or
+        changed in any way, including their documentation, when two APIs are
+        compared. </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            <a href="http://javadiff.sourceforge.net/">
+            http://javadiff.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Task Documentation:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+            <a href="http://cvs.sourceforge.net/viewcvs.py/*checkout*/javadiff/jdiff/jdiff.html?rev=HEAD&amp;content-type=text/html#JDiffAntTask">
+            (in CVS)</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JFlex"></a>
+        JFlex
+      </h4>
+                        <p>JFlex is a lexical analyzer generator (also known as
+        scanner generator) for Java, written in Java.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jflex.de/">http://jflex.de/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.jflex.de/mailing.html">jflex-users mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JindentTask"></a>
+        JindentTask
+      </h4>
+                        <p>JindentTask is a very straightforward wrapping of the
+        Jindent tool, a vendor code beautifier. It enables to use
+        Jindent natively from Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://the.edouard.mercier.free.fr/Jindent_content.php">http://the.edouard.mercier.free.fr/Jindent_content.php</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Edouard Mercier
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Jing Task"></a>
+        Jing Task
+      </h4>
+                        <p> Validates XML files against the RELAX NG alternative to XML Schema.
+        The Jing task for Ant allows you to efficiently validate
+        multiple files against multiple RELAX NG patterns and integrate
+        RELAX NG validation with other XML processing.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.thaiopensource.com/relaxng/jing-ant.html">
+            http://www.thaiopensource.com/relaxng/jing-ant.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD-like
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="jMetra"></a>
+        jMetra
+      </h4>
+                        <p>jMetra is a tool for collecting code metrics across a
+        project lifecycle and compiling the results into
+        JavaDoc-styled documentation to analyze project metrics over
+        time.  jMetra is best utilized by integrating it with your
+        project's scheduled build process.</p>
+                                <p>It works from the command line or using several provided
+        Ant tasks.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.jmetra.com/">http://www.jmetra.com/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:tnewton@hypercisioninc.com">R Todd Newton
+              </a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial, free licenses for open source projects and
+            evaluations.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JMX4Ant"></a>
+        JMX4Ant
+      </h4>
+                        <p>JMX4Ant provides tasks for integration with JMX (Java Management
+        Extensions). It provides tasks for getting and setting attributes
+        of MBeans, invoking their methods and much more.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://jmx4ant.sourceforge.net/">http://jmx4ant.sourceforge.net/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:bdueck@yahoo.com">Brian Dueck</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License 1.1
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JNI"></a>
+        JNI
+      </h4>
+                        <p>
+
+          JNI is a free toolkit that makes easy work of
+          integrating Java and C through the Java Native
+          Interface (JNI). It includes a code generator that
+          generates both Java "proxy" classes to access C
+          "peer" classes, and C "proxy" classes to access
+          Java "peer" classes or interfaces. It also
+          includes a core library with a simplified JVM
+          interface as well as "helper" classes to ease
+          working with the JNI data types. The code
+          generation is driven by an XML project file that
+          can be created with the assistance of the GUI
+          Project Manager. The code generation can be
+          invoked either from Ant or from the
+          GUI. Includes a comprehensive printable PDF User
+          Guide and plenty of examples.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jnipp.sf.net/">http://jnipp.sf.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:ptrewhella@users.sf.net">Phillip E. Trewhella</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JPP"></a>
+        JPP
+      </h4>
+                        <p>
+          <a href="http://www.javapreprocessor.com">JPP</a> is a preprocessor for Ant supporting
+          many different file types that allows you to include / exclude contents based on 
+          build-time parameters.  It is completely invisible to other tools and takes the hassle 
+          out of maintaining customised code or content.  It is free, is provided as an Ant task, 
+          and very simple to use.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.javapreprocessor.com">http://www.javapreprocessor.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto://info@javapreprocessor.com">info@javapreprocessor.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JReleaseInfo"></a>
+        JReleaseInfo
+      </h4>
+                        <p>Sometimes you are interested at runtime to have information
+        from build time. This may be the build date, a build number or
+        the version.  The JReleaseInfo Ant Task generates a java
+        source file with getter methods for any desired and provided
+        properties.  Furthermore, it can automatically generate a
+        viewer (which can e.g.  be used as main-class in a library jar
+        file) that shows the included release information.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jreleaseinfo.sourceforge.net/">HomePage on SourceForge</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/jreleaseinfo/">Forums/Tracker on SourceForge</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JRun Ant Tasks"></a>
+        JRun Ant Tasks
+      </h4>
+                        <p>JRun 4 SP1 ships with lib/jrun-ant-tasks.jar, which defines
+        three Ant tasks: jrun, jrunapp, and jrunjmx.  Documentation
+        for the tasks can be found in JRun under
+        docs/ant/jrun.html.</p>
+                                <p>Note that the service pack must be installed on top of an
+        existing JRun 4 installation.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://dynamic.macromedia.com/bin/MM/software/trial/hwswrec.jsp?product=jrun_sp">http://dynamic.macromedia.com/bin/MM/software/trial/hwswrec.jsp?product=jrun_sp</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:bdeitte@macromedia.com">Brian Deitte</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JSMin Ant Task"></a>
+        JSMin Ant Task
+      </h4>
+                        <p>The JSMin Ant task can be used for the automated minification of javascript files
+          in your build and deploy processes.</p>
+                                <p>JSMin is a filter which removes comments and unnecessary whitespace from javascript
+          files. It typically reduces filesize by half, resulting in faster downloads.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://code.google.com/p/jsmin-ant-task/">http://code.google.com/p/jsmin-ant-task/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:matt_at_matthaynes_dot_net">M. Haynes</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JudoScript Ant Task"></a>
+        JudoScript Ant Task
+      </h4>
+                        <p>The &lt;judoscript&gt; task is an easy way to embed JudoScript
+           code in the Ant build script. The tag format is quite simple. You can
+           either embed code directly, or can specify an external JudoScript program
+           file as the <code>src</code> attribute value. Parameters can be specified
+           as the <code>params</code> attribute; this is applicable to both embedded
+           code and external files.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.judoscript.com/articles/ant.html">http://www.judoscript.com/articles/ant.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:judoscript@hotmail.com">James Jianbo Huang</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Lesser GNU Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Just4log Ant Task"></a>
+        Just4log Ant Task
+      </h4>
+                        <p>Just4log is a ant task to optimize JVM bytecode with regards
+        for Logs ( be it, Log4j, Apache Commons or JDK 1.4 )
+        It depends on apache BCEL for Bytecode engineering.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.2 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://just4log.sourceforge.net">http://just4log.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:lbruand@wanadoo.fr">Lucas Bruand</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License 1.1.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Kanaputs"></a>
+        Kanaputs
+      </h4>
+                        <p>Kanaputs is a parser for java based scripting. It is an
+        interpreter for Java. With Kanaputs you can use Java as an
+        interpreted language: no more compilation, each instruction is
+        executed when you write it.  It is a small programmation
+        language to make script files above Java.</p>
+                                <p>Kanaputs Ant Task provides a way to add any kind of
+        programmatic features in your Ant script. The code you insert
+        stays OS independent (because Kanaputs uses Java) and is
+        completely integrated with Ant as you can give Ant properties
+        to the Kanaputs code and get back the results in other
+        properties.</p>
+                                <p>Moreover, as you can invoke any kind of Java code with
+        Kanaputs, you can popup windows from your Ant file to ask the
+        user to do a choice.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.kanaputs.org/">http://www.kanaputs.org/</a> <br />
+              <a href="http://www.kanaputs.org/ant.html">http://www.kanaputs.org/ant.html</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:kfra@kanaputs.org">kfra@kanaputs.org</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="LaTeX Task"></a>
+        LaTeX Task
+      </h4>
+                        <p>Simple Task to use (PDF)LaTeX, BibTeX, Makeindex and GlossTeX to
+        create your documentation.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.2 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.dokutransdata.de/">http://www.dokutransdata.de/</a><br />
+              <a href="http://www.dokutransdata.de/ant_latex/">http://www.dokutransdata.de/ant_latex/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:jaloma@dokutransdata.de">jaloma@dokutransdata.de</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Macker"></a>
+        Macker
+      </h4>
+                        <p>A build-time architectural testing tool, designed
+        to maintain clean layering / tiering / modularity.
+        Macker works against compiled class files, checking
+        dependencies between classes against a set of
+        pattern-based access rules you specify for your
+        project in an XML rules file.  Macker doesn't presume
+        anything about your architecture -- you write the
+        rules, and Macker keeps you honest about them.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and higher (1.4 untested but may work)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://innig.net/macker/">http://innig.net/macker/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://innig.net/macker/contact.html">Paul Cantrell</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU GPL 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="MakeRunScript"></a>
+        MakeRunScript
+      </h4>
+                        <p>MakeRunScript creates a run script for your application.  Even if you are developing on windows,
+        you can make a run script for *nix and vice versa.  If you've used the built-in java task before, you
+        already know how to use 90% of MakeRunScript.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.7 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/makerunscript/">http://sourceforge.net/projects/makerunscript/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/forum/?group_id=210204">MakeRunScript forums</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="mtxslt"></a>
+        mtxslt
+      </h4>
+                        <p>The mtxslt (Multi-XSLT) extends the standard Ant "xslt/style" task
+        to make it easy to use multiple XSLT engines during the same build.
+        This is useful for regression testing of XSLT scripts against several
+        engines.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://mtxslt.sourceforge.net/">http://mtxslt.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:abcoates@theOffice.net">Anthony B. Coates</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="nsd2LaTeX Task"></a>
+        nsd2LaTeX Task
+      </h4>
+                        <p>Simple Task to use nsd2ltx to build your Nassi-Shneiderman diagrams.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.2 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.dokutransdata.de/">http://www.dokutransdata.de/</a><br />
+              <a href="http://www.dokutransdata.de/ant_nsd2ltx/">http://www.dokutransdata.de/ant_nsd2ltx/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:jaloma@dokutransdata.de">jaloma@dokutransdata.de</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Nurflugel AntScript Visualizer"></a>
+        Nurflugel AntScript Visualizer
+      </h4>
+                        <p>The Nurflugel AntScript Visualizer takes your build file,
+        finds any imported build files, and shows all relationships
+        between targets, taskdefs, macrodefs, Ant and Antcalls; output
+        options include PDF, SVG, and PNG.  Many options including
+        grouping by build file, inclusion/exclusion of targets,
+        taskdefs, imports, etc.  Installation is via Java WebStart, so
+        you'll always have the freshest version available.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.nurflugel.com/webstart/AntScriptVisualizer/">http://www.nurflugel.com/webstart/AntScriptVisualizer/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          dbullard &lt;at&gt; nurflugel &lt;dot&gt; com (email
+            will receive a challenge to weed out spam)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Orangevolt Ant Tasks"></a>
+        Orangevolt Ant Tasks
+      </h4>
+                        <p>Orangevolt ANT Tasks is a collection of Tasks for Apache
+        Ant.</p>
+                                <p>The Orangevolt Ant Tasks collections provides a bunch of
+        Appplication Deployment related Tasks from windows specific
+        tasks (registry access, executable generation), *nix specific
+        tasks (kde/gnome shortcut generation) to many useful utility
+        tasks like jnlp generation.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 or above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/ovanttasks">http://sourceforge.net/projects/ovanttasks</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:info@roxes.com">info@roxes.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="pack"></a>
+        pack
+      </h4>
+                        <p>pack is a task to build the smallest possible JAR to link
+        and run one or more classes.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sadun-util.sourceforge.net/pack.html">http://sadun-util.sourceforge.net/pack.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:cristiano@xtractor.com">Cristiano Sadun</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="PCT"></a>
+        PCT
+      </h4>
+                        <p>PCT is a task to compile Progress code, and in a more general
+        way, to deal with Progress procedures and databases.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://pct.sourceforge.net">http://pct.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:justus_phenix@users.sourceforge.net">Gilles QUERRET</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Licence:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="PesterCat Ant Toolkit"></a>
+        PesterCat Ant Toolkit
+      </h4>
+                        <p>PesterCat is a web testing tool that was designed to
+           perform functional testing for web applications. The PesterCat
+           Ant Toolkit contains tasks to playback test scripts and create
+           HTML reports.
+         </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.pestercat.com/">http://www.pestercat.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="PMD"></a>
+        PMD
+      </h4>
+                        <p>PMD checks Java source code for unused variables,
+        unnecessary object creation, etc</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://pmd.sf.net/">http://pmd.sf.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:tcopeland@apache.org">Tom Copeland</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="PRes"></a>
+        PRes
+      </h4>
+                        <p>PRes is short for Property Resources and will generate a Java source
+           file from name=value pair .property files which can be compiled like any
+           other class.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later (may work with earlier)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://mseries.sourceforge.net">http://mseries.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://web.ukonline.co.uk/mseries/contact.html">MSeries</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="ProGuard"></a>
+        ProGuard
+      </h4>
+                        <p><a href="http://proguard.sourceforge.net/">ProGuard</a> is
+        a free Java class file shrinker and obfuscator.  It can detect
+        and remove unused classes, fields, methods, and attributes. It
+        can then rename the remaining classes, fields, and methods
+        using short meaningless names.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.5. Should work with all versions.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://proguard.sourceforge.net/">http://proguard.sourceforge.net/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://proguard.sourceforge.net/feedback.html">Feedback Page</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="properties2java"></a>
+        properties2java
+      </h4>
+                        <p>Properties2Java is an Ant task for automatic conversion of
+        java ".properties" files to ".java" files extending the
+        java.util.ListResourceBundle.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6 or above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://properties2java.jayefem.de/">http://properties2java.jayefem.de/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:properties2java@jayefem.de">Jan-Friedrich Mutter</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Purge"></a>
+        Purge
+      </h4>
+                        <p>Purge deletes all but the most recent few files from a fileset.
+        For example: if you have generated files (logs, .ear, .war, .jar
+        etc) accumulating in a directory, the purge task will allow you
+        to delete the older files, keeping just the most recent ones.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 or above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.dallaway.com/ant/">http://www.dallaway.com/ant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:purge@dallaway.com">Richard Dallaway</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="RefactorIT"></a>
+        RefactorIT
+      </h4>
+                        <p>RefactorIT includes an Ant task for metrics and audits.
+        RefactorIT is a Java refactoring, audit and metrics tool.
+        It plugs into major Java IDEs, also runs stand-alone with
+        a GUI and a command line interface.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.refactorit.com/">http://www.refactorit.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@refactorit.com">support@refactorit.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial. (Free for accredited open source products, see
+            <a href="http://www.refactorit.com/osc">http://www.refactorit.com/osc</a>.)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Reflectant Task"></a>
+        Reflectant Task
+      </h4>
+                        <p>This is a task for reflection invocation from within ant build file.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 or above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/reflectant/">http://sourceforge.net/projects/reflectant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:sv_ant@mail.bg">sv_ant@mail.bg</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          The Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="rundoc"></a>
+        rundoc
+      </h4>
+                        <p>A task designed to help with the single-sourcing of program
+        documentation. Rundoc replaces special commands
+        (in the format <i>@@rundoc:command param1 param2...@@</i>) embedded
+        within text files with their output in a
+        specified format. Currently, only Docbook format is supported.</p>
+                                <p>Rundoc was written to keep sample code output in program
+        documentation synchronized with the actual output
+        of the current code, by running the referenced code when the
+        documentation is built.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.6  Should work with all versions.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.martiansoftware.com/lab/index.html#rundoc">http://www.martiansoftware.com/lab/index.html#rundoc</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Revised BSD
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="SerialVer"></a>
+        SerialVer
+      </h4>
+                        <p>SerialVer adds the Java serialver functionality to Apache
+        Ant.  This project adds Tasks and FilterReaders to get, to
+        insert and to modify the serialVersionUID in the source code
+        of a serializable class.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://serialver.sourceforge.net/">http://serialver.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://lists.sourceforge.net/lists/listinfo/serialver-development">developer mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Simian"></a>
+        Simian
+      </h4>
+                        <p>Simian (Similarity Analyser) identifies duplication in Java,
+        C#, C, CPP, COBOL, JSP, HTML source code and even plain text files.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.redhillconsulting.com.au/products/simian/">
+            http://www.redhillconsulting.com.au/products/simian/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:simian-user-subscribe@redhillconsulting.com.au">
+            simian-user-subscribe@redhillconsulting.com.au (User Mailinglist)
+            </a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial, Free Licenses available for Non-Commercial Projects
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="SmartAnalyzer"></a>
+        SmartAnalyzer
+      </h4>
+                        <p>Powerful analysis of dependencies between Java classes.
+        Only affected classes will be recompiled and it can be used
+        with any bytecode compiler.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Ant version 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://smartanalyzer.sourceforge.net/">http://smartanalyzer.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/smartanalyzer">support at sourceforge project page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public Licence (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="snip"></a>
+        snip
+      </h4>
+                        <p>A task designed to help with the single-sourcing of program documentation.
+        Snip extracts snippets of text from files, placing them into properties in the Ant project.
+        These properties can then be used by any other Ant task, and are particularly useful when
+        referenced by &lt;filter&gt;s within the &lt;copy&gt; task.</p>
+                                <p>Snip was originally written to keep snippets of sample code in API documentation synchronized
+        with the actual sample classes.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with 1.5.1.  Should work with all versions.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.martiansoftware.com/lab/index.html#snip">http://www.martiansoftware.com/lab/index.html#snip</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Revised BSD
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="spell"></a>
+        spell
+      </h4>
+                        <p>Spell Check checks the spelling of all files in a directory. Code is broken into
+        single words and compared to a dictionary. If the words are not in the dictionary
+        they are written to a file.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+           <!-- JHM: asked Rob for that; he'll ping me if he is back at home --> 
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://robmayhew.com/antspell/antspelltask.html">http://robmayhew.com/antspell/antspelltask.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.robmayhew.com/">Rob Mayhew</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+           <!-- same as above --> 
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="SQL Compiler (SQLC)"></a>
+        SQL Compiler (SQLC)
+      </h4>
+                        <p>SQL Compiler (SQLC) compiles database metadata and SQL statements into data access and data transfer classes.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.5.4 and 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/products/sqlc">http://www.hammurapi.biz/products/sqlc</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="SQLUnit"></a>
+        SQLUnit
+      </h4>
+                        <p>SQLUnit is a regression and unit testing harness for testing
+         database stored procedures. The test suite is written as an XML file.
+         The SQLUnit harness itself is written in Java and uses the JUnit unit
+         testing framework to convert the XML test specifications to JDBC calls
+         and compare the results generated from the calls with the specified
+         results. It also provides the &lt;sqlunit&gt; task to run the tests
+         from a build script.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sqlunit.sourceforge.net">http://sqlunit.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/forum/?group_id=77832">Project forums</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Styler"></a>
+        Styler
+      </h4>
+                        <p>The styler task makes useful combinations of XSLT transformations
+        easy to specify in an Ant build file. Like the built-in Ant task
+        style, styler can apply a single transformation to a set of XML files.
+        But it can also:</p>
+                                <ul>
+          <li>handle multiple transformations, in parallel or pipelined.</li>
+          <li>enable transformations that split or merge files</li>
+          <li>process non-XML files, especially HTML (based on JTidy)</li>
+          <li>apply non-XSLT transformation, especially "regular
+          fragmentations"</li>
+          <li>use any custom XMLReader or XMLFilter class to handle new file
+          formats and transformation techniques.</li>
+        </ul>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.langdale.com.au/styler/">http://www.langdale.com.au/styler/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:adv@langdale.com.au">Arnold deVos</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Syntax"></a>
+        Syntax
+      </h4>
+                        <p>Transforms source files into HTML documents with syntax
+        highlighting. It can handle a variety of source files
+        including Java, HTML, C/C++, SQL, and Java properties.  Colors
+        for elements are specified using cascading style sheets.  The
+        output can be templated for easy integration with a site's
+        look and feel.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ostermiller.org/syntax/ant.html">http://ostermiller.org/syntax/ant.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ostermiller.org/contact.pl?regarding=Syntax+Highlighting">Stephen Ostermiller</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL)
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="TestSetGenerator"></a>
+        TestSetGenerator
+      </h4>
+                        <p>The TestSetGenerator is an ant task for generating property files with
+        testsets based on the results of SQL queries and validation plug-ins. Very
+        usefull when building unit tests that make use of changing datasets. This
+        task is an extension of the Ant SQL task. Hsqldb is used for both the
+        examples and the unittests.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          ANT 1.4 (or later)
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://anttestsetgen.sourceforge.net/">http://anttestsetgen.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:m.c.jansen@planet.nl">m.c.jansen@planet.nl</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Tidy Imports (Tim)"></a>
+        Tidy Imports (Tim)
+      </h4>
+                        <p>Tim is a handy utility that can be executed on the command
+        line or via Ant that automatically formats your import
+        declarations. Tim is capable of removing unused imports,
+        expanding or collapsing imports and even organising them into
+        pre-determined groups.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.chive.com/tim.htm">http://www.chive.com/tim.htm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@chive.com">support@chive.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="TiniAnt"></a>
+        TiniAnt
+      </h4>
+                        <p>TiniAnt is an Ant task to support building applications for
+        the <a href="http://www.ibutton.com/TINI/">TINI</a>.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 to 1.4.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://tiniant.sourceforge.net/">http://tiniant.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:kelly@ad1440.net">Sean Kelly</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD-like license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Transformica"></a>
+        Transformica
+      </h4>
+                        <p>Transformica is a versatile and extensible code generator.
+           Supports multiple source models including database metadata, Java source files, grammar
+           files and custom models.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.5.x and 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/products/transformica">http://www.hammurapi.biz/products/transformica</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Venus Application Publisher's (Vamp) Ant Task Suite"></a>
+        Venus Application Publisher's (Vamp) Ant Task Suite
+      </h4>
+                        <p>Venus Application Publisher's (Vamp) Ant Task Suite allows
+        you to sign and package your applications into relocatable Web
+        Archives that you can drop into your web server for
+        single-click launching using Java Web Start or into single
+        Java Archive installers that serve up their content through a
+        built-in, multi-threaded, ultra light-weight web server.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and 1.3
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.geocities.com/vamp201/ant.html">http://www.geocities.com/vamp201/ant.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:vamp201@yahoo.com">Gerald Bauer</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Version_Tool"></a>
+        Version_Tool
+      </h4>
+                        <p>A versioning tool for Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ant.ryangrier.com/">http://ant.ryangrier.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:version_tool@ryangrier.com">version_tool@ryangrier.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="VPP"></a>
+        VPP
+      </h4>
+                        <p>VPP provides general file preprocessing support based on
+        the Velocity Template Engine.  The core functionality is
+        provided as a filter for use with tasks that supports filter
+        chains.  Also included are replacement tasks for &lt;copy&gt; and
+        &lt;javac&gt; that integrate support for preprocessing.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.1 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://vpp.sourceforge.net/">http://vpp.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:vpp-user@lists.sourceforge.net">vpp-user@lists.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="WOProject"></a>
+        WOProject
+      </h4>
+                        <p>WOProject provides a set of tools to work with
+        <a href="http://webobjects.com/">WebObjects 5.1</a>
+        independent from platform and IDE. It significantly
+        improves developer productivity
+        and makes complex project structures more flexible compared to
+        traditional Makefile-based approach.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://objectstyle.org/woproject/">http://objectstyle.org/woproject/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:andrus@objectstyle.org">Andrus Adamchik</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="WSDLValidate"></a>
+        WSDLValidate
+      </h4>
+                        <p>WSDLValidate is, as it sounds, a tool to validate WSDL files.
+        <a href="http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/wsvt-home/docs/articles/wsdl20Validator/wsdlvalidateant.html">WSDLValidate</a>
+        is similar in configuration to the optional Ant task <a href="http://ant.apache.org/manual/OptionalTasks/xmlvalidate.html">XMLValidate</a>.
+        WSDLValidate can optionally validate a WSDL document against the <a href="http://www.ws-i.org">WS-I Basic Profile</a>.
+        </p>
+                                <p>WSDLValidate is available as an Ant task, an Eclipse plug-in and a
+        command line utility.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 or later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.eclipse.org/wsvt">http://www.eclipse.org/wsvt</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.eclipse.org/wsvt">Project newsgroup and
+            mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www-124.ibm.com/developerworks/oss/CPLv1.0.htm">Common Public
+            License (CPL)</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Xcluder"></a>
+        Xcluder
+      </h4>
+                        <p>xcluder is an XML Inclusions (XInclude) task for Apache Ant.
+        Offers the choice of using Xerces or Elliotte Rusty Harold's XOM API.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 or later. XInclude compliance depends on the
+            underlying Xerces or XOM used. Xerces 2.5.0 and above works fine,
+            but please note that 2.6.1 and 2.6.2 processed the
+            http://www.w3.org/2003/XInclude, now obsolete by
+            http://www.w3.org/2001/XInclude used by the latest
+            Candidate Recommendation (13 April 2004).
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/xcluder">http://sourceforge.net/projects/xcluder</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:mbatsis@users.sf.net">mbatsis@users.sf.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License (GPL), GNU Library or Lesser
+            General Public License (LGPL)
+            
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XDoclet"></a>
+        XDoclet
+      </h4>
+                        <p>XDoclet is an extended Javadoc Doclet engine for use in Ant.
+           It lets you create custom Javadoc @tags and based on those tags
+           generates source code or other files (such as xml-ish deployment
+           descriptors). Templates and matching tasks are provided to generate
+           EJB and web application deployment descriptors.
+           </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/xdoclet/">http://sourceforge.net/projects/xdoclet/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XInclude"></a>
+        XInclude
+      </h4>
+                        <p><a href="http://www.jeckle.de/freeStuff/xia/index.html">XInclude</a> is
+          a W3C standardized vocabulary for including arbitrary text or XML
+          documents in other XML documents. This task performes the inclusion
+          using an existing XInclude implementation</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.2
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.jeckle.de/freeStuff/xia/index.html">http://www.jeckle.de/freeStuff/xia/index.html</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:mario@jeckle.de">mario@jeckle.de</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Lesser GNU Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XML Directory Listing Ant Task"></a>
+        XML Directory Listing Ant Task
+      </h4>
+                        <p>The XML Directory Listing task can recurse through a directory structure and produce an 
+        XML representation. The resulting file can then be transformed further with Ant. </p>
+                                <p>The XML output is configurable through various options. The SAX parsing is fast and has a 
+        low memory footprint.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5 or higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://code.google.com/p/xml-dir-listing/">http://code.google.com/p/xml-dir-listing/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:matt_at_matthaynes_dot_net">M. Haynes</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XMLReleaseNotes (XRN)"></a>
+        XMLReleaseNotes (XRN)
+      </h4>
+                        <p>This framework is a release notes framework that enables to
+        generate textual release notes from an XML file. This is an
+        open framework that enables to integrate the information
+        coming from VSC and bug tracking solutions, for instance.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://xmlreleasenotes.free.fr/">http://xmlreleasenotes.free.fr/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Edouard Mercier
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XmlTask"></a>
+        XmlTask
+      </h4>
+                        <p>XmlTask provides a simple means to modify XML documents
+        without having to learn XSLT. A simple path reference to an
+        XML node specifies the node you want to change, and how you
+        want to allow XML insertion and removal, or attribute
+        changes. The emphasis is on providing the simplest means to
+        perform common XML replacements</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.oopsconsultancy.com/software/xmltask/">http://www.oopsconsultancy.com/software/xmltask/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:xmltask-users@lists.sourceforge.net">xmltask-users at lists.sourceforge.net</a> 
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="yGuard"></a>
+        yGuard
+      </h4>
+                        <p>yGuard is a free Java(TM) Bytecode Obfuscator Task that
+        needs no external script or project files. It can completely
+        be configured and run through the Ant build script. The task
+        supports multiple Jar files at once and makes use of
+        patternsets and regular expressions to specify elements, which
+        should be left unobfuscated.  Additionally it can be used to
+        produce patches for obfuscated applications that have already
+        been deployed.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.yworks.com/en/products_yguard_about.htm">http://www.yworks.com/en/products_yguard_about.htm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:yguard@yworks.com">yGuard@yWorks.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Library: LGPL, Task: Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Zelix KlassMaster"></a>
+        Zelix KlassMaster
+      </h4>
+                        <p>The task ZKMTask allows the Zelix KlassMaster Java obfuscator to be integrated into an Ant build.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.zelix.com/klassmaster/docs/buildToolApi.html">http://www.zelix.com/klassmaster/docs/buildToolApi.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="Build Listeners"></a>
+      Build Listeners
+    </h3>
+                              <h4 class="subsection">
+        <a name="AntUtility"></a>
+        AntUtility
+      </h4>
+                        <p>
+          Wondering why your Ant build is slow? Is your continuous integration server taking too 
+          long to produce your project builds? This project may help. This project includes a small 
+          number of classes for use with Ant that can help you to analyze your build in a 
+          non-intrusive manner.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://antutility.dev.java.net/">https://antutility.dev.java.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:dgreen@dev.java.net">David Green</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache Software License</a>
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="Compiler Implementations"></a>
+      Compiler Implementations
+    </h3>
+                              <h4 class="subsection">
+        <a name="Generics (JSR14) Early-Access Compiler Adapter"></a>
+        Generics (JSR14) Early-Access Compiler Adapter
+      </h4>
+                        <p>This is an Ant compiler-adapter that allows you to use the
+        normal <code>&lt;javac&gt;</code> task plus Sun's early-access
+        compiler to compile Generics-enabled Java code.  (This is only
+        necessary until JDK1.5 is released.)</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.madbean.com/blog/3/">http://www.madbean.com/blog/3/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Matt Quail &lt;spud[at]madbean[dot]com&gt;
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Public Domain
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="miniRMI &lt;code&gt;&amp;lt;rmic&amp;gt;&lt;/code&gt; implementation"></a>
+        miniRMI <code>&lt;rmic&gt;</code> implementation
+      </h4>
+                        <p>miniRMI is a freeware opensource library that serves as a
+        lightweight replacement for the original java.rmi packages and
+        is suitable especially for applets. Ant 1.4+
+        <code>&lt;rmic&gt;</code> adapter included.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://dione.zcu.cz/~toman40/miniRMI/">http://dione.zcu.cz/~toman40/miniRMI/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:Petr.Toman@pinknet.cz">Petr Toman</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Gnu Lesser Public License
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="IDE and Editor Integration"></a>
+      IDE and Editor Integration
+    </h3>
+                              <h4 class="subsection">
+        <a name="AntFarm"></a>
+        AntFarm
+      </h4>
+                        <p>A plugin that integrates Ant into the jEdit editor.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://plugins.jedit.org/plugins/?AntFarm">http://plugins.jedit.org/plugins/?AntFarm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jedit-devel@lists.sourceforge.net">jEdit developers mailinglist</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntRunner"></a>
+        AntRunner
+      </h4>
+                        <p>An OpenTool that integrates Ant into the JBuilder IDE
+        (version 5 and later).</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antrunner.sourceforge.net/">http://antrunner.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:dirk.schnelle@web.de">Dirk Schnelle</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="CAPlex"></a>
+        CAPlex
+      </h4>
+                        <p>CA Plex is an architected RAD tool that combines the techniques of
+        model-driven development, code generation and patterns to create
+        business applications for multiple platforms, including Java, .NET and
+        IBM System i. In its 6.0 release, CA Plex includes integrated support
+        for building generated Java code with Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://wiki.plexinfo.net/index.php?title=Customizing_Plex_6.0_ANT_builds">http://wiki.plexinfo.net/index.php?title=Customizing_Plex_6.0_ANT_builds</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ca.com/us/products/product.aspx?ID=258">http://www.ca.com/us/products/product.aspx?ID=258</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Eclipse"></a>
+        Eclipse
+      </h4>
+                        <p>Eclipse is a universal tool platform with Ant integration.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              Ant 1.3 and higher <br />
+              Bundles Ant 1.6.2 as of Eclipse 3.0.1 (tested with Ant 1.5.4 - 1.6.2) <br />
+              Eclipse 3.2 bundles Ant 1.6.5 <br />
+              Eclipse 3.3 bundles Ant 1.7.0 
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.eclipse.org/">http://www.eclipse.org/</a>
+              or
+              <a href="http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ant-home/index.html">
+                http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ant-home/index.html
+              </a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="news://news.eclipse.org/eclipse.platform">news://news.eclipse.org/eclipse.platform</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Common Public License Version 1.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Gel"></a>
+        Gel
+      </h4>
+                        <p>Java IDE with support for Ant.  Gel is a native Microsoft
+        Windows software.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.gexperts.com/gel.html">http://www.gexperts.com/gel.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://groups.yahoo.com/group/gelide/">Project Mailing List</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="IntelliJ IDEA 5.0"></a>
+        IntelliJ IDEA 5.0
+      </h4>
+                        <p>Java IDE with refactoring support and Ant integration.
+      The IDE has special editing and navigation support for Ant.
+      </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.intellij.com/idea/">http://www.intellij.com/idea/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@intellij.com">support@intellij.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial; Academic and OpenSource licenses available.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JBuilder"></a>
+        JBuilder
+      </h4>
+                        <p>Borland JBuilder
+        comes with built-in Ant support, including build file editing.
+        Some versions come with Ant debugging support.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Bundles Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.codegear.com/en/products/jbuilder">http://www.codegear.com/en/products/jbuilder</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://support.codegear.com/en">http://support.codegear.com/en</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial; Turbo JBuilder 2007 is free.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JDEE"></a>
+        JDEE
+      </h4>
+                        <p>The Java Development Environment for Emacs (JDEE) supports
+        Apache Ant as one of three built-in ways to build your
+        applications.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jdee.sunsite.dk/">http://jdee.sunsite.dk/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jde-subscribe@sunsite.auc.dk">JDEE Mailing list.</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="NetBeans"></a>
+        NetBeans
+      </h4>
+                        <p>A module that integrates Ant into the NetBeans IDE, as well as derivative products such as Sun Java
+        Studio (formerly Forte for Java and Sun ONE Studio) and Sun Java Studio Creator.
+        This IDE uses Ant as its <i>sole</i> means of building applications,
+        with custom tasks and an Ant-aware editor.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles 1.6.5 for NetBeans 5.0 and 5.5; 1.7.0 for NetBeans 6.0
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.netbeans.org/">http://www.netbeans.org/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:nbdev@netbeans.org">nbdev@netbeans.org</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Common Development and Distribution License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Optistic IDX Java IDE"></a>
+        Optistic IDX Java IDE
+      </h4>
+                        <p>Java IDE with deep Ant integration. IDX is a native Microsoft Windows program.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.optistic.com/idx">http://optistic.com/idx</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:support@optistic.com">support@optistic.com</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial; Academic and OpenSource licenses available.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Oracle JDeveloper 10i"></a>
+        Oracle JDeveloper 10i
+      </h4>
+                        <p>Java IDE with support for Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.oracle.com/technology/products/jdev/index.html">http://www.oracle.com/technology/products/jdev/index.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://forums.oracle.com/forums/forum.jspa?forumID=83">JDeveloper Forum</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Virtual Ant"></a>
+        Virtual Ant
+      </h4>
+                        <p>
+          Instead of manually creating build scripts in XML, Virtual Ant provides a fully virtual file system
+          where you can run your tasks in real time and see the results. Everything that you do is recorded and
+          turned into an Ant build script.
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              Ant 1.6.5 onwards
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.placidsystems.com/virtualant/">http://www.placidsystems.com/virtualant/</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="mailto:support@placidsystems.com">support@placidsystems.com</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial; OpenSource licenses available too.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="WebSphere Studio Application Developer"></a>
+        WebSphere Studio Application Developer
+      </h4>
+                        <p>WSAD features Ant integrate by virtue of being built on the Eclipse tools platform.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.4.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ibm.com/developerworks/websphere/">http://www.ibm.com/developerworks/websphere/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Article:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Using Ant with WebSphere Studio Application Developer<ul>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle1.html">Part 1</a></li>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle2.html">Part 2</a></li>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle3.html">Part 3</a></li>
+            </ul>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="Source Control Systems"></a>
+      Source Control Systems
+    </h3>
+                        <p>There are several integration with SCM systems. Some are
+      <a href="manual/tasksoverview.html#scm">built in</a>. But some are available as
+      external libraries. Here a list of task libraries we are aware of:</p>
+                                      <h4 class="subsection">
+        <a name="clearAntLib"></a>
+        clearAntLib
+      </h4>
+                        <p>This library is a collection of "value-add" Ant tasks for integrating 
+         IBM Rational ClearCase with Apache Ant. The integration makes full use 
+         of the power and capabilities of Ant, with support for nested elements 
+         (such as filesets) and also supports conditions. There are a number of 
+         tasks for creating XML reports on both ClearCase baselines and labels as 
+         well as a task for "staging" ClearCase objects.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.1 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://clearantlib.sourceforge.net/">
+            http://clearantlib.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/forum/?group_id=123764">Forum</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          The Apache Software License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Surround SCM"></a>
+        Surround SCM
+      </h4>
+                        <p>These are tasks that allow users to access Surround SCM
+         functionality from within Ant build scripts.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.seapine.com/scmresources.php#integration">
+            Surround SCM Resource Center</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:support@seapine.com">Seapine Support</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU Lesser General Public License
+      </td>
+      </tr>
+          </table>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/faq.html b/trunk/docs/faq.html
new file mode 100644
index 0000000..be19818
--- /dev/null
+++ b/trunk/docs/faq.html
@@ -0,0 +1,2089 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Frequently Asked Questions</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="bodewig@apache.org">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                              <span class="sel">Frequently Asked Questions</span>
+                              </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Frequently Asked Questions</h1>
+    
+        <h3 class="section">Questions</h3>
+                <h4 class="toc">About this FAQ</h4>
+        <ul>
+                <li><a href="#latest-version">
+  Where do I find the latest version of this
+        document?
+      </a></li>
+                <li><a href="#adding-faqs">
+  How can I contribute to this FAQ?
+      </a></li>
+                <li><a href="#creating-faq">
+  How do you create the HTML version of this
+        FAQ?
+      </a></li>
+            </ul>
+                <h4 class="toc">General</h4>
+        <ul>
+                <li><a href="#what-is-ant">
+  What is Apache Ant?
+      </a></li>
+                <li><a href="#ant-name">
+  Why do you call it Ant?
+      </a></li>
+                <li><a href="#history">
+  Tell us a little bit about Ant's history.
+      </a></li>
+            </ul>
+                <h4 class="toc">Installation</h4>
+        <ul>
+                <li><a href="#no-gnu-tar">
+  I get checksum errors when I try to extract the
+      <code>tar.gz</code> distribution file. Why?
+      </a></li>
+                <li><a href="#RedHat_ES_3">
+  How do you get ant-1.6.x (or any version later than
+      1.5.2) to work on on RedHat ES 3?
+      </a></li>
+            </ul>
+                <h4 class="toc">How do I ...</h4>
+        <ul>
+                <li><a href="#implement-os-specific-configuration">
+  How do I realize os--specific configurations?
+      </a></li>
+                <li><a href="#adding-external-tasks">
+  How do I add an external task that I've written to the
+      page "External Tools and Tasks"?
+      </a></li>
+                <li><a href="#create-extensions">
+  How do I create new tasks?
+      </a></li>
+                <li><a href="#passing-cli-args">
+  How do I pass parameters from the command line to my
+        build file?
+      </a></li>
+                <li><a href="#jikes-switches">
+  How can I use Jikes-specific command-line
+        switches?
+      </a></li>
+                <li><a href="#shell-redirect-1">
+  How do I include a &lt; character in my command-line arguments?
+      </a></li>
+                <li><a href="#shell-redirect-2">
+  How do I redirect standard input or standard output
+        in the <code>&lt;exec&gt;</code> task?
+      </a></li>
+                <li><a href="#batch-shell-execute">
+  How do I execute a batch file or shell script from Ant?
+      </a></li>
+                <li><a href="#multi-conditions">
+  I want to execute a particular target only if
+        multiple conditions are true.
+      </a></li>
+                <li><a href="#encoding">
+  How can I include national characters like German
+        umlauts in my build file?
+      </a></li>
+                <li><a href="#use-zip-instead-of-jar">
+  How do I use <code>jar</code>'s <code>M</code> switch?
+      I don't want a MANIFEST.
+      </a></li>
+                <li><a href="#propertyvalue-as-name-for-property">
+  How can I do something like <code>&lt;property name="prop"
+      value="${${anotherprop}}"/&gt;</code> (double expanding the property)?
+      </a></li>
+                <li><a href="#delete-directory-children-only">
+  How can I delete everything beneath a particular directory,
+    preserving the directory itself?
+      </a></li>
+            </ul>
+                <h4 class="toc">It doesn't work (as expected)</h4>
+        <ul>
+                <li><a href="#general-advice">
+  General Advice
+      </a></li>
+                <li><a href="#always-recompiles">
+  Why does Ant always recompile all my Java files?
+      </a></li>
+                <li><a href="#defaultexcludes">
+  I've used a <code>&lt;delete&gt;</code> task to
+      delete unwanted SourceSafe control files (CVS files, editor
+      backup files, etc.), but it doesn't seem to work; the files
+      never get deleted. What's wrong?
+      </a></li>
+                <li><a href="#stop-dependency">
+  I have a target I want to skip if a property is set,
+      so I have <code>unless="property"</code> as an attribute
+      of the target, but all the targets this target
+      depends on are still executed. Why?
+      </a></li>
+                <li><a href="#include-order">
+  In my <code>&lt;fileset&gt;</code>, I've put in an
+      <code>&lt;exclude&gt;</code> of all files followed by an
+      <code>&lt;include&gt;</code> of just the files I want, but it
+      isn't giving me any files at all. What's wrong?
+      
+      </a></li>
+                <li><a href="#properties-not-trimmed">
+  <code>ant</code> failed to build my program via javac
+      even when I put the needed jars in an external
+      <code>build.properties</code> file and reference them by
+      <code>pathelement</code> or <code>classpath refid</code>.
+      </a></li>
+                <li><a href="#winzip-lies">
+  Ant creates WAR files with a lower-case
+        <code>web-inf</code> or JAR files with a lower-case
+        <code>meta-inf</code> directory.
+      </a></li>
+                <li><a href="#NoClassDefFoundError">
+  I installed Ant 1.6.x and now get
+        <code>Exception in thread "main" java.lang.NoClassDefFoundError:
+        </code>
+      
+      </a></li>
+                <li><a href="#InstantiationException">
+  I installed Ant 1.6.x and now get
+        <code>java.lang.InstantiationException: org.apache.tools.ant.Main</code>
+      
+      </a></li>
+                <li><a href="#mangled-manifest">
+  
+        Whenever I use the Ant jar or manifest related tasks, long lines in
+        my manifest are wrapped at 70 characters and the resulting jar does
+        not work in my application server. Why does Ant do this?
+      
+      </a></li>
+            </ul>
+                <h4 class="toc">Ant and IDEs/Editors</h4>
+        <ul>
+                <li><a href="#integration">
+  Is Ant supported by my IDE/Editor?
+      </a></li>
+                <li><a href="#emacs-mode">
+  Why doesn't (X)Emacs/vi/MacOS X's project builder
+      correctly parse the error messages generated by Ant?
+      </a></li>
+            </ul>
+                <h4 class="toc">Advanced Issues</h4>
+        <ul>
+                <li><a href="#dtd">
+  Is there a DTD that I can use to validate my build
+      files?
+      </a></li>
+                <li><a href="#xml-entity-include">
+  How do I include an XML snippet in my build file?
+      </a></li>
+                <li><a href="#mail-logger">
+  How do I send an email with the result of my build
+        process?
+      </a></li>
+                <li><a href="#listener-properties">
+  How do I get at the properties that Ant was running
+      with from inside BuildListener?
+      </a></li>
+            </ul>
+                <h4 class="toc">Known Problems</h4>
+        <ul>
+                <li><a href="#170-requires-junit">
+  Ant 1.7.0 doesn't build from sources without
+        JUnit
+      </a></li>
+                <li><a href="#remove-cr">
+  &lt;chmod&gt; or &lt;exec&gt; doesn't work in Ant
+        1.3 on Unix
+      </a></li>
+                <li><a href="#javadoc-cannot-execute">
+  JavaDoc failed: java.io.IOException: javadoc: cannot execute
+      </a></li>
+                <li><a href="#delegating-classloader">
+  &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt;
+      </a></li>
+                <li><a href="#delegating-classloader-1.5">
+  &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.5.x version
+      </a></li>
+                <li><a href="#delegating-classloader-1.6">
+  &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.6.x version
+      </a></li>
+                <li><a href="#winxp-jdk14-ant14">
+  When running Ant 1.4 on Windows XP and JDK 1.4, I get
+      various errors when trying to <code>&lt;exec&gt;</code>, fork
+      <code>&lt;java&gt;</code> or access environment
+      variables.
+      </a></li>
+                <li><a href="#1.5-cygwin-sh">
+  The <code>ant</code> wrapper script of Ant 1.5 fails
+      for Cygwin if <code>ANT_HOME</code> is set to a Windows style
+      path.
+      </a></li>
+                <li><a href="#1.5.2-zip-broken">
+  <code>&lt;zip&gt;</code> is broken in Ant 1.5.2.
+      </a></li>
+                <li><a href="#unknownelement.taskcontainer">
+  
+        Why do my custom task containers see Unknown Elements in Ant 1.6
+        - they worked in Ant 1.5?
+      
+      </a></li>
+                <li><a href="#java.exception.stacktrace">
+  
+        The program I run via &lt;java&gt; throws an exception but I
+        can't seem to get the full stack trace.
+      
+      </a></li>
+                <li><a href="#junit-no-runtime-xml">
+  
+        Using format="xml", &lt;junit&gt; fails with a
+        <code>NoClassDefFoundError</code> if forked.
+      
+      </a></li>
+                <li><a href="#xalan-jdk1.5">
+  
+        <code>&lt;junitreport&gt;</code> doesn't work with JDK 1.5 but
+        worked fine with JDK 1.4.
+      
+      </a></li>
+            </ul>
+    
+      <h3 class="section">Answers</h3>
+                    <p class="faq">
+      <a name="latest-version"></a>
+      Where do I find the latest version of this
+        document?
+    </p>
+                  <p>The latest version can always be found at Ant's homepage
+          <a href="http://ant.apache.org/faq.html">http://ant.apache.org/faq.html</a>.</p>
+                    <p class="faq">
+      <a name="adding-faqs"></a>
+      How can I contribute to this FAQ?
+    </p>
+                  <p>The page you are looking it is generated from
+          <a href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/faq.xml">this</a>
+          document.  If you want to add a new question, please submit
+          a patch against this document to one of Ant's mailing lists;
+          hopefully, the structure is self-explanatory.</p>
+                        <p>If you don't know how to create a patch, see the patches
+          section of <a href="http://jakarta.apache.org/site/source.html">this
+          page</a>.</p>
+                    <p class="faq">
+      <a name="creating-faq"></a>
+      How do you create the HTML version of this
+        FAQ?
+    </p>
+                  <p>We use
+        <a href="http://jakarta.apache.org/velocity/anakia.html">Anakia</a>
+        to render the HTML version from the original XML file.</p>
+                        <p>The Velocity stylesheets used to process the XML files can
+        be found in the <code>xdocs/stylesheets</code> subdirectory of
+        Ant's SVN repository - the build file
+        <code>docs.xml</code> at the top level of the ant SVN
+        module (trunk) is used to drive Anakia.</p>
+                        <p>This file assumes that you have the
+        <code>jakarta-site2</code> CVS module checked out as well, but
+        if you follow the instruction from Anakia's homepage, you
+        should get it to work without that.  Just make sure all
+        required jars are in the task's classpath.</p>
+                                <p class="faq">
+      <a name="what-is-ant"></a>
+      What is Apache Ant?
+    </p>
+                  <p> Ant is a Java-based build tool. In theory, it is kind of
+        like Make, without Make's wrinkles and with the full
+        portability of pure Java code.</p>
+                    <p class="faq">
+      <a name="ant-name"></a>
+      Why do you call it Ant?
+    </p>
+                  <p>According to Ant's original author, James Duncan
+        Davidson, the name is an acronym for "Another Neat
+        Tool".</p>
+                        <p>Later explanations go along the lines of "ants
+        do an extremely good job at building things", or
+        "ants are very small and can carry a weight dozens of times
+        their own" - describing what Ant is intended to
+        be.</p>
+                    <p class="faq">
+      <a name="history"></a>
+      Tell us a little bit about Ant's history.
+    </p>
+                  <p>Initially, Ant was part of the Tomcat code base, when it was
+        donated to the Apache Software Foundation. It was
+        created by James Duncan Davidson, who is also the original
+        author of Tomcat. Ant was there to build Tomcat, nothing
+        else.</p>
+                        <p>Soon thereafter, several open source Java projects realized
+        that Ant could solve the problems they had with Makefiles.
+        Starting with the projects hosted at Jakarta and the old Java
+        Apache project, Ant spread like a virus and is now the build
+        tool of choice for a lot of projects.</p>
+                        <p>In January 2000, Ant was moved to a separate CVS module and
+        was promoted to a project of its own, independent of
+        Tomcat, and became Apache Ant.</p>
+                        <p>The first version of Ant that was exposed to a larger audience
+        was the one that shipped with Tomcat's 3.1 release on 19 April
+        2000.  This version has later been referred to as Ant
+        0.3.1.</p>
+                        <p>The first official release of Ant as a stand-alone product was
+        Ant 1.1, released on 19 July 2000.  The complete release
+        history:</p>
+                              <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant Version
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Release Date
+      </th>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.1
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          19 July 2000
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.2
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          24 October 2000
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.3
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          3 March 2001
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.4
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          3 September 2001
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.4.1
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          11 October 2001
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          10 July 2002
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.1
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          3 October 2002
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.2
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          3 March 2003
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.3
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          9 April 2003
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.5.4
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          12 August 2003
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.0
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          18 December 2003
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.1
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          12 February 2004
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.2
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          16 July 2004
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.3
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          28 April 2005
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.4
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          19 May 2005
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6.5
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          2 June 2005
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.7.0
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          19 December 2006
+      </td>
+      </tr>
+          </table>
+                                <p class="faq">
+      <a name="no-gnu-tar"></a>
+      I get checksum errors when I try to extract the
+      <code>tar.gz</code> distribution file. Why?
+    </p>
+                  <p>Ant's distribution contains file names that are longer
+        than 100 characters, which is not supported by the standard
+        tar file format. Several different implementations of tar use
+        different and incompatible ways to work around this
+        restriction.</p>
+                        <p>Ant's &lt;tar&gt; task can create tar archives that use
+        the GNU tar extension, and this has been used when putting
+        together the distribution. If you are using a different
+        version of tar (for example, the one shipping with Solaris),
+        you cannot use it to extract the archive.</p>
+                        <p>The solution is to either install GNU tar, which can be
+        found <a href="http://www.gnu.org/software/tar/tar.html">here</a>,
+        or use the zip archive instead (you can extract it using
+        <code>jar xf</code>).</p>
+                    <p class="faq">
+      <a name="RedHat_ES_3"></a>
+      How do you get ant-1.6.x (or any version later than
+      1.5.2) to work on on RedHat ES 3?
+    </p>
+                  <p>Redhat ES 3.0 comes installed with ant 1.5.2. Even if you
+        have your PATH and ANT_HOME variables set correctly to a later
+        version of ant, you will always be forced to use the
+        preinstalled version.</p>
+                        <p>To use a later version of ant on this OS you could do the
+        following:</p>
+                        <pre class="code">
+$ ant -version
+Apache Ant version 1.5.2-23 compiled on November 12 2003
+$ su -
+# rpm -e ant ant-libs
+# exit
+$ hash -r
+$ ant -version
+Apache Ant version 1.6.2 compiled on July 16 2004
+</pre>
+                                <p class="faq">
+      <a name="implement-os-specific-configuration"></a>
+      How do I realize os--specific configurations?
+    </p>
+                  <p>The core idea is using property files which name accords to the
+        os-name. Then simply use the build-in property <tt>os.name</tt>.</p>
+                        <p>For better use you should also provide a file with defaul values.
+        But be careful with the correct os-names. For test simply &lt;echo&gt;
+        the ${os.name} on all machines and you can be sure to use the right
+        file names.</p>
+                        <pre class="code">
+          &lt;property file=&quot;${os.name}.properties&quot;/&gt;
+          &lt;property file=&quot;default.properties&quot;/&gt;
+</pre>
+                    <p class="faq">
+      <a name="adding-external-tasks"></a>
+      How do I add an external task that I've written to the
+      page "External Tools and Tasks"?
+    </p>
+                  <p>Join and post a message to the dev or user mailing
+        list (one list is enough), including the following
+        information:</p>
+                        <ul>
+          <li>the name of the task/tool</li>
+          <li>a short description of the task/tool</li>
+          <li>a Compatibility: entry stating with which version(s) of
+          Ant the tool/task is compatible to</li>
+          <li>a URL: entry linking to the main page of the tool/task</li>
+          <li>a Contact: entry containing the email address or the URL
+          of a webpage for the person or list to contact for issues
+          related to the tool/task.  <strong>Note that we'll add a
+          link on the page, so any email address added there is not
+          obfuscated and can (and probably will) be abused by robots
+          harvesting websites for addresses to spam.</strong></li>
+          <li>a License: entry containing the type of license for the
+          tool/task</li>
+        </ul>
+                        <p>The preferred format for this information is a patch to <a href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/external.xml">this</a>
+        document.</p>
+                        <p>If you have written something bigger than a 'simple plugin' to Ant it
+        may be better to add the link to <a href="projects.html">projects.html</a>.
+        The procedure to add it is the same. The file to patch is <a href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/projects.xml">this</a>
+        document. The syntax of that file is the same.</p>
+                    <p class="faq">
+      <a name="create-extensions"></a>
+      How do I create new tasks?
+    </p>
+                  <p>Apart from a lot of information on using Ant, the
+        <a href="manual/index.html">Manual</a> also contains information
+        on how to extend Ant with new tasks. This information
+        can be found under "Developing with Ant".</p>
+                        <p>Chances are that someone else already created the task you
+        want to create, it may be wise to see
+        <a href="external.html">External Tools and Tasks</a> and
+        <a href="projects.html">Related Projects</a> first.</p>
+                    <p class="faq">
+      <a name="passing-cli-args"></a>
+      How do I pass parameters from the command line to my
+        build file?
+    </p>
+                  <p>Use properties. Using <code>ant
+        -D<em>name</em>=<em>value</em></code> lets you define values for
+        properties on the Ant command line. These properties can then be
+        used within your build file as
+        any normal property: <code>${<em>name</em>}</code> will put in
+        <code><em>value</em></code>.</p>
+                    <p class="faq">
+      <a name="jikes-switches"></a>
+      How can I use Jikes-specific command-line
+        switches?
+    </p>
+                  <p>A couple of switches are supported via "magic"
+          properties:</p>
+                              <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          switch
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          property
+      </th>
+                          <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          default
+      </th>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          +E
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          build.compiler.emacs
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          false == not set
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          +P
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          build.compiler.pedantic
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          false == not set
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          +F
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          build.compiler.fulldepend
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          false == not set
+      </td>
+      </tr>
+                  <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <strong>(Only for Ant &lt; 1.4; replaced by the
+                <code><strong>nowarn</strong></code>
+                attribute of the <code><strong>&lt;javac&gt;</strong></code>
+                task after that.)</strong><br />-nowarn
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          build.compiler.warnings
+      </td>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          true == not set
+      </td>
+      </tr>
+          </table>
+                        <p>With Ant &gt;= 1.5, you can also use nested
+          <code>&lt;compilerarg&gt;</code> elements with the
+          <code>&lt;javac&gt;</code> task.</p>
+                    <p class="faq">
+      <a name="shell-redirect-1"></a>
+      How do I include a &lt; character in my command-line arguments?
+    </p>
+                  <p>The short answer is "Use: <code>&amp;lt;</code>".</p>
+                        <p>The long answer is that this probably won't do what you
+        want anyway (see <a href="#shell-redirect-2">the next
+        section</a>).</p>
+                    <p class="faq">
+      <a name="shell-redirect-2"></a>
+      How do I redirect standard input or standard output
+        in the <code>&lt;exec&gt;</code> task?
+    </p>
+                  <p>Say you want to redirect the standard output stream of the
+        <code>m4</code> command to write to a file, something
+        like:</p>
+                        <pre class="code">
+shell-prompt&gt; m4 foo.m4 &gt; foo
+</pre>
+                        <p>and try to translate it into</p>
+                        <pre class="code">
+&lt;exec executable=&quot;m4&quot;&gt;
+  &lt;arg value=&quot;foo.m4&quot;/&gt;
+  &lt;arg value=&quot;&amp;gt;&quot;/&gt;
+  &lt;arg value=&quot;foo&quot;/&gt;
+&lt;/exec&gt;
+</pre>
+                        <p>This will not do what you expect.  The output redirection is
+        performed by your shell, not the command itself, so this
+        should read:</p>
+                        <pre class="code">
+&lt;exec executable=&quot;/bin/sh&quot;&gt;
+  &lt;arg value=&quot;-c&quot; /&gt;
+  &lt;arg value=&quot;m4 foo.m4 &amp;gt; foo&quot; /&gt;
+&lt;/exec&gt;
+</pre>
+                        <p>Note that you must use the <code>value</code> attribute of
+        <code>&lt;arg&gt;</code> in the last element, in order to have
+        the command passed as a single, quoted argument. Alternatively,
+        you can use:</p>
+                        <pre class="code">
+&lt;exec executable=&quot;/bin/sh&quot;&gt;
+  &lt;arg line='-c &quot;m4 foo.m4 &amp;gt; foo&quot;'/&gt;
+&lt;/exec&gt;
+</pre>
+                        <p>Note the double-quotes nested inside the single-quotes.</p>
+                    <p class="faq">
+      <a name="batch-shell-execute"></a>
+      How do I execute a batch file or shell script from Ant?
+    </p>
+                  <p>On native Unix systems, you should be able to run shell scripts
+           directly. On systems running a Unix-type shell (for example, Cygwin
+           on Windows) execute the (command) shell instead - <code>cmd</code>
+           for batch files, <code>sh</code> for shell scripts - then pass the
+           batch file or shell script (plus any arguments to the script)
+           as a single command, using the <code>/c</code> or
+           <code>-c</code> switch, respectively. See
+           <a href="#shell-redirect-2">the above section</a>
+           for example <code>&lt;exec&gt;</code> tasks
+           executing <code>sh</code>. For batch files, use something like:</p>
+                        <pre class="code">
+&lt;exec dir=&quot;.&quot; executable=&quot;cmd&quot; os=&quot;Windows NT&quot;&gt;
+  &lt;arg line=&quot;/c test.bat&quot;/&gt;
+&lt;/exec&gt;
+</pre>
+                    <p class="faq">
+      <a name="multi-conditions"></a>
+      I want to execute a particular target only if
+        multiple conditions are true.
+    </p>
+                  <p>There are actually several answers to this question.</p>
+                        <p>If you have only one set and one unset property to test,
+        you can specify both an <code>if</code> and an <code>unless</code>
+        attribute for the target, and they will act as if they
+        are "anded" together.</p>
+                        <p>If you are using a version of Ant 1.3 or earlier, the
+        way to work with all other cases is to chain targets together
+        to determine the specific state you want to test for.</p>
+                        <p>To see how this works, assume you have three properties:
+        <code>prop1</code>, <code>prop2</code>, and <code>prop3</code>.
+        You want to test that <code>prop1</code> and <code>prop2</code>
+        are set, and that <code>prop3</code> is not. If the condition
+        holds true you want to echo "yes".</p>
+                        <p>Here is the implementation in Ant 1.3 and earlier:</p>
+                        <pre class="code">
+&lt;target name=&quot;cond&quot; depends=&quot;cond-if&quot;/&gt;
+
+&lt;target name=&quot;cond-if&quot; if=&quot;prop1&quot;&gt;
+  &lt;antcall target=&quot;cond-if-2&quot;/&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;cond-if-2&quot; if=&quot;prop2&quot;&gt;
+  &lt;antcall target=&quot;cond-if-3&quot;/&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;cond-if-3&quot; unless=&quot;prop3&quot;&gt;
+  &lt;echo message=&quot;yes&quot;/&gt;
+&lt;/target&gt;
+</pre>
+                        <p>Note: <code>&lt;antcall&gt;</code> tasks do <em>not</em> pass
+        property changes back up to the environment they were called
+        from, so you wouldn't be able to, for example, set a
+        <code>result</code> property in the <code>cond-if-3</code> target,
+        then do
+        <code>&lt;echo message="result is ${result}"/&gt;</code>
+        in the <code>cond</code> target.</p>
+                        <p>Starting with Ant 1.4, you can use the
+        <code>&lt;condition&gt;</code> task.</p>
+                        <pre class="code">
+&lt;target name=&quot;cond&quot; depends=&quot;cond-if,cond-else&quot;/&gt;
+
+&lt;target name=&quot;check-cond&quot;&gt;
+  &lt;condition property=&quot;cond-is-true&quot;&gt;
+    &lt;and&gt;
+      &lt;not&gt;
+        &lt;equals arg1=&quot;${prop1}&quot; arg2=&quot;$${prop1}&quot; /&gt;
+      &lt;/not&gt;
+      &lt;not&gt;
+        &lt;equals arg1=&quot;${prop2}&quot; arg2=&quot;$${prop2}&quot; /&gt;
+      &lt;/not&gt;
+      &lt;equals arg1=&quot;${prop3}&quot; arg2=&quot;$${prop3}&quot; /&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;cond-if&quot; depends=&quot;check-cond&quot; if=&quot;cond-is-true&quot;&gt;
+  &lt;echo message=&quot;yes&quot;/&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;cond-else&quot; depends=&quot;check-cond&quot; unless=&quot;cond-is-true&quot;&gt;
+  &lt;echo message=&quot;no&quot;/&gt;
+&lt;/target&gt;
+</pre>
+                        <p>This version takes advantage of two things:</p>
+                        <ul>
+          <li>If a property <code>a</code> has not been set,
+          <code>${a}</code> will evaluate to <code>${a}</code>.</li>
+
+          <li>To get a literal <code>$</code> in Ant, you have to
+          escape it with another <code>$</code> - this will also break
+          the special treatment of the <code>${</code> sequence.</li>
+        </ul>
+                        <p>Because testing for a literal <code>${property}</code> string
+        isn't all that readable or easy to understand,
+        post-1.4.1 Ant introduces the <code>&lt;isset&gt;</code> element
+        to the <code>&lt;condition&gt;</code> task.</p>
+                        <p>Here is the previous example done using
+        <code>&lt;isset&gt;</code>:</p>
+                        <pre class="code">
+&lt;target name=&quot;check-cond&quot;&gt;
+  &lt;condition property=&quot;cond-is-true&quot;&gt;
+    &lt;and&gt;
+      &lt;isset property=&quot;prop1&quot;/&gt;
+      &lt;isset property=&quot;prop2&quot;/&gt;
+      &lt;not&gt;
+        &lt;isset property=&quot;prop3&quot;/&gt;
+      &lt;/not&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+&lt;/target&gt;
+</pre>
+                        <p>The last option is to use a scripting language to set the
+        properties. This can be particularly handy when you need much
+        finer control than the simple conditions shown here but, of
+        course, comes with the overhead of adding JAR files to support
+        the language, to say nothing of the added maintenance in requiring
+        two languages to implement a single system. See the
+        <a href="manual/OptionalTasks/script.html">
+        <code>&lt;script&gt;</code> task documentation</a> for more
+        details.</p>
+                    <p class="faq">
+      <a name="encoding"></a>
+      How can I include national characters like German
+        umlauts in my build file?
+    </p>
+                  <p>You need to tell the XML parser which character encoding
+        your build file uses, this is done inside the <a href="http://www.w3.org/TR/2000/REC-xml-20001006#sec-prolog-dtd">XML
+        declaration</a>.</p>
+                        <p>By default the parser assumes you are using the UTF-8
+        encoding instead of your platform's default.  For most Western
+        European countries you should set the encoding to
+        <code>ISO-8859-1</code>.  To do so, make the very first line
+        of you build file read like</p>
+                        <pre class="code">
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot; ?&gt;
+</pre>
+                    <p class="faq">
+      <a name="use-zip-instead-of-jar"></a>
+      How do I use <code>jar</code>'s <code>M</code> switch?
+      I don't want a MANIFEST.
+    </p>
+                  <p>A JAR archive is a ZIP file, so if you don't want a
+        MANIFEST you can simply use <code>&lt;zip&gt;</code>.</p>
+                        <p>If your file names contain national characters you should
+        know that Sun's <code>jar</code> utility like Ant's
+        <code>&lt;jar&gt;</code> uses UTF-8 to encode their names while
+        <code>&lt;zip&gt;</code> uses your platforms default encoding.
+        Use the encoding attribute of <code>&lt;zip&gt;</code> if
+        necessary.</p>
+                    <p class="faq">
+      <a name="propertyvalue-as-name-for-property"></a>
+      How can I do something like <code>&lt;property name="prop"
+      value="${${anotherprop}}"/&gt;</code> (double expanding the property)?
+    </p>
+                  <p>Without any external help you can not.</p>
+                        <p>With &lt;script/&gt;, which needs external libraries, you can do</p>
+                        <pre class="code">
+&lt;script language=&quot;javascript&quot;&gt;
+    propname = project.getProperty(&quot;anotherprop&quot;);
+    project.setNewProperty(&quot;prop&quot;, propname);
+&lt;/script&gt;
+</pre>
+                        <p>With AntContrib (external task library) you can do <code>
+         &lt;propertycopy name="prop" from="${anotherprop}"/&gt;</code>.</p>
+                        <p>With Ant 1.6 you can simulate the AntContribs &lt;propertycopy&gt;
+         and avoid the need of an external library:</p>
+                        <pre class="code">
+&lt;macrodef name=&quot;propertycopy&quot;&gt;
+  &lt;attribute name=&quot;name&quot;/&gt;
+  &lt;attribute name=&quot;from&quot;/&gt;
+  &lt;sequential&gt;
+    &lt;property name=&quot;@{name}&quot; value=&quot;${@{from}}&quot;/&gt;
+  &lt;/sequential&gt;
+&lt;/macrodef&gt;
+</pre>
+                    <p class="faq">
+      <a name="delete-directory-children-only"></a>
+      How can I delete everything beneath a particular directory,
+    preserving the directory itself?
+    </p>
+                  <p>Most users who go down this path have no problem figuring out that
+  <code>&lt;delete includeemptydirs="true" /&gt;</code> will help them.  The
+  seemingly tricky part is preserving the base directory itself,
+  which Ant includes in the directory scan. Fortunately the answer is simple:
+</p>
+                        <pre class="code">
+&lt;delete includeemptydirs=&quot;true&quot;&gt;
+  &lt;fileset dir=&quot;dirtokeep&quot; includes=&quot;**/*&quot; /&gt;
+&lt;/delete&gt;
+</pre>
+                                <p class="faq">
+      <a name="general-advice"></a>
+      General Advice
+    </p>
+                  <p>There are many reasons why Ant doesn't behave as
+        expected, not all of them are due to Ant bugs.  See our <a href="problems.html">Having Problems?</a> page for hints that
+        may help pinning down the reasons for your problem.</p>
+                    <p class="faq">
+      <a name="always-recompiles"></a>
+      Why does Ant always recompile all my Java files?
+    </p>
+                  <p>In order to find out which files should be compiled, Ant
+        compares the timestamps of the source files to those of the
+        resulting <code>.class</code> files.  Opening all source files
+        to find out which package they belong to would be very
+        inefficient. Instead, Ant expects you to place your
+        source files in a directory hierarchy that mirrors your
+        package hierarchy and to point Ant to the root of this
+        directory tree with the <code>srcdir</code> attribute.</p>
+                        <p>Say you have <code>&lt;javac srcdir="src"
+        destdir="dest"/&gt;</code>.  If Ant finds a file
+        <code>src/a/b/C.java</code>, it expects it to be in package
+        <code>a.b</code> so that the resulting <code>.class</code>
+        file is going to be <code>dest/a/b/C.class</code>.</p>
+                        <p>If your source-tree directory structure does not match your
+        package structure, Ant's heuristic won't work, and
+        it will recompile classes that are up-to-date.  Ant is not the
+        only tool that expects a source-tree layout like this.</p>
+                        <p>If you have Java source files that aren't declared to
+        be part of any package, you can still use the <code>&lt;javac&gt;</code>
+        task to compile these files correctly - just set the
+        <code>srcdir</code> and <code>destdir</code> attributes to
+        the actual directory the source
+        files live in and the directory the class files should go into,
+        respectively.</p>
+                    <p class="faq">
+      <a name="defaultexcludes"></a>
+      I've used a <code>&lt;delete&gt;</code> task to
+      delete unwanted SourceSafe control files (CVS files, editor
+      backup files, etc.), but it doesn't seem to work; the files
+      never get deleted. What's wrong?
+    </p>
+                  <p>This is probably happening because, by default, Ant excludes
+        SourceSafe control files (<code>vssver.scc</code>) and certain other
+        files from FileSets.</p>
+                        <p>Here's what you probably did:</p>
+                        <pre class="code">
+&lt;delete&gt;
+  &lt;fileset dir=&quot;${build.src}&quot; includes=&quot;**/vssver.scc&quot;/&gt;
+&lt;/delete&gt;
+</pre>
+                        <p>You need to switch off the default exclusions,
+           and it will work:</p>
+                        <pre class="code">
+&lt;delete&gt;
+  &lt;fileset dir=&quot;${build.src}&quot; includes=&quot;**/vssver.scc&quot;
+           defaultexcludes=&quot;no&quot;/&gt;
+&lt;/delete&gt;
+</pre>
+                        <p>For a complete listing of the patterns that are excluded
+        by default, see <a href="manual/dirtasks.html#defaultexcludes">the user
+        manual</a>.</p>
+                    <p class="faq">
+      <a name="stop-dependency"></a>
+      I have a target I want to skip if a property is set,
+      so I have <code>unless="property"</code> as an attribute
+      of the target, but all the targets this target
+      depends on are still executed. Why?
+    </p>
+                  <p>The list of dependencies is generated by Ant before any of the
+        targets are run. This allows dependent targets, such as an
+        <code>init</code> target, to set properties that can control the
+               execution of the targets higher in the dependency graph. This
+              is a good thing.</p>
+                        <p>However, when your dependencies break down the
+        higher-level task
+        into several smaller steps, this behaviour becomes
+        counter-intuitive. There are a couple of solutions available:
+        </p>
+                        <ol>
+          <li>Put the same condition on each of the dependent targets.</li>
+
+          <li>Execute the steps using <code>&lt;antcall&gt;</code>,
+          instead of specifying them inside the <code>depends</code>
+          attribute.</li>
+        </ol>
+                    <p class="faq">
+      <a name="include-order"></a>
+      In my <code>&lt;fileset&gt;</code>, I've put in an
+      <code>&lt;exclude&gt;</code> of all files followed by an
+      <code>&lt;include&gt;</code> of just the files I want, but it
+      isn't giving me any files at all. What's wrong?
+      
+    </p>
+                  <p>The order of the <code>&lt;include&gt;</code> and
+        <code>&lt;exclude&gt;</code> tags within a <code>&lt;fileset&gt;</code>
+        is ignored when the FileSet is created. Instead, all of the
+        <code>&lt;include&gt;</code> elements are processed together,
+        followed by all of the <code>&lt;exclude&gt;</code>
+        elements. This means that the <code>&lt;exclude&gt;</code>
+        elements only apply to the file list produced by the
+        <code>&lt;include&gt;</code> elements.</p>
+                        <p>To get the files you want, focus on just the
+        <code>&lt;include&gt;</code> patterns that would be necessary
+        to get them. If you find you need to trim the list that the
+        <code>&lt;include&gt;</code> elements produce, then use
+        <code>&lt;exclude&gt;</code> elements.</p>
+                    <p class="faq">
+      <a name="properties-not-trimmed"></a>
+      <code>ant</code> failed to build my program via javac
+      even when I put the needed jars in an external
+      <code>build.properties</code> file and reference them by
+      <code>pathelement</code> or <code>classpath refid</code>.
+    </p>
+                  <p>When <code>ant</code> loads properties from an external
+        file it doesn't touch the value of properties, trailing blanks
+        will not be trimmed for example.</p>
+                        <p>If the value represents a file path, like a jar needed to
+        compile, the task which requires the value, javac for example
+        would fail to compile since it can't find the file due to
+        trailing spaces.</p>
+                    <p class="faq">
+      <a name="winzip-lies"></a>
+      Ant creates WAR files with a lower-case
+        <code>web-inf</code> or JAR files with a lower-case
+        <code>meta-inf</code> directory.
+    </p>
+                  <p>No it doesn't.</p>
+                        <p>You may have seen these lower-case directory names in
+        WinZIP, but WinZIP is trying to be helpful (and fails).  If
+        WinZIP encounters a filename that is all upper-case, it
+        assumes it has come from an old DOS box and changes the case to
+        all lower-case for you.</p>
+                        <p>If you extract (or just check) the archive with jar, you
+        will see that the names have the correct case.</p>
+                        <p>With WinZIP (version 8.1 at least), this can be corrected in the
+        configuration.  In the Options/Configuration menu, in the View tab, General
+        section, check the "Allow all upper case files names" box.  The META-INF and
+        WEB-INF will look correct.</p>
+                    <p class="faq">
+      <a name="NoClassDefFoundError"></a>
+      I installed Ant 1.6.x and now get
+        <code>Exception in thread "main" java.lang.NoClassDefFoundError:
+        </code>
+      
+    </p>
+                  <p>
+          The cause of this is that there is an old version of ant somewhere in the
+          class path or configuration.
+        </p>
+                        <p>
+          A version of this problem happens with jars that are in the classpath
+          that include an embedded copy of ant classes.
+          An example of this is some copies of weblogic.jar.
+        </p>
+                        <p>
+        One can check if this is the case by doing (on unix/sh):
+        <code><pre>
+        unset CLASSPATH
+        ant -version
+        </pre>
+        </code>
+        </p>
+                    <p class="faq">
+      <a name="InstantiationException"></a>
+      I installed Ant 1.6.x and now get
+        <code>java.lang.InstantiationException: org.apache.tools.ant.Main</code>
+      
+    </p>
+                  <p>
+          The cause of this is that there is an old version of ant somewhere in the
+          class path or configuration.
+        </p>
+                        <p>
+          A version of this problem may be seen on some linux systems.
+          Some linux systems (Fedora Core 2 for example), comes with a version
+          of ant pre-installed. There is a configuration file called
+          <code>/etc/ant.conf</code> which if present, the ant shell
+          script will 'dot' include. On Fedora Core 2, the /etc/ant.conf
+          file resets the <code>ANT_HOME</code> environment variable to
+          <code>/usr/share/ant</code>. This causes the problem that
+          an old version of ant (1.5.x in this cause) will be used
+          with a new version of the ant script file.
+        </p>
+                        <p>
+          One can check if this is the case by doing
+          <code>ant --noconfig -version</code>.
+        </p>
+                    <p class="faq">
+      <a name="mangled-manifest"></a>
+      
+        Whenever I use the Ant jar or manifest related tasks, long lines in
+        my manifest are wrapped at 70 characters and the resulting jar does
+        not work in my application server. Why does Ant do this?
+      
+    </p>
+                  <p>
+          Ant implements the Java
+          <a href="http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html">Jar
+          file specification</a>. Please refer to the notes section where it
+          discusses the maximum allowable length of a line and the concept of
+          continuation characters.
+        </p>
+                        <p>
+          If a jar file produced by Ant does not work in your appserver, and
+          that failure is due to the wrapped manifest, then you need
+          to consult your appserver provider, as it is a bug in their
+          appserver. Far more likely, however, is a problem in your
+          specification of your classpath. It is not Ant's wrapping of your
+          classpath that is the problem.
+        </p>
+                        <p>
+          Do not raise a bug about this issue until you have checked to ensure
+          that the problem is not due to your classpath specification.
+        </p>
+                                <p class="faq">
+      <a name="integration"></a>
+      Is Ant supported by my IDE/Editor?
+    </p>
+                  <p>See the <a href="external.html#IDE and Editor Integration">section
+        on IDE integration</a> on our External Tools and Tasks page.</p>
+                    <p class="faq">
+      <a name="emacs-mode"></a>
+      Why doesn't (X)Emacs/vi/MacOS X's project builder
+      correctly parse the error messages generated by Ant?
+    </p>
+                  <p>Ant adds a "banner" with the name of the current
+        task in front of all logging messages - and there are no built-in
+        regular expressions in your editor that would account for
+        this.</p>
+                        <p>You can disable this banner by invoking Ant with the
+        <code>-emacs</code> switch.  To make Ant autodetect
+        Emacs' compile mode, put this into your
+        <code>.antrc</code> (contributed by Ville Skyttä).</p>
+                        <pre class="code">
+# Detect (X)Emacs compile mode
+if [ &quot;$EMACS&quot; = &quot;t&quot; ] ; then
+  ANT_ARGS=&quot;$ANT_ARGS -emacs&quot;
+  ANT_OPTS=&quot;$ANT_OPTS -Dbuild.compiler.emacs=true&quot;
+fi
+</pre>
+                        <p>Alternatively, you can add the following snippet to your
+        <code>.emacs</code> to make Emacs understand Ant's
+        output.</p>
+                        <pre class="code">
+(require 'compile)
+(setq compilation-error-regexp-alist
+  (append (list
+     ;; works for jikes
+     '(&quot;^\\s-*\\[[^]]*\\]\\s-*\\(.+\\):\\([0-9]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:&quot; 1 2 3)
+     ;; works for javac
+     '(&quot;^\\s-*\\[[^]]*\\]\\s-*\\(.+\\):\\([0-9]+\\):&quot; 1 2))
+  compilation-error-regexp-alist))
+</pre>
+                        <p>Yet another alternative that preserves most of Ant's
+        formatting is to pipe Ant's output through the following Perl
+        script by Dirk-Willem van Gulik:</p>
+                        <pre class="code">
+#!/usr/bin/perl
+#
+# May 2001 dirkx@apache.org - remove any
+# [foo] lines from the output; keeping
+# spacing more or less there.
+#
+$|=1;
+while(&lt;STDIN&gt;) {
+        if (s/^(\s+)\[(\w+)\]//) {
+                if ($2 ne $last) {
+                        print &quot;$1\[$2\]&quot;;
+                        $s = ' ' x length($2);
+                } else {
+                        print &quot;$1 $s &quot;;
+                };
+                $last = $2;
+        };
+        print;
+};
+</pre>
+                                <p class="faq">
+      <a name="dtd"></a>
+      Is there a DTD that I can use to validate my build
+      files?
+    </p>
+                  <p>An incomplete DTD can be created by the
+          <code>&lt;antstructure&gt;</code> task - but this one
+          has a few problems:</p>
+                        <ul>
+            <li>It doesn't know about required attributes.  Only
+            manual tweaking of this file can help here.</li>
+
+            <li>It is not complete - if you add new tasks via
+            <code>&lt;taskdef&gt;</code> it won't know about it.  See
+            <a href="http://www.sdv.fr/pages/casa/html/ant-dtd.en.html">this
+            page</a> by Michel Casabianca for a solution to this
+            problem.  Note that the DTD you can download at this page
+            is based on Ant 0.3.1.</li>
+
+            <li>It may even be an invalid DTD.  As Ant allows tasks
+            writers to define arbitrary elements, name collisions will
+            happen quite frequently - if your version of Ant contains
+            the optional <code>&lt;test&gt;</code> and
+            <code>&lt;junit&gt;</code> tasks, there are two XML
+            elements named <code>test</code> (the task and the nested child
+            element of <code>&lt;junit&gt;</code>) with different attribute
+            lists.  This problem cannot be solved; DTDs don't give a
+            syntax rich enough to support this.</li>
+          </ul>
+                    <p class="faq">
+      <a name="xml-entity-include"></a>
+      How do I include an XML snippet in my build file?
+    </p>
+                  <p>You can use XML's way of including external files and let
+        the parser do the job for Ant:</p>
+                        <pre class="code">
+&lt;?xml version=&quot;1.0&quot;?&gt;
+
+&lt;!DOCTYPE project [
+       &lt;!ENTITY common SYSTEM &quot;common.xml&quot;&gt;
+]&gt;
+
+&lt;project name=&quot;test&quot; default=&quot;test&quot; basedir=&quot;.&quot;&gt;
+
+  &lt;target name=&quot;setup&quot;&gt;
+    ...
+  &lt;/target&gt;
+
+  &amp;common;
+
+  ...
+
+&lt;/project&gt;
+</pre>
+                        <p>will literally include the contents of <code>common.xml</code> where
+        you've placed the <code>&amp;common;</code> entity.</p>
+                        <p>(The filename <code>common.xml</code> in this example is resolved
+        relative to the containing XML file by the XML parser. You may also use
+        an absolute <code>file:</code> protocol URI.)</p>
+                        <p>In combination with a DTD, this would look like this:</p>
+                        <pre class="code">
+&lt;!DOCTYPE project PUBLIC &quot;-//ANT//DTD project//EN&quot; &quot;ant.dtd&quot; [
+   &lt;!ENTITY include SYSTEM &quot;header.xml&quot;&gt;
+]&gt;
+</pre>
+                        <p>Starting with Ant 1.6, there is a new
+        <code>&lt;import&gt;</code> task that can (also) be used to
+        include build file fragments.  Unlike the snippets used with
+        entity includes, the referenced files have to be complete Ant
+        build files, though.</p>
+                        <p>The example above would become:</p>
+                        <pre class="code">
+&lt;?xml version=&quot;1.0&quot;?&gt;
+&lt;project name=&quot;test&quot; default=&quot;test&quot; basedir=&quot;.&quot;&gt;
+
+  &lt;target name=&quot;setup&quot;&gt;
+    ...
+  &lt;/target&gt;
+
+  &lt;import file=&quot;./common.xml&quot;/&gt;
+
+  ...
+
+&lt;/project&gt;
+</pre>
+                        <p>Unlike entity includes, <code>&lt;import&gt;</code> will
+        let you use Ant properties in the file name.</p>
+                    <p class="faq">
+      <a name="mail-logger"></a>
+      How do I send an email with the result of my build
+        process?
+    </p>
+                  <p>If you are using a nightly build of Ant 1.5 after
+        2001-12-14, you can use the built-in MailLogger:</p>
+                        <pre class="code">
+         ant -logger org.apache.tools.ant.listener.MailLogger
+</pre>
+                        <p>See the <a href="http://svn.apache.org/repos/asf/ant/core/trunk/docs/manual/listeners.html">Listeners
+        &amp; Loggers</a> documentation for details on the properties
+        required.</p>
+                        <p>For older versions of Ant, you can use a custom
+        BuildListener that sends out an email
+        in the buildFinished() method.  Will Glozer
+        &lt;will.glozer@jda.com&gt; has written such a listener based
+        on <a href="http://java.sun.com/products/javamail/">JavaMail</a>.
+        The source is:</p>
+                        <pre class="code">
+import java.io.*;
+import java.util.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import org.apache.tools.ant.*;
+
+/**
+ * A simple listener that waits for a build to finish and sends an email
+ * of the results.  The settings are stored in &quot;monitor.properties&quot; and
+ * are fairly self explanatory.
+ *
+ * @author      Will Glozer
+ * @version     1.05a 09/06/2000
+ */
+public class BuildMonitor implements BuildListener {
+    protected Properties props;
+
+    /**
+     * Create a new BuildMonitor.
+     */
+    public BuildMonitor() throws Exception {
+        props = new Properties();
+        InputStream is = getClass().getResourceAsStream(&quot;monitor.properties&quot;);
+        props.load(is);
+        is.close();
+    }
+
+    public void buildStarted(BuildEvent e) {
+    }
+
+    /**
+     * Determine the status of the build and the actions to follow, now that
+     * the build has completed.
+     *
+     * @param       e       Event describing the build status.
+     */
+    public void buildFinished(BuildEvent e) {
+        Throwable th = e.getException();
+        String status = (th != null) ? &quot;failed&quot; : &quot;succeeded&quot;;
+
+        try {
+            String key = &quot;build.&quot; + status;
+            if (props.getProperty(key + &quot;.notify&quot;).equalsIgnoreCase(&quot;false&quot;)) {
+                    return;
+            }
+
+            Session session = Session.getDefaultInstance(props, null);
+
+            MimeMessage message = new MimeMessage(session);
+            message.addRecipients(Message.RecipientType.TO, parseAddresses(
+                props.getProperty(key + &quot;.email.to&quot;)));
+            message.setSubject(props.getProperty(key + &quot;.email.subject&quot;));
+
+            BufferedReader br = new BufferedReader(new FileReader(
+                props.getProperty(&quot;build.log&quot;)));
+            StringWriter sw = new StringWriter();
+
+            String line = br.readLine();
+            while (line != null) {
+                sw.write(line);
+                sw.write(&quot;\n&quot;);
+                line = br.readLine();
+            }
+            br.close();
+
+            message.setText(sw.toString(), &quot;UTF-8&quot;);
+            sw.close();
+
+            Transport transport = session.getTransport();
+            transport.connect();
+            transport.send(message);
+            transport.close();
+        } catch (Exception ex) {
+            System.out.println(&quot;BuildMonitor failed to send email!&quot;);
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Parse a comma separated list of internet email addresses.
+     *
+     * @param       s       The list of addresses.
+     * @return      Array of Addresses.
+     */
+    protected Address[] parseAddresses(String s) throws Exception {
+        StringTokenizer st = new StringTokenizer(s, &quot;,&quot;);
+        Address[] addrs = new Address[st.countTokens()];
+
+        for (int i = 0; i &lt; addrs.length; i++) {
+            addrs[i] = new InternetAddress(st.nextToken());
+        }
+        return addrs;
+    }
+
+    public void messageLogged(BuildEvent e) {
+    }
+
+    public void targetStarted(BuildEvent e) {
+    }
+
+    public void targetFinished(BuildEvent e) {
+    }
+
+    public void taskStarted(BuildEvent e) {
+    }
+
+    public void taskFinished(BuildEvent e) {
+    }
+}
+</pre>
+                        <p>With a <code>monitor.properties</code> like this:</p>
+                        <pre class="code">
+# configuration for build monitor
+
+mail.transport.protocol=smtp
+mail.smtp.host=&lt;host&gt;
+mail.from=Will Glozer &lt;will.glozer@jda.com&gt;
+
+build.log=build.log
+
+build.failed.notify=true
+build.failed.email.to=will.glozer@jda.com
+build.failed.email.subject=Nightly build failed!
+
+build.succeeded.notify=true
+build.succeeded.email.to=will.glozer@jda.com
+build.succeeded.email.subject=Nightly build succeeded!
+</pre>
+                        <p><code>monitor.properties</code> should be placed right next
+        to your compiled <code>BuildMonitor.class</code>.  To use it,
+        invoke Ant like:</p>
+                        <pre class="code">
+ant -listener BuildMonitor -logfile build.log
+</pre>
+                        <p>Make sure that <code>mail.jar</code> from JavaMail and
+        <code>activation.jar</code> from the
+        <a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">Java
+        Beans Activation Framework</a> are in your <code>CLASSPATH</code>.</p>
+                    <p class="faq">
+      <a name="listener-properties"></a>
+      How do I get at the properties that Ant was running
+      with from inside BuildListener?
+    </p>
+                  <p>You can get at a hashtable with all the properties that Ant
+        has been using through the BuildEvent parameter. For
+        example:</p>
+                        <pre class="code">
+public void buildFinished(BuildEvent e) {
+    Hashtable table = e.getProject().getProperties();
+    String buildpath = (String)table.get(&quot;build.path&quot;);
+    ...
+}
+</pre>
+                        <p>This is more accurate than just reading the same property
+        files that your project does, since it will give the correct
+        results for properties that were specified on the Ant command line.</p>
+                                <p class="faq">
+      <a name="170-requires-junit"></a>
+      Ant 1.7.0 doesn't build from sources without
+        JUnit
+    </p>
+                  <p>When building Ant 1.7.0 from the source release without
+        junit.jar the build fails with the message "We cannot build
+        the test jar unless JUnit is present".</p>
+                        <p>With Ant 1.7.0 we've started to add ant-testutil.jar as
+        part of the distribution and this causes a hard dependency on
+        JUnit - at least in version 1.7.0.  Unfortunately the
+        installation docs don't say so.</p>
+                        <p>There are two workarounds:</p>
+                        <ol>
+
+          <li>Add junit.jar to your CLASSPATH when building Ant.</li>
+
+          <li>Change Ant's buildfile and remove test-jar from the
+          depends list of the dist-lite target.</li>
+
+        </ol>
+                    <p class="faq">
+      <a name="remove-cr"></a>
+      &lt;chmod&gt; or &lt;exec&gt; doesn't work in Ant
+        1.3 on Unix
+    </p>
+                  <p>The <code>antRun</code> script in <code>ANT_HOME/bin</code>
+        has DOS instead of Unix line endings; you must remove the
+        carriage-return characters from this file.  This can be done by
+        using Ant's <code>&lt;fixcrlf&gt;</code> task
+        or something like:</p>
+                        <pre class="code">
+tr -d '\r' &lt; $ANT_HOME/bin/antRun &gt; /tmp/foo
+mv /tmp/foo $ANT_HOME/bin/antRun
+</pre>
+                    <p class="faq">
+      <a name="javadoc-cannot-execute"></a>
+      JavaDoc failed: java.io.IOException: javadoc: cannot execute
+    </p>
+                  <p>There is a bug in the Solaris reference implementation of
+        the JDK (see <a href="http://developer.java.sun.com/developer/bugParade/bugs/4230399.html">http://developer.java.sun.com/developer/bugParade/bugs/4230399.html</a>).
+        This also appears to be true under Linux. Moving the JDK to
+        the front of the PATH fixes the problem.</p>
+                    <p class="faq">
+      <a name="delegating-classloader"></a>
+      &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt;
+    </p>
+                  <p>Starting with Ant 1.7.0, &lt;junit&gt; will honor your
+        nested &lt;classpath&gt;.</p>
+                        <p>These tasks don't ignore your classpath setting, you
+        are facing a common problem with delegating classloaders.</p>
+                        <p>This question collects a common type of problem: A task
+        needs an external library and it has a nested classpath
+        element so that you can point it to this external library, but
+        that doesn't work unless you put the external library
+        into the <code>CLASSPATH</code> or place it in
+        <code>ANT_HOME/lib</code>.</p>
+                        <p>Some background is necessary before we can discuss
+        solutions for <a href="#delegating-classloader-1.5">Ant
+        1.5.x</a> and <a href="#delegating-classloader-1.6">Ant
+        1.6.x</a>.</p>
+                        <p>When you specify a nested <code>&lt;classpath&gt;</code> in
+        Ant, Ant creates a new class loader that uses the path you
+        have specified.  It then tries to load additional classes from
+        this classloader.</p>
+                        <p>In most cases - for example using &lt;style&gt; or
+        &lt;junit&gt; - Ant doesn't load the external library
+        directly, it is the loaded class that does so.</p>
+                        <p>In the case of <code>&lt;junit&gt;</code> it is the task
+        implementation itself and in the case of
+        <code>&lt;style&gt;</code> it is the implementation of the
+        <code>org.apache.tools.ant.taskdefs.XSLTLiaison</code>
+        class.</p>
+                        <p><em>As of Ant 1.7</em> <code>&lt;junit&gt;</code> no longer
+        requires you to have <code>junit.jar</code> in Ant's startup
+        classpath even if <code>ant-junit.jar</code> is present there.</p>
+                        <p>Ant's class loader implementation uses Java's
+        delegation model, see <a href="http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html">http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html</a>
+        the paragraph</p>
+                        <blockquote>The <code>ClassLoader</code> class uses a
+        delegation model to search for classes and resources. Each
+        instance of <code>ClassLoader</code> has an associated parent
+        class loader.  When called upon to find a class or resource, a
+        <code>ClassLoader</code> instance will delegate the search for
+        the class or resource to its parent class loader before
+        attempting to find the class or resource itself. The virtual
+        machine's built-in class loader, called the bootstrap
+        class loader, does not itself have a parent but may serve as
+        the parent of a <code>ClassLoader</code>
+        instance.</blockquote>
+                        <p>The possible solutions depend on the version of Ant you
+        use, see the next sections.</p>
+                    <p class="faq">
+      <a name="delegating-classloader-1.5"></a>
+      &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.5.x version
+    </p>
+                  <p>Please read <a href="#delegating-classloader">the previous
+        entry</a> before you go ahead.</p>
+                        <p>First of all let's state that Ant's wrapper script
+        (<code>ant</code> or <code>ant.bat</code>) adds all
+        <code>.jar</code> files from <code>ANT_HOME/lib</code> to
+        <code>CLASSPATH</code>, therefore "in
+        <code>CLASSPATH</code>" shall mean "either in your
+        <code>CLASSPATH</code> environment variable or
+        <code>ANT_HOME/lib</code>" for the rest of this
+        answer.</p>
+                        <p>The root of the problem is that the class that needs the
+        external library is on the <code>CLASSPATH</code>.</p>
+                        <p>Let's see what happens when you load the &lt;junit&gt;
+        task.  Ant's class loader will consult the
+        bootstrap class loader first, which tries to load classes from
+        <code>CLASSPATH</code>.  The bootstrap class loader
+        doesn't know anything about Ant's class loader or
+        even the path you have specified.</p>
+                        <p>If the bootstrap class loader can load the class Ant has
+        asked it to load (which it can if <code>optional.jar</code> is
+        part of <code>CLASSPATH</code>), this class will try to load
+        the external library from <code>CLASSPATH</code> as well - it
+        doesn't know anything else - and will not find it unless
+        the library is in <code>CLASSPATH</code> as well.</p>
+                        <p>To solve this, you have two major options:</p>
+                        <ol>
+          <li>put all external libraries you need in
+          <code>CLASSPATH</code> as well this is not what you want,
+          otherwise you wouldn't have found this FAQ entry.</li>
+
+          <li>remove the class that loads the external library from
+          the <code>CLASSPATH</code>.</li>
+        </ol>
+                        <p>The easiest way to do this is to remove
+        <code>optional.jar</code> from <code>ANT_HOME/lib</code>.  If
+        you do so, you will have to <code>&lt;taskdef&gt;</code> all
+        optional tasks and use nested <code>&lt;classpath&gt;</code>
+        elements in the <code>&lt;taskdef&gt;</code> tasks that point
+        to the new location of <code>optional.jar</code>.  Also,
+        don't forget to add the new location of
+        <code>optional.jar</code> to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code>
+        task.</p>
+                        <p>If you want to avoid to <code>&lt;taskdef&gt;</code> all
+        optional tasks you need, the only other option is to remove
+        the classes that should not be loaded via the bootstrap class
+        loader from <code>optional.jar</code> and put them into a
+        separate archive. Add this separate archive to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code> task
+        - and make sure the separate archive is not in
+        <code>CLASSPATH</code>.</p>
+                        <p>In the case of <code>&lt;junit&gt;</code> you'd have
+        to remove all classes that are in the
+        <code>org/apache/tools/ant/taskdefs/optional/junit</code>
+        directory, in the <code>&lt;style&gt;</code> case it is one of
+        the <code>*Liaison</code> classes in
+        <code>org/apache/tools/ant/taskdefs/optional</code>.</p>
+                        <p>If you use the option to break up <code>optional.jar</code>
+        for <code>&lt;junit&gt;</code> or remove
+        <code>ant-junit.jar</code>, you still have to use a
+        <code>&lt;taskdef&gt;</code> with a nested
+        <code>&lt;classpath&gt;</code> to define the junit task.</p>
+                    <p class="faq">
+      <a name="delegating-classloader-1.6"></a>
+      &lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.6.x version
+    </p>
+                  <p>Please read <a href="#delegating-classloader">the general
+        entry</a> before you go ahead.</p>
+                        <p>The wrapper script of Ant 1.6.x no longer adds the contents
+        of <code>ANT_HOME/lib</code> to <code>CLASSPATH</code>,
+        instead Ant will create a classloader on top of the bootstrap
+        classloader - let's call it the coreloader for the rest of
+        this answer - which holds the contents of
+        <code>ANT_HOME/lib</code>.  Ant's core and its tasks will be
+        loaded through this classloader and not the bootstrap
+        classloader.</p>
+                        <p>This causes some small but notable differences between Ant
+        1.5.x and 1.6.x.  Most importantly, a third-party task that is
+        part of <code>CLASSPATH</code> will no longer work in Ant
+        1.6.x since the task now can't find Ant's classes.  In a sense
+        this is the same problem this entry is about, only
+        <code>ant.jar</code> has become the external library in
+        question now.</p>
+                        <p>This coreloader also holds the contents of
+        <code>~/.ant/lib</code> and any file or directory that has
+        been specified using Ant's <code>-lib</code> command line
+        argument.</p>
+                        <p>Let's see what happens when you load the &lt;junit&gt;
+        task.  Ant's class loader will consult the bootstrap
+        class loader first, which tries to load classes from
+        <code>CLASSPATH</code>.  The bootstrap class loader
+        doesn't know anything about Ant's class loader or
+        even the path you have specified.  If it fails to find the
+        class using the bootstrap classloader it will try the
+        coreloader next.  Again, the coreloader doesn't know anything
+        about your path.</p>
+                        <p>If the coreloader can load the class Ant has asked it to
+        load (which it can if <code>ant-junit.jar</code> is in
+        <code>ANT_HOME/lib</code>), this class will try to load the
+        external library from coreloader as well - it doesn't
+        know anything else - and will not find it unless the library
+        is in <code>CLASSPATH</code> or the coreloader as well.</p>
+                        <p>To solve this, you have the following major options:</p>
+                        <ol>
+          <li>put all external libraries you need in
+          <code>CLASSPATH</code> as well this is not what you want,
+          otherwise you wouldn't have found this FAQ entry.</li>
+
+          <li>put all external libraries you need in
+          <code>ANT_HOME/lib</code> or <code>.ant/lib</code>.  This
+          probably still isn't what you want, but you might reconsider
+          the <code>.ant/lib</code> option.</li>
+
+          <li>Always start Ant with the <code>-lib</code> command line
+          switch and point to your external libraries (or the
+          directories holding them).</li>
+
+          <li>remove the class that loads the external library from
+          the coreloader.</li>
+        </ol>
+                        <p>In Ant 1.6 <code>optional.jar</code> has been split into
+        multiple jars, each one containing classes with the same
+        dependencies on external libraries.  You can move the
+        "offending" jar out of <code>ANT_HOME/lib</code>.  For the
+        <code>&lt;junit&gt;</code> task it would be
+        <code>ant-junit.jar</code> and for <code>&lt;style&gt;</code>
+        it would be <code>ant-trax.jar</code>
+        or <code>ant-xslp.jar</code> - 
+        depending on the processor you use.</p>
+                        <p>If you do so, you will have to <code>&lt;taskdef&gt;</code>
+        all optional tasks that need the external library and use
+        nested <code>&lt;classpath&gt;</code> elements in the
+        <code>&lt;taskdef&gt;</code> tasks that point to the new
+        location of <code>ant-*.jar</code>.  Also, don't forget
+        to add the new location of <code>ant-*.jar</code> to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code>
+        task.</p>
+                        <p>For example</p>
+                        <pre class="code">
+    &lt;taskdef name=&quot;junit&quot;
+            class=&quot;org.apache.tools.ant.taskdefs.optional.junit.JUnitTask&quot;&gt;
+      &lt;classpath&gt;
+        &lt;pathelement location=&quot;HOME-OF/junit.jar&quot;/&gt;
+        &lt;pathelement location=&quot;NEW-HOME-OF/ant-junit.jar&quot;/&gt;
+      &lt;/classpath&gt;
+    &lt;/taskdef&gt;
+</pre>
+                    <p class="faq">
+      <a name="winxp-jdk14-ant14"></a>
+      When running Ant 1.4 on Windows XP and JDK 1.4, I get
+      various errors when trying to <code>&lt;exec&gt;</code>, fork
+      <code>&lt;java&gt;</code> or access environment
+      variables.
+    </p>
+                  <p>Ant &lt; 1.5 doesn't recognize Windows XP as a flavor
+        of Windows that runs <code>CMD.EXE</code> instead of
+        <code>COMMAND.COM</code>.  JDK 1.3 will tell Ant that Windows
+        XP is Windows 2000 so the problem doesn't show up
+        there.</p>
+                        <p>Apart from upgrading to Ant 1.5 or better, setting the
+        environment variable <code>ANT_OPTS</code> to
+        <code>-Dos.name=Windows_NT</code> prior to invoking Ant has
+        been confirmed as a workaround.</p>
+                    <p class="faq">
+      <a name="1.5-cygwin-sh"></a>
+      The <code>ant</code> wrapper script of Ant 1.5 fails
+      for Cygwin if <code>ANT_HOME</code> is set to a Windows style
+      path.
+    </p>
+                  <p>This problem has been reported only hours after Ant 1.5 has
+        been released, see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=10664">Bug
+        10664</a> and all its duplicates.</p>
+                        <p>A fixed version of the wrapper script can be found <a href="http://ant.apache.org/old-releases/v1.5/errata/">here</a>.
+        Simply replace your script with this version.</p>
+                    <p class="faq">
+      <a name="1.5.2-zip-broken"></a>
+      <code>&lt;zip&gt;</code> is broken in Ant 1.5.2.
+    </p>
+                  <p>Yes, it is.</p>
+                        <p>The problem reported by most people - see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17648">Bug
+        17648</a> and all its duplicates - is that Ant creates
+        archives that a partially unreadable by WinZIP.  Luckily
+        <code>jar</code> deals with the archives and so the generated
+        jars/wars/ears will most likely work for you anyway.</p>
+                        <p>There are additional problems, see bugs <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17780">Bug
+        17780</a>, <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17871">Bug
+        17871</a> and <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=18403">Bug
+        18403</a>.  All of them are supposed to be fixed with Ant
+        1.5.3 (and only 18403 should exist in 1.5.3beta1).</p>
+                    <p class="faq">
+      <a name="unknownelement.taskcontainer"></a>
+      
+        Why do my custom task containers see Unknown Elements in Ant 1.6
+        - they worked in Ant 1.5?
+      
+    </p>
+                  <p>
+          The objects added in TaskContainer.addTask(Task task)
+          have changed from  Tasks to UnknownElements.
+        </p>
+                        <p>
+          There was a number of valid reasons for this change. But the backward
+          compatibility problems were not noticed until after Ant 1.6.0 was
+          released.
+        </p>
+                        <p>
+          Your container class will need to be modified to check if the Task
+          is an UnknownElement and call perform on it to
+          convert it to a Task and to execute it.
+          (see apache.tools.ant.taskdefs.Sequential)
+        </p>
+                        <p>
+          If you want to do more processing on the task,
+          you need to use the techniques in apache.tools.ant.taskdefs.Antlib#execute()
+          This does make use of one 1.6 method call (UE#getRealObject()),
+          you need to use UE#getTask() instead - this will
+          return null for non tasks (types like fileset id=x).
+        </p>
+                        <p>
+          So.. iterate over the tasks, if they are UEs, convert them to
+          tasks, using UE#maybeConfigure and UE#getTask()
+        </p>
+                        <pre class="code">
+        for (Iterator i = tasks.iterator(); i.hasNext();) {
+           Task t = (Task) i.next();
+           if (t instanceof UnknownElement) {
+              ((UnknownElement) t).maybeConfigure();
+              t = ((UnknownElement) t).getTask();
+              if (t == null) {
+                  continue;
+              }
+           }
+           // .... original Custom code
+        }
+        </pre>
+                        <p>
+          This approach should work for ant1.5 and ant1.6.
+        </p>
+                    <p class="faq">
+      <a name="java.exception.stacktrace"></a>
+      
+        The program I run via &lt;java&gt; throws an exception but I
+        can't seem to get the full stack trace.
+      
+    </p>
+                  <p>This is a know bug that has been fixed after the release of
+        Ant 1.6.1.</p>
+                        <p>As a workaround, run your &lt;java&gt; task with
+        <code>fork="true"</code> and Ant will display the full
+        trace.</p>
+                    <p class="faq">
+      <a name="junit-no-runtime-xml"></a>
+      
+        Using format="xml", &lt;junit&gt; fails with a
+        <code>NoClassDefFoundError</code> if forked.
+      
+    </p>
+                  <p>The XML formatter needs the <a href="http://www.w3.org/DOM/">DOM classes</a> to work.  If you
+        are using JDK 1.4 or later they are included with your Java
+        Runtime and this problem won't occur.  If you are running JDK
+        1.3 or earlier, the DOM classes have to be on your
+        &lt;junit&gt; task's &lt;classpath&gt;.</p>
+                        <p>Prior to Ant 1.6.0 Ant would include the DOM classes from
+        the XML parser that is used by Ant itself if you set the
+        includeAntRuntime attribute to true (the default).  With Ant
+        1.6.0 this has been changed as this behavior made it
+        impossible to use a different XML parser in your tests.</p>
+                        <p>This means that you have to take care of the DOM classes
+        explicitly starting with Ant 1.6.0.  If you don't need to set
+        up a different XML parser for your tests, the easiest solution
+        is to add</p>
+                        <pre class="code">
+&lt;pathelement path=&quot;${ant.home}/lib/xml-apis.jar:${ant.home}/lib/xercesImpl.jar&quot;/&gt;
+</pre>
+                        <p>to your task's &lt;classpath&gt;.</p>
+                    <p class="faq">
+      <a name="xalan-jdk1.5"></a>
+      
+        <code>&lt;junitreport&gt;</code> doesn't work with JDK 1.5 but
+        worked fine with JDK 1.4.
+      
+    </p>
+                  <p>While JDK 1.4.x contains a version of Xalan-J 2, JDK 1.5
+        (and later?) have <a href="http://java.sun.com/j2se/1.5.0/compatibility.html#4959783">moved
+        to XSLTC</a>.  Since this task uses Xalan's redirect
+        extensions for its internal stylesheet, Ant prior to 1.6.2 didn't support
+        XSLTC.  This means that you have to install <a href="http://xml.apache.org/xalan-j/">Xalan-J 2</a> in order
+        to use this task with JDK 1.5 in older versions of Ant.</p>
+                        <p>Starting with Ant 1.6.2 <code>&lt;junitreport&gt;</code>
+        supports JDK 1.5.</p>
+                    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/favicon.ico b/trunk/docs/favicon.ico
new file mode 100644
index 0000000..161bcf7
--- /dev/null
+++ b/trunk/docs/favicon.ico
Binary files differ
diff --git a/trunk/docs/images/JDJEditorsChoiceAward.jpg b/trunk/docs/images/JDJEditorsChoiceAward.jpg
new file mode 100644
index 0000000..5dcb998
--- /dev/null
+++ b/trunk/docs/images/JDJEditorsChoiceAward.jpg
Binary files differ
diff --git a/trunk/docs/images/ant_logo.ico b/trunk/docs/images/ant_logo.ico
new file mode 100644
index 0000000..9dbc258
--- /dev/null
+++ b/trunk/docs/images/ant_logo.ico
Binary files differ
diff --git a/trunk/docs/images/ant_logo_large.gif b/trunk/docs/images/ant_logo_large.gif
new file mode 100644
index 0000000..e99363b
--- /dev/null
+++ b/trunk/docs/images/ant_logo_large.gif
Binary files differ
diff --git a/trunk/docs/images/ant_logo_medium.gif b/trunk/docs/images/ant_logo_medium.gif
new file mode 100644
index 0000000..44bc07f
--- /dev/null
+++ b/trunk/docs/images/ant_logo_medium.gif
Binary files differ
diff --git a/trunk/docs/images/ant_logo_small.gif b/trunk/docs/images/ant_logo_small.gif
new file mode 100644
index 0000000..34080c9
--- /dev/null
+++ b/trunk/docs/images/ant_logo_small.gif
Binary files differ
diff --git a/trunk/docs/images/beta.png b/trunk/docs/images/beta.png
new file mode 100644
index 0000000..924a75d
--- /dev/null
+++ b/trunk/docs/images/beta.png
Binary files differ
diff --git a/trunk/docs/images/current.gif b/trunk/docs/images/current.gif
new file mode 100644
index 0000000..af0f64f
--- /dev/null
+++ b/trunk/docs/images/current.gif
Binary files differ
diff --git a/trunk/docs/images/group-logo.gif b/trunk/docs/images/group-logo.gif
new file mode 100644
index 0000000..de57d34
--- /dev/null
+++ b/trunk/docs/images/group-logo.gif
Binary files differ
diff --git a/trunk/docs/images/jp_rcwinner_2003.gif b/trunk/docs/images/jp_rcwinner_2003.gif
new file mode 100644
index 0000000..63d8313
--- /dev/null
+++ b/trunk/docs/images/jp_rcwinner_2003.gif
Binary files differ
diff --git a/trunk/docs/images/jw_ec_logo_winner2002.gif b/trunk/docs/images/jw_ec_logo_winner2002.gif
new file mode 100644
index 0000000..334b114
--- /dev/null
+++ b/trunk/docs/images/jw_ec_logo_winner2002.gif
Binary files differ
diff --git a/trunk/docs/images/jw_ec_logo_winner2003.gif b/trunk/docs/images/jw_ec_logo_winner2003.gif
new file mode 100644
index 0000000..dbbb422
--- /dev/null
+++ b/trunk/docs/images/jw_ec_logo_winner2003.gif
Binary files differ
diff --git a/trunk/docs/images/label.gif b/trunk/docs/images/label.gif
new file mode 100644
index 0000000..bc4cb58
--- /dev/null
+++ b/trunk/docs/images/label.gif
Binary files differ
diff --git a/trunk/docs/images/menu-left.gif b/trunk/docs/images/menu-left.gif
new file mode 100644
index 0000000..0ca9047
--- /dev/null
+++ b/trunk/docs/images/menu-left.gif
Binary files differ
diff --git a/trunk/docs/images/menu-right.gif b/trunk/docs/images/menu-right.gif
new file mode 100644
index 0000000..879c028
--- /dev/null
+++ b/trunk/docs/images/menu-right.gif
Binary files differ
diff --git a/trunk/docs/images/page.gif b/trunk/docs/images/page.gif
new file mode 100644
index 0000000..b0b3944
--- /dev/null
+++ b/trunk/docs/images/page.gif
Binary files differ
diff --git a/trunk/docs/images/printer.gif b/trunk/docs/images/printer.gif
new file mode 100644
index 0000000..5021187
--- /dev/null
+++ b/trunk/docs/images/printer.gif
Binary files differ
diff --git a/trunk/docs/images/project-logo.gif b/trunk/docs/images/project-logo.gif
new file mode 100644
index 0000000..5d9cd7f
--- /dev/null
+++ b/trunk/docs/images/project-logo.gif
Binary files differ
diff --git a/trunk/docs/images/sdm_productivity_award.gif b/trunk/docs/images/sdm_productivity_award.gif
new file mode 100644
index 0000000..6d76aa0
--- /dev/null
+++ b/trunk/docs/images/sdm_productivity_award.gif
Binary files differ
diff --git a/trunk/docs/images/search-left.gif b/trunk/docs/images/search-left.gif
new file mode 100644
index 0000000..cb20446
--- /dev/null
+++ b/trunk/docs/images/search-left.gif
Binary files differ
diff --git a/trunk/docs/images/search-right.gif b/trunk/docs/images/search-right.gif
new file mode 100644
index 0000000..1005573
--- /dev/null
+++ b/trunk/docs/images/search-right.gif
Binary files differ
diff --git a/trunk/docs/images/spacer.gif b/trunk/docs/images/spacer.gif
new file mode 100644
index 0000000..35d42e8
--- /dev/null
+++ b/trunk/docs/images/spacer.gif
Binary files differ
diff --git a/trunk/docs/images/tab-left.gif b/trunk/docs/images/tab-left.gif
new file mode 100644
index 0000000..1bfd754
--- /dev/null
+++ b/trunk/docs/images/tab-left.gif
Binary files differ
diff --git a/trunk/docs/images/tab-right.gif b/trunk/docs/images/tab-right.gif
new file mode 100644
index 0000000..6803a85
--- /dev/null
+++ b/trunk/docs/images/tab-right.gif
Binary files differ
diff --git a/trunk/docs/images/tabSel-left.gif b/trunk/docs/images/tabSel-left.gif
new file mode 100644
index 0000000..46abc4d
--- /dev/null
+++ b/trunk/docs/images/tabSel-left.gif
Binary files differ
diff --git a/trunk/docs/images/tabSel-right.gif b/trunk/docs/images/tabSel-right.gif
new file mode 100644
index 0000000..881f74c
--- /dev/null
+++ b/trunk/docs/images/tabSel-right.gif
Binary files differ
diff --git a/trunk/docs/index.html b/trunk/docs/index.html
new file mode 100644
index 0000000..82db8c8
--- /dev/null
+++ b/trunk/docs/index.html
@@ -0,0 +1,342 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Welcome</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Conor MacNeill">
+  <meta name="email" content="">
+        <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="stefan.bodewig@freenet.de">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                              <span class="sel">Welcome</span>
+                              </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Welcome</h1>
+            <h3 class="section">
+      <a name="Apache Ivy is an Ant Sub-Project Now!"></a>
+      Apache Ivy is an Ant Sub-Project Now!
+    </h3>
+                        <h3>October 11, 2007 - Apache Ivy is an Ant Sub-Project Now!</h3>
+                                <p>Apache Ivy, "A Java based tool for tracking, resolving and
+    managing project dependencies.", just finished <a href="http://incubator.apache.org/">Incubation</a> and has joined
+    the Ant project.  More information will be available from the Ant
+    site soon.</p>
+                                <p>Until we've finished the migration, you can learn more about
+    Ivy from its <a href="http://incubator.apache.org/ivy/">Incubator
+    website</a>.</p>
+                        <h3 class="section">
+      <a name="Ant 1.7.0"></a>
+      Ant 1.7.0
+    </h3>
+                        <h3>December 19, 2006 - Ant 1.7.0 Available</h3>
+                                <p>Apache Ant 1.7.0 is now available for <a href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+                                <p>Ant 1.7 introduces a resource framework. Some of the core ant 
+    tasks such as &lt;copy/&gt; are now able to process not only file 
+    system resources but also zip entries, tar entries, paths, ... 
+    Resource collections group resources, and can be further 
+    combined with operators such as union and intersection. This 
+    can be extended by custom resources and custom tasks using resources.</p>
+                                <p>
+    Ant 1.7 starts outsourcing of optional tasks to Antlibs. 
+    The .NET antlib in preparation will replace the .NET optional tasks which ship in Ant.
+    Support for the version control system Subversion will be only provided as an antlib to
+    be released shortly. 
+    </p>
+                                <p>Ant 1.7 fixes also a large number of bugs.</p>
+                                <p>Ant 1.7 has some initial support for Java6 features.</p>
+                        <h3 class="section">
+      <a name="AntUnit 1.0"></a>
+      AntUnit 1.0
+    </h3>
+                        <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+                                <p>Apache AntUnit 1.0 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a href="antlibs/antunit/">AntUnit home page</a>.</p>
+                        <h3 class="section">
+      <a name=".NET Ant Library 1.0"></a>
+      .NET Ant Library 1.0
+    </h3>
+                        <h3>November 6, 2006 - Apache .NET Ant Library 1.0 Available</h3>
+                                <p>Apache .NET Ant Library 1.0 is now available for <a href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+                                <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+                                <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+                        <h3 class="section">
+      <a name="Apache Ant"></a>
+      Apache Ant
+    </h3>
+                        <p>
+Apache Ant is a Java-based build tool. In theory, it is kind of like
+Make, but without Make's wrinkles.
+</p>
+                                <p>
+Why another build tool when there is already <em>make</em>, <em>gnumake</em>,
+<em>nmake</em>, <em>jam</em>, and
+others? Because all those tools have limitations that Ant's original author
+couldn't live with when developing software across multiple platforms. Make-like
+tools are inherently shell-based -- they evaluate a set of dependencies, then
+execute commands not unlike what you would issue in a shell. This means that you
+can easily extend these tools by using or writing any program for the OS that
+you are working on. However, this also means that you limit yourself to the OS,
+or at least the OS type such as Unix, that you are working on.
+</p>
+                                <p>
+Makefiles are inherently evil as well. Anybody who has worked on them for any
+time has run into the dreaded tab problem. "Is my command not executing
+because I have a space in front of my tab!!!" said the original author of
+Ant way too many times. Tools like Jam took care of this to a great degree, but
+still have yet another format to use and remember.
+</p>
+                                <p>
+Ant is different. Instead of a model where it is extended with shell-based
+commands, Ant is extended using Java classes. Instead of writing shell commands,
+the configuration files are XML-based, calling out a target tree where various
+tasks get executed. Each task is run by an object that implements a particular
+Task interface.
+</p>
+                                <p>
+Granted, this removes some of the expressive power that is inherent by being
+able to construct a shell command such as
+<code>`find . -name foo -exec rm {}`</code>, but it
+gives you the ability to be cross platform -- to work anywhere and everywhere.
+And hey, if you really need to execute a shell command, Ant has an
+<code>&lt;exec&gt;</code> task that
+allows different commands to be executed based on the OS that it is executing
+on.
+</p>
+                        <h3 class="section">
+      <a name="Documentation"></a>
+      Documentation
+    </h3>
+                        <p>
+You can view the documentation for the current release (Apache Ant 1.7.0)
+<a href="manual/index.html">online</a>
+</p>
+                                <p>
+Comprehensive documentation is included in the source and binary distributions.
+</p>
+                        <h3 class="section">
+      <a name="Get Involved"></a>
+      Get Involved
+    </h3>
+                        <ul>
+<li><a href="http://jakarta.apache.org/getinvolved/getinvolvedindex.html">Get Involved</a></li>
+<li><a href="mail.html">Join Mailing Lists</a></li>
+<li><a href="http://marc.theaimsgroup.com/?l=ant-dev&amp;r=1&amp;w=2">Search the Dev Mailing List</a>
+</li>
+<li><a href="http://marc.theaimsgroup.com/?l=ant-user&amp;r=1&amp;w=2">Search the User Mailing List</a>
+</li>
+</ul>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/legal.html b/trunk/docs/legal.html
new file mode 100644
index 0000000..da290af
--- /dev/null
+++ b/trunk/docs/legal.html
@@ -0,0 +1,238 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Legal</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Jon S. Stevens">
+  <meta name="email" content="jon@latchkey.com">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                              <span class="sel">Legal</span>
+                              </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Legal</h1>
+            <h3 class="section">
+      <a name="Legal Stuff They Make Us Say"></a>
+      Legal Stuff They Make Us Say
+    </h3>
+                        <p>All material on this website is Copyright © 1999-2008,
+      The Apache Software Foundation.</p>
+                                <p>Sun, Sun Microsystems, Solaris, Java, JavaServer Web
+      Development Kit, and JavaServer Pages are trademarks or
+      registered trademarks of Sun Microsystems, Inc. UNIX is a
+      registered trademark in the United States and other countries,
+      exclusively licensed through X/Open Company, Ltd.  Windows,
+      WindowsNT, and Win32 are registered trademarks of Microsoft
+      Corp. All other product names mentioned herein and throughout
+      the entire web site are trademarks of their respective
+      owners.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/license.html b/trunk/docs/license.html
new file mode 100644
index 0000000..021e2ff
--- /dev/null
+++ b/trunk/docs/license.html
@@ -0,0 +1,512 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - License</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="The Apache Software Foundation">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                              <span class="sel">License</span>
+                              </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">License</h1>
+            <h3 class="section">
+      <a name="The Apache Software License Version 2.0"></a>
+      The Apache Software License Version 2.0
+    </h3>
+                        <p>The Apache Software License Version 2.0 applies 
+    to all releases of Ant starting with ant 1.6.1</p>
+                                <pre class="code">/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      &quot;License&quot; shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      &quot;Licensor&quot; shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      &quot;Legal Entity&quot; shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      &quot;control&quot; means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      &quot;You&quot; (or &quot;Your&quot;) shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      &quot;Source&quot; form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      &quot;Object&quot; form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      &quot;Work&quot; shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      &quot;Derivative Works&quot; shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      &quot;Contribution&quot; shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, &quot;submitted&quot;
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as &quot;Not a Contribution.&quot;
+ *
+ *      &quot;Contributor&quot; shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a &quot;NOTICE&quot; text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an &quot;AS IS&quot; BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets &quot;[]&quot;
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same &quot;printed page&quot; as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+    </pre>
+                                <p>You can download the original license file <a href="./LICENSE" target="_new">here.</a></p>
+                                <p>The License is accompanied by a NOTICE</p>
+                                <pre class="code">
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Ant distribution.                      ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   This product includes also software developed by :
+     - the W3C consortium (http://www.w3c.org) ,
+     - the SAX project (http://www.saxproject.org)
+
+   Please read the different LICENSE files present in the root directory of
+   this distribution.
+
+   The names &quot;Ant&quot; and  &quot;Apache Software Foundation&quot;  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.
+</pre>
+                        <h3 class="section">
+      <a name="The Apache Software License, Version 1.1"></a>
+      The Apache Software License, Version 1.1
+    </h3>
+                        <p> The Apache Software License, Version 1.1, applies to all versions of up to ant 1.6.0 included.</p>
+                                <pre class="code">/*
+ * ============================================================================
+ *                   The Apache Software License, Version 1.1
+ * ============================================================================
+ * 
+ *    Copyright (C) 2000-2003 The Apache Software Foundation. All
+ *    rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, 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  acknowledgment:  &quot;This product includes  software
+ *    developed  by the  Apache Software Foundation  (http://www.apache.org/).&quot;
+ *    Alternately, this  acknowledgment may  appear in the software itself,  if
+ *    and wherever such third-party acknowledgments normally appear.
+ * 
+ * 4. The names &quot;Ant&quot; and  &quot;Apache Software Foundation&quot;  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 &quot;Apache&quot;, nor may
+ *    &quot;Apache&quot; appear  in their name,  without prior written permission  of the
+ *    Apache Software Foundation.
+ * 
+ * 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 (INCLU-
+ * DING, 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 &lt;http://www.apache.org/&gt;.
+ *
+ */
+</pre>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/mail.html b/trunk/docs/mail.html
new file mode 100644
index 0000000..93867d5
--- /dev/null
+++ b/trunk/docs/mail.html
@@ -0,0 +1,331 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Mailing Lists</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Apache Ant PMC">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                              <span class="sel">Mailing Lists</span>
+                              </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Mailing Lists</h1>
+            <h3 class="section">
+      <a name="Mailing Lists"></a>
+      Mailing Lists
+    </h3>
+                        <p>Please read the <a href="http://jakarta.apache.org/site/mail.html">guidelines of
+      the Jakarta Project</a> before subscribing and posting to any of
+      the lists below.  They apply to Ant's lists as well.</p>
+                                <p>The user and dev list are subscriber only lists, this means
+      you have to subscribe before you can post to the list.  Please
+      note that any HTML parts sent to the lists will be removed by our
+      mailing list software - you shouldn't be sending HTML mails
+      anyway.</p>
+                                <p>To subscribe to a mailinglist use the links below. In your first email you will get some
+      information about working with the list manager <a href="http://www.ezmlm.org/">EZMLM</a>.</p>
+                                      <h4 class="subsection">
+        <a name="User List: user@ant.apache.org"></a>
+        User List: user@ant.apache.org
+      </h4>
+                        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:user-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:user-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-user/">ASF Archive</a>
+          <a href="http://marc.theaimsgroup.com/?l=ant-user&amp;r=1&amp;w=2">Third Party Archive</a>
+        </p>
+                                <p>This list is for developers that are using Ant in their own
+        projects to ask questions, share knowledge, and discuss issues
+        related to using Ant as a build tool.</p>
+                                                          <h4 class="subsection">
+        <a name="Ivy User List: ivy-user@ant.apache.org"></a>
+        Ivy User List: ivy-user@ant.apache.org
+      </h4>
+                        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:ivy-user-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:ivy-user-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-ivy-user/">ASF Archive</a>
+        </p>
+                                <p>This list is for developers that are using Ivy or IvyDE in
+        their own projects to ask questions, share knowledge, and
+        discuss issues related to using Ivy with or without Ant.</p>
+                                                          <h4 class="subsection">
+        <a name="Developer List: dev@ant.apache.org"></a>
+        Developer List: dev@ant.apache.org
+      </h4>
+                        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:dev-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:dev-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-dev/">ASF Archive</a>
+          <a href="http://marc.theaimsgroup.com/?l=ant-dev&amp;r=1&amp;w=2">Third Party Archive</a>
+        </p>
+                                <p>This is the list where participating developers of the Ant
+        build tool, Ivy or the Ant libraries developed by the Ant team
+        meet and discuss issues, code changes/additions, etc.</p>
+                                                          <h4 class="subsection">
+        <a name="Notifications List: notifications@ant.apache.org"></a>
+        Notifications List: notifications@ant.apache.org
+      </h4>
+                        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:notifications-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:notifications-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-notifications/">ASF Archive</a>
+        </p>
+                                <p>Subscribers to this list get notices of each and every
+        code change, build results, testing notices, etc.</p>
+                                                          <h4 class="subsection">
+        <a name="How to unsubscribe your old email address"></a>
+        How to unsubscribe your old email address
+      </h4>
+                        <p>
+        First, find out the particular email adress to which ezmlm is sending.
+        The email headers are visible in Microsoft Outlook via the messages menu
+        "View | Options".
+        <pre>
+        Microsoft Mail Internet Headers Version 2.0
+        ...
+        List-Unsubscribe: &lt;mailto:user-unsubscribe@ant.apache.org&gt;
+        List-Help: &lt;mailto:user-help@ant.apache.org&gt;
+        List-Post: &lt;mailto:user@ant.apache.org&gt;
+        List-Id: "Ant Users List" &lt;user.ant.apache.org&gt;
+        Reply-To: "Ant Users List" &lt;user@ant.apache.org&gt;
+        Delivered-To: mailing list user@ant.apache.org
+        ...
+        Return-Path: user-return-12345-<i>john=host.domain</i>@ant.apache.org
+        ...
+        </pre>
+        The <i>Return-Path</i> header contains the email address which is subscribed. 
+        </p>
+                                <p> To stop subscription for the address john@host.domain , send an email to <pre>dev-unsubscribe-john=host.domain@ant.apache.org</pre>
+          or to  <pre>user-unsubscribe-john=host.domain@ant.apache.org</pre>.
+        </p>
+                                            <h3 class="section">
+      <a name="Archives"></a>
+      Archives
+    </h3>
+                        <p>These lists are archived at</p>
+                                <ul>
+          <li><a href="http://mail-archives.apache.org/mod_mbox/">List Index on mail-archives.apache.org</a></li>
+          <li><a href="http://ant.apache.org/mail/">Full mbox archives of all lists</a></li>
+          <li><a href="http://marc.theaimsgroup.com/">Mailing list Archives</a></li>
+          <li><a href="http://news.gmane.org/gmane.comp.jakarta.ant.devel/">Ant Developer List on gmane</a></li>
+          <li><a href="http://news.gmane.org/gmane.comp.jakarta.ant.user/">Ant User List on gmane</a></li>
+          <li><a href="http://www.nabble.com/Ant---Dev-f108.html">Ant Developer List on nabble</a></li>
+          <li><a href="http://www.nabble.com/Ant---Users-f107.html">Ant User List on nabble</a></li>
+          <li><a href="http://ant.markmail.org/">Mailing List Archive at MarkMail</a></li>
+        </ul>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/manual/CoreTasks/ant.html b/trunk/docs/manual/CoreTasks/ant.html
new file mode 100644
index 0000000..b8b35e1
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/ant.html
@@ -0,0 +1,297 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Ant Task</title>
+</head>
+
+<body>
+
+<h2><a name="ant">Ant</a></h2>
+<h3>Description</h3>
+
+<p>Runs Ant on a supplied buildfile. This can be used to build
+subprojects.  <strong>This task must not be used outside of a
+<code>target</code> if it invokes the same build file it is part
+of.</strong></p>
+
+<p>When the <i>antfile</i> attribute is omitted, the file &quot;build.xml&quot;
+in the supplied directory (<i>dir</i> attribute) is used.</p>
+<p>If no target attribute is supplied, the default target of the new project is
+used.</p>
+<p>By default, all of the properties of the current project will be
+available in the new project.  Alternatively, you can set the
+<i>inheritAll</i> attribute to <code>false</code> and only
+&quot;user&quot; properties (i.e., those passed on the command-line)
+will be passed to the new project.  In either case, the set of
+properties passed to the new project will override the properties that
+are set in the new project (See also the <a
+href="property.html">property task</a>).</p>
+
+<p>You can also set properties in the new project from the old project
+by using nested property tags. These properties are always passed
+to the new project and any project created in that project
+regardless of the setting of <i>inheritAll</i>.  This allows you to
+parameterize your subprojects.  Properties defined on the command line
+cannot be overridden by nested <code>&lt;property&gt;</code> elements.</p>
+
+<p>References to data types can also be passed to the new project, but
+by default they are not.  If you set the inheritrefs attribute to
+true, all references will be copied, but they will not override
+references defined in the new project.</p>
+
+<p>Nested <a href="#reference"><i><code>&lt;reference&gt;</code></i></a> elements
+can also be used to copy references from the calling project to the
+new project, optionally under a different id.  References taken from
+nested elements will override existing references that have been
+defined outside of targets in the new project - but not those defined
+inside of targets.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">antfile</td>
+    <td valign="top">the buildfile to use. Defaults to
+      &quot;build.xml&quot;.  This file is expected to be a filename
+      relative to the dir attribute given.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+         <td valign="top">the directory to use as a basedir for the new Ant project.
+      Defaults to the current project's basedir, unless
+      inheritall has been set to false, in which case it doesn't
+      have a default value.  This will override the basedir
+      setting of the called project.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">the target of the new Ant project that should be executed.
+      Defaults to the new project's default target.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">Filename to write the ant output to.  This is
+    relative to the value of the dir attribute if it has been set or
+    to the base directory of the current project otherwise.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inheritAll</td>
+    <td valign="top">If <code>true</code>, pass all properties to the
+      new Ant project.  Defaults to <code>true</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inheritRefs</td>
+    <td valign="top">If <code>true</code>, pass all references to the
+      new Ant project.  Defaults to <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>property</h4>
+<p>See the description of the <a href="property.html">property
+task</a>. <br>
+These properties become equivalent to properties you define on
+the command line. These are special properties and they will always get passed
+down, even through additional <code>&lt;*ant*&gt;</code> tasks with inheritall set to
+false (see above). <br>
+Note that the <code>refid</code> attribute points to a
+reference in the calling project, not in the new one.</p>
+
+<h4><a name="reference">reference</a></h4>
+<p>Used to choose references that shall be copied into the new project,
+optionally changing their id.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">The id of the reference in the calling project.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">torefid</td>
+    <td valign="top">The id of the reference in the new project.</td>
+    <td valign="top" align="center">No, defaults to the value of refid.</td>
+  </tr>
+</table>
+
+<h4>propertyset</h4>
+
+<p>You can specify a set of properties to be copied into the new
+project with <a
+href="../CoreTypes/propertyset.html">propertyset</a>s.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>target</h4>
+
+<p>You can specify multiple targets using nested <code>&lt;target&gt;</code> elements
+instead of using the target attribute.  These will be executed as if
+Ant had been invoked with a single target whose dependencies are the
+targets so specified, in the order specified.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the called target.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<p><em>since Ant 1.6.3</em>.</p>
+
+<h3>Basedir of the new project</h3>
+
+<p>The basedir value of the new project is affected by the two
+attributes dir and inheritall, see the following table for
+details:</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>dir attribute</b></td>
+    <td valign="top"><b>inheritAll attribute</b></td>
+    <td valign="top"><b>new project's basedir</b></td>
+  </tr>
+  <tr>
+    <td valign="top">value provided</td>
+    <td valign="top">true</td>
+    <td valign="top">value of dir attribute</td>
+  </tr>
+  <tr>
+    <td valign="top">value provided</td>
+    <td valign="top">false</td>
+    <td valign="top">value of dir attribute</td>
+  </tr>
+  <tr>
+    <td valign="top">omitted</td>
+    <td valign="top">true</td>
+    <td valign="top">basedir of calling project (the one whose build
+        file contains the <code>&lt;ant&gt;</code> task).</td>
+  </tr>
+  <tr>
+    <td valign="top">omitted</td>
+    <td valign="top">false</td>
+    <td valign="top">basedir attribute of the <code>&lt;project&gt;</code> element
+        of the new project</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;ant antfile=&quot;subproject/subbuild.xml&quot; target=&quot;compile&quot;/&gt;
+
+&lt;ant dir=&quot;subproject&quot;/&gt;
+
+&lt;ant antfile=&quot;subproject/property_based_subbuild.xml&quot;&gt;
+  &lt;property name=&quot;param1&quot; value=&quot;version 1.x&quot;/&gt;
+  &lt;property file=&quot;config/subproject/default.properties&quot;/&gt;
+&lt;/ant&gt;
+
+&lt;ant inheritAll=&quot;false&quot; antfile=&quot;subproject/subbuild.xml&quot;&gt;
+  &lt;property name=&quot;output.type&quot; value=&quot;html&quot;/&gt;
+&lt;/ant&gt;
+</pre></blockquote>
+
+<p>These lines invoke the same build file:</p>
+<blockquote><pre>
+&lt;ant antfile=&quot;sub1/sub2/build.xml&quot; /&gt;
+&lt;ant antfile=&quot;sub2/build.xml&quot; dir=&quot;sub1&quot; /&gt;
+&lt;ant antfile=&quot;build.xml&quot; dir=&quot;sub1/sub2&quot; /&gt;
+</pre></blockquote>
+
+<p>The build file of the calling project defines some
+<code>&lt;path&gt;</code> elements like this:</p>
+
+<blockquote><pre>
+&lt;path id="path1"&gt;
+    ...
+&lt;/path&gt;
+&lt;path id="path2"&gt;
+    ...
+&lt;/path&gt;
+</pre></blockquote>
+
+<p>and the called build file (<code>subbuild.xml</code>) also defines
+a <code>&lt;path&gt;</code> with the id <code>path1</code>, but
+<code>path2</code> is not defined:</p>
+
+<blockquote><pre>
+&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;true&quot;/&gt;
+</pre></blockquote>
+
+<p>will not override <code>subbuild</code>'s definition of
+<code>path1</code>, but make the parent's definition of
+<code>path2</code> available in the subbuild.</p>
+
+<blockquote><pre>
+&lt;ant antfile=&quot;subbuild.xml&quot;/&gt;
+</pre></blockquote>
+
+<p>as well as</p>
+
+<blockquote><pre>
+&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot;/&gt;
+</pre></blockquote>
+
+<p>will neither override <code>path1</code> nor copy
+<code>path2</code>.</p>
+
+<blockquote><pre>
+&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot;&gt;
+  &lt;reference refid=&quot;path1&quot;/&gt;
+&lt;/ant&gt;
+</pre></blockquote>
+
+<p>will override <code>subbuild</code>'s definition of
+<code>path1</code>.</p>
+
+<blockquote><pre>
+&lt;ant antfile=&quot;subbuild.xml&quot; inheritrefs=&quot;false&quot;&gt;
+  &lt;reference refid=&quot;path1&quot; torefid=&quot;path2&quot;/&gt;
+&lt;/ant&gt;
+</pre></blockquote>
+
+<p>will copy the parent's definition of <code>path1</code> into the
+new project using the id <code>path2</code>.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/antcall.html b/trunk/docs/manual/CoreTasks/antcall.html
new file mode 100644
index 0000000..12fe330
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/antcall.html
@@ -0,0 +1,191 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>AntCall Task</title>
+</head>
+
+<body>
+
+<h2><a name="antcall">AntCall</a></h2>
+<h3>Description</h3>
+
+<p>Call another target within the same buildfile optionally
+specifying some properties (params in this context).  <strong>This
+task must not be used outside of a <code>target</code>.</strong></p>
+
+<p>By default, all of the properties of the current project will be
+available in the new project.   Alternatively, you can
+set the <i>inheritAll</i> attribute to <code>false</code> and only
+&quot;user&quot; properties (i.e., those passed on the command-line)
+will be passed to the new project.  In either case, the set of
+properties passed to the new project will override the properties that
+are set in the new project (See also the <a href="property.html">property task</a>).</p>
+<p>You can also set properties in the new project from the old project
+by using nested param tags. These properties are always passed
+to the new project and any project created in that project
+regardless of the setting of <i>inheritAll</i>.  This allows you to
+parameterize your subprojects.  Properties defined on the command line
+can not be overridden by nested <code>&lt;param&gt;</code> elements.</p>
+
+<p>Nested <a href="#reference"><i><code>&lt;reference&gt</code>;</i></a> elements can
+be used to copy references from the calling project to the new
+project, optionally under a different id.  References taken from
+nested elements will override existing references that have been
+defined outside of targets in the new project - but not those defined
+inside of targets.</p>
+
+<p>
+When a target is invoked by antcall, all of its dependent targets will
+also be called within the context of any new parameters. For example. if
+the target &quot;doSomethingElse&quot; depended on the target &quot;init&quot;, then the
+<i>antcall</i> of &quot;doSomethingElse&quot; will call &quot;init&quot; during the call.
+Of course, any properties defined in the antcall task or inherited from the calling target
+will be fixed and not overridable in the init task--or indeed in the &quot;doSomethingElse&quot; task.
+</p>
+
+<p>If the build file changes after you've started the build, the
+behavior of this task is undefined.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">The target to execute.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">inheritAll</td>
+    <td valign="top">If <code>true</code>, pass all properties to the new Ant
+    project.  Defaults to <code>true</code>.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inheritRefs</td>
+    <td valign="top">If <code>true</code>, pass all references to the
+      new Ant project.  Defaults to <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Note on <code>inheritRefs</code></h3>
+
+<p><code>&lt;antcall&gt;</code> will not override existing references,
+even if you set <code>inheritRefs</code> to true.  As the called build
+files is the same build file as the calling one, this means it will
+not override any reference set via an <code>id</code> attribute at
+all.  The only references that can be inherited by the child project
+are those defined by nested <code>&lt;reference&gt;</code> elements or
+references defined by tasks directly (not using the <code>id</code>
+attribute).</p>
+
+<h3>Parameters specified as nested elements</h3>
+<h4>param</h4>
+<p>Specifies the properties to set before running the specified target. See <a
+href="property.html">property</a> for usage guidelines.<br>
+These properties become equivalent to properties you define on
+the command line. These are special properties and they will always get passed
+down, even through additional <code>&lt;*ant*&gt;</code> tasks with inheritall set to
+false (see above).
+</p>
+
+<h4><a name="reference">reference</a></h4>
+<p>Used to choose references that shall be copied into the new project,
+optionally changing their id.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">The id of the reference in the calling project.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">torefid</td>
+    <td valign="top">The id of the reference in the new project.</td>
+    <td valign="top" align="center">No, defaults to the value of refid.</td>
+  </tr>
+</table>
+
+<h4>propertyset</h4>
+
+<p>You can specify a set of properties to be copied into the new
+project with <a
+href="../CoreTypes/propertyset.html">propertyset</a>s.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>target</h4>
+
+<p>You can specify multiple targets using nested <code>&lt;target&gt;</code> elements
+instead of using the target attribute.  These will be executed as if
+Ant had been invoked with a single target whose dependencies are the
+targets so specified, in the order specified.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the called target.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<p><em>since Ant 1.6.3</em>.</p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;target name=&quot;default&quot;&gt;
+  &lt;antcall target=&quot;doSomethingElse&quot;&gt;
+    &lt;param name=&quot;param1&quot; value=&quot;value&quot;/&gt;
+  &lt;/antcall&gt;
+&lt;/target&gt;
+
+&lt;target name=&quot;doSomethingElse&quot;&gt;
+  &lt;echo message=&quot;param1=${param1}&quot;/&gt;
+&lt;/target&gt;
+</pre></blockquote>
+<p>Will run the target 'doSomethingElse' and echo 'param1=value'.</p>
+
+<blockquote><pre>
+&lt;antcall ... &gt;
+  &lt;reference refid=&quot;path1&quot; torefid=&quot;path2&quot;/&gt;
+&lt;/antcall&gt;
+</pre></blockquote>
+
+<p>will copy the parent's definition of <code>path1</code> into the
+new project using the id <code>path2</code>.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/antstructure.html b/trunk/docs/manual/CoreTasks/antstructure.html
new file mode 100644
index 0000000..252cb24
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/antstructure.html
@@ -0,0 +1,100 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>AntStructure Task</title>
+</head>
+
+<body>
+
+<h2><a name="antstructure">AntStructure</a></h2>
+<h3>Description</h3> 
+
+<p>Generates an DTD for Ant buildfiles which contains information
+about all tasks currently known to Ant.</p>
+
+<p>Actually the DTD will not be a real DTD for buildfiles since Ant's
+usage of XML cannot be captured with a DTD.  Several elements in Ant
+can have different attribute lists depending on the element that
+contains them.  &quot;fail&quot; for example can be <a
+href="fail.html">the task</a> or the nested child element of the <a
+href="../OptionalTasks/sound.html">sound</a> task.  Don't consider the
+generated DTD something to rely upon.</p>
+
+<p>Also note that the DTD generated by this task is incomplete, you can
+always add XML entities using <a
+href="taskdef.html"><code>&lt;taskdef&gt;</code></a> or <a
+href="typedef.html"><code>&lt;typedef&gt;</code></a>. See <a
+href="http://www.sdv.fr/pages/casa/html/ant-dtd.en.html"
+target="_top">here</a> for a way to get around this problem.</p>
+<p>This task doesn't know about required attributes, all will be
+listed as <code>#IMPLIED</code>.</p>
+
+<p><em>Since Ant 1.7</em> custom structure printers can be used
+instead of the one that emits a DTD.  In order to plug in your own
+structure, you have to implement the interface
+<code>org.apache.tools.ant.taskdefs.AntStructure.StructurePrinter</code>
+and <code>&lt;typedef&gt; your class and use the new type as a nested
+element of this task - see the example below.</code>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">file to write the DTD to.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;antstructure output=&quot;project.dtd&quot; /&gt;
+</pre></blockquote>
+
+<p><b>Emitting your own structure instead of a DTD</b></p>
+
+<p>First you need to implement the interface</p>
+
+<pre>
+package org.example;
+import org.apache.tools.ant.taskdefs.AntStructure;
+public class MyPrinter implements AntStructure.StructurePrinter {
+    ...
+}
+</pre>
+
+<p>and then use it via typedef</p>
+
+<pre>
+  &lt;typedef name="myprinter" classname="org.example.MyPrinter" /&gt;
+  &lt;antstructure output="project.my"&gt;
+    &lt;myprinter /&gt;
+  &lt;/antstructure&gt;
+</pre>
+
+<p>Your own StructurePrinter can accept attributes and nested elements
+just like any other Ant type or task.</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/antversion.html b/trunk/docs/manual/CoreTasks/antversion.html
new file mode 100644
index 0000000..bc46cd1
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/antversion.html
@@ -0,0 +1,95 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Antversion Task</title>
+</head>
+
+<body>
+
+<h2><a name="antversion">Antversion</a></h2>
+<h3>Description</h3>
+<p>
+Stores the Ant version (when used as task) or checks for a specific Ant version 
+(when used as condition).
+<b>Since Ant 1.7.0</b>
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required (Task)</b></td>
+    <td align="center" valign="top"><b>Required (Condition)</b></td>
+  </tr>
+  <tr>
+    <td valign="top">atleast</td>
+    <td valign="top">The version that this at least.
+      The format is major.minor.point.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" rowspan="2" align="center">One of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">exactly</td>
+    <td valign="top">The version that this ant is exactly.
+      The format is <tt>major.minor.point</tt>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center">No (ignored)</td>
+  </tr>
+</table>
+
+
+<h3>Examples</h3>
+
+<blockquote><pre>
+&lt;antversion property=&quot;antversion&quot;/&gt;
+</pre></blockquote>
+<p>Stores the current Ant version in the property <i>antversion</i>.</p>
+
+<blockquote><pre>
+&lt;antversion property=&quot;antversion&quot; atleast=&quot;1.6&quot;/&gt;
+</pre></blockquote>
+<p>Stores the Ant version in the property <i>antversion</i> if the current Ant version is 1.6.0
+or higher. Otherwise the property remains unset.</p>
+
+<blockquote><pre>
+&lt;antversion property=&quot;ant-is-exact-7&quot; exactly=&quot;1.7.0&quot;/&gt;
+</pre></blockquote>
+<p>Sets the property <i>ant-is-exact-7</i> if Ant 1.7.0 is running. Neither 1.6.5 nor 1.7.0
+would match.</p>
+
+<blockquote><pre>
+&lt;condition property=&quot;Ant17isOnline&quot;&gt;
+  &lt;and&gt;
+    &lt;antversion exactly=&quot;1.7.0&quot;/&gt;
+    &lt;http url=&quot;http://ant.apache.org&quot;/&gt;
+  &lt;/and&gt;
+&lt;/condition&gt;
+</pre></blockquote>
+<p>Sets <i>Ant17isOnline</i> if Ant 1.7.0 is running and can get a non-error-response from
+the Ant homepage.</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/apply.html b/trunk/docs/manual/CoreTasks/apply.html
new file mode 100644
index 0000000..9954950
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/apply.html
@@ -0,0 +1,449 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>Apply Task</title>
+</head>
+
+<body>
+
+<h2><a name="apply">Apply/<i>ExecOn</i></a></h2>
+<p><i>The name <code>execon</code> is deprecated and only kept for backwards
+compatibility.</i></p>
+<h3>Description</h3>
+<p>Executes a system command. When the <i>os</i> attribute is specified, then
+the command is only executed when Ant is run on one of the specified operating
+systems.</p>
+
+<p>The files and/or directories of a number of <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s
+&ndash; including but not restricted to
+ <a href="../CoreTypes/fileset.html">FileSet</a>s,
+ <a href="../CoreTypes/dirset.html">DirSet</a>s
+ (<em>since&nbsp;Ant&nbsp;1.6</em>) or
+ <a href="../CoreTypes/filelist.html">FileList</a>s
+ (<em>since&nbsp;Ant&nbsp;1.6</em>)
+&ndash;
+ are passed as arguments to the system command.</p>
+<p>If you specify a nested <a href="../CoreTypes/mapper.html">mapper</a>,
+the timestamp of each source file is compared to the timestamp of a
+target file which is defined by the nested mapper element and searched
+for in the given <i>dest</i>, if specified.</p>
+<p>At least one fileset or filelist is required,
+and you must not specify more than one mapper.</p>
+
+<p>Note that you cannot interact with the forked program, the only way
+to send input to it is via the input and inputstring attributes.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">executable</td>
+    <td valign="top">the command to execute without any command line
+      arguments.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the directory where the command is expected to place
+    target files when it is executed. This attribute is valid only when used
+    in conjunction with a nested mapper; if omitted, the target filenames
+    returned by the mapper will be interpreted as absolute paths.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">spawn</td>
+    <td valign="top">whether or not you want the commands to be spawned.<br>
+    If you spawn a command, its output will not be logged by ant.<br>
+    The input, output, error, and result property settings are not active when spawning a process.<br>
+    <em>since&nbsp;Ant&nbsp;1.6</em>
+    </td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the directory in which the command should be executed.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">relative</td>
+    <td valign="top">whether the filenames should be passed on the
+      command line as relative pathnames (relative to the base directory
+      of the corresponding fileset/list for source files or the
+      <i>dest</i> attribute for target files).</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">forwardslash</td>
+    <td valign="top">whether the file names should be passed
+      with forward slashes even if the operating system requires other
+      file separator. The option is ignored if the system file separator
+      is a forward slash.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">os</td>
+    <td valign="top">list of Operating Systems on which the command may be
+      executed.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">osfamily</td>
+    <td valign="top">OS family as used in the &lt;os&gt; condition.
+    <em>since Ant 1.7</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">the file to which the output of the command
+    should be redirected.  If the error stream is not also redirected
+    to a file or property, it will appear in this output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">error</td>
+    <td valign="top">The file to which the standard error of the
+    command should be redirected.  <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">logError</td>
+    <td valign="top">This attribute is used when you wish to see error
+    output in Ant's log and you are redirecting output to a
+    file/property. The error output will not be included in the output
+    file/property. If you redirect error with the &quot;error&quot; or
+    &quot;errorProperty&quot; attributes, this will have no effect.
+    <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">whether output should be appended to or overwrite
+      an existing file.  If you set parallel to false, you will probably
+      want to set this one to true.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">outputproperty</td>
+    <td valign="top">the name of a property in which the output of the
+    command should be stored.  Unless the error stream is redirected
+    to a separate file or stream, this property will include the error
+    output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property in which the standard error of the
+      command should be stored.  <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">input</td>
+    <td valign="top">A file from which the executed command's standard
+    input is taken. This attribute is mutually exclusive with the
+    inputstring attribute.  <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inputstring</td>
+    <td valign="top">A string which serves as the input stream for the
+    executed command. This attribute is mutually exclusive with the
+    input attribute.  <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">resultproperty</td>
+    <td valign="top">the name of a property in which the return code
+      of the command should be stored. Only of interest if
+      failonerror=false. If you set parallel to false, only the result
+      of the first execution will be stored.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Stop the command if it doesn't finish within the
+      specified time (given in milliseconds).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the buildprocess if the command exits with a
+      returncode other than 0.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failifexecutionfails</td>
+    <td valign="top">Stop the build if we can't start the program.
+      Defaults to true. </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">skipemptyfilesets</td>
+    <td valign="top">Don't run the command, if no source files have
+      been found or are newer than their corresponding target
+      files.  Despite its name, this attribute applies to filelists as
+      well.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">parallel</td>
+    <td valign="top">Run the command only once, appending all files as
+      arguments. If false, command will be executed once for every file.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">One of <i>file</i>, <i>dir</i> or
+      <i>both</i>. If set to <i>file</i>, only the names of plain
+      files will be sent to the command. If set to <i>dir</i>, only
+      the names of directories are considered.<br>
+      <strong>Note:</strong> The type attribute does not apply to
+      nested <i>dirset</i>s - <i>dirset</i>s always implicitly
+      assume type to be <i>dir</i>.</td>
+    <td align="center" valign="top">No, default is <i>file</i></td>
+  </tr>
+  <tr>
+    <td valign="top">newenvironment</td>
+    <td valign="top">Do not propagate old environment when new environment
+      variables are specified.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">vmlauncher</td>
+    <td valign="top">Run command using the Java VM's execution facilities
+        where available. If set to false the underlying OS's shell,
+        either directly or through the antRun scripts, will be used.
+        Under some operating systems, this gives access to facilities
+        not normally available through the VM including, under Windows,
+        being able to execute scripts, rather than their associated
+        interpreter.  If you want to specify the name of the
+        executable as a relative path to the directory given by the
+        dir attribute, it may become necessary to set vmlauncher to
+        false as well.</td>
+    <td align="center" valign="top">No, default is <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">resolveExecutable</td>
+    <td valign="top">When this attribute is true, the name of the
+    executable if resolved firstly against the project basedir and if
+    that does not exist, against the execution directory if
+    specified. On Unix systems, if you only want to allow execution of
+    commands in the user's path, set this to false.
+    <em>since&nbsp;Ant&nbsp;1.6</em></td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">maxparallel</td>
+    <td valign="top">Limit the amount of parallelism by passing at
+      most this many sourcefiles at once.  Set it to &lt;= 0 for
+      unlimited. <em>Since&nbsp;Ant&nbsp;1.6.</em></td>
+    <td align="center" valign="top">No, unlimited by default</td>
+  </tr>
+  <tr>
+    <td valign="top">addsourcefile</td>
+    <td valign="top">Whether source file names should be added to the
+      command automatically. <em>Since&nbsp;Ant&nbsp;1.6.</em></td>
+    <td align="center" valign="top">No, default is <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to print a summary after execution or not.
+      <em>Since&nbsp;Ant&nbsp;1.6.</em></td>
+    <td align="center" valign="top">No, default <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">ignoremissing</td>
+    <td valign="top">Whether to ignore nonexistent files specified
+      via filelists.  <em>Since&nbsp;Ant&nbsp;1.6.2.</em></td>
+    <td align="center" valign="top">No, default is <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">force</td>
+    <td valign="top">Whether to bypass timestamp comparisons
+      for target files.  <em>Since&nbsp;Ant&nbsp;1.6.3.</em></td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>fileset</h4>
+<p>You can use any number of nested <code>&lt;fileset&gt;</code>
+elements to define the files for this task and refer to
+<code>&lt;fileset&gt;</code>s defined elsewhere.</p>
+<h4>filelist</h4>
+<p><em>Since&nbsp;Ant&nbsp;1.6</em></p>
+<p>You can use any number of nested <code>&lt;filelist&gt;</code>
+elements to define the files for this task and refer to
+<code>&lt;filelist&gt;</code>s defined elsewhere.</p>
+<h4>dirset</h4>
+<p><em>Since&nbsp;Ant&nbsp;1.6</em></p>
+<p>You can use any number of nested <code>&lt;dirset&gt;</code>
+elements to define the directories for this task and refer to
+<code>&lt;dirset&gt;</code>s defined elsewhere.</p>
+
+<h4>Any other <a href="../CoreTypes/resources.html#collection">Resource
+Collection</a></h4>
+<p><em>since Ant 1.7</em></p>
+<p>You can use any number of nested resource collections.</p>
+
+<h4>mapper</h4>
+<p>A single <code>&lt;mapper&gt;</code> specifies the target files relative
+to the <code>dest</code> attribute for dependency checking. If the
+<code>dest</code> attribute is specified it will be used as a base directory
+for resolving relative pathnames returned by the mapper. At least one
+<code>&lt;fileset&gt;</code> or <code>&lt;filelist&gt;</code> is required.</p>
+<h4>arg</h4>
+<p>Command line arguments should be specified as nested
+<code>&lt;arg&gt;</code> elements. See <a
+href="../using.html#arg">Command line arguments</a>.</p>
+<h4>srcfile</h4>
+<p>By default the file names of the source files will be added to the
+end of the command line (unless you set addsourcefile to
+<code>false</code>). If you need to place it somewhere different,
+use a nested <code>&lt;srcfile&gt;</code> element between your
+<code>&lt;arg&gt;</code> elements to mark the insertion point.</p>
+<h4>targetfile</h4>
+<p><code>&lt;targetfile&gt;</code> is similar to
+<code>&lt;srcfile&gt;</code> and marks the position of the target
+filename on the command line. If omitted, the target filenames will
+not be added to the command line at all. This element can only be
+specified if you also define a nested mapper.</p>
+<h4>env</h4>
+<p>It is possible to specify environment variables to pass to the
+system command via nested <code>&lt;env&gt;</code> elements. See the
+description in the section about <a href="exec.html#env">exec</a></p>
+<h4>redirector</h4>
+<i><b>Since&nbsp;Ant&nbsp;1.6.2</b></i>
+<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
+can be specified.  &lt;apply&gt;'s behavior is like that of
+<a href="exec.html#redirector">exec</a> with regard to
+redirectors, with the exception that, in non-<i>parallel</i> mode,
+file mapping will take place with each iteration.  This grants the
+user the capacity to receive input from, and send output to, different
+files for each sourcefile.
+</p>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;apply executable=&quot;ls&quot;&gt;
+  &lt;arg value=&quot;-l&quot;/&gt;
+  &lt;fileset dir=&quot;/tmp&quot;&gt;
+    &lt;patternset&gt;
+      &lt;exclude name=&quot;**/*.txt&quot;/&gt;
+    &lt;/patternset&gt;
+  &lt;/fileset&gt;
+  &lt;fileset refid=&quot;other.files&quot;/&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+<p>invokes <code>ls -l</code>, adding the absolute filenames of all
+files below <code>/tmp</code> not ending in <code>.txt</code> and all
+files of the FileSet with <code>id</code> <code>other.files</code> to
+the command line.</p>
+<blockquote><pre>
+&lt;apply executable=&quot;somecommand&quot; parallel=&quot;false&quot;&gt;
+  &lt;arg value=&quot;arg1&quot;/&gt;
+  &lt;srcfile/&gt;
+  &lt;arg value=&quot;arg2&quot;/&gt;
+  &lt;fileset dir=&quot;/tmp&quot;/&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+<p>invokes <code>somecommand arg1 SOURCEFILENAME arg2</code> for each
+file in <code>/tmp</code> replacing SOURCEFILENAME with the absolute
+filename of each file in turn. If <code>parallel</code> had been set
+to true, SOURCEFILENAME would be replaced with the absolute filenames
+of all files separated by spaces.</p>
+<blockquote><pre>
+&lt;apply executable=&quot;cc&quot; dest=&quot;src/C&quot; parallel=&quot;false&quot;&gt;
+  &lt;arg value=&quot;-c&quot;/&gt;
+  &lt;arg value=&quot;-o&quot;/&gt;
+  &lt;targetfile/&gt;
+  &lt;srcfile/&gt;
+  &lt;fileset dir=&quot;src/C&quot; includes=&quot;*.c&quot;/&gt;
+  &lt;mapper type=&quot;glob&quot; from=&quot;*.c&quot; to=&quot;*.o&quot;/&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+<p>invokes <code>cc -c -o TARGETFILE SOURCEFILE</code> for each
+<code>.c</code> file that is newer than the corresponding
+<code>.o</code>, replacing TARGETFILE with the absolute filename of
+the <code>.o</code> and SOURCEFILE with the absolute name of the
+<code>.c</code> file.</p>
+<blockquote><pre>
+&lt;mapper id=&quot;out&quot; type=&quot;glob&quot;
+           from=&quot;src${file.separator}*.file&quot;
+           to=&quot;dest${file.separator}*.out&quot;/&gt;
+
+&lt;apply executable=&quot;processfile&quot; dest=&quot;dest&quot;&gt;
+  &lt;fileset dir=&quot;src&quot; includes=&quot;*.file&quot;/&gt;
+  &lt;mapper refid=&quot;out&quot;/&gt;
+  &lt;redirector&gt;
+    &lt;outputmapper refid=&quot;out&quot;/&gt;
+  &lt;/redirector&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+Applies the fictitious &quot;processfile&quot; executable to all
+files matching <code>*.file</code> in the <code>src</code> directory.
+The <code>out</code> <code>&lt;mapper&gt;</code> has been set up to map
+<code>*.file</code> to <code>*.out</code>, then this <code>&lt;mapper&gt;</code>
+is used to specify <code>targetfile</code>s for this &lt;apply&gt;
+task.  A reference to <code>out</code> is then used as an
+<code>&lt;outputmapper&gt;</code> nested in a <code>&lt;redirector&gt;</code>, which in turn is
+nested beneath this <code>&lt;apply&gt;</code> instance.  This allows us to perform
+dependency checking against output files--the target files in this case.
+<blockquote><pre>
+&lt;apply executable="ls" parallel="true"
+       force="true" dest="${basedir}" append="true" type="both"&gt;
+  &lt;path&gt;
+    &lt;pathelement path="${env.PATH}"/&gt;
+  &lt;/path&gt;
+  &lt;identitymapper/&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+Applies the "ls" executable to all directories in the PATH, effectively
+listing all executables that are available on the PATH.
+
+<blockquote><pre>
+&lt;apply executable="jsmin" addsourcefile="false"&gt;
+    &lt;!-- Collect the JS-files --&gt;
+    &lt;fileset dir="src" includes="*.js"/&gt;
+    &lt;redirector&gt;
+        &lt;!-- redirect STDIN; fileset collects relative to its dir, but we need --&gt;
+        &lt;!-- relative to basedir --&gt;
+        &lt;inputmapper type="glob" from="*" to="src/*"/&gt;
+        &lt;!-- redirect STDOUT to file in dest-dir --&gt;
+        &lt;outputmapper id="out" type="glob" from="*.js" to="dest/*.js"/&gt;
+    &lt;/redirector&gt;
+&lt;/apply&gt;
+</pre></blockquote>
+Conversion of the command <code>jsmin &lt; src/a.js &gt; dest/a.js</code> but for
+all files in the src-directory. Because the filename itself should not be passed
+to the <code>jsmin</code> program, the <code>addsourcefile</code> is set to
+<code>false</code>.
+
+
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/apt.html b/trunk/docs/manual/CoreTasks/apt.html
new file mode 100644
index 0000000..b53ca98
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/apt.html
@@ -0,0 +1,183 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html lang="en-us"><head>
+<meta http-equiv="Content-Language" content="en-us"><link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Apt Task</title></head>
+
+<body>
+
+<h2><a name="Apt">Apt</a></h2>
+<h3>Description</h3>
+<p>Runs the annotation processor tool (apt), and then optionally compiles
+   the original code, and any generated source code. This task requires Java 1.5.
+   It may work on later versions, but this cannot be confirmed until those
+   versions ship. Be advised that the Apt tool does appear to be an unstable
+   part of the JDK framework, so may change radically in future versions. 
+   In particular it is likely to be obsolete in JDK 6, which can run annotation
+   processors as part of javac.
+   If the &lt;apt&gt; task does break when upgrading JVM, please
+   check to see if there is a more recent version of Ant that tracks
+   any changes.</p>
+
+
+<p>This task inherits from the <a href="javac.html">Javac Task</a>, and thus
+   supports nearly all of the same attributes, and subelements.  
+   There is one special case, the <tt>fork</tt> attribute, which is present
+   but which can only be set to <tt>true</tt>. That is, apt only works as
+   a forked process.
+ </p>
+ <p>
+   In addition, it supports
+   the following addition items:</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tbody><tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">compile</td>
+    <td valign="top">After running the Apt, should the code be compiled.  (see the
+                     <code>-nocompile</code> flag on the Apt executable)</td>
+    <td align="center" valign="top">No, defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">factory</td>
+    <td valign="top">The fully qualified classname of the AnnotationProcessFactory to be used
+                     to construct annotation processors.  This represents the <code>-factory</code>
+                     command line flag of the Apt executable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">factorypathref</td>
+    <td valign="top">The reference id of the path used to find the classes needed by the
+                     AnnotationProcessorFactory (and the location of the factory itself).
+                     This represents the <code>-factorypath</code> flag on the Apt executable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">preprocessdir</td>
+    <td valign="top">The directory used for preprocessing.  This is the directory where the
+                     generated source code will be place.  This represents the <code>-s</code> flag on
+                     the Apt executable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</tbody></table>
+
+<h3>Parameters specified as nested elements</h3>
+
+
+<h4>factorypath</h4>
+
+<p>You can specify the path used to find the classes needed by the AnnotationProcessorFactory
+   at runtime, using this element.  It is represents as a generic path like structure.  This
+   represents the <code>-factorypath</code> flag on the Apt executable.</p>
+
+
+<h4>option</h4>
+
+<p>Used to represent a generic option to pass to Apt.  This represents the <code>-A</code> flag on the
+   Apt executable.  You can specify zero or more <code>&lt;option&gt;</code> elements.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tbody><tr>
+  <td valign="top" width="12%"><b>Attribute</b></td>
+  <td valign="top" width="78%"><b>Description</b></td>
+  <td valign="top" width="10%"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td align="center">The name of the option</td>
+    <td align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td align="center">The value to set the option to</td>
+    <td align="center">Yes.</td>
+  </tr>
+</tbody></table>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;apt srcdir="${src}"
+     destdir="${build}"
+     classpath="xyz.jar"
+     debug="on"
+     compile="true"
+     factory="com.mycom.MyAnnotationProcessorFactory"
+     factorypathref="my.factorypath.id"
+     preprocessdir="${preprocess.dir}"&gt;
+&lt;/apt&gt;
+</pre></blockquote>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores
+the <code>.class</code> files in the <code>${build}</code> directory.
+The classpath used includes <code>xyz.jar</code>, and compiling with
+debug information is on.  It also forces the generated source code to
+be compiled.  The generated source code will be placed in
+<code>${preprocess.dir}</code> directory, using the class
+<code>com.mycom.MyAnnotationProcessorFactory</code> to supply
+AnnotationProcessor instances.</p>
+
+
+<h3>Notes</h3>
+
+<p>
+The inherited "fork" attribute is set to true by default; please do not change it.
+</p>
+
+<p>
+The inherited "compiler" attribute is ignored, as it is forced to use the Apt compiler
+</p>
+
+<p>Using the Apt compiler with the "compile" option set to "true"
+   forces you to use Sun's Apt compiler, which will use the JDK's Javac compiler.
+   If you wish to use another compiler, you will first need run the Apt processor
+   with the "compile" flag set to "false", and then use a
+   <code>&lt;javac&gt;</code> task to compile first your original source code, and then the
+   generated source code:</p>
+
+<blockquote><pre>
+&lt;apt srcdir="${src}"
+     destdir="${build}"
+     classpath="xyz.jar"
+     debug="true"
+     compile="false"
+     factory="com.mycom.MyAnnotationProcessorFactory"
+     factorypathref="my.factorypath.id"
+     preprocessdir="${preprocess.dir}"&gt;
+&lt;/apt&gt;
+
+&lt;javac srcdir="${src}"
+       destdir="${build}"
+       classpath="xyz.jar"
+       debug="on"/&gt;
+
+&lt;javac srcdir="${preprocess.dir}"
+       destdir="${build}"
+       classpath="xyz.jar"
+       debug="true"/&gt;
+</pre></blockquote>
+
+This may involve more build file coding, but the speedup gained from switching
+to jikes may justify the effort.
+<p>
+</p>
+
+</body></html>
diff --git a/trunk/docs/manual/CoreTasks/available.html b/trunk/docs/manual/CoreTasks/available.html
new file mode 100644
index 0000000..6e4a171
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/available.html
@@ -0,0 +1,160 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Available Task</title>
+</head>
+
+<body>
+
+<h2><a name="available">Available</a></h2>
+<h3>Description</h3>
+<p>Sets a property if a resource is available at runtime. This resource can be a
+file, a directory, a class in the classpath, or a JVM system resource.</p>
+<p>If the resource is present, the property value is set to true by
+default; otherwise, the property is not set. You can set the value to
+something other than the default by specifying the <code>value</code> attribute.</p>
+<p>Normally, this task is used to set properties that are useful to avoid target
+execution depending on system parameters.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The value to set the property to. Defaults to &quot;true&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">The class to look for in the classpath.</td>
+    <td valign="middle" align="center" rowspan="3">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to look for.</td>
+  </tr>
+  <tr>
+    <td valign="top">resource</td>
+    <td valign="top">The resource to look for in the JVM.</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use when looking up <code>classname</code> or <code>resource</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filepath</td>
+    <td valign="top">The path to use when looking up <code>file</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a <a href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">The type of <code>file</code> to look for, either a directory (<code>type=&quot;dir&quot;</code>) or a file
+      (<code>type=&quot;file&quot;</code>). If not set, the property will be set if the name specified in the <code>file</code>
+      attribute exists as either a file or a directory.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">ignoresystemclasses</td>
+    <td valign="top">Ignore Ant's runtime classes, using only the specified
+      classpath.  Only affects the "classname" attribute.  Defaults to &quot;false&quot;</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">searchparents</td>
+    <td valign="top">This contains the behaviour of the "file" type.
+      If true, the available task will, when
+      searching for a file, search not only the directories specified but
+      will also search the parent directories of those
+      specified.
+      If false, only the directories specified will be searched.
+      Defaults to "false".
+      <em>Since Ant 1.7</em>
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>classpath</h4>
+<p><code>Available</code>'s <code>classpath</code> attribute is a <a
+href="../using.html#path">path-like structure</a> and can also be set via a nested
+<code>&lt;classpath&gt;</code> element.</p>
+<h4>filepath</h4>
+<p><code>Available</code>'s <code>filepath</code> attribute is a <a
+href="../using.html#path">path-like structure</a> and can also be set via a nested
+<code>&lt;filepath&gt;</code> element.</p>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;available classname=&quot;org.whatever.Myclass&quot; property=&quot;Myclass.present&quot;/&gt;
+</pre></blockquote>
+<p>sets the <code>Myclass.present</code> property to the value &quot;true&quot;
+if the class <code>org.whatever.Myclass</code> is found in Ant's classpath.</p>
+<blockquote><pre>
+&lt;property name=&quot;jaxp.jar&quot; value=&quot;./lib/jaxp11/jaxp.jar&quot;/&gt;
+&lt;available file=&quot;${jaxp.jar}&quot; property=&quot;jaxp.jar.present&quot;/&gt;
+</pre></blockquote>
+<p>sets the <code>jaxp.jar.present</code> property to the value &quot;true&quot;
+if the file <code>./lib/jaxp11/jaxp.jar</code> is found.</p>
+<blockquote><pre>
+&lt;available file=&quot;/usr/local/lib&quot; type=&quot;dir&quot;
+           property=&quot;local.lib.present&quot;/&gt;
+</pre></blockquote>
+<p>sets the <code>local.lib.present</code> property to the value &quot;true&quot;
+if the directory <code>/usr/local/lib</code> is found.</p>
+<blockquote><pre>
+...in project ...
+&lt;property name=&quot;jaxp.jar&quot; value=&quot;./lib/jaxp11/jaxp.jar&quot;/&gt;
+&lt;path id=&quot;jaxp&quot; location=&quot;${jaxp.jar}&quot;/&gt;
+...in target ...
+&lt;available classname=&quot;javax.xml.transform.Transformer&quot;
+           classpathref=&quot;jaxp&quot; property=&quot;jaxp11.present&quot;/&gt;
+</pre></blockquote>
+<p>sets the <code>jaxp11.present</code> property to the value &quot;true&quot;
+if the class <code>javax.xml.transform.Transformer</code> is found in the classpath referenced by <code>jaxp</code> (in this case, <code>./lib/jaxp11/jaxp.jar</code>).
+</p>
+<blockquote><pre>
+&lt;available property=&quot;have.extras&quot; resource=&quot;extratasks.properties&quot;&gt;
+  &lt;classpath&gt;
+    &lt;pathelement location=&quot;/usr/local/ant/extra.jar&quot; /&gt;
+&nbsp;&nbsp;&lt;/classpath&gt;
+&lt;/available&gt;
+</pre></blockquote>
+<p>sets the <code>have.extras</code> property to the value &quot;true&quot;
+if the resource-file <code>extratasks.properties</code> is found.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/basename.html b/trunk/docs/manual/CoreTasks/basename.html
new file mode 100644
index 0000000..0822d8f
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/basename.html
@@ -0,0 +1,92 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Basename Task</title>
+</head>
+
+<body>
+
+<h2><a name="echo">Basename</a></h2>
+<h3>Description</h3>
+<p>
+Task to determine the basename of a specified file, optionally minus a
+specified suffix.
+</p>
+<p>
+When this task executes, it will set the specified property to the
+value of the last path element of the specified file. If <code>file</code> is a
+directory, the basename will be the last directory element. If
+<code>file</code> is a full-path, relative-path, or simple filename,
+the basename will be the simple file name, without any directory elements.
+</p>
+<p> 
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The path to take the basename of.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">suffix</td>
+    <td valign="top">The suffix to remove from the resulting basename
+      (specified either with or without the &quot;<code>.</code>&quot;).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;basename property=&quot;jar.filename&quot; file=&quot;${lib.jarfile}&quot;/&gt;
+</pre></blockquote>
+will set <code>jar.filename</code> to
+<code>myjar.jar</code>, if <code>lib.jarfile</code> is defined as either a
+full-path filename (eg., <code>/usr/local/lib/myjar.jar</code>),
+a relative-path filename (eg., <code>lib/myjar.jar</code>),
+or a simple filename (eg., <code>myjar.jar</code>).
+<blockquote><pre>
+&lt;basename property=&quot;cmdname&quot; file=&quot;D:/usr/local/foo.exe&quot;
+          suffix=&quot;.exe&quot;/&gt;
+</pre></blockquote>
+will set <code>cmdname</code> to <code>foo</code>.
+<blockquote><pre>
+&lt;property environment=&quot;env&quot;/&gt;
+&lt;basename property=&quot;temp.dirname&quot; file=&quot;${env.TEMP}&quot;/&gt;
+</pre></blockquote>
+
+will set <code>temp.dirname</code> to the last directory element of
+the path defined for the <code>TEMP</code> environment variable.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/buildnumber.html b/trunk/docs/manual/CoreTasks/buildnumber.html
new file mode 100644
index 0000000..8bae674
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/buildnumber.html
@@ -0,0 +1,74 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>BuildNumber Task</title>
+</head>
+
+<body>
+
+<h2><a name="buildnumber">BuildNumber</a></h2>
+<h3>Description</h3>
+<p>This is a basic task that can be used to track build numbers.</p>
+<p>It will first attempt to read a build number from a file (by default,
+<code>build.number</code> in the current directory), then
+set the property <code>build.number</code> to the value that was read in
+(or to <code>0</code>, if no such value). It will then increment the
+number by one and write it back out to the file.
+(See the
+<a href="../OptionalTasks/propertyfile.html">PropertyFile</a> task
+if you need finer control over things such as the property name or
+the number format.)
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to read and write the build number from/to.</td>
+    <td align="center" valign="top">No; defaults to &quot;build.number&quot;</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;buildnumber/&gt;
+</pre></blockquote>
+
+<p>Read, increment, and write a build number to the default file,
+<code>build.number</code>.</p>
+
+<blockquote><pre>
+&lt;buildnumber file=&quot;mybuild.number&quot;/&gt;
+</pre></blockquote>
+
+<p>Read, increment, and write a build number to the file
+<code>mybuild.number</code>.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/changelog.html b/trunk/docs/manual/CoreTasks/changelog.html
new file mode 100644
index 0000000..56a8f52
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/changelog.html
@@ -0,0 +1,244 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ChangeLog Task</title>
+</head>
+
+<body>
+
+<h2><a name="changelog">CvsChangeLog</a></h2>
+<h3>Description</h3>
+<p>Generates an XML-formatted report file of the change logs recorded in a
+<a href="http://www.nongnu.org/cvs/" target="_top">CVS</a> repository. </p>
+<p><b>Important:</b> This task needs "cvs" on the path. If it isn't, you will get
+an error (such as error 2 on windows). If <code>&lt;cvs&gt;</code> doesn't work, try to execute cvs.exe
+from the command line in the target directory in which you are working.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td colspan="3">Attributes from parent Cvs task which are meaningful here<br>
+    Since ant 1.6.1</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRoot</td>
+    <td valign="top">the <code>CVSROOT</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRsh</td>
+    <td valign="top">the <code>CVS_RSH</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">the package/module to check out.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">Port used by CVS to communicate with the server.</td>
+    <td align="center" valign="top">No, default port 2401.</td>
+  </tr>
+  <tr>
+    <td valign="top">passfile</td>
+    <td valign="top">Password file to read passwords from.</td>
+    <td align="center" valign="top">No, default file <code>~/.cvspass</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the build process if the command exits with a
+      return code other than <code>0</code>. Defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tag</td>
+    <td valign="top">query the changelog for a specific branch.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td colspan="3">Specific attributes</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The directory from which to run the CVS <em>log</em>
+     command.</td>
+    <td align="center" valign="top">No; defaults to ${basedir}.</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">The file in which to write the change log report.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">usersfile</td>
+    <td valign="top">Property file that contains name-value pairs mapping
+     user IDs and names that should be used in the report in place of
+     the user ID.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">daysinpast</td>
+    <td valign="top">Sets the number of days into the past for which the
+     change log information should be retrieved.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">start</td>
+    <td valign="top">The earliest date from which change logs are to be
+     included in the report.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">end</td>
+    <td valign="top">The latest date to which change logs are to be
+     included in the report.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<h4><a name="user">user</a></h4>
+<p>The nested <code>&lt;user&gt;</code> element allows you to specify a
+mapping between a user ID as it appears on the CVS server and a name to
+include in the formatted report.
+Anytime the specified user ID has made a change in the repository, the
+<code>&lt;author&gt;</code> tag in the report file will include
+the name specified in <code>displayname</code> rather than the user ID.
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">displayname</td>
+    <td valign="top">The name to be used in the CVS change log report.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">userid</td>
+    <td valign="top">The userid of the person as it exists on the CVS server.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+
+<h3>Examples</h3>
+<pre>  &lt;cvschangelog dir=&quot;dve/network&quot;
+                destfile=&quot;changelog.xml&quot;
+  /&gt;</pre>
+
+<p>Generates a change log report for all the changes that have been made
+under the <code>dve/network</code> directory.
+It writes these changes into the file <code>changelog.xml</code>.</p>
+
+<pre>  &lt;cvschangelog dir=&quot;dve/network&quot;
+                destfile=&quot;changelog.xml&quot;
+                daysinpast=&quot;10&quot;
+  /&gt;</pre>
+
+<p>Generates a change log report for any changes that were made
+under the <code>dve/network</code> directory in the past 10 days.
+It writes these changes into the file <code>changelog.xml</code>.</p>
+
+<pre>  &lt;cvschangelog dir=&quot;dve/network&quot;
+                destfile=&quot;changelog.xml&quot;
+                start=&quot;20 Feb 2002&quot;
+                end=&quot;20 Mar 2002&quot;
+  /&gt;</pre>
+
+<p>Generates a change log report for any changes that were made
+between February 20, 2002 and March 20, 2002
+under the <code>dve/network</code> directory.
+It writes these changes into the file <code>changelog.xml</code>.</p>
+
+<pre>  &lt;cvschangelog dir=&quot;dve/network&quot;
+                destfile=&quot;changelog.xml&quot;
+                start=&quot;20 Feb 2002&quot;
+  /&gt;</pre>
+
+<p>Generates a change log report for any changes that were made
+after February 20, 2002 under the <code>dve/network</code> directory.
+It writes these changes into the file <code>changelog.xml</code>.</p>
+
+<pre>  &lt;cvschangelog dir=&quot;dve/network&quot;
+                destfile=&quot;changelog.xml&quot;&gt;
+       &lt;user displayname=&quot;Peter Donald&quot; userid=&quot;donaldp&quot;/&gt;
+  &lt;/cvschangelog&gt;</pre>
+
+<p>Generates a change log report for all the changes that were made
+under the <code>dve/network</code> directory, substituting the name
+&quot;Peter Donald&quot; in the <code>&lt;author&gt;</code> tags
+anytime it encounters a change made by the user ID &quot;donaldp&quot;.
+It writes these changes into the file <code>changelog.xml</code>.</p>
+
+<p>Generates a change log report on the <code>ANT_16_BRANCH</code>.</p>
+<pre>
+ &lt;cvschangelog dir=&quot;c:/dev/asf/ant.head&quot; passfile=&quot;c:/home/myself/.cvspass&quot;
+                destfile=&quot;changelogant.xml&quot; tag=&quot;ANT_16_BRANCH&quot;/&gt;
+</pre>
+<h4>Generate Report</h4>
+<p>Ant includes a basic XSLT stylesheet that you can use to generate 
+a HTML report based on the xml output. The following example illustrates
+how to generate a HTML report from the XML report.</p>
+
+<pre>
+        &lt;style in="changelog.xml" 
+               out="changelog.html" 
+               style="${ant.home}/etc/changelog.xsl"&gt;
+          &lt;param name="title" expression="Ant ChangeLog"/&gt;
+          &lt;param name="module" expression="ant"/&gt;
+          &lt;param name="cvsweb" expression="http://cvs.apache.org/viewcvs/"/&gt;
+        &lt;/style&gt;
+</pre>
+
+<h4>Sample Output</h4>
+<pre>
+&lt;changelog&gt;
+  &lt;entry&gt;
+    &lt;date&gt;2002-03-06&lt;/date&gt;
+    &lt;time&gt;12:00&lt;/time&gt;
+    &lt;author&gt;Peter Donald&lt;/author&gt;
+    &lt;file&gt;
+      &lt;name&gt;org/apache/myrmidon/build/AntlibDescriptorTask.java&lt;/name&gt;
+      &lt;revision&gt;1.3&lt;/revision&gt;
+      &lt;prevrevision&gt;1.2&lt;/prevrevision&gt;
+    &lt;/file&gt;
+    &lt;msg&gt;&lt;![CDATA[Use URLs directly rather than go via a File.
+
+This allows templates to be stored inside jar]]&gt;&lt;/msg&gt;
+  &lt;/entry&gt;
+&lt;/changelog&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/checksum.html b/trunk/docs/manual/CoreTasks/checksum.html
new file mode 100644
index 0000000..ba04210
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/checksum.html
@@ -0,0 +1,261 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Checksum Task</title>
+</head>
+
+<body>
+
+<h2><a name="checksum">Checksum</a></h2>
+<h3>Description</h3>
+<p>
+Generates checksum for files.  This task can also be used to
+perform checksum verifications.
+</p>
+
+<p>Note that many popular message digest functions - including MD5 and
+SHA-1 - have been broken recently.  If you are going to use the task
+to create checksums used in an environment where security is
+important, please take some time to investigate the algorithms offered
+by your JCE provider.  Note also that some JCE providers like the one
+by <a href="http://www.bouncycastle.org/">The Legion of the Bouncy
+Castle</a>, the <a href="http://www.gnu.org/software/gnu-crypto/">GNU
+project</a> or <a
+href="http://jce.iaik.tugraz.at/products/01_jce/index.php">the
+Technical University Graz</a> offer more digest algorithms than those
+built-in into your JDK.</p>
+
+<p>
+Warning: the case of the extension is that of the algorithm used.
+If you ask for "SHA1", you get a .SHA1 extension; if you ask for "sha1", you
+get a file ending in .sha1. The Java Crypto Engines are case-insensitive
+in matching algorithms, so choose a name to match your desired output extension,
+or set the <tt>fileext</tt> attribute.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to generate checksum for.</td>
+    <td valign="top" align="center">One of either <var>file</var> or
+    at least one nested (filesystem-only) resource collection.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">The root directory where checksums should be written.</td>
+    <td valign="top" align="center">No. If not specified, checksum files
+      will be written to the same directory as the files themselves.
+      <em>since Ant 1.6</em>
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">algorithm</td>
+    <td valign="top">Specifies the algorithm to be used to
+      compute the checksum. Defaults to &quot;MD5&quot;.
+      Other popular algorithms like &quot;SHA&quot; may be used
+      as well.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">provider</td>
+    <td valign="top">Specifies the provider of the algorithm.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fileext</td>
+    <td valign="top">The generated checksum file's name will be the
+    original filename with the fileext added to it.
+    Defaults to a "." and the algorithm name being used.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">This attribute can mean two different things, it
+    depends on the presence of the verifyproperty attribute.<br>
+    <b>If you don't set the verifyproperty attribute</b>, property
+    specifies the name of the property to be set with the generated
+    checksum value.<br>
+    <b>If you set the verifyproperty attribute</b>, property specifies
+    the checksum you expect to be generated (the checksum itself, not
+    a name of a property containing the checksum).<br>
+    This cannot be specified when fileext is being used or when the
+    number of files for which checksums is to be generated is greater
+    than 1.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">Specifies the pattern to use as a pattern
+    suitable for <a
+    href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/MessageFormat.html">MessageFormat</a>
+    where <code>{0}</code> is replaced with the checksum and
+    <code>{1}</code> with the file name.</td>
+    <td valign="top" align="center">No - default is &quot;{0}&quot;.</td>
+  </tr>
+  <tr>
+    <td valign="top">format</td>
+    <td valign="top">Specifies the pattern to use as one of a
+    well-known format.  Supported values are 
+      <table border="1">
+      <tr>
+        <th>name</th>
+        <th>pattern</th>
+        <th>description</th>
+      </tr>
+      <tr>
+        <td>CHECKSUM </td>
+        <td><tt>{0}</tt></td>
+        <td>only the checksum itself </td>
+      </tr>
+      <tr>
+        <td>MD5SUM </td>
+        <td><tt>{0} *{1}</tt></td>
+        <td>the format of GNU textutils md5sum</td>
+      </tr>
+      <tr>
+        <td>SVF </td>
+        <td><tt>MD5 ({1}) = {0}</tt></td>
+        <td>the format of BSDs md5 command </td>
+      </tr>
+      </table>
+    </td>
+    <td valign="top" align="center">No - default is &quot;CHECKSUM&quot;.</td>
+  </tr>
+  <tr>
+    <td valign="top">totalproperty</td>
+    <td valign="top">If specified, this attribute specifies the name of
+      the property that will hold a checksum of all the checksums and
+      file paths. The individual checksums and the relative paths to the files
+      within the resource collections in which they are defined will be used to
+      compute this checksum. (The file separators in the paths will be
+      converted to '/' before computation to ensure platform portability).
+      <em>since Ant 1.6</em>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">forceoverwrite</td>
+    <td valign="top">Overwrite existing files even if the destination
+      files are newer. Defaults to &quot;no&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verifyproperty</td>
+    <td valign="top">Specifies the name of the property to be set
+    with &quot;true&quot; or &quot;false&quot; depending upon whether
+    the generated checksum matches the existing checksum.  When
+    this is set, the generated checksum is not written to a file or
+    property, but rather, the content of the file or property is used to
+    check against the generated checksum.
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">readbuffersize</td>
+    <td valign="top">The size of the buffer (in bytes) to use when
+    reading a file. Defaults to &quot;8192&quot; - you may get a
+    better performance on big files if you increase this value.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>resource collection</h4>
+ <p>
+ <a href="../CoreTypes/resources.html#collection">Resource collections</a> are
+ used to select files for which checksums should be generated.
+ </p>
+
+<h3>Examples</h3>
+<p><b>Example 1</b></p>
+<blockquote><pre>&lt;checksum file=&quot;foo.bar&quot;/&gt;</pre></blockquote>
+Generates a MD5 checksum for foo.bar and stores the checksum in the destination file
+foo.bar.MD5.  foo.bar.MD5 is overwritten only if foo.bar is newer than itself.
+
+<p><b>Example 2</b></p>
+<blockquote><pre>&lt;checksum file=&quot;foo.bar&quot; forceOverwrite=&quot;yes&quot;/&gt;</pre></blockquote>
+Generates a MD5 checksum for foo.bar and stores the checksum in foo.bar.MD5.
+If foo.bar.MD5 already exists, it is overwritten.
+
+<p><b>Example 3</b></p>
+<blockquote><pre>&lt;checksum file=&quot;foo.bar&quot; property=&quot;foobarMD5&quot;/&gt;</pre></blockquote>
+Generates a MD5 checksum for foo.bar and stores it in the Project Property foobarMD5.
+
+<p><b>Example 4</b></p>
+<blockquote><pre>&lt;checksum file=&quot;foo.bar&quot; verifyProperty=&quot;isMD5ok&quot;/&gt;</pre></blockquote>
+Generates a MD5 checksum for foo.bar, compares it against foo.bar.MD5 and sets
+isMD5ok to either true or false, depending upon the result.
+
+<p><b>Example 5</b></p>
+<blockquote><pre>&lt;checksum file=&quot;foo.bar&quot; algorithm=&quot;SHA&quot; fileext=&quot;asc&quot;/&gt;</pre></blockquote>
+Generates a SHA checksum for foo.bar and stores the checksum in the destination file
+foo.bar.asc.  foo.bar.asc is overwritten only if foo.bar is newer than itself.
+
+<p><b>Example 6</b></p>
+<blockquote><pre>
+&lt;checksum file=&quot;foo.bar&quot; property=&quot;${md5}&quot; verifyProperty=&quot;isEqual&quot;/&gt;
+</pre></blockquote>
+Generates a MD5 checksum for foo.bar, compares it against the value of the property
+md5, and sets isEqual to either true or false, depending upon the result.
+
+<p><b>Example 7</b></p>
+<blockquote><pre>
+&lt;checksum&gt;
+  &lt;fileset dir=&quot;.&quot;&gt;
+    &lt;include name=&quot;foo*&quot;/&gt;
+  &lt;/fileset&gt;
+&lt;/checksum&gt;
+</pre></blockquote>
+Works just like Example 1, but generates a .MD5 file for every file that begins with the name foo.
+
+<p><b>Example 8</b></p>
+<blockquote><pre>
+&lt;condition property=&quot;isChecksumEqual&quot;&gt;
+  &lt;checksum&gt;
+    &lt;fileset dir=&quot;.&quot;&gt;
+      &lt;include name=&quot;foo.bar&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;/checksum&gt;
+&lt;/condition&gt;
+</pre></blockquote>
+Works like Example 4, but only sets isChecksumEqual to true, if the
+checksum matches - it will never be set to false.  This example
+demonstrates use with the Condition task.
+
+
+<h3>Note:</h3>
+When working with more than one file, if condition and/or verifyproperty is used,
+the result will be true only if the checksums matched correctly for all files being
+considered.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/chmod.html b/trunk/docs/manual/CoreTasks/chmod.html
new file mode 100644
index 0000000..8d12c25
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/chmod.html
@@ -0,0 +1,203 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Chmod Task</title>
+</head>
+
+<body>
+
+<h2><a name="chmod">Chmod</a></h2>
+<h3>Description</h3>
+<p>Changes the permissions of a file or all files inside specified
+directories. Right now it has effect only under Unix or NonStop Kernel (Tandem).
+The permissions are also UNIX style, like the argument for the chmod command.</p>
+<p>See the section on <a href="../dirtasks.html#directorybasedtasks">directory based
+tasks</a>, on how the inclusion/exclusion of files works, and how to
+write patterns.</p>
+
+<p>This task holds an implicit <a
+href="../CoreTypes/fileset.html">FileSet</a> and supports all of
+FileSet's attributes and nested elements directly. More sets can be
+specified using nested <code>&lt;fileset&gt;</code> or
+<code>&lt;dirset&gt;</code> (<em>since Ant 1.6</em>) elements. </p>
+
+<p>Starting with Ant 1.6, this task also supports nested <a
+href="../CoreTypes/filelist.html">filelist</a>s.</p>
+
+<p>Starting with Ant 1.7, this task supports arbitrary <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s
+as nested elements.</p>
+
+<p>By default this task will use a single invocation of the underlying
+chmod command.  If you are working on a large number of files this may
+result in a command line that is too long for your operating system.
+If you encounter such problems, you should set the maxparallel
+attribute of this task to a non-zero value.  The number to use highly
+depends on the length of your file names (the depth of your directory
+tree) and your operating system, so you'll have to experiment a
+little.  POSIX recommends command line length limits of at least 4096
+characters, this may give you an approximation for the number you
+could use as initial value for these experiments.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file or single directory of which the permissions 
+      must be changed.</td>
+    <td valign="top" valign="middle" rowspan="2">exactly one of the two or nested <code>&lt;fileset/list&gt;</code> elements.</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the directory which holds the files whose permissions 
+      must be changed.</td>
+  </tr>
+  <tr>
+    <td valign="top">perm</td>
+    <td valign="top">the new permissions.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">parallel</td>
+    <td valign="top">process all specified files using a single
+      <code>chmod</code> command. Defaults to true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">One of <i>file</i>, <i>dir</i> or
+      <i>both</i>. If set to <i>file</i>, only the permissions of
+      plain files are going to be changed. If set to <i>dir</i>, only
+      the directories are considered.<br>
+      <strong>Note:</strong> The type attribute does not apply to
+      nested <i>dirset</i>s - <i>dirset</i>s always implicitly
+      assume type to be <i>dir</i>.</td>
+    <td align="center" valign="top">No, default is <i>file</i></td>
+  </tr>
+  <tr>
+    <td valign="top">maxparallel</td>
+    <td valign="top">Limit the amount of parallelism by passing at
+      most this many sourcefiles at once.  Set it to &lt;= 0 for
+      unlimited.  Defaults to unlimited.  <em>Since Ant 1.6.</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to print a summary after execution or not.
+      Defaults to <code>false</code>.  <em>Since Ant 1.6.</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+  <blockquote><pre>
+&lt;chmod file=&quot;${dist}/start.sh&quot; perm=&quot;ugo+rx&quot;/&gt;
+</pre></blockquote>
+<p>makes the &quot;start.sh&quot; file readable and executable for anyone on a
+UNIX system.</p>
+<blockquote><pre>
+&lt;chmod file=&quot;${dist}/start.sh&quot; perm=&quot;700&quot;/&gt;
+</pre></blockquote>
+<p>makes the &quot;start.sh&quot; file readable, writable and executable only for the owner on a
+UNIX system.</p>
+<blockquote>
+<pre>
+&lt;chmod dir=&quot;${dist}/bin&quot; perm=&quot;ugo+rx&quot; 
+       includes=&quot;**/*.sh&quot;/&gt;
+</pre>
+</blockquote>
+<p>makes all &quot;.sh&quot; files below <code>${dist}/bin</code>
+readable and executable for anyone on a UNIX system.</p>
+<blockquote>
+<pre>
+&lt;chmod perm=&quot;g+w&quot;&gt;
+  &lt;fileset dir=&quot;shared/sources1&quot;&gt;
+    &lt;exclude name=&quot;**/trial/**&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;fileset refid=&quot;other.shared.sources&quot;/&gt;
+&lt;/chmod&gt;
+</pre>
+</blockquote>
+<p>makes all files below <code>shared/sources1</code> (except those
+below any directory named trial) writable for members of the same
+group on a UNIX system. In addition all files belonging to a FileSet
+with <code>id</code> <code>other.shared.sources</code> get the same
+permissions.</p>
+
+<blockquote>
+<pre>
+&lt;chmod perm=&quot;go-rwx&quot; type=&quot;file&quot;&gt;
+  &lt;fileset dir=&quot;/web&quot;&gt;
+    &lt;include name=&quot;**/*.cgi&quot;/&gt;
+    &lt;include name=&quot;**/*.old&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;dirset dir=&quot;/web&quot;&gt;
+    &lt;include name=&quot;**/private_*&quot;/&gt;
+  &lt;/dirset&gt;
+&lt;/chmod&gt;
+</pre>
+</blockquote>
+
+<p>keeps non-owners from touching cgi scripts, files with a <code>.old</code>
+extension or directories beginning with <code>private_</code>. A directory 
+ending in <code>.old</code> or a file beginning with private_ would remain
+unaffected.</p>
+
+
+  <h3>Note on maxparallel attribute</h3>
+  <p>
+    Some shells have a limit of the number of characters that
+    a command line may contain. 
+    This maximum limit varies from shell to shell and from operating
+    system to operating system.
+    If one has a large number of files to change mode on, consider
+    using the <em>maxparallel</em> attribute. For example
+    when using AIX and the limit is reached, the system responds
+    with a warning: "Warning: 
+    UNIXProcess.forkAndExec native error: The parameter or environment lists
+    are too long". A value of about 300 seems to result in a
+    command line that is acceptable.
+  </p>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/common.html b/trunk/docs/manual/CoreTasks/common.html
new file mode 100644
index 0000000..6fa3418
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/common.html
@@ -0,0 +1,59 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Common</title>
+</head>
+
+<body>
+
+<h2><a name="javac">Common Attributes of all Tasks</a></h2>
+<p>All tasks share the following attributes:</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">id</td>
+    <td valign="top">Unique identifier for this task instance, can be
+       used to reference this task in scripts.</td>
+    <td valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">taskname</td>
+    <td valign="top">A different name for this task instance - will
+      show up in the logging output.</td>
+    <td valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">description</td>
+    <td valign="top">Room for your comments</td>
+    <td valign="top">No</td>
+  </tr>
+</table>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/componentdef.html b/trunk/docs/manual/CoreTasks/componentdef.html
new file mode 100644
index 0000000..b082fc1
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/componentdef.html
@@ -0,0 +1,62 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Componentdef Task</title>
+</head>
+
+<body>
+
+<h2><a name="componentdef">componentdef</a></h2>
+<h3>Description</h3>
+  <p>
+    Adds a component definination to the current project.
+    A compenent definition is the same as a
+    <a href="typedef.html">typedef</a> except:
+  </p>
+    <ol>
+      <li>
+        that it can only be used in other types or tasks that
+        accept components (by having an <i>add()</i> method).
+      </li>
+      <li>
+        multiple components may have the same name, provided them
+        implement different interfaces.
+      </li>
+    </ol>
+  <p>
+    The purpose of this it allow internal ant definitions to be
+    be made for tags like "and" or "or".
+  </p>
+
+  <h3>Examples</h3>
+
+<pre> &lt;componentdef name="or" onerror="ignore"
+    classname="com.apache.tools.ant.taskdefs.conditions.Or"/&gt;
+  &lt;componentdef name="or" onerror="ignore"
+    classname="com.apache.tools.ant.types.resources.selectors.Or"/&gt;</pre>
+  <p>
+    defines two components with the same name "or", one is a condition
+    (see <a href="conditions.html">conditions</a>) and one is 
+    a selector (see <a href="../CoreTypes/selectors.html">selectors</a>).
+  </p>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/concat.html b/trunk/docs/manual/CoreTasks/concat.html
new file mode 100644
index 0000000..9a4ab60
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/concat.html
@@ -0,0 +1,300 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+    <head>
+      <meta http-equiv="Content-Language" content="en-us">
+      <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Concat</title>
+    </head>
+
+    <body>
+
+      <h2><a name="Concat">Concat</a></h2>
+
+      <h3>Description</h3>
+
+      <p>
+        Concatenates one or more 
+        <a href="../CoreTypes/resources.html">resource</a>s
+        to a single file or to the console. The destination
+        file will be created if it does not exist.
+      </p>
+
+      <p><strong>Since Ant 1.7.1</strong>, this task can be used as a
+        <a href="../CoreTypes/resources.html#collection">Resource Collection</a>
+        that will return exactly one 
+        <a href="../CoreTypes/resources.html">resource</a>.
+      </p>
+
+      <p>
+        <a href="../CoreTypes/resources.html#collection">
+Resource Collection</a>s are used to
+        select which resources are to be concatenated. There is no
+        singular attribute to specify a single resource to cat.
+      </p>
+
+      <h3>Parameters</h3>
+
+      <table border="1" cellpadding="2" cellspacing="0">
+
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Required</b></td>
+        </tr>
+
+        <tr>
+          <td valign="top">destfile</td>
+          <td valign="top">
+            The destination file for the concatenated stream.
+        If not specified the console will be used instead.
+          </td>
+          <td valign="top" align="center">
+            No
+          </td>
+        </tr>
+
+        <tr>
+          <td valign="top">append</td>
+          <td valign="top">
+            Specifies whether or not the file specified by 'destfile'
+            should be appended. Defaults to &quot;no&quot;.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">force</td>
+          <td valign="top">
+            Specifies whether or not the file specified by 'destfile'
+            should be written to even if it is newer than all source files.
+            <em>since Ant 1.6</em>.
+            Defaults to &quot;yes&quot;.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+
+        <tr>
+          <td valign="top">encoding</td>
+          <td valign="top">
+            Specifies the encoding for the input files. Please see <a
+            href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">
+            http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>
+            for a list of possible values. Defaults to the platform's
+            default character encoding.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">outputencoding</td>
+          <td valign="top">
+            The encoding to use when writing the output file
+            <em>since Ant 1.6</em>.
+            Defaults to the value of the encoding attribute
+            if given or the default JVM encoding otherwise.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">fixlastline</td>
+          <td valign="top">
+                 Specifies whether or not to check if
+            each file concatenated is terminated by
+            a new line. If this attribute is &quot;yes&quot;
+            a new line will be appended to the stream if
+            the file did not end in a new line.
+            <em>since Ant 1.6</em>.
+            Defaults to &quot;no&quot;.
+            This attribute does not apply to embedded text.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">eol</td>
+          <td valign="top">
+            Specifies what the end of line character are
+            for use by the fixlastline attribute.
+            <em>since Ant 1.6</em>
+            Valid values for this property are:
+            <ul>
+              <li>cr: a single CR</li>
+              <li>lf: a single LF</li>
+              <li>crlf: the pair CRLF</li>
+              <li>mac: a single CR</li>
+              <li>unix: a single LF</li>
+              <li>dos: the pair CRLF</li>
+            </ul>
+            The default is platform dependent.
+            For Unix platforms, the default is &quot;lf&quot;.
+            For DOS based systems (including Windows),
+            the default is &quot;crlf&quot;.
+            For Mac OS, the default is &quot;cr&quot;.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">binary</td>
+          <td valign="top">
+            <em>since Ant 1.6.2</em>
+            If this attribute is set to true, the task concatenates the files
+            in a byte by byte fashion. If this attribute is false, concat will
+            not normally work for binary files due to character encoding
+            issues.
+            If this option is set to true, the destfile attribute must be
+            set, and the task cannot used nested text.
+            Also the attributes encoding, outputencoding, filelastline
+            cannot be used.
+            The default is false.
+          </td>
+          <td valign="top" align="center">No</td>
+        </tr>
+
+      </table>
+
+      <h3>Parameters specified as nested elements</h3>
+        <h4>Resource Collection</h4>
+        <p><em>since Ant 1.7</em>.</p>
+
+      <p>
+        Any of the various <a href="../CoreTypes/resources.html#collection">
+        Resource Collection</a> types can specify the resources to be
+        concatenated.
+      </p>
+
+      <h4>filterchain</h4>
+        <p><em>since Ant 1.6</em>.</p>
+      <p>The concat task supports nested
+        <a href="../CoreTypes/filterchain.html"> FilterChain</a>s.</p>
+
+      <h4>header, footer</h4>
+        <p><em>since Ant 1.6</em>.</p>
+      <p>Used to prepend or postpend text into the concatenated stream.</p>
+      <p>The text may be in-line or be in a file.</p>
+      <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Required</b></td>
+        </tr>
+        <tr>
+          <td valign="top">filtering</td>
+          <td valign="top">
+            Whether to filter the text provided by this sub element,
+            default is "yes".
+          <td valign="top" align = "center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">file</td>
+          <td valign="top">A file to place at the head or tail of the
+                           concatenated text.
+          <td valign="top" align = "center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">trim</td>
+          <td valign="top">Whether to trim the value, default is "no"</td>
+          <td valign="top" align = "center">No</td>
+        </tr>
+        <tr>
+          <td valign="top">trimleading</td>
+          <td valign="top">
+            Whether to trim leading white space on each line, default is "no"
+          </td>
+          <td valign="top" align = "center">No</td>
+        </tr>
+      </table>
+
+      <h3>Examples</h3>
+
+      <p><b>Concatenate a string to a file:</b></p>
+
+      <pre>
+  &lt;concat destfile=&quot;README&quot;&gt;Hello, World!&lt;/concat&gt;
+      </pre>
+
+      <p><b>Concatenate a series of files to the console:</b></p>
+
+      <pre>
+  &lt;concat&gt;
+    &lt;fileset dir=&quot;messages&quot; includes=&quot;*important*&quot;/&gt;
+  &lt;/concat&gt;
+      </pre>
+
+      <p><b>Concatenate a single file, appending if the destination file exists:</b></p>
+
+      <pre>
+  &lt;concat destfile=&quot;NOTES&quot; append=&quot;true&quot;&gt;
+    &lt;filelist dir=&quot;notes&quot; files=&quot;note.txt&quot;/&gt;
+  &lt;/concat&gt;
+      </pre>
+
+      <p><b>Concatenate a series of files, update the destination
+      file only if is older that all the source files:</b></p>
+
+      <pre>
+  &lt;concat destfile=&quot;${docbook.dir}/all-sections.xml&quot;
+          force=&quot;no&quot;&gt;
+    &lt;filelist dir=&quot;${docbook.dir}/sections&quot;
+         files=&quot;introduction.xml,overview.xml&quot;/&gt;
+    &lt;fileset dir=&quot;${docbook.dir}&quot;
+         includes=&quot;sections/*.xml&quot;
+         excludes=&quot;introduction.xml,overview.xml&quot;/&gt;
+  &lt;/concat&gt;
+      </pre>
+
+      <p><b>Concatenate a series of files, expanding ant properties</b></p>
+        <pre>
+   &lt;concat destfile="${build.dir}/subs"&gt;
+      &lt;path&gt;
+        &lt;fileset dir="${src.dir}" includes="*.xml"/&gt;
+        &lt;pathelement location="build.xml"/&gt;
+      &lt;/path&gt;
+      &lt;filterchain&gt;
+        &lt;expandproperties/&gt;
+      &lt;/filterchain&gt;
+   &lt;/concat&gt;
+        </pre>
+
+      <p><b>Filter the lines containing project from build.xml and output
+           them to report.output, prepending with a header</b></p>
+        <pre>
+   &lt;concat destfile="${build.dir}/report.output"&gt;
+      &lt;header filtering="no" trimleading="yes"&gt;
+          Lines that contain project
+          ==========================
+      &lt;/header&gt;
+      &lt;path path="build.xml"/&gt;
+      &lt;filterchain&gt;
+         &lt;linecontains&gt;
+           &lt;contains value="project"/&gt;
+         &lt;/linecontains&gt;
+      &lt;/filterchain&gt;
+   &lt;/concat&gt;
+        </pre>
+
+      <p><b>Concatenate a number of binary files.</b></p>
+        <pre>
+   &lt;concat destfile="${build.dir}/dist.bin" binary="yes"&gt;
+     &lt;fileset file="${src.dir}/scripts/dist.sh" /&gt;
+     &lt;fileset file="${build.dir}/dist.tar.bz2" /&gt;
+   &lt;/concat&gt;
+        </pre>
+
+      
+
+    </body>
+
+  </html>
diff --git a/trunk/docs/manual/CoreTasks/condition.html b/trunk/docs/manual/CoreTasks/condition.html
new file mode 100644
index 0000000..e592f6e
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/condition.html
@@ -0,0 +1,110 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Condition Task</title>
+</head>
+
+<body>
+
+<h2><a name="Condition">Condition</a></h2>
+<h3>Description</h3>
+<p>Sets a property if a certain condition holds true - this is a
+generalization of <a href="available.html">Available</a> and <a
+href="uptodate.html">Uptodate</a>.</p>
+<p>If the condition holds true, the property value is set to true by
+default; otherwise, the property is not set. You can set the value to
+something other than the default by specifying the <code>value</code>
+attribute.</p>
+<p>Conditions are specified as <a href="#nested">nested elements</a>,
+you must specify exactly one condition.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The value to set the property to. Defaults to
+      &quot;true&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">else</td>
+    <td valign="top">The value to set the property to if the condition
+      evaluates to <i>false</i>. By default the property will remain unset.
+      <em>Since Ant 1.6.3</em>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3><a name="nested">Parameters specified as nested elements</a></h3>
+<p>All conditions to test are specified as nested elements, for a
+complete list see <a href="conditions.html">here</a>.</p>
+
+<h3>Examples</h3>
+<pre>
+  &lt;condition property=&quot;javamail.complete&quot;&gt;
+    &lt;and&gt;
+      &lt;available classname=&quot;javax.activation.DataHandler&quot;/&gt;
+      &lt;available classname=&quot;javax.mail.Transport&quot;/&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>javamail.complete</code> if both the
+JavaBeans Activation Framework and JavaMail are available in the
+classpath.</p>
+
+<pre>
+  &lt;condition property=&quot;isMacOsButNotMacOsX&quot;&gt;
+    &lt;and&gt;
+      &lt;os family=&quot;mac&quot;/&gt;
+
+      &lt;not&gt;
+        &lt;os family=&quot;unix&quot;/&gt;
+
+      &lt;/not&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>isMacOsButNotMacOsX</code> if the current
+operating system is MacOS, but not MacOS X - which Ant considers to be
+in the Unix family as well.</p>
+
+<pre>
+  &lt;condition property=&quot;isSunOSonSparc&quot;&gt;
+    &lt;os name=&quot;SunOS&quot; arch=&quot;sparc&quot;/&gt;
+
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>isSunOSonSparc</code> if the current
+operating system is SunOS and if it is running on a sparc architecture.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/conditions.html b/trunk/docs/manual/CoreTasks/conditions.html
new file mode 100644
index 0000000..665f67e
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/conditions.html
@@ -0,0 +1,968 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Conditions Task</title>
+</head>
+
+<body>
+
+<h2><a name="Conditions">Conditions</a></h2>
+  <p>Conditions are nested elements of the 
+<a href="condition.html"><code>&lt;condition&gt;</code></a> and
+<a href="waitfor.html"><code>&lt;waitfor&gt;</code></a> tasks.
+    There are core conditions and custom conditions. Custom
+    conditions are described in
+    <a href="../CoreTypes/custom-programming.html#customconditions">
+      Custom Conditions</a>.
+    Core Conditions are described below.
+  </p>
+  <h3><a name="coreconditions">Core Conditions</a></h3>
+
+<p>These are the nested elements that can be used as conditions in the
+<a href="condition.html"><code>&lt;condition&gt;</code></a> and
+<a href="waitfor.html"><code>&lt;waitfor&gt;</code></a> tasks.</p>
+
+<h4>not</h4>
+<p>The <code>&lt;not&gt;</code> element expects exactly one other
+condition to be nested into this element, negating the result of the
+condition.  It doesn't have any attributes and accepts all nested
+elements of the condition task as nested elements as well.</p>
+
+<h4>and</h4> <p>
+The <code>&lt;and&gt;</code> element doesn't have any attributes and
+accepts an arbitrary number of conditions as nested elements - all
+nested elements of the condition task are supported.  This condition
+is true if all of its contained conditions are, conditions will be
+evaluated in the order they have been specified in the build file.</p>
+<p>The <code>&lt;and&gt;</code> condition has the same shortcut
+semantics as the Java &amp;&amp; operator, as soon as one of the
+nested conditions is false, no other condition will be evaluated.</p>
+
+<h4>or</h4> <p>
+The <code>&lt;or&gt;</code> element doesn't have any attributes and
+accepts an arbitrary number of conditions as nested elements - all
+nested elements of the condition task are supported.  This condition
+is true if at least one of its contained conditions is, conditions
+will be evaluated in the order they have been specified in the build
+file.</p> <p>The <code>&lt;or&gt;</code> condition has the same
+shortcut semantics as the Java || operator, as soon as one of the
+nested conditions is true, no other condition will be evaluated.</p>
+
+<h4>xor</h4>
+<p>The <code>&lt;xor&gt;</code> element performs an exclusive
+or on all nested elements, similar to the <code>^</code> operator
+in Java. It only evaluates to true if an odd number of nested conditions
+are true. There is no shortcutting of evaluation, unlike the <code>&lt;and&gt;</code>
+and <code>&lt;or&gt;</code> tests.
+It doesn't have any attributes and accepts all nested
+elements of the condition task as nested elements as well.</p>
+
+<h4>available</h4>
+<p>This condition is identical to the <a
+href="available.html">Available</a> task, all attributes and nested
+elements of that task are supported, the property and value attributes
+are redundant and will be ignored.</p>
+
+<h4>uptodate</h4>
+<p>This condition is identical to the <a
+href="uptodate.html">Uptodate</a> task, all attributes and nested
+elements of that task are supported, the property and value attributes
+are redundant and will be ignored.</p>
+
+<h4>os</h4>
+<p>Test whether the current operating system is of a given type.  Each
+defined attribute is tested and the result is true only if <i>all</i>
+the tests succeed.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">family</td>
+    <td valign="top">The name of the operating system family to expect.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the operating system to expect.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">arch</td>
+    <td valign="top">The architecture of the operating system to expect.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">version</td>
+    <td valign="top">The version of the operating system to expect.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<p>Supported values for the family attribute are:
+<ul>
+  <li>windows (for all versions of Microsoft Windows)</li>
+  <li>dos (for all Microsoft DOS based operating systems including
+    Microsoft Windows and OS/2)</li>
+  <li>mac (for all Apple Macintosh systems)</li>
+  <li>unix (for all Unix and Unix-like operating systems)</li>
+  <li>netware (for Novell NetWare)</li>
+  <li>os/2 (for OS/2)</li>
+  <li>tandem (for HP's NonStop Kernel - formerly Tandem)</li>
+  <li>win9x for Microsoft Windows 95 and 98, ME and CE</li>
+  <li>winnt for Microsoft Windows NT-based systems, including Windows 2000, XP and
+      successors</li>
+  <li>z/os for z/OS and OS/390</li>
+  <li>os/400 for OS/400</li>
+  <li>openvms for OpenVMS</li>
+</ul>
+
+<h4>equals</h4>
+<p>Tests whether the two given Strings are identical</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">arg1</td>
+    <td valign="top">First string to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">arg2</td>
+    <td valign="top">Second string to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Perform a case sensitive comparision.  Default is
+        true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">trim</td>
+    <td valign="top">Trim whitespace from arguments before comparing
+        them.  Default is false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h4>isset</h4>
+<p>Test whether a given property has been set in this project.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>checksum</h4>
+<p>This condition is identical to the <a href="checksum.html">Checksum</a>
+task, all attributes and nested elements of that task are supported,
+the property and overwrite attributes are redundant and will be
+ignored.</p>
+
+<h4>http</h4>
+<p>The <code>http</code> condition checks for a valid response from a
+web server of the specified url. By default, HTTP responses errors
+of 400 or greater are viewed as invalid.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">The full URL of the page to request. The web server must
+      return a status code below the value of <tt>errorsBeginAt</tt></td>
+    <td align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">errorsBeginAt</td>
+    <td valign="top">The lowest HTTP response code that signals an error;
+    by default '400'; server errors, not-authorized, not-found and the like
+    are detected</td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h4>socket</h4>
+<p>The <code>socket</code> condition checks for the existence of a
+TCP/IP listener at the specified host and port.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">server</td>
+    <td valign="top">The DNS name or IP address of the server.</td>
+    <td align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">The port number to connect to.</td>
+    <td align="center">Yes.</td>
+  </tr>
+</table>
+
+<h4>filesmatch</h4>
+<p>Test two files for matching. Nonexistence of one file results in "false",
+although if neither exists they are considered equal in terms of content.
+This test does a byte for byte comparision, so test time scales with
+byte size. NB: if the files are different sizes, one of them is missing
+or the filenames match the answer is so obvious the detailed test is omitted.
+
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file1</td>
+    <td valign="top">First file to test</td>
+    <td align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">file2</td>
+    <td valign="top">Second file to test</td>
+    <td align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">textfile</td>
+    <td valign="top">Whether to ignore line endings
+        when comparing files; defaults to <i>false</i>, while
+        <i>true</i> triggers a binary comparison. <b>Since Ant 1.7</b>
+    </td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h4>contains</h4>
+<p>Tests whether a string contains another one.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">string</td>
+    <td valign="top">The string to search in.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">substring</td>
+    <td valign="top">The string to search for.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Perform a case sensitive comparision.  Default is
+        true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h4>istrue</h4>
+<p>Tests whether a string equals any of the ant definitions of true,
+that is "true","yes", or "on"</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">value to test</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;istrue value=&quot;${someproperty}&quot;/&gt;
+&lt;istrue value=&quot;false&quot;/&gt;
+</pre></blockquote>
+
+<h4>isfalse</h4>
+<p>Tests whether a string is not true, the negation of &lt;istrue&gt;
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">value to test</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;isfalse value=&quot;${someproperty}&quot;/&gt;
+&lt;isfalse value=&quot;false&quot;/&gt;
+</pre></blockquote>
+
+<h4>isreference</h4>
+
+<p>Test whether a given reference has been defined in this project and
+- optionally - is of an expected type.</p>
+
+<p>This condition has been added in Apache Ant 1.6.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">The id of the reference to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">Name of the data type or task this reference is
+       expected to be.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+  <h4>issigned</h4>
+  <p>
+    Test whether a jarfile is signed.
+    If the name of the
+    signature is passed, the file is checked for presence of that
+    particular signature; otherwise the file is checked for the
+    existence of any signature. It does not perform rigorous
+    signature validation; it only looks for the presence of a signature.
+  </p>
+  <p>
+    This condition was added in Apache Ant 1.7.
+  </p>
+  <table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">
+      The jarfile that is to be tested for the presence
+      of a signature.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top"> The signature name to check for.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  </table>
+  <h4>isfileselected</h4>
+  <p>
+    Test whether a file passes an embedded
+    <a href="../CoreTypes/selectors.html">selector</a>.
+  </p>
+  <p>
+    This condition was added in Apache Ant 1.6.3.
+  </p>
+  <table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">
+      The file to check if is passes the embedded selector.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">The base directory to use for name based selectors. It this is not set,
+      the project's basedirectory will be used.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  </table>
+  <p>
+    Example usage:
+  </p>
+<blockquote><pre>
+&lt;isfileselected file="a.xml"&gt;
+  &lt;date datetime="06/28/2000 2:02 pm" when="equal"/&gt;
+&lt;/isfileselected&gt;
+</pre></blockquote>
+<h4>typefound</h4>
+
+<p>Test whether a given type is defined, and that
+its implementation class can be loaded. Types include
+tasks, datatypes, scriptdefs, macrodefs and presetdefs.</p>
+
+<p>This condition was added in Apache Ant 1.7.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">name of the type</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">uri</td>
+    <td valign="top">
+      The uri that this type lives in.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+  <p>
+    Example usages:
+  </p>
+<blockquote><pre>
+&lt;typefound name="junit"/&gt;
+&lt;typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/&gt;
+</pre></blockquote>
+
+<h4>scriptcondition</h4>
+
+<p>Evaluate a condition based on a script in any
+<a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+  or
+  <a href="https://scripting.dev.java.net">JSR 223</a>
+supported language.
+</p>
+<p>
+See the <a href="../OptionalTasks/script.html">Script</a> task for
+an explanation of scripts and dependencies.
+</p>
+
+<p>This condition was added in Apache Ant 1.7.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">language</td>
+    <td valign="top">script language</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">manager</td>
+    <td valign="top">
+      The script engine manager to use.
+      See the <a href="../OptionalTasks/script.html">script</a> task
+      for using this attribute.
+    </td>
+    <td valign="top" align="center">No - default is "auto"</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">default boolean value</td>
+    <td valign="top" align="center">No -default is "false"</td>
+  </tr>  
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">filename of script source</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">setbeans</td>
+    <td valign="top">whether to have all properties, references and targets as
+      global variables in the script.</td>
+    <td valign="top" align="center">No, default is "true".</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">
+      The classpath to pass into the script.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a
+       <a href="../using.html#references">reference</a> to a path defined elsewhere.
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h5>Parameters specified as nested elements</h5>
+<h6>classpath</h6>
+  <p>
+    See the <a href="../OptionalTasks/script.html">script</a> task
+    for using this nested element.
+  </p>
+<h5>Description</h5>
+<p>
+The script supports script language inline, this script has access to the
+same beans as the <code>&lt;script&gt;</code> task, and to the <code>self</code> bean,
+which refers back to the condition itself. If the script evaluates to a boolean result,
+this is the result of the condition's evaluation (<em>since Ant 1.7.1</em>).
+Alternatively, <code>self.value</code> can be used to set the evaluation result.
+</p>
+<p>
+Example:
+</p>
+<blockquote><pre>
+&lt;scriptcondition language=&quot;javascript&quot;
+        value=&quot;true&quot;&gt;
+    self.setValue(false);
+&lt;/scriptcondition&gt;
+</pre></blockquote>
+
+Sets the default value of the condition to true, then in the script, 
+sets the value to false. This condition always evaluates to "false"
+
+<h4>parsersupports</h4>
+
+<p>Tests whether Ant's XML parser supports a given
+feature or property, as per the SAX/JAXP specifications, by
+attempting to set the appropriate property/feature/</p>
+
+<p>This condition was added in Apache Ant 1.7.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">property to set</td>
+    <td valign="top" align="center">one of property or feature</td>
+  </tr>
+  <tr>
+    <td valign="top">feature</td>
+    <td valign="top">feature to set</td>
+    <td valign="top" align="center">one of property or feature</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">string (property) or boolean (feature)</td>
+    <td valign="top" align="center">For property tests, but not for feature tests</td>
+  </tr>
+</table>
+
+<blockquote><pre>
+&lt;parsersupports feature="http://xml.org/sax/features/namespaces"/&gt;
+</pre></blockquote>
+Check for namespace support. All SAX2 parsers should have this.
+<blockquote><pre>
+&lt;or&gt;
+  &lt;parsersupports
+    feature="http://apache.org/xml/features/validation/schema"/&gt;
+  &lt;parsersupports
+    feature="http://java.sun.com/xml/jaxp/properties/schemaSource"/&gt;
+&lt;/or&gt;
+</pre></blockquote>
+
+Check for XML Schema support.
+
+<pre>
+&lt;parsersupports
+  property="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+  value="document.xsd"/&gt;
+</pre>
+
+Check for Xerces-specific definition of the location of the no namespace schema.
+
+<h4>isreachable</h4>
+
+<p>Uses Java1.5+ networking APIs to probe for a (remote) system being
+reachable. Exactly what probe mechanisms are used is an implementation
+feature of the JVM. They may include ICMP "ping" packets, UDP or TCP connections
+to port 7 "echo service" or other means. On Java1.4 and earlier, being able
+to resolve the hostname is considered success. This means that if DNS is not
+working or a URL/hostname is bad, the test will fail, but otherwise succeed
+even if the remote host is actually absent.
+
+</p>
+<p>
+This condition turns unknown host exceptions into false conditions. This is
+because on a laptop, DNS is one of the first services when the network goes; you
+are implicitly offline.
+</p>
+<p>
+ If a URL is supplied instead of a host, the hostname is extracted
+ and used in the test - all other parts of the URL are discarded.
+</p>
+<p>
+The test may not work through firewalls, that is, something may be reachable
+using a protocol such as HTTP, while the lower level ICMP packets get dropped
+on the floor. Similarly, a host may detected as reachable with ICMP, but
+not reachable on other ports (i.e. port 80), because of firewalls.
+</p>
+<p>
+
+This condition was added in Apache Ant 1.7.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">host</td>
+    <td valign="top">host to check for</td>
+    <td valign="top" align="center">one of url or host</td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">URL containing hostname</td>
+    <td valign="top" align="center">one of url or host</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">timeout in seconds</td>
+    <td valign="top" align="center">no, default is 30s</td>
+  </tr>
+</table>
+
+<blockquote><pre>
+&lt;condition property="offline"&gt;
+  &lt;isreachable url="http://ibiblio.org/maven/" /&gt;
+&lt;/condition&gt;
+</pre></blockquote>
+
+<p>
+Probe for the maven repository being reachable.
+</p>
+
+<blockquote><pre>
+&lt;condition property="offline"&gt;
+  &lt;isreachable host="ibiblio.org" timeout="10" /&gt;
+&lt;/condition&gt;
+</pre></blockquote>
+
+<p>
+Probe for the maven repository being reachable using the hostname, ten second timeout..
+</p>
+
+<h4>length</h4>
+<p>This condition is a facet of the <a href="length.html">Length</a> task.
+  It is used to test the length of a string or one or more files.
+  <b>Since Ant 1.6.3</b>
+</p>
+
+<blockquote><pre>
+&lt;length string=" foo " trim="true" length="3" /&gt;
+</pre></blockquote>
+<p>Verify a string is of a certain length.</p>
+
+<blockquote><pre>
+&lt;length file=&quot;foo&quot; when=&quot;greater&quot; length=&quot;0&quot; /&gt;
+</pre></blockquote>
+<p>Verify that file <i>foo</i> is not empty.</p>
+
+<h4>isfailure</h4>
+
+<p>Test the return code of an executable (see the
+<a href="exec.html">Exec</a> task) for failure. <b>Since Ant 1.7</b></p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">code</td>
+    <td valign="top">The return code to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>resourcecount</h4>
+<p>This condition is a facet of the
+  <a href="resourcecount.html">ResourceCount</a> task.
+  It is used to test the size of a 
+  <a href="../CoreTypes/resources.html#collection">resource collection</a>.
+  <b>Since Ant 1.7</b>
+</p>
+
+<blockquote><pre>
+&lt;resourcecount refid=&quot;myresourcecollection&quot; when=&quot;greater&quot; count=&quot;0&quot; /&gt;
+</pre></blockquote>
+<p>Verify that a resource collection is not empty.</p>
+
+<h4>resourcesmatch</h4>
+<p>Test resources for matching. Nonexistence of one or more resources results in
+"false", although if none exists they are considered equal in terms of content.
+By default this test does a byte for byte comparision, so test time scales with
+byte size. NB: if the files are different sizes, one of them is missing
+or the filenames match the answer is so obvious the detailed test is omitted.
+The resources to check are specified as nested
+<a href="../CoreTypes/resources.html#collection">resource collections</a>,
+meaning that more than two resources can be checked; in this case all resources
+must match. <b>Since Ant 1.7</b>
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">astext</td>
+    <td valign="top">Whether to ignore line endings
+        when comparing resource content; defaults to <i>false</i>,
+        while <i>true</i> triggers a binary comparison.
+    </td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h4>hasmethod</h4>
+
+<p> Tests for a class having a method or field. If the class is not found 
+    or fails to load, the build fails. 
+    
+    <b>Since Ant 1.7</b>
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+        <td width="12%" valign="top"><b>Attribute</b></td>
+        <td width="78%" valign="top"><b>Description</b></td>
+        <td width="10%" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+        <td valign="top">classname</td>
+        <td valign="top">name of the class to load</td>
+        <td align="center">yes</td>
+    </tr>
+    <tr>
+        <td valign="top">field</td>
+        <td valign="top">name of a field to look for</td>
+        <td align="center">one of field or method</td>
+    </tr>
+    <tr>
+        <td valign="top">method</td>
+        <td valign="top">name of a method to look for</td>
+        <td align="center">one of field or method</td>
+    </tr>
+    
+    <tr>
+        <td valign="top">ignoreSystemClasses</td>
+        <td valign="top">should system classes be ignored?</td>
+        <td align="center">No -default is false</td>
+    </tr>
+    <tr>
+        <td valign="top">classpath</td>
+        <td valign="top">a class path</td>
+        <td align="center">No</td>
+    </tr>
+    <tr>
+        <td valign="top">classpathref</td>
+        <td valign="top">reference to a class path</td>
+        <td align="center">No</td>
+    </tr>
+</table>
+
+<p>
+    There is also a nested &lt;classpath&gt; element, which can be used to specify 
+    a classpath.
+</p>
+<blockquote><pre>
+&lt;hasmethod classname="java.util.ArrayList" method="trimToSize"  /&gt;
+</pre></blockquote>
+
+<p>Looks for the method trimToSize in the ArrayList class.</p>
+
+<h4>matches</h4>
+
+<p>
+  Test if the specified string matches the specified regular
+  expression pattern.
+  <b>Since Ant 1.7</b></p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">string</td>
+    <td valign="top">The string to test.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">The regular expression pattern used to test.</td>
+    <td valign="top" align="center">Yes, unless there is a nested
+      <code>&lt;regexp&gt;</code> element.</td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Perform a case sensitive match.  Default is
+        true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">multiline</td>
+    <td valign="top">
+      Perform a multi line match.
+      Default is false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">singleline</td>
+    <td valign="top">
+      This allows '.' to match new lines.
+      SingleLine is not to be confused with multiline, SingleLine is a perl
+      regex term, it corresponds to dotall in java regex.
+      Default is false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+  <p>
+    There is also an optional &lt;regexp&gt; element, which can be used to specify
+    a regular expression instead of the "pattern" attribute.
+    See <a href="../CoreTypes/regexp.html">Regexp Type</a> for the description
+    of the nested element regexp and of
+    the choice of regular expression implementation.
+  </p>
+  <p>
+    An example:
+  </p>
+<blockquote><pre>
+&lt;condition property="legal-password"&gt;
+  &lt;matches pattern="[1-9]" string="${user-input}"/&gt;
+&lt;/condition&gt;
+&lt;fail message="Your password should at least contain one number"
+      unless="legal-password"/&gt;
+</pre></blockquote>
+  <p>
+    The following example sets the property "ok" if
+    the property "input" is three characters long, starting
+    with 'a' and ending with 'b'.
+  </p>
+<blockquote><pre>
+&lt;condition property="ok"&gt;
+  &lt;matches string="${input}" pattern="^a.b$"/&gt;
+&lt;/condition&gt;
+</pre></blockquote>
+  <p>
+    The following defines a reference regular expression for
+    matching dates and then uses antunit to check if the
+    property "today" is in the correct format:
+  </p>
+<blockquote><pre>
+&lt;regexp id="date.pattern" pattern="^[0123]\d-[01]\d-[12]\d\d\d$"/&gt;
+
+&lt;au:assertTrue xmlns:au="antlib:org.apache.ant.antunit"&gt;
+  &lt;matches string="${today}"&gt;
+    &lt;regexp refid="date.pattern"/&gt;
+  &lt;/matches&gt;
+&lt;/au:assertTrue&gt;
+</pre></blockquote>
+  <p>
+    The following example shows the use of the singleline and the casesensitive
+    flags.
+  </p>
+<blockquote><pre>
+&lt;au:assertTrue&gt;
+  &lt;matches string="AB${line.separator}C" pattern="^ab.*C$"
+           casesensitive="false"
+           singleline="true"/&gt;
+&lt;/au:assertTrue&gt;
+&lt;au:assertFalse&gt;
+  &lt;matches string="AB${line.separator}C" pattern="^ab.*C$"
+           casesensitive="false"
+           singleline="false"/&gt;
+&lt;/au:assertFalse&gt;
+</pre></blockquote>
+<h4>antversion</h4>
+<p>This condition is identical to the <a
+href="antversion.html">Antversion</a> task, all attributes are supported, the property attribute
+is redundant and will be ignored.</p>
+
+
+<h4>hasfreespace</h4>
+
+<p>
+  Tests a partition to see if there is enough space.
+  <b>Since Ant 1.7.0</b></p>
+  <p>Needed attribute can be specified using standard computing terms:<br/>
+    <ul>
+      <li>K : Kilobytes (1024 bytes)</li>
+      <li>M : Megabytes (1024 K)</li>
+      <li>G : Gigabytes (1024 M)</li>
+      <li>T : Terabytes (1024 G)</li>
+      <li>P : Petabytes (1024 T)</li>
+    </ul>
+  </p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">partition</td>
+    <td valign="top">The partition or filesystem to check for freespace</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">needed</td>
+    <td valign="top">The amount of freespace needed.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+  <p>
+    An example:
+  </p>
+<blockquote><pre>
+&lt;hasfreespace partition="c:" needed="100M"/&gt;
+</pre></blockquote>
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/copy.html b/trunk/docs/manual/CoreTasks/copy.html
new file mode 100644
index 0000000..ff95b4c
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/copy.html
@@ -0,0 +1,340 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Copy Task</title>
+</head>
+
+<body>
+
+<h2><a name="copy">Copy</a></h2>
+<h3>Description</h3>
+<p>Copies a file or resource collection to a new file or directory.  By default, files are
+only copied if the source file is newer than the destination file,
+or when the destination file does not exist.  However, you can explicitly
+overwrite files with the <code>overwrite</code> attribute.</p>
+
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select a group of files to copy.  To use a
+resource collection, the <code>todir</code> attribute must be set.</p>
+
+<p>
+<strong>Note: </strong>If you employ filters in your copy operation,
+you should limit the copy to text files. Binary files will be corrupted
+by the copy operation.
+This applies whether the filters are implicitly defined by the
+<a href="filter.html">filter</a> task or explicitly provided to the copy
+operation as <a href="../CoreTypes/filterset.html">filtersets</a>.
+  <em>See <a href="#encoding">encoding note</a></em>.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to copy.</td>
+    <td valign="top" align="center">Yes, unless a nested
+    resource collection element is used.</td>
+  </tr>
+  <tr>
+    <td valign="top">preservelastmodified</td>
+    <td valign="top">Give the copied files the same last modified
+      time as the original source files.</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">tofile</td>
+    <td valign="top">The file to copy to.</td>
+    <td valign="top" align="center" rowspan="2">With the <code>file</code>
+      attribute, either <code>tofile</code> or <code>todir</code> can be used.
+      With nested resource collection elements, if the number of included files
+      is greater than 1, or if only the <code>dir</code> attribute is
+      specified in the <code>&lt;fileset&gt;</code>, or if the
+      <code>file</code> attribute is also specified, then only
+      <code>todir</code> is allowed.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">The directory to copy to.</td>
+  </tr>
+  <tr>
+    <td valign="top">overwrite</td>
+    <td valign="top">Overwrite existing files even if the destination
+      files are newer.</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">filtering</td>
+    <td valign="top">Indicates whether token filtering using the global
+      build-file filters should take place during the copy.
+      <em>Note</em>: Nested <code>&lt;filterset&gt;</code> elements will
+      always be used, even if this attribute is not specified, or its value is
+      <code>false</code> (<code>no</code>, or <code>off</code>).</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">flatten</td>
+    <td valign="top">Ignore the directory structure of the source files,
+      and copy all files into the directory specified by the <code>todir</code>
+      attribute.  Note that you can achieve the same effect by using a
+      <a href="../CoreTypes/mapper.html#flatten-mapper">flatten mapper</a>.</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">includeEmptyDirs</td>
+     <td valign="top">Copy any empty directories included in the FileSet(s).
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">If false, log a warning message, but do not stop the
+       build, when the file to copy does not exist or one of the nested
+       filesets points to a directory that doesn't exist or an error occurs
+       while copying.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+     <td valign="top">Log the files that are being copied.</td>
+     <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding to assume when filter-copying the
+    files. <em>since Ant 1.5</em>.</td>
+    <td align="center">No - defaults to default JVM encoding</td>
+  </tr>
+  <tr>
+    <td valign="top">outputencoding</td>
+    <td valign="top">The encoding to use when writing the files.
+    <em>since Ant 1.6</em>.</td>
+    <td align="center">No - defaults to the value of the encoding
+    attribute if given or the default JVM encoding otherwise.</td>
+  </tr>
+  <tr>
+    <td valign="top">enablemultiplemappings</td>
+    <td valign="top">
+      If true the task will process to all the mappings for a
+      given source path. If false the task will only process
+      the first file or directory. This attribute is only relevant
+      if there is a mapper subelement.
+      <em>since Ant 1.6</em>.</td>
+    <td align="center">No - defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">granularity</td>
+    <td valign="top">The number of milliseconds leeway to give before
+    deciding a file is out of date. This is needed because not every
+    file system supports tracking the last modified time to the
+    millisecond level. Default is 1 second, or 2 seconds on DOS
+    systems.  This can also be useful if source and target files live
+    on separate machines with clocks being out of sync.  <em>since Ant
+    1.6.2</em>.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>fileset or any other resource collection</h4>
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select groups of files to copy.  To use a
+resource collection, the <code>todir</code> attribute must be set.</p>
+<p>Prior to Ant 1.7 only <code>&lt;fileset&gt;</code> has been
+supported as a nested element.</p>
+
+<h4>mapper</h4>
+ <p>You can define filename transformations by using a nested <a
+ href="../CoreTypes/mapper.html">mapper</a> element. The default mapper used by
+ <code>&lt;copy&gt;</code> is the <a
+ href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a>.</p>
+  <p>
+    <em>Since Ant 1.6.3</em>,
+    one can use a filenamemapper type in place of the mapper element.
+  </p>
+
+<p>Note that the source name handed to the mapper depends on the
+resource collection you use.  If you use <code>&lt;fileset&gt;</code>
+or any other collection that provides a base directory, the name
+passed to the mapper will be a relative filename, relative to the base
+directory.  In any other case the absolute filename of the source will
+be used.</p>
+
+<h4>filterset</h4>
+ <p><a href="../CoreTypes/filterset.html">FilterSet</a>s are used to replace
+tokens in files that are copied.
+ To use a FilterSet, use the nested <code>&lt;filterset&gt;</code> element.</p>
+
+<h4>filterchain</h4>
+<p>The Copy task supports nested <a href="../CoreTypes/filterchain.html">
+FilterChain</a>s.</p>
+
+<p>
+If <code>&lt;filterset&gt;</code> and <code>&lt;filterchain&gt;</code> elements are used inside the
+same <code>&lt;copy&gt;</code> task, all <code>&lt;filterchain&gt;</code> elements are processed first
+followed by <code>&lt;filterset&gt;</code> elements.
+</p>
+
+<h3>Examples</h3>
+<p><b>Copy a single file</b></p>
+<pre>
+  &lt;copy file=&quot;myfile.txt&quot; tofile=&quot;mycopy.txt&quot;/&gt;
+</pre>
+<p><b>Copy a single file to a directory</b></p>
+<pre>
+  &lt;copy file=&quot;myfile.txt&quot; todir=&quot;../some/other/dir&quot;/&gt;
+</pre>
+<p><b>Copy a directory to another directory</b></p>
+<pre>
+  &lt;copy todir=&quot;../new/dir&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;/&gt;
+  &lt;/copy&gt;
+</pre>
+<p><b>Copy a set of files to a directory</b></p>
+<pre>
+  &lt;copy todir=&quot;../dest/dir&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;&gt;
+      &lt;exclude name=&quot;**/*.java&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;/copy&gt;
+
+  &lt;copy todir=&quot;../dest/dir&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot; excludes=&quot;**/*.java&quot;/&gt;
+  &lt;/copy&gt;
+</pre>
+<p><b>Copy a set of files to a directory, appending
+<code>.bak</code> to the file name on the fly</b></p>
+<pre>
+  &lt;copy todir=&quot;../backup/dir&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;/&gt;
+    &lt;globmapper from=&quot;*&quot; to=&quot;*.bak&quot;/&gt;
+  &lt;/copy&gt;
+</pre>
+
+<p><b>Copy a set of files to a directory, replacing @TITLE@ with Foo Bar
+in all files.</b></p>
+<pre>
+  &lt;copy todir=&quot;../backup/dir&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;/&gt;
+    &lt;filterset&gt;
+      &lt;filter token=&quot;TITLE&quot; value=&quot;Foo Bar&quot;/&gt;
+    &lt;/filterset&gt;
+  &lt;/copy&gt;
+</pre>
+
+<p><b>Collect all items from the current CLASSPATH setting into a
+destination directory, flattening the directory structure.</b></p>
+<pre>
+  &lt;copy todir=&quot;dest&quot; flatten=&quot;true&quot;&gt;
+    &lt;path&gt;
+      &lt;pathelement path=&quot;${java.class.path}&quot;/&gt;
+    &lt;/path&gt;
+  &lt;/copy&gt;
+</pre>
+
+<p><b>Copies some resources to a given directory.</b></p>
+<pre>
+  &lt;copy todir=&quot;dest&quot; flatten=&quot;true&quot;&gt;
+    &lt;resources&gt;
+      &lt;file file=&quot;src_dir/file1.txt&quot;/&gt;
+      &lt;url url=&quot;http://ant.apache.org/index.html&quot;/&gt;
+    &lt;/resources&gt;
+  &lt;/copy&gt;
+</pre>
+
+<p><b>Copies the two newest resources into a destination directory.</b></p>
+<pre>
+  &lt;copy todir=&quot;dest&quot; flatten=&quot;true&quot;&gt;
+    &lt;first count=&quot;2&quot;&gt;
+      &lt;sort&gt;
+        &lt;date xmlns=&quot;antlib:org.apache.tools.ant.types.resources.comparators&quot;/&gt;
+        &lt;resources&gt;
+          &lt;file file=&quot;src_dir/file1.txt&quot;/&gt;
+          &lt;file file=&quot;src_dir/file2.txt&quot;/&gt;
+          &lt;file file=&quot;src_dir/file3.txt&quot;/&gt;
+          &lt;url url=&quot;http://ant.apache.org/index.html&quot;/&gt;
+        &lt;/resources&gt;
+      &lt;/sort&gt;
+    &lt;/first&gt;
+  &lt;/copy&gt;
+</pre>
+
+
+<p><strong>Unix Note:</strong> File permissions are not retained when files
+are copied; they end up with the default <code>UMASK</code> permissions
+instead. This
+is caused by the lack of any means to query or set file permissions in the
+current Java runtimes. If you need a permission-preserving copy function,
+use <code>&lt;exec executable="cp" ... &gt;</code> instead.
+</p>
+
+<p><strong>Windows Note:</strong> If you copy a file to a directory
+where that file already exists, but with different casing,
+the copied file takes on the case of the original. The workaround is to
+<a href="delete.html">delete</a>
+the file in the destination directory before you copy it.
+</p>
+  <p>
+    <strong><a name="encoding">Important Encoding Note:</a></strong>
+    The reason that binary files when filtered get corrupted is that
+    filtering involves reading in the file using a Reader class. This
+    has an encoding specifing how files are encoded. There are a number
+    of different types of encoding - UTF-8, UTF-16, Cp1252, ISO-8859-1,
+    US-ASCII and (lots) others. On Windows the default character encoding
+    is Cp1252, on Unix it is usually UTF-8. For both of these encoding
+    there are illegal byte sequences (more in UTF-8 than for Cp1252).
+  </p>
+  <p>
+    How the Reader class deals with these illegal sequences is up to the
+    implementation
+    of the character decoder. The current Sun Java implemenation is to
+    map them to legal characters. Previous Sun Java (1.3 and lower) threw
+    a MalformedInputException. IBM Java 1.4 also thows this exception.
+    It is the mapping of the characters that cause the corruption.
+  </p>
+  <p>
+    On Unix, where the default is normally UTF-8, this is a <em>big</em>
+    problem, as it is easy to edit a file to contain non US Ascii characters
+    from ISO-8859-1, for example the Danish oe character. When this is
+    copied (with filtering) by Ant, the character get converted to a
+    question mark (or some such thing).
+  </p>
+  <p>
+    There is not much that Ant can do. It cannot figure out which
+    files are binary - a UTF-8 version of Korean will have lots of
+    bytes with the top bit set. It is not informed about illegal
+    character sequences by current Sun Java implementions.
+  </p>
+  <p>
+    One trick for filtering containing only US-ASCII is to
+    use the ISO-8859-1 encoding. This does not seem to contain
+    illegal character sequences, and the lower 7 bits are US-ASCII.
+    Another trick is to change the LANG environment variable from
+    something like "us.utf8" to "us".
+  </p>
+    
+
+
+
+</body></html>
diff --git a/trunk/docs/manual/CoreTasks/copydir.html b/trunk/docs/manual/CoreTasks/copydir.html
new file mode 100644
index 0000000..38d91b6
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/copydir.html
@@ -0,0 +1,136 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Copydir Task</title>
+</head>
+
+<body>
+
+<h2><a name="copydir">Copydir</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the Copy task instead.</i></p>
+<h3>Description</h3>
+<p>Copies a directory tree from the source to the destination.</p>
+<p>It is possible to refine the set of files that are being copied. This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>src</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">the directory to copy.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the directory to copy to.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filtering</td>
+    <td valign="top">indicates whether token filtering should take place during
+      the copy</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">flatten</td>
+    <td valign="top">ignore directory structure of source directory,
+      copy all files into a single directory, specified by the <code>dest</code>
+      attribute (default is <code>false</code>).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">forceoverwrite</td>
+    <td valign="top">overwrite existing files even if the destination
+      files are newer (default is false).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;copydir src=&quot;${src}/resources&quot;
+           dest=&quot;${dist}&quot;
+  /&gt;</pre>
+<p>copies the directory <code>${src}/resources</code> to <code>${dist}</code>.</p>
+<pre>  &lt;copydir src=&quot;${src}/resources&quot;
+           dest=&quot;${dist}&quot;
+           includes=&quot;**/*.java&quot;
+           excludes=&quot;**/Test.java&quot;
+  /&gt;</pre>
+<p>copies the directory <code>${src}/resources</code> to <code>${dist}</code>
+recursively. All java files are copied, except for files with the name <code>Test.java</code>.</p>
+<pre>  &lt;copydir src=&quot;${src}/resources&quot;
+           dest=&quot;${dist}&quot;
+           includes=&quot;**/*.java&quot;
+           excludes=&quot;mypackage/test/**&quot;/&gt;</pre>
+<p>copies the directory <code>${src}/resources</code> to <code>${dist}</code>
+recursively. All java files are copied, except for the files under the <code>mypackage/test</code>
+directory.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/copyfile.html b/trunk/docs/manual/CoreTasks/copyfile.html
new file mode 100644
index 0000000..e204a7e
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/copyfile.html
@@ -0,0 +1,73 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Copyfile Task</title>
+</head>
+
+<body>
+
+<h2><a name="copyfile">Copyfile</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the Copy task instead.</i></p>
+<h3>Description</h3>
+<p>Copies a file from the source to the destination. The file is only copied if
+the source file is newer than the destination file, or when the destination file
+does not exist.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">the filename of the file to copy.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the filename of the file where to copy to.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">filtering</td>
+    <td valign="top">indicates whether token filtering should take place during
+      the copy</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">forceoverwrite</td>
+    <td valign="top">overwrite existing files even if the destination
+      files are newer (default is false).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <p><code>&lt;copyfile src=&quot;test.java&quot; dest=&quot;subdir/test.java&quot;/&gt;</code></p>
+  <p><code>&lt;copyfile src=&quot;${src}/index.html&quot; dest=&quot;${dist}/help/index.html&quot;/&gt;</code></p>
+</blockquote>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/cvs.html b/trunk/docs/manual/CoreTasks/cvs.html
new file mode 100644
index 0000000..ed09b00
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/cvs.html
@@ -0,0 +1,200 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>CVS Task</title>
+</head>
+
+<body>
+
+<h2><a name="cvs">Cvs</a></h2>
+<h3>Description</h3>
+<p>Handles packages/modules retrieved from a
+<a href="http://www.nongnu.org/cvs/" target="_top">CVS</a> repository.</p>
+<p><b>Important:</b> This task needs &quot;<code>cvs</code>&quot; on the path. If it isn't, you will get
+an error (such as error <code>2</code> on windows). If <code>&lt;cvs&gt;</code> doesn't work, try to execute <code>cvs.exe</code>
+from the command line in the target directory in which you are working.
+
+<p><b>CVSNT Note</b>: CVSNT prefers users to store the passwords
+inside the registry.  If the <a href="cvspass.html">cvspass task</a>
+and the passfile attribute don't seem to work for you, the most likely
+reason is that CVSNT ignores your .cvspass file completely.  See <a
+href="http://issues.apache.org/bugzilla/show_bug.cgi?id=21657#c5">bug
+zilla report 21657</a> for recommended workarounds.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">command</td>
+    <td valign="top">the CVS command to execute.</td>
+    <td align="center" valign="top">No, default &quot;checkout&quot;.</td>
+  </tr>
+  <tr>
+    <td valign="top">compression</td>
+    <td valign="top"><code>true</code> or <code>false</code> - if set
+    to true, this is the same as <code>compressionlevel=&quot;3&quot;</code></td>
+    <td align="center" valign="top">No. Defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">compressionlevel</td>
+    <td valign="top">A number between 1 and 9 (corresponding to
+    possible values for CVS' <code>-z#</code> argument). Any
+    other value is treated as <code>compression=&quot;false&quot;</code></td>
+    <td align="center" valign="top">No. Defaults to no compression.</td>
+  </tr>
+
+  <tr>
+    <td valign="top">cvsRoot</td>
+    <td valign="top">the <code>CVSROOT</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRsh</td>
+    <td valign="top">the <code>CVS_RSH</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the directory where the checked out files should
+    be placed.  Note that this is different from CVS's <code>-d</code> command line
+    switch as Ant will never shorten pathnames to avoid empty
+    directories.</td>
+    <td align="center" valign="top">No, default is project's basedir.</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">the package/module to check out.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tag</td>
+    <td valign="top">the tag of the package/module to check out.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">date</td>
+    <td valign="top">Use the most recent revision no later than the given date</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">suppress informational messages. This is the same as <code>-q</code> on the command line.</td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">reallyquiet</td>
+    <td valign="top">suppress all messages. This is the same as
+      <code>-Q</code> on the command line.  <em>since Ant 1.6</em>.</td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">noexec</td>
+    <td valign="top">report only, don't change any files.</td>
+    <td align="center" valign="top">No, default to &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">the file to direct standard output from the command.</td>
+    <td align="center" valign="top">No, default output to ANT Log as <code>MSG_INFO</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">error</td>
+    <td valign="top">the file to direct standard error from the command.</td>
+    <td align="center" valign="top">No, default error to ANT Log as <code>MSG_WARN</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">whether to append output/error when redirecting to a file.</td>
+    <td align="center" valign="top">No, default to &quot;false&quot;.</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">Port used by CVS to communicate with the server.</td>
+    <td align="center" valign="top">No, default port <code>2401</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">passfile</td>
+    <td valign="top">Password file to read passwords from.</td>
+    <td align="center" valign="top">No, default file <code>~/.cvspass</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the build process if the command exits with a
+      return code other than <code>0</code>. Defaults to &quot;false&quot;</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;cvs cvsRoot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot;
+       package=&quot;ant&quot;
+       dest=&quot;${ws.dir}&quot;
+  /&gt;</pre>
+<p>checks out the package/module &quot;ant&quot; from the CVS
+repository pointed to by the <code>cvsRoot</code> attribute, and stores the files in &quot;<code>${ws.dir}</code>&quot;.</p>
+<pre>  &lt;cvs dest=&quot;${ws.dir}&quot; command=&quot;update&quot;/&gt;</pre>
+<p>updates the package/module that has previously been checked out into
+&quot;<code>${ws.dir}</code>&quot;.</p>
+
+<pre>  &lt;cvs command=&quot;-q diff -u -N&quot; output=&quot;patch.txt&quot;/&gt;</pre>
+
+<p>silently (<code>-q</code>) creates a file called <code>patch.txt</code> which contains a unified (<code>-u</code>) diff which includes new files added via &quot;cvs add&quot; (<code>-N</code>) and can be used as input to patch.
+The equivalent, using  <code>&lt;commandline&gt;</code> elements, is:
+</p>
+<pre>
+&lt;cvs output=&quot;patch&quot;&gt;
+    &lt;commandline&gt;
+        &lt;argument value=&quot;-q&quot;/&gt;
+        &lt;argument value=&quot;diff&quot;/&gt;
+        &lt;argument value=&quot;-u&quot;/&gt;
+        &lt;argument value=&quot;-N&quot;/&gt;
+    &lt;/commandline&gt;
+&lt;/cvs&gt;
+</pre>
+or:
+<pre>
+&lt;cvs output=&quot;patch&quot;&gt;
+    &lt;commandline&gt;
+        &lt;argument line=&quot;-q diff -u -N&quot;/&gt;
+    &lt;/commandline&gt;
+&lt;/cvs&gt;
+</pre>
+<p>
+You may include as many <code>&lt;commandline&gt;</code> elements as you like. 
+Each will inherit the <code>failonerror</code>, <code>compression</code>, and other &quot;global&quot; parameters
+from the <code>&lt;cvs&gt;</code> element.
+</p>
+
+
+<pre>  &lt;cvs command=&quot;update -A -d&quot;/&gt;</pre>
+<p>Updates from the head of repository ignoring sticky bits (<code>-A</code>) and creating any new directories as necessary (<code>-d</code>).</p>
+<p>Note: the text of the command is passed to cvs &quot;as-is&quot; so any cvs options should appear
+before the command, and any command options should appear after the command as in the diff example
+above. See <a href="http://ximbiot.com/cvs/wiki/index.php?title=Category:User_Documentation" target="_top">the cvs manual</a> for details,
+specifically the <a href="http://ximbiot.com/cvs/wiki/index.php?title=CVS--Concurrent_Versions_System_v1.12.12.1:_Guide_to_CVS_commands#SEC116" target="_top">Guide to CVS commands</a></p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/cvspass.html b/trunk/docs/manual/CoreTasks/cvspass.html
new file mode 100644
index 0000000..185dde7
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/cvspass.html
@@ -0,0 +1,70 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>CVSPass Task</title>
+</head>
+
+<body>
+
+<h2><a name="cvs">cvspass</a></h2>
+<h3>Description</h3>
+<p>Adds entries to a .cvspass file. Adding entries to this file has the same affect as a cvs login command.</p>
+
+<p><b>CVSNT Note</b>: CVSNT prefers users to store the passwords
+inside the registry.  If the task doesn't seem to work for you, the
+most likely reason is that CVSNT ignores your .cvspass file
+completely.  See <a
+href="http://issues.apache.org/bugzilla/show_bug.cgi?id=21657#c5">bug
+zilla report 21657</a> for recommended workarounds.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">cvsroot</td>
+    <td valign="top">the CVS repository to add an entry for.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">Password to be added to the password file.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">passfile</td>
+    <td valign="top">Password file to add the entry to.</td>
+    <td align="center" valign="top">No, default is <code>~/.cvspass</code>.</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;cvspass cvsroot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot;
+       password=&quot;anoncvs&quot;
+  /&gt;</pre>
+<p>Adds an entry into the ~/.cvspass password file.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/cvstagdiff.html b/trunk/docs/manual/CoreTasks/cvstagdiff.html
new file mode 100644
index 0000000..5c8a9e7
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/cvstagdiff.html
@@ -0,0 +1,206 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>CvsTagDiff Task</title>
+</head>
+<body>
+<h2><a name="cvstagdiff">CvsTagDiff</a></h2>
+<h3>Description</h3>
+<p>Generates an XML-formatted report file of the changes between two tags or dates recorded in a
+<a href="http://www.nongnu.org/cvs/" target="_top">CVS</a> repository. </p>
+<p><b>Important:</b> This task needs "cvs" on the path. If it isn't, you will get
+an error (such as error 2 on windows). If <code>&lt;cvs&gt;</code> doesn't work, try to execute <code>cvs.exe</code>
+from the command line in the target directory in which you are working.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">startTag</td>
+    <td valign="top">The earliest tag from which diffs are to be
+     included in the report.</td>
+    <td align="center" valign="top" rowspan="2">exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">startDate</td>
+    <td valign="top">The earliest date from which diffs are to be
+     included in the report.<br>
+     accepts all formats accepted by the cvs command for -D date_spec arguments</td>
+  </tr>
+  <tr>
+    <td valign="top">endTag</td>
+    <td valign="top">The latest tag from which diffs are to be
+     included in the report.</td>
+    <td align="center" valign="top" rowspan="2">exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">endDate</td>
+    <td valign="top">The latest date from which diffs are to be
+     included in the report.<br>
+     accepts all formats accepted by the cvs command for -D date_spec arguments</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">The file in which to write the diff report.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h3>Parameters inherited from the <code>cvs</code> task</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">compression</td>
+    <td valign="top"><code>true</code>, <code>false</code>, or the number 1-9 (corresponding to possible values for CVS <code>-z#</code> argument). Any other value is treated as false</td>
+    <td align="center" valign="top">No. Defaults to no compression. if passed <code>true</code>, level 3 compression is assumed.</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRoot</td>
+    <td valign="top">the CVSROOT variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRsh</td>
+    <td valign="top">the CVS_RSH variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">the package/module to analyze.<br>
+    Since ant 1.6
+    multiple packages separated by spaces are possible.
+    aliases corresponding to different modules are also possible</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">suppress informational messages.</td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">Port used by CVS to communicate with the server.</td>
+    <td align="center" valign="top">No, default port 2401.</td>
+  </tr>
+  <tr>
+    <td valign="top">passfile</td>
+    <td valign="top">Password file to read passwords from.</td>
+    <td align="center" valign="top">No, default file <code>~/.cvspass</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the buildprocess if the command exits with a
+      returncode other than 0. Defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;cvstagdiff cvsRoot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot;
+                destfile=&quot;tagdiff.xml&quot;
+                package=&quot;ant&quot;
+                startTag=&quot;ANT_14&quot;
+                endTag=&quot;ANT_141&quot;
+  /&gt;</pre>
+
+<p>Generates a tagdiff report for all the changes that have been made
+in the <code>ant</code> module between the tags <code>ANT_14</code> and <code>ANT_141</code>.
+It writes these changes into the file <code>tagdiff.xml</code>.</p>
+
+<pre>  &lt;cvstagdiff
+                destfile=&quot;tagdiff.xml&quot;
+                package=&quot;ant&quot;
+                startDate=&quot;2002-01-01&quot;
+                endDate=&quot;2002-31-01&quot;
+  /&gt;</pre>
+
+<p>Generates a tagdiff report for all the changes that have been made
+in the <code>ant</code> module in january 2002. In this example <code>cvsRoot</code>
+has not been set. The current <code>cvsRoot</code> will be used (assuming the build is started
+from a folder stored in <code>cvs</code>.
+It writes these changes into the file <code>tagdiff.xml</code>.</p>
+
+<pre>  &lt;cvstagdiff
+                destfile=&quot;tagdiff.xml&quot;
+                package=&quot;ant jakarta-gump&quot;
+                startDate=&quot;2003-01-01&quot;
+                endDate=&quot;2003-31-01&quot;
+  /&gt;</pre>
+
+<p>Generates a tagdiff report for all the changes that have been made
+in the <code>ant</code> and <code>jakarta-gump</code> modules in january 2003.
+In this example <code>cvsRoot</code>
+has not been set. The current <code>cvsRoot</code> will be used (assuming the build is started
+from a folder stored in <code>cvs</code>.
+It writes these changes into the file <code>tagdiff.xml</code>.</p>
+
+<h4>Generate Report</h4>
+<p>Ant includes a basic XSLT stylesheet that you can use to generate 
+a HTML report based on the xml output. The following example illustrates
+how to generate a HTML report from the XML report.</p>
+
+<pre>
+        &lt;style in="tagdiff.xml" 
+               out="tagdiff.html" 
+               style="${ant.home}/etc/tagdiff.xsl"&gt;
+          &lt;param name="title" expression="Ant Diff"/&gt;
+          &lt;param name="module" expression="ant"/&gt;
+          &lt;param name="cvsweb" expression="http://cvs.apache.org/viewcvs/"/&gt;
+        &lt;/style&gt;
+</pre>
+
+<h4>Output</h4>
+<p>
+The cvsroot and package attributes of the tagdiff element are new in ant 1.6.<br>
+Notes on entry attributes :
+<table border="1">
+<tr><th>Attribute</th><th>Comment</th></tr>
+<tr><td>name</td><td>when reporting on one package, the package name is removed from the output</td></tr>
+<tr><td>revision</td><td>supplied for files which exist at the end of the reporting period</td></tr>
+<tr><td>prevrevision</td><td>supplied for files which exist at the beginning of the reporting period.<br>
+Old CVS servers do not supply it for deleted files. CVS 1.12.2 supplies it.</td></tr>
+</table>
+</p>
+<pre>
+&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+&lt;tagdiff startTag=&quot;ANT_14&quot; endTag=&quot;ANT_141&quot; 
+cvsroot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot; package=&quot;ant&quot;&gt;
+  &lt;entry&gt;
+    &lt;file&gt;
+      &lt;name&gt;src/main/org/apache/tools/ant/DirectoryScanner.java&lt;/name&gt;
+      &lt;revision&gt;1.15.2.1&lt;/revision&gt;
+      &lt;prevrevision&gt;1.15&lt;/prevrevision&gt;
+    &lt;/file&gt;
+  &lt;/entry&gt;
+&lt;/tagdiff&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/cvsversion.html b/trunk/docs/manual/CoreTasks/cvsversion.html
new file mode 100644
index 0000000..41f55af
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/cvsversion.html
@@ -0,0 +1,108 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>CVSVersion Task</title>
+</head>
+
+<body>
+
+<h2><a name="cvs">CvsVersion</a></h2>
+<h3>Description</h3>
+<p>
+This task allows to retrieve a CVS client and server version.
+  <i>Since Ant 1.6.1.</i>
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td colspan="3">Attributes from parent Cvs task which are meaningful here</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRoot</td>
+    <td valign="top">the <code>CVSROOT</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cvsRsh</td>
+    <td valign="top">the <code>CVS_RSH</code> variable.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">directory containing the checked out version of the project</td>
+    <td align="center" valign="top">No, default is project's basedir.</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">the package/module to check out.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">Port used by CVS to communicate with the server.</td>
+    <td align="center" valign="top">No, default port 2401.</td>
+  </tr>
+  <tr>
+    <td valign="top">passfile</td>
+    <td valign="top">Password file to read passwords from.</td>
+    <td align="center" valign="top">No, default file ~/.cvspass.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the build process if the command exits with a
+      return code other than <code>0</code>. Defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td colspan="3">Specific attributes</td>
+  </tr>
+  <tr>
+    <td valign="top">clientversionproperty</td>
+    <td valign="top">Name of a property where the cvsclient version
+      should be stored</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">serverversionproperty</td>
+    <td valign="top">Name of a property where the cvs server version
+      should be stored</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;cvsversion cvsRoot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot;
+       passfile=&quot;/home/myself/.cvspass&quot;
+       serverversionproperty=&quot;apachecvsversion&quot;
+       clientversionproperty=&quot;localcvsversion&quot;
+  /&gt;</pre>
+<p>finds out the cvs client and server versions and stores the versions in the
+properties called apachecvsversion and localcvsversion</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/defaultexcludes.html b/trunk/docs/manual/CoreTasks/defaultexcludes.html
new file mode 100644
index 0000000..5557747
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/defaultexcludes.html
@@ -0,0 +1,107 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>DefaultExcludes Task</title>
+</head>
+
+<body>
+
+<h2><a name="echo">DefaultExcludes</a></h2>
+
+<p><em>since Ant 1.6</em></p>
+
+<h3>Description</h3>
+<p>Alters the default excludes for all subsequent processing in the
+build, and prints out the current default excludes if desired.
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">echo</td>
+    <td valign="top">whether or not to print out the default excludes.(defaults to false)</td>
+    <td valign="top" align="center">attribute "true" required if no
+                                    other attribute specified</td>
+  </tr>
+  <tr>
+    <td valign="top">default</td>
+    <td valign="top">go back to hard wired default excludes</td>
+    <td valign="top" align="center">attribute "true" required if no
+    if no other attribute is specified</td>
+  </tr>
+  <tr>
+    <td valign="top">add</td>
+    <td valign="top">the pattern to add to the default excludes</td>
+    <td valign="top" align="center">if no other attribute is specified</td>
+  </tr>
+  <tr>
+    <td valign="top">remove</td>
+    <td valign="top">remove the specified pattern from the default excludes</td>
+    <td valign="top" align="center">if no other attribute is specified</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+<p>Print out the default excludes</p>
+
+<pre>  &lt;defaultexcludes echo=&quot;true&quot;/&gt;</pre>
+
+<p>Print out the default excludes and exclude all *.bak files in
+<strong>all</strong> further processing</p>
+
+<pre>  &lt;defaultexcludes echo=&quot;true&quot; add=&quot;**/*.bak&quot;/&gt;</pre>
+
+<p>Silently allow several fileset based tasks to operate on emacs
+backup files and then restore normal behavior</p>
+
+<pre>
+  &lt;defaultexcludes remove=&quot;**/*~&quot;/&gt;
+
+  (do several fileset based tasks here)
+
+  &lt;defaultexcludes default=&quot;true&quot;/&gt;
+</pre>
+
+<h3>Notes</h3>
+By default the pattern <tt>**/.svn</tt> and <tt>**/.svn/**</tt> are set as default 
+excludes. With version 1.3 Subversion supports the 
+<a target="_blank" href="http://subversion.tigris.org/svn_1.3_releasenotes.html">&quot;_svn hack&quot;</a>.
+That means, that the svn-libraries evaluate environment variables and use <i>.svn</i> 
+or <i>_svn</i> directory regarding to that value. We had chosen not to evaluate environment variables to
+get a more reliable build. Instead you have to change the settings by yourself by changing
+the exclude patterns:
+<pre>
+  &lt;defaultexcludes remove=&quot;**/.svn&quot;/&gt;
+  &lt;defaultexcludes remove=&quot;**/.svn/**&quot;/&gt;
+  &lt;defaultexcludes add=&quot;**/_svn&quot;/&gt;
+  &lt;defaultexcludes add=&quot;**/_svn/**&quot;/&gt;
+</pre>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/delete.html b/trunk/docs/manual/CoreTasks/delete.html
new file mode 100644
index 0000000..545277a
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/delete.html
@@ -0,0 +1,196 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Delete Task</title>
+</head>
+
+<body>
+
+<h2><a name="delete">Delete</a></h2>
+<h3>Description</h3>
+<p>Deletes a single file, a specified directory and all its files and
+subdirectories, or a set of files specified by one or more
+<a href="../CoreTypes/resources.html#collection">resource collection</a>s.
+The literal implication of <code>&lt;fileset&gt;</code> is that
+directories are not included; however the removal of empty directories can
+be triggered when using nested filesets by setting the
+<code>includeEmptyDirs</code> attribute to <i>true</i>. Note that this
+attribute is meaningless in the context of any of the various resource
+collection types that <i>do</i> include directories, but that no attempt
+will be made to delete non-empty directories in any case.</p>
+<p>
+If you use this task to delete temporary files created by editors
+and it doesn't seem to work, read up on the
+<a href="../dirtasks.html#defaultexcludes">default exclusion set</a>
+in <strong>Directory-based Tasks</strong>, and see the
+<code>defaultexcludes</code> attribute below.
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to delete, specified as either the simple
+     filename (if the file exists in the current base directory), a
+     relative-path filename, or a full-path filename.</td>
+    <td align="center" valign="middle" rowspan="2">At least one of the two,
+     unless nested resource collections are specified
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The directory to delete, including all its files and
+     subdirectories.<br>
+     <b>Note:</b> <code>dir</code> is <em>not</em> used
+     to specify a directory name for <code>file</code>; <code>file</code>
+     and <code>dir</code> are independent of each other.<br>
+     <b>WARNING:</b> Do <b>not</b> set <code>dir</code> to
+     <code>&quot;.&quot;</code>, <code>&quot;${basedir}&quot;</code>,
+     or the full-pathname equivalent unless you truly <em>intend</em> to
+     recursively remove the entire contents of the current base directory
+     (and the base directory itself, if different from the current working
+     directory).</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to show the name of each deleted file.</td>
+    <td align="center" valign="top">No, default &quot;false&quot;</i></td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">If the specified file or directory does not exist,
+     do not display a diagnostic message (unless Ant
+     has been invoked with the <code>-verbose</code> or
+     <code>-debug</code> switches) or modify the exit status to
+     reflect an error.
+     When set to &quot;true&quot;, if a file or directory cannot be deleted,
+     no error is reported. This setting emulates the
+     <code>-f</code> option to the Unix <em>rm</em> command.
+     Setting this to &quot;true&quot; implies setting
+     <code>failonerror</code> to &quot;false&quot;.
+    </td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Controls whether an error (such as a failure to
+    delete a file) stops the build or is merely reported to the screen.
+    Only relevant if <code>quiet</code> is &quot;false&quot;.</td>
+    <td align="center" valign="top">No, default &quot;true&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">includeemptydirs</td>
+    <td valign="top">Whether to delete empty directories
+                     when using filesets.</td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top"><em>Deprecated.</em>  Use resource collections.
+      Comma- or space-separated list of patterns of
+      files that must be deleted. All files are relative to the directory
+      specified in <code>dir</code>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top"><em>Deprecated.</em>  Use resource collections.
+      The name of a file. Each line of
+      this file is taken to be an include pattern.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top"><em>Deprecated.</em>  Use resource collections.
+      Comma- or space-separated list of patterns of
+      files that must be excluded from the deletion list.
+      All files are relative to the directory specified in <code>dir</code>.
+      No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top"><em>Deprecated.</em>  Use resource collections.
+      The name of a file. Each line of
+      this file is taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top"><em>Deprecated.</em>  Use resource collections.
+      Whether to use <a href="../dirtasks.html#defaultexcludes">
+      default excludes.</a></td>
+    <td align="center" valign="top">No, default &quot;true&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">deleteonexit</td>
+    <td valign="top">
+      Indicates whether to use File#deleteOnExit() if there is a
+      failure to delete a file, this causes the jvm to attempt
+      to delete the file when the jvm process is terminating.
+      <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No, default &quot;false&quot;</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;delete file=&quot;/lib/ant.jar&quot;/&gt;</pre>
+<p>deletes the file <code>/lib/ant.jar</code>.</p>
+<pre>  &lt;delete dir=&quot;lib&quot;/&gt;</pre>
+<p>deletes the <code>lib</code> directory, including all files
+and subdirectories of <code>lib</code>.</p>
+
+<pre>  &lt;delete&gt;
+    &lt;fileset dir=&quot;.&quot; includes=&quot;**/*.bak&quot;/&gt;
+  &lt;/delete&gt;
+</pre>
+<p>deletes all files with the extension <code>.bak</code> from the current directory
+and any subdirectories.</p>
+
+<pre>  &lt;delete includeEmptyDirs=&quot;true&quot;&gt;
+    &lt;fileset dir=&quot;build&quot;/&gt;
+  &lt;/delete&gt;
+</pre>
+<p>deletes all files and subdirectories of <code>build</code>, including
+<code>build</code> itself.</p>
+
+<pre>  &lt;delete includeemptydirs=&quot;true&quot;&gt;
+    &lt;fileset dir=&quot;build&quot; includes=&quot;**/*&quot;/&gt;
+  &lt;/delete&gt;
+</pre>
+<p>deletes all files and subdirectories of <code>build</code>, without
+<code>build</code> itself.</p>
+
+<pre>  &lt;delete includeemptydirs=&quot;true&quot;&gt;
+    &lt;fileset dir=&quot;src&quot; includes=&quot;**/.svn&quot; defaultexcludes=&quot;false&quot;/&gt;
+  &lt;/delete&gt;
+</pre>
+<p>deletes the subversion metadata directories under <code>src</code>. Because <code>.svn</code>
+is on of the <a href="../dirtasks.html#defaultexcludes">default excludes</a> you have to use the 
+<code>defaultexcludes</code> flag, otherwise Ant wont delete these directories and the files in it.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/deltree.html b/trunk/docs/manual/CoreTasks/deltree.html
new file mode 100644
index 0000000..98adf4f
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/deltree.html
@@ -0,0 +1,56 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Deltree Task</title>
+</head>
+
+<body>
+
+<h2><a name="deltree">Deltree</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the Delete task instead.</i></p>
+<h3>Description</h3>
+<p>Deletes a directory with all its files and subdirectories.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the directory to delete.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;deltree dir=&quot;dist&quot;/&gt;</pre>
+<p>deletes the directory <code>dist</code>, including its files and
+subdirectories.</p>
+<pre>  &lt;deltree dir=&quot;${dist}&quot;/&gt;</pre>
+<p>deletes the directory <code>${dist}</code>, including its files and
+subdirectories.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/dependset.html b/trunk/docs/manual/CoreTasks/dependset.html
new file mode 100644
index 0000000..cb902d6
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/dependset.html
@@ -0,0 +1,161 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>DependSet Task</title>
+</head>
+
+<body>
+
+<h2>DependSet</h2>
+
+A task to manage arbitrary dependencies between resources.
+
+<h3>Description</h3>
+
+<p>
+The dependset task compares a set of sources with a set of target
+files.  If any of the sources has been modified more recently than
+any of the target files, all of the target files are removed.
+</p>
+<p>
+Sources and target files are specified via nested
+<a href="../CoreTypes/resources.html#collection">Resource Collection</a>s;
+sources can be resources of any type, while targets are restricted to files
+only. At least one set of sources and one set of targets is required.
+</p>
+<p>
+Use a FileSet when you want to use wildcard include or exclude
+patterns and don't care about missing files.  Use a FileList when you
+want to consider the non-existence of a file as if it were out of
+date.  If there are any non-existing files in any source or target
+FileList, all target files will be removed.
+</p>
+<p>
+DependSet is useful to capture dependencies that are not or cannot be
+determined algorithmically.  For example, the <code>&lt;style&gt;</code> task only
+compares the source XML file and XSLT stylesheet against the target
+file to determined whether to restyle the source.  Using dependset you
+can extend this dependency checking to include a DTD or XSD file as
+well as other stylesheets imported by the main stylesheet.
+</p>
+
+<h3>Parameters</h3>
+
+<p>
+(none)
+</p>
+
+<h3>Parameters Specified as Nested Elements</h3>
+
+<h4>sources</h4>
+
+<p>The <code>&lt;sources&gt;</code> element is a
+<a href="../CoreTypes/resources.html#union">Union</a> into which
+arbitrary resource collections can be nested. <b>Since Ant 1.7</b>
+</p>
+
+<h4>srcfileset</h4>
+
+<p>
+The nested <code>&lt;srcfileset&gt;</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in
+this fileset will be compared against all files included in all of the
+<code>&lt;targetfileset&gt;</code> filesets and <code>&lt;targetfilelist&gt;</code>
+filelists.  Multiple <code>&lt;srcfileset&gt;</code> filesets may be specified.
+</p>
+
+<h4>srcfilelist</h4>
+
+<p>
+The nested <code>&lt;srcfilelist&gt;</code> element specifies a <a
+href="../CoreTypes/filelist.html">FileList</a>. All files included in
+this filelist will be compared against all files included in all of the 
+<code>&lt;targetfileset&gt;</code> filesets and <code>&lt;targetfilelist&gt;</code>
+filelists.  Multiple <code>&lt;srcfilelist&gt;</code> filelists may be specified.
+</p>
+
+<h4>targets</h4>
+
+<p>The <code>&lt;targets&gt;</code> element is a
+<a href="../using.html#path">Path</a> and thus can
+include any filesystem-based resource. <b>Since Ant 1.7</b>
+</p>
+
+<h4>targetfileset</h4>
+
+<p>
+The nested <code>&lt;targetfileset&gt;</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>.  All files included in
+this fileset will be compared against all files included in all of the
+<code>&lt;srcfileset&gt;</code> filesets and <code>&lt;sourcefilelist&gt;</code>
+filelists, and if any are older, they are all deleted.
+Multiple <code>&lt;targetfileset&gt;</code> filesets may be specified.
+</p>
+
+<h4>targetfilelist</h4>
+
+<p>
+The nested <code>&lt;targetfilelist&gt;</code> element specifies a <a
+href="../CoreTypes/filelist.html">FileList</a>.  All files included in
+this filelist will be compared against all files included in all of the
+<code>&lt;srcfileset&gt;</code> filesets and <code>&lt;sourcefilelist&gt;</code>
+filelists, and if any are older, they are all deleted.
+Multiple <code>&lt;targetfilelist&gt;</code> filelists may be specified.
+</p>
+
+<h3>Examples</h3>
+<blockquote> <pre>
+    &lt;dependset&gt;
+       &lt;srcfilelist
+           dir   = &quot;${dtd.dir}&quot;
+           files = &quot;paper.dtd,common.dtd&quot;/&gt;
+       &lt;srcfilelist
+           dir   = &quot;${xsl.dir}&quot;
+           files = &quot;common.xsl&quot;/&gt;
+       &lt;srcfilelist
+           dir   = &quot;${basedir}&quot;
+           files = &quot;build.xml&quot;/&gt;
+       &lt;targetfileset
+           dir      = &quot;${output.dir}&quot;
+           includes = &quot;**/*.html&quot;/&gt;
+    &lt;/dependset&gt;  </pre>
+</blockquote>
+
+<p> 
+In this example derived HTML files in the ${output.dir} directory 
+will be removed if any are out-of-date with respect to:</p>
+<ol>
+<li>the DTD of their source XML files</li>
+<li>a common DTD (imported by the main DTD)</li>
+<li>a subordinate XSLT stylesheet (imported by the main stylesheet), or</li>
+<li>the buildfile</li>
+</ol>
+
+<p>
+If any of the sources in the above example does not exist, all
+target files will also be removed.  To ignore missing sources instead,
+use filesets instead of filelists for the sources.
+</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/diagnostics.html b/trunk/docs/manual/CoreTasks/diagnostics.html
new file mode 100644
index 0000000..632da60
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/diagnostics.html
@@ -0,0 +1,49 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Diagnostics Task</title>
+</head>
+
+<body>
+
+<h2><a name="diagnostics">Diagnostics</a></h2>
+<h3>Diagnostics</h3>
+<p>
+Runs Ant's <code>-diagnostics</code> code inside Ant itself. This is good for 
+debugging Ant's configuration under an IDE. 
+<b>Since Ant 1.7.0</b>
+</p>
+
+
+<h3>Examples</h3>
+
+<pre>
+    &lt;target name="diagnostics" description="diagnostics"&gt;
+        &lt;diagnostics/&gt;
+    &lt;/target&gt;
+</pre>
+<p>
+    Prints out the current diagnostics dump.
+</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/dirname.html b/trunk/docs/manual/CoreTasks/dirname.html
new file mode 100644
index 0000000..03227b4
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/dirname.html
@@ -0,0 +1,74 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Dirname Task</title>
+</head>
+
+<body>
+
+<h2><a name="echo">Dirname</a></h2>
+<h3>Description</h3>
+<p>
+Task to determine the directory path of a specified file.
+</p>
+<p> 
+When this task executes, it will set the specified property to the
+value of the specified file (or directory) up to, but not including,
+the last path element. If the specified file is a path that ends in a
+filename, the filename will be dropped. If the specified file is just
+a filename, the directory will be the current directory.
+</p>
+  <p>
+    <em>Note:</em> This is not the same as the UNIX dirname command, which is
+    defined as "strip non-directory suffix from filename". &lt;dirname&gt;
+    determines the full directory path of the specified file.
+  </p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The path to take the dirname of.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;dirname property=&quot;antfile.dir&quot; file=&quot;${ant.file}&quot;/&gt;</pre>
+will set <code>antfile.dir</code> to the directory path for
+<code>${ant.file}</code>.
+<pre>  &lt;dirname property=&quot;foo.dirname&quot; file=&quot;foo.txt&quot;/&gt;</pre>
+will set <code>foo.dirname</code> to the project's basedir.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/ear.html b/trunk/docs/manual/CoreTasks/ear.html
new file mode 100644
index 0000000..4e5b6bf
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/ear.html
@@ -0,0 +1,213 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>EAR Task</title>
+</head>
+
+<body>
+
+<h2><a name="ear">Ear</a></h2>
+<h3>Description</h3>
+<p>An extension of the <a href="jar.html">Jar</a> task with special
+treatment for files that should end up in an Enterprise Application archive.</p>
+<p>(The Ear task is a shortcut for specifying the particular layout of a EAR file. 
+The same thing can be accomplished by using the <i>prefix</i> and <i>fullpath</i>
+attributes of zipfilesets in a Zip or Jar task.)</p>
+<p>The extended zipfileset element from the zip task (with attributes <i>prefix</i>, <i>fullpath</i>, and <i>src</i>) is available in the Ear task.</p>
+
+<p><b>Please note that the zip format allows multiple files of the same
+fully-qualified name to exist within a single archive.  This has been
+documented as causing various problems for unsuspecting users.  If you wish
+to avoid this behavior you must set the <code>duplicate</code> attribute
+to a value other than its default, <code>&quot;add&quot;</code>.</b></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the EAR file to create.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">appxml</td>
+    <td valign="top">The deployment descriptor to use (META-INF/application.xml).</td>
+    <td valign="top" align="center">Yes, unless update is set to true</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory from which to jar the files.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compress</td>
+    <td valign="top">Not only store data but also compress them,
+    defaults to true.  Unless you set the <em>keepcompression</em>
+    attribute to false, this will apply to the entire archive, not
+    only the files you've added while updating.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepcompression</td>
+    <td valign="top">For entries coming from existing archives (like
+    nested <em>zipfileset</em>s or while updating the archive), keep
+    the compression as it has been originally instead of using the
+    <em>compress</em> attribute.  Defaults false.  <em>Since Ant
+    1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The character encoding to use for filenames
+      inside the archive.  Defaults to UTF8. <strong>It is not
+      recommended to change this value as the created archive will most
+      likely be unreadable for Java otherwise.</strong></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesonly</td>
+    <td valign="top">Store only file entries, defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">manifest</td>
+    <td valign="top">the manifest file to use.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesetmanifest</td>
+    <td valign="top">behavior when a Manifest is found in a zipfileset or zipgroupfileset file is found.  Valid values are &quot;skip&quot;, &quot;merge&quot;, and &quot;mergewithoutmain&quot;.  &quot;merge&quot; will merge all of the manifests together, and merge this into any other specified manifests.  &quot;mergewithoutmain&quot; merges everything but the Main section of the manifests.  Default value is &quot;skip&quot;.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">whenmanifestonly</td>
+    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;create&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">manifestencoding</td>
+    <td valign="top">The encoding used to read the JAR manifest, when a manifest file is specified.</td>
+    <td valign="top" align="center">No, defaults to the platform encoding.</td>
+  </tr>
+  <tr>
+    <td valign="top">index</td>
+    <td valign="top">whether to create an <A
+    HREF="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index">index
+    list</A> to speed up classloading.  This is a JDK 1.3+ specific
+    feature.  Unless you specify additional jars with nested <a
+    href="#indexjars"><code>indexjars</code></a> elements, only the
+    contents of this jar will be included in the index.  Defaults to
+    false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">update</td>
+    <td valign="top">indicates whether to update or overwrite
+      the destination file if it already exists.  Default is &quot;false&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">duplicate</td>
+    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;.  The default value is &quot;add&quot;.  </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">roundup</td>
+    <td valign="top">Whether the file modification times will be
+    rounded up to the next even number of seconds.<br>
+    Zip archives store file modification times with a granularity of
+    two seconds, so the times will either be rounded up or down.  If
+    you round down, the archive will always seem out-of-date when you
+    rerun the task, so the default is to round up.  Rounding up may
+    lead to a different type of problems like JSPs inside a web
+    archive that seem to be slightly more recent than precompiled
+    pages, rendering precompilation useless.<br>
+    Defaults to true.  <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">level</td>
+    <td valign="top">Non-default level at which file compression should be
+    performed. Valid values range from 0 (no compression/fastest) to 9
+    (maximum compression/slowest). <em>Since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested elements</h3>
+
+<h4>metainf</h4>
+<p>The nested <code>metainf</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>META-INF</code> directory of the ear file. If this
+fileset includes a file named <code>MANIFEST.MF</code>, the file is
+ignored and you will get a warning.</p>
+
+<h4>manifest, indexjars, service</h4>
+These are inherited from <a href="jar.html">&lt;jar&gt;</a>
+
+<h2>Example</h2>
+<pre>
+    &lt;ear destfile=&quot;${build.dir}/myapp.ear&quot; appxml=&quot;${src.dir}/metadata/application.xml&quot;&gt;
+      &lt;fileset dir=&quot;${build.dir}&quot; includes=&quot;*.jar,*.war&quot;/&gt;
+    &lt;/ear&gt;
+</pre>
+
+
+</body>
+</html>
+
+
diff --git a/trunk/docs/manual/CoreTasks/echo.html b/trunk/docs/manual/CoreTasks/echo.html
new file mode 100644
index 0000000..dedee62
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/echo.html
@@ -0,0 +1,180 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Echo Task</title>
+</head>
+
+<body>
+
+<h2><a name="echo">Echo</a></h2>
+<h3>Description</h3>
+<p>Echoes a message to the current loggers and listeners which
+means <tt>System.out</tt> unless overridden. A <tt>level</tt>
+can be specified, which controls at what logging level the message is
+filtered at.
+<p>
+The task can also echo to a file, in which case the option to append rather
+than overwrite the file is available, and the <tt>level</tt> option is
+ignored</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">message</td>
+    <td valign="top">the message to echo.</td>
+    <td valign="top" align="center">No.  Text may also be included in a
+      character section within this element.  If neither is included a 
+      blank line will be emitted in the output.</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file to write the message to.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Append to an existing file (or
+      <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/FileWriter.html#FileWriter(java.lang.String, boolean)" target="_blank">
+      open a new file / overwrite an existing file</a>)?
+    </td>
+    <td valign="top" align="center">No - default is false.</td>
+  </tr>
+  <tr>
+    <td valign="top">level</td>
+    <td valign="top">Control the level at which this message is reported.
+            One of "error", "warning", "info", "verbose", "debug" (decreasing order)</td>
+    <td valign="top" align="center">No - default is "warning".</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">encoding to use, default is ""; the local system encoding. <em>since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>
+&lt;echo message=&quot;Hello, world&quot;/&gt;
+</pre>
+<pre>
+&lt;echo message=&quot;Embed a line break:${line.separator}&quot;/&gt;
+</pre>
+<pre>
+&lt;echo&gt;Embed another:${line.separator}&lt;/echo&gt;
+</pre>
+<pre>
+&lt;echo&gt;This is a longer message stretching over
+two lines.
+&lt;/echo&gt;
+</pre>
+<pre>
+&lt;echo&gt;
+This is a longer message stretching over
+three lines; the first line is a blank
+&lt;/echo&gt;
+</pre>
+The newline immediately following the &lt;echo&gt; tag will be part of the output.<br>
+Newlines in character data within the content of an element are not discarded by XML parsers.<br>
+See <a href="http://www.w3.org/TR/2004/REC-xml-20040204/#sec-line-ends">
+W3C Recommendation 04 February 2004 / End of Line handling
+</a> for more details.
+
+<pre>&lt;echo message=&quot;Deleting drive C:&quot; level=&quot;debug&quot;/&gt;</pre>
+A message which only appears in <tt>-debug</tt> mode.
+<pre>&lt;echo level=&quot;error&quot;&gt;
+Imminent failure in the antimatter containment facility.
+Please withdraw to safe location at least 50km away.
+&lt;/echo&gt;
+</pre>
+A message which appears even in <tt>-quiet</tt> mode.
+
+<pre>&lt;echo file="runner.csh" append="false"&gt;#\!/bin/tcsh
+java-1.3.1 -mx1024m ${project.entrypoint} $$*
+&lt;/echo&gt;</pre>
+Generate a shell script by echoing to a file.
+Note the use of a double $ symbol to stop Ant
+filtering out the single $ during variable expansion
+
+<p>Depending on the loglevel Ant runs, messages are print out or silently
+ignored:
+<table>
+<tr>
+  <th>Ant-Statement</th>
+  <th>-quiet, -q</th>
+  <th><i>no statement</th>
+  <th>-verbose, -v</th>
+  <th>-debug, -d</th>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is error message." level="error" /&gt;</pre></td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is warning message." /&gt;</pre></td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is warning message." level="warning" /&gt;</pre></td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is info message." level="info" /&gt;</pre></td>
+  <td align="center">not logged</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is verbose message." level="verbose" /&gt;</pre></td>
+  <td align="center">not logged</td>
+  <td align="center">not logged</td>
+  <td align="center">ok</td>
+  <td align="center">ok</td>
+</tr>
+<tr>
+  <td><pre>&lt;echo message="This is debug message." level="debug" /&gt;</pre></td>
+  <td align="center">not logged</td>
+  <td align="center">not logged</td>
+  <td align="center">not logged</td>
+  <td align="center">ok</td>
+</tr>
+</table>
+
+
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/echoxml.html b/trunk/docs/manual/CoreTasks/echoxml.html
new file mode 100755
index 0000000..f3ddaf1
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/echoxml.html
@@ -0,0 +1,65 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>EchoXML Task</title>
+</head>
+
+<body>
+
+<h2>EchoXML</h2>
+<h3>Description</h3>
+<p>Echo nested XML to the console or a file. <b>Since Ant 1.7</b></p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to receive the XML. If omitted nested
+      XML will be echoed to the log.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Whether to append <code>file</code>, if specified.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+Nested XML content is required.
+
+<h3>Examples</h3>
+<pre>&lt;echoxml file=&quot;subbuild.xml&quot;&gt;
+  &lt;project default=&quot;foo&quot;&gt;
+    &lt;target name=&quot;foo&quot;&gt;
+      &lt;echo&gt;foo&lt;/echo&gt;
+    &lt;/target&gt;
+  &lt;/project&gt;
+&lt;/echoxml&gt;
+</pre>
+<p>Creates an Ant buildfile, <code>subbuild.xml</code>.</p>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/exec.html b/trunk/docs/manual/CoreTasks/exec.html
new file mode 100644
index 0000000..0df7328
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/exec.html
@@ -0,0 +1,431 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>Exec Task</title>
+</head>
+
+<body>
+
+<h2><a name="exec">Exec</a></h2>
+<h3>Description</h3>
+<p>Executes a system command. When the <i>os</i> attribute is specified, then
+the command is only executed when Ant is run on one of the specified operating
+systems.</p>
+
+<p>Note that you cannot interact with the forked program, the only way
+to send input to it is via the input and inputstring attributes. Also note that
+since Ant 1.6, any attempt to read input in the forked program will receive an
+EOF (-1). This is a change from Ant 1.5, where such an attempt would block.</p>
+
+
+
+<h4>Windows Users</h4>
+<p>The <code>&lt;exec&gt;</code> task delegates to <code>Runtime.exec</code> which in turn
+apparently calls <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocess.asp">
+<code>::CreateProcess</code></a>. It is the latter Win32 function that defines
+the exact semantics of the call. In particular, if you do not put a file extension
+on the executable, only ".EXE" files are looked for, not ".COM", ".CMD" or other file
+types listed in the environment variable PATHEXT. That is only used by the shell.
+</p>
+  <p>
+    Note that <em>.bat</em> files cannot in general by executed directly.
+    One normally needs to execute the command shell executable <code>cmd</code>
+    using the <code>/c</code> switch.
+  </p>
+  <blockquote>
+<pre>
+&lt;target name="help"&gt;
+  &lt;exec executable="cmd"&gt;
+    &lt;arg value="/c"/&gt;
+    &lt;arg value="ant.bat"/&gt;
+    &lt;arg value="-p"/&gt;
+  &lt;/exec&gt;
+&lt;/target&gt;
+</pre></blockquote>
+
+<h4>Cygwin Users</h4>
+<p>The <code>&lt;exec&gt;</code> task will not understand paths such as /bin/sh
+for the executable parameter.  This is because the Java VM in which Ant is
+running is a standard Windows executable and is not aware of the Cygwin
+environment (i.e., doesn't load <code>cygwin1.dll</code>).  The only
+work-around for this is to compile a JVM under Cygwin (at your own risk).
+See for instance 
+<a href="http://java.sun.com/javase/6/docs/build/README-builds.html#cygwin">
+sun jdk 6 build instructions for cygwin</a>.
+</p>
+
+<h4>OpenVMS Users</h4>
+<p>The command specified using <code>executable</code> and
+<code>&lt;arg&gt;</code> elements is executed exactly as specified
+inside a temporary DCL script.  This has some implications:
+<ul>
+<li>paths have to be written in VMS style</li>
+<li>if your <code>executable</code> points to a DCL script remember to
+prefix it with an <code>@</code>-sign
+(e.g. <code>executable="@[FOO]BAR.COM"</code>), just as you would in a
+DCL script</li>
+</ul>
+For <code>&lt;exec&gt;</code> to work in an environment with a Java VM
+older than version 1.4.1-2 it is also <i>required</i> that the logical
+<code>JAVA$FORK_SUPPORT_CHDIR</code> is set to <code>TRUE</code> in
+the job table (see the <i>JDK Release Notes</i>).</p>
+
+<p>Please note that the Java VM provided by HP doesn't follow OpenVMS'
+conventions of exit codes.  If you run a Java VM with this task, the
+task may falsely claim that an error occurred (or silently ignore an
+error).  Don't use this task to run <code>JAVA.EXE</code>, use a
+<code>&lt;java&gt;</code> task with the <code>fork</code> attribute
+set to <code>true</code> instead as this task will follow the VM's
+interpretation of exit codes.</p>
+
+<h4>RedHat S/390 Users</h4>
+
+<p>It has been <a
+href="http://listserv.uark.edu/scripts/wa.exe?A1=ind0404&L=vmesa-l#33">reported
+on the VMESA-LISTSERV</a> that shell scripts invoked via the Ant Exec
+task must have their interpreter specified, i.e., the scripts must
+start with something like:
+
+<blockquote>
+<pre>
+#!/bin/bash
+</pre>
+</blockquote>
+
+or the task will fail as follows:
+
+<blockquote>
+<pre>
+[exec] Warning: UNIXProcess.forkAndExec native error: Exec format error
+[exec] Result: 255
+</pre>
+</blockquote>
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">command</td>
+    <td valign="top">the command to execute with all command line
+      arguments. <b>deprecated, use executable and nested
+      <code>&lt;arg&gt;</code> elements instead</b>.</td>
+    <td align="center" rowspan="2">Exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">executable</td>
+    <td valign="top">the command to execute without any command line
+      arguments.</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the directory in which the command should be executed.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">os</td>
+    <td valign="top">list of Operating Systems on which the command may be
+      executed. If the current OS's name is contained in this list, the command will
+      be executed. The OS's name is determined by the Java Virtual machine and is set
+      in the &quot;os.name&quot; system property.
+      </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">osfamily</td>
+    <td valign="top">OS family as used in the &lt;os&gt; condition.
+    <em>since Ant 1.7</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">spawn</td>
+    <td valign="top">whether or not you want the command to be spawned<br>
+    Default is false.<br>
+    If you spawn a command, its output will not be logged by ant.<br>
+    The input, output, error, and result property settings are not active when spawning a process.<br>
+    <em>since Ant 1.6</em>
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">Name of a file to which to write the output. If the error stream
+      is not also redirected to a file or property, it will appear in this output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">error</td>
+    <td valign="top">The file to which the standard error of the
+    command should be redirected.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">logError</td>
+    <td valign="top">This attribute is used when you wish to see error output in Ant's
+                     log and you are redirecting output to a file/property. The error
+                     output will not be included in the output file/property. If you
+                     redirect error with the &quot;error&quot; or &quot;errorProperty&quot;
+                     attributes, this will have no effect.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Whether output and error files should be appended to or overwritten.
+    Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputproperty</td>
+    <td valign="top">The name of a property in which the output of the
+      command should be stored. Unless the error stream is redirected to a separate
+      file or stream, this property will include the error output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property in which the standard error of the
+      command should be stored.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">input</td>
+    <td valign="top">A file from which the executed command's standard input
+                     is taken. This attribute is mutually exclusive with the
+                     inputstring attribute.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inputstring</td>
+    <td valign="top">A string which serves as the input stream for the
+                     executed command. This attribute is mutually exclusive with the
+                     input attribute.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">resultproperty</td>
+    <td valign="top">the name of a property in which the return code of the
+      command should be stored. Only of interest if failonerror=false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Stop the command if it doesn't finish within the
+      specified time (given in milliseconds).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the buildprocess if the command exits with a
+      return code signaling failure. Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failifexecutionfails</td>
+    <td valign="top">Stop the build if we can't start the program.
+      Defaults to true. </td>
+    <td align="center" valign="top">No</td>
+  </tr>  <tr>
+    <td valign="top">newenvironment</td>
+    <td valign="top">Do not propagate old environment when new environment
+      variables are specified.</td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">vmlauncher</td>
+    <td valign="top">Run command using the Java VM's execution facilities
+        where available. If set to false the underlying OS's shell,
+        either directly or through the antRun scripts, will be used.
+        Under some operating systems, this gives access to facilities
+        not normally available through the VM including, under Windows,
+        being able to execute scripts, rather than their associated
+        interpreter.  If you want to specify the name of the
+        executable as a relative path to the directory given by the
+        dir attribute, it may become necessary to set vmlauncher to
+        false as well.</td>
+    <td align="center" valign="top">No, default is <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">resolveexecutable</td>
+    <td valign="top">When this attribute is true, the name of the executable
+                     is resolved firstly against the project basedir and
+                     if that does not exist, against the execution
+                     directory if specified. On Unix systems, if you only
+                     want to allow execution of commands in the user's path,
+                     set this to false.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">searchpath</td>
+    <td valign="top">When this attribute is true, then
+                     system path environment variables will
+                     be searched when resolving the location
+                     of the executable. <em>since Ant 1.6.3</em></td>
+    <td align="center" valign="top">No, default is <i>false</i></td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;exec dir=&quot;${src}&quot; executable=&quot;cmd.exe&quot; os=&quot;Windows 2000&quot; output=&quot;dir.txt&quot;&gt;
+  &lt;arg line=&quot;/c dir&quot;/&gt;
+&lt;/exec&gt;</pre>
+</blockquote>
+<h3>Parameters specified as nested elements</h3>
+<h4>arg</h4>
+<p>Command line arguments should be specified as nested
+<code>&lt;arg&gt;</code> elements. See <a
+href="../using.html#arg">Command line arguments</a>.</p>
+<h4><a name="env">env</a></h4>
+<p>It is possible to specify environment variables to pass to the
+system command via nested <code>&lt;env&gt;</code> elements.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">key</td>
+    <td valign="top">
+      The name of the environment variable.
+      <br/>
+      <em>Note: (Since Ant 1.7)</em>
+      For windows, the name is case-insensitive.
+    </td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The literal value for the environment variable.</td>
+    <td align="center" rowspan="3">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+    <td valign="top">The value for a PATH like environment
+      variable. You can use ; or : as path separators and Ant will
+      convert it to the platform's local conventions.</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The value for the environment variable. Will be
+      replaced by the absolute filename of the file by Ant.</td>
+  </tr>
+</table>
+<a name="redirector"><h4>redirector</h4></a>
+<i><b>Since Ant 1.6.2</b></i>
+<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
+can be specified.  In general, the attributes of the redirector behave
+as the corresponding attributes available at the task level.  The most
+notable peculiarity stems from the retention of the &lt;exec&gt;
+attributes for backwards compatibility.  Any file mapping is done
+using a <CODE>null</CODE> sourcefile; therefore not all
+<a href="../CoreTypes/mapper.html">Mapper</a> types will return
+results.  When no results are returned, redirection specifications
+will fall back to the task level attributes.  In practice this means that
+defaults can be specified for input, output, and error output files.
+</p>
+<h3>Errors and return codes</h3>
+By default the return code of a <code>&lt;exec&gt;</code> is ignored; when you set
+<code>failonerror="true"</code> then any return code signaling failure
+(OS specific) causes the build to fail. Alternatively, you can set
+<code>resultproperty</code> to the name of a property and have it assigned to
+the result code (barring immutability, of course).
+<p>
+If the attempt to start the program fails with an OS dependent error code,
+then <code>&lt;exec&gt;</code> halts the build unless <code>failifexecutionfails</code>
+is set to <code>false</code>. You can use that to run a program if it exists, but
+otherwise do nothing.
+<p>
+What do those error codes mean? Well, they are OS dependent. On Windows
+boxes you have to look at
+<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes__0-499_.asp">
+the documentation</a>; error code 2 means 'no such program', which usually means
+it is not on the path. Any time you see such an error from any Ant task, it is
+usually not an Ant bug, but some configuration problem on your machine.
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;exec executable=&quot;emacs&quot;&gt;
+  &lt;env key=&quot;DISPLAY&quot; value=&quot;:1.0&quot;/&gt;
+&lt;/exec&gt;
+</pre></blockquote>
+<p>starts <code>emacs</code> on display 1 of the X Window System.</p>
+
+<blockquote><pre>
+&lt;property environment=&quot;env&quot;/&gt;
+&lt;exec ... &gt;
+  &lt;env key=&quot;PATH&quot; path=&quot;${env.PATH}:${basedir}/bin&quot;/&gt;
+&lt;/exec&gt;
+</pre></blockquote>
+<p>adds <code>${basedir}/bin</code> to the <code>PATH</code> of the
+system command.</p>
+
+<blockquote><pre>
+&lt;property name="browser" location="C:/Program Files/Internet Explorer/iexplore.exe"/&gt;
+&lt;property name="file" location="ant/docs/manual/index.html"/&gt;
+
+&lt;exec executable="${browser}" spawn="true"&gt;
+    &lt;arg value="${file}"/&gt;
+&lt;/exec&gt;
+</pre></blockquote>
+<p>Starts the <i>${browser}</i> with the specified <i>${file}</i> and end the
+Ant process. The browser will remain.</p>
+
+<blockquote><pre>
+&lt;exec executable=&quot;cat&quot;&gt;
+    &lt;redirector outputproperty=&quot;redirector.out&quot;
+                errorproperty=&quot;redirector.err&quot;
+                inputstring=&quot;blah before blah&quot;&gt;
+        &lt;inputfilterchain&gt;
+            &lt;replacestring from=&quot;before&quot; to=&quot;after&quot;/&gt;
+        &lt;/inputfilterchain&gt;
+        &lt;outputmapper type=&quot;merge&quot; to=&quot;redirector.out&quot;/&gt;
+        &lt;errormapper type=&quot;merge&quot; to=&quot;redirector.err&quot;/&gt;
+    &lt;/redirector&gt;
+&lt;/exec&gt;
+</pre></blockquote>
+
+Sends the string &quot;blah before blah&quot; to the &quot;cat&quot; executable,
+using an <a href="../CoreTypes/filterchain.html">&lt;inputfilterchain&gt;</a>
+to replace &quot;before&quot; with &quot;after&quot; on the way in.
+Output is sent to the file &quot;redirector.out&quot; and stored
+in a property of the same name.  Similarly, error output is sent to
+a file and a property, both named &quot;redirector.err&quot;.
+
+
+<p><b>Note:</b> do not try to specify arguments using
+a simple arg-element and separate them by spaces. This results in
+only a single argument containing the entire string.</p>
+<p>
+<b>Timeouts: </b> If a timeout is specified, when it is reached the
+sub process is killed and a message printed to the log. The return
+value of the execution will be "-1", which will halt the build if
+<tt>failonerror=true</tt>, but be ignored otherwise.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/fail.html b/trunk/docs/manual/CoreTasks/fail.html
new file mode 100644
index 0000000..0eb1741
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/fail.html
@@ -0,0 +1,143 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Fail Task</title>
+</head>
+
+<body>
+
+<h2><a name="fail">Fail</a></h2>
+<h3>Description</h3>
+<p>Exits the current build (just throwing a BuildException), optionally printing additional information.</p>
+<p>The message of the Exception can be set via the message attribute
+or character data nested into the element.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">message</td>
+    <td valign="top">A message giving further information on why the build exited</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only fail if a property of the given name exists
+      in the current project</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only fail if a property of the given name doesn't
+      exist in the current project</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">status</td>
+    <td valign="top">Exit using the specified status code;
+      assuming the generated Exception is not caught, the
+      JVM will exit with this status. <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<p>As an alternative to the <i>if</i>/<i>unless</i> attributes,
+  conditional failure can be achieved using a single nested
+  <code>&lt;condition&gt;</code> element, which should contain exactly one
+  core or custom condition.  For information about conditions, see
+  <a href="conditions.html">here</a>.<br><b>Since Ant 1.6.2</b>
+</p>
+
+<h3>Examples</h3>
+
+<pre>  &lt;fail/&gt;</pre>
+<p>will exit the current build with no further information given.</p>
+<pre>
+BUILD FAILED
+
+build.xml:4: No message
+</pre>
+
+<pre>  &lt;fail message=&quot;Something wrong here.&quot;/&gt;</pre>
+<p>will exit the current build and print something
+  like the following to wherever your output goes:
+</p>
+<pre>
+BUILD FAILED
+
+build.xml:4: Something wrong here.
+</pre>
+
+<pre>  &lt;fail&gt;Something wrong here.&lt;/fail&gt;</pre>
+<p>will give the same result as above.</p>
+
+<pre>  &lt;fail unless=&quot;thisdoesnotexist&quot;/&gt;</pre>
+<p>will exit the current build and print something
+  like the following to wherever your output goes:
+</p>
+<pre>
+BUILD FAILED
+
+build.xml:2: unless=thisdoesnotexist
+</pre>
+
+Using a condition to achieve the same effect:
+
+<pre>
+  &lt;fail&gt;
+     &lt;condition&gt;
+       &lt;not&gt;
+         &lt;isset property=&quot;thisdoesnotexist&quot;/&gt;
+       &lt;/not&gt;
+     &lt;/condition&gt;
+   &lt;/fail&gt;
+</pre>
+
+<p>Output:</p>
+<pre>
+BUILD FAILED
+
+build.xml:2: condition satisfied
+</pre>
+
+<pre>
+&lt;fail message=&quot;Files are missing.&quot;&gt;
+    &lt;condition&gt;
+        &lt;not&gt;
+            &lt;resourcecount count=&quot;2&quot;&gt;
+                &lt;fileset id=&quot;fs&quot; dir=&quot;.&quot; includes=&quot;one.txt,two.txt&quot;/&gt;
+            &lt;/resourcecount&gt;
+        &lt;/not&gt;
+    &lt;/condition&gt;
+&lt;/fail&gt;
+</pre>
+<p>Will check that both files <i>one.txt</i> and <i>two.txt</i> are present otherwise the build
+will fail.</p>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/filter.html b/trunk/docs/manual/CoreTasks/filter.html
new file mode 100644
index 0000000..16ba88c
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/filter.html
@@ -0,0 +1,79 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Filter Task</title>
+</head>
+
+<body>
+
+<h2><a name="filter">Filter</a></h2>
+<h3>Description</h3>
+<p>Sets a token filter for this project or read multiple token filter from
+an input file and sets these as filters.
+Token filters are used by all tasks that perform file copying operations
+through the Project commodity methods. See the warning
+<a href="../using.html#filters"><em>here</em></a> before using.</p>
+<p>Note 1: the token string must not contain the separators chars (@).<br>
+Note 2: Either token and value attributes must be provided, or only the
+filtersfile attribute.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">token</td>
+    <td valign="top">the token string without @</td>
+    <td align="center" valign="top">Yes*</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the string that should be put to replace the token when the 
+      file is copied</td>
+    <td align="center" valign="top">Yes*</td>
+  </tr>
+  <tr>
+    <td valign="top">filtersfile</td>
+    <td valign="top">The file from which the filters must be read. This file must be a formatted as a property file. </td>
+    <td align="center" valign="top">Yes*</td>
+  </tr>
+</table>
+<p>* see notes 1 and 2 above parameters table.</p>
+<h3>Examples</h3>
+<pre>  &lt;filter token=&quot;year&quot; value=&quot;2000&quot;/&gt;
+  &lt;copy todir=&quot;${dest.dir}&quot; filtering=&quot;true&quot;&gt;
+    &lt;fileset dir=&quot;${src.dir}&quot;/&gt;
+  &lt;/copy&gt;</pre> 
+<p>will copy recursively all the files from the <i>src.dir</i> directory into
+the <i>dest.dir</i> directory replacing all the occurrences of the string <i>@year@</i>
+with <i>2000.</i></p>
+<pre>  &lt;filter filtersfile=&quot;deploy_env.properties&quot;/&gt;</pre>
+will read all property entries from the <i>deploy_env.properties</i> file
+and set these as filters.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/fixcrlf.html b/trunk/docs/manual/CoreTasks/fixcrlf.html
new file mode 100644
index 0000000..83f16fd
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/fixcrlf.html
@@ -0,0 +1,327 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FixCRLF Task</title>
+</head>
+
+<body>
+
+<h2><a name="fixcrlf">FixCRLF</a></h2>
+<h3>Description</h3>
+  <p>
+    Adjusts a text file to local conventions.
+  </p>
+
+  <p>
+    The set of files to be adjusted can be refined with the
+    <i>includes</i>, <i>includesfile</i>, <i>excludes</i>,
+    <i>excludesfile</i> and <i>defaultexcludes</i>
+    attributes. Patterns provided through the <i>includes</i> or
+    <i>includesfile</i> attributes specify files to be
+    included. Patterns provided through the <i>exclude</i> or
+    <i>excludesfile</i> attribute specify files to be
+    excluded. Additionally, default exclusions can be specified with
+    the <i>defaultexcludes</i> attribute. See the section on <a
+    href="../dirtasks.html#directorybasedtasks">directory-based
+    tasks</a>, for details of file inclusion/exclusion patterns
+    and their usage.
+  </p>
+
+  <p>
+    This task forms an implicit
+    <a href="../CoreTypes/fileset.html">FileSet</a> and
+    supports all attributes of <code>&lt;fileset&gt;</code>
+    (<code>dir</code> becomes <code>srcdir</code>) as well as the nested
+    <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+    <code>&lt;patternset&gt;</code> elements.
+  </p>
+
+  <p>
+    The output file is only written if it is a new file, or if it
+    differs from the existing file.  This prevents spurious
+    rebuilds based on unchanged files which have been regenerated
+    by this task.
+  </p>
+
+  <p>
+    Since <b>Ant 1.7</b>, this task can be used in a
+    <a href="../CoreTypes/filterchain.html">filterchain</a>.
+  </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="center" rowspan="2"><b>Attribute</b></td>
+    <td valign="center" rowspan="2"><b>Description</b></td>
+    <td align="center" valign="top" colspan="2"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="center"><b>As Task</b></td>
+    <td valign="center"><b>As Filter</b></td>
+  </tr>
+  <tr>
+    <td valign="top">srcDir</td>
+    <td valign="top">Where to find the files to be fixed up.</td>
+    <td valign="top" align="center" rowspan="2">One of these</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">Name of a single file to fix. <b>Since Ant 1.7</b></td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">destDir</td>
+    <td valign="top">Where to place the corrected files.  Defaults to
+      srcDir (replacing the original file).</td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern.</td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern.</td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.
+    </td>
+    <td valign="top" align="center">No</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding of the files.</td>
+    <td align="center">No; defaults to default JVM encoding.</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">outputencoding</td>
+    <td valign="top">The encoding to use when writing the files.
+                     <b>Since Ant 1.7</b></td>
+    <td align="center">No; defaults to the value of the encoding attribute.</td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">preservelastmodified</td>
+    <td valign="top">Whether to preserve the last modified
+                     date of source files. <b>Since Ant 1.6.3</b></td>
+    <td align="center">No; default is <i>false</i></td>
+    <td bgcolor="#CCCCCC">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">eol</td>
+    <td valign="top">
+      Specifies how end-of-line (EOL) characters are to be
+      handled.  The EOL characters are CR, LF and the pair CRLF.
+      Valid values for this property are:
+      <ul>
+        <li>asis: leave EOL characters alone</li>
+        <li>cr: convert all EOLs to a single CR</li>
+        <li>lf: convert all EOLs to a single LF</li>
+        <li>crlf: convert all EOLs to the pair CRLF</li>
+        <li>mac: convert all EOLs to a single CR</li>
+        <li>unix: convert all EOLs to a single LF</li>
+        <li>dos: convert all EOLs to the pair CRLF</li>
+      </ul>
+      Default is based on the platform on which you are running this task.
+      For Unix platforms (including Mac OS X), the default is &quot;lf&quot;.
+      For DOS-based systems (including Windows), the default is
+      &quot;crlf&quot;.
+      For Mac environments other than OS X, the default is &quot;cr&quot;.
+      <p>
+        This is the preferred method for specifying EOL.  The
+        &quot;<i><b>cr</b></i>&quot; attribute (see below) is
+        now deprecated.
+      </p>
+      <p>
+        <i>N.B.</i>: One special case is recognized. The three
+        characters CR-CR-LF are regarded as a single EOL.
+        Unless this property is specified as &quot;asis&quot;,
+        this sequence will be converted into the specified EOL
+        type.
+      </p>
+    </td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cr</td>
+    <td valign="top">
+      <i><b>Deprecated.</b></i> Specifies how CR characters are
+      to be handled at end-of-line (EOL).  Valid values for this
+      property are:
+      <ul>
+        <li>asis: leave EOL characters alone.</li>
+        <li>
+          add: add a CR before any single LF characters. The
+          intent is to convert all EOLs to the pair CRLF.
+        </li>
+        <li>
+          remove: remove all CRs from the file.  The intent is
+          to convert all EOLs to a single LF.
+        </li>
+      </ul>
+      Default is based on the platform on which you are running
+      this task.  For Unix platforms, the default is &quot;remove&quot;.
+      For DOS based systems (including Windows), the default is
+      &quot;add&quot;.
+      <p>
+        <i>N.B.</i>: One special case is recognized. The three
+        characters CR-CR-LF are regarded as a single EOL.
+        Unless this property is specified as &quot;asis&quot;,
+        this sequence will be converted into the specified EOL
+        type.
+      </p>
+    </td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">javafiles</td>
+    <td valign="top">
+      Used only in association with the
+      &quot;<i><b>tab</b></i>&quot; attribute (see below), this
+      boolean attribute indicates whether the fileset is a set
+      of java source files
+      (&quot;yes&quot;/&quot;no&quot;). Defaults to
+      &quot;no&quot;.  See notes in section on &quot;tab&quot;.
+    </td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tab</td>
+    <td valign="top">Specifies how tab characters are to be handled.  Valid
+      values for this property are:
+      <ul>
+      <li>add: convert sequences of spaces which span a tab stop to tabs</li>
+      <li>asis: leave tab and space characters alone</li>
+      <li>remove: convert tabs to spaces</li>
+      </ul>
+      Default for this parameter is &quot;asis&quot;.
+      <p>
+        <i>N.B.</i>: When the attribute
+        &quot;<i><b>javafiles</b></i>&quot; (see above) is
+        &quot;true&quot;, literal TAB characters occurring
+        within Java string or character constants are never
+        modified.  This functionality also requires the
+        recognition of Java-style comments.
+      </p>
+      <p>
+  	<i>N.B.</i>: There is an incompatibility between this
+  	and the previous version in the handling of white
+  	space at the end of lines.  This version does
+  	<i><b>not</b></i> remove trailing whitespace on lines.
+      </p>
+    </td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tablength</td>
+    <td valign="top">TAB character interval. Valid values are between
+      2 and 80 inclusive.  The default for this parameter is 8.</td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">eof</td>
+    <td valign="top">Specifies how DOS end of file (control-Z) characters are
+      to be handled.  Valid values for this property are:
+      <ul>
+      <li>add: ensure that there is an EOF character at the end of the file</li>
+      <li>asis: leave EOF characters alone</li>
+      <li>remove: remove any EOF character found at the end</li>
+      </ul>
+      Default is based on the platform on which you are running this task.
+      For Unix platforms, the default is remove.  For DOS based systems
+      (including Windows), the default is asis.
+      </td>
+    <td valign="top" align="center" colspan="2">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fixlast</td>
+    <td valign="top">Whether to add a missing EOL to the last line
+                     of a processed file. <b>Since Ant 1.6.1</b></td>
+    <td align="center" colspan="2">No; default is <i>true</i></td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>&lt;fixcrlf srcdir=&quot;${src}&quot; includes=&quot;**/*.sh&quot;
+         eol=&quot;lf&quot; eof=&quot;remove&quot; /&gt;</pre>
+<p>Replaces EOLs with LF characters and removes eof characters from
+  the shell scripts.  Tabs and spaces are left as is.</p>
+<pre>&lt;fixcrlf srcdir=&quot;${src}&quot;
+         includes=&quot;**/*.bat&quot; eol=&quot;crlf&quot; /&gt;</pre>
+<p>Replaces all EOLs with cr-lf pairs in the batch files.
+  Tabs and spaces are left as is.
+  EOF characters are left alone if run on
+  DOS systems, and are removed if run on Unix systems.</p>
+<pre>&lt;fixcrlf srcdir=&quot;${src}&quot;
+         includes=&quot;**/Makefile&quot; tab=&quot;add&quot; /&gt;</pre>
+<p>Sets EOLs according to local OS conventions, and
+  converts sequences of spaces and tabs to the minimal set of spaces and
+  tabs which will maintain spacing within the line.  Tabs are
+  set at 8 character intervals.  EOF characters are left alone if
+  run on DOS systems, and are removed if run on Unix systems.
+  Many versions of make require tabs prior to commands.</p>
+  <pre>&lt;fixcrlf srcdir=&quot;${src}&quot; includes=&quot;**/*.java&quot;
+         tab=&quot;remove&quot; tablength=&quot;3&quot;
+         eol=&quot;lf&quot; javafiles=&quot;yes&quot; /&gt;</pre>
+<p>
+  Converts all EOLs in the included java source files to a
+  single LF.  Replace all TAB characters except those in string
+  or character constants with spaces, assuming a tab width of 3.
+  If run on a unix system, any CTRL-Z EOF characters at the end
+  of the file are removed.  On DOS/Windows, any such EOF
+  characters will be left untouched.
+</p>
+<pre>&lt;fixcrlf srcdir=&quot;${src}&quot;
+         includes=&quot;**/README*&quot; tab=&quot;remove&quot; /&gt;</pre>
+<p>Sets EOLs according to local OS conventions, and
+  converts all tabs to spaces, assuming a tab width of 8.
+  EOF characters are left alone if run on
+  DOS systems, and are removed if run on Unix systems.
+  You never know what editor a user will use to browse READMEs.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/genkey.html b/trunk/docs/manual/CoreTasks/genkey.html
new file mode 100644
index 0000000..96959c2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/genkey.html
@@ -0,0 +1,125 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>GenKey Task</title>
+</head>
+
+<body>
+
+<h2><a name="genkey">GenKey</a></h2>
+<h3>Description</h3>
+<p>Generates a key in a keystore. </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">alias</td>
+    <td valign="top">the alias to add under</td>
+    <td valign="top" align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">storepass</td>
+    <td valign="top">password for keystore integrity. Must
+	be at least 6 characters long</td>
+    <td valign="top" align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">keystore</td>
+    <td valign="top">keystore location</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">storetype</td>
+    <td valign="top">keystore type</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keypass</td>
+    <td valign="top">password for private key (if different)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sigalg</td>
+    <td valign="top">the algorithm to use in signing</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keyalg</td>
+    <td valign="top">the method to use when generating name-value pair</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">(true | false) verbose output when signing</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dname</td>
+    <td valign="top">The distinguished name for entity</td>
+    <td valign="top" align="center">Yes if dname element unspecified</td>
+  </tr>
+  <tr>
+    <td valign="top">validity</td>
+    <td valign="top">(integer) indicates how many days certificate is valid</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keysize</td>
+    <td valign="top">(integer) indicates the size of key generated</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<p>Alternatively you can specify the distinguished name by creating a
+sub-element named dname and populating it with param elements that
+have a name and a value. When using the subelement it is automatically
+encoded properly and commas (&quot;<code>,</code>&quot;) are replaced
+with &quot;<code>\,</code>&quot;.</p>
+
+<p>The following two examples are identical: </p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;genkey alias=&quot;apache-group&quot; storepass=&quot;secret&quot; 
+  dname=&quot;CN=Ant Group, OU=Jakarta Division, O=Apache.org, C=US&quot;/&gt;
+</pre></blockquote>
+
+<blockquote>
+  <pre>
+&lt;genkey alias=&quot;apache-group&quot; storepass=&quot;secret&quot; &gt;
+  &lt;dname&gt;
+    &lt;param name=&quot;CN&quot; value=&quot;Ant Group&quot;/&gt;
+    &lt;param name=&quot;OU&quot; value=&quot;Jakarta Division&quot;/&gt;
+    &lt;param name=&quot;O&quot;  value=&quot;Apache.Org&quot;/&gt;
+    &lt;param name=&quot;C&quot;  value=&quot;US&quot;/&gt;
+  &lt;/dname&gt;
+&lt;/genkey&gt;</pre>
+</blockquote>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/get.html b/trunk/docs/manual/CoreTasks/get.html
new file mode 100644
index 0000000..1b9929c
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/get.html
@@ -0,0 +1,125 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Get Task</title>
+</head>
+
+<body>
+
+<h2><a name="get">Get</a></h2>
+<h3>Description</h3>
+<p>Gets a file from a URL. When the verbose option is &quot;on&quot;, this task
+displays a '.' for every 100 Kb retrieved. Any URL schema supported by
+the runtime is valid here, including http:, ftp: and jar:; 
+https: is only valid if the appropriate support is added to the pre-1.4 Java
+runtimes. 
+ 
+</p>
+The <i>usetimestamp</i> option enables you to control downloads so that the remote file is
+only fetched if newer than the local copy. If there is no local copy, the download always takes 
+place. When a file is downloaded, the timestamp of the downloaded file is set to the remote timestamp,
+if  the JVM is Java1.2 or later. 
+NB: This timestamp facility only works on downloads using the HTTP protocol. 
+<p>
+A username and password can be specified, in which case basic 'slightly encoded
+plain text' authentication is used. This is only secure over an HTTPS link.
+</p>
+<p>
+<b>Proxies</b>. Since Ant1.7, Ant running on Java1.5 or later defaults to 
+    <a href="../proxy.html">using
+    the proxy settings of the operating system</a>. There is also the  
+ <a href="../OptionalTasks/setproxy.html">&lt;setproxy&gt;</a> task for
+    earlier Java versions. With proxies turned on, <code>&lt;get&gt;</code> requests against
+    localhost may not work as expected, if the request is relayed to the proxy.
+    The <code>-noproxy</code> option can be used to turn this feature off.
+</p>
+ 
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">the URL from which to retrieve a file.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the file where to store the retrieved file.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">show verbose progress information (&quot;on&quot;/&quot;off&quot;).</td>
+    <td align="center" valign="top">No; default "false"</td>
+  </tr>
+  <tr>
+    <td valign="top">ignoreerrors</td>
+    <td valign="top">Log errors but don't treat as fatal.</td>
+    <td align="center" valign="top">No; default "false"</td>
+  </tr>
+  <tr>
+    <td valign="top">usetimestamp</td>
+    <td valign="top">conditionally download a file based on the timestamp of the
+    local copy. HTTP only</td>
+    <td align="center" valign="top">No; default "false"</td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">username for 'BASIC' http authentication</td>
+    <td align="center" valign="top">if password is set</td>
+  </tr>  
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">password: required </td>
+    <td align="center" valign="top">if username is set</td>
+  </tr>  
+
+</table>
+<h3>Examples</h3>
+<pre>  &lt;get src=&quot;http://ant.apache.org/&quot; dest=&quot;help/index.html&quot;/&gt;</pre>
+<p>Gets the index page of http://ant.apache.org/, and stores it in the file <code>help/index.html</code>.</p>
+
+<pre>  &lt;get src=&quot;http://www.apache.org/dist/ant/KEYS&quot; 
+    dest=&quot;KEYS&quot; 
+    verbose=&quot;true&quot;
+    usetimestamp=&quot;true&quot;/&gt;</pre>
+<p>
+Gets the PGP keys of Ant's (current and past) release managers, if the local copy
+is missing or out of date. Uses the verbose option 
+for progress information.
+</p>
+
+<pre>  &lt;get src=&quot;https://insecure-bank.org/statement/user=1214&quot; 
+    dest=&quot;statement.html&quot; 
+    username="1214";
+    password="secret"/&gt;</pre>
+<p>
+Fetches some file from a server with access control. Because https is being used the
+fact that basic auth sends passwords in plaintext is moot.
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/gunzip.html b/trunk/docs/manual/CoreTasks/gunzip.html
new file mode 100644
index 0000000..32e2cf2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/gunzip.html
@@ -0,0 +1,29 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>GUnZip Task</title>
+</head>
+
+<body>
+This document's new home is <A HREF="unpack.html">here</A>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/gzip.html b/trunk/docs/manual/CoreTasks/gzip.html
new file mode 100644
index 0000000..6054d31
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/gzip.html
@@ -0,0 +1,29 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>GZip Task</title>
+</head>
+
+<body>
+This document's new home is <A HREF="pack.html">here</A>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/import.html b/trunk/docs/manual/CoreTasks/import.html
new file mode 100644
index 0000000..64541a9
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/import.html
@@ -0,0 +1,172 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>Import Task</title>
+</head>
+<body>
+  <h2><a name="import">Import</a></h2>
+  <h3>Description</h3>
+  <p>
+    Imports another build file into the current project.
+  </p>
+  <p>
+    On execution it will read another Ant file into
+    the same Project. This means that it basically works like the 
+    <a href="http://ant.apache.org/faq.html#xml-entity-include">Entity
+      Includes as explained in the Ant FAQ</a>, as if the imported file was
+    contained in the importing file, minus the top <code>&lt;project&gt;</code>
+    tag.
+  </p>
+  <p>
+    The import task may only be used as a top-level task. This means that
+    it may not be used in a target.
+  </p>
+  <p>
+There are two further functional aspects that pertain to this task and
+that are not possible with entity includes:
+<ul>
+  <li>target overriding</li>
+  <li>special properties</li>
+</ul>
+  </p>
+<h4>Target overriding</h4>
+
+<p>If a target in the main file is also present in at least one of the
+imported files, the one from the main file takes precedence.</p>
+
+<p>So if I import for example a <i>docsbuild.xml</i> file named <b>builddocs</b>,
+that contains a &quot;<b>docs</b>&quot; target, I can redefine it in my main
+buildfile and that is the one that will be called. This makes it easy to
+keep the same target name, so that the overriding target is still called
+by any other targets--in either the main or imported buildfile(s)--for which
+it is a dependency, with a different implementation. The target from <i>docsbuild.xml</i> is
+made available by the name &quot;<b>builddocs</b><b>.docs</b>&quot;.
+This enables the new implementation to call the old target, thus
+<i>enhancing</i> it with tasks called before or after it.</p>
+
+<h4>Special Properties</h4>
+
+<p>Imported files are treated as they are present in the main
+buildfile. This makes it easy to understand, but it makes it impossible
+for them to reference files and resources relative to their path.
+Because of this, for every imported file, Ant adds a property that
+contains the path to the imported buildfile. With this path, the
+imported buildfile can keep resources and be able to reference them
+relative to its position.</p>
+
+<p>So if I import for example a <i>docsbuild.xml</i> file named <b>builddocs</b>,
+I can get its path as <b>ant.file.builddocs</b>, similarly to the <b>ant.file</b>
+property of the main buildfile.</p>
+
+<p>Note that &quot;builddocs&quot; is not the filename, but the name attribute
+present in the imported project tag.</p>
+  <p>
+    If import file does not have a name attribute, the ant.file.projectname
+    property will not be set.
+  </p>
+
+<h4>Resolving files against the imported file</h4>
+
+<p>Suppose your main build file called <code>importing.xml</code>
+imports a build file <code>imported.xml</code>, located anywhere on
+the file system, and <code>imported.xml</code> reads a set of
+properties from <code>imported.properties</code>:</p>
+
+<pre>&lt;!-- importing.xml --&gt;
+&lt;project name="importing" basedir="." default="..."&gt;
+&nbsp; &lt;import file="${path_to_imported}/imported.xml"/&gt;
+&lt;/project&gt;
+
+&lt;!-- imported.xml --&gt;
+&lt;project name="imported" basedir="." default="..."&gt;
+&nbsp; &lt;property file="imported.properties"/&gt;
+&lt;/project&gt;
+</pre>
+
+<p>This snippet however will resolve <code>imported.properties</code>
+against the basedir of <code>importing.xml</code>, because the basedir
+of <code>imported.xml</code> is ignored by Ant. The right way to use
+<code>imported.properties</code> is:</p>
+
+<pre>
+&lt;!-- imported.xml --&gt;
+&lt;project name="imported" basedir="." default="..."&gt;
+&nbsp; &lt;dirname property="imported.basedir" file="${ant.file.imported}"/&gt;
+&nbsp; &lt;property file="${imported.basedir}/imported.properties"/&gt;
+&lt;/project&gt;
+</pre>
+
+<p>As explained above <code>${ant.file.imported}</code> stores the
+path of the build script, that defines the project called
+<code>imported</code>, (in short it stores the path to
+<code>imported.xml</code>) and <a
+href="dirname.html"><code>&lt;dirname&gt;</code></a> takes its
+directory. This technique also allows <code>imported.xml</code> to be
+used as a standalone file (without being imported in other
+project).</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tbody>
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">
+        file
+      </td>
+      <td valign="top">
+        The file to import. If this is a relative file name, the file name will be resolved
+        relative to the <i>importing</i> file. <b>Note</b>, this is unlike most other
+        ant file attributes, where relative files are resolved relative to ${basedir}.
+      </td>
+      <td valign="top" align="center">Yes</td>
+    </tr>
+    <tr>
+      <td valign="top">
+        optional
+      </td>
+      <td valign="top">
+        If true, do not stop the build if the file does not exist,
+        default is false.
+      </td>
+      <td valign="top" align="center">No</td>
+    </tr>
+  </tbody>
+</table>
+
+<h3>Examples</h3>
+<pre>&nbsp; &lt;import file=&quot;../common-targets.xml&quot;/&gt;
+</pre>
+
+<p>Imports targets from the common-targets.xml file that is in a parent
+directory.</p>
+
+<pre>&nbsp; &lt;import file=&quot;${deploy-platform}.xml&quot;/&gt;
+</pre>
+
+<p>Imports the project defined by the property deploy-platform</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/input.html b/trunk/docs/manual/CoreTasks/input.html
new file mode 100644
index 0000000..4671fa2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/input.html
@@ -0,0 +1,195 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Input Task</title>
+</head>
+
+<body>
+
+<h2><a name="input">Input</a></h2>
+<h3>Description</h3>
+
+<p>Allows user interaction during the build process by prompting for
+input.  To do so, it uses the configured 
+<a href="../inputhandler.html">InputHandler</a>.</p>
+
+<p>The prompt can be set via the message attribute or as character
+data nested into the element.</p>
+
+<p>Optionally a set of valid input arguments can be defined via the
+validargs attribute. Input task will not accept a value that doesn't match
+one of the predefined.</p>
+
+<p>Optionally a property can be created from the value entered by the
+user. This property can then be used during the following build
+run. Input behaves according to <a href="property.html">property
+task</a> which means that existing properties cannot be overriden.
+Since Ant 1.6, <code>&lt;input&gt;</code> will not prompt for input if
+a property should be set by the task that has already been set in the
+project (and the task wouldn't have any effect).</p>
+
+<p>A regular complaint about this task is that it echoes characters to the
+console, this is a critical security defect, we must fix it immediately, etc, etc.
+We know it leaves something to be desired, but the problem is Java, not Ant.
+There is nothing we can do to stop the console echoing. </p>
+
+<p>
+IDE behaviour depends upon the IDE: some hang waiting for input, some let you
+type it in. For this situation, place the password in a (secured) property
+file and load in before the input task.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">message</td>
+    <td valign="top">the Message which gets displayed to the user
+    during the build run.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">validargs</td>
+    <td valign="top">comma separated String containing valid input
+    arguments. If set, input task will reject any input not defined
+    here.  Validargs are compared case sensitive. If you want 'a' and
+    'A' to be accepted you will need to define both arguments within
+    validargs.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">addproperty</td>
+    <td valign="top">the name of a property to be created from
+    input. Behaviour is equal to <a href="property.html">property
+    task</a> which means that existing properties cannot be
+    overridden.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultvalue</td>
+    <td valign="top">Defines the default value of the property to be
+    created from input.  Property value will be set to default if no
+    input is received.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters Specified as Nested Elements</h3>
+<h4>Handler</h4>
+<p>Since <b>Ant 1.7</b>, a nested &lt;handler&gt; element can be used to
+specify an InputHandler, so that different InputHandlers may be used
+among different Input tasks.
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">one of "default","propertyfile", or "greedy".
+    </td>
+    <td align="center" valign="top" rowspan="3">One of these</td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">Reference to an <code>InputHandler</code>
+        defined elsewhere in the project.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">The name of an <code>InputHandler</code> subclass.</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use with <i>classname</i>.</td>
+    <td valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The refid of a classpath to use with <i>classname</i>.</td>
+    <td valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">loaderref</td>
+    <td valign="top">The refid of a classloader to use with <i>classname</i>.
+    </td>
+    <td valign="top">No</td>
+  </tr>
+</table>
+<br />
+The classpath can also be specified by means of one or more nested
+&lt;classpath&gt; elements.</p>
+
+<h3>Examples</h3>
+<pre>  &lt;input/&gt;</pre>
+<p>Will pause the build run until return key is pressed when using the
+<a href="../inputhandler.html#defaulthandler">default
+InputHandler</a>, the concrete behavior is defined by the InputHandler
+implementation you use.</p>
+<pre>  &lt;input&gt;Press Return key to continue...&lt;/input&gt;</pre>
+<p>Will display the message &quot;Press Return key to
+continue...&quot; and pause the build run until return key is pressed
+(again, the concrete behavior is implementation dependent).</p>
+<pre>  &lt;input
+    message=&quot;Press Return key to continue...&quot;
+  /&gt;</pre>
+<p>Will display the message &quot;Press Return key to
+continue...&quot; and pause the build run until return key is pressed
+(see above).</p>
+<pre>
+  &lt;input
+    message=&quot;All data is going to be deleted from DB continue (y/n)?&quot;
+    validargs=&quot;y,n&quot;
+    addproperty=&quot;do.delete&quot;
+  /&gt;
+  &lt;condition property=&quot;do.abort&quot;&gt;
+    &lt;equals arg1=&quot;n&quot; arg2=&quot;${do.delete}&quot;/&gt;
+  &lt;/condition&gt;
+  &lt;fail if=&quot;do.abort&quot;&gt;Build aborted by user.&lt;/fail&gt;
+</pre>
+<p>Will display the message &quot;All data is going to be deleted from
+DB continue (y/n)?&quot; and require 'y' to continue build or 'n' to
+exit build with following message &quot;Build aborted by
+user.&quot;.</p>
+<pre>  &lt;input
+    message=&quot;Please enter db-username:&quot;
+    addproperty=&quot;db.user&quot;
+  /&gt;</pre>
+<p>Will display the message &quot;Please enter db-username:&quot; and set the
+property <code>db.user</code> to the value entered by the user.</p>
+
+<pre>  &lt;input
+    message=&quot;Please enter db-username:&quot;
+    addproperty=&quot;db.user&quot;
+    defaultvalue=&quot;Scott-Tiger&quot;
+  /&gt;</pre>
+<p>Same as above, but will set <code>db.user</code> to the value
+<i>Scott- Tiger</i> if the user enters no value (simply types
+&lt;return&gt;).</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/jar.html b/trunk/docs/manual/CoreTasks/jar.html
new file mode 100644
index 0000000..5d70818
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/jar.html
@@ -0,0 +1,441 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Jar Task</title>
+</head>
+
+<body>
+
+<h2><a name="jar">Jar</a></h2>
+<h3>Description</h3>
+<p>Jars a set of files.</p>
+<p>The <i>basedir</i> attribute is the reference directory from where to jar.</p>
+<p>Note that file permissions will not be stored in the resulting jarfile.</p>
+<p>It is possible to refine the set of files that are being jarred. This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>basedir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<p>You can also use nested file sets for more flexibility, and specify
+multiple ones to merge together different trees of files into one JAR.
+The extended fileset and groupfileset child elements from the zip task are
+also available in the jar task.
+See the <a href="zip.html">Zip</a> task for more details and examples.</p>
+<p>If the manifest is omitted, a simple one will be supplied by Ant.</p>
+
+<p>The <code>update</code> parameter controls what happens if the JAR
+file already exists. When set to <code>yes</code>, the JAR file is
+updated with the files specified. When set to <code>no</code> (the
+default) the JAR file is overwritten. An example use of this is
+provided in the <a href="zip.html">Zip task documentation</a>.  Please
+note that ZIP files store file modification times with a granularity
+of two seconds.  If a file is less than two seconds newer than the
+entry in the archive, Ant will not consider it newer.</p>
+
+<p>The <code>whenmanifestonly</code> parameter controls what happens when no
+files, apart from the manifest file, or nested services, match.
+If <code>skip</code>, the JAR is not created and a warning is issued.
+If <code>fail</code>, the JAR is not created and the build is halted with an error.
+If <code>create</code>, (default) an empty JAR file (only containing a manifest and services)
+is created.</p>
+
+<p>(The Jar task is a shortcut for specifying the manifest file of a JAR file.
+The same thing can be accomplished by using the <i>fullpath</i>
+attribute of a zipfileset in a Zip task. The one difference is that if the
+<i>manifest</i> attribute is not specified, the Jar task will
+include an empty one for you.)</p>
+
+<p>Manifests are processed by the Jar task according to the
+<a target="_blank" href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html">Jar file specification.</a>
+Note in particular that this may result in manifest lines greater than 72 bytes
+being wrapped and continued on the next line.</p>
+
+<p>The Jar task checks whether you specified package information according to the
+<a target="_blank" href="http://java.sun.com/j2se/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning">
+versioning specification</a>.</p>
+
+<p><b>Please note that the zip format allows multiple files of the same
+fully-qualified name to exist within a single archive. This has been
+documented as causing various problems for unsuspecting users. If you wish
+to avoid this behavior you must set the <code>duplicate</code> attribute
+to a value other than its default, <code>"add"</code>.</b></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the JAR file to create.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory from which to jar the files.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compress</td>
+    <td valign="top">Not only store data but also compress them,
+    defaults to true.  Unless you set the <em>keepcompression</em>
+    attribute to false, this will apply to the entire archive, not
+    only the files you've added while updating.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepcompression</td>
+    <td valign="top">For entries coming from existing archives (like
+    nested <em>zipfileset</em>s or while updating the archive), keep
+    the compression as it has been originally instead of using the
+    <em>compress</em> attribute.  Defaults false.  <em>Since Ant
+    1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The character encoding to use for filenames
+      inside the archive.  Defaults to UTF8. <strong>It is not
+      recommended to change this value as the created archive will most
+      likely be unreadable for Java otherwise.</strong></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesonly</td>
+    <td valign="top">Store only file entries, defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">manifest</td>
+    <td valign="top">the manifest file to use.  This can be either the location of a manifest, or the name of a jar added through a fileset.  If its the name of an added jar, the task expects the manifest to be in the jar at META-INF/MANIFEST.MF</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesetmanifest</td>
+    <td valign="top">behavior when a Manifest is found in a zipfileset or zipgroupfileset file is found.  Valid values are &quot;skip&quot;, &quot;merge&quot;, and &quot;mergewithoutmain&quot;.  &quot;merge&quot; will merge all of the manifests together, and merge this into any other specified manifests.  &quot;mergewithoutmain&quot; merges everything but the Main section of the manifests.  Default value is &quot;skip&quot;.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">update</td>
+    <td valign="top">indicates whether to update or overwrite
+      the destination file if it already exists.  Default is &quot;false&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">whenmanifestonly</td>
+    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;create&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">duplicate</td>
+    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;.  The default value is &quot;add&quot;.  </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">index</td>
+    <td valign="top">whether to create an <A
+    HREF="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index">index
+    list</A> to speed up classloading.  This is a JDK 1.3+ specific
+    feature.  Unless you specify additional jars with nested <a
+    href="#indexjars"><code>indexjars</code></a> elements, only the
+    contents of this jar will be included in the index.  Defaults to
+    false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">manifestencoding</td>
+    <td valign="top">The encoding used to read the JAR manifest, when a manifest file is specified.</td>
+    <td valign="top" align="center">No, defaults to the platform encoding.</td>
+  </tr>
+  <tr>
+    <td valign="top">roundup</td>
+    <td valign="top">Whether the file modification times will be
+    rounded up to the next even number of seconds.<br>
+    Zip archives store file modification times with a granularity of
+    two seconds, so the times will either be rounded up or down.  If
+    you round down, the archive will always seem out-of-date when you
+    rerun the task, so the default is to round up.  Rounding up may
+    lead to a different type of problems like JSPs inside a web
+    archive that seem to be slightly more recent than precompiled
+    pages, rendering precompilation useless.<br>
+    Defaults to true.  <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">level</td>
+    <td valign="top">Non-default level at which file compression should be
+    performed. Valid values range from 0 (no compression/fastest) to 9
+    (maximum compression/slowest). <em>Since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strict</td>
+    <td valign="top">Configures how to handle breaks of the packaging version
+    specification: <ul>
+    <li><b>fail</b> = throws a BuildException</li>
+    <li><b>warn</b> = logs a message on warn level</li>
+    <li><b>ignore</b> = logs a message on verbose level (default)</li>
+    </ul>
+    <em>Since Ant 1.7.1</em></td>
+    <td valign="top" align="center">No, defaults to <tt>ignore</tt>. </td>
+  </tr>
+</table>
+
+<h3>Nested elements</h3>
+<h4>metainf</h4>
+<p>The nested <code>metainf</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>META-INF</code> directory of the jar file. If this
+fileset includes a file named <code>MANIFEST.MF</code>, the file is
+ignored and you will get a warning.</p>
+
+<h4>manifest</h4>
+<p>The manifest nested element allows the manifest for the Jar file to
+be provided inline in the build file rather than in an external
+file. This element is identical to the
+<a href="manifest.html">manifest</a> task, but the file and mode
+attributes must be omitted.</p>
+<p>
+If both an inline manifest and an external file are both specified, the
+manifests are merged.
+</p>
+
+<p>When using inline manifests, the Jar task will check whether the manifest
+contents have changed (i.e. the manifest as specified is different in any way
+from the manifest that exists in the Jar, if it exists.
+If the manifest values have changed the jar will be updated or rebuilt, as
+appropriate.
+</p>
+
+<a name="indexjars"><h4>indexjars</h4></a>
+
+<p><em>since ant 1.6.2</em></p>
+
+<p>The nested <code>indexjars</code> element specifies a <a
+href="../using.html#path">PATH like structure</a>.  Its content is
+completely ignored unless you set the index attribute of the task to
+true.</p>
+
+<p>The index created by this task will contain indices for the
+archives contained in this path, the names used for the archives
+depend on your manifest:</p>
+<ul>
+  <li>If the generated jar's manifest contains no Class-Path
+  attribute, the file name without any leading directory path will be
+  used and all parts of the path will get indexed.</li>
+  <li>If the manifest contains a Class-Path attribute, this task will
+  try to guess which part of the Class-Path belongs to a given
+  archive.  If it cannot guess a name, the archive will be skipped,
+  otherwise the name listed inside the Class-Path attribute will be
+  used.</li>
+</ul>
+
+<p>This task will not create any index entries for archives that are
+empty or only contain files inside the META-INF directory.</p>
+<a name="service"><h4>service</h4></a>
+
+<p><em>since ant 1.7.0</em></p>
+
+<p>
+  The nested <code>service</code> element specifies a service.
+  Services are described by
+  <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider</a>.
+  The approach is to have providers JARs include files named by the service
+  provided, for example,
+  META-INF/services/javax.script.ScriptEngineFactory
+  which can include implementation class names, one per line (usually just one per JAR).
+
+  The name of the
+  service is set by the "type" attribute. The classname implementing
+  the service is the the "provider" attribute, or it one wants to
+  specify a number of classes that implement the service, by
+  "provider" nested elements.
+</p>
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">The name of the service.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">provider</td>
+    <td valign="top">
+      The classname of the class implemening the service.
+    </td>
+    <td valign="top" align="center">Yes, unless there is a nested
+      <code>&lt;provider&gt;</code> element.</td>
+  </tr>
+</table>
+  <p>
+    The provider classname is specified either by the "provider" attribute, or
+    by a nested &lt;provider&gt; element, which has a single "classname" attribute.
+    If a JAR file has more that one implementation of the service, a number of
+    nested &lt;provider&gt; elements may be used.
+  </p>
+  
+  
+<h3>Examples</h3>
+
+<pre>  &lt;jar destfile=&quot;${dist}/lib/app.jar&quot; basedir=&quot;${build}/classes&quot;/&gt;</pre>
+<p>jars all files in the <code>${build}/classes</code> directory into a file
+called <code>app.jar</code> in the <code>${dist}/lib</code> directory.</p>
+
+<pre>  &lt;jar destfile=&quot;${dist}/lib/app.jar&quot;
+       basedir=&quot;${build}/classes&quot;
+       excludes=&quot;**/Test.class&quot;
+  /&gt;</pre>
+<p>jars all files in the <code>${build}/classes</code> directory into a file
+called <code>app.jar</code> in the <code>${dist}/lib</code> directory. Files
+with the name <code>Test.class</code> are excluded.</p>
+
+<pre>  &lt;jar destfile=&quot;${dist}/lib/app.jar&quot;
+       basedir=&quot;${build}/classes&quot;
+       includes=&quot;mypackage/test/**&quot;
+       excludes=&quot;**/Test.class&quot;
+  /&gt;</pre>
+<p>jars all files in the <code>${build}/classes</code> directory into a file
+called <code>app.jar</code> in the <code>${dist}/lib</code> directory. Only
+files under the directory <code>mypackage/test</code> are used, and files with
+the name <code>Test.class</code> are excluded.</p>
+
+<pre>  &lt;jar destfile=&quot;${dist}/lib/app.jar&quot;&gt;
+    &lt;fileset dir=&quot;${build}/classes&quot;
+             excludes=&quot;**/Test.class&quot;
+    /&gt;
+    &lt;fileset dir=&quot;${src}/resources&quot;/&gt;
+  &lt;/jar&gt;</pre>
+<p>jars all files in the <code>${build}/classes</code> directory and also
+in the <code>${src}/resources</code> directory together into a file
+called <code>app.jar</code> in the <code>${dist}/lib</code> directory.
+Files with the name <code>Test.class</code> are excluded.
+If there are files such as <code>${build}/classes/mypackage/MyClass.class</code>
+and <code>${src}/resources/mypackage/image.gif</code>, they will appear
+in the same directory in the JAR (and thus be considered in the same package
+by Java).</p>
+
+<pre>  &lt;jar destfile=&quot;test.jar&quot; basedir=&quot;.&quot;&gt;
+    &lt;include name=&quot;build&quot;/&gt;
+    &lt;manifest&gt;
+      &lt;!-- Who is building this jar? --&gt;
+      &lt;attribute name=&quot;Built-By&quot; value=&quot;${user.name}&quot;/&gt;
+      &lt;!-- Information about the program itself --&gt;
+      &lt;attribute name=&quot;Implementation-Vendor&quot; value=&quot;ACME inc.&quot;/&gt;
+      &lt;attribute name=&quot;Implementation-Title&quot; value=&quot;GreatProduct&quot;/&gt;
+      &lt;attribute name=&quot;Implementation-Version&quot; value=&quot;1.0.0beta2&quot;/&gt;
+      &lt;!-- details --&gt;
+      &lt;section name=&quot;common/class1.class&quot;&gt;
+        &lt;attribute name=&quot;Sealed&quot; value=&quot;false&quot;/&gt;
+      &lt;/section&gt;
+    &lt;/manifest&gt;
+  &lt;/jar&gt;</pre>
+<p>
+This is an example of an inline manifest specification including the version of the build
+program (Implementation-Version). Note that the Built-By attribute will take the value of the Ant 
+property ${user.name}. The manifest produced by the above would look like this:
+</p>
+<pre><code>Manifest-Version: 1.0
+Built-By: conor
+Implementation-Vendor: ACME inc.
+Implementation-Title: GreatProduct
+Implementation-Version: 1.0.0beta2
+Created-By: Apache Ant 1.7.0
+
+Name: common/MyClass.class
+Sealed: false</code></pre>
+
+
+<p>
+  The following shows how to create a jar file specifing a service
+  with an implementation of the JDK6 scripting interface:
+</p>
+<blockquote><pre>&lt;jar jarfile="pinky.jar"&gt;
+  &lt;fileset dir="build/classes"/&gt;
+  &lt;service type="javax.script.ScriptEngineFactory"
+           provider="org.acme.PinkyLanguage"/&gt;
+&lt;/jar&gt;
+</pre></blockquote>
+
+<p>
+  The following shows how to create a jar file specifing a service
+  with two implementations of the JDK6 scripting interface:
+</p>
+<blockquote><pre>
+&lt;jar jarfile="pinkyandbrain.jar"&gt;
+  &lt;fileset dir="classes"/&gt;
+  &lt;service type="javax.script.ScriptEngineFactory"&gt;
+    &lt;provider classname="org.acme.PinkyLanguage"/&gt;
+    &lt;provider classname="org.acme.BrainLanguage"/&gt;
+  &lt;/service&gt;
+&lt;/jar&gt;
+</pre></blockquote>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/java.html b/trunk/docs/manual/CoreTasks/java.html
new file mode 100644
index 0000000..cc46d74
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/java.html
@@ -0,0 +1,395 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Java Task</title>
+</head>
+
+<body>
+
+<h2><a name="java">Java</a></h2>
+<h3>Description</h3>
+<p>Executes a Java class within the running (Ant) VM or forks another VM if
+specified.</p>
+<p>
+If odd things go wrong when you run this task, set fork="true" to use a new
+JVM.
+
+<p>As of Ant 1.6.3, you can interact with a forked VM, as well as
+sending input to it via the <code>input</code> and <code>inputstring</code>
+attributes.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the Java class to execute.</td>
+    <td align="center" valign="top">Either <tt>jar</tt> or <tt>classname</tt></td>
+  </tr>
+  <tr>
+    <td valign="top">jar</td>
+    <td valign="top">the location of the jar file to execute (must have a
+    Main-Class entry in the manifest). Fork must be set to true if this option is selected.
+    See notes below for more details.
+    </td>
+    <td align="center" valign="top">Either <tt>jar</tt> or <tt>classname</tt></td>
+  </tr>
+  <tr>
+    <td valign="top">args</td>
+    <td valign="top">the arguments for the class that is
+      executed. <b>deprecated, use nested <code>&lt;arg&gt;</code>
+      elements instead.</b></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use, given as <a
+      href="../using.html#references">reference</a> to a PATH defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fork</td>
+    <td valign="top">if enabled triggers the class execution in another VM
+      (disabled by default)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">spawn</td>
+    <td valign="top">if enabled allows to start a process which will outlive ant.<br>
+    Requires fork=true, and not compatible
+    with timeout, input, output, error, result attributes.<br>
+      (disabled by default)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">jvm</td>
+    <td valign="top">the command used to invoke the Java Virtual Machine,
+      default is 'java'.  The command is resolved by java.lang.Runtime.exec().
+      Ignored if fork is disabled.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">jvmargs</td>
+    <td valign="top">the arguments to pass to the forked VM (ignored
+      if fork is disabled). <b>deprecated, use nested
+      <code>&lt;jvmarg&gt;</code> elements instead.</b></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">maxmemory</td>
+    <td valign="top">Max amount of memory to allocate to the forked VM
+      (ignored if fork is disabled)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the buildprocess if the command exits with a
+      returncode other than 0. Default is "false" (see <a href="#failonerror">note</a>)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">resultproperty</td>
+    <td valign="top">The name of a property in which the return code of the
+      command should be stored. Only of interest if failonerror=false
+      and if fork=true.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The directory to invoke the VM in.  (ignored if
+      fork is disabled)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">Name of a file to which to write the output. If the error stream
+      is not also redirected to a file or property, it will appear in this output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">error</td>
+    <td valign="top">The file to which the standard error of the command should be
+      redirected. </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">logError</td>
+    <td valign="top">This attribute is used when you wish to see error output in Ant's
+                     log and you are redirecting output to a file/property. The error
+                     output will not be included in the output file/property. If you
+                     redirect error with the &quot;error&quot; or &quot;errorProperty&quot;
+                     attributes, this will have no effect.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Whether output and error files should be appended to or overwritten.
+    Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputproperty</td>
+    <td valign="top">The name of a property in which the output of the
+      command should be stored. Unless the error stream is redirected to a separate
+      file or stream, this property will include the error output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property in which the standard error of the
+      command should be stored.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">input</td>
+    <td valign="top">A file from which the executed command's standard input
+                     is taken. This attribute is mutually exclusive with the
+                     inputstring attribute</td>
+    <td align="center" valign="top">No; default is to take standard input from console
+        (unless <code>spawn="true"</code>)</td>
+  </tr>
+  <tr>
+    <td valign="top">inputstring</td>
+    <td valign="top">A string which serves as the input stream for the
+                     executed command. This attribute is mutually exclusive with the
+                     input attribute.</td>
+    <td align="center" valign="top">No; default is to take standard input from console
+        (unless <code>spawn="true"</code>)</td>
+  </tr>
+  <tr>
+    <td valign="top">newenvironment</td>
+    <td valign="top">Do not propagate old environment when new
+      environment variables are specified. Default is &quot;false&quot;
+      (ignored if fork is disabled).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Stop the command if it doesn't finish within the
+    specified time (given in milliseconds).  <strong>It is highly
+    recommended to use this feature only if fork is enabled.</strong></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">clonevm</td>
+    <td valign="top">If set to true, then all system properties
+      and the bootclasspath of the forked Java Virtual Machine will be
+      the same as those of the Java VM running Ant.  Default is
+      &quot;false&quot; (ignored if fork is disabled).
+      <em>since Ant 1.7</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>arg and jvmarg</h4>
+<p>Use nested <code>&lt;arg&gt;</code> and <code>&lt;jvmarg&gt;</code>
+elements to specify arguments for the Java class and the forked VM respectively.
+See <a href="../using.html#arg">Command line arguments</a>.</p>
+<h4>sysproperty</h4>
+<p>Use nested <code>&lt;sysproperty&gt;</code>
+elements to specify system properties required by the class.
+These properties will be made available to the VM during the execution
+of the class (either ANT's VM or the forked VM). The attributes
+for this element are the same as for <a href="exec.html#env">environment
+variables</a>.</p>
+
+<h4>syspropertyset</h4>
+
+<p>You can specify a set of properties to be used as system properties
+with <a href="../CoreTypes/propertyset.html">syspropertyset</a>s.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>classpath</h4>
+<p><code>Java</code>'s <i>classpath</i> attribute is a <a
+href="../using.html#path">PATH like structure</a> and can also be set via a nested
+<i>classpath</i> element.</p>
+
+<h4>bootclasspath</h4>
+
+<p>The location of bootstrap class files can be specified using this
+<a href="../using.html#path">PATH like structure</a> - will be ignored
+if <i>fork</i> is not <code>true</code> or the target VM doesn't
+support it (i.e. Java 1.1).</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>env</h4>
+<p>It is possible to specify environment variables to pass to the
+forked VM via nested <i>env</i> elements. See the description in the
+section about <a href="exec.html#env">exec</a></p>
+<p>Settings will be ignored if fork is disabled.</p>
+
+<h4>permissions</h4>
+<p>Security permissions can be revoked and granted during the execution of the
+class via a nested <i>permissions</i> element. For more information please
+see <a href="../CoreTypes/permissions.html">permissions</a></p>
+<p>When the permission RuntimePermission exitVM has not been granted (or has
+been revoked) the System.exit() call will be intercepted
+and treated like indicated in <i>failonerror</i>.</p>
+<p>Note:<br>
+If you do not specify permissions,
+a set of default permissions will be added to your Java invocation to make
+sure that the ant run will continue or terminated as indicated by
+<i>failonerror</i>. All permissions not granted per default will be
+checked by whatever security manager was already in place. exitVM will be
+disallowed.
+</p>
+<p>Settings will be ignored if fork is enabled.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>assertions</h4>
+
+<p>You can control enablement of Java 1.4 assertions with an
+<a href="../CoreTypes/assertions.html"><tt>&lt;assertions&gt;</tt></a>
+subelement.</p>
+
+<p>Assertion statements are currently ignored in non-forked mode.</p>
+
+<p><em>since Ant 1.6.</em></p>
+
+<a name="redirector"><h4>redirector</h4></a>
+<i><b>Since Ant 1.6.2</b></i>
+<p>A nested <a href="../CoreTypes/redirector.html">I/O Redirector</a>
+can be specified.  In general, the attributes of the redirector behave
+as the corresponding attributes available at the task level.  The most
+notable peculiarity stems from the retention of the <code>&lt;java&gt;</code>
+attributes for backwards compatibility.  Any file mapping is done
+using a <CODE>null</CODE> sourcefile; therefore not all
+<a href="../CoreTypes/mapper.html">Mapper</a> types will return
+results.  When no results are returned, redirection specifications
+will fall back to the task level attributes.  In practice this means that
+defaults can be specified for input, output, and error output files.
+</p>
+<h3>Errors and return codes</h3>
+By default the return code of a <code>&lt;java&gt;</code> is ignored.
+Alternatively, you can set <code>resultproperty</code> to the name
+of a property and have it assigned to the result code (barring immutability,
+of course).
+When you set <code>failonerror="true"</code>, the only possible value for
+<code>resultproperty</code> is 0. Any non-zero response is treated as an
+error and would mean the build exits.
+<p> Similarly, if <code>failonerror="false"</code> and <code>fork="false"</code>
+, then <code>&lt;java&gt;</code> <b>must</b> return 0 otherwise the build will
+exit, as the class was run by the build JVM.</p>
+
+<h3>JAR file execution</h3>
+
+<p>The parameter of the <tt>jar</tt> attribute is of type <tt>File</tt>;
+that is, the parameter is resolved to an absolute file relative to the
+base directory of the project, <i>not</i> the directory in which the Java
+task is run. If you need to locate a JAR file relative to the directory
+the task will be run in, you need to explicitly create the full path
+to the JAR file.</p>
+<p>When using the <tt>jar</tt> attribute, all classpath settings are 
+ignored according to <a href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/java.html#-jar">Sun's
+specification</a>. 
+
+
+<h3>Examples</h3>
+<pre>
+       &lt;java classname=&quot;test.Main&quot;&gt;
+         &lt;arg value=&quot;-h&quot;/&gt;
+         &lt;classpath&gt;
+           &lt;pathelement location=&quot;dist/test.jar&quot;/&gt;
+           &lt;pathelement path=&quot;${java.class.path}&quot;/&gt;
+         &lt;/classpath&gt;
+       &lt;/java&gt;
+</pre>
+Run a class in this JVM with a new jar on the classpath
+
+<pre>
+       &lt;java jar=&quot;dist/test.jar&quot;
+           fork="true"
+           failonerror="true"
+           maxmemory="128m"
+           &gt;
+         &lt;arg value=&quot;-h&quot;/&gt;
+         &lt;classpath&gt;
+           &lt;pathelement location=&quot;dist/test.jar&quot;/&gt;
+           &lt;pathelement path=&quot;${java.class.path}&quot;/&gt;
+         &lt;/classpath&gt;
+       &lt;/java&gt;
+</pre>
+Run the JAR test.jar in this project's dist/lib directory.
+using the manifest supplied entry point, forking (as required),
+and with a maximum memory of 128MB. Any non zero return code breaks the build.
+
+<pre>
+       &lt;java
+           dir="${exec.dir}"
+           jar=&quot;${exec.dir}/dist/test.jar&quot;
+           fork="true"
+           failonerror="true"
+           maxmemory="128m"
+           &gt;
+         &lt;arg value=&quot;-h&quot;/&gt;
+         &lt;classpath&gt;
+           &lt;pathelement location=&quot;dist/test.jar&quot;/&gt;
+           &lt;pathelement path=&quot;${java.class.path}&quot;/&gt;
+         &lt;/classpath&gt;
+       &lt;/java&gt;
+</pre>
+Run the JAR dist/test.jar relative to the directory
+<tt>${exec.dir}</tt>, this being the same directory into which the JVM
+is to start up.
+
+<pre>  &lt;java classname=&quot;test.Main&quot;/&gt;</pre>
+Runs a given class with the current classpath.
+
+<pre>
+  &lt;java classname=&quot;test.Main&quot;
+        fork=&quot;yes&quot; &gt;
+    &lt;sysproperty key=&quot;DEBUG&quot; value=&quot;true&quot;/&gt;
+    &lt;arg value=&quot;-h&quot;/&gt;
+    &lt;jvmarg value=&quot;-Xrunhprof:cpu=samples,file=log.txt,depth=3&quot;/&gt;
+  &lt;/java&gt;
+</pre>
+Add system properties and JVM-properties to the JVM as in
+<code>java ="-Xrunhprof:cpu=samples,file=log.txt,depth=3 -DDEBUG=true test.Main</code>
+
+<pre>  &lt;java classname=&quot;ShowJavaVersion&quot; classpath=&quot;.&quot;
+        jvm=&quot;path-to-java14-home/bin/java&quot; fork=&quot;true&quot;
+        taskname=&quot;java1.4&quot; &gt;
+</pre>
+Use a given Java implementation (another the one Ant is currently using) to run the class.
+For documentation in the log <code>taskname</code> is used to change the <code>[java]</code>
+log-prefix to <code>[java1.4]</code>.
+
+
+<p><strong>Note</strong>: you can not specify the (highly deprecated) MSJVM, "jview.exe" as the
+JVM, as it takes different parameters for other JVMs,
+That JVM can be started from <code>&lt;exec&gt;</code> if required.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/javac.html b/trunk/docs/manual/CoreTasks/javac.html
new file mode 100644
index 0000000..0d5f9c6
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/javac.html
@@ -0,0 +1,796 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html lang="en-us">
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Javac Task</title>
+</head>
+
+<body>
+
+<h2><a name="javac">Javac</a></h2>
+<h3>Description</h3>
+<p>Compiles a Java source tree.</p>
+<p>The source and destination directory will be recursively scanned for Java
+source files to compile. Only Java files that have no corresponding
+<code>.class</code> file
+or where the class file is older than the
+<code>.java</code> file will be compiled.</p>
+<p>Note: Ant uses only the names of the source and class files to find
+the classes that need a rebuild. It will not scan the source and therefore
+will have no knowledge about nested classes, classes that are named different
+from the source file, and so on. See the
+<a href="../OptionalTasks/depend.html"><code>&lt;depend&gt;</code></a> task
+for dependency checking based on other than just
+existence/modification times.</p>
+<p>When the source files are part of a package, the directory structure of
+the source tree should follow the package
+hierarchy.</p>
+<p>It is possible to refine the set of files that are being compiled.
+This can be done with the <code>includes</code>, <code>includesfile</code>,
+<code>excludes</code>, and <code>excludesfile</code>
+attributes. With the <code>includes</code> or
+<code>includesfile</code> attribute, you specify the files you want to
+have included.
+The <code>exclude</code> or <code>excludesfile</code> attribute is used
+to specify
+the files you want to have excluded. In both cases, the list of files
+can be specified by either the filename, relative to the directory(s) specified
+in the <code>srcdir</code> attribute or nested <code>&lt;src&gt;</code>
+element(s), or by using wildcard patterns. See the section on
+<a href="../dirtasks.html#directorybasedtasks">directory-based tasks</a>,
+for information on how the
+inclusion/exclusion of files works, and how to write wildcard patterns.</p>
+<p>It is possible to use different compilers. This can be specified by
+either setting the global <code>build.compiler</code> property, which will
+affect all <code>&lt;javac&gt;</code> tasks throughout the build, or by
+setting the <code>compiler</code> attribute, specific to the current
+<code>&lt;javac&gt;</code> task.
+<a name="compilervalues">Valid values for either the
+<code>build.compiler</code> property or the <code>compiler</code>
+attribute are:</a></p>
+<ul>
+  <li><code>classic</code> (the standard compiler of JDK 1.1/1.2) &ndash;
+      <code>javac1.1</code> and
+      <code>javac1.2</code> can be used as aliases.</li>
+  <li><code>modern</code> (the standard compiler of JDK 1.3/1.4/1.5/1.6) &ndash;
+      <code>javac1.3</code> and
+      <code>javac1.4</code> and
+      <code>javac1.5</code> and
+      <code>javac1.6</code> can be used as aliases.</li>
+  <li><code>jikes</code> (the <a
+    href="http://jikes.sourceforge.net/" target="_top">Jikes</a>
+    compiler).</li>
+  <li><code>jvc</code> (the Command-Line Compiler from Microsoft's SDK
+      for Java / Visual J++) &ndash; <code>microsoft</code> can be used
+      as an alias.</li>
+  <li><code>kjc</code> (the <a href="http://www.dms.at/kopi/" target="_top">kopi</a>
+    compiler).</li>
+  <li><code>gcj</code> (the gcj compiler from gcc).</li>
+  <li><code>sj</code> (Symantec java compiler) &ndash;
+      <code>symantec</code> can be used as an alias.</li>
+  <li><code>extJavac</code> (run either modern or classic in a JVM of
+      its own).</li>
+</ul>
+<p>The default is <code>javac1.x</code> with <code>x</code> depending
+on the JDK version you use while you are running Ant.
+If you wish to use a different compiler interface than those
+supplied, you can write a class that implements the CompilerAdapter interface
+(<code>package org.apache.tools.ant.taskdefs.compilers</code>). Supply the full
+classname in the <code>build.compiler</code> property or the
+<code>compiler</code> attribute.
+</p>
+<p>The fork attribute overrides the <code>build.compiler</code> property
+or <code>compiler</code> attribute setting and
+expects a JDK1.1 or higher to be set in <code>JAVA_HOME</code>.
+</p>
+<p>You can also use the <code>compiler</code> attribute to tell Ant
+which JDK version it shall assume when it puts together the command
+line switches - even if you set <code>fork=&quot;true&quot;</code>.
+This is useful if you want to run the compiler of JDK 1.1 while you
+current JDK is 1.2+.  If you use
+<code>compiler=&quot;javac1.1&quot;</code> and (for example)
+<code>depend=&quot;true&quot;</code> Ant will use the command line
+switch <code>-depend</code> instead of <code>-Xdepend</code>.</p>
+<p>This task will drop all entries that point to non-existent
+files/directories from the classpath it passes to the compiler.</p>
+<p><strong>Windows Note:</strong>When the modern compiler is used
+in unforked mode on Windows, it locks up the files present in the
+classpath of the <code>&lt;javac&gt;</code> task, and does not release them.
+The side effect of this is that you will not be able to delete or move
+those files later on in the build.  The workaround is to fork when
+invoking the compiler.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">srcdir</td>
+    <td valign="top">Location of the java files. (See the
+     <a href="#srcdirnote">note</a> below.)</td>
+    <td align="center" valign="top">Yes, unless nested <code>&lt;src&gt;</code> elements are present.</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">Location to store the class files.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">Comma- or space-separated list of files (may be specified using
+      wildcard patterns) that must be
+      included; all <code>.java</code> files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">The name of a file that contains a list of files to
+      include (may be specified using wildcard patterns).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">Comma- or space-separated list of files (may be specified using
+      wildcard patterns) that must be excluded; no files (except default
+      excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">The name of a file that contains a list of files to
+      exclude (may be specified using wildcard patterns).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sourcepath</td>
+    <td valign="top">The sourcepath to use; defaults to the value of the srcdir attribute (or nested <code>&lt;src&gt;</code> elements).
+        To suppress the sourcepath switch, use <code>sourcepath=&quot;&quot;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bootclasspath</td>
+    <td valign="top">
+      Location of bootstrap class files. (See <a href="#bootstrap">below</a>
+      for using the -X and -J-X parameters for specifing
+      the bootstrap classpath).
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a
+      <a href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sourcepathref</td>
+    <td valign="top">The sourcepath to use, given as a
+      <a href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bootclasspathref</td>
+    <td valign="top">Location of bootstrap class files, given as a
+      <a href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">extdirs</td>
+    <td valign="top">Location of installed extensions.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">Encoding of source files. (Note: gcj doesn't support
+      this option yet.)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">nowarn</td>
+    <td valign="top">Indicates whether the <code>-nowarn</code> switch
+      should be passed to the compiler; defaults to <code>off</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debug</td>
+    <td valign="top">Indicates whether source should be compiled with
+    debug information; defaults to <code>off</code>.  If set to
+    <code>off</code>, <code>-g:none</code> will be passed on the
+    command line for compilers that support it (for other compilers, no
+    command line argument will be used).  If set to <code>true</code>,
+    the value of the <code>debuglevel</code> attribute determines the
+    command line argument.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debuglevel</td>
+    <td valign="top">Keyword list to be appended to the <code>-g</code>
+      command-line switch.  This will be ignored by all implementations except
+      <code>modern</code>, <code>classic(ver &gt;= 1.2)</code> and <code>jikes</code>.
+      Legal values are <code>none</code> or a comma-separated list of the
+      following keywords:
+      <code>lines</code>, <code>vars</code>, and <code>source</code>.
+      If <code>debuglevel</code> is not specified, by default,
+      nothing will be
+      appended to <code>-g</code>.  If <code>debug</code> is not turned on,
+      this attribute will be ignored.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">optimize</td>
+    <td valign="top">
+      Indicates whether source should be compiled with
+      optimization; defaults to <code>off</code>. <strong>Note</strong>
+      that this flag is just ignored by Sun's <code>javac</code> starting
+      with JDK 1.3 (since compile-time optimization is unnecessary).
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">deprecation</td>
+    <td valign="top">Indicates whether source should be compiled with
+      deprecation information; defaults to <code>off</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">Generate class files for specific VM version
+    (e.g., <code>1.1</code> or <code>1.2</code>). <b>Note that the
+    default value depends on the JVM that is running Ant.  In
+    particular, if you use JDK 1.4+ the generated classes will not be
+    usable for a 1.1 Java VM unless you explicitly set this attribute
+    to the value 1.1 (which is the default value for JDK 1.1 to
+    1.3).  We highly recommend to always specify this
+    attribute.</b><br>
+    A default value for this attribute can be provided using the magic
+    <a
+    href="../javacprops.html#target"><code>ant.build.javac.target</code></a>
+    property.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Asks the compiler for verbose output; defaults to
+      <code>no</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">depend</td> <td valign="top">Enables dependency-tracking
+      for compilers that support this (<code>jikes</code> and
+      <code>classic</code>).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeAntRuntime</td>
+    <td valign="top">Whether to include the Ant run-time libraries in the
+      classpath; defaults to <code>yes</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeJavaRuntime</td>
+    <td valign="top">Whether to include the default run-time
+      libraries from the executing VM in the classpath;
+      defaults to <code>no</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fork</td>
+    <td valign="top">Whether to execute <code>javac</code> using the
+      JDK compiler externally; defaults to <code>no</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">executable</td>
+    <td valign="top">Complete path to the <code>javac</code>
+      executable to use in case of <code>fork=&quot;yes&quot;</code>.
+      Defaults to the compiler of the Java version that is currently
+      running Ant.  Ignored if <code>fork=&quot;no&quot;</code>.<br>
+      Since Ant 1.6 this attribute can also be used to specify the
+      path to the executable when using jikes, jvc, gcj or sj.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">memoryInitialSize</td>
+    <td valign="top">The initial size of the memory for the underlying VM,
+      if <code>javac</code> is run externally; ignored otherwise. Defaults
+      to the standard VM memory setting.
+      (Examples: <code>83886080</code>, <code>81920k</code>, or
+      <code>80m</code>)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">memoryMaximumSize</td>
+    <td valign="top">The maximum size of the memory for the underlying VM,
+      if <code>javac</code> is run externally; ignored otherwise. Defaults
+      to the standard VM memory setting.
+      (Examples: <code>83886080</code>, <code>81920k</code>, or
+      <code>80m</code>)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Indicates whether compilation errors
+        will fail the build; defaults to <code>true</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorProperty</td>
+    <td valign="top">
+      The property to set (to the value "true") if compilation fails.
+      <em>Since Ant 1.7.1</em>.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">source</td>
+
+    <td valign="top">Value of the <code>-source</code> command-line
+    switch; will be ignored by all implementations prior to
+    <code>javac1.4</code> (or <code>modern</code> when Ant is not
+    running in a 1.3 VM) and <code>jikes</code>.<br> If you use this
+    attribute together with <code>jikes</code>, you must make sure
+    that your version of jikes supports the <code>-source</code>
+    switch.  By default, no <code>-source</code> argument will be used
+    at all.<br>
+    <b>Note that the default value depends on the JVM that is running
+    Ant.  We highly recommend to always specify this
+    attribute.</b><br>
+    A default value for this attribute can be provided using the magic
+    <a
+    href="../javacprops.html#source"><code>ant.build.javac.source</code></a>
+    property.</td>
+
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td valign="top">The compiler implementation to use.
+      If this attribute is not set, the value of the
+      <code>build.compiler</code> property, if set, will be used.
+      Otherwise, the default compiler for the current VM will be used.
+      (See the above <a href="#compilervalues">list</a> of valid
+      compilers.)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">listfiles</td>
+    <td valign="top">Indicates whether the source files to be compiled will
+      be listed; defaults to <code>no</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tempdir</td>
+    <td valign="top">Where Ant should place temporary files.
+      This is only used if the task is forked and the
+      command line args length exceeds 4k.
+      <em>Since Ant 1.6</em>.</td>
+    <td align="center" valign="top">
+      No; default is <i>java.io.tmpdir</i>.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">updatedProperty</td>
+    <td valign="top">
+      The property to set (to the value "true") 
+      if compilation has taken place
+      and has been successful.
+      <em>Since Ant 1.7.1</em>.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeDestClasses</td>
+    <td valign="top">
+      This attribute controls whether to include the
+      destination classes directory in the classpath
+      given to the compiler.
+      The default value of this is "true" and this
+      means that previously compiled classes are on
+      the classpath for the compiler. This means that "greedy" compilers
+      will not recompile dependant classes that are already compiled.
+      In general this is a good thing as it stops the compiler
+      for doing unnecessary work. However, for some edge cases,
+      involving generics, the javac compiler
+      needs to compile the dependant classes to get the generics
+      information. One example is documented in the bug report:
+      <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=40776">
+        Bug 40776 - a problem compiling a Java 5 project with generics</a>.
+      Setting the attribute to "false" will cause the compiler
+      to recompile dependent classes.
+      <em>Since Ant 1.7.1</em>.
+    </td>
+    <td align="center" valign="top">No - default is "true"</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>srcdir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<h4><code>src</code>, <code>classpath</code>, <code>sourcepath</code>,
+<code>bootclasspath</code> and <code>extdirs</code></h4>
+<p><code>&lt;javac&gt;</code>'s <code>srcdir</code>, <code>classpath</code>,
+<code>sourcepath</code>, <code>bootclasspath</code>, and
+<code>extdirs</code> attributes are
+<a href="../using.html#path">path-like structures</a>
+and can also be set via nested
+<code>&lt;src&gt;</code>,
+<code>&lt;classpath&gt;</code>,
+<code>&lt;sourcepath&gt;</code>,
+<code>&lt;bootclasspath&gt;</code> and
+<code>&lt;extdirs&gt;</code> elements, respectively.</p>
+
+<h4>compilerarg</h4>
+
+<p>You can specify additional command line arguments for the compiler
+with nested <code>&lt;compilerarg&gt;</code> elements.  These elements
+are specified like <a href="../using.html#arg">Command-line
+Arguments</a> but have an additional attribute that can be used to
+enable arguments only if a given compiler implementation will be
+used.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">value</td>
+    <td align="center" rowspan="4">See
+    <a href="../using.html#arg">Command-line Arguments</a>.</td>
+    <td align="center" rowspan="4">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">line</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td>Only pass the specified argument if the chosen
+      compiler implementation matches the value of this attribute.
+      Legal values are the
+      same as those in the above <a href="#compilervalues">list</a> of valid
+      compilers.)</td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+         source=&quot;1.4&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores
+the <code>.class</code> files in the <code>${build}</code> directory.
+The classpath used includes <code>xyz.jar</code>, and compiling with
+debug information is on. The source level is 1.4,
+so you can use <code>assert</code> statements.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         fork=&quot;true&quot;
+         source=&quot;1.2&quot;
+         target=&quot;1.2&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores the <code>.class</code> files in the
+<code>${build}</code> directory.  This will fork off the javac
+compiler using the default <code>javac</code> executable.
+The source level is 1.2 (similar to 1.1 or 1.3) and
+the class files should be runnable under JDK 1.2+ as well.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         fork=&quot;java$$javac.exe&quot;
+         source=&quot;1.5&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores the <code>.class</code> files in the
+<code>${build}</code> directory.  This will fork off the javac
+compiler, using the executable named <code>java$javac.exe</code>.  Note
+that the <code>$</code> sign needs to be escaped by a second one.
+The source level is 1.5, so you can use generics.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         includes=&quot;mypackage/p1/**,mypackage/p2/**&quot;
+         excludes=&quot;mypackage/p1/testpackage/**&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+  /&gt;</pre>
+<p>compiles <code>.java</code> files under the <code>${src}</code>
+directory, and stores the
+<code>.class</code> files in the <code>${build}</code> directory.
+The classpath used includes <code>xyz.jar</code>, and debug information is on.
+Only files under <code>mypackage/p1</code> and <code>mypackage/p2</code> are
+used. All files in and below the <code>mypackage/p1/testpackage</code>
+directory are excluded from compilation.
+You didn't specify a source or target level,
+so the actual values used will depend on which JDK you ran Ant with.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}:${src2}&quot;
+         destdir=&quot;${build}&quot;
+         includes=&quot;mypackage/p1/**,mypackage/p2/**&quot;
+         excludes=&quot;mypackage/p1/testpackage/**&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+  /&gt;</pre>
+
+<p>is the same as the previous example, with the addition of a second
+source path, defined by
+the property <code>src2</code>. This can also be represented using nested
+<code>&lt;src&gt;</code> elements as follows:</p>
+
+<pre>  &lt;javac destdir=&quot;${build}&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;&gt;
+    &lt;src path=&quot;${src}&quot;/&gt;
+    &lt;src path=&quot;${src2}&quot;/&gt;
+    &lt;include name=&quot;mypackage/p1/**&quot;/&gt;
+    &lt;include name=&quot;mypackage/p2/**&quot;/&gt;
+    &lt;exclude name=&quot;mypackage/p1/testpackage/**&quot;/&gt;
+  &lt;/javac&gt;</pre>
+
+<p>If you want to run the javac compiler of a different JDK, you
+should tell Ant, where to find the compiler and which version of JDK
+you will be using so it can choose the correct command line switches.
+The following example executes a JDK 1.1 javac in a new process and
+uses the correct command line switches even when Ant is running in a
+Java VM of a different version:</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         fork=&quot;yes&quot;
+         executable=&quot;/opt/java/jdk1.1/bin/javac&quot;
+         compiler=&quot;javac1.1&quot;
+  /&gt;</pre>
+
+<p><a name="srcdirnote"><b>Note:</b></a>
+If you wish to compile only source files located in certain packages below a
+common root, use the <code>include</code>/<code>exclude</code> attributes
+or <code>&lt;include&gt;</code>/<code>&lt;exclude&gt;</code> nested elements
+to filter for these packages. Do not include part of your package structure
+in the <code>srcdir</code> attribute
+(or nested <code>&lt;src&gt;</code> elements), or Ant will recompile your
+source files every time you run your compile target. See the
+<a href="http://ant.apache.org/faq.html#always-recompiles">Ant FAQ</a>
+for additional information.</p>
+
+<p>
+If you wish to compile only files explicitly specified and disable
+javac's default searching mechanism then you can unset the sourcepath
+attribute:
+<pre>  &lt;javac sourcepath=&quot;&quot; srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot; &gt;
+    &lt;include name="**/*.java"/&gt;
+    &lt;exclude name="**/Example.java"/&gt;
+  &lt;/javac&gt;</pre>
+That way the javac will compile all java source files under &quot;${src}&quot;
+directory but skip the examples. The compiler will even produce errors if some of
+the non-example files refers to them.
+</p>
+
+<p>
+If you wish to compile with a special JDK (another than the one Ant is currently using),
+set the <code>executable</code> and <code>fork</code> attribute. Using <code>taskname</code>
+could show in the log, that these settings are fix.
+<pre>  &lt;javac srcdir=&quot;&quot; 
+         destdir=&quot;&quot;
+         executable=&quot;path-to-java14-home/bin/javac&quot; 
+         fork=&quot;true&quot;
+         taskname=&quot;javac1.4&quot; /&gt;</pre>
+</p>
+
+
+<p><b>Note:</b> If you are using Ant on Windows and a new DOS window pops up
+for every use of an external compiler, this may be a problem of the JDK you are
+using.  This problem may occur with all JDKs &lt; 1.2.</p>
+
+
+<p>
+If you want to activate other compiler options like <i>lint</i> you could use
+the <tt>&lt;compilerarg&gt;</tt> element:
+<pre>  &lt;javac srcdir="${src.dir}"
+         destdir="${classes.dir}"
+         classpathref="libraries"&gt;
+    &lt;compilerarg value="-Xlint"/&gt;
+  &lt;/javac&gt; </pre>
+</p>  
+
+
+<h3>Jikes Notes</h3>
+
+<p>You need Jikes 1.15 or later.</p>
+
+<p>Jikes supports some extra options, which can be set be defining
+the properties shown below prior to invoking the task. The setting
+for each property will be in affect for all <code>&lt;javac&gt;</code>
+tasks throughout the build.
+The Ant developers are aware that
+this is ugly and inflexible &ndash; expect a better solution in the future.
+All the options are boolean, and must be set to <code>true</code> or
+<code>yes</code> to be
+interpreted as anything other than false. By default,
+<code>build.compiler.warnings</code> is <code>true</code>,
+while all others are <code>false</code>.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Property</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Default</b></td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.emacs
+	</td>
+	<td valign="top">
+	Enable emacs-compatible error messages.
+    </td>
+    <td valign="top">
+	<code>false</code>
+	</td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.fulldepend
+	</td>
+	<td valign="top">
+	Enable full dependency checking; see<br>
+	the <code>+F</code> switch in the Jikes manual.
+    </td>
+    <td valign="top">
+	<code>false</code>
+	</td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.pedantic
+	</td>
+	<td valign="top">
+	Enable pedantic warnings.
+    </td>
+    <td valign="top">
+	<code>false</code>
+	</td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.warnings<br>
+        <strong>Deprecated</strong>. Use
+  <code>&lt;javac&gt;</code>'s <code>nowarn</code>
+  attribute instead.
+	</td>
+	<td valign="top">
+	Don't disable warning messages.
+    </td>
+    <td valign="top">
+	<code>true</code>
+	</td>
+  </tr>
+</table>
+
+<h3>Jvc Notes</h3>
+
+<p>Jvc will enable Microsoft extensions unless you set the property
+<code>build.compiler.jvc.extensions</code> to false before invoking
+<code>&lt;javac&gt;</code>.</p>
+
+<h3><a name="bootstrap">Bootstrap Options</h3>
+<p>
+  The Sun javac compiler has a <em>bootclasspath</em> command
+  line option - this corresponds to the "bootclasspath" attribute/element
+  of the &lt;javac&gt; task. The Sun compiler also allows more
+  control over the boot classpath using the -X and -J-X attributes.
+  One can set these by using the &lt;compilerarg&gt;. Since Ant 1.6.0,
+  there is a shortcut to convert path references to strings that
+  can by used in an OS independent fashion (see
+  <a href="../using.html#pathshortcut">pathshortcut</a>). For example:
+</p>
+<pre>
+  &lt;path id="lib.path.ref"&gt;
+    &lt;fileset dir="lib" includes="*.jar"/&gt;
+  &lt;/path&gt;
+  &lt;javac srcdir="src" destdir="classes"&gt;
+    &lt;compilerarg arg="-Xbootstrap/p:${toString:lib.path.ref}"/&gt;
+  &lt;/javac&gt;
+</pre>
+
+  
+</p>
+
+<h3>OpenJDK Notes</h3>
+<p>
+  The <a href="https://openjdk.dev.java.net/">openjdk</a>
+  project has provided the javac
+  <a href="https://openjdk.dev.java.net/compiler/">compiler</a>
+  as an opensource project. The output of this project is a
+  <code>javac.jar</code> which contains the javac compiler.
+  This compiler may be used with the <code>&lt;javac&gt;</code> task with
+  the use of a "-Xbootstrapclass/p" java argument. The argument needs
+  to be given to the runtime system of the javac executable, so it needs
+  to be prepended with a "-J". For example:
+
+<blockquote><pre>
+  &lt;property name="patched.javac.jar"
+            location="${my.patched.compiler}/dist/lib/javac.jar"/&gt;
+
+  &lt;presetdef name="patched.javac"&gt;
+    &lt;javac fork="yes"&gt;
+      &lt;compilerarg value="-J-Xbootclasspath/p:${patched.javac.jar}"/&gt;
+    &lt;/javac&gt;
+  &lt;/presetdef&gt;
+
+
+  &lt;patched.javac srcdir="src/java" destdir="build/classes"
+                 debug="yes"/&gt;
+</pre></blockquote>
+
+  <h3>Note on package-info.java</h3>
+  <p>
+    <code>package-info.java</code> files were introduced in Java5 to
+    allow package level annotations. On compilation, if the java file
+    does not contain runtime annotations, there will be no .class file
+    for the java file. Up to <b>Ant 1.7.1</b>, when the &lt;javac&gt;
+    task is run again, the
+    task will try to compile the package-info java files again.
+  </p>
+  <p>
+    In <b>Ant 1.7.1</b> the package-info.java will only be compiled if:
+    <ol>
+      <li>
+        If a <code>package-info.class</code> file exists and is older than
+        the <code>package-info.java</code> file.
+      </li>
+      <li>
+        If the directory for the 
+        <code>package-info.class</code> file does not exist.
+      </li>
+      <li>
+        If the directory for the
+        <code>package-info.class</code> file exists, and has an older
+        modification time than the
+        the <code>package-info.java</code> file. In this case
+        &lt;javac&gt; will touch the corresponding .class directory
+        on successful compilation.
+      </li>
+    </ol>
+  </p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/javadoc.html b/trunk/docs/manual/CoreTasks/javadoc.html
new file mode 100644
index 0000000..432781d
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/javadoc.html
@@ -0,0 +1,850 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Javadoc Task</title>
+</head>
+
+<body>
+
+<h2><a name="javadoc">Javadoc/<i>Javadoc2</i></a></h2>
+<h3>Description</h3>
+<p>Generates code documentation using the javadoc tool.</p>
+<p>The source directory will be recursively scanned for Java source files to process
+but only those matching the inclusion rules, and not matching the exclusions rules
+will be passed to the javadoc tool. This
+allows wildcards to be used to choose between package names, reducing verbosity
+and management costs over time. This task, however, has no notion of
+&quot;changed&quot; files, unlike the <a href="javac.html">javac</a> task. This means
+all packages will be processed each time this task is run. In general, however,
+this task is used much less frequently.</p>
+<p>This task works seamlessly between different javadoc versions (1.2 and 1.4),
+with the obvious restriction that the 1.4 attributes
+will be ignored if run in a 1.2 VM.</p>
+<p>NOTE: since javadoc calls System.exit(), javadoc cannot be run inside the
+same VM as Ant without breaking functionality. For this reason, this task
+always forks the VM. This overhead is not significant since javadoc is normally a heavy
+application and will be called infrequently.</p>
+<p>NOTE: the packagelist attribute allows you to specify the list of packages to
+document outside of the Ant file. It's a much better practice to include everything
+inside the <code>build.xml</code> file. This option was added in order to make it easier to
+migrate from regular makefiles, where you would use this option of javadoc.
+The packages listed in packagelist are not checked, so the task performs even
+if some packages are missing or broken. Use this option if you wish to convert from
+an existing makefile. Once things are running you should then switch to the regular
+notation. </p>
+
+<p><i><b>DEPRECATION:</b> the javadoc2 task simply points to the javadoc task and it's
+there for back compatibility reasons. Since this task will be removed in future
+versions, you are strongly encouraged to use <a href="javadoc.html">javadoc</a>
+instead.</i></p>
+
+<p>In the table below, 1.2 means available if your current Java VM is
+a 1.2 VM (but not 1.3 or later), 1.4+ for any VM of at least version 1.4, otherwise
+any VM of at least version 1.2 is acceptable. JDK 1.1 is no longer supported.
+If you specify the <code>executable</code> attribute it is up to you
+to ensure that this command supports the attributes you wish to use.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Availability</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">sourcepath</td>
+    <td valign="top">Specify where to find source files</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" rowspan="3">At least one of the three or nested
+    <code>&lt;sourcepath&gt;</code>, <code>&lt;fileset&gt;</code> or
+    <code>&lt;packageset&gt;</code></td>
+  </tr>
+  <tr>
+    <td valign="top">sourcepathref</td>
+    <td valign="top">Specify where to find source files by <a
+      href="../using.html#references">reference</a> to a PATH defined elsewhere.</td>
+    <td align="center" valign="top">all</td>
+  </tr>
+  <tr>
+    <td valign="top">sourcefiles</td>
+    <td valign="top">Comma separated list of source files -- see also
+    the nested <code>source</code> element.</td>
+    <td align="center" valign="top">all</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">Destination directory for output files</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">Yes, unless a doclet has been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">maxmemory</td>
+    <td valign="top">Max amount of memory to allocate to the javadoc VM</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">packagenames</td>
+    <td valign="top">Comma separated list of package files (with terminating
+      wildcard) -- see also the nested <code>package</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">packageList</td>
+    <td valign="top">The name of a file containing the packages to process</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">Specify where to find user class files</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Bootclasspath</td>
+    <td valign="top">Override location of class files loaded by the bootstrap
+      class loader</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">Specify where to find user class files by <a
+      href="../using.html#references">reference</a> to a PATH defined elsewhere.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bootclasspathref</td>
+    <td valign="top">Override location of class files loaded by the
+      bootstrap class loader by <a href="../using.html#references">reference</a> to a
+      PATH defined elsewhere.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Extdirs</td>
+    <td valign="top">Override location of installed extensions</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Overview</td>
+    <td valign="top">Read overview documentation from HTML file</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">access</td>
+    <td valign="top">Access mode: one of <code>public</code>, <code>protected</code>,
+                     <code>package</code>, or <code>private</code></td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No (default <code>protected</code>)</td>
+  </tr>
+  <tr>
+    <td valign="top">Public</td>
+    <td valign="top">Show only public classes and members</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Protected</td>
+    <td valign="top">Show protected/public classes and members (default)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Package</td>
+    <td valign="top">Show package/protected/public classes and members</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Private</td>
+    <td valign="top">Show all classes and members</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Old</td>
+    <td valign="top">Generate output using JDK 1.1 emulating doclet</td>
+    <td align="center" valign="top">1.2</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Verbose</td>
+    <td valign="top">Output messages about what Javadoc is doing</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Locale</td>
+    <td valign="top">Locale to be used, e.g. en_US or en_US_WIN</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Encoding</td>
+    <td valign="top">Source file encoding name</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Version</td>
+    <td valign="top">Include @version paragraphs</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Use</td>
+    <td valign="top">Create class and package usage pages</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Author</td>
+    <td valign="top">Include @author paragraphs</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Splitindex</td>
+    <td valign="top">Split index into one file per letter</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Windowtitle</td>
+    <td valign="top">Browser window title for the documentation (text)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Doctitle</td>
+    <td valign="top">Include title for the package index(first) page (html-code)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Header</td>
+    <td valign="top">Include header text for each page (html-code)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">Footer</td>
+    <td valign="top">Include footer text for each page (html-code)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bottom</td>
+    <td valign="top">Include bottom text for each page (html-code)</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">link</td>
+    <td valign="top">Create links to javadoc output at the given URL
+    -- see also the nested <code>link</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">linkoffline</td>
+    <td valign="top">Link to docs at <code>&lt;url&gt;</code> using package list at
+    <code>&lt;url2&gt;</code> - separate the URLs by using a space character -- see
+    also the nested <code>link</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">group</td>
+    <td valign="top">Group specified packages together in overview
+    page.  The format is as described <a
+    href="#groupattribute">below</a> -- see also the nested
+    <code>group</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">nodeprecated</td>
+    <td valign="top">Do not include @deprecated information</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">nodeprecatedlist</td>
+    <td valign="top">Do not generate deprecated list</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">notree</td>
+    <td valign="top">Do not generate class hierarchy</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">noindex</td>
+    <td valign="top">Do not generate index</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">nohelp</td>
+    <td valign="top">Do not generate help link</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">nonavbar</td>
+    <td valign="top">Do not generate navigation bar</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">serialwarn</td>
+    <td valign="top">Generate warning about @serial tag</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">helpfile</td>
+    <td valign="top">Specifies the HTML help file to use</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">stylesheetfile</td>
+    <td valign="top">Specifies the CSS stylesheet to use</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">charset</td>
+    <td valign="top">Charset for cross-platform viewing of generated
+      documentation</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">docencoding</td>
+    <td valign="top">Output file encoding name</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">doclet</td>
+    <td valign="top">Specifies the class file that starts the doclet
+    used in generating the documentation -- see also the nested
+    <code>doclet</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">docletpath</td>
+    <td valign="top">Specifies the path to the doclet class file that is specified with the -doclet option.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">docletpathref</td>
+    <td valign="top">Specifies the path to the doclet class file that
+      is specified with the -doclet option by <a
+      href="../using.html#references">reference</a> to a PATH defined elsewhere.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">additionalparam</td>
+    <td valign="top">Lets you add additional parameters to the javadoc
+    command line. Useful for doclets. Parameters containing spaces
+    need to be quoted using &amp;quot; -- see also the nested
+    <code>arg</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the buildprocess if the command exits with a
+      returncode other than 0.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludepackagenames</td>
+    <td valign="top">comma separated list of packages you don't want
+      docs for -- see also the nested <code>excludepackage</code> element.</td>
+    <td align="center" valign="top">all</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used
+      (<code>yes</code> | <code>no</code>); default excludes are used when omitted.</td>
+    <td align="center" valign="top">all</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">useexternalfile</td>
+    <td valign="top">indicates whether the sourcefile name specified
+      in srcfiles or as nested source elements should be written to a
+      temporary file to make the command line shorter. Also applies to
+      the package names specified via the packagenames attribute or
+      nested package elements.<em>Since Ant 1.7.0</em>, also applies
+      to all the other command line options.
+      (<code>yes</code> | <code>no</code>). Default is no.</td>
+    <td align="center" valign="top">all</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">source</td>
+    <td valign="top">Necessary to enable javadoc to handle assertions
+    present in J2SE v 1.4 source code. Set this to &quot;1.4&quot; to
+    documents code that compiles using <code>&quot;javac -source
+    1.4&quot;</code>.<br>
+    A default value for this attribute can be provided using the magic
+    <a
+    href="../javacprops.html#source"><code>ant.build.javac.source</code></a>
+    property.</td>
+    <td align="center" valign="top">1.4+</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">linksource</td>
+    <td valign="top">Generate hyperlinks to source files.
+      <em>since Ant 1.6</em>.
+      (<code>yes</code> | <code>no</code>). Default is no.</td>
+    <td align="center" valign="top">1.4+</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">breakiterator</td>
+    <td valign="top">Use the new breakiterator algorithm.
+      <em>since Ant 1.6</em>.
+      (<code>yes</code> | <code>no</code>). Default is no.</td>
+    <td align="center" valign="top">1.4+</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">noqualifier</td>
+    <td valign="top">Enables the <code>-noqualifier</code> argument -
+      must be <code>all</code> or a colon separated list of packages.
+      <em>since Ant 1.6</em>.</td>
+    <td align="center" valign="top">1.4+</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includenosourcepackages</td>
+    <td valign="top">If set to true, packages that don't contain Java
+      source but a package.html will get documented as well.
+      <em>since Ant 1.6.3</em>.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No (default is <code>false</code>)</td>
+  </tr>
+  <tr>
+    <td valign="top">executable</td>
+    <td valign="top">Specify a particular <code>javadoc</code> executable
+      to use in place of the default binary (found in the same JDK as Ant is running in).
+      <em>since Ant 1.6.3</em>.</td>
+    <td align="center" valign="top">all</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4><a name="groupattribute">Format of the group attribute</a></h4>
+<p>The arguments are comma-delimited. Each single argument is 2
+space-delimited strings, where the first one is the group's title and
+the second one a colon delimited list of packages.</p>
+<p>If you need to specify more than one group, or a group whose title
+contains a comma or a space character, using <a
+href="#groupelement">nested group elements</a> is highly
+recommended.</p>
+<p>E.g.:</p>
+<pre>    group=&quot;XSLT_Packages org.apache.xalan.xslt*,XPath_Packages org.apache.xalan.xpath*&quot;</pre>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>packageset</h4>
+
+<p>A <a href="../CoreTypes/dirset.html">DirSet</a>.  All matched
+directories that contain Java source files will be passed to javadoc
+as package names.  Package names are created from the directory names
+by translating the directory separator into dots.  Ant assumes the
+base directory of the packageset points to the root of a package
+hierarchy.</p>
+
+<p>The <code>packagenames</code>, <code>excludepackagenames</code> and
+<code>defaultexcludes</code> attributes of the task have no effect on
+the nested <code>&lt;packageset&gt;</code> elements.</p>
+
+<h4>fileset</h4>
+
+<p>A <a href="../CoreTypes/fileset.html">FileSet</a>.  All matched
+files will be passed to javadoc as source files.  Ant will
+automatically add the include pattern <code>**/*.java</code> (and
+<code>**/package.html</code> if includenosourcepackages is true) to
+these filesets.</p>
+
+<p>Nested filesets can be used to document sources that are in the
+default package or if you want to exclude certain files from
+documentation.  If you want to document all source files and don't use
+the default package, packagesets should be used instead as this
+increases javadocs performance.</p>
+
+<p>The <code>packagenames</code>, <code>excludepackagenames</code> and
+<code>defaultexcludes</code> attributes of the task have no effect on
+the nested <code>&lt;fileset&gt;</code> elements.</p>
+
+<h4>sourcefiles</h4>
+
+<p>A container for arbitrary file system based <a
+href="../CoreTypes/resources.html#collection">resource
+collections</a>.  All files contained in any of the nested collections
+(this includes nested filesets, filelists or paths) will be passed to
+javadoc as source files.</p>
+
+<h4>package</h4>
+<p>Same as one entry in the list given by <code>packagenames</code>.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The package name (may be a wildcard)</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4>excludepackage</h4>
+<p>Same as one entry in the list given by <code>excludepackagenames</code>.</p>
+
+<h5>Parameters</h5>
+Same as for <code>package</code>.
+
+<h4>source</h4>
+<p>Same as one entry in the list given by <code>sourcefiles</code>.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The source file to document</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4>doctitle</h4>
+
+<p>Same as the <code>doctitle</code> attribute, but you can nest text
+inside the element this way.</p>
+
+<h4>header</h4>
+
+<p>Similar to <code>&lt;doctitle&gt;</code>.</p>
+
+<h4>footer</h4>
+
+<p>Similar to <code>&lt;doctitle&gt;</code>.</p>
+
+<h4>bottom</h4>
+
+<p>Similar to <code>&lt;doctitle&gt;</code>.</p>
+
+<h4>link</h4>
+<p>Create link to javadoc output at the given URL. This performs the
+same role as the link and linkoffline attributes. You can use either
+syntax (or both at once), but with the nested elements you can easily
+specify multiple occurrences of the arguments.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">href</td>
+    <td valign="top">The URL for the external documentation you wish
+    to link to.  This can be an absolute URL, or a relative file
+    name.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">offline</td>
+    <td valign="top">True if this link is not available online at the time of
+                     generating the documentation</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">packagelistLoc</td>
+    <td valign="top">The location to the directory containing the package-list file for
+                     the external documentation</td>
+    <td align="center" valign="top">Only if the offline attribute is true</td>
+  </tr>
+  <tr>
+    <td valign="top">resolveLink</td>
+    <td valign="top">If the link attribute is a relative file name,
+    Ant will first try to locate the file relative to the current
+    project's basedir and if it finds a file there use an absolute URL
+    for the link attribute, otherwise it will pass the file name
+    verbatim to the javadoc command.</td>
+    <td align="center" valign="top">No, default is false.</td>
+  </tr>
+</table>
+
+<h4><a name="groupelement">group</a></h4>
+<p>Separates packages on the overview page into whatever groups you
+specify, one group per table. This performs the same role as the group
+attribute. You can use either syntax (or both at once), but with the
+nested elements you can easily specify multiple occurrences of the
+arguments.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">title</td>
+    <td valign="top">Title of the group</td>
+    <td align="center" valign="top">Yes, unless nested <code>&lt;title&gt;</code> given</td>
+  </tr>
+  <tr>
+    <td valign="top">packages</td>
+    <td valign="top">List of packages to include in that group. Multiple packages are separated with ':'.</td>
+    <td align="center" valign="top">Yes, unless nested <code>&lt;package&gt;</code>s given</td>
+  </tr>
+</table>
+
+<p>The title may be specified as a nested <code>&lt;title&gt;</code> element
+with text contents, and the packages may be listed with nested
+<code>&lt;package&gt;</code> elements as for the main task.</p>
+
+<h4>doclet</h4>
+<p>The doclet nested element is used to specify the doclet that javadoc will
+use to process the input source files. A number of the standard javadoc arguments
+are actually arguments of the standard doclet. If these are specified in the javadoc
+task's attributes, they will be passed to the doclet specified in the
+<code>&lt;doclet&gt;</code> nested element. Such attributes should only be specified,
+therefore, if they can be interpreted by the doclet in use.</p>
+
+<p>If the doclet requires additional parameters, these can be specified with
+<code>&lt;param&gt;</code> elements within the <code>&lt;doclet&gt;</code>
+element. These parameters are restricted to simple strings. An example usage
+of the doclet element is shown below:</p>
+
+<pre>  &lt;javadoc ... &gt;
+     &lt;doclet name=&quot;theDoclet&quot;
+             path=&quot;path/to/theDoclet&quot;&gt;
+        &lt;param name=&quot;-foo&quot; value=&quot;foovalue&quot;/&gt;
+        &lt;param name=&quot;-bar&quot; value=&quot;barvalue&quot;/&gt;
+     &lt;/doclet&gt;
+  &lt;/javadoc&gt;
+</pre>
+
+<h4><a name="tagelement">tag</a></h4>
+
+<p>The tag nested element is used to specify custom tags. This option
+is only available with Java 1.4.</p>
+
+<p>If you want to specify a standard tag using a nested tag element
+because you want to determine the order the tags are output, you must
+not set the description attribute for those tags.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the tag (e.g. <code>todo</code>)</td>
+    <td align="center" valign="top">Yes, unless the <code>dir</code> attribute is specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">description</td>
+    <td valign="top">Description for tag (e.g. <code>To do:</code>)</td>
+    <td align="center" valign="top">
+      No, the javadoc executable will pick a default if this is not specified.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">enabled</td>
+    <td valign="top">Whether or not the tag is enabled (defaults to <code>true</code>)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">scope</td>
+    <td valign="top">Scope for the tag - the elements in which it can be used. This
+    is a comma separated list of some of the elements: <code>overview</code>,
+    <code>packages</code>, <code>types</code>, <code>constructors</code>,
+    <code>methods</code>, <code>fields</code> or the default, <code>all</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">If this attribute is specified, this element will behave as an implicit
+    <a href="../CoreTypes/fileset.html">fileset</a>. The files included by this fileset should
+    contain each tag definition on a separate line, as described in the
+    <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/javadoc.html#tag">Javadoc reference guide</a>:
+    <pre>ejb.bean:t:XDoclet EJB Tag
+todo:a:To Do</pre>
+      <b>Note:</b> The  Javadoc reference quide has double quotes around
+the description part of the definition. This will not work when used in
+a file, as the definition is quoted again when given to
+the javadoc program.
+    <br/>
+      <b>Note:</b> If this attribute is specified, all the other attributes in this
+    element will be ignored.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4><a name="tagletelement">taglet</a></h4>
+<p>The taglet nested element is used to specify custom taglets. This option is
+only available with Java 1.4.</p>
+
+<h5>Parameters</h5>
+<table width="90%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the taglet class
+              (e.g. <code>com.sun.tools.doclets.ToDoTaglet</code>)</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+    <td valign="top">A path specifying the search path for the taglet class
+            (e.g. <code>/home/taglets</code>).
+            The path may also be specified by a nested <code>&lt;path&gt;</code> element</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4>sourcepath, classpath and bootclasspath</h4>
+<p><code>Javadoc</code>'s <i>sourcepath</i>, <i>classpath</i> and
+<i>bootclasspath</i> attributes are <a href="../using.html#path">PATH like
+structure</a> and can also be set via nested <i>sourcepath</i>,
+<i>classpath</i> and <i>bootclasspath</i> elements
+respectively.</p>
+
+<h4>arg</h4>
+
+<p>Use nested <code>&lt;arg&gt;</code> to specify additional
+arguments.  See <a href="../using.html#arg">Command line
+arguments</a>. <em>Since Ant 1.6</em></p>
+
+<h3>Example</h3>
+<pre>  &lt;javadoc packagenames=&quot;com.dummy.test.*&quot;
+           sourcepath=&quot;src&quot;
+           excludepackagenames=&quot;com.dummy.test.doc-files.*&quot;
+           defaultexcludes=&quot;yes&quot;
+           destdir=&quot;docs/api&quot;
+           author=&quot;true&quot;
+           version=&quot;true&quot;
+           use=&quot;true&quot;
+           windowtitle=&quot;Test API&quot;&gt;
+    &lt;doctitle&gt;&lt;![CDATA[&lt;h1&gt;Test&lt;/h1&gt;]]&gt;&lt;/doctitle&gt;
+    &lt;bottom&gt;&lt;![CDATA[&lt;i&gt;Copyright &amp;#169; 2000 Dummy Corp. All Rights Reserved.&lt;/i&gt;]]&gt;&lt;/bottom&gt;
+    &lt;tag name=&quot;todo&quot; scope=&quot;all&quot; description=&quot;To do:&quot;/&gt;
+    &lt;group title=&quot;Group 1 Packages&quot; packages=&quot;com.dummy.test.a*&quot;/&gt;
+    &lt;group title=&quot;Group 2 Packages&quot; packages=&quot;com.dummy.test.b*:com.dummy.test.c*&quot;/&gt;
+    &lt;link offline=&quot;true&quot; href=&quot;http://java.sun.com/j2se/1.5.0/docs/api/&quot; packagelistLoc=&quot;C:\tmp&quot;/&gt;
+    &lt;link href=&quot;http://developer.java.sun.com/developer/products/xml/docs/api/&quot;/&gt;
+  &lt/javadoc&gt;</pre>
+
+<p>is the same as</p>
+
+<pre>  &lt;javadoc
+           destdir=&quot;docs/api&quot;
+           author=&quot;true&quot;
+           version=&quot;true&quot;
+           use=&quot;true&quot;
+           windowtitle=&quot;Test API&quot;&gt;
+
+    &lt;packageset dir=&quot;src&quot; defaultexcludes=&quot;yes&quot;&gt;
+      &lt;include name=&quot;com/dummy/test/**&quot;/&gt;
+      &lt;exclude name=&quot;com/dummy/test/doc-files/**&quot;/&gt;
+    &lt;/packageset&gt;
+
+    &lt;doctitle&gt;&lt;![CDATA[&lt;h1&gt;Test&lt;/h1&gt;]]&gt;&lt;/doctitle&gt;
+    &lt;bottom&gt;&lt;![CDATA[&lt;i&gt;Copyright &amp;#169; 2000 Dummy Corp. All Rights Reserved.&lt;/i&gt;]]&gt;&lt;/bottom&gt;
+    &lt;tag name=&quot;todo&quot; scope=&quot;all&quot; description=&quot;To do:&quot;/&gt;
+    &lt;group title=&quot;Group 1 Packages&quot; packages=&quot;com.dummy.test.a*&quot;/&gt;
+    &lt;group title=&quot;Group 2 Packages&quot; packages=&quot;com.dummy.test.b*:com.dummy.test.c*&quot;/&gt;
+    &lt;link offline=&quot;true&quot; href=&quot;http://java.sun.com/j2se/1.5.0/docs/api/&quot; packagelistLoc=&quot;C:\tmp&quot;/&gt;
+    &lt;link href=&quot;http://developer.java.sun.com/developer/products/xml/docs/api/&quot;/&gt;
+  &lt/javadoc&gt;</pre>
+
+<p>or</p>
+
+<pre>  &lt;javadoc
+           destdir=&quot;docs/api&quot;
+           author=&quot;true&quot;
+           version=&quot;true&quot;
+           use=&quot;true&quot;
+           windowtitle=&quot;Test API&quot;&gt;
+
+    &lt;fileset dir=&quot;src&quot; defaultexcludes=&quot;yes&quot;&gt;
+      &lt;include name=&quot;com/dummy/test/**&quot;/&gt;
+      &lt;exclude name=&quot;com/dummy/test/doc-files/**&quot;/&gt;
+    &lt;/fileset&gt;
+
+    &lt;doctitle&gt;&lt;![CDATA[&lt;h1&gt;Test&lt;/h1&gt;]]&gt;&lt;/doctitle&gt;
+    &lt;bottom&gt;&lt;![CDATA[&lt;i&gt;Copyright &amp;#169; 2000 Dummy Corp. All Rights Reserved.&lt;/i&gt;]]&gt;&lt;/bottom&gt;
+    &lt;tag name=&quot;todo&quot; scope=&quot;all&quot; description=&quot;To do:&quot;/&gt;
+    &lt;group title=&quot;Group 1 Packages&quot; packages=&quot;com.dummy.test.a*&quot;/&gt;
+    &lt;group title=&quot;Group 2 Packages&quot; packages=&quot;com.dummy.test.b*:com.dummy.test.c*&quot;/&gt;
+    &lt;link offline=&quot;true&quot; href=&quot;http://java.sun.com/j2se/1.5.0/docs/api/&quot; packagelistLoc=&quot;C:\tmp&quot;/&gt;
+    &lt;link href=&quot;http://developer.java.sun.com/developer/products/xml/docs/api/&quot;/&gt;
+  &lt/javadoc&gt;</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/length.html b/trunk/docs/manual/CoreTasks/length.html
new file mode 100755
index 0000000..cfd32ac
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/length.html
@@ -0,0 +1,120 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Length Task</title>
+</head>
+
+<body>
+
+<h2>Length</h2>
+<h3>Description</h3>
+<p>Display or set a property containing length information for
+   a string, a file, or one or more nested
+   <a href="../CoreTypes/resources.html#collection">Resource Collection</a>s.
+   Can also be used as a condition. <b>Since Ant 1.6.3</b></p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The property to set.  If omitted
+      the results are written to the log. Ignored when
+      processing as a condition.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">Single file whose length to report.</td>
+    <td valign="top" align="center" rowspan="2">One of these,
+      or one or more nested filesets</td>
+  </tr>
+  <tr>
+    <td valign="top">string</td>
+    <td valign="top">The string whose length to report.</td>
+  </tr>
+  <tr>
+    <td valign="top">mode</td>
+    <td valign="top">File length mode; when &quot;all&quot; the resulting
+      value is the sum of all included resources' lengths; when &quot;each&quot;
+      the task outputs the absolute path and length of each included resource,
+      one per line. Ignored when processing as a condition.</td>
+    <td valign="top" align="center">No; default is &quot;all&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">trim</td>
+    <td valign="top">Whether to trim when operating on a string.</td>
+    <td valign="top" align="center">No; only valid when string is set</td>
+  </tr>
+  <tr>
+    <td valign="top">length</td>
+    <td valign="top">Comparison length for processing as a condition.</td>
+    <td valign="top" align="center">Yes, in condition mode</td>
+  </tr>
+  <tr>
+    <td valign="top">when</td>
+    <td valign="top">Comparison type: "equal", "eq", "greater", "gt", "less",
+      "lt", "ge" (greater or equal), "ne" (not equal), "le" (less or equal)
+      for use when operating as a condition.</td>
+    <td valign="top" align="center">No; default is "equal"</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>Resource Collections</h4>
+<p>You can include resources via nested
+  <a href="../CoreTypes/resources.html#collection">Resource Collection</a>s.</p>
+
+<h3>Examples</h3>
+
+<pre>&lt;length string=&quot;foo&quot; property=&quot;length.foo&quot; /&gt;
+</pre>
+<p>Stores the length of the string &quot;foo&quot; in the property named
+<i>length.foo</i>.</p>
+
+<pre>&lt;length file=&quot;bar&quot; property=&quot;length.bar&quot; /&gt;
+</pre>
+<p>Stores the length of file &quot;bar&quot; in the property named
+<i>length.bar</i>.</p>
+
+<pre>
+&lt;length property=&quot;length&quot; mode=&quot;each&quot;&gt;
+    &lt;fileset dir=&quot;.&quot; includes=&quot;foo,bar&quot;/&gt;
+&lt;/length&gt;
+</pre>
+<p>Writes the file paths of <i>foo</i> and <i>bar</i> and their length into 
+the property <i>length</i>.</p>
+
+<pre>
+&lt;length property=&quot;length&quot; mode=&quot;all&quot;&gt;
+    &lt;fileset dir=&quot;.&quot; includes=&quot;foo,bar&quot;/&gt;
+&lt;/length&gt;
+</pre>
+<p>Adds the length of <i>foo</i> and <i>bar</i> and stores the result in property <i>length</i>.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/loadfile.html b/trunk/docs/manual/CoreTasks/loadfile.html
new file mode 100644
index 0000000..f7befba
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/loadfile.html
@@ -0,0 +1,133 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>LoadFile Task</title>
+</head>
+
+<body>
+
+
+<h2><a name="loadfile">LoadFile</a></h2>
+<h3>Description</h3>
+<p>
+Specialization of <a href="loadresource.html">loadresource</a> that
+works on files exclusively and provides a srcFile attribute for
+convenience.  Unless an encoding is specified, the encoding of the
+current locale is used.
+</p>
+<p>If the resource content is empty (maybe after processing a filterchain) 
+the property is not set.</p>
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">srcFile</td>
+    <td valign="top">source file</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">property to save to</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">encoding to use when loading the file</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Whether to halt the build on failure</td>
+    <td align="center" valign="top">No, default "true"</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">Do not display a diagnostic message (unless Ant has been 
+    invoked with the <code>-verbose</code> or <code>-debug</code>
+    switches) or modify the exit status to reflect an error. Setting this to 
+    "true" implies setting failonerror to "false".
+      <em>Since Ant 1.7.0.</em>
+    </td>
+    <td align="center" valign="top">No, default "false"</td>
+  </tr>
+
+</table>
+<p>
+The LoadFile task supports nested <a href="../CoreTypes/filterchain.html">
+FilterChain</a>s.
+
+<h3>Examples</h3>
+<pre>    &lt;loadfile property="message"
+      srcFile="message.txt"/&gt;
+</pre>
+Load file message.txt into property "message"; an <tt>&lt;echo&gt;</tt>
+can print this.  This is identical to
+<pre>    &lt;loadresource property="message"&gt;
+       &lt;file file="message.txt"/&gt;
+    &lt;/loadresource&gt;
+</pre>
+</p>
+
+<pre>    &lt;loadfile property="encoded-file"
+      srcFile="loadfile.xml"
+      encoding="ISO-8859-1"/&gt;
+</pre>
+Load a file using the latin-1 encoding
+
+<pre>    &lt;loadfile
+      property="optional.value"
+      srcFile="optional.txt"
+      failonerror="false"/&gt;
+</pre>
+Load a file, don't fail if it is missing (a message is printed, though)
+
+<pre>    &lt;loadfile
+      property="mail.recipients"
+      srcFile="recipientlist.txt"&gt;
+      &lt;filterchain&gt;
+        &lt;<a href="../CoreTypes/filterchain.html#striplinebreaks">striplinebreaks</a>/&gt;
+      &lt;/filterchain&gt;
+    &lt;/loadfile&gt;
+</pre>
+Load a property which can be used as a parameter for another task (in this case mail),
+merging lines to ensure this happens.
+
+<pre>    &lt;loadfile
+      property="system.configuration.xml"
+      srcFile="configuration.xml"&gt;
+        &lt;filterchain&gt;
+          &lt;<a href="../CoreTypes/filterchain.html#expandproperties">expandproperties</a>/&gt;
+        &lt;/filterchain&gt;
+    &lt;/loadfile&gt;
+</pre>
+Load an XML file into a property, expanding all properties declared
+in the file in the process.
+
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/loadproperties.html b/trunk/docs/manual/CoreTasks/loadproperties.html
new file mode 100644
index 0000000..0f253c2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/loadproperties.html
@@ -0,0 +1,127 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>LoadProperties Task</title>
+</head>
+
+<body>
+
+
+<h2><a name="loadproperties">LoadProperties</a></h2>
+<h3>Description</h3>
+<p>
+Load a file's contents as Ant properties.  This is equivalent
+to <code>&lt;property file|resource=&quot;...&quot;/&gt;</code> except that it
+supports nested <code>&lt;filterchain&gt;</code> elements.
+Also if the file is missing, the build is halted with an error, rather
+than a warning being printed.
+</p>
+
+<p>If you want to simulate <a href="property.html">property</a>'s
+prefix attribute, please use <a
+href="../CoreTypes/filterchain.html#prefixlines">prefixlines</a>
+filter.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">srcFile</td>
+    <td valign="top">source file</td>
+    <td valign="top" rowspan="2" align="center">One of these or a
+          nested resource</td>
+  </tr>
+  <tr>
+    <td valign="top">resource</td>
+    <td valign="top">the resource name of the property file</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">encoding to use when loading the file</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use when looking up a resource.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use when looking up a resource,
+      given as <a href="../using.html#references">reference</a>
+      to a <code>&lt;path&gt;</code> defined elsewhere..</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any <a href="../CoreTypes/resources.html">resource</a> or single element
+resource collection</h4>
+
+<p>The specified resource will be used as src. <em>Since Ant 1.7</em></p>
+
+<h4><a href="../CoreTypes/filterchain.html">FilterChain</a></h4>
+
+<h4>classpath</h4>
+
+<p>for use with the <i>resource</i> attribute.</p>
+
+<h3>Examples</h3>
+<pre>    &lt;loadproperties srcFile="file.properties"/&gt;
+</pre>
+or
+<pre>
+    &lt;loadproperties&gt;
+      &lt;file file="file.properties"/&gt;
+    &lt;/loadproperties&gt;
+</pre>
+Load contents of file.properties as Ant properties.
+
+<pre>    &lt;loadproperties srcFile="file.properties"&gt;
+      &lt;filterchain&gt;
+        &lt;<a href="../CoreTypes/filterchain.html#linecontains">linecontains</a>&gt;
+          &lt;contains value=&quot;import.&quot;/&gt;
+        &lt;/linecontains&gt;
+      &lt;/filterchain&gt;
+    &lt;/loadproperties&gt;
+</pre>
+Read the lines that contain the string &quot;import.&quot;
+from the file &quot;file.properties&quot; and load them as
+Ant properties.
+
+<pre>
+    &lt;loadproperties&gt;
+      &lt;<a href="../CoreTypes/resources.html#gzipresource">gzipresource</a>&gt;
+        &lt;<a href="../CoreTypes/resources.html#url">url</a> url="http://example.org/url.properties.gz"/&gt;
+      &lt;/gzipresource&gt;
+    &lt;/loadproperties&gt;
+</pre>
+Load contents of http://example.org/url.properties.gz, uncompress it
+on the fly and load the contents as Ant properties.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/loadresource.html b/trunk/docs/manual/CoreTasks/loadresource.html
new file mode 100755
index 0000000..d6c5d75
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/loadresource.html
@@ -0,0 +1,90 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>LoadResource Task</title>
+</head>
+
+<body>
+
+
+<h2><a name="loadresource">LoadResource</a></h2>
+
+<p><em>Since Ant 1.7</em></p>
+
+<h3>Description</h3>
+<p>
+Load a text resource into a single property. Unless an encoding is
+specified, the encoding of the current locale is used.  Resources to
+load are specified as nested <a
+href="../CoreTypes/resources.html">resource</a> elements or single
+element resource collections. If the resource content is empty (maybe after
+processing a filterchain) the property is not set.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">property to save to</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">encoding to use when loading the resource</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Whether to halt the build on failure</td>
+    <td align="center" valign="top">No, default "true"</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">Do not display a diagnostic message (unless Ant has been 
+    invoked with the <code>-verbose</code> or <code>-debug</code>
+    switches) or modify the exit status to reflect an error. Setting this to 
+    "true" implies setting failonerror to "false".
+    </td>
+    <td align="center" valign="top">No, default "false"</td>
+  </tr>
+</table>
+<p>
+The LoadResource task supports nested <a href="../CoreTypes/filterchain.html">
+FilterChain</a>s.
+
+<h3>Examples</h3>
+<pre>
+&lt;loadresource property="homepage"&gt;
+  &lt;url url="http://ant.apache.org/index.html"/&gt;
+&lt;/loadresource&gt;
+</pre>
+Load the entry point of Ant's homepage into property "homepage"; an
+<tt>&lt;echo&gt;</tt> can print this.
+
+<p>For more examples see the <a href="loadfile.html">loadfile</a> task.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/macrodef.html b/trunk/docs/manual/CoreTasks/macrodef.html
new file mode 100644
index 0000000..5609b9d
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/macrodef.html
@@ -0,0 +1,376 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+    <title>MacroDef Task</title>
+  </head>
+
+  <body>
+
+    <h2><a name="macrodef">MacroDef</a></h2>
+    <h3>Description</h3>
+    <p>
+      This defines a new task using a <code>&lt;sequential&gt;</code>
+      nested task as a template. Nested elements <code>&lt;attribute&gt;</code> and
+      <code>&lt;element&gt;</code> are used to specify attributes and elements of
+      the new task. These get substituted into the <code>&lt;sequential&gt;</code>
+      task when the new task is run.
+    </p>
+    <h3>Note</h3>
+    <p>
+      You can also use <i>prior defined</i> attributes for default-values in
+      other attributes. See the examples.
+    </p>
+    <p>
+      <em>since Ant 1.6</em>
+    </p>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">The name of the new definition.</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">uri</td>
+        <td valign="top">
+          The uri that this definition should live in.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">description</td>
+        <td valign="top">A description of the macrodef
+          (for documentation purposes only).
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">backtrace</td>
+        <td valign="top">
+          This controls the error traceback if they is an
+          error detected when running the macro. If this is
+          set to true, there will be an error trackback, if false
+          there will not be one. <em>Since Ant 1.7</em>.
+        </td>
+        <td valign="top" align="center">No; default <em>true</em></td>
+      </tr>
+    </table>
+      <h3>Parameters specified as nested elements</h3>
+    <h4>attribute</h4>
+    <p>
+      This is used to specify attributes of the new task. The values
+      of the attributes get substituted into the templated task.
+      The attributes will be required attributes unless a default
+      value has been set.
+    </p>
+    <p>
+      This attribute is placed in the body of the templated
+      task using a notation similar to the ant property notation
+      - @{attribute name}. (May be remembered as "put the substitution
+      AT this location").
+    </p>
+    <p>
+      The escape sequence @@ is used to escape @. This allows @{x} to be
+      placed in the text without substitution of x by using @@{x}.
+      This corresponds to the $$ escape sequence for properties.
+    </p>
+    <p>
+      The case of the attribute is ignored, so @{myAttribute} is treated the
+      same as @{MyAttribute}.
+    </p>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">The name of the new attribute</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">default</td>
+        <td valign="top">
+          The default value of the attribute.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">description</td>
+        <td valign="top">
+          This contains a description of the attribute.
+          <em>since ant 1.6.1</em>
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+    <h4>element</h4>
+    <p>
+      This is used to specify nested elements of the new task.
+      The contents of the nested elements of the task instance
+      are placed in the templated task at the tag name.
+    </p>
+    <p>
+      The case of the element name is ignored.
+    </p>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">The name of the element</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">optional</td>
+        <td valign="top">
+          If true this nested element is optional. Default is
+          false - i.e the nested element is required in
+          the new task.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">implicit</td>
+        <td valign="top">
+          If true this nested element is implicit. This means that
+          any nested elements of the macrodef instance will be placed
+          in the element indicated by the name of this element.
+          There can only be one element if an element is implicit.
+          The default value is false. <em>since ant 1.6.2</em>
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">description</td>
+        <td valign="top">
+          This contains a description
+          informing the user what the contents of the element are expected to be.
+          <em>since ant 1.6.1</em>
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+    <h4>text</h4>
+    <p>
+      This is used to specify the treatment of text contents of the macro invocation.
+      If this element is not present, then any nested text in the macro invocation
+      will be an error. If the text element is present, then the name
+      becomes an attribute that gets set to the nested text of the macro invocation.
+      <em>Since ant 1.6.1.</em>
+    </p>
+    <p>
+      The case of the text name is ignored.
+    </p>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">The name of the text attribute</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">optional</td>
+        <td valign="top">
+          If true nested text in the macro is optional, default is "false".
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">trim</td>
+        <td valign="top">
+          If true, the nested text is trimmed of white space,
+          default is "false".
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">description</td>
+        <td valign="top">
+          This contains a description
+          informing the user what the nested text of the macro is expected
+          to be.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <h3>Examples</h3>
+    <p>
+      The following example defined a task called testing and
+      runs it.
+    </p>
+    <blockquote>
+<pre class=code>
+&lt;macrodef name="testing"&gt;
+   &lt;attribute name="v" default="NOT SET"/&gt;
+   &lt;element name="some-tasks" optional="yes"/&gt;
+   &lt;sequential&gt;
+      &lt;echo&gt;v is @{v}&lt;/echo&gt;
+      &lt;some-tasks/&gt;
+   &lt;/sequential&gt;
+&lt;/macrodef&gt;
+
+&lt;testing v="This is v"&gt;
+   &lt;some-tasks&gt;
+      &lt;echo&gt;this is a test&lt;/echo&gt;
+   &lt;/some-tasks&gt;
+&lt;/testing&gt;
+</pre>
+    </blockquote>
+    <p>
+      The following fragment defines a task called <code>&lt;call-cc&gt;</code> which
+      take the attributes "target", "link" and "target.dir" and the
+      nested element "cc-elements". The body of the task
+      uses the <code>&lt;cc&gt;</code> task from the
+      <a href="http://ant-contrib.sourceforge.net/">ant-contrib</a> project.
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;macrodef name="call-cc"&gt;
+   &lt;attribute name="target"/&gt;
+   &lt;attribute name="link"/&gt;
+   &lt;attribute name="target.dir"/&gt;
+   &lt;element name="cc-elements"/&gt;
+   &lt;sequential&gt;
+      &lt;mkdir dir="${obj.dir}/@{target}"/&gt;
+      &lt;mkdir dir="@{target.dir}"/&gt;
+         &lt;cc link="@{link}" objdir="${obj.dir}/@{target}"
+             outfile="@{target.dir}/@{target}"&gt;
+            &lt;compiler refid="compiler.options"/&gt;
+            &lt;cc-elements/&gt;
+         &lt;/cc&gt;
+      &lt;/sequential&gt;
+&lt;/macrodef&gt;
+</pre>
+    </blockquote>
+    <p>
+      This then can be used as follows:
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;call-cc target="unittests" link="executable"
+         target.dir="${build.bin.dir}"&gt;
+   &lt;cc-elements&gt;
+      &lt;includepath location="${gen.dir}"/&gt;
+      &lt;includepath location="test"/&gt;
+      &lt;fileset dir="test/unittest" includes = "**/*.cpp"/&gt;
+      &lt;fileset dir="${gen.dir}" includes = "*.cpp"/&gt;
+      &lt;linker refid="linker-libs"/&gt;
+   &lt;/cc-elements&gt;
+&lt;/call-cc&gt;
+</pre>
+    </blockquote>
+    <p>
+      The following fragment shows &lt;call-cc&gt;, but this time
+      using an implicit element and with the link and target.dir arguments
+      having default values.
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;macrodef name="call-cc"&gt;
+   &lt;attribute name="target"/&gt;
+   &lt;attribute name="link" default="executable"/&gt;
+   &lt;attribute name="target.dir" default="${build.bin.dir}"/&gt;
+   &lt;element name="cc-elements" implicit="yes"/&gt;
+   &lt;sequential&gt;
+      &lt;mkdir dir="${obj.dir}/@{target}"/&gt;
+      &lt;mkdir dir="@{target.dir}"/&gt;
+         &lt;cc link="@{link}" objdir="${obj.dir}/@{target}"
+             outfile="@{target.dir}/@{target}"&gt;
+            &lt;compiler refid="compiler.options"/&gt;
+            &lt;cc-elements/&gt;
+         &lt;/cc&gt;
+      &lt;/sequential&gt;
+&lt;/macrodef&gt;
+</pre>
+    </blockquote>
+    <p>
+      This then can be used as follows, note that &lt;cc-elements&gt;
+      is not specified.
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;call-cc target="unittests"/&gt;
+   &lt;includepath location="${gen.dir}"/&gt;
+   &lt;includepath location="test"/&gt;
+   &lt;fileset dir="test/unittest" includes = "**/*.cpp"/&gt;
+   &lt;fileset dir="${gen.dir}" includes = "*.cpp"/&gt;
+   &lt;linker refid="linker-libs"/&gt;
+&lt;/call-cc&gt;
+</pre>
+    </blockquote>
+    <p>
+      The following shows the use of the <code>text</code> element.
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;macrodef name="echotest"&gt;
+   &lt;text name="text"/&gt;
+   &lt;sequential&gt;
+      &lt;echo&gt;@{text}&lt;/echo&gt;
+   &lt;/sequential&gt;
+&lt;/macrodef&gt;
+&lt;echotest&gt;
+   Hello world
+&lt;/echotest&gt;
+</pre>
+    </blockquote>
+    <p>
+      The following uses a prior defined attribute for setting the
+      default value of another. The output would be
+      <tt>one=test two=test</tt>. If you change the order of lines
+      *1 and *2 the output would be <tt>one=test two=@{one}</tt>,
+      because while processing the <i>two</i>-line the value for
+      <i>one</i> is not set.
+    </p>
+    <blockquote>
+<pre class="code">
+&lt;macrodef name="test"&gt;
+   &lt;attribute name="one"/&gt;                     <b>*1</b>
+   &lt;attribute name="two" default="@{one}"/&gt;    <b>*2</b>
+   &lt;sequential&gt;
+      &lt;echo&gt;one=@{one}   two=@{two}&lt;/echo&gt;
+   &lt;/sequential&gt;
+&lt;/macrodef&gt;
+&lt;test one="test"/&gt;
+</pre>
+    </blockquote>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/mail.html b/trunk/docs/manual/CoreTasks/mail.html
new file mode 100644
index 0000000..4081904
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/mail.html
@@ -0,0 +1,324 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Mail Task</title>
+</head>
+
+<body>
+
+<h2><a name="mail">Mail</a></h2>
+<h3>Description</h3>
+  <p>
+    A task to send SMTP email.
+  </p>
+  <p>
+    This task can send mail using either plain
+    text, UU encoding, or MIME format mail, depending on what is available.
+  </p>
+  <p>
+    SMTP auth and SSL/TLS require JavaMail and are only available in MIME format.
+  </p>
+  <p>
+    Attachments may be sent using nested
+    <code>&lt;attachments&gt;</code> elements, which are <a
+    href="../using.html#path">path-like structures</a>.  This means
+    any filesystem based <a
+    href="../CoreTypes/resources.html">resource</a> or resource
+    collection can be used to point to attachments.  Prior to Ant 1.7
+    only <code>&lt;fileset&gt;</code> has been supported as a nested
+    element, you can still use this directly without an
+    <code>&lt;attachments&gt;</code> container.
+  </p>
+  <p>
+    <strong>Note:</strong> This task may depend on external libraries
+    that are not included in the Ant distribution. 
+    See <a href="../install.html#librarydependencies">Library Dependencies</a>
+    for more information.
+  </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">from</td>
+    <td valign="top">Email address of sender.</td>
+    <td align="center" valign="top">Either a <code>from</code> attribute, or a <code>&lt;from&gt;</code>
+    element.</td>
+  </tr>
+  <tr>
+    <td valign="top">replyto</td>
+    <td valign="top">Replyto email address.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tolist</td>
+    <td valign="top">Comma-separated list of recipients.</td>
+    <td align="center" valign="middle" rowspan="3">At least one of these, or the
+       equivalent elements.</td>
+  </tr>
+  <tr>
+    <td valign="top">cclist</td>
+    <td valign="top">Comma-separated list of recipients to carbon copy</td>
+    </tr>
+  <tr>
+    <td valign="top">bcclist</td>
+    <td valign="top">Comma-separated list of recipients to blind carbon copy
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">message</td>
+    <td valign="top">Message to send in the body of the email.</td>
+    <td align="center" valign="middle" rowspan="2">One of these or a
+    <code>&lt;message&gt;</code> element.</td>
+  </tr>
+  <tr>
+    <td valign="top">messagefile</td>
+    <td valign="top">File to send as the body of the email. Property
+    values in the file will be expanded.</td>
+  </tr>
+      <td valign="top">messagemimetype</td>
+    <td valign="top">The content type of the message.  The default is
+    <code>text/plain</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">files</td>
+    <td valign="top">Files to send as attachments to the email.  Separate multiple
+    file names using a comma or space.  You can also use <code>&lt;fileset&gt;</code>
+    elements to specify files.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">flag to indicate whether to halt the build on
+    any error.  The default value is <code>true</code>.</td>
+    <td align="center" valign="top">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">includefilenames</td>
+    <td valign="top">Include filename(s) before file contents.
+    Valid only when the <code>plain</code> encoding is used.  The default
+    value is <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mailhost</td>
+    <td valign="top">Host name of the SMTP server.  The default value is
+    <code>localhost</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mailport</td>
+    <td valign="top">TCP port of the SMTP server.  The default value is 25.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">user</td>
+    <td valign="top">user name for SMTP auth</td>
+    <td valign="center">Yes, if SMTP auth is required on your SMTP server<br></br>
+    the email message will be then sent using Mime and requires JavaMail</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">password for SMTP auth</td>
+    <td valign="center">Yes, if SMTP auth is required on your SMTP server<br></br>
+    the email message will be then sent using Mime and requires JavaMail</td>
+  </tr>
+  <tr>
+    <td valign="top">ssl</td>
+    <td valign="top">"true", "on" or "yes" accepted here<br></br>
+    indicates whether you need TLS/SSL</td>
+    <td valign="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">Specifies the encoding to use for the content of the email.
+    Values are <code>mime</code>, <code>uu</code>, <code>plain</code>, or
+      <code>auto</code>.  The default value is <code>auto</code>.
+      <code>uu</code> or <code>plain</code> are not compatible with SMTP auth</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">charset</td>
+    <td valign="top">Character set of the email.<br>
+    You can also set the charset in the message nested element.<br>
+    These options are mutually exclusive.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">subject</td>
+    <td valign="top">Email subject line.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Note regarding the attributes containing email addresses</h3>
+Since Ant 1.6, the attributes from, replyto, tolist, cclist, bcclist
+can contain email addresses of the form :
+<ul>
+<li>address@xyz.com</li>
+<li>name &lt;address@xyz.com&gt;</li>
+<li>&lt;address@xyz.com&gt; name</li>
+<li>(name) address@xyz.com</li>
+<li>address@xyz.com (name)</li>
+</ul>
+<p>You need to enter the angle brackets as XML entities
+<code>&amp;gt;</code> and <code>&amp;lt;</code>.</p>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>to / cc / bcc / from/ replyto </h4>
+<p>Adds an email address element.  It takes the following attributes:</p>
+
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The display name for the address.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">address</td>
+    <td valign="top">The email address.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4>message</h4>
+
+<p>Specifies the message to include in the email body.  It takes the following
+attributes:</p>
+
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">The file to use as the message.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mimetype</td>
+    <td valign="top">The content type to use for the message.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">charset</td>
+    <td valign="top">Character set of the message<br>
+    You can also set the charset as attribute of the enclosing mail task.<br>
+    These options are mutually exclusive.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>If the <code>src</code> attribute is not specified, then text can be added
+inside the <code>&lt;message&gt;</code> element. Property expansion will occur
+in the message, whether it is specified as an external file or as text within
+the <code>&lt;message&gt;</code> element.</p>
+
+<h4>header</h4>
+<p><strong>Since Ant 1.7</strong>, arbitrary mail headers can be added by
+  specifying these attributes on one or more nested header elements:</p>
+
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name associated with this mail header.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The value to assign to this mail header.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<p>It is permissible to duplicate the name attribute amongst multiple headers.
+</p>
+
+<h3>Examples</h3>
+
+<blockquote><pre>
+&lt;mail from=&quot;me&quot;
+      tolist=&quot;you&quot;
+      subject=&quot;Results of nightly build&quot;
+      files=&quot;build.log&quot;/&gt;
+</pre></blockquote>
+
+<p>Sends an email from <i>me</i> to <i>you</i> with a subject of
+<i>Results of nightly build</i> and includes the contents of the file
+<i>build.log</i> in the body of the message.</p>
+
+<blockquote><pre>
+&lt;mail mailhost=&quot;smtp.myisp.com&quot; mailport=&quot;1025&quot; subject=&quot;Test build&quot;&gt;
+  &lt;from address=&quot;config@myisp.com&quot;/&gt;
+  &lt;replyto address=&quot;me@myisp.com&quot;/&gt;
+  &lt;to address=&quot;all@xyz.com&quot;/&gt;
+  &lt;message&gt;The ${buildname} nightly build has completed&lt;/message&gt;
+  &lt;attachments&gt;
+    &lt;fileset dir=&quot;dist&quot;&gt;
+      &lt;include name=&quot;**/*.zip&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;/attachments&gt;
+&lt;/mail&gt;
+</pre></blockquote>
+
+<p>Sends an eMail from <i>config@myisp.com</i> to <i>all@xyz.com</i> with a subject of
+<i>Test Build</i>. Replies to this email will go to <i>me@myisp.com</i>.
+Any zip files from the dist directory are attached.&nbsp; The
+task will attempt to use JavaMail and fall back to UU encoding or no encoding in
+that order depending on what support classes are available. <code>${buildname}</code>
+will be replaced with the <code>buildname</code> property's value.</p>
+
+<blockquote><pre>
+&lt;property name=&quot;line2&quot; value=&quot;some_international_message&quot;/&gt;
+&lt;echo message=&quot;${line2}&quot;/&gt;
+
+&lt;mail mailhost=&quot;somehost@xyz.com&quot; mailport=&quot;25&quot; subject=&quot;Test build&quot;  charset=&quot;utf-8&quot;&gt;
+  &lt;from address=&quot;me@myist.com&quot;/&gt;
+  &lt;to address=&quot;all@xyz.com&quot;/&gt;
+  &lt;message&gt;some international text:${line2}&lt;/message&gt;
+&lt;/mail&gt;
+</pre></blockquote>
+
+<p>Sends an eMail from <i>me@myisp.com</i> to <i>all@xyz.com</i> with a subject of
+<i>Test Build</i>, the message body being coded in UTF-8
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/makeurl.html b/trunk/docs/manual/CoreTasks/makeurl.html
new file mode 100644
index 0000000..bef63e2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/makeurl.html
@@ -0,0 +1,236 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Makeurl
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Makeurl
+ Task</strong></font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0"/>
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+This task takes one or more filenames and turns them into URLs, which it then assigns to a property.
+Useful when setting up RMI or JNLP codebases, for example.
+Nested filesets are supported; if present, these are turned into the URLs with the supplied separator between them (default: space).
+<p/>
+<p>Examples:</p>
+<pre>
+&lt;makeurl file="${user.home}/.m2/repository" property="m2.repository.url"/&gt;
+</pre>
+Sets the property <code>m2.repository.url</code> to the file: URL of the local Maven2 repository.
+<pre>
+&lt;makeurl property="codebase"&gt;&lt;fileset dir="lib includes="*.jar"/&gt;&lt;/makeurl&gt;
+</pre>
+Set the property <code>codebase</code> to the three URLs of the files provided as nested elements.
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+ <!-- Ignore -->
+
+
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">file</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">name of a file to be converted into a URL</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optional, if a nested fileset or path is supplied</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">property</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">name of a property to set to the URL</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">required</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">separator</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">separator for the multi-URL option</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">validate</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">validate that every named file exists</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optional; default: true</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>fileset</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        A fileset of JAR files to include in the URL list, each separated by the separator.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>path</strong> (org.apache.tools.ant.types.Path)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Add a path to the URL. All elements in the path will be converted to individual URL entries.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/manifest.html b/trunk/docs/manual/CoreTasks/manifest.html
new file mode 100644
index 0000000..60cf180
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/manifest.html
@@ -0,0 +1,176 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Manifest Task</title>
+</head>
+
+<body>
+
+<h2><a name="manifest">Manifest</a></h2>
+<h3>Description</h3>
+<p>Creates a manifest file.</p>
+
+<p>This task can be used to write a Manifest file, optionally
+replacing or updating an existing file.</p>
+
+
+
+<p>Manifests are processed according to the 
+<a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html">Jar
+file specification.</a>. Specifically, a manifest element consists of
+a set of attributes and sections. These sections in turn may contain
+attributes. Note in particular that this may result in manifest lines
+greater than 72 bytes being wrapped and continued on the next
+line.</p>
+
+<p>
+  The Ant team regularly gets complaints that this task in generating invalid
+  manifests. By and large, this is not the case: we believe that we are following
+  the specification to the letter. The usual problem is that some third party
+  manifest reader is not following the same specification as well as they think
+  they should; we cannot generate invalid manifest files just because one
+  single application is broken. J2ME runtimes appear to be particularly troublesome.
+</p>
+
+<p>
+  If you find that Ant generates manifests incompatible with your runtime, take
+  a manifest it has built, fix it up however you need and switch to using the &lt;zip&gt
+  task to create the JAR, feeding in the hand-crafted manifest.
+</p>
+
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the manifest-file to create/update.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">mode</td>
+    <td valign="top">One of "update" or "replace", default is "replace".</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding used to read the existing manifest when updating.</td>
+    <td valign="top" align="center">No, defaults to UTF-8 encoding.</td>
+  </tr>
+</table>
+
+<h3>Nested elements</h3>
+<h4><a name="attribute">attribute</a></h4>
+<p>One attribute for the manifest file.  Those attributes that are
+not nested into a section will be added to the "Main" section.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the attribute, <br>
+        must match the regexp <tt>[A-Za-z0-9][A-Za-z0-9-_]*</tt>.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the value of the attribute.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+
+<h4>section</h4>
+<p>A manifest section - you can nest <a
+href="#attribute">attribute</a> elements into sections.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the section.</td>
+    <td valign="top" align="center">No, if omitted it will be assumed
+       to be the main section.</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+<pre>
+  &lt;manifest file=&quot;MANIFEST.MF&quot;&gt;
+    &lt;attribute name=&quot;Built-By&quot; value=&quot;${user.name}&quot;/&gt;
+    &lt;section name=&quot;common&quot;&gt;
+      &lt;attribute name=&quot;Specification-Title&quot; value=&quot;Example&quot;/&gt;
+      &lt;attribute name=&quot;Specification-Version&quot; value=&quot;${version}&quot;/&gt;
+      &lt;attribute name=&quot;Specification-Vendor&quot; value=&quot;Example Organization&quot;/&gt;
+      &lt;attribute name=&quot;Implementation-Title&quot; value=&quot;common&quot;/&gt;
+      &lt;attribute name=&quot;Implementation-Version&quot; value=&quot;${version} ${TODAY}&quot;/&gt; 
+      &lt;attribute name=&quot;Implementation-Vendor&quot; value=&quot;Example Corp.&quot;/&gt;
+    &lt;/section&gt;
+    &lt;section name=&quot;common/class1.class&quot;&gt;
+      &lt;attribute name=&quot;Sealed&quot; value=&quot;false&quot;/&gt;
+    &lt;/section&gt;
+  &lt;/manifest&gt;
+</pre>
+
+<p>Creates or replaces the file MANIFEST.MF.  Note that the Built-By
+attribute will take the value of the Ant property ${user.name}.  The
+same is true for the ${version} and ${TODAY} properties.  This example
+produces a MANIFEST.MF that contains 
+<a href="http://java.sun.com/j2se/1.5.0/docs/guide/versioning/">package
+version identification</a> for the package <code>common</code>.</p>
+
+<p>The manifest produced by the above would look like this:</p>
+
+<pre><code>Manifest-Version: 1.0
+Built-By: bodewig
+Created-By: Apache Ant 1.7
+
+Name: common
+Specification-Title: Example
+Specification-Vendor: Example Organization
+Implementation-Vendor: Example Corp.
+Specification-Version: 1.2
+Implementation-Version: 1.2 February 19 2006
+Implementation-Title: common
+
+Name: common/class1.class
+Sealed: false
+
+</code></pre>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/manifestclasspath.html b/trunk/docs/manual/CoreTasks/manifestclasspath.html
new file mode 100644
index 0000000..a065aaa
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/manifestclasspath.html
@@ -0,0 +1,112 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ManifestClassPath Task</title>
+</head>
+
+<body>
+
+<h2><a name="manifestclasspath">Manifestclasspath</a></h2>
+
+<h3>Description</h3>
+<p>Converts a <a href="../using.html#path">Path</a> into a property
+whose value is appropriate for a <a href="manifest.html">Manifest</a>'s
+<code>Class-Path</code> attribute.</p>
+
+<p>This task is often used to work around command line limitations on Windows
+when using very long class paths when launching an application. The long class
+path normally specified on the command line is replaced by a single (possibly
+empty) jar file which an in-manifest Class-Path attribute whose value lists
+all the jar and zip files the class path should contain. The files referenced
+from this attribute must be found relatively to the jar file itself, usually
+in the same directory. The Java VM automically uses all file entries listed
+in the Class-Path attributes of a jar to locate/load classes. Note though that
+it silently ignores entries for which it cannot find any corresponding file.</p>
+
+<p>Note that the property value created may be longer than a manifest's maximum
+72 characters per line, but will be properly wrapped as per the Jar
+specification by the <code>&lt;manifest&gt;</code> element, where the
+defined property is re-referenced.</p>
+
+<p><em>since Ant 1.7</em></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">the name of the property to set. This property must
+                     not already be set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">jarfile</td>
+    <td valign="top">
+      the filename for the Jar which will contain the manifest that will
+      use the property this task will set. This file need not exist yet,
+      but its parent directory must exist.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">maxParentLevels</td>
+    <td valign="top">
+      The maximum number of parent directories one is allowed to traverse
+      to navigate from the jar file to the path entry. Put differently, the
+      maximum number of .. which is allowed in the relative path from the
+      jar file to a given class path enty. Specify 0 to enforce a path
+      entry to be in the same directory (or one of its sub-directories)
+      as the jar file itself.  Defaults to 2 levels.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<h4>classpath</h4>
+<p>A <a href="../using#path.html">Path-like</a> element, which can be
+defined in-place, or refer to a path defined elsewhere using the
+<code>&lt;classpath refid="<em>pathid</em>" /&gt;</code> syntax.
+This classpath must not be empty, and is required.</p>
+
+<h3>Examples</h3>
+<div id="example1">
+  <blockquote><pre>
+    &lt;manifestclasspath property="jar.classpath"
+                       jarfile="build/acme.jar"&gt;
+      &lt;classpath refid="classpath" /&gt;
+    &lt;/manifestclasspath&gt;
+  </pre></blockquote>
+  <p>Assuming a path of id "classpath" was already defined, convert this
+  path relatively to the build/ directory that will contain acme.jar, which
+  can later be created with <code>&lt;jar&gt;</code> with a nested 
+  <code>&lt;manifest&gt;</code> element that lists an
+  <code>&lt;attribute name="Class-Path" value="${jar.classpath}" /&gt;</code>.
+  </p>
+</div>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/mkdir.html b/trunk/docs/manual/CoreTasks/mkdir.html
new file mode 100644
index 0000000..5d945c0
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/mkdir.html
@@ -0,0 +1,52 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Mkdir Task</title>
+</head>
+
+<body>
+
+<h2><a name="mkdir">Mkdir</a></h2>
+<h3>Description</h3>
+<p>Creates a directory. Also non-existent parent directories are created, when
+necessary. Does nothing if the directory already exist.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the directory to create.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>&lt;mkdir dir=&quot;${dist}&quot;/&gt;</pre>
+<p>creates a directory <code>${dist}</code>.</p>
+<pre>&lt;mkdir dir=&quot;${dist}/lib&quot;/&gt;</pre>
+<p>creates a directory <code>${dist}/lib</code>.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/move.html b/trunk/docs/manual/CoreTasks/move.html
new file mode 100644
index 0000000..8f81162
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/move.html
@@ -0,0 +1,230 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Move Task</title>
+</head>
+
+<body>
+
+<h2><a name="move">Move</a></h2>
+<h3>Description</h3>
+<p>Moves a file to a new file or directory, or collections of files to
+a new directory.  By default, the
+destination file is overwritten if it already exists.  When <var>overwrite</var> is
+turned off, then files are only moved if the source file is newer than
+the destination file, or when the destination file does not exist.</p>
+
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select a group of files to move.  Only
+file system based resource collections are supported, this includes <a
+href="../CoreTypes/fileset.html">fileset</a>s, <a
+href="../CoreTypes/filelist.html">filelist</a> and <a
+href="../using.html#path">path</a>.  Prior to Ant 1.7 only
+<code>&lt;fileset&gt;</code> has been supported as a nested element.
+To use a resource collection, the <code>todir</code> attribute must be
+set.</p>
+
+<p><b>Since Ant 1.6.3</b>, the <i>file</i> attribute may be used to move
+(rename) an entire directory.  If <i>tofile</i> denotes an existing file, or
+there is a directory by the same name in <i>todir</i>, the action will fail.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file or directory to move</td>
+    <td valign="top" align="center">One of <var>file</var> or
+     at least one nested resource collection element</td>
+  </tr>
+  <tr>
+    <td valign="top">preservelastmodified</td>
+    <td valign="top">Give the moved files the same last modified
+      time as the original source files.
+      (<em>Note</em>: Ignored on Java 1.1)</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">tofile</td>
+    <td valign="top">the file to move to</td>
+    <td valign="top" align="center" rowspan="2">With the <var>file</var> attribute,
+    either <var>tofile</var> or <var>todir</var> can be used.  With nested filesets,
+    if the fileset size is greater than 1 or if the only entry in the fileset is a
+    directory or if the <var>file</var> attribute is already specified, only
+    <var>todir</var> is allowed</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">the directory to move to</td>
+  </tr>
+  <tr>
+    <td valign="top">overwrite</td>
+    <td valign="top">overwrite existing files even if the destination
+      files are newer (default is &quot;true&quot;)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filtering</td>
+    <td valign="top">indicates whether token filtering should take place during
+      the move.  See the <a href="filter.html">filter</a> task for a description of
+      how filters work.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">flatten</td>
+    <td valign="top">ignore directory structure of source directory,
+      copy all files into a single directory, specified by the <var>todir</var>
+      attribute (default is &quot;false&quot;).Note that you can achieve the
+      same effect by using a <a href="../CoreTypes/mapper.html#flatten-mapper">flatten mapper</a></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeEmptyDirs</td>
+	 <td valign="top">Copy empty directories included with the nested FileSet(s).
+	   Defaults to &quot;yes&quot;.</td>
+	 <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">If false, log a warning message, but do not stop the
+       build, when the file to copy does not exist or one of the nested
+       filesets points to a directory that doesn't exist or an error occurs
+       while moving.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+     <td valign="top">Log the files that are being moved.</td>
+     <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding to assume when filter-copying the
+    files. <em>since Ant 1.5</em>.</td>
+    <td align="center">No - defaults to default JVM encoding</td>
+  </tr>
+  <tr>
+    <td valign="top">outputencoding</td>
+    <td valign="top">The encoding to use when writing the files.
+    <em>since Ant 1.6</em>.</td>
+    <td align="center">No - defaults to the value of the encoding
+    attribute if given or the default JVM encoding otherwise.</td>
+  </tr>
+  <tr>
+    <td valign="top">enablemultiplemapping</td>
+    <td valign="top">
+      If true the task will process to all the mappings for a
+      given source path. If false the task will only process
+      the first file or directory. This attribute is only relevant
+      if there is a mapper subelement.
+      <em>since Ant 1.6</em>.</td>
+    <td align="center">No - defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">granularity</td>
+    <td valign="top">The number of milliseconds leeway to give before
+    deciding a file is out of date. This is needed because not every
+    file system supports tracking the last modified time to the
+    millisecond level. Default is 0 milliseconds, or 2 seconds on DOS
+    systems.  This can also be useful if source and target files live
+    on separate machines with clocks being out of sync.  <em>since Ant
+    1.6</em>.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>mapper</h4>
+<p>You can define file name transformations by using a nested <a
+href="../CoreTypes/mapper.html">mapper</a> element. The default mapper used by
+<code>&lt;move&gt;</code> is the <a
+href="../CoreTypes/mapper.html#identity-mapper">identity</a>.</p>
+<p>Note that the source name handed to the mapper depends on the
+resource collection you use.  If you use <code>&lt;fileset&gt;</code>
+or any other collection that provides a base directory, the name
+passed to the mapper will be a relative filename, relative to the base
+directory.  In any other case the absolute filename of the source will
+be used.</p>
+<h4>filterchain</h4>
+<p>The Move task supports nested <a href="../CoreTypes/filterchain.html">
+FilterChain</a>s.</p>
+
+<p>
+If <code>&lt;filterset&gt;</code> and <code>&lt;filterchain&gt;</code> elements are used inside the
+same <code>&lt;move&gt;</code> task, all <code>&lt;filterchain&gt;</code> elements are processed first
+followed by <code>&lt;filterset&gt;</code> elements.
+</p>
+
+<h3>Examples</h3>
+<p><b>Move a single file (rename a file)</b></p>
+<pre>
+  &lt;move file=&quot;file.orig&quot; tofile=&quot;file.moved&quot;/&gt;
+</pre>
+<p><b>Move a single file to a directory</b></p>
+<pre>
+  &lt;move file=&quot;file.orig&quot; todir=&quot;dir/to/move/to&quot;/&gt;
+</pre>
+<p><b>Move a directory to a new directory</b></p>
+<pre>
+  &lt;move todir=&quot;new/dir/to/move/to&quot;&gt;
+    &lt;fileset dir=&quot;src/dir&quot;/&gt;
+  &lt;/move&gt;
+</pre>
+  <i>or, since Ant 1.6.3:</i>
+<pre>
+  &lt;move file=&quot;src/dir&quot; tofile=&quot;new/dir/to/move/to&quot;/&gt;
+</pre>
+<p><b>Move a set of files to a new directory</b></p>
+<pre>
+  &lt;move todir=&quot;some/new/dir&quot;&gt;
+    &lt;fileset dir=&quot;my/src/dir&quot;&gt;
+      &lt;include name=&quot;**/*.jar&quot;/&gt;
+      &lt;exclude name=&quot;**/ant.jar&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;/move&gt;
+</pre>
+<p><b>Move a list of files to a new directory</b></p>
+<pre>
+  &lt;move todir=&quot;some/new/dir&quot;&gt;
+    &lt;filelist dir=&quot;my/src/dir&quot;&gt;
+      &lt;file name="file1.txt"/&gt;
+      &lt;file name="file2.txt"/&gt;
+    &lt;/filelist&gt;
+  &lt;/move&gt;
+</pre>
+<p><b>Append <code>&quot;.bak&quot;</code> to the names of all files
+in a directory.</b></p>
+<pre>
+  &lt;move todir=&quot;my/src/dir&quot; includeemptydirs=&quot;false&quot;&gt;
+    &lt;fileset dir=&quot;my/src/dir&quot;&gt;
+      &lt;exclude name=&quot;**/*.bak&quot;/&gt;
+    &lt;/fileset&gt;
+    &lt;mapper type=&quot;glob&quot; from=&quot;*&quot; to=&quot;*.bak&quot;/&gt;
+  &lt;/move&gt;
+</pre>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/nice.html b/trunk/docs/manual/CoreTasks/nice.html
new file mode 100644
index 0000000..03c0eaa
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/nice.html
@@ -0,0 +1,70 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Nice Task</title>
+</head>
+
+<body>
+
+<h2><a name="echo">Nice</a></h2>
+<h3>Description</h3>
+<p>Provide "nice-ness" to the current thread
+   and/or query the current value.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">currentpriority</td>
+    <td valign="top">the name of the property whose value should be
+                     set to the current &quot;nice-ness&quot; level.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">newpriority</td>
+    <td valign="top">the value to which the
+                     &quot;nice-ness&quot; level should be set.
+                     Must be a valid Java Thread priority.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>   &lt;nice newpriority=&quot;10&quot;/&gt;</pre>
+Set the Thread priority to 10 (highest).
+<pre>   &lt;nice currentpriority=&quot;priority&quot;/&gt;</pre>
+Store the current Thread priority in the user property "priority".
+<pre>
+   &lt;nice currentpriority=&quot;currentpriority&quot; newpriority=&quot;1&quot;/&gt;
+</pre>
+<p>Set the current Thread priority to 1 (lowest), storing the original
+priority in the user property "currentpriority".  This
+can be used to set the priority back to its original value later.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/pack.html b/trunk/docs/manual/CoreTasks/pack.html
new file mode 100644
index 0000000..bf6d670
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/pack.html
@@ -0,0 +1,76 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>GZip/BZip2 Tasks</title>
+</head>
+
+<body>
+
+<h2><a name="pack">GZip/BZip2</a></h2>
+<h3>Description</h3>
+<p>Packs a resource using the GZip or BZip2 algorithm.
+The output file is only generated if it doesn't exist or the source
+resource is newer.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">the file to gzip/bzip.</td>
+    <td align="center" valign="top">Yes, or a nested resource collection.</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the destination file to create.</td>
+    <td align="center" valign="top" rowspan="2">Exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">zipfile</td>
+    <td valign="top">the <i>deprecated</i> old name of destfile.</td>
+  </tr>
+</table>
+<h4>any <a href="../CoreTypes/resources.html">resource</a> or single element
+resource collection</h4>
+
+<p>The specified resource will be used as src. <em>Since Ant 1.7</em></p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;gzip src=&quot;test.tar&quot; destfile=&quot;test.tar.gz&quot;/&gt;
+</pre></blockquote>
+<blockquote><pre>
+&lt;bzip2 src=&quot;test.tar&quot; destfile=&quot;test.tar.bz2&quot;/&gt;
+</pre></blockquote>
+<blockquote><pre>
+&lt;gzip destfile=&quot;archive.tar.gz&quot;&gt;
+  &lt;url url="http://example.org/archive.tar"/&gt;
+&lt;/gzip&gt;
+</pre></blockquote>
+<p>downloads <i>http://example.org/archive.tar</i> and compresses it
+to <i>archive.tar.gz</i> in the project's basedir on the fly.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/parallel.html b/trunk/docs/manual/CoreTasks/parallel.html
new file mode 100644
index 0000000..ad9a674
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/parallel.html
@@ -0,0 +1,236 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Parallel Task</title>
+</head>
+
+<body>
+
+<h2>Parallel</h2>
+<h3>Description</h3>
+<p>
+    Executes nested tasks in parallel with no guarantees of thread safety.
+    Every task will run in its own thread, with the likelihood of 
+    concurrency problems scaling with the number of CPUs on the host system.
+</p>
+<p><b>Warning:</b> While the Ant core is believed to be thread safe, no such 
+    guarantees are made about tasks, which are not tested for thread safety during
+    Ant's test process. 
+    Third party tasks may or may not be thread safe, and some of Ant's core tasks, such as
+    <code>&lt;javac&gt;</code> are definitely not re-entrant. This is because they use libraries that
+    were never designed to be used in a multithreaded environment.
+</p>
+<p>
+    The primary use case for <code>&lt;parallel&gt;</code> is to run external programs
+    such as an application server, and the JUnit or TestNG test suites at the
+    same time. Anyone trying to run large Ant task sequences in parallel, such
+    as javadoc and javac at the same time, is implicitly taking on the task
+    of identifying and fixing all concurrency bugs the tasks that they run.
+    
+</p>
+<p>
+    Accordingly, while this task has uses, it should be considered an advanced
+    task which should be used in certain batch-processing or testing situations,
+    rather than an easy trick to speed up build times on a multiway CPU. 
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">threadCount</td>
+    <td valign="top">Maximum numbers of thread to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">threadsPerProcessor</td>
+    <td valign="top">Maximum number of threads to use per available processor
+(Java 1.4+)</td>
+    <td align="center" valign="top">No, defers to threadCount</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Number of milliseconds before execution is terminated</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonany</td>
+    <td valign="top">If any of the nested tasks fails, execution of the task completes
+                     at that point without waiting for any other tasks to complete.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">pollInterval</td>
+    <td valign="top">Currently has no effect</td>
+    <td align="center" valign="top">No, default is 1000</td>
+  </tr>
+</table>
+
+<p>Parallel tasks have a number of uses in an Ant build file including:</p>
+<ul>
+<li>Taking advantage of available processing resources to execute external
+ programs simultaneously.</li>
+<li>Testing servers, where the server can be run in one thread and the test
+harness is run in another thread.</li>
+</ul>
+
+<p>Any valid Ant task may be embedded within a
+parallel task, including other parallel tasks, though there is no guarantee that
+the tasks will be thread safe in such an environment.</p>
+
+<p>While the tasks within the parallel task are being run, the main
+thread will be blocked waiting for all the child threads to complete. If
+execution is terminated by a timeout or a nested task failure when the
+<code>failonany</code>
+flag is set, the parallel task will complete without waiting for other nested
+tasks to complete in other threads.
+</p>
+
+<p>If any of the tasks within the <code>&lt;parallel&gt;</code> task fails and failonany is
+not set, the remaining tasks in other threads will continue to run until
+all threads have completed. In this situation, the parallel task will also fail.</p>
+
+<p>The parallel task may be combined with the <a href="sequential.html">
+sequential</a> task to define sequences of tasks to be executed on each thread
+within the parallel block</p>
+
+<p>The <code>threadCount</code> attribute can be used to place a maximum number of available
+threads for the execution.  When not present all child tasks will be executed at
+once.  When present then the maximum number of concurrently executing tasks will
+not exceed the number of threads specified.  Furthermore, each task will be
+started in the order they are given.  But no guarantee is made as to the speed
+of execution or the order of completion of the tasks, only that each will be
+started before the next.<p>
+
+<p>If you are using Java 1.4 or later you can also use the <code>threadsPerProcessor</code>
+and the number of available threads will be the stated multiple of the number of
+processors (there is no affinity to a particular processor however).  This will
+override the value in <code>threadCount</code>.  If <code>threadsPerProcessor</code>
+is specified on any older JVM, then the value in <code>threadCount</code> will be used as is.</p>
+
+<p>When using <code>threadCount</code> and  <code>threadsPerProcessor</code> 
+    care should be taken to ensure that the build does not deadlock.  
+    This can be caused by tasks such as <code>waitfor</code>
+    taking up all available threads before the tasks that would unlock the 
+    <code>waitfor</code>
+would occur.  This is not a replacement for Java Language level thread
+semantics and is best used for "embarassingly parallel" tasks.</p>
+
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>daemons</h4>
+<p>
+The parallel task supports a <code>&lt;daemons&gt;</code> nested element. This is a list of tasks
+which are to be run in parallel daemon threads. The parallel task will not wait for
+these tasks to complete. Being daemon threads, however, they will not prevent Ant from
+completing, whereupon the threads are terminated. Failures in daemon threads which
+occur before the parallel task itself finishes will be reported and can cause
+parallel to throw an exception. Failures which occur after parallel has completed are not
+reported.
+</p>
+
+<p>Daemon tasks can be used, for example, to start test servers which might not be easily
+terminated from Ant. By using <code>&lt;daemons&gt;</code> such servers do not halt the build.
+</p>
+
+
+<h3>Examples</h3>
+<pre>
+&lt;parallel&gt;
+  &lt;wlrun ... &gt;
+  &lt;sequential&gt;
+    &lt;sleep seconds=&quot;30&quot;/&gt;
+    &lt;junit fork="true" forkmode="once" ... &gt;
+    &lt;wlstop/&gt;
+  &lt;/sequential&gt;
+&lt;/parallel&gt;
+</pre>
+<p>This example represents a typical pattern for testing a server application.
+In one thread the server is started (the <code>&lt;wlrun&gt;</code> task). 
+The other thread consists
+of a three tasks which are performed in sequence. The <code>&lt;sleep&gt;</code> task is used to
+give the server time to come up. Another task which is capable of validating
+that the server is available could be used in place of the <code>&lt;sleep&gt;</code> task. The
+<code>&lt;junit&gt;</code> test harness then runs, again in its own JVM. Once the tests are complete, the server is stopped
+(using <code>&lt;wlstop&gt;</code> in this example), allowing both threads to complete. The
+<code>&lt;parallel&gt;</code> task will also complete at this time and the build will then
+continue.</p>
+
+<pre>
+&lt;parallel&gt;
+  &lt;javac fork="true"...&gt; &lt;!-- compiler servlet code --&gt;
+  &lt;wljspc ...&gt; &lt;!-- precompile JSPs --&gt;
+&lt;/parallel&gt;
+</pre>
+
+<p>This example shows two independent tasks being run to achieve better
+resource utilization during the build. In this instance, some servlets are being
+compiled in one thead and a set of JSPs is being precompiled in another. Developers
+need to be careful that the two tasks are independent, both in
+terms of their dependencies and in terms of their potential interactions in
+Ant's external environment. Here we set <code>fork="true"</code> for the 
+<code>&lt;javac&gt;</code> task, so that it runs in a new process; 
+if the <code>&lt;wljspc&gt;</code> task used the javac compiler in-VM
+(it may), concurrency problems may arise.
+</p>
+
+<taskdef name=""
+<pre>
+ &lt;macrodef name="dbpurge"&gt;
+    &lt;attribute file="file"/&gt;
+   &lt;sequential&gt;
+      &lt;java jar="utils/dbpurge.jar" fork="true" &gt;
+        &lt;arg file="@{file} /&gt;
+      &lt;/java&gt;
+   &lt;/sequential&gt;
+&lt;/macrodef&gt;
+    
+&lt;parallel threadCount='4'&gt;
+  &lt;dbpurge file="db/one" /&gt;
+  &lt;dbpurge file="db/two" /&gt;
+  &lt;dbpurge file="db/three" /&gt;
+  &lt;dbpurge file="db/four" /&gt;
+  &lt;dbpurge file="db/five" /&gt;
+  &lt;dbpurge file="db/six" /&gt;
+  &lt;dbpurge file="db/seven" /&gt;
+  &lt;dbpurge file="db/eight" /&gt;
+  &lt;!-- repeated about 40 times --&gt;
+&lt;/parallel&gt;
+</pre>
+
+<p>This example represents a typical need for use of the threadCount and
+threadsPerProcessor attributes.  Spinning up all 40 of those tasks could cripple
+the system for memory and CPU time.  By limiting the number of
+concurrent executions you can reduce contention for CPU, memory and disk IO, 
+and so actually finish faster.  This is also a good
+candidiate for use of threadCount (and possibly threadsPerProcessor) because
+each task is independent (every new JVM is forked) and has no dependencies on
+the other tasks.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/patch.html b/trunk/docs/manual/CoreTasks/patch.html
new file mode 100644
index 0000000..a7beb2a
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/patch.html
@@ -0,0 +1,104 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Patch Task</title>
+</head>
+
+<body>
+
+<h2><a name="patch">Patch</a></h2>
+<h3>Description</h3>
+<p>Applies a diff file to originals. ; requires "patch" to be
+ on the execution path.  </p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">patchfile</td> 
+    <td valign="top">the file that includes the diff output</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">originalfile</td> 
+    <td valign="top">the file to patch</td>
+    <td align="center" valign="top">No, tries to guess it from the diff 
+      file</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td> 
+    <td valign="top">the file to send the output to instead of
+      patching the file(s) in place.  <em>since Ant 1.6</em></td>
+    <td align="center" valign="top">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">backups</td> 
+    <td valign="top">Keep backups of the unpatched files</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td> 
+    <td valign="top">Work silently unless an error occurs</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">reverse</td> 
+    <td valign="top">Assume patch was created with old and new files 
+      swapped.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">ignorewhitespace</td> 
+    <td valign="top">Ignore whitespace differences.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strip</td> 
+    <td valign="top">Strip the smallest prefix containing <i>num</i> leading 
+      slashes from filenames.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td> 
+    <td valign="top">The directory in which to run the patch command.</td>
+    <td align="center" valign="top">No, default is the project's basedir.</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;patch patchfile=&quot;module.1.0-1.1.patch&quot;/&gt;</pre>
+<p>applies the diff included in <i>module.1.0-1.1.patch</i> to the
+files in base directory guessing the filename(s) from the diff output.</p>
+<pre>  &lt;patch patchfile=&quot;module.1.0-1.1.patch&quot; strip=&quot;1&quot;/&gt;</pre>
+<p>like above but one leading directory part will be removed. i.e. if
+the diff output looked like</p>
+<pre>
+--- a/mod1.0/A	Mon Jun  5 17:28:41 2000
++++ a/mod1.1/A	Mon Jun  5 17:28:49 2000
+</pre> 
+the leading <i>a/</i> will be stripped.
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/pathconvert.html b/trunk/docs/manual/CoreTasks/pathconvert.html
new file mode 100644
index 0000000..097963c
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/pathconvert.html
@@ -0,0 +1,218 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PathConvert Task</title>
+</head>
+
+<body>
+
+<h2><a name="pathconvert">Pathconvert</a></h2>
+<h3>Description</h3>
+<p>Converts nested <a href="../CoreTypes/resources.html#collection">
+ResourceCollection</a>s, or a reference to just one, into a path
+form for a particular platform, optionally storing the result into
+a given property. It can also be used when you need
+to convert a Resource Collection into a list, separated by a given
+character, such as a comma or space, or, conversely, e.g. to convert a list
+of files in a FileList into a path.
+</p>
+<p>Nested <code>&lt;map&gt;</code> elements can be specified to map Windows
+drive letters to Unix paths, and vice-versa.</p>
+<p>More complex transformations can be achieved using a nested
+<a href="../CoreTypes/mapper.html"><code>&lt;mapper&gt;</code></a>
+(since Ant 1.6.2).
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">targetos</td>
+    <td valign="top">
+        The target architecture.  Must be one of 'unix', 'windows', 
+        'netware', 'tandem' or 'os/2'.
+        This is a shorthand mechanism for specifying both
+        <code>pathsep</code> and <code>dirsep</code>
+        according to the specified target architecture.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dirsep</td>
+    <td valign="top">
+       The character(s) to use as the directory separator in the
+       generated paths.
+    </td>
+    <td valign="top" align="center">No, defaults to current JVM <tt>File.separator</tt></td>
+  </tr>
+  <tr>
+    <td valign="top">pathsep</td>
+    <td valign="top">
+       The character(s) to use as the path-element separator in the
+       generated paths.
+    </td>
+    <td valign="top" align="center">No, defaults to current JVM <tt>File.pathSeparator</tt></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property in which to place the converted path.</td>
+    <td valign="top" align="center">No, result will be logged if unset</td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">What to convert, given as a
+        <a href="../using.html#references">reference</a> to a
+        <code>&lt;path&gt;</code>, <code>&lt;fileset&gt;</code>,
+        <code>&lt;dirset&gt;</code>, or <code>&lt;filelist&gt;</code>
+        defined elsewhere</td>
+    <td valign="top" align="center">No; if omitted, a nested
+        <code>&lt;path&gt;</code> element must be supplied.</td>
+  </tr>
+    <td valign="top">setonempty</td>
+    <td valign="top">Should the property be set, even if the result
+      is the empty string?
+    <td valign="top" align="center">No; default is &quot;true&quot;.
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>map</h4>
+<p>Specifies the mapping of path prefixes between Unix and Windows.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">from</td>
+    <td valign="top">
+      The prefix to match.  Note that this value is case-insensitive when
+      the build is running on a Windows platform and case-sensitive 
+      when running on a Unix platform.
+      <em>Since Ant 1.7.0</em>, on Windows this value is also insensitive
+      to the slash style used for directories, one can use '/' or '\'.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">to</td>
+    <td valign="top">The replacement text to use when <code>from</code> is matched.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<p>Each map element specifies a single replacement map to be applied to the elements of
+   the path being processed.  If no map entries are specified, then no path prefix mapping
+   is performed.
+</p>
+<p><strong>Note</strong>: The map elements are applied in the order specified,
+and only the first matching map element is applied.  So, the ordering of
+your map elements can be important, if any <code>from</code> values are
+prefixes of other <code>from</code> values.</i>
+</p>   
+<h4>Resource Collections</h4>
+<p>If the <code>refid</code> attribute is not specified, then one or more
+   nested <a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s must be supplied.</p>
+<h4>mapper</h4>
+<p>A single nested <a href="../CoreTypes/mapper.html">
+<code>&lt;mapper&gt;</code></a> element can be specified
+to perform any of various filename transformations (since Ant 1.6.2).
+</p>
+
+<h3>Examples</h3>
+<p>In the examples below, assume that the <code>${wl.home}</code> property
+has the value
+<code>d:\weblogic</code>, and <code>${wl.home.unix}</code> has the value
+<code>/weblogic</code>.</p>
+<h4>Example 1</h4>
+<pre>
+    &lt;path id="wl.path"&gt;
+      &lt;pathelement location=&quot;${wl.home}/lib/weblogicaux.jar&quot;/&gt;
+      &lt;pathelement location=&quot;${wl.home}/classes&quot;/&gt;
+      &lt;pathelement location=&quot;${wl.home}/mssqlserver4/classes&quot;/&gt;
+      &lt;pathelement location=&quot;c:\winnt\System32&quot;/&gt;
+    &lt;/path&gt;
+    
+    &lt;pathconvert targetos=&quot;unix&quot; property=&quot;wl.path.unix&quot; refid=&quot;wl.path&quot;&gt;
+      &lt;map from=&quot;${wl.home}&quot; to=&quot;${wl.home.unix}&quot;/&gt;
+      &lt;map from=&quot;c:&quot; to=&quot;&quot;/&gt;
+    &lt;/pathconvert&gt;
+</pre>
+<p> will generate the path shown below
+and store it in the property named <code>wl.path.unix</code>.
+</p>   
+<pre>
+/weblogic/lib/weblogicaux.jar:/weblogic/classes:/weblogic/mssqlserver4/classes:/WINNT/SYSTEM32
+</pre>
+
+<h4>Example 2</h4>
+Given a FileList defined as:
+<pre>
+  &lt;filelist id=&quot;custom_tasks.jars&quot;
+        dir=&quot;${env.HOME}/ant/lib&quot;
+        files=&quot;njavac.jar,xproperty.jar&quot;/&gt;
+</pre>
+then:
+<pre>
+    &lt;pathconvert targetos=&quot;unix&quot; property=&quot;custom_tasks.jars&quot; refid=&quot;custom_tasks.jars&quot;&gt;
+      &lt;map from=&quot;${env.HOME}&quot; to=&quot;/usr/local&quot;/&gt;
+    &lt;/pathconvert&gt;
+</pre>
+will convert the list of files to the following Unix path:
+<pre>
+/usr/local/ant/lib/njavac.jar:/usr/local/ant/lib/xproperty.jar
+</pre>
+
+<h4>Example 3</h4>
+<pre>
+    &lt;fileset dir=&quot;${src.dir}&quot; id=&quot;src.files&quot;&gt;
+      &lt;include name=&quot;**/*.java&quot;/&gt;
+    &lt;/fileset&gt;
+  
+    &lt;pathconvert pathsep=&quot;,&quot; property=&quot;javafiles&quot; refid=&quot;src.files&quot;/&gt;
+</pre>
+<p>This example takes the set of files determined by the fileset (all files ending
+in <tt>.java</tt>), joins them together separated by commas, and places the resulting
+list into the property <tt>javafiles</tt>.  The directory separator is not specified, so
+it defaults to the appropriate character for the current platform.  Such a list could
+then be used in another task, like <tt>javadoc</tt>, that requires a comma separated
+list of files.
+</p>
+<h4>Example 4</h4>
+<pre>
+    &lt;pathconvert property="prop" dirsep="|"&gt;
+      &lt;map from="${basedir}/abc/" to=''/&gt;
+      &lt;path location="abc/def/ghi"/&gt;
+    &lt;/pathconvert&gt;
+</pre>
+  <p>
+    This example sets the property "prop" to "def|ghi" on
+    Windows and on Unix.
+  </p>
+</body>
+</html>
+
+ 
diff --git a/trunk/docs/manual/CoreTasks/presetdef.html b/trunk/docs/manual/CoreTasks/presetdef.html
new file mode 100644
index 0000000..eb6c594
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/presetdef.html
@@ -0,0 +1,184 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PreSetDef Task</title>
+    <style type="text/css">
+      <!--
+           .code { background: #EFEFEF; margin-top: }
+           -->
+    </style>
+  </head>
+  
+  <body>
+    
+    <h2><a name="presetdef">PreSetDef</a></h2>
+    <h3>Description</h3>
+    <p>
+      The preset definition generates a new definition
+      based on a current definition with some attributes
+      or elements preset.
+    </p>
+    <p>
+      <em>since Ant 1.6</em>
+    </p>
+    <p>
+      The resolution of properties in any of the attributes or
+      nested text takes place with the definition is used and <em>not</em>
+      when the preset definition is defined.
+    </p>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">the name of the new definition</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">uri</td>
+        <td valign="top">
+          The uri that this definition should live in.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+    <h3>Parameters specified as nested elements</h3>
+    <h4>another type with attributes or elements set</h4>
+    <p>The <code>&lt;presetdef&gt;</code> task takes one nested element as a parameter.
+      This nested element can be any other type or task. The attributes
+      and elements that need to be preset are placed here.
+    </p>
+    
+    <h3>Examples</h3>
+      The following fragment defines a javac task with the debug, deprecation
+      srcdir and destdir
+      attributes set. It also has a src element to source files from a generated
+      directory.
+    <blockquote>
+<pre class="code">
+&lt;presetdef name="my.javac"&gt;
+   &lt;javac debug="${debug}" deprecation="${deprecation}"
+          srcdir="${src.dir}" destdir="${classes.dir}"&gt;
+      &lt;src path="${gen.dir}"/&gt;
+   &lt;/javac&gt;
+&lt;/presetdef&gt;
+</pre>
+    </blockquote>
+      This can be used as a normal javac task - example:
+    <blockquote>
+<pre class="code">
+&lt;my.javac/&gt;
+</pre>
+    </blockquote>
+      The attributes specified in the preset task may be overridden - i.e.
+      they may be seen as optional attributes - example:
+    <blockquote>
+<pre class="code">
+&lt;my.javac srcdir="${test.src}" deprecation="no"/&gt;
+</pre>
+    </blockquote>
+      One may put a presetdef definition in an antlib.
+      For example suppose the jar file antgoodies.jar has
+      the antlib.xml as follows:
+    <blockquote>
+<pre class="code">
+&lt;antlib&gt;
+   &lt;taskdef resource="com/acme/antgoodies/tasks.properties"/&gt;
+   &lt;!-- Implement the common use of the javac command --&gt;
+   &lt;presetdef name="javac"&gt;
+      &lt;javac deprecation="${deprecation}" debug="${debug}"
+             srcdir="src" destdir="classes"/&gt;
+   &lt;/presetdef&gt;
+&lt;/antlib&gt;
+</pre>
+    </blockquote>
+      One may then use this in a build file as follows:
+    <blockquote>
+<pre class="code">
+&lt;project default="example" xmlns:antgoodies="antlib:com.acme.antgoodies"&gt;
+   &lt;target name="example"&gt;
+      &lt;!-- Compile source --&gt;
+      &lt;antgoodies:javac srcdir="src/main"/&gt;
+      &lt;!-- Compile test code --&gt;
+      &lt;antgoodies:javac srcdir="src/test"/&gt;
+   &lt;/target&gt;
+&lt;/project&gt;
+</pre>
+    </blockquote>
+    <p>
+      The following is an example of evaluation of properties when the
+      definition is used:
+    </p>
+     <blockquote>
+<pre class="code">
+&lt;target name="defineandcall"&gt;
+   &lt;presetdef name="showmessage"&gt;
+      &lt;echo&gt;message is '${message}'&lt;/echo&gt;
+   &lt;/presetdef&gt;
+   &lt;showmessage/&gt;
+   &lt;property name="message" value="Message 1"/&gt;
+   &lt;showmessage/&gt;
+   &lt;antcall target="called"&gt;
+      &lt;param name="message" value="Message 2"/&gt;
+   &lt;/antcall&gt;
+&lt;/target&gt;
+&lt;target name="called"&gt;
+   &lt;showmessage/&gt;
+&lt;/target&gt;
+</pre>
+     </blockquote>
+     <p>
+        The command ant defineandcall results in the output:
+     </p>
+     <blockquote>
+<pre class="code">
+defineandcall:
+[showmessage] message is '${message}'
+[showmessage] message is 'Message 1'
+
+called:
+[showmessage] message is 'Message 2'
+</pre>
+     </blockquote>
+<p>
+It is possible to use a trick to evaluate properties when the definition is
+<em>made</em> rather than used. This can be useful if you do not expect some
+properties to be available in child builds run with
+<code>&lt;ant ... inheritall="false"&gt;</code>:
+</p>
+<blockquote><pre class="code">
+&lt;macrodef name="showmessage-presetdef"&gt;
+  &lt;attribute name="messageval"/&gt;
+  &lt;presetdef name="showmessage"&gt;
+    &lt;echo&gt;message is '@{messageval}'&lt;/echo&gt;
+  &lt;/presetdef&gt;
+&lt;/macrodef&gt;
+&lt;showmessage-presetdef messageval="${message}"/&gt;
+</pre></blockquote>
+    <hr></hr>
+    
+  </body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/property.html b/trunk/docs/manual/CoreTasks/property.html
new file mode 100644
index 0000000..c7b25d2
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/property.html
@@ -0,0 +1,272 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Property Task</title>
+</head>
+
+<body>
+
+<h2><a name="property">Property</a></h2>
+<h3>Description</h3>
+<p>Sets a <a href="../using.html#properties">property</a>
+(by name and value), or set of properties (from file or
+resource) in the project.  Properties are case sensitive.</p>
+ Properties are immutable: whoever sets a property first freezes it for the
+ rest of the build; they are most definitely not variables.
+<p>There are six ways to set properties:</p>
+<ul>
+  <li>By supplying both the <i>name</i> and <i>value</i> attribute.</li>
+  <li>By supplying both the <i>name</i> and <i>refid</i> attribute.</li>
+  <li>By setting the <i>file</i> attribute with the filename of the property
+    file to load. This property file has the format as defined by the file used
+    in the class java.util.Properties, with the same rules about how
+    non-ISO8859-1 characters must be escaped.</li>
+  <li>By setting the <i>url</i> attribute with the url from which to load the
+    properties. This url must be directed to a file that has the format as defined
+    by the file used in the class java.util.Properties.</li>
+  <li>By setting the <i>resource</i> attribute with the resource name of the
+    property file to load. A resource is a property file on the current
+    classpath, or on the specified classpath.</li>
+  <li>By setting the <i>environment</i> attribute with a prefix to use.
+    Properties will be defined for every environment variable by
+    prefixing the supplied name and a period to the name of the variable.</li>
+</ul>
+<p>Although combinations of these ways are possible, only one should be used
+at a time. Problems might occur with the order in which properties are set, for
+instance.</p>
+<p>The value part of the properties being set, might contain references to other
+properties. These references are resolved at the time these properties are set.
+This also holds for properties loaded from a property file.</p>
+<p>A list of predefined properties can be found <a
+href="../using.html#built-in-props">here</a>.</p>
+<p>Since Ant 1.7.1 it is possible to load properties defined in xml
+according to <a href="http://java.sun.com/dtd/properties.dtd">Suns DTD</a>,
+if Java5+ is present. For this the name of the file, resource or url has 
+to end with <tt>.xml</tt>.</p>
+
+<h4>OpenVMS Users</h4>
+<p>With the <code>environment</code> attribute this task will load all defined
+logicals on an OpenVMS system.  Logicals with multiple equivalence names get
+mapped to a property whose value is a comma separated list of all equivalence
+names.  If a logical is defined in multiple tables, only the most local
+definition is available (the table priority order being PROCESS, JOB, GROUP,
+SYSTEM).
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the property to set.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the value of the property.</td>
+    <td valign="middle" align="center" rowspan="3">One of these, when using the
+       name attribute</td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">Sets the property to the absolute filename of the
+      given file. If the value of this attribute is an absolute path, it
+      is left unchanged (with / and \ characters converted to the
+      current platforms conventions). Otherwise it is taken as a path
+      relative to the project's basedir and expanded.</td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top"><a href="../using.html#references">Reference</a> to an object
+      defined elsewhere. Only yields reasonable results for references
+      to <a href="../using.html#path">PATH like structures</a> or properties.</td>
+  </tr>
+  <tr>
+    <td valign="top">resource</td>
+    <td valign="top"> the name of the classpath resource containing
+      properties settings in properties file format.</td>
+    <td valign="middle" align="center" rowspan="4">One of these, when
+      <b>not</b> using the name attribute</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the location of the properties file to load.</td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">a url containing properties-format settings.</td>
+  </tr>
+  <tr>
+    <td valign="top">environment</td>
+    <td valign="top">the prefix to use when retrieving environment variables. Thus
+    if you specify environment=&quot;myenv&quot; you will be able to access OS-specific
+    environment variables via property names &quot;myenv.PATH&quot; or
+    &quot;myenv.TERM&quot;. Note that if you supply a property name with a final
+    &quot;.&quot; it will not be doubled; i.e. environment=&quot;myenv.&quot; will still
+    allow access of environment variables through &quot;myenv.PATH&quot; and
+    &quot;myenv.TERM&quot;. This functionality is currently only implemented
+    on <a href="#notes-env">select platforms</a>. Feel free to send patches to increase the
+    number of platforms on which this functionality is supported ;).<br>
+    Note also that properties are case-sensitive, even if the
+    environment variables on your operating system are not; e.g. Windows 2000's
+    system path variable is set to an Ant property named "env.Path"
+    rather than "env.PATH".</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use when looking up a resource.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use when looking up a resource,
+      given as <a href="../using.html#references">reference</a> to a <code>&lt;path&gt;</code> defined
+      elsewhere..</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">prefix</td>
+    <td valign="top">Prefix to apply to properties loaded using <code>file</code>,
+    <code>resource</code>, or <code>url</code>.
+      A "." is appended to the prefix if not specified.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>classpath</h4>
+<p><code>Property</code>'s <i>classpath</i> attribute is a <a
+href="../using.html#path">PATH like structure</a> and can also be set via a nested
+<i>classpath</i> element.</p>
+<h3>Examples</h3>
+<pre>  &lt;property name=&quot;foo.dist&quot; value=&quot;dist&quot;/&gt;</pre>
+<p>sets the property <code>foo.dist</code> to the value &quot;dist&quot;.</p>
+<pre>  &lt;property file=&quot;foo.properties&quot;/&gt;</pre>
+<p>reads a set of properties from a file called &quot;foo.properties&quot;.</p>
+<pre>  &lt;property url=&quot;http://www.mysite.com/bla/props/foo.properties&quot;/&gt;</pre>
+<p>reads a set of properties from the address &quot;http://www.mysite.com/bla/props/foo.properties&quot;.</p>
+<pre>  &lt;property resource=&quot;foo.properties&quot;/&gt;</pre>
+<p>reads a set of properties from a resource called &quot;foo.properties&quot;.</p>
+<p>Note that you can reference a global properties file for all of your Ant
+builds using the following:</p>
+<pre>  &lt;property file=&quot;${user.home}/.ant-global.properties&quot;/&gt;</pre>
+<p>since the &quot;user.home&quot; property is defined by the Java virtual machine
+to be your home directory.  Where the &quot;user.home&quot; property resolves to in
+the file system depends on the operating system version and the JVM implementation.
+On Unix based systems, this will map to the user's home directory. On modern Windows
+variants, this will most likely resolve to the user's directory in the &quot;Documents
+and Settings&quot; folder. Older windows variants such as Windows 98/ME are less
+predictable, as are other operating system/JVM combinations.</p>
+
+<pre>
+  &lt;property environment=&quot;env&quot;/&gt;
+  &lt;echo message=&quot;Number of Processors = ${env.NUMBER_OF_PROCESSORS}&quot;/&gt;
+  &lt;echo message=&quot;ANT_HOME is set to = ${env.ANT_HOME}&quot;/&gt;
+</pre>
+<p>reads the system environment variables and stores them in properties, prefixed with &quot;env&quot;.
+Note that this only works on <em>select</em> operating systems.
+Two of the values are shown being echoed.
+</p>
+
+<h3>Property Files</h3>
+
+As stated, this task will load in a properties file stored in the file
+system, or as a resource on a classpath. Here are some interesting facts
+about this feature
+<ol>
+<li>If the file is not there, nothing is printed except at -verbose log
+level. This lets you have optional configuration files for every
+project, that team members can customize.
+<li>The rules for this format are laid down
+<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream)">by Sun</a>.
+This makes it hard for Team Ant to field bug reports about it.
+<li>Trailing spaces are not stripped. It may have been what you wanted.
+<li>Want unusual characters? Escape them \u0456 or \" style.
+<li>Ant Properties are expanded in the file.
+</ol>
+In-file property expansion is very cool. Learn to use it.
+<p>
+Example:
+<pre>
+build.compiler=jikes
+deploy.server=lucky
+deploy.port=8080
+deploy.url=http://${deploy.server}:${deploy.port}/
+</pre>
+
+
+<a name="notes-env"></a>
+<h3>Notes about environment variables</h3>
+<p>
+  Ant runs on Java 1.2 therefore it cant use Java5 features for accessing environment
+  variables. So it starts a command in a new process which prints the environment variables,
+  analyzes the output and creates the properties. <br>
+  There are commands for the following operating systems implemented in
+  <a href="http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/Execute.java?view=markup">
+  Execute.java</a> (method <tt>getProcEnvCommand()</tt>):
+  <table>
+    <tr>
+      <th>OS</th>
+      <th>command</th>
+    </tr>
+    <tr>
+      <td> os/2 </td>
+      <td> cmd /c set </td>
+    </tr>
+    <tr>
+      <td colspan="2"> windows </td>
+    </tr>
+    <tr>
+      <td> * win9x </td>
+      <td> command.com /c set </td>
+    </tr>
+    <tr>
+      <td> * other </td>
+      <td> cmd /c set </td>
+    </tr>
+    <tr>
+      <td> z/os </td>
+      <td> /bin/env <b>OR</b> /usr/bin/env <b>OR</b> env   <i>(depending on read rights)</i> </td>
+    </tr>
+    <tr>
+      <td> unix </td>
+      <td> /bin/env <b>OR</b> /usr/bin/env <b>OR</b> env   <i>(depending on read rights)</i> </td>
+    </tr>
+    <tr>
+      <td> netware </td>
+      <td> env </td>
+    </tr>
+    <tr>
+      <td> os/400 </td>
+      <td> env </td>
+    </tr>
+    <tr>
+      <td> openvms </td>
+      <td> show logical </td>
+    </tr>
+  </table>
+</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/recorder.html b/trunk/docs/manual/CoreTasks/recorder.html
new file mode 100644
index 0000000..62bede0
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/recorder.html
@@ -0,0 +1,172 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Recorder Task</title>
+</head>
+
+<body>
+
+<h2><a name="log">Record</a></h2>
+<h3>Description</h3>
+<p>A recorder is a listener to the current build process that records the
+output to a file.</p>
+
+<p>Several recorders can exist at the same time.  Each recorder is
+associated with a file.  The filename is used as a unique identifier for
+the recorders.  The first call to the recorder task with an unused filename
+will create a recorder (using the parameters provided) and add it to the
+listeners of the build.  All subsequent calls to the recorder task using
+this filename will modify that recorders state (recording or not) or other
+properties (like logging level).</p>
+
+<p>Some technical issues: the file's print stream is flushed for &quot;finished&quot;
+events (buildFinished, targetFinished and taskFinished), and is closed on
+a buildFinished event.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the file this logger is associated with.</td>
+    <td align="center" valign="middle">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">action</td>
+    <td valign="top">This tells the logger what to do: should it start
+    recording or stop?  The first time that the recorder task is called for
+    this logfile, and if this attribute is not provided, then the default
+    for this attribute is &quot;start&quot;.  If this attribute is not provided on
+    subsequent calls, then the state remains as previous.
+    [Values = {start|stop}, Default = no state change]</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Should the recorder append to a file, or create a new
+    one? This is only applicable the first time this task is called for
+    this file.  [Values = {yes|no}, Default=no]</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">emacsmode</td>
+    <td valign="top">Removes <code>[task]</code> banners like Ant's
+    <code>-emacs</code> command line switch if set to
+    <em>true</em>.</td>
+    <td align="center" valign="middle">no, default is <em>false</em></td>
+  </tr>
+  <tr>
+    <td valign="top">loglevel</td>
+    <td valign="top">At what logging level should this recorder instance
+    record to?  This is not a once only parameter (like <code>append</code>
+    is) -- you can increase or decrease the logging level as the build process
+    continues.  [Values= {error|warn|info|verbose|debug}, Default = no change]
+    </td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<p>The following build.xml snippet is an example of how to use the recorder
+to record just the <code>&lt;javac&gt;</code> task:</p>
+<pre>
+    ...
+    &lt;compile &gt;
+        &lt;record name=&quot;log.txt&quot; action=&quot;start&quot;/&gt;
+        &lt;javac ...
+        &lt;record name=&quot;log.txt&quot; action=&quot;stop&quot;/&gt;
+    &lt;compile/&gt;
+    ...
+</pre>
+
+<p>The following two calls to <code>&lt;record&gt;</code> set up two
+recorders: one to file &quot;records-simple.log&quot; at logging level <code>info</code>
+(the default) and one to file &quot;ISO.log&quot; using logging level of
+<code>verbose</code>.</p>
+<pre>
+    ...
+    &lt;record name=&quot;records-simple.log&quot;/&gt;
+    &lt;record name=&quot;ISO.log&quot; loglevel=&quot;verbose&quot;/&gt;
+    ...
+</pre>
+
+<h3>Notes</h3>
+<p>There is some functionality that I would like to be able to add in the
+future.  They include things like the following:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">listener</td>
+    <td valign="top">A classname of a build listener to use from this point
+    on instead of the default listener.</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">includetarget</td>
+    <td valign="top" rowspan=2>A comma-separated list of targets to automatically
+    record.  If this value is &quot;all&quot;, then all targets are recorded.
+    [Default = all]</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludetarget</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">includetask</td>
+    <td valign="top" rowspan=2>A comma-separated list of task to automatically
+    record or not.  This could be difficult as it could conflict with the
+    <code>includetarget/excludetarget</code>.  (e.g.:
+    <code>includetarget=&quot;compile&quot; exlcudetask=&quot;javac&quot;</code>, what should
+    happen?)</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludetask</td>
+    <td align="center" valign="middle">no</td>
+  </tr>
+  <tr>
+    <td valign="top">action</td>
+    <td valign="top">add greater flexibility to the action attribute.  Things
+    like <code>close</code> to close the print stream.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top"></td>
+    <td valign="top"></td>
+    <td align="center" valign="top"></td>
+  </tr>
+</table>
+
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/rename.html b/trunk/docs/manual/CoreTasks/rename.html
new file mode 100644
index 0000000..330fbe3
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/rename.html
@@ -0,0 +1,64 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Rename Task</title>
+</head>
+
+<body>
+
+<h2><a name="rename">Rename</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the Move task instead.</i></p>
+<h3>Description</h3>
+<p>Renames a given file.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">file to rename.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">new name of the file.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">replace</td>
+    <td valign="top">Enable replacing of existing file (default: on).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;rename src=&quot;foo.jar&quot; dest=&quot;${name}-${version}.jar&quot;/&gt;</pre> 
+<p>Renames the file <code>foo.jar</code> to <code>${name}-${version}.jar</code> (assuming <code>name</code>
+ and <code>version</code> being predefined properties). If a file named <code>${name}-${version}.jar</code>
+ already exists, it will be removed prior to renaming <code>foo.jar</code>.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/replace.html b/trunk/docs/manual/CoreTasks/replace.html
new file mode 100644
index 0000000..bd0823e
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/replace.html
@@ -0,0 +1,205 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Replace Task</title>
+</head>
+
+<body>
+
+<h2><a name="replace">Replace</a></h2>
+<h3>Description</h3>
+<p>Replace is a directory based task for replacing the occurrence of a given string with another string 
+in selected file.</p>
+<p>If you want to replace a text that crosses line boundaries, you
+must use a nested <code>&lt;replacetoken&gt;</code> element.</p>
+
+<p>The output file is only written if it differs from the existing
+file.  This prevents spurious rebuilds based on unchanged files which
+have been regenerated by this task.</p> 
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">file for which the token should be replaced.</td>
+    <td align="center" rowspan="2">Exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The base directory to use when replacing a token in 
+      multiple files.</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding of the files upon which replace operates.</td>
+    <td align="center">No - defaults to default JVM encoding</td>
+  </tr>
+  <tr>
+    <td valign="top">token</td>
+    <td valign="top">the token which must be replaced.</td>
+    <td valign="top" align="center">Yes, unless a nested
+    <code>replacetoken</code> element or the replacefilterfile
+    attribute is used.</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the new value for the token. When omitted, an empty string
+      (&quot;&quot;) is used.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">summary</td>
+    <td valign="top">Indicates whether a summary of the replace operation 
+                     should be produced, detailing how many token occurrences 
+                     and files were processed
+                     </td>
+    <td valign="top" align="center">No, by default no summary is produced</td>
+  </tr>
+  <tr>
+    <td valign="top">propertyFile</td>
+    <td valign="top">valid property file from which properties specified using nested <code>&lt;replacefilter&gt;</code> elements are drawn.</td>
+    <td valign="top" align="center">Yes only if <i>property</i> attribute of <code>&lt;replacefilter&gt;</code> is used.</td>
+  </tr>
+  <tr>
+    <td valign="top">replacefilterfile</td>
+    <td valign="top">valid property file.  Each property will be
+    treated as a replacefilter where <code>token</code> is the name of
+    the property and <code>value</code> is the properties value.
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>  &lt;replace file=&quot;${src}/index.html&quot; token=&quot;@@@&quot; value=&quot;wombat&quot;/&gt;</pre>
+<p>replaces occurrences of the string &quot;@@@&quot; with the string
+&quot;wombat&quot;, in the file <code>${src}/index.html</code>.</p>
+<h3>Parameters specified as nested elements</h3>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code> as well as the
+nested <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<p>If either the text you want to replace or the replacement text
+cross line boundaries, you can use nested elements to specify
+them.</p>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;replace dir=&quot;${src}&quot; value=&quot;wombat&quot;&gt;
+  &lt;include name=&quot;**/*.html&quot;/&gt;
+  &lt;replacetoken&gt;&lt;![CDATA[multi line
+token]]&gt;&lt;/replacetoken&gt;
+&lt;/replace&gt;
+</pre></blockquote>
+<p>replaces occurrences of the string &quot;multi
+line<i>\n</i>token&quot; with the string &quot;wombat&quot;, in all
+HTML files in the directory <code>${src}</code>.Where <i>\n</i> is
+the platform specific line separator.</p>
+<blockquote><pre>
+&lt;replace file=&quot;${src}/index.html&quot;&gt;
+  &lt;replacetoken&gt;&lt;![CDATA[two line
+token]]&gt;&lt;/replacetoken&gt;
+  &lt;replacevalue&gt;&lt;![CDATA[two line
+token]]&gt;&lt;/replacevalue&gt;
+&lt;/replace&gt;
+</pre></blockquote>
+<h4>replacefilter</h4>
+<p>In addition to allowing for multiple replacements, optional nested <code>&lt;replacefilter&gt;</code> elements allow replacement values to be extracted from a property file. The name of this file is specified using the <code>&lt;replace&gt;</code> attribute <i>propertyFile</i>.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">token</td>
+    <td valign="top">The string to search for.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The replacement string.</td>
+    <td align="center" rowspan="2">Either may be specified, but not both. Both can be omitted, if desired.</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">Name of the property whose value is to serve as the replacement value.</td>
+  </tr>
+</table>
+<p>If neither <i>value</i> nor <i>property</i> is used, the value provided using the <code>&lt;replace&gt;</code> attribute <i>value</i> and/or the <code>&lt;replacevalue&gt;</code> element is used. If no value was specified using either of these options, the token is replaced with an empty string.
+</p>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;replace 
+    file=&quot;configure.sh&quot;
+    value=&quot;defaultvalue&quot;
+    propertyFile=&quot;source/name.properties&quot;&gt;
+  &lt;replacefilter 
+    token=&quot;@token1@&quot;/&gt;
+  &lt;replacefilter 
+    token=&quot;@token2@&quot; 
+    value=&quot;value2&quot;/&gt;
+  &lt;replacefilter 
+    token=&quot;@token3@&quot; 
+    property=&quot;property.key&quot;/&gt;
+&lt;/replace&gt;
+</pre></blockquote>
+<p>In file <code>configure.sh</code>, replace all instances of &quot;@token1@&quot; with &quot;defaultvalue&quot;, all instances of &quot;@token2@&quot; with &quot;value2&quot;, and all instances of &quot;@token3@&quot; with the value of the property &quot;property.key&quot;, as it appears in property file <code>src/name.properties</code>.</p>
+<p><b>Note:</b> It is possible to use either the <i>token</i>/<code>&lt;replacetoken&gt;</code> and <i>value</i>/<code>&lt;replacevalue&gt;</code> attributes/elements, the nested replacefilter elements, or both in the same operation.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/resourcecount.html b/trunk/docs/manual/CoreTasks/resourcecount.html
new file mode 100755
index 0000000..30fb578
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/resourcecount.html
@@ -0,0 +1,82 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ResourceCount Task</title>
+</head>
+
+<body>
+
+<h2>ResourceCount</h2>
+<h3>Description</h3>
+<p>Display or set a property containing the size of a nested
+   <a href="../CoreTypes/resources.html#collection">Resource Collection</a>.
+   Can also be used as a condition. <b>Since Ant 1.7</b></p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The property to set. If omitted the results are written
+      to the log. Ignored when processing as a condition.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">A <a href="../using.html#references">reference</a>
+      to a Resource Collection.</td>
+    <td valign="top" align="center">
+      Yes, unless a nested Resource Collection is supplied
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">count</td>
+    <td valign="top">Comparison count for processing as a condition.</td>
+    <td valign="top" align="center">Yes, in condition mode</td>
+  </tr>
+  <tr>
+    <td valign="top">when</td>
+    <td valign="top">Comparison type: "equal", "eq", "greater", "gt", "less",
+      "lt", "ge" (greater or equal), "ne" (not equal), "le" (less or equal)
+      for use when operating as a condition.</td>
+    <td valign="top" align="center">No; default is "equal"</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>Resource Collection</h4>
+<p>A single
+  <a href="../CoreTypes/resources.html#collection">Resource Collection</a>
+should be specified via a nested element or the <code>refid</code> attribute.
+</p>
+<h3>Examples</h3>
+<pre>&lt;resourcecount property=&quot;count.foo&quot;&gt;
+  &lt;filelist dir=&quot;.&quot; files=&quot;foo,bar&quot; /&gt;
+&lt;/resourcecount&gt;
+</pre>
+<p>Stores the number of resources in the specified filelist (two)
+in the property named <i>count.foo</i>.</p>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/retry.html b/trunk/docs/manual/CoreTasks/retry.html
new file mode 100644
index 0000000..994829f
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/retry.html
@@ -0,0 +1,55 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Retry Task</title>
+</head>
+<body>
+<h2>Retry</h2>
+<h3>Description</h3>
+<p>Retry is a container which executes a single nested task until either: there is no failure; or:
+its <em>retrycount</em> has been exceeded. If this happens a BuildException is thrown.
+<em>Since Ant 1.7.1</em></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr> 
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr> 
+    <td valign="top">retrycount</td>
+    <td valign="top">number of times to attempt to execute the nested task</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<p>Any valid Ant task may be embedded within the retry task.</p>
+
+<h3>Example</h3>
+<pre>
+&lt;retry retrycount="3"&gt;
+  &lt;get src="http://www.unreliable-server.com/unreliable.tar.gz" 
+       dest="/home/retry/unreliable.tar.gz" /&gt;
+&lt;/retry&gt;
+</pre>
+<p>This example shows how to use <code>&lt;retry&gt;</code> to wrap a task which must interact with an unreliable network resource.</p>
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/rmic.html b/trunk/docs/manual/CoreTasks/rmic.html
new file mode 100644
index 0000000..3bbda35
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/rmic.html
@@ -0,0 +1,272 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Rmic Task</title>
+</head>
+
+<body>
+
+<h2><a name="rmic">Rmic</a></h2>
+<h3>Description</h3>
+<p>Runs the rmic compiler for a certain class.</p>
+<p>Rmic can be run on a single class (as specified with the classname
+attribute) or a number of classes at once (all classes below base that
+are neither _Stub nor _Skel classes).  If you want to rmic a single
+class and this class is a class nested into another class, you have to
+specify the classname in the form <code>Outer$$Inner</code> instead of
+<code>Outer.Inner</code>.</p>
+<p>It is possible to refine the set of files that are being rmiced. This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>base</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<p>It is possible to use different compilers. This can be selected
+with the &quot;build.rmic&quot; property or the <code>compiler</code>
+attribute.
+<a name="compilervalues">Here are the choices</a>:</p>
+<ul>
+  <li>default -the default compiler (kaffe or sun) for the platform.
+  <li>sun (the standard compiler of the JDK)</li>
+  <li>kaffe (the standard compiler of <a href="http://www.kaffe.org" target="_top">Kaffe</a>)</li>
+  <li>weblogic</li>
+  <li>forking - the sun compiler forked into a separate process (since Ant 1.7)</li>
+  <li>xnew - the sun compiler forked into a separate process,
+      with the -Xnew option (since Ant 1.7).
+      This is the most reliable way to use -Xnew</li>
+    <li> "" (empty string). This has the same behaviour as not setting the compiler attribute.
+    First the value of <tt>build.rmic</tt> is used if defined, and if not, the default
+    for the platform is chosen. If build.rmic is set to this, you get the default.
+
+</ul>
+
+<p>The <a href="http://dione.zcu.cz/~toman40/miniRMI/">miniRMI</a>
+project contains a compiler implementation for this task as well,
+please consult miniRMI's documentation to learn how to use it.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">base</td>
+    <td valign="top">the location to store the compiled files.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the class for which to run <code>rmic</code>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filtering</td>
+    <td valign="top">indicates whether token filtering should take place</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sourcebase</td>
+    <td valign="top">Pass the &quot;-keepgenerated&quot; flag to rmic and
+ move the generated source file to the given sourcebase directory.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">stubversion</td>
+    <td valign="top">Specify the JDK version for the generated stub code.
+ Specify &quot;1.1&quot; to pass the &quot;-v1.1&quot; option to rmic,
+ "1.2" for -v12, compat for -vcompat. <br>
+        Since Ant1.7, if you do not specify a version, and do not ask
+        for iiop or idl files, "compat" is selected.
+ 
+ </td>
+    <td align="center" valign="top">No, default="compat"</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use during compilation</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use during compilation, given as <a
+      href="../using.html#references">reference</a> to a PATH defined elsewhere</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verify</td>
+    <td valign="top">check that classes implement Remote before handing them 
+        to rmic (default is false)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">iiop</td>
+    <td valign="top">indicates that portable (RMI/IIOP) stubs should be generated</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">iiopopts</td>
+    <td valign="top">additional arguments for IIOP class generation</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">idl</td>
+    <td valign="top">indicates that IDL output files should be generated</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">idlopts</td>
+    <td valign="top">additional arguments for IDL file generation</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debug</td>
+    <td valign="top">generate debug info (passes -g to rmic). Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeAntRuntime</td> 
+    <td valign="top">whether to include the Ant run-time libraries;
+      defaults to <code>yes</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includeJavaRuntime</td> 
+    <td valign="top">whether to include the default run-time
+      libraries from the executing VM; defaults to <code>no</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">extdirs</td>
+    <td valign="top">location of installed extensions.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td valign="top">The compiler implementation to use.
+      If this attribute is not set, the value of the
+      <code>build.rmic</code> property, if set, will be used.
+      Otherwise, the default compiler for the current VM will be used.
+      (See the above <a href="#compilervalues">list</a> of valid
+      compilers.)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>classpath and extdirs</h4>
+<p><code>Rmic</code>'s <i>classpath</i> and <i>extdirs</i> attributes are <a
+href="../using.html#path">PATH like structure</a> and can also be set via a nested
+<i>classpath</i> and <i>extdirs</i> elements.</p>
+
+<h4>compilerarg</h4>
+
+<p>You can specify additional command line arguments for the compiler
+with nested <code>&lt;compilerarg&gt;</code> elements.  These elements
+are specified like <a href="../using.html#arg">Command-line
+Arguments</a> but have an additional attribute that can be used to
+enable arguments only if a given compiler implementation will be
+used.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">value</td>
+    <td align="center" rowspan="4">See
+    <a href="../using.html#arg">Command-line Arguments</a>.</td>
+    <td align="center" rowspan="4">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">line</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td>Only pass the specified argument if the chosen
+      compiler implementation matches the value of this attribute.
+      Legal values are the
+      same as those in the above <a href="#compilervalues">list</a> of valid
+      compilers.)</td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;rmic classname=&quot;com.xyz.FooBar&quot; base=&quot;${build}/classes&quot;/&gt;</pre>
+<p>runs the rmic compiler for the class <code>com.xyz.FooBar</code>. The
+compiled files will be stored in the directory <code>${build}/classes</code>.</p>
+<pre>  &lt;rmic base=&quot;${build}/classes&quot; includes=&quot;**/Remote*.class&quot;/&gt;</pre>
+<p>runs the rmic compiler for all classes with <code>.class</code>
+files below <code>${build}/classes</code> whose classname starts with
+<i>Remote</i>. The compiled files will be stored in the directory
+<code>${build}/classes</code>.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/sequential.html b/trunk/docs/manual/CoreTasks/sequential.html
new file mode 100644
index 0000000..5a653fe
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/sequential.html
@@ -0,0 +1,55 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Sequential Task</title>
+</head>
+
+<body>
+
+<h2>Sequential</h2>
+<h3>Description</h3>
+<p>Sequential is a container task - it can contain other Ant tasks. The nested 
+tasks are simply executed in sequence. Sequential's primary use is to support 
+the sequential execution of a subset of tasks within the 
+<a href="parallel.html">parallel</a> task</p>
+
+<p>The sequential task has no attributes and does not support any nested 
+elements apart from Ant tasks. Any valid Ant task may be embedded within the 
+sequential task.</p>
+
+<h3>Example</h3>
+<pre>
+&lt;parallel&gt;
+  &lt;wlrun ... &gt;
+  &lt;sequential&gt;
+    &lt;sleep seconds=&quot;30&quot;/&gt;
+    &lt;junit ... &gt;
+    &lt;wlstop/&gt;
+  &lt;/sequential&gt;
+&lt;/parallel&gt;
+</pre>
+<p>This example shows how the sequential task is used to execute three tasks in
+sequence, while another task is being executed in a separate thread. </p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/signjar.html b/trunk/docs/manual/CoreTasks/signjar.html
new file mode 100644
index 0000000..4a09d6d
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/signjar.html
@@ -0,0 +1,235 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SignJar Task</title>
+</head>
+
+<body>
+
+<h2><a name="signjar">SignJar</a></h2>
+<h3>Description</h3>
+<p>Signs JAR files with the <tt>jarsigner</tt> command line tool. 
+It will take a named file in the <tt>jar</tt> attribute, and an optional
+<tt>destDir</tt> or <tt>signedJar</tt> attribute. Nested paths are also
+supported; here only an (optional) <tt>destDir</tt> is allowed. If a destination
+directory or explicit JAR file name is not provided, JARs are signed in place.
+</p>
+<p>
+Dependency rules
+</p>
+<ul>
+<li>Nonexistent destination JARs are created/signed</li>
+<li>Out of date destination JARs are created/signed</li>
+<li>If a destination file and a source file are the same,
+and <tt>lazy</tt> is true, the JAR is only signed if it does not 
+contain a signature by this alias.</li>
+<li>If a destination file and a source file are the same,
+and <tt>lazy</tt> is false, the JAR is signed.</li> 
+</ul>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">jar</td>
+    <td valign="top">the jar file to sign</td>
+    <td valign="top" align="center">Yes, unless nested paths have
+      been used.</td>
+  </tr>
+  <tr>
+    <td valign="top">alias</td>
+    <td valign="top">the alias to sign under</td>
+    <td valign="top" align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">storepass</td>
+    <td valign="top">password for keystore integrity.</td>
+    <td valign="top" align="center">Yes.</td>
+  </tr>
+  <tr>
+    <td valign="top">keystore</td>
+    <td valign="top">keystore location</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">storetype</td>
+    <td valign="top">keystore type</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keypass</td>
+    <td valign="top">password for private key (if different)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sigfile</td>
+    <td valign="top">name of .SF/.DSA file</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">signedjar</td>
+    <td valign="top">name of signed JAR file. This can only be set when 
+    the <tt>jar</tt> attribute is set.</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">(true | false) verbose output when signing</td>
+    <td valign="top" align="center">No; default false</td>
+  </tr>
+  <tr>
+    <td valign="top">internalsf</td>
+    <td valign="top">(true | false) include the .SF file inside the signature
+block</td>
+    <td valign="top" align="center">No; default false</td>
+  </tr>
+  <tr>
+    <td valign="top">sectionsonly</td>
+    <td valign="top">(true | false) don't compute hash of entire manifest</td>
+    <td valign="top" align="center">No; default false</td>
+  </tr>
+  <tr>
+    <td valign="top">lazy</td>
+    <td valign="top">flag to control whether the presence of a signature
+  file means a JAR is signed. This is only used when the target JAR matches
+  the source JAR</td>
+    <td valign="top" align="center">No; default false</td>
+  </tr>
+  <tr>
+    <td valign="top">maxmemory</td>
+    <td valign="top">Specifies the maximum memory the jarsigner VM will use. Specified in the
+                     style of standard java memory specs (e.g. 128m = 128 MBytes)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">preservelastmodified</td>
+    <td valign="top">Give the signed files the same last modified
+      time as the original jar files.</td>
+    <td valign="top" align="center">No; default false.</td>
+  </tr>
+  <tr>
+    <td valign="top">tsaurl</td>
+    <td valign="top">URL for a timestamp authority for timestamped
+    JAR files in Java1.5+</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tsacert</td>
+    <td valign="top">alias in the keystore for a timestamp authority for 
+    timestamped JAR files in Java1.5+</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  
+</table>
+<h3>Parameters as nested elements</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+    <td valign="top">path of JAR files to sign. <em>since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fileset</td>
+    <td valign="top">fileset of JAR files to sign. </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mapper</td>
+    <td valign="top">A mapper to rename jar files during signing</td>
+    <td valign="top" align="center">No, and only one can be supplied</td>
+  </tr>
+  <tr>
+    <td valign="top">sysproperty</td>
+    <td valign="top">JVM system properties, with the syntax of Ant
+    <a href="exec.html#env">environment variables</a> </td>
+    <td valign="top" align="center">No, and only one can be supplied</td>
+  </tr>
+ </table>
+
+
+<h3>Examples</h3>
+  <blockquote><pre>
+&lt;signjar jar=&quot;${dist}/lib/ant.jar&quot;
+alias=&quot;apache-group&quot; storepass=&quot;secret&quot;/&gt;
+</pre></blockquote>
+<p>
+  signs the ant.jar with alias &quot;apache-group&quot; accessing the
+  keystore and private key via &quot;secret&quot; password.
+</p>
+  <blockquote><pre>
+&lt;signjar destDir="signed"
+    alias="testonly" keystore="testkeystore"
+    storepass="apacheant"
+    preservelastmodified="true"&gt;
+  &lt;path&gt;
+    &lt;fileset dir="dist" includes="**/*.jar" /&gt;
+  &lt;/path&gt;
+  &lt;flattenmapper /&gt;
+&lt;/signjar&gt;
+</pre></blockquote>
+<p>
+Sign all JAR files matching the dist/**/*.jar pattern, copying them to the
+directory "signed" afterwards. The flatten mapper means that they will
+all be copied to this directory, not to subdirectories.
+
+</p>
+  <blockquote><pre>
+&lt;signjar
+    alias="testonly" keystore="testkeystore"
+    storepass="apacheant"
+    lazy="true"
+    &gt;
+  &lt;path&gt;
+    &lt;fileset dir="dist" includes="**/*.jar" /&gt;
+  &lt;/path&gt;
+&lt;/signjar&gt;
+</pre></blockquote>
+<p>
+Sign all the JAR files in dist/**/*.jar <i>in-situ</i>. Lazy signing is used,
+so the files will only be signed if they are not already signed.
+</p>
+<h3>About timestamp signing</h3>
+
+<p>
+Timestamped JAR files are a new feature in Java1.5; a feature supported in Ant since
+Ant 1.7. Ant does not yet support proxy setup for this singing process, and
+the whole TSA feature is not tested yet. Furthermore, the 
+<a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/time-of-signing-beta1.html">
+official TSA documentation</a>
+warns that the API is subject to change. If a future version of Java changes the
+API, Ant will break. It may be possible to hide changes if and when they occur,
+but this can not be guaranteed. 
+</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/sleep.html b/trunk/docs/manual/CoreTasks/sleep.html
new file mode 100644
index 0000000..80827b5
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/sleep.html
@@ -0,0 +1,85 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Sleep Task</title>
+</head>
+
+<body>
+
+<h2><a name="sleep">Sleep</a></h2>
+<h3>Description</h3>
+<p> A task for sleeping a short period of time, useful when a build or deployment 
+  process requires an interval between tasks.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr> 
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr> 
+    <td valign="top">hours</td>
+    <td valign="top">hours to to add to the sleep time</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">minutes</td>
+    <td valign="top"> minutes to add to the sleep time</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">seconds</td>
+    <td valign="top">seconds to add to the sleep time</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">milliseconds</td>
+    <td valign="top">milliseconds to add to the sleep time</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">failonerror</td>
+    <td valign="top">flag controlling whether to break the build on an error. 
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<p>The sleep time is the sum of specified values, hours, minutes seconds and milliseconds. 
+  A negative value can be supplied to any of them provided the total sleep time 
+  is positive</p>
+<p>Note that sleep times are always hints to be interpred by the OS how it feels 
+  - small times may either be ignored or rounded up to a minimum timeslice. Note 
+  also that the system clocks often have a fairly low granularity too, which complicates 
+  measuring how long a sleep actually took.</p>
+<h3>Examples</h3>
+<pre>   &lt;sleep milliseconds=&quot;10&quot;/&gt;</pre>
+Sleep for about 10 mS. 
+<pre>   &lt;sleep seconds=&quot;2&quot;/&gt;</pre>
+Sleep for about 2 seconds. 
+<pre>   &lt;sleep hours=&quot;1&quot; minutes=&quot;-59&quot; seconds=&quot;-58&quot;/&gt;</pre>
+<p>Sleep for one hour less 59:58, or two seconds again </p>
+<pre>   &lt;sleep/&gt;</pre>
+Sleep for no time at all. This may yield the CPU time to another thread or process. 
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/sql.html b/trunk/docs/manual/CoreTasks/sql.html
new file mode 100644
index 0000000..f70c426
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/sql.html
@@ -0,0 +1,387 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SQL Task</title>
+</head>
+<body>
+
+<h2><a name="sql">Sql</a></h2>
+<h3>Description</h3>
+<p>Executes a series of SQL statements via JDBC to a database. Statements can 
+either be read in from a text file using the <i>src</i> attribute or from 
+between the enclosing SQL tags.</p>
+
+<p>Multiple statements can be provided, separated by semicolons (or the 
+defined <i>delimiter</i>). Individual lines within the statements can be 
+commented using either --, // or REM at the start of the line.</p>
+
+<p>The <i>autocommit</i> attribute specifies whether auto-commit should be 
+turned on or off whilst executing the statements. If auto-commit is turned 
+on each statement will be executed and committed. If it is turned off the 
+statements will all be executed as one transaction.</p>
+
+<p>The <i>onerror</i> attribute specifies how to proceed when an error occurs 
+during the execution of one of the statements. 
+The possible values are: <b>continue</b> execution, only show the error;
+<b>stop</b> execution and commit transaction;
+and <b>abort</b> execution and transaction and fail task.</p>
+
+<p>
+<b>Proxies</b>. Some JDBC drivers (including the Oracle thin driver), 
+    use the JVM's proxy settings to route their JDBC operations to the database.
+    Since Ant1.7, Ant running on Java1.5 or later defaults to 
+    <a href="../proxy.html">using
+    the proxy settings of the operating system</a>. 
+    Accordingly, the OS proxy settings need to be valid, or Ant's proxy
+    support disabled with <code>-noproxy</code> option.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+<tr>
+  <td width="12%" valign="top">driver</td>
+  <td width="78%" valign="top">Class name of the jdbc driver</td>
+  <td width="10%" valign="top">Yes</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">url</td>
+  <td width="78%" valign="top">Database connection url</td>
+  <td width="10%" valign="top">Yes</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">userid</td>
+  <td width="78%" valign="top">Database user name</td>
+  <td width="10%" valign="top">Yes</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">password</td>
+  <td width="78%" valign="top">Database password</td>
+  <td width="10%" valign="top">Yes</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">src</td>
+  <td width="78%" valign="top">File containing SQL statements</td>
+  <td width="10%" valign="top">Yes, unless statements enclosed within tags</td>
+</tr>
+<tr>
+  <td valign="top">encoding</td>
+  <td valign="top">The encoding of the files containing SQL statements</td>
+  <td align="center">No - defaults to default JVM encoding</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">delimiter</td>
+  <td width="78%" valign="top">String that separates SQL statements</td>
+  <td width="10%" valign="top">No, default &quot;;&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">autocommit</td>
+  <td width="78%" valign="top">Auto commit flag for database connection (default false)</td>
+  <td width="10%" valign="top">No, default &quot;false&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">print</td>
+  <td width="78%" valign="top">Print result sets from the statements (default false)</td>
+  <td width="10%" valign="top">No, default &quot;false&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">showheaders</td>
+  <td width="78%" valign="top">Print headers for result sets from the statements (default true)</td>
+  <td width="10%" valign="top">No, default &quot;true&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">showtrailers</td>
+  <td width="78%" valign="top">Print trailer for number of rows affected (default true)</td>
+  <td width="10%" valign="top">No, default &quot;true&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">output</td>
+  <td width="78%" valign="top">Output file for result sets (defaults to System.out)</td>
+  <td width="10%" valign="top">No (print to System.out by default)</td>
+</tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">whether output should be appended to or overwrite
+    an existing file.  Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+<tr>
+  <td width="12%" valign="top">classpath</td>
+  <td width="78%" valign="top">Classpath used to load driver</td>
+  <td width="10%" valign="top">No (use system classpath)</td>
+</tr>
+  <tr>
+    <td width="12%" valign="top">classpathref</td>
+    <td width="78%" valign="top">The classpath to use, given as a <a href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+  <td width="10%" valign="top">No (use system classpath)</td>
+  </tr>
+<tr>
+  <td width="12%" valign="top">onerror</td>
+  <td width="78%" valign="top">Action to perform when statement fails: continue, stop, abort</td>
+  <td width="10%" valign="top">No, default &quot;abort&quot;</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">rdbms</td>
+  <td width="78%" valign="top">Execute task only if this rdbms</td>
+  <td width="10%" valign="top">No (no restriction)</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">version</td>
+  <td width="78%" valign="top">Execute task only if rdbms version match</td>
+  <td width="10%" valign="top">No (no restriction)</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">caching</td>
+  <td width="78%" valign="top">Should the task cache loaders and the driver?</td>
+  <td width="10%" valign="top">No (default=true)</td>
+</tr>
+
+<tr>
+  <td width="12%" valign="top">delimitertype</td>
+  <td width="78%" valign="top">Control whether the delimiter will only be recognized on a line by itself.<br>
+    Can be "normal" -anywhere on the line, or "row", meaning it must be on a line by itself</td>
+  <td width="10%" valign="top">No (default:normal)</td>
+</tr>
+
+<tr>
+  <td width="12%" valign="top">keepformat</td>
+  <td width="78%" valign="top">Control whether the format of the sql will be preserved.<br>
+    Useful when loading packages and procedures.
+  <td width="10%" valign="top">No (default=false)</td>
+</tr>
+
+<tr>
+  <td width="12%" valign="top">escapeprocessing</td>
+  <td width="78%" valign="top">Control whether the Java statement
+    object will perform escape substitution.<br>
+    See <a
+    href="http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Statement.html#setEscapeProcessing(boolean)">Statement's
+    API docs</a> for details.  <em>Since Ant 1.6</em>.
+  <td width="10%" valign="top">No (default=true)</td>
+</tr>
+
+<tr>
+  <td width="12%" valign="top">expandproperties</td>
+  <td width="78%" valign="top">Set to true to turn on property expansion in
+  nested SQL, inline in the task or nested transactions. <em>Since Ant 1.7</em>.
+  <td width="10%" valign="top">No (default=true)</td>
+</tr>
+
+<tr>
+  <td width="12%" valign="top">rawblobs</td>
+  <td width="78%" valign="top">If true, will write raw streams rather than hex encoding when
+    printing BLOB results. <em>Since Ant 1.7.1</em>.</td>
+  <td width="10%" valign="top">No, default <em>false</em></td>
+</tr>
+
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<h4>transaction</h4>
+<p>Use nested <code>&lt;transaction&gt;</code> 
+elements to specify multiple blocks of commands to the executed
+executed in the same connection but different transactions. This
+is particularly useful when there are multiple files to execute
+on the same schema.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">File containing SQL statements</td>
+    <td valign="top" align="center">Yes, unless statements enclosed within tags</td>
+  </tr>
+</table>
+<p>The <code>&lt;transaction&gt;</code> element supports any <a
+href="../CoreTypes/resources.html">resource</a> or single element
+resource collection as nested element to specify the resource
+containing the SQL statements.</p>
+
+<h4>any <a href="../CoreTypes/resources.html">resource</a> or resource
+collection</h4>
+
+<p>You can specify multiple sources via nested resource collection
+elements.  Each resource of the collection will be run in a
+transaction of its own.  Prior to Ant 1.7 only filesets were
+supported.  Use a sort resource collection to get a predictable order
+of transactions. </p>
+
+<h4>classpath</h4>
+<p><code>Sql</code>'s <em>classpath</em> attribute is a <a
+href="../using.html#path">PATH like structure</a> and can also be set via a nested
+<em>classpath</em> element. It is used to load the JDBC classes.</p>
+
+<h3>Examples</h3>
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;
+    src=&quot;data.sql&quot;
+/&gt;
+</pre></blockquote>
+
+<p>Connects to the database given in <i>url</i> as the sa user using the 
+org.database.jdbcDriver and executes the SQL statements contained within 
+the file data.sql</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;
+    &gt;
+insert
+into table some_table
+values(1,2,3,4);
+
+truncate table some_other_table;
+&lt;/sql&gt;
+</pre></blockquote>
+
+<p>Connects to the database given in <i>url</i> as the sa
+ user using the org.database.jdbcDriver and executes the two SQL statements 
+ inserting data into some_table and truncating some_other_table. Ant Properties
+ in the nested text will not be expanded.</p>
+
+<p>Note that you may want to enclose your statements in
+<code>&lt;![CDATA[</code> ... <code>]]&gt;</code> sections so you don't
+need to escape <code>&lt;</code>, <code>&gt;</code> <code>&amp;</code>
+or other special characters. For example:</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;
+    &gt;&lt;![CDATA[
+
+update some_table set column1 = column1 + 1 where column2 &lt; 42;
+
+]]&gt;&lt;/sql&gt;
+</pre></blockquote>
+
+The following command turns property expansion in nested text on (it is off purely for backwards
+compatibility), then creates a new user in the HSQLDB database using Ant properties. 
+
+<blockquote><pre>&lt;sql
+    driver="org.hsqldb.jdbcDriver";
+    url="jdbc:hsqldb:file:${database.dir}"
+    userid="sa"
+    password=""
+    expandProperties="true"
+    &gt;
+  &lt;transaction&gt;
+    CREATE USER ${newuser} PASSWORD ${newpassword}
+  &lt;/transaction&gt;
+&lt;/sql&gt;
+</pre></blockquote>
+
+
+<p>The following connects to the database given in url as the sa user using 
+the org.database.jdbcDriver and executes the SQL statements contained within 
+the files data1.sql, data2.sql and data3.sql and then executes the truncate 
+operation on <i>some_other_table</i>.</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot; &gt;
+  &lt;transaction  src=&quot;data1.sql&quot;/&gt;
+  &lt;transaction  src=&quot;data2.sql&quot;/&gt;
+  &lt;transaction  src=&quot;data3.sql&quot;/&gt;
+  &lt;transaction&gt;
+    truncate table some_other_table;
+  &lt;/transaction&gt;
+&lt;/sql&gt;
+</pre></blockquote>
+
+<p>The following example does the same as (and may execute additional
+SQL files if there are more files matching the pattern
+<code>data*.sql</code>) but doesn't guarantee that data1.sql will be
+run before <code>data2.sql</code>.</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;&gt;
+  &lt;path&gt;
+    &lt;fileset dir=&quot;.&quot;&gt;
+      &lt;include name=&quot;data*.sql&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;path&gt;
+  &lt;transaction&gt;
+    truncate table some_other_table;
+  &lt;/transaction&gt;
+&lt;/sql&gt;
+</pre></blockquote>
+
+<p>The following connects to the database given in url as the sa user using the 
+org.database.jdbcDriver and executes the SQL statements contained within the 
+file data.sql, with output piped to outputfile.txt, searching /some/jdbc.jar 
+as well as the system classpath for the driver class.</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;
+    src=&quot;data.sql&quot;
+    print=&quot;yes&quot;
+    output=&quot;outputfile.txt&quot;
+    &gt;
+&lt;classpath&gt;
+	&lt;pathelement location=&quot;/some/jdbc.jar&quot;/&gt;
+&lt;/classpath&gt;
+&lt;/sql&gt;
+</pre></blockquote>
+
+<p>The following will only execute if the RDBMS is &quot;oracle&quot; and the version 
+starts with &quot;8.1.&quot;</p>
+
+<blockquote><pre>&lt;sql
+    driver=&quot;org.database.jdbcDriver&quot;
+    url=&quot;jdbc:database-url&quot;
+    userid=&quot;sa&quot;
+    password=&quot;pass&quot;
+    src=&quot;data.sql&quot;
+    rdbms=&quot;oracle&quot;
+    version=&quot;8.1.&quot;
+    &gt;
+insert
+into table some_table
+values(1,2,3,4);
+
+truncate table some_other_table;
+&lt;/sql&gt;
+</pre></blockquote>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/style.html b/trunk/docs/manual/CoreTasks/style.html
new file mode 100644
index 0000000..f7961a3
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/style.html
@@ -0,0 +1,485 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>XSLT Task</title>
+</head>
+
+<body>
+
+<h2><a name="style">XSLT</a></h2>
+<p><em>The name <code>style</code> is a deprecated name for the same task.</em></p>
+<h3>Description</h3>
+<p>Process a set of documents via XSLT.</p>
+<p>This is useful for building views of XML based documentation,
+or for generating code.</p>
+<p><b>Note:</b> If you are using JDK 1.4 or higher, this task does not require external libraries
+not supplied in the Ant distribution. However, often the built in XSL engine is not as up
+to date as a fresh download, so an update is still highly recommended.
+See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p>
+<p>It is possible to refine the set of files that are being processed. This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and supports all
+  attributes of <code>&lt;fileset&gt;</code> (<code>dir</code> becomes <code>basedir</code>)
+  as well as the nested <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code>
+  and <code>&lt;patternset&gt;</code> elements.</p>
+
+<p><b>Note</b>: Unlike other similar tasks, this task treats
+directories that have been matched by the include/exclude patterns of
+the implicit fileset in a special way.  It will apply the stylesheets
+to all files contain in them as well.  Since the default include
+pattern is <code>**</code> this means it will apply the stylesheet to
+all files.  If you specify an excludes pattern, it may still work on
+the files matched by those patterns because the parent directory has
+been matched.  If this behavior is not what you want, set the
+scanincludedirectories attribute to false.</p>
+
+<p>Starting with Ant 1.7 this task supports nested <a
+href="../CoreTypes/resources.html#collection">resource collection</a>s
+in addition to (or instead of, depending on the useImplicitFileset
+attribute) the implicit fileset formed by this task.</p>
+
+<p>This task supports the use of a nested <code>&lt;param&gt;</code> element which is used to pass values
+  to an <code>&lt;xsl:param&gt;</code> declaration.</p>
+<p>This task supports the use of a nested <a href="../CoreTypes/xmlcatalog.html">xmlcatalog</a>
+element which is used to perform Entity and URI resolution.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">where to find the source XML file, default is the
+      project's basedir.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">directory in which to store the results.</td>
+    <td align="center" valign="top">Yes, unless in and out have been
+      specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">extension</td>
+    <td valign="top">desired file extension to be used for the targets. If not
+      specified, the default is &quot;.html&quot;.  Will be ignored if
+      a nested <code>&lt;mapper&gt;</code> has been specified.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">style</td>
+    <td valign="top">name of the stylesheet to use - given either relative
+      to the project's basedir or as an absolute path.<br/>
+      <br/>
+      Alternatively, a nested element which ant can interpret as a resource
+      can be used to indicate where to find the stylesheet<br/>
+      <em>deprecated variation :</em> <br/>
+      If the stylesheet cannot be found, and if you have specified the
+      attribute basedir for the task, ant will assume that the style
+      attribute is relative to the basedir of the task.
+    </td>
+    <td align="center" valign="top">No, if the location of
+        the stylesheet is specified using a nested &lt;style&gt; element</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use when looking up the XSLT
+      processor.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use, given as <a
+      href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">force</td>
+    <td valign="top">Recreate target files, even if they are newer
+      than their corresponding source files or the stylesheet.</td>
+    <td valign="top" align="center">No; default is false</td>
+  </tr>
+  <tr>
+    <td valign="top">processor</td>
+
+    <td valign="top">name of the XSLT processor to use.
+      Permissible value is :<ul>
+      <li>&quot;trax&quot; for a TraX compliant processor (ie JAXP interface
+      implementation such as Xalan 2 or Saxon)</li></ul>
+      Defaults to trax.
+      <br/>
+      Support for xalan1 has been removed in ant 1.7.
+      </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be included.
+      All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is taken to be
+      an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be excluded.
+      No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is taken to be
+      an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">in</td>
+    <td valign="top">specifies a single XML document to be styled. Should be used
+      with the out attribute.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">out</td>
+    <td valign="top">specifies the output name for the styled result from the
+      in attribute.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">scanincludeddirectories</td>
+    <td valign="top">If any directories are matched by the
+      includes/excludes patterns, try to transform all files in these
+      directories.  Default is <code>true</code></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">reloadstylesheet</td>
+    <td valign="top">Control whether the stylesheet transformer is created
+    anew for every transform opertaion. If you set this to true, performance may
+    suffer, but you may work around a bug in certain Xalan-J versions.
+    Default is <code>false</code>.  <em>Since Ant 1.5.2</em>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">useImplicitFileset</td>
+    <td valign="top">Whether the implicit fileset formed by this task
+    shall be used.  If you set this to false you must use nested
+    resource collections - or the in attribute, in which case this
+    attribute has no impact anyway.  Default is <code>true</code>.
+    <em>Since Ant 1.7</em>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filenameparameter</td>
+    <td valign="top">Specifies a xsl parameter for accessing the name
+    of the current processed file. If not set, the file name is not
+    passed to the transformation.
+    <em>Since Ant 1.7</em>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filedirparameter</td>
+    <td valign="top">Specifies a xsl parameter for accessing the directory
+    of the current processed file. For files in the current directory a
+    value of '.' will be passed to the transformation.
+    If not set, the directory is not passed to the transformation. 
+    <em>Since Ant 1.7</em>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any <a href="../CoreTypes/resources.html#collection">resource
+collection</a></h4>
+
+<p><em>since Ant 1.7</em></p>
+
+<p>Use resource collections to specify resources that the stylesheet
+should be applied to.  Use a nested mapper and the task's destdir
+attribute to specify the output files.</p>
+
+<h4>classpath</h4>
+<p>The classpath to load the processor from can be specified via a
+nested <code>&lt;classpath&gt;</code>, as well - that is, a
+<a href="../using.html#path">path</a>-like structure.</p>
+
+<h4>xmlcatalog</h4>
+<p>The <a href="../CoreTypes/xmlcatalog.html">xmlcatalog</a>
+element is used to perform Entity and URI resolution.</p>
+
+<h4>param</h4>
+<p>Param is used to pass a parameter to the XSL stylesheet.</p>
+<blockquote>
+<h4>Parameters</h4>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the XSL parameter</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">expression</td>
+    <td valign="top">Text value to be placed into the param.<br>
+    Was originally intended to be an XSL expression.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">The param will only passed if this property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">The param will only passed unless this property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+
+</table>
+</blockquote>
+
+<h4>outputproperty ('trax' processors only)</h4>
+<p>Used to specify how you wish the result tree to be output
+as specified in the <a href="http://www.w3.org/TR/xslt#output">
+XSLT specifications</a>.
+<blockquote>
+<h4>Parameters</h4>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the property</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">value of the property.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</blockquote>
+
+<h4>factory ('trax' processors only)</h4>
+Used to specify factory settings.
+<blockquote>
+<h4>Parameters</h4>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">fully qualified classname of the
+    transformer factory to use. For example
+      <tt>org.apache.xalan.processor.TransformerFactoryImpl</tt>
+       or <tt>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</tt>
+       or <tt>net.sf.saxon.TransformerFactoryImpl</tt>...
+    </td>
+    <td align="center" valign="top">No. Defaults to the JAXP lookup mechanism.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>attribute </h4>
+<p>Used to specify settings of the processor factory.
+The attribute names and values are entirely processor specific
+so you must be aware of the implementation to figure them out.
+Read the documentation of your processor.
+For example, in Xalan 2.x:
+<ul>
+<li>http://xml.apache.org/xalan/features/optimize (boolean)</li>
+<li>http://xml.apache.org/xalan/features/incremental (boolean)</li>
+<li>...</li>
+</ul>
+And in Saxon 7.x:
+<ul>
+<li>http://saxon.sf.net/feature/allow-external-functions (boolean)</li>
+<li>http://saxon.sf.net/feature/timing (boolean)</li>
+<li>http://saxon.sf.net/feature/traceListener (string)</li>
+<li>http://saxon.sf.net/feature/treeModel (integer)</li>
+<li>http://saxon.sf.net/feature/linenumbering (integer)</li>
+<li>...</li>
+</ul>
+<blockquote>
+<h4>Parameters</h4>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the attribute</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">value of the attribute.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</blockquote>
+</blockquote>
+<h4>mapper</h4>
+
+<p><em>since Ant 1.6.2</em></p>
+
+<p>You can define filename transformations by using a nested <a
+href="../CoreTypes/mapper.html">mapper</a> element. The default mapper
+used by <code>&lt;xslt&gt;</code> removes the file extension from the
+source file and adds the extension specified via the extension
+attribute.</p>
+
+<h4>style</h4>
+
+<p><em>Since Ant 1.7</em></p>
+
+<p>The nested style element can be used to specify your stylesheet in terms
+of Ant's <a href="../CoreTypes/resources.html">resource</a> types.  With
+this element, the stylesheet should be specified as a nested resource or
+single-element collection.  Alternatively, use the <code>refid</code> to
+specify the resource or collection as a reference.</p>
+
+<h3>Examples</h3>
+<blockquote>
+  <pre>
+&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
+       extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;/&gt;</pre>
+  <h4>Using an xmlcatalog</h4>
+  <pre>
+&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
+      extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&gt;
+  &lt;xmlcatalog refid=&quot;mycatalog&quot;/&gt;
+&lt;/xslt&gt;
+
+&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
+   extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&gt;
+   &lt;xmlcatalog&gt;
+       &lt;dtd
+         publicId=&quot;-//ArielPartners//DTD XML Article V1.0//EN&quot;
+         location=&quot;com/arielpartners/knowledgebase/dtd/article.dtd&quot;/&gt;
+   &lt;/xmlcatalog&gt;
+&lt;/xslt&gt;
+</pre>
+  <h4>Using XSL parameters</h4>
+<pre>
+&lt;xslt basedir=&quot;doc&quot; destdir=&quot;build/doc&quot;
+      extension=&quot;.html&quot; style=&quot;style/apache.xsl&quot;&gt;
+  &lt;param name=&quot;date&quot; expression=&quot;07-01-2000&quot;/&gt;
+&lt;/xslt&gt;</pre>
+
+  <p>Then if you declare a global parameter &quot;date&quot; with the top-level
+  element &lt;xsl:param name=&quot;date&quot;/&gt;, the variable
+  <code>$date</code> will subsequently have the value 07-01-2000.
+  </p>
+
+  <h4>Using output properties</h4>
+<pre>
+&lt;xslt in=&quot;doc.xml&quot; out=&quot;build/doc/output.xml&quot;
+      style=&quot;style/apache.xsl&quot;&gt;
+  &lt;outputproperty name=&quot;method&quot; value=&quot;xml&quot;/&gt;
+  &lt;outputproperty name=&quot;standalone&quot; value=&quot;yes&quot;/&gt;
+  &lt;outputproperty name=&quot;encoding&quot; value=&quot;iso8859_1&quot;/&gt;
+  &lt;outputproperty name=&quot;indent&quot; value=&quot;yes&quot;/&gt;
+&lt;/xslt&gt;
+</pre>
+
+  <h4>Using factory settings</h4>
+<pre>
+&lt;xslt in=&quot;doc.xml&quot; out=&quot;build/doc/output.xml&quot;
+      style=&quot;style/apache.xsl&quot;&gt;
+  &lt;factory name=&quot;org.apache.xalan.processor.TransformerFactoryImpl&quot;&gt;
+    &lt;attribute name=&quot;http://xml.apache.org/xalan/features/optimize&quot; value=&quot;true&quot;/&gt;
+  &lt;/factory&gt;
+&lt;/xslt&gt;</pre>
+
+  <h4>Using a mapper</h4>
+<pre>
+&lt;xslt basedir=&quot;in&quot; destdir=&quot;out&quot;
+      style=&quot;style/apache.xsl&quot;&gt;
+  &lt;mapper type=&quot;glob&quot; from=&quot;*.xml.en&quot; to=&quot;*.html.en&quot;/&gt;
+&lt;/xslt&gt;</pre>
+
+  <h4>Using a nested resource to define the stylesheet</h4>
+    <pre>
+&lt;xslt in="data.xml" out="${out.dir}/out.xml"&gt;
+    &lt;style&gt;
+        &lt;url url="${printParams.xsl.url}"/&gt;
+    &lt;/style&gt;
+    &lt;param name="set" expression="value"/&gt;
+&lt;/xslt&gt;</pre>
+
+  <h4>Print the current processed file name</h4>
+<pre>
+&lt;project&gt;
+  &lt;xslt style=&quot;printFilename.xsl&quot; destdir=&quot;out&quot; basedir=&quot;in&quot; extension=&quot;.txt&quot;
+        filenameparameter=&quot;filename&quot;
+        filedirparameter=&quot;filedir&quot;
+  /&gt;
+&lt;/project&gt;
+
+&lt;xsl:stylesheet
+  version=&quot;1.0&quot;
+  xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
+
+    &lt;xsl:param name=&quot;filename&quot;&gt;&lt;/xsl:param&gt;
+    &lt;xsl:param name=&quot;filedir&quot;&gt;.&lt;/xsl:param&gt;
+
+&lt;xsl:template match=&quot;/&quot;&gt;
+  Current file is &lt;xsl:value-of select=&quot;$filename&quot;/&gt; in directory &lt;xsl:value-of select=&quot;$filedir&quot;/&gt;.
+&lt;/xsl:template&gt;
+
+&lt;/xsl:stylesheet&gt;
+</pre>
+
+</blockquote>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/subant.html b/trunk/docs/manual/CoreTasks/subant.html
new file mode 100644
index 0000000..94652f5
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/subant.html
@@ -0,0 +1,598 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Subant
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Subant
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Calls a given target for all defined sub-builds.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+<p>
+            Calls a given target for all defined sub-builds.
+            This is an extension
+            of ant for bulk project execution.
+
+            <strong>This task must not be used outside of a
+                <code>target</code> if it invokes the same build file it is
+                part of.</strong>
+        </p>
+        <p><em>Since Ant 1.6</em></p>
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="#828DA6">
+          <font color="#ffffff" face="arial,helvetica.sanserif">
+                              <a name="Use with directories">
+          <strong>Use with directories</strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td>
+        <p>
+                subant can be used with directory sets to execute a build from different directories.
+                2 different options are offered :
+            </p>
+<ul>
+                <li>
+                    to run the same build file <code>/somepath/otherpath/mybuild.xml</code>
+                    with different base directories, use the genericantfile attribute
+                </li>
+                <li>if you want to run <code>directory1/mybuild.xml</code>, <code>directory2/mybuild.xml</code>, <code>....</code>,
+                    use the antfile attribute. The subant task does not set the base directory for you in this case, because you can specify it in each build file.
+                </li>
+            </ul>
+
+      </td></tr>
+    </table>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+ <!-- Ignore -->
+
+
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->
+
+    <!-- Attribute Group -->
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">antfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Build file name, to use in conjunction with directories.<br> Defaults to "build.xml".<br> If <code>genericantfile</code> is set, this attribute is ignored.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="10">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">buildpath</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the buildpath to be used to find sub-projects.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">buildpathref</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Buildpath to use, by reference.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Reference</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets whether to fail with a build exception on error, or go on.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">genericantfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Build file path, to use in conjunction with directories.<br> Use <code>genericantfile</code>, in order to run the same build file with different basedirs.<br> If this attribute is set, <code>antfile</code> is ignored.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">inheritall</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1"
+                        face="arial,helvetica,sanserif">Corresponds to
+                        <code>&lt;ant&gt;</code>'s
+                        <code>inheritall</code> attribute but defaults
+                        to false in this task..</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">inheritrefs</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Corresponds to <code>&lt;ant&gt;</code>'s <code>inheritrefs</code> attribute.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">output</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Corresponds to <code>&lt;ant&gt;</code>'s <code>output</code> attribute.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">target</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"></font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">verbose</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">
+            Enable/ disable log messages showing when each sub-build path is entered/ exited.
+            The default value is false.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>any filesystem based <a href="../CoreTypes/resources.html#collection">resource collection</a></strong></font>
+      </td></tr>
+      <tr><td><blockquote>
+        This includes <code>&lt;fileset&gt;</code>,
+        <code>&lt;dirset&gt;</code> and <code>&lt;filelist&gt;</code>
+        which are the nested resource collections supported prior
+        to Ant 1.7.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>dirset</strong> (org.apache.tools.ant.types.DirSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Adds a directory set to the implicit build path. <p> <em>Note that the directories will be added to the build path in no particular order, so if order is significant, one should use a file list instead!</em>
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>filelist</strong> (org.apache.tools.ant.types.FileList)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Adds an ordered file list to the implicit build path. <p> <em>Note that contrary to file and directory sets, file lists can reference non-existent files or directories!</em>
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>fileset</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Adds a file set to the implicit build path. <p> <em>Note that the directories will be added to the build path in no particular order, so if order is significant, one should use a file list instead!</em>
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>property</strong> (org.apache.tools.ant.taskdefs.Property)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Corresponds to <code>&lt;ant&gt;</code>'s nested <code>&lt;property&gt;</code> element.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>propertyset</strong> (org.apache.tools.ant.types.PropertySet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Corresponds to <code>&lt;ant&gt;</code>'s nested <code>&lt;propertyset&gt;</code> element.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>buildpath</strong> (org.apache.tools.ant.types.Path)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Creates a nested build path, and add it to the implicit build path.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>buildpathelement</strong> (org.apache.tools.ant.types.Path.PathElement)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        Creates a nested <code>&lt;buildpathelement&gt;</code>, and add it to the implicit build path.
+ <!-- Ignore -->
+ <!-- Ignore -->
+
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+
+
+
+<!-- manually written -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>target</strong> (org.apache.tools.ant.taskdefs.Ant.TargetElement)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        You can specify multiple targets using nested <code>&lt;target&gt;</code> elements
+        instead of using the target attribute.  These will be executed as if
+        Ant had been invoked with a single target whose dependencies are the
+        targets so specified, in the order specified.
+ <!-- Ignore -->
+ <!-- Ignore -->
+      <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Required</b></td>
+        </tr>
+        <tr>
+          <td valign="top">name</td>
+          <td valign="top">The name of the called target.</td>
+          <td valign="top" align="center">Yes</td>
+        </tr>
+      </table>
+      <p><em>since Ant 1.7</em>.</p>
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+<!-- manually written end -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+          <font color="#ffffff" face="arial,helvetica.sanserif">
+                              <a name="examples">
+          <strong>Examples</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote style="">
+        <pre>
+        &lt;project name="subant" default="subant1"&gt;
+            &lt;property name="build.dir" value="subant.build"/&gt;
+            &lt;target name="subant1"&gt;
+                &lt;subant target=""&gt;
+                    &lt;property name="build.dir" value="subant1.build"/&gt;
+                    &lt;property name="not.overloaded" value="not.overloaded"/&gt;
+                    &lt;fileset dir="." includes="*/build.xml"/&gt;
+                &lt;/subant&gt;
+            &lt;/target&gt;
+        &lt;/project&gt;
+        </pre>
+<p>
+            this snippet build file will run ant in each subdirectory of the project directory,
+            where a file called build.xml can be found.
+            The property build.dir will have the value subant1.build in the ant projects called by subant.
+        </p>
+<pre>
+          &lt;subant target=""&gt;
+              &lt;propertyset&gt;
+                  &lt;propertyref prefix="toplevel"/&gt;
+                  &lt;mapper type="glob" from="foo*" to="bar*"/&gt;
+              &lt;/propertyset&gt;
+              &lt;fileset dir="." includes="*/build.xml"/&gt;
+          &lt;/subant&gt;
+        </pre>
+<p>
+            this snippet build file will run ant in each subdirectory of the project directory,
+            where a file called build.xml can be found.
+            All properties whose name starts with "foo" are passed, their names are changed to start with "bar" instead
+        </p>
+<pre>
+          &lt;subant target="compile" genericantfile="/opt/project/build1.xml"&gt;
+              &lt;dirset dir="." includes="projects*"/&gt;
+          &lt;/subant&gt;
+        </pre>
+<p>
+            assuming the subdirs of the project dir are called projects1, projects2, projects3
+            this snippet will execute the compile target of /opt/project/build1.xml,
+            setting the basedir to projects1, projects2, projects3
+        </p>
+
+        <!-- manually written -->
+        <p>Now a little more complex - but useful - scenario. Assume that we have
+        a directory structure like this:</p>
+        <pre>
+        root
+          |  common.xml
+          |  build.xml
+          |
+          +-- modules
+                +-- modA
+                |     +-- src
+                +-- modB
+                      +-- src
+
+        <u><b>common.xml:</b></u><br>
+        &lt;project&gt;
+            &lt;property name="src.dir"      value="src"/&gt;
+            &lt;property name="build.dir"    value="build"/&gt;
+            &lt;property name="classes.dir"  value="${build.dir}/classes"/&gt;
+
+            &lt;target name="compile"&gt;
+                &lt;mkdir dir="${classes.dir}"/&gt;
+                &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;
+            &lt;/target&gt;
+
+            &lt;!-- more targets --&gt;
+        &lt;/project&gt;
+
+        <u><b>build.xml:</b></u><br>
+        &lt;project&gt;
+
+            &lt;macrodef name="iterate"&gt;
+                &lt;attribute name="target"/&gt;
+                &lt;sequential&gt;
+                    &lt;subant target="@{target}"&gt;
+                        &lt;fileset dir="modules" includes="*/build.xml"/&gt;
+                    &lt;/subant&gt;
+                &lt;/sequential&gt;
+            &lt;/macrodef&gt;
+
+
+            &lt;target name="compile"&gt;
+                &lt;iterate target="compile"/&gt;
+            &lt;/target&gt;
+
+            &lt;!-- more targets --&gt;
+        &lt;/project&gt;
+
+        <u><b>modules/modA/build.xml:</b></u><br>
+        &lt;project name="modA"&gt;
+            &lt;import file="../../common.xml"/&gt;
+        &lt;/project&gt;
+        </pre>
+
+        <p>This results in very small buildfiles in the modules, maintainable
+        buildfile (common.xml) and a clear project structure. Additionally
+        the root buildfile is capable to run the whole build over all
+        modules.
+        </p>
+
+        <pre>
+        &lt;subant failonerror="false"&gt;
+            &lt;fileset dir="." includes="**/build.xml" excludes="build.xml"/&gt;
+            &lt;target name="clean"/&gt;
+            &lt;target name="build"/&gt;
+        &lt;/subant&gt;
+        </pre>
+
+        <p>Does a &quot;clean build&quot; for each subproject.</p>
+        <p><b>Hint:</b> because buildfiles are plain xml, you could generate the
+        masterbuildfile from the common buildfile by using a XSLT transformation:
+        </p>
+
+        <pre>
+        &lt;xslt in=&quot;common.xml&quot;
+              out=&quot;master.xml&quot;
+              style=&quot;${ant.home}/etc/common2master.xsl&quot;
+        /&gt;
+        </pre>
+
+        <!-- manually written -->
+
+      </blockquote></td></tr>
+
+    </table>
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/sync.html b/trunk/docs/manual/CoreTasks/sync.html
new file mode 100644
index 0000000..7ec4971
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/sync.html
@@ -0,0 +1,137 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Sync Task</title>
+</head>
+
+<body>
+
+<h2><a name="get">Sync</a></h2>
+<p><em>Since Ant 1.6</em></p>
+<h3>Description</h3>
+
+<p>Synchronize a target directory from the files defined in one or
+more <a href="../CoreTypes/resources.html#collection">Resource Collection</a>s.</p>
+
+<p>Any file in the target directory that has not been matched by at
+least one of the nested resource collections gets removed.  I.e. if you exclude a
+file in your sources and a file of that name is present in the target
+dir, it will get removed from the target.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">the target directory to sync with the resource collections</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>  
+  <tr>
+    <td valign="top">overwrite</td>
+    <td valign="top">Overwrite existing files even if the destination
+      files are newer.</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">includeEmptyDirs</td>
+     <td valign="top">Copy any empty directories included in the resource collection(s).
+     </td>
+     <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">If is set to false, log a warning message, but do not stop the build,
+       when one of the nested filesets points to a directory that
+       doesn't exist.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+     <td valign="top">Log the files that are being copied.</td>
+     <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">granularity</td>
+    <td valign="top">The number of milliseconds leeway to give before
+    deciding a file is out of date. This is needed because not every
+    file system supports tracking the last modified time to the
+    millisecond level. Default is 0 milliseconds, or 2 seconds on DOS
+    systems.  This can also be useful if source and target files live
+    on separate machines with clocks being out of sync.  <em>since Ant
+    1.6.2</em>.</td>
+     <td valign="top" align="center">No.</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>fileset or any other resource collection</h4>
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select groups of files to copy.  To use a
+resource collection, the <code>todir</code> attribute must be set.</p>
+<p>Prior to Ant 1.7 only <code>&lt;fileset&gt;</code> has been
+supported as a nested element.</p>
+
+<h4>preserveInTarget</h4>
+
+<p>Specifies files or directories that should be kept in the target
+directory even if they are not present in one of the source
+directories.</p>
+
+<p>This nested element is like a <a
+href="../CoreTypes/fileset.html">FileSet</a> except that it doesn't
+support the dir attribute and the usedefaultexcludes attribute
+defaults to false.</p>
+
+<h3>Examples</h3>
+
+<blockquote><pre>
+&lt;sync todir=&quot;site&quot;&gt;
+  &lt;fileset dir=&quot;generated-site&quot;/&gt;
+&lt;/sync&gt;
+</pre></blockquote>
+<p>overwrites all files in <em>site</em> with newer files from
+<em>generated-site</em>, deletes files from <em>site</em> that are not
+present in <em>generated-site</em>.</p>
+
+<blockquote><pre>
+&lt;sync todir=&quot;site&quot;&gt;
+  &lt;fileset dir=&quot;generated-site&quot;/&gt;
+  &lt;preserveintarget&gt;
+    &lt;include name=&quot;**/CVS/**&quot;/&gt;
+  &lt;/preserveintarget&gt;
+&lt;/sync&gt;
+</pre></blockquote>
+<p>overwrites all files in <em>site</em> with newer files from
+<em>generated-site</em>, deletes files from <em>site</em> that are not
+present in <em>generated-site</em> but keeps all files in any
+<em>CVS</em> sub-directory.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/tar.html b/trunk/docs/manual/CoreTasks/tar.html
new file mode 100644
index 0000000..18ea8b0
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/tar.html
@@ -0,0 +1,250 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Tar Task</title>
+</head>
+
+<body>
+
+<h2><a name="tar">Tar</a></h2>
+<h3>Description</h3>
+<p>Creates a tar archive.</p>
+<p>The <i>basedir</i> attribute is the reference directory from where to tar.</p>
+<p>This task is a <a href="../dirtasks.html#directorybasedtasks">directory based task</a>
+and, as such, forms an implicit <a href="../CoreTypes/fileset.html">Fileset</a>. This
+defines which files, relative to the <i>basedir</i>, will be included in the
+archive. The tar task supports all the attributes of Fileset to refine the
+set of files to be included in the implicit fileset.</p>
+
+<p>In addition to the implicit fileset, the tar task supports nested
+      resource collections and a special form of filesets. These
+filesets are extended to allow control over the access mode, username and groupname
+to be applied to the tar entries. This is useful, for example, when preparing archives for
+Unix systems where some files need to have execute permission.</p>
+
+<p>Early versions of tar did not support path lengths greater than 100
+characters. Modern versions of tar do so, but in incompatible ways.
+The behaviour of the tar task when it encounters such paths is
+controlled by the <i>longfile</i> attribute.
+If the longfile attribute is set to <code>fail</code>, any long paths will
+cause the tar task to fail.  If the longfile attribute is set to
+<code>truncate</code>, any long paths will be truncated to the 100 character
+maximum length prior to adding to the archive. If the value of the longfile
+attribute is set to <code>omit</code> then files containing long paths will be
+omitted from the archive.  Either option ensures that the archive can be
+untarred by any compliant version of tar. If the loss of path or file
+information is not acceptable, and it rarely is, longfile may be set to the
+value <code>gnu</code>. The tar task will then produce a GNU tar file which
+can have arbitrary length paths. Note however, that the resulting archive will
+only be able to be untarred with GNU tar.  The default for the longfile
+attribute is <code>warn</code> which behaves just like the gnu option except
+that it produces a warning for each file path encountered that does not match
+the limit.</p>
+
+<p>This task can perform compression by setting the compression attribute to "gzip"
+or "bzip2".</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the tar-file to create.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory from which to tar the files.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">longfile</td>
+    <td valign="top">Determines how long files (&gt;100 chars) are to be
+       handled.  Allowable values are &quot;truncate&quot;, &quot;fail&quot;,
+       &quot;warn&quot;, &quot;omit&quot; and &quot;gnu&quot;.  Default is
+       &quot;warn&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compression</td>
+    <td valign="top">compression method.  Allowable values are 
+       &quot;none&quot;, &quot;gzip&quot; and &quot;bzip2&quot;.  Default is
+       &quot;none&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+
+The tar task supports nested <a
+href="../CoreTypes/tarfileset.html">tarfileset</a> elements. These are
+extended <a href="../CoreTypes/fileset.html">FileSets</a> which,
+in addition to the standard elements, support one additional
+attributes
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">preserveLeadingSlashes</td>
+    <td valign="top">Indicates whether leading `/'s should
+    be preserved in the file names. Default is <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4>any other resource collection</h4>
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select groups of files to archive.</p>
+<p>Prior to Ant 1.7 only <code>&lt;fileset&gt;</code> has been
+supported as a nested element.</p>
+
+<h3>Examples</h3>
+<pre>
+&lt;tar destfile=&quot;${dist}/manual.tar&quot; basedir=&quot;htdocs/manual&quot;/&gt;
+&lt;gzip destfile=&quot;${dist}/manual.tar.gz&quot; src=&quot;${dist}/manual.tar&quot;/&gt;</pre>
+<p>tars all files in the <code>htdocs/manual</code> directory into a file called <code>manual.tar</code>
+in the <code>${dist}</code>  directory, then applies the gzip task to compress
+it.</p>
+
+<pre>
+&lt;tar destfile=&quot;${dist}/manual.tar&quot;
+     basedir=&quot;htdocs/manual&quot;
+     excludes=&quot;mydocs/**, **/todo.html&quot;
+/&gt;</pre>
+<p>tars all files in the <code>htdocs/manual</code> directory into a file called <code>manual.tar</code>
+in the <code>${dist}</code> directory. Files in the directory <code>mydocs</code>,
+or files with the name <code>todo.html</code> are excluded.</p>
+
+<pre>
+&lt;tar destfile=&quot;${basedir}/docs.tar&quot;&gt;
+  &lt;tarfileset dir=&quot;${dir.src}/docs&quot;
+              fullpath=&quot;/usr/doc/ant/README&quot;
+              preserveLeadingSlashes=&quot;true&quot;&gt;
+    &lt;include name=&quot;readme.txt&quot;/&gt;
+  &lt;/tarfileset&gt;
+  &lt;tarfileset dir=&quot;${dir.src}/docs&quot;
+              prefix=&quot;/usr/doc/ant&quot;
+              preserveLeadingSlashes=&quot;true&quot;&gt;
+    &lt;include name=&quot;*.html&quot;/&gt;
+  &lt;/tarfileset&gt;
+&lt;/tar&gt;</pre>
+<p>
+  Writes the file <code>docs/readme.txt</code> as
+  <code>/usr/doc/ant/README</code> into the archive. All
+  <code>*.html</code> files in the <code>docs</code> directory are
+  prefixed by <code>/usr/doc/ant</code>, so for example
+  <code>docs/index.html</code> is written as
+  <code>/usr/doc/ant/index.html</code> to the archive.
+</p>
+
+<pre>
+&lt;tar longfile=&quot;gnu&quot;
+     destfile=&quot;${dist.base}/${dist.name}-src.tar&quot;&gt;
+  &lt;tarfileset dir=&quot;${dist.name}/..&quot; mode=&quot;755&quot; username=&quot;ant&quot; group=&quot;ant&quot;&gt;
+    &lt;include name=&quot;${dist.name}/bootstrap.sh&quot;/&gt;
+    &lt;include name=&quot;${dist.name}/build.sh&quot;/&gt;
+  &lt;/tarfileset&gt;
+  &lt;tarfileset dir=&quot;${dist.name}/..&quot; username=&quot;ant&quot; group=&quot;ant&quot;&gt;
+    &lt;include name=&quot;${dist.name}/**&quot;/&gt;
+    &lt;exclude name=&quot;${dist.name}/bootstrap.sh&quot;/&gt;
+    &lt;exclude name=&quot;${dist.name}/build.sh&quot;/&gt;
+  &lt;/tarfileset&gt;
+&lt;/tar&gt;
+</pre>
+<p>This example shows building a tar which uses the GNU extensions for long paths and
+where some files need to be marked as executable (mode 755)
+and the rest are use the default mode (read-write by owner). The first
+fileset selects just the executable files. The second fileset must exclude
+the executable files and include all others. </p>
+
+
+
+<p><strong>Note: </strong> The tar task does not ensure that a file is only selected
+by one resource collection. If the same file is selected by more than one collection, it will be included in the
+tar file twice, with the same path.</p>
+
+<p><strong>Note:</strong> The patterns in the include and exclude
+elements are considered to be relative to the corresponding dir
+attribute as with all other filesets.  In the example above,
+<code>${dist.name}</code> is not an absolute path, but a simple name
+of a directory, so <code>${dist.name}</code> is a valid path relative
+to <code>${dist.name}/..</code>.</p>
+
+
+<pre>
+&lt;tar destfile="release.tar.gz" compression="gzip"&gt;
+  &lt;zipfileset src="release.zip"/&gt;
+&lt;/tar&gt;
+</pre>
+<p>Re-packages a ZIP archive as a GZip compressed tar archive.  If
+Unix file permissions have been stored as part of the ZIP file, they
+will be retained in the resulting tar archive.</p>
+
+
+<p><strong>Note:</strong>
+  Please note the tar task creates a tar file, it does not append 
+  to an existing tar file. The existing tar file is replaced instead.
+  As with most tasks in Ant, the task only takes action if the output
+  file (the tar file in this case) is older than the input files, or
+  if the output file does not exist.
+</p>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/taskdef.html b/trunk/docs/manual/CoreTasks/taskdef.html
new file mode 100644
index 0000000..d0b70ae
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/taskdef.html
@@ -0,0 +1,43 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>TaskDef Task</title>
+</head>
+
+<body>
+
+<h2><a name="taskdef">Taskdef</a></h2>
+<h3>Description</h3>
+  <p>Adds a task definition to the current project, such that this new task can be
+    used in the current project.</p>
+  <p>This task is a form of <a href="typedef.html">Typedef</a> with the
+    attributes "adapter" and "adaptto" set to the values 
+    "org.apache.tools.ant.TaskAdapter" and "org.apache.tools.ant.Task"
+    respectively.
+<h3>Examples</h3>
+<pre>  &lt;taskdef name=&quot;myjavadoc&quot; classname=&quot;com.mydomain.JavadocTask&quot;/&gt;</pre>
+<p>makes a task called <code>myjavadoc</code> available to Ant. The class <code>com.mydomain.JavadocTask</code>
+implements the task.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/tempfile.html b/trunk/docs/manual/CoreTasks/tempfile.html
new file mode 100644
index 0000000..dcb55d4
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/tempfile.html
@@ -0,0 +1,231 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Tempfile
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Tempfile
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">This task sets a property to the name of a temporary file.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+          This task sets a property to the name of a temporary file.
+          Unlike <code>java.io.File.createTempFile</code>,
+          this task does not actually create the temporary file, but it does guarantee that the
+          file did not exist when the task was executed.
+
+          <p>Examples:
+
+          <pre>&lt;tempfile property="temp.file"/&gt;</pre>
+
+          create a temporary file
+
+          <pre>&lt;tempfile property="temp.file" suffix=".xml"/&gt;</pre>
+
+          create a temporary file with the <code>.xml</code> suffix
+
+          <pre>&lt;tempfile property="temp.file" destDir="build"/&gt;</pre>
+
+          create a temporary file in the <code>build</code> subdirectory
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+ <!-- Ignore -->
+
+
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">property</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the property you wish to assign the temporary file to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="1">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Required</font>
+        </td>
+    </tr>
+
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the destination directory. If not set, the basedir directory is used instead.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="5">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">prefix</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the optional prefix string for the temp file.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">suffix</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the optional suffix string for the temp file.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">deleteonexit</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Whether the temp file will be marked for deletion on normal exit of the Java Virtual Machine (even though the file may never be created); default <em>false</em>. <strong>Since Ant 1.7</strong></font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">createfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Whether the temp file should be created by this task; default <em>false</em>.<strong>Since Ant 1.8</strong></font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/touch.html b/trunk/docs/manual/CoreTasks/touch.html
new file mode 100644
index 0000000..a3fde3b
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/touch.html
@@ -0,0 +1,145 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Touch Task</title>
+</head>
+
+<body>
+
+<h2><a name="touch">Touch</a></h2>
+<h3>Description</h3>
+
+<p>Changes the modification time of a resource and possibly creates it
+at the same time. In addition to working with a single file, this Task
+can also work on <a href="../CoreTypes/resource.html">resources</a> and
+resource collections (which also includes directories).  Prior to Ant
+1.7 only FileSet or <a href="../CoreTypes/filelist.html">Filelist</a>
+(since Ant 1.6) have been supported.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The name of the file.</td>
+    <td valign="top" align="center">Unless a nested resource collection element
+       has been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">millis</td>
+    <td valign="top">Specifies the new modification time of the file
+       in milliseconds since midnight Jan 1 1970.</td>
+    <td valign="center" align="center" rowspan="2">No--datetime takes
+       precedence, however if both are omitted the current time is assumed.</td>
+  </tr>
+  <tr>
+    <td valign="top">datetime</td>
+    <td valign="top">Specifies the new modification time of the file. The 
+       special value &quot;now&quot; indicates the current time 
+       (now supported since Ant 1.8).</td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">SimpleDateFormat-compatible pattern string.
+       Defaults to MM/DD/YYYY HH:MM AM_or_PM or MM/DD/YYYY HH:MM:SS AM_or_PM.
+       <b>Since Ant 1.6.3</b></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mkdirs</td>
+    <td valign="top">Whether to create nonexistent parent
+       directories when touching new files. <b>Since Ant 1.6.3</b></td>
+    <td valign="top" align="center">No, default <i>false</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to log the creation of new files.
+       <b>Since Ant 1.6.3</b></td>
+    <td valign="top" align="center">No, default <i>true</i>.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>any resource collection</h4>
+
+<p>You can use any number of nested resource collection elements to
+define the resources for this task and refer to resources defined
+elsewhere.  <b>Note:</b> resources passed to this task must implement
+the <code>org.apache.tools.ant.types.resources.Touchable</code>
+interface, this is true for all filesystem-based resources like those
+returned by path, fileset ot filelist.</p>
+
+<p>For backwards compatibility directories matched by nested filesets
+will be "touched" as well, use a &lt;type&gt; selector to suppress
+this.  This only applies to filesets nested into the task directly,
+not to filesets nested into a path or any other resource
+collection.</p>
+
+<h4>mapper</h4>
+<p><em>Since Ant 1.6.3,</em> a nested <a href="../CoreTypes/mapper.html">
+    mapper</a> can be specified.  Files specified via nested
+    <code>fileset</code>s, <code>filelist</code>s, or the <code>file</code>
+    attribute are mapped using the specified mapper.  For each file mapped,
+    the resulting files are touched. If no time has been specified and
+    the original file exists its timestamp will be used.
+    If no time has been specified and the original file does not exist the 
+    current time is used. Since Ant 1.8 the task settings (<code>millis</code>,
+    and <code>datetime</code>) have priority over the timestamp of the original
+    file.</p>
+<h3>Examples</h3>
+<pre>  &lt;touch file=&quot;myfile&quot;/&gt;</pre>
+<p>creates <code>myfile</code> if it doesn't exist and changes the
+modification time to the current time.</p>
+<pre>  &lt;touch file=&quot;myfile&quot; datetime=&quot;06/28/2000 2:02 pm&quot;/&gt;</pre>
+<p>creates <code>myfile</code> if it doesn't exist and changes the
+modification time to Jun, 28 2000 2:02 pm (14:02 for those used to 24
+hour times).</p>
+<pre>  &lt;touch datetime=&quot;09/10/1974 4:30 pm&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;/&gt;
+  &lt;/touch&gt;</pre>
+<p>changes the modification time to Oct, 09 1974 4:30 pm of all files and directories 
+  found in <code>src_dir</code>. </p>
+<pre>  &lt;touch file=&quot;myfile&quot; datetime=&quot;06/28/2000 2:02:17 pm&quot;/&gt;</pre>
+<p>creates <code>myfile</code> if it doesn't exist and changes the
+modification time to Jun, 28 2000 2:02:17 pm (14:02:17 for those used to 24
+hour times), if the filesystem allows a precision of one second - a
+time close to it otherwise.</p>
+<pre>  &lt;touch file=&quot;foo&quot;&gt;
+    &lt;mapper type=&quot;glob&quot; from=&quot;foo&quot; to=&quot;bar&quot; /&gt;
+  &lt;/touch&gt;
+</pre>
+<p>creates <code>bar</code> if it doesn't exist and changes the
+modification time to that of <code>foo</code>.</p>
+
+<pre>  &lt;touch file=&quot;foo&quot; datetime=&quot;now&quot;&gt;
+    &lt;mapper type=&quot;regexp&quot; from=&quot;^src(.*)\.java&quot; to=&quot;shadow\1.empty&quot; /&gt;
+  &lt;/touch&gt;
+</pre>
+<p>creates files in the <code>shadow</code> directory for every java file in the
+   <code>src</code> directory if it doesn't exist and changes the modification
+   time of those files to the current time.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/truncate.html b/trunk/docs/manual/CoreTasks/truncate.html
new file mode 100644
index 0000000..b898517
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/truncate.html
@@ -0,0 +1,109 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Truncate Task</title>
+</head>
+
+<body>
+
+<h2><a name="touch">Truncate</a></h2>
+<h3>Description</h3>
+
+<p>Set the length of one or more files, as the intermittently available
+<code>truncate</code> Unix utility/function. In addition to working with
+a single file, this Task can also work on
+<a href="../CoreTypes/resource.html">resources</a> and resource collections.
+<strong>Since Ant 1.7.1</strong>.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The name of the file.</td>
+    <td valign="top" align="center">Unless a nested resource collection element
+       has been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">length</td>
+    <td valign="top">Specifies the new file length (in bytes) to set.
+                     The following suffixes are supported:
+      <ul>
+        <li>K : Kilobytes (1024 bytes)</li>
+        <li>M : Megabytes (1024 K)</li>
+        <li>G : Gigabytes (1024 M)</li>
+        <li>T : Terabytes (1024 G)</li>
+        <li>P : Petabytes (1024 T)</li>
+      </ul>
+    </td>
+    <td valign="center" align="center" rowspan="2">At most one of these.
+      Omitting both implies <code>length="0"</code>.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">adjust</td>
+    <td valign="top">Specifies the number of bytes
+      (and positive/negative direction)
+      by which to adjust file lengths.  The same suffixes are supported
+      for this attribute as for the <code>length</code> attribute.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">create</td>
+    <td valign="top">Whether to create nonexistent files.</td>
+    <td valign="top" align="center">No, default <i>true</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">mkdirs</td>
+    <td valign="top">Whether to create nonexistent parent
+       directories when creating new files.</td>
+    <td valign="top" align="center">No, default <i>false</i>.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>any resource collection</h4>
+
+<p>You can use any number of nested resource collection elements to
+define the resources for this task and refer to resources defined
+elsewhere.  <b>Note:</b> resources passed to this task are expected
+to be filesystem-based.</p>
+
+<h3>Examples</h3>
+
+<pre>  &lt;truncate file="foo" /&gt;</pre>
+<p>Sets the length of file <code>foo</code> to zero.</p>
+
+<pre>  &lt;truncate file="foo" length="1K" /&gt;</pre>
+<p>Sets the length of file <code>foo</code> to 1 kilobyte (1024 bytes).</p>
+
+<pre>  &lt;truncate file="foo" adjust="1K" /&gt;</pre>
+<p>Adjusts the length of file <code>foo</code> upward by 1 kilobyte.</p>
+
+<pre>  &lt;truncate file="foo" adjust="-1M" /&gt;</pre>
+<p>Adjusts the length of file <code>foo</code> downward by 1 megabyte.</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/tstamp.html b/trunk/docs/manual/CoreTasks/tstamp.html
new file mode 100644
index 0000000..b71516a
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/tstamp.html
@@ -0,0 +1,161 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>TStamp Task</title>
+</head>
+
+<body>
+
+<h2><a name="tstamp">Tstamp</a></h2>
+
+<h3>Description</h3>
+<p>Sets the <code>DSTAMP</code>, <code>TSTAMP</code>, and <code>TODAY</code>
+properties in the current project. By default,
+the <code>DSTAMP</code> property is in the
+format &quot;yyyyMMdd&quot;, <code>TSTAMP</code> is in the
+format &quot;hhmm&quot;, and <code>TODAY</code> is in the
+format &quot;MMMM dd yyyy&quot;. Use the nested <code>&lt;format&gt;</code> element
+to specify a different format.</p>
+
+<p>These properties can be used in the build-file, for instance, to create
+time-stamped filenames, or used to replace placeholder tags inside documents
+to indicate, for example, the release date. The best place for this task is
+probably in an initialization target.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">prefix</td>
+    <td valign="top">Prefix used for all properties set. The default is no prefix.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+The Tstamp task supports a <code>&lt;format&gt;</code> nested element that
+allows a property to be set to the current date and time in a given format.
+The date/time patterns are as defined in the Java
+<a href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html">SimpleDateFormat</a> class.
+The format element also allows offsets to be applied to the time to generate different time values.
+<br><br>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">
+        The property to receive the date/time string in the given pattern.
+    </td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">The date/time pattern to be used. The values are as defined by the Java SimpleDateFormat class.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">timezone</td>
+    <td valign="top">The timezone to use for displaying time. The values are as defined by the Java <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/TimeZone.html">TimeZone</a> class.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">offset</td>
+    <td valign="top">The numeric offset to the current time</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unit</td>
+    <td valign="top">The unit of the offset to be applied to the current time.
+                     Valid Values are
+                     <ul>
+                        <li>millisecond</li>
+                        <li>second</li>
+                        <li>minute</li>
+                        <li>hour</li>
+                        <li>day</li>
+                        <li>week</li>
+                        <li>month</li>
+                        <li>year</li>
+                     </ul>
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">locale</td>
+    <td valign="top">The locale used to create date/time string. The general
+      form is &quot;language, country, variant&quot; but either variant or variant and
+      country may be omitted. For more information please refer to documentation
+      for the
+      <a href="http://java.sun.com/j2se/1.3/docs/api/java/util/Locale.html">Locale</a>
+      class.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+<pre>
+  &lt;tstamp/&gt;
+</pre>
+
+<p>
+sets the standard <code>DSTAMP</code>, <code>TSTAMP</code>,
+and <code>TODAY</code> properties according to the default formats.</p>
+<pre>
+  &lt;tstamp&gt;
+    &lt;format property=&quot;TODAY_UK&quot; pattern=&quot;d-MMMM-yyyy&quot; locale=&quot;en,UK&quot;/&gt;
+  &lt;/tstamp&gt;
+</pre>
+<p>
+sets the standard properties as well as the property
+<code>TODAY_UK</code> with the date/time pattern &quot;d-MMMM-yyyy&quot;
+using English locale (eg. 21-May-2001).</p>
+
+<pre>
+  &lt;tstamp&gt;
+      &lt;format property=&quot;touch.time&quot; pattern=&quot;MM/dd/yyyy hh:mm aa&quot;
+              offset=&quot;-5&quot; unit=&quot;hour&quot;/&gt;
+  &lt;/tstamp&gt;
+</pre>
+<p>
+Creates a timestamp, in the property touch.time, 5 hours before the current time. The format in this example
+is suitable for use with the <code>&lt;touch&gt;</code> task. The standard properties are set also.</p>
+
+<pre>
+  &lt;tstamp prefix="start"/&gt;
+</pre>
+<p>
+Sets three properties with the standard formats, prefixed with "start.":
+<code>start.DSTAMP</code>, <code>start.TSTAMP</code>, and <code>start.TODAY</code>.</p>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/typedef.html b/trunk/docs/manual/CoreTasks/typedef.html
new file mode 100644
index 0000000..4ef69fc
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/typedef.html
@@ -0,0 +1,241 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Typedef Task</title>
+</head>
+
+<body>
+
+<h2><a name="typedef">Typedef</a></h2>
+<h3>Description</h3>
+  <p>
+    Adds a task or a data type definition to the current project
+    such that this new type or task can be used in the current project.
+  </p>
+  <p>
+    A Task is any class that extends org.apache.tools.ant.Task or
+    can be adapted as a Task using an adapter class.
+  </p>
+  <p>
+    Data types are things like <a href="../using.html#path">paths</a> or
+    <a href="../CoreTypes/fileset.html">filesets</a> that can be defined at
+    the project level and referenced via their ID attribute.
+    Custom data types usually need custom tasks to put them to good use.
+  </p>
+  <p>
+    Two attributes are needed to make a definition: the name that
+    identifies this data type uniquely, and the full name of the class
+    (including its package name) that implements this type.
+  </p>
+  <p>
+    You can also define a group of definitions at once using the file or
+    resource attributes.  These attributes point to files in the format of
+    Java property files or an xml format.
+  </p>
+  <p>
+    For property files each line defines a single data type in the
+    format:</p>
+  <pre>
+    typename=fully.qualified.java.classname
+  </pre>
+    
+  <p>
+    The xml format is described in the
+    <a href="../CoreTypes/antlib.html">Antlib</a> section.
+  </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the data type</td>
+    <td valign="top" align="center">Yes, unless the file or resource type
+      attributes have been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the full class name implementing the data type</td>
+    <td valign="top" align="center">Yes, unless file or resource
+      have been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">Name of the file to load definitions from.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">resource</td>
+    <td valign="top">
+      Name of the resource to load definitions from.
+      If multiple resources by this name are found along the classpath,
+      and the format is "properties", the first resource will be loaded;
+      otherwise all such resources will be loaded.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">format</td>
+    <td valign="top">The format of the file or resource. The values
+      are "properties" or "xml". If the value is "properties" the file/resource
+      is a property file contains name to classname pairs. If the value
+      is "xml", the file/resource is an xml file/resource structured according
+      to <a href="../CoreTypes/antlib.html">Antlib</a>.
+      The default is "properties" unless the file/resource name ends with
+      ".xml", in which case the format attribute will have the value "xml".
+      <b>since Ant 1.6</b>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td> <td valign="top">the classpath to
+      use when looking up <code>classname</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">
+      a reference to a classpath to use when looking up <code>classname</code>.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">loaderRef</td>
+    <td valign="top">the name of the loader that is
+      used to load the class, constructed from the specified classpath. Use
+      this to allow multiple tasks/types to be loaded with the same loader,
+      so they can call each other. <b>since Ant 1.5</b> </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">onerror</td>
+    <td valign="top">The action to take if there was a failure in defining the
+      type. The values are <i>fail</i>: cause a build exception; <i>report</i>:
+      output a warning, but continue; <i>ignore</i>: do nothing.
+      <b>since Ant 1.6</b>
+      An additional value is <i>failall</i>: cause all behavior of fail,
+      as well as a build exception for the resource or file attribute
+      if the resource or file is not found. <b>since Ant 1.7</b>
+      The default is <i>fail</i>.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">adapter</td>
+    <td valign="top">A class that is used to adapt the defined class to
+      another interface/class. The adapter class must implement the interface
+      "org.apache.tools.ant.TypeAdapter". The adapter class will be used
+      to wrap the defined class unless the defined class implements/extends
+      the class defined by the attribute "adaptto".
+      If "adaptto" is not set, the defined class will always be wrapped.
+      <b>since Ant 1.6</b>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">adaptto</td>
+    <td valign="top">This attribute is used in conjunction with the
+      adapter attribute.
+      If the defined class does not implement/extend the interface/class
+      specified by this attribute, the adaptor class will be used
+      to wrap the class. <b>since Ant 1.6</b>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">uri</td>
+    <td valign="top">
+      The uri that this definition should live in.
+      <b>since Ant 1.6</b>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+  <h3>Parameters specified as nested elements</h3>
+  <h4>classpath</h4>
+  <p><code>Typedef</code>'s <i>classpath</i> attribute is a 
+    <a href="../using.html#path">path-like structure</a> and can also be set
+    via a nested <i>classpath</i> element.</p>
+
+<h3>Examples</h3>
+  The following fragment defines define a type called <i>urlset</i>.
+  <pre>
+    &lt;typedef name="urlset" classname="com.mydomain.URLSet"/&gt; </pre>
+  The data type is now available to Ant. The
+  class <code>com.mydomain.URLSet</code> implements this type.</p>
+
+
+  <p>
+    Assuming a class <i>org.acme.ant.RunnableAdapter</i> that
+    extends Task and implements <i>org.apache.tools.ant.TypeAdapter</i>,
+    and in the execute method invokes <i>run</i> on the proxied object,
+    one may use a Runnable class as an Ant task. The following fragment
+    defines a task called <i>runclock</i>.
+  </p>
+  <pre>
+    &lt;typedef name="runclock"
+             classname="com.acme.ant.RunClock"
+             adapter="org.acme.ant.RunnableAdapter"/&gt;
+  </pre>
+
+
+  <p>
+    The following fragment shows the use of the classpathref and
+    loaderref to load up two definitions.
+  </p>
+  <pre>
+    &lt;path id="lib.path"&gt;
+      &lt;fileset dir="lib" includes="lib/*.jar"/&gt;
+    &lt;/path&gt;
+
+    &lt;typedef name="filter1"
+             classname="org.acme.filters.Filter1"
+             classpathref="lib.path"
+             loaderref="lib.path.loader"
+             /&gt;
+    &lt;typedef name="filter2"
+             classname="org.acme.filters.Filter2"
+             loaderref="lib.path.loader"
+             /&gt;
+  </pre>
+  
+  
+  <p>
+    If you want to load an antlib into a special xml-namespace, the <tt>uri</tt> attribute
+    is important:
+  </p>
+  <pre>
+  &lt;project xmlns:antcontrib="antlib:net.sf.antcontrib"&gt;
+     &lt;taskdef uri="antlib:net.sf.antcontrib"
+              resource="net/sf/antcontrib/antlib.xml"
+              classpath="path/to/ant-contrib.jar"/&gt;
+  </pre>
+            
+  
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/unpack.html b/trunk/docs/manual/CoreTasks/unpack.html
new file mode 100644
index 0000000..c80bd72
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/unpack.html
@@ -0,0 +1,117 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>GUnzip/BUnzip2 Task</title>
+</head>
+
+<body>
+
+<h2><a name="unpack">GUnzip/BUnzip2</a></h2>
+<h3>Description</h3>
+<p>Expands a resource packed using GZip or BZip2.</p>
+
+<p>If <i>dest</i> is a directory the name of the destination file is
+the same as <i>src</i> (with the &quot;.gz&quot; or &quot;.bz2&quot;
+extension removed if present). If <i>dest</i> is omitted, the parent
+dir of <i>src</i> is taken. The file is only expanded if the source
+resource is newer than the destination file, or when the destination file
+does not exist.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">the file to expand.</td>
+    <td align="center" valign="top">Yes, or a nested resource collection.</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">the destination file or directory.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any <a href="../CoreTypes/resources.html">resource</a> or single element
+resource collection</h4>
+
+<p>The specified resource will be used as src.</p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;gunzip src=&quot;test.tar.gz&quot;/&gt;
+</pre></blockquote>
+<p>expands <i>test.tar.gz</i> to <i>test.tar</i></p>
+<blockquote><pre>
+&lt;bunzip2 src=&quot;test.tar.bz2&quot;/&gt;
+</pre></blockquote>
+<p>expands <i>test.tar.bz2</i> to <i>test.tar</i></p>
+<blockquote><pre>
+&lt;gunzip src=&quot;test.tar.gz&quot; dest=&quot;test2.tar&quot;/&gt;
+</pre></blockquote>
+<p>expands <i>test.tar.gz</i> to <i>test2.tar</i></p>
+<blockquote><pre>
+&lt;gunzip src=&quot;test.tar.gz&quot; dest=&quot;subdir&quot;/&gt;
+</pre></blockquote>
+<p>expands <i>test.tar.gz</i> to <i>subdir/test.tar</i> (assuming
+subdir is a directory).</p>
+<blockquote><pre>
+&lt;gunzip dest=&quot;.&quot;&gt;
+  &lt;url url="http://example.org/archive.tar.gz"/&gt;
+&lt;/gunzip&gt;
+</pre></blockquote>
+<p>downloads <i>http://example.org/archive.tar.gz</i> and expands it
+to <i>archive.tar</i> in the project's basedir on the fly.</p>
+
+<h3>Related tasks</h3>
+
+<pre>
+&lt;gunzip src="some-archive.gz" dest="some-dest-dir"/&gt;
+</pre>
+
+is identical to
+
+<pre>
+&lt;copy todir="some-dest-dir"&gt;
+  &lt;gzipresource&gt;
+    &lt;file file="some-archive.gz"/&gt;
+  &lt;/gzipresource&gt;
+  &lt;mapper type="glob" from="*.gz" to="*"/&gt;
+&lt;/copy&gt;
+</pre>
+
+<p>The same is also true for <code>&lt;bunzip2&gt;</code> and
+<code>&lt;bzip2resource&gt;</code>.  <code>&lt;copy&gt;</code> offers
+additional features like <a
+href="../CoreTypes/filterchains.html">filtering files</a> on the fly,
+allowing a file to be mapped to multiple destinations, preserving the
+last modified time or a configurable file system timestamp
+granularity.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/untar.html b/trunk/docs/manual/CoreTasks/untar.html
new file mode 100644
index 0000000..bfaf28f
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/untar.html
@@ -0,0 +1,35 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Untar Task</title>
+</head>
+
+<body>
+
+<h2><a name="untar">Untar</a></h2>
+<h3>Description</h3>
+<p>Untars a tarfile.</p>
+
+This document has moved <A HREF="unzip.html">here</A>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/unzip.html b/trunk/docs/manual/CoreTasks/unzip.html
new file mode 100644
index 0000000..ff395e3
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/unzip.html
@@ -0,0 +1,178 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Unzip Task</title>
+</head>
+
+<body>
+
+<h2><a name="unzip">Unjar/Untar/Unwar/Unzip</a></h2>
+<h3>Description</h3>
+<p>Unzips a zip-, war-, or jar file.</p>
+<p><a href="../CoreTypes/patternset.html">PatternSet</a>s are used to select files to extract
+<I>from</I> the archive.  If no patternset is used, all files are extracted.
+</p>
+
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s may be used to select archived files to perform
+unarchival upon.  Only file system based resource collections are
+supported by Unjar/Unwar/Unzip, this includes <a
+href="../CoreTypes/fileset.html">fileset</a>, <a
+href="../CoreTypes/filelist.html">filelist</a>, <a
+href="../using.html#path">path</a>, and <a
+href="../CoreTypes/resources.html#files">files</a>.
+Untar supports arbitrary resource collections.
+Prior to Ant 1.7 only fileset has been supported as a nested element.</p>
+
+<p>You can define filename transformations by using a nested <a href="../CoreTypes/mapper.html">mapper</a> element.  The default mapper is the
+<a href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a>.
+</p>
+<p>File permissions will not be restored on extracted files.</p>
+<p>The untar task recognizes the long pathname entries used by GNU tar.<p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">archive file to expand.</td>
+    <td align="center" valign="top">Yes, if filesets are not used.</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">directory where to store the expanded files.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">overwrite</td>
+    <td valign="top">Overwrite files, even if they are newer than the
+      corresponding entries in the archive (true or false, default is
+      true).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compression</td>
+    <td valign="top"><b>Note:</b> This attribute is only available for
+    the <code>untar</code> task.<br>
+    compression method.  Allowable values are &quot;none&quot;,
+    &quot;gzip&quot; and &quot;bzip2&quot;.  Default is
+    &quot;none&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top"><b>Note:</b> This attribute is not available for
+    the <code>untar</code> task.<br>
+    The character encoding that has been used for filenames
+    inside the zip file.  For a list of possible values see <a
+    href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.<br>
+    Defaults to &quot;UTF8&quot;, use the magic value
+    <code>native-encoding</code> for the platform's default character
+    encoding.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;unzip src=&quot;${tomcat_src}/tools-src.zip&quot; dest=&quot;${tools.home}&quot;/&gt;
+</pre>
+<p>
+<pre>
+&lt;gunzip src=&quot;tools.tar.gz&quot;/&gt;
+&lt;untar src=&quot;tools.tar&quot; dest=&quot;${tools.home}&quot;/&gt;
+</pre>
+<pre>
+&lt;unzip src=&quot;${tomcat_src}/tools-src.zip&quot;
+       dest=&quot;${tools.home}&quot;&gt;
+    &lt;patternset&gt;
+        &lt;include name=&quot;**/*.java&quot;/&gt;
+        &lt;exclude name=&quot;**/Test*.java&quot;/&gt;
+    &lt;/patternset&gt;
+&lt;/unzip&gt;
+</pre>
+<p>
+<pre>
+&lt;unzip dest=&quot;${tools.home}&quot;&gt;
+    &lt;patternset&gt;
+        &lt;include name=&quot;**/*.java&quot;/&gt;
+        &lt;exclude name=&quot;**/Test*.java&quot;/&gt;
+    &lt;/patternset&gt;
+    &lt;fileset dir=&quot;.&quot;&gt;
+        &lt;include name=&quot;**/*.zip&quot;/&gt;
+        &lt;exclude name=&quot;**/tmp*.zip&quot;/&gt;
+    &lt;/fileset&gt;
+&lt;/unzip&gt;
+</pre>
+<p>
+<pre>
+&lt;unzip src=&quot;apache-ant-bin.zip&quot; dest=&quot;${tools.home}&quot;&gt;
+    &lt;patternset&gt;
+        &lt;include name=&quot;apache-ant/lib/ant.jar&quot;/&gt;
+    &lt;/patternset&gt;
+    &lt;mapper type=&quot;flatten&quot;/&gt;
+&lt;/unzip&gt;
+</pre>
+
+<h3>Related tasks</h3>
+
+<pre>
+&lt;unzip src="some-archive" dest="some-dir"&gt;
+  &lt;patternset&gt;
+    &lt;include name="some-pattern"/&gt;
+  &lt;/patternset&gt;
+  &lt;mapper type=&quot;some-mapper&quot;/&gt;
+&lt;/unzip&gt;
+</pre>
+
+is identical to
+
+<pre>
+&lt;copy todir="some-dir" preservelastmodified="true"&gt;
+  &lt;zipfileset src="some-archive"&gt;
+    &lt;patternset&gt;
+      &lt;include name="some-pattern"/&gt;
+    &lt;/patternset&gt;
+  &lt;/zipfileset&gt;
+  &lt;mapper type=&quot;some-mapper&quot;/&gt;
+&lt;/copy&gt;
+</pre>
+
+<p>The same is also true for <code>&lt;untar&gt;</code> and
+<code>&lt;tarfileset&gt;</code>.  <code>&lt;copy&gt;</code> offers
+additional features like <a href="../CoreTypes/filterchain.html">filtering files</a> on the fly,
+allowing a file to be mapped to multiple destinations or a
+configurable file system timestamp granularity.</p>
+
+<pre>&lt;zip destfile=&quot;new.jar&quot;&gt;
+  &lt;zipfileset src=&quot;old.jar&quot;&gt;
+    &lt;exclude name=&quot;do/not/include/this/class&quot;/&gt;
+  &lt;/zipfileset&gt;
+&lt;/zip&gt;
+</pre>
+<p>&quot;Deletes&quot; files from a zipfile.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/uptodate.html b/trunk/docs/manual/CoreTasks/uptodate.html
new file mode 100644
index 0000000..bfc95aa
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/uptodate.html
@@ -0,0 +1,171 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Uptodate Task</title>
+</head>
+
+<body>
+
+<h2><a name="uptodate">Uptodate</a></h2>
+<h3>Description</h3>
+<p>Sets a property if a target file or set of target files is more up-to-date
+than a source file or set of source files. A single source file is specified
+using the <code>srcfile</code> attribute. A set of source files is specified
+using the nested <code>&lt;srcfiles&gt;</code>
+elements. These are <a href="../CoreTypes/fileset.html">FileSet</a>s,
+whereas multiple target files are specified using a nested
+<a href="../CoreTypes/mapper.html"><code>&lt;mapper&gt;</code></a> element.</p>
+<p>By default, the value of the property is set to <code>true</code> if
+the timestamp of the source file(s) is not more recent than the timestamp of
+the corresponding target file(s). You can set the value to something other
+than the default by specifying the <code>value</code> attribute.</p>
+<p>If a <code>&lt;srcfiles&gt;</code> element is used, without also specifying
+a <code>&lt;mapper&gt;</code> element, the default behavior is to use a
+<a href="../CoreTypes/mapper.html#merge-mapper">merge mapper</a>, with the
+<code>to</code> attribute set to the value of the
+<code>targetfile</code> attribute.</p>
+<p>Normally, this task is used to set properties that are useful to avoid
+target execution depending on the relative age of the specified files.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of the property to set.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The value to set the property to.</td>
+    <td valign="top" align="center">No; defaults to <code>true</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">srcfile</td>
+    <td valign="top">The file to check against the target file(s).</td>
+    <td valign="top" align="center">Yes, unless a nested
+    <code>&lt;srcfiles&gt;</code> or <code>&lt;srcresources&gt;</code>
+    element is present.</td>
+  </tr>
+  <tr>
+    <td valign="top">targetfile</td>
+    <td valign="top">The file for which we want to determine the status.</td>
+    <td valign="top" align="center">Yes, unless a nested
+      <code>&lt;mapper&gt;</code> element is present.</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<h4><a name="srcfiles">srcfiles</a></h4>
+<p>The nested <code>&lt;srcfiles&gt;</code> element allows you to specify a
+set of files to check against the target file(s).</p>
+
+<p><strong>Note:</strong> You can specify either the <code>srcfile</code>
+attribute or nested <code>&lt;srcfiles&gt;</code> elements, but not both.
+
+<h4><a name="srcresources">srcresources</a></h4>
+<p>The nested <code>&lt;srcresources&gt;</code> element is a <a
+href="../CoreTypes/resources.html#union">union</a> and allows you to
+specify a collection of resources to check against the target file(s).
+<em>Since Ant 1.7</em></p>
+
+<h4><a name="mapper">mapper</a></h4>
+<p>The nested <code>&lt;mapper&gt;</code> element allows you to specify
+a set of target files to check for being up-to-date with respect to a
+set of source files.</p>
+   <p>
+      The mapper "to" attribute is relative to the target file, or to
+      the "dir" attribute of the nested srcfiles element.
+   </p>
+  <p>
+    <em>Since Ant 1.6.3</em>,
+    one can use a filenamemapper type in place of the mapper element.
+  </p>
+<h3>Examples</h3>
+<pre>  &lt;uptodate property=&quot;xmlBuild.notRequired&quot; targetfile=&quot;${deploy}\xmlClasses.jar&quot; &gt;
+    &lt;srcfiles dir= &quot;${src}/xml&quot; includes=&quot;**/*.dtd&quot;/&gt;
+  &lt;/uptodate&gt;</pre>
+<p>sets the property <code>xmlBuild.notRequired</code> to <code>true</code>
+if the <code>${deploy}/xmlClasses.jar</code> file is more up-to-date than
+any of the DTD files in the <code>${src}/xml</code> directory.</p>
+<p>This can be written as:</p>
+<pre>  &lt;uptodate property=&quot;xmlBuild.notRequired&quot;&gt;
+    &lt;srcfiles dir= &quot;${src}/xml&quot; includes=&quot;**/*.dtd&quot;/&gt;
+    &lt;mapper type=&quot;merge&quot; to=&quot;${deploy}\xmlClasses.jar&quot;/&gt;
+  &lt;/uptodate&gt;</pre>
+as well.
+
+The <code>xmlBuild.notRequired</code> property can then be used in a
+<code>&lt;target&gt;</code> tag's <code>unless</code> attribute to
+conditionally run that target. For example, running the following target:</p>
+<pre>
+&lt;target name=&quot;xmlBuild&quot; depends=&quot;chkXmlBuild&quot; unless=&quot;xmlBuild.notRequired&quot;&gt;
+  ...
+&lt;/target&gt;
+</pre>
+will first run the <code>chkXmlBuild</code> target, which contains
+the <code>&lt;uptodate&gt;</code> task that determines whether
+<code>xmlBuild.notRequired</code> gets set. The property named in
+the <code>unless</code> attribute is then checked for being set/not set.
+If it did get set (ie., the jar file is up-to-date),
+then the <code>xmlBuild</code> target won't be run.
+</p>
+
+<p> The following example shows a single source file being checked
+against a single target file:</p>
+<pre>  &lt;uptodate property=&quot;isUpToDate&quot;
+            srcfile=&quot;/usr/local/bin/testit&quot;
+            targetfile=&quot;${build}/.flagfile&quot;/&gt;
+</pre>
+<p>sets the property <code>isUpToDate</code> to <code>true</code>
+if <code>/usr/local/bin/testit</code> is not newer than
+<code>${build}/.flagfile</code>.</p>
+</p>
+  <p>
+    The following shows usage of a relative mapper.
+  </p>
+  <pre>
+    &lt;uptodate property="checkUptodate.uptodate"&gt;
+      &lt;srcfiles dir="src" includes="*"/&gt;
+      &lt;mapper type="merge" to="../dest/output.done"/&gt;
+    &lt;/uptodate&gt;
+    &lt;echo message="checkUptodate result: ${checkUptodate.uptodate}"/&gt;
+  </pre>
+  <p>
+    The previous example can be a bit confusing, so it may be better to
+    use absolute paths:
+  </p>
+  <pre>
+    &lt;property name="dest.dir" location="dest"/&gt;
+    &lt;uptodate property="checkUptodate.uptodate"&gt;
+      &lt;srcfiles dir="src" includes="*"/&gt;
+      &lt;mapper type="merge" to="${dest.dir}/output.done"/&gt;
+    &lt;/uptodate&gt;
+  </pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/waitfor.html b/trunk/docs/manual/CoreTasks/waitfor.html
new file mode 100644
index 0000000..54ff8ed
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/waitfor.html
@@ -0,0 +1,133 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>WaitFor Task</title>
+</head>
+
+<body>
+
+<h2>Waitfor</h2>
+<h3>Description</h3>
+<p>Blocks execution until a set of specified conditions become true. This is intended
+  to be used with the <a href="parallel.html">parallel</a> task to
+  synchronize a set of processes.</p>
+<p>The conditions to wait for are defined in <a href="waitfor.html#nested">nested elements</a>,
+if multiple conditions are specified, then the task will wait until all conditions are true..</p>
+<p></p>
+<p>If both maxwait and maxwaitunit are not specified, the maxwait is 3 minutes (180000 milliseconds).</p>
+<p>If the <code>timeoutproperty</code> attribute has been set, a
+property of that name will be created if the condition didn't come
+true within the specified time.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">maxwait</td>
+    <td valign="top">The maximum amount of time to wait for all the required conditions
+      to become true before failing the task. Defaults to 180000 maxwaitunits.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">maxwaitunit</td>
+    <td valign="top">The unit of time that must be used to interpret the value of the
+    maxwait attribute.  Defaults to millisecond.
+                     Valid Values are
+                     <ul>
+                        <li>millisecond</li>
+                        <li>second</li>
+                        <li>minute</li>
+                        <li>hour</li>
+                        <li>day</li>
+                        <li>week</li>
+                     </ul>
+      </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">checkevery</td>
+    <td valign="top">The amount of time to wait between each test of the conditions.
+      Defaults to 500 checkeveryunits.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">checkeveryunit</td>
+    <td valign="top">The unit of time that must be used to interpret the value of the
+    checkevery attribute.  Defaults to millisecond.
+                     Valid Values are
+                     <ul>
+                        <li>millisecond</li>
+                        <li>second</li>
+                        <li>minute</li>
+                        <li>hour</li>
+                        <li>day</li>
+                        <li>week</li>
+                     </ul>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timeoutproperty</td>
+    <td valign="top">the name of the property to set if maxwait has
+      been exceeded.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3><a name="nested">Nested Elements</a></h3>
+
+<p>The available conditions that satisfy the
+<code>&lt;waitfor&gt;</code> task are the same as those for the
+<a href="condition.html"><code>&lt;condition&gt;</code></a> task. See
+<a href="conditions.html">here</a> for the full list.</p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;waitfor maxwait="30" maxwaitunit="second"&gt;
+        &lt;available file="errors.log"/&gt;
+&lt;/waitfor&gt;
+</pre></blockquote>
+<p>waits up to 30 seconds for a file called errors.log to appear.</p>
+<blockquote><pre>
+&lt;waitfor maxwait="3" maxwaitunit="minute" checkevery="500"&gt;
+        &lt;http url="http://localhost/myapp/index.html"/&gt;
+&lt;/waitfor&gt;
+</pre></blockquote>
+<p>waits up to 3 minutes (and checks every 500 milliseconds) for a web server on localhost
+  to serve up the specified URL.</p>
+<blockquote><pre>
+&lt;waitfor maxwait="10" maxwaitunit="second"&gt;
+        &lt;and&gt;
+            &lt;socket server="dbserver" port="1521"/&gt;
+            &lt;http url="http://webserver/mypage.html"/&gt;
+        &lt;/and&gt;
+&lt;/waitfor&gt;
+</pre></blockquote>
+<p>waits up to 10 seconds for a server on the dbserver machine to begin listening
+  on port 1521 and for the http://webserver/mypage.html web page
+  to become available.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTasks/war.html b/trunk/docs/manual/CoreTasks/war.html
new file mode 100644
index 0000000..bd2b5a7
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/war.html
@@ -0,0 +1,290 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>WAR Task</title>
+</head>
+
+<body>
+
+<h2><a name="war">War</a></h2>
+<h3>Description</h3>
+<p>An extension of the <a href="jar.html">Jar</a> task with special
+treatment for files that should end up in the
+<code>WEB-INF/lib</code>, <code>WEB-INF/classes</code> or
+<code>WEB-INF</code> directories of the Web Application Archive.</p>
+<p>(The War task is a shortcut for specifying the particular layout of a WAR file.
+The same thing can be accomplished by using the <i>prefix</i> and <i>fullpath</i>
+attributes of zipfilesets in a Zip or Jar task.)</p>
+<p>The extended zipfileset element from the zip task
+    (with attributes <i>prefix</i>, <i>fullpath</i>, and <i>src</i>)
+    is available in the War task. The task is also resource-enabled
+    and will add nested resources and resource collections to the archive.</p>
+
+<p>
+    Before Servlet API 2.5/Java EE 5, a WEB-INF/web.xml file was mandatory in a
+    WAR file, so this task failed if the <code>webxml</code> attribute was missing.
+    As the web.xml file is now optional, the <code>webxml</code> attribute may now
+    be made optional. However, as most real web applications do need a web.xml file,
+    it is not optional by default. The task will fail if the file is not
+    included, unless the <code>needxmlfile</code> attribute
+    is set to <code>true</code>. The task
+    will warn if more than one web.xml file is added to the JAR  
+    through the filesets.
+</p>
+
+
+<p><b>Please note that the Zip format allows multiple files of the same
+fully-qualified name to exist within a single archive.  This has been
+documented as causing various problems for unsuspecting users.  If you wish
+to avoid this behavior you must set the <code>duplicate</code> attribute
+to a value other than its default, <code>&quot;add&quot;</code>.</b></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the WAR file to create.</td>
+    <td align="center" valign="top" rowspan="2">Exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">warfile</td>
+    <td valign="top"><i>Deprecated</i> name of the file to create
+    -use <tt>destfile</tt> instead.</td>
+  </tr>
+  <tr>
+    <td valign="top">webxml</td>
+    <td valign="top">The servlet configuration descriptor to use (WEB-INF/web.xml).</td>
+    <td valign="top" align="center">Yes, unless <tt>needxmlfile</tt> is true,
+    the file is pulled in via a nested fileset, or an existing WAR file is
+    being updated.</td>
+  </tr>
+  <tr>
+    <td valign="top">needxmlfile</td>
+    <td valign="top">Flag to indicate whether or not the web.xml file is needed.
+        I=it should be set to false when generating
+        servlet 2.5+ WAR files without a web.xml file.
+        <em>Since Ant 1.7</em></td>
+    <td valign="top" align="center">No -default "true"</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory from which to jar the files.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compress</td>
+    <td valign="top">Not only store data but also compress them,
+    defaults to true.  Unless you set the <em>keepcompression</em>
+    attribute to false, this will apply to the entire archive, not
+    only the files you've added while updating.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepcompression</td>
+    <td valign="top">For entries coming from existing archives (like
+    nested <em>zipfileset</em>s or while updating the archive), keep
+    the compression as it has been originally instead of using the
+    <em>compress</em> attribute.  Defaults false.  <em>Since Ant
+    1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The character encoding to use for filenames
+      inside the archive.  Defaults to UTF8. <strong>It is not
+      recommended to change this value as the created archive will most
+      likely be unreadable for Java otherwise.</strong></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesonly</td>
+    <td valign="top">Store only file entries, defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">manifest</td>
+    <td valign="top">the manifest file to use.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesetmanifest</td>
+    <td valign="top">behavior when a Manifest is found in a zipfileset or zipgroupfileset file is found.  Valid values are &quot;skip&quot;, &quot;merge&quot;, and &quot;mergewithoutmain&quot;.  &quot;merge&quot; will merge all of the manifests together, and merge this into any other specified manifests.  &quot;mergewithoutmain&quot; merges everything but the Main section of the manifests.  Default value is &quot;skip&quot;.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">whenmanifestonly</td>
+    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;create&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">update</td>
+    <td valign="top">indicates whether to update or overwrite
+      the destination file if it already exists.  Default is &quot;false&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">duplicate</td>
+    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;.  The default value is &quot;add&quot;.  </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">roundup</td>
+    <td valign="top">Whether the file modification times will be
+    rounded up to the next even number of seconds.<br>
+    Zip archives store file modification times with a granularity of
+    two seconds, so the times will either be rounded up or down.  If
+    you round down, the archive will always seem out-of-date when you
+    rerun the task, so the default is to round up.  Rounding up may
+    lead to a different type of problems like JSPs inside a web
+    archive that seem to be slightly more recent than precompiled
+    pages, rendering precompilation useless.<br>
+    Defaults to true.  <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">level</td>
+    <td valign="top">Non-default level at which file compression should be
+    performed. Valid values range from 0 (no compression/fastest) to 9
+    (maximum compression/slowest). <em>Since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested elements</h3>
+
+<h4>lib</h4>
+<p>The nested <code>lib</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>WEB-INF/lib</code> directory of the war file.</p>
+
+<h4>classes</h4>
+<p>The nested <code>classes</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>WEB-INF/classes</code> directory of the war file.</p>
+
+<h4>webinf</h4>
+<p>The nested <code>webinf</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>WEB-INF</code> directory of the war file. If this
+fileset includes a file named <code>web.xml</code>, the file is
+ignored and you will get a warning.</p>
+
+<h4>metainf</h4>
+<p>The nested <code>metainf</code> element specifies a <a
+href="../CoreTypes/fileset.html">FileSet</a>. All files included in this fileset will
+end up in the <code>META-INF</code> directory of the war file. If this
+fileset includes a file named <code>MANIFEST.MF</code>, the file is
+ignored and you will get a warning.</p>
+
+<h4>manifest, indexjars, service</h4>
+These are inherited from <a href="jar.html">&lt;jar&gt;</a>
+
+<h3>Examples</h3>
+
+<p>Assume the following structure in the project's base directory:</p>
+<pre>
+thirdparty/libs/jdbc1.jar
+thirdparty/libs/jdbc2.jar
+build/main/com/myco/myapp/Servlet.class
+src/metadata/myapp.xml
+src/html/myapp/index.html
+src/jsp/myapp/front.jsp
+src/graphics/images/gifs/small/logo.gif
+src/graphics/images/gifs/large/logo.gif
+</pre>
+then the war file <code>myapp.war</code> created with
+<pre>
+&lt;war destfile=&quot;myapp.war&quot; webxml=&quot;src/metadata/myapp.xml&quot;&gt;
+  &lt;fileset dir=&quot;src/html/myapp&quot;/&gt;
+  &lt;fileset dir=&quot;src/jsp/myapp&quot;/&gt;
+  &lt;lib dir=&quot;thirdparty/libs&quot;&gt;
+    &lt;exclude name=&quot;jdbc1.jar&quot;/&gt;
+  &lt;/lib&gt;
+  &lt;classes dir=&quot;build/main&quot;/&gt;
+  &lt;zipfileset dir=&quot;src/graphics/images/gifs&quot;
+              prefix=&quot;images&quot;/&gt;
+&lt;/war&gt;
+</pre>
+will consist of
+<pre>
+WEB-INF/web.xml
+WEB-INF/lib/jdbc2.jar
+WEB-INF/classes/com/myco/myapp/Servlet.class
+META-INF/MANIFEST.MF
+index.html
+front.jsp
+images/small/logo.gif
+images/large/logo.gif
+</pre>
+using Ant's default manifest file. The content of
+<code>WEB-INF/web.xml</code> is identical to
+<code>src/metadata/myapp.xml</code>.
+
+<p>We regulary receive bug reports that this task is creating the WEB-INF
+directory, and thus it is our fault your webapp doesn't work. The cause
+of these complaints lies in WinZip, which turns an all upper-case
+directory into an all lower case one in a fit of helpfulness. Please check that
+<code>jar xvf yourwebapp.war</code> shows the same behaviour before filing another
+report.<br/>
+Winzip has an option allowing all uppercase names (which is off by default!).  It can be enabled by:
+Menu "Options" -> "Configuration",  "View" property/tab page, then "General" group box has an option called "Allow all uppercase file names".
+</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/whichresource.html b/trunk/docs/manual/CoreTasks/whichresource.html
new file mode 100644
index 0000000..d5e62e0
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/whichresource.html
@@ -0,0 +1,120 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us">
+      <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+        <title>Whichresource Task</title>
+      </link>
+    </meta>
+  </head>
+
+
+  <body>
+    <h2><a name="whichresource">Whichresource</a></h2>
+    <h3>Description</h3>
+    <p>
+      Find a class or resource on the supplied classpath, or the
+      system classpath if none is supplied.
+      The named property is set if the item can be found.
+      For example:
+    </p>
+<blockquote><pre>
+  &lt;whichresource resource="/log4j.properties" property="log4j.url" &gt;
+</pre></blockquote>
+    <h3>Parameters</h3>
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">property</td>
+        <td valign="top">
+          The property to fill with the URL of the resource of class.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">class</td>
+        <td valign="top">
+          The name of the class to look for.
+        </td>
+        <td valign="top" align="center" rowspan="2">Exactly one of these.</td>
+      </tr>
+      <tr>
+        <td valign="top">resource</td>
+        <td valign="top">
+          The name of the resource to look for.
+        </td>
+      </tr>
+      <tr>
+        <td valign="top">classpath</td>
+        <td valign="top">
+          The classpath to use when looking up <code>class</code>
+          or <code>resource</code>.
+        </td>
+        <td align="center" valign="top">No</td>
+      </tr>
+      <tr>
+        <td valign="top">classpathref</td>
+        <td valign="top">
+          The classpath to use, given as a
+          <a href="../using.html#references">reference</a>
+          to a path defined elsewhere.
+          <em>Since Ant 1.7.1.</em>
+        </td>
+        <td align="center" valign="top">No</td>
+      </tr>
+    </table>
+    <h3>Parameters specified as nested elements</h3>
+    <h4>classpath</h4>
+    <p>
+      <code>Whichresource</code>'s <code>classpath</code> attribute is a
+      <a href="../using.html#path">path-like structure</a> and can also be
+      set via a nested <code>&lt;classpath&gt;</code> element.
+    </p>
+    <h3>Examples</h3>
+    <p>
+      The following shows using a classpath reference.
+    </p>
+<blockquote><pre>
+  &lt;path id="bsf.classpath"&gt;
+    &lt;fileset dir="${user.home}/lang/bsf" includes="*.jar"/&gt;
+  &lt;/path&gt;
+  &lt;whichresource property="bsf.class.location"
+                 class="org.apache.bsf.BSFManager"
+                 classpathref="bsf.classpath"/&gt;
+  &lt;echo&gt;${bsf.class.location}&lt;/echo&gt;
+</pre></blockquote>
+    <p>
+      The following shows using a nested classpath.
+    </p>
+<blockquote><pre>
+  &lt;whichresource
+    property="ant-contrib.antlib.location"
+    resource="net/sf/antcontrib/antlib.xml"&gt;
+    &lt;classpath&gt;
+      &lt;path path="f:/testing/ant-contrib/target/ant-contrib.jar"/&gt;
+    &lt;/classpath&gt;
+  &lt;/whichresource&gt;
+  &lt;echo&gt;${ant-contrib.antlib.location}&lt;/echo&gt;
+</pre></blockquote>
+  </body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/xmlproperty.html b/trunk/docs/manual/CoreTasks/xmlproperty.html
new file mode 100644
index 0000000..32b990e
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/xmlproperty.html
@@ -0,0 +1,289 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>XmlProperty Task</title>
+</head>
+
+<body>
+
+<h2><a name="xmlproperty">XmlProperty</a></h2>
+<h3>Description</h3>
+<p>
+Loads property values from a well-formed xml file. There are no other restrictions
+than "well-formed". You can choose the layout you want. For example this XML property file:
+<pre>
+  &lt;root&gt;
+    &lt;properties&gt;
+      &lt;foo&gt;bar&lt;/foo&gt;
+    &lt;/properties&gt;
+  &lt;/root&gt;
+</pre>
+is roughly equivalent to this Java property file:
+<pre>
+  root.properties.foo = bar
+</pre>
+
+<p>
+By default, this load
+does <em>no</em> processing of the input.  In particular, unlike the
+<a href="property.html">Property task</a>, property references
+(i.e., <samp>${foo}</samp>) are not resolved.
+<p>
+<a name="semanticAttributes">
+<h3>Semantic Attributes</h3>
+</a>
+Input processing can be enabled by using the <b>semanticAttributes</b>
+attribute.  If this attribute is set to <i>true</i> (its default is
+<i>false</i>), the following processing occurs as the input XML file
+is loaded:
+<ul>
+  <li>Property references are resolved.</li>
+  <li>The following attributes are treated differently:
+    <ul>
+      <li><b>id</b>: The property is associated with the given id value.</li>
+      <li><b>location</b>: The property is treated as a file location</li>
+      <li><b>refid</b>: The property is set to the value of the
+          referenced property.</li>
+      <li><b>value</b>: The property is set to the value indicated.</li>
+    </ul>
+  </li>
+  <li><a href="../using.html#path">Path-like Structures</a> can be defined
+      by use of the following attributes:
+    <ul>
+      <li><b>pathid</b>: The given id is used to identify a path.  The
+          nested XML tag name is ignored.  Child elements can be used
+          (XML tag names are ignored) to identify elements of the path.</li>
+    </ul>
+  </li>
+</ul>
+<p>
+For example, with semantic attribute processing enabled, this XML property
+file:
+<pre>
+  &lt;root&gt;
+    &lt;properties&gt;
+      &lt;foo location="bar"/&gt;
+      &lt;quux&gt;${root.properties.foo}&lt;/quux&gt;
+    &lt;/properties&gt;
+  &lt;/root&gt;
+</pre>
+is roughly equivalent to the following fragments in a build.xml file:
+<pre>
+  &lt;property name="root.properties.foo" location="bar"/&gt;
+  &lt;property name="root.properties.quux" value="${root.properties.foo}"/&gt;
+</pre>
+
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The XML file to parse.</td>
+    <td valign="top" align="center">Yes, or a nested resource collection.</td>
+  </tr>
+  <tr>
+    <td valign="top">prefix</td>
+    <td valign="top">The prefix to prepend to each property</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepRoot</td>
+    <td valign="top">Keep the xml root tag as the
+                     first value in the property name.</td>
+    <td valign="top" align="center">No, default is <i>true</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">validate</td>
+    <td valign="top">Validate the input file (e.g. by a DTD). Otherwise the XML must only be well-formed.</td>
+    <td valign="top" align="center">No, default is <i>false</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">collapseAttributes</td>
+    <td valign="top">Treat attributes as nested elements.</td>
+    <td valign="top" align="center">No, default is <i>false</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">semanticAttributes</td>
+    <td valign="top">Enable special handling of certain attribute names.
+                     See the <a href="#semanticAttributes">Semantic Attributes</a>
+                     section for more information.</td>
+    <td valign="top" align="center">No, default is <i>false</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">includeSemanticAttribute</td>
+    <td valign="top">Include the semantic attribute name
+                     as part of the property name.  Ignored if
+                     <i>semanticAttributes</i> is not set to <i>true</i>.
+                     See the <a href="#semanticAttributes">Semantic Attributes</a>
+                     section for more information.</td>
+    <td valign="top" align="center">No, default is <i>false</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">rootDirectory</td>
+    <td valign="top">The directory to use for resolving file references. Ignored
+                     if <i>semanticAttributes</i> is not set to <i>true</i>.</td>
+    <td valign="top" align="center">No, default is <i>${basedir}</i>.</td>
+  </tr>
+  <tr>
+    <td valign="top">delimiter</td>
+    <td valign="top">Delimiter for splitting multiple values.<br><i>since Ant 1.7.1</i></td>
+    <td valign="top" align="center">No, defaults to comma</td>
+  </tr>
+</table>
+
+<h3><a name="nested">Nested Elements</a></h3>
+<h4>xmlcatalog</h4>
+<p>The <a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a>
+element is used to perform entity resolution.</p>
+
+<h4>any <a href="../CoreTypes/resources.html">resource</a> or single element
+resource collection</h4>
+
+<p>The specified resource will be used as input.</p>
+
+<a name="examples">
+<h3>Examples</h3>
+</a>
+
+<h4>Non-semantic Attributes</h4>
+
+<p>Here is an example xml file that does not have any semantic attributes.</p>
+
+<pre>
+   &lt;root-tag myattr="true"&gt;
+    &lt;inner-tag someattr="val"&gt;Text&lt;/inner-tag&gt;
+    &lt;a2&gt;&lt;a3&gt;&lt;a4&gt;false&lt;/a4&gt;&lt;/a3&gt;&lt;/a2&gt;
+   &lt;/root-tag&gt;
+</pre>
+
+<h5>default loading</h5>
+<p>This entry in a build file:
+<pre>   &lt;xmlproperty file="somefile.xml"/&gt;</pre>
+is equivalent to the following properties:
+<pre>
+   root-tag(myattr)=true
+   root-tag.inner-tag=Text
+   root-tag.inner-tag(someattr)=val
+   root-tag.a2.a3.a4=false
+</pre>
+
+<h5>collapseAttributes=false</h5>
+<p>This entry in a build file:
+<pre>   &lt;xmlproperty file="somefile.xml" collapseAttributes="true"/&gt;</pre>
+is equivalent to the following properties:
+<pre>
+   root-tag.myattr=true
+   root-tag.inner-tag=Text
+   root-tag.inner-tag.someatt=val
+   root-tag.a2.a3.a4=false
+</pre>
+
+<h5>keepRoot=false</h5>
+<p>This entry in a build file:
+<pre>   &lt;xmlproperty file="somefile.xml" keepRoot="false"/&gt;</pre>
+is equivalent to the following properties:
+<pre>
+   inner-tag=Text
+   inner-tag(someattr)=val
+   a2.a3.a4=false
+</pre>
+
+<h4>Semantic Attributes</h4>
+
+<p>Here is an example xml file that has semantic attributes.</p>
+<pre>
+  &lt;root-tag&gt;
+    &lt;version value="0.0.1"/&gt;
+    &lt;build folder="build"&gt;
+      &lt;classes id="build.classes" location="${build.folder}/classes"/&gt;
+      &lt;reference refid="build.classes"/&gt;
+    &lt;/build&gt;
+    &lt;compile&gt;
+      &lt;classpath pathid="compile.classpath"&gt;
+        &lt;pathelement location="${build.classes}"/&gt;
+      &lt;/classpath&gt;
+    &lt;/compile&gt;
+    &lt;run-time&gt;
+      &lt;jars&gt;*.jar&lt;/jars&gt;
+      &lt;classpath pathid="run-time.classpath"&gt;
+        &lt;path refid="compile.classpath"/&gt;
+        &lt;pathelement path="${run-time.jars}"/&gt;
+      &lt;/classpath&gt;
+    &lt;/run-time&gt;
+  &lt;/root-tag&gt;
+</pre>
+
+<h5>default loading (semanticAttributes=true)</h5>
+<p>This entry in a build file:
+<pre>   &lt;xmlproperty file="somefile.xml"
+                semanticAttributes="true"/&gt;</pre>
+is equivalent to the following entries in a build file:
+<pre>
+  &lt;property name="version" value="0.0.1"/&gt;
+  &lt;property name="build.folder" value="build"/&gt;
+  &lt;property name="build.classes" location="${build.folder}/classes" id="build.classes"/&gt;
+  &lt;property name="build.reference" refid="build.classes"/&gt;
+
+  &lt;property name="run-time.jars" value="*.jar/&gt;
+
+  &lt;classpath id="compile.classpath"&gt;
+    &lt;pathelement location="${build.classes}"/&gt;
+  &lt;/classpath&gt;
+
+  &lt;classpath id="run-time.classpath"&gt;
+    &lt;path refid="compile.classpath"/&gt;
+    &lt;pathelement path="${run-time.jars}"/&gt;
+  &lt;/classpath&gt;
+</pre>
+
+<h5>includeSemanticAttribute="true"</h5>
+<p>This entry in a build file:
+<pre>   &lt;xmlproperty file="somefile.xml"
+                semanticAttributes="true"
+                includeSemanticAttribute="true"/&gt;
+</pre>
+is equivalent to the following entries in a build file:
+<pre>
+  &lt;property name="version.value" value="0.0.1"/&gt;
+  &lt;property name="build.folder" value="build"/&gt;
+  &lt;property name="build.classes.location" location="${build.folder}/classes"/&gt;
+  &lt;property name="build.reference.refid" refid="build.location"/&gt;
+
+  &lt;property name="run-time.jars" value="*.jar/&gt;
+
+  &lt;classpath id="compile.classpath"&gt;
+    &lt;pathelement location="${build.classes}"/&gt;
+  &lt;/classpath&gt;
+
+  &lt;classpath id="run-time.classpath"&gt;
+    &lt;path refid="compile.classpath"/&gt;
+    &lt;pathelement path="${run-time.jars}"/&gt;
+  &lt;/classpath&gt;
+</pre>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTasks/zip.html b/trunk/docs/manual/CoreTasks/zip.html
new file mode 100644
index 0000000..aa3ed9c
--- /dev/null
+++ b/trunk/docs/manual/CoreTasks/zip.html
@@ -0,0 +1,304 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Zip Task</title>
+</head>
+
+<body>
+
+<h2><a name="zip">Zip</a></h2>
+<h3>Description</h3>
+<p>Creates a zipfile.</p>
+<p>The <i>basedir</i> attribute is the reference directory from where to zip.</p>
+<p>Note that file permissions will not be stored in the resulting zipfile.</p>
+<p>It is possible to refine the set of files that are being zipped. This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns. </p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>basedir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<p>Or, you may place within it nested file sets, or references to file sets.
+In this case <code>basedir</code> is optional; the implicit file set is <i>only used</i>
+if <code>basedir</code> is set. You may use any mixture of the implicit file set
+(with <code>basedir</code> set, and optional attributes like <code>includes</code>
+and optional subelements like <code>&lt;include&gt;</code>); explicit nested
+<code>&lt;fileset&gt;</code> elements so long as at least one fileset total is specified. The ZIP file will
+only reflect the relative paths of files <i>within</i> each fileset. The Zip task and its derivatives know a special form of a fileset named zipfileset that has additional attributes (described below). </p>
+<p>The Zip task also supports the merging of multiple zip files into the zip file. 
+This is possible through either the <i>src</i> attribute of any nested filesets 
+or by using the special nested fileset <i>zipgroupfileset</i>.</p>
+
+<p>The <code>update</code> parameter controls what happens if the ZIP
+file already exists. When set to <code>yes</code>, the ZIP file is
+updated with the files specified. (New files are added; old files are
+replaced with the new versions.) When set to <code>no</code> (the
+default) the ZIP file is overwritten if any of the files that would be
+added to the archive are newer than the entries inside the archive.
+Please note that ZIP files store file modification times with a
+granularity of two seconds.  If a file is less than two seconds newer
+than the entry in the archive, Ant will not consider it newer.</p>
+
+<p>The <code>whenempty</code> parameter controls what happens when no files match.
+If <code>skip</code> (the default), the ZIP is not created and a warning is issued.
+If <code>fail</code>, the ZIP is not created and the build is halted with an error.
+If <code>create</code>, an empty ZIP file (explicitly zero entries) is created,
+which should be recognized as such by compliant ZIP manipulation tools.</p>
+<p>This task will now use the platform's default character encoding
+for filenames - this is consistent with the command line ZIP tools,
+but causes problems if you try to open them from within Java and your
+filenames contain non US-ASCII characters. Use the encoding attribute
+and set it to UTF8 to create zip files that can safely be read by
+Java.</p>
+
+<p>Starting with Ant 1.5.2, <code>&lt;zip&gt;</code> can store Unix permissions
+inside the archive (see description of the filemode and dirmode
+attributes for <a href="../CoreTypes/zipfileset.html">&lt;zipfileset&gt;</a>).
+Unfortunately there is no portable way to store these permissions.
+Ant uses the algorithm used by <a href="http://www.info-zip.org">Info-Zip's</a>
+implementation of the zip and unzip commands - these are the default
+versions of zip and unzip for many Unix and Unix-like systems.</p>
+
+<p><b>Please note that the zip format allows multiple files of the same
+fully-qualified name to exist within a single archive.  This has been
+documented as causing various problems for unsuspecting users.  If you wish
+to avoid this behavior you must set the <code>duplicate</code> attribute
+to a value other than its default, <code>&quot;add&quot;</code>.</b></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">the zip-file to create.</td>
+    <td align="center" valign="top" rowspan="2">Exactly one of the two.</td>
+  </tr>
+  <tr>
+    <td valign="top">zipfile</td>
+    <td valign="top">the <i>deprecated</i> old name of destfile.</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory from which to zip the files.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compress</td>
+    <td valign="top">Not only store data but also compress them,
+    defaults to true.  Unless you set the <em>keepcompression</em>
+    attribute to false, this will apply to the entire archive, not
+    only the files you've added while updating.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepcompression</td>
+    <td valign="top">For entries coming from existing archives (like
+    nested <em>zipfileset</em>s or while updating the archive), keep
+    the compression as it has been originally instead of using the
+    <em>compress</em> attribute.  Defaults false.  <em>Since Ant
+    1.6</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The character encoding to use for filenames
+    inside the zip file.  For a list of possible values see <a
+    href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+    Defaults to the platform's default character encoding.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">filesonly</td>
+    <td valign="top">Store only file entries, defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">update</td>
+    <td valign="top">indicates whether to update or overwrite
+      the destination file if it already exists.  Default is &quot;false&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">whenempty</td>
+    <td valign="top">behavior when no files match.  Valid values are &quot;fail&quot;, &quot;skip&quot;, and &quot;create&quot;.  Default is &quot;skip&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">duplicate</td>
+    <td valign="top">behavior when a duplicate file is found.  Valid values are &quot;add&quot;, &quot;preserve&quot;, and &quot;fail&quot;. The default value is &quot;add&quot;.  </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">roundup</td>
+    <td valign="top">Whether the file modification times will be
+    rounded up to the next even number of seconds.<br>
+    Zip archives store file modification times with a granularity of
+    two seconds, so the times will either be rounded up or down.  If
+    you round down, the archive will always seem out-of-date when you
+    rerun the task, so the default is to round up.  Rounding up may
+    lead to a different type of problems like JSPs inside a web
+    archive that seem to be slightly more recent than precompiled
+    pages, rendering precompilation useless.<br>
+    Defaults to true.  <em>Since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">comment</td>
+    <td valign="top">Comment to store in the archive. <em>Since Ant 1.6.3</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">level</td>
+    <td valign="top">Non-default level at which file compression should be
+    performed. Valid values range from 0 (no compression/fastest) to 9
+    (maximum compression/slowest). <em>Since Ant 1.7</em></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any resource collection</h4>
+<p><a href="../CoreTypes/resources.html#collection">Resource
+Collection</a>s are used to select groups of files to archive.</p>
+<p>Prior to Ant 1.7 only <code>&lt;fileset&gt;</code> and
+<code>&lt;zipfileset&gt;</code> have been supported as nested elements.</p>
+
+<a name="zipgroupfileset" />
+<h4>zipgroupfileset</h4>
+<p>A <code>&lt;zipgroupfileset&gt;</code> allows for multiple zip files to be 
+merged into the archive. Each file found in this fileset is added to the archive 
+the same way that <i>zipfileset src</i> files are added.</p>
+
+
+<h3>Examples</h3>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;
+       basedir=&quot;htdocs/manual&quot;
+  /&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory into a file called <code>manual.zip</code>
+in the <code>${dist}</code> directory.</p>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;
+       basedir=&quot;htdocs/manual&quot;
+       update=&quot;true&quot;
+  /&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory into a file called <code>manual.zip</code>
+in the <code>${dist}</code> directory. If <code>manual.zip</code>
+doesn't exist, it is created; otherwise it is updated with the
+new/changed files.</p>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;
+       basedir=&quot;htdocs/manual&quot;
+       excludes=&quot;mydocs/**, **/todo.html&quot;
+  /&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory. Files in the directory <code>mydocs</code>,
+or files with the name <code>todo.html</code> are excluded.</p>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;
+       basedir=&quot;htdocs/manual&quot;
+       includes=&quot;api/**/*.html&quot;
+       excludes=&quot;**/todo.html&quot;
+  /&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory. Only html files under the directory <code>api</code>
+are zipped, and files with the name <code>todo.html</code> are excluded.</p>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;&gt;
+    &lt;fileset dir=&quot;htdocs/manual&quot;/&gt;
+    &lt;fileset dir=&quot;.&quot; includes=&quot;ChangeLog.txt&quot;/&gt;
+  &lt;/zip&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory, and also adds the file <code>ChangeLog.txt</code> in the
+current directory. <code>ChangeLog.txt</code> will be added to the top of the ZIP file, just as if
+it had been located at <code>htdocs/manual/ChangeLog.txt</code>.</p>
+<pre>  &lt;zip destfile=&quot;${dist}/manual.zip&quot;&gt;
+    &lt;zipfileset dir=&quot;htdocs/manual&quot; prefix=&quot;docs/user-guide&quot;/&gt;
+    &lt;zipfileset dir=&quot;.&quot; includes=&quot;ChangeLog27.txt&quot; fullpath=&quot;docs/ChangeLog.txt&quot;/&gt;
+    &lt;zipfileset src=&quot;examples.zip&quot; includes=&quot;**/*.html&quot; prefix=&quot;docs/examples&quot;/&gt;
+  &lt;/zip&gt;</pre>
+<p>zips all files in the <code>htdocs/manual</code> directory into the <code>docs/user-guide</code> directory
+in the archive, adds the file <code>ChangeLog27.txt</code> in the
+current directory as <code>docs/ChangeLog.txt</code>, and includes all the html files in <code>examples.zip</code> 
+under <code>docs/examples</code>.  The archive might end up containing the files:</p>
+<pre>    docs/user-guide/html/index.html
+    docs/ChangeLog.txt
+    docs/examples/index.html
+</pre>
+<p>
+The code
+<pre>
+  &lt;zip destfile=&quot;${dist}/manual.zip&quot;&gt;
+    &lt;zipfileset dir=&quot;htdocs/manual&quot; prefix=&quot;docs/user-guide&quot;/&gt;
+    &lt;zipgroupfileset dir=&quot;.&quot; includes=&quot;examples*.zip&quot;/&gt;
+  &lt;/zip&gt;
+</pre>
+<p>
+<p>zips all files in the <code>htdocs/manual</code> directory into the <code>docs/user-guide</code> directory in the archive and includes all the files in any file that maches <code>examples*.zip</code>, such as all files within <code>examples1.zip</code> or <code>examples_for_brian.zip</code>.
+
+<pre>
+&lt;zip dest="release.zip"&gt;
+  &lt;tarfileset src="release.tar"/&gt;
+&lt;/zip&gt;
+</pre>
+
+<p>Re-packages a TAR archive as a ZIP archive.  If Unix file
+permissions have been stored as part of the TAR file, they will be
+retained in the resulting ZIP archive.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/antlib.html b/trunk/docs/manual/CoreTypes/antlib.html
new file mode 100644
index 0000000..a5128a0
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/antlib.html
@@ -0,0 +1,267 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>AntLib</title>
+  </head>
+
+  <body>
+    <h2><a name="antlib">Antlib</a></h2>
+
+
+    <h3>Description</h3>
+    <p>
+      An antlib file is an xml file with a root element of "antlib".
+      Antlib's elements are ant definition tasks - like
+      
+      and <a href="../CoreTasks/taskdef.html">Taskdef</a>,
+      or any ant task that extends
+      <code>org.apache.tools.ant.taskdefs.AntlibDefinition</code>.
+    </p>
+    <p>
+        The current set of declarations bundled with Ant that do this are:
+    </p>
+        <ol>
+            <li><a href="../CoreTasks/typedef.html">Typedef</a>
+            </li>
+            <li><a href="../CoreTasks/taskdef.html">Taskdef</a>
+            </li>
+            <li><a href="../CoreTasks/macrodef.html">Macrodef</a>
+            </li>
+            <li><a href="../CoreTasks/presetdef.html">Presetdef</a>
+            </li>
+            <li><a href="../OptionalTasks/scriptdef.html">Scriptdef</a>
+            </li>
+        </ol>
+    <p>
+      A group of tasks and types may be defined together in an antlib
+      file. For example the file <i>sample.xml</i> contains the following:
+    </p>
+    <blockquote>
+      <pre>
+&lt;?xml version="1.0"?&gt;
+&lt;antlib&gt;
+   &lt;typedef name="if" classname="org.acme.ant.If"/&gt;
+   &lt;typedef name="scriptpathmapper"
+            classname="org.acme.ant.ScriptPathMapper"
+            onerror="ignore"/&gt;
+   &lt;macrodef name="print"&gt;
+      &lt;attribute name="file"/&gt;
+      &lt;sequential&gt;
+         &lt;concat taskname="print"&gt;
+            &lt;fileset dir="." includes="@{file}"/&gt;
+         &lt;/concat&gt;
+      &lt;/sequential&gt;
+   &lt;/macrodef&gt;
+&lt;/antlib&gt;
+      </pre>
+    </blockquote>
+    <p>
+      It defines two types or tasks, <i>if</i> and <i>scriptpathmapper</i>.
+      This antlib file may be used in a build script as follows:
+    </p>
+    <blockquote>
+      <pre>
+&lt;typedef file="sample.xml"/&gt;
+      </pre>
+    </blockquote>
+    <p>
+      The other attributes of <code>&lt;typedef&gt;</code> may be used as well.
+      For example, assuming that the <i>sample.xml</i> is in a jar
+      file <i>sample.jar</i> also containing the classes, the
+      following build fragment will define the <i>if</i> and <i>scriptpathmapper</i>
+      tasks/types and place them in the namespace uri <i>samples:/acme.org</i>.
+    </p>
+    <blockquote>
+      <pre>
+&lt;typedef resource="org/acme/ant/sample.xml"
+         uri="samples:/acme.org"/&gt;
+      </pre>
+    </blockquote>
+    <p>
+      The definitions may then be used as follows:
+    </p>
+    <blockquote>
+      <pre>
+&lt;sample:if valuetrue="${props}" xmlns:sample="samples:/acme.org"&gt;
+   &lt;sample:scriptpathmapper language="beanshell"&gt;
+      some bean shell
+   &lt;/sample:scriptpathmapper&gt;
+&lt;/sample:if&gt;
+      </pre>
+    </blockquote>
+
+
+    <h3><a name="antlibnamespace">Antlib namespace</a></h3>
+    <p>
+      The name space URIs with the pattern <b>antlib:<i>java package</i></b>
+      are given special treatment.
+    </p>
+    <p>
+      When ant encounters a element with a namespace URI with this pattern, it
+      will check to see if there is a resource of the name <i>antlib.xml</i> in
+      the package directory in the default classpath.
+    </p>
+    <p>
+      For example, assuming that the file <i>antcontrib.jar</i> has been placed
+      in the directory <i>${ant.home}/lib</i> and it contains the resource
+      <i>net/sf/antcontrib/antlib.xml</i> which has all antcontrib's definitions
+      defined, the following build file will automatically load the antcontrib
+      definitions at location <i>HERE</i>:
+    </p>
+    <blockquote>
+      <pre>
+&lt;project default="deletetest" xmlns:antcontrib="antlib:net.sf.antcontrib"&gt;
+   &lt;macrodef name="showdir"&gt;
+      &lt;attribute name="dir"/&gt;
+      &lt;sequential&gt;
+         &lt;antcontrib:shellscript shell="bash"&gt;  &lt;!-- HERE --&gt;
+            ls -Rl @{dir}
+         &lt;/antcontrib:shellscript&gt;
+      &lt;/sequential&gt;
+   &lt;/macrodef&gt;
+
+   &lt;target name="deletetest"&gt;
+      &lt;delete dir="a" quiet="yes"/&gt;
+      &lt;mkdir dir="a/b"/&gt;
+      &lt;touch file="a/a.txt"/&gt;
+      &lt;touch file="a/b/b.txt"/&gt;
+      &lt;delete&gt;
+         &lt;fileset dir="a"/&gt;
+      &lt;/delete&gt;
+      &lt;showdir dir="a"/&gt;
+   &lt;/target&gt;
+&lt;/project&gt;
+      </pre>
+    </blockquote>
+    <p>
+      The requirement that the resource is in the default classpath
+      may be removed in future versions of Ant.</p>
+    </p>
+
+
+	<h3><a name="loadFromInside">Load antlib from inside of the buildfile</a></h3>
+	<p>
+	  If you want to seperate the antlib from your local Ant installation, e.g. because you 
+	  want to hold that jar in your projects SCM system, you have to specify a classpath, so 
+	  that Ant could find that jar. The best solution is loading the antlib with <tt>&lt;taskdef&gt;</tt>.
+	</p>
+    <blockquote>
+      <pre>
+&lt;project xmlns:<font color="green">antcontrib</font>="<font color="red">antlib:net.sf.antcontrib</font>"&gt;
+   &lt;taskdef uri="<font color="red">antlib:net.sf.antcontrib</font>"
+            resource="net/sf/antcontrib/antlib.xml"
+            classpath="path/to/ant-contrib.jar"/&gt;
+   
+   &lt;target name="iterate"&gt;
+      &lt;<font color="green">antcontrib</font>:for param="file"&gt;
+         &lt;fileset dir="."/&gt;
+         &lt;sequential&gt;
+            &lt;echo message="- @{file}"/&gt;
+         &lt;/sequential&gt;
+      &lt;/antcontrib:for&gt;
+   &lt;/target&gt;
+&lt;/project&gt;
+      </pre>
+    </blockquote>
+
+	
+	
+
+    <h3><a name="currentnamespace">Current namespace</a></h3>
+    <p>
+      Definitions defined in antlibs may be used in antlibs. However
+      the namespace that definitions are placed in are dependent on
+      the <code>&lt;typedef&gt;</code> that uses the antlib. To deal with this
+      problem, the definitions are placed in the namepace URI <i>ant:current</i>
+      for the duration of the antlib execution.
+      For example the following antlib defines the task <code>&lt;if&gt;</code>, the
+      type <code>&lt;isallowed&gt;</code> and a macro
+      <code>&lt;ifallowed&gt;</code> that makes use of the task and type:
+    </p>
+    <blockquote>
+      <pre>
+&lt;antlib xmlns:current="ant:current"&gt;
+   &lt;taskdef name="if" classname="org.acme.ant.If"/&gt;
+   &lt;typedef name="isallowed" classname="org.acme.ant.Isallowed"/&gt;
+   &lt;macrodef name="ifallowed"&gt;
+      &lt;attribute name="action"/&gt;
+      &lt;element name="do"/&gt;
+      &lt;sequential&gt;
+         &lt;current:if&gt;
+            &lt;current:isallowed test="@{action}"/&gt;
+            &lt;current:then&gt;
+               &lt;do/&gt;
+            &lt;/current:then&gt;
+         &lt;/current:if&gt;
+      &lt;/sequential&gt;
+   &lt;/macrodef&gt;
+&lt;/antlib&gt;
+      </pre>
+    </blockquote>
+
+
+    <h3>Other examples and comments</h3>
+    <p>
+      Antlibs may make use of other antlibs.
+    </p>
+    <p>
+      As the names defined in the antlib are in the namespace uri as
+      specified by the calling <code>&lt;typedef&gt;</code> or by automatic element
+      resolution, one may reuse names from core ant types and tasks,
+      provided the caller uses a namespace uri. For example, the
+      following antlib may be used to define defaults for various
+      tasks:
+    </p>
+    <blockquote>
+      <pre>
+&lt;antlib xmlns:antcontrib="antlib:net.sf.antcontrib"&gt;
+   &lt;presetdef name="javac"&gt;
+      &lt;javac deprecation="${deprecation}"
+             debug="${debug}"/&gt;
+   &lt;/presetdef&gt;
+   &lt;presetdef name="delete"&gt;
+      &lt;delete quiet="yes"/&gt;
+   &lt;/presetdef&gt;
+   &lt;presetdef name="shellscript"&gt;
+      &lt;antcontrib:shellscript shell="bash"/&gt;
+   &lt;/presetdef&gt;
+&lt;/antlib&gt;
+      </pre>
+    </blockquote>
+    <p>
+      This may be used as follows:
+    </p>
+    <blockquote>
+      <pre>
+&lt;project xmlns:local="localpresets"&gt;
+   &lt;typedef file="localpresets.xml" uri="localpresets"/&gt;
+   &lt;local:shellscript&gt;
+      echo "hello world"
+   &lt;/local:shellscript&gt;
+&lt;/project&gt;
+      </pre>
+    </blockquote>
+    
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/assertions.html b/trunk/docs/manual/CoreTypes/assertions.html
new file mode 100644
index 0000000..f6117dc
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/assertions.html
@@ -0,0 +1,208 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Assertions type</title>
+</head>
+
+<body>
+
+<h2><a name="assertions">Assertions</a></h2>
+<p>
+The <tt>assertions</tt> type enables or disables the Java 1.4 assertions feature,
+on a whole Java program, or components of a program. It can be used
+in <a href="../CoreTasks/java.html"><code>&lt;java&gt;</code></a> and
+<a href="../OptionalTasks/junit.html"><code>&lt;junit&gt;</code></a> to add extra validation to code.  
+
+<p>
+Assertions are covered in the 
+<a href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html">J2SDK 1.4 documentation</a>,
+and the
+<a href="http://java.sun.com/docs/books/jls/assert-spec.html">Java Language Specification</a>.
+
+<p>
+The key points to note are that a <tt>java.lang.AssertionError</tt>
+is thrown when an assertion fails, and that the facility is only available 
+on Java 1.4 and later. To enable assertions one must set <tt>source="1.4"</tt>
+(or later) in <tt>&lt;javac&gt;</tt> when the source is being compiled, and
+that the code must contain <tt>assert</tt> statements to be tested. The
+result of such an action is code that neither compiles or runs on earlier
+versions of Java. For this reason Ant itself currently contains no assertions.
+<p>
+
+When assertions are enabled (or disabled) in a task through nested 
+assertions elements, the class loader or command line is modified with the 
+appropriate options. This means that the JVM executed must be a Java 1.4
+or later JVM, even if there are no assertions in the code. Attempting to
+enable assertions on earlier VMs will result in an "Unrecognized option" 
+error and the JVM will not start.  
+
+<p>
+<h4>Attributes</h4>
+<p>
+
+
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">enableSystemAssertions</td>
+    <td valign="top">Flag to turn system assertions on or off.</td>
+    <td valign="top" align="center">No; default is "unspecified"</td>
+  </tr>
+</table>
+<p>
+When system assertions have been neither enabled nor disabled, then
+the JVM is not given any assertion information - the default action of the
+ current JVMs is to disable system assertions. 
+<p>
+Note also that there is no apparent documentation for what parts of the
+JRE come with useful assertions.
+
+<h3>Nested elements</h3>
+
+<h4>enable</h4>
+<p>
+Enable assertions in portions of code.
+If neither a package nor class is specified, assertions are turned on in <i>all</i> (user) code.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">class</td>
+    <td valign="top">The name of a class on which to enable assertions.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">
+    The name of a package in which to enable assertions on all classes. (Includes subpackages.)
+    Use "<tt>...</tt>" for the anonymous package.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h4>disable</h4>
+<p>
+Disable assertions in portions of code.
+
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">class</td>
+    <td valign="top">The name of a class on which to disable assertions.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">
+    The name of a package in which to disable assertions on all classes. (Includes subpackages.)
+    Use "<tt>...</tt>" for the anonymous package.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<p>
+
+Because assertions are disabled by default, it only makes sense to disable
+assertions where they have been enabled in a parent package.
+
+
+<h4>Examples</h4>
+
+<h5>Example: enable assertions in all user classes</h5>
+
+All classes not in the JRE (i.e. all non-system classes) will have assertions turned on.
+<pre>
+&lt;assertions&gt;
+  &lt;enable/&gt;
+&lt;/assertions&gt;
+</pre>
+
+<h5>Example: enable a single class</h5>
+
+Enable assertions in a class called Test
+<pre>
+&lt;assertions&gt;
+  &lt;enable class="Test"/&gt;
+&lt;/assertions&gt;
+</pre>
+
+<h5>Example: enable a package</h5>
+
+Enable assertions in the <tt>org.apache</tt> package
+and all packages starting with the <tt>org.apache.</tt> prefix
+<pre>
+&lt;assertions&gt;
+  &lt;enable package="org.apache"/&gt;
+&lt;/assertions&gt;
+</pre>
+
+<h5>Example: System assertions</h5>
+
+Example: enable system assertions and assertions in all <tt>org.apache</tt> packages except
+for Ant (but including <tt>org.apache.tools.ant.Main</tt>)
+<pre>
+&lt;assertions enableSystemAssertions="true"&gt;
+  &lt;enable package="org.apache"/&gt;
+  &lt;disable package="org.apache.tools.ant"/&gt;
+  &lt;enable class="org.apache.tools.ant.Main"/&gt;
+&lt;/assertions&gt;
+</pre>
+
+<h5>Example: disabled and anonymous package assertions</h5>
+
+Disable system assertions; enable those in the anonymous package
+<pre>
+&lt;assertions enableSystemAssertions="false"&gt;
+  &lt;enable package="..."/&gt;
+&lt;/assertions&gt;
+</pre>
+
+
+<h5>Example: referenced assertions</h5>
+
+This type is a datatype, so you can declare assertions and use them later
+
+<pre>
+&lt;assertions id="project.assertions"&gt;
+  &lt;enable package="org.apache.test"/&gt;
+&lt;/assertions&gt;
+
+&lt;assertions refid="project.assertions"/&gt;
+</pre>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/custom-programming.html b/trunk/docs/manual/CoreTypes/custom-programming.html
new file mode 100644
index 0000000..d2f94e9
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/custom-programming.html
@@ -0,0 +1,415 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us"></meta>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Custom Components</title>
+  </head>
+  <body>
+    <h2>Custom Components</h2>
+    <h3>Overview</h3>
+    <p>
+      Custom components are conditions, selectors, filters and other
+      objects that are defined outside ant core.
+    </p>
+    <p>
+      In Ant 1.6 custom conditions, selectors and filters has
+      been overhauled.
+    </p>
+    <p>
+      It is now possible to define custom conditions, selectors and filters
+      that behave like Ant Core components.
+      This is achieved by allowing datatypes defined in build scripts
+      to be used as custom components if the class of the datatype
+      is compatible, or has been adapted by an adapter class.
+    </p>
+    <p>
+      The old methods of defining custom components are still supported.
+    </p>
+    <h3>Definition and use</h3>
+    <p>
+      A custom component is a normal Java class that implements a particular
+      interface or extends a  particular class, or has been adapted to the
+      interface or class.
+    </p>
+    <p>
+      It is exactly like writing a
+      <a href="../develop.html#writingowntask">custom task</a>.
+      One defines attributes and nested elements by writing <i>setter</i>
+      methods and <i>add</i> methods.
+    </p>
+    <p>
+      After the class has been written, it is added to the ant system
+      by using <code>&lt;typedef&gt;</code>.
+    </p>
+    <h3><a name="customconditions">Custom Conditions</a></h3>
+    <p>
+      Custom conditions are datatypes that implement
+      <code>org.apache.tools.ant.taskdefs.condition.Condition</code>.
+      For example a custom condition that returns true if a
+      string is all upper case could be written as:
+    </p>
+    <blockquote>
+      <pre>
+package com.mydomain;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+public class AllUpperCaseCondition implements Condition {
+    private String value;
+
+    // The setter for the "value" attribute
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    // This method evaluates the condition
+    public boolean eval() {
+        if (value == null) {
+            throw new BuildException("value attribute is not set");
+        }
+        return value.toUpperCase().equals(value);
+   }
+}
+      </pre>
+    </blockquote>
+
+    <p>
+        Adding the condition to the system is achieved as follows:
+    </p>
+    <blockquote>
+      <pre>
+&lt;typedef
+    name="alluppercase"
+    classname="com.mydomain.AllUpperCaseCondition"
+    classpath="${mydomain.classes}"/&gt;
+      </pre>
+    </blockquote>
+    <p>
+      This condition can now be used wherever a Core Ant condition
+      is used.
+    </p>
+    <blockquote>
+      <pre>
+&lt;condition property="allupper"&gt;
+   &lt;alluppercase value="THIS IS ALL UPPER CASE"/&gt;
+&lt;/condition&gt;
+      </pre>
+    </blockquote>
+    <h3><a name="customselectors">Custom Selectors</a></h3>
+    <p>
+      Custom selectors are datatypes that implement
+      <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
+    </p>
+    <p>There is only one method required.
+      <code>public boolean isSelected(File basedir, String filename,
+        File file)</code>.
+      It returns true
+      or false depending on whether the given file should be
+      selected or not.
+    </p>
+    <p>
+      An example of a custom selection that selects filenames ending
+      in ".java" would be:
+    </p>
+    <blockquote>
+      <pre>
+package com.mydomain;
+import java.io.File;
+import org.apache.tools.ant.types.selectors.FileSelector;
+public class JavaSelector implements FileSelector {
+    public boolean isSelected(File b, String filename, File f) {
+       return filename.toLowerCase().endsWith(".java");
+    }
+}
+      </pre>
+    </blockquote>
+    <p>
+      Adding the selector to the system is achieved as follows:
+    </p>
+    <blockquote>
+      <pre>
+&lt;typedef
+    name="javaselector"
+    classname="com.mydomain.JavaSelector"
+    classpath="${mydomain.classes}"/&gt;
+      </pre>
+    </blockquote>
+        <p>
+      This selector can now be used wherever a Core Ant selector
+      is used, for example:
+    </p>
+    <blockquote>
+      <pre>
+&lt;copy todir="to"&gt;
+   &lt;fileset dir="src"&gt;
+      &lt;javaselector/&gt;
+   &lt;/fileset&gt;
+&lt;/copy&gt;
+      </pre>
+    </blockquote>
+
+      <p>
+        One may use
+        <code>org.apache.tools.ant.types.selectors.BaseSelector</code>,
+        a convenience class that provides reasonable default
+        behaviour.
+        It has some predefined behaviours you can take advantage
+        of. Any time you encounter a problem when setting attributes or
+        adding tags, you can call setError(String errmsg) and the class
+        will know that there is a problem. Then, at the top of your
+        <code>isSelected()</code> method call <code>validate()</code> and
+        a BuildException will be thrown with the contents of your error
+        message. The <code>validate()</code> method also gives you a
+        last chance to check your settings for consistency because it
+        calls <code>verifySettings()</code>. Override this method and
+        call <code>setError()</code> within it if you detect any
+        problems in how your selector is set up.
+    </p>
+    <p>
+      To write custom selector containers one should extend
+      <code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.
+      Implement the
+      <code>public boolean isSelected(File baseDir, String filename, File file)</code>
+      method to do the right thing. Chances are you'll want to iterate
+      over the selectors under you, so use
+      <code>selectorElements()</code> to get an iterator that will do
+      that.
+    </p>
+    <p>
+      For example to create a selector container that will select files
+      if a certain number of contained selectors select, one could write
+      a selector as follows:
+    </p>
+    <blockquote>
+      <pre>
+public class MatchNumberSelectors extends BaseSelectorContainer {
+    private int number = -1;
+    public void setNumber(int number) {
+        this.number = number;
+    }
+    public void verifySettings() {
+        if (number &lt; 0) {
+           throw new BuildException("Number attribute should be set");
+        }
+    }
+    public boolean isSelected(File baseDir, String filename, File file) {
+        validate();
+        int numberSelected = 0;
+        for (Enumeration e = selectorElements(); e.hasNextElement();) {
+            FileSelector s = (FileSelector) e.nextElement();
+            if (s.isSelected(baseDir, filename, file)) {
+                numberSelected++;
+            }
+        }
+        return numberSelected == number;
+    }
+}
+      </pre>
+    </blockquote>
+    <p>
+      To define and use this selector one could do:
+    </p>
+    <blockquote>
+      <pre>
+&lt;typedef name="numberselected"
+         classname="com.mydomain.MatchNumberSelectors"/&gt;
+...
+&lt;fileset dir="${src.path}"&gt;
+   &lt;numberselected number="2"&gt;
+      &lt;contains text="script" casesensitive="no"/&gt;
+      &lt;size value="4" units="Ki" when="more"/&gt;
+      &lt;javaselector/&gt;
+   &lt;/numberselected&gt;
+&lt;/fileset&gt;
+      </pre>
+    </blockquote>
+    <p>
+      <i>The custom selector</i>
+    </p>
+    <p>
+      The custom selector was the pre ant 1.6 way of defining custom selectors.
+      This method is still supported for backward compatibility.
+    </p>
+    <p>You can write your own selectors and use them within the selector
+      containers by specifying them within the <code>&lt;custom&gt;</code> tag.</p>
+
+        <p>To create a new Custom Selector, you have to create a class that
+        implements
+        <code>org.apache.tools.ant.types.selectors.ExtendFileSelector</code>.
+        The easiest way to do that is through the convenience base class
+        <code>org.apache.tools.ant.types.selectors.BaseExtendSelector</code>,
+        which provides all of the methods for supporting
+        <code>&lt;param&gt;</code> tags. First, override the
+        <code>isSelected()</code> method, and optionally the
+        <code>verifySettings()</code> method. If your custom
+        selector requires parameters to be set, you can also override
+        the <code>setParameters()</code> method and interpret the
+        parameters that are passed in any way you like. Several of the
+        core selectors demonstrate how to do that because they can
+        also be used as custom selectors.</p>
+
+
+    <p>Once that is written, you include it in your build file by using
+      the <code>&lt;custom&gt;</code> tag.
+    </p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">classname</td>
+        <td valign="top">The name of your class that implements
+          <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">classpath</td>
+        <td valign="top">The classpath to use in order to load the
+          custom selector class. If neither this classpath nor the
+          classpathref are specified, the class will be
+          loaded from the classpath that Ant uses.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">classpathref</td>
+        <td valign="top">A reference to a classpath previously
+          defined. If neither this reference nor the
+          classpath above are specified, the class will be
+          loaded from the classpath that Ant uses.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is how you use <code>&lt;custom&gt;</code> to
+      use your class as a selector:
+    </p>
+
+    <blockquote><pre>
+&lt;fileset dir="${mydir}" includes="**/*"&gt;
+    &lt;custom classname="com.mydomain.MySelector"&gt;
+        &lt;param name="myattribute" value="myvalue"/&gt;
+    &lt;/custom&gt;
+&lt;/fileset&gt;
+      </pre></blockquote>
+
+
+    <p>The core selectors that can also be used as custom selectors
+      are</p>
+
+    <ul>
+      <li><a href="selectors.html#containsselect">Contains Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.ContainsSelector</code>
+      </li>
+      <li><a href="selectors.html#dateselect">Date Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.DateSelector</code>
+      </li>
+      <li><a href="selectors.html#depthselect">Depth Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.DepthSelector</code>
+      </li>
+      <li><a href="selectors.html#filenameselect">Filename Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.FilenameSelector</code>
+      </li>
+      <li><a href="selectors.html#sizeselect">Size Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.SizeSelector</code>
+      </li>
+    </ul>
+
+    <p>Here is the example from the Depth Selector section rewritten
+    to use the selector through <code>&lt;custom&gt;</code>.</p>
+
+    <blockquote><pre>
+&lt;fileset dir="${doc.path}" includes="**/*"&gt;
+    &lt;custom classname="org.apache.tools.ant.types.selectors.DepthSelector"&gt;
+        &lt;param name="max" value="1"/&gt;
+    &lt;/custom&gt;
+&lt;/fileset&gt;
+      </pre></blockquote>
+
+    <p>Selects all files in the base directory and one directory below
+      that.</p>
+
+    <h3><a name="filterreaders">Custom Filter Readers</a></h3>
+    <p>
+      Custom filter readers selectors are datatypes that implement
+      <code>org.apache.tools.ant.types.filters.ChainableReader</code>.
+    </p>
+    <p>There is only one method required.
+      <code>Reader chain(Reader reader)</code>.
+      This returns a reader that filters input from the specified
+      reader.
+    </p>
+    <p>
+      For example a filterreader that removes every second character
+      could be:
+    </p>
+    <blockquote>
+      <pre>
+public class RemoveOddCharacters implements ChainableReader {
+   public Reader chain(Reader reader) {
+      return new BaseFilterReader(reader) {
+          int count = 0;
+          public int read() throws IOException {
+              while (true) {
+                int c = in.read();
+                if (c == -1) {
+                    return c;
+                }
+                count++;
+                if ((count % 2) == 1) {
+                    return c;
+                }
+              }
+          }
+      }
+   }
+}
+      </pre>
+    </blockquote>
+    <p>
+      For line oriented filters it may be easier to extend
+      <code>ChainableFilterReader</code> an inner class of
+      <code>org.apache.tools.ant.filters.TokenFilter</code>.
+    </p>
+    <p>
+      For example a filter that appends the line number could be
+    </p>
+    <blockquote>
+      <pre>
+public class AddLineNumber extends ChainableReaderFilter {
+   private void lineNumber = 0;
+   public String filter(String string) {
+      lineNumber++;
+      return "" + lineNumber + "\t" + string;
+   }
+}
+      </pre>
+    </blockquote>
+
+
+    <hr></hr>
+  </body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/description.html b/trunk/docs/manual/CoreTypes/description.html
new file mode 100644
index 0000000..85942be
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/description.html
@@ -0,0 +1,46 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Apache Ant User Manual</title>
+</head>
+
+<body>
+
+<h2><a name="description">Description</a></h2>
+<h3>Description</h3>
+<p>Allows for a description of the project to be specified that
+will be included in the output of the <code>ant &#x2011;projecthelp</code>
+command.</p>
+
+<h3>Parameters</h3>
+<p>(none)</p>
+<h3>Examples</h3>
+<pre>  
+&lt;description&gt;
+This buildfile is used to build the Foo subproject within 
+the large, complex Bar project.
+&lt;/description&gt;
+</pre>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/dirset.html b/trunk/docs/manual/CoreTypes/dirset.html
new file mode 100644
index 0000000..f5fe313
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/dirset.html
@@ -0,0 +1,139 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>DirSet Type</title>
+</head>
+
+<body>
+
+<h2><a name="dirset">DirSet</a></h2>
+<p>A DirSet is a group of directories. These directories can be found in a
+directory tree starting in a base directory and are matched by
+patterns taken from a number of <a href="patternset.html">PatternSets</a>
+and <a href="selectors.html">Selectors</a>.
+</p>
+<p>PatternSets can be specified as nested
+<code>&lt;patternset&gt;</code> elements. In addition, DirSet holds
+an implicit PatternSet and supports the nested
+<code>&lt;include&gt;</code>, <code>&lt;includesfile&gt;</code>,
+<code>&lt;exclude&gt;</code> and <code>&lt;excludesfile&gt;</code>
+elements of <code>&lt;patternset&gt;</code> directly, as well as
+<code>&lt;patternset&gt;</code>'s attributes.</p>
+<p>Selectors are available as nested elements within the DirSet.
+If any of the selectors within the DirSet do not select the directory, it
+is not considered part of the DirSet. This makes a DirSet
+equivalent to an <code>&lt;and&gt;</code> selector container.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The root of the directory tree of this DirSet.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">A comma- or space-separated list of patterns of directories that
+     must be included; all directories are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">The name of a file; each line of this file is
+      taken to be an include pattern.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">A comma- or space-separated list of patterns of directories that
+     must be excluded; no directories are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">The name of a file; each line of this file is
+      taken to be an exclude pattern.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Specifies whether case-sensitivity should be applied
+     (<code>true</code>|<code>yes</code>|<code>on</code> or
+     <code>false</code>|<code>no</code>|<code>off</code>).</td>
+    <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">followsymlinks</td>
+    <td valign="top">Shall symbolic links be followed? Defaults to
+      true. See <a href="fileset.html#symlink">fileset's documentation</a>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h4>Examples</h4>
+
+<blockquote><pre>
+&lt;dirset dir=&quot;${build.dir}&quot;&gt;
+  &lt;include name=&quot;apps/**/classes&quot;/&gt;
+  &lt;exclude name=&quot;apps/**/*Test*&quot;/&gt;
+&lt;/dirset&gt;
+</pre></blockquote>
+<p>Groups all directories named <code>classes</code> found under the
+<code>apps</code> subdirectory of <code>${build.dir}</code>, except those
+that have the text <code>Test</code> in their name.</p>
+
+<blockquote><pre>
+&lt;dirset dir=&quot;${build.dir}&quot;&gt;
+  &lt;patternset id=&quot;non.test.classes&quot;&gt;
+    &lt;include name=&quot;apps/**/classes&quot;/&gt;
+    &lt;exclude name=&quot;apps/**/*Test*&quot;/&gt;
+  &lt;/patternset&gt;
+&lt;/dirset&gt;
+</pre></blockquote>
+<p>Groups the same directories as the above example, but also establishes
+a PatternSet that can be referenced in other
+<code>&lt;dirset&gt;</code> elements, rooted at a different directory.</p>
+
+<blockquote><pre>
+&lt;dirset dir=&quot;${debug_build.dir}&quot;&gt;
+  &lt;patternset refid=&quot;non.test.classes&quot;/&gt;
+&lt;/dirset&gt;
+</pre></blockquote>
+<p>Groups all directories in directory <code>${debug_build.dir}</code>,
+using the same patterns as the above example.</p>
+
+<blockquote><pre>
+&lt;dirset id=&quot;dirset&quot; dir=&quot;${workingdir}&quot;&gt;
+   &lt;present targetdir=&quot;${workingdir}&quot;&gt;
+        &lt;mapper type=&quot;glob&quot; from=&quot;*&quot; to=&quot;*/${markerfile}&quot; /&gt;
+   &lt;/present&gt;
+&lt;/dirset&gt;
+</pre></blockquote>
+<p>Selects all directories somewhere under <code>${workingdir}</code>
+which contain a <code>${markerfile}</code>.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/filelist.html b/trunk/docs/manual/CoreTypes/filelist.html
new file mode 100644
index 0000000..e25e36d
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/filelist.html
@@ -0,0 +1,120 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FileList Type</title>
+</head>
+
+<body>
+
+<h2><a name="filelist">FileList</a></h2> 
+
+<p>FileLists are explicitly named lists of files.  Whereas FileSets
+act as filters, returning only those files that exist in the file
+system and match specified patterns, FileLists are useful for
+specifying files that may or may not exist.  Multiple files are
+specified as a list of files, relative to the specified directory,
+with no support for wildcard expansion (filenames with wildcards will be
+included in the list unchanged).
+FileLists can appear inside tasks that support this feature or as stand-alone
+types.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The base directory of this FileList.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">files</td>
+    <td valign="top">The list of file names. This is a list of
+    file name separated by whitespace, or by commas.</td>
+    <td valign="top" align="center">
+      Yes, unless there is a nested file element</td>
+  </tr>
+</table>
+  <h4>Nested Element: file</h4>
+  <p>
+    This represents a file name. The nested element allows filenames containing
+    white space and commas.
+  </p>
+  <p><em>Since Ant 1.6.2</em></p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">name</td>
+      <td valign="top">The name of the file.</td>
+      <td valign="top" align="center">Yes</td>
+    </tr>
+</table>  
+<h4>Examples</h4>
+<blockquote><pre>
+&lt;filelist 
+    id=&quot;docfiles&quot; 
+    dir=&quot;${doc.src}&quot;
+    files=&quot;foo.xml,bar.xml&quot;/&gt; 
+</pre></blockquote>
+
+<p>The files <code>${doc.src}/foo.xml</code> and
+<code>${doc.src}/bar.xml</code>.  Note that these files may not (yet)
+actually exist.
+</p>
+
+<blockquote><pre>
+&lt;filelist 
+    id=&quot;docfiles&quot; 
+    dir=&quot;${doc.src}&quot;
+    files=&quot;foo.xml
+           bar.xml&quot;/&gt; 
+</pre></blockquote>
+
+<p>Same files as the example above.</p>
+
+<blockquote><pre>
+&lt;filelist refid=&quot;docfiles&quot;/&gt; 
+</pre></blockquote>
+
+<p>Same files as the example above.</p>
+
+<blockquote><pre>
+&lt;filelist 
+    id=&quot;docfiles&quot; 
+    dir=&quot;${doc.src}&quot;&gt;
+    &lt;file name="foo.xml"/&gt;
+    &lt;file name="bar.xml"/&gt;
+&lt;/filelist&gt;
+</pre></blockquote>
+
+<p>Same files as the example above.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/fileset.html b/trunk/docs/manual/CoreTypes/fileset.html
new file mode 100644
index 0000000..8f49f2c
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/fileset.html
@@ -0,0 +1,183 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FileSet Type</title>
+</head>
+
+<body>
+
+<h2><a name="fileset">FileSet</a></h2>
+<p>A FileSet is a group of files. These files can be found in a
+directory tree starting in a base directory and are matched by
+patterns taken from a number of <a
+href="patternset.html">PatternSets</a> and
+<a href="selectors.html">Selectors</a>.
+<p>PatternSets can be specified as nested
+<code>&lt;patternset&gt;</code> elements. In addition, FileSet holds
+an implicit PatternSet and supports the nested
+<code>&lt;include&gt;</code>, <code>&lt;includesfile&gt;</code>,
+<code>&lt;exclude&gt;</code> and <code>&lt;excludesfile&gt;</code>
+elements of PatternSet directly, as well as PatternSet's
+attributes.</p>
+<p>Selectors are available as nested elements within the FileSet.
+If any of the selectors within the FileSet do not select the file, the
+file is not considered part of the FileSet. This makes a FileSet
+equivalent to an <code>&lt;and&gt;</code> selector container.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">the root of the directory tree of this FileSet.</td>
+    <td valign="middle" align="center" rowspan="2">Either dir or file must be specified</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">shortcut for specifying a single-file fileset</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether <a href="../dirtasks.html#defaultexcludes">default excludes</a> should be used or not
+      (<code>yes | no</code>); default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included; all files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an include pattern.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded; no files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an exclude pattern.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Must the include and exclude patterns be treated in a case sensitive way?
+        Defaults to true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">followsymlinks</td>
+    <td valign="top">Shall symbolic links be followed? Defaults to
+      true. See the note <a href="#symlink">below</a>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">erroronmissingdir</td>
+    <td valign="top">
+      Specify what happens if the base directory does not exist.
+      If true a build error will happen, if false, the fileset
+      will be ignored/empty.
+      Defaults to true.
+      <em>Since Ant 1.7.1 (default is true for backward compatibility
+        reasons.)</em>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<p><a name="symlink"><b>Note</b></a>: All files/directories for which
+the canonical path is different from its path are considered symbolic
+links.  On Unix systems this usually means the file really is a
+symbolic link but it may lead to false results on other
+platforms.</p>
+
+<h4>Examples</h4>
+<blockquote><pre>
+&lt;fileset dir=&quot;${server.src}&quot; casesensitive=&quot;yes&quot;&gt;
+  &lt;include name=&quot;**/*.java&quot;/&gt;
+  &lt;exclude name=&quot;**/*Test*&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+<p>Groups all files in directory <code>${server.src}</code> that are Java
+source files and don't have the text <code>Test</code> in their
+name.</p>
+
+<blockquote><pre>
+&lt;fileset dir=&quot;${server.src}&quot; casesensitive=&quot;yes&quot;&gt;
+  &lt;patternset id=&quot;non.test.sources&quot;&gt;
+    &lt;include name=&quot;**/*.java&quot;/&gt;
+    &lt;exclude name=&quot;**/*Test*&quot;/&gt;
+  &lt;/patternset&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+<p>Groups the same files as the above example, but also establishes
+a PatternSet that can be referenced in other
+<code>&lt;fileset&gt;</code> elements, rooted at a different directory.</p>
+
+<blockquote><pre>
+&lt;fileset dir=&quot;${client.src}&quot; &gt;
+  &lt;patternset refid=&quot;non.test.sources&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+<p>Groups all files in directory <code>${client.src}</code>, using the
+same patterns as the above example.</p>
+
+<blockquote><pre>
+&lt;fileset dir=&quot;${server.src}&quot; casesensitive=&quot;yes&quot;&gt;
+  &lt;filename name=&quot;**/*.java&quot;/&gt;
+  &lt;filename name=&quot;**/*Test*&quot; negate=&quot;true&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+<p>Groups the same files as the top example, but using the
+<code>&lt;filename&gt;</code> selector.</p>
+
+<blockquote><pre>
+&lt;fileset dir=&quot;${server.src}&quot; casesensitive=&quot;yes&quot;&gt;
+  &lt;filename name=&quot;**/*.java&quot;/&gt;
+  &lt;not&gt;
+    &lt;filename name=&quot;**/*Test*&quot;/&gt;
+  &lt;/not&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+<p>Groups the same files as the previous example using a combination of the
+<code>&lt;filename&gt;</code> selector and the <code>&lt;not&gt;</code>
+selector container.</p>
+
+<blockquote><pre>
+&lt;fileset dir="src" includes="main/" /&gt;
+</pre></blockquote>
+<p>Selects all files in <i>src/main</i> (e.g. <i>src/main/Foo.java</i> or 
+<i>src/main/application/Bar.java</i>).</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/filterchain.html b/trunk/docs/manual/CoreTypes/filterchain.html
new file mode 100644
index 0000000..29a8613
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/filterchain.html
@@ -0,0 +1,1491 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FilterChains and FilterReaders</title>
+</head>
+
+<body>
+
+<h2>FilterChains and FilterReaders</h2>
+Consider the flexibility of Unix pipes.  If you wanted,
+for example, to copy just those lines that contained the
+string blee from the first 10 lines of a text file 'foo'
+(<em>you wouldn't want to filter a binary file</em>)
+to a file 'bar', you would do something like:<p>
+<code>
+cat foo|head -n10|grep blee &gt; bar
+</code><p>
+Ant was not flexible enough.  There was no way for the
+<code>&lt;copy&gt;</code> task to do something similar.  If you wanted
+the <code>&lt;copy&gt;</code> task to get the first 10 lines, you would have
+had to create special attributes:<p>
+<code>
+&lt;copy file=&quot;foo&quot; tofile=&quot;bar&quot; head=&quot;10&quot; contains=&quot;blee&quot;/&gt;
+</code><p>
+The obvious problem thus surfaced: Ant tasks would not be able
+to accommodate such data transformation attributes as they would
+be endless.  The task would also not know in which order these
+attributes were to be interpreted.  That is, must the task execute the
+contains attribute first and then the head attribute or vice-versa?
+What Ant tasks needed was a mechanism to allow pluggable filter (data
+transformer) chains.  Ant would provide a few filters for which there
+have been repeated requests.  Users with special filtering needs
+would be able to easily write their own and plug them in.<p>
+
+The solution was to refactor data transformation oriented
+tasks to support FilterChains.  A FilterChain is a group of
+ordered FilterReaders.  Users can define their own FilterReaders
+by just extending the java.io.FilterReader class.  Such custom
+FilterReaders can be easily plugged in as nested elements of
+<code>&lt;filterchain&gt;</code> by using <code>&lt;filterreader&gt;</code> elements.
+<p>
+Example:
+<blockquote><pre>
+&lt;copy file=&quot;${src.file}&quot; tofile=&quot;${dest.file}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;your.extension.of.java.io.FilterReader&quot;&gt;
+      &lt;param name=&quot;foo&quot; value=&quot;bar&quot;/&gt;
+    &lt;/filterreader&gt;
+    &lt;filterreader classname=&quot;another.extension.of.java.io.FilterReader&quot;&gt;
+      &lt;classpath&gt;
+        &lt;pathelement path="${classpath}"/&gt;
+      &lt;/classpath&gt;
+      &lt;param name=&quot;blah&quot; value=&quot;blee&quot;/&gt;
+      &lt;param type=&quot;abra&quot; value=&quot;cadabra&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/copy&gt;
+</pre></blockquote>
+
+Ant provides some built-in filter readers.  These filter readers
+can also be declared using a syntax similar to the above syntax.
+However, they can be declared using some simpler syntax also.<p>
+Example:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;headfilter lines=&quot;15&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+is equivalent to:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.HeadFilter&quot;&gt;
+      &lt;param name=&quot;lines&quot; value=&quot;15&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+The following built-in tasks support nested <code>&lt;filterchain&gt;</code> elements.<br>
+<a href="../CoreTasks/concat.html">Concat</a>,<br>
+<a href="../CoreTasks/copy.html">Copy</a>,<br>
+<a href="../CoreTasks/loadfile.html">LoadFile</a>,<br>
+<a href="../CoreTasks/loadproperties.html">LoadProperties</a>,<br>
+<a href="../CoreTasks/move.html">Move</a><br><br>
+
+A FilterChain is formed by defining zero or more of the following
+nested elements.<br>
+<a href="#filterreader">FilterReader</a><br>
+<a href="#classconstants">ClassConstants</a><br>
+<a href="#escapeunicode">EscapeUnicode</a><br>
+<a href="#expandproperties">ExpandProperties</a><br>
+<a href="#headfilter">HeadFilter</a><br>
+<a href="#linecontains">LineContains</a><br>
+<a href="#linecontainsregexp">LineContainsRegExp</a><br>
+<a href="#prefixlines">PrefixLines</a><br>
+<a href="#replacetokens">ReplaceTokens</a><br>
+<a href="#stripjavacomments">StripJavaComments</a><br>
+<a href="#striplinebreaks">StripLineBreaks</a><br>
+<a href="#striplinecomments">StripLineComments</a><br>
+<a href="#tabstospaces">TabsToSpaces</a><br>
+<a href="#tailfilter">TailFilter</a><br>
+<a href="#deletecharacters">DeleteCharacters</a><br>
+<a href="#concatfilter">ConcatFilter</a><br>
+<a href="#tokenfilter">TokenFilter</a><br>
+<a href="../CoreTasks/fixcrlf.html">FixCRLF</a><br>
+
+<h3><a name="filterreader">FilterReader</a></h3>
+
+The filterreader element is the generic way to
+define a filter.  User defined filter elements are
+defined in the build file using this.  Please note that
+built in filter readers can also be defined using this
+syntax.
+
+A FilterReader element must be supplied with a class name as
+an attribute value.  The class resolved by this name must
+extend java.io.FilterReader.  If the custom filter reader
+needs to be parameterized, it must implement
+org.apache.tools.type.Parameterizable.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>classname</td>
+    <td vAlign=top>The class name of the filter reader.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+
+<p>
+<h4>Nested Elements:</h4>
+<code>&lt;filterreader&gt;</code> supports <code>&lt;classpath&gt;</code> and <code>&lt;param&gt;</code>
+as nested elements.  Each <code>&lt;param&gt;</code> element may take in the following
+attributes - name, type and value.
+<p>
+The following FilterReaders are supplied with the default
+distribution.
+
+<h3><a name="classconstants">ClassConstants</a></h3>
+<p>
+  This filters basic constants defined in a Java Class,
+  and outputs them in lines composed of the format <i>name</i>=<i>value</i>.
+  This filter uses the <em>bcel</em> library to understand the Java Class file.
+  See <a href="../install.html#librarydependencies">Library Dependencies</a>.
+<p>
+  <p>
+    <em><b>Important:</b></em>
+    This filter is different from most of the other filters.
+    Most of the filters operate on a sequence of characters.
+    This filter operates on the sequence of bytes that makes up
+    a class. However the bytes arrive to the filter as a sequence
+    of characters. This means that one must be careful on the
+    choice of character encoding to use. Most encoding lose information
+    on conversion from an arbitary sequence of bytes to characters
+    and back again to bytes. In particular the usual default
+    character encodings (CP152 and UTF-8) do.
+    For this reason, <em>since Ant 1.7</em>, the character
+    encoding <b>ISO-8859-1</b> is used to convert from characters back to
+    bytes, so one <b>has</b> to use this encoding for reading the java
+    class file.
+<h4>Example:</h4>
+
+This loads the basic constants defined in a Java class as Ant properties.
+
+<blockquote><pre>
+&lt;loadproperties srcfile="foo.class" encoding="ISO-8859-1"&gt;
+  &lt;filterchain&gt;
+    &lt;classconstants/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadproperties&gt;
+</pre></blockquote>
+
+This loads the constants from a Java class file as Ant properties,
+prepending the names with a prefix.
+
+    <blockquote><pre>
+&lt;loadproperties srcfile="build/classes/org/acme/bar.class"
+                encoding="ISO-8859-1"&gt;
+  &lt;filterchain&gt;
+    &lt;classconstants/&gt;
+    &lt;prefixlines prefix="ini."/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadproperties&gt;
+</pre></blockquote>
+<h3><a name="escapeunicode">EscapeUnicode</a></h3>
+<p>
+This filter converts its input by changing all non US-ASCII characters
+into their equivalent unicode escape backslash u plus 4 digits.</p>
+
+<p><em>since Ant 1.6</em></p>
+
+<h4>Example:</h4>
+
+This loads the basic constants defined in a Java class as Ant properties.
+<blockquote><pre>
+&lt;loadproperties srcfile=&quot;non_ascii_property.properties&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.EscapeUnicode&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadproperties&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadproperties srcfile=&quot;non_ascii_property.properties&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;escapeunicode/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadproperties&gt;
+</pre></blockquote>
+
+<h3><a name="expandproperties">ExpandProperties</a></h3>
+<p>
+If the data contains data that represents Ant
+properties (of the form ${...}), that is substituted
+with the property's actual value.
+<p>
+<h4>Example:</h4>
+
+This results in the property modifiedmessage holding the value
+&quot;All these moments will be lost in time, like teardrops in the rain&quot;
+<blockquote><pre>
+&lt;echo
+  message=&quot;All these moments will be lost in time, like teardrops in the ${weather}&quot;
+  file=&quot;loadfile1.tmp&quot;
+  /&gt;
+&lt;property name=&quot;weather&quot; value=&quot;rain&quot;/&gt;
+&lt;loadfile property=&quot;modifiedmessage&quot; srcFile=&quot;loadfile1.tmp&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.ExpandProperties&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;echo
+  message=&quot;All these moments will be lost in time, like teardrops in the ${weather}&quot;
+  file=&quot;loadfile1.tmp&quot;
+  /&gt;
+&lt;property name=&quot;weather&quot; value=&quot;rain&quot;/&gt;
+&lt;loadfile property=&quot;modifiedmessage&quot; srcFile=&quot;loadfile1.tmp&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;expandproperties/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+<h3><a name="headfilter">HeadFilter</a></h3>
+
+This filter reads the first few lines from the data supplied to it.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>lines</td>
+    <td vAlign=top align="center">Number of lines to be read.
+    Defaults to &quot;10&quot; <br> A negative value means that all lines are
+    passed (useful with <i>skip</i>)</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>skip</td>
+    <td vAlign=top align="center">Number of lines to be skipped (from the beginning).
+    Defaults to &quot;0&quot;</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+<h4>Example:</h4>
+
+This stores the first 15 lines of the supplied data in the property src.file.head
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.HeadFilter&quot;&gt;
+      &lt;param name=&quot;lines&quot; value=&quot;15&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;headfilter lines=&quot;15&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+This stores the first 15 lines, skipping the first 2 lines, of the supplied data
+in the property src.file.head. (Means: lines 3-17)
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;headfilter lines=&quot;15&quot; skip=&quot;2&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+See the testcases for more examples (<i>src\etc\testcases\filters\head-tail.xml</i> in the
+source distribution).
+
+<h3><a name="linecontains">LineContains</a></h3>
+
+This filter includes only those lines that contain all the user-specified
+strings.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Type</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>contains</td>
+    <td vAlign=top align="center">Substring to be searched for.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>negate</td>
+    <td vAlign=top align="center">Whether to select
+      <i>non-</i>matching lines only. <b>Since Ant 1.7</b></td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+<h4>Example:</h4>
+
+This will include only those lines that contain <code>foo</code> and
+<code>bar</code>.
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContains&quot;&gt;
+  &lt;param type=&quot;contains&quot; value=&quot;foo&quot;/&gt;
+  &lt;param type=&quot;contains&quot; value=&quot;bar&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;linecontains&gt;
+  &lt;contains value=&quot;foo&quot;/&gt;
+  &lt;contains value=&quot;bar&quot;/&gt;
+&lt;/linecontains&gt;
+</pre></blockquote>
+
+Negation:
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContains&quot;&gt;
+  &lt;param type=&quot;negate&quot; value=&quot;true&quot;/&gt;
+  &lt;param type=&quot;contains&quot; value=&quot;foo&quot;/&gt;
+  &lt;param type=&quot;contains&quot; value=&quot;bar&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+<i>or</i>
+<blockquote><pre>
+&lt;linecontains negate=&quot;true&quot;&gt;
+  &lt;contains value=&quot;foo&quot;/&gt;
+  &lt;contains value=&quot;bar&quot;/&gt;
+&lt;/linecontains&gt;
+</pre></blockquote>
+
+<h3><a name="linecontainsregexp">LineContainsRegExp</a></h3>
+
+Filter which includes only those lines that contain the user-specified
+regular expression matching strings.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Type</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>regexp</td>
+    <td vAlign=top align="center">Regular expression to be searched for.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>negate</td>
+    <td vAlign=top align="center">Whether to select
+      <i>non-</i>matching lines only. <b>Since Ant 1.7</b></td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+
+See <a href="regexp.html">Regexp Type</a> for the description of the nested element regexp and of
+the choice of regular expression implementation.
+<h4>Example:</h4>
+
+This will fetch all those lines that contain the pattern <code>foo</code>
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContainsRegExp&quot;&gt;
+  &lt;param type=&quot;regexp&quot; value=&quot;foo*&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;linecontainsregexp&gt;
+  &lt;regexp pattern=&quot;foo*&quot;/&gt;
+&lt;/linecontainsregexp&gt;
+</pre></blockquote>
+
+Negation:
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContainsRegExp&quot;&gt;
+  &lt;param type=&quot;negate&quot; value=&quot;true&quot;/&gt;
+  &lt;param type=&quot;regexp&quot; value=&quot;foo*&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+<i>or</i>
+<blockquote><pre>
+&lt;linecontainsregexp negate=&quot;true&quot;&gt;
+  &lt;regexp pattern=&quot;foo*&quot;/&gt;
+&lt;/linecontainsregexp&gt;
+</pre></blockquote>
+
+<h3><a name="prefixlines">PrefixLines</a></h3>
+
+Attaches a prefix to every line.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>prefix</td>
+    <td vAlign=top align="center">Prefix to be attached to lines.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+<p>
+<h4>Example:</h4>
+
+This will attach the prefix <code>Foo</code> to all lines.
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.PrefixLines&quot;&gt;
+  &lt;param name=&quot;prefix&quot; value=&quot;Foo&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;prefixlines prefix=&quot;Foo&quot;/&gt;
+</pre></blockquote>
+
+<h3><a name="replacetokens">ReplaceTokens</a></h3>
+
+This filter reader replaces all strings that are
+sandwiched between begintoken and endtoken with
+user defined values.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Type</b></td>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>tokenchar</td>
+    <td vAlign=top>begintoken</td>
+    <td vAlign=top>Character marking the
+    beginning of a token.  Defaults to @</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>tokenchar</td>
+    <td vAlign=top>endtoken</td>
+    <td vAlign=top>Character marking the
+    end of a token.  Defaults to @</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>token</td>
+    <td vAlign=top>User defined String.</td>
+    <td vAlign=top>User defined search String.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>propertiesfile</td>
+    <td vAlign=top>Not applicable.</td>
+    <td vAlign=top>Properties file to take tokens from.</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+
+<h4>Example:</h4>
+
+This replaces occurrences of the string &#64;DATE&#64; in the data
+with today's date and stores it in the property ${src.file.replaced}
+<blockquote><pre>
+&lt;tstamp/&gt;
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.replaced}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.ReplaceTokens&quot;&gt;
+      &lt;param type=&quot;token&quot; name=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;tstamp/&gt;
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.replaced}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;replacetokens&gt;
+      &lt;token key=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+    &lt;/replacetokens&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+This will treat each properties file entry in sample.properties as a token/key pair :
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.replaced}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.ReplaceTokens&quot;&gt;
+      &lt;param type=&quot;propertiesfile&quot; value=&quot;sample.properties&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+&lt;/filterchain&gt;
+</pre></blockquote>
+
+<h3><a name="stripjavacomments">StripJavaComments</a></h3>
+
+This filter reader strips away comments from the data,
+using Java syntax guidelines.  This filter does not
+take in any parameters.
+<p>
+<h4>Example:</h4>
+
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${java.src.file}&quot; property=&quot;${java.src.file.nocomments}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.StripJavaComments&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${java.src.file}&quot; property=&quot;${java.src.file.nocomments}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;stripjavacomments/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+<h3><a name="striplinebreaks">StripLineBreaks</a></h3>
+
+This filter reader strips away specific characters
+from the data supplied to it.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>linebreaks</td>
+    <td vAlign=top align="center">Characters that are to
+    be stripped out.  Defaults to &quot;\r\n&quot;</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+<h4>Examples:</h4>
+
+This strips the '\r' and '\n' characters.
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.contents}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.StripLineBreaks&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.contents}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;striplinebreaks/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+This treats the '(' and ')' characters as line break characters and
+strips them.
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.contents}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.StripLineBreaks&quot;&gt;
+      &lt;param name=&quot;linebreaks&quot; value=&quot;()&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+<h3><a name="striplinecomments">StripLineComments</a></h3>
+
+This filter removes all those lines that begin with strings
+that represent comments as specified by the user.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Type</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>comment</td>
+    <td vAlign=top align="center">Strings that identify a line as a comment
+    when they appear at the start of the line.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+<p>
+<h4>Examples:</h4>
+
+This removes all lines that begin with #, --, REM, rem and //
+<blockquote><pre>
+&lt;filterreader classname=&quot;org.apache.tools.ant.filters.StripLineComments&quot;&gt;
+  &lt;param type=&quot;comment&quot; value=&quot;#&quot;/&gt;
+  &lt;param type=&quot;comment&quot; value=&quot;--&quot;/&gt;
+  &lt;param type=&quot;comment&quot; value=&quot;REM &quot;/&gt;
+  &lt;param type=&quot;comment&quot; value=&quot;rem &quot;/&gt;
+  &lt;param type=&quot;comment&quot; value=&quot;//&quot;/&gt;
+&lt;/filterreader&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;striplinecomments&gt;
+  &lt;comment value=&quot;#&quot;/&gt;
+  &lt;comment value=&quot;--&quot;/&gt;
+  &lt;comment value=&quot;REM &quot;/&gt;
+  &lt;comment value=&quot;rem &quot;/&gt;
+  &lt;comment value=&quot;//&quot;/&gt;
+&lt;/striplinecomments&gt;
+</pre></blockquote>
+
+<h3><a name="tabstospaces">TabsToSpaces</a></h3>
+
+This filter replaces tabs with spaces
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>tablength</td>
+    <td vAlign=top align="center">Defaults to &quot;8&quot;</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+<h4>Examples:</h4>
+
+This replaces tabs in ${src.file} with spaces.
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.notab}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.TabsToSpaces&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.notab}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;tabstospaces/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+<h3><a name="tailfilter">TailFilter</a></h3>
+
+This filter reads the last few lines from the data supplied to it.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>lines</td>
+    <td vAlign=top align="center">Number of lines to be read.
+    Defaults to &quot;10&quot; <br> A negative value means that all lines are
+    passed (useful with <i>skip</i>)</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>skip</td>
+    <td vAlign=top align="center">Number of lines to be skipped (from the end).
+    Defaults to &quot;0&quot; </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+
+<h4>Background:</h4>
+With HeadFilter and TailFilter you can extract each part of a text file you want.
+This graphic shows the dependencies:
+
+<table cellSpacing=0 cellPadding=2 border=1>
+<tr>
+ <th> Content </th>
+ <th></th>
+ <th></th>
+ <th></th>
+ <th> Filter </th>
+</tr>
+<tr>
+ <td> Line 1 </td>
+ <td rowspan="2" bgcolor="#C0C0C0">&nbsp;</td>
+ <td rowspan="9" bgcolor="#FF00FF">&nbsp;</td>
+ <td rowspan="4">&nbsp;</td>
+ <td rowspan="11">
+    <table>
+    <tr>
+     <td bgcolor="#C0C0C0">&nbsp;</td>
+     <td><pre>&lt;filterchain&gt;
+    &lt;headfilter lines="2"/&gt;
+&lt;/filterchain&gt;</pre></td>
+    </tr>
+    <tr>
+     <td bgcolor="#FF00FF">&nbsp;</td>
+     <td><pre>&lt;filterchain&gt;
+    &lt;tailfilter lines="-1" skip="2"/&gt;
+&lt;/filterchain&gt;</pre></td>
+    </tr>
+    <tr>
+     <td bgcolor="#008000">&nbsp;</td>
+     <td><pre>&lt;filterchain&gt;
+    &lt;headfilter lines="-1" skip="2"/&gt;
+&lt;/filterchain&gt;</pre></td>
+    </tr>
+    <tr>
+     <td bgcolor="#0000FF">&nbsp;</td>
+     <td><pre>&lt;filterchain&gt;
+    &lt;headfilter lines="-1" skip="2"/&gt;
+    &lt;tailfilter lines="-1" skip="2"/&gt;
+&lt;/filterchain&gt;</pre></td>
+    </tr>
+    <tr>
+     <td bgcolor="#00FF00">&nbsp;</td>
+     <td><pre>&lt;filterchain&gt;
+    &lt;tailfilter lines="2"/&gt;
+&lt;/filterchain&gt;</pre></td>
+    </tr>
+    </table>
+ </td>
+</tr>
+<tr>
+ <td> Line 2 </td>
+</tr>
+<tr>
+ <td> Line 3 </td>
+ <td rowspan="9" bgcolor="#008000">&nbsp;</td>
+</tr>
+<tr>
+ <td> Line 4 </td>
+</tr>
+<tr>
+ <td> Line 5 </td>
+ <td rowspan="3" bgcolor="#0000FF">&nbsp;</td>
+</tr>
+<tr>
+ <td> Lines ... </td>
+</tr>
+<tr>
+ <td> Line 95 </td>
+</tr>
+<tr>
+ <td> Line 96 </td>
+ <td rowspan="4">&nbsp;</td>
+</tr>
+<tr>
+ <td> Line 97 </td>
+</tr>
+<tr>
+ <td> Line 98 </td>
+ <td rowspan="2" bgcolor="#00FF00">&nbsp;</td>
+</tr>
+<tr>
+ <td> Line 99 </td>
+</tr>
+</table>
+
+
+
+<h4>Examples:</h4>
+
+This stores the last 15 lines of the supplied data in the property ${src.file.tail}
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.tail}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.TailFilter&quot;&gt;
+      &lt;param name=&quot;lines&quot; value=&quot;15&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.tail}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;tailfilter lines=&quot;15&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+
+This stores the last 5 lines of the first 15 lines of the supplied
+data in the property ${src.file.mid}
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.mid}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.HeadFilter&quot;&gt;
+      &lt;param name=&quot;lines&quot; value=&quot;15&quot;/&gt;
+    &lt;/filterreader&gt;
+    &lt;filterreader classname=&quot;org.apache.tools.ant.filters.TailFilter&quot;&gt;
+      &lt;param name=&quot;lines&quot; value=&quot;5&quot;/&gt;
+    &lt;/filterreader&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+Convenience method:
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;${src.file.mid}&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;headfilter lines=&quot;15&quot;/&gt;
+    &lt;tailfilter lines=&quot;5&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+
+This stores the last 10 lines, skipping the last 2 lines, of the supplied data
+in the property src.file.head. (Means: if supplied data contains 60 lines,
+lines 49-58 are extracted)
+<blockquote><pre>
+&lt;loadfile srcfile=&quot;${src.file}&quot; property=&quot;src.file.head&quot;&gt;
+  &lt;filterchain&gt;
+    &lt;tailfilter lines=&quot;10&quot; skip=&quot;2&quot;/&gt;
+  &lt;/filterchain&gt;
+&lt;/loadfile&gt;
+</pre></blockquote>
+
+<h3><a name="deletecharacters">DeleteCharacters</a></h3>
+
+  <p>This filter deletes specified characters.</p>
+  <p><em>since Ant 1.6</em></p>
+  <p>This filter is only available in the convenience form.</p>
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>chars</td>
+    <td vAlign=top>
+      The characters to delete. This attribute is
+      <a href="#backslash">backslash enabled</a>.
+    </td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+<p>
+<h4>Examples:</h4>
+
+Delete tabs and returns from the data.
+<blockquote><pre>
+&lt;deletecharacters chars="\t\r"/&gt;
+</pre></blockquote>
+
+<h3><a name="concatfilter">ConcatFilter</a></h3>
+  <p>This filter prepends or appends the content file to the filtered files.</p>
+  <p><em>since Ant 1.6</em></p>
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Parameter Name</b></td>
+    <td vAlign=top><b>Parameter Value</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>prepend</td>
+    <td vAlign=top>
+      The name of the file which content should be prepended to the file.
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>append</td>
+    <td vAlign=top>
+      The name of the file which content should be appended to the file.
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+
+<h4>Examples:</h4>
+
+Do nothing:
+<blockquote><pre>
+&lt;filterchain&gt;
+    &lt;concatfilter/&gt;
+&lt;/filterchain&gt;
+</pre></blockquote>
+
+Adds a license text before each java source:
+<blockquote><pre>
+&lt;filterchain&gt;
+    &lt;concatfilter prepend="apache-license-java.txt"/&gt;
+&lt;/filterchain&gt;
+</pre></blockquote>
+
+
+
+<h3><a name="tokenfilter">TokenFilter</a></h3>
+This filter tokenizes the inputstream into strings and passes these
+strings to filters of strings. Unlike the other filterreaders, this does
+not support params, only convenience methods are implemented.
+The tokenizer and the string filters are defined by nested elements.
+<p><em>since Ant 1.6</em></p>
+<p>
+Only one tokenizer element may be used, the LineTokenizer is the
+default if none are specified.  A tokenizer
+splits the input into token strings and trailing delimiter strings.
+<p>
+There may be zero or more string filters. A string filter processes
+a token and either returns a string or a null.
+It the string is not null it is passed to the next filter. This
+proceeds until all the filters are called.
+If a string is returned after all the filters, the string is
+outputs with its associated token delimitier
+(if one is present).
+The trailing delimiter may be overridden by the <i>delimOutput</i>
+attribute.
+<p>
+<a name="backslash"><em>blackslash interpretation</em></a>
+A number of attributes (including <i>delimOutput</i>) interpret
+backslash escapes. The following are understood: \n, \r, \f, \t
+and \\.
+
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>delimOutput</td>
+    <td vAlign=top>
+     This overrides the tokendelimiter
+        returned by the tokenizer if it is not empty. This
+     attribute is backslash enabled.
+</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<p>
+
+    The following tokenizers are provided by the default distribution.
+    <p>
+        <a href="#linetokenizer">LineTokenizer</a><br>
+        <a href="#filetokenizer">FileTokenizer</a><br>
+        <a href="#stringtokenizer">StringTokenizer</a><br>
+    </p>
+
+    The following string filters are provided by the default distribution.
+    <p>
+        <a href="#replacestring">ReplaceString</a><br>
+        <a href="#containsstring">ContainsString</a><br>
+        <a href="#replaceregex">ReplaceRegex</a><br>
+        <a href="#containsregex">ContainsRegex</a><br>
+        <a href="#trim">Trim</a><br>
+        <a href="#ignoreblank">IgnoreBlank</a><br>
+        <a href="#filterdeletecharacters">DeleteCharacters</a><br>
+    </p>
+
+    The following string filters are provided by the optional distribution.
+    <p>
+        <a href="#scriptfilter">ScriptFilter</a><br>
+    </p>
+
+Some of the filters may be used directly within a filter chain. In this
+case a tokenfilter is created implicitly. An extra attribute "byline"
+is added to the filter to specify whether to use a linetokenizer
+(byline="true") or a filetokenizer (byline="false"). The default
+is "true".
+<p>
+
+<p><b><em><a name="linetokenizer">LineTokenizer</a></em></b></p>
+This tokenizer splits the input into lines.
+The tokenizer delimits lines
+by "\r", "\n" or "\r\n".
+This is the default tokenizer.
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>includeDelims</td>
+    <td vAlign=top>
+      Include the line endings in the token.
+      Default is false.
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<h4>Examples:</h4>
+
+Convert input current line endings to unix style line endings.
+<blockquote><pre>
+&lt;tokenfilter delimoutput=&quot;\n&quot;/&gt;
+</pre></blockquote>
+
+
+Remove blank lines.
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;ignoreblank/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+<p><b><em><a name="filetokenizer">FileTokenizer</a></em></b></p>
+This tokenizer treats <b>all</b> the input as a token. So be
+careful not to use this on very large input.
+<h4>Examples:</h4>
+
+Replace the first occurrence of package with //package.
+<blockquote><pre>
+&lt;tokenfilter&gt;
+      &lt;filetokenizer/&gt;
+      &lt;replaceregex pattern="([\n\r]+[ \t]*|^[ \t]*)package"
+                    flags="s"
+                    replace="\1//package"/&gt;
+&lt;/tokenfilter&gt;
+</pre></blockquote>
+
+<p><b><em><a name="stringtokenizer">StringTokenizer</a></em></b></p>
+This tokenizer is based on java.util.StringTokenizer.
+It splits up the input into strings separated by white space, or
+by a specified list of delimiting characters.
+If the stream starts with delimiter characters, the first
+token will be the empty string (unless the <i>delimsaretokens</i>
+attribute is used).
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>delims</td>
+    <td vAlign=top>The delimiter characters. White space
+      is used if this is not set. (White space is defined
+      in this case by java.lang.Character.isWhitespace()).
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">delimsaretokens</td>
+    <td valign="top">If this is true,
+      each delimiter character is returned as a token.
+      Default is false.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressdelims</td>
+    <td valign="top">
+      If this is true, delimiters are not returned.
+      Default is false.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>includeDelims</td>
+    <td vAlign=top>
+      Include the delimiters in the token.
+      Default is false.
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+
+<h4>Examples:</h4>
+
+Surround each non space token with a "[]".
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;stringtokenizer/&gt;
+    &lt;replaceregex pattern="(.+)" replace="[\1]"/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+<p><b><em><a name="replacestring">ReplaceString</a></em></b></p>
+This is a simple filter to replace strings.
+This filter may be used directly within a filterchain.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>from</td>
+    <td vAlign=top>The string that must be replaced.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">to</td>
+    <td valign="top">The new value for the replaced string. When omitted
+      an empty string is used.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h4>Examples:</h4>
+
+Replace "sun" with "moon".
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;replacestring from="sun" to="moon"/&gt;
+&lt;/tokenfilter&gt;
+</pre></blockquote>
+
+<p><b><em><a name="containsstring">ContainsString</a></em></b></p>
+This is a simple filter to filter tokens that contains
+a specified string.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>contains</td>
+    <td vAlign=top>The string that the token must contain.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>Examples:</h4>
+
+Include only lines that contain "foo";
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;containsstring contains="foo"/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+<p><b><em><a name="replaceregex">ReplaceRegex</a></em></b></p>
+This string filter replaces regular expressions.
+This filter may be used directly within a filterchain.
+<p>
+ See <a href="regexp.html#implementation">Regexp Type</a>
+concerning the choice of the implementation.
+</p>
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>pattern</td>
+    <td vAlign=top>The regular expression pattern to match in
+      the token.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>replace</td>
+    <td vAlign=top>The substitution pattern to replace the matched
+      regular expression. When omitted an empty string is used.</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>flags</td>
+    <td vAlign=top>See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation of regex flags.</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+<h4>Examples:</h4>
+
+Replace all occurrences of "hello" with "world", ignoring case.
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;replaceregex pattern="hello" replace="world" flags="gi"/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+<p><b><em><a name="containsregex">ContainsRegex</a></em></b></p>
+This filters strings that match regular expressions.
+The filter may optionally replace the matched regular expression.
+This filter may be used directly within a filterchain.
+<p>
+See
+<a href="regexp.html#implementation">Regexp Type</a>
+concerning the choice of regular expression implementation.
+</p>
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>pattern</td>
+    <td vAlign=top>The regular expression pattern to match in
+      the token.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>replace</td>
+    <td vAlign=top>The substitution pattern to replace the matched
+      regular expression. When omitted the orignal token is returned.
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>flags</td>
+    <td vAlign=top>See
+<a href="../OptionalTasks/replaceregexp.html">ReplaceRegexp</a>
+for an explanation of regex flags.</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+
+<h4>Examples:</h4>
+
+Filter lines that contain "hello" or "world", ignoring case.
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;containsregex pattern="(hello|world)" flags="i"/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+This example replaces lines like "SUITE(TestSuite, bits);" with
+"void register_bits();" and removes other lines.
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;containsregex
+        pattern="^ *SUITE\(.*,\s*(.*)\s*\).*"
+        replace="void register_\1();"/&gt;
+&lt;/tokenfilter&gt;
+</pre></blockquote>
+
+<p><b><em><a name="trim">Trim</a></em></b></p>
+This filter trims whitespace from the start and end of
+tokens.
+This filter may be used directly within a filterchain.
+<p><b><em><a name="ignoreblank">IgnoreBlank</a></em></b></p>
+This filter removes empty tokens.
+This filter may be used directly within a filterchain.
+<p><b><em><a name="filterdeletecharacters">DeleteCharacters</a></em></b></p>
+This filter deletes specified characters from tokens.
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>chars</td>
+    <td vAlign=top>The characters to delete. This attribute
+      is backslash enabled.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>Examples:</h4>
+
+Delete tabs from lines, trim the lines and removes empty lines.
+
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;deletecharacters chars="\t"/&gt;
+    &lt;trim/&gt;
+    &lt;ignoreblank/&gt;
+&lt;/tokenfilter&gt;
+
+</pre></blockquote>
+
+<p><b><em><a name="scriptfilter">ScriptFilter</a></em></b></p>
+This is an optional filter that executes a script in a
+<a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+  or
+  <a href="https://scripting.dev.java.net">JSR 223</a>
+supported language.</p>
+See the <a href="../OptionalTasks/script.html">Script</a> task for
+an explanation of scripts and dependencies.
+</p>
+<p>
+The script is provided with an object <i>self</i> that has
+getToken() and setToken(String) methods.
+The getToken() method returns the current token. The setToken(String)
+method replaces the current token.
+</p>
+
+This filter may be used directly within a filterchain.<p>
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>language</td>
+    <td vAlign=top> The programming language the script is written in.
+Must be a supported Apache BSF or JSR 223 language</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">manager</td>
+    <td valign="top">
+      The script engine manager to use.
+      See the <a href="../OptionalTasks/script.html">script</a> task
+      for using this attribute.
+    </td>
+    <td valign="top" align="center">No - default is "auto"</td>
+  </tr>
+  <tr>
+    <td vAlign=top>src</td>
+    <td vAlign=top>The location of the script as a file, if not inline
+    </td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">setbeans</td>
+    <td valign="top">whether to have all properties, references and targets as
+      global variables in the script.</td>
+    <td valign="top" align="center">No, default is "true".</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">
+      The classpath to pass into the script.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a
+       <a href="../using.html#references">reference</a> to a path defined elsewhere.
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+  <p>
+    This filter can take a nested &lt;classpath&gt; element.
+    See the <a href="../OptionalTasks/script.html">script</a> task
+    on how to use this element.
+  </p>
+<h4>Examples:</h4>
+
+Convert to uppercase:
+<blockquote><pre>
+&lt;tokenfilter&gt;
+    &lt;scriptfilter language="javascript"&gt;
+        self.setToken(self.getToken().toUpperCase());
+    &lt;/scriptfilter&gt;
+&lt;/tokenfilter&gt;
+</pre></blockquote>
+
+Remove lines containing the string "bad" while
+copying text files:
+  <blockquote>
+    <pre>
+&lt;copy todir="dist"&gt;
+  &lt;fileset dir="src" includes="**/*.txt"/&gt;
+  &lt;filterchain&gt;
+    &lt;scriptfilter language="beanshell"&gt;
+        if (self.getToken().indexOf("bad") != -1) {
+            self.setToken(null);
+        }
+    &lt;/scriptfilter&gt;
+  &lt;/filterchain&gt;
+&lt;/copy&gt;
+    </pre>
+  </blockquote>
+
+<h4>Custom tokenizers and string filters</h4>
+
+Custom string filters and tokenizers may be plugged in by
+extending the interfaces org.apache.tools.ant.filters.TokenFilter.Filter
+and org.apache.tools.ant.util.Tokenizer respectly.
+
+They are defined the build file using <code>&lt;typedef/&gt;</code>. For
+example a string filter that capitalizes words may be declared as:
+<blockquote><pre>
+package my.customant;
+import org.apache.tools.ant.filters.TokenFilter;
+
+public class Capitalize
+    implements TokenFilter.Filter
+{
+    public String filter(String token) {
+        if (token.length() == 0)
+            return token;
+        return token.substring(0, 1).toUpperCase() +
+                token.substring(1);
+   }
+}
+</pre></blockquote>
+
+This may be used as follows:
+<blockquote><pre>
+  &lt;typedef type="capitalize" classname="my.customant.Capitalize"
+           classpath="my.customant.path"/&gt;
+  &lt;copy file="input" tofile="output"&gt;
+    &lt;filterchain&gt;
+      &lt;tokenfilter&gt;
+        &lt;stringtokenizer/&gt;
+        &lt;capitalize/&gt;
+      &lt;/tokenfilter&gt;
+    &lt;/filterchain&gt;
+  &lt;/copy&gt;
+</pre></blockquote>
+
+</body></html>
diff --git a/trunk/docs/manual/CoreTypes/filterset.html b/trunk/docs/manual/CoreTypes/filterset.html
new file mode 100644
index 0000000..468b450
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/filterset.html
@@ -0,0 +1,181 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FilterSet Type</title>
+</head>
+
+<body>
+<h2><a name="filterset">FilterSet</a></h2>
+
+<p>FilterSets are groups of filters. Filters can be defined as token-value
+pairs 
+or be read in from a file. FilterSets can appear inside tasks that support this 
+feature or at the same level as <code>&lt;target&gt;</code> - i.e., as
+children of 
+<code>&lt;project&gt;</code>.</p>
+
+<p>FilterSets support the <code>id</code> and <code>refid</code>
+attributes.  You can define a FilterSet with an <code>id</code>
+attribute and then refer to that definition from another FilterSet
+with a <code>refid</code> attribute.  It is also possible to nest
+filtersets into filtersets to get a set union of the contained
+filters.</p>
+
+<p>In addition, FilterSets can specify
+<code>begintoken</code> and/or 
+<code>endtoken</code> attributes to define what to match.</p>
+<p>Filtersets are used for doing 
+replacements in tasks such as <code>&lt;copy&gt;</code>, etc.</p>
+
+<p>
+<strong>Note: </strong>When a filterset is used in an operation, the files are 
+processed in text mode and the filters applied line by line. This means that
+the copy operations will typically corrupt binary files. When applying filters
+you should ensure that the set of files being filtered are all text files.
+</p>
+
+<h2>Filterset</h2>
+
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top><b>Default</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>begintoken</td>
+    <td vAlign=top>The string marking the beginning of a token (eg.,
+      <code>&#64;DATE&#64;</code>).</td>
+    <td vAlign=top>@</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>endtoken</td>
+    <td vAlign=top>The string marking the end of a token (eg.,
+      <code>&#64;DATE&#64;</code>).</td>
+    <td vAlign=top>@</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>filtersfile</td>
+    <td vAlign=top>Specify a single filtersfile.</td>
+    <td vAlign=top><i>none</i></td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>recurse</td>
+    <td vAlign=top>Indicates whether the replacement text of tokens
+      should be searched for more tokens. <b>Since Ant 1.6.3</b></td>
+    <td vAlign=top><i>true</i></td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+  <tr>
+    <td vAlign=top>onmissingfiltersfile</td>
+    <td vAlign=top>Indicate behavior when a nonexistent <i>filtersfile</i>
+      is specified.  One of "fail", "warn", "ignore". <b>Since Ant 1.7</b></td>
+    <td vAlign=top>"fail"</td>
+    <td vAlign=top align="center">No</td>
+  </tr>
+</table>
+
+<h2>Filter</h2>
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>token</td>
+    <td vAlign=top>The token to replace (eg., <code>&#64;DATE&#64;</code>)</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+  <tr>
+    <td vAlign=top>value</td>
+    <td vAlign=top>The value to replace it with
+     (eg., <code>Thursday, April 26, 2001</code>).</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+
+<h2>Filtersfile</h2>
+<table cellSpacing=0 cellPadding=2 border=1>
+  <tr>
+    <td vAlign=top><b>Attribute</b></td>
+    <td vAlign=top><b>Description</b></td>
+    <td vAlign=top align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td vAlign=top>file</td>
+    <td vAlign=top>A properties file of 
+      name-value pairs from which to load the tokens.</td>
+    <td vAlign=top align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>Examples</h4>
+
+<p>You are copying the <code>version.txt</code> file to the <code>dist</code>
+directory from the <code>build</code> directory 
+but wish to replace the token <code>&#64;DATE&#64;</code> with today's date.</p>
+<blockquote><pre>
+&lt;copy file=&quot;${build.dir}/version.txt&quot; toFile=&quot;${dist.dir}/version.txt&quot;&gt;
+  &lt;filterset&gt;
+    &lt;filter token=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+  &lt;/filterset&gt;
+&lt;/copy&gt;
+</pre></blockquote>
+
+<p>You are copying the <code>version.txt</code> file to the <code>dist</code>
+directory from the build directory 
+but wish to replace the token <code>%DATE*</code> with today's date.</p>
+<blockquote><pre>
+&lt;copy file=&quot;${build.dir}/version.txt&quot; toFile=&quot;${dist.dir}/version.txt&quot;&gt;
+  &lt;filterset begintoken=&quot;%&quot; endtoken=&quot;*&quot;&gt;
+    &lt;filter token=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+  &lt;/filterset&gt;
+&lt;/copy&gt;
+</pre></blockquote>
+
+<p>Copy all the docs but change all dates and appropriate notices as stored in a file.</p>
+<blockquote><pre>
+&lt;copy toDir=&quot;${dist.dir}/docs&quot;&gt;
+  &lt;fileset dir=&quot;${build.dir}/docs&quot;&gt;
+    &lt;include name=&quot;**/*.html&quot;&gt;
+  &lt;/fileset&gt;
+  &lt;filterset begintoken=&quot;%&quot; endtoken=&quot;*&quot;&gt;
+    &lt;filtersfile file=&quot;${user.dir}/dist.properties&quot;/&gt;
+  &lt;/filterset&gt;
+&lt;/copy&gt;
+</pre></blockquote>
+
+<p>Define a FilterSet and reference it later.</p>
+<blockquote><pre>
+&lt;filterset id=&quot;myFilterSet&quot; begintoken=&quot;%&quot; endtoken=&quot;*&quot;&gt;
+  &lt;filter token=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+&lt;/filterset&gt;
+
+&lt;copy file=&quot;${build.dir}/version.txt&quot; toFile=&quot;${dist.dir}/version.txt&quot;&gt;
+  &lt;filterset refid=&quot;myFilterSet&quot;/&gt;
+&lt;/copy&gt;
+</pre></blockquote>
+</body></html>
diff --git a/trunk/docs/manual/CoreTypes/mapper.html b/trunk/docs/manual/CoreTypes/mapper.html
new file mode 100644
index 0000000..914c1ea
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/mapper.html
@@ -0,0 +1,888 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Mapper Type</title>
+</head>
+
+<body>
+
+<h2><a name="mapper">Mapping File Names</a></h2>
+<p>Some tasks take source files and create target files. Depending on
+the task, it may be quite obvious which name a target file will have
+(using <a href="../CoreTasks/javac.html">javac</a>, you know there will be
+<code>.class</code> files for your <code>.java</code> files) - in
+other cases you may want to specify the target files, either to help
+Ant or to get an extra bit of functionality.</p>
+<p>While source files are usually specified as <a
+href="fileset.html">fileset</a>s, you don't specify target files directly -
+instead, you tell Ant how to find the target file(s) for one source file. An
+instance of <code>org.apache.tools.ant.util.FileNameMapper</code> is
+responsible for this. It constructs target file names based on rules
+that can be parameterized with <code>from</code> and <code>to</code>
+attributes - the exact meaning of which is implementation-dependent.</p>
+<p>These instances are defined in <code>&lt;mapper&gt;</code> elements
+with the following attributes:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">specifies one of the built-in implementations.</td>
+    <td rowspan="2" align="center" valign="middle">Exactly one of these</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">specifies the implementation by class name.</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use when looking up
+      <code>classname</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use, given as <a
+      href="../using.html#references">reference</a> to a path defined elsewhere.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">from</td>
+    <td valign="top">the <code>from</code> attribute for the given
+      implementation.</td>
+    <td align="center" valign="top">Depends on implementation.</td>
+  </tr>
+  <tr>
+    <td valign="top">to</td>
+    <td valign="top">the <code>to</code> attribute for the given
+      implementation.</td>
+    <td align="center" valign="top">Depends on implementation.</td>
+  </tr>
+</table>
+<p>Note that Ant will not automatically convert / or \ characters in
+the <code>to</code> and <code>from</code> attributes to the correct
+directory separator of your current platform.  If you need to specify
+this separator, use <code>${file.separator}</code> instead.
+  For the regexpmapper, <code>${file.separator}</code> will not work,
+as on windows it is the '\' character, and this is an escape character
+for regular expressions, one should use the <code>handledirsep</code> attribute
+instead.
+</p>
+<h3>Parameters specified as nested elements</h3>
+<p>The classpath can be specified via a nested
+<code>&lt;classpath&gt;</code>, as well - that is,
+a <a href="../using.html#path">path</a>-like structure.</p>
+<p><b>Since Ant 1.6.2,</b> nested File Mappers can
+be supplied via either <CODE>&lt;mapper&gt;</CODE> elements or
+<a href="../CoreTasks/typedef.html"><code>&lt;typedef&gt;</code></a>'d
+implementations of <CODE>org.apache.tools.ant.util.FileNameMapper</CODE>.
+If nested File Mappers are specified by either means, the mapper will be
+implicitly configured as a <a href="#composite-mapper">composite mapper</a>.
+</p>
+<hr>
+<h3>The built-in mapper types are:</h3>
+<p>All built-in mappers are case-sensitive.</p>
+<p><b>As of Ant 1.6.2,</b> each of the built-in mapper implementation
+  types is directly accessible using a specific tagname. This makes it
+  possible for filename mappers to support attributes in addition to
+  the generally available <i>to</i> and <i>from</i>.<br>
+  The <code>&lt;mapper type|classname=&quot;...&quot;&gt;</code> usage
+  form remains valid for reasons of backward compatibility.</p>
+
+    <!--                                        -->
+    <!--             Identity Mapper            -->
+    <!--                                        -->
+
+<h4><a name="identity-mapper">identity</a></h4>
+<p>The target file name is identical to the source file name. Both
+<code>to</code> and <code>from</code> will be ignored.</p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;mapper type=&quot;identity&quot;/&gt;
+&lt;identitymapper/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>A.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top"><code>C.properties</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+  </tr>
+</table>
+
+    <!--                                        -->
+    <!--             Flatten Mapper             -->
+    <!--                                        -->
+
+<h4><a name="flatten-mapper">flatten</a></h4>
+<p>The target file name is identical to the source file name, with all
+leading directory information stripped off. Both <code>to</code> and
+<code>from</code> will be ignored.</p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;mapper type=&quot;flatten&quot;/&gt;
+&lt;flattenmapper/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>A.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>B.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top"><code>C.properties</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>A.properties</code></td>
+  </tr>
+</table>
+
+    <!--                                        -->
+    <!--             Merge Mapper               -->
+    <!--                                        -->
+
+<h4><a name="merge-mapper">merge</a></h4>
+<p>The target file name will always be the same, as defined by
+<code>to</code> - <code>from</code> will be ignored.</p>
+<h5>Examples:</h5>
+<blockquote><pre>
+&lt;mapper type=&quot;merge&quot; to=&quot;archive.tar&quot;/&gt;
+&lt;mergemapper to=&quot;archive.tar&quot;/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>archive.tar</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>archive.tar</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top"><code>archive.tar</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>archive.tar</code></td>
+  </tr>
+</table>
+
+    <!--                                        -->
+    <!--              Glob Mapper               -->
+    <!--                                        -->
+
+<h4><a name="glob-mapper">glob</a></h4>
+<p>Both <code>to</code> and <code>from</code> define patterns that may
+contain at most one <code>*</code>. For each source file that matches
+the <code>from</code> pattern, a target file name will be constructed
+from the <code>to</code> pattern by substituting the <code>*</code> in
+the <code>to</code> pattern with the text that matches the
+<code>*</code> in the <code>from</code> pattern. Source file names
+that don't match the <code>from</code> pattern will be ignored.</p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;mapper type=&quot;glob&quot; from=&quot;*.java&quot; to=&quot;*.java.bak&quot;/&gt;
+&lt;globmapper from=&quot;*.java&quot; to=&quot;*.java.bak&quot;/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>A.java.bak</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>foo/bar/B.java.bak</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;mapper type=&quot;glob&quot; from=&quot;C*ies&quot; to=&quot;Q*y&quot;/&gt;
+&lt;globmapper from=&quot;C*ies&quot; to=&quot;Q*y&quot;/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top"><code>Q.property</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>Qlasses/dir/dir2/A.property</code></td>
+  </tr>
+</table>
+  <p>
+    The globmapper mapper can take the following extra attributes.
+  </p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">casesensitive</td>
+      <td valign="top">
+        If this is false, the mapper will ignore case when matching the glob pattern.
+        This attribute can be true or false, the default is true.
+      <em>Since Ant 1.6.3.</em>
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">handledirsep</td>
+      <td valign="top">
+        If this is specified, the mapper will ignore the difference between the normal
+        directory separator characters - \ and /.
+        This attribute can be true or false, the default is false.
+        This attribute is useful for cross-platform build files.
+        <em>Since Ant 1.6.3.</em>
+        <td align="center" valign="top">No</td>
+      </tr>
+    </table>
+    <p>
+      An example:
+    </p>
+    <pre>
+      &lt;pathconvert property="x" targetos="unix"&gt;
+        &lt;path path="Aj.Java"/&gt;
+        &lt;mapper&gt;
+        &lt;chainedmapper&gt;
+          &lt;flattenmapper/&gt;
+          &lt;globmapper from="a*.java" to="*.java.bak" casesensitive="no"/&gt;
+        &lt;/chainedmapper&gt;
+        &lt;/mapper&gt;
+      &lt;/pathconvert&gt;
+      &lt;echo&gt;x is ${x}&lt;/echo&gt;
+    </pre>
+    <p>
+      will output "x is j.java.bak".
+    </p>
+    <p>
+      and
+    </p>
+    <pre>
+      &lt;pathconvert property="x" targetos="unix"&gt;
+        &lt;path path="d/e/f/j.java"/&gt;
+        &lt;mapper&gt;
+          &lt;globmapper from="${basedir}\d/e\*" to="*" ignoredirchar="yes"/&gt;
+        &lt;/mapper&gt;
+      &lt;/pathconvert&gt;
+      &lt;echo&gt;x is ${x}&lt;/echo&gt;
+    </pre>
+    <p>
+      will output "x is f/j.java".
+    </p>
+
+
+    <!--                                        -->
+    <!--             RegExp Mapper              -->
+    <!--                                        -->
+
+<h4><a name="regexp-mapper">regexp</a></h4>
+<p>Both <code>to</code> and <code>from</code> define regular
+expressions. If the source file name matches the <code>from</code>
+pattern, the target file name will be constructed from the
+<code>to</code> pattern, using <code>\0</code> to <code>\9</code> as
+back-references for the full
+match (<code>\0</code>) or the matches of the subexpressions in
+parentheses.
+Source
+files not matching the <code>from</code> pattern will be ignored.</p>
+<p>Note that you need to escape a dollar-sign (<code>$</code>) with
+another dollar-sign in Ant.</p>
+<p>The regexp mapper needs a supporting library and an implementation
+of <code>org.apache.tools.ant.util.regexp.RegexpMatcher</code> that
+hides the specifics of the library. Ant comes with implementations for
+<a href="http://java.sun.com/j2se/1.4/docs/api/java/util/regex/package-summary.html"  target="_top">the java.util.regex package of JDK 1.4 or higher</a>,
+<a href="http://jakarta.apache.org/regexp/" target="_top">jakarta-regexp</a> and <a
+href="http://jakarta.apache.org/oro/" target="_top">jakarta-ORO</a>. If you compile
+from sources and plan to use one of them, make sure the libraries are
+in your <code>CLASSPATH</code>. For information about using <a
+href="http://www.cacas.org/~wes/java/" target="_top">gnu.regexp</a> or <a
+href="http://www.crocodile.org/~sts/Rex/" target="_top">gnu.rex</a> with Ant, see <a
+href="http://marc.theaimsgroup.com/?l=ant-dev&m=97550753813481&w=2" target="_top">this</a>
+article.</p>
+<p>This means, you need one of the supported regular expression
+  libraries <strong>and</strong>
+  the corresponding <code>ant-[jakarta-oro, jakarta-regexp, apache-oro, apache-regexp}.jar</code>
+from the Ant release you are using.
+Make sure, both will be loaded from the same
+classpath, that is either put them into your <code>CLASSPATH</code>,
+<code>ANT_HOME/lib</code> directory or a nested
+<code>&lt;classpath&gt;</code> element of the mapper - you cannot have
+<code>ant-[jakarta-oro, jakarta-regexp, apache-oro, apache-regexp].jar</code> in <code>ANT_HOME/lib</code>
+ and the library
+in a nested <code>&lt;classpath&gt;</code>.</p>
+<p>Ant will choose the regular-expression library based on the
+following algorithm:</p>
+<ul>
+<li>If the system property
+<code>ant.regexp.matcherimpl</code> has been set, it is taken as the
+name of the class implementing
+<code>org.apache.tools.ant.util.regexp.RegexpMatcher</code> that
+should be used.</li>
+<li>If it has not been set, first try the JDK 1.4 classes, then
+jakarta-ORO and finally try jakarta-regexp.</li>
+</ul>
+
+<b>Examples:</b>
+<blockquote><pre>
+&lt;mapper type=&quot;regexp&quot; from=&quot;^(.*)\.java$$&quot; to=&quot;\1.java.bak&quot;/&gt;
+&lt;regexpmapper from=&quot;^(.*)\.java$$&quot; to=&quot;\1.java.bak&quot;/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>A.java.bak</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>foo/bar/B.java.bak</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;mapper type=&quot;regexp&quot; from=&quot;^(.*)/([^/]+)/([^/]*)$$&quot; to=&quot;\1/\2/\2-\3&quot;/&gt;
+&lt;regexpmapper from=&quot;^(.*)/([^/]+)/([^/]*)$$&quot; to=&quot;\1/\2/\2-\3&quot;/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>foo/bar/bar-B.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>Classes/dir/dir2/dir2-A.properties</code></td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;mapper type="regexp" from="^(.*)\.(.*)$$" to="\2.\1"/&gt;
+&lt;regexpmapper from="^(.*)\.(.*)$$&" to="\2.\1"/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>A.java</code></td>
+    <td valign="top"><code>java.A</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo/bar/B.java</code></td>
+    <td valign="top"><code>java.foo/bar/B</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>C.properties</code></td>
+    <td valign="top"><code>properties.C</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>Classes/dir/dir2/A.properties</code></td>
+    <td valign="top"><code>properties.Classes/dir/dir2/A</code></td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;mapper type="regexp" from="^(.*?)(\$$[^/\\\.]*)?\.class$$" to="\1.java"/&gt;
+&lt;regexpmapper from="^(.*?)(\$$[^/\\\.]*)?\.class$$" to="\1.java"/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>ClassLoader.class</code></td>
+    <td valign="top"><code>ClassLoader.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>java/lang/ClassLoader.class</code></td>
+    <td valign="top"><code>java/lang/ClassLoader.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>java\lang\ClassLoader$1.class</code></td>
+    <td valign="top"><code>java\lang\ClassLoader.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>java/lang/ClassLoader$foo$1.class</code></td>
+    <td valign="top"><code>java/lang/ClassLoader.java</code></td>
+  </tr>
+</table>
+  <p>
+    The regexpmapper mapper can take the following extra attributes.
+  </p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">casesensitive</td>
+      <td valign="top">
+        If this is false, the mapper will ignore case when matching the pattern.
+        This attribute can be true or false, the default is true.
+      <em>Since Ant 1.6.3.</em>
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">handledirsep</td>
+      <td valign="top">
+        If this is specified, the mapper will treat a \ character in a filename
+        as a / for the purposes of matching.
+        This attribute can be true or false, the default is false.
+        This attribute is useful for cross-platform build files.
+        <em>Since Ant 1.6.3.</em>
+        <td align="center" valign="top">No</td>
+      </tr>
+    </table>
+    <p>
+      An example:
+    </p>
+    <pre>
+      &lt;pathconvert property="x" targetos="unix"&gt;
+        &lt;path path="Aj.Java"/&gt;
+        &lt;chainedmapper&gt;
+          &lt;flattenmapper/&gt;
+          &lt;regexpmapper from="a(.*)\.java" to="\1.java.bak" casesensitive="no"/&gt;
+        &lt;/chainedmapper&gt;
+      &lt;/pathconvert&gt;
+      &lt;echo&gt;x is ${x}&lt;/echo&gt;
+    </pre>
+    <p>
+      will output "x is j.java.bak".
+    </p>
+    <p>
+      and
+    </p>
+    <pre>
+    &lt;pathconvert property="hd.prop" targetos="windows"&gt;
+      &lt;path path="d\e/f\j.java"/&gt;
+      &lt;chainedmapper&gt;
+        &lt;regexpmapper from="${basedir}/d/e/(.*)" to="\1" handledirsep="yes"/&gt;
+      &lt;/chainedmapper&gt;
+    &lt;/pathconvert&gt;
+    </pre>
+    <p>
+      will set <code>hd.prop</code> to "f\j.java".
+    </p>
+
+    <!--                                        -->
+    <!--             Package Mapper             -->
+    <!--                                        -->
+
+<h4><a name="package-mapper">package</a></h4>
+<p>Sharing the same syntax as the <a href="#glob-mapper">glob mapper</a>,
+the package mapper replaces
+directory separators found in the matched source pattern with dots in the target
+pattern placeholder. This mapper is particularly useful in combination
+with <code>&lt;uptodate&gt;</code> and <code>&lt;junit&gt;</code> output.</p>
+<b>Example:</b>
+<blockquote><pre>
+&lt;mapper type="package" from="*Test.java" to="TEST-*Test.xml"/&gt;
+&lt;packagemapper from="*Test.java" to="TEST-*Test.xml"/&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>org/apache/tools/ant/util/PackageMapperTest.java</code></td>
+    <td valign="top"><code>TEST-org.apache.tools.ant.util.PackageMapperTest.xml</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>org/apache/tools/ant/util/Helper.java</code></td>
+    <td valign="top">ignored</td>
+  </tr>
+</table>
+
+    <!--                                        -->
+    <!--           Unpackage Mapper             -->
+    <!--                                        -->
+
+<h4><a name="unpackage-mapper">unpackage (since Ant 1.6.0)</a></h4>
+  <p>This mapper is the inverse of the <a href="#package-mapper">package</a> mapper.
+    It replaces the dots in a package name with directory separators. This
+    is useful for matching XML formatter results against their JUnit test
+    test cases. The mapper shares the sample syntax
+    as the <a href="#glob-mapper">glob mapper</a>.
+  </p>
+<b>Example:</b>
+<blockquote><pre>
+&lt;mapper type="unpackage" from="TEST-*Test.xml" to="${test.src.dir}/*Test.java"&gt;
+&lt;unpackagemapper from="TEST-*Test.xml" to="${test.src.dir}/*Test.java"&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file name</b></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>TEST-org.acme.AcmeTest.xml</code></td>
+    <td valign="top"><code>${test.src.dir}/org/acme/AcmeTest.java</code></td>
+  </tr>
+</table>
+
+    <!--                                        -->
+    <!--           Composite Mapper             -->
+    <!--                                        -->
+
+<h4><a name="composite-mapper">composite (since Ant 1.6.2)</a></h4>
+  <p>This mapper implementation can contain multiple nested mappers.
+    File mapping is performed by passing the source filename to each nested
+    <code>&lt;mapper&gt;</code> in turn, returning all results.
+    The <i>to</i> and <i>from</i> attributes are ignored.</p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;compositemapper&gt;
+  &lt;identitymapper/&gt;
+  &lt;packagemapper from="*.java" to="*"/&gt;
+&lt;/compositemapper&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file names</b></td>
+  </tr>
+  <tr>
+    <td valign="center" rowspan="2"><code>foo/bar/A.java</code></td>
+    <td valign="top"><code>foo/bar/A.java</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo.bar.A</code></td>
+  </tr>
+</table>
+  <p>The composite mapper has no corresponding
+    <code>&lt;mapper <b>type</b>&gt;</code> attribute.
+  </p>
+
+    <!--                                        -->
+    <!--            Chained Mapper              -->
+    <!--                                        -->
+
+<h4><a name="chained-mapper">chained (since Ant 1.6.2)</a></h4>
+  <p>This mapper implementation can contain multiple nested mappers.
+    File mapping is performed by passing the source filename to the first
+    nested mapper, its results to the second, and so on.  The target filenames
+    generated by the last nested mapper comprise the ultimate results of the
+    mapping operation.  The <i>to</i> and <i>from</i> attributes are ignored.</p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;chainedmapper&gt;
+  &lt;flattenmapper/&gt;
+  &lt;globmapper from="*" to="new/path/*"/&gt;
+  &lt;mapper&gt;
+    &lt;globmapper from="*" to="*1"/&gt;
+    &lt;globmapper from="*" to="*2"/&gt;
+  &lt;/mapper&gt;
+&lt;/chainedmapper&gt;
+</pre></blockquote>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file names</b></td>
+  </tr>
+  <tr>
+    <td valign="center" rowspan="2"><code>foo/bar/A.java</code></td>
+    <td valign="top"><code>new/path/A.java1</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>new/path/A.java2</code></td>
+  </tr>
+  <tr>
+    <td valign="center" rowspan="2"><code>boo/far/B.java</code></td>
+    <td valign="top"><code>new/path/B.java1</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>new/path/B.java2</code></td>
+  </tr>
+</table>
+  <p>The chained mapper has no corresponding
+    <code>&lt;mapper <b>type</b>&gt;</code> attribute.
+  </p>
+
+    <!--                                        -->
+    <!--             Filter Mapper              -->
+    <!--                                        -->
+
+<h4><a name="filter-mapper">filtermapper (since Ant 1.6.3)</a></h4>
+    <p>
+      This mapper implementation applies a <a href="filterchain.html">filterchain</a>
+      to the source file name.
+    </p>
+<b>Examples:</b>
+<blockquote><pre>
+&lt;filtermapper&gt;
+  &lt;replacestring from="\" to="/"/&gt;
+&lt;/filtermapper&gt;
+</pre></blockquote>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file names</b></td>
+  </tr>
+  <tr>
+    <td valign="center"><code>foo\bar\A.java</code></td>
+    <td valign="top"><code>foo/bar/A.java</code></td>
+  </tr>
+</table>
+<blockquote><pre>
+&lt;filtermapper&gt;
+  &lt;scriptfilter language="beanshell"&gt;
+    self.setToken(self.getToken().toUpperCase());
+  &lt;/scriptfilter&gt;
+&lt;/filtermapper&gt;
+</pre></blockquote>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file names</b></td>
+  </tr>
+  <tr>
+    <td valign="center"><code>foo\bar\A.java</code></td>
+    <td valign="top"><code>FOO\BAR\A.JAVA</code></td>
+  </tr>
+</table>
+
+  <p>The filtermapper has no corresponding
+    <code>&lt;mapper <b>type</b>&gt;</code> attribute.
+  </p>
+
+    <!--                                        -->
+    <!--             Script Mapper              -->
+    <!--                                        -->
+
+<h4><a name="script-mapper">scriptmapper (since Ant 1.7)</a></h4>
+<p>
+This mapper executes a script written in <a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+or
+  <a href="https://scripting.dev.java.net">JSR 223</a>
+supported language, once per file to map.</p>
+The script can be declared inline or in a specified file.
+</p>
+<p>
+See the <a href="../OptionalTasks/script.html">Script</a> task for
+an explanation of scripts and dependencies.
+</p>
+
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">language</td>
+      <td valign="top">
+        Scripting language
+      </td>
+      <td align="center" valign="top">Yes</td>
+    </tr>
+    <tr>
+      <td valign="top">manager</td>
+      <td valign="top">
+        The script engine manager to use.
+        See the <a href="../OptionalTasks/script.html">script</a> task
+        for using this attribute.
+      </td>
+      <td valign="top" align="center">No - default is "auto"</td>
+    </tr>
+    <tr>
+      <td valign="top">src</td>
+      <td valign="top">
+        File containing the script
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">setbeans</td>
+      <td valign="top">whether to have all properties, references and targets as
+        global variables in the script.</td>
+      <td valign="top" align="center">No, default is "true".</td>
+    </tr>
+    <tr>
+      <td valign="top">classpath</td>
+      <td valign="top">
+        The classpath to pass into the script.
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">classpathref</td>
+      <td valign="top">The classpath to use, given as a
+        <a href="../using.html#references">reference</a> to a path defined elsewhere.
+        <td align="center" valign="top">No</td>
+      </tr>
+    </table>
+  <p>
+    This filename mapper can take a nested &lt;classpath&gt; element.
+    See the <a href="../OptionalTasks/script.html">script</a> task
+    on how to use this element.
+  </p>
+
+<p>
+  <b>Example:</b>
+</p>
+<blockquote><pre>
+&lt;scriptmapper language="javascript"&gt;
+  self.addMappedName(source.toUpperCase());
+  self.addMappedName(source.toLowerCase());
+&lt;/scriptmapper&gt;
+</pre></blockquote>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Source file name</b></td>
+    <td valign="top"><b>Target file names</b></td>
+  </tr>
+  <tr>
+    <td valign="center" rowspan="2"><code>foo\bar\A.java</code></td>
+    <td valign="top"><code>FOO\BAR\A.JAVA</code></td>
+  </tr>
+  <tr>
+    <td valign="top"><code>foo\bar\a.java</code></td>
+  </tr>
+</table>
+
+<p>
+To use this mapper, the scripts need access to the source file,
+and the ability to return multiple mappings. Here are the relevant beans and
+their methods. The script is called once for every source file, with the
+list of mapped names reset after every invocation.
+
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Script bean</b></td>
+      <td valign="top"><b>Description</b></td>
+    </tr>
+    <tr>
+      <td valign="top"><code>source: String</code></td>
+      <td valign="top">
+        The file/path to map
+      </td>
+    </tr>
+    <tr>
+      <td valign="top"><code>self</code></td>
+      <td valign="top">
+        the scriptmapper itself
+      </td>
+    </tr>
+    <tr>
+      <td valign="top"><code>self.addMappedName(String name)</code></td>
+      <td valign="top">
+        Add a new mapping
+      </td>
+    </tr>
+    <tr>
+      <td valign="top"><code>self.clear()</code></td>
+      <td valign="top">
+        Reset the list of files.
+      </td>
+    </tr>
+    </table>
+
+  <p>The scriptmapper has no corresponding
+    <code>&lt;mapper <b>type</b>&gt;</code> attribute.
+  </p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/namespace.html b/trunk/docs/manual/CoreTypes/namespace.html
new file mode 100644
index 0000000..9e84245
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/namespace.html
@@ -0,0 +1,220 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html><head><link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>XmlNamespaceSupport</title></head>
+  <body>
+    <h2><a name="namespace">XML Namespace Support</a></h2>
+    Ant 1.6 introduces support for XML namespaces. 
+    <h3>History</h3>
+    
+    <p>
+      All releases of Ant prior to Ant 1.6 do not support XML namespaces.
+      No support basically implies two things here:
+    </p>
+    <ul>
+      <li> Element names correspond to the "qname" of the tags, which is
+        usually the same as the local name. But if the build file writer uses
+        colons in names of defined tasks/types, those become part of the
+        element name. Turning on namespace support gives colon-separated
+        prefixes in tag names a special meaning, and thus build files using
+        colons in user-defined tasks and types will break.
+      </li>
+      <li> Attributes with the names 'xmlns' and 'xmlns:<code>&lt;prefix&gt;</code>'
+        are not treated specially, which means that custom tasks and types have
+        actually been able to use such attributes as parameter names. Again,
+        such tasks/types are going to break when namespace support is enabled
+        on the parser.
+      </li>
+    </ul>
+    <p>Use of colons in element names has been discouraged in the past,
+      and using any attribute starting with "xml" is actually strongly
+      discouraged by the XML spec to reserve such names for future use.
+    </p>
+    <h3>Motivation</h3>
+
+    <p>In build files using a lot of custom and third-party tasks, it is
+      easy to get into name conflicts. When individual types are defined, the
+      build file writer can do some namespacing manually (for example, using
+      "tomcat-deploy" instead of just "deploy"). But when defining whole
+      libraries of types using the <code>&lt;typedef&gt;</code> 'resource' attribute, the
+      build file writer has no chance to override or even prefix the names
+      supplied by the library. </p>
+    <h3>Assigning Namespaces</h3>
+
+    <p>
+      Adding a 'prefix' attribute to <code>&lt;typedef&gt;</code> might have been enough,
+      but XML already has a well-known method for namespacing. Thus, instead
+      of adding a 'prefix' attribute, the <code>&lt;typedef&gt;</code> and <code>&lt;taskdef&gt;</code>
+      tasks get a 'uri' attribute, which stores the URI of the XML namespace
+      with which the type should be associated:
+    </p><pre> &lt;typedef resource="org/example/tasks.properties" uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+ &lt;my:task xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+    ...
+ &lt;/my:task&gt;
+</pre>
+    <p>As the above example demonstrates, the namespace URI needs to be
+      specified at least twice: one time as the value of the 'uri' attribute,
+      and another time to actually map the namespace to occurrences of
+      elements from that namespace, by using the 'xmlns' attribute. This
+      mapping can happen at any level in the build file:
+    </p><pre> &lt;project name="test" xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt; 
+   &lt;typedef resource="org/example/tasks.properties" uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+   &lt;my:task&gt;
+     ...
+   &lt;/my:task&gt;
+ &lt;/project&gt;
+</pre>
+    <p>
+      Use of a namespace prefix is of course optional. Therefore
+      the example could also look like this:
+    </p><pre> &lt;project name="test"&gt; 
+   &lt;typedef resource="org/example/tasks.properties" uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+   &lt;task xmlns="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+     ...
+   &lt;/task&gt;
+ &lt;/project&gt;
+</pre>
+    <p>
+      Here, the namespace is set as the default namespace for the <code>&lt;task&gt;</code>
+      element and all its descendants.
+    </p>
+    <h3>Default namespace</h3>
+    <p>
+      The default namespace used by Ant is "antlib:org.apache.tools.ant".
+    </p>
+    <pre>
+&lt;typedef resource="org/example/tasks.properties" uri="antlib:org.apache.tools.ant"/&gt;
+&lt;task&gt;
+      ....
+&lt;/task&gt;
+    </pre>
+
+     
+
+    <h3>Namespaces and Nested Elements</h3>
+
+    <p>
+      Almost always in Ant 1.6, elements nested inside a namespaced
+      element have the same namespace as their parent. So if 'task' in the
+      example above allowed a nested 'config' element, the build file snippet
+      would look like this:
+    </p><pre> &lt;typedef resource="org/example/tasks.properties" uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+ &lt;my:task xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+   &lt;my:config a="foo" b="bar"/&gt;
+   ...
+ &lt;/my:task&gt;
+</pre>
+    <p>If the element allows or requires a lot of nested elements, the
+      prefix needs to be used for every nested element. Making the namespace
+      the default can reduce the verbosity of the script:
+    </p><pre> &lt;typedef resource="org/example/tasks.properties" uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+          &lt;task xmlns="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+          &lt;config a="foo" b="bar"/&gt;
+   ...
+          &lt;/task&gt;
+        </pre>
+    <p>
+      From Ant 1.6.2, elements nested inside a namespaced element may also be
+      in Ant's default namespace. This means that the following is now allowed:
+    </p>
+    </p><pre> &lt;typedef resource="org/example/tasks.properties"
+   uri="<a href="http://example.org/tasks">http://example.org/tasks</a>"/&gt;
+ &lt;my:task xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+   &lt;config a="foo" b="bar"/&gt;
+   ...
+ &lt;/my:task&gt;
+</pre>
+      
+    <h3>Namespaces and Attributes</h3>
+
+    <p>
+      Attributes are only used to configure the element they belong to if:
+    </p>
+    <ul>
+      <li> they have no namespace (note that the default namespace does *not* apply to attributes)
+      </li>
+      <li> they are in the same namespace as the element they belong to
+      </li>
+    </ul>
+    <p>
+      Other attributes are simply ignored.
+    </p>
+    <p>
+      This means that both:
+    </p>
+    <p>
+    </p><pre> &lt;my:task xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+   &lt;my:config a="foo" b="bar"/&gt;
+   ...
+ &lt;/my:task&gt;
+</pre>
+    <p>
+      and
+    </p>
+    <pre> &lt;my:task xmlns:my="<a href="http://example.org/tasks">http://example.org/tasks</a>"&gt;
+   &lt;my:config my:a="foo" my:b="bar"/&gt;
+   ...
+ &lt;/my:task&gt;
+</pre>
+    <p>
+      result in the parameters "a" and "b" being used as parameters to configure the nested "config" element.
+    </p>
+    <p>It also means that you can use attributes from other namespaces
+      to markup the build file with extra metadata, such as RDF and
+      XML-Schema (whether that's a good thing or not). The same is not true
+      for elements from unknown namespaces, which result in a error.
+    </p>
+    <h3>Mixing Elements from Different Namespaces</h3>
+
+    <p>Now comes the difficult part: elements from different namespaces can
+      be woven together under certain circumstances. This has a lot to do
+      with the Ant 1.6
+      <a href="../develop.html#nestedtype">add type introspection rules</a>:
+      Ant types and tasks are now free to accept arbritrary named types as
+      nested elements, as long as the concrete type implements the interface
+      expected by the task/type. The most obvious example for this is the
+      <code>&lt;condition&gt;</code> task, which supports various nested conditions, all
+      of which extend the interface <tt>Condition</tt>. To integrate a
+      custom condition in Ant, you can now simply <code>&lt;typedef&gt;</code> the
+      condition, and then use it anywhere nested conditions are allowed
+      (assuming the containing element has a generic <tt>add(Condition)</tt> or <tt>addConfigured(Condition)</tt> method):
+</p><pre> &lt;typedef resource="org/example/conditions.properties" uri="<a href="http://example.org/conditions">http://example.org/conditions</a>"/&gt;
+ &lt;condition property="prop" xmlns="<a href="http://example.org/conditions">http://example.org/conditions</a>"&gt;
+   &lt;and&gt;
+     &lt;available file="bla.txt"/&gt;
+     &lt;my:condition a="foo"/&gt;
+   &lt;/and&gt;
+ &lt;/condition&gt;
+</pre>
+    <p>
+      In Ant 1.6, this feature cannot be used as much as we'd all like to: a
+      lot of code has not yet been adapted to the new introspection rules,
+      and elements like Ant's built-in conditions and selectors are not
+      really types in 1.6. This is expected to change in Ant 1.7.
+    </p>
+    <h3>Namespaces and Antlib</h3>
+
+    <p>
+      The new <a href="antlib.html">AntLib</a>
+      feature is also very much integrated with the namespace support in Ant
+      1.6. Basically, you can "import" Antlibs simply by using a special
+      scheme for the namespace URI: the <tt>antlib</tt> scheme, which expects the package name in which a special <tt>antlib.xml</tt> file is located.
+    </p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/patternset.html b/trunk/docs/manual/CoreTypes/patternset.html
new file mode 100644
index 0000000..6d92caf
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/patternset.html
@@ -0,0 +1,189 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PatternSet Type</title>
+</head>
+
+<body>
+
+<h2><a name="patternset">PatternSet</a></h2>
+<p><a href="../dirtasks.html#patterns">Patterns</a> can be grouped to
+sets and later be referenced by their <code>id</code> attribute. They
+are defined via a <code>patternset</code> element, which can appear
+nested into a <a href="fileset.html">FileSet</a> or a directory-based
+task that constitutes an implicit FileSet. In addition,
+<code>patternset</code>s can be defined as a stand alone element at
+the same level as <code>target</code> &#151; i.e., as children of
+<code>project</code> as well as as children of
+<code>target</code>.</p> <p>Patterns can be specified by nested
+<code>&lt;include&gt;</code>, or <code>&lt;exclude&gt;</code> elements
+or the following attributes.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an include pattern. You can specify more than one
+      include file by using a nested includesfile elements.</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded; no files (except default excludes) are excluded when omitted.</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an exclude pattern. You can specify more than one
+      exclude file by using a nested excludesfile elements.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4><code>include</code> and <code>exclude</code></h4>
+<p>Each such element defines a single pattern for files to include or
+exclude.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the <a href="../dirtasks.html#patterns">pattern</a>
+      to in/exclude.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only use this pattern if the named property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only use this pattern if the named property is
+       <b>not</b> set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h4><code>includesfile</code> and <code>excludesfile</code></h4>
+<p>If you want to list the files to include or exclude external to
+your build file, you should use the includesfile/excludesfile
+attributes or elements.  Using the attribute, you can only specify a
+single file of each type, while the nested elements can be specified
+more than once - the nested elements also support if/unless attributes
+you can use to test the existance of a property.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the file holding the patterns to
+      in/exclude.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only read this file if the named property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only read this file if the named property is
+      <b>not</b> set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h4><code>patternset</code></h4>
+<p>Patternsets may be nested within one another, adding the nested
+patterns to the parent patternset.</p>
+<h4><code>invert</code></h4>
+<p>A nested patternset can be inverted using the <code>&lt;invert&gt;</code>
+element. <em>Since Ant 1.7.1</em></p>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;patternset id=&quot;non.test.sources&quot;&gt;
+  &lt;include name=&quot;**/*.java&quot;/&gt;
+  &lt;exclude name=&quot;**/*Test*&quot;/&gt;
+&lt;/patternset&gt;
+</pre></blockquote>
+<p>Builds a set of patterns that matches all <code>.java</code> files
+that do not contain the text <code>Test</code> in their name. This set
+can be <a href="../using.html#references">referred</a> to via
+<code>&lt;patternset refid=&quot;non.test.sources&quot;/&gt;</code>,
+by tasks that support this feature, or by FileSets.</p>
+<p>Note that while the <code>includes</code> and
+<code>excludes</code> attributes accept
+multiple elements separated by commas or spaces, the nested
+<code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code> elements expect their name
+attribute to hold a single pattern.</p>
+<p>The nested elements allow you to use if and unless arguments to
+specify that the element should only be used if a property is set, or
+that it should be used only if a property is not set.</p>
+<p>For example</p>
+<blockquote><pre>
+&lt;patternset id=&quot;sources&quot;&gt;
+  &lt;include name=&quot;std/**/*.java&quot;/&gt;
+  &lt;include name=&quot;prof/**/*.java&quot; if=&quot;professional&quot;/&gt;
+  &lt;exclude name=&quot;**/*Test*&quot;/&gt;
+&lt;/patternset&gt;
+</pre></blockquote>
+<p>will only include the files in the sub-directory <em>prof</em> if the property
+<em>professional</em> is set to some value.</p>
+<p>The two sets</p>
+<blockquote><pre>
+&lt;patternset includesfile=&quot;some-file&quot;/&gt;
+</pre></blockquote>
+<p>and</p>
+<blockquote><pre>
+&lt;patternset&gt;
+  &lt;includesfile name=&quot;some-file&quot;/&gt; 
+&lt;patternset/&gt;
+</pre></blockquote>
+<p>are identical.  The include patterns will be read from the file
+<code>some-file</code>, one pattern per line.</p>
+<blockquote><pre>
+&lt;patternset&gt;
+  &lt;includesfile name=&quot;some-file&quot;/&gt; 
+  &lt;includesfile name=&quot;${some-other-file}&quot; 
+                if=&quot;some-other-file&quot;
+  /&gt; 
+&lt;patternset/&gt;
+</pre></blockquote>
+<p>will also read include patterns from the file the property
+<code>some-other-file</code> points to, if a property of that name has
+been defined.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/permissions.html b/trunk/docs/manual/CoreTypes/permissions.html
new file mode 100644
index 0000000..a1be0f1
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/permissions.html
@@ -0,0 +1,164 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Permissions type</title>
+</head>
+
+<body>
+
+<h2><a name="permissions">Permissions</a></h2>
+<p>
+Permissions represents a set of security permissions granted or revoked to
+a specific part code executed in the JVM where ant is running in.
+The actual Permissions are specified via a set of nested permission items either
+<code>&lt;grant&gt;</code>ed or <code>&lt;revoke&gt;</code>d.</p>
+<p>
+In the base situation a <a href="#baseset">base set</a> of permissions granted. 
+Extra permissions can be
+granted. A granted permission can be overruled by revoking a permission.
+The security manager installed by the permissions will throw an 
+<code>SecurityException</code> if
+the code subject to these permissions try to use an permission that has not been 
+granted or that has been revoked.</p>
+<h3>Nested elements</h3>
+<h4>grant</h4>
+<p>
+Indicates a specific permission is always granted. Its attributes indicate which 
+permissions are granted.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">class</td>
+    <td valign="top">The fully qualified name of the Permission class.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the Permission. The actual contents depends on the
+    Permission class.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">actions</td>
+    <td valign="top">The actions allowed. The actual contents depend on the 
+    Permission class and name.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<p>
+Implied permissions are granted.
+</p>
+<p>
+Please note that some Permission classes may actually need a name and / or actions in order to function properly. The name and actions are parsed by the actual
+Permission class.
+</p>
+<h4>revoke</h4>
+<p>
+Indicates a specific permission is revoked.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">class</td>
+    <td valign="top">The fully qualified name of the Permission class.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the Permission. The actual contents depends on the
+    Permission class.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">actions</td>
+    <td valign="top">The actions allowed. The actual contents depend on the 
+    Permission class and name.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<p>
+Implied permissions are not resolved and therefore also not revoked.
+</p>
+<p>
+The name can handle the * wildcard at the end of the name, in which case all 
+permissions of the specified class of which the name starts with the specified name
+(excluding the *) are revoked. Note that the - wildcard often supported by the
+granted properties is not supported.
+If the name is left empty all names match, and are revoked.
+If the actions are left empty all actions match, and are revoked.
+</p>
+<h3><a name="baseset">Base set</a></h3>
+A permissions set implictly contains the following permissions:
+<blockquote><pre>
+&lt;grant class=&quot;java.net.SocketPermission&quot; name=&quot;localhost:1024-&quot; actions=&quot;listen&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vendor&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vendor.url&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.class.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;os.name&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;os.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;os.arch&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;file.encoding&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;file.separator&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;path.separator&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;line.separator&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.specification.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.specification.vendor&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.specification.name&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.specification.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.specification.vendor&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.specification.name&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.version&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.vendor&quot; actions=&quot;read&quot;&gt;
+&lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;java.vm.name&quot; actions=&quot;read&quot;&gt;
+</blockquote></pre>
+These permissions can be revoked via <code>&lt;revoke&gt;</code> elements if necessary.
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;permissions&gt;
+  &lt;grant class=&quot;java.security.AllPermission&quot;/&gt;
+  &lt;revoke class=&quot;java.util.PropertyPermission&quot;/&gt;
+&lt;/permissions&gt;
+</pre></blockquote>
+<p>
+Grants all permissions to the code except for those handling Properties.
+</p>
+<blockquote><pre>
+&lt;permissions&gt;
+  &lt;grant class=&quot;java.net.SocketPermission&quot; name=&quot;foo.bar.com&quot; action=&quot;connect&quot;/&gt;
+  &lt;grant class=&quot;java.util.PropertyPermission&quot; name=&quot;user.home&quot; action=&quot;read,write&quot;/&gt;
+&lt;/permissions&gt;
+</pre></blockquote>
+<p>
+Grants the base set of permissions with the addition of a SocketPermission to connect
+to foo.bar.com and the permission to read and write the user.home system property.
+</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/propertyset.html b/trunk/docs/manual/CoreTypes/propertyset.html
new file mode 100644
index 0000000..ba57649
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/propertyset.html
@@ -0,0 +1,143 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PropertySet Type</title>
+</head>
+
+<body>
+
+<h2><a name="propertyset">PropertySet</a></h2>
+<p><em>Since Ant 1.6</em></p>
+
+<p>Groups a set of properties to be used by reference in a task that
+supports this.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">dynamic</td>
+    <td valign="top">Whether to reevaluate the set everytime the set
+      is used.  Default is &quot;<code>true</code>&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">negate</td>
+    <td valign="top">Whether to negate results. If
+      &quot;<code>true</code>&quot;, all properties <i>not</i>
+      selected by nested elements will be returned. Default is
+      &quot;<code>false</code>&quot;. <em>Since Ant 1.6.2</em>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>propertyref</h4>
+
+<p>Selects properties from the current project to be included in the
+set.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Select the property with the given name.</td>
+    <td align="center" valign="top" rowspan="4">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">prefix</td>
+    <td valign="top">Select the properties whose name starts with the
+      given string.</td>
+  </tr>
+  <tr>
+    <td valign="top">regex</td>
+    <td valign="top">Select the properties that match the given
+      regular expression.  Similar to <a
+      href="mapper.html#regexp-mapper">regexp type mappers</a>, this
+      requires a supported regular expression library.</td>
+  </tr>
+  <tr>
+    <td valign="top">builtin</td>
+    <td valign="top">Selects a builtin set of properties.  Valid
+      values for this attribute are <code>all</code> for all Ant
+      properties, <code>system</code> for the system properties and
+      <code>commandline</code> for all properties specified on the
+      command line when invoking Ant (plus a number of special
+      internal Ant properties).</td>
+  </tr>
+</table>
+
+<h4>propertyset</h4>
+
+<p>A <code>propertyset</code> can be used as the set union of more
+<code>propertyset</code>s.</p>
+
+<p>For example:</p>
+
+<blockquote><pre>
+&lt;propertyset id=&quot;properties-starting-with-foo&quot;&gt;
+  &lt;propertyref prefix=&quot;foo&quot;/&gt;
+&lt;/propertyset&gt;
+&lt;propertyset id=&quot;properties-starting-with-bar&quot;&gt;
+  &lt;propertyref prefix=&quot;bar&quot;/&gt;
+&lt;/propertyset&gt;
+&lt;propertyset id=&quot;my-set&quot;&gt;
+  &lt;propertyset refid=&quot;properties-starting-with-foo&quot;/&gt;
+  &lt;propertyset refid=&quot;properties-starting-with-bar&quot;/&gt;
+&lt;/propertyset&gt;
+</pre></blockquote>
+
+<p>collects all properties whose name starts with either
+&quot;foo&quot; or &quot;bar&quot; in the set named
+&quot;my-set&quot;.</p>
+
+<h4>mapper</h4>
+
+<p>A <a href="mapper.html">mapper</a> - at maximum one mapper can be
+specified.  The mapper is used to change the names of the property
+keys, for example:
+
+<blockquote><pre>
+&lt;propertyset id=&quot;properties-starting-with-foo&quot;&gt;
+  &lt;propertyref prefix=&quot;foo&quot;/&gt;
+  &lt;mapper type=&quot;glob&quot; from=&quot;foo*&quot; to=&quot;bar*&quot;/&gt;
+&lt;/propertyset&gt;
+</pre></blockquote>
+
+<p>collects all properties whose name starts with &quot;foo&quot;, but
+changes the names to start with &quot;bar&quot; instead.</p>
+
+<p>If supplied, the nested mapper will be applied
+subsequent to any negation of matched properties.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/redirector.html b/trunk/docs/manual/CoreTypes/redirector.html
new file mode 100644
index 0000000..81dd925
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/redirector.html
@@ -0,0 +1,183 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Redirector Type</title>
+</head>
+
+<body>
+
+<h2><a name="redirector">I/O redirection</a></h2>
+<p>For many tasks, input and output can be defined in a fairly
+straightforward fashion.  The <a href="../CoreTasks/exec.html">exec</a>
+task, used to execute an external process, stands as a very
+basic example.  The executed process may accept input, produce
+output, or do either or both depending upon various circumstances.
+Output may be classified as &quot;output&quot; or as &quot;error
+output.&quot;  The <code>&lt;redirector&gt;</code> type provides a concrete means
+of redirecting input and output featuring the use of
+<a href="./mapper.html">File Mapper</a>s to specify
+source (input) and destination (output/error) files.  <em>Since Ant 1.6.2</em>
+<p>The <code>&lt;redirector&gt;</code> element accepts the following attributes:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">Name of a file to which output should be written.
+      If the error stream is not also redirected to a file or property,
+      it will appear in this output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">error</td>
+    <td valign="top">The file to which the standard error of the
+      command should be redirected.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">logError</td>
+    <td valign="top">This attribute is used when you wish to see
+      error output in Ant's log and you are redirecting output to
+      a file/property. The error output will not be included in
+      the output file/property. If you redirect error with the
+      <i>error</i> or <i>errorProperty</i> attributes, this will
+      have no effect.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Whether output and error files should be
+      appended to rather than overwritten. Defaults to
+      <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">createemptyfiles</td>
+    <td valign="top">Whether output and error files should be
+      created even when empty.  Defaults to <code>true</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputproperty</td>
+    <td valign="top">The name of a property in which the output of the
+      command should be stored. Unless the error stream is redirected
+      to a separate file or stream, this property will include the
+      error output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property in which the standard error
+      of the command should be stored.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">input</td>
+    <td valign="top">A file from which the executed command's standard input
+      is taken. This attribute is mutually exclusive with the
+      <i>inputstring</i> attribute.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inputstring</td>
+    <td valign="top">A string which serves as the input stream for the
+      executed command. This attribute is mutually exclusive with the
+      <i>input</i> attribute.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">inputencoding</td>
+    <td valign="top">The input encoding.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputencoding</td>
+    <td valign="top">The output encoding.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorencoding</td>
+    <td valign="top">The error encoding.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">alwayslog</td>
+    <td valign="top">Always send to the log in addition to
+        any other destination. <i>Since Ant 1.6.3</i>.
+    </td>
+    <td align="center" valign="top">No, default is <code>false</code></td>
+  </tr>
+  <tr>
+    <td valign="top">loginputstring</td>
+    <td valign="top">Controls the display of <i>inputstring</i>'s value in
+        log messages. Set to <code>false</code> when sending sensitive data
+        (e.g. passwords) to external processes. <i>Since Ant 1.6.3</i>.
+    </td>
+    <td align="center" valign="top">No, default is <code>true</code></td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>inputmapper</h4>
+<p>A single <a href="./mapper.html">File Mapper</a> used to redirect process
+input.  Multiple mapping results should concatenate all mapped files as input.
+Mapping will ordinarily be performed on a task-specified sourcefile;
+consult the documentation of the individual task for more details.
+A nested <code>&lt;inputmapper&gt;</code> is not compatible with either of the
+<i>input</i> or <i>inputstring</i> attributes.</p>
+<h4>outputmapper</h4>
+<p>A single <a href="./mapper.html">File Mapper</a> used to redirect process
+output.  Mapping will ordinarily be performed on a task-specified sourcefile;
+consult the documentation of the individual task for more details.
+A nested <code>&lt;outputmapper&gt;</code> is not compatible with the
+<i>output</i> attribute.</p>
+<h4>errormapper</h4>
+<p>A single <a href="./mapper.html">File Mapper</a> used to redirect error
+output.  Mapping will ordinarily be performed on a task-specified sourcefile;
+consult the documentation of the individual task for more details.
+A nested <code>&lt;errormapper&gt;</code> is not compatible with the
+<i>error</i> attribute.</p>
+<h4>inputfilterchain</h4>
+<p>A <a href="./filterchain.html">FilterChain</a> can be
+applied to the process input.</p>
+<h4>outputfilterchain</h4>
+<p>A <a href="./filterchain.html">FilterChain</a> can be
+applied to the process output.</p>
+<h4>errorfilterchain</h4>
+<p>A <a href="./filterchain.html">FilterChain</a> can be
+applied to the error output.</p>
+<h3>Usage</h3>
+Tasks known to support I/O redirection:
+<ul>
+<li><a href="../CoreTasks/exec.html">Exec</a></li>
+<li><a href="../CoreTasks/apply.html">Apply</a></li>
+<li><a href="../CoreTasks/java.html">Java</a></li>
+</ul>
+<p>The expected behavior of a <code>&lt;redirector&gt;</code> is to a great degree
+dependent on the supporting task.  Any possible points of confusion
+should be noted at the task level.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/CoreTypes/regexp.html b/trunk/docs/manual/CoreTypes/regexp.html
new file mode 100644
index 0000000..2e9f7a7
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/regexp.html
@@ -0,0 +1,112 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Regexp Type</title>
+</head>
+
+<body>
+
+<h2><a name="regexp">Regexp</a></h2>
+<p>
+Regexp represents a regular expression.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">regular expression pattern</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote><pre>
+     &lt;regexp id="myregexp" pattern="alpha(.+)beta"/&gt;<br>
+</pre></blockquote>
+<p>
+Defines a regular expression for later use with id myregexp.
+</p>
+<blockquote><pre>
+     &lt;regexp refid="myregexp"/&gt;<br>
+</pre></blockquote>
+<p>
+Use the regular expression with id myregexp.
+</p>
+<h3><a name="implementation">Choice of regular expression implementation</a></h3>
+<p>
+Ant comes with
+wrappers for
+<a href="http://java.sun.com/j2se/1.4/docs/api/java/util/regex/package-summary.html" target="_top">the java.util.regex package of JDK 1.4</a>,
+<a href="http://jakarta.apache.org/regexp/" target="_top">jakarta-regexp</a>
+and <a href="http://jakarta.apache.org/oro/" target="_top">jakarta-ORO</a>,
+See <a href="../install.html#librarydependencies">installation dependencies</a>
+ concerning the supporting libraries.</p>
+<p>
+The property <code>ant.regexp.regexpimpl</code> governs which regular expression implementation will be chosen.
+Possible values for this property are :
+<ul>
+<li>
+org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
+</li>
+<li>
+org.apache.tools.ant.util.regexp.JakartaOroRegexp
+</li>
+<li>
+org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
+</li>
+</ul>
+It can also be another implementation of the interface <code>org.apache.tools.ant.util.regexp.Regexp</code>.
+If <code>ant.regexp.regexpimpl</code> is not defined, ant checks in the order Jdk14Regexp, JakartaOroRegexp,
+ JakartaRegexp for the availability of the corresponding library. The first of these 3 which is found will be used.</p>
+<p>
+There are cross-platform issues for matches related to line terminator.
+For example if you use $ to anchor your regular expression on the end of a line
+the results might be very different depending on both your platform and the regular
+expression library you use. It is 'highly recommended' that you test your pattern on
+both Unix and Windows platforms before you rely on it.
+<ul>
+    <li>Jakarta Oro defines a line terminator as '\n' and is consistent with Perl.</li>
+    <li>Jakarta RegExp uses a system-dependant line terminator.</li>
+    <li>JDK 1.4 uses '\n', '\r\n', '\u0085', '\u2028', '\u2029' as a default
+    but is configured in the wrapper to use only '\n' (UNIX_LINE)</li>
+</ul>
+<em>We <b>strongly</b> recommend that you use Jakarta Oro.</em>
+</p>
+<h3>Usage</h3>
+The following tasks and types use the Regexp type :
+<ul>
+<li><a href="../OptionalTasks/replaceregexp.html">ReplaceRegExp task</a></li>
+<li><a href="filterchain.html#linecontainsregexp">LineContainsRegexp filter</a></li>
+</ul>
+<p>
+These string filters also use the mechanism of regexp to choose a regular expression implementation :
+</p>
+<ul>
+<li><a href="filterchain.html#containsregex">ContainsRegex string filter</a></li>
+<li><a href="filterchain.html#replaceregex">ReplaceRegex string filter</a></li>
+</ul>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/resources.html b/trunk/docs/manual/CoreTypes/resources.html
new file mode 100644
index 0000000..f15bc2f
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/resources.html
@@ -0,0 +1,983 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Resources and Resource Collections</title>
+</head>
+
+<body>
+
+<h2><a name="resource">Resources</a></h2>
+<p>
+A file-like entity can be abstracted to the concept of a <i>resource</i>.
+In addition to providing access to file-like attributes, a resource
+implementation should, when possible, provide the means to read content
+from and/or write content to the underlying entity. Although the resource
+concept was introduced in <i>Ant 1.5.2</i>, resources are available for
+explicit use beginning in <b>Ant 1.7</b>.
+</p>
+
+<h3>The built-in resource types are:</h3>
+
+<ul>
+  <li><a href="#basic">resource</a> - a basic resource.</li>
+  <li><a href="#bzip2resource">bzip2resource</a> - a BZip2 compressed resource.</li>
+  <li><a href="#file">file</a> - a file.</li>
+  <li><a href="#gzipresource">gzipresource</a> - a GZip compressed resource.</li>
+  <li><a href="#javaresource">javaresource</a> - a resource loadable
+        via a Java classloader.</li>
+  <li><a href="#propertyresource">propertyresource</a> - an Ant property.</li>
+  <li><a href="#string">string</a> - a text string.</li>
+  <li><a href="#tarentry">tarentry</a> - an entry in a tar file.</li>
+  <li><a href="#url">url</a> - a URL.</li>
+  <li><a href="#zipentry">zipentry</a> - an entry in a zip file.</li>
+</ul>
+
+<h4><a name="basic">resource</a></h4>
+
+<p>A basic resource. Other resource types derive from this basic
+type; as such all its attributes are available, though in most cases
+irrelevant attributes will be ignored. This and all resource
+implementations are also usable as single-element
+<a href="#collection">Resource Collections</a>.
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of this resource</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">exists</td>
+    <td valign="top">Whether this resource exists</td>
+    <td align="center" valign="top">No, default <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">lastmodified</td>
+    <td valign="top">The last modification time of this resource</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">directory</td>
+    <td valign="top">Whether this resource is directory-like</td>
+    <td align="center" valign="top">No, default <i>false</i></td>
+  </tr>
+  <tr>
+    <td valign="top">size</td>
+    <td valign="top">The size of this resource</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4><a name="file">file</a></h4>
+
+<p>Represents a file accessible via local filesystem conventions.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file represented by this resource</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">The base directory of this resource.  When this
+      attribute is set, attempts to access the name of the resource
+      will yield a path relative to this location.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h4><a name="javaresource">javaresource</a></h4>
+
+<p>Represents a resource loadable via a Java classloader.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the resource.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use when looking up a resource.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">the classpath to use when looking up a resource,
+      given as <a href="../using.html#references">reference</a>
+      to a <code>&lt;path&gt;</code> defined elsewhere..</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">loaderRef</td>
+    <td valign="top">the name of the loader that is
+      used to load the resource, constructed from the specified classpath.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>The classpath can also be specified as nested classpath element,
+where <b>&lt;classpath&gt;</b> is a <a
+href="../using.html#path">path-like structure</a>.</p>
+
+<h4><a name="zipentry">zipentry</a></h4>
+
+<p>Represents an entry in a ZIP archive.  The archive can be specified
+using the archive attribute or a nested single-element resource
+collection.  <code>zipentry</code> only supports file system resources
+as nested elements.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">zipfile or its alias name archive</td>
+    <td valign="top">The zip file containing this resource</td>
+    <td align="center" valign="top">Yes, unless a nested resource
+    collection has been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the archived resource</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding of the zipfile</td>
+    <td align="center" valign="top">No;
+      platform default used if unspecified</td>
+  </tr>
+</table>
+
+<h4><a name="tarentry">tarentry</a></h4>
+
+<p>Represents an entry in a TAR archive.  The archive can be specified
+using the archive attribute or a nested single-element resource
+collection.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">archive</td>
+    <td valign="top">The tar archive containing this resource</td>
+    <td align="center" valign="top">Yes, unless a nested resource
+    collection has been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the archived resource</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4><a name="gzipresource">gzipresource</a></h4>
+
+<p>This is not a stand-alone resource, but a wrapper around another
+resource providing compression of the resource's contents on the fly.
+A single element resource collection must be specified as a nested
+element.</p>
+
+<h4><a name="bzip2resource">bzip2resource</a></h4>
+
+<p>This is not a stand-alone resource, but a wrapper around another
+resource providing compression of the resource's contents on the fly.
+A single element resource collection must be specified as a nested
+element.</p>
+
+<h4><a name="url">url</a></h4>
+
+<p>Represents a URL.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">The url to expose</td>
+    <td rowspan="3" align="center" valign="middle">Exactly one of these</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to expose as a file: url</td>
+  </tr>
+</table>
+
+<h4><a name="string">string</a></h4>
+
+<p>Represents a Java String. It can be written to, but only once, after which
+it will be an error to write to again.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The value of this resource</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>The resource also supports nested text, which can only be supplied if the <code>value</code> attribute is unset:
+  </p>
+<pre>
+  &lt;string>
+        self.log("Ant version =${ant.version}");
+  &lt;/string>
+</pre>
+    
+</p>
+
+<h4><a name="propertyresource">propertyresource</a></h4>
+
+<p>Represents an Ant property.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The property name</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<hr>
+<h2><a name="collection">Resource Collections</a></h2>
+<p>
+A Resource Collection is an abstraction of an entity that groups
+together a number of <a href="#resource">resources</a>. Several of
+Ant's "legacy" datatypes have been modified to behave as Resource Collections:
+<ul>
+  <li><a href="fileset.html">fileset</a>,
+    <a href="dirset.html">dirset</a>,
+    <a href="filelist.html">filelist</a>, and
+    <a href="../using.html#path">path</a>
+    (and derivative types) expose <a href="#file">file</a> resources
+  </li>
+  <li><a href="zipfileset.html">tarfileset</a>
+    can expose <a href="#file">file</a> or <a href="#tarentry">tarentry</a>
+    resources depending on configuration
+  </li>
+  <li><a href="zipfileset.html">zipfileset</a>
+    can expose <a href="#file">file</a> or <a href="#zipentry">zipentry</a>
+    resources depending on configuration
+  </li>
+  <li><a href="propertyset.html">propertyset</a>
+    exposes <a href="#property">property</a> resources
+  </li>
+</ul>
+</p>
+<p>Strangely, some tasks can even legitimately behave as resource collections:
+<ul>
+  <li><a href="../CoreTasks/concat.html">concat</a>
+    exposes a concatenated resource, and adds e.g.
+    <a href="../filterchain.html">filtering</a>
+    to Ant's resource-related capabilities.
+  </li>
+</ul>
+</p>
+<h3>The additional built-in resource collections are:</h3>
+<ul>
+  <li><a href="#resources">resources</a> - generic resource collection</li>
+  <li><a href="#files">files</a> - collection of files similar to
+    <a href="fileset.html">fileset</a></li>
+  <li><a href="#restrict">restrict</a> - restrict a resource collection
+    to include only resources meeting specified criteria</li>
+  <li><a href="#sort">sort</a> - sorted resource collection</li>
+  <li><a href="#first">first</a> - first <i>n</i> resources from a
+    nested collection</li>
+  <li><a href="#last">last</a> - last <i>n</i> resources from a
+    nested collection</li>
+  <li><a href="#tokens">tokens</a> - <a href="#string">string</a> tokens
+    gathered from a nested collection</li>
+  <li><a href="#union">union</a> - set union of nested resource collections</li>
+  <li><a href="#intersect">intersect</a> - set intersection
+    of nested resource collections</li>
+  <li><a href="#difference">difference</a> - set difference
+    of nested resource collections</li>
+</ul>
+<h4><a name="resources">resources</a></h4>
+<p>A generic resource collection, designed for use with
+  <a href="../using.html#references">references</a>.
+  For example, if a third-party Ant task generates a Resource Collection
+  of an unknown type, it can still be accessed via a
+  <code>&lt;resources&gt;</code> collection. The secondary use of this
+  collection type is as a container of other resource collections,
+  preserving the order of nested collections as well as
+  duplicate resources (contrast with <a href="#union">union</a>).
+</p>
+
+<h4><a name="files">files</a></h4>
+<p>A group of files. These files are matched by <b>absolute</b> patterns
+  taken from a number of <a href="patternset.html">PatternSets</a>.
+  These can be specified as nested <code>&lt;patternset&gt;</code>
+  elements. In addition, <code>&lt;files&gt;</code> holds an implicit
+  PatternSet and supports the nested <code>&lt;include&gt;</code>,
+  <code>&lt;includesfile&gt;</code>, <code>&lt;exclude&gt;</code>
+  and <code>&lt;excludesfile&gt;</code> elements of PatternSet directly,
+  as well as PatternSet's attributes.
+</p>
+<p><a href="selectors.html">File Selectors</a> are available as nested
+  elements. A file must be selected by all selectors in order to be included;
+  <code>&lt;files&gt;</code> is thus equivalent to an
+  <code>&lt;and&gt;</code> file selector container.
+</p>
+<p><b>More simply put</b>, this type is equivalent to a
+  <a href="fileset.html">fileset</a> with no base directory.
+  <b>Please note</b> that without a base directory,
+  filesystem scanning is based entirely on include and exclude patterns.
+  A <a href="selectors.html#filenameselect">filename</a> (or any)
+  selector can <i>only</i> influence the scanning process <i>after</i>
+  the file has been included based on pattern-based selection.
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns
+      of files that must be included</td>
+    <td rowspan="2" valign="middle" align="center">At least one of these</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an include pattern.</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns
+      of files that must be excluded</td>
+    <td rowspan="2" valign="top" align="center">No, default none
+      (except default excludes when true)</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file; each line of this file is
+      taken to be an exclude pattern.</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">Whether
+      <a href="../dirtasks.html#defaultexcludes">default excludes</a>
+      should be used</td>
+    <td valign="top" align="center">No, default <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">casesensitive</td>
+    <td valign="top">Whether patterns are case-sensitive</td>
+    <td valign="top" align="center">No, default <i>true</i></td>
+  </tr>
+  <tr>
+    <td valign="top">followsymlinks</td>
+    <td valign="top">Whether to follow symbolic links
+      (see note <a href="#symlink">below</a>)</td>
+    <td valign="top" align="center">No, default <i>true</i></td>
+  </tr>
+</table>
+
+<p><a name="symlink"><b>Note</b></a>: All files/directories for which
+the canonical path is different from its path are considered symbolic
+links.  On Unix systems this usually means the file really is a
+symbolic link but it may lead to false results on other
+platforms.
+</p>
+
+<h4><a name="restrict">restrict</a></h4>
+<p>Restricts a nested resource collection using resource selectors:
+<blockquote>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <p>A single resource collection is required.</p>
+  <p>Nested resource selectors are used to "narrow down" the included
+    resources. These are patterned after <a href="selectors.html">file
+    selectors</a> but are, unsurprisingly, targeted to resources.
+    Several built-in resource selectors are available in the internal
+    <a href="antlib.html">antlib</a>
+    <code>org.apache.tools.ant.types.resources.selectors</code>:
+  </p>
+
+  <ul>
+    <li><a href="#rsel.name">name</a> - select resources by name.</li>
+    <li><a href="#rsel.exists">exists</a> - select existing resources.</li>
+    <li><a href="#rsel.date">date</a> - select resources by date.</li>
+    <li><a href="#rsel.type">type</a> - select resources by type.</li>
+    <li><a href="#rsel.size">size</a> - select resources by size.</li>
+    <li><a href="#rsel.instanceof">instanceof</a>
+      - select resources by class or Ant datatype.</li>
+    <li><a href="#rsel.and">and</a> - "and" nested resource selectors.</li>
+    <li><a href="#rsel.or">or</a> - "or" nested resource selectors.</li>
+    <li><a href="#rsel.not">not</a> - "not" a nested resource selector.</li>
+    <li><a href="#rsel.none">none</a>
+      - select resources selected by no nested resource selectors.</li>
+    <li><a href="#rsel.majority">majority</a> - select resources selected
+      by a majority of nested resource selectors.</li>
+    <li><a href="selectors.html#modified">modified</a> - select resources which
+      content has changed.</li>
+    <li><a href="selectors.html#containsselect">contains</a> - select resources 
+      containing a particular text string.</li>
+    <li><a href="selectors.html#regexpselect">containsregexp</a> - select
+      resources whose contents match a particular regular expression.</li>
+    <li><a href="#rsel.compare">compare</a> - select resources
+      based on comparison to other resources.</li>
+  </ul>
+
+  <h4><a name="rsel.name">name</a></h4>
+  <p>Selects resources by name.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">name</td>
+      <td valign="top">The name pattern to test</td>
+      <td align="center" valign="top">Yes</td>
+    </tr>
+    <tr>
+      <td valign="top">casesensitive</td>
+      <td valign="top">Whether name comparisons are case-sensitive</td>
+      <td align="center" valign="top">No, default <i>true</i></td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.exists">exists</a></h4>
+  <p>Selects existing resources.</p>
+
+  <h4><a name="rsel.date">date</a></h4>
+  <p>Selects resources by date.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">millis</td>
+      <td valign="top">The comparison date/time in ms since January 1, 1970</td>
+      <td rowspan="2" align="center" valign="middle">One of these</td>
+    </tr>
+    <tr>
+      <td valign="top">datetime</td>
+      <td valign="top">The formatted comparison date/time</td>
+    </tr>
+    <tr>
+      <td valign="top">pattern</td>
+      <td valign="top">SimpleDateFormat-compatible pattern
+        for use with the <code>datetime</code> attribute</td>
+      <td align="center" valign="top">
+        No, default is "MM/DD/YYYY HH:MM AM_or_PM"</td>
+    </tr>
+    <tr>
+      <td valign="top">granularity</td>
+      <td valign="top">The number of milliseconds leeway to use when
+        comparing file modification times. This is needed because not
+        every file system supports tracking the last modified time to
+        the millisecond level.</td>
+      <td align="center" valign="top">No; default varies by platform:
+        FAT filesystems = 2 sec; Unix = 1 sec; NTFS = 1 ms.</td>
+    </tr>
+    <tr>
+      <td valign="top">when</td>
+      <td valign="top">One of "before", "after", "equal"</td>
+      <td align="center" valign="top">No, default "equal"</td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.type">type</a></h4>
+  <p>Selects resources by type (file or directory).</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">type</td>
+      <td valign="top">One of "file", "dir"</td>
+      <td align="center" valign="top">Yes</td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.size">size</a></h4>
+  <p>Selects resources by size.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">size</td>
+      <td valign="top">The size to compare</td>
+      <td align="center" valign="top">Yes</td>
+    </tr>
+    <tr>
+      <td valign="top">when</td>
+      <td valign="top">One of "equal", "eq", "greater", "gt", "less", "lt",
+        "ge" (greater or equal), "ne" (not equal), "le" (less or equal)</td>
+      <td align="center" valign="top">No, default "equal"</td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.instanceof">instanceof</a></h4>
+  <p>Selects resources by type.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">class</td>
+      <td valign="top">The class of which the resource must be an instance</td>
+      <td rowspan="2" align="center" valign="middle">One of these</td>
+    </tr>
+    <tr>
+      <td valign="top">type</td>
+      <td valign="top">The Ant type that must
+        be assignable from the resource</td>
+    </tr>
+    <tr>
+      <td valign="top">uri</td>
+      <td valign="top">The uri in which <i>type</i> must be defined</td>
+      <td valign="top">No</td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.and">and</a></h4>
+  <p>Selects a resource if it is selected by all nested resource selectors.</p>
+
+  <h4><a name="rsel.or">or</a></h4>
+  <p>Selects a resource if it is selected
+    by at least one nested resource selector.</p>
+
+  <h4><a name="rsel.not">not</a></h4>
+  <p>Negates the selection result of the single
+    nested resource selector allowed.</p>
+
+  <h4><a name="rsel.none">none</a></h4>
+  <p>Selects a resource if it is selected
+    by no nested resource selectors.</p>
+
+  <h4><a name="rsel.majority">majority</a></h4>
+  <p>Selects a resource if it is selected
+    by the majority of nested resource selectors.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">allowtie</td>
+      <td valign="top">Whether a tie (when there is an even number
+        of nested resource selectors) is considered a majority</td>
+      <td valign="top">No, default <i>true</i></td>
+    </tr>
+  </table>
+
+  <h4><a name="rsel.compare">compare</a></h4>
+  <p>Selects a resource based on its comparison to one or more "control"
+     resources using nested <a href="#rcmp">resource comparators</a>.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">when</td>
+      <td valign="top">Comparison ("equal"/"eq", "greater"/"gt", "less"/"lt",
+        "le" (less or equal), "ge" (greater or equal), "ne" (not equal).</td>
+      <td valign="top">No, default "equal"</td>
+    </tr>
+    <tr>
+      <td valign="top">against</td>
+      <td valign="top">Quantifier ("all"/"each"/"every", "any"/"some",
+        (exactly) "one", "most"/"majority", "none".</td>
+      <td valign="top">No, default "all"</td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <p>The resources against which comparisons will be made must be specified
+    using the nested &lt;control&gt; element, which denotes a
+    <a href="#resources">resources</a> collection.</p>
+  <h4>Examples</h4>
+  <p>Assuming the namespace settings
+<pre><code>  rsel="antlib:org.apache.tools.ant.types.resources.selectors"
+  rcmp="antlib:org.apache.tools.ant.types.resources.comparators"
+</code></pre></p>
+  <pre>
+&lt;restrict&gt;
+  &lt;fileset dir="src" includes="a,b,c,d,e,f,g" /&gt;
+  &lt;rsel:compare when="le" against="all"&gt;
+    &lt;control&gt;
+      &lt;resource name="d" /&gt;
+    &lt;/control&gt;
+    &lt;rcmp:name /&gt;
+  &lt;/rsel:compare&gt;
+&lt;/restrict&gt;
+  </pre>
+  <p>Selects files a, b, c, and d.</p>
+  <pre>
+    &lt;project rsel=&quot;antlib:org.apache.tools.ant.types.resources.selectors&quot;&gt;
+        &lt;macrodef name=&quot;copyFromPath&quot;&gt;
+            &lt;attribute name=&quot;todir&quot;/&gt;
+            &lt;attribute name=&quot;refid&quot;/&gt;
+            &lt;element name=&quot;nested-resource-selectors&quot; optional=&quot;yes&quot; implicit=&quot;true&quot;/&gt;
+            &lt;sequential&gt;
+                &lt;mkdir dir=&quot;@{todir}&quot; taskname=&quot;copyFromPath&quot;/&gt;
+                &lt;copy todir=&quot;@{todir}&quot; taskname=&quot;copyFromPath&quot;&gt;
+                    &lt;restrict&gt;
+                        &lt;path refid=&quot;@{refid}&quot;/&gt;
+                        &lt;rsel:or&gt;
+                            &lt;nested-resource-selectors/&gt;
+                        &lt;/rsel:or&gt;
+                    &lt;/restrict&gt;
+                    &lt;flattenmapper/&gt;
+                &lt;/copy&gt;
+            &lt;/sequential&gt;
+        &lt;/macrodef&gt;
+        &lt;copyFromPath refid=&quot;classpath&quot; todir=&quot;todir&quot;&gt;
+            &lt;rsel:name name=&quot;log4j.properties&quot;/&gt;
+            &lt;rsel:name name=&quot;default.properties&quot;/&gt;
+        &lt;/copyFromPath&gt;
+     &lt;/project&gt;
+  </pre>
+  <p>Creates the <tt>todir</tt> directory and copies (if present) the
+     files <tt>log4j.properties</tt> and <tt>default.properties</tt>
+     from the Classpath (already used while compiling).
+  </p>
+
+</blockquote>
+
+<h4><a name="sort">sort</a></h4>
+
+<p>Sorts a nested resource collection according to the resources'
+   natural order, or by one or more nested <a href="#rcmp">resource
+   comparators</a>:</p>
+<blockquote>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <p>A single resource collection is required.</p>
+  <p>The sort can be controlled and customized by specifying one or more
+    resource comparators. Resources can be sorted according to multiple
+    criteria; the first specified is the "outermost", while the last
+    specified is the "innermost". Several built-in resource comparators
+    are available in the internal <a href="antlib.html">antlib</a>
+    <code>org.apache.tools.ant.types.resources.comparators</code>:
+  </p>
+  <h4><a name="rcmp">Resource Comparators:</a></h4>
+  <ul>
+    <li><a href="#rcmp.name">name</a> - sort resources by name</li>
+    <li><a href="#rcmp.exists">exists</a> - sort resources by existence</li>
+    <li><a href="#rcmp.date">date</a> - sort resources by date</li>
+    <li><a href="#rcmp.type">type</a> - sort resources by type</li>
+    <li><a href="#rcmp.size">size</a> - sort resources by size</li>
+    <li><a href="#rcmp.content">content</a> - sort resources by content</li>
+    <li><a href="#rcmp.reverse">reverse</a> - reverse the natural sort order,
+      or that of a single nested resource comparator</li>
+  </ul>
+
+  <h4><a name="rcmp.name">name</a></h4>
+  <p>Sort resources by name.</p>
+
+  <h4><a name="rcmp.exists">exists</a></h4>
+  <p>Sort resources by existence.
+    Not existing is considered "less than" existing.</p>
+
+  <h4><a name="rcmp.date">date</a></h4>
+  <p>Sort resources by date.</p>
+
+  <h4><a name="rcmp.type">type</a></h4>
+  <p>Sort resources by type (file or directory).
+    Because directories contain files, they are considered "greater".</p>
+
+  <h4><a name="rcmp.size">size</a></h4>
+  <p>Sort resources by size.</p>
+
+  <h4><a name="rcmp.content">content</a></h4>
+  <p>Sort resources by content.</p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">binary</td>
+      <td valign="top">Whether content should be compared in binary mode.
+        If <i>false<i>, content will be compared without regard to
+        platform-specific line-ending conventions.</td>
+      <td valign="top">No, default <i>true</i></td>
+    </tr>
+  </table>
+
+  <h4><a name="rcmp.reverse">reverse</a></h4>
+  <p>Reverse the natural sort order, or that of a single nested comparator.</p>
+
+  <h4>Examples</h4>
+  <pre>
+    &lt;property name=&quot;eol&quot; value=&quot;${line.separator}&quot; /&gt;
+    &lt;pathconvert property=&quot;sorted&quot; pathsep=&quot;${eol}&quot;&gt;
+      &lt;sort&gt;
+        &lt;tokens&gt;
+          &lt;string value=&quot;foo bar etc baz&quot; /&gt;
+          &lt;stringtokenizer /&gt;
+        &lt;/tokens&gt;
+      &lt;/sort&gt;
+    &lt;/pathconvert&gt;</pre>
+  <p>The resource of type string &quot;foo bar etc baz&quot; is split into four tokens by 
+  the stringtokenizer. These tokens are sorted and there <i>sorted</i> gets the value
+  of &quot;bar baz etc foo&quot;.</p>
+  
+  <pre>
+    &lt;sort&gt;
+      &lt;fileset dir=&quot;foo&quot; /&gt;
+      &lt;reverse xmlns=&quot;antlib:org.apache.tools.ant.types.resources.comparators&quot;&gt;
+        &lt;date /&gt;
+      &lt;/reverse&gt;
+    &lt;/sort&gt;</pre>
+  <p>This takes all files from <i>foo</i>
+     and sorts them by modification date in reverse order.
+     Because the resource comparators used (<code>&lt;reverse&gt;</code>
+     and <code>&lt;date&gt;</code>) are in an internal antlib
+     their namespace must be set explicitly.
+  </p>
+
+</blockquote>
+
+<h4><a name="first">first</a></h4>
+<p>Includes the first <i>count</i> resources from a nested resource collection.
+This can be used in conjunction with the <a href="#sort">sort</a> collection,
+for example, to select the first few oldest, largest, etc. resources from a
+larger collection.</p>
+<blockquote>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">count</td>
+      <td valign="top">The number of resources to include</td>
+      <td valign="top" align="center">No, default 1</td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <p>A single resource collection is required.</p>
+</blockquote>
+
+<h4><a name="last">last</a></h4>
+<p>Includes the last <i>count</i> resources from a nested resource collection.
+This can be used in conjunction with the <a href="#sort">sort</a> collection,
+for example, to select the last few oldest, largest, etc. resources from a
+larger collection. <strong>Since Ant 1.7.1</strong>.</p>
+<blockquote>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">count</td>
+      <td valign="top">The number of resources to include</td>
+      <td valign="top" align="center">No, default 1</td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <p>A single resource collection is required.</p>
+</blockquote>
+
+<h4><a name="tokens">tokens</a></h4>
+<p>Includes the <a href="#string">string</a> tokens gathered from a nested
+ resource collection. Uses the same tokenizers supported by the
+<a href="filterchain.html#tokenfilter">TokenFilter</a>. Hint: imaginative
+  use of this resource collection can implement equivalents for such Unix
+  functions as <code>sort</code>, <code>grep -c</code>, <code>wc</code> and
+  <code>wc -l</code>.</p>
+<blockquote>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">encoding</td>
+      <td valign="top">The encoding of the nested resources</td>
+      <td valign="top" align="center">No, default is platform default</td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  <h4>Parameters specified as nested elements</h4>
+  <ul>
+    <li>A single resource collection is required.</li>
+    <li>One nested tokenizer may be specified.  If omitted, a
+        <a href="filterchain.html#linetokenizer">LineTokenizer</a> will be used.
+    </li>
+  </ul>
+</blockquote>
+
+<h4><a name="setlogic">Set operations</a></h4>
+<blockquote>
+  <p>The following resource collections implement set operations:</p>
+  <ul>
+    <li><a href="#union">union</a></li>
+    <li><a href="#intersect">intersect</a></li>
+    <li><a href="#difference">difference</a></li>
+  </ul>
+
+  <h4><a name="union">union</a></h4>
+  <p>Union of nested resource collections.</p>
+
+  <h4><a name="intersect">intersect</a></h4>
+  <p>Intersection of nested resource collections.</p>
+
+  <h4><a name="difference">difference</a></h4>
+  <p>Difference of nested resource collections.</p>
+
+  <p>The following attributes apply to all set-operation resource collections:
+  </p>
+  <table border="1" cellpadding="2" cellspacing="0">
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td align="center" valign="top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">cache</td>
+      <td valign="top">Whether to cache results; disabling
+        may seriously impact performance</td>
+      <td valign="top" align="center">No, default <i>true</i></td>
+    </tr>
+  </table>
+  
+  <h4>Examples</h4>
+  <pre>
+    &lt;resources id=&quot;A&quot;&gt;
+        &lt;string value=&quot;a&quot;/&gt;
+        &lt;string value=&quot;b&quot;/&gt;
+    &lt;/resources&gt;
+    &lt;resources id=&quot;B&quot;&gt;
+        &lt;string value=&quot;b&quot;/&gt;
+        &lt;string value=&quot;c&quot;/&gt;
+    &lt;/resources&gt;
+    &lt;union id=&quot;union&quot;&gt;&lt;resources refid=&quot;A&quot;/&gt;&lt;resources refid=&quot;B&quot;/&gt;&lt;/union&gt;
+    &lt;intersect id=&quot;intersect&quot;&gt;&lt;resources refid=&quot;A&quot;/&gt;&lt;resources refid=&quot;B&quot;/&gt;&lt;/intersect&gt;
+    &lt;difference id=&quot;difference&quot;&gt;&lt;resources refid=&quot;A&quot;/&gt;&lt;resources refid=&quot;B&quot;/&gt;&lt;/difference&gt;
+    &lt;echo&gt;
+      A: ${toString:A}                    = a;b
+      B: ${toString:B}                    = b;c
+
+      union     : ${toString:union}       = a;b;c
+      intersect : ${toString:intersect}   = b
+      difference: ${toString:difference}  = a;c
+    &lt;/echo&gt;
+  </pre>
+</blockquote>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/selectors-program.html b/trunk/docs/manual/CoreTypes/selectors-program.html
new file mode 100755
index 0000000..940b3d1
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/selectors-program.html
@@ -0,0 +1,264 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us">
+    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Programming Selectors in Ant</title>
+  </head>
+
+  <body>
+    <h2>Programming your own Selectors</h2>
+
+    <h3>Selector Programming API</h3>
+
+    <p>Want to define your own selectors? It's easy!</p>
+
+    <p>First, pick the type of selector that you want to define. There
+    are three types, and a recipe for each one follows. Chances are
+    you'll want to work with the first one, Custom Selectors.</p>
+
+    <ol>
+      <li>Custom Selectors
+
+        <p>This is the category that Ant provides specifically for you to
+        define your own Selectors. Anywhere you want to use your selector
+        you use the <code>&lt;custom&gt;</code> element and specify
+        the class name of your selector within it. See the
+        <a href="selectors.html#customselect">Custom Selectors</a>
+        section of the Selector page for details. The
+        <code>&lt;custom&gt;</code> element can be used anywhere
+        the core selectors can be used. It can be contained within
+        <a href="selectors.html#selectcontainers">Selector Containers</a>,
+        for example.</p>
+
+        <p>To create a new Custom Selector, you have to create a class that
+        implements
+        <code>org.apache.tools.ant.types.selectors.ExtendFileSelector</code>.
+        The easiest way to do that is through the convenience base class
+        <code>org.apache.tools.ant.types.selectors.BaseExtendSelector</code>,
+        which provides all of the methods for supporting
+        <code>&lt;param&gt;</code> tags. First, override the
+        <code>isSelected()</code> method, and optionally the
+        <code>verifySettings()</code> method. If your custom
+        selector requires parameters to be set, you can also override
+        the <code>setParameters()</code> method and interpret the
+        parameters that are passed in any way you like. Several of the
+        core selectors demonstrate how to do that because they can
+        also be used as custom selectors.</p>
+
+      <li>Core Selectors
+
+        <p>These are the selectors used by Ant itself. To implement one of
+        these, you will have to alter some of the classes contained within
+        Ant.</p>
+
+        <ul>
+          <li><p>First, create a class that implements
+            <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
+            You can either choose to implement all methods yourself from
+            scratch, or you can extend
+            <code>org.apache.tools.ant.types.selectors.BaseSelector</code>
+            instead, a convenience class that provides reasonable default
+            behaviour for many methods.</p>
+
+            <p>There is only one method required.
+            <code>public boolean isSelected(File basedir, String filename,
+              File file)</code>
+              is the real purpose of the whole exercise. It returns true
+              or false depending on whether the given file should be
+              selected from the list or not.</p>
+
+            <p>If you are using
+            <code>org.apache.tools.ant.types.selectors.BaseSelector</code>
+            there are also some predefined behaviours you can take advantage
+            of. Any time you encounter a problem when setting attributes or
+            adding tags, you can call setError(String errmsg) and the class
+            will know that there is a problem. Then, at the top of your
+            <code>isSelected()</code> method call <code>validate()</code> and
+            a BuildException will be thrown with the contents of your error
+            message. The <code>validate()</code> method also gives you a
+            last chance to check your settings for consistency because it
+            calls <code>verifySettings()</code>. Override this method and
+            call <code>setError()</code> within it if you detect any
+            problems in how your selector is set up.</p>
+
+            <p>You may also want to override <code>toString()</code>.</p>
+
+          <li><p>Put an <code>add</code> method for your selector in
+            <code>org.apache.tools.ant.types.selectors.SelectorContainer</code>.
+            This is an interface, so you will also have to add an implementation
+            for the method in the classes which implement it, namely
+            <code>org.apache.tools.ant.types.AbstractFileSet</code>,
+            <code>org.apache.tools.ant.taskdefs.MatchingTask</code> and
+            <code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.
+            Once it is in there, it will be available everywhere that core
+            selectors are appropriate.</p>
+        </ul>
+
+      <li>Selector Containers
+        <p>Got an idea for a new Selector Container? Creating a new one is
+        no problem:</p>
+        <ul>
+          <li><p>Create a new class that implements
+            <code>org.apache.tools.ant.types.selectors.SelectorContainer</code>.
+            This will ensure that your new
+            Container can access any new selectors that come along. Again, there
+            is a convenience class available for you called
+            <code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.
+            </p>
+          <li><p>Implement the
+            <code>public boolean isSelected(String filename, File file)</code>
+            method to do the right thing. Chances are you'll want to iterate
+            over the selectors under you, so use
+            <code>selectorElements()</code> to get an iterator that will do
+            that.</p>
+          <li><p>Again, put an <code>add</code> method for your container in
+            <code>org.apache.tools.ant.types.selectors.SelectorContainer</code>
+            and its implementations
+            <code>org.apache.tools.ant.types.AbstractFileSet</code> and
+            <code>org.apache.tools.ant.types.selectors.BaseSelectorContainer</code>.
+            </p>
+        </ul>
+    </ol>
+
+    <h3>Testing Selectors</h3>
+
+    <p>For a robust component (and selectors are (Project)Components) tests are
+    necessary. For testing Tasks we use JUnit TestCases - more specific
+    <tt>org.apache.tools.ant.BuildFileTest extends junit.framework.TestCase</tt>.
+    Some of its features like configure the (test) project by reading its buildfile and
+    execute targets we need for selector tests also. Therefore we use that BuildFileTest.
+    But testing selectors requires some more work: having a set of files, instantiate
+    and configure the selector, check the selection work and more. Because we usually
+    extend <tt>BaseExtendSelector</tt> its features have to be tested also (e.g. setError()).
+    </p>
+
+    <p>That's why we have a base class for doing our selector tests:
+    <tt>org.apache.tools.ant.types.selectors.BaseSelectorTest</tt>.</p>
+
+    <p>This class extends TestCase and therefore can included in the set of Ant's
+    unit tests. It holds an instance of preconfigured BuildFileTest. Configuration
+    is done by parsing the src/etc/testcases/types/selectors.xml. BaseSelectorTest
+    then gives us helper methods for handling multiple selections. </p>
+
+    <p>Because the term "testcase" or "testenvironment" are so often used, this
+    special testenvironment got a new name: <i>bed</i>. Like you initialize the
+    test environment by calling setUp() and cleaning by calling tearDown() (<i>or like
+    to make your bed before go sleeping</i>) you have to do that work with your
+    <i>bed</i> by calling <tt>makeBed()</tt> respecitive <tt>cleanupBed()</tt>.</p>
+
+    <p>A usual test scenario is<ol>
+       <li>make the bed</li>
+       <li>instantiate the selector</li>
+       <li>configure the selector</li>
+       <li>let the selector do some work</li>
+       <li>verify the work</li>
+       <li>clean the bed</li>
+       </ol>
+    </p>
+
+    <p>For common way of instantiation you have to override the <tt>getInstance()</tt>
+    simply by returning a new object of your selector. For easier "selection and verification work"
+    BaseSelectorTest provides the method <tt>performTests()</tt> which
+    iterates over all files (and directories) in the String array <tt>filenames</tt>
+    and checks whether the given selector returns the expected result. If an error
+    occurred (especially the selector does not return the expected result) the test
+    fails and the failing filenames are logged.</p>
+
+    <p>An example test would be:<pre>
+package org.apache.tools.ant.types.selectors;
+
+public class MySelectorTest extends BaseSelectorTest {
+
+    public MySelectorTest(String name) {
+        super(name);
+    }
+
+    public BaseSelector getInstance() {
+        return new MySelector();
+    }
+
+    public void testCase1() {
+        try {
+            // initialize test environment 'bed'
+            makeBed();
+
+            // Configure the selector
+            MySelector s = (MySelector)getSelector();
+            s.addParam("key1", "value1");
+            s.addParam("key2", "value2");
+            s.setXX(true);
+            s.setYY("a value");
+
+            // do the tests
+            performTests(s, "FTTTTTTTTTTT");  // First is not selected - rest is
+
+        } finally {
+            // cleanup the environment
+            cleanupBed();
+        }
+    }
+}
+    </pre>
+    As an example of an error JUnit could log<pre>
+    [junit]     FAILED
+    [junit] Error for files: <font color=blue>.;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz</font>
+    [junit] expected:&lt;<font color=blue>FTTTFTTTF...</font>&gt; but was:&lt;TTTTTTTTT...&gt;
+    [junit] junit.framework.ComparisonFailure: Error for files: .;copy.filterset.filtered;tar/gz/asf-logo.gif.tar.gz
+    [junit] expected:&lt;FTTTFTTTF...&gt; but was:&lt;TTTTTTTTT...&gt;
+    [junit]     at junit.framework.Assert.assertEquals(Assert.java:81)
+    [junit]     at org.apache.tools.ant.types.selectors.BaseSelectorTest.performTest(BaseSelectorTest.java:194)
+    </pre></p>
+
+    <p>Described above the test class should provide a <tt>getInstance()</tt>
+    method. But that isn't used here. The used <tt>getSelector()</tt> method is
+    implemented in the base class and gives an instance of an Ant Project to
+    the selector. This is usually done inside normal build file runs, but not
+    inside this special environment, so this method gives the selector the
+    ability to use its own Project object (<tt>getProject()</tt>), for example
+    for logging.</p>
+
+
+    <h3>Logging</h3>
+
+    <p>During development and maybe later you sometimes need the output of information.
+    Therefore Logging is needed. Because the selector extends BaseExtendSelector or directly
+    BaseSelector it is an Ant <tt>DataType</tt> and therefore a <tt>ProjectComponent</tt>. <br>
+    That means that you have access to the project object and its logging capability.
+    <tt>ProjectComponent</tt> itself provides <i>log</i> methods which will do the
+    access to the project instance. Logging is therefore done simply with:
+    <pre>
+        log( "message" );
+    </pre>
+    or
+    <pre>
+        log( "message" , loglevel );
+    </pre>
+    where the <tt>loglevel</tt> is one of the values <ul>
+    <li> org.apache.tools.ant.Project.MSG_ERR </li>
+    <li> org.apache.tools.ant.Project.MSG_WARN </li>
+    <li> org.apache.tools.ant.Project.MSG_INFO  (= default) </li>
+    <li> org.apache.tools.ant.Project.MSG_VERBOSE </li>
+    <li> org.apache.tools.ant.Project.MSG_DEBUG </li>
+    </ul>
+    </p>
+
+    
+  </body>
+
+</html>
diff --git a/trunk/docs/manual/CoreTypes/selectors.html b/trunk/docs/manual/CoreTypes/selectors.html
new file mode 100755
index 0000000..9f37ee5
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/selectors.html
@@ -0,0 +1,1527 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head>
+    <meta http-equiv="Content-Language" content="en-us">
+    <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+    <title>Selectors in Ant</title>
+  </head>
+
+  <body>
+    <h2>Selectors</h2>
+
+    <p>Selectors are a mechanism whereby the files that make up a
+    <code>&lt;fileset&gt;</code> can be selected based on criteria
+    other than filename as provided by the <code>&lt;include&gt;</code>
+    and <code>&lt;exclude&gt;</code> tags.</p>
+
+    <h3>How to use a Selector</h3>
+
+    <p>A selector is an element of FileSet, and appears within it. It can
+    also be defined outside of any target by using the <code>&lt;selector&gt;</code> tag
+    and then using it as a reference.
+    </p>
+
+    <p>Different selectors have different attributes. Some selectors can
+    contain other selectors, and these are called
+    <a href="#selectcontainers"><code>Selector Containers</code></a>.
+    There is also a category of selectors that allow
+    user-defined extensions, called
+    <a href="#customselect"><code>Custom Selectors</code></a>.
+    The ones built in to Ant are called
+    <a href="#coreselect"><code>Core Selectors</code></a>.
+    </p>
+
+    <a name="coreselect"></a>
+    <h3>Core Selectors</h3>
+
+    <p>Core selectors are the ones that come standard
+    with Ant. They can be used within a fileset and can be contained
+    within Selector Containers.</p>
+
+    <p>The core selectors are:</p>
+
+    <ul>
+      <li><a href="#containsselect"><code>&lt;contains&gt;</code></a> - Select
+        files that contain a particular text string</li>
+      <li><a href="#dateselect"><code>&lt;date&gt;</code></a> - Select files
+        that have been modified either before or after a particular date
+        and time</li>
+      <li><a href="#dependselect"><code>&lt;depend&gt;</code></a> - Select files
+        that have been modified more recently than equivalent files
+        elsewhere</li>
+      <li><a href="#depthselect"><code>&lt;depth&gt;</code></a> - Select files
+        that appear so many directories down in a directory tree</li>
+      <li><a href="#differentselect"><code>&lt;different&gt;</code></a> - Select files
+        that are different from those elsewhere</li>
+      <li><a href="#filenameselect"><code>&lt;filename&gt;</code></a> - Select
+        files whose name matches a particular pattern. Equivalent to
+        the include and exclude elements of a patternset.</li>
+      <li><a href="#presentselect"><code>&lt;present&gt;</code></a> - Select
+        files that either do or do not exist in some other location</li>
+      <li><a href="#regexpselect"><code>&lt;containsregexp&gt;</code></a> - Select
+        files that match a regular expression</li>
+      <li><a href="#sizeselect"><code>&lt;size&gt;</code></a> - Select files
+        that are larger or smaller than a particular number of bytes.</li>
+      <li><a href="#typeselect"><code>&lt;type&gt;</code></a> - Select files
+        that are either regular files or directories.</li>
+      <li><a href="#modified"><code>&lt;modified&gt;</code></a> - Select files if
+        the return value of the configured algorithm is different from that
+        stored in a cache.</li>
+      <li><a href="#signedselector"><code>&lt;signedselector&gt;</code></a> - Select files if
+        they are signed, and optionally if they have a signature of a certain name.
+      </li>
+      <li><a href="#scriptselector"><code>&lt;scriptselector&gt;</code></a> - 
+        Use a BSF or JSR 223 scripting language to create
+        your own selector
+      </li>
+    </ul>
+
+    <a name="containsselect"></a>
+    <h4>Contains Selector</h4>
+
+    <p>The <code>&lt;contains&gt;</code> tag in a FileSet limits
+    the files defined by that fileset to only those which contain the
+    string specified by the <code>text</code> attribute.
+    .</p>
+    <p>The <code>&lt;contains&gt;</code> selector can be used as a
+      ResourceSelector (see the
+      <a href="resources.html#restrict">&lt;restrict&gt;</a>
+      ResourceCollection).</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">text</td>
+        <td valign="top">Specifies the text that every file must contain
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">casesensitive</td>
+        <td valign="top">Whether to pay attention to case when looking
+          for the string in the <code>text</code> attribute. Default is
+          true.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">ignorewhitespace</td>
+        <td valign="top">Whether to eliminate whitespace before checking
+          for the string in the <code>text</code> attribute. Default is
+          false.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Contains Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${doc.path}&quot; includes=&quot;**/*.html&quot;&gt;
+    &lt;contains text=&quot;script&quot; casesensitive=&quot;no&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the HTML files that contain the string
+    <code>script</code>.</p>
+
+
+    <a name="dateselect"></a>
+    <h4>Date Selector</h4>
+
+    <p>The <code>&lt;date&gt;</code> tag in a FileSet will put
+    a limit on the files specified by the include tag, so that tags
+    whose last modified date does not meet the date limits specified
+    by the selector will not end up being selected.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">datetime</td>
+        <td valign="top">Specifies the date and time to test for.
+          Should be in the format MM/DD/YYYY HH:MM AM_or_PM, or
+          an alternative pattern specified via the <i>pattern</i>
+          attribute.
+        </td>
+        <td valign="top" align="center" rowspan="2">At least one of the two.</td>
+      </tr>
+      <tr>
+        <td valign="top">millis</td>
+        <td valign="top">The number of milliseconds since 1970 that should
+          be tested for. It is usually much easier to use the datetime
+          attribute.
+        </td>
+      </tr>
+      <tr>
+        <td valign="top">when</td>
+        <td valign="top">Indicates how to interpret the date, whether
+          the files to be selected are those whose last modified times should
+          be before, after, or equal to the specified value. Acceptable
+          values for this attribute are:
+          <ul>
+            <li>before - select files whose last modified date is before the indicated date
+            <li>after - select files whose last modified date is after the indicated date
+            <li>equal - select files  whose last modified date is this exact date
+          </ul>
+          The default is equal.
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">granularity</td>
+        <td valign="top">The number of milliseconds leeway to use when
+          comparing file modification times. This is needed because not every
+          file system supports tracking the last modified time to the
+          millisecond level. Default is 0 milliseconds, or 2 seconds on DOS systems.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">pattern</td>
+        <td valign="top">The <CODE>SimpleDateFormat</CODE>-compatible pattern
+          to use when interpreting the <i>datetime</i> attribute.
+          <i>Since Ant 1.6.2</i>
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">checkdirs</td>
+        <td valign="top">
+          Indicates whether or not to check dates on directories.
+        </td>
+        <td valign="top" align="center">No, defaults to <i>false</i></td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Date Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${jar.path}&quot; includes=&quot;**/*.jar&quot;&gt;
+    &lt;date datetime=&quot;01/01/2001 12:00 AM&quot; when=&quot;before&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all JAR files which were last modified before midnight
+    January 1, 2001.</p>
+
+
+    <a name="dependselect"></a>
+    <h4>Depend Selector</h4>
+
+    <p>The <code>&lt;depend&gt;</code> tag selects files
+    whose last modified date is later than another, equivalent file in
+    another location.</p>
+
+    <p>The <code>&lt;depend&gt;</code> tag supports the use of a
+    contained <a href="mapper.html"><code>&lt;mapper&gt;</code></a> element
+    to define the location of the file to be compared against. If no
+    <code>&lt;mapper&gt;</code> element is specified, the
+    <code>identity</code> type mapper is used.</p>
+
+    <p>The <code>&lt;depend&gt;</code> selector is case-sensitive.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">targetdir</td>
+        <td valign="top">The base directory to look for the files to compare
+          against. The precise location depends on a combination of this
+          attribute and the <code>&lt;mapper&gt;</code> element, if any.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">granularity</td>
+        <td valign="top">The number of milliseconds leeway to give before
+          deciding a file is out of date. This is needed because not every
+          file system supports tracking the last modified time to the
+          millisecond level. Default is 0 milliseconds, or 2 seconds on DOS systems.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Depend Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${ant.1.5}/src/main&quot; includes=&quot;**/*.java&quot;&gt;
+    &lt;depend targetdir=&quot;${ant.1.4.1}/src/main&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the Java source files which were modified in the
+      1.5 release.
+    </p>
+
+
+    <a name="depthselect"></a>
+    <h4>Depth Selector</h4>
+
+    <p>The <code>&lt;depth&gt;</code> tag selects files based on
+    how many directory levels deep they are in relation to the base
+    directory of the fileset.
+    </p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">min</td>
+        <td valign="top">The minimum number of directory levels below
+          the base directory that a file must be in order to be selected.
+          Default is no limit.
+        </td>
+        <td valign="top" align="center" rowspan="2">At least one of the two.</td>
+      </tr>
+      <tr>
+        <td valign="top">max</td>
+        <td valign="top">The maximum number of directory levels below
+          the base directory that a file can be and still be selected.
+          Default is no limit.
+        </td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Depth Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${doc.path}&quot; includes=&quot;**/*&quot;&gt;
+    &lt;depth max=&quot;1&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all files in the base directory and one directory below
+    that.</p>
+
+    <a name="differentselect">
+    <h4>Different Selector</h4>
+
+    <p>The <code>&lt;different&gt;</code> selector will select a file
+    if it is deemed to be 'different' from an equivalent file in
+    another location. The rules for determining difference between
+    the two files are as follows:
+    <ol>
+    <li> If there is no 'other' file, it's different.
+    <li> Files with different lengths are different.
+    <li> If <tt>ignoreFileTimes</tt> is turned off, then differing file
+    timestamps will cause files to be regarded as different.
+    <li> Unless <tt>ignoreContents</tt> is set to true,
+         a byte-for-byte check is run against the two files.
+    </ol>
+
+    This is a useful selector to work with programs and tasks that don't handle
+    dependency checking properly; even if a predecessor task always creates its
+    output files, followup tasks can be driven off copies made with a different
+    selector, so their dependencies are driven on the absolute state of the
+    files, not just a timestamp. For example: anything fetched from a web site,
+    or the output of some program. To reduce the amount of checking, when using
+    this task inside a <code>&lt;copy&gt;</code> task, set
+    <tt>preservelastmodified</tt> to <i>true</i> to propagate the timestamp
+    from the source file to the destination file.<p>
+
+    The <code>&lt;different&gt;</code> selector supports the use of a
+    contained <a href="mapper.html"><code>&lt;mapper&gt;</code></a> element
+    to define the location of the file to be compared against. If no
+    <code>&lt;mapper&gt;</code> element is specified, the
+    <code>identity</code> type mapper is used.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">targetdir</td>
+        <td valign="top">The base directory to look for the files to compare
+          against. The precise location depends on a combination of this
+          attribute and the <code>&lt;mapper&gt;</code> element, if any.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">ignoreFileTimes</td>
+        <td valign="top">Whether to use file times in the comparison or not.
+          Default is true (time differences are ignored).
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">ignoreContents</td>
+        <td valign="top">Whether to do a byte per byte compare.
+          Default is false (contents are compared).
+          Since Ant 1.6.3
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">granularity</td>
+        <td valign="top">The number of milliseconds leeway to give before
+          deciding a file is out of date. This is needed because not every
+          file system supports tracking the last modified time to the
+          millisecond level. Default is 0 milliseconds, or 2 seconds on DOS systems.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Different Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${ant.1.5}/src/main&quot; includes=&quot;**/*.java&quot;&gt;
+    &lt;different targetdir=&quot;${ant.1.4.1}/src/main&quot;
+        ignoreFileTimes="true"/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Compares all the Java source files between the 1.4.1 and the 1.5 release
+    and selects those who are different, disregarding file times.
+    </p>
+
+    <a name="filenameselect"></a>
+    <h4>Filename Selector</h4>
+
+    <p>The <code>&lt;filename&gt;</code> tag acts like the
+    <code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code>
+    tags within a fileset. By using a selector instead, however,
+    one can combine it with all the other selectors using whatever
+    <a href="#selectcontainers">selector container</a> is desired.
+    </p>
+
+    <p>The <code>&lt;filename&gt;</code> selector is
+    case-sensitive.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">name</td>
+        <td valign="top">The name of files to select. The name parameter
+          can contain the standard Ant wildcard characters.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">casesensitive</td>
+        <td valign="top">Whether to pay attention to case when looking
+          at file names. Default is "true".
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">negate</td>
+        <td valign="top">Whether to reverse the effects of this filename
+          selection, therefore emulating an exclude rather than include
+          tag. Default is "false".
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Filename Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${doc.path}&quot; includes=&quot;**/*&quot;&gt;
+    &lt;filename name=&quot;**/*.css&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the cascading style sheet files.</p>
+
+
+    <a name="presentselect"></a>
+    <h4>Present Selector</h4>
+
+    <p>The <code>&lt;present&gt;</code> tag selects files
+    that have an equivalent file in another directory tree.</p>
+
+    <p>The <code>&lt;present&gt;</code> tag supports the use of a
+    contained <a href="mapper.html"><code>&lt;mapper&gt;</code></a> element
+    to define the location of the file to be tested against. If no
+    <code>&lt;mapper&gt;</code> element is specified, the
+    <code>identity</code> type mapper is used.</p>
+
+    <p>The <code>&lt;present&gt;</code> selector is case-sensitive.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">targetdir</td>
+        <td valign="top">The base directory to look for the files to compare
+          against. The precise location depends on a combination of this
+          attribute and the <code>&lt;mapper&gt;</code> element, if any.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">present</td>
+        <td valign="top">Whether we are requiring that a file is present in
+          the src directory tree only, or in both the src and the target
+          directory tree. Valid values are:
+          <ul>
+            <li>srconly - select files only if they are in the src
+              directory tree but not in the target directory tree
+            <li>both - select files only if they are present both in the
+              src and target directory trees
+          </ul>
+          Default is both. Setting this attribute to &quot;srconly&quot;
+          is equivalent to wrapping the selector in the <code>&lt;not&gt;</code>
+          selector container.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Present Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${ant.1.5}/src/main&quot; includes=&quot;**/*.java&quot;&gt;
+    &lt;present present=&quot;srconly&quot; targetdir=&quot;${ant.1.4.1}/src/main&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the Java source files which are new in the
+      1.5 release.
+    </p>
+
+    <a name="regexpselect"></a>
+    <h4>Regular Expression Selector</h4>
+
+    <p>The <code>&lt;containsregexp&gt;</code> tag in a FileSet limits
+    the files defined by that fileset to only those which contain a
+    match to the regular expression specified by the <code>expression</code> attribute.
+    </p>
+    <p>The <code>&lt;containsregexp&gt;</code> selector can be used as a
+      ResourceSelector (see the
+      <a href="resources.html#restrict">&lt;restrict&gt;</a>
+      ResourceCollection).</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">expression</td>
+        <td valign="top">Specifies the regular expression that must
+        match true in every file</td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the regular expression Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${doc.path}&quot; includes=&quot;*.txt&quot;&gt;
+    &lt;containsregexp expression=&quot;[4-6]\.[0-9]&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the text files that match the regular expression
+    (have a 4,5 or 6 followed by a period and a number from 0 to 9).
+
+
+    <a name="sizeselect"></a>
+    <h4>Size Selector</h4>
+
+    <p>The <code>&lt;size&gt;</code> tag in a FileSet will put
+    a limit on the files specified by the include tag, so that tags
+    which do not meet the size limits specified by the selector will not
+    end up being selected.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">value</td>
+        <td valign="top">The size of the file which should be tested for.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">units</td>
+        <td valign="top">The units that the <code>value</code> attribute
+          is expressed in. When using the standard single letter SI
+          designations, such as &quot;k&quot;,&quot;M&quot;, or
+          &quot;G&quot;, multiples of 1000 are used. If you want to use
+          power of 2 units, use the IEC standard: &quot;Ki&quot; for 1024,
+          &quot;Mi&quot; for 1048576, and so on. The default is no units,
+          which means the <code>value</code> attribute expresses the exact
+          number of bytes.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">when</td>
+        <td valign="top">Indicates how to interpret the size, whether
+          the files to be selected should be larger, smaller, or equal to
+          that value. Acceptable values for this attribute are:
+          <ul>
+            <li>less - select files less than the indicated size
+            <li>more - select files greater than the indicated size
+            <li>equal - select files this exact size
+          </ul>
+          The default is equal.
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Size Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${jar.path}&quot;&gt;
+  &lt;patternset&gt;
+    &lt;include name=&quot;**/*.jar&quot;/&gt;
+  &lt;/patternset&gt;
+  &lt;size value=&quot;4&quot; units=&quot;Ki&quot; when=&quot;more&quot;/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all JAR files that are larger than 4096 bytes.</p>
+
+    <a name="typeselect"></a>
+    <h4>Type Selector</h4>
+
+    <p>The <code>&lt;type&gt;</code> tag selects files of a certain type:
+    directory or regular.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">type</td>
+        <td valign="top">The type of file which should be tested for.
+            Acceptable values are:
+            <ul>
+                <li>file - regular files</li>
+                <li>dir - directories</li>
+            </ul>
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Type Selector to select only
+    directories in <code>${src}</code></p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${src}&quot;&gt;
+  &lt;type type="dir"/&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>The Type Selector is often used in conjunction with other selectors.
+    For example, to select files that also exist in a <code>template</code>
+    directory, but avoid selecting empty directories, use:
+
+<blockquote><pre>
+&lt;fileset dir="${src}"&gt;
+    &lt;and&gt;
+        &lt;present targetdir="template"/&gt;
+        &lt;type type="file"/&gt;
+    &lt;/and&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+
+    <a name="modified"></a>
+    <h4>Modified Selector</h4>
+    <p>The <code>&lt;modified&gt;</code> selector computes a value for a file, compares that
+    to the value stored in a cache and select the file, if these two values
+    differ.</p>
+    <p>Because this selector is highly configurable the order in which the selection is done
+    is: <ol>
+        <li> get the absolute path for the file </li>
+        <li> get the cached value from the configured cache (absolute path as key) </li>
+        <li> get the new value from the configured algorithm </li>
+        <li> compare these two values with the configured comparator </li>
+        <li> update the cache if needed and requested </li>
+        <li> do the selection according to the comparison result </li>
+        </ol>
+    The comparison, computing of the hashvalue and the store is done by implementation
+    of special interfaces. Therefore they may provide additional parameters.</p>
+
+    <p>The <code>&lt;modified&gt;</code> selector can be used as a
+      ResourceSelector (see the
+      <a href="resources.html#restrict">&lt;restrict&gt;</a>
+      ResourceCollection).
+    In that case it maps simple file resources to files and does its job. If the
+    resource is from another type, the <code>&lt;modified&gt;</code> selector tries
+    to (<b>attention!</b>) copy the content into a local file for computing the
+    hashvalue.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top"> algorithm </td>
+        <td valign="top"> The type of algorithm should be used.
+            Acceptable values are (further information see later):
+            <ul>
+                <li> hashvalue - HashvalueAlgorithm </li>
+                <li> digest - DigestAlgorithm </li>
+                <li> checksum - ChecksumAlgorithm </li>
+            </ul>
+        </td>
+        <td valign="top" align="center"> No, defaults to <i>digest</i> </td>
+      </tr>
+      <tr>
+        <td valign="top"> cache </td>
+        <td valign="top"> The type of cache should be used.
+            Acceptable values are (further information see later):
+            <ul>
+                <li> propertyfile - PropertyfileCache </li>
+            </ul>
+        </td>
+        <td valign="top" align="center"> No, defaults to <i>propertyfile</i> </td>
+      </tr>
+      <tr>
+        <td valign="top"> comparator </td>
+        <td valign="top"> The type of comparator should be used.
+            Acceptable values are (further information see later):
+            <ul>
+                <li> equal - EqualComparator </li>
+                <li> rule - java.text.RuleBasedCollator
+                  <!-- NOTE -->
+                  <i>(see <a href="#ModSelNote">note</a> for restrictions)</i>
+                </li>
+            </ul>
+        </td>
+        <td valign="top" align="center"> No, defaults to <i>equal</i> </td>
+      </tr>
+      <tr>
+        <td valign="top"> algorithmclass </td>
+        <td valign="top"> Classname of custom algorithm implementation. Lower
+          priority than <i>algorithm</i>. </td>
+        <td valign="top" align="center"> No </td>
+      </tr>
+      <tr>
+        <td valign="top"> cacheclass </td>
+        <td valign="top"> Classname of custom cache implementation. Lower
+          priority than <i>cache</i>. </td>
+        <td valign="top" align="center"> No </td>
+      </tr>
+      <tr>
+        <td valign="top"> comparatorclass </td>
+        <td valign="top"> Classname of custom comparator implementation. Lower
+          priority than <i>comparator</i>. </td>
+        <td valign="top" align="center"> No </td>
+      </tr>
+      <tr>
+        <td valign="top"> update </td>
+        <td valign="top"> Should the cache be updated when values differ? (boolean) </td>
+        <td valign="top" align="center"> No, defaults to <i>true</i> </td>
+      </tr>
+      <tr>
+        <td valign="top"> seldirs </td>
+        <td valign="top"> Should directories be selected? (boolean) </td>
+        <td valign="top" align="center"> No, defaults to <i>true</i> </td>
+      </tr>
+      <tr>
+        <td valign="top"> selres </td>
+        <td valign="top"> Should Resources whithout an InputStream, and
+           therefore without checking, be selected?  (boolean) </td>
+        <td valign="top" align="center"> No, defaults to <i>true</i>. Only relevant
+           when used as ResourceSelector. </td>
+      </tr>
+      <tr>
+        <td valign="top"> delayupdate </td>
+        <td valign="top"> If set to <i>true</i>, the storage of the cache will be delayed until the
+             next finished BuildEvent; task finished, target finished or build finished,
+             whichever comes first.  This is provided for increased performance.  If set
+             to <i>false</i>, the storage of the cache will happen with each change.  This
+             attribute depends upon the <i>update</i> attribute. (boolean)</td>
+        <td valign="top" align="center"> No, defaults to <i>true</i> </td>
+      </tr>
+    </table>
+
+    <p>These attributes can be set with nested <code>&lt;param/&gt;</code> tags. With <code>&lt;param/&gt;</code>
+    tags you can set other values too - as long as they are named according to
+    the following rules: <ul>
+        <li> <b> algorithm </b>: same as attribute algorithm </li>
+        <li> <b> cache </b>: same as attribute cache </li>
+        <li> <b> comparator </b>: same as attribute comparator </li>
+        <li> <b> algorithmclass </b>: same as attribute algorithmclass </li>
+        <li> <b> cacheclass </b>: same as attribute cacheclass </li>
+        <li> <b> comparatorclass </b>: same as attribute comparatorclass </li>
+        <li> <b> update </b>: same as attribute update </li>
+        <li> <b> seldirs </b>: same as attribute seldirs </li>
+        <li> <b> algorithm.* </b>: Value is transfered to the algorithm via its
+                                   <i>set</i>XX-methods </li>
+        <li> <b> cache.* </b>: Value is transfered to the cache via its
+                                   <i>set</i>XX-methods </li>
+        <li> <b> comparator.* </b>: Value is transfered to the comparator via its
+                                   <i>set</i>XX-methods </li>
+    </ul></p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr><td colspan="2"><font size="+1"><b> Algorithm options</b></font></td></tr>
+      <tr>
+        <td valign="top"><b>Name</b></td>
+        <td valign="top"><b>Description</b></td>
+      </tr>
+      <tr>
+        <td valign="top"> hashvalue </td>
+        <td valign="top"> Reads the content of a file into a java.lang.String
+          and use thats hashValue(). No additional configuration required.
+        </td>
+      </tr>
+      <tr>
+        <td valign="top"> digest </td>
+        <td valign="top"> Uses java.security.MessageDigest. This Algorithm supports
+          the following attributes:
+          <ul>
+            <li><i>algorithm.algorithm</i> (optional): Name of the Digest algorithm
+                (e.g. 'MD5' or 'SHA', default = <i>MD5</i>) </li>
+            <li><i>algorithm.provider</i> (optional): Name of the Digest provider
+                (default = <i>null</i>) </li>
+          </ul>
+        </td>
+      </tr>
+      <tr>
+        <td valign="top"> checksum </td>
+        <td valign="top"> Uses java.util.zip.Checksum. This Algorithm supports
+          the following attributes:
+          <ul>
+            <li><i>algorithm.algorithm</i> (optional): Name of the algorithm
+                (e.g. 'CRC' or 'ADLER', default = <i>CRC</i>) </li>
+          </ul>
+        </td>
+      </tr>
+      <tr><td colspan="2"><font size="+1"><b> Cache options </b></font></td></tr>
+      <tr>
+        <td valign="top"> propertyfile </td>
+        <td valign="top"> Use the java.util.Properties class and its possibility
+          to load and store to file.
+          This Cache implementation supports the following attributes:
+          <ul>
+            <li><i>cache.cachefile</i> (optional): Name of the properties-file
+                (default = <i>cache.properties</i>) </li>
+          </ul>
+        </td>
+      </tr>
+      <tr><td colspan="2"><font size="+1"><b> Comparator options</b></font></td></tr>
+      <tr>
+        <td valign="top"> equal </td>
+        <td valign="top"> Very simple object comparison. </td>
+      </tr>
+      <tr>
+        <td valign="top"> rule </td>
+        <td valign="top"> Uses <i>java.text.RuleBasedCollator</i> for Object
+          comparison.
+          <!-- NOTE -->
+          <i>(see <a href="#ModSelNote">note</a> for restrictions)</i>
+        </td>
+      </tr>
+    </table>
+
+    <p>The <code>&lt;modified&gt;</code> selector supports a nested
+    <code>&lt;classpath&gt;</code> element that represents a <a href="../using.html#path">
+    PATH like structure</a> for finding custom interface implementations. </p>
+
+    <p>Here are some examples of how to use the Modified Selector:</p>
+
+    <blockquote><pre>
+    &lt;copy todir="dest"&gt;
+        &lt;fileset dir="src"&gt;
+            &lt;modified/&gt;
+        &lt;/fileset&gt;
+    &lt;/copy&gt;
+    </pre></blockquote>
+    <p>This will copy all files from <i>src</i> to <i>dest</i> which content has changed.
+    Using an updating PropertyfileCache with cache.properties and
+    MD5-DigestAlgorithm.</p>
+
+    <blockquote><pre>
+    &lt;copy todir="dest"&gt;
+        &lt;fileset dir="src"&gt;
+            &lt;modified update="true"
+                      seldirs="true"
+                      cache="propertyfile"
+                      algorithm="digest"
+                      comparator="equal"&gt;
+                &lt;param name="cache.cachefile"     value="cache.properties"/&gt;
+                &lt;param name="algorithm.algorithm" value="MD5"/&gt;
+            &lt;/modified&gt;
+        &lt;/fileset&gt;
+    &lt;/copy&gt;
+    </pre></blockquote>
+  <p>This is the same example rewritten as CoreSelector with setting the all the values
+  (same as defaults are).</p>
+
+    <blockquote><pre>
+    &lt;copy todir="dest"&gt;
+        &lt;fileset dir="src"&gt;
+            &lt;custom class="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector"&gt;
+                &lt;param name="update"     value="true"/&gt;
+                &lt;param name="seldirs"    value="true"/&gt;
+                &lt;param name="cache"      value="propertyfile"/&gt;
+                &lt;param name="algorithm"  value="digest"/&gt;
+                &lt;param name="comparator" value="equal"/&gt;
+                &lt;param name="cache.cachefile"     value="cache.properties"/&gt;
+                &lt;param name="algorithm.algorithm" value="MD5"/&gt;
+            &lt;/custom&gt;
+        &lt;/fileset&gt;
+    &lt;/copy&gt;
+    </pre></blockquote>
+  <p>And this is the same rewritten as CustomSelector.</p>
+
+    <blockquote><pre>
+  &lt;target name="generate-and-upload-site"&gt;
+      &lt;echo&gt; generate the site using forrest &lt;/echo&gt;
+      &lt;antcall target="site"/&gt;
+
+      &lt;echo&gt; upload the changed file &lt;/echo&gt;
+      &lt;ftp server="${ftp.server}" userid="${ftp.user}" password="${ftp.pwd}"&gt;
+          &lt;fileset dir="htdocs/manual"&gt;
+              &lt;modified/&gt;
+          &lt;/fileset&gt;
+      &lt;/ftp&gt;
+  &lt;/target&gt;
+    </pre></blockquote>
+  <p>A useful scenario for this selector inside a build environment
+  for homepage generation (e.g. with <a href="http://xml.apache.org/forrest/">
+  Apache Forrest</a>). Here all <b>changed</b> files are uploaded to the server. The
+  CacheSelector saves therefore much upload time.</p>
+
+    <blockquote><pre>
+  &lt;modified cacheclassname="com.mycompany.MyCache"&gt;
+      &lt;classpath&gt;
+          &lt;pathelement location="lib/mycompony-antutil.jar"/&gt;
+      &lt;/classpath&gt;
+  &lt;/modified&gt;
+    </pre></blockquote>
+    <p>Uses <tt>com.mycompany.MyCache</tt> from a jar outside of Ants own classpath
+    as cache implementation</p>
+
+  <a name="ModSelNote"></a>
+  <h4>Note on RuleBasedCollator</h4>
+  <p>The RuleBasedCollator needs a format for its work, but its needed while
+  instantiation. There is a problem in the initialization algorithm for this
+  case. Therefore you should not use this (or tell me the workaround :-).</p>
+
+      <a name="signedselector"></a>
+      <h4>Signed Selector</h4>
+
+      <p>
+        The <code>&lt;signedselector&gt;</code> tag selects signed files and optionaly
+        signed with a certain name.
+      </p>
+      <p>
+        This selector has been added in Apache Ant 1.7.
+      </p>
+      <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Required</b></td>
+        </tr>
+        <tr>
+          <td valign="top">name</td>
+          <td valign="top"> The signature name to check for.</td>
+          <td valign="top" align="center">no</td>
+        </tr>
+      </table>
+
+      <a name="scriptselector"></a>
+      <h4>Script Selector</h4>
+
+      <p>
+        The <code>&lt;scriptselector&gt;</code> element enables you
+        to write a complex selection algorithm in any
+        <a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+        or
+        <a href="https://scripting.dev.java.net">JSR 223</a>
+        supported language.</p>
+        See the <a href="../OptionalTasks/script.html">Script</a> task for
+        an explanation of scripts and dependencies.
+      </p>
+      <p>
+        This selector was added in Apache Ant 1.7.
+      </p>
+      <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Required</b></td>
+        </tr>
+        <tr>
+          <td valign="top">language</td>
+          <td valign="top">language of the script.</td>
+          <td valign="top" align="center">yes</td>
+        </tr>
+        <tr>
+          <td valign="top">manager</td>
+          <td valign="top">
+            The script engine manager to use.
+            See the <a href="../OptionalTasks/script.html">script</a> task
+            for using this attribute.
+          </td>
+          <td valign="top" align="center">No - default is "auto"</td>
+        </tr>
+        <tr>
+          <td valign="top">src</td>
+          <td valign="top">filename of the script</td>
+          <td valign="top" align="center">no</td>
+        </tr>
+        <tr>
+          <td valign="top">setbeans</td>
+          <td valign="top">whether to have all properties, references and targets as
+            global variables in the script.</td>
+          <td valign="top" align="center">No, default is "true".</td>
+        </tr>
+        <tr>
+          <td valign="top">classpath</td>
+          <td valign="top">
+            The classpath to pass into the script.
+          </td>
+          <td align="center" valign="top">No</td>
+        </tr>
+        <tr>
+          <td valign="top">classpathref</td>
+          <td valign="top">The classpath to use, given as a
+            <a href="../using.html#references">reference</a> to a path defined elsewhere.
+            <td align="center" valign="top">No</td>
+          </tr>
+      </table>
+  <p>
+    This selector can take a nested &lt;classpath&gt; element.
+    See the <a href="../OptionalTasks/script.html">script</a> task
+    on how to use this element.
+  </p>
+      <p>
+      If no <code>src</code> attribute is supplied, the script must be nested
+      inside the selector declaration.
+      </p>
+      <p>The embedded script is invoked for every test, with
+         the bean <code>self</code>
+        is bound to the selector. It has an attribute <code>selected</code>
+        must can be set using <code>setSelected(boolean)</code> to select that
+        file.
+
+      <p>
+
+      The following beans are configured for every script, alongside
+      the classic set of project, properties, and targets.
+
+      <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Bean</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td valign="top"><b>Type</b></td>
+        </tr>
+        <tr>
+          <td valign="top">self</td>
+          <td valign="top">selector instance</td>
+          <td valign="top">org.apache.tools.ant.types.optional</td>
+        </tr>
+        <tr>
+          <td valign="top">filename</td>
+          <td valign="top">filename of the selection</td>
+          <td valign="top" >String</td>
+        </tr>
+        <tr>
+          <td valign="top">file</td>
+          <td valign="top">file of the selection</td>
+          <td valign="top" >java.io.File</td>
+        </tr>
+        <tr>
+          <td valign="top">basedir</td>
+          <td valign="top">Fileset base directory</td>
+          <td valign="top" >java.io.File</td>
+        </tr>
+
+      </table>
+      <p>
+      The <code>self</code> bean maps to the selector, which has the following
+      attributes. Only the <code>selected</code> flag is writeable, the rest
+      are read only via their getter methods.
+
+            <table border="1" cellpadding="2" cellspacing="0">
+        <tr>
+          <td valign="top"><b>Attribute</b></td>
+          <td valign="top"><b>Description</b></td>
+          <td align="center" valign="top"><b>Type</b></td>
+        </tr>
+        <tr>
+          <td valign="top">selected</td>
+          <td valign="top">writeable flag to select this file</td>
+          <td valign="top" align="center">boolean</td>
+        </tr>
+        <tr>
+          <td valign="top">filename</td>
+          <td valign="top">filename of the selection</td>
+          <td valign="top" >String</td>
+        </tr>
+        <tr>
+          <td valign="top">file</td>
+          <td valign="top">file of the selection</td>
+          <td valign="top" >java.io.File</td>
+        </tr>
+        <tr>
+          <td valign="top">basedir</td>
+          <td valign="top">Fileset base directory</td>
+          <td valign="top" >java.io.File</td>
+        </tr>
+      </table>
+
+      <p>
+      Example
+      </p>
+<pre>
+    &lt;scriptselector language=&quot;javascript&quot;&gt;
+      self.setSelected(true);
+    &lt;/scriptselector&gt;
+</pre>
+    <p>
+    Selects every file.
+    </p>
+
+<pre>
+    &lt;scriptselector language=&quot;javascript&quot;&gt;
+      self.setSelected((filename.length%2)==0);
+    &lt;/scriptselector&gt;
+</pre>
+Select files whose filename length is even.
+
+    <a name="selectcontainers"></a>
+    <h3>Selector Containers</h3>
+
+    <p>To create more complex selections, a variety of selectors that
+    contain other selectors are available for your use. They combine the
+    selections of their child selectors in various ways.</p>
+
+    <p>The selector containers are:</p>
+
+    <ul>
+      <li><a href="#andselect"><code>&lt;and&gt;</code></a> - select a file only if all
+        the contained selectors select it.
+      <li><a href="#majorityselect"><code>&lt;majority&gt;</code></a> - select a file
+        if a majority of its selectors select it.
+      <li><a href="#noneselect"><code>&lt;none&gt;</code></a> - select a file only if
+        none of the contained selectors select it.
+      <li><a href="#notselect"><code>&lt;not&gt;</code></a> - can contain only one
+        selector, and reverses what it selects and doesn't select.
+      <li><a href="#orselect"><code>&lt;or&gt;</code></a> - selects a file if any one
+        of the contained selectors selects it.
+      <li><a href="#selectorselect"><code>&lt;selector&gt;</code></a> - contains only one
+        selector and forwards all requests to it without alteration, provided
+        that any <code>&quot;if&quot;</code> or
+        <code>&quot;unless&quot;</code> conditions are met. This
+        is the selector to use if you want to define a reference. It is
+        usable as an element of <code>&lt;project&gt;</code>. It is also
+        the one to use if you want selection of files to be dependent on
+        Ant property settings.
+    </ul>
+
+    <p>All selector containers can contain any other selector, including
+    other containers, as an element. Using containers, the selector tags
+    can be arbitrarily deep. Here is a complete list of allowable
+    selector elements within a container:</P>
+
+    <ul>
+      <li><code>&lt;and&gt;</code></li>
+      <li><code>&lt;contains&gt;</code></li>
+      <li><code>&lt;custom&gt;</code></li>
+      <li><code>&lt;date&gt;</code></li>
+      <li><code>&lt;depend&gt;</code></li>
+      <li><code>&lt;depth&gt;</code></li>
+      <li><code>&lt;filename&gt;</code></li>
+      <li><code>&lt;majority&gt;</code></li>
+      <li><code>&lt;none&gt;</code></li>
+      <li><code>&lt;not&gt;</code></li>
+      <li><code>&lt;or&gt;</code></li>
+      <li><code>&lt;present&gt;</code></li>
+      <li><code>&lt;selector&gt;</code></li>
+      <li><code>&lt;size&gt;</code></li>
+    </ul>
+
+    <a name="andselect"></a>
+    <h4>And Selector</h4>
+
+    <p>The <code>&lt;and&gt;</code> tag selects files that are
+    selected by all of the elements it contains. It returns as
+    soon as it finds a selector that does not select the file,
+    so it is not guaranteed to check every selector.
+    </p>
+
+    <p>Here is an example of how to use the And Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${dist}&quot; includes=&quot;**/*.jar&quot;&gt;
+    &lt;and&gt;
+        &lt;size value=&quot;4&quot; units=&quot;Ki&quot; when=&quot;more&quot;/&gt;
+        &lt;date datetime=&quot;01/01/2001 12:00 AM&quot; when=&quot;before&quot;/&gt;
+    &lt;/and&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the JAR file larger than 4096 bytes which haven't been update
+      since the last millenium.
+    </p>
+
+
+    <a name="majorityselect"></a>
+    <h4>Majority Selector</h4>
+
+    <p>The <code>&lt;majority&gt;</code> tag selects files provided
+    that a majority of the contained elements also select it. Ties are
+    dealt with as specified by the <code>allowtie</code> attribute.
+    </p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">allowtie</td>
+        <td valign="top">Whether files should be selected if there
+          are an even number of selectors selecting them as are
+          not selecting them. Default is true.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+
+    <p>Here is an example of how to use the Majority Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${docs}&quot; includes=&quot;**/*.html&quot;&gt;
+    &lt;majority&gt;
+        &lt;contains text=&quot;project&quot; casesensitive="false"/&gt;
+        &lt;contains text=&quot;taskdef&quot; casesensitive="false"/&gt;
+        &lt;contains text=&quot;IntrospectionHelper&quot; casesensitive="true"/&gt;
+    &lt;/majority&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the HTML files which contain at least two of the three
+    phrases "project", "taskdef", and "IntrospectionHelper" (this last phrase must
+    match case exactly).
+    </p>
+
+
+    <a name="noneselect"></a>
+    <h4>None Selector</h4>
+
+    <p>The <code>&lt;none&gt;</code> tag selects files that are
+    not selected by any of the elements it contains. It returns as
+    soon as it finds a selector that selects the file,
+    so it is not guaranteed to check every selector.
+    </p>
+
+    <p>Here is an example of how to use the None Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${src}&quot; includes=&quot;**/*.java&quot;&gt;
+    &lt;none&gt;
+        &lt;present targetdir=&quot;${dest}&quot;/&gt;
+        &lt;present targetdir=&quot;${dest}&quot;&gt;
+            &lt;mapper type=&quot;glob&quot; from=&quot;*.java&quot; to=&quot;*.class&quot;/&gt;
+        &lt;/present&gt;
+    &lt;/none&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects only Java files which do not have equivalent java or
+    class files in the dest directory.
+    </p>
+
+
+    <a name="notselect"></a>
+    <h4>Not Selector</h4>
+
+    <p>The <code>&lt;not&gt;</code> tag reverses the meaning of the
+    single selector it contains.
+    </p>
+
+    <p>Here is an example of how to use the Not Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${src}&quot; includes=&quot;**/*.java&quot;&gt;
+    &lt;not&gt;
+        &lt;contains text=&quot;test&quot;/&gt;
+    &lt;/not&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the files in the src directory that do not contain the
+    string "test".
+    </p>
+
+
+    <a name="orselect"></a>
+    <h4>Or Selector</h4>
+
+    <p>The <code>&lt;or&gt;</code> tag selects files that are
+    selected by any one of the elements it contains. It returns as
+    soon as it finds a selector that selects the file,
+    so it is not guaranteed to check every selector.
+    </p>
+
+    <p>Here is an example of how to use the Or Selector:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${basedir}&quot;&gt;
+    &lt;or&gt;
+        &lt;depth max=&quot;0&quot;/&gt;
+        &lt;filename name="*.png"/&gt;
+        &lt;filename name="*.gif"/&gt;
+        &lt;filename name="*.jpg"/&gt;
+    &lt;/or&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all the files in the top directory along with all the
+    image files below it.
+    </p>
+
+
+    <a name="selectorselect"></a>
+    <h4>Selector Reference</h4>
+
+    <p>The <code>&lt;selector&gt;</code> tag is used to create selectors
+    that can be reused through references. It is the only selector which can
+    be used outside of
+    any target, as an element of the <code>&lt;project&gt;</code> tag. It
+    can contain only one other selector, but of course that selector can
+    be a container.
+    </p>
+
+    <p>The <code>&lt;selector&gt;</code> tag can also be used to select
+    files conditionally based on whether an Ant property exists or not.
+    This functionality is realized using the <code>&quot;if&quot;</code> and
+    <code>&quot;unless&quot;</code> attributes in exactly the same way they
+    are used on targets or on the <code>&lt;include&gt;</code> and
+    <code>&lt;exclude&gt;</code> tags within a
+    <code>&lt;patternset&gt;</code>.</p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">if</td>
+        <td valign="top">Allow files to be selected only if the named
+          property is set.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">unless</td>
+        <td valign="top">Allow files to be selected only if the named
+          property is <b>not</b> set.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is an example of how to use the Selector Reference:</p>
+
+    <blockquote><pre>
+&lt;project default=&quot;all&quot; basedir=&quot;./ant&quot;&gt;
+
+    &lt;selector id=&quot;completed&quot;&gt;
+        &lt;none&gt;
+            &lt;depend targetdir=&quot;build/classes&quot;&gt;
+                &lt;mapper type=&quot;glob&quot; from=&quot;*.java&quot; to=&quot;*.class&quot;/&gt;
+            &lt;/depend&gt;
+            &lt;depend targetdir=&quot;docs/manual/api&quot;&gt;
+                &lt;mapper type=&quot;glob&quot; from=&quot;*.java&quot; to=&quot;*.html&quot;/&gt;
+            &lt;/depend&gt;
+        &lt;/none&gt;
+    &lt;/selector&gt;
+
+    &lt;target&gt;
+        &lt;zip&gt;
+            &lt;fileset dir=&quot;src/main&quot; includes=&quot;**/*.java&quot;&gt;
+                &lt;selector refid=&quot;completed&quot;/&gt;
+            &lt;/fileset&gt;
+        &lt;/zip&gt;
+    &lt;/target&gt;
+
+&lt;/project&gt;
+</pre></blockquote>
+
+    <p>Zips up all the Java files which have an up-to-date equivalent
+    class file and javadoc file associated with them.
+    </p>
+
+    <p>And an example of selecting files conditionally, based on whether
+    properties are set:</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${working.copy}&quot;&gt;
+    &lt;or&gt;
+        &lt;selector if=&quot;include.tests&quot;&gt;
+            &lt;filename name=&quot;**/*Test.class&quot;&gt;
+        &lt;/selector&gt;
+        &lt;selector if=&quot;include.source&quot;&gt;
+            &lt;and&gt;
+                &lt;filename name=&quot;**/*.java&quot;&gt;
+                &lt;not&gt;
+                    &lt;selector unless=&quot;include.tests&quot;&gt;
+                        &lt;filename name=&quot;**/*Test.java&quot;&gt;
+                    &lt;/selector&gt;
+                &lt;/not&gt;
+            &lt;/and&gt;
+        &lt;/selector&gt;
+    &lt;/or&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>A fileset that conditionally contains Java source files and Test
+    source and class files.</p>
+
+    <a name="customselect"></a>
+    <h3>Custom Selectors</h3>
+
+    <p>You can write your own selectors and use them within the selector
+    containers by specifying them within the <code>&lt;custom&gt;</code> tag.</p>
+
+    <p>First, you have to write your selector class in Java. The only
+    requirement it must meet in order to be a selector is that it implements
+    the <code>org.apache.tools.ant.types.selectors.FileSelector</code>
+    interface, which contains a single method. See
+    <a href="selectors-program.html">Programming Selectors in Ant</a> for
+    more information.</p>
+
+    <p>Once that is written, you include it in your build file by using
+    the <code>&lt;custom&gt;</code> tag.
+    </p>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td valign="top"><b>Attribute</b></td>
+        <td valign="top"><b>Description</b></td>
+        <td align="center" valign="top"><b>Required</b></td>
+      </tr>
+      <tr>
+        <td valign="top">classname</td>
+        <td valign="top">The name of your class that implements
+          <code>org.apache.tools.ant.types.selectors.FileSelector</code>.
+        </td>
+        <td valign="top" align="center">Yes</td>
+      </tr>
+      <tr>
+        <td valign="top">classpath</td>
+        <td valign="top">The classpath to use in order to load the
+          custom selector class. If neither this classpath nor the
+          classpathref are specified, the class will be
+          loaded from the classpath that Ant uses.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">classpathref</td>
+        <td valign="top">A reference to a classpath previously
+          defined. If neither this reference nor the
+          classpath above are specified, the class will be
+          loaded from the classpath that Ant uses.
+        </td>
+        <td valign="top" align="center">No</td>
+      </tr>
+    </table>
+
+    <p>Here is how you use <code>&lt;custom&gt;</code> to
+    use your class as a selector:
+    </p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${mydir}&quot; includes=&quot;**/*&quot;&gt;
+    &lt;custom classname=&quot;com.mydomain.MySelector&quot;&gt;
+        &lt;param name=&quot;myattribute&quot; value=&quot;myvalue&quot;/&gt;
+    &lt;/custom&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>A number of core selectors can also be used as custom selectors
+    by specifying their attributes using <code>&lt;param&gt;</code> elements. These
+    are</p>
+
+    <ul>
+      <li><a href="#containsselect">Contains Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.ContainsSelector</code>
+      <li><a href="#dateselect">Date Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.DateSelector</code>
+      <li><a href="#depthselect">Depth Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.DepthSelector</code>
+      <li><a href="#filenameselect">Filename Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.FilenameSelector</code>
+      <li><a href="#sizeselect">Size Selector</a> with
+        classname <code>org.apache.tools.ant.types.selectors.SizeSelector</code>
+    </ul>
+
+    <p>Here is the example from the Depth Selector section rewritten
+    to use the selector through <code>&lt;custom&gt;</code>.</p>
+
+    <blockquote><pre>
+&lt;fileset dir=&quot;${doc.path}&quot; includes=&quot;**/*&quot;&gt;
+    &lt;custom classname=&quot;org.apache.tools.ant.types.selectors.DepthSelector&quot;&gt;
+        &lt;param name=&quot;max&quot; value=&quot;1&quot;/&gt;
+    &lt;/custom&gt;
+&lt;/fileset&gt;
+</pre></blockquote>
+
+    <p>Selects all files in the base directory and one directory below
+    that.</p>
+
+    <p>For more details concerning writing your own selectors, consult
+    <a href="selectors-program.html">Programming Selectors in Ant</a>.</p>
+
+    
+
+  </body>
+
+</html>
diff --git a/trunk/docs/manual/CoreTypes/tarfileset.html b/trunk/docs/manual/CoreTypes/tarfileset.html
new file mode 100755
index 0000000..920d024
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/tarfileset.html
@@ -0,0 +1,160 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>TarFileSet Type</title>
+</head>
+<body>
+<h2><a name="fileset">TarFileSet</a></h2>
+
+<p><em>TarFileSet</em> has been added as a stand-alone type in Ant
+1.7.</p>
+
+<p>A <code>&lt;tarfileset&gt;</code> is a special form of a <code>&lt;<a
+ href="fileset.html">fileset</a>&gt;</code> which can behave in 2
+different ways : <br>
+</p>
+<ul>
+  <li>When the <span style="font-style: italic;">src</span> attribute
+  is used - or a nested resource collection has been specified, the
+  tarfileset is populated with tar entries found in the file <span
+  style="font-style: italic;">src</span>.<br>
+  </li>
+  <li>When the <span style="font-style: italic;">dir</span> attribute
+is used, the tarfileset is populated with filesystem files found under <span
+ style="font-style: italic;">dir</span>.<br>
+  </li>
+</ul>
+<p><code>&lt;tarfileset&gt;</code> supports all attributes of <code>&lt;<a
+ href="fileset.html">fileset</a>&gt;</code>
+in addition to those listed below.<br>
+</p>
+<p>A tarfileset can be defined with the <span style="font-style:
+italic;">id </span>attribute and referred to with the <span
+style="font-style: italic;">refid</span> attribute.  This is also true
+for tarfileset which has been added in Ant 1.7.<br>
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tbody>
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td valign="top" align="center"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">prefix</td>
+      <td valign="top">all files in the fileset are prefixed with that 
+path in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">fullpath</td>
+      <td valign="top">the file described by the fileset is placed at  
+that exact location in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">src</td>
+      <td valign="top">may be used in place of the <i>dir</i> attribute
+ to specify a tar file whose contents will be extracted and     included
+in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">filemode</td>
+      <td valign="top">A 3 digit octal string, specify the user, group 
+and other modes in the standard Unix fashion.  Only applies to    
+plain files.  Default is 644.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">dirmode</td>
+      <td valign="top">A 3 digit octal string, specify the user, group 
+and other modes in the standard Unix fashion.  Only applies to    
+directories.  Default is 755.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">username</td>
+      <td valign="top">The username for the tar entry. This is not the same as the UID.
+       </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">group</td>
+      <td valign="top">The groupname for the tar entry. This is not the same as the GID.
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">uid</td>
+      <td valign="top">The user identifier (UID) for the tar entry. This is an integer value
+        and is not the same as the username.
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">gid</td>
+      <td valign="top">The group identifier (GID) for the tar entry.
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+  </tbody>
+</table>
+<p>The <i>fullpath</i> attribute can only be set for filesets that
+represent a single file. The <i>prefix</i> and <i>fullpath</i>
+attributes cannot both be set on the same fileset.</p>
+<p>When using the <i>src</i> attribute, include and exclude patterns
+may be used to specify a subset of the archive for inclusion in the
+archive as with the <i>dir</i> attribute.</p>
+
+<p>Please note that currently only the <a
+href="../CoreTasks/tar.html">tar</a> task uses the permission and
+ownership attributes.</p>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any <a href="resources.html">resource</a> or single element
+resource collection</h4>
+
+<p>The specified resource will be used as src.</p>
+
+<h4>Examples</h4>
+<blockquote>
+<pre>
+  &lt;copy todir="some-dir"&gt;
+    &lt;tarfileset includes="lib/**"&gt;
+      &lt;bzip2resource&gt;
+        &lt;url url="http://example.org/dist/some-archive.tar.bz2"/&gt;
+      &lt;/bzip2resource&gt;
+    &lt;/tarfileset&gt;
+  &lt;/copy&gt;
+      </pre></blockquote>
+
+<p>downloads the archive some-archive.tar.bz2, uncompresses and
+extracts it on the fly, copies the contents of the lib directory into
+some-dir and discards the rest of the archive.  File timestamps will
+be compared between the archive's entries and files inside the target
+directory, no files get overwritten unless they are out-of-date.</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/xmlcatalog.html b/trunk/docs/manual/CoreTypes/xmlcatalog.html
new file mode 100644
index 0000000..67058ae
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/xmlcatalog.html
@@ -0,0 +1,306 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>XMLCatalog Type</title>
+</head>
+
+<body>
+
+<h2><a name="XMLCatalog">XMLCatalog</a></h2>
+
+<p>An XMLCatalog is a catalog of public resources such as DTDs or
+entities that are referenced in an XML document.  Catalogs are
+typically used to make web references to resources point to a locally
+cached copy of the resource.</p>
+
+<p>This allows the XML Parser, XSLT Processor or other consumer of XML 
+documents
+to efficiently allow a local substitution for a resource available on the 
+web.
+</p>
+<p><b>Note:</b> This task <em>uses, but does not depend on</em> external
+libraries not included in the Ant distribution.  See <a
+  href="../install.html#librarydependencies">Library Dependencies</a> for more
+information.</p>
+<p>This data type provides a catalog of resource locations based
+on the <a
+href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
+OASIS "Open Catalog" standard</a>.  The catalog entries are used
+both for Entity resolution and URI resolution, in accordance with
+the <code>org.xml.sax.EntityResolver</code> and <code>
+javax.xml.transform.URIResolver</code> interfaces as defined
+in the <a href="http://java.sun.com/xml/jaxp">Java API for XML
+Processing (JAXP) Specification</a>.</p>
+<p>For example, in a <code>web.xml</code> file, the DTD is referenced as:
+<pre>
+&lt;!DOCTYPE web-app PUBLIC &quot;-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN&quot;
+  &quot;http://java.sun.com/j2ee/dtds/web-app_2_2.dtd&quot;&gt;
+</pre>
+The XML processor, without XMLCatalog support, would need to retrieve the 
+DTD from
+the URL specified whenever validation of the document was required.
+</p>
+<p>This can be very time consuming during the build process,
+especially where network throughput is limited.  Alternatively, you
+can do the following:
+<ol>
+<li>Copy <code>web-app_2_2.dtd</code> onto your local disk somewhere (either in the
+filesystem or even embedded inside a jar or zip file on the classpath).</li>
+<li>Create an <code>&lt;xmlcatalog&gt;</code> with a <code>&lt;dtd&gt;</code> 
+element whose <code>location</code> attribute points to the file.</li>
+<li>Success! The XML processor will now use the local copy instead of calling out
+to the internet.</li>
+</ol>
+</p>
+<p>XMLCatalogs can appear inside tasks
+that support this feature or at the same level as <code>target</code>
+- i.e., as children of <code>project</code> for reuse across different 
+tasks,
+e.g. XML Validation and XSLT Transformation.  The XML Validate task
+uses XMLCatalogs for entity resolution.  The XSLT Transformation
+task uses XMLCatalogs for both entity and URI resolution.</p>
+<p>XMLCatalogs are specified as either a reference to another
+XMLCatalog, defined previously in a build file, or as a list of
+<code>dtd</code> or <code>entity</code> locations.  In addition,
+external catalog files may be specified in a nested <code>catalogpath</code> ,
+but they will be ignored unless the resolver library from
+xml-commons is available in the system classpath.  <b>Due to backwards
+incompatible changes in the resolver code after the release of
+resolver 1.0, Ant will not support resolver.jar in version 1.0 - we
+expect a resolver release 1.1 to happen before Ant 1.6 gets
+released.</b>  A separate classpath for entity resolution may be
+specified inline via nested <code>classpath</code> elements; otherwise
+the system classpath is used for this as well.</p>
+<p>XMLCatalogs can also be nested inside other XMLCatalogs.  For
+example, a "superset" XMLCatalog could be made by including several
+nested XMLCatalogs that referred to other, previously defined
+XMLCatalogs.</p>
+<p>Resource locations can be specified either in-line or in
+external catalog file(s), or both.  In order to use an external
+catalog file, the xml-commons resolver library ("resolver.jar")
+must be in your path.  External catalog files may be either <a
+href="http://oasis-open.org/committees/entity/background/9401.html">
+plain text format</a> or <a
+href="http://www.oasis-open.org/committees/entity/spec-2001-08-06.html">
+XML format</a>.  If the xml-commons resolver library is not found in the
+classpath, external catalog files, specified in <code>catalogpath</code>, 
+will be ignored and a warning
+will be logged.  In this case, however, processing of inline entries will
+proceed normally.</p>
+<p>Currently, only <code>&lt;dtd&gt;</code> and
+<code>&lt;entity&gt;</code> elements may be specified inline; these
+roughly correspond to OASIS catalog entry types <code>PUBLIC</code> and
+<code>URI</code> respectively.  By contrast, external catalog files
+may use any of the entry types defined in the 
+<a href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
++OASIS specification</a>.</p>
+<h3><a name="ResolverAlgorithm">Entity/DTD/URI Resolution Algorithm</a></h3>
+
+When an entity, DTD, or URI is looked up by the XML processor, the
+XMLCatalog searches its list of entries to see if any match.  That is,
+it attempts to match the <code>publicId</code> attribute of each entry
+with the PublicID or URI of the entity to be resolved.  Assuming a
+matching entry is found, XMLCatalog then executes the following steps:
+
+<h4>1. Filesystem lookup</h4>
+
+<p>The <code>location</code> is first looked up in the filesystem.  If
+the <code>location</code> is a relative path, the ant project basedir
+attribute is used as the base directory.  If the <code>location</code>
+specifies an absolute path, it is used as is.  Once we have an
+absolute path in hand, we check to see if a valid and readable file
+exists at that path.  If so, we are done.  If not, we proceed to the
+next step.</p>
+
+<h4>2. Classpath lookup</h4>
+
+<p>The <code>location</code> is next looked up in the classpath.
+Recall that jar files are merely fancy zip files.  For classpath
+lookup, the <code>location</code> is used as is (no base is
+prepended).  We use a Classloader to attempt to load the resource from
+the classpath.  For example, if hello.jar is in the classpath and it
+contains <code>foo/bar/blat.dtd</code> it will resolve an entity whose
+<code>location</code> is <code>foo/bar/blat.dtd</code>.  Of course, it
+will <em>not</em> resolve an entity whose <code>location</code> is
+<code>blat.dtd</code>.
+
+
+<h4>3a. Apache xml-commons resolver lookup</h4>
+
+<p>What happens next depends on whether the resolver library from
+xml-commons is available on the classpath.  If so, we defer all
+further attempts at resolving to it.  The resolver library supports
+extremely sophisticated functionality like URL rewriting and so on,
+which can be accessed by making the appropriate entries in external
+catalog files (XMLCatalog does not yet provide inline support for all
+of the entries defined in the <a
+href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">OASIS
+standard</a>).</p>
+
+<h4>3. URL-space lookup</h4>
+
+<p>Finally, we attempt to make a URL out of the <code>location</code>.
+At first this may seem like this would defeat the purpose of
+XMLCatalogs -- why go back out to the internet?  But in fact, this can
+be used to (in a sense) implement HTTP redirects, substituting one URL
+for another.  The mapped-to URL might also be served by a local web
+server.  If the URL resolves to a valid and readable resource, we are
+done.  Otherwise, we give up.  In this case, the XML processor will
+perform its normal resolution algorithm.  Depending on the processor
+configuration, further resolution failures may or may not result in
+fatal (i.e. build-ending) errors.</p>
+
+<h3>XMLCatalog attributes</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">id</td>
+    <td valign="top">a unique name for an XMLCatalog, used for referencing 
+the
+    XMLCatalog's contents from another XMLCatalog</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">refid</td>
+    <td valign="top">the <code>id</code> of another XMLCatalog whose 
+contents
+    you would like to be used for this XMLCatalog</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>XMLCatalog nested elements</h3>
+<h4>dtd/entity</h4>
+<p>The <code>dtd</code> and <code>entity</code> elements used to specify
+XMLCatalogs are identical in their structure</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">publicId</td>
+    <td valign="top">The public identifier used when defining a dtd or 
+entity,
+    e.g. <code>&quot;-//Sun Microsystems, Inc.//DTD Web Application 
+2.2//EN&quot;</code>
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">The location of the local replacement to be used for 
+the public identifier specified. This may be specified as a file name, 
+resource name found on the classpath, or a URL.  Relative paths will
+be resolved according to the base, which by default is the Ant project
+basedir.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<h4>classpath</h4>
+<p>The classpath to use for <a href="#ResolverAlgorithm">entity
+resolution</a>.  The nested <code>&lt;classpath&gt;</code> is a
+<a href="../using.html#path">path</a>-like structure.</p>
+<h4>catalogpath</h4>
+<p>
+The nested <code>catalogpath</code> element is a <a
+href="../using.html#path">path</a>-like structure listing catalog files to
+search.  All files in this path are assumed to be OASIS catalog files, in
+either
+<a href="http://oasis-open.org/committees/entity/background/9401.html">
+plain text format</a> or <a
+href="http://www.oasis-open.org/committees/entity/spec-2001-08-06.html">
+XML format</a>. Entries specifying nonexistent files will be ignored. If the
+resolver library from xml-commons is not available in the classpath, all
+<code>catalogpaths</code> will be ignored and a warning will be logged.
+</p>
+<h3>Examples</h3>
+<p>Set up an XMLCatalog with a single dtd referenced locally in a user's 
+home 
+directory:</p>
+<blockquote><pre>
+    &lt;xmlcatalog&gt;
+        &lt;dtd 
+            publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
+            location=&quot;/home/dion/downloads/docbook/docbookx.dtd&quot;/&gt;
+    &lt;/xmlcatalog&gt;
+</pre></blockquote>
+<p>Set up an XMLCatalog with a multiple dtds to be found either in the
+filesystem (relative to the Ant project basedir) or in the classpath:
+</p>
+<blockquote><pre>
+    &lt;xmlcatalog id=&quot;commonDTDs&quot;&gt;
+        &lt;dtd 
+            publicId=&quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;
+            location=&quot;docbook/docbookx.dtd&quot;/&gt;
+        &lt;dtd 
+            publicId=&quot;-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN&quot;
+            location=&quot;web-app_2_2.dtd&quot;/&gt;
+    &lt;/xmlcatalog&gt;
+</pre></blockquote>
+
+<p>Set up an XMLCatalog with a combination of DTDs and entities as
+well as a nested XMLCatalog and external catalog files in both
+formats:</p>
+
+<blockquote><pre>
+    &lt;xmlcatalog id=&quot;allcatalogs&quot;&gt;
+        &lt;dtd 
+            publicId=&quot;-//ArielPartners//DTD XML Article V1.0//EN&quot;
+            location=&quot;com/arielpartners/knowledgebase/dtd/article.dtd&quot;/&gt;
+        &lt;entity 
+            publicId=&quot;LargeLogo&quot;
+            location=&quot;com/arielpartners/images/ariel-logo-large.gif&quot;/&gt;
+        &lt;xmlcatalog refid="commonDTDs"/&gt;
+            &lt;catalogpath&gt;
+                &lt;pathelement location="/etc/sgml/catalog"/&gt;
+                &lt;fileset 
+                    dir=&quot;/anetwork/drive&quot;
+                    includes=&quot;**/catalog&quot;/&gt;
+                &lt;fileset 
+                    dir=&quot;/my/catalogs&quot;
+                    includes=&quot;**/catalog.xml&quot;/&gt;
+            &lt;/catalogpath&gt;
+        &lt;/xmlcatalog&gt;
+    &lt;/xmlcatalog&gt;
+</pre></blockquote>
+<p>To reference the above XMLCatalog in an <code>xslt</code> task:<p>
+<blockquote><pre>
+    &lt;xslt basedir="${source.doc}"
+           destdir="${dest.xdocs}"
+           extension=".xml"
+           style="${source.xsl.converter.docbook}"
+           includes="**/*.xml"
+           force="true"&gt;
+        &lt;xmlcatalog refid=&quot;allcatalogs&quot;/&gt;
+    &lt;/xslt&gt;
+</pre></blockquote>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/CoreTypes/zipfileset.html b/trunk/docs/manual/CoreTypes/zipfileset.html
new file mode 100644
index 0000000..b6ed88f
--- /dev/null
+++ b/trunk/docs/manual/CoreTypes/zipfileset.html
@@ -0,0 +1,136 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ZipFileSet Type</title>
+</head>
+<body>
+<h2><a name="fileset">ZipFileSet</a></h2>
+
+<p>A <code>&lt;zipfileset&gt;</code> is a special form of a <code>&lt;<a
+ href="fileset.html">fileset</a>&gt;</code> which can behave in 2
+different ways : <br>
+</p>
+<ul>
+  <li>When the <span style="font-style: italic;">src</span> attribute
+  is used - or a nested resource collection has been specified
+  (<em>since Ant 1.7</em>), the zipfileset is populated with 
+  zip entries found in the file <span style="font-style:
+  italic;">src</span>.<br>
+  </li>
+  <li>When the <span style="font-style: italic;">dir</span> attribute
+is used, the zipfileset is populated with filesystem files found under <span
+ style="font-style: italic;">dir</span>.<br>
+  </li>
+</ul>
+<p><code>&lt;zipfileset&gt;</code> supports all attributes of <code>&lt;<a
+ href="fileset.html">fileset</a>&gt;</code>
+in addition to those listed below.<br>
+</p>
+<p>Since Ant 1.6, a zipfileset can be defined with the <span
+ style="font-style: italic;">id </span>attribute and referred to with
+the <span style="font-style: italic;">refid</span> attribute.<br>
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tbody>
+    <tr>
+      <td valign="top"><b>Attribute</b></td>
+      <td valign="top"><b>Description</b></td>
+      <td valign="top" align="center"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="top">prefix</td>
+      <td valign="top">all files in the fileset are prefixed with that 
+path in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">fullpath</td>
+      <td valign="top">the file described by the fileset is placed at  
+that exact location in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">src</td>
+      <td valign="top">may be used in place of the <i>dir</i> attribute
+ to specify a zip file whose contents will be extracted and     included
+in the archive.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">filemode</td>
+      <td valign="top">A 3 digit octal string, specify the user, group 
+and other modes in the standard Unix fashion.  Only applies to    
+plain files.  Default is 644. <em>since Ant 1.5.2</em>.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">dirmode</td>
+      <td valign="top">A 3 digit octal string, specify the user, group 
+and other modes in the standard Unix fashion.  Only applies to    
+directories.  Default is 755. <em>since Ant 1.5.2</em>.</td>
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">encoding</td>
+      <td valign="top">The character encoding to use for filenames
+      inside the zip file.  For a list of possible values see <a
+      href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+      Defaults to the platform's default character encoding.
+      <b>Only supported by zipfileset.</b></td>
+      <td align="center" valign="top">No</td>
+    </tr>
+  </tbody>
+</table>
+<p>The <i>fullpath</i> attribute can only be set for filesets that
+represent a single file. The <i>prefix</i> and <i>fullpath</i>
+attributes cannot both be set on the same fileset.</p>
+<p>When using the <i>src</i> attribute, include and exclude patterns
+may be used to specify a subset of the archive for inclusion in the
+archive as with the <i>dir</i> attribute.</p>
+
+<p>Please note that currently only the <a
+href="../CoreTasks/tar.html">tar</a> and <a
+href="../CoreTaks/zip.html">zip</a> tasks use the permission.</p>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>any file system based <a href="resources.html">resource</a> or
+single element resource collection</h4>
+
+<p>The specified resource will be used as src.</p>
+
+<h4>Examples</h4>
+<blockquote>
+  <pre>  &lt;zip destfile="${dist}/manual.zip"&gt;<br>    &lt;zipfileset dir="htdocs/manual" prefix="docs/user-guide"/&gt;<br>    &lt;zipfileset dir="." includes="ChangeLog27.txt" fullpath="docs/ChangeLog.txt"/&gt;<br>    &lt;zipfileset src="examples.zip" includes="**/*.html" prefix="docs/examples"/&gt;<br>  &lt;/zip&gt;<br></pre>
+  <p>zips all files in the <code>htdocs/manual</code> directory into
+the <code>docs/user-guide</code> directory in the archive, adds the
+file <code>ChangeLog27.txt</code> in the current directory as <code>docs/ChangeLog.txt</code>,
+and includes all the html files in <code>examples.zip</code> under <code>docs/examples</code>.
+The archive might end up containing the files:</p>
+  <code> docs/user-guide/html/index.html<br>
+docs/ChangeLog.txt<br>
+docs/examples/index.html<br>
+  </code></blockquote>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/Integration/anttool1.gif b/trunk/docs/manual/Integration/anttool1.gif
new file mode 100644
index 0000000..ad450ba
--- /dev/null
+++ b/trunk/docs/manual/Integration/anttool1.gif
Binary files differ
diff --git a/trunk/docs/manual/Integration/jext-plugin.html b/trunk/docs/manual/Integration/jext-plugin.html
new file mode 100644
index 0000000..a130eb4
--- /dev/null
+++ b/trunk/docs/manual/Integration/jext-plugin.html
@@ -0,0 +1,56 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Apache AntWork Plugin for the Jext Java Text Editor</title>
+</head>
+<body>
+
+<h1>AntWork Plugin for the Jext Java Text Editor</h1>
+ <a name="authors"></a>by<ul>
+  <li>Klaus Hartlage
+      (<a href="mailto:KHartlage@t-online.de">KHartlage@t-online.de</a>)</li>
+</ul>
+<hr>
+
+<p>You can download the plugin at: <a
+href="ftp://jext.sourceforge.net/pub/jext/plugins/AntWork.zip">ftp://jext.sourceforge.net/pub/jext/plugins/AntWork.zip</a></p>
+
+<h2>Installation instructions from the Readme.txt:</h2>
+
+<p>You have to enable the Jext Console to see the Ant output (menu:
+Edit-&gt;Options... - General Panel), because the Ant messages are
+redirected to the Jext console.</p>
+
+<p>You can configure the Ant call in the Jext menu: Edit-&gt;Options... -
+Plugin Options - Antwork Plugin Panel; here you can set the ant home
+directory and the path to your build file.</p>
+
+<p>You can start AntWork in the menu: Plugins-&gt;Ant-&gt;Work Now!  In the
+appearing dialog box you can enter the target which you want to
+compile.</p>
+
+<p>If a javac error occurs in the ant run an error-list opens within
+Jext. With a double-click on the error-message you jump to the error
+in the specified java text file.</p>
+
+
+</body></html>
diff --git a/trunk/docs/manual/Integration/remacc.gif b/trunk/docs/manual/Integration/remacc.gif
new file mode 100644
index 0000000..e02e048
--- /dev/null
+++ b/trunk/docs/manual/Integration/remacc.gif
Binary files differ
diff --git a/trunk/docs/manual/Integration/toolmenu.gif b/trunk/docs/manual/Integration/toolmenu.gif
new file mode 100644
index 0000000..164db44
--- /dev/null
+++ b/trunk/docs/manual/Integration/toolmenu.gif
Binary files differ
diff --git a/trunk/docs/manual/LICENSE b/trunk/docs/manual/LICENSE
new file mode 100644
index 0000000..f820d4b
--- /dev/null
+++ b/trunk/docs/manual/LICENSE
@@ -0,0 +1,203 @@
+/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] [name of copyright owner]
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
diff --git a/trunk/docs/manual/OptionalTasks/BorlandEJBTasks.html b/trunk/docs/manual/OptionalTasks/BorlandEJBTasks.html
new file mode 100644
index 0000000..126fe5c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/BorlandEJBTasks.html
@@ -0,0 +1,143 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Borland EJB Tasks</title>
+</head>
+
+<body>
+
+<h2><a name="log">BorlandDeploy</a>Tool</h2>
+<p>by Benoit Moussaud (<a href="mailto:benoit.moussaud@criltelecom.com">benoit.moussaud@criltelecom.com</a>)</p>
+
+
+<h3>Description</h3>
+<p>The BorlandDeployTool is a vendor specific nested element for the Ejbjar optional task.</p>
+<p>BorlandDeploymentTool is dedicated to the Borland Application Server 4.5.x and Borland
+  Enterprise Server 5.x. It  generates and compiles the stubs and skeletons for all ejb described into the
+  Deployment Descriptor, builds the jar file including the support files and
+  verify whether the produced jar is valid or not.</p>
+
+<p>Benoit Moussaud maintains a separate <a
+href="http://www.moussaud.org/ejbjar.html">FAQ</a> for this task at
+his homepage.</p>
+
+<h3>Borland element</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top" width="63"><b>Attribute</b></td>
+    <td valign="top" width="915"><b>Description</b></td>
+    <td align="center" valign="top" width="62"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">destdir</td>
+    <td valign="top" width="915">The base directory into which the generated borland
+      ready jar files are deposited</td>
+    <td align="center" valign="middle" width="62">yes</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">debug</td>
+    <td valign="top" width="915">If true, turn on the debug mode for each borland
+      tools (java2iiop, iastool ...) default = false</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">verify</td>
+    <td valign="top" width="915">If true, turn on the verification at the end
+      of the jar production (default = false)</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">verifyargs</td>
+    <td valign="top" width="915">extra parameter for verify command</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">suffix</td>
+    <td valign="top" width="915">String value appended to the basename of the
+      deployment descriptor to create the filename of the Borland EJB jar file.</td>
+    <td align="center" valign="middle" width="62">No, defaults to '-ejb.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">basdtd</td>
+    <td valign="top" width="915"><b>Deprecated</b>. Defines the location of the
+      DTD which covers the Borland specific deployment descriptors.
+      This should not be necessary if you have borland in your classpath. If you
+      do not, you should use a nested
+      <a href="ejb.html#ejbjar-dtd"><code>&lt;dtd&gt;</code></a> element, described
+      in the ejbjar task documentation.</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">ejbdtd</td>
+    <td valign="top" width="915"><b>Deprecated</b>. Defines the location of the
+      ejb-jar DTD in the class hierarchy. This should not be necessary
+      if you have borland in your classpath. If you do not, you should use a
+      nested <a href="ejb.html#ejbjar-dtd"><code>&lt;dtd&gt;</code></a> element,
+      described in the ejbjar task
+      documentation. </td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">generateclient </td>
+    <td valign="top" width="915">If true, turn on the generation of the corresponding
+      ejbjar (default = false)</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">version</td>
+    <td valign="top" width="915">set the Borland Application Version.
+            <ul>
+              <li>4 means B.A.S (Borland Application Server) 4.x, target will add ejb-inprise.xml file</li>
+              <li>5 means B.E.S (Borland Application Server) 5.x, target will add ejb-borland.xml file</li>
+            </ul>
+          </td>
+    <td align="center" valign="middle" width="62">No, defaults to 4</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">java2iiopParams </td>
+    <td valign="top" width="915">If filled, the params are added to the java2iiop command (ex: -no_warn_missing_define)</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+
+</table>
+
+<h3>Examples</h3>
+<p>The following build.xml snippet is an example of how to use Borland element
+  into the ejbjar task</p>
+<pre>    &lt;ejbjar srcdir=&quot;${build.classes}&quot; basejarname=&quot;vsmp&quot; descriptordir=&quot;${rsc.dir}/hrmanager&quot;&gt;
+        &lt;borland destdir=&quot;lib&quot; verify=&quot;on&quot; generateclient=&quot;on&quot; version=&quot;5&quot;&gt;
+          &lt;classpath refid=&quot;classpath&quot;/&gt;
+        &lt;/borland&gt;
+        &lt;include name=&quot;**\ejb-jar.xml&quot;/&gt;
+        &lt;support dir=&quot;${build.classes}&quot;&gt;
+          &lt;include name=&quot;demo\*.class&quot;/&gt;
+          &lt;include name=&quot;demo\helper\*.class&quot;/&gt;
+         &lt;/support&gt;
+     &lt;/ejbjar&gt;</pre>
+<pre>The borland element will generate into the lib dir an ejb jar file using the deployment descriptor placed into the ${rsc.dir}/hrmanager directory.
+The verify phase is turned on and the generate client phase as well.
+</pre>
+
+<h3>&nbsp;</h3>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/BorlandGenerateClient.html b/trunk/docs/manual/OptionalTasks/BorlandGenerateClient.html
new file mode 100644
index 0000000..01956b2
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/BorlandGenerateClient.html
@@ -0,0 +1,90 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>BorlandGenerateClient Task</title>
+</head>
+
+<body>
+
+<h2><a name="log">BorlandGenerateClient</a></h2>
+<p>by Benoit Moussaud (<a href="mailto:benoit.moussaud@criltelecom.com">benoit.moussaud@criltelecom.com</a>)</p>
+<h3>Description</h3>
+<p>The BorlandGenerateClient is a task dedicated to Borland Application Server
+  v 4.5. It offers to generate the client jar file corresponding to an ejb jar
+  file.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top" width="63"><b>Attribute</b></td>
+    <td valign="top" width="915"><b>Description</b></td>
+    <td align="center" valign="top" width="62"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">ejbjar</td>
+    <td valign="top" width="915">ejb jar file</td>
+    <td align="center" valign="middle" width="62">yes</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">debug</td>
+    <td valign="top" width="915">If true, turn on the debug mode for each borland
+      tools (java2iiop, iastool ...) default = false</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">clientjar</td>
+    <td valign="top" width="915">client jar file name. If missing the client jar
+      file name is build using the ejbjar file name: ejbjar = hellobean-ejb.jar
+      =&gt; hellobean-ejbclient.jar</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">mode</td>
+    <td valign="top" width="915">choose the command launching mode. Two values:
+      java or fork. default = fork. java is not supported for version=5.Possibility to specify a classpath.</td>
+    <td align="center" valign="middle" width="62">no</td>
+  </tr>
+  <tr>
+    <td valign="top" width="63">version</td>
+    <td valign="top" width="915">set the Borland Application Version.
+            <ul>
+              <li>4 means B.A.S (Borland Application Server 4.x)</li>
+              <li>5 means B.E.S (Borland Application Server 5.x)</li>
+            </ul>
+          </td>
+    <td align="center" valign="middle" width="62">No, defaults to 4</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<p>The following build.xml snippet is an example of how to use Borland element
+   into the ejbjar task using the java mode.</p>
+<pre>
+&lt;blgenclient ejbjar=&quot;lib/secutest-ejb.jar&quot; clientjar=&quot;lib/client.jar&quot; debug=&quot;true&quot; mode=&quot;fork&quot;&gt; version=&quot;5&quot;&gt;
+    &lt;classpath&gt;
+        &lt;pathelement location=&quot;mymodule.jar&quot;/&gt;
+    &lt;/classpath&gt;
+&lt;/blgenclient&gt;
+</pre>
+<pre>&nbsp;</pre>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/antlr.html b/trunk/docs/manual/OptionalTasks/antlr.html
new file mode 100644
index 0000000..e7d4fdb
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/antlr.html
@@ -0,0 +1,200 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ANTLR Task</title>
+</head>
+
+<body>
+
+<h2><a name="antlr">ANTLR</a></h2>
+<h3>Description</h3>
+<p>
+  Invokes the <a HREF="http://www.antlr.org/" target="_top">ANTLR</a> Translator generator
+  on a grammar file.
+</p>
+<p>
+  To use the ANTLR task, set the <i>target</i> attribute to the name of the
+  grammar file to process.  Optionally, you can also set the
+  <i>outputdirectory</i> to write the generated file to a specific directory.
+  Otherwise ANTLR writes the generated files to the directory containing
+  the grammar file.
+</p>
+<p>
+  This task only invokes ANTLR if the grammar file (or the
+  supergrammar specified by the glib attribute) is newer than the
+  generated files.
+</p>
+<p>Antlr 2.7.1 Note:
+<i>
+  To successfully run ANTLR, your best option is probably to build the whole
+  jar with the provided script <b>mkalljar</b> and drop the resulting jar (about 300KB)
+  into ${ant.home}/lib. Dropping the default jar (70KB) is probably not enough
+  for most needs and your only option will be to add ANTLR home directory
+  to your classpath as described in ANTLR <tt>install.html</tt> document.
+</i>
+</p>
+<p>Antlr 2.7.2 Note:
+<i>
+  Instead of the above, you will need antlrall.jar that can be created
+  by the <b>antlr-all.jar</b> target of the Makefile provided with the
+  download.
+</i>
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">The grammar file to process.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">outputdirectory</td>
+    <td valign="top">
+      The directory to write the generated files to.  If not set, the files
+      are written to the directory containing the grammar file.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">glib</td>
+    <td valign="top">
+      An optional super grammar file that the target grammar overrides.  This
+      feature is only needed for advanced vocabularies.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debug</td>
+    <td valign="top">
+      When set to "yes", this flag adds code to the generated parser that will
+      launch the ParseView debugger upon invocation.  The default is "no".
+      <br>
+      Note: ParseView is a separate component that needs to be installed or your
+      grammar will have compilation errors.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">html</td>
+    <td valign="top">
+      Emit an html version of the grammar with hyperlinked actions.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">diagnostic</td>
+    <td valign="top">
+      Generates a text file with debugging information based on the target grammar.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">trace</td>
+    <td valign="top">
+      Forces <b>all</b> rules to call traceIn/traceOut if set to "yes".
+      The default is "no".
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">traceParser</td>
+    <td valign="top">
+      Only forces parser rules to call traceIn/traceOut if set to "yes".
+      The default is "no".
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">traceLexer</td>
+    <td valign="top">
+      Only forces lexer rules to call traceIn/traceOut if set to "yes".
+      The default is "no".
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">traceTreeWalker</td>
+    <td valign="top">
+      Only forces tree walker rules to call traceIn/traceOut if set to
+      "yes".  The default is "no".
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <!--tr>
+    <td valign="top">fork</td>
+    <td valign="top">Run ANTLR in a separate VM.</td>
+    <td align="center" valign="top">No, default is &quot;off&quot;</td>
+  </tr-->
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The directory to invoke the VM in. <!--(ignored if
+      fork is disabled)--></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3><a name="nested">Nested Elements</a></h3>
+
+<p><code>ANTLR</code> supports a nested <code>&lt;classpath&gt;</code>
+element, that represents a <a href="../using.html#path">PATH like
+structure</a>. It is given as a convenience if you have to specify
+the original ANTLR directory. In most cases, dropping the appropriate
+ANTLR jar in the normal Ant lib repository will be enough.</p>
+
+<h4>jvmarg</h4>
+
+<p><!--If fork is enabled, -->Additional parameters may be passed to the new
+VM via nested <code>&lt;jvmarg&gt;</code> attributes, for example:</p>
+
+<pre>
+&lt;antlr target="..."&gt;
+  &lt;jvmarg value=&quot;-Djava.compiler=NONE&quot;/&gt;
+  ...
+&lt;/antlr&gt;
+</pre>
+
+<p>would run ANTLR in a VM without JIT.</p>
+
+<p><code>&lt;jvmarg&gt;</code> allows all attributes described in <a
+href="../using.html#arg">Command line arguments</a>.</p>
+
+<h3>Example</h3>
+<blockquote><pre>
+&lt;antlr
+    target=&quot;etc/java.g&quot;
+    outputdirectory=&quot;build/src&quot;
+/&gt;
+</pre></blockquote>
+<p>
+  This invokes ANTLR on grammar file etc/java.g, writing the generated
+  files to build/src.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/attrib.html b/trunk/docs/manual/OptionalTasks/attrib.html
new file mode 100644
index 0000000..41d22e5
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/attrib.html
@@ -0,0 +1,148 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Ant User Manual</title>
+</head>
+
+<body>
+
+<h2><a name="attrib">Attrib</a></h2>
+<p><em>Since Ant 1.6.</em></p>
+<h3>Description</h3>
+
+<p>Changes the attributes of a file or all files inside specified
+directories.  Right now it has effect only under Windows. Each of the
+4 possible permissions has its own attribute, matching the arguments
+for the attrib command.</p>
+
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s, 
+<a href="../CoreTypes/dirset.html">DirSet</a>s or <a
+href="../CoreTypes/filelist.html">FileList</a>s can be specified using
+nested <code>&lt;fileset&gt;</code>, <code>&lt;dirset&gt;</code> and 
+<code>&lt;filelist&gt;</code> elements.</p>
+
+<p>Starting with Ant 1.7, this task supports arbitrary <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s
+as nested elements.</p>
+
+<p>By default this task will use a single invocation of the underlying
+attrib command.  If you are working on a large number of files this
+may result in a command line that is too long for your operating
+system.  If you encounter such problems, you should set the
+maxparallel attribute of this task to a non-zero value.  The number to
+use highly depends on the length of your file names (the depth of your
+directory tree), so you'll have to experiment a little.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file or directory of which the permissions must be
+    changed.</td>
+    <td valign="top" valign="middle">Yes or nested
+    <code>&lt;fileset/list&gt;</code> elements.</td>
+  </tr>
+  <tr>
+    <td valign="top">readonly</td>
+    <td valign="top">the readonly permission.</td>
+    <td valign="top" rowspan="4">at least one of the four. </td>
+  </tr>
+  <tr>
+    <td valign="top">archive</td>
+    <td valign="top">the archive permission.</td>
+  </tr>
+  <tr>
+    <td valign="top">system</td>
+    <td valign="top">the system permission.</td>
+  </tr>
+  <tr>
+    <td valign="top">hidden</td>
+    <td valign="top">the hidden permission.</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">One of <i>file</i>, <i>dir</i> or <i>both</i>. If set to
+      <i>file</i>, only the permissions of plain files are going to be changed.
+      If set to <i>dir</i>, only the directories are considered.<br>
+      <strong>Note:</strong> The type attribute does not apply to
+      nested <i>dirset</i>s - <i>dirset</i>s always implicitly
+      assume type to be <i>dir</i>.</td>
+    <td align="center" valign="top">No, default is <i>file</i></td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to print a summary after execution or not.
+      Defaults to <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">parallel</td>
+    <td valign="top">process all specified files using a single
+      <code>chmod</code> command. Defaults to true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">maxparallel</td>
+    <td valign="top">Limit the amount of parallelism by passing at
+      most this many sourcefiles at once.  Set it to &lt;= 0 for
+      unlimited.  Defaults to unlimited.  <em>Since Ant 1.6.</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+  <blockquote>
+<pre>&lt;attrib file=&quot;${dist}/run.bat&quot; readonly=&quot;true&quot; hidden=&quot;true&quot;/&gt;</pre>
+</blockquote>
+<p>makes the &quot;run.bat&quot; file read-only and hidden.</p>
+
+<blockquote>
+  <pre>&lt;attrib readonly=&quot;false&quot;&gt;
+  &lt;fileset dir=&quot;${meta.inf}&quot; includes=&quot;**/*.xml&quot;/&gt;
+&lt;/attrib&gt;
+</pre>
+</blockquote>
+<p>makes all &quot;.xml&quot; files below <code>${meta.inf}</code> readable.</p>
+
+<blockquote>
+  <pre>
+&lt;attrib readonly=&quot;true&quot; archive=&quot;true&quot;&gt;
+  &lt;fileset dir=&quot;shared/sources1&quot;&gt;
+    &lt;exclude name=&quot;**/trial/**&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;fileset refid=&quot;other.shared.sources&quot;/&gt;
+&lt;/attrib&gt;
+</pre>
+</blockquote>
+<p>makes all files below <code>shared/sources1</code> (except those below any
+  directory named trial) read-only and archived. In addition all files belonging
+  to a FileSet with <code>id</code> <code>other.shared.sources</code> get the
+  same attributes.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/cab.html b/trunk/docs/manual/OptionalTasks/cab.html
new file mode 100644
index 0000000..cafab48
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/cab.html
@@ -0,0 +1,167 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Cab Task</title>
+</head>
+
+<body>
+
+<h2><a name="cab">Cab</a></h2>
+<h3>Description</h3>
+<p>The cab task creates Microsoft cab archive files.  It is invoked
+similar to the <a href="../CoreTasks/jar.html">jar</a> or <a href="../CoreTasks/zip.html">zip</a> tasks.
+This task will work on Windows using the external cabarc tool (provided by Microsoft)
+which must be located in your executable path.</p>
+<p>To use this task on other platforms you need to download and compile libcabinet from
+<a href="http://trill.cis.fordham.edu/~barbacha/cabinet_library/">
+http://trill.cis.fordham.edu/~barbacha/cabinet_library/</a>.</p>
+<p>See the section on <a href="../dirtasks.html#directorybasedtasks">directory based
+tasks</a>, on how the inclusion/exclusion of files works, and how to
+write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>basedir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">cabfile</td>
+    <td valign="top">the name of the cab file to create.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the directory to start archiving files from.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">set to &quot;yes&quot; if you want to see the output from
+      the cabarc tool.  defaults to &quot;no&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compress</td>
+    <td valign="top">set to &quot;no&quot; to store files without compressing.
+      defaults to &quot;yes&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">options</td>
+    <td valign="top">use to set additional command-line options for
+      the cabarc tool.  should not normally be necessary.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that
+      must be included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that
+      must be excluded. No files (except default excludes) are excluded
+      when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used
+      or not (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>fileset</h4>
+
+<p>The cab task supports one nested <a
+href="../CoreTypes/fileset.html"><code>&lt;fileset&gt;</code></a>
+element to specify the files to be included in the archive.
+  If this is specified, the "basedir" attribute cannot be used.
+</p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;cab cabfile=&quot;${dist}/manual.cab&quot;
+     basedir=&quot;htdocs/manual&quot;
+  /&gt;
+</pre></blockquote>
+<p>cabs all files in the htdocs/manual directory into a file called
+manual.cab in the ${dist} directory.</p>
+<blockquote><pre>
+&lt;cab cabfile=&quot;${dist}/manual.cab&quot;
+     basedir=&quot;htdocs/manual&quot;
+     excludes=&quot;mydocs/**, **/todo.html&quot;
+  /&gt;
+</pre></blockquote>
+<p>cabs all files in the htdocs/manual directory into a file called
+manual.cab in the ${dist} directory. Files in the directory mydocs,
+or files with the name todo.html are excluded.</p>
+<blockquote><pre>
+&lt;cab cabfile=&quot;${dist}/manual.cab&quot;
+     basedir=&quot;htdocs/manual&quot;
+     includes=&quot;api/**/*.html&quot;
+     excludes=&quot;**/todo.html&quot;
+     verbose=&quot;yes&quot;
+  /&gt;
+</pre></blockquote>
+<p>Cab all files in the htdocs/manual directory into a file called
+manual.cab in the ${dist} directory. Only html files under the
+directory api are archived, and files with the name todo.html are
+excluded. Output from the cabarc tool is displayed in the build
+output.</p>
+
+<blockquote><pre>
+&lt;cab cabfile=&quot;${dist}/manual.cab&quot;
+     verbose=&quot;yes&quot;&gt;
+  &lt;fileset
+       dir=&quot;htdocs/manual&quot;
+       includes=&quot;api/**/*.html&quot;
+       excludes=&quot;**/todo.html&quot;
+  /&gt;
+&lt;/cab&gt;
+</pre></blockquote>
+<p>is equivalent to the example above.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/ccm.html b/trunk/docs/manual/OptionalTasks/ccm.html
new file mode 100644
index 0000000..d9c181c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/ccm.html
@@ -0,0 +1,273 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Continuus Tasks</title>
+</head>
+
+<body>
+
+<h1>Continuus Support</h1>
+<ul>
+  <li><a href="#ccmcheckin">CCMCheckin</a></li>
+  <li><a href="#ccmcheckout">CCMCheckout</a></li>
+  <li><a href="#ccmcheckintask">CCMCheckinTask</a></li>
+  <li><a href="#ccmreconfigure">CCMReconfigure</a></li>
+  <li><a href="#ccmcreatetask">CCMCreateTask</a></li>
+</ul>
+
+<p>These ant tasks are wrappers around Continuus Source Manager. They have been tested
+  against versions 5.1/6.2 on Windows 2000, but should work on other platforms with ccm installed.</p>
+<p>author: <a href="mailto:benoit.moussaud@criltelecom.com">Benoit Mousaud (benoit.moussaud@criltelecom.com) </a></p>
+<hr>
+<h2><a name="ccmcheckin">CCMCheckin</a></h2>
+<h3>Description</h3>
+Task to checkin a file
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0" width="598">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>file</td>
+    <td>Path to the file that the command will operate on</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Default is &quot;Checkin&quot; plus the date</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>task</td>
+    <td>Specify the task number used to check in the file (may use 'default')</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>ccmdir</td>
+    <td>path to the ccm executable file, required if it is not on the PATH</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <pre>&lt;ccmcheckin file=&quot;c:/wa/com/foo/MyFile.java&quot;
+        comment=&quot;mycomment&quot;/&gt;
+</pre>
+</blockquote>
+<p>Checks in the file <i>c:/wa/com/foo/MyFile.java</i>.
+  Comment attribute <i>mycomment</i> is added as a task comment. The task
+  used is the one set as the default.</p>
+<hr>
+<h2><a name="ccmcheckout">CCMCheckout</a></h2>
+<h3>Description</h3>
+Task to perform a Checkout command to Continuus
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0" width="614">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>file</td>
+    <td>Path to the file that the command will operate on</td>
+    <td rowspan=2">Yes (file|fileset)</td>
+  </tr>
+  <tr>
+    <td>fileset</td>
+    <td>fileset containing the file to be checked out</td>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>task</td>
+    <td>Specify the task number used to checkin the file (may use
+      'default')</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>ccmdir</td>
+    <td>path to the ccm executable file, required if it is not on the PATH</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <pre>&lt;ccmcheckout file=&quot;c:/wa/com/foo/MyFile.java&quot;
+        comment=&quot;mycomment&quot;/&gt;
+</pre>
+</blockquote>
+<p>Check out the file <i>c:/wa/com/foo/MyFile.java</i>.
+  Comment attribute <i>mycomment</i> is added as a task comment
+   The used task is the one set as the default.</p>
+<blockquote>
+  <pre>&lt;ccmcheckout  comment=&quot;mycomment&quot;&gt;
+  &lt;fileset dir=&quot;lib&quot; &gt;
+    &lt;include name=&quot;**/*.jar&quot;/&gt;
+  &lt;/fileset&gt;
+&lt;/ccmcheckout &gt;
+  </pre>
+</blockquote>
+
+<p>Check out all the files in the <i>lib</i> directory having the <i>.jar</i> extension.
+  Comment attribute <i>mycomment</i> is added as a task comment
+   The used task is the one set as the default.</p>
+
+
+
+<hr>
+<h2><a name="ccmcheckintask">CCMCheckinTask</a></h2>
+<h3>Description</h3>
+Task to perform a check in default task command to Continuus
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>task</td>
+    <td>Specify the task number used to check in the file (may use 'default')</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>ccmdir</td>
+    <td >path to the ccm executable file, required if it is not on the PATH</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples </h3>
+<blockquote>
+  <pre>&lt;ccmcheckintask comment=&quot;blahblah/&gt;
+</pre>
+</blockquote>
+<p>Does a Checkin default task on all the checked out files in the current task.</p>
+<hr>
+<h2><a name="ccmreconfigure">CCMReconfigure</a></h2>
+<h3>Description</h3>
+Task to perform an reconfigure command to Continuus.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>recurse</td>
+    <td>recurse on subproject (default false)</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>verbose</td>
+    <td>do a verbose reconfigure operation (default false)</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>ccmproject</td>
+    <td>Specifies the ccm project on which the operation is applied.</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td>ccmdir</td>
+    <td >path to the ccm executable file, required if it is not on the PATH</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+ <pre>&lt;ccmreconfigure ccmproject=&quot;ANTCCM_TEST#BMO_1&quot;
+         verbose=&quot;true&quot;/&gt;
+</pre>
+</blockquote>
+<p>Does a Continuus <i>reconfigure</i> on the project <i>ANTCCM_TEST#BMO_1</i>.
+</p>
+<hr>
+<h2><a name="ccmcreatetask">CCMCreateTask</a></h2>
+<h3>Description</h3>
+Create a Continuus task.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>platform</td>
+    <td>Specify the target platform</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>ccmdir</td>
+    <td >path to the ccm executable file, required if it is not on the PATH</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>resolver</td>
+    <td>Specify the resolver</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>release</td>
+    <td>Specify the CCM release</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>subsystem</td>
+    <td>Specify the subsystem</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>task</td>
+    <td>Specify the task number used to checkin the file (may use 'default')</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <pre>&lt;ccmcreatetask resolver=&quot;${user.name}&quot;
+            release=&quot;ANTCCM_TEST&quot; comment=&quot;blahblah&quot;/&gt;
+</pre>
+</blockquote>
+<p>Creates a task for the release <i>ANTCCM_TEST</i> with the
+  current user as the resolver for this task.</p>
+
+
+</body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/chgrp.html b/trunk/docs/manual/OptionalTasks/chgrp.html
new file mode 100644
index 0000000..35052ed
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/chgrp.html
@@ -0,0 +1,166 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Chgrp Task</title>
+</head>
+
+<body>
+
+<h2><a name="Chgrp">Chgrp</a></h2>
+<p><em>Since Ant 1.6.</em></p>
+<h3>Description</h3>
+
+<p>Changes the group of a file or all files inside specified
+directories. Right now it has effect only under Unix.  The group
+attribute is equivalent to the corresponding argument for the chgrp
+command.</p>
+
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s, 
+<a href="../CoreTypes/dirset.html">DirSet</a>s or <a
+href="../CoreTypes/filelist.html">FileList</a>s can be specified using
+nested <code>&lt;fileset&gt;</code>, <code>&lt;dirset&gt;</code> and 
+<code>&lt;filelist&gt;</code> elements.</p>
+
+<p>Starting with Ant 1.7, this task supports arbitrary <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s
+as nested elements.</p>
+
+<p>By default this task will use a single invocation of the underlying
+chgrp command.  If you are working on a large number of files this may
+result in a command line that is too long for your operating system.
+If you encounter such problems, you should set the maxparallel
+attribute of this task to a non-zero value.  The number to use highly
+depends on the length of your file names (the depth of your directory
+tree) and your operating system, so you'll have to experiment a
+little.  POSIX recommends command line length limits of at least 4096
+characters, this may give you an approximation for the number you
+could use as initial value for these experiments.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file or directory of which the group must be
+    changed.</td>
+    <td valign="top" valign="middle">Yes, unless nested
+      <code>&lt;fileset|filelist|dirset&gt;</code>
+      elements are specified</td>
+  </tr>
+  <tr>
+    <td valign="top">group</td>
+    <td valign="top">the new group.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">parallel</td>
+    <td valign="top">process all specified files using a single
+      <code>chgrp</code> command. Defaults to true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">One of <i>file</i>, <i>dir</i> or
+      <i>both</i>. If set to <i>file</i>, only the group of
+      plain files are going to be changed. If set to <i>dir</i>, only
+      the directories are considered.<br>
+      <strong>Note:</strong> The type attribute does not apply to
+      nested <i>dirset</i>s - <i>dirset</i>s always implicitly
+      assume type to be <i>dir</i>.</td>
+    <td align="center" valign="top">No, default is <i>file</i></td>
+  </tr>
+  <tr>
+    <td valign="top">maxparallel</td>
+    <td valign="top">Limit the amount of parallelism by passing at
+      most this many sourcefiles at once.  Set it to &lt;= 0 for
+      unlimited.  Defaults to unlimited.</td>
+    <td align="center" valign="top">No</td>
+
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to print a summary after execution or not.
+      Defaults to <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+
+</table>
+<h3>Examples</h3>
+  <blockquote><pre>
+&lt;chgrp file=&quot;${dist}/start.sh&quot; group=&quot;coders&quot;/&gt;
+</pre>
+</blockquote>
+<p>makes the &quot;start.sh&quot; file belong to the coders group on a
+UNIX system.</p>
+<blockquote>
+<pre>
+&lt;chgrp group=&quot;coders&quot;&gt;
+  &lt;fileset dir=&quot;${dist}/bin&quot; includes=&quot;**/*.sh&quot;/&gt;
+&lt;/chgrp&gt;
+</pre>
+</blockquote>
+<p>makes all &quot;.sh&quot; files below <code>${dist}/bin</code>
+belong to the coders group on a UNIX system.</p>
+<blockquote>
+<pre>
+&lt;chgrp group=&quot;coders&quot;&gt;
+  &lt;fileset dir=&quot;shared/sources1&quot;&gt;
+    &lt;exclude name=&quot;**/trial/**&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;fileset refid=&quot;other.shared.sources&quot;/&gt;
+&lt;/chgrp&gt;
+</pre>
+</blockquote>
+<p>makes all files below <code>shared/sources1</code> (except those
+below any directory named trial) belong to the coders group on a UNIX 
+system. In addition all files belonging to a FileSet
+with <code>id</code> <code>other.shared.sources</code> get the same
+group.</p>
+
+<blockquote>
+<pre>
+&lt;chgrp group=&quot;webdev&quot; type=&quot;file&quot;&gt;
+  &lt;fileset dir=&quot;/web&quot;&gt;
+    &lt;include name=&quot;**/*.test.jsp&quot;/&gt;
+    &lt;include name=&quot;**/*.new&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;dirset dir=&quot;/web&quot;&gt;
+    &lt;include name=&quot;**/test_*&quot;/&gt;
+  &lt;/dirset&gt;
+&lt;/chmod&gt;
+</pre>
+</blockquote>
+
+<p>makes all <code>.test.jsp</code>, and <code>.new</code> files belong to 
+group webdev. Directories beginning with <code>test_</code> also will belong 
+to webdev, but if there is a directory that ends in <code>.new</code> or a file
+that begins with <code>test_</code> it will be unaffected.</p>
+
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/chown.html b/trunk/docs/manual/OptionalTasks/chown.html
new file mode 100644
index 0000000..21c5563
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/chown.html
@@ -0,0 +1,164 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Chown Task</title>
+</head>
+
+<body>
+
+<h2><a name="Chown">Chown</a></h2>
+<p><em>Since Ant 1.6.</em></p>
+<h3>Description</h3>
+
+<p>Changes the owner of a file or all files inside specified
+directories. Right now it has effect only under Unix.  The owner
+attribute is equivalent to the corresponding argument for the chown
+command.</p>
+
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s, 
+<a href="../CoreTypes/dirset.html">DirSet</a>s or <a
+href="../CoreTypes/filelist.html">FileList</a>s can be specified using
+nested <code>&lt;fileset&gt;</code>, <code>&lt;dirset&gt;</code> and 
+<code>&lt;filelist&gt;</code> elements.</p>
+
+<p>Starting with Ant 1.7, this task supports arbitrary <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s
+as nested elements.</p>
+
+<p>By default this task will use a single invocation of the underlying
+chown command.  If you are working on a large number of files this may
+result in a command line that is too long for your operating system.
+If you encounter such problems, you should set the maxparallel
+attribute of this task to a non-zero value.  The number to use highly
+depends on the length of your file names (the depth of your directory
+tree) and your operating system, so you'll have to experiment a
+little.  POSIX recommends command line length limits of at least 4096
+characters, this may give you an approximation for the number you
+could use as initial value for these experiments.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file or directory of which the owner must be
+    changed.</td>
+    <td valign="top" valign="middle">Yes or nested
+    <code>&lt;fileset/list&gt;</code> elements.</td>
+  </tr>
+  <tr>
+    <td valign="top">owner</td>
+    <td valign="top">the new owner.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">parallel</td>
+    <td valign="top">process all specified files using a single
+      <code>chown</code> command. Defaults to true.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">One of <i>file</i>, <i>dir</i> or
+      <i>both</i>. If set to <i>file</i>, only the owner of
+      plain files are going to be changed. If set to <i>dir</i>, only
+      the directories are considered.<br>
+      <strong>Note:</strong> The type attribute does not apply to
+      nested <i>dirset</i>s - <i>dirset</i>s always implicitly
+      assume type to be <i>dir</i>.</td>
+    <td align="center" valign="top">No, default is <i>file</i></td>
+  </tr>
+  <tr>
+    <td valign="top">maxparallel</td>
+    <td valign="top">Limit the amount of parallelism by passing at
+      most this many sourcefiles at once.  Set it to &lt;= 0 for
+      unlimited.  Defaults to unlimited.</td>
+    <td align="center" valign="top">No</td>
+
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether to print a summary after execution or not.
+      Defaults to <code>false</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+
+</table>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;chown file="${dist}/start.sh" owner="coderjoe"/&gt;
+</pre>
+</blockquote>
+<p>makes the "start.sh" file belong to coderjoe on a
+UNIX system.</p>
+<blockquote>
+<pre>
+    &lt;chown owner="coderjoe"&gt;
+      &lt;fileset dir="${dist}/bin" includes="**/*.sh"/&gt;
+    &lt;/chown&gt;
+</pre>
+</blockquote>
+<p>makes all ".sh" files below <code>${dist}/bin</code>
+belong to coderjoe on a UNIX system.</p>
+<blockquote>
+<pre>
+&lt;chown owner="coderjoe"&gt;
+  &lt;fileset dir="shared/sources1"&gt;
+    &lt;exclude name="**/trial/**"/&gt;
+  &lt;/fileset&gt;
+  &lt;fileset refid="other.shared.sources"/&gt;
+&lt;/chown&gt;
+</pre>
+</blockquote>
+<p>makes all files below <code>shared/sources1</code> (except those
+below any directory named trial) belong to coderjoe on a UNIX 
+system. In addition all files belonging to a FileSet
+with <code>id</code> <code>other.shared.sources</code> get the same
+owner.</p>
+
+<blockquote>
+<pre>
+&lt;chown owner="webadmin" type="file"&gt;
+  &lt;fileset dir="/web"&gt;
+    &lt;include name="**/*.cgi"/&gt;
+    &lt;include name="**/*.old"/&gt;
+  &lt;/fileset&gt;
+  &lt;dirset dir="/web"&gt;
+    &lt;include name="**/private_*"/&gt;
+  &lt;/dirset&gt;
+&lt;/chmod&gt;
+</pre>
+</blockquote>
+
+<p>makes cgi scripts, files with a <code>.old</code> extension or
+directories beginning with <code>private_</code> belong to the user named
+webadmin. A directory ending in <code>.old</code> or a file beginning with 
+<code>private_</code> would remain unaffected.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/clearcase.html b/trunk/docs/manual/OptionalTasks/clearcase.html
new file mode 100644
index 0000000..73ab4a0
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/clearcase.html
@@ -0,0 +1,958 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+  <title>Clearcase Tasks</title>
+</head>
+
+<body>
+<h1>Ant ClearCase Tasks</h1>
+<p>by:<br>
+Curtis White (cwhite at aracnet dot com),<br>
+Sean P. Kane (spkane at genomatica dot com),<br>
+Rob Anderson (Anderson.Rob at vectorscm dot com), and<br>
+Sean Egan    (sean at cm-logic dot com)</p>
+
+<p>Version 1.6 - 02/25/2003</p>
+
+<h1>ClearCase Support</h1>
+<h2>Table of Contents</h2>
+<ul>
+  <li><A href="#introduction">Introduction</a>
+  <li><A href="#cccheckin">CCCheckin</a>
+  <li><A href="#cccheckout">CCCheckout</a>
+  <li><A href="#ccuncheckout">CCUnCheckout</a>
+  <li><A href="#ccupdate">CCUpdate</a>
+  <li><A href="#ccmklbtype">CCMklbtype</a>
+  <li><A href="#ccmklabel">CCMklabel</a>
+  <li><A href="#ccrmtype">CCRmtype</a>
+  <li><A href="#cclock">CCLock</a>
+  <li><A href="#ccunlock">CCUnlock</a>
+  <li><A href="#ccmkbl">CCMkbl</a>
+  <li><A href="#ccmkattr">CCMkattr</a>
+  <li><A href="#ccmkdir">CCMkdir</a>
+  <li><A href="#ccmkelem">CCMkelem</a></li>
+
+</ul>
+
+<hr>
+<h2><a name="introduction">Introduction</a></h2>
+<p>Ant provides several optional tasks for working with ClearCase. These tasks correspond to various
+ClearCase commands using the Cleartool program. The current tasks available for Ant correspond to only
+a few of the significant ClearCase commands.</p>
+
+<p>More tasks can be easily added by deriving from the ClearCase class and then adding
+functionality that is specific to that ClearCase command.</p>
+<p>
+    Important: these tasks all require <code>cleartool</code> on the command line.
+    If a task fails with an IOException, especially error code 2 on Windows,
+    this is your problem.
+</p>
+
+
+<hr>
+<h2><a name="cccheckin">CCCheckin</a></h2>
+<h3>Description</h3>
+Task to perform a "cleartool checkin" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>viewpath</td>
+    <td>Path to the ClearCase view file or directory that the command
+        will operate on</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Only one of comment or commentfile may be used.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>commentfile</td>
+    <td>Specify a file containing a comment. Only one of comment or commentfile
+        may be used.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>nowarn</td>
+    <td>Suppress warning messages</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>preservetime</td>
+    <td>Preserve the modification time</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>keepcopy</td>
+    <td>Keeps a copy of the file with a .keep extension</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>identical</td>
+    <td>Allows the file to be checked in even if it is identical
+        to the original</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;cccheckin viewpath="c:/views/viewdir/afile"
+        commentfile="acomment.txt"
+        nowarn="true"
+        identical="true"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>checkin</i> on the file <i>c:/views/viewdir/afile</i>.
+Comment text from the file <i>acomment.txt</i> is added to ClearCase as a comment.
+All warning messages are suppressed. The file is checked in even if it is
+<i>identical</i> to the original.</p>
+<hr>
+<h2><a name="cccheckout">CCCheckout</a></h2>
+<h3>Description</h3>
+Task to perform a "cleartool checkout" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>viewpath</td>
+    <td>Path to the ClearCase view file or directory that the command
+        will operate on</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>reserved</td>
+    <td>Specifies whether to check out the file as reserved or not</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td>out</td>
+    <td>Creates a writable file under a different filename</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>nodata</td>
+    <td>Checks out the file but does not create an editable file
+        containing its data</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>branch</td>
+    <td>Specify a branch to check out the file to</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>version</td>
+    <td>Allows checkout of a version other than main latest</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>nowarn</td>
+    <td>Suppress warning messages</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Only one of comment or commentfile may be used.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>commentfile</td>
+    <td>Specify a file containing a comment. Only one of comment or
+        commentfile may be used.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>notco</td>
+    <td>Fail if it's already checked out to the current view. Set to false to ignore it.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;cccheckout viewpath="c:/views/viewdir/afile"
+        reserved="true"
+        branch="abranch"
+        nowarn="true"
+        comment="Some comment text"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>checkout</i> on the file <i>c:/views/viewdir/afile</i>.
+It is checked out as <i>reserved</i> on branch called <i>abranch</i>. All
+warning messages are suppressed. A <i>Some comment text</i> is added to
+ClearCase as a comment.</p>
+<hr>
+<h2><a name="ccuncheckout">CCUnCheckout</a></h2>
+<h3>Description</h3>
+Task to perform a UnCheckout command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>viewpath</td>
+    <td>Path to the ClearCase view file or directory that the command
+        will operate on</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>keepcopy</td>
+    <td>Specifies whether to keep a copy of the file with a .keep
+        extension or not</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccuncheckout viewpath="c:/views/viewdir/afile"
+        keepcopy="true"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>uncheckout</i> on the file <i>c:/views/viewdir/afile</i>.
+A copy of the file called <i>c:/views/viewdir/afile.keep</i> is kept.</p>
+<hr>
+<h2><a name="ccupdate">CCUpdate</a></h2>
+<h3>Description</h3>
+Task to perform an "cleartool update" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>viewpath</td>
+    <td>Path to the ClearCase snapshot view file or directory that the command
+        will operate on</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>graphical</td>
+    <td>Displays a graphical dialog during the update</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>log</td>
+    <td>Specifies a log file for ClearCase to write to</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>overwrite</td>
+    <td>Specifies whether to overwrite hijacked files or not</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>rename</td>
+    <td>Specifies that hijacked files should be renamed with a .keep extension</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>currenttime</td>
+    <td>Specifies that modification time should be written as the
+        current time. Either currenttime or preservetime can be
+        specified.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>preservetime</td>
+    <td>Specifies that modification time should preserved from the
+        VOB time. Either currenttime or preservetime can be
+        specified.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccupdate viewpath="c:/views/viewdir"
+        graphical="false"
+        log="log.log"
+        overwrite="true"
+        currenttime="true"
+        rename="false"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>update</i> on the snapshot view directory <i>c:/views/viewdir</i>.
+A graphical dialog will be displayed. The output will be logged to
+<i>log.log</i> and it will overwrite any hijacked files. The modified
+time will be set to the current time.</p>
+
+
+
+<hr>
+<h2><a name="ccmklbtype">CCMklbtype</a></h2>
+<h3>Description</h3>
+Task to perform a "mklbtype" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>typename</td>
+    <td>Name of the label type to create</td>
+    <td>Yes</td>
+  <tr>
+  <tr>
+    <td>vob</td>
+    <td>Name of the VOB</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>replace</td>
+    <td>Replace an existing label definition of the same type</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>global</td>
+    <td>Either global or ordinary can be specified, not both. Creates a label type that is global to the VOB or to VOBs that use this VOB</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>ordinary</td>
+    <td>Either global or ordinary can be specified, not both. Creates a label type that can be used only in the current VOB. <B>Default</B></td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>pbranch</td>
+    <td>Allows the label type to be used once per branch in a given element's version tree</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>shared</td>
+    <td>Sets the way mastership is checked by ClearCase. See ClearCase documentation for details</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>commentfile</td>
+    <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr></tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmklbtype typename="VERSION_1"
+        ordinary="true"
+        comment="Development version 1"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mklbtype</i> to create a label type named <i>VERSION_1</i>.
+It is created as <i>ordinary</i> so it is available only to the current VOB.
+The text <i>Development version 1</i> is added as a comment.</p>
+
+
+<hr>
+<h2><a name="ccmklabel">CCMklabel</a></h2>
+<h3>Description</h3>
+Task to perform a "mklabel" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>typename</td>
+    <td>Name of the label type</td>
+    <td>Yes</td>
+  <tr>
+  <tr>
+    <td>viewpath</td>
+    <td>Path to the ClearCase view file or directory that the command will operate on</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>replace</td>
+    <td>Replace a label of the same type on the same branch</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>recurse</td>
+    <td>Process each subdirectory under viewpath</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>version</td>
+    <td>Identify a specific version to attach the label to</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>vob</td>
+    <td>Name of the VOB</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>commentfile</td>
+    <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr></tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmklabel viewpath="c:/views/viewdir/afile"
+        comment="Some comment text"
+        recurse="true"
+        version="\main\2"
+        typename="VERSION_1"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mklabel</i> on the file <i>c:/views/viewdir/afile</i> under
+the main branch for version 2 (<i>\main\2</i>). Text <i>Some comment text</i> is added
+as a comment. It will <i>recurse</i> all subdirectories.
+
+
+<hr>
+<h2><a name="ccrmtype">CCRmtype</a></h2>
+<h3>Description</h3>
+Task to perform a "rmtype" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>typekind</td>
+    <td>The kind of type to create. Valid types are:
+      <table border="0" width="40%">
+        <tr>
+          <td width="15%"> </td>
+          <td><b>attype</b><br>
+              <b>brtype</b><br>
+              <b>eltype</b><br>
+              <b>hltype</b><br>
+              <b>lbtype</b><br>
+              <b>trtype</b>
+          </td>
+          <td>- <br>
+              - <br>
+              - <br>
+              - <br>
+              - <br>
+              -
+          </td>
+          <td>attribute type<br>
+              branch type<br>
+              element type<br>
+              hyperlink type<br>
+              label type<br>
+              trigger type
+          </td>
+        </tr>
+      </table>
+    </td>
+    <td>Yes</td>
+  <tr>
+  <tr>
+    <td>typename</td>
+    <td>The name of the type to remove</td>
+    <td>Yes</td>
+  <tr>
+  <tr>
+    <td>ignore</td>
+    <td>Used with trigger types only. Forces removal of trigger type even if a pre-operation trigger would prevent its removal</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>rmall</td>
+    <td>Removes all instances of a type and the type object itself</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>comment</td>
+    <td>Specify a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr>
+  <tr>
+    <td>commentfile</td>
+    <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+    <td>No</td>
+  <tr></tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccrmtype typekind="lbtype"
+        typename="VERSION_1"
+        commentfile="acomment.txt"
+        rmall="true"/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>rmtype</i> to remove a label type (<i>lbtype</i>) named <i>VERSION_1</i>.
+Comment text from the file <i>acomment.txt</i> is added as a comment. All instances of the type
+are removed, including the type object itself.</p>
+<hr>
+
+<h2><a name="cclock">CCLock</a></h2>
+<h3>Description</h3>
+Task to perform a "cleartool lock" command to ClearCase.
+<h3>Parameters</h3>
+ <table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>replace</td>
+      <td>Specifies replacing an existing lock</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>nusers</td>
+      <td>Specifies user(s) who can still modify the object</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>obsolete</td>
+      <td>Specifies that the object should be marked obsolete</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>comment</td>
+      <td>Specifies how to populate comments fields</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>pname</td>
+      <td>Specifies the object pathname to be locked.</td>
+      <td>No</td>
+   <tr>
+      <td>objselect</td>
+      <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>objsel</td>
+      <td>Specifies the object(s) to be locked.<br>
+      Since ant 1.6.1</td>
+      <td>No</td>
+   <tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+
+ </table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;cclock
+    objsel="stream:Application_Integration@\MyProject_PVOB"
+    /&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>lock</i> on the object <i>stream:Application_Integration@\MyProject_PVOB</i>.</p>
+<hr>
+
+<h2><a name="ccunlock">CCUnlock</a></h2>
+<h3>Description</h3>
+Task to perform a "cleartool unlock" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>comment</td>
+      <td>Specifies how to populate comments fields</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>pname</td>
+      <td>Specifies the object pathname to be unlocked.</td>
+      <td>No</td>
+   <tr>
+      <td>objselect</td>
+      <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>objsel</td>
+      <td>Specifies the object(s) to be unlocked.<br>
+      Since ant 1.6.1</td>
+      <td>No</td>
+   <tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+
+ </table>
+ <h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccunlock
+    objsel="stream:Application_Integration@\MyProject_PVOB"
+    /&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>unlock</i> on the object <i>stream:Application_Integration@\MyProject_PVOB</i>.</p>
+<hr>
+
+<h2><a name="ccmkbl">CCMkbl</a></h2>
+<h3>Description</h3>
+Task to perform a "cleartool mkbl" command to ClearCase.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>comment</td>
+      <td>Specify a comment. Only one of comment or cfile may be
+used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>commentfile</td>
+      <td>Specify a file containing a comment. Only one of comment or
+cfile may be used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>baselinerootname</td>
+      <td>Specify the name to be associated with the baseline.</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>nowarn</td>
+      <td>Suppress warning messages</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>identical</td>
+      <td>Allows the baseline to be created even if it is identical to the
+previous baseline.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>full</td>
+      <td>Creates a full baseline.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>nlabel</td>
+      <td>Allows the baseline to be created without a label.</td>
+      <td>No</td>
+   </tr>
+  <tr>
+    <td>failonerr</td>
+    <td>Throw an exception if the command fails. Default is true.<br>
+    Since ant 1.6.1</td>
+    <td>No</td>
+  </tr>
+ </table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmkbl
+    baselinerootname="Application_Baseline_AUTO"
+    identical="yes"
+    full="no"
+    viewpath="v:\ApplicationCC"
+    /&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mkbl</i> on the Integration view at <i>v:\ApplicationCC</i>
+even if it is <i>identical</i> to a previous baseline. The new baseline with be
+incremental and named "Application_Baseline_AUTO".</p>
+<hr>
+
+<h2><a name="ccmkattr">CCMkattr</a></h2>
+<h3>Description</h3>
+Task to perform a &quot;cleartool mkattr&quot; command to ClearCase.<br>
+Since ant 1.6.1
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>viewpath</td>
+      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>replace</td>
+      <td>Replace the value of the attribute if it already exists</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>recurse</td>
+      <td>Process each subdirectory under viewpath</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>version</td>
+      <td>Identify a specific version to attach the attribute to</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>typename</td>
+      <td>Name of the attribute type</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>typevalue</td>
+      <td>Value to attach to the attribute type</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>comment</td>
+      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>commentfile</td>
+      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>failonerr</td>
+      <td>Throw an exception if the command fails. Default is true</td>
+      <td>No</td>
+   </tr>
+ </table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmkattr viewpath=&quot;c:/views/viewdir/afile&quot;
+    typename=&quot;BugFix&quot;
+    typevalue=&quot;34445&quot;
+    /&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mkattr</i> on the file <i>c:/views/viewdir/afile</i> and
+attaches the attribute <i>BugFix</i> with a value of <i>34445</i> to it.</p>
+<hr>
+
+<h2><a name="ccmkdir">CCMkdir</a></h2>
+<h3>Description</h3>
+Task to perform a &quot;cleartool mkdir&quot; command to ClearCase.<br>
+Since ant 1.6.1
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>viewpath</td>
+      <td>Path to the ClearCase view directory that the command will operate on</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>comment</td>
+      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>commentfile</td>
+      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>nocheckout</td>
+      <td>Do not checkout after element creation</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>failonerr</td>
+      <td>Throw an exception if the command fails. Default is true</td>
+      <td>No</td>
+   </tr>
+ </table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmkdir viewpath=&quot;c:/views/viewdir/adir&quot;
+        nochcekout=&quot;true&quot;
+        comment=&quot;Some comment text&quot;/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mkdir</i> on the dir <i>c:/views/viewdir/adir</i> and
+does not automatically check it out.</p>
+<hr>
+
+<h2><a name="ccmkelem">CCMkelem</a></h2>
+<h3>Description</h3>
+Task to perform a &quot;cleartool mkelem&quot; command to ClearCase.<br>
+Since ant 1.6.1
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+   <tr>
+      <td>viewpath</td>
+      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+      <td>Yes</td>
+   <tr>
+   <tr>
+      <td>comment</td>
+      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>commentfile</td>
+      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>nowarn</td>
+      <td>Suppress warning messages</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>nocheckout</td>
+      <td>Do not checkout after element creation</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>checkin</td>
+      <td>Checkin element after creation</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>preservetime</td>
+      <td>Preserve the modification time (for checkin)</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>master</td>
+      <td>Assign mastership of the main branch to the current site</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>eltype</td>
+      <td>Element type to use during element creation</td>
+      <td>No</td>
+   <tr>
+   <tr>
+      <td>failonerr</td>
+      <td>Throw an exception if the command fails. Default is true</td>
+      <td>No</td>
+   <tr>
+ </table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;ccmkelem viewpath=&quot;c:/views/viewdir/afile&quot;
+        eltype=&quot;text_file&quot;
+        checkin=&quot;true&quot;
+        comment=&quot;Some comment text&quot;/&gt;
+</pre>
+</blockquote>
+<p>Does a ClearCase <i>mkelem</i> on the file <i>c:/views/viewdir/afile</i> with
+element type <i>text_file</i>. It also checks in the file after creation.</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/csc.html b/trunk/docs/manual/OptionalTasks/csc.html
new file mode 100644
index 0000000..855ed91
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/csc.html
@@ -0,0 +1,494 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Csc
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Csc
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Compiles C# source into executables or modules.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Compiles C# source into executables or modules. csc.exe on Windows or mcs on any other platform must be on the execute path, unless another executable or the full path to that executable is specified in the <tt>executable</tt> parameter <p> All parameters are optional: <code>&lt;csc/&gt;</code> should suffice to produce a debug build of all *.cs files. However, naming an <tt>destFile</tt>stops the csc compiler from choosing an output name from random, and allows the dependency checker to determine if the file is out of date. <p> The task is a directory based task, so attributes like <b>includes="*.cs" </b> and <b>excludes="broken.cs"</b> can be used to control the files pulled in. By default, all *.cs files from the project folder down are included in the command. When this happens the output file -if not specified- is taken as the first file in the list, which may be somewhat hard to control. Specifying the output file with <tt>destFile</tt> seems prudent. <p> <p> For more complex source trees, nested <tt>src</tt> elements can be supplied. When such an element is present, the implicit fileset is ignored. This makes sense, when you think about it :)  <p>For historical reasons the pattern <code>**/*.cs</code> is preset as includes list and you can not override it with an explicit includes attribute.  Use nested <code>&lt;src&gt;</code> elements instead of the basedir attribute if you need more control.</p> <p> References to external files can be made through the references attribute, or (since Ant1.6), via nested <code>&lt;reference&gt;</code> filesets. With the latter, the timestamps of the references are also used in the dependency checking algorithm. <p> Example <pre>&lt;csc optimize=&quot;true&quot; debug=&quot;false&quot; docFile=&quot;documentation.xml&quot; warnLevel=&quot;4&quot; unsafe=&quot;false&quot; targetType=&quot;exe&quot; incremental=&quot;false&quot; mainClass = &quot;MainApp&quot; destFile=&quot;NetApp.exe&quot; &gt; &lt;src dir="src" includes="*.cs"/&gt; &lt;reference file="${testCSC.dll}"/&gt; &lt;define name="RELEASE"/&gt; &lt;define name="DEBUG" if="debug.property"/&gt; &lt;define name="def3" unless="def3.property"/&gt; &lt;/csc&gt; </pre>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">additionalmodules</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of modules to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="26">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">debug</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the debug flag on or off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">definitions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of defined constants.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the destination directory of files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the name of exe/library to create.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">docfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">file for generated XML documentation</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">executable</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the name of the program, overriding the defaults. Can be used to set the full path to a program, or to switch to an alternate implementation of the command, such as the Mono or Rotor versions -provided they use the same command line arguments as the .NET framework edition</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Any extra options which are not explicitly supported by this task.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, fail on compilation errors.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">filealign</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the file alignment. Valid values are 0,512, 1024, 2048, 4096, 8192, and 16384, 0 means 'leave to the compiler'</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">fullpaths</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, print the full path of files on errors.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">includedefaultreferences</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, automatically includes the common assemblies in dotnet, and tells the compiler to link in mscore.dll. set the automatic reference inclusion flag on or off this flag controls the /nostdlib option in CSC</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">incremental</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the incremental compilation flag on or off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">mainclass</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the name of main class for executables.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">noconfig</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">A flag that tells the compiler not to read in the compiler settings files 'csc.rsp' in its bin directory and then the local directory</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optimize</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, enables optimization flag.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">outputfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">The output file. This is identical to the destFile attribute.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">referencefiles</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path of references to include. Wildcards should work.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">references</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of DLLs to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the source directory of the files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">targettype</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the target type to one of exe|library|module|winexe</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">"exe", "library", "module", "winexe"</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">unsafe</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, enables the unsafe keyword.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">utf8output</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, require all compiler output to be in UTF8 format.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">warnlevel</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Level of warning currently between 1 and 4 with 4 being the strictest.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32icon</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the filename of icon to include.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32res</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the filename of a win32 resource (.RES) file to include. This is not a .NET resource, but what Windows is used to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>define</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetDefine)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a define to the list of definitions
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>reference</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new reference fileset to the compilation
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>resource</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetResource)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        link or embed a resource
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>src</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new source directory to the compile
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/depend.html b/trunk/docs/manual/OptionalTasks/depend.html
new file mode 100644
index 0000000..786864d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/depend.html
@@ -0,0 +1,216 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Depend Task</title>
+</head>
+
+<body>
+
+<h2>Depend</h2>
+
+A task to manage Java class file dependencies.
+
+<h3>Description</h3>
+
+<p>
+The depend task works by determining which classes are out of date with
+respect to their source and then removing the class files of any other
+classes which depend on the out-of-date classes.
+</p>
+
+<p> To determine the class dependencies, the depend task analyses the class 
+files of all class files passed to it. Depend does not parse your source code in 
+any way but relies upon the class references encoded into the class files by the 
+compiler. This is generally faster than parsing the Java source.</p>
+
+<p>
+To learn more about how this information is obtained from the class files, 
+please refer to <a href="http://java.sun.com/docs/books/vmspec/">the Java 
+Virtual Machine Specification</a>
+</p>
+
+<p> Since a class' dependencies only change when the class itself changes, the 
+depend task is able to cache dependency information. Only those class files 
+which have changed will have their dependency information re-analysed. Note that 
+if you change a class' dependencies by changing the source, it will be 
+recompiled anyway. You can examine the dependency files created to understand 
+the  dependencies of your classes. Please do not rely, however, on the format of 
+the information, as it may change in a later release. </p>
+
+<p> Once depend discovers all of the class dependencies, it &quot;inverts&quot; 
+this relation to determine, for each class, which other classes are dependent 
+upon it. This &quot;affects&quot; list is used to discover which classes are 
+invalidated by the out of date class. The class files of the invalidated 
+classes are removed, triggering the compilation of the affected classes. </p>
+
+<p> The depend task supports an attribute, &quot;closure&quot; which controls 
+whether depend will only consider direct class-class relationships or whether it 
+will also consider transitive, indirect relationships. For example, say there 
+are three classes, A, which depends on B, which in-turn depend on C. Now say 
+that class C is out of date. Without closure, only class B would be removed by 
+depend. With closure set, class A would also be removed. Normally direct 
+relationships are sufficient - it is unusual for a class to depend on another 
+without having a direct relationship. With closure set, you will notice that 
+depend typically removes far more class files. </p>
+
+<p>The classpath attribute for <code>&lt;depend&gt;</code> is optional. If it is present, 
+depend will check class dependencies against classes and jars on this classpath.
+Any classes which depend on an element from this classpath and which are older 
+than that element will be deleted. A typical example where you would use this 
+facility would be where you are building a utility jar and want to make sure 
+classes which are out of date with respect to this jar are rebuilt. You should
+<b>not</b> include jars in this classpath which you do not expect to change, 
+such as the JDK runtime jar or third party jars, since doing so will just slow 
+down the dependency check. This means that if you do use a classpath for the 
+depend task it may be different from the classpath necessary to actually 
+compile your code.</p>
+
+<h3>Performance</h3> 
+
+<p> The performance of the depend task is dependent on a 
+number of factors such as class relationship complexity and how many class files 
+are out of date. The decision about whether it is cheaper to just recompile all 
+classes or to use the depend task will depend on the size of your project and 
+how interrelated your classes are. </p>
+
+
+<h3>Limitations</h3>
+
+<p> There are some source dependencies which depend will not detect. </p>
+
+<ul>
+<li>If the Java compiler optimizes away a class relationship, 
+    there can be a source dependency without a class dependency. </li>
+    
+<li>Non public classes cause two problems. Firstly depend cannot relate
+    the class file to a source file. In the future this may be addressed
+    using the source file attribute in the classfile. Secondly, neither 
+    depend nor the compiler tasks can detect when a non public class is
+    missing. Inner classes are handled by the depend task.</li>
+</ul>
+
+The most obvious example of these limitations is that the task can't tell
+which classes to recompile when a constant primitive data type exported 
+by other classes is changed. For example, a change in the definition of
+something like
+<pre>
+public final class Constants {
+  public final static boolean DEBUG=false;
+}
+</pre> will not be picked up by other classes.
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">srcDir</td>
+    <td valign="top">This is the directory where the source exists. depend
+will examine this to determine which classes are out of date. If you use multiple
+source directories you can pass this attribute a path of source directories.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">destDir</td>
+    <td valign="top">This is the root directory of the class files which
+will be analysed. If this is not present, the srcdir is used.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cache</td>
+    <td valign="top">This is a directory in which depend can store and
+retrieve dependency information. If this is not present, depend will not
+use a cache </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">closure</td>
+    <td valign="top">This attribute controls whether depend only removes
+classes which directly depend on out of date classes. If this is set to true,
+depend will traverse the class dependency graph deleting all affected
+classes. Defaults to false</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dump</td>
+    <td valign="top">If true the dependency information will be written to the debug level log
+                     </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath containing jars and classes for which <code>&lt;depend&gt;</code> should also
+                     check dependencies</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">warnOnRmiStubs</td>
+    <td valign="top">Flag to disable warnings about files that look like rmic generated stub/skeleton
+    classes, and which have no .java source. Useful when doing rmi development. </td>
+    <td valign="top" align="center">No, default=true</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<p>The <code>depend</code> task's <code>classpath</code> attribute is a 
+<a href="../using.html#path">PATH-like structure</a> and can also be set
+via a nested <code>&lt;classpath&gt;</code> element.</p>
+
+<p>Additionally,
+this task forms an implicit
+<a href="../CoreTypes/fileset.html">FileSet</a>
+and supports all attributes of
+<code>&lt;fileset&gt;</code> (<code>dir</code> becomes <code>srcdir</code>),
+as well as the nested <code>&lt;include&gt;</code>,
+<code>&lt;exclude&gt;</code>, and <code>&lt;patternset&gt;</code> elements.
+
+<h3>Examples</h3>
+<pre>&lt;depend srcdir=&quot;${java.dir}&quot;
+        destdir=&quot;${build.classes}&quot;
+        cache=&quot;depcache&quot;
+        closure=&quot;yes&quot;/&gt;</pre>
+
+<p>removes any classes in the <code>${build.classes}</code> directory
+that depend on out-of-date classes. Classes are considered out-of-date with 
+respect to the source in the <code>${java.dir}</code> directory, using the same
+mechanism as the <code>&lt;javac&gt;</code> task. In this example, the
+<code>&lt;depend&gt;</code> task caches its dependency 
+information in the <code>depcache</code> directory. </p>
+
+<pre>
+&lt;depend srcdir=&quot;${java.dir}&quot; destdir=&quot;${build.classes}&quot;
+        cache=&quot;depcache&quot; closure=&quot;yes&quot;&gt;
+  &lt;include name=&quot;**/*.java&quot;/&gt;
+  &lt;excludesfile name=&quot;${java.dir}/build_excludes&quot;/&gt;
+&lt;/depend&gt;
+</pre>
+<p>does the same as the previous example, but explicitly includes all
+<code>.java</code> files, except those that match the list given
+in <code>${java.dir}/build_excludes</code>.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/dotnet.html b/trunk/docs/manual/OptionalTasks/dotnet.html
new file mode 100644
index 0000000..7ad6ff6
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/dotnet.html
@@ -0,0 +1,326 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>.NET Tasks</title>
+</head>
+
+<h1>.NET tasks</h1>
+<h2>Introduction</h2>
+
+
+<p><strong>These tasks are deprecated and will be removed in a future
+release of Ant.  They are now part of the <a
+href="http://ant.apache.org/antlibs/dotnet/index.html">.NET
+Antlib</a>.</strong></p>
+
+Ant support for .NET goes back to before .NET was released, and
+continues to be expanded based on user demand. Users writing nothing but
+a .NET application, may want to look at the .NET-based
+<A href="http://nant.sourceforge.net/">NAnt</A> project, that supports
+both the Microsoft and the Ximian managed <A
+href="http://go-mono.com/">Mono</A> project's implementation of the
+.NET framework.
+<p>
+
+Over time, the .NET tasks in Ant have tended to evolve to meet a few
+limited needs. Firstly, developers working with complex deployment problems may
+want to use ant to use the fairly advanced deployment tasks Ant ships
+with. Secondly, anyone who has a cross-platform project can use these
+tasks to cover the .NET side of the problem. Here, cross-platform can
+mean more than just Java and .NET: the C++ tasks in the ant-contrib
+project on sourceforge can be used with Ant to do native C++ and .NET
+cross development if that is your need. Finally, Ant support for .NET
+lets one automate .NET development under an automated build process,
+such as AntHill or Cruise Control.
+
+<p>
+
+What this means is that the Ant tasks for .NET support do not get as
+much rigorous use as the Java tools, and are evolving more slowly -that
+includes the time for support calls to change. But as a consequence,
+developers working on .NET support have more freedom to play around with
+the code. It also means that the fairly unusual set of tasks supported
+by ant enable a few interesting operations that can not be performed any
+other way:
+<ol>
+
+<li>Integrating with a Java based SOAP Service -generating C# code from
+the server's WSDL and running it against the server.
+</li>
+<li>Building and deploying a C#-based Web Service, then using the Apache
+Axis tasks to create JUnit tests to call the endpoints.
+
+<li>Patching .NET type libraries to work with more complex IDL than the
+basic <code>&lt;importtypelib&gt;</code> wrapper around tlbimport supports. Hence the
+disassembler and the reassembler.
+</li>
+
+</ol>
+Needless to say, possible does not mean easy.
+<A href="http://www.manning.com/hatcher/chap15.pdf">Chapter 15</A> of
+Java Development with Ant covers the first of these, using the Ant1.5
+version of the tasks. Going the other way -generating Java client
+code and JUnit testcases is covered in
+<A href="http://www.iseran.com/Steve/papers/interop/">The Wondrous curse
+of Interop</A>. The final trick, IDL and Typelib abuse, is not
+documented as we do not want to encourage such an ugly practise. It,
+can, however, be done if absolutely necessary. 
+
+<h3>Task List</h3>
+
+<table border="0" >
+<tr>
+  <td><b>Task</b></td>
+  <td><b>Description</b></td>
+</tr>
+<tr>
+  <td><a href="csc.html">csc</a></td>
+  <td>Compiles C# code</td>
+</tr>
+
+<tr>
+  <td><a href="vbc.html">vbc</a></td>
+  <td>Compiles VB.NET code</td>
+</tr>
+
+<tr>
+  <td><a href="jsharpc.html">jsharpc</a></td>
+  <td>Compiles J# files</td>
+</tr>
+
+<tr>
+  <td><a href="ildasm.html">ildasm</a></td>
+  <td>Disassembles .NET executables and libraries</td>
+</tr>
+
+<tr>
+  <td><a href="ilasm.html">ilasm</a></td>
+  <td>Assembles .il files</td>
+</tr>
+
+<tr>
+  <td><a href="wsdltodotnet.html">wsdltodotnet</a></td>
+  <td>Generates .NET code (C# or VB) from a WSDL file</td>
+</tr>
+
+<tr>
+  <td><a href="importtypelib.html">importtypelib</a></td>
+  <td>Imports a COM type library into .NET</td>
+</tr>
+
+</table>
+
+<hr>
+<h3>Common .NET Datatypes </h3>
+
+There are some datatypes that are common to the core compiler classes:
+csc, vbc and  jsharpc
+
+<h4>Resource</h4>
+
+This is a resource that is included in the build. Ant uses this for
+dependency checking -if resources included this way have changed, the
+executable or library will be rebuilt.
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">File</td> 
+    <td valign="top">the resource to include</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td> 
+    <td valign="top">the name of the resource. 
+    Optional unless the resource is
+    marked as public or private</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">embed</td> 
+    <td valign="top">flag to control whether the resource
+    is embedded in the assembly, or just linked to it</td>
+    <td align="center" valign="top">No -default is true</td>
+  </tr>
+  <tr>
+    <td valign="top">public</td> 
+    <td valign="top">VB only: flag to control if a resource should be 
+    public or private. Set to true for public, false for private
+    and leave undefined for for neither. </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h5>Examples</h5>
+
+<pre>
+&lt;resource file="app.ico" name="icon"/&gt;
+&lt;resource file="splash.jpg"/&gt;
+&lt;resource name="splash" file="splash.jpg" public="false"/&gt;
+</pre>
+
+<h4>Define</h4>
+
+This is a definition; in .NET these can either be defined or undefined,
+unlike C++ #defines, which can be either undefined or arbitrary text.
+The Ant compilation tasks can unconditionally add definitions, or
+conditionally set a compile-time definition if an ant property is
+defined or not.
+<p>
+
+Dependency Logic: the tasks are not (yet) clever enough to remember what
+the last definitions were and trigger a rebuild when they change. Clean
+build the code when the defines are likely to be different.
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td> 
+    <td valign="top">the name of the definition</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td> 
+    <td valign="top">name of a ant property to test for;
+    the definition is only set if this property is defined.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td> 
+    <td valign="top">name of a ant property to test for;
+    the definition is only set if this property is undefined.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h5>Examples</h5>
+
+<pre>
+&lt;define name="unsafe"/&gt;
+&lt;define name="debug" if="build.debug"/&gt;
+&lt;define name="dotnet" unless="build.mono"/&gt;
+</pre>
+
+<hr>
+<h3> Change Log </h3>
+
+<h4>Ant1.6</h4>
+This revision goes along with NET 1.1, though there is no reason why
+it should not work on other versions.
+<p>
+
+<ol>
+<li>vbc task</li>
+<li>jsharpc task</li>
+<li>mono support</li>
+<li>ilasm</li>
+<li>tlbimport</li>
+<li>Reference filesets in the compiler tasks</li>
+<li>definitions in the compiler tasks</li>
+<li>multiple source filesets in the compiler tasks. If these are used, the
+implicit fileset is disabled</li>
+</ol>
+
+The compile tasks: vbc, jsharpc, and csc, all contain lots of common code
+in a shared base class: if you can use one you should be able to use
+another.
+
+<h4>Ant 1.5</h4>
+This revision goes along with NET 1.0 (SP1)
+<ol>
+<li>CSC: added filealign</li>
+<li>CSC: added reference to office.dll</li>
+<li>CSC: dependency checking! only if destFile is set!
+<li>WsdlToDotnet written
+</ol>
+
+<h4>Version 0.5</h4>
+This revision goes along with NET 1.0 (SP1)
+<ol>
+<li>CSC: added filealign</li>
+<li>CSC: added reference to office.dll</li>
+<li>CSC: dependency checking! only if destFile is set!
+<li>WsdlToDotnet written
+</ol>
+
+<h4>Version 0.4</h4>
+This is the beta-2 revision of the tasks.
+<ol>
+<li>ILASM: pulled the owner attribute, added keyfile for giving binaries a strong name
+(MD5 hash of the checksum)</li>
+<li>CSC: added win32res , noConfig, utf8output, fullpaths</li>
+<li>CSC: </li>
+</ol>
+
+<h4>Version 0.3</h4>
+
+The changes here reflect Beta-1 of the dotnet SDK and experience of use in
+more complex projects. This build does not work with the older SDK,
+primarily because the automatic reference feature references libraries
+only found in the new SDK version.
+<p>
+External changes</p>
+<ul>
+<li>Recursive inclusion of .cs and .il files</li>
+
+<li>Documentation enhanced, includes examples and details of all parameters</li>
+
+<li>The csc task automatically includes the common dotnet assemblies, so
+there is no need to remember to refer to 'System.dll', 'System.Web.Services',
+ etc. This feature can be disabled by setting the 'includeDefaultReferences'
+ flag to false. </li>
+
+ <li> References can also be referred to using the ReferenceFiles parameter, which
+is an ant path specification. The old 'references' string is still retained.</li>
+<li> An 'extraoptions' attribute enables the build file to include any CSC options
+which are not explicitly supported in the CSC task. </li>
+</ul>
+
+Internal changes
+<ul>
+<li>Some minor refactoring (move common code a method)</li>
+<li>Application of Jedits JavaStyle task resulted in a major reshaping of
+the codebase and the insertion of a blank line every second line. Significant
+effort was required to revert some (but not all) changes.</li>
+<li>Removed throws clause from methods which can't throw exception
+</ul>
+
+The test harness has been expanded to include unicode source file
+(the build works but the rest of the system has 'issues' with high unicode
+package and method names)
+
+<h4>Version 0.2</h4>
+First public edition, added to the ant cvs tree. Tested on the PDC build of
+the dotnet SDK only, and still immature. The command execution code was
+refactored out into a 'NetCommand' class for re-use. The Ilasm task was added
+at this time.
+
+<h4>Version 0.1</h4>
+Initial proof of concept; very rudimentary support for CSC only.
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/echoproperties.html b/trunk/docs/manual/OptionalTasks/echoproperties.html
new file mode 100644
index 0000000..00d2981
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/echoproperties.html
@@ -0,0 +1,146 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Echoproperties Task</title>
+</head>
+
+<body>
+
+<h2><a name="echoproperties">echoproperties</a></h2>
+<h3>Description</h3>
+
+<p>Displays all the current properties (or a subset of them specified
+by a nested <code>&lt;propertyset&gt;</code>) in the project.  The
+output can be sent to a file if desired.  This task can be used as a
+somewhat contrived means of returning data from an
+<tt>&lt;ant&gt;</tt> invocation, but is really for debugging build
+files.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">If specified, the value indicates the name of the
+    file to send the output of the statement to.  The generated output file
+    is compatible for loading by any Java application as a property file.
+    If not specified, then the output will go to the Ant log.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">prefix</td>
+    <td valign="top">
+        a prefix which is used to filter the properties
+        only those properties starting with this prefix will be echoed.
+        <P>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">regex</td>
+    <td valign="top">
+        a regular expression which is used to filter the
+        properties
+        only those properties whose names match it will be echoed.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>   
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">By default, the "failonerror" attribute is enabled.
+    If an error occurs while writing the properties to a file, and this
+    attribute is enabled, then a BuildException will be thrown, causing the
+    build to fail.  If disabled, then IO errors will be reported as a log
+    statement, and the build will continue without failure from this task.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">format</td>
+    <td valign="top">One of <code>text</code> or <code>xml</code>.
+    Determines the output format.  Defaults to <code>text</code>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>propertyset</h4>
+
+<p>You can specify subsets of properties to be echoed with <a
+href="../CoreTypes/propertyset.html">propertyset</a>s. Using
+<tt>propertyset</tt>s gives more control on which properties will be
+picked up. The attributes <tt>prefix</tt> and <tt>regex</tt> are just
+shorcuts that use <tt>propertyset</tt>s internally.
+</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h3>Examples</h3>
+<blockquote><pre>
+  &lt;echoproperties/&gt;
+</pre></blockquote>
+<p>Report the current properties to the log.</p>
+<blockquote><pre>
+  &lt;echoproperties destfile="my.properties"/&gt;
+</pre></blockquote>
+<p>Report the current properties to the file "my.properties", and will
+fail the build if the file could not be created or written to.</p>
+<blockquote><pre>
+  &lt;echoproperties destfile="my.properties" failonerror="false"/&gt;
+</pre></blockquote>
+<p>Report the current properties to the file "my.properties", and will
+log a message if the file could not be created or written to, but will still
+allow the build to continue.</p>
+<blockquote><pre>
+  &lt;echoproperties prefix="java."/&gt;
+</pre></blockquote>
+<p>List all properties beginning with "java."</p>
+<blockquote><pre>
+  &lt;echoproperties&gt;
+    &lt;propertyset&gt;
+      &lt;propertyref prefix="java."/&gt;
+    &lt;/propertyset&gt;
+  &lt;/echoproperties&gt;
+</pre></blockquote>
+<p>This again lists all properties beginning with "java." using a nested
+<tt>&lt;/propertyset&gt;</tt> which is an equivalent but longer way.</p>
+<blockquote><pre>
+  &lt;echoproperties regex=".*ant.*"/&gt;
+</pre></blockquote>
+<p>Lists all properties that contain "ant" in their names.
+The equivalent snippet with <tt>&lt;/propertyset&gt;</tt> is:</p>
+<blockquote><pre>
+  &lt;echoproperties&gt;
+    &lt;propertyset&gt;
+      &lt;propertyref regex=".*ant.*"/&gt;
+    &lt;/propertyset&gt;
+  &lt;/echoproperties&gt;
+</pre></blockquote>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/ejb.html b/trunk/docs/manual/OptionalTasks/ejb.html
new file mode 100644
index 0000000..ff36cc8
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/ejb.html
@@ -0,0 +1,1776 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>EJB Tasks</title>
+
+</head>
+
+<body>
+
+<h1>Ant EJB Tasks User Manual</h1>
+<p>by</p>
+<!-- Names are in alphabetical order, on last name -->
+<ul>
+  <li>Paul Austin (<a href="mailto:p_d_austin@yahoo.com">p_d_austin@yahoo.com</a>)</li>
+  <li>Holger Engels (<a href="mailto:hengels@innovidata.com">hengels@innovidata.com</a>)</li>
+  <li>Tim Fennell (<a href="mailto:tfenne@rcn.com">tfenne@rcn.com</a>)</li>
+  <li>Martin Gee (<a href="mailto:martin.gee@icsynergy.com">martin.gee@icsynergy.com</a>)</li>
+  <li>Conor MacNeill</li>
+  <li>Cyrille Morvan (<a href="mailto:cmorvan@ingenosya.com">cmorvan@ingenosya.com</a>)</li>
+  <li>Greg Nelson (<a href="mailto:gn@sun.com">gn@sun.com</a>)</li>
+  <li>Rob van Oostrum(<a href="mailto:rob@springwellfarms.ca">rob@springwellfarms.ca</a>)</li>
+</ul>
+
+<hr>
+<h2>Table of Contents</h2>
+<ul>
+  <li><a href="#introduction">Introduction</a></li>
+  <li><a href="#ejbtasks">EJB Tasks</a></li>
+</ul>
+
+<hr>
+<h2><a name="introduction">Introduction</a></h2>
+<p>Ant provides a number of optional tasks for developing 1.x and 2.x
+<a href="http://java.sun.com/products/ejb" target="_top">Enterprise Java Beans (EJBs)</a>.
+In general these tasks are specific to the particular vendor's EJB Server.</p>
+
+<p> The tasks support:<br>
+
+<ul>
+  <li><a href="http://www.borland.com">Borland </a>
+  Application Server 4.5</li>
+  <li><a href="http://www.iplanet.com">iPlanet </a>
+  Application Server 6.0</li>
+  <li><a href="http://www.jboss.org/" target="_top">
+  JBoss 2.1</a> and above EJB servers</li>
+  <li><a href="http://www.bea.com" target="_top">Weblogic</a>
+   4.5.1 through to 7.0 EJB servers</li>
+  <li><a href="http://www.objectweb.org/jonas/" target="_top">JOnAS</a>
+   2.4.x and 2.5 Open Source EJB server</li>
+  <li><a href="http://www.ibm.com/websphere">IBM WebSphere</a> 4.0</li>
+</ul>
+    Vendors such as BEA and IBM now provide custom Ant tasks to work with their
+    particular products. More importantly, EJB3.0 renders this whole process obsolete.
+    Accordingly, developement of these tasks is effectively frozen. Bug reports
+    and especially patches are welcome, but there is no pressing need to add
+    support for new application servers. Nobody should be writing new EJB2.x applications
+    and definitely not new EJB2.x servers.
+</p>
+
+<hr>
+<h2><a name="ejbtasks">EJB Tasks</a></h2>
+<table border="1" cellpadding="5">
+ <tr><td>Task</td><td colspan="2">Application Servers</td></tr>
+ <tr><td><a href="BorlandGenerateClient.html">blgenclient</a></td><td colspan="2">Borland Application Server 4.5 and 5.x</td></tr>
+ <tr><td><a href="#ddcreator">ddcreator</a></td><td colspan="2">Weblogic 4.5.1</td></tr>
+ <tr><td><a href="#ejbc">ejbc</a></td><td colspan="2">Weblogic 4.5.1</td></tr>
+ <tr><td><a href="#iplanet-ejbc">iplanet-ejbc</a></td><td colspan="2">iPlanet Application Server 6.0</td></tr>
+ <tr><td rowspan="7"><a href="#ejbjar">ejbjar</a></td><td colspan="2" align="center"><b>Nested Elements</b></td></tr>
+ <tr><td><a href="BorlandEJBTasks.html">borland</a></td><td>Borland Application Server 4.5 and 5.x</td></tr>
+ <tr><td><a href="#ejbjar_iplanet">iPlanet</a></td><td>iPlanet Application Server 6.0</td></tr>
+ <tr><td><a href="#ejbjar_jboss">jboss</a></td><td>JBoss</td></tr>
+ <tr><td><a href="#ejbjar_jonas">jonas</a></td><td>JOnAS 2.4.x and 2.5</td></tr>
+ <tr><td><a href="#ejbjar_weblogic">weblogic</a></td><td>Weblogic 5.1 to 7.0</td></tr>
+ <tr><td><a href="#ejbjar_websphere">websphere</a></td><td>IBM WebSphere 4.0</td></tr>
+ <tr><td><a href="#wlrun">wlrun</a></td><td colspan="2">Weblogic 4.5.1 to 7.0</td></tr>
+ <tr><td><a href="#wlstop">wlstop</a></td><td colspan="2">Weblogic 4.5.1 to 7.0</td></tr>
+
+</table>
+
+<hr>
+<h2><a name="ddcreator">ddcreator</a></h2>
+<h3><b>Description:</b></h3>
+<p>ddcreator will compile a set of Weblogic text-based deployment descriptors into a serialized
+EJB deployment descriptor. The selection of which of the text-based descriptors are to be compiled
+is based on the standard Ant include and exclude selection mechanisms.
+</p>
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">descriptors</td>
+    <td valign="top">This is the base directory from which descriptors are selected.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">The directory where the serialized deployment descriptors will be written</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">This is the classpath to use to run the underlying weblogic ddcreator tool.
+                     This must include the <code>weblogic.ejb.utils.DDCreator</code> class</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;ddcreator descriptors=&quot;${dd.dir}&quot;
+           dest=&quot;${gen.classes}&quot;
+           classpath=&quot;${descriptorbuild.classpath}&quot;&gt;
+  &lt;include name=&quot;*.txt&quot;/&gt;
+&lt;/ddcreator&gt;
+</pre>
+
+<hr>
+<h2><a name="ejbc">ejbc</a></h2>
+<h3><b>Description:</b></h3>
+<p>The ejbc task will run Weblogic's ejbc tool. This tool will take a serialized deployment descriptor,
+examine the various EJB interfaces and bean classes and then generate the required support classes
+necessary to deploy the bean in a Weblogic EJB container. This will include the RMI stubs and skeletons
+as well as the classes which implement the bean's home and remote interfaces.</p>
+<p>
+The ant task which runs this tool is able to compile several beans in a single operation. The beans to be
+compiled are selected by including their serialized deployment descriptors. The standard ant
+<code>include</code> and <code>exclude</code> constructs can be used to select the deployment descriptors
+to be included. </p>
+<p>
+Each descriptor is examined to determine whether the generated classes are out of date and need to be
+regenerated. The deployment descriptor is de-serialized to discover the home, remote and
+implementation classes. The corresponding source files are determined and checked to see their
+modification times. These times and the modification time of the serialized descriptor itself are
+compared with the modification time of the generated classes. If the generated classes are not present
+or are out of date, the ejbc tool is run to generate new versions.</p>
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">descriptors</td>
+    <td valign="top">This is the base directory from which the serialized deployment descriptors are selected.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">dest</td>
+    <td valign="top">The base directory where the generated classes, RIM stubs and RMI skeletons are written</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">manifest</td>
+    <td valign="top">The name of a manifest file to be written. This manifest will contain an entry for each EJB processed</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">The base directory of the source tree containing the source files of the home interface,
+                     remote interface and bean implementation classes.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">This classpath must include both the <code>weblogic.ejbc</code> class and the
+                     class files of the bean, home interface, remote interface, etc of the bean being
+                     processed.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepgenerated</td>
+    <td>Controls whether ejbc will keep the
+        intermediate Java files used to build the class files. This can be
+        useful when debugging.</td>
+    <td>No, defaults to false.</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;ejbc descriptors=&quot;${gen.classes}&quot;
+           src=&quot;${src.dir}&quot;
+           dest=&quot;${gen.classes}&quot;
+           manifest=&quot;${build.manifest}&quot;
+           classpath=&quot;${descriptorbuild.classpath}&quot;&gt;
+  &lt;include name=&quot;*.ser&quot;/&gt;
+&lt;/ejbc&gt;
+</pre>
+
+<hr>
+<h2>
+<a NAME="iplanet-ejbc"></a>iplanet-ejbc</h2>
+
+<h3>
+<b>Description:</b></h3>
+Task to compile EJB stubs and skeletons for the iPlanet Application Server
+6.0.  Given a standard EJB 1.1 XML descriptor as well as an iAS-specific
+EJB descriptor, this task will generate the stubs and skeletons required
+to deploy the EJB to iAS.  Since the XML descriptors can include multiple
+EJBs, this is a convenient way of specifying many EJBs in a single Ant
+task.
+<p>For each EJB specified, the task will locate the three classes that
+comprise the EJB in the destination directory.  If these class files
+cannot be located in the destination directory, the task will fail. The
+task will also attempt to locate the EJB stubs and skeletons in this directory.
+If found, the timestamps on the stubs and skeletons will be checked to
+ensure they are up to date. Only if these files cannot be found or if they
+are out of date will the iAS ejbc utility be called to generate new stubs
+and skeletons.</p>
+<h3>
+Parameters:</h3>
+
+<table border="1" cellspacing="0" cellpadding="2">
+<tr>
+<td valign="top"><b>Attribute</b></td>
+
+<td valign="top"><b>Description</b></td>
+
+<td align="center" valign="top"><b>Required</b></td>
+</tr>
+
+<tr>
+<td valign="top">ejbdescriptor</td>
+
+<td valign="top">Standard EJB 1.1 XML descriptor (typically titled "ejb-jar.xml").</td>
+
+<td align="center" valign="top">Yes</td>
+</tr>
+
+<tr>
+<td valign="top">iasdescriptor</td>
+
+<td valign="top">iAS-specific EJB XML descriptor (typically titled "ias-ejb-jar.xml").</td>
+
+<td align="center" valign="top">Yes</td>
+</tr>
+
+<tr>
+<td valign="top">dest</td>
+
+<td valign="top">The is the base directory where the RMI stubs and skeletons
+are written. In addition, the class files for each bean (home interface,
+remote interface, and EJB implementation) must be found in this directory.</td>
+
+<td align="center" valign="top">Yes</td>
+</tr>
+
+<tr>
+<td valign="top">classpath</td>
+
+<td valign="top">The classpath used when generating EJB stubs and skeletons.
+If omitted, the classpath specified when Ant was started will be used.
+Nested "classpath" elements may also be used.</td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">keepgenerated</td>
+
+<td valign="top">Indicates whether or not the Java source files which are
+generated by ejbc will be saved or automatically deleted. If "yes", the
+source files will be retained. If omitted, it defaults to "no". </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">debug</td>
+
+<td>Indicates whether or not the ejbc utility should log additional debugging
+statements to the standard output. If "yes", the additional debugging statements
+will be generated.  If omitted, it defaults to "no". </td>
+
+<td align="center" valign="top">
+<center>No</center>
+</td>
+</tr>
+
+<tr>
+<td valign="top">iashome</td>
+
+<td>May be used to specify the "home" directory for this iAS installation.
+This is used to find the ejbc utility if it isn't included in the user's
+system path. If specified, it should refer to the "[install-location]/iplanet/ias6/ias"
+directory. If omitted, the ejbc utility must be on the user's system path. </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+</table>
+
+<h3>
+Examples</h3>
+
+<pre>
+&lt;iplanet-ejbc ejbdescriptor="ejb-jar.xml"
+              iasdescriptor="ias-ejb-jar.xml"
+              dest="${build.classesdir}"
+              classpath="${ias.ejbc.cpath}"/&gt;
+
+
+&lt;iplanet-ejbc ejbdescriptor="ejb-jar.xml"
+              iasdescriptor="ias-ejb-jar.xml"
+              dest="${build.classesdir}"
+              keepgenerated="yes"
+              debug="yes"
+              iashome="${ias.home}"&gt;
+              &lt;classpath&gt;
+                  &lt;pathelement path="."/&gt;
+                  &lt;pathelement path="${build.classpath}"/&gt;
+              &lt;/classpath&gt;
+&lt;/iplanet-ejbc&gt;
+
+
+</pre>
+
+<hr>
+<h2><a name="wlrun">wlrun</a></h2>
+<h3><b>Description:</b></h3>
+
+<p>The <code>wlrun</code> task is used to start a weblogic server. The task runs
+a weblogic instance in a separate Java Virtual Machine. A number of parameters
+are used to control the operation of the weblogic instance. Note that the task,
+and hence ant, will not complete until the weblogic instance is stopped.</p>
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required for 4.5.1 and 5.1</b></td>
+    <td align="center" valign="top"><b>Required for 6.0</b></td>
+  </tr>
+  <tr>
+    <td valign="top">BEA Home</td>
+    <td valign="top">The location of the BEA Home where the server's config is defined.
+                     If this attribute is present, wlrun assumes that the server will
+                     be running under Weblogic 6.0</td>
+    <td valign="top" align="center">N/A</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">home</td>
+    <td valign="top">The location of the weblogic home that is to be used. This is the location
+                     where weblogic is installed.</td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center">Yes. Note this is the absolute location, not relative to
+                                    BEA home.</td>
+  </tr>
+  <tr>
+    <td valign="top">Domain</td>
+    <td valign="top">The domain to which the server belongs.</td>
+    <td valign="top" align="center">N/A</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to be used with the Java Virtual Machine that runs the Weblogic
+                     Server. Prior to Weblogic 6.0, this is typically set to the Weblogic
+                     boot classpath. Under Weblogic 6.0 this should include all the
+                     weblogic jars</td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">wlclasspath</td>
+    <td valign="top">The weblogic classpath used by the Weblogic Server.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">N/A</td>
+  </tr>
+  <tr>
+    <td valign="top">properties</td>
+    <td valign="top">The name of the server's properties file within the weblogic home directory
+                     used to control the weblogic instance.</td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center">N/A</td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the weblogic server within the weblogic home which is to be run.
+                     This defaults to &quot;myserver&quot;</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">policy</td>
+    <td valign="top">The name of the security policy file within the weblogic home directory that
+                     is to be used. If not specified, the default policy file <code>weblogic.policy</code>
+                     is used.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">The management username used to manage the server</td>
+    <td valign="top" align="center">N/A</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">The server's management password</td>
+    <td valign="top" align="center">N/A</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">pkPassword</td>
+    <td valign="top">The private key password so the server can decrypt the SSL
+                     private key file</td>
+    <td valign="top" align="center">N/A</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">jvmargs</td>
+    <td valign="top">Additional argument string passed to the Java Virtual Machine used to run the
+                     Weblogic instance.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">weblogicMainClass</td>
+    <td valign="top">name of the main class for weblogic</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+
+<p>The wlrun task supports nested <code>&lt;classpath&gt;</code> and <code>&lt;wlclasspath&gt;</code>
+elements to set the respective classpaths.</p>
+
+<h3>Examples</h3>
+
+<p>This example shows the use of wlrun to run a server under Weblogic 5.1</p>
+
+<pre>
+    &lt;wlrun taskname=&quot;myserver&quot;
+           classpath=&quot;${weblogic.boot.classpath}&quot;
+           wlclasspath=&quot;${weblogic.classes}:${code.jars}&quot;
+           name=&quot;myserver&quot;
+           home=&quot;${weblogic.home}&quot;
+           properties=&quot;myserver/myserver.properties&quot;/&gt;
+</pre>
+
+<p>This example shows wlrun being used to run the petstore server under
+Weblogic 6.0</p>
+
+<pre>
+    &lt;wlrun taskname=&quot;petstore&quot;
+           classpath=&quot;${weblogic.classes}&quot;
+           name=&quot;petstoreServer&quot;
+           domain=&quot;petstore&quot;
+           home=&quot;${weblogic.home}&quot;
+           password=&quot;petstorePassword&quot;
+           beahome=&quot;${bea.home}&quot;/&gt;
+</pre>
+
+<hr>
+<h2><a name="wlstop">wlstop</a></h2>
+<h3><b>Description:</b></h3>
+
+<p>The <code>wlstop</code> task is used to stop a weblogic instance which is
+currently running. To shut down an instance you must supply both a username and
+a password. These will be stored in the clear in the build script used to stop
+the instance. For security reasons, this task is therefore only appropriate in a
+development environment. </p>
+
+<p>This task works for most version of Weblogic, including 6.0. You need to
+specify the BEA Home to have this task work correctly under 6.0</p>
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">BEAHome</td>
+    <td valign="top">This attribute selects Weblogic 6.0 shutdown.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to be used with the Java Virtual Machine that runs the Weblogic
+                     Shutdown command.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">user</td>
+    <td valign="top">The username of the account which will be used to shutdown the server</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">The password for the account specified in the user parameter.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">The URL which describes the port to which the server is listening for T3 connections.
+                     For example, t3://localhost:7001</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">delay</td>
+    <td valign="top">The delay in seconds after which the server will stop. This defaults to an
+                     immediate shutdown.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested Element</h3>
+
+<p>The classpath of the wlstop task can be set by a <code>&lt;classpath&gt;</code> nested element.</p>
+
+<h3>Examples</h3>
+
+<p>This example show the shutdown for a Weblogic 6.0 server</p>
+
+<pre>
+    &lt;wlstop classpath=&quot;${weblogic.classes}&quot;
+            user=&quot;system&quot;
+            url=&quot;t3://localhost:7001&quot;
+            password=&quot;foobar&quot;
+            beahome=&quot;${bea.home}&quot;/&gt;
+</pre>
+
+<hr>
+
+<h2><a name="ejbjar">ejbjar</a></h2>
+<h3><b>Description:</b></h3>
+
+<p>This task is designed to support building of EJB jar files (EJB 1.1 &amp; 2.0).
+Support is currently provided for 'vanilla' EJB jar files - i.e. those containing only
+the user generated class files and the standard deployment descriptor. Nested
+elements provide support for vendor specific deployment tools. These currently
+include: </p>
+<ul>
+  <li>Borland Application Server 4.5</li>
+  <li>iPlanet Application Server 6.0</li>
+  <li>JBoss 2.1 and above</li>
+  <li>Weblogic 5.1/6.0 session/entity beans using the weblogic.ejbc tool</li>
+  <li>IBM WebSphere 4.0</li>
+  <li>TOPLink for WebLogic 2.5.1-enabled entity beans</li>
+  <li><a href="http://www.objectweb.org/jonas/">JOnAS</a> 2.4.x and 2.5 Open Source EJB server</li>
+</ul>
+
+
+<p>The task works as a directory scanning task, and performs an action for each
+deployment descriptor found. As such the includes and excludes should be set
+to ensure that all desired EJB descriptors are found, but no application
+server descriptors are found. For each descriptor found, ejbjar will parse the
+deployment descriptor to determine the necessary class files which implement the
+bean. These files are assembled along with the deployment descriptors into a
+well formed EJB jar file. Any support files which need to be included in the
+generated jar can be added with the <code>&lt;support&gt;</code> nested element. For each
+class included in the jar, ejbjar will scan for any super classes or super
+interfaces. These will be added to the generated jar.</p>
+
+<p>If no nested vendor-specific deployment elements are present, the task will
+simply generate a generic EJB jar. Such jars are typically used as the input to
+vendor-specific deployment tools. For each nested deployment element, a vendor
+specific deployment tool is run to generate a jar file ready for deployment in
+that vendor's EJB container. </p>
+
+<p>The jar files are only built if they are out of date.  Each deployment tool
+element will examine its target jar file and determine if it is out of date with
+respect to the class files and deployment descriptors that make up the bean. If
+any of these files are newer than the jar file the jar will be rebuilt otherwise
+a message is logged that the jar file is up to date.</p>
+
+<p>The task uses the
+<a href="http://jakarta.apache.org/bcel"> jakarta-BCEL </a> framework
+to extract all dependent classes. This
+means that, in addition to the classes that are mentioned in the
+deployment descriptor, any classes that these depend on are also
+automatically included in the jar file.</p>
+
+
+<h3>Naming Convention</h3>
+
+Ejbjar handles the processing of multiple beans, and it uses a set of naming
+conventions to determine the name of the generated EJB jars. The naming convention
+that is used is controlled by the &quot;naming&quot; attribute. It supports the
+following values
+<ul>
+
+<li>descriptor</li>
+<p>This is the default naming scheme. The name of the generated bean is derived from the
+name of the deployment descriptor.  For an Account bean, for example, the deployment
+descriptor would be named <code>Account-ejb-jar.xml</code>. Vendor specific descriptors are
+located using the same naming convention. The weblogic bean, for example, would be named
+<code>Account-weblogic-ejb-jar.xml</code>. Under this arrangement, the deployment descriptors
+can be separated from the code implementing the beans, which can be useful when the same bean code
+is deployed in separate beans.
+</p>
+
+<p>This scheme is useful when you are using one bean per EJB jar and where you may be
+deploying the same bean classes in different beans, with different deployment characteristics.
+
+<li>ejb-name</li>
+<p> This naming scheme uses the <code>&lt;ejb-name&gt;</code> element from the deployment descriptor to
+determine the bean name. In this situation, the descriptors normally use the generic
+descriptor names, such as <code>ejb-jar.xml</code> along with any associated vendor specific descriptor
+names. For example, If the value of the <code>&lt;ejb-name&gt;</code> were to be given in the deployment descriptor
+as follows:
+<pre>
+&lt;ejb-jar&gt;
+    &lt;enterprise-beans&gt;
+        &lt;entity&gt;
+            &lt;ejb-name&gt;Sample&lt;/ejb-name&gt;
+            &lt;home&gt;org.apache.ant.ejbsample.SampleHome&lt;/home&gt;
+</pre>
+
+then the name of the generated bean would be <code>Sample.jar</code>
+</p>
+<p> This scheme is useful where you want to use the standard deployment descriptor names, which may be more
+compatible with other EJB tools. This scheme must have one bean per jar.
+</p>
+<li>directory</li>
+<p>
+In this mode, the name of the generated bean jar is derived from the directory
+containing the deployment descriptors. Again the deployment descriptors typically use
+the standard filenames. For example, if the path to the deployment descriptor is
+<code>/home/user/dev/appserver/dd/sample</code>, then the generated
+bean will be named <code>sample.jar</code>
+</p>
+<p>
+This scheme is also useful when you want to use standard style descriptor names. It is often
+most useful when the  descriptors are located in the same directory as the bean source code,
+although that is not mandatory. This scheme can handle multiple beans per jar.
+</p>
+
+<li>basejarname</li>
+<p>
+The final scheme supported by the <code>&lt;ejbjar&gt;</code> task is used when you want to specify the generated
+bean jar name directly. In this case the name of the generated jar is specified by the
+&quot;basejarname&quot; attribute. Since all generated beans will have the same name, this task should
+be only used when each descriptor is in its own directory.
+</p>
+
+<p>
+This scheme is most appropriate when you are using multiple beans per jar and only process a single
+deployment descriptor. You typically want to specify the name of the jar and not derive it from the
+beans in the jar.
+</p>
+
+</ul>
+
+<a name="ejbjar_deps"><h3>Dependencies</h3></a>
+<p>In addition to the bean classes, ejbjar is able to ad additional classes to the generated
+ejbjar. These classes are typically the support classes which are used by the bean's classes or as
+parameters to the bean's methods.</p>
+
+<p>In versions of Ant prior to 1.5, ejbjar used reflection and attempted to add the super
+classes and super interfaces of the bean classes. For this technique to work the bean
+classes had to be loaded into Ant's JVM. This was not always possible due to class dependencies.
+</p>
+
+<p>The ejbjar task in Ant releases 1.5 and later uses the
+<a href="http://jakarta.apache.org/bcel"> jakarta-BCEL </a> library
+to analyze the bean's class
+files directly, rather than loading them into the JVM. This also allows ejbjar to add all
+of the required support classes for a bean and not just super classes.
+</p>
+
+<p>In Ant 1.5, a new attribute, <code>dependency</code> has been introduced to allow the
+buildfile to control what additional classes are added to the generated jar. It takes three
+possible values</p>
+<ul>
+<li><code>none</code> - only the bean classes and interfaces described in the bean's
+descriptor are added to the jar.</li>
+<li><code>super</code> - this is the default value and replicates the original ejbjar
+behaviour where super classes and super interfaces are added to the jar</li>
+<li><code>full</code> - In this mode all classes used by the bean's classes and interfaces
+are added to the jar</li>
+</ul>
+<p>The <code>super</code> and <code>full</code> values require the
+<a href="http://jakarta.apache.org/bcel"> jakarta-BCEL </a> library
+to be available. If it is not, ejbjar will drop back to the behaviour corresponding to
+the value <code>none</code>.</p>
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">descriptordir</td>
+    <td valign="top">The base directory under which to scan for EJB
+                     deployment descriptors. If this attribute is not
+                     specified, then the deployment descriptors must be
+                     located in the directory specified by the 'srcdir'
+                     attribute.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">srcdir</td>
+    <td valign="top">The base directory containing the .class files that
+                     make up the bean. Included are the home- remote- pk-
+                     and implementation- classes and all classes, that these
+                     depend on. Note that this can be the same as the
+                     descriptordir if all files are in the same directory
+                     tree.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">The base directory into which generated jar files are
+                     deposited. Jar files are deposited in directories
+                     corresponding to their location within the descriptordir
+                     namespace. Note that this attribute is only used if the
+                     task is generating generic jars (i.e. no vendor-specific
+                     deployment elements have been specified).</td>
+    <td valign="top" align="center">Yes, unless vendor-specific deployment elements
+    have been specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">cmpversion</td>
+    <td valign="top">Either <code>1.0</code> or <code>2.0</code>.<br>
+    Default is <code>1.0</code>.<br>
+    A CMP 2.0 implementation exists currently only for JBoss.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">naming</td>
+    <td valign="top">Controls the naming convention used to name generated
+                     EJB jars. Please refer to the description above.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">basejarname</td>
+    <td valign="top">The base name that is used for the generated jar files.
+                     If this attribute is specified, the generic jar file name
+                     will use this value as the prefix (followed by the value
+                     specified in the 'genericjarsuffix' attribute) and the
+                     resultant ejb jar file (followed by any suffix specified
+                     in the nested element).</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">basenameterminator</td>
+    <td valign="top">String value used to substring out a string from the name
+                     of each deployment descriptor found, which is then used to
+                     locate related deployment descriptors (e.g. the WebLogic
+                     descriptors). For example, a basename of '.' and a
+                     deployment descriptor called 'FooBean.ejb-jar.xml' would
+                     result in a basename of 'FooBean' which would then be used
+                     to find FooBean.weblogic-ejb-jar.xml and
+                     FooBean.weblogic-cmp-rdbms-jar.xml, as well as to create
+                     the filenames of the jar files as FooBean-generic.jar and
+                     FooBean-wl.jar. This attribute is not used if the
+                     'basejarname' attribute is specified.</td>
+    <td valign="top" align="center">No, defaults to '-'.</td>
+  </tr>
+  <tr>
+    <td valign="top">genericjarsuffix</td>
+    <td valign="top">String value appended to the basename of the deployment
+                     descriptor to create the filename of the generic EJB jar
+                     file.</td>
+    <td valign="top" align="center">No, defaults to '-generic.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">This classpath is used when resolving classes which
+                     are to be added to the jar. Typically nested deployment
+                     tool elements will also support a classpath which
+                     will be combined with this classpath when resolving
+                     classes</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">flatdestdir</td>
+    <td valign="top">Set this attribute to true if you want all generated jars
+                     to be placed in the root of the destdir, rather than
+                     according to the location of the deployment descriptor
+                     within the descriptor dir hierarchy.</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">dependency</td>
+    <td valign="top">This attribute controls which additional classes and interfaces
+                     are added to the jar. Please refer to the description
+                     <a href="#ejbjar_deps">above</a></td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+
+<p>In addition to the vendor specific nested elements, the ejbjar task provides
+three nested elements. </p>
+
+<h4>Classpath</h4>
+
+<p>The <code>&lt;classpath&gt;</code> nested element allows the classpath
+to be set. It is useful when setting the classpath from a reference path. In all
+other respects the behaviour is the same as the classpath attribute.</p>
+
+<a name="ejbjar-dtd"><h4>dtd</h4></a>
+
+<p>The <code>&lt;dtd&gt;</code> element is used to specify the local location of DTDs to be
+used when parsing the EJB deployment descriptor. Using a local DTD is much
+faster than loading the DTD across the net. If you are running ejbjar behind a
+firewall you may not even be able to access the remote DTD. The supported
+vendor-specific nested elements know the location of the required DTDs within
+the vendor class hierarchy and, in general, this means <code>&lt;dtd&gt;</code> elements are
+not required. It does mean, however, that the vendor's class hierarchy must be
+available in the classpath when Ant is started. If your want to run Ant without
+requiring the vendor classes in the classpath, you would need to use a
+<code>&lt;dtd&gt;</code> element.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">publicId</td>
+    <td valign="top">The public Id of the DTD for which the location is being provided</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">The location of the local copy of the DTD. This can either be a
+                     file or a resource loadable from the classpath.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4>support</h4>
+
+<p>The <code>&lt;support&gt;</code> nested element is used to supply additional classes
+(files) to be included in the generated jars. The <code>&lt;support&gt;</code> element is a
+<a href="../CoreTypes/fileset.html">FileSet</a>, so it can either reference a fileset declared elsewhere or it can be
+defined in-place with the appropriate <code>&lt;include&gt;</code> and <code>&lt;exclude&gt;</code> nested
+elements. The files in the support fileset are added into the generated EJB jar
+in the same relative location as their location within the support fileset. Note
+that when ejbjar generates more than one jar file, the support files are added
+to each one.</p>
+
+<h3>Vendor-specific deployment elements</h3>
+
+Each vendor-specific nested element controls the generation of a deployable jar
+specific to that vendor's EJB container. The parameters for each supported
+deployment element are detailed here.
+
+
+<h3><a name="ejbjar_jboss">Jboss element</a></h3>
+
+<p>The jboss element searches for the JBoss specific deployment descriptors and adds them
+to the final ejb jar file. JBoss has two deployment descriptors:
+<ul><li>jboss.xml</li>
+<li>for container manager persistence:<br>
+<table border="1">
+<tr><td><b>CMP version</b></td><td><b>File name</b></td></tr>
+<tr><td>CMP 1.0</td><td>jaws.xml</td></tr>
+<tr><td>CMP 2.0</td><td>jbosscmp-jdbc.xml</td></tr>
+</table>
+</li>
+</ul>
+<br>
+. The JBoss server uses hot deployment and does
+not require compilation of additional stubs and skeletons.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">The base directory into which the generated weblogic ready
+                     jar files are deposited. Jar files are deposited in
+                     directories corresponding to their location within the
+                     descriptordir namespace. </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">genericjarsuffix</td>
+    <td valign="top">A generic jar is generated as an intermediate step in
+                     build the weblogic deployment jar. The suffix used to
+                     generate the generic jar file is not particularly
+                     important unless it is desired to keep the generic
+                     jar file. It should not, however, be the same
+                     as the suffix setting.</td>
+    <td valign="top" align="center">No, defaults to '-generic.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">suffix</td>
+    <td valign="top">String value appended to the basename of the deployment
+                     descriptor to create the filename of the JBoss EJB
+                     jar file.</td>
+    <td valign="top" align="center">No, defaults to '.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">keepgeneric</td>
+    <td valign="top">This controls whether the generic file used as input to
+                     ejbc is retained.</td>
+    <td valign="top" align="center">No, defaults to false</td>
+  </tr>
+</table>
+
+
+<h3><a name="ejbjar_weblogic">Weblogic element</a></h3>
+
+<p>The weblogic element is used to control the weblogic.ejbc compiler for
+generating weblogic EJB jars. Prior to Ant 1.3, the method of locating CMP
+descriptors was to use the ejbjar naming convention. So if your ejb-jar was
+called, Customer-ejb-jar.xml, your weblogic descriptor was called Customer-
+weblogic-ejb-jar.xml and your CMP descriptor had to be Customer-weblogic-cmp-
+rdbms-jar.xml. In addition, the <code>&lt;type-storage&gt;</code> element in the weblogic
+descriptor had to be set to the standard name META-INF/weblogic-cmp-rdbms-
+jar.xml, as that is where the CMP descriptor was mapped to in the generated
+jar.</p>
+
+<p>There are a few problems with this scheme. It does not allow for more than
+one CMP descriptor to be defined in a jar and it is not compatible with the
+deployment descriptors generated by some tools.</p>
+
+<p>In Ant 1.3, ejbjar parses the weblogic deployment descriptor to discover the
+CMP descriptors, which are then included automatically. This behaviour is
+controlled by the newCMP attribute. Note that if you move to the new method of
+determining CMP descriptors, you will need to update your weblogic deployment
+descriptor's <code>&lt;type-storage&gt;</code> element. In the above example, you would
+define this as META-INF/Customer-weblogic-cmp-rdbms-jar.xml.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">The base directory into which the generated weblogic ready
+                     jar files are deposited. Jar files are deposited in
+                     directories corresponding to their location within the
+                     descriptordir namespace. </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">genericjarsuffix</td>
+    <td valign="top">A generic jar is generated as an intermediate step in
+                     build the weblogic deployment jar. The suffix used to
+                     generate the generic jar file is not particularly
+                     important unless it is desired to keep the generic
+                     jar file. It should not, however, be the same
+                     as the suffix setting.</td>
+    <td valign="top" align="center">No, defaults to '-generic.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">suffix</td>
+    <td valign="top">String value appended to the basename of the deployment
+                     descriptor to create the filename of the WebLogic EJB
+                     jar file.</td>
+    <td valign="top" align="center">No, defaults to '.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to be used when running the weblogic ejbc
+                     tool. Note that this tool typically requires the classes
+                     that make up the bean to be available on the classpath.
+                     Currently, however, this will cause the ejbc tool to be
+                     run in a separate VM</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">wlclasspath</td>
+    <td valign="top">Weblogic 6.0 will give a warning if the home and remote interfaces
+                     of a bean are on the system classpath used to run weblogic.ejbc.
+                     In that case, the standard weblogic classes should be set with
+                     this attribute (or equivalent nested element) and the
+                     home and remote interfaces located with the standard classpath
+                     attribute</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keepgeneric</td>
+    <td valign="top">This controls whether the generic file used as input to
+                     ejbc is retained.</td>
+    <td valign="top" align="center">No, defaults to false</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td valign="top">This allows for the selection of a different compiler
+                     to be used for the compilation of the generated Java
+                     files. This could be set, for example, to Jikes to
+                     compile with the Jikes compiler. If this is not set
+                     and the <code>build.compiler</code> property is set
+                     to jikes, the Jikes compiler will be used. If this
+                     is not desired, the value &quot;<code>default</code>&quot;
+                     may be given to use the default compiler</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">rebuild</td>
+    <td valign="top">This flag controls whether weblogic.ejbc is always
+                     invoked to build the jar file. In certain circumstances,
+                     such as when only a bean class has been changed, the jar
+                     can be generated by merely replacing the changed classes
+                     and not rerunning ejbc. Setting this to false will reduce
+                     the time to run ejbjar.
+                     </td>
+    <td valign="top" align="center">No, defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">keepgenerated</td>
+    <td valign="top">Controls whether weblogic will keep the generated Java
+                     files used to build the class files added to the
+                     jar. This can be useful when debugging
+                     </td>
+    <td valign="top" align="center">No, defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">args</td>
+    <td valign="top">Any additional arguments to be passed to the weblogic.ejbc
+                     tool.
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">weblogicdtd</td>
+    <td valign="top"><b>Deprecated</b>. Defines the location of the ejb-jar DTD in
+                     the weblogic class hierarchy. This should not be necessary if you
+                     have weblogic in your classpath. If you do not, you should use a
+                     nested <code>&lt;dtd&gt;</code> element, described above. If you do choose
+                     to use an attribute, you should use a
+                     nested <code>&lt;dtd&gt;</code> element.
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">wldtd</td>
+    <td valign="top"><b>Deprecated</b>. Defines the location of the weblogic-ejb-jar
+                     DTD which covers the Weblogic specific deployment descriptors.
+                     This should not be necessary if you have weblogic in your
+                     classpath. If you do not, you should use a nested <code>&lt;dtd&gt;</code>
+                     element, described above.
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">ejbdtd</td>
+    <td valign="top"><b>Deprecated</b>. Defines the location of the ejb-jar DTD in
+                     the weblogic class hierarchy. This should not be necessary if you
+                     have weblogic in your classpath. If you do not, you should use a
+                     nested <code>&lt;dtd&gt;</code> element, described above.
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">newCMP</td>
+    <td valign="top">If this is set to true, the new method for locating
+                     CMP descriptors will be used.</td>
+    <td valign="top" align="center">No. Defaults to false</td>
+  </tr>
+  <tr>
+    <td valign="top">oldCMP</td>
+    <td valign="top"><b>Deprecated</b> This is an antonym for newCMP which should be used instead.</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">noEJBC</td>
+    <td valign="top">If this attribute is set to true, Weblogic's ejbc will not be run on the EJB jar.
+                     Use this if you prefer to run ejbc at deployment time.</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">ejbcclass</td>
+    <td valign="top">Specifies the classname of the ejbc compiler. Normally ejbjar determines
+                     the appropriate class based on the DTD used for the EJB. The EJB 2.0 compiler
+                     featured in weblogic 6 has, however, been deprecated in version 7. When
+                     using with version 7 this attribute should be set to
+                     &quot;weblogic.ejbc&quot; to avoid the deprecation warning.</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">jvmargs</td>
+    <td valign="top">Any additional arguments to be passed to the Virtual Machine
+                     running weblogic.ejbc tool. For example to set the memory size,
+                     this could be jvmargs=&quot;-Xmx128m&quot;
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">jvmdebuglevel</td>
+    <td valign="top">Sets the weblogic.StdoutSeverityLevel to use when running
+                     the Virtual Machine that executes ejbc. Set to 16 to avoid
+                     the warnings about EJB Home and Remotes being in the classpath
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+  <tr>
+    <td valign="top">outputdir</td>
+    <td valign="top">If set ejbc will be given this directory as the output
+                     destination rather than a jar file. This allows for the
+                     generation of &quot;exploded&quot; jars.
+                     </td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+</table>
+
+<p>The weblogic nested element supports three nested elements. The
+first two, <code>&lt;classpath&gt;</code> and <code>&lt;wlclasspath&gt;</code>, are used to set the
+respective classpaths. These nested elements are useful when setting up
+class paths using reference Ids. The last, <code>&lt;sysproperty&gt;</code>, allows
+Java system properties to be set during the compiler run. This turns out
+to be necessary for supporting CMP EJB compilation in all environments.
+</p>
+
+<h3>TOPLink for Weblogic element</h3>
+
+<p><b><i>Deprecated</i></b></p>
+
+<p>The toplink element is no longer required. Toplink beans can now be built with the standard
+weblogic element, as long as the newCMP attribute is set to &quot;true&quot;
+</p>
+
+<p>The TopLink element is used to handle beans which use Toplink for the CMP operations. It
+is derived from the standard weblogic element so it supports the same set of attributes plus these
+additional attributes</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">toplinkdescriptor</td>
+    <td valign="top">This specifies the name of the TOPLink deployment descriptor file contained in the
+                     'descriptordir' directory.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">toplinkdtd</td>
+    <td valign="top">This specifies the location of the TOPLink DTD file. This can be a file path or
+                     a file URL. This attribute is not required, but using a local DTD is recommended.</td>
+    <td valign="top" align="center">No, defaults to dtd file at www.objectpeople.com.</td>
+  </tr>
+</table>
+
+
+<h3>Examples</h3>
+
+<p>This example shows ejbjar being used to generate deployment jars using a
+Weblogic EJB container. This example requires the naming standard to be used for
+the deployment descriptors. Using this format will create a ejb jar file for
+each variation of '*-ejb-jar.xml' that is found in the deployment descriptor
+directory.</p>
+
+<pre>
+    &lt;ejbjar srcdir=&quot;${build.classes}&quot;
+            descriptordir=&quot;${descriptor.dir}&quot;&gt;
+      &lt;weblogic destdir=&quot;${deploymentjars.dir}&quot;
+                classpath=&quot;${descriptorbuild.classpath}&quot;/&gt;
+      &lt;include name=&quot;**/*-ejb-jar.xml&quot;/&gt;
+      &lt;exclude name=&quot;**/*weblogic*.xml&quot;/&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+<p>If weblogic is not in the Ant classpath, the following example
+shows how to specify the location of the weblogic DTDs. This
+example also show the use of a nested classpath element.</p>
+
+<pre>
+    &lt;ejbjar descriptordir=&quot;${src.dir}&quot; srcdir=&quot;${build.classes}&quot;&gt;
+       &lt;weblogic destdir=&quot;${deployment.webshop.dir}&quot;
+                 keepgeneric=&quot;true&quot;
+                 args=&quot;-g -keepgenerated ${ejbc.compiler}&quot;
+                 suffix=&quot;.jar&quot;
+                 oldCMP=&quot;false&quot;&gt;
+         &lt;classpath&gt;
+           &lt;pathelement path=&quot;${descriptorbuild.classpath}&quot;/&gt;
+         &lt;/classpath&gt;
+       &lt;/weblogic&gt;
+       &lt;include name=&quot;**/*-ejb-jar.xml&quot;/&gt;
+       &lt;exclude name=&quot;**/*-weblogic-ejb-jar.xml&quot;/&gt;
+       &lt;dtd publicId=&quot;-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN&quot;
+            location=&quot;${weblogic.home}/classes/weblogic/ejb/deployment/xml/ejb-jar.dtd&quot;/&gt;
+       &lt;dtd publicId=&quot;-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN&quot;
+            location=&quot;${weblogic.home}/classes/weblogic/ejb/deployment/xml/weblogic-ejb-jar.dtd&quot;/&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+
+<p>This example shows ejbjar being used to generate a single deployment jar
+using a Weblogic EJB container. This example does not require the deployment
+descriptors to use the naming standard. This will create only one ejb jar file -
+'TheEJBJar.jar'.</p>
+
+
+<pre>
+    &lt;ejbjar srcdir=&quot;${build.classes}&quot;
+            descriptordir=&quot;${descriptor.dir}&quot;
+            basejarname=&quot;TheEJBJar&quot;&gt;
+      &lt;weblogic destdir=&quot;${deploymentjars.dir}&quot;
+                classpath=&quot;${descriptorbuild.classpath}&quot;/&gt;
+      &lt;include name=&quot;**/ejb-jar.xml&quot;/&gt;
+      &lt;exclude name=&quot;**/weblogic*.xml&quot;/&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+<p>This example shows ejbjar being used to generate deployment jars for a TOPLink-enabled entity bean using a
+Weblogic EJB container. This example does not require the deployment descriptors to use the naming standard.
+This will create only one TOPLink-enabled ejb jar file - 'Address.jar'.</p>
+
+<pre>
+    &lt;ejbjar srcdir=&quot;${build.dir}&quot;
+            destdir=&quot;${solant.ejb.dir}&quot;
+            descriptordir=&quot;${descriptor.dir}&quot;
+            basejarname=&quot;Address&quot;&gt;
+            &lt;weblogictoplink destdir=&quot;${solant.ejb.dir}&quot;
+                    classpath=&quot;${java.class.path}&quot;
+                    keepgeneric=&quot;false&quot;
+                    toplinkdescriptor=&quot;Address.xml&quot;
+                    toplinkdtd=&quot;file:///dtdfiles/toplink-cmp_2_5_1.dtd&quot;
+                    suffix=&quot;.jar&quot;/&gt;
+            &lt;include name=&quot;**/ejb-jar.xml&quot;/&gt;
+            &lt;exclude name=&quot;**/weblogic-ejb-jar.xml&quot;/&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+<p>This final example shows how you would set-up ejbjar under Weblogic 6.0. It also shows the use of the
+<code>&lt;support&gt;</code> element to add support files</p>
+
+<pre>
+    &lt;ejbjar descriptordir=&quot;${dd.dir}&quot; srcdir=&quot;${build.classes.server}&quot;&gt;
+       &lt;include name=&quot;**/*-ejb-jar.xml&quot;/&gt;
+       &lt;exclude name=&quot;**/*-weblogic-ejb-jar.xml&quot;/&gt;
+       &lt;support dir=&quot;${build.classes.server}&quot;&gt;
+            &lt;include name=&quot;**/*.class&quot;/&gt;
+       &lt;/support&gt;
+       &lt;weblogic destdir=&quot;${deployment.dir}&quot;
+                 keepgeneric=&quot;true&quot;
+                 suffix=&quot;.jar&quot;
+                 rebuild=&quot;false&quot;&gt;
+         &lt;classpath&gt;
+            &lt;pathelement path=&quot;${build.classes.server}&quot;/&gt;
+         &lt;/classpath&gt;
+         &lt;wlclasspath&gt;
+            &lt;pathelement path=&quot;${weblogic.classes}&quot;/&gt;
+         &lt;/wlclasspath&gt;
+       &lt;/weblogic&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+
+<h3><a name="ejbjar_websphere">WebSphere element</a></h3>
+
+<p>The websphere element searches for the websphere specific deployment descriptors and
+adds them to the final ejb jar file. Websphere has two specific descriptors for session
+beans:
+<ul>
+   <li>ibm-ejb-jar-bnd.xmi</li>
+   <li>ibm-ejb-jar-ext.xmi</li>
+</ul>
+and another two for container managed entity beans:
+<ul>
+   <li>Map.mapxmi</li>
+   <li>Schema.dbxmi</li>
+</ul>
+In terms of WebSphere, the generation of container code and stubs is called <code>deployment</code>.
+This step can be performed by the websphere element as part of the jar generation process. If the
+switch <code>ejbdeploy</code> is on, the ejbdeploy tool from the websphere toolset is called for
+every ejb-jar. Unfortunately, this step only works, if you use the ibm jdk. Otherwise, the rmic
+(called by ejbdeploy) throws a ClassFormatError. Be sure to switch ejbdeploy off, if run ant with
+sun jdk.
+</p>
+
+<p>
+For the websphere element to work, you have to provide a complete classpath, that contains all
+classes, that are required to reflect the bean classes. For ejbdeploy to work, you must also provide
+the classpath of the ejbdeploy tool and set the <i>websphere.home</i> property (look at the examples below).
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">The base directory into which the generated weblogic ready
+                     jar files are deposited. Jar files are deposited in
+                     directories corresponding to their location within the
+                     descriptordir namespace. </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">ejbdeploy</td>
+    <td valign="top">Decides whether ejbdeploy is called. When you set this to true,
+                     be sure, to run ant with the ibm jdk.</td>
+    <td valign="top" align="center">No, defaults to true</td>
+  </tr>
+  <tr>
+    <td valign="top">suffix</td>
+    <td valign="top">String value appended to the basename of the deployment
+                     descriptor to create the filename of the WebLogic EJB
+                     jar file.</td>
+    <td valign="top" align="center">No, defaults to '.jar'.</td>
+  </tr>
+  <tr>
+    <td valign="top">keepgeneric</td>
+    <td valign="top">This controls whether the generic file used as input to
+                     ejbdeploy is retained.</td>
+    <td valign="top" align="center">No, defaults to false</td>
+  </tr>
+  <tr>
+    <td valign="top">rebuild</td>
+    <td valign="top">This controls whether ejbdeploy is called although no changes
+                     have occurred.</td>
+    <td valign="top" align="center">No, defaults to false</td>
+  </tr>
+  <tr>
+    <td valign="top">tempdir</td>
+    <td valign="top">A directory, where ejbdeploy will write temporary files</td>
+    <td valign="top" align="center">No, defaults to '_ejbdeploy_temp'.</td>
+  </tr>
+  <tr>
+    <td valign="top">dbName<br>dbSchema</td>
+    <td valign="top">These options are passed to ejbdeploy.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">dbVendor</td>
+    <td valign="top">This option is passed to ejbdeploy. 
+                   <p>
+                   Valid options can be obtained by running the following command:
+                   <code>
+                   &lt;WAS_HOME&gt;/bin/EJBDeploy.[sh/bat] -help
+                   </code>
+                   </p>
+                    This is also used to determine the name of the Map.mapxmi and
+                     Schema.dbxmi files, for example Account-DB2UDBWIN_V71-Map.mapxmi
+                     and Account-DB2UDBWIN_V71-Schema.dbxmi.
+                     </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">codegen<br>quiet<br>novalidate<br>noinform<br>trace<br>
+                     use35MappingRules</td>
+    <td valign="top">These options are all passed to ejbdeploy. All options
+                     except 'quiet' default to false.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">rmicOptions</td>
+    <td valign="top">This option is passed to ejbdeploy and will be passed
+                     on to rmic.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<p>This example shows ejbjar being used to generate deployment jars for all deployment descriptors
+in the descriptor dir:</p>
+
+<pre>
+    &lt;property name=&quot;webpshere.home&quot; value=&quot;${was4.home}&quot;/&gt;
+    &lt;ejbjar srcdir="${build.class}" descriptordir="etc/ejb"&gt;
+      &lt;include name="*-ejb-jar.xml"/&gt;
+      &lt;websphere dbvendor="DB2UDBOS390_V6"
+                 ejbdeploy="true"
+                 oldCMP="false"
+                 tempdir="/tmp"
+                 destdir="${dist.server}"&gt;
+        &lt;wasclasspath&gt;
+          &lt;pathelement location="${was4.home}/deploytool/itp/plugins/org.eclipse.core.boot/boot.jar"/&gt;
+          &lt;pathelement location="${was4.home}/deploytool/itp/plugins/com.ibm.etools.ejbdeploy/runtime/batch.jar"/&gt;
+          &lt;pathelement location="${was4.home}/lib/xerces.jar"/&gt;
+          &lt;pathelement location="${was4.home}/lib/ivjejb35.jar"/&gt;
+          &lt;pathelement location="${was4.home}/lib/j2ee.jar"/&gt;
+          &lt;pathelement location="${was4.home}/lib/vaprt.jar"/&gt;
+        &lt;/wasclasspath&gt;
+        &lt;classpath&gt;
+          &lt;path refid="build.classpath"/&gt;
+        &lt;/classpath&gt;
+      &lt;/websphere&gt;
+      &lt;dtd publicId="-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
+           location="${lib}/dtd/ejb-jar_1_1.dtd"/&gt;
+    &lt;/ejbjar&gt;
+</pre>
+
+<h3><a name="ejbjar_iplanet">iPlanet Application Server (iAS) element</a></h3>
+
+The &lt;iplanet&lt; nested element is used to build iAS-specific stubs and
+
+skeletons and construct a JAR file which may be deployed to the iPlanet
+Application Server 6.0.  The build process will always determine if
+the EJB stubs/skeletons and the EJB-JAR file are up to date, and it will
+do the minimum amount of work required.
+<p>Like the WebLogic element, a naming convention for the EJB descriptors
+is most commonly used to specify the name for the completed JAR file.
+For example, if the EJB descriptor ejb/Account-ejb-jar.xml is found in
+the descriptor directory, the iplanet element will search for an iAS-specific
+EJB descriptor file named ejb/Account-ias-ejb-jar.xml (if it isn't found,
+the task will fail) and a JAR file named ejb/Account.jar will be written
+in the destination directory.  Note that when the EJB descriptors
+are added to the JAR file, they are automatically renamed META-INF/ejb-jar.xml
+and META-INF/ias-ejb-jar.xml.</p>
+<p>Of course, this naming behaviour can be modified by specifying attributes
+in the ejbjar task (for example, basejarname, basenameterminator, and flatdestdir)
+as well as the iplanet element (for example, suffix).  Refer to the
+appropriate documentation for more details.</p>
+<h3>
+Parameters:</h3>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+<td valign="top"><b>Attribute</b></td>
+
+<td valign="top"><b>Description</b></td>
+
+<td align="center" valign="top"><b>Required</b></td>
+</tr>
+
+<tr>
+<td valign="top">destdir</td>
+
+<td valign="top">The base directory into which the generated JAR files will
+be written. Each JAR file is written in directories which correspond to
+their location within the "descriptordir" namespace.</td>
+
+<td align="center" valign="top">Yes</td>
+</tr>
+
+<tr>
+<td valign="top">classpath</td>
+
+<td valign="top">The classpath used when generating EJB stubs and skeletons.
+If omitted, the classpath specified in the "ejbjar" parent task will be
+used.  If specified, the classpath elements will be prepended to the
+classpath specified in the parent "ejbjar" task. Note that nested "classpath"
+elements may also be used.</td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">keepgenerated</td>
+
+<td valign="top">Indicates whether or not the Java source files which are
+generated by ejbc will be saved or automatically deleted. If "yes", the
+source files will be retained.  If omitted, it defaults to "no". </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">debug</td>
+
+<td>Indicates whether or not the ejbc utility should log additional debugging
+statements to the standard output. If "yes", the additional debugging statements
+will be generated.  If omitted, it defaults to "no". </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">iashome</td>
+
+<td>May be used to specify the "home" directory for this iAS installation.
+This is used to find the ejbc utility if it isn't included in the user's
+system path.  If specified, it should refer to the [install-location]/iplanet/ias6/ias
+directory.  If omitted, the ejbc utility must be on the user's system
+path. </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+
+<tr>
+<td valign="top">suffix</td>
+
+<td>String value appended to the JAR filename when creating each JAR.
+If omitted, it defaults to ".jar". </td>
+
+<td align="center" valign="top">No</td>
+</tr>
+</table>
+
+<p>As noted above, the iplanet element supports additional <code>&lt;classpath&gt;</code>
+nested elements.</p>
+<h3>
+Examples</h3>
+This example demonstrates the typical use of the <code>&lt;iplanet&gt;</code> nested element.
+It will name each EJB-JAR using the "basename" prepended to each standard
+EJB descriptor.  For example, if the descriptor named "Account-ejb-jar.xml"
+is processed, the EJB-JAR will be named "Account.jar"
+<pre>
+    &lt;ejbjar srcdir="${build.classesdir}"
+            descriptordir="${src}"&gt;
+
+            &lt;iplanet destdir="${assemble.ejbjar}"
+                     classpath="${ias.ejbc.cpath}"/&gt;
+            &lt;include name="**/*-ejb-jar.xml"/&gt;
+            &lt;exclude name="**/*ias-*.xml"/&gt;
+    &lt;/ejbjar&gt;</pre>
+
+This example demonstrates the use of a nested classpath element as well
+as some of the other optional attributes.
+<pre>
+    &lt;ejbjar srcdir="${build.classesdir}"
+            descriptordir="${src}"&gt;
+
+            &lt;iplanet destdir="${assemble.ejbjar}"
+                     iashome="${ias.home}"
+                     debug="yes"
+                     keepgenerated="yes"&gt;
+                     &lt;classpath&gt;
+                         &lt;pathelement path="."/&gt;
+                         &lt;pathelement path="${build.classpath}"/&gt;
+                     &lt;/classpath&gt;
+            &lt;/iplanet&gt;
+            &lt;include name="**/*-ejb-jar.xml"/&gt;
+            &lt;exclude name="**/*ias-*.xml"/&gt;
+    &lt;/ejbjar&gt;</pre>
+
+This example demonstrates the use of basejarname attribute.  In this
+case, the completed EJB-JAR will be named "HelloWorld.jar"  If multiple
+EJB descriptors might be found, care must be taken to ensure that the completed
+JAR files don't overwrite each other.
+<pre>
+    &lt;ejbjar srcdir="${build.classesdir}"
+            descriptordir="${src}"
+            basejarname="HelloWorld"&gt;
+
+            &lt;iplanet destdir="${assemble.ejbjar}"
+                     classpath="${ias.ejbc.cpath}"/&gt;
+            &lt;include name="**/*-ejb-jar.xml"/&gt;
+            &lt;exclude name="**/*ias-*.xml"/&gt;
+    &lt;/ejbjar&gt;</pre>
+This example demonstrates the use of the dtd nested element. If the local
+copies of the DTDs are included in the classpath, they will be automatically
+referenced without the nested elements.  In iAS 6.0 SP2, these local DTDs are
+found in the [iAS-install-directory]/APPS directory.  In iAS 6.0 SP3, these
+local DTDs are found in the [iAS-install-directory]/dtd directory.
+<pre>
+    &lt;ejbjar srcdir="${build.classesdir}"
+            descriptordir="${src}"&gt;
+            &lt;iplanet destdir="${assemble.ejbjar}"&gt;
+                     classpath="${ias.ejbc.cpath}"/&gt;
+            &lt;include name="**/*-ejb-jar.xml"/&gt;
+            &lt;exclude name="**/*ias-*.xml"/&gt;
+
+            &lt;dtd publicId="-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN"
+                 location="${ias.home}/APPS/ejb-jar_1_1.dtd"/&gt;
+            &lt;dtd publicId="-//Sun Microsystems, Inc.//DTD iAS Enterprise JavaBeans 1.0//EN"
+                 location="${ias.home}/APPS/IASEjb_jar_1_0.dtd"/&gt;
+    &lt;/ejbjar&gt;</pre>
+
+<h3><a name="ejbjar_jonas">JOnAS (Java Open Application Server) element</a></h3>
+
+<p>The <code>&lt;jonas&gt;</code> nested element is used to build JOnAS-specific stubs and
+skeletons thanks to the <code>GenIC</code> specific tool, and construct a JAR
+file which may be deployed to the JOnAS Application Server. The build process
+will always determine if the EJB stubs/skeletons and the EJB-JAR file are up to
+date, and it will do the minimum amount of work required.</p>
+
+<p>Like the WebLogic element, a naming convention for the EJB descriptors is
+most commonly used to specify the name for the completed JAR file. For example,
+if the EJB descriptor <code>ejb/Account-ejb-jar.xml</code> is found in the
+descriptor directory, the <code>&lt;jonas&gt;</code> element will search for a JOnAS-specific
+EJB descriptor file named <code>ejb/Account-jonas-ejb-jar.xml</code> and a JAR
+file named <code>ejb/Account.jar</code> will be written in the destination
+directory. But the <code>&lt;jonas&gt;</code> element can also use the JOnAS naming
+convention. With the same example as below, the EJB descriptor can also be named
+<code>ejb/Account.xml</code> (no base name terminator here) in the descriptor
+directory. Then the <code>&lt;jonas&gt;</code> element will search for a JOnAS-specific EJB
+descriptor file called <code>ejb/jonas-Account.xml</code>. This convention do
+not follow strictly the ejb-jar naming convention recommendation but is
+supported for backward compatibility with previous version of JOnAS.</p>
+
+<p>Note that when the EJB descriptors are added to the JAR file, they are
+automatically renamed <code>META-INF/ejb-jar.xml</code> and
+<code>META-INF/jonas-ejb-jar.xml</code>.</p>
+
+<p>Of course, this naming behavior can be modified by specifying attributes in
+the ejbjar task (for example, basejarname, basenameterminator, and flatdestdir)
+as well as the iplanet element (for example, suffix). Refer to the appropriate
+documentation for more details.</p>
+
+<h3> Parameters:</h3>
+
+<table border="1" cellspacing="0" cellpadding="2">
+  <tbody>
+    <tr>
+      <td valign="Top"><b>Attribute</b></td>
+      <td valign="Top"><b>Description</b></td>
+      <td align="Center" valign="Top"><b>Required</b></td>
+    </tr>
+    <tr>
+      <td valign="Top">destdir</td>
+      <td valign="Top">The base directory into which the generated JAR files
+      will be written. Each JAR file is written in directories which correspond
+      to their location within the "<code>descriptordir</code>" namespace.</td>
+      <td align="Center" valign="Top">Yes</td>
+    </tr>
+    <tr>
+      <td valign="Top">jonasroot</td>
+      <td valign="Top">The root directory for JOnAS.</td>
+      <td valign="Top" align="Center">Yes</td>
+    </tr>
+    <tr>
+      <td valign="Top">classpath</td>
+      <td valign="Top">The classpath used when generating EJB stubs and
+      skeletons. If omitted, the classpath specified in the "ejbjar" parent
+      task will be used. If specified, the classpath elements will be prepended
+      to the classpath specified in the parent "ejbjar" task (see also the ORB
+      attribute documentation below). Note that nested "classpath" elements may
+      also be used.</td>
+      <td valign="Top" align="Center">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">keepgenerated</td>
+      <td valign="Top"><code>true</code> if the intermediate Java
+      source files generated by GenIC must be deleted or not. If
+      omitted, it defaults to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">nocompil</td>
+      <td valign="Top"><code>true</code> if the generated source files
+      must not be compiled via the java and rmi compilers. If omitted,
+      it defaults to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">novalidation</td>
+      <td valign="Top"><code>true</code> if the XML deployment descriptors must
+      be parsed without validation. If omitted, it defaults to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">javac</td>
+      <td valign="Top">Java compiler to use. If omitted, it defaults
+      to the value of <code>build.compiler</code> property.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">javacopts</td>
+      <td valign="Top">Options to pass to the java compiler.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">rmicopts</td>
+      <td valign="Top">Options to pass to the rmi compiler.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">secpropag</td>
+      <td valign="top"><code>true</code> if the RMI Skel. and
+      Stub. must be modified to implement the implicit propagation of
+      the security context (the transactional context is always
+      provided). If omitted, it defaults to <code>false</code>.</td>
+      <td valign="top" align="center">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">verbose</td>
+      <td valign="Top">Indicates whether or not to use -verbose switch. If
+      omitted, it defaults to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">additionalargs</td>
+      <td valign="Top">Add additional args to GenIC.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">keepgeneric</td>
+      <td valign="Top"><code>true</code> if the generic JAR file used as input
+      to GenIC must be retained. If omitted, it defaults to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">suffix</td>
+      <td>String value appended to the JAR filename when creating each JAR.  If
+      omitted, it defaults to ".jar". </td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">orb</td>
+      <td>Choose your ORB : RMI, JEREMIE, DAVID. If omitted, it defaults to the
+      one present in classpath. If specified, the corresponding JOnAS JAR is
+      automatically added to the classpath.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+      <td valign="Top">nogenic</td>
+      <td valign="Top">If this attribute is set to <code>true</code>,
+      JOnAS's GenIC will not be run on the EJB JAR. Use this if you
+      prefer to run GenIC at deployment time. If omitted, it defaults
+      to <code>false</code>.</td>
+      <td align="Center" valign="Top">No</td>
+    </tr>
+    <tr>
+  </tbody>
+</table>
+
+<p>As noted above, the jonas element supports additional <code>&lt;classpath&gt;</code>
+nested elements.</p>
+
+<h3>Examples</h3>
+
+<p>This example shows ejbjar being used to generate deployment jars using a
+JOnAS EJB container. This example requires the naming standard to be used for
+the deployment descriptors. Using this format will create a EJB JAR file for
+each variation of &nbsp;'*-jar.xml' that is found in the deployment descriptor
+directory.&nbsp;</p>
+
+<pre>
+      &lt;ejbjar srcdir="${build.classes}"
+              descriptordir="${descriptor.dir}"&gt;
+        &lt;jonas destdir="${deploymentjars.dir}"
+             jonasroot="${jonas.root}"
+             orb="RMI"/&gt;
+        &lt;include name="**/*.xml"/&gt;
+        &lt;exclude name="**/jonas-*.xml"/&gt;
+        &lt;support dir="${build.classes}"&gt;
+             &lt;include name="**/*.class"/&gt;
+        &lt;/support&gt;
+      &lt;/ejbjar&gt;
+</pre>
+
+<p>This example shows ejbjar being used to generate a single deployment jar
+using a JOnAS EJB container. This example does require the deployment
+descriptors to use the naming standard. This will create only one ejb jar file -
+'TheEJBJar.jar'.</p>
+
+<pre>
+      &lt;ejbjar srcdir="${build.classes}"
+              descriptordir="${descriptor.dir}"
+              basejarname="TheEJBJar"&gt;
+        &lt;jonas destdir="${deploymentjars.dir}"
+                  jonasroot="${jonas.root}"
+                  suffix=".jar"
+                  classpath="${descriptorbuild.classpath}"/&gt;
+        &lt;include name="**/ejb-jar.xml"/&gt;
+        &lt;exclude name="**/jonas-ejb-jar.xml"/&gt;
+      &lt;/ejbjar&gt;
+</pre>
+
+
+
+
+</body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/ftp.html b/trunk/docs/manual/OptionalTasks/ftp.html
new file mode 100644
index 0000000..77681cd
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/ftp.html
@@ -0,0 +1,718 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>FTP Task</title>
+</head>
+
+<body>
+
+<h2><a name="ftp">FTP</a></h2>
+<h3>Description</h3>
+<p>The ftp task implements a basic FTP client that can send, receive,
+list, delete files, and create directories.  See below for descriptions and examples of how
+to perform each task.</p>
+<p><b>Note:</b> This task depends on external libraries not included in the Ant distribution.
+See <a href="../install.html#commons-net">Library Dependencies</a> for more information.
+<i>Get the latest version of this library, for the best support in Ant</i>
+
+</p>
+<p>The ftp task attempts to determine what file system is in place on the FTP server.
+Supported server types are Unix, NT, OS2, VMS, and OS400.  In addition, NT and OS400 servers
+which have been configured to display the directory in Unix style are also supported correctly.
+Otherwise, the system will default to Unix standards.
+<i>remotedir</i> must be specified in the exact syntax required by the ftp
+server. If the usual Unix conventions are not supported by the server,
+<i>separator</i> can be used to set the file separator that should be used
+instead.</p>
+<p>See the section on <a href="../dirtasks.html#directorybasedtasks">directory based
+tasks</a>, on how the inclusion/exclusion of files works, and how to
+write patterns.</p>
+<p>
+This task does not currently use the proxy information set by the
+<a href="setproxy.html"><code>&lt;setproxy&gt;</code></a> task, and cannot go through
+a firewall via socks. 
+<p>
+<b>Warning: </b> there have been problems reported concerning the ftp get with the <code>newer</code> attribute.
+Problems might be due to format of ls -l differing from what is expected by commons-net,
+for instance due to specificities of language used by the ftp server in the directory listing.
+If you encounter such a problem, please send an email including a sample directory listing
+coming from your ftp server (ls -l on the ftp prompt).
+</p>
+<p>
+If you can connect but not upload or download, try setting the <code>passive</code>
+attribute to true to use the existing (open) channel, instead of having the server
+try to set up a new connection.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top" width="15%"><b>Attribute</b></td>
+    <td valign="top" width="65%"><b>Description</b></td>
+    <td align="center" valign="top" width="20%"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">server</td>
+    <td valign="top">the address of the remote ftp server.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">the port number of the remote ftp server.
+                     Defaults to port 21.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">userid</td>
+    <td valign="top">the login id to use on the ftp server.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">the login password to use on the ftp server.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">account</td>
+    <td valign="top">the account to use on the ftp server.
+        <em>since Ant 1.7</em>.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">remotedir</td>
+    <td valign="top">remote directory on the
+                     ftp server
+                     see table below for detailed usage
+                     </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">action</td>
+    <td valign="top">the ftp action to perform, defaulting to "send".
+                     Currently supports "put", "get",
+                     "del", "list", "chmod",
+                     "mkdir", "rmdir", and "site".</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">binary</td>
+    <td valign="top">selects binary-mode ("yes") or text-mode
+                     ("no") transfers.
+                     Defaults to "yes"</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">passive</td>
+    <td valign="top">selects passive-mode ("yes") transfers, for
+                     better through-firewall connectivity, at the price
+                     of performance.
+                     Defaults to "no"</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">displays information on each file transferred if set 
+                     to "yes". Defaults to "no".</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">depends</td>
+    <td valign="top">transfers only new or changed files if set to 
+                     "yes". Defaults to "no".</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">newer</td>
+    <td valign="top">a synonym for <i>depends</i>.
+    see timediffauto and timediffmillis</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timediffauto</td>
+    <td valign="top">set to <code>"true"</code>
+    to make ant calculate the time difference between client and server.<br>
+    <em>requires write access in the remote directory</em><br>
+    Since ant 1.6</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <a name="timestampGranularity"/>
+  <tr>
+    <td valign="top">timestampGranularity</td>
+    <td valign="top">Specify either <code>MINUTE</code>, <code>NONE</code>,
+     (or you may specify <code>""</code> which is equivalent to not specifying a value,
+     useful for property-file driven scripts).  Allows override of the typical situation 
+     in PUT and GET where local filesystem timestamps are <code>HH:mm:ss</code> 
+     and the typical FTP server's timestamps are <code>HH:mm</code>.  This can throw 
+     off uptodate calculations.  However, the default values should suffice for most
+     applications.<br>
+    Since ant 1.7
+    </td>
+    <td valign="top" align="center">No.  Only applies in "puts" and "gets" where the
+    default values are <code>MINUTE</code> for PUT and <code>NONE</code> for GET.  
+    (It is not as necessary in GET because we have the <b>preservelastmodified</b> option.)</td>
+  </tr>
+  <tr>
+    <td valign="top">timediffmillis</td>
+    <td valign="top"><b>Deprecated</b>. Number of milliseconds to add to the time on 
+    the remote machine to get the time on the local machine.  The <b>timestampGranularity</b> 
+    attribute (for which the default values should suffice in most situations), and the 
+    <b>serverTimeZoneConfig</b> option, should make this unnecessary. 
+    <b>serverTimeZoneConfig</b> does the math for you and also knows about 
+    Daylight Savings Time.<br>
+    Since ant 1.6
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">separator</td>
+    <td valign="top">sets the file separator used on the ftp server.
+                     Defaults to "/".</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">umask</td>
+    <td valign="top">sets the default file permissions for new files,
+                     unix only.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">chmod</td>
+    <td valign="top">sets or changes file permissions for new or existing files,
+      unix only. If used with a put action, chmod will be issued for each file.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">listing</td>
+    <td valign="top">the file to write results of the "list" action.
+                     Required for the "list" action, ignored otherwise.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">ignoreNoncriticalErrors</td>
+    <td valign="top">flag which permits the task to ignore some non-fatal error
+      codes sent by some servers during directory creation: wu-ftp in particular.
+      Default: false</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">skipFailedTransfers</td>
+    <td valign="top">flag which enables unsuccessful file put, delete
+    and get operations to be skipped with a warning and the
+    remainder of the files still transferred. Default: false</td>
+    <td valign="top" align="center">No</td>
+  </tr>  
+  <tr>
+    <td valign="top">preservelastmodified</td>
+    <td valign="top">Give the copied files the same last modified
+      time as the original source files (applies to getting files only).
+      (<em>Note</em>: Ignored on Java 1.1)</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">retriesAllowed</td>
+    <td valign="top">Set the number of retries allowed on an file-transfer operation.
+    If a number > 0 specified, each file transfer can fail up to that
+    many times before the operation is failed.  If -1 or "forever" specified, the
+    operation will keep trying until it succeeds.</td>
+    <td valign="top" align="center">No; defaults to 0</td>
+  </tr>
+  <tr>
+    <td valign="top">siteCommand</td>
+    <td valign="top">Set the server-specific SITE command to execute if
+    the <code>action</code> attribute has been specified as <code>"site"</code>.
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">initialSiteCommand</td>
+    <td valign="top">Set a server-specific SITE command to execute immediately
+    after login.
+    <td valign="top" align="center">No</td>
+  </tr>
+
+    <tr>
+    <td colspan="3">
+    <p><b>The following attributes require <a href=
+    "http://jakarta.apache.org/commons/net/download.html">
+    jakarta-commons-net-1.4.0 or greater</a>.</b></p>
+    <p>
+    Use these options when the standard options don't work, because
+    <ul><li>the server is in a different timezone and you need timestamp
+    dependency checking</li>
+    <li>the default timestamp formatting doesn't match the server display and
+    list parsing therefore fails</li></ul>
+    </p><p>
+    If none of these is specified, the default mechanism of letting the system
+    auto-detect the server OS type based on the FTP SYST command and assuming
+    standard formatting for that OS type will be used.
+    </p><p>
+    To aid in property-file-based development where a build script is configured
+    with property files, for any of these attributes, a value of <code>""</code>
+    is equivalent to not specifying it.
+    </p><p>
+    Please understand that these options are incompatible with the autodetection
+    scheme.  If any of these options is specified, (other than with a value of
+    <code>""</code> ) a system type must be chosen and if systemTypeKey is not
+    specified, UNIX will be assumed. The philosophy behind this is that these
+    options are for setting non-standard formats, and a build-script author who
+    knows what system he is dealing with will know what options to need to be
+    set. Otherwise, these options should be left alone and the default
+    autodetection scheme can be used and will work in the majority of cases.
+    </p></td>
+    </tr>
+  <tr>
+    <td valign="top">systemTypeKey</td>
+    <td valign="top">Specifies the type of system in use on the server.
+      Supported values are <code>"UNIX", "VMS", "WINDOWS", "OS/2", "OS/400",
+      "MVS".</code>  If not specified, (or specified as <code>""</code>) and if
+      no other xxxConfig attributes are specified, the autodectection mechanism
+      based on the FTP SYST command will be used.<br>
+      Since ant 1.7
+    </td>
+    <td valign="top" align="center">No, but if any of the following xxxConfig
+        attributes is specified, UNIX will be assumed, even if <code>""</code>
+        is specified here.
+    </td>
+   </tr>
+   <tr>
+    <td valign="top">serverTimeZoneConfig</td>
+    <td valign="top">Specify as a Java
+     <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/TimeZone.html">
+     TimeZone</a> identifier, (e.g. <code>GMT</code>, <code>America/Chicago</code> or
+    <code>Asia/Jakarta</code>) the timezone used by the server for timestamps.  This 
+      enables timestamp dependency checking even when the server is in a different 
+      time zone from the client. Time Zones know, also, about daylight savings time, 
+      and do not require you to calculate milliseconds of difference.  If not specified, 
+      (or specified as <code>""</code>), the time zone of the client is assumed.<br>
+      Since ant 1.7
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    
+    <td valign="top">defaultDateFormatConfig</td>
+    <td valign="top">Specify in Java 
+    <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html">
+     SimpleDateFormat</a> notation, (e.g.
+     <code>yyyy-MM-dd</code>), the date format generally used by the FTP server
+      to parse dates.  In some cases this will be the only date format used.
+      In others, (unix for example) this will be used for dates
+      older than a year old. (See <b>recentDateFormatConfig</b>).  If not specified,
+      (or specified as <code>""</code>), the default date format for the system
+      type indicated by the <b>systemTypeKey</b> attribute will be used.<br>
+      Since ant 1.7
+    </td>
+    <td valign="top" align="center">
+    No.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">recentDateFormatConfig</td>
+    <td valign="top">Specify in Java 
+    <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html">
+     SimpleDateFormat</a> notation,
+      (e.g. <code>MMM dd hh:mm</code>) the date format used by the FTP server
+      to parse dates less than a year old.  If not specified (or specified as
+      <code>""</code>), and if the system type indicated by the system key uses
+      a recent date format, its standard format will be used.<br>
+      Since ant 1.7
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">serverLanguageCodeConfig</td>
+    <td valign="top">a <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt">
+      two-letter ISO-639 language code</a> used to specify the
+      language used by the server to format month names.  This only needs to be
+      specified when the server uses non-numeric abbreviations for months in its
+      date listings in a language other than English.  This appears to be
+      becoming rarer and rarer, as commonly distributed ftp servers seem
+      increasingly to use English or all-numeric formats.
+      Languages supported are:
+      <ul>
+      	<li>en - English</li>
+      	<li>fr - French</li>
+      	<li>de - German</li>
+      	<li>it - Italian</li>
+      	<li>es - Spanish</li>
+      	<li>pt - Portuguese</li>
+      	<li>da - Danish</li>
+      	<li>sv - Swedish</li>
+      	<li>no - Norwegian</li>
+      	<li>nl - Dutch</li>
+      	<li>ro - Romanian</li>
+      	<li>sq - Albanian</li>
+      	<li>sh - Serbo-croatian</li>
+      	<li>sk - Slovak</li>
+      	<li>sl - Slovenian</li>
+      </ul>
+      If you require a language other than the above, see also the
+      <b>shortMonthNamesConfig</b> attribute.<br>
+      Since ant 1.7
+    </td>
+
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">shortMonthNamesConfig</td>
+    <td valign="top">specify the month abbreviations used on the server in file
+      timestamp dates as a pipe-delimited string for each month. For example,
+      a set of month names used by a hypothetical
+      Icelandic FTP server might conceivably be specified as
+      <code>"jan|feb|mar|apr|ma&#xED;|j&#xFA;n|j&#xFA;l|&#xE1;g&#xFA;|sep|okt|n&#xF3;v|des"</code>.
+      This attribute exists primarily to support languages not supported by
+      the <b>serverLanguageCode</b> attribute.<br>
+      Since ant 1.7
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Note about remotedir attribute</h3>
+<table  border="1" cellpadding="2" cellspacing="0"
+ >
+  <tbody>
+    <tr>
+      <td style="vertical-align: top;" width="20%">Action<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">meaning of <code>remotedir</code><br>
+      </td>
+      <td style="vertical-align: top;">use of nested <code>fileset</code>
+(s)<br>
+      </td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">send/put<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">base directory to
+which the files are sent<br>
+      </td>
+      <td style="vertical-align: top;">they are used normally and
+evaluated on the local machine<br>
+      </td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">recv/get<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">base directory from
+which the files are retrieved<br>
+      </td>
+      <td style="vertical-align: top;">the remote files located under
+the <code>remotedir </code>matching the include/exclude patterns of
+the <code>fileset&nbsp;</code></td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">del/delete<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">base directory from
+which files get deleted<br>
+      </td>
+      <td style="vertical-align: top;">the remote files located under
+the <code>remotedir </code>matching the include/exclude patterns of
+the <code>fileset <br>
+      </code></td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">list<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">base directory from
+which files are listed<br>
+      </td>
+      <td style="vertical-align: top;">the remote files located under
+the <code>remotedir </code>matching the include/exclude patterns of
+the <code>fileset <br>
+      </code></td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">mkdir</td>
+      <td style="vertical-align: top;" width="40%">directory to create<br>
+      </td>
+      <td style="vertical-align: top;">not used<br>
+      </td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">chmod</td>
+      <td style="vertical-align: top;" width="40%">base directory from
+which the mode of files get changed<br>
+      </td>
+      <td style="vertical-align: top;">the remote files located under
+the <code>remotedir </code>matching the include/exclude patterns of
+the <code>fileset <br>
+      </code></td>
+    </tr>
+    <tr>
+      <td style="vertical-align: top;" width="20%">rmdir<br>
+      </td>
+      <td style="vertical-align: top;" width="40%">base directory from
+which directories get removed<br>
+      </td>
+      <td style="vertical-align: top;">the remote directories located
+under the <code>remotedir </code>matching the include/exclude
+patterns of the <code>fileset <br>
+      </code></td>
+    </tr>
+  </tbody>
+</table><h3>Parameters specified as nested elements</h3>
+<h4>fileset</h4>
+<p>The ftp task supports any number of nested <a
+href="../CoreTypes/fileset.html"><code>&lt;fileset&gt;</code></a> elements to specify
+the files to be retrieved, or deleted, or listed, or whose mode you want to change.</p>
+<p>
+The attribute <code>followsymlinks</code> of <code>fileset</code> is supported on
+local (put) as well as remote (get, chmod, delete) filesets.
+<em>Before ant 1.6 there was no support of symbolic links in remote filesets.
+In order to exclude symbolic links (preserve the behavior of ant 1.5.x and older),
+you need to explicitly set <code>followsymlinks</code> to <code>false</code>.</em>
+On remote filesets hidden files are not checked for being symbolic links. Hidden
+files are currently assumed to not be symbolic links.
+</p>
+<p>
+Remote filesets do not support selectors.<br>
+</p>
+
+<h3>Sending Files</h3>
+<p>The easiest way to describe how to send files is with a couple of examples:</p>
+<pre>
+  &lt;ftp server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"&gt;
+    &lt;fileset dir="htdocs/manual"/&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and 
+uploads all files in the <code>htdocs/manual</code> directory 
+to the default directory for that user.</p>
+<pre>  &lt;ftp server="ftp.apache.org"
+       remotedir="incoming"
+       userid="anonymous"
+       password="me@myorg.com"
+       depends="yes"&gt;
+    &lt;fileset dir="htdocs/manual"/&gt;
+  &lt;/ftp&gt;</pre>
+<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and
+uploads all new or changed files in the <code>htdocs/manual</code> directory 
+to the <code>incoming</code> directory relative to the default directory
+for <code>anonymous</code>.</p>
+<pre>  &lt;ftp server="ftp.apache.org"
+       port="2121"
+       remotedir="/pub/incoming"
+       userid="coder"
+       password="java1"
+       passive="yes"
+       depends="yes"
+       binary="no"&gt;
+    &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;</pre>
+<p>Logs in to <code>ftp.apache.org</code> at port <code>2121</code> as
+<code>coder</code> with password <code>java1</code> and uploads all new or
+changed HTML files in the <code>htdocs/manual</code> directory to the
+<code>/pub/incoming</code> directory. The files are transferred in text mode.
+Passive mode has been switched on to send files from behind a firewall.</p>
+<pre>  &lt;ftp server="ftp.hypothetical.india.org"
+       port="2121"
+       remotedir="/pub/incoming"
+       userid="coder"
+       password="java1"
+       depends="yes"
+       binary="no"
+       systemTypeKey="Windows"
+       serverTimeZoneConfig="India/Calcutta"&gt;
+    &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;</pre>
+<p>Logs in to a Windows server at <code>ftp.hypothetical.india.org</code>
+at port <code>2121</code> as <code>coder</code> with password <code>java1</code>
+and uploads all new or changed (accounting for timezone differences)
+HTML files in the <code>htdocs/manual</code>
+directory to the <code>/pub/incoming</code> directory. The files are transferred
+in text mode.</p>
+<pre>  &lt;ftp server="ftp.nt.org"
+       remotedir="c:\uploads"
+       userid="coder"
+       password="java1"
+       separator="\"
+       verbose="yes"&gt;
+    &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;</pre><p>Logs in to the Windows-based <code>ftp.nt.org</code> as 
+<code>coder</code> with password <code>java1</code> and uploads all 
+HTML files in the <code>htdocs/manual</code> directory to the 
+<code>c:\uploads</code> directory.  Progress messages are displayed as each
+file is uploaded.</p>
+<h3>Getting Files</h3>
+<p>Getting files from an FTP server works pretty much the same way as 
+sending them does.  The only difference is that the nested filesets
+use the remotedir attribute as the base directory for the files on the
+FTP server, and the dir attribute as the local directory to put the files
+into.  The file structure from the FTP site is preserved on the local machine.</p>
+<pre>
+  &lt;ftp action="get"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"&gt;
+    &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and 
+recursively downloads all .html files from default directory for that user 
+into the <code>htdocs/manual</code> directory on the local machine.</p>
+<pre>
+  &lt;ftp action="get"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"
+       systemTypeKey="UNIX"
+       defaultDateFormatConfig="yyyy-MM-dd HH:mm"&gt;
+    &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>If apache.org ever switches to a unix FTP server that uses the new all-numeric
+format for timestamps, this version would become necessary.  It would accomplish
+the same functionality as the previous example but would successfully handle the
+numeric timestamps.
+The <code>systemTypeKey</code> is not necessary here but helps clarify what is
+going on.</p>
+<pre>
+  &lt;ftp action="get"
+       server="ftp.hypthetical.fr"
+       userid="anonymous"
+       password="me@myorg.com"
+       defaultDateFormatConfig="d MMM yyyy"
+       recentDateFormatConfig="d MMM HH:mm"
+       serverLanguageCodeConfig="fr"&gt;
+     &lt;fileset dir="htdocs/manual"&gt;
+      &lt;include name="**/*.html"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>Logs into a UNIX FTP server at <code>ftp.hypothetical.fr</code> which displays
+dates with French names in Standard European format, as <code>anonymous</code>, and
+recursively downloads all .html files from default directory for that user
+into the <code>htdocs/manual</code> directory on the local machine.</p>
+
+<h3>Deleting Files</h3>
+As you've probably guessed by now, you use nested fileset elements to 
+select the files to delete from the remote FTP server.  Again, the 
+filesets are relative to the remote directory, not a local directory.  In
+fact, the dir attribute of the fileset is ignored completely.
+
+<pre>
+  &lt;ftp action="del"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"&gt;
+    &lt;fileset&gt;
+      &lt;include name="**/*.tmp"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and
+tries to delete all *.tmp files from the default directory for that user.
+If you don't have permission to delete a file, a BuildException is thrown.</p>
+<h3>Listing Files</h3>
+<pre>
+  &lt;ftp action="list"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"
+       listing="data/ftp.listing"&gt;
+    &lt;fileset&gt;
+      &lt;include name="**"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>This provides a file listing in <code>data/ftp.listing</code> of all the files on
+the FTP server relative to the default directory of the <code>anonymous</code>
+user. The listing is in whatever format the FTP server normally lists files.</p>
+
+<h3>Creating Directories</h3>
+<p>Note that with the mkdir action, the directory to create is specified using the
+remotedir attribute.</p>
+<pre>
+  &lt;ftp action="mkdir"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"
+       remotedir="some/remote/dir"/&gt;
+</pre>
+<p>This creates the directory <code>some/remote/dir</code> beneath the default root
+directory.  As with all other actions, the directory separator character must be correct
+according to the desires of the FTP server.</p>
+<h3>Removing Directories</h3>
+This action uses nested fileset elements to 
+select the directories to remove from the remote FTP server.  The 
+filesets are relative to the remote directory, not a local directory. 
+The dir attribute of the fileset is ignored completely.
+The directories to be removed must be empty, or contain only
+other directories that have been also selected to be removed by the filesets
+patterns, otherwise a BuildException will be thrown.
+Also, if you don't have permission to remove a directory, a BuildException is 
+thrown.
+
+<pre>
+  &lt;ftp action="rmdir"
+       server="ftp.apache.org"
+       userid="anonymous"
+       password="me@myorg.com"
+       remotedir="/somedir" &gt;
+    &lt;fileset&gt;
+      &lt;include name="dira"/&gt;
+      &lt;include name="dirb/**"/&gt;
+    &lt;/fileset&gt;
+  &lt;/ftp&gt;
+</pre>
+<p>Logs in to <code>ftp.apache.org</code> as <code>anonymous</code> and
+tries to remove <code>/somedir/dira</code> directory and
+all the directories tree starting at, and including, <code>/somedir/dirb</code>.
+When removing the <code>/somedir/dirb</code> tree,
+it will start at the leaves moving up to the root, so that when
+it tries to remove a directory it is sure all the directories under it are
+already removed.
+Obviously all the files in the tree must have been already deleted.
+</p>
+<p>As an example suppose you want to delete everything contained into 
+<code>/somedir</code>, so invoke first the <code>&lt;ftp&gt;</code> task with
+<code>action="delete"</code>, then with
+<code>action="rmdir"</code> specifying in both cases
+<code>remotedir="/somedir"</code> and
+
+<pre>
+    &lt;fileset&gt;
+        &lt;include name="**"/&gt;
+    &lt;/fileset&gt;
+</pre>
+
+The directory specified in the <code>remotedir</code> parameter is never
+selected for remove, so if you need to remove it, specify its parent in
+<code>remotedir</code> parameter and include it in the 
+<code>&lt;fileset&gt;</code> pattern, like <code>"somedir/**"</code>.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/ilasm.html b/trunk/docs/manual/OptionalTasks/ilasm.html
new file mode 100644
index 0000000..2cd02f4
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/ilasm.html
@@ -0,0 +1,278 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Ilasm
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Ilasm
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Assembles .NET Intermediate Language files.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Assembles .NET Intermediate Language files. ilasm.exe must be on the execute path, unless another executable or the full path to that executable is specified in the <tt>executable</tt> parameter <p> <p> All parameters are optional: <code>&lt;il/&gt;</code> should suffice to produce a debug build of all *.il files. The option set is roughly compatible with the CSharp class; even though the command line options are only vaguely equivalent. [The low level commands take things like /OUT=file, csc wants /out:file ... /verbose is used some places; /quiet here in ildasm... etc.] It would be nice if someone made all the command line tools consistent (and not as brittle as the java cmdline tools) <p> <p> The task is a directory based task, so attributes like <b>includes="*.il" </b> and <b>excludes="broken.il"</b> can be used to control the files pulled in. You can also use nested &lt;src&gt filesets to refer to source. <p>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">debug</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the debug flag on or off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="10">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the name of exe/library to create.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Any extra options which are not explicitly supported by this task.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, fails if ilasm tool fails.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">keyfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">the name of a file containing a private key.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">listing</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, produce a listing (off by default).</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">outputfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the output file; identical to setDestFile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">resourcefile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">name of resource file to include.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the source directory of the files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">verbose</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, enable verbose ILASM output.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>reference</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new reference fileset to the compilation
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>src</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new source directory to the compile
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/ildasm.html b/trunk/docs/manual/OptionalTasks/ildasm.html
new file mode 100644
index 0000000..113f6be
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/ildasm.html
@@ -0,0 +1,338 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Ildasm
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Ildasm
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Task to take a .NET or Mono -generated managed executable and turn it into ILASM assembly code.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Task to take a .NET or Mono -generated managed executable and turn it into ILASM assembly code. Useful when converting imported typelibs into assembler before patching and recompiling, as one has to do when doing advanced typelib work. <p> As well as generating the named output file, the ildasm program will also generate resource files <code>Icons.resources</code> <code>Message.resources</code> and a .res file whose filename stub is derived from the source in ways to obscure to determine. There is no way to control whether or not these files are created, or where they are created (they are created in the current directory; their names come from inside the executable and may be those used by the original developer). This task creates the resources in the directory specified by <code>resourceDir</code> if set, else in the same directory as the <code>destFile</code>. <p> This task requires the .NET SDK installed and ildasm on the path. To disassemble using alternate CLR systems, set the executable attribute to the name/path of the alternate implementation -one that must support all the classic ildasm commands. <p> Dependency logic: the task executes the command if the output file is missing or older than the source file. It does not take into account changes in the options of the task, or timestamp differences in resource files. When the underlying ildasm executable fails for some reason, it leaves the .il file in place with some error message. To prevent this from confusing the dependency logic, the file specified by the <code>dest</code> attribute is <i>always</i> deleted after an unsuccessful build.
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">assembler</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">enable (default) or disable assembly language in the output</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="17">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">bytes</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">enable or disable (default) the original bytes as comments</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">the output file (required)</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">encoding</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Select the output encoding: ascii, utf8 or unicode</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">"ascii", "utf8", "unicode"</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">executable</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">override the name of the executable (normally ildasm) or set its full path. Do not set a relative path, as the ugly hacks needed to create resource files in the dest directory force us to change to this directory before running the application. i.e use &lt;property location&gt to create an absolute path from a relative one before setting this value.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">header</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">include header information; default false.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">item</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">name a single item to decode; a class or a method e.g item="Myclass::method" or item="namespace1::namespace2::Myclass:method(void(int32))</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">linenumbers</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">include line number information; default=false</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">metadata</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">include metadata information</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">progressbar</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">show a graphical progress bar in a window during the process; off by default</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">quoteallnames</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">quote all names.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">rawexceptionhandling</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">enable raw exception handling (default = false)</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">resourcedir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the name of the directory for resources to be created. We cannot control their names, but we can say where they get created. If not set, the directory of the dest file is used</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">showsource</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">include the source as comments (default=false)</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">sourcefile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">the file to disassemble -required</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">alternate name for sourceFile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">visibility</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">visibility options: one or more of the following, with + signs to concatenate them: <pre> pub : Public pri : Private fam : Family asm : Assembly faa : Family and Assembly foa : Family or Assembly psc : Private Scope </pre> e.g. visibility="pub+pri". Family means <code>protected</code> in C#;</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/image-classdiagram.gif b/trunk/docs/manual/OptionalTasks/image-classdiagram.gif
new file mode 100644
index 0000000..fa4b81e
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/image-classdiagram.gif
Binary files differ
diff --git a/trunk/docs/manual/OptionalTasks/image.html b/trunk/docs/manual/OptionalTasks/image.html
new file mode 100644
index 0000000..c2574cf
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/image.html
@@ -0,0 +1,239 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Image Task</title>
+</head>
+
+<body>
+
+<h2><a name="image">Image</a></h2>
+<h3>Description</h3>
+<p>Applies a chain of image operations on a set of files.</p>
+<p>Requires Java Advanced Image API from Sun.</p>
+
+<h5>Overview of used datatypes</h5>
+<img src="image-classdiagram.gif" border="0" alt="Class-Diagram">
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top"> failonerror </td>
+    <td valign="top"> Boolean value. If false, note errors to the output but keep going. </td>
+    <td align="center"> no (defaults to <i>true</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> srcdir </td>
+    <td valign="top"> Directory containing the images. </td>
+    <td align="center"> yes, unless nested fileset is used </td>
+  </tr>
+  <tr>
+    <td valign="top"> encoding </td>
+    <td valign="top"> Image encoding type. <br>
+      Valid (caseinsensitive) are: jpg, jpeg, tif, tiff
+    </td>
+    <td align="center"> no (defaults to <i>JPEG</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> overwrite </td>
+    <td valign="top"> Boolean value. Sets whether or not to overwrite
+      a file if there is naming conflict.
+    </td>
+    <td align="center"> no (defaults to <i>false</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> gc </td>
+    <td valign="top"> Boolean value. Enables garbage collection after
+      each image processed.
+    </td>
+    <td align="center"> no (defaults to <i>false</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> destdir </td>
+    <td valign="top"> Directory where the result images are stored. </td>
+    <td align="center"> no (defaults to value of <i>srcdir</i>) </td>
+  </tr>
+  <!-- attributes inherited from MatchingTask -->
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top"> excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top"> caseSensitive </td>
+    <td valign="top"> Boolean value. Sets case sensitivity of the file system. </td>
+    <td align="center"> no (defaults to <i>false</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> followSymlinks </td>
+    <td valign="top"> Boolean value. Sets whether or not symbolic links should be followed. </td>
+    <td align="center"> no (defaults to <i>true</i>) </td>
+  </tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code> as well as the
+nested <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+
+
+<h4>ImageOperation</h4>
+<p>Adds an ImageOperation to chain.</p>
+<h5>Nested Elements</h5>
+ImageOperation can handle nested Rotate, Draw, Rectangle, Text and Scale objects.
+
+<h4>Rotate</h4>
+<p>Adds a Rotate ImageOperation to chain.</p>
+<h5>Parameters</h5>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top"> angle </td>
+    <td valign="top"> Float value. Sets the angle of rotation in degrees. </td>
+    <td align="center"> no (defaults to <i>0.0F</i>) </td>
+  </tr>
+</table>
+
+<h4>Scale</h4>
+<p>Adds a Scale ImageOperation to chain.</p>
+<h5>Parameters</h5>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+    <td valign="top"> proportions </td>
+    <td valign="top"> Sets which dimension to control proportions from. Valid values are:<ul>
+        <li>&quot;ignore&quot; -  treat the dimensions independently.</li>
+        <li>&quot;height&quot; - keep proportions based on the width.</li>
+        <li>&quot;width&quot; - keep proportions based on the height.</li>
+        <li>&quot;cover&quot; - keep proportions and fit in the supplied dimensions.</li>
+        <li>&quot;fit&quot; - keep proportions and cover the supplied dimensions.</li>
+    </ul></td>
+    <td align="center"> no (defaults to <i>ignore</i>) </td>
+  <tr>
+    <td valign="top"> width </td>
+    <td valign="top"> Sets the width of the image, either as an integer or a %. </td>
+        <!-- todo: if integer, what kind? cm, px, inches, ... -->
+    <td align="center"> no (defaults to <i>100%</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> height </td>
+    <td valign="top"> Sets the height of the image, either as an integer or a %. </td>
+        <!-- todo: if integer, what kind? cm, px, inches, ... -->
+    <td align="center"> no (defaults to <i>100%</i>) </td>
+  </tr>
+</table>
+
+<h4>Draw</h4>
+<p>Adds a Draw ImageOperation to chain. DrawOperation DataType objects can be
+nested inside the Draw object.</p>
+<h5>Parameters</h5>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top"> xloc </td>
+    <td valign="top"> X-Position where to draw nested image elements. </td>
+    <td align="center"> no (defaults to <i>0</i>) </td>
+  </tr>
+  <tr>
+    <td valign="top"> yloc </td>
+    <td valign="top"> Y-Position where to draw nested image elements. </td>
+    <td align="center"> no (defaults to <i>0</i>) </td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+<blockquote><pre>
+&nbsp;&lt;image destdir="samples/low" overwrite="yes"&gt;
+&nbsp;&nbsp;&nbsp;&nbsp; &lt;fileset dir="samples/full"&gt;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;include name="**/*.jpg"/&gt;
+&nbsp;&nbsp;&nbsp;&nbsp; &lt;/fileset&gt;
+&nbsp;&nbsp;&nbsp;&nbsp; &lt;scale width="160" height="160" proportions="fit"/&gt;
+&nbsp;&lt;/image&gt;
+</pre></blockquote>
+<p>Create thumbnails of my images and make sure they all fit within the 160x160 size whether the
+image is portrait or landscape.</p>
+
+<blockquote><pre>
+&lt;image srcdir="src" includes="*.png"&gt;
+    &lt;scale proportions="width" width="40"/&gt;
+&lt;/image&gt;
+</pre></blockquote>
+<p>Creates a thumbnail for all PNG-files in <i>src</i> in the size of 40 pixel keeping the proportions
+and stores the <i>src</i>.</p>
+
+<blockquote><pre>
+&lt;image srcdir="src" destdir="dest" includes="*.png"&gt;
+    &lt;scale proportions="width" width="40"/&gt;
+&lt;/image&gt;
+</pre></blockquote>
+<p>Same as above but stores the result in <i>dest</i>.</p>
+
+<blockquote><pre>
+</pre></blockquote>
+
+
+
+</body>
+</html>
+
+
diff --git a/trunk/docs/manual/OptionalTasks/importtypelib.html b/trunk/docs/manual/OptionalTasks/importtypelib.html
new file mode 100644
index 0000000..12292b6
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/importtypelib.html
@@ -0,0 +1,206 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Importtypelib
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Importtypelib
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Import a COM type library into the .NET framework.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Import a COM type library into the .NET framework. <p> This task is a wrapper to .NET's tlbimport; it imports a tlb file to a NET assembly by generating a binary assembly (.dll) that contains all the binding metadata. It uses date timestamps to minimise rebuilds. <p> Example <pre> &lt;importtypelib srcfile="xerces.tlb" destfile="xerces.dll" namespace="Apache.Xerces"/&gt; </pre>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">name the output file. required</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="6">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set any extra options that are not yet supported by this task.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">namespace</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">what namespace is the typelib to be in. required</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">what is the source .tlb file? required.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">unsafe</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">do you want unsafe code.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">usesysarray</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set this to map a COM SafeArray to the System.Array class</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/jarlib-available.html b/trunk/docs/manual/OptionalTasks/jarlib-available.html
new file mode 100644
index 0000000..c71732c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jarlib-available.html
@@ -0,0 +1,135 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>jarlib-available Task</title>
+</head>
+
+<body>
+
+<h2><a name="jarlib-available">jarlib-available</a></h2>
+<h3>Description</h3>
+<p>Check whether an extension is present in a fileset or an extensionSet.
+If the extension is present then a property is set.</p>
+
+<p>Note that this task
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+<p>See the Extension and ExtensionSet documentation for further details</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of property to set if extensions is available.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to check for extension</td>
+    <td valign="top" align="center">No, one of file, nested
+    ExtensionSet or nested fileset must be present.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>extension</h4>
+ <p><a href="../OptionalTypes/extension.html">Extension</a> the extension
+ to search for.</p>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select
+sets of files to check for extension.</p>
+
+<h4>extensionSet</h4>
+ <p><a href="../OptionalTypes/extensionset.html">ExtensionSet</a>s is the set
+ of extensions to search for extension in.</p>
+
+<h3>Examples</h3>
+<p><b>Search for extension in single file</b></p>
+<pre>
+  &lt;jarlib-available property=&quot;myext.present&quot; file=&quot;myfile.jar&quot;&gt;
+    &lt;extension
+      extensionName=&quot;org.apache.tools.ant&quot;
+      specificationVersion=&quot;1.4.9&quot;
+      specificationVendor=&quot;Apache Software Foundation&quot;/&gt;
+  &lt;/jarlib-available&gt;
+</pre>
+
+<p><b>Search for extension in single file referencing external Extension</b></p>
+<pre>
+  &lt;extension id=&quot;myext&quot;
+    extensionName=&quot;org.apache.tools.ant&quot;
+    specificationVersion=&quot;1.4.9&quot;
+    specificationVendor=&quot;Apache Software Foundation&quot;/&gt;
+
+  &lt;jarlib-available property=&quot;myext.present&quot; file=&quot;myfile.jar&quot;&gt;
+    &lt;extension refid=&quot;myext&quot;/&gt;
+  &lt;/jarlib-available&gt;
+</pre>
+<p><b>Search for extension in fileset</b></p>
+<pre>
+  &lt;extension id=&quot;myext&quot;
+    extensionName=&quot;org.apache.tools.ant&quot;
+    specificationVersion=&quot;1.4.9&quot;
+    specificationVendor=&quot;Apache Software Foundation&quot;/&gt;
+
+  &lt;jarlib-available property=&quot;myext.present&quot;&gt;
+    &lt;extension refid=&quot;myext&quot;/&gt;
+    &lt;fileset dir="lib"&gt;
+      &lt;include name="*.jar"/&gt;
+    &lt;/fileset&gt;
+  &lt;/jarlib-available&gt;
+</pre>
+<p><b>Search for extension in extensionSet</b></p>
+<pre>
+  &lt;extension id=&quot;myext&quot;
+    extensionName=&quot;org.apache.tools.ant&quot;
+    specificationVersion=&quot;1.4.9&quot;
+    specificationVendor=&quot;Apache Software Foundation&quot;/&gt;
+
+  &lt;jarlib-available property=&quot;myext.present&quot;&gt;
+    &lt;extension refid=&quot;myext&quot;/&gt;
+    &lt;extensionSet id=&quot;exts3&quot;&gt;
+      &lt;libfileset
+        includeUrl=&quot;false&quot;
+        includeImpl=&quot;true&quot;
+        dir=&quot;lib&quot;&gt;
+        &lt;include name=&quot;*.jar&quot;/&gt;
+      &lt;/libfileset&gt;
+    &lt;/extensionSet&gt;
+  &lt;/jarlib-available&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/jarlib-display.html b/trunk/docs/manual/OptionalTasks/jarlib-display.html
new file mode 100644
index 0000000..82bfff2
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jarlib-display.html
@@ -0,0 +1,81 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>jarlib-display Task</title>
+</head>
+
+<body>
+
+<h2><a name="jarlib-display">jarlib-display</a></h2>
+<h3>Description</h3>
+<p>Display the "Optional Package" and "Package Specification" information
+ contained within the specified jars.</p>
+
+<p>Note that this task
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+<p>See the Extension and ExtensionSet documentation for further details</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to display extension information about.</td>
+    <td valign="top" align="center">No, but one of file or fileset must be
+    present.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s contain list of files to
+ display Extension information  about.</p>
+
+<h3>Examples</h3>
+<p><b>Display Extension info for a single file</b></p>
+<pre>
+  &lt;jarlib-display file=&quot;myfile.jar&quot;&gt;
+</pre>
+
+<p><b>Display Extension info for a fileset</b></p>
+<pre>
+  &lt;jarlib-display&gt;
+    &lt;fileset dir="lib"&gt;
+      &lt;include name="*.jar"/&gt;
+    &lt;/fileset&gt;
+  &lt;/jarlib-display&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/jarlib-manifest.html b/trunk/docs/manual/OptionalTasks/jarlib-manifest.html
new file mode 100644
index 0000000..dadda50
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jarlib-manifest.html
@@ -0,0 +1,124 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>jarlib-manifest Task</title>
+</head>
+
+<body>
+
+<h2><a name="jarlib-manifest">jarlib-manifest</a></h2>
+<h3>Description</h3>
+<p>Task to generate a manifest that declares all the dependencies
+ in manifest. The dependencies are determined by looking in the
+ specified path and searching for Extension / "Optional Package"
+ specifications in the manifests of the jars.</p>
+
+<p>Note that this task
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+<p>See the Extension and ExtensionSet documentation for further details</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">The file to generate Manifest into</td>
+    <td valign="top" align="center">Yes.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>extension</h4>
+ <p><a href="../OptionalTypes/extension.html">Extension</a> the extension
+ that this library implements.</p>
+
+<h4>depends</h4>
+ <p><a href="../OptionalTypes/extensionset.html">ExtensionSet</a>s containing
+ all dependencies for jar.</p>
+
+<h4>options</h4>
+ <p><a href="../OptionalTypes/extensionset.html">ExtensionSet</a>s containing
+ all optional dependencies for jar. (Optional dependencies will be used if
+ present else they will be ignored)</p>
+
+<h3>Examples</h3>
+<p><b>Basic Manifest generated for single Extension</b></p>
+<pre>
+&lt;extension id=&quot;e1&quot;
+    extensionName=&quot;MyExtensions&quot;
+    specificationVersion=&quot;1.0&quot;
+    specificationVendor=&quot;Peter Donald&quot;
+    implementationVendorID=&quot;vv&quot;
+    implementationVendor=&quot;Apache&quot;
+    implementationVersion=&quot;2.0&quot;
+    implementationURL=&quot;http://somewhere.com&quot;/&gt;
+
+&lt;jarlib-manifest destfile=&quot;myManifest.txt&quot;&gt;
+    &lt;extension refid=&quot;e1&quot;/&gt;
+&lt;/jarlib-manifest&gt;
+</pre>
+
+<p><b>Search for extension in fileset</b></p>
+<p><b>A large example with required and optional dependencies</b></p>
+<pre>
+&lt;extension id=&quot;e1&quot;
+    extensionName=&quot;MyExtensions&quot;
+    specificationVersion=&quot;1.0&quot;
+    specificationVendor=&quot;Peter Donald&quot;
+    implementationVendorID=&quot;vv&quot;
+    implementationVendor=&quot;Apache&quot;
+    implementationVersion=&quot;2.0&quot;
+    implementationURL=&quot;http://somewhere.com&quot;/&gt;
+
+&lt;extensionSet id=&quot;option.ext&quot;&gt;
+    &lt;libfileset dir=&quot;lib/option&quot;&gt;
+        &lt;include name=&quot;**/*.jar&quot;/&gt;
+    &lt;/libfileset&gt;
+&lt;/extensionSet&gt;
+
+&lt;extensionSet id=&quot;depends.ext&quot;&gt;
+    &lt;libfileset dir=&quot;lib/required&quot;&gt;
+        &lt;include name=&quot;*.jar&quot;/&gt;
+    &lt;/libfileset&gt;
+&lt;/extensionSet&gt;
+
+&lt;jarlib-manifest destfile=&quot;myManifest.txt&quot;&gt;
+    &lt;extension refid=&quot;e1&quot;/&gt;
+    &lt;depends refid=&quot;depends.ext&quot;/&gt;
+    &lt;options refid=&quot;option.ext&quot;/&gt;
+&lt;/jarlib-manifest&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/jarlib-resolve.html b/trunk/docs/manual/OptionalTasks/jarlib-resolve.html
new file mode 100644
index 0000000..c6e0835
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jarlib-resolve.html
@@ -0,0 +1,212 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>jarlib-resolve Task</title>
+</head>
+
+<body>
+
+<h2><a name="jarlib-resolve">jarlib-resolve</a></h2>
+<h3>Description</h3>
+<p>Try to locate a jar to satisfy an extension and place
+ location of jar into property. The task allows you to
+ add a number of resolvers that are capable of locating a
+ library for a specific extension. Each resolver will be attempted
+ in specified order until library is found or no resolvers are left.
+ If no resolvers are left and failOnError is true then a BuildException
+ will be thrown.</p>
+
+<p>Note that this task
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+<p>See the Extension and ExtensionSet documentation for further details</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The name of property to set to library location.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">failOnError</td>
+    <td valign="top">True if failure to locate library should result in build exception.</td>
+    <td valign="top" align="center">No, defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">checkExtension</td>
+    <td valign="top">True if libraries returned by nested resolvers should be checked to see if
+    they supply extension.</td>
+    <td valign="top" align="center">No, defaults to true.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>extension</h4>
+ <p><a href="../OptionalTypes/extension.html">Extension</a> the extension
+ to resolve. Must be present</p>
+
+<h4>location</h4>
+ <p>The location sub element allows you to look for a library in a
+ location relative to project directory.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">The pathname of library.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>url</h4>
+ <p>The url resolver allows you to download a library from a URL to a
+ local file.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">The URL to download.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">The file to download URL into.</td>
+    <td valign="top" align="center">No, But one of destfile or
+    destdir must be present</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">The directory in which to place downloaded file.</td>
+    <td valign="top" align="center">No, But one of destfile or
+    destdir must be present</td>
+  </tr>
+</table>
+
+<h4>ant</h4>
+ <p>The ant resolver allows you to run a ant build file to generate a library.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">antfile</td>
+    <td valign="top">The build file.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">destfile</td>
+    <td valign="top">The file that the ant build creates.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">The target to run in build file.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<p><b>Resolve Extension to file.</b> If file does not exist or file
+   does not implement extension then throw an exception.</p>
+<pre>
+  &lt;extension id=&quot;dve.ext&quot;
+    extensionName=&quot;org.realityforge.dve&quot;
+    specificationVersion=&quot;1.2&quot;
+    specificationVendor=&quot;Peter Donald&quot;/&gt;
+
+  &lt;jarlib-resolve property="dve.library"&gt;
+    &lt;extension refid="dve.ext"/&gt;
+    &lt;location location="/opt/jars/dve.jar"/&gt;
+  &lt;/jarlib-resolve&gt;
+</pre>
+
+<p><b>Resolve Extension to url.</b> If url does not exist or can not write
+   to destfile or files does not implement extension then throw an exception.</p>
+<pre>
+  &lt;extension id=&quot;dve.ext&quot;
+    extensionName=&quot;org.realityforge.dve&quot;
+    specificationVersion=&quot;1.2&quot;
+    specificationVendor=&quot;Peter Donald&quot;/&gt;
+
+  &lt;jarlib-resolve property="dve.library"&gt;
+    &lt;extension refid="dve.ext"/&gt;
+    &lt;url url="http://www.realityforge.net/jars/dve.jar" destfile="lib/dve.jar"/&gt;
+  &lt;/jarlib-resolve&gt;
+</pre>
+
+<p><b>Resolve Extension to file produce by ant build.</b> If file does not get produced
+   or ant file is missing or build fails then throw an exception (Note does not check
+   that library implements extension).</p>
+<pre>
+  &lt;extension id=&quot;dve.ext&quot;
+    extensionName=&quot;org.realityforge.dve&quot;
+    specificationVersion=&quot;1.2&quot;
+    specificationVendor=&quot;Peter Donald&quot;/&gt;
+
+  &lt;jarlib-resolve property="dve.library" checkExtension="false"&gt;
+    &lt;extension refid="dve.ext"/&gt;
+    &lt;ant antfile="../dve/build.xml" target="main" destfile="lib/dve.jar"/&gt;
+  &lt;/jarlib-resolve&gt;
+</pre>
+
+<p><b>Resolve Extension via multiple methods.</b> First check local file to see if it implements
+  extension. If it does not then try to build it from source in parallel directory. If that
+  fails then finally try to download it from a website. If all steps fail then throw a build
+  exception.</p>
+<pre>
+  &lt;extension id=&quot;dve.ext&quot;
+    extensionName=&quot;org.realityforge.dve&quot;
+    specificationVersion=&quot;1.2&quot;
+    specificationVendor=&quot;Peter Donald&quot;/&gt;
+
+  &lt;jarlib-resolve property="dve.library"&gt;
+    &lt;extension refid="dve.ext"/&gt;
+    &lt;location location="/opt/jars/dve.jar"/&gt;
+    &lt;ant antfile="../dve/build.xml" target="main" destfile="lib/dve.jar"/&gt;
+    &lt;url url="http://www.realityforge.net/jars/dve.jar" destfile="lib/dve.jar"/&gt;
+  &lt;/jarlib-resolve&gt;
+</pre>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/javacc.html b/trunk/docs/manual/OptionalTasks/javacc.html
new file mode 100644
index 0000000..63b460c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/javacc.html
@@ -0,0 +1,204 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JavaCC Task</title>
+</head>
+
+<body>
+
+<h2><a name="javacc">JavaCC</a></h2>
+<h3>Description</h3>
+<p>
+  Invokes the <a HREF="http://javacc.dev.java.net/" target="_top">JavaCC</a> compiler
+  compiler on a grammar file.
+</p>
+<p>
+  To use the javacc task, set the <i>target</i> attribute to the name of the
+  grammar file to process.  You also need to specify the directory containing
+  the JavaCC installation using the <i>javacchome</i> attribute, so that ant
+  can find the JavaCC classes.  Optionally, you can also set the
+  <i>outputdirectory</i> to write the generated file to a specific directory.
+  Otherwise javacc writes the generated files to the directory containing
+  the grammar file.
+</p>
+<p>
+  This task only invokes JavaCC if the grammar file is newer than the generated
+  Java files.  javacc assumes that the Java class name of the generated parser
+  is the same as the name of the grammar file, ignoring the .jj.
+  If this is not the case, the javacc task will still work, but it will always
+  generate the output files.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">target</td>
+    <td valign="top">The grammar file to process.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">javacchome</td>
+    <td valign="top">The directory containing the JavaCC distribution.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">outputdirectory</td>
+    <td valign="top">
+      The directory to write the generated files to.  If not set, the files
+      are written to the directory containing the grammar file.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">buildparser</td>
+    <td valign="top">Sets the BUILD_PARSER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">buildtokenmanager</td>
+    <td valign="top">Sets the BUILD_TOKEN_MANAGER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">cachetokens</td>
+    <td valign="top">Sets the CACHE_TOKENS grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">choiceambiguitycheck</td>
+    <td valign="top">Sets the CHOICE_AMBIGUITY_CHECK grammar option.  This is an integer option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">commontokenaction</td>
+    <td valign="top">Sets the COMMON_TOKEN_ACTION grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debuglookahead</td>
+    <td valign="top">Sets the DEBUG_LOOKAHEAD grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debugparser</td>
+    <td valign="top">Sets the DEBUG_PARSER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">debugtokenmanager</td>
+    <td valign="top">Sets the DEBUG_TOKEN_MANAGER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">errorreporting</td>
+    <td valign="top">Sets the ERROR_REPORTING grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">forcelacheck</td>
+    <td valign="top">Sets the FORCE_LA_CHECK grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">ignorecase</td>
+    <td valign="top">Sets the IGNORE_CASE grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">javaunicodeescape</td>
+    <td valign="top">Sets the JAVA_UNICODE_ESCAPE grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">jdkversion</td>
+    <td valign="top">Sets the JDK_VERSION option. This is a string option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>  <tr>
+    <td valign="top">keeplinecolumn</td>
+    <td valign="top">Sets the KEEP_LINE_COLUMN grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">lookahead</td>
+    <td valign="top">Sets the LOOKAHEAD grammar option.  This is an integer option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">optimizetokenmanager</td>
+    <td valign="top">Sets the OPTIMIZE_TOKEN_MANAGER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">otherambiguitycheck</td>
+    <td valign="top">Sets the OTHER_AMBIGUITY_CHECK grammar option.  This is an integer option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sanitycheck</td>
+    <td valign="top">Sets the SANITY_CHECK grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">static</td>
+    <td valign="top">Sets the STATIC grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unicodeinput</td>
+    <td valign="top">Sets the UNICODE_INPUT grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">usercharstream</td>
+    <td valign="top">Sets the USER_CHAR_STREAM grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">usertokenmanager</td>
+    <td valign="top">Sets the USER_TOKEN_MANAGER grammar option.  This is a boolean option.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Example</h3>
+<blockquote><pre>
+&lt;javacc
+    target=&quot;src/Parser.jj&quot;
+    outputdirectory=&quot;build/src&quot;
+    javacchome=&quot;c:/program files/JavaCC&quot;
+    static=&quot;true&quot;
+/&gt;
+</pre></blockquote>
+<p>
+  This invokes JavaCC on grammar file src/Parser.jj, writing the generated
+  files to build/src.  The grammar option STATIC is set to true when
+  invoking JavaCC.
+</p>
+
+
+</body>
+</html>
+
+
diff --git a/trunk/docs/manual/OptionalTasks/javah.html b/trunk/docs/manual/OptionalTasks/javah.html
new file mode 100644
index 0000000..36ebb8a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/javah.html
@@ -0,0 +1,192 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Javah Task</title>
+</head>
+
+<body>
+
+<h2><a name="javah">Javah</a></h2>
+<h3>Description</h3>
+<p>Generates JNI headers from a Java class.</p>
+<p> When this task executes, it will generate the C header and source files that
+are needed to implement native methods. JNI operates differently depending on
+whether <a href="http://java.sun.com/j2se/1.3/docs/tooldocs/win32/javah.html">JDK1.2</a>
+(or later) or <a href="http://java.sun.com/products/jdk/1.1/docs/tooldocs/win32/javah.html">pre-JDK1.2</a>
+systems are used.</p>
+
+<p>It is possible to use different compilers. This can be selected
+with the <code>implementation</code> attribute.  <a
+name="implementationvalues">Here are the choices</a>:</p>
+<ul>
+  <li>default - the default compiler (kaffeh or sun) for the platform.</li>
+  <li>sun (the standard compiler of the JDK)</li>
+  <li>kaffeh (the native standard compiler of <a href="http://www.kaffe.org" target="_top">Kaffe</a>)</li>
+</ul>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="center"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">class</td>
+    <td valign="top">the fully-qualified name of the class (or classes,
+      separated by commas)</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">outputFile</td>
+    <td valign="top">concatenates the resulting header or source files for all the classes listed into this file</td>
+    <td align="center" valign="middle" rowspan="2">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">sets the directory where javah saves the header files or the
+      stub files.</td>
+  </tr>
+  <tr>
+    <td valign="top">force</td>
+    <td valign="top">specifies that output files should always be written (JDK1.2 only)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">old</td>
+    <td valign="top">specifies that old JDK1.0-style header files should be generated
+      (otherwise output file contain JNI-style native method      function prototypes) (JDK1.2 only)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">stubs</td>
+    <td valign="top">generate C declarations from the Java object file (used with old)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">causes Javah to print a message concerning the status     of the generated files</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">the classpath to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bootclasspath</td>
+    <td valign="top">location of bootstrap class files.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">extdirs</td>
+    <td valign="top"> location of installed extensions.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">implementation</td>
+    <td valign="top">The compiler implementation to use.  If this
+    attribute is not set, the default compiler for the current VM
+    will be used.  (See the above <a
+    href="#implementationvalues">list</a> of valid compilers.)</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<p>Either outputFile or destdir must be supplied, but not both.&nbsp;</p>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>arg</h4>
+
+<p>You can specify additional command line arguments for the compiler
+with nested <code>&lt;arg&gt;</code> elements.  These elements are
+specified like <a href="../using.html#arg">Command-line Arguments</a>
+but have an additional attribute that can be used to enable arguments
+only if a given compiler implementation will be used.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">value</td>
+    <td align="center" rowspan="4">See
+    <a href="../using.html#arg">Command-line Arguments</a>.</td>
+    <td align="center" rowspan="4">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">line</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+  </tr>
+  <tr>
+    <td valign="top">implementation</td>
+    <td>Only pass the specified argument if the chosen compiler
+    implementation matches the value of this attribute.  Legal values
+    are the same as those in the above <a
+    href="#implementationvalues">list</a> of valid compilers.)</td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>  &lt;javah destdir=&quot;c&quot; class=&quot;org.foo.bar.Wibble&quot;/&gt;</pre>
+<p>makes a JNI header of the named class, using the JDK1.2 JNI model. Assuming
+the directory 'c' already exists, the file <tt>org_foo_bar_Wibble.h</tt>
+is created there. If this file already exists, it is left unchanged.</p>
+<pre>  &lt;javah outputFile=&quot;wibble.h&quot;&gt;
+    &lt;class name=&quot;org.foo.bar.Wibble,org.foo.bar.Bobble&quot;/&gt;
+  &lt;/javah&gt;</pre>
+<p>is similar to the previous example, except the output is written to a file
+called <tt>wibble.h</tt>
+in the current directory.</p>
+<pre>  &lt;javah destdir=&quot;c&quot; force=&quot;yes&quot;&gt;
+    &lt;class name=&quot;org.foo.bar.Wibble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Bobble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Tribble&quot;/&gt;
+  &lt;/javah&gt;</pre>
+<p>writes three header files, one for each of the classes named. Because the
+force option is set, these header files are always written when the Javah task
+is invoked, even if they already exist.</p>
+<pre>  &lt;javah destdir=&quot;c&quot; verbose=&quot;yes&quot; old=&quot;yes&quot; force=&quot;yes&quot;&gt;
+    &lt;class name=&quot;org.foo.bar.Wibble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Bobble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Tribble&quot;/&gt;
+  &lt;/javah&gt;
+  &lt;javah destdir=&quot;c&quot; verbose=&quot;yes&quot; stubs=&quot;yes&quot; old=&quot;yes&quot; force=&quot;yes&quot;&gt;
+    &lt;class name=&quot;org.foo.bar.Wibble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Bobble&quot;/&gt;
+    &lt;class name=&quot;org.foo.bar.Tribble&quot;/&gt;
+  &lt;/javah&gt;</pre>
+<p>writes the headers for the three classes using the 'old' JNI format, then
+writes the corresponding .c stubs. The verbose option will cause Javah to
+describe its progress.</p>
+
+
+</body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/jdepend.html b/trunk/docs/manual/OptionalTasks/jdepend.html
new file mode 100644
index 0000000..fd8f94a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jdepend.html
@@ -0,0 +1,177 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+
+<html>
+<head>
+   <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JDepend Task</title>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta http-equiv="Content-Language" content="en-us">
+</head>
+
+<body>
+
+<h2><a NAME="JDepend"></a>JDepend</h2>
+
+<h3>Description</h3>
+
+<P>Invokes the <a href="http://www.clarkware.com/software/JDepend.html">JDepend</a> parser.</P>
+
+<P>This parser &quot;traverses a set of Java source file directories and generates design quality metrics for each Java package&quot;.
+It allows to &quot;automatically measure the quality of a design in terms of its extensibility, reusability, and maintainability to
+effectively manage and control package dependencies.&quot;</P>
+
+<p>Source file directories are defined by nested
+<code>&lt;sourcespath&gt;</code>; Class file directories are defined
+by nested <code>&lt;classesespath&gt;</code>, see <a
+href="#nested">nested elements</a>.</p>
+
+<p>Optionally, you can also set the <code>outputfile</code> name where the output is stored. By default the task writes its report to the standard output.</P>
+
+<p> The task requires at least the JDepend 1.2 version. </p>
+
+<h3>Parameters</h3>
+
+<table BORDER=1 CELLSPACING=0 CELLPADDING=2 >
+  <tr>
+    <td VALIGN=TOP><b>Attribute</b></td>
+    <td VALIGN=TOP><b>Description</b></td>
+    <td ALIGN=CENTER VALIGN=TOP><b>Required</b></td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>outputfile</td>
+    <td VALIGN=TOP>The output file name. If not set, the output is printed on the standard output.</td>
+    <td ALIGN=CENTER VALIGN=TOP>No</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>format</td>
+    <td VALIGN=TOP>The format to write the output in. The default is "text", the alternative is "xml"</td>
+    <td ALIGN=CENTER VALIGN=TOP>No</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>fork</td>
+    <td VALIGN=TOP>Run the tests in a separate VM.</td>
+    <td ALIGN=CENTER VALIGN=TOP>No, default is "off"</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>haltonerror</td>
+    <td VALIGN=TOP>Stop the build process if an error occurs during the jdepend analysis.</td>
+    <td ALIGN=CENTER VALIGN=TOP>No, default is "off"</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>timeout</td>
+    <td VALIGN=TOP>Cancel the operation if it doesn't finish in the given time (measured in milliseconds). (Ignored if fork is disabled.)</td>
+    <td ALIGN=CENTER VALIGN=TOP>No</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>jvm</td>
+    <td VALIGN=TOP>The command used to invoke the Java Virtual Machine, default is 'java'. The command is resolved by java.lang.Runtime.exec(). (Ignored if fork is disabled.)</td>
+    <td ALIGN=CENTER VALIGN=TOP>No, default "java"</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>dir</td>
+    <td VALIGN=TOP>The directory to invoke the VM in. (Ignored if fork is disabled)</td>
+    <td ALIGN=CENTER VALIGN=TOP>No</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>includeruntime</td>
+    <td VALIGN=TOP>Implicitly add the classes required to run jdepend
+    in forked mode. (Ignored if fork is disabled). Since ant 1.6.</td>
+    <td ALIGN=CENTER VALIGN=TOP>No, default is "no".</td>
+  </tr>
+  <tr>
+    <td VALIGN=TOP>classpathref</td>
+    <td VALIGN=TOP>the classpath to use, given as reference to a PATH defined elsewhere.</td>
+    <td ALIGN=CENTER VALIGN=TOP>No</td>
+  </tr>
+</table>
+
+<h3><a name="nested">Nested Elements</a></h3>
+
+<p><code>jdepend</code> supports four nested elements:
+<code>&lt;classpath&gt;, &lt;classespath&gt; </code> and
+<code>&lt;sourcespath&gt;</code>, that represent <a
+href="../using.html#path">PATH like structures</a>, and
+<code>&lt;exclude&gt;</code>.</p>
+
+<p><code>&lt;sourcespath&gt;</code> is used to define the paths of the
+source code to analyze, but it is deprecated. With version 2.5 of
+JDepend, only class files are analyzed. The nested element
+<code>&lt;classespath&gt;</code> replaces <code>&lt;sourcespath&gt;</code> and is used to define
+the paths of compiled class code to analyze; the <code>&lt;sourcespath&gt;</code>
+variable is still available in case you are using an earlier version
+of JDepend.  The <code>&lt;exclude&gt;</code> element can be used to set packages
+to ignore (requires JDepend 2.5 or above).</p>
+
+<h3>Examples</h3>
+
+<blockquote>
+<pre>
+&lt;jdepend classpathref="base.path"&gt;
+&nbsp;&nbsp;&nbsp; &lt;classespath&gt;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;pathelement location="build"/&gt;
+&nbsp;&nbsp;&nbsp; &lt;/classespath&gt;
+&lt;/jdepend&gt;
+
+</pre>
+</blockquote>
+
+<p>This invokes JDepend on the <code>build</code> directory, writing
+the output on the standard output. The classpath is defined using a
+classpath reference.</p>
+
+<blockquote>
+<pre>
+&lt;jdepend outputfile="docs/jdepend.xml" fork="yes" format="xml"&gt;
+&nbsp;&nbsp;&nbsp; &lt;sourcespath&gt;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;pathelement location="src"/&gt;
+&nbsp;&nbsp;&nbsp; &lt;/sourcespath&gt;
+&nbsp;&nbsp;&nbsp; &lt;classpath&gt;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;pathelement location="classes"/&gt;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;pathelement location="lib/jdepend.jar"/&gt;
+&nbsp;&nbsp;&nbsp; &lt;/classpath&gt;
+&lt;/jdepend&gt;
+</pre>
+</blockquote>
+
+<p>This invokes JDepend in a separate VM on the <code>src</code> and
+<code>testsrc</code> directories, writing the output to the
+<code>&lt;docs/jdepend.xml&gt;</code> file in xml format. The
+classpath is defined using nested elements. </p>
+
+<blockquote>
+<pre>
+&lt;jdepend classpathref="base.path"&gt;
+&nbsp;&nbsp;&nbsp; &lt;exclude name="java.*&gt;
+&nbsp;&nbsp;&nbsp; &lt;exclude name="javax.*&gt;
+&nbsp;&nbsp;&nbsp; &lt;classespath&gt;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;pathelement location="build"/&gt;
+&nbsp;&nbsp;&nbsp; &lt;/classespath&gt;
+&lt;/jdepend&gt;
+</pre>
+</blockquote>
+
+<p>This invokes JDepend with the build directory as the base for class
+files to analyze, and will ignore all classes in the java.* and
+javax.* packages.</p>
+
+
+</body>
+</html>
+
+
diff --git a/trunk/docs/manual/OptionalTasks/jjdoc.html b/trunk/docs/manual/OptionalTasks/jjdoc.html
new file mode 100644
index 0000000..a0349d3
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jjdoc.html
@@ -0,0 +1,116 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta http-equiv="Content-Language" content="en-us">
+   <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JJDoc Task</title>
+</head>
+<body>
+
+<h2>
+<a NAME="jjtree"></a>JJDoc</h2>
+<p><em>Since Ant 1.6</em></p>
+<h3>Description</h3>
+
+<p>Invokes the <a href="http://javacc.dev.java.net/">JJDoc</a> preprocessor
+for the JavaCC compiler compiler. It takes a JavaCC parser specification
+and produces documentation for the BNF grammar.
+It can operate in three modes, determined by command line options.
+<p>To use the jjdoc task, set the <i>target</i> attribute to the name
+of the JavaCC grammar file to process. You also need to specify the directory
+containing the JavaCC installation using the <i>javacchome</i> attribute,
+so that ant can find the JavaCC classes. Optionally, you can also set the
+<i>outputfile</i> to write the generated BNF documentation file to a specific (directory and) file.
+Otherwise jjdoc writes the generated BNF documentation file as the JavaCC
+grammar file with a suffix .txt or .html.</p>
+<p>This task only invokes JJDoc if the grammar file is newer than the
+generated BNF documentation file.</p>
+
+<h3>Parameters</h3>
+
+<table BORDER CELLSPACING=0 CELLPADDING=2 >
+<tr>
+<td VALIGN=TOP><b>Attribute</b></td>
+
+<td VALIGN=TOP><b>Description</b></td>
+
+<td ALIGN=CENTER VALIGN=TOP><b>Required</b></td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>target</td>
+
+<td VALIGN=TOP>The javacc grammar file to process.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>Yes</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>javacchome</td>
+
+<td VALIGN=TOP>The directory containing the JavaCC distribution.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>Yes</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>outputfile</td>
+
+<td VALIGN=TOP>The file to write the generated BNF documentation file to. If not set,
+the file is written with the same name as the JavaCC grammar file but with a the suffix .html or .txt.&nbsp;</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>text</td>
+
+<td VALIGN=TOP>Sets the TEXT BNF documentation option. This is a boolean
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>onetable</td>
+
+<td VALIGN=TOP>Sets the ONE_TABLE BNF documentation option. This is a boolean option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+</table>
+
+<h3>
+Example</h3>
+
+<blockquote>
+<pre>&lt;jjdoc&nbsp;
+&nbsp;&nbsp;&nbsp; target="src/Parser.jj"&nbsp;
+&nbsp;&nbsp;&nbsp; outputfile="doc/ParserBNF.html"
+&nbsp;&nbsp;&nbsp; javacchome="c:/program files/JavaCC"&nbsp;
+/&gt;</pre>
+</blockquote>
+This invokes JJDoc on grammar file src/Parser.jj, writing the generated
+BNF documentation file, ParserBNF.html, file to doc.
+<br>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/jjtree.html b/trunk/docs/manual/OptionalTasks/jjtree.html
new file mode 100644
index 0000000..390186e
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jjtree.html
@@ -0,0 +1,556 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta http-equiv="Content-Language" content="en-us">
+   <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JJTree Task</title>
+</head>
+<body>
+
+<h2>
+<a NAME="jjtree"></a>JJTree</h2>
+
+<h3>
+Description</h3>
+<p>Invokes the <a href="http://javacc.dev.java.net/">JJTree</a> preprocessor
+for the JavaCC compiler compiler. It inserts parse tree building actions
+at various places in the JavaCC source that it generates. The output of
+JJTree is run through JavaCC to create the parser.
+<p>To use the jjtree task, set the <i>target</i> attribute to the name
+of the JJTree grammar file to process. You also need to specify the directory
+containing the JavaCC installation using the <i>javacchome</i> attribute,
+so that ant can find the JavaCC classes. Optionally, you can also set the
+<i>outputdirectory</i>
+to write the generated JavaCC grammar and node files to a specific directory.
+Otherwise jjtree writes the generated JavaCC grammar and node files to the directory
+containing the JJTree grammar file. As an extra option, you can also set the
+<i>outputfile</i> to write the generated JavaCC grammar file to a specific (directory and) file.
+Otherwise jjtree writes the generated JavaCC grammar file as the JJTree
+grammar file with a suffix .jj.</p>
+<p>This task only invokes JJTree if the grammar file is newer than the
+generated JavaCC file.</p>
+
+<h3>Parameters</h3>
+
+<table BORDER CELLSPACING=0 CELLPADDING=2 >
+<tr>
+<td VALIGN=TOP><b>Attribute</b></td>
+
+<td VALIGN=TOP><b>Description</b></td>
+
+<td ALIGN=CENTER VALIGN=TOP><b>Required</b></td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>target</td>
+
+<td VALIGN=TOP>The jjtree grammar file to process.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>Yes</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>javacchome</td>
+
+<td VALIGN=TOP>The directory containing the JavaCC distribution.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>Yes</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>outputdirectory</td>
+
+<td VALIGN=TOP>The directory to write the generated JavaCC grammar and node files to.
+If not set, the files are written to the directory containing the grammar file.&nbsp;</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>outputfile</td>
+
+<td VALIGN=TOP>The file to write the generated JavaCC grammar file
+to. If not set, the file is written with the same name as the JJTree
+grammar file but with a the suffix <code>.jj</code>.  This is a
+filename relative to <em>outputdirectory</em> if specified, the
+project's basedir.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>buildnodefiles</td>
+
+<td VALIGN=TOP>Sets the BUILD_NODE_FILES grammar option. This is a boolean
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>multi</td>
+
+<td VALIGN=TOP>Sets the MULTI grammar option. This is a boolean option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodedefaultvoid</td>
+
+<td VALIGN=TOP>Sets the NODE_DEFAULT_VOID grammar option. This is a boolean
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodefactory</td>
+
+<td VALIGN=TOP>Sets the NODE_FACTORY grammar option. This is boolean option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodescopehook</td>
+
+<td VALIGN=TOP>Sets the NODE_SCOPE_HOOK grammar option. This is a boolean
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodeusesparser</td>
+
+<td VALIGN=TOP>Sets the NODE_USES_PARSER grammar option. This is a boolean
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>static</td>
+
+<td VALIGN=TOP>Sets the STATIC grammar option. This is a boolean option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>visitor</td>
+
+<td VALIGN=TOP>Sets the VISITOR grammar option. This is a boolean option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodepackage</td>
+
+<td VALIGN=TOP>Sets the NODE_PACKAGE grammar option. This is a string option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>visitorexception</td>
+
+<td VALIGN=TOP>Sets the VISITOR_EXCEPTION grammar option. This is a string
+option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP>nodeprefix</td>
+
+<td VALIGN=TOP>Sets the NODE_PREFIX grammar option. This is a string option.</td>
+
+<td ALIGN=CENTER VALIGN=TOP>No</td>
+</tr>
+</table>
+
+<h3>
+Example</h3>
+
+<blockquote>
+<pre>&lt;jjtree&nbsp;
+&nbsp;&nbsp;&nbsp; target="src/Parser.jjt"&nbsp;
+&nbsp;&nbsp;&nbsp; outputdirectory="build/src"
+&nbsp;&nbsp;&nbsp; javacchome="c:/program files/JavaCC"&nbsp;
+&nbsp;&nbsp;&nbsp; nodeusesparser="true"
+/&gt;</pre>
+</blockquote>
+This invokes JJTree on grammar file src/Parser.jjt, writing the generated
+grammar file, Parser.jj, file to build/src. The grammar option NODE_USES_PARSER
+is set to true when invoking JJTree.
+<br>
+
+<h3>Comparison output locations between command line JJTree and different Ant taskdef versions</h3>
+
+<table cellpadding="3" border="1">
+<tr>
+  <td><b>Command Line JJTree options</b>
+    <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>and Generated Files</i> (working directory: <code>/tmp</code>)</td>
+  <td><b>Ant 1.5.3</b> versus command line</td>
+  <td><b>Ant 1.6</b> versus command line</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  grammar.jjt</b>
+    /tmp/grammar.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  relative/grammar.jjt</b>
+    /tmp/grammar.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td><pre>
+/tmp/relative/grammar.jj
+/tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  /tmp/absolute/grammar.jjt</b>
+    /tmp/grammar.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td><pre>
+/tmp/absolute/grammar.jj
+/tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:relative  grammar.jjt</b>
+    /tmp/relative/grammar.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:relative  relative/grammar.jjt</b>
+    /tmp/relative/grammar.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:relative  /tmp/absolute/grammar.jjt</b>
+    /tmp/relative/grammar.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:/tmp/absolute/  grammar.jjt</b>
+    /tmp/absolute/grammar.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:/tmp/absolute/  relative/grammar.jjt</b>
+    /tmp/absolute/grammar.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_DIRECTORY:/tmp/absolute/  /tmp/absolute/grammar.jjt</b>
+    /tmp/absolute/grammar.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Same</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  grammar.jjt</b>
+    /tmp/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  relative/grammar.jjt</b>
+    /tmp/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  /tmp/absolute/grammar.jjt</b>
+    /tmp/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:relative  grammar.jjt</b>
+    /tmp/relative/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:relative  relative/grammar.jjt</b>
+    /tmp/relative/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:relative  /tmp/absolute/grammar.jjt</b>
+    /tmp/relative/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  grammar.jjt</b>
+    /tmp/absolute/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  relative/grammar.jjt</b>
+    /tmp/absolute/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  /tmp/absolute/grammar.jjt</b>
+    /tmp/absolute/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  relative/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  /tmp/absolute/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:relative  grammar.jjt</b>
+    /tmp/relative/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:relative  relative/grammar.jjt</b>
+    /tmp/relative/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:relative  /tmp/absolute/grammar.jjt</b>
+    /tmp/relative/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  grammar.jjt</b>
+    /tmp/absolute/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  relative/grammar.jjt</b>
+    /tmp/absolute/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  /tmp/absolute/grammar.jjt</b>
+    /tmp/absolute/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  relative/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  /tmp/absolute/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:<i><u>D:</u></i>/tmp/subdir/output.jj  grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Not Supported *)</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:<i><u>D:</u></i>/tmp/subdir/output.jj  relative/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Not Supported *)</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:<i><u>D:</u></i>/tmp/subdir/output.jj  /tmp/absolute/grammar.jjt</b>
+    /tmp/subdir/output.jj
+    /tmp/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Not Supported *)</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:relative  grammar.jjt</b>
+    /tmp/relative/tmp/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:relative  relative/grammar.jjt</b>
+    /tmp/relative/tmp/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:relative  /tmp/absolute/grammar.jjt</b>
+    /tmp/relative/tmp/subdir/output.jj
+    /tmp/relative/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  grammar.jjt</b>
+    /tmp/absolute/tmp/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  relative/grammar.jjt</b>
+    /tmp/absolute/tmp/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+<tr>
+  <td><pre><b>jjtree  -OUTPUT_FILE:/tmp/subdir/output.jj  -OUTPUT_DIRECTORY:/tmp/absolute/  /tmp/absolute/grammar.jjt</b>
+    /tmp/absolute/tmp/subdir/output.jj
+    /tmp/absolute/&lt;generated&gt;.java</pre>
+  </td>
+  <td>Not Supported</td>
+  <td>Same</td>
+</tr>
+</table>
+
+<p>*) <u>Footnote</u>: When running JJTree with the Ant taskdef <i>jjtree</i> the option <code>-OUTPUT_DIRECTORY</code> must always 
+be set, because the project's basedir and the ant working directory might differ. So even if you don't specify the jjtree taskdef 
+<i>outputdirectory</i> JJTree will be called with the <code>-OUTPUT_DIRECTORY</code> set to the project's basedirectory. 
+But when the <code>-OUTPUT_DIRECTORY</code> is set, the <code>-OUTPUT_FILE</code> setting is handled as if relative to this 
+<code>-OUTPUT_DIRECTORY</code>. Thus when the <code>-OUTPUT_FILE</code> is absolute or contains a drive letter we have a 
+problem. 
+Therefore absolute <i>outputfile</i>s (when the <i>outputdirectory</i> isn't specified) are made relative to the default directory.
+And for this reason <i>outputfile</i>s that contain a drive letter can't be supported.</p>
+
+<p>By the way: specifying a drive letter in the <code>-OUTPUT_FILE</code> when the <code>-OUTPUT_DIRECTORY</code> is set, also 
+results in strange behavior when running JJTree from the command line.</p>
+
+<br>
+
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/jlink.html b/trunk/docs/manual/OptionalTasks/jlink.html
new file mode 100644
index 0000000..47bd240
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jlink.html
@@ -0,0 +1,177 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JLink Task</title>
+</head>
+<body>
+
+<h2><a name="jlink">Jlink</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated. Use a <a href="../CoreTypes/zipfileset.html">zipfileset</a>
+ or <a href="../CoreTasks/zip.html#zipgroupfileset">zipgroupfileset</a> with the
+ <a href="../CoreTasks/jar.html">Jar task</a> or <a href="../CoreTasks/zip.html">Zip task</a>
+ instead.</i></p>
+
+<h3><b>Description:</b></h3>
+<p>Links entries from sub-builds and libraries.</p>
+
+<p>The jlink task can be used to build jar and zip files, similar to 
+the <i>jar</i> task.
+However, jlink provides options for controlling the way entries from 
+input files
+are added to the output file. Specifically, capabilities for merging 
+entries from
+multiple zip or jar files is available.</p>
+
+<p>If a mergefile is specified directly (eg. at the top level of a 
+<i>mergefiles</i>
+pathelement) <i>and</i> the mergefile ends in &quot;.zip&quot; or 
+&quot;.jar&quot;,
+entries in the mergefile will be merged into the outfile. A file with 
+any other extension
+will be added to the output file, even if it is specified in the 
+mergefiles element.
+Directories specified in either the mergefiles or addfiles element 
+are added to the
+output file as you would expect: all files in subdirectories are 
+recursively added to
+the output file with appropriate prefixes in the output file 
+(without merging).
+</p>
+
+<p>
+In the case where duplicate entries and/or files are found among the 
+files to be merged or
+added, jlink merges or adds the first entry and ignores all subsequent entries.
+</p>
+
+<p>
+jlink ignores META-INF directories in mergefiles. Users should supply their
+own manifest information for the output file.
+</p>
+
+<p>It is possible to refine the set of files that are being jlinked. 
+This can be
+done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, 
+<i>excludesfile</i>,
+and <i>defaultexcludes</i> attributes on the <i>addfiles</i> and 
+<i>mergefiles</i>
+nested elements. With the <i>includes</i> or <i>includesfile</i>
+attribute you specify the files you want to have included by using patterns.
+The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns. The patterns are
+relative to the <i>base</i> directory.</p>
+
+
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <td valign="top"><b>Attribute</b></td>
+     <td valign="top"><b>Description</b></td>
+     <td align="center" valign="top"><b>Required</b></td>
+   </tr>
+   <tr>
+     <td valign="top">outfile</td>
+     <td valign="top">the path of the output file.</td>
+     <td valign="top" align="center">Yes</td>
+   </tr>
+   <tr>
+     <td valign="top">compress</td>
+     <td valign="top">whether or not the output should be compressed. 
+<i>true</i>,
+                      <i>yes</i>, or <i>on</i> result in compressed output.
+                      If omitted, output will be uncompressed (inflated).</td>
+     <td valign="top" align="center">No</td>
+   </tr>
+   <tr>
+     <td valign="top">mergefiles</td>
+     <td valign="top">files to be merged into the output, if possible.</td>
+     <td valign="middle" align="center" rowspan="2">At least one of 
+mergefiles or addfiles</td>
+   </tr>
+   <tr>
+     <td valign="top">addfiles</td>
+     <td valign="top">files to be added to the output.</td>
+   </tr>
+</table>
+
+<h3>Examples</h3>
+
+<p>The following will merge the entries in mergefoo.jar and mergebar.jar 
+into out.jar.
+mac.jar and pc.jar will be added as single entries to out.jar.</p>
+<pre>
+&lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;&gt;
+   &lt;mergefiles&gt;
+     &lt;pathelement path=&quot;${build.dir}/mergefoo.jar&quot;/&gt;
+     &lt;pathelement path=&quot;${build.dir}/mergebar.jar&quot;/&gt;
+   &lt;/mergefiles&gt;
+   &lt;addfiles&gt;
+     &lt;pathelement path=&quot;${build.dir}/mac.jar&quot;/&gt;
+     &lt;pathelement path=&quot;${build.dir}/pc.zip&quot;/&gt;
+   &lt;/addfiles&gt;
+&lt;/jlink&gt;
+</pre>
+
+<p><b>Non-deprecated alternative to the above:</b></p>
+<pre>
+&lt;jar compress=&quot;false&quot; destfile=&quot;out.jar&quot;&gt;
+  &lt;zipgroupfileset dir=&quot;${build.dir}&quot;&gt;
+    &lt;include name=&quot;mergefoo.jar&quot;/&gt;
+    &lt;include name=&quot;mergebar.jar&quot;/&gt;
+  &lt;/zipgroupfileset&gt;
+  &lt;fileset dir=&quot;${build.dir}&quot;&gt;
+    &lt;include name=&quot;mac.jar&quot;/&gt;
+    &lt;include name=&quot;pc.jar&quot;/&gt;
+  &lt;/fileset&gt;
+&lt;/jar&gt;
+</pre>
+
+<p>Suppose the file foo.jar contains two entries: bar.class and 
+barnone/myClass.zip.
+Suppose the path for file foo.jar is build/tempbuild/foo.jar. The 
+following example
+will provide the entry tempbuild/foo.jar in the out.jar.</p>
+<pre>
+&lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;&gt;
+   &lt;mergefiles&gt;
+     &lt;pathelement path=&quot;build/tempbuild&quot;/&gt;
+   &lt;/mergefiles&gt;
+&lt;/jlink&gt;
+</pre>
+
+<p>However, the next example would result in two top-level entries in out.jar,
+namely bar.class and barnone/myClass.zip</p>
+<pre>
+&lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;&gt;
+   &lt;mergefiles&gt;
+     &lt;pathelement path=&quot;build/tempbuild/foo.jar&quot;/&gt;
+   &lt;/mergefiles&gt;
+&lt;/jlink&gt;
+</pre>
+
+
+</body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/jsharpc.html b/trunk/docs/manual/OptionalTasks/jsharpc.html
new file mode 100644
index 0000000..276e42e
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jsharpc.html
@@ -0,0 +1,434 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Jsharpc
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Jsharpc
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Compile J# source down to a managed .NET application. <p>For historical reasons the pattern <code>**/*.java</code> is preset as includes list and you can not override it with an explicit includes attribute.  Use nested <code>&lt;src&gt;</code> elements instead of the basedir attribute if you need more control.</p></font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Compile J# source down to a managed .NET application. <p> J# is not Java. But it is the language closest to Java in the .NET framework. This task compiles jsharp source (.java files), and generates a .NET managed exe or dll. <p>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">additionalmodules - note that your version of vjc may not support this option.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of modules to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="21">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">baseaddress</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"></font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">debug</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the debug flag on or off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the destination directory of files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the name of exe/library to create.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">executable</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the name of the program, overriding the defaults. Can be used to set the full path to a program, or to switch to an alternate implementation of the command, such as the Mono or Rotor versions -provided they use the same command line arguments as the .NET framework edition</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Any extra options which are not explicitly supported by this task.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, fail on compilation errors.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">includedefaultreferences</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, automatically includes the common assemblies in dotnet, and tells the compiler to link in mscore.dll. set the automatic reference inclusion flag on or off this flag controls the /nostdlib option in CSC</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">mainclass</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the name of main class for executables.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optimize</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, enables optimization flag.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">purejava</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">do we want pure java (default, true) or corrupted J#?</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">referencefiles</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path of references to include. Wildcards should work.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">references</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of DLLs to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">securescoping</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Make package scoped code visible to the current assembly only (default: false) .NET does not have package scoping. Instead it has assembly, private and public. By default, package content is public to all.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the source directory of the files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">targettype</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the target type to one of exe|library|module|winexe</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">"exe", "library", "module", "winexe"</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">utf8output</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, require all compiler output to be in UTF8 format.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">warnlevel</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Level of warning currently between 1 and 4 with 4 being the strictest.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32icon</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the filename of icon to include.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32res</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the filename of a win32 resource (.RES) file to include. This is not a .NET resource, but what Windows is used to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>define</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetDefine)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a define to the list of definitions
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>reference</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new reference fileset to the compilation
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>resource</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetResource)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        link or embed a resource
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>src</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new source directory to the compile
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/jspc.html b/trunk/docs/manual/OptionalTasks/jspc.html
new file mode 100644
index 0000000..fb3428c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/jspc.html
@@ -0,0 +1,308 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JSPC Task</title>
+</head>
+
+<body>
+
+<h2><a name="jspc">jspc (deprecated)</a></h2>
+<h3>Description</h3>
+
+<p> Ant task to run the JSP compiler and turn JSP pages into Java source.
+
+<p><b>Deprecated</b> if you use this task with Tomcat's Jasper JSP
+compiler, you should seriously consider using the task shipping with
+Tomcat instead.  This task is only tested against Tomcat 4.x. There
+are known problems with Tomcat 5.x that won't get fixed in Ant, please
+use Tomcat's jspc task instead.<br/>
+Instead of relying on container specific JSP-compilers we suggest deploying 
+the raw files (*.jsp) and use the container build-in functions: after deploying run
+a test suite (e.g. with <a href="http://jakarta.apache.org/cactus/">Cactus</a> or 
+<a href="http://httpunit.sourceforge.net/">HttpUnit</a>) against the deployed web 
+application. So you'll get the test result <i>and</i> the compiled JSPs.
+</p>
+
+<p>
+
+This task can be used to precompile JSP pages for fast initial invocation
+of JSP pages, deployment on a server without the full JDK installed,
+or simply to syntax check the pages without deploying them.
+In most cases, a javac task is usually the next stage in the build process.
+The task does basic dependency checking to prevent unnecessary recompilation -this
+checking compares source and destination timestamps, and does not factor
+in class or taglib dependencies, or <code>&lt;jsp:include&gt;</code> references.
+
+<p>
+By default the task uses the Jasper JSP compiler. This
+means the task needs jasper.jar and jasper-runtime.jar, which come with
+builds of Tomcat 4/Catalina from the
+<a href="http://jakarta.apache.org/tomcat/">Jakarta Tomcat project</a>,
+and any other Jar files which may be needed in future versions (it changes)
+
+We recommend (in March 2003) Tomcat version 4.1.x for the most robust version
+of Jasper.
+
+<p>
+There are many limitations with this task which partially stem from the
+many versions of Jasper, others from implementation 'issues' in the task
+(i.e. nobody's willingness to radically change large bits of it to work
+around jasper). Because of this and the fact that JSP pages do not have
+to be portable across implementations -or versions of implementations-
+this task is better used for validating JSP pages before deployment,
+rather than precompiling them. For that, just deploy and run your httpunit
+junit tests after deployment to compile and test your pages, all in one
+go.
+ 
+</p>
+
+
+<h3>Parameters</h3>
+The Task has the following attributes:<p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">destdir</td>
+    <td valign="top">Where to place the generated files. They are located
+    under here according to the given package name.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">srcdir</td>
+    <td valign="top">Where to look for source jsp files.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">The verbosity integer to pass to the compiler. Default="0"</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">package</td>
+    <td valign="top">Name of the destination package for generated java
+    classes.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td valign="top">class name of a JSP compiler adapter,
+    such as "jasper" or "jasper41"</td>
+    <td valign="top" align="center">No -defaults to "jasper"</td>
+  </tr>
+  <tr>
+    <td valign="top">ieplugin</td>
+    <td valign="top">Java Plugin classid for Internet Explorer.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">mapped</td>
+    <td valign="top">(boolean) Generate separate write() calls for each HTML
+    line in the JSP.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use to run the jsp compiler.
+    This can also be specified
+    by the nested element <code>classpath</code>
+    <a href="../using.html#path">Path</a>).</td>
+    <td valign="top" align="center">No, but it seems to work better when used</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">A <a href="../using.html#references">Reference</a>. As
+    per <code>classpath</code></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">flag to control action on compile failures: default=yes</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">uribase</td>
+    <td valign="top">
+    The uri context of relative URI
+    references in the JSP pages. If it does not
+    exist then it is derived from the location of the file
+    relative to the declared or derived value of <tt>uriroot.</tt>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">uriroot</td>
+    <td valign="top">
+    The root directory that uri files should be resolved
+    against.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compiler</td>
+    <td valign="top">
+    Class name of jsp compiler adapter to use.  Defaults to
+    the standard adapter for Jasper.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compilerclasspath</td>
+    <td valign="top">The classpath used to find the compiler adapter specified
+    by the <code>compiler</code> attribute.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">webinc</td>
+    <td valign="top">Output file name for the fraction of web.xml that lists servlets.</td>
+    <td valign="top" align="center">No</td>
+  </tr>    
+  <tr>
+    <td valign="top">webxml</td>
+    <td valign="top">File name for web.xml to be generated</td>
+    <td valign="top" align="center">No</td>
+  </tr>  
+
+  </table>
+
+<P>The <tt>mapped</tt> option will, if set to true, split the JSP text content into a
+one line per call format.  There are comments above and below the mapped
+write calls to localize where in the JSP file each line of text comes
+from.  This can lead to a minor performance degradation (but it is bound
+by a linear complexity).  Without this options all adjacent writes are
+concatenated into a single write.</P>
+
+<P>The <tt>ieplugin</tt> option is used by the <tt>&lt;jsp:plugin&gt;</tt> tags.
+If the Java Plug-in COM Class-ID you want to use changes then it can be
+specified here.  This should not need to be altered.</P>
+
+<P><tt>uriroot</tt> specifies the root of the web
+application.  This is where all absolute uris will be resolved from.
+If it is not specified then the first JSP page will be used to derive
+it.  To derive it each parent directory of the first JSP page is
+searched for a <tt>WEB-INF</tt> directory, and the directory closest to
+the JSP page that has one will be used.  If none can be found then the
+directory Jasperc was called from will be used.  This only affects pages
+translated from an explicitly declared JSP file -including references
+to taglibs</P>
+
+<P><tt>uribase</tt> is used to establish the uri context of
+relative URI references in the JSP pages.  If it does not exist then it
+is derived from the location of the file relative to the declared or
+derived value of <tt>uriroot</tt>. This only affects pages
+translated from an explicitly declared JSP file.</P>
+
+<h3>Parameters specified as nested elements</h3>
+
+This task is a <a href="../dirtasks.html">directory based task</a>, like
+<strong>javac</strong>, so the jsp files to be compiled are located as java
+files are by <strong>javac</strong>. That is, elements such as <tt>includes</tt> and
+<tt>excludes</tt> can be used directly inside the task declaration.
+
+<p>
+
+Elements specific to the jspc task are:-
+
+<h4>classpath</h4>
+
+The classpath used to compile the JSP pages, specified as for any other
+classpath.
+
+<h4>classpathref</h4>
+a reference to an existing classpath
+
+<h4>webapp</h4>
+Instructions to jasper to build an entire web application.
+The base directory must have a WEB-INF subdirectory beneath it.
+When used, the task hands off all dependency checking to the compiler.
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the base directory of the web application</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<h3>Example</h3>
+<pre>
+&lt;jspc srcdir="${basedir}/src/war"
+      destdir="${basedir}/gensrc"
+      package="com.i3sp.jsp"
+      compiler="jasper41"
+      verbose="9"&gt;
+  &lt;include name="**/*.jsp"/&gt;
+&lt;/jspc&gt;
+</pre>
+Build all jsp pages under src/war into the destination /gensrc, in a
+package hierarchy beginning with com.i3sp.jsp.
+<pre>
+&lt;jspc
+      destdir="interim"
+      verbose="1"
+      srcdir="src"
+      compiler="jasper41"
+      package="com.i3sp.jsp"&gt;
+  &lt;include name="**/*.jsp"/&gt;
+&lt;/jspc&gt;
+&lt;depend
+         srcdir="interim"
+         destdir="build"
+         cache="build/dependencies"
+         classpath="lib/taglibs.jar"/&gt;
+&lt;javac
+         srcdir="interim"
+         destdir="build"
+         classpath="lib/taglibs.jar"
+         debug="on"/&gt;
+</pre>
+Generate jsp pages then javac them down to
+bytecodes. Include lib/taglib jar in the java compilation.
+ Dependency checking is used to scrub the
+java files if class dependencies indicate it is needed.
+
+<p><h4>Notes</h4>
+Using the <code>package</code> attribute it is possible to identify the resulting
+java files and thus do full dependency checking - this task should only rebuild
+java files if their jsp file has been modified. However, this only works
+with some versions of jasper. By default the checking supports tomcat 4.0.x
+with the "jasper" compiler, set the compiler to "jasper41" for the tomcat4.1.x
+dependency checking.
+Even when it does work, changes in
+.TLD imports or in compile time includes do not get picked up.
+
+<p>
+Jasper generates JSP pages against the JSP1.2 specification -a copy of
+version 2.3 of the servlet specification is needed on the classpath to
+compile the Java code.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/junit.html b/trunk/docs/manual/OptionalTasks/junit.html
new file mode 100644
index 0000000..84c9d5a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/junit.html
@@ -0,0 +1,672 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JUnit Task</title>
+</head>
+<body>
+
+<h2><a name="junit">JUnit</a></h2>
+<h3>Description</h3>
+
+<p>This task runs tests from the JUnit testing framework. The latest
+version of the framework can be found at
+<a href="http://www.junit.org">http://www.junit.org</a>.
+This task has been tested with JUnit 3.0 up to JUnit 3.8.2; it won't
+work with versions prior to JUnit 3.0. It also works with JUnit 4.0, including
+"pure" JUnit 4 tests using only annotations and no <code>JUnit4TestAdapter</code>.</p>
+<p><strong>Note:</strong> This task depends on external libraries not included
+in the Ant distribution.  See <a href="../install.html#librarydependencies">
+Library Dependencies</a> for more information.
+</p>
+<p>
+<strong>Note</strong>:
+You must have <code>junit.jar</code> available.
+You can do one of:
+</p>
+<ol>
+<li>
+Put both <code>junit.jar</code> and <code>ant-junit.jar</code> in
+<code>ANT_HOME/lib</code>.
+</li>
+<li>
+Do not put either in <code>ANT_HOME/lib</code>, and instead
+include their locations in your <code>CLASSPATH</code> environment variable.
+</li>
+<li>
+Add both JARs to your classpath using <code>-lib</code>.
+</li>
+<li>
+Specify the locations of both JARs using
+a <code>&lt;classpath&gt;</code> element in a <code>&lt;taskdef&gt;</code> in the build file.
+</li>
+<li>
+Leave <code>ant-junit.jar</code> in its default location in <code>ANT_HOME/lib</code>
+but include <code>junit.jar</code> in the <code>&lt;classpath&gt;</code> passed
+to <code>&lt;junit&gt;</code>. <em>(since Ant 1.7)</em>
+</li>
+</ol>
+<p>
+See <a href="../../faq.html#delegating-classloader" target="_top">the
+FAQ</a> for details.
+</p>
+
+<p>Tests are defined by nested <code>test</code> or
+<code>batchtest</code> tags (see <a href="#nested">nested
+elements</a>).</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">printsummary</td>
+    <td valign="top">Print one-line statistics for each testcase. Can
+      take the values <code>on</code>,
+      <code>off</code>, and
+      <code>withOutAndErr</code>.
+      <code>withOutAndErr</code> is the same
+      as <code>on</code> but also includes the output of the test
+      as written to <code>System.out</code> and <code>System.err</code>.</td>
+    <td align="center" valign="top">No; default is <code>off</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">fork</td>
+    <td valign="top">Run the tests in a separate VM.</td>
+    <td align="center" valign="top">No; default is <code>off</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">forkmode</td>
+    <td valign="top">Controls how many Java Virtual Machines get
+    created if you want to fork some tests.  Possible values are
+    &quot;perTest&quot; (the default), &quot;perBatch&quot; and
+    &quot;once&quot;.  &quot;once&quot; creates only a single Java VM
+    for all tests while &quot;perTest&quot; creates a new VM for each
+    TestCase class.  &quot;perBatch&quot; creates a VM for each nested
+    <code>&lt;batchtest&gt;</code> and one collecting all nested
+    <code>&lt;test&gt;</code>s.  Note that only tests with the same
+    settings of <code>filtertrace</code>, <code>haltonerror</code>,
+    <code>haltonfailure</code>, <code>errorproperty</code> and
+    <code>failureproperty</code> can share a VM, so even if you set
+    <code>forkmode</code> to &quot;once&quot;, Ant may have to create
+    more than a single Java VM.  This attribute is ignored for tests
+    that don't get forked into a new Java VM.  <em>since Ant 1.6.2</em></td>
+    <td align="center" valign="top">No; default is <code>perTest</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">haltonerror</td>
+    <td valign="top">Stop the build process if an error occurs during the test
+       run.</td>
+    <td align="center" valign="top">No; default is <code>off</code>.</td>
+  </tr>
+<tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property to set in the event of an error.</td>
+    <td align="center" valign="top">No</td>
+</tr>
+  <tr>
+    <td valign="top">haltonfailure</td>
+    <td valign="top">Stop the build process if a test fails (errors are
+      considered failures as well).</td>
+    <td align="center" valign="top">No; default is <code>off</code>.</td>
+  </tr>
+<tr>
+    <td valign="top">failureproperty</td>
+    <td valign="top">The name of a property to set in the event of a failure
+      (errors are considered failures as well).</td>
+    <td align="center" valign="top">No.</td>
+</tr>
+  <tr>
+    <td valign="top">filtertrace</td>
+    <td valign="top">Filter out Junit and Ant stack frames from error and failure stack traces.</td>
+    <td align="center" valign="top">No; default is <code>on</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Cancel the individual tests if they don't finish
+      in the given time (measured in milliseconds).  Ignored if
+      <code>fork</code> is disabled.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">maxmemory</td>
+    <td valign="top">Maximum amount of memory to allocate to the forked VM.
+      Ignored if <code>fork</code> is disabled.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">jvm</td>
+    <td valign="top">The command used to invoke the Java Virtual Machine,
+      default is 'java'.  The command is resolved by
+      <code>java.lang.Runtime.exec()</code>.
+      Ignored if <code>fork</code> is disabled.</td>
+    <td align="center" valign="top">No; default is <code>java</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">dir</td>
+    <td valign="top">The directory in which to invoke the VM. Ignored if
+      <code>fork</code> is disabled.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">newenvironment</td>
+    <td valign="top">Do not propagate the old environment when new
+      environment variables are specified. Ignored if <code>fork</code> is
+      disabled.</td>
+    <td align="center" valign="top">No; default is <code>false</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">includeantruntime</td>
+    <td valign="top">Implicitly add the Ant classes required to run
+      the tests and JUnit to the classpath in forked mode.
+      <b>Note:</b> Please read the <a
+      href="../../faq.html#junit-no-runtime-xml">Ant FAQ</a> if you
+      want to set this to <code>false</code> and use the XML formatter
+      at the same time.</td>
+    <td align="center" valign="top">No; default is <code>true</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">showoutput</td>
+    <td valign="top">Send any output generated by tests to Ant's
+      logging system as well as to the formatters.  By default only the
+      formatters receive the output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputtoformatters</td>
+    <td valign="top">
+      <em>Since Ant 1.7.0.</em><br/>
+      Send any output generated by tests to the test formatters.
+      This is "true" by default.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">tempdir</td>
+    <td valign="top">Where Ant should place temporary files.
+      <em>Since Ant 1.6</em>.</td>
+    <td align="center" valign="top">No; default is the project's base
+      directory.</td>
+  </tr>
+  <tr>
+    <td valign="top">reloading</td>
+    <td valign="top">Whether or not a new classloader should be instantiated for each test case.<br>
+    Ignore if <code>fork</code> is set to true.
+      <em>Since Ant 1.6</em>.</td>
+    <td align="center" valign="top">No; default is <code>true</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">clonevm</td>
+    <td valign="top">If set to true true, then all system properties
+      and the bootclasspath of the forked Java Virtual Machine will be
+      the same as those of the Java VM running Ant.  Default is
+      &quot;false&quot; (ignored if fork is disabled).
+      <em>since Ant 1.7</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>By using the <code>errorproperty</code> and <code>failureproperty</code>
+attributes, it is possible to
+perform setup work (such as starting an external server), execute the test,
+clean up, and still fail the build in the event of a failure.</p>
+
+<p>The <code>filtertrace</code> attribute condenses error and failure
+stack traces before reporting them.
+It works with both the plain and XML formatters.  It filters out any lines
+that begin with the following string patterns:<pre>
+   "junit.framework.TestCase"
+   "junit.framework.TestResult"
+   "junit.framework.TestSuite"
+   "junit.framework.Assert."
+   "junit.swingui.TestRunner"
+   "junit.awtui.TestRunner"
+   "junit.textui.TestRunner"
+   "java.lang.reflect.Method.invoke("
+   "sun.reflect."
+   "org.apache.tools.ant."</pre></p>
+
+<h3><a name="nested">Nested Elements</a></h3>
+
+<p>The <code>&lt;junit&gt;</code> task
+supports a nested <code>&lt;classpath&gt;</code>
+element that represents a <a href="../using.html#path">PATH like
+structure</a>.</p>
+
+<p>As of Ant 1.7, this classpath may be used to refer to <code>junit.jar</code>
+as well as your tests and the tested code.
+
+<h4>jvmarg</h4>
+
+<p>If <code>fork</code> is enabled, additional parameters may be passed to
+the new VM via nested <code>&lt;jvmarg&gt;</code> elements. For example:</p>
+
+<pre>
+&lt;junit fork=&quot;yes&quot;&gt;
+  &lt;jvmarg value=&quot;-Djava.compiler=NONE&quot;/&gt;
+  ...
+&lt;/junit&gt;
+</pre>
+
+<p>would run the test in a VM without JIT.</p>
+
+<p><code>&lt;jvmarg&gt;</code> allows all attributes described in <a
+href="../using.html#arg">Command-line Arguments</a>.</p>
+
+<h4>sysproperty</h4>
+
+<p>Use nested <code>&lt;sysproperty&gt;</code> elements to specify system
+properties required by the class. These properties will be made available
+to the VM during the execution of the test (either ANT's VM or the forked VM,
+if <code>fork</code> is enabled).
+The attributes for this element are the same as for <a href="../CoreTasks/exec.html#env">environment variables</a>.</p>
+
+<pre>
+&lt;junit fork=&quot;no&quot;&gt;
+  &lt;sysproperty key=&quot;basedir&quot; value=&quot;${basedir}&quot;/&gt;
+  ...
+&lt;/junit&gt;
+</pre>
+
+<p>would run the test in ANT's VM and make the <code>basedir</code> property
+available to the test.</p>
+
+<h4>syspropertyset</h4>
+
+<p>You can specify a set of properties to be used as system properties
+with <a href="../CoreTypes/propertyset.html">syspropertyset</a>s.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>env</h4>
+
+<p>It is possible to specify environment variables to pass to the
+forked VM via nested <code>&lt;env&gt;</code> elements. For a description
+of the <code>&lt;env&gt;</code> element's attributes, see the
+description in the <a href="../CoreTasks/exec.html#env">exec</a> task.</p>
+
+<p>Settings will be ignored if <code>fork</code> is disabled.</p>
+
+<h4>bootclasspath</h4>
+
+<p>The location of bootstrap class files can be specified using this
+<a href="../using.html#path">PATH like structure</a> - will be ignored
+if <i>fork</i> is not <code>true</code> or the target VM doesn't
+support it (i.e. Java 1.1).</p>
+
+<p><em>since Ant 1.6</em>.</p>
+
+<h4>permissions</h4>
+<p>Security permissions can be revoked and granted during the execution of the 
+class via a nested <i>permissions</i> element. For more information please
+see <a href="../CoreTypes/permissions.html">permissions</a></p>
+
+<p>Settings will be ignored if fork is enabled.</p>
+
+<p><em>since Ant 1.6</em>.</p>
+ 
+<h4>assertions</h4>
+
+<p>You can control enablement of Java 1.4 assertions with an
+<a href="../CoreTypes/assertions.html"><tt>&lt;assertions&gt;</tt></a>
+subelement.</p>
+ 
+<p>Assertion statements are currently ignored in non-forked mode.</p>
+
+<p><em>since Ant 1.6.</em></p>
+
+<h4>formatter</h4>
+
+<p>The results of the tests can be printed in different
+formats. Output will always be sent to a file, unless you set the
+<code>usefile</code> attribute to <code>false</code>.
+The name of the file is determined by the
+name of the test and can be set by the <code>outfile</code> attribute
+of <code>&lt;test&gt;</code>.</p>
+
+<p>There are four predefined formatters - one prints the test results
+in XML format, the other emits plain text.  The formatter named
+<code>brief</code> will only print detailed information for testcases
+that failed, while <code>plain</code> gives a little statistics line
+for all test cases.  Custom formatters that need to implement
+<code>org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter</code>
+can be specified.</p>
+
+<p>If you use the XML formatter, it may not include the same output
+that your tests have written as some characters are illegal in XML
+documents and will be dropped.</p>
+
+<p>The fourth formatter named <code>failure</code> (since Ant 1.8.0) 
+collects all failing <code>testXXX()</code>
+methods and creates a new <code>TestCase</code> which delegates only these
+failing methods. The name and the location can be specified via Java System property or Ant property
+<code>ant.junit.failureCollector</code>. The value has to point to the directory and 
+the name of the resulting class (without suffix). It defaults to <i>java-tmp-dir</i>/FailedTests.</p>
+
+<p><b>Note:</b> Please read the <a
+href="../../faq.html#junit-no-runtime-xml">Ant FAQ</a> if you want to
+set the fork attribute to <code>true</code>, the includeAntRuntime
+attribute to <code>false</code> and use the XML formatter at the same
+time.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">Use a predefined formatter (either
+      <code>xml</code>, <code>plain</code>, <code>brief</code> or <code>failure</code>).</td>
+    <td align="center" rowspan="2">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">Name of a custom formatter class.</td>
+  </tr>
+  <tr>
+    <td valign="top">extension</td>
+    <td valign="top">Extension to append to the output filename.</td>
+    <td align="center">Yes, if <code>classname</code> has been used.</td>
+  </tr>
+  <tr>
+    <td valign="top">usefile</td>
+    <td valign="top">Boolean that determines whether output should be
+      sent to a file.</td>
+    <td align="center">No; default is <code>true</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only use formatter if the named property is set.</td>
+    <td align="center">No; default is <code>true</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only use formatter if the named property is <b>not</b> set.</td>
+    <td align="center">No; default is <code>true</code>.</td>
+  </tr>  
+</table>
+
+<h4>test</h4>
+
+<p>Defines a single test class.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the test class.</td>
+    <td align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">fork</td>
+    <td valign="top">Run the tests in a separate VM.
+      Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">haltonerror</td>
+    <td valign="top">Stop the build process if an error occurs during the test
+       run. Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+<tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property to set in the event of an error.
+      Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+</tr>
+  <tr>
+    <td valign="top">haltonfailure</td>
+    <td valign="top">Stop the build process if a test fails (errors are
+      considered failures as well).  Overrides value set in
+      <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+<tr>
+    <td valign="top">failureproperty</td>
+    <td valign="top">The name of a property to set in the event of a failure
+      (errors are considered failures as well). Overrides value set in
+      <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+</tr>
+  <tr>
+    <td valign="top">filtertrace</td>
+    <td valign="top">Filter out Junit and Ant stack frames from error and failure stack
+    traces.  Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No; default is <code>on</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">Directory to write the reports to.</td>
+    <td align="center" valign="top">No; default is the current directory.</td>
+  </tr>
+  <tr>
+    <td valign="top">outfile</td>
+    <td valign="top">Base name of the test result. The full filename is
+      determined by this attribute and the extension of
+      <code>formatter</code>.</td>
+    <td align="center" valign="top">No; default is
+      <code>TEST-</code><em>name</em>, where <em>name</em> is the name of
+      the test specified in the <code>name</code> attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only run test if the named property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only run test if the named property is <b>not</b> set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>Tests can define their own formatters via nested
+<code>&lt;formatter&gt;</code> elements.</p>
+
+<h4>batchtest</h4>
+
+<p>Define a number of tests based on pattern matching.</p>
+
+<p><code>batchtest</code> collects the included <a href="../CoreTypes/resources.html">resources</a> from any number
+of nested <a
+href="../CoreTypes/resources.html#collection">Resource Collection</a>s. It then
+generates a test class name for each resource that ends in
+<code>.java</code> or <code>.class</code>.</p>
+
+<p>Any type of Resource Collection is supported as a nested element,
+prior to Ant 1.7 only <code>&lt;fileset&gt;</code> has been
+supported.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">fork</td>
+    <td valign="top">Run the tests in a separate VM.
+      Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">haltonerror</td>
+    <td valign="top">Stop the build process if an error occurs during the test
+       run. Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+<tr>
+    <td valign="top">errorproperty</td>
+    <td valign="top">The name of a property to set in the event of an error.
+      Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+</tr>
+  <tr>
+    <td valign="top">haltonfailure</td>
+    <td valign="top">Stop the build process if a test fails (errors are
+      considered failures as well).  Overrides value set in
+      <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+<tr>
+    <td valign="top">failureproperty</td>
+    <td valign="top">The name of a property to set in the event of a failure
+      (errors are considered failures as well). Overrides value set in
+      <code>&lt;junit&gt;</code></td>
+    <td align="center" valign="top">No</td>
+</tr>
+  <tr>
+    <td valign="top">filtertrace</td>
+    <td valign="top">Filter out Junit and Ant stack frames from error and failure stack
+    traces.  Overrides value set in <code>&lt;junit&gt;</code>.</td>
+    <td align="center" valign="top">No; default is <code>on</code>.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">Directory to write the reports to.</td>
+    <td align="center" valign="top">No; default is the current directory.</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">Only run tests if the named property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">Only run tests if the named property is <strong>not</strong> set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>Batchtests can define their own formatters via nested
+<code>&lt;formatter&gt;</code> elements.</p>
+
+<h3>Examples</h3>
+
+<pre>
+&lt;junit&gt;
+  &lt;test name="my.test.TestCase"/&gt;
+&lt;/junit&gt;
+</pre>
+
+<p>Runs the test defined in <code>my.test.TestCase</code> in the same
+VM. No output will be generated unless the test fails.</p>
+
+<pre>
+&lt;junit printsummary="yes" fork="yes" haltonfailure="yes"&gt;
+  &lt;formatter type="plain"/&gt;
+  &lt;test name="my.test.TestCase"/&gt;
+&lt;/junit&gt;
+</pre>
+
+<p>Runs the test defined in <code>my.test.TestCase</code> in a
+separate VM.  At the end of the test, a one-line summary will be
+printed. A detailed report of the test can be found in
+<code>TEST-my.test.TestCase.txt</code>. The build process will be
+stopped if the test fails.</p>
+
+<pre>
+&lt;junit printsummary="yes" haltonfailure="yes"&gt;
+  &lt;classpath&gt;
+    &lt;pathelement location="${build.tests}"/&gt;
+    &lt;pathelement path="${java.class.path}"/&gt;
+  &lt;/classpath&gt;
+
+  &lt;formatter type="plain"/&gt;
+
+  &lt;test name="my.test.TestCase" haltonfailure="no" outfile="result"&gt;
+    &lt;formatter type="xml"/&gt;
+  &lt;/test&gt;
+
+  &lt;batchtest fork="yes" todir="${reports.tests}"&gt;
+    &lt;fileset dir="${src.tests}"&gt;
+      &lt;include name="**/*Test*.java"/&gt;
+      &lt;exclude name="**/AllTests.java"/&gt;
+    &lt;/fileset&gt;
+  &lt;/batchtest&gt;
+&lt;/junit&gt;
+</pre>
+
+<p>Runs <code>my.test.TestCase</code> in the same VM, ignoring the
+given CLASSPATH; only a warning is printed if this test fails. In
+addition to the plain text test results, for this test a XML result
+will be output to <code>result.xml</code>.  
+Then, for each matching file in the directory defined for
+<code>${src.tests}</code> a
+test is run in a separate VM. If a test fails, the build process is
+aborted. Results are collected in files named
+<code>TEST-</code><em>name</em><code>.txt</code> and written to
+<code>${reports.tests}</code>.</p>
+
+<pre>
+&lt;target name=&quot;test&quot;&gt;
+    &lt;property name=&quot;collector.dir&quot; value=&quot;${build.dir}/failingTests&quot;/&gt;
+    &lt;property name=&quot;collector.class&quot; value=&quot;FailedTests&quot;/&gt;
+    &lt;!-- Delete 'old' collector classes --&gt;
+    &lt;delete&gt;
+        &lt;fileset dir=&quot;${collector.dir}&quot; includes=&quot;${collector.class}*.class&quot;/&gt;
+    &lt;/delete&gt;
+    &lt;!-- compile the FailedTests class if present --&gt; 
+    &lt;javac srcdir=&quot;${collector.dir}&quot; destdir=&quot;${collector.dir}&quot;/&gt;
+    &lt;available file=&quot;${collector.dir}/${collector.class}.class&quot; property=&quot;hasFailingTests&quot;/&gt;
+    &lt;junit haltonerror=&quot;false&quot; haltonfailure=&quot;false&quot;&gt;
+        &lt;sysproperty key=&quot;ant.junit.failureCollector&quot; value=&quot;${collector.dir}/${collector.class}&quot;/&gt;
+        &lt;classpath&gt;
+            &lt;pathelement location=&quot;${collector.dir}&quot;/&gt;
+        &lt;/classpath&gt;
+        &lt;batchtest todir=&quot;${collector.dir}&quot; unless=&quot;hasFailingTests&quot;&gt;
+            &lt;fileset dir=&quot;${collector.dir}&quot; includes=&quot;**/*.java&quot; excludes=&quot;**/${collector.class}.*&quot;/&gt;
+            &lt;!-- for initial creation of the FailingTests.java --&gt;
+            &lt;formatter type=&quot;failure&quot;/&gt;
+            &lt;!-- I want to see something ... --&gt;
+            &lt;formatter type=&quot;plain&quot; usefile=&quot;false&quot;/&gt;
+        &lt;/batchtest&gt;
+        &lt;test name=&quot;FailedTests&quot; if=&quot;hasFailingTests&quot;&gt;
+            &lt;!-- update the FailingTests.java --&gt;
+            &lt;formatter type=&quot;failure&quot;/&gt;
+            &lt;!-- again, I want to see something --&gt;
+            &lt;formatter type=&quot;plain&quot; usefile=&quot;false&quot;/&gt;
+        &lt;/test&gt;
+    &lt;/junit&gt;
+&lt;/target&gt;
+</pre>
+<p>On the first run all tests are collected via the <code>&lt;batchtest/&gt;</code>
+element. It's <code>plain</code> formatter shows the output on the console. The
+<code>failure</code> formatter creates a java source file in 
+<code>${build.dir}/failingTests/FailedTests.java</code> which extends 
+<code>junit.framework.TestCase</code> and returns from a <code>suite()</code>
+method a test suite for the failing tests. <br/>
+On a second run the collector class exists and instead of the <code>&lt;batchtest/&gt;</code>
+the single <code>&lt;test/&gt;</code> will run. So only the failing test cases are re-run.
+The two nested formatters are for displaying (for the user) and for updating the collector
+class.
+</p>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/junitreport.html b/trunk/docs/manual/OptionalTasks/junitreport.html
new file mode 100644
index 0000000..fa86d7d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/junitreport.html
@@ -0,0 +1,205 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>JUnitReport Task</title>
+</head>
+
+<body>
+
+<h2><a name="junitreport">JUnitReport</a></h2>
+Merge the individual XML files generated by the JUnit task and eventually apply
+a stylesheet on the resulting merged document to provide a browsable report of
+the testcases results.
+<p><strong>Note:</strong> This task depends on external libraries not included in
+the Ant distribution.  See <a href="../install.html#librarydependencies">
+Library Dependencies</a> for more information.</p>
+
+<h3>Requirements</h3>
+
+<p>The task needs Apache <a
+href="http://xml.apache.org/xalan-j/">Xalan 2.4.1+ or Xalan XSLTC</a>
+(JDK 1.4 contains a version of Xalan-J 2.x while JDK 1.5 ships with a
+version of XSLTC). Starting from JDK 1.4.2-01 it ships with a bundled
+Xalan-J 2.4.1+, meaning that JDK version prior to 1.4.2-01 won't work
+out of the box. The table below summarize the compatibility status. 
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr><th>Xalan</th><th>Sun JDK Bundle</th><th>Status<th></tr> 
+<tr><td>2.4.1+</td><td>JDK 1.4.2-01+</td><td>OK</td></tr>
+<tr><td>XSLTC</td><td>JDK 1.5.x</td><td>OK</td></tr>
+<tr><td>2.x</td><td>JDK 1.4.x</td><td>DEPRECATED<br><i>Use ${ant.home}/etc/junit-frames-xalan1.xsl
+<br> Upgrade Xalan using the JDK endorsement mechanism</i></td></tr>
+</table>
+
+<p>With Ant 1.6.2 we had to decide between supporting Xalan-J 1/Xalan J 2.4.1-
+and Xalan 2.4.1+/XSLTC, since there was no way to support both couples at the same
+time.</p>
+<p>With Ant 1.7 we had to drop support Xalan-J 1, since Xalan-J 1 has not 
+available anymore for quite some time.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">tofile</td>
+    <td valign="top">The name of the XML file that will aggregate all individual
+      XML testsuite previously generated by the JUnit task.</td>
+    <td align="center" valign="top">No. Default to TESTS-TestSuites.xml</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">The directory where should be written the file resulting
+      from the individual XML testsuite aggregation.</td>
+    <td align="center" valign="top">No. Default to current directory</td>
+  </tr>
+</table>
+<h3><a name="nested">Nested Elements</a></h3>
+<h4>fileset</h4>
+<p><code>junitreport</code> collects individual xml files generated by the JUnit
+task using the nested <a href="../CoreTypes/fileset.html"><code>&lt;FileSet&gt;</code></a>
+element.</p>
+<h4>report</h4>
+<p>Generate a browsable report based on the document created by the merge.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td width="12%" valign="top"><b>Attribute</b></td>
+    <td width="78%" valign="top"><b>Description</b></td>
+    <td width="10%" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">format</td>
+    <td valign="top">The format of the generated report. Must be &quot;noframes&quot;
+      or &quot;frames&quot;.</td>
+    <td align="center" valign="top">No, default to &quot;frames&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">styledir</td>
+    <td valign="top">The directory where the stylesheets are defined. They must
+      be conforming to the following conventions:
+      <ul>
+        <li>frames format: the stylesheet must be named <i>junit-frames.xsl</i>.</li>
+        <li>noframes format: the stylesheet must be named <i>junit-noframes.xsl</i>.</li>
+      </ul>
+    </td>
+    <td align="center" valign="top">No. Default to embedded stylesheets.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">The directory where the files resulting from the
+      transformation should be written to.</td>
+    <td align="center" valign="top">No. Default to current directory</td>
+  </tr>
+</table>
+<p> Ant assumes the following concerning the <tt>frames</tt> and <tt>noframes</tt> formats :</p>
+<p>The <tt>frames</tt> format uses
+a stylesheet which is generating output <em>only</em> by redirecting.</p>
+<p>The
+<tt>noframes</tt> format does not use redirecting and generates one
+file called <tt>junit-noframes.html</tt>.</p>
+<p>Custom versions of <tt>junit-frames.xsl</tt> or <tt>junit-noframes.xsl</tt> must adhere to the above conventions.</p>
+
+<h3>Nested Element of the report tag</h3>
+<h4>param</h4>
+<em>Since Ant 1.7</em>the report tag supports nested param tags.
+These tags can pass XSL parameters to the stylesheet.
+<h3>Parameters</h3>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">Name of the XSL parameter</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">expression</td>
+    <td valign="top">Text value to be placed into the param.<br>
+    Was originally intended to be an XSL expression.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">The param will only passed if this property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">The param will only passed unless this property is set.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<p>The built-in stylesheets support the following parameters:</p>
+<table width="60%" border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>XSL-Parameter</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">TITLE</td>
+    <td valign="top">Title used in &lt;title&gt; and &lt;h1&gt; tags</td>
+    <td align="center" valign="top">No. Defaults to <i>Unit Test Results.</i></td>
+  </tr>
+</table>
+
+
+
+<h3>Example of report</h3>
+<blockquote>
+  <pre>&lt;junitreport todir=&quot;./reports&quot;&gt;
+  &lt;fileset dir=&quot;./reports&quot;&gt;
+    &lt;include name=&quot;TEST-*.xml&quot;/&gt;
+  &lt;/fileset&gt;
+  &lt;report format=&quot;frames&quot; todir=&quot;./report/html&quot;/&gt;
+&lt;/junitreport&gt;
+</pre>
+</blockquote>
+<p>would generate a <tt>TESTS-TestSuites.xml</tt> file in the directory <tt>reports</tt> and
+generate the default framed report in the directory <tt>report/html</tt>.</p>
+<h3>Example of report with xsl params</h3>
+<blockquote>
+  <pre>
+&lt;junitreport todir="${outputdir}"&gt;
+    &lt;fileset dir="${jrdir}"&gt;
+        &lt;include name="TEST-*.xml"/&gt;
+    &lt;/fileset&gt;
+    &lt;report todir="${outputdir}/html"
+        styledir="junitreport"
+        format="frames"&gt;
+        &lt;param name="key1" expression="value1"/&gt;
+        &lt;param name="key2" expression="value2"/&gt;
+    &lt;/report&gt;
+&lt;/junitreport&gt;
+  </pre>
+  </blockquote>
+<p>This example requires a file called <tt>junitreport/junit-frames.xsl</tt>.
+    The XSL parameters key1 and key2 will be passed to the XSL transformation.</p>
+
+</body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/mimemail.html b/trunk/docs/manual/OptionalTasks/mimemail.html
new file mode 100644
index 0000000..a8652d3
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/mimemail.html
@@ -0,0 +1,115 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>MimeMail Task</title>
+</head>
+
+<body>
+
+<h2><a name="mimemail">MimeMail</a></h2>
+
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the <a href="../CoreTasks/mail.html">mail</a> task instead.</i></p>
+
+<h3>Description</h3>
+<p>Sends SMTP mail with MIME attachments.
+<a href="http://java.sun.com/products/javamail/index.html">JavaMail</a>
+and <a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">Java
+Activation Framework</a> are required for this task.</p>
+<p>Multiple files can be attached using <a href="../CoreTypes/fileset.html">FileSets.</a></p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">message</td>
+    <td valign="top">The message body</td>
+    <td valign="top" align="center" rowspan="2">No, but only one of of 'message' or
+      'messageFile' may be specified.&nbsp; If not specified, a fileset must be
+      provided.</td>
+  </tr>
+  <tr>
+    <td valign="top">messageFile</td>
+    <td valign="top">A filename to read and used as the message body</td>
+  </tr>
+  <tr>
+    <td valign="top">messageMimeType</td>
+    <td valign="top">MIME type to use for 'message' or 'messageFile' when
+      attached.</td>
+    <td align="center" valign="top">No, defaults to "text/plain"</td>
+  </tr>
+  <tr>
+    <td valign="top">tolist</td>
+    <td valign="top">Comma-separated list of To: recipients</td>
+    <td valign="top" align="center" rowspan="3">Yes, at least one of 'tolist', 'cclist',
+      or 'bcclist' must be specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">cclist</td>
+    <td valign="top">Comma-separated list of CC: recipients</td>
+    <td valign="top" align="center">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">bcclist</td>
+    <td valign="top">Comma-separated list of BCC: recipients</td>
+    <td valign="top" align="center">&nbsp;</td>
+  </tr>
+  <tr>
+    <td valign="top">mailhost</td>
+    <td valign="top">Host name of the mail server.</td>
+    <td valign="top" align="center">No, default to &quot;localhost&quot;</td>
+  </tr>
+  <tr>
+    <td valign="top">subject</td>
+    <td valign="top">Email subject line.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">from</td>
+    <td valign="top">Email address of sender.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Stop the build process if an error occurs sending the
+      e-mail.</td>
+    <td valign="top" align="center">No, default to &quot;true&quot;</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<p><b>Send a single HTML file as the body of a message</b></p>
+<pre>    &lt;mimemail messageMimeType=&quot;text/html&quot; messageFile=&quot;overview-summary.html&quot;
+        tolist=&quot;you&quot; subject=&quot;JUnit Test Results: ${TODAY}&quot; from=&quot;me&quot;/&gt;</pre>
+<p><b>Sends all files in a directory as attachments</b></p>
+<pre>    &lt;mimemail message=&quot;See attached files&quot; tolist=&quot;you&quot; subject=&quot;Attachments&quot; from=&quot;me&quot;&gt;
+        &lt;fileset dir=&quot;.&quot;&gt;
+            &lt;include name=&quot;dist/*.*&quot;/&gt;
+        &lt;/fileset&gt;
+    &lt;/mimemail&gt;
+</pre>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/native2ascii.html b/trunk/docs/manual/OptionalTasks/native2ascii.html
new file mode 100644
index 0000000..c040fe6
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/native2ascii.html
@@ -0,0 +1,212 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+  <head><link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Native2Ascii Task</title></head>
+  <body>
+    <h2>Native2Ascii</h2>
+
+    <h3>Description:</h3>
+
+    <p>
+      Converts files from native encodings to ASCII with escaped Unicode.
+      A common usage is to convert source files maintained in a native
+      operating system encoding, to ASCII prior to compilation.
+    </p>
+
+    <p>
+      Files in the directory <em>src</em>
+      are converted from a native encoding to ASCII.
+      By default, all files in the directory are converted.
+      However, conversion may be limited to selected files using
+      <em>includes</em> and <em>excludes</em> attributes.
+      For more information on file matching patterns,
+      see the section on
+      <a href="../dirtasks.html#directorybasedtasks">directory based tasks</a>.
+      If no <em>encoding</em> is specified,
+      the default encoding for the JVM is used.
+      If <em>ext</em> is specified, then output files are renamed
+      to use it as a new extension.
+      More sophisticated file name translations can be achieved using a nested
+      <em><code>&lt;mapper&gt;</code></em> element. By default an
+      <a href="../CoreTypes/mapper.html#identity-mapper">identity mapper</a> will be used.
+      If <em>dest</em> and <em>src</em> point to the same directory,
+      the <em>ext</em> attribute or a nested <em><code>&lt;mapper&gt;</code></em>
+      is required.
+    </p>
+
+    <p>
+      This task forms an implicit <a href="../CoreTypes/fileset.html">File Set</a>,
+      and supports all attributes of <code>&lt;fileset&gt;</code>
+      (<code>dir</code> becomes <code>src</code>) as well as
+      nested <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code>,
+      and <code>&lt;patternset&gt;</code> elements.
+    </p>
+
+    <p>It is possible to use different converters. This can be selected
+      with the <code>implementation</code> attribute.
+      <a name="implementationvalues">Here are the choices</a>:</p>
+    <ul>
+      <li>default - the default converter (kaffe or sun) for the platform.</li>
+      <li>sun (the standard converter of the JDK)</li>
+      <li>kaffe (the standard converter of <a href="http://www.kaffe.org" target="_top">Kaffe</a>)</li>
+    </ul>
+
+    <table border="1" cellpadding="2" cellspacing="0">
+      <tr>
+        <td><b>Attribute</b></td>
+        <td><b>Description</b></td>
+        <td><b>Required</b></td>
+      </tr>
+      <tr>
+        <td>reverse</td>
+        <td>Reverse the sense of the conversion,
+          i.e. convert from ASCII to native <b>only supported by the
+            sun converter</b></td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>encoding</td>
+        <td>The native encoding the files are in
+          (default is the default encoding for the JVM)</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>src</td>
+        <td>The directory to find files in (default is <em>basedir</em>)</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>dest</td>
+        <td>The directory to output file to</td>
+        <td align="center">Yes</td>
+      </tr>
+      <tr>
+        <td>ext</td>
+        <td>File extension to use in renaming output files</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>defaultexcludes</td>
+        <td>indicates whether default excludes should be used or not
+          (&quot;yes&quot;/&quot;no&quot;).
+          Default excludes are used when omitted.
+        </td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>includes</td>
+        <td>comma- or space-separated list of patterns of files that must be
+          included. All files are included when omitted.</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>includesfile</td>
+        <td>the name of a file. Each line of this file is
+          taken to be an include pattern</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>excludes</td>
+        <td>comma- or space-separated list of patterns of files that must be excluded.
+          No files (except default excludes) are excluded when omitted.</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td>excludesfile</td>
+        <td>the name of a file. Each line of this file is
+          taken to be an exclude pattern</td>
+        <td align="center">No</td>
+      </tr>
+      <tr>
+        <td valign="top">implementation</td>
+        <td valign="top">The converter implementation to use.
+          If this attribute is not set, the default converter for the
+          current VM will be used.  (See the above <a
+          href="#implementationvalues">list</a> of valid converters.)</td>
+        <td align="center" valign="top">No</td>
+      </tr>
+    </table>
+
+<h3>Parameters specified as nested elements</h3>
+
+<h4>arg</h4>
+
+<p>You can specify additional command line arguments for the converter
+with nested <code>&lt;arg&gt;</code> elements.  These elements are
+specified like <a href="../using.html#arg">Command-line Arguments</a>
+but have an additional attribute that can be used to enable arguments
+only if a given converter implementation will be used.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">value</td>
+    <td align="center" rowspan="4">See
+    <a href="../using.html#arg">Command-line Arguments</a>.</td>
+    <td align="center" rowspan="4">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">line</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+  </tr>
+  <tr>
+    <td valign="top">implementation</td>
+    <td>Only pass the specified argument if the chosen converter
+    implementation matches the value of this attribute.  Legal values
+    are the same as those in the above <a
+    href="#implementationvalues">list</a> of valid compilers.)</td>
+    <td align="center">No</td>
+  </tr>
+</table>
+
+    <h3>Examples</h3>
+
+    <pre>
+&lt;native2ascii encoding=&quot;EUCJIS&quot; src=&quot;srcdir&quot; dest=&quot;srcdir&quot;
+   includes=&quot;**/*.eucjis&quot; ext=&quot;.java&quot;/&gt;
+    </pre>
+
+    <p>
+      Converts all files in the directory <em>srcdir</em>
+      ending in <code>.eucjis</code> from the EUCJIS encoding to ASCII
+      and renames them to end in <code>.java</code>.
+    </p>
+
+<pre>
+&lt;native2ascii encoding=&quot;EUCJIS&quot; src=&quot;native/japanese&quot; dest=&quot;src&quot;
+   includes=&quot;**/*.java&quot;/&gt;
+</pre>
+
+    <p>
+      Converts all the files ending in <code>.java</code>
+      in the directory <em>native/japanese</em> to ASCII,
+      placing the results in the directory <em>src</em>.
+      The names of the files remain the same.
+    </p>
+  </body>
+
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/netrexxc.html b/trunk/docs/manual/OptionalTasks/netrexxc.html
new file mode 100644
index 0000000..f02e233
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/netrexxc.html
@@ -0,0 +1,330 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>NetRexxC Task</title>
+</head>
+
+<body>
+
+<h2><a name="netrexxc">NetRexxC</a></h2>
+<h3>Description</h3>
+<p>Compiles a <a href="http://www2.hursley.ibm.com/netrexx" target="_top">NetRexx</a>
+source tree within the running (Ant) VM.</p>
+<p>The source and destination directory will be recursively scanned for
+NetRexx source files to compile.  Only NetRexx files that have no corresponding
+class file or where the class file is older than the java file will be compiled.</p>
+<p>Files in the source tree are copied to the destination directory,
+allowing support files to be located properly in the classpath. The source
+files are copied because the NetRexx compiler cannot produce class files in a
+specific directory via parameters</p>
+<p>The directory structure of the source tree should follow the package
+hierarchy.</p>
+<p>It is possible to refine the set of files that are being compiled/copied.
+This can be done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and
+<i>defaultexcludes</i> attributes. With the <i>includes</i> or <i>includesfile</i> attribute you
+specify the files you want to have included by using patterns. The
+<i>exclude</i> or <i>excludesfile</i> attribute is used to specify the files you want to have
+excluded.  This is also done with patterns.  And finally with the
+<i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+<p>This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>srcdir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<p>All properties except classpath, srcdir and destDir are also available as properties in the form
+<code>ant.netrexxc.<i>attributename</i></code>, eg.<br>
+<code>&lt;property name="ant.netrexxc.verbose" value="noverbose"/&gt;</code><br>
+or from the command line as<br>
+<code>ant -Dant.netrexxc.verbose=noverbose ...</code>
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">binary</td>
+    <td valign="top">Whether literals are treated as the java binary
+      type rather than the NetRexx types</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to use during compilation</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">comments</td>
+    <td valign="top">Whether comments are passed through to the
+      generated java source</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compact</td>
+    <td valign="top">Whether error messages come out in compact or
+      verbose format. Default is the compact format.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">compile</td>
+    <td valign="top">Whether the NetRexx compiler should compile the
+      generated java code</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">console</td>
+    <td valign="top">Whether or not messages should be displayed on the
+      'console'</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">crossref</td>
+    <td valign="top">Whether variable cross references are generated</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">decimal</td>
+    <td valign="top">Whether decimal arithmetic should be used for the
+      NetRexx code</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when
+      omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">destDir</td>
+    <td valign="top">the destination directory into which the NetRexx
+      source files should be copied and then compiled</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">diag</td>
+    <td valign="top">Whether diagnostic information about the compile is
+      generated</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when
+      omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">explicit</td>
+    <td valign="top">Whether variables must be declared explicitly
+      before use</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">format</td>
+    <td valign="top">Whether the generated java code is formatted nicely
+      or left to match NetRexx line numbers for call stack debugging</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">java</td>
+    <td valign="top">Whether the generated java code is produced</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">keep</td>
+    <td valign="top">Sets whether the generated java source file should be kept
+      after compilation. The generated files will have an extension of
+      .java.keep, <b>not</b> .java</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">logo</td>
+    <td valign="top">Whether the compiler text logo is displayed when
+      compiling</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">replace</td>
+    <td valign="top">Whether the generated .java file should be replaced
+      when compiling</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">savelog</td>
+    <td valign="top">Whether the compiler messages will be written to
+      NetRexxC.log as well as to the console</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">sourcedir</td>
+    <td valign="top">Tells the NetRexx compiler to store the class files in the
+      same directory as the source files. The alternative is the working
+      directory</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">srcDir</td>
+    <td valign="top">Set the source dir to find the source NetRexx
+      files</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">strictargs</td>
+    <td valign="top">Tells the NetRexx compiler that method calls always
+      need parentheses, even if no arguments are needed, e.g.
+      <code>aStringVar.getBytes</code> vs.
+      <code>aStringVar.getBytes()</code></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strictassign</td>
+    <td valign="top">Tells the NetRexx compile that assignments must
+      match exactly on type</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strictcase</td>
+    <td valign="top">Specifies whether the NetRexx compiler should be
+      case sensitive or not</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strictimport</td>
+    <td valign="top">Whether classes need to be imported explicitly using an
+      <code>import</code> statement.  By default the NetRexx compiler will
+      import certain packages automatically</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strictprops</td>
+    <td valign="top">Whether local properties need to be qualified
+      explicitly using <code>this</code></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">strictsignal</td>
+    <td valign="top">Whether the compiler should force catching of
+      exceptions by explicitly named types</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">symbols</td>
+    <td valign="top">Whether debug symbols should be generated into the
+      class file</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">time</td>
+    <td valign="top">Asks the NetRexx compiler to print compilation
+      times to the console</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">trace</td>
+    <td valign="top">Turns on or off tracing and directs the resultant
+      trace output</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">utf8</td>
+    <td valign="top">Tells the NetRexx compiler that the source is in UTF8</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Whether lots of warnings and error messages should
+      be generated</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressMethodArgumentNotUsed</td>
+    <td valign="top">Tells whether we should filter out the
+      &amp;Method argument not used&amp; messages in strictargs mode.</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressPrivatePropertyNotUsed</td>
+    <td valign="top">Tells whether we should filter out the
+      &amp;Private Property defined, but not used&amp; messages in strictargs mode.</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressVariableNotUsed</td>
+    <td valign="top">Tells whether we should filter out the
+      &amp;Variable set but not used&amp; messages in strictargs mode.
+      Please be careful with this one, as you can hide errors behind it!</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressExceptionNotSignalled</td>
+    <td valign="top">Tells whether we should filter out the
+      &amp;Exception is declared, but not signaled within the method&amp;
+      messages in strictsignal mode.</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">suppressDeprecation</td>
+    <td valign="top">Tells whether we should filter out any deprecation-messages
+      of the compiler out.</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <p><code>&lt;netrexxc srcDir=&quot;/source/project&quot;
+           includes=&quot;vnr/util/*&quot;
+           destDir=&quot;/source/project/build&quot;
+           classpath=&quot;/source/project2/proj.jar&quot;
+           comments=&quot;true&quot;
+           crossref=&quot;false&quot; replace=&quot;true&quot;
+           keep=&quot;true&quot;/&gt;</code>
+  </p>
+</blockquote>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/perforce.html b/trunk/docs/manual/OptionalTasks/perforce.html
new file mode 100644
index 0000000..8655b3a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/perforce.html
@@ -0,0 +1,1006 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Perforce Tasks</title>
+</head>
+<body>
+<h1>Perforce Tasks User Manual</h1>
+<p>by</p>
+<ul>
+    <li>Les Hughes (<a href="mailto:leslie.hughes@rubus.com">leslie.hughes@rubus.com</a>)</li>
+    <li>Kirk Wylie (<a href="mailto:kirk@radik.com">kirk@radik.com</a>)</li>
+    <li>Matt Bishop (<a href="mailto:matt@thebishops.org">matt@thebishops.org</a>)</li>
+    <li>Antoine Levy-Lambert</li>
+</ul>
+<hr>
+<h2>Contents</h2>
+<ul>
+    <li><a href="#intro">Introduction</a></li>
+    <li><a href="#tasks">The Tasks</a></li>
+    <li><a href="#changes">Change History</a></li>
+</ul>
+<br>
+<h2><a name="intro">Introduction</a></h2>
+<p>These tasks provide an interface to the <a href="http://www.perforce.com" target="_top">Perforce</a> SCM.
+The <code>org.apache.tools.ant.taskdefs.optional.perforce</code> package consists of a simple framework to support 
+p4 functionality as well as some Ant tasks encapsulating frequently used (by me :-) p4 commands. 
+However, the addition of new p4 commands is a pretty simple task (see the source). 
+Although it is possible to use these commands on the desktop, 
+they were primarily intended to be used by automated build systems.</p>
+
+<p><b>Note:</b> These tasks require the <a href="http://jakarta.apache.org/oro" target="_top">oro</a> regular
+expression package. See <a href="../install.html#librarydependencies">library dependencies</a> for the precise
+version required.
+You will also need the Perforce client executable (p4 or p4.exe but not p4win.exe) in your path.
+</p>
+
+
+
+<h2><a name="tasks">The Tasks</a></h2>
+
+<table border="0" cellspacing="0" cellpadding="3">
+    <tr>
+      <td><b>Task</b></td>
+      <td><b>Description</b></td>
+    </tr>
+    <tr>
+        <td><a href="#p4sync">P4Sync</a></td>
+        <td>Synchronise a workspace to a depot</td>
+    </tr>
+    <tr>
+        <td><a href="#p4change">P4Change</a></td>
+        <td>Request a new changelist from the Perforce server</td>
+    </tr>
+    <tr>
+        <td><a href="#p4edit">P4Edit</a></td>
+        <td>Open files for edit (checkout)</td>
+    </tr>
+    <tr>
+        <td><a href="#p4submit">P4Submit</a></td>
+        <td>Submit a changelist to the Perforce server (checkin)</td>
+    </tr>
+    <tr>
+        <td><a href="#p4have">P4Have</a></td>
+        <td>List current files in client view, useful for reporting</td>
+    </tr>
+    <tr>
+        <td><a href="#p4label">P4Label</a></td>
+        <td>Create a label reflecting files in the current workspace</td>
+    </tr>
+    <tr>
+        <td><a href="#p4labelsync">P4Labelsync</a></td>
+        <td>Syncs an existing label</td>
+    </tr>
+    <tr>
+        <td><a href="#p4counter">P4Counter</a></td>
+        <td>Obtain or set the value of a counter</td>
+    </tr>
+	    <tr>
+        <td><a href="#p4reopen">P4Reopen</a></td>
+        <td>Move files between changelists</td>
+    </tr>
+
+	    <tr>
+        <td><a href="#p4revert">P4Revert</a></td>
+        <td>Revert files</td>
+    </tr>
+	    
+    <tr>
+        <td><a href="#p4add">P4Add</a></td>
+        <td>Add files</td>
+    </tr>
+    <tr>
+      <td><a href="#p4delete">P4Delete</a></td>
+      <td>Delete files</td>
+    </tr>
+    <tr>
+      <td><a href="#p4integrate">P4Integrate</a></td>
+      <td>Integrate files</td>
+    </tr>
+    <tr>
+      <td><a href="#p4resolve">P4Resolve</a></td>
+      <td>Resolve files</td>
+    </tr>
+    <tr>
+        <td><a href="#p4fstat">P4Fstat</a></td>
+        <td>Show differences between local repository and p4 repository</td>
+    </tr>
+</table>
+
+<h3>General P4 Properties</h3>
+<p>Each p4 task requires a number of settings, either through build-wide properties, individual attributes 
+or environment variables. These are
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Property</b></td>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Env Var</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Default</b></td>
+  </tr>
+  <tr>
+    <td valign="top">p4.port</td>
+    <td valign="top">port</td>
+    <td valign="top">P4PORT</td>
+    <td valign="top">The p4d server and port to connect to</td>
+    <td valign="top">perforce:1666</td>
+  </tr>
+  <tr>
+    <td valign="top">p4.client</td>
+    <td valign="top">client</td>
+    <td valign="top">P4CLIENT</td>
+    <td valign="top">The p4 client spec to use</td>
+    <td valign="top">The logged in username</td>
+  </tr>
+  <tr>
+    <td valign="top">p4.user</td>
+    <td valign="top">user</td>
+    <td valign="top">P4USER</td>
+    <td valign="top">The p4 username</td>
+    <td valign="top">The logged in username</td>
+  </tr>
+<tr>
+    <td valign="top" align="center">--</td>
+    <td valign="top">view</td>
+    <td valign="top" align="center">--</td>
+    <td valign="top">The client, branch or label view to operate upon. See the p4 user guide for more info.</td>
+    <td valign="top">//...</td>
+  </tr>
+
+</table>
+<p> Your local installation of Perforce may require other settings (e.g.
+P4PASSWD, P4CONFIG). Many of these settings can be set using the globalopts
+attribute (described below), but not all. If a setting cannot be set
+by the command-line options, then it can only be set outside of Ant as an 
+environment variable.
+</p>
+<p>
+Additionally, you may also specify the following attributes:
+</p>
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td valign="top"><b>Attribute</b></td>
+  <td valign="top"><b>Description</b></td>
+  <td align="center" valign="top"><b>Required</b></td>
+</tr>
+<tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">Specifies whether to stop the build
+     (<code>true</code>|<code>yes</code>|<code>on</code>)
+     or keep going (<code>false</code>|<code>no</code>|<code>off</code>)
+     if an error is returned from the p4 command.</td>
+    <td valign="top">No; defaults to true.</td>
+  </tr>
+  <tr>
+      <td valign="top">globalopts<br></td>
+      <td valign="top">Specifies global options for perforce to use while
+      executing the task. These properties should be concatenated into one
+      string,<br>
+      such as "-P <i>password</i> -C EUCJIS". Use the command-line option
+      syntax, NOT the environment variable names. See the<br>
+      Perforce Command Reference for details.</td>
+      <td valign="top">No<br></td>
+  </tr>
+</table>
+</p>
+
+<h3>Examples</h3>
+<p>Setting in the environment:-</p>
+<p>
+(Unix csh)</p>
+<pre>setenv P4PORT myperforcebox:1666</pre>
+<p>(Unix sh et al)</p>
+<pre>P4USER=myp4userid; export P4USER</pre>
+<p>Using build properties:-</p>
+<pre>&lt;property name=&quot;p4.client&quot; value=&quot;nightlybuild&quot;/&gt;</pre>
+<p>Using task attributes:-</p>
+<pre>
+&lt;p4Whatever
+	port=&quot;myserver:1666&quot;
+	client=&quot;smoketest&quot;
+	user=&quot;smoketestdude&quot;
+	.
+	.
+	.
+/&gt;
+</pre>
+
+<p>
+For more information regarding the underlying 'p4' commands you are referred to the Perforce Command Reference
+available from the <a href="http://www.perforce.com/" target="_top">Perforce website</a>.
+</p>
+
+
+<hr>
+<h2>Task Descriptions</h2>
+<h2><a name="p4sync">P4Sync</a></h2>
+<h3>Description:</h3>
+<p>Synchronize the current workspace with the depot.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">force</td>
+    <td valign="top">force a refresh of files, if this attribute has
+    been set.</td>
+    <td valign="top" align="center">no - if omitted, it will be off,
+    otherwise a refresh will be forced.</td>
+  </tr>
+<tr>
+    <td valign="top">label</td>
+    <td valign="top">sync client to label</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>&lt;p4sync label=&quot;nightlybuild-0.0123&quot; force=&quot;foo&quot;/&gt;
+&lt;p4sync view=&quot;//depot/projects/projectfoo/main/src/...&quot;/&gt;
+</pre>
+<hr>
+
+
+
+<h2><a name="p4change">P4Change</a></h2>
+<h3>Description:</h3>
+<p>Request a new changelist from the Perforce server. 
+This task sets the ${p4.change} property which can then be passed to <A HREF="#p4submit">P4Submit</A>,
+<A HREF="#p4edit">P4Edit</A>, or <a HREF="#p4add">P4Add</A>, or <a HREF="#p4delete">P4Delete</A>,
+then to <A HREF="#p4submit">P4Submit</A>.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">description</td>
+    <td valign="top">Description for ChangeList. If none specified, it will
+                     default to "AutoSubmit By Ant"</td>
+    <td valign="top" align="center">No.</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>&lt;p4change description="Change Build Number in Script"&gt;
+</pre>
+<hr>
+
+
+
+
+<h2><a name="p4edit">P4Edit</a></h2>
+<h3>Description:</h3>
+<p>Open file(s) for edit. P4Change should be used to obtain a new changelist for P4Edit as,
+although P4Edit can open files to the default change,  P4Submit cannot yet submit it.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">view</td>
+    <td valign="top">The filespec to request to edit</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">change</td>
+    <td valign="top">An existing changelist number to assign files to.</td>
+    <td valign="top" align="center">No, but see above.</td>
+  </tr>
+
+</table>
+
+<h3>Examples</h3>
+<pre>
+&lt;p4edit
+    view=&quot;//depot/projects/projectfoo/main/src/Blah.java...&quot;
+    change=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+
+
+
+
+<h2><a name="p4submit">P4Submit</a></h2>
+<h3>Description:</h3>
+<p>Submit a changelist, usually obtained from P4Change.
+<p>P4Submit will also change the value of the property p4.change if the change list is renamed by the Perforce server.
+<p>P4Submit will set a property p4.needsresolve to 1 if the change could not be submitted due to files needing resolving.
+<p>Files will need resolve if at the time of checking in, the revision that was checked out to do the current edit
+is not the latest any more.
+<p>If no files need resolve, the p4.needsresolve will be set to 0.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">change</td>
+    <td valign="top">The changelist number to submit</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">changeproperty</td>
+    <td valign="top">Name of a property to which the new change number
+    will be assigned if the Perforce server renumbers the change<br>
+    Since ant 1.6.1</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">needsresolveproperty</td>
+    <td valign="top">Name of property which will be set to <code>true</code>
+    if the submit requires a resolve<br>
+    Since ant 1.6.1</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>&lt;p4submit change=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+
+
+
+
+<h2><a name="p4have">P4Have</a></h2>
+<h3>Description:</h3>
+<p>List handy file info reflecting the current client contents.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">None</td>
+    <td valign="top" align="center">--</td>
+    <td valign="top" align="center">--</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>&lt;p4have/&gt;
+</pre>
+<hr>
+
+
+
+
+<h2><a name="p4label">P4Label</a></h2>
+<h3>Description:</h3>
+<p>Create a new label and set contents to reflect current client file revisions.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the label</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">view</td>
+    <td valign="top">client view to use for label<br>
+    The view can contain multiple lines separated by ; or :</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">desc</td>
+    <td valign="top">Label Description</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">lock</td>
+    <td valign="top">Lock the label once created.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+
+
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;p4label
+	name=&quot;NightlyBuild:${DSTAMP}:${TSTAMP}&quot; 
+	desc=&quot;Auto Nightly Build&quot;
+	lock=&quot;locked&quot;
+	view=&quot;//firstdepot/...;//secondepot/foo/bar/...&quot;
+/&gt;
+</pre>
+<hr>
+
+
+<h2><a name="p4labelsync">P4Labelsync</a></h2>
+<h3>Description:</h3>
+<p>Syncs an existing label against the current workspace or against specified revisions.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+    <td align="center" valign="top"><b>Perforce command line flag</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the label</td>
+    <td valign="center" align="center">Yes</td>
+    <td valign="top" align="center">-l labelname</td>
+  </tr>
+  <tr>
+    <td valign="top">view</td>
+    <td valign="top">
+    list of files or revision specs separated by : or ;<br>
+    in the absence of this attribute, the labelsync will be done against the current Perforce client or the value of the p4client attribute or the value of the p4.client property or the value of the environment variable P4CLIENT</td>
+    <td valign="center" align="center">No</td>
+    <td valign="center" align="center">file[revRange] ... </td>
+  </tr>
+  <tr>
+    <td valign="top">simulationmode</td>
+    <td valign="top">Displays which effect the operation would have on the label but do not actually do it</td>
+    <td valign="center" align="center">No</td>
+    <td valign="top" align="center">-n</td>
+  </tr>
+  <tr>
+    <td valign="top">add</td>
+    <td valign="top">If set to true, preserve files which exist in the label, but not in the current view</td>
+    <td valign="center" align="center">No</td>
+    <td valign="top" align="center">-a</td>
+  </tr>
+  <tr>
+    <td valign="top">delete</td>
+    <td valign="top">If set to true, remove from the label the files mentioned in the view attribute</td>
+    <td valign="center" align="center">No</td>
+    <td valign="top" align="center">-d</td>
+  </tr>
+
+
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;
+p4labelsync
+name=&quot;current_release&quot;
+view="//depot/...#head;//depot2/file1#25"
+add=&quot;true&quot;
+/&gt;
+</pre>
+This example will add into the label called <i>current_release</i> the current head revision of all the files located under <i>//depot</i>
+and the revision 25 of the file <i>//depot2/file1</i>.
+<pre>
+&lt;
+p4labelsync
+name=&quot;current_release&quot;
+p4client=&quot;myclient&quot;
+/&gt;
+</pre>
+This example will update the label called <i>current_release</i> so that it reflects the Perforce client <i>myclient</i>.<br>
+Files present in the label before the sync and not present currently in the client will be removed from the label, because the add attribute is not set.
+<pre>
+&lt;
+p4labelsync
+name=&quot;current_release&quot;
+/&gt;
+</pre>
+This example will update the label called <i>current_release</i> so that it reflects the current default client for the ant Perforce tasks.<br>
+The default client is by order of priority :
+<ul>
+<li>
+the value of the p4.client property if set in the project
+</li>
+<li>
+the value of the P4CLIENT environment variable
+</li>
+<li>
+the default Perforce client from the Windows registry under Windows operating systems
+</li>
+</ul>
+Files present in the label before the sync and not present currently in the client will be removed from the label, because the add attribute is not set.
+<hr>
+
+
+<h2><a name="p4counter">P4Counter</a></h2>
+<h3>Description:</h3>
+<p>
+Obtain or set the value of a counter. When used in its base form
+(where only the counter name is provided), the counter value will be
+printed to the output stream. When the value is provided, the counter
+will be set to the value provided. When a property name is provided,
+the property will be filled with the value of the counter. You may
+not specify to both get and set the value of the counter in the same
+Task.
+</p>
+<P>
+The user performing this task must have Perforce &quot;review&quot; permissions
+as defined by Perforce protections in order for this task to succeed.
+</P>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the counter</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The new value for the counter</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">property</td>
+    <td valign="top">The property to be set with the value of the counter</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+Print the value of the counter named &quot;last-clean-build&quot; to the output stream:
+<pre>
+&lt;p4counter name=&quot;last-clean-build&quot;/&gt;
+</PRE>
+Set the value of the counter based on the value of the &quot;TSTAMP&quot; property:
+<PRE>
+&lt;p4counter name=&quot;last-clean-build&quot; value=&quot;${TSTAMP}&quot;/&gt;
+</PRE>
+Set the value of the &quot;p4.last.clean.build&quot; property to the current
+value of the &quot;last-clean-build&quot; counter:
+<PRE>
+&lt;p4counter name=&quot;last-clean-build&quot; property=&quot;p4.last.clean.build&quot;/&gt;
+</pre>
+<hr>
+
+
+
+
+<h2><a name="p4reopen">P4Reopen</a></h2>
+<h3>Description:</h3>
+<p>
+Move (or reopen in Perforce speak) checkout files between changelists.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">tochange</td>
+    <td valign="top">The changelist to move files to.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+Move all open files to the default changelist
+<pre>
+&lt;p4reopen view=&quot;//...&quot; tochange=&quot;default&quot;/&gt;
+</PRE>
+Create a new changelist then reopen into it, any files from the view //projects/foo/main/...
+<PRE>
+&lt;p4change description="Move files out of the way"/&gt;
+&lt;p4reopen view=&quot;//projects/foo/main/...&quot; tochange=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+
+
+
+<h2><a name="p4revert">P4Revert</a></h2>
+<h3>Description:</h3>
+<p>
+Reverts files.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">change</td>
+    <td valign="top">The changelist to revert.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">revertOnlyUnchanged</td>
+    <td valign="top">Revert only unchanged files (p4 revert -a)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  
+</table>
+
+<h3>Examples</h3>
+Revert everything!
+<pre>
+&lt;p4revert view=&quot;//...&quot;/&gt;
+</PRE>
+Revert any unchanged files in the default change
+<PRE>
+&lt;p4revert change="default" revertonlyunchanged=&quot;true&quot;/&gt;
+</pre>
+<hr>
+
+<h2><a name="p4add">P4Add</a></h2>
+<h3>Description:</h3>
+<p>
+Adds files specified in nested fileset children.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">commandlength</td>
+    <td valign="top">A positive integer specifying the maximum length
+        of the commandline when calling Perforce to add the files. 
+        Defaults to 450, higher values mean faster execution,
+        but also possible failures.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">changelist</td>
+    <td valign="top">If specified the open files are associated with the
+specified pending changelist number; otherwise the open files are
+associated with the default changelist.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  
+</table>
+
+<h3>Examples</h3>
+Require a changelist, add all java files starting from a directory,
+and submit
+
+<pre>
+&lt;p4change/&gt;
+&lt;p4add commandlength=&quot;20000&quot; changelist=&quot;${p4.change}&quot;&gt;
+    &lt;fileset dir=&quot;../dir/src/&quot; includes=&quot;**/*.java&quot;/&gt;
+&lt;p4add&gt;
+&lt;p4submit change=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+
+<h2><a name="p4fstat">P4Fstat</a></h2>
+<h3>Description:</h3>
+<p>
+Lists files under Perforce control and files not under Perforce control in one or several filesets
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">showfilter</td>
+    <td valign="top">should be one of
+      <table border="1">
+        <tr><td>value</td><td>description</td></tr>
+        <tr><td>&quot;all&quot;</td><td>list all files, first the ones which are under Perforce control, then the others</td></tr>
+        <tr><td>&quot;existing&quot;</td><td>list only files under Perforce control</td></tr>
+        <tr><td>&quot;non-existing&quot;</td><td>list only files which are not under Perforce control</td></tr></table>
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">fileset</td>
+    <td valign="top">one or several <a href="../CoreTypes/fileset.html">fileset(s)</a></td>
+    <td valign="top" align="center">yes (at least one fileset is needed)</td>
+  </tr>
+</table>
+Several nested filesets can be used with P4Fstat, one should be there at least.
+<h3>Examples</h3>
+will list all the files under C:\dev\gnu\depot, sorted by under Perforce or not under Perforce<br>
+<pre>
+&lt;project name=&quot;p4fstat&quot; default=&quot;p4fstat&quot; basedir=&quot;C:\dev\gnu&quot;&gt;
+    &lt;target name=&quot;p4fstat&quot; &gt;
+        &lt;p4fstat showfilter=&quot;all&quot;&gt;
+            &lt;fileset dir=&quot;depot&quot; includes=&quot;**/*&quot;/&gt;
+        &lt;/p4fstat&gt;
+    &lt;/target&gt;
+&lt;/project&gt;</p>
+</pre>
+
+
+
+
+<h2><a name="p4delete">P4Delete</a></h2>
+<h3>Description:</h3>
+<p>Open file(s) for delete. P4Change should be used to obtain a new changelist for P4Delete as,
+although P4Delete can open files to the default change,  P4Submit cannot yet submit it.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">view</td>
+    <td valign="top">The filespec to request to delete</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">change</td>
+    <td valign="top">An existing changelist number to assign files to.</td>
+    <td valign="top" align="center">No, but see above.</td>
+  </tr>
+
+</table>
+
+<h3>Examples</h3>
+<pre>
+&lt;p4delete
+    view=&quot;//depot/projects/projectfoo/main/src/Blah.java...&quot;
+    change=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+<h2><a name="p4integrate">P4Integrate</a></h2>
+<h3>Description:</h3>
+<p>Open file(s) for integrate. P4Change should be used to obtain a new changelist for P4Integrate as,
+although P4Integrate can open files to the default change,  P4Submit cannot yet submit it.
+</p>
+<h3>Parameters</h3>
+<p>If this task is used without using a branch definition, both fromfile and tofile must be supplied.
+If a branch definition is supplied, at least one of fromfile or tofile should be supplied.
+Both fromfile and tofile can be supplied together with a branch definition.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+    <td align="center" valign="top"><b>Perforce command line flag</b></td>
+  </tr>
+  <tr>
+    <td valign="top">fromfile</td>
+    <td valign="top">Original file or view</td>
+    <td valign="top" align="center">required if a branch is not specified</td>
+    <td valign="top" align="center"></td>
+  </tr>
+  <tr>
+    <td valign="top">tofile</td>
+    <td valign="top">Target file or view.</td>
+    <td valign="top" align="center">required if a branch is not specified</td>
+    <td valign="top" align="center"></td>
+  </tr>
+  <tr>
+    <td valign="top">branch</td>
+    <td valign="top">Name of branch specification</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-b</td>
+  </tr>
+  <tr>
+    <td valign="top">change</td>
+    <td valign="top">An existing changelist number to assign files to.</td>
+    <td valign="top" align="center">No, but see above.</td>
+    <td valign="top" align="center">-c</td>
+  </tr>
+  <tr>
+    <td valign="top">forceintegrate</td>
+    <td valign="top">Forces integration regardless of previous integration history (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-f</td>
+  </tr>
+  <tr>
+    <td valign="top">restoredeletedrevisions</td>
+    <td valign="top">Enables integration around deleted revisions (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-d</td>
+  </tr>
+  <tr>
+    <td valign="top">leavetargetrevision</td>
+    <td valign="top">Prevents target files from being synced to head revision before integration (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-h</td>
+  </tr>
+  <tr>
+    <td valign="top">enablebaselessmerges</td>
+    <td valign="top">Forces integration to existing target files which have no integration history relative to the source files (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-i</td>
+  </tr>
+  <tr>
+    <td valign="top">simulationmode</td>
+    <td valign="top">Displays which integrations are necessary but do not actually schedule them (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-n</td>
+  </tr>
+  <tr>
+    <td valign="top">reversebranchmappings</td>
+    <td valign="top">Reverses mappings in the branch view, with source and target files exchanging place (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-r</td>
+  </tr>
+  <tr>
+    <td valign="top">propagatesourcefiletype</td>
+    <td valign="top">Makes source file type propagate to existing target files (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-t</td>
+  </tr>
+  <tr>
+    <td valign="top">nocopytargetfiles</td>
+    <td valign="top">Prevents the physical delivery on disk of new target files (*)</td>
+    <td valign="center">No</td>
+    <td valign="top" align="center">-v</td>
+  </tr>
+</table>
+<br>
+(*) The following applies for a number of flags. The default is false. To set the flag, use  &quot;true&quot;
+
+<h3>Examples</h3>
+<pre>
+&lt;p4integrate
+    fromfile=&quot;//depot/projects/projectfoo/main/src/Blah.java...&quot;
+    tofile=&quot;//depot/projects/projectfoo/release/src/Blah.java...&quot;
+    change=&quot;${p4.change}&quot;/&gt;
+</pre>
+<hr>
+<h2><a name="p4resolve">P4Resolve</a></h2>
+<h3>Description:</h3>
+<p>Resolves files. You want to do this if :
+<ul>
+<li>
+there have been or there may be concurrent edits of the same file. For instance, you have begun to edit a file, and while you were working on it, somebody has submitted a new version  of the same file. When you first attempt to submit your file(s), you will get a message (property p4.needsresolve set).
+</li>
+<li>
+you have just been doing an integration to existing target files
+</li>
+</ul>
+P4Resolve does not use a change list number (it takes it from the files it is working on).
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+    <td align="center" valign="top"><b>Perforce command line flag</b></td>
+  </tr>
+  <tr>
+    <td valign="top">view</td>
+    <td valign="top">The filespec to request to delete</td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center"></td>
+   </tr>
+  <tr>
+    <td valign="top">resolvemode</td>
+    <td valign="top">Should have one of these values :
+      <ul>
+        <li>&quot;automatic&quot;</li>
+        <li>&quot;force&quot;</li>
+        <li>&quot;safe&quot;</li>
+        <li>&quot;theirs&quot;</li>
+        <li>&quot;yours&quot;</li>
+      </ul></td>
+    <td valign="top" align="center">Yes</td>
+    <td valign="top" align="center">corresponds to one of -am -af -as -at -ay </td>
+  </tr>
+  <tr>
+    <td valign="top">redoall</td>
+    <td valign="top">allows previously resolved files to be resolved again (*)</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">-f</td>
+  </tr>
+  <tr>
+    <td valign="top">simulationmode</td>
+    <td valign="top">Lists the integrations which would be performed, without actually doing them. (*)</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">-n</td>
+  </tr>
+  <tr>
+    <td valign="top">forcetextmode</td>
+    <td valign="top">Attempts a textual merge, even for binary files (*)</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">-t</td>
+  </tr>
+  <tr>
+    <td valign="top">markersforall</td>
+    <td valign="top">Puts in markers for all changes, conflicting or not (*)</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">-v</td>
+  </tr>
+</table>
+<br>
+(*) The following applies for a number of flags. The default is false. To set the flag, use  &quot;true&quot;
+
+<h3>Examples</h3>
+<pre>
+&lt;p4resolve
+    view=&quot;//depot/projects/projectfoo/main/src/Blah.java...&quot;
+    resolvemode=&quot;automatic&quot;/&gt;
+</pre>
+
+<h2><a name="changes">Change History</a></h2>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+    <td valign="top">Sept 2000</td>
+    <td valign="top" align="center">--</td>
+    <td valign="top">Internal Release within Rubus</td>
+</tr>
+
+<tr>
+    <td valign="top">Nov 2000</td>
+    <td valign="top">V1.0</td>
+    <td valign="top">Initial Release donated to ASF :-)</td>
+</tr>
+<tr>
+    <td valign="top">Jan 2001</td>
+    <td valign="top">V1.1</td>
+    <td valign="top">Fixed cross platform (NT/Unix) bug<br>
+    Refactored p4 output handling code<br>
+    Refactored exec'ing code</td>    
+</tr>
+<tr>
+    <td valign="top">Jan 2003</td>
+    <td valign="top">V1.2</td>
+    <td valign="top">Added globalopts to P4Base to allow 
+                     additional global options to be set.<br>
+                     Added p4fstat task</td>
+</tr>
+<tr>
+    <td valign="top">May 2003</td>
+    <td valign="top">V1.3</td>
+    <td valign="top">Added p4labelsync, p4resolve, p4integrate.<br>
+                     Changed p4submit (detection of changes of change numbers,
+                     and of failed submits due to resolution needed)</td>
+</tr>
+<tr>
+    <td valign="top">Jan 2004</td>
+    <td valign="top">ant 1.6.1</td>
+    <td valign="top">
+Changed p4submit, needsresolveproperty and changeproperty added</td>
+</tr>
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/propertyfile.html b/trunk/docs/manual/OptionalTasks/propertyfile.html
new file mode 100644
index 0000000..b573983
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/propertyfile.html
@@ -0,0 +1,206 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PropertyFile Task</title>
+</head>
+
+<body>
+
+<h1>PropertyFile</h1>
+<p>by</p>
+<!-- Names are in alphabetical order, on last name -->
+<ul>
+  <li>Thomas Christen (<a href="mailto:chr@active.ch">chr@active.ch</a>)</li>
+  <li>Jeremy Mawson (<a href="mailto:jem@loftinspace.com.au">jem@loftinspace.com/au</a>)</li>
+</ul>
+
+<hr>
+<h2>Table of Contents</h2>
+<ul>
+  <li><a href="#introduction">Introduction</a></li>
+  <li><a href="#proptask">PropertyFile Task</a></li>
+  <li><a href="#entryElement">Entry Task</a></li>
+</ul>
+
+<hr>
+<h2><a name="introduction">Introduction</a></h2>
+<p>Ant provides an optional task for editing property files.  This is very useful
+when wanting to make unattended modifications to configuration files for application
+servers and applications.  Currently, the task maintains a working property file with
+the ability to add properties or make changes to existing ones.  However, any comments
+are lost.</p>
+
+<hr>
+<h2><a name="proptask">PropertyFile Task</a></h2>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+<tr>
+  <td width="12%" valign="top">file</td>
+  <td width="78%" valign="top">Location of the property file to be edited</td>
+  <td width="10%" valign="top">Yes</td>
+</tr>
+<tr>
+  <td width="12%" valign="top">comment</td>
+  <td width="78%" valign="top">Header for the file itself</td>
+  <td width="10%" valign="top">no</td>
+</tr>
+</table>
+
+<h3>Parameters specified as nested elements</h3>
+<h4><a name="entryElement">Entry</a></h4>
+<p>Use nested <code>&lt;entry&gt;</code>
+elements to specify actual modifications to the property file itself.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">key</td>
+    <td valign="top">Name of the property name/value pair</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">Value to set (=), to add (+) or subtract (-)</td>
+    <td valign="top" align="center" rowspan="2">At least one must be specified</td>
+  </tr>
+  <tr>
+    <td valign="top">default</td>
+    <td valign="top">Initial value to set for a property if it is not
+                     already defined in the property file.<br>
+                     For type date, an additional keyword is allowed: &quot;now&quot;</td>
+    </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">Regard the value as : int, date or string (default)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">operation</td>
+    <td valign="top">&quot;+&quot; or &quot;=&quot; (default) for all datatypes<br>&quot;-&quot; (for date and int only).<br>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">pattern</td>
+    <td valign="top">For int and date type only. If present, Values will
+                     be parsed and formatted accordingly.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unit</td>
+    <td valign="top">The unit of the value to be applied to date +/- operations.
+                     Valid Values are:
+                     <ul>
+                        <li>millisecond</li>
+                        <li>second</li>
+                        <li>minute</li>
+                        <li>hour</li>
+                        <li>day (default)</li>
+                        <li>week</li>
+                        <li>month</li>
+                        <li>year</li>
+                     </ul>
+                     This only applies to date types using a +/- operation.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<p>The rules used when setting a property value are shown below.&nbsp; The
+operation occurs <b>after</b> these rules are considered.</p>
+
+<ul>
+  <li>If only value is specified, the property is set to it regardless of its
+  previous value.</li>
+  <li>If only default is specified and the property previously existed in the
+  property file, it is unchanged.</li>
+  <li>If only default is specified and the property did not exist in the
+  property file, the property is set to default.</li>
+  <li>If value and default are both specified and the property previously
+  existed in the property file, the property is set to value.</li>
+  <li>If value and default are both specified and the property did not exist in
+  the property file, the property is set to default.</li>
+</ul>
+<p>&nbsp;</p>
+
+<h3>Examples</h3>
+
+<p>The following changes the my.properties file.  Assume my.properties look like:</p>
+
+<pre># A comment
+akey=novalue</pre>
+
+<p>After running, the file would now look like
+</p>
+<pre>#Thu Nov 02 23:41:47 EST 2000
+akey=avalue
+adate=2000/11/02 23\:41
+anint=1
+formated.int=0014
+formated.date=028 17\:34
+</pre>
+<p>
+The slashes conform to the expectations of the Properties class.  The file will be stored in a manner so that each character is examined and escaped if necessary.  Note that the original comment is now lost.  Please keep this in mind when running this task against heavily commented properties files.  It may be best to have a commented version in the source tree, copy it to a deployment area, and then run the modifications on the copy.  Future versions of PropertyFile will hopefully eliminate this shortcoming.
+</p>
+
+<blockquote><pre>&lt;propertyfile
+    file=&quot;my.properties&quot;
+    comment=&quot;My properties&quot;&gt;
+  &lt;entry  key=&quot;akey&quot; value=&quot;avalue&quot;/&gt;
+  &lt;entry  key=&quot;adate&quot; type=&quot;date&quot; value=&quot;now&quot;/&gt;
+  &lt;entry  key=&quot;anint&quot; type=&quot;int&quot; operation=&quot;+&quot;/&gt;
+  &lt;entry  key=&quot;formated.int&quot; type=&quot;int&quot; default=&quot;0013&quot; operation=&quot;+&quot; pattern=&quot;0000&quot;/&gt;
+  &lt;entry  key=&quot;formated.date&quot; type=&quot;date&quot; value=&quot;now&quot; pattern=&quot;DDD HH:mm&quot;/&gt;
+&lt;/propertyfile&gt;
+</pre></blockquote>
+<p>
+To produce dates relative from today :</p>
+<blockquote><pre>&lt;propertyfile
+    file=&quot;my.properties&quot;
+    comment=&quot;My properties&quot;&gt;
+  &lt;entry  key=&quot;formated.date-1&quot;
+      type=&quot;date&quot; default=&quot;now&quot; pattern=&quot;DDD&quot;
+      operation=&quot;-&quot; value=&quot;1&quot;/&gt;
+  &lt;entry  key=&quot;formated.tomorrow&quot;
+      type=&quot;date&quot; default=&quot;now&quot; pattern=&quot;DDD&quot;
+      operation=&quot;+&quot; value=&quot;1&quot;/&gt;
+&lt;/propertyfile&gt;
+</pre></blockquote>
+
+<p>
+Concatenation of strings :</p>
+<blockquote><pre>&lt;propertyfile
+    file=&quot;my.properties&quot;
+    comment=&quot;My properties&quot;&gt;
+  &lt;entry  key=&quot;progress&quot; default=&quot;&quot; operation=&quot;+&quot; value=&quot;.&quot;/&gt;
+&lt;/propertyfile&gt;
+</pre></blockquote>
+<p>Each time called, a &quot;.&quot; will be appended to &quot;progress&quot;
+</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/pvcstask.html b/trunk/docs/manual/OptionalTasks/pvcstask.html
new file mode 100644
index 0000000..aef8175
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/pvcstask.html
@@ -0,0 +1,295 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+   <meta http-equiv="Content-Language" content="en-us">
+   <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>PVCS task</title>
+</head>
+<body>
+
+<h1>
+Ant Pvcs Task User Manual</h1>
+
+<p><b>Note:</b>
+Before using this task, the user running ant must have access to the
+commands of PVCS (get and pcli) and must have access to the
+repository. Note that the way to specify the repository is platform
+dependent so use property to specify location of repository.
+</p>
+
+by
+<br><!-- Names are in alphabetical order, on last name -->
+<ul>
+  <li>Thomas Christensen (<a href="mailto:tchristensen@nordija.com">tchristensen@nordija.com</a>)</li>
+  <li>Don Jeffery (<a href="mailto:donj@apogeenet.com">donj@apogeenet.com</a>)</li>
+  <li>Jon Dickinson (<a href="mailto:dickinson.j@ucles.org.uk">dickinson.j@ucles.org.uk</a>)</li>
+</ul>
+Version 1.1 - 2001/06/27<br>
+<p>Problems with UNC pathnames and the use of () in paths are fixed and an updateonly
+  argument introduced.</p>
+Version 1.0 - 2001/01/31<br>
+<p>Initial release.</p>
+<hr>
+<h2>
+Table of Contents</h2>
+<ul>
+  <li><a href="#introduction">Introduction</a></li>
+  <li><a href="#pvcs">Pvcs Task</a></li>
+</ul>
+<hr>
+
+<h2><a NAME="introduction">Introduction</a></h2>
+The pvcs task allows the user of ant to extract the latest edition
+of the source code from a PVCS repository. PVCS is a version control system
+developed by <a href="http://www.merant.com/products/pvcs">Merant</a>.
+<br>
+This version has been tested against PVCS version 6.5 and 6.6 under Windows and Solaris.
+
+<hr>
+<h2><a NAME="pvcs">Pvcs Task</a></h2>
+<h3>Description</h3>
+The pvcs task is set to point at a PVCS repository and optionally a project
+within that repository, and can from that specification get the latest
+version of the files contained by the repository.
+<h3>
+Parameters</h3>
+
+<table BORDER CELLSPACING=0 CELLPADDING=2 >
+<tr>
+<td VALIGN=TOP WIDTH="12%"><b>Attribute</b></td>
+
+<td VALIGN=TOP WIDTH="78%"><b>Description</b></td>
+
+<td VALIGN=TOP WIDTH="10%"><b>Required</b></td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">repository</td>
+
+<td VALIGN=TOP WIDTH="78%">The location of the repository (see your PVCS
+manuals)</td>
+
+<td VALIGN=TOP WIDTH="10%">Yes</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">pvcsproject</td>
+
+<td VALIGN=TOP WIDTH="78%">The project within the PVCS repository to extract
+files from (&quot;/&quot; is root project and that is default if this attribute isn't
+specified)</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">label</td>
+
+<td VALIGN=TOP WIDTH="78%">Only files marked with this label are extracted.</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">promotiongroup</td>
+
+<td VALIGN=TOP WIDTH="78%">Only files within this promotion group are extracted. Using
+both the <i>label</i> and the <i>promotiongroup</i> tag will cause the files in the
+promotion group and with that label to be extracted.
+</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">config</td>
+
+<td VALIGN=TOP WIDTH="78%">path of a non default .cfg file.
+Can be given absolute or relative to ant's base directory.
+</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">force</td>
+
+<td VALIGN=TOP WIDTH="78%">If set to <i>yes</i> all files that exists and are writable are overwritten. Default <i>no</i> causes the files that are writable to be ignored. This stops the PVCS command <i>get</i> to stop asking questions!</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">workspace</td>
+
+<td VALIGN=TOP WIDTH="78%">By specifying a workspace, the files are extracted to that location. A PVCS workspace is a
+name for a location of the workfiles and isn't as such the location itself. You define the location for a workspace
+using the PVCS GUI clients. If this isn't specified the default workspace for the current user is used.</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">pvcsbin</td>
+
+<td VALIGN=TOP WIDTH="78%">On some systems the PVCS executables <i>pcli</i>
+and <i>get</i> are not found in the PATH. In such cases this attribute
+should be set to the bin directory of the PVCS installation containing
+the executables mentioned before. If this attribute isn't specified the
+tag expects the executables to be found using the PATH environment variable.</td>
+
+<td VALIGN=TOP WIDTH="10%">No</td>
+</tr>
+    <tr>
+      <td VALIGN=TOP WIDTH="12%">ignorereturncode</td>
+      <td VALIGN=TOP WIDTH="78%">If set to <i>true</i> the return value from executing
+        the pvcs commands are ignored.</td>
+      <td VALIGN=TOP WIDTH="10%">No</td>
+    </tr>
+    <tr>
+      <td VALIGN=TOP WIDTH="12%">updateonly</td>
+      <td VALIGN=TOP WIDTH="78%">If set to <i>true</i> files are gotten only if
+        newer than existing local files.</td>
+      <td VALIGN=TOP WIDTH="10%">No</td>
+    </tr>
+    <tr>
+      <td valign="TOP">filenameformat</td>
+      <td valign="TOP">The format of your folder names in a
+          format suitable for <code>java.text.MessageFormat</code>.
+          Defaults to <code>{0}-arc({1})</code>.  Repositories where
+          the archive extension is not  <code>-arc</code> should set
+          this.</td>
+      <td valign="TOP">No</td>
+    </tr>
+    <tr>
+      <td valign="TOP">linestart</td>
+        <td valign="TOP">Used to parse the output of the pcli
+          command. It defaults to <code>&quot;P:</code>.  The parser already
+          knows about / and \\, this property is useful in cases where the
+          repository is accessed on a Windows platform via a drive letter
+          mapping.</td>
+      <td valign="TOP">No</td>
+    </tr>
+    <tr>
+      <td valign="TOP">revision</td>
+      <td valign="TOP">Retrieve the specified revision.</td>
+      <td valign="TOP">No</td>
+    </tr>
+    <tr>
+      <td valign="TOP">userid</td>
+      <td valign="TOP">Use the specified userid.</td>
+      <td valign="TOP">No</td>
+    </tr>
+</table>
+<h3><a name="nested">Nested Elements</a></h3>
+
+<h3>pvcsproject element</h3>
+<p><code>pvcs</code> supports a nested
+<code>&lt;pvcsproject&gt;</code> element, that represents a project
+within the PVCS repository to extract files from.  By nesting multiple
+<code>&lt;pvcsproject&gt;</code> elements under the
+<code>&lt;pvcs&gt;</code> task, multiple projects can be
+specified.</p>
+
+<h3>Parameters</h3>
+
+<table BORDER CELLSPACING=0 CELLPADDING=2 >
+<tr>
+<td VALIGN=TOP WIDTH="12%"><b>Attribute</b></td>
+
+<td VALIGN=TOP WIDTH="78%"><b>Description</b></td>
+
+<td VALIGN=TOP WIDTH="10%"><b>Required</b></td>
+</tr>
+
+<tr>
+<td VALIGN=TOP WIDTH="12%">name</td>
+
+<td VALIGN=TOP WIDTH="78%">The name of the pvcs project</td>
+
+<td VALIGN=TOP WIDTH="10%">Yes</td>
+</tr>
+</table>
+
+<h3>Examples</h3>
+The following set-up extracts the latest version of the files in the pvcs repository.
+<pre>
+  &lt;!-- =================================================================== --&gt;
+  &lt;!-- Get the latest version                                              --&gt;
+  &lt;!-- =================================================================== --&gt;
+  &lt;target name=&quot;getlatest&quot;&gt;
+    &lt;pvcs repository=&quot;/mnt/pvcs&quot; pvcsproject=&quot;/myprj&quot;/&gt;
+  &lt;/target&gt;</ul>
+</pre>
+<p>Now run:</p>
+<code>ant getlatest</code>
+<p>This will cause the following output to appear:</p>
+<pre>
+  getlatest:
+  [pvcs] PVCS Version Manager (VMGUI) v6.6.10 (Build 870) for Windows NT/80x86
+  [pvcs] Copyright 1985-2000 MERANT. All rights reserved.
+  [pvcs] PVCS Version Manager (get) v6.6.10 (Build 870) for Windows NT/80x86
+  [pvcs] Copyright 1985-2000 MERANT. All rights reserved.
+  [pvcs] c:\myws\myprj\main.java &lt;- C:\mypvcs\archives\myprj\main.java-arc
+  [pvcs] rev 1.1
+  [pvcs] c:\myws\myprj\apache\tool.java &lt;- C:\mypvcs\archives\myprj\apache\tools.java-arc
+  [pvcs] rev 1.5
+
+  BUILD SUCCESSFUL
+
+  Total time: 19 seconds</pre>
+
+This next example extracts the latest version of the files in the pvcs
+repository from two projects using nested <code>&lt;pvcsproject&gt;</code> elements.
+<pre>
+  &lt;!-- ===================================================================--&gt;
+  &lt;!-- Get latest from myprj and myprj2                                   --&gt;
+  &lt;!-- ===================================================================--&gt;
+  &lt;target name=&quot;getlatest2&quot;&gt;
+    &lt;pvcs repository=&quot;/mnt/pvcs&quot;&gt;
+      &lt;pvcsproject name=&quot;/myprj&quot;/&gt;
+      &lt;pvcsproject name=&quot;/myprj2&quot;/&gt;
+    &lt;/pvcs&gt;
+  &lt;/target&gt;</ul>
+</pre>
+<p>Now run:</p>
+<code>ant getlatest2</code>
+<p>This will cause the following output to appear:</p>
+<pre>
+  getlatest2:
+  [pvcs] PVCS Version Manager (VMGUI) v6.6.10 (Build 870) for Windows NT/80x86
+  [pvcs] Copyright 1985-2000 MERANT.  All rights reserved.
+  [pvcs] PVCS Version Manager (get) v6.6.10 (Build 870) for Windows NT/80x86
+  [pvcs] Copyright 1985-2000 MERANT.  All rights reserved.
+  [pvcs] c:\myws\myprj\main.java &lt;- C:\mypvcs\archives\myprj\main.java-arc
+  [pvcs] rev 1.1
+  [pvcs] c:\myws\myprj\apache\tool.java &lt;- C:\mypvcs\archives\myprj\apache\tool.java-arc
+  [pvcs] rev 1.5
+  [pvcs] c:\myws\myprj2\apache\tool2.java &lt;- C:\mypvcs\archives\myprj2\apache\tool2.java-arc
+  [pvcs] rev 1.2
+
+  BUILD SUCCESSFUL
+
+  Total time: 22 seconds</pre>
+
+<hr WIDTH="100%">
+<p>PVCS is a registered trademark of MERANT.</p>
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/renameextensions.html b/trunk/docs/manual/OptionalTasks/renameextensions.html
new file mode 100644
index 0000000..d1695ee
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/renameextensions.html
@@ -0,0 +1,123 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>RenameExtensions Task</title>
+</head>
+
+<body>
+
+<h2><a name="renameexts">RenameExtensions</a></h2>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the <a href="../CoreTasks/move.html">move</a>
+task with a <a href="../CoreTypes/mapper.html#glob-mapper">glob mapper</a> instead.</i></p>
+<h3>Description</h3>
+<p>Renames files in the <code>srcDir</code> directory ending with the
+<code>fromExtension</code> string so that they end with the
+<code>toExtension</code> string. Files are only replaced if
+<code>replace</code> is true
+</p>
+<p>See the section on
+<a href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.
+This task forms an implicit <a href="../CoreTypes/fileset.html">FileSet</a> and
+supports all attributes of <code>&lt;fileset&gt;</code>
+(<code>dir</code> becomes <code>srcDir</code>) as well as the nested
+<code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+<code>&lt;patternset&gt;</code> elements.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">defaultexcludes</td>
+    <td valign="top">indicates whether default excludes should be used or not
+      (&quot;yes&quot;/&quot;no&quot;). Default excludes are used when
+      omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      excluded. No files (except default excludes) are excluded when
+      omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">excludesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an exclude pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fromExtention</td>
+    <td valign="top">The string that files must end in to be renamed</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">comma- or space-separated list of patterns of files that must be
+      included. All files are included when omitted.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">includesfile</td>
+    <td valign="top">the name of a file. Each line of this file is
+      taken to be an include pattern</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">replace</td>
+    <td valign="top">Whether the file being renamed to should be
+      replaced if it already exists</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">srcDir</td>
+    <td valign="top">The starting directory for files to search in</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">toExtension</td>
+    <td valign="top">The string that renamed files will end with on
+      completion</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+  <p><code>&lt;renameext srcDir=&quot;/source/project1&quot;
+              includes=&quot;**&quot;
+              excludes=&quot;**/samples/*&quot;
+              fromExtension=&quot;.java.keep&quot;
+              toExtension=&quot;.java&quot;
+              replace=&quot;true&quot;/&gt;
+</code>
+  </p>
+</blockquote>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/replaceregexp.html b/trunk/docs/manual/OptionalTasks/replaceregexp.html
new file mode 100644
index 0000000..9697d2d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/replaceregexp.html
@@ -0,0 +1,159 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ReplaceRegExp Task</title>
+</head>
+<body>
+
+<h2><a name="replaceregexp">ReplaceRegExp</a></h2>
+<h3>Description</h3>
+<p>ReplaceRegExp is a directory based task for replacing the
+occurrence of a given regular expression with a substitution pattern
+in a selected file or set of files.</p>
+
+<p>The output file is only written if it differs from the existing
+file.  This prevents spurious rebuilds based on unchanged files which
+have been regenerated by this task.</p> 
+
+<p>Similar to <a href="../CoreTypes/mapper.html#regexp-mapper">regexp
+type mappers</a> this task needs a supporting regular expression
+library and an implementation of
+<code>org.apache.tools.ant.util.regexp.Regexp</code>.
+See details in the documentation of the <a href="../CoreTypes/regexp.html#implementation">Regexp Type</a>. </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">file for which the regular expression should be replaced.</td>
+    <td align="center">Yes if no nested <code>&lt;fileset&gt;</code> is used</td>
+  </tr>
+  <tr>
+    <td valign="top">match</td>
+    <td valign="top">The regular expression pattern to match in the file(s)</td>
+    <td align="center">Yes, if no nested <code>&lt;regexp&gt;</code> is used</td>
+  </tr>
+  <tr>
+    <td valign="top">replace</td>
+    <td valign="top">The substitution pattern to place in the file(s) in place
+                     of the regular expression.</td>
+    <td align="center">Yes, if no nested <code>&lt;substitution&gt;</code> is used</td>
+  </tr>
+  <tr>
+    <td valign="top">flags</td>
+    <td valign="top">The flags to use when matching the regular expression.  For more
+                     information, consult the Perl5 syntax<br>
+                     g : Global replacement.  Replace all occurrences found<br>
+                     i : Case Insensitive.  Do not consider case in the match<br>
+                     m : Multiline.  Treat the string as multiple lines of input, using "^" and "$" as the start or end of any line, respectively, rather than start or end of string.<br>
+                     s : Singleline.  Treat the string as a single line of input, using "." to match any character, including a newline, which normally, it would not match.<br>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">byline</td>
+    <td valign="top">Process the file(s) one line at a time, executing the replacement
+                     on one line at a time (<i>true/false</i>).  This is useful if you
+                     want to only replace the first occurrence of a regular expression on
+                     each line, which is not easy to do when processing the file as a whole.
+                     Defaults to <i>false</i>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">encoding</td>
+    <td valign="top">The encoding of the file. <em>since Ant 1.6</em></td>
+    <td align="center">No - defaults to default JVM encoding</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<pre>
+&lt;replaceregexp file=&quot;${src}/build.properties&quot;
+               match=&quot;OldProperty=(.*)&quot;
+               replace=&quot;NewProperty=\1&quot;
+               byline=&quot;true&quot;
+/&gt;
+</pre>
+<p>replaces occurrences of the property name &quot;OldProperty&quot;
+ with &quot;NewProperty&quot; in a properties file, preserving the existing
+value, in the file <code>${src}/build.properties</code></p>
+
+<h3>Parameters specified as nested elements</h3>
+<p>This task supports a nested <a href="../CoreTypes/fileset.html">FileSet</a>
+   element.</p>
+<p>This task supports a nested <i><a href="../CoreTypes/regexp.html">Regexp</a></i> element to specify
+   the regular expression.  You can use this element to refer to a previously
+   defined regular expression datatype instance.</p>
+<blockquote>
+     &lt;regexp id="id" pattern="alpha(.+)beta"/&gt;<br>
+     &lt;regexp refid="id"/&gt;
+</blockquote>
+<p>This task supports a nested <i>Substitution</i> element to specify
+   the substitution pattern.  You can use this element to refer to a previously
+   defined substitution pattern datatype instance.</p>
+<blockquote>
+     &lt;substitution id="id" expression="beta\1alpha"/&gt;<br>
+     &lt;substitution refid="id"/&gt;
+</blockquote>
+<h3>Examples</h3>
+<blockquote>
+  <pre>
+&lt;replaceregexp byline=&quot;true&quot;&gt;
+  &lt;regexp pattern=&quot;OldProperty=(.*)&quot;/&gt;
+  &lt;substitution expression=&quot;NewProperty=\1&quot;/&gt;
+  &lt;fileset dir=&quot;.&quot;&gt;
+    &lt;include name=&quot;*.properties&quot;/&gt;
+  &lt;/fileset&gt;
+&lt;/replaceregexp&gt;
+</pre></blockquote>
+<p>replaces occurrences of the property name &quot;OldProperty&quot;
+ with &quot;NewProperty&quot; in a properties file, preserving the existing
+value, in all files ending in <code>.properties</code> in the current directory</p>
+
+<blockquote>
+<pre>&lt;replaceregexp match="\s+" replace=" " flags="g" byline="true"&gt;
+    &lt;fileset dir="${html.dir}" includes="**/*.html"/&gt;
+&lt;/replaceregexp&gt;
+</pre></blockquote>
+<p>replaces all whitespaces (blanks, tabs, etc) by one blank remaining the
+line separator. So with input
+
+<blockquote>
+<pre>
+&lt;html&gt;    &lt;body&gt;
+&lt;&lt;TAB&gt;&gt;&lt;h1&gt;    T E S T   &lt;/h1&gt;  &lt;&lt;TAB&gt;&gt;    
+&lt;&lt;TAB&gt;&gt; &lt;/body&gt;&lt;/html&gt;
+</pre></blockquote>
+would converted to
+<pre>
+&lt;html&gt; &lt;body&gt;
+ &lt;h1&gt; T E S T &lt;/h1&gt; &lt;/body&gt;&lt;/html&gt;
+</pre>
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/rexec.html b/trunk/docs/manual/OptionalTasks/rexec.html
new file mode 100644
index 0000000..281ffd9
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/rexec.html
@@ -0,0 +1,116 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>RExec Task</title>
+</head>
+
+<body>
+
+<h2><a name="rexec">RExec</a></h2>
+<h3>Description</h3>
+Task to automate a remote rexec session. Just like the Telnet task,
+it uses nested <tt>&lt;read&gt;</tt> to indicate strings to wait for, and
+<tt>&lt;write&gt;</tt> tags to specify text to send to the remote process.
+
+<p><b>Note:</b> This task depends on external libraries not included in the Ant distribution.
+See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p>
+
+<p>You can specify the commands you want to execute as nested elements
+or via the command attribute, we recommend you use the command
+attribute.  If you use the command attribute, you must use the
+username and password attributes as well.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>userid</td>
+     <td>the login id to use on the remote server.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>password</td>
+     <td>the login password to use on the remote server.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>server</td>
+     <td>the address of the remote rexec server.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>command</td>
+     <td>the command to execute on the remote server.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>port</td>
+     <td>the port number of the remote rexec server. Defaults to port 512 in BSD Unix systems.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>timeout</td>
+     <td>set a default timeout to wait for a response. Specified in seconds. Default is no timeout.</td>
+     <td>No</td>
+  </tr>
+</table>
+<h3><a name="nested">Nested Elements</a></h3>
+The input to send to the server, and responses to wait for, are
+described as nested elements.  
+
+<h4>read</h4>
+
+<p>declare (as a text child of this element) a string to wait for.
+The element supports the timeout attribute, which overrides any
+timeout specified for the task as a whole. It also has a <tt>string</tt>
+attribute, which is an alternative to specifying the string as 
+a text element.
+</p>
+<i>It is not necessary to declare a closing <code>&lt;read&gt;</code> element like for the Telnet task. The connection is not broken until the command has completed and
+the input stream (output of the command) is terminated.
+</i>
+<h4>write</h4>
+
+<p>describes the text to send to the server. The <tt>echo</tt> boolean
+attribute controls whether the string is echoed to the local log; 
+this is "true" by default
+</p>
+<h3>Example</h3>
+A simple example of connecting to a server and running a command.
+
+<blockquote><pre>
+&lt;rexec userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot; command=&quot;ls&quot;/&gt;
+</pre></blockquote>
+
+The task can be used with other ports as well:
+<blockquote><pre>
+&lt;rexec port=&quot;80&quot; userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot; command=&quot;ls&quot;/&gt;
+</pre></blockquote>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/rpm.html b/trunk/docs/manual/OptionalTasks/rpm.html
new file mode 100644
index 0000000..b213e06
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/rpm.html
@@ -0,0 +1,123 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<html>
+
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Rpm Task</title>
+</head>
+
+<body>
+
+<h2><a name="rpm">Rpm</a></h2>
+<h3>Description</h3>
+<p>
+  A basic task for invoking the rpm executable to build a RedHat Package Manager Linux installation
+  file. The task currently only works on Linux or other Unix platforms with rpm support.
+</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">specFile</td>
+    <td valign="top">The name of the spec file to be used. This must be relative to the SPECS directory
+    under the root of the RPM set in the topDir attribute.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">topDir</td>
+    <td valign="top">
+      This is the directory which will have the expected
+      subdirectories, SPECS, SOURCES, BUILD, SRPMS.  If this isn't specified,
+      the default RPM directory of the system (or user, if ~/.rpmmacros defines it) is used (often
+      /usr/src/rpm.<br>
+      Defining a topdir will set <tt>%_topdir</tt> to the specified directory -there is no need
+      to edit your .rpmmacros file.
+    </td>
+    <td valign="top" align="center">No, but your build file is very brittle if it is not set.</td>
+  </tr>
+  <tr>
+    <td valign="top">cleanBuildDir</td>
+    <td valign="top">This will remove the generated files in the BUILD
+      directory.
+      See the the <tt>--clean</tt> option of rpmbuild.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">removeSpec</td>
+    <td valign="top">This will remove the spec file from SPECS.
+      See the the <tt>--rmspec</tt> option of rpmbuild.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">removeSource</td>
+    <td valign="top">Flag (optional, default=false) 
+        to remove the sources after the build.
+        See the the <tt>--rmsource</tt> option of rpmbuild.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">rpmBuildCommand</td>
+    <td valign="top">The executable to use for building the RPM.
+      Defaults to <code>rpmbuild</code> if it can be found or
+      <code>rpm</code> otherwise.  Set this if you don't have either on
+      your PATH or want to use a different executable.  <em>Since Ant
+      1.6</em>.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">command</td>
+    <td valign="top">The command to pass to the rpmbuild program. The default is "-bb"</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">quiet</td>
+    <td valign="top">Suppress output. Defaults to false.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">output/error</td>
+    <td valign="top">Where standard output and error go</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failOnError</td>
+    <td valign="top">Stop the buildprocess if the RPM build command exits with 
+       a non-zero retuncode. Defaults to false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<pre>
+    &lt;rpm
+        specFile="example.spec"
+        topDir="build/rpm"
+        cleanBuildDir="true"
+        failOnError="true"/&gt;
+</pre>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/schemavalidate.html b/trunk/docs/manual/OptionalTasks/schemavalidate.html
new file mode 100644
index 0000000..dce51d0
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/schemavalidate.html
@@ -0,0 +1,283 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SchemaValidate Task</title>
+</head>
+
+<body>
+
+<h2><a name="schemavalidate">SchemaValidate</a></h2>
+<h3>Description</h3>
+
+<p>This task validates XML files described by an XML Schema.
+The task extends the XmlValidate task with XSD-specific features.</p>
+<ol>
+<li>The parser is created validating and namespace aware
+</li>
+<li>Validation is turned on.</li>
+<li>Schema validation is turned on.</li>
+<li>Any no-namespace schema URL or file supplied is used as the no-namespace schema
+<li>All nested schema declarations are turned into the list of namespace-url
+bindings for schema lookup.
+</ol>
+
+Note that nested catalogs are still used for lookup of the URLs given as the
+sources of schema documents, so you can still delegate lookup to a catalog, you
+just need to list all schema URIs and their URL equivalents.
+
+<p>This task supports the use of nested
+  <li><a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a> elements</li>
+  <li> <tt>&lt;schema&gt;</tt> elements, that bind a namespace URI to a URL or a
+  local filename.
+  <li><tt>&lt;dtd&gt;</tt> elements which are used to resolve DTDs and entities.</li>
+  <li><tt>&lt;attribute&gt;</tt> elements which are used to set features on the parser.
+      These can be any number of
+      <a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a>
+      or other features that your parser may support.</li>
+  <li><tt>&lt;property&gt;</tt> elements, containing string properties
+</p>
+
+<p>
+The task only supports SAX2 or later parsers: it is an error to specify a SAX1
+parser. 
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the parser to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">where to find the parser class. 
+    Optionally can use an embedded <tt>&lt;classpath&gt;</tt> element.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">disableDTD</td>
+    <td valign="top">
+      Flag to disable DTD support. DTD support is needed to 
+      validate XSD files themselves, amongst others.
+    </td>
+    <td valign="top" align="center">No - default false</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">fails on a error if set to true (defaults to true).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file(s) you want to check. (optionally can use an embedded fileset)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">fullchecking</td>
+    <td valign="top">
+      enable full schema checking. Slow but strict.
+    </td>
+    <td valign="top" align="center">No - default true</td>
+  </tr>
+  
+  <tr>
+    <td valign="top">lenient</td>
+    <td valign="top">
+      if true, only check the XML document is well formed
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">noNamespaceFile</td>
+    <td valign="top">
+      filename of a no-namespace XSD file to provide the 
+      schema for no-namespace XML content.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">noNamespaceURL</td>
+    <td valign="top">
+      URL of a no-namespace XSD file to provide the 
+      schema for no-namespace XML content.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">warn</td>
+    <td valign="top">log parser warn events.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3><a name="nested">Nested Elements</a></h3>
+
+
+<h4>schema</h4>
+<p>
+Identify the name and location of a schema that may be used in validating
+the document(s).
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">namespace</td>
+    <td valign="top">URI of the schema namespace</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">url</td>
+    <td valign="top">URL of the schema</td>
+    <td align="center" valign="top">One of url or file is required</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">file of the schema</td>
+    <td align="center" valign="top">One of url or file is required</td>
+  </tr>
+</table>
+
+<h4>dtd</h4>
+<p>
+<tt>&lt;dtd&gt;</tt> is used to specify different locations for DTD resolution.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">publicId</td>
+    <td valign="top">Public ID of the DTD to resolve</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">Location of the DTD to use, which can be a file,
+    a resource, or a URL</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+<h4>xmlcatalog</h4>
+<p>The <a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a>
+element is used to perform entity resolution.</p>
+<h4>attribute</h4>
+<p>The <tt>&lt;attribute&gt;</tt> element is used to set parser features.<br>
+Features usable with the xerces parser are defined here :
+ <a href="http://xml.apache.org/xerces-j/features.html">Setting features</a><br>
+
+SAX features are defined here:
+ <a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a><br>
+ </p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The boolean value of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</p>
+
+<h4>property</h4>
+<p>The <tt>&lt;property&gt;</tt> element is used to set properties.
+These properties are defined here for the xerces XML parser implementation :
+ <a href="http://xml.apache.org/xerces-j/properties.html">XML Parser properties</a>
+Properties can be used to set the schema used to validate the XML file.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The string value of the property</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</p>
+
+
+<h3>Examples</h3>
+<pre>
+    &lt;schemavalidate
+      noNamespaceFile="document.xsd"
+      file="xml/endpiece.xml"&gt;
+    &lt;/schemavalidate&gt;
+</pre>
+Validate a document against an XML schema. The document does not declare
+any schema itself, which is why the <tt>noNamespaceFile</tt> is needed. 
+<pre>
+    &lt;presetdef name="validate-soap"&gt;
+      &lt;schemavalidate &gt;
+        &lt;schema namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing"
+          file="${soap.dir}/ws-addressing.xsd" /&gt;
+        &lt;schema namespace="http://www.w3.org/2003/05/soap-envelope"
+          file="${soap.dir}/soap12.xsd" /&gt;
+        &lt;schema namespace="http://schemas.xmlsoap.org/wsdl/"
+          file="${soap.dir}/wsdl.xsd" /&gt;
+        &lt;schema namespace="http://www.w3.org/2001/XMLSchema"
+          file="${soap.dir}/XMLSchema.xsd" /&gt;
+        &lt;/schemavalidate&gt;
+    &lt;/presetdef&gt;
+</pre>
+Declare a new preset task, <tt>&lt;validate-soap&gt;</tt>, that validates
+XSD and WSDL documents against the relevant specifications. 
+To validate XSD documents, you also need XMLSchema.dtd and datatypes.dtd in 
+the same directory as XMLSchema.xsd, or pointed to via the catalog. All
+these files can be fetched from <a href="http://www.w3.org/2001/XMLSchema">
+the W3C</a>. 
+<pre>
+    &lt;validate-soap file="xml/test.xsd"/&gt;
+</pre>
+Use the preset task defined above to validate an XML Schema document.
+<br>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/scp.html b/trunk/docs/manual/OptionalTasks/scp.html
new file mode 100644
index 0000000..380c89d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/scp.html
@@ -0,0 +1,267 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SCP Task</title>
+</head>
+
+<body>
+
+<h2><a name="scp">SCP</a></h2>
+<h3>Description</h3>
+
+<p><em>since Ant 1.6</em></p>
+
+<p>Copies a file or FileSet to or from a (remote) machine running an SSH daemon.
+FileSet <i>only</i> works for copying files from the local machine to a
+remote machine.</p>
+
+<p><b>Note:</b> This task depends on external libraries not included
+in the Ant distribution.  See <a
+href="../install.html#librarydependencies">Library Dependencies</a>
+for more information.  This task has been tested with jsch-0.1.2 and later.</p>
+
+<p>See also the <a href="sshexec.html">sshexec task</a></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The file to copy.  This can be a local path or a
+    remote path of the form <i>user[:password]@host:/directory/path</i>.
+    <i>:password</i> can be omitted if you use key based
+    authentication or specify the password attribute.  The way remote
+    path is recognized is whether it contains @ character or not. This
+    will not work if your localPath contains @ character.</td>
+    <td valign="top" align="center">Yes, unless a nested
+    <code>&lt;fileset&gt;</code> element is used.</td>
+  </tr>
+  <tr>
+    <td valign="top">localFile</td>
+    <td valign="top">This is an alternative to the file attribute. But
+    this must always point to a local file. The reason this was added
+    was that when you give file attribute it is treated as remote if
+    it contains @ character. This character can exist also in local
+    paths.  <em>since Ant 1.6.2</em></td>
+    <td valign="top" align="center">Alternative to file attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">remoteFile</td>
+    <td valign="top">This is an alternative to the file attribute. But
+    this must always point to a remote file.  <em>since Ant 1.6.2</em></td>
+    <td valign="top" align="center">Alternative to file attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">The directory to copy to.  This can be a local path
+    or a remote path of the form <i>user[:password]@host:/directory/path</i>.
+    <i>:password</i> can be omitted if you use key based
+    authentication or specify the password attribute.  The way remote
+    path is recognized is whether it contains @ character or not. This
+    will not work if your localPath contains @ character.</td>
+    <td valian="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">localTodir</td>
+    <td valign="top">This is an alternative to the todir
+    attribute. But this must always point to a local directory. The
+    reason this was added was that when you give todir attribute it is
+    treated as remote if it contains @ character. This character can
+    exist also in local paths.  <em>since Ant 1.6.2</em></td>
+    <td valian="top" align="center">Alternative to todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">localTofile</td>
+    <td valign="top">Changes the file name to the given name while
+    receiving it, only useful if receiving a single file.  <em>since
+    Ant 1.6.2</em></td>
+    <td valian="top" align="center">Alternative to todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">remoteTodir</td>
+    <td valign="top">This is an alternative to the todir
+    attribute. But this must always point to a remote directory.
+    <em>since Ant 1.6.2</em></td>
+    <td valian="top" align="center">Alternative to todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">remoteTofile</td>
+    <td valign="top">Changes the file name to the given name while
+    sending it, only useful if sending a single file.  <em>since
+    Ant 1.6.2</em></td>
+    <td valian="top" align="center">Alternative to todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">The port to connect to on the remote host.</td>
+    <td valian="top" align="center">No, defaults to 22.</td>
+  </tr>
+  <tr>
+    <td valign="top">trust</td>
+    <td valign="top">This trusts all unknown hosts if set to yes/true.<br>
+      <strong>Note</strong> If you set this to false (the default), the
+      host you connect to must be listed in your knownhosts file, this
+      also implies that the file exists.</td>
+    <td valian="top" align="center">No, defaults to No.</td>
+  </tr>
+  <tr>
+    <td valign="top">knownhosts</td>
+    <td valign="top">This sets the known hosts file to use to validate
+    the identity of the remote host.  This must be a SSH2 format file.
+    SSH1 format is not supported.</td>
+    <td valian="top" align="center">No, defaults to
+    ${user.home}/.ssh/known_hosts.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">Whether to halt the build if the transfer fails.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+     <td valign="top">The password.</td>
+     <td valign="top" align="center">Not if you are using key based
+     authentication or the password has been given in the file or
+     todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">keyfile</td>
+     <td valign="top">Location of the file holding the private key.</td>
+     <td valign="top" align="center">Yes, if you are using key based
+     authentication.</td>
+  </tr>
+  <tr>
+    <td valign="top">passphrase</td>
+     <td valign="top">Passphrase for your private key.</td>
+     <td valign="top" align="center">Yes, if you are using key based
+     authentication.</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Determines whether SCP outputs verbosely to the
+    user. Currently this means outputting dots/stars showing the
+    progress of a file transfer.  <em>since Ant 1.6.2</em></td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">sftp</td>
+    <td valign="top">Determines whether SCP uses the sftp protocol.
+    The sftp protocol is the file transfer protocol of SSH2.  It is
+    recommended that this be set to true if you are copying to/from a
+    server that doesn't support scp1. <em>since Ant 1.7</em></td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select
+sets of files to copy.
+ To use a fileset, the <code>todir</code> attribute must be set.</p>
+
+<h3>Examples</h3>
+<p><b>Copy a single local file to a remote machine</b></p>
+<pre>
+  &lt;scp file=&quot;myfile.txt&quot; todir=&quot;user:password@somehost:/home/chuck&quot;/&gt;
+</pre>
+
+<p><b>Copy a single local file to a remote machine with separate
+password attribute</b></p>
+<pre>
+  &lt;scp file=&quot;myfile.txt&quot; todir=&quot;user@somehost:/home/chuck&quot; password=&quot;password&quot;/&gt;
+</pre>
+
+<p><b>Copy a single local file to a remote machine using key base
+authentication.</b></p>
+<pre>
+  &lt;scp file=&quot;myfile.txt&quot;
+       todir=&quot;user@somehost:/home/chuck&quot; 
+       keyfile=&quot;${user.home}/.ssh/id_dsa&quot;
+       passphrase=&quot;my extremely secret passphrase&quot;
+  /&gt;
+</pre>
+
+<p><b>Copy a single remote file to a local directory</b></p>
+<pre>
+  &lt;scp file=&quot;user:password@somehost:/home/chuck/myfile.txt&quot; todir=&quot;../some/other/dir&quot;/&gt;
+</pre>
+
+<p><b>Copy a remote directory to a local directory</b></p>
+<pre>
+  &lt;scp file=&quot;user:password@somehost:/home/chuck/*&quot; todir=&quot;/home/sara&quot;/&gt;
+</pre>
+
+<p><b>Copy a local directory to a remote directory</b></p>
+<pre>
+  &lt;scp todir=&quot;user:password@somehost:/home/chuck/&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;/&gt;
+  &lt;/scp&gt;
+</pre>
+<p><b>Copy a set of files to a directory</b></p>
+<pre>
+  &lt;scp todir=&quot;user:password@somehost:/home/chuck&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot;&gt;
+      &lt;include name=&quot;**/*.java&quot;/&gt;
+    &lt;/fileset&gt;
+  &lt;/scp&gt;
+
+  &lt;scp todir=&quot;user:password@somehost:/home/chuck&quot;&gt;
+    &lt;fileset dir=&quot;src_dir&quot; excludes=&quot;**/*.java&quot;/&gt;
+  &lt;/scp&gt;
+</pre>
+
+<p><strong>Security Note:</strong>  Hard coding passwords and/or usernames
+in scp task can be a serious security hole.  Consider using variable
+substitution and include the password on the command line.  For example:
+<p>
+<pre>
+    &lt;scp todir=&quot;${username}:${password}@host:/dir&quot; ...&gt;
+</pre>
+Invoking ant with the following command line:
+<pre>
+    ant -Dusername=me -Dpassword=mypassword target1 target2
+</pre>
+
+Is slightly better, but the username/password is exposed to all users on an Unix
+system (via the ps command). The best approach is to use the
+<code>&lt;input&gt;</code> task and/or retrieve the password from a (secured)
+.properties file.
+
+<p>
+
+<p><strong>Unix Note:</strong> File permissions are not retained when files
+are copied; they end up with the default <code>UMASK</code> permissions
+instead. This is caused by the lack of any means to query or set file
+permissions in the current Java runtimes. If you need a permission-
+preserving copy function, use <code>&lt;exec executable="scp" ... &gt;</code>
+instead.
+</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/script.html b/trunk/docs/manual/OptionalTasks/script.html
new file mode 100644
index 0000000..8d55f9b
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/script.html
@@ -0,0 +1,391 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"></meta>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Script Task</title>
+</head>
+
+<body>
+
+<h2><a name="script">Script</a></h2>
+<h3>Description</h3>
+  <p>Execute a script in a
+    <a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a>
+    or
+    <a href="https://scripting.dev.java.net">JSR 223</a>  supported language.
+  </p>
+  <p><b>Note:</b>
+    This task depends on external libraries not included in the Ant distribution.
+    See <a href="../install.html#librarydependencies">Library Dependencies</a>
+    for more information.
+  </p>
+  <p>
+    The task may use the BSF scripting manager or the JSR 223 manager that
+    is included in JDK6 and higher. This is controlled by the <code>manager</code>
+    attribute. The JSR 223 scripting manager is indicated by "javax".
+  </p>
+  <p>All items (tasks, targets, etc) of the running project are
+    accessible from the script, using either their <code>name</code> or
+    <code>id</code> attributes (as long as their names are considered
+    valid Java identifiers, that is).
+    This is controlled by the "setbeans" attribute of the task.
+    The name "project" is a pre-defined reference to the Project, which can be
+    used instead of the project name. The name "self" is a pre-defined reference to the actual
+    <code>&lt;script&gt;</code>-Task instance.<br>From these objects you have access to the Ant Java API, see the
+<a href="../api/index.html">JavaDoc</a> (especially for
+<a href="../api/org/apache/tools/ant/Project.html">Project</a> and
+<a href="../api/org/apache/tools/ant/taskdefs/optional/Script.html">Script</a>) for more information.</p>
+<p>If you are using JavaScript under BSF, a good resource is <a target="_blank" href="http://www.mozilla.org/rhino/doc.html">
+http://www.mozilla.org/rhino/doc.html</a> as we are using their JavaScript interpreter.</p>
+<p>Scripts can do almost anything a task written in Java could do.</p>
+<p>Rhino provides a special construct - the <i>JavaAdapter</i>. With that you can
+create an object which implements several interfaces, extends classes and for which you
+can overwrite methods. Because this is an undocumented feature (yet), here is the link
+to an explanation: <a href="http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&newwindow=1&frame=right&th=610d2db45c0756bd&seekm=391EEC3C.5236D929%40yahoo.com#link2">
+Groups@Google: "Rhino, enum.js, JavaAdapter?"</a> by Norris Boyd in the newsgroup
+<i>netscape.public.mozilla.jseng</i>.</p>
+
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">language</td>
+    <td valign="top">The programming language the script is written in.
+      Must be a supported Apache BSF or JSR 223 language</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">manager</td>
+    <td valign="top">
+      <em>Since: Ant 1.7. </em>
+      The script engine manager to use. This can have
+      one of three values ("auto", "bsf" or "javax").
+      The default value is "auto".
+      <dl>
+        <li>"bsf" use the BSF scripting manager to run
+          the language.</li>
+        <li>"javax" use the <em>javax.scripting</em> manager
+          to run the language. (This will only work for JDK6 and higher).</li>
+        <li>"auto" use the BSF engine if it exists,
+          otherwise use the <em>javax.scripting</em> manager.</li>
+      </dl>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">The location of the script as a file, if not inline</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">setbeans</td>
+    <td valign="top">
+      This attribute controls whether to set variables for
+      all properties, references and targets in the running script.
+      If this attribute is false, only the the "project" and "self" variables are set.
+      If this attribute is true all the variables are set. The default value of this
+      attribute is "true".  <em>Since Ant 1.7</em>
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">
+      The classpath to pass into the script. <em>Since Ant 1.7</em>
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a
+       <a href="../using.html#references">reference</a> to a path defined elsewhere.
+    <em>Since Ant 1.7</em></td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+<h4>classpath</h4>
+  <p><em>Since Ant 1.7</em></p>
+<p>
+  <code>Script</code>'s <code>classpath</code> attribute is a 
+  <a href="../using.html#path">path-like structure</a> and can also be set via a nested
+  <code>&lt;classpath&gt;</code> element.
+  <p>
+    If a classpath is set, it will be used as the current thread
+    context classloader, and
+    as the classloader given to the BSF manager. 
+    This means that it can be used to specify
+    the classpath containing the language implementation for BSF
+    or for JSR 223 managers.
+    This can be useful if one wants
+    to keep ${user.home}/.ant/lib free of lots of scripting language
+    specific jar files.
+  </p>
+  <p>
+    <b>NB: (Since Ant 1.7.1)</b>
+    This classpath <em>can</em> be used to
+    specify the location of
+    the BSF jar file and/or languages
+    that have engines in the BSF jar file. This includes the
+    javascript, jython, netrexx and jacl languages.
+  </p>
+</p>
+<h3>Examples</h3>
+The following snippet shows use of five different languages:
+  <blockquote><pre>
+    &lt;property name="message" value="Hello world"/&gt;
+
+    &lt;script language="groovy"&gt;
+      println("message is " + message)
+    &lt;/script&gt;
+
+    &lt;script language="beanshell"&gt;
+      System.out.println("message is " + message);
+    &lt;/script&gt;
+
+    &lt;script language="judoscript"&gt;
+        println 'message is ', message
+    &lt;/script&gt;
+
+    &lt;script language="ruby"&gt;
+        print 'message is ', $message, "\n"
+    &lt;/script&gt;
+
+    &lt;script language="jython"&gt;
+print "message is %s" % message
+    &lt;/script&gt;
+</pre>
+  </blockquote>
+  <p>
+  Note that for the <i>jython</i> example, the script contents <b>must</b>
+  start on the first column.
+  </p>
+  <p>
+    Note also that for the <i>ruby</i> example, the names of the set variables are prefixed
+    by a '$'.
+  <p>
+    The following script shows a little more complicated jruby example:
+  </p>
+  <blockquote><pre>
+&lt;script language="ruby"&gt;
+  xmlfiles = Dir.new(".").entries.delete_if { |i| ! (i =~ /\.xml$/) }
+  xmlfiles.sort.each { |i| $self.log(i) }
+&lt;/script&gt;
+</pre>
+  </blockquote>
+  <p>
+    The same example in groovy is:
+  </p>
+  <blockquote><pre>
+&lt;script language="groovy"&gt;
+  xmlfiles = new java.io.File(".").listFiles().findAll{ it =~ "\.xml$"}
+  xmlfiles.sort().each { self.log(it.toString())}
+&lt;/script&gt;
+</pre>
+  </blockquote>
+  <p>
+    The following example shows the use of classpath to specify the location
+    of the beanshell jar file.
+  </p>
+  <blockquote><pre>
+&lt;script language="beanshell" setbeans="true"&gt;
+  &lt;classpath&gt;
+    &lt;fileset dir="${user.home}/lang/beanshell" includes="*.jar" /&gt;
+  &lt;/classpath&gt;
+  System.out.println("Hello world");
+&lt;/script&gt;
+</pre>
+  </blockquote>
+  <p>
+    The following script uses javascript to create a number of
+    echo tasks and execute them.
+  </p>
+<blockquote><pre>
+&lt;project name=&quot;squares&quot; default=&quot;main&quot; basedir=&quot;.&quot;&gt;
+
+  &lt;target name=&quot;main&quot;&gt;
+
+    &lt;script language=&quot;javascript&quot;&gt; &lt;![CDATA[
+
+      for (i=1; i&lt;=10; i++) {
+        echo = squares.createTask(&quot;echo&quot;);
+        echo.setMessage(i*i);
+        echo.perform();
+      }
+
+    ]]&gt; &lt;/script&gt;
+
+  &lt;/target&gt;
+
+&lt;/project&gt;
+</pre></blockquote>
+<p>generates</p>
+<blockquote><pre>
+main:
+1
+4
+9
+16
+25
+36
+49
+64
+81
+100
+
+BUILD SUCCESSFUL
+</pre></blockquote>
+
+<p>Now a more complex example using the Java API and the Ant API. The goal is to list the
+filesizes of all files a <code>&lt;fileset/&gt;</code> caught.</p>
+<blockquote><pre>
+
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="<font color=blue>MyProject</font>" basedir="." default="main"&gt;
+
+  &lt;property name="fs.dir" value="src"/&gt;
+  &lt;property name="fs.includes" value="**/*.txt"/&gt;
+  &lt;property name="fs.excludes" value="**/*.tmp"/&gt;
+
+  &lt;target name="main"&gt;
+    &lt;script language="javascript"&gt; &lt;![CDATA[
+
+      // import statements
+      <font color=blue>// importPackage(java.io)</font>;
+      <font color=blue>importClass(java.io.File)</font>;
+
+      // Access to Ant-Properties by their names
+      dir      = <font color=blue>project</font>.getProperty("fs.dir");
+      includes = <font color=blue>MyProject</font>.getProperty("fs.includes");
+      excludes = <font color=blue>self.getProject()</font>  .<font color=blue>getProperty("fs.excludes")</font>;
+
+      // Create a &lt;fileset dir="" includes=""/&gt;
+      fs = project.<font color=blue>createDataType("fileset")</font>;
+      fs.setDir( new File(dir) );
+      <font color=blue>fs.setIncludes(includes)</font>;
+      fs.setExcludes(excludes);
+
+      // Get the files (array) of that fileset
+      ds = fs.getDirectoryScanner(project);
+      srcFiles = ds.getIncludedFiles();
+
+      // iterate over that array
+      for (i=0; i&lt;srcFiles.length; i++) {
+
+        // get the values via Java API
+        var basedir  = fs.getDir(project);
+        var filename = srcFiles[i];
+        var file = <font color=blue>new File(basedir, filename)</font>;
+        var size = file.length();
+
+        // create and use a Task via Ant API
+        echo = MyProject.<font color=blue>createTask("echo")</font>;
+        echo.setMessage(filename + ": " + size + " byte");
+        echo.<font color=blue>perform()</font>;
+      }
+    ]]&gt;&lt;/script&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre></blockquote>
+<p>We want to use the Java API. Because we don't want always typing the package signature
+we do an import. Rhino knows two different methods for import statements: one for packages
+and one for a single class. By default only the <i>java</i> packages are available, so
+<i>java.lang.System</i> can be directly imported with <code>importClass/importPackage</code>.
+For other packages you have to prefix the full classified name with <i>Packages</i>.
+For example Ant's <i>FileUtils</i> class can be imported with
+<code>importClass(<b>Packages</b>.org.apache.tools.ant.util.FileUtils)</code>
+<br>
+The <code>&lt;script&gt;</code> task populates the Project instance under
+the name <i>project</i>, so we can use that reference. Another way is to use its given name
+or getting its reference from the task itself.<br>
+The Project provides methods for accessing and setting properties, creating DataTypes and
+Tasks and much more.<br>
+After creating a FileSet object we initialize that by calling its set-methods. Then we can
+use that object like a normal Ant task (<code>&lt;copy&gt;</code> for example).<br>
+For getting the size of a file we instantiate a <code>java.io.File</code>. So we are using
+normal Java API here.<br>
+Finally we use the <code>&lt;echo&gt;</code> task for producing the output. The task is not executed by
+its execute() method, because the perform() method (implemented in Task itself) does the
+appropriate logging before and after invoking execute().
+</p>
+<p>
+  Here is an example of using beanshell to create an ant
+  task. This task will add filesets and paths to a referenced
+  path. If the path does not exist, it will be created.
+</p>
+<blockquote><pre>
+&lt;!--
+       Define addtopath task
+ --&gt;
+&lt;script language="beanshell"&gt;
+    import org.apache.tools.ant.Task;
+    import org.apache.tools.ant.types.Path;
+    import org.apache.tools.ant.types.FileSet;
+    public class AddToPath extends Task {
+        private Path path;
+        public void setRefId(String id) {
+            path = getProject().getReference(id);
+            if (path == null) {
+                path = new Path(getProject());
+                getProject().addReference(id, path);
+            }
+        }
+        public void add(Path c) {
+            path.add(c);
+        }
+        public void add(FileSet c) {
+            path.add(c);
+        }
+        public void execute() {
+            // Do nothing
+        }
+    }
+    project.addTaskDefinition("addtopath", AddToPath.class);
+&lt;/script&gt;
+</pre></blockquote>
+  <p>
+    An example of using this task to create a path
+    from a list of directories (using antcontrib's
+    <a href="http://ant-contrib.sourceforge.net/tasks/tasks/for.html">
+      &lt;for&gt;</a> task) follows:
+  </p>
+<blockquote><pre>
+&lt;path id="main.path"&gt;
+  &lt;fileset dir="build/classes"/&gt;
+&lt;/path&gt;
+&lt;ac:for param="ref" list="commons,fw,lps"
+        xmlns:ac="antlib:net.sf.antcontrib"&gt;
+  &lt;sequential&gt;
+    &lt;addtopath refid="main.path"&gt;
+      &lt;fileset dir="${dist.dir}/@{ref}/main"
+               includes="**/*.jar"/&gt;
+    &lt;/addtopath&gt;
+  &lt;/sequential&gt;
+&lt;/ac:for&gt;
+</pre></blockquote>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/scriptdef.html b/trunk/docs/manual/OptionalTasks/scriptdef.html
new file mode 100755
index 0000000..d63411a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/scriptdef.html
@@ -0,0 +1,332 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Scriptdef Task</title>
+</head>
+
+<body>
+
+<h2><a name="script">Scriptdef</a></h2>
+<h3>Description</h3>
+<p>Scriptdef can be used to define an Ant task using a scripting language. Ant
+scripting languages supported by
+<a href="http://jakarta.apache.org/bsf" target="_top">Apache BSF</a> 
+or
+  <a href="https://scripting.dev.java.net">JSR 223</a>
+may be
+used to define the script. Scriptdef provides a mechanism to encapsulate
+control logic from a build within an Ant task minimizing the need for
+providing control style tasks in Ant itself. Complex logic can be made
+available while retaining the simple structure of an Ant build file. Scriptdef
+is also useful for prototyping new custom tasks. Certainly as the complexity
+of the script increases it would be better to migrate the task definition
+into a Java based custom task.
+</p>
+
+<p><b>Note:</b> This task depends on external libraries not included in the
+Ant distribution. See
+<a href="../install.html#librarydependencies">Library Dependencies</a>
+for more information.</p>
+
+
+
+<p>The attributes and nested elements supported by the task may be defined
+using <code>&lt;attribute&gt;</code> and <code>&lt;element&gt;</code> nested elements. These are
+available to the script that implements the task as two collection style
+script variables <code>attributes</code> and <code>elements</code>. The
+elements in the <code>attributes</code> collection may be accessed by the
+attribute name. The <code>elements</code> collection is accessed by the nested
+element name. This will return a list of all instances of the nested element.
+The instances in this list may be accessed by an integer index.
+</p>
+
+<p><b>Note:</b> Ant will turn all attribute and element names into all
+lowercase names, so even if you use name="SomeAttribute", you'll have
+to use "someattribute" to retrieve the attribute's value from the
+<code>attributes</code> collection.</p>
+
+<p>The name "self" (<i>since Ant 1.6.3</i>) is a pre-defined reference to the
+    script def task instance.
+    It can be used for logging, or for integration with the rest of
+    ant. the <code>self.text attribute</code> contains
+    any nested text passed to the script</p>
+
+<p>If an attribute or element is not passed in, 
+then <code>attributes.get()</code> or <code>elements.get()</code> will 
+return null. It is up to the script to perform any checks and validation. 
+<code>self.fail(String message)</code>can be used to raise a 
+<code>BuildException</code>.
+</p>
+
+
+<p>The name "project" is a pre-defined reference to the Ant Project. For
+more information on writing scripts, please refer to the
+<a href="script.html"><code>&lt;script&gt;</code></a> task
+</p>
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the task to be created using the script</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">language</td>
+    <td valign="top">The programming language the script is written in.
+      Must be a supported Apache BSF or JSR 223 language</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">manager</td>
+    <td valign="top">
+      The script engine manager to use.
+      See the <a href="../OptionalTasks/script.html">script</a> task
+      for using this attribute.
+    </td>
+    <td valign="top" align="center">No - default is "auto"</td>
+  </tr>
+  <tr>
+    <td valign="top">src</td>
+    <td valign="top">The location of the script as a file, if not inline</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">uri</td>
+    <td valign="top">
+      The XML namespace uri that this definition should live in.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">
+      The classpath to pass into the script.
+    </td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">The classpath to use, given as a
+      <a href="../using.html#references">reference</a> to a path defined elsewhere.
+      <td align="center" valign="top">No</td>
+    </tr>
+    <tr>
+      <td valign="top">loaderRef</td>
+      <td valign="top">the name of the loader that is
+        used to load the script, constructed from the specified 
+        classpath. This allows multiple script defintions
+        to reuse the same class loader.
+      </td>
+      <td align="center" valign="top">No</td>
+    </tr>
+  </table>
+
+<h3>Nested elements</h3>
+<h4>attribute</h4>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the attribute</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+
+<h4>element</h4>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the nested element to be supported by the
+                     task defined by the script</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the classname of the class to be used for the nested element.
+         This specifies the class directly and is an alternative to specifying
+         the Ant type name.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">type</td>
+    <td valign="top">This is the name of an Ant task or type which is to
+        be used when this element is to be created. This is an alternative
+        to specifying the class name directly. If the type is in a namespace,
+        the URI and a : must be prefixed to the type. For example
+        <code>type="antlib:example.org:newtype"</code></td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">any resource or resource collection</td>
+    <td valign="top">Since Ant1.7.1, this task can load scripts
+    from any resource supplied as a nested element. when </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+
+</table>
+
+  <h4>classpath</h4>
+  <p>
+    See the <a href="../OptionalTasks/script.html">script</a> task
+    for using this nested element.
+  </p>
+
+
+<h3>Examples</h3>
+
+<p>
+The following definition creates a task which supports an attribute called
+attr and two nested elements, one being a fileset and the other a path. When
+executed, the resulting task logs the value of the attribute and the basedir
+of the first fileset.
+</p>
+
+<pre>
+  &lt;scriptdef name=&quot;scripttest&quot; language=&quot;javascript&quot;&gt;
+    &lt;attribute name=&quot;attr1&quot;/&gt;
+    &lt;element name=&quot;fileset&quot; type=&quot;fileset&quot;/&gt;
+    &lt;element name=&quot;path&quot; type=&quot;path&quot;/&gt;
+    &lt;![CDATA[
+
+      self.log(&quot;Hello from script&quot;);
+      self.log(&quot;Attribute attr1 = &quot; + attributes.get(&quot;attr1&quot;));
+      self.log(&quot;First fileset basedir = &quot;
+        + elements.get(&quot;fileset&quot;).get(0).getDir(project));
+
+    ]]&gt;
+  &lt;/scriptdef&gt;
+
+  &lt;scripttest attr1=&quot;test&quot;&gt;
+    &lt;path&gt;
+      &lt;pathelement location=&quot;src&quot;/&gt;
+    &lt;/path&gt;
+    &lt;fileset dir=&quot;src&quot;/&gt;
+    &lt;fileset dir=&quot;main&quot;/&gt;
+  &lt;/scripttest&gt;
+</pre>
+
+<p>
+The following variation on the above script lists the number of fileset elements
+and iterates through them
+</p>
+<pre>
+  &lt;scriptdef name=&quot;scripttest2&quot; language=&quot;javascript&quot;&gt;
+    &lt;element name=&quot;fileset&quot; type=&quot;fileset&quot;/&gt;
+    &lt;![CDATA[
+      filesets = elements.get(&quot;fileset&quot;);
+      self.log(&quot;Number of filesets = &quot; + filesets.size());
+      for (i = 0; i &lt; filesets.size(); ++i) {
+        self.log(&quot;fileset &quot; + i + &quot; basedir = &quot;
+          + filesets.get(i).getDir(project));
+      }
+    ]]&gt;
+  &lt;/scriptdef&gt
+
+  &lt;scripttest2&gt;
+    &lt;fileset dir=&quot;src&quot;/&gt;
+    &lt;fileset dir=&quot;main&quot;/&gt;
+  &lt;/scripttest2&gt;
+</pre>
+
+<p>
+When a script has a syntax error, the scriptdef name will be listed in the
+error. For example in the above script, removing the closing curly bracket
+would result in this error
+</p>
+
+<p><code>build.xml:15: SyntaxError: missing } in compound
+statement (scriptdef <code>&lt;scripttest2&gt;</code>; line 10)</code></p>
+
+<p>
+Script errors are only detected when a script task is actually executed.
+</p>
+<p>
+    The next example does uses nested text in Jython. It also declares 
+    the script in a new xml namespace, which must be used to refer to 
+    the task. Declaring scripts in a new namespace guarantees that Ant will 
+    not create a task of the same (namespace,localname) name pair. 
+</p>
+
+<pre>
+&lt;target name="echo-task-jython"&gt;
+  &lt;scriptdef language="jython"
+      name="echo"
+      uri="http://example.org/script"&gt;
+      &lt;![CDATA[
+self.log("text: " +self.text)
+    ]]&gt;
+    &lt;/scriptdef&gt;
+&lt;/target&gt;
+
+&lt;target name="testEcho" depends="echo-task-jython"
+    xmlns:s="http://example.org/script"&gt;
+  &lt;s:echo&gt;nested text&lt;/s:echo&gt;
+&lt;/target&gt;
+</pre>
+
+The next example shows the use of &lt;classpath&gt; and
+"loaderref" to get access to the beanshell jar.
+<pre>
+    &lt;scriptdef name="b1" language="beanshell"
+               loaderref="beanshell-ref"&gt;
+      &lt;attribute name="a"/&gt;
+      &lt;classpath
+        path="${user.home}/scripting/beanshell/bsh-1.3b1.jar"/&gt;
+      self.log("attribute a is " + attributes.get("a"));
+    &lt;/scriptdef&gt;
+
+    &lt;scriptdef name="b2" language="beanshell"
+               loaderref="beanshell-ref"&gt;
+      &lt;attribute name="a2"/&gt;
+      self.log("attribute a2 is " + attributes.get("a2"));
+    &lt;/scriptdef&gt;
+
+    &lt;b1 a="this is an 'a'"/&gt;
+    &lt;b2 a2="this is an 'a2' for b2"/&gt;
+</pre>
+<h3>Testing Scripts</h3>
+
+<p>
+The easiest way to test scripts is to use the 
+<a href="http://ant.apache.org/antlibs/antunit/">AntUnit</a> ant library.
+This will run all targets in a script that begin with "test" (and their dependencies). </p>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/serverdeploy.html b/trunk/docs/manual/OptionalTasks/serverdeploy.html
new file mode 100644
index 0000000..971aaf4
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/serverdeploy.html
@@ -0,0 +1,335 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ServerDeploy Task</title>
+
+</head>
+
+<body>
+
+<h1><a name="serverdeploy">ANT ServerDeploy User Manual</a></h1>
+<p>by</p>
+<!-- Names are in alphabetical order, on last name -->
+<ul>
+<li>Christopher A. Longo (<a href="mailto:cal@cloud9.net">cal@cloud9.net</a>)</li>
+<li>Cyrille Morvan (<a href="mailto:cmorvan@ingenosya.com">cmorvan@ingenosya.com</a>)</li>
+</ul>
+
+</p>
+<hr>
+<p> At present the tasks support:<br>
+
+<ul>
+<li><a href="http://www.bea.com" target="_top">Weblogic</a> servers</li>
+<li><a href="http://www.objectweb.org/jonas/" target="_top">JOnAS</a>
+2.4 Open Source EJB server</li>
+</ul>
+Over time we expect further optional tasks  to support additional J2EE Servers.
+</p>
+
+<hr>
+
+<table border="1" cellpadding="5">
+<tr><td>Task</td><td colspan="2">Application Servers</td></tr>
+<tr><td rowspan="4"><a href="#serverdeploy_element">serverdeploy</a></td><td colspan="2" align="center"><b>Nested Elements</b></td></tr>
+<tr><td><a href="#serverdeploy_generic">generic</a></td><td>Generic task</td></tr>
+<tr><td><a href="#serverdeploy_jonas">jonas</a></td><td>JOnAS 2.4</td></tr>
+<tr><td><a href="#serverdeploy_weblogic">weblogic</a></td><td>Weblogic</td></tr>
+
+</table>
+
+<a name="serverdeploy_element">
+<h2>ServerDeploy element</h2>
+
+<h3><b>Description:</b></h3>
+
+<p>The <code>serverdeploy</code> task is used to run a "hot" deployment tool for
+vendor-specific J2EE server. The task requires nested elements which define
+the attributes of the vendor-specific deployment tool being executed.
+Vendor-specific deployment tools elements may enforce rules for which
+attributes are required, depending on the tool.
+</p>
+
+<h3>Parameters:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">action</td>
+    <td valign="top">This is the action to be performed.  For most cases this
+    will be "deploy".  Some tools support additional actions, such as "delete", "list",
+    "undeploy", "update"...</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">source</td>
+    <td valign="top">A fully qualified path/filename of the component to be deployed.
+    This may be an .ear, .jar, .war, or any other type that is supported by the server.
+    </td>
+    <td>Tool dependent</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+
+<p>The serverdeploy task supports a nested <code>classpath</code> element to set the classpath.</p>
+
+<h3>Vendor-specific nested elements</h3>
+
+<h3>Parameters used for all tools:</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">classpath</td>
+    <td valign="top">The classpath to be passed to the JVM running the tool.
+    The classpath may also be supplied as a nested element.</td>
+    <td>Tool dependent</td>
+  </tr>
+  <tr>
+    <td valign="top">server</td>
+    <td valign="top">The address or URL for the server where the component will be deployed.</td>
+    <td>Tool dependent</td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">The user with privileges to deploy applications to the server.</td>
+    <td>Tool dependent</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">The password of the user with privileges to deploy applications to the server.</td>
+    <td>Tool dependent</td>
+  </tr>
+</table>
+
+<p>Also supported are nested vendor-specific elements.</p>
+
+<a name="serverdeploy_generic">
+<h3>Generic element</h3>
+This element is provided for generic Java-based deployment tools.
+The generic task accepts (but does not require) nested <code>arg</code>
+and <code>jvmarg</code> elements.
+A JVM will be spawned with the provided attributes.  It is recommended
+that a vendor-specific element be used over the generic one if at all
+possible.
+<p>The following attributes are supported by the generic element.</p>
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">This is the fully qualified classname of the Java based
+    deployment tool to execute.</td>
+    <td>Yes</td>
+  </tr>
+</table>
+</p>
+
+<h3>Nested Elements</h3>
+<p>The generic element supports nested <code>&lt;arg&gt;</code> and <code>&lt;jvmarg&gt;</code> elements.</p>
+
+<h3>Example</h3>
+
+<p>This example shows the use of generic deploy element to deploy a component
+using a Java based deploy tool:</p>
+
+<pre>
+    &lt;serverdeploy action=&quot;deploy&quot; source=&quot;${lib.dir}/ejb_myApp.ear&quot;&gt;
+        &lt;generic classname="com.yamato.j2ee.tools.deploy.DeployTool"
+            classpath=&quot;${classpath}&quot;
+            username=&quot;${user.name}&quot;
+            password=&quot;${user.password}&quot;&gt;
+            &lt;arg value="-component=WildStar"/&gt;
+            &lt;arg value="-force"/&gt;
+            &lt;jvmarg value="-ms64m"/&gt;
+            &lt;jvmarg value="-mx128m"/&gt;
+        &lt;/generic&gt;
+    &lt;/serverdeploy&gt;
+</pre>
+
+<a name="serverdeploy_weblogic">
+<h3>WebLogic element</h3>
+<p>
+The WebLogic element contains additional attributes to run the
+<code>weblogic.deploy</code> deployment tool.
+<p>Valid actions for the tool are <code>deploy</code>, <code>undeploy</code>,
+<code>list</code>, <code>update</code>, and <code>delete</code>.
+<p>If the action is <code>deploy</code> or <code>update</code>,
+the <code>application</code> and <code>source</code> attributes must be set.
+If the action is <code>undeploy</code> or <code>delete</code>,
+the <code>application</code> attribute must be set.  If the <code>username</code>
+attribute is omitted, it defaults to "system".  The <code>password</code> attribute is
+required for all actions.
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">application</td>
+    <td valign="top">This is the name of the application being deployed</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">component</td>
+    <td valign="top">This is the component string for deployment targets.
+    It is in the form <code>&lt;component&gt;:&lt;target1&gt;,&lt;target2&gt;...</code>
+    Where component is the archive name (minus the .jar, .ear, .war
+    extension).  Targets are the servers where the components will be deployed</td>
+    <td>no</td>
+  </tr>
+  <tr>
+    <td valign="top">debug</td>
+    <td valign="top">If set to true, additional information will be
+    printed during the deployment process.</td>
+    <td>No</td>
+  </tr>
+</table>
+
+
+<h3>Examples</h3>
+
+<p>This example shows the use of serverdeploy to deploy a component to a WebLogic server:</p>
+
+<pre>
+    &lt;serverdeploy action=&quot;deploy&quot; source=&quot;${lib.dir}/ejb_myApp.ear&quot;&gt;
+        &lt;weblogic application=&quot;myapp&quot;
+            server=&quot;t3://myserver:7001&quot;
+            classpath=&quot;${weblogic.home}/lib/weblogic.jar&quot;
+            username=&quot;${user.name}&quot;
+            password=&quot;${user.password}&quot;
+            component=&quot;ejb_foobar:myserver,productionserver&quot;
+            debug=&quot;true&quot;/&gt;
+    &lt;/serverdeploy&gt;
+</pre>
+
+<p>This example shows serverdeploy being used to delete a component from a
+WebLogic server:</p>
+
+<pre>
+    &lt;serverdeploy action=&quot;delete&quot; source=&quot;${lib.dir}/ejb_myApp.jar&quot;/&gt
+        &lt;weblogic application=&quot;myapp&quot;
+            server=&quot;t3://myserver:7001&quot;
+            classpath=&quot;${weblogic.home}/lib/weblogic.jar&quot;
+            username=&quot;${user.name}&quot;
+            password=&quot;${user.password}&quot;/&gt;
+    &lt;/serverdeploy&gt;
+</pre>
+
+<a name="serverdeploy_jonas">
+<h3>JOnAS (Java Open Application Server) element</h3>
+<p>
+The JOnAS element contains additional attributes to run the
+<code>JonasAdmin</code> deployment tool.
+<p>Valid actions for the tool are <code>deploy</code>, <code>undeploy</code>,
+<code>list</code> and <code>update</code>.
+<p>You can't use <code>user</code> and <code>password</code> property with this 
+task.
+<p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">jonasroot</td>
+    <td valign="top">The root directory for JOnAS.</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">orb</td>
+    <td valign="top">Choose your ORB : RMI, JEREMIE, DAVID, ... If omitted, it defaults
+     to the one present in classpath. The corresponding JOnAS JAR is
+     automatically added to the classpath. If your orb is DAVID (RMI/IIOP) you must 
+     specify davidhost and davidport properties.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td valign="top">davidhost</td>
+    <td valign="top">The value for the system property : <code>david.CosNaming.default_host</code> .</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td valign="top">davidport</td>
+    <td valign="top">The value for the system property : <code>david.CosNaming.default_port</code> .</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">This is the fully qualified classname of the Java based
+    deployment tool to execute. Default to <code>org.objectweb.jonas.adm.JonasAdmin</code></td>
+    <td>No</td>
+  </tr>
+
+</table>
+
+<h3>Nested Elements</h3>
+<p>The jonas element supports nested <code>&lt;arg&gt;</code> and <code>&lt;jvmarg&gt;</code> elements.</p>
+
+
+<h3>Examples</h3>
+
+<p>This example shows the use of serverdeploy to deploy a component to a JOnAS server:</p>
+
+<pre>
+    &lt;serverdeploy action=&quot;deploy&quot; source=&quot;${lib.dir}/ejb_myApp.jar&quot;&gt;
+        &lt;jonas server=&quot;MyJOnAS&quot; jonasroot="${jonas.root}"&gt;
+
+           &lt;classpath&gt;
+               &lt;pathelement path=&quot;${jonas.root}/lib/RMI_jonas.jar&quot;/&gt;
+               &lt;pathelement path=&quot;${jonas.root}/config/&quot;/&gt;
+           &lt;/classpath&gt;
+        &lt;/jonas&gt;
+    &lt;/serverdeploy&gt;
+</pre>
+
+<p>This example shows serverdeploy being used to list the components from a
+JOnAS server and a WebLogic server:</p>
+
+<pre>
+    &lt;serverdeploy action=&quot;list&quot;/&gt
+        &lt;jonas jonasroot=&quot;${jonas.root}&quot; orb=&quot;JEREMIE&quot;/&gt;
+        &lt;weblogic application=&quot;myapp&quot
+            server=&quot;t3://myserver:7001&quot;
+            classpath=&quot;${weblogic.home}/lib/weblogic.jar&quot;
+            username=&quot;${user.name}&quot;
+            password=&quot;${user.password}&quot;/&gt;
+    &lt;/serverdeploy&gt;
+</pre>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/setproxy.html b/trunk/docs/manual/OptionalTasks/setproxy.html
new file mode 100644
index 0000000..60aa984
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/setproxy.html
@@ -0,0 +1,222 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Setproxy
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Setproxy
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Sets Java's web proxy properties, so that tasks and code run in the same JVM can have through-the-firewall access to remote web sites, and remote ftp sites.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Sets Java's web proxy properties, so that tasks and code run in the same JVM can have through-the-firewall access to remote web sites, and remote ftp sites. You can nominate an http and ftp proxy, or a socks server, reset the server settings, or do nothing at all. <p> Examples <pre>&lt;setproxy/&gt;</pre> do nothing <pre>&lt;setproxy proxyhost="firewall"/&gt;</pre> set the proxy to firewall:80 <pre>&lt;setproxy proxyhost="firewall" proxyport="81"/&gt;</pre> set the proxy to firewall:81 <pre>&lt;setproxy proxyhost=""/&gt;</pre> stop using the http proxy; don't change the socks settings <pre>&lt;setproxy socksproxyhost="socksy"/&gt;</pre> use socks via socksy:1080 <pre>&lt;setproxy socksproxyhost=""/&gt;</pre> stop using the socks server. <p> You can set a username and password for http with the <tt>proxyHost</tt> and <tt>proxyPassword</tt> attributes. On Java1.4 and above these can also be used against SOCKS5 servers. </p>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+ <!-- Ignore -->
+
+
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">nonproxyhosts</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">A list of hosts to bypass the proxy on. These should be separated with the vertical bar character '|'. Only in Java 1.4 does ftp use this list. e.g. fozbot.corp.sun.com|*.eng.sun.com</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="7">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">proxyhost</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">the HTTP/ftp proxy host. Set this to "" for the http proxy option to be disabled</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">proxypassword</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the password for the proxy. Used only if the proxyUser is set.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">proxyport</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">the HTTP/ftp proxy port number; default is 80</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">proxyuser</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the proxy user. Probably requires a password to accompany this setting. Default=""</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">socksproxyhost</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">The name of a Socks server. Set to "" to turn socks proxying off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">socksproxyport</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the ProxyPort for socks connections. The default value is 1080</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/sos.html b/trunk/docs/manual/OptionalTasks/sos.html
new file mode 100644
index 0000000..f6efe55
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/sos.html
@@ -0,0 +1,503 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+
+  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+  <link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SOS Tasks</title>
+
+</head>
+<body>
+
+<div align="center">
+<h1>SourceOffSite Tasks User Manual</h1>
+
+<div align="left">by
+<ul>
+<li><a href="mailto:jesse@cryptocard.com">Jesse Stockall</a></li>
+</ul>
+Version 1.1 2002/01/23
+<br>
+<br>
+
+<hr width="100%" size="2">
+<h2>Contents</h2>
+
+<ul>
+    <li><a href="#intro">Introduction</a></li>
+    <li><a href="#tasks">The Tasks</a></li>
+
+</ul>
+<br>
+
+<h2><a name="intro">Introduction</a> </h2>
+
+<p>These tasks provide an interface to the <a href="http://msdn.microsoft.com/ssafe/default.asp" target="_top">
+Microsoft Visual SourceSafe</a> SCM via <a href="http://www.sourcegear.com">
+SourceGear's</a> <a href="http://sourcegear.com/sos/index.htm">SourceOffSite</a>
+product. SourceOffSite is an add-on to Microsoft's VSS, that allows remote
+development teams and tele-commuters that need fast and secure read/write
+access to a centralized SourceSafe database via any TCP/IP connection. SOS
+provides Linux ,Solaris &amp; Windows clients. The
+<code> org.apache.tools.ant.taskdefs.optional.sos</code>
+package consists  of a simple framework to support SOS functionality as well
+as some Ant tasks  encapsulating frequently used SOS commands.  Although it
+is possible to use  these commands on the desktop,  they were primarily intended
+to be used by  automated build systems. These tasks have been tested with
+SourceOffSite  version 3.5.1 connecting to VisualSourceSafe 6.0. The tasks
+have been tested with Linux, Solaris &amp; Windows2000.</p>
+
+<h2><a name="tasks">The Tasks</a> </h2>
+
+<table border="0" cellspacing="0" cellpadding="3">
+       <tbody>
+         <tr>
+           <td><a href="#SOSGet">sosget</a></td>
+           <td>Retrieves a read-only copy of the specified project or file.</td>
+         </tr>
+         <tr>
+           <td><a href="#SOSLabel">soslabel</a></td>
+           <td>Assigns a label to the specified project.</td>
+         </tr>
+         <tr>
+           <td><a href="#SOSCheckIn">soscheckin</a></td>
+           <td>Updates VSS with changes made to a checked out file or project,
+           and unlocks the VSS master copy.</td>
+         </tr>
+         <tr>
+           <td><a href="#SOSCheckOut">soscheckout</a></td>
+           <td>Retrieves a read-write copy of the specified project
+           or file, locking the&nbsp;VSS master copy</td>
+         </tr>
+
+  </tbody>
+</table>
+     <br>
+
+<hr width="100%" size="2">
+<h2>Task Descriptions</h2>
+
+<h2><a name="SOSGet"></a>SOSGet<br>
+     </h2>
+<h3>Description</h3>
+             Task to perform GET commands with SOS<br>
+<h3>Parameters</h3>
+     </div>
+     </div>
+
+<table border="1">
+     <tbody>
+       <tr>
+          <th>Attribute</th>
+          <th>Values</th>
+          <th>Required</th>
+        </tr>
+        <tr>
+          <td>soscmd</td>
+          <td>Directory which contains soscmd(.exe) <br>
+          soscmd(.exe) must be in the path if this is not specified</td>
+          <td>No</td>
+        </tr>
+        <tr>
+           <td>vssserverpath</td>
+           <td>path to the srcsafe.ini  - eg. \\server\vss\srcsafe.ini</td>
+           <td>Yes</td>
+        </tr>
+        <tr>
+           <td>sosserverpath</td>
+           <td>address &amp; port of the SOS server  - eg. 192.168.0.1:8888</td>
+           <td>Yes</td>
+        </tr>
+        <tr>
+           <td>projectpath</td>
+           <td>SourceSafe project path - eg. $/SourceRoot/Project1</td>
+           <td>Yes</td>
+        </tr>
+        <tr>
+           <td>file</td>
+           <td>Filename to act upon<br>
+           If no file is specified then act upon the project</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>username</td>
+           <td>SourceSafe username</td>
+           <td>Yes</td>
+        </tr>
+        <tr>
+           <td>password</td>
+           <td>SourceSafe password</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>localpath</td>
+           <td>Override the working directory and get to the specified path</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>soshome</td>
+           <td>The path to the SourceOffSite home directory</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>nocompress</td>
+           <td>true or false - disable compression</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>recursive</td>
+           <td>true or false - Only works with the GetProject command</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>version</td>
+           <td>a version number to get - Only works with the GetFile command</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>label</td>
+           <td>a label version to get - Only works with the GetProject command</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>nocache</td>
+           <td>true or false - Only needed if SOSHOME is set as an environment variable</td>
+           <td>No</td>
+        </tr>
+        <tr>
+           <td>verbose</td>
+           <td>true or false - Status messages are displayed</td>
+           <td>No</td>
+        </tr>
+  </tbody>
+</table>
+
+<h3>Example</h3>
+
+<pre>
+&lt;sosget verbose=&quot;true&quot;
+        recursive=&quot;true&quot;
+        username=&quot;build&quot;
+        password=&quot;build&quot;
+        localpath=&quot;tmp&quot;
+        projectpath=&quot;$/SourceRoot/project1&quot;
+        sosserverpath=&quot;192.168.10.6:8888&quot;
+        vssserverpath=&quot;d:\vss\srcsafe.ini&quot;/&gt;
+</pre>
+<small>Connects to a SourceOffsite server on 192.168.10.6:8888 with
+build,build as the username &amp; password. The SourceSafe  database resides
+on the same box as the SOS server  &amp; the VSS database  is at
+&quot;d:\vss\srcsafe.ini&quot; Does a recursive GetProject on
+$/SourceRoot/project1, using tmp as the working
+directory. </small><br>
+<br>
+
+<hr width="100%" size="2">
+<h2><a name="SOSLabel"></a>SOSLabel</h2>
+
+<h3>Description</h3>
+             Task to perform Label commands with SOS<br>
+<h3>Parameters</h3>
+
+<table border="1">
+    <tbody><tr>
+      <th>Attribute</th>
+      <th>Values</th>
+      <th>Required</th>
+    </tr>
+    <tr>
+      <td>soscmd</td>
+      <td>Directory which contains soscmd(.exe) <br>
+      soscmd(.exe) must be in the path if this is not specified</td>
+      <td>No</td>
+    </tr>
+    <tr>
+       <td>vssserverpath</td>
+       <td>path to the srcsafe.ini  - eg. \\server\vss\srcsafe.ini</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>sosserverpath</td>
+       <td>address and port of the SOS server  - eg. 192.168.0.1:8888</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>projectpath</td>
+       <td>SourceSafe project path - eg. $/SourceRoot/Project1</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>username</td>
+       <td>SourceSafe username</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>password</td>
+       <td>SourceSafe password</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>label</td>
+       <td>The label to apply to a project</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>comment</td>
+       <td>A comment to be applied to all files being labeled</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>verbose</td>
+       <td>true or false - Status messages are displayed</td>
+       <td>No</td>
+    </tr>
+  </tbody>
+</table>
+
+<h3>Example</h3>
+<pre>
+&lt;soslabel username=&quot;build&quot;
+          password=&quot;build&quot;
+          label=&quot;test label&quot;
+          projectpath=&quot;$/SourceRoot/project1&quot;
+          sosserverpath=&quot;192.168.10.6:8888&quot;
+          vssserverpath=&quot;d:\vss\srcsafe.ini&quot;/&gt;
+</pre>
+
+<small>Connects to a SourceOffsite server on 192.168.10.6:8888 with
+build,build as the username &amp; password. The SourceSafe database resides
+on the same box as  the  SOS server  &amp; the VSS database is at
+&quot;d:\vss\srcsafe.ini&quot;. Labels the $/SourceRoot/project1
+project with &quot;test label&quot;.</small><br>
+<br>
+
+<hr width="100%" size="2"><br>
+
+<h2><a name="SOSCheckIn"></a>SOSCheckIn</h2>
+
+<h3>Description</h3>
+        Task to perform CheckIn commands with SOS<br>
+<h3>Parameters</h3>
+<table border="1">
+       <tbody>
+    <tr>
+      <th>Attribute</th>
+      <th>Values</th>
+      <th>Required</th>
+    </tr>
+    <tr>
+      <td>soscmd</td>
+      <td>Directory which contains soscmd(.exe) <br>
+      soscmd(.exe) must be in the path if this is not specified</td>
+      <td>No</td>
+    </tr>
+    <tr>
+       <td>vssserverpath</td>
+       <td>path to the srcsafe.ini  - eg. \\server\vss\srcsafe.ini</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>sosserverpath</td>
+       <td>address and port of the SOS server  - eg. 192.168.0.1:8888</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>projectpath</td>
+       <td>SourceSafe project path - eg. $/SourceRoot/Project1</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>file</td>
+       <td>Filename to act upon<br> If no file is specified then act upon the project</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>username</td>
+       <td>SourceSafe username</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>password</td>
+       <td>SourceSafe password</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>localpath</td>
+       <td>Override the working directory and get to the specified path</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>soshome</td>
+       <td>The path to the SourceOffSite home directory</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>nocompress</td>
+       <td>true or false - disable compression</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>recursive</td>
+       <td>true or false - Only works with the CheckOutProject command</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>nocache</td>
+       <td>true or false - Only needed if SOSHOME is set as an environment variable</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>verbose</td>
+       <td>true or false - Status messages are displayed</td>
+       <td>No</td>
+    </tr>
+    <tr><td>comment</td>
+       <td>A comment to be applied to all files being checked in</td>
+       <td>No</td>
+    </tr>
+ </tbody>
+</table>
+
+<h3>Example</h3>
+<pre>
+&lt;soscheckin username=&quot;build&quot;
+            password=&quot;build&quot;
+            file=&quot;foobar.txt&quot;
+            verbose=&quot;true&quot;
+            comment=&quot;comment abc&quot;
+            projectpath=&quot;$/SourceRoot/project1&quot;
+            sosserverpath=&quot;server1:8888&quot;
+            vssserverpath=&quot;\\server2\vss\srcsafe.ini&quot;/&gt;
+</pre>
+
+<small>Connects to a SourceOffsite server on server1:8888 with build,build as
+the username &amp; password. The SourceSafe database resides on a different
+box (server2) &amp; the VSS database is on a share called
+&quot;vss&quot;. Checks-in only the &quot;foobar.txt&quot; file adding
+a comment of &quot;comment abc&quot;. Extra status messages will be
+displayed on screen.</small><br>
+<br>
+
+<hr width="100%" size="2">
+<h2><a name="SOSCheckOut"></a>SOSCheckOut</h2>
+
+<h3>Description</h3>
+       Task to perform CheckOut commands with SOS<br>
+
+<h3>Parameters</h3>
+
+<table border="1">
+       <tbody>
+    <tr>
+      <th>Attribute</th>
+      <th>Values</th>
+      <th>Required</th>
+    </tr>
+    <tr>
+      <td>soscmd</td>
+      <td>Directory which contains soscmd(.exe) <br>
+      soscmd(.exe) must be in the path if this is not specified</td>
+      <td>No</td>
+    </tr>
+    <tr>
+       <td>vssserverpath</td>
+       <td>path to the srcsafe.ini  - eg. \\server\vss\srcsafe.ini</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>sosserverpath</td>
+       <td>address and port of the SOS server  - eg. 192.168.0.1:8888</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>projectpath</td>
+       <td>SourceSafe project path - eg. $/SourceRoot/Project1</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>file</td>
+       <td>Filename to act upon<br> If no file is specified then act upon the project</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>username</td>
+       <td>SourceSafe username</td>
+       <td>Yes</td>
+    </tr>
+    <tr>
+       <td>password</td>
+       <td>SourceSafe password</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>localpath</td>
+       <td>Override the working directory and get to the specified path</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>soshome</td>
+       <td>The path to the SourceOffSite home directory</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>nocompress</td>
+       <td>true or false - disable compression</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>recursive</td>
+       <td>true or false - Only works with the CheckOutProject command</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>nocache</td>
+       <td>true or false - Only needed if SOSHOME is set as an environment variable</td>
+       <td>No</td>
+    </tr>
+    <tr>
+       <td>verbose</td>
+       <td>true or false - Status messages are displayed</td>
+       <td>No</td>
+    </tr>
+  </tbody>
+</table>
+     <br>
+
+<h3>Example</h3>
+<pre>
+&lt;soscheckout soscmd=&quot;/usr/local/bin&quot;
+             verbose=&quot;true&quot;
+             username=&quot;build&quot;
+             password=&quot;build&quot;
+             projectpath=&quot;$/SourceRoot/project1&quot;
+             sosserverpath=&quot;192.168.10.6:8888&quot;
+             vssserverpath=&quot;\\server2\vss\srcsafe.ini&quot;/&gt;
+</pre>
+
+<small>Connects to a SourceOffsite server on server1:8888 with build,build as
+the username &amp; password. The SourceSafe database resides on a different
+box (server2) &amp; the VSS database is on a share called
+&quot;vss&quot;. Checks-out &quot;project1&quot;, Only the
+&quot;project1&quot; directory will be locked as the recursive option
+was not set. Extra status messages will be displayed on screen. The
+soscmd(.exe) file to be used resides in /usr/local/bin.</small><br>
+<br>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/sound.html b/trunk/docs/manual/OptionalTasks/sound.html
new file mode 100644
index 0000000..1095f80
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/sound.html
@@ -0,0 +1,123 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Sound Task</title>
+</head>
+
+<body>
+
+<h2><a name="sound">Sound</a></h2>
+<h3>Description</h3>
+<p>Plays a sound-file at the end of the build, according to whether
+the build failed or succeeded. You can specify either a specific
+sound-file to play, or, if a directory is specified, the
+<code>&lt;sound&gt;</code> task will randomly select a file to play.
+Note: At this point, the random selection is based on all the files
+in the directory, not just those ending in appropriate suffixes
+for sound-files, so be sure you only have sound-files in the 
+directory you specify.</p>
+<p>More precisely <code>&lt;sound&gt;</code> registers a hook that is
+triggered when the build finishes. Therefore you have to place this
+task as top level or inside a target which is always executed.</p>
+<p>
+Unless you are running on Java 1.3 or later, you need the Java Media Framework
+on the classpath (javax.sound). 
+</p>
+
+
+<h3>Nested Elements</h3>
+<h4>success</h4>
+<p>Specifies the sound to be played if the build succeeded.</p>
+<h4>fail</h4>
+<p>Specifies the sound to be played if the build failed.</p>
+
+<h3>Nested Element Parameters</h3>
+<p>
+The following attributes may be used on the <code>&lt;success&gt;</code> 
+and <code>&lt;fail&gt;</code> elements:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">source</td>
+    <td valign="top">the path to a sound-file directory, or the name of a
+specific sound-file, to be played. If this file does not exist, an error message
+will be logged.
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">loops</td>
+    <td valign="top">the number of extra times to play the sound-file;
+      default is <code>0</code>.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">duration</td>
+    <td valign="top">the amount of time (in milliseconds) to play
+      the sound-file.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;target name=&quot;fun&quot; if=&quot;fun&quot; unless=&quot;fun.done&quot;&gt;
+  &lt;sound&gt;
+    &lt;success source=&quot;${user.home}/sounds/bell.wav&quot;/&gt;
+    &lt;fail source=&quot;${user.home}/sounds/ohno.wav&quot; loops=&quot;2&quot;/&gt;
+  &lt;/sound&gt;
+  &lt;property name=&quot;fun.done&quot; value=&quot;true&quot;/&gt;
+&lt;/target&gt;
+</pre>
+</blockquote>
+plays the <code>bell.wav</code> sound-file if the build succeeded, or
+the <code>ohno.wav</code> sound-file if the build failed, three times,
+if the <code>fun</code> property is set to <code>true</code>.
+If the target
+is a dependency of an &quot;initialization&quot; target that other
+targets depend on, the
+<code>fun.done</code> property prevents the target from being executed
+more than once.
+<blockquote>
+<pre>
+&lt;target name=&quot;fun&quot; if=&quot;fun&quot; unless=&quot;fun.done&quot;&gt;
+  &lt;sound&gt;
+    &lt;success source=&quot;//intranet/sounds/success&quot;/&gt;
+    &lt;fail source=&quot;//intranet/sounds/failure&quot;/&gt;
+  &lt;/sound&gt;
+  &lt;property name=&quot;fun.done&quot; value=&quot;true&quot;/&gt;
+&lt;/target&gt;
+</pre>
+</blockquote>
+randomly selects a sound-file to play when the build succeeds or fails.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/splash.html b/trunk/docs/manual/OptionalTasks/splash.html
new file mode 100644
index 0000000..bfa10a3
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/splash.html
@@ -0,0 +1,119 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Ant User Manual</title>
+</head>
+
+<body>
+
+<h2><a name="Splash">Splash</a></h2>
+<p>by Les Hughes (leslie.hughes@rubus.com)
+<h3>Description</h3>
+<p>This task creates a splash screen. The splash screen is displayed
+for the duration of the build and includes a handy progress bar as
+well. Use in conjunction with the sound task to provide interest
+whilst waiting for your builds to complete...</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+    <td align="center" valign="top"><b>Default</b></td>
+  </tr>
+  <tr>
+    <td valign="top">imageurl</td>
+    <td valign="top">A URL pointing to an image to display.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">antlogo.gif from the classpath</td>
+  </tr>
+ 
+  <tr>
+    <td valign="top">showduration</td>
+    <td valign="top">Initial period to pause the build to show the
+    splash in milliseconds.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">5000 ms</td>
+  </tr>  
+</table>
+<h3>Deprecated properties</h3>
+  
+The following properties can be used to configure the proxy settings to retrieve
+an image from behind a firewall. However, the settings apply not just to this
+task, but to all following tasks. Therefore they are now mostly deprecated in 
+preference to the <code>&lt;setproxy&gt;</code> task, that makes it clear to readers of
+the build exactly what is going on. We say mostly as this task's support
+includes proxy authentication, so you may still need to use its
+proxy attributes.
+  
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top">useproxy</td>
+    <td valign="top">Use a proxy to access imgurl. Note: Only tested
+    on JDK 1.2.2 and above</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">None</td>
+  </tr>
+  <tr>
+    <td valign="top">proxy</td>
+    <td valign="top">IP or hostname of the proxy server</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">None</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">Proxy portnumber</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">None</td>
+  </tr>
+  <tr>
+    <td valign="top">user</td>
+    <td valign="top">User to authenticate to the proxy as.</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">None</td>
+
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">Proxy password</td>
+    <td valign="top" align="center">No</td>
+    <td valign="top" align="center">None</td>
+  </tr>
+
+</table>
+<h3>Examples</h3>
+<blockquote><pre>
+&lt;splash/&gt;
+</pre></blockquote>
+<p>Splash <code>images/ant_logo_large.gif</code> from the classpath.</p>
+<blockquote><pre>
+&lt;splash imageurl=&quot;http://jakarta.apache.org/images/jakarta-logo.gif&quot;
+           useproxy=&quot;true&quot;
+           showduration=&quot;5000&quot;/&gt;
+
+</pre></blockquote>
+<p>Splashes the jakarta logo, for
+an initial period of 5 seconds.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/sshexec.html b/trunk/docs/manual/OptionalTasks/sshexec.html
new file mode 100644
index 0000000..0ca960d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/sshexec.html
@@ -0,0 +1,192 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>SSHEXEC Task</title>
+</head>
+
+<body>
+
+<h2><a name="sshexec">SSHEXEC</a></h2>
+<h3>Description</h3>
+
+<p><em>since Ant 1.6</em></p>
+
+<p>Runs a command on a remote machine running SSH daemon.
+</p>
+
+<p><b>Note:</b> This task depends on external libraries not included
+in the Ant distribution.  See <a
+href="../install.html#librarydependencies">Library Dependencies</a>
+for more information.  This task has been tested with jsch-0.1.29 and above
+and won't work with versions of jsch earlier than
+0.1.28.</p>
+
+<p>See also the <a href="scp.html">scp task</a></p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">host</td>
+    <td valign="top">The hostname or IP address of the remote host to which you wish to connect.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">The username on the remote host to which you are connecting.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">command</td>
+    <td valign="top">The command to run on the remote host.</td>
+    <td valian="top" align="center">Either this or commandResource must be set</td>
+  </tr>
+  <tr>
+    <td valign="top">commandResource</td>
+    <td valign="top">The resource (file) that contains the commands to run on the remote host.
+    Since Ant 1.7.1</td>
+    <td valian="top" align="center">Either this or command must be set</td>
+  </tr>
+  <tr>
+    <td valign="top">port</td>
+    <td valign="top">The port to connect to on the remote host.</td>
+    <td valian="top" align="center">No, defaults to 22.</td>
+  </tr>
+  <tr>
+    <td valign="top">trust</td>
+
+    <td valign="top">This trusts all unknown hosts if set to yes/true.<br>
+      <strong>Note</strong> If you set this to false (the default), the
+      host you connect to must be listed in your knownhosts file, this
+      also implies that the file exists.</td>
+    <td valian="top" align="center">No, defaults to No.</td>
+  </tr>
+  <tr>
+    <td valign="top">knownhosts</td>
+    <td valign="top">This sets the known hosts file to use to validate
+    the identity of the remote host.  This must be a SSH2 format file.
+    SSH1 format is not supported.</td>
+    <td valian="top" align="center">No, defaults to
+    ${user.home}/.ssh/known_hosts.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">Whether to halt the build if the command does not complete successfully.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+     <td valign="top">The password.</td>
+     <td valign="top" align="center">Not if you are using key based
+     authentication or the password has been given in the file or
+     todir attribute.</td>
+  </tr>
+  <tr>
+    <td valign="top">keyfile</td>
+     <td valign="top">Location of the file holding the private key.</td>
+     <td valign="top" align="center">Yes, if you are using key based
+     authentication.</td>
+  </tr>
+  <tr>
+    <td valign="top">passphrase</td>
+     <td valign="top">Passphrase for your private key.</td>
+     <td valign="top" align="center">No, defaults to an empty string.</td>
+  </tr>
+  <tr>
+    <td valign="top">output</td>
+    <td valign="top">Name of a file to which to write the output.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">append</td>
+    <td valign="top">Whether output file should be appended to or overwritten. Defaults to false, meaning overwrite any existing file.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">outputproperty</td>
+    <td valign="top">The name of a property in which the output of the 
+      command should be stored.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">timeout</td>
+    <td valign="top">Stop the command if it doesn't finish within the
+      specified time (given in milliseconds). Defaults to 0 which means &quot;wait forever&quot;.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<p><b>Run a command on a remote machine using password authentication</b></p>
+<pre>
+  &lt;sshexec host=&quot;somehost&quot;
+	username=&quot;dude&quot;
+	password=&quot;yo&quot;
+	command=&quot;touch somefile&quot;/&gt;
+</pre>
+
+<p><b>Run a command on a remote machine using key authentication</b></p>
+<pre>
+  &lt;sshexec host=&quot;somehost&quot;
+	username=&quot;dude&quot;
+	keyfile=&quot;${user.home}/.ssh/id_dsa&quot;
+	passphrase=&quot;yo its a secret&quot;
+	command=&quot;touch somefile&quot;/&gt;
+</pre>
+
+<p><b>Run a command on a remote machine using key authentication with no passphrase</b></p>
+<pre>
+  &lt;sshexec host=&quot;somehost&quot;
+	username=&quot;dude&quot;
+	keyfile=&quot;${user.home}/.ssh/id_dsa&quot;
+	command=&quot;touch somefile&quot;/&gt;
+</pre>
+
+<p><b>Run a set of commands from a command resource (file) on a remote machine using key authentication with no passphrase</b></p>
+<pre>
+  &lt;sshexec host=&quot;somehost&quot;
+	username=&quot;dude&quot;
+	keyfile=&quot;${user.home}/.ssh/id_dsa&quot;
+	commandResource=&quot;to_run&quot;/&gt;
+</pre>
+
+
+<p><strong>Security Note:</strong>  Hard coding passwords and/or usernames
+in sshexec task can be a serious security hole.  Consider using variable
+substitution and include the password on the command line.  For example:<br>
+<pre>
+  &lt;sshexec host=&quot;somehost&quot;
+	username=&quot;${username}&quot;
+	password=&quot;${password}&quot;
+	command=&quot;touch somefile&quot;/&gt;
+</pre>
+Invoke ant with the following command line:
+<pre>
+    ant -Dusername=me -Dpassword=mypassword target1 target2
+</pre>
+</p>
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/starteam.html b/trunk/docs/manual/OptionalTasks/starteam.html
new file mode 100644
index 0000000..54e3359
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/starteam.html
@@ -0,0 +1,990 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>StarTeam Tasks</title>
+</head>
+<body>
+<h1>StarTeam Support</h1>
+<ul>
+  <li><a href="#stcheckout">STCheckout</a></li> 
+  <li><a href="#stcheckin">STCheckin</a></li>
+  <li><a href="#stlabel">STLabel</a></li>
+  <li><a href="#stlist">STList</a></li>
+  <li><a href="#starteam"><i>StarTeam (deprecated) </i></a></li>
+</ul>
+
+<p>
+The StarTeam revision control system was recently acquired by Borland.
+These tasks make use of functions from the StarTeam API to work with that system.  
+As a result they are only available to licensed users of StarTeam.  You must have
+<CODE>starteam-sdk.jar</CODE> in your classpath to run these tasks.
+For more information about the StarTeam API and how to license it, see
+the <a href="http://www.borland.com/starteam/">Borland</a> web site.</p>
+  <p>
+    <em>All the StarTeam task names are in lower case.</em>
+  </p>
+<h3>Important Note on Installation and Licensing:</h3>
+<p>
+<b>On Windows machines, the mere presence of <CODE>starteam-sdk.jar</CODE> on the classpath 
+is not sufficient for getting these tasks to work properly.</b>  These tasks also require a 
+fully-installed and fully-licensed version of the StarGate Runtime.  This is part 
+of a StarTeam client installation or may be installed separately.  The full client
+install is not required.  In particular, the Windows path must include the directory where 
+the StarGate Runtime <CODE>.dll</CODE> files are installed.
+</p><p>
+Earlier versions of Ant (prior to 1.5.2) did not have this restriction because they
+were not as dependent on the StarTeam runtime - which the newer versions use to access
+StarTeam file status information.  The older versions lacked this important capability.
+</p>
+<hr></hr>
+
+<a name="common-params">
+<h2>Common Parameters for All Starteam Tasks</h2></a>
+<p>
+The following parameters, having to do with making the connection to a StarTeam project, are common to all the following tasks except the deprecated <i>StarTeam</i> task.
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">The username of the account used to log in to the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">The password of the account used to log in to the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+
+  <tr>
+    <td valign="top">URL</td>
+    <td valign="top">A string of the form <code>servername:portnum/project/view</code> 
+which enables user to set all of these elements in one string. </td>
+    <td align="center" valign="center"> Either this ...</td>
+  </tr>  
+  <tr>
+    <td valign="top">servername</td>
+    <td valign="top">The name of the StarTeam server.</td>
+    <td align="center" valign="center" rowspan = "4">... or <b>all four</b> of these must be defined.</td>  
+   </tr>
+  <tr>
+    <td valign="top">serverport</td>
+    <td valign="top">The port number of the StarTeam server.</td>
+  </tr>
+  <tr>
+    <td valign="top">projectname</td>
+    <td valign="top">The name of the StarTeam project on which to operate.</td>
+  </tr>
+  <tr>
+    <td valign="top">viewname</td>
+    <td valign="top">The name of the view in the StarTeam project on which to operate.</td>
+  </tr>
+
+
+</table>
+
+<hr></hr>
+
+<a name="stcheckout">
+<h2>STCheckout</h2></a>
+
+<h3>Description</h3>
+
+Checks out files from a StarTeam project.
+
+<p>
+The <i>includes</i> and <i>excludes</i> attributes function differently from
+other tasks in Ant. Inclusion/exclusion by folder is NOT supported.
+</p>
+
+<h3>Parameters</h3>
+See also <A href="#common-params">the required common StarTeam parameters</A>.<br></br>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+
+  <tr>
+    <td valign="top">rootstarteamfolder</td>
+    <td valign="top">The root of the subtree in the StarTeam repository from which to 
+    check out files.  Defaults to the root folder of the view ('/'). 
+      <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
+      Relative paths have little meaning in this context and confuse StarTeam.</i></b>
+      </td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  <tr>
+    <td valign="top">rootlocalfolder</td>
+    <td valign="top">The local folder which will be the root of the tree to which files are checked out.  If this is not supplied, then the StarTeam "default folder" associated with <i>rootstarteamfolder</i> is used.
+   </td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  
+  <tr>
+    <td valign="top">createworkingdirs</td>
+    <td valign="top">creates local folders even when the corresponding StarTeam folder is empty.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">deleteuncontrolled</td>
+    <td valign="top">if true, any files NOT in StarTeam will be deleted.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+    <tr>
+    <td valign="top">includes</td>
+    <td valign="top">Only check out files that match at least one of the patterns in this list.  Patterns must be separated by <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">Do not check out files that match at least one of the patterns in this list.  Patterns must be separated by  <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">label</td>
+    <td valign="top">Check out files as of this label.  The label must exist in starteam or an exception will be thrown.</td>
+    <td align="center" valign="center" rowspan="2">Either or neither, but not both, may be specified.  Neither <code>locked</code> or <code>unlocked</code> may be true if either <code>label</code> or <code>asofdate</code> is specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">asofdate</td>
+    <td valign="top">Check out files as of this date.  The date must
+    be formatted in ISO8601 datetime
+    (<code>yyyy-MM-dd'T'HH:mm:ss</code>), ISO8601
+    date(<code>yyyy-MM-dd</code>) or a user-defined SimpleDateFormat
+    defined in the <code>asofDateFormat</code> attribute.  If the date
+    is not parsable by the default or selected format, an exception
+    will be thrown.  <em>Since Ant 1.6.</em></td>
+  </tr>
+  <tr>
+    <td valign="top">asofdateformat</td>
+    <td valign="top">java.util.SimpleDateFormat compatible string used
+    to parse the <code>asofdate</code> attribute.  <em>Since Ant
+    1.6.</em></td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">recursive</td>
+    <td valign="top">Indicates if subfolders should be searched for files to check out.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">forced</td>
+    <td valign="top">If true, checkouts will occur regardless of the status 
+that StarTeam is maintaining for the file.   If false, status will be used to determine which files to check out. Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr> 
+ <tr>
+    <td valign="top">locked</td>
+    <td valign="top">If true, file will be locked against changes by other 
+users.  If false (default) has no effect. 
+    <td align="center" valign="center" rowspan="2">Either or neither, but not both, may be true. Neither may be true if a <code>label</code> or an <code>asofdate</code> is specified.</td>
+  </tr>
+  <tr>
+    <td valign="top">unlocked</td>
+    <td valign="top">If true, file will be unlocked so that other users may
+change it.  This is a way to reverse changes that have not yet been checked in.
+If false (default) has no effect.</td> 
+  </tr>
+  <tr>
+    <td valign="top">userepositorytimestamp</td>
+    <td valign="top">true means checked out files will get the repository timestamp.
+false(default) means the checked out files will be timestamped at the time
+of checkout.</td>    <td align="center" valign="top">no</td>
+
+  </tr>
+  <tr>
+    <td valign="top">preloadfileinformation</td>
+    <td valign="top">The StarTeam server has the ability to preload file metadata for an
+    entire tree prior to beginning action on that tree.  Doing so can in some instances 
+    lead to substantially faster actions, particularly over large trees.  Setting this 
+    to "yes" (default) engages this functionality, setting it to "no" turns it off.</td>    
+    <td align="center" valign="top">no</td>
+  </tr>
+    
+  <tr>
+    <td valign="top">convertEOL</td>
+    <td valign="top">If true, (default) all ascii files will have their end-of-line 
+    characters adjusted to that of the local machine on checkout.  This is normally
+    what you'd want but if for some reason you don't want that to happen, set it to false
+    and the files will be checked out with whatever end-of-line characters are used on
+    the server. </td>    
+    <td align="center" valign="top">no</td>
+  </tr>
+
+</table>
+
+<h3>Examples</h3>
+
+<pre>
+  &lt;stcheckout servername="STARTEAM" 
+              serverport="49201"
+              projectname="AProject" 
+              viewname="AView"
+              username="auser"
+              password="secret"
+              rootlocalfolder="C:\dev\buildtest\co"
+              forced="true"
+  /&gt;
+</pre>
+
+The minimum necessary to check out files out from a StarTeam server.  This will
+check out all files in the <i>AView</i> view of the <i>AProject</i> project to
+<code>C:\dev\buildtest\co</code>.  Empty folders in StarTeam will have local folders 
+created for them and any non-StarTeam files found in the tree will be deleted.
+
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView" 
+              username="auser"
+              password="secret"
+              rootlocalfolder="C:\dev\buildtest\co"
+              forced="true"
+  /&gt;
+</pre>
+And this is a simpler way of accomplishing the same thing as the previous example, using the URL attribute.
+<br></br>
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView" 
+              username="auser"
+              password="secret"
+              rootlocalfolder="C:\dev\buildtest\co"
+              rootstarteamfolder="\Dev"
+              excludes="*.bak *.old"
+              label="v2.6.001"
+              forced="true"
+  /&gt;
+</pre>
+
+This will check out all files from the <i>Dev</i> folder and below that do not
+end in <i>.bak</i> or <i>.old</i> with the label <i>v2.6.001</i>.  
+
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView"
+              username="auser"
+              password="secret"
+              rootlocalfolder="C:\dev\buildtest\co"
+              includes="*.htm,*.html"
+              excludes="index.*"
+              forced="true"
+  /&gt;
+</pre>
+
+     
+This is an example of overlapping <i>includes</i> and <i>excludes</i> attributes.  Because
+<i>excludes</i> takes precedence over <i>includes</i>, files named <code>index.html</code> will
+not be checked out by this command.
+
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView"
+              username="auser"
+              password="secret"
+              rootlocalfolder="C:\dev\buildtest\co"
+              includes="*.htm,*.html"
+              excludes="index.*"
+              forced="true"
+              recursive="false"
+  /&gt;
+</pre>
+This example is like the previous one, but will only check out files in 
+C:\dev\buildtest\co, because of the turning off of the recursive attribute.
+
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView"
+              username="auser"
+              password="secret"
+              rootstarteamfolder="src/java"
+              rootlocalfolder="C:\dev\buildtest\co"
+              forced="true"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+  &lt;stcheckout URL="STARTEAM:49201/Aproject/AView"
+              username="auser"
+              password="secret"
+              rootstarteamfolder="src/java"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+ &lt;stcheckout URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootstarteamfolder="src/java"
+             rootlocalfolder="C:\dev\buildtest\co\src\java"
+             forced="true"
+  /&gt;
+</pre>
+
+In the preceding three examples, assuming that the AProject project has a default folder of
+"C:\work\AProject", the first example will check out the tree of files rooted in the src/java folder of the AView view of the AProject in the StarTeam repository to a local tree rooted at C:\dev\buildtest\co, 
+the second to a tree rooted at C:\work\AProject\src\java (since no <i>rootlocalfolder</i> is specified) and the third to a tree rooted at C:\dev\buildtest\co\src\java.  Note also, that since the second example does not set "forced" true, only those files which the repository considers out-of-date will be checked out.
+<hr></hr>
+
+<a name="stcheckin">
+<h2>STCheckin</h2></a>
+
+<h3>Description</h3>
+
+Checks files into a StarTeam project.  Optionally adds files and in the local tree that are not managed by the repository to its control.
+
+<p>
+The <i>includes</i> and <i>excludes</i> attributes function differently from
+other tasks in Ant. Inclusion/exclusion by folder is NOT supported.
+</p>
+
+<h3>Parameters</h3>
+See also <A href="#common-params">the required common StarTeam parameters</A>.<br></br>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">rootstarteamfolder</td>
+    <td valign="top">The root of the subtree in the StarTeam repository into which to 
+    files will be checked.  Defaults to the root folder of the view ('/').
+       <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
+      Relative paths have little meaning in this context and confuse StarTeam.</i></b></td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  <tr>
+    <td valign="top">rootlocalfolder</td>
+    <td valign="top">The local folder which will be the root of the tree to which files are checked out.  If this is not supplied, then the StarTeam "default folder" associated with <i>rootstarteamfolder</i> is used. </td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  
+
+  <tr>
+    <td valign="top">comment</td>
+    <td valign="top">Checkin comment to be saved with the file.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+
+  <tr>
+    <td valign="top">adduncontrolled</td>
+    <td valign="top">if true, any files or folders NOT in StarTeam will be 
+added to the repository.  Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+    <tr>
+    <td valign="top">includes</td>
+    <td valign="top">Only check in files that match at least one of the patterns in this list.  Patterns must be separated by <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">Do not check in files that match at least one of the patterns in this list.  Patterns must be separated by  <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">recursive</td>
+    <td valign="top">Indicates if subfolders should be searched for files to check in.  Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">forced</td>
+    <td valign="top">If true, checkins will occur regardless of the status 
+that StarTeam is maintaining for the file.  If false, checkins will use this status to decide which files to update.  Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+    <td valign="top">unlocked</td>
+    <td valign="top">If true, file will be unlocked so that other users may
+change it.  If false (default) lock status will not change.
+    <td align="center" valign="top">no</td> 
+  </tr>
+  <tr>
+    <td valign="top">preloadfileinformation</td>
+    <td valign="top">The StarTeam server has the ability to preload file metadata for an
+    entire tree prior to beginning action on that tree.  Doing so can in some instances 
+    lead to substantially faster actions, particularly over large trees.  Setting this 
+    to "yes" (default) engages this functionality, setting it to "no" turns it off.</td>    
+    <td align="center" valign="top">no</td>
+  </tr>
+  </table>
+
+<h3>Examples</h3>
+
+<pre>
+  &lt;stcheckin servername="STARTEAM" 
+             serverport="49201"
+             projectname="AProject" 
+             viewname="AView"
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             forced="true"
+  /&gt;
+</pre>
+
+The minimum necessary to check files into a StarTeam server.  This will
+check all files on the local tree rooted at <code>C:\dev\buildtest\co</code>
+into the <i>AView</i> view of the <i>AProject</i> project in the repository.
+For files and folders in the local tree but not in starteam, nothing will be done.  Since the <i>forced</i> attribute is set, the files which are checked in will be checked in without regard to what the StarTeam repository considers their status to be.  This is a reasonable choice of attributes since StarTeam's status for a file is calculated based on the local file in the StarTeam default directory, not on the directory we are actually working with.
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView" 
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             forced="true"
+  /&gt;
+</pre>
+And this is a simpler way of giving the same commands as the command above using the URL shortcut.
+<br></br>
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView" 
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             rootstarteamfolder="\Dev"
+             excludes="*.bak *.old"
+             forced="true"
+  /&gt;
+</pre>
+
+This will check all files in to the <i>Dev</i> folder and below that do not
+end in <i>.bak</i> or <i>.old</i> from the tree rooted at"C:\dev\buildtest\co" .  
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             includes="*.htm,*.html"
+             excludes="index.*"
+             forced="true"
+  /&gt;
+</pre>
+
+     
+This is an example of overlapping <i>includes</i> and <i>excludes</i> attributes.  Because
+<i>excludes</i> takes precedence over <i>includes</i>, files named <code>index.html</code> will
+not be checked in by this command.
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             rootstarteamfolder="src/java"
+             includes="*.htm,*.html"
+             excludes="index.*"
+             forced="true"
+             recursive="false"
+  /&gt;
+</pre>
+This example is like the previous one, but will only check in files from 
+C:\dev\buildtest\co, because of the turning off of the recursive attribute.
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             rootstarteamfolder="src/java"
+             includes="version.txt"
+             forced="true"
+             recursive="false"
+  /&gt;
+</pre>
+This example is like the previous one, but will only check only in one file, C:\dev\buildtest\co\version.txt to the StarTeam folder src/java.
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootlocalfolder="C:\dev\buildtest\co"
+             rootstarteamfolder="src/java"
+             includes="version.java"
+             forced="true"
+             recursive="false"
+             addUncontrolled="true"
+             comment="Fix Bug #667"
+  /&gt;
+</pre>
+This example is like the previous one, but will only check only in one file, C:\dev\buildtest\co\version.java to the StarTeam folder src/java.  Because the <i>addUncontrolled</i> attribute has been set, if StarTeam does not already control this file in this location, it will be added to the repository.  Also, it will write a comment to the repository for this version of the file.
+
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootstarteamfolder="src/java"
+             rootlocalfolder="C:\dev\buildtest\co"
+             forced="true"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+  &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootstarteamfolder="src/java"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+ &lt;stcheckin URL="STARTEAM:49201/Aproject/AView"
+             username="auser"
+             password="secret"
+             rootstarteamfolder="src/java"
+             rootlocalfolder="C:\dev\buildtest\co\src\java"
+             forced="true"
+  /&gt;
+</pre>
+
+In the preceding three examples, assuming that the AProject project has a default folder of C:\work\buildtest\co\AProject,  
+the first example will check in files from a tree rooted at C:\dev\buildtest\co, 
+the second from a tree rooted at C:\work\buildtest\co\AProject\src\java, 
+and the third from a tree rooted at C:\dev\buildtest\co\src\java all to a tree rooted at src/java
+
+<hr></hr>
+
+<a name="stlabel">
+<h2>STLabel</h2></a>
+
+<h3>Description</h3>
+
+Creates a view label in StarTeam at the specified view.  The label will be classified by StarTeam as a "build label".  This task will fail if there already exists in <i>viewname</i> a label with the same name as the <i>label</i> parameter. 
+
+<h3>Parameters</h3>
+See also <A href="#common-params">the required common StarTeam parameters</A>.<br></br>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+
+  <tr>
+    <td valign="top">label</td>
+    <td valign="top">The name to be given to the label</td>
+    <td align="center" valign="top">yes</td>
+  </tr> 
+  <tr>
+    <td valign="top">description</td>
+    <td valign="top">A description of the label to be stored in the StarTeam project.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">revisionlabel</td>
+    <td valign="top">Yes means that the label attribute is to be saved as a &quot;revision label&quot;.  No (default) means that it will be saved as a &quot;view label&quot;</td>
+    <td align="center" valign="top">no</td>
+  </tr> 
+  <tr>
+    <td valign="top">buildlabel</td>
+    <td valign="top">Yes means that the label attribute is to be saved as a &quot;build label&quot;.  
+      This means that Change Requests which have an &quot;AddressedIn&quot; field value of &quot;next build&quot;
+       will have this label assigned to that field when the label is created.  
+       No (default) means that no CRs will have this label assigned to them.  This will have no effect if <b>revisionlabel</b> is also true.  </td>
+    <td align="center" valign="top">no</td>
+  </tr> 
+
+ <tr>
+    <td valign="top">lastbuild</td>
+    <td valign="top">The timestamp of the build that will be stored with the label.  Must be formatted <code>yyyyMMddHHmmss</code></td>
+    <td align="center" valign="top">no</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+This example shows the use of this tag.  It will create a View label that is a build label named <i>Version 6.2</i> with
+<i>&quot;Thorough description&quot;</i> as its description.
+<pre>
+  &lt;tstamp&gt;
+    &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
+  &lt;/tstamp&gt;  
+  &lt;stlabel URL="STARTEAM:49201/Aproject/AView"
+           username="auser"
+           password="secret"
+           label="Version 6.2"
+           lastbuild="${nowstamp}"
+           description="Thorough description"
+  /&gt;
+</pre>
+This example creates a non-build View label named <i>Version 6.3</i> with
+<i>&quot;Thorough description&quot;</i> as its description.
+<pre>
+  &lt;tstamp&gt;
+    &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
+  &lt;/tstamp&gt;  
+  &lt;stlabel URL="STARTEAM:49201/Aproject/AView"
+           username="auser"
+           password="secret"
+           label="Version 6.3"
+           lastbuild="${nowstamp}"
+           description="Thorough description"
+           buildlabel="false"
+  /&gt;
+</pre>
+This example will create a Revision label that is a build label named <i>Version 6.2.00.001</i> with
+<i>&quot;revision label&quot;</i> as its description.
+<pre>
+  &lt;tstamp&gt;
+    &lt;format property="nowstamp" pattern="yyyyMMddHHmmss" locale="en"/&gt;
+  &lt;/tstamp&gt;  
+  &lt;stlabel URL="STARTEAM:49201/Aproject/AView"
+           username="auser"
+           password="secret"
+           label="Version 6.2.00.001"
+           description="revision label"
+           revisionlabel="true"
+  /&gt;
+</pre>
+
+<hr></hr>
+<a name="stlist">
+<h2>STList</h2></a>
+
+<h3>Description</h3>
+
+Produces a listing of the contents of the StarTeam repository at the specified view and StarTeamFolder.  The listing will contain the name of the user, if any, who has the file locked, the size of the file, its lastModifiedDate in the repository, the name of the file, and the status of the local file in the default local directory relative to the repository. 
+
+<h3>Parameters</h3>
+See also <A href="#common-params">the required common StarTeam parameters</A>.<br></br>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+
+  <tr>
+    <td valign="top">rootstarteamfolder</td>
+    <td valign="top">The root of the subtree in the StarTeam repository to be listed.  Defaults to the root folder of the view ('/'). <b><i>If supplied, this should always be an "absolute" path, that is, it should begin with a '/'.  
+      Relative paths have little meaning in this context and confuse StarTeam.</i></b></td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  <tr>
+    <td valign="top">rootlocalfolder</td>
+    <td valign="top">The local folder which will be the root of the tree to which files are compared.  If this is not supplied, then the StarTeam "default folder" associated with <i>rootstarteamfolder</i> is used and a status field will appear in the listing.  Otherwise, the status field will not appear.
+   </td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+    <tr>
+    <td valign="top">includes</td>
+    <td valign="top">Only list files that match at least one of the patterns in this list.  Patterns must be separated by <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">Do not list files that match at least one of the patterns in this list.  Patterns must be separated by  <i>commas</i>.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">label</td>
+    <td valign="top">List files, dates, and statuses as of this label.  The label must exist in starteam or an exception will be thrown.  If not specified, the most recent version of each file will be listed.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">asofdate</td>
+    <td valign="top">List files, dates, and statuses as of this date.
+    The date must be formatted in ISO8601 datetime
+    (<code>yyyy-MM-dd'T'HH:mm:ss</code>), ISO8601
+    date(<code>yyyy-MM-dd</code>) or a user-defined SimpleDateFormat
+    defined in the <code>asofDateFormat</code> attribute.  If the date
+    is not parsable by the default or selected format, an exception
+    will be thrown.  <em>Since Ant 1.6.</em></td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">asofdateformat</td>
+    <td valign="top">java.util.SimpleDateFormat compatible string used
+    to parse the <code>asofdate</code> attribute.  <em>Since Ant
+    1.6.</em></td>
+    <td align="center" valign="top">no</td>
+  </tr>
+
+  <tr>
+    <td valign="top">recursive</td>
+    <td valign="top">Indicates if subfolders should be searched for files to list.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+    <tr>
+    <td valign="top">listuncontrolled</td>
+    <td valign="top">if true, any files or folders NOT in StarTeam will be included in the listing.
+    If false, they won't.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+    </tr>
+  
+  <tr>
+    <td valign="top">preloadfileinformation</td>
+    <td valign="top">The StarTeam server has the ability to preload file metadata for an
+    entire tree prior to beginning action on that tree.  Doing so can in some instances 
+    lead to substantially faster actions, particularly over large trees.  Setting this 
+    to "yes" (default) engages this functionality, setting it to "no" turns it off.</td>    
+    <td align="center" valign="top">no</td>
+  </tr>
+
+</table>
+<h3>Examples</h3>
+
+<pre>
+
+  &lt;stlist url="WASHINGTON:49201/build"
+          username="auser"
+          password="secret"
+ /&gt;
+</pre>
+
+The above command might produce the following listing:
+
+<pre>
+   [stlist] Folder: Build (Default folder: C:/work/build)
+   [stlist] Folder: dev (Default folder: C:/work/build/dev)
+   [stlist] Out of date  Sue Developer        1/1/02 7:25:47 PM CST     4368 build.xml
+   [stlist] Missing      George Hacker        1/1/02 7:25:49 PM CST       36 Test01.properties
+   [stlist] Current                           1/1/02 7:25:49 PM CST     4368 build2.xml
+   [stlist] Folder: test (Default folder C:/work/build/dev/test)
+   [stlist] Missing                           1/1/02 7:25:50 PM CST     4368 build2.xml
+</pre>
+
+while adding a <i>rootlocalfolder</i> and an <i>excludes</i> param ...
+
+<pre>
+
+  &lt;stlist url="WASHINGTON:49201/build"
+          username="auser"
+          password="secret"
+          rootlocalfolder="srcdir2"
+          excludes="*.properties"
+ /&gt;
+</pre>
+
+might produce this listing. The status is missing because we are not going against the default folder.
+
+<pre>
+   [stlist] overriding local folder to srcdir2
+   [stlist] Folder: Build (Local folder: srcdir2)
+   [stlist] Folder: dev (Local folder: srcdir2/dev)
+   [stlist] Sue Developer        1/1/02 7:25:47 PM CST     4368 build.xml
+   [stlist]                      1/1/02 7:25:49 PM CST     4368 build2.xml
+   [stlist] Folder: test (Local folder: srcdir2/dev/test)
+   [stlist]                      1/1/02 7:25:50 PM CST     4368 build2.xml
+ 
+
+</pre>
+
+<hr></hr>
+
+<a name="starteam">
+<h2>Starteam</h2></a>
+<h3><i>Deprecated</i></h3>
+<p><i>This task has been deprecated.  Use the <a href="#stcheckout">STCheckout</a> task instead.</i></p>
+<h3>Description</h3>
+
+Checks out files from a StarTeam project.
+
+<p>
+The <i>includes</i> and <i>excludes</i> attributes function differently from
+other tasks in Ant.  Multiple patterns must be separated by spaces, not
+commas.  See the examples for more information.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">username</td>
+    <td valign="top">The username of the account used to log in to the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">password</td>
+    <td valign="top">The password of the account used to log in to the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>  
+  <tr>
+    <td valign="top">servername</td>
+    <td valign="top">The name of the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">serverport</td>
+    <td valign="top">The port number of the StarTeam server.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">projectname</td>
+    <td valign="top">The name of the StarTeam project.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">viewname</td>
+    <td valign="top">The name of the view in the StarTeam project.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>
+
+  <tr>
+    <td valign="top">targetfolder</td>
+    <td valign="top">The folder to which files are checked out.  What this precisely means is determined by the <i>targetFolderAbsolute</i> param.</td>
+    <td align="center" valign="top">yes</td>
+  </tr>  
+  <tr>
+    <td valign="top">targetFolderAbsolute</td>
+    <td valign="top">Determines how <i>targetfolder</i> is interpreted, that is, whether the StarTeam "default folder" for the project is factored in (false) or whether <i>targetFolder</i> is a complete mapping to <i>foldername</i> (true).
+      If "true", the target tree will be rooted at <i>targetfolder+"default folder"</i>.  If false, the target tree will be rooted at <i>targetfolder</i>.  Defaults to "false".  </td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  <tr>
+    <td valign="top">foldername</td>
+    <td valign="top">The subfolder in the project from which to check out files.</td>
+    <td align="center" valign="top">no</td>
+  </tr>  
+  <tr>
+    <td valign="top">force</td>
+    <td valign="top">Overwrite existing folders if this is set to "true".  Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">recursion</td>
+    <td valign="top">Indicates if subfolders should be searched for files to check out.  Defaults to "true".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">verbose</td>
+    <td valign="top">Provides progress information.  Defaults to "false".</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">includes</td>
+    <td valign="top">Only check out files that match at least one of the patterns in this list.  Patterns must be separated by spaces.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+  <tr>
+    <td valign="top">excludes</td>
+    <td valign="top">Do not check out files that match at least one of the patterns in this list.  Patterns must be separated by spaces.  Patterns in <i>excludes</i> take precedence over patterns in <i>includes</i>.</td>
+    <td align="center" valign="top">no</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+
+<pre>
+  &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co"
+  /&gt;
+</pre>
+
+The minimum necessary to check out files out from a StarTeam server.  This will
+check out all files in the <i>AView</i> view of the <i>AProject</i> project to
+<code>C:\dev\buildtest\co</code>.
+
+<pre>
+  &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co"
+            foldername="\Dev"
+            excludes="*.bak *.old"
+            force="true"
+  /&gt;
+</pre>
+
+This will checkout all files from the <i>Dev</i> folder and below that do not
+end in <i>.bak</i> or <i>.old</i>.  The force flag will cause any existing files to be
+overwritten by the version in StarTeam.
+
+<pre>
+  &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co"
+            includes="*.htm *.html"
+            excludes="index.*"
+  /&gt;
+</pre>
+
+
+       
+This is an example of overlapping <i>includes</i> and <i>excludes</i> attributes.  Because
+<i>excludes</i> takes precedence over <i>includes</i>, files named <code>index.html</code> will
+not be checked out by this command.
+
+
+<pre>
+ &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            foldername="src/java"
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co"
+            targetfolderabsolute="true"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+ &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            foldername="src/java"
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co"
+            targetfolderabsolute ="false"
+  /&gt;
+</pre>
+<br></br>
+<pre>
+ &lt;starteam servername="STARTEAM" 
+            serverport="49201"
+            projectname="AProject" 
+            foldername="src/java"
+            viewname="AView"
+            username="auser"
+            password="secret"
+            targetfolder="C:\dev\buildtest\co\src\java"
+            targetfolderabsolute="true"
+  /&gt;
+</pre>
+
+In the preceding three examples, assuming that the AProject project has a default folder of
+"AProject", the first example will check the files located in starteam under src/java out to a tree rooted at C:\dev\buildtest\co, 
+the second to a tree rooted at C:\dev\buildtest\co\AProject\src\java and the third to a tree rooted at C:\dev\buildtest\co\src\java.
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/stylebook.html b/trunk/docs/manual/OptionalTasks/stylebook.html
new file mode 100644
index 0000000..ff4cd8a
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/stylebook.html
@@ -0,0 +1,89 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>StyleBook Task</title>
+</head>
+
+<body>
+
+<h2><a name="stylebook">Stylebook</a></h2>
+<h3>Description</h3>
+
+<strong>This task is deprecated as stylebook itself has been
+deprecated by the Apache XML community.</strong>
+
+<p>This executes the apache Stylebook documentation generator. 
+Unlike the commandline version of this tool, all three arguments
+are required to run stylebook.</p>
+<p><b>Note:</b> This task depends on external libraries not included in the Ant distribution.
+See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p>
+<p>
+ Being extended from <code>&lt;Java&gt;</code>, all the parent's attributes
+ and options are available. Do not set any apart from the <tt>classpath</tt>
+ as they are not guaranteed to be there in future.
+ </p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">book</td>
+    <td valign="top">the book xml file that the documentation generation starts from
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">skindirectory</td>
+    <td valign="top">the directory that contains the stylebook skin
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">targetdirectory</td>
+    <td valign="top">the destination directory where the documentation is generated 
+    </td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+</table>
+<p>
+The user can also specify the nested <code>&lt;classpath&gt;</code> element which defines classpath 
+in which the task is executed.</p>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;stylebook targetdirectory=&quot;build/docs&quot; 
+           book=&quot;src/xdocs/book.xml&quot; 
+           skindirectory=&quot;src/skins/myskin&quot;/&gt;
+</pre>
+</blockquote>
+The above will generate documentation in build/docs starting from the book 
+src/xdocs/book.xml and using the skin located in directory src/skins/myskin.
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/symlink.html b/trunk/docs/manual/OptionalTasks/symlink.html
new file mode 100644
index 0000000..879e489
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/symlink.html
@@ -0,0 +1,140 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Symlink Task</title>
+</head>
+
+<body>
+
+<h2><a name="symlink">Symlink</a></h2>
+<h3>Description</h3>
+<p> Manages symbolic links on Unix based platforms. Can be used to
+make an individual link, delete a link, create multiple links from properties files, 
+or create properties files describing links in the specified directories.
+Existing links are not overwritten by default.
+
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select a
+set of links to record, or a set of property files to create links from. </p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">action</td>
+    <td valign="top">The type of action to perform, may be "single", 
+    "record", "recreate" or "delete".</td>
+    <td valign="top" align="center">No, defaults to single.</td>
+  </tr>
+  <tr>
+    <td valign="top">link</td>
+    <td valign="top">The name of the link to be created or deleted.</td>
+    <td valign="center" align="center" >required for 
+    action="single" or "delete". Ignored in other actions.</td>
+  </tr>
+  <tr>
+    <td valign="top">resource</td>
+    <td valign="top">The resource the link should point to.</td>
+    <td valign="top" align="center">required for action="single". Ignored in other actions.</td>
+  </tr>
+  <tr>
+    <td valign="top">linkfilename</td>
+    <td valign="top">The name of the properties file to create in 
+    each included directory.</td>
+    <td valign="top" align="center">required for action="record". 
+    Ignored in other actions.</td>
+  </tr>
+  <tr>
+    <td valign="top">overwrite</td>
+    <td valign="top">Overwrite existing links or not.</td>
+    <td valign="top" align="center">No; defaults to false.</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+     <td valign="top">Stop build if true, log a warning message, but do not stop the build,
+       when the an error occurs if false.
+     </td>
+     <td valign="top" align="center">No; defaults to true.</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+ 
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s
+ are used when action = "record" to select directories and linknames to be recorded. 
+ They are also used when action = "recreate" to specify both the name of the property 
+ files to be processed, and the directories in which they can be found. At least one 
+ fileset is required for each case.</p>
+ 
+<h3>Examples</h3>
+
+  <p> Make a link named "foo" to a resource named "bar.foo" in subdir:</p>
+  <pre>
+  &lt;symlink link="${dir.top}/foo" resource="${dir.top}/subdir/bar.foo"/&gt;
+  </pre>
+ 
+  <p> Record all links in subdir and it's descendants in files named
+  "dir.links"</p>
+  <pre>
+  &lt;symlink action="record" linkfilename="dir.links"&gt;
+     &lt;fileset dir="${dir.top}" includes="subdir&#47;**"/&gt;
+  &lt;/symlink&gt;
+  </pre>
+ 
+  <p> Recreate the links recorded in the previous example:</p>
+  <pre>
+  &lt;symlink action="recreate"&gt;
+     &lt;fileset dir="${dir.top}" includes="subdir&#47;**&#47;dir.links"/&gt;  
+  &lt;/symlink&gt;
+  </pre>
+ 
+ <p> Delete a link named "foo":
+ <pre>
+ &lt;symlink action="delete" link="${dir.top}/foo"/&gt;
+ </pre>
+
+  <p><strong>Java 1.2 and earlier:</strong> Due to limitations on executing system
+  level commands in Java versions earlier than 1.3 this task may have difficulty
+  operating with a relative path in ANT_HOME. The typical symptom is an 
+  IOException where ant can't find /some/working/directory${ANT_HOME}/bin/antRun
+  or something similar. The workaround is to change your ANT_HOME environment
+  variable to an absolute path, which will remove the /some/working/directory portion
+  of the above path and allow ant to find the correct commandline execution script.
+ 
+  <p><strong>LIMITATIONS:</strong> Because Java has no direct support for
+  handling symlinks this task divines them by comparing canonical and
+  absolute paths. On non-unix systems this may cause false positives.
+  Furthermore, any operating system on which the command
+  <code>ln -s &lt;linkname&gt; &lt;resourcename&gt;</code> is not a valid 
+  command on the command line will not be able to use action="single" or 
+  action="recreate". Action="record" and action=delete should still work. Finally, 
+  the lack of support for symlinks in Java means that all links are recorded as 
+  links to the <strong>canonical</strong> resource name. Therefore the link:
+  <code>link --> subdir/dir/../foo.bar</code> will be recorded as
+  <code>link=subdir/foo.bar</code> and restored as
+  <code>link --> subdir/foo.bar</code></p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/telnet.html b/trunk/docs/manual/OptionalTasks/telnet.html
new file mode 100644
index 0000000..e7a320b
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/telnet.html
@@ -0,0 +1,155 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Telnet Task</title>
+</head>
+
+<body>
+
+<h2><a name="telnet">Telnet</a></h2>
+<h3>Description</h3>
+Task to automate a remote telnet session. The task uses 
+nested <tt>&lt;read&gt;</tt> to indicate strings to wait for, and
+<tt>&lt;write&gt;</tt> tags to specify text to send.  
+
+<p>If you do specify a userid and password, the system will 
+assume a common unix prompt to wait on. This behavior can be easily over-ridden.</p>
+<p><b>Note:</b> This task depends on external libraries not included in the Ant distribution.
+See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p>
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>userid</td>
+     <td>the login id to use on the telnet server.</td>
+     <td>Only if password is specified</td>
+  </tr>
+  <tr>
+     <td>password</td>
+     <td>the login password to use on the telnet server.</td>
+     <td>Only if userid is specified</td>
+  </tr>
+  <tr>
+     <td>server</td>
+     <td>the address of the remote telnet server.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>port</td>
+     <td>the port number of the remote telnet server. Defaults to port 23.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>initialCR</td>
+     <td>send a cr after connecting (&quot;yes&quot;). Defaults to &quot;no&quot;.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>timeout</td>
+     <td>set a default timeout to wait for a response. Specified in seconds. Default is no timeout.</td>
+     <td>No</td>
+  </tr>
+</table>
+<h3><a name="nested">Nested Elements</a></h3>
+The commands to send to the server, and responses to wait for, are
+described as nested elements.  
+
+<h4>read</h4>
+
+<p>declare (as a text child of this element) a string to wait for.
+The element supports the timeout attribute, which overrides any
+timeout specified for the task as a whole. It also has a <tt>string</tt>
+attribute, which is an alternative to specifying the string as 
+a text element.
+</p>
+<i>Always declare an opening and closing
+<code>&lt;read&gt;</code> element to ensure that statements are not sent before
+the connection is ready, and that the connection is not broken before
+the final command has completed.
+</i>
+<h4>write</h4>
+
+<p>describes the text to send to the server. The <tt>echo</tt> boolean
+attribute controls whether the string is echoed to the local log; 
+this is "true" by default
+</p>
+<h3>Examples</h3>
+A simple example of connecting to a server and running a command.  This assumes
+ a prompt of &quot;ogin:&quot; for the userid, and a prompt of &quot;assword:&quot;
+ for the password.
+
+<blockquote><pre>
+&lt;telnet userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot;&gt;
+   &lt;read&gt;/home/bob&lt;/read&gt;
+   &lt;write&gt;ls&lt;/write&gt;
+   &lt;read string=&quot;/home/bob&quot;/&gt;
+&lt;/telnet&gt;
+</pre></blockquote>
+
+This task can be rewritten as:
+<blockquote><pre>
+&lt;telnet server=&quot;localhost&quot;&gt;
+   &lt;read&gt;ogin:&lt;/read&gt;
+   &lt;write&gt;bob&lt;/write&gt;
+   &lt;read&gt;assword:&lt;/read&gt;
+   &lt;write&gt;badpass&lt;/write&gt;
+   &lt;read&gt;/home/bob&lt;/read&gt;
+   &lt;write&gt;ls&lt;/write&gt;
+   &lt;read&gt;/home/bob&lt;/read&gt;
+&lt;/telnet&gt;
+</pre></blockquote>
+
+A timeout can be specified at the <code>&lt;telnet&gt;</code> level or at the <code>&lt;read&gt;</code> level. 
+This will connect, issue a sleep command that is suppressed from displaying and wait 
+10 seconds before quitting.
+<blockquote><pre>
+&lt;telnet userid=&quot;bob&quot; password=&quot;badpass&quot; server=&quot;localhost&quot; timeout=&quot;20&quot;&gt;
+   &lt;read&gt;/home/bob&lt;/read&gt;
+   &lt;write echo=&quot;false&quot;&gt;sleep 15&lt;/write&gt;
+   &lt;read timeout=&quot;10&quot;&gt;/home/bob&lt;/read&gt;
+&lt;/telnet&gt;
+</pre></blockquote>
+
+The task can be used with other ports as well:
+<blockquote><pre>
+&lt;telnet port=&quot;80&quot; server=&quot;localhost&quot; timeout=&quot;20&quot;&gt;
+   &lt;read/&gt;
+   &lt;write&gt;GET / http/0.9&lt;/write&gt;
+   &lt;write/&gt;
+   &lt;read timeout=&quot;10&quot;&gt;&amp;lt;/HTML&amp;gt;&lt;/read&gt;
+&lt;/telnet&gt;
+</pre></blockquote>
+<p>
+To use this task against the WinNT telnet service, you need to configure the service to use 
+classic authentication rather than NTLM negotiated authentication. 
+This can be done in the Telnet Server Admin app: 
+select "display/change registry settings", then "NTLM", then set the value of NTLM to 1.
+</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTasks/translate.html b/trunk/docs/manual/OptionalTasks/translate.html
new file mode 100644
index 0000000..f941021
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/translate.html
@@ -0,0 +1,182 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Translate Task</title>
+</head>
+
+<body>
+
+<h2><a name="translate">Translate</a></h2>
+<h3>Description</h3>
+<p>Identifies keys in files delimited by special tokens
+and translates them with values read from resource bundles.
+</p>
+<p>
+A resource bundle contains locale-specific key-value pairs.
+A resource bundle is a hierarchical set of property files.
+A bundle name makes up its base family name.  Each file that
+makes up this bundle has this name plus its locale.  For example,
+if the resource bundle name is MyResources, the file that contains
+German text will take the name MyResources_de.  In addition to
+language, country and variant are also used to form the files in
+the bundle.
+</p>
+<p>
+The resource bundle lookup searches for resource files with various
+suffixes on the basis of (1) the desired locale and (2) the default
+locale (basebundlename), in the following order from lower-level
+(more specific) to parent-level (less specific):
+</p>
+<pre>
+basebundlename + &quot;_&quot; + language1 + &quot;_&quot; + country1 + &quot;_&quot; + variant1
+basebundlename + &quot;_&quot; + language1 + &quot;_&quot; + country1
+basebundlename + &quot;_&quot; + language1
+basebundlename
+basebundlename + &quot;_&quot; + language2 + &quot;_&quot; + country2 + &quot;_&quot; + variant2
+basebundlename + &quot;_&quot; + language2 + &quot;_&quot; + country2
+basebundlename + &quot;_&quot; + language2
+</pre>
+<p>
+The file names generated thus are appended with the string &quot;.properties&quot;
+to make up the file names that are to be used.
+</p>
+<p>
+File encoding is supported.  The encoding scheme of the source files,
+destination files and the bundle files can be specified.
+
+Destination files can be explicitly overwritten using the
+<var>forceoverwrite</var> attribute.  If <var>forceoverwrite</var>
+is false, the destination file is overwritten only if either the
+source file or any of the files that make up the bundle have been
+modified after the destination file was last modified.
+</p>
+<p>
+<em>New in Ant 1.6:</em><br>
+Line endings of source files are preserved in the translated files.
+</p>
+<p><a href="../CoreTypes/fileset.html">FileSet</a>s are used to select files to
+translate.
+</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">todir</td>
+    <td valign="top">Destination directory where destination files are
+      to be created.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">starttoken</td>
+    <td valign="top">The starting token to identify keys.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">endtoken</td>
+    <td valign="top">The ending token to identify keys.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">bundle</td>
+    <td valign="top">Family name of resource bundle.</td>
+    <td valign="top" align="center">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">bundlelanguage</td>
+    <td valign="top">
+        Locale specific language of resource bundle.  Defaults to
+        default locale's language.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bundlecountry</td>
+    <td valign="top">
+        Locale specific country of resource bundle.  Defaults to
+        default locale's country.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bundlevariant</td>
+    <td valign="top">
+        Locale specific variant of resource bundle.  Defaults to
+        the default variant of the country and language being used.
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">srcencoding</td>
+    <td valign="top">Source file encoding scheme.  Defaults to
+    system default file encoding.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">destencoding</td>
+    <td valign="top">Destination file encoding scheme.  Defaults to
+    source file encoding.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">bundleencoding</td>
+    <td valign="top">Resource Bundle file encoding scheme.  Defaults to
+    source file encoding.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">forceoverwrite</td>
+    <td valign="top">Overwrite existing files even if the destination
+      files are newer. Defaults to &quot;no&quot;.</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+<h3>Parameters specified as nested elements</h3>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSets</a> are used to select files that
+ contain keys for which value translated files are to be generated.
+</p>
+<h3>Examples</h3>
+<p><b>Translate source file encoded in english into its japanese
+equivalent using a resource bundle encoded in japanese.
+</b></p>
+<pre>
+  &lt;translate toDir=&quot;$(dest.dir}/ja&quot;
+        starttoken=&quot;#&quot;
+        endtoken=&quot;#&quot;
+        bundle=&quot;resource/BaseResource&quot;
+        bundlelanguage=&quot;ja&quot;
+        forceoverwrite=&quot;yes&quot;
+        srcencoding=&quot;ISO8859_1&quot;
+        destencoding=&quot;SJIS&quot;
+        bundleencoding=&quot;SJIS&quot;&gt;
+        &lt;fileset dir=&quot;${src.dir}&quot;&gt;
+            &lt;include name=&quot;**/*.jsp&quot;/&gt;
+        &lt;/fileset&gt;
+  &lt;/translate&gt;
+</pre>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/vbc.html b/trunk/docs/manual/OptionalTasks/vbc.html
new file mode 100644
index 0000000..a2d3d4e
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/vbc.html
@@ -0,0 +1,470 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Vbc
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Vbc
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">This task compiles Visual Basic.NET source into executables or modules.  <p>For historical reasons the pattern <code>**/*.vb</code> is preset as includes list and you can not override it with an explicit includes attribute.  Use nested <code>&lt;src&gt;</code> elements instead of the basedir attribute if you need more control.</p></font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        This task compiles Visual Basic.NET source into executables or modules. The task requires vbc.exe on the execute path, unless it or an equivalent program is specified in the <tt>executable</tt> parameter <p> All parameters are optional: <code>&lt;vbc/&gt;</code> should suffice to produce a debug build of all *.vb files. <p> The task is a directory based task, so attributes like <tt>includes=&quot;**\/*.vb&quot;</tt> and <tt>excludes=&quot;broken.vb&quot;</tt> can be used to control the files pulled in. By default, all *.vb files from the project folder down are included in the command. When this happens the destFile -if not specified- is taken as the first file in the list, which may be somewhat hard to control. Specifying the output file with <tt>destfile</tt> is prudent. </p> <p> Also, dependency checking only works if destfile is set. As with <code>&lt;csc&gt;</code> nested <tt>src</tt> filesets of source, reference filesets, definitions and resources can be provided. <p> Example </p> <pre>&lt;vbc optimize=&quot;true&quot; debug=&quot;false&quot; warnLevel=&quot;4&quot; targetType=&quot;exe&quot; definitions=&quot;RELEASE&quot; excludes=&quot;src/unicode_class.vb&quot; mainClass = &quot;MainApp&quot; destFile=&quot;NetApp.exe&quot; optionExplicit=&quot;true&quot; optionCompare=&quot;text&quot; references="System.Xml,System.Web.Xml" &gt; &lt;reference file="${testCSC.dll}"/&gt; &lt;define name="RELEASE"/&gt; &lt;define name="DEBUG" if="debug.property"/&gt; &lt;define name="def3" unless="def2.property"/&gt; &lt;/vbc&gt; </pre>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">additionalmodules</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of modules to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="24">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">debug</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the debug flag on or off.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the destination directory of files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the name of exe/library to create.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">executable</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the name of the program, overriding the defaults. Can be used to set the full path to a program, or to switch to an alternate implementation of the command, such as the Mono or Rotor versions -provided they use the same command line arguments as the .NET framework edition</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Any extra options which are not explicitly supported by this task.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, fail on compilation errors.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">imports</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Declare global imports for namespaces in referenced metadata files.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">includedefaultreferences</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, automatically includes the common assemblies in dotnet, and tells the compiler to link in mscore.dll. set the automatic reference inclusion flag on or off this flag controls the /nostdlib option in CSC</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">mainclass</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the name of main class for executables.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optimize</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, enables optimization flag.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optioncompare</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Specify binary- or text-style string comparisons. Defaults to "binary"</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optionexplicit</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Whether to require explicit declaration of variables.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">optionstrict</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Enforce strict language semantics.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">referencefiles</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path of references to include. Wildcards should work.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Path</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">references</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Semicolon separated list of DLLs to refer to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">removeintchecks</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Whether to remove integer checks. Default false.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">rootnamespace</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Specifies the root namespace for all type declarations.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcdir</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the source directory of the files to be compiled.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">targettype</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the target type to one of exe|library|module|winexe</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">"exe", "library", "module", "winexe"</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">utf8output</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">If true, require all compiler output to be in UTF8 format.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">warnlevel</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Level of warning currently between 1 and 4 with 4 being the strictest.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">int</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32icon</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Set the filename of icon to include.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">win32res</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the filename of a win32 resource (.RES) file to include. This is not a .NET resource, but what Windows is used to.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>define</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetDefine)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a define to the list of definitions
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>reference</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new reference fileset to the compilation
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>resource</strong> (org.apache.tools.ant.taskdefs.optional.dotnet.DotnetResource)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        link or embed a resource
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#828DA6">
+        <font color="#ffffff" face="arial,helvetica.sanserif" size="-1">
+          <strong>src</strong> (org.apache.tools.ant.types.FileSet)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        add a new source directory to the compile
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/vss.html b/trunk/docs/manual/OptionalTasks/vss.html
new file mode 100644
index 0000000..fb3ea0c
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/vss.html
@@ -0,0 +1,823 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Microsoft Visual SourceSafe(VSS) Tasks</title>
+</head>
+<body>
+<h1>Microsoft Visual SourceSafe Tasks User Manual</h1>
+<p>by</p>
+<ul>
+    <li>Craig Cottingham</li>
+    <li>Andrew Everitt</li>
+    <li>Balazs Fejes 2</li>
+    <li><a href="mailto:Glenn_Twiggs@bmc.com">Glenn_Twiggs@bmc.com</a></li>
+    <li>Martin Poeschl (<a href="mailto:mpoeschl@marmot.at">mpoeschl@marmot.at</a>)</li>
+    <li>Phillip Wells</li>
+    <li>Jon Skeet (<a href="mailto:jon.skeet@peramon.com">jon.skeet@peramon.com</a>)</li>
+    <li>Nigel Magnay (<a href="mailto:nigel.magnay@parsec.co.uk">nigel.magnay@parsec.co.uk</a>)</li>
+    <li>Gary S. Weaver</li>
+    <li>Jesse Stockall</li>
+ </ul>
+<hr>
+<h2>Contents</h2>
+<ul>
+    <li><a href="#intro">Introduction</a></li>
+    <li><a href="#tasks">The Tasks</a></li>
+</ul>
+<br>
+<h2><a name="intro">Introduction</a></h2>
+<p>These tasks provide an interface to the
+<a href="http://msdn.microsoft.com/ssafe/default.asp" target="_top">Microsoft Visual SourceSafe</a> SCM.
+The <code>org.apache.tools.ant.taskdefs.optional.vss</code> package consists of a simple framework to support
+vss functionality as well as some Ant tasks encapsulating frequently used vss commands.
+Although it is possible to use these commands on the desktop,
+they were primarily intended to be used by automated build systems.</p>
+<p>
+If you get a CreateProcesss IOError=2 when running these, it means
+that ss.exe was not found. Check to see if you can run it from the
+command line -you may need to alter your path, or set the <tt>ssdir</tt>
+property.
+<h2><a name="tasks">The Tasks</a></h2>
+
+<table border="0" cellspacing="0" cellpadding="3">
+    <tr>
+        <td><a href="#vssget">vssget</a></td>
+        <td>Retrieves a copy of the specified VSS file(s).</td>
+    </tr>
+    <tr>
+        <td><a href="#vsslabel">vsslabel</a></td>
+        <td>Assigns a label to the specified version or current version of a file or project.</td>
+    </tr>
+    <tr>
+        <td><a href="#vsshistory">vsshistory</a></td>
+        <td>Shows the history of a file or project in VSS.</td>
+    </tr>
+    <tr>
+        <td><a href="#vsscheckin">vsscheckin</a></td>
+        <td>Updates VSS with changes made to a checked out file, and unlocks the VSS master copy.</td>
+    </tr>
+    <tr>
+        <td><a href="#vsscheckout">vsscheckout</a></td>
+        <td>Copies a file from the current project to the current folder, for the purpose of editing.</td>
+    </tr>
+    <tr>
+        <td><a href="#vssadd">vssadd</a></td>
+        <td>Adds a new file into the VSS Archive</td>
+    </tr>
+    <tr>
+        <td><a href="#vsscp">vsscp</a></td>
+        <td>Change the current project being used in VSS</td>
+    </tr>
+    <tr>
+        <td><a href="#vsscreate">vsscreate</a></td>
+        <td>Creates a project in VSS.</td>
+    </tr>
+</table>
+
+<hr>
+<h2>Task Descriptions</h2>
+
+<!-- VSSGET -->
+
+<h2><a name="vssget">VssGet</a></h2>
+<h3>Description</h3>
+Task to perform GET commands to Microsoft Visual SourceSafe.
+<p>If you specify two or more attributes from version, date and
+label only one will be used in the order version, date, label.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project/file(s) you wish to
+         perform the action on.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>localpath</td>
+     <td>Override the working directory and get to the specified path</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>writable</td>
+     <td>true or false; default false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>recursive</td>
+     <td>true or false; default false. Note however that in the SourceSafe UI
+     , there is a setting accessed via Tools/Options/GeneralTab called
+     &quot;Act on projects recursively&quot;.  If this setting is checked,
+     then the recursive attribute is effectively ignored, and the get
+     will always be done recursively
+     </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>version</td>
+     <td>a version number to get</td>
+     <td rowspan="3">No, only one of these allowed</td>
+  </tr>
+  <tr>
+     <td>date</td>
+     <td>a date stamp to get at</td>
+  </tr>
+  <tr>
+     <td>label</td>
+     <td>a label to get for</td>
+  </tr>
+  <tr>
+     <td>quiet</td>
+     <td>suppress output (off by default)</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>autoresponse</td>
+     <td>What to respond with (sets the -I option). By default, -I- is
+     used; values of Y or N will be appended to this.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>writablefiles</td>
+    <td>Behavior when local files are writable. Valid options are: <code>replace</code>, 
+        <code>skip</code> and <code>fail</code>; Defaults to <code>fail</code>
+        <br><code>skip</code> implies <code>failonerror=false</code></td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>filetimestamp</td>
+    <td>Set the behavior for timestamps of local files. Valid options are <code>current</code>, 
+        <code>modified</code>, or <code>updated</code>. Defaults to <code>current</code>.</td> 
+    <td>No</td>
+  </tr>
+</table>
+<p>Note that only one of version, date or label should be specified</p>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vssget localPath=&quot;C:\mysrc\myproject&quot;
+        recursive=&quot;true&quot;
+        label=&quot;Release1&quot;
+        login=&quot;me,mypassword&quot;
+        vsspath=&quot;$/source/aProject&quot;
+        writable=&quot;true&quot;/&gt;
+</pre>
+</blockquote>
+<p>Does a get on the VSS-Project <i>$/source/myproject</i> using the username
+<i>me</i> and the password <i>mypassword</i>. It will recursively get the files
+which are labeled <i>Release1</i> and write them to the local directory
+<i>C:\mysrc\myproject</i>. The local files will be writable.</p>
+<hr>
+
+<!-- VSSLABEL -->
+
+<h2><a name="vsslabel">VssLabel</a></h2>
+<h3>Description</h3>
+Task to perform LABEL commands to Microsoft Visual SourceSafe.
+<p>Assigns a label to the specified version or current version of a file or
+project.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+   <tr>
+     <th>Attribute</th>
+     <th>Values</th>
+     <th>Required</th>
+   </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project/file(s) you wish to
+         perform the action on.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+   <tr>
+      <td>label</td>
+      <td>A label to apply to the hierarchy</td>
+      <td>Yes</td>
+   </tr>
+   <tr>
+      <td>version</td>
+      <td>An existing file or project version to label. By default the current
+      version is labeled.</td>
+      <td>No</td>
+   </tr>
+   <tr>
+      <td>comment</td>
+      <td>The comment to use for this label. Empty or '-' for no comment.</td>
+      <td>No</td>
+   </tr>
+  <tr>
+     <td>autoresponse</td>
+     <td>What to respond with (sets the -I option). By default, -I- is
+     used; values of Y or N will be appended to this.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vsslabel vsspath=&quot;$/source/aProject&quot;
+          login=&quot;me,mypassword&quot;
+          label=&quot;Release1&quot;/&gt;
+</pre>
+</blockquote>
+<p>Labels the current version of the VSS project <i>$/source/aProject</i> with
+the label <i>Release1</i> using the username <i>me</i> and the password
+<i>mypassword</i>.
+</p>
+<blockquote>
+<pre>
+&lt;vsslabel vsspath=&quot;$/source/aProject/myfile.txt&quot;
+          version=&quot;4&quot;
+          label=&quot;1.03.004&quot;/&gt;
+</pre>
+</blockquote>
+<p>Labels version 4 of the VSS file <i>$/source/aProject/myfile.txt</i> with the
+label <i>1.03.004</i>. If this version already has a label, the operation (and
+the build) will fail.
+</p>
+<hr>
+
+<!-- VSSHISTORY -->
+
+<h2><a name="vsshistory">VssHistory</a></h2>
+<h3>Description</h3>
+Task to perform HISTORY commands to Microsoft Visual SourceSafe.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project/file(s) you wish to
+         perform the action on.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>fromDate</td>
+    <td>Start date for comparison</td>
+    <td>See below</td>
+  </tr>
+  <tr>
+    <td>toDate</td>
+    <td>End date for comparison</td>
+    <td>See below</td>
+  </tr>
+  <tr>
+    <td>dateFormat</td>
+    <td>Format of dates in fromDate and toDate. Used when calculating dates with
+      the numdays attribute. This string uses the formatting rules of SimpleDateFormat.
+      Defaults to DateFormat.SHORT.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>fromLabel</td>
+    <td>Start label for comparison</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>toLabel</td>
+    <td>Start label for comparison</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>numdays</td>
+    <td>The number of days for comparison.</td>
+    <td>See below</td>
+  </tr>
+  <tr>
+    <td>output</td>
+    <td>File to write the diff.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>recursive</td>
+    <td>true or false</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>style</td>
+    <td>brief, codediff, default or nofile. The default is default.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>user</td>
+    <td>Name the user whose changes we would like to see</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h4>Specifying the time-frame</h4>
+<p>There are different ways to specify what time-frame you wish to evaluate:</p>
+<ul>
+  <li>Changes between two dates: Specify both <code>fromDate</code> and <code>toDate</code> </li>
+  <li>Changes before a date: Specify <code>toDate</code></li>
+  <li>Changes after a date: Specify <code>fromDate</code></li>
+  <li>Changes X Days before a date: Specify <code>toDate</code> and (negative!) <code>numDays</code></li>
+  <li>Changes X Days after a date: Specify <code>fromDate</code> and <code>numDays</code></li>
+</ul>
+
+
+<h3>Examples</h3>
+<blockquote>
+  <pre>
+&lt;vsshistory vsspath=&quot;$/myProject&quot; recursive=&quot;true&quot;
+            fromLabel=&quot;Release1&quot;
+            toLabel=&quot;Release2&quot;/&gt;
+</pre>
+</blockquote>
+<p>Shows all changes between &quot;Release1&quot; and &quot;Release2&quot;.</p>
+
+<blockquote>
+  <pre>
+&lt;vsshistory vsspath=&quot;$/myProject&quot; recursive=&quot;true&quot;
+            fromDate=&quot;01.01.2001&quot;
+            toDate=&quot;31.03.2001&quot;/&gt;
+</pre>
+</blockquote>
+<p>Shows all changes between January 1st 2001 and March 31st 2001 (in Germany, date must be specified according to your locale).</p>
+
+<blockquote>
+  <pre>
+&lt;tstamp&gt;
+  &lt;format property=&quot;to.tstamp&quot; pattern=&quot;M-d-yy;h:mma&quot;/&gt;
+&lt;/tstamp&gt;
+
+&lt;vsshistory vsspath=&quot;$/myProject&quot; recursive=&quot;true&quot;
+            numDays=&quot;-14&quot;
+            dateFormat=&quot;M-d-yy;h:mma&quot;
+            toDate=&quot;${to.tstamp}&quot;/&gt;
+</pre>
+</blockquote>
+<p>Shows all changes in the 14 days before today.</p>
+<hr>
+
+<!-- VSSCHECKIN -->
+
+<h2><a name="vsscheckin">VssCheckin</a></h2>
+<h3>Description</h3>
+Task to perform CHECKIN commands to Microsoft Visual SourceSafe.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project/file(s) you wish to
+         perform the action on.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>localpath</td>
+     <td>Override the working directory and get to the specified path</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>writable</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>recursive</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>comment</td>
+     <td>Comment to use for the files that where checked in.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>autoresponse</td>
+     <td>'Y', 'N' or empty. Specify how to reply to questions from VSS.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vsscheckin vsspath=&quot;$/test/test*&quot;
+            localpath=&quot;D:\build\&quot;
+            comment=&quot;Modified by automatic build&quot;/&gt;
+</pre>
+</blockquote>
+<p>Checks in the file(s) named <i>test*</i> in the project <i>$/test</i> using
+the local directory <i>D:\build</i>.</p>
+<hr>
+
+<!-- VSSCHECKOUT -->
+
+<h2><a name="vsscheckout">VssCheckout</a></h2>
+<h3>Description</h3>
+Task to perform CHECKOUT commands to Microsoft Visual SourceSafe.
+<p>If you specify two or more attributes from version, date and
+label only one will be used in the order version, date, label.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project/file(s) you wish to
+         perform the action on.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>localpath</td>
+     <td>Override the working directory and get to the specified path</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>writable</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>recursive</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>version</td>
+     <td>a version number to get</td>
+     <td rowspan="3">No, only one of these allowed</td>
+  </tr>
+  <tr>
+     <td>date</td>
+     <td>a date stamp to get at</td>
+  </tr>
+  <tr>
+     <td>label</td>
+     <td>a label to get for</td>
+  </tr>
+  <tr>
+    <td>writablefiles</td>
+    <td>Behavior when local files are writable. Valid options are: <code>replace</code>, 
+        <code>skip</code> and <code>fail</code>; Defaults to <code>fail</code>
+        <br><code>skip</code> implies <code>failonerror=false</code></td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>filetimestamp</td>
+    <td>Set the behavior for timestamps of local files. Valid options are <code>current</code>, 
+        <code>modified</code>, or <code>updated</code>. Defaults to <code>current</code>.</td> 
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>getlocalcopy</td>
+    <td>Set the behavior to retrieve local copies of the files. Defaults to true.</td> 
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vsscheckout vsspath=&quot;$/test&quot;
+             localpath=&quot;D:\build&quot;
+             recursive=&quot;true&quot;
+             login=&quot;me,mypass&quot;/&gt;
+</pre>
+</blockquote>
+<p>Does a recursive checkout of the project <i>$/test</i> to the directory D:\build.
+</p>
+<hr>
+
+<!-- VSSADD -->
+
+<h2><a name="vssadd">VssAdd</a></h2>
+<h3>Description</h3>
+Task to perform ADD commands to Microsoft Visual SourceSafe.
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>localpath</td>
+     <td>Specify the local file(s) to add to VSS</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>writable</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>recursive</td>
+     <td>true or false</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>comment</td>
+     <td>Comment to use for the files that where checked in.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>autoresponse</td>
+     <td>'Y', 'N' or empty. Specify how to reply to questions from VSS.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vssadd localpath=&quot;D:\build\build.00012.zip&quot;
+            comment=&quot;Added by automatic build&quot;/&gt;
+</pre>
+</blockquote>
+<p>Add the file named build.00012.zip into the project current working
+directory (see vsscp).</p>
+<hr>
+
+<!-- VSSCP -->
+
+<h2><a name="vsscp">VssCp</a></h2>
+<h3>Description</h3>
+<p>Task to perform CP (Change Project) commands to Microsoft Visual SourceSafe.</p>
+<p>This task is typically used before a VssAdd in order to set the target project</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+     <td>vsspath</td>
+     <td>SourceSafe path which specifies the project you wish to
+         make the current project.</td>
+     <td>Yes</td>
+  </tr>
+  <tr>
+     <td>login</td>
+     <td>username[,password] - The username and password needed to get access
+         to VSS. Note that you may need to specify both (if you have a password) -
+         Ant/VSS will hang if you leave the password out and VSS does not accept
+         login without a password. </td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>ssdir</td>
+     <td>directory where <code>ss.exe</code> resides. By default the
+         task expects it to be in the PATH.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+     <td>serverPath</td>
+     <td>directory where <code>srcsafe.ini</code> resides.</td>
+     <td>No</td>
+  </tr>
+  <tr>
+    <td>failonerror</td>
+    <td>Stop the buildprocess if ss.exe exits with a returncode of 100. Defaults to true</td>
+    <td>No</td>
+  </tr>
+</table>
+
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vsscp vsspath=&quot;$/Projects/ant&quot;/&gt;
+</pre>
+</blockquote>
+<p>Sets the current VSS project to <i>$/Projects/ant</i>.</p>
+<hr>
+
+<!-- VSSCREATE -->
+
+ <h2><a name="vsscreate">VssCreate</a></h2>
+ <h3>Description</h3>
+ Task to perform CREATE commands to Microsoft Visual Source Safe.
+ <p>Creates a new project in VSS.</p>
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <th>Attribute</th>
+    <th>Values</th>
+    <th>Required</th>
+  </tr>
+  <tr>
+    <td>login</td>
+    <td>username,password</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>vsspath</td>
+    <td>SourceSafe path of project to be created</td>
+    <td>Yes</td>
+  </tr>
+  <tr>
+    <td>ssdir</td>
+    <td>directory where <code>ss.exe</code> resides. By default the task expects it to be in the PATH.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>quiet</td>
+    <td>suppress output (off by default)</td>
+    <td>No</td>
+   </tr>
+  <tr>
+    <td>failOnError</td>
+    <td>fail if there is an error creating the project (true by default)</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>autoresponse</td>
+    <td>What to respond with (sets the -I option). By default, -I- is used; values of Y or N will be appended to this.</td>
+    <td>No</td>
+  </tr>
+  <tr>
+    <td>comment</td>
+    <td>The comment to use for this label. Empty or '-' for no comment.</td>
+    <td>No</td>
+  </tr>
+</table>
+<h3>Examples</h3>
+<blockquote>
+<pre>
+&lt;vsscreate vsspath=&quot;$/existingProject/newProject&quot;/&gt;
+</pre>
+</blockquote>
+<p>Creates the VSS-Project <i>$/existingProject/newProject</i>.</p>
+<hr>
+
+<!-- Footer -->
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/wljspc.html b/trunk/docs/manual/OptionalTasks/wljspc.html
new file mode 100644
index 0000000..b2183db
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/wljspc.html
@@ -0,0 +1,99 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head><link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>WLJSPC Task</title></head>
+<body>
+<h1>wljspc</h1>
+<h3>Description</h3>
+<p>Class to precompile JSP's using weblogic's jsp compiler (weblogic.jspc)</p>
+Tested only on Weblogic 4.5.1 - NT4.0 and Solaris 5.7,5.8<br>
+<h3>Parameters</h3>
+<table border="1" cellPadding="2" cellSpacing="0">
+  <tbody>
+    <tr>
+      <th>Attribute</th>
+      <th>Values</th>
+      <th>Required</th>
+    </tr>
+    <tr>
+      <td>src</td>
+      <td>root of source tree for JSP, ie, the document root for your weblogic server</td>
+      <td>Yes</td>
+    </tr>
+    <tr>
+      <td>
+dest</td>
+      <td> root of destination directory, what you have set as WorkingDir in the weblogic properties</td>
+      <td>Yes</td>
+    </tr>
+    <tr>
+      <td>
+package</td>
+      <td> start package name under which your JSP's would be compiled</td>
+      <td>Yes</td>
+    </tr>
+    <tr>
+      <td>
+classpath</td>
+      <td>Class path to use when compiling jsp's</td>
+      <td>Yes</td>
+    </tr>
+  </tbody>
+</table>
+<p>
+<br>
+
+A classpath should be set which contains the weblogic classes as well as all application classes<br>
+referenced by the JSP. The system classpath is also appended when the jspc is called, so you may<br>
+choose to put everything in the classpath while calling Ant. However, since presumably the JSP's will reference<br>
+classes being build by Ant, it would be better to explicitly add the classpath in the task<br>
+<br>
+The task checks timestamps on the JSP's and the generated classes, and compiles<br>
+only those files that have changed.<br>
+<br>
+It follows the weblogic naming convention of putting classes in<br>
+<b> _dirName/_fileName.class for dirname/fileName.jsp   </b><br>
+<br>
+</p>
+<h3><br>
+Example<br>
+</h3>
+<p>
+<pre>
+&lt;target name="jspcompile" depends="compile"&gt;
+  &lt;wljspc src="c:\\weblogic\\myserver\\public_html" dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp"&gt
+    &lt;classpath&gt;
+      &lt;pathelement location="${weblogic.classpath}"/&gt;
+      &lt;pathelement path="${compile.dest}"/&gt;
+    &lt;/classpath&gt;
+  &lt;/wljspc&gt;
+&lt;/target&gt;
+</pre>
+
+</p>
+
+<h3>Limitations</h3>
+<ul>
+<li>This works only on weblogic 4.5.1</li>
+<li>It compiles the files thru the Classic compiler only.</li>
+<li>Since it is my experience that weblogic jspc throws out of memory error on being given too
+many files at one go, it is called multiple times with one jsp file each.</li>
+</ul>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/wsdltodotnet.html b/trunk/docs/manual/OptionalTasks/wsdltodotnet.html
new file mode 100644
index 0000000..dfd070f
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/wsdltodotnet.html
@@ -0,0 +1,230 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+    
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>Wsdltodotnet
+ Task</title>
+</head>
+
+<body bgcolor="#ffffff" text="#000000" link="#525D76"
+      alink="#525D76" vlink="#525D76">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>Wsdltodotnet
+ Task</strong></font>
+            <br><font face="arial,helvetica,sanserif">Converts a WSDL file or URL resource into a .NET language.</font>
+          </td>
+          <td>
+            <!-- PROJECT LOGO -->
+            <a href="http://ant.apache.org/">
+              <img src="../../images/ant_logo_large.gif" align="right" alt="Apache Ant" border="0">
+            </a>
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+
+          <!-- Applying task/long-description -->
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="description">
+          <strong>Description</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        Converts a WSDL file or URL resource into a .NET language. Why add a wrapper to the MS WSDL tool? So that you can verify that your web services, be they written with Axis or anyone else's SOAP toolkit, work with .NET clients. This task is dependency aware when using a file as a source and destination; so if you <code>&lt;get&gt;</code> the file (with <code>usetimestamp="true"</code>) then you only rebuild stuff when the WSDL file is changed. Of course, if the server generates a new timestamp every time you ask for the WSDL, this is not enough...use the <code>&lt;filesmatch&gt;</code> <code>&lt;condition&gt;</code> to to byte for byte comparison against a cached WSDL file then make the target conditional on that test failing. See "Creating an XML Web Service Proxy", "wsdl.exe" docs in the framework SDK documentation
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="attributes">
+          <strong>Parameters</strong></a></font>
+      </td></tr>
+      <tr><td><blockquote>
+        <table>
+          <tr>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Attribute</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Description</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Type</b></font>
+        </td>
+        <td bgcolor="#cccccc" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>Requirement</b></font>
+        </td>
+          </tr>
+    <!-- Attribute Group -->    
+    
+    <!-- Attribute Group -->    
+        <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">destfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Name of the file to generate. Required</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left" rowspan="8">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Optional</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">extraoptions</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Any extra WSDL.EXE options which aren't explicitly supported by the ant wrapper task; optional</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">failonerror</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Whether or not a failure should halt the build. Optional - default is <code>true</code>.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">language</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">set the language; one of "CS", "JS", or "VB" optional, default is CS for C# source</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">namespace</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">namespace to place the source in. optional; default ""</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">server</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">flag to enable server side code generation; optional, default=false</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">boolean</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">srcfile</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">The local WSDL file to parse; either url or srcFile is required.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">File</font>
+        </td>
+    </tr>
+    <!-- Attribute -->
+    <tr>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">url</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">Sets the URL to fetch. Fetching is by wsdl.exe; Ant proxy settings are ignored; either url or srcFile is required.</font>
+        </td>
+        <td bgcolor="#eeeeee" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">String</font>
+        </td>
+    </tr>
+
+
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="#525D76">
+        <font color="#ffffff" face="arial,helvetica.sanserif">
+          <a name="elements">
+          <strong>Parameters as nested elements</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+
+
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+</table>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/OptionalTasks/xmlvalidate.html b/trunk/docs/manual/OptionalTasks/xmlvalidate.html
new file mode 100644
index 0000000..e99e534
--- /dev/null
+++ b/trunk/docs/manual/OptionalTasks/xmlvalidate.html
@@ -0,0 +1,263 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>XMLValidate Task</title>
+</head>
+
+<body>
+
+<h2><a name="xmlvalidate">XMLValidate</a></h2>
+<h3>Description</h3>
+
+<p>This task checks that XML files are valid (or only well formed). The
+task uses the SAX2 parser implementation provided by JAXP by default
+(probably the one that is used by Ant itself), but one can specify any
+SAX1/2 parser if needed.</p>
+
+<p>This task supports the use of nested
+  <li><a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a> elements</li>
+  <li><tt>&lt;dtd&gt;</tt> elements which are used to resolve DTDs and entities</li>
+  <li><tt>&lt;attribute&gt;</tt> elements which are used to set features on the parser.
+      These can be any number of
+      <a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a>
+      or other features that your parser may support.</li>
+  <li><tt>&lt;property&gt;</tt> elements, containing string properties
+</p>
+
+<p><b>Warning</b> : JAXP creates by default a non namespace aware parser.
+The <tt>"http://xml.org/sax/features/namespaces"</tt> feature is set
+by default to <tt>false</tt> by the JAXP implementation used by ant. To validate
+a document containing namespaces,
+set the namespaces feature to <tt>true</tt> explicitly by nesting the following element:
+<pre>
+  &lt;attribute name="http://xml.org/sax/features/namespaces" value="true"/&gt;
+</pre>
+If you are using for instance a <tt>xsi:noNamespaceSchemaLocation</tt> attribute in your XML files,
+you will need this namespace support feature.
+</p>
+<p>If you are using a parser not generated by JAXP, by using the <tt>classname</tt> attribute of xmlvalidate, this warning
+may not apply.</p>
+
+
+<h3>Parameters</h3>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">the file(s) you want to check. (optionally can use an embedded fileset)</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">lenient</td>
+    <td valign="top">
+      if true, only check the XML document is well formed
+        (ignored if the specified parser is a SAX1 parser)
+    </td>
+    <td valign="top" align="center">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">the parser to use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">classpathref</td>
+    <td valign="top">where to find the parser class. Optionally can use an embedded <tt>&lt;classpath&gt;</tt> element.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">failonerror</td>
+    <td valign="top">fails on a error if set to true (defaults to true).</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">warn</td>
+    <td valign="top">log parser warn events.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+
+<h3><a name="nested">Nested Elements</a></h3>
+<h4>dtd</h4>
+<p>
+<tt>&lt;dtd&gt;</tt> is used to specify different locations for DTD resolution.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">publicId</td>
+    <td valign="top">Public ID of the DTD to resolve</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">location</td>
+    <td valign="top">Location of the DTD to use, which can be a file,
+    a resource, or a URL</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+<h4>xmlcatalog</h4>
+<p>The <a href="../CoreTypes/xmlcatalog.html"><tt>&lt;xmlcatalog&gt;</tt></a>
+element is used to perform entity resolution.</p>
+<h4>attribute</h4>
+<p>The <tt>&lt;attribute&gt;</tt> element is used to set parser features.<br>
+Features usable with the xerces parser are defined here :
+ <a href="http://xml.apache.org/xerces-j/features.html">Setting features</a><br>
+
+SAX features are defined here:
+ <a href="http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"><tt>http://xml.org/sax/features/</tt></a><br>
+ </p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The boolean value of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</p>
+
+<h4>property</h4>
+<p>The <tt>&lt;property&gt;</tt> element is used to set properties.
+These properties are defined here for the xerces XML parser implementation :
+ <a href="http://xml.apache.org/xerces-j/properties.html">XML Parser properties</a>
+Properties can be used to set the schema used to validate the XML file.
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">The name of the feature</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">The string value of the property</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+</p>
+
+
+<h3>Examples</h3>
+<pre>
+&lt;xmlvalidate file="toto.xml"/&gt;
+</pre>
+Validate toto.xml
+<pre>
+&lt;xmlvalidate failonerror="no" lenient="yes" warn="yes"
+             classname="org.apache.xerces.parsers.SAXParser"&gt;
+             classpath="lib/xerces.jar"&gt;
+  &lt;fileset dir="src" includes="style/*.xsl"/&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+Validate all .xsl files in src/style, but only warn if there is an error, rather than
+halt the build.
+<pre>
+
+&lt;xmlvalidate file="struts-config.xml" warn="false"&gt;
+  &lt;dtd publicId="-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
+       location="struts-config_1_0.dtd"/&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+
+Validate a struts configuration, using a local copy of the DTD. 
+<pre> 
+&lt;xmlvalidate failonerror="no"&gt;
+  &lt;fileset dir="${project.dir}" includes="**/*.xml"/&gt;
+  &lt;xmlcatalog refid="mycatalog"/&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+
+Scan all XML files in the project, using a predefined catalog to map URIs to local files.
+<pre>
+&lt;xmlvalidate failonerror="no"&gt;
+  &lt;fileset dir="${project.dir}" includes="**/*.xml"/&gt;
+  &lt;xmlcatalog&gt;
+       &lt;dtd
+         publicId=&quot;-//ArielPartners//DTD XML Article V1.0//EN&quot;
+         location=&quot;com/arielpartners/knowledgebase/dtd/article.dtd&quot;/&gt;
+  &lt;/xmlcatalog&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+Scan all XML files in the project, using the catalog defined inline.
+
+<pre>
+&lt;xmlvalidate failonerror="yes" lenient="no" warn="yes"&gt;
+  &lt;fileset dir="xml" includes="**/*.xml"/&gt;
+  &lt;attribute name="http://xml.org/sax/features/validation" value="true"/&gt;
+  &lt;attribute name="http://apache.org/xml/features/validation/schema"  value="true"/&gt;
+  &lt;attribute name="http://xml.org/sax/features/namespaces" value="true"/&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+Validate all .xml files in xml directory with the parser configured to perform XSD validation.
+Note: The parser must support the feature
+<code>http://apache.org/xml/features/validation/schema</code>.
+The <a href="schemavalidate.html">schemavalidate</a> task is better for validating
+W3C XML Schemas, as it extends this task with the right options automatically enabled,
+and makes it easy to add a list of schema files/URLs to act as sources.
+
+<pre>
+<!-- Converts path to URL format -->
+&lt;pathconvert dirsep="/" property="xsd.file"&gt;
+&lt;path&gt;
+   &lt;pathelement location="xml/doc.xsd"/&gt;
+&lt;/path&gt;
+&lt;/pathconvert&gt;
+
+&lt;xmlvalidate file="xml/endpiece-noSchema.xml" lenient="false"
+  failonerror="true" warn="true"&gt;
+  &lt;attribute name="http://apache.org/xml/features/validation/schema"
+  value="true"/&gt;
+  &lt;attribute name="http://xml.org/sax/features/namespaces" value="true"/&gt;
+  &lt;property
+  name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+  value="${xsd.file}"/&gt;
+&lt;/xmlvalidate&gt;
+</pre>
+<br>
+Validate the file xml/endpiece-noSchema.xml against the schema xml/doc.xsd.
+<br>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTypes/classfileset.html b/trunk/docs/manual/OptionalTypes/classfileset.html
new file mode 100644
index 0000000..2bfb33d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTypes/classfileset.html
@@ -0,0 +1,119 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ClassFileSet Type</title>
+</head>
+
+<body>
+<h2><a name="fileset">ClassFileSet</a></h2>
+<p>A classfileset is a specialised type of fileset which, given a set of 
+&quot;root&quot; classes, will include all of the class files upon which the 
+root classes depend. This is typically used to create a jar with all of the
+required classes for a particular application.
+</p>
+<p>
+classfilesets are typically used by reference. They are declared with an
+&quot;id&quot; value and this is then used as a reference where a normal fileset
+is expected.
+</p>
+<p>
+This type requires the <code>jakarta-BCEL</code> library.
+</p>
+
+
+<h3>Attributes</h3>
+<p>The class fileset support the following attributes in addition
+to those supported by the 
+<a href="../CoreTypes/fileset.html">standard fileset</a>:
+</p>
+ 
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">rootclass</td>
+    <td valign="top">A single root class name</td>
+    <td valign="top" align="center">No</td>
+  </tr>
+</table>
+
+<h3>Nested Elements</h3>
+
+<h4>Root</h4>
+<p>
+When more than one root class is required, multiple nested <code>&lt;root&gt;</code> elements
+may be used
+</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">classname</td>
+    <td valign="top">The fully qualified name of the root class</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+</table>
+
+<h4>RootFileSet</h4>
+<p>
+A root fileset is used to add a set of root classes from a fileset. In this case the entries in 
+the fileset are expected to be Java class files. The name of the Java class is determined by the 
+relative location of the classfile in the fileset. So, the file 
+<code>org/apache/tools/ant/Project.class</code> corresponds to the Java class
+<code>org.apache.tools.ant.Project</code>.</p>
+
+<h4>Examples</h4>
+<blockquote><pre>
+&lt;classfileset id=&quot;reqdClasses" dir=&quot;${classes.dir}&quot;&gt;
+  &lt;root classname=&quot;org.apache.tools.ant.Project&quot;/&gt;
+&lt;/classfileset&gt;
+</pre></blockquote>
+
+<p>This example creates a fileset containing all the class files upon which the 
+<code>org.apache.tools.ant.Project</code> class depends. This fileset could 
+then be used to create a jar. 
+</p>
+
+<blockquote><pre>
+&lt;jar destfile=&quot;minimal.jar&quot;&gt;
+  &lt;fileset refid=&quot;reqdClasses&quot;/&gt;
+&lt;/jar&gt;
+</pre></blockquote>
+
+<blockquote><pre>
+&lt;classfileset id=&quot;reqdClasses&quot; dir=&quot;${classes.dir}&quot;&gt;
+  &lt;rootfileset dir=&quot;${classes.dir}&quot; includes=&quot;org/apache/tools/ant/Project*.class&quot;/&gt;
+&lt;/classfileset&gt;
+</pre></blockquote>
+
+<p>This example constructs the classfileset using all the class with names starting with Project 
+in the org.apache.tools.ant package</p> 
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTypes/extension.html b/trunk/docs/manual/OptionalTypes/extension.html
new file mode 100644
index 0000000..90b2765
--- /dev/null
+++ b/trunk/docs/manual/OptionalTypes/extension.html
@@ -0,0 +1,114 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Extension Type</title>
+</head>
+
+<body>
+<h2><a name="fileset">Extension</a></h2>
+<p>Utility type that represents either an available "Optional Package"
+ (formerly known as "Standard Extension") as described in the manifest
+ of a JAR file, or the requirement for such an optional package.</p>
+<p>Note that this type
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+
+<h3>Attributes</h3>
+<p>The extension type supports the following attributes</a>:
+</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">extensionName</td>
+    <td valign="top">The name of extension</td>
+    <td valign="top" align="center">yes</td>
+  </tr>
+  <tr>
+    <td valign="top">specificationVersion</td>
+    <td valign="top">The version of extension specification (Must be in
+    dewey decimal aka dotted decimal notation. 3.2.4)</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">specificationVendor</td>
+    <td valign="top">The specification vendor</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">implementationVersion</td>
+    <td valign="top">The version of extension implementation (Must be in
+    dewey decimal aka dotted decimal notation. 3.2.4)</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">implementationVendor</td>
+    <td valign="top">The implementation vendor</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">implementationVendorId</td>
+    <td valign="top">The implementation vendor ID</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+  <tr>
+    <td valign="top">implementationURL</td>
+    <td valign="top">The url from which to retrieve extension.</td>
+    <td valign="top" align="center">no</td>
+  </tr>
+</table>
+
+<h4>Examples</h4>
+<blockquote><pre>
+&lt;extension id=&quot;e1&quot;
+    extensionName=&quot;MyExtensions&quot;
+    specificationVersion=&quot;1.0&quot;
+    specificationVendor=&quot;Peter Donald&quot;
+    implementationVendorID=&quot;vv&quot;
+    implementationVendor=&quot;Apache&quot;
+    implementationVersion=&quot;2.0&quot;
+    implementationURL=&quot;http://somewhere.com/myExt.jar&quot;/&gt;
+</pre></blockquote>
+
+<p>Fully specific extension object.</p>
+
+<blockquote><pre>
+&lt;extension id=&quot;e1&quot;
+    extensionName=&quot;MyExtensions&quot;
+    specificationVersion=&quot;1.0&quot;
+    specificationVendor=&quot;Peter Donald&quot;/&gt;
+</pre></blockquote>
+
+<p>Extension object that just species the specification details.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/OptionalTypes/extensionset.html b/trunk/docs/manual/OptionalTypes/extensionset.html
new file mode 100644
index 0000000..c3b151d
--- /dev/null
+++ b/trunk/docs/manual/OptionalTypes/extensionset.html
@@ -0,0 +1,83 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>ExtensionSet Type</title>
+</head>
+
+<body>
+<h2><a>ExtensionSet</a></h2>
+<p>Utility type that represents a set of Extensions.</p>
+<p>Note that this type
+works with extensions as defined by the "Optional Package" specification.
+ For more information about optional packages, see the document
+<em>Optional Package Versioning</em> in the documentation bundle for your
+Java2 Standard Edition package, in file
+<code>guide/extensions/versioning.html</code> or online at
+<a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+
+<h3>Nested Elements</h3>
+
+<h4>extension</h4>
+<p><a href="extension.html">Extension</a> object to add to set.</p>
+
+<h4>fileset</h4>
+ <p><a href="../CoreTypes/fileset.html">FileSet</a>s all files contained
+ contained within set that are jars and implement an extension are added
+ to extension set.</p>
+
+<h4>LibFileSet</h4>
+ <p>All files contained contained within set that are jars and implement 
+ an extension are added to extension set. However the extension information 
+ may be modified by attributes of libfileset</p>
+
+<h4>Examples</h4>
+<blockquote><pre>
+&lt;extension id=&quot;e1&quot;
+    extensionName=&quot;MyExtensions&quot;
+    specificationVersion=&quot;1.0&quot;
+    specificationVendor=&quot;Peter Donald&quot;
+    implementationVendorID=&quot;vv&quot;
+    implementationVendor=&quot;Apache&quot;
+    implementationVersion=&quot;2.0&quot;
+    implementationURL=&quot;http://somewhere.com/myExt.jar&quot;/&gt;
+
+&lt;libfileset id="lfs"
+               includeUrl="true"
+               includeImpl="false"
+               dir="tools/lib"&gt;
+  &lt;include name="*.jar"/&gt;
+&lt;/libfileset&gt;
+
+&lt;extensionSet id="exts"&gt;
+  &lt;libfileset dir="lib"&gt;
+    &lt;include name="*.jar"/&gt;
+  &lt;/libfileset&gt;
+  &lt;libfileset refid="lfs"/&gt;
+  &lt;extension refid="e1"/&gt;
+&lt;/extensionSet&gt;
+
+</pre></blockquote>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/antexternal.html b/trunk/docs/manual/antexternal.html
new file mode 100644
index 0000000..80951d6
--- /dev/null
+++ b/trunk/docs/manual/antexternal.html
@@ -0,0 +1,160 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>InputHandler</title>
+</head>
+
+<body>
+<h1>Using Ant Tasks Outside of Ant</h1>
+
+<h2>Rationale</h2>
+
+<p>Ant provides a rich set of tasks for buildfile creators and
+administrators.  But what about programmers?  Can the functionality
+provided by Ant tasks be used in java programs?</p>
+
+<p>Yes, and its quite easy.  Before getting into the details, however, 
+we should mention the pros and cons of this approach:
+
+<h3>Pros</h3>
+
+<table cellpadding="0" margin="0" border="1">
+<tr>
+<td><b>Robust</b></td>
+<td>
+Ant tasks are very robust.  They have been banged on by many people.
+Ant tasks have been used in many different contexts, and have
+therefore been instrumented to take care of a great many boundary
+conditions and potentially obscure errors.
+</td>
+</tr>
+<tr>
+<td><b>Cross Platform</b></td>
+<td>
+Ant tasks are cross platform.  They have been tested on all of the
+volume platforms, and several rather unusual ones (Netware and OS/390, to
+name a few).
+</td>
+</tr>
+<tr>
+<td><b>Community Support</b></td>
+<td>
+Using Ant tasks means you have less of your own code to support.  Ant
+code is supported by the entire Apache Ant community.
+</td>
+</tr>
+</table>
+
+<h3>Cons</h3>
+
+<table cellpadding="0" margin="0" border="1">
+<tr>
+<td><b>Dependency on Ant Libraries</b></td>
+<td>
+Obviously, if you use an Ant task in your code, you will have to add
+"ant.jar" to your path.  Of course, you could use a code optimizer to
+remove the unnecessary classes, but you will still probably require a
+chunk of the Ant core.
+</td>
+</tr>
+<tr>
+<td><b>Loss of Flexibility</b></td>
+<td>
+At some point, if you find yourself having to modify the Ant code, it
+probably makes more sense to "roll your own."  Of course, you can
+still steal some code snippets and good ideas.  This is the beauty of
+open source!
+</td>
+</tr>
+</table>
+
+
+<h2>Example</h2>
+
+<p>Let's say you want to unzip a zip file programmatically from java
+into a certain directory.  Of course you could write your own routine
+to do this, but why not use the Ant task that has already been written?</p>
+
+<p>In my example, I wanted to be able to unzip a file from within an
+XSLT Transformation.  XSLT Transformers can be extended by plugging in
+static methods in java.  I therefore need a function something like
+this:</p>
+
+<pre>
+/**
+ * Unzip a zip file into a given directory.
+ *
+ * @param zipFilepath A pathname representing a local zip file
+ * @param destinationDir where to unzip the archive to
+ */
+ static public void unzip(String zipFilepath, String destinationDir)
+</pre>
+
+<p>
+The Ant task to perform this function is
+<code>org.apache.tools.ant.taskdefs.Expand</code>.  All we have to do
+is create a dummy Ant <code>Project</code> and <code>Target</code>,
+set the <code>Task</code> parameters that would normally be set in a
+buildfile, and call <code>execute()</code>.</p>
+
+<p>First, let's make sure we have the proper includes:</p>
+
+<pre>
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.taskdefs.Expand;
+import java.io.File;
+</pre>
+
+<p>The function call is actually quite simple:</p>
+
+<pre>
+static public void unzip(String zipFilepath, String destinationDir) {
+
+    final class Expander extends Expand {
+        public Expander() {
+ 	    project = new Project();
+	    project.init();
+	    taskType = "unzip";
+	    taskName = "unzip";
+	    target = new Target();
+	}	
+    }
+    Expander expander = new Expander();
+    expander.setSrc(new File(zipfile));
+    expander.setDest(new File(destdir));
+    expander.execute();
+</pre>
+
+<p>In actual practice, you will probably want to add your own error
+handling code and you may not want to use a local inner class.
+However, the point of the example is to show how an Ant task can be
+called programmatically in relatively few lines of code.</p>
+
+<p>The question you are probably asking yourself at this point is:
+<i>How would I know which classes and methods have to be called in
+order to set up a dummy Project and Target?</i> The answer is: you
+don't.  Ultimately, you have to be willing to get your feet wet and
+read the source code.  The above example is merely designed to whet
+your appetite and get you started.  Go for it!</p>
+
+
+</html>
diff --git a/trunk/docs/manual/anttaskslist.html b/trunk/docs/manual/anttaskslist.html
new file mode 100644
index 0000000..9fb2d7b
--- /dev/null
+++ b/trunk/docs/manual/anttaskslist.html
@@ -0,0 +1,42 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Ant Tasks</h3>
+<a href="tasksoverview.html" target="mainFrame">Overview of Ant Tasks</a><br/>
+<a href="coretasklist.html" target="navFrame">Core Tasks</a><br/>
+<a href="optionaltasklist.html" target="navFrame">Optional Tasks</a><br/>
+<div style="padding-left:1em">
+  <a href="install.html#librarydependencies" target="mainFrame">
+  Library Dependencies</a><br/>
+</div>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/api/index.html b/trunk/docs/manual/api/index.html
new file mode 100644
index 0000000..af3099e
--- /dev/null
+++ b/trunk/docs/manual/api/index.html
@@ -0,0 +1,31 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+<link rel="stylesheet" type="text/css" href="../stylesheets/style.css">
+<title>Apache Ant API</title>
+</head>
+<body>
+<b>Apache Ant API has not been generated</b>
+
+<p>If you see this page online at <a
+href="http://ant.apache.org/">ant.apache.org</a>, it is not a bug, but
+on purpose.  We do not provide an online version of the API docs, they
+are included with all our distributions.</p>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/base_task_classes.html b/trunk/docs/manual/base_task_classes.html
new file mode 100644
index 0000000..1b058eb
--- /dev/null
+++ b/trunk/docs/manual/base_task_classes.html
@@ -0,0 +1,114 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Tasks Designed for Extension</title>
+</head>
+
+<body>
+<h1>Tasks Designed for Extension</h1>
+
+<p>These classes are designed to be extended.  Always start here when writing your own task.</p>
+
+<p><strong>The links will not work in the online version of this document.</strong></p>
+
+<table border="1">
+<thead>
+<tr>
+<th>
+Class
+</th>
+<th>
+Description
+</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/Task.html">Task</a>
+</td>
+<td>
+Base class for all tasks.
+</td>
+</tr>
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/taskdefs/AbstractCvsTask.html">AbstractCvsTask</a>
+</td>
+<td>
+Another task can extend this with some customized output processing
+</td>
+</tr>
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/taskdefs/JDBCTask.html">JDBCTask</a>
+</td>
+<td>
+Handles JDBC configuration needed by SQL type tasks.
+</td>
+</tr>
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/taskdefs/MatchingTask.html">MatchingTask</a>
+</td>
+<td>
+This is an abstract task that should be used by all those tasks that require to include or exclude files based on pattern matching.
+</td>
+</tr>
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/taskdefs/Pack.html">Pack</a>
+</td>
+<td>
+Abstract Base class for pack tasks.
+</td>
+</tr>
+
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/taskdefs/Unpack.html">Unpack</a>
+</td>
+<td>
+Abstract Base class for unpack tasks.
+</td>
+</tr>
+
+<tr>
+<td>
+<a href="api/org/apache/tools/ant/dispatch/DispatchTask.html">DispatchTask</a>
+</td>
+<td>
+Abstract Base class for tasks that may have multiple actions.
+</td>
+</tr>
+
+</tbody>
+</table>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/clonevm.html b/trunk/docs/manual/clonevm.html
new file mode 100644
index 0000000..0235546
--- /dev/null
+++ b/trunk/docs/manual/clonevm.html
@@ -0,0 +1,52 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>ant.build.clonevm</title>
+</head>
+
+<body>
+
+<h2><a name="clonevm">ant.build.clonevm</a></h2>
+
+<p><em>Since Ant 1.7</em></p>
+
+<p>The value of the ant.build.clonevm system property controls how Ant
+instruments forked Java Virtual Machines.  The <a
+href="CoreTasks/java.html">java</a> and <a
+href="OptionalTasks/junit.html">junit</a> tasks support clonevm
+attributes to control the VMs on a task-by-task basis while the system
+property applies to all forked Java VMs.</p>
+
+<p>If the value of the property is true, then all system properties of
+the forked Java Virtual Machine will be the same as those of the Java
+VM running Ant.  In addition, if you set ant.build.clonevm to true and <a
+href="sysclasspath.html">build.sysclasspath</a> has not been set, the
+bootclasspath of forked Java VMs gets constructed as if
+build.sysclasspath had the value "last".</p>
+
+<p>Note that this has to be a system property, so it cannot be
+specified on the Ant command line.  Use the ANT_OPTS environment
+variable instead.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/conceptstypeslist.html b/trunk/docs/manual/conceptstypeslist.html
new file mode 100644
index 0000000..6e09a84
--- /dev/null
+++ b/trunk/docs/manual/conceptstypeslist.html
@@ -0,0 +1,78 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Concepts</h3>
+<a href="clonevm.html">ant.build.clonevm</a><br/>
+<a href="sysclasspath.html">build.sysclasspath</a><br/>
+<a href="javacprops.html">Ant properties controlling javac</a><br/>
+<a href="CoreTasks/common.html">Common Attributes</a><br/>
+
+<h3>Core Types</h3>
+<a href="CoreTypes/description.html">Description Type</a><br/>
+<a href="dirtasks.html">Directory-based Tasks</a><br/>
+<a href="CoreTypes/dirset.html">DirSet</a><br/>
+<a href="CoreTypes/filelist.html">FileList</a><br/>
+<a href="CoreTypes/fileset.html">FileSet</a><br/>
+<a href="CoreTypes/mapper.html">File Mappers</a><br/>
+<a href="CoreTypes/filterchain.html">FilterChains and FilterReaders</a><br/>
+<a href="CoreTypes/filterset.html">FilterSet</a><br/>
+<a href="CoreTypes/patternset.html">PatternSet</a><br/>
+<a href="using.html#path">Path-like Structures</a><br/>
+<a href="CoreTypes/permissions.html">Permissions</a><br/>
+<a href="CoreTypes/propertyset.html">PropertySet</a><br/>
+<a href="CoreTypes/redirector.html">I/O Redirectors</a><br/>
+<a href="CoreTypes/regexp.html">Regexp</a><br/>
+<a href="CoreTypes/resources.html">Resources</a><br/>
+<a href="CoreTypes/resources.html#collection">Resource Collections</a><br/>
+<a href="CoreTypes/selectors.html">Selectors</a><br/>
+<a href="CoreTypes/tarfileset.html">TarFileSet</a><br/>
+<a href="CoreTypes/xmlcatalog.html">XMLCatalog</a><br/>
+<a href="CoreTypes/zipfileset.html">ZipFileSet</a><br/>
+
+<h3>Optional Types</h3>
+<a href="OptionalTypes/classfileset.html">Class Fileset</a><br/>
+<a href="OptionalTypes/extension.html">Extension Package</a><br/>
+<a href="OptionalTypes/extensionset.html">Set of Extension Packages</a><br/>
+
+<h3>Namespace</h3>
+<a href="CoreTypes/namespace.html">Namespace Support</a><br/>
+
+<h3>Antlib</h3>
+<a href="CoreTypes/antlib.html">Antlib</a><br/>
+<a href="CoreTypes/antlib.html#antlibnamespace">Antlib namespace</a><br/>
+<a href="CoreTypes/antlib.html#currentnamespace">Current namespace</a><br/>
+
+<h3>Custom Components</h3>
+<a href="CoreTypes/custom-programming.html">Custom Components</a><br/>
+<a href="CoreTypes/custom-programming.html#customconditions">Conditions</a><br/>
+<a href="CoreTypes/custom-programming.html#customselectors">Selectors</a><br/>
+<a href="CoreTypes/custom-programming.html#filterreaders">FilterReaders</a><br/>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/coretasklist.html b/trunk/docs/manual/coretasklist.html
new file mode 100644
index 0000000..2d23389
--- /dev/null
+++ b/trunk/docs/manual/coretasklist.html
@@ -0,0 +1,133 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<a href="optionaltasklist.html" target="navFrame">Optional Tasks</a><br/>
+<a href="tasksoverview.html" target="mainFrame">Overview of Ant Tasks</a><br/>
+<a href="conceptstypeslist.html" target="navFrame">Concepts and Types</a><br/>
+
+<h3>Core Tasks</h3>
+<a href="CoreTasks/ant.html">Ant</a><br/>
+<a href="CoreTasks/antcall.html">AntCall</a><br/>
+<a href="CoreTasks/antstructure.html">AntStructure</a><br/>
+<a href="CoreTasks/antversion.html">AntVersion</a><br/>
+<a href="CoreTasks/apply.html">Apply/<i>ExecOn</i></a><br/>
+<a href="CoreTasks/apt.html">Apt</a><br/>
+<a href="CoreTasks/available.html">Available</a><br/>
+<a href="CoreTasks/basename.html">Basename</a><br/>
+<a href="CoreTasks/buildnumber.html">BuildNumber</a><br/>
+<a href="CoreTasks/unpack.html">BUnzip2</a><br/>
+<a href="CoreTasks/pack.html">BZip2</a><br/>
+<a href="CoreTasks/checksum.html">Checksum</a><br/>
+<a href="CoreTasks/chmod.html">Chmod</a><br/>
+<a href="CoreTasks/concat.html">Concat</a><br/>
+<a href="CoreTasks/condition.html">Condition</a><br/>
+<div style="padding-left:1em">
+  <a href="CoreTasks/conditions.html">Supported conditions</a><br/>
+</div>
+<a href="CoreTasks/copy.html">Copy</a><br/>
+<a href="CoreTasks/copydir.html"><i>Copydir</i></a><br/>
+<a href="CoreTasks/copyfile.html"><i>Copyfile</i></a><br/>
+<a href="CoreTasks/componentdef.html">Componentdef</a><br/>
+<a href="CoreTasks/cvs.html">Cvs</a><br/>
+<a href="CoreTasks/changelog.html">CvsChangeLog</a><br/>
+<a href="CoreTasks/cvsversion.html">CvsVersion</a><br/>
+<a href="CoreTasks/cvspass.html">CVSPass</a><br/>
+<a href="CoreTasks/cvstagdiff.html">CvsTagDiff</a><br/>
+<a href="CoreTasks/defaultexcludes.html">Defaultexcludes</a><br/>
+<a href="CoreTasks/delete.html">Delete</a><br/>
+<a href="CoreTasks/deltree.html"><i>Deltree</i></a><br/>
+<a href="CoreTasks/dependset.html">Dependset</a><br/>
+<a href="CoreTasks/diagnostics.html">Diagnostics</a><br/>
+<a href="CoreTasks/dirname.html">Dirname</a><br/>
+<a href="CoreTasks/ear.html">Ear</a><br/>
+<a href="CoreTasks/echo.html">Echo</a><br/>
+<a href="CoreTasks/echoxml.html">EchoXML</a><br/>
+<a href="CoreTasks/exec.html">Exec</a><br/>
+<a href="CoreTasks/fail.html">Fail</a><br/>
+<a href="CoreTasks/filter.html">Filter</a><br/>
+<a href="CoreTasks/fixcrlf.html">FixCRLF</a><br/>
+<a href="CoreTasks/genkey.html">GenKey</a><br/>
+<a href="CoreTasks/get.html">Get</a><br/>
+<a href="CoreTasks/unpack.html">GUnzip</a><br/>
+<a href="CoreTasks/pack.html">GZip</a><br/>
+<a href="CoreTasks/import.html">Import</a><br/>
+<a href="CoreTasks/input.html">Input</a><br/>
+<a href="CoreTasks/jar.html">Jar</a><br/>
+<a href="CoreTasks/java.html">Java</a><br/>
+<a href="CoreTasks/javac.html">Javac</a><br/>
+<a href="CoreTasks/javadoc.html">Javadoc/<i>Javadoc2</i></a><br/>
+<a href="CoreTasks/length.html">Length</a><br/>
+<a href="CoreTasks/loadfile.html">LoadFile</a><br/>
+<a href="CoreTasks/loadproperties.html">LoadProperties</a><br/>
+<a href="CoreTasks/loadresource.html">LoadResource</a><br/>
+<a href="CoreTasks/makeurl.html">MakeURL</a><br/>
+<a href="CoreTasks/mail.html">Mail</a><br/>
+<a href="CoreTasks/macrodef.html">MacroDef</a><br/>
+<a href="CoreTasks/manifest.html">Manifest</a><br/>
+<a href="CoreTasks/manifestclasspath.html">ManifestClassPath</a><br/>
+<a href="CoreTasks/mkdir.html">Mkdir</a><br/>
+<a href="CoreTasks/move.html">Move</a><br/>
+<a href="CoreTasks/nice.html">Nice</a><br/>
+<a href="CoreTasks/parallel.html">Parallel</a><br/>
+<a href="CoreTasks/patch.html">Patch</a><br/>
+<a href="CoreTasks/pathconvert.html">PathConvert</a><br/>
+<a href="CoreTasks/presetdef.html">PreSetDef</a><br/>
+<a href="CoreTasks/property.html">Property</a><br/>
+<a href="CoreTasks/recorder.html">Record</a><br/>
+<a href="CoreTasks/rename.html"><i>Rename</i></a><br/>
+<a href="CoreTasks/replace.html">Replace</a><br/>
+<a href="CoreTasks/resourcecount.html">ResourceCount</a><br/>
+<a href="CoreTasks/retry.html">Retry</a><br/>
+<a href="CoreTasks/rmic.html">Rmic</a><br/>
+<a href="CoreTasks/sequential.html">Sequential</a><br/>
+<a href="CoreTasks/signjar.html">SignJar</a><br/>
+<a href="CoreTasks/sleep.html">Sleep</a><br/>
+<a href="CoreTasks/sql.html">Sql</a><br/>
+<a href="CoreTasks/subant.html">Subant</a><br/>
+<a href="CoreTasks/sync.html">Sync</a><br/>
+<a href="CoreTasks/tar.html">Tar</a><br/>
+<a href="CoreTasks/taskdef.html">Taskdef</a><br/>
+<a href="CoreTasks/tempfile.html">Tempfile</a><br/>
+<a href="CoreTasks/touch.html">Touch</a><br/>
+<a href="CoreTasks/truncate.html">Truncate</a><br/>
+<a href="CoreTasks/tstamp.html">TStamp</a><br/>
+<a href="CoreTasks/typedef.html">Typedef</a><br/>
+<a href="CoreTasks/unzip.html">Unjar</a><br/>
+<a href="CoreTasks/unzip.html">Untar</a><br/>
+<a href="CoreTasks/unzip.html">Unwar</a><br/>
+<a href="CoreTasks/unzip.html">Unzip</a><br/>
+<a href="CoreTasks/uptodate.html">Uptodate</a><br/>
+<a href="CoreTasks/waitfor.html">Waitfor</a><br/>
+<a href="CoreTasks/whichresource.html">WhichResource</a><br/>
+<a href="CoreTasks/war.html">War</a><br/>
+<a href="CoreTasks/xmlproperty.html">XmlProperty</a><br/>
+<a href="CoreTasks/style.html">XSLT/<i>Style</i></a><br/>
+<a href="CoreTasks/zip.html">Zip</a><br/>
+</body>
+</html>
diff --git a/trunk/docs/manual/cover.html b/trunk/docs/manual/cover.html
new file mode 100644
index 0000000..c52bd95
--- /dev/null
+++ b/trunk/docs/manual/cover.html
@@ -0,0 +1,42 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Apache Ant 1.8.0 User Manual</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+<div align="center"> 
+  <h1><img src="../images/ant_logo_large.gif" width="190" height="120"></h1>
+  <h1>Apache Ant 1.7.1 Manual</h1>
+  <p align="left">This is the manual for version 1.8.0 of 
+  <a target="_top" href="http://ant.apache.org/index.html">Apache Ant</a>. 
+    If your version 
+    of Ant (as verified with <tt>ant -version</tt>) is older or newer than this 
+    version then this is not the correct manual set. Please use the documentation 
+    appropriate to your current version. Also, if you are using a version
+    older than the most recent release, we recommend an upgrade to fix bugs
+    as well as provide new functionality. </p>
+  <p>&nbsp;</p>
+</div>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/credits.html b/trunk/docs/manual/credits.html
new file mode 100644
index 0000000..65f1f47
--- /dev/null
+++ b/trunk/docs/manual/credits.html
@@ -0,0 +1,69 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<title>Apache Ant User Manual - Credits</title>
+</head>
+
+<body>
+
+<div align="center">
+<h1>Apache Ant User Manual</h1>
+<p>by</p>
+</div>
+<!-- Names are in alphabetical order, on last name -->
+<ul>
+  <li>Stephane Bailliez (<a href="mailto:sbailliez@imediation.com">sbailliez@imediation.com</a>)</li>
+  <li>Nicola Ken Barozzi (<a href="mailto:nicolaken@apache.org">nicolaken@apache.org</a>)</li>
+  <li>Jacques Bergeron (<a href="mailto:jacques.bergeron@dogico.com">jacques.bergeron@dogico.com</a>)</li>
+  <li>Stefan Bodewig (<a href="mailto:stefan.bodewig@freenet.de">stefan.bodewig@freenet.de</a>)</li>
+  <li>Patrick Chanezon (<a href="mailto:chanezon@netscape.com">chanezon@netscape.com</a>)</li>
+  <li>James Duncan Davidson (<a href="mailto:duncan@x180.com">duncan@x180.com</a>)</li>
+  <li>Tom Dimock (<a href="mailto:tad1@cornell.edu">tad1@cornell.edu</a>)</li>
+  <li>Peter Donald (<a href="mailto:donaldp@apache.org">donaldp@apache.org</a>)</li>
+  <li>dIon Gillard (<a href="mailto:dion@apache.org">dion@apache.org</a>)</li>
+  <li>Erik Hatcher (<a href="mailto:ehatcher@apache.org">ehatcher@apache.org</a>)</li>
+  <li>Diane Holt (<a href="mailto:holtdl@yahoo.com">holtdl@yahoo.com</a>)</li>
+  <li>Bill Kelly (<a href="mailto:bill.kelly@softwired-inc.com">bill.kelly@softwired-inc.com</a>)</li>
+  <li>Martijn Kruithof</li>
+  <li>Arnout J. Kuiper (<a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>)</li>
+  <li>Antoine Lévy-Lambert</li>
+  <li>Conor MacNeill</li>
+  <li>Jan Matèrne</li>
+  <li>Stefano Mazzocchi (<a href="mailto:stefano@apache.org">stefano@apache.org</a>)</li>
+  <li>Erik Meade (<a href="mailto:emeade@geekfarm.org">emeade@geekfarm.org</a>)</li>
+  <li>Sam Ruby (<a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a>)</li>
+  <li>Nico Seessle (<a href="mailto:nico@seessle.de">nico@seessle.de</a>)</li>
+  <li>Jon S. Stevens (<a href="mailto:jon@latchkey.com">jon@latchkey.com</a>)</li>
+  <li>Wolf Siberski</li>
+  <li>Magesh Umasankar</li>
+  <li>Roger Vaughn (<a href="mailto:rvaughn@seaconinc.com">rvaughn@seaconinc.com</a>)</li>
+  <li>Dave Walend (<a href="mailto:dwalend@cs.tufts.edu">dwalend@cs.tufts.edu</a>)</li>
+  <li>Phillip Wells (<a href="mailto:philwells@rocketmail.com">philwells@rocketmail.com</a>)</li>
+  <li>Christoph Wilhelms</li>
+  <li>Craeg Strong (<a href="mailto:cstrong@arielpartners.com">cstrong@arielpartners.com</a>)</li>
+</ul>
+
+<center>
+<p>Version: 1.7.0</p>
+</center>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/develop.html b/trunk/docs/manual/develop.html
new file mode 100644
index 0000000..88ff90e
--- /dev/null
+++ b/trunk/docs/manual/develop.html
@@ -0,0 +1,521 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Writing Your Own Task</title>
+</head>
+
+<body>
+<h1>Developing with Ant</h1>
+
+<h2><a name="writingowntask">Writing Your Own Task</a></h2>
+<p>It is very easy to write your own task:</p>
+<ol>
+  <li>Create a Java class that extends <code>org.apache.tools.ant.Task</code>
+      or <a href="base_task_classes.html">another class</a> that was designed to be extended.</li>
+  <li>For each attribute, write a <i>setter</i> method. The setter method must be a
+    <code>public void</code> method that takes a single argument. The
+    name of the method must begin with <code>set</code>, followed by the
+    attribute name, with the first character of the name in uppercase, and the rest in
+
+    lowercase<a href="#footnote-1"><sup>*</sup></a>.  That is, to support an attribute named
+    <code>file</code> you create a method <code>setFile</code>.
+    Depending on the type of the argument, Ant will perform some
+    conversions for you, see <a href="#set-magic">below</a>.</li>
+
+  <li>If your task shall contain other tasks as nested elements (like
+  <a href="CoreTasks/parallel.html"><code>parallel</code></a>), your
+  class must implement the interface
+  <code>org.apache.tools.ant.TaskContainer</code>.  If you do so, your
+  task can not support any other nested elements.  See 
+  <a href="#taskcontainer">below</a>.</li>
+
+<li>If the task should support character data (text nested between the
+start end end tags), write a <code>public void addText(String)</code>
+method.  Note that Ant does <strong>not</strong> expand properties on
+the text it passes to the task.</li>
+
+<li>For each nested element, write a <i>create</i>, <i>add</i> or
+<i>addConfigured</i> method.  A create method must be a
+<code>public</code> method that takes no arguments and returns an
+<code>Object</code> type. The name of the create method must begin
+with <code>create</code>, followed by the element name. An add (or
+addConfigured) method must be a <code>public void</code> method that
+takes a single argument of an <code>Object</code> type with a
+no-argument constructor.  The name of the add (addConfigured) method
+must begin with <code>add</code> (<code>addConfigured</code>),
+followed by the element name.  For a more complete discussion see 
+<a href="#nested-elements">below</a>.</li>
+
+<li>Write a <code>public void execute</code> method, with no arguments, that
+throws a <code>BuildException</code>. This method implements the task
+itself.</li>
+</ol>
+
+<hr>
+<p><a name="footnote-1">*</a> Actually the case of the letters after
+the first one doesn't really matter to Ant, using all lower case is a
+good convention, though.</p>
+
+<h3>The Life-cycle of a Task</h3>
+<ol>
+  <li>
+    The xml element that contains the tag corresponding to the
+    task gets converted to an UnknownElement at parser time.
+    This UnknownElement gets placed in a list within a target
+    object, or recursivly within another UnknownElement.
+  </li>
+  <li>
+    When the target is executed, each UnknownElement is invoked
+    using an <code>perform()</code> method. This instantiates
+    the task. This means that tasks only gets
+    instantiated at run time.
+  </li>
+
+  <li>The task gets references to its project and location inside the
+    buildfile via its inherited <code>project</code> and
+    <code>location</code> variables.</li>
+
+  <li>If the user specified an <code>id</code> attribute to this task,
+    the project
+    registers a reference to this newly created task, at run
+    time.</li>
+
+  <li>The task gets a reference to the target it belongs to via its
+    inherited <code>target</code> variable.</li>
+
+  <li><code>init()</code> is called at run time.</li>
+
+  <li>All child elements of the XML element corresponding to this task
+    are created via this task's <code>createXXX()</code> methods or
+    instantiated and added to this task via its <code>addXXX()</code>
+    methods, at run time.</li>
+
+  <li>All attributes of this task get set via their corresponding
+    <code>setXXX</code> methods, at runtime.</li>
+
+  <li>The content character data sections inside the XML element
+    corresponding to this task is added to the task via its
+    <code>addText</code> method, at runtime.</li>
+
+  <li>All attributes of all child elements get set via their corresponding
+    <code>setXXX</code> methods, at runtime.</li>
+
+  <li><a name="execute"><code>execute()</code></a> is called at runtime.
+    If <code>target1</code> and <code>target2</code> both depend
+    on <code>target3</code>, then running
+    <code>'ant target1 target2'</code> will run all tasks in
+    <code>target3</code> twice.</li>
+</ol>
+
+<h3><a name="set-magic">Conversions Ant will perform for attributes</a></h3>
+
+<p>Ant will always expand properties before it passes the value of an
+attribute to the corresponding setter method.</p>
+
+<p>The most common way to write an attribute setter is to use a
+<code>java.lang.String</code> argument.  In this case Ant will pass
+the literal value (after property expansion) to your task.  But there
+is more!  If the argument of you setter method is</p>
+
+<ul>
+
+  <li><code>boolean</code>, your method will be passed the value
+  <i>true</i> if the value specified in the build file is one of
+  <code>true</code>, <code>yes</code>, or <code>on</code> and
+  <i>false</i> otherwise.</li>
+
+  <li><code>char</code> or <code>java.lang.Character</code>, your
+  method will be passed the first character of the value specified in
+  the build file.</li>
+
+  <li>any other primitive type (<code>int</code>, <code>short</code>
+  and so on), Ant will convert the value of the attribute into this
+  type, thus making sure that you'll never receive input that is not a
+  number for that attribute.</li>
+
+  <li><code>java.io.File</code>, Ant will first determine whether the
+  value given in the build file represents an absolute path name.  If
+  not, Ant will interpret the value as a path name relative to the
+  project's basedir.</li>
+
+  <li><code>org.apache.tools.ant.types.Path</code>, Ant will tokenize
+  the value specified in the build file, accepting <code>:</code> and
+  <code>;</code> as path separators.  Relative path names will be
+  interpreted as relative to the project's basedir.</li>
+
+  <li><code>java.lang.Class</code>, Ant will interpret the value
+  given in the build file as a Java class name and load the named
+  class from the system class loader.</li>
+
+  <li>any other type that has a constructor with a single
+  <code>String</code> argument, Ant will use this constructor to
+  create a new instance from the value given in the build file.</li>
+
+  <li>A subclass of
+  <code>org.apache.tools.ant.types.EnumeratedAttribute</code>, Ant
+  will invoke this classes <code>setValue</code> method.  Use this if
+  your task should support enumerated attributes (attributes with
+  values that must be part of a predefined set of values).  See
+  <code>org/apache/tools/ant/taskdefs/FixCRLF.java</code> and the
+  inner <code>AddAsisRemove</code> class used in <code>setCr</code>
+  for an example.</li>
+
+  <li>A (Java 5) enumeration. Ant will call the setter with the enum constant
+  matching the value given in the build file. This is easier than using
+  <code>EnumeratedAttribute</code> and can result in cleaner code, but of course
+  your task will not run on JDK 1.4 or earlier. Note that any override of
+  <code>toString()</code> in the enumeration is ignored; the build file must use
+  the declared name (see <code>Enum.getName()</code>). You may wish to use lowercase
+  enum constant names, in contrast to usual Java style, to look better in build files.
+  <em>As of Ant 1.7.0.</em></li>
+
+</ul>
+
+<p>What happens if more than one setter method is present for a given
+attribute?  A method taking a <code>String</code> argument will always
+lose against the more specific methods.  If there are still more
+setters Ant could chose from, only one of them will be called, but we
+don't know which, this depends on the implementation of your Java
+virtual machine.</p>
+
+<h3><a name="nested-elements">Supporting nested elements</a></h3>
+
+<p>Let's assume your task shall support nested elements with the name
+<code>inner</code>.  First of all, you need a class that represents
+this nested element.  Often you simply want to use one of Ant's
+classes like <code>org.apache.tools.ant.types.FileSet</code> to
+support nested <code>fileset</code> elements.</p>
+
+<p>Attributes of the nested elements or nested child elements of them
+will be handled using the same mechanism used for tasks (i.e. setter
+methods for attributes, addText for nested text and
+create/add/addConfigured methods for child elements).</p>
+
+<p>Now you have a class <code>NestedElement</code> that is supposed to
+be used for your nested <code>&lt;inner&gt;</code> elements, you have
+three options:</p>
+
+<ol>
+  <li><code>public NestedElement createInner()</code></li>
+  <li><code>public void addInner(NestedElement anInner)</code></li>
+  <li><code>public void addConfiguredInner(NestedElement anInner)</code></li>
+</ol>
+
+<p>What is the difference?</p>
+
+<p>Option 1 makes the task create the instance of
+<code>NestedElement</code>, there are no restrictions on the type.
+For the options 2 and 3, Ant has to create an instance of
+<code>NestedInner</code> before it can pass it to the task, this
+means, <code>NestedInner</code> must have a <code>public</code> no-arg
+  constructor or a <code>public</code> one-arg constructor
+  taking a Project class as a parameter.
+This is the only difference between options 1 and 2.</p>
+
+<p>The difference between 2 and 3 is what Ant has done to the object
+before it passes it to the method.  <code>addInner</code> will receive
+an object directly after the constructor has been called, while
+<code>addConfiguredInner</code> gets the object <em>after</em> the
+attributes and nested children for this new object have been
+handled.</p>
+
+<p>What happens if you use more than one of the options?  Only one of
+the methods will be called, but we don't know which, this depends on
+the implementation of your Java virtual machine.</p>
+
+  <h3><a name="nestedtype">Nested Types</a></h3>
+If your task needs to nest an arbitary type that has been defined
+  using <code>&lt;typedef&gt;</code> you have two options.
+  <ol>
+    <li><code>public void add(Type type)</code></li>
+    <li><code>public void addConfigured(Type type)</code></li>
+  </ol>
+  The difference between 1 and 2 is the same as between 2 and 3 in the
+  previous section.
+  <p>
+    For example suppose one wanted to handle objects object of type
+    org.apache.tools.ant.taskdefs.condition.Condition, one may
+    have a class:
+  </p>
+  <blockquote>
+  <pre>
+public class MyTask extends Task {
+    private List conditions = new ArrayList();
+    public void add(Condition c) {
+        conditions.add(c);
+    }
+    public void execute() {
+     // iterator over the conditions
+    }
+}
+  </pre>
+  </blockquote>
+  <p>
+    One may define and use this class like this:
+  </p>
+  <blockquote>
+    <pre>
+&lt;taskdef name="mytask" classname="MyTask" classpath="classes"/&gt;
+&lt;typedef name="condition.equals"
+         classname="org.apache.tools.ant.taskdefs.conditions.Equals"/&gt;
+&lt;mytask&gt;
+    &lt;condition.equals arg1="${debug}" arg2="true"/&gt;
+&lt;/mytask&gt;
+    </pre>
+  </blockquote>
+  <p>
+    A more complicated example follows:
+  </p>
+  <blockquote>
+    <pre>
+public class Sample {
+    public static class MyFileSelector implements FileSelector {
+         public void setAttrA(int a) {}
+         public void setAttrB(int b) {}
+         public void add(Path path) {}
+         public boolean isSelected(File basedir, String filename, File file) {
+             return true;
+         }
+     }
+
+    interface MyInterface {
+        void setVerbose(boolean val);
+    }        
+
+    public static class BuildPath extends Path {
+        public BuildPath(Project project) {
+            super(project);
+        }
+        
+        public void add(MyInterface inter) {}
+        public void setUrl(String url) {}
+    }
+
+    public static class XInterface implements MyInterface {
+        public void setVerbose(boolean x) {}
+        public void setCount(int c) {}
+    }
+}
+    </pre>
+  </blockquote>
+  <p>
+    This class defines a number of static classes that implement/extend
+    Path, MyFileSelector and MyInterface. These may be defined and used
+    as follows:
+  </p>
+  <pre>
+    <blockquote>
+&lt;typedef name="myfileselector" classname="Sample$MyFileSelector"
+         classpath="classes" loaderref="classes"/&gt;
+&lt;typedef name="buildpath" classname="Sample$BuildPath"
+         classpath="classes" loaderref="classes"/&gt;
+&lt;typedef name="xinterface" classname="Sample$XInterface"
+         classpath="classes" loaderref="classes"/&gt;
+
+&lt;copy todir="copy-classes"&gt;
+   &lt;fileset dir="classes"&gt;
+      &lt;myfileselector attra="10" attrB="-10"&gt;
+         &lt;buildpath path="." url="abc"&gt;
+            &lt;xinterface count="4"/&gt;
+         &lt;/buildpath&gt;
+      &lt;/myfileselector&gt;
+   &lt;/fileset&gt;
+&lt;/copy&gt;
+    </blockquote>
+  </pre>
+<h3><a name="taskcontainer">TaskContainer</a></h3>
+
+<p>The <code>TaskContainer</code> consists of a single method,
+<code>addTask</code> that basically is the same as an <a
+href="#nested-elements">add method</a> for nested elements.  The task
+instances will be configured (their attributes and nested elements
+have been handled) when your task's <code>execute</code> method gets
+invoked, but not before that.</p>
+
+<p>When we <a href="#execute">said</a> <code>execute</code> would be
+called, we lied ;-).  In fact, Ant will call the <code>perform</code>
+method in <code>org.apache.tools.ant.Task</code>, which in turn calls
+<code>execute</code>.  This method makes sure that <a
+href="#buildevents">Build Events</a> will be triggered.  If you
+execute the task instances nested into your task, you should also
+invoke <code>perform</code> on these instances instead of
+<code>execute</code>.</p>
+
+<h3>Example</h3>
+<p>Let's write our own task, which prints a message on the
+<code>System.out</code> stream.
+The
+task has one attribute, called <code>message</code>.</p>
+<blockquote>
+<pre>
+package com.mydomain;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+public class MyVeryOwnTask extends Task {
+    private String msg;
+
+    // The method executing the task
+    public void execute() throws BuildException {
+        System.out.println(msg);
+    }
+
+    // The setter for the &quot;message&quot; attribute
+    public void setMessage(String msg) {
+        this.msg = msg;
+    }
+}
+</pre>
+</blockquote>
+<p>It's really this simple ;-)</p>
+<p>Adding your task to the system is rather simple too:</p>
+<ol>
+  <li>Make sure the class that implements your task is in the classpath when
+    starting Ant.</li>
+  <li>Add a <code>&lt;taskdef&gt;</code> element to your project.
+    This actually adds your task to the system.</li>
+  <li>Use your task in the rest of the buildfile.</li>
+</ol>
+
+<h3>Example</h3>
+<blockquote>
+<pre>
+&lt;?xml version=&quot;1.0&quot;?&gt;
+
+&lt;project name=&quot;OwnTaskExample&quot; default=&quot;main&quot; basedir=&quot;.&quot;&gt;
+  &lt;taskdef name=&quot;mytask&quot; classname=&quot;com.mydomain.MyVeryOwnTask&quot;/&gt;
+
+  &lt;target name=&quot;main&quot;&gt;
+    &lt;mytask message=&quot;Hello World! MyVeryOwnTask works!&quot;/&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre>
+</blockquote>
+<h3>Example 2</h3>
+To use a task directly from the buildfile which created it, place the
+<code>&lt;taskdef&gt;</code> declaration inside a target
+<i>after the compilation</i>. Use the <code>classpath</code> attribute of
+<code>&lt;taskdef&gt;</code> to point to where the code has just been
+compiled.
+<blockquote>
+<pre>
+&lt;?xml version=&quot;1.0&quot;?&gt;
+
+&lt;project name=&quot;OwnTaskExample2&quot; default=&quot;main&quot; basedir=&quot;.&quot;&gt;
+
+  &lt;target name=&quot;build&quot; &gt;
+    &lt;mkdir dir=&quot;build&quot;/&gt;
+    &lt;javac srcdir=&quot;source&quot; destdir=&quot;build&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;target name=&quot;declare&quot; depends=&quot;build&quot;&gt;
+    &lt;taskdef name=&quot;mytask&quot;
+        classname=&quot;com.mydomain.MyVeryOwnTask&quot;
+        classpath=&quot;build&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;target name=&quot;main&quot; depends=&quot;declare&quot;&gt;
+    &lt;mytask message=&quot;Hello World! MyVeryOwnTask works!&quot;/&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre>
+</blockquote>
+
+<p>Another way to add a task (more permanently), is to add the task name and
+implementing class name to the <code>default.properties</code> file in the
+<code>org.apache.tools.ant.taskdefs</code>
+package. Then you can use it as if it were a built-in task.</p>
+
+<hr>
+<h2><a name="buildevents">Build Events</a></h2>
+<P>Ant is capable of generating build events as it performs the tasks necessary to build a project.
+Listeners can be attached to Ant to receive these events. This capability could be used, for example,
+to connect Ant to a GUI or to integrate Ant with an IDE.
+</P>
+<p>To use build events you need to create an ant <code>Project</code> object. You can then call the
+<code>addBuildListener</code> method to add your listener to the project. Your listener must implement
+the <code>org.apache.tools.antBuildListener</code> interface. The listener will receive BuildEvents
+for the following events</P>
+<ul>
+<li>Build started</li>
+<li>Build finished</li>
+<li>Target started</li>
+<li>Target finished</li>
+<li>Task started</li>
+<li>Task finished</li>
+<li>Message logged</li>
+</ul>
+
+<p>If the build file invokes another build file via <a
+href="CoreTasks/ant.html"><code>&lt;ant&gt;</code></a> or <a
+href="CoreTasks/subant.html"><code>&lt;subant&gt;</code></a> or uses <a
+href="CoreTasks/antcall.html"><code>&lt;antcall&gt;</code></a>, you are creating a
+new Ant "project" that will send target and task level events of its
+own but never sends build started/finished events.  Ant 1.6.2
+introduces an extension of the BuildListener interface named
+SubBuildListener that will receive two new events for</p>
+<ul>
+<li>SubBuild started</li>
+<li>SubBuild finished</li>
+</ul>
+<p>If you are interested in those events, all you need to do is to
+implement the new interface instead of BuildListener (and register the
+listener, of course).</p>
+
+<p>
+If you wish to attach a listener from the command line you may use the
+<code>-listener</code> option. For example:</p>
+<blockquote>
+  <pre>ant -listener org.apache.tools.ant.XmlLogger</pre>
+</blockquote>
+<p>will run Ant with a listener that generates an XML representation of the build progress. This
+listener is included with Ant, as is the default listener, which generates the logging to standard output.</p>
+
+<p><b>Note: </b>A listener must not access System.out and System.err directly since ouput on 
+these streams is redirected by Ant's core to the build event system. Accessing these 
+streams can cause an infinite loop in Ant. Depending on the version of Ant, this will
+either cause the build to terminate or the Java VM to run out of Stack space. A logger, also, may 
+not access System.out and System.err directly. It must use the streams with which it has
+been configured.
+</p>
+
+<hr>
+<h2><a name="integration">Source code integration</a></h2>
+
+The other way to extend Ant through Java is to make changes to existing tasks, which is positively encouraged.
+Both changes to the existing source and new tasks can be incorporated back into the Ant codebase, which
+benefits all users and spreads the maintenance load around.
+<p>
+
+Please consult the
+<a href="http://jakarta.apache.org/site/getinvolved.html">Getting Involved</a> pages on the Jakarta web site
+for details on how to fetch the latest source and how to submit changes for reincorporation into the
+source tree.
+<p>
+Ant also has some
+<a href="http://ant.apache.org/ant_task_guidelines.html">task guidelines</a>
+which provides some advice to people developing and testing tasks. Even if you intend to
+keep your tasks to yourself, you should still read this as it should be informative.
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/developlist.html b/trunk/docs/manual/developlist.html
new file mode 100644
index 0000000..1d8420e
--- /dev/null
+++ b/trunk/docs/manual/developlist.html
@@ -0,0 +1,47 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Developing with Ant</h3>
+
+<a href="../ant_in_anger.html">Ant in Anger</a><br/>
+<a href="../ant_task_guidelines.html">Ant Task Guidelines</a><br/>
+<a href="develop.html#writingowntask">Writing Your Own Task</a><br/>
+<a href="base_task_classes.html">Tasks Designed for Extension</a><br/>
+<a href="develop.html#buildevents">Build Events</a><br/>
+<a href="develop.html#integration">Source-code Integration</a><br/>
+<a href="inputhandler.html">InputHandler</a><br/>
+<a href="antexternal.html">Using Ant Tasks Outside of Ant</a><br/>
+
+<br/>Tutorials<br/>
+<a href="tutorial-HelloWorldWithAnt.html">Hello World with Ant</a><br/>
+<a href="tutorial-writing-tasks.html">Writing Tasks</a><br/>
+<a href="tutorial-tasks-filesets-properties.html">Tasks using Properties, Filesets &amp; Paths</a><br/>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/dirtasks.html b/trunk/docs/manual/dirtasks.html
new file mode 100644
index 0000000..84860ef
--- /dev/null
+++ b/trunk/docs/manual/dirtasks.html
@@ -0,0 +1,300 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Directory-based Tasks</title>
+</head>
+
+<body>
+
+<h2><a name="directorybasedtasks">Directory-based Tasks</a></h2>
+<p>Some tasks use directory trees for the actions they perform.
+For example, the <a href="CoreTasks/javac.html">javac</a> task, which
+compiles a directory tree with <code>.java</code> files into
+<code>.class</code> files, is one of these directory-based tasks. Because
+some of these tasks do so much work with a directory tree, the task itself
+can act as an implicit <a href="CoreTypes/fileset.html">FileSet</a>.</p>
+<p>Whether the fileset is implicit or not, it can often be very useful to
+work on a subset of the directory tree. This section describes how you can
+select a subset of such a directory tree when using one of these
+directory-based tasks.</p>
+<p>Ant gives you two ways to create a subset of files in a fileset, both of
+which can be used at the same time:</p>
+<ul>
+  <li>Only include files and directories that match any
+    <code>include</code> patterns and do not match any
+    <code>exclude</code> patterns in a given
+    <a href="CoreTypes/patternset.html">PatternSet</a>.</li>
+  <li>Select files based on selection criteria defined by a collection of
+    <a href="CoreTypes/selectors.html">selector</a> nested elements.</li>
+</ul>
+<h3><a name="patternset">Patternset</a></h3>
+
+<p>We said that Directory-based tasks can sometimes act as an implicit
+<a href="CoreTypes/fileset.html"><code>&lt;fileset&gt;</code></a>,
+but in addition to that, a FileSet acts as an implicit
+<a href="CoreTypes/patternset.html"><code>&lt;patternset&gt;</code></a>.</p>
+
+<p>The inclusion and exclusion elements of the implicit PatternSet can be
+specified inside the directory-based task (or explicit fileset) via
+either:</p>
+<ul>
+  <li>the attributes <code>includes</code> and
+    <code>excludes</code>.</li>
+  <li>nested elements <code>&lt;include&gt;</code> and
+    <code>&lt;exclude&gt;</code>.</li>
+  <li>external files specified with the attributes
+    <code>includesfile</code> and <code>excludesfile</code>.</li>
+  <li>external files specified with the nested elements
+    <code>&lt;includesfile&gt;</code> and <code>&lt;excludesfile&gt;</code>.
+  </li>
+</ul>
+<p>
+When dealing with an external file, each line of the file
+is taken as a pattern that is added to the list of include or exclude
+patterns.</p>
+
+<p>When both inclusion and exclusion are used, only files/directories that
+match at least one of the include patterns and don't match any of the
+exclude patterns are used. If no include pattern is given, all files
+are assumed to match the include pattern (with the possible exception of
+the default excludes).</p>
+
+<h4><a name="patterns">Patterns</a></h4>
+
+<p>As described earlier, patterns are used for the inclusion and exclusion
+of files. These patterns look very much like the patterns used in DOS and
+UNIX:</p>
+<p>'*' matches zero or more characters, '?' matches one character.</p>
+
+<p>In general, patterns are considered relative paths, relative to a
+task dependent base directory (the dir attribute in the case of
+<code>&lt;fileset&gt;</code>).  Only files found below that base
+directory are considered.  So while a pattern like
+<code>../foo.java</code> is possible, it will not match anything when
+applied since the base directory's parent is never scanned for
+files.</p>
+
+<p><b>Examples:</b></p>
+<p>
+<code>*.java</code>&nbsp;&nbsp;matches&nbsp;&nbsp;<code>.java</code>,
+<code>x.java</code> and <code>FooBar.java</code>, but
+not <code>FooBar.xml</code> (does not end with <code>.java</code>).</p>
+<p>
+<code>?.java</code>&nbsp;&nbsp;matches&nbsp;&nbsp;<code>x.java</code>,
+<code>A.java</code>, but not <code>.java</code> or <code>xyz.java</code>
+(both don't have one character before <code>.java</code>).</p>
+<p>
+Combinations of <code>*</code>'s and <code>?</code>'s are allowed.</p>
+<p>Matching is done per-directory. This means that first the first directory in
+the pattern is matched against the first directory in the path to match. Then
+the second directory is matched, and so on. For example, when we have the pattern
+<code>/?abc/*/*.java</code>
+and the path <code>/xabc/foobar/test.java</code>,
+the first <code>?abc</code> is matched with <code>xabc</code>,
+then <code>*</code> is matched with <code>foobar</code>,
+and finally <code>*.java</code> is matched with <code>test.java</code>.
+They all match, so the path matches the pattern.</p>
+<p>To make things a bit more flexible, we add one extra feature, which makes it
+possible to match multiple directory levels. This can be used to match a
+complete directory tree, or a file anywhere in the directory tree.
+To do this, <code>**</code>
+must be used as the name of a directory.
+When <code>**</code> is used as the name of a
+directory in the pattern, it matches zero or more directories.
+For example:
+<code>/test/**</code> matches all files/directories under <code>/test/</code>,
+such as <code>/test/x.java</code>,
+or <code>/test/foo/bar/xyz.html</code>, but not <code>/xyz.xml</code>.</p>
+<p>There is one &quot;shorthand&quot;: if a pattern ends
+with <code>/</code>
+or <code>\</code>, then <code>**</code>
+is appended.
+For example, <code>mypackage/test/</code> is interpreted as if it were
+<code>mypackage/test/**</code>.</p>
+<p><b>Example patterns:</b></p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><code>**/CVS/*</code></td>
+    <td valign="top">Matches all files in <code>CVS</code>
+      directories that can be located
+      anywhere in the directory tree.<br>
+      Matches:
+      <pre>
+      CVS/Repository
+      org/apache/CVS/Entries
+      org/apache/jakarta/tools/ant/CVS/Entries
+      </pre>
+      But not:
+      <pre>
+      org/apache/CVS/foo/bar/Entries (<code>foo/bar/</code>
+      part does not match)
+      </pre>
+    </td>
+  </tr>
+  <tr>
+    <td valign="top"><code>org/apache/jakarta/**</code></td>
+    <td valign="top">Matches all files in the <code>org/apache/jakarta</code>
+      directory tree.<br>
+      Matches:
+      <pre>
+      org/apache/jakarta/tools/ant/docs/index.html
+      org/apache/jakarta/test.xml
+      </pre>
+      But not:
+      <pre>
+      org/apache/xyz.java
+      </pre>
+      (<code>jakarta/</code> part is missing).</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>org/apache/**/CVS/*</code></td>
+    <td valign="top">Matches all files in <code>CVS</code> directories
+      that are located anywhere in the directory tree under
+      <code>org/apache</code>.<br>
+      Matches:
+      <pre>
+      org/apache/CVS/Entries
+      org/apache/jakarta/tools/ant/CVS/Entries
+      </pre>
+      But not:
+      <pre>
+      org/apache/CVS/foo/bar/Entries
+      </pre>
+      (<code>foo/bar/</code> part does not match)</td>
+  </tr>
+  <tr>
+    <td valign="top"><code>**/test/**</code></td>
+    <td valign="top">Matches all files that have a <code>test</code>
+        element in their path, including <code>test</code> as a filename.</td>
+  </tr>
+</table>
+<p>When these patterns are used in inclusion and exclusion, you have a powerful
+way to select just the files you want.</p>
+
+<h3><a name="selectors">Selectors</a></h3>
+<p>The <a href="CoreTypes/fileset.html"><code>&lt;fileset&gt;</code></a>,
+whether implicit or explicit in the
+directory-based task, also acts as an
+<a href="CoreTypes/selectors.html#andselect"><code>&lt;and&gt;</code></a>
+selector container. This can be used to create arbitrarily complicated
+selection criteria for the files the task should work with. See the
+<a href="CoreTypes/selectors.html">Selector</a> documentation for more
+information.</p>
+
+<h3><a name="tasklist">Standard Tasks/Filesets</a></h3>
+<p>Many of the standard tasks in ant take one or more filesets which follow
+the rules given here. This list, a subset of those, is a list of standard ant
+tasks that can act as an implicit fileset:</p>
+<ul>
+      <li><a href="CoreTasks/checksum.html"><code>&lt;checksum&gt;</code></a></li>
+  <li><a href="CoreTasks/copydir.html"><code>&lt;copydir&gt;</code></a> (deprecated)</li>
+  <li><a href="CoreTasks/delete.html"><code>&lt;delete&gt;</code></a></li>
+  <li><a href="CoreTasks/dependset.html"><code>&lt;dependset&gt;</code></a></li>
+  <li><a href="CoreTasks/fixcrlf.html"><code>&lt;fixcrlf&gt;</code></a></li>
+  <li><a href="CoreTasks/javac.html"><code>&lt;javac&gt;</code></a></li>
+  <li><a href="CoreTasks/replace.html"><code>&lt;replace&gt;</code></a></li>
+  <li><a href="CoreTasks/rmic.html"><code>&lt;rmic&gt;</code></a></li>
+  <li><a href="CoreTasks/style.html"><code>&lt;style&gt;</code> (aka <code>&lt;xslt&gt;</code>)</a></li>
+  <li><a href="CoreTasks/tar.html"><code>&lt;tar&gt;</code></a></li>
+  <li><a href="CoreTasks/zip.html"><code>&lt;zip&gt;</code></a></li>
+  <li><a href="OptionalTasks/ejb.html#ddcreator"><code>&lt;ddcreator&gt;</code></a></li>
+  <li><a href="OptionalTasks/ejb.html#ejbjar"><code>&lt;ejbjar&gt;</code></a></li>
+  <li><a href="OptionalTasks/ejb.html#ejbc"><code>&lt;ejbc&gt;</code></a></li>
+  <li><a href="OptionalTasks/cab.html"><code>&lt;cab&gt;</code></a></li>
+  <li><a href="OptionalTasks/native2ascii.html"><code>&lt;native2ascii&gt;</code></a></li>
+  <li><a href="OptionalTasks/netrexxc.html"><code>&lt;netrexxc&gt;</code></a></li>
+  <li>
+    <a href="OptionalTasks/renameextensions.html"><code>&lt;renameextensions&gt;</code></a>
+  </li>
+  <li><a href="OptionalTasks/depend.html"><code>&lt;depend&gt;</code></a></li>
+  <li><a href="OptionalTasks/dotnet.html"><code>&lt;ilasm&gt;</code></a></li>
+  <li><a href="OptionalTasks/dotnet.html"><code>&lt;csc&gt;</code></a></li>
+  <li><a href="OptionalTasks/dotnet.html"><code>&lt;vbc&gt;</code></a></li>
+  <li><a href="OptionalTasks/translate.html"><code>&lt;translate&gt;</code></a></li>
+  <li><a href="OptionalTasks/image.html"><code>&lt;image&gt;</code></a></li>
+  <li><a href="OptionalTasks/jlink.html"><code>&lt;jlink&gt;</code></a> (deprecated)</li>
+  <li><a href="OptionalTasks/jspc.html"><code>&lt;jspc&gt;</code></a></li>
+  <li><a href="OptionalTasks/wljspc.html"><code>&lt;wljspc&gt;</code></a></li>
+</ul>
+
+<h3><a name="examples">Examples</a></h3>
+<pre>
+&lt;copy todir=&quot;${dist}&quot;&gt;
+  &lt;fileset dir=&quot;${src}&quot;
+           includes=&quot;**/images/*&quot;
+           excludes=&quot;**/*.gif&quot;
+  /&gt;
+&lt;/copy&gt;</pre>
+<p>This copies all files in directories called <code>images</code> that are
+located in the directory tree defined by <code>${src}</code> to the
+destination directory defined by <code>${dist}</code>,
+but excludes all <code>*.gif</code> files from the copy.</p>
+<pre>
+&lt;copy todir=&quot;${dist}&quot;&gt;
+  &lt;fileset dir=&quot;${src}&quot;&gt;
+    &lt;include name=&quot;**/images/*&quot;/&gt;
+    &lt;exclude name=&quot;**/*.gif&quot;/&gt;
+  &lt;/fileset&gt;
+&lt;/copy&gt;
+</pre>
+<p> The same as the example above, but expressed using nested elements.</p>
+
+<pre>
+&lt;delete dir=&quot;${dist}&quot;&gt;
+    &lt;include name=&quot;**/images/*&quot;/&gt;
+    &lt;exclude name=&quot;**/*.gif&quot;/&gt;
+&lt;/delete&gt;
+</pre>
+<p>Deleting the original set of files, the <code>delete</code> task can act
+as an implicit fileset.</p>
+
+<h3><a name="defaultexcludes">Default Excludes</a></h3>
+<p>There are a set of definitions that are excluded by default from all
+directory-based tasks. They are:</p>
+<pre>
+     **/*~
+     **/#*#
+     **/.#*
+     **/%*%
+     **/._*
+     **/CVS
+     **/CVS/**
+     **/.cvsignore
+     **/SCCS
+     **/SCCS/**
+     **/vssver.scc
+     **/.svn
+     **/.svn/**
+     **/.DS_Store
+</pre>
+<p>If you do not want these default excludes applied, you may disable
+them with the <code>defaultexcludes=&quot;no&quot;</code>
+attribute.</p>
+
+<p>This is the default list; note that you can modify the list of
+default excludes by using the <a
+href="CoreTasks/defaultexcludes.html">defaultexcludes</a> task.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/favicon.ico b/trunk/docs/manual/favicon.ico
new file mode 100644
index 0000000..9dbc258
--- /dev/null
+++ b/trunk/docs/manual/favicon.ico
Binary files differ
diff --git a/trunk/docs/manual/feedback.html b/trunk/docs/manual/feedback.html
new file mode 100644
index 0000000..2e2c191
--- /dev/null
+++ b/trunk/docs/manual/feedback.html
@@ -0,0 +1,72 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Apache Ant User Manual - Feedback</title>
+</head>
+
+<body>
+
+<h1><a name="feedback">Feedback</a> and Troubleshooting</h1>
+<p>If things do not work, especially simple things like <tt>ant -version</tt>, 
+  then something is wrong with your configuration. Before filing bug reports and 
+  emailing all the ant mailing lists</p>
+<ol>
+  <li>Check your environment variables. Are ANT_HOME and JAVA_HOME correct? If 
+    they have quotes or trailing slashes, remove them.</li>
+  <li>Unset CLASSPATH; if that is wrong things go horribly wrong. Ant does not 
+    need the CLASSPATH variable defined to anything to work.</li>
+  <li>Make sure there are no versions of crimson.jar or other XML parsers in JRE/ext</li>
+  <li>Is your path correct? is Ant on it? What about JDK/bin? have you tested 
+    this? If you are using Jikes, is it on the path? A createProcess error (especially 
+    with ID=2 on windows) usually means executable not found on the path.</li>
+  <li>Which version of ant are you running? Other applications distribute a copy 
+    -it may be being picked up by accident.</li>
+  <li>If a task is failing to run is optional.jar in ANT_HOME/lib? Are there any 
+    libraries which it depends on missing?</li>
+  <li>If a task doesn't do what you expect, run <tt>ant -verbose</tt> or <tt>ant 
+    -debug</tt> to see what is happening</li>
+</ol>
+<p>If you can't fix your problem, start with the <a href="http://ant.apache.org/mail.html" target="_top">Ant 
+  User Mailing List</a> . These are other ant users who will help you learn to 
+  use ant. If they cannot fix it then someone may suggest filing a bug report, 
+  which will escalate the issue. Remember of course, that support, like all open 
+  source development tasks, is voluntary. If you haven't invested time in helping 
+  yourself by following the steps above, it is unlikely that anyone will invest 
+  the time in helping you. </p>
+<p>Also, if you don't understand something, the <a href="http://ant.apache.org/mail.html" target="_top">Ant 
+  User Mailing List</a> is the place to ask questions. Not the developer list, 
+  nor the individuals whose names appears in the source and documentation. If 
+  they answered all such emails, nobody would have any time to improve ant. </p>
+<p>To provide feedback on this software, please subscribe to the <a href="http://ant.apache.org/mail.html" target="_top">Ant 
+  User Mailing List</a> </p>
+
+<p>If you want to contribute to Ant or stay current with the latest
+development, join the
+<a href="http://ant.apache.org/mail.html" target="_top">Ant Development Mailing List</a>
+</p>
+<p>A searchable archive can be found at <a
+href="http://marc.theaimsgroup.com" target="_top">http://marc.theaimsgroup.com</a>.
+Other archives will be documented online at  <a href="http://ant.apache.org/mail.html#Archives" target="_top">Mailing Lists Archives</a> </p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/ide.html b/trunk/docs/manual/ide.html
new file mode 100644
index 0000000..cf13645
--- /dev/null
+++ b/trunk/docs/manual/ide.html
@@ -0,0 +1,105 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>IDE Integration</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>IDE Integration</h3>
+<p>
+All the modern Java IDEs support Ant almost out of the box.
+</p>
+
+<ul>
+  <li>
+    <a href="http://antrunner.sourceforge.net/">
+      AntRunner For JBuilder (unbundled)
+    </a>
+  </li>
+  <li>
+    <a href="Integration/jext-plugin.html">
+      AntWork Plugin for the Jext Java Text Editor (unbundled)
+    </a>
+  </li>
+  <li>
+    <a href="http://jdee.sunsite.dk/">
+      JDEE (Java Development Environment for Emacs)
+    </a> has built-in text ANT integration: selection of target through text
+    field, execution, hyperlink to compilation errors. Installation: built-in
+    JDEE 2.2.8 or later. Configuration: through customize menu
+    "Jde Build Function"
+  </li>
+  <li>
+    <a href="http://www.intellij.com/idea/">
+      IDEA
+    </a> has built-in GUI ANT integration: GUI selection of targets, execution,
+    hyperlink to compilation errors
+  </li>
+  <li>
+    <a href="http://ant.netbeans.org/">
+      NetBeans
+    </a>
+    NetBeans IDE uses Ant as the basis for its project system starting with the 4.0 release.
+  </li>
+  <li>
+    <a href="http://jedit.org/">
+      jEdit
+    </a>
+    jEdit is an open source java IDE with some great plugins for Java dev, a
+    good XML editor and the Antfarm plugin to execute targets in a build
+    file.
+  </li>
+  <li>
+    <a href="http://eclipse.org/">
+      Eclipse
+    </a>
+    Eclipse is IBM's counterpoint to NetBeans; an open source IDE with
+    Java and Ant support.
+  </li>
+  <li>
+    <a href="Integration/VAJAntTool.html">
+      VisualAge for Java</a>
+  </li>
+  <li>
+    <a href="http://www7b.software.ibm.com/wsdd/library/techarticles/0203_searle/searle1.html">
+      WebSphere Studio Application Developer
+    </a>
+  </li>
+  <li>
+    <a href="http://www.borland.com/jbuilder/pdf/jb9_feamatrix.pdf">
+      JBuilder 9 Personal
+    </a>
+    JBuilder supports Ant with the following features. Add Ant nodes to
+    projects and execute Ant targets from within JBuilder. Add custom Ant-based
+    build tasks with custom Ant libraries to run Ant from within JBuilder.
+    Rapid navigation from Ant build error messages to source files.
+    Customize build menu and toolbar with custom build targets.
+  </li>
+</ul>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/index.html b/trunk/docs/manual/index.html
new file mode 100644
index 0000000..f056e61
--- /dev/null
+++ b/trunk/docs/manual/index.html
@@ -0,0 +1,34 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Apache Ant User Manual</title>
+</head>
+
+<frameset cols="26%,74%">
+<frame src="toc.html" name="navFrame">
+<frame src="cover.html" name="mainFrame">
+</frameset>
+<noframes>
+<H2>Apache Ant User Manual</H2>
+
+<a href="toc.html">Apache Ant User Manual</a></noframes>
+
+</html>
diff --git a/trunk/docs/manual/inputhandler.html b/trunk/docs/manual/inputhandler.html
new file mode 100644
index 0000000..d334934
--- /dev/null
+++ b/trunk/docs/manual/inputhandler.html
@@ -0,0 +1,110 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>InputHandler</title>
+</head>
+
+<body>
+<h1>InputHandler</h1>
+
+<h2>Overview</h2>
+
+<p>When a task wants to prompt a user for input, it doesn't simply
+read the input from the console as this would make it impossible to
+embed Ant in an IDE.  Instead it asks an implementation of the
+<code>org.apache.tools.ant.input.InputHandler</code> interface to
+prompt the user and hand the user input back to the task.</p>
+
+<p>To do this, the task creates an <code>InputRequest</code> object
+and passes it to the <code>InputHandler</code> Such an
+<code>InputRequest</code> may know whether a given user input is valid
+and the <code>InputHandler</code> is supposed to reject all invalid
+input.</p>
+
+<p>Exactly one <code>InputHandler</code> instance is associated with
+every Ant process, users can specify the implementation using the
+<code>-inputhandler</code> command line switch.</p>
+
+<h2>InputHandler</h2>
+
+<p>The <code>InputHandler</code> interface contains exactly one
+method</p>
+
+<pre>
+    void handleInput(InputRequest request) 
+        throws org.apache.tools.ant.BuildException;
+</pre>
+
+<p>with some pre- and postconditions.  The main postcondition is that
+this method must not return unless the <code>request</code> considers
+the user input valid, it is allowed to throw an exception in this
+situation.</p>
+
+<p>Ant comes with three built-in implementations of this interface:</p>
+
+<h3><a name="defaulthandler">DefaultInputHandler</a></h3>
+
+<p>This is the implementation you get, when you don't use the
+<code>-inputhandler</code> command line switch at all.  This
+implementation will print the prompt encapsulated in the
+<code>request</code> object to Ant's logging system and re-prompt for
+input until the user enters something that is considered valid input
+by the <code>request</code> object.  Input will be read from the
+console and the user will need to press the Return key.</p>
+
+<h3>PropertyFileInputHandler</h3>
+
+<p>This implementation is useful if you want to run unattended build
+processes.  It reads all input from a properties file and makes the
+build fail if it cannot find valid input in this file.  The name of
+the properties file must be specified in the Java system property
+<code>ant.input.properties</code>.</p>
+
+<p>The prompt encapsulated in a <code>request</code> will be used as
+the key when looking up the input inside the properties file.  If no
+input can be found, the input is considered invalid and an exception
+will be thrown.</p>
+
+<p><strong>Note</strong> that <code>ant.input.properties</code> must
+be a Java system property, not an Ant property.  I.e. you cannot
+define it as a simple parameter to <code>ant</code>, but you can
+define it inside the <code>ANT_OPTS</code> environment variable.</p>
+
+<h3>GreedyInputHandler</h3>
+
+<p>Like the default implementation, this InputHandler reads from standard
+input. However, it consumes <i>all</i> available input. This behavior is
+useful for sending Ant input via an OS pipe. <b>Since Ant 1.7</b>.</p>
+
+<h2>InputRequest</h2>
+
+<p>Instances of <code>org.apache.tools.ant.input.InputRequest</code>
+encapsulate the information necessary to ask a user for input and
+validate this input.</p>
+
+<p>The instances of <code>InputRequest</code> itself will accept any
+input, but subclasses may use stricter validations.
+<code>org.apache.tools.ant.input.MultipleChoiceInputRequest</code>
+should be used if the user input must be part of a predefined set of
+choices.</p>
+
+
+</html>
diff --git a/trunk/docs/manual/install.html b/trunk/docs/manual/install.html
new file mode 100644
index 0000000..e2fb287
--- /dev/null
+++ b/trunk/docs/manual/install.html
@@ -0,0 +1,982 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Installing Ant</title>
+</head>
+
+<body>
+<h1>Installing Ant</h1>
+<h2><a name="getting">Getting Ant</a></h2>
+
+<h3>Download Area Layout</h3>
+<table>
+<tr>
+  <th>Filename or Path</th>
+  <th>Description</th>
+</tr>
+<tr>
+  <td>KEYS</td>
+  <td>PGP-Keysfile. It contains the PGP-keys of Ant developers so you can 'trust' the distribution. </td>
+</tr>
+<tr>
+  <td>RELEASE-NOTES-{version}.html</td>
+  <td>
+    Release notes of the given version in HTML format. When upgrading your Ant installation you
+    should have a look at the <i>Changes that could break older environments</i> section.
+  </td>
+</tr>
+<tr>
+  <td>ant-current-bin.zip</td>
+  <td>
+    ZIP-Archive containing the compiled version of Ant in the last released version. This is the file
+    most users will want to download.
+  </td>
+</tr>
+<tr>
+  <td>ant-current-src.zip</td>
+  <td>
+    ZIP-Archive containing the sources of Ant. If you have this you could compile Ant itself.
+    If you do not have the <i>required</i> dependencies, the classes depeding on them are just not
+    build.
+  </td>
+</tr>
+<tr>
+  <td>ant-current-*.asc</td>
+  <td>
+    Security file for checking the correctness of the zip file. This one is the
+    <a href="http://en.wikipedia.org/wiki/Pretty_Good_Privacy" target="_blank">PGP</a> key.
+  </td>
+</tr>
+<tr>
+  <td>ant-current-*.md5</td>
+  <td>
+    Security file for checking the correctness of the zip file. This one is the
+    <a href="http://en.wikipedia.org/wiki/Md5" target="_blank">MD5</a> key.
+  </td>
+</tr>
+<tr>
+  <td>ant-current-*.sha1</td>
+  <td>
+    Security file for checking the correctness of the zip file. This one is the
+    <a href="http://en.wikipedia.org/wiki/SHA-1" target="_blank">SHA1</a> key.
+  </td>
+</tr>
+<tr>
+  <td>antlibs/</td>
+  <td>
+    This directory holds the Antlibs that are made of available by the Apache Ant project.
+    Antlibs are bundles of Ant tasks that are not delivered as part of the Ant core but are
+    available as optional downloads.
+  </td>
+</tr>
+<tr>
+  <td>binaries/</td>
+  <td>
+    The binaries directory holds specific Ant releases bundled in both ZIP and tar.gz compression
+    formats. The named releases are in contrast to the ant-current-bin.zip file in the parent 
+    directory, which is always guaranteed to be the most current release of Ant.
+  </td>
+</tr>
+<tr>
+  <td>common/</td>
+  <td>
+    The common directory holds various files, such as the Apache License file that Ant is licensed
+    under, that people may wish to examine without having to download the whole Ant distribution.
+  </td>
+</tr>
+<tr>
+  <td>source/</td>
+  <td>
+    The source directory holds the source code for specific Ant releases bundled in both ZIP and 
+    tar.gz compression formats. The named releases are in contrast to the ant-current-src.zip file
+    in the parent directory, which is always guaranteed to hold the source code for the most current 
+    release of Ant.
+  </td>
+</tr>
+</table>
+
+<h3>Binary Edition</h3>
+<p>The latest stable version of Ant is available from the Ant web page <a
+href="http://ant.apache.org/" target="_top">http://ant.apache.org/</a>.
+
+<h3>As a binary in an RPM Package</h3>
+
+<p>Consult the <a href="#jpackage">jpackage</a> section below.</p>
+
+<h3>Bundled in IDEs</h3>
+<p>
+    All the main Java IDEs ship with Ant, products such as Eclipse, NetBeans
+    and IntelliJ IDEA. If you install Ant this way you usually get the most recent
+    release of Ant at the time the IDE was released. Some of the IDEs (Eclipse
+    and NetBeans in particular) ship with extra tasks that only work if
+    IDE-specific tools are on Ant's path. To use these on command-line versions
+    of Ant, the relevant JARs need to be added to the command-line Ant as
+    extra libraries/tasks. Note that if it is an IDE task or extension that is
+    not behaving, the Ant team is unable to field bug reports. Try the IDE mailing
+    lists first, who will cross-file bugs if appropriate.
+</p>
+<p>
+    IDE's can invariably be pointed at different Ant installations. This lets
+    developers upgrade to a new release of Ant, and eliminate inconsistencies
+    between command-line and IDE Ant.
+</p>
+
+<h3>Bundled in Java applications</h3>
+
+<p>
+    Many Java applications, most particularly application servers, ship with
+    a version of Ant. These are primarily for internal use by the application,
+    using the Java APIs to delegate tasks such as JSP page compilation to the Ant
+    runtime. Such distributions are usually unsupported by everyone. Particularly
+    troublesome are those products that non only ship with their own Ant release,
+    they add their own version of ANT.BAT or ant.sh to the PATH. If Ant starts
+    behaving wierdly after installing something, try the
+    <a href="#diagnostics">diagnostics</a> advice.
+</p>
+
+<h3>Source Edition</h3>
+
+<p>If you prefer the source edition, you can download the source for the latest
+Ant release from
+<a href="http://ant.apache.org/srcdownload.cgi" target="_top">http://ant.apache.org/srcdownload.cgi</a>.
+
+If you prefer the leading-edge code, you can access
+the code as it is being developed via SVN. The Ant website has details on
+<a href="http://ant.apache.org/svn.html" target="_top">accessing SVN</a>.
+All bug fixes will go in against the HEAD of the source tree, and the first
+response to many bugreps will be "have you tried the latest version".
+Don't be afraid to download and build a prererelease edition, as everything
+other than new features are usually stable.
+    </p>
+<p>
+
+
+See the section <a href="#buildingant">Building Ant</a> on how to
+build Ant from the source code.
+You can also access the
+<a href="http://svn.apache.org/viewcvs.cgi/ant/" target="_top">
+Ant SVN repository</a> on-line. </p>
+
+<hr>
+<h2><a name="sysrequirements">System Requirements</a></h2>
+Ant has been used successfully on many platforms, including Linux,
+commercial flavours of Unix such as Solaris and HP-UX,
+Windows NT-platforms, OS/2 Warp, Novell Netware 6, OpenVMS and MacOS X.
+The platforms used most for development are, in no particular order,
+Linux, MacOS X, Windows XP and Unix; these are therefore that platforms
+that tend to work best. As of Ant1.7, Windows 9x is no longer supported.
+<p>
+To build and use Ant, you must have a JAXP-compliant XML parser installed and
+available on your classpath, such as Xerces.</p>
+<p>
+The binary distribution of Ant includes the latest version of the
+<a href="http://xml.apache.org/xerces2-j/index.html" target="_top">Apache Xerces2</a> XML parser.
+Please see
+<a href="http://java.sun.com/xml/" target="_top">http://java.sun.com/xml/</a>
+for more information about JAXP.
+If you wish to use a different JAXP-compliant parser, you should remove
+<code>xercesImpl.jar</code> and <code>xml-apis.jar</code>
+from Ant's <code>lib</code> directory.
+<p>
+You can then either put the JARs of your preferred parser into Ant's
+<code>lib</code> directory or put the jars on the system classpath.
+Some parts of Ant will fail if you use an old parser, especially one
+that is not namespace-aware. In particular, avoid the Crimson parser.</p>
+
+<p>Tip: "ant -diagnostics" will list the XML parser used and its location.</p>
+
+<p>
+For the current version of Ant, you will also need a JDK installed on
+your system, version 1.2 or later required, 1.5 or later strongly recommended.
+The later the version of Java , the more Ant tasks you get.
+</p>
+<p>
+<strong>Note #2: </strong>If a JDK is not present, only the JRE runtime, then many tasks will not work.
+</p>
+
+<h3>Open Source Java Runtimes</h3>
+<p>
+    The Ant team strongly supports users running Ant on Kaffe and other
+    open source Java runtimes, and so strives to have a product that works
+    well on those platforms. What appears to work well is Kaffe with
+    Gnu Classpath and the Xerces and Xalan libraries.
+</p>
+
+<hr>
+<h2><a name="installing">Installing Ant</a></h2>
+<p>The binary distribution of Ant consists of the following directory layout:
+<pre>
+  ant
+   +--- README, LICENSE, fetch.xml, other text files. //basic information
+   +--- bin  // contains launcher scripts
+   |
+   +--- lib  // contains Ant jars plus necessary dependencies
+   |
+   +--- docs // contains documentation
+   |      |
+   |      +--- images  // various logos for html documentation
+   |      |
+   |      +--- manual  // Ant documentation (a must read ;-)
+   |
+   +--- etc // contains xsl goodies to:
+            //   - create an enhanced report from xml output of various tasks.
+            //   - migrate your build files and get rid of 'deprecated' warning
+            //   - ... and more ;-)
+</pre>
+
+Only the <code>bin</code> and <code>lib</code> directories are
+required to run Ant.
+
+To install Ant, choose a directory and copy the distribution
+files there. This directory will be known as ANT_HOME.
+</p>
+
+<table width="80%">
+<tr>
+  <td colspan="2">
+    <b>Windows 95, Windows 98 &amp; Windows ME Note:</b>
+  </td>
+</tr>
+<tr>
+  <td width="5%">&nbsp;</td>
+  <td><i>
+On these systems, the script used to launch Ant will have
+problems if ANT_HOME is a long filename (i.e. a filename which is not
+of the format known as &quot;8.3&quot;). This is due to
+limitations in the OS's handling of the <code>&quot;for&quot;</code>
+batch-file statement. It is recommended, therefore, that Ant be
+installed in a <b>short</b>, 8.3 path, such as C:\Ant. </i>
+  </td>
+</tr>
+<tr>
+  <td width="5%">&nbsp;</td>
+  <td>
+    <p>On these systems you will also need to configure more environment
+       space to cater for the environment variables used in the Ant lauch script.
+       To do this, you will need to add or update the following line in
+       the <code>config.sys</code> file
+    </p>
+    <p><code>shell=c:\command.com c:\ /p /e:32768</code></p>
+  </td>
+</tr>
+</table>
+
+<h3>Setup</h3>
+<p>
+Before you can run Ant there is some additional set up you
+will need to do unless you are installing the <a href="#jpackage">RPM
+version from jpackage.org</a>:</p>
+<ul>
+<li>Add the <code>bin</code> directory to your path.</li>
+<li>Set the <code>ANT_HOME</code> environment variable to the
+directory where you installed Ant.  On some operating systems, Ant's
+startup scripts can guess <code>ANT_HOME</code> (Unix dialects and
+Windows NT/2000), but it is better to not rely on this behavior.</li>
+<li>Optionally, set the <code>JAVA_HOME</code> environment variable
+(see the <a href="#advanced">Advanced</a> section below).
+This should be set to the directory where your JDK is installed.</li>
+</ul>
+<p><strong>Note:</strong> Do not install Ant's ant.jar file into the lib/ext
+directory of the JDK/JRE. Ant is an application, whilst the extension
+directory is intended for JDK extensions. In particular there are security
+restrictions on the classes which may be loaded by an extension.</p>
+
+<table width="80%">
+<tr>
+  <td colspan="2">
+    <b>Windows Note:</b>
+  </td>
+</tr>
+<tr>
+  <td width="5%">&nbsp;</td>
+  <td>
+    The ant.bat script makes use of three environment variables -
+    ANT_HOME, CLASSPATH and JAVA_HOME. <b>Ensure</b> that ANT_HOME and JAVA_HOME variables are set, 
+    and that they do <b><u>not</u></b> have quotes (either
+    ' or &quot;) and they do <b><u>not</u></b> end with \ or with /. CLASSPATH should be unset or 
+    empty.
+  </td>
+</tr>
+</table>
+
+<h3><a name="checkInstallation">Check Installation</a></h3>
+<p>You can check the basic installation with opening a new shell and typing <tt>ant</tt>. You
+should get a message like this
+<pre>
+Buildfile: build.xml does not exist!
+Build failed
+</pre>
+So Ant works. This message is there because you need to write an individual buildfile for your 
+project. With a <tt>ant -version</tt> you should get an output like
+<pre>
+Apache Ant version 1.7.0 compiled on December 13 2006
+</pre> 
+
+
+</p>
+
+<h3><a name="optionalTasks">Optional Tasks</a></h3>
+<p>Ant supports a number of optional tasks. An optional task is a task which
+typically requires an external library to function. The optional tasks are
+packaged together with the core Ant tasks.</p>
+
+<p>The external libraries required by each of the optional tasks is detailed
+in the <a href="#librarydependencies">Library Dependencies</a> section. These external
+libraries must be added to Ant's classpath, in any of the following ways:
+</p>
+<ul>
+    <li><p>
+        In <code><i>ANT_HOME</i>/lib</code>. This makes the JAR files available to all
+        Ant users and builds.
+    </p></li>
+
+    <li><p>
+        In <code>${user.home}/.ant/lib</code> (as of Ant 1.6). This
+        allows different users to add new libraries to Ant. All JAR files
+        added to this directory are available to command-line Ant.
+    </p></li>
+
+    <li><p>
+        On the command line with a <code>-lib</code> parameter. This lets
+        you add new JAR files on a case-by-case basis.
+    </p></li>
+
+    <li><p>
+        In the <code>CLASSPATH</code> environment variable. Avoid this; it makes
+        the JAR files visible to <i>all</i> Java applications, and causes
+        no end of support calls. See <a href="#classpath">below</a> for details.
+        </p>
+    </li>
+
+    <li><p>
+        In some <code>&lt;classpath&gt;</code> accepted by the task itself.
+        For example, as of Ant 1.7.0 you can run the <code>&lt;junit&gt;</code>
+        task without <code>junit.jar</code> in Ant's own classpath, so long as
+        it is included (along with your program and tests) in the classpath
+        passed when running the task.
+        </p><p>
+        Where possible, this option is generally
+        to be preferred, as the Ant script itself can determine the best path
+        to load the library from: via relative path from the basedir (if you
+        keep the library under version control with your project), according
+        to Ant properties, environment variables, Ivy downloads, whatever you like.
+    </p></li>
+
+</ul>
+
+<p>
+    IDEs have different ways of adding external JAR files and third-party tasks
+    to Ant. Usually it is done by some configuration dialog. Sometimes JAR files
+    added to a project are automatically added to ant's classpath.
+</p>
+
+<h3><a name="classpath">The <code>CLASSPATH</code> environment variable</a></h3>
+<p>
+
+The <code>CLASSPATH</code> environment variable is a source of many Ant support queries. As
+the round trip time for diagnosis on the Ant user mailing list can be slow, and
+because filing bug reports complaining about 'ant.bat' not working will be
+rejected by the developers as WORKSFORME "this is a configuration problem, not a
+bug", you can save yourself a lot of time and frustration by following some
+simple steps.
+
+</p>
+<ol>
+
+<li>Do not ever set <code>CLASSPATH</code>. Ant does not need it, it only causes confusion
+and breaks things.
+
+</li>
+
+<li>If you ignore the previous rule, do not ever, ever, put quotes in the
+<code>CLASSPATH</code>, even if there is a space in a directory. This will break Ant, and it
+is not needed. </li>
+
+<li>If you ignore the first rule, do not ever, ever, have a trailing backslash
+in a <code>CLASSPATH</code>, as it breaks Ant's ability to quote the string. Again, this is
+not needed for the correct operation of the <code>CLASSPATH</code> environment variable, even
+if a DOS directory is to be added to the path. </li>
+
+<li>You can stop Ant using the <code>CLASSPATH</code> environment variable by setting the
+<code>-noclasspath</code> option on the command line. This is an easy way
+to test for classpath-related problems.</li>
+
+</ol>
+
+<p>
+
+The usual symptom of <code>CLASSPATH</code> problems is that ant will not run with some error
+about not being able to find <code>org.apache.tools.ant.launch.Launcher</code>, or, if you have got the
+quotes/backslashes wrong, some very weird Java startup error. To see if this is
+the case, run <code>ant -noclasspath</code> or unset the <code>CLASSPATH</code> environment
+variable.
+
+</p>
+
+<p>
+You can also make your Ant script reject this environment
+variable just by placing the following at the top of the script (or in an init target):
+</p>
+<pre>
+&lt;property environment="env."/&gt;
+&lt;property name="env.CLASSPATH" value=""/&gt;
+&lt;fail message="Unset $CLASSPATH / %CLASSPATH% before running Ant!"&gt;
+    &lt;condition&gt;
+        &lt;not&gt;
+            &lt;equals arg1="${env.CLASSPATH}" arg2=""/&gt;
+        &lt;/not&gt;
+    &lt;/condition&gt;
+&lt;/fail&gt;
+</pre>
+
+<h3><a name="proxy">Proxy Configuration</a></h3>
+
+<p> Many Ant built-in and third-party tasks use network connections to retrieve
+files from HTTP servers. If you are behind a firewall with a proxy server, then
+Ant needs to be configured with the proxy. Here are the different ways to do
+this. </p>
+
+<ul>
+
+<li><b>With Java1.5</b><br>
+
+When you run Ant on Java1.5, you could try to use the automatic proxy setup
+mechanism with <code>-autoproxy</code>. 
+
+</li>
+
+<li><b>With explicit JVM properties.</b><br>
+
+These are documented <a
+href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html" target="_top">by Sun</a>,
+and control the proxy behaviour of the entire JVM. To set them in Ant, declare
+them in the <code>ANT_OPTS</code> environment variable. This is the best option
+for a non-mobile system. For a laptop, you have to change these settings as you
+roam.
+
+</li>
+
+<li><b>In the build file itself</b><br>
+
+If you are writing an build file that is always to be used behind the firewall,
+the &lt;setproxy&gt; task lets you configure the proxy (which it does by setting
+the JVM properties). If you do this, we strongly recommend using ant properties
+to define the proxy host, port, etc, so that individuals can override the
+defaults.</li>
+
+</ul>
+
+<p> The Ant team acknowledges that this is unsatisfactory. Until the JVM
+automatic proxy setup works properly everywhere, explicit JVM options via
+ANT_ARGS are probably the best solution. Setting properties on Ant's
+command line do not work, because those are <i>Ant properties</i> being set, not
+JVM options. This means the following does not set up the command line:
+
+</p>
+
+<pre>ant -Dhttp.proxyHost=proxy -Dhttp.proxyPort=81</pre>
+
+<p> All it does is set up two Ant properties.</p>
+
+<p>One other troublespot with
+proxies is with authenticating proxies. Ant cannot go beyond what the JVM does
+here, and as it is very hard to remotely diagnose, test and fix proxy-related
+problems, users who work behind a secure proxy will have to spend much time
+configuring the JVM properties until they are happy. </p>
+
+
+<h3><a name="windows">Windows and OS/2</a></h3>
+<p>Assume Ant is installed in <code>c:\ant\</code>. The following sets up the
+environment:</p>
+<pre>set ANT_HOME=c:\ant
+set JAVA_HOME=c:\jdk-1.5.0.05
+set PATH=%PATH%;%ANT_HOME%\bin</pre>
+
+<h3>Linux/Unix (bash)</h3>
+<p>Assume Ant is installed in <code>/usr/local/ant</code>. The following sets up
+the environment:</p>
+<pre>export ANT_HOME=/usr/local/ant
+export JAVA_HOME=/usr/local/jdk-1.5.0.05
+export PATH=${PATH}:${ANT_HOME}/bin</pre>
+
+<h3>Linux/Unix (csh)</h3>
+<pre>setenv ANT_HOME /usr/local/ant
+setenv JAVA_HOME /usr/local/jdk/jdk-1.5.0.05
+set path=( $path $ANT_HOME/bin )</pre>
+
+<p>
+Having a symbolic link set up to point to the JVM/JSK version makes updates more seamless. </p>
+<a name="jpackage"></a>
+<h3>RPM version from jpackage.org</h3>
+<p>
+The <a href="http://www.jpackage.org" target="_top">JPackage project</a> distributes an RPM version of Ant.
+With this version, it is not necessary to set <code> JAVA_HOME </code>or
+<code> ANT_HOME </code>environment variables and the RPM installer will correctly
+place the Ant executable on your path.
+</p>
+  <p>
+    <b>NOTE:</b> <em>Since Ant 1.7.0</em>, if the <code>ANT_HOME</code>
+    environment variable is set, the jpackage distribution will be
+    ignored.
+  </p>
+  <p>
+Optional jars for the JPackage version are handled in two ways.  The easiest, and
+best way is to get these external libraries from JPackage if JPackage has them
+available.  (Note: for each such library, you will have to get both the external
+package itself (e.g. <code>oro-2.0.8-2jpp.noarch.rpm</code>) and the small library that links
+ant and the external package (e.g. <code>ant-apache-oro-1.6.2-3jpp.noarch.rpm</code>).
+</p><p>
+However, JPackage does not package proprietary software, and since some of the
+optional packages depend on proprietary jars, they must be handled as follows.
+This may violate the spirit of JPackage, but it is necessary if you need these proprietary packages.
+For example, suppose you want to install support for starteam, which jpackage does not
+support:
+<ol>
+<li>Decide where you want to deploy the extra jars.  One option is in <code>$ANT_HOME/lib</code>,
+which, for JPackage is usually <code>/usr/share/ant/lib</code>.  Another, less messy option
+is to create an <code>.ant/lib</code> subdirectory of your home directory and place your
+non-jpackage ant jars there, thereby avoiding mixing jpackage
+libraries with non-jpacakge stuff in the same folder.
+More information on where Ant finds its libraries is available
+<a href="http://ant.apache.org/manual/running.html#libs">here</a></li>
+<li>Download a non-jpackage binary distribution from the regular
+    <a href="http://ant.apache.org/bindownload.cgi" target="_top">Apache Ant site</a></li>
+<li>Unzip or untar the distribution into a temporary directory</li>
+<li>Copy the linking jar, in this case <code>ant-starteam.jar</code>, into the library directory you
+chose in step 1 above.</li>
+<li>Copy the proprietary jar itself into the same directory.</li>
+</ol>
+Finally, if for some reason you are running on a system with both the JPackage and Apache versions of Ant
+available, if you should want to run the Apache version (which will have to be specified with an absolute file name,
+not found on the path), you should use Ant's <code>--noconfig</code> command-line switch to avoid JPackage's classpath mechanism.
+
+
+<h3><a name="advanced">Advanced</a></h3>
+
+<p>There are lots of variants that can be used to run Ant. What you need is at
+least the following:</p>
+<ul>
+<li>The classpath for Ant must contain <code>ant.jar</code> and any jars/classes
+needed for your chosen JAXP-compliant XML parser.</li>
+<li>When you need JDK functionality
+(such as for the <a href="CoreTasks/javac.html">javac</a> task or the
+<a href="CoreTasks/rmic.html">rmic</a> task), then <code>tools.jar</code>
+must be added. The scripts supplied with Ant,
+in the <code>bin</code> directory, will add
+the required JDK classes automatically, if the <code>JAVA_HOME</code>
+environment variable is set.</li>
+
+<li>When you are executing platform-specific applications, such as the
+<a href="CoreTasks/exec.html">exec</a> task or the
+<a href="CoreTasks/cvs.html">cvs</a> task, the property <code>ant.home</code>
+must be set to the directory containing where you installed Ant. Again
+this is set by the Ant scripts to the value of the ANT_HOME environment
+variable.</li>
+</ul>
+The supplied ant shell scripts all support an <tt>ANT_OPTS</tt>
+environment variable which can be used to supply extra options
+to ant. Some of the scripts also read in an extra script stored
+in the users home directory, which can be used to set such options. Look
+at the source for your platform's invocation script for details.
+
+<hr>
+<h2><a name="buildingant">Building Ant</a></h2>
+<p>To build Ant from source, you can either install the Ant source distribution
+or checkout the ant module from SVN.</p>
+<p>Once you have installed the source, change into the installation
+directory.</p>
+
+<p>Set the <code>JAVA_HOME</code> environment variable
+to the directory where the JDK is installed.
+See <a href="#installing">Installing Ant</a>
+for examples on how to do this for your operating system. </p>
+
+<p><b>Note</b>: The bootstrap process of Ant requires a greedy
+compiler like Sun's javac or jikes.  It does not work with gcj or
+kjc.</p>
+
+<p>Make sure you have downloaded any auxiliary jars required to
+build tasks you are interested in. These should be
+added to the <code>lib/optional</code>
+directory of the source tree.
+See <a href="#librarydependencies">Library Dependencies</a>
+for a list of JAR requirements for various features.
+Note that this will make the auxiliary JAR
+available for the building of Ant only. For running Ant you will
+still need to
+make the JARs available as described under
+<a href="#installing">Installing Ant</a>.</p>
+
+<p>Your are now ready to build Ant:</p>
+<blockquote>
+  <p><code>build -Ddist.dir=&lt;<i>directory_to_contain_Ant_distribution</i>&gt; dist</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Windows</i>)</p>
+  <p><code>sh build.sh -Ddist.dir=&lt;<i>directory_to_contain_Ant_distribution</i>&gt; dist</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Unix</i>)</p>
+</blockquote>
+
+<p>This will create a binary distribution of Ant in the directory you specified.</p>
+
+<p>The above action does the following:</p>
+<ul>
+
+<li>If necessary it will bootstrap the Ant code. Bootstrapping involves the manual
+compilation of enough Ant code to be able to run Ant. The bootstrapped Ant is
+used for the remainder of the build steps. </li>
+
+<li>Invokes the bootstrapped Ant with the parameters passed to the build script. In
+this case, these parameters define an Ant property value and specify the &quot;dist&quot; target
+in Ant's own <code>build.xml</code> file.</li>
+
+<li>Create the ant.jar and ant-launcher.jar JAR files</li>
+
+<li>Create optional JARs for which the build had the relevant libraries. If
+a particular library is missing from ANT_HOME/lib/optional, then the matching
+ant- JAR file will not be created. For example, ant-junit.jar is only built
+if there is a junit.jar in the optional directory.</li>
+</ul>
+
+<p>On most occasions you will not need to explicitly bootstrap Ant since the build
+scripts do that for you. If however, the build file you are using makes use of features
+not yet compiled into the bootstrapped Ant, you will need to manually bootstrap.
+Run <code>bootstrap.bat</code> (Windows) or <code>bootstrap.sh</code> (UNIX)
+to build a new bootstrap version of Ant.</p>
+
+If you wish to install the build into the current <code>ANT_HOME</code>
+directory, you can use:
+<blockquote>
+  <p><code>build install</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Windows</i>)</p>
+  <p><code>sh build.sh install</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Unix</i>)</p>
+</blockquote>
+
+You can avoid the lengthy Javadoc step, if desired, with:
+<blockquote>
+  <p><code>build install-lite</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Windows</i>)</p>
+  <p><code>sh build.sh install-lite</code>&nbsp;&nbsp;&nbsp;&nbsp;(<i>Unix</i>)</p>
+</blockquote>
+This will only install the <code>bin</code> and <code>lib</code> directories.
+<p>Both the <code>install</code> and
+<code>install-lite</code> targets will overwrite
+the current Ant version in <code>ANT_HOME</code>.</p>
+
+<hr>
+<h2><a name="librarydependencies">Library Dependencies</a></h2>
+<p>The following libraries are needed in Ant's classpath
+if you are using the
+indicated feature. Note that only one of the regexp libraries is
+needed for use with the mappers
+(and Java 1.4 and higher includes a regexp implementation which
+Ant will find automatically).
+You will also need to install the particular
+Ant optional jar containing the task definitions to make these
+tasks available. Please refer to the <a href="#optionalTasks">
+Installing Ant / Optional Tasks</a> section above.</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td><b>Jar Name</b></td>
+    <td><b>Needed For</b></td>
+    <td><b>Available At</b></td>
+  </tr>
+  <tr>
+    <td>An XSL transformer like Xalan</td>
+    <td>style task</td>
+    <td>
+    <b>If you use JDK 1.4+, an XSL transformer is already included, so you need not do anything special.</b><br>
+    <ul><li>XALAN : <a href="http://xml.apache.org/xalan-j/index.html"
+    target="_top">http://xml.apache.org/xalan-j/index.html</a></li>
+    </ul>
+    </td>
+  </tr>
+  <tr>
+    <td>jakarta-regexp-1.3.jar</td>
+    <td>regexp type with mappers</td>
+    <td><a href="http://jakarta.apache.org/regexp/" target="_top">http://jakarta.apache.org/regexp/</a></td>
+  </tr>
+  <tr>
+    <td>jakarta-oro-2.0.8.jar</td>
+    <td>regexp type with mappers and the perforce tasks<br>
+    To use the FTP task,
+you need jakarta-oro 2.0.8 or later, and <a href="#commons-net">commons-net</a></td>
+    <td><a href="http://jakarta.apache.org/oro/" target="_top">http://jakarta.apache.org/oro/</a></td>
+  </tr>
+  <tr>
+    <td>junit.jar</td>
+    <td><code>&lt;junit&gt;</code> task. May be in classpath passed to task rather than Ant's classpath.</td>
+    <td><a href="http://www.junit.org/" target="_top">http://www.junit.org/</a></td>
+  </tr>
+  <tr>
+    <td>xalan.jar</td>
+    <td>junitreport task</td>
+    <td><a href="http://xml.apache.org/xalan-j/" target="_top">http://xml.apache.org/xalan-j/</a></td>
+  </tr>
+  <tr>
+    <td>stylebook.jar</td>
+    <td>stylebook task</td>
+    <td>SVN repository of <a href="http://xml.apache.org/svn.html" target="_top">http://xml.apache.org/svn.html</a></td>
+  </tr>
+  <tr>
+    <td>antlr.jar</td>
+    <td>antlr task</td>
+    <td><a href="http://www.antlr.org/" target="_top">http://www.antlr.org/</a></td>
+  </tr>
+  <tr>
+    <td>bsf.jar</td>
+    <td>script task
+      <p>
+        <strong>Note</strong>: Ant 1.6 and later require Apache BSF, not
+        the IBM version.  I.e. you need BSF 2.3.0-rc1 or later.
+      </p>
+      <p>
+        <strong>Note</strong>: BSF 2.4.0 is needed to use a post 1.5R3 version
+        of rhino's javascript.
+      </p>
+      <p>
+        <strong>Note</strong>: BSF 2.4.0 uses jakarata-commons-logging
+        so it needs the commons-logging.jar.
+      </p>
+      </td>
+    <td><a href="http://jakarta.apache.org/bsf/" target="_top">http://jakarta.apache.org/bsf/</a></td>
+  </tr>
+  <tr>
+    <td>Groovy jars</td>
+    <td>Groovy with script and scriptdef tasks<br>
+      You need to get the groovy jar and two asm jars from a groovy
+      installation. The jars are groovy-[version].jar, asm-[vesion].jar and
+      asm-util-[version].jar and antlr-[version].jar.
+      As of groovy version 1.0-JSR-06, the jars are
+      groovy-1.0-JSR-06.jar, antlr-2.7.5.jar, asm-2.2.jar and asm-util-2.2.jar.
+      Alternatively one may use the embedded groovy jar file.
+      This is located in the embedded directory of the groovy distribution.
+      This bundles all the needed jar files into one jar file.
+      It is called groovy-all-[version].jar.
+    </td>
+    <td>
+      <a href="http://groovy.codehaus.org/" target="_top">http://groovy.codehaus.org/</a>
+      <br>
+      The asm jars are also available from the creators of asm -
+      <a href="http://asm.objectweb.org/" target="_top">http://asm.objectweb.org/</a>
+    </td>
+  </tr>
+  <tr>
+    <td>netrexx.jar</td>
+    <td>netrexx task, Rexx with the script task</td>
+    <td><a href="http://www.ibm.com/software/awdtools/netrexx/download.html" target="_top">
+        http://www.ibm.com/software/awdtools/netrexx/download.html</a></td>
+  </tr>
+  <tr>
+    <td>js.jar</td>
+    <td>Javascript with script task<br>
+    If you use Apache BSF 2.3.0-rc1, you must use rhino 1.5R3 (later
+    versions of BSF (e.g. version 2.4.0) work with 1.5R4 and higher).</td>
+    <td><a href="http://www.mozilla.org/rhino/" target="_top">http://www.mozilla.org/rhino/</a></td>
+  </tr>
+  <tr>
+    <td>jython.jar</td>
+    <td>Python with script task<br>
+    Warning : jython.jar also contains classes from jakarta-oro.
+    Remove these classes if you are also using jakarta-oro.</td>
+    <td><a href="http://jython.sourceforge.net/" target="_top">http://jython.sourceforge.net/</a></td>
+  </tr>
+  <tr>
+    <td>jpython.jar</td>
+    <td>Python with script task <b>deprecated, jython is the prefered engine</b></td>
+    <td><a href="http://www.jpython.org/" target="_top">http://www.jpython.org/</a></td>
+  </tr>
+  <tr>
+    <td>jacl.jar and tcljava.jar</td>
+    <td>TCL with script task</td>
+    <td><a href="http://www.scriptics.com/software/java/" target="_top">http://www.scriptics.com/software/java/</a></td>
+  </tr>
+  <tr>
+    <td>BeanShell JAR(s)</td>
+    <td>BeanShell with script task.
+      <br>
+    <strong>Note</strong>: Ant requires BeanShell version 1.3 or
+      later</td>
+    <td><a href="http://www.beanshell.org/" target="_top">http://www.beanshell.org/</a></td>
+  </tr>
+  <tr>
+    <td>jruby.jar</td>
+    <td>Ruby with script task</td>
+    <td><a href="http://jruby.sourceforge.net/" target="_top">http://jruby.sourceforge.net/</a></td>
+  </tr>
+  <tr>
+    <td>judo.jar</td>
+    <td>Judoscript with script task</td>
+    <td><a href="http://www.judoscript.com/index.html" target="_top">http://www.judoscript.com/index.html</a></td>
+  </tr>
+  <tr>
+    <td>commons-logging.jar</td>
+    <td>CommonsLoggingListener</td>
+    <td><a href="http://jakarta.apache.org/commons/logging/index.html"
+           target="_top">http://jakarta.apache.org/commons/logging/index.html</a></td>
+  </tr>
+  <tr>
+    <td>log4j.jar</td>
+    <td>Log4jListener</td>
+    <td><a href="http://jakarta.apache.org/log4j/docs/index.html"
+           target="_top">http://jakarta.apache.org/log4j/docs/index.html</a></td>
+  </tr>
+  <tr>
+    <td><a name="commons-net">commons-net.jar</a></td>
+    <td>ftp, rexec and telnet tasks<br>
+    jakarta-oro 2.0.8 or later is required together with commons-net 1.4.0.<br>
+    For all users, a minimum version of commons-net of 1.4.0 is recommended.  Earlier
+    versions did not support the full range of configuration options, and 1.4.0 is needed
+    to compile Ant.
+    </td>
+    <td><a href="http://jakarta.apache.org/commons/net/index.html"
+           target="_top">http://jakarta.apache.org/commons/net/index.html</a></td>
+  </tr>
+  <tr>
+    <td>bcel.jar</td>
+    <td>classfileset data type,
+        JavaClassHelper used by the ClassConstants filter reader and
+        optionally used by ejbjar for dependency determination
+    </td>
+    <td><a href="http://jakarta.apache.org/bcel/" target="_top">http://jakarta.apache.org/bcel/</a></td>
+  </tr>
+  <tr>
+    <td>mail.jar</td>
+    <td>Mail task with Mime encoding, and the MimeMail task</td>
+    <td><a href="http://java.sun.com/products/javamail/"
+        target="_top">http://java.sun.com/products/javamail/</a></td>
+  </tr>
+  <tr>
+    <td>jsse.jar</td>
+    <td>
+Support for SMTP over TLS/SSL <br>
+in the Mail task<br>
+Already included Java 1.4+</td>
+    <td><a href="http://java.sun.com/products/jsse/"
+        target="_top">http://java.sun.com/products/jsse/</a></td>
+  </tr>
+  <tr>
+    <td>activation.jar</td>
+    <td>Mail task with Mime encoding, and the MimeMail task</td>
+    <td><a href="http://java.sun.com/products/javabeans/glasgow/jaf.html"
+        target="_top">http://java.sun.com/products/javabeans/glasgow/jaf.html</a></td>
+  </tr>
+  <tr>
+    <td>jdepend.jar</td>
+    <td>jdepend task</td>
+    <td><a href="http://www.clarkware.com/software/JDepend.html"
+        target="_top">http://www.clarkware.com/software/JDepend.html</a></td>
+  </tr>
+  <tr>
+    <td>resolver.jar <b>1.1beta or later</b></td>
+    <td>xmlcatalog datatype <em>only if support for external catalog files is desired</em></td>
+    <td><a href="http://xml.apache.org/commons/"
+    target="_top">http://xml.apache.org/commons/</a>.</td>
+  </tr>
+  <tr>
+    <td>jsch.jar <b>0.1.29 or later</b></td>
+    <td>sshexec and scp tasks</td>
+    <td><a href="http://www.jcraft.com/jsch/index.html"
+        target="_top">http://www.jcraft.com/jsch/index.html</a></td>
+  </tr>
+  <tr>
+    <td>JAI - Java Advanced Imaging</td>
+    <td>image task</td>
+    <td><a href="http://java.sun.com/products/java-media/jai/"
+        target="_top">http://java.sun.com/products/java-media/jai/</a></td>
+  </tr>
+  <tr>
+    <td>Starteam SDK</td>
+    <td>Starteam version management tasks</td>
+    <td><a href="http://www.borland.com/downloads/download_starteam.html"
+        target="_top">http://www.borland.com/downloads/download_starteam.html</a></td>
+  </tr>
+</table>
+<br>
+<h2><a name="Troubleshooting">Troubleshooting</a></h2>
+
+
+<h3><a name="diagnostics">Diagnostics</a></h3>
+
+<p> Ant has a built in diagnostics feature. If you run <code>ant
+-diagnostics</code> ant will look at its internal state and print it out. This
+code will check and print the following things. </p>
+
+<ul>
+
+<li>Where Ant is running from. Sometimes you can be surprised.</li>
+
+<li>The version of ant.jar and of the ant-*.jar containing the optional tasks -
+    and whether they match</li>
+
+<li>Which JAR files are in ANT_HOME/lib
+
+<li>Which optional tasks are available. If a task is not listed as being
+available, either it is not present, or libraries that it depends on are
+absent.</li>
+
+
+<li>XML Parser information</li>
+
+<li>JVM system properties
+</li>
+
+<li>The status of the temp directory. If this is not writeable, or its clock is
+horribly wrong (possible if it is on a network drive), a lot of tasks will fail
+with obscure error messages.</li>
+
+<li>The current time zone as Java sees it. If this is not what it should be for
+your location, then dependency logic may get confused.
+
+</ul>
+
+<p>
+    Running <code>ant -diagnostics</code> is a good way to check that ant is
+    installed. It is also a first step towards self-diagnosis of any problem.
+    Any configuration problem reported to the user mailing list will probably
+    result ins someone asking you to run the command and show the results, so
+    save time by using it yourself.
+</p>
+
+<p>
+    For under-IDE diagostics, use the &lt;diagnostics&gt; task to run the same
+    tests as an ant task. This can be added to a diagnostics target in a build
+    file to see what tasks are available under the IDE, what the XML parser and
+    classpath is, etc.
+</p>
+
+<h3><a name="ant-user">user mailing list</a></h3>
+
+<p> If you cannot get Ant installed or working, the Ant user mailing list is the
+best place to start with any problem. Please do your homework first, make sure
+that it is not a <a href="#classpath"><code>CLASSPATH</code></a> problem, and run a <a
+href="#diagnostics">diagnostics check</a> to see what Ant thinks of its own
+state. Why the user list, and not the developer list?
+Because there are more users than developers, so more people who can help you. </p>
+
+<p>
+
+Please only file a bug report against Ant for a configuration/startup problem if
+there really is a fixable bug in Ant related to configuration, such as it not
+working on a particular platform, with a certain JVM version, etc, or if you are
+advised to do it by the user mailing list.
+</p>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/installlist.html b/trunk/docs/manual/installlist.html
new file mode 100644
index 0000000..1e80d5f
--- /dev/null
+++ b/trunk/docs/manual/installlist.html
@@ -0,0 +1,44 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Installing Ant</h3>
+<p><a href="install.html#getting">Getting Ant</a><br/>
+  <a href="install.html#sysrequirements">System Requirements</a><br/>
+  <a href="install.html#installing">Installing Ant</a><br/>
+  <a href="install.html#checkInstallation">Check Installation</a><br/>
+  <a href="install.html#buildingant">Building Ant</a><br/>
+  <a href="install.html#librarydependencies">Library Dependencies</a><br/>
+  <a href="platform.html">Platform Specific Issues</a><br/>
+  <a href="proxy.html">Proxy configuration</a><br/>
+</p>
+<p><br/>
+</p>
+</body>
+</html>
+
diff --git a/trunk/docs/manual/intro.html b/trunk/docs/manual/intro.html
new file mode 100644
index 0000000..e5673ed
--- /dev/null
+++ b/trunk/docs/manual/intro.html
@@ -0,0 +1,69 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Apache Ant User Manual - Introduction</title>
+</head>
+
+<body>
+<h1><a name="introduction">Introduction</a></h1>
+<p>Apache Ant is a Java-based build tool. In theory, it is kind of like
+<i>make</i>, without <i>make</i>'s wrinkles.</p>
+<h3>Why?</h3>
+<p>Why another build tool when there is already
+<i>make</i>,
+<i>gnumake</i>,
+<i>nmake</i>,
+<i>jam</i>,
+and
+others? Because all those tools have limitations that Ant's original author
+couldn't live with when developing software across multiple platforms.
+Make-like
+tools are inherently shell-based: they evaluate a set of dependencies,
+then execute commands not unlike what you would issue on a shell.
+This means that you
+can easily extend these tools by using or writing any program for the OS that
+you are working on; however, this also means that you limit yourself to the OS,
+or at least the OS type, such as Unix, that you are working on.</p>
+<p>Makefiles are inherently evil as well. Anybody who has worked on them for any
+time has run into the dreaded tab problem. &quot;Is my command not executing
+because I have a space in front of my tab?!!&quot; said the original author of
+Ant way too many times. Tools like Jam took care of this to a great degree, but
+still have yet another format to use and remember.</p>
+<p>Ant is different. Instead of a model where it is extended with shell-based
+commands, Ant is extended using Java classes. Instead of writing shell commands,
+the configuration files are XML-based, calling out a target tree where various
+tasks get executed. Each task is run by an object that implements a particular
+Task interface.</p>
+<p>Granted, this removes some of the expressive power that is inherent in being
+able to construct a shell command such as
+<nobr><code>`find . -name foo -exec rm {}`</code></nobr>, but it
+gives you the ability to be cross-platform--to work anywhere and
+everywhere. And
+hey, if you really need to execute a shell command, Ant has an
+<code>&lt;exec&gt;</code> task that
+allows different commands to be executed based on the OS it is executing
+on.</p>
+
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/javacprops.html b/trunk/docs/manual/javacprops.html
new file mode 100644
index 0000000..1b5c1d8
--- /dev/null
+++ b/trunk/docs/manual/javacprops.html
@@ -0,0 +1,53 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Properties controlling javac</title>
+</head>
+
+<body>
+
+<p>The source and target attributes of <code>&lt;javac&gt;</code>
+don't have any default values for historical reasons.  Since the
+underlying javac compiler's default depends on the JDK you use, you
+may encounter build files that don't explicitly set those attributes
+and that will no longer compile using a newer JDK.  If you cannot
+change the build file, Ant provides two properties that help you
+setting default values for these attributes.  If the attributes have
+been set explicitly, the properties listed here will be ignored.</p>
+
+<h2><a name="source">ant.build.javac.source</a></h2>
+
+<p><em>Since Ant 1.7</em></p>
+
+<p>Provides a default value for <code>&lt;javac&gt;</code>'s and
+<code>&lt;javadoc&gt;</code>'s source attribute.</p>
+
+<h2><a name="target">ant.build.javac.target</a></h2>
+
+<p><em>Since Ant 1.7</em></p>
+
+<p>Provides a default value for <code>&lt;javac&gt;</code>'s target
+attribute.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/listeners.html b/trunk/docs/manual/listeners.html
new file mode 100644
index 0000000..7af7eb4
--- /dev/null
+++ b/trunk/docs/manual/listeners.html
@@ -0,0 +1,503 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Listeners &amp; Loggers</title>
+</head>
+
+<body>
+<h1>Listeners &amp; Loggers</h1>
+
+<h2><a name="Overview">Overview</a></h2>
+
+<p>Ant has two related features to allow the build process to be monitored:
+listeners and loggers.</p>
+
+<h3><a name="Listeners">Listeners</a></h3>
+
+<p>A listener is alerted of the following events:</p>
+
+<ul>
+  <li>build started</li>
+  <li>build finished</li>
+  <li>target started</li>
+  <li>target finished</li>
+  <li>task started</li>
+  <li>task finished</li>
+  <li>message logged</li>
+</ul>
+
+<p>
+  These are used internally for various recording and housekeeping operations,
+  however new listeners may registered on the command line through the <code>-listener</code>
+  argument.
+</p>
+
+<h3><a name="Loggers">Loggers</a></h3>
+
+<p>Loggers extend the capabilities of listeners and add the following features:</p>
+
+<ul>
+  <li>Receives a handle to the standard output and error print streams and
+  therefore can log information to the console or the <code>-logfile</code> specified file.</li>
+  <li>Logging level (-quiet, -verbose, -debug) aware</li>
+  <li>Emacs-mode aware</li>
+</ul>
+
+<h2><a name="builtin">Built-in Listeners/Loggers</a></h2>
+
+<table border="1" cellspacing="1" width="100%" id="AutoNumber1">
+  <tr>
+    <td width="33%">Classname</td>
+    <td width="33%">Description</td>
+    <td width="34%">Type</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#DefaultLogger">org.apache.tools.ant.DefaultLogger</a></code></td>
+    <td width="33%">The logger used implicitly unless overridden with the
+    <code>-logger</code> command-line switch.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#NoBannerLogger">
+    org.apache.tools.ant.NoBannerLogger</a></code></td>
+    <td width="33%">This logger omits output of empty target output.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#MailLogger">
+    org.apache.tools.ant.listener.MailLogger</a></code></td>
+    <td width="33%">Extends DefaultLogger such that output is still generated
+    the same, and when the build is finished an e-mail can be sent.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#AnsiColorLogger">
+    org.apache.tools.ant.listener.AnsiColorLogger</a></code></td>
+    <td width="33%">Colorifies the build output.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#Log4jListener">
+    org.apache.tools.ant.listener.Log4jListener</a></code></td>
+    <td width="33%">Passes events to Log4j for highly customizable logging.</td>
+    <td width="34%">BuildListener</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#XmlLogger">org.apache.tools.ant.XmlLogger</a></code></td>
+    <td width="33%">Writes the build information to an XML file.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#TimestampedLogger">org.apache.tools.ant.TimestampedLogger</a></code></td>
+    <td width="33%">Prints the time that a build finished</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#BigProjectLogger">org.apache.tools.ant.listener.BigProjectLogger</a></code></td>
+    <td width="33%">Prints the project name every target</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+  <tr>
+    <td width="33%"><code><a href="#ProfileLogger">org.apache.tools.ant.listener.ProfileLogger</a></code></td>
+    <td width="33%">The default logger, with start times, end times and
+    durations added for each task and target.</td>
+    <td width="34%">BuildLogger</td>
+  </tr>
+</table>
+<h3><a name="DefaultLogger">DefaultLogger</a></h3>
+
+<p>Simply run Ant normally, or:</p>
+
+<blockquote>
+
+<p><code>ant -logger org.apache.tools.ant.DefaultLogger</code></p>
+
+</blockquote>
+
+<h3><a name="NoBannerLogger">NoBannerLogger</a></h3>
+
+<p>Removes output of empty target output.</p>
+
+<blockquote>
+
+<p><code>ant -logger org.apache.tools.ant.NoBannerLogger</code></p>
+
+</blockquote>
+
+<h3><a name="MailLogger">MailLogger</a></h3>
+
+<p>The MailLogger captures all output logged through DefaultLogger (standard Ant
+output) and will send success and failure messages to unique e-mail lists, with
+control for turning off success or failure messages individually.</p>
+<p>Properties controlling the operation of MailLogger:</p>
+<table border="1" cellspacing="1" width="100%" id="AutoNumber2">
+  <tr>
+    <th width="337">Property</th>
+    <th width="63%">Description</th>
+    <th width="63%">Required</th>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.mailhost </td>
+    <td width="63%">Mail server to use</td>
+    <td width="63%">No, default &quot;localhost&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.port </td>
+    <td width="63%">SMTP Port for the Mail server</td>
+    <td width="63%">No, default &quot;25&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.user</td>
+    <td width="63%">user name for SMTP auth</td>
+    <td width="63%">Yes, if SMTP auth is required on your SMTP server<br>
+    the email message will be then sent using Mime and requires JavaMail</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.password</td>
+    <td width="63%">password for SMTP auth</td>
+    <td width="63%">Yes, if SMTP auth is required on your SMTP server<br>
+    the email message will be then sent using Mime and requires JavaMail</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.ssl</td>
+    <td width="63%">on or true if ssl is needed<br>
+    This feature requires JavaMail</td>
+    <td width="63%">
+    no</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.from</td>
+    <td width="63%">Mail &quot;from&quot; address</td>
+    <td width="63%">Yes, if mail needs to be sent</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.replyto</td>
+    <td width="63%">Mail &quot;replyto&quot; address(es), comma-separated</td>
+    <td width="63%">No</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.failure.notify </td>
+    <td width="63%">Send build failure e-mails?</td>
+    <td width="63%">No, default &quot;true&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.success.notify </td>
+    <td width="63%">Send build success e-mails?</td>
+    <td width="63%">No, default &quot;true&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.failure.to </td>
+    <td width="63%">Address(es) to send failure messages to, comma-separated</td>
+    <td width="63%">Yes, if failure mail is to be sent</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.success.to </td>
+    <td width="63%">Address(es) to send success messages to, comma-separated</td>
+    <td width="63%">Yes, if success mail is to be sent</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.failure.subject </td>
+    <td width="63%">Subject of failed build</td>
+    <td width="63%">No, default &quot;Build Failure&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.success.subject </td>
+    <td width="63%">Subject of successful build</td>
+    <td width="63%">No, default &quot;Build Success&quot;</td>
+  </tr>
+  <tr>
+    <td width="337">MailLogger.properties.file </td>
+    <td width="63%">Filename of properties file that will override other values.</td>
+    <td width="63%">No</td>
+  </tr>
+</table>
+<blockquote>
+
+<p><code>ant -logger org.apache.tools.ant.listener.MailLogger</code></p>
+
+</blockquote>
+
+<h3><a name="AnsiColorLogger">AnsiColorLogger</a></h3>
+
+<p>The AnsiColorLogger adds color to the standard Ant output
+by prefixing and suffixing ANSI color code escape sequences to
+it.  It is just an extension of <a href="#DefaultLogger">DefaultLogger</a>
+and hence provides all features that DefaultLogger does.</p>
+<p>AnsiColorLogger differentiates the output by assigning
+different colors depending upon the type of the message.</p>
+<p>If used with the -logfile option, the output file
+will contain all the necessary escape codes to
+display the text in colorized mode when displayed
+in the console using applications like cat, more, etc.</p>
+<p>This is designed to work on terminals that support ANSI
+color codes.  It works on XTerm, ETerm, Win9x Console
+(with ANSI.SYS loaded.), etc.</p>
+<p><Strong>NOTE:</Strong>
+It doesn't work on WinNT and successors, even when a COMMAND.COM console loaded with
+ANSI.SYS is used.</p>
+<p>If the user wishes to override the default colors
+with custom ones, a file containing zero or more of the
+custom color key-value pairs must be created.  The recognized keys
+and their default values are shown below:</p><code><pre>
+AnsiColorLogger.ERROR_COLOR=2;31
+AnsiColorLogger.WARNING_COLOR=2;35
+AnsiColorLogger.INFO_COLOR=2;36
+AnsiColorLogger.VERBOSE_COLOR=2;32
+AnsiColorLogger.DEBUG_COLOR=2;34</pre></code>
+<p>Each key takes as value a color combination defined as
+<b>Attribute;Foreground;Background</b>.  In the above example, background
+value has not been used.</p>
+<p>This file must be specfied as the value of a system variable
+named ant.logger.defaults and passed as an argument using the -D
+option to the <b>java</b> command that invokes the Ant application.
+An easy way to achieve this is to add -Dant.logger.defaults=
+<i>/path/to/your/file</i> to the ANT_OPTS environment variable.
+Ant's launching script recognizes this flag and will pass it to
+the java command appropriately.</p>
+<p>Format:</p><pre>
+AnsiColorLogger.*=Attribute;Foreground;Background
+
+Attribute is one of the following:
+0 -&gt; Reset All Attributes (return to normal mode)
+1 -&gt; Bright (Usually turns on BOLD)
+2 -&gt; Dim
+3 -&gt; Underline
+5 -&gt; link
+7 -&gt; Reverse
+8 -&gt; Hidden
+
+Foreground is one of the following:
+30 -&gt; Black
+31 -&gt; Red
+32 -&gt; Green
+33 -&gt; Yellow
+34 -&gt; Blue
+35 -&gt; Magenta
+36 -&gt; Cyan
+37 -&gt; White
+
+Background is one of the following:
+40 -&gt; Black
+41 -&gt; Red
+42 -&gt; Green
+43 -&gt; Yellow
+44 -&gt; Blue
+45 -&gt; Magenta
+46 -&gt; Cyan
+47 -&gt; White</pre>
+
+<blockquote>
+
+<p><code>ant -logger org.apache.tools.ant.listener.AnsiColorLogger</code></p>
+
+</blockquote>
+
+<h3><a name="Log4jListener">Log4jListener</a></h3>
+
+<p>Passes build events to Log4j, using the full classname's of the generator of
+each build event as the category:</p>
+
+<ul>
+  <li>build started / build finished - org.apache.tools.ant.Project</li>
+  <li>target started / target finished - org.apache.tools.ant.Target</li>
+  <li>task started / task finished - the fully qualified classname of the task</li>
+  <li>message logged - the classname of one of the above, so if a task logs a
+  message, its classname is the category used, and so on.</li>
+</ul>
+
+<p>All start events are logged as INFO.&nbsp; Finish events are either logged as
+INFO or ERROR depending on whether the build failed during that stage. Message
+events are logged according to their Ant logging level, mapping directly to a
+corresponding Log4j level.</p>
+
+<blockquote>
+
+<p><code>ant -listener org.apache.tools.ant.listener.Log4jListener</code></p>
+
+</blockquote>
+
+<p>To use Log4j you will need the Log4j JAR file and a 'log4j.properties'
+configuration file.  Both should be placed somewhere in your Ant
+classpath. If the log4j.properties is in your project root folder you can
+add this with <i>-lib</i> option:</p>
+
+<blockquote>
+<pre><code>ant -listener org.apache.tools.ant.listener.Log4jListener -lib .</code></pre>
+</blockquote>
+
+<p>If, for example, you wanted to capture the same information output to the
+console by the DefaultLogger and send it to a file named 'build.log', you
+could use the following configuration:</p>
+
+<blockquote>
+
+<pre><code>log4j.rootLogger=ERROR, LogFile
+log4j.logger.org.apache.tools.ant.Project=INFO
+log4j.logger.org.apache.tools.ant.Target=INFO
+log4j.logger.org.apache.tools.ant.taskdefs=INFO
+log4j.logger.org.apache.tools.ant.taskdefs.Echo=WARN
+
+log4j.appender.LogFile=org.apache.log4j.FileAppender
+log4j.appender.LogFile.layout=org.apache.log4j.PatternLayout
+log4j.appender.LogFile.layout.ConversionPattern=[%6r] %8c{1} : %m%n
+log4j.appender.LogFile.file=build.log
+</code></pre>
+
+</blockquote>
+
+<p>For more information about configuring Log4J see <a href="http://logging.apache.org/log4j/docs/documentation.html">its
+documentation page</a>.</p>
+
+<h3><a name="XmlLogger">XmlLogger</a></h3>
+
+<p>Writes all build information out to an XML file named log.xml, or the value
+of the <code>XmlLogger.file</code> property if present, when used as a
+listener. When used as a logger, it writes all output to either the
+console or to the value of <code>-logfile</code>. Whether used as a listener
+or logger, the output is not generated until the build is complete, as it
+buffers the information in order to provide timing information for task,
+targets, and the project.
+<p>
+By default the XML file creates
+a reference to an XSLT file "log.xsl" in the current directory; look in
+ANT_HOME/etc for one of these. You can set the property
+<code>ant.XmlLogger.stylesheet.uri</code> to provide a uri to a style sheet.
+this can be a relative or absolute file path, or an http URL.
+If you set the property to the empty string, "", no XSLT transform
+is declared at all.
+</p>
+
+<blockquote>
+
+<p><code>ant -listener org.apache.tools.ant.XmlLogger</code><br>
+<code>ant -logger org.apache.tools.ant.XmlLogger -verbose -logfile build_log.xml</code></p>
+
+</blockquote>
+
+
+<h3><a name="TimestampedLogger">TimestampedLogger</a></h3>
+
+<p>
+  Acts like the default logger, except that the final success/failure message also includes
+  the time that the build completed. For example:
+</p>
+<pre>
+  BUILD SUCCESSFUL - at 16/08/05 16:24
+</pre>
+<p>To use this listener, use the command:</p>
+
+<blockquote>
+
+<code>ant  -logger org.apache.tools.ant.listener.TimestampedLogger</code>
+
+</blockquote>
+
+<h3><a name="BigProjectLogger">BigProjectLogger</a></h3>
+
+<p>
+  This logger is designed to make examining the logs of a big build easier,
+  especially those run under continuous integration tools. It
+</p>
+<ol>
+  <li>When entering a child project, prints its name and directory</li>
+  <li>When exiting a child project, prints its name</li>
+  <li>Includes the name of the project when printing a target</li>
+  <li>Omits logging the names of all targets that have no direct task output</li>
+  <li>Includes the build finished timestamp of the TimeStamp logger</li>
+</ol>
+<p>
+  This is useful when using &lt;subant&gt; to build a large project
+  from many smaller projects -the output shows which particular
+  project is building. Here is an example in which "clean" is being called
+  on all a number of child projects, only some of which perform work:
+</p>
+<pre>
+
+======================================================================
+Entering project "xunit"
+In /home/ant/components/xunit
+======================================================================
+
+xunit.clean:
+   [delete] Deleting directory /home/ant/components/xunit/build
+   [delete] Deleting directory /home/ant/components/xunit/dist
+
+======================================================================
+Exiting project "xunit"
+======================================================================
+
+======================================================================
+Entering project "junit"
+In /home/ant/components/junit
+======================================================================
+
+======================================================================
+Exiting project "junit"
+======================================================================
+</pre>
+
+<p>
+  The entry and exit messages are very verbose in this example, but in
+  a big project compiling or testing many child components, the messages
+  are reduced to becoming clear delimiters of where different projects
+  are in charge -or more importantly, which project is failing.
+</p>
+
+<p>To use this listener, use the command:</p>
+<blockquote>
+
+<code>ant  -logger org.apache.tools.ant.listener.BigProjectLogger</code>
+
+</blockquote>
+
+<h2><a name="dev">Writing your own</a></h2>
+
+<p>See the <a href="develop.html#buildevents">Build Events</a> section for
+developers.</p>
+
+<p>Notes:</p>
+
+<ul>
+  <li>
+    A listener or logger should not write to standard output or error in the <code>messageLogged() method</code>;
+    Ant captures these internally and it will trigger an infinite loop.
+  </li>
+  <li>
+    Logging is synchronous; all listeners and loggers are called one after the other, with the build blocking until
+    the output is processed. Slow logging means a slow build.
+  </li>
+  <li>When a build is started, and <code>BuildListener.buildStarted(BuildEvent event)</code> is called,
+    the project is not fully functional. The build has started, yes, and the event.getProject() method call
+    returns the Project instance, but that project is initialized with JVM and ant properties, nor has it
+    parsed the build file yet. You cannot call <code>Project.getProperty()</code> for property lookup, or
+    <code>Project.getName()</code> to get the project name (it will return null).
+  </li>
+  <li>
+    Classes that implement <code>org.apache.tools.ant.SubBuildListener</code> receive notifications when child projects
+    start and stop.
+  </li>
+
+</ul>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/optionaltasklist.html b/trunk/docs/manual/optionaltasklist.html
new file mode 100644
index 0000000..e9f146a
--- /dev/null
+++ b/trunk/docs/manual/optionaltasklist.html
@@ -0,0 +1,92 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<a href="coretasklist.html" target="navFrame">Core Tasks</a><br/>
+<a href="tasksoverview.html" target="mainFrame">Overview of Ant Tasks</a><br/>
+<a href="conceptstypeslist.html" target="navFrame">Concepts and Types</a><br/>
+
+<h3>Optional Tasks</h3>
+<a href="OptionalTasks/dotnet.html"><i>.NET Tasks</i></a><br/>
+<a href="OptionalTasks/antlr.html">ANTLR</a><br/>
+<a href="OptionalTasks/attrib.html">Attrib</a><br/>
+<a href="OptionalTasks/cab.html">Cab</a><br/>
+<a href="OptionalTasks/chgrp.html">Chgrp</a><br/>
+<a href="OptionalTasks/chown.html">Chown</a><br/>
+<a href="OptionalTasks/clearcase.html">Clearcase Tasks</a><br/>
+<a href="OptionalTasks/ccm.html">Continuus/Synergy Tasks</a><br/>
+<a href="OptionalTasks/depend.html">Depend</a><br/>
+<a href="OptionalTasks/ejb.html">EJB Tasks</a><br/>
+<a href="OptionalTasks/echoproperties.html">Echoproperties</a><br/>
+<a href="OptionalTasks/ftp.html">FTP</a><br/>
+<a href="OptionalTasks/image.html">Image</a><br/>
+<a href="OptionalTasks/jarlib-available.html">Jarlib-available</a><br/>
+<a href="OptionalTasks/jarlib-display.html">Jarlib-display</a><br/>
+<a href="OptionalTasks/jarlib-manifest.html">Jarlib-manifest</a><br/>
+<a href="OptionalTasks/jarlib-resolve.html">Jarlib-resolve</a><br/>
+<a href="OptionalTasks/javacc.html">JavaCC</a><br/>
+<a href="OptionalTasks/javah.html">Javah</a><br/>
+<a href="OptionalTasks/jspc.html">JspC</a><br/>
+<a href="OptionalTasks/jdepend.html">JDepend</a><br/>
+<a href="OptionalTasks/jjdoc.html">JJDoc</a><br/>
+<a href="OptionalTasks/jjtree.html">JJTree</a><br/>
+<a href="OptionalTasks/jlink.html"><i>Jlink</i></a><br/>
+<a href="OptionalTasks/junit.html">JUnit</a><br/>
+<a href="OptionalTasks/junitreport.html">JUnitReport</a><br/>
+<a href="OptionalTasks/mimemail.html"><i>MimeMail</i></a><br/>
+<a href="OptionalTasks/native2ascii.html">Native2Ascii</a><br/>
+<a href="OptionalTasks/netrexxc.html">NetRexxC</a><br/>
+<a href="OptionalTasks/perforce.html">Perforce Tasks</a><br/>
+<a href="OptionalTasks/propertyfile.html">PropertyFile</a><br/>
+<a href="OptionalTasks/pvcstask.html">Pvcs</a><br/>
+<a href="OptionalTasks/renameextensions.html"><i>RenameExtensions</i></a><br/>
+<a href="OptionalTasks/replaceregexp.html">ReplaceRegExp</a><br/>
+<a href="OptionalTasks/rexec.html">RExec</a><br/>
+<a href="OptionalTasks/rpm.html">Rpm</a><br/>
+<a href="OptionalTasks/schemavalidate.html">SchemaValidate</a><br/>
+<a href="OptionalTasks/scp.html">Scp</a><br/>
+<a href="OptionalTasks/script.html">Script</a><br/>
+<a href="OptionalTasks/scriptdef.html">Scriptdef</a><br/>
+<a href="OptionalTasks/serverdeploy.html">ServerDeploy</a><br/>
+<a href="OptionalTasks/setproxy.html">Setproxy</a><br/>
+<a href="OptionalTasks/sound.html">Sound</a><br/>
+<a href="OptionalTasks/sos.html">SourceOffSite</a><br/>
+<a href="OptionalTasks/splash.html">Splash</a><br/>
+<a href="OptionalTasks/sshexec.html">Sshexec</a><br/>
+<a href="OptionalTasks/starteam.html">Starteam Tasks</a><br/>
+<a href="OptionalTasks/stylebook.html"><i>Stylebook</i></a><br/>
+<a href="OptionalTasks/symlink.html">Symlink</a><br/>
+<a href="OptionalTasks/telnet.html">Telnet</a><br/>
+<a href="OptionalTasks/translate.html">Translate</a><br/>
+<a href="OptionalTasks/vss.html#tasks">Microsoft Visual SourceSafe Tasks</a><br/>
+<a href="OptionalTasks/wljspc.html">Weblogic JSP Compiler</a><br/>
+<a href="OptionalTasks/xmlvalidate.html">XmlValidate</a><br/>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/platform.html b/trunk/docs/manual/platform.html
new file mode 100644
index 0000000..5c4893c
--- /dev/null
+++ b/trunk/docs/manual/platform.html
@@ -0,0 +1,205 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Platform Issues</title>
+</head>
+
+<h1>Platform Issues</h1>
+
+<h2>Java versions</h2>
+<h3>Java 1.5</h3>
+
+You may need a bigger stack than default, especially if you are using the built in
+XSLT engine. We recommend you use Apache Xalan; indeed, some tasks (JUnit report in XML,
+for example) may not work against the shipping XSL engine.
+
+<h3>Java 1.2</h3>
+
+
+You may sometimes see messages like
+<pre>
+A nonfatal internal JIT (3.10.107(x)) error 'chgTarg: Conditional' has
+occurred in :
+  'org/apache/tools/ant/Project.addReference
+(Ljava/lang/String;Ljava/lang/Object;)V': Interpreting method.
+  Please report this error in detail to
+  http://java.sun.com/cgi-bin/bugreport.cgi
+</pre>
+These are caused by subtle incompatibilities between the Java1.4+ compiled
+release; bugs in the Java runtime that Sun won't fix. Possible solutions:-
+<ol>
+<li>Upgrade your JVM.
+<li>Recompile Ant on a Java1.2 machine
+<li>Add <tt>-Djava.compiler=NONE</tt> to
+the value of your ANT_OPTS environment variable. This turns the JIT off.
+<li>Ignore the messages.
+</ol>
+
+
+
+
+<h2>Unix and Linux</h2>
+
+<ul>
+<li> You should use a GNU version of <tt>tar</tt> to untar the Apache 
+Ant source tree, if you have downloaded this as a tar file. If you get
+wierd errors about missing files, this is the problem. 
+</li>
+<li> Ant does not preserve file permissions when a file is copied, moved or 
+archived, because Java does not let it read or write the permissions.
+ Use <tt>&lt;chmod&gt;</tt> to set permissions, and when creating a 
+tar archive, use the <tt>mode</tt> attribute of <tt>&lt;tarfileset&gt;</tt>
+to set the permissions in the tar file, or <code>&lt;apply&gt;</code> the real tar program.
+</li>
+<li> Ant is not symbolic link aware in moves, deletes and when recursing down a tree
+of directories to build up a list of files. Unexpected things can happen.
+</li>
+<li> Linux on IA-64: apparently you need a larger heap than the default
+one (64M) to compile big projects. If you get out of heap
+errors, either increase the heap or use a forking javac. Better yet,
+use jikes for extra compilation speed.   
+</li>
+
+</ul>
+
+
+<h2>Microsoft Windows</h2>
+<p>
+Windows 9x (win95, win98, win98SE and winME) are not supported in Ant1.7,
+</p>
+
+<p>
+The Ant team has retired support for these products because they are outdated and
+can expose customers to security risks. We recommend that customers who are
+still running Windows 98 or Windows Me upgrade to a newer, more secure 
+operating system, as soon as possible.
+</p>
+<p>
+Customers who upgrade to Linux report improved security, richer
+functionality, and increased productivity. 
+</p>
+<h2>Microsoft Windows 2K, XP and Server 2K03 </h2>
+
+<p>
+Windows 9x (win95, win98, win98SE and winME) has a batch file system which
+does not work fully with long file names, so we recommend that ant and the JDK
+are installed into directories without spaces, and with 8.3 filenames. 
+The Perl and Python launcher scripts do not suffer from this limitation.
+</p>
+<p>
+All versions of windows are usually case insensitive, although mounted 
+file systems (Unix drives, Clearcase views) can be case sensitive underneath,
+confusing patternsets.
+</p>
+<p>
+Ant can often not delete a directory which is open in an Explorer window. 
+There is nothing we can do about this short of spawning a program to kill
+the shell before deleting directories.
+Nor can files that are in use be overwritten.
+</p>
+<p>
+    Finally, if any Ant task fails with an IOError=2, it means that whatever
+    native program Ant is trying to run, it is not on the path.
+</p>
+
+<h2>Microsoft Windows Vista</h2>
+<p>
+    There are reports of problems with Windows Vista security bringing up
+    dialog boxes asking if the user wants to run an untrusted executable
+    during an ant run, such as when the &lt;signjar&gt task runs the jarsigner.exe
+    program. This is beyond Ant's control, and stems from the OS trying to provide
+    some illusion of security by being reluctant to run unsigned native executables.
+    The latest Java versions appear to resolve this problem by having signed
+    binaries. 
+</p>
+
+
+<h2>Cygwin</h2>
+
+Cygwin is not an operating system; rather it is an application suite 
+running under Windows and providing some UNIX like functionality. Sun has 
+not created any specific Java Development Kit or Java Runtime Environment for 
+cygwin. See this link : 
+<a href="http://www.inonit.com/cygwin/faq/">http://www.inonit.com/cygwin/faq/</a> . 
+Only Windows path 
+names are supported by JDK and JRE tools under Windows or cygwin. Relative path 
+names such as "src/org/apache/tools" are supported, but Java tools do not 
+understand /cygdrive/c to mean c:\.
+<p>
+The utility cygpath (used industrially in the ant script to support cygwin) can 
+convert cygwin path names to Windows.
+You can use the <code>&lt;exec&gt;</code> task in ant to convert cygwin paths to Windows path, for 
+instance like that :
+<pre>
+&lt;property name=&quot;some.cygwin.path&quot; value=&quot;/cygdrive/h/somepath&quot;/&gt;
+&lt;exec executable=&quot;cygpath&quot; outputproperty=&quot;windows.pathname&quot;&gt;
+   &lt;arg value=&quot;--windows&quot;/&gt;
+   &lt;arg value=&quot;${some.cygwin.path}&quot;/&gt;
+&lt;/exec&gt;
+&lt;echo message=&quot;${windows.pathname}&quot;/&gt;
+</pre>
+
+We get lots of support calls from Cygwin users. Either it is incredibly
+popular, or it is trouble. If you do use it, remember that Java is a
+Windows application, so Ant is running in a Windows process, not a
+Cygwin one. This will save us having to mark your bug reports as invalid. 
+
+<h2>Apple MacOS X</h2>
+
+MacOS X is the first of the Apple platforms that Ant supports completely;
+it is treated like any other Unix. 
+
+<h2>Novell Netware</h2>
+
+<p>To give the same level of sophisticated control as Ant's startup scripts on other platforms, it was decided to make the main ant startup on NetWare be via a Perl Script, "runant.pl".  This is found in the bin directory (for instance - bootstrap\bin or dist\bin).</p>
+
+<p>One important item of note is that you need to set up the following to run ant:</p>
+<ul><li><code>CLASSPATH</code> - put ant.jar, xercesImpl.jar, xml-apis.jar and any other needed jars on the system classpath.</li>
+   <li><code>ANT_OPTS</code> - On NetWare, <code>ANT_OPTS</code> needs to include a parameter of the form, <nobr>"-envCWD=<code>ANT_HOME</code>"</nobr>, with <code>ANT_HOME</code> being the fully expanded location of Ant, <b>not</b> an environment variable.  This is due to the fact that the NetWare System Console has no notion of a current working directory.</li>
+</ul>
+<p>It is suggested that you create up an ant.ncf that sets up these parameters, and calls <code>perl ANT_HOME/dist/bin/runant.pl</code></p>
+<p>The following is an example of such an NCF file(assuming ant is installed in <nobr>'sys:/apache-ant/'):</nobr></p>
+<code>
+   &nbsp;&nbsp;&nbsp;envset CLASSPATH=SYS:/apache-ant/bootstrap/lib/ant.jar<br>
+   &nbsp;&nbsp;&nbsp;envset CLASSPATH=$CLASSPATH;SYS:/apache-ant/lib/xercesImpl.jar <br>
+   &nbsp;&nbsp;&nbsp;envset CLASSPATH=$CLASSPATH;SYS:/apache-ant/lib/xml-apis.jar <br>
+   &nbsp;&nbsp;&nbsp;envset CLASSPATH=$CLASSPATH;SYS:/apache-ant/lib/optional/junit.jar <br>
+   &nbsp;&nbsp;&nbsp;envset CLASSPATH=$CLASSPATH;SYS:/apache-ant/bootstrap/lib/optional.jar <br>
+<br>
+   &nbsp;&nbsp;&nbsp;setenv ANT_OPTS=-envCWD=sys:/apache-ant <br>
+   &nbsp;&nbsp;&nbsp;envset ANT_OPTS=-envCWD=sys:/apache-ant <br>
+   &nbsp;&nbsp;&nbsp;setenv ANT_HOME=sys:/apache-ant/dist/lib <br>
+   &nbsp;&nbsp;&nbsp;envset ANT_HOME=sys:/apache-ant/dist/lib <br>
+<br>
+   &nbsp;&nbsp;&nbsp;perl sys:/apache-ant/dist/bin/runant.pl <br>
+</code>
+
+<p>Ant works on JVM version 1.3 or higher.  You may have some luck running it on JVM 1.2, but serious problems have been found running Ant on JVM 1.1.7B.  These problems are caused by JVM bugs that will not be fixed.</p>
+<p>JVM 1.3 is supported on Novell NetWare versions 5.1 and higher.</p>
+
+
+<h2>Other platforms</h2>
+Support for other platforms is not guaranteed to be complete, as certain 
+techniques to hide platform details from build files need to be written and
+tested on every particular platform. Contributions in this area are welcome.
+
+
+</html>
diff --git a/trunk/docs/manual/proxy.html b/trunk/docs/manual/proxy.html
new file mode 100644
index 0000000..1a87037
--- /dev/null
+++ b/trunk/docs/manual/proxy.html
@@ -0,0 +1,295 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Proxy Configuration</title>
+</head>
+
+<body>
+<h2>Proxy Configuration</h2>
+
+<p>
+This page discussing proxy issues on command-line ant.
+Consult your IDE documentation for IDE-specific information upon proxy setup.
+</p>
+
+<p>
+
+All tasks and threads running in Ant's JVM share the same HTTP/FTP/Socks
+proxy configuration.
+</p>
+
+<p>
+    When any task tries to retrieve content from an HTTP page, including the
+    <code>&lt;get&gt;</code> task, any automated URL retrieval in
+    an XML/XSL task, or any third-party task that uses the <code>java.net.URL</code>
+    classes, the proxy settings may make the difference between success and failure.
+</p>
+<p>
+    Anyone authoring a build file behind a blocking firewall will immediately appreciate
+    the problems and may want to write a build file to deal with the problem, but
+    users of third party build build files may find that the build file itself
+    does not work behind the firewall.
+</p>
+<p>
+    This is a long standing problem with Java and Ant. The only way to fix
+    it is to explictly configure Ant with the proxy settings, either
+    by passing down the proxy details as JVM properties, or to
+    tell Ant on a Java1.5+ system to have the JVM work it out for itself.
+
+</p>
+
+
+
+<h3>Java1.5+ proxy support (new for Ant1.7)</h3>
+<p>
+    When Ant starts up, if the <code>-autoproxy</code>
+    command is supplied, Ant sets the
+    <code>java.net.useSystemProxies</code> system property. This tells 
+    a Java1.5+ JVM to use the current set of property settings of the host
+    environment. Other JVMs, such as the Kaffe and Apache Harmony runtimes,
+    may also use this property in future.
+    It is ignored on the Java1.4 and earlier runtimes.
+</p>
+<p>
+    This property maybe enough to give command-line Ant
+    builds network access, although in practise the results
+    are inconsistent.
+</p>
+<p>
+    It is has also been reported a breaking the IBM Java 5 JRE on AIX,
+    and does not always work on Linux (presumably due to missing gconf settings)
+    Other odd things can go wrong, like Oracle JDBC drivers or pure Java SVN clients.
+</p>
+
+<p>
+    To make the <code>-autoproxy</code> option the default, add it to the environment variable
+    <code>ANT_ARGS</code>, which contains a list of arguments to pass to Ant on every
+    command line run.
+</p>
+
+<h4>How Autoproxy works</h4>
+<p>
+We are grateful for some input from Sun as to how the proxy code works under
+Java 1.5 and up. The <code>java.net.useSystemProxies</code> is checked only
+once, at startup time, the other checks (registry, gconf, system properties) are done
+dynamically whenever needed (socket connection, URL connection etc..).
+</p>
+<h5>Windows</h5>
+
+<p>
+The JVM goes straight to the registry, bypassing WinInet, as it is not
+present/consistent on all supported Windows platforms (it is part of IE,
+really). Java 7 may use the Windows APIs on the platforms when it is present.
+</p>
+
+<h5>Linux</h5>
+
+<p>
+The JVM uses the gconf library to look at specific entries.
+The GConf-2 settings used are:
+</p>
+<pre>
+ - /system/http_proxy/use_http_proxy            boolean
+ - /system/http_proxy/use_authentication        boolean
+ - /system/http_proxy/host                      string
+ - /system/http_proxy/authentication_user       string
+ - /system/http_proxy/authentication_password   string
+ - /system/http_proxy/port                      int
+ - /system/proxy/socks_host                     string
+ - /system/proxy/mode                           string
+ - /system/proxy/ftp_host                       string
+ - /system/proxy/secure_host                    string
+ - /system/proxy/socks_port                     int
+ - /system/proxy/ftp_port                       int
+ - /system/proxy/secure_port                    int
+ - /system/proxy/no_proxy_for                   list
+ - /system/proxy/gopher_host                    string
+ - /system/proxy/gopher_port                    int
+</pre>
+<p>
+If you are using KDE or another GUI than Gnome, you can still use the
+<code>gconf-editor</code> tool to add these entries.
+</p>
+
+
+<h3>Manual JVM options</h3>
+<p>
+    Any JVM can have its proxy options explicitly configured by passing
+    the appropriate <code>-D</code> system property options to the runtime.
+    Ant can be configured through all its shell scripts via the
+    <code>ANT_OPTS</code> environment variable, which is a list of options to
+    supply to Ant's JVM:
+</p>
+<p>
+  For bash:
+</p>  
+<pre>
+    export ANT_OPTS="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+</pre>
+  For csh/tcsh:
+<pre>
+    setenv ANT_OPTS "-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+</pre>
+<p>
+If you insert this line into the Ant shell script itself, it gets picked up
+by all continuous integration tools running on the system that call Ant via the
+command line.
+</p>
+<p>
+  For Windows, set the <code>ANT_OPTS</code> environment variable in the appropriate "My Computer" 
+  properties dialog box (winXP), "Computer" properties (Vista)
+</p>
+<p>
+  This mechanism works across Java versions, is cross-platform and reliable. 
+  Once set, all build files run via the command line will automatically have
+  their proxy setup correctly, without needing any build file changes. It also
+  apparently overrides Ant's automatic proxy settings options.
+</p>
+<p>  
+  It is limited in the following ways:
+</p>  
+  <ol>
+  <li>Does not work under IDEs. These need their own proxy settings changed</li>
+  <li>Not dynamic enough to deal with laptop configuration changes.</li>
+  </ol>
+
+
+<h3>SetProxy Task</h3>
+<p>
+    The <a href="OptionalTasks/setproxy.html">setproxy task</a> can be used to
+    explicitly set a proxy in a build file. This manipulates the many proxy 
+    configuration properties of a JVM, and controls the proxy settings for all 
+    network operations in the same JVM from that moment. 
+</p>
+<p>
+    If you have a build file that is only to be used in-house, behind a firewall, on
+    an older JVM, <i>and you cannot change Ant's JVM proxy settings</i>, then
+    this is your best option. It is ugly and brittle, because the build file now contains
+    system configuration information. It is also hard to get this right across
+    the many possible proxy options of different users (none, HTTP, SOCKS).
+</p>
+
+
+<p>
+    Note that proxy configurations set with this task will probably override
+    any set by other mechanisms. It can also be used with fancy tricks to 
+    only set a proxy if the proxy is considered reachable:
+</p>
+
+<pre>
+  &lt;target name="probe-proxy" depends="init"&gt;
+    &lt;condition property="proxy.enabled"&gt;
+      &lt;and&gt;
+        &lt;isset property="proxy.host"/&gt;
+        &lt;isreachable host="${proxy.host}"/&gt;
+      &lt;/and&gt;
+    &lt;/condition&gt;
+  &lt;/target&gt;
+
+  &lt;target name="proxy" depends="probe-proxy" if="proxy.enabled"&gt;
+    &lt;property name="proxy.port" value="80"/&gt;
+    &lt;property name="proxy.user" value=""/&gt;
+    &lt;property name="proxy.pass" value=""/&gt;
+    &lt;setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"
+      proxyuser="${proxy.user}" proxypassword="${proxy.pass}"/&gt;
+  &lt;/target&gt;
+</pre>
+
+<h3>Custom ProxySelector implementations</h3>
+<p>
+    As Java lets developers write their own ProxySelector implementations, it 
+    is theoretically possible for someone to write their own proxy selector class that uses
+    different policies to determine proxy settings. There is no explicit support
+    for this in Ant, and it has not, to the team's knowledge, been attempted. 
+</p>
+<p>
+    This could be the most flexible of solutions, as one could easily imagine
+    an Ant-specific proxy selector that was driven off ant properties, rather
+    than system properties. Developers could set proxy options in their
+    custom build.properties files, and have this propagate.
+</p>
+<p>
+    One issue here is with concurrency: the default proxy selector is per-JVM,
+    not per-thread, and so the proxy settings will apply to all sockets opened
+    on all threads; we also have the problem of how to propagate options from
+    one build to the JVM-wide selector.
+</p>
+
+<h3>Configuring the Proxy settings of Java programs under Ant</h3>
+
+<p>
+    Any program that is executed with <code>&lt;java&gt;</code> without setting
+    <code>fork="true"</code> will pick up the Ant's settings. If you need
+    different values, set <code>fork="false"</code> and provide the values
+    in <code>&lt;sysproperty&gt;</code> elements.
+</p>    
+    If you wish to have
+    a forked process pick up the Ant's settings, use the 
+    <a href="CoreTypes/propertyset.html"><code>&lt;syspropertyset&gt;</code></a>
+    element to propagate the normal proxy settings. The following propertyset
+    is a datatype which can be referenced in a <code>&lt;java&gt;</code> task to
+    pass down the current values.
+    
+</p>
+<pre>
+&lt;propertyset id="proxy.properties">
+  &lt;propertyref prefix="java.net.useSystemProxies"/>
+  &lt;propertyref prefix="http."/>
+  &lt;propertyref prefix="https."/>
+  &lt;propertyref prefix="ftp."/>
+  &lt;propertyref prefix="socksProxy"/>
+&lt;/propertyset>
+</pre>
+
+<h3>Summary and conclusions</h3>
+<p>
+There are four ways to set up proxies in Ant.
+</p>
+<ol>
+<li>With Ant1.7 and Java 1.5+ using the <code>-autoproxy</code> parameter.</li>
+<li>Via JVM system properties -set these in the ANT_ARGS environment variable.</li>
+<li>Via the &lt;setproxy&gt; task.</li>
+<li>Custom ProxySelector implementations</li>
+</ol>
+<p>
+Proxy settings are automatically shared with Java programs started under Ant <i>
+that are not forked</i>; to pass proxy settings down to subsidiary programs, use
+a propertyset.
+</p>
+<p>
+Over time, we expect the Java 5+ proxy features to stabilize, and for Java code
+to adapt to them. However, given the fact that it currently does break some
+builds, it will be some time before Ant enables the automatic proxy feature by
+default. Until then, you have to enable the <code>-autoproxy</code> option or
+use one of the alternate mechanisms to configure the JVM.
+
+<h4>Further reading</h4>
+
+<ul>
+<li><a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
+Java Networking Properties</a>. Notice how not all proxy settings are documented
+there.
+<li><a href="http://blogs.sun.com/roller/resources/jcc/Proxies.pdf">Proxies</a>
+</li>
+</ul>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/running.html b/trunk/docs/manual/running.html
new file mode 100644
index 0000000..90c24af
--- /dev/null
+++ b/trunk/docs/manual/running.html
@@ -0,0 +1,584 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Running Apache Ant</title>
+</head>
+
+<body>
+
+<h1>Running Ant</h1>
+<h2><a name="commandline">Command Line</a></h2>
+<p> If you've installed Ant as described in the
+<a href="install.html"> Installing Ant</a> section,
+running Ant from the command-line is simple: just type
+<code>ant</code>.</p>
+<p>When no arguments are specified, Ant looks for a <code>build.xml</code>
+file in the current directory and, if found, uses that file as the
+build file and runs the target specified in the <code>default</code>
+attribute of the <code>&lt;project&gt;</code> tag.
+To make Ant use
+a build file other than <code>build.xml</code>, use the command-line
+option <nobr><code>-buildfile <i>file</i></code></nobr>,
+where <i>file</i> is the name of the build file you want to use.</p>
+If you use the <nobr><code>-find [<i>file</i>]</code></nobr> option,
+Ant will search for a build file first in the current directory, then in
+the parent directory, and so on, until either a build file is found or the root
+of the filesystem has been reached. By default, it will look for a build file
+called <code>build.xml</code>. To have it search for a build file other
+than <code>build.xml</code>, specify a file argument.
+<strong>Note:</strong> If you include any other flags or arguments
+on the command line after
+the <nobr><code>-find</code></nobr> flag, you must include the file argument
+for the <nobr><code>-find</code></nobr> flag, even if the name of the
+build file you want to find is <code>build.xml</code>.
+
+<p>You can also set <a href="using.html#properties">properties</a> on the
+command line.  This can be done with
+the <nobr><code>-D<i>property</i>=<i>value</i></code></nobr> option,
+where <i>property</i> is the name of the property,
+and <i>value</i> is the value for that property. If you specify a
+property that is also set in the build file
+(see the <a href="CoreTasks/property.html">property</a> task),
+the value specified on the
+command line will override the value specified in the
+build file.
+Defining properties on the command line can also be used to pass in
+the value of environment variables; just pass
+<nobr><code>-DMYVAR=%MYVAR%</code></nobr> (Windows) or
+<nobr><code>-DMYVAR=$MYVAR</code></nobr> (Unix)
+to Ant. You can then access
+these variables inside your build file as <code>${MYVAR}</code>.
+You can also access environment variables using the
+<a href="CoreTasks/property.html"> property</a> task's
+<code>environment</code> attribute.
+</p>
+
+<p>Options that affect the amount of logging output by Ant are:
+<nobr><code>-quiet</code></nobr>,
+which instructs Ant to print less
+information to the console;
+<nobr><code>-verbose</code></nobr>, which causes Ant to print
+additional information to the console; and <nobr><code>-debug</code></nobr>,
+which causes Ant to print considerably more additional information.
+</p>
+
+<p>It is also possible to specify one or more targets that should be executed.
+When omitted, the target that is specified in the
+<code>default</code> attribute of the
+<a href="using.html#projects"><code>project</code></a> tag is
+used.</p>
+
+<p>The <nobr><code>-projecthelp</code></nobr> option prints out a list
+of the build file's targets. Targets that include a
+<code>description</code> attribute are listed as &quot;Main targets&quot;,
+those without a <code>description</code> are listed as
+&quot;Other targets&quot;, then the &quot;Default&quot; target is listed
+("Other targets" are only displayed if there are no main
+targets, or if Ant is invoked in -verbose or -debug mode).
+
+<h3><a name="options">Command-line Options Summary</a></h3>
+<pre>ant [options] [target [target2 [target3] ...]]
+Options:
+  -help, -h              print this message
+  -projecthelp, -p       print project help information
+  -version               print the version information and exit
+  -diagnostics           print information that might be helpful to
+                         diagnose or report problems.
+  -quiet, -q             be extra quiet
+  -verbose, -v           be extra verbose
+  -debug, -d             print debugging information
+  -emacs, -e             produce logging information without adornments
+  -lib &lt;path&gt;            specifies a path to search for jars and classes
+  -logfile &lt;file&gt;        use given file for log
+    -l     &lt;file&gt;                ''
+  -logger &lt;classname&gt;    the class which is to perform logging
+  -listener &lt;classname&gt;  add an instance of class as a project listener
+  -noinput               do not allow interactive input
+  -buildfile &lt;file&gt;      use given buildfile
+    -file    &lt;file&gt;              ''
+    -f       &lt;file&gt;              ''
+  -D&lt;property&gt;=&lt;value&gt;   use value for given property
+  -keep-going, -k        execute all targets that do not depend
+                         on failed target(s)
+  -propertyfile &lt;name&gt;   load all properties from file with -D
+                         properties taking precedence
+  -inputhandler &lt;class&gt;  the class which will handle input requests
+  -find &lt;file&gt;           (s)earch for buildfile towards the root of
+    -s  &lt;file&gt;           the filesystem and use it
+  -nice  number          A niceness value for the main thread:
+                         1 (lowest) to 10 (highest); 5 is the default
+  -nouserlib             Run ant without using the jar files from ${user.home}/.ant/lib
+  -noclasspath           Run ant without using CLASSPATH
+  -autoproxy             Java 1.5+ : use the OS proxies
+  -main &lt;class&gt;          override Ant's normal entry point
+</pre>
+<p>For more information about <code>-logger</code> and
+<code>-listener</code> see
+<a href="listeners.html">Loggers &amp; Listeners</a>.
+<p>For more information about <code>-inputhandler</code> see
+<a href="inputhandler.html">InputHandler</a>.
+<p>Easiest way of changing the exit-behaviour is subclassing the original main class:
+<pre>
+public class CustomExitCode extends org.apache.tools.ant.Main {
+    protected void exit(int exitCode) {
+        // implement your own behaviour, e.g. NOT exiting the JVM
+    }
+}
+</pre> and starting Ant with access (<tt>-lib path-to-class</tt>) to this class.
+</p>
+
+<h3><a name="libs">Library Directories</a></h3>
+<p>
+Prior to Ant 1.6, all jars in the ANT_HOME/lib would be added to the CLASSPATH
+used to run Ant. This was done in the scripts that started Ant. From Ant 1.6,
+two directories are scanned by default and more can be added as required. The
+default directories scanned are ANT_HOME/lib and a user specific directory,
+${user.home}/.ant/lib. This arrangement allows the Ant installation to be
+shared by many users while still allowing each user to deploy additional jars.
+Such additional jars could be support jars for Ant's optional tasks or jars
+containing third-party tasks to be used in the build. It also allows the main Ant installation to be locked down which will please system adminstrators.
+</p>
+
+<p>
+Additional directories to be searched may be added by using the -lib option.
+The -lib option specifies a search path. Any jars or classes in the directories
+of the path will be added to Ant's classloader. The order in which jars are
+added to the classpath is as follows:
+</p>
+
+<ul>
+  <li>-lib jars in the order specified by the -lib elements on the command line</li>
+  <li>jars from ${user.home}/.ant/lib (unless -nouserlib is set)</li>
+  <li>jars from ANT_HOME/lib</li>
+</ul>
+
+<p>
+Note that the CLASSPATH environment variable is passed to Ant using a -lib
+option. Ant itself is started with a very minimalistic classpath.
+Ant should work perfectly well with an empty CLASSPATH environment variable,
+something the the -noclasspath option actually enforces. We get many more support calls related to classpath problems (especially quoting problems) than
+we like.
+
+</p>
+
+<p>
+The location of ${user.home}/.ant/lib is somewhat dependent on the JVM. On Unix
+systems ${user.home} maps to the user's home directory whilst on recent
+versions of Windows it will be somewhere such as
+C:\Documents&nbsp;and&nbsp;Settings\username\.ant\lib. You should consult your
+JVM documentation for more details.
+</p>
+
+<h3>Examples</h3>
+<blockquote>
+  <pre>ant</pre>
+</blockquote>
+<p>runs Ant using the <code>build.xml</code> file in the current directory, on
+the default target.</p>
+<blockquote>
+  <pre>ant -buildfile test.xml</pre>
+</blockquote>
+<p>runs Ant using the <code>test.xml</code> file in the current directory, on
+the default target.</p>
+<blockquote>
+  <pre>ant -buildfile test.xml dist</pre>
+</blockquote>
+<p>runs Ant using the <code>test.xml</code> file in the current directory, on
+the target called <code>dist</code>.</p>
+<blockquote>
+  <pre>ant -buildfile test.xml -Dbuild=build/classes dist</pre>
+</blockquote>
+<p>runs Ant using the <code>test.xml</code> file in the current directory, on
+the target called <code>dist</code>, setting the <code>build</code> property
+to the value <code>build/classes</code>.</p>
+
+<blockquote>
+  <pre>ant -lib /home/ant/extras</pre>
+</blockquote>
+<p>runs Ant picking up additional task and support jars from the
+/home/ant/extras location
+</p>
+
+<h3><a name="files">Files</a></h3>
+
+<p>The Ant wrapper script for Unix will source (read and evaluate) the
+file <code>~/.antrc</code> before it does anything. On Windows, the Ant
+wrapper batch-file invokes <code>%HOME%\antrc_pre.bat</code> at the start and
+<code>%HOME%\antrc_post.bat</code> at the end.  You can use these
+files, for example, to set/unset environment variables that should only be
+visible during the execution of Ant.  See the next section for examples.</p>
+
+<h3><a name="envvars">Environment Variables</a></h3>
+
+<p>The wrapper scripts use the following environment variables (if
+set):</p>
+
+<ul>
+  <li><code>JAVACMD</code> - full path of the Java executable.  Use this
+  to invoke a different JVM than <code>JAVA_HOME/bin/java(.exe)</code>.</li>
+
+  <li><code>ANT_OPTS</code> - command-line arguments that should be
+  passed to the JVM. For example, you can define system properties or set
+  the maximum Java heap size here.</li>
+
+  <li><code>ANT_ARGS</code> - Ant command-line arguments. For example,
+  set <code>ANT_ARGS</code> to point to a different logger, include a
+  listener, and to include the <code>-find</code> flag.</li>
+  <strong>Note:</strong> If you include <code>-find</code>
+  in <code>ANT_ARGS</code>, you should include the name of the build file
+  to find, even if the file is called <code>build.xml</code>.
+</ul>
+
+<h3><a name="sysprops">Java System Properties</a></h3>
+<p>Some of Ant's core classes can be configured via system properties.</p>
+<p>Here is the result of a search through the codebase. Because system properties are
+available via Project instance, I searched for them with a
+<pre>
+    grep -r -n "getPropert" * &gt; ..\grep.txt
+</pre>
+command. After that I filtered out the often-used but not-so-important values (most of them
+read-only values): <i>path.separator, ant.home, basedir, user.dir, os.name,
+line.separator, java.home, java.version, java.version, user.home, java.class.path</i><br>
+And I filtered out the <i>getPropertyHelper</i> access.</p>
+<table border="1">
+<tr>
+  <th>property name</th>
+  <th>valid values /default value</th>
+  <th>description</th>
+</tr>
+<tr>
+  <td><code>ant.build.javac.source</code></td>
+  <td>Source-level version number</td>
+  <td>Default <em>source</em> value for &lt;javac&gt;/&lt;javadoc&gt;</td>
+</tr>
+<tr>
+  <td><code>ant.build.javac.target</code></td>
+  <td>Class-compatibility version number</td>
+  <td>Default <em>target</em> value for &lt;javac&gt;</td>
+</tr>
+<tr>
+  <td><code>ant.executor.class</code></td>
+  <td>classname; default is org. apache. tools. ant. helper. DefaultExecutor</td>
+  <td><b>Since Ant 1.6.3</b> Ant will delegate Target invocation to the
+org.apache.tools.ant.Executor implementation specified here.
+  </td>
+</tr>
+
+<tr>
+  <td><code>ant.file</code></td>
+  <td>read only: full filename of the build file</td>
+  <td>This is set to the name of the build file. In
+  <a href="CoreTasks/import.html">
+  &lt;import&gt;-ed</a> files, this is set to the containing build file.
+  </td>
+</tr>
+
+<tr>
+  <td><code>ant.file.*</code></td>
+  <td>read only: full filename of the build file of Ant projects
+  </td>
+  <td>This is set to the name of a file by project;
+  this lets you determine the location of <a href="CoreTasks/import.html">
+  &lt;import&gt;-ed</a> files,
+  </td>
+</tr>
+
+<tr>
+  <td><code>ant.input.properties</code></td>
+  <td>filename (required)</td>
+  <td>Name of the file holding the values for the
+      <a href="inputhandler.html">PropertyFileInputHandler</a>.
+  </td>
+</tr>
+<tr>
+  <td><code>ant.logger.defaults</code></td>
+  <!-- add the blank after the slash, so the browser can do a line break -->
+  <td>filename (optional, default '/org/ apache/ tools/ ant/ listener/ defaults.properties')</td>
+  <td>Name of the file holding the color mappings for the
+      <a href="listeners.html#AnsiColorLogger">AnsiColorLogger</a>.
+  </td>
+</tr>
+<tr>
+  <td><code>ant.netrexxc.*</code></td>
+  <td>several formats</td>
+  <td>Use specified values as defaults for <a href="OptionalTasks/netrexxc.html">netrexxc</a>.
+  </td>
+</tr>
+<tr>
+  <td><code>ant.PropertyHelper</code></td>
+  <td>ant-reference-name (optional)</td>
+  <td>Specify the PropertyHelper to use. The object must be of the type
+      org.apache.tools.ant.PropertyHelper. If not defined an object of
+      org.apache.tools.ant.PropertyHelper will be used as PropertyHelper.
+  </td>
+</tr>
+<tr>
+  <td><code>ant.regexp.regexpimpl</code></td>
+  <td>classname</td>
+  <td>classname for a RegExp implementation; if not set Ant tries to
+      find another (JDK14+, Apache Oro...);
+      <a href="CoreTypes/mapper.html#regexp-mapper">RegExp-Mapper</a>
+      "Choice of regular expression implementation"
+  </td>
+</tr>
+<tr>
+  <td><code>ant.reuse.loader</code></td>
+  <td>boolean</td>
+  <td>allow to reuse classloaders
+      used in org.apache.tools.ant.util.ClasspathUtil
+  </td>
+</tr>
+<tr>
+  <td><code>ant.XmlLogger.stylesheet.uri</code></td>
+  <td>filename (default 'log.xsl')</td>
+  <td>Name for the stylesheet to include in the logfile by
+      <a href="listeners.html#XmlLogger">XmlLogger</a>.
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler</code></td>
+  <td>name</td>
+  <td>Specify the default compiler to use.
+      see <a href="CoreTasks/javac.html">javac</a>,
+      <a href="OptionalTasks/ejb.html#ejbjar_weblogic">EJB Tasks</a>
+      (compiler attribute),
+      <a href="OptionalTasks/javah.html">javah</a>
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler.emacs</code></td>
+  <td>boolean (default false)</td>
+  <td>Enable emacs-compatible error messages.
+      see <a href="CoreTasks/javac.html">javac</a> "Jikes Notes"
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler.fulldepend</code></td>
+  <td>boolean (default false)</td>
+  <td>Enable full dependency checking
+      see <a href="CoreTasks/javac.html">javac</a> "Jikes Notes"
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler.jvc.extensions</code></td>
+  <td>boolean (default true)</td>
+  <td>enable Microsoft extensions of their java compiler
+      see <a href="CoreTasks/javac.html">javac</a> "Jvc Notes"
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler.pedantic</code></td>
+  <td>boolean (default false)</td>
+  <td>Enable pedantic warnings.
+      see <a href="CoreTasks/javac.html">javac</a> "Jikes Notes"
+  </td>
+</tr>
+<tr>
+  <td><code>build.compiler.warnings</code></td>
+  <td>Deprecated flag</td>
+  <td> see <a href="CoreTasks/javac.html">javac</a> "Jikes Notes" </td>
+</tr>
+<tr>
+  <td><code>build.rmic</code></td>
+  <td>name</td>
+  <td>control the <a href="CoreTasks/rmic.html">rmic</a> compiler </td>
+</tr>
+<tr>
+  <td><code>build.sysclasspath</code></td>
+  <td>"only", something else</td>
+  <td>only: current threads get the actual class loader
+      (AntClassLoader.setThreadContextLoader()).
+      else: use core loader as default (ComponentHelper.initTasks()). Disable
+      changing the classloader (oata.taskdefs.Classloader.execute() experimental
+      task).
+      <!-- somewhere documented in the manual?? -->
+  </td>
+</tr>
+<tr>
+  <td><code>file.encoding</code></td>
+  <td>name of a supported character set (e.g. UTF-8, ISO-8859-1, US-ASCII)</td>
+  <td>use as default character set of email messages; use as default for source-, dest- and bundleencoding
+      in <a href="OptionalTasks/translate.html">translate</a> <br>
+      see JavaDoc of <a target="_blank" href="http://java.sun.com/j2se/1.4.2/docs/api/java/nio/charset/Charset.html">java.nio.charset.Charset</a>
+      for more information about character sets (not used in Ant, but has nice docs).
+  </td>
+</tr>
+<tr>
+  <td><code>jikes.class.path</code></td>
+  <td>path</td>
+  <td>The specified path is added to the classpath if jikes is used as compiler.</td>
+</tr>
+<tr>
+  <td><code>MailLogger.properties.file, MailLogger.*</code></td>
+  <td>filename (optional, defaults derived from Project instance)</td>
+  <td>Name of the file holding properties for sending emails by the
+      <a href="listeners.html#MailLogger">MailLogger</a>. Override properties set
+      inside the buildfile or via command line.
+  </td>
+</tr>
+<tr>
+  <td><code>org.apache.tools.ant.ProjectHelper</code></td>
+  <!-- add the blank after the slash, so the browser can do a line break -->
+  <td>classname (optional, default 'org.apache.tools.ant.ProjectHelper')</td>
+  <td>specifies the classname to use as ProjectHelper. The class must extend
+      org.apache.tools.ant.ProjectHelper.
+  </td>
+</tr>
+<tr>
+  <td><code>p4.port, p4.client, p4.user</code></td>
+  <td>several formats</td>
+  <td>Specify defaults for port-, client- and user-setting of the
+      <a href="OptionalTasks/perforce.html">perforce</a> tasks.
+  </td>
+</tr>
+<tr>
+  <td><code>websphere.home
+  <td>path</td>
+  <td>Points to home directory of websphere.
+      see <a href="OptionalTasks/ejb.html#ejbjar_websphere">EJB Tasks</a>
+  </td>
+</tr>
+<tr>
+  <td><code>XmlLogger.file
+  <td>filename (default 'log.xml')</td>
+  <td>Name for the logfile for <a href="listeners.html#MailLogger">MailLogger</a>.
+  </td>
+</tr>
+</table>
+
+<p>
+If new properties get added (it happens), expect them to appear under the
+"ant." and "org.apache.tools.ant" prefixes, unless the developers have a
+very good reason to use another prefix. Accordingly, please avoid using
+properties that begin with these prefixes. This protects you from future
+Ant releases breaking your build file.
+</p>
+<h3>return code</h3>
+<p>the ant start up scripts (in their Windows and Unix version) return
+the return code of the java program. So a successful build returns 0,
+failed builds return other values.
+</p>
+
+<h2><a name="cygwin">Cygwin Users</a></h2>
+<p>The Unix launch script that come with Ant works correctly with Cygwin. You
+should not have any problems launching Ant from the Cygwin shell. It is
+important to note, however, that once Ant is running it is part of the JDK
+which operates as a native Windows application. The JDK is not a Cygwin
+executable, and it therefore has no knowledge of Cygwin paths, etc. In
+particular when using the <code>&lt;exec&gt;</code> task, executable names such
+as &quot;/bin/sh&quot; will not work, even though these work from the Cygwin
+shell from which Ant was launched. You can use an executable name such as
+&quot;sh&quot; and rely on that command being available in the Windows path.
+</p>
+
+<h2><a name="os2">OS/2 Users</a></h2>
+<p>The OS/2 launch script was developed to perform complex tasks. It has two parts:
+<code>ant.cmd</code> which calls Ant and <code>antenv.cmd</code> which sets the environment for Ant.
+Most often you will just call <code>ant.cmd</code> using the same command line options as described
+above. The behaviour can be modified by a number of ways explained below.</p>
+
+<p>Script <code>ant.cmd</code> first verifies whether the Ant environment is set correctly. The
+requirements are:</p>
+<ol>
+<li>Environment variable <code>JAVA_HOME</code> is set.</li>
+<li>Environment variable <code>ANT_HOME</code> is set.</li>
+<li>Environment variable <code>CLASSPATH</code> is set and contains at least one element from
+<code>JAVA_HOME</code> and at least one element from <code>ANT_HOME</code>.</li>
+</ol>
+
+<p>If any of these conditions is violated, script <code>antenv.cmd</code> is called. This script
+first invokes configuration scripts if there exist: the system-wide configuration
+<code>antconf.cmd</code> from the <code>%ETC%</code> directory and then the user configuration
+<code>antrc.cmd</code> from the <code>%HOME%</code> directory. At this moment both
+<code>JAVA_HOME</code> and <code>ANT_HOME</code> must be defined because <code>antenv.cmd</code>
+now adds <code>classes.zip</code> or <code>tools.jar</code> (depending on version of JVM) and
+everything from <code>%ANT_HOME%\lib</code> except <code>ant-*.jar</code> to
+<code>CLASSPATH</code>. Finally <code>ant.cmd</code> calls per-directory configuration
+<code>antrc.cmd</code>. All settings made by <code>ant.cmd</code> are local and are undone when the
+script ends. The settings made by <code>antenv.cmd</code> are persistent during the lifetime of the
+shell (of course unless called automatically from <code>ant.cmd</code>). It is thus possible to call
+<code>antenv.cmd</code> manually and modify some settings before calling <code>ant.cmd</code>.</p>
+
+<p>Scripts <code>envset.cmd</code> and <code>runrc.cmd</code> perform auxiliary tasks. All scripts
+have some documentation inside.</p>
+
+<h2><a name="viajava">Running Ant via Java</a></h2>
+<p>If you have installed Ant in the do-it-yourself way, Ant can be started
+from one of two entry points:</p>
+<blockquote>
+  <pre>java -Dant.home=c:\ant org.apache.tools.ant.Main [options] [target]</pre>
+</blockquote>
+
+<blockquote>
+  <pre>java -Dant.home=c:\ant org.apache.tools.ant.launch.Launcher [options] [target]</pre>
+</blockquote>
+
+<p>
+The first method runs Ant's traditional entry point. The second method uses
+the Ant Launcher introduced in Ant 1.6. The former method does not support
+the -lib option and all required classes are loaded from the CLASSPATH. You must
+ensure that all required jars are available. At a minimum the CLASSPATH should
+include:
+</p>
+
+<ul>
+<li><code>ant.jar</code> and <code>ant-launcher.jar</code></li>
+<li>jars/classes for your XML parser</li>
+<li>the JDK's required jar/zip files</li>
+</ul>
+
+<p>
+The latter method supports the -lib, -nouserlib, -noclasspath options and will
+    load jars from the specified ANT_HOME. You should start the latter with the most minimal
+classpath possible, generally just the ant-launcher.jar.
+</p>
+
+<a name="viaant"/>
+
+Ant can be started in Ant via the <code>&lt;java&gt;</code> command.
+Here is an example:
+
+<pre>
+&lt;java
+        classname="org.apache.tools.ant.launch.Launcher"
+        fork="true"
+        failonerror="true"
+        dir="${sub.builddir}"
+        timeout="4000000"
+        taskname="startAnt"
+&gt;
+    &lt;classpath&gt;
+        &lt;pathelement location="${ant.home}/lib/ant-launcher.jar"/&gt;
+    &lt;/classpath&gt;
+    &lt;arg value="-buildfile"/&gt;
+    &lt;arg file="${sub.buildfile}"/&gt;
+    &lt;arg value="-Dthis=this"/&gt;
+    &lt;arg value="-Dthat=that"/&gt;
+    &lt;arg value="-Dbasedir=${sub.builddir}"/&gt;
+    &lt;arg value="-Dthe.other=the.other"/&gt;
+    &lt;arg value="${sub.target}"/&gt;
+&lt;/java&gt;
+</pre>
+<br>
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/runninglist.html b/trunk/docs/manual/runninglist.html
new file mode 100644
index 0000000..062d945
--- /dev/null
+++ b/trunk/docs/manual/runninglist.html
@@ -0,0 +1,44 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Running Ant</h3>
+<a href="running.html#commandline">Command Line</a><br/>
+<div style="padding-left:1em">
+  <a href="running.html#options">Options</a><br/>
+  <a href="running.html#libs">Library Directories</a><br/>
+  <a href="running.html#files">Files</a><br/>
+  <a href="running.html#envvars">Environment Variables</a><br/>
+  <a href="running.html#sysprops">Java System Properties</a><br/>
+  <a href="running.html#cygwin">Cygwin Users</a><br/>
+  <a href="running.html#os2">OS/2 Users</a><br/>
+</div>
+<a href="running.html#viajava">Running Ant via Java</a><br/>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/stylesheets/antmanual.css b/trunk/docs/manual/stylesheets/antmanual.css
new file mode 100644
index 0000000..049b2ed
--- /dev/null
+++ b/trunk/docs/manual/stylesheets/antmanual.css
@@ -0,0 +1,20 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * 
+ */
+body {
+    background-image:url(/images/beta.png)
+}
diff --git a/trunk/docs/manual/stylesheets/style.css b/trunk/docs/manual/stylesheets/style.css
new file mode 100644
index 0000000..8d07f65
--- /dev/null
+++ b/trunk/docs/manual/stylesheets/style.css
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+h2 {
+  font-size: 200%;
+  background-color: ffffff;
+}
+
+h3 {
+  font-size: 130%;
+  color:     #ffffff;
+  background-color: #525D76;
+}
+
+h4 {
+  color:  #ffffff;
+  background-color: #828DA6;
+}
+
+td {
+   background-color: eeeeee;
+   color:            000000;
+}
+
+/* first row */
+table tr:first-child td {
+   background-color: cccccc;
+   color:            000000;
+}
+
+/* or th as first row */
+table th {
+   background-color: cccccc;
+   color:            000000;
+}
+
+pre {
+   background-color: efefef;
+}
+
+/* code snippets in examples and tutorials */
+.code { 
+   background: #EFEFEF; 
+   margin-top: 
+}
+
+/* highlight console output */
+.output { 
+   color: #FFFFFF; 
+   background: #837A67; 
+}
+
diff --git a/trunk/docs/manual/sysclasspath.html b/trunk/docs/manual/sysclasspath.html
new file mode 100644
index 0000000..d2d0098
--- /dev/null
+++ b/trunk/docs/manual/sysclasspath.html
@@ -0,0 +1,80 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>build.sysclasspath</title>
+</head>
+
+<body>
+
+<h2><a name="sysclasspath">build.sysclasspath</a></h2>
+<p>The value of the build.sysclasspath property
+control how the system classpath, ie. the classpath in effect when
+Ant is run, affects the behaviour of classpaths in Ant.
+The default behavior varies from Ant to Ant task.</p>
+
+The values and their meanings are:
+
+<table cellspacing="20">
+<tr>
+<th align="left" valign="top">only</th>
+<td>Only the system classpath is used and classpaths specified in build files,
+etc are ignored. This situation could be considered as the person running
+the build file knows more about the environment than the person writing the
+build file
+</td>
+</tr>
+
+<tr>
+<th align="left" valign="top">ignore</th>
+<td>
+The system classpath is ignored. This situation is the reverse of the
+above. The person running the build trusts the build file writer to get the
+build file right
+</td>
+</tr>
+
+<tr>
+<th align="left" valign="top">last</th>
+<td>
+The classpath is concatenated to any specified classpaths at the end. This
+is a compromise, where the build file writer has priority.
+</td>
+</tr>
+
+<tr>
+<th align="left" valign="top">first</th>
+<td>
+Any specified classpaths are concatenated to the system classpath. This is
+the other form of compromise where the build runner has priority.
+</td>
+</tr>
+</table>
+
+<p><em>Since Ant 1.7</em> the value of this property also affects the
+bootclasspath settings--it combines the bootclasspath that has been
+specified for a task with the bootclasspath of the Java VM running
+Ant.  If the property has not been set, it defaults to "ignore" in
+this case.</p>
+
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/tasksoverview.html b/trunk/docs/manual/tasksoverview.html
new file mode 100644
index 0000000..4932f85
--- /dev/null
+++ b/trunk/docs/manual/tasksoverview.html
@@ -0,0 +1,1231 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Overview of Ant Tasks</title>
+  <base target="mainFrame">
+</head>
+
+<body>
+<a name="top"></a>
+<h2>Overview of Ant Tasks</h2>
+<p>Given the large number of tasks available with Ant, it may be
+difficult to get an overall view of what each task can do.  The following
+tables provide a short description of each task and a link to the complete
+documentation.</p>
+
+<a href="#archive">Archive Tasks</a><br>
+<a href="#audit">Audit/Coverage Tasks</a><br>
+<a href="#compile">Compile Tasks</a><br>
+<a href="#deploy">Deployment Tasks</a><br>
+<a href="#doc">Documentation Tasks</a><br>
+<a href="#ejb">EJB Tasks</a><br>
+<a href="#exec">Execution Tasks</a><br>
+<a href="#file">File Tasks</a><br>
+<a href="#extensions">Java2 Extensions Tasks</a><br>
+<a href="#log">Logging Tasks</a><br>
+<a href="#mail">Mail Tasks</a><br>
+<a href="#misc">Miscellaneous Tasks</a><br>
+<a href="#net">.NET Tasks</a><br>
+<a href="#preproc">Pre-process Tasks</a><br>
+<a href="#prop">Property Tasks</a><br>
+<a href="#remote">Remote Tasks</a><br>
+<a href="#scm">SCM Tasks</a><br>
+<a href="#testing">Testing Tasks</a><br>
+<a href="#vaj">Visual Age for Java Tasks</a><br>
+
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="archive">Archive Tasks</a>
+</font>
+</th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th nowrap>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/unpack.html">BUnzip2</a></td>
+    <td><p>Expands a file packed using GZip or BZip2.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/pack.html">BZip2</a></td>
+    <td><p>Packs a file using the GZip or BZip2 algorithm. This task
+     does not do any dependency checking; the output file is always
+     generated</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/cab.html">Cab</a></td>
+    <td><p>Creates Microsoft CAB archive files. It is invoked
+     similar to the <a href="CoreTasks/jar.html">Jar</a> or
+     <a href="CoreTasks/zip.html">Zip</a> tasks. This task will work on
+     Windows using the external <i>cabarc</i> tool (provided by Microsoft),
+     which must be located in your executable path.</p></td>
+   </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/ear.html">Ear</a></td>
+    <td><p>An extension of the <a href="CoreTasks/jar.html">Jar</a> task with
+     special treatment for files that should end up in an
+     Enterprise Application archive.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/gunzip.html">GUnzip</a></td>
+    <td><p>Expands a GZip file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/gzip.html">GZip</a></td>
+    <td><p>GZips a set of files.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/jar.html">Jar</a></td>
+    <td><p>Jars a set of files.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/jlink.html">Jlink</a></td>
+    <td><p><i>Deprecated.</i> Use the <code>zipfileset</code>
+     and <code>zipgroupfileset</code> attributes of the
+     <a href="CoreTasks/jar.html">Jar</a> or
+     <a href="CoreTasks/zip.html">Zip</a> tasks instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/manifest.html">Manifest</a></td>
+    <td><p>Creates a manifest file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/rpm.html">Rpm</a></td>
+    <td><p>Invokes the <i>rpm</i> executable to build a Linux installation
+     file. This task currently only works on Linux or other Unix platforms
+     with RPM support.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/signjar.html">SignJar</a></td>
+    <td><p>Signs a jar or zip file with the <i>javasign</i>
+     command-line tool.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/tar.html">Tar</a></td>
+    <td><p>Creates a tar archive.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/unzip.html">Unjar</a></td>
+    <td><p>Unzips a jarfile.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/untar.html">Untar</a></td>
+    <td><p>Untars a tarfile.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/unzip.html">Unwar</a></td>
+    <td><p>Unzips a warfile.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/unzip.html">Unzip</a></td>
+    <td><p>Unzips a zipfile.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/war.html">War</a></td>
+    <td><p>An extension of the <a href="CoreTasks/jar.html">Jar</a> task
+     with special treatment for files that should end up in the
+     <code>WEB-INF/lib</code>, <code>WEB-INF/classes</code>, or
+     <code>WEB-INF</code> directories of the Web Application Archive.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/zip.html">Zip</a></td>
+    <td><p>Creates a zipfile.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="audit">Audit/Coverage Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/jdepend.html">JDepend</a></td>
+    <td><p>Invokes the <a href="http://www.clarkware.com/software/JDepend.html">
+     JDepend</a> parser. This parser &quot;traverses a set of Java source-file
+     directories and generates design-quality metrics for each Java
+     package&quot;.</p></td>
+   </tr>
+
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="compile">Compile Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/depend.html">Depend</a></td>
+    <td><p>Determines which classfiles are out-of-date with respect to their
+     source, removing the classfiles of any other classes that depend on the
+     out-of-date classes, forcing the re-compile of the removed classfiles.
+     Typically used in conjunction with the
+     <a href="CoreTasks/javac.html">Javac</a> task.</p></td>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/javac.html">Javac</a></td>
+    <td><p>Compiles the specified source file(s) within the running
+     (Ant) VM, or in another VM if the <code>fork</code> attribute is
+     specified.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/apt.html">Apt</a></td>
+    <td><p>Runs the annotation processor tool (apt), and then optionally compiles
+   the original code, and any generated source code.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/jspc.html">JspC</a></td>
+    <td><p>Runs the JSP compiler. It can be used to precompile JSP pages
+     for fast initial invocation of JSP pages, deployment on a server without
+     the full JDK installed, or simply to syntax-check the pages without
+     deploying them. The <a href="CoreTasks/javac.html">Javac</a> task
+     can be used to compile the generated Java source.
+     (For Weblogic JSP compiles,
+     see the <a href="OptionalTasks/wljspc.html">Wljspc</a> task.)</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/netrexxc.html">NetRexxC</a></td>
+    <td><p>Compiles a
+     <a href="http://www2.hursley.ibm.com/netrexx" target="_top">NetRexx</a>
+     source tree within the running (Ant) VM.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/rmic.html">Rmic</a></td>
+    <td><p>Runs the <i>rmic</i> compiler on the specified file(s).</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/wljspc.html">Wljspc</a></td>
+    <td><p>Compiles JSP pages using Weblogic's JSP compiler,
+     <i>weblogic.jspc</i>. (For non-Weblogic JSP compiles, see the
+     <a href="OptionalTasks/jspc.html">JspC</a> task.</p></td>
+  </tr>
+
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="deploy">Deployment Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/serverdeploy.html">ServerDeploy</a></td>
+    <td><p>Task to run a &quot;hot&quot; deployment tool for vendor-specific
+     J2EE server.
+    </p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="doc">Documentation Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/javadoc.html">Javadoc/<i>Javadoc2</i></a></td>
+    <td><p>Generates code documentation using the <i>javadoc</i> tool.
+     The Javadoc2 task is deprecated; use the Javadoc task instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/stylebook.html">Stylebook</a></td>
+    <td><p>Executes the Apache Stylebook documentation generator.
+     Unlike the command-line version of this tool, all three arguments
+     are required to run the Stylebook task.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="ejb">EJB Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/ejb.html">EJB Tasks</a></td>
+    <td><p>(See the documentation describing the EJB tasks.)</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="exec">Execution Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/ant.html">Ant</a></td>
+    <td><p>Runs Ant on a supplied buildfile, optionally
+     passing properties (with possibly new values).
+     This task can be used to build sub-projects.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/antcall.html">AntCall</a></td>
+    <td><p>Runs another target within the same buildfile, optionally
+     passing properties (with possibly new values).</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/apply.html">Apply/<i>ExecOn</i></a></td>
+    <td><p>Executes a system command. When the <code>os</code> attribute is
+     specified, the command is only executed when Ant is run on one
+     of the specified operating systems.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/dependset.html">Dependset</a></td>
+    <td><p>This task compares a set of source files with a set of target
+     files.  If any of the source files is newer than any of
+     the target files, all the target files are removed. </p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/exec.html">Exec</a></td>
+    <td><p>Executes a system command. When the <code>os</code> attribute
+     is specified, the command is only executed when Ant is run on one of
+     the specified operating systems.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/java.html">Java</a></td>
+    <td><p>Executes a Java class within the running (Ant) VM, or in
+     another VM if the <code>fork</code> attribute is specified.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/parallel.html">Parallel</a></td>
+    <td><p>A container task that can contain other Ant tasks.
+     Each nested task specified within the <code>&lt;parallel&gt;</code>
+     tag will be executed in its own thread.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/sequential.html">Sequential</a></td>
+    <td><p>A container task that can contain other Ant tasks.
+     The nested tasks are simply executed in sequence. Its primary use is
+     to support the sequential execution of a subset of tasks within
+     the <code>&lt;parallel&gt;</code> tag.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/sleep.html">Sleep</a></td>
+    <td><p> A task for suspending execution for a specified period of time.
+     Useful when a build or deployment process requires an interval between
+     tasks.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/subant.html">Subant</a></td>
+    <td><p> Calls a given target for all defined sub-builds. This is an extension of ant for bulk project execution.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/waitfor.html">Waitfor</a></td>
+    <td><p>Blocks execution until a set of specified conditions become true.
+     This task is intended to be used with the
+     <a href="CoreTasks/parallel.html">Parallel</a> task to synchronize
+     a set of processes.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="file">File Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/attrib.html">Attrib</a></td>
+    <td><p>Changes the permissions and/or attributes of a file or all
+    files inside the specified directories. Currently, it has effect
+    only under Windows.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/checksum.html">Checksum</a></td>
+    <td><p>Generates a checksum for a file or set of files. This task can
+     also be used to perform checksum verifications.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/chgrp.html">Chgrp</a></td>
+    <td><p>Changes the group ownership of a file or all files inside
+    the specified directories. Currently, it has effect only under
+    Unix.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/chmod.html">Chmod</a></td>
+    <td><p>Changes the permissions of a file or all files inside the
+     specified directories. Currently, it has effect only under Unix.
+     The permissions are also UNIX style, like the arguments for the
+    <i>chmod</i> command.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/chown.html">Chown</a></td>
+    <td><p>Changes the owner of a file or all files inside the
+    specified directories. Currently, it has effect only under
+    Unix.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/concat.html">Concat</a></td>
+    <td><p>Concatenates multiple files into a single one or to Ant's
+     logging system.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/copy.html">Copy</a></td>
+    <td><p>Copies a file or Fileset to a new file or directory.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/copydir.html"><i>Copydir</i></a></td>
+    <td><p><i>Deprecated.</i>  Use the
+     <a href="CoreTasks/copy.html">Copy</a> task instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/copyfile.html"><i>Copyfile</i></a></td>
+    <td><p><i>Deprecated.</i>  Use the
+     <a href="CoreTasks/copy.html">Copy</a> task instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/delete.html">Delete</a></td>
+    <td><p>Deletes either a single file, all files and sub-directories
+     in a specified directory, or a set of files specified by one or more
+     <a href="CoreTypes/fileset.html">FileSet</a>s.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/deltree.html"><i>Deltree</i></a></td>
+    <td><p><i>Deprecated.</i>  Use the
+     <a href="CoreTasks/delete.html">Delete</a> task instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/filter.html">Filter</a></td>
+    <td><p>Sets a token filter for this project, or reads multiple token
+     filters from a specified file and sets these as filters. Token filters
+     are used by all tasks that perform file-copying operations.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/fixcrlf.html">FixCRLF</a></td>
+    <td><p>Modifies a file to add or remove tabs, carriage returns, linefeeds,
+     and EOF characters.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/get.html">Get</a></td>
+    <td><p>Gets a file from a URL.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/mkdir.html">Mkdir</a></td>
+    <td><p>Creates a directory. Non-existent parent directories are created,
+     when necessary.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/move.html">Move</a></td>
+    <td><p>Moves a file to a new file or directory, or a set(s) of file(s) to
+     a new directory.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/patch.html">Patch</a></td>
+    <td><p>Applies a &quot;diff&quot; file to originals.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/rename.html"><i>Rename</i></a></td>
+    <td><p><i>Deprecated.</i>  Use the <a href="CoreTasks/move.html">Move</a>
+    task instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/renameextensions.html">
+     <i>RenameExtensions</i></a></td>
+    <td><p><i>Deprecated</i>. Use the <a href="CoreTasks/move.html">Move</a>
+     task with a <a href="CoreTypes/mapper.html#glob-mapper">glob mapper</a>
+     instead.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/replace.html">Replace</a></td>
+    <td><p>Replace is a directory-based task for replacing the occurrence
+     of a given string with another string in selected file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/replaceregexp.html">
+     ReplaceRegExp</a></td>
+    <td><p>Directory-based task for replacing the occurrence of a given
+     regular expression with a substitution pattern in a file or set of
+     files.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/sync.html">Sync</a></td>
+    <td><p>Synchronize two directory trees.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/tempfile.html">Tempfile</a></td>
+    <td><p>Generates a name for a new temporary file and sets the specified
+     property to that name.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/touch.html">Touch</a></td>
+    <td><p>Changes the modification time of a file and possibly creates it at
+     the same time.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="extensions">Java2 Extensions Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap>
+    <a href="OptionalTasks/jarlib-available.html">Jarlib-available</a></td>
+    <td><p>Check whether an extension is present in a FileSet or an
+      ExtensionSet. If the extension is present, the specified property is
+     set.</p>
+    </td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap>
+    <a href="OptionalTasks/jarlib-display.html">Jarlib-display</a></td>
+    <td><p>Display the &quot;Optional Package&quot; and
+      &quot;Package Specification&quot; information contained within the
+      specified jars.</p>
+    </td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap>
+    <a href="OptionalTasks/jarlib-manifest.html">Jarlib-manifest</a></td>
+    <td><p>Task to generate a manifest that declares all the dependencies
+      in manifest. The dependencies are determined by looking in the
+      specified path and searching for Extension/&quot;Optional Package&quot;
+      specifications in the manifests of the jars.</p>
+    </td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap>
+    <a href="OptionalTasks/jarlib-resolve.html">Jarlib-resolve</a></td>
+    <td><p>Try to locate a jar to satisfy an extension, and place the
+      location of the jar into the specified property.</p>
+    </td>
+  </tr>
+</table>
+
+<p></p>
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="log">Logging Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/recorder.html">Record</a></td>
+    <td><p>Runs a listener that records the logging output of the
+     build-process events to a file. Several recorders can exist
+     at the same time. Each recorder is associated with a file.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="mail">Mail Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/mail.html">Mail</a></td>
+    <td><p>A task to send SMTP email.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/mimemail.html">MimeMail</a></td>
+    <td><p><i>Deprecated</i>. Use the <a href="CoreTasks/mail.html">Mail</a>
+     task instead.</p></td>
+  </tr>
+
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="misc">Miscellaneous Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/defaultexcludes.html">Defaultexcludes</a></td>
+    <td><p>Modify the list of default exclude patterns from within
+    your build file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/echo.html">Echo</a></td>
+    <td><p>Echoes text to <code>System.out</code> or to a file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/fail.html">Fail</a></td>
+    <td><p>Exits the current build by throwing a BuildException,
+     optionally printing additional information.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/genkey.html">GenKey</a></td>
+    <td><p>Generates a key in keystore.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/input.html">Input</a></td>
+    <td><p>Allows user interaction during the build process by displaying a
+     message and reading a line of input from the console.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/script.html">Script</a></td>
+    <td><p>Executes a script in a
+     <a href="http://jakarta.apache.org/bsf/"
+      target="_top">Apache BSF</a>-supported language.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/sound.html">Sound</a></td>
+    <td><p>Plays a sound file at the end of the build, according to whether
+     the build failed or succeeded.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/splash.html">Splash</a></td>
+    <td><p>Displays a splash screen.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/sql.html">Sql</a></td>
+    <td><p>Executes a series of SQL statements via JDBC to a database.
+     Statements can either be read in from a text file using the
+     <code>src</code> attribute, or from between the enclosing SQL
+     tags.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/taskdef.html">Taskdef</a></td>
+    <td><p>Adds a task definition to the current project, such that this
+     new task can be used in the current project.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/tstamp.html">TStamp</a></td>
+    <td><p>Sets the <code>DSTAMP</code>, <code>TSTAMP</code>, and
+     <code>TODAY</code> properties in the current project, based on
+     the current date and time.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/typedef.html">Typedef</a></td>
+    <td><p>Adds a data-type definition to the current project, such that this
+     new type can be used in the current project.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/xmlvalidate.html">XmlValidate</a></td>
+    <td><p>Checks that XML files are valid (or only well-formed). This task
+     uses the XML parser that is currently used by Ant by default, but any SAX1/2
+     parser can be specified, if needed.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="net">.NET Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/dotnet.html">.NET Tasks</a></td>
+    <td><p>(See the documentation describing the .NET tasks.)</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="preproc">Pre-process Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/antlr.html">ANTLR</a></td>
+    <td><p>Invokes the <a HREF="http://www.antlr.org/" target="_top">ANTLR</a>
+     Translator generator on a grammar file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/antstructure.html">AntStructure</a></td>
+    <td><p>Generates a DTD for Ant buildfiles that contains information
+     about all tasks currently known to Ant.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/import.html">Import</a></td>
+    <td><p>Import another build file and potentially override targets
+    in it with targets of your own.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/javacc.html">JavaCC</a></td>
+    <td><p>Invokes the
+     <a HREF="http://javacc.dev.java.net/" target="_top">
+     JavaCC</a> compiler-compiler on a grammar file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/javah.html">Javah</a></td>
+    <td><p>Generates JNI headers from a Java class.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/jjdoc.html">JJDoc</a></td>
+    <td><p>Invokes the <a href="http://javacc.dev.java.net/">
+     JJDoc</a> documentation generator for the JavaCC compiler-compiler.
+     JJDoc takes a JavaCC parser specification and produces documentation
+     for the BNF grammar.  It can operate in three modes, determined by
+     command line options. This task only invokes JJDoc if the grammar file
+     is newer than the generated BNF grammar documentation.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/jjtree.html">JJTree</a></td>
+    <td><p>Invokes the <a href="http://javacc.dev.java.net/">
+     JJTree</a> preprocessor for the JavaCC compiler-compiler. It inserts
+     parse-tree building actions at various places in the JavaCC source that
+     it generates. The output of JJTree is run through JavaCC to create the
+     parser. This task only invokes JJTree if the grammar file is newer than
+     the generated JavaCC file.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/macrodef.html">Macrodef</a></td>
+    <td><p>Define a new task as a macro built-up upon other tasks.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/native2ascii.html">
+     Native2Ascii</a></td>
+    <td><p>Converts files from native encodings to ASCII with escaped Unicode.
+      A common usage is to convert source files maintained in a native
+      operating system encoding to ASCII, prior to compilation.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/presetdef.html">Presetdef</a></td>
+    <td><p>Define a new task by instrumenting an existing task with
+    default values for attributes or child elements.</p>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/translate.html">Translate</a></td>
+    <td><p>Identifies keys in files, delimited by special tokens, and
+     translates them with values read from resource bundles.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/style.html">XSLT</a></td>
+    <td><p>Processes a set of documents via XSLT.</p></td>
+  </tr>
+
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="prop">Property Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/available.html">Available</a></td>
+    <td><p>Sets a property if a specified file, directory, class in the
+     classpath, or JVM system resource is available at runtime.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/basename.html">Basename</a></td>
+    <td><p>Sets a property to the last element of a specified path.
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/buildnumber.html">BuildNumber</a></td>
+    <td><p>Task that can be used to track build numbers.
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/condition.html">Condition</a></td>
+    <td><p>Sets a property if a certain condition holds true; this is a
+     generalization of <a href="CoreTasks/available.html">Available</a> and
+     <a href="CoreTasks/uptodate.html">Uptodate</a>.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/dirname.html">Dirname</a></td>
+    <td><p>Sets a property to the value of the specified file up to,
+     but not including, the last path element.
+  </tr>
+
+  <tr valign="top">
+    <td nowrap>
+    <a href="OptionalTasks/echoproperties.html">Echoproperties</a><br>
+
+    </td>
+    <td><p>Lists the current properties.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/loadfile.html">LoadFile</a></td>
+    <td><p>Loads a file into a property.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/loadproperties.html">LoadProperties</a></td>
+    <td><p>Load a file's contents as Ant properties. This task is
+     equivalent to using <code>&lt;property file=&quot;...&quot;/&gt;</code>
+     except that it supports nested <code>&lt;filterchain&gt;</code> elements,
+     and it cannot be specified outside a target.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/makeurl.html">MakeURL</a></td>
+    <td><p>Creates a URL (list) from a file/fileset or path</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/pathconvert.html">PathConvert</a></td>
+    <td><p>Converts a nested path, path reference, filelist reference, or
+     fileset reference to the form usable on a specified platform and/or
+     to a list of items separated by the specified separator and stores
+     the result in the specified property.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/property.html">Property</a></td>
+    <td><p>Sets a property (by name and value), or set of properties
+     (from a file or resource) in the project.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/propertyfile.html">
+     PropertyFile</a></td>
+    <td><p>Creates or modifies property files. Useful when wanting to make
+     unattended modifications to configuration files for application
+     servers and applications. Typically used for things such as
+     automatically generating a build number and saving it to a build
+     properties file, or doing date manipulation.<p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/uptodate.html">Uptodate</a></td>
+    <td><p>Sets a property if a given target file is newer than a set of
+     source files.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/whichresource.html">Whichresource</a></td>
+    <td><p>Find a class or resource.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/xmlproperty.html">XmlProperty</a></td>
+    <td><p>Loads property values from a well-formed XML file.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="remote">Remote Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/ftp.html">FTP</a></td>
+    <td><p>Implements a basic FTP client that can send, receive,
+     list, and delete files, and create directories.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/rexec.html">Rexec</a></td>
+    <td><p>Task to automate a remote rexec session.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/scp.html">Scp</a></td>
+    <td><p>Copy files to or from a remote server using SSH.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/setproxy.html">setproxy</a></td>
+    <td><p>Sets Java's web proxy properties, so that tasks and code run
+ in the same JVM can have through-the-firewall access to remote web sites.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/sshexec.html">Sshexec</a></td>
+    <td><p>Execute a command on a remote server using SSH.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/telnet.html">Telnet</a></td>
+    <td><p>Task to automate a remote <i>telnet</i> session. This task uses
+     nested <code>&lt;read&gt;</code> and <code>&lt;write&gt;</code> tags
+     to indicate strings to wait for and specify text to send.</p></td>
+  </tr>
+
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="scm">SCM Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/cvs.html">Cvs</a></td>
+    <td><p>Handles packages/modules retrieved from a
+     <a href="http://www.nongnu.org/cvs/" target="_top">CVS</a>
+     repository.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/changelog.html">CvsChangeLog</a></td>
+    <td><p>Generates an XML report of the changes recorded in a
+     <a href="http://www.nongnu.org/cvs/" target="_top">CVS</a>
+     repository.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/cvspass.html">CVSPass</a></td>
+    <td><p>Adds entries to a .cvspass file. Adding entries to this file
+     has the same affect as a <i>cvs login</i> command.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="CoreTasks/cvstagdiff.html">CvsTagDiff</a></td>
+    <td><p>Generates an XML-formatted report file of the changes between
+    two tags or dates recorded in a <a href="http://www.nongnu.org/cvs/"
+    target="_top">CVS</a> repository.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/clearcase.html">ClearCase</a></td>
+    <td><p>Tasks to perform the ClearCase cleartool <i>checkin</i>, <i>checkout</i>,
+     <i>uncheckout</i>, <i>update</i>, <i>lock</i>, <i>unlock</i>, <i>mklbtype</i>, <i>rmtype</i>, <i>mklabel</i>, <i>mkattr</i>, <i>mkdir</i>, <i>mkelem</i>, and <i>mkbl</i> commands.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/ccm.html">Continuus/Synergy</a></td>
+    <td><p>Tasks to perform the Continuus <i>ccmcheckin</i>,
+     <i>ccmcheckout</i>, <i>ccmcheckintask</i>, <i>ccmreconfigure</i>, and
+     <i>ccmcreateTask</i> commands.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/vss.html">
+     Microsoft Visual SourceSafe</a></td>
+    <td><p>Tasks to perform the Visual SourceSafe <i>vssget</i>,
+     <i>vsslabel</i>, <i>vsshistory</i>, <i>vsscheckin</i>,
+     <i>vsscheckout</i>, <i>vssadd</i>, <i>vsscp</i>, and <i>vsscreate</i>
+     commands.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/perforce.html">Perforce</a></td>
+    <td><p>Tasks to perform the Perforce <i>p4sync</i>, <i>p4change</i>,
+     <i>p4edit</i>, <i>p4submit</i>, <i>p4have</i>, <i>p4label</i>,
+     <i>p4counter</i>, <i>p4reopen</i>, <i>p4revert</i>, and <i>p4add</i>
+     commands.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/pvcstask.html">Pvcs</a></td>
+    <td><p>Allows the user extract the latest edition of the source code
+     from a PVCS repository.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/sos.html">SourceOffSite</a></td>
+    <td><p>Tasks to perform the SourceOffSite <i>sosget</i>, <i>soslabel</i>,
+     <i>soscheckin</i>, and <i>soscheckout</i> commands.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/starteam.html">StarTeam</a></td>
+    <td><p>Tasks to perform the StarTeam <i>stcheckout</i>, <i>stcheckin</i>,
+     <i>stlabel</i>, and <i>stlist</i> commands. The
+     <a href="OptionalTasks/starteam.html#starteam">Starteam</a> task
+     is deprecated; use
+     <a href="OptionalTasks/starteam.html#stcheckout">STCheckout</a>
+     instead.</p></td>
+  </tr>
+</table>
+
+<p></p>
+<table width="100%" border="0" cellpadding="4" cellspacing="0">
+<th align="left">
+<font size="+0" face="arial,helvetica,sanserif">
+<a name="testing">Testing Tasks</a>
+</font></th>
+<font size="-1" face="arial,helvetica,sanserif">
+<th align="right"><a href="#top">[Back to top]</a></th>
+</font>
+</table>
+<table width="100%" border="1" cellpadding="4" cellspacing="0">
+  <tr valign="top">
+    <th nowrap>Task Name</th>
+    <th>Description</th>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/junit.html">Junit</a></td>
+    <td><p>Runs tests from the <a href="http://www.junit.org">Junit</a>
+     testing framework. This task has been tested with JUnit 3.0 up to
+     JUnit 3.7; it won't work with versions prior to JUnit 3.0.</p></td>
+  </tr>
+
+  <tr valign="top">
+    <td nowrap><a href="OptionalTasks/junitreport.html">JunitReport</a></td>
+    <td><p>Merges the individual XML files generated by the
+     <a href="OptionalTasks/junit.html">Junit</a> task and applies a
+     stylesheet on the resulting merged document to provide a browsable
+     report of the testcases results.</p></td>
+  </tr>
+
+</table>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/toc.html b/trunk/docs/manual/toc.html
new file mode 100644
index 0000000..8a4ab0c
--- /dev/null
+++ b/trunk/docs/manual/toc.html
@@ -0,0 +1,47 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2>Table of Contents</h2>
+<a href="intro.html">Introduction</a><br/>
+<a href="installlist.html" target="navFrame">Installing Ant</a><br/>
+<a href="usinglist.html" target="navFrame">Using Ant</a><br/>
+<a href="runninglist.html" target="navFrame">Running Ant</a><br/>
+<a href="anttaskslist.html" target="navFrame">Ant Tasks</a><br/>
+<a href="conceptstypeslist.html" target="navFrame">Concepts and Types</a><br/>
+<a href="listeners.html" target="mainFrame">Loggers &amp; Listeners</a><br/>
+<a href="ide.html" target="navFrame">Editor/IDE Integration</a><br/>
+<a href="developlist.html" target="navFrame">Developing with Ant</a><br/>
+<a href="tutorials.html" target="navFrame">Tutorials</a><br/>
+<a href="api/index.html" target="_top">Ant API</a><br/>
+<a href="LICENSE">License</a><br/>
+<a href="feedback.html">Feedback and Troubleshooting</a><br/>
+<br/>
+<a href="credits.html">Authors</a><br/>
+
+</body>
+</html>
+
diff --git a/trunk/docs/manual/tutorial-HelloWorldWithAnt.html b/trunk/docs/manual/tutorial-HelloWorldWithAnt.html
new file mode 100644
index 0000000..4eb0e55
--- /dev/null
+++ b/trunk/docs/manual/tutorial-HelloWorldWithAnt.html
@@ -0,0 +1,517 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+  <title>Tutorial: Hello World with Ant</title>
+  <link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+</head>
+<body>
+<h1>Tutorial: Hello World with Ant</h1>
+
+<p>This document provides a step by step tutorial for starting java programming with Ant.
+It does <b>not</b> contain deeper knowledge about Java or Ant. This tutorial has the goal
+to let you see, how to do the easiest steps in Ant.</p>
+
+
+
+<h2>Content</h2>
+<p><ul>
+<li><a href="#prepare">Preparing the project</a></li>
+<li><a href="#four-steps">Enhance the build file</a></li>
+<li><a href="#enhance">Enhance the build file</a></li>
+<li><a href="#ext-libs">Using external libraries</a></li>
+<li><a href="#resources">Resources</a></li>
+</ul></p>
+
+
+<a name="prepare"></a>
+<h2>Preparing the project</h2>
+<p>We want to separate the source from the generated files, so our java source files will
+be in <tt>src</tt> folder. All generated files should be under <tt>build</tt>, and there
+splitted into several subdirectories for the individual steps: <tt>classes</tt> for our compiled
+files and <tt>jar</tt> for our own JAR-file.</p>
+<p>We have to create only the <tt>src</tt> directory. (Because I am working on Windows, here is 
+the win-syntax - translate to your shell):</p>
+
+<pre class="code">
+md src
+</pre>
+
+<p>The following simple Java class just prints a fixed message out to STDOUT,
+so just write this code into <tt>src\oata\HelloWorld.java</tt>.</p>
+
+<pre class="code">
+package oata;
+
+public class HelloWorld {
+    public static void main(String[] args) {
+        System.out.println("Hello World");
+    }
+}
+</pre>
+
+<p>Now just try to compile and run that:
+<pre class="code">
+md build\classes
+javac -sourcepath src -d build\classes src\oata\HelloWorld.java
+java -cp build\classes oata.HelloWorld
+</pre>
+which will result in
+<pre class="output">
+Hello World
+</pre>
+</p>
+
+<p>Creating a jar-file is not very difficult. But creating a <i>startable</i> jar-file needs more steps: create a
+manifest-file containing the start class, creating the target directory and archiving the files.</p>
+<pre class="code">
+echo Main-Class: oata.HelloWorld&gt;myManifest
+md build\jar
+jar cfm build\jar\HelloWorld.jar myManifest -C build\classes .
+java -jar build\jar\HelloWorld.jar
+</pre>
+
+<p><b>Note:</b> Do not have blanks around the &gt;-sign in the <tt>echo Main-Class</tt> instruction because it would 
+falsify it!</p>
+
+
+<a name="four-steps"></a>
+<h2>Four steps to a running application</h2>
+<p>After finishing the java-only step we have to think about our build process. We <i>have</i> to compile our code, otherwise we couldn't
+start the program. Oh - "start" - yes, we could provide a target for that. We <i>should</i> package our application.
+Now it's only one class - but if you want to provide a download, no one would download several hundreds files ...
+(think about a complex Swing GUI - so let us create a jar file. A startable jar file would be nice ... And it's a
+good practise to have a "clean" target, which deletes all the generated stuff. Many failures could be solved just
+by a "clean build".</p>
+
+<p>By default Ant uses <tt>build.xml</tt> as the name for a buildfile, so our <tt>.\build.xml</tt> would be:</p>
+<pre class="code">
+&lt;project&gt;
+
+    &lt;target name="clean"&gt;
+        &lt;delete dir="build"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="compile"&gt;
+        &lt;mkdir dir="build/classes"/&gt;
+        &lt;javac srcdir="src" destdir="build/classes"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="jar"&gt;
+        &lt;mkdir dir="build/jar"/&gt;
+        &lt;jar destfile="build/jar/HelloWorld.jar" basedir="build/classes"&gt;
+            &lt;manifest&gt;
+                &lt;attribute name="Main-Class" value="oata.HelloWorld"/&gt;
+            &lt;/manifest&gt;
+        &lt;/jar&gt;
+    &lt;/target&gt;
+
+    &lt;target name="run"&gt;
+        &lt;java jar="build/jar/HelloWorld.jar" fork="true"/&gt;
+    &lt;/target&gt;
+
+&lt;/project&gt;
+</pre>
+
+<p>Now you can compile, package and run the application via</p>
+<pre class="code">
+ant compile
+ant jar
+ant run
+</pre>
+<p>Or shorter with</p>
+<pre class="code">
+ant compile jar run
+</pre>
+
+<p>While having a look at the buildfile, we will see some similar steps between Ant and the java-only commands:
+<table>
+<tr>
+  <th>java-only</th>
+  <th>Ant</th>
+</tr>
+<tr>
+  <td valign="top"><pre class="code">
+md build\classes
+javac
+    -sourcepath src
+    -d build\classes
+    src\oata\HelloWorld.java
+echo Main-Class: oata.HelloWorld>mf
+md build\jar
+jar cfm
+    build\jar\HelloWorld.jar
+    mf
+    -C build\classes
+    .
+
+
+
+java -jar build\jar\HelloWorld.jar
+  </pre></td>
+  <td valign="top"><pre class="code">
+&lt;mkdir dir="build/classes"/&gt;
+&lt;javac
+    srcdir="src"
+    destdir="build/classes"/&gt;
+<i>&lt;!-- automatically detected --&gt;</i>
+<i>&lt;!-- obsolete; done via manifest tag --&gt;</i>
+&lt;mkdir dir="build/jar"/&gt;
+&lt;jar
+    destfile="build/jar/HelloWorld.jar"
+
+    basedir="build/classes"&gt;
+    &lt;manifest&gt;
+        &lt;attribute name="Main-Class" value="oata.HelloWorld"/&gt;
+    &lt;/manifest&gt;
+&lt;/jar&gt;
+&lt;java jar="build/jar/HelloWorld.jar" fork="true"/&gt;
+  </pre></td>
+</tr></table>
+</p>
+
+
+
+<a name="enhance"></a>
+<h2>Enhance the build file</h2>
+<p>Now we have a working buildfile we could do some enhancements: many time you are referencing the
+same directories, main-class and jar-name are hard coded, and while invocation you have to remember
+the right order of build steps.</p>
+<p>The first and second point would be addressed with <i>properties</i>, the third with a special property - an attribute
+of the &lt;project&gt;-tag and the fourth problem can be solved using dependencies.</p>
+
+
+<pre class="code">
+&lt;project name="HelloWorld" basedir="." default="main"&gt;
+
+    &lt;property name="src.dir"     value="src"/&gt;
+
+    &lt;property name="build.dir"   value="build"/&gt;
+    &lt;property name="classes.dir" value="${build.dir}/classes"/&gt;
+    &lt;property name="jar.dir"     value="${build.dir}/jar"/&gt;
+
+    &lt;property name="main-class"  value="oata.HelloWorld"/&gt;
+
+
+
+    &lt;target name="clean"&gt;
+        &lt;delete dir="${build.dir}"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="compile"&gt;
+        &lt;mkdir dir="${classes.dir}"/&gt;
+        &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="jar" depends="compile"&gt;
+        &lt;mkdir dir="${jar.dir}"/&gt;
+        &lt;jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}"&gt;
+            &lt;manifest&gt;
+                &lt;attribute name="Main-Class" value="${main-class}"/&gt;
+            &lt;/manifest&gt;
+        &lt;/jar&gt;
+    &lt;/target&gt;
+
+    &lt;target name="run" depends="jar"&gt;
+        &lt;java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="clean-build" depends="clean,jar"/&gt;
+
+    &lt;target name="main" depends="clean,run"/&gt;
+
+&lt;/project&gt;
+</pre>
+
+
+<p>Now it's easier, just do a <tt class="code">ant</tt> and you will get</p>
+<pre class="output">
+Buildfile: build.xml
+
+clean:
+
+compile:
+    [mkdir] Created dir: C:\...\build\classes
+    [javac] Compiling 1 source file to C:\...\build\classes
+
+jar:
+    [mkdir] Created dir: C:\...\build\jar
+      [jar] Building jar: C:\...\build\jar\HelloWorld.jar
+
+run:
+     [java] Hello World
+
+main:
+
+BUILD SUCCESSFUL
+</pre>
+
+
+<a name="ext-libs"></a>
+<h2>Using external libraries</h2>
+<p>Somehow told us not to use syso-statements. For log-Statements we should use a Logging-API - customizable on a high
+degree (including switching off during usual life (= not development) execution). We use Log4J for that, because <ul>
+<li>it is not part of the JDK (1.4+) and we want to show how to use external libs</li>
+<li>it can run under JDK 1.2 (as Ant)</li>
+<li>it's highly configurable</li>
+<li>it's from Apache ;-)</li>
+</ul></p>
+<p>We store our external libraries in a new directory <tt>lib</tt>. Log4J can be
+<a href="http://www.apache.org/dist/logging/log4j/1.2.13/logging-log4j-1.2.13.zip">downloaded [1]</a> from Logging's Homepage.
+Create the <tt>lib</tt> directory and extract the log4j-1.2.9.jar into that lib-directory. After that we have to modify
+our java source to use that library and our buildfile so that this library could be accessed during compilation and run.
+</p>
+<p>Working with Log4J is documented inside its manual. Here we use the <i>MyApp</i>-example from the
+<a href="http://logging.apache.org/log4j/docs/manual.html">Short Manual [2]</a>. First we have to modify the java source to
+use the logging framework:</p>
+
+<pre class="code">
+package oata;
+
+<b>import org.apache.log4j.Logger;</b>
+<b>import org.apache.log4j.BasicConfigurator;</b>
+
+public class HelloWorld {
+    <b>static Logger logger = Logger.getLogger(HelloWorld.class);</b>
+
+    public static void main(String[] args) {
+        <b>BasicConfigurator.configure();</b>
+        <font color="blue"><b>logger.info("Hello World");</b></font>          // the old SysO-statement
+    }
+}
+</pre>
+
+<p>Most of the modifications are "framework overhead" which has to be done once. The blue line is our "old System-out"
+statement.</p>
+<p>Don't try to run <tt>ant</tt> - you will only get lot of compiler errors. Log4J is not inside the classpath so we have
+to do a little work here. But do not change the CLASSPATH environment variable! This is only for this project and maybe
+you would break other environments (this is one of the most famous mistakes when working with Ant). We introduce Log4J
+(or to be more precise: all libraries (jar-files) which are somewhere under <tt>.\lib</tt>) into our buildfile:</p>
+
+<pre class="code">
+&lt;project name="HelloWorld" basedir="." default="main"&gt;
+    ...
+    <b>&lt;property name="lib.dir"     value="lib"/&gt;</b>
+
+    <b>&lt;path id="classpath"&gt;</b>
+        <b>&lt;fileset dir="${lib.dir}" includes="**/*.jar"/&gt;</b>
+    <b>&lt;/path&gt;</b>
+
+    ...
+
+    &lt;target name="compile"&gt;
+        &lt;mkdir dir="${classes.dir}"/&gt;
+        &lt;javac srcdir="${src.dir}" destdir="${classes.dir}" <b>classpathref="classpath"</b>/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="run" depends="jar"&gt;
+        &lt;java fork="true" <b>classname="${main-class}"</b>&gt;
+            <b>&lt;classpath&gt;</b>
+                <b>&lt;path refid="classpath"/&gt;</b>
+                <font color="red"><b>&lt;path location="${jar.dir}/${ant.project.name}.jar"/&gt;</b></font>
+            <b>&lt;/classpath&gt;</b>
+        &lt;/java&gt;
+    &lt;/target&gt;
+
+    ...
+
+&lt;/project&gt;
+</pre>
+
+<p>In this example we start our application not via its Main-Class manifest-attribute, because we could not provide
+a jarname <i>and</i> a classpath. So add our class in the red line to the already defined path and start as usual. Running
+<tt>ant</tt> would give (after the usual compile stuff):</p>
+
+<pre class="output">
+[java] 0 [main] INFO oata.HelloWorld  - Hello World
+</pre>
+
+<p>What's that? <ul>
+<li><i>[java]</i> Ant task running at the moment</li>
+<li><i>0</i> <font size="-1">sorry don't know - some Log4J stuff</font></li>
+<li><i>[main]</i> the running thread from our application </li>
+<li><i>INFO</i> log level of that statement</i>
+<li><i>oata.HelloWorld</i> source of that statement</i>
+<li><i>-</i> separator</li>
+<li><i>Hello World</i> the message</li>
+</ul>
+For another layout ... have a look inside Log4J's documentation about using other PatternLayout's.</p>
+
+
+<a name="config-files">
+<h2>Configuration files</h2>
+<p>Why we have used Log4J? "It's highly configurable"? No - all is hard coded! But that is not the debt of Log4J - it's
+ours. We had coded <tt>BasicConfigurator.configure();</tt> which implies a simple, but hard coded configuration. More
+confortable would be using a property file. In the java source delete the BasicConfiguration-line from the main() method
+(and the related import-statement). Log4J will search then for a configuration as described in it's manual. Then create 
+a new file <tt>src/log4j.properties</tt>. That's the default name for Log4J's configuration and using that name would make 
+life easier - not only the framework knows what is inside, you too!</p>
+
+<pre class="code">
+log4j.rootLogger=DEBUG, <b>stdout</b>
+
+log4j.appender.<b>stdout</b>=org.apache.log4j.ConsoleAppender
+
+log4j.appender.<b>stdout</b>.layout=org.apache.log4j.PatternLayout
+log4j.appender.<b>stdout</b>.layout.ConversionPattern=<font color="blue"><b>%m%n</b></font>
+</pre>
+
+<p>This configuration creates an output channel ("Appender") to console named as <tt>stdout</tt> which prints the
+message (%m) followed by a line feed (%n) - same as the earlier System.out.println() :-) Oooh kay - but we haven't
+finished yet. We should deliver the configuration file, too. So we change the buildfile:</p>
+
+<pre class="code">
+    ...
+    &lt;target name="compile"&gt;
+        &lt;mkdir dir="${classes.dir}"/&gt;
+        &lt;javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/&gt;
+        <b>&lt;copy todir="${classes.dir}"&gt;</b>
+            <b>&lt;fileset dir="${src.dir}" excludes="**/*.java"/&gt;</b>
+        <b>&lt;/copy&gt;</b>
+    &lt;/target&gt;
+    ...
+</pre>
+
+<p>This copies all resources (as long as they haven't the suffix ".java") to the build directory, so we could
+start the application from that directory and these files will included into the jar.</p>
+
+
+<a name="junit">
+<h2>Testing the class</h2>
+<p>In this step we will introduce the usage of the JUnit [3] testframework in combination with Ant. Because Ant
+has a built-in JUnit 3.8.2 you could start directly using it. Write a test class in <tt>src\HelloWorldTest.java</tt>: </p>
+
+<pre class="code">
+public class HelloWorldTest extends junit.framework.TestCase {
+
+    public void testNothing() {
+    }
+    
+    public void testWillAlwaysFail() {
+        fail("An error message");
+    }
+    
+}</pre>
+
+<p>Because we dont have real business logic to test, this test class is very small: just show how to start. For 
+further information see the JUnit documentation [3] and the manual of <a href="OptionalTasks/junit.html">junit</a> task.
+Now we add a junit instruction to our buildfile:</p>
+
+<pre class="code">
+    ...
+
+    &lt;target name="run" depends="jar"&gt;
+        &lt;java fork="true" classname="${main-class}"&gt;
+            &lt;classpath&gt;
+                &lt;path refid="classpath"/&gt;
+                &lt;path <b>id="application"</b> location="${jar.dir}/${ant.project.name}.jar"/&gt;
+            &lt;/classpath&gt;
+        &lt;/java&gt;
+    &lt;/target&gt;
+    
+    <b>&lt;target name="junit" depends="jar"&gt;
+        &lt;junit printsummary="yes"&gt;
+            &lt;classpath&gt;
+                &lt;path refid="classpath"/&gt;
+                &lt;path refid="application"/&gt;
+            &lt;/classpath&gt;
+            
+            &lt;batchtest fork="yes"&gt;
+                &lt;fileset dir="${src.dir}" includes="*Test.java"/&gt;
+            &lt;/batchtest&gt;
+        &lt;/junit&gt;
+    &lt;/target&gt;</b>
+
+    ...
+
+</pre>
+
+<p>We reuse the path to our own jar file as defined in run-target by giving it an ID.
+The <tt>printsummary=yes</tt> lets us see more detailed information than just a "FAILED" or "PASSED" message.
+How much tests failed? Some errors? Printsummary lets us know. The classpath is set up to find our classes.
+To run tests the <tt>batchtest</tt> here is used, so you could easily add more test classes in the future just
+by naming them <tt>*Test.java</tt>. This is a common naming scheme.</p>
+
+<p>After a <tt class="code">ant junit</tt> you'll get:</p>
+
+<pre class="output">
+...
+junit:
+    [junit] Running HelloWorldTest
+    [junit] Tests run: 2, Failures: 1, Errors: 0, Time elapsed: 0,01 sec
+    [junit] Test HelloWorldTest FAILED
+
+BUILD SUCCESSFUL
+...
+</pre>
+
+<p>We can also produce a report. Something that you (and other) could read after closing the shell .... 
+There are two steps: 1. let &lt;junit&gt; log the information and 2. convert these to something readable (browsable).<p>
+
+<pre class="code">
+    ...
+    <b>&lt;property name="report.dir"  value="${build.dir}/junitreport"/&gt;</b>
+    ...
+    &lt;target name="junit" depends="jar"&gt;
+        <b>&lt;mkdir dir="${report.dir}"/&gt;</b>
+        &lt;junit printsummary="yes"&gt;
+            &lt;classpath&gt;
+                &lt;path refid="classpath"/&gt;
+                &lt;path refid="application"/&gt;
+            &lt;/classpath&gt;
+            
+            <b>&lt;formatter type="xml"/&gt;</b>
+            
+            &lt;batchtest fork="yes" <b>todir="${report.dir}"</b>&gt;
+                &lt;fileset dir="${src.dir}" includes="*Test.java"/&gt;
+            &lt;/batchtest&gt;
+        &lt;/junit&gt;
+    &lt;/target&gt;
+    
+    <b>&lt;target name="junitreport"&gt;
+        &lt;junitreport todir="${report.dir}"&gt;
+            &lt;fileset dir="${report.dir}" includes="TEST-*.xml"/&gt;
+            &lt;report todir="${report.dir}"/&gt;
+        &lt;/junitreport&gt;
+    &lt;/target&gt;</b>
+</pre>
+
+<p>Because we would produce a lot of files and these files would be written to the current directory by default,
+we define a report directory, create it before running the <tt>junit</tt> and redirect the logging to it. The log format
+is XML so <tt>junitreport</tt> could parse it. In a second target <tt>junitreport</tt> should create a browsable 
+HTML-report for all generated xml-log files in the report directory. Now you can open the ${report.dir}\index.html and
+see the result (looks something like JavaDoc).<br>
+Personally I use two different targets for junit and junitreport. Generating the HTML report needs some time and you dont
+need the HTML report just for testing, e.g. if you are fixing an error or a integration server is doing a job.
+</p>
+
+
+
+
+<a name="resources"></a>
+<h2>Resources</h2>
+<pre>
+    [1] <a href="http://www.apache.org/dist/logging/log4j/1.2.13/logging-log4j-1.2.13.zip">http://www.apache.org/dist/logging/log4j/1.2.13/logging-log4j-1.2.13.zip</a>
+    [2] <a href="http://logging.apache.org/log4j/docs/manual.html">http://logging.apache.org/log4j/docs/manual.html</a>
+    [3] <a href="http://www.junit.org/index.htm">http://www.junit.org/index.htm</a>
+</pre>
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/tutorial-tasks-filesets-properties.html b/trunk/docs/manual/tutorial-tasks-filesets-properties.html
new file mode 100644
index 0000000..a28dd6b
--- /dev/null
+++ b/trunk/docs/manual/tutorial-tasks-filesets-properties.html
@@ -0,0 +1,979 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+  <link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+  <title>Tutorial: Tasks using Properties, Filesets &amp; Paths</title>
+</head>
+<body>
+<h1>Tutorial: Tasks using Properties, Filesets &amp; Paths</h1>
+
+<p>After reading the tutorial about <a href="tutorial-writing-tasks.html">writing
+tasks [1]</a> this tutorial explains how to get and set properties and how to use
+nested filesets and paths. Finally it explains how to contribute tasks to Ant.</p>
+
+<h2>Content</h2>
+<p><ul>
+<li><a href="#goal">The goal</a></li>
+<li><a href="#buildenvironment">Build environment</a></li>
+<li><a href="#propertyaccess">Property access</a></li>
+<li><a href="#filesets">Using filesets</a></li>
+<li><a href="#path">Using nested paths</a></li>
+<li><a href="#returning-list">Returning a list</a></li>
+<li><a href="#documentation">Documentation</a></li>
+<li><a href="#contribute">Contribute the new task</a></li>
+<li><a href="#resources">Resources</a></li>
+</ul></p>
+
+
+<h2><a name="goal">The goal</a></h2>
+<p>The goal is to write a task, which searchs in a path for a file and saves the
+location of that file in a property.</p>
+
+
+<h2><a name="buildenvironment">Build environment</a></h2>
+<p>We can use the buildfile from the other tutorial and modify it a little bit.
+That's the advantage of using properties - we can reuse nearly the whole script. :-)</p>
+<pre class="code">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="<b>FindTask</b>" basedir="." default="test"&gt;
+    ...
+    &lt;target name="use.init" description="Taskdef's the <b>Find</b>-Task" depends="jar"&gt;
+        &lt;taskdef name="<b>find</b>" classname="<b>Find</b>" classpath="${ant.project.name}.jar"/&gt;
+    &lt;/target&gt;
+
+    <b>&lt;!-- the other use.* targets are deleted --&gt;</b>
+    ...
+&lt;/project&gt;
+</pre>
+
+<p>The buildfile is in the archive <a href="tutorial-tasks-filesets-properties.zip">
+tutorial-tasks-filesets-properties.zip [2]</a> in <tt>/build.xml.01-propertyaccess</tt>
+(future version saved as *.02..., final version as build.xml; same for sources).</p>
+
+
+<h2><a name="propertyaccess">Property access</a></h2>
+<p>Our first step is to set a property to a value and print the value of that property.
+So our scenario would be
+<pre class="code">
+    &lt;find property="test" value="test-value"/&gt;
+    &lt;find print="test"/&gt;
+</pre>
+ok, can be rewritten with the core tasks
+<pre class="code">
+    &lt;property name="test" value="test-value"/&gt;
+    &lt;echo message="${test}"/&gt;
+</pre>
+but I have to start on known ground :-)</p>
+<p>So what to do? Handling three attributes (property, value, print) and an execute method.
+Because this is only an introduction example I don't do much checking:
+
+<pre class="code">
+import org.apache.tools.ant.BuildException;
+
+public class Find extends Task {
+
+    private String property;
+    private String value;
+    private String print;
+
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    // setter for value and print
+
+    public void execute() {
+        if (print != null) {
+            String propValue = <b>getProject().getProperty(print)</b>;
+            log(propValue);
+        } else {
+            if (property == null) throw new BuildException("property not set");
+            if (value    == null) throw new BuildException("value not set");
+            <b>getProject().setNewProperty(property, value)</b>;
+        }
+    }
+}
+</pre>
+
+As said in the other tutorial, the property access is done via Project instance.
+We get this instance via the public <tt>getProject()</tt> method which we inherit from
+<tt>Task</tt> (more precise from ProjectComponent). Reading a property is done via
+<tt>getProperty(<i>propertyname</i>)</tt> (very simple, isn't it?). This property returns
+the value as String or <i>null</i> if not set.<br>
+Setting a property is ... not really difficult, but there is more than one setter. You can
+use the <tt>setProperty()</tt> method which will do the job like expected. But there is
+a golden rule in Ant: <i>properties are immutable</i>. And this method sets the property
+to the specified value - whether it has a value before that or not. So we use another
+way. <tt>setNewProperty()</tt> sets the property only if there is no property with that
+name. Otherwise a message is logged.</p>
+
+<p><i>(by the way: a short word to ants "namespaces" (don't
+be confused with xml namespaces:
+an <code>&lt;antcall&gt;</code> creates a new space for property names. All properties from the caller
+are passed to the callee, but the callee can set its own properties without notice by the
+caller.)</i></p>
+
+<p>There are some other setter, too (but I haven't used them, so I can't say something
+to them, sorry :-)</p>
+
+<p>After putting our two line example from above into a target names <tt>use.simple</tt>
+we can call that from our testcase:
+
+<pre class="code">
+import org.apache.tools.ant.BuildFileTest;
+
+public class FindTest extends BuildFileTest {
+
+    public FindTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("build.xml");
+    }
+
+    public void testSimple() {
+        <b>expectLog("use.simple", "test-value");</b>
+    }
+}
+</pre>
+
+and all works fine.</p>
+
+
+
+<h2><a name="filesets">Using filesets</a></h2>
+<p>Ant provides a common way of bundling files: the fileset. Because you are reading
+this tutorial I think you know them and I don't have to spend more explanations about
+their usage in buildfiles. Our goal is to search a file in path. And on this step the
+path is simply a fileset (or more precise: a collection of filesets). So our usage
+would be
+<pre class="code">
+    &lt;find file="ant.jar" location="location.ant-jar"&gt;
+        &lt;fileset dir="${ant.home}" includes="**/*.jar"/&gt;
+    &lt;/find&gt;
+</pre>
+</p>
+
+<p>What do we need? A task with two attributes (file, location) and nested
+filesets. Because we had attribute handling already explained in the example above and the
+handling of nested elements is described in the other tutorial the code should be very easy:
+<pre class="code">
+public class Find extends Task {
+
+    private String file;
+    private String location;
+    private Vector filesets = new Vector();
+
+    public void setFile(String file) {
+        this.file = file;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public void addFileset(FileSet fileset) {
+        filesets.add(fileset);
+    }
+
+    public void execute() {
+    }
+}
+</pre>
+Ok - that task wouldn't do very much, but we can use it in the described manner without
+failure. On next step we have to implement the execute method. And before that we will
+implement the appropriate testcases (TDD - test driven development).</p>
+
+<p>In the other tutorial we have reused the already written targets of our buildfile.
+Now we will configure most of the testcases via java code (sometimes it's much easier
+to write a target than doing it via java coding). What can be tested?<ul>
+<li>not valid configured task (missing file, missing location, missing fileset)</li>
+<li>don't find a present file</li>
+<li>behaviour if file can't be found</li>
+</ul>
+Maybe you find some more testcases. But this is enough for now.<br>
+For each of these points we create a <tt>testXX</tt> method.</p>
+
+<pre class="code">
+public class FindTest extends BuildFileTest {
+
+    ... // constructor, setUp as above
+
+    public void testMissingFile() {
+        <b>Find find = new Find();</b>
+        try {
+            <b>find.execute();</b>
+            fail("No 'no-file'-exception thrown.");
+        } catch (Exception e) {
+            // exception expected
+            String expected = "file not set";
+            assertEquals("Wrong exception message.", expected, e.getMessage());
+        }
+    }
+
+    public void testMissingLocation() {
+        Find find = new Find();
+        <b>find.setFile("ant.jar");</b>
+        try {
+            find.execute();
+            fail("No 'no-location'-exception thrown.");
+        } catch (Exception e) {
+            ... // similar to testMissingFile()
+        }
+    }
+
+    public void testMissingFileset() {
+        Find find = new Find();
+        find.setFile("ant.jar");
+        find.setLocation("location.ant-jar");
+        try {
+            find.execute();
+            fail("No 'no-fileset'-exception thrown.");
+        } catch (Exception e) {
+            ... // similar to testMissingFile()
+        }
+    }
+
+    public void testFileNotPresent() {
+        executeTarget("testFileNotPresent");
+        String result = getProject().getProperty("location.ant-jar");
+        assertNull("Property set to wrong value.", result);
+    }
+
+    public void testFilePresent() {
+        executeTarget("testFilePresent");
+        String result = getProject().getProperty("location.ant-jar");
+        assertNotNull("Property not set.", result);
+        assertTrue("Wrong file found.", result.endsWith("ant.jar"));
+    }
+}
+</pre>
+
+<p>If we run this test class all test cases (except <i>testFileNotPresent</i>) fail. Now we
+can implement our task, so that these test cases will pass.</p>
+
+<pre class="code">
+    protected void validate() {
+        if (file==null) throw new BuildException("file not set");
+        if (location==null) throw new BuildException("location not set");
+        if (filesets.size()&lt;1) throw new BuildException("fileset not set");
+    }
+
+    public void execute() {
+        validate();                                                             // 1
+        String foundLocation = null;
+        for(Iterator itFSets = filesets.iterator(); itFSets.hasNext(); ) {      // 2
+            FileSet fs = (FileSet)itFSets.next();
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());         // 3
+            String[] includedFiles = ds.getIncludedFiles();
+            for(int i=0; i&lt;includedFiles.length; i++) {
+                String filename = includedFiles[i].replace('\\','/');           // 4
+                filename = filename.substring(filename.lastIndexOf("/")+1);
+                if (foundLocation==null &amp;&amp; file.equals(filename)) {
+                    File base  = ds.getBasedir();                               // 5
+                    File found = new File(base, includedFiles[i]);
+                    foundLocation = found.getAbsolutePath();
+                }
+            }
+        }
+        if (foundLocation!=null)                                                // 6
+            getProject().setNewProperty(location, foundLocation);
+    }
+</pre>
+
+<p>On <b>//1</b> we check the prerequisites for our task. Doing that in a <tt>validate</tt>-method
+is a common way, because we separate the prerequisites from the real work. On <b>//2</b> we iterate
+over all nested filesets. If we don't want to handle multiple filesets, the <tt>addFileset()</tt>
+method has to reject the further calls. We can get the result of a fileset via its DirectoryScanner
+like done in <b>//3</b>. After that we create a plattform independend String representation of
+the file path (<b>//4</b>, can be done in other ways of course). We have to do the <tt>replace()</tt>,
+because we work with a simple string comparison. Ant itself is platform independant and can
+therefore run on filesystems with slash (/, e.g. Linux) or backslash (\, e.g. Windows) as
+path separator. Therefore we have to unify that. If we found our file we create an absolute
+path representation on <b>//5</b>, so that we can use that information without knowing the basedir.
+(This is very important on use with multiple filesets, because they can have different basedirs
+and the return value of the directory scanner is relative to its basedir.) Finally we store the
+location of the file as property, if we had found one (<b>//6</b>).</p>
+
+<p>Ok, much more easier in this simple case would be to add the <i>file</i> as additional
+<i>include</i> element to all filesets. But I wanted to show how to handle complex situations
+whithout being complex :-)</p>
+
+<p>The test case uses the ant property <i>ant.home</i> as reference. This property is set by the
+<tt>Launcher</tt> class which starts ant. We can use that property in our buildfiles as a
+<a href="using.html#built-in-props">build-in property [3]</a>. But if we create a new ant
+environment we have to set that value for our own. And we use the <code>&lt;junit&gt;</code> task in fork-mode.
+Therefore we have do modify our buildfile:
+<pre class="code">
+    &lt;target name="junit" description="Runs the unit tests" depends="jar"&gt;
+        &lt;delete dir="${junit.out.dir.xml}"/&gt;
+        &lt;mkdir  dir="${junit.out.dir.xml}"/&gt;
+        &lt;junit printsummary="yes" haltonfailure="no"&gt;
+            &lt;classpath refid="classpath.test"/&gt;
+            <b>&lt;sysproperty key="ant.home" value="${ant.home}"/&gt;</b>
+            &lt;formatter type="xml"/&gt;
+            &lt;batchtest fork="yes" todir="${junit.out.dir.xml}"&gt;
+                &lt;fileset dir="${src.dir}" includes="**/*Test.java"/&gt;
+            &lt;/batchtest&gt;
+        &lt;/junit&gt;
+    &lt;/target&gt;
+</pre>
+
+
+<h2><a name="path">Using nested paths</a></h2>
+<p>A task providing support for filesets is a very comfortable one. But there is another
+possibility of bundling files: the <code>&lt;path&gt;</code>. Fileset are easy if the files are all under
+a common base directory. But if this is not the case you have a problem. Another disadvantage
+is its speed: if you have only a few files in a huge directory structure, why not use a
+<code>&lt;filelist&gt;</code> instead? <code>&lt;path&gt;</code>s combines these datatypes in that way that a path contains
+other paths, filesets, dirsets and filelists. This is why <a href="http://ant-contrib.sourceforge.net/">
+Ant-Contribs [4]</a> <code>&lt;foreach&gt;</code> task is modified to support paths instead of filesets. So we want that,
+too.</p>
+
+<p>Changing from fileset to path support is very easy:</p>
+<pre class="code">
+<i><b>Change java code from:</b></i>
+    private Vector filesets = new Vector();
+    public void addFileset(FileSet fileset) {
+        filesets.add(fileset);
+    }
+<i><b>to:</b></i>
+    private Vector paths = new Vector();                      *1
+    public void add<b>Path</b>(<b>Path</b> path) {                          *2
+        paths.add(path);
+    }
+<i><b>and build file from:</b></i>
+    &lt;find file="ant.jar" location="location.ant-jar"&gt;
+        &lt;fileset dir="${ant.home}" includes="**/*.jar"/&gt;
+    &lt;/find&gt;
+<i><b>to:</b></i>
+    &lt;find file="ant.jar" location="location.ant-jar"&gt;
+        <b>&lt;path&gt;</b>                                                *3
+            &lt;fileset dir="${ant.home}" includes="**/*.jar"/&gt;
+        &lt;/path&gt;
+    &lt;/find&gt;
+</pre>
+<p>On <b>*1</b> we rename only the vector. It�s just for better reading the source. On <b>*2</b>
+we have to provide the right method: an add<i>Name</i>(<i>Type</i> t). Therefore replace the
+fileset with path here. Finally we have to modify our buildfile on <b>*3</b> because our task
+doesn�t support nested filesets any longer. So we wrap the fileset inside a path.</p>
+
+<p>And now we modify the testcase. Oh, not very much to do :-) Renaming the <tt>testMissingFileset()</tt>
+(not really a <i>must-be</i> but better it�s named like the think it does) and update the
+<i>expected</i>-String in that method (now a <tt>path not set</tt> message is expected). The more complex
+test cases base on the buildscript. So the targets <tt>testFileNotPresent</tt> and <tt>testFilePresent</tt> have to be
+modified in the manner described above.</p>
+
+<p>The test are finished. Now we have to adapt the task implementation. The easiest modification is
+in the <tt>validate()</tt> method where we change le last line to <tt>if (paths.size()&lt;1) throw new
+BuildException("path not set");</tt>. In the <tt>execute()</tt> method we have a little more work.
+... mmmh ... in reality it's lesser work, because the Path class does the whole DirectoryScanner-handling
+and creating-absolute-paths stuff for us. So the execute method is just:</p>
+
+<pre class="code">
+    public void execute() {
+        validate();
+        String foundLocation = null;
+        for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) {
+            Path path = (<b>Path</b>)itPaths.next();                                // 1
+            String[] includedFiles = <b>path.list()</b>;                            // 2
+            for(int i=0; i&lt;includedFiles.length; i++) {
+                String filename = includedFiles[i].replace('\\','/');
+                filename = filename.substring(filename.lastIndexOf("/")+1);
+                if (foundLocation==null &amp;&amp; file.equals(filename)) {
+                    <b>foundLocation = includedFiles[i];</b>                        // 3
+                }
+            }
+        }
+        if (foundLocation!=null)
+            getProject().setNewProperty(location, foundLocation);
+    }
+</pre>
+
+<p>Of course we have to do the typecase to Path on <b>//1</b>. On <b>//2</b> and <b>//3</b>
+we see that the Path class does the work for us: no DirectoryScanner (was at 2) and no
+creating of the absolute path (was at 3).</p>
+
+
+
+<h2><a name="returning-list">Returning a list</a></h2>
+<p>So far so good. But could a file be on more than one place in the path? - Of course.<br>
+And would it be good to get all of them? - It depends on ...<p>
+
+<p>In this section we will extend that task to support returning a list of all files.
+Lists as property values are not supported by Ant natively. So we have to see how other
+tasks use lists. The most famous task using lists is Ant-Contribs <code>&lt;foreach&gt;</code>. All list
+elements are concatenated and separated with a customizable separator (default ',').</p>
+
+<p>So we do the following:</p>
+
+<pre class="code">
+    &lt;find ... <b>delimiter=""</b>/&gt; ... &lt;/find&gt;
+</pre>
+
+<p>If the delimiter is set we will return all found files as list with that delimiter.</p>
+
+<p>Therefore we have to<ul>
+<li>provide a new attribute</li>
+<li>collect more than the first file</li>
+<li>delete duplicates</li>
+<li>create the list if necessary</li>
+<li>return that list</li>
+</ul></p>
+
+<p>So we add as testcase:</p>
+<pre class="code">
+<b><i>in the buildfile:</i></b>
+    &lt;target name="test.init"&gt;
+        &lt;mkdir dir="test1/dir11/dir111"/&gt;                             *1
+        &lt;mkdir dir="test1/dir11/dir112"/&gt;
+        ...
+        &lt;touch file="test1/dir11/dir111/test"/&gt;
+        &lt;touch file="test1/dir11/dir111/not"/&gt;
+        ...
+        &lt;touch file="test1/dir13/dir131/not2"/&gt;
+        &lt;touch file="test1/dir13/dir132/test"/&gt;
+        &lt;touch file="test1/dir13/dir132/not"/&gt;
+        &lt;touch file="test1/dir13/dir132/not2"/&gt;
+        &lt;mkdir dir="test2"/&gt;
+        &lt;copy todir="test2"&gt;                                          *2
+            &lt;fileset dir="test1"/&gt;
+        &lt;/copy&gt;
+    &lt;/target&gt;
+
+    &lt;target name="testMultipleFiles" depends="use.init,<b>test.init</b>"&gt;    *3
+        &lt;find file="test" location="location.test" <b>delimiter=";"</b>&gt;
+            &lt;path&gt;
+                &lt;fileset dir="test1"/&gt;
+                &lt;fileset dir="test2"/&gt;
+            &lt;/path&gt;
+        &lt;/find&gt;
+        &lt;delete&gt;                                                      *4
+            &lt;fileset dir="test1"/&gt;
+            &lt;fileset dir="test2"/&gt;
+        &lt;/delete&gt;
+    &lt;/target&gt;
+
+<b><i>in the test class:</i></b>
+    public void testMultipleFiles() {
+        executeTarget("testMultipleFiles");
+        String result = getProject().getProperty("location.test");
+        assertNotNull("Property not set.", result);
+        assertTrue("Only one file found.", result.indexOf(";") &gt; -1);
+    }
+</pre>
+
+<p>Now we need a directory structure where we CAN find files with the same
+name in different directories. Because we can't sure to have one we create
+one on <b>*1</b> and <b>*2</b>. And of course we clean up that on <b>*4</b>. The creation
+can be done inside our test target or in a separate one, which will be better
+for reuse later (<b>*3</b>).
+
+<p>The task implementation is modified as followed:</p>
+
+<pre class="code">
+    private Vector foundFiles = new Vector();
+    ...
+    private String delimiter = null;
+    ...
+    public void setDelimiter(String delim) {
+        delimiter = delim;
+    }
+    ...
+    public void execute() {
+        validate();
+        // find all files
+        for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) {
+            Path path = (Path)itPaths.next();
+            String[] includedFiles = path.list();
+            for(int i=0; i&lt;includedFiles.length; i++) {
+                String filename = includedFiles[i].replace('\\','/');
+                filename = filename.substring(filename.lastIndexOf("/")+1);
+                if (file.equals(filename) &amp;&amp; <b>!foundFiles.contains(includedFiles[i]</b>)) {   // 1
+                    foundFiles.add(includedFiles[i]);
+                }
+            }
+        }
+
+        // create the return value (list/single)
+        String rv = null;
+        if (foundFiles.size() &gt; 0) {                                        // 2
+            if (delimiter==null) {
+                // only the first
+                rv = (String)foundFiles.elementAt(0);
+            } else {
+                // create list
+                StringBuffer list = new StringBuffer();
+                for(Iterator it=foundFiles.iterator(); it.hasNext(); ) {    // 3
+                    list.append(it.next());
+                    if (<b>it.hasNext()</b>) list.append(delimiter);               // 4
+                }
+                rv = list.toString();
+            }
+        }
+
+        // create the property
+        if (rv!=null)
+            getProject().setNewProperty(location, rv);
+    }
+</pre>
+
+<p>The algorithm does: finding all files, creating the return value depending on the users
+wish, returning the value as property. On <b>//1</b> we eliminates the duplicates. <b>//2</b>
+ensures that we create the return value only if we have found one file. On <b>//3</b> we
+iterate over all found files and <b>//4</b> ensures that the last entry has no trailing
+delimiter.</p>
+
+<p>Ok, first searching for all files and then returning only the first one ... You can
+tune the performance of your own :-)</p>
+
+
+<h2><a name="documentation">Documentation</a></h2>
+<p>A task is useless if the only who is able to code the buildfile is the task developer
+(and he only the next few weeks :-). So documentation is also very important. In which
+form you do that depends on your favourite. But inside Ant there is a common format and
+it has advantages if you use that: all task users know that form, this form is requested if
+you decide to contribute your task. So we will doc our task in that form.</p>
+
+<p>If you have a look at the manual page of the <a href="CoreTasks/java.html">java [5]</a>
+   task you will see<ul>
+<li>it is plain html</li>
+<li>starts with the name</li>
+<li>has sections: description, parameters, nested elements, (maybe return codes) and (most
+important :-) examples</li>
+<li>parameters are listed in a table with columns for attribute name, its description and whether
+  it's required (if you add a feature after an Ant release, provide a <tt>since Ant xx</tt>
+  statement when it's introduced)</li>
+<li>describe the nested elements (since-statement if necessary)</li>
+<li>provide one or more useful examples; first code then description</li>
+</ul>
+As a template we have:
+
+<pre class="code">
+&lt;html&gt;
+
+&lt;head&gt;
+&lt;meta http-equiv="Content-Language" content="en-us"&gt;
+&lt;title&gt; <b>Taskname</b> Task&lt;/title&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+
+&lt;h2&gt;&lt;a name="<i>taskname</i>"&gt;<b>Taskname</b>&lt;/a&gt;&lt;/h2&gt;
+&lt;h3&gt;Description&lt;/h3&gt;
+&lt;p&gt; <b>Describe the task.</b>&lt;/p&gt;
+
+&lt;h3&gt;Parameters&lt;/h3&gt;
+&lt;table border="1" cellpadding="2" cellspacing="0"&gt;
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;&lt;b&gt;Attribute&lt;/b&gt;&lt;/td&gt;
+    &lt;td valign="top"&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;&lt;b&gt;Required&lt;/b&gt;&lt;/td&gt;
+  &lt;/tr&gt;
+
+  <b>do this html row for each attribute (including inherited attributes)</b>
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;classname&lt;/td&gt;
+    &lt;td valign="top"&gt;the Java class to execute.&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;Either jar or classname&lt;/td&gt;
+  &lt;/tr&gt;
+
+&lt;/table&gt;
+
+&lt;h3&gt;Parameters specified as nested elements&lt;/h3&gt;
+
+<b>Describe each nested element (including inherited)</b>
+&lt;h4&gt;your nested element</b>&lt;/h4&gt;
+&lt;p&gt; <b>description</b> &lt;/p&gt;
+&lt;p&gt;&lt;em&gt;since Ant 1.6&lt;/em&gt;.&lt;/p&gt;
+
+&lt;h3&gt;Examples&lt;/h3&gt;
+&lt;pre&gt;
+    <b>A code sample; don't forget to escape the &lt; of the tags with &amp;lt;</b>
+&lt;/pre&gt;
+<b>what should that example do?</b>
+
+&lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<p>For our task we have <a href="CoreTasks/find.html">that [6]</a>:</p>
+<pre class="code">
+&lt;html&gt;
+
+&lt;head&gt;
+&lt;meta http-equiv="Content-Language" content="en-us"&gt;
+&lt;title&gt; Find Task&lt;/title&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+
+&lt;h2&gt;&lt;a name="find"&gt;Find&lt;/a&gt;&lt;/h2&gt;
+&lt;h3&gt;Description&lt;/h3&gt;
+&lt;p&gt;Searchs in a given path for a file and returns the absolute to it as property.
+If delimiter is set this task returns all found locations.&lt;/p&gt;
+
+&lt;h3&gt;Parameters&lt;/h3&gt;
+&lt;table border="1" cellpadding="2" cellspacing="0"&gt;
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;&lt;b&gt;Attribute&lt;/b&gt;&lt;/td&gt;
+    &lt;td valign="top"&gt;&lt;b&gt;Description&lt;/b&gt;&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;&lt;b&gt;Required&lt;/b&gt;&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;file&lt;/td&gt;
+    &lt;td valign="top"&gt;The name of the file to search.&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;yes&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;location&lt;/td&gt;
+    &lt;td valign="top"&gt;The name of the property where to store the location&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;yes&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td valign="top"&gt;delimiter&lt;/td&gt;
+    &lt;td valign="top"&gt;A delimiter to use when returning the list&lt;/td&gt;
+    &lt;td align="center" valign="top"&gt;only if the list is required&lt;/td&gt;
+  &lt;/tr&gt;
+&lt;/table&gt;
+
+&lt;h3&gt;Parameters specified as nested elements&lt;/h3&gt;
+
+&lt;h4&gt;path&lt;/h4&gt;
+&lt;p&gt;The path where to search the file.&lt;/p&gt;
+
+&lt;h3&gt;Examples&lt;/h3&gt;
+&lt;pre&gt;
+    &lt;find file="ant.jar" location="loc"&gt;
+        &lt;path&gt;
+            &lt;fileset dir="${ant.home}"/&gt;
+        &lt;path&gt;
+    &lt;/find&gt;
+&lt;/pre&gt;
+Searches in Ants home directory for a file &lt;i&gt;ant.jar&lt;/i&gt; and stores its location in
+property &lt;i&gt;loc&lt;/i&gt; (should be ANT_HOME/bin/ant.jar).
+
+&lt;pre&gt;
+    &lt;find file="ant.jar" location="loc" delimiter=";"&gt;
+        &lt;path&gt;
+            &lt;fileset dir="C:/"/&gt;
+        &lt;path&gt;
+    &lt;/find&gt;
+    &lt;echo&gt;ant.jar found in: ${loc}&lt;/echo&gt;
+&lt;/pre&gt;
+Searches in Windows C: drive for all &lt;i&gt;ant.jar&lt;/i&gt; and stores their locations in
+property &lt;i&gt;loc&lt;/i&gt; delimited with &lt;i&gt;';'&lt;/i&gt;. (should need a long time :-)
+After that it prints out the result (e.g. C:/ant-1.5.4/bin/ant.jar;C:/ant-1.6/bin/ant.jar).
+
+&lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+
+<h2><a name="contribute">Contribute the new task</a></h2>
+If we decide to contribute our task, we should do some things:<ul>
+<li>is our task welcome? :-) Simply ask on the user list</li>
+<li>is the right package used? </li>
+<li>does the code conform to the styleguide?</li>
+<li>do all tests pass? </li>
+<li>does the code compile on JDK 1.2 (and passes all tests there)?</li>
+<li>code under Apache license</li>
+<li>create a patch file</li>
+<li>publishing that patch file</li>
+</ul>
+The <a href="../ant_task_guidelines.html">Ant Task Guidelines [7]</a> support additional
+information on that.</p>
+
+<p>Now we will check the "Checklist before submitting a new task" described in that guideline.
+<ul>
+<li>Java file begins with Apache license statement. <b><i>must do that</i></b></li>
+<li>Task does not depend on GPL or LGPL code. <b><i>ok</i></b></li>
+<li>Source code complies with style guidelines <b><i>have to check (checkstyle)</i></b></li>
+<li>Code compiles and runs on Java1.2 <b><i>have to try</i></b></li>
+<li>Member variables are private, and provide public accessor methods
+        if access is actually needed. <b><i>have to check (checkstyle)</i></b></li>
+<li><i>Maybe</i> Task has failonerror attribute to control failure behaviour <b><i>hasn't</i></b></li>
+<li>New test cases written and succeed <b><i>passed on JDK 1.4, have to try on JDK 1.2</i></b></li>
+<li>Documentation page written <b><i>ok</i></b></li>
+<li>Example task declarations in the documentation tested. <b><i>ok (used in tests)</i></b></li>
+<li>Patch files generated using cvs diff -u <b><i>to do</i></b></li>
+<li>patch files include a patch to defaults.properties to register the
+tasks <b><i>to do</i></b></li>
+<li>patch files include a patch to coretasklist.html or
+optionaltasklist.html to link to the new task page <b><i>to do</i></b></li>
+<li>Message to dev contains [SUBMIT] and task name in subject <b><i>to do</i></b></li>
+<li>Message body contains a rationale for the task <b><i>to do</i></b></li>
+<li>Message attachments contain the required files -source, documentation,
+test and patches zipped up to escape the HTML filter. <b><i>to do</i></b></li>
+</ul>
+
+
+<h3>Package / Directories</h3>
+<p>This task does not depend on any external library. Therefore we can use this as
+a core task. This task contains only one class. So we can use the standard package
+for core tasks: <tt>org.apache.tools.ant.taskdefs</tt>. Implementations are in the
+directory <tt>src/main</tt>, tests in <tt>src/testcases</tt> and buildfiles for
+tests in <tt>src/etc/testcases</tt>.</p>
+
+<p>Now we integrate our work into Ants distribution. So first we do an update of our
+cvs tree. If not done yet, you have to checkout the ant module from Apaches cvs server
+as described in <a href="http://ant.apache.org/cvs.html">Access the Source Tree (AnonCVS)
+[8]</a> (password is <i>anoncvs</i>):<pre class="output">
+cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login                 //1
+cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic checkout ant          //2
+</pre>
+If you have a local copy of Ants sources just do an update
+<pre class="output">
+cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic login
+cd ant                                                                       //3
+cvs -d :pserver:anoncvs@cvs.apache.org:/home/cvspublic update                //4
+</pre></p>
+
+<p>We use the <i>-d</i> flag on <b>//1</b> to specifiy the cvs directory. You can
+specify the environment variable CVSROOT with that value and after that you haven�t
+to use that flag any more. On <b>//2</b> we get the whole cvs tree of ant. (Sorry,
+but that uses a lot of time ... 10 up to 30 minutes are not unusual ... but this has
+to be done only once :-). A cvs update doesn't use a modulename but you have to be
+inside the directory. Therefore we go into that on <b>//3</b> and do the update
+on <b>//4</b>.</p>
+
+<p>Now we will build our Ant distribution and do a test. So we can see if there
+are any tests failing on our machine. (We can ignore these failing tests on later
+steps; windows syntax used here- translate to xNIX if needed):
+<pre class="output">
+ANTHOME&gt; build                                                    // 1
+ANTHOME&gt; set ANT_HOME=%CD%\dist                                   // 2
+ANTHOME&gt; ant test -Dtest.haltonfailure=false                      // 3
+</pre>
+
+First we have to build our Ant distribution (<b>//1</b>). On <b>//2</b> we set the ANT_HOME
+environment variable to the directory where the new created distribution is stored
+(%CD% is expanded to the current directory on Windows 2000 and XP, on 9x and NT
+write it out). On <b>//3</b> we let Ant do all the tests (which enforced a compile
+of all tests) without stopping on first failure.</p>
+
+<p>Next we apply our work onto Ants sources. Because we haven't modified any, this is
+a relative simple step. <i>(Because I have a local copy of Ant and usually contribute my
+work, I work on the local copy just from the beginning. The advantage: this step isn't
+necessary and saves a lot of work if you modify existing source :-)</i>.
+
+<ul>
+<li>move the Find.java to ANTHOME/src/main/org/apache/tools/ant/taskdefs/Find.java </li>
+<li>move the FindTest.java to ANTHOME/src/testcases/org/apache/tools/ant/taskdefs/FindTest.java </li>
+<li>move the build.xml to ANTHOME/src/etc/testcases/taskdefs/<b>find.xml</b> (!!! renamed !!!)</li>
+<li>add a <tt>package org.apache.tools.ant.taskdefs;</tt> at the beginning of the two java files </li>
+<li>delete all stuff from find.xml keeping the targets "testFileNotPresent", "testFilePresent",
+    "test.init" and "testMultipleFiles" </li>
+<li>delete the dependency to "use.init" in the find.xml </li>
+<li>in FindTest.java change the line <tt>configureProject("build.xml");</tt> to
+    <tt>configureProject("src/etc/testcases/taskdefs/find.xml");</tt> </li>
+<li>move the find.html to ANTHOME/docs/manual/CoreTasks/find.html </li>
+<li>add a <tt>&lt;a href="CoreTasks/find.html"&gt;Find&lt;/a&gt;&lt;br&gt;</tt>
+    in the ANTHOME/docs/manual/coretasklist.html </li>
+</ul>
+
+Now our modifications are done and we will retest it:
+<pre class="output">
+ANTHOME&gt; build
+ANTHOME&gt; ant run-single-test                                      // 1
+             -Dtestcase=org.apache.tools.ant.taskdefs.FindTest    // 2
+             -Dtest.haltonfailure=false
+</pre>
+Because we only want to test our new class, we use the target for single tests, specify
+the test to use and configure not to halt on the first failure - we want to see all
+failures of our own test (<b>//1 + 2</b>).</p>
+
+<p>And ... oh, all tests fail: <i>Ant could not find the task or a class this task relies upon.</i></p>
+
+<p>Ok: in the earlier steps we told Ant to use the Find class for the <code>&lt;find&gt;</code> task (remember the
+<code>&lt;taskdef&gt;</code> statement in the "use.init" target). But now we want to introduce that task as
+a core task. And nobody wants to taskdef the javac, echo, ... So what to do? The answer is the
+src/main/.../taskdefs/default.properties. Here is the mapping between taskname and implementing
+class done. So we add a <tt>find=org.apache.tools.ant.taskdefs.Find</tt> as the last core
+task (just before the <tt># optional tasks</tt> line). Now a second try:
+<pre class="output">
+ANTHOME&gt; build                                                    // 1
+ANTHOME&gt; ant run-single-test
+             -Dtestcase=org.apache.tools.ant.taskdefs.FindTest
+             -Dtest.haltonfailure=false
+</pre>
+We have to rebuild (<b>//1</b>) Ant because the test look in the %ANT_HOME%\lib\ant.jar
+(more precise: on the classpath) for the properties file. And we have only modified it in the
+source path. So we have to rebuild that jar. But now all tests pass and we check whether our class
+breaks some other tests.
+<pre class="output">
+ANTHOME&gt; ant test -Dtest.haltonfailure=false
+</pre>
+Because there are a lot of tests this step requires a little bit of time. So use the <i>run-single-test</i>
+during development and do the <i>test</i> only at the end (maybe sometimes during development too).
+We use the <i>-Dtest.haltonfailure=false</i> here because there could be other tests fail and we have
+to look into them.</p>
+
+<p>This test run should show us two things: our test will run and the number of failing tests
+is the same as directly after the cvs update (without our modifications).</p>
+
+
+
+<h3>Apache license statement</h3>
+<p>Simply copy the license text from one the other source from the Ant source tree.</p>
+
+
+<h3>Test on JDK 1.2</h3>
+<p>Until version 1.5 Ant must be able to run on a JDK 1.1. With version 1.6 this is not a
+requisite any more. But JDK 1.2 is a must-to-work-with. So we have to test that. You can download older
+JDKs from <a href="http://java.sun.com/products/archive/index.html">Sun [9]</a>.</p>
+
+<p>Clean the ANT_HOME variable, delete the <i>build, bootstrap</i> and <i>dist</i> directory
+and point JAVA_HOME to the JDK 1.2 home directory. Then do the <tt>build</tt>, set ANT_HOME
+and run <tt>ant test</tt> (like above).</p>
+
+<p>Our test should pass.</p>
+
+
+
+<h3>Checkstyle</h3>
+<p>There are many things we have to ensure. Indentation with 4 spaces, blanks here and there, ...
+(all described in the <a href="../ant_task_guidelines.html">Ant Task Guidelines [7]</a> which
+includes the <a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">Sun code style
+[10]</a>). Because there are so many things we would be happy to have a tool for do the checks.
+There is one: checkstyle. Checkstyle is available at <a href="http://checkstyle.sourceforge.net/">
+Sourceforge [11]</a> and Ant provides with the <tt>check.xml</tt> a buildfile which will do the job
+for us.</p>
+
+<p>Download it and put the checkstyle-*-all.jar into your %USERPROFILE%\.ant\lib directory.
+All jar's stored there are available to Ant so you haven't to add it to you %ANT_HOME%\lib
+directory (this feature was added with Ant 1.6).</p>
+
+<p>So we will run the tests with
+<pre class="output">
+ANTHOME&gt; ant -f check.xml checkstyle htmlreport
+</pre>
+I prefer the HTML report because there are lots of messages and we can navigate faster.
+Open the ANTHOME/build/reports/checkstyle/html/index.html and navigate to the Find.java. Now we
+see that there are some errors: missing whitespaces, unused imports, missing javadocs. So we have
+to do that.</p>
+
+<p>Hint: start at the <b>buttom</b> of the file so the line numbers in the report will keep
+up to date and you will find the next error place much more easier without redoing the checkstyle.</p>
+
+<p>After cleaning up the code according to the messages we delete the reports directory and
+do a second checkstyle run. Now our task isn't listed. That's fine :-)</p>
+
+
+
+<!--
+  Couldnt create the diff that way for myself, but that should be documented.
+  But on the other hand this tutorial should not be forgotten any longer so I
+  comment that out.  JHM
+<h3>Creating the diff</h3>
+<p>Creating a diff for Ant is very easy: just start <tt>ant -f patch.xml</tt> and all is done
+automatically. This step requires a cvs executable in your path and internet access (more precise:
+cvs access). As a result we get a file <i> XXX </i>.</p>
+-->
+
+
+<h3>Publish the task</h3>
+<p>Finally we publish that archive. As described in the <a href="../ant_task_guidelines.html">
+Ant Task Guidelines [7]</a> we can post it on the developer mailinglist or we create a BugZilla
+entry. For both we need some information:</p>
+
+<table border="1">
+<tr>
+  <th>subject</th>
+  <td><i>short description</i></td>
+  <td>Task for finding files in a path</td>
+</tr>
+<tr>
+  <th>body</th>
+  <td><i>more details about the path</i></td>
+  <td>This new task looks inside a nested <code>&lt;path/&gt;</code> for occurrences of a file and stores
+      all locations as a property. See the included manual for details.</td>
+</tr>
+<tr>
+  <th>attachements</th>
+  <td><i>all files needed to apply the path</td>
+  <td>Archive containing a patch with the new and modified resources</td>
+</tr>
+</table>
+
+<p>Sending an email with these information is very easy and I think I haven't to show that.
+The other way - BugZilla - is slightly more difficult. But it has the advantage that entries
+will not be forgotten (once per week a report is generated). So I will show this way.</p>
+
+<p>You must have a BugZilla account for that. So open the <a href="http://issues.apache.org/bugzilla/">
+BugZilla Main Page [12]</a> and follow the link
+<a href="http://issues.apache.org/bugzilla/createaccount.cgi">Open a new Bugzilla account [13]</a>
+and the steps described there if you haven't one.</p>
+
+<ol>
+<li>From the BugZilla main page choose <a href="http://issues.apache.org/bugzilla/enter_bug.cgi">Enter
+    a new bug report [14]</a></li>
+<li>Choose "Ant" as product </li>
+<li>Version is the last "Alpha (nightly)" (at this time 1.7)</li>
+<li>Component is "Core tasks"</li>
+<li>Plattform and Severity are ok with "Other" and "Normal"</li>
+<li>Initial State is ok with "New"</li>
+<li>Same with the empy "Assigned to"</li>
+<li>It is not required to add yourself as CC, because you are the reporter and therefore will be
+    informed on changes</li>
+<li>URL: no url required</li>
+<li>Summary: add the <i>subject</i> from the table</li>
+<li>Description: add the <i>body</i> from the table</li>
+<li>Then press "Commit"</li>
+<li>After redirecting to the new created bug entry click "Create a New Attachment"</li>
+<li>Enter the path to your local path file into "File" or choose it via the "File"'s
+    button.</li>
+<li>Enter a short description into "Description", so that you could guess, what the
+    path file includes. Here we could add "Initial Patch".</li>
+<li>The "Content Type" is "auto-detect". You could use the "patch" type, if you only
+    provide a single path file, but we want do upload more that one, included in our
+    patch.zip.</li>
+<li>Then press "Commit"</li>
+</ol>
+Now the new task is uploaded into the bug database.
+
+
+<h2><a name="resources">Resources</a></h2>
+&nbsp;&nbsp;[1] <a href="tutorial-writing-tasks.html">tutorial-writing-tasks.html</a><br>
+&nbsp;&nbsp;[2] <a href="tutorial-tasks-filesets-properties.zip">tutorial-tasks-filesets-properties.zip</a><br>
+&nbsp;&nbsp;[3] <a href="using.html#built-in-props">using.html#built-in-props</a><br>
+&nbsp;&nbsp;[4] <a href="http://ant-contrib.sourceforge.net/">http://ant-contrib.sourceforge.net/</a><br>
+&nbsp;&nbsp;[5] <a href="CoreTasks/java.html">CoreTasks/java.html</a><br>
+&nbsp;&nbsp;[6] <a href="CoreTasks/find.html">CoreTasks/find.html</a><br>
+&nbsp;&nbsp;[7] <a href="../ant_task_guidelines.html">../ant_task_guidelines.html</a><br>
+&nbsp;&nbsp;[8] <a href="http://ant.apache.org/cvs.html">http://ant.apache.org/cvs.html</a><br>
+&nbsp;&nbsp;[9] <a href="http://java.sun.com/products/archive/index.html">http://java.sun.com/products/archive/index.html</a><br>
+&nbsp;&nbsp;[10] <a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html</a><br>
+&nbsp;&nbsp;[11] <a href="http://checkstyle.sourceforge.net/">http://checkstyle.sourceforge.net/</a><br>
+&nbsp;&nbsp;[12] <a href="http://issues.apache.org/bugzilla/">http://issues.apache.org/bugzilla/</a><br>
+&nbsp;&nbsp;[13] <a href="http://issues.apache.org/bugzilla/createaccount.cgi">http://issues.apache.org/bugzilla/createaccount.cgi</a><br>
+&nbsp;&nbsp;[14] <a href="http://issues.apache.org/bugzilla/enter_bug.cgi">http://issues.apache.org/bugzilla/enter_bug.cgi</a><br>
+
+
+<!--
+  TODO:
+  - how to create a path (path.xml / command line)
+-->
+
+
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/tutorial-tasks-filesets-properties.zip b/trunk/docs/manual/tutorial-tasks-filesets-properties.zip
new file mode 100644
index 0000000..94c8a10
--- /dev/null
+++ b/trunk/docs/manual/tutorial-tasks-filesets-properties.zip
Binary files differ
diff --git a/trunk/docs/manual/tutorial-writing-tasks-src.zip b/trunk/docs/manual/tutorial-writing-tasks-src.zip
new file mode 100644
index 0000000..3567c3b
--- /dev/null
+++ b/trunk/docs/manual/tutorial-writing-tasks-src.zip
Binary files differ
diff --git a/trunk/docs/manual/tutorial-writing-tasks.html b/trunk/docs/manual/tutorial-writing-tasks.html
new file mode 100644
index 0000000..96ca63c
--- /dev/null
+++ b/trunk/docs/manual/tutorial-writing-tasks.html
@@ -0,0 +1,767 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+<head>
+  <title>Tutorial: Writing Tasks</title>
+  <link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+</head>
+<body>
+<h1>Tutorial: Writing Tasks</h1>
+
+<p>This document provides a step by step tutorial for writing
+tasks.</p>
+<h2>Content</h2>
+<p><ul>
+<li><a href="#buildenvironment">Set up the build environment</a></li>
+<li><a href="#write1">Write the Task</a></li>
+<li><a href="#use1">Use the Task</a></li>
+<li><a href="#TaskAdapter">Integration with TaskAdapter</a></li>
+<li><a href="#derivingFromTask">Deriving from Ant's Task</a></li>
+<li><a href="#attributes">Attributes</a></li>
+<li><a href="#NestedText">Nested Text</a></li>
+<li><a href="#NestedElements">Nested Elements</a></li>
+<li><a href="#complex">Our task in a little more complex version</a></li>
+<li><a href="#TestingTasks">Test the Task</a></li>
+<li><a href="#resources">Resources</a></li>
+</ul></p>
+
+<a name="buildenvironment"></a>
+<h2>Set up the build environment</h2>
+<p>Ant builds itself, we are using Ant too (why we would write
+a task if not? :-) therefore we should use Ant for our build.<p>
+<p>We choose a directory as root directory. All things will be done
+here if I say nothing different. I will reference this directory
+as <i>root-directory</i> of our project. In this root-directory we
+create a text file names <i>build.xml</i>. What should Ant do for us?
+<ul>
+<li>compiles my stuff</li>
+<li>make the jar, so that I can deploy it</li>
+<li>clean up everything</li>
+</ul>
+So the buildfile contains three targets.
+<pre class="code">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="MyTask" basedir="." default="jar"&gt;
+
+    &lt;target name="clean" description="Delete all generated files"&gt;
+        &lt;delete dir="classes"/&gt;
+        &lt;delete file="MyTasks.jar"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="compile" description="Compiles the Task"&gt;
+        &lt;javac srcdir="src" destdir="classes"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="jar" description="JARs the Task"&gt;
+        &lt;jar destfile="MyTask.jar" basedir="classes"/&gt;
+    &lt;/target&gt;
+
+&lt;/project&gt;
+</pre>
+
+This buildfile uses often the same value (src, classes, MyTask.jar), so we should rewrite that
+using <code>&lt;property&gt;</code>s. On second there are some handicaps: <code>&lt;javac&gt;</code> requires that the destination
+directory exists; a call of "clean" with a non existing classes directory will fail; "jar" requires
+the execution of some steps bofore. So the refactored code is:
+
+<pre class="code">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="MyTask" basedir="." default="jar"&gt;
+
+    <b>&lt;property name="src.dir" value="src"/&gt;</b>
+    <b>&lt;property name="classes.dir" value="classes"/&gt;</b>
+
+    &lt;target name="clean" description="Delete all generated files"&gt;
+        &lt;delete dir="<b>${classes.dir}</b>" <b>failonerror="false"</b>/&gt;
+        &lt;delete file="<b>${ant.project.name}.jar</b>"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="compile" description="Compiles the Task"&gt;
+        <b>&lt;mkdir dir="${classes.dir}"/&gt;</b>
+        &lt;javac srcdir="<b>${src.dir}</b>" destdir="${classes.dir}"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="jar" description="JARs the Task" <b>depends="compile"</b>&gt;
+        &lt;jar destfile="${ant.project.name}.jar" basedir="${classes.dir}"/&gt;
+    &lt;/target&gt;
+
+&lt;/project&gt;
+</pre>
+<i>ant.project.name</i> is one of the
+<a href="http://ant.apache.org/manual/using.html#built-in-props" target="_blank">
+build-in properties [1]</a> of Ant.
+
+
+<a name="write1"></a>
+<h2>Write the Task</h2>
+
+Now we write the simplest Task - a HelloWorld-Task (what else?). Create a text file
+<i>HelloWorld.java</i> in the src-directory with:
+<pre class="code">
+public class HelloWorld {
+    public void execute() {
+        System.out.println("Hello World");
+    }
+}
+</pre>
+and we can compile and jar it with <tt>ant</tt> (default target is "jar" and via
+its <i>depends</i>-clause the "compile" is executed before).
+
+
+
+<a name="use1"></a>
+<h2>Use the Task</h2>
+<p>But after creating the jar we want to use our new Task. Therefore we need a
+new target "use". Before we can use our new task we have to declare it with
+<a href="http://ant.apache.org/manual/CoreTasks/taskdef.html" target="_blank">
+<code>&lt;taskdef&gt;</code> [2]</a>. And for easier process we change the default clause:
+<pre class="code">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="MyTask" basedir="." default="<b>use</b>"&gt;
+
+    ...
+
+    <b>&lt;target name="use" description="Use the Task" depends="jar"&gt;
+        &lt;taskdef name="helloworld" classname="HelloWorld" classpath="${ant.project.name}.jar"/&gt;
+        &lt;helloworld/&gt;
+    &lt;/target&gt;</b>
+
+&lt;/project&gt;
+</pre>
+
+Important is the <i>classpath</i>-attribute. Ant searches in its /lib directory for
+tasks and our task isn't there. So we have to provide the right location. </p>
+
+<p>Now we can type in <tt>ant</tt> and all should work ...
+<pre class="output">
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 1 source file to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+use:
+[helloworld] Hello World
+
+BUILD SUCCESSFUL
+Total time: 3 seconds
+</pre>
+
+
+
+<a name="TaskAdapter"></a>
+<h2>Integration with TaskAdapter</h2>
+<p>Our class has nothing to do with Ant. It extends no superclass and implements
+no interface. How does Ant know to integrate? Via name convention: our class provides
+a method with signature <tt>public void execute()</tt>. This class is wrapped by Ant's
+<tt>org.apache.tools.ant.TaskAdapter</tt> which is a task and uses reflection for
+setting a reference to the project and calling the <i>execute()</i> method.</p>
+
+<p><i>Setting a reference to the project</i>? Could be interesting. The Project class
+gives us some nice abilities: access to Ant's logging facilities getting and setting
+properties and much more. So we try to use that class:
+<pre class="code">
+import org.apache.tools.ant.Project;
+
+public class HelloWorld {
+
+    private Project project;
+
+    public void setProject(Project proj) {
+        project = proj;
+    }
+
+    public void execute() {
+        String message = project.getProperty("ant.project.name");
+        project.log("Here is project '" + message + "'.", Project.MSG_INFO);
+    }
+}
+</pre>
+and the execution with <tt>ant</tt> will show us the expected
+<pre class="output">
+use:
+Here is project 'MyTask'.
+</pre></p>
+
+
+<a name="derivingFromTask"></a>
+<h2>Deriving from Ant's Task</h2>
+<p>Ok, that works ... But usually you will extend <tt>org.apache.tools.ant.Task</tt>.
+That class is integrated in Ant, get's the project-reference, provides documentation
+fiels, provides easier access to the logging facility and (very useful) gives you
+the exact location where <i>in the buildfile</i> this task instance is used.</p>
+
+<p>Oki-doki - let's us use some of these:
+<pre class="code">
+import org.apache.tools.ant.Task;
+
+public class HelloWorld extends Task {
+    public void execute() {
+        // use of the reference to Project-instance
+        String message = getProject().getProperty("ant.project.name");
+
+        // Task's log method
+        log("Here is project '" + message + "'.");
+
+        // where this task is used?
+        log("I am used in: " +  getLocation() );
+    }
+}
+</pre>
+which gives us when running
+<pre class="output">
+use:
+[helloworld] Here is project 'MyTask'.
+[helloworld] I am used in: C:\tmp\anttests\MyFirstTask\build.xml:23:
+</pre>
+
+
+<a name="attributes">
+<h2>Attributes</h2>
+<p>Now we want to specify the text of our message (it seems that we are
+rewriting the <code>&lt;echo/&gt;</code> task :-). First we well do that with an attribute.
+It is very easy - for each attribute provide a <tt>public void set<code>&lt;attributename&gt;</code>(<code>&lt;type&gt;</code>
+newValue)</tt> method and Ant will do the rest via reflection.</p>
+<pre class="code">
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+public class HelloWorld extends Task {
+
+    String message;
+    public void setMessage(String msg) {
+        message = msg;
+    }
+
+    public void execute() {
+        if (message==null) {
+            throw new BuildException("No message set.");
+        }
+        log(message);
+    }
+
+}
+</pre>
+<p>Oh, what's that in execute()? Throw a <i>BuildException</i>? Yes, that's the usual
+way to show Ant that something important is missed and complete build should fail. The
+string provided there is written as build-failes-message. Here it's necessary because
+the log() method can't handle a <i>null</i> value as parameter and throws a NullPointerException.
+(Of course you can initialize the <i>message</i> with a default string.)</p>
+
+<p>After that we have to modify our buildfile:
+<pre class="code">
+    &lt;target name="use" description="Use the Task" depends="jar"&gt;
+        &lt;taskdef name="helloworld"
+                 classname="HelloWorld"
+                 classpath="${ant.project.name}.jar"/&gt;
+        &lt;helloworld <b>message="Hello World"</b>/&gt;
+    &lt;/target&gt;
+</pre>
+That's all.</p>
+
+<p>Some background for working with attributes: Ant supports any of these datatypes as
+arguments of the set-method:<ul>
+<li>elementary data type like <i>int</i>, <i>long</i>, ...</li>
+<li>its wrapper classes like <i>java.lang.Integer</i>, <i>java.lang.Long</i>, ...</li>
+<li><i>java.lang.String</i></li>
+<li>some more classes (e.g. <i>java.io.File</i>; see
+    <a href="http://ant.apache.org/manual/develop.html#set-magic">Manual
+    'Writing Your Own Task' [3]</a>)</li>
+</ul>
+Before calling the set-method all properties are resolved. So a <tt>&lt;helloworld message="${msg}"/&gt;</tt>
+would not set the message string to "${msg}" if there is a property "msg" with a set value.
+
+
+<a name="NestedText"></a>
+<h2>Nested Text</h2>
+<p>Maybe you have used the <code>&lt;echo&gt;</code> task in a way like <tt>&lt;echo&gt;Hello World&lt;/echo&gt;</tt>.
+For that you have to provide a <tt>public void addText(String text)</tt> method.
+<pre class="code">
+...
+public class HelloWorld extends Task {
+    ...
+    public void addText(String text) {
+        message = text;
+    }
+    ...
+}
+</pre>
+But here properties are <b>not</b> resolved! For resolving properties we have to use
+Project's <tt>replaceProperties(String propname) : String</tt> method which takes the
+property name as argument and returns its value (or ${propname} if not set).</p>
+
+
+<a name="NestedElements"></a>
+<h2>Nested Elements</h2>
+<p>There are several ways for inserting the ability of handling nested elements. See
+the <a href="http://ant.apache.org/manual/develop.html#nested-elements">Manual [4]</a> for other.
+We use the first way of the three described ways. There are several steps for that:<ol>
+<li>We create a class for collecting all the info the nested element should contain.
+  This class is created by the same rules for attributes and nested elements
+  as for the task (<code>set&lt;attributename&gt;</code>() methods). </li>
+<li>The task holds multiple instances of this class in a list.</li>
+<li>A factory method instantiates an object, saves the reference in the list
+  and returns it to Ant Core.</li>
+<li>The execute() method iterates over the list and evaluates its values.</li>
+</ol></p>
+<pre class="code">
+import java.util.Vector;
+import java.util.Iterator;
+...
+    public void execute() {
+        if (message!=null) log(message);
+        for (Iterator it=messages.iterator(); it.hasNext(); ) {      <b>// 4</b>
+            Message msg = (Message)it.next();
+            log(msg.getMsg());
+        }
+    }
+
+
+    Vector messages = new Vector();                                  <b>// 2</b>
+
+    public Message createMessage() {                                 <b>// 3</b>
+        Message msg = new Message();
+        messages.add(msg);
+        return msg;
+    }
+
+    public class Message {                                           <b>// 1</b>
+        public Message() {}
+
+        String msg;
+        public void setMsg(String msg) { this.msg = msg; }
+        public String getMsg() { return msg; }
+    }
+...
+</pre>
+<p>Then we can use the new nested element. But where is xml-name for that defined?
+The mapping XML-name : classname is defined in the factory method:
+<tt>public <i>classname</i> create<i>XML-name</i>()</tt>. Therefore we write in
+the buildfile
+<pre class="code">
+        &lt;helloworld&gt;
+            &lt;message msg="Nested Element 1"/&gt;
+            &lt;message msg="Nested Element 2"/&gt;
+        &lt;/helloworld&gt;
+</pre>
+<p>Note that if you choose to use methods 2 or 3, the class that represents the nested
+element must be declared as <pre>static</pre></p>
+
+<a name="complex"></a>
+<h2>Our task in a little more complex version</h2>
+<p>For recapitulation now a little refactored buildfile:
+<pre class="code">
+&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
+&lt;project name="MyTask" basedir="." default="use"&gt;
+
+    &lt;property name="src.dir" value="src"/&gt;
+    &lt;property name="classes.dir" value="classes"/&gt;
+
+    &lt;target name="clean" description="Delete all generated files"&gt;
+        &lt;delete dir="${classes.dir}" failonerror="false"/&gt;
+        &lt;delete file="${ant.project.name}.jar"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="compile" description="Compiles the Task"&gt;
+        &lt;mkdir dir="${classes.dir}"/&gt;
+        &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="jar" description="JARs the Task" depends="compile"&gt;
+        &lt;jar destfile="${ant.project.name}.jar" basedir="${classes.dir}"/&gt;
+    &lt;/target&gt;
+
+
+    &lt;target name="use.init"
+            description="Taskdef the HelloWorld-Task"
+            depends="jar"&gt;
+        &lt;taskdef name="helloworld"
+                 classname="HelloWorld"
+                 classpath="${ant.project.name}.jar"/&gt;
+    &lt;/target&gt;
+
+
+    &lt;target name="use.without"
+            description="Use without any"
+            depends="use.init"&gt;
+        &lt;helloworld/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="use.message"
+            description="Use with attribute 'message'"
+            depends="use.init"&gt;
+        &lt;helloworld message="attribute-text"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="use.fail"
+            description="Use with attribute 'fail'"
+            depends="use.init"&gt;
+        &lt;helloworld fail="true"/&gt;
+    &lt;/target&gt;
+
+    &lt;target name="use.nestedText"
+            description="Use with nested text"
+            depends="use.init"&gt;
+        &lt;helloworld&gt;nested-text&lt;/helloworld&gt;
+    &lt;/target&gt;
+
+    &lt;target name="use.nestedElement"
+            description="Use with nested 'message'"
+            depends="use.init"&gt;
+        &lt;helloworld&gt;
+            &lt;message msg="Nested Element 1"/&gt;
+            &lt;message msg="Nested Element 2"/&gt;
+        &lt;/helloworld&gt;
+    &lt;/target&gt;
+
+
+    &lt;target name="use"
+            description="Try all (w/out use.fail)"
+            depends="use.without,use.message,use.nestedText,use.nestedElement"
+    /&gt;
+
+&lt;/project&gt;
+</pre>
+
+And the code of the task:
+<pre class="code">
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import java.util.Vector;
+import java.util.Iterator;
+
+/**
+ * The task of the tutorial.
+ * Print a message or let the build fail.
+ * @since 2003-08-19
+ */
+public class HelloWorld extends Task {
+
+
+    /** The message to print. As attribute. */
+    String message;
+    public void setMessage(String msg) {
+        message = msg;
+    }
+
+    /** Should the build fail? Defaults to <i>false</i>. As attribute. */
+    boolean fail = false;
+    public void setFail(boolean b) {
+        fail = b;
+    }
+
+    /** Support for nested text. */
+    public void addText(String text) {
+        message = text;
+    }
+
+
+    /** Do the work. */
+    public void execute() {
+        // handle attribute 'fail'
+        if (fail) throw new BuildException("Fail requested.");
+
+        // handle attribute 'message' and nested text
+        if (message!=null) log(message);
+
+        // handle nested elements
+        for (Iterator it=messages.iterator(); it.hasNext(); ) {
+            Message msg = (Message)it.next();
+            log(msg.getMsg());
+        }
+    }
+
+
+    /** Store nested 'message's. */
+    Vector messages = new Vector();
+
+    /** Factory method for creating nested 'message's. */
+    public Message createMessage() {
+        Message msg = new Message();
+        messages.add(msg);
+        return msg;
+    }
+
+    /** A nested 'message'. */
+    public class Message {
+        // Bean constructor
+        public Message() {}
+
+        /** Message to print. */
+        String msg;
+        public void setMsg(String msg) { this.msg = msg; }
+        public String getMsg() { return msg; }
+    }
+
+}
+</pre>
+
+And it works:
+<pre class="output">
+C:\tmp\anttests\MyFirstTask&gt;ant
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 1 source file to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+use.init:
+
+use.without:
+
+use.message:
+[helloworld] attribute-text
+
+use.nestedText:
+[helloworld] nested-text
+
+use.nestedElement:
+[helloworld]
+[helloworld]
+[helloworld]
+[helloworld]
+[helloworld] Nested Element 1
+[helloworld] Nested Element 2
+
+use:
+
+BUILD SUCCESSFUL
+Total time: 3 seconds
+C:\tmp\anttests\MyFirstTask&gt;ant use.fail
+Buildfile: build.xml
+
+compile:
+
+jar:
+
+use.init:
+
+use.fail:
+
+BUILD FAILED
+C:\tmp\anttests\MyFirstTask\build.xml:36: Fail requested.
+
+Total time: 1 second
+C:\tmp\anttests\MyFirstTask&gt;
+</pre>
+Next step: test ...
+
+
+
+<a name="TestingTasks"></a>
+<h2>Test the Task</h2>
+<p>We have written a test already: the use.* tasks in the buildfile. But its
+difficult to test that automatically. Common (and in Ant) used is JUnit for
+that. For testing tasks Ant provides a baseclass <tt>org.apache.tools.ant.BuildFileTest</tt>.
+This class extends <tt>junit.framework.TestCase</tt> and can therefore be integrated
+into the unit tests. But this class provides some for testing tasks useful methods:
+initialize Ant, load a buildfile, execute targets,
+expecting BuildExceptions with a specified text, expect a special text
+in the output log ... </p>
+
+<p>In Ant it is usual that the testcase has the same name as the task with a prepending
+<i>Test</i>, therefore we will create a file <i>HelloWorldTest.java</i>. Because we
+have a very small project we can put this file into <i>src</i> directory (Ant's own
+testclasses are in /src/testcases/...). Because we have already written our tests
+for "hand-test" we can use that for automatic tests, too. But there is one little
+problem we have to solve: all test supporting classes are not part of the binary
+distribution of Ant. So you can build the special jar file from source distro with
+target "test-jar" or you can download a nightly build from
+<a href="http://gump.covalent.net/jars/latest/ant/ant-testutil.jar">
+http://gump.covalent.net/jars/latest/ant/ant-testutil.jar [5]</a>.</p>
+
+<p>For executing the test and creating a report we need the optional tasks <code>&lt;junit&gt;</code>
+and <code>&lt;junitreport&gt;</code>. So we add to the buildfile:
+<pre class="code">
+...
+<font color="#9F9F9F">&lt;project name="MyTask" basedir="." </font>default="test"<font color="#9F9F9F">&gt;</font>
+...
+    &lt;property name="ant.test.lib" value="ant-testutil.jar"/&gt;
+    &lt;property name="report.dir"   value="report"/&gt;
+    &lt;property name="junit.out.dir.xml"  value="${report.dir}/junit/xml"/&gt;
+    &lt;property name="junit.out.dir.html" value="${report.dir}/junit/html"/&gt;
+
+    &lt;path id="classpath.run"&gt;
+        &lt;path path="${java.class.path}"/&gt;
+        &lt;path location="${ant.project.name}.jar"/&gt;
+    &lt;/path&gt;
+
+    &lt;path id="classpath.test"&gt;
+        &lt;path refid="classpath.run"/&gt;
+        &lt;path location="${ant.test.lib}"/&gt;
+    &lt;/path&gt;
+
+    &lt;target name="clean" description="Delete all generated files"&gt;
+        &lt;delete failonerror="false" includeEmptyDirs="true"&gt;
+            &lt;fileset dir="." includes="${ant.project.name}.jar"/&gt;
+            &lt;fileset dir="${classes.dir}"/&gt;
+            &lt;fileset dir="${report.dir}"/&gt;
+        &lt;/delete&gt;
+    &lt;/target&gt;
+
+    <font color="#9F9F9F">&lt;target name="compile" description="Compiles the Task"&gt;
+        &lt;mkdir dir="${classes.dir}"/&gt;
+        &lt;javac srcdir="${src.dir}" destdir="${classes.dir}" </font>classpath="${ant.test.lib}"<font color="#9F9F9F">/&gt;
+    &lt;/target&gt;</font>
+...
+    &lt;target name="junit" description="Runs the unit tests" depends="jar"&gt;
+        &lt;delete dir="${junit.out.dir.xml}"/&gt;
+        &lt;mkdir  dir="${junit.out.dir.xml}"/&gt;
+        &lt;junit printsummary="yes" haltonfailure="no"&gt;
+            &lt;classpath refid="classpath.test"/&gt;
+            &lt;formatter type="xml"/&gt;
+            &lt;batchtest fork="yes" todir="${junit.out.dir.xml}"&gt;
+                &lt;fileset dir="${src.dir}" includes="**/*Test.java"/&gt;
+            &lt;/batchtest&gt;
+        &lt;/junit&gt;
+    &lt;/target&gt;
+
+    &lt;target name="junitreport" description="Create a report for the rest result"&gt;
+        &lt;mkdir dir="${junit.out.dir.html}"/&gt;
+        &lt;junitreport todir="${junit.out.dir.html}"&gt;
+            &lt;fileset dir="${junit.out.dir.xml}"&gt;
+                &lt;include name="*.xml"/&gt;
+            &lt;/fileset&gt;
+            &lt;report format="frames" todir="${junit.out.dir.html}"/&gt;
+        &lt;/junitreport&gt;
+    &lt;/target&gt;
+
+    &lt;target name="test"
+            depends="junit,junitreport"
+            description="Runs unit tests and creates a report"
+    /&gt;
+...
+</pre></p>
+
+<p>Back to the <i>src/HelloWorldTest.java</i>. We create a class extending
+<i>BuildFileTest</i> with String-constructor (JUnit-standard), a <i>setUp()</i>
+method initializing Ant and for each testcase (targets use.*) a <i>testXX()</i>
+method invoking that target.
+<pre class="code">
+import org.apache.tools.ant.BuildFileTest;
+
+public class HelloWorldTest extends BuildFileTest {
+
+    public HelloWorldTest(String s) {
+        super(s);
+    }
+
+    public void setUp() {
+        // initialize Ant
+        configureProject("build.xml");
+    }
+
+    public void testWithout() {
+        executeTarget("use.without");
+        assertEquals("Message was logged but should not.", getLog(), "");
+    }
+
+    public void testMessage() {
+        // execute target 'use.nestedText' and expect a message
+        // 'attribute-text' in the log
+        expectLog("use.message", "attribute-text");
+    }
+
+    public void testFail() {
+        // execute target 'use.fail' and expect a BuildException
+        // with text 'Fail requested.'
+        expectBuildException("use.fail", "Fail requested.");
+    }
+
+    public void testNestedText() {
+        expectLog("use.nestedText", "nested-text");
+    }
+
+    public void testNestedElement() {
+        executeTarget("use.nestedElement");
+        assertLogContaining("Nested Element 1");
+        assertLogContaining("Nested Element 2");
+    }
+}
+</pre></p>
+
+<p>When starting <tt>ant</tt> we'll get a short message to STDOUT and
+a nice HTML-report.
+<pre class="output">
+C:\tmp\anttests\MyFirstTask&gt;ant
+Buildfile: build.xml
+
+compile:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\classes
+    [javac] Compiling 2 source files to C:\tmp\anttests\MyFirstTask\classes
+
+jar:
+      [jar] Building jar: C:\tmp\anttests\MyFirstTask\MyTask.jar
+
+junit:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\xml
+    [junit] Running HelloWorldTest
+    [junit] Tests run: 5, Failures: 0, Errors: 0, Time elapsed: 2,334 sec
+
+
+
+junitreport:
+    [mkdir] Created dir: C:\tmp\anttests\MyFirstTask\report\junit\html
+[junitreport] Using Xalan version: Xalan Java 2.4.1
+[junitreport] Transform time: 661ms
+
+test:
+
+BUILD SUCCESSFUL
+Total time: 7 seconds
+C:\tmp\anttests\MyFirstTask&gt;
+</pre></p>
+
+
+<a name="resources"></a>
+<h2>Resources</h2>
+<p>This tutorial and its resources are available via
+<a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=22570">BugZilla [6]</a>.
+The ZIP provided there contains<ul>
+<li>this tutorial</li>
+<li>the buildfile (last version)</li>
+<li>the source of the task (last version)</li>
+<li>the source of the unit test (last version)</li>
+<li>the ant-testutil.jar (nightly build of 2003-08-18)</li>
+<li>generated classes</li>
+<li>generated jar</li>
+<li>generated reports</li>
+</ul>
+The last sources and the buildfile are also available
+<a href="tutorial-writing-tasks-src.zip">here [7]</a> inside the manual.
+</p>
+
+
+Used Links:<br>
+&nbsp;&nbsp;[1] <a href="http://ant.apache.org/manual/using.html#built-in-props">http://ant.apache.org/manual/using.html#built-in-props</a><br>
+&nbsp;&nbsp;[2] <a href="http://ant.apache.org/manual/CoreTasks/taskdef.html">http://ant.apache.org/manual/CoreTasks/taskdef.html</a><br>
+&nbsp;&nbsp;[3] <a href="http://ant.apache.org/manual/develop.html#set-magic">http://ant.apache.org/manual/develop.html#set-magic</a><br>
+&nbsp;&nbsp;[4] <a href="http://ant.apache.org/manual/develop.html#nested-elements">http://ant.apache.org/manual/develop.html#nested-elements</a><br>
+&nbsp;&nbsp;[5] <a href="http://gump.covalent.net/jars/latest/ant/ant-testutil.jar">http://gump.covalent.net/jars/latest/ant/ant-testutil.jar</a><br>
+&nbsp;&nbsp;[6] <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=22570">http://issues.apache.org/bugzilla/show_bug.cgi?id=22570</a><br>
+&nbsp;&nbsp;[7] <a href="tutorial-writing-tasks-src.zip">tutorial-writing-tasks-src.zip</a><br>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/tutorials.html b/trunk/docs/manual/tutorials.html
new file mode 100644
index 0000000..f436beb
--- /dev/null
+++ b/trunk/docs/manual/tutorials.html
@@ -0,0 +1,45 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Tutorials</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Tutorials</h3>
+
+<p><a href="tutorial-HelloWorldWithAnt.html">Hello World with Ant</a><br/>
+A step by step tutorial for starting java programming with Ant.</p>
+
+<p><a href="tutorial-writing-tasks.html">Writing Tasks</a><br/>
+A step by step tutorial for writing tasks.</p>
+
+<p><a href="tutorial-tasks-filesets-properties.html">Tasks using Properties, Filesets &amp; Paths</a><br/>
+How to get and set properties and how to use nested filesets and paths 
+while writing tasks. Finally it explains how to contribute tasks to Ant.</p>
+
+
+
+</body>
+</html>
diff --git a/trunk/docs/manual/using.html b/trunk/docs/manual/using.html
new file mode 100644
index 0000000..d10f56b
--- /dev/null
+++ b/trunk/docs/manual/using.html
@@ -0,0 +1,722 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css">
+<title>Writing a Simple Buildfile</title>
+</head>
+
+<body>
+<h1>Using Ant</h1>
+<h2><a name="buildfile">Writing a Simple Buildfile</a></h2>
+<p>Ant's buildfiles are written in XML. Each buildfile contains one project
+and at least one (default) target. Targets contain task elements.
+Each task element of the buildfile can have an <code>id</code> attribute and
+can later be referred to by the value supplied to this. The value has
+to be unique. (For additional information, see the
+<a href="#tasks"> Tasks</a> section below.)</p>
+<h3><a name="projects">Projects</a></h3>
+<p>A <i>project</i> has three attributes:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the project.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">default</td>
+    <td valign="top">the default target to use when no target is supplied.</td>
+    <td align="center" valign="top">No; however, <b>since Ant 1.6.0</b>,
+        every project includes an implicit target that contains any and
+        all top-level tasks and/or types. This target will always be
+        executed as part of the project's initialization, even when Ant is
+        run with the <a href="running.html#options">-projecthelp</a> option.
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">basedir</td>
+    <td valign="top">the base directory from which all path calculations are
+      done. This attribute might be overridden by setting
+      the &quot;basedir&quot;
+      property beforehand. When this is done, it must be omitted in the
+      project tag. If neither the attribute nor the property have
+      been set, the parent directory of the buildfile will be used.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<p>Optionally, a description for the project can be provided as a
+top-level <code>&lt;description&gt;</code> element (see the <a
+href="CoreTypes/description.html">description</a> type).</p>
+
+<p>Each project defines one or more <i>targets</i>.
+A target is a set of <i>tasks</i> you want
+to be executed. When starting Ant, you can select which target(s) you
+want to have executed. When no target is given,
+the project's default is used.</p>
+
+<h3><a name="targets">Targets</a></h3>
+<p>A target can depend on other targets. You might have a target for compiling,
+for example, and a target for creating a distributable. You can only build a
+distributable when you have compiled first, so the distribute target
+<i>depends on</i> the compile target. Ant resolves these dependencies.</p>
+<p>It should be noted, however, that Ant's <code>depends</code> attribute
+only specifies the <i>order</i> in which targets should be executed - it
+does not affect whether the target that specifies the dependency(s) gets
+executed if the dependent target(s) did not (need to) run.
+</p>
+<p>Ant tries to execute the targets in the <code>depends</code>
+attribute in the order
+they appear (from left to right). Keep in mind that it is possible that a target
+can get executed earlier when an earlier target depends on it:</p>
+<blockquote>
+<pre>&lt;target name=&quot;A&quot;/&gt;
+&lt;target name=&quot;B&quot; depends=&quot;A&quot;/&gt;
+&lt;target name=&quot;C&quot; depends=&quot;B&quot;/&gt;
+&lt;target name=&quot;D&quot; depends=&quot;C,B,A&quot;/&gt;</pre>
+</blockquote>
+<p>Suppose we want to execute target D. From its
+<code>depends</code> attribute, you
+might think that first target C, then B and then A is executed.
+Wrong! C depends on B, and B depends on A, so first A is executed, then B, then C, and finally D.</p>
+<p>In a chain of dependencies stretching back from a given target such
+as D above, each target gets executed only once, even when more than
+one target depends on it. Thus, executing the D target will first
+result in C being called, which in turn will first call B, which in
+turn will first call A. After A, then B, then C have executed,
+execution returns to the dependency list of D, which will <u>not</u>
+call B and A, since they were already called in process of dependency
+resolution for C and B respectively as dependencies of D. Had no such
+dependencies been discovered in processing C and B, B and A would
+have been executed after C in processing D's dependency list.</p>
+<p>A target also has the ability to perform its execution if (or
+unless) a property has been set. This allows, for example, better
+control on the building process depending on the state of the system
+(java version, OS, command-line property defines, etc.).  To make a target
+<i>sense</i> this property, you should add the <code>if</code> (or
+<code>unless</code>) attribute with the name of the property that the target
+should react to. <strong>Note:</strong> Ant will only check whether
+the property has been set, the value doesn't matter.  A property set
+to the empty string is still an existing property.  For example:</p>
+<blockquote>
+  <pre>&lt;target name=&quot;build-module-A&quot; if=&quot;module-A-present&quot;/&gt;</pre>
+  <pre>&lt;target name=&quot;build-own-fake-module-A&quot; unless=&quot;module-A-present&quot;/&gt;</pre>
+</blockquote>
+<p>In the first example, if the <code>module-A-present</code>
+property is set (to any value, e.g. <i>false</i>), the target will be run. In the second
+example, if the <code>module-A-present</code> property is set
+(again, to any value), the target will not be run.
+</p>
+<p>Only one propertyname can be specified in the if/unless clause. If you want to check
+multiple conditions, you can use a dependend target for computing the result for the check:</p>
+<blockquote><pre>
+&lt;target name="myTarget" depends="myTarget.check" if="myTarget.run"&gt;
+    &lt;echo&gt;Files foo.txt and bar.txt are present.&lt;/echo&gt;
+&lt/target&gt;
+
+&lt;target name="myTarget.check"&gt;
+    &lt;condition property="myTarget.run"&gt;
+        &lt;and&gt;
+            &lt;available file="foo.txt"/&gt;
+            &lt;available file="bar.txt"/&gt;
+        &lt;/and&gt;
+    &lt;/condition&gt;
+&lt/target&gt;
+</pre></blockquote>
+<p>If no <code>if</code> and no <code>unless</code> attribute is present,
+the target will always be executed.</p>
+
+<p>
+<b>Important:</b> the <code>if</code> and <code>unless</code> attributes only
+enable or disable the target to which they are attached. They do not control
+whether or not targets that a conditional target depends upon get executed.
+In fact, they do not even get evaluated until the target is about to be executed,
+and all its predecessors have already run.
+
+<p>The optional <code>description</code> attribute can be used to provide a one-line description of this target, which is printed by the
+<nobr><code>-projecthelp</code></nobr> command-line option. Targets
+without such a description are deemed internal and will not be listed,
+unless either the <nobr><code>-verbose</code></nobr> or
+<nobr><code>-debug</code></nobr> option is used.
+</p>
+<p>It is a good practice to place your <a
+href="CoreTasks/tstamp.html">tstamp</a> tasks in a so-called
+<i>initialization</i> target, on which
+all other targets depend. Make sure that target is always the first one in
+the depends list of the other targets. In this manual, most initialization targets
+have the name <code>&quot;init&quot;</code>.</p>
+<p>If the depends attribute and the if/unless attribute are set, the depends attribute is
+executed first.</p>
+<p>A target has the following attributes:</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the target.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">depends</td>
+    <td valign="top">a comma-separated list of names of targets on which this
+      target depends.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">if</td>
+    <td valign="top">the name of the property that must be set in order for this
+      target to execute.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">unless</td>
+    <td valign="top">the name of the property that must not be set in order
+      for this target to execute.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">description</td>
+    <td valign="top">a short description of this target's function.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+</p>
+
+<p>A target name can be any alphanumeric string valid in the encoding of the XML
+file. The empty string &quot;&quot; is in this set, as is
+comma &quot;,&quot; and space &quot; &quot;.
+Please avoid using these, as they will not be supported in future Ant versions
+because of all the confusion they cause. IDE support of unusual target names,
+or any target name containing spaces, varies with the IDE.</p>
+
+<p>Targets beginning with a hyphen such as <code>&quot;-restart&quot;</code>
+are valid, and can be used
+to name targets that should not be called directly from the command line.</p>
+
+<h3><a name="tasks">Tasks</a></h3>
+<p>A task is a piece of code that can be executed.</p>
+<p>A task can have multiple attributes (or arguments, if you prefer). The value
+of an attribute might contain references to a property. These references will be
+resolved before the task is executed.</p>
+<p>Tasks have a common structure:</p>
+<blockquote>
+  <pre>&lt;<i>name</i> <i>attribute1</i>=&quot;<i>value1</i>&quot; <i>attribute2</i>=&quot;<i>value2</i>&quot; ... /&gt;</pre>
+</blockquote>
+<p>where <i>name</i> is the name of the task,
+<i>attributeN</i> is the attribute name, and
+<i>valueN</i> is the value for this attribute.</p>
+<p>There is a set of <a href="coretasklist.html" target="navFrame">built-in tasks</a>, along with a
+number of
+<a href="optionaltasklist.html" target="navFrame"> optional tasks</a>, but it is also very
+easy to <a href="develop.html#writingowntask">write your own</a>.</p>
+<p>All tasks share a task name attribute. The value of
+this attribute will be used in the logging messages generated by
+Ant.</p>
+Tasks can be assigned an <code>id</code> attribute:
+<blockquote>
+<pre>&lt;<i>taskname</i> id="<i>taskID</i>" ... /&gt;</pre>
+</blockquote>
+where <i>taskname</i> is the name of the task, and <i>taskID</i> is
+a unique identifier for this task.
+You can refer to the
+corresponding task object in scripts or other tasks via this name.
+For example, in scripts you could do:
+<blockquote>
+<pre>
+&lt;script ... &gt;
+  task1.setFoo("bar");
+&lt;/script&gt;
+</pre>
+</blockquote>
+to set the <code>foo</code> attribute of this particular task instance.
+In another task (written in Java), you can access the instance via
+<code>project.getReference("task1")</code>.
+<p>
+Note<sup>1</sup>: If &quot;task1&quot; has not been run yet, then
+it has not been configured (ie., no attributes have been set), and if it is
+going to be configured later, anything you've done to the instance may
+be overwritten.
+</p>
+<p>
+Note<sup>2</sup>: Future versions of Ant will most likely <i>not</i>
+be backward-compatible with this behaviour, since there will likely be no
+task instances at all, only proxies.
+</p>
+
+<h3><a name="properties">Properties</a></h3>
+<p>A project can have a set of properties. These might be set in the buildfile
+by the <a href="CoreTasks/property.html">property</a> task, or might be set outside Ant. A
+property has a name and a value; the name is case-sensitive. Properties may be used in the value of
+task attributes. This is done by placing the property name between
+&quot;<code>${</code>&quot; and &quot;<code>}</code>&quot; in the
+attribute value. For example,
+if there is a &quot;builddir&quot; property with the value
+&quot;build&quot;, then this could be used in an attribute like this:
+<code>${builddir}/classes</code>.
+This is resolved at run-time as <code>build/classes</code>.</p>
+<p>In the event you should need to include this construct literally
+(i.e. without property substitutions), simply "escape" the '$' character
+by doubling it. To continue the previous example:
+<pre>  &lt;echo&gt;$${builddir}=${builddir}&lt;/echo&gt;</pre>
+will echo this message:
+<pre>  ${builddir}=build/classes</pre></p>
+<p>In order to maintain backward compatibility with older Ant releases,
+a single '$' character encountered apart from a property-like construct
+(including a matched pair of french braces) will be interpreted literally;
+that is, as '$'.  The "correct" way to specify this literal character,
+however, is by using the escaping mechanism unconditionally, so that "$$"
+is obtained by specifying "$$$$".  Mixing the two approaches yields
+unpredictable results, as "$$$" results in "$$".</p>
+
+<h3><a name="built-in-props">Built-in Properties</a></h3>
+<p>Ant provides access to all system properties as if they had been
+defined using a <code>&lt;property&gt;</code> task.
+For example, <code>${os.name}</code> expands to the
+name of the operating system.</p>
+<p>For a list of system properties see
+<a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/System.html#getProperties()">the Javadoc of System.getProperties</a>.
+</p>
+<p>In addition, Ant has some built-in properties:</p>
+<pre>
+basedir             the absolute path of the project's basedir (as set
+                    with the basedir attribute of <a href="#projects">&lt;project&gt;)</a>.
+ant.file            the absolute path of the buildfile.
+ant.version         the version of Ant
+ant.project.name    the name of the project that is currently executing;
+                    it is set in the name attribute of &lt;project&gt;.
+ant.java.version    the JVM version Ant detected; currently it can hold
+                    the values &quot;1.2&quot;, &quot;1.3&quot;, &quot;1.4&quot; and &quot;1.5&quot;.
+</pre>
+<p>There is also another property, but this is set by the launcher script and therefore
+maybe not set inside IDEs:</p>
+<pre>
+ant.home            home directory of Ant
+</pre>
+
+<a name="example"><h3>Example Buildfile</h3></a>
+<pre>
+&lt;project name=&quot;MyProject&quot; default=&quot;dist&quot; basedir=&quot;.&quot;&gt;
+    &lt;description&gt;
+        simple example build file
+    &lt;/description&gt;
+  &lt;!-- set global properties for this build --&gt;
+  &lt;property name=&quot;src&quot; location=&quot;src&quot;/&gt;
+  &lt;property name=&quot;build&quot; location=&quot;build&quot;/&gt;
+  &lt;property name=&quot;dist&quot;  location=&quot;dist&quot;/&gt;
+
+  &lt;target name=&quot;init&quot;&gt;
+    &lt;!-- Create the time stamp --&gt;
+    &lt;tstamp/&gt;
+    &lt;!-- Create the build directory structure used by compile --&gt;
+    &lt;mkdir dir=&quot;${build}&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;target name=&quot;compile&quot; depends=&quot;init&quot;
+        description=&quot;compile the source &quot; &gt;
+    &lt;!-- Compile the java code from ${src} into ${build} --&gt;
+    &lt;javac srcdir=&quot;${src}&quot; destdir=&quot;${build}&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;target name=&quot;dist&quot; depends=&quot;compile&quot;
+        description=&quot;generate the distribution&quot; &gt;
+    &lt;!-- Create the distribution directory --&gt;
+    &lt;mkdir dir=&quot;${dist}/lib&quot;/&gt;
+
+    &lt;!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --&gt;
+    &lt;jar jarfile=&quot;${dist}/lib/MyProject-${DSTAMP}.jar&quot; basedir=&quot;${build}&quot;/&gt;
+  &lt;/target&gt;
+
+  &lt;target name=&quot;clean&quot;
+        description=&quot;clean up&quot; &gt;
+    &lt;!-- Delete the ${build} and ${dist} directory trees --&gt;
+    &lt;delete dir=&quot;${build}&quot;/&gt;
+    &lt;delete dir=&quot;${dist}&quot;/&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre>
+
+<p>Notice that we are declaring properties outside any target.  As of
+Ant 1.6 all tasks can be declared outside targets (earlier version
+only allowed <tt>&lt;property&gt;</tt>,<tt>&lt;typedef&gt;</tt> and
+<tt>&lt;taskdef&gt;</tt>).  When you do this they are evaluated before
+any targets are executed.  Some tasks will generate build failures if
+they are used outside of targets as they may cause infinite loops
+otherwise (<code>&lt;antcall&gt;</code> for example).</p>
+
+<p>
+We have given some targets descriptions; this causes the <tt>projecthelp</tt>
+invocation option to list them as public targets with the descriptions; the
+other target is internal and not listed.
+<p>
+Finally, for this target to work the source in the <tt>src</tt> subdirectory
+should be stored in a directory tree which matches the package names. Check the
+<tt>&lt;javac&gt;</tt> task for details.
+
+<a name="filters"><h3>Token Filters</h3></a>
+<p>A project can have a set of tokens that might be automatically expanded if
+found when a file is copied, when the filtering-copy behavior is selected in the
+tasks that support this. These might be set in the buildfile
+by the <a href="CoreTasks/filter.html">filter</a> task.</p>
+<p>Since this can potentially be a very harmful behavior,
+the tokens in the files <b>must</b>
+be of the form <code>@</code><i>token</i><code>@</code>, where
+<i>token</i> is the token name that is set
+in the <code>&lt;filter&gt;</code> task. This token syntax matches the syntax of other build systems
+that perform such filtering and remains sufficiently orthogonal to most
+programming and scripting languages, as well as with documentation systems.</p>
+<p>Note: If a token with the format <code>@</code><i>token</i><code>@</code>
+is found in a file, but no
+filter is associated with that token, no changes take place;
+therefore, no escaping
+method is available - but as long as you choose appropriate names for your
+tokens, this should not cause problems.</p>
+<p><b>Warning:</b> If you copy binary files with filtering turned on, you can corrupt the
+files. This feature should be used with text files <em>only</em>.</p>
+
+<h3><a name="path">Path-like Structures</a></h3>
+<p>You can specify <code>PATH</code>- and <code>CLASSPATH</code>-type
+references using both
+&quot;<code>:</code>&quot; and &quot;<code>;</code>&quot; as separator
+characters. Ant will
+convert the separator to the correct character of the current operating
+system.</p>
+<p>Wherever path-like values need to be specified, a nested element can
+be used. This takes the general form of:</p>
+<pre>
+    &lt;classpath&gt;
+      &lt;pathelement path=&quot;${classpath}&quot;/&gt;
+      &lt;pathelement location=&quot;lib/helper.jar&quot;/&gt;
+    &lt;/classpath&gt;
+</pre>
+<p>The <code>location</code> attribute specifies a single file or
+directory relative to the project's base directory (or an absolute
+filename), while the <code>path</code> attribute accepts colon-
+or semicolon-separated lists of locations. The <code>path</code>
+attribute is intended to be used with predefined paths - in any other
+case, multiple elements with <code>location</code> attributes should be
+preferred.</p>
+<p>As a shortcut, the <code>&lt;classpath&gt;</code> tag
+supports <code>path</code> and
+<code>location</code> attributes of its own, so:</p>
+<pre>
+    &lt;classpath&gt;
+      &lt;pathelement path=&quot;${classpath}&quot;/&gt;
+    &lt;/classpath&gt;
+</pre>
+<p>can be abbreviated to:</p>
+<pre>
+    &lt;classpath path=&quot;${classpath}&quot;/&gt;
+</pre>
+<p>In addition, one or more
+<a href="CoreTypes/resources.html#collection">Resource Collection</a>s
+can be specified as nested elements (these must consist of
+<a href="CoreTypes/resources.html#file">file</a>-type resources only).
+Additionally, it should be noted that although resource collections are
+processed in the order encountered, certain resource collection types
+such as <a href="CoreTypes/fileset.html">fileset</a>,
+<a href="CoreTypes/dirset.html">dirset</a> and
+<a href="CoreTypes/resources.html#files">files</a>
+are undefined in terms of order.</p>
+<pre>
+    &lt;classpath&gt;
+      &lt;pathelement path=&quot;${classpath}&quot;/&gt;
+      &lt;fileset dir=&quot;lib&quot;&gt;
+        &lt;include name=&quot;**/*.jar&quot;/&gt;
+      &lt;/fileset&gt;
+      &lt;pathelement location=&quot;classes&quot;/&gt;
+      &lt;dirset dir=&quot;${build.dir}&quot;&gt;
+        &lt;include name=&quot;apps/**/classes&quot;/&gt;
+        &lt;exclude name=&quot;apps/**/*Test*&quot;/&gt;
+      &lt;/dirset&gt;
+      &lt;filelist refid=&quot;third-party_jars&quot;/&gt;
+    &lt;/classpath&gt;
+</pre>
+<p>This builds a path that holds the value of <code>${classpath}</code>,
+followed by all jar files in the <code>lib</code> directory,
+the <code>classes</code> directory, all directories named
+<code>classes</code> under the <code>apps</code> subdirectory of
+<code>${build.dir}</code>, except those
+that have the text <code>Test</code> in their name, and
+the files specified in the referenced FileList.</p>
+<p>If you want to use the same path-like structure for several tasks,
+you can define them with a <code>&lt;path&gt;</code> element at the
+same level as <i>target</i>s, and reference them via their
+<i>id</i> attribute--see <a href="#references">References</a> for an
+example.</p>
+<p>A path-like structure can include a reference to another path-like
+structure (a path being itself a resource collection)
+via nested <code>&lt;path&gt;</code> elements:</p>
+<pre>
+    &lt;path id=&quot;base.path&quot;&gt;
+      &lt;pathelement path=&quot;${classpath}&quot;/&gt;
+      &lt;fileset dir=&quot;lib&quot;&gt;
+        &lt;include name=&quot;**/*.jar&quot;/&gt;
+      &lt;/fileset&gt;
+      &lt;pathelement location=&quot;classes&quot;/&gt;
+    &lt;/path&gt;
+
+    &lt;path id=&quot;tests.path&quot;&gt;
+      &lt;path refid=&quot;base.path&quot;/&gt;
+      &lt;pathelement location=&quot;testclasses&quot;/&gt;
+    &lt;/path&gt;
+</pre>
+ The shortcuts previously mentioned for <code>&lt;classpath&gt;</code> are also valid for <code>&lt;path&gt;</code>.For example:
+<pre>
+    &lt;path id=&quot;base.path&quot;&gt;
+      &lt;pathelement path=&quot;${classpath}&quot;/&gt;
+    &lt;/path&gt;
+</pre>
+can be written as:
+<pre>
+    &lt;path id=&quot;base.path&quot; path=&quot;${classpath}&quot;/&gt;
+</pre>
+
+  <h4><a name="pathshortcut">Path Shortcut</a></h4>
+  <p>
+    In Ant 1.6 a shortcut for converting paths to OS specific strings
+    in properties has been added. One can use the expression 
+    ${toString:<em>pathreference</em>} to convert a path element
+    reference to a string that can be used for a path argument.
+    For example:
+  </p>
+<pre>
+  &lt;path id="lib.path.ref"&gt;
+    &lt;fileset dir="lib" includes="*.jar"/&gt;
+  &lt;/path&gt;
+  &lt;javac srcdir="src" destdir="classes"&gt;
+    &lt;compilerarg arg="-Xbootstrap/p:${toString:lib.path.ref}"/&gt;
+  &lt;/javac&gt;
+</pre>
+
+
+<h3><a name="arg">Command-line Arguments</a></h3>
+<p>Several tasks take arguments that will be passed to another
+process on the command line. To make it easier to specify arguments
+that contain space characters, nested <code>arg</code> elements can be used.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+<tr>
+  <td width="12%" valign="top"><b>Attribute</b></td>
+  <td width="78%" valign="top"><b>Description</b></td>
+  <td width="10%" valign="top"><b>Required</b></td>
+</tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">a single command-line argument; can contain space
+      characters.</td>
+    <td align="center" rowspan="5">Exactly one of these.</td>
+  </tr>
+  <tr>
+    <td valign="top">file</td>
+    <td valign="top">The name of a file as a single command-line
+      argument; will be replaced with the absolute filename of the file.</td>
+  </tr>
+  <tr>
+    <td valign="top">path</td>
+    <td valign="top">A string that will be treated as a path-like
+      string as a single command-line argument; you can use <code>;</code>
+      or <code>:</code> as
+      path separators and Ant will convert it to the platform's local
+      conventions.</td>
+  </tr>
+  <tr>
+    <td valign="top">pathref</td>
+    <td valign="top"><a href="#references">Reference</a> to a path
+      defined elsewhere.  Ant will convert it to the platform's local
+      conventions.</td>
+  </tr>
+  <tr>
+    <td valign="top">line</td>
+    <td valign="top">a space-delimited list of command-line arguments.</td>
+  </tr>
+</table>
+
+<p>It is highly recommended to avoid the <code>line</code> version
+when possible.  Ant will try to split the command line in a way
+similar to what a (Unix) shell would do, but may create something that
+is very different from what you expect under some circumstances.</p>
+
+<h4>Examples</h4>
+<blockquote><pre>
+  &lt;arg value=&quot;-l -a&quot;/&gt;
+</pre></blockquote>
+<p>is a single command-line argument containing a space character,
+<i>not</i> separate commands "-l" and "-a".</p>
+<blockquote><pre>
+  &lt;arg line=&quot;-l -a&quot;/&gt;
+</pre></blockquote>
+<p>This is a command line with two separate arguments, "-l" and "-a".</p>
+<blockquote><pre>
+  &lt;arg path=&quot;/dir;/dir2:\dir3&quot;/&gt;
+</pre></blockquote>
+<p>is a single command-line argument with the value
+<code>\dir;\dir2;\dir3</code> on DOS-based systems and
+<code>/dir:/dir2:/dir3</code> on Unix-like systems.</p>
+
+<h3><a name="references">References</a></h3>
+
+<p>Any project element can be assigned an identifier using its
+<code>id</code> attribute. In most cases the element can subsequently
+be referenced by specifying the <code>refid</code> attribute on an
+element of the same type.  This can be useful if you are going to
+replicate the same snippet of XML over and over again--using a
+<code>&lt;classpath&gt;</code> structure more than once, for example.</p>
+<p>The following example:</p>
+<blockquote><pre>
+&lt;project ... &gt;
+  &lt;target ... &gt;
+    &lt;rmic ...&gt;
+      &lt;classpath&gt;
+        &lt;pathelement location=&quot;lib/&quot;/&gt;
+        &lt;pathelement path=&quot;${java.class.path}/&quot;/&gt;
+        &lt;pathelement path=&quot;${additional.path}&quot;/&gt;
+      &lt;/classpath&gt;
+    &lt;/rmic&gt;
+  &lt;/target&gt;
+
+  &lt;target ... &gt;
+    &lt;javac ...&gt;
+      &lt;classpath&gt;
+        &lt;pathelement location=&quot;lib/&quot;/&gt;
+        &lt;pathelement path=&quot;${java.class.path}/&quot;/&gt;
+        &lt;pathelement path=&quot;${additional.path}&quot;/&gt;
+      &lt;/classpath&gt;
+    &lt;/javac&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre></blockquote>
+<p>could be rewritten as:</p>
+<blockquote><pre>
+&lt;project ... &gt;
+  &lt;path id=&quot;project.class.path&quot;&gt;
+    &lt;pathelement location=&quot;lib/&quot;/&gt;
+    &lt;pathelement path=&quot;${java.class.path}/&quot;/&gt;
+    &lt;pathelement path=&quot;${additional.path}&quot;/&gt;
+  &lt;/path&gt;
+
+  &lt;target ... &gt;
+    &lt;rmic ...&gt;
+      &lt;classpath refid=&quot;project.class.path&quot;/&gt;
+    &lt;/rmic&gt;
+  &lt;/target&gt;
+
+  &lt;target ... &gt;
+    &lt;javac ...&gt;
+      &lt;classpath refid=&quot;project.class.path&quot;/&gt;
+    &lt;/javac&gt;
+  &lt;/target&gt;
+&lt;/project&gt;
+</pre></blockquote>
+<p>All tasks that use nested elements for 
+<a href="CoreTypes/patternset.html">PatternSet</a>s, 
+<a href="CoreTypes/fileset.html">FileSet</a>s, 
+<a href="CoreTypes/zipfileset.html">ZipFileSet</a>s or 
+<a href="#path">path-like structures</a> accept references to these structures 
+as shown in the examples. Using <code>refid</code> on a task will ordinarily 
+have the same effect (referencing a task already declared), but the user 
+should be aware that the interpretation of this attribute is dependent on the 
+implementation of the element upon which it is specified. Some tasks (the 
+<a href="CoreTasks/property.html">property</a> task is a handy example) 
+deliberately assign a different meaning to <code>refid</code>.</p>
+
+
+<h3><a name="toString">Getting the value of a Reference with ${toString:}</a></h3>
+<p>
+Any Ant type which has been declared with a reference can also its string
+value extracted by using the <code>${toString:}</code> operation,
+with the name of the reference listed after the  <code>toString:</code> text. 
+The  <code>toString()</code> method of the Java class instance that is
+referenced is invoked -all built in types strive to produce useful and relevant
+output in such an instance.
+</p>
+<p>
+For example, here is how to get a listing of the files in a fileset, 
+<p>
+<pre>
+&lt;fileset id=&quot;sourcefiles&quot; dir=&quot;src&quot; includes=&quot;**/*.java&quot; /&gt;
+&lt;echo&gt; sourcefiles = ${toString:sourcefiles} &lt;/echo&gt;
+</pre>
+<p>
+There is no guarantee that external types provide meaningful information in such
+a situation</p>
+
+
+<h3><a name="external-tasks">Use of external tasks</a></h3> 
+Ant supports a plugin mechanism for using third party tasks. For using them you 
+have to do two steps: 
+<ol>
+  <li>place their implementation somewhere where Ant can find them</li>
+  <li>declare them.</li>
+</ol> 
+Don't add anything to the CLASSPATH environment variable - this is often the  
+reason for very obscure errors. Use Ant's own <a href="install.html#optionalTasks">mechanisms</a> 
+for adding libraries: 
+<ul>
+  <li>via command line argument <code>-lib</code></li>
+  <li>adding to <code>${user.home}/.ant/lib</code></li>
+  <li>adding to <code>${ant.home}/lib</code></li>
+</ul>
+For the declaration there are several ways:
+<ul>
+  <li>declare a single task per using instruction using  
+      <code>&lt;<a href="CoreTasks/taskdef.html">taskdef</a> name=&quot;taskname&quot; 
+      classname=&quot;ImplementationClass&quot;/&gt;</code>
+      <br>
+      <code>&lt;taskdef name=&quot;for&quot; classname=&quot;net.sf.antcontrib.logic.For&quot; /&gt; 
+      &lt;for ... /&gt;</code>
+  </li>
+  <li>declare a bundle of tasks using a properties-file holding these 
+      taskname-ImplementationClass-pairs and <code>&lt;taskdef&gt;</code>
+      <br>
+      <code>&lt;taskdef resource=&quot;net/sf/antcontrib/antcontrib.properties&quot; /&gt; 
+      &lt;for ... /&gt;</code>
+  </li>
+  <li>declare a bundle of tasks using a <a href="CoreTypes/antlib.html">xml-file</a> holding these  
+      taskname-ImplementationClass-pairs and <code>&lt;taskdef&gt;</code>
+      <br>
+      <code>&lt;taskdef resource=&quot;net/sf/antcontrib/antlib.xml&quot; /&gt; 
+      &lt;for ... /&gt;</code>
+  </li>
+  <li>declare a bundle of tasks using a xml-file named antlib.xml, XML-namespace and 
+      <a href="CoreTypes/antlib.html#antlibnamespace"><code>antlib:</code> protocoll handler</a> 
+      <br>
+      <code>&lt;project xmlns:ac=&quot;antlib:net.sf.antconrib&quot;/&gt; 
+      &lt;ac:for ... /&gt;</code>
+  </li>
+</ul>
+
+If you need a special function, you should
+<ol>
+  <li>have a look at this manual, because Ant provides lot of tasks</li>
+  <li>have a look at the external task page in the <a href="../external.html">manual</a>
+      (or better <a href="http://ant.apache.org/external.html">online</a>)</li>
+  <li>have a look at the external task <a href="http://wiki.apache.org/ant/AntExternalTaskdefs">wiki 
+      page</a></li>
+  <li>ask on the <a href="http://ant.apache.org/mail.html#User%20List">Ant user</a> list</li>
+  <li><a href="tutorial-writing-tasks.html">implement </a>(and share) your own</li>
+</ol>
+
+</body>
+</html>
diff --git a/trunk/docs/manual/usinglist.html b/trunk/docs/manual/usinglist.html
new file mode 100644
index 0000000..8d6982c
--- /dev/null
+++ b/trunk/docs/manual/usinglist.html
@@ -0,0 +1,47 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us"/>
+<link rel="stylesheet" type="text/css" href="stylesheets/style.css"/>
+<title>Apache Ant User Manual</title>
+<base target="mainFrame"/>
+</head>
+
+<body>
+
+<h2><a href="toc.html" target="navFrame">Table of Contents</a></h2>
+
+<h3>Using Ant</h3>
+<a href="using.html#buildfile">Writing a Simple Buildfile</a><br/>
+<div style="padding-left:1em">
+  <a href="using.html#projects">Projects</a><br/>
+  <a href="using.html#targets">Targets</a><br/>
+  <a href="using.html#tasks">Tasks</a><br/>
+  <a href="using.html#properties">Properties</a><br/>
+  <a href="using.html#built-in-props">Built-in Properties</a><br/>
+  <a href="using.html#example">Example Buildfile</a><br/>
+  <a href="using.html#filters">Token Filters</a><br/>
+  <a href="using.html#path">Path-like Structures</a><br/>
+  <a href="using.html#arg">Command-line Arguments</a><br/>
+  <a href="using.html#references">References</a><br/>
+  <a href="using.html#external-tasks">Use of external tasks</a><br/>
+</div>
+</body>
+</html>
+
diff --git a/trunk/docs/mission.html b/trunk/docs/mission.html
new file mode 100644
index 0000000..b03229e
--- /dev/null
+++ b/trunk/docs/mission.html
@@ -0,0 +1,292 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Apache Ant Mission</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Apache Ant PMC">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                              <span class="sel">Apache Ant Mission</span>
+                              </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Apache Ant Mission</h1>
+            <h3 class="section">
+      <a name="Board Resolution"></a>
+      Board Resolution
+    </h3>
+                        <p>Apache Ant is a project of the <a href="http://www.apache.org/">Apache Software Foundation</a>.  It
+    started as a subproject of the <a href="http://jakarta.apache.org/">Apache Jakarta Project</a>.</p>
+                                <p>This is the board resolution (from the <a href="http://www.apache.org/foundation/records/minutes/2002/board_minutes_2002_11_18.txt">minutes</a>)
+    that created the Apache Ant project:</p>
+                                <pre class="code">
+7.D. Resolution [R3] to create the Ant PMC
+
+WHEREAS, the Board of Directors deems it to be in the best
+interests of the Foundation and consistent with the
+Foundation's purpose to establish a Project Management
+Committee charged with the creation and maintenance of
+open-source software related to the Apache Ant build tool, for
+distribution at no charge to the public.
+
+NOW, THEREFORE, BE IT RESOLVED, that a Project Management
+Committee (PMC), to be known as the &quot;Apache Ant PMC&quot;, be and
+hereby is established pursuant to Bylaws of the Foundation; and
+be it further
+
+RESOLVED, that the Apache Ant PMC be and hereby is responsible
+for the creation and maintenance of the Ant build system and
+related software components, based on software licensed to the
+Foundation; and be it further
+
+RESOLVED, that the office of &quot;Vice President, Apache Ant&quot; be
+and hereby is created, the person holding such office to serve
+at the direction of the Board of Directors as the chair of the
+Apache Ant PMC, and to have primary responsibility for
+management of the projects within the scope of responsibility
+of the Apache Ant PMC; and be it further
+
+RESOLVED, that the persons listed immediately below be and
+hereby are appointed to serve as the initial members of the
+Apache Ant PMC:
+
+   Bruce Atherton
+   Stephane Bailliez
+   Stefan Bodewig
+   Erik Hatcher
+   Diane Holt
+   Donald Leslie
+   Steve Loughran
+   Conor MacNeill
+   Costin Manolache
+   Sam Ruby
+   Jon Skeet
+   Magesh Umasankar
+   Christoph Wilhelms
+
+NOW, THEREFORE, BE IT FURTHER RESOLVED, that Conor MacNeill be
+and hereby is appointed to the office of Vice President, Apache
+Ant, to serve in accordance with and subject to the direction
+of the Board of Directors and the Bylaws of the Foundation
+until death, resignation, retirement, removal or
+disqualification, or until a successor is appointed; and be it
+further
+
+RESOLVED, that the initial Apache Ant PMC be and hereby is
+tasked with the creation of a set of bylaws intended to
+encourage open development and increased participation in the
+Apache Ant Project.
+
+By Unanimous Vote, Resolution R3 was approved. The Ant PMC is
+hereby created.
+    </pre>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/nightlies.html b/trunk/docs/nightlies.html
new file mode 100644
index 0000000..b8109bd
--- /dev/null
+++ b/trunk/docs/nightlies.html
@@ -0,0 +1,229 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Nightly Builds</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                              <span class="sel">Nightly Builds</span>
+                              </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Nightly Builds</h1>
+            <h3 class="section">
+      <a name="Nightly Builds"></a>
+      Nightly Builds
+    </h3>
+                        <p>If you wish to use the latest Ant features, you can try downloading a
+<a href="http://people.apache.org/builds/ant/nightly/">nightly build</a>.
+</p>
+                                <p>If you want to build Ant from sources, you can use a <a href="http://svn.apache.org/snapshots/ant/">Subversion snapshot</a>.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/page.css b/trunk/docs/page.css
new file mode 100644
index 0000000..a256c93
--- /dev/null
+++ b/trunk/docs/page.css
@@ -0,0 +1,212 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+body {
+    background-color: #FFFFFF;
+    color: #000000;
+    margin: 0px 0px 0px 0px;
+    font-family: Verdana, Helvetica, sans-serif;
+    font-size : 90%;
+}
+
+a:link { color: #0F3660; }
+a:visited { color: #009999; }
+a:active { color: #000066; }
+a:hover { color: #000066; }
+
+.menucontainer {
+    float: left;
+    background-color: #4C6C8F;
+    margin: 0px 5px;
+    width: 250px;
+}
+
+.menu {
+    font-size : 90%;
+    padding: 3px 8px 5px 3px;
+    border-right: 1px solid #294563;
+    border-left: 1px solid #294563;
+}
+
+.menu a:link { color: #FFFFFF;  text-decoration : none;  }
+.menu a:visited { color: #FFFFFF; text-decoration : none; }
+.menu a:hover { color: #FFCC00; text-decoration : none; }
+.menu ul { margin: 0px 0px 0px 20px; padding: 0px; }
+.menu li  { list-style-image: url('images/label.gif'); font-weight : bold; }
+.menu ul ul li .sel { list-style-image: url('images/current.gif'); font-weight : normal; }
+.menu ul ul li  { list-style-image: url('images/page.gif'); font-weight : normal; }
+
+.menuheader {
+    color: #CFDCED;
+}
+
+.sel {
+    color: #ffcc00;
+}
+
+.tab { font-size : 85%; border: 0; background-color: #294563;}
+.tab a:link {   text-decoration : none;  }
+.tab a:visited { text-decoration : none; color: #2A4A6D }
+.tab a:hover { color: #000066; }
+
+table .title { background-color: #FFFFFF; width:100%; border: 0px; }
+.dida { font-size: 80%; }
+
+.pre { white-space: pre;}
+.nowrap { white-space: nowrap;}
+
+.main {
+    margin-left: 280px;
+    margin-right: 5px;
+}
+
+.content {
+    padding: 5px 5px 5px 10px;
+    font : small Verdana, Helvetica, sans-serif;
+    font-size : 90%;
+}
+
+.content .ForrestTable { width: 100%; background-color: #7099C5; color: #ffffff; font-size : 90%;}
+.content .ForrestTable caption { text-align: left; color: black; font-weight: bold; }
+.content .ForrestTable th { text-align: center; }
+.content .ForrestTable td { background-color: #f0f0ff; color: black; }
+
+.content .externals { width: 80%; background-color: #7099C5; color: #ffffff; font-size : 90%;}
+.content .externals caption { text-align: left; color: black; font-weight: bold; }
+.content .externals th { width: 120px; text-align: right; }
+.content .externals td { background-color: #f0f0ff; color: black; }
+
+
+
+.frame { margin: 5px 20px 5px 20px; font-size: 90%; }
+.frame .content { margin: 0px; }
+
+.note { border: solid 1px #7099C5; background-color: #f0f0ff; }
+.note .label { background-color: #7099C5; color: #ffffff; }
+
+.warning { border: solid 1px #D00000; background-color: #fff0f0; }
+.warning .label { background-color: #D00000; color: #ffffff; }
+
+.fixme { border: solid 1px #C6C600; background-color: #FAF9C3; }
+.fixme .label { background-color: #C6C600; color: #ffffff; }
+
+.code { border-color: #CFDCED; border-style: solid; border-width: 1px; }
+.codefrag {	font-family: "Courier New", Courier, monospace; }
+
+.highlight { background-color: yellow; }
+
+.minitoc {margin: 5px 5px 5px 40px;}
+
+.dtdElement { width: 100%;	font-size: 90%; background-color : #ffffff; }
+
+.dtdTag {    color: #990000; text-transform : uppercase;  font-style : normal;  font-size : 120%;  font-weight : bold; }
+
+.section {
+    font-family: Verdana, Helvetica, sans-serif;
+    background-color: #294563;
+    color: #ffffff;
+    font-weight: bold;
+    padding: 2px;
+    margin-top: 20px;
+    clear: right;
+}
+
+.subsection {
+    font-family: arial,helvetica,sanserif;
+    background-color: #4C6C8F;
+    color: #ffffff;
+    font-weight: bold;
+    padding: 2px;
+    clear: right;
+}
+
+.toc {
+    font-family: arial,helvetica,sanserif;
+    background-color: #4C6C8F;
+    color: #ffffff;
+    font-weight: bold;
+    padding: 2px;
+}
+
+.faq {
+    font-family: arial,helvetica,sanserif;
+    background-color: #4C6C8F;
+    color: #ffffff;
+    font-weight: bold;
+    padding: 2px;
+}
+
+.navpath {
+    font-family: arial,helvetica,sanserif;
+    background-color: #CFDCED;
+    padding: 2px 6px;
+    margin: 0px 0px 0px 0px;
+    font-size: 90%;
+    border-bottom: 2px solid #4C6C8F;
+}
+
+.title {
+    font-family: Verdana, Helvetica, sans-serif;
+}
+
+.copyright {
+    font-family: arial,helvetica,sanserif;
+    font-size: 90%;
+    background-color: #CFDCED;
+    clear: both;
+    text-align: center;
+    margin: 0px;
+    border-top: thin solid #4C6C8F;
+}
+
+.bluebar {
+    padding: 5px 5px 5px 10px;
+    background-color: #4C6C8F;
+    margin: 0px;
+}
+
+.lightbluebar {
+    padding: 5px 5px 5px 10px;
+    background-color: #CFDCED;
+    margin: 0px;
+    border-top: 1px solid #294563;
+    border-bottom: 1px solid #294563;
+}
+
+.logobar {
+    background-color: #294563;
+    padding-right: 10px;
+    margin: 0px;
+}
+
+.searchcaption {
+    color: #FFFFFF;
+    text-align: left;
+    font-family: arial,helvetica,sanserif;
+    font-size: 90%;
+    background-color: #4C6C8F;
+    margin: 0px;
+}
+
+@media print {
+   .menu {
+     display: none;
+   }
+}
+
+#adcontainer {
+}
\ No newline at end of file
diff --git a/trunk/docs/problems.html b/trunk/docs/problems.html
new file mode 100644
index 0000000..75ae98d
--- /dev/null
+++ b/trunk/docs/problems.html
@@ -0,0 +1,397 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Having Problems?</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Conor MacNeill">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                              <span class="sel">Having Problems?</span>
+                              </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Having Problems?</h1>
+            <h3 class="section">
+      <a name="Having Problems?"></a>
+      Having Problems?
+    </h3>
+                        <p>
+           This page details some steps you can take to try and resolve
+           any problems you may be having with Ant. If you find you can't
+           resolve the problem, then this page will help you collect some of
+           the relevant information to provide in a bug report. This information
+           will help the Ant developers understand and resolve the problem.
+           Of course, not all the steps here will make sense for every problem
+           you may encounter - these are just some suggestions to point
+           you in the right direction.
+        </p>
+                                      <h4 class="subsection">
+        <a name="Ensure that you are actually running the version of Ant that you think you do"></a>
+        Ensure that you are actually running the version of Ant that you think you do
+      </h4>
+                        <p>Many tools include a version of Ant and some Operating
+        Systems even install it by default now, so you may have a
+        version of Ant installed that you haven't been aware of.</p>
+                                <p>One of the first things to do is to run
+          <br /><br />
+          <font face="verdana" size="-1">ant -version</font>
+          <br /><br />
+          and
+          <br /><br />
+          <font face="verdana" size="-1">ant -diagnostics</font>
+          <br /><br />
+          to be sure.  Also, we highly recommend that you run Ant with
+          an empty CLASSPATH.  If any other version of Ant can be
+          loaded from the CLASSPATH, many types of errors may happen
+          because of incompatible classes being loaded.</p>
+                                <p>See <a href="faq.html">the FAQ</a> for <a href="faq.html#NoClassDefFoundError">some</a> <a href="faq.html#InstantiationException">examples</a>, but many
+        other problems are a result of an old version of Ant on your
+        system as well.</p>
+                                                          <h4 class="subsection">
+        <a name="Read the Manual"></a>
+        Read the Manual
+      </h4>
+                        <p>
+            The first step to take when you have a problem with Ant is to read
+            the <a href="manual/index.html">manual</a> entry for the task or
+            concept that is giving you trouble. In particular, check the
+            meaning of a task's attributes and nested elements. Perhaps an
+            attribute is available that would provide the behavior you require.
+            If you have problems with the manual itself, you can submit a
+            documentation bug report (see below) to help us improve the Ant
+            documentation.
+         </p>
+                                                          <h4 class="subsection">
+        <a name="Examine Debug Output"></a>
+        Examine Debug Output
+      </h4>
+                        <p>
+            If you're still having a problem, the next step is to try and
+            gather additional information about what Ant is doing.
+            Try running Ant with the <code>verbose</code> flag:
+            <br /><br />
+            <font face="verdana" size="-1">ant -verbose</font>
+            <br /><br />
+            or
+            <br /><br />
+            <font face="verdana" size="-1">ant -v</font>
+            <br /><br />
+
+            This will produce output that starts like the following:</p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+Ant version 1.4.1 compiled on October 11 2001<br />
+Buildfile: build.xml<br />
+Detected Java version: 1.3 in: D:\usr\local\java\jdk13\jre<br />
+Detected OS: Windows NT<br />
+parsing buildfile D:\ant\build.xml
+with URI = file:D:/ant/build.xml<br />
+Project base dir set to: D:\ant<br />
+  [property] Loading Environment env.<br />
+  [property] Loading D:\ant\conf.properties<br />
+Build sequence for target 'debug' is [debug]<br />
+Complete build sequence is [debug, gensrc, compile, jar, test]<br />
+. . .<br />
+
+      </td>
+      </tr>
+          </table>
+                                <p>
+              You should be able to see from the trace more about what Ant
+              is doing and why it's taking a particular course of action.
+              If you need even more information, you can use the
+              <code>-debug</code> flag rather than
+              <code>-verbose</code>.
+              This will generally produce so much
+              output that you may want to save the output to a file and
+              analyze it in an editor. You can save the output using the
+              <code>-logfile &lt;filename&gt;</code> flag, or
+              using redirection.
+           </p>
+                                <p>
+              Once you have all this debug information, how can you use it
+              to solve your problem?  That will depend on the task in question
+              and the nature of your problem. Each task logs different aspects
+              of its operation, but it should give you an idea of what is going
+              on. For example, the <code>&lt;javac&gt;</code> task logs the
+              reasons why it
+              chooses to compile particular class files and not others, along
+              with which compiler it is using and the arguments it will pass
+              to that compiler. The following partial trace shows why
+              <code>&lt;javac&gt;</code> is adding one class file but
+              skipping another.
+              This is followed by which compiler it will be using, the
+              arguments that will get passed to the compiler,
+              and a list of all the class files to be compiled.
+           </p>
+                                      <table class="ForrestTable" cellspacing="1" cellpadding="4">
+              <tr>
+                      <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+[javac] Test.java omitted as D:\classes\Test.class is up to date.<br />
+[javac] Unset.java added as D:\classes\Unset.class is outdated.<br />
+[javac] Compiling 1 source file to D:\classes<br />
+[javac] Using classic compiler<br />
+[javac] Compilation args: -d D:\classes -classpath D:\classes;<br />
+D:\jdk118\classes.zip; -sourcepath D:\src\java -g:none<br />
+[javac] File to be compiled:<br />
+D:\src\java\Unset.java<br />
+
+      </td>
+      </tr>
+          </table>
+                                <p>
+              In many cases, Ant tasks are wrappers around OS commands or
+              other Java classes. In debug mode, many of these tasks will
+              print out the equivalent command line, as the
+              <code>&lt;javac&gt;</code> task
+              output does. If you are having a problem, it is often useful to
+              run the command directly from the command line, in the same way
+              Ant is running it, and see if the problem occurs from there
+              as well. The problem may be in the command that is being run,
+              or it may be in the way the Ant task is running the command.
+              You can also see the effect of changing attribute values on the
+              generated command line. This can help you to understand whether
+              you are using the correct attributes and values.
+            </p>
+                                                          <h4 class="subsection">
+        <a name="Has It Been Fixed?"></a>
+        Has It Been Fixed?
+      </h4>
+                        <p>
+            After examining the debug output, if you still believe that the
+            problem you are having is caused by Ant, chances are that someone
+            else may have already encountered this problem, and perhaps it has
+            been fixed. The next step, therefore, would be to download the
+            sources of ant, see <a href="svn.html">svn</a>.
+        </p>
+                                <p>
+          <a href="http://vmgump.apache.org/gump/public/index.html">Gump</a>
+          is building ant every night and using the ant built from the
+          latest source to build a long list of open source projects. However,
+          the version of ant built by gump is not available for download. Even
+          if it were, it would not include most of the optional tasks.
+        </p>
+                                <p>
+            We currently do not have nightly builds including the optional tasks.
+        </p>
+                                            <h3 class="section">
+      <a name="bugs"></a>
+      bugs
+    </h3>
+                        <p>If you are convinced that you have identified an unfixed bug, please turn to
+      our document concerning the <a href="bugs.html">bug database</a>.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/projects.html b/trunk/docs/projects.html
new file mode 100644
index 0000000..412755f
--- /dev/null
+++ b/trunk/docs/projects.html
@@ -0,0 +1,1372 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Related Projects</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="bodewig@apache.org">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                              <span class="sel">Related Projects</span>
+                              </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Related Projects</h1>
+            <h3 class="section">
+      <a name="Related Projects"></a>
+      Related Projects
+    </h3>
+                        <p>Nothing listed here is directly supported by the Ant
+      developers, if you encounter any problems with them, please use
+      the contact information.</p>
+                                      <h4 class="subsection">
+        <a name="AndroMDA"></a>
+        AndroMDA
+      </h4>
+                        <p>AndroMDA is a code generator tool that follows the Model
+        Driven Architecture (MDA) paradigm. It takes a UML model from
+        a CASE-tool and generates classes and deployable components
+        (J2EE or other) specific for your application
+        architecture.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.4.1 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.andromda.org/">http://www.AndroMDA.org/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=73047">project mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          BSD license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntContrib"></a>
+        AntContrib
+      </h4>
+                        <p>The Ant-Contrib project is a collection of user supplied
+        task (like an <code>&lt;if&gt;</code> task) and a development
+        playground for experimental tasks like a C/C++ compilation
+        task for different compilers.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.4.1 and above
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://ant-contrib.sourceforge.net/">http://ant-contrib.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=36177">project mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antelope"></a>
+        Antelope
+      </h4>
+                        <p>A GUI for running Ant and editing build files, can run as
+        stand-alone or as a plugin to jEdit. In addition to running
+        targets, Antelope can generate performance statistics and can
+        trace/display a target's execution path without actually
+        executing the target.</p>
+                                <p>Includes several additional tasks: Assert, If/Else,
+        Try/Catch/Finally, Switch, Variable, Stopwatch, Limit, Math,
+        Post, SSH, SCP, AntFetch, AntCallBack.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and higher.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antelope.tigris.org/">http://antelope.tigris.org/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:daleanson@users.sourceforge.net">Dale Anson</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntHill"></a>
+        AntHill
+      </h4>
+                        <p>Anthill is a build tool that promotes a controlled build
+        process by ensuring that every build reflects the source
+        repository contents and tagging the repository with a unique
+        build number after every build. Anthill also encourages the
+        sharing of knowledge within an organization by automatically
+        updating a project intranet site with artifacts from the
+        latest build.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.3, is compatible with Ant 1.3 to 1.4.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.urbancode.com/projects/anthill/">http://www.urbancode.com/projects/anthill/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:mbz@urbancode.com">Maciej Zawadzki</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Mozilla-like license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antigen"></a>
+        Antigen
+      </h4>
+                        <p>Antigen (Ant Installer Generator) is a tool to take an Ant build script, combine it with a GUI
+        and wrap it up as an executable jar file. Its main use is for creating graphical, ant-based installers.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          bundles Ant 1.6.2
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antigen.sourceforge.net/">http://antigen.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:johndavidtaylor@users.sourceforge.net">Jon Tayler</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Academic Free License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntInstaller"></a>
+        AntInstaller
+      </h4>
+                        <p>Builds MSI style installers (with command line option)
+        using Ant as Back end. UI developed by writing an XML install
+        descriptor.  Runtime launched from scripts or an all inclusive
+        Jar.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.1 others not tested
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antinstaller.sf.net/">http://antinstaller.sf.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:teknopaul@users.sourceforge.net">teknopaul@users.sourceforge.net</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL but in the process of of moving to Apache2.0 on request
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antlion"></a>
+        Antlion
+      </h4>
+                        <p>The Antlion Project adds value to Ant build scripts by providing
+        tasks which centralizes the library dependencies, and enables
+        projects to define dependencies upon other projects.</p>
+                                <p>External dependencies may be loaded from a custom local
+        repository or Maven-like remote repositories. Antlion handles
+        the generation of properties, filesets, and paths.</p>
+                                <p>Inter-project dependencies allow for building the other
+        project's files if they aren't already built.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antlion.sourceforge.net/">http://antlion.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://sourceforge.net/mail/?group_id=93410">Project mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache License, Version 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="AntShellExt (Ant Shell Extension)"></a>
+        AntShellExt (Ant Shell Extension)
+      </h4>
+                        <p>Ant Shell Extension is a Windows Explorer enhancement that adds a contextual 
+        menu when you right click over an Ant xml file, so you can execute all the actions 
+        defined in that file without going to a command console or starting your favourite 
+        IDE to make a simple clean.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Tested with Ant 1.6 and later, should work with all versions
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.elpagestion.com/os_ant_en.shtml">
+                http://www.elpagestion.com/os_ant_en.shtml</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:opensource@elpagestion.com">Project mail</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Antworks"></a>
+        Antworks
+      </h4>
+                        <p>The antworks project is a set of tools and standardized targets that
+        greatly simplifies using ant in your project.</p>
+                                <p>
+            The driver behind antworks is Importer. Importer is an extension to the
+            ant import task that will download and
+            cache an ant build.xml file and it's associated resources called
+            antlets.  Antlets are available for Java compiling
+            and packaging,  JUnit, Forrest, J2EE and
+            <a href="http://antworks.sourceforge.net/antlets/">more</a>.
+            </p>
+                                <p>
+            See the <a href="http://antworks.sourceforge.net/start.html ">Getting Started</a>
+            guide for more information.
+            </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          1.6 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://antworks.sourceforge.net/">http://antworks.sourceforge.net/index.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://lists.sourceforge.net/lists/listinfo/antworks-developers">Antworks Developers mailing lists</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          The Apache License 2.0
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="BuildMonkey"></a>
+        BuildMonkey
+      </h4>
+                        <p>BuildMonkey is a Web-based automated build dashboard, with upload
+           capability and google web search. It schedules the running of Ant
+           build scripts - checking sources out of CM - and makes the results
+           available centrally.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5.4 or later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.buildmonkey.com/">http://www.buildmonkey.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jb@buildmonkey.com">jb@buildmonkey.com</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware, commercial/support licences available
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="CruiseControl"></a>
+        CruiseControl
+      </h4>
+                        <p>CruiseControl is a tool for setting up a continuous build
+        process.  CruiseControl provides an Ant wrapper and a set of
+        tasks to automate the checkout/build/test cycle. CruiseControl
+        also comes bundled with a servlet for viewing the status of
+        the current build, as well as previous build results.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.2 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cruisecontrol.sourceforge.net/">http://cruisecontrol.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://cruisecontrol.sourceforge.net/contact.html">Project Mailing Lists and Administrators</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Release 1.0 has been licensed under the GNU General Public
+            License.  Starting with release 1.1 the license has been
+            changed to a BSD-like license.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Invicta"></a>
+        Invicta
+      </h4>
+                        <p>Invicta is a build management tool. Using simple project definition files,
+        it generates powerful build scripts (such as ANT) while hiding their
+        complexity. Invicta is a modular framework that allows developing additional
+        components and output types.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.5 and higher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://invicta.sf.net/">http://invicta.sf.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://invicta.sf.net/contact.html">Project Mailing Lists and Administrators</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="JAM - JavaGen Ant Modules"></a>
+        JAM - JavaGen Ant Modules
+      </h4>
+                        <p>JAM is a modular Ant toolkit for developing and testing Java/J2EE
+        applications. JAM supports EJB and Servlet/JSP development using XDoclet,
+        JUnit, Cactus, Maven, Castor and MDA/UML code generation on various J2EE
+        servers including JBoss.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.javagen.com/jam.jsp">http://www.javagen.com/jam.jsp</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.javagen.com/feedback.do">Feedback</a> <br />
+                <a href="http://www.javagen.com/bugs.do">Bug Reports</a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Krysalis Centipede"></a>
+        Krysalis Centipede
+      </h4>
+                        <p>The Centipede admin told us, that that project
+           "is no more" and that "Antworks has taken it place."
+        </p>
+                                                          <h4 class="subsection">
+        <a name="Leafcutter"></a>
+        Leafcutter
+      </h4>
+                        <p>Leafcutter is an API which allows you to execute Ant tasks from Java code. <br />
+           Leafcutter is useful as: <ul>
+           <li>A way of integrating Ant tasks into existing Java programs. </li>
+           <li>A wholesale alternative to standard Ant for process automation. </li>
+           </ul>
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <i>unknown</i>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://leafcutter.dev.java.net/">https://leafcutter.dev.java.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://leafcutter.dev.java.net/servlets/ProjectForumView">Discussion Forum</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache Software Foundation License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="luntbuild"></a>
+        luntbuild
+      </h4>
+                        <p>Luntbuild is an open source build automation and management
+        tool based on Apache Ant. Builds are setup through concepts of
+        projects, views, schedules, modules, etc. All configurations
+        and monitoring tasks is performed from a clean web
+        interface. It supports schedules builds, force builds,
+        rebuilds, clean build, increment build, etc.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sourceforge.net/projects/luntbuild/">http://www.sourceforge.net/projects/luntbuild/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/luntbuild/">luntbuild project page</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Opensource
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="NAnt"></a>
+        NAnt
+      </h4>
+                        <p>NAnt is a .NET based build tool. In theory it is kind of
+        like make without make's wrinkles. In practice it's a lot like
+        Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          compatible in spirit.
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://nant.sourceforge.net/">http://nant.sourceforge.net/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/mail/?group_id=31650">project mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Parabuild"></a>
+        Parabuild
+      </h4>
+                        <p>Parabuild is an automated multiplatform build management server.
+        Parabuild helps software teams and organizations of all sizes reduce
+        risks of project failures and increase productivity by providing provides
+        automatic continuous integration builds and stable scheduled builds.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.3 and later
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.viewtier.com/products/parabuild.htm">http://www.viewtier.com/products/parabuild.htm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.viewtier.com/about_us.htm">http://www.viewtier.com/about_us.htm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Commercial
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Rant"></a>
+        Rant
+      </h4>
+                        <p>Rant stands for Remote Ant. It is a distributed build
+        system that allows an Ant build file to launch builds on other
+        systems and receive exceptions should they occur.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://sourceforge.net/projects/remoteant/">http://sourceforge.net/projects/remoteant/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:cnelson@einnovation.com">Chris Nelson</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          MIT License
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Savant"></a>
+        Savant
+      </h4>
+                        <p>Savant helps simplify builds and codebases by handling the
+        resolution of project dependencies automatically. Savant supports
+        Maven style dependency downloads and various other methods of
+        retrieving dependencies, including fetching files from CVS modules.
+        Savant goes a step further than other dependency solutions and provides
+        the means for multiple internal projects to build each other in order
+        to resolve inter-project dependencies.</p>
+                                <p>Savant can be used via various Ant types and tasks as well as used
+        from any Java application including those that do not make use of Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.1
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.inversoft.com/">http://www.inversoft.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.inversoft.com/contact.html">http://www.inversoft.com/contact.html</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          LGPL
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="WebTest"></a>
+        WebTest
+      </h4>
+                        <p>WebTest is a free open source tool for automated testing of web applications.
+        It is a set of powerful Ant tasks allowing to call web pages, mimic user actions
+        (clicking links, filling forms, ...) and verify the results.
+        The generated reports give comprehensive information on success and failure of the test steps.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.6.5
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://webtest.canoo.com/">http://webtest.canoo.com/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://lists.canoo.com/mailman/listinfo/webtest/">project mailing list</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Apache like license
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="XML Publication"></a>
+        XML Publication
+      </h4>
+                        <p>XML Publication is a set of tools to generate Web pages
+        from desktop documents or other structured documents using
+        XSLT and Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.4
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://XMLpublication.org/">http://XMLpublication.org/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:jmvanel@free.fr">Jean-Marc Vanel</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          GNU General Public License.
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="yEd"></a>
+        yEd
+      </h4>
+                        <p>yEd is a freeware multi-purpose graph and diagram editor
+        that runs on the Java 2 platform. It provides an import filter
+        for Ant build scripts that makes it possible to conveniently
+        display and browse the dependencies between the different targets
+        of the build file. This is especially useful for debugging and
+        understanding large build files.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Compatibility:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant 1.x
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.yworks.com/products/yed/">http://www.yworks.com/products/yed/</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Contact:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.yworks.com/en/company_contact.htm">yWorks Support</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          License:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Freeware
+      </td>
+      </tr>
+          </table>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/projects/index.html b/trunk/docs/projects/index.html
new file mode 100644
index 0000000..ce40753
--- /dev/null
+++ b/trunk/docs/projects/index.html
@@ -0,0 +1,184 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Welcome</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+          <meta name="author" content="Christoph Wilhelms">
+  <meta name="email" content="christoph.wilhelms@t-online.de">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                              <span class="sel">Welcome</span>
+                              </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Welcome</h1>
+            <h3 class="section">
+      <a name="Welcome to the Ant Projects Area"></a>
+      Welcome to the Ant Projects Area
+    </h3>
+                        <h3>This is where the Ant sub-projects live!</h3>
+                                <p>Now, that Ant has become an Apache Top-Level Project it is time to make space on this
+    Web-Page for Ant sub-projects.</p>
+                                <p>To make sure you do not miss anything: Stay tuned and visit this page from time to time :)!
+    </p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/projects/ivy.html b/trunk/docs/projects/ivy.html
new file mode 100644
index 0000000..1e6d4fa
--- /dev/null
+++ b/trunk/docs/projects/ivy.html
@@ -0,0 +1,181 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - The Ivy Subproject</title>
+        <link type="text/css" href="../page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="../breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="../images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="../images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="../images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="../images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="../images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="5"><img alt="" height="8" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="../index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Home</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="../images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="8"><img alt="" height="5" width="8" src="../images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Projects</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="../images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                                                              
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Projects
+          <ul>
+                            <li>
+                                    <a href="../projects/index.html">Welcome</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ant Libraries
+          <ul>
+                            <li>
+                                    <a href="../antlibs/index.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/charter.html">Charter</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/proper.html">Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="../antlibs/sandbox.html">Sandbox Ant Libraries</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/antlibs/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Ivy
+          <ul>
+                            <li>
+                                    <a href="../projects/ivy.html">Introduction</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/">Homepage</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/ivy/download.cgi">Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ivy/">Wiki</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="../images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="../images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">The Ivy Subproject</h1>
+            <h3 class="section">
+      <a name="The Ivy Subproject"></a>
+      The Ivy Subproject
+    </h3>
+                        <h3>Apache Ivy</h3>
+                                <p>Ivy is a simple yet powerful dependency manager featuring continuous integration,
+      dependencies of dependencies management, multiple repositories including ibiblio and
+      high performance (use of a local cache).</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/resources.html b/trunk/docs/resources.html
new file mode 100644
index 0000000..5c72f6f
--- /dev/null
+++ b/trunk/docs/resources.html
@@ -0,0 +1,1444 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Resources</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Stefan Bodewig">
+  <meta name="email" content="bodewig@apache.org">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                              <span class="sel">Resources</span>
+                              </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Resources</h1>
+            <h3 class="section">
+      <a name="FAQs"></a>
+      FAQs
+    </h3>
+                              <h4 class="subsection">
+        <a name="At Ant's website"></a>
+        At Ant's website
+      </h4>
+                        <p>Starting with the release of Ant 1.4 the Ant's FAQ is
+        bundled with the distribution, the most recent version can
+        always be found at the website.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          FAQ:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="faq.html">http://ant.apache.org/faq.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="jGuru"></a>
+        jGuru
+      </h4>
+                        <p>jGuru hosts an interactive Ant discussion forum and FAQ system</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Forum:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.jguru.com/forums/home.jsp?topic=Ant">http://www.jguru.com/forums/home.jsp?topic=Ant</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          FAQ:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.jguru.com/faq/home.jsp?topic=Ant">http://www.jguru.com/faq/home.jsp?topic=Ant</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="FAQ about Borland Application Server tasks"></a>
+        FAQ about Borland Application Server tasks
+      </h4>
+                        <p>Benoit Moussaud, the original author of the Borland
+        Application Server specific <a href="manual/OptionalTasks/ejb.html#ejbtasks">EJB tasks</a> has put
+        together a FAQ for this specific subtask.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          FAQ:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.moussaud.org/ejbjar.html">http://www.moussaud.org/ejbjar.html</a>
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="WIKIs"></a>
+      WIKIs
+    </h3>
+                              <h4 class="subsection">
+        <a name="Apache"></a>
+        Apache
+      </h4>
+                        <p>The ASF provides a Wiki farm for Apache projects.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Main page:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://wiki.apache.org/general">Apache Wiki Farm</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ant Wiki:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://wiki.apache.org/ant/">Ant Wiki</a>
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="Books"></a>
+      Books
+    </h3>
+                        <p>The most recent books come first</p>
+                                      <h4 class="subsection">
+        <a name="Ant in Action"></a>
+        Ant in Action
+      </h4>
+                        <p>Published April/May 2007, and covering Ant 1.7.</p>
+                                <p>This is a major rewrite of the first edition; still 600 pages long.
+        </p>
+                                <p>
+          This book moves up from Ant1.5 to Java1.5 and 1.7, with a near-complete
+          rewrite of the applied-ant section, covering new topics such as
+          antlibs, repository management with Ivy, Xml Schema validation,
+          EJB3.0/Java EE development and advanced deployment using SmartFrog.
+          The ant coding section looks at AntUnit, antlib authoring and
+          scripting languages, while the beginners chapters, the first third
+          of the book, still shows developers how to build, test, package and
+          redistribute a Java application.
+        </p>
+                                <p>
+          If you are one of the 20,000+ owners of the first edition, it is now
+          obsolete. Sorry :)
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Steve Loughran and Erik Hatcher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Publisher URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.manning.com/loughran/">
+                http://www.manning.com/loughran/
+              </a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Book URL
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://antbook.org/">
+                http://antbook.org/
+              </a>
+            
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Source code repository
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://sourceforge.net/projects/antbook">
+                http://sourceforge.net/projects/antbook
+              </a>
+            
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>193239480X</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/193239480X/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=193239480X" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=193239480X" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=193239480X&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Ant: The Definitive Guide, 2nd edition"></a>
+        Ant: The Definitive Guide, 2nd edition
+      </h4>
+                        <p>Published April 2005, and covers Ant release 1.6.1.</p>
+                                <p>This is a complete rewrite of the first edition; this book is
+        now 290 pages and so covers Ant in more depth than its predecessor.
+        </p>
+                                <p>It also mixes reference information (tables) with text explanation
+        on how to use the tasks. Contents includes JUnit, CVS, execution, basic
+        deployment, Web application development and XDoclet. There is also coverage
+        of XDoclet, and a chapter on how to extend Ant in Java.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Steve Holzner
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.oreilly.com/catalog/anttdg2/">http://www.oreilly.com/catalog/anttdg2/</a>
+            
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>0596006098</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0596006098/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=0596006098" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=0596006098" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=0596006098&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Pragmatic Project Automation"></a>
+        Pragmatic Project Automation
+      </h4>
+                        <p>
+
+        How to Build, Deploy, and Monitor Java Applications.
+        Published: July 2004 ISBN:        0-9745140-3-9
+        </p>
+                                <p>
+          This is not a reference guide to Ant, but a book on how to automate the build process.
+          The core build, continuous integration, reporting and release management
+          are all covered. Ant is of course central to this. This is a fun read!
+        </p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Mike Clark
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          
+              <a href="http://www.pragmaticprogrammer.com/sk/auto/">http://www.pragmaticprogrammer.com/sk/auto//</a>
+            
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>0974514039</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0974514039/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=0974514039" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=0974514039" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=0974514039&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Extreme Programming with Ant"></a>
+        Extreme Programming with Ant
+      </h4>
+                        <p> This book shows how to implement an XP project using Ant 1.5.3, and many other 3rd party tools.  Covers:</p>
+                                <ul>
+               <li>The fundamentals of Ant: concepts, core and optional tasks</li>
+               <li>How to write custom Ant components, including custom Tasks, Loggers, Listeners, Input Handlers, Selectors, Filters, Mappers and Data Types</li>
+               <li>Mitigating risks by creating spike tests with Ant buildfiles</li>
+               <li>Add CVS version control and testing with JUnit</li>
+               <li>Automate nightly builds and reporting</li>
+               <li>Deploy applications dynamically using XDoclet</li>
+               <li>Enforcing Code Standards with Jalopy, PMD, CheckStyle, iContract, JDepend</li>
+               <li>Using Remote Ant (Rant) and CruiseControl</li>
+               <li>Generating project documentation</li>
+               <li>Adapting an XP process for use by other teams or across an enterprise</li>
+               <li>Custom Task examples to generating UML diagrams, creating reports and metrics on-the-fly</li>
+               <li>Follows a case-study of a team that implements an XP Project</li>
+            </ul>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Authors:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Glenn Niemeyer and Jeremy Poteet
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sams.com/catalog/product.asp?product_id=%7BFB825A48-BC04-4C55-BD8C-DF93C6BBF920%7D">http://www.sams.com/catalog/product.asp?product_id=%7BFB825A48-BC04-4C55-BD8C-DF93C6BBF920%7D</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>0672325624</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0672325624/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=0672325624" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=0672325624" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=0672325624&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Ant. Das Java-Build-Tool in der Praxis"></a>
+        Ant. Das Java-Build-Tool in der Praxis
+      </h4>
+                        <p>A German language book on Ant that covers Ant 1.5.
+        This is the original description:</p>
+                                <pre class="code">
+        Das Build-Tool Ant ist das Open-Source-Werkzeug, das den Entwicklungsprozess einer Java-
+        oder J2EE-Anwendung wesentlich vereinfacht. Gesteuert durch XML-basierte Skripte f�hrt es
+        nahezu alle Aufgaben aus, die nach dem Kodieren einer Anwendung anfallen.</pre>
+                                <p>Some topics:</p>
+                                <ul>
+                <li>creating archives (zip, jar)</li>
+                <li>call the java compiler</li>
+                <li>edit property files</li>
+                <li>file operation</li>
+                <li>source code control systems</li>
+            </ul>
+                                <p>The book is available in English as "Ant: The Java Build Tool in Practice"</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Authors:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Bernd Matzke
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.addison-wesley.de/main/main.asp?page=home/bookdetails&amp;ProductID=13459">http://www.addison-wesley.de/main/main.asp?page=home/bookdetails&amp;ProductID=13459</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>3827320666</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/3827320666/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=3827320666" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=3827320666" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=3827320666&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Java Development with Ant"></a>
+        Java Development with Ant
+      </h4>
+                        <p>Published 2002. This book covers Ant 1.5, including:</p>
+                                <ul>
+                <li>The new Ant 1.5 features</li>
+                <li>Ant's datatypes and property handling</li>
+                <li>JUnit testing and reporting</li>
+                <li>Continuous integration techniques</li>
+                <li>XDoclet for attribute-oriented programming</li>
+                <li>EJB generation, building, and packaging</li>
+                <li>Writing and testing native code</li>
+                <li>Building Web Services with Apache Axis</li>
+                <li>Deploying your system to multiple remote servers</li>
+                <li>Using and writing
+                    <ul>
+                        <li>Loggers</li>
+                        <li>Listeners</li>
+                        <li>Selectors</li>
+                        <li>Custom tasks</li>
+                    </ul>
+                </li>
+            </ul>
+                                <p>Also available in Korean and German editions</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Authors:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Erik Hatcher and Steve Loughran
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.manning.com/antbook/">http://www.manning.com/antbook/</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>1930110588</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/1930110588/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=1930110588" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=1930110588" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=1930110588&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Ant: The Definitive Guide, 1st edition"></a>
+        Ant: The Definitive Guide, 1st edition
+      </h4>
+                        <p>Published 2002, Covers Ant release 1.4.1.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Authors:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Jesse E. Tilly and Eric M. Burke
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.oreilly.com/catalog/anttdg/">http://www.oreilly.com/catalog/anttdg/</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>0596001843</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/0596001843/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=0596001843" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=0596001843" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=0596001843&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Ant. Kurz und Gut."></a>
+        Ant. Kurz und Gut.
+      </h4>
+                        <p>A German language short reference for Ant that covers Ant
+        1.4.  This is the original description:</p>
+                                <pre class="code">
+  Ant kurz &amp; gut enthält eine vollständige Referenz der Built-in Tasks
+  und ihrer jeweiligen Attribute sowie kurze Beispiele für ihre Verwendung.
+  Daneben bietet das Buch eine knappe Einführung in die Arbeit mit Ant und
+  eine Erläuterung der Ant-Basiselemente (Projekte, Properties, Targets und Tasks).
+  Behandelt werden außerdem grundlegende Konzepte wie Filesets, Patternsets und
+  Pfadstrukturen, das Schreiben eigener Tasks, die Aufruf-Syntax und Optional Tasks. </pre>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Stefan Edlich
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.amazon.de/exec/obidos/ASIN/3897212412/">http://www.amazon.de/exec/obidos/ASIN/3897212412/</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>3897212412</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/3897212412/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=3897212412" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=3897212412" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=3897212412&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                                            <h4 class="subsection">
+        <a name="Java Tools for eXtreme Programming"></a>
+        Java Tools for eXtreme Programming
+      </h4>
+                        <p>This book covers the following XP subjects:</p>
+                                <ul>
+                <li>Automated unit and functional testing</li>
+                <li>Continuous integration through build and deployment automation</li>
+                <li>The value of refactoring and continuous integration</li>
+                <li>How Ant, JUnit, JUnitPerf, Cactus, HTTPUnit, and JMeter
+                can be used to achieve the goals of the XP methodology</li>
+            </ul>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Authors:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Richard Hightower and Nicholas Lesiecki
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.wiley.com/cda/product/0,,047120708X,00.html">http://www.wiley.com/cda/product/0,,047120708X,00.html</a>
+      </td>
+      </tr>
+            <tr><th>ISBN:</th><td>047120708X</td></tr>
+    </table>
+                            <p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/047120708X/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=047120708X" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=047120708X" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=047120708X&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+                              <h3 class="section">
+      <a name="Articles and Presentations"></a>
+      Articles and Presentations
+    </h3>
+                        <p>The following sections list articles and presentations
+      written about Apache Ant.  If you've written something that
+      should be included, please post it to one of the mailing
+      lists.</p>
+                        <h3 class="section">
+      <a name="Articles"></a>
+      Articles
+    </h3>
+                              <h4 class="subsection">
+        <a name="Extending Ant Input Abilities"></a>
+        Extending Ant Input Abilities
+      </h4>
+                        <p>The contents of this document is the following:<ul>
+           <li>Section 2 provides a simple example how InputHandlers are created,</li>
+           <li>Section 3 develops an inputhandler that masks the passwords typed on the command line,</li>
+           <li>Section 4 gives two handlers, whose input is typed in graphical components,</li>
+           <li>Section 5 extends Input task so that we can use dierent input handlers on different uses of &lt;input&gt;,</li>
+           <li>Section 6 describes a problem found while writing this document,</li>
+           <li>Section 7 summarizes some dark corners the author do not understand.</li>
+         </ul></p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Ivan Ivanov
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="https://sourceforge.net/project/showfiles.php?group_id=103509">https://sourceforge.net/project/showfiles.php?group_id=103509 (Download ZIP+PDF from Sourceforge)</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Keep the Ant, Hold the XML"></a>
+        Keep the Ant, Hold the XML
+      </h4>
+                        <p>Key G. Gauthier talks about writing "buildfiles" in Java.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Key G. Gauthier
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ftponline.com/javapro/2004_06/magazine/features/kgauthier/">http://www.ftponline.com/javapro/2004_06/magazine/features/kgauthier/</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant 1.6 for Task Writers"></a>
+        Ant 1.6 for Task Writers
+      </h4>
+                        <p>This article talks about XML namespace handling, Ant
+        libraries and the newly introduced type polymorphism.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Stefan Bodewig
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://otn.oracle.com/pub/articles/bodewig_taskwriters.html">http://otn.oracle.com/pub/articles/bodewig_taskwriters.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Managing Build Complexity with Apache Ant 1.6"></a>
+        Managing Build Complexity with Apache Ant 1.6
+      </h4>
+                        <p>As Apache Ant is applied to increasingly difficult tasks,
+        its users are creating more complex and less legible build
+        files. This is due, in part, to the limited tools for
+        decomposition and code reuse within previous versions of
+        Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Geoffrey Wiseman
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sys-con.com/story/?storyid=45078&amp;DE=1">http://www.sys-con.com/story/?storyid=45078&amp;DE=1</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="New Ant 1.6 Features for Big Projects"></a>
+        New Ant 1.6 Features for Big Projects
+      </h4>
+                        <p>This article describes the &lt;macrodef&gt;, &lt;import&gt;
+          and &lt;subant&gt; tasks in detail and shows how they help in
+          building bigger systems.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Stefan Bodewig
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://otn.oracle.com/pub/articles/bodewig_ant1.6.html">http://otn.oracle.com/pub/articles/bodewig_ant1.6.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Programmieren für Ant"></a>
+        Programmieren für Ant
+      </h4>
+                        <p>This article describes the main topics of programming your own tasks.
+        Description is done on five examples.</p>
+                                <p>This article is written in German and published in
+        <a href="http://www.sigs-datacom.de/sd/publications/js/index.htm">Java-Spektrum</a>
+        5/2004.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Bernd Matzke
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sigs-datacom.de/sd/news/document?PID=216">http://www.sigs-datacom.de/sd/news/document?PID=216</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant in Anger: Using Ant in a Production Development System"></a>
+        Ant in Anger: Using Ant in a Production Development System
+      </h4>
+                        <p>This document describes strategies and some basic examples of how to
+        use Ant in larger team development projects.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Steve Loughran
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="ant_in_anger.html">http://ant.apache.org/ant_in_anger.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant Task Guidelines"></a>
+        Ant Task Guidelines
+      </h4>
+                        <p>This document describes how to write custom Ant tasks, and how to submit
+        them to potentially be included in Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Steve Loughran
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="ant_task_guidelines.html">http://ant.apache.org/ant_task_guidelines.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Build a Better Robot with Ant"></a>
+        Build a Better Robot with Ant
+      </h4>
+                        <p>This article describes the gory details of writing custom
+           Ant tasks.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Erik Hatcher
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.fawcette.com/javapro/2003_02/magazine/features/ehatcher/">http://www.fawcette.com/javapro/2003_02/magazine/features/ehatcher/l</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Automating the build and test process"></a>
+        Automating the build and test process
+      </h4>
+                        <p>This article demonstrates an approach to the automated build and test process. Working with Ant 1.3 and the JUnit test framework, it shows how to automate a process that captures pertinent information about each test suite run, generates an attractive report, and e-mails the report.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:ehatcher@apache.org">Erik Hatcher</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ibm.com/developerworks/java/library/j-junitmail/">http://www.ibm.com/developerworks/java/library/j-junitmail/</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Incremental development with Ant and JUnit"></a>
+        Incremental development with Ant and JUnit
+      </h4>
+                        <p>This article explores the benefits of unit testing with Ant and
+        JUnit, detailing how to develop automated unit tests and integrate them
+        into your build process.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:malcolm@nuearth.com">Malcolm Davis</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www-106.ibm.com/developerworks/library/j-ant/?dwzone=java">http://www-106.ibm.com/developerworks/library/j-ant/?dwzone=java</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Automate your build process using Java and Ant"></a>
+        Automate your build process using Java and Ant
+      </h4>
+                        <p>This article provides an introduction to using Ant with some basic
+        examples and by highlighting some of the important tasks.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:michael.cymerman@javaworld.com">Michael Cymerman</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.javaworld.com/javaworld/jw-10-2000/jw-1020-ant.html">http://www.javaworld.com/javaworld/jw-10-2000/jw-1020-ant.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Short tutorial in Cactus' (formerly J2EEUnit)       documentation"></a>
+        Short tutorial in Cactus' (formerly J2EEUnit)       documentation
+      </h4>
+                        <p>There is a short tutorial on how to use Ant in Cactus'
+        documentation.  It has a slant towards build files that will be used
+        with Cactus.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Cactus development team
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://jakarta.apache.org/cactus/howto_ant_primer.html">http://jakarta.apache.org/cactus/howto_ant_primer.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Developing custom Ant tasks with VisualAge for Java"></a>
+        Developing custom Ant tasks with VisualAge for Java
+      </h4>
+                        <p>This article outlines how to integrate Ant into VisualAge for Java,
+        and how to write and debug custom tasks using the IDE and the
+        integrated debugger.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:glenn@somanetworks.com">Glenn McAllister</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www7.software.ibm.com/vad.nsf/data/document2366?OpenDocument&amp;p=1&amp;BCT=1&amp;Footer=1">http://www7.software.ibm.com/vad.nsf/data/document2366?OpenDocument&amp;p=1&amp;BCT=1&amp;Footer=1</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Automated builds with VisualAge for Java and Ant"></a>
+        Automated builds with VisualAge for Java and Ant
+      </h4>
+                        <p>This article shows how you can perform command line builds with a
+        VisualAge for Java repository.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:glenn@somanetworks.com">Glenn McAllister</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www7.software.ibm.com/vad.nsf/Data/Document4366?OpenDocument&amp;p=1&amp;BCT=3&amp;Footer=1">http://www7.software.ibm.com/vad.nsf/Data/Document4366?OpenDocument&amp;p=1&amp;BCT=3&amp;Footer=1</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant: A Build Tool from the Jakarta Project"></a>
+        Ant: A Build Tool from the Jakarta Project
+      </h4>
+                        <p>This article is from the "Best Practices" section of
+        Sun's Dot-Com Builder Site.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Laura Geele Wang
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://dcb.sun.com/practices/profiles/ant.jsp">http://dcb.sun.com/practices/profiles/ant.jsp</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Making a Mountain Out of an Anthill"></a>
+        Making a Mountain Out of an Anthill
+      </h4>
+                        <p>This article is from the June 2001 issue of the Java Developer'
+        Journal.  You need to be a registered JDJ subscriber to view this
+        article.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Neal Ford
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sys-con.com/java/archivesa.cfm?volume=06&amp;issue=06">http://www.sys-con.com/java/archivesa.cfm?volume=06&amp;issue=06</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Using Ant and Weblogic EJBs"></a>
+        Using Ant and Weblogic EJBs
+      </h4>
+                        <p>This article describes how to use Ant to create Weblogic EJBs, and
+        some workarounds for issues you may encounter.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Jesse E. Tilly
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.onjava.com/pub/a/onjava/2001/06/25/antejb.html">http://www.onjava.com/pub/a/onjava/2001/06/25/antejb.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Using JavaScript with Ant"></a>
+        Using JavaScript with Ant
+      </h4>
+                        <p>A tutorial about using JavaScript and XSLT with Ant.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Dylan Schiemann
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.sitepen.com/ant/javascript.html">http://www.sitepen.com/ant/javascript.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Building with Ant"></a>
+        Building with Ant
+      </h4>
+                        <p>Series of articles that describe a framework for web
+        application development based on Ant and JUnit.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:alexc@purpletech.com">Alex Chaffee</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Introduction: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12065_989631,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12065_989631,00.html</a><br />
+                Directory Structure: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12082_994991,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12082_994991,00.html</a><br />
+                Deployment and Distribution: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12077_998241,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12077_998241,00.html</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Developing with JAXB and Ant"></a>
+        Developing with JAXB and Ant
+      </h4>
+                        <p>Series of articles that shows how to use Ant together with
+        the Java API for XML Binding (JAXB).</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Joseph Shelby
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.onjava.com/pub/a/onjava/2002/03/06/jaxant1.html">http://www.onjava.com/pub/a/onjava/2002/03/06/jaxant1.html</a><br />
+                <a href="http://www.onjava.com/pub/a/onjava/2002/03/13/jaxbant2.html">http://www.onjava.com/pub/a/onjava/2002/03/13/jaxbant2.html</a>
+      </td>
+      </tr>
+          </table>
+                                            <h3 class="section">
+      <a name="Presentations"></a>
+      Presentations
+    </h3>
+                              <h4 class="subsection">
+        <a name="Ant Build Tool"></a>
+        Ant Build Tool
+      </h4>
+                        <p>A PowerPoint presentation on Ant 1.2.  It provides a basic overview
+        of Ant's capabilities.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="mailto:chanezon@netscape.com">Patrick Chanezon</a>
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://people.netscape.com/chanezon/tech/ant/ant_preso.ppt">http://people.netscape.com/chanezon/tech/ant/ant_preso.ppt</a>
+      </td>
+      </tr>
+          </table>
+                                                          <h4 class="subsection">
+        <a name="Ant"></a>
+        Ant
+      </h4>
+                        <p>A detailed Ant 1.3 PowerPoint presentation, made at the St. Louis Java Users Group
+        meeting in March 2001.  Includes a detailed build file and basic
+        descriptions of all the built in and optional tasks.  Updated for Ant 1.4 in October 2001.
+        Available in PDF format now.</p>
+                                      <table class="externals" cellspacing="1" cellpadding="4">
+              <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          Author:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          Mark Volkmann
+      </td>
+      </tr>
+                  <tr>
+                      <th colspan="1" rowspan="1"
+      valign="top" align="left">
+          URL:
+      </th>
+                          <td colspan="1" rowspan="1"
+      valign="top" align="left">
+          <a href="http://www.ociweb.com/jnb/files/Ant.pdf">http://www.ociweb.com/jnb/files/Ant.pdf</a>
+      </td>
+      </tr>
+          </table>
+                                    
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/slides/extending_ant.odp b/trunk/docs/slides/extending_ant.odp
new file mode 100644
index 0000000..278ba7c
--- /dev/null
+++ b/trunk/docs/slides/extending_ant.odp
Binary files differ
diff --git a/trunk/docs/srcdownload.cgi b/trunk/docs/srcdownload.cgi
new file mode 100755
index 0000000..4324f76
--- /dev/null
+++ b/trunk/docs/srcdownload.cgi
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Wrapper script around mirrors.cgi script
+# (we must change to that directory in order for python to pick up the
+#  python includes correctly)
+cd /www/www.apache.org/dyn/mirrors
+/www/www.apache.org/dyn/mirrors/mirrors.cgi $*
diff --git a/trunk/docs/srcdownload.html b/trunk/docs/srcdownload.html
new file mode 100644
index 0000000..08cd6cb
--- /dev/null
+++ b/trunk/docs/srcdownload.html
@@ -0,0 +1,341 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - Source Distributions</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+        </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                              <span class="sel">Source Distributions</span>
+                              </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">Source Distributions</h1>
+            <h3 class="section">
+      <a name="Downloading Ant"></a>
+      Downloading Ant
+    </h3>
+                        <p>Use the links below to download a source distribution of Ant from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>.</p>
+                                <p>Ant is distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+                                <p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/">mirror</a>.</p>
+                        <h3 class="section">
+      <a name="Mirror"></a>
+      Mirror
+    </h3>
+                        <p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+                                <form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+                        <h3 class="section">
+      <a name="Current Release of Ant"></a>
+      Current Release of Ant
+    </h3>
+                        <p>Currently, Apache Ant 1.7.0 is the best available version, see the
+<a href="[preferred]/ant/README.html">release notes</a>.</p>
+                                <div class="warning">
+<div class="label">Note</div>
+<div class="content">Ant 1.7.0 has been released on 19-Dec-2006 and
+may not be available on all mirrors for a few days.</div>
+</div>
+                                <br />
+                                <div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+                                <ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.zip">apache-ant-1.7.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.tar.gz">apache-ant-1.7.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.tar.bz2">apache-ant-1.7.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+                        <h3 class="section">
+      <a name="Old Ant Releases"></a>
+      Old Ant Releases
+    </h3>
+                        <p>Older releases of Ant can be found <a href="http://archive.apache.org/dist/ant/source/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a href="[location]#Current Release of Ant">latest</a> release.</p>
+                        <h3 class="section">
+      <a name="Verify Releases"></a>
+      Verify Releases
+    </h3>
+                        <p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+                                <p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+                                <p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-1.7.0-src.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-1.7.0-src.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-1.7.0-src.tar.gz.asc
+</code></p>
+                                <p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a href="http://www.fourmilab.ch/md5/">here</a>, <a href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+                                <p>We highly recommend to verify the PGP signature, though.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/svn.html b/trunk/docs/svn.html
new file mode 100644
index 0000000..9c96ea6
--- /dev/null
+++ b/trunk/docs/svn.html
@@ -0,0 +1,253 @@
+
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+        <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>Apache Ant - SVN Repositories</title>
+        <link type="text/css" href="./page.css" rel="stylesheet">
+          <meta name="author" content="Antoine Levy-Lambert">
+  <meta name="email" content="">
+      </head>
+
+    <body>
+      <p class="navpath">
+        <script src="./breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="./images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="./images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="#4C6C8F">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="./images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="./images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="./images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+                  <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+                                  <td width="8"><img alt="" height="5" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-left.gif"></td><td valign="middle" bgcolor="#4C6C8F"><font color="#ffffff" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="#4C6C8F"><img height="5" width="5" alt="" src="./images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                                    <td width="5"><img alt="" height="8" width="8" src="./images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-left.gif"></td><td valign="middle" bgcolor="#B2C4E0"><a href="./projects/index.html"><font size="2" face="Arial, Helvetica, Sans-serif">Projects</font></a></td><td valign="top" width="5" bgcolor="#B2C4E0"><img height="5" width="5" alt="" src="./images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+                            </tr>
+              </table>
+            </div>
+
+      <div class="bluebar"></div>
+                    
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+              <li class="menuheader">Apache Ant
+          <ul>
+                            <li>
+                                    <a href="./index.html">Welcome</a>
+                                </li>
+                            <li>
+                                    <a href="./license.html">License</a>
+                                </li>
+                            <li>
+                                    <a href="./antnews.html">News</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Documentation
+          <ul>
+                            <li>
+                                    <a href="./manual/index.html">Manual</a>
+                                </li>
+                            <li>
+                                    <a href="./projects.html">Related Projects</a>
+                                </li>
+                            <li>
+                                    <a href="./external.html">External Tools and Tasks</a>
+                                </li>
+                            <li>
+                                    <a href="./resources.html">Resources</a>
+                                </li>
+                            <li>
+                                    <a href="./faq.html">Frequently Asked Questions</a>
+                                </li>
+                            <li>
+                                    <a href="http://wiki.apache.org/ant/FrontPage">Wiki</a>
+                                </li>
+                            <li>
+                                    <a href="./problems.html">Having Problems?</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Download
+          <ul>
+                            <li>
+                                    <a href="http://ant.apache.org/bindownload.cgi">Binary Distributions</a>
+                                </li>
+                            <li>
+                                    <a href="http://ant.apache.org/srcdownload.cgi">Source Distributions</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Contributing
+          <ul>
+                            <li>
+                                    <a href="./mail.html">Mailing Lists</a>
+                                </li>
+                            <li>
+                                    <a href="./svn.html">Subversion Repositories</a>
+                                </li>
+                            <li>
+                                    <a href="./nightlies.html">Nightly Builds</a>
+                                </li>
+                            <li>
+                                    <a href="./bugs.html">Bug Database</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Sponsorship
+          <ul>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/thanks.html">Thanks</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
+                                </li>
+                            <li>
+                                    <a href="http://www.apache.org/foundation/contributing.html">Donations</a>
+                                </li>
+                      </ul>
+        </li>
+              <li class="menuheader">Project Management
+          <ul>
+                            <li>
+                                    <a href="./contributors.html">Contributors</a>
+                                </li>
+                            <li>
+                                    <a href="./mission.html">Apache Ant Mission</a>
+                                </li>
+                            <li>
+                                    <a href="./bylaws.html">Project Bylaws</a>
+                                </li>
+                            <li>
+                                    <a href="./legal.html">Legal</a>
+                                </li>
+                      </ul>
+        </li>
+            </ul>
+    </div>
+    <center>
+    <!--#include virtual="/ads/buttonbar.html" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="./images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="./images/menu-right.gif">
+  </div>
+      <div class="lightbluebar">&nbsp;</div>
+  <div class="main">
+  <div class="content">
+    <h1 class="title">SVN Repositories</h1>
+            <h3 class="section">
+      <a name="Access the Source Tree (Subversion)"></a>
+      Access the Source Tree (Subversion)
+    </h3>
+                        <p>Anyone can checkout source code from our public Subversion repository. To do so,
+         simply use the following command (if you are using a GUI client, configure it
+         appropriately):</p>
+                                <pre class="code">
+svn co http://svn.apache.org/repos/asf/ant/[project]/trunk/ ant-[project]</pre>
+                                <p>Modules available for access are:</p>
+                                <ul>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/core/trunk/">ant</a> - The "main" Ant module.<br />
+         http://svn.apache.org/repos/asf/ant/core/trunk/
+        </li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/">antunit</a> Test framework for Ant.<br />
+            http://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/">Dotnet antlib</a> Contains Nant, Nunit, ...<br />
+            http://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/">svn antlib</a> Contains tasks to interact with Subversion repositories.<br />
+            http://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/">sandbox</a> - New developments. Contains currently gendoc.<br />
+            http://svn.apache.org/repos/asf/ant/sandbox/
+        </li>
+      </ul>
+                                <p>If you are not familiar with Subversion, <a href="http://jakarta.apache.org/site/cvsindex.html">Jakarta's
+      source repositories page</a> may hold many helpful hints.</p>
+                                <p>Nightly snapshots of the SVN tree are available at
+        <a href="http://svn.apache.org/snapshots/ant/">http://svn.apache.org/snapshots/ant/</a>.</p>
+                                <p>A nice view of the source history is available through
+      <a href="http://fisheye3.cenqua.com/browse/ant/">Cenqua's Fisheye instance</a>.</p>
+                
+    </div>
+  </div>
+
+        <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/trunk/docs/webtest/testkeystore b/trunk/docs/webtest/testkeystore
new file mode 100644
index 0000000..2fd22c9
--- /dev/null
+++ b/trunk/docs/webtest/testkeystore
Binary files differ
diff --git a/trunk/fetch.xml b/trunk/fetch.xml
new file mode 100644
index 0000000..b3417fe
--- /dev/null
+++ b/trunk/fetch.xml
@@ -0,0 +1,233 @@
+<?xml version="1.0"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+  =======================================================================
+    Build file to fetch optional libraries for Apache Ant
+  =======================================================================
+-->
+<project name="fetch" default="all" basedir=".">
+
+<description>
+  This build file downloads JAR files that optional Ant tasks use,
+  and installs them in a location that is accessible the next time Ant runs.
+
+  You can choose three locations, by going -Ddest=LOCATION on the command line
+  -Ddest=user     user lib dir  ${user.home}/.ant/lib
+  -Ddest=system   ant lib dir   ${ant.home}/lib --Default--
+  -Ddest=optional optional dir  ${ant.home}/lib/optional  (for Ant developers)
+
+  You may also need to set proxy settings. On Java1.5, Ant tries to get
+  this from the OS, unless you use the -noproxy option.
+
+  Proxies can be configured manually setting the JVM proxy values in the
+  ANT_OPTS environment variable.
+
+  For example, to set the proxy up in the tcsh shell, the command would be
+  something like:
+
+  For csh/tcsh:
+    setenv ANT_OPTS "-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+  For bash:
+    export ANT_OPTS="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+  For Windows, set the environment variable in the appropriate dialog box
+  and open a new console. or, by hand
+    set ANT_OPTS = -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080
+</description>
+
+  <!-- Give user a chance to override without editing this file
+       (and without typing -D each time it compiles it) -->
+  <property file="${user.home}/.ant/ant.properties"/>
+  <property name="lib.dir" location="lib" />
+  <property name="optional.dir" location="${lib.dir}/optional" />
+  <property name="userlib.dir" location="${user.home}/.ant/lib" />
+
+  <!-- load in our properties table -->
+  <property file="${lib.dir}/libraries.properties"/>
+
+  <import file="get-m2.xml" />
+
+  <target name="pick-dest">
+    <property name="dest" value="system" />
+    <condition property="dest.dir"
+      value="${lib.dir}">
+      <equals arg1="${dest}" arg2="system" />
+    </condition>
+    <condition property="dest.dir"
+      value="${optional.dir}">
+      <equals arg1="${dest}" arg2="optional" />
+    </condition>
+    <condition property="dest.dir"
+      value="${userlib.dir}">
+      <equals arg1="${dest}" arg2="user" />
+    </condition>
+    <fail unless="dest.dir">Unknown destination : ${dest}</fail>
+    <echo>Downloading to ${dest.dir}</echo>
+    <property name="m2.dest.dir" value="${dest.dir}" />
+  </target>
+
+
+  <target name="macros" depends="pick-dest,get-m2"
+    xmlns:artifact="antlib:org.apache.maven.artifact.ant">
+
+    <macrodef name="f2">
+      <attribute name="project" />
+      <attribute name="archive" default="@{project}"/>
+      <sequential>
+        <fail>
+        Unknown archive @{archive} -no property @{archive}.version defined.
+          <condition>
+            <not>
+            <isset property="@{archive}.version"/>
+            </not>
+          </condition>
+        </fail>
+        <artifact:dependencies pathID="@{archive}.path">
+          <dependency groupID="@{project}"
+            artifactID="@{archive}"
+            version="${@{archive}.version}"/>
+        </artifact:dependencies>
+        <!-- now we are left with the problem of getting the files
+             into our directory -->
+        <copypath destdir="${dest.dir}" pathref="@{archive}.path">
+          <flattenmapper/>
+        </copypath>
+      </sequential>
+    </macrodef>
+  </target>
+
+
+
+  <!-- any init stuff -->
+  <target name="init" depends="macros" />
+
+
+  <target name="diag" depends="init">
+    <echoproperties />
+  </target>
+
+  <target name="logging"
+    description="load logging libraries"
+    depends="init">
+    <f2 project="log4j" />
+    <f2 project="commons-logging" archive="commons-logging-api" />
+  </target>
+
+  <target name="junit"
+    description="load junit libraries"
+    depends="init">
+    <f2 project="junit" />
+  </target>
+
+  <target name="xml"
+    description="load full XML libraries (xalan, resolver)"
+    depends="init">
+    <f2 project="xalan" />
+    <f2 project="xml-resolver" />
+  </target>
+
+  <!--
+   This is not used as
+   we like to get the more recent artifacts than are in the repo at the time of writing (2006-12-21)
+   -->
+
+  <target name="xerces"
+      description="load an updated version of Xerces"
+      depends="init">
+    <f2 project="xerces" archive="xercesImpl"/>
+    <f2 project="xerces" archive="xml-apis" />
+  </target>
+
+  <target name="networking"
+    description="load networking libraries (commons-net; jsch)"
+    depends="init">
+    <f2 project="commons-net" />
+    <f2 project="com.jcraft" archive="jsch"/>
+  </target>
+
+  <target name="regexp"
+    description="load regexp libraries"
+    depends="init">
+    <f2 project="regexp" />
+    <f2 project="oro" />
+  </target>
+
+  <target name="antlr"
+    description="load antlr libraries"
+    depends="init">
+    <f2 project="antlr" />
+  </target>
+
+  <target name="bcel"
+    description="load bcel libraries"
+    depends="init">
+    <f2 project="bcel" />
+  </target>
+
+  <target name="jdepend"
+    description="load jdepend libraries"
+    depends="init">
+    <f2 project="jdepend" />
+  </target>
+
+  <target name="bsf"
+    description="load bsf libraries"
+    depends="init">
+    <f2 project="bsf" />
+  </target>
+
+  <target name="jruby"
+          description="load jruby"
+          depends="bsf">
+    <f2 project="org.jruby" archive="jruby"/>
+  </target>
+
+  <target name="beanshell"
+          description="load beanshell support"
+          depends="bsf">
+    <f2 project="org.beanshell" archive="bsh"/>
+    <f2 project="org.beanshell" archive="bsh-core"/>
+  </target>
+
+  <target name="jython"
+          description="load jython"
+          depends="bsf">
+    <f2 project="jython" archive="jython"/>
+  </target>
+
+  <target name="rhino"
+          description="load rhino"
+          depends="bsf">
+    <f2 project="rhino" archive="js"/>
+  </target>
+
+  <target name="script"
+          description="load script languages"
+          depends="bsf,jruby,jython,beanshell,rhino"/>
+
+  <target name="debugging"
+    description="internal ant debugging"
+    depends="init">
+    <f2 project="which" />
+  </target>
+
+  <target name="all"
+    description="load all the libraries"
+    depends="logging,junit,xml,networking,regexp,antlr,bcel,jdepend,bsf,debugging,script" />
+
+</project>
diff --git a/trunk/get-m2.xml b/trunk/get-m2.xml
new file mode 100644
index 0000000..4111e81
--- /dev/null
+++ b/trunk/get-m2.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+  =======================================================================
+   Build file to fetch maven2 tasks; extracted from (Ant's) fetch.xml
+  =======================================================================
+-->
+<project name="get-m2" default="get-m2" basedir=".">
+
+<description>
+  This build file downloads the Maven2 Ant tasks,
+  and installs them in the location specified by the m2.dest.dir property.
+
+  You may need to set proxy settings. On Java1.5, Ant tries to get
+  this from the OS, unless you use the -noproxy option.
+
+  Proxies can be configured manually setting the JVM proxy values in the
+  ANT_OPTS environment variable.
+
+  For example, to set the proxy up in the tcsh shell, the command would be
+  something like:
+
+  For csh/tcsh:
+    setenv ANT_OPTS "-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+  For bash:
+    export ANT_OPTS="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"
+  For Windows, set the environment variable in the appropriate dialog box
+  and open a new console. or, by hand
+    set ANT_OPTS = -Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080
+</description>
+
+  <property file="get-m2.properties" />
+
+  <property name="m2.antlib.resource"
+            value="org/apache/maven/artifact/ant/antlib.xml" />
+
+  <property name="m2.antlib.uri"
+            value="antlib:org.apache.maven.artifact.ant" />
+
+  <macrodef name="require">
+    <attribute name="property" />
+    <sequential>
+      <fail unless="@{property}">$${@{property}} not specified</fail>
+    </sequential>
+  </macrodef>
+
+  <target name="probe-m2">
+    <require property="m2.dest.dir" />
+    <require property="m2.jar.name" />
+
+    <!-- Look for M2 ant tasks in our classpath-->
+    <property name="m2.artifact" location="${m2.dest.dir}/${m2.jar.name}" />
+    <available property="m2.antlib.found" resource="${m2.antlib.resource}" />
+    <condition property="m2.antlib.typefound">
+      <typefound name="${m2.antlib.uri}:artifact" />
+    </condition>
+    <available property="m2.artifact.found" file="${m2.artifact}" type="file" />
+  </target>
+
+  <target name="download-m2" depends="probe-m2" unless="m2.artifact.found">
+    <require property="m2.antlib.url" />
+    <echo>Downloading to ${m2.dest.dir}</echo>
+
+    <mkdir dir="${m2.dest.dir}" />
+    <!-- fetch M2 ant tasks into our repository, if it is not there-->
+    <get src="${m2.antlib.url}"
+      dest="${m2.artifact}"
+      verbose="true"
+      usetimestamp="false" />
+  </target>
+
+  <target name="dont-validate-m2-checksum" depends="probe-m2"
+          if="m2.artifact.found">
+    <property name="checksum.equal" value="true" />
+  </target>
+
+  <target name="validate-m2-checksum"
+          depends="download-m2,dont-validate-m2-checksum"
+          if="m2.sha1.checksum" unless="m2.artifact.found">
+    <checksum file="${m2.artifact}"
+        algorithm="SHA"
+        property="${m2.sha1.checksum}"
+        verifyProperty="checksum.equal" />
+  </target>
+
+  <target name="checksum-mismatch" depends="validate-m2-checksum"
+          if="m2.sha1.checksum" unless="checksum.equal">
+    <delete file="${m2.artifact}" />
+    <fail>
+      Failed to verify the downloaded file ${m2.antlib.url}" against the checksum
+      coded into libraries.properties.
+      The local copy has been deleted, for security reasons
+    </fail>
+  </target>
+
+  <target name="checksum-match" depends="checksum-mismatch"
+          unless="m2.antlib.found">
+    <taskdef classpath="${m2.artifact}" resource="${m2.antlib.resource}"
+             uri="${m2.antlib.uri}" />
+  </target>
+
+  <target name="get-m2" depends="checksum-match"
+      description="Download the Maven2 Ant tasks" />
+
+</project>
diff --git a/trunk/lib/README b/trunk/lib/README
new file mode 100644
index 0000000..7ebe030
--- /dev/null
+++ b/trunk/lib/README
@@ -0,0 +1,16 @@
+Please refer to the Ant manual under Installing Ant / Library
+Dependencies for a list of the jar requirements for various optional
+tasks and features.
+
+This directory contains xercesImpl.jar from the 2.9.0 release of
+Apache Xerces.  For more information or newer releases see
+<http://xerces.apache.org/xerces2-j/>.  Xerces is provided under the
+same license as Apache Ant itself, see the file LICENSE.txt.  For
+additional Xerces specific notes see the file NOTICE.xerces.
+
+It also contains xml-apis.jar, an Apache-controlled collection of
+standard classes from the 1.3.04 release of the Apache XML-Commons
+release.  For more information or newer releases see
+<http://xml.apache.org/commons/>.  See the files LICENSE.dom and
+LICENSE.sax for the terms of distribution.
+
diff --git a/trunk/lib/libraries.properties b/trunk/lib/libraries.properties
new file mode 100644
index 0000000..651cc47
--- /dev/null
+++ b/trunk/lib/libraries.properties
@@ -0,0 +1,62 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#this file declares the libraries for use in 
+#a given release of the components
+
+#if you change this, change the checksum to match
+m2.version=2.0.4
+m2.url=http://ibiblio.org/maven2/
+m2.artifact-name=maven-artifact-ant
+m2.jar.name=${m2.artifact-name}-${m2.version}-dep.jar
+#this is the URL of the antlib library, that is pulled down for everything else.
+m2.antlib.url=${m2.url}/org/apache/maven/${m2.artifact-name}/${m2.version}/${m2.jar.name}
+#this is the sha1 checksum of the artifact
+m2.sha1.checksum=4e7ddfdb91600e9b59bb965ff8eef2f06015df50
+
+
+#versions of different libraries. Please keep in alphabetical order, except
+#when a specific dependency forces them to be out-of-order
+antlr.version=2.7.2
+bcel.version=5.1
+bsf.version=2.4.0
+bsh.version=2.0b4
+bsh-core.version=${bsh.version}
+commons-net.version=1.4.0
+commons-logging.version=1.0.4
+commons-logging-api.version=${commons-logging.version}
+jdepend.version=2.7
+jruby.version=0.8.3
+junit.version=3.8.2
+jsch.version=0.1.29
+jython.version=2.1
+log4j.version=1.2.13
+#js is the javascript implementation of the rhino project
+js.version=1.6R3
+oro.version=2.0.8
+regexp.version=1.3
+which.version=1.0
+xerces.version=2.9.0
+xercesImpl.version=${xerces.version}
+#should be in sync w/ xerces, but not in the maven repository
+#xmlParserAPIs.version=${xerces.version}
+#xmlParserAPIs.version=2.6.1
+xml-apis.version=1.3.04
+xalan.version=2.7.0
+xml-resolver.version=1.1
+
+#paired
+jacl.version=1.2.6
+tcljava.version=${jacl.version}
diff --git a/trunk/lib/optional/LICENSE.junit.html b/trunk/lib/optional/LICENSE.junit.html
new file mode 100644
index 0000000..5d7e1b6
--- /dev/null
+++ b/trunk/lib/optional/LICENSE.junit.html
@@ -0,0 +1,259 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html><head><title>Common Public License - v 1.0</title>

+

+

+

+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"></head><body bgcolor="#ffffff" vlink="#800000">

+

+

+<p align="center"><b>Common Public License - v 1.0</b>

+</p><p><b></b><font size="3"></font>

+</p><p><font size="3"></font><font size="2">THE ACCOMPANYING PROGRAM IS

+PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE ("AGREEMENT").

+ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES

+RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</font>

+</p><p><font size="2"></font>

+</p><p><font size="2"><b>1.  DEFINITIONS</b></font>

+</p><p><font size="2">"Contribution" means:</font>

+

+</p><ul><font size="2">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<br clear="left">

+b) in the case of each subsequent Contributor:</font></ul>

+

+

+<ul><font size="2">i)	 	changes to the Program, and</font></ul>

+

+

+<ul><font size="2">ii)		additions to the Program;</font></ul>

+

+

+<ul><font size="2">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </font><font size="2">A

+Contribution 'originates' from a Contributor if it was added to the

+Program by such Contributor itself or anyone acting on such

+Contributor's behalf. </font><font size="2">Contributions do not

+include additions to the Program which: (i) are separate modules of

+software distributed in conjunction with the Program under their own

+license agreement, and (ii) are not derivative works of the Program. </font></ul>

+

+<p><font size="2"></font>

+</p><p><font size="2">"Contributor" means any person or entity that distributes the Program.</font>

+</p><p><font size="2"></font><font size="2"></font>

+</p><p><font size="2">"Licensed Patents " mean patent claims licensable

+by a Contributor which are necessarily infringed by the use or sale of

+its Contribution alone or when combined with the Program. </font>

+</p><p><font size="2"></font><font size="2"></font>

+</p><p><font size="2"></font><font size="2">"Program" means the Contributions distributed in accordance with this Agreement.</font>

+</p><p><font size="2"></font>

+</p><p><font size="2">"Recipient" means anyone who receives the Program under this Agreement, including all Contributors.</font>

+</p><p><font size="2"><b></b></font>

+</p><p><font size="2"><b>2.  GRANT OF RIGHTS</b></font>

+

+</p><ul><font size="2"></font><font size="2">a)	</font><font size="2">Subject to the terms of this Agreement, each Contributor hereby grants</font><font size="2"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</font><font color="#ff0000" size="2"> </font><font size="2">reproduce,

+prepare derivative works of, publicly display, publicly perform,

+distribute and sublicense the Contribution of such Contributor, if any,

+and such derivative works, in source code and object code form.</font></ul>

+

+

+<ul><font size="2"></font></ul>

+

+

+<ul><font size="2"></font><font size="2">b) 	Subject to the terms of this Agreement, each Contributor hereby grants </font><font size="2">Recipient a non-exclusive, worldwide,</font><font color="#008000" size="2"> </font><font size="2">royalty-free

+patent license under Licensed Patents to make, use, sell, offer to

+sell, import and otherwise transfer the Contribution of such

+Contributor, if any, in source code and object code form. This patent

+license shall apply to the combination of the Contribution and the

+Program if, at the time the Contribution is added by the Contributor,

+such addition of the Contribution causes such combination to be covered

+by the Licensed Patents. The patent license shall not apply to any

+other combinations which include the Contribution. No hardware per se

+is licensed hereunder. </font></ul>

+

+

+<ul><font size="2"></font></ul>

+

+

+<ul><font size="2">c) Recipient understands that although each

+Contributor grants the licenses to its Contributions set forth herein,

+no assurances are provided by any Contributor that the Program does not

+infringe the patent or other intellectual property rights of any other

+entity. Each Contributor disclaims any liability to Recipient for

+claims brought by any other entity based on infringement of

+intellectual property rights or otherwise. As a condition to exercising

+the rights and licenses granted hereunder, each Recipient hereby

+assumes sole responsibility to secure any other intellectual property

+rights needed, if any. For example, if a third party patent license is

+required to allow Recipient to distribute the Program, it is

+Recipient's responsibility to acquire that license before distributing

+the Program.</font></ul>

+

+

+<ul><font size="2"></font></ul>

+

+

+<ul><font size="2">d) Each Contributor represents that to its knowledge

+it has sufficient copyright rights in its Contribution, if any, to

+grant the copyright license set forth in this Agreement. </font></ul>

+

+

+<ul><font size="2"></font></ul>

+

+<p><font size="2"><b>3.  REQUIREMENTS</b></font>

+</p><p><font size="2"><b></b>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</font>

+

+</p><ul><font size="2">a)	it complies with the terms and conditions of this Agreement; and</font></ul>

+

+

+<ul><font size="2">b)	its license agreement:</font></ul>

+

+

+<ul><font size="2">i)	effectively disclaims</font><font size="2"> on

+behalf of all Contributors all warranties and conditions, express and

+implied, including warranties or conditions of title and

+non-infringement, and implied warranties or conditions of

+merchantability and fitness for a particular purpose; </font></ul>

+

+

+<ul><font size="2">ii) effectively excludes on behalf of all

+Contributors all liability for damages, including direct, indirect,

+special, incidental and consequential damages, such as lost profits; </font></ul>

+

+

+<ul><font size="2">iii)</font><font size="2"> states that any

+provisions which differ from this Agreement are offered by that

+Contributor alone and not by any other party; and</font></ul>

+

+

+<ul><font size="2">iv) states that source code for the Program is

+available from such Contributor, and informs licensees how to obtain it

+in a reasonable manner on or through a medium customarily used for

+software exchange.</font><font color="#0000ff" size="2"> </font><font color="#ff0000" size="2"></font></ul>

+

+

+<ul><font color="#ff0000" size="2"></font><font size="2"></font></ul>

+

+<p><font size="2">When the Program is made available in source code form:</font>

+

+</p><ul><font size="2">a)	it must be made available under this Agreement; and </font></ul>

+

+

+<ul><font size="2">b)	a copy of this Agreement must be included with each copy of the Program.  </font></ul>

+

+<p><font size="2"></font><font color="#0000ff" size="2"><strike></strike></font>

+</p><p><font color="#0000ff" size="2"><strike></strike></font><font size="2">Contributors may not remove or alter any copyright notices contained within the Program.  </font>

+</p><p><font size="2"></font>

+</p><p><font size="2">Each Contributor must identify itself as the

+originator of its Contribution, if any, in a manner that reasonably

+allows subsequent Recipients to identify the originator of the

+Contribution. </font>

+</p><p><font size="2"></font>

+</p><p><font size="2"><b>4.  COMMERCIAL DISTRIBUTION</b></font>

+</p><p><font size="2">Commercial distributors of software may accept

+certain responsibilities with respect to end users, business partners

+and the like. While this license is intended to facilitate the

+commercial use of the Program, the Contributor who includes the Program

+in a commercial product offering should do so in a manner which does

+not create potential liability for other Contributors. Therefore, if a

+Contributor includes the Program in a commercial product offering, such

+Contributor ("Commercial Contributor") hereby agrees to defend and

+indemnify every other Contributor ("Indemnified Contributor") against

+any losses, damages and costs (collectively "Losses") arising from

+claims, lawsuits and other legal actions brought by a third party

+against the Indemnified Contributor to the extent caused by the acts or

+omissions of such Commercial Contributor in connection with its

+distribution of the Program in a commercial product offering. The

+obligations in this section do not apply to any claims or Losses

+relating to any actual or alleged intellectual property infringement.

+In order to qualify, an Indemnified Contributor must: a) promptly

+notify the Commercial Contributor in writing of such claim, and b)

+allow the Commercial Contributor to control, and cooperate with the

+Commercial Contributor in, the defense and any related settlement

+negotiations. The Indemnified Contributor may participate in any such

+claim at its own expense.</font>

+</p><p><font size="2"></font>

+</p><p><font size="2">For example, a Contributor might include the

+Program in a commercial product offering, Product X. That Contributor

+is then a Commercial Contributor. If that Commercial Contributor then

+makes performance claims, or offers warranties related to Product X,

+those performance claims and warranties are such Commercial

+Contributor's responsibility alone. Under this section, the Commercial

+Contributor would have to defend claims against the other Contributors

+related to those performance claims and warranties, and if a court

+requires any other Contributor to pay any damages as a result, the

+Commercial Contributor must pay those damages.</font>

+</p><p><font size="2"></font><font color="#0000ff" size="2"></font>

+</p><p><font color="#0000ff" size="2"></font><font size="2"><b>5.  NO WARRANTY</b></font>

+</p><p><font size="2">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT,

+THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR

+CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT

+LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,

+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</font><font size="2"> solely responsible for determining the appropriateness of using and distributing </font><font size="2">the Program</font><font size="2"> and assumes all risks associated with its exercise of rights under this Agreement</font><font size="2">,

+including but not limited to the risks and costs of program errors,

+compliance with applicable laws, damage to or loss of data, </font><font size="2">programs or equipment, and unavailability or interruption of operations</font><font size="2">.  </font><font size="2"></font>

+</p><p><font size="2"></font>

+</p><p><font size="2"></font><font size="2"><b>6.  DISCLAIMER OF LIABILITY</b></font>

+</p><p><font size="2"></font><font size="2">EXCEPT AS EXPRESSLY SET

+FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL

+HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,

+EXEMPLARY, OR CONSEQUENTIAL DAMAGES </font><font size="2">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</font><font size="2">

+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 OR DISTRIBUTION OF THE PROGRAM OR THE

+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE

+POSSIBILITY OF SUCH DAMAGES.</font>

+</p><p><font size="2"></font><font size="2"></font>

+</p><p><font size="2"><b>7.  GENERAL</b></font>

+</p><p><font size="2"></font><font size="2">If any provision of this

+Agreement is invalid or unenforceable under applicable law, it shall

+not affect the validity or enforceability of the remainder of the terms

+of this Agreement, and without further action by the parties hereto,

+such provision shall be reformed to the minimum extent necessary to

+make such provision valid and enforceable.</font>

+</p><p><font size="2"></font>

+</p><p><font size="2">If Recipient institutes patent litigation against

+a Contributor with respect to a patent applicable to software

+(including a cross-claim or counterclaim in a lawsuit), then any patent

+licenses granted by that Contributor to such Recipient under this

+Agreement shall terminate as of the date such litigation is filed. In

+addition, if Recipient institutes patent litigation against any entity

+(including a cross-claim or counterclaim in a lawsuit) alleging that

+the Program itself (excluding combinations of the Program with other

+software or hardware) infringes such Recipient's patent(s), then such

+Recipient's rights granted under Section 2(b) shall terminate as of the

+date such litigation is filed. </font><font size="2"></font>

+</p><p><font size="2"></font>

+</p><p><font size="2">All Recipient's rights under this Agreement shall

+terminate if it fails to comply with any of the material terms or

+conditions of this Agreement and does not cure such failure in a

+reasonable period of time after becoming aware of such noncompliance.

+If all Recipient's rights under this Agreement terminate, Recipient

+agrees to cease use and distribution of the Program as soon as

+reasonably practicable. However, Recipient's obligations under this

+Agreement and any licenses granted by Recipient relating to the Program

+shall continue and survive. </font><font size="2"></font>

+</p><p><font size="2"></font>

+</p><p><font size="2"></font><font size="2">Everyone is permitted to

+copy and distribute copies of this Agreement, but in order to avoid

+inconsistency the Agreement is copyrighted and may only be modified in

+the following manner. The Agreement Steward reserves the right to </font><font size="2">publish new versions (including revisions) of this Agreement from time to </font><font size="2">time.

+No one other than the Agreement Steward has the right to modify this

+Agreement. IBM is the initial Agreement Steward. IBM may assign the

+responsibility to serve as the Agreement Steward to a suitable separate

+entity. </font><font size="2">Each new version of the Agreement will

+be given a distinguishing version number. The Program (including

+Contributions) may always be distributed subject to the version of the

+Agreement under which it was received. In addition, after a new version

+of the Agreement is published, Contributor may elect to distribute the

+Program (including its Contributions) under the new </font><font size="2">version.  </font><font size="2">Except

+as expressly stated in Sections 2(a) and 2(b) above, Recipient receives

+no rights or licenses to the intellectual property of any Contributor

+under this Agreement, whether expressly, </font><font size="2">by implication, estoppel or otherwise</font><font size="2">.</font><font size="2">  All rights in the Program not expressly granted under this Agreement are reserved.</font>

+</p><p><font size="2"></font>

+</p><p><font size="2">This Agreement is governed by the laws of the

+State of New York and the intellectual property laws of the United

+States of America. No party to this Agreement will bring a legal action

+under this Agreement more than one year after the cause of action

+arose. Each party waives its rights to a jury trial in any resulting

+litigation.</font>

+</p><p><font size="2"></font><font size="2"></font>

+</p><p><font size="2"></font>

+

+</p></body></html>
\ No newline at end of file
diff --git a/trunk/lib/optional/README b/trunk/lib/optional/README
new file mode 100644
index 0000000..eed1267
--- /dev/null
+++ b/trunk/lib/optional/README
@@ -0,0 +1,3 @@
+The file junit-3.8.2.jar is version 3.8.2 of JUnit, see the file LICENSE.junit
+for the terms of distribution.  For more information about JUnit or
+the latest release, see <http://www.junit.org/>.
diff --git a/trunk/lib/optional/ant-antunit-1.0.jar b/trunk/lib/optional/ant-antunit-1.0.jar
new file mode 100644
index 0000000..d8e2fba
--- /dev/null
+++ b/trunk/lib/optional/ant-antunit-1.0.jar
Binary files differ
diff --git a/trunk/lib/optional/junit-3.8.2.jar b/trunk/lib/optional/junit-3.8.2.jar
new file mode 100644
index 0000000..c8f711d
--- /dev/null
+++ b/trunk/lib/optional/junit-3.8.2.jar
Binary files differ
diff --git a/trunk/lib/xercesImpl.jar b/trunk/lib/xercesImpl.jar
new file mode 100644
index 0000000..e0a4c2e
--- /dev/null
+++ b/trunk/lib/xercesImpl.jar
Binary files differ
diff --git a/trunk/lib/xml-apis.jar b/trunk/lib/xml-apis.jar
new file mode 100644
index 0000000..d42c0ea
--- /dev/null
+++ b/trunk/lib/xml-apis.jar
Binary files differ
diff --git a/trunk/patch.xml b/trunk/patch.xml
new file mode 100644
index 0000000..7b7f8be
--- /dev/null
+++ b/trunk/patch.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+  =======================================================================
+   Use Apache Ant to generate a patch file for Apache Ant.
+  =======================================================================
+-->
+<project name="create-patch" default="patchpackage" basedir=".">
+    <property environment="env"/>
+    <property name="patch.package" value="patch.tar.gz"/>
+    <property name="patch.file" value="patch.txt"/>
+
+    <condition property="svn.found">
+        <or>
+            <available file="svn" filepath="${env.PATH}"/>
+            <available file="svn.exe" filepath="${env.PATH}"/>
+            <available file="svn.exe" filepath="${env.Path}"/>
+        </or>
+    </condition>
+
+    <target name="createpatch">
+        <fail unless="svn.found"
+              message="You need a version of svn to create the patch"/>
+        <exec executable="svn" output="${patch.file}">
+            <arg value="diff"/>
+        </exec>
+    </target>
+
+    <target name="newfiles" depends="createpatch">
+        <delete file="${patch.package}"/>
+        <exec executable="svn" output="${patch.file}.tmp">
+            <arg value="status"/>
+        </exec>
+        <replace file="${patch.file}.tmp" token="?      " value=""/>
+    </target>
+
+    <target name="patchpackage" depends="newfiles">
+        <tar basedir="${basedir}"
+            tarfile="${patch.package}"
+            compression="gzip"
+            includesfile="${patch.file}.tmp"
+            excludes="${patch.file}.tmp"/>
+        <delete file="${patch.file}.tmp"/>
+    </target>
+</project>
diff --git a/trunk/proposal/ant-site/anakia/build.xml b/trunk/proposal/ant-site/anakia/build.xml
new file mode 100644
index 0000000..62ca702
--- /dev/null
+++ b/trunk/proposal/ant-site/anakia/build.xml
@@ -0,0 +1,55 @@
+<project name="build-site" default="docs" basedir=".">
+
+    <!-- Initialization properties -->
+    <property name="project.name" value="ant"/>
+    <property name="docs.src"     location="xdocs"/>
+    <property name="docs.dest"    location="docs"/>
+    <property name="project.file" value="stylesheets/project.xml" />
+    <property name="site.dir"     location="../../../../jakarta-site2" />
+    <property name="templ.path"   location="xdocs/stylesheets" />
+    <property name="velocity.props"   location="${docs.src}/velocity.properties" />
+
+    <path id="anakia.classpath">
+        <fileset dir="${site.dir}/lib">
+            <include name="*.jar"/>
+        </fileset>
+    </path>
+
+    <target name="prepare">    
+        <available classname="org.apache.velocity.anakia.AnakiaTask" 
+                   property="AnakiaTask.present">
+            <classpath refid="anakia.classpath"/>
+        </available>
+    </target>
+
+    <target depends="prepare" name="prepare-error" unless="AnakiaTask.present">
+        <echo>
+            AnakiaTask is not present! Please check to make sure that 
+            velocity.jar is in your classpath.
+        </echo>
+    </target>
+
+    <target name="docs" depends="prepare-error" if="AnakiaTask.present">
+        <taskdef name="anakia" classname="org.apache.velocity.anakia.AnakiaTask">
+            <classpath refid="anakia.classpath"/>
+        </taskdef>
+        
+        <anakia basedir="${docs.src}" destdir="${docs.dest}/"
+             extension=".html" style="./site.vsl"
+             projectFile="${project.file}"
+             excludes="**/stylesheets/**"
+             includes="**/*.xml"
+             lastModifiedCheck="true"
+             templatePath="${templ.path}"
+             velocityPropertiesFile="${velocity.props}">
+        </anakia>
+    </target>
+    
+    <target name="javadocs">
+      <ant antfile="build.xml" target="dist_javadocs">
+        <property name="dist.javadocs" value="${docs.dest}/manual/api" />
+      </ant>
+    </target>
+    
+    <target name="all" depends="docs, javadocs"/>
+</project>
diff --git a/trunk/proposal/ant-site/forrest/anakia2forrest.xsl b/trunk/proposal/ant-site/forrest/anakia2forrest.xsl
new file mode 100644
index 0000000..f24cead
--- /dev/null
+++ b/trunk/proposal/ant-site/forrest/anakia2forrest.xsl
@@ -0,0 +1,134 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<!--
+
+  A little bit of automated transformation to help conversion
+  from Anakia to Forrest/Cocoon docs.
+  
+  This is purely experimental, it hem...should work, well mostly
+  but it should manage to break a couple of things so you will
+  need a manual pass to fix things after that.
+  
+  Stephane Bailliez, sbailliez@apache.org
+  
+  -->
+  <xsl:output method="xml" indent="yes" doctype-system="document-v11.dtd"
+  doctype-public="-//APACHE//DTD Documentation V1.1//EN" encoding="ISO-8859-1"/>
+
+  <!-- properties = header in Forrest language -->
+  <xsl:template match="properties">
+    <header>
+      <xsl:apply-templates select="*[ local-name() != 'author']"/>
+      <author>
+        <xsl:apply-templates select="author"/>
+      </author>
+    </header>
+  </xsl:template>
+
+  <xsl:template match="author">
+    <person id="{text()}">
+      <!--
+      not everyone gives his mail in order not to receive too much spam... or be
+      assimilated as 24/24 7/7 support
+      -->
+      <xsl:if test="@email"><xsl:attribute name="email"><xsl:value-of select="@email"/></xsl:attribute></xsl:if>
+    </person>
+  </xsl:template>
+
+  <!-- section = subsection with forrest and the title is an element -->
+  <xsl:template match="section|subsection">
+    <section>
+      <title><xsl:value-of select="@name"/></title>
+      <xsl:apply-templates/>
+    </section>
+  </xsl:template>
+
+  <!-- Ignore those tags they should not be here, this will clean up
+  some but will break others, anyways. br is evil :) -->
+  <xsl:template match="br|nobr">
+    <xsl:apply-templates/>
+  </xsl:template>
+
+  <!-- font should not be there, it was used to do a source (or code ?)-->
+  <xsl:template match="font">
+    <source>
+      <xsl:apply-templates/>
+    </source>
+  </xsl:template>
+
+  <!-- assumes img = icon rather than figure -->
+  <xsl:template match="img">
+    <icon>
+    <xsl:apply-templates select="@alt|@src|@width|@height"/>
+    </icon>
+  </xsl:template>
+  
+  <!-- assume every anchor with a name is an anchor -->
+  <xsl:template match="a[@name]">
+    <anchor>
+      <xsl:apply-templates select="@*"/>
+      <xsl:apply-templates/>
+    </anchor>  
+  </xsl:template>
+  
+  <!-- try to be super smart to detect link/anchor/jump -->
+  <xsl:template match="a[@href]">
+    <xsl:choose>
+      <!-- something with a hashmark is a jump -->
+      <xsl:when test="starts-with(@href, '#')">
+        <jump>
+          <xsl:apply-templates select="@*"/>
+          <xsl:apply-templates/>        
+        </jump>
+      </xsl:when>
+      <!--
+        assume everything out of apache domain would be better with a fork
+        This is really a life style, I hate windows forking all over my
+        desktop but it's quite convenient sometimes when too lazy to shift.
+        One super thing would be to do like Microsoft.com and put an
+        extra icon via forrest after the link when it send outside
+        the apache site.
+      -->
+      <xsl:when test="starts-with(@href, 'http://') and not(contains(@href, 'apache.org'))">
+        <fork>
+          <xsl:apply-templates select="@*"/>
+          <xsl:apply-templates/>        
+        </fork>
+      </xsl:when>
+      <!-- fallback to a basic link -->
+      <xsl:otherwise>
+        <link>
+          <xsl:apply-templates select="@*"/>
+          <xsl:apply-templates/>
+        </link>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <!---
+    Ugly hack to define an axial table
+    The css could be defined as text-align:right !important;
+    -->
+  <xsl:template match="table">
+    <table>
+    <!--
+      (tr[1]/th and tr[1]/td) would give the same result
+      but I'm using following-sibbling to sound super smart
+      and obfuscate my code. It hard to write, so it should
+      be hard to understand ;-)
+      -->
+    <xsl:if test="tr[1]/th[following-sibling::td]">
+      <xsl:attribute name="class">axial</xsl:attribute>
+    </xsl:if>
+    <xsl:apply-templates select="@*"/>
+    <xsl:apply-templates/>
+    </table>
+  </xsl:template>
+
+<!-- wide rule, copy all nodes and attributes -->
+  <xsl:template match="node()|@*" priority="-1">
+    <xsl:copy>
+      <xsl:apply-templates select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/proposal/ant-site/forrest/build.xml b/trunk/proposal/ant-site/forrest/build.xml
new file mode 100644
index 0000000..fed24f0
--- /dev/null
+++ b/trunk/proposal/ant-site/forrest/build.xml
@@ -0,0 +1,18 @@
+<project name="anakia2forrest" default="run" basedir=".">
+
+    <!-- Initialization properties -->
+    <property name="anakia.xdocs.src"     location="../anakia/xdocs"/>
+    <property name="docs.dest"    location="docs"/>
+
+    <!-- run forrest, run ! -->
+    <target name="run">      
+      <xslt force="true" basedir="${anakia.xdocs.src}" destdir="${docs.dest}"
+        includes="**/*.xml"
+        extension=".xml"
+        style="${basedir}/anakia2forrest.xsl"/>      
+      
+      <xslt force="true" in="${anakia.xdocs.src}/stylesheets/project.xml" out="${docs.dest}/book.xml"
+        style="${basedir}/project2book.xsl"/>
+    </target>
+
+</project>
diff --git a/trunk/proposal/ant-site/forrest/project2book.xsl b/trunk/proposal/ant-site/forrest/project2book.xsl
new file mode 100644
index 0000000..8ae0841
--- /dev/null
+++ b/trunk/proposal/ant-site/forrest/project2book.xsl
@@ -0,0 +1,36 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<!--
+
+  A little bit of automated transformation to help conversion
+  from Anakia to Forrest/Cocoon docs.
+  
+  This is purely experimental, it hem...should work, well mostly
+  but it should manage to break a couple of things so you will
+  need a manual pass to fix things after that.
+  
+  Stephane Bailliez, sbailliez@apache.org
+  
+  -->
+  <xsl:output method="xml" indent="yes" doctype-system="book-cocoon-v10.dtd"
+  doctype-public="-//APACHE//DTD Cocoon Documentation Book V1.0//EN" encoding="ISO-8859-1"/>
+
+  <xsl:template match="project">
+    <book copyright="2002 The Apache Software Foundation"
+          xmlns:xlink="http://www.w3.org/1999/xlink"
+          software="{@name}"
+          title="{title/text()}">
+        <xsl:apply-templates select="body/menu"/>
+    </book>
+  </xsl:template>
+
+  <xsl:template match="menu">
+    <menu label="{@name}">
+        <xsl:apply-templates select="item"/>
+    </menu>
+  </xsl:template>
+
+  <xsl:template match="item">
+    <menu-item label="{@name}" href="{@href}"/>
+  </xsl:template>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/proposal/embed/README b/trunk/proposal/embed/README
new file mode 100644
index 0000000..35782ee
--- /dev/null
+++ b/trunk/proposal/embed/README
@@ -0,0 +1,2 @@
+Copy the files in o.a.t.ant, recompile.
+
diff --git a/trunk/proposal/embed/build.xml b/trunk/proposal/embed/build.xml
new file mode 100644
index 0000000..70e8651
--- /dev/null
+++ b/trunk/proposal/embed/build.xml
@@ -0,0 +1,98 @@
+<project name="embed" default="main" basedir=".">
+  <description>Embed proposal</description>
+  <property file="${user.home}/build.properties" />
+  <property file="user.properties" />
+
+  <property name="base.path" location="/usr/share/java"/>
+  <property name="ant.src" location="../.."/>
+  <property name="commons.src" location="${ant.src}/../jakarta-commons"/>
+  <property name="sandbox.src" location="${ant.src}/../jakarta-commons-sandbox"/>
+
+  <property name="embed.build" location="build"/>
+  <property name="debug" value="true"/>
+
+  <!-- Those 2 should be moved to JXPath and velocity. -->  
+  <property name="commons-logging.jar" location="${commons.src}/logging/dist/commons-logging.jar" /> 
+  <property name="jxpath.jar" location="${commons.src}/jxpath/dist/commons-jxpath.jar" /> 
+  <property name="velocity.jar" location="${base.path}/velocity/velocity-20020220.jar" />
+  <property name="velocity-dep.jar" location="${base.path}/velocity/velocity-dep-20020220.jar" />
+  <property name="jexl.jar" location="${sandbox.src}/jexl/dist/commons-jexl.jar" />
+
+  <property name="commons-discovery.jar" location="${commons.src}/discovery/dist/commons-discovery.jar" />
+
+  <target name="init">
+      <mkdir dir="build/classes" />
+  </target>
+    
+  <target name="build" depends="main" />
+
+  <target name="main" depends="init,main-ant15" >
+  </target>
+
+  <target name="main-ant15" depends="init" 
+          description="Build hacks into ant1.5 to support some 1.6 features" >
+   <echo>Embed is no longer supported with ant1.6. It is only used with ant1.5 ! The dynamic properties work with both, use embed-optional target</echo>
+    <javac srcdir="src/java"  
+           debug="${debug}"
+           destdir="${embed.build}/classes" >
+      <include name="**" />
+      <exclude name="org/apache/tools/ant/taskdefs/optional/**" />
+    </javac>
+
+    <copy toDir="${embed.build}/classes">
+      <fileset dir="src/java" includes="META-INF/**" />
+    </copy>
+
+    <jar file="${embed.build}/ant-sax2.jar" basedir="${embed.build}/classes">
+      <include name="**" />
+    </jar>
+        
+  </target>
+
+  <target name="embed-optional" depends="init" >
+    <javac srcdir="src/java"  
+           debug="${debug}"
+           destdir="${embed.build}/classes" >
+      <include name="org/apache/tools/ant/taskdefs/optional/**" />
+      <include name="org/apache/tools/ant/taskdefs/XMLDOM**" />
+      <classpath>
+        <!-- all this will move to their package -->
+        <pathelement location="build/classes" />
+        <pathelement location="${jxpath.jar}" />
+        <pathelement location="${velocity.jar}" />
+        <pathelement location="${jexl.jar}" />
+        <pathelement location="${commons-discovery.jar}" />
+        <pathelement location="${commons-logging.jar}" />
+      </classpath>
+    </javac>
+
+    <copy toDir="${embed.build}/classes">
+      <fileset dir="src/java" includes="META-INF/**" />
+    </copy>
+
+    <jar file="${embed.build}/optional-dynprop.jar" basedir="${embed.build}/classes">
+      <include name="org/apache/tools/ant/taskdefs/optional/**" />
+      <include name="org/apache/tools/ant/taskdefs/XMLDOM**" />
+    </jar>
+        
+  </target>
+
+  <target name="gump" description="Patch gump bootstrap ant" depends="main" >
+  </target>
+
+  <target name="install" description="Installs built jars">
+    <echo message="Copy ${embed.build}/ant-sax2.jar toDir=${ant.home}/lib"/>
+
+    <mkdir dir="${ant.home}/lib" />
+    <copy file="${embed.build}/ant-sax2.jar" toDir="${ant.home}/lib"/>
+
+  </target>
+
+  <target name="install-embed" depends="main, install" 
+          description="Builds and installs embed without optional"/>
+ 
+  <target name="install-embed-optional" depends="embed-optional, install" 
+          description="Installs extra built jars" >
+    <copy file="${embed.build}/optional-dynprop.jar" toDir="${ant.home}/lib"/>
+  </target> 
+</project>
diff --git a/trunk/proposal/embed/src/java/META-INF/services/org.apache.tools.ant.ProjectHelper b/trunk/proposal/embed/src/java/META-INF/services/org.apache.tools.ant.ProjectHelper
new file mode 100644
index 0000000..3a14806
--- /dev/null
+++ b/trunk/proposal/embed/src/java/META-INF/services/org.apache.tools.ant.ProjectHelper
@@ -0,0 +1 @@
+org.apache.tools.ant.helper.ProjectHelperImpl2
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentFactory.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentFactory.java
new file mode 100644
index 0000000..7596c78
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentFactory.java
@@ -0,0 +1,116 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.lang.reflect.Modifier;
+
+
+import org.apache.tools.ant.types.FilterSet; 
+import org.apache.tools.ant.types.FilterSetCollection; 
+import org.apache.tools.ant.util.FileUtils; 
+
+// XXX It would be a good idea to merge all 'hooks' into one AntInterceptor
+// mechanism. That would make it much easier to read and extend.
+
+/** 
+ * Abstract component creation and configuration.
+ *
+ * TODO: Multiple ComponentHelpers can be registered in a project, either by an
+ * embedding application or by taskdef-like tasks.
+ *
+ * After a ProjectComponentHelper is registered, it'll manage the construction and 
+ * configuration of tasks/types/etc. It has full control over how the
+ * component is created - and may provide runtime wrapping for components
+ * not implementing the Task/DataType interfaces.
+ * It works in close relation with TaskAdapter and RuntimeConfigurable
+ * to handle delayed evaluation of tasks or custom attribute-&gt;task mapping.
+ * If it returns a wrapper for Task, the wrapper is required to extend
+ * TaskAdapter.
+ *
+ * The common 'Chain' pattern is used to construct
+ * tasks, with the original behavior ( Class registry ) tried last, by the
+ * default helper implementation.
+ *
+ * Note that 'delayed' construction of tasks is used.
+ *
+ */
+public interface ProjectComponentFactory {
+
+    /** Creates an ant component..
+     *
+     * A factory may have knowledge about the tasks it creates. It can return
+     * an object extending TaskAdapter that emulates Task/DataType. If null is returned,
+     * the next helper is tried.
+     *
+     * @param project the context for task creation.
+     * @param role Class name for the expected role ( Task, Type, Filter, etc ). Null for 'any'
+     * @param ns namespace if a SAX2 parser is used, null for 'classical' ant
+     * @param taskName the (local) name of the task.
+     */
+    public Object createProjectComponent( Project project,
+                                          String ns,
+                                          String taskName )
+        throws BuildException;
+    // XXX class loader ? Can use the ns, but additional hints may be available in taskdef
+    // 
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentHelper.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentHelper.java
new file mode 100644
index 0000000..4b8db9e
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/ProjectComponentHelper.java
@@ -0,0 +1,138 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.lang.reflect.Modifier;
+
+
+import org.apache.tools.ant.types.FilterSet; 
+import org.apache.tools.ant.types.FilterSetCollection; 
+import org.apache.tools.ant.util.FileUtils; 
+
+/** 
+ * Component creation and configuration.
+ *
+ * After a ProjectComponentFactory is registered, it'll manage the construction and 
+ * configuration of tasks/types/etc. It has full control over how the
+ * component is created - and may provide runtime wrapping for components
+ * not implementing the Task/DataType interfaces.
+ * It works in close relation with TaskAdapter and RuntimeConfigurable
+ * to handle delayed evaluation of tasks or custom attribute-&gt;task mapping.
+ * If it returns a wrapper for Task, the wrapper is required to extend
+ * TaskAdapter.
+ *
+ * The common 'Chain' pattern is used to construct
+ * tasks, with the original behavior ( Class registry ) tried last, by the
+ * default helper implementation.
+ *
+ * Note that 'delayed' construction of tasks is used.
+ *
+ */
+public class ProjectComponentHelper  {
+    static private ProjectComponentHelper singleton=new ProjectComponentHelper();
+    
+    Vector factories=new Vector();
+
+    /**
+     */
+    public static ProjectComponentHelper getProjectComponentHelper() {
+        // Singleton for now, it may change ( per/classloader )
+        return singleton;
+    }
+
+    public void addComponentFactory( ProjectComponentFactory fact ) {
+        factories.addElement( fact );
+    }
+    
+    public Object createProjectComponent( UnknownElement ue, Project project,
+                                          String ns,
+                                          String taskName )
+        throws BuildException
+    {
+        Object component=null;
+        for( int i=0; i< factories.size(); i++ ) {
+            ProjectComponentFactory fact=(ProjectComponentFactory)factories.elementAt(i);
+            component=fact.createProjectComponent( project, ns, taskName );
+            if( component!=null ) return component;
+        }
+
+        // System.out.println("Fallback to project default " + taskName );
+        // Can't create component. Default is to use the old methods in project.
+
+        // This policy is taken from 1.5 ProjectHelper. In future the difference between
+        // task and type should disapear.
+        if( project.getDataTypeDefinitions().get(taskName) != null ) {
+            // This is the original policy in ProjectHelper. The 1.5 version of UnkwnonwElement
+            // used to try first to create a task, and if it failed tried a type. In 1.6 the diff
+            // should disapear.
+            component = project.createDataType(taskName);
+            if( component!=null ) return component;
+        }
+
+        // from UnkwnonwElement.createTask. The 'top level' case is removed, we're
+        // allways lazy
+        component = project.createTask(taskName);
+
+        return component;
+    }
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/PropertyHelper.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/PropertyHelper.java
new file mode 100644
index 0000000..1774573
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/PropertyHelper.java
@@ -0,0 +1,627 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.helper.*;
+
+import java.util.*;
+
+import org.xml.sax.AttributeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributeListImpl;
+import org.xml.sax.helpers.AttributesImpl;
+
+/* ISSUES:
+ - ns param. It could be used to provide "namespaces" for properties, which
+ may be more flexible.
+ - Object value. In ant1.5 String is used for Properties - but it would be nice
+ to support generic Objects ( the property remains imutable - you can't change
+ the associated object ). This will also allow JSP-EL style setting using the
+ Object if an attribute contains only the property ( name="${property}" could
+ avoid Object-&gt;String-&gt;Object conversion )
+ - Currently we "chain" only for get and set property ( probably most users
+ will only need that - if they need more they can replace the top helper ).
+ Need to discuss this and find if we need more.
+ */
+
+/** NOT FINAL. API MAY CHANGE
+ *
+ * Deals with properties - substitution, dynamic properties, etc.
+ *
+ * This is the same code as in Ant1.5. The main addition is the ability
+ * to chain multiple PropertyHelpers and to replace the default.
+ *
+ * @since Ant 1.6
+ */
+public class PropertyHelper {
+
+    protected Project project;
+    protected PropertyHelper next;
+
+    /** Project properties map (usually String to String). */
+    protected Hashtable properties = new Hashtable();
+    /**
+     * Map of "user" properties (as created in the Ant task, for example).
+     * Note that these key/value pairs are also always put into the
+     * project properties, so only the project properties need to be queried.
+     * Mapping is String to String.
+     */
+    protected Hashtable userProperties = new Hashtable();
+    /**
+     * Map of inherited "user" properties - that are those "user"
+     * properties that have been created by tasks and not been set
+     * from the command line or a GUI tool.
+     * Mapping is String to String.
+     */
+    protected Hashtable inheritedProperties = new Hashtable();
+
+    protected PropertyHelper() {
+    }
+
+    // --------------------  Hook management  --------------------
+
+    public void setProject(Project p ) {
+        this.project=p;
+    }
+
+    /** There are 2 ways to hook into property handling:
+     *  - you can replace the main PropertyHelper. The replacement is required
+     * to support the same semantics ( of course :-)
+     *
+     *  - you can chain a property helper capable of storing some properties.
+     *  Again, you are required to respect the immutability semantics ( at
+     *  least for non-dynamic properties )
+     *
+     * @param next
+     */
+    public void setNext( PropertyHelper next ) {
+        this.next=next;
+    }
+
+    public PropertyHelper getNext() {
+        return next;
+    }
+
+    /** Factory method to create a property processor.
+     *  Users can provide their own or replace it using "ant.PropertyHelper"
+     *  reference. User tasks can also add themself to the chain, and provide
+     *  dynamic properties.
+     */
+    public static PropertyHelper getPropertyHelper(Project project) {
+        PropertyHelper ph=(PropertyHelper)project.getReference( "ant.PropertyHelper" );
+        if( ph!=null ) return ph;
+        ph=new PropertyHelper();
+        ph.setProject( project );
+
+        project.addReference( "ant.PropertyHelper",ph );
+        return ph;
+    }
+
+    // --------------------  Methods to override  --------------------
+
+    /**
+     * Sets a property. Any existing property of the same name
+     * is overwritten, unless it is a user property. Will be called
+     * from setProperty().
+     *
+     * If all helpers return false, the property will be saved in
+     * the default properties table by setProperty.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @return true if this helper has stored the property, false if it
+     *    couldn't. Each helper should delegate to the next one ( unless it
+     *    has a good reason not to ).
+     */
+    public boolean setPropertyHook(String ns, String name,
+                                   Object value,
+                                   boolean inherited, boolean user,
+                                   boolean isNew)
+    {
+        if( getNext()!=null ) {
+            boolean subst=getNext().setPropertyHook(ns, name, value,
+                    inherited, user, isNew);
+            // If next has handled the property
+            if( subst ) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /** Get a property. If all hooks return null, the default
+     * tables will be used.
+     *
+     * @param ns
+     * @param name
+     * @return
+     */
+    public Object getPropertyHook(String ns, String name, boolean user) {
+        if( getNext() != null ) {
+            Object o=getNext().getPropertyHook(ns, name, user);
+            if( o!= null ) return o;
+        }
+        // Experimental/Testing, will be removed
+        if( name.startsWith( "toString:" )) {
+            name=name.substring( "toString:".length());
+            Object v=project.getReference( name );
+            if( v==null ) return null;
+            return v.toString();
+        }
+
+
+        return null;
+    }
+
+    // -------------------- Optional methods   --------------------
+    // You can override those methods if you want to optimize or
+    // do advanced things ( like support a special syntax ).
+    // The methods do not chain - you should use them when embedding ant
+    // ( by replacing the main helper )
+
+    /**
+     * Parses a string containing <code>${xxx}</code> style property
+     * references into two lists. The first list is a collection
+     * of text fragments, while the other is a set of string property names.
+     * <code>null</code> entries in the first list indicate a property
+     * reference from the second list.
+     *
+     * It can be overriden with a more efficient or customized version.
+     *
+     * @param value     Text to parse. Must not be <code>null</code>.
+     * @param fragments List to add text fragments to.
+     *                  Must not be <code>null</code>.
+     * @param propertyRefs List to add property names to.
+     *                     Must not be <code>null</code>.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     */
+    public void parsePropertyString(String value, Vector fragments,
+                                    Vector propertyRefs)
+        throws BuildException
+    {
+        parsePropertyStringDefault(value, fragments, propertyRefs);
+    }
+
+    /**
+     * Replaces <code>${xxx}</code> style constructions in the given value
+     * with the string value of the corresponding data types.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     * @param keys  Mapping (String to String) of property names to their
+     *              values. If <code>null</code>, only project properties will
+     *              be used.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     */
+    public String replaceProperties(String ns, String value,
+                                    Hashtable keys)
+            throws BuildException
+    {
+        if (value == null) {
+            return null;
+        }
+
+        Vector fragments = new Vector();
+        Vector propertyRefs = new Vector();
+        parsePropertyString(value, fragments, propertyRefs);
+
+        StringBuffer sb = new StringBuffer();
+        Enumeration i = fragments.elements();
+        Enumeration j = propertyRefs.elements();
+
+        while (i.hasMoreElements()) {
+            String fragment = (String) i.nextElement();
+            if (fragment == null) {
+                String propertyName = (String) j.nextElement();
+                Object replacement=null;
+
+                // try to get it from the project or keys
+                // Backward compatibility
+                if( keys!=null ) {
+                    replacement=keys.get(propertyName);
+                }
+                if( replacement==null ) {
+                    replacement=getProperty(ns, propertyName);
+                }
+
+                if (replacement == null ) {
+                    project.log("Property ${" + propertyName
+                            + "} has not been set", Project.MSG_VERBOSE);
+                }
+                fragment = (replacement!=null)
+                        ? replacement.toString()
+                        : "${" + propertyName + "}";
+            }
+            sb.append(fragment);
+        }
+
+        return sb.toString();
+    }
+
+    // -------------------- Default implementation  --------------------
+    // Methods used to support the default behavior and provide backward
+    // compatibility. Some will be deprecated, you should avoid calling them.
+
+
+    /** Default implementation of setProperty. Will be called from Project.
+     *  This is the original 1.5 implementation, with calls to the hook
+     *  added.
+     */
+    public synchronized boolean setProperty(String ns, String name,
+                                            Object value, boolean verbose)
+    {
+        // user ( CLI ) properties take precedence
+        if (null != userProperties.get(name)) {
+            if( verbose ) {
+                project.log("Override ignored for user property " + name,
+                        Project.MSG_VERBOSE);
+            }
+            return false;
+        }
+
+        boolean done=this.setPropertyHook(ns, name, value, false, false, false);
+        if( done ) {
+            return true;
+        }
+
+        if (null != properties.get(name) && verbose) {
+            project.log("Overriding previous definition of property " + name,
+                    Project.MSG_VERBOSE);
+        }
+
+        if( verbose ) {
+            project.log("Setting project property: " + name + " -> " +
+                    value, Project.MSG_DEBUG);
+        }
+        properties.put(name, value);
+        return true;
+    }
+
+    /**
+     * Sets a property if no value currently exists. If the property
+     * exists already, a message is logged and the method returns with
+     * no other effect.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @since Ant 1.6
+     */
+    public synchronized void setNewProperty(String ns, String name,
+                                            Object value)
+    {
+        if (null != properties.get(name)) {
+            project.log("Override ignored for property " + name,
+                    Project.MSG_VERBOSE);
+            return;
+        }
+
+        boolean done=this.setPropertyHook(ns, name, value, false, true, false);
+        if( done ) {
+            return;
+        }
+
+        project.log("Setting project property: " + name + " -> " +
+                value, Project.MSG_DEBUG);
+        properties.put(name, value);
+    }
+
+    /**
+     * Sets a user property, which cannot be overwritten by
+     * set/unset property calls. Any previous value is overwritten.
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     */
+    public synchronized void setUserProperty(String ns, String name,
+                                             Object value)
+    {
+        project.log("Setting ro project property: " + name + " -> " +
+                value, Project.MSG_DEBUG);
+        userProperties.put(name, value);
+
+        boolean done=this.setPropertyHook(ns, name, value, false, false, true);
+        if( done ) {
+            return;
+        }
+        properties.put(name, value);
+    }
+
+    /**
+     * Sets a user property, which cannot be overwritten by set/unset
+     * property calls. Any previous value is overwritten. Also marks
+     * these properties as properties that have not come from the
+     * command line.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     */
+    public synchronized void setInheritedProperty(String ns, String name,
+                                                  Object value)
+    {
+        inheritedProperties.put(name, value);
+
+        project.log("Setting ro project property: " + name + " -> " +
+                value, Project.MSG_DEBUG);
+        userProperties.put(name, value);
+
+        boolean done=this.setPropertyHook(ns, name, value, true, false, false);
+        if( done ) {
+            return;
+        }
+        properties.put(name, value);
+    }
+
+    // -------------------- Getting properties  --------------------
+
+    /**
+     * Returns the value of a property, if it is set.  You can override
+     * this method in order to plug your own storage.
+     *
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+    public Object getProperty(String ns, String name) {
+        if (name == null) {
+            return null;
+        }
+
+        Object o=getPropertyHook(ns, name, false);
+        if( o!= null ) {
+            return o;
+        }
+
+        return properties.get(name);
+    }
+    /**
+     * Returns the value of a user property, if it is set.
+     *
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+    public Object getUserProperty(String ns, String name) {
+        if (name == null) {
+            return null;
+        }
+        Object o=getPropertyHook(ns, name, true);
+        if( o!= null ) {
+            return o;
+        }
+        return  userProperties.get(name);
+    }
+
+
+    // -------------------- Access to property tables  --------------------
+    // This is used to support ant call and similar tasks. It should be
+    // deprecated, it is possible to use a better ( more efficient )
+    // mechanism to preserve the context.
+
+    // TODO: do we need to delegate ?
+
+    /**
+     * Returns a copy of the properties table.
+     * @return a hashtable containing all properties
+     *         (including user properties).
+     */
+    public Hashtable getProperties() {
+        Hashtable propertiesCopy = new Hashtable();
+
+        Enumeration e = properties.keys();
+        while (e.hasMoreElements()) {
+            Object name = e.nextElement();
+            Object value = properties.get(name);
+            propertiesCopy.put(name, value);
+        }
+
+        // There is a better way to save the context. This shouldn't
+        // delegate to next, it's for backward compat only.
+
+        return propertiesCopy;
+    }
+
+    /**
+     * Returns a copy of the user property hashtable
+     * @return a hashtable containing just the user properties
+     */
+    public Hashtable getUserProperties() {
+        Hashtable propertiesCopy = new Hashtable();
+
+        Enumeration e = userProperties.keys();
+        while (e.hasMoreElements()) {
+            Object name = e.nextElement();
+            Object value = properties.get(name);
+            propertiesCopy.put(name, value);
+        }
+
+        return propertiesCopy;
+    }
+
+    /**
+     * Copies all user properties that have not been set on the
+     * command line or a GUI tool from this instance to the Project
+     * instance given as the argument.
+     *
+     * <p>To copy all "user" properties, you will also have to call
+     * {@link #copyUserProperties copyUserProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.6
+     */
+    public void copyInheritedProperties(Project other) {
+        Enumeration e = inheritedProperties.keys();
+        while (e.hasMoreElements()) {
+            String arg = e.nextElement().toString();
+            if (other.getUserProperty(arg) != null) {
+                continue;
+            }
+            Object value = inheritedProperties.get(arg);
+            other.setInheritedProperty(arg, value.toString());
+        }
+    }
+
+    /**
+     * Copies all user properties that have been set on the command
+     * line or a GUI tool from this instance to the Project instance
+     * given as the argument.
+     *
+     * <p>To copy all "user" properties, you will also have to call
+     * {@link #copyInheritedProperties copyInheritedProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.6
+     */
+    public void copyUserProperties(Project other) {
+        Enumeration e = userProperties.keys();
+        while (e.hasMoreElements()) {
+            Object arg = e.nextElement();
+            if (inheritedProperties.containsKey(arg)) {
+                continue;
+            }
+            Object value = userProperties.get(arg);
+            other.setUserProperty(arg.toString(), value.toString());
+        }
+    }
+
+    // -------------------- Property parsing  --------------------
+    // Moved from ProjectHelper. You can override the static method -
+    // this is used for backward compatibility ( for code that calls
+    // the parse method in ProjectHelper ).
+
+    /** Default parsing method. It is here only to support backward compat
+     * for the static ProjectHelper.parsePropertyString().
+     */
+    static void parsePropertyStringDefault(String value, Vector fragments,
+                                    Vector propertyRefs)
+        throws BuildException
+    {
+        int prev = 0;
+        int pos;
+        //search for the next instance of $ from the 'prev' position
+        while ((pos = value.indexOf("$", prev)) >= 0) {
+
+            //if there was any text before this, add it as a fragment
+            //TODO, this check could be modified to go if pos>prev;
+            //seems like this current version could stick empty strings
+            //into the list
+            if (pos > 0) {
+                fragments.addElement(value.substring(prev, pos));
+            }
+            //if we are at the end of the string, we tack on a $
+            //then move past it
+            if (pos == (value.length() - 1)) {
+                fragments.addElement("$");
+                prev = pos + 1;
+            } else if (value.charAt(pos + 1) != '{') {
+                //peek ahead to see if the next char is a property or not
+                //not a property: insert the char as a literal
+                /*
+                fragments.addElement(value.substring(pos + 1, pos + 2));
+                prev = pos + 2;
+                */
+                if (value.charAt(pos + 1) == '$') {
+                    //backwards compatibility two $ map to one mode
+                    fragments.addElement("$");
+                    prev = pos + 2;
+                } else {
+                    //new behaviour: $X maps to $X for all values of X!='$'
+                    fragments.addElement(value.substring(pos, pos + 2));
+                    prev = pos + 2;
+                }
+
+            } else {
+                //property found, extract its name or bail on a typo
+                int endName = value.indexOf('}', pos);
+                if (endName < 0) {
+                    throw new BuildException("Syntax error in property: "
+                                                 + value);
+                }
+                String propertyName = value.substring(pos + 2, endName);
+                fragments.addElement(null);
+                propertyRefs.addElement(propertyName);
+                prev = endName + 1;
+            }
+        }
+        //no more $ signs found
+        //if there is any tail to the file, append it
+        if (prev < value.length()) {
+            fragments.addElement(value.substring(prev));
+        }
+    }
+
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/RuntimeConfigurable2.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/RuntimeConfigurable2.java
new file mode 100644
index 0000000..7422ae3
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/RuntimeConfigurable2.java
@@ -0,0 +1,348 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.helper.*;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Vector;
+import java.util.Hashtable;
+import org.xml.sax.AttributeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.helpers.AttributeListImpl;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Wrapper class that holds the attributes of an element, its children, and
+ * any text within it. It then takes care of configuring that element at
+ * runtime.
+ *
+ * This uses SAX2 and a more flexible substitution mechansim, based on
+ * o.a.tomcat.util.IntrospectionUtil.
+ *
+ */
+public class RuntimeConfigurable2 extends RuntimeConfigurable {
+
+    /** Name of the element to configure. elementName in UE */
+    private String elementTag = null;  
+    /** List of child element wrappers.  */
+    private Vector children = new Vector();
+    /** The element to configure. realThing in UE */
+    private Object wrappedObject = null;
+    /** XML attributes for the element. */
+    private Attributes attributes;
+    /** Text appearing within the element. */
+    private StringBuffer characters = new StringBuffer();
+    /** Indicates if the wrapped object has been configured */
+    private boolean proxyConfigured = false;
+
+    Project project;
+    protected Location location = Location.UNKNOWN_LOCATION;
+    
+    /**
+     * Sole constructor creating a wrapper for the specified object.
+     *
+     * @param proxy The element to configure. Must not be <code>null</code>.
+     * @param elementTag The tag name generating this element.
+     *                   Should not be <code>null</code>.
+     */
+    public RuntimeConfigurable2(Project project, Location location, Object proxy, String elementTag) {
+        super( proxy, elementTag );
+        wrappedObject = proxy;
+        this.elementTag = elementTag;
+        // This should never happen - all objects are lazy
+        if( proxy instanceof Task )
+            ((Task)proxy).setRuntimeConfigurableWrapper( this );
+        proxyConfigured=false;
+    }
+
+    Project getProject() {
+        return project;
+    }
+
+    Location getLocation() {
+        return location;
+    }    
+    /**
+     * Sets the element to configure. This is used when the real type of
+     * an element isn't known at the time of wrapper creation.
+     *
+     * @param proxy The element to configure. Must not be <code>null</code>.
+     */
+    public void setProxy(Object proxy) {
+        wrappedObject = proxy;
+        proxyConfigured=false;
+    }
+
+    public Object getProxy() {
+        return wrappedObject;
+    }
+
+    /**
+     * Sets the attributes for the wrapped element.
+     *
+     * @param attributes List of attributes defined in the XML for this
+     *                   element. May be <code>null</code>.
+     * @deprecated It shouldn't be called by anyone except ProjectHelper
+     */
+    public void setAttributes(AttributeList attributes) {
+        //    this.attributes = new AttributeListImpl(attributes);
+    }
+
+    public void setAttributes2(Attributes attributes) {
+        this.attributes=new AttributesImpl( attributes );
+    }
+    
+    /**
+     * Returns the list of attributes for the wrapped element.
+     * 
+     * @return An AttributeList representing the attributes defined in the
+     *         XML for this element. May be <code>null</code>.
+     * @deprecated only for bkwd compatibility
+     */
+    public AttributeList getAttributes() {
+        return sax1Attributes( attributes );
+    }
+
+    public Attributes getAttributes2() {
+        return attributes;
+    }
+
+    public static AttributeList sax1Attributes( Attributes sax2Att ) {
+        AttributeListImpl sax1Att=new AttributeListImpl();
+        int length = sax2Att.getLength();
+        if (length > 0) {
+            for (int i = 0; i < length; i++) {
+                // System.out.println("Attributes: " + sax2Att.getQName(i) + " " +
+                //                    sax2Att.getValue(i));
+                sax1Att.addAttribute( sax2Att.getQName(i), 
+                                      sax2Att.getType(i),
+                                      sax2Att.getValue(i));
+            }
+	}
+        return sax1Att;
+    }
+
+    /**
+     * Adds a child element to the wrapped element.
+     * 
+     * @param child The child element wrapper to add to this one.
+     *              Must not be <code>null</code>.
+     */
+    public void addChild(RuntimeConfigurable child) {
+        // addChild( UnknownElement ) in UE
+        children.addElement(child);
+    }
+
+    /**
+     * Returns the child wrapper at the specified position within the list.
+     * 
+     * @param index The index of the child to return.
+     * 
+     * @return The child wrapper at position <code>index</code> within the
+     *         list.
+     */
+    public RuntimeConfigurable getChild(int index) {
+        return (RuntimeConfigurable) children.elementAt(index);
+    }
+
+    /**
+     * Adds characters from #PCDATA areas to the wrapped element.
+     * 
+     * @param data Text to add to the wrapped element. 
+     *        Should not be <code>null</code>.
+     */
+    public void addText(String data) {
+        characters.append(data);
+    }
+
+    /**
+     * Adds characters from #PCDATA areas to the wrapped element.
+     * 
+     * @param buf A character array of the text within the element.
+     *            Must not be <code>null</code>.
+     * @param start The start element in the array.
+     * @param count The number of characters to read from the array.
+     * 
+     */
+    public void addText(char[] buf, int start, int count) {
+        addText(new String(buf, start, count));
+    }
+
+    /**
+     * Returns the tag name of the wrapped element.
+     * 
+     * @return The tag name of the wrapped element. This is unlikely
+     *         to be <code>null</code>, but may be.
+     */
+    public String getElementTag() {
+        // getTag in UE
+        return elementTag;
+    }
+
+    /**
+     * Configures the wrapped element and all its children.
+     * The attributes and text for the wrapped element are configured,
+     * and then each child is configured and added. Each time the
+     * wrapper is configured, the attributes and text for it are
+     * reset.
+     * 
+     * If the element has an <code>id</code> attribute, a reference
+     * is added to the project as well.
+     * 
+     * @param p The project containing the wrapped element. 
+     *          Must not be <code>null</code>.
+     * 
+     * @exception BuildException if the configuration fails, for instance due
+     *            to invalid attributes or children, or text being added to
+     *            an element which doesn't accept it.
+     */
+    public void maybeConfigure(Project p) throws BuildException {
+        maybeConfigure(p, true);
+    }
+
+    /**
+     * Configures the wrapped element.  The attributes and text for
+     * the wrapped element are configured.  Each time the wrapper is
+     * configured, the attributes and text for it are reset.
+     *
+     * If the element has an <code>id</code> attribute, a reference
+     * is added to the project as well.
+     *
+     * @param p The project containing the wrapped element.
+     *          Must not be <code>null</code>.
+     *
+     * @param configureChildren Whether to configure child elements as
+     * well.  if true, child elements will be configured after the
+     * wrapped element.
+     *
+     * @exception BuildException if the configuration fails, for instance due
+     *            to invalid attributes or children, or text being added to
+     *            an element which doesn't accept it.
+     */
+    public void maybeConfigure(Project p, boolean configureChildren) 
+        throws BuildException {
+        String id = null;
+
+        if( proxyConfigured ) {
+            return;
+        }
+        PropertyHelper ph=PropertyHelper.getPropertyHelper(p);
+
+        Object target=(wrappedObject instanceof TaskAdapter) ?
+                ((TaskAdapter)wrappedObject).getProxy() : wrappedObject;
+
+        if (attributes != null) {
+            IntrospectionHelper ih =
+                    IntrospectionHelper.getHelper(target.getClass());
+            p.addBuildListener( ih );
+
+            for (int i = 0; i < attributes.getLength(); i++) {
+                String name= attributes.getQName(i);
+                String value= attributes.getValue(i);
+
+                // reflect these into the target
+                value = ph.replaceProperties(null, value, p.getProperties());
+                try {
+                    ih.setAttribute(p, target,
+                            name.toLowerCase(Locale.US), value);
+                } catch (BuildException be) {
+                    // id attribute must be set externally
+                    if (!name.equals("id")) {
+                        throw be;
+                    }
+                }
+            }
+            id = attributes.getValue("id");
+            // No way - this will be used on future calls ( if the task is used
+            // multiple times: attributes = null;
+        }
+        if (characters.length() != 0) {
+            ProjectHelper.addText(p, wrappedObject, characters.toString());
+        }
+        Enumeration enum = children.elements();
+        while (enum.hasMoreElements()) {
+            RuntimeConfigurable2 child 
+                = (RuntimeConfigurable2) enum.nextElement();
+            if (child.wrappedObject instanceof Task) {
+                Task childTask = (Task) child.wrappedObject;
+                childTask.setRuntimeConfigurableWrapper(child);
+            }
+
+            if (configureChildren) {
+                if (child.wrappedObject instanceof Task) {
+                    Task childTask = (Task) child.wrappedObject;
+                    childTask.maybeConfigure();
+                } else {
+                    child.maybeConfigure(p);
+                }
+                ProjectHelper.storeChild(p, wrappedObject, child.wrappedObject,
+                                         child.getElementTag()
+                                         .toLowerCase(Locale.US));
+            }
+        }
+
+        if (id != null) {
+            // p.addReference(id, wrappedObject);
+            p.getReferences().put( id, wrappedObject );
+            //System.out.println("XXX updating reference " + this + " " + id + " " + wrappedObject );
+        }
+
+        proxyConfigured = true; 
+   }
+
+
+
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/UnknownElement2.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/UnknownElement2.java
new file mode 100644
index 0000000..6f273de
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/UnknownElement2.java
@@ -0,0 +1,332 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+import org.apache.tools.ant.*;
+
+import java.util.Vector;
+
+// XXX Use this as a replacement for the adapter !
+
+/**
+ * Wrapper class that holds all the information necessary to create a task
+ * or data type.
+ *
+ * With PH2, all components will be wrapped. Long term we should consolidate
+ * UnkndownElement and RuntimeConfigurable.
+ * 
+ *
+ * @deprecated All tasks will be lazily created and configured before execution.
+ *       The xml reader will create a tree of RuntimeConfigurable, and tasks will
+ *       be constructed ( and reconstructed for loops ) just before execution. The
+ *       UnknonwnElement construct is no longer needed.
+ */
+public class UnknownElement2 extends UnknownElement {
+
+    /**
+     * Holds the name of the task/type or nested child element of a
+     * task/type that hasn't been defined at parser time or has
+     * been redefined since original creation.
+     */
+    private String elementName;
+
+    /**
+     * The real object after it has been loaded.
+     */
+    private Object realThing;
+
+    /**
+     * List of child elements (UnknownElements).
+     */
+    private Vector children = new Vector();
+
+    /**
+     * Creates an UnknownElement for the given element name.
+     *
+     * @param elementName The name of the unknown element.
+     *                    Must not be <code>null</code>.
+     */
+    public UnknownElement2(String elementName) {
+        super( elementName );
+        this.elementName = elementName;
+    }
+
+    /**
+     * Returns the name of the XML element which generated this unknown
+     * element.
+     *
+     * @return the name of the XML element which generated this unknown
+     *         element.
+     */
+    public String getTag() {
+        return elementName;
+    }
+
+    public RuntimeConfigurable getWrapper() {
+        return wrapper;
+    }
+
+    protected RuntimeConfigurable2 getWrapper2() {
+        return (RuntimeConfigurable2)wrapper;
+    }
+
+
+    /**
+     * Creates the real object instance and child elements, then configures
+     * the attributes and text of the real object. This unknown element
+     * is then replaced with the real object in the containing target's list
+     * of children.
+     *
+     * @exception BuildException if the configuration fails
+     */
+    public void maybeConfigure() throws BuildException {
+        ProjectComponentHelper helper=ProjectComponentHelper.getProjectComponentHelper();
+        // Used to be: makeObject(this, getWrapper2());
+        realThing = helper.createProjectComponent( this, getProject(), null, 
+                                                   this.getTag());
+        if (realThing == null) {
+            throw getNotFoundException("task or type", this.getTag());
+        }
+
+        getWrapper2().setProxy(realThing);
+
+        if (realThing instanceof Task) {
+            Task task=(Task)realThing;
+            task.setLocation(this.getLocation());
+            // UnknownElement always has an associated target
+            task.setOwningTarget(this.getOwningTarget());
+            task.init();
+            task.setRuntimeConfigurableWrapper(getWrapper2());
+
+            // For Script to work. Ugly
+            // The reference is replaced by RuntimeConfigurable
+            this.getOwningTarget().replaceChild(this, (Task)realThing);
+        }
+
+        handleChildren(realThing, getWrapper2());
+
+        getWrapper2().maybeConfigure(getProject());
+
+
+    }
+
+    /**
+     * Handles output sent to System.out by this task or its real task.
+     *
+     * @param line The line of output to log. Should not be <code>null</code>.
+     */
+    protected void handleOutput(String line) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleOutput(line);
+        } else {
+            super.handleOutput(line);
+        }
+    }
+
+    /**
+     * Handles error output sent to System.err by this task or its real task.
+     *
+     * @param line The error line to log. Should not be <code>null</code>.
+     */
+    protected void handleErrorOutput(String line) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleErrorOutput(line);
+        } else {
+            super.handleErrorOutput(line);
+        }
+    }
+
+    /**
+     * Executes the real object if it's a task. If it's not a task
+     * (e.g. a data type) then this method does nothing.
+     */
+    public void execute() {
+        if (realThing == null) {
+            // plain impossible to get here, maybeConfigure should
+            // have thrown an exception.
+            throw new BuildException("Could not create task of type: "
+                                     + elementName, getLocation());
+        }
+
+        if (realThing instanceof Task) {
+            ((Task) realThing).execute();
+        }
+        // the task will not be reused ( a new init() will be called )
+        // Let GC do its job
+        realThing=null;
+    }
+
+    /**
+     * Adds a child element to this element.
+     *
+     * @param child The child element to add. Must not be <code>null</code>.
+     */
+    public void addChild(UnknownElement child) {
+        children.addElement(child);
+    }
+
+    /**
+     * Creates child elements, creates children of the children
+     * (recursively), and sets attributes of the child elements.
+     *
+     * @param parent The configured object for the parent.
+     *               Must not be <code>null</code>.
+     *
+     * @param parentWrapper The wrapper containing child wrappers
+     *                      to be configured. Must not be <code>null</code>
+     *                      if there are any children.
+     *
+     * @exception BuildException if the children cannot be configured.
+     */
+    protected void handleChildren(Object parent,
+                                  RuntimeConfigurable parentWrapper)
+        throws BuildException {
+
+        if (parent instanceof TaskAdapter) {
+            parent = ((TaskAdapter) parent).getProxy();
+        }
+
+        Class parentClass = parent.getClass();
+        IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass);
+
+        for (int i = 0;  i < children.size(); i++) {
+            RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
+            UnknownElement child = (UnknownElement) children.elementAt(i);
+            Object realChild = null;
+
+            if (parent instanceof TaskContainer) {
+                ProjectComponentHelper helper=ProjectComponentHelper.getProjectComponentHelper();
+                // Used to be: makeTask(child, childWrapper, false);
+                realChild = helper.createProjectComponent( child, getProject(), null, 
+                                                           child.getTag());
+                if (realChild == null ) {
+                    throw getNotFoundException("task", child.getTag());
+                }
+
+                // XXX DataTypes will be wrapped or treated like normal components 
+                if( realChild instanceof Task ) {
+                    ((TaskContainer) parent).addTask((Task) realChild);
+                    Task task=(Task)realChild;
+                    task.setLocation(child.getLocation());
+                    // UnknownElement always has an associated target
+                    task.setOwningTarget(this.getOwningTarget());
+                    task.init();
+                } else {
+                    // What ? Add data type ? createElement ?
+                }
+            } else {
+                // Introspection-based task creation
+                realChild = ih.createElement(getProject(), parent, child.getTag());
+            }
+
+            childWrapper.setProxy(realChild);
+            if (parent instanceof TaskContainer) {
+                ((Task) realChild).setRuntimeConfigurableWrapper(childWrapper);
+            }
+
+            child.handleChildren(realChild, childWrapper);
+
+            if (parent instanceof TaskContainer) {
+                ((Task) realChild).maybeConfigure();
+            }
+        }
+    }
+
+    /**
+     * @deprecated no longer used
+     */
+    protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) {
+        /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+        return null;
+    }
+
+    /**
+     * @deprecated no longer used
+     */
+    protected Task makeTask(UnknownElement ue, RuntimeConfigurable w,
+                            boolean onTopLevel) {
+        /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+        return null;
+    }
+
+
+    /**
+     * Returns the name to use in logging messages.
+     *
+     * @return the name to use in logging messages.
+     */
+    public String getTaskName() {
+        return elementName; // cleaner, works for everything
+        //         return realThing == null || !(realThing instanceof Task) ?
+        //             super.getTaskName() : ((Task) realThing).getTaskName();
+    }
+
+    public Object getWrapped() {
+        return realThing;
+    }
+    
+    /**
+     * returns the task instance after it has been created and if it is a task.
+     *
+     * @return a task instance or <code>null</code> if the real object is not
+     *         a task.
+     */
+    public Task getTask() {
+        if (realThing instanceof Task) {
+            return (Task) realThing;
+        }
+        return null;
+    }
+
+}// UnknownElement
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/ProjectHelperImpl2.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/ProjectHelperImpl2.java
new file mode 100644
index 0000000..7e6e136
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/ProjectHelperImpl2.java
@@ -0,0 +1,1192 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.helper;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Stack;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.AttributeList;
+import org.xml.sax.helpers.XMLReaderAdapter;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.AttributeListImpl;
+
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Sax2 based project reader
+ *
+ */
+public class ProjectHelperImpl2 extends ProjectHelper {
+    /* Stateless */
+
+    // singletons - since all state is in the context
+    static AntHandler elementHandler=new ElementHandler();
+    static AntHandler targetHandler=new TargetHandler();
+    static AntHandler nestedElementHandler=new NestedElementHandler();
+    static AntHandler mainHandler=new MainHandler();
+    static AntHandler projectHandler=new ProjectHandler();
+
+    /**
+     * helper for path -&gt; URI and URI -&gt; path conversions.
+     */
+    private static FileUtils fu = FileUtils.newFileUtils();
+
+    /** Method to add several 'special' tasks that are specific
+     *  to this helper. In future we could use the properties file
+     */
+    private void hookSpecialTasks(Project project) {
+        try {
+            Class c=Class.forName("org.apache.tools.ant.taskdefs.SystemPath");
+            // deprecated
+            project.addTaskDefinition( "systemPath" , c );
+            // the new name ( in ant16 )
+            project.addTaskDefinition( "classloader" , c );
+
+            c=Class.forName("org.apache.tools.ant.taskdefs.Description");
+            project.addTaskDefinition( "description" , c );
+            c=Class.forName("org.apache.tools.ant.taskdefs.Import");
+            project.addTaskDefinition( "import" , c );
+            c=Class.forName("org.apache.tools.ant.taskdefs.Taskdef2");
+            project.addTaskDefinition( "taskdef" , c );
+//              try {
+//                 Task t=new TaskDiscovery();
+//                 t.setProject(project);
+//                 t.execute();
+//             } catch( Exception ex ) {
+//                 System.out.println("Can't load TaskDiscovery " + ex );
+//             }
+        } catch (Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+    
+
+    public void parse(Project project, Object source) throws BuildException {
+        hookSpecialTasks(project);
+        AntXmlContext context=new AntXmlContext(project, this);
+        
+        project.addReference( "ant.parsing.context", context );
+
+        parse(project, source,new RootHandler(context));
+
+        // XXX How to deal with description ??
+        context.implicitTarget.execute();
+    }
+
+    /**
+     * Parses the project file, configuring the project as it goes.
+     * 
+     * @exception BuildException if the configuration is invalid or cannot 
+     *                           be read
+     */
+    public void parse(Project project, Object source, RootHandler handler) throws BuildException {
+        
+        AntXmlContext context=handler.context;
+
+        if(source instanceof File) {
+            context.buildFile=(File)source;
+//         } else if( source instanceof InputStream ) {
+//         } else if( source instanceof URL ) {
+//         } else if( source instanceof InputSource ) {
+        } else {
+            throw new BuildException( "Source " + source.getClass().getName() +
+                                      " not supported by this plugin" );
+        }
+
+        FileInputStream inputStream = null;
+        InputSource inputSource = null;
+
+        context.buildFile = new File(context.buildFile.getAbsolutePath());
+        context.buildFileParent = new File(context.buildFile.getParent());
+        
+        try {
+            /**
+             * SAX 2 style parser used to parse the given file. 
+             */
+            context.parser =JAXPUtils.getXMLReader();
+
+            String uri = ProjectHelperImpl2.toURI(context.buildFile.getAbsolutePath());
+
+            //String uri = "file:" + context.buildFile.getAbsolutePath().replace('\\', '/');
+            //for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
+            //    uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
+            //}
+            
+            inputStream = new FileInputStream(context.buildFile);
+            inputSource = new InputSource(inputStream);
+            inputSource.setSystemId(uri);
+            System.err.println("Parsing with PH2: " + context.buildFile);
+            project.log("parsing buildfile " + context.buildFile + " with URI = " + uri, Project.MSG_VERBOSE);
+
+            DefaultHandler hb = handler;
+
+            context.parser.setContentHandler(hb);
+            context.parser.setEntityResolver(hb);
+            context.parser.setErrorHandler(hb);
+            context.parser.setDTDHandler(hb);
+            context.parser.parse(inputSource);
+        } catch(SAXParseException exc) {
+            Location location =
+                new Location(exc.getSystemId(), exc.getLineNumber(), exc.getColumnNumber());
+
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                BuildException be = (BuildException) t;
+                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+                    be.setLocation(location);
+                }
+                throw be;
+            }
+            
+            throw new BuildException(exc.getMessage(), t, location);
+        }
+        catch(SAXException exc) {
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                throw (BuildException) t;
+            }
+            throw new BuildException(exc.getMessage(), t);
+        }
+        catch(FileNotFoundException exc) {
+            throw new BuildException(exc);
+        }
+        catch(UnsupportedEncodingException exc) {
+              throw new BuildException("Encoding of project file is invalid.",exc);
+        }
+        catch(IOException exc) {
+            throw new BuildException("Error reading project file: " +exc.getMessage(), exc);
+        }
+        finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                }
+                catch (IOException ioe) {
+                    // ignore this
+                }
+            }
+        }
+    }
+
+    /**
+     * The common superclass for all SAX event handlers used to parse
+     * the configuration file. 
+     *
+     * The context will hold all state information. At each time
+     * there is one active handler for the current element. It can
+     * use onStartChild() to set an alternate handler for the child.
+     */ 
+    public static class AntHandler  {
+        /**
+         * Handles the start of an element. This base implementation does nothing.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void onStartElement(String uri, String tag, String qname,
+                                   Attributes attrs,
+                                   AntXmlContext context)
+            throws SAXParseException
+        {
+        }
+
+        /**
+         * Handles the start of an element. This base implementation just
+         * throws an exception - you must override this method if you expect
+         * child elements.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname,
+                                       Attributes attrs,
+                                       AntXmlContext context)
+            throws SAXParseException
+        {
+            throw new SAXParseException("Unexpected element \"" + qname + " \"", context.locator);
+        }
+
+        public void onEndChild(String uri, String tag, String qname,
+                                     AntXmlContext context)
+            throws SAXParseException
+        {
+        }
+
+        /**
+         * Called when this element and all elements nested into it have been
+         * handled (i.e. at the </end_tag_of_the_element> ).
+         */
+        public void onEndElement(String uri, String tag, AntXmlContext context) {
+        }
+
+        /**
+         * Handles text within an element. This base implementation just
+         * throws an exception, you must override it if you expect content.
+         * 
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * 
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void characters(char[] buf, int start, int count, AntXmlContext context)
+            throws SAXParseException
+        {
+            String s = new String(buf, start, count).trim();
+
+            if (s.length() > 0) {
+                throw new SAXParseException("Unexpected text \"" + s + "\"", context.locator);
+            }
+        }
+
+        /** Will be called every time a namespace is reached.
+            It'll verify if the ns was processed, and if not load the task definitions.
+        */
+        protected void checkNamespace( String uri ) {
+            
+        }
+    }
+
+    /** Context information for the ant processing.
+     */
+    public static class AntXmlContext {
+        /** The project to configure. */
+        private Project project;
+
+        /** The configuration file to parse. */
+        public File buildFile;
+
+        /** 
+         * Parent directory of the build file. Used for resolving entities
+         * and setting the project's base directory.
+         */
+        public File buildFileParent;
+
+        /** Name of the current project */
+        public String currentProjectName;
+
+        /** 
+         * Locator for the configuration file parser. 
+         * Used for giving locations of errors etc.
+         */
+        Locator locator;
+
+        // Do we need those ?
+        public ProjectHelperImpl2 helper;
+        org.xml.sax.XMLReader parser;
+
+         /**
+          * Target that all other targets will depend upon implicitly.
+          *
+          * <p>This holds all tasks and data type definitions that have
+          * been placed outside of targets.</p>
+          */
+        Target implicitTarget = new Target();
+
+        /** Current target ( no need for a stack as the processing model
+            allows only one level of target ) */
+        public Target currentTarget=null;
+
+        /** The stack of RuntimeConfigurable2 wrapping the
+            objects. 
+        */
+        Vector wStack=new Vector();
+
+        public Hashtable namespaces=new Hashtable();
+        
+        // Import stuff
+        public boolean ignoreProjectTag=false;
+        public Hashtable importedFiles = new Hashtable();
+        public int importlevel = 0;
+
+        public AntXmlContext(Project project, ProjectHelperImpl2 helper) {
+            this.project=project;
+            implicitTarget.setName("");
+            this.helper=helper;
+        }
+
+        public Project getProject() {
+            return project;
+        }
+
+        public RuntimeConfigurable2 currentWrapper() {
+            if( wStack.size() < 1 ) return null;
+            return (RuntimeConfigurable2)wStack.elementAt( wStack.size() - 1 );
+        }
+
+        public RuntimeConfigurable2 parentWrapper() {
+            if( wStack.size() < 2 ) return null;
+            return (RuntimeConfigurable2)wStack.elementAt( wStack.size() - 2 );
+        }
+
+        public void pushWrapper( RuntimeConfigurable2 wrapper ) {
+            wStack.addElement(wrapper);
+        }
+
+        public void popWrapper() {
+            if( wStack.size() > 0 ) 
+                wStack.removeElementAt( wStack.size() - 1 );
+        }
+
+        public Vector getWrapperStack() {
+            return wStack;
+        }
+        
+        /**
+         * Scans an attribute list for the <code>id</code> attribute and 
+         * stores a reference to the target object in the project if an
+         * id is found.
+         * <p>
+         * This method was moved out of the configure method to allow
+         * it to be executed at parse time.
+         * 
+         * @see #configure(Object,AttributeList,Project)
+         */
+        void configureId(Object element, Attributes attr) {
+            String id = attr.getValue("id");
+            if (id != null) {
+                project.addReference(id, element);
+            }
+        }
+
+    }
+    
+    /**
+     * Handler for ant processing. Uses a stack of AntHandlers to
+     * implement each element ( the original parser used a recursive behavior,
+     * with the implicit execution stack )
+     */
+    public static class RootHandler extends DefaultHandler {
+        Stack antHandlers=new Stack();
+        AntHandler currentHandler=null;
+        AntXmlContext context;
+        
+        public RootHandler(AntXmlContext context) {
+            currentHandler=ProjectHelperImpl2.mainHandler;
+            antHandlers.push( currentHandler );
+            this.context=context;
+        }
+        
+        /**
+         * Resolves file: URIs relative to the build file.
+         * 
+         * @param publicId The public identifer, or <code>null</code>
+         *                 if none is available. Ignored in this 
+         *                 implementation.
+         * @param systemId The system identifier provided in the XML 
+         *                 document. Will not be <code>null</code>.
+         */
+        public InputSource resolveEntity(String publicId,
+                                         String systemId) {
+        
+            context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
+        
+            if (systemId.startsWith("file:")) {
+                String path = ProjectHelperImpl2.fromURI(systemId);
+
+                File file = new File(path);
+                if (!file.isAbsolute()) {
+                    file = fu.resolveFile(context.buildFileParent, path);
+                }
+                try {
+                    InputSource inputSource = new InputSource(new FileInputStream(file));
+                    inputSource.setSystemId(ProjectHelperImpl2.toURI(file.getAbsolutePath()));
+                    return inputSource;
+                } catch (FileNotFoundException fne) {
+                    context.project.log(file.getAbsolutePath() + " could not be found",
+                            Project.MSG_WARN);
+                }
+
+            }
+            // use default if not file or file not found
+            return null;
+        }
+
+        /**
+         * Handles the start of a project element. A project handler is created
+         * and initialised with the element name and attributes.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if the tag given is not 
+         *                              <code>"project"</code>
+         */
+        public void startElement(String uri, String tag, String qname, Attributes attrs)
+            throws SAXParseException
+        {
+            AntHandler next=currentHandler.onStartChild(uri, tag, qname, attrs, context);
+            antHandlers.push( currentHandler );
+            currentHandler=next;
+            currentHandler.onStartElement( uri, tag, qname, attrs, context );
+        }
+
+        /**
+         * Sets the locator in the project helper for future reference.
+         * 
+         * @param locator The locator used by the parser.
+         *                Will not be <code>null</code>.
+         */
+        public void setDocumentLocator(Locator locator) {
+            context.locator = locator;
+        }
+
+        /**
+         * Handles the end of an element. Any required clean-up is performed
+         * by the onEndElement() method and then the original handler is restored to
+         * the parser.
+         * 
+         * @param name The name of the element which is ending.
+         *             Will not be <code>null</code>.
+         * 
+         * @exception SAXException in case of error (not thrown in 
+         *                         this implementation)
+         * 
+         */
+        public void endElement(String uri, String name, String qName) throws SAXException {
+            currentHandler.onEndElement(uri, name, context);
+            AntHandler prev=(AntHandler)antHandlers.pop();
+            currentHandler=prev;
+            if( currentHandler!=null )
+                currentHandler.onEndChild( uri, name, qName, context );
+        }
+
+        public void characters(char[] buf, int start, int count)
+            throws SAXParseException
+        {
+            currentHandler.characters( buf, start, count, context );
+        }
+    }
+
+    public static class MainHandler extends AntHandler {
+
+        public AntHandler onStartChild(String uri, String name, String qname,
+                                       Attributes attrs,
+                                       AntXmlContext context)
+            throws SAXParseException
+        {
+            if (qname.equals("project")) {
+                return ProjectHelperImpl2.projectHandler;
+            } else {
+//                 if( context.importlevel > 0 ) {
+//                     // we are in an imported file. Allow top-level <target>.
+//                     if( qname.equals( "target" ) )
+//                         return ProjectHelperImpl2.targetHandler;
+//                 }
+                throw new SAXParseException("Unexpected element \"" + qname + "\" " + name, context.locator);
+            }
+        }        
+    }
+    
+    /**
+     * Handler for the top level "project" element.
+     */
+    public static class ProjectHandler extends AntHandler {
+        
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"default"</code>,
+         * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
+         * 
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * 
+         * @exception SAXParseException if an unexpected attribute is 
+         *            encountered or if the <code>"default"</code> attribute
+         *            is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname,
+                                   Attributes attrs,
+                                   AntXmlContext context)
+            throws SAXParseException
+        {
+            String id = null;
+            String baseDir = null;
+
+            Project project=context.getProject();
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getQName(i);
+                String value = attrs.getValue(i);
+                
+                if (key.equals("default")) {
+                    if ( value != null && !value.equals("")) {
+                        if( !context.ignoreProjectTag )
+                            project.setDefaultTarget(value);
+                    }
+                } else if (key.equals("name")) {
+                    if (value != null) {
+                        context.currentProjectName=value;
+
+                        if( !context.ignoreProjectTag ) {
+                            project.setName(value);
+                            project.addReference(value, project);
+                        } 
+                    }
+                } else if (key.equals("id")) {
+                    if (value != null) {
+                        // What's the difference between id and name ?
+                        if( !context.ignoreProjectTag ) {
+                            project.addReference(value, project);
+                        }
+                    }
+                } else if (key.equals("basedir")) {
+                    if( !context.ignoreProjectTag )
+                        baseDir = value;
+                } else {
+                    // XXX ignore attributes in a different NS ( maybe store them ? )
+                    throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) + "\"", context.locator);
+                }
+            }
+
+            project.setUserProperty("ant.file."+context.currentProjectName,
+                    context.buildFile.toString());
+
+            if( context.ignoreProjectTag ) {
+                // no further processing
+                return;
+            }
+            // set explicitely before starting ?
+            if (project.getProperty("basedir") != null) {
+                project.setBasedir(project.getProperty("basedir"));
+            } else {
+                // Default for baseDir is the location of the build file.
+                if (baseDir == null) {
+                    project.setBasedir(context.buildFileParent.getAbsolutePath());
+                } else {
+                    // check whether the user has specified an absolute path
+                    if ((new File(baseDir)).isAbsolute()) {
+                        project.setBasedir(baseDir);
+                    } else {
+                        project.setBaseDir(project.resolveFile(baseDir,
+                                                               context.buildFileParent));
+                    }
+                }
+            }
+            
+            project.addTarget("", context.implicitTarget);
+            context.currentTarget=context.implicitTarget;
+        }
+
+        /**
+         * Handles the start of a top-level element within the project. An
+         * appropriate handler is created and initialised with the details
+         * of the element.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if the tag given is not 
+         *            <code>"taskdef"</code>, <code>"typedef"</code>,
+         *            <code>"property"</code>, <code>"target"</code>
+         *            or a data type definition
+         */
+        public AntHandler onStartChild(String uri, String name, String qname,
+                                       Attributes attrs,
+                                       AntXmlContext context)
+            throws SAXParseException
+        {
+            if (qname.equals("target")) {
+                return ProjectHelperImpl2.targetHandler;
+            } else {
+                return ProjectHelperImpl2.elementHandler;
+            } 
+        }
+
+    }
+
+    /**
+     * Handler for "target" elements.
+     */
+    public static class TargetHandler extends AntHandler {
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"name"</code>,
+         * <code>"depends"</code>, <code>"if"</code>,
+         * <code>"unless"</code>, <code>"id"</code> and 
+         * <code>"description"</code>.
+         * 
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * 
+         * @exception SAXParseException if an unexpected attribute is encountered
+         *            or if the <code>"name"</code> attribute is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname,
+                                   Attributes attrs,
+                                   AntXmlContext context)
+            throws SAXParseException
+        {
+            String name = null;
+            String depends = "";
+
+            Project project=context.getProject();
+            Target target = new Target();
+            context.currentTarget=target;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getQName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                    if( "".equals( name ) )
+                        throw new BuildException("name attribute must not be empty");
+                } else if (key.equals("depends")) {
+                    depends = value;
+                } else if (key.equals("if")) {
+                    target.setIf(value);
+                } else if (key.equals("unless")) {
+                    target.setUnless(value);
+                } else if (key.equals("id")) {
+                    if (value != null && !value.equals("")) {
+                        context.getProject().addReference(value, target);
+                    }
+                } else if (key.equals("description")) {
+                    target.setDescription(value);
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.locator);
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("target element appears without a name attribute",
+                                            context.locator);
+            }
+            
+            Hashtable currentTargets = project.getTargets();
+
+            // If the name has already beend defined ( import for example )
+            if(currentTargets.containsKey(name)) {
+                // Alter the name.
+                if( context.currentProjectName != null ) {
+                    String newName=context.currentProjectName + "." + name;
+                    project.log("Already defined in main or a previous import, define "
+                                + name + " as " + newName,
+                                Project.MSG_VERBOSE);
+                    name=newName;
+                } else {
+                    project.log("Already defined in main or a previous import, ignore "
+                                + name,
+                                Project.MSG_VERBOSE);
+                    name=null;
+                }
+            }
+
+            if( name != null ) {
+                target.setName(name);
+                project.addOrReplaceTarget(name, target);
+            }
+
+
+            project.log("Targets are now: "+ currentTargets ,
+                        Project.MSG_VERBOSE);
+
+            // take care of dependencies
+            if (depends.length() > 0) {
+                target.setDepends(depends);
+            }
+        }
+
+        /**
+         * Handles the start of an element within a target.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String name, String qname,
+                                       Attributes attrs,
+                                       AntXmlContext context)
+            throws SAXParseException
+        {
+            return ProjectHelperImpl2.elementHandler;
+        }
+        public void onEndElement(String uri, String tag, AntXmlContext context) {
+            context.currentTarget=context.implicitTarget;
+        }
+    }
+
+    /**
+     * Handler for all project elements ( tasks, data types )
+     */
+    public static class ElementHandler extends AntHandler {
+
+        /**
+         * Constructor.
+         */
+        public ElementHandler() {
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         * 
+         * @param tag Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         *            
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * 
+         * @exception SAXParseException in case of error (not thrown in
+         *                              this implementation)
+         */
+        public void onStartElement(String uri, String tag, String qname,
+                                   Attributes attrs,
+                                   AntXmlContext context)
+            throws SAXParseException
+        {
+            RuntimeConfigurable2 parentWrapper=context.currentWrapper();
+            RuntimeConfigurable2 wrapper=null;
+            
+            if (false && context.getProject().getDataTypeDefinitions().get(qname) != null) {
+/*
+  UnknownElement should work for data types as well. 
+                // We should eliminate the special treatement of data type.
+                try {
+                    Object element = context.getProject().createDataType(qname);
+                    if (element == null) {
+                        // can it happen ? We just checked that the type exists
+                        throw new BuildException("Unknown data type "+qname);
+                    }
+                
+                    wrapper = new RuntimeConfigurable2(context.getProject(), null, element, qname);
+                    wrapper.setAttributes2(attrs);
+                    context.currentTarget.addDataType(wrapper);
+                } catch (BuildException exc) {
+                    throw new SAXParseException(exc.getMessage(), context.locator, exc);
+                }
+*/
+            } else {
+                Task task=null;
+                /*
+                // Don't try to create the task now - for consistency and to
+                // simplify the model it is better to keep everything lazy
+
+                try {
+                    task = context.getProject().createTask(qname);
+                } catch (BuildException e) {
+                    // swallow here, will be thrown again in 
+                    // UnknownElement.maybeConfigure if the problem persists.
+                }
+
+                // The consequence of lazy eval - UnknownElement must deal with
+                // TaskContainer case.
+                */
+
+                if (task == null) {
+                    task = new UnknownElement2(qname);
+                    task.setProject(context.getProject());
+                    //XXX task.setTaskType(qname);
+                    task.setTaskName(qname);
+                }
+
+                Location location=new Location(context.locator.getSystemId(),
+                                               context.locator.getLineNumber(),
+                                               context.locator.getColumnNumber());
+                task.setLocation(location);
+                context.configureId(task, attrs);
+                
+                task.setOwningTarget(context.currentTarget);
+
+                Object parent=null;
+                if( parentWrapper!=null ) {
+                    parent=parentWrapper.getProxy();
+                }
+
+                // With lazy eval, parent will also be UnknwonElement ( even if the task
+                // is a TaskContainer ). It is UnknownElement who must check this.
+                if( parent instanceof TaskContainer ) {
+                    // Task included in a TaskContainer
+                    System.err.println("Shouldn't happen ");
+                    /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+                    ((TaskContainer)parent).addTask( task );
+                } else {
+                    // Task included in a target ( including the default one ).
+                    context.currentTarget.addTask( task );
+                }
+                // container.addTask(task);
+                task.init();
+
+                wrapper=new RuntimeConfigurable2(context.getProject(), location, task, task.getTaskName());
+                wrapper.setAttributes2(attrs);
+
+                if (parentWrapper != null) {
+                    parentWrapper.addChild(wrapper);
+                }
+            }
+
+            context.pushWrapper( wrapper );
+        }
+
+
+        /**
+         * Adds text to the task, using the wrapper
+         * 
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * 
+         * @exception SAXParseException if the element doesn't support text
+         * 
+         * @see ProjectHelper#addText(Project,Object,char[],int,int)
+         */
+        public void characters(char[] buf, int start, int count,
+                               AntXmlContext context)
+            throws SAXParseException
+        {
+            RuntimeConfigurable2 wrapper=context.currentWrapper();
+            wrapper.addText(buf, start, count);
+        }
+        
+        /**
+         * Handles the start of an element within a target. Task containers
+         * will always use another task handler, and all other tasks
+         * will always use a nested element handler.
+         * 
+         * @param tag The name of the element being started. 
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * 
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname,
+                                       Attributes attrs,
+                                       AntXmlContext context)
+            throws SAXParseException
+        {
+            // this element
+            RuntimeConfigurable2 wrapper=context.currentWrapper();
+            
+            Object element=wrapper.getProxy();
+            if (element instanceof TaskContainer) {
+                // task can contain other tasks - no other nested elements possible
+                // This will be handled inside UE
+                System.err.println("Shouldn't happen - UE");
+                /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+                return ProjectHelperImpl2.elementHandler;
+            }
+            else {
+                return ProjectHelperImpl2.nestedElementHandler;
+            }
+        }
+
+        public void onEndElement(String uri, String tag, AntXmlContext context) {
+            context.popWrapper();
+        }
+
+        public void onEndChild(String uri, String tag, String qname,
+                                     AntXmlContext context)
+            throws SAXParseException
+        {
+        }
+    }
+
+    /**
+     * Handler for all nested properties. Same as ElementHandler, except that
+     * it doesn't deal with DataTypes and doesn't support TaskContainer.
+     *
+     * This is the original behavior - I just made few changes to avoid duplicated
+     * code.
+     */
+    public static class NestedElementHandler extends ElementHandler {
+        /**
+         * Constructor.
+         */
+        public NestedElementHandler() {
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         * 
+         * @param tag Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         *            
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * 
+         * @exception SAXParseException in case of error, such as a 
+         *            BuildException being thrown during configuration.
+         */
+        public void onStartElement(String uri, String propType, String qname,
+                                   Attributes attrs,
+                                   AntXmlContext context)
+            throws SAXParseException
+        {
+            RuntimeConfigurable2 parentWrapper=context.currentWrapper();
+            RuntimeConfigurable2 wrapper=null;
+            try {
+                Object element;
+                Object parent=parentWrapper.getProxy();
+
+                // Parent will allways be UnknownElement. 
+                if (parent instanceof TaskAdapter) {
+                    System.err.println("Shouldn't happen ");
+                    /*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
+                    parent = ((TaskAdapter) parent).getProxy();
+                }
+                
+                String elementName = qname.toLowerCase(Locale.US);
+                if (parent instanceof UnknownElement) {
+                    UnknownElement uc = new UnknownElement2(elementName);
+                    uc.setProject(context.getProject());
+                    ((UnknownElement) parent).addChild(uc);
+                    element = uc;
+                } else {
+                    // It may be a data type. Will be removed when we consolidate UE/RC
+                    Class parentClass = parent.getClass();
+                    IntrospectionHelper ih = 
+                        IntrospectionHelper.getHelper(parentClass);
+                    element = ih.createElement(context.getProject(), parent, elementName);
+                }
+
+                context.configureId(element, attrs);
+
+                wrapper = new RuntimeConfigurable2(context.getProject(), null, element, qname);
+                wrapper.setAttributes2(attrs);
+                parentWrapper.addChild(wrapper);
+            } catch (BuildException exc) {
+                throw new SAXParseException(exc.getMessage(), context.locator, exc);
+            }
+            context.pushWrapper( wrapper );
+        }
+    }
+
+    // --------------------  Backward compatibility with 1.5  --------------------
+
+    /**
+     * Constructs a <code>file:</code> URI that represents the
+     * external form of the given pathname.
+     *
+     * <p>Will be an absolute URI if the given path is absolute.</p>
+     *
+     * <p>This code doesn't handle non-ASCII characters properly.</p>
+     *
+     * @since Ant 1.6
+     */
+    public static String toURI(String path) {
+        StringBuffer sb = new StringBuffer("file:");
+
+        // catch exception if normalize thinks this is not an absolute path
+        try {
+            path = fu.normalize(path).getAbsolutePath();
+            sb.append("//");
+            // add an extra slash for filesystems with drive-specifiers
+            if (!path.startsWith("/")) {
+                sb.append("/");
+            }
+
+        } catch (BuildException e) {
+            // relative path
+        }
+
+        path = path.replace('\\', '/');
+        CharacterIterator iter = new StringCharacterIterator(path);
+        for (char c = iter.first(); c != CharacterIterator.DONE;
+             c = iter.next()) {
+            if (isSpecial[c]) {
+                sb.append('%');
+                sb.append(escapedChar1[c]);
+                sb.append(escapedChar2[c]);
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Constructs a file path from a <code>file:</code> URI.
+     *
+     * <p>Will be an absolute path if the given URI is absolute.</p>
+     *
+     * <p>Swallows '%' that are not followed by two characters,
+     * doesn't deal with non-ASCII characters.</p>
+     *
+     * @since Ant 1.6
+     */
+    public static String fromURI(String uri) {
+        if (!uri.startsWith("file:")) {
+            throw new IllegalArgumentException("Can only handle file: URIs");
+        }
+        if (uri.startsWith("file://")) {
+            uri = uri.substring(7);
+        } else {
+            uri = uri.substring(5);
+        }
+
+        uri = uri.replace('/', File.separatorChar);
+        if (Os.isFamily("dos") && uri.startsWith("\\") && uri.length() > 2
+                && Character.isLetter(uri.charAt(1)) && uri.charAt(2) == ':') {
+            uri = uri.substring(1);
+        }
+
+        StringBuffer sb = new StringBuffer();
+        CharacterIterator iter = new StringCharacterIterator(uri);
+        for (char c = iter.first(); c != CharacterIterator.DONE;
+             c = iter.next()) {
+            if (c == '%') {
+                char c1 = iter.next();
+                if (c1 != CharacterIterator.DONE) {
+                    int i1 = Character.digit(c1, 16);
+                    char c2 = iter.next();
+                    if (c2 != CharacterIterator.DONE) {
+                        int i2 = Character.digit(c2, 16);
+                        sb.append((char) ((i1 << 4) + i2));
+                    }
+                }
+            } else {
+                sb.append(c);
+            }
+        }
+
+        String path = sb.toString();
+        // catch exception if normalize thinks this is not an absolute path
+        try {
+            path = fu.normalize(path).getAbsolutePath();
+        } catch (BuildException e) {
+            // relative path
+        }
+        return path;
+    }
+    // for toURI
+    private static boolean[] isSpecial = new boolean[256];
+    private static char[] escapedChar1 = new char[256];
+    private static char[] escapedChar2 = new char[256];
+
+
+    // stolen from FilePathToURI of the Xerces-J team
+    static {
+        for (int i = 0; i <= 0x20; i++) {
+            isSpecial[i] = true;
+            escapedChar1[i] = Character.forDigit(i >> 4, 16);
+            escapedChar2[i] = Character.forDigit(i & 0xf, 16);
+        }
+        isSpecial[0x7f] = true;
+        escapedChar1[0x7f] = '7';
+        escapedChar2[0x7f] = 'F';
+        char[] escChs = {'<', '>', '#', '%', '"', '{', '}',
+                         '|', '\\', '^', '~', '[', ']', '`'};
+        int len = escChs.length;
+        char ch;
+        for (int i = 0; i < len; i++) {
+            ch = escChs[i];
+            isSpecial[ch] = true;
+            escapedChar1[ch] = Character.forDigit(ch >> 4, 16);
+            escapedChar2[ch] = Character.forDigit(ch & 0xf, 16);
+        }
+    }
+
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/TaskAdapter2.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/TaskAdapter2.java
new file mode 100644
index 0000000..dfc86f3
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/helper/TaskAdapter2.java
@@ -0,0 +1,196 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.helper;
+
+import java.lang.reflect.Method;
+import org.apache.tools.ant.*;
+
+/**
+ * Uses introspection to "adapt" an arbitrary Bean which doesn't
+ * itself extend Task, but still contains an execute method and optionally 
+ * a setProject method.
+ *
+ *  The adapter can also be used to wrap tasks that are loaded in a different class loader
+ *  by ant, when used in programatic mode.
+ *
+ */
+public class TaskAdapter2 extends Task { // implements DynamicConfigurator {
+    /* Need to support DynamicConfigurator so that adapted tasks can
+       support that too.
+    */
+    
+    /** Object to act as a proxy for. */
+    private Object proxy;
+    private String methodName="execute";
+    
+    private IntrospectionHelper ih;
+
+    void setIntrospectionHelper( IntrospectionHelper ih ) {
+        this.ih=ih;
+    }
+
+    IntrospectionHelper getIntrospectionHelper()
+    {
+        if( ih==null ) {
+            ih = IntrospectionHelper.getHelper(target.getClass());
+        }
+        return ih;
+    }
+
+    public void setDynamicAttribute(String name, String value)
+            throws BuildException
+    {
+        setAttribute( name, value );
+    }
+
+    public Object createDynamicElement(String name) throws BuildException
+    {
+        return null;
+    }
+
+    
+    /** Experimental, non-public method for better 'adaptation'
+     *
+     */
+    void setAttribute( String name, String value )
+        throws BuildException
+    {
+        try {
+            ih.setAttribute( project, proxy, name, value );
+        } catch( BuildException ex ) {
+            if( "do".equals( name ) ) {
+                setDo( value );
+            } else {
+                throw ex;
+            }
+        }
+    }
+        
+    /** Set the 'action' method. This allow beans implementing multiple
+     * actions or using methods other than 'execute()' to be used in ant
+     * without any modification.
+     * 
+     *  @ant:experimental 
+     */
+    public void setDo(String methodName ) {
+        this.methodName=methodName;
+    }
+    
+    /**
+     * Executes the proxied task.
+     */
+    public void execute() throws BuildException {
+        Method setProjectM = null;
+        try {
+            Class c = proxy.getClass();
+            setProjectM = 
+                c.getMethod( "setProject", new Class[] {Project.class});
+            if(setProjectM != null) {
+                setProjectM.invoke(proxy, new Object[] {project});
+            }
+        } catch (NoSuchMethodException e) {
+             // ignore this if the class being used as a task does not have
+            // a set project method.
+        } catch( Exception ex ) {
+            log("Error setting project in " + proxy.getClass(), 
+                Project.MSG_ERR);
+            throw new BuildException( ex );
+        }
+
+
+        Method executeM=null;
+        try {
+            Class c=proxy.getClass();
+            executeM=c.getMethod( methodName, new Class[0] );
+            if( executeM == null ) {
+                log("No public " + methodName + "() in " + proxy.getClass(), Project.MSG_ERR);
+                throw new BuildException("No public " + methodName +"() in " + proxy.getClass());
+            }
+            executeM.invoke(proxy, null);
+            return; 
+        } catch (java.lang.reflect.InvocationTargetException ie) {
+            log("Error in " + proxy.getClass(), Project.MSG_ERR);
+            Throwable t = ie.getTargetException();
+            if (t instanceof BuildException) {
+                throw ((BuildException) t);
+            } else {
+                throw new BuildException(t);
+            }
+        } catch( Exception ex ) {
+            log("Error in " + proxy.getClass(), Project.MSG_ERR);
+            throw new BuildException( ex );
+        }
+
+    }
+    
+    /**
+     * Sets the target object to proxy for.
+     * 
+     * @param o The target object. Must not be <code>null</code>.
+     */
+    public void setProxy(Object o) {
+        this.proxy = o;
+    }
+
+    /**
+     * Returns the target object being proxied.
+     * 
+     * @return the target proxy object
+     */
+    public Object getProxy() {
+        return this.proxy ;
+    }
+
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Description.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Description.java
new file mode 100644
index 0000000..4c1e818
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Description.java
@@ -0,0 +1,90 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Description task. If top level tasks are executed during processing, import
+ * and description can be regular tasks, with no need for special code in processor.
+ *
+ * ( this only works for top-level descr. AFAIK that's how it works in ant1.5 )
+ * If this would be extended for <description> elements in targets - a special
+ * construct would be needed to mark this as 'parsing time' task.
+ * 
+ */
+public class Description extends Task {
+    String descr;
+    
+    public Description() {
+    }
+
+    public String getDescription() {
+        return descr;
+    }
+
+    public void addText( String text ) {
+        this.descr=text;
+    }
+
+    public void execute() throws BuildException {
+        project.setDescription( descr );
+    }
+}
+
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Import.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Import.java
new file mode 100644
index 0000000..8f0304d
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Import.java
@@ -0,0 +1,179 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.helper.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Stack;
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.AttributeList;
+import org.xml.sax.helpers.XMLReaderAdapter;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.AttributeListImpl;
+
+import org.apache.tools.ant.util.JAXPUtils;
+
+/**
+ * Import task.
+ *
+ * It must be 'top level'. On execution it'll read another file
+ * into the same Project. 
+ *
+ */
+public class Import extends Task {
+    String file;
+
+    public void setFile( String file ) {
+        // I don't think we can use File - different rules
+        // for relative paths.
+        this.file=file;
+    }
+    
+    /**
+     * Initialisation routine called after handler creation
+     * with the element name and attributes. The attributes which
+     * this handler can deal with are: <code>"default"</code>,
+     * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
+     *
+     * @param tag Name of the element which caused this handler
+     *            to be created. Should not be <code>null</code>.
+     *            Ignored in this implementation.
+     * @param attrs Attributes of the element which caused this
+     *              handler to be created. Must not be <code>null</code>.
+     *
+     * @exception SAXParseException if an unexpected attribute is
+     *            encountered or if the <code>"default"</code> attribute
+     *            is missing.
+     */
+    public void execute() throws BuildException
+    {
+        if (file == null) {
+            throw new BuildException("import element appears without a file attribute");
+        }
+    
+        ProjectHelperImpl2.AntXmlContext context;
+        context=(ProjectHelperImpl2.AntXmlContext)project.getReference("ant.parsing.context");
+
+        context.importlevel++;
+
+        project.log("importlevel: "+(context.importlevel-1)+" -> "+(context.importlevel),
+                    Project.MSG_DEBUG);
+        project.log("Importing file "+file+" from "+
+                    context.buildFile.getAbsolutePath(),
+                    Project.MSG_VERBOSE);
+
+        // Paths are relative to the build file they're imported from,
+        // *not* the current directory (same as entity includes).
+        File importedFile = new File(file);
+        if (!importedFile.isAbsolute()) {
+            importedFile = new File(context.buildFileParent, file);
+        }
+        if (!importedFile.exists()) {
+                throw new BuildException("Cannot find "+file+" imported from "+
+                                         context.buildFile.getAbsolutePath());
+        }
+        
+        // Add parent build file to the map to avoid cycles...
+        String parentFilename = getPath(context.buildFile);
+        if (!context.importedFiles.containsKey(parentFilename)) {
+            context.importedFiles.put(parentFilename, context.buildFile);
+        }
+
+        // Make sure we import the file only once
+        String importedFilename = getPath(importedFile);
+        if (context.importedFiles.containsKey(importedFilename)) {
+            project.log("\nSkipped already imported file:\n   "+importedFilename+"\n",
+                        Project.MSG_WARN);
+            context.importlevel--;
+            project.log("importlevel: "+context.importlevel+" <- "+
+                        (context.importlevel+1) ,Project.MSG_DEBUG);          
+            return;
+        } else {
+            context.importedFiles.put(importedFilename, importedFile);
+        }
+    
+        context.ignoreProjectTag=true;
+        context.helper.parse(project, importedFile, new ProjectHelperImpl2.RootHandler(context));
+        
+        context.importlevel--;
+        project.log("importlevel: "+context.importlevel+" <- "+
+                            (context.importlevel+1) ,Project.MSG_DEBUG);          
+    }
+    
+    private static String getPath(File file) {
+        try {
+            return file.getCanonicalPath();
+        }
+        catch (IOException e) {
+            return file.getAbsolutePath();
+        }
+    }
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/SystemPath.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/SystemPath.java
new file mode 100644
index 0000000..916b85b
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/SystemPath.java
@@ -0,0 +1,227 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import java.io.*;
+import java.util.*;
+import org.xml.sax.Locator;
+import org.xml.sax.InputSource;
+//import org.xml.sax.HandlerBase;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXException;
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.AttributeList;
+import org.xml.sax.helpers.XMLReaderAdapter;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.AttributeListImpl;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * Specify a system path, to be used to load optional.jar and all
+ * related libraries.
+ *
+ * Using the specified path it'll try to load or reload all optional
+ * tasks. The typical use is:
+ * <pre>
+ *  &lt;path id="ant.deps" &gt;
+ *     &lt;fileset ... /&gt;
+ *  &lt;/path&gt;
+ *
+ *  &lt;systemPath pathRef="ant.deps" /&gt;
+ *
+ *  &lt;junit ... /&gt;
+ * </pre>
+ *
+ * This requires that ant-sax2.jar is included in ant/lib.
+ *
+ * It has a single property, a reference to a &lt;path&gt; containing all
+ * the jars that you need. It'll automatically reload optional.jar
+ * tasks in a different (non-delegating) loader.
+ *
+ */
+public class SystemPath extends Task {
+    public static final String SYSTEM_LOADER_REF="ant.system.loader";
+    
+    public SystemPath() {
+    }
+
+    public void setPathRef( Reference pathRef ) throws BuildException {
+        setClasspathRef( pathRef );
+    }
+
+    /** Specify which path will be used.
+     */
+    public void setClasspathRef( Reference pathRef ) throws BuildException {
+        Path path=(Path)pathRef.getReferencedObject(project);
+
+        initSystemLoader(path);
+
+    }
+    
+    /** Will prepare the class loader to allow dynamic modifications
+     *   of the classpath. Optional tasks are loaded in a different loader.
+     */
+    private void initSystemLoader(Path path) {
+        try {
+            //if( project.getReference( SYSTEM_LOADER_REF ) != null )
+            //    return; // already done that.
+            
+            // reverse loader
+            AntClassLoader acl=(AntClassLoader)project.getReference(SYSTEM_LOADER_REF);
+            if( acl==null ) {
+                acl=new AntClassLoader( this.getClass().getClassLoader(), true );
+                acl.addLoaderPackageRoot( "org.apache.tools.ant.taskdefs.optional");
+                project.addReference( SYSTEM_LOADER_REF, acl );
+            }
+
+
+            String list[]=path.list();
+            for( int i=0; i<list.length; i++ ) {
+                File f= new File( list[i] );
+                if( f.exists() ) {
+                    acl.addPathElement(f.getAbsolutePath());
+                    log("Adding to class loader " +  acl + " " + f.getAbsolutePath(),
+                        Project.MSG_DEBUG);
+                }
+            }
+            
+            // XXX find the classpath - add the optional jars.
+            String antHome=project.getProperty( "ant.home" );
+            File optionalJar=new File( antHome + "/lib/optional.jar" );
+            if( optionalJar.exists() )
+                acl.addPathElement(optionalJar.getAbsolutePath() );
+
+            // reinit the loader for optional, if they were in /lib/
+            Hashtable tasks=project.getTaskDefinitions();
+
+            //System.out.println("Replacing jars" );
+            // reload all optional tasks in this loader.
+            // Some tasks weren't defined by the normal init(), since deps were missing.
+            String defs = "/org/apache/tools/ant/taskdefs/defaults.properties";
+
+            try {
+                Properties props = new Properties();
+                InputStream in = this.getClass().getResourceAsStream(defs);
+                if (in == null) {
+                    throw new BuildException("Can't load default task list");
+                }
+                props.load(in);
+                in.close();
+
+                Enumeration enum = tasks.keys();
+                while(  enum.hasMoreElements()) {
+                    String key = (String) enum.nextElement();
+                    Class c=(Class)tasks.get(key);
+                    if( ! c.getName().startsWith( "org.apache.tools.ant.taskdefs.optional" ))
+                        continue;
+                    // other classes that needs to be replaced ??
+                    try {
+                        Class taskClass = acl.loadClass(c.getName());
+                        //project.addTaskDefinition(key, taskClass);
+                        project.getTaskDefinitions().put(key, taskClass);
+                        //System.out.println("Loaded " + key + " " + taskClass.getClassLoader() );
+                    } catch (NoClassDefFoundError ncdfe) {
+                        log("Could not load a dependent class ("
+                            + ncdfe.getMessage() + ") for task " + key, Project.MSG_DEBUG);
+                    } catch (ClassNotFoundException cnfe) {
+                        log("Could not load class (" + c.getName()
+                            + ") for task " + key, Project.MSG_DEBUG);
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+
+                // Some tasks couldn't be defined on the first run
+                enum = props.propertyNames();
+                while (enum.hasMoreElements()) {
+                    String key = (String) enum.nextElement();
+                    String value = props.getProperty(key);
+                    if( ! value.startsWith( "org.apache.tools.ant.taskdefs.optional" ))
+                        continue;
+                    if( tasks.get( key ) != null )
+                        continue;
+                    // other classes that needs to be replaced ??
+                    try {
+                        Class taskClass = acl.loadClass(value);
+                        //project.addTaskDefinition(key, taskClass);
+                        project.getTaskDefinitions().put(key, taskClass);
+                        //System.out.println("Loaded " + key + " " + taskClass.getClassLoader() );
+                    } catch (NoClassDefFoundError ncdfe) {
+                        log("Could not load a dependent class ("
+                            + ncdfe.getMessage() + ") for task " + key, Project.MSG_DEBUG);
+                    } catch (ClassNotFoundException cnfe) {
+                        log("Could not load class (" + value
+                            + ") for task " + key, Project.MSG_DEBUG);
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            } catch (IOException ioe) {
+                throw new BuildException("Can't load default task list");
+            }
+            
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Taskdef2.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Taskdef2.java
new file mode 100644
index 0000000..646cf8b
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/Taskdef2.java
@@ -0,0 +1,347 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+import java.io.*;
+import java.util.*;
+
+// XXX Had to cut&paste the code in Definer - since most fields are private
+// and no accessor is available.
+
+/**
+ * Special version of taskdef using the configurable ant class loader.
+ * It will also have additional features ( META-INF/ant.properties ,etc ).
+ * 
+ *
+ * @since Ant 1.6
+ * @ant.task category="internal"
+ */
+public class Taskdef2 extends Definer {
+    private String name;
+    private String value;
+    private Path classpath;
+    private File file;
+    private String resource;
+    private boolean reverseLoader = false;
+    private String loaderId = null;
+    private String classpathId = null;
+
+    private static final String REUSE_LOADER_REF = "ant.reuse.loader";
+
+    /**
+     * @deprecated stop using this attribute
+     * @ant.attribute ignore="true"
+     */
+    public void setReverseLoader(boolean reverseLoader) {
+        this.reverseLoader = reverseLoader;
+        log("The reverseloader attribute is DEPRECATED. It will be removed",
+            Project.MSG_WARN);
+    }
+
+    /**
+     * Set the classpath to be used when searching for component being defined
+     *
+     * @param classpath an Ant Path object containing the classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Create the classpath to be used when searching for component being defined
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * reference to a classpath to use when loading the files.
+     * To actually share the same loader, set loaderref as well
+     */
+    public void setClasspathRef(Reference r) {
+        classpathId=r.getRefId();
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Use the reference to locate the loader. If the loader is not
+     * found, taskdef will use the specified classpath and register it
+     * with the specified name.
+     *
+     * This allow multiple taskdef/typedef to use the same class loader,
+     * so they can be used together. It eliminate the need to
+     * put them in the CLASSPATH.
+     *
+     * @since Ant 1.5
+     */
+    public void setLoaderRef(Reference r) {
+        loaderId = r.getRefId();
+    }
+
+
+    public void execute() throws BuildException {
+        AntClassLoader al = createLoader();
+
+        if (file == null && resource == null) {
+
+            // simple case - one definition
+            if (name == null || value == null) {
+                String msg = "name or classname attributes of "
+                    + getTaskName() + " element "
+                    + "are undefined";
+                throw new BuildException(msg);
+            }
+            addDefinition(al, name, value);
+
+        } else {
+
+            InputStream is = null;
+            try {
+                if (name != null || value != null) {
+                    String msg = "You must not specify name or value "
+                        + "together with file or resource.";
+                    throw new BuildException(msg, getLocation());
+                }
+
+                if (file != null && resource != null) {
+                    String msg = "You must not specify both, file and "
+                        + "resource.";
+                    throw new BuildException(msg, getLocation());
+                }
+
+
+                Properties props = new Properties();
+                if (file != null) {
+                    log("Loading definitions from file " + file,
+                        Project.MSG_VERBOSE);
+                    is = new FileInputStream(file);
+                    if (is == null) {
+                        log("Could not load definitions from file " + file
+                            + ". It doesn\'t exist.", Project.MSG_WARN);
+                    }
+                }
+                if (resource != null) {
+                    log("Loading definitions from resource " + resource,
+                        Project.MSG_VERBOSE);
+                    is = al.getResourceAsStream(resource);
+                    if (is == null) {
+                        log("Could not load definitions from resource "
+                            + resource + ". It could not be found.",
+                            Project.MSG_WARN);
+                    }
+                }
+
+                if (is != null) {
+                    props.load(is);
+                    Enumeration keys = props.keys();
+                    while (keys.hasMoreElements()) {
+                        String n = (String) keys.nextElement();
+                        String v = props.getProperty(n);
+                        addDefinition(al, n, v);
+                    }
+                }
+            } catch (IOException ex) {
+                throw new BuildException(ex, getLocation());
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {}
+                }
+            }
+        }
+    }
+
+    /**
+     * create the classloader then hand the definition off to the subclass;
+     * @throws BuildException when the class wont load for any reason
+     */
+    protected void addDefinition(ClassLoader al, String name, String value)
+        throws BuildException {
+        try {
+            Class c = al.loadClass(value);
+            AntClassLoader.initializeClass(c);
+            addDefinition(name, c);
+        } catch (ClassNotFoundException cnfe) {
+            String msg = getTaskName() + " class " + value
+                + " cannot be found";
+            throw new BuildException(msg, cnfe, getLocation());
+        } catch (NoClassDefFoundError ncdfe) {
+            String msg = getTaskName() + " class " + value
+                + " cannot be found";
+            throw new BuildException(msg, ncdfe, getLocation());
+        }
+    }
+
+    /**
+     * create a classloader for this definition
+     */
+    protected AntClassLoader createLoader() {
+        // magic property
+        if (getProject().getProperty(REUSE_LOADER_REF) != null) {
+            // Generate the 'reuse' name automatically from the reference.
+            // This allows <taskdefs> that work on both ant1.4 and ant1.5.
+            // ( in 1.4 it'll require the task/type to be in classpath if they
+            //   are used togheter ).
+            if (loaderId == null && classpathId != null) {
+                loaderId = "ant.loader." + classpathId;
+            }
+        }
+
+        // If a loader has been set ( either by loaderRef or magic property )
+        if (loaderId != null) {
+            Object reusedLoader = getProject().getReference(loaderId);
+            if (reusedLoader != null) {
+                if (reusedLoader instanceof AntClassLoader) {
+                    return (AntClassLoader)reusedLoader;
+                }
+                // In future the reference object may be the <loader> type
+                // if( reusedLoader instanceof Loader ) {
+                //      return ((Loader)reusedLoader).getLoader(project);
+                // }
+            }
+        }
+
+        AntClassLoader al = (AntClassLoader)project.getReference( "ant.system.loader" );
+        if( al==null ) {
+            if (classpath != null) {
+                al = new AntClassLoader(getProject(), classpath, !reverseLoader);
+            } else {
+                al = new AntClassLoader(getProject(), Path.systemClasspath,
+                                        !reverseLoader);
+            }
+        } else {
+            if (classpath != null) {
+                al = new AntClassLoader(al, getProject(), classpath, !reverseLoader);
+            } else {
+                al = new AntClassLoader(al, getProject(), Path.systemClasspath,
+                                        !reverseLoader);
+            }
+        }
+        // need to load Task via system classloader or the new
+        // task we want to define will never be a Task but always
+        // be wrapped into a TaskAdapter.
+        al.addSystemPackageRoot("org.apache.tools.ant");
+
+
+        // If the loader is new, record it for future uses by other
+        // task/typedefs
+        if (loaderId != null) {
+            if (getProject().getReference(loaderId) == null) {
+                getProject().addReference(loaderId, al);
+            }
+        }
+
+        return al;
+    }
+
+    /**
+     * Name of the property file  to load
+     * ant name/classname pairs from.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Name of the property resource to load
+     * ant name/classname pairs from.
+     */
+    public void setResource(String res) {
+        this.resource = res;
+    }
+
+    /**
+     * Name of the property resource to load
+     * ant name/classname pairs from.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the classname of the object we are defining. 
+     * May be <code>null</code>.
+     */
+    public String getClassname() {
+        return value;
+    }
+
+    /**
+     * The full class name of the object being defined.
+     * Required, unless file or resource have
+     * been specified.
+     */
+    public void setClassname(String v) {
+        value = v;
+    }
+
+    /**
+     * subclassed handler for definitions; called by parent during
+     * execution.
+     */
+    protected void addDefinition(String name, Class c) throws BuildException {
+        getProject().addTaskDefinition(name, c);
+    }
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/XMLDOM.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/XMLDOM.java
new file mode 100644
index 0000000..0283b1b
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/XMLDOM.java
@@ -0,0 +1,138 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+/**
+ * Loads an xml file as DOM in a DataType
+ *
+ */
+public class XMLDOM extends DataType {
+    /** The name of this data type */
+    public static final String DATA_TYPE_NAME = "xmldom";
+
+    private File xmlfile = null;
+    private Document docRoot = null;
+
+    public XMLDOM() {
+    }
+
+    public void setFile(File xmlfile) {
+        this.xmlfile = xmlfile;
+    }
+
+    /***
+     * Gets the Document root of the DOM 
+     * given project.
+     */
+    public Document getRoot() {
+      if(docRoot==null){
+        try{
+          DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+          //FIXME eventually set DocumentBuilderFactory properties in the future 
+          DocumentBuilder builder = factory.newDocumentBuilder();
+          //FIXME eventually set DocumentBuilder properties in the future 
+          this.docRoot = builder.parse(xmlfile);
+        }
+        catch(ParserConfigurationException pce){
+          throw new BuildException("Error in the configuration of the parser", pce);
+        }
+        catch(SAXException se){
+          throw new BuildException("Error during parsing", se);
+        }
+        catch(IOException ioe){
+          throw new BuildException("Can't load the specified file", ioe);
+        }
+      }      
+      
+      return docRoot;
+    }
+
+
+    /***
+     * Get the RegularExpression this reference refers to in
+     * the given project.  Check for circular references too
+     */
+/*
+    public Substitution getRef(Project p) {
+        if (!isChecked()) {
+            Stack stk = new Stack();
+            stk.push(this);
+            dieOnCircularReference(stk, p);
+        }
+
+        
+        Object o = getRefid().getReferencedObject(p);
+        if (!(o instanceof Substitution)) {
+            String msg = getRefid().getRefId() + " doesn\'t denote a substitution";
+            throw new BuildException(msg);
+        } else {
+            return (Substitution) o;
+        }
+    }
+*/
+} //-- XMLDOM.java
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPath.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPath.java
new file mode 100644
index 0000000..0f76b64
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPath.java
@@ -0,0 +1,203 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.types.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.commons.jxpath.*;
+
+// Experimental: need to add code to select the 'root', etc.
+
+/**
+ *  Enable JXPath dynamic properties.
+ *
+ */
+public class JXPath extends Task {
+
+    public static String PREFIX="jxpath:";
+    JXPathPropertyHelper helper=new JXPathPropertyHelper();
+
+    public JXPath() {
+    }
+
+    public JXPathContext getJXPathContext() {
+        return helper.jxpathCtx;
+    }
+
+    public void execute() {
+        JXPathIntrospector.registerDynamicClass(Hashtable.class, JXPathHashtableHandler.class);
+        helper.jxpathCtx=JXPathContext.newContext( project );
+        helper.jxpathCtx.setVariables(new AntVariables());
+
+        PropertyHelper phelper=PropertyHelper.getPropertyHelper( project );
+        helper.setProject( project );
+        helper.setNext( phelper.getNext() );
+        phelper.setNext( helper );
+
+        project.addReference( "jxpathTask", this );
+
+    }
+
+
+    static class JXPathPropertyHelper extends PropertyHelper {
+        JXPathContext jxpathCtx;
+
+        public boolean setPropertyHook( String ns, String name, Object v, boolean inh,
+                                        boolean user, boolean isNew)
+        {
+            if( ! name.startsWith(PREFIX) ) {
+                // pass to next
+                return super.setPropertyHook(ns, name, v, inh, user, isNew);
+            }
+            name=name.substring( PREFIX.length() );
+
+            jxpathCtx.setValue( name, v );
+            return true;
+        }
+
+        public Object getPropertyHook( String ns, String name , boolean user) {
+            if( ! name.startsWith(PREFIX) ) {
+                // pass to next
+                return super.getPropertyHook(ns, name, user);
+            }
+
+            name=name.substring( PREFIX.length() );
+
+            //Object o=jxpathCtx.getValue( name );
+            //System.out.println("JXPath: getProperty " + ns + " " + name + "=" + o + o.getClass());
+
+            String result = "";
+
+            Iterator iter = jxpathCtx.iterate(name);
+
+            if(iter==null||!iter.hasNext()){
+                return "null";
+            }
+
+            result += iter.next();
+
+            while (iter.hasNext()) {
+                Object o = iter.next();
+                result += ", "+o;
+            }
+
+            return result;
+        }
+    }
+
+
+    public static class JXPathHashtableHandler implements DynamicPropertyHandler {
+
+        private static final String[] STRING_ARRAY = new String[0];
+
+        /**
+         * Returns string representations of all keys in the map.
+         */
+        public String[] getPropertyNames(Object object){
+            // System.out.println("getPropertyNames " + object );
+            Hashtable map = (Hashtable) object;
+            String names[] = new String[map.size()];
+            Enumeration it = map.keys();
+            for (int i = 0; i < names.length; i++){
+                names[i] = String.valueOf(it.nextElement());
+            }
+            return names;
+        }
+
+        /**
+         * Returns the value for the specified key.
+         */
+        public Object getProperty(Object object, String propertyName) {
+            //  System.out.println("getProperty " + object + " " + propertyName);
+            return ((Hashtable) object).get(propertyName);
+        }
+
+        /**
+         * Sets the specified key value.
+         */
+        public void setProperty(Object object, String propertyName, Object value){
+            ((Hashtable)object).put(propertyName, value);
+        }
+    }
+
+    public class AntVariables implements Variables {
+
+         protected AntVariables(){
+         }
+
+         public void declareVariable(String varName, Object value){
+           project.setNewProperty(varName, value.toString());
+         }
+
+         public Object getVariable(String varName){
+           return project.getProperty(varName);
+         }
+
+         public boolean isDeclaredVariable(String varName){
+           return project.getProperty(varName) == null ? false : true ;
+         }
+
+         public void undeclareVariable(String varName){
+           throw new UnsupportedOperationException("Cannot undeclare variables in Ant.");
+         }
+
+    }
+
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPathSet.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPathSet.java
new file mode 100644
index 0000000..f5c5941
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JXPathSet.java
@@ -0,0 +1,116 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.commons.jxpath.*;
+
+
+/**
+ *  Set a JXPath property
+ *  
+ *
+ * @deprecated A generic <property> should be used.
+ */
+public class JXPathSet extends Task {
+
+    String path;
+    String valueString;
+    String refId;
+    
+    public JXPathSet() {
+    }
+
+    /** The JXPath pointing to the target.
+     *  The root of the tree is the Project.
+     *  Example:
+     *      /references[@name='myRef']
+     *
+     */
+    public void setPath( String path ) {
+        this.path=path;
+    }
+
+    /** The value will be the referenced object.
+     */
+    public void setRefId( String refId ) {
+        this.refId=refId;
+    }
+
+    /** Set the value to be used.
+     */
+    public void setValue( String s ) {
+        this.valueString=s;
+    }
+
+    public void execute() {
+        JXPathContext jxpathCtx;
+        JXPath jxpathTask=(JXPath)project.getReference( "jxpathTask" );
+        jxpathCtx=jxpathTask.getJXPathContext();
+
+        Object value=null;
+        if( refId!=null )
+            value=project.getReference( refId );
+        if( value==null )
+            value=valueString;
+        
+        jxpathCtx.setValue( path, value );
+    }    
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JexlProperties.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JexlProperties.java
new file mode 100644
index 0000000..08f09a1
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/JexlProperties.java
@@ -0,0 +1,113 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.types.*;
+import java.io.*;
+import java.util.*;
+
+import org.apache.commons.jexl.*;
+
+/**
+ *  Enable JEXL dynamic properties
+ *  
+ *
+ */
+public class JexlProperties extends Task {
+    public static String PREFIX="jexl:";
+    JexlPropertyHelper helper=new JexlPropertyHelper();
+
+    public JexlProperties() {
+    }
+
+    static class JexlPropertyHelper extends PropertyHelper {
+        JexlContext jc;
+
+        public Object getPropertyHook( String ns, String name, boolean user ) {
+            if( ! name.startsWith(PREFIX) ) {
+                return super.getPropertyHook(ns, name, user);
+            }
+            try {
+                name=name.substring( PREFIX.length() );
+                Expression e = ExpressionFactory.createExpression(name);
+                Object o = e.evaluate(jc);
+
+                return o;
+            } catch( Exception ex ) {
+                ex.printStackTrace();
+                return null;
+            }
+        }
+    }
+    
+    public void execute() {
+        /*
+         *  First make a jexlContext and put stuff in it
+         */
+        helper.jc = JexlHelper.createContext();
+        helper.jc.getVars().put("ant", project);
+
+        // register it
+        PropertyHelper phelper=PropertyHelper.getPropertyHelper( project );
+        helper.setNext( phelper.getNext() );
+        helper.setProject( project );
+        phelper.setNext( helper );
+
+
+
+    }    
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/TaskDiscovery.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/TaskDiscovery.java
new file mode 100644
index 0000000..e774244
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/TaskDiscovery.java
@@ -0,0 +1,142 @@
+/*
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002, 2006 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", "Commons", 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/>.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+import org.apache.tools.ant.*;
+
+import java.util.*;
+
+import org.apache.commons.discovery.*;
+import org.apache.commons.discovery.jdk.JDKHooks;
+import org.apache.commons.discovery.resource.*;
+
+
+/**
+ * Default implementation for discovery and (lazy) creation of tasks.
+ *
+ * Several mechanisms will be used:
+ * - properties files found in the classpath ( META-INF/ant.tasks ).
+ * - resources named after the task name: META-INF/ant/[TASK_NAME].task
+ *
+ */
+public class TaskDiscovery extends Task implements ProjectComponentFactory
+{
+    String RESOURCE_NAME="META-INF/ant.tasks";
+
+    // Also discovery the 'legacy' names - in ant1.6 the initial preloaded tasks
+    // should be deprecated.
+    
+    Resource[] discoveredTasks = null;
+
+    Hashtable taskDefs=new Hashtable();
+
+    public Object createProjectComponent( Project project,
+                                          String ns,
+                                          String taskName )
+        throws BuildException
+    {
+        //        System.out.println("Try create " + taskName);
+        // 
+        return null;
+    }
+
+    public String toString() {
+        StringBuffer sb=new StringBuffer();
+        sb.append( "DiscoveredTasks[" );
+        if( discoveredTasks != null ) {
+            for( int i=0; i<discoveredTasks.length; i++ ) {
+                if( i>0) sb.append( ", ");
+                sb.append( discoveredTasks[i] );
+            }
+            sb.append( "]");
+        }
+        return sb.toString();
+    }
+
+
+    Properties taskClassNames=new Properties();
+
+    /** @TODO: Register itself as ProjectComponentHelper.
+     */
+    public void execute() throws BuildException
+    {
+        ProjectComponentHelper pcHelper=ProjectComponentHelper.getProjectComponentHelper();
+        pcHelper.addComponentFactory( this );
+        
+        // We'll read all 'ant.tasks' at startup, and every time an unknown task
+        // is found ( the classloader may be different from last time ). Not the best
+        // solution, just a start.
+        DiscoverResources disc = new DiscoverResources();
+        disc.addClassLoader( JDKHooks.getJDKHooks().getThreadContextClassLoader() );
+        disc.addClassLoader( this.getClass().getClassLoader() );
+        
+        ResourceIterator ri = disc.findResources(RESOURCE_NAME);
+        
+        Vector vector = new Vector();
+        while (ri.hasNext()) {
+            Resource resourceInfo = ri.nextResource();
+            vector.add(resourceInfo);
+            System.out.println("Found " + resourceInfo);
+
+            
+        }
+        
+        discoveredTasks = new Resource[vector.size()];
+        vector.copyInto(discoveredTasks);
+    }
+        
+}
diff --git a/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/VelocityProperties.java b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/VelocityProperties.java
new file mode 100644
index 0000000..d21a459
--- /dev/null
+++ b/trunk/proposal/embed/src/java/org/apache/tools/ant/taskdefs/optional/VelocityProperties.java
@@ -0,0 +1,127 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.types.*;
+import java.io.*;
+import java.util.*;
+
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.Template;
+
+/**
+ *  Enable Velocity dynamic properties
+ *  
+ *
+ */
+public class VelocityProperties extends Task {
+    public static final String PREFIX="vm:";
+    VelocityPropertyHelper helper=new VelocityPropertyHelper();
+
+    public VelocityProperties() {
+    }
+
+    static class VelocityPropertyHelper extends PropertyHelper {
+        VelocityEngine engine;
+        VelocityContext context;
+
+        public Object getPropertyHook( String ns, String name, boolean user ) {
+            if( ! name.startsWith(PREFIX) ) {
+                // pass on to next
+                return super.getPropertyHook(ns, name, user);
+            }
+            try {
+                name=name.substring( PREFIX.length() );
+                StringWriter sw=new StringWriter();
+
+                engine.evaluate( context, sw, "antVM", name );
+
+                System.out.println("VM: getProperty " + ns + " " + name + "=" + sw.toString());
+                return sw.toString();
+            } catch( Exception ex ) {
+                ex.printStackTrace();
+                return null;
+            }
+        }
+    }
+
+    public VelocityEngine getVelocityEngine() {
+        return helper.engine;
+    }
+    
+    public void execute() {
+        try {
+            // Prepare the engine
+            helper.engine=new VelocityEngine();
+            helper.engine.init();
+            
+            helper.context=new VelocityContext();
+            helper.context.put( "ant", project );
+
+            // Register it
+            PropertyHelper phelper=PropertyHelper.getPropertyHelper( project );
+            helper.setNext( phelper.getNext() );
+            helper.setProject( project );
+            phelper.setNext( helper );
+
+        } catch( Exception ex ) {
+            ex.printStackTrace();
+        }
+
+    }    
+}
diff --git a/trunk/proposal/embed/test.xml b/trunk/proposal/embed/test.xml
new file mode 100644
index 0000000..3af5535
--- /dev/null
+++ b/trunk/proposal/embed/test.xml
@@ -0,0 +1,126 @@
+<project name="embed-test" default="main" basedir=".">
+  <property name="ant.src" location="../.."/>
+  <description>Test for embed proposal</description>        
+  <import file="build.xml"/>
+
+  <!-- This is a tricky problem: import will append tasks at the
+    end of the task list. That's a bug, it should replace the
+    <import> task with the content. When fixed, this should show
+    the real value. --> 
+  <echo message="Base.path from build.xml ( in top level ): ${base.path}"/>
+  
+  <target name="init">
+     <property name="junit.jar" location="${base.path}/junit3.7/junit.jar"/>
+     <echo>Base.path from build.xml ( in init ) : ${base.path}</echo>
+
+    <path id="myJars" >
+      <pathelement path="${junit.jar}" />
+      <pathelement path="${jxpath.jar}" />
+      <pathelement path="${velocity-dep.jar}" />
+      <pathelement path="${velocity.jar}" />
+      <pathelement path="${jexl.jar}" />
+      <pathelement path="${commons-discovery.jar}" />
+      <pathelement path="${commons-logging.jar}" />
+      <pathelement path="${ant.home}/lib/ant-sax2.jar" />
+      <pathelement location="/usr/share/java/xalan-j_2_3_1/bin/xercesImpl.jar"/>
+      <pathelement location="${ant.home}/lib/xercesImpl.jar"/>
+      <pathelement location="${ant.home}/lib/xml-apis.jar"/>
+      <pathelement location="${ant.home}/lib/ant.jar"/>
+      <fileset dir="${ant.home}/lib" includes="optional-*.jar" />
+    </path>
+
+    <echo>Path: ${toString:myJars}</echo>
+
+    <classloader classpathRef="myJars"/>
+  
+  </target>
+
+  <target name="xmldom" depends="init">
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.JXPath"
+             name="jxpath" />
+    <typedef classname="org.apache.tools.ant.taskdefs.XMLDOM"
+             name="xmlDom" />
+
+    <xmlDom id="module.xml" file="/ws/jakarta-gump/project/jakarta-ant.xml"/>
+    <!-- Enable Jxpath support -->
+    <jxpath/>
+    <echo>Name: ${jxpath:/references/module.xml/root/module/project[1]/@name}</echo>
+
+  </target>
+
+
+  <target name="discovery" depends="init">
+    <echo message="${commons-discovery.jar}"/>
+
+    <systemPath pathRef="myJars"/>
+
+    <taskdef classname="org.apache.tools.ant.taskdefs.ServiceDiscoveryTask"
+             name="discovery" />
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.JXPath"
+             name="jxpath" />
+
+    <jxpath/>
+    <discovery debug="1" id="myDiscovery"
+               serviceName="META-INF/services/javax.xml.parsers.SAXParserFactory" />
+    <echo message="Found ${jxpath:/references[@name='myDiscovery']}" />
+
+  </target>
+
+  <target name="systemPathTest" depends="init">
+    <junit id="replacedJunit" />
+    <echo message="Found JUNIT: ${toString:replacedJunit}" />
+  </target>
+
+  <target name="dynamicProperties" depends="init">
+    <!-- This is Taksdef2.java - it'll use the systemPath as parent loader
+      -->
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.JXPath"
+             name="jxpath" />
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.JXPathSet"
+             name="jxpathSet" />
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.VelocityProperties"
+             name="velocityProperties" />
+    <taskdef classname="org.apache.tools.ant.taskdefs.optional.JexlProperties"
+             name="jexlProperties" />
+
+    <!-- Init JxPath. '/' is the project -->
+    <jxpath/>
+    <velocityProperties/>
+    <jexlProperties/>
+    
+    <echo id="foo" message="Starting dynamic props tests" />
+
+    <echo message="Value: ${vm:$ant.references.jxpathTask.foo}" />
+    <jxpathSet path="/references[@name='jxpathTask']/foo" value="Test"/>
+    <echo message="Value: ${vm:$ant.references.jxpathTask.foo}" />
+
+    <echo message="${jexl:ant.references.jxpathTask.foo=bar}" />
+    <echo message="Value: ${vm:$ant.references.jxpathTask.foo}" />
+
+    <echo message="jexl /references/myJars: ${jexl:ant.references.myJars}" />
+
+    <echo message="jxPath /targets[1]: ${jxpath:/targets[1]}" />
+    <echo message="jxPath /references: ${jxpath:/references}" />
+    <echo message="jxPath /references[@name='myJars']: ${jxpath:/references[@name='myJars']}" />
+    <echo message="jxPath /references/myJars: ${jxpath:/references/myJars}" />
+
+    <!-- This is XMLDOM.java - a datatype that holds an xml DOM  -->
+    <typedef name="xmldom" classname="org.apache.tools.ant.taskdefs.XMLDOM"/>
+
+    <!-- Init XMLDOM. The DOM of file test.xml will be referenced via the id-->
+    <xmldom id="test.xml" file="test.xml"/>  
+
+    <echo message="XMLDOM: ${jxpath:/references/test.xml/root/project/@name}" />
+
+  </target>
+
+  <target name="main" depends="init,dynamicProperties,systemPathTest,test-import">
+  </target>
+
+
+  <target name="test-import" >
+    <antcall target="embed.main" />
+  </target>
+
+
+</project>
diff --git a/trunk/proposal/myrmidon/README.txt b/trunk/proposal/myrmidon/README.txt
new file mode 100644
index 0000000..7d8543b
--- /dev/null
+++ b/trunk/proposal/myrmidon/README.txt
@@ -0,0 +1 @@
+Myrmidon has moved to a new top level cvs jakarta-ant-myrmidon
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/antunit/README b/trunk/proposal/sandbox/antunit/README
new file mode 100644
index 0000000..40e7a14
--- /dev/null
+++ b/trunk/proposal/sandbox/antunit/README
@@ -0,0 +1 @@
+Moved to http://svn.apache.org/repos/asf/ant/sandbox/antlibs/antunit/trunk/
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/clearcase/build.sh b/trunk/proposal/sandbox/clearcase/build.sh
new file mode 100644
index 0000000..f15a7e7
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/build.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+cygwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+esac
+
+PWD=`pwd`
+if $cygwin ; then
+    PWD=`cygpath --windows "$PWD"`
+fi
+
+cd ../../..
+/bin/sh ./build.sh -buildfile $PWD/build.xml $*
+cd $PWD
+
diff --git a/trunk/proposal/sandbox/clearcase/build.xml b/trunk/proposal/sandbox/clearcase/build.xml
new file mode 100644
index 0000000..afbd817
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/build.xml
@@ -0,0 +1,62 @@
+<project name="clearcase-proposal" basedir="." default="compile">
+  <property file=".ant.properties"/>
+  <property file="${user.home}/.ant.properties"/>
+  
+  <!--property name="build.sysclasspath" value="ignore"/-->
+  <property name="build.compiler" value="jikes"/>
+  <!--property name="build.compiler.emacs" value="on"/-->
+  <property name="build.compiler.pedantic" value="true"/>
+  <property name="build.compiler.depend" value="true"/>
+  <property name="build.compiler.fulldepend" value="true"/>
+
+  <property name="debug" value="on"/>
+  <property name="optimize" value="off"/>
+  <property name="deprecation" value="on"/>
+
+  <property name="build.dir" value="build"/>
+  <property name="build.lib" value="${build.dir}/lib"/>
+  <property name="build.src" value="${build.dir}/src"/>
+  <property name="build.classes" value="${build.dir}/classes"/>
+  <property name="build.dist" value="${build.dir}/dist"/>
+
+  <property name="java.dir" value="src/java"/>
+  <property name="tests.dir" value="src/testcases"/>
+  <property name="ant.base.dir" location="../../.."/>
+  <property name="lib.dir" location="${ant.base.dir}/lib"/>
+  <property name="bootstrap.dir" location="${ant.base.dir}/bootstrap"/>
+  
+  <path id="project.class.path">
+    <pathelement path="${build.classes}" />
+    <fileset dir="${lib.dir}" includes="**/*.jar"/>
+    <fileset dir="${bootstrap.dir}/lib" includes="ant.jar"/>
+  </path>
+
+  <target name="compile"
+          description="--> compile the source code">
+    <mkdir dir="${build.classes}"/>
+    <javac srcdir="src/main"
+           destdir="${build.classes}"
+           debug="${debug}"
+           optimize="${optimize}"
+           deprecation="${deprecation}"
+           includeantruntime="no">
+      <classpath refid="project.class.path"/>
+    </javac>
+  </target>
+  
+  <target name="dist"
+          depends="clean,compile"
+          description="--> create a jar">
+    <mkdir dir="${build.dist}"/>
+    <jar destfile="${build.dist}/cc-tasks.jar" basedir="${build.classes}"/>
+  </target>
+
+  <target name="clean"
+          description="--> cleans up build and dist directories">
+    <delete dir="${build.dir}" />
+    <delete>
+      <fileset dir="." includes="**/*.bak" defaultexcludes="no"/>
+    </delete>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkin.xml b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkin.xml
new file mode 100644
index 0000000..3d38947
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkin.xml
@@ -0,0 +1,34 @@
+<project name="cc-checkin" basedir="." default="noop"/>
+    
+    <!-- default value for test.dir, override to specify a cc location -->
+    <property name="test.dir" location="."/>
+    
+    <target name="noop"/>
+      
+    <target name="test-allcheckedout" description="should co all ci files">
+        <cc-checkin viewpath="${test.dir}" comment="test-allcheckedout">
+            <include name="**/*.cctest.ci"/>
+        </cc-checkin>
+    </target>
+
+    <target name="test-allcheckedin" description="should ci nothing"> 
+        <cc-checkin viewpath="${test.dir}" comment="test-allcheckedin">
+            <include name="**/*.cctest.co"/>
+        </cc-checkin>
+    </target>
+    
+    <target name="test-allprivate" description="should ci nothing">
+        <cc-checkin viewpath="${test.dir}" comment="test-allprivate">
+            <include name="**/*.cctest.private"/>
+        </cc-checkin>
+    </target>
+    
+    <target name="test-mix" description="should ci only co files">
+        <cc-checkin viewpath="${test.dir}">
+            <include name="**/*.cctest.private"/>
+            <include name="**/*.cctest.ci"/>
+            <include name="**/*.cctest.co"/>
+        </cc-checkin>        
+    </target>
+    
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkout.xml b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkout.xml
new file mode 100644
index 0000000..64e5410
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-checkout.xml
@@ -0,0 +1,34 @@
+<project name="cc-checkout" basedir="." default="noop"/>
+    
+    <!-- default value for test.dir, override to specify a cc location -->
+    <property name="test.dir" location="."/>
+    
+    <target name="noop"/>
+      
+    <target name="test-allcheckedout" description="should co nothing">
+        <cc-checkout viewpath="${test.dir}" comment="test-allcheckedout">
+            <include name="**/*.cctest.ci"/>
+        </cc-checkout>
+    </target>
+
+    <target name="test-allcheckedin" description="should co all files"> 
+        <cc-checkout viewpath="${test.dir}" comment="test-allcheckedin">
+            <include name="**/*.cctest.co"/>
+        </cc-checkout>
+    </target>
+    
+    <target name="test-allprivate" description="should co nothing">
+        <cc-checkout viewpath="${test.dir}" comment="test-allprivate">
+            <include name="**/*.cctest.private"/>
+        </cc-checkout>
+    </target>
+    
+    <target name="test-mix" description="should co only ci files">
+        <cc-checkout viewpath="${test.dir}">
+            <include name="**/*.cctest.private"/>
+            <include name="**/*.cctest.ci"/>
+            <include name="**/*.cctest.co"/>
+        </cc-checkout>
+    </target>
+    
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-mkelem.xml b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-mkelem.xml
new file mode 100644
index 0000000..fb953a5
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/etc/testcases/cc-mkelem.xml
@@ -0,0 +1,34 @@
+<project name="cc-mkelem" basedir="." default="noop"/>
+    
+    <!-- default value for test.dir, override to specify a cc location -->
+    <property name="test.dir" location="."/>
+    
+    <target name="noop"/>
+      
+    <target name="test-allcheckedout" description="should mkelem nothing">
+        <cc-mkelem viewpath="${test.dir}" comment="test-allcheckedout">
+            <include name="**/*.cctest.ci"/>
+        </cc-mkelem>
+    </target>
+
+    <target name="test-allcheckedin" description="should mkelem nothing"> 
+        <cc-mkelem viewpath="${test.dir}" comment="test-allcheckedin">
+            <include name="**/*.cctest.co"/>
+        </cc-mkelem>
+    </target>
+    
+    <target name="test-allprivate" description="should mkelem all files">
+        <cc-mkelem viewpath="${test.dir}" comment="test-allprivate">
+            <include name="**/*.cctest.private"/>
+        </cc-mkelem>
+    </target>
+    
+    <target name="test-mix" description="should mkelem only private files">
+        <cc-mkelem viewpath="${test.dir}">
+            <include name="**/*.cctest.private"/>
+            <include name="**/*.cctest.ci"/>
+            <include name="**/*.cctest.co"/>
+        </cc-mkelem>        
+    </target>
+    
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
new file mode 100644
index 0000000..cae85d3
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
@@ -0,0 +1,123 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Creates a permanent new version of an element
+ *
+ * @see http://clearcase.rational.com/doc/latest/ccase_ux/ccref/checkin.html
+ *
+ */
+public class CCCheckin extends CCMatchingTask {
+    private boolean nowarn = false;
+    private boolean ptime = false;
+    private boolean keep = false;
+    private boolean identical = true;
+
+    protected Vector getOptions(){
+        Vector v = new Vector();
+        v.addElement("ci");
+        if (nowarn){
+            v.addElement("-nowarn");
+        }
+        if (ptime){
+            v.addElement("-ptime");
+        }
+        if (comment != null){
+            v.addElement("-cfile");
+            v.addElement(commentFile.getPath());
+        }
+        if (keep){
+            v.addElement("-keep");
+        }
+        if (identical){
+            v.addElement("-identical");
+        }
+        v.addElement("<pname>");
+        return v;
+    }
+
+    protected void execute(String[] args, CCFile file) throws BuildException {
+        args[args.length - 1] = file.getPath();
+        CmdResult res = CCUtils.cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    protected boolean accept(CCFile file) {
+        return file.isCheckedOut();
+    }
+
+    // bean setters
+    public void setNowarn(boolean nowarn) {
+        this.nowarn = nowarn;
+    }
+
+    public void setPtime(boolean ptime) {
+        this.ptime = ptime;
+    }
+
+    public void setKeep(boolean keep) {
+        this.keep = keep;
+    }
+
+    public void setIdentical(boolean identical) {
+        this.identical = identical;
+    }
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
new file mode 100644
index 0000000..93a90fb
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
@@ -0,0 +1,131 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+
+/**
+ * Creates a modifiable copy of a version
+ *
+ * @see http://clearcase.rational.com/doc/latest/ccase_ux/ccref/checkout.html
+ *
+ */
+public class CCCheckout extends CCMatchingTask {
+    private boolean reserved = true;
+    private String branch = null;
+    private boolean version = false;
+    private boolean nwarn = false;
+    private String out = null;
+    private boolean ndata = false;
+    private boolean ptime = false;
+
+    protected Vector getOptions(){
+        Vector v = new Vector();
+        v.addElement("co");
+        v.addElement(reserved ? "-reserved":"-unreserved");
+        if (nwarn){
+            v.addElement("-nwarn");
+        }
+        if (branch != null){
+            v.addElement("-branch");
+            v.addElement(branch);
+        } else if (version) {
+            v.addElement("-version");
+        }
+        if (out != null){
+            v.addElement("-out");
+            v.addElement(out);
+        } else if (ndata){
+            v.addElement("-ndata");
+        }
+        if (ptime){
+            v.addElement("-ptime");
+        }
+        v.addElement("<pname>");
+        return v;
+    }
+
+    protected boolean accept(CCFile file) {
+        return file.isCheckedIn();
+    }
+
+    // bean setters
+    public void setPtime(boolean ptime) {
+        this.ptime = ptime;
+    }
+
+    public void setReserved(boolean reserved) {
+        this.reserved = reserved;
+    }
+
+    public void setOut(String out) {
+        this.out = out;
+    }
+
+    public void setNdata(boolean ndata) {
+        this.ndata = ndata;
+    }
+
+    public void setBranch(String branch) {
+        this.branch = branch;
+    }
+
+    public void setVersion(boolean version) {
+        this.version = version;
+    }
+
+    public void setNwarn(boolean nwarn) {
+        this.nwarn = nwarn;
+    }
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFile.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFile.java
new file mode 100644
index 0000000..c643475
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCFile.java
@@ -0,0 +1,135 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * An extended file that gives state information.
+ *
+ */
+public class CCFile extends File {
+
+    /** is it checkedout */
+    private boolean checkedout = false;
+
+    /** is it under source control ? */
+    private boolean versioned = false;
+
+    /** was this file already described once ? */
+    private boolean described = false;
+
+    public CCFile(String parent, String child) {
+        super(parent, child);
+    }
+
+    public CCFile(File parent, String child) {
+        super(parent, child);
+    }
+
+    public CCFile(String pathname) {
+        super(pathname);
+    }
+
+    /**
+     * @return whether the file is checkedout. A non checkedout file
+     * does not imply it is a checkedin one.
+     * @see #isCheckedIn()
+     * @see #isVersioned()
+     */
+    public boolean isCheckedOut() {
+        if (!described){
+            refresh();
+        }
+        return checkedout;
+    }
+
+    /**
+     * @return whether the file is versioned or not.
+     */
+    public boolean isVersioned() {
+        if (!described){
+            refresh();
+        }
+        return versioned;
+    }
+
+    /**
+     * @return whether the file is checkedin or not. A non checkedin file
+     * does not imply it is a checkedout one.
+     * @see #isCheckedOut()
+     * @see #isVersioned()
+     */
+    public boolean isCheckedIn(){
+        return isVersioned() && !isCheckedOut();
+    }
+
+    /**
+     * Refresh the file status in case it changed since the
+     * first access.
+     */
+    public void refresh() {
+        String[] args = {"describe", "-fmt", "\"%m %o\"", getAbsolutePath() };
+        CmdResult res = CCUtils.cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+        String stdout = res.getStdout();
+        versioned = (stdout.indexOf("view private object") == -1);
+        checkedout = (stdout.indexOf("checkout") != -1);
+        described = true;
+    }
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMatchingTask.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMatchingTask.java
new file mode 100644
index 0000000..01d26ac
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMatchingTask.java
@@ -0,0 +1,212 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+
+/**
+ * Base task for all Clearcase tasks involving multiple-file processing.
+ *
+ */
+public abstract class CCMatchingTask extends MatchingTask {
+    
+    /** view path to use. Equivalent to base directory of processing */
+    protected File viewpath;
+
+    /** cc helper tools */
+    protected CCUtils utils = new CCUtils(this);
+    
+    /** the set of collected files to checkin */
+    protected Hashtable files = null;
+
+    /** comments to use for the operation */
+    protected String comment = null;
+
+    /** the comment file created from the comments. It avoids escaping issues */
+    protected File commentFile;
+
+    /** cleartool options (and command as well) */
+    protected String[] options;
+
+    /**
+     * @return a vector of options representing the cleartool arguments.
+     * The last arguments is normally allocated and replaced at the last
+     * moment before running the command.
+     * @see #execute(String[], CCFile)
+     */
+    protected abstract Vector getOptions();
+    
+    /**
+     * @param file the clearcase file
+     * @return whether this file should be accepted or not by the
+     * command to restrict the file processing and errors. For
+     * example you might not want to checkin files that are
+     * already checked in and that are collected by the fileset
+     */
+    protected boolean accept(CCFile file){
+        return true;
+    }
+
+    public void execute() throws BuildException {
+        try {
+            preExecute();
+            doExecute();
+        } finally {
+            postExecute();
+        }
+    }
+    
+    /** check for attributes and builds the options array */
+    protected void preExecute() throws BuildException {
+        if (viewpath == null){
+            throw new BuildException("Invalid viewpath");
+        }
+        if (comment != null){
+            commentFile = CCUtils.createCommentFile(comment);
+        }
+        Vector v = getOptions();
+        options = new String[v.size()];
+        v.copyInto(options);
+    }
+    
+    /** clean up method calls after doExecute */
+    protected void postExecute(){
+        if (commentFile != null){
+            commentFile.delete();
+        }
+    }
+
+    /**
+     * The core processing. It loops over all files and calls
+     * <tt>execute(String[], CCFile)</tt>
+     */
+    protected void doExecute() throws BuildException {
+        Enumeration elems = getFiles().elements();
+        log("Processing " + files.size() + " elements...");
+        while ( elems.hasMoreElements() ){
+            execute(options, (CCFile)elems.nextElement());
+        }
+    }
+    
+    /**
+     * Calls the cleartool command with the appropriate parameters. Note the
+     * the last array element is supposed to be used by the filepath.
+     * @param args the cleartool command to execute. The last element being allocated
+     * and representing the filepath.
+     * @param file the file element to process.
+     * @throws BuildException thrown if an error occurs when processing the
+     * cleartool command.
+     */
+    protected void execute(String[] args, CCFile file) throws BuildException {
+        args[args.length - 1] = file.getPath();
+        CmdResult res = utils.cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    /**
+     * Restrict the set of files/directories to be processed.
+     * @return the set of files to be processed. The key is made up
+     * the filepath and the value is the <tt>CCFile</tt> instance.
+     * @see #accept(CCFile)
+     */
+    protected Hashtable getFiles(){
+        if (files != null){
+            return files;
+        }
+        files = new Hashtable();
+        DirectoryScanner ds = getDirectoryScanner(viewpath);
+        String[] includes = ds.getIncludedDirectories();
+        addElements(files, ds.getBasedir(), includes);
+        includes = ds.getIncludedFiles();
+        addElements(files, ds.getBasedir(), includes);
+        return files;
+    }
+
+    /**
+     * Helper method to restrict a set of relative elements and add them
+     * to a map.
+     * @param map the map w/ a path/CCFile mapping to add elements to.
+     * @param basedir the base directory for all elements in the array.
+     * @param elems the set of elements to restrict.
+     * @see #accept(CCFile)
+     */
+    protected void addElements(Hashtable map, File basedir, String[] elems){
+        for (int i = 0; i < elems.length; i++){
+            CCFile f = new CCFile(basedir, elems[i]);
+            if ( accept(f) ){
+                map.put(f.getPath(), f);
+            }
+        }
+    }
+
+// Ant bean setters
+    
+    public void setViewPath(File value){
+        this.viewpath = value;
+    }
+
+    public void setComment(String value){
+        comment = value;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
new file mode 100644
index 0000000..ca2dfec
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
@@ -0,0 +1,195 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.io.File;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+
+/**
+ * Creates a file or directory element.
+ *
+ * @see http://clearcase.rational.com/doc/latest/ccase_ux/ccref/mkelem.html
+ *
+ */
+public class CCMkelem extends CCMatchingTask {
+
+    private String type;
+
+    private boolean nocheckout;
+
+    private boolean checkin;
+
+    private boolean preserveTime;
+
+    private Hashtable codirs = new Hashtable();
+
+    public void execute(String[] args, CCFile file) throws BuildException {
+        CCFile parent = (CCFile)codirs.get(file.getParent());
+        if (parent == null){
+            parent = new CCFile(file.getParent());
+            if ( !parent.isVersioned() ){
+                mkelemDirectory(parent);
+                // ensure versioned dir
+            } else if ( parent.isCheckedIn() ){
+                utils.checkout( parent );
+            }
+            codirs.put(parent.getPath(), parent);
+        }
+        args[args.length - 1] = file.getAbsolutePath();
+        CmdResult res = CCUtils.cleartool(args);
+        if (res.getStatus() != 0) {
+            throw new BuildException(res.getStdErr());
+        }
+
+    }
+
+    protected void postExecute() {
+        // checkin back all co directories
+        Enumeration dirs = codirs.elements();
+        while( dirs.hasMoreElements() ){
+            File dir = (File)dirs.nextElement();
+            utils.checkin( dir );
+        }
+        super.postExecute();
+    }
+
+    /** create the command line options based on user input */
+    protected Vector getOptions(){
+        Vector v = new Vector();
+        v.addElement("mkelem");
+        if (type != null){
+            v.addElement("-eltype");
+            v.addElement(type);
+        }
+        if (comment == null){
+            v.addElement("-nc");
+        } else {
+            commentFile = CCUtils.createCommentFile(comment);
+            v.addElement("-cfi");
+            v.addElement(commentFile.getAbsolutePath());
+        }
+        if (nocheckout){
+            v.addElement("-nco");
+        } else if (checkin){
+            v.addElement("-ci");
+            if (preserveTime){
+                v.addElement("-ptime");
+            }
+        }
+        v.addElement("<pname>"); // dummy arg for file
+        return v;
+    }
+
+    private void mkelemDirectory(CCFile dir) throws BuildException {
+        // resolve symoblic link if any...
+        dir = new CCFile( utils.resolveSymbolicLink(dir.getAbsoluteFile()).getAbsolutePath() );
+
+        // make sure that the parent is versioned...
+        CCFile parent = new CCFile(dir.getParent());
+        boolean should_ci = false;
+        if ( !parent.isVersioned() ){
+            mkelemDirectory(parent);
+            codirs.put(parent.getPath(), parent.getAbsoluteFile());
+        }
+        // ...and checkout it if already checked in.
+        if ( parent.isCheckedIn() ){
+            utils.checkout(parent.getAbsoluteFile());
+            codirs.put(parent.getPath(), parent.getAbsoluteFile());
+        }
+
+        // rename the unversioned directory into a temporary one...
+        File mkelem_file = new File(dir.getAbsolutePath() + "_mkelem");
+        dir.renameTo( mkelem_file );
+        // then create it via Clearcase...
+        utils.mkdir( dir );
+        codirs.put(dir.getPath(), dir.getAbsoluteFile());
+        // .. and populate it back with its files...
+        File[] files = dir.listFiles();
+        for (int i = 0; i < files.length; i++){
+            File newFile = new File(dir, files[i].getName());
+            if ( !files[i].renameTo( newFile ) ) {
+                throw new BuildException("Could not rename dir '" + files[i] + "' into '" + newFile + "'" );
+            }
+        }
+        // delete this one only if things went smoothly...
+        mkelem_file.delete();
+    }
+
+// bean setters
+    public void setType(String value){
+        type = value;
+    }
+
+    public void setNoCheckout(boolean value){
+        nocheckout = value;
+    }
+
+    public void setCheckin(boolean value){
+        checkin = value;
+    }
+
+    public void setPreserveTime(boolean value){
+        preserveTime = value;
+    }
+
+
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
new file mode 100644
index 0000000..9eb7011
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
@@ -0,0 +1,125 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Attaches version labels to version of elements.
+ *
+ * @see http://clearcase.rational.com/doc/latest/ccase_ux/ccref/mklabel.html#2051
+ *
+ */
+public class CCMklabel extends CCMatchingTask {
+    private boolean replace = false;
+    private boolean follow = false;
+    private String version = null;
+    private boolean recurse = false;
+
+    protected Vector getOptions(){
+        Vector v = new Vector();
+        v.addElement("mklabel");
+        if (replace){
+            v.addElement("-replace");
+        }
+        if (recurse){
+            v.addElement("-recurse");
+        }
+        if (follow){
+            v.addElement("-follow");
+        }
+        if (comment != null){
+            v.addElement("-cfile");
+            v.addElement(commentFile.getPath());
+        }
+        if (version != null){
+            v.addElement("-version");
+            v.addElement(version);
+        }
+        v.addElement("<pname>");
+        return v;
+    }
+
+    protected void doExecute() throws BuildException {
+        // not very nice, but we'll try to speed up things
+        // by assuming a recurse is set only to the viewpath.
+        if (recurse){
+            options[options.length - 1] = viewpath.getPath();
+            utils.cleartool(options);
+        } else {
+            super.doExecute();
+        }
+    }
+
+    protected boolean accept(CCFile file) {
+        //@fixme does it fail on checkedout files ?
+        return file.isVersioned();
+    }
+    //  bean setters
+
+    public void setRecurse(boolean value){
+        recurse = value;
+    }
+    public void setVersion(String value){
+        version = value;
+    }
+    public void setReplace(boolean value){
+        replace = value;
+    }
+    public void setFollow(boolean value){
+        follow = value;
+    }
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmname.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmname.java
new file mode 100644
index 0000000..7b390c5
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmname.java
@@ -0,0 +1,123 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.io.File;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Removes the name of an element or VOB symbolic link from a directory version
+ *
+ * @see http://clearcase.rational.com/doc/latest/ccase_ux/ccref/rmname.html
+ *
+ */
+public class CCRmname extends CCMatchingTask {
+
+    private boolean force = false;
+
+    /** used to cache co directories */
+    private Hashtable codirs = new Hashtable();
+
+    protected Vector getOptions() {
+        Vector v = new Vector();
+        v.addElement("rmname");
+        if (comment != null){
+            v.addElement("-cfile");
+            v.addElement(commentFile.getPath());
+        } else {
+            v.addElement("-comment");
+            v.addElement(CCUtils.DEFAULT_COMMENT);
+        }
+        if (force){
+            v.addElement("-f");
+        }
+        v.addElement("<pname>");
+        return v;
+    }
+
+    public void execute(String[] args, CCFile file) throws BuildException {
+        CCFile parent = new CCFile(file.getParent());
+        // we have first to co the parent
+        if ( parent.isCheckedIn() ){
+            utils.checkout(parent);
+        }
+        // remove the element
+        args[args.length - 1] = file.getAbsolutePath();
+        CmdResult res = utils.cleartool(args);
+        // if it failed, unco otherwise ci the parent
+        if (res.getStatus() != 0){
+            utils.uncheckout(parent);
+            throw new BuildException(res.getStdErr());
+        } else {
+            utils.checkin(parent);
+        }
+    }
+
+    protected boolean accept(CCFile file){
+        return file.isCheckedIn();
+    }
+
+// bean setters
+    public void setForce(boolean value){
+        force = value;
+    }
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUtils.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUtils.java
new file mode 100644
index 0000000..e1e33ca
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUtils.java
@@ -0,0 +1,304 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+
+/**
+ * Helper methods related to clearcase commands.
+ *
+ */
+public final class CCUtils {
+
+    public final static String DEFAULT_COMMENT = "\"Automatic operation from Jakarta Ant\"";
+
+    private final static RegexpMatcherFactory __reFactory = new RegexpMatcherFactory();
+
+    /** the matchers cache: pattern/matcher */
+    private final static Hashtable matchers = new Hashtable();
+
+    private Task task;
+
+    public CCUtils(Task task){
+        this.task = task;
+    }
+
+    /**
+     * return a group of matches of a given RE in a string.
+     * @param pattern the pattern to match in the input data.
+     * @param input the data where to look for the pattern.
+     * @return the group of matches if any, 0 being the full match
+     * and the rest being parenthesized expressions. <tt>null</tt>
+     * if there are no matches.
+     */
+    public Vector matches(String pattern, String input){
+        RegexpMatcher matcher = (RegexpMatcher)matchers.get(pattern);
+        if (matcher == null){
+            matcher = __reFactory.newRegexpMatcher();
+            matcher.setPattern(pattern);
+            matchers.put(pattern, matcher);
+        }
+        return matcher.getGroups(input);
+    }
+
+    /**
+     * Try to resolve a symbolic link if it is one.
+     * @param toresolve the symbolic link to resolve.
+     * @return the resolved link if it is a symbolic link, otherwise
+     * return the original link.
+     */
+    public File resolveSymbolicLink(File toresolve) throws BuildException {
+        String[] args = { "ls", "-l", toresolve.getAbsolutePath() };
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0 ){
+            throw new BuildException(res.getStdErr());
+        }
+        Vector groups = matches("symbolic link(.*)-->(.*)", res.getStdout());
+        if (groups == null){
+            return toresolve; // or null ?
+        }
+        String path = (String)groups.elementAt(2);
+        path = path.trim();
+        File resolved = new File(path);
+        if ( !resolved.isAbsolute() ){
+            resolved = new File(toresolve.getParent(), path);
+        }
+        return resolved;
+    }
+
+    /**
+     * Move a file to another. (ie rename)
+     */
+    public void move(File from, File to) throws BuildException {
+        String[] args = {"move", "-nc", from.getPath(), to.getPath()};
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0) {
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    /**
+     * return the list of checkedout files in a given viewpath.
+     * @param viewpath the path to the view/directory to look for
+     * checkedout files.
+     * @param recurse <tt>true</tt> to look for files recursively,
+     * otherwise <tt>false</tt>
+     * @return the list of checkedout files in the view (full pathname).
+     */
+    public Hashtable lsco(File viewpath, boolean recurse) {
+        String recurseParam = recurse ? "-r" : "";
+        String fullpath = viewpath.getAbsolutePath();
+        //@fixme is -cvi conflicting with -r ?
+        String[] args = {"lsco", recurseParam, "-cvi", "-s", "-me", fullpath};
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0) {
+            throw new BuildException(res.getStdErr());
+        }
+
+        Vector lines = res.getStdoutLines();
+        Hashtable map = toFiles(lines);
+        return map;
+    }
+
+    /**
+     * Transform a set of paths into canonical paths.
+     * Typically this should be used to transform a set of
+     * output lines by cleartool representing file paths.
+     */
+    public static Hashtable toFiles(Vector paths){
+        Hashtable map = new Hashtable();
+        for (int i = 0; i < paths.size(); i++) {
+            String path = (String) paths.elementAt(i);
+            try {
+                // the path is normally the full path, we normally
+                // not need to do a new File(viewpath, path)
+                File f = new File(path);
+                path = f.getCanonicalPath();
+                map.put(path, path);
+            } catch (IOException e) {
+                // assume it's not a file...
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Returns the list of files that are *not* checked out.
+     * @see #lsco(File, boolean)
+     */
+    public Hashtable lsnco(File viewpath){
+        String[] args = {"find", viewpath.getAbsolutePath(), "-type", "f", "-cvi", "-nxn", "-print"};
+        CmdResult res = cleartool(args);
+        Vector lines = res.getStdoutLines();
+        Hashtable all = toFiles(lines);
+        Hashtable co = lsco(viewpath, true);
+        // remove the co files
+        Enumeration keys = co.keys();
+        while ( keys.hasMoreElements() ){
+            Object path = keys.nextElement();
+            Object o = all.remove(path);
+            if (o == null){
+                // oops how come a co file is not found by find ?
+            }
+        }
+        return all;
+    }
+
+    /** returns the list of private files in the view */
+    public Hashtable lsprivate(File viewpath){
+        // for a snapshot view, we must use ls -r -view_only
+        return null;
+    }
+
+    public void checkin(File file){
+        String[] args = {"ci", "-nc", "-identical", file.getAbsolutePath()} ;
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    public void checkout(File file){
+        String[] args = {"co", "-nc", "-unreserved", file.getAbsolutePath()} ;
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    public void uncheckout(File file){
+        String[] args = {"unco", "-rm", file.getAbsolutePath() };
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    public void mkdir(File file, String comment) {
+
+    }
+
+    public void mkdir(File file){
+        String[] args = {"mkdir", "-nc", file.getAbsolutePath() };
+        CmdResult res = cleartool(args);
+        if (res.getStatus() != 0){
+            throw new BuildException(res.getStdErr());
+        }
+    }
+
+    /**
+     * Helper method to execute a given cleartool command.
+     * @param args the parameters used to execute cleartool.
+     * @return the result of the command.
+     */
+    public static CmdResult cleartool(String[] args) {
+        String[] nargs = new String[args.length + 1];
+        nargs[0] = "cleartool";
+        System.arraycopy(args, 0, nargs, 1, args.length);
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        ExecuteStreamHandler handler = new PumpStreamHandler(out, err);
+        Execute exe = new Execute(handler);
+        exe.setCommandline(nargs);
+        try {
+            int retcode = exe.execute();
+            return new CmdResult(retcode, out.toString(), err.toString());
+        } catch (IOException e){
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Create the comment file used by cleartool commands.
+     */
+    public static File createCommentFile(String comment) {
+        FileUtils futils = FileUtils.newFileUtils();
+        File f = futils.createTempFile("ant_cc", ".tmp", new File("."));
+        Writer writer = null;
+        try {
+            writer = new BufferedWriter(new FileWriter(f));
+            writer.write(comment);
+            writer.flush();
+        } catch (IOException e){
+            throw new BuildException(e);
+        } finally {
+            if (writer != null){
+                try {
+                    writer.close();
+                } catch (IOException e){
+                }
+            }
+        }
+        return f;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CmdResult.java b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CmdResult.java
new file mode 100644
index 0000000..59618c2
--- /dev/null
+++ b/trunk/proposal/sandbox/clearcase/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CmdResult.java
@@ -0,0 +1,97 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ *
+ */
+public class CmdResult {
+
+    private String stdout;
+
+    private String stderr;
+
+    private int code = 0;
+
+    public CmdResult(int code, String stdout, String stderr){
+        this.code = code;
+        this.stdout = stdout;
+        this.stderr = stderr;
+    }
+
+    public String getStdout(){
+        return stdout;
+    }
+
+    public Vector getStdoutLines(){
+        return StringUtils.lineSplit(stdout);
+    }
+
+    public String getStdErr(){
+        return stderr;
+    }
+
+    public Vector getStdErrLines(){
+        return StringUtils.lineSplit(stderr);
+    }
+
+    public int getStatus(){
+        return code;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/dotnet/README b/trunk/proposal/sandbox/dotnet/README
new file mode 100644
index 0000000..a748baa
--- /dev/null
+++ b/trunk/proposal/sandbox/dotnet/README
@@ -0,0 +1 @@
+Moved to http://svn.apache.org/repos/asf/ant/sandbox/antlibs/dotnet/trunk/
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/filterreaders/README b/trunk/proposal/sandbox/filterreaders/README
new file mode 100644
index 0000000..5c1a5bf
--- /dev/null
+++ b/trunk/proposal/sandbox/filterreaders/README
@@ -0,0 +1,82 @@
+
+***** Filter Readers is now available in Ant's main development tree *****
+
+
+Ant Filter Readers
+==================
+
+Usecase:
+========
+* Usage of filtering has become a common pattern in 
+  Ant's tasks.  Filtering is being performed one way or
+  another in tasks like <copy>, <move>, <fixcrlf>,
+  <loadfile>, etc.
+
+* There is no generic way to add custom filters
+  currently to these tasks.  User has to either extend
+  the task to add custom filter processing or add
+  more attributes as needed to the task itself.
+  
+* If user is provided with a pluggable filtering
+  mechanism, changes to built-in tasks can be mininized,
+  while at the same time providing increased flexibility
+  to the user.
+
+Design:
+======
+* FilterChain is an ordered collection of 'AntFilterReader's and
+  'java.io.FilterReader's
+
+* Each AntFilterReader encloses the custom class representing 
+  the actual java.io.FilterReader and contains configuration 
+  parameters that may be used by the custom class if it
+  implements the org.apache.tools.ant.types.Parameterizable
+  interface.
+
+* For ease of use, Ant's core filter readers can
+  be used with a filter reader specific syntax also.
+  
+* Custom filter readers can be created easily even
+  without using any of Ant's API - all one needs to
+  do to create a custom filter is to extend 
+  java.io.FilterReader.
+  
+* If the extended class also implements Parameterizable,
+  operation parameters can be made available to the
+  custom filter.
+
+* Each FilterReader is piped through the other, if any, in
+  the chain, in the order of declaration.
+
+Example:
+=======
+
+<loadfile srcFile="foo" property="bar">
+    <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.StripLineComments">
+            <param type="comment" value="//"/>
+            <param type="comment" value="REM "/>
+            <param type="comment" value="--"/>
+        </filterreader>
+        <filterreader classname="org.apache.tools.ant.filters.StripLineBreaks"/>
+    </filterchain>
+</loadfile>
+
+The above example loads the contents of the file foo,
+filters out the lines that begin with //, REM and --,
+removes line breaks and then stores the result in
+the property named bar.
+
+Since StripLineComments and StripLineBreaks are built-in
+Ant filter readers, the same can also be represented as:
+
+<loadfile srcFile="foo" property="bar">
+    <filterchain>
+        <striplinecomments>
+            <comment value="//"/>
+            <comment value="REM "/>
+            <comment value="--"/>
+        </striplinecomments>
+        <striplinebreaks/>
+    </filterchain>
+</loadfile>
diff --git a/trunk/proposal/sandbox/httptasks/build.xml b/trunk/proposal/sandbox/httptasks/build.xml
new file mode 100644
index 0000000..01df859
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/build.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" ?>
+<project name="httptasks" default="all">
+    <description>
+        Build the HTTP tasks into the main ant dir
+        This is not production quality
+
+    </description>
+  <property name="base" location="../../.." />
+  <property name="build.dir" location="${base}/build" />
+  <property name="classes.dir" location="${build.dir}/classes" />
+  <property name="src.dir" location="src/main"/>
+
+  <property name="debug" value="true" />
+  <property name="deprecation" value="false" />
+  <property name="optimize" value="true" />
+
+
+  <target name="init">
+    <mkdir dir="${classes.dir}" />
+  </target>
+
+  <target name="all" depends="compile" />
+
+  <target name="compile" depends="init">
+    <javac srcdir="${src.dir}" destdir="${classes.dir}"
+           debug="${debug}"
+           deprecation="${deprecation}"
+           includeantruntime="true"
+           optimize="${optimize}">
+      <include name="**/*.java"/>
+    </javac>
+<!--    <copy toDir="${classes.dir}" preservelastmodified="true" >
+      <fileset dir="${src.dir}">
+        <include name="**/*.xml" />
+      </fileset>
+    </copy>-->
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/httptasks/docs/manual/OptionalTasks/httptasks.html b/trunk/proposal/sandbox/httptasks/docs/manual/OptionalTasks/httptasks.html
new file mode 100644
index 0000000..2c089d6
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/docs/manual/OptionalTasks/httptasks.html
@@ -0,0 +1,429 @@
+<html>
+<head>
+<title>Http Tasks</title>
+</head>
+<body>
+<h2>Http Tasks</h2>
+
+Tasks do to make the basic HTTP requests: get, post, head, put, with authentication.
+There is also a task to configure the proxy settings of the http tasks.
+<p>
+These tasks significantly extend the basic <a
+href="../CoreTasks/get.html">get task</a>, but are split off into the optional section
+so that
+<ol>
+<li> The core ant file doesn't get so big
+<li> this implementation can move to using an optional jar (HttpClient) to work around
+limitations of the HTTP support built in to the Java platform.   
+</ol>
+
+<h3>Core Functionality and Parameters</h3>
+
+<p>Common functionality to the core tasks tasks is </p>
+
+<ol>
+
+<li>Ability to name the remote url which the target of the request.</li>
+
+<li>Ability to name a local file as the local store of any returned
+content.</li>
+
+<li>Ability to name a property as the local store of any returned
+content.</li>
+
+<li>Ability to name a property to be set to &quot;true&quot; when a
+request succeeds.</li>
+
+<li>The option to list a number of parameters, each with a name and a
+value. Some methods (HttpGet, HttpHead) attach these parameters to the
+stated url to generate the url to actually fetch. Others (HttpPost) send
+the parameters up in the standard representation of form data.</li>
+
+<li>The option to state the authentication policy and then the username
+and password. Currently only basic authentication is used, which is
+utterly insecure except over an https link</li>
+
+<li>A 'verbose' option which provides extra information and progess
+information during a download.</li>
+
+<li>Timestamp control, using the <i>usetimestamp</i> flag. When set the
+timestamp of downloaded content is set to match that of the remote file
+(Java 1.2 or later only), and the local timestamp of the destination
+file (if it exists) used to set the if-modified-since header in the
+request, which will trigger optional download only. </li>
+
+</ol>
+
+<h3>Parameters</h3>
+
+<p> The <i>url</i> parameter specifies the URL to access. The optional
+<i>dest</i> parameter specifies a destination to which the retrieved
+page will be written. The optional <i>destinationproperty </i>parameter
+specifies a name of a property to save the content to, instead of a
+property. If neither <i>dest</i> nor <i>destinationproperty</i>
+specified, the contents of the specified URL are discarded (this is
+useful when accessing the URL for the purpose of causing some action on
+the remote server).</p>
+
+<p> When the <i>verbose</i> option is enabled, the task displays a '.' for every 
+  64 KB retrieved. If the <i>blocksize</i> parameter is adjusted then files are 
+  uploaded or downloaded in a different size block from this, and progress markers 
+  appear appropriately. </p>
+
+The <i>usetimestamp</i> option enables you to control downloads so that
+the remote file is only fetched if newer than the local copy. If there
+is no local copy, the download always takes place. When a file is
+downloaded, the timestamp of the downloaded file is set to the remote
+timestamp, if the JVM is Java1.2 or later. NB: This timestamp facility
+only works on downloads using the HTTP protocol.
+
+<p>The <i>authtype</i>, <i>username</i>, and <i>password</i> options enable support 
+  for password protected pages. Currently only 'Basic' authentication is used, 
+  which is notoriously insecure except over an encrypted https channel.</p>
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr> 
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td align="center" valign="top"><b>Required</b></td>
+  </tr>
+  <tr> 
+    <td valign="top">authtype</td>
+    <td valign="top">the HTTP authentication protocol to use, <i>none</i> or <i>basic</i>.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">blocksize</td>
+    <td valign="top">size (in kilobytes) of the data block used for upload and 
+      download. Default: 64.<br>
+      Keep this to a multiple of the hard disk sector size for file IO performance.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top"><b>dest</b></td>
+    <td valign="top">the file where to store the retrieved file.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">destinationProperty</td>
+    <td valign="top">the name of a property to fill with the returned content. 
+      Ignored if <i>dest</i> is set</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">failonerror</td>
+    <td valign="top">stop the build if the request failed. default: true</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">password</td>
+    <td valign="top">the password for authentication.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">successProperty</td>
+    <td valign="top">the name of a property to set to &quot;true&quot; if the 
+      request succeeds.<br>
+      Set <i>failonerror</i> to false for this to be of use.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top"><b>url</b></td>
+    <td valign="top">the URL from which to retrieve a file.</td>
+    <td align="center" valign="top">Yes</td>
+  </tr>
+  <tr> 
+    <td valign="top">usecaches</td>
+    <td valign="top">boolean to enable 'caching' of content during the fetch process. 
+      default:false</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr>
+    <td valign="top">useresponsecode</td>
+    <td valign="top">boolean to enable success/failure to be determined by result 
+      of the received response code. HTTP only. default=true.</td>
+    <td align="center" valign="top">&nbsp;</td>
+  </tr>
+  <tr> 
+    <td valign="top">username</td>
+    <td valign="top">the user name for authentication.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">usetimestamp</td>
+    <td valign="top">boolean flag to conditionally download a file based on the 
+      timestamp of the local copy. HTTP only</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+  <tr> 
+    <td valign="top">verbose</td>
+    <td valign="top"> boolean flag to control progress information display.</td>
+    <td align="center" valign="top">No</td>
+  </tr>
+</table>
+<p> The <i>successProperty</i> names a property which will be set to "true" if 
+  the request was deemed successful. For any non-http protocol, success is defined 
+  as the request completing. For http and https, success is defined as the request 
+  completing, and the response code from the serving being one of the 'success' 
+  values -any number between 200 and 299 inclusive. The usual HTTP_OK (200) is 
+  therefore a success, as is HTTP_ACCEPTED (202). But failures such as BAD_REQUEST 
+  (400) and the ubiquitous HTTP_NOT_FOUND (404) are most definately errors. So 
+  an attempt to access a missing url may result 'failure',even though some content 
+  was download (such as, perhaps, the 'file not found' text). If this is not what 
+  you desire, then set <i>useresponsecode</i>=&quot;false&quot; for the system 
+  to interpret any data back as a success. 
+<h3>Parameters specified as nested elements</h3>
+
+<p><b>param</b></p>
+
+<p>Specifies an HTTP request parameter to send as part of the request.
+For <i>get</i> and <i>head</i> request methods the parameters are
+encoded as part of the URL. For <i>post</i> request methods, the
+parameters are sent as the POST request data.</p>
+
+<table cellspacing="0" cellpadding="2" border="1">
+  <tbody>
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="middle"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the request property to set.</td>
+    <td valign="top" align="middle">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the value of the request property. You may alternatively
+      specify the value as text between the beginning and ending param tags.</td>
+    <td valign="center" align="middle">Yes</td>
+  </tr>
+  </tbody>
+</table>
+
+<p><b>header</b></p>
+
+<p>Specifies an arbitrary HTTP request header that will be sent with the
+request.</p>
+
+<table cellspacing="0" cellpadding="2" border="1">
+  <tr>
+    <td valign="top"><b>Attribute</b></td>
+    <td valign="top"><b>Description</b></td>
+    <td valign="top" align="middle"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top">name</td>
+    <td valign="top">the name of the HTTP request header</td>
+    <td valign="top" align="middle">Yes</td>
+  </tr>
+  <tr>
+    <td valign="top">value</td>
+    <td valign="top">the value of the HTTP request header. You may alternatively
+      specify the value as text between the beginning and ending header tags.</td>
+    <td valign="center" align="middle">Yes</td>
+  </tr>
+</table>
+<h3>Quirky Limitations of java.net classes</h3>
+Multiple HTTP headers can with the same name can <b>not</b> be set, even 
+though the protocol permits it. Java1.1 and Java 1.2 <i>may</i> permit multiple 
+cookies to be set, but this behaviour is explicitly not supported on Java1.3,
+as someone went and change the code to stop this (Java bug ID #4242254). 
+You need to set multiple cookies in one go and hope the far end can handle it
+<p>
+Bug ID #4160499 covers another issue, to wit: some versions of Java throw
+exceptions when an error code is greater than 400 and the dest file isn't
+one of a few simple file types, but Java 1.2 and 1.3 do not. So there
+is no way to get the error text when a jsp page throws some exception.
+<p>
+Also, although this isnt going to be filed until we have a short
+test case, but if you recieve a short response with less content than 
+the content-length header promises, the library seems to silently 
+reduce the content length header to match, which seems the wrong action.     
+
+  
+  
+<h2><a name="httpget">HttpGet</a></h2>
+<h3>Description</h3>
+
+<p>Accesses a URL to retrieve a file or to cause some action on the server.</p>
+
+<p> This task should be preferred above the <a href="#cvs">CVS task</a> when doing 
+  automated builds. CVS is significantly slower than loading a compressed archive 
+  with http/ftp. This task will also retrieve content using other supported protocols, 
+  such as ftp: and file: 
+<p>All the attributes of httptask may be used. Note that a quirk of the implementation 
+  of the http client in java makes it impossible to reliably fetch the response 
+  details from any unsuccessful request against a URL which doesn't end in '.htm,.html 
+  or .txt'. This means that if the task is used to compile jsp pages by issuing 
+  request against them, the text details of any errors will not be picked up. 
+<h3>Examples</h3>
+
+<pre>  &lt;httpget url=&quot;http://jakarta.apache.org/&quot; dest=&quot;help/index.html&quot;/&gt;</pre>
+<p>Fetches the index page of http://jakarta.apache.org/, and stores it in the 
+  file <code>help/index.html</code>. </p>
+
+<pre>    &lt;httpget src=&quot;http://jakarta.apache.org/builds/tomcat/nightly/ant.zip&quot;
+        dest=&quot;optional.jar&quot;
+        verbose=&quot;true&quot;
+        usetimestamp=&quot;true&quot;
+	&gt;
+        &lt;header name=&quot;Cookie&quot; value=&quot;someid=43ff2b&quot;/&gt;
+    &lt;/httpget&gt;</pre>
+<p> Retrieves the nightly ant build from the tomcat distribution, if the local 
+  copy is missing or out of date. Uses the verbose option for progress information. 
+  A cookie is supplied for the server's benefit.</p>
+<pre>    &lt;httpget url="https://www.pizzaservices.com/prices.jsp"
+         dest="pizza-prices.xml&quot;&gt;
+       &lt;param name=&quot;zipcode&quot;&gt;57340&lt;/param&gt;
+       &lt;param name=&quot;pizza&quot;&gt;pepperoni&lt;/param&gt;
+    &lt;/httpget&gt;</pre>
+<p>Builds a URL by adding parameters (&quot;?zipcode=57340&amp;pizza=pepperoni&quot;) 
+  to the base URL and then fetches the contents (fictional example)</p>
+<h2><a name="httphead">HttpHead</a> </h2>
+<p>The http HEAD request is similar to the normal GET request , except it, by 
+  definition, returns no content, just a success code and http headers. Accordingly, 
+  the destination properties of the base class -<i>dest</i> and -, <i>destinationpropertyname</i>) 
+  are not supported -any attempt to use them will result in a build failure. Note 
+  also that the http and https protocols are the only protocols supported. </p>
+<p>
+HttpHead is useful for triggering server side actions, but note that many servers
+interpret a HEAD very differently from a GET. An HttpGet request with the
+return data discarded is often a more reliable approach.
+</p>
+
+<p> Where head can be useful is in testing for the availability and reachability 
+  of servers, such as in the following test for apache being reachable, which 
+  sets a variable on success:- 
+<pre>
+    &lt;httphead url="http://www.apache.org/"
+    	 failonerror="false"
+    	 successproperty="reachable.apache"
+    	 /&gt;
+</pre>
+
+<p>Note that sometimes a missing file on a mis-configured server still generates 
+  a successful '200' response to a GET request -and returns a 'missing' file page, 
+  but a HEAD request will reliably pick up the 'missing file' error. </p>
+<h2><a name="httppost">HttpPost</a></h2>
+
+<p>This implements the POST request. Supplied parameter data is turned into form 
+  data and sent as the body of the request, rather than appended to the URL. If 
+  a file to upload is specified instead, using <i>uploadFile</i>, the parameter 
+  values are ignored. Instead the content type of the file is sent in the header 
+  -based on the <i>contentType</i> attribute or what the java runtime thinks the 
+  content type is based on the file extension. The file is uploaded. </p>
+
+<p>Like HttpGet, this command can return a content which can downloaded to a file,
+  to a property, or just ignored.</p>
+
+<p>This task adds two new attributes to the base set. </p>
+<table cellspacing="0" cellpadding="2" border="1">
+  <tr>
+    <td valign="top" width="78"><b>Attribute</b></td>
+    <td valign="top" width="559"><b>Description</b></td>
+    <td valign="top" align="middle" width="62"><b>Required</b></td>
+  </tr>
+  <tr>
+    <td valign="top" width="78">uploadFile</td>
+    <td valign="top" width="559">a file to upload. when specified, all parameters
+      are ignored.</td>
+    <td valign="top" align="middle" width="62">
+      <div align="center">no</div>
+    </td>
+  </tr>
+  <tr>
+    <td valign="top" width="78">contentType </td>
+    <td valign="top" width="559">the type of the content (text/html, text/xml,
+      application/binary, etc). Only of relevance when a file is being uploaded,
+      and still optional in that case. </td>
+    <td valign="center" align="middle" width="62">
+      <div align="center">no</div>
+    </td>
+  </tr>
+</table>
+<h3></h3>
+<pre>
+   &lt;httppost url=&quot;http://www.example.com/servlet/docserver&quot;
+           authtype=&quot;basic&quot; username=&quot;joe&quot; password=&quot;silly&quot;&gt;
+       &lt;param name=&quot;action&quot; value=&quot;getdoc&quot;/&gt;
+       &lt;param name=&quot;ISBN&quot;&gt;038550120X&lt;/param&gt;
+       &lt;param name=&quot;pages&quot;&gt;19-20&lt;/param&gt;
+       &lt;header name=&quot;Accept-Language&quot; value=&quot;en-us&quot;/&gt;
+   &lt;/httppost&gt;</pre>
+<p>Accesses a server at www.foo.com, passing a request to some servlet asking it
+to retrieve several pages from a stored book. An HTTP header specifying
+acceptable languages for the returned contents is also sent. Basic
+authentication is used with a user name of &quot;joe&quot; and a password of
+&quot;silly&quot;.</p>
+<p>
+<pre>    &lt;httppost url="https://www.pizzaservices.com"
+         uploadFile="pizza-order.xml"
+         contentType="text/xml"&gt;
+</pre>
+<p>Sends a pre-prepared order for a pizza to a pizza vendor accepting orders using 
+  xml-rpc requests. (NB: fictional example) </p>
+<h2><a name="SetProxy"></a>SetProxy</h2>
+<p>This task configures the proxy settings for all http tasks which follow it 
+  in the build. That includes the original Get task, but not the telnet and FTP 
+  tasks. The proxy settings remain in place until changed or the build finishes, 
+  and will also hold for other ant build files invoked and even non-forked java 
+  invocations, and even URL resolutions of XML parsers running in the same JVM
+  </p>
+<table cellspacing="0" cellpadding="2" border="1">
+  <tr> 
+    <td valign="top" width="78"><b>Attribute</b></td>
+    <td valign="top" width="559"><b>Description</b></td>
+    <td valign="top" align="middle" width="62"><b>Required</b></td>
+  </tr>
+  <tr> 
+    <td valign="top" width="78">proxyHost</td>
+    <td valign="top" width="559">hostname of a web/ftp proxy server</td>
+    <td valign="top" align="middle" width="62"> 
+      <div align="center">no</div>
+    </td>
+  </tr>
+  <tr> 
+    <td valign="top" width="78">proxyPort </td>
+    <td valign="top" width="559">integer; the port of the proxy server</td>
+    <td valign="center" align="middle" width="62"> 
+      <div align="center">no</div>
+    </td>
+  </tr>
+  <tr> 
+    <td valign="top" width="78">socksProxyHost</td>
+    <td valign="top" width="559">hostname of a SOCKS4 proxy server</td>
+    <td valign="center" align="middle" width="62"> 
+      <div align="center">no</div>
+    </td>
+  </tr>
+  <tr> 
+    <td valign="top" width="78">socksProxyPort</td>
+    <td valign="top" width="559">integer; port number of a SOCKS4 server (default=1080)</td>
+    <td valign="center" align="middle" width="62"> 
+      <div align="center">no</div>
+    </td>
+  </tr>
+</table>
+<h3></h3>
+<p>Turn off all proxies</p>
+<pre>    &lt;setproxy proxyhost=&quot;&quot; socksProxyHost=&quot;&quot; /&gt;</pre>
+<p>Set web proxy to 'web-proxy:80'; do not make any changes to existing socks 
+  settings (if any)</p>
+<pre>    &lt;setproxy proxyHost=&quot;web-proxy&quot; proxyPort=&quot;80&quot;/&gt;</pre>
+<p>Turn on socks</p>
+<pre>    &lt;setproxy socksProxyHost=&quot;socks-server&quot; socksProxyPort=&quot;1080&quot;/&gt;</pre>
+<p>Do nothing</p>
+<pre>    &lt;setproxy/&gt;</pre>
+<hr>
+<p align="center">Copyright &copy; 2000,2001 Apache Software Foundation. All rights
+Reserved.</p>
+
+</body>
+</html>
+
+
+
+
+
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/Base64Encode.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/Base64Encode.java
new file mode 100644
index 0000000..e5f4e3c
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/Base64Encode.java
@@ -0,0 +1,113 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+/**
+ * This code handles Base64 encoding for basic authentication
+ * and the like
+ *
+ * @created 02 April 2001
+ */
+class Base64Encode {
+
+    /**
+     * the encode alphabet
+     */
+    private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
+
+
+    /**
+     * Encode a block of binary data as base64 as specified in RFC1521.
+     *
+     * @param data the binary data to encode.
+     * @return An array of characters that represent the data encoded
+     *      as Base64
+     */
+    public char[] encodeBase64(byte[] data) {
+        char[] out = new char[((data.length + 2) / 3) * 4];
+
+        //
+        // 3 bytes encode to 4 chars.  Output is always an even
+        // multiple of 4 characters.
+        //
+        for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
+            boolean quad = false;
+            boolean triple = false;
+            //convert to unsigned byte
+            int val = (0xFF & (int) data[i]);
+            val <<= 8;
+            if ((i + 1) < data.length) {
+                val |= (0xFF & (int) data[i + 1]);
+                triple = true;
+            }
+            val <<= 8;
+            if ((i + 2) < data.length) {
+                val |= (0xFF & (int) data[i + 2]);
+                quad = true;
+            }
+            out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
+            val >>= 6;
+            out[index + 2] = alphabet[(triple ? (val & 0x3F) : 64)];
+            val >>= 6;
+            out[index + 1] = alphabet[val & 0x3F];
+            val >>= 6;
+            out[index + 0] = alphabet[val & 0x3F];
+        }
+        return out;
+    }
+
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/ContentGuesser.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/ContentGuesser.java
new file mode 100644
index 0000000..112b351
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/ContentGuesser.java
@@ -0,0 +1,99 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.IOException;
+import java.net.*;
+
+/**
+ * this is a class to work around the fact a function I want (guessContentTypeFromName)
+ * is protected.
+ *
+ * @created March 17, 2001
+ */
+class ContentGuesser extends URLConnection {
+
+    /**
+     * stub Constructor for the ContentGuesser object
+     *
+     * @param url Description of Parameter
+     */
+    ContentGuesser(URL url) {
+        super(url);
+    }
+
+
+    /**
+     * this stub is needed for the build
+     *
+     * @exception IOException Description of Exception
+     */
+    public void connect()
+        throws IOException {
+    }
+
+
+    /**
+     * make a protected method public.
+     * This guesses file type from extension. It's ok for very
+     * well known types...
+     * @param filename file to guess type of
+     * @return what the system guessed
+     */
+    public static String guessContentType(String filename) {
+        return guessContentTypeFromName(filename);
+    }
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpAuthenticationStrategy.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpAuthenticationStrategy.java
new file mode 100644
index 0000000..c24ac03
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpAuthenticationStrategy.java
@@ -0,0 +1,86 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import org.apache.tools.ant.BuildException;
+import java.net.URLConnection;
+
+/**
+ * this interface is for use by classes which authenticate connections.
+ *
+ * @created 20 March 2001
+ */
+
+public interface HttpAuthenticationStrategy {
+
+
+    /**
+     * Sets the AuthenticationHeader attribute of the HttpAuthStrategy
+     * object
+     *
+     * @param requestConnection The current request
+     * @param responseConnection any previous request, which can contain a
+     *          challenge for the next round. Will often be null
+     * @param user the current user name
+     * @param password the current password
+     */
+    public void setAuthenticationHeader(URLConnection requestConnection,
+            URLConnection responseConnection,
+            String user, String password)
+            throws BuildException ;
+
+
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpBasicAuth.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpBasicAuth.java
new file mode 100644
index 0000000..937fd98
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpBasicAuth.java
@@ -0,0 +1,107 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.taskdefs.Get;
+
+
+/**
+ * this class implements basic auth, the one that shouldn't be used
+ * except over an encrypted link or trusted network.
+ *
+ * @created 20 March 2001
+ */
+
+public class HttpBasicAuth implements HttpAuthenticationStrategy {
+
+
+    /**
+     * Sets the AuthenticationHeader attribute of the HttpAuthStrategy
+     * object
+     *
+     * @param requestConnection The current request
+     * @param responseConnection any previous request, which can contain a
+     *          challenge for the next round. Will often be null
+     * @param user the current user name
+     * @param password the current password
+     */
+    public void setAuthenticationHeader(URLConnection requestConnection,
+            URLConnection responseConnection,
+            String username, String password)
+            throws BuildException {
+
+        if (username != null) {
+            password = username == null ? "" : password;
+            String encodeStr = username + ":" + password;
+            char[] encodedPass;
+            String encodedPassStr;
+            
+            Base64Encode encoder = new Base64Encode();
+            encodedPass = encoder.encodeBase64(encodeStr.getBytes());
+            encodedPassStr= new String(encodedPass);
+            /* this uses the get task
+            Get.Base64Converter converter= new Get.Base64Converter();
+            encodedPassStr = converter.encode(encodeStr);
+            */
+            String authStr = "BASIC " +encodedPassStr;
+            requestConnection.setRequestProperty("Authorization", authStr);
+            }
+        }
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpDigestAuth.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpDigestAuth.java
new file mode 100644
index 0000000..399f49b
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpDigestAuth.java
@@ -0,0 +1,98 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+
+
+/**
+ * this class implements basic auth, the one that shouldn't be used
+ * except over an encrypted link or trusted network.
+ *
+ * @created 20 March 2001
+ */
+
+public class HttpDigestAuth implements HttpAuthenticationStrategy {
+
+
+    /**
+     * Sets the AuthenticationHeader attribute of the HttpAuthStrategy
+     * object
+     *
+     * @param requestConnection The current request
+     * @param responseConnection any previous request, which can contain a
+     *          challenge for the next round. Will often be null
+     * @param user the current user name
+     * @param password the current password
+     */
+    public void setAuthenticationHeader(URLConnection requestConnection,
+            URLConnection responseConnection,
+            String username, String password)
+            throws BuildException {
+
+        if (username != null) {
+            password = username == null ? "" : password;
+            String encodeStr = username + ":" + password;
+            Base64Encode encoder = new Base64Encode();
+            char[] encodedPass = encoder.encodeBase64(encodeStr.getBytes());
+            String authStr = "BASIC " + new String(encodedPass);
+            requestConnection.setRequestProperty("Authorization", authStr);
+            }
+        }
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpGet.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpGet.java
new file mode 100644
index 0000000..264c3c1
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpGet.java
@@ -0,0 +1,90 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+
+/**
+ * This class implements boring old HTTP1.0 get. It represents
+ * a refactoring of Get to HttpTask and then into a specific
+ * subclass. because almost everything is done by the parent,
+ * this class is almost completely empty
+ * @since ant1.5
+ * @created March 17, 2001
+ */
+
+public class HttpGet extends HttpTask {
+
+     /**
+     * override of test
+     * @return true always
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return true;
+    }
+
+     /**
+     * this must be overridden by implementations
+     * to set the request method to GET, POST, whatever
+     * @return GET, obviously
+     */
+     public String getRequestMethod() {
+         return "GET";
+     }
+}
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpHead.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpHead.java
new file mode 100644
index 0000000..3742a60
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpHead.java
@@ -0,0 +1,109 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+
+/**
+ * Head is a get with a different method and the notion of
+ * destination file missing. Why would anyone want to make a HEAD
+ * request? a) side effects on the server and b) polling for stuff
+ * @since ant1.5
+ * @created March 17, 2001
+ */
+
+public class HttpHead extends HttpTask {
+
+     /**
+     * this must be overridden by implementations
+     * to set the request method to GET, POST, whatever
+     * @return HEAD always
+     */
+     public String getRequestMethod() {
+         return "HEAD";
+     }
+
+     /**
+     * override of test
+     * @return true always
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return true;
+    }
+
+    /**
+     * add a check for all the destination settings being
+     * null; nothing else makes sense for a HEAD.
+     *
+     * @return true if everything is fine. false if we have encountered
+     *      problems but arent allowed to fail on an error,
+     * @exception BuildException only throw this when the failonerror
+     *      flag is true
+     */
+
+    protected void verifyArguments()
+        throws BuildException {
+        BuildException trouble = null;
+        if(getDest() != null || getDestinationProperty() !=null) {
+            throw new BuildException("destination properties must not be defined for a HEAD request");
+        }
+        super.verifyArguments();
+    }
+
+}
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpPost.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpPost.java
new file mode 100644
index 0000000..fbb30c0
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpPost.java
@@ -0,0 +1,222 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+
+/**
+ * this class does post of form content or raw files. you can have one
+ * or the other -as soon as a file is specified all the other properties
+ * are dropped on the floor.
+ * a file post will have content type determined from the extension, you can
+ * override it
+ * @since ant1.5
+ * @created March 17, 2001
+ */
+
+public class HttpPost extends HttpTask {
+
+    /**
+     * file to upload. Null is ok
+     */
+
+    protected File postFile=null;
+
+    /**
+     * set the file to post
+     */
+    public void setUploadFile(File postFile) {
+        this.postFile=postFile;
+    }
+
+     /**
+      * query the post file
+      * @return the file or null for 'not defined'
+      */
+    public File getUploadFile() {
+        return postFile;
+    }
+
+    /**
+     * content type. ignored when the file is null,
+     * and even then we guess it if aint specified
+     */
+
+     private String contentType;
+
+     /**
+      * set the content type. Recommended if a file is being uploaded
+      */
+     public void setContentType(String contentType) {
+         this.contentType=contentType;
+     }
+
+     /**
+      * query the content type
+      * @return the content type or null for 'not defined'
+      */
+     public String getContentType() {
+         return contentType;
+     }
+
+     /**
+     * override of test
+     * @return false always
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return false;
+    }
+
+    /**
+     * this override of the base connect pumps
+     * up the parameter vector as form data
+     *
+      * @param connection where to connect to
+     * @exception BuildException build trouble
+     * @exception IOException IO trouble
+     */
+    protected URLConnection doConnect(URLConnection connection)
+        throws BuildException, IOException {
+
+        if(postFile==null) {
+            return doConnectFormPost(connection);
+        }
+        else {
+            return doConnectFilePost(connection);
+        }
+    }
+
+    /**
+     * feed up the parameter vector as form data
+     *
+      * @param connection where to connect to
+     * @exception BuildException build trouble
+     * @exception IOException IO trouble
+     */
+    protected URLConnection doConnectFormPost(URLConnection connection)
+        throws BuildException, IOException {
+
+        log("Posting data as a form",Project.MSG_VERBOSE);
+        // Create the output payload
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream(256);
+        PrintWriter out = new PrintWriter(byteStream);
+        writePostData(out);
+        out.flush();
+        out.close();
+        byte[] data=byteStream.toByteArray();
+        //send it
+        
+        return doConnectWithUpload(connection,
+                "application/x-www-form-urlencoded",
+                byteStream.size(),
+                new ByteArrayInputStream(data));
+    }
+
+    /**
+     * feed up the data file
+     *
+      * @param connection where to connect to
+     * @exception BuildException build trouble
+     * @exception IOException IO trouble
+     */
+    protected URLConnection doConnectFilePost(URLConnection connection)
+        throws BuildException, IOException {
+        int size=(int)postFile.length();
+        log("Posting file "+postFile,Project.MSG_VERBOSE);
+        InputStream instream=new FileInputStream(postFile);
+        String type=contentType;
+        if(type==null) {
+            type=ContentGuesser.guessContentType(postFile.getName());
+        }
+        return doConnectWithUpload(connection,
+                type,
+                size,
+                instream);
+    }
+
+
+    /**
+     * write out post data in form mode
+     *
+     * @param out Description of Parameter
+     */
+    protected void writePostData(PrintWriter out) {
+        HttpRequestParameter param;
+        Vector params=getRequestParameters();
+        for (int i = 0; i < params.size(); i++) {
+            if (i > 0) {
+                out.print('&');
+            }
+            param = (HttpRequestParameter) params.get(i);
+            out.print(param.toString());
+            log("parameter : "+param.toString(),Project.MSG_DEBUG);
+        }
+    }
+
+     /**
+     * this must be overridden by implementations
+     * to set the request method to GET, POST, whatever
+     * @return the method string
+     */
+     public String getRequestMethod() {
+         return "POST";
+     }
+
+
+}
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpRequestParameter.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpRequestParameter.java
new file mode 100644
index 0000000..453248d
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpRequestParameter.java
@@ -0,0 +1,139 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+import java.net.URLEncoder;
+
+/**
+ * This class is used to store name-value pairs for request parameters
+ * and headers
+ *
+ * @created March 17, 2001
+ */
+
+public class HttpRequestParameter {
+
+    /**
+     * request name
+     */
+    private String name;
+    
+    /**
+     * request value
+     */
+    private String value;
+
+
+    /**
+     * Sets the Name attribute of the request parameter
+     *
+     * @param name The new Name value
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Sets the Value attribute of the request parameter
+     *
+     * @param value The new Value value
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+
+    /**
+     * Gets the Name attribute of the request parameter
+     *
+     * @return The Name value
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Gets the Value attribute of the request parameter
+     *
+     * @return The Value
+     */
+    public String getValue() {
+        return value;
+    }
+
+
+    /**
+     * Adds a feature to the Text attribute of the request parameter
+     *
+     * @param text The feature to be added to the Text attribute
+     */
+    public void addText(String text) {
+        this.value = text;
+    }
+
+
+    /**
+     * simple stringifier returning name and value encoded for use in HTTP requests
+     *
+     * @return a string for informational purposes
+     */
+    public String toString() {
+        return  URLEncoder.encode(getName())+
+            '='+URLEncoder.encode(getValue());
+    }
+
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpTask.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpTask.java
new file mode 100644
index 0000000..6dfcb75
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/HttpTask.java
@@ -0,0 +1,1141 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * This class is a foundational class for all the tasks which implement
+ * http methods. To implement a subclass you *must* provide
+ * an implementation of getRequestMethod(). Consider also
+ * stating the parameter policy (areParamsAddedToUrl()) and
+ * then, if needed, overriding doConnect, and the onConnected(),
+ * OnDownloadFinished() methods.
+ * @since ant1.5
+ * @created March 17, 2001
+ */
+public abstract class HttpTask extends Task {
+
+    /**
+     * flag to control action on execution trouble
+     */
+    protected boolean failOnError=true;
+
+    /**
+     * this sets the size of the buffer and the hash for download
+     */
+
+    protected int blockSize = 64;
+
+    /**
+     * property to set on success
+     */
+
+    protected String successProperty;
+
+    /**
+     * source URL. required
+     */
+    private String source;
+
+    /**
+     * destination for download
+     */
+    private File dest;
+    /**
+     * verbose flag gives extra information
+     */
+    private boolean verbose = false;
+
+    /**
+     * timestamp based download flag. off by default
+     */
+    private boolean useTimestamp = false;
+
+    /**
+     * authorization mechanism in use.
+     */
+    private int authType = AUTH_NONE;
+
+    /**
+     * username for authentication
+     */
+    private String username;
+
+    /**
+     * password for authentication
+     */
+    private String password;
+
+    /**
+     * parameters to send on a request
+     */
+    private Vector params = new Vector();
+
+    /**
+     * headers to send on a request
+     */
+    private Vector headers = new Vector();
+
+    /**
+     * cache policy
+     */
+    private boolean usecaches = false;
+
+    /**
+     * the name of a destination property
+     */
+
+    private String destinationPropname = null;
+
+    /***
+     * a flag to control whether or not response codes
+     * are acted on
+     */
+    private boolean useResponseCode=true;
+
+    /**
+     * No authentication specified
+     */
+    public final static int AUTH_NONE = 0;
+
+    /**
+     * basic 'cleartext' authentication
+     */
+    public final static int AUTH_BASIC = 1;
+
+    /**
+     * digest auth. not actually supported but present for completeness
+     */
+    public final static int AUTH_DIGEST = 2;
+
+
+    /**
+     * turn caching on or off. only relevant for protocols and methods
+     * which are cacheable (HEAD, GET) on http
+     *
+     * @param usecaches The new UseCaches value
+     */
+    public void setUseCaches(boolean usecaches) {
+        this.usecaches = usecaches;
+    }
+
+    /**
+     * turn caching on or off. only relevant for protocols and methods
+     * which are cacheable (HEAD, GET) on http
+     *
+     * @param usecaches The new UseCaches value
+     */
+    public void setUseResponseCode(boolean useResponseCodes ) {
+        this.useResponseCode  = useResponseCode ;
+    }
+
+
+    /**
+     * Set the URL.
+     *
+     * @param u URL for the file.
+     */
+    public void setURL(String u) {
+        this.source = u;
+    }
+
+
+    /**
+     * the local destination for any response. this can be null for 'dont
+     * download'
+     *
+     * @param dest Path to file.
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+/**
+     * the local destination for any response. this can be null for 'dont
+     * download'
+     *
+     * @param dest Path to file.
+     */
+    public void setDestinationProperty(String name) {
+        this.destinationPropname = name;
+    }
+
+
+    /**
+     * Be verbose, if set to " <CODE>true</CODE> ".
+     *
+     * @param verbose The new Verbose value
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+
+    /**
+     * set fail on error flag
+     *
+     * @param b The new FailOnError value
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+
+    /**
+     * Use timestamps, if set to " <CODE>true</CODE> ". <p>
+     *
+     * In this situation, the if-modified-since header is set so that
+     * the file is only fetched if it is newer than the local file (or
+     * there is no local file) This flag is only valid on HTTP connections,
+     * it is ignored in other cases. When the flag is set, the local copy
+     * of the downloaded file will also have its timestamp set to the
+     * remote file time. <br>
+     * Note that remote files of date 1/1/1970 (GMT) are treated as 'no
+     * timestamp', and web servers often serve files with a timestamp
+     * in the future by replacing their timestamp with that of the current
+     * time. Also, inter-computer clock differences can cause no end of
+     * grief.
+     *
+     * @param usetimestamp The new UseTimestamp value
+     */
+    public void setUseTimestamp(boolean usetimestamp) {
+        if (project.getJavaVersion() != Project.JAVA_1_1) {
+            this.useTimestamp = usetimestamp;
+        }
+        else {
+            log("usetimestamp is not supported on java 1.1", Project.MSG_WARN);
+        }
+    }
+
+
+    /**
+     * Sets the Authtype attribute of the HttpTask object REVISIT/REFACTOR
+     *
+     * @param type The new Authtype value
+     */
+    public void setAuthtype(AuthMethodType type) {
+        this.authType=type.mapValueToNumber();
+    }
+
+
+    /**
+     * Sets the Username used for authentication. setting the username
+     * implicitly turns authentication on.
+     *
+     * @param username The new Username value
+     */
+    public void setUsername(String username) {
+        this.username = username;
+        if (authType == AUTH_NONE) {
+            authType = AUTH_BASIC;
+        }
+    }
+
+
+    /**
+     * Sets the Password attribute of the HttpTask object
+     *
+     * @param password The new Password value
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+
+    /**
+     * set a variable to be set in the event of success
+     *
+     * @param successProperty The new SuccessProperty value
+     */
+    public void setSuccessProperty(String successProperty) {
+        this.successProperty = successProperty;
+    }
+
+    /**
+     * get block size (kb)
+     */
+
+     public int getBlockSize() {
+         return blockSize;
+     }
+
+     /**
+      * set the new block size for download
+      * @param the new value (in kilobytes)
+      */
+     public void setBlockSize(int blocksize) {
+         this.blockSize=blockSize;
+     }
+
+
+    /**
+     * query cache policy
+     *
+     * @return The UseCaches value
+     */
+    public boolean getUseCaches() {
+        return usecaches;
+    }
+
+
+    /**
+     * query fail on error flag
+     *
+     * @return The FailFailOnError value
+     */
+    public boolean getFailOnError() {
+        return failOnError;
+    }
+
+
+    /**
+     * get the username
+     *
+     * @return current username or null for 'none'
+     */
+    public String getUsername() {
+        return username;
+    }
+
+
+    /**
+     * get the password
+     *
+     * @return current password or null for 'none'
+     */
+    public String getPassword() {
+        return password;
+    }
+
+
+    /**
+     * @return The RemoteURL value
+     */
+    public String getURL() {
+        return source;
+    }
+
+
+    /**
+     * access parameters
+     *
+     * @return The RequestParameters value
+     */
+    public Vector getRequestParameters() {
+        return params;
+    }
+
+
+    /**
+     * accessor of success property name
+     *
+     * @return The SuccessProperty value
+     */
+    public String getSuccessProperty() {
+        return successProperty;
+    }
+
+    /**
+     * accessor of destination property name
+     *
+     * @return The destination value
+     */
+    public String getDestinationProperty() {
+        return destinationPropname;
+    }
+
+    /**
+     * accessor of destination
+     *
+     * @return Thedestination
+     */
+    public File getDest() {
+        return dest;
+    }
+
+
+    /**
+     * if the user wanted a success property, this is it. of course, it
+     * is only relevant if failonerror=false
+     *
+     * @return Description of the Returned Value
+     */
+
+    public void noteSuccess() {
+        if (successProperty != null && successProperty.length() > 0) {
+            getProject().setProperty(successProperty, "true");
+        }
+    }
+
+
+    /**
+     * Does the work.
+     * @todo extract content length header and use it to verify
+     * completeness of download
+     * @exception BuildException Thrown in unrecoverable error.
+     */
+    public void execute()
+        throws BuildException {
+
+        //check arguments, will bail out if there
+        //was trouble 
+        verifyArguments();
+        
+        //set up the URL connection
+        URL url = buildURL();
+
+        try {
+
+            //now create a connection
+            URLConnection connection = url.openConnection();
+
+            //set caching option to whatever
+            connection.setUseCaches(getUseCaches());
+
+            //set the timestamp option if flag is set and
+            //the local file actually exists.
+            long localTimestamp = getTimestamp();
+            if (localTimestamp != 0) {
+                if (verbose) {
+                    Date t = new Date(localTimestamp);
+                    log("local file date : " + t.toString());
+                }
+                connection.setIfModifiedSince(localTimestamp);
+            }
+
+            // Set auth header, if specified
+            //NB: verifyArguments will already have checked that you can't
+            //have a null username with a non-null strategy.
+            HttpAuthenticationStrategy authStrategy=getAuthStrategy();
+            if (authStrategy != null) {
+                authStrategy.setAuthenticationHeader(connection,null,username,password);
+            }
+
+            // Set explicitly specified request headers
+            HttpRequestParameter header;
+            for (int i = 0; i < headers.size(); i++) {
+                header = (HttpRequestParameter) headers.get(i);
+                connection.setRequestProperty(header.getName(), header.getValue());
+            }
+
+            //cast to an http connection if we can,
+            //then set the request method pulled from the subclass
+            String method=getRequestMethod();
+            HttpURLConnection httpConnection = null;
+            if (connection instanceof HttpURLConnection) {
+                httpConnection = (HttpURLConnection) connection;
+                httpConnection.setRequestMethod(method);
+            }
+            log("making "+method+" to "+url);
+
+            //call self or subclass for the connect.
+            //the connection object may change identity at this point.
+            connection=doConnect(connection);
+
+            //then provide a bit of overridable post processing for the fun of it
+            if (!onConnected(connection)) {
+                return;
+            }
+
+            //repeat the cast.
+            if (connection instanceof HttpURLConnection) {
+                httpConnection = (HttpURLConnection) connection;
+            }
+            if(httpConnection != null) {
+                // check for a 304 result (HTTP only) when we set the timestamp
+                // earlier on (A fractional performance tweak)
+                if (localTimestamp != 0) {
+                    if (getResponseCode(httpConnection) == HttpURLConnection.HTTP_NOT_MODIFIED) {
+                        //not modified so no file download. just return instead
+                        //and trace out something so the user doesn't think that the
+                        //download happened when it didn't
+                        log("Local file is up to date - so nothing was downloaded");
+                        noteSuccess();
+                        return;
+                    }
+                }
+
+            }
+            
+
+            //get the input stream
+            InputStream is = getInputStream(connection);
+
+            //bail out if the input stream isn't valid at this point
+            //again, though we should have got to this point earlier.
+            
+            if (is == null) {
+                log("Can't get " + url, Project.MSG_ERR);
+                if (getFailOnError()) {
+                    return;
+                }
+                throw new BuildException("Can't reach URL");
+            }
+
+            //pick a file or null stream for saving content
+            OutputStream out = null;
+            if (dest != null) {
+                log("Saving output to "+dest,Project.MSG_DEBUG);
+                out = new FileOutputStream(dest);
+            }
+            else {
+                if(destinationPropname!=null) {
+                    //save contents to a property
+                    log("Saving output to property "+destinationPropname,
+                        Project.MSG_DEBUG);
+                    out=new ByteArrayOutputStream(blockSize * 1024);
+                }
+                else {
+                    //discard everything
+                    out = new NullOutputStream();
+                }
+            }
+
+            //get content length
+            //do it this way instead of calling getContentLength() because
+            //that way is sporadically unreliable (length is downgraded to 
+            //size of small packets)
+            int contentLength=connection.getHeaderFieldInt("Content-Length",-1);
+            int bytesRead=0;
+            
+            //now start download.
+            byte[] buffer = new byte[blockSize * 1024];
+            int length;
+
+            while ((length = is.read(buffer)) >= 0 && 
+                (contentLength==-1 || bytesRead<contentLength)) {
+                bytesRead+=length;
+                out.write(buffer, 0, length);
+                if (verbose) {
+                    showProgressChar('.');
+                }
+            }
+
+            //finished successfully - clean up.
+            if (verbose) {
+                showProgressChar('\n');
+            }
+
+
+            //if it we were saving to a byte array, then
+            //set the destination property with its contents
+            if(out instanceof ByteArrayOutputStream) {
+                getProject().setProperty(destinationPropname,
+                        out.toString());
+            }
+            
+            //everything is downloaded; close files
+            out.flush();
+            out.close();
+            is.close();
+            is=null;
+            out=null;
+            
+
+            //another overridable notification method
+            if (!onDownloadFinished(connection)) {
+                return;
+            }
+
+            //REFACTOR: move this down to HttpHead? What if a post wants
+            //to set a date?
+            //if (and only if) the use file time option is set, then the
+            //saved file now has its timestamp set to that of the downloaded file
+            if (useTimestamp) {
+                long remoteTimestamp = connection.getLastModified();
+                if (verbose) {
+                    Date t = new Date(remoteTimestamp);
+                    log("last modified = " + t.toString()
+                             + ((remoteTimestamp == 0) ? " - using current time instead" : ""));
+                }
+                if (remoteTimestamp != 0) {
+                    touchFile(dest, remoteTimestamp);
+                }
+            }
+
+            
+            String failureString=null;
+            if(contentLength>-1 && bytesRead!=contentLength) {
+                failureString="Incomplete download -Expected "+contentLength
+                                +"received "+bytesRead+" bytes";
+            }
+            else {
+
+                //finally clean anything up.
+                //http requests have their response code checked, and only
+                //those in the success range are deemed successful.
+                if (httpConnection != null && useResponseCode) {
+                    int statusCode=httpConnection.getResponseCode();
+                    if(statusCode <200 || statusCode >299) {
+                         failureString="Server error code "+statusCode+" received";
+                    }
+                }
+            }
+                
+            //check for an error message
+            if(failureString==null) {
+                noteSuccess();
+            }
+            else {
+                if(failOnError)
+                    throw new BuildException(failureString);
+                else
+                    log(failureString,Project.MSG_ERR);
+            }
+            
+        }
+        catch (IOException ioe) {
+            log("Error performing "+getRequestMethod() +" on " + url +
+                " : "+ioe.toString(), Project.MSG_ERR);
+            if (failOnError) {
+                throw new BuildException(ioe);
+            }
+        }
+    }
+
+    /**
+     * show a progress character
+     * @todo this doesn't work in shell wrappers
+     */
+
+    protected void showProgressChar(char c) {
+        System.out.write(c);
+    }
+
+
+    /**
+     * Adds a form / request parameter.
+     *
+     * @param param The feature to be added to the HttpRequestParameter
+     *      attribute
+     */
+    public void addParam(HttpRequestParameter param) {
+        params.add(param);
+    }
+
+
+    /**
+     * Adds an HTTP request header.
+     *
+     * @param header The feature to be added to the Header attribute
+     */
+    public void addHeader(HttpRequestParameter header) {
+        headers.add(header);
+    }
+
+
+    /**
+     * this must be overridden by implementations to set the request method
+     * to GET, POST, whatever NB: this method only gets called for an
+     * http request
+     *
+     * @return the method string
+     */
+    protected abstract String getRequestMethod();
+
+
+    /**
+     * determine the timestamp to use if the flag is set and the local
+     * file actually exists.
+     *
+     * @return 0 for 'no timestamp', a number otherwhise
+     */
+
+    protected long getTimestamp() {
+        long timestamp = 0;
+        if (useTimestamp && dest != null && dest.exists()) {
+            timestamp = dest.lastModified();
+        }
+        else {
+            timestamp = 0;
+        }
+        return timestamp;
+    }
+
+
+    /**
+     * ask for authentication details. An empty string means 'no auth'
+     *
+     * @return an RFC2617 auth string
+     */
+
+    protected String getAuthenticationString() {
+        // Set authorization eader, if specified
+        if (authType == AUTH_BASIC && username != null) {
+            password = password == null ? "" : password;
+            String encodeStr = username + ":" + password;
+            Base64Encode encoder = new Base64Encode();
+            char[] encodedPass = encoder.encodeBase64(encodeStr.getBytes());
+            String authStr = "BASIC " + new String(encodedPass);
+            return authStr;
+        }
+        else {
+            return null;
+        }
+    }
+
+
+    /**
+     * this overridable method verifies that all the params are valid
+     * the base implementation checks for remote url validity and if the
+     * destination is not null, write access to what mustnt be a directory.
+     * sublcasses can call the base class as well as check their own data
+     *
+     * @return true if everything is fine. false if we have encountered
+     *      problems but arent allowed to fail on an error,
+     * @exception BuildException only throw this when the failonerror
+     *      flag is true
+     */
+
+    protected void verifyArguments()
+        throws BuildException {
+        BuildException trouble = null;
+        //check remote params -but only create an exception, not throw it
+        if (getURL() == null) {
+            throw new BuildException("target URL missing");
+        }
+        //check destination parameters  -but only create an exception, not throw it
+        if (dest != null && dest.exists()) {
+            if (dest.isDirectory()) {
+                throw new BuildException("The specified destination is a directory");
+            }
+            else if (!dest.canWrite()) {
+                throw new BuildException("Can't write to " + dest.getAbsolutePath());
+            }
+        }
+        //check auth policy
+        if(authType!=AUTH_NONE && username==null) {
+           throw new BuildException("no username defined to use with authorisation");
+        }
+     }
+
+
+    /**
+     * set the timestamp of a named file to a specified time. prints a
+     * warning on java1.1
+     *
+     * @param file Description of Parameter
+     * @param timemillis Description of Parameter
+     * @exception BuildException Thrown in unrecoverable error. Likely
+     *      this comes from file access failures.
+     */
+    protected void touchFile(File file, long timemillis)
+        throws BuildException {
+        getProject().setFileLastModified(file, timemillis);
+    }
+
+
+    /**
+     * build a URL from the source url, maybe with parameters attached
+     *
+     * @return Description of the Returned Value
+     * @exception BuildException Description of Exception
+     */
+    protected URL buildURL()
+        throws BuildException {
+        String urlbase = getURL();
+        try {
+            if (areParamsAddedToUrl()) {
+                urlbase = parameterizeURL();
+            }
+            return new URL(urlbase);
+        }
+        catch (MalformedURLException e) {
+            throw new BuildException("Invalid URL");
+        }
+    }
+
+
+    /**
+     * take a url and add parameters to it. if there are no parameters
+     * the base url string is returned
+     *
+     * @return a string to be used for URL creation
+     * @exception BuildException Description of Exception
+     */
+    protected String parameterizeURL()
+        throws BuildException {
+        //return immediately if there are no parameters
+        if (params.size() == 0) {
+            return getURL();
+        }
+
+        StringBuffer buf = new StringBuffer(getURL());
+        //this devious little line code recognises a parameter string already
+        //in the source url, and if so doesnt add a new one
+        buf.append(source.indexOf('?') == -1 ? '?' : '&');
+        HttpRequestParameter param;
+
+        //run through the parameter list, encode the name/value pairs and
+        //append them to the list
+        for (int i = 0; i < params.size(); i++) {
+            if (i > 0) {
+                buf.append('&');
+            }
+            param = (HttpRequestParameter) params.get(i);
+            buf.append(param.toString());
+        }
+        return buf.toString();
+    }
+
+
+    /**
+     * query for the request wanting parameters on the url default is
+     * true, subclasses may want to change
+     *
+     * @return true if a url should have params attached.
+     */
+
+    protected boolean areParamsAddedToUrl() {
+        return true;
+    }
+
+    /**
+     * get the auth policy
+     * a null return value means 'no policy chosen'
+     * @return current authorisation strategy or null
+     */
+
+     protected HttpAuthenticationStrategy getAuthStrategy() {
+        HttpAuthenticationStrategy strategy=null;
+        switch(authType) {
+            case AUTH_BASIC:
+                strategy=new HttpBasicAuth();
+                break;
+
+            case AUTH_DIGEST:
+                //TODO
+                break;
+
+            case AUTH_NONE:
+            default:
+                break;
+        }
+        return strategy;
+
+     }
+
+    /**
+     * this method opens the connection. It can recognise a 401 error code
+     * and in digest auth will then open a new connection with the
+     * supplied nonce encoded. That is why it can return a new
+     * connection object.
+     * @todo handle digest auth
+     * @param connection where to connect to
+     * @exception BuildException build trouble
+     * @exception IOException IO trouble
+     * @return a new connection. This may be different than the old one
+     */
+
+    protected URLConnection makeConnectionWithAuthHandling(URLConnection connection)
+        throws BuildException, IOException {
+        log("Connecting to "+connection.toString(),Project.MSG_DEBUG);    
+        connection.connect();
+        URLConnection returnConnection=connection;
+        log("connected",Project.MSG_DEBUG);
+        if (connection instanceof HttpURLConnection) {
+            HttpURLConnection httpConnection = (HttpURLConnection) connection;
+            if(getResponseCode(httpConnection)==HttpURLConnection.HTTP_UNAUTHORIZED
+                        && authType==AUTH_DIGEST) {
+                //TODO auth failure. in digest mode we can make a new auth
+                //duplicating all the settings then reconnect
+                //and return it
+                log("Digest authentication needed but not yet supported",Project.MSG_DEBUG);
+            }
+        }
+
+        return returnConnection;
+    }
+
+
+    /** 
+     * by making a query for a value from the connection, we force the
+     * client code to actually do the http request and go into input mode.
+     * so next we can check for trouble. 
+     */
+    void probeConnection (HttpURLConnection connection) {
+        String probe=connection.getHeaderFieldKey(0);
+    }
+    
+
+    /**
+     * get a response from a connection request.
+     * This code fixes a problem found in HttpURLConnection, that
+     * any attempt to get the response code would trigger a FileNotFound
+     * @see <a href="http://developer.java.sun.com/developer/bugParade/bugs/4160499.html">
+     * BugParade details </a>
+     * "If the requested file does not exist, and ends in .html, .htm, .txt or /, you
+     *  will get the error stream with no exception thrown. If the file does not end
+     *  like any of these you can catch the exception and immediately request it again
+     *  to get the error stream. The response code can be obtained with
+     *  getResponseCode()."
+     * which means, to really get the response code you need to ask twice.
+     * @param connection the current http link
+     * @return whatever we get back
+     * @throws IOException if anything other than file not found gets thrown,
+     * and even a FileNotFound exception if that gets thrown too many times.
+     */
+    protected int getResponseCode(HttpURLConnection connection)
+    throws IOException  {
+        //force the creation of the input stream
+        //(which is what HttpURLConnection.getResponseCode() does internally
+        //that way the bug handler code is only needed once.
+
+        //probeConnection(connection);
+        IOException swallowed=null;
+        boolean caught=false;
+        int response=0;
+        for (int attempts = 0; attempts < 5; attempts++) {
+            try {
+                response = connection.getResponseCode();
+                caught=true;
+                break;
+            }
+            catch (FileNotFoundException ex) {
+                log("Swallowed FileNotFoundException in getResponseCode",
+                    Project.MSG_VERBOSE);
+                log(ex.toString(),Project.MSG_DEBUG);
+                swallowed=ex;
+            }
+        }
+        if(!caught && swallowed!=null) {
+            throw swallowed;
+        }
+        return response;
+    }
+
+    /**
+     * get an input stream from a connection
+     * This code tries to fix a problem found in HttpURLConnection, that
+     * any attempt to get the response code would trigger a FileNotFound
+     * BugParade ID 4160499 :
+     * <blockquote>
+     * "If the requested file does not exist, and ends in .html, .htm, .txt or /, you
+     *  will get the error stream with no exception thrown. If the file does not end
+     *  like any of these you can catch the exception and immediately request it again
+     *  to get the error stream. The response code can be obtained with
+     *  getResponseCode()."
+     * <blockquote>
+     * which means, to really get the response code you need to ask twice. More to the point
+     * this handling is not consistent across JVMs: on java 1.3 you can ask as often as you like
+     * but you are not going to get the input stream on a JSP page when it has some 500 class error.
+     * @param connection the current link
+     * @return the input stream.
+     * @throws IOException if anything other than file not found gets thrown,
+     * and even a FileNotFound exception if that gets thrown too many times.
+     */
+
+   protected InputStream getInputStream(URLConnection connection)
+    throws IOException  {
+        IOException swallowed=null;
+        InputStream instream=null;
+        for (int attempts = 0; attempts < 5; attempts++) {
+            try {
+                instream = connection.getInputStream();
+                break;
+            }
+            catch (FileNotFoundException ex) {
+                log("Swallowed IO exception in getInputStream",
+                    Project.MSG_VERBOSE);
+                log(ex.toString(),Project.MSG_DEBUG);
+                swallowed=ex;
+            }
+        }
+        if(instream==null && swallowed!=null) {
+            throw swallowed;
+        }
+        return instream;
+    }
+
+
+
+    /**
+     * this method is inteded for overriding. it is called when connecting
+     * to a URL, and the base implementation just calls connect() on the
+     * parameter. any subclass that wants to pump its own datastream up
+     * (like post) must override this
+     *
+     * @param connection where to connect to
+     * @exception BuildException build trouble
+     * @exception IOException IO trouble
+     */
+
+    protected URLConnection doConnect(URLConnection connection)
+        throws BuildException, IOException {
+        return makeConnectionWithAuthHandling(connection);
+    }
+
+
+    /**
+     * this is a method for upload centric post-like requests
+     *
+     * @param connection who we talk to
+     * @param contentType Description of Parameter
+     * @param contentLength Description of Parameter
+     * @param content Description of Parameter
+     * @exception IOException something went wrong with the IO
+     */
+    protected URLConnection doConnectWithUpload(URLConnection connection,
+            String contentType, int contentLength,
+            InputStream content)
+        throws IOException {
+
+        log("uploading " + contentLength + " bytes of type " + contentType,
+                Project.MSG_VERBOSE);
+        //tell the connection we are in output mode
+        connection.setDoOutput(true);
+
+
+        // Set content length and type headers
+        connection.setRequestProperty("Content-Length", String.valueOf(contentLength));
+        connection.setRequestProperty("Content-Type", contentType);
+        //todo: add auth handling
+        //connection=makeConnectionWithAuthHandling(connection);
+        connection.connect();
+        OutputStream toServer = connection.getOutputStream();
+
+        //create a buffer which is the smaller of
+        //the content length and the block size (in KB)
+        int buffersize=blockSize*1024;
+        if(contentLength<buffersize)
+            buffersize=contentLength;
+        byte[] buffer = new byte[buffersize];
+        int remaining = contentLength;
+
+        while (remaining > 0) {
+            int read = content.read(buffer);
+            log("block of "+read,Project.MSG_DEBUG);
+            toServer.write(buffer, 0, read);
+            remaining -= read;
+            if (verbose) {
+                showProgressChar('^');
+            }
+        }
+        if (verbose) {
+            showProgressChar('\n');
+        }
+        log("upload completed",Project.MSG_DEBUG);
+        return connection;
+    }
+
+    /**
+     * internal event handler called after a connect can throw an exception
+     * or return false for an immediate exit from the process
+     *
+     * @param connection the now open connection
+     * @return true if the execution is to continue
+     * @exception BuildException Description of Exception
+     */
+    protected boolean onConnected(URLConnection connection)
+        throws BuildException {
+        return true;
+    }
+
+
+    /**
+     * internal event handler called after the download is complete the
+     * code can still bail out at this point, and the connection may contain
+     * headers of interest. can throw an exception or return false for
+     * an immediate exit from the process
+     *
+     * @param connection the now open connection
+     * @return true if the execution is to continue
+     * @exception BuildException Description of Exception
+     */
+    protected boolean onDownloadFinished(URLConnection connection)
+        throws BuildException {
+        return true;
+    }
+
+
+    /**
+     * Enumerated attribute for "authType" with the value "basic" (note,
+     * eventually we can add "digest" authentication)
+     *
+     * @created March 17, 2001
+     */
+    public static class AuthMethodType extends EnumeratedAttribute {
+        /**
+         * Gets the possible values of authorisation supported
+         *
+         * @return The Values value
+         */
+        public String[] getValues() {
+            return new String[]{"none", "basic","digest"};
+        }
+
+        /**
+         * lookup from value to a numeric value. defaults to 0, basic-auth
+         * @param choice string selection
+         * @return selected value
+        */
+        public int  mapValueToNumber() {
+            String choice=getValue();
+            int value=0;
+            String[] values=getValues();
+            for(int i=0;i<values.length;i++) {
+                if(values[i].equalsIgnoreCase(choice))
+                    value=i;
+            }
+            return value;
+        }
+    }
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/NullOutputStream.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/NullOutputStream.java
new file mode 100644
index 0000000..57658ce
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/NullOutputStream.java
@@ -0,0 +1,105 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * simple output stream which discards all write requests this should
+ * really be part of java.io, as it is sporadically invaluable
+ *
+ * @created March 17, 2001
+ */
+public class NullOutputStream extends OutputStream {
+
+    /**
+     * discard all incoming bytes
+     *
+     * @param b byte to write
+     * @exception IOException never throwable in this subclass
+     */
+    public void write(int b)
+        throws IOException {
+    }
+
+
+    /**
+     * discard all incoming bytes
+     *
+     * @param b  byte array
+     * @exception IOException never throwable in this subclass
+     */
+    public void write(byte[] b)
+        throws IOException {
+    }
+
+
+    /**
+     * discard all incoming bytes
+     *
+     * @param b  byte array
+     * @param off starting offset
+     * @param len length to write
+     * @exception IOException never throwable in this subclass
+     */
+    public void write(byte[] b,
+            int off,
+            int len)
+        throws IOException {
+    }
+
+}
+
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/SetProxy.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/SetProxy.java
new file mode 100644
index 0000000..63b4a33
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/SetProxy.java
@@ -0,0 +1,239 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2001 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/>.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.lang.reflect.*;
+import org.apache.tools.ant.*;
+
+/**
+ * proxy definition task. This allows all web tasks in the build file
+ * executed after this task to access the web through a proxy server
+ *
+ * @created March 17, 2001
+ */
+
+public class SetProxy extends Task {
+
+    /**
+     * proxy details
+     */
+    protected String proxyHost = null;
+
+    /**
+     * name of proxy port
+     */
+    protected int proxyPort = 80;
+
+    /**
+     * socks host.
+     */
+    private String socksProxyHost = null;
+    /**
+     * socks proxy port. 1080 is the default
+     */
+    private int socksProxyPort = 1080;
+
+
+
+    /**
+     * set a proxy host. the port should be defined too
+     *
+     * @param hostname the new proxy hostname
+     */
+    public void setProxyHost(String hostname) {
+        proxyHost = hostname;
+    }
+
+
+    /**
+     * set the proxy port number.
+     *
+     * @param port port number of the proxy
+     */
+    public void setProxyPort(int port) {
+        proxyPort = port;
+    }
+
+
+    /**
+     * accessor to proxy hostname
+     *
+     * @return the hostname or null
+     */
+
+    public String getProxyHost() {
+        return proxyHost;
+    }
+
+
+    /**
+     * accessor to proxy hostname
+     *
+     * @return the port number
+     */
+
+    public int getProxyPort() {
+        return proxyPort;
+    }
+
+
+    /**
+     * Set the SocksProxyHost attribute
+     *
+     * @param host The new SocksProxyHost value
+     */
+    public void setSocksProxyHost(String host) {
+        this.socksProxyHost = host;
+    }
+
+
+    /**
+     * Set the SocksProxyPort attribute
+     *
+     * @param port The new SocksProxyPort value
+     */
+    public void setSocksProxyPort(int port) {
+        this.socksProxyPort = port;
+    }
+
+
+
+    /**
+     * if the proxy port and host settings are not null, then the settings
+     * get applied these settings last beyond the life of the object and
+     * apply to all network connections
+     *
+     * @return true if the settings were applied
+     */
+
+    public void applyWebProxySettings() {
+        boolean settingsChanged=false;
+        Properties prop = System.getProperties();
+        if (getProxyHost() != null) {
+            log("Setting proxy to " + getProxyHost() + ":" + getProxyPort(),
+                    Project.MSG_VERBOSE);
+            prop.put("http.proxyHost", getProxyHost());
+            prop.put("http.proxyPort", String.valueOf(getProxyPort()));
+            prop.put("https.proxyHost", getProxyHost());
+            prop.put("https.proxyPort", String.valueOf(getProxyPort()));
+            prop.put("ftp.proxyHost", getProxyHost());
+            prop.put("ftp.proxyPort", String.valueOf(getProxyPort()));
+            settingsChanged=true;
+        }
+
+        //socks
+        if (socksProxyHost != null) {
+            log("Setting proxy to " + getProxyHost() + ":" + getProxyPort(),
+                    Project.MSG_VERBOSE);
+            prop.put("socksProxyHost", socksProxyHost);
+            prop.put("socksProxyPort", Integer.toString(socksProxyPort));
+            settingsChanged=true;
+        }
+
+        //for Java1.1 we need to tell the system that the settings are new
+        if(settingsChanged && project.getJavaVersion() == Project.JAVA_1_1) {
+            prop.put("http.proxySet", "true");
+            sun.net.www.http.HttpClient.resetProperties();
+        }
+        legacyResetProxySettingsCall();
+    }
+
+
+    /**
+     * make a call to sun.net.www.http.HttpClient.resetProperties();
+     * this is only needed for java 1.1; reflection is used to stop the compiler
+     * whining, and in case cleanroom JVMs dont have the class.
+     * @return Description of the Returned Value
+     * @returns
+     */
+
+    protected boolean legacyResetProxySettingsCall() {
+        try {
+            Class c = Class.forName("sun.net.www.http.HttpClient");
+            Method reset = c.getMethod("resetProperties", null);
+            reset.invoke(null, null);
+            return true;
+        }
+        catch (ClassNotFoundException cnfe) {
+            return false;
+        }
+        catch (NoSuchMethodException e) {
+            return false;
+        }
+        catch (IllegalAccessException e) {
+            return false;
+        }
+        catch (InvocationTargetException e) {
+            return false;
+        }
+
+    }
+
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException Thrown in unrecoverable error.
+     */
+    public void execute()
+        throws BuildException {
+        applyWebProxySettings();
+    }
+
+}
+
diff --git a/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/hostname.java b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/hostname.java
new file mode 100644
index 0000000..c62e767
--- /dev/null
+++ b/trunk/proposal/sandbox/httptasks/src/main/org/apache/tools/ant/taskdefs/optional/http/hostname.java
@@ -0,0 +1,184 @@
+/*
+ *  The Apache Software License, Version 1.1
+ *
+ *  Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.http;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.net.InetAddress;
+
+import org.apache.tools.ant.*;
+
+/**
+ * trivial task to get the hostname of a box; as IPaddr, hostname, or
+ * fullname.
+ *
+ * @created 07 January 2002
+ */
+
+public class hostname extends Task {
+
+    /**
+     * Description of the Field
+     */
+    private String property;
+
+    /**
+     * Description of the Field
+     */
+    private boolean failonerror = true;
+
+    /**
+     * Description of the Field
+     */
+    private boolean address = false;
+
+
+    /**
+     * Sets the FailOnError attribute of the Hostname object
+     *
+     * @param failonerror The new FailOnError value
+     */
+    public void setFailOnError(boolean failonerror) {
+        this.failonerror = failonerror;
+    }
+
+
+    /**
+     * Sets the Address attribute of the Hostname object
+     *
+     * @param address The new Address value
+     */
+    public void setAddress(boolean address) {
+        this.address = address;
+    }
+
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException Thrown in unrecoverable error.
+     */
+    public void execute()
+        throws BuildException {
+        if(property==null) {
+           throw new BuildException("Property attribute must be defined"); 
+        }
+        String result;
+        String exception = null;
+        try {
+            if (address) {
+                result = getAddress();
+            }
+            else {
+                result = getHostname();
+            }
+            project.setNewProperty(property, result);
+        } catch (UnknownHostException e) {
+            exception = e;
+        } catch (SecurityException e) {
+            exception = e;
+        }
+        if (e != null) {
+            if (failonerror) {
+                throw new BuildException("resolving hostname", e);
+            }
+            else {
+                log("failed to resolve local hostname", Project.MSG_ERR);
+            }
+        }
+    }
+
+
+    /**
+     * Gets the Address attribute of the Hostname object
+     *
+     * @return The Address value
+     * @exception SecurityException Description of Exception
+     * @exception UnknownHostException Description of Exception
+     */
+    public String getAddress()
+        throws SecurityException, UnknownHostException {
+        return getLocalHostAddress().getHostAddress();
+    }
+
+
+    /**
+     * Gets the Hostname attribute of the Hostname object
+     *
+     * @return The Hostname value
+     * @exception SecurityException Description of Exception
+     * @exception UnknownHostException Description of Exception
+     */
+    public String getHostname()
+        throws SecurityException, UnknownHostException {
+        return getLocalHostAddress().getHostName();
+    }
+
+
+    /**
+     * Gets the LocalHostAddress attribute of the Hostname object
+     *
+     * @return The LocalHostAddress value
+     * @exception UnknownHostException Description of Exception
+     */
+    public InetAddress getLocalHostAddress()
+        throws UnknownHostException {
+        return InetAddress.getLocalHost();
+    }
+
+}
+
diff --git a/trunk/proposal/sandbox/input/README b/trunk/proposal/sandbox/input/README
new file mode 100644
index 0000000..6c45e20
--- /dev/null
+++ b/trunk/proposal/sandbox/input/README
@@ -0,0 +1,8 @@
+The input proposal has been accepted as part of main Ant and has been
+merged with the main code tree on 2002-04-22.
+
+The only part that didn't get moved over was SwingInputHandler that
+has never been more than a proof of concept - if you really want to
+see it, you can find it in CVS's Attic:
+
+<http://cvs.apache.org/viewcvs/jakarta-ant/proposal/sandbox/input/src/main/org/apache/tools/ant/input/Attic/SwingInputHandler.java>
diff --git a/trunk/proposal/sandbox/junit/build.bat b/trunk/proposal/sandbox/junit/build.bat
new file mode 100755
index 0000000..ae9ffc1
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/build.bat
@@ -0,0 +1,30 @@
+@echo off
+
+set OLDCLASSPATH=%CLASSPATH%
+set REAL_ANT_HOME=%ANT_HOME%
+set ANT_HOME=bootstrap
+if exist bootstrap\lib\ant.jar if exist bootstrap\bin\ant.bat if exist bootstrap\bin\lcp.bat if exist bootstrap\bin\antRun.bat goto runAnt
+call bootstrap.bat
+if exist bootstrap\lib\ant.jar if exist bootstrap\bin\ant.bat if exist bootstrap\bin\lcp.bat if exist bootstrap\bin\antRun.bat goto runAnt
+echo Bootstrap FAILED
+goto cleanup
+
+:runAnt
+set LOCALCLASSPATH=lib\crimson.jar;bootstrap\lib\ant.jar
+for %%i in (lib\optional\*.jar) do call bootstrap\bin\lcp.bat %%i
+set CLASSPATH=lib\optional\xalanj1compat.jar;%LOCALCLASSPATH%;%CLASSPATH%
+set LOCALCLASSPATH=
+
+if not "%REAL_ANT_HOME%" == "" goto install_ant
+call bootstrap\bin\ant.bat -emacs %1 %2 %3 %4 %5 %6 %7 %8 %9
+goto cleanup
+
+:install_ant
+call bootstrap\bin\ant.bat -emacs -Dant.install="%REAL_ANT_HOME%" %1 %2 %3 %4 %5 %6 %7 %8 %9
+
+rem clean up
+:cleanup
+set ANT_HOME=%REAL_ANT_HOME%
+set REAL_ANT_HOME=
+set CLASSPATH=%OLDCLASSPATH%
+set OLDCLASSPATH=
diff --git a/trunk/proposal/sandbox/junit/build.sh b/trunk/proposal/sandbox/junit/build.sh
new file mode 100644
index 0000000..f15a7e7
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/build.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+cygwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+esac
+
+PWD=`pwd`
+if $cygwin ; then
+    PWD=`cygpath --windows "$PWD"`
+fi
+
+cd ../../..
+/bin/sh ./build.sh -buildfile $PWD/build.xml $*
+cd $PWD
+
diff --git a/trunk/proposal/sandbox/junit/build.xml b/trunk/proposal/sandbox/junit/build.xml
new file mode 100644
index 0000000..746178b
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/build.xml
@@ -0,0 +1,79 @@
+<project name="junit-proposal" basedir="." default="compile">
+  <property file=".ant.properties"/>
+  <property file="${user.home}/.ant.properties"/>
+  
+  <!--property name="build.sysclasspath" value="ignore"/-->
+  <property name="build.compiler" value="jikes"/>
+  <!--property name="build.compiler.emacs" value="on"/-->
+  <property name="build.compiler.pedantic" value="true"/>
+  <property name="build.compiler.depend" value="true"/>
+  <property name="build.compiler.fulldepend" value="true"/>
+
+  <property name="debug" value="on"/>
+  <property name="optimize" value="off"/>
+  <property name="deprecation" value="on"/>
+
+  <property name="build.dir" value="build"/>
+  <property name="build.lib" value="${build.dir}/lib"/>
+  <property name="build.src" value="${build.dir}/src"/>
+  <property name="build.classes" value="${build.dir}/classes"/>
+  
+  <property name="testcases.classes" value="${build.dir}/testcases"/>
+
+  <property name="java.dir" value="src/java"/>
+  <property name="tests.dir" value="src/testcases"/>
+  <property name="ant.base.dir" location="../../.."/>
+  <property name="ant.lib.dir" location="${ant.base.dir}/lib"/>
+  <property name="lib.dir" location="lib"/>
+  <property name="bootstrap.dir" location="${ant.base.dir}/bootstrap"/>
+  
+  <path id="project.class.path">
+    <pathelement path="${build.classes}" />
+    <fileset dir="${ant.lib.dir}" includes="**/*.jar"/>
+    <fileset dir="${bootstrap.dir}/lib" includes="ant.jar"/>
+    <fileset dir="${lib.dir}" includes="**/*.jar"/>
+  </path>
+
+
+  <target name="compile"
+          description="--> compile the source code">
+    <mkdir dir="${build.classes}"/>
+    <javac srcdir="src/main"
+           destdir="${build.classes}"
+           debug="${debug}"
+           optimize="${optimize}"
+           deprecation="${deprecation}"
+           includeantruntime="no">
+      <classpath refid="project.class.path"/>
+    </javac>
+    <antcall target="compile-tests"/>
+  </target>
+  
+
+  <target name="clean"
+          description="--> cleans up build and dist directories">
+    <delete dir="${build.dir}" />
+    <delete>
+      <fileset dir="." includes="**/*.bak" defaultexcludes="no"/>
+    </delete>
+  </target>
+
+  <target name="compile-tests">
+    <mkdir dir="${testcases.classes}"/>
+    <javac srcdir="src/testcases"
+           destdir="${testcases.classes}"
+           debug="${debug}"
+           optimize="${optimize}"
+           deprecation="${deprecation}"
+           includeantruntime="no">
+      <classpath refid="project.class.path"/>
+    </javac>
+  </target>
+  
+  <target name="run-ant-tests" depends="compile">
+     <!--ant dir="${ant.base.dir}" target="build" inheritall="false"/>
+     <ant dir="${ant.base.dir}" target="compile-tests" inheritall="false"/-->
+     <ant antfile="rjunit-ant-tests.xml"/>
+  </target>
+  
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/junit/lib/excalibur-i18n-1.0.jar b/trunk/proposal/sandbox/junit/lib/excalibur-i18n-1.0.jar
new file mode 100644
index 0000000..5c533b5
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/lib/excalibur-i18n-1.0.jar
Binary files differ
diff --git a/trunk/proposal/sandbox/junit/rjunit-ant-tests.xml b/trunk/proposal/sandbox/junit/rjunit-ant-tests.xml
new file mode 100644
index 0000000..5d98526
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/rjunit-ant-tests.xml
@@ -0,0 +1,34 @@
+<project name="rjunit-ant-tests" basedir="." default="ant-tests">  
+  <!--
+    run ant tests. This is unusable if not running it
+    via build.xml as it should inherits properties
+    -->
+  <taskdef classname="org.apache.tools.ant.taskdefs.optional.rjunit.RJUnitTask"
+    name="rjunit">
+      <classpath>
+        <path location="${build.classes}"/>
+        <path location="${java.dir}"/>
+        <fileset dir="${lib.dir}" includes="**/*.jar"/>
+      </classpath>
+  </taskdef>
+  <target name="ant-tests">
+      <rjunit>
+          <server port="6666">
+              <formatter type="brief">
+                  <!--param name="file" location="junit-test-log.txt"/-->
+              </formatter>
+          </server>
+          <client host="127.0.0.1"  port="6666">
+              <classpath>
+                <fileset dir="${ant.lib.dir}" includes="**/*.jar"/>
+                <path location="${ant.base.dir}/build/classes"/>
+                <path location="${java.dir}"/>
+              </classpath>
+              <jvmarg value="-Xmx256MB"/>
+              <batchtest path="${ant.base.dir}/build/testcases">
+                  <include name="**/*Test.class"/>
+              </batchtest>
+          </client>
+      </rjunit>
+   </target>
+ </project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ArrayEnumeration.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ArrayEnumeration.java
new file mode 100644
index 0000000..525acb2
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ArrayEnumeration.java
@@ -0,0 +1,110 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * Convenient enumeration over an array of objects.
+ */
+class ArrayEnumeration implements Enumeration {
+
+    /** convenient null enumeration */
+    public final static Enumeration NULL_ENUMERATION =
+            new ArrayEnumeration(new Object[0]);
+
+    /** object array */
+    private Object[] array;
+
+    /** current index */
+    private int pos;
+
+    /**
+     * Initialize a new enumeration that wraps an array.
+     * @param       array   the array of object to enumerate.
+     */
+    public ArrayEnumeration(Object[] array) {
+        this.array = array;
+        this.pos = 0;
+    }
+
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return  <code>true</code> if and only if this enumeration object
+     *           contains at least one more element to provide;
+     *          <code>false</code> otherwise.
+     */
+    public boolean hasMoreElements() {
+        return (pos < array.length);
+    }
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * object has at least one more element to provide.
+     *
+     * @return     the next element of this enumeration.
+     * @throws  NoSuchElementException  if no more elements exist.
+     */
+    public Object nextElement() throws NoSuchElementException {
+        if (hasMoreElements()) {
+            Object o = array[pos];
+            pos++;
+            return o;
+        }
+        throw new NoSuchElementException();
+    }
+}
+
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BaseTestElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BaseTestElement.java
new file mode 100644
index 0000000..401f963
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BaseTestElement.java
@@ -0,0 +1,117 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Enumeration;
+
+import junit.runner.TestCollector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Base test implementation that implements the if/unless logic.
+ *
+ */
+public abstract class BaseTestElement
+        extends ProjectComponent implements TestCollector {
+
+    /** run the test only if this property is present */
+    private String ifProperty;
+
+    /** run the test unless this property is present */
+    private String unlessProperty;
+
+    public final Enumeration collectTests() {
+        if (shouldRun()) {
+            return getTests();
+        }
+        return ArrayEnumeration.NULL_ENUMERATION;
+    }
+
+    public final void setIf(final String value) {
+        ifProperty = value;
+    }
+
+    public final void setUnless(final String value) {
+        unlessProperty = value;
+    }
+
+    /**
+     * Implementation of the test collection process
+     * @return the enumeration of fully qualified classname representing
+     * a JUnit Test.
+     */
+    protected abstract Enumeration getTests();
+
+    /**
+     * check whether this test should be run or not.
+     * @return whether or not the test should run based on
+     * the presence of <tt>if</tt> and <tt>unless</tt> properties.
+     * @see #setIf(String)
+     * @see #setUnless(String)
+     */
+    protected boolean shouldRun() {
+        final Project project = getProject();
+        if ( ifProperty != null &&
+                project.getProperty(ifProperty) == null ){
+            return false;
+        }
+        if (unlessProperty != null &&
+                project.getProperty(unlessProperty) != null) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BatchTestElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BatchTestElement.java
new file mode 100644
index 0000000..26c57d0
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/BatchTestElement.java
@@ -0,0 +1,103 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Enumeration;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+
+/**
+ * A test element where tests files are specified by include/exclude
+ * patterns. tests files location are specified by one ore multiple
+ * path elements. (directory or archive).
+ *
+ * <pre>
+ * <!ELEMENT batchtest>
+ * <!ATTLIST batchtest path CDATA required>
+ * </pre>
+ *
+ */
+public class BatchTestElement extends BaseTestElement {
+
+    private ClasspathTestCollector collector = new ClasspathTestCollector();
+
+// Test collector implementation
+
+    public Enumeration getTests() {
+        final Project project = getProject();
+        collector.setProject(project);
+        return collector.collectTests();
+    }
+
+// Ant bean accessors
+
+    public void setPath(Path path) {
+        collector.setPath(path);
+    }
+
+    public Path getPath() {
+        return collector.getPath();
+    }
+
+    public PatternSet.NameEntry createInclude() {
+        return collector.createInclude();
+    }
+
+    public PatternSet.NameEntry createExclude() {
+        return collector.createExclude();
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClasspathTestCollector.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClasspathTestCollector.java
new file mode 100644
index 0000000..e1f164c
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClasspathTestCollector.java
@@ -0,0 +1,195 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import junit.runner.TestCollector;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+
+/**
+ * A rough implementation of a test collector that will collect tests
+ * using include/exclude patterns in a set of paths. A path can either
+ * be a directory or an archive. (zip or jar file)
+ *
+ */
+public final class ClasspathTestCollector extends ProjectComponent
+        implements TestCollector {
+
+    private final static int SUFFIX_LENGTH = ".class".length();
+
+    private final PatternSet patterns = new PatternSet();
+
+    private Path path = null;
+
+    public Enumeration collectTests() {
+        Hashtable collected = new Hashtable();
+        // start from last, so that first elements
+        // override last one in case there are duplicates.
+        // ie mimic classpath behavior.
+        String[] paths = path.list();
+        for (int i = paths.length - 1; i >= 0; i--) {
+            File f = new File(paths[i]);
+            ArrayList included = null;
+            if (f.isDirectory()) {
+                included = gatherFromDirectory(f);
+            } else if (f.getName().endsWith(".zip")
+                    || f.getName().endsWith(".jar")) {
+                included = gatherFromArchive(f);
+            } else {
+                continue;
+            }
+            // add tests to the already collected one
+            final int includedCount = included.size();
+            log("Adding " + includedCount + " testcases from " + f, Project.MSG_VERBOSE);
+            for (int j = 0; j < includedCount; j++) {
+                String testname = (String) included.get(j);
+                collected.put(testname, "");
+            }
+        }
+        log("Collected " + collected.size() + " testcases from " + paths.length + " path(s).", Project.MSG_VERBOSE);
+        return collected.keys();
+    }
+
+
+    /**
+     * Return the list of classnames from a directory that match
+     * the specified patterns.
+     * @param dir the base directory (must also be the base package)
+     * @return the list of classnames matching the pattern.
+     */
+    protected ArrayList gatherFromDirectory(File dir) {
+        Project project = getProject();
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(dir);
+        ds.setIncludes(patterns.getIncludePatterns(project));
+        ds.setExcludes(patterns.getExcludePatterns(project));
+        ds.scan();
+        String[] included = ds.getIncludedFiles();
+        return testClassNameFromFile(included);
+    }
+
+    /**
+     * Return the list of classnames from a zipfile that match
+     * the specified patterns.
+     * @param zip the zipfile (must also be the base package)
+     * @return the list of classnames matching the pattern.
+     */
+    protected ArrayList gatherFromArchive(File zip) {
+        ZipScanner zs = new ZipScanner();
+        zs.setBasedir(zip);
+        zs.setIncludes(patterns.getIncludePatterns(getProject()));
+        zs.setExcludes(patterns.getExcludePatterns(getProject()));
+        zs.scan();
+        String[] included = zs.getIncludedFiles();
+        return testClassNameFromFile(included);
+    }
+
+    /**
+     * transform a set of file into their matching classname
+     * @todo what about using a mapper for this ?
+     */
+    protected ArrayList testClassNameFromFile(String[] classFileNames) {
+        ArrayList tests = new ArrayList(classFileNames.length);
+        for (int i = 0; i < classFileNames.length; i++) {
+            String file = classFileNames[i];
+            if (isTestClass(file)) {
+                String classname = classNameFromFile(file);
+                tests.add(classname);
+            }
+        }
+        return tests;
+    }
+
+    protected boolean isTestClass(String classFileName) {
+        return classFileName.endsWith(".class");
+    }
+
+    protected String classNameFromFile(String classFileName) {
+        // convert /a/b.class to a.b
+        String s = classFileName.substring(0, classFileName.length() - SUFFIX_LENGTH);
+        String s2 = s.replace(File.separatorChar, '.');
+        if (s2.startsWith(".")) {
+            s2 = s2.substring(1);
+        }
+        return s2;
+    }
+
+// Ant bean accessors
+
+    public void setPath(Path path) {
+        this.path = path;
+    }
+
+    public Path getPath() {
+        return this.path;
+    }
+
+    public PatternSet.NameEntry createInclude() {
+        return patterns.createInclude();
+    }
+
+    public PatternSet.NameEntry createExclude() {
+        return patterns.createExclude();
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClientElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClientElement.java
new file mode 100644
index 0000000..d9f0995
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ClientElement.java
@@ -0,0 +1,260 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import junit.runner.TestCollector;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * An element representing the client configuration.
+ *
+ * <pre>
+ * <!ELEMENT server (jvmarg)* (classpath)* (test)* (batchtest)*>
+ * <!ATTLIST server port numeric 6666>
+ * <!ATTLIST server host CDATA 127.0.0.1>
+ * </pre>
+
+ */
+public final class ClientElement extends ProjectComponent {
+    /** resources */
+    private final static Resources RES =
+            ResourceManager.getPackageResources(ClientElement.class);
+
+    /** port to contact the server. Default to 6666 */
+    private int port = 6666;
+
+    /** server hostname to connect to. Default to 127.0.0.1 */
+    private String host = "127.0.0.1";
+
+    /** test collector elements */
+    private ArrayList testCollectors = new ArrayList();
+
+    /** the command line to launch the TestRunner */
+    private CommandlineJava cmd = new CommandlineJava();
+
+    /** the parent task */
+    private RJUnitTask parent;
+
+    /** help debug the TestRunner */
+    private boolean debug = false;
+
+    /** create a new client */
+    public ClientElement(RJUnitTask value) {
+        parent = value;
+        cmd.setClassname("org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunner");
+    }
+
+    /** core entry point */
+    public final void execute() throws BuildException {
+        try {
+            preExecute();
+            doExecute();
+        } finally {
+            postExecute();
+        }
+    }
+
+    protected void preExecute() throws BuildException {
+        // must appended to classpath to avoid conflicts.
+        JUnitHelper.addClasspathEntry(createClasspath(), "/junit/framework/TestCase.class");
+        JUnitHelper.addClasspathEntry(createClasspath(), "/org/apache/tools/ant/Task.class");
+        JUnitHelper.addClasspathEntry(createClasspath(), "/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunner.class");
+    }
+
+    protected void doExecute() throws BuildException {
+        File tmp = configureTestRunner();
+        Execute execute = new Execute(new LogStreamHandler(parent, Project.MSG_VERBOSE, Project.MSG_VERBOSE));
+        execute.setCommandline(cmd.getCommandline());
+        execute.setAntRun(project);
+
+        log(RES.getString("task.process-cmdline.log", cmd.toString()), Project.MSG_VERBOSE);
+        int retVal = 0;
+        try {
+            retVal = execute.execute();
+            if (retVal != 0) {
+                throw new BuildException("task.process-failed.error");
+            }
+        } catch (IOException e) {
+            String msg = RES.getString("task.process-failed.error");
+            throw new BuildException(msg, e);
+        } finally {
+            tmp.delete();
+        }
+    }
+
+    protected void postExecute() {
+        // nothing
+    }
+
+    /**
+     * @return all collected tests specified with test elements.
+     */
+    protected Enumeration collectTests() {
+        final int count = testCollectors.size();
+        final Enumeration[] tests = new Enumeration[count];
+        for (int i = 0; i < count; i++) {
+            TestCollector te = (TestCollector) testCollectors.get(i);
+            tests[i] = te.collectTests();
+        }
+        return new CompoundEnumeration(tests);
+    }
+
+    /**
+     * Configure the runner with the appropriate configuration file.
+     * @return the reference to the temporary configuration file
+     * to be deleted once the TestRunner has ended.
+     */
+    protected File configureTestRunner() throws BuildException {
+        Properties props = new Properties();
+        props.setProperty("debug", String.valueOf(debug));
+        props.setProperty("host", host);
+        props.setProperty("port", String.valueOf(port));
+        // get all test classes to run...
+        StringBuffer buf = new StringBuffer(10240);
+        Enumeration classnames = collectTests();
+        while (classnames.hasMoreElements()) {
+            String classname = (String) classnames.nextElement();
+            buf.append(classname).append(" ");
+        }
+        props.setProperty("classnames", buf.toString());
+
+        // dump the properties to a temporary file.
+        FileUtils futils = FileUtils.newFileUtils();
+        File f = futils.createTempFile("junit-antrunner", "tmp", new File("."));
+        OutputStream os = null;
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            os = new BufferedOutputStream(new FileOutputStream(f));
+            props.store(baos, "JUnit Ant Runner configuration file");
+            log(baos.toString(), Project.MSG_VERBOSE);
+            os.write(baos.toByteArray());
+        } catch (IOException e) {
+            throw new BuildException(e);
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                }
+            }
+        }
+
+        // configure the runner
+        cmd.createArgument().setValue("-file");
+        cmd.createArgument().setValue(f.getAbsolutePath());
+        return f;
+    }
+
+// --- Ant bean setters
+
+    /** set the port to connect to */
+    public void setPort(int value) {
+        port = value;
+    }
+
+    /** set the host to contact */
+    public void setHost(String value) {
+        host = value;
+    }
+
+    /** set debug mode for the runner. it will log a file to working dir */
+    public void setDebug(boolean flag) {
+        debug = flag;
+    }
+
+    /** Create a new JVM argument. */
+    public Commandline.Argument createJvmarg() {
+        return cmd.createVmArgument();
+    }
+
+    /** classpath to be set for running tests */
+    public Path createClasspath() {
+        return cmd.createClasspath(getProject());
+    }
+
+    /** add a single test element */
+    public void addConfiguredTest(TestElement value) {
+        testCollectors.add(value);
+    }
+
+    /** add a batch test element */
+    public void addConfiguredBatchTest(BatchTestElement value) {
+        // add the classpath of batchtest to cmd classpath
+        Path path = value.getPath();
+        cmd.getClasspath().append(path);
+        testCollectors.add(value);
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/CompoundEnumeration.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/CompoundEnumeration.java
new file mode 100644
index 0000000..1f84891
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/CompoundEnumeration.java
@@ -0,0 +1,131 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * Convenient enumeration over an array of enumeration. For example:
+ * <pre>
+ * Enumeration e1 = v1.elements();
+ * while (e1.hasMoreElements()){
+ *    // do something
+ * }
+ * Enumeration e2 = v2.elements();
+ * while (e2.hasMoreElements()){
+ *    // do the same thing
+ * }
+ * </pre>
+ * can be written as:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), v2.elements() };
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()){
+ *    // do something
+ * }
+ * </pre>
+ * Note that the enumeration will skip null elements in the array. The following is
+ * thus possible:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), null, v2.elements() }; // a null enumeration in the array
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()){
+ *    // do something
+ * }
+ * </pre>
+ */
+public class CompoundEnumeration implements Enumeration {
+
+    /** enumeration array */
+    private Enumeration[] enumArray;
+
+    /** index in the enums array */
+    private int index = 0;
+
+    public CompoundEnumeration(Enumeration[] enumarray) {
+        this.enumArray = enumarray;
+    }
+
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return  <code>true</code> if and only if this enumeration object
+     *           contains at least one more element to provide;
+     *          <code>false</code> otherwise.
+     */
+    public boolean hasMoreElements() {
+        while (index < enumArray.length) {
+            if (enumArray[index] != null && enumArray[index].hasMoreElements()) {
+                return true;
+            }
+            index++;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * object has at least one more element to provide.
+     *
+     * @return     the next element of this enumeration.
+     * @throws  NoSuchElementException  if no more elements exist.
+     */
+    public Object nextElement() throws NoSuchElementException {
+        if (hasMoreElements()) {
+            return enumArray[index].nextElement();
+        }
+        throw new NoSuchElementException();
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/FilterElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/FilterElement.java
new file mode 100644
index 0000000..632ce42
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/FilterElement.java
@@ -0,0 +1,136 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.lang.reflect.Constructor;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.FilterFormatter;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.FilterStackFormatter;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * A filter element that can be used inside a ResultFormatterElement to denote
+ * a filtering. Note that the filtering order correspond to the element
+ * order. The first element being the top filter, the last element
+ * being the bottom filter.
+ *
+ * <pre>
+ * <!ELEMENT filter>
+ * <!ATTLIST filter type (stack) required>
+ * <!ATTLIST filter classname CDATA required>
+ * </pre>
+ *
+ */
+public class FilterElement {
+
+    /** filter classname, is should inherit from FilterFormatter */
+    private String classname;
+
+    /**
+     * Called by introspection on <tt>type</tt> attribute.
+     * @see FilterAttribute
+     */
+    public void setType(FilterAttribute fa) {
+        setClassName(fa.getClassName());
+    }
+
+    /**
+     * Called by introspection on <tt>classname</tt> attribute.
+     * It must inherit from <tt>FilterFormatter</tt>
+     * @see FilterFormatter
+     */
+    public void setClassName(String name) {
+        classname = name;
+    }
+
+    /**
+     * Wrap this filter around a given formatter.
+     * @throws BuildException if any error happens when creating this filter.
+     */
+    public Formatter createFilterFormatter(Formatter f) throws BuildException {
+        try {
+            Class clazz = Class.forName(classname);
+            if (!FilterFormatter.class.isAssignableFrom(clazz)) {
+                throw new BuildException(clazz + " must be a FilterFormatter.");
+            }
+            Constructor ctor = clazz.getConstructor(new Class[]{Formatter.class});
+            return (Formatter) ctor.newInstance(new Object[]{f});
+        } catch (BuildException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /** a predefined set of filters w/ their class mapping */
+    public static class FilterAttribute extends EnumeratedAttribute {
+        /** the predefined alias for filters */
+        private final static String[] VALUES = {"stack"};
+
+        /** the class corresponding to the alias (in the same order) */
+        private final static String[] CLASSNAMES = {FilterStackFormatter.class.getName()};
+
+        public String[] getValues() {
+            return VALUES;
+        }
+
+        /** get the classname matching the alias */
+        public String getClassName() {
+            return CLASSNAMES[getIndex()];
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/JUnitHelper.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/JUnitHelper.java
new file mode 100644
index 0000000..ff12b5c
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/JUnitHelper.java
@@ -0,0 +1,197 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.types.Path;
+
+/**
+ * A set of helpers functions to deal with JUnit.
+ *
+ */
+public final class JUnitHelper {
+
+    private final static String SUITE_METHODNAME = "suite";
+
+    /**
+     * This method parse the output of the method <tt>toString()</tt>
+     * from the <tt>TestCase</tt> class. The format returned is:
+     * <tt>name(classname)</tt>
+     * @return the string corresponding to name.
+     */
+    public static String getTestName(String text){
+        int p1 = text.indexOf('(');
+        return text.substring(0, p1);
+    }
+
+    /**
+     * This method parse the output of the method <tt>toString()</tt>
+     * from the <tt>TestCase</tt> class. The format returned is:
+     * <tt>name(classname)</tt>
+     * @return the string corresponding to classname.
+     */
+    public static String getSuiteName(String text){
+        int p1 = text.indexOf('(');
+        int p2 = text.indexOf(')', p1);
+        return text.substring(p1 + 1, p2);
+    }
+
+    /**
+     * Returns the Test corresponding to to the given class name
+     * @param loader classloader to use when loading the class or
+     * <tt>null</tt> for system classloader.
+     * @param classname the classname of the test we want to extract.
+     * @throws Exception a generic exception
+     */
+    public static Test getTest(ClassLoader loader, String classname) throws Exception {
+        Class clazz = null;
+        if (loader == null) {
+            clazz = Class.forName(classname);
+        } else {
+            loader.loadClass(classname);
+        }
+        return getTest(clazz);
+    }
+
+
+    /**
+     * Extract a test from a given class
+     * @param clazz the class to extract a test from.
+     */
+    public static Test getTest(Class clazz) {
+        try {
+            Object obj = clazz.newInstance();
+            if (obj instanceof TestSuite) {
+                return (TestSuite) obj;
+            }
+        } catch (Exception e) {
+        }
+        try {
+            // check if there is a suite method
+            Method suiteMethod = clazz.getMethod(SUITE_METHODNAME, new Class[0]);
+            return (Test) suiteMethod.invoke(null, new Class[0]);
+        } catch (Exception e) {
+        }
+
+        // check if it is really a valid testcase
+        int modifiers = clazz.getModifiers();
+        if ( !Modifier.isPublic(modifiers) ||
+                Modifier.isAbstract(modifiers) ||
+                !TestCase.class.isAssignableFrom(clazz)) {
+            return null;
+        }
+        // try to extract a test suite automatically
+        // this will generate warnings if the class is no suitable Test
+        try {
+            return new TestSuite(clazz);
+        } catch (Exception e) {
+        }
+        return null;
+    }
+
+    /**
+     * Search for the given resource and return the directory or archive
+     * that contains it.
+     *
+     * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+     * getResource doesn't contain the name of the archive.</p>
+     *
+     * @param resource the resource to look for in the JVM classpath.
+     * @return the file or directory containing the resource or
+     * <tt>null</tt> if it does not know how to handle it.
+     */
+    public static File getResourceEntry(String resource) {
+        URL url = JUnitHelper.class.getResource(resource);
+        if (url == null) {
+            // can't find the resource...
+            return null;
+        }
+        String u = url.toString();
+        if (u.startsWith("jar:file:")) {
+            int pling = u.indexOf("!");
+            String jarName = u.substring(9, pling);
+            return new File((new File(jarName)).getAbsolutePath());
+        } else if (u.startsWith("file:")) {
+            int tail = u.indexOf(resource);
+            String dirName = u.substring(5, tail);
+            return new File((new File(dirName)).getAbsolutePath());
+        }
+        // don't know how to handle it...
+        return null;
+    }
+
+    /**
+     * Add the entry corresponding to a specific resource to the
+     * specified path instance. The entry can either be a directory
+     * or an archive.
+     * @param path the path to add the resource entry to.
+     * @param resource the resource to look for.
+     * @see #getResourceEntry(String)
+     */
+    public static void addClasspathEntry(Path path, String resource) {
+        File f = getResourceEntry(resource);
+        if (f != null) {
+            path.createPathElement().setLocation(f);
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/KeepAliveOutputStream.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/KeepAliveOutputStream.java
new file mode 100644
index 0000000..d3ce706
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/KeepAliveOutputStream.java
@@ -0,0 +1,84 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Class that can be used to wrap <tt>System.out</tt> and <tt>System.err</tt>
+ * without getting anxious about the client closing the stream.
+ *
+ * <p>
+ * In code-language it means that it is not necessary to do:
+ * <pre>
+ * if (out != System.out && out!= System.err){
+ *   out.close();
+ * }
+ * </pre>
+ * </p>
+ *
+ */
+public class KeepAliveOutputStream extends FilterOutputStream {
+
+    public KeepAliveOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    /** this method does nothing */
+    public void close() throws IOException {
+        //
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/OutputAttribute.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/OutputAttribute.java
new file mode 100644
index 0000000..f7f8bb8
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/OutputAttribute.java
@@ -0,0 +1,110 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Attempt to create an output specific attribute.
+ * <p>
+ * The possible output values are 'stdout' and 'stderr', otherwise
+ * it is assumed that the value represent a file.
+ * </p>
+ * Note that stdout and stderr are wrapped by a <tt>KeepAliveOutputStream</tt>
+ * so that the stream cannot be closed.
+ *
+ * @see KeepAliveOutputStream
+ */
+public class OutputAttribute extends ProjectComponent {
+
+    /** keyword to represent stdout output */
+    public final static String STDOUT = "stdout";
+
+    /** keyword to represent stderr output */
+    public final static String STDERR = "stderr";
+
+    /** the selected value for output, either stdout,stderr or filepath */
+    private String value;
+
+    /**
+     * Create a new output attribute from a value.
+     */
+    public OutputAttribute(String value) {
+        this.value = value;
+    }
+
+    /**
+     * @return the outputstream corresponding to the selected attribute.
+     */
+    public OutputStream getOutputStream() {
+        if (STDOUT.equals(value)) {
+            return new KeepAliveOutputStream(System.out);
+        } else if (STDERR.equals(value)) {
+            return new KeepAliveOutputStream(System.err);
+        }
+        File f = getProject().resolveFile(value);
+        try {
+            return new FileOutputStream(f);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTask.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTask.java
new file mode 100644
index 0000000..955d5e1
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTask.java
@@ -0,0 +1,170 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * The core JUnit task.
+ *
+ */
+public class RJUnitTask extends Task {
+
+    private final static Resources RES =
+            ResourceManager.getPackageResources(RJUnitTask.class);
+
+    /** port to run the server on */
+    private int port = -1;
+
+    /** timeout period in ms */
+    private long timeout = -1;
+
+    /** client configuraiton element */
+    private ClientElement client = null;
+
+    /** server configuration element */
+    private ServerElement server = null;
+
+// task implementation
+
+    public void execute() throws BuildException {
+        if (client == null && server == null) {
+            throw new BuildException("Invalid state: need to be server, client or both");
+        }
+
+        // 1) server and client
+        if (server != null && client != null) {
+            ServerWorker worker = new ServerWorker();
+            worker.start();
+            client.execute();
+            Exception caught = null;
+            try {
+                worker.join();
+                caught = worker.getException();
+            } catch (InterruptedException e){
+                caught = e;
+            }
+            if (caught != null){
+                throw new BuildException(caught);
+            }
+            return;
+        }
+
+        // 2) server only (waiting for client)
+        if (server != null && client == null) {
+            server.execute();
+            return;
+        }
+
+        // 3) client only (connecting to server)
+        if (server == null && client != null) {
+            client.execute();
+            return;
+        }
+    }
+
+// Ant bean accessors
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * create a new client in charge of running tests and sending
+     * the results to the server that collect them.
+     */
+    public ClientElement createClient() {
+        if (client == null) {
+            client = new ClientElement(this);
+        }
+        return client;
+    }
+
+    /**
+     * create a new client in charge of running tests and sending
+     * the results to the server that collect them.
+     */
+    public ServerElement createServer() {
+        if (server == null) {
+            server = new ServerElement(this);
+        }
+        return server;
+    }
+
+
+    /** the worker to run the server on */
+    class ServerWorker extends Thread {
+        private Exception caught = null;
+
+        public void run() {
+            try {
+                server.execute();
+            } catch (Exception e) {
+                caught = e;
+                e.printStackTrace();
+            }
+        }
+
+        public Exception getException() {
+            return caught;
+        }
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/Resources.properties b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/Resources.properties
new file mode 100644
index 0000000..74a470f
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/Resources.properties
@@ -0,0 +1,3 @@
+# task
+task.process-cmdline.log = Executing {0}
+task.process-failed.error = Process failed.
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ResultFormatterElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ResultFormatterElement.java
new file mode 100644
index 0000000..a81634d
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ResultFormatterElement.java
@@ -0,0 +1,234 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * An element representing a <tt>Formatter</tt>
+ *
+ * <pre>
+ * <!ELEMENT formatter (filter)*>
+ * <!ATTLIST formatter type (plain|xml|brief) #REQUIRED>
+ * <!ATTLIST formatter classname CDATA #REQUIRED>
+ * <!ATTLIST formatter extension CDATA #IMPLIED>
+ * <!ATTLIST formatter usefile (yes|no) no>
+ * </pre>
+ *
+ *
+ * @see RJUnitTask
+ * @see Formatter
+ */
+public class ResultFormatterElement {
+
+    /** output stream for the formatter */
+    private OutputStream out = new KeepAliveOutputStream(System.out);
+
+    /** formatter classname */
+    private String classname;
+
+    /** the filters to apply to this formatter */
+    private Vector filters = new Vector();
+
+    /** the parameters set for configuration purposes */
+    private Vector params = new Vector();
+
+    /**
+     * set an existing type of formatter.
+     * @see TypeAttribute
+     * @see #setClassname(String)
+     */
+    public void setType(TypeAttribute type) {
+        setClassname(type.getClassName());
+    }
+
+    /**
+     * <p> Set name of class to be used as the formatter.
+     *
+     * <p> This class must implement <code>Formatter</code>
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * Setting a comma separated list of filters in the specified order.
+     * @see #addFilter(FilterElement)
+     */
+    public void setFilters(String filters) {
+        StringTokenizer st = new StringTokenizer(filters, ",");
+        while (st.hasMoreTokens()) {
+            FilterElement fe = new FilterElement();
+            FilterElement.FilterAttribute fa = new FilterElement.FilterAttribute();
+            fa.setValue(st.nextToken());
+            fe.setType(fa);
+            addFilter(fe);
+        }
+    }
+
+    /**
+     * Add a filter to this formatter.
+     */
+    public void addFilter(FilterElement fe) {
+        filters.addElement(fe);
+    }
+
+    /**
+     * Add a parameter that can be used for configuration.
+     */
+    public void addParam(Parameter param) {
+        params.addElement(param);
+    }
+
+    /**
+     * Set whether the formatter should log to file.
+     */
+    public void setOutput(OutputAttribute output) {
+        this.out = output.getOutputStream();
+    }
+
+    /**
+     * create the Formatter corresponding to this element.
+     */
+    protected Formatter createFormatter() throws BuildException {
+        if (classname == null) {
+            throw new BuildException("you must specify type or classname");
+        }
+        Formatter f = null;
+        try {
+            Class clazz = Class.forName(classname);
+            if (!Formatter.class.isAssignableFrom(clazz)) {
+                throw new BuildException(clazz + " is not a Formatter");
+            }
+            f = (Formatter) clazz.newInstance();
+        } catch (BuildException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+
+        // wrap filters in the reverse order: first = top, last = bottom.
+        for (int i = filters.size() - 1; i >= 0; i--) {
+            FilterElement fe = (FilterElement) filters.elementAt(i);
+            f = fe.createFilterFormatter(f);
+        }
+
+        // create properties from parameters
+        Properties props = new Properties();
+        for (int i = 0; i < params.size(); i++) {
+            Parameter param = (Parameter) params.elementAt(i);
+            props.put(param.getName(), param.getValue());
+        }
+        // it is assumed here that the filters are chaining til the
+        // wrapped formatter.
+        f.init(props);
+        return f;
+    }
+
+    /**
+     * <p> Enumerated attribute with the values "plain", "xml" and "brief".
+     * <p> Use to enumerate options for <tt>type</tt> attribute.
+     */
+    public final static class TypeAttribute extends EnumeratedAttribute {
+        private final static String[] VALUES = {"plain", "xml", "brief"};
+        private final static String[] CLASSNAMES = {
+            "org.apache.tools.ant.taskdefs.optional.rjunit.formatter.PlainFormatter",
+            "org.apache.tools.ant.taskdefs.optional.rjunit.formatter.XMLFormatter",
+            "org.apache.tools.ant.taskdefs.optional.rjunit.formatter.BriefFormatter"
+        };
+
+        public String[] getValues() {
+            return VALUES;
+        }
+
+        public String getClassName() {
+            return CLASSNAMES[getIndex()];
+        }
+    }
+
+    /** a parameter that be used to configure a formatter */
+    public final static class Parameter {
+        private String name;
+        private String value;
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public void setLocation(File file) {
+            setValue(file.getAbsolutePath());
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public String getValue() {
+            return this.value;
+        }
+    }
+}
+
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ServerElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ServerElement.java
new file mode 100644
index 0000000..ec45530
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ServerElement.java
@@ -0,0 +1,140 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.Server;
+
+/**
+ * An element representing the server configuration.
+ *
+ * <pre>
+ * <!ELEMENT server (formatter)*>
+ * <!ATTLIST server port numeric 6666>
+ * <!ATTLIST server haltonfailure (yes|no) no>
+ * <!ATTLIST server haltonerror (yes|no) no>
+ * </pre>
+ *
+ */
+public final class ServerElement extends ProjectComponent {
+
+    /** formatters that write the tests results */
+    private ArrayList formatters = new ArrayList();
+
+    /** port to run the server on. Default to 6666 */
+    private int port = 6666;
+
+    /** stop the client run if a failure occurs */
+    private boolean haltOnFailure = false;
+
+    /** stop the client run if an error occurs */
+    private boolean haltOnError = false;
+
+    /** the parent task */
+    private RJUnitTask parent;
+
+    private Server server;
+
+    /** create a new server */
+    public ServerElement(RJUnitTask value) {
+        parent = value;
+    }
+
+    /** start the server and block until client has finished */
+    public void execute() throws BuildException {
+        // configure the server...
+        server = new Server(port);
+        final int formatterCount = formatters.size();
+        for (int i = 0; i < formatterCount; i++) {
+            final Formatter f = (Formatter) formatters.get(i);
+            server.addListener(f);
+        }
+
+        // and run it. It will stop once a client has finished.
+        try {
+            server.start(false); // do not loop
+        } catch (IOException e) {
+            throw new BuildException(e);
+        } finally {
+            server.shutdown();
+        }
+    }
+
+    /** set the port to listen to */
+    public void setPort(int value) {
+        port = value;
+    }
+
+//@fixme  logic problem here, should the server say to the client
+// that there it should stop or should the client do it itself ?
+
+    public void setHaltOnFailure(boolean value) {
+        haltOnFailure = value;
+    }
+
+    public void setHaltOnError(boolean value) {
+        haltOnError = value;
+    }
+
+    /** add a new formatter element */
+    public void addConfiguredFormatter(ResultFormatterElement fe) {
+        Formatter formatter = fe.createFormatter();
+        formatters.add(formatter);
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/TestElement.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/TestElement.java
new file mode 100644
index 0000000..594ed39
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/TestElement.java
@@ -0,0 +1,78 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Enumeration;
+
+/**
+ * A simple test element.
+ *
+ */
+public class TestElement extends BaseTestElement {
+
+    /** classname of JUnit test */
+    private String name;
+
+//@fixme, a path is needed for a test.
+
+    public Enumeration getTests() {
+        return new ArrayEnumeration(new String[]{name});
+    }
+
+// Ant bean setters
+
+    public void setName(String value) {
+        this.name = value;
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/WatchdogTest.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/WatchdogTest.java
new file mode 100644
index 0000000..18ab9c4
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/WatchdogTest.java
@@ -0,0 +1,114 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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", "Jakarta-Regexp", 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/>.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import junit.extensions.TestDecorator;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+/**
+ * A Test decorator that allows to cancel a test if it exceeds
+ * a certain time. It can be used globally or individually over
+ * each testcase.
+ *
+ */
+public class WatchdogTest extends TestDecorator {
+
+    /** the time out delay in msecs */
+    private long timeOut;
+
+    /**
+     * Create a new watchdog.
+     * @param test the test to watch for
+     * @param msecs the time out delay in msecs.
+     */
+    public WatchdogTest(Test test, long msecs) {
+        super(test);
+        timeOut = msecs;
+    }
+
+    public void run(TestResult result) {
+        Thread worker = createWorker(result);
+        worker.start();
+
+        try {
+            // wait at most the timeOut time.
+            worker.join(timeOut);
+
+            // if the thread is still alive, it must be killed.
+            if (worker.isAlive()) {
+                worker.interrupt();
+                result.addFailure(getTest(),
+                        new AssertionFailedError("Timed out after " + timeOut + "ms"));
+            }
+        } catch (InterruptedException e) {
+            worker.interrupt();
+            result.addError(getTest(), e);
+            result.stop();
+        }
+    }
+
+    /** create a new worker thread */
+    protected Thread createWorker(final TestResult result) {
+        Thread worker = new Thread("JUnit Test Worker") {
+            public void run() {
+                getTest().run(result);
+            }
+        };
+        return worker;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScanner.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScanner.java
new file mode 100644
index 0000000..4fb4836
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScanner.java
@@ -0,0 +1,190 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.tools.ant.DirectoryScanner;
+
+/**
+ * Provide a way to scan entries in a zip file. Note that it extends
+ * DirectoryScanner to make use of protected methods but implementation
+ * may not be valid for some methods.
+ * <p>
+ * the setBaseDir() must be called to set the reference to the archive
+ * file (.jar or .zip).
+ * </p>
+ *
+ */
+public class ZipScanner extends DirectoryScanner {
+    public ZipScanner() {
+    }
+
+    public void setExcludes(String[] excludes) {
+        super.setExcludes(excludes);
+        normalize(this.excludes);
+    }
+
+    public void setIncludes(String[] includes) {
+        super.setIncludes(includes);
+        normalize(this.includes);
+    }
+
+    /**
+     * normalize a set of paths so that it uses / otherwise matching will
+     * fail beautifully since archives use / to denote a path.
+     */
+    protected void normalize(String[] files) {
+        if (files != null) {
+            for (int i = 0; i < files.length; i++) {
+                files[i] = files[i].replace('\\', '/');
+            }
+        }
+    }
+
+    /**
+     * Scans the archive for files that match at least one include
+     * pattern, and don't match any exclude patterns.
+     *
+     * @exception IllegalStateException when the zip file was set incorrecly
+     */
+    public void scan() {
+        if (basedir == null) {
+            throw new IllegalStateException("No zipfile set");
+        }
+        if (!basedir.exists()) {
+            throw new IllegalStateException("zipfile " + basedir
+                    + " does not exist");
+        }
+        if (basedir.isDirectory()) {
+            throw new IllegalStateException("zipfile " + basedir
+                    + " is not a file");
+        }
+
+        if (includes == null) {
+            // No includes supplied, so set it to 'matches all'
+            includes = new String[1];
+            includes[0] = "**";
+        }
+        if (excludes == null) {
+            excludes = new String[0];
+        }
+
+        filesIncluded = new Vector();
+        filesNotIncluded = new Vector();
+        filesExcluded = new Vector();
+        dirsIncluded = new Vector();
+        dirsNotIncluded = new Vector();
+        dirsExcluded = new Vector();
+
+        if (isIncluded("")) {
+            if (!isExcluded("")) {
+                dirsIncluded.addElement("");
+            } else {
+                dirsExcluded.addElement("");
+            }
+        } else {
+            dirsNotIncluded.addElement("");
+        }
+        scandir(basedir, "", true);
+    }
+
+    protected void scandir(File file, String vpath, boolean fast) {
+        ZipFile zip = null;
+        try {
+            zip = new ZipFile(file);
+        } catch (IOException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+
+        Enumeration entries = zip.entries();
+        while (entries.hasMoreElements()) {
+            ZipEntry entry = (ZipEntry) entries.nextElement();
+            String name = entry.getName();
+            // @fixme do we need to strip out entries that starts
+            // with . or ./ ?
+            if (entry.isDirectory()) {
+                if (isIncluded(name)) {
+                    if (!isExcluded(name)) {
+                        dirsIncluded.addElement(name);
+                    } else {
+                        everythingIncluded = false;
+                        dirsExcluded.addElement(name);
+                    }
+                } else {
+                    everythingIncluded = false;
+                    dirsNotIncluded.addElement(name);
+                }
+            } else {
+                if (isIncluded(name)) {
+                    if (!isExcluded(name)) {
+                        filesIncluded.addElement(name);
+                    } else {
+                        everythingIncluded = false;
+                        filesExcluded.addElement(name);
+                    }
+                } else {
+                    everythingIncluded = false;
+                    filesNotIncluded.addElement(name);
+                }
+            }
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseFormatter.java
new file mode 100644
index 0000000..c359ce5
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseFormatter.java
@@ -0,0 +1,97 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * Provide a common set of attributes and methods to factorize
+ *
+ */
+public abstract class BaseFormatter implements Formatter {
+
+    public void init(Properties props) throws BuildException {
+    }
+
+    public void onTestStarted(TestRunEvent evt) {
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+    }
+
+    public void onTestError(TestRunEvent evt) {
+    }
+
+    public void onSuiteStarted(TestRunEvent evt) {
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+    }
+
+    public void onRunStarted(TestRunEvent evt) {
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseStreamFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseStreamFormatter.java
new file mode 100644
index 0000000..cf08b01
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BaseStreamFormatter.java
@@ -0,0 +1,140 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.io.BufferedWriter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.KeepAliveOutputStream;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * Base formatter providing default implementation to deal with
+ * either stdout or a file.
+ * <p>
+ * The file is specified by initializing the formatter with
+ * a filepath mapped by the key 'file'.
+ * </p>
+ * <p>
+ * if no file key exists in the properties, it defaults to stdout.
+ * </p>
+ *
+ */
+public class BaseStreamFormatter extends BaseFormatter {
+
+    /** the key used to specifiy a filepath */
+    public final static String FILE_KEY = "file";
+
+    /** writer to output the data to */
+    private PrintWriter writer;
+
+    protected void finalize() throws Throwable {
+        super.finalize();
+        close();
+    }
+
+    public void init(Properties props) throws BuildException {
+        String file = props.getProperty(FILE_KEY);
+        OutputStream os = null;
+        if (file != null) {
+            try {
+                // fixme need to resolve the file !!!!
+                os = new FileOutputStream(file);
+            } catch (IOException e) {
+                throw new BuildException(e);
+            }
+        } else {
+            os = new KeepAliveOutputStream(System.out);
+        }
+        setOutput(os);
+    }
+
+    /**
+     * Helper method to wrap the stream over an UTF8 buffered writer.
+     */
+    protected void setOutput(OutputStream value) {
+        try {
+            // do not buffer but flush each line.
+            writer = new PrintWriter(new OutputStreamWriter(value, "UTF8"), true);
+        } catch (IOException e) {
+            // should not happen
+            throw new BuildException(e);
+        }
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        close();
+    }
+
+    protected void close() {
+        if (writer != null) {
+            writer.flush();
+            writer.close();
+        }
+    }
+
+    /**
+     * @return the writer used to print data.
+     */
+    protected final PrintWriter getWriter() {
+        return writer;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java
new file mode 100644
index 0000000..00303d4
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/BriefFormatter.java
@@ -0,0 +1,83 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * Display additional messages from a <tt>SummaryFormatter</tt>
+ * for failures and errors.
+ *
+ */
+public class BriefFormatter extends SummaryFormatter {
+
+    private final static Resources RES =
+            ResourceManager.getPackageResources(BriefFormatter.class);
+
+    public void onTestFailure(TestRunEvent evt) {
+        String msg = RES.getString("brief.status-failure.msg", evt.getName(),
+                evt.getError().getStackTrace());
+        getWriter().println(msg);
+        super.onTestFailure(evt);
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        String msg = RES.getString("brief.status-error.msg", evt.getName(),
+                evt.getError().getStackTrace());
+        getWriter().println(msg);
+        super.onTestError(evt);
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterFormatter.java
new file mode 100644
index 0000000..bf99d70
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterFormatter.java
@@ -0,0 +1,123 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * A base class that can be used to filter data.
+ *
+ */
+public abstract class FilterFormatter implements Formatter {
+
+    private Formatter formatter;
+
+    protected FilterFormatter(Formatter formatter) {
+        setFormatter(formatter);
+    }
+
+    /** final to enforce chaining of initialization */
+    public final void init(Properties props) throws BuildException {
+        formatter.init(props);
+    }
+
+    public void onSuiteStarted(TestRunEvent evt) {
+        formatter.onSuiteStarted(evt);
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+        formatter.onSuiteEnded(evt);
+    }
+
+    public void onTestStarted(TestRunEvent evt) {
+        formatter.onTestStarted(evt);
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+        formatter.onTestEnded(evt);
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        formatter.onTestFailure(evt);
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        formatter.onTestError(evt);
+    }
+
+    public void onRunStarted(TestRunEvent evt) {
+        formatter.onRunStarted(evt);
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        formatter.onRunEnded(evt);
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+        formatter.onRunEnded(evt);
+    }
+
+    /** set the wrapped formatter */
+    protected void setFormatter(Formatter value) {
+        formatter = value;
+    }
+
+    /** return the wrapped formatter */
+    protected Formatter getFormatter() {
+        return formatter;
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java
new file mode 100644
index 0000000..a5cb917
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatter.java
@@ -0,0 +1,168 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.ExceptionData;
+
+/**
+ * Filtered Formatter that strips out unwanted stack frames from the full
+ * stack trace, for instance it will filter the lines containing the
+ * following matches:
+ * <pre>
+ *   junit.framework.TestCase
+ *   junit.framework.TestResult
+ *   junit.framework.TestSuite
+ *   junit.framework.Assert.
+ *   junit.swingui.TestRunner
+ *   junit.awtui.TestRunner
+ *   junit.textui.TestRunner
+ *   java.lang.reflect.Method.invoke(
+ *   org.apache.tools.ant.
+ * </pre>
+ * Removing all the above will help to make stacktrace more readable.
+ *
+ */
+public class FilterStackFormatter extends FilterFormatter {
+
+    /** the set of matches to look for in a stack trace */
+    private final static String[] DEFAULT_TRACE_FILTERS = new String[]{
+        "junit.framework.TestCase",
+        "junit.framework.TestResult",
+        "junit.framework.TestSuite",
+        "junit.framework.Assert.", // don't filter AssertionFailure
+        "junit.swingui.TestRunner",
+        "junit.awtui.TestRunner",
+        "junit.textui.TestRunner",
+        "java.lang.reflect.Method.invoke(",
+        "org.apache.tools.ant."
+    };
+
+    private final String[] filters = getFilters();
+
+    /**
+     * Creates a new <tt>FilterStackFormatter</tt>
+     * @param formatter the formatter to be filtered.
+     */
+    public FilterStackFormatter(Formatter formatter) {
+        super(formatter);
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        filterEvent(evt);
+        super.onTestFailure(evt);
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        filterEvent(evt);
+        super.onTestFailure(evt);
+    }
+
+    protected void filterEvent(TestRunEvent evt){
+        String filteredTrace = filter(evt.getError().getStackTrace());
+        ExceptionData error = new ExceptionData(
+                evt.getError().getType(),
+                evt.getError().getMessage(),
+                filteredTrace);
+        evt.setError(error);
+    }
+
+    protected String filter(String trace){
+        StringTokenizer st = new StringTokenizer(trace, "\r\n");
+        StringBuffer buf = new StringBuffer(trace.length());
+        while (st.hasMoreTokens()) {
+            String line = st.nextToken();
+            if (accept(line)) {
+                buf.append(line).append(StringUtils.LINE_SEP);
+            }
+        }
+        return buf.toString();
+    }
+    /**
+     * Check whether or not the line should be accepted.
+     * @param line the line to be check for acceptance.
+     * @return <tt>true</tt> if the line is accepted, <tt>false</tt> if not.
+     */
+    protected boolean accept(String line) {
+        for (int i = 0; i < filters.length; i++) {
+            if (line.indexOf(filters[i]) > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @return the filters to use for this
+     */
+    protected static String[] getFilters(){
+        // @fixme hack for now, need something better.
+        // using configuration properties ?
+        String filters = System.getProperty("ant.rjunit.stacktrace.filters");
+        if (filters == null){
+            return DEFAULT_TRACE_FILTERS;
+        }
+        StringTokenizer st = new StringTokenizer(filters, ",");
+        String[] results = new String[ st.countTokens() ];
+        int i = 0;
+        while (st.hasMoreTokens()){
+            results[i++] = st.nextToken();
+        }
+        return results;
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Formatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Formatter.java
new file mode 100644
index 0000000..258a2dd
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Formatter.java
@@ -0,0 +1,73 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener;
+
+/**
+ * The formatter interface.
+ *
+ */
+public interface Formatter extends TestRunListener {
+    /**
+     * Initialize the formatter with some custom properties
+     * For example it could be a filename, a port and hostname,
+     * a database, etc...
+     */
+    public void init(Properties props) throws BuildException;
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java
new file mode 100644
index 0000000..9757322
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/PlainFormatter.java
@@ -0,0 +1,101 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.util.Properties;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * Default formatter to text.
+ *
+ */
+public class PlainFormatter extends BaseStreamFormatter {
+
+    public void onSuiteStarted(TestRunEvent evt) {
+        getWriter().println("  suite: " + evt.getName());
+        super.onSuiteStarted(evt);
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+        getWriter().println("  end suite");
+        super.onSuiteEnded(evt);
+    }
+
+    public void onTestStarted(TestRunEvent evt) {
+        getWriter().println("    running test: " + evt.getName());
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+        getWriter().println("    success: " + evt.getName());
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        getWriter().println("    failure: " + evt.getName());
+        getWriter().println(evt.getError().getStackTrace());
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        getWriter().println("    error: " + evt.getName());
+        getWriter().println(evt.getError().getStackTrace());
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        getWriter().println("run ended");
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+        getWriter().println("run stopped");
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Resources.properties b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Resources.properties
new file mode 100644
index 0000000..9ffd8a5
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/Resources.properties
@@ -0,0 +1,8 @@
+# Summary formatter
+suite.summary.msg = TestSuite: {0}\nTests run: {1, number, integer}, Failures: {2, number, integer}, Errors: {3, number, integer}, Time elapsed: {4, number, integer}s\n
+run.summary.msg=Summary Tests run: {0, number, integer}, Failures: {1, number, integer}, Errors: {2, number, integer}, Time elapsed: {3, number, integer}s
+
+# Brief formatter
+brief.status-error.msg = TestCase: {0}\tCaused an ERROR\n{1}\n
+brief.status-failure.msg = TestCase: {0}\tFAILED\n{1}\n
+
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/SummaryFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/SummaryFormatter.java
new file mode 100644
index 0000000..3579185
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/SummaryFormatter.java
@@ -0,0 +1,91 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestSummary;
+
+/**
+ * Display a summary message at the end of a testsuite stating
+ * runs, failures, errors, and elapsed time.
+ *
+ */
+public class SummaryFormatter extends BaseStreamFormatter {
+
+    private final static Resources RES =
+            ResourceManager.getPackageResources(SummaryFormatter.class);
+
+    public void onSuiteEnded(TestRunEvent evt) {
+        TestSummary summary = evt.getSummary();
+        String msg = RES.getString("suite.summary.msg",
+                evt.getName(),
+                new Integer(summary.runCount()),
+                new Integer(summary.failureCount()),
+                new Integer(summary.errorCount()),
+                new Long(summary.elapsedTime()/1000));
+        getWriter().println(msg);
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        TestSummary summary = evt.getSummary();
+        String msg = RES.getString("run.summary.msg",
+                new Integer(summary.runCount()),
+                new Integer(summary.failureCount()),
+                new Integer(summary.errorCount()),
+                new Long(summary.elapsedTime()/1000));
+        getWriter().println(msg);
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java
new file mode 100644
index 0000000..90a9712
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/XMLFormatter.java
@@ -0,0 +1,284 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Date;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.rjunit.JUnitHelper;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestSummary;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.ExceptionData;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * XML Formatter. Due to the nature of the XML we are forced to store
+ * everything in memory until it is finished. It might be resource
+ * intensive when running lots of testcases.
+ *
+ * <testsuites stop="true">
+ *  <testsuite name="" time="">
+ *    <testcase name="" time="">
+ *      <error/>
+ *    </testcase>
+ *    <testcase name="" time="">
+ *      <failure/>
+ *    </testcase>
+ *  </testsuite>
+ * </testsuites>
+ *
+ */
+public class XMLFormatter extends BaseStreamFormatter {
+
+    /** the testsuites element for the aggregate document */
+    public final static String TESTSUITES = "testsuites";
+
+    /** the testsuite element */
+    public final static String TESTSUITE = "testsuite";
+
+    /** the testcase element */
+    public final static String TESTCASE = "testcase";
+
+    /** the error element */
+    public final static String ERROR = "error";
+
+    /** the failure element */
+    public final static String FAILURE = "failure";
+
+    /** the system-err element */
+    public final static String SYSTEM_ERR = "system-err";
+
+    /** the system-out element */
+    public final static String SYSTEM_OUT = "system-out";
+
+    /** package attribute for the aggregate document */
+    public final static String ATTR_PACKAGE = "package";
+
+    /** name attribute for property, testcase and testsuite elements */
+    public final static String ATTR_NAME = "name";
+
+    /** time attribute for testcase and testsuite elements */
+    public final static String ATTR_TIME = "time";
+
+    /** errors attribute for testsuite elements */
+    public final static String ATTR_ERRORS = "errors";
+
+    /** failures attribute for testsuite elements */
+    public final static String ATTR_FAILURES = "failures";
+
+    /** tests attribute for testsuite elements */
+    public final static String ATTR_TESTS = "tests";
+
+    /** type attribute for failure and error elements */
+    public final static String ATTR_TYPE = "type";
+
+    /** message attribute for failure elements */
+    public final static String ATTR_MESSAGE = "message";
+
+    /** the properties element */
+    public final static String PROPERTIES = "properties";
+
+    /** the property element */
+    public final static String PROPERTY = "property";
+
+    /** value attribute for property elements */
+    public final static String ATTR_VALUE = "value";
+
+    /** The XML document. */
+    private Document doc = getDocumentBuilder().newDocument();
+
+    /**  The wrapper for the whole testsuite. */
+    private Element rootElement = doc.createElement(TESTSUITES);
+
+    private Element lastTestElement = null;
+    private TestRunEvent lastTestEvent = null;
+    private Element lastSuiteElement = null;
+    private long programStart;
+
+    public void onSuiteStarted(TestRunEvent evt) {
+        String fullclassname = evt.getName();
+        int pos = fullclassname.lastIndexOf('.');
+
+        // a missing . might imply no package at all. Don't get fooled.
+        String pkgName = (pos == -1) ? "" : fullclassname.substring(0, pos);
+        String classname = (pos == -1) ? fullclassname : fullclassname.substring(pos + 1);
+
+        Element suite = doc.createElement(TESTSUITE);
+        suite.setAttribute(ATTR_NAME, classname);
+        suite.setAttribute(ATTR_PACKAGE, pkgName);
+        rootElement.appendChild(suite);
+        lastSuiteElement = suite;
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+        Element suite = lastSuiteElement;
+        TestSummary summary = evt.getSummary();
+        suite.setAttribute(ATTR_TIME, String.valueOf(summary.elapsedTime()/1000.0f));
+        suite.setAttribute(ATTR_TESTS, String.valueOf(summary.runCount()));
+        suite.setAttribute(ATTR_FAILURES, String.valueOf(summary.failureCount()));
+        suite.setAttribute(ATTR_ERRORS, String.valueOf(summary.errorCount()));
+        lastSuiteElement = null;
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        final String elapsedTime = String.valueOf(evt.getTimeStamp() - programStart);
+        rootElement.setAttribute("elapsed_time", elapsedTime);
+        // Output properties
+        final Element propsElement = doc.createElement(PROPERTIES);
+        rootElement.appendChild(propsElement);
+        final Properties props = evt.getProperties();
+        if (props != null) {
+            Enumeration e = props.propertyNames();
+            while (e.hasMoreElements()) {
+                String name = (String) e.nextElement();
+                Element propElement = doc.createElement(PROPERTY);
+                propElement.setAttribute(ATTR_NAME, name);
+                propElement.setAttribute(ATTR_VALUE, props.getProperty(name));
+                propsElement.appendChild(propElement);
+            }
+        }
+        close();
+    }
+
+    public void onRunStarted(TestRunEvent evt) {
+        programStart = evt.getTimeStamp();
+        final String date = DateUtils.format(programStart, DateUtils.ISO8601_DATETIME_PATTERN);
+        rootElement.setAttribute("program_start", date);
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+        rootElement.setAttribute("stopped", "true");
+        onRunEnded(evt);
+    }
+
+    public void onTestStarted(TestRunEvent evt) {
+        Element test = doc.createElement(TESTCASE);
+        String name = JUnitHelper.getTestName(evt.getName());
+        test.setAttribute(ATTR_NAME, name);
+        String suiteName = JUnitHelper.getSuiteName(evt.getName());
+        String lastSuiteName = lastSuiteElement.getAttribute(ATTR_PACKAGE)
+                + "." + lastSuiteElement.getAttribute(ATTR_NAME);
+        if ( !suiteName.equals(lastSuiteName) ){
+            throw new BuildException("Received testcase from test "
+                    + suiteName + " and was expecting "
+                    + lastSuiteElement.getAttribute("name"));
+        }
+        lastSuiteElement.appendChild(test);
+        lastTestElement = test;
+        lastTestEvent = evt;
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+        // with a TestSetup, startTest and endTest are not called.
+        if (lastTestEvent == null) {
+            onTestStarted(evt);
+        }
+        float time = (evt.getTimeStamp() - lastTestEvent.getTimeStamp()) / 1000.0f;
+        lastTestElement.setAttribute(ATTR_TIME, Float.toString(time));
+        lastTestElement = null;
+        lastTestEvent = null;
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        onTestFailure(evt);
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        String type = evt.getType() == TestRunEvent.TEST_FAILURE ? FAILURE : ERROR;
+        Element nested = doc.createElement(type);
+        lastTestElement.appendChild(nested);
+        ExceptionData error = evt.getError();
+        nested.setAttribute(ATTR_MESSAGE, error.getMessage());
+        nested.setAttribute(ATTR_TYPE, error.getType());
+        Text text = doc.createTextNode(error.getStackTrace());
+        nested.appendChild(text);
+        onTestEnded(evt);
+    }
+
+    protected void close() {
+        // the underlying writer uses UTF8 encoding
+        getWriter().println("<?xml version='1.0' encoding='UTF-8' ?>");
+        String now = DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN);
+        rootElement.setAttribute("snapshot_created", now);
+        try {
+            final DOMElementWriter domWriter = new DOMElementWriter();
+            domWriter.write(rootElement, getWriter(), 0, "  ");
+        } catch (IOException e) {
+            throw new BuildException(e);
+        } finally {
+            super.close();
+        }
+    }
+
+    private static DocumentBuilder getDocumentBuilder() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        } catch (Exception exc) {
+            throw new ExceptionInInitializerError(exc);
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java
new file mode 100644
index 0000000..c3eccfc
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/EventDispatcher.java
@@ -0,0 +1,179 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Dispatch messages to appropriate listener methode based on event id.
+ *
+ */
+public class EventDispatcher {
+
+    private final static HashMap eventMap = new HashMap(3);
+
+    static {
+        registerDefaults();
+    }
+
+    /** the set of registered listeners */
+    private ArrayList listeners = new ArrayList();
+
+    /**
+     * Add a new listener.
+     * @param listener a listener that will receive events from the client.
+     */
+    public void addListener(TestRunListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removeListener(TestRunListener listener) {
+        listeners.remove(listener);
+    }
+
+    /**
+     * Process a message from the client and dispatch the
+     * appropriate message to the listeners.
+     */
+    public void dispatchEvent(TestRunEvent evt) {
+        final Integer type = new Integer(evt.getType());
+        final EventAction action = (EventAction) eventMap.get(type);
+        if (action == null) {
+            return;
+        }
+        synchronized (listeners) {
+            final int count = listeners.size();
+            for (int i = 0; i < count; i++) {
+                TestRunListener listener = (TestRunListener) listeners.get(i);
+                action.dispatch(listener, evt);
+            }
+        }
+    }
+
+    private static void registerDefaults() {
+        registerAction(TestRunEvent.RUN_STARTED, new RunStartedAction());
+        registerAction(TestRunEvent.RUN_ENDED, new RunEndedAction());
+        registerAction(TestRunEvent.TEST_STARTED, new TestStartedAction());
+        registerAction(TestRunEvent.TEST_ENDED, new TestEndedAction());
+        registerAction(TestRunEvent.TEST_FAILURE, new TestFailureAction());
+        registerAction(TestRunEvent.TEST_ERROR, new TestErrorAction());
+        registerAction(TestRunEvent.SUITE_STARTED, new SuiteStartedAction());
+        registerAction(TestRunEvent.SUITE_ENDED, new SuiteEndedAction());
+        registerAction(TestRunEvent.RUN_STOPPED, new RunStoppedAction());
+    }
+
+    private static void registerAction(int id, EventAction action){
+        eventMap.put(new Integer(id), action);
+    }
+
+    public interface EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt);
+    }
+
+    private static class RunStartedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onRunStarted(evt);
+        }
+    }
+
+    private static class RunEndedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onRunEnded(evt);
+        }
+    }
+
+    private static class TestStartedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onTestStarted(evt);
+        }
+    }
+
+    private static class TestEndedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onTestEnded(evt);
+        }
+    }
+
+    private static class TestFailureAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onTestFailure(evt);
+        }
+    }
+
+    private static class TestErrorAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onTestError(evt);
+        }
+    }
+
+    private static class SuiteStartedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onSuiteStarted(evt);
+        }
+    }
+
+    private static class SuiteEndedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onSuiteEnded(evt);
+        }
+    }
+
+    private static class RunStoppedAction implements EventAction {
+        public void dispatch(TestRunListener listener, TestRunEvent evt) {
+            listener.onRunStopped(evt);
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/ExceptionData.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/ExceptionData.java
new file mode 100644
index 0000000..19b80fb
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/ExceptionData.java
@@ -0,0 +1,132 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.Serializable;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * A wrapper around an exception since an exception stacktrace is
+ * not serializable.
+ *
+ */
+public class ExceptionData implements Serializable {
+
+    /** the stacktrace of the exception */
+    private final String stacktrace;
+
+    /** the classname of an exception */
+    private final String type;
+
+    /** the message associated to this exception */
+    private final String message;
+
+    /**
+     * Create a new error.
+     * @param exception the exception to run as
+     */
+    public ExceptionData(Throwable exception) {
+        this(exception.getClass().getName(),
+                exception.getMessage(),
+                StringUtils.getStackTrace(exception));
+    }
+
+    /**
+     * Create a new error.
+     * @param type the type of the error (ie classname).
+     * @param message the message associated to this error.
+     * @param stacktrace the full stacktrace of this error.
+     */
+    public ExceptionData(String type, String message, String stacktrace) {
+        this.stacktrace = stacktrace;
+        this.type = type;
+        this.message = message;
+    }
+
+    /**
+     * @return the type of the error (ie classname)
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * @return the message associated to this error.
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * @return the stacktrace for this error.
+     */
+    public String getStackTrace() {
+        return stacktrace;
+    }
+
+    public boolean equals(Object o){
+        if ( o instanceof ExceptionData ){
+            ExceptionData other = (ExceptionData)o;
+            return ( ( type == null ? other.type == null :  type.equals(other.type) ) &&
+                    ( message == null ? other.message == null : message.equals(other.message) ) &&
+                    ( stacktrace == null ? other.stacktrace == null : stacktrace.equals(other.stacktrace) ) );
+        }
+        return false;
+    }
+
+    public String toString() {
+        return (message != null) ? (type + ": " + message) : type;
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java
new file mode 100644
index 0000000..75f68cd
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Messenger.java
@@ -0,0 +1,120 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * Read or write events to/from appropriate streams.
+ *
+ */
+public class Messenger {
+
+    private InputStream in;
+
+    private OutputStream out;
+
+    public Messenger(InputStream in, OutputStream out) throws IOException {
+        setOutputStream( new ObjectOutputStream(out) );
+        setInputStream( new ObjectInputStream(in) );
+    }
+
+    protected void finalize() throws Throwable {
+        close();
+    }
+
+    public void close() throws IOException {
+        if (out != null) {
+            out.flush();
+            out.close();
+            out = null;
+        }
+        if (in != null) {
+            in.close();
+            in = null;
+        }
+    }
+
+    public TestRunEvent read() {
+        try {
+            return (TestRunEvent)((ObjectInputStream)in).readObject();
+        } catch (Exception e){
+            return null;
+        }
+    }
+
+    public void writeEvent(TestRunEvent evt) throws IOException {
+        ((ObjectOutputStream)out).writeObject(evt);
+    }
+
+    protected OutputStream getOutputStream(){
+        return out;
+    }
+
+    protected InputStream getInputStream(){
+        return in;
+    }
+
+    protected void setOutputStream(OutputStream out){
+        this.out = out;
+    }
+
+    protected void setInputStream(InputStream in){
+        this.in = in;
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Server.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Server.java
new file mode 100644
index 0000000..67662f6
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/Server.java
@@ -0,0 +1,176 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * The server that will receive events from a remote client.
+ *
+ * <i>
+ * This code is based on the code from Erich Gamma made for the
+ * JUnit plugin for <a href="http://www.eclipse.org">Eclipse</a> and is
+ * merged with code originating from Ant 1.4.x.
+ * </i>
+ *
+ * @see TestRunner
+ */
+public class Server {
+
+    /** the port where the server is listening */
+    private int port = -1;
+
+    /** the server socket */
+    private ServerSocket server;
+
+    /** the client that is connected to the server */
+    private Socket client;
+
+    /** the reader in charge of interpreting messages from the client */
+    private Messenger messenger;
+
+    private EventDispatcher dispatcher = new EventDispatcher();
+
+    public Server(int port) {
+        this.port = port;
+    }
+
+    protected void finalize() throws Exception {
+        cancel();
+        shutdown();
+    }
+
+    /**
+     * add a new listener
+     * @param listener a instance of a listener.
+     */
+    public void addListener(TestRunListener listener) {
+        dispatcher.addListener(listener);
+    }
+
+    /**
+     * remove an existing listener
+     * @param listener a instance of a listener.
+     */
+    public void removeListener(TestRunListener listener) {
+        dispatcher.removeListener(listener);
+    }
+
+    /** return whether there is a client running or not */
+    public synchronized boolean isRunning() {
+        return client != null && server != null && messenger != null;
+    }
+
+    /** start a server to the specified port */
+    public void start(boolean loop) throws IOException {
+        server = new ServerSocket(port);
+        while (server != null) {
+            client = server.accept();
+            messenger = new Messenger(client.getInputStream(), client.getOutputStream());
+            TestRunEvent evt = null;
+            try {
+                while ( (evt = messenger.read()) != null ) {
+                    dispatcher.dispatchEvent(evt);
+                }
+            } catch (Exception e){
+                e.printStackTrace();
+                //@fixme this stacktrace might be normal when closing
+                // the socket. So decompose the above in distinct steps
+            }
+            if (!loop){
+                break;
+            }
+        }
+    }
+
+    /** cancel the connection to the client */
+    public synchronized void cancel() {
+        if (isRunning()) {
+            TestRunEvent evt = new TestRunEvent(new Integer(-1), TestRunEvent.RUN_STOP);
+            try {
+                messenger.writeEvent(evt);
+            } catch (IOException e){
+            }
+        }
+    }
+
+    /** shutdown the server and any running client */
+    public synchronized void shutdown() {
+        try {
+            if (messenger != null) {
+                messenger.close();
+                messenger = null;
+            }
+        } catch (IOException e){
+        }
+        try {
+            if (client != null) {
+                client.shutdownInput();
+                client.shutdownOutput();
+                client.close();
+                client = null;
+            }
+        } catch (IOException e) {
+        }
+        try {
+            if (server != null) {
+                server.close();
+                server = null;
+            }
+        } catch (IOException e) {
+        }
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java
new file mode 100644
index 0000000..d4e884b
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunEvent.java
@@ -0,0 +1,190 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.util.EventObject;
+import java.util.Properties;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Provide the basic events to be used during the tests.
+ * This is not very extensible but since the events should be somewhat
+ * limited, for now this is better to do it like this.
+ *
+ */
+public class TestRunEvent extends EventObject {
+
+    // received from clients
+    public final static int RUN_STARTED = 0;
+    public final static int RUN_ENDED = 1;
+    public final static int RUN_STOPPED = 2;
+    public final static int TEST_STARTED = 3;
+    public final static int TEST_FAILURE = 4;
+    public final static int TEST_ERROR = 5;
+    public final static int TEST_ENDED = 6;
+    public final static int SUITE_STARTED = 7;
+    public final static int SUITE_ENDED = 8;
+
+    // received from server
+    public final static int RUN_STOP = 9;
+
+    /** the type of event */
+    private int type = -1;
+
+    /** timestamp for all events */
+    private long timestamp = System.currentTimeMillis();
+
+    /** name of testcase(method name) or testsuite (classname) */
+    private String name;
+
+    /** stacktrace for error or failure */
+    private ExceptionData error;
+
+    /** properties for end of testrun */
+    private Properties props;
+
+    /** handy result for each end of sequence */
+    private TestSummary result;
+
+    public TestRunEvent(Integer id, int type){
+        super(id);
+        this.type = type;
+    }
+
+    public TestRunEvent(Integer id, int type, String name, TestSummary result){
+        this(id, type, name);
+        this.result = result;
+    }
+
+    public TestRunEvent(Integer id, int type, String name){
+        this(id, type);
+        this.name = name;
+    }
+
+    public TestRunEvent(Integer id, int type, Properties props, TestSummary result){
+        this(id, type);
+        this.props = props;
+        this.result = result;
+    }
+
+    public TestRunEvent(Integer id, int type, String name, Throwable t){
+        this(id, type, name);
+        this.error = new ExceptionData(t);
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public void setTimeStamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public void setError(ExceptionData error) {
+        this.error = error;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setProperties(Properties props) {
+        this.props = props;
+    }
+
+    public int getType(){
+        return type;
+    }
+
+    public long getTimeStamp(){
+        return timestamp;
+    }
+
+    public String getName(){
+        return name;
+    }
+
+    public TestSummary getSummary(){
+        return result;
+    }
+
+    public ExceptionData getError(){
+        return error;
+    }
+
+    public Properties getProperties(){
+        return props;
+    }
+
+    public boolean equals(Object o){
+        if (o instanceof TestRunEvent){
+            TestRunEvent other = (TestRunEvent)o;
+            return ( (type == other.type) &&
+                    (timestamp == other.timestamp) &&
+                    ( name == null ? other.name == null :  name.equals(other.name) ) &&
+                    ( error == null ? other.error == null : error.equals(other.error) ) &&
+                    ( props == null ? other.props == null : props.equals(other.props) ) &&
+                    ( result == null ? other.result == null : result.equals(other.result) ) );
+        }
+        return false;
+    }
+
+    public String toString(){
+        StringBuffer buf = new StringBuffer();
+        buf.append("id: ").append(source);
+        buf.append("type: ").append(type);
+        return buf.toString();
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunListener.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunListener.java
new file mode 100644
index 0000000..f5ade87
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunListener.java
@@ -0,0 +1,75 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.util.EventListener;
+
+
+/**
+ *
+ */
+public interface TestRunListener extends EventListener {
+
+    void onRunStarted(TestRunEvent evt);
+    void onRunEnded(TestRunEvent evt);
+    void onRunStopped(TestRunEvent evt);
+
+    void onSuiteStarted(TestRunEvent evt);
+    void onSuiteEnded(TestRunEvent evt);
+
+    void onTestStarted(TestRunEvent evt);
+    void onTestError(TestRunEvent evt);
+    void onTestFailure(TestRunEvent evt);
+    void onTestEnded(TestRunEvent evt);
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunner.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunner.java
new file mode 100644
index 0000000..f505ad4
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunner.java
@@ -0,0 +1,486 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Random;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.JUnitHelper;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.Formatter;
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.PlainFormatter;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * TestRunner for running tests and send results to a remote server.
+ *
+ * <i>
+ * This code is based on the code from Erich Gamma made for the
+ * JUnit plugin for <a href="http://www.eclipse.org">Eclipse</a> and is
+ * merged with code originating from Ant 1.4.x.
+ * </i>
+ *
+ */
+public class TestRunner implements TestListener {
+
+    /** unique identifier for the runner */
+    private final Integer id = new Integer( (new Random()).nextInt() );
+
+    /** host to connect to */
+    private String host = "127.0.0.1";
+
+    /** port to connect to */
+    private int port = -1;
+
+    /** handy debug flag */
+    private boolean debug = false;
+
+    /** the list of test class names to run */
+    private final ArrayList testClassNames = new ArrayList();
+
+    /** result of the current test */
+    private TestResult testResult;
+
+    /** client socket to communicate with the server */
+    private Socket clientSocket;
+
+    /** writer to send message to the server */
+    private Messenger messenger;
+
+    /** helpful formatter to debug events directly here */
+    private final Formatter debugFormatter = new PlainFormatter();
+
+    /** bean constructor */
+    public TestRunner() {
+        Properties props = new Properties();
+        props.setProperty("file", "rjunit-client-debug.log");
+        debugFormatter.init(props);
+    }
+
+    /**
+     * Set the debug mode.
+     * @param debug true to set to debug mode otherwise false.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Set the port to connect to the server
+     * @param port a valid port number.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Set the hostname of the server
+     * @param host the hostname or ip of the server
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Add a test class name to be executed by this runner.
+     * @param classname the class name of the test to run.
+     */
+    public void addTestClassName(String classname) {
+        testClassNames.add(classname);
+    }
+
+    /**
+     * Thread listener for a shutdown from the server
+     * Note that it will stop any running test.
+     */
+    private class StopThread extends Thread {
+        public void run() {
+            try {
+                TestRunEvent evt = null;
+                if ((evt = messenger.read()) != null) {
+                    if (evt.getType() == TestRunEvent.RUN_STOP) {
+                        TestRunner.this.stop();
+                    }
+                }
+            } catch (Exception e) {
+                TestRunner.this.stop();
+            }
+        }
+    }
+
+    /**
+     * Entry point for command line.
+     * Usage:
+     * <pre>
+     * TestRunner -classnames <classnames> -port <port> -host <host> -debug
+     * -file
+     * -classnames <list of whitespace separated classnames to run>
+     * -port       <port to connect to>
+     * -host       <host to connect to>
+     * -debug      to run in debug mode
+     * </pre>
+     */
+    public static void main(String[] args) throws Exception {
+        TestRunner testRunServer = new TestRunner();
+        testRunServer.init(args);
+        testRunServer.run();
+    }
+
+    /**
+     * Parses the arguments of command line.
+     * testClassNames, host, port, listeners and debug mode are set
+     * @see  #main(String[])
+     */
+    protected void init(String[] args) throws Exception {
+        for (int i = 0; i < args.length; i++) {
+            if ("-file".equalsIgnoreCase(args[i])) {
+                // @fixme if you mix file and other options it will be a mess,
+                // not important right now.
+                FileInputStream fis = new FileInputStream(args[++i]);
+                Properties props = new Properties();
+                props.load(fis);
+                fis.close();
+                init(props);
+            }
+            if ("-classnames".equalsIgnoreCase(args[i])) {
+                for (int j = ++i; j < args.length; j++) {
+                    if (args[j].startsWith("-"))
+                        break;
+                    addTestClassName(args[j]);
+                }
+            }
+            if ("-port".equalsIgnoreCase(args[i])) {
+                setPort(Integer.parseInt(args[++i]));
+            }
+            if ("-host".equalsIgnoreCase(args[i])) {
+                setHost(args[++i]);
+            }
+            if ("-debug".equalsIgnoreCase(args[i])) {
+                setDebug(true);
+            }
+        }
+    }
+
+    /**
+     * Initialize the TestRunner from properties.
+     * @param props the properties containing configuration data.
+     * @see #init(String[])
+     */
+    protected void init(Properties props) {
+        if (props.getProperty("debug") != null) {
+            setDebug(true);
+        }
+        String port = props.getProperty("port");
+        if (port != null) {
+            setPort(Integer.parseInt(port));
+        }
+        String host = props.getProperty("host");
+        if (host != null) {
+            setHost(host);
+        }
+        String classnames = props.getProperty("classnames");
+        if (classnames != null) {
+            StringTokenizer st = new StringTokenizer(classnames);
+            while (st.hasMoreTokens()) {
+                addTestClassName(st.nextToken());
+            }
+        }
+    }
+
+    public final void run() throws Exception {
+        if (testClassNames.size() == 0) {
+            throw new IllegalArgumentException("No TestCase specified");
+        }
+        connect();
+
+        testResult = new TestResult();
+        testResult.addListener(this);
+        runTests();
+
+        testResult.removeListener(this);
+        if (testResult != null) {
+            testResult.stop();
+            testResult = null;
+        }
+    }
+
+    /**
+     * Transform all classnames into instantiated <tt>Test</tt>.
+     * @throws Exception a generic exception that can be thrown while
+     * instantiating a test case.
+     */
+    protected Map getSuites() throws Exception {
+        final int count = testClassNames.size();
+        log("Extracting testcases from " + count + " classnames...");
+        final Map suites = new HashMap();
+        for (int i = 0; i < count; i++) {
+            String classname = (String) testClassNames.get(i);
+            try {
+                Test test = JUnitHelper.getTest(null, classname);
+                if (test != null) {
+                    suites.put(classname, test);
+                }
+            } catch (Exception e) {
+                // notify log error instead ?
+                log("Could not get Test instance from " + classname);
+                log(e);
+            }
+        }
+        log("Extracted " + suites.size() + " testcases.");
+        return suites;
+    }
+
+    private void runTests() throws Exception {
+
+        Map suites = getSuites();
+
+        // count all testMethods and inform TestRunListeners
+        int count = countTests(suites.values());
+        log("Total tests to run: " + count);
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.RUN_STARTED);
+        if (debug){
+            debugFormatter.onRunStarted(evt);
+        }
+        fireEvent(evt);
+
+        TestSummary runSummary = new TestSummary();
+        runSummary.start(testResult);
+        for (Iterator it = suites.entrySet().iterator(); it.hasNext(); ) {
+            Map.Entry entry = (Map.Entry)it.next();
+            String name = (String)entry.getKey();
+            Test test = (Test)entry.getValue();
+            if (test instanceof TestCase) {
+                test = new TestSuite(name);
+            }
+            runTest(test, name);
+        }
+        runSummary.stop(testResult);
+
+        // inform TestRunListeners of test end
+        int type = (testResult == null || testResult.shouldStop()) ?
+            TestRunEvent.RUN_STOPPED : TestRunEvent.RUN_ENDED;
+        evt = new TestRunEvent(id, type, System.getProperties(), runSummary);
+        if (debug){
+            debugFormatter.onRunEnded(evt);
+        }
+        fireEvent(evt);
+        log("Finished after " + runSummary.elapsedTime() + "ms");
+        shutDown();
+    }
+
+    /**
+     * run a single suite and dispatch its results.
+     * @param test the instance of the testsuite to run.
+     * @param name the name of the testsuite (classname)
+     */
+    private void runTest(Test test, String name){
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.SUITE_STARTED, name);
+        if (debug){
+            debugFormatter.onSuiteStarted(evt);
+        }
+        fireEvent(evt);
+        TestSummary suiteSummary = new TestSummary();
+        suiteSummary.start(testResult);
+        try {
+            test.run(testResult);
+        } finally {
+            suiteSummary.stop(testResult);
+            evt = new TestRunEvent(id, TestRunEvent.SUITE_ENDED, name, suiteSummary);
+            if (debug){
+                debugFormatter.onSuiteEnded(evt);
+            }
+            fireEvent(evt);
+        }
+    }
+
+    /**
+     * count the number of test methods in all tests
+     */
+    private final int countTests(Collection tests) {
+        int count = 0;
+        for (Iterator it = tests.iterator(); it.hasNext(); ) {
+            Test test = (Test)it.next();
+            count = count + test.countTestCases();
+        }
+        return count;
+    }
+
+    protected void stop() {
+        if (testResult != null) {
+            testResult.stop();
+        }
+    }
+
+    /**
+     * connect to the specified host and port.
+     * @throws IOException if any error occurs during connection.
+     */
+    protected void connect() throws IOException {
+        log("Connecting to " + host + " on port " + port + "...");
+        clientSocket = new Socket(host, port);
+        messenger = new Messenger(clientSocket.getInputStream(), clientSocket.getOutputStream());
+        new StopThread().start();
+    }
+
+
+    protected void shutDown() {
+        try {
+            if (messenger != null) {
+                messenger.close();
+                messenger = null;
+            }
+        } catch (IOException e) {
+            log(e);
+        }
+
+        try {
+            if (clientSocket != null) {
+                clientSocket.close();
+                clientSocket = null;
+            }
+        } catch (IOException e) {
+            log(e);
+        }
+    }
+
+    protected void fireEvent(TestRunEvent evt){
+        try {
+            messenger.writeEvent(evt);
+        } catch (IOException e){
+            log(e);
+        }
+    }
+
+// -------- JUnit TestListener implementation
+
+
+    public void startTest(Test test) {
+        String testName = test.toString();
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.TEST_STARTED, testName);
+        if (debug){
+            debugFormatter.onTestStarted(evt);
+        }
+        fireEvent(evt);
+    }
+
+    public void addError(Test test, Throwable t) {
+        String testName = test.toString();
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.TEST_ERROR, testName, t);
+        if (debug){
+            debugFormatter.onTestError(evt);
+        }
+        fireEvent(evt);
+    }
+
+    /**
+     * this implementation is for JUnit &lt; 3.4
+     * @see #addFailure(Test, Throwable)
+     */
+    public void addFailure(Test test, AssertionFailedError afe) {
+        addFailure(test, (Throwable) afe);
+    }
+
+    /**
+     * This implementation is for JUnit &lt;= 3.4
+     * @see #addFailure(Test, AssertionFailedError)
+     */
+    public void addFailure(Test test, Throwable t) {
+        String testName = test.toString();
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.TEST_FAILURE, testName, t);
+        if (debug){
+            debugFormatter.onTestFailure(evt);
+        }
+        fireEvent(evt);
+    }
+
+    public void endTest(Test test) {
+        String testName = test.toString();
+        TestRunEvent evt = new TestRunEvent(id, TestRunEvent.TEST_ENDED, testName);
+        if (debug){
+            debugFormatter.onTestEnded(evt);
+        }
+        fireEvent(evt);
+    }
+
+    public void log(String msg) {
+        if (debug) {
+            System.out.println(msg);
+        }
+    }
+
+    public void log(Throwable t) {
+        if (debug) {
+            t.printStackTrace();
+        }
+    }
+}
+
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestSummary.java b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestSummary.java
new file mode 100644
index 0000000..686a770
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestSummary.java
@@ -0,0 +1,174 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.Serializable;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+
+/**
+ * A helpful test summary that is somewhat similar to <tt>TestResult</tt>.
+ * Here the difference is that this test summary should register to
+ * the test result the time you wan to collect information.
+ *
+ */
+public final class TestSummary implements Serializable, TestListener {
+
+    /** time elapsed during tests run  in ms */
+    private long elapsedTime;
+
+    /** number of errors */
+    private int errorCount;
+
+    /** number of successes */
+    private int successCount;
+
+    /** number of failures */
+    private int failureCount;
+
+    /** number of runs */
+    private int runCount;
+
+    /** bean constructor */
+    public TestSummary() {
+    }
+
+    /**
+     * @return the number of errors that occurred in this test.
+     */
+    public int errorCount() {
+        return errorCount;
+    }
+
+    /**
+     * @return the number of successes that occurred in this test.
+     */
+    public int successCount() {
+        return successCount;
+    }
+
+    /**
+     * @return the number of failures that occurred in this test.
+     */
+    public int failureCount() {
+        return failureCount;
+    }
+
+    /**
+     * @return the number of runs that occurred in this test.
+     * a run is the sum of failures + errors + successes.
+     */
+    public int runCount() {
+        return runCount;
+    }
+
+    /**
+     * @return the elapsed time in ms
+     */
+    public long elapsedTime() {
+        return elapsedTime;
+    }
+
+//
+    /**
+     * register to the <tt>TestResult</tt> and starts the time counter.
+     * @param result the instance to register to.
+     * @see #stop(TestResult)
+     */
+    public void start(TestResult result){
+        elapsedTime = System.currentTimeMillis();
+        result.addListener(this);
+    }
+
+    /**
+     * unregister from the <tt>TestResult</tt> and stops the time counter.
+     * @param result the instance to unregister from.
+     * @see #start(TestResult)
+     */
+    public void stop(TestResult result){
+        elapsedTime = System.currentTimeMillis() - elapsedTime;
+        result.removeListener(this);
+    }
+
+// test listener implementation
+
+    public void addError(Test test, Throwable throwable) {
+        errorCount++;
+    }
+
+    public void addFailure(Test test, AssertionFailedError error) {
+        failureCount++;
+    }
+
+    public void endTest(Test test) {
+        successCount++;
+    }
+
+    public void startTest(Test test) {
+        runCount++;
+    }
+
+    public String toString(){
+        StringBuffer buf = new StringBuffer();
+        buf.append("run: ").append(runCount);
+        buf.append(" success: ").append(successCount);
+        buf.append(" failures: ").append(failureCount);
+        buf.append(" errors: ").append(errorCount);
+        buf.append(" elapsed: ").append(elapsedTime);
+        return buf.toString();
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/usecase.xml b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/usecase.xml
new file mode 100644
index 0000000..ef673c4
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/main/org/apache/tools/ant/taskdefs/optional/rjunit/usecase.xml
@@ -0,0 +1,51 @@
+<project name="" basedir="." default="tests">
+
+    <target name="tests">
+
+        <rjunit port="1234">
+            <server>
+                <formatter type="xml" filters="stacktrace"/>
+                <formatter type="plain" filters="stacktrace"/>
+                <formatter type="jms" filters="stacktrace">
+                    <param name="queue" value="test_queue"/>
+                </formatter>
+                <formatter type="rmi" filters="stacktrace">
+                    <param name="host" value="127.0.0.1"/>
+                    <param name="port" value="6789"/>
+                </formatter>
+            </server>
+
+            <client host="127.0.0.1">
+                <classpath refid="test-classpath"/>
+                <jvmarg value="-Xmx=512MB"/>
+                <test name="org.apache.test.NullTest" if="condition1">
+                <batchtest path="${classpath}" unless="condition2">
+                    <include name="**Test*"/>
+                </batchtest>
+            </client>
+        <rjunit>
+    </target>
+
+    <target name="server-only">
+        <!-- will block until a client connect and finishes -->
+        <rjunit port="1234">
+            <server>
+                <formatter type="xml" filters="stacktrace"/>
+                    <param name="file" location="test.xml"/>
+                </formatter>
+            </server>
+       </rjunit>
+    </target>
+
+    <target name="server-only">
+        <!-- will connect to an existing server and send results -->
+        <rjunit port="1234">
+            <client host="127.0.0.1">
+                <classpath refid="test-classpath"/>
+                <jvmarg value="-Xmx=512MB"/>
+                <test name="org.apache.test.NullTest" if="condition1">
+            </client>
+       </rjunit>
+    </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTaskTest.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTaskTest.java
new file mode 100644
index 0000000..bcb5894
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/RJUnitTaskTest.java
@@ -0,0 +1,105 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+import java.net.URL;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+
+/**
+ *
+ */
+public class RJUnitTaskTest extends BuildFileTest {
+    public RJUnitTaskTest(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        configureProject("data/build-test.xml");
+    }
+
+    protected void configureProject(String resource){
+        URL url = getClass().getResource(resource);
+        assertNotNull("Could not find resource :" + resource, url);
+        super.configureProject(url.getFile());
+    }
+
+    public void testServerAndClient(){
+        executeTarget("server-and-client");
+        System.out.println(getFullLog());
+    }
+    public void testServerAndClient2(){
+        executeTarget("server-and-client");
+        System.out.println(getFullLog());
+    }
+    /*
+    public void testStandalone() throws Exception {
+        // run server first..
+        Thread thread = new Thread(){
+            public void run(){
+                executeTarget("server-only");
+            }
+        };
+        thread.start();
+
+        executeTarget("client-only");
+        System.out.println(getFullLog());
+        thread.join();
+    }
+*/
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/TestRunRecorder.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/TestRunRecorder.java
new file mode 100644
index 0000000..2f53d56
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/TestRunRecorder.java
@@ -0,0 +1,115 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener;
+
+/**
+ * A TestRunListener that stores all events for later check.
+ *
+ * <p>
+ * All the events are stored chronologically in distinct vectors
+ * and are made available as public instances
+ * </p>
+ *
+ */
+public class TestRunRecorder implements TestRunListener {
+
+// all these are public in order for testcases to have access quickly
+    public Vector testStarted = new Vector();
+    public Vector testEnded = new Vector();
+    public Vector testFailed = new Vector();
+    public Vector testError = new Vector();
+    public Vector runStarted = new Vector();
+    public Vector runEnded = new Vector();
+    public Vector runStopped = new Vector();
+
+    public void onTestStarted(TestRunEvent evt) {
+        testStarted.addElement(evt);
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+        testEnded.addElement(evt);
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        testFailed.addElement(evt);
+    }
+
+    public void onRunStarted(TestRunEvent evt) {
+        runStarted.addElement(evt);
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+        runEnded.addElement(evt);
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+        runStopped.addElement(evt);
+    }
+
+    public void onSuiteStarted(TestRunEvent evt) {
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+    }
+
+    public void onTestError(TestRunEvent evt) {
+        testError.addElement( evt );
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScannerTest.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScannerTest.java
new file mode 100644
index 0000000..adba411
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/ZipScannerTest.java
@@ -0,0 +1,104 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+/**
+ * Basic test to ensure that the collector is working.
+ *
+ */
+public class ZipScannerTest extends TestCase {
+    public ZipScannerTest(String s) {
+        super(s);
+    }
+
+    protected ZipScanner _scanner;
+
+    protected void setUp() throws Exception {
+        _scanner = new ZipScanner();
+        String path = System.getProperty("java.home") + "/lib/rt.jar";
+        _scanner.setBasedir(path);
+    }
+
+    public void testScan() throws Exception {
+        _scanner.scan();
+        String[] files = _scanner.getIncludedFiles();
+        assertContains(files, "java/lang/Exception.class");
+        String[] dirs = _scanner.getIncludedDirectories();
+        assertContains(dirs, "java/lang/");
+    }
+
+    public void testIncludes() throws Exception {
+        _scanner.setIncludes( new String[]{ "**/Exception.class" });
+        _scanner.scan();
+        String[] files = _scanner.getIncludedFiles();
+        assertEquals(1, files.length);
+        assertEquals(files[0], "java/lang/Exception.class");
+    }
+
+
+
+    public void assertContains(Object[] lists, Object o){
+        for (int i = 0; i < lists.length; i++){
+            if (lists[i].equals(o)){
+                return;
+            }
+        }
+        fail("Should contain " + o);
+    }
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/Test1.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/Test1.java
new file mode 100644
index 0000000..a08cc18
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/Test1.java
@@ -0,0 +1,77 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.data;
+
+import junit.framework.TestCase;
+
+/**
+ * Provide a common set of test reporting.
+ *
+ */
+public class Test1 extends TestCase {
+    public Test1(String s) {
+        super(s);
+    }
+
+    public void testSuccess(){
+    }
+
+    public void testFailure(){
+        fail("failure on purpose");
+    }
+
+    public void testError(){
+        throw new RuntimeException("error on purpose");
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/build-test.xml b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/build-test.xml
new file mode 100644
index 0000000..d2f7233
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/data/build-test.xml
@@ -0,0 +1,42 @@
+<project name="rjunit-tests" basedir="." default="server-and-client">
+
+    <taskdef name="rjunit" classname="org.apache.tools.ant.taskdefs.optional.rjunit.RJUnitTask"/>
+
+    <target name="server-and-client">
+        <echo message="java.class.path: ${java.class.path}"/>
+        <rjunit>
+            <server port="1234">
+                <formatter type="plain">
+                    <param name="file" location="junit-test-log.txt"/>
+                </formatter>
+            </server>
+            <client host="127.0.0.1"  port="1234">
+                <classpath path="${java.class.path}"/>
+                <test name="org.apache.tools.ant.taskdefs.optional.junit.data.Test1"/>
+            </client>
+        </rjunit>
+    </target>
+
+    <target name="server-only">
+        <rjunit>
+            <server port="1234">
+                <formatter type="plain">
+                    <param name="file" location="junit-test-log.txt"/>
+                </formatter>
+                <formatter type="xml">
+                    <param name="file" location="junit-test-log.xml"/>
+                </formatter>
+            </server>
+        </rjunit>
+    </target>
+
+    <target name="client-only">
+        <rjunit>
+            <client host="127.0.0.1"  port="1234">
+                <classpath path="${java.class.path}"/>
+                <test name="org.apache.tools.ant.taskdefs.optional.junit.data.Test1"/>
+            </client>
+        </rjunit>
+    </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatterTest.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatterTest.java
new file mode 100644
index 0000000..41fc17f
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FilterStackFormatterTest.java
@@ -0,0 +1,159 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunEvent;
+
+/**
+ * Not exactly rocket science test.. dooh !
+ *
+ */
+public class FilterStackFormatterTest extends TestCase
+        implements Formatter {
+
+    public FilterStackFormatterTest(String s) {
+        super(s);
+    }
+
+    protected String trace;
+    protected String expected;
+
+    protected void setUp() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
+        pw.println("org.apache.test.ClassName.method(ClassName.java:125)");
+        pw.println("\tat org.apache.test.C1.m1(C1.java:125)");
+        pw.println("\tat junit.framework.TestCase.m0(TestCase.java:999)");
+        pw.println("\tat org.apache.test.C2.m1(C2.java:125)");
+        pw.println("\tat junit.framework.TestResult.m1(TestResult.java:999)");
+        pw.println("\tat org.apache.test.C3.m1(C3.java:125)");
+        pw.println("\tat junit.framework.TestSuite.m2(TestSuite.java:999)");
+        pw.println("\tat org.apache.test.C4.m1(C4.java:125)");
+        pw.println("\tat junit.framework.Assert.m3(Assert.java:999)");
+        pw.println("\tat junit.swingui.TestRunner.m3(TestRunner.java:999)");
+        pw.println("\tat junit.awtui.TestRunner.m3(TestRunner.java:999)");
+        pw.println("\tat org.apache.test.C5.m1(C5.java:125)");
+        pw.println("\tat junit.textui.TestRunner.m3(TestRunner.java:999)");
+        pw.println("\tat java.lang.reflect.Method.invoke(Method.java:999)");
+        pw.println("\tat org.apache.tools.ant.C.m(C.java:999)");
+        pw.println("\tat org.apache.test.C6.m1(C6.java:125)");
+        trace = sw.toString();
+        sw.getBuffer().setLength(0);
+
+        pw.println("org.apache.test.ClassName.method(ClassName.java:125)");
+        pw.println("\tat org.apache.test.C1.m1(C1.java:125)");
+        pw.println("\tat org.apache.test.C2.m1(C2.java:125)");
+        pw.println("\tat org.apache.test.C3.m1(C3.java:125)");
+        pw.println("\tat org.apache.test.C4.m1(C4.java:125)");
+        pw.println("\tat org.apache.test.C5.m1(C5.java:125)");
+        pw.println("\tat org.apache.test.C6.m1(C6.java:125)");
+        expected = sw.toString();
+    }
+
+    public void testFiltering() {
+        /*
+        FilterStackFormatter wrapper = new FilterStackFormatter(this);
+        Exception e = new Exception("xx");
+        e.fillInStackTrace();
+        TestRunEvent evt = new TestRunEvent(new Integer(1), TestRunEvent.TEST_ERROR, "xx");
+        wrapper.onTestFailure(evt);
+        StringUtils.getStackTrace()
+        assertEquals(expected, filteredTrace);
+        */
+    }
+
+
+// --- formatter implementation
+    protected String filteredTrace;
+
+    public void onTestStarted(TestRunEvent evt) {
+    }
+
+    public void onTestEnded(TestRunEvent evt) {
+    }
+
+    public void init(Properties props) throws BuildException {
+    }
+
+    public void onTestFailure(TestRunEvent evt) {
+        filteredTrace = trace;
+    }
+
+    public void onSuiteStarted(TestRunEvent evt) {
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+    }
+
+    public void onTestError(TestRunEvent evt) {
+    }
+
+    public void onRunStarted(TestRunEvent evt) {
+    }
+
+    public void onRunEnded(TestRunEvent evt) {
+    }
+
+    public void onRunStopped(TestRunEvent evt) {
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FormatterRecorder.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FormatterRecorder.java
new file mode 100644
index 0000000..29da93a
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/formatter/FormatterRecorder.java
@@ -0,0 +1,73 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.formatter;
+
+import java.io.OutputStream;
+import java.util.Properties;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.TestRunRecorder;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * A formatter recorder that serves the same purpose as
+ * a <tt>TestRunRecorder</tt>
+ *
+ *
+ * @see TestRunRecorder
+ */
+public class FormatterRecorder extends TestRunRecorder
+        implements Formatter {
+    public void init(Properties props) throws BuildException {
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/MessageReaderTest.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/MessageReaderTest.java
new file mode 100644
index 0000000..c966217
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/MessageReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.io.PrintWriter;
+import java.io.PipedOutputStream;
+import java.io.PipedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener;
+import org.apache.tools.ant.taskdefs.optional.rjunit.TestRunRecorder;
+
+/**
+ * Ensure that the Reader/Writer works fine.
+ *
+ */
+public class MessageReaderTest extends TestCase {
+
+    private EventDispatcher dispatcher;
+
+    protected TestRunRecorder recorder;
+
+    public MessageReaderTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() {
+        dispatcher = new EventDispatcher();
+        recorder = new TestRunRecorder();
+        dispatcher.addListener( recorder );
+    }
+
+    public void testTestRunStarted() throws Exception {
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.RUN_STARTED);
+        dispatcher.fireRunStarted( evt );
+        assertEquals(evt, recorder.runStarted.elementAt(0));
+    }
+
+    public void testTestStarted() throws Exception {
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.TEST_STARTED, "xxxx");
+        dispatcher.fireTestStarted( evt );
+        assertEquals(evt, recorder.testStarted.elementAt(0));
+    }
+
+    public void testTestEnded() throws Exception {
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.TEST_ENDED, "xxxx");
+        dispatcher.fireTestEnded( evt );
+        assertEquals(evt, recorder.testEnded.elementAt(0));
+    }
+
+    public void testTestFailedError() throws Exception {
+        Exception e = new Exception("error");
+        e.fillInStackTrace();
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.TEST_ERROR, "xxxx", e);
+        dispatcher.fireTestError( evt );
+        assertEquals(evt, recorder.testError.elementAt(0));
+    }
+
+    public void testTestFailedFailure() throws Exception {
+        Exception e = new Exception("error");
+        e.fillInStackTrace();
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.TEST_FAILURE, "xxxx", e);
+        dispatcher.fireTestFailure( evt );
+        assertEquals(evt, recorder.testFailed.elementAt(0));
+    }
+
+    public void testTestRunEnded() throws Exception {
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.RUN_ENDED);
+        dispatcher.fireRunEnded( evt );
+        assertEquals(evt, recorder.runEnded.elementAt(0));
+    }
+
+    public void testTestRunStopped() throws Exception {
+        TestRunEvent evt = new TestRunEvent(new Integer(99), TestRunEvent.RUN_STOPPED);
+        dispatcher.fireRunStopped( evt );
+        assertEquals(evt, recorder.runStopped.elementAt(0));
+    }
+
+
+
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestCases.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestCases.java
new file mode 100644
index 0000000..520b48e
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestCases.java
@@ -0,0 +1,110 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.Test;
+import junit.extensions.TestSetup;
+
+/**
+ *
+ */
+public class TestCases {
+
+    /** null testcase w/ 3 tests */
+    public static class NullTestCase extends TestCase {
+        public NullTestCase(String s) {
+            super(s);
+        }
+        public void testSuccess(){}
+        public void testFailure(){ assertTrue(false); }
+        public void testError(){ throw new RuntimeException("on purpose"); }
+    }
+
+    /** testcase w/ a static suite method */
+    public static class NullTestSuite extends TestCase {
+        public NullTestSuite(String s) {
+            super(s);
+        }
+        public static Test suite(){
+            return new TestSuite(NullTestCase.class);
+        }
+    }
+
+    public static class SimpleTestCase extends TestCase {
+        public SimpleTestCase(String s) {
+            super(s);
+        }
+        public void testSuccess(){}
+    }
+
+    public static class FailSetupTestSuite extends TestCase {
+        public FailSetupTestSuite(String s) {
+            super(s);
+        }
+        public static Test suite(){
+            return new FailTestSetup( new TestSuite(SimpleTestCase.class) );
+        }
+    }
+
+    public static class FailTestSetup extends TestSetup {
+        public FailTestSetup(Test test) {
+            super(test);
+        }
+        protected void setUp(){
+            throw new IllegalArgumentException("on purpose");
+        }
+    }
+}
diff --git a/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunnerTest.java b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunnerTest.java
new file mode 100644
index 0000000..15b0134
--- /dev/null
+++ b/trunk/proposal/sandbox/junit/src/testcases/org/apache/tools/ant/taskdefs/optional/rjunit/remote/TestRunnerTest.java
@@ -0,0 +1,179 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs.optional.rjunit.remote;
+
+import java.util.Vector;
+import java.util.Properties;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.framework.TestListener;
+
+import org.apache.tools.ant.taskdefs.optional.rjunit.formatter.PlainFormatter;
+import org.apache.tools.ant.taskdefs.optional.rjunit.remote.TestRunListener;
+import org.apache.tools.ant.taskdefs.optional.rjunit.TestRunRecorder;
+
+/**
+ * TestCase for the test runner.
+ *
+ */
+public class TestRunnerTest extends TestCase
+        implements TestRunListener {
+
+    public final static int PORT = 1234;
+
+    protected Server server;
+
+    protected TestRunner runner;
+
+    protected TestRunRecorder recorder;
+
+    protected boolean done;
+
+    public TestRunnerTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() throws Exception {
+        server = createServer();
+        server.start();
+        runner = createClient();
+        recorder = new TestRunRecorder();
+        server.addListener( recorder );
+        server.addListener( this );
+    }
+
+    protected void tearDown() throws Exception {
+        server.shutdown();
+        runner.stop();
+    }
+
+    protected Server createServer() throws Exception {
+        return new Server(PORT);
+    }
+
+    protected TestRunner createClient() throws Exception {
+        TestRunner client = new TestRunner();
+        client.setDebug(true);
+        client.setHost("127.0.0.1");
+        client.setPort(PORT);
+        return client;
+    }
+
+    public void testNullTestCase() throws Exception {
+        runner.addTestClassName(TestCases.NullTestCase.class.getName());
+//        server.addListener( new PlainFormatter() );
+        runner.run();
+        synchronized(this){ while (!done){ wait(); } }
+        assertEquals(1, recorder.runStarted.size());
+        /*
+        assertTrue(recorder.runStarted.elementAt(0).toSt("testSuccess"));
+        assertTrue(started.contains("testFailure"));
+        assertTrue(started.contains("testError"));*/
+
+    }
+
+    public void testFailSetupTestCase() throws Exception {
+        runner.addTestClassName(TestCases.FailSetupTestSuite.class.getName());
+        runner.run();
+        synchronized(this){ while (!done){ wait(); } }
+
+        assertEquals(1, recorder.runStarted.size());
+        assertEquals(1, recorder.runEnded.size());
+    }
+
+    public void testFailSetupTestSuite() throws Exception {
+        runner.addTestClassName(TestCases.FailSetupTestSuite.class.getName());
+        runner.run();
+        synchronized(this){ while (!done){ wait(); } }
+        assertEquals(1, recorder.runStarted.size());
+        assertEquals(1, recorder.runEnded.size());
+    }
+
+    public static void main(String[] args){
+        TestSuite suite = new TestSuite(TestRunnerTest.class);
+        junit.textui.TestRunner.run(suite);
+    }
+
+// TestRunListener implementation
+    public void onTestStarted(TestRunEvent evt) {
+    }
+    public void onTestEnded(TestRunEvent evt) {
+    }
+    public void onTestFailure(TestRunEvent evt) {
+    }
+    public void onRunStarted(TestRunEvent count) {
+    }
+    public void onRunEnded(TestRunEvent evt) {
+        synchronized(this){
+            done = true;
+            notify();
+        }
+    }
+    public void onRunStopped(TestRunEvent evt) {
+        synchronized(this){
+            done = true;
+            notify();
+        }
+    }
+
+    public void onSuiteStarted(TestRunEvent evt) {
+    }
+
+    public void onSuiteEnded(TestRunEvent evt) {
+    }
+
+    public void onTestError(TestRunEvent evt) {
+    }
+}
diff --git a/trunk/proposal/sandbox/selectors/README b/trunk/proposal/sandbox/selectors/README
new file mode 100644
index 0000000..fce8eaa
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/README
@@ -0,0 +1,34 @@
+Selector API
+============
+
+Currently our filesets allow us to select a set of files based on name patterns.
+For instance we could create a set of all the files that end with ".java". 
+However there are cases when you wish to select files based on their other 
+attributes, such as if they are read only or if they are older than a specified 
+date etc. 
+
+The selector API is one such mechanism to do this. The selector API will allow 
+you to build file sets based on criteria other than name. Some possible criteria 
+would be 
+
+Is the file readable? 
+Is the file writeable? 
+What date was the file modified on? 
+What size is the file? 
+Does the contents contain the string "magic"? 
+
+If we end up supporting a VFS then we could expand the number of selectors 
+considerably. A mock representation that has been proposed before is the 
+following. Of course this is subject to change as soon as someone wants to 
+tackle this action ;) 
+
+ <include name="**/*.java">
+   <selector type="permission" value="r"/>
+
+   <!-- could optionally be directory/or some other system specific features -->
+   <selector type="type" value="file"/> 
+   <selector type="modify-time" 
+             operation="greater-than" 
+             value="29th Feb 2003"/>
+ </include>
+
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/DirectoryScanner.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/DirectoryScanner.java
new file mode 100644
index 0000000..821b737
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/DirectoryScanner.java
@@ -0,0 +1,1204 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Pattern;
+import org.apache.tools.ant.selectors.FileSelector;
+
+/**
+ * Class for scanning a directory for files/directories that match a certain
+ * criteria.
+ * <p>
+ * These criteria consist of a set of include and exclude patterns. With these
+ * patterns, you can select which files you want to have included, and which
+ * files you want to have excluded.
+ * <p>
+ * The idea is simple. A given directory is recursively scanned for all files
+ * and directories. Each file/directory is matched against a set of include
+ * and exclude patterns. Only files/directories that match at least one
+ * pattern of the include pattern list, and don't match a pattern of the
+ * exclude pattern list will be placed in the list of files/directories found.
+ * <p>
+ * When no list of include patterns is supplied, "**" will be used, which
+ * means that everything will be matched. When no list of exclude patterns is
+ * supplied, an empty list is used, such that nothing will be excluded.
+ * <p>
+ * The pattern matching is done as follows:
+ * The name to be matched is split up in path segments. A path segment is the
+ * name of a directory or file, which is bounded by
+ * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
+ * E.g. "abc/def/ghi/xyz.java" is split up in the segments "abc", "def", "ghi"
+ * and "xyz.java".
+ * The same is done for the pattern against which should be matched.
+ * <p>
+ * Then the segments of the name and the pattern will be matched against each
+ * other. When '**' is used for a path segment in the pattern, then it matches
+ * zero or more path segments of the name.
+ * <p>
+ * There are special case regarding the use of <code>File.separator</code>s at
+ * the beginningof the pattern and the string to match:<br>
+ * When a pattern starts with a <code>File.separator</code>, the string
+ * to match must also start with a <code>File.separator</code>.
+ * When a pattern does not start with a <code>File.separator</code>, the
+ * string to match may not start with a <code>File.separator</code>.
+ * When one of these rules is not obeyed, the string will not
+ * match.
+ * <p>
+ * When a name path segment is matched against a pattern path segment, the
+ * following special characters can be used:
+ * '*' matches zero or more characters,
+ * '?' matches one character.
+ * <p>
+ * Examples:
+ * <p>
+ * "**\*.class" matches all .class files/dirs in a directory tree.
+ * <p>
+ * "test\a??.java" matches all files/dirs which start with an 'a', then two
+ * more characters and then ".java", in a directory called test.
+ * <p>
+ * "**" matches everything in a directory tree.
+ * <p>
+ * "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where
+ * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
+ * <p>
+ * Case sensitivity may be turned off if necessary.  By default, it is
+ * turned on.
+ * <p>
+ * Example of usage:
+ * <pre>
+ *   String[] includes = {"**\\*.class"};
+ *   String[] excludes = {"modules\\*\\**"};
+ *   ds.setIncludes(includes);
+ *   ds.setExcludes(excludes);
+ *   ds.setBasedir(new File("test"));
+ *   ds.setCaseSensitive(true);
+ *   ds.scan();
+ *
+ *   System.out.println("FILES:");
+ *   String[] files = ds.getIncludedFiles();
+ *   for (int i = 0; i < files.length;i++) {
+ *     System.out.println(files[i]);
+ *   }
+ * </pre>
+ * This will scan a directory called test for .class files, but excludes all
+ * .class files in all directories under a directory called "modules"
+ *
+ */
+public class DirectoryScanner implements FileScanner {
+
+    /**
+     * Patterns that should be excluded by default.
+     *
+     * @see #addDefaultExcludes()
+     */
+    protected final static String[] DEFAULTEXCLUDES = {
+        "**/*~",
+        "**/#*#",
+        "**/.#*",
+        "**/%*%",
+        "**/CVS",
+        "**/CVS/**",
+        "**/.cvsignore",
+        "**/SCCS",
+        "**/SCCS/**",
+        "**/vssver.scc"
+    };
+
+    /**
+     * The base directory which should be scanned.
+     */
+    protected File basedir;
+
+    /**
+     * The patterns for the files that should be included.
+     */
+    protected Pattern[] includes;
+
+    /**
+     * The patterns for the files that should be excluded.
+     */
+    protected Pattern[] excludes;
+
+    /**
+     * The files that where found and matched at least one includes, and matched
+     * no excludes.
+     */
+    protected Vector filesIncluded;
+
+    /**
+     * The files that where found and did not match any includes.
+     */
+    protected Vector filesNotIncluded;
+
+    /**
+     * The files that where found and matched at least one includes, and also
+     * matched at least one excludes.
+     */
+    protected Vector filesExcluded;
+
+    /**
+     * The directories that where found and matched at least one includes, and
+     * matched no excludes.
+     */
+    protected Vector dirsIncluded;
+
+    /**
+     * The directories that where found and did not match any includes.
+     */
+    protected Vector dirsNotIncluded;
+
+    /**
+     * The files that where found and matched at least one includes, and also
+     * matched at least one excludes.
+     */
+    protected Vector dirsExcluded;
+
+    /**
+     * Have the Vectors holding our results been built by a slow scan?
+     */
+    protected boolean haveSlowResults = false;
+
+    /**
+     * Should the file system be treated as a case sensitive one?
+     */
+    protected boolean isCaseSensitive = true;
+
+    /**
+     * Is everything we've seen so far included?
+     */
+    protected boolean everythingIncluded = true;
+
+    private static Hashtable selectorClasses = null;
+
+    static {
+        String defs = "/org/apache/tools/ant/selectors/defaults.properties";
+        selectorClasses = new Hashtable();
+
+        try {
+            Properties props = new Properties();
+            InputStream in = DirectoryScanner.class.getResourceAsStream(defs);
+            if (in == null) {
+                throw new BuildException("Can't load default selector list");
+            }
+            props.load(in);
+            in.close();
+
+            Enumeration enum = props.propertyNames();
+            while (enum.hasMoreElements()) {
+                String key = (String) enum.nextElement();
+                String value = props.getProperty(key);
+                try {
+                    selectorClasses.put(key, Class.forName(value));
+                } catch (NoClassDefFoundError ncdfe) {
+                } catch (ClassNotFoundException cnfe) {
+                }
+            }
+        } catch (IOException ioe) {
+            throw new BuildException("Can't load default selector list");
+        }
+    }
+
+    /**
+     * Constructor.
+     */
+    public DirectoryScanner() {
+    }
+
+
+    /**
+     * Does the path match the start of this pattern up to the first "**".
+     *
+     * <p>This is not a general purpose test and should only be used if you
+     * can live with false positives.</p>
+     *
+     * <p><code>pattern=**\\a</code> and <code>str=b</code> will yield true.
+     *
+     * @param pattern the (non-null) pattern to match against
+     * @param str     the (non-null) string (path) to match
+     */
+    protected static boolean matchPatternStart(String pattern, String str) {
+        return matchPatternStart(pattern, str, true);
+    }
+
+    /**
+     * Does the path match the start of this pattern up to the first "**".
+     *
+     * <p>This is not a general purpose test and should only be used if you
+     * can live with false positives.</p>
+     *
+     * <p><code>pattern=**\\a</code> and <code>str=b</code> will yield true.
+     *
+     * @param pattern             the (non-null) pattern to match against
+     * @param str                 the (non-null) string (path) to match
+     * @param isCaseSensitive     must matches be case sensitive?
+     */
+    protected static boolean matchPatternStart(String pattern, String str,
+                                               boolean isCaseSensitive) {
+        // When str starts with a File.separator, pattern has to start with a
+        // File.separator.
+        // When pattern starts with a File.separator, str has to start with a
+        // File.separator.
+        if (str.startsWith(File.separator) !=
+            pattern.startsWith(File.separator)) {
+            return false;
+        }
+
+        Vector patDirs = new Vector();
+        StringTokenizer st = new StringTokenizer(pattern,File.separator);
+        while (st.hasMoreTokens()) {
+            patDirs.addElement(st.nextToken());
+        }
+
+        Vector strDirs = new Vector();
+        st = new StringTokenizer(str,File.separator);
+        while (st.hasMoreTokens()) {
+            strDirs.addElement(st.nextToken());
+        }
+
+        int patIdxStart = 0;
+        int patIdxEnd   = patDirs.size()-1;
+        int strIdxStart = 0;
+        int strIdxEnd   = strDirs.size()-1;
+
+        // up to first '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = (String)patDirs.elementAt(patIdxStart);
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir,(String)strDirs.elementAt(strIdxStart), isCaseSensitive)) {
+                return false;
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            return true;
+        } else if (patIdxStart > patIdxEnd) {
+            // String not exhausted, but pattern is. Failure.
+            return false;
+        } else {
+            // pattern now holds ** while string is not exhausted
+            // this will generate false positives but we can live with that.
+            return true;
+        }
+    }
+
+    protected static boolean isSelected(String fileToScan, Vector selectorList) {
+        boolean isInclusive = true;
+        if (selectorList != null ) {
+            PatternSet.SelectorEntry[] selectorEntries =
+                new PatternSet.SelectorEntry[selectorList.size()];
+            selectorList.copyInto(selectorEntries);
+            boolean[] selectorIndices = new boolean[selectorEntries.length];
+
+            for (int i = 0; i < selectorEntries.length; i++) {
+                String type = selectorEntries[i].getType();
+                String value = selectorEntries[i].getValue();
+                String operation = selectorEntries[i].getOperation();
+                Class c = (Class) selectorClasses.get(type);
+                if (c != null) {
+                    FileSelector s = null;
+                    try {
+                        s = (FileSelector) c.newInstance();
+                        s.setValue(value);
+                        s.setOperation(operation);
+                        isInclusive = s.isSelected(fileToScan);
+                    } catch (InstantiationException ie) {
+                    } catch (IllegalAccessException ie) {
+                    }
+                    if (!isInclusive) {
+                        break;
+                    }
+                }
+            }
+        }
+        return isInclusive;
+    }
+
+    /**
+     * Matches a path against a pattern.
+     *
+     * @param pattern the (non-null) pattern to match against
+     * @param str     the (non-null) string (path) to match
+     *
+     * @return <code>true</code> when the pattern matches against the string.
+     *         <code>false</code> otherwise.
+     */
+    protected static boolean matchPath(String pattern, String str) {
+        return matchPath(pattern, null, str, true);
+    }
+
+    protected static boolean matchPath(String pattern,
+                                       String str, boolean isCaseSensitive) {
+        return matchPath(pattern, null, str, isCaseSensitive);
+    }
+
+    /**
+     * Matches a path against a pattern.
+     *
+     * @param pattern            the (non-null) pattern to match against
+     * @param str                the (non-null) string (path) to match
+     * @param isCaseSensitive    must a case sensitive match be done?
+     *
+     * @return <code>true</code> when the pattern matches against the string.
+     *         <code>false</code> otherwise.
+     */
+    protected static boolean matchPath(String pattern, Vector selectorList,
+                                       String str, boolean isCaseSensitive) {
+        // When str starts with a File.separator, pattern has to start with a
+        // File.separator.
+        // When pattern starts with a File.separator, str has to start with a
+        // File.separator.
+        if (str.startsWith(File.separator) !=
+            pattern.startsWith(File.separator)) {
+            return false;
+        }
+
+        Vector patDirs = new Vector();
+        StringTokenizer st = new StringTokenizer(pattern,File.separator);
+        while (st.hasMoreTokens()) {
+            patDirs.addElement(st.nextToken());
+        }
+
+        Vector strDirs = new Vector();
+        st = new StringTokenizer(str,File.separator);
+        while (st.hasMoreTokens()) {
+            strDirs.addElement(st.nextToken());
+        }
+
+        int patIdxStart = 0;
+        int patIdxEnd   = patDirs.size()-1;
+        int strIdxStart = 0;
+        int strIdxEnd   = strDirs.size()-1;
+
+        // up to first '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = (String)patDirs.elementAt(patIdxStart);
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir,(String)strDirs.elementAt(strIdxStart), isCaseSensitive)) {
+                return false;
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (!patDirs.elementAt(i).equals("**")) {
+                    return false;
+                }
+            }
+            return isSelected(str, selectorList);
+        } else {
+            if (patIdxStart > patIdxEnd) {
+                // String not exhausted, but pattern is. Failure.
+                return false;
+            }
+        }
+
+        // up to last '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = (String)patDirs.elementAt(patIdxEnd);
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir,(String)strDirs.elementAt(strIdxEnd), isCaseSensitive)) {
+                return false;
+            }
+            patIdxEnd--;
+            strIdxEnd--;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (!patDirs.elementAt(i).equals("**")) {
+                    return false;
+                }
+            }
+            return isSelected(str, selectorList);
+        }
+
+        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+            int patIdxTmp = -1;
+            for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
+                if (patDirs.elementAt(i).equals("**")) {
+                    patIdxTmp = i;
+                    break;
+                }
+            }
+            if (patIdxTmp == patIdxStart+1) {
+                // '**/**' situation, so skip one
+                patIdxStart++;
+                continue;
+            }
+            // Find the pattern between padIdxStart & padIdxTmp in str between
+            // strIdxStart & strIdxEnd
+            int patLength = (patIdxTmp-patIdxStart-1);
+            int strLength = (strIdxEnd-strIdxStart+1);
+            int foundIdx  = -1;
+strLoop:
+            for (int i = 0; i <= strLength - patLength; i++) {
+                for (int j = 0; j < patLength; j++) {
+                    String subPat = (String)patDirs.elementAt(patIdxStart+j+1);
+                    String subStr = (String)strDirs.elementAt(strIdxStart+i+j);
+                    if (!match(subPat,subStr, isCaseSensitive)) {
+                        continue strLoop;
+                    }
+                }
+
+                foundIdx = strIdxStart+i;
+                break;
+            }
+
+            if (foundIdx == -1) {
+                return false;
+            }
+
+            patIdxStart = patIdxTmp;
+            strIdxStart = foundIdx+patLength;
+        }
+
+        for (int i = patIdxStart; i <= patIdxEnd; i++) {
+            if (!patDirs.elementAt(i).equals("**")) {
+                return false;
+            }
+        }
+
+        return isSelected(str, selectorList);
+    }
+
+
+    /**
+     * Matches a string against a pattern. The pattern contains two special
+     * characters:
+     * '*' which means zero or more characters,
+     * '?' which means one and only one character.
+     *
+     * @param pattern the (non-null) pattern to match against
+     * @param str     the (non-null) string that must be matched against the
+     *                pattern
+     *
+     * @return <code>true</code> when the string matches against the pattern,
+     *         <code>false</code> otherwise.
+     */
+    public static boolean match(String pattern, String str) {
+        return match(pattern, str, true);
+    }
+
+
+    /**
+     * Matches a string against a pattern. The pattern contains two special
+     * characters:
+     * '*' which means zero or more characters,
+     * '?' which means one and only one character.
+     *
+     * @param pattern the (non-null) pattern to match against
+     * @param str     the (non-null) string that must be matched against the
+     *                pattern
+     *
+     * @return <code>true</code> when the string matches against the pattern,
+     *         <code>false</code> otherwise.
+     */
+    protected static boolean match(String pattern, String str, boolean isCaseSensitive) {
+        char[] patArr = pattern.toCharArray();
+        char[] strArr = str.toCharArray();
+        int patIdxStart = 0;
+        int patIdxEnd   = patArr.length-1;
+        int strIdxStart = 0;
+        int strIdxEnd   = strArr.length-1;
+        char ch;
+
+        boolean containsStar = false;
+        for (int i = 0; i < patArr.length; i++) {
+            if (patArr[i] == '*') {
+                containsStar = true;
+                break;
+            }
+        }
+
+        if (!containsStar) {
+            // No '*'s, so we make a shortcut
+            if (patIdxEnd != strIdxEnd) {
+                return false; // Pattern and string do not have the same size
+            }
+            for (int i = 0; i <= patIdxEnd; i++) {
+                ch = patArr[i];
+                if (ch != '?') {
+                    if (isCaseSensitive && ch != strArr[i]) {
+                        return false;// Character mismatch
+                    }
+                    if (!isCaseSensitive && Character.toUpperCase(ch) !=
+                        Character.toUpperCase(strArr[i])) {
+                        return false; // Character mismatch
+                    }
+                }
+            }
+            return true; // String matches against pattern
+        }
+
+        if (patIdxEnd == 0) {
+            return true; // Pattern contains only '*', which matches anything
+        }
+
+        // Process characters before first star
+        while((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
+            if (ch != '?') {
+                if (isCaseSensitive && ch != strArr[strIdxStart]) {
+                    return false;// Character mismatch
+                }
+                if (!isCaseSensitive && Character.toUpperCase(ch) !=
+                    Character.toUpperCase(strArr[strIdxStart])) {
+                    return false;// Character mismatch
+                }
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // All characters in the string are used. Check if only '*'s are
+            // left in the pattern. If so, we succeeded. Otherwise failure.
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (patArr[i] != '*') {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        // Process characters after last star
+        while((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
+            if (ch != '?') {
+                if (isCaseSensitive && ch != strArr[strIdxEnd]) {
+                    return false;// Character mismatch
+                }
+                if (!isCaseSensitive && Character.toUpperCase(ch) !=
+                    Character.toUpperCase(strArr[strIdxEnd])) {
+                    return false;// Character mismatch
+                }
+            }
+            patIdxEnd--;
+            strIdxEnd--;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // All characters in the string are used. Check if only '*'s are
+            // left in the pattern. If so, we succeeded. Otherwise failure.
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (patArr[i] != '*') {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        // process pattern between stars. padIdxStart and patIdxEnd point
+        // always to a '*'.
+        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+            int patIdxTmp = -1;
+            for (int i = patIdxStart+1; i <= patIdxEnd; i++) {
+                if (patArr[i] == '*') {
+                    patIdxTmp = i;
+                    break;
+                }
+            }
+            if (patIdxTmp == patIdxStart+1) {
+                // Two stars next to each other, skip the first one.
+                patIdxStart++;
+                continue;
+            }
+            // Find the pattern between padIdxStart & padIdxTmp in str between
+            // strIdxStart & strIdxEnd
+            int patLength = (patIdxTmp-patIdxStart-1);
+            int strLength = (strIdxEnd-strIdxStart+1);
+            int foundIdx  = -1;
+            strLoop:
+            for (int i = 0; i <= strLength - patLength; i++) {
+                for (int j = 0; j < patLength; j++) {
+                    ch = patArr[patIdxStart+j+1];
+                    if (ch != '?') {
+                        if (isCaseSensitive && ch != strArr[strIdxStart+i+j]) {
+                            continue strLoop;
+                        }
+                        if (!isCaseSensitive && Character.toUpperCase(ch) !=
+                            Character.toUpperCase(strArr[strIdxStart+i+j])) {
+                            continue strLoop;
+                        }
+                    }
+                }
+
+                foundIdx = strIdxStart+i;
+                break;
+            }
+
+            if (foundIdx == -1) {
+                return false;
+            }
+
+            patIdxStart = patIdxTmp;
+            strIdxStart = foundIdx+patLength;
+        }
+
+        // All characters in the string are used. Check if only '*'s are left
+        // in the pattern. If so, we succeeded. Otherwise failure.
+        for (int i = patIdxStart; i <= patIdxEnd; i++) {
+            if (patArr[i] != '*') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+
+    /**
+     * Sets the basedir for scanning. This is the directory that is scanned
+     * recursively. All '/' and '\' characters are replaced by
+     * <code>File.separatorChar</code>. So the separator used need not match
+     * <code>File.separatorChar</code>.
+     *
+     * @param basedir the (non-null) basedir for scanning
+     */
+    public void setBasedir(String basedir) {
+        setBasedir(new File(basedir.replace('/',File.separatorChar).replace('\\',File.separatorChar)));
+    }
+
+
+
+    /**
+     * Sets the basedir for scanning. This is the directory that is scanned
+     * recursively.
+     *
+     * @param basedir the basedir for scanning
+     */
+    public void setBasedir(File basedir) {
+        this.basedir = basedir;
+    }
+
+
+
+    /**
+     * Gets the basedir that is used for scanning. This is the directory that
+     * is scanned recursively.
+     *
+     * @return the basedir that is used for scanning
+     */
+    public File getBasedir() {
+        return basedir;
+    }
+
+
+
+    /**
+     * Sets the case sensitivity of the file system
+     *
+     * @param specifies if the filesystem is case sensitive
+     */
+    public void setCaseSensitive(boolean isCaseSensitive) {
+        this.isCaseSensitive = isCaseSensitive;
+    }
+
+    /**
+     * Sets the set of include patterns to use. All '/' and '\' characters are
+     * replaced by <code>File.separatorChar</code>. So the separator used need
+     * not match <code>File.separatorChar</code>.
+     * <p>
+     * When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @param includes list of include patterns
+     */
+    public void setIncludes(String[] includes) {
+        if (includes == null) {
+            this.includes = null;
+        } else {
+            Pattern[] p = new Pattern[includes.length];
+            for (int i = 0; i < includes.length; i++) {
+                p[i] = new Pattern();
+                p[i].setPattern(includes[i]);
+            }
+            setIncludes(p);
+        }
+    }
+
+    public void setIncludes(Pattern[] includes) {
+        if (includes == null) {
+            this.includes = null;
+        } else {
+            this.includes = new Pattern[includes.length];
+            for (int i = 0; i < includes.length; i++) {
+                String pattern;
+                pattern = includes[i].getPattern().replace('/',File.separatorChar).replace('\\',File.separatorChar);
+                if (pattern.endsWith(File.separator)) {
+                    pattern += "**";
+                }
+                this.includes[i] = new Pattern();
+                this.includes[i].setPattern(pattern);
+                this.includes[i].setSelectorList(includes[i].getSelectorList());
+            }
+        }
+    }
+
+    /**
+     * Sets the set of exclude patterns to use. All '/' and '\' characters are
+     * replaced by <code>File.separatorChar</code>. So the separator used need
+     * not match <code>File.separatorChar</code>.
+     * <p>
+     * When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @param excludes list of exclude patterns
+     */
+    public void setExcludes(String[] excludes) {
+        if (excludes == null) {
+            this.excludes = null;
+        } else {
+            Pattern[] p = new Pattern[excludes.length];
+            for (int i = 0; i < excludes.length; i++) {
+                p[i] = new Pattern();
+                p[i].setPattern(excludes[i]);
+            }
+            setExcludes(p);
+        }
+    }
+
+    public void setExcludes(Pattern[] excludes) {
+        if (excludes == null) {
+            this.excludes = null;
+        } else {
+            this.excludes = new Pattern[excludes.length];
+            for (int i = 0; i < excludes.length; i++) {
+                String pattern;
+                pattern = excludes[i].getPattern().replace('/',File.separatorChar).replace('\\',File.separatorChar);
+                if (pattern.endsWith(File.separator)) {
+                    pattern += "**";
+                }
+                this.excludes[i] = new Pattern();
+                this.excludes[i].setPattern(pattern);
+                this.excludes[i].setSelectorList(excludes[i].getSelectorList());
+            }
+        }
+    }
+
+    /**
+     * Has the scanner excluded or omitted any files or directories it
+     * came accross?
+     *
+     * @return true if all files and directories that have been found,
+     * are included.
+     */
+    public boolean isEverythingIncluded() {
+        return everythingIncluded;
+    }
+
+
+    /**
+     * Scans the base directory for files that match at least one include
+     * pattern, and don't match any exclude patterns.
+     *
+     * @exception IllegalStateException when basedir was set incorrecly
+     */
+    public void scan() {
+        if (basedir == null) {
+            throw new IllegalStateException("No basedir set");
+        }
+        if (!basedir.exists()) {
+            throw new IllegalStateException("basedir " + basedir
+                                            + " does not exist");
+        }
+        if (!basedir.isDirectory()) {
+            throw new IllegalStateException("basedir " + basedir
+                                            + " is not a directory");
+        }
+
+        if (includes == null) {
+            // No includes supplied, so set it to 'matches all'
+            includes = new Pattern[1];
+            includes[0] = new Pattern();
+            includes[0].setPattern("**");
+        }
+        if (excludes == null) {
+            excludes = new Pattern[0];
+        }
+
+        filesIncluded    = new Vector();
+        filesNotIncluded = new Vector();
+        filesExcluded    = new Vector();
+        dirsIncluded     = new Vector();
+        dirsNotIncluded  = new Vector();
+        dirsExcluded     = new Vector();
+
+        if (isIncluded("")) {
+            if (!isExcluded("")) {
+                dirsIncluded.addElement("");
+            } else {
+                dirsExcluded.addElement("");
+            }
+        } else {
+            dirsNotIncluded.addElement("");
+        }
+        scandir(basedir, "", true);
+    }
+
+    /**
+     * Toplevel invocation for the scan.
+     *
+     * <p>Returns immediately if a slow scan has already been requested.
+     */
+    protected void slowScan() {
+        if (haveSlowResults) {
+            return;
+        }
+
+        String[] excl = new String[dirsExcluded.size()];
+        dirsExcluded.copyInto(excl);
+
+        String[] notIncl = new String[dirsNotIncluded.size()];
+        dirsNotIncluded.copyInto(notIncl);
+
+        for (int i=0; i<excl.length; i++) {
+            if (!couldHoldIncluded(excl[i])) {
+                scandir(new File(basedir, excl[i]),
+                        excl[i]+File.separator, false);
+            }
+        }
+
+        for (int i=0; i<notIncl.length; i++) {
+            if (!couldHoldIncluded(notIncl[i])) {
+                scandir(new File(basedir, notIncl[i]),
+                        notIncl[i]+File.separator, false);
+            }
+        }
+
+        haveSlowResults  = true;
+    }
+
+
+    /**
+     * Scans the passed dir for files and directories. Found files and
+     * directories are placed in their respective collections, based on the
+     * matching of includes and excludes. When a directory is found, it is
+     * scanned recursively.
+     *
+     * @param dir   the directory to scan
+     * @param vpath the path relative to the basedir (needed to prevent
+     *              problems with an absolute path when using dir)
+     *
+     * @see #filesIncluded
+     * @see #filesNotIncluded
+     * @see #filesExcluded
+     * @see #dirsIncluded
+     * @see #dirsNotIncluded
+     * @see #dirsExcluded
+     */
+    protected void scandir(File dir, String vpath, boolean fast) {
+        String[] newfiles = dir.list();
+
+        if (newfiles == null) {
+            /*
+             * two reasons are mentioned in the API docs for File.list
+             * (1) dir is not a directory. This is impossible as
+             *     we wouldn't get here in this case.
+             * (2) an IO error occurred (why doesn't it throw an exception
+             *     then???)
+             */
+            throw new BuildException("IO error scanning directory "
+                                     + dir.getAbsolutePath());
+        }
+
+        for (int i = 0; i < newfiles.length; i++) {
+            String name = vpath+newfiles[i];
+            File   file = new File(dir,newfiles[i]);
+            if (file.isDirectory()) {
+                if (isIncluded(name)) {
+                    if (!isExcluded(name)) {
+                        dirsIncluded.addElement(name);
+                        if (fast) {
+                            scandir(file, name+File.separator, fast);
+                        }
+                    } else {
+                        everythingIncluded = false;
+                        dirsExcluded.addElement(name);
+                        if (fast && couldHoldIncluded(name)) {
+                            scandir(file, name+File.separator, fast);
+                        }
+                    }
+                } else {
+                    everythingIncluded = false;
+                    dirsNotIncluded.addElement(name);
+                    if (fast && couldHoldIncluded(name)) {
+                        scandir(file, name+File.separator, fast);
+                    }
+                }
+                if (!fast) {
+                    scandir(file, name+File.separator, fast);
+                }
+            } else if (file.isFile()) {
+                if (isIncluded(name)) {
+                    if (!isExcluded(name)) {
+                        filesIncluded.addElement(name);
+                    } else {
+                        everythingIncluded = false;
+                        filesExcluded.addElement(name);
+                    }
+                } else {
+                    everythingIncluded = false;
+                    filesNotIncluded.addElement(name);
+                }
+            }
+        }
+    }
+
+
+
+    /**
+     * Tests whether a name matches against at least one include pattern.
+     *
+     * @param name the name to match
+     * @return <code>true</code> when the name matches against at least one
+     *         include pattern, <code>false</code> otherwise.
+     */
+    protected boolean isIncluded(String name) {
+        for (int i = 0; i < includes.length; i++) {
+            if (matchPath(includes[i].getPattern(),
+                          includes[i].getSelectorList(),
+                          name, isCaseSensitive)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests whether a name matches the start of at least one include pattern.
+     *
+     * @param name the name to match
+     * @return <code>true</code> when the name matches against at least one
+     *         include pattern, <code>false</code> otherwise.
+     */
+    protected boolean couldHoldIncluded(String name) {
+        for (int i = 0; i < includes.length; i++) {
+            if (matchPatternStart(includes[i].getPattern(),name, isCaseSensitive)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests whether a name matches against at least one exclude pattern.
+     *
+     * @param name the name to match
+     * @return <code>true</code> when the name matches against at least one
+     *         exclude pattern, <code>false</code> otherwise.
+     */
+    protected boolean isExcluded(String name) {
+        for (int i = 0; i < excludes.length; i++) {
+            if (matchPath(excludes[i].getPattern(),
+                          excludes[i].getSelectorList(),
+                          name, isCaseSensitive)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Get the names of the files that matched at least one of the include
+     * patterns, and matched none of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    public String[] getIncludedFiles() {
+        int count = filesIncluded.size();
+        String[] files = new String[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = (String)filesIncluded.elementAt(i);
+        }
+        return files;
+    }
+
+
+
+    /**
+     * Get the names of the files that matched at none of the include patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    public String[] getNotIncludedFiles() {
+        slowScan();
+        int count = filesNotIncluded.size();
+        String[] files = new String[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = (String)filesNotIncluded.elementAt(i);
+        }
+        return files;
+    }
+
+
+
+    /**
+     * Get the names of the files that matched at least one of the include
+     * patterns, an matched also at least one of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    public String[] getExcludedFiles() {
+        slowScan();
+        int count = filesExcluded.size();
+        String[] files = new String[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = (String)filesExcluded.elementAt(i);
+        }
+        return files;
+    }
+
+
+
+    /**
+     * Get the names of the directories that matched at least one of the include
+     * patterns, an matched none of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    public String[] getIncludedDirectories() {
+        int count = dirsIncluded.size();
+        String[] directories = new String[count];
+        for (int i = 0; i < count; i++) {
+            directories[i] = (String)dirsIncluded.elementAt(i);
+        }
+        return directories;
+    }
+
+
+
+    /**
+     * Get the names of the directories that matched at none of the include
+     * patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    public String[] getNotIncludedDirectories() {
+        slowScan();
+        int count = dirsNotIncluded.size();
+        String[] directories = new String[count];
+        for (int i = 0; i < count; i++) {
+            directories[i] = (String)dirsNotIncluded.elementAt(i);
+        }
+        return directories;
+    }
+
+
+
+    /**
+     * Get the names of the directories that matched at least one of the include
+     * patterns, an matched also at least one of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    public String[] getExcludedDirectories() {
+        slowScan();
+        int count = dirsExcluded.size();
+        String[] directories = new String[count];
+        for (int i = 0; i < count; i++) {
+            directories[i] = (String)dirsExcluded.elementAt(i);
+        }
+        return directories;
+    }
+
+
+
+    /**
+     * Adds the array with default exclusions to the current exclusions set.
+     *
+     */
+    public void addDefaultExcludes() {
+        int excludesLength = excludes == null ? 0 : excludes.length;
+        Pattern[] newExcludes;
+        newExcludes = new Pattern[excludesLength + DEFAULTEXCLUDES.length];
+        if (excludesLength > 0) {
+            System.arraycopy(excludes,0,newExcludes,0,excludesLength);
+        }
+        for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
+            newExcludes[i+excludesLength] = new Pattern();
+            newExcludes[i+excludesLength].setPattern(DEFAULTEXCLUDES[i].replace('/',File.separatorChar).replace('\\',File.separatorChar));
+        }
+
+        Pattern[] ep = new Pattern[newExcludes.length];
+        for (int i = 0; i < ep.length; i++) {
+            ep[i] = new Pattern();
+            ep[i].setPattern(newExcludes[i].getPattern());
+        }
+
+        excludes = ep;
+    }
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/FileScanner.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/FileScanner.java
new file mode 100644
index 0000000..a971a8c
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/FileScanner.java
@@ -0,0 +1,175 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+package org.apache.tools.ant;
+
+import java.io.File;
+import org.apache.tools.ant.types.Pattern;
+
+/**
+ * An interface used to describe the actions required by any type of
+ * directory scanner.
+ */
+public interface FileScanner {
+    /**
+     * Adds an array with default exclusions to the current exclusions set.
+     *
+     */
+    void addDefaultExcludes();
+    /**
+     * Gets the basedir that is used for scanning. This is the directory that
+     * is scanned recursively.
+     *
+     * @return the basedir that is used for scanning
+     */
+    File getBasedir();
+    /**
+     * Get the names of the directories that matched at least one of the include
+     * patterns, an matched also at least one of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    String[] getExcludedDirectories();
+    /**
+     * Get the names of the files that matched at least one of the include
+     * patterns, an matched also at least one of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    String[] getExcludedFiles();
+    /**
+     * Get the names of the directories that matched at least one of the include
+     * patterns, an matched none of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    String[] getIncludedDirectories();
+    /**
+     * Get the names of the files that matched at least one of the include
+     * patterns, an matched none of the exclude patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    String[] getIncludedFiles();
+    /**
+     * Get the names of the directories that matched at none of the include
+     * patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the directories
+     */
+    String[] getNotIncludedDirectories();
+    /**
+     * Get the names of the files that matched at none of the include patterns.
+     * The names are relative to the basedir.
+     *
+     * @return the names of the files
+     */
+    String[] getNotIncludedFiles();
+    /**
+     * Scans the base directory for files that match at least one include
+     * pattern, and don't match any exclude patterns.
+     *
+     * @exception IllegalStateException when basedir was set incorrecly
+     */
+    void scan();
+    /**
+     * Sets the basedir for scanning. This is the directory that is scanned
+     * recursively.
+     *
+     * @param basedir the (non-null) basedir for scanning
+     */
+    void setBasedir(String basedir);
+    /**
+     * Sets the basedir for scanning. This is the directory that is scanned
+     * recursively.
+     *
+     * @param basedir the basedir for scanning
+     */
+    void setBasedir(File basedir);
+    /**
+     * Sets the set of exclude patterns to use.
+     *
+     * @param excludes list of exclude patterns
+     */
+    void setExcludes(String[] excludes);
+    /**
+     * Sets the set of include patterns to use.
+     *
+     * @param includes list of include patterns
+     */
+    void setIncludes(String[] includes);
+    /**
+     * Sets the set of exclude patterns to use.
+     *
+     * @param excludes list of exclude patterns
+     */
+    void setExcludes(Pattern[] excludes);
+    /**
+     * Sets the set of include patterns to use.
+     *
+     * @param includes list of include patterns
+     */
+    void setIncludes(Pattern[] includes);
+
+    /**
+     * Sets the case sensitivity of the file system
+     *
+     * @param specifies if the filesystem is case sensitive
+     */
+    void setCaseSensitive(boolean isCaseSensitive);
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileSelector.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileSelector.java
new file mode 100644
index 0000000..bd2c567
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileSelector.java
@@ -0,0 +1,66 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.selectors;
+
+import java.io.File;
+
+/**
+ * File Selector API.
+ *
+ */
+public interface FileSelector {
+    public void setValue(final String value);
+    public void setOperation(final String operation);
+    public boolean isSelected(final String file);
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileTypeSelector.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileTypeSelector.java
new file mode 100644
index 0000000..bf12d41
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/FileTypeSelector.java
@@ -0,0 +1,127 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+ package org.apache.tools.ant.selectors;
+
+import java.io.File;
+
+/**
+ * File selector that performs selection based on
+ * file type - file and directory.
+ *
+ */
+public class FileTypeSelector implements FileSelector {
+    private String value = null;
+    private String operation = "equals";
+    private boolean cached = false;
+    private boolean negate = false;
+    private boolean checkForFile = false;
+    private boolean checkForDir = false;
+
+    public void setCached(final boolean cached) {
+        this.cached = cached;
+    }
+
+    public boolean isCached() {
+        return cached;
+    }
+
+    public void setValue(final String value) {
+        this.value = value;
+        setCached(false);
+    }
+
+    public void setOperation(final String operation) {
+        this.operation = operation;
+        setCached(false);
+    }
+
+    public void doCache() {
+        if (!isCached()) {
+            if (value == null) {
+                throw new NullPointerException("value must not be null.");
+            }
+            if (value.equalsIgnoreCase("file")) {
+                checkForFile = true;
+                checkForDir = false;
+            } else if (value.equalsIgnoreCase("directory")) {
+                checkForDir = true;
+                checkForFile = false;
+            }
+            if (!operation.equalsIgnoreCase("equals")) {
+                negate = true;
+            } else {
+                negate = false;
+            }
+            setCached(true);
+        }
+    }
+
+    public boolean isSelected(final String file) {
+        doCache();
+        if (file == null) {
+            throw new NullPointerException("file must not be null.");
+        }
+        boolean retValue = false;
+        File f = new File(file);
+        if (checkForFile) {
+            retValue = f.isFile();
+        } else if (checkForDir) {
+            retValue = f.isDirectory();
+        }
+        if (negate) {
+            retValue = !retValue;
+        }
+        return retValue;
+    }
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/defaults.properties b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/defaults.properties
new file mode 100644
index 0000000..4887f11
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/selectors/defaults.properties
@@ -0,0 +1 @@
+type=org.apache.tools.ant.selectors.FileTypeSelector
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/FileSet.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/FileSet.java
new file mode 100644
index 0000000..2c1e407
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/FileSet.java
@@ -0,0 +1,335 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.FileScanner;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+
+import java.io.File;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * Moved out of MatchingTask to make it a standalone object that could
+ * be referenced (by scripts for example).
+ *
+ */
+public class FileSet extends DataType implements Cloneable {
+
+    private PatternSet defaultPatterns = new PatternSet();
+    private Vector additionalPatterns = new Vector();
+
+    private File dir;
+    private boolean useDefaultExcludes = true;
+    private boolean isCaseSensitive = true;
+
+    public FileSet() {
+        super();
+    }
+
+    protected FileSet(FileSet fileset) {
+        this.dir = fileset.dir;
+        this.defaultPatterns = fileset.defaultPatterns;
+        this.additionalPatterns = fileset.additionalPatterns;
+        this.useDefaultExcludes = fileset.useDefaultExcludes;
+        this.isCaseSensitive = fileset.isCaseSensitive;
+        setProject(getProject());
+    }
+
+
+
+    /**
+     * Makes this instance in effect a reference to another PatternSet
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (dir != null || defaultPatterns.hasPatterns()) {
+            throw tooManyAttributes();
+        }
+        if (!additionalPatterns.isEmpty()) {
+            throw noChildrenAllowed();
+        }
+        super.setRefid(r);
+    }
+
+    public void setDir(File dir) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+
+        this.dir = dir;
+    }
+
+    public File getDir(Project p) {
+        if (isReference()) {
+            return getRef(p).getDir(p);
+        }
+        return dir;
+    }
+
+    public PatternSet createPatternSet() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        PatternSet patterns = new PatternSet();
+        additionalPatterns.addElement(patterns);
+        return patterns;
+    }
+
+    /**
+     * add a name entry on the include list
+     */
+    public PatternSet.NameEntry createInclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return defaultPatterns.createInclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     */
+    public PatternSet.NameEntry createIncludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return defaultPatterns.createIncludesFile();
+    }
+
+    /**
+     * add a name entry on the exclude list
+     */
+    public PatternSet.NameEntry createExclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return defaultPatterns.createExclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     */
+    public PatternSet.NameEntry createExcludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return defaultPatterns.createExcludesFile();
+    }
+
+    /**
+     * Sets the set of include patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param includes the string containing the include patterns
+     */
+    public void setIncludes(String includes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+
+        defaultPatterns.setIncludes(includes);
+    }
+
+    /**
+     * Sets the set of exclude patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param excludes the string containing the exclude patterns
+     */
+    public void setExcludes(String excludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+
+        defaultPatterns.setExcludes(excludes);
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param incl The file to fetch the include patterns from.
+     */
+     public void setIncludesfile(File incl) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+
+         defaultPatterns.setIncludesfile(incl);
+     }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param excl The file to fetch the exclude patterns from.
+     */
+     public void setExcludesfile(File excl) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+
+         defaultPatterns.setExcludesfile(excl);
+     }
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+     *                           should be used, "false"|"off"|"no" when they
+     *                           shouldn't be used.
+     */
+    public void setDefaultexcludes(boolean useDefaultExcludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+
+        this.useDefaultExcludes = useDefaultExcludes;
+    }
+
+    /**
+     * Sets case sensitivity of the file system
+     *
+     * @param isCaseSensitive "true"|"on"|"yes" if file system is case
+     *                           sensitive, "false"|"off"|"no" when not.
+     */
+    public void setCaseSensitive(boolean isCaseSensitive) {
+        this.isCaseSensitive = isCaseSensitive;
+    }
+
+    /**
+     * Returns the directory scanner needed to access the files to process.
+     */
+    public DirectoryScanner getDirectoryScanner(Project p) {
+        if (isReference()) {
+            return getRef(p).getDirectoryScanner(p);
+        }
+
+        if (dir == null) {
+            throw new BuildException("No directory specified for fileset.");
+        }
+
+        if (!dir.exists()) {
+            throw new BuildException(dir.getAbsolutePath()+" not found.");
+        }
+        if (!dir.isDirectory()) {
+            throw new BuildException(dir.getAbsolutePath()+" is not a directory.");
+        }
+
+        DirectoryScanner ds = new DirectoryScanner();
+        setupDirectoryScanner(ds, p);
+        ds.scan();
+        return ds;
+    }
+
+    public void setupDirectoryScanner(FileScanner ds, Project p) {
+        if (ds == null) {
+            throw new IllegalArgumentException("ds cannot be null");
+        }
+
+        ds.setBasedir(dir);
+
+        for (int i=0; i<additionalPatterns.size(); i++) {
+            Object o = additionalPatterns.elementAt(i);
+            defaultPatterns.append2((PatternSet) o, p);
+        }
+
+        p.log( "FileSet: Setup file scanner in dir " + dir +
+            " with " + defaultPatterns, p.MSG_DEBUG );
+
+        ds.setIncludes(defaultPatterns.getIncludePatterns2(p));
+        ds.setExcludes(defaultPatterns.getExcludePatterns2(p));
+        if (useDefaultExcludes) {
+          ds.addDefaultExcludes();
+        }
+        ds.setCaseSensitive(isCaseSensitive);
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced FileSet.
+     */
+    protected FileSet getRef(Project p) {
+        if (!checked) {
+            Stack stk = new Stack();
+            stk.push(this);
+            dieOnCircularReference(stk, p);
+        }
+
+        Object o = ref.getReferencedObject(p);
+        if (!(o instanceof FileSet)) {
+            String msg = ref.getRefId()+" doesn\'t denote a fileset";
+            throw new BuildException(msg);
+        } else {
+            return (FileSet) o;
+        }
+    }
+
+    /**
+     * Return a FileSet that has the same basedir and same patternsets
+     * as this one.
+     */
+    public Object clone() {
+        if (isReference()) {
+            return new FileSet(getRef(getProject()));
+        } else {
+            return new FileSet(this);
+        }
+    }
+
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/Pattern.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/Pattern.java
new file mode 100644
index 0000000..7f273e2
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/Pattern.java
@@ -0,0 +1,103 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+ package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.BuildException;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Named collection of include/exclude tags.
+ *
+ */
+public class Pattern {
+    private String pattern = null;
+    private Vector selectorList = null;
+
+    /**
+     * Set the pattern
+     * @param pattern    the pattern to match
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * Set the list of Selector entries
+     * @param selectorList    the vector list of 'SelectorEntry's
+     */
+    public void setSelectorList(Vector selectorList) {
+        this.selectorList = selectorList;
+    }
+
+    /**
+     * Get the pattern
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Get the list of Selector entries
+     */
+    public Vector getSelectorList() {
+        return selectorList;
+    }
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/PatternSet.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/PatternSet.java
new file mode 100644
index 0000000..ad5fb02
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/PatternSet.java
@@ -0,0 +1,587 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000-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/>.
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.BuildException;
+
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Named collection of include/exclude tags.
+ *
+ * <p>Moved out of MatchingTask to make it a standalone object that
+ * could be referenced (by scripts for example).
+ *
+ */
+public class PatternSet extends DataType {
+    private Vector includeList = new Vector();
+    private Vector excludeList = new Vector();
+    private Vector includesFileList = new Vector();
+    private Vector excludesFileList = new Vector();
+
+
+     /**
+     * inner class to hold a selector list.  A SelectorEntry
+     * is made up of the pattern and selection detail.
+     */
+    public static class SelectorEntry {
+        private String type;
+        private String value;
+        private String operation;
+
+        public void setType(String t) {
+            this.type = t;
+        }
+
+        public void setValue(String val) {
+            this.value = val;
+        }
+
+        public void setOperation(String op) {
+            this.operation = op;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public String getValue() {
+            return value;
+        }
+
+        public String getOperation() {
+            return operation;
+        }
+    }
+
+    /**
+     * inner class to hold a name on list.  "If" and "Unless" attributes
+     * may be used to invalidate the entry based on the existence of a
+     * property (typically set thru the use of the Available task).
+     */
+    public class NameEntry {
+        private String name;
+        private String ifCond;
+        private String unlessCond;
+        private Vector selectorList = new Vector();
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public void setIf(String cond) {
+            ifCond = cond;
+        }
+
+        public void setUnless(String cond) {
+            unlessCond = cond;
+        }
+
+        /**
+         * Include/Exclude can contain nested selectors
+         */
+        public SelectorEntry createSelector() {
+            if (isReference()) {
+                throw noChildrenAllowed();
+            }
+            return addSelectorToList(selectorList);
+        }
+
+        /**
+         * add a selector entry to the given list
+         */
+        private SelectorEntry addSelectorToList(final Vector list) {
+            final SelectorEntry result = new SelectorEntry();
+            list.addElement(result);
+            return result;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Vector getSelectorList() {
+            return selectorList;
+        }
+
+        public String evalName(Project p) {
+            return valid(p) ? name : null;
+        }
+
+        private boolean valid(Project p) {
+            if (ifCond != null && p.getProperty(ifCond) == null) {
+                return false;
+            } else if (unlessCond != null && p.getProperty(unlessCond) != null) {
+                return false;
+            }
+            return true;
+        }
+
+        public String toString() {
+            StringBuffer buf = new StringBuffer(name);
+            if ((ifCond != null) || (unlessCond != null)) {
+                buf.append(":");
+                String connector = "";
+
+                if (ifCond != null) {
+                    buf.append("if->");
+                    buf.append(ifCond);
+                    connector = ";";
+                }
+                if (unlessCond != null) {
+                    buf.append(connector);
+                    buf.append("unless->");
+                    buf.append(unlessCond);
+                }
+            }
+
+            return buf.toString();
+        }
+
+        public void setSelectorList(Vector list) {
+            this.selectorList = list;
+        }
+    }
+
+    public PatternSet() {
+        super();
+    }
+
+    /**
+     * Makes this instance in effect a reference to another PatternSet
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (!includeList.isEmpty() || !excludeList.isEmpty()) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * add a name entry on the include list
+     */
+    public NameEntry createInclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(includeList);
+    }
+
+    /**
+     * add a name entry on the include files list
+     */
+    public NameEntry createIncludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(includesFileList);
+    }
+
+    /**
+     * add a name entry on the exclude list
+     */
+    public NameEntry createExclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(excludeList);
+    }
+
+    /**
+     * add a name entry on the exclude files list
+     */
+    public NameEntry createExcludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(excludesFileList);
+    }
+
+    /**
+     * Sets the set of include patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param includes the string containing the include patterns
+     */
+    public void setIncludes(String includes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (includes != null && includes.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(includes, ", ", false);
+            while (tok.hasMoreTokens()) {
+                createInclude().setName(tok.nextToken());
+            }
+        }
+    }
+
+    /**
+     * Sets the set of exclude patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param excludes the string containing the exclude patterns
+     */
+    public void setExcludes(String excludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (excludes != null && excludes.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(excludes, ", ", false);
+            while (tok.hasMoreTokens()) {
+                createExclude().setName(tok.nextToken());
+            }
+        }
+    }
+
+    /**
+     * add a name entry to the given list
+     */
+    private NameEntry addPatternToList(Vector list) {
+        NameEntry result = new NameEntry();
+        list.addElement(result);
+        return result;
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param includesFile The file to fetch the include patterns from.
+     */
+     public void setIncludesfile(File includesFile) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+         createIncludesFile().setName(includesFile.getAbsolutePath());
+     }
+
+    /**
+     * Sets the name of the file containing the excludes patterns.
+     *
+     * @param excludesFile The file to fetch the exclude patterns from.
+     */
+     public void setExcludesfile(File excludesFile) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+         createExcludesFile().setName(excludesFile.getAbsolutePath());
+     }
+
+    /**
+     *  Reads path matching patterns from a file and adds them to the
+     *  includes or excludes list (as appropriate).
+     */
+    private void readPatterns(File patternfile, Vector patternlist, Project p)
+        throws BuildException {
+
+        BufferedReader patternReader = null;
+        try {
+            // Get a FileReader
+            patternReader =
+                new BufferedReader(new FileReader(patternfile));
+
+            // Create one NameEntry in the appropriate pattern list for each
+            // line in the file.
+            String line = patternReader.readLine();
+            while (line != null) {
+                if (line.length() > 0) {
+                    line = p.replaceProperties(line);
+                    addPatternToList(patternlist).setName(line);
+                }
+                line = patternReader.readLine();
+            }
+        } catch(IOException ioe)  {
+            String msg = "An error occured while reading from pattern file: "
+                + patternfile;
+            throw new BuildException(msg, ioe);
+        } finally {
+            if( null != patternReader ) {
+                try {
+                    patternReader.close();
+                } catch(IOException ioe) {
+                    //Ignore exception
+                }
+            }
+        }
+    }
+
+    public void append2(PatternSet other, Project p) {
+         if (isReference()) {
+             throw new BuildException("Cannot append to a reference");
+         }
+        Pattern[] incl = other.getIncludePatterns2(p);
+        if (incl != null) {
+            for (int i=0; i<incl.length; i++) {
+                NameEntry ne = createInclude();
+                ne.setName(incl[i].getPattern());
+                ne.setSelectorList(incl[i].getSelectorList());
+            }
+        }
+
+        Pattern[] excl = other.getExcludePatterns2(p);
+        if (excl != null) {
+            for (int i=0; i<excl.length; i++) {
+                NameEntry ne = createExclude();
+                ne.setName(excl[i].getPattern());
+                ne.setSelectorList(incl[i].getSelectorList());
+            }
+        }
+    }
+
+    /**
+     * Adds the patterns of the other instance to this set.
+     */
+    public void append(PatternSet other, Project p) {
+        if (isReference()) {
+            throw new BuildException("Cannot append to a reference");
+        }
+
+        String[] incl = other.getIncludePatterns(p);
+        if (incl != null) {
+            for (int i=0; i<incl.length; i++) {
+                createInclude().setName(incl[i]);
+            }
+        }
+
+        String[] excl = other.getExcludePatterns(p);
+        if (excl != null) {
+            for (int i=0; i<excl.length; i++) {
+                createExclude().setName(excl[i]);
+            }
+        }
+    }
+
+    /**
+     * Returns the filtered include patterns as an array of Patterns
+     */
+    public Pattern[] getIncludePatterns2(Project p) {
+        if (isReference()) {
+            return getRef(p).getIncludePatterns2(p);
+        } else {
+            readFiles(p);
+            return makeArray2(includeList, p);
+        }
+    }
+
+    /**
+     * Returns the filtered exclude patterns as an array of Patterns
+     */
+    public Pattern[] getExcludePatterns2(Project p) {
+        if (isReference()) {
+            return getRef(p).getExcludePatterns2(p);
+        } else {
+            readFiles(p);
+            return makeArray2(excludeList, p);
+        }
+    }
+
+    /**
+     * Returns the filtered include patterns.
+     */
+    public String[] getIncludePatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).getIncludePatterns(p);
+        } else {
+            readFiles(p);
+            return makeArray(includeList, p);
+        }
+    }
+
+    /**
+     * Returns the filtered include patterns.
+     */
+    public String[] getExcludePatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).getExcludePatterns(p);
+        } else {
+            readFiles(p);
+            return makeArray(excludeList, p);
+        }
+    }
+
+    /**
+     * helper for FileSet.
+     */
+    boolean hasPatterns() {
+        return includesFileList.size() > 0 || excludesFileList.size() > 0
+            || includeList.size() > 0 || excludeList.size() > 0;
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced PatternSet.
+     */
+    private PatternSet getRef(Project p) {
+        if (!checked) {
+            Stack stk = new Stack();
+            stk.push(this);
+            dieOnCircularReference(stk, p);
+        }
+
+        Object o = ref.getReferencedObject(p);
+        if (!(o instanceof PatternSet)) {
+            String msg = ref.getRefId()+" doesn\'t denote a patternset";
+            throw new BuildException(msg);
+        } else {
+            return (PatternSet) o;
+        }
+    }
+
+
+     /**
+     * Convert a vector of NameEntry elements into an array of Patterns
+     */
+    private Pattern[] makeArray2(Vector list, Project p) {
+        if (list.size() == 0) return null;
+
+        Vector tmpPatterns = new Vector();
+        for (Enumeration e = list.elements() ; e.hasMoreElements() ;) {
+            NameEntry ne = (NameEntry)e.nextElement();
+            String pattern = ne.evalName(p);
+            if (pattern != null && pattern.length() > 0) {
+                Pattern pat = new Pattern();
+                pat.setPattern(pattern);
+                pat.setSelectorList(ne.getSelectorList());
+                tmpPatterns.addElement(pat);
+            }
+        }
+
+        Pattern result[] = new Pattern[tmpPatterns.size()];
+        tmpPatterns.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Convert a vector of NameEntry elements into an array of Strings.
+     */
+    private String[] makeArray(Vector list, Project p) {
+        if (list.size() == 0) {
+          return null;
+        }
+
+        Vector tmpNames = new Vector();
+        for (Enumeration e = list.elements() ; e.hasMoreElements() ;) {
+            NameEntry ne = (NameEntry)e.nextElement();
+            String pattern = ne.evalName(p);
+            if (pattern != null && pattern.length() > 0) {
+                tmpNames.addElement(pattern);
+            }
+        }
+
+        String result[] = new String[tmpNames.size()];
+        tmpNames.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Read includesfile ot excludesfile if not already done so.
+     */
+    private void readFiles(Project p) {
+        if (includesFileList.size() > 0) {
+            Enumeration e = includesFileList.elements();
+            while (e.hasMoreElements()) {
+                NameEntry ne = (NameEntry)e.nextElement();
+                String fileName = ne.evalName(p);
+                if (fileName != null) {
+                    File inclFile = p.resolveFile(fileName);
+                    if (!inclFile.exists()) {
+                        throw new BuildException("Includesfile "
+                                                 + inclFile.getAbsolutePath()
+                                                 + " not found.");
+                    }
+                    readPatterns(inclFile, includeList, p);
+                }
+            }
+            includesFileList.removeAllElements();
+        }
+
+        if (excludesFileList.size() > 0) {
+            Enumeration e = excludesFileList.elements();
+            while (e.hasMoreElements()) {
+                NameEntry ne = (NameEntry)e.nextElement();
+                String fileName = ne.evalName(p);
+                if (fileName != null) {
+                    File exclFile = p.resolveFile(fileName);
+                    if (!exclFile.exists()) {
+                        throw new BuildException("Excludesfile "
+                                                 + exclFile.getAbsolutePath()
+                                                 + " not found.");
+                    }
+                    readPatterns(exclFile, excludeList, p);
+                }
+            }
+            excludesFileList.removeAllElements();
+        }
+    }
+
+    public String toString()
+    {
+        return "patternSet{ includes: " + includeList +
+            " excludes: " + excludeList + " }";
+    }
+
+}
diff --git a/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/ZipScanner.java b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/ZipScanner.java
new file mode 100644
index 0000000..6511909
--- /dev/null
+++ b/trunk/proposal/sandbox/selectors/src/main/org/apache/tools/ant/types/ZipScanner.java
@@ -0,0 +1,139 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 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/>.
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.Pattern;
+import java.io.File;
+
+/**
+ * ZipScanner accesses the pattern matching algorithm in DirectoryScanner,
+ * which are protected methods that can only be accessed by subclassing.
+ *
+ * This implementation of FileScanner defines getIncludedFiles to return
+ * only the Zip File which is being scanned, not the matching Zip entries.
+ * Arguably, it should return the matching entries, however this would
+ * complicate existing code which assumes that FileScanners return a
+ * set of file system files that can be accessed directly.
+ *
+ */
+public class ZipScanner extends DirectoryScanner {
+
+    /**
+     * The zip file which should be scanned.
+     */
+    protected File srcFile;
+
+    /**
+     * Sets the srcFile for scanning. This is the jar or zip file that is scanned
+     * for matching entries.
+     *
+     * @param srcFile the (non-null) zip file name for scanning
+     */
+    public void setSrc(File srcFile) {
+        this.srcFile = srcFile;
+    }
+
+    /**
+     * Returns the zip file itself, not the matching entries within the zip file.
+     * This keeps the uptodate test in the Zip task simple; otherwise we'd need
+     * to treat zip filesets specially.
+     *
+     * @return the source file from which entries will be extracted.
+     */
+    public String[] getIncludedFiles() {
+        String[] result = new String[1];
+        result[0] = srcFile.getAbsolutePath();
+        return result;
+    }
+
+    /**
+     * Returns an empty list of directories to create.
+     */
+    public String[] getIncludedDirectories() {
+        return new String[0];
+    }
+
+    /**
+     * Initialize DirectoryScanner data structures.
+     */
+    public void init() {
+        if (includes == null) {
+            // No includes supplied, so set it to 'matches all'
+            includes = new Pattern[1];
+            includes[0] = new Pattern();
+            includes[0].setPattern("**");
+        }
+        if (excludes == null) {
+            excludes = new Pattern[0];
+        }
+    }
+
+    /**
+     * Matches a jar entry against the includes/excludes list,
+     * normalizing the path separator.
+     *
+     * @param path the (non-null) path name to test for inclusion
+     *
+     * @return <code>true</code> if the path should be included
+     *         <code>false</code> otherwise.
+     */
+    public boolean match(String path) {
+        String vpath = path.replace('/', File.separatorChar).
+            replace('\\', File.separatorChar);
+        return isIncluded(vpath) && !isExcluded(vpath);
+    }
+
+}
diff --git a/trunk/proposal/sandbox/svn/README b/trunk/proposal/sandbox/svn/README
new file mode 100644
index 0000000..b1076d2
--- /dev/null
+++ b/trunk/proposal/sandbox/svn/README
@@ -0,0 +1 @@
+Moved to http://svn.apache.org/repos/asf/ant/sandbox/antlibs/svn/trunk/
diff --git a/trunk/proposal/xdocs/build.xml b/trunk/proposal/xdocs/build.xml
new file mode 100644
index 0000000..77d286b
--- /dev/null
+++ b/trunk/proposal/xdocs/build.xml
@@ -0,0 +1,567 @@
+<?xml version="1.0" ?>
+<project name="xdocs" default="default">
+
+  <!--
+    Give user a chance to override without editing this file
+    (and without typing -D each time)
+  -->
+  <property file="${user.home}/.${ant.project.name}.properties"/>
+
+  <property name="src.root"
+            location="../../src/main"/>
+  <property name="docs.src"
+            location="../../xdocs"/>
+  <property name="xdocs.dir"
+            location="xdocs"/>
+            
+  <property name="build.dir" location="build"/>
+  <property name="antdoclet.src.dir" location="src"/>
+  <property name="gen.dir" location="${build.dir}/gen"/>
+  <property name="build.docs.dir" location="${build.dir}/docs"/>
+  <property name="ant.package" value="org/apache/tools/ant"/>
+  <property name="optional.package" value="${ant.package}/taskdefs/optional"/>
+  <property name="optional.type.package" value="${ant.package}/types/optional"/>
+  <property name="apache.resolver.type.package" value="${ant.package}/types/resolver"/>
+  <property name="util.package" value="${ant.package}/util"/>
+  <property name="regexp.package" value="${util.package}/regexp"/>
+
+  <path id="classpath">
+  </path>
+
+  <!-- depends on JDK version -->
+  <selector id="needs.jdk1.3+">
+    <or>
+      <filename name="${ant.package}/taskdefs/TestProcess*"/>
+      <filename name="${optional.package}/extension/**"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jdk1.4+">
+    <or>
+      <filename name="${regexp.package}/Jdk14Regexp*"/>
+    </or>
+  </selector>
+
+  <!-- classes that should be present in Sun based JVMs, but not in
+  Kaffe for example -->
+  <selector id="needs.sun.tools">
+    <or>
+      <filename name="${optional.package}/Native2Ascii*"/>
+      <filename name="${optional.package}/Javah*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.sun.uue">
+    <filename name="${ant.package}/taskdefs/email/UUMailer*"/>
+  </selector>
+
+  <selector id="needs.sun.b64">
+    <or>
+      <filename name="${optional.package}/splash/SplashTask*"/>
+    </or>
+  </selector>
+
+  <!-- depends on external libraries -->
+  <selector id="needs.trax">
+    <or>
+      <filename name="${optional.package}/TraXLiaison*"/>
+      <filename name="${optional.package}/sitraka/**"/>
+      <filename name="${optional.package}/metamata/MMetrics*"/>
+      <filename name="${optional.package}/XsltTest*"/>
+      <filename name="${ant.package}/types/XMLCatalogBuildFileTest*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.xalan1">
+    <or>
+      <filename name="${optional.package}/XalanLiaison*"/>
+      <filename name="${optional.package}/junit/Xalan1Executor*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.xalan2">
+    <filename name="${optional.package}/junit/Xalan2Executor*"/>
+  </selector>
+
+  <selector id="needs.xslp">
+    <filename name="${optional.package}/XslpLiaison*"/>
+  </selector>
+
+  <selector id="needs.apache.resolver">
+    <filename name="${apache.resolver.type.package}/**"/>
+  </selector>
+
+  <selector id="needs.junit">
+    <filename name="${optional.package}/junit/**"/>
+  </selector>
+
+  <selector id="needs.jakarta.regexp">
+    <filename name="${regexp.package}/JakartaRegexp*"/>
+  </selector>
+
+  <selector id="needs.jakarta.oro">
+    <or>
+      <filename name="${regexp.package}/JakartaOro*"/>
+      <filename name="${optional.package}/perforce/*"/>
+      <filename name="${optional.package}/metamata/MAudit*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jakarta.bcel">
+    <or>
+      <filename name="${ant.package}/filters/util/JavaClassHelper*"/>
+      <filename name="${util.package}/depend/bcel/*"/>
+      <filename name="${optional.type.package}/depend/ClassFileSetTest*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jakarta.log4j">
+    <filename name="${ant.package}/listener/Log4jListener*"/>
+  </selector>
+
+  <selector id="needs.commons.logging">
+    <filename name="${ant.package}/listener/CommonsLoggingListener*"/>
+  </selector>
+
+  <selector id="needs.bsf">
+    <or>
+      <filename name="${optional.package}/Script*"/>
+      <filename name="${optional.package}/script/**/*"/>
+      <filename name="${optional.type.package}/Script*"/>
+      <filename name="${util.package}/Script*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.stylebook">
+    <filename name="${optional.package}/StyleBook*"/>
+  </selector>
+
+  <selector id="needs.javamail">
+    <or>
+      <filename name="${ant.package}/taskdefs/email/MimeMailer*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.icontract">
+    <filename name="${optional.package}/IContract*"/>
+  </selector>
+
+  <selector id="needs.netrexx">
+    <filename name="${optional.package}/NetRexxC*"/>
+  </selector>
+
+  <selector id="needs.weblogic.ejbc">
+    <filename name="${optional.package}/ejb/Ejbc*"/>
+  </selector>
+
+  <selector id="needs.weblogic.ddcreator">
+    <filename name="${optional.package}/ejb/DDCreator*"/>
+  </selector>
+
+  <selector id="needs.weblogic.server">
+    <or>
+      <filename name="${optional.package}/ejb/WLRun*"/>
+      <filename name="${optional.package}/ejb/WLStop*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.commons.net">
+    <or>
+      <filename name="${optional.package}/net/FTP*"/>
+      <filename name="${optional.package}/net/RExec*"/>
+      <filename name="${optional.package}/net/TelnetTask*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.starteam">
+    <or>
+      <filename name="${optional.package}/scm/AntStarTeam*"/>
+      <filename name="${optional.package}/starteam/*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.vaj">
+    <filename name="${optional.package}/ide/VAJ*"/>
+  </selector>
+
+  <selector id="needs.antlr">
+    <filename name="${optional.package}/ANTLR*"/>
+  </selector>
+
+  <selector id="needs.jmf">
+    <filename name="${optional.package}/sound/*"/>
+  </selector>
+
+  <selector id="needs.jai">
+    <or>
+      <filename name="${optional.package}/image/*"/>
+      <filename name="${ant.package}/types/optional/image/*"/>
+    </or>
+  </selector>
+
+  <selector id="needs.jdepend">
+    <filename name="${optional.package}/jdepend/*"/>
+  </selector>
+
+  <selector id="needs.swing">
+    <filename name="${optional.package}/splash/*"/>
+  </selector>
+
+  <selector id="needs.jsch">
+    <filename name="${optional.package}/ssh/*"/>
+  </selector>
+
+  <available property="jdk1.3+" classname="java.lang.StrictMath"/>
+  <available property="jdk1.4+" classname="java.lang.CharSequence"/>
+  <available property="kaffe" classname="kaffe.util.NotImplemented"/>
+  <available property="bsf.present"
+    classname="org.apache.bsf.BSFManager"
+    classpathref="classpath"/>
+  <available property="netrexx.present"
+    classname="netrexx.lang.Rexx"
+    classpathref="classpath"/>
+  <available property="trax.present"
+    classname="javax.xml.transform.Transformer"
+    classpathref="classpath"/>
+  <condition property="trax.impl.present">
+    <or>
+      <and>
+        <isset property="javax.xml.transform.TransformerFactory"/>
+        <available classname="${javax.xml.transform.TransformerFactory}"
+          classpathref="classpath"/>
+      </and>
+      <available resource="META-INF/services/javax.xml.transform.TransformerFactory"/>
+    </or>
+  </condition>
+  <available property="xslp.present"
+    classname="com.kvisco.xsl.XSLProcessor"
+    classpathref="classpath"/>
+  <available property="apache.resolver.present"
+    classname="org.apache.xml.resolver.tools.CatalogResolver"
+    classpathref="classpath"/>
+  <available property="xalan.present"
+    classname="org.apache.xalan.xslt.XSLTProcessorFactory"
+    classpathref="classpath"/>
+  <available property="xalan2.present"
+    classname="org.apache.xalan.transformer.TransformerImpl"
+    classpathref="classpath"/>
+  <available property="ejb.ejbc.present"
+    classname="weblogic.ejbc"
+    classpathref="classpath"/>
+  <available property="ejb.DDCreator.present"
+    classname="weblogic.ejb.utils.DDCreator"
+    classpathref="classpath"/>
+  <available property="ejb.wls.present"
+    classname="weblogic.Server"
+    classpathref="classpath"/>
+  <available property="junit.present"
+    classname="junit.framework.TestCase"
+    classpathref="classpath"/>
+  <available property="commons.net.present"
+    classname="org.apache.commons.net.ftp.FTPClient"
+    classpathref="classpath"/>
+  <available property="starteam.present"
+    classname="com.starbase.util.Platform"
+    classpathref="classpath"/>
+  <available property="antlr.present"
+    classname="antlr.Tool"
+    classpathref="classpath"/>
+  <available property="vaj.present"
+    classname="com.ibm.ivj.util.base.Workspace"
+    classpathref="classpath"/>
+  <available property="stylebook.present"
+    classname="org.apache.stylebook.Engine"
+    classpathref="classpath"/>
+  <available property="jakarta.regexp.present"
+    classname="org.apache.regexp.RE"
+    classpathref="classpath"/>
+  <available property="jakarta.oro.present"
+    classname="org.apache.oro.text.regex.Perl5Matcher"
+    classpathref="classpath"/>
+  <available property="jmf.present"
+    classname="javax.sound.sampled.Clip"
+    classpathref="classpath"/>
+  <available property="jai.present"
+    classname="javax.media.jai.JAI"
+    classpathref="classpath"/>
+  <available property="icontract.present"
+    classname="com.reliablesystems.iContract.IContracted"
+    classpathref="classpath"/>
+  <available property="jdepend.present"
+    classname="jdepend.framework.JDepend"
+    classpathref="classpath"/>
+  <available property="log4j.present"
+    classname="org.apache.log4j.Category"
+    classpathref="classpath"/>
+  <available property="commons.logging.present"
+    classname="org.apache.commons.logging.LogFactory"
+    classpathref="classpath"/>
+  <available property="xalan.envcheck"
+    classname="org.apache.xalan.xslt.EnvironmentCheck"
+    classpathref="classpath"/>
+  <available property="which.present"
+    classname="org.apache.env.Which"
+    classpathref="classpath"/>
+
+  <available property="xerces.present"
+    classname="org.apache.xerces.parsers.SAXParser"
+    classpathref="classpath"/>
+  <available property="bcel.present"
+    classname="org.apache.bcel.Constants"
+    classpathref="classpath"/>
+  <available property="sunuue.present"
+    classname="sun.misc.UUEncoder"
+    classpathref="classpath"/>
+
+  <condition property="javamail.complete">
+    <and>
+      <available classname="javax.activation.DataHandler"
+        classpathref="classpath"/>
+      <available classname="javax.mail.Transport"
+        classpathref="classpath"/>
+    </and>
+  </condition>
+
+  <condition property="some.regexp.support">
+    <or>
+      <isset property="jdk1.4+"/>
+      <isset property="jakarta.regexp.present"/>
+      <isset property="jakarta.oro.present"/>
+    </or>
+  </condition>
+
+  <condition property="tests.and.ant.share.classloader">
+    <or>
+      <equals arg1="${junit.fork}" arg2="true"/>
+      <equals arg1="${build.sysclasspath}" arg2="only"/>
+    </or>
+  </condition>
+
+  <condition property="sun.tools.present">
+    <and>
+      <available classname="sun.tools.native2ascii.Main"/>
+      <available classname="com.sun.tools.javah.Main"/>
+    </and>
+  </condition>
+
+  <available property="base64.present" classname="sun.misc.BASE64Encoder"/>
+
+  <property name="build.tests.resolved" location="${build.tests}"/>
+  <condition property="tests.are.on.system.classpath">
+    <or>
+      <!-- relative paths in CLASSPATH -->
+      <contains string="${java.class.path}"
+        substring="${build.tests}"/>
+      <!-- absolute paths in CLASSPATH -->
+      <contains string="${java.class.path}"
+        substring="${build.tests.resolved}"/>
+    </or>
+  </condition>
+
+  <condition property="jasper.present">
+    <and>
+      <available classname="org.apache.jasper.compiler.Compiler"/>
+      <available classname="org.apache.jasper.JasperException"/>
+    </and>
+  </condition>
+
+  <condition property="swing.present">
+    <or>
+      <not>
+        <isset property="kaffe"/>
+      </not>
+      <available classname="javax.swing.ImageIcon"
+        classpathref="classpath"/>
+    </or>
+  </condition>
+  <condition property="wsdl.found">
+    <or>
+      <available file="wsdl" filepath="${env.PATH}"/>
+      <available file="wsdl.exe" filepath="${env.PATH}"/>
+      <available file="wsdl.exe" filepath="${env.Path}"/>
+    </or>
+  </condition>
+  <echo level="verbose"> wsdl.found=${wsdl.found}</echo>
+  <condition property="csc.found">
+    <or>
+      <available file="csc" filepath="${env.PATH}"/>
+      <available file="csc.exe" filepath="${env.PATH}"/>
+      <available file="csc.exe" filepath="${env.Path}"/>
+    </or>
+  </condition>
+  <echo level="verbose"> csc.found=${csc.found}</echo>
+  <condition property="dotnetapps.found">
+    <and>
+      <isset property="csc.found"/>
+      <isset property="wsdl.found"/>
+    </and>
+  </condition>
+  <echo level="verbose"> dotnetapps.found=${dotnetapps.found}</echo>
+
+  <available property="rhino.present"
+    classname="org.mozilla.javascript.Scriptable"
+    classpathref="classpath"/>
+  <available property="beanshell.present"
+    classname="bsh.StringUtil"
+    classpathref="classpath"/>
+  <available property="jsch.present"
+    classname="com.jcraft.jsch.Session"
+    classpathref="classpath"/>
+
+  <path id="xdoclet.classpath">
+    <path>
+      <fileset dir="lib" includes="*.jar"/>
+    </path>
+    <path>
+      <fileset dir="${ant.home}/lib" includes="*.jar"/>
+    </path>
+    <!-- do not remove this. This is an extension point used by things like Axis
+      and other projects that autogen their task docs -->
+    <pathelement path="${xdoclet.extra.classpath}" />
+  </path>
+
+  <target name="init">
+    <mkdir dir="${build.dir}" />
+    <mkdir dir="${gen.dir}" />
+    <mkdir dir="${build.docs.dir}" />
+    <property name="xdoclet.classpath.asprop"
+        refid="xdoclet.classpath"/>
+    <echo level="verbose">
+    xdoclet.classpath=${xdoclet.classpath}
+    xdoclet.extra.classpath=${xdoclet.extra.classpath}
+    </echo>
+    <!-- <echoproperties/> -->
+  </target>
+
+  <target name="clean">
+    <delete dir="${build.dir}"/>
+    <delete dir="${gen.dir}"/>
+  </target>
+
+  <target name="declare-tasks" depends="package">
+    <taskdef name="antdoclet"
+             classname="org.apache.ant.xdoclet.AntDocletTask">
+      <classpath>
+        <path refid="xdoclet.classpath"/>
+        <pathelement location="${build.dir}/classes"/>
+      </classpath>
+    </taskdef>
+  </target>
+  
+  <target name="gen" depends="declare-tasks"
+    description="generate the XML files from the annotated source">
+    <antdoclet destdir="${gen.dir}"
+               excludedtags="@version,@author"
+               force="${xdoclet.force}"
+               mergedir="${antdoclet.src.dir}">
+      <fileset dir="${src.root}">
+        <selector id="conditional-patterns">
+          <not>
+            <or>
+              <selector refid="needs.jdk1.3+" unless="jdk1.3+"/>
+              <selector refid="needs.jdk1.4+" unless="jdk1.4+"/>
+              <selector refid="needs.sun.tools" unless="sun.tools.present"/>
+              <selector refid="needs.sun.uue" unless="sunuue.present"/>
+              <selector refid="needs.sun.b64" unless="base64.present"/>
+
+              <selector refid="needs.trax" unless="trax.present"/>
+              <selector refid="needs.xalan1" unless="xalan.present"/>
+              <selector refid="needs.xalan2" unless="xalan2.present"/>
+              <selector refid="needs.xslp" unless="xslp.present"/>
+              <selector refid="needs.apache.resolver" unless="apache.resolver.present"/>
+              <selector refid="needs.junit" unless="junit.present"/>
+              <selector refid="needs.jakarta.regexp"
+                unless="jakarta.regexp.present"/>
+              <selector refid="needs.jakarta.oro" unless="jakarta.oro.present"/>
+              <selector refid="needs.jakarta.bcel" unless="bcel.present"/>
+              <selector refid="needs.jakarta.log4j" unless="log4j.present"/>
+              <selector refid="needs.commons.logging"
+                unless="commons.logging.present"/>
+              <selector refid="needs.bsf" unless="bsf.present"/>
+              <selector refid="needs.stylebook" unless="stylebook.present"/>
+              <selector refid="needs.javamail" unless="javamail.complete"/>
+              <selector refid="needs.icontract" unless="icontract.present"/>
+              <selector refid="needs.netrexx" unless="netrexx.present"/>
+              <selector refid="needs.weblogic.ejbc" unless="ejb.ejbc.present"/>
+              <selector refid="needs.weblogic.ddcreator"
+                unless="ejb.DDCreator.present"/>
+              <selector refid="needs.weblogic.server" unless="ejb.wls.present"/>
+              <selector refid="needs.commons.net" unless="commons.net.present"/>
+              <selector refid="needs.starteam" unless="starteam.present"/>
+              <selector refid="needs.vaj" unless="vaj.present"/>
+              <selector refid="needs.antlr" unless="antlr.present"/>
+              <selector refid="needs.jmf" unless="jmf.present"/>
+              <selector refid="needs.jai" unless="jai.present"/>
+              <selector refid="needs.jdepend" unless="jdepend.present"/>
+              <selector refid="needs.swing" unless="swing.present"/>
+              <selector refid="needs.jsch" unless="jsch.present"/>
+            </or>
+          </not>
+        </selector>
+      </fileset>
+      <taskdescriptor/>
+<!--      <taskdefproperties/> -->
+    </antdoclet>
+  </target>
+
+  <target name="prepare-for-docs">
+    <copy todir="${build.docs.dir}">
+      <fileset dir="${basedir}/../../docs" includes="artwork/**" />
+    </copy>
+    <mkdir dir="${xdocs.dir}" />
+    <copy todir="${xdocs.dir}">
+      <fileset dir="${docs.src}" includes="stylesheets/project.xml" />
+    </copy>
+  </target>
+  
+  <!--inserted for external build files to call -->
+  
+  <target name="gen-and-prepare-for-docs"
+   depends="gen,prepare-for-docs" />
+   
+  <target name="docs" depends="prepare-for-docs" >
+    <!-- Copy stuff so things are in the correct relative location. -->
+    <!-- Generate HTML using DVSL -->
+    <ant dir="dvsl"/>
+  </target>
+
+  <target name="compile" depends="init">
+    <mkdir dir="${build.dir}/classes"/>
+    <javac destdir="${build.dir}/classes"
+           srcdir="${antdoclet.src.dir}"
+           deprecation="on"
+           debug="true"
+           classpathref="xdoclet.classpath"
+    />
+  </target>
+
+  <target name="package" depends="compile">
+<!--    <jar destfile="${build.dir}/xdoclet-ant.jar">
+      <fileset dir="${build.dir}/classes"/>
+      <metainf dir="metadata" includes="xdoclet.xml"/>
+      <fileset dir="src" includes="**/*.xdt"/>
+    </jar> -->
+
+    <mkdir dir="${build.dir}/classes/META-INF"/>
+    <copy todir="${build.dir}/classes/META-INF">
+        <fileset dir="metadata"/>
+    </copy>
+    <copy todir="${build.dir}/classes">
+        <fileset dir="src" includes="**/*.xdt"/>
+    </copy>
+  </target>
+
+  <target name="indexgen" depends="compile">
+    <taskdef name="indexgen"
+             classpath="${build.dir}/classes"
+             classname="org.apache.ant.xdoclet.IndexGen"
+    />
+    <indexgen rootdir="${build.dir}/docs/manual"/>
+  </target>
+
+  <target name="docs-from-scratch" depends="clean,gen,docs,indexgen"/>
+
+  <target name="default" depends="gen"/>
+
+</project>
+
diff --git a/trunk/proposal/xdocs/dvsl/README.txt b/trunk/proposal/xdocs/dvsl/README.txt
new file mode 100644
index 0000000..e86af1e
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/README.txt
@@ -0,0 +1,16 @@
+This directory contains support for generating HTML task documentation
+from the XDoclet generated XML.  DVSL
+(http://jakarta.apache.org/velocity/dvsl/) is used for this purpose.  It has
+many of the benefits of XSLT but uses Velocity as its template language.
+
+This is in a subdirectory as it is effectively a sub-proposal demonstrating
+one way the task XML can be transformed into HTML.
+
+Directions:
+1. Generate the XML task docs by running the build.xml in the parent
+   directory.
+2. Generate the HTML docs by running the build file in this directory.
+   The output is written to ../build/docs/manual.
+
+-Bill Burton <billb@progress.com>
+
diff --git a/trunk/proposal/xdocs/dvsl/build.xml b/trunk/proposal/xdocs/dvsl/build.xml
new file mode 100644
index 0000000..203abc3
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/build.xml
@@ -0,0 +1,45 @@
+<project name="AntManual" default="taskdocs" basedir=".">
+
+  <property file="${basedir}/build.properties"/>
+
+  <property name="lib.dir" location="${basedir}/lib" />
+  <property name="build.dir" location="${basedir}/../build" />
+  <property name="docs.src" location="${basedir}/../../../xdocs" />
+  <property name="taskdocs.src" location="${build.dir}/gen" />
+  <property name="stylesheet" location="${docs.src}/stylesheets/project.xml"/>
+
+  <!-- The docs destination directory  -->
+  <property name="docs.dest" location="${build.dir}/docs"/>
+  <property name="manual.dest" location="${docs.dest}/manual" />
+  <property name="xdocs.dir" location="${basedir}/xdocs"/>
+  <property name="stylesheet.dir" location="${xdocs.dir}/stylesheets"/>
+
+  <!-- Construct compile classpath -->
+  <path id="classpath">
+    <fileset dir="${lib.dir}">
+      <include name="**/*.jar"/>
+    </fileset>
+  </path>
+
+  <target name="init">
+    <taskdef name="dvsl" classname="org.apache.tools.dvsl.DVSLTask">
+      <classpath>
+        <path refid="classpath"/>
+      </classpath>
+    </taskdef>
+    <!-- Make stuff available relative to current location -->
+    <mkdir dir="${stylesheet.dir}" />
+    <copy todir="${stylesheet.dir}" file="${stylesheet}"/>
+  </target>
+
+  <target name="taskdocs" depends="init"
+          description="Generate Task Documentation">
+    <dvsl basedir="${taskdocs.src}" destdir="${manual.dest}"
+          style="task.dvsl" extension=".html"
+          toolboxfile="toolbox.props"
+          includes="**/*.xml">
+      <velconfig name="velocimacro.library" value="" />
+    </dvsl>
+  </target>
+
+</project>
diff --git a/trunk/proposal/xdocs/dvsl/lib/dom4j-1.2-jp.jar b/trunk/proposal/xdocs/dvsl/lib/dom4j-1.2-jp.jar
new file mode 100644
index 0000000..cbd4a12
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/lib/dom4j-1.2-jp.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/dvsl/lib/dom4j-README.txt b/trunk/proposal/xdocs/dvsl/lib/dom4j-README.txt
new file mode 100644
index 0000000..07c61ae
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/lib/dom4j-README.txt
@@ -0,0 +1,19 @@
+This is the standard dom4j 1.2 release with a patch applied to jaxen.  The
+patch fixes a problem where DocumentHelper.createPattern("aaa | bbb") would
+fail never matching the element <bbb> because the pattern for "bbb" had been
+overwritten by the pattern for "aaa".
+
+--- org/jaxen/pattern/UnionPattern.java.orig    Wed Aug  8 17:29:49 2001
++++ org/jaxen/pattern/UnionPattern.java Wed Mar  6 01:39:51 2002
+@@ -91,7 +91,7 @@
+     public Pattern simplify()
+     {
+         this.lhs = lhs.simplify();
+-        this.rhs = lhs.simplify();
++        this.rhs = rhs.simplify();
+         init();
+         return this;
+     }
+
+
+
diff --git a/trunk/proposal/xdocs/dvsl/lib/velocity-dep-1.3-dev.jar b/trunk/proposal/xdocs/dvsl/lib/velocity-dep-1.3-dev.jar
new file mode 100644
index 0000000..2594020
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/lib/velocity-dep-1.3-dev.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/dvsl/lib/velocity-dvsl-0.42.jar b/trunk/proposal/xdocs/dvsl/lib/velocity-dvsl-0.42.jar
new file mode 100644
index 0000000..2fcc8af
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/lib/velocity-dvsl-0.42.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/dvsl/task.dvsl b/trunk/proposal/xdocs/dvsl/task.dvsl
new file mode 100644
index 0000000..966853b
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/task.dvsl
@@ -0,0 +1,524 @@
+#*
+ *  DVSL Stylesheet to format the Ant Task documentation.
+ *#
+
+#set( $relative-path = "../../" )
+#if (false)
+#set( $body-bg = '#ffffff' )
+#set( $body-fg = '#000000' )
+#set( $body-link = '#525D76' )
+##set( $banner-bg = '#EEEEEE')
+#set( $banner-fg = '#000000')
+#set( $sub-banner-bg = '#828DA6')
+#set( $sub-banner-fg = '#ffffff')
+##set( $table-th-bg = '#FFEEEE')
+##set( $table-td-bg = '#FFEEEE')
+##set( $source-color = '#CCFFFF')
+
+#set( $table-th-bg = '#EEEEEE')
+#set( $table-td-bg = '#EEEEEE')
+#set( $banner-bg = '#a0ddf0')
+##set( $banner-bg = '#525D76')
+##set( $table-th-bg = '#039acc')
+##set( $table-td-bg = '#a0ddf0')
+#set( $source-color = '#023264')
+#end
+
+#set( $body-bg = '#ffffff' )
+#set( $body-fg = '#000000' )
+#set( $body-link = '#525D76' )
+#set( $banner-bg = '#525D76')
+#set( $banner-fg = '#ffffff')
+#set( $sub-banner-bg = '#828DA6')
+#set( $sub-banner-fg = '#ffffff')
+#set( $table-th-bg = '#cccccc')
+#set( $table-td-bg = '#eeeeee')
+#set( $source-color = '#023264')
+#set( $source-font-size = '+0')
+
+## Double quote for convenience
+#set ($qq = '"')
+
+## Macro to output argument if test evaluates to true
+#macro(ifset $test $output)
+#if ( $test )$output#end
+#end
+
+## Macro to capitalize a word making the first letter upper case
+#macro(capitalize $word)
+$word.substring(0,1).toUpperCase()$word.substring(1)
+#end
+
+
+#match( "task" )
+  #set( $project = $node.selectSingleNode("document('xdocs/stylesheets/project.xml')/project" ) )
+  #if ($node.name().equals("task"))
+    #set( $title = "#capitalize($attrib.name) Task" )
+    #set( $summary = $node.short-description )   
+  #end
+
+<html>
+<head>
+  <meta http-equiv="Content-Language" content="en-us">
+  <title>$title</title>
+</head>
+
+<body bgcolor="$body-bg" text="$body-fg" link="$body-link"
+      alink="$body-link" vlink="$body-link">
+
+<table border="0" width="100%" cellspacing="4">
+
+  <!-- PAGE HEADER -->
+  <tr>
+    <td>
+      <table border="0" width="100%"><tr>
+          <td valign="bottom">
+            <font size="+3" face="arial,helvetica,sanserif"><strong>$title</strong></font>
+#*          *##if( $summary )
+            <br><font face="arial,helvetica,sanserif">$summary</font>
+#*          *##end
+          </td>
+          <td>
+#*        *##if( $project.logo )
+            #set( $alt = $project.logo )
+            #set( $home = $project.attribute("href") )
+            #set( $src = $project.logo.attribute( "href" ) )
+            <!-- PROJECT LOGO -->
+            <a href="$home">
+              <img src="${relative-path}$src" align="right" alt="$alt" border="0"/>
+            </a>
+#*        *##end
+          </td>
+      </tr></table>
+    </td>
+  </tr>
+
+  <!-- START RIGHT SIDE MAIN BODY -->
+  <tr>
+    <td  valign="top" align="left">
+#*    *##if ($node.name().equals("task"))
+#*      Use description from merged XML if available, else javadoc comment *#
+#*      *##if ($node.external.description)
+          <!-- Applying task/description -->
+#*        *#$context.applyTemplates("external/description")
+#*      *##else
+          <!-- Applying task/long-description -->
+#*        *#$context.applyTemplates("long-description")
+#*      *##end
+#*     *#$context.applyTemplates("short-description")
+#*     *#$context.applyTemplates("attribute/description")
+#*     *#$context.applyTemplates("element/description")
+#*     *#$context.applyTemplates("structure/attribute-groups")
+#*     *#$context.applyTemplates("structure/elements")
+#*     *#$context.applyTemplates("external/section")
+#*    *##end
+    </td>
+  </tr>
+  <!-- END RIGHT SIDE MAIN BODY -->
+
+  <!-- FOOTER SEPARATOR -->
+  <tr>
+    <td>
+      <hr noshade="" size="1"/>
+    </td>
+  </tr>
+
+  <!-- PAGE FOOTER -->
+  <tr>
+    <td>
+      <div align="center"><font color="$body-link" size="-1"><em>
+        Copyright &#169; 2000-2005, Apache Software Foundation
+      </em></font></div>
+    </td>
+  </tr>
+
+</table>
+
+</body>
+</html>
+#end
+
+#*
+    Macro to format a table heading cell
+*#
+#macro( th $text )
+        <td bgcolor="$table-th-bg" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif"><b>$text</b></font>
+        </td>
+#end
+
+#*
+    Macro to format a table body cell
+*#
+#macro( td $text )
+        <td bgcolor="$table-td-bg" valign="top" align="left">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">$text</font>
+        </td>
+#end
+
+#*
+    Macro to format a table body cell that spans multiple rows
+*#
+#macro( tdmr $text $rows  )
+        <td bgcolor="$table-td-bg" valign="top" align="left" rowspan="$rows">
+          <font color="#000000" size="-1" face="arial,helvetica,sanserif">$text</font>
+        </td>
+#end
+
+
+#*
+    Macro to format a section banner
+*#
+#macro( section $anchor $name )
+      <tr><td bgcolor="$banner-bg">
+        <font color="$banner-fg" face="arial,helvetica.sanserif">
+          <a name="$anchor">
+          <strong>$name</strong></a></font>
+      </td></tr>
+#end
+
+#*
+    Macro to format a subsection banner
+*#
+#macro( subsection $anchor $name )
+      <tr><td bgcolor="$sub-banner-bg">
+        <font color="$sub-banner-fg" face="arial,helvetica.sanserif">
+          <a name="$anchor">
+          <strong>$name</strong></a></font>
+      </td></tr>
+#end
+
+
+#*
+    Process javadoc long description section
+*#
+#match( "long-description" )
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+#*      *##section("description" "Description")
+
+      <tr><td><blockquote>
+        $node.value().trim()
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+#end
+
+#*
+    Process javadoc short description section
+*#
+#match( "short-description" )
+ <!-- Ignore -->
+#end
+
+#*
+    Process javadoc attribute/description section
+*#
+#match( "attribute/description" )
+ <!-- Ignore -->
+#end
+
+#*
+    Process javadoc element/description section
+*#
+#match( "element/description" )
+ <!-- Ignore -->
+#end
+
+
+#*
+    Process external desciption
+*#
+#match( "external/description" )
+    <!-- Start Description -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+#*      *##section("description" "Description")
+
+      <tr><td><blockquote>
+#*      *#$context.applyTemplates("*")
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Description -->
+#end
+
+#*
+    Process top level attributes
+*#
+#match( "structure/attribute-groups" )
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+#*      *##section("attributes" "Parameters") 
+      <tr><td><blockquote>
+        <table>
+          <tr>
+#*          *##th("Attribute")
+#*          *##th("Description")
+#*          *##th("Type")
+#*          *##th("Requirement")
+          </tr>
+#*        *#$context.applyTemplates("*")
+        </table>
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Attributes -->
+#end
+
+#*
+    Process attribute group
+*#
+#match( "structure/attribute-groups/attribute-group" )
+    <!-- Attribute Group -->    
+    #set ($attributeGroup = $attrib.description)
+    #set ($numGroups = $node.selectNodes("attribute").size())
+    #set ($inGroup = true)
+#*        *#$context.applyTemplates("*")
+#end
+
+#*
+    Process a single attribute
+*#
+#match( "structure/attribute-groups/attribute-group/attribute" )    
+    <!-- Attribute -->
+    <tr>
+#*    *##td($attrib.name)
+#*    *##td($node.description)
+#*    *##td($attrib.briefType)
+#if ($inGroup)
+#*    *##tdmr($attributeGroup $numGroups)
+#set ($inGroup = false)
+#end
+    </tr>
+#end
+
+#*
+    Process all elements
+*#
+#match( "elements" )
+    <!-- Start Elements -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+#*      *##section("elements" "Parameters as nested elements")
+
+      <tr><td><blockquote>
+#*      *#$context.applyTemplates("*")
+      </blockquote></td></tr>
+
+    </table>
+    <!-- End Elements -->
+#end
+
+#*
+    Process a single element
+*#
+#match( "element" )
+    <!-- Start Element -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+      <tr><td bgcolor="$sub-banner-bg">
+        <font color="$sub-banner-fg" face="arial,helvetica.sanserif" size="-1">
+          <strong>$attrib.name</strong> ($attrib.type)</font>
+      </td></tr>
+      <tr><td><blockquote>
+        $node.description.toString().trim()
+#*      *#$context.applyTemplates("*")
+      </blockquote></td></tr>
+    </table>
+    <!-- End Element -->
+#end
+
+#*
+    Process attributes within elements
+*#
+#match( "element/attributes" )
+    <!-- Start Attributes -->
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td>
+        <table>
+          <tr>
+#*          *##th("Attribute")
+#*          *##th("Description")
+#*          *##th("Type")
+          </tr>
+#*        *#$context.applyTemplates("*")
+        </table>
+      </td></tr>
+
+    </table>
+    <!-- End Attributes -->
+#end
+
+
+#*
+ *   Process a menu for the navigation bar
+ *#
+#match( "menu" )
+    <tr><td>
+    <p>
+      <strong>$attrib.name</strong>
+    </p>
+    </td><td>
+    <ul>
+        $context.applyTemplates("item")
+    </ul></td></tr>
+#end
+
+
+#*
+ *   Process a menu item for the navigation bar
+ *#
+#match( "item" )
+#if( $attrib.href.endsWith("$outputfilename") && !$attrib.href.startsWith("http"))
+	<strong>$attrib.name</strong>
+#else
+#if( $attrib.href.startsWith("http") )
+        <a href="$attrib.href">$attrib.name</a>
+    #else
+        <a href="${relative-path}$attrib.href">$attrib.name</a>
+    #end
+#end
+#end
+
+#*
+ *  process a documentation section
+ *#
+#match( "section" )
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <tr><td>&nbsp;</td></tr>
+
+      <tr><td bgcolor="$banner-bg">
+          <font color="$banner-fg" face="arial,helvetica.sanserif">
+          #if ( $attrib.anchor )
+              #set( $anchor = $attrib.anchor )
+          #else
+              #set( $anchor = $attrib.name )
+          #end
+          <a name="$anchor">
+          <strong>$attrib.name</strong></a></font>
+      </td></tr>
+
+      <tr><td><blockquote>
+        $context.applyTemplates("*")
+      </blockquote></td></tr>
+
+    </table>
+#end
+
+#match( "subsection" )
+    <table border="0" cellspacing="0" cellpadding="2" width="100%">
+      <!-- Subsection heading -->
+      <tr><td bgcolor="$sub-banner-bg">
+          <font color="$sub-banner-fg" face="arial,helvetica.sanserif">
+          #if ( $attrib.anchor )
+              #set( $anchor = $attrib.anchor )
+          #else
+              #set( $anchor = $attrib.name )
+          #end
+          <a name="$anchor">
+          <strong>$attrib.name</strong></a></font>
+      </td></tr>
+      <!-- Subsection body -->
+      <tr><td>
+        $context.applyTemplates("*")
+      </td></tr>
+    </table>
+#end
+
+#*
+ *  process a the requirement groups
+ *#
+#match( "requirement-group" )
+    #if ($regGroup == $attrib.name)
+#*      *#$attrib.description
+    #end
+#end
+
+#match( "source" )
+    <div align="left">
+      <table cellspacing="4" cellpadding="0" border="0">
+        <tr>
+          <td bgcolor="$source-color" width="1" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="$source-color" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="$source-color" width="1" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="$source-color" width="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="#ffffff" height="1">
+          <font size="$source-font-size"><pre>$toolbox.htmlescape.getText( $node.value() )</pre></font>
+          </td>
+          <td bgcolor="$source-color" width="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+        <tr>
+          <td bgcolor="$source-color" width="1" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="$source-color" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+          <td bgcolor="$source-color" width="1" height="1">
+            <img src="/images/void.gif" width="1" height="1" vspace="0" hspace="0" border="0"/>
+          </td>
+        </tr>
+      </table>
+    </div>
+#end
+
+
+#match("table")
+<table>
+$context.applyTemplates("*")
+</table>
+#end
+
+#match("tr")
+<tr>
+$context.applyTemplates("*")
+</tr>
+#end
+
+#match( "td" )
+<td bgcolor="$table-td-bg" #*
+    *##ifset($attrib.colspan "colspan=$qq$attrib.colspan$qq ")#*
+    *##ifset($attrib.rowspan "rowspan=$qq$attrib.rowspan$qq ")#*
+    *#valign="top" align="left">
+    <font color="#000000" size="-1" face="arial,helvetica,sanserif">
+       $node.copy( $node.children() )
+    </font>
+</td>
+#end
+
+#match( "th" )
+<td bgcolor="$table-th-bg" #*
+    *##ifset($attrib.colspan "colspan=$qq$attrib.colspan$qq ")#*
+    *##ifset($attrib.rowspan "rowspan=$qq$attrib.rowspan$qq ")#*
+    *#valign="top" align="left">
+    <font color="#000000" size="-1" face="arial,helvetica,sanserif">
+       <b>$node.copy( $node.children())</b>
+    </font>
+</td>
+#end
+
+#match("*")
+$node.copy()
+#end
+
diff --git a/trunk/proposal/xdocs/dvsl/toolbox.props b/trunk/proposal/xdocs/dvsl/toolbox.props
new file mode 100644
index 0000000..70da669
--- /dev/null
+++ b/trunk/proposal/xdocs/dvsl/toolbox.props
@@ -0,0 +1,4 @@
+toolbox.contextname = toolbox
+toolbox.tool.htmlescape = org.apache.velocity.anakia.Escape
+
+
diff --git a/trunk/proposal/xdocs/lib/LICENSE.xdoclet.txt b/trunk/proposal/xdocs/lib/LICENSE.xdoclet.txt
new file mode 100644
index 0000000..575814f
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/LICENSE.xdoclet.txt
@@ -0,0 +1,37 @@
+
+
+Copyright (c) 2000-2003, XDoclet Team
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+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.
+
+Neither the name of the XDoclet team nor the names of its contributors may be
+used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
+AND ANY EXPRESS 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 REGENTS OR 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.
+
+Other Licenses
+
+Licenses of the products XDoclet depends on:
+
+    * Jakarta Ant
+    * Xerces
+
diff --git a/trunk/proposal/xdocs/lib/commons-collections-2.0.jar b/trunk/proposal/xdocs/lib/commons-collections-2.0.jar
new file mode 100644
index 0000000..4f4f97b
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/commons-collections-2.0.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/commons-logging.jar b/trunk/proposal/xdocs/lib/commons-logging.jar
new file mode 100644
index 0000000..aca1e41
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/commons-logging.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/xdoclet-1.2.jar b/trunk/proposal/xdocs/lib/xdoclet-1.2.jar
new file mode 100644
index 0000000..80a713c
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/xdoclet-1.2.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/xdoclet-ejb-module-1.2.jar b/trunk/proposal/xdocs/lib/xdoclet-ejb-module-1.2.jar
new file mode 100644
index 0000000..0c0d008
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/xdoclet-ejb-module-1.2.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/xdoclet-web-module-1.2.jar b/trunk/proposal/xdocs/lib/xdoclet-web-module-1.2.jar
new file mode 100644
index 0000000..d56f836
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/xdoclet-web-module-1.2.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/xdoclet-xdoclet-module-1.2.jar b/trunk/proposal/xdocs/lib/xdoclet-xdoclet-module-1.2.jar
new file mode 100644
index 0000000..e4288ee
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/xdoclet-xdoclet-module-1.2.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/lib/xjavadoc-1.0.2.jar b/trunk/proposal/xdocs/lib/xjavadoc-1.0.2.jar
new file mode 100644
index 0000000..560294f
--- /dev/null
+++ b/trunk/proposal/xdocs/lib/xjavadoc-1.0.2.jar
Binary files differ
diff --git a/trunk/proposal/xdocs/log4j.properties b/trunk/proposal/xdocs/log4j.properties
new file mode 100644
index 0000000..11c6313
--- /dev/null
+++ b/trunk/proposal/xdocs/log4j.properties
@@ -0,0 +1,33 @@
+log4j.rootCategory=INFO, Console
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+#log4j.appender.Console.layout.ConversionPattern=%m%n
+log4j.appender.Console.layout.ConversionPattern=(%-35c{2} %-4L) %m%n
+
+# Uncomment to debug all
+log4j.category.xdoclet=DEBUG
+
+# Uncomment to debug all Ejb Module tasks only
+#log4j.category.xdoclet.modules.ejb=DEBUG
+
+# Uncomment to debug the class SubTask only
+#log4j.category.xdoclet.SubTask=DEBUG
+#log4j.category.xdoclet.TemplateSubTask=DEBUG
+#log4j.category.xdoclet.template.TemplateEngine=DEBUG
+
+# Uncomment to debug the execute() method of SubTask only
+#log4j.category.xdoclet.SubTask.execute=DEBUG
+
+# Uncomment this line if you want to see stack traces
+# Please always do so when you want to report a bug
+#log4j.category.xdoclet.DocletTask=DEBUG
+#log4j.category.xdoclet.XDocletMain=DEBUG
+
+# Uncomment to debug the ModuleFinder
+#log4j.category.xdoclet.loader.ModuleFinder.findModules=DEBUG
+
+# Uncomment to debug the MethodTagsHandler
+#log4j.category.xdoclet.tagshandler.MethodTagsHandler=DEBUG
+
+# Uncomment to debug the GenerationManager
+#log4j.category.xdoclet.GenerationManager.generation=DEBUG
diff --git a/trunk/proposal/xdocs/metadata/xdoclet.xml b/trunk/proposal/xdocs/metadata/xdoclet.xml
new file mode 100644
index 0000000..ccf9389
--- /dev/null
+++ b/trunk/proposal/xdocs/metadata/xdoclet.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+<!DOCTYPE xdoclet-module PUBLIC "-//XDoclet Team//DTD XDoclet Module 1.0//EN" "http://xdoclet.sourceforge.net/dtd/xdoclet-module_1_0.dtd">
+-->
+
+<xdoclet-module>
+    <taghandler
+        namespace="Ant"
+        class="org.apache.ant.xdoclet.TaskTagsHandler"
+    />
+
+    <subtask
+        name="taskdescriptor"
+        implementation-class="org.apache.ant.xdoclet.TaskDescriptorSubTask"
+        parent-task-class="org.apache.ant.xdoclet.AntDocletTask"
+    />
+    <subtask
+        name="taskdefproperties"
+        implementation-class="org.apache.ant.xdoclet.TaskDefPropertiesSubTask"
+        parent-task-class="org.apache.ant.xdoclet.AntDocletTask"
+    />
+</xdoclet-module>
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntDocletTask.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntDocletTask.java
new file mode 100644
index 0000000..c90d8a4
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntDocletTask.java
@@ -0,0 +1,80 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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/>.
+ */
+
+package org.apache.ant.xdoclet;
+
+import org.apache.tools.ant.BuildException;
+
+import xdoclet.DocletTask;
+
+/**
+ * @created       January 5, 2003
+ * @ant.element   name="antdoclet" display-name="AntDoclet Task"
+ */
+public class AntDocletTask extends DocletTask
+{
+    public AntDocletTask()
+    {
+        // by default, binary classes do not provide their
+        // methods for performance reasons, but it is needed
+        // here to climb up and find true tasks.
+        System.setProperty("xjavadoc.compiledmethods", "true");
+    }
+
+    protected void validateOptions() throws BuildException
+    {
+        super.validateOptions();
+        checkClass("org.apache.tools.ant.IntrospectionHelper");
+    }
+}
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntSubTask.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntSubTask.java
new file mode 100644
index 0000000..af87e6d
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/AntSubTask.java
@@ -0,0 +1,174 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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/>.
+ */
+package org.apache.ant.xdoclet;
+
+import java.util.Collection;
+import java.util.Iterator;
+import xjavadoc.XClass;
+import xjavadoc.XJavaDoc;
+import xjavadoc.XMethod;
+
+import xdoclet.TemplateSubTask;
+import xdoclet.XDocletException;
+import xdoclet.util.TypeConversionUtil;
+
+/**
+ * @created   January 5, 2003
+ */
+public abstract class AntSubTask extends TemplateSubTask
+{
+
+    /**
+     * Checks many factors to determine if the class is indeed an Ant task or not.
+     *
+     * @param clazz
+     * @return
+     * @todo                        perhaps make deprecation switch configurable
+     */
+    public final static boolean isAntTask(XClass clazz)
+    {
+        if (clazz.isAbstract()) {
+            return false;
+        }
+
+        // no inner classes (for now - but is this possible? desired?)
+        if (clazz.isInner()) {
+            return false;
+        }
+
+        String ignoreValue = clazz.getDoc().getTagAttributeValue("ant.task", "ignore");
+        boolean ignore = TypeConversionUtil.stringToBoolean(ignoreValue, false);
+
+        if (ignore) {
+            return false;
+        }
+
+        /*
+         * Tag[] tags = clazz.tags();
+         * for (int i = 0; i < tags.length; i++) {
+         * if ("@deprecated".equals(tags[i].name())) {
+         * return false;
+         * }
+         * }
+         */
+        if (hasExecuteMethod(clazz)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Check for class implementing an execute() method. Recursive calls are made to superclasses.
+     *
+     * @param clazz
+     * @return
+     */
+    private static boolean hasExecuteMethod(XClass clazz)
+    {
+        if (clazz == null) {
+            return false;
+        }
+
+        // It ain't a task if we've climbed back to Task itself.
+        // Also ignore other special Ant classes
+        if ("org.apache.tools.ant.Task".equals(clazz.getQualifiedName()) ||
+            "org.apache.tools.ant.Target".equals(clazz.getQualifiedName()) ||
+            "org.apache.tools.ant.TaskAdapter".equals(clazz.getQualifiedName()) ||
+            "org.apache.tools.ant.UnknownElement".equals(clazz.getQualifiedName())) {
+            return false;
+        }
+
+        // need to check that only runtime exceptions are thrown?
+        Collection methods = clazz.getMethods(true);
+        Iterator iter = methods.iterator();
+
+        while (iter.hasNext()) {
+            XMethod method = (XMethod) iter.next();
+
+            if ("execute".equals(method.getName())) {
+                if (method.getParameters().size() == 0) {
+                    if (method.getReturnType().getType().getName().equals("void")) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    protected void startProcess() throws XDocletException
+    {
+        XJavaDoc xjd = new XJavaDoc();
+        xjd.setUseNodeParser(false);
+        xjd.getSourceClasses();
+
+        super.startProcess();
+    }
+
+    /**
+     * Returns true if the class is an Ant task. This causes the task to be processed by the XDoclet template task.
+     *
+     * @param clazz
+     * @return
+     * @exception XDocletException
+     */
+    protected boolean matchesGenerationRules(XClass clazz) throws XDocletException
+    {
+        boolean match = isAntTask(clazz);
+
+        return match;
+    }
+}
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/IndexGen.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/IndexGen.java
new file mode 100644
index 0000000..e9baf00
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/IndexGen.java
@@ -0,0 +1,144 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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/>.
+ */
+
+package org.apache.ant.xdoclet;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.TreeMap;
+import java.util.Arrays;
+import java.util.Iterator;
+
+/**
+ * Quick and dirty index.html generator for proposal/xdocs
+ *
+ */
+public class IndexGen extends Task {
+    private File rootDir;
+
+    public void setRootDir(File rootDir) {
+        this.rootDir = rootDir;
+    }
+
+    public void execute() throws BuildException {
+        TreeMap data = new TreeMap();
+
+        String[] categories = rootDir.list();
+
+        if (categories == null) {
+            throw new BuildException("Root directory \"" + rootDir.getPath() + "\" does not exist!", getLocation());
+        }
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("<html><head><title>xdocs index</title></head>");
+        sb.append("<body>");
+
+        int catCount = 0;
+        int taskCount = 0;
+
+        // grab all categories and tasks
+        for (int i=0; i < categories.length; i++) {
+            String category = categories[i];
+            File catDir = new File(rootDir, category);
+
+            if (!catDir.isDirectory()) {
+                continue;
+            }
+
+            String[] tasks = catDir.list();
+            Arrays.sort(tasks);
+
+            data.put(category, tasks);
+        }
+
+        Iterator iter = data.keySet().iterator();
+        while (iter.hasNext()) {
+            catCount++;
+            String category = (String) iter.next();
+
+            sb.append("<h2>" + category + "</h2>");
+
+            sb.append("<ul>");
+
+            String[] tasks = (String[]) data.get(category);
+
+            for (int j=0; j < tasks.length; j++) {
+                taskCount++;
+                String task = tasks[j];
+                sb.append("<li>");
+                sb.append("<a href=\"" + category + "/" + task + "\">" + task + "</a>");
+                sb.append("</li>");
+            }
+
+            sb.append("</ul>");
+        }
+
+        sb.append("</body></html>");
+
+        FileWriter fw = null;
+        try {
+            fw = new FileWriter(new File(rootDir,"index.html"));
+            fw.write(sb.toString());
+            fw.close();
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+
+        log("Index generated: " + catCount + " categories and " + taskCount + " tasks");
+    }
+}
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDefPropertiesSubTask.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDefPropertiesSubTask.java
new file mode 100644
index 0000000..a32bf07
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDefPropertiesSubTask.java
@@ -0,0 +1,39 @@
+ /*
+ * Copyright  2003, 2005 The Apache Software Foundation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.ant.xdoclet;
+
+import xdoclet.TemplateSubTask;
+
+/**
+ * Generates Ant taskdef properties files, suitable for bulk defining tasks with Ant's &lt;taskdef&gt; task.
+ *
+ * @created       January 5, 2003
+ * @ant.element   display-name="taskdefproperties" name="taskdefproperties"
+ *      parent="org.apache.ant.xdoclet.AntDocletTask"
+ * @ant.task      ignore="true"
+ */
+public class TaskDefPropertiesSubTask extends AntSubTask
+{
+    protected static String DEFAULT_TEMPLATE_FILE = "resources/taskdef_properties.xdt";
+
+    public TaskDefPropertiesSubTask()
+    {
+        setTemplateURL(getClass().getResource(DEFAULT_TEMPLATE_FILE));
+        setDestinationFile("taskdef.properties");
+    }
+}
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDescriptorSubTask.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDescriptorSubTask.java
new file mode 100644
index 0000000..8d9a6f8
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskDescriptorSubTask.java
@@ -0,0 +1,60 @@
+ /*
+  * Copyright  2003, 2005 The Apache Software Foundation
+  *
+  *  Licensed under the Apache License, Version 2.0 (the "License");
+  *  you may not use this file except in compliance with the License.
+  *  You may obtain a copy of the License at
+  *
+  *      http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing, software
+  *  distributed under the License is distributed on an "AS IS" BASIS,
+  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  *  See the License for the specific language governing permissions and
+  *  limitations under the License.
+  *
+  */
+
+package org.apache.ant.xdoclet;
+
+import java.io.File;
+
+import xdoclet.XDocletException;
+import xjavadoc.XClass;
+
+/**
+ * Generates Ant task descriptors.
+ *
+ * @created              January 1, 2003
+ * @ant.element          display-name="taskdescriptor" name="taskdescriptor"
+ *      parent="xdoclet.modules.apache.ant.org.apache.ant.xdoclet.AntDocletTask"
+ * @ant.task             ignore="true"
+ * @xdoclet.merge-file   file="{0}.xml" relates-to="{0}.xml" description="Used for code examples. An example merge file
+ *      may be found in Ant's proposal/xdocs/src directory."
+ */
+public class TaskDescriptorSubTask extends AntSubTask
+{
+    protected static String DEFAULT_TEMPLATE_FILE = "resources/task_xml.xdt";
+
+    public TaskDescriptorSubTask()
+    {
+        setTemplateURL(getClass().getResource(DEFAULT_TEMPLATE_FILE));
+        setDestinationFile("{0}.xml");
+    }
+
+    /**
+     * Custom file naming. Use the task name for the file name rather than the default class name.
+     *
+     * @param clazz
+     * @return
+     * @exception XDocletException
+     */
+    protected String getGeneratedFileName(XClass clazz) throws XDocletException
+    {
+        String dir = TaskTagsHandler.getCategoryName(clazz);
+        String taskName = TaskTagsHandler.getTaskName(clazz);
+
+        return new File(dir, taskName + ".xml").toString();
+    }
+
+}
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskTagsHandler.java b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskTagsHandler.java
new file mode 100644
index 0000000..adbff6f
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/TaskTagsHandler.java
@@ -0,0 +1,855 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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/>.
+ */
+
+package org.apache.ant.xdoclet;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import xjavadoc.XClass;
+import xjavadoc.XMethod;
+import xjavadoc.XParameter;
+import xjavadoc.XTag;
+import xdoclet.XDocletException;
+import xdoclet.XDocletTagSupport;
+import xdoclet.tagshandler.AbstractProgramElementTagsHandler;
+import xdoclet.tagshandler.MethodTagsHandler;
+
+/**
+ * Custom tag handler for XDoclet templates for Ant-specific processing.
+ *
+ * @created              January 1, 2003
+ * @xdoclet.taghandler   namespace="Ant"
+ * @todo                 clean up logic so that all setters are gathered first (even superclass) and sorted along wih
+ *      them
+ * @todo                 need to create better logic for finding proper setters
+ * @todo                 add ifIsAntTask, among other convenience tags
+ */
+public class TaskTagsHandler extends XDocletTagSupport
+{
+
+    /**
+     * Default category for tasks without a category attribute.
+     */
+    public final static String DEFAULT_CATEGORY = "other";
+
+    /**
+     * Default requirement group for attributes without group.
+     */
+    public final static String DEFAULT_GROUP = "optional";
+
+    /**
+     * Requirement group description for optional attributes.
+     */
+    public final static String DESC_OPTIONAL = "optional";
+
+    /**
+     * Requirement group description for required attributes.
+     */
+    public final static String DESC_REQUIRED = "required";
+
+    private static Map attributeDisplayMap = new HashMap();
+    private static Map elementDisplayMap = new HashMap();
+
+    private static String[] fluffPrefixes = {"set a", "set the", "sets a", "sets the"};
+
+    static {
+        attributeDisplayMap.put("java.lang.String", "String");
+        attributeDisplayMap.put("boolean", "boolean");
+        attributeDisplayMap.put("org.apache.tools.ant.types.Path", "Path");
+        attributeDisplayMap.put("org.apache.tools.ant.types.Reference", "Reference");
+        attributeDisplayMap.put("java.io.File", "File");
+        attributeDisplayMap.put("java.util.Date", "Date");
+        attributeDisplayMap.put("java.net.URL", "URL");
+        attributeDisplayMap.put("java.lang.Long", "long");
+        attributeDisplayMap.put("java.lang.Integer", "int");
+        attributeDisplayMap.put("java.lang.Float", "float");
+        attributeDisplayMap.put("java.lang.Double", "double");
+
+        elementDisplayMap.put("org.apache.tools.ant.types.Path", "Path");
+        elementDisplayMap.put("org.apache.tools.ant.types.FileSet", "Fileset");
+        elementDisplayMap.put("org.apache.tools.ant.taskdefs.Property", "see &lt;property&gt;");
+        elementDisplayMap.put("org.apache.tools.ant.types.Mapper", "Mapper");
+        elementDisplayMap.put("org.apache.tools.ant.types.PatternSet", "Patternset");
+        elementDisplayMap.put("org.apache.tools.ant.types.FileList", "Filelist");
+        elementDisplayMap.put("org.apache.tools.ant.types.FilterChain", "FilterChain");
+        elementDisplayMap.put("org.apache.tools.ant.types.FilterSet", "Filterset");
+        elementDisplayMap.put("org.apache.tools.ant.types.ZipFileSet", "ZipFileset");
+        elementDisplayMap.put("org.apache.tools.ant.types.DirSet", "Dirset");
+        elementDisplayMap.put("org.apache.tools.ant.types.XMLCatalog", "XMLCatalog");
+    }
+
+    /**
+     * Provides the Ant task name. Order of rules:
+     *
+     * @param clazz
+     * @return  Lowercased classname with "Task" suffix removed
+     */
+    public final static String getTaskName(XClass clazz)
+    {
+        String tagValue = clazz.getDoc().getTagAttributeValue("ant.task", "name");
+
+        if (tagValue == null) {
+            // use classname, but strip "Task" suffix if there
+            tagValue = clazz.getName();
+
+            if (tagValue.endsWith("Task")) {
+                tagValue = tagValue.substring(0, tagValue.indexOf("Task"));
+            }
+
+            tagValue = tagValue.toLowerCase();
+        }
+        return tagValue;
+    }
+
+    /**
+     * Provides the Ant category name as the Value of the category attribute.
+     *
+     * @param clazz
+     * @return
+     */
+    public final static String getCategoryName(XClass clazz)
+    {
+        String tagValue = clazz.getDoc().getTagAttributeValue("ant.task", "category");
+
+        if (tagValue != null) {
+            tagValue = tagValue.toLowerCase();
+        }
+        else {
+            tagValue = DEFAULT_CATEGORY;
+        }
+        return tagValue;
+    }
+
+    /**
+     * Iterates over all Ant tasks
+     *
+     * @param template
+     * @param attributes
+     * @exception XDocletException
+     */
+    public void forAllTasks(String template, Properties attributes) throws XDocletException
+    {
+        Collection classes = AbstractProgramElementTagsHandler.getAllClasses();
+        XClass cur_class = null;
+
+        Iterator iter = classes.iterator();
+
+        while (iter.hasNext()) {
+            cur_class = (XClass) iter.next();
+            setCurrentClass(cur_class);
+
+            if (AntSubTask.isAntTask(cur_class)) {
+                generate(template);
+            }
+        }
+    }
+
+    /**
+     * Iterates over all Ant attributes.
+     *
+     * @param template              XDoclet template
+     * @param attributes            Tag parameters
+     * @exception XDocletException  Oops!
+     */
+    public void forAllAttributesInGroup(String template, Properties attributes) throws XDocletException
+    {
+        // throw exception if not an Ant task
+
+        XClass cur_class = getCurrentClass();
+
+        XMethod[] methods = getAttributeMethods(cur_class);
+
+        String group = attributes.getProperty("group", DEFAULT_GROUP);
+
+        for (int i = 0; i < methods.length; i++) {
+            String value = methods[i].getDoc().getTagAttributeValue("ant.attribute", "group");
+
+            if ((value != null && value.equals(group)) || (value == null && group.equals(DEFAULT_GROUP))) {
+                setCurrentMethod(methods[i]);
+                generate(template);
+            }
+        }
+    }
+
+    /**
+     * Determines if there's at least one Ant attribute.
+     *
+     * @param template              XDoclet template
+     * @param attributes            Tag parameters
+     * @exception XDocletException  Oops!
+     */
+    public void ifHasAttributes(String template, Properties attributes) throws XDocletException
+    {
+        // throw exception if not an Ant task
+
+        XClass cur_class = getCurrentClass();
+
+        XMethod[] methods = getAttributeMethods(cur_class);
+
+        if (methods.length > 0) {
+            generate(template);
+        }
+    }
+
+    /**
+     * Iterates over all Ant nested element methods (addXXX, addConfiguredXXX, addXXX)
+     *
+     * @param template              XDoclet template
+     * @param attributes            Tag parameters
+     * @exception XDocletException  Oops!
+     */
+    public void forAllElements(String template, Properties attributes) throws XDocletException
+    {
+        // throw exception if not an Ant task
+
+        XClass cur_class = getCurrentClass();
+
+        XMethod[] methods = getElementMethods(cur_class);
+
+        for (int i = 0; i < methods.length; i++) {
+            setCurrentMethod(methods[i]);
+            generate(template);
+        }
+    }
+
+    /**
+     * Iterates over all ant.attribute.group tags.
+     *
+     * @param template           XDoclet template
+     * @param attributes         Tag parameters
+     * @throws XDocletException  Oops!
+     */
+    public void forAllAttributeGroups(String template, Properties attributes) throws XDocletException
+    {
+        Collection tags = getCurrentClass().getDoc().getTags("ant.attribute.group");
+
+        for (Iterator t = tags.iterator(); t.hasNext(); ) {
+            setCurrentClassTag((XTag) t.next());
+
+            generate(template);
+        }
+    }
+
+    /**
+     * Provides the name of a requirement group.
+     *
+     * @return                   The description of the group, or 'optional' if not is defined
+     * @throws XDocletException
+     */
+    public String attributeGroupName() throws XDocletException
+    {
+        XTag tag = getCurrentClassTag();
+        String name = tag.getAttributeValue("name");
+
+        return name != null ? name : DEFAULT_GROUP;
+    }
+
+    /**
+     * Provides the description for a requirement group.
+     *
+     * @return                   The description of the group, or 'Optional' if not is defined
+     * @throws XDocletException
+     */
+    public String attributeGroupDesc() throws XDocletException
+    {
+        XTag tag = getCurrentClassTag();
+        String desc = tag.getAttributeValue("description");
+
+        return desc != null ? desc : DESC_OPTIONAL;
+    }
+
+    /**
+     * Provides the element name for the current method
+     *
+     * @return
+     * @exception XDocletException
+     */
+    public String elementName() throws XDocletException
+    {
+        String methodName = getCurrentMethod().getName();
+        String elementName = "<not a valid element>";
+
+        if (methodName.startsWith("addConfigured")) {
+            elementName = methodName.substring(13, methodName.length());
+        }
+        else if (methodName.startsWith("add")) {
+            elementName = methodName.substring(3, methodName.length());
+        }
+        else if (methodName.startsWith("create")) {
+            elementName = methodName.substring(6, methodName.length());
+        }
+        return elementName.toLowerCase();
+    }
+
+    public String displayAttributeType() throws XDocletException
+    {
+        Collection parameters = getCurrentMethod().getParameters();
+        XParameter param = (XParameter) parameters.iterator().next();
+
+        String methodType = param.getType().getQualifiedName();
+        String display = (String) attributeDisplayMap.get(methodType);
+
+        if (display == null) {
+
+//            System.out.println("type = " + methodType);
+
+            Class clazz = getAttributeClass(methodType);
+
+            if (clazz == null) {
+                return methodType;
+            }
+
+            Object instance = null;
+
+            try {
+                instance = clazz.newInstance();
+            }
+            catch (InstantiationException e) {
+            }
+            catch (IllegalAccessException e) {
+            }
+
+            if (instance != null && instance instanceof EnumeratedAttribute) {
+                EnumeratedAttribute enum1 = (EnumeratedAttribute) instance;
+                String[] values = enum1.getValues();
+
+                display = "";
+                for (int i = 0; i < values.length; i++) {
+                    display += "&quot;" + values[i] + "&quot;";
+                    if (i != (values.length - 1)) {
+                        display += ", ";
+                    }
+                }
+                return display;
+            }
+
+            display = "";
+        }
+        return display;
+    }
+
+    public String displayElementType() throws XDocletException
+    {
+        String elementType = elementType();
+        String display = (String) elementDisplayMap.get(elementType);
+
+        if (display == null) {
+            display = "";
+        }
+        return display;
+    }
+
+    /**
+     * Provides the element type for the current method
+     *
+     * @return
+     * @exception XDocletException
+     */
+    public String elementType() throws XDocletException
+    {
+        XClass clazz = elementClassDoc();
+
+        if (clazz == null) {
+            throw new XDocletException("Method is not an Ant element!");
+        }
+        return clazz.getQualifiedName();
+    }
+
+    /**
+     * Provides the Ant task name.
+     *
+     * @return
+     * @exception XDocletException
+     * @see                         #getTaskName(xjavadoc.XClass)
+     */
+    public String taskName() throws XDocletException
+    {
+        return getTaskName(getCurrentClass());
+    }
+
+    public String propertyName()
+    {
+        return MethodTagsHandler.getPropertyNameFor(getCurrentMethod()).toLowerCase();
+    }
+
+    public String shortMethodDescription() throws XDocletException
+    {
+        String desc = getCurrentMethod().getDoc().getFirstSentence();
+
+        if (desc == null || desc.length() == 0) {
+            desc = "no description";
+        }
+
+        desc = desc.trim();
+
+        String descLower = desc.toLowerCase();
+
+        for (int i = 0; i < fluffPrefixes.length; i++) {
+            String prefix = fluffPrefixes[i].toLowerCase() + " ";
+
+            if (descLower.startsWith(prefix)) {
+                desc = desc.substring(prefix.length());
+                break;
+            }
+        }
+
+        desc = desc.substring(0, 1).toUpperCase() + desc.substring(1);
+
+        if (!desc.endsWith(".")) {
+            desc += ".";
+        }
+
+        return desc;
+    }
+
+    /**
+     * Provides the Ant category name.
+     *
+     * @return
+     * @exception XDocletException
+     * @see                         #getCategoryName(xjavadoc.XClass)
+     */
+    public String categoryName() throws XDocletException
+    {
+        return getCategoryName(getCurrentClass());
+    }
+
+    /**
+     * Provides the requirment group for the current method
+     *
+     * @return                   The group listed in the source, or 'optional' of none is listed
+     * @throws XDocletException  oops
+     */
+    public String attributeGroup() throws XDocletException
+    {
+        String value = getCurrentMethod().getDoc().getTagAttributeValue("ant.attribute", "group");
+
+        return value != null ? value : DEFAULT_GROUP;
+    }
+
+    private Class getAttributeClass(String type) throws XDocletException
+    {
+//        System.out.println("type = " + type);
+
+        Class clazz = null;
+
+        try {
+            clazz = Class.forName(type);
+        }
+        catch (ClassNotFoundException e) {
+            int lastDotPosition = type.lastIndexOf('.');
+
+            if (lastDotPosition < 0) {
+                // probably a primitive
+                return null;
+            }
+            type = type.substring(0, lastDotPosition) + "$" + type.substring(lastDotPosition + 1);
+            try {
+                clazz = Class.forName(type);
+            }
+            catch (ClassNotFoundException e1) {
+                throw new XDocletException(e1.getMessage());
+            }
+        }
+        return clazz;
+    }
+
+
+    /**
+     * @param cur_class
+     * @return
+     * @exception XDocletException
+     * @todo                        refactor to cache methods per class, and save some time
+     */
+    private XMethod[] getAttributeMethods(XClass cur_class) throws XDocletException
+    {
+        // Use Ant's own introspection mechanism to gather the
+        // attributes this class supports
+        IntrospectionHelper is = null;
+
+        try {
+            is = IntrospectionHelper.getHelper(Class.forName(cur_class.getQualifiedName()));
+        }
+        catch (ClassNotFoundException e) {
+            throw new XDocletException(e, e.getMessage());
+        }
+
+        // Regroup the attributes, since IntrospectionHelper
+        // doesn't give us the whole data structure directly
+        Enumeration enum2 = is.getAttributes();
+        Properties attributeTypeMap = new Properties();
+
+        while (enum2.hasMoreElements()) {
+            String name = (String) enum2.nextElement();
+            Class type = is.getAttributeType(name);
+
+            attributeTypeMap.setProperty(name, type.getName());
+//            System.out.println(name + " = " + type.getName());
+        }
+
+        // We need to return XMethod[] from this method
+        // so get all methods from the current class
+        XMethod[] allMethods = getMethods(cur_class);
+
+//        System.out.println("allMethods = " + allMethods.length);
+
+        // And now filter the methods based
+        // on what IntrospectionHelper says
+        List attributeMethods = new ArrayList();
+
+        for (int i = 0; i < allMethods.length; i++) {
+            XMethod method = allMethods[i];
+            String methodName = method.getName();
+
+//            System.out.println("methodName = " + methodName);
+
+            if (!methodName.startsWith("set")) {
+                continue;
+            }
+
+            String attributeName = methodName.substring(3).toLowerCase();
+
+//            System.out.println("attributeName = " + attributeName);
+
+            if ((method.getParameters().size() != 1) || (!method.isPublic())) {
+                continue;
+            }
+
+            Iterator it = method.getParameters().iterator();
+            String attributeType = ((XParameter) it.next()).getType().getQualifiedName();
+
+//            System.out.println("attributeType = " + attributeType);
+
+            String mapAttribute = attributeTypeMap.getProperty(attributeName);
+
+            if (mapAttribute == null) {
+                continue;
+            }
+
+            // inner classes are noted with $ in our map, but not
+            // n the parameter type name.
+            if (!attributeType.equals(mapAttribute.replace('$', '.'))) {
+                continue;
+            }
+
+//            System.out.println(methodName + " : " + attributeName + " : " + attributeType);
+
+            attributeMethods.add(method);
+        }
+
+        return (XMethod[]) attributeMethods.toArray(new XMethod[attributeMethods.size()]);
+    }
+
+    /**
+     * @param cur_class
+     * @return
+     * @exception XDocletException
+     * @todo                        add checks for number parameters and appropriate return value check for proper
+     *      exception too? method prefixes: add, create, addConfigured (but not addText)
+     * @todo                        add DynamicConfigurator (this should be noted in the template, not dealt with here)
+     */
+    private XMethod[] getElementMethods(XClass cur_class) throws XDocletException
+    {
+        // Use Ant's own introspection mechanism to gather the
+        // elements this class supports
+        IntrospectionHelper is = null;
+
+        try {
+            is = IntrospectionHelper.getHelper(Class.forName(cur_class.getQualifiedName()));
+        }
+        catch (ClassNotFoundException e) {
+            throw new XDocletException(e.getMessage());
+        }
+
+        // Regroup the elements, since IntrospectionHelper
+        // doesn't give us the whole data structure directly
+        Enumeration enum3 = is.getNestedElements();
+        Properties elementTypeMap = new Properties();
+
+        while (enum3.hasMoreElements()) {
+            String name = (String) enum3.nextElement();
+            Class type = is.getElementType(name);
+
+            elementTypeMap.setProperty(name, type.getName());
+//            System.out.println(name + " = " + type.getName());
+        }
+
+        // We need to return MethodDoc[] from this method
+        // so get all methods from the current class
+        XMethod[] allMethods = getMethods(cur_class);
+
+        // And now filter the MethodDoc's based
+        // on what IntrospectionHelper says
+        List elementMethods = new ArrayList();
+
+        for (int i = 0; i < allMethods.length; i++) {
+            XMethod method = allMethods[i];
+            String methodName = method.getName();
+
+            // Object create(), void add(Object), void addConfigured(Object)
+            String elementName = null;
+
+            // true if addXXX or addConfiguredXXX
+            boolean adder = false;
+
+            if (methodName.startsWith("create")) {
+                elementName = methodName.substring(6).toLowerCase();
+            }
+
+            if (methodName.startsWith("add")) {
+                int length = 3;
+
+                if (methodName.startsWith("addConfigured")) {
+                    length = 13;
+                }
+
+                elementName = methodName.substring(length).toLowerCase();
+                adder = true;
+            }
+
+            if (elementName == null) {
+                continue;
+            }
+
+//            System.out.println("elementName = " + elementName);
+
+            String elementType = null;
+
+            if (adder) {
+                if (method.getParameters().size() != 1) {
+                    continue;
+                }
+                Iterator it = method.getParameters().iterator();
+                elementType = ((XParameter) it.next()).getType().getQualifiedName();
+            }
+            else {
+                elementType = method.getReturnType().getType().getQualifiedName();
+            }
+
+            if (!method.isPublic()) {
+                continue;
+            }
+
+            String mapElementType = elementTypeMap.getProperty(elementName);
+
+//            System.out.println("elementType = " + elementType + " mapElementType = " + mapElementType);
+            if (mapElementType == null) {
+                continue;
+            }
+
+            // inner classes are noted with $ in our map, but not
+            // the parameter type name.
+            if (!elementType.equals(mapElementType.replace('$', '.'))) {
+                continue;
+            }
+
+            elementMethods.add(method);
+        }
+
+        return (XMethod[]) elementMethods.toArray(new XMethod[elementMethods.size()]);
+    }
+
+    /**
+     * This is a slightly refactored (thank you IntelliJ) version of some cut-and-paste from XDoclet code. It sorts all
+     * methods together rather than in batches of superclasses like XDoclet stuff does.
+     *
+     * @param cur_class
+     * @return
+     */
+    private XMethod[] getMethods(XClass cur_class)
+    {
+        Map already = new HashMap();
+
+        List methods = new ArrayList();
+
+        while (cur_class != null) {
+            // hardcoded to stop when it hits Task, nothing there
+            // or above that needs to be processed
+            if (cur_class.getQualifiedName().equals("org.apache.tools.ant.Task") ||
+                cur_class.getQualifiedName().equals("org.apache.tools.ant.taskdefs.MatchingTask")) {
+                break;
+            }
+
+            Collection curMethods = cur_class.getMethods();
+
+            Iterator iter = curMethods.iterator();
+
+            while (iter.hasNext()) {
+                XMethod method = (XMethod) iter.next();
+
+                if (isDeprecated(method)) {
+                    continue;
+                }
+                if (shouldIgnore(method)) {
+                    continue;
+                }
+
+                String methodName = method.getName();
+
+//                System.out.println("method = " + method + ":" + methodName);
+
+                if (method.getContainingClass() == cur_class) {
+                    if (already.containsKey(methodName) == false) {
+                        already.put(methodName, method);
+                        methods.add(method);
+                    }
+                }
+            }
+
+            cur_class = cur_class.getSuperclass();
+        }
+
+        return sortMethods(methods);
+    }
+
+    private boolean isDeprecated(XMethod method)
+    {
+        Collection tags = method.getDoc().getTags();
+        Iterator iter = tags.iterator();
+
+        while (iter.hasNext()) {
+            XTag tag = (XTag) iter.next();
+
+            if (tag.getName().equals("@deprecated")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Provides the element type for the current method. If the return type is null, the first parameter is used.
+     *
+     * @return
+     */
+    private XClass elementClassDoc()
+    {
+        XClass clazz = null;
+        String methodName = getCurrentMethod().getName();
+
+        if (methodName.startsWith("addConfigured") ||
+            methodName.startsWith("add") ||
+            methodName.startsWith("create")) {
+            clazz = getCurrentMethod().getReturnType().getType();
+            if ("void".equals(clazz.getName())) {
+                Collection params = getCurrentMethod().getParameters();
+
+                if (params.size() == 1) {
+                    Iterator it = params.iterator();
+                    clazz = ((XParameter)it.next()).getType();
+                }
+            }
+        }
+//        System.out.println(methodName + ": clazz = " + clazz.getQualifiedName());
+        return clazz;
+    }
+
+    /**
+     * For now, lump attributes and elements together since we won't have those tags on the same method.
+     *
+     * @param method
+     * @return        True if the method should be ignored.
+     */
+    private boolean shouldIgnore(XMethod method)
+    {
+        String value = method.getDoc().getTagAttributeValue("ant.attribute", "ignore");
+
+        if ("true".equals(value)) {
+            return true;
+        }
+
+        value = method.getDoc().getTagAttributeValue("ant.element", "ignore");
+        if ("true".equals(value)) {
+            return true;
+        }
+        return false;
+    }
+
+    private XMethod[] sortMethods(List methods)
+    {
+        //sort methods
+        Collections.sort(methods,
+            new Comparator()
+            {
+                public int compare(Object o1, Object o2)
+                {
+                    XMethod m1 = (XMethod) o1;
+                    XMethod m2 = (XMethod) o2;
+
+                    return m1.getName().compareTo(m2.getName());
+                }
+
+
+                public boolean equals(Object obj)
+                {
+                    //dumb
+                    return obj == this;
+                }
+            });
+
+        return (XMethod[]) methods.toArray(new XMethod[methods.size()]);
+    }
+}
+
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/task_xml.xdt b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/task_xml.xdt
new file mode 100644
index 0000000..ec4564a
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/task_xml.xdt
@@ -0,0 +1,92 @@
+<task name="<XDtAnt:taskName/>" category="<XDtAnt:categoryName/>"
+      classname="<XDtClass:fullClassName/>"
+      <XDtClass:ifHasClassTag tagName="deprecated">deprecated="true"</XDtClass:ifHasClassTag>
+      <XDtType:ifIsOfType type="org.apache.tools.ant.taskdefs.MatchingTask">matchingTask="true"</XDtType:ifIsOfType>>
+
+  <XDtMerge:merge file="{0}.xml" generateMergedFile="false">
+    <!-- no merge file present -->
+  </XDtMerge:merge>
+
+  <short-description><![CDATA[<XDtClass:firstSentenceDescription/>]]></short-description>
+  <long-description>
+    <![CDATA[<XDtClass:classComment no-comment-signs="true"/>]]>
+  </long-description>
+
+  <structure>
+
+      <attribute-groups>
+
+        <attribute-group name="required"
+                         description="Required">
+            <XDtAnt:forAllAttributesInGroup group="required">
+              <attribute name="<XDtAnt:propertyName/>"
+                         type="<XDtParameter:forAllMethodParams><XDtParameter:methodParamType/></XDtParameter:forAllMethodParams>"
+                         <XDtMethod:ifHasMethodTag tagName="deprecated">deprecated="true"</XDtMethod:ifHasMethodTag>
+                         briefType="<XDtAnt:displayAttributeType/>">
+                         <short-description><![CDATA[<XDtAnt:shortMethodDescription/>]]></short-description>
+                         <description><![CDATA[<XDtMethod:methodComment no-comment-signs="true"/>]]></description>
+              </attribute>
+            </XDtAnt:forAllAttributesInGroup>
+        </attribute-group>
+
+        <XDtAnt:forAllAttributeGroups>
+          <attribute-group name="<XDtAnt:attributeGroupName/>"
+                           description="<XDtAnt:attributeGroupDesc/>">
+            <XDtAnt:forAllAttributesInGroup group="<XDtAnt:attributeGroupName/>">
+              <attribute name="<XDtAnt:propertyName/>"
+                         type="<XDtParameter:forAllMethodParams><XDtParameter:methodParamType/></XDtParameter:forAllMethodParams>"
+                         <XDtMethod:ifHasMethodTag tagName="deprecated">deprecated="true"</XDtMethod:ifHasMethodTag>
+                         briefType="<XDtAnt:displayAttributeType/>">
+                         <short-description><![CDATA[<XDtAnt:shortMethodDescription/>]]></short-description>
+                         <description><![CDATA[<XDtMethod:methodComment no-comment-signs="true"/>]]></description>
+              </attribute>
+            </XDtAnt:forAllAttributesInGroup>
+          </attribute-group>
+        </XDtAnt:forAllAttributeGroups>
+
+        <attribute-group name="optional"
+                         description="Optional">
+            <XDtAnt:forAllAttributesInGroup group="optional">
+              <attribute name="<XDtAnt:propertyName/>"
+                         type="<XDtParameter:forAllMethodParams><XDtParameter:methodParamType/></XDtParameter:forAllMethodParams>"
+                         <XDtMethod:ifHasMethodTag tagName="deprecated">deprecated="true"</XDtMethod:ifHasMethodTag>
+                         briefType="<XDtAnt:displayAttributeType/>">
+                         <short-description><![CDATA[<XDtAnt:shortMethodDescription/>]]></short-description>
+                         <description><![CDATA[<XDtMethod:methodComment no-comment-signs="true"/>]]></description>
+              </attribute>
+            </XDtAnt:forAllAttributesInGroup>
+        </attribute-group>
+
+      </attribute-groups>
+
+    <elements>
+
+      <XDtAnt:forAllElements>
+        <element name="<XDtAnt:elementName/>" type="<XDtAnt:elementType/>"
+                 <XDtMethod:ifHasMethodTag tagName="deprecated">deprecated="true"</XDtMethod:ifHasMethodTag>
+                 briefType="<XDtAnt:displayElementType/>"
+          <XDtClass:pushClass value="<XDtAnt:elementType/>">
+            <XDtClass:ifIsClassAbstract>abstract="true"</XDtClass:ifIsClassAbstract>>
+          </XDtClass:pushClass>
+          <short-description><![CDATA[<XDtAnt:shortMethodDescription/>]]></short-description>
+          <description>
+            <![CDATA[<XDtMethod:methodComment no-comment-signs="true"/>]]>
+          </description>
+        </element>
+      </XDtAnt:forAllElements>
+
+    </elements>
+
+    <XDtMethod:setCurrentMethod name="addText" parameters="java.lang.String">
+      <body <XDtMethod:ifHasMethodTag tagName="deprecated">deprecated="true"</XDtMethod:ifHasMethodTag>>
+        <description><![CDATA[
+          <XDtMethod:methodComment no-comment-signs="true"/>
+        ]]></description>
+      </body>
+    </XDtMethod:setCurrentMethod>
+
+  </structure>
+
+</task>
+
+
diff --git a/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/taskdef_properties.xdt b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/taskdef_properties.xdt
new file mode 100644
index 0000000..09d21c4
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/ant/xdoclet/resources/taskdef_properties.xdt
@@ -0,0 +1,2 @@
+<XDtAnt:forAllTasks><XDtAnt:taskName/>=<XDtClass:fullClassName/>
+</XDtAnt:forAllTasks>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/ConditionTask.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/ConditionTask.xml
new file mode 100644
index 0000000..60b112b
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/ConditionTask.xml
@@ -0,0 +1,54 @@
+<!-- Condition task -->
+<external>
+<description>
+
+<p>Sets a property if a certain condition holds true - this is a
+generalization of <a href="available.html">Available</a> and <a
+href="uptodate.html">Uptodate</a>.</p>
+<p>If the condition holds true, the property value is set to true by
+default; otherwise, the property is not set. You can set the value to
+something other than the default by specifying the <code>value</code>
+attribute.</p>
+<p>Conditions are specified as <a href="#nested">nested elements</a>,
+you must specify exactly one condition.</p>
+
+</description>
+
+<section anchor="examples" name="Examples">
+
+<pre>
+  &lt;condition property=&quot;javamail.complete&quot;&gt;
+    &lt;and&gt;
+      &lt;available classname=&quot;javax.activation.DataHandler&quot; /&gt;
+      &lt;available classname=&quot;javax.mail.Transport&quot; /&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>javamail.complete</code> if both the
+JavaBeans Activation Framework and JavaMail are available in the
+classpath.</p>
+
+<pre>
+  &lt;condition property=&quot;isMacOsButNotMacOsX&quot;&gt;
+    &lt;and&gt;
+      &lt;os family=&quot;mac&quot; />
+      &lt;not&gt;
+        &lt;os family=&quot;unix&quot; />
+      &lt;/not&gt;
+    &lt;/and&gt;
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>isMacOsButNotMacOsX</code> if the current
+operating system is MacOS, but not MacOS X - which Ant considers to be
+in the Unix family as well.</p>
+
+<pre>
+  &lt;condition property=&quot;isSunOSonSparc&quot;&gt;
+    &lt;os name=&quot;SunOS&quot; arch=&quot;sparc&quot; />
+  &lt;/condition&gt;
+</pre>
+<p>sets the property <code>isSunOSonSparc</code> if the current
+operating system is SunOS and if it is running on a sparc architecture.</p>
+
+</section>
+</external>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javac.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javac.xml
new file mode 100644
index 0000000..c2b314e
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javac.xml
@@ -0,0 +1,195 @@
+<!-- javac task -->
+<external>
+<description>
+
+<p>Compiles a Java source tree.</p>
+
+<p>The source and destination directory will be recursively scanned for Java
+source files to compile. Only Java files that have no corresponding class file
+or where the class file is older than the java file will be compiled.</p>
+
+<p>Note: Ant uses only the names of the source and class files to find
+the classes that need a rebuild. It will not scan the source and therefor
+will have no knowledge about nested classes, classes that are named different
+from the source file and so on.</p>
+
+<p>The directory structure of the source tree should follow the package
+hierarchy.</p>
+
+<p>It is possible to refine the set of files that are being compiled/copied.
+This can be done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i>
+attributes. With the <i>includes</i> or <i>includesfile</i> attribute you specify the files you want to
+have included by using patterns. The <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+the files you want to have excluded. This is also done with patterns. And
+finally with the <i>defaultexcludes</i> attribute, you can specify whether you
+want to use default exclusions or not. See the section on <a
+href="../dirtasks.html#directorybasedtasks">directory based tasks</a>, on how the
+inclusion/exclusion of files works, and how to write patterns.</p>
+
+<p>It is possible to use different compilers. This can be selected with the
+&quot;build.compiler&quot; property or the compiler attribute. Here are the choices:-</p>
+<ul>
+  <li>classic (the standard compiler of JDK 1.1/1.2) - javac1.1 and
+     javac1.2 can be used as aliases</li>
+  <li>modern (the standard compiler of JDK 1.3/1.4) - javac1.3 and
+     javac1.4 can be used as aliases</li>
+  <li>jikes (the <a
+    href="http://oss.software.ibm.com/developerworks/opensource/jikes/project" target="_top">Jikes</a>
+    compiler)</li>
+  <li>jvc (the Command-Line Compiler from Microsoft's SDK for Java /
+    Visual J++) - microsoft can be used as an alias</li>
+  <li>kjc (the <a href="http://www.dms.at/kopi/" target="_top">kopi</a>
+    compiler)</li>
+  <li>gcj (the gcj compiler from gcc)</li>
+  <li>sj (Symantec java compiler) - symantec can be used as an alias</li>
+  <li>extJavac (run either modern or classic in a JVM of its own)</li>
+</ul>
+<p>For JDK 1.1/1.2, classic is the default. For JDK 1.3/1.4, modern is the default.
+If you wish to use a different compiler interface than those
+supplied, write a class that implements the CompilerAdapter interface
+(package org.apache.tools.ant.taskdefs.compilers). Supply the full
+classname in the &quot;build.compiler&quot; property.</p>
+
+<p>The fork attribute overrides the build.compiler setting and expects
+a JDK1.1 or higher to be set in java.home.</p>
+
+<p>This task will drop all entries that point to non-existent
+files/directories from the CLASSPATH it passes to the compiler.</p>
+
+<p><strong>Windows Note:</strong>When the modern compiler is used
+in unforked mode on Windows, it locks up the files present in the
+classpath of the &lt;javac&gt; task, and does not release them.  The side
+effect of this is that you will not be able to delete or move
+those files later on in the build.  The workaround is to fork when
+invoking the compiler.</p>
+
+</description>
+
+<section anchor="examples" name="Examples">
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores
+the <code>.class</code> files in the <code>${build}</code> directory.
+The classpath used contains <code>xyz.jar</code>, and debug information is on.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         fork=&quot;true&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores the <code>.class</code> files in the
+<code>${build}</code> directory.  This will fork off the javac
+compiler using the default javac executable.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         fork=&quot;java$$javac.exe&quot;
+  /&gt;</pre>
+<p>compiles all <code>.java</code> files under the <code>${src}</code>
+directory, and stores the <code>.class</code> files in the
+<code>${build}</code> directory.  This will fork off the javac
+compiler using the executable named <code>java$javac.exe</code>.  Note
+that the <code>$</code> sign needs to be escaped by a second one.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}&quot;
+         destdir=&quot;${build}&quot;
+         includes=&quot;mypackage/p1/**,mypackage/p2/**&quot;
+         excludes=&quot;mypackage/p1/testpackage/**&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+  /&gt;</pre>
+<p>compiles <code>.java</code> files under the <code>${src}</code>
+directory, and stores the
+<code>.class</code> files in the <code>${build}</code> directory.
+The classpath used contains <code>xyz.jar</code>, and debug information is on.
+Only files under <code>mypackage/p1</code> and <code>mypackage/p2</code> are
+used. Files in the <code>mypackage/p1/testpackage</code> directory are excluded
+from compilation.</p>
+
+<pre>  &lt;javac srcdir=&quot;${src}:${src2}&quot;
+         destdir=&quot;${build}&quot;
+         includes=&quot;mypackage/p1/**,mypackage/p2/**&quot;
+         excludes=&quot;mypackage/p1/testpackage/**&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;
+  /&gt;</pre>
+
+<p>is the same as the previous example, with the addition of a second
+source path, defined by
+the property <code>src2</code>. This can also be represented using nested
+<code>&lt;src&gt;</code> elements as follows:</p>
+
+<pre>  &lt;javac destdir=&quot;${build}&quot;
+         classpath=&quot;xyz.jar&quot;
+         debug=&quot;on&quot;&gt;
+    &lt;src path=&quot;${src}&quot;/&gt;
+    &lt;src path=&quot;${src2}&quot;/&gt;
+    &lt;include name=&quot;mypackage/p1/**&quot;/&gt;
+    &lt;include name=&quot;mypackage/p2/**&quot;/&gt;
+    &lt;exclude name=&quot;mypackage/p1/testpackage/**&quot;/&gt;
+  &lt;/javac&gt;</pre>
+
+<p><b>Note:</b> If you are using Ant on Windows and a new DOS window pops up
+for every use of an external compiler, this may be a problem of the JDK you are using.
+This problem may occur with all JDKs &lt; 1.2.</p>
+
+<p><b>Note:</b> If you wish to compile only source-files located in some packages below a
+common root you should not include these packages in the srcdir-attribute. Use include/exclude-attributes
+or elements to filter for these packages. If you include part of your package-structure inside the srcdir-attribute
+(or nested src-elements) Ant will start to recompile your sources every time you call it.</p>
+
+</section>
+
+<section anchor="jikes" name="Jikes Notes">
+
+<p>Jikes supports some extra options, which can be set be defining
+properties prior to invoking the task. The ant developers are aware that
+this is ugly and inflexible -expect a better solution in the future. All
+the options are boolean, and must be set to &quot;true&quot; or &quot;yes&quot; to be
+interpreted as anything other than false; by default
+build.compiler.warnings is &quot;true&quot; while all others are &quot;false&quot;</p>
+
+<table border="1" cellpadding="2" cellspacing="0">
+  <tr>
+    <td valign="top">
+	build.compiler.emacs
+	</td>
+	<td valign="top">
+	Enable emacs compatible error messages
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.warnings<br />
+        <b>This property has been deprecated, use the nowarn attribute
+          instead</b>
+	</td>
+	<td valign="top">
+	don't disable warning messages
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.pedantic
+	</td>
+	<td valign="top">
+	enable pedantic warnings
+    </td>
+  </tr>
+  <tr>
+    <td valign="top">
+	build.compiler.fulldepend
+	</td>
+	<td valign="top">
+	enable full dependency checking,<br />
+	&quot;+F&quot; in the jikes manual.
+    </td>
+  </tr>
+</table>
+
+</section>
+</external>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javadoc.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javadoc.xml
new file mode 100644
index 0000000..509ec7f
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Javadoc.xml
@@ -0,0 +1,59 @@
+<!-- javadoc task -->
+<external>
+<description>
+
+<p>Generates code documentation using the javadoc tool.</p>
+
+<p>The source directory will be recursively scanned for Java source files to process
+but only those matching the inclusion rules, and not matching the exclusions rules
+will be passed to the javadoc tool. This
+allows wildcards to be used to choose between package names, reducing verbosity
+and management costs over time. This task, however, has no notion of
+&quot;changed&quot; files, unlike the <a href="javac.html">javac</a> task. This means
+all packages will be processed each time this task is run. In general, however,
+this task is used much less frequently.</p>
+
+<p>This task works seamlessly between different javadoc versions (1.1 and 1.2),
+with the obvious restriction that the 1.2 attributes will be ignored if run in a
+1.1 VM.</p>
+
+<p>NOTE: since javadoc calls System.exit(), javadoc cannot be run inside the
+same VM as ant without breaking functionality. For this reason, this task
+always forks the VM. This overhead is not significant since javadoc is normally a heavy
+application and will be called infrequently.</p>
+
+<p>NOTE: the packagelist attribute allows you to specify the list of packages to
+document outside of the Ant file. It's a much better practice to include everything
+inside the build.xml file. This option was added in order to make it easier to
+migrate from regular makefiles, where you would use this option of javadoc.
+The packages listed in packagelist are not checked, so the task performs even
+if some packages are missing or broken. Use this option if you wish to convert from
+an existing makefile. Once things are running you should then switch to the regular
+notation. </p>
+
+<p><i><b>DEPRECATION:</b> the javadoc2 task simply points to the javadoc task and it's
+there for back compatibility reasons. Since this task will be removed in future
+versions, you are strongly encouraged to use <a href="javadoc.html">javadoc</a>
+instead.</i></p>
+</description>
+
+<section anchor="examples" name="Example">
+<pre>  &lt;javadoc packagenames=&quot;com.dummy.test.*&quot;
+           sourcepath=&quot;src&quot;
+           excludepackagenames=&quot;com.dummy.test.doc-files.*&quot;
+           defaultexcludes=&quot;yes&quot;
+           destdir=&quot;docs/api&quot;
+           author=&quot;true&quot;
+           version=&quot;true&quot;
+           use=&quot;true&quot;
+           windowtitle=&quot;Test API&quot;&gt;
+    &lt;doctitle&gt;&lt;![CDATA[&lt;h1&gt;Test&lt;/h1&gt;]]&gt;&lt;/doctitle&gt;
+    &lt;bottom&gt;&lt;![CDATA[&lt;i&gt;Copyright &amp;#169; 2000 Dummy Corp. All Rights Reserved.&lt;/i&gt;]]&gt;&lt;/bottom&gt;
+    &lt;tag name=&quot;todo&quot; scope=&quot;all&quot; description=&quot;To do:&quot; /&gt;
+    &lt;group title=&quot;Group 1 Packages&quot; packages=&quot;com.dummy.test.a*&quot;/&gt;
+    &lt;group title=&quot;Group 2 Packages&quot; packages=&quot;com.dummy.test.b*:com.dummy.test.c*&quot;/&gt;
+    &lt;link offline=&quot;true&quot; href=&quot;http://java.sun.com/products/jdk/1.2/docs/api/&quot; packagelistLoc=&quot;C:\tmp&quot;/&gt;
+    &lt;link href=&quot;http://developer.java.sun.com/developer/products/xml/docs/api/&quot;/&gt;
+  &lt;/javadoc&gt;</pre>
+</section>
+</external>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Property.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Property.xml
new file mode 100644
index 0000000..29e2f2d
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Property.xml
@@ -0,0 +1,65 @@
+<!-- property task -->
+<external>
+<description>
+
+<p>Sets a property (by name and value), or set of properties (from file or resource) in the project.</p>
+
+<p>Properties are case sensitive.</p>
+
+<p>Properties are immutable: whoever sets a property first freezes it for the rest of the build; they are most definately not variable.</p>
+
+<p>There are five ways to set properties:
+  <ul>
+    <li>By supplying both the name and value attribute.</li>
+    <li>By supplying both the name and refid attribute.</li>
+    <li>By setting the file attribute with the filename of the property file to load. This property file has the format as defined by the file used in the class java.util.Properties.</li>
+    <li>By setting the resource attribute with the resource name of the property file to load. This property file has the format as defined by the file used in the class java.util.Properties.</li>
+    <li>By setting the environment attribute with a prefix to use. Properties will be defined for every environment variable by prefixing the supplied name and a period to the name of the variable.</li>
+  </ul>
+</p>  
+<p>Although combinations of these ways are possible, only one should be used at a time. Problems might occur with the order in which properties are set, for instance.</p>
+
+<p>The value part of the properties being set, might contain references to other properties. These references are resolved at the time these properties are set. This also holds for properties loaded from a property file.</p>
+
+<p>A list of predefined properties can be found here.</p>
+
+</description>
+
+<section anchor="examples" name="Examples">
+    <source><![CDATA[
+    <property name="foo.dist" value="dist"/>
+        ]]></source>
+<p>sets the property <code>foo.dist</code> to the value &quot;dist&quot;.</p>
+    <source><![CDATA[
+    <property file="foo.properties"/>
+        ]]></source>
+<p>reads a set of properties from a file called &quot;foo.properties&quot;.</p>
+    <source><![CDATA[
+    <property resource="foo.properties"/>
+        ]]></source>
+<p>reads a set of properties from a resource called &quot;foo.properties&quot;.</p>
+<p>Note that you can reference a global properties file for all of your Ant
+builds using the following:</p>
+    <source><![CDATA[
+    <property file="${user.home}/.ant-global.properties"/>
+        ]]></source>
+<p>since the &quot;user.home&quot; property is defined by the Java virtual machine
+to be your home directory.  Where the &quot;user.home&quot; property resolves to in
+the file system depends on the operating system version and the JVM implementation.
+On Unix based systems, this will map to the user's home directory. On modern Windows
+variants, this will most likely resolve to the user's directory in the &quot;Documents
+and Settings&quot; folder. Older windows variants such as Windows 98/ME are less 
+predictable, as are other operating system/JVM combinations.</p>
+
+<source><![CDATA[
+  <property environment="env">
+  <echo message="Number of Processors = ${env.NUMBER_OF_PROCESSORS}">
+  <echo message="ANT_HOME is set to = ${env.ANT_HOME}">
+]]></source>
+<p>reads the system environment variables and stores them in properties, prefixed with &quot;env&quot;.
+Note that this only works on <em>select</em> operating systems.
+Two of the values are shown being echoed. 
+</p>
+
+</section>
+</external>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml
new file mode 100644
index 0000000..981eaf8
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/SubAnt.xml
@@ -0,0 +1,129 @@
+<external>
+    <description>
+        <p>
+            Calls a given target for all defined sub-builds.
+            This is an extension
+            of ant for bulk project execution.
+
+            <strong>This task must no be used outside of a
+                <code>target</code> if it invokes the same build file it is
+                part of.</strong>
+        </p>
+        <subsection name="Use with directories">
+            <p>
+                subant can be used with directory sets to execute a build from different directories.
+                2 different options are offered :
+            </p>
+            <ul>
+                <li>
+                    to run the same build file <code>/somepath/otherpath/mybuild.xml</code>
+                    with different base directories, use the genericantfile attribute
+                </li>
+                <li>if you want to run <code>directory1/mybuild.xml</code>, <code>directory2/mybuild.xml</code>, <code>....</code>,
+                    use the antfile attribute. The subant task does not set the base directory for you in this case, because you can specify it in each build file.
+                </li>
+            </ul>
+        </subsection>
+     </description>
+    <section anchor="examples" name="Examples">
+        <pre>
+        &lt;project name="subant" default="subant1"&gt;
+        &lt;property name="build.dir" value="subant.build"/&gt;
+        &lt;target name="subant1"&gt;
+            &lt;subant target=""&gt;
+              &lt;property name="build.dir" value="subant1.build"/&gt;
+              &lt;property name="not.overloaded" value="not.overloaded"/&gt;
+              &lt;fileset dir="." includes="*/build.xml"/&gt;
+            &lt;/subant&gt;
+        &lt;/target&gt;
+        &lt;/project&gt;
+        </pre>
+        <p>
+            this snippet build file will run ant in each subdirectory of the project directory,
+            where a file called build.xml can be found.
+            The property build.dir will have the value subant1.build in the ant projects called by subant.
+        </p>
+        <pre>
+          &lt;subant target=""&gt;
+             &lt;propertyset&gt;
+                  &lt;propertyref prefix="toplevel"/&gt;
+                  &lt;mapper type="glob" from="foo*" to="bar*"/&gt;
+             &lt;/propertyset&gt;
+             &lt;fileset dir="." includes="*/build.xml"/&gt;
+          &lt;/subant&gt;
+        </pre>
+        <p>
+            this snippet build file will run ant in each subdirectory of the project directory,
+            where a file called build.xml can be found.
+            All properties whose name starts with &quot;foo&quot; are passed, their names are changed to start with &quot;bar&quot; instead
+        </p>
+        <pre>
+          &lt;subant target="compile" genericantfile="/opt/project/build1.xml"&gt;
+             &lt;dirset dir="." includes="projects*"/&gt;
+          &lt;/subant&gt;
+        </pre>
+        <p>
+            assuming the subdirs of the project dir are called projects1, projects2, projects3
+            this snippet will execute the compile target of /opt/project/build1.xml,
+            setting the basedir to projects1, projects2, projects3
+        </p>
+        <p>Now a little more complex - but useful - scenario. Assume that we have
+        a directory structure like this:</p>
+        <pre>
+        root
+          |  common.xml
+          |  build.xml
+          |
+          +-- modules
+                +-- modA
+                |     +-- src
+                +-- modB
+                      +-- src
+
+        <u><b>common.xml:</b></u><br/>
+        &lt;project&gt;
+            &lt;property name="src.dir"      value="src"/&gt;
+            &lt;property name="build.dir"    value="build"/&gt;
+            &lt;property name="classes.dir"  value="${build.dir}/classes"/&gt;
+
+            &lt;target name="compile"&gt;
+                &lt;mkdir dir="${classes.dir}"/&gt;
+                &lt;javac srcdir="${src.dir}" destdir="${classes.dir}"/&gt;
+            &lt;/target&gt;
+
+            &lt;!-- more targets --&gt;
+        &lt;/project&gt;
+
+        <u><b>build.xml:</b></u><br/>
+        &lt;project&gt;
+
+            &lt;macrodef name="iterate"&gt;
+                &lt;attribute name="target"/&gt;
+                &lt;sequential&gt;
+                    &lt;subant target="@{target}"&gt;
+                        &lt;fileset dir="modules" includes="*/build.xml"/&gt;
+                    &lt;/subant&gt;
+                &lt;/sequential&gt;
+            &lt;/macrodef&gt;
+
+
+            &lt;target name="compile"&gt;
+                &lt;iterate target="compile"/&gt;
+            &lt;/target&gt;
+
+            &lt;!-- more targets --&gt;
+        &lt;/project&gt;
+
+        <u><b>modules/modA/build.xml:</b></u><br/>
+        &lt;project name="modA"&gt;
+            &lt;import file="../../common.xml"/&gt;
+        &lt;/project&gt;
+        </pre>
+
+        <p>This results in very small buildfiles in the modules, maintainable
+        buildfile (common.xml) and a clear project structure. Additionally
+        the root buildfile is capable to run the whole build over all
+        modules.
+        </p>
+    </section>
+</external>
\ No newline at end of file
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Tar.xml b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Tar.xml
new file mode 100644
index 0000000..856537a
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Tar.xml
@@ -0,0 +1,111 @@
+<!-- tar task -->
+<external>
+<description>
+<p>Creates a tar archive.</p>
+
+<p>The <i>basedir</i> attribute is the reference directory from where to tar.</p>
+
+<p>This task is a <a href="../dirtasks.html#directorybasedtasks">directory based task</a>
+and, as such, forms an implicit <a href="../CoreTypes/fileset.html">Fileset</a>. This
+defines which files, relative to the <i>basedir</i>, will be included in the
+archive. The tar task supports all the attributes of Fileset to refine the
+set of files to be included in the implicit fileset.</p>
+
+<p>In addition to the implicit fileset, the tar task supports nested filesets. These
+filesets are extended to allow control over the access mode, username and groupname
+to be applied to the tar entries. This is useful, for example, when preparing archives for
+Unix systems where some files need to have execute permission.</p>
+
+<p>Early versions of tar did not support path lengths greater than 100
+characters. Modern versions of tar do so, but in incompatible ways.
+The behaviour of the tar task when it encounters such paths is
+controlled by the <i>longfile</i> attribute.
+If the longfile attribute is set to <code>fail</code>, any long paths will
+cause the tar task to fail.  If the longfile attribute is set to
+<code>truncate</code>, any long paths will be truncated to the 100 character
+maximum length prior to adding to the archive. If the value of the longfile
+attribute is set to <code>omit</code> then files containing long paths will be
+omitted from the archive.  Either option ensures that the archive can be
+untarred by any compliant version of tar. If the loss of path or file
+information is not acceptable, and it rarely is, longfile may be set to the
+value <code>gnu</code>. The tar task will then produce a GNU tar file which
+can have arbitrary length paths. Note however, that the resulting archive will
+only be able to be untarred with GNU tar.  The default for the longfile
+attribute is <code>warn</code> which behaves just like the gnu option except
+that it produces a warning for each file path encountered that does not match
+the limit.</p>
+
+<p>Note that this task does not perform compression. You might want to use the
+<a href="gzip.html">GZip</a> task to prepare a .tar.gz package.</p>
+</description>
+
+<section anchor="examples" name="Examples">
+<pre>  &lt;tar tarfile=&quot;${dist}/manual.tar&quot; basedir=&quot;htdocs/manual&quot;/&gt;
+  &lt;gzip zipfile=&quot;${dist}/manual.tar.gz&quot; src=&quot;${dist}/manual.tar&quot;/&gt;</pre>
+<p>tars all files in the <code>htdocs/manual</code> directory into a file called <code>manual.tar</code>
+in the <code>${dist}</code>  directory, then applies the gzip task to compress
+it.</p>
+<pre>  &lt;tar destfile=&quot;${dist}/manual.tar&quot;
+       basedir=&quot;htdocs/manual&quot;
+       excludes=&quot;mydocs/**, **/todo.html&quot;
+  /&gt;</pre>
+<p>tars all files in the <code>htdocs/manual</code> directory into a file called <code>manual.tar</code>
+in the <code>${dist}</code> directory. Files in the directory <code>mydocs</code>,
+or files with the name <code>todo.html</code> are excluded.</p>
+
+<pre>
+&lt;tar destfile=&quot;${basedir}/docs.tar&quot;&gt;
+  &lt;tarfileset dir=&quot;${dir.src}/docs&quot;
+              fullpath=&quot;/usr/doc/ant/README&quot;
+              preserveLeadingSlashes=&quot;true&quot;&gt;
+    &lt;include name=&quot;readme.txt&quot;/&gt;
+  &lt;/tarfileset&gt;
+  &lt;tarfileset dir=&quot;${dir.src}/docs&quot;
+              prefix=&quot;/usr/doc/ant&quot;
+              preserveLeadingSlashes=&quot;true&quot;&gt;
+    &lt;include name=&quot;*.html&quot;/&gt;
+  &lt;/tarfileset&gt;
+&lt;/tar&gt;</pre>
+
+<p>
+  Writes the file <code>docs/readme.txt</code> as
+  <code>/usr/doc/ant/README</code> into the archive. All
+  <code>*.html</code> files in the <code>docs</code> directory are
+  prefixed by <code>/usr/doc/ant</code>, so for example
+  <code>docs/index.html</code> is written as
+  <code>/usr/doc/ant/index.html</code> to the archive.
+</p>
+
+
+<pre>&lt;tar longfile=&quot;gnu&quot;
+     destfile=&quot;${dist.base}/${dist.name}-src.tar&quot; &gt;
+  &lt;tarfileset dir=&quot;${dist.name}/..&quot; mode=&quot;755&quot; username=&quot;ant&quot; group=&quot;ant&quot;&gt;
+    &lt;include name=&quot;${dist.name}/bootstrap.sh&quot;/&gt;
+    &lt;include name=&quot;${dist.name}/build.sh&quot;/&gt;
+  &lt;/tarfileset&gt;
+  &lt;tarfileset dir=&quot;${dist.name}/..&quot; username=&quot;ant&quot; group=&quot;ant&quot;&gt;
+    &lt;include name=&quot;${dist.name}/**&quot;/&gt;
+    &lt;exclude name=&quot;${dist.name}/bootstrap.sh&quot;/&gt;
+    &lt;exclude name=&quot;${dist.name}/build.sh&quot;/&gt;
+  &lt;/tarfileset&gt;
+&lt;/tar&gt; </pre>
+
+<p>This example shows building a tar which uses the GNU extensions for long paths and
+where some files need to be marked as executable (mode 755)
+and the rest are use the default mode (read-write by owner). The first
+fileset selects just the executable files. The second fileset must exclude
+the executable files and include all others. </p>
+
+<p><strong>Note: </strong> The tar task does not ensure that a file is only selected
+by one fileset. If the same file is selected by more than one fileset, it will be included in the
+tar file twice, with the same path.</p>
+
+<p><strong>Note:</strong> The patterns in the include and exclude
+elements are considered to be relative to the corresponding dir
+attribute as with all other filesets.  In the example above,
+<code>${dist.name}</code> is not an absolute path, but a simple name
+of a directory, so <code>${dist.name}</code> is a valid path relative
+to <code>${dist.name}/..</code>.</p>
+
+</section>
+</external>
diff --git a/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Test.java b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Test.java
new file mode 100644
index 0000000..2430a80
--- /dev/null
+++ b/trunk/proposal/xdocs/src/org/apache/tools/ant/taskdefs/Test.java
@@ -0,0 +1,67 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 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/>.
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+
+/**
+ * @ant:task name="test"
+ */
+public class Test {
+    private String value;
+    
+    public void setValue (String value) {
+        this.value = value;
+    }
+}
diff --git a/trunk/proposal/xdocs/templates/datatype_xdoc.template b/trunk/proposal/xdocs/templates/datatype_xdoc.template
new file mode 100644
index 0000000..748d544
--- /dev/null
+++ b/trunk/proposal/xdocs/templates/datatype_xdoc.template
@@ -0,0 +1,49 @@
+<XDtTagDef:tagDef namespace="AntDatatype" handler="org.apache.tools.ant.xdoclet.DatatypeTagsHandler"/>
+<XDtTagDef:tagDef namespace="AntTask" handler="org.apache.tools.ant.xdoclet.TaskTagsHandler"/>
+<datatype name="<XDtAntDatatype:typeName/>"
+          classname="<XDtClass:fullClassName/>">
+  <short-description><![CDATA[<XDtClass:firstSentenceDescription/>]]></short-description>
+  <long-description>
+    <![CDATA[<XDtClass:classComment no-comment-signs="true"/>]]>
+  </long-description>
+
+  <structure>
+
+    <attributes>
+    <XDtAntTask:forAllAttributes>
+      <attribute name="<XDtMethod:propertyName/>" type="<XDtParameter:forAllMethodParams><XDtParameter:methodParamType/></XDtParameter:forAllMethodParams>">
+        <description><![CDATA[
+          <XDtMethod:methodComment no-comment-signs="true"/>
+        ]]></description>
+      </attribute>
+    </XDtAntTask:forAllAttributes>
+    </attributes>
+
+    <elements>
+    <XDtAntTask:forAllElements>
+      <element name="<XDtAntTask:elementName/>" type="<XDtAntTask:elementType/>">
+        <description>
+          <![CDATA[<XDtMethod:methodComment no-comment-signs="true"/>]]>
+        </description>
+        <XDtClass:pushClass value="<XDtAntTask:elementType/>">
+        <XDtAntTask:ifHasAttributes>
+        <attributes>
+          <XDtAntTask:forAllAttributes>
+          <attribute name="<XDtMethod:propertyName/>" type="<XDtParameter:forAllMethodParams><XDtParameter:methodParamType/></XDtParameter:forAllMethodParams>">
+            <description><![CDATA[
+              <XDtMethod:methodComment no-comment-signs="true"/>
+            ]]></description>
+          </attribute>
+          </XDtAntTask:forAllAttributes>
+        </attributes>
+        </XDtAntTask:ifHasAttributes>
+        </XDtClass:pushClass>
+      </element>
+
+    </XDtAntTask:forAllElements>
+    </elements>
+
+    </structure>
+</datatype>
+
+
diff --git a/trunk/proposal/xdocs/templates/type_defaults_properties.template b/trunk/proposal/xdocs/templates/type_defaults_properties.template
new file mode 100644
index 0000000..3e1cf72
--- /dev/null
+++ b/trunk/proposal/xdocs/templates/type_defaults_properties.template
@@ -0,0 +1,3 @@
+<XDtTagDef:tagDef namespace="Ant" handler="org.apache.tools.ant.xdoclet.DatatypeTagsHandler"/>
+<XDtAnt:forAllDatatypes><XDtAnt:typeName/>=<XDtClass:fullClassName/>
+</XDtAnt:forAllDatatypes>
diff --git a/trunk/src/antidote/WHAT-IS-THIS-P b/trunk/src/antidote/WHAT-IS-THIS-P
new file mode 100644
index 0000000..6384ad4
--- /dev/null
+++ b/trunk/src/antidote/WHAT-IS-THIS-P
@@ -0,0 +1,6 @@
+This /used/ to be the home of Antidote, the GUI for Ant. It has moved
+(or rather, graduate) to the cvs module ant-antidote, and must
+be retrieved separately from Ant, but can be found in the same place you found
+source version of Ant.
+
+-- The Antidote Team --
diff --git a/trunk/src/etc/ant-bin.wxs b/trunk/src/etc/ant-bin.wxs
new file mode 100644
index 0000000..f050aa1
--- /dev/null
+++ b/trunk/src/etc/ant-bin.wxs
@@ -0,0 +1,461 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!-- generated by tallow.exe
+
+     tallow.exe -d dist/lib -d dist/bin -d dist/etc -d dist/docs -dav -nologo > src/etc/ant-bin.wxs
+
+     after that I've removed the javadocs (too many directories I
+     would have had to created GUIDs for) added GUIDs, changed the
+     top-level directory reference, changed id of the manual
+     directory, removed index.html from it and finally made the File
+     entries valid by adding DiskId attributes.
+
+     Yes, we need a task to automate this.
+-->
+<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
+  <Fragment>
+    <DirectoryRef Id="INSTALLDIR">
+      <Directory Id="directory0" Name="lib">
+        <Component Id="component0" DiskId="1" Guid="F0D9EDBA-4CE3-4660-A826-A197B598DE31">
+          <File DiskId="1" Id="file0" Name="ANT-AN_1.JAR" LongName="ant-antlr.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-antlr.jar" />
+          <File DiskId="1" Id="file1" Name="ANFAFB_1.JAR" LongName="ant-apache-bcel.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-bcel.jar" />
+          <File DiskId="1" Id="file2" Name="AND873_1.JAR" LongName="ant-apache-bsf.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-bsf.jar" />
+          <File DiskId="1" Id="file3" Name="ANT-AP_4.JAR" LongName="ant-apache-log4j.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-log4j.jar" />
+          <File DiskId="1" Id="file4" Name="ANT-AP_3.JAR" LongName="ant-apache-oro.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-oro.jar" />
+          <File DiskId="1" Id="file5" Name="ANT-AP_1.JAR" LongName="ant-apache-regexp.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-regexp.jar" />
+          <File DiskId="1" Id="file6" Name="ANT-AP_2.JAR" LongName="ant-apache-resolver.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-apache-resolver.jar" />
+          <File DiskId="1" Id="file7" Name="ANT-CO_1.JAR" LongName="ant-commons-logging.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-commons-logging.jar" />
+          <File DiskId="1" Id="file8" Name="ANT-CO_2.JAR" LongName="ant-commons-net.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-commons-net.jar" />
+          <File DiskId="1" Id="file9" Name="ant-jai.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-jai.jar" />
+          <File DiskId="1" Id="file10" Name="ANT-JA_1.JAR" LongName="ant-javamail.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-javamail.jar" />
+          <File DiskId="1" Id="file11" Name="ANT-JD_1.JAR" LongName="ant-jdepend.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-jdepend.jar" />
+          <File DiskId="1" Id="file12" Name="ant-jmf.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-jmf.jar" />
+          <File DiskId="1" Id="file13" Name="ant-jsch.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-jsch.jar" />
+          <File DiskId="1" Id="file14" Name="ANT-JU_1.JAR" LongName="ant-junit.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-junit.jar" />
+          <File DiskId="1" Id="file15" Name="ANT-LA_1.JAR" LongName="ant-launcher.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-launcher.jar" />
+          <File DiskId="1" Id="file16" Name="ANT-NE_1.JAR" LongName="ant-netrexx.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-netrexx.jar" />
+          <File DiskId="1" Id="file17" Name="ANT-NO_1.JAR" LongName="ant-nodeps.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-nodeps.jar" />
+          <File DiskId="1" Id="file18" Name="ANT-ST_2.JAR" LongName="ant-starteam.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-starteam.jar" />
+          <File DiskId="1" Id="file19" Name="ANT-ST_1.JAR" LongName="ant-stylebook.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-stylebook.jar" />
+          <File DiskId="1" Id="file20" Name="ANT-SW_1.JAR" LongName="ant-swing.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-swing.jar" />
+          <File DiskId="1" Id="file21" Name="ant-trax.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-trax.jar" />
+          <File DiskId="1" Id="file22" Name="ANT-WE_1.JAR" LongName="ant-weblogic.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-weblogic.jar" />
+          <File DiskId="1" Id="file23" Name="ANT-XA_1.JAR" LongName="ant-xalan1.jar" Vital="yes" src="$(var.dist.dir)/lib\ant-xalan1.jar" />
+          <File DiskId="1" Id="file24" Name="ant.jar" Vital="yes" src="$(var.dist.dir)/lib\ant.jar" />
+          <File DiskId="1" Id="file25" Name="LIBRAR_1.PRO" LongName="libraries.properties" Vital="yes" src="$(var.dist.dir)/lib\libraries.properties" />
+          <File DiskId="1" Id="file26" Name="README" Vital="yes" src="$(var.dist.dir)/lib\README" />
+          <File DiskId="1" Id="file27" Name="XERCES_1.JAR" LongName="xercesImpl.jar" Vital="yes" src="$(var.dist.dir)/lib\xercesImpl.jar" />
+          <File DiskId="1" Id="file28" Name="xml-apis.jar" Vital="yes" src="$(var.dist.dir)/lib\xml-apis.jar" />
+        </Component>
+      </Directory>
+      <Directory Id="directory1" Name="bin">
+        <Component Id="component1" DiskId="1" Guid="B1C93EBD-96B8-46c8-9CBD-246CB8964F89">
+          <File DiskId="1" Id="file29" Name="ant" Vital="yes" src="$(var.dist.dir)/bin\ant" />
+          <File DiskId="1" Id="file30" Name="ant.bat" Vital="yes" src="$(var.dist.dir)/bin\ant.bat" />
+          <File DiskId="1" Id="file31" Name="ant.cmd" Vital="yes" src="$(var.dist.dir)/bin\ant.cmd" />
+          <File DiskId="1" Id="file32" Name="antenv.cmd" Vital="yes" src="$(var.dist.dir)/bin\antenv.cmd" />
+          <File DiskId="1" Id="file33" Name="antRun" Vital="yes" src="$(var.dist.dir)/bin\antRun" />
+          <File DiskId="1" Id="file34" Name="antRun.bat" Vital="yes" src="$(var.dist.dir)/bin\antRun.bat" />
+          <File DiskId="1" Id="file35" Name="antRun.pl" Vital="yes" src="$(var.dist.dir)/bin\antRun.pl" />
+          <File DiskId="1" Id="file36" Name="COMPLE_1.PL" LongName="complete-ant-cmd.pl" Vital="yes" src="$(var.dist.dir)/bin\complete-ant-cmd.pl" />
+          <File DiskId="1" Id="file37" Name="envset.cmd" Vital="yes" src="$(var.dist.dir)/bin\envset.cmd" />
+          <File DiskId="1" Id="file38" Name="lcp.bat" Vital="yes" src="$(var.dist.dir)/bin\lcp.bat" />
+          <File DiskId="1" Id="file39" Name="runant.pl" Vital="yes" src="$(var.dist.dir)/bin\runant.pl" />
+          <File DiskId="1" Id="file40" Name="runant.py" Vital="yes" src="$(var.dist.dir)/bin\runant.py" />
+          <File DiskId="1" Id="file41" Name="runrc.cmd" Vital="yes" src="$(var.dist.dir)/bin\runrc.cmd" />
+        </Component>
+      </Directory>
+      <Directory Id="directory2" Name="docs">
+        <Component Id="component2" DiskId="1" Guid="3C4A5D18-7D5F-4d98-B810-83EE3EC47468">
+          <File DiskId="1" Id="file42" Name="ANTNEW_1.HTM" LongName="antnews.html" Vital="yes" src="$(var.dist.dir)/docs\antnews.html" />
+          <File DiskId="1" Id="file43" Name="ANT_IN_1.HTM" LongName="ant_in_anger.html" Vital="yes" src="$(var.dist.dir)/docs\ant_in_anger.html" />
+          <File DiskId="1" Id="file44" Name="ANT_TA_1.HTM" LongName="ant_task_guidelines.html" Vital="yes" src="$(var.dist.dir)/docs\ant_task_guidelines.html" />
+          <File DiskId="1" Id="file45" Name="APPEND_1.PDF" LongName="appendix_e.pdf" Vital="yes" src="$(var.dist.dir)/docs\appendix_e.pdf" />
+          <File DiskId="1" Id="file46" Name="BREADC_1.JS" LongName="breadcrumbs.js" Vital="yes" src="$(var.dist.dir)/docs\breadcrumbs.js" />
+          <File DiskId="1" Id="file47" Name="BUGS_1.HTM" LongName="bugs.html" Vital="yes" src="$(var.dist.dir)/docs\bugs.html" />
+          <File DiskId="1" Id="file48" Name="BYLAWS_1.HTM" LongName="bylaws.html" Vital="yes" src="$(var.dist.dir)/docs\bylaws.html" />
+          <File DiskId="1" Id="file49" Name="CONTRI_1.HTM" LongName="contributors.html" Vital="yes" src="$(var.dist.dir)/docs\contributors.html" />
+          <File DiskId="1" Id="file50" Name="EXTERN_1.HTM" LongName="external.html" Vital="yes" src="$(var.dist.dir)/docs\external.html" />
+          <File DiskId="1" Id="file51" Name="FAQ_1.HTM" LongName="faq.html" Vital="yes" src="$(var.dist.dir)/docs\faq.html" />
+          <File DiskId="1" Id="file52" Name="favicon.ico" Vital="yes" src="$(var.dist.dir)/docs\favicon.ico" />
+          <File DiskId="1" Id="file53" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\index.html" />
+          <File DiskId="1" Id="file54" Name="LEGAL_1.HTM" LongName="legal.html" Vital="yes" src="$(var.dist.dir)/docs\legal.html" />
+          <File DiskId="1" Id="file55" Name="LICENSE" Vital="yes" src="$(var.dist.dir)/docs\LICENSE" />
+          <File DiskId="1" Id="file56" Name="LICENS_1.HTM" LongName="license.html" Vital="yes" src="$(var.dist.dir)/docs\license.html" />
+          <File DiskId="1" Id="file57" Name="MAIL_1.HTM" LongName="mail.html" Vital="yes" src="$(var.dist.dir)/docs\mail.html" />
+          <File DiskId="1" Id="file58" Name="MISSIO_1.HTM" LongName="mission.html" Vital="yes" src="$(var.dist.dir)/docs\mission.html" />
+          <File DiskId="1" Id="file59" Name="page.css" Vital="yes" src="$(var.dist.dir)/docs\page.css" />
+          <File DiskId="1" Id="file60" Name="PROBLE_1.HTM" LongName="problems.html" Vital="yes" src="$(var.dist.dir)/docs\problems.html" />
+          <File DiskId="1" Id="file61" Name="PROJEC_1.HTM" LongName="projects.html" Vital="yes" src="$(var.dist.dir)/docs\projects.html" />
+          <File DiskId="1" Id="file62" Name="RESOUR_1.HTM" LongName="resources.html" Vital="yes" src="$(var.dist.dir)/docs\resources.html" />
+          <File DiskId="1" Id="file63" Name="SVN_1.HTM" LongName="svn.html" Vital="yes" src="$(var.dist.dir)/docs\svn.html" />
+        </Component>
+        <Directory Id="directory3" Name="ant2">
+          <Component Id="component3" DiskId="1" Guid="B0B46EDA-078C-4042-802D-0FD43ECC51EC">
+            <File DiskId="1" Id="file64" Name="ACTION_1.HTM" LongName="actionlist.html" Vital="yes" src="$(var.dist.dir)/docs\ant2\actionlist.html" />
+            <File DiskId="1" Id="file65" Name="FEATUR_1.HTM" LongName="features.html" Vital="yes" src="$(var.dist.dir)/docs\ant2\features.html" />
+            <File DiskId="1" Id="file66" Name="FUNCTI_1.HTM" LongName="FunctionalRequirements.html" Vital="yes" src="$(var.dist.dir)/docs\ant2\FunctionalRequirements.html" />
+            <File DiskId="1" Id="file67" Name="ORIGIN_1.HTM" LongName="original-specification.html" Vital="yes" src="$(var.dist.dir)/docs\ant2\original-specification.html" />
+            <File DiskId="1" Id="file68" Name="REQUES_1.HTM" LongName="requested-features.html" Vital="yes" src="$(var.dist.dir)/docs\ant2\requested-features.html" />
+            <File DiskId="1" Id="file69" Name="REQUES_1.TXT" LongName="requested-features.txt" Vital="yes" src="$(var.dist.dir)/docs\ant2\requested-features.txt" />
+            <File DiskId="1" Id="file70" Name="VFS.txt" Vital="yes" src="$(var.dist.dir)/docs\ant2\VFS.txt" />
+          </Component>
+        </Directory>
+        <Directory Id="directory4" Name="antlibs">
+          <Component Id="component4" DiskId="1" Guid="3A955A77-B40C-4fdf-89F2-0B8ED71B3C9B">
+            <File DiskId="1" Id="file71" Name="CHARTE_1.HTM" LongName="charter.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\charter.html" />
+            <File DiskId="1" Id="file72" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\index.html" />
+            <File DiskId="1" Id="file73" Name="PROPER_1.HTM" LongName="proper.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\proper.html" />
+            <File DiskId="1" Id="file74" Name="SANDBO_1.HTM" LongName="sandbox.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\sandbox.html" />
+          </Component>
+          <Directory Id="directory5" Name="antunit">
+            <Component Id="component5" DiskId="1" Guid="001EC157-1971-4371-91D1-67438148BE4F">
+              <File DiskId="1" Id="file75" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\antunit\index.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory6" Name="dotnet">
+            <Component Id="component6" DiskId="1" Guid="946324D1-7A08-429b-9866-C88A7AFEC34B">
+              <File DiskId="1" Id="file76" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\dotnet\index.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory7" Name="svn">
+            <Component Id="component7" DiskId="1" Guid="92069BFE-0095-4570-A49F-3AFA2A37C65A">
+              <File DiskId="1" Id="file77" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\antlibs\svn\index.html" />
+            </Component>
+          </Directory>
+        </Directory>
+        <Directory Id="directory8" Name="images">
+          <Component Id="component8" DiskId="1" Guid="CD77BA2D-BC86-4dfa-9DB3-ED1A13F1C742">
+            <File DiskId="1" Id="file78" Name="ant_logo.ico" Vital="yes" src="$(var.dist.dir)/docs\images\ant_logo.ico" />
+            <File DiskId="1" Id="file79" Name="ANT_LO_3.GIF" LongName="ant_logo_large.gif" Vital="yes" src="$(var.dist.dir)/docs\images\ant_logo_large.gif" />
+            <File DiskId="1" Id="file80" Name="ANT_LO_1.GIF" LongName="ant_logo_medium.gif" Vital="yes" src="$(var.dist.dir)/docs\images\ant_logo_medium.gif" />
+            <File DiskId="1" Id="file81" Name="ANT_LO_2.GIF" LongName="ant_logo_small.gif" Vital="yes" src="$(var.dist.dir)/docs\images\ant_logo_small.gif" />
+            <File DiskId="1" Id="file82" Name="beta.png" Vital="yes" src="$(var.dist.dir)/docs\images\beta.png" />
+            <File DiskId="1" Id="file83" Name="current.gif" Vital="yes" src="$(var.dist.dir)/docs\images\current.gif" />
+            <File DiskId="1" Id="file84" Name="GROUP-_1.GIF" LongName="group-logo.gif" Vital="yes" src="$(var.dist.dir)/docs\images\group-logo.gif" />
+            <File DiskId="1" Id="file85" Name="JDJEDI_1.JPG" LongName="JDJEditorsChoiceAward.jpg" Vital="yes" src="$(var.dist.dir)/docs\images\JDJEditorsChoiceAward.jpg" />
+            <File DiskId="1" Id="file86" Name="JP_RCW_1.GIF" LongName="jp_rcwinner_2003.gif" Vital="yes" src="$(var.dist.dir)/docs\images\jp_rcwinner_2003.gif" />
+            <File DiskId="1" Id="file87" Name="JW_EC__2.GIF" LongName="jw_ec_logo_winner2002.gif" Vital="yes" src="$(var.dist.dir)/docs\images\jw_ec_logo_winner2002.gif" />
+            <File DiskId="1" Id="file88" Name="JW_EC__1.GIF" LongName="jw_ec_logo_winner2003.gif" Vital="yes" src="$(var.dist.dir)/docs\images\jw_ec_logo_winner2003.gif" />
+            <File DiskId="1" Id="file89" Name="label.gif" Vital="yes" src="$(var.dist.dir)/docs\images\label.gif" />
+            <File DiskId="1" Id="file90" Name="MENU-L_1.GIF" LongName="menu-left.gif" Vital="yes" src="$(var.dist.dir)/docs\images\menu-left.gif" />
+            <File DiskId="1" Id="file91" Name="MENU-R_1.GIF" LongName="menu-right.gif" Vital="yes" src="$(var.dist.dir)/docs\images\menu-right.gif" />
+            <File DiskId="1" Id="file92" Name="page.gif" Vital="yes" src="$(var.dist.dir)/docs\images\page.gif" />
+            <File DiskId="1" Id="file93" Name="printer.gif" Vital="yes" src="$(var.dist.dir)/docs\images\printer.gif" />
+            <File DiskId="1" Id="file94" Name="PROJEC_1.GIF" LongName="project-logo.gif" Vital="yes" src="$(var.dist.dir)/docs\images\project-logo.gif" />
+            <File DiskId="1" Id="file95" Name="SDM_PR_1.GIF" LongName="sdm_productivity_award.gif" Vital="yes" src="$(var.dist.dir)/docs\images\sdm_productivity_award.gif" />
+            <File DiskId="1" Id="file96" Name="SEARCH_1.GIF" LongName="search-left.gif" Vital="yes" src="$(var.dist.dir)/docs\images\search-left.gif" />
+            <File DiskId="1" Id="file97" Name="SEARCH_2.GIF" LongName="search-right.gif" Vital="yes" src="$(var.dist.dir)/docs\images\search-right.gif" />
+            <File DiskId="1" Id="file98" Name="spacer.gif" Vital="yes" src="$(var.dist.dir)/docs\images\spacer.gif" />
+            <File DiskId="1" Id="file99" Name="tab-left.gif" Vital="yes" src="$(var.dist.dir)/docs\images\tab-left.gif" />
+            <File DiskId="1" Id="file100" Name="TAB-RI_1.GIF" LongName="tab-right.gif" Vital="yes" src="$(var.dist.dir)/docs\images\tab-right.gif" />
+            <File DiskId="1" Id="file101" Name="TABSEL_1.GIF" LongName="tabSel-left.gif" Vital="yes" src="$(var.dist.dir)/docs\images\tabSel-left.gif" />
+            <File DiskId="1" Id="file102" Name="TABSEL_2.GIF" LongName="tabSel-right.gif" Vital="yes" src="$(var.dist.dir)/docs\images\tabSel-right.gif" />
+          </Component>
+        </Directory>
+        <Directory Id="manual" Name="manual">
+          <Component Id="component9" DiskId="1" Guid="75121217-770F-4a38-97FC-8F44779ACA9C">
+            <File DiskId="1" Id="file103" Name="ANTEXT_1.HTM" LongName="antexternal.html" Vital="yes" src="$(var.dist.dir)/docs\manual\antexternal.html" />
+            <File DiskId="1" Id="file104" Name="ANTTAS_1.HTM" LongName="anttaskslist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\anttaskslist.html" />
+            <File DiskId="1" Id="file105" Name="BASE_T_1.HTM" LongName="base_task_classes.html" Vital="yes" src="$(var.dist.dir)/docs\manual\base_task_classes.html" />
+            <File DiskId="1" Id="file106" Name="CLONEV_1.HTM" LongName="clonevm.html" Vital="yes" src="$(var.dist.dir)/docs\manual\clonevm.html" />
+            <File DiskId="1" Id="file107" Name="CONCEP_1.HTM" LongName="conceptstypeslist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\conceptstypeslist.html" />
+            <File DiskId="1" Id="file108" Name="CORETA_1.HTM" LongName="coretasklist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\coretasklist.html" />
+            <File DiskId="1" Id="file109" Name="COVER_1.HTM" LongName="cover.html" Vital="yes" src="$(var.dist.dir)/docs\manual\cover.html" />
+            <File DiskId="1" Id="file110" Name="CREDIT_1.HTM" LongName="credits.html" Vital="yes" src="$(var.dist.dir)/docs\manual\credits.html" />
+            <File DiskId="1" Id="file111" Name="DEVELO_1.HTM" LongName="develop.html" Vital="yes" src="$(var.dist.dir)/docs\manual\develop.html" />
+            <File DiskId="1" Id="file112" Name="DEVELO_2.HTM" LongName="developlist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\developlist.html" />
+            <File DiskId="1" Id="file113" Name="DIRTAS_1.HTM" LongName="dirtasks.html" Vital="yes" src="$(var.dist.dir)/docs\manual\dirtasks.html" />
+            <File DiskId="1" Id="file114" Name="favicon.ico" Vital="yes" src="$(var.dist.dir)/docs\manual\favicon.ico" />
+            <File DiskId="1" Id="file115" Name="FEEDBA_1.HTM" LongName="feedback.html" Vital="yes" src="$(var.dist.dir)/docs\manual\feedback.html" />
+            <File DiskId="1" Id="file116" Name="IDE_1.HTM" LongName="ide.html" Vital="yes" src="$(var.dist.dir)/docs\manual\ide.html" />
+            <File DiskId="1" Id="file118" Name="INPUTH_1.HTM" LongName="inputhandler.html" Vital="yes" src="$(var.dist.dir)/docs\manual\inputhandler.html" />
+            <File DiskId="1" Id="file119" Name="INSTAL_1.HTM" LongName="install.html" Vital="yes" src="$(var.dist.dir)/docs\manual\install.html" />
+            <File DiskId="1" Id="file120" Name="INSTAL_2.HTM" LongName="installlist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\installlist.html" />
+            <File DiskId="1" Id="file121" Name="INTRO_1.HTM" LongName="intro.html" Vital="yes" src="$(var.dist.dir)/docs\manual\intro.html" />
+            <File DiskId="1" Id="file122" Name="JAVACP_1.HTM" LongName="javacprops.html" Vital="yes" src="$(var.dist.dir)/docs\manual\javacprops.html" />
+            <File DiskId="1" Id="file123" Name="LICENSE" Vital="yes" src="$(var.dist.dir)/docs\manual\LICENSE" />
+            <File DiskId="1" Id="file124" Name="LISTEN_1.HTM" LongName="listeners.html" Vital="yes" src="$(var.dist.dir)/docs\manual\listeners.html" />
+            <File DiskId="1" Id="file125" Name="OPTION_1.HTM" LongName="optionaltasklist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\optionaltasklist.html" />
+            <File DiskId="1" Id="file126" Name="PLATFO_1.HTM" LongName="platform.html" Vital="yes" src="$(var.dist.dir)/docs\manual\platform.html" />
+            <File DiskId="1" Id="file127" Name="PROXY_1.HTM" LongName="proxy.html" Vital="yes" src="$(var.dist.dir)/docs\manual\proxy.html" />
+            <File DiskId="1" Id="file128" Name="RUNNIN_2.HTM" LongName="running.html" Vital="yes" src="$(var.dist.dir)/docs\manual\running.html" />
+            <File DiskId="1" Id="file129" Name="RUNNIN_1.HTM" LongName="runninglist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\runninglist.html" />
+            <File DiskId="1" Id="file130" Name="SYSCLA_1.HTM" LongName="sysclasspath.html" Vital="yes" src="$(var.dist.dir)/docs\manual\sysclasspath.html" />
+            <File DiskId="1" Id="file131" Name="TASKSO_1.HTM" LongName="tasksoverview.html" Vital="yes" src="$(var.dist.dir)/docs\manual\tasksoverview.html" />
+            <File DiskId="1" Id="file132" Name="TOC_1.HTM" LongName="toc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\toc.html" />
+            <File DiskId="1" Id="file133" Name="TUTORI_1.HTM" LongName="tutorial-HelloWorldWithAnt.html" Vital="yes" src="$(var.dist.dir)/docs\manual\tutorial-HelloWorldWithAnt.html" />
+            <File DiskId="1" Id="file134" Name="TUTORI_3.HTM" LongName="tutorial-tasks-filesets-properties.html" Vital="yes" src="$(var.dist.dir)/docs\manual\tutorial-tasks-filesets-properties.html" />
+            <File DiskId="1" Id="file135" Name="TUTORI_1.ZIP" LongName="tutorial-tasks-filesets-properties.zip" Vital="yes" src="$(var.dist.dir)/docs\manual\tutorial-tasks-filesets-properties.zip" />
+            <File DiskId="1" Id="file136" Name="TUTORI_2.ZIP" LongName="tutorial-writing-tasks-src.zip" Vital="yes" src="$(var.dist.dir)/docs\manual\tutorial-writing-tasks-src.zip" />
+            <File DiskId="1" Id="file137" Name="TUTORI_2.HTM" LongName="tutorial-writing-tasks.html" Vital="yes" src="$(var.dist.dir)/docs\manual\tutorial-writing-tasks.html" />
+            <File DiskId="1" Id="file138" Name="USING_1.HTM" LongName="using.html" Vital="yes" src="$(var.dist.dir)/docs\manual\using.html" />
+            <File DiskId="1" Id="file139" Name="USINGL_1.HTM" LongName="usinglist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\usinglist.html" />
+          </Component>
+          <Directory Id="directory89" Name="CORETA_1" LongName="CoreTasks">
+            <Component Id="component86" DiskId="1" Guid="5853F9CD-8B34-410d-80DD-9595C9EA9AB5">
+              <File DiskId="1" Id="file399" Name="ANT_1.HTM" LongName="ant.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\ant.html" />
+              <File DiskId="1" Id="file400" Name="ANTCAL_1.HTM" LongName="antcall.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\antcall.html" />
+              <File DiskId="1" Id="file401" Name="ANTSTR_1.HTM" LongName="antstructure.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\antstructure.html" />
+              <File DiskId="1" Id="file402" Name="APPLY_1.HTM" LongName="apply.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\apply.html" />
+              <File DiskId="1" Id="file403" Name="APT_1.HTM" LongName="apt.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\apt.html" />
+              <File DiskId="1" Id="file404" Name="AVAILA_1.HTM" LongName="available.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\available.html" />
+              <File DiskId="1" Id="file405" Name="BASENA_1.HTM" LongName="basename.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\basename.html" />
+              <File DiskId="1" Id="file406" Name="BUILDN_1.HTM" LongName="buildnumber.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\buildnumber.html" />
+              <File DiskId="1" Id="file407" Name="CHANGE_1.HTM" LongName="changelog.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\changelog.html" />
+              <File DiskId="1" Id="file408" Name="CHECKS_1.HTM" LongName="checksum.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\checksum.html" />
+              <File DiskId="1" Id="file409" Name="CHMOD_1.HTM" LongName="chmod.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\chmod.html" />
+              <File DiskId="1" Id="file410" Name="COMMON_1.HTM" LongName="common.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\common.html" />
+              <File DiskId="1" Id="file411" Name="CONCAT_1.HTM" LongName="concat.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\concat.html" />
+              <File DiskId="1" Id="file412" Name="CONDIT_1.HTM" LongName="condition.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\condition.html" />
+              <File DiskId="1" Id="file413" Name="CONDIT_2.HTM" LongName="conditions.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\conditions.html" />
+              <File DiskId="1" Id="file414" Name="COPY_1.HTM" LongName="copy.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\copy.html" />
+              <File DiskId="1" Id="file415" Name="COPYDI_1.HTM" LongName="copydir.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\copydir.html" />
+              <File DiskId="1" Id="file416" Name="COPYFI_1.HTM" LongName="copyfile.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\copyfile.html" />
+              <File DiskId="1" Id="file417" Name="CVS_1.HTM" LongName="cvs.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\cvs.html" />
+              <File DiskId="1" Id="file418" Name="CVSPAS_1.HTM" LongName="cvspass.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\cvspass.html" />
+              <File DiskId="1" Id="file419" Name="CVSTAG_1.HTM" LongName="cvstagdiff.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\cvstagdiff.html" />
+              <File DiskId="1" Id="file420" Name="CVSVER_1.HTM" LongName="cvsversion.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\cvsversion.html" />
+              <File DiskId="1" Id="file421" Name="DEFAUL_1.HTM" LongName="defaultexcludes.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\defaultexcludes.html" />
+              <File DiskId="1" Id="file422" Name="DELETE_1.HTM" LongName="delete.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\delete.html" />
+              <File DiskId="1" Id="file423" Name="DELTRE_1.HTM" LongName="deltree.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\deltree.html" />
+              <File DiskId="1" Id="file424" Name="DEPEND_1.HTM" LongName="dependset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\dependset.html" />
+              <File DiskId="1" Id="file425" Name="DIRNAM_1.HTM" LongName="dirname.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\dirname.html" />
+              <File DiskId="1" Id="file426" Name="EAR_1.HTM" LongName="ear.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\ear.html" />
+              <File DiskId="1" Id="file427" Name="ECHO_1.HTM" LongName="echo.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\echo.html" />
+              <File DiskId="1" Id="file428" Name="ECHOXM_1.HTM" LongName="echoxml.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\echoxml.html" />
+              <File DiskId="1" Id="file429" Name="EXEC_1.HTM" LongName="exec.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\exec.html" />
+              <File DiskId="1" Id="file430" Name="FAIL_1.HTM" LongName="fail.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\fail.html" />
+              <File DiskId="1" Id="file431" Name="FILTER_1.HTM" LongName="filter.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\filter.html" />
+              <File DiskId="1" Id="file432" Name="FIXCRL_1.HTM" LongName="fixcrlf.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\fixcrlf.html" />
+              <File DiskId="1" Id="file433" Name="GENKEY_1.HTM" LongName="genkey.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\genkey.html" />
+              <File DiskId="1" Id="file434" Name="GET_1.HTM" LongName="get.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\get.html" />
+              <File DiskId="1" Id="file435" Name="GUNZIP_1.HTM" LongName="gunzip.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\gunzip.html" />
+              <File DiskId="1" Id="file436" Name="GZIP_1.HTM" LongName="gzip.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\gzip.html" />
+              <File DiskId="1" Id="file437" Name="IMPORT_1.HTM" LongName="import.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\import.html" />
+              <File DiskId="1" Id="file438" Name="INPUT_1.HTM" LongName="input.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\input.html" />
+              <File DiskId="1" Id="file439" Name="JAR_1.HTM" LongName="jar.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\jar.html" />
+              <File DiskId="1" Id="file440" Name="JAVA_1.HTM" LongName="java.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\java.html" />
+              <File DiskId="1" Id="file441" Name="JAVAC_1.HTM" LongName="javac.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\javac.html" />
+              <File DiskId="1" Id="file442" Name="JAVADO_1.HTM" LongName="javadoc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\javadoc.html" />
+              <File DiskId="1" Id="file443" Name="LENGTH_1.HTM" LongName="length.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\length.html" />
+              <File DiskId="1" Id="file444" Name="LIBRAR_1.HTM" LongName="libraries.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\libraries.html" />
+              <File DiskId="1" Id="file445" Name="LOADFI_1.HTM" LongName="loadfile.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\loadfile.html" />
+              <File DiskId="1" Id="file446" Name="LOADPR_1.HTM" LongName="loadproperties.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\loadproperties.html" />
+              <File DiskId="1" Id="file447" Name="LOADRE_1.HTM" LongName="loadresource.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\loadresource.html" />
+              <File DiskId="1" Id="file448" Name="MACROD_1.HTM" LongName="macrodef.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\macrodef.html" />
+              <File DiskId="1" Id="file449" Name="MAIL_1.HTM" LongName="mail.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\mail.html" />
+              <File DiskId="1" Id="file450" Name="MAKEUR_1.HTM" LongName="makeurl.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\makeurl.html" />
+              <File DiskId="1" Id="file451" Name="MANIFE_1.HTM" LongName="manifest.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\manifest.html" />
+              <File DiskId="1" Id="file452" Name="MANIFE_2.HTM" LongName="manifestclasspath.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\manifestclasspath.html" />
+              <File DiskId="1" Id="file453" Name="MKDIR_1.HTM" LongName="mkdir.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\mkdir.html" />
+              <File DiskId="1" Id="file454" Name="MOVE_1.HTM" LongName="move.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\move.html" />
+              <File DiskId="1" Id="file455" Name="NICE_1.HTM" LongName="nice.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\nice.html" />
+              <File DiskId="1" Id="file456" Name="PACK_1.HTM" LongName="pack.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\pack.html" />
+              <File DiskId="1" Id="file457" Name="PARALL_1.HTM" LongName="parallel.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\parallel.html" />
+              <File DiskId="1" Id="file458" Name="PATCH_1.HTM" LongName="patch.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\patch.html" />
+              <File DiskId="1" Id="file459" Name="PATHCO_1.HTM" LongName="pathconvert.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\pathconvert.html" />
+              <File DiskId="1" Id="file460" Name="PRESET_1.HTM" LongName="presetdef.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\presetdef.html" />
+              <File DiskId="1" Id="file461" Name="PROPER_1.HTM" LongName="property.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\property.html" />
+              <File DiskId="1" Id="file462" Name="RECORD_1.HTM" LongName="recorder.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\recorder.html" />
+              <File DiskId="1" Id="file463" Name="RENAME_1.HTM" LongName="rename.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\rename.html" />
+              <File DiskId="1" Id="file464" Name="REPLAC_1.HTM" LongName="replace.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\replace.html" />
+              <File DiskId="1" Id="file465" Name="RESOUR_1.HTM" LongName="resourcecount.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\resourcecount.html" />
+              <File DiskId="1" Id="file466" Name="RMIC_1.HTM" LongName="rmic.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\rmic.html" />
+              <File DiskId="1" Id="file467" Name="SEQUEN_1.HTM" LongName="sequential.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\sequential.html" />
+              <File DiskId="1" Id="file468" Name="SIGNJA_1.HTM" LongName="signjar.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\signjar.html" />
+              <File DiskId="1" Id="file469" Name="SLEEP_1.HTM" LongName="sleep.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\sleep.html" />
+              <File DiskId="1" Id="file470" Name="SQL_1.HTM" LongName="sql.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\sql.html" />
+              <File DiskId="1" Id="file471" Name="STYLE_1.HTM" LongName="style.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\style.html" />
+              <File DiskId="1" Id="file472" Name="SUBANT_1.HTM" LongName="subant.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\subant.html" />
+              <File DiskId="1" Id="file473" Name="SYNC_1.HTM" LongName="sync.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\sync.html" />
+              <File DiskId="1" Id="file474" Name="TAR_1.HTM" LongName="tar.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\tar.html" />
+              <File DiskId="1" Id="file475" Name="TASKDE_1.HTM" LongName="taskdef.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\taskdef.html" />
+              <File DiskId="1" Id="file476" Name="TEMPFI_1.HTM" LongName="tempfile.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\tempfile.html" />
+              <File DiskId="1" Id="file477" Name="TOUCH_1.HTM" LongName="touch.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\touch.html" />
+              <File DiskId="1" Id="file478" Name="TSTAMP_1.HTM" LongName="tstamp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\tstamp.html" />
+              <File DiskId="1" Id="file479" Name="TYPEDE_1.HTM" LongName="typedef.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\typedef.html" />
+              <File DiskId="1" Id="file480" Name="UNPACK_1.HTM" LongName="unpack.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\unpack.html" />
+              <File DiskId="1" Id="file481" Name="UNTAR_1.HTM" LongName="untar.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\untar.html" />
+              <File DiskId="1" Id="file482" Name="UNZIP_1.HTM" LongName="unzip.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\unzip.html" />
+              <File DiskId="1" Id="file483" Name="UPTODA_1.HTM" LongName="uptodate.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\uptodate.html" />
+              <File DiskId="1" Id="file484" Name="WAITFO_1.HTM" LongName="waitfor.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\waitfor.html" />
+              <File DiskId="1" Id="file485" Name="WAR_1.HTM" LongName="war.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\war.html" />
+              <File DiskId="1" Id="file486" Name="WHICHR_1.HTM" LongName="whichresource.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\whichresource.html" />
+              <File DiskId="1" Id="file487" Name="XMLPRO_1.HTM" LongName="xmlproperty.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\xmlproperty.html" />
+              <File DiskId="1" Id="file488" Name="ZIP_1.HTM" LongName="zip.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTasks\zip.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory90" Name="CORETY_1" LongName="CoreTypes">
+            <Component Id="component87" DiskId="1" Guid="2BDC2593-705E-48c2-BC85-22BB4A4D242C">
+              <File DiskId="1" Id="file489" Name="ANTLIB_1.HTM" LongName="antlib.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\antlib.html" />
+              <File DiskId="1" Id="file490" Name="ASSERT_1.HTM" LongName="assertions.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\assertions.html" />
+              <File DiskId="1" Id="file491" Name="CUSTOM_1.HTM" LongName="custom-programming.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\custom-programming.html" />
+              <File DiskId="1" Id="file492" Name="DESCRI_1.HTM" LongName="description.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\description.html" />
+              <File DiskId="1" Id="file493" Name="DIRSET_1.HTM" LongName="dirset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\dirset.html" />
+              <File DiskId="1" Id="file494" Name="FILELI_1.HTM" LongName="filelist.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\filelist.html" />
+              <File DiskId="1" Id="file495" Name="FILESE_1.HTM" LongName="fileset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\fileset.html" />
+              <File DiskId="1" Id="file496" Name="FILTER_1.HTM" LongName="filterchain.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\filterchain.html" />
+              <File DiskId="1" Id="file497" Name="FILTER_2.HTM" LongName="filterset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\filterset.html" />
+              <File DiskId="1" Id="file498" Name="MAPPER_1.HTM" LongName="mapper.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\mapper.html" />
+              <File DiskId="1" Id="file499" Name="NAMESP_1.HTM" LongName="namespace.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\namespace.html" />
+              <File DiskId="1" Id="file500" Name="PATTER_1.HTM" LongName="patternset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\patternset.html" />
+              <File DiskId="1" Id="file501" Name="PERMIS_1.HTM" LongName="permissions.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\permissions.html" />
+              <File DiskId="1" Id="file502" Name="PROPER_1.HTM" LongName="propertyset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\propertyset.html" />
+              <File DiskId="1" Id="file503" Name="REDIRE_1.HTM" LongName="redirector.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\redirector.html" />
+              <File DiskId="1" Id="file504" Name="REGEXP_1.HTM" LongName="regexp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\regexp.html" />
+              <File DiskId="1" Id="file505" Name="RESOUR_1.HTM" LongName="resources.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\resources.html" />
+              <File DiskId="1" Id="file506" Name="SELECT_1.HTM" LongName="selectors-program.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\selectors-program.html" />
+              <File DiskId="1" Id="file507" Name="SELECT_2.HTM" LongName="selectors.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\selectors.html" />
+              <File DiskId="1" Id="file508" Name="TARFIL_1.HTM" LongName="tarfileset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\tarfileset.html" />
+              <File DiskId="1" Id="file509" Name="XMLCAT_1.HTM" LongName="xmlcatalog.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\xmlcatalog.html" />
+              <File DiskId="1" Id="file510" Name="ZIPFIL_1.HTM" LongName="zipfileset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\CoreTypes\zipfileset.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory91" Name="INTEGR_1" LongName="Integration">
+            <Component Id="component88" DiskId="1" Guid="BBE81178-4985-4100-A40F-9E82CF9299B2">
+              <File DiskId="1" Id="file511" Name="ANTIDO_1.HTM" LongName="Antidote.html" Vital="yes" src="$(var.dist.dir)/docs\manual\Integration\Antidote.html" />
+              <File DiskId="1" Id="file512" Name="anttool1.gif" Vital="yes" src="$(var.dist.dir)/docs\manual\Integration\anttool1.gif" />
+              <File DiskId="1" Id="file513" Name="JEXT-P_1.HTM" LongName="jext-plugin.html" Vital="yes" src="$(var.dist.dir)/docs\manual\Integration\jext-plugin.html" />
+              <File DiskId="1" Id="file514" Name="remacc.gif" Vital="yes" src="$(var.dist.dir)/docs\manual\Integration\remacc.gif" />
+              <File DiskId="1" Id="file515" Name="toolmenu.gif" Vital="yes" src="$(var.dist.dir)/docs\manual\Integration\toolmenu.gif" />
+            </Component>
+          </Directory>
+          <Directory Id="directory92" Name="OPTION_1" LongName="OptionalTasks">
+            <Component Id="component89" DiskId="1" Guid="85A5E430-F30C-4c89-B2D4-2758DFAD681A">
+              <File DiskId="1" Id="file516" Name="ANTLR_1.HTM" LongName="antlr.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\antlr.html" />
+              <File DiskId="1" Id="file517" Name="ATTRIB_1.HTM" LongName="attrib.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\attrib.html" />
+              <File DiskId="1" Id="file518" Name="BORLAN_1.HTM" LongName="BorlandEJBTasks.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\BorlandEJBTasks.html" />
+              <File DiskId="1" Id="file519" Name="BORLAN_2.HTM" LongName="BorlandGenerateClient.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\BorlandGenerateClient.html" />
+              <File DiskId="1" Id="file520" Name="CAB_1.HTM" LongName="cab.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\cab.html" />
+              <File DiskId="1" Id="file521" Name="CCM_1.HTM" LongName="ccm.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\ccm.html" />
+              <File DiskId="1" Id="file522" Name="CHGRP_1.HTM" LongName="chgrp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\chgrp.html" />
+              <File DiskId="1" Id="file523" Name="CHOWN_1.HTM" LongName="chown.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\chown.html" />
+              <File DiskId="1" Id="file524" Name="CLEARC_1.HTM" LongName="clearcase.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\clearcase.html" />
+              <File DiskId="1" Id="file525" Name="CSC_1.HTM" LongName="csc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\csc.html" />
+              <File DiskId="1" Id="file526" Name="DEPEND_1.HTM" LongName="depend.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\depend.html" />
+              <File DiskId="1" Id="file527" Name="DOTNET_1.HTM" LongName="dotnet.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\dotnet.html" />
+              <File DiskId="1" Id="file528" Name="ECHOPR_1.HTM" LongName="echoproperties.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\echoproperties.html" />
+              <File DiskId="1" Id="file529" Name="EJB_1.HTM" LongName="ejb.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\ejb.html" />
+              <File DiskId="1" Id="file530" Name="FTP_1.HTM" LongName="ftp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\ftp.html" />
+              <File DiskId="1" Id="file531" Name="ILASM_1.HTM" LongName="ilasm.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\ilasm.html" />
+              <File DiskId="1" Id="file532" Name="ILDASM_1.HTM" LongName="ildasm.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\ildasm.html" />
+              <File DiskId="1" Id="file533" Name="IMAGE-_1.GIF" LongName="image-classdiagram.gif" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\image-classdiagram.gif" />
+              <File DiskId="1" Id="file534" Name="IMAGE_1.HTM" LongName="image.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\image.html" />
+              <File DiskId="1" Id="file535" Name="IMPORT_1.HTM" LongName="importtypelib.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\importtypelib.html" />
+              <File DiskId="1" Id="file536" Name="JARLIB_1.HTM" LongName="jarlib-available.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jarlib-available.html" />
+              <File DiskId="1" Id="file537" Name="JARLIB_2.HTM" LongName="jarlib-display.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jarlib-display.html" />
+              <File DiskId="1" Id="file538" Name="JARLIB_4.HTM" LongName="jarlib-manifest.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jarlib-manifest.html" />
+              <File DiskId="1" Id="file539" Name="JARLIB_3.HTM" LongName="jarlib-resolve.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jarlib-resolve.html" />
+              <File DiskId="1" Id="file540" Name="JAVACC_1.HTM" LongName="javacc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\javacc.html" />
+              <File DiskId="1" Id="file541" Name="JAVAH_1.HTM" LongName="javah.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\javah.html" />
+              <File DiskId="1" Id="file542" Name="JDEPEN_1.HTM" LongName="jdepend.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jdepend.html" />
+              <File DiskId="1" Id="file543" Name="JJDOC_1.HTM" LongName="jjdoc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jjdoc.html" />
+              <File DiskId="1" Id="file544" Name="JJTREE_1.HTM" LongName="jjtree.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jjtree.html" />
+              <File DiskId="1" Id="file545" Name="JLINK_1.HTM" LongName="jlink.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jlink.html" />
+              <File DiskId="1" Id="file546" Name="JPCOVE_1.HTM" LongName="jpcoverage.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jpcoverage.html" />
+              <File DiskId="1" Id="file547" Name="JSHARP_1.HTM" LongName="jsharpc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jsharpc.html" />
+              <File DiskId="1" Id="file548" Name="JSPC_1.HTM" LongName="jspc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\jspc.html" />
+              <File DiskId="1" Id="file549" Name="JUNIT_1.HTM" LongName="junit.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\junit.html" />
+              <File DiskId="1" Id="file550" Name="JUNITR_1.HTM" LongName="junitreport.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\junitreport.html" />
+              <File DiskId="1" Id="file551" Name="MAUDIT_1.HTM" LongName="maudit.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\maudit.html" />
+              <File DiskId="1" Id="file552" Name="MIMEMA_1.HTM" LongName="mimemail.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\mimemail.html" />
+              <File DiskId="1" Id="file553" Name="MMETRI_1.HTM" LongName="mmetrics.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\mmetrics.html" />
+              <File DiskId="1" Id="file554" Name="MPARSE_1.HTM" LongName="mparse.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\mparse.html" />
+              <File DiskId="1" Id="file555" Name="NATIVE_1.HTM" LongName="native2ascii.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\native2ascii.html" />
+              <File DiskId="1" Id="file556" Name="NETREX_1.HTM" LongName="netrexxc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\netrexxc.html" />
+              <File DiskId="1" Id="file557" Name="PERFOR_1.HTM" LongName="perforce.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\perforce.html" />
+              <File DiskId="1" Id="file558" Name="PROPER_1.HTM" LongName="propertyfile.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\propertyfile.html" />
+              <File DiskId="1" Id="file559" Name="PVCSTA_1.HTM" LongName="pvcstask.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\pvcstask.html" />
+              <File DiskId="1" Id="file560" Name="RENAME_1.HTM" LongName="renameextensions.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\renameextensions.html" />
+              <File DiskId="1" Id="file561" Name="REPLAC_1.HTM" LongName="replaceregexp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\replaceregexp.html" />
+              <File DiskId="1" Id="file562" Name="REXEC_1.HTM" LongName="rexec.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\rexec.html" />
+              <File DiskId="1" Id="file563" Name="RPM_1.HTM" LongName="rpm.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\rpm.html" />
+              <File DiskId="1" Id="file564" Name="SCHEMA_1.HTM" LongName="schemavalidate.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\schemavalidate.html" />
+              <File DiskId="1" Id="file565" Name="SCP_1.HTM" LongName="scp.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\scp.html" />
+              <File DiskId="1" Id="file566" Name="SCRIPT_2.HTM" LongName="script.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\script.html" />
+              <File DiskId="1" Id="file567" Name="SCRIPT_1.HTM" LongName="scriptdef.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\scriptdef.html" />
+              <File DiskId="1" Id="file568" Name="SERVER_1.HTM" LongName="serverdeploy.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\serverdeploy.html" />
+              <File DiskId="1" Id="file569" Name="SETPRO_1.HTM" LongName="setproxy.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\setproxy.html" />
+              <File DiskId="1" Id="file570" Name="SOS_1.HTM" LongName="sos.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\sos.html" />
+              <File DiskId="1" Id="file571" Name="SOUND_1.HTM" LongName="sound.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\sound.html" />
+              <File DiskId="1" Id="file572" Name="SPLASH_1.HTM" LongName="splash.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\splash.html" />
+              <File DiskId="1" Id="file573" Name="SSHEXE_1.HTM" LongName="sshexec.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\sshexec.html" />
+              <File DiskId="1" Id="file574" Name="STARTE_1.HTM" LongName="starteam.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\starteam.html" />
+              <File DiskId="1" Id="file575" Name="STYLEB_1.HTM" LongName="stylebook.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\stylebook.html" />
+              <File DiskId="1" Id="file576" Name="SYMLIN_1.HTM" LongName="symlink.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\symlink.html" />
+              <File DiskId="1" Id="file577" Name="TELNET_1.HTM" LongName="telnet.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\telnet.html" />
+              <File DiskId="1" Id="file578" Name="TRANSL_1.HTM" LongName="translate.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\translate.html" />
+              <File DiskId="1" Id="file579" Name="VBC_1.HTM" LongName="vbc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\vbc.html" />
+              <File DiskId="1" Id="file580" Name="VSS_1.HTM" LongName="vss.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\vss.html" />
+              <File DiskId="1" Id="file581" Name="WLJSPC_1.HTM" LongName="wljspc.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\wljspc.html" />
+              <File DiskId="1" Id="file582" Name="WSDLTO_1.HTM" LongName="wsdltodotnet.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\wsdltodotnet.html" />
+              <File DiskId="1" Id="file583" Name="XMLVAL_1.HTM" LongName="xmlvalidate.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTasks\xmlvalidate.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory93" Name="OPTION_2" LongName="OptionalTypes">
+            <Component Id="component90" DiskId="1" Guid="0507ED6A-50CE-4c58-A046-B74E7CFCB3CA">
+              <File DiskId="1" Id="file584" Name="CLASSF_1.HTM" LongName="classfileset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTypes\classfileset.html" />
+              <File DiskId="1" Id="file585" Name="EXTENS_2.HTM" LongName="extension.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTypes\extension.html" />
+              <File DiskId="1" Id="file586" Name="EXTENS_1.HTM" LongName="extensionset.html" Vital="yes" src="$(var.dist.dir)/docs\manual\OptionalTypes\extensionset.html" />
+            </Component>
+          </Directory>
+          <Directory Id="directory94" Name="STYLES_1" LongName="stylesheets">
+            <Component Id="component91" DiskId="1" Guid="4B25D154-CC25-4f93-8D36-BF23E4C29F06">
+              <File DiskId="1" Id="file587" Name="ANTMAN_1.CSS" LongName="antmanual.css" Vital="yes" src="$(var.dist.dir)/docs\manual\stylesheets\antmanual.css" />
+              <File DiskId="1" Id="file588" Name="style.css" Vital="yes" src="$(var.dist.dir)/docs\manual\stylesheets\style.css" />
+            </Component>
+          </Directory>
+        </Directory>
+        <Directory Id="directory95" Name="projects">
+          <Component Id="component92" DiskId="1" Guid="FB149E10-8B7F-4206-AA50-8698C06BEC6E">
+            <File DiskId="1" Id="file589" Name="INDEX_1.HTM" LongName="index.html" Vital="yes" src="$(var.dist.dir)/docs\projects\index.html" />
+          </Component>
+        </Directory>
+        <Directory Id="directory96" Name="webtest">
+          <Component Id="component93" DiskId="1" Guid="A26B499E-E57F-47e3-88B2-66C1293383BE">
+            <File DiskId="1" Id="file590" Name="TESTKE_1" LongName="testkeystore" Vital="yes" src="$(var.dist.dir)/docs\webtest\testkeystore" />
+          </Component>
+        </Directory>
+      </Directory>
+      <Directory Id="directory97" Name="etc">
+        <Component Id="component94" DiskId="1" Guid="90BD5A92-DA62-48ce-8799-868E387EC7C8">
+          <File DiskId="1" Id="file591" Name="ANT-BO_1.JAR" LongName="ant-bootstrap.jar" Vital="yes" src="$(var.dist.dir)/etc\ant-bootstrap.jar" />
+          <File DiskId="1" Id="file592" Name="CHANGE_1.XSL" LongName="changelog.xsl" Vital="yes" src="$(var.dist.dir)/etc\changelog.xsl" />
+          <File DiskId="1" Id="file593" Name="COVERA_1.XSL" LongName="coverage-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\coverage-frames.xsl" />
+          <File DiskId="1" Id="file594" Name="JDEPEN_1.XSL" LongName="jdepend-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\jdepend-frames.xsl" />
+          <File DiskId="1" Id="file595" Name="jdepend.xsl" Vital="yes" src="$(var.dist.dir)/etc\jdepend.xsl" />
+          <File DiskId="1" Id="file596" Name="JUNIT-_3.XSL" LongName="junit-frames-xalan1.xsl" Vital="yes" src="$(var.dist.dir)/etc\junit-frames-xalan1.xsl" />
+          <File DiskId="1" Id="file597" Name="JUNIT-_1.XSL" LongName="junit-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\junit-frames.xsl" />
+          <File DiskId="1" Id="file598" Name="JUNIT-_2.XSL" LongName="junit-noframes.xsl" Vital="yes" src="$(var.dist.dir)/etc\junit-noframes.xsl" />
+          <File DiskId="1" Id="file599" Name="log.xsl" Vital="yes" src="$(var.dist.dir)/etc\log.xsl" />
+          <File DiskId="1" Id="file600" Name="MAUDIT_1.XSL" LongName="maudit-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\maudit-frames.xsl" />
+          <File DiskId="1" Id="file601" Name="MMETRI_1.XSL" LongName="mmetrics-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\mmetrics-frames.xsl" />
+          <File DiskId="1" Id="file602" Name="tagdiff.xsl" Vital="yes" src="$(var.dist.dir)/etc\tagdiff.xsl" />
+        </Component>
+        <Directory Id="directory98" Name="CHECKS_1" LongName="checkstyle">
+          <Component Id="component95" DiskId="1" Guid="2AEB59C7-5CEF-401c-9AB9-911B995F00FC">
+            <File DiskId="1" Id="file603" Name="CHECKS_1.XSL" LongName="checkstyle-frames.xsl" Vital="yes" src="$(var.dist.dir)/etc\checkstyle\checkstyle-frames.xsl" />
+            <File DiskId="1" Id="file604" Name="CHECKS_3.XSL" LongName="checkstyle-text.xsl" Vital="yes" src="$(var.dist.dir)/etc\checkstyle\checkstyle-text.xsl" />
+            <File DiskId="1" Id="file605" Name="CHECKS_2.XSL" LongName="checkstyle-xdoc.xsl" Vital="yes" src="$(var.dist.dir)/etc\checkstyle\checkstyle-xdoc.xsl" />
+          </Component>
+        </Directory>
+      </Directory>
+    </DirectoryRef>
+  </Fragment>
+</Wix>
\ No newline at end of file
diff --git a/trunk/src/etc/ant-msi.wxs b/trunk/src/etc/ant-msi.wxs
new file mode 100644
index 0000000..34b59eb
--- /dev/null
+++ b/trunk/src/etc/ant-msi.wxs
@@ -0,0 +1,122 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!--
+   WiX File describing the MSI for Ant
+   
+   XSD lives at http://wix.cvs.sourceforge.net/*checkout*/wix/wix2.0/src/wix/Xsd/wix.xsd
+-->
+<Wix xmlns='http://schemas.microsoft.com/wix/2003/01/wi'>
+
+  <Product Name="Apache Ant $(var.version)"
+    Id="61A421CE-D93F-478c-98C8-9C31FCE44C7A"
+    Version="$(var.version)" Language="1033"
+    Manufacturer="Apache Software Foundation">
+
+    <Package Id='????????-????-????-????-????????????'
+      Keywords='Installer' Languages="1033"
+      Description="Apache Ant $(var.version) installer"
+      Comments='Apache Ant is a Java based build tool'
+      Manufacturer='Apache Software Foundation'
+      InstallerVersion='200'
+      Compressed='yes'/>
+
+    <Media Id='1' Cabinet='ant.cab' EmbedCab='yes' />
+
+    <Directory Id='TARGETDIR' Name='SourceDir'>
+      <Directory Id='ProgramFilesFolder' Name='PFiles'>
+        <Directory Id='ASF' Name='Apache'
+          LongName="Apache Software Foundation">
+          <Directory Id='INSTALLDIR' Name='Ant'
+            LongName='Ant $(var.version)'>
+
+            <Component Id="licenses"
+              Guid="09346EB3-08D2-4a7f-9D64-47E4E414FE65">
+              <File DiskId="1" Id="fetch.xml" Name="fetch.xml"
+                Vital="yes" src="$(var.dist.dir)/fetch.xml"/>
+              <File DiskId="1" Id="INSTALL" Name="INSTALL"
+                Vital="yes" src="$(var.dist.dir)/INSTALL"/>
+              <File DiskId="1" Id="KEYS" Name="KEYS"
+                Vital="yes" src="$(var.dist.dir)/KEYS"/>
+              <File DiskId="1" Id="LICENSE" Name="LICENSE"
+                Vital="yes" src="$(var.dist.dir)/LICENSE"/>
+              <File DiskId="1" Id="LICENSE.dom" Name="LICENSE.dom"
+                Vital="yes" src="$(var.dist.dir)/LICENSE.dom"/>
+              <File DiskId="1" Id="LICENSE.sax" Name="LICENSE.sax"
+                Vital="yes" src="$(var.dist.dir)/LICENSE.sax"/>
+              <File DiskId="1" Id="LICENSE.xer" Name="LICENSE.xer"
+                LongName="LICENSE.xerces"
+                Vital="yes" src="$(var.dist.dir)/LICENSE.xerces"/>
+              <File DiskId="1" Id="NOTICE" Name="NOTICE"
+                Vital="yes" src="$(var.dist.dir)/NOTICE"/>
+              <File DiskId="1" Id="README" Name="README"
+                Vital="yes" src="$(var.dist.dir)/README"/>
+              <File DiskId="1" Id="WHATSNEW" Name="WHATSNEW"
+                Vital="yes" src="$(var.dist.dir)/WHATSNEW"/>
+            </Component>
+          </Directory>
+        </Directory>
+      </Directory>
+
+      <Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
+        <Directory Id="ProgramMenuDir" Name='Ant'
+          LongName="Apache Ant $(var.version)" />
+      </Directory>
+
+    </Directory>  
+        
+    <Feature Id="Complete" Level="1">
+      <ComponentRef Id="manualIndex"/>
+      <ComponentRef Id="licenses"/>
+      <ComponentRef Id="component0"/>
+      <ComponentRef Id="component1"/>
+      <ComponentRef Id="component2"/>
+      <ComponentRef Id="component3"/>
+      <ComponentRef Id="component4"/>
+      <ComponentRef Id="component5"/>
+      <ComponentRef Id="component6"/>
+      <ComponentRef Id="component7"/>
+      <ComponentRef Id="component8"/>
+      <ComponentRef Id="component9"/>
+      <ComponentRef Id="component86"/>
+      <ComponentRef Id="component87"/>
+      <ComponentRef Id="component88"/>
+      <ComponentRef Id="component89"/>
+      <ComponentRef Id="component90"/>
+      <ComponentRef Id="component91"/>
+      <ComponentRef Id="component92"/>
+      <ComponentRef Id="component93"/>
+      <ComponentRef Id="component94"/>
+      <ComponentRef Id="component95"/>
+    </Feature>
+  </Product>
+
+  <Fragment>
+    <DirectoryRef Id="manual">
+      <Component Id="manualIndex"
+        Guid="3125AB68-1388-49aa-89F8-9F5B80EBE64B">
+        <File DiskId="1" Id="antManualIndex"
+          Name="INDEX_1.HTM" LongName="index.html"
+          Vital="yes" src="$(var.dist.dir)/docs/manual/index.html">
+          <Shortcut Id="startmenuAntDocs"
+            Directory="ProgramMenuDir" Name="Manual" />
+        </File>
+      </Component>
+    </DirectoryRef>
+  </Fragment>
+
+</Wix>
diff --git a/trunk/src/etc/ant-update.xsl b/trunk/src/etc/ant-update.xsl
new file mode 100644
index 0000000..1ef87d9
--- /dev/null
+++ b/trunk/src/etc/ant-update.xsl
@@ -0,0 +1,119 @@
+<?xml version="1.0"?>
+<xsl:stylesheet	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="xml" indent="yes"/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+ 
+<!--
+
+  The purpose have this XSL is to provide a fast way to update a buildfile
+  from deprecated tasks.
+  
+  It should particularly be useful when there is a lot of build files to migrate.
+  If you do not want to migrate to a particular task and want to keep it for
+  various reason, just comment the appropriate template.
+  
+  !!!! Use at your own risk. !!!!
+  
+  @author <a href="sbailliez@apache.org">Stephane Bailliez</a>
+  
+-->
+ 
+ 
+  <!-- (zip|jar|war|ear)file attributes are replaced by destfile in their respective task -->
+  <xsl:template match="zip">
+    <zip destfile="{@zipfile}">
+      <xsl:apply-templates select="@*[not(name()='zipfile')]|node()"/>
+    </zip>
+  </xsl:template>
+  <xsl:template match="jar">
+    <jar destfile="{@jarfile}">
+      <xsl:apply-templates select="@*[not(name()='jarfile')]|node()"/>
+    </jar>
+  </xsl:template>
+  <xsl:template match="war">
+    <war destfile="{@warfile}">
+      <xsl:apply-templates select="@*[not(name()='warfile')]|node()"/>
+    </war>
+  </xsl:template>
+  <xsl:template match="ear">
+    <ear destfile="{@earfile}">
+      <xsl:apply-templates select="@*[not(name()='earfile')]|node()"/>
+    </ear>
+  </xsl:template>
+   
+ 
+  <!-- copydir is replaced by copy -->
+  <xsl:template match="copydir">
+    <copy todir="{@dest}">
+      <xsl:apply-templates select="@flatten|@filtering"/>
+      <xsl:if test="@forceoverwrite">
+        <xsl:attribute name="overwrite"><xsl:value-of select="@forceoverwrite"/></xsl:attribute>
+      </xsl:if>
+      <fileset dir="{@src}">
+          <xsl:apply-templates select="@includes|@includesfile|@excludes|@excludesfile|node()"/>
+      </fileset>
+    </copy>
+  </xsl:template>
+
+  <!-- copyfile is replaced by copy -->
+  <xsl:template match="copyfile">
+    <copy file="{@src}" tofile="{@dest}">
+      <xsl:apply-templates select="@filtering"/>
+      <xsl:if test="@forceoverwrite">
+        <xsl:attribute name="overwrite"><xsl:value-of select="@forceoverwrite"/></xsl:attribute>
+      </xsl:if>
+    </copy>
+  </xsl:template>
+
+  <!-- deltree is replaced by delete -->
+  <xsl:template match="deltree">
+    <delete dir="{@dir}"/>
+  </xsl:template>
+
+  <!-- execon is replaced by apply -->
+  <xsl:template match="execon">
+    <apply>
+      <xsl:apply-templates select="@*|node()"/>
+    </apply>
+  </xsl:template>
+
+  <!-- rename is replaced by move -->
+  <xsl:template match="rename">
+    <move file="{@src}" tofile="{@dest}">
+      <xsl:if test="@replace">
+        <xsl:attribute name="overwrite"><xsl:value-of select="@replace"/></xsl:attribute>
+      </xsl:if>
+    </move>
+  </xsl:template>
+
+  <!-- javadoc2 is replaced by javadoc -->
+  <xsl:template match="javadoc2">
+    <javadoc>
+      <xsl:apply-templates select="@*|node()"/>
+    </javadoc>
+  </xsl:template>
+
+
+  <!-- Copy every node and attributes recursively -->
+  <xsl:template match="node()|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+  
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/src/etc/changelog.xsl b/trunk/src/etc/changelog.xsl
new file mode 100644
index 0000000..c6aef8f
--- /dev/null
+++ b/trunk/src/etc/changelog.xsl
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<xsl:stylesheet
+    xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+    version='1.0'>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   
+-->
+  <xsl:param name="title"/>
+  <xsl:param name="module"/>
+  <xsl:param name="cvsweb"/>
+
+  <xsl:output method="html" indent="yes" encoding="US-ASCII"
+              doctype-public="-//W3C//DTD HTML 4.01//EN"
+              doctype-system="http://www.w3.org/TR/html401/strict.dtd"/>
+
+  <!-- Copy standard document elements.  Elements that
+       should be ignored must be filtered by apply-templates
+       tags. -->
+  <xsl:template match="*">
+    <xsl:copy>
+      <xsl:copy-of select="attribute::*[. != '']"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="changelog">
+    <html>
+      <head>
+        <title><xsl:value-of select="$title"/></title>
+        <style type="text/css">
+          body, p {
+            font-family: Verdana, Arial, Helvetica, sans-serif;
+            font-size: 80%;
+            color: #000000;
+            background-color: #ffffff;
+          }
+          tr, td {
+            font-family: Verdana, Arial, Helvetica, sans-serif;
+            background: #eeeee0;
+          }
+          td {
+            padding-left: 20px;
+          }
+      .dateAndAuthor {
+            font-family: Verdana, Arial, Helvetica, sans-serif;
+            font-weight: bold;
+            text-align: left;
+            background: #a6caf0;
+            padding-left: 3px;
+      }
+          a {
+            color: #000000;
+          }
+          pre {
+            font-weight: bold;
+          }
+        </style>
+      </head>
+      <body>
+        <h1>
+          <a name="top"><xsl:value-of select="$title"/></a>
+        </h1>
+        <p style="text-align: right">Designed for use with <a href="http://ant.apache.org/">Apache Ant</a>.</p>
+        <hr/>
+        <table border="0" width="100%" cellspacing="1">
+          
+          <xsl:apply-templates select=".//entry">
+            <xsl:sort select="date" data-type="text" order="descending"/>
+            <xsl:sort select="time" data-type="text" order="descending"/>
+          </xsl:apply-templates>
+          
+        </table>
+        
+      </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:template match="entry">
+    <tr>
+      <td class="dateAndAuthor">
+        <xsl:value-of select="date"/><xsl:text> </xsl:text><xsl:value-of select="time"/><xsl:text> </xsl:text><xsl:value-of select="author"/>
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <pre>
+<xsl:apply-templates select="msg"/></pre>
+        <ul>
+          <xsl:apply-templates select="file"/>
+        </ul>
+      </td>
+    </tr>
+  </xsl:template>
+
+  <xsl:template match="date">
+    <i><xsl:value-of select="."/></i>
+  </xsl:template>
+
+  <xsl:template match="time">
+    <i><xsl:value-of select="."/></i>
+  </xsl:template>
+
+  <xsl:template match="author">
+    <i>
+      <a>
+        <xsl:attribute name="href">mailto:<xsl:value-of select="."/></xsl:attribute>
+        <xsl:value-of select="."/></a>
+    </i>
+  </xsl:template>
+
+  <xsl:template match="file">
+    <li>
+      <a>
+        <xsl:choose>
+          <xsl:when test="string-length(prevrevision) = 0 ">
+            <xsl:attribute name="href"><xsl:value-of select="$cvsweb"/><xsl:value-of select="$module" />/<xsl:value-of select="name" />?rev=<xsl:value-of select="revision" />&amp;content-type=text/x-cvsweb-markup</xsl:attribute>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:attribute name="href"><xsl:value-of select="$cvsweb"/><xsl:value-of select="$module" />/<xsl:value-of select="name" />?r1=<xsl:value-of select="revision" />&amp;r2=<xsl:value-of select="prevrevision"/></xsl:attribute>
+          </xsl:otherwise>
+        </xsl:choose>
+        <xsl:value-of select="name" /> (<xsl:value-of select="revision"/>)</a>
+    </li>
+  </xsl:template>
+
+  <!-- Any elements within a msg are processed,
+       so that we can preserve HTML tags. -->
+  <xsl:template match="msg">
+    <xsl:apply-templates/>
+  </xsl:template>
+  
+</xsl:stylesheet>
diff --git a/trunk/src/etc/checkstyle/RequiredHeader.txt b/trunk/src/etc/checkstyle/RequiredHeader.txt
new file mode 100755
index 0000000..6a5bb9a
--- /dev/null
+++ b/trunk/src/etc/checkstyle/RequiredHeader.txt
@@ -0,0 +1,17 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
diff --git a/trunk/src/etc/checkstyle/checkstyle-config b/trunk/src/etc/checkstyle/checkstyle-config
new file mode 100644
index 0000000..877fb90
--- /dev/null
+++ b/trunk/src/etc/checkstyle/checkstyle-config
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.1//EN" "http://www.puppycrawl.com/dtds/configuration_1_1.dtd">
+
+<module name="Checker">
+  <module name="TreeWalker">
+    <!-- Javadoc requirements -->
+    <module name="JavadocType">
+      <property name="scope" value="protected"/>
+    </module>
+    <module name="JavadocMethod">
+      <property name="scope" value="protected"/>
+      <property name="allowUndeclaredRTE" value="true"/>
+    </module>
+    <module name="JavadocVariable">
+       <property name="scope" value="public"/>
+    </module>
+
+    <!-- element naming -->
+    <module name="PackageName"/>
+    <module name="TypeName"/>
+    <module name="ConstantName"/>
+    <module name="LocalFinalVariableName"/>
+    <module name="LocalVariableName"/>
+    <module name="MemberName"/>
+    <module name="MethodName"/>
+    <module name="ParameterName"/>
+    <module name="StaticVariableName"/>
+
+    <!-- required licence file -->
+    <module name="Header">
+        <property name="headerFile" value="${config.dir}/RequiredHeader.txt"/>
+        <property name="ignoreLines" value="2"/>
+    </module>
+
+    <!-- Import conventions -->
+    <module name="AvoidStarImport"/>
+    <module name="IllegalImport"/>
+    <module name="RedundantImport"/>
+    <module name="UnusedImports"/>
+
+    <!-- size limits -->
+    <module name="FileLength"/>
+    <module name="LineLength">
+      <property name="max" value="100"/>
+      <property name="ignorePattern" value="^ *\* *[^ ]+$"/>
+    </module>
+    <module name="MethodLength"/>
+    <module name="ParameterNumber"/>
+
+    <!-- whitespace checks -->
+    <module name="EmptyForIteratorPad"/>
+    <module name="NoWhitespaceAfter"/>
+    <module name="NoWhitespaceBefore"/>
+    <module name="OperatorWrap"/>
+    <module name="ParenPad"/>
+    <module name="TabCharacter"/>
+    <module name="WhitespaceAfter"/>
+    <module name="WhitespaceAround"/>
+
+    <!-- Modifier Checks -->
+    <module name="ModifierOrder"/>
+    <module name="RedundantModifier"/>
+
+
+    <!-- Checks for blocks -->
+    <module name="AvoidNestedBlocks"/>
+    <module name="EmptyBlock">
+      <property name="option" value="text"/>
+    </module>
+    <module name="LeftCurly"/>
+    <module name="NeedBraces"/>
+    <module name="RightCurly"/>
+
+
+    <!-- Checks for common coding problems -->
+    <!--<module name="AvoidInlineConditionals"/> -->
+    <module name="DoubleCheckedLocking"/>
+    <module name="EmptyStatement"/>
+    <module name="EqualsHashCode"/>
+    <module name="IllegalInstantiation">
+      <property name="classes" value="java.lang.Boolean"/>
+    </module>
+    <module name="InnerAssignment"/>
+    <module name="MagicNumber"/>
+    <module name="MissingSwitchDefault"/>
+    <!-- Allow redundant throw declarations for doc purposes 
+    <module name="RedundantThrows">
+      <property name="allowUnchecked" value="true"/>
+    </module>
+         -->
+    <module name="SimplifyBooleanExpression"/>
+    <module name="SimplifyBooleanReturn"/>
+
+    <!-- Checks for class design -->
+    <!-- <module name="DesignForExtension"/> -->
+    <module name="FinalClass"/>
+    <module name="HideUtilityClassConstructor"/>
+    <module name="InterfaceIsType"/>
+    <module name="VisibilityModifier"/>
+
+    <!-- Miscellaneous other checks. -->
+    <module name="ArrayTypeStyle"/>
+    <module name="GenericIllegalRegexp">
+      <property name="format" value="\s+$"/>
+      <property name="message" value="Line has trailing spaces."/>
+    </module>
+    <module name="TodoComment"/>
+    <module name="UpperEll"/>
+    <!-- allow comment suppression of checks -->
+    <module name="FileContentsHolder"/>
+  </module>
+  <!-- <module name="au.com.redhillconsulting.simian.SimianCheck"/> -->
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle\:([\w\|]+) *OFF"/>
+    <property name="onCommentFormat" value="CheckStyle\:([\w\|]+) *ON"/>
+    <property name="checkFormat" value="$1"/>
+  </module>
+</module>
diff --git a/trunk/src/etc/checkstyle/checkstyle-frames.xsl b/trunk/src/etc/checkstyle/checkstyle-frames.xsl
new file mode 100644
index 0000000..abaafd6
--- /dev/null
+++ b/trunk/src/etc/checkstyle/checkstyle-frames.xsl
@@ -0,0 +1,299 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="org.apache.xalan.lib.Redirect"
+    extension-element-prefixes="redirect">
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+    <xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+    <xsl:decimal-format decimal-separator="." grouping-separator="," />
+
+    <xsl:param name="output.dir" select="'.'"/>
+    <xsl:param name="basedir" select="'.'"/>
+
+    <xsl:template match="checkstyle">
+        <!-- create the index.html -->
+        <redirect:write file="{$output.dir}/index.html">
+            <xsl:call-template name="index.html"/>
+        </redirect:write>
+
+        <!-- create the stylesheet.css -->
+        <redirect:write file="{$output.dir}/stylesheet.css">
+            <xsl:call-template name="stylesheet.css"/>
+        </redirect:write>
+
+        <!-- create the overview-summary.html at the root -->
+        <redirect:write file="{$output.dir}/overview-frame.html">
+            <xsl:apply-templates select="." mode="overview"/>
+        </redirect:write>
+
+        <!-- create the all-classes.html at the root -->
+        <redirect:write file="{$output.dir}/allclasses-frame.html">
+            <xsl:apply-templates select="." mode="all.classes"/>
+        </redirect:write>
+
+        <!-- process all files -->
+        <xsl:apply-templates select="file[count(error) != 0]"/>
+    </xsl:template>
+
+    <xsl:template name="index.html">
+        <html>
+            <head>
+                <title>CheckStyle Audit</title>
+            </head>
+            <frameset cols="20%,80%">
+                <frame src="allclasses-frame.html" name="fileListFrame"/>
+                <frame src="overview-frame.html" name="fileFrame"/>
+            </frameset>
+            <noframes>
+                <h2>Frame Alert</h2>
+                <p>
+                    This document is designed to be viewed using the frames feature.
+                    If you see this message, you are using a non-frame-capable web client.
+                </p>
+            </noframes>
+        </html>
+    </xsl:template>
+
+    <xsl:template name="pageHeader">
+        <table border="0" cellpadding="0" cellspacing="0" width="100%">
+            <tr>
+                <td class="text-align:right"><h2>CheckStyle Audit</h2></td>
+            </tr>
+            <tr>
+                <td class="text-align:right">Designed for use with
+                  <a href='http://checkstyle.sourceforge.net/'>CheckStyle</a> and
+                  <a href='http://ant.apache.org/'>Ant</a>.</td>
+            </tr>
+        </table>
+        <hr size="1"/>
+    </xsl:template>
+
+    <xsl:template match="checkstyle" mode="overview">
+        <html>
+            <head>
+                <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+            </head>
+            <body>
+                <!-- page header -->
+                <xsl:call-template name="pageHeader"/>
+
+                <!-- Summary part -->
+                <xsl:apply-templates select="." mode="summary"/>
+                <hr size="1" width="100%" align="left"/>
+
+                <!-- File list part -->
+                <xsl:apply-templates select="." mode="filelist"/>
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template name="stylesheet.css">
+        .bannercell {
+        border: 0px;
+        padding: 0px;
+        }
+        body {
+        margin-left: 10;
+        margin-right: 10;
+        font:normal 80% arial,helvetica,sanserif;
+        background-color:#FFFFFF;
+        color:#000000;
+        }
+        .oddrow td {
+        background: #efefef;
+        }
+        .evenrow td {
+        background: #fff;
+        }
+        th, td {
+        text-align: left;
+        vertical-align: top;
+        }
+        th {
+        font-weight:bold;
+        background: #ccc;
+        color: black;
+        }
+        table, th, td {
+        font-size:100%;
+        border: none
+        }
+        table.log tr td, tr th {
+
+        }
+        h2 {
+        font-weight:bold;
+        font-size:140%;
+        margin-bottom: 5;
+        }
+        h3 {
+        font-size:100%;
+        font-weight:bold;
+        background: #525D76;
+        color: white;
+        text-decoration: none;
+        padding: 5px;
+        margin-right: 2px;
+        margin-left: 2px;
+        margin-bottom: 0;
+        }
+    </xsl:template>
+
+    <!--
+    Creates an all-classes.html file that contains a link to all files.
+    -->
+    <xsl:template match="checkstyle" mode="all.classes">
+        <html>
+            <head>
+                <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+            </head>
+            <body>
+                <h2>Files</h2>
+                <p>
+                    <table width="100%">
+                        <!-- For each file create its part -->
+                        <xsl:apply-templates select="file[count(error) != 0]" mode="all.classes">
+                            <xsl:sort select="substring-after(@name, $basedir)"/>
+                        </xsl:apply-templates>
+                    </table>
+                </p>
+            </body>
+        </html>
+    </xsl:template>
+
+    <xsl:template match="checkstyle" mode="filelist">
+        <h3>Files</h3>
+        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+            <tr>
+                <th>Name</th>
+                <th>Errors</th>
+            </tr>
+            <xsl:apply-templates select="file[count(error) != 0]" mode="filelist">
+                <xsl:sort select="count(error)" order="descending" data-type="number"/>
+            </xsl:apply-templates>
+        </table>
+    </xsl:template>
+
+    <xsl:template match="file" mode="filelist">
+        <tr>
+            <xsl:call-template name="alternated-row"/>
+            <td nowrap="nowrap">
+                <a>
+                    <xsl:attribute name="href">
+                        <xsl:text>files/</xsl:text><xsl:value-of select="substring-after(@name, $basedir)"/><xsl:text>.html</xsl:text>
+                    </xsl:attribute>
+                    <xsl:value-of select="substring-after(@name, $basedir)"/>
+                </a>
+            </td>
+            <td><xsl:value-of select="count(error)"/></td>
+        </tr>
+    </xsl:template>
+
+    <xsl:template match="file" mode="all.classes">
+        <tr>
+            <td nowrap="nowrap">
+                <a target="fileFrame">
+                    <xsl:attribute name="href">
+                        <xsl:text>files/</xsl:text><xsl:value-of select="substring-after(@name, $basedir)"/><xsl:text>.html</xsl:text>
+                    </xsl:attribute>
+                    <xsl:value-of select="substring-after(@name, $basedir)"/>
+                </a>
+            </td>
+        </tr>
+    </xsl:template>
+
+    <!--
+    transform string like a/b/c to ../../../
+    @param path the path to transform into a descending directory path
+    -->
+    <xsl:template name="path">
+        <xsl:param name="path"/>
+
+        <!-- Convert a windows path '\' to a unix path '/' for further processing. -->
+        <xsl:variable name="path2" select="translate($path,'\','/')"/>
+
+        
+        <xsl:if test="contains($path2,'/')">
+            <xsl:text>../</xsl:text>
+            <xsl:call-template name="path">
+                <xsl:with-param name="path"><xsl:value-of select="substring-after($path2,'/')"/></xsl:with-param>
+            </xsl:call-template>
+        </xsl:if>
+        <xsl:if test="not(contains($path2,'/')) and not($path2 = '')">
+            <xsl:text>../</xsl:text>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template match="file">
+        <redirect:write file="{$output.dir}/files/{substring-after(@name, $basedir)}.html">
+            <html>
+                <head>
+                    <link rel="stylesheet" type="text/css">
+                        <xsl:attribute name="href"><xsl:call-template name="path"><xsl:with-param name="path" select="substring-after(@name, $basedir)"/></xsl:call-template><xsl:text>stylesheet.css</xsl:text></xsl:attribute>
+                    </link>
+                </head>
+                <body>
+                    <xsl:call-template name="pageHeader"/>
+                    <h3>File <xsl:value-of select="substring-after(@name, $basedir)"/></h3>
+                    <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+                        <tr>
+                            <th>Error Description</th>
+                            <th>Line:Column</th>
+                        </tr>
+                        <xsl:for-each select="error">
+                            <tr>
+                                <xsl:call-template name="alternated-row"/>
+                                <td><a title="{@source}"><xsl:value-of select="@message"/></a></td>
+                                <td align="center"><xsl:value-of select="@line"/><xsl:if test="@column">:<xsl:value-of select="@column"/></xsl:if></td>
+                            </tr>
+                        </xsl:for-each>
+                    </table>
+                </body>
+            </html>
+        </redirect:write>
+    </xsl:template>
+
+    <xsl:template match="checkstyle" mode="summary">
+        <h3>Summary</h3>
+        <xsl:variable name="fileCount" select="count(file)"/>
+        <xsl:variable name="errorCount" select="count(file/error)"/>
+        <xsl:variable name="fileErrorCount" select="count(file[count(error) != 0])"/>
+        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+            <tr>
+                <th>Total Files</th>
+                <th>Files With Errors</th>
+                <th>Errors</th>
+            </tr>
+            <tr>
+                <xsl:call-template name="alternated-row"/>
+                <td><xsl:value-of select="$fileCount"/></td>
+                <td><xsl:value-of select="$fileErrorCount"/></td>
+                <td><xsl:value-of select="$errorCount"/></td>
+            </tr>
+        </table>
+    </xsl:template>
+
+    <xsl:template name="alternated-row">
+        <xsl:attribute name="class">
+            <xsl:if test="position() mod 2 = 1">oddrow</xsl:if>
+            <xsl:if test="position() mod 2 = 0">evenrow</xsl:if>
+        </xsl:attribute>
+    </xsl:template>
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/src/etc/checkstyle/checkstyle-text.xsl b/trunk/src/etc/checkstyle/checkstyle-text.xsl
new file mode 100644
index 0000000..7359e41
--- /dev/null
+++ b/trunk/src/etc/checkstyle/checkstyle-text.xsl
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+    <xsl:strip-space elements="checkstyle"/>
+    <xsl:preserve-space elements="file"/>
+    <xsl:output method="text"/>
+    <xsl:template match="checkstyle/file/error">
+        <xsl:value-of select="../@name"/>
+        <xsl:text>:</xsl:text>
+        <xsl:value-of select="@line"/>
+        <xsl:text>:</xsl:text>
+        <xsl:value-of select="@column"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="@message"/>
+    </xsl:template>
+</xsl:stylesheet>
+
diff --git a/trunk/src/etc/checkstyle/checkstyle-xdoc.xsl b/trunk/src/etc/checkstyle/checkstyle-xdoc.xsl
new file mode 100644
index 0000000..5fc6eab
--- /dev/null
+++ b/trunk/src/etc/checkstyle/checkstyle-xdoc.xsl
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="org.apache.xalan.lib.Redirect"
+    extension-element-prefixes="redirect">
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+    <xsl:output method="xml" indent="yes"/>
+    <xsl:decimal-format decimal-separator="." grouping-separator="," />
+
+    <xsl:param name="output.dir" select="'.'"/>
+    <xsl:param name="basedir" select="'.'"/>
+
+    <xsl:template match="checkstyle">
+      <document>
+        <properties>
+          <title>Checkstyle Audit</title>
+        </properties>
+
+        <body>
+          <xsl:apply-templates select="." mode="summary"/>
+          <!-- File list part -->
+          <xsl:apply-templates select="." mode="filelist"/>
+          <xsl:apply-templates select="file[count(error) != 0]"/>
+        </body>
+      </document>
+    </xsl:template>
+
+    <xsl:template match="checkstyle" mode="filelist">
+      <section name="Files">
+        <table>
+            <tr>
+                <th>Name</th>
+                <th>Errors</th>
+            </tr>
+            <xsl:apply-templates select="file[count(error) != 0]" mode="filelist">
+                <xsl:sort select="count(error)" order="descending" data-type="number"/>
+            </xsl:apply-templates>
+        </table>
+      </section>
+    </xsl:template>
+
+    <xsl:template match="file" mode="filelist">
+        <tr>
+            <xsl:call-template name="alternated-row"/>
+            <td nowrap="nowrap">
+                <a>
+                    <xsl:attribute name="href">
+                        <xsl:text>files</xsl:text><xsl:value-of select="substring-after(@name, $basedir)"/><xsl:text>.html</xsl:text>
+                    </xsl:attribute>
+                    <xsl:value-of select="substring-after(@name, $basedir)"/>
+                </a>
+            </td>
+            <td><xsl:value-of select="count(error)"/></td>
+        </tr>
+    </xsl:template>
+
+    <xsl:template match="file">
+      <redirect:write file="{$output.dir}/files{substring-after(@name, $basedir)}.xml">
+        <document>
+          <properties>
+            <title>Checkstyle Audit</title>
+          </properties>
+
+          <body>
+            <section name="Details for {substring-after(@name, $basedir)}">
+              <table>
+                  <tr>
+                      <th>Error Description</th>
+                      <th>Line</th>
+                  </tr>
+                  <xsl:for-each select="error">
+                      <tr>
+                          <xsl:call-template name="alternated-row"/>
+                          <td><a title="{@source}"><xsl:value-of select="@message"/></a></td>
+                          <td><xsl:value-of select="@line"/></td>
+                      </tr>
+                  </xsl:for-each>
+              </table>
+            </section>
+          </body>
+        </document>
+      </redirect:write>
+    </xsl:template>
+
+    <xsl:template match="checkstyle" mode="summary">
+      <section name="Summary">
+        <xsl:variable name="fileCount" select="count(file)"/>
+        <xsl:variable name="errorCount" select="count(file/error)"/>
+        <xsl:variable name="fileErrorCount" select="count(file[count(error) != 0])"/>
+        <table>
+            <tr>
+                <th>Files</th>
+                <th>Files With Errors</th>
+                <th>Errors</th>
+            </tr>
+            <tr>
+                <xsl:call-template name="alternated-row"/>
+                <td><xsl:value-of select="$fileCount"/></td>
+                <td><xsl:value-of select="$fileErrorCount"/></td>
+                <td><xsl:value-of select="$errorCount"/></td>
+            </tr>
+        </table>
+      </section>
+    </xsl:template>
+
+    <xsl:template name="alternated-row">
+        <xsl:attribute name="class">
+            <xsl:if test="position() mod 2 = 1">oddrow</xsl:if>
+            <xsl:if test="position() mod 2 = 0">evenrow</xsl:if>
+        </xsl:attribute>
+    </xsl:template>
+</xsl:stylesheet>
+
diff --git a/trunk/src/etc/common2master.xsl b/trunk/src/etc/common2master.xsl
new file mode 100644
index 0000000..9ee35bd
--- /dev/null
+++ b/trunk/src/etc/common2master.xsl
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>

+<!-- 

+	This stylesheet can be used to generate a master buildfile from a common

+	buildfile (see manual for <subant>).

+	Foreach <target> in the common buildfile it generates a corresponding 

+	target in the master buildfile for iterating over that target.

+-->

+<xsl:stylesheet

+  version="1.0"

+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

+

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+

+    <xsl:output indent="no" method="text" encoding="ISO-8859-1"/>

+    <xsl:strip-space elements="*"/>

+

+

+<xsl:template match="/">

+    <xsl:apply-templates/>

+</xsl:template>

+

+

+

+<xsl:template match="project">

+<![CDATA[

+<project name="master"> 

+

+    <macrodef name="iterate">

+        <attribute name="target"/>

+        <sequential>

+            <subant target="@{target}">

+                <fileset dir="modules" includes="*/build.xml"/>

+            </subant>

+        </sequential>

+    </macrodef>

+]]>

+   

+    <xsl:apply-templates/>

+    

+<![CDATA[

+</project>

+]]>

+</xsl:template>

+

+

+<xsl:template match="target">

+    &lt;target name=&quot;<xsl:value-of select="@name"/>&quot;<xsl:if test="@description"> description=&quot;<xsl:value-of select="@description"/>&quot;</xsl:if>&gt;

+        &lt;iterate target=&quot;<xsl:value-of select="@name"/>&quot;/&gt;

+    &lt;/target&gt;

+</xsl:template>

+

+

+<xsl:template match="text()"/>

+

+

+

+</xsl:stylesheet>

+

diff --git a/trunk/src/etc/coverage-frames.xsl b/trunk/src/etc/coverage-frames.xsl
new file mode 100644
index 0000000..a55a52a
--- /dev/null
+++ b/trunk/src/etc/coverage-frames.xsl
@@ -0,0 +1,489 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="org.apache.xalan.lib.Redirect"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes"/>
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!--
+
+ Sample stylesheet to be used with JProbe 3.0 XML output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+ It is best used with JProbe Coverage Ant task that gives you the benefit
+ of a reference classpath so that you have the list of classes/methods
+ that are not used at all in a given classpath.
+
+ @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+
+-->
+
+<!-- default output directory is current directory -->
+<xsl:param name="output.dir" select="'.'"/>
+
+<!-- ======================================================================
+    Root element
+    ======================================================================= -->
+<xsl:template match="/snapshot">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- process all packages -->
+    <xsl:apply-templates select="./package" mode="write"/>
+</xsl:template>
+
+<!-- =======================================================================
+    Frameset definition. Entry point for the report.
+    3 frames: packageListFrame, classListFrame, classFrame
+    ======================================================================= -->
+<xsl:template name="index.html">
+<html>
+    <head><title>Coverage Results.</title></head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="packageListFrame"/>
+            <frame src="allclasses-frame.html" name="classListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="classFrame"/>
+    </frameset>
+    <noframes>
+        <h2>Frame Alert</h2>
+        <p>
+        This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+        </p>
+    </noframes>
+</html>
+</xsl:template>
+
+<!-- =======================================================================
+    Stylesheet CSS used
+    ======================================================================= -->
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+    .bannercell {
+      border: 0px;
+      padding: 0px;
+    }
+    body {
+      margin-left: 10;
+      margin-right: 10;
+      font:normal 80% arial,helvetica,sanserif;
+      background-color:#FFFFFF;
+      color:#000000;
+    }
+    .a td {
+      background: #efefef;
+    }
+    .b td {
+      background: #fff;
+    }
+    th, td {
+      text-align: left;
+      vertical-align: top;
+    }
+    th {
+      font-weight:bold;
+      background: #ccc;
+      color: black;
+    }
+    table, th, td {
+      font-size:100%;
+      border: none
+    }
+    table.log tr td, tr th {
+
+    }
+    h2 {
+      font-weight:bold;
+      font-size:140%;
+      margin-bottom: 5;
+    }
+    h3 {
+      font-size:100%;
+      font-weight:bold;
+      background: #525D76;
+      color: white;
+      text-decoration: none;
+      padding: 5px;
+      margin-right: 2px;
+      margin-left: 2px;
+      margin-bottom: 0;
+    }
+</xsl:template>
+
+<!-- =======================================================================
+    List of all classes in all packages
+    This will be the first page in the classListFrame
+    ======================================================================= -->
+<xsl:template match="snapshot" mode="all.classes">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link"/>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:for-each select="package/class">
+                    <xsl:sort select="@name"/>
+                    <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/>
+                    <xsl:variable name="link">
+                        <xsl:if test="not($package.name='')">
+                            <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                        </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                    </xsl:variable>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a target="classFrame" href="{$link}"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<!-- list of all packages -->
+<xsl:template match="snapshot" mode="all.packages">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link"/>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+            <table width="100%">
+                <xsl:for-each select="package">
+                    <xsl:sort select="@name" order="ascending"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{translate(@name,'.','/')}/package-summary.html" target="classFrame">
+                                <xsl:value-of select="@name"/>
+                            </a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<!-- overview of statistics in packages -->
+<xsl:template match="snapshot" mode="overview.packages">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link"/>
+        </head>
+        <body onload="open('allclasses-frame.html','classListFrame')">
+        <xsl:call-template name="pageHeader"/>
+        <h3>Summary</h3>
+        <table class="log" cellpadding="5" cellspacing="2" width="100%">
+            <tr>
+                <!--th width="10%" nowrap="nowrap">Date</th>
+                <th width="10%" nowrap="nowrap">Elapsed time</th-->
+                <th width="10%" nowrap="nowrap">Reported Classes</th>
+                <th width="10%" nowrap="nowrap">Methods Hit</th>
+                <th width="10%" nowrap="nowrap">Lines Hit</th>
+            </tr>
+            <tr class="a">
+                <!--td nowrap="nowrap"><xsl:value-of select="execution_log/@program_start"/></td>
+                <td><xsl:value-of select="format-number(execution_log/@elapsed_time div 1000,'0.0')"/>secs</td-->
+                <td><xsl:value-of select="count(package/class)"/></td>
+                <td><xsl:value-of select="format-number(cov.data/@hit_methods div cov.data/@total_methods,'0.0%')"/></td>
+                <td><xsl:value-of select="format-number(cov.data/@hit_lines div cov.data/@total_lines,'0.0%')"/></td>
+            </tr>
+        </table>
+        <table border="0" width="100%">
+        <tr>
+        <td style="text-align: justify;">
+        To ensure accurate test runs on Java applications, developers need to know how much of
+        the code has been tested, and where to find any untested code. Coverage helps you
+        locate untested code, and measure precisely how much code has been exercised.
+        The result is a higher quality application in a shorter period of time.
+        <p/>
+        </td>
+        </tr>
+        </table>
+
+        <h3>Packages</h3>
+        <table class="log" cellpadding="5" cellspacing="2" width="100%">
+            <xsl:apply-templates select="package[1]" mode="stats.header"/>
+            <!-- display packages and sort them via their coverage rate -->
+            <xsl:for-each select="package">
+                <xsl:sort data-type="number" select="cov.data/@hit_lines div cov.data/@total_lines"/>
+                <tr>
+                  <xsl:call-template name="alternate-row"/>
+                    <td><a href="{translate(@name,'.','/')}/package-summary.html"><xsl:value-of select="@name"/></a></td>
+                    <td><xsl:value-of select="format-number(cov.data/@hit_methods div cov.data/@total_methods,'0.0%')"/></td>
+                    <td><xsl:value-of select="format-number(cov.data/@hit_lines div cov.data/@total_lines,'0.0%')"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        <xsl:call-template name="pageFooter"/>
+        </body>
+        </html>
+</xsl:template>
+
+<!--
+ detailed info for a package. It will output the list of classes
+, the summary page, and the info for each class
+-->
+<xsl:template match="package" mode="write">
+    <xsl:variable name="package.dir">
+        <xsl:if test="not(@name = '')"><xsl:value-of select="translate(@name,'.','/')"/></xsl:if>
+        <xsl:if test="@name = ''">.</xsl:if>
+    </xsl:variable>
+
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:apply-templates select="." mode="classes.list"/>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:apply-templates select="." mode="package.summary"/>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <xsl:for-each select="class">
+        <redirect:write file="{$output.dir}/{$package.dir}/{@name}.html">
+            <xsl:apply-templates select="." mode="class.details"/>
+        </redirect:write>
+    </xsl:for-each>
+</xsl:template>
+
+<!-- list of classes in a package -->
+<xsl:template match="package" mode="classes.list">
+    <html>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="@name"/>
+            </xsl:call-template>
+        </HEAD>
+        <BODY>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <H2><a href="package-summary.html" target="classFrame"><xsl:value-of select="@name"/></a></H2>
+                    </td>
+                </tr>
+            </table>
+
+            <H2>Classes</H2>
+            <TABLE WIDTH="100%">
+                <xsl:for-each select="class">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </TABLE>
+        </BODY>
+    </html>
+</xsl:template>
+
+<!-- summary of a package -->
+<xsl:template match="package" mode="package.summary">
+    <HTML>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="@name"/>
+            </xsl:call-template>
+        </HEAD>
+        <!-- when loading this package, it will open the classes into the frame -->
+        <BODY onload="open('package-frame.html','classListFrame')">
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="@name"/></h3>
+            <table class="log" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:apply-templates select="." mode="stats.header"/>
+                <xsl:apply-templates select="." mode="stats"/>
+            </table>
+
+            <xsl:if test="count(class) &gt; 0">
+                <H3>Classes</H3>
+                <table class="log" cellpadding="5" cellspacing="2" width="100%">
+                    <xsl:apply-templates select="." mode="stats.header"/>
+                    <xsl:apply-templates select="class" mode="stats">
+                        <xsl:sort data-type="number" select="cov.data/@hit_lines div cov.data/@total_lines"/>
+                    </xsl:apply-templates>
+                </table>
+            </xsl:if>
+            <xsl:call-template name="pageFooter"/>
+        </BODY>
+    </HTML>
+</xsl:template>
+
+<!-- details of a class -->
+<xsl:template match="class" mode="class.details">
+    <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/>
+    <HTML>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+        </HEAD>
+        <BODY>
+            <xsl:call-template name="pageHeader"/>
+            <H3>Class <xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></H3>
+
+            <!-- class summary -->
+            <table class="log" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:apply-templates select="." mode="stats.header"/>
+                <xsl:apply-templates select="." mode="stats"/>
+            </table>
+
+            <!-- details of methods -->
+            <H3>Methods</H3>
+            <table class="log" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:apply-templates select="method[1]" mode="stats.header"/>
+                <xsl:apply-templates select="method" mode="stats">
+                    <xsl:sort data-type="number" select="cov.data/@hit_lines div cov.data/@total_lines"/>
+                </xsl:apply-templates>
+            </table>
+            <xsl:call-template name="pageFooter"/>
+        </BODY>
+    </HTML>
+
+</xsl:template>
+
+<!-- Page Header -->
+<xsl:template name="pageHeader">
+  <!-- jakarta logo -->
+  <table border="0" cellpadding="0" cellspacing="0" width="100%">
+  <tr>
+    <td class="bannercell" rowspan="2">
+      <a href="http://jakarta.apache.org/">
+      <img src="http://jakarta.apache.org/images/jakarta-logo.gif" alt="http://jakarta.apache.org" align="left" border="0"/>
+      </a>
+    </td>
+        <td style="text-align:right"><h2>Source Code Coverage</h2></td>
+        </tr>
+        <tr>
+        <td style="text-align:right">Designed for use with <a href='http://www.sitraka.com/jprobe'>Sitraka JProbe</a> and <a href='http://jakarta.apache.org'>Ant</a>.</td>
+        </tr>
+  </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- Page Footer -->
+<xsl:template name="pageFooter">
+</xsl:template>
+
+
+<xsl:template name="table.header">
+    <tr>
+        <th width="80%">Name</th>
+        <th width="10%" nowrap="nowrap">Methods Hit</th>
+        <th width="10%" nowrap="nowrap">Lines Hit</th>
+    </tr>
+</xsl:template>
+
+<xsl:template match="method" mode="stats.header">
+    <tr>
+        <th width="90%">Name</th>
+        <th width="10%" nowrap="nowrap">Lines Hit</th>
+    </tr>
+</xsl:template>
+<xsl:template match="method" mode="stats">
+    <tr>
+      <xsl:call-template name="alternate-row"/>
+        <td><xsl:value-of select="@name"/></td>
+        <td>
+        <xsl:value-of select="format-number(cov.data/@hit_lines div cov.data/@total_lines,'0.0%')"/>
+        </td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="package|class" mode="stats.header">
+    <tr>
+        <th width="80%">Name</th>
+        <th width="10%" nowrap="nowrap">Methods Hit</th>
+        <th width="10%" nowrap="nowrap">Lines Hit</th>
+    </tr>
+</xsl:template>
+<xsl:template match="package|class" mode="stats">
+    <tr>
+      <xsl:call-template name="alternate-row"/>
+        <td><xsl:value-of select="@name"/></td>
+        <td><xsl:value-of select="format-number(cov.data/@hit_methods div cov.data/@total_methods,'0.0%')"/></td>
+        <td><xsl:value-of select="format-number(cov.data/@hit_lines div cov.data/@total_lines,'0.0%')"/></td>
+    </tr>
+</xsl:template>
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></LINK>
+</xsl:template>
+
+<!-- alternated row style -->
+<xsl:template name="alternate-row">
+<xsl:attribute name="class">
+  <xsl:if test="position() mod 2 = 1">a</xsl:if>
+  <xsl:if test="position() mod 2 = 0">b</xsl:if>
+</xsl:attribute>
+</xsl:template>
+
+</xsl:stylesheet>
+
+
diff --git a/trunk/src/etc/jdepend-frames.xsl b/trunk/src/etc/jdepend-frames.xsl
new file mode 100644
index 0000000..ccc9dcc
--- /dev/null
+++ b/trunk/src/etc/jdepend-frames.xsl
@@ -0,0 +1,487 @@
+<?xml version="1.0"?>
+<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+  xmlns:lxslt="http://xml.apache.org/xslt"
+  xmlns:redirect="org.apache.xalan.lib.Redirect"
+  extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   
+-->
+<!--
+
+ Sample stylesheet to be used with JDepend XML output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+ @author <a href="mailto:jtulley@novell.com">Jeff Tulley</a>
+
+  -->
+<xsl:param name="output.dir" select="'.'"/>
+
+<xsl:template match="JDepend">
+   <!-- create the index.html -->
+   <redirect:write file="{$output.dir}/index.html">
+      <xsl:call-template name="index.html"/>
+   </redirect:write>
+
+  <!-- create the stylesheet.css -->
+  <redirect:write file="{$output.dir}/stylesheet.css">
+    <xsl:call-template name="stylesheet.css"/>
+   </redirect:write>
+
+   <!-- create the overview-packages.html at the root -->
+  <redirect:write file="{$output.dir}/overview-summary.html">
+    <xsl:apply-templates select="." mode="overview.packages"/>
+  </redirect:write>
+
+   <!-- create the overview-packages.html at the root -->
+   <redirect:write file="{$output.dir}/overview-packages.html">
+    <xsl:apply-templates select="." mode="packages.details"/>
+  </redirect:write>
+
+   <!-- create the overview-cycles.html at the root -->
+   <redirect:write file="{$output.dir}/overview-cycles.html">
+    <xsl:apply-templates select="." mode="cycles.details"/>
+  </redirect:write>
+
+   <!-- create the overview-cycles.html at the root -->
+   <redirect:write file="{$output.dir}/overview-explanations.html">
+    <xsl:apply-templates select="." mode="explanations"/>
+  </redirect:write>
+
+  <!-- create the all-packages.html at the root -->
+   <redirect:write file="{$output.dir}/all-packages.html">
+    <xsl:apply-templates select="Packages" mode="all.packages"/>
+  </redirect:write>
+
+  <!-- create the all-cycles.html at the root -->
+  <redirect:write file="{$output.dir}/all-cycles.html">
+    <xsl:apply-templates select="Cycles" mode="all.cycles"/>
+  </redirect:write>
+</xsl:template>
+
+
+<xsl:template name="index.html">
+<html>
+   <head>
+      <title>JDepend Analysis</title>
+   </head>
+      <frameset cols="20%,80%">
+         <frameset rows="30%,70%">
+            <frame src="all-packages.html" name="packageListFrame"/>
+            <frame src="all-cycles.html" name="classListFrame"/>
+         </frameset>
+         <frame src="overview-summary.html" name="classFrame"/>
+      </frameset>
+      <noframes>
+         <h2>Frame Alert</h2>
+         <p>
+            This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+         </p>
+      </noframes>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+   <style type="text/css">
+    body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+    }
+    table tr td, tr th {
+      font-size: 68%;
+    }
+    table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+    }
+    table.details tr td{
+    background:#eeeee0;
+    }
+
+    p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+    margin-left:2em;
+    margin-right:2em;
+    }
+    h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+    }
+    h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+    }
+    h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+    }
+    h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+    }
+    h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+    }
+    h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+    }
+    .Error {
+    font-weight:bold; color:red;
+    }
+    .Failure {
+    font-weight:bold; color:purple;
+    }
+    .Properties {
+    text-align:right;
+    }
+  </style>
+</xsl:template>
+
+<xsl:template match="JDepend" mode="overview.packages">
+   <html>
+      <head>
+         <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+      </head>
+      <body>
+         <xsl:call-template name="pageHeader"/>
+  <table width="100%"><tr align="left"><h2>Summary</h2><td>
+  </td><td align="right">
+  [summary]
+  [<a href="overview-packages.html">packages</a>]
+  [<a href="overview-cycles.html">cycles</a>]
+  [<a href="overview-explanations.html">explanations</a>]
+   </td></tr></table>
+         <table width="100%" class="details">
+            <tr>
+               <th>Package</th>
+               <th>Total Classes</th>
+               <th><a href="overview-explanations.html#EXnumber">Abstract Classes</a></th>
+               <th><a href="overview-explanations.html#EXnumber">Concrete Classes</a></th>
+               <th><a href="overview-explanations.html#EXafferent">Afferent Couplings</a></th>
+               <th><a href="overview-explanations.html#EXefferent">Efferent Couplings</a></th>
+               <th><a href="overview-explanations.html#EXabstractness">Abstractness</a></th>
+               <th><a href="overview-explanations.html#EXinstability">Instability</a></th>
+               <th><a href="overview-explanations.html#EXdistance">Distance</a></th>
+
+            </tr>
+            <xsl:for-each select="./Packages/Package">
+               <xsl:if test="count(error) = 0">
+                  <tr>
+                     <td align="left">
+                        <a>
+                           <xsl:attribute name="href">overview-packages.html#PK<xsl:value-of select="@name"/>
+                           </xsl:attribute>
+                           <xsl:value-of select="@name"/>
+                        </a>
+                     </td>
+                     <td align="right"><xsl:value-of select="Stats/TotalClasses"/></td>
+                     <td align="right"><xsl:value-of select="Stats/AbstractClasses"/></td>
+                     <td align="right"><xsl:value-of select="Stats/ConcreteClasses"/></td>
+                     <td align="right"><xsl:value-of select="Stats/Ca"/></td>
+                     <td align="right"><xsl:value-of select="Stats/Ce"/></td>
+                     <td align="right"><xsl:value-of select="Stats/A"/></td>
+                     <td align="right"><xsl:value-of select="Stats/I"/></td>
+                     <td align="right"><xsl:value-of select="Stats/D"/></td>
+                  </tr>
+               </xsl:if>
+            </xsl:for-each>
+            <xsl:for-each select="./Packages/Package">
+               <xsl:if test="count(error) &gt; 0">
+                  <tr>
+                     <td align="left">
+                        <xsl:value-of select="@name"/>
+                     </td>
+                     <td align="left" colspan="8"><xsl:value-of select="error"/></td>
+                  </tr>
+               </xsl:if>
+            </xsl:for-each>
+         </table>
+      </body>
+   </html>
+</xsl:template>
+
+<xsl:template match="JDepend" mode="packages.details">
+   <html>
+      <head>
+          <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+      </head>
+      <body>
+         <xsl:call-template name="pageHeader"/>
+  <table width="100%"><tr align="left"><h2>Packages</h2><td>
+  </td><td align="right">
+  [<a href="overview-summary.html">summary</a>]
+  [packages]
+  [<a href="overview-cycles.html">cycles</a>]
+  [<a href="overview-explanations.html">explanations</a>]
+   </td></tr></table>
+
+  <xsl:for-each select="./Packages/Package">
+    <xsl:if test="count(error) = 0">
+      <h3><a><xsl:attribute name="name">PK<xsl:value-of select="@name"/></xsl:attribute>
+      <xsl:value-of select="@name"/></a></h3>
+
+      <table width="100%"><tr>
+        <td><a href="overview-explanations.html#EXafferent">Afferent Couplings</a>: <xsl:value-of select="Stats/Ca"/></td>
+        <td><a href="overview-explanations.html#EXefferent">Efferent Couplings</a>: <xsl:value-of select="Stats/Ce"/></td>
+        <td><a href="overview-explanations.html#EXabstractness">Abstractness</a>: <xsl:value-of select="Stats/A"/></td>
+        <td><a href="overview-explanations.html#EXinstability">Instability</a>: <xsl:value-of select="Stats/I"/></td>
+        <td><a href="overview-explanations.html#EXdistance">Distance</a>: <xsl:value-of select="Stats/D"/></td>
+      </tr></table>
+
+      <table width="100%" class="details">
+        <tr>
+          <th>Abstract Classes</th>
+          <th>Concrete Classes</th>
+          <th>Used by Packages</th>
+          <th>Uses Packages</th>
+        </tr>
+        <tr>
+          <td valign="top" width="25%">
+          <xsl:if test="count(AbstractClasses/Class)=0">
+              <i>None</i>
+            </xsl:if>
+            <xsl:for-each select="AbstractClasses/Class">
+              <xsl:value-of select="node()"/><br/>
+            </xsl:for-each>
+          </td>
+          <td valign="top" width="25%">
+            <xsl:if test="count(ConcreteClasses/Class)=0">
+              <i>None</i>
+            </xsl:if>
+            <xsl:for-each select="ConcreteClasses/Class">
+              <xsl:value-of select="node()"/><br/>
+            </xsl:for-each>
+          </td>
+          <td valign="top" width="25%">
+            <xsl:if test="count(UsedBy/Package)=0">
+              <i>None</i>
+            </xsl:if>
+            <xsl:for-each select="UsedBy/Package">
+              <a>
+                        <xsl:attribute name="href">overview-packages.html#PK<xsl:value-of select="node()"/></xsl:attribute>
+                <xsl:value-of select="node()"/>
+              </a><br/>
+            </xsl:for-each>
+          </td>
+          <td valign="top" width="25%">
+            <xsl:if test="count(DependsUpon/Package)=0">
+              <i>None</i>
+            </xsl:if>
+            <xsl:for-each select="DependsUpon/Package">
+              <a>
+                        <xsl:attribute name="href">overview-packages.html#PK<xsl:value-of select="node()"/></xsl:attribute>
+                <xsl:value-of select="node()"/>
+              </a><br/>
+            </xsl:for-each>
+          </td>
+        </tr>
+      </table>
+    </xsl:if>
+  </xsl:for-each>
+  <!-- this is often a long listing; provide a lower navigation table also -->
+  <table width="100%"><tr align="left"><td></td><td align="right">
+  [<a href="overview-summary.html">summary</a>]
+  [packages]
+  [<a href="overview-cycles.html">cycles</a>]
+  [<a href="overview-explanations.html">explanations</a>]
+   </td></tr></table>
+      </body>
+   </html>
+</xsl:template>
+
+<xsl:template match="JDepend" mode="cycles.details">
+   <html>
+      <head>
+         <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+      </head>
+      <body>
+         <xsl:call-template name="pageHeader"/>
+  <table width="100%"><tr align="left"><h2>Cycles</h2><td>
+  </td><td align="right">
+  [<a href="overview-summary.html">summary</a>]
+  [<a href="overview-packages.html">packages</a>]
+  [cycles]
+  [<a href="overview-explanations.html">explanations</a>]
+   </td></tr></table>
+  <!--<table width="100%"><tr><td>
+  </td><td align="right">
+    [<a href="#NVsummary">summary</a>]
+  [<a href="#NVpackages">packages</a>]
+  [<a href="#NVcycles">cycles</a>]
+   [<a href="#NVexplanations">explanations</a>]
+  </td></tr></table> -->
+
+  <xsl:if test="count(Cycles/Package) = 0">
+    <p>There are no cyclic dependancies.</p>
+  </xsl:if>
+  <xsl:for-each select="Cycles/Package">
+     <h3><a><xsl:attribute name="name">#CY<xsl:value-of select="@Name"/></xsl:attribute><xsl:value-of select="@Name"/></a></h3><p>
+    <xsl:for-each select="Package">
+      <xsl:value-of select="."/><br/>
+    </xsl:for-each></p>
+  </xsl:for-each>
+  <!-- this is often a long listing; provide a lower navigation table also -->
+  <table width="100%"><tr align="left"><td></td><td align="right">
+  [<a href="overview-summary.html">summary</a>]
+  [<a href="overview-packages.html">packages</a>]
+  [cycles]
+  [<a href="overview-explanations.html">explanations</a>]
+   </td></tr></table>
+  </body>
+  </html>
+</xsl:template>
+
+<xsl:template match="JDepend" mode="explanations">
+   <html>
+      <head>
+         <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+      </head>
+      <body>
+         <xsl:call-template name="pageHeader"/>
+
+  <table width="100%"><tr align="left"><h2>Explanations</h2><td>
+  </td><td align="right">
+  [<a href="overview-summary.html">summary</a>]
+  [<a href="overview-packages.html">packages</a>]
+  [<a href="overview-cycles.html">cycles</a>]
+  [explanations]
+   </td></tr></table>
+
+  <p>The following explanations are for quick reference and are lifted directly from the original <a href="http://www.clarkware.com/software/JDepend.html">JDepend documentation</a>.</p>
+
+  <h3><a name="EXnumber">Number of Classes</a></h3>
+    <p>The number of concrete and abstract classes (and interfaces) in the package is an indicator of the extensibility of the package.</p>
+  <h3><a name="EXafferent">Afferent Couplings</a></h3>
+    <p>The number of other packages that depend upon classes within the package is an indicator of the package's responsibility. </p>
+  <h3><a name="EXefferent">Efferent Couplings</a></h3>
+    <p>The number of other packages that the classes in the package depend upon is an indicator of the package's independence. </p>
+  <h3><a name="EXabstractness">Abstractness</a></h3>
+    <p>The ratio of the number of abstract classes (and interfaces) in the analyzed package to the total number of classes in the analyzed package. </p>
+    <p>The range for this metric is 0 to 1, with A=0 indicating a completely concrete package and A=1 indicating a completely abstract package. </p>
+  <h3><a name="EXinstability">Instability</a></h3>
+    <p>The ratio of efferent coupling (Ce) to total coupling (Ce / (Ce + Ca)). This metric is an indicator of the package's resilience to change. </p>
+    <p>The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package. </p>
+  <h3><a name="EXdistance">Distance</a></h3>
+    <p>The perpendicular distance of a package from the idealized line A + I = 1. This metric is an indicator of the package's balance between abstractness and stability. </p>
+    <p>A package squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal packages are either completely abstract and stable (x=0, y=1) or completely concrete and instable (x=1, y=0). </p>
+    <p>The range for this metric is 0 to 1, with D=0 indicating a package that is coincident with the main sequence and D=1 indicating a package that is as far from the main sequence as possible. </p>
+
+      </body>
+   </html>
+</xsl:template>
+
+
+<!--
+Creates an html file that contains a link to all package links in overview-packages.html.
+  @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="JDepend/Packages" mode="all.packages">
+  <html>
+    <head>
+      <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+    </head>
+    <body>
+  <table width="100%"><tr align="left"><td></td><td nowrap="nowrap" align="right">
+  [<a href="overview-summary.html" target="classFrame">summary</a>]
+  [<a href="overview-packages.html" target="classFrame">packages</a>]
+  [<a href="overview-cycles.html" target="classFrame">cycles</a>]
+  [<a href="overview-explanations.html" target="classFrame">explanations</a>]
+   </td></tr></table>
+      <h2>Packages</h2>
+        <table width="100%">
+          <xsl:apply-templates select="Package[count(error)=0]" mode="all.packages.link">
+            <xsl:sort select="@name"/>
+          </xsl:apply-templates>
+          <xsl:apply-templates select="Package[count(error) &gt; 0]" mode="all.packages.nolink">
+            <xsl:sort select="@name"/>
+          </xsl:apply-templates>
+        </table>
+    </body>
+  </html>
+</xsl:template>
+
+<xsl:template match="JDepend/Packages/Package" mode="all.packages.link">
+  <tr>
+    <td nowrap="nowrap">
+         <a href="overview-packages.html#PK{@name}" target="classFrame">
+        <xsl:value-of select="@name"/>
+      </a>
+    </td>
+  </tr>
+</xsl:template>
+
+<!--
+I do not know JDepend enough to know if every error results in a non-analyzed package,
+but that is how I am presenting it to the viewer.  This may need to change.
+  @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="JDepend/Packages/Package" mode="all.packages.nolink">
+  <tr>
+    <td nowrap="nowrap">
+       Not Analyzed: <xsl:value-of select="@name"/>
+    </td>
+  </tr>
+</xsl:template>
+
+<!--
+Creates an html file that contains a link to all package links in overview-cycles.html.
+  @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="JDepend/Cycles" mode="all.cycles">
+  <html>
+    <head>
+      <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
+    </head>
+    <body>
+  <table width="100%"><tr align="left"><td></td><td nowrap="nowrap" align="right">
+  [<a href="overview-summary.html" target="classFrame">summary</a>]
+  [<a href="overview-packages.html" target="classFrame">packages</a>]
+  [<a href="overview-cycles.html" target="classFrame">cycles</a>]
+  [<a href="overview-explanations.html" target="classFrame">explanations</a>]
+   </td></tr></table>
+      <h2>Cycles</h2>
+        <table width="100%">
+           <xsl:apply-templates select="Package" mode="all.cycles">
+            <xsl:sort select="@Name"/>
+          </xsl:apply-templates>
+        </table>
+    </body>
+  </html>
+</xsl:template>
+
+<xsl:template match="JDepend/Cycles/Package" mode="all.cycles">
+  <tr>
+    <td nowrap="nowrap">
+         <a href="overview-cycles.html#CY{@Name}" target="classFrame"><xsl:value-of select="@Name"/></a>
+    </td>
+  </tr>
+</xsl:template>
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+   <h1>JDepend Analysis</h1>
+  <table width="100%">
+  <tr>
+    <td align="left"></td>
+      <td align="right">Designed for use with <a href="http://www.clarkware.com/software/JDepend.html">JDepend</a> and <a href="http://jakarta.apache.org">Ant</a>.</td>
+  </tr>
+  </table>
+  <hr size="1"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/jdepend.xsl b/trunk/src/etc/jdepend.xsl
new file mode 100644
index 0000000..f813297
--- /dev/null
+++ b/trunk/src/etc/jdepend.xsl
@@ -0,0 +1,276 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<xsl:output method="html" indent="yes"  encoding="US-ASCII"/>
+
+<xsl:template match="JDepend">
+    <html>
+    <head>
+        <title>JDepend Analysis</title>
+        
+    <style type="text/css">
+      body {
+        font:normal 68% verdana,arial,helvetica;
+        color:#000000;
+      }
+      table tr td, tr th {
+          font-size: 68%;
+      }
+      table.details tr th{
+        font-weight: bold;
+        text-align:left;
+        background:#a6caf0;
+      }
+      table.details tr td{
+        background:#eeeee0;
+      }
+      
+      p {
+        line-height:1.5em;
+        margin-top:0.5em; margin-bottom:1.0em;
+        margin-left:2em;
+        margin-right:2em;
+      }
+      h1 {
+        margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+      }
+      h2 {
+        margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+      }
+      h3 {
+        margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+      }
+      h4 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h5 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h6 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      .Error {
+        font-weight:bold; color:red;
+      }
+      .Failure {
+        font-weight:bold; color:purple;
+      }
+      .Properties {
+        text-align:right;
+      }
+      </style>
+        
+        
+    </head>
+    <body>
+    <!--h1>JDepend Report</h1>
+    <ul>
+    <xsl:for-each select="./Packages/Package">
+                <xsl:sort select="@name"/>
+        <li><xsl:value-of select="@name"/></li>
+    </xsl:for-each>
+    </ul-->
+    
+    <h1><a name="top">JDepend Analysis</a></h1>
+    <p align="right">Designed for use with <a href="http://www.clarkware.com/software/JDepend.html">JDepend</a> and <a href="http://jakarta.apache.org">Ant</a>.</p>
+    <hr size="2" />
+    
+    <table width="100%"><tr><td>
+    <a name="NVsummary"><h2>Summary</h2></a>
+    </td><td align="right">
+    [<a href="#NVsummary">summary</a>]
+    [<a href="#NVpackages">packages</a>]
+    [<a href="#NVcycles">cycles</a>]
+    [<a href="#NVexplanations">explanations</a>]
+    </td></tr></table>
+    
+    <table width="100%" class="details">
+        <tr>
+            <th>Package</th>
+            <th>Total Classes</th>
+            <th><a href="#EXnumber">Abstract Classes</a></th>
+            <th><a href="#EXnumber">Concrete Classes</a></th>
+            <th><a href="#EXafferent">Afferent Couplings</a></th>
+            <th><a href="#EXefferent">Efferent Couplings</a></th>
+            <th><a href="#EXabstractness">Abstractness</a></th>
+            <th><a href="#EXinstability">Instability</a></th>
+            <th><a href="#EXdistance">Distance</a></th>
+            
+        </tr>
+    <xsl:for-each select="./Packages/Package">
+        <xsl:if test="count(error) = 0">
+            <tr>
+                <td align="left">
+                    <a>
+                    <xsl:attribute name="href">#PK<xsl:value-of select="@name"/>
+                    </xsl:attribute>
+                    <xsl:value-of select="@name"/>
+                    </a>
+                </td>
+                <td align="right"><xsl:value-of select="Stats/TotalClasses"/></td>
+                <td align="right"><xsl:value-of select="Stats/AbstractClasses"/></td>
+                <td align="right"><xsl:value-of select="Stats/ConcreteClasses"/></td>
+                <td align="right"><xsl:value-of select="Stats/Ca"/></td>
+                <td align="right"><xsl:value-of select="Stats/Ce"/></td>
+                <td align="right"><xsl:value-of select="Stats/A"/></td>
+                <td align="right"><xsl:value-of select="Stats/I"/></td>
+                <td align="right"><xsl:value-of select="Stats/D"/></td>
+                
+
+            </tr>
+        </xsl:if>
+    </xsl:for-each>
+    <xsl:for-each select="./Packages/Package">
+        <xsl:if test="count(error) &gt; 0">
+            <tr>
+                <td align="left">
+                    <xsl:value-of select="@name"/>
+                </td>
+                <td align="left" colspan="8"><xsl:value-of select="error"/></td>
+            </tr>
+        </xsl:if>
+    </xsl:for-each>
+    </table>
+    
+    <table width="100%"><tr><td>
+    <a name="NVpackages"><h2>Packages</h2></a>
+    </td><td align="right">
+    [<a href="#NVsummary">summary</a>]
+    [<a href="#NVpackages">packages</a>]
+    [<a href="#NVcycles">cycles</a>]
+    [<a href="#NVexplanations">explanations</a>]
+    </td></tr></table>
+    
+    <xsl:for-each select="./Packages/Package">
+        <xsl:if test="count(error) = 0">
+            <h3><a><xsl:attribute name="name">PK<xsl:value-of select="@name"/></xsl:attribute>
+            <xsl:value-of select="@name"/></a></h3>
+            
+            <table width="100%"><tr>
+                <td><a href="#EXafferent">Afferent Couplings</a>: <xsl:value-of select="Stats/Ca"/></td>
+                <td><a href="#EXefferent">Efferent Couplings</a>: <xsl:value-of select="Stats/Ce"/></td>
+                <td><a href="#EXabstractness">Abstractness</a>: <xsl:value-of select="Stats/A"/></td>
+                <td><a href="#EXinstability">Instability</a>: <xsl:value-of select="Stats/I"/></td>
+                <td><a href="#EXdistance">Distance</a>: <xsl:value-of select="Stats/D"/></td>
+            </tr></table>
+            
+            <table width="100%" class="details">
+                <tr>
+                    <th>Abstract Classes</th>
+                    <th>Concrete Classes</th>
+                    <th>Used by Packages</th>
+                    <th>Uses Packages</th>
+                </tr>
+                <tr>
+                    <td valign="top" width="25%">
+                    <xsl:if test="count(AbstractClasses/Class)=0">
+                            <i>None</i>
+                        </xsl:if>
+                        <xsl:for-each select="AbstractClasses/Class">
+                            <xsl:value-of select="node()"/><br/>
+                        </xsl:for-each>
+                    </td>
+                    <td valign="top" width="25%">
+                        <xsl:if test="count(ConcreteClasses/Class)=0">
+                            <i>None</i>
+                        </xsl:if>
+                        <xsl:for-each select="ConcreteClasses/Class">
+                            <xsl:value-of select="node()"/><br/>
+                        </xsl:for-each>
+                    </td>
+                    <td valign="top" width="25%">
+                        <xsl:if test="count(UsedBy/Package)=0">
+                            <i>None</i>
+                        </xsl:if>
+                        <xsl:for-each select="UsedBy/Package">
+                            <a>
+                                <xsl:attribute name="href">#PK<xsl:value-of select="node()"/></xsl:attribute>
+                                <xsl:value-of select="node()"/>
+                            </a><br/>
+                        </xsl:for-each>
+                    </td>
+                    <td valign="top" width="25%">
+                        <xsl:if test="count(DependsUpon/Package)=0">
+                            <i>None</i>
+                        </xsl:if>
+                        <xsl:for-each select="DependsUpon/Package">
+                            <a>
+                                <xsl:attribute name="href">#PK<xsl:value-of select="node()"/></xsl:attribute>
+                                <xsl:value-of select="node()"/>
+                            </a><br/>
+                        </xsl:for-each>
+                    </td>
+                </tr>
+            </table>
+        </xsl:if>
+    </xsl:for-each>
+    
+    <table width="100%"><tr><td>
+    <a name="NVcycles"><h2>Cycles</h2></a>
+    </td><td align="right">
+    [<a href="#NVsummary">summary</a>]
+    [<a href="#NVpackages">packages</a>]
+    [<a href="#NVcycles">cycles</a>]
+    [<a href="#NVexplanations">explanations</a>]
+    </td></tr></table>
+    
+    <xsl:if test="count(Cycles/Package) = 0">
+        <p>There are no cyclic dependancies.</p>
+    </xsl:if>
+    <xsl:for-each select="Cycles/Package">
+        <h3><xsl:value-of select="@Name"/></h3><p>
+        <xsl:for-each select="Package">
+            <xsl:value-of select="."/><br/>
+        </xsl:for-each></p>
+    </xsl:for-each>
+    
+    <table width="100%"><tr><td>
+    <a name="NVexplanations"><h2>Explanations</h2></a>
+    </td><td align="right">
+    [<a href="#NVsummary">summary</a>]
+    [<a href="#NVpackages">packages</a>]
+    [<a href="#NVcycles">cycles</a>]
+    [<a href="#NVexplanations">explanations</a>]
+    </td></tr></table>
+    
+    <p>The following explanations are for quick reference and are lifted directly from the original <a href="http://www.clarkware.com/software/JDepend.html">JDepend documentation</a>.</p>
+    
+    <h3><a name="EXnumber">Number of Classes</a></h3>
+        <p>The number of concrete and abstract classes (and interfaces) in the package is an indicator of the extensibility of the package.</p>
+    <h3><a name="EXafferent">Afferent Couplings</a></h3>
+        <p>The number of other packages that depend upon classes within the package is an indicator of the package's responsibility. </p>
+    <h3><a name="EXefferent">Efferent Couplings</a></h3>
+        <p>The number of other packages that the classes in the package depend upon is an indicator of the package's independence. </p>
+    <h3><a name="EXabstractness">Abstractness</a></h3> 
+        <p>The ratio of the number of abstract classes (and interfaces) in the analyzed package to the total number of classes in the analyzed package. </p>
+        <p>The range for this metric is 0 to 1, with A=0 indicating a completely concrete package and A=1 indicating a completely abstract package. </p>
+    <h3><a name="EXinstability">Instability</a></h3>
+        <p>The ratio of efferent coupling (Ce) to total coupling (Ce / (Ce + Ca)). This metric is an indicator of the package's resilience to change. </p>
+        <p>The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package. </p>
+    <h3><a name="EXdistance">Distance</a></h3>
+        <p>The perpendicular distance of a package from the idealized line A + I = 1. This metric is an indicator of the package's balance between abstractness and stability. </p>
+        <p>A package squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal packages are either completely abstract and stable (x=0, y=1) or completely concrete and instable (x=1, y=0). </p>
+        <p>The range for this metric is 0 to 1, with D=0 indicating a package that is coincident with the main sequence and D=1 indicating a package that is as far from the main sequence as possible. </p>
+    
+    </body>
+    </html>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/junit-frames-xalan1.xsl b/trunk/src/etc/junit-frames-xalan1.xsl
new file mode 100644
index 0000000..8cef4ca
--- /dev/null
+++ b/trunk/src/etc/junit-frames-xalan1.xsl
@@ -0,0 +1,719 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="org.apache.xalan.lib.Redirect"
+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator=","/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+-->
+<xsl:param name="output.dir" select="'.'"/>
+
+
+<xsl:template match="testsuites">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- process all packages -->
+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+        <xsl:call-template name="package">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="package">
+    <xsl:param name="name"/>
+    <xsl:variable name="package.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:call-template name="classes.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:call-template name="package.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+    <xsl:for-each select="/testsuites/testsuite[@package = $name]">
+        <redirect:write file="{$output.dir}/{$package.dir}/{@name}.html">
+            <xsl:apply-templates select="." mode="class.details"/>
+        </redirect:write>
+        <xsl:if test="string-length(./system-out)!=0">
+            <redirect:write file="{$output.dir}/{$package.dir}/{@name}-out.txt">
+                <xsl:value-of select="./system-out" />
+            </redirect:write>
+        </xsl:if>
+        <xsl:if test="string-length(./system-err)!=0">
+            <redirect:write file="{$output.dir}/{$package.dir}/{@name}-err.txt">
+                <xsl:value-of select="./system-err" />
+            </redirect:write>
+        </xsl:if>
+    </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<html>
+    <head>
+        <title>Unit Test Results.</title>
+    </head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="packageListFrame"/>
+            <frame src="allclasses-frame.html" name="classListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="classFrame"/>
+        <noframes>
+            <h2>Frame Alert</h2>
+            <p>
+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+            </p>
+        </noframes>
+    </frameset>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+}
+table tr td, table tr th {
+    font-size: 68%;
+}
+table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+}
+table.details tr td{
+    background:#eeeee0;
+}
+
+p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+}
+h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+}
+h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+}
+h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+}
+h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+.Error {
+    font-weight:bold; color:red;
+}
+.Failure {
+    font-weight:bold; color:purple;
+}
+.Properties {
+  text-align:right;
+}
+</xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every testsuite class.
+    It prints a summary of the testsuite and detailed information about
+    testcase methods.
+     ====================================================================== -->
+<xsl:template match="testsuite" mode="class.details">
+    <xsl:variable name="package.name" select="@package"/>
+    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>
+    <html>
+        <head>
+          <title>Unit Test Results: <xsl:value-of select="$class.name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+       <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:apply-templates select="properties"/>
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style type=\"text/css\">");
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Class <xsl:value-of select="$class.name"/></h3>
+
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="testsuite.test.header"/>
+                <xsl:apply-templates select="." mode="print.test"/>
+            </table>
+
+            <h2>Tests</h2>
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <xsl:call-template name="testcase.test.header"/>
+              <!--
+              test can even not be started at all (failure to load the class)
+              so report the error directly
+              -->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+                <xsl:apply-templates select="./testcase" mode="print.test"/>
+            </table>
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <xsl:if test="string-length(./system-out)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        System.out &#187;
+                    </a>
+                </div>
+            </xsl:if>
+            <xsl:if test="string-length(./system-err)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@name"/>-err.txt</xsl:attribute>
+                        System.err &#187;
+                    </a>
+                </div>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every package.
+    It prints the name of all classes that belongs to this package.
+    @param name the package name to print classes.
+     ====================================================================== -->
+<!-- list of classes in a package -->
+<xsl:template name="classes.list">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <title>Unit Test Classes: <xsl:value-of select="$name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <h2><a href="package-summary.html" target="classFrame">
+                            <xsl:value-of select="$name"/>
+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>
+                        </a></h2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    Creates an all-classes.html file that contains a link to all package-summary.html
+    on each class.
+-->
+<xsl:template match="testsuites" mode="all.classes">
+    <html>
+        <head>
+            <title>All Unit Test Classes</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite" mode="all.classes">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.classes">
+    <xsl:variable name="package.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="classFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($package.name='')">
+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all package-summary.html files on
+    each package existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="testsuites" mode="all.packages">
+    <html>
+        <head>
+            <title>All Unit Test Packages</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages">
+                    <xsl:sort select="@package"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.packages">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame">
+                <xsl:value-of select="@package"/>
+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.packages">
+    <html>
+        <head>
+            <title>Unit Test Results: Summary</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+        <xsl:call-template name="pageHeader"/>
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:otherwise>Pass</xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><xsl:value-of select="$testCount"/></td>
+            <td><xsl:value-of select="$failureCount"/></td>
+            <td><xsl:value-of select="$errorCount"/></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.
+        </td>
+        </tr>
+        </table>
+
+        <h2>Packages</h2>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <!-- get the node set containing all testsuites that have the same package -->
+                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <tr valign="top">
+                    <!-- display a failure if there is any failure/error in the package -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="sum($insamepackage/@errors) &gt; 0">Error</xsl:when>
+                            <xsl:when test="sum($insamepackage/@failures) &gt; 0">Failure</xsl:when>
+                            <xsl:otherwise>Pass</xsl:otherwise>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="./{translate(@package,'.','/')}/package-summary.html">
+                        <xsl:value-of select="@package"/>
+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+                    </a></td>
+                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$insamepackage/@timestamp"/></td>
+                    <td><xsl:value-of select="$insamepackage/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="package.summary">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="class.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/>
+            <xsl:if test="count($insamepackage) &gt; 0">
+                <h2>Classes</h2>
+                <p>
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+                    <xsl:apply-templates select="$insamepackage" mode="print.test">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+                </p>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>
+</xsl:template>
+
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1>Unit Test Results</h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href="http://www.junit.org/">JUnit</a> and <a href="http://ant.apache.org/">Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <tr valign="top">
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>
+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>
+                <xsl:otherwise>Pass</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><a href="{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><xsl:apply-templates select="@tests"/></td>
+        <td><xsl:apply-templates select="@errors"/></td>
+        <td><xsl:apply-templates select="@failures"/></td>
+        <td><xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><xsl:value-of select="@name"/></td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!-- Note : the below template error and failure are the same style
+            so just call the same style store in the toolkit template -->
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<!-- Style for the error and failure in the testcase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:param name="br"><br/></xsl:param>
+    <xsl:value-of select='stringutils:replace(string($word),"&#xA;",$br)'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/trunk/src/etc/junit-frames.xsl b/trunk/src/etc/junit-frames.xsl
new file mode 100644
index 0000000..9ea322a
--- /dev/null
+++ b/trunk/src/etc/junit-frames.xsl
@@ -0,0 +1,877 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="http://xml.apache.org/xalan/redirect"
+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator=","/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+-->
+<xsl:param name="output.dir" select="'.'"/>
+<xsl:param name="TITLE">Unit Test Results.</xsl:param>
+
+
+<xsl:template match="testsuites">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- create the all-tests.html at the root -->
+    <redirect:write file="{$output.dir}/all-tests.html">
+        <xsl:apply-templates select="." mode="all.tests"/>
+    </redirect:write>
+
+    <!-- create the alltests-fails.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-fails.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'fails'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- create the alltests-errors.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-errors.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'errors'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- process all packages -->
+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+        <xsl:call-template name="package">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="package">
+    <xsl:param name="name"/>
+    <xsl:variable name="package.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:call-template name="classes.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:call-template name="package.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+  <xsl:for-each select="/testsuites/testsuite[@package = $name]">
+    <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}.html">
+      <xsl:apply-templates select="." mode="class.details"/>
+    </redirect:write>
+    <xsl:if test="string-length(./system-out)!=0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-out.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-out"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="string-length(./system-err)!=0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-err.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-err"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="@failures != 0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-fails.html">
+        <xsl:apply-templates select="." mode="class.details">
+          <xsl:with-param name="type" select="'fails'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="@errors != 0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-errors.html">
+        <xsl:apply-templates select="." mode="class.details">
+          <xsl:with-param name="type" select="'errors'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<html>
+    <head>
+        <title><xsl:value-of select="$TITLE"/></title>
+    </head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="packageListFrame"/>
+            <frame src="allclasses-frame.html" name="classListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="classFrame"/>
+        <noframes>
+            <h2>Frame Alert</h2>
+            <p>
+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+            </p>
+        </noframes>
+    </frameset>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+}
+table tr td, table tr th {
+    font-size: 68%;
+}
+table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+}
+table.details tr td{
+    background:#eeeee0;
+}
+
+p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+}
+h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+}
+h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+}
+h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+}
+h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+.Error {
+    font-weight:bold; color:red;
+}
+.Failure {
+    font-weight:bold; color:purple;
+}
+.Properties {
+  text-align:right;
+}
+</xsl:template>
+
+<!-- Create list of all/failed/errored tests -->
+<xsl:template match="testsuites" mode="all.tests">
+    <xsl:param name="type" select="'all'"/>
+    <html>
+	<xsl:variable name="title">
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <xsl:text>All Failures</xsl:text>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <xsl:text>All Errors</xsl:text>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:text>All Tests</xsl:text>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</xsl:variable>
+	<head>
+	    <title>Unit Test Results: <xsl:value-of select="$title"/></title>
+	    <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+	</head>
+	<body>
+	    <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h2><xsl:value-of select="$title"/></h2>
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header">
+		    <xsl:with-param name="show.class" select="'yes'"/>
+		</xsl:call-template>
+		<!--
+                test can even not be started at all (failure to load the class)
+		so report the error directly
+		-->
+              <xsl:if test="./error">
+                <tr class="Error">
+                  <td colspan="4">
+                    <xsl:apply-templates select="./error"/>
+                  </td>
+                </tr>
+              </xsl:if>
+              <xsl:choose>
+                <xsl:when test="$type = 'fails'">
+                  <xsl:apply-templates select=".//testcase[failure]" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:when test="$type = 'errors'">
+                  <xsl:apply-templates select=".//testcase[error]" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:apply-templates select=".//testcase" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:otherwise>
+              </xsl:choose>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every testsuite class.
+    It prints a summary of the testsuite and detailed information about
+    testcase methods.
+     ====================================================================== -->
+<xsl:template match="testsuite" mode="class.details">
+    <xsl:param name="type" select="'all'"/>
+    <xsl:variable name="package.name" select="@package"/>
+    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>
+    <html>
+        <head>
+          <title>Unit Test Results: <xsl:value-of select="$class.name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+       <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:apply-templates select="properties"/>
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style type=\"text/css\">");
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Class <xsl:value-of select="$class.name"/></h3>
+
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="testsuite.test.header"/>
+                <xsl:apply-templates select="." mode="print.test"/>
+            </table>
+
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <h2>Failures</h2>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <h2>Errors</h2>
+		</xsl:when>
+		<xsl:otherwise>
+		    <h2>Tests</h2>
+		</xsl:otherwise>
+	    </xsl:choose>
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header"/>
+		<!--
+                test can even not be started at all (failure to load the class)
+		so report the error directly
+		-->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+		<xsl:choose>
+		    <xsl:when test="$type = 'fails'">
+			<xsl:apply-templates select="./testcase[failure]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:when test="$type = 'errors'">
+			<xsl:apply-templates select="./testcase[error]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:otherwise>
+			<xsl:apply-templates select="./testcase" mode="print.test"/>
+		    </xsl:otherwise>
+		</xsl:choose>
+            </table>
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <xsl:if test="string-length(./system-out)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        System.out &#187;
+                    </a>
+                </div>
+            </xsl:if>
+            <xsl:if test="string-length(./system-err)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-err.txt</xsl:attribute>
+                        System.err &#187;
+                    </a>
+                </div>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every package.
+    It prints the name of all classes that belongs to this package.
+    @param name the package name to print classes.
+     ====================================================================== -->
+<!-- list of classes in a package -->
+<xsl:template name="classes.list">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <title>Unit Test Classes: <xsl:value-of select="$name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <h2><a href="package-summary.html" target="classFrame">
+                            <xsl:value-of select="$name"/>
+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>
+                        </a></h2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@id}_{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    Creates an all-classes.html file that contains a link to all package-summary.html
+    on each class.
+-->
+<xsl:template match="testsuites" mode="all.classes">
+    <html>
+        <head>
+            <title>All Unit Test Classes</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite" mode="all.classes">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.classes">
+    <xsl:variable name="package.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="classFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($package.name='')">
+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@id"/>_<xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all package-summary.html files on
+    each package existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="testsuites" mode="all.packages">
+    <html>
+        <head>
+            <title>All Unit Test Packages</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages">
+                    <xsl:sort select="@package"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.packages">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame">
+                <xsl:value-of select="@package"/>
+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.packages">
+    <html>
+        <head>
+            <title>Unit Test Results: Summary</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+        <xsl:call-template name="pageHeader"/>
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:otherwise>Pass</xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><a title="Display all tests" href="all-tests.html"><xsl:value-of select="$testCount"/></a></td>
+            <td><a title="Display all failures" href="alltests-fails.html"><xsl:value-of select="$failureCount"/></a></td>
+            <td><a title="Display all errors" href="alltests-errors.html"><xsl:value-of select="$errorCount"/></a></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.
+        </td>
+        </tr>
+        </table>
+
+        <h2>Packages</h2>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <!-- get the node set containing all testsuites that have the same package -->
+                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <tr valign="top">
+                    <!-- display a failure if there is any failure/error in the package -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="sum($insamepackage/@errors) &gt; 0">Error</xsl:when>
+                            <xsl:when test="sum($insamepackage/@failures) &gt; 0">Failure</xsl:when>
+                            <xsl:otherwise>Pass</xsl:otherwise>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="./{translate(@package,'.','/')}/package-summary.html">
+                        <xsl:value-of select="@package"/>
+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+                    </a></td>
+                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$insamepackage/@timestamp"/></td>
+                    <td><xsl:value-of select="$insamepackage/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="package.summary">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="class.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/>
+            <xsl:if test="count($insamepackage) &gt; 0">
+                <h2>Classes</h2>
+                <p>
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+                    <xsl:apply-templates select="$insamepackage" mode="print.test">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+                </p>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>
+</xsl:template>
+
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1><xsl:value-of select="$TITLE"/></h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href="http://www.junit.org/">JUnit</a> and <a href="http://ant.apache.org/">Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <xsl:param name="show.class" select="''"/>
+    <tr valign="top">
+	<xsl:if test="boolean($show.class)">
+	    <th>Class</th>
+	</xsl:if>
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>
+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>
+                <xsl:otherwise>Pass</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:apply-templates select="@tests"/></a></td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="@errors != 0">
+		    <a title="Display only errors" href="{@id}_{@name}-errors.html"><xsl:apply-templates select="@errors"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="@errors"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="@failures != 0">
+		    <a title="Display only failures" href="{@id}_{@name}-fails.html"><xsl:apply-templates select="@failures"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="@failures"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td><xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <xsl:param name="show.class" select="''"/>
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+	<xsl:variable name="class.href">
+	    <xsl:value-of select="concat(translate(../@package,'.','/'), '/', ../@id, '_', ../@name, '.html')"/>
+	</xsl:variable>
+	<xsl:if test="boolean($show.class)">
+	    <td><a href="{$class.href}"><xsl:value-of select="../@name"/></a></td>
+	</xsl:if>
+        <td>
+	    <a name="{@name}"/>
+	    <xsl:choose>
+		<xsl:when test="boolean($show.class)">
+		    <a href="{concat($class.href, '#', @name)}"><xsl:value-of select="@name"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:value-of select="@name"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!-- Note : the below template error and failure are the same style
+            so just call the same style store in the toolkit template -->
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<!-- Style for the error and failure in the testcase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/trunk/src/etc/junit-noframes.xsl b/trunk/src/etc/junit-noframes.xsl
new file mode 100644
index 0000000..f0ab964
--- /dev/null
+++ b/trunk/src/etc/junit-noframes.xsl
@@ -0,0 +1,467 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+        xmlns:lxslt="http://xml.apache.org/xslt"
+        xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"
+  doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" />
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<xsl:param name="TITLE">Unit Test Results.</xsl:param>
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a non-framed report that can be useful to send via
+ e-mail or such.
+
+-->
+<xsl:template match="testsuites">
+    <html>
+        <head>
+            <title><xsl:value-of select="$TITLE"/></title>
+    <style type="text/css">
+      body {
+        font:normal 68% verdana,arial,helvetica;
+        color:#000000;
+      }
+      table tr td, table tr th {
+          font-size: 68%;
+      }
+      table.details tr th{
+        font-weight: bold;
+        text-align:left;
+        background:#a6caf0;
+      }
+      table.details tr td{
+        background:#eeeee0;
+      }
+
+      p {
+        line-height:1.5em;
+        margin-top:0.5em; margin-bottom:1.0em;
+      }
+      h1 {
+        margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+      }
+      h2 {
+        margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+      }
+      h3 {
+        margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+      }
+      h4 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h5 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h6 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      .Error {
+        font-weight:bold; color:red;
+      }
+      .Failure {
+        font-weight:bold; color:purple;
+      }
+      .Properties {
+        text-align:right;
+      }
+      </style>
+      <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:for-each select="./testsuite">
+            <xsl:apply-templates select="properties"/>
+        </xsl:for-each>
+
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style>")
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <a name="top"></a>
+            <xsl:call-template name="pageHeader"/>
+
+            <!-- Summary part -->
+            <xsl:call-template name="summary"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- Package List part -->
+            <xsl:call-template name="packagelist"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- For each package create its part -->
+            <xsl:call-template name="packages"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- For each class create the  part -->
+            <xsl:call-template name="classes"/>
+
+        </body>
+    </html>
+</xsl:template>
+
+
+
+    <!-- ================================================================== -->
+    <!-- Write a list of all packages with an hyperlink to the anchor of    -->
+    <!-- of the package name.                                               -->
+    <!-- ================================================================== -->
+    <xsl:template name="packagelist">
+        <h2>Packages</h2>
+        Note: package statistics are not computed recursively, they only sum up all of its testsuites numbers.
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <!-- list all packages recursively -->
+            <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package"/>
+                <xsl:variable name="testsuites-in-package" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <xsl:variable name="testCount" select="sum($testsuites-in-package/@tests)"/>
+                <xsl:variable name="errorCount" select="sum($testsuites-in-package/@errors)"/>
+                <xsl:variable name="failureCount" select="sum($testsuites-in-package/@failures)"/>
+                <xsl:variable name="timeCount" select="sum($testsuites-in-package/@time)"/>
+
+                <!-- write a summary for the package -->
+                <tr valign="top">
+                    <!-- set a nice color depending if there is an error/failure -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                            <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="#{@package}"><xsl:value-of select="@package"/></a></td>
+                    <td><xsl:value-of select="$testCount"/></td>
+                    <td><xsl:value-of select="$errorCount"/></td>
+                    <td><xsl:value-of select="$failureCount"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="$timeCount"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$testsuites-in-package/@timestamp"/></td>
+                    <td><xsl:value-of select="$testsuites-in-package/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+    </xsl:template>
+
+
+    <!-- ================================================================== -->
+    <!-- Write a package level report                                       -->
+    <!-- It creates a table with values from the document:                  -->
+    <!-- Name | Tests | Errors | Failures | Time                            -->
+    <!-- ================================================================== -->
+    <xsl:template name="packages">
+        <!-- create an anchor to this package name -->
+        <xsl:for-each select="/testsuites/testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+            <xsl:sort select="@package"/>
+                <a name="{@package}"></a>
+                <h3>Package <xsl:value-of select="@package"/></h3>
+
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+
+                    <!-- match the testsuites of this package -->
+                    <xsl:apply-templates select="/testsuites/testsuite[./@package = current()/@package]" mode="print.test"/>
+                </table>
+                <a href="#top">Back to top</a>
+                <p/>
+                <p/>
+        </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template name="classes">
+        <xsl:for-each select="testsuite">
+            <xsl:sort select="@name"/>
+            <!-- create an anchor to this class name -->
+            <a name="{@name}"></a>
+            <h3>TestCase <xsl:value-of select="@name"/></h3>
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+              <xsl:call-template name="testcase.test.header"/>
+              <!--
+              test can even not be started at all (failure to load the class)
+              so report the error directly
+              -->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+                <xsl:apply-templates select="./testcase" mode="print.test"/>
+            </table>
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <p/>
+
+            <a href="#top">Back to top</a>
+        </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template name="summary">
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><xsl:value-of select="$testCount"/></td>
+            <td><xsl:value-of select="$failureCount"/></td>
+            <td><xsl:value-of select="$errorCount"/></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <i>failures</i> are anticipated and checked for with assertions while <i>errors</i> are unanticipated.
+        </td>
+        </tr>
+        </table>
+    </xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1><xsl:value-of select="$TITLE"/></h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href='http://www.junit.org'>JUnit</a> and <a href='http://ant.apache.org/ant'>Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <tr valign="top">
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <!-- set a nice color depending if there is an error/failure -->
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>
+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>
+            </xsl:choose>
+        </xsl:attribute>
+
+        <!-- print testsuite information -->
+        <td><a href="#{@name}"><xsl:value-of select="@name"/></a></td>
+        <td><xsl:value-of select="@tests"/></td>
+        <td><xsl:value-of select="@errors"/></td>
+        <td><xsl:value-of select="@failures"/></td>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="failure | error">Error</xsl:when>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><xsl:value-of select="@name"/></td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<!-- Style for the error and failure in the tescase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <!-- display the stacktrace -->
+    <code>
+        <br/><br/>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the later is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/log.xsl b/trunk/src/etc/log.xsl
new file mode 100644
index 0000000..5040993
--- /dev/null
+++ b/trunk/src/etc/log.xsl
@@ -0,0 +1,203 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+   
+-->
+ 
+<!--
+
+  The purpose have this XSL is to provide a nice way to look at the output
+  from the Ant XmlLogger (ie: ant -listener org.apache.tools.ant.XmlLogger )
+  
+  @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
+  
+-->
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+
+<xsl:template match="/">
+<html>
+  <head>
+    <style type="text/css">
+    .bannercell {
+      border: 0px;
+      padding: 0px;
+    }
+    body {
+      margin: 0;
+      font:normal 100% arial,helvetica,sanserif;
+      background-color:#FFFFFF;
+      color:#000000;
+    }
+    table.status {
+      font:bold 80% arial,helvetica,sanserif;
+      background-color:#525D76;
+      color:#ffffff;
+    }
+    table.log tr td, tr th {
+      font-size: 80%;
+    }
+    .error {
+      color:red;
+    }
+    .warn {
+      color:brown;
+    }
+    .info {
+      color:gray;
+    }
+    .debug{
+      color:gray;
+    }
+    .failed {
+      font-size:80%;
+      background-color: red;
+      color:#FFFFFF;
+      font-weight: bold
+    }
+    .complete {
+      font-size:80%;
+      background-color: #525D76;
+      color:#FFFFFF;
+      font-weight: bold
+    }
+    .a td { 
+      background: #efefef;
+    }
+    .b td { 
+      background: #fff;
+    }
+    th, td {
+      text-align: left;
+      vertical-align: top;
+    }
+    th {
+      background: #ccc;
+      color: black;
+    }
+    table, th, td {
+      border: none
+    }
+    h3 {
+      font:bold 80% arial,helvetica,sanserif;
+      background: #525D76;
+      color: white;
+      text-decoration: none;
+      padding: 5px;
+      margin-right: 2px;
+      margin-left: 2px;
+      margin-bottom: 0;
+    }
+    </style>
+  </head>
+  <body>
+    <!-- jakarta logo -->
+    <table border="0" cellpadding="0" cellspacing="0" width="100%">
+    <tr>
+      <td valign="top" class="bannercell">
+        <a href="http://jakarta.apache.org/">
+        <img src="http://jakarta.apache.org/images/jakarta-logo.gif" alt="http://jakarta.apache.org" align="left" border="0"/>
+        </a>
+      </td>
+      <td style="text-align:right;vertical-align:bottom">
+        <a href="http://ant.apache.org/">Apache Ant</a>
+      </td>
+    </tr>
+    </table>
+      
+    <table border="0" width="100%">
+    <tr><td><hr noshade="yes" size="1"/></td></tr>
+    </table>
+
+    <xsl:apply-templates select="build"/>
+
+  </body>
+</html>
+</xsl:template>
+
+<xsl:template match="build">
+  <!-- build status -->
+  <table width="100%">
+    <xsl:attribute name="class">
+      <xsl:if test="@error">failed</xsl:if>
+      <xsl:if test="not(@error)">complete</xsl:if>
+    </xsl:attribute>
+    <tr>
+      <xsl:if test="@error">
+        <td nowrap="yes">Build Failed</td> 
+      </xsl:if>
+      <xsl:if test="not(@error)">
+        <td nowrap="yes">Build Complete</td>
+      </xsl:if>
+        <td style="text-align:right" nowrap="yes">Total Time: <xsl:value-of select="@time"/></td>
+    </tr>
+    <tr>
+      <td colspan="2">
+        <xsl:if test="@error">
+          <tt><xsl:value-of select="@error"/></tt><br/>
+          <i style="font-size:80%">See the <a href="#stacktrace" alt="Click for details">stacktrace</a>.</i>
+        </xsl:if>
+      </td>
+    </tr>
+  </table>
+  <table border="1" cellspacing="2" cellpadding="3" width="100%" style="font-size:80%">
+    <tr class="a"><td width="1">ant.file</td><td><xsl:value-of select="substring-after(//message[contains(text(),'ant.file')], '->')"/></td></tr>
+    <tr class="b"><td width="1">ant.version</td><td><xsl:value-of select="substring-after(//message[contains(text(),'ant.version')], '->')"/></td></tr>
+    <tr class="a"><td width="1">java.version</td><td><xsl:value-of select="substring-after(//message[contains(text(),'java.vm.version')], '->')"/></td></tr>
+    <tr class="b"><td width="1">os.name</td><td><xsl:value-of select="substring-after(//message[contains(text(),'os.name')], '->')"/></td></tr>
+  </table>
+  <!-- build information -->
+  <h3>Build events</h3>
+  <table class="log" border="1" cellspacing="2" cellpadding="3" width="100%">
+  <tr>
+    <th nowrap="yes" align="left" width="1%">target</th>
+    <th nowrap="yes" align="left" width="1%">task</th>
+    <th nowrap="yes" align="left">message</th>
+  </tr>
+  <xsl:apply-templates select=".//message[@priority != 'debug']"/>
+  </table>
+  <p>
+  <!-- stacktrace -->
+  <xsl:if test="stacktrace">
+  <a name="stacktrace"/>
+  <h3>Error details</h3>
+  <table width="100%">
+    <tr><td>
+      <pre><xsl:value-of select="stacktrace"/></pre>
+    </td></tr>
+  </table>
+  </xsl:if>
+  </p>
+</xsl:template>
+
+<!-- report every message but those with debug priority -->
+<xsl:template match="message[@priority!='debug']">
+  <tr valign="top">
+    <!-- alternated row style -->
+    <xsl:attribute name="class">
+      <xsl:if test="position() mod 2 = 1">a</xsl:if>
+      <xsl:if test="position() mod 2 = 0">b</xsl:if>
+    </xsl:attribute>
+    <td nowrap="yes" width="1%"><xsl:value-of select="../../@name"/></td>
+    <td nowrap="yes" style="text-align:right" width="1%">[ <xsl:value-of select="../@name"/> ]</td>
+    <td class="{@priority}" nowrap="yes">
+            <xsl:value-of select="text()"/>
+    </td>
+  </tr>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/manifest b/trunk/src/etc/manifest
new file mode 100644
index 0000000..758bc0f
--- /dev/null
+++ b/trunk/src/etc/manifest
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Main-Class: org.apache.tools.ant.Main
+
+
diff --git a/trunk/src/etc/maudit-frames.xsl b/trunk/src/etc/maudit-frames.xsl
new file mode 100644
index 0000000..257c0c8
--- /dev/null
+++ b/trunk/src/etc/maudit-frames.xsl
@@ -0,0 +1,503 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="org.apache.xalan.lib.Redirect"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+
+    Stylesheet to transform an XML file generated by the Ant MAudit task into
+    a set of JavaDoc-like HTML page to make pages more convenient to be browsed.
+
+    It use the Xalan redirect extension to write to multiple output files.
+
+    @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+-->
+
+<xsl:param name="output.dir" select="'.'"/>
+
+
+<xsl:template match="classes">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- process all packages -->
+    <xsl:for-each select="./class[not(./@package = preceding-sibling::class/@package)]">
+        <xsl:call-template name="package">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="package">
+    <xsl:param name="name"/>
+    <xsl:variable name="package.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:call-template name="classes.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:call-template name="package.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+    <xsl:for-each select="/classes/class[@package = $name]">
+        <redirect:write file="{$output.dir}/{$package.dir}/{@name}.html">
+            <xsl:apply-templates select="." mode="class.details"/>
+        </redirect:write>
+    </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<HTML>
+    <HEAD><TITLE>Audit Results.</TITLE></HEAD>
+    <FRAMESET cols="20%,80%">
+        <FRAMESET rows="30%,70%">
+            <FRAME src="overview-frame.html" name="packageListFrame"/>
+            <FRAME src="allclasses-frame.html" name="classListFrame"/>
+        </FRAMESET>
+        <FRAME src="overview-summary.html" name="classFrame"/>
+    </FRAMESET>
+    <noframes>
+        <H2>Frame Alert</H2>
+        <P>
+        This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+        </P>
+    </noframes>
+</HTML>
+</xsl:template>
+
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+    .bannercell {
+      border: 0px;
+      padding: 0px;
+    }
+    body {
+      margin-left: 10;
+      margin-right: 10;
+      font:normal 80% arial,helvetica,sanserif;
+      background-color:#FFFFFF;
+      color:#000000;
+    }
+    .a td {
+      background: #efefef;
+    }
+    .b td {
+      background: #fff;
+    }
+    th, td {
+      text-align: left;
+      vertical-align: top;
+    }
+    th {
+      font-weight:bold;
+      background: #ccc;
+      color: black;
+    }
+    table, th, td {
+      font-size:100%;
+      border: none
+    }
+    table.log tr td, tr th {
+
+    }
+    h2 {
+      font-weight:bold;
+      font-size:140%;
+      margin-bottom: 5;
+    }
+    h3 {
+      font-size:100%;
+      font-weight:bold;
+      background: #525D76;
+      color: white;
+      text-decoration: none;
+      padding: 5px;
+      margin-right: 2px;
+      margin-left: 2px;
+      margin-bottom: 0;
+    }
+</xsl:template>
+
+
+<!-- print the violations of the class -->
+<xsl:template match="class" mode="class.details">
+    <xsl:variable name="package.name" select="@package"/>
+    <HTML>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+        </HEAD>
+        <BODY>
+            <xsl:call-template name="pageHeader"/>
+            <H3>Class <xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></H3>
+
+            <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:call-template name="class.audit.header"/>
+                <xsl:apply-templates select="." mode="print.audit"/>
+            </table>
+
+            <H3>Violations</H3>
+            <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:call-template name="violation.audit.header"/>
+                <xsl:apply-templates select="./violation" mode="print.audit">
+                    <xsl:sort data-type="number" select="@line"/>
+                </xsl:apply-templates>
+            </table>
+            <xsl:call-template name="pageFooter"/>
+        </BODY>
+    </HTML>
+</xsl:template>
+
+
+<!-- list of classes in a package -->
+<xsl:template name="classes.list">
+    <xsl:param name="name"/>
+    <HTML>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </HEAD>
+        <BODY>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <H2><a href="package-summary.html" target="classFrame"><xsl:value-of select="$name"/></a></H2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Classes</h2>
+            <TABLE WIDTH="100%">
+                <xsl:apply-templates select="/classes/class[./@package = $name]" mode="classes.list">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </TABLE>
+        </BODY>
+    </HTML>
+</xsl:template>
+<!-- the class to list -->
+<xsl:template match="class" mode="classes.list">
+    <tr>
+        <td nowrap="nowrap">
+            <!-- @bug naming to fix for inner classes -->
+            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an all-classes.html file that contains a link to all package-summary.html
+    on each class.
+-->
+<xsl:template match="classes" mode="all.classes">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:apply-templates select=".//class" mode="all.classes">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="class" mode="all.classes">
+    <!-- (ancestor::package)[last()] is buggy in MSXML3 ? -->
+    <xsl:variable name="package.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="classFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($package.name='')">
+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all package-summary.html files on
+    each package existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="classes" mode="all.packages">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+                <table width="100%">
+                    <xsl:apply-templates select="class[not(./@package = preceding-sibling::class/@package)]" mode="all.packages">
+                        <xsl:sort select="@package" order="ascending"/>
+                    </xsl:apply-templates>
+                </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="class" mode="all.packages">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="{translate(@package,'.','/')}/package-summary.html" target="classFrame">
+                <xsl:value-of select="@package"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="classes" mode="overview.packages">
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body onload="open('allclasses-frame.html','classListFrame')">
+        <xsl:call-template name="pageHeader"/>
+        <h3>Summary</h3>
+        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+        <tr>
+            <th>Audited classes</th>
+            <th>Reported classes</th>
+            <th>Violations</th>
+        </tr>
+        <tr class="a">
+            <td><xsl:value-of select="@audited"/></td>
+            <td><xsl:value-of select="@reported"/></td>
+            <td><xsl:value-of select="@violations"/></td>
+        </tr>
+        </table>
+        <table border="0" width="100%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: Rules checked have originated from style guidelines suggested by the language designers,
+        experience from the Java development community and insite experience. Violations are generally
+        reported with a reference to the <a href="http://java.sun.com/docs/books/jls/second_edition/html/jTOC.doc.html">Java Language Specifications</a> (JLS x.x.x)
+        and Metamata Audit rules (x.x).
+        Please consult these documents for additional information about violations.
+        <p/>
+        Rules checked also enforce adherence to <a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">Sun Java coding guidelines</a> in use at Jakarta.
+        <p/>
+        One should note that these violations do not necessary underline errors but should be used
+        as an indication for <i>possible</i> errors. As always, use your best judgment and review
+        them carefully, it might save you hours of debugging.
+        </td>
+        </tr>
+        </table>
+
+        <h3>Packages</h3>
+        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+            <xsl:call-template name="class.audit.header"/>
+            <xsl:for-each select="class[not(./@package = preceding-sibling::class/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <tr>
+          <xsl:call-template name="alternate-row"/>
+                    <td><a href="{translate(@package,'.','/')}/package-summary.html"><xsl:value-of select="@package"/></a></td>
+                    <td><xsl:value-of select="sum(/classes/class[./@package = current()/@package]/@violations)"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        <xsl:call-template name="pageFooter"/>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="package.summary">
+    <xsl:param name="name"/>
+    <HTML>
+        <HEAD>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </HEAD>
+        <BODY>
+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="100%">
+                <xsl:call-template name="class.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:if test="count(/classes/class[./@package = $name]) &gt; 0">
+                <H3>Classes</H3>
+                <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+                    <xsl:call-template name="class.audit.header"/>
+                    <xsl:apply-templates select="/classes/class[./@package = $name]" mode="print.audit">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+            </xsl:if>
+            <xsl:call-template name="pageFooter"/>
+        </BODY>
+    </HTML>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></LINK>
+</xsl:template>
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+
+  <!-- jakarta logo -->
+  <table border="0" cellpadding="0" cellspacing="0" width="100%">
+  <tr>
+    <td class="bannercell" rowspan="2">
+      <a href="http://jakarta.apache.org/">
+      <img src="http://jakarta.apache.org/images/jakarta-logo.gif" alt="http://jakarta.apache.org" align="left" border="0"/>
+      </a>
+    </td>
+        <td style="text-align:right"><h2>Source Code Audit</h2></td>
+        </tr>
+        <tr>
+        <td style="text-align:right">Designed for use with <a href='http://www.webgain.com/products/quality_analyzer/'>Webgain QA/Metamata Audit</a> and <a href='http://jakarta.apache.org'>Ant</a>.</td>
+        </tr>
+  </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- Page HEADER -->
+<xsl:template name="pageFooter">
+</xsl:template>
+
+
+<!-- class header -->
+<xsl:template name="class.audit.header">
+    <tr>
+        <th width="80%">Name</th>
+        <th>Violations</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="violation.audit.header">
+    <tr>
+        <th>Line</th>
+        <th>Message</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="class" mode="print.audit">
+    <tr>
+    <xsl:call-template name="alternate-row"/>
+        <td><a href="{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><xsl:apply-templates select="@violations"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="violation" mode="print.audit">
+    <tr>
+    <xsl:call-template name="alternate-row"/>
+        <td><xsl:value-of select="@line"/></td>
+        <td><xsl:apply-templates select="@message"/></td>
+    </tr>
+</xsl:template>
+
+<!-- alternated row style -->
+<xsl:template name="alternate-row">
+<xsl:attribute name="class">
+  <xsl:if test="position() mod 2 = 1">a</xsl:if>
+  <xsl:if test="position() mod 2 = 0">b</xsl:if>
+</xsl:attribute>
+</xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/trunk/src/etc/mmetrics-frames.xsl b/trunk/src/etc/mmetrics-frames.xsl
new file mode 100644
index 0000000..8b4643a
--- /dev/null
+++ b/trunk/src/etc/mmetrics-frames.xsl
@@ -0,0 +1,1026 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+  xmlns:lxslt="http://xml.apache.org/xslt"
+  xmlns:xalan="http://xml.apache.org/xalan"
+  xmlns:redirect="org.apache.xalan.lib.Redirect"
+  exclude-result-prefixes="xalan"
+  extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+  @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+  -->
+<xsl:param name="output.dir" select="'.'"/>
+
+<!-- default max value for the metrics -->
+<xsl:param name="vg.max" select="10"/>
+<xsl:param name="loc.max" select="1000"/>
+<xsl:param name="dit.max" select="10"/>
+<xsl:param name="noa.max" select="250"/>
+<xsl:param name="nrm.max" select="50"/>
+<xsl:param name="nlm.max" select="250"/>
+<xsl:param name="wmc.max" select="250"/>
+<xsl:param name="rfc.max" select="50"/>
+<xsl:param name="dac.max" select="10"/>
+<xsl:param name="fanout.max" select="10"/>
+<xsl:param name="cbo.max" select="15"/>
+<xsl:param name="lcom.max" select="10"/>
+<xsl:param name="nocl.max" select="10"/>
+
+
+<!-- create a tree fragment to speed up processing -->
+<xsl:variable name="doctree.var">
+  <xsl:element name="classes">
+    <xsl:for-each select=".//class">
+      <xsl:element name="class">
+        <xsl:attribute name="package">
+          <xsl:value-of select="(ancestor::package)[last()]/@name"/>
+        </xsl:attribute>
+        <xsl:copy-of select="@*"/>
+        <xsl:attribute name="name">
+          <xsl:apply-templates select="." mode="class.name"/>
+        </xsl:attribute>
+        <xsl:copy-of select="method"/>
+      </xsl:element>
+    </xsl:for-each>
+  </xsl:element>
+</xsl:variable>
+
+<xsl:variable name="doctree" select="xalan:nodeset($doctree.var)"/>
+
+<xsl:template match="metrics">
+
+  <!-- create the index.html -->
+  <redirect:write file="{$output.dir}/index.html">
+    <xsl:call-template name="index.html"/>
+  </redirect:write>
+
+  <!-- create the stylesheet.css -->
+  <redirect:write file="{$output.dir}/stylesheet.css">
+    <xsl:call-template name="stylesheet.css"/>
+  </redirect:write>
+
+  <redirect:write file="{$output.dir}/metrics-reference.html">
+    <xsl:call-template name="metrics-reference.html"/>
+  </redirect:write>
+
+  <!-- create the overview-packages.html at the root -->
+  <redirect:write file="{$output.dir}/overview-summary.html">
+    <xsl:apply-templates select="." mode="overview.packages"/>
+  </redirect:write>
+
+  <!-- create the all-packages.html at the root -->
+  <redirect:write file="{$output.dir}/overview-frame.html">
+    <xsl:apply-templates select="." mode="all.packages"/>
+  </redirect:write>
+
+  <!-- create the all-classes.html at the root -->
+  <redirect:write file="{$output.dir}/allclasses-frame.html">
+    <xsl:apply-templates select="." mode="all.classes"/>
+  </redirect:write>
+
+  <!-- process all packages -->
+  <xsl:apply-templates select=".//package"/>
+</xsl:template>
+
+
+<xsl:template match="package">
+  <xsl:variable name="package.name" select="@name"/>
+  <xsl:variable name="package.dir">
+    <xsl:if test="not($package.name = 'unnamed package')"><xsl:value-of select="translate($package.name,'.','/')"/></xsl:if>
+    <xsl:if test="$package.name = 'unnamed package'">.</xsl:if>
+  </xsl:variable>
+  <!-- create a classes-list.html in the package directory -->
+  <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+    <xsl:apply-templates select="." mode="classes.list"/>
+  </redirect:write>
+
+  <!-- create a package-summary.html in the package directory -->
+  <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+    <xsl:apply-templates select="." mode="package.summary"/>
+  </redirect:write>
+
+  <!-- for each class, creates a @name.html -->
+  <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+  <xsl:for-each select="$doctree/classes/class[@package = current()/@name]">
+      <!--Processing <xsl:value-of select="$class.name"/><xsl:text>&#10;</xsl:text> -->
+    <redirect:write file="{$output.dir}/{$package.dir}/{@name}.html">
+      <xsl:apply-templates select="." mode="class.details"/>
+    </redirect:write>
+  </xsl:for-each>
+</xsl:template>
+
+<!-- little trick to compute the classname for inner and non inner classes -->
+<!-- this is all in one line to avoid CRLF in the name -->
+<xsl:template match="class" mode="class.name">
+    <xsl:if test="parent::class"><xsl:apply-templates select="parent::class" mode="class.name"/>.<xsl:value-of select="@name"/></xsl:if><xsl:if test="not(parent::class)"><xsl:value-of select="@name"/></xsl:if>
+</xsl:template>
+
+
+<xsl:template name="index.html">
+<HTML>
+  <HEAD><TITLE>Metrics Results.</TITLE></HEAD>
+  <FRAMESET cols="20%,80%">
+    <FRAMESET rows="30%,70%">
+      <FRAME src="overview-frame.html" name="packageListFrame"/>
+      <FRAME src="allclasses-frame.html" name="classListFrame"/>
+    </FRAMESET>
+    <FRAME src="overview-summary.html" name="classFrame"/>
+  </FRAMESET>
+  <noframes>
+    <H2>Frame Alert</H2>
+    <P>
+    This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+    </P>
+  </noframes>
+</HTML>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="metrics-reference.html">
+<html>
+<head>
+<link title="Style" type="text/css" rel="stylesheet" href="stylesheet.css"/>
+</head>
+<body style="text-align:justify;">
+<h2>Metrics Reference</h2>
+<a href="#V(G)">V(G)</a> |
+<a href="#LOC">LOC</a> |
+<a href="#DIT">DIT</a> |
+<a href="#NOA">NOA</a> |
+<a href="#NRM">NRM</a> |
+<a href="#NLM">NLM</a> |
+<a href="#WMC">WMC</a> |
+<a href="#RFC">RFC</a> |
+<a href="#DAC">DAC</a> |
+<a href="#FANOUT">FANOUT</a> |
+<a href="#CBO">CBO</a> |
+<a href="#LCOM">LCOM</a> |
+<a href="#NOC">NOC</a>
+
+<a name="V(G)"/>
+<h3>Cyclomatic Complexity - V(G)</h3>
+This metric was introduced in the 1970s to measure the amount of control
+flow complexity or branching complexity in a module such as a
+subroutine. It gives the number of paths that may be taken through the
+code, and was initially developed to give some measure of the cost of
+producing a test case for the module by executing each path.
+<p/>
+Methods with a high cyclomatic complexity tend to be more difficult to
+understand and maintain. In general the more complex the methods of an
+application, the more difficult it will be to test it, and this will adversely
+affect its reliability.
+<p/>
+V(G) is a measure of the control flow complexity of a method or
+constructor.  It counts the number of branches in the body of the method,
+defined as:
+<ul>
+<li>while statements;</li>
+<li>if statements;</li>
+<li>for statements.</li>
+</ul>
+
+The metric can also be configured to count each case of a switch
+statement as well.
+
+<a name="LOC"/>
+<h3>Lines of Code - LOC</h3>
+
+This is perhaps the simplest of all the metrics to define and compute.
+Counting lines has a long history as a software metric dating from before
+the rise of structured programming, and it is still in widespread use today.
+The size of a method affects the ease with which it can be understood, its
+reusability and its maintainability. There are a variety of ways that the size
+can be calculated. These include counting all the lines of code, the number
+of statements, the blank lines of code, the lines of commentary, and the
+lines consisting only of syntax such as block delimiters.
+<p/>
+This metric can also be used for sizing other constructs as well, for
+example, the overall size of a Java class or package can be measured by
+counting the number of source lines it consists of.
+<p/>
+LOC can be used to determine the size of a compilation unit (source file),
+class or interface, method, constructor, or field.  It can be configured to
+ignore:
+<ul>
+<li>blank lines;</li>
+<li>lines consisting only of comments;</li>
+<li>lines consisting only of opening and closing braces.</li>
+</ul>
+
+<a name="DIT"/>
+<h3>Depth of Inheritance Hierarchy - DIT</h3>
+
+This metric calculates how far down the inheritance hierarchy a class is
+declared. In Java all classes have java.lang.Object as their ultimate
+superclass, which is defined to have a depth of 1. So a class that
+immediately extends java.lang.Object has a metric value of 2; any of its
+subclasses will have a value of 3, and so on.
+<p/>
+A class that is deep within the tree inherits more methods and state
+variables, thereby increasing its complexity and making it difficult to
+predict its behavior. It can be harder to understand a system with many
+inheritance layers.
+<p/>
+DIT is defined for classes and interfaces:
+<ul>
+<li>all interface types have a depth of 1;</li>
+<li>the class java.lang.Object has a depth of 1;</li>
+<li>all other classes have a depth of 1 + the depth of their super class.</li>
+</ul>
+
+<a name="NOA"/>
+<h3>Number of Attributes - NOA</h3>
+
+The number of distinct state variables in a class serves as one measure of
+its complexity. The more state a class represents the more difficult it is to
+maintain invariants for it. It also hinders comprehensibility and reuse.
+<p/>
+In Java, state can be exposed to subclasses through protected fields, which
+entails that the subclass also be aware of and maintain any invariants. This
+interference with the class's data encapsulation can be a source of defects
+and hidden dependencies between the state variables.
+<p/>
+NOA is defined for classes and interfaces.  It counts the number of fields
+declared in the class or interface.
+
+<a name="NRM"/>
+<h3>Number of Remote Methods - NRM</h3>
+
+NRM is defined for classes.  A remote method call is defined as an
+invocation of a method that is not declared in any of:
+<ul>
+<li>the class itself;</li>
+<li>a class or interface that the class extends or implements;</li>
+<li>a class or method that extends the class.</li>
+</ul>
+
+The value is the count of all the remote method calls in all of the methods
+and constructors of the class.
+
+<a name="NLM"/>
+<h3>Number of Local Methods - NLM</h3>
+
+NLM is defined for classes and interfaces.  A local method is defined as a
+method that is declared in the class or interface. NLM can be configured to
+include the local methods of all of the class's superclasses.  Methods with
+public, protected, package and private visibility can be independently
+counted by setting configuration parameters.
+
+<a name="WMC"/>
+<h3>Weighted Methods per Class - WMC</h3>
+
+If the number of methods in a class can be determined during the design
+and modeling phase of a project, it can be used as a predictor of how
+much time and effort is needed to develop, debug and maintain it. This
+metric can be further refined by incorporating a weighting for the
+complexity of each method. The usual weighting is given by the cyclomatic
+complexity of the method.
+<p/>
+The subclasses of a class inherit all of its public and protected methods,
+and possibly its package methods as well, so the number of methods a
+class has directly impacts the complexity of its subclasses. Classes with
+large numbers of methods are often specific to a particular application,
+reducing the ability to reuse them.
+<p/>
+The definition of WMC is based upon NLM, and it provides the same
+configuration parameters for counting inherited methods and of varying
+visibility. The main difference is that NLM always counts each method as 1,
+whereas WMC will weight each method. There are two weighting schemes:
+<ul>
+<li>V(G) the cyclomatic complexity of the method is used as its weight.
+   Methods from class files are given a V(G) of 1.</li>
+<li>the arity, or the number of parameters of the method are used to
+   determine the weight.</li>
+</ul>
+
+<a name="RFC"/>
+<h3>Response For Class - RFC</h3>
+
+The response set of a class is the set of all methods that can be invoked as
+a result of a message sent to an object of the class. This includes methods
+in the class's inheritance hierarchy and methods that can be invoked on
+other objects. The Response For Class metric is defined to be size of the
+response set for the class. A class which provides a larger response set is
+considered to be more complex than one with a smaller response set.
+<p/>
+One reason for this is that if a method call on a class can result in a large
+number of different method calls on the target and other classes, then it
+can be harder to test the behavior of the class and debug problems. It will
+typically require a deeper understanding of the potential interactions that
+objects of the class can have with the rest of the system.
+<p/>
+RFC is defined as the sum of NLM and NRM for the class.  The local methods
+include all of the public, protected, package and private methods, but not
+methods declared only in a superclass.
+
+<a name="DAC"/>
+<h3>Data Abstraction Coupling - DAC</h3>
+
+DAC is defined for classes and interfaces.  It counts the number of reference
+types that are used in the field declarations of the class or interface.  The
+component types of arrays are also counted.  Any field with a type that is
+either a supertype or a subtype of the class is not counted.
+
+<a name="FANOUT"/>
+<h3>Fan Out - FANOUT</h3>
+
+FANOUT is defined for classes and interfaces, constructors and methods. It
+counts the number of reference types that are used in:
+<ul>
+<li>field declarations;</li>
+<li>formal parameters and return types;</li>
+<li>throws declarations;</li>
+<li>local variables.</li>
+</ul>
+
+The component types of arrays are also counted. Any type that is either a
+supertype or a subtype of the class is not counted.
+
+<a name="CBO"/>
+<h3>Coupling Between Objects - CBO</h3>
+
+When one object or class uses another object or class they are said to be
+coupled. One major source of coupling is that between a superclass and a
+subclass. A coupling is also introduced when a method or field in another
+class is accessed, or when an object of another class is passed into or out
+of a method invocation. Coupling Between Objects is a measure of the
+non-inheritance coupling between two objects.
+<p/>
+A high value of coupling reduces the modularity of the class and makes
+reuse more difficult. The more independent a class is the more likely it is
+that it will be possible to reuse it in another part of the system. When a
+class is coupled to another class it becomes sensitive to changes in that
+class, thereby making maintenance for difficult. In addition, a class that is
+overly dependent on other classes can be difficult to understand and test in
+isolation.
+<p/>
+CBO is defined for classes and interfaces, constructors and methods. It
+counts the number of reference types that are used in:
+<ul>
+<li>field declarations</li>
+<li>formal parameters and return types</li>
+<li>throws declarations</li>
+<li>local variables</li>
+</ul>
+
+It also counts:
+<ul>
+<li>types from which field and method selections are made</li>
+</ul>
+
+The component types of arrays are also counted. Any type that is either a
+supertype or a subtype of the class is not counted.
+
+<a name="LCOM"/>
+<h3>Lack of Cohesion Of Methods - LCOM</h3>
+
+The cohesion of a class is the degree to which its methods are related to
+each other. It is determined by examining the pattern of state variable
+accesses within the set of methods. If all the methods access the same state
+variables then they have high cohesion; if they access disjoint sets of
+variables then the cohesion is low. An extreme example of low cohesion
+would be if none of the methods accessed any of the state variables.
+
+If a class exhibits low method cohesion it indicates that the design of the
+class has probably been partitioned incorrectly, and could benefit by being
+split into more classes with individually higher cohesion. On the other
+hand, a high value of cohesion (a low lack of cohesion) implies that the
+class is well designed. A cohesive class will tend to provide a high degree
+of encapsulation, whereas a lack of cohesion decreases encapsulation and
+increases complexity.
+<p/>
+Another form of cohesion that is useful for Java programs is cohesion
+between nested and enclosing classes. A nested class that has very low
+cohesion with its enclosing class would probably better designed as a peer
+class rather than a nested class.
+<p/>
+LCOM is defined for classes. Operationally, LCOM takes each pair of
+methods in the class and determines the set of fields they each access. If
+they have disjoint sets of field accesses increase the count P by one. If they
+share at least one field access then increase Q by one. After considering
+each pair of methods,
+LCOM = (P > Q) ? (P - Q) : 0
+<p/>
+Indirect access to fields via local methods can be considered by setting a
+metric configuration parameter.
+
+<a name="NOC"/>
+<h3>Number Of Classes - NOC</h3>
+
+The overall size of the system can be estimated by calculating the number
+of classes it contains. A large system with more classes is more complex
+than a smaller one because the number of potential interactions between
+objects is higher. This reduces the comprehensibility of the system which
+in turn makes it harder to test, debug and maintain.
+<p/>
+If the number of classes in the system can be projected during the initial
+design phase of the project it can serve as a base for estimating the total
+effort and cost of developing, debugging and maintaining the system.
+<p/>
+The NOC metric can also usefully be applied at the package and class level
+as well as the total system.
+<p/>
+NOCL is defined for class and interfaces. It counts the number of classes or
+interfaces that are declared. This is usually 1, but nested class declarations
+will increase this number.
+</body>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+    .bannercell {
+      border: 0px;
+      padding: 0px;
+    }
+    body {
+      margin-left: 10;
+      margin-right: 10;
+      font:normal 80% arial,helvetica,sanserif;
+      background-color:#FFFFFF;
+      color:#000000;
+    }
+    .a td {
+      background: #efefef;
+    }
+    .b td {
+      background: #fff;
+    }
+    th, td {
+      text-align: left;
+      vertical-align: top;
+    }
+    th {
+      font-weight:bold;
+      background: #ccc;
+      color: black;
+    }
+    table, th, td {
+      font-size:100%;
+      border: none
+    }
+    table.log tr td, tr th {
+
+    }
+    h2 {
+      font-weight:bold;
+      font-size:140%;
+      margin-bottom: 5;
+    }
+    h3 {
+      font-size:100%;
+      font-weight:bold;
+      background: #525D76;
+      color: white;
+      text-decoration: none;
+      padding: 5px;
+      margin-right: 2px;
+      margin-left: 2px;
+      margin-bottom: 0;
+    }
+    .Error {
+      font-weight:bold; color:red;
+    }
+
+</xsl:template>
+
+<!-- print the metrics of the class -->
+<xsl:template match="class" mode="class.details">
+  <!--xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/-->
+  <xsl:variable name="package.name" select="@package"/>
+  <HTML>
+    <HEAD>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="$package.name"/>
+      </xsl:call-template>
+    </HEAD>
+    <BODY>
+      <xsl:call-template name="pageHeader"/>
+
+      <H3>Class <xsl:if test="not($package.name = 'unnamed package')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></H3>
+      <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+        <xsl:call-template name="all.metrics.header"/>
+        <xsl:apply-templates select="." mode="print.metrics"/>
+      </table>
+
+      <H3>Methods</H3>
+      <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+        <xsl:call-template name="method.metrics.header"/>
+        <xsl:apply-templates select="method" mode="print.metrics"/>
+      </table>
+
+      <xsl:call-template name="pageFooter"/>
+    </BODY>
+  </HTML>
+</xsl:template>
+
+
+<!-- list of classes in a package -->
+<xsl:template match="package" mode="classes.list">
+  <HTML>
+    <HEAD>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="@name"/>
+      </xsl:call-template>
+    </HEAD>
+    <BODY>
+      <table width="100%">
+        <tr>
+          <td nowrap="nowrap">
+            <H2><a href="package-summary.html" target="classFrame"><xsl:value-of select="@name"/></a></H2>
+          </td>
+        </tr>
+      </table>
+
+      <H2>Classes</H2>
+      <TABLE WIDTH="100%">
+        <!-- xalan-nodeset:nodeset for Xalan 1.2.2 -->
+            <xsl:for-each select="$doctree/classes/class[@package = current()/@name]">
+                <xsl:sort select="@name"/>
+          <tr>
+            <td nowrap="nowrap">
+              <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+            </td>
+          </tr>
+            </xsl:for-each>
+      </TABLE>
+    </BODY>
+  </HTML>
+</xsl:template>
+
+
+<!--
+  Creates an all-classes.html file that contains a link to all package-summary.html
+  on each class.
+-->
+<xsl:template match="metrics" mode="all.classes">
+  <html>
+    <head>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="''"/>
+      </xsl:call-template>
+    </head>
+    <body>
+      <h2>Classes</h2>
+      <table width="100%">
+          <xsl:for-each select="$doctree/classes/class">
+              <xsl:sort select="@name"/>
+              <xsl:apply-templates select="." mode="all.classes"/>
+          </xsl:for-each>
+      </table>
+    </body>
+  </html>
+</xsl:template>
+
+<xsl:template match="class" mode="all.classes">
+    <xsl:variable name="package.name" select="@package"/>
+    <xsl:variable name="class.name" select="@name"/>
+  <tr>
+    <td nowrap="nowrap">
+      <a target="classFrame">
+        <xsl:attribute name="href">
+          <xsl:if test="not($package.name='unnamed package')">
+            <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+          </xsl:if>
+          <xsl:value-of select="$class.name"/><xsl:text>.html</xsl:text>
+        </xsl:attribute>
+        <xsl:value-of select="$class.name"/>
+      </a>
+    </td>
+  </tr>
+</xsl:template>
+
+<!--
+  Creates an html file that contains a link to all package-summary.html files on
+  each package existing on testsuites.
+  @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="metrics" mode="all.packages">
+  <html>
+    <head>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="./package/@name"/>
+      </xsl:call-template>
+    </head>
+    <body>
+      <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+      <h2>Packages</h2>
+        <table width="100%">
+          <xsl:apply-templates select=".//package[not(./@name = 'unnamed package')]" mode="all.packages">
+            <xsl:sort select="@name"/>
+          </xsl:apply-templates>
+        </table>
+    </body>
+  </html>
+</xsl:template>
+
+<xsl:template match="package" mode="all.packages">
+  <tr>
+    <td nowrap="nowrap">
+      <a href="{translate(@name,'.','/')}/package-summary.html" target="classFrame">
+        <xsl:value-of select="@name"/>
+      </a>
+    </td>
+  </tr>
+</xsl:template>
+
+
+<xsl:template match="metrics" mode="overview.packages">
+  <html>
+    <head>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="''"/>
+      </xsl:call-template>
+    </head>
+    <body onload="open('allclasses-frame.html','classListFrame')">
+    <xsl:call-template name="pageHeader"/>
+    <h3>Summary</h3>
+    <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+    <tr>
+      <th><a href="metrics-reference.html#V(G)">V(G)</a></th>
+      <th><a href="metrics-reference.html#LOC">LOC</a></th>
+      <th><a href="metrics-reference.html#DIT">DIT</a></th>
+      <th><a href="metrics-reference.html#NOA">NOA</a></th>
+      <th><a href="metrics-reference.html#NRM">NRM</a></th>
+      <th><a href="metrics-reference.html#NLM">NLM</a></th>
+      <th><a href="metrics-reference.html#WMC">WMC</a></th>
+      <th><a href="metrics-reference.html#RFC">RFC</a></th>
+      <th><a href="metrics-reference.html#DAC">DAC</a></th>
+      <th><a href="metrics-reference.html#FANOUT">FANOUT</a></th>
+      <th><a href="metrics-reference.html#CBO">CBO</a></th>
+      <th><a href="metrics-reference.html#LCOM">LCOM</a></th>
+      <th><a href="metrics-reference.html#NOCL">NOCL</a></th>
+    </tr>
+    <xsl:apply-templates select="." mode="print.metrics"/>
+    </table>
+    <table border="0" width="100%">
+    <tr>
+    <td style="text-align: justify;">
+    Note: Metrics evaluate the quality of software by analyzing the program source and quantifying
+    various kind of complexity. Complexity is a common source of problems and defects in software.
+    High complexity makes it more difficult to develop, understand, maintain, extend, test and debug
+    a program.
+    <p/>
+    The primary use of metrics is to focus your attention on those parts of code that potentially are
+    complexity hot spots. Once the complex areas your program have been uncovered, you can take remedial
+    actions.
+    For additional information about metrics and their meaning, please consult
+    Metamata Metrics manual.
+    </td>
+    </tr>
+    </table>
+
+    <h3>Packages</h3>
+    <table border="0" cellpadding="5" cellspacing="2" width="100%">
+      <xsl:call-template name="all.metrics.header"/>
+      <xsl:for-each select=".//package[not(@name = 'unnamed package')]">
+        <xsl:sort select="@name" order="ascending"/>
+        <xsl:apply-templates select="." mode="print.metrics"/>
+      </xsl:for-each>
+    </table>
+    <!-- @bug there could some classes at this level (classes in unnamed package) -->
+    <xsl:call-template name="pageFooter"/>
+    </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="package" mode="package.summary">
+  <HTML>
+    <HEAD>
+      <xsl:call-template name="create.stylesheet.link">
+        <xsl:with-param name="package.name" select="@name"/>
+      </xsl:call-template>
+    </HEAD>
+    <body onload="open('package-frame.html','classListFrame')">
+      <xsl:call-template name="pageHeader"/>
+      <!-- create an anchor to this package name -->
+      <h3>Package <xsl:value-of select="@name"/></h3>
+
+      <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+        <xsl:call-template name="all.metrics.header"/>
+        <xsl:apply-templates select="." mode="print.metrics"/>
+      </table>
+
+      <table border="0" width="100%">
+      <tr>
+      <td style="text-align: justify;">
+      Note: Metrics evaluate the quality of software by analyzing the program source and quantifying
+      various kind of complexity. Complexity is a common source of problems and defects in software.
+      High complexity makes it more difficult to develop, understand, maintain, extend, test and debug
+      a program.
+      <p/>
+      The primary use of metrics is to focus your attention on those parts of code that potentially are
+      complexity hot spots. Once the complex areas your program have been uncovered, you can take remedial
+      actions.
+      For additional information about metrics and their meaning, please consult
+      Metamata Metrics manual.
+      </td>
+      </tr>
+      </table>
+
+      <xsl:variable name="classes-in-package" select="$doctree/classes/class[@package = current()/@name]"/>
+      <xsl:if test="count($classes-in-package) &gt; 0">
+        <H3>Classes</H3>
+        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
+          <xsl:call-template name="all.metrics.header"/>
+          <xsl:for-each select="$classes-in-package">
+                <xsl:sort select="@name"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+          </xsl:for-each>
+        </table>
+      </xsl:if>
+
+      <xsl:call-template name="pageFooter"/>
+    </body>
+  </HTML>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+  <xsl:param name="path"/>
+  <xsl:if test="contains($path,'.')">
+    <xsl:text>../</xsl:text>
+    <xsl:call-template name="path">
+      <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+    </xsl:call-template>
+  </xsl:if>
+  <xsl:if test="not(contains($path,'.')) and not($path = '')">
+    <xsl:text>../</xsl:text>
+  </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+  <xsl:param name="package.name"/>
+  <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></LINK>
+</xsl:template>
+
+
+<!-- Page Header -->
+<xsl:template name="pageHeader">
+
+  <!-- jakarta logo -->
+  <table border="0" cellpadding="0" cellspacing="0" width="100%">
+  <tr>
+    <td class="bannercell" rowspan="2">
+      <a href="http://jakarta.apache.org/">
+      <img src="http://jakarta.apache.org/images/jakarta-logo.gif" alt="http://jakarta.apache.org" align="left" border="0"/>
+      </a>
+    </td>
+    <td style="text-align:right"><h2>Source Code Metrics</h2></td>
+    </tr>
+    <tr>
+    <td style="text-align:right">Designed for use with <a href='http://www.webgain.com/products/quality_analyzer/'>Webgain QA/Metamata Metrics</a> and <a href='http://jakarta.apache.org'>Ant</a>.</td>
+    </tr>
+  </table>
+  <hr size="1"/>
+</xsl:template>
+
+<!-- Page Footer -->
+<xsl:template name="pageFooter">
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="all.metrics.header">
+  <tr>
+    <th width="80%">Name</th>
+    <th nowrap="nowrap">V(G)</th>
+    <th>LOC</th>
+    <th>DIT</th>
+    <th>NOA</th>
+    <th>NRM</th>
+    <th>NLM</th>
+    <th>WMC</th>
+    <th>RFC</th>
+    <th>DAC</th>
+    <th>FANOUT</th>
+    <th>CBO</th>
+    <th>LCOM</th>
+    <th>NOCL</th>
+  </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="method.metrics.header">
+  <tr>
+    <th width="80%">Name</th>
+    <th nowrap="nowrap">V(G)</th>
+    <th>LOC</th>
+    <th>FANOUT</th>
+    <th>CBO</th>
+  </tr>
+</xsl:template>
+
+<!-- method information -->
+<xsl:template match="method" mode="print.metrics">
+  <tr>
+    <xsl:call-template name="alternate-row"/>
+    <td><xsl:apply-templates select="@name"/></td>
+    <td><xsl:apply-templates select="@vg"/></td>
+    <td><xsl:apply-templates select="@loc"/></td>
+    <td><xsl:apply-templates select="@fanout"/></td>
+    <td><xsl:apply-templates select="@cbo"/></td>
+  </tr>
+</xsl:template>
+
+<!-- class information -->
+<xsl:template match="class" mode="print.metrics">
+  <tr>
+    <xsl:call-template name="alternate-row"/>
+    <td><a href="{@name}.html"><xsl:value-of select="@name"/></a></td>
+    <td><xsl:apply-templates select="@vg"/></td>
+    <td><xsl:apply-templates select="@loc"/></td>
+    <td><xsl:apply-templates select="@dit"/></td>
+    <td><xsl:apply-templates select="@noa"/></td>
+    <td><xsl:apply-templates select="@nrm"/></td>
+    <td><xsl:apply-templates select="@nlm"/></td>
+    <td><xsl:apply-templates select="@wmc"/></td>
+    <td><xsl:apply-templates select="@rfc"/></td>
+    <td><xsl:apply-templates select="@dac"/></td>
+    <td><xsl:apply-templates select="@fanout"/></td>
+    <td><xsl:apply-templates select="@cbo"/></td>
+    <td><xsl:apply-templates select="@lcom"/></td>
+    <td><xsl:apply-templates select="@nocl"/></td>
+  </tr>
+</xsl:template>
+
+<xsl:template match="file|package" mode="print.metrics">
+  <tr>
+    <xsl:call-template name="alternate-row"/>
+    <td>
+    <a href="{translate(@name,'.','/')}/package-summary.html" target="classFrame">
+    <xsl:value-of select="@name"/>
+    </a>
+    </td>
+    <td><xsl:apply-templates select="@vg"/></td>
+    <td><xsl:apply-templates select="@loc"/></td>
+    <td><xsl:apply-templates select="@dit"/></td>
+    <td><xsl:apply-templates select="@noa"/></td>
+    <td><xsl:apply-templates select="@nrm"/></td>
+    <td><xsl:apply-templates select="@nlm"/></td>
+    <td><xsl:apply-templates select="@wmc"/></td>
+    <td><xsl:apply-templates select="@rfc"/></td>
+    <td><xsl:apply-templates select="@dac"/></td>
+    <td><xsl:apply-templates select="@fanout"/></td>
+    <td><xsl:apply-templates select="@cbo"/></td>
+    <td><xsl:apply-templates select="@lcom"/></td>
+    <td><xsl:apply-templates select="@nocl"/></td>
+  </tr>
+</xsl:template>
+
+<xsl:template match="metrics" mode="print.metrics">
+  <tr>
+    <xsl:call-template name="alternate-row"/>
+      <!-- the global metrics is the top package metrics -->
+    <td><xsl:apply-templates select="./package/@vg"/></td>
+    <td><xsl:apply-templates select="./package/@loc"/></td>
+    <td><xsl:apply-templates select="./package/@dit"/></td>
+    <td><xsl:apply-templates select="./package/@noa"/></td>
+    <td><xsl:apply-templates select="./package/@nrm"/></td>
+    <td><xsl:apply-templates select="./package/@nlm"/></td>
+    <td><xsl:apply-templates select="./package/@wmc"/></td>
+    <td><xsl:apply-templates select="./package/@rfc"/></td>
+    <td><xsl:apply-templates select="./package/@dac"/></td>
+    <td><xsl:apply-templates select="./package/@fanout"/></td>
+    <td><xsl:apply-templates select="./package/@cbo"/></td>
+    <td><xsl:apply-templates select="./package/@lcom"/></td>
+    <td><xsl:apply-templates select="./package/@nocl"/></td>
+  </tr>
+</xsl:template>
+
+<!-- alternated row style -->
+<xsl:template name="alternate-row">
+<xsl:attribute name="class">
+  <xsl:if test="position() mod 2 = 1">a</xsl:if>
+  <xsl:if test="position() mod 2 = 0">b</xsl:if>
+</xsl:attribute>
+</xsl:template>
+
+
+<!-- how to display the metrics with their max value -->
+<!-- @todo the max values must be external to the xsl -->
+
+  <xsl:template match="@vg">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$vg.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@loc">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$loc.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@dit">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$dit.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@noa">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$noa.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@nrm">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$nrm.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@nlm">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$nlm.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@wmc">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$wmc.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@rfc">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$rfc.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@dac">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$dac.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@fanout">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$fanout.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@cbo">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$cbo.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@lcom">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$lcom.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template match="@nocl">
+    <xsl:call-template name="display-value">
+      <xsl:with-param name="value" select="current()"/>
+      <xsl:with-param name="max" select="$nocl.max"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="display-value">
+    <xsl:param name="value"/>
+    <xsl:param name="max"/>
+    <xsl:if test="$value > $max">
+      <xsl:attribute name="class">Error</xsl:attribute>
+    </xsl:if>
+    <xsl:value-of select="$value"/>
+  </xsl:template>
+
+</xsl:stylesheet>
+
diff --git a/trunk/src/etc/performance/build.xml b/trunk/src/etc/performance/build.xml
new file mode 100644
index 0000000..c3e3ed9
--- /dev/null
+++ b/trunk/src/etc/performance/build.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="all" xmlns:ac="antlib:net.sf.antcontrib">
+  <description>
+    This build file is designed to report the performance
+    of ant from various releases.
+    to use:
+    * install ant-contrib.jar to ($ANT_HOME|$HOME/.ant)/lib
+    * install beanshell jar and bsf jar
+    * use unix (with bash) or install cygwin
+    * set the env variables {whichever needs testing}
+      ANT_HOME
+      ANT_HOME_6_5 (the directory containing ant 1.6.5)
+      ANT_HOME_6_4
+      ANT_HOME_5_4
+    
+    * run ant
+    For example:
+       export ANT_HOME="c:/cygwin/home/me/svn/trunk/dist"
+       export ANT_HOME_5_4="l:/apps/apache-ant-1.5.4"
+       ant.bat
+
+    TODO: more build files.
+  </description>
+  <property environment="env"/>
+
+  <target name="all" depends="gen,do-times"/>
+
+  <target name="clean">
+    <delete quiet="yes" dir="build"/>
+  </target>
+
+  <macrodef name="run-ant-files">
+    <attribute name="env-ant"/>
+    <sequential>
+      <ac:if>
+        <isset property="@{env-ant}"/>
+        <then>
+          <ac:shellscript shell="bash">
+            export ANT_HOME=${@{env-ant}}
+            echo $ANT_HOME
+            echo -n "--  props.xml     --: "
+            $ANT_HOME/bin/ant -f build/gen/props.xml | grep time
+            echo -n "-- ant-call.xml   --: "
+            $ANT_HOME/bin/ant -f build/gen/ant-call.xml | grep time
+          </ac:shellscript>
+        </then>
+      </ac:if>
+    </sequential>
+  </macrodef>
+  
+  <target name="do-times">
+    <run-ant-files env-ant="env.ANT_HOME"/>
+    <run-ant-files env-ant="env.ANT_HOME_6_5"/>
+    <run-ant-files env-ant="env.ANT_HOME_6_2"/>
+    <run-ant-files env-ant="env.ANT_HOME_5_4"/>
+  </target>
+
+
+  <target name="gen-dirs">
+    <mkdir dir="build/gen"/>
+  </target>
+
+  <target name="avail">
+    <available property="avail.props.xml"
+               file="props.xml" filepath="build/gen"/>
+    <available property="avail.ant-call.xml"
+               file="ant-call.xml" filepath="build/gen"/>
+  </target>
+
+  <target name="gen-props" depends="gen-dirs,avail" unless="avail.props.xml">
+    <script language="beanshell">
+      import java.io.*;
+      out = new PrintWriter(new BufferedWriter(new FileWriter(
+          "build/gen/props.xml")));
+      out.println("&lt;project name='props' default='props'&gt;");
+      out.println("  &lt;target name='props'&gt;");
+      for (int i = 0; i &lt; 20000; ++i) {
+          out.println(
+              "    &lt;property name='prop" + i + "' value='val'/&gt;");
+      }
+      out.println("  &lt;/target&gt;");
+      out.println("&lt;/project&gt;");
+      out.close();
+      self.log("Created build/gen/props.xml");
+    </script>
+  </target>
+
+  <target name="gen-ant-call" depends="gen-dirs,avail"
+          unless="avail.ant-call.xml">
+    <script language="beanshell">
+      import java.io.*;
+      out = new PrintWriter(new BufferedWriter(new FileWriter(
+          "build/gen/ant-call.xml")));
+      out.println("&lt;project name='ant-call' default='call'&gt;");
+      out.println("  &lt;target name='me'/&gt;");
+      out.println("  &lt;target name='call'&gt;");
+      for (int i = 0; i &lt; 1000; ++i) {
+          out.println("    &lt;antcall target='me'/&gt;");
+      }
+      out.println("  &lt;/target&gt;");
+      out.println("&lt;/project&gt;");
+      out.close();
+      self.log("Created build/gen/ant-call.xml");
+    </script>
+  </target>
+
+  <target name="gen" depends="gen-ant-call,gen-props"/>
+</project>
diff --git a/trunk/src/etc/poms/README.txt b/trunk/src/etc/poms/README.txt
new file mode 100644
index 0000000..0a04128
--- /dev/null
+++ b/trunk/src/etc/poms/README.txt
@@ -0,0 +1,54 @@
+Building Ant with Maven
+-----------------------
+
+The Ant jars can be built using Maven and the POMS present in this directory.
+
+Libs not available in the maven repository
+
+groupId          artifactId       version   comment
+com.bea          weblogic         8.1.3.0   download it
+com.bea          weblogicclasses  5.1       a newer version can do.
+jai              jai-core         1.1.2_01  download jai from sun
+jai              jai-codec        1.1.2.1   download jai from sun
+javax.media      jmf              2.1.1e    dowmload jmf from sun
+com.ibm.netrexx  netrexx          2.0.5     I used the file NetRexxC.jar from the netrexx distribution
+com.starteam     starteam-sdk     5.2       the original file is called starteam-sdk.jar
+stylebook        stylebook        1.0-b2    the original file is called stylebook-1.0-b2.jar
+
+to install a jar file into your local Maven cache, do this
+
+mvn install:install-file -DgroupId=foo.org -DartifactId=xx -Dversion=x.y -Dpackaging=jar -Dfile=/a/b/foo.jar
+
+HOW TO BUILD :
+
+from this directory, type 
+
+mvn install (or mvn package)
+
+If you do not have all the dependencies, you can remove the modules that you will not be able to build 
+from the pom.xml in this directory.
+
+You also might want to disable the tests. 
+
+mvn install -Dmaven.test.skip=true 
+
+
+
+TODO :
+
+ * see if the dependency to weblogicclasses.jar can be replaced by a dependency to some j2ee.jar from Sun,
+as it supplies some javax.ejb classes which are required at compile time.
+
+
+PROBLEMS :
+
+ * the unit tests cannot run properly, the maven-surefire-plugin sets a system property basedir 
+which make a large part of our tests fail
+
+ * JIRA issue http://jira.codehaus.org/browse/MSUREFIRE-177 asking the Maven colleagues to fix this. :-)
+
+REFERENCES :
+
+about skipping tests :
+http://maven.apache.org/plugins/maven-surefire-plugin/examples/skipping-test.html
+
diff --git a/trunk/src/etc/poms/ant-antlr/pom.xml b/trunk/src/etc/poms/ant-antlr/pom.xml
new file mode 100644
index 0000000..f13dde2
--- /dev/null
+++ b/trunk/src/etc/poms/ant-antlr/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-antlr</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>antlr specific task.

+    The implementation forks a java process, therefore the antlr jar file is only needed at runtime</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <optional>true</optional>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <!-- add a dependency with antlr 2.7.2 consistent with libraries.properties antlr 2.7.6 is also available on ibiblio-->

+      <groupId>antlr</groupId>

+      <artifactId>antlr</artifactId>

+      <version>2.7.2</version>

+      <optional>true</optional>

+      <scope>runtime</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/taskdefs/optional/ANTLR*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-bcel/pom.xml b/trunk/src/etc/poms/ant-apache-bcel/pom.xml
new file mode 100644
index 0000000..426772c
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-bcel/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-bcel</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>bcel</groupId>

+      <artifactId>bcel</artifactId>

+      <version>5.1</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/tfilters/util/JavaClassHelper*</include>

+            <include>org/apache/tools/ant/tutil/depend/bcel/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-bsf/pom.xml b/trunk/src/etc/poms/ant-apache-bsf/pom.xml
new file mode 100644
index 0000000..c571fe7
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-bsf/pom.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-bsf</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>bsf</groupId>

+      <artifactId>bsf</artifactId>

+      <version>2.4.0</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/taskdefs/optional/Script*</include>

+            <include>org/apache/tools/ant/taskdefs/optional/script/**</include>

+            <include>org/apache/tools/ant/types/optional/*Script*</include>

+            <include>org/apache/tools/ant/util/Script*</include>

+            <include>org/apache/tools/ant/util/optional/Script*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-log4j/pom.xml b/trunk/src/etc/poms/ant-apache-log4j/pom.xml
new file mode 100644
index 0000000..0a3658d
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-log4j/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-log4j</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>log4j</groupId>

+      <artifactId>log4j</artifactId>

+      <version>1.2.13</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/listener/Log4jListener*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-oro/pom.xml b/trunk/src/etc/poms/ant-apache-oro/pom.xml
new file mode 100644
index 0000000..86a025a
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-oro/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-oro</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>oro</groupId>

+      <artifactId>oro</artifactId>

+      <version>2.0.8</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/util/regexp/JakartaOro*</include>

+            <include>org/apache/tools/ant/taskdefs/optional/perforce/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-regexp/pom.xml b/trunk/src/etc/poms/ant-apache-regexp/pom.xml
new file mode 100644
index 0000000..44c84d8
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-regexp/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-regexp</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>regexp</groupId>

+      <artifactId>regexp</artifactId>

+      <version>1.3</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/util/regexp/JakartaRegexp*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+  

+</project>

diff --git a/trunk/src/etc/poms/ant-apache-resolver/pom.xml b/trunk/src/etc/poms/ant-apache-resolver/pom.xml
new file mode 100644
index 0000000..558d0db
--- /dev/null
+++ b/trunk/src/etc/poms/ant-apache-resolver/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-apache-resolver</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>xml-resolver</groupId>

+      <artifactId>xml-resolver</artifactId>

+      <version>1.1</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/types/resolver/**</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-commons-logging/pom.xml b/trunk/src/etc/poms/ant-commons-logging/pom.xml
new file mode 100644
index 0000000..ba088c0
--- /dev/null
+++ b/trunk/src/etc/poms/ant-commons-logging/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-commons-logging</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>Ant Listener based on commons-logging</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>commons-logging</groupId>

+      <artifactId>commons-logging-api</artifactId>

+      <version>1.0.4</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/tlistener/CommonsLoggingListener*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-commons-net/pom.xml b/trunk/src/etc/poms/ant-commons-net/pom.xml
new file mode 100644
index 0000000..036a960
--- /dev/null
+++ b/trunk/src/etc/poms/ant-commons-net/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-commons-net</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>ftp, rexec and telnet tasks</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>commons-net</groupId>

+      <artifactId>commons-net</artifactId>

+      <version>1.4.0</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/taskdefs/optional/net/FTP*</include>

+            <include>org/apache/tools/ant/taskdefs/optional/net/RExec*</include>

+            <include>org/apache/tools/ant/taskdefs/optional/net/TelnetTask*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-jai/pom.xml b/trunk/src/etc/poms/ant-jai/pom.xml
new file mode 100644
index 0000000..e8b66e2
--- /dev/null
+++ b/trunk/src/etc/poms/ant-jai/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-jai</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>image task and corresponding types.

+  jai (Java Advanced Imaging) is not available in public Maven repositories, therefore the dependencies are included with a scope provided

+    the download URL is http://java.sun.com/products/java-media/jai/

+  </description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>javax.media</groupId>

+      <artifactId>jai-core</artifactId>

+      <version>1.1.2_01</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>jai</groupId>

+      <artifactId>jai-codec</artifactId>

+      <version>1.1.2.1</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/taskdefs/optional/image/*</include>

+            <include>org/apache/tools/ant/types/optional/image/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-javamail/pom.xml b/trunk/src/etc/poms/ant-javamail/pom.xml
new file mode 100644
index 0000000..36b13fb
--- /dev/null
+++ b/trunk/src/etc/poms/ant-javamail/pom.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-javamail</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>implementation of the mail task based on javamail.

+    Required to send emails to SMTP servers using user/password combinations

+  or to send mail over SSL</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>javax.mail</groupId>

+      <artifactId>mail</artifactId>

+      <version>1.4</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>javax.activation</groupId>

+      <artifactId>activation</artifactId>

+      <version>1.1</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies> 

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/email/MimeMailer*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-jdepend/pom.xml b/trunk/src/etc/poms/ant-jdepend/pom.xml
new file mode 100644
index 0000000..6cfbd43
--- /dev/null
+++ b/trunk/src/etc/poms/ant-jdepend/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-jdepend</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>task jdepend invoking the jdepend parser. There is also a version 2.9.1 of the

+    jdepend parser available on the maven repository</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>jdepend</groupId>

+      <artifactId>jdepend</artifactId>

+      <version>2.7</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/jdepend/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-jmf/pom.xml b/trunk/src/etc/poms/ant-jmf/pom.xml
new file mode 100644
index 0000000..5c87225
--- /dev/null
+++ b/trunk/src/etc/poms/ant-jmf/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-jmf</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>contains the sound task and a soundplayer listener

+    download the dependency from http://java.sun.com/products/java-media/jmf/</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>javax.media</groupId>

+      <artifactId>jmf</artifactId>

+      <version>2.1.1e</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/sound/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+  </project>

diff --git a/trunk/src/etc/poms/ant-jsch/pom.xml b/trunk/src/etc/poms/ant-jsch/pom.xml
new file mode 100644
index 0000000..6490656
--- /dev/null
+++ b/trunk/src/etc/poms/ant-jsch/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-jsch</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>contains the sshexec and scp tasks

+  jsch 0.1.29 might not be available from maven</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>com.jcraft</groupId>

+      <artifactId>jsch</artifactId>

+      <version>0.1.29</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/ssh/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-junit/pom.xml b/trunk/src/etc/poms/ant-junit/pom.xml
new file mode 100644
index 0000000..778c3bd
--- /dev/null
+++ b/trunk/src/etc/poms/ant-junit/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-junit</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>contains the junit and junirreport tasks</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>junit</groupId>

+      <artifactId>junit</artifactId>

+      <version>3.8.2</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <artifactId>maven-antrun-plugin</artifactId>

+        <executions>

+          <execution>

+            <id>create-timestamp-file</id>

+            <phase>generate-resources</phase>

+            <goals>

+              <goal>run</goal>

+            </goals>

+            <configuration>

+              <tasks>

+                <mkdir dir="${project.build.outputDirectory}"/>

+                <copy todir="${project.build.outputDirectory}/org/apache/tools/ant/taskdefs/optional/junit/xsl">

+                  <fileset dir="${project.build.sourceDirectory}/../etc">

+                    <include name="junit-frames.xsl"/>

+                    <include name="junit-noframes.xsl"/>

+                  </fileset>

+                </copy>              

+              </tasks>

+            </configuration>

+          </execution>

+

+        </executions>

+      </plugin>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/junit/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-launcher/pom.xml b/trunk/src/etc/poms/ant-launcher/pom.xml
new file mode 100644
index 0000000..dd47c33
--- /dev/null
+++ b/trunk/src/etc/poms/ant-launcher/pom.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-launcher</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/launch/*.java</include>

+          </includes>

+

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/ant-launcher/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/ant-launcher/testcases</testOutputDirectory>

+    <directory>../../../../target/ant-launcher</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-netrexx/pom.xml b/trunk/src/etc/poms/ant-netrexx/pom.xml
new file mode 100644
index 0000000..ecaf307
--- /dev/null
+++ b/trunk/src/etc/poms/ant-netrexx/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-netrexx</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>NetRexxC task

+    dependency can be downloaded from http://www.ibm.com/software/awdtools/netrexx/download.html</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>com.ibm.netrexx</groupId>

+      <artifactId>netrexx</artifactId>

+      <version>2.0.5</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/NetRexxC*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-nodeps/pom.xml b/trunk/src/etc/poms/ant-nodeps/pom.xml
new file mode 100644
index 0000000..8f133be
--- /dev/null
+++ b/trunk/src/etc/poms/ant-nodeps/pom.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-nodeps</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>contains all the optional tasks and types which do not have particular dependencies</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <!-- the implementation jar of the xerces jar will be used by ant to parse

+      XML files, particularly the build files, if the JDK does not provide a parser

+      xercesImpl.jar is provided with ant -->

+      <groupId>xerces</groupId>

+      <artifactId>xercesImpl</artifactId>

+      <version>2.9.0</version>

+      <optional>true</optional>

+      <scope>runtime</scope>

+    </dependency>

+    <dependency>

+      <!-- xml-apis contains the org.w3c.dom package 

+        since ant is using DOM APIS to parse the XML build file and do other XML related activities

+        xml-apis is a compile time dependency

+        a version of xml-apis.jar is delivered with ant -->

+      <groupId>xml-apis</groupId>

+      <artifactId>xml-apis</artifactId>

+      <version>1.3.04</version>

+      <optional>true</optional>

+      <scope>compile</scope>

+    </dependency>

+

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant/taskdefs/optional/**</include>

+            <include>org/apache/tools/ant/types/optional/**</include>

+            <include>org/apache/tools/ant/util/depend/*</include>

+            <include>org/apache/tools/ant/util/optional/**</include>

+            <include>org/apache/tools/ant/util/java15/**</include>

+            <include>org/apache/tools/ant/util/regexp/Jdk14Regexp*</include>

+          </includes>

+          <excludes>

+            <exclude>org/apache/tools/ant/taskdefs/optional/TraXLiaison*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/junit/**</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/perforce/**</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/Script*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/script/**</exclude>

+            <exclude>org/apache/tools/ant/util/optional/Script*</exclude>

+            <exclude>org/apache/tools/ant/types/optional/*Script*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/StyleBook*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/NetRexxC*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ejb/Ejbc*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ejb/DDCreator*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ejb/WLRun*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ejb/WLStop*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/net/Telnet*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/net/FTP*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/net/RExec*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/scm/AntStarTeam*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/starteam/*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ANTLR*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/sound/*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/image/*</exclude>

+            <exclude>org/apache/tools/ant/types/optional/image/*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/jdepend/*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/splash/*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/optional/ssh/*</exclude>

+            

+          </excludes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/ant-nodeps/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/ant-nodeps/testcases</testOutputDirectory>

+    <directory>../../../../target/ant-nodeps</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-starteam/pom.xml b/trunk/src/etc/poms/ant-starteam/pom.xml
new file mode 100644
index 0000000..587ece6
--- /dev/null
+++ b/trunk/src/etc/poms/ant-starteam/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-starteam</artifactId>

+  <description>Starteam SDK tasks</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>com.starteam</groupId>

+      <artifactId>starteam-sdk</artifactId>

+      <version>5.2</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/scm/AntStarTeam*</include>

+            <include>org/apache/tools/ant//taskdefs/optional/scm/starteam/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant-stylebook/pom.xml b/trunk/src/etc/poms/ant-stylebook/pom.xml
new file mode 100644
index 0000000..949e208
--- /dev/null
+++ b/trunk/src/etc/poms/ant-stylebook/pom.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-stylebook</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>executes the Apache Stylebook document generator. Deprecated since Ant 1.7</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>stylebook</groupId>

+      <artifactId>stylebook</artifactId>

+      <version>1.0-b2</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/StyleBook*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+  

+</project>

diff --git a/trunk/src/etc/poms/ant-swing/pom.xml b/trunk/src/etc/poms/ant-swing/pom.xml
new file mode 100644
index 0000000..4eb5165
--- /dev/null
+++ b/trunk/src/etc/poms/ant-swing/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-swing</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>a listener and a splash task based on Swing</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/splash/*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+  

+</project>

diff --git a/trunk/src/etc/poms/ant-testutil/pom.xml b/trunk/src/etc/poms/ant-testutil/pom.xml
new file mode 100644
index 0000000..84d95be
--- /dev/null
+++ b/trunk/src/etc/poms/ant-testutil/pom.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!--
+  This POM has been created manually by the Ant Development Team.
+  Please contact us if you are not satisfied with the data contained in this POM.
+  URL : http://ant.apache.org
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.ant</groupId>
+    <artifactId>ant-parent</artifactId>
+    <relativePath>../pom.xml</relativePath>
+    <version>1.7.1-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.ant</groupId>
+  <artifactId>ant-testutil</artifactId>
+  <version>1.7.1-SNAPSHOT</version>
+  <description>test utility classes</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.ant</groupId>
+      <artifactId>ant</artifactId>
+      <version>1.7.1-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.2</source>
+          <target>1.2</target>
+          <includes>
+            <include>org/apache/tools/ant/BuildFileTest*</include>
+            <include>org/apache/tools/ant/util/regexp/RegexpMatcherTest*</include>
+            <include>org/apache/tools/ant/util/regexp/RegexpTest*</include>
+            <include>org/apache/tools/ant/taskdefs/optional/AbstractXSLTLiaisonTest*</include>
+            <include>org/apache/tools/ant/types/AbstractFileSetTest*</include>
+          </includes>
+        </configuration>
+      </plugin>
+    </plugins>
+    <sourceDirectory>../../../../src/tests/junit</sourceDirectory>
+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>
+    <directory>../../../../target/${project.artifactId}</directory>
+  </build>
+  
+</project>
diff --git a/trunk/src/etc/poms/ant-trax/pom.xml b/trunk/src/etc/poms/ant-trax/pom.xml
new file mode 100644
index 0000000..b137925
--- /dev/null
+++ b/trunk/src/etc/poms/ant-trax/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-trax</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <description>contains particularly one class necessary for the execution of the xslt task</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <!-- the implementation jar of the xerces jar will be used by ant to parse

+      XML files, particularly the build files, if the JDK does not provide a parser

+      xercesImpl.jar is provided with ant -->

+      <groupId>xerces</groupId>

+      <artifactId>xercesImpl</artifactId>

+      <version>2.9.0</version>

+      <optional>true</optional>

+      <scope>runtime</scope>

+    </dependency>

+    <dependency>

+      <!-- xml-apis contains the org.w3c.dom package 

+        since ant is using DOM APIS to parse the XML build file and do other XML related activities

+        xml-apis is a compile time dependency

+        a version of xml-apis.jar is delivered with ant -->

+      <groupId>xml-apis</groupId>

+      <artifactId>xml-apis</artifactId>

+      <version>1.3.04</version>

+      <optional>true</optional>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <!-- xalan contains a TRAX compliant implementation -->

+      <groupId>xalan</groupId>

+      <artifactId>xalan</artifactId>

+      <version>2.7.0</version>

+      <optional>true</optional>

+      <scope>runtime</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/TraXLiaison*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+  </project>

diff --git a/trunk/src/etc/poms/ant-weblogic/pom.xml b/trunk/src/etc/poms/ant-weblogic/pom.xml
new file mode 100644
index 0000000..e46a6c9
--- /dev/null
+++ b/trunk/src/etc/poms/ant-weblogic/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-weblogic</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <groupId>com.bea</groupId>

+      <artifactId>weblogicclasses</artifactId>

+      <version>5.1</version>

+      <scope>provided</scope>

+    </dependency>

+    <dependency>

+      <groupId>com.bea</groupId>

+      <artifactId>weblogic</artifactId>

+      <version>8.1.3.0</version>

+      <scope>provided</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <includes>

+            <include>org/apache/tools/ant//taskdefs/optional/ejb/Ejbc*</include>

+            <include>org/apache/tools/ant//taskdefs/optional/ejb/DDCreator*</include>

+            <include>org/apache/tools/ant//taskdefs/optional/ejb/WLRun*</include>

+            <include>org/apache/tools/ant//taskdefs/optional/ejb/WLStop*</include>

+          </includes>

+        </configuration>

+      </plugin>

+    </plugins>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../../target/${project.artifactId}/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/${project.artifactId}/testcases</testOutputDirectory>

+    <directory>../../../../target/${project.artifactId}</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/ant/pom.xml b/trunk/src/etc/poms/ant/pom.xml
new file mode 100644
index 0000000..e49309c
--- /dev/null
+++ b/trunk/src/etc/poms/ant/pom.xml
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0"

+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <parent>

+    <groupId>org.apache.ant</groupId>

+    <artifactId>ant-parent</artifactId>

+    <relativePath>../pom.xml</relativePath>

+    <version>1.7.1-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <name>org.apache.tools.ant</name>

+  <description>Apache Ant</description>

+  <dependencies>

+    <dependency>

+      <groupId>org.apache.ant</groupId>

+      <artifactId>ant-launcher</artifactId>

+      <version>1.7.1-SNAPSHOT</version>

+      <scope>compile</scope>

+    </dependency>

+    <dependency>

+      <!-- the implementation jar of the xerces jar will be used by ant to parse

+      XML files, particularly the build files, if the JDK does not provide a parser

+        xercesImpl.jar is provided with ant -->

+      <groupId>xerces</groupId>

+      <artifactId>xercesImpl</artifactId>

+      <version>2.9.0</version>

+      <optional>true</optional>

+      <scope>runtime</scope>

+    </dependency>

+    <dependency>

+      <!-- xml-apis contains the org.w3c.dom package 

+      since ant is using DOM APIS to parse the XML build file and do other XML related activities

+      xml-apis is a compile time dependency

+      a version of xml-apis.jar is delivered with ant -->

+      <groupId>xml-apis</groupId>

+      <artifactId>xml-apis</artifactId>

+      <version>1.3.04</version>

+      <optional>true</optional>

+      <scope>compile</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <filters>

+      <filter>../../../../target/ant/.build.timestamp.properties</filter>

+    </filters>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-jar-plugin</artifactId>

+        <configuration> </configuration>

+      </plugin>

+      <plugin>

+        <artifactId>maven-antrun-plugin</artifactId>

+        <executions>

+          <execution>

+            <id>create-timestamp-file</id>

+            <phase>generate-resources</phase>

+            <goals>

+              <goal>run</goal>

+            </goals>

+            <configuration>

+              <tasks>

+                <tstamp/>

+                <mkdir dir="${project.build.directory}"/>

+                <touch file="${project.build.directory}/.build.timestamp.properties"/>

+                <echo file="${project.build.directory}/.build.timestamp.properties" append="false"

+                  message="TODAY=${TODAY}"/>

+              </tasks>

+            </configuration>

+          </execution>

+          <execution>

+            <id>delete-timestamp-file</id>

+            <phase>clean</phase>

+            <goals>

+              <goal>run</goal>

+            </goals>

+            <configuration>

+              <tasks>

+                <delete file="${project.build.directory}/.build.timestamp.properties"/>

+              </tasks>

+            </configuration>

+          </execution>

+        </executions>

+      </plugin>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-compiler-plugin</artifactId>

+        <configuration>

+          <source>1.2</source>

+          <target>1.2</target>

+          <excludes>

+            <exclude>org/apache/tools/ant/taskdefs/optional/**</exclude>

+            <exclude>org/apache/tools/ant/filters/util/JavaClassHelper*</exclude>

+            <exclude>org/apache/tools/ant/types/optional/**</exclude>

+            <exclude>org/apache/tools/ant/types/resolver/**</exclude>

+            <exclude>org/apache/tools/ant/util/depend/**</exclude>

+            <exclude>org/apache/tools/ant/util/optional/**</exclude>

+            <exclude>org/apache/tools/ant/util/Script*</exclude>

+            <exclude>org/apache/tools/ant/listener/Log4jListener*</exclude>

+            <exclude>org/apache/tools/ant/listener/CommonsLoggingListener*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/JakartaRegexp*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/JakartaOro*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/Jdk14Regexp*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/email/MimeMailer*</exclude>

+            <exclude>org/apache/tools/ant/launch/**</exclude>

+          </excludes>

+          <testExcludes>

+            <exclude>org/apache/tools/ant/taskdefs/optional/**</exclude>

+            <exclude>org/apache/tools/ant/filters/util/JavaClassHelper*</exclude>

+            <exclude>org/apache/tools/ant/types/optional/**</exclude>

+            <exclude>org/apache/tools/ant/types/resolver/**</exclude>

+            <exclude>org/apache/tools/ant/util/depend/**</exclude>

+            <exclude>org/apache/tools/ant/util/optional/**</exclude>

+            <exclude>org/apache/tools/ant/util/Script*</exclude>

+            <exclude>org/apache/tools/ant/listener/Log4jListener*</exclude>

+            <exclude>org/apache/tools/ant/listener/CommonsLoggingListener*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/JakartaRegexp*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/JakartaOro*</exclude>

+            <exclude>org/apache/tools/ant/util/regexp/Jdk14Regexp*</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/email/MimeMailer*</exclude>

+            <exclude>org/apache/tools/ant/launch/**</exclude>

+            <exclude>org/apache/tools/ant/taskdefs/StyleTest*</exclude>

+          </testExcludes>

+        </configuration>

+      </plugin>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-surefire-plugin</artifactId>

+        <configuration>

+          <omitBasedir>true</omitBasedir>

+          <systemProperties>

+            <property>

+              <name>ant.home</name>

+              <value>${env.ANT_HOME}</value>

+            </property>

+            <property>

+              <name>build.tests</name>

+              <value>../../../../target/ant/testcases</value>

+            </property>

+            <property>

+              <name>build.tests.value</name>

+              <value>../../../../target/ant/testcases</value>

+            </property>

+            <property>

+              <name>offline</name>

+              <value>true</value>

+            </property>

+            <property>

+              <name>root</name>

+              <value>../../../..</value>

+            </property>

+          </systemProperties>

+        </configuration>

+      </plugin>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-surefire-report-plugin</artifactId>

+      </plugin>

+    </plugins>

+    <resources>

+      <resource>

+        <directory>../../../../src/main</directory>

+        <filtering>true</filtering>

+        <includes>

+          <include>org/apache/tools/ant/taskdefs/default.properties</include>

+          <include>org/apache/tools/ant/types/default.properties</include>

+          <include>org/apache/tools/ant/taskdefs/default.properties</include>

+          <include>org/apache/tools/ant/types/conditions/antlib.xml</include>

+          <include>org/apache/tools/ant/defaultManifest.mf</include>

+          <include>org/apache/tools/ant/version.txt</include>

+        </includes>

+      </resource>

+      <resource>

+        <directory>../../../../src/resources</directory>

+        <filtering>true</filtering>

+        <includes>

+          <include>**/antlib.xml</include>

+        </includes>

+      </resource>

+      <resource>

+        <directory>../../../../docs</directory>

+        <filtering>false</filtering>

+        <includes>

+          <include>images/ant_logo_large.gif</include>

+        </includes>

+      </resource>

+    </resources>

+    <testResources>

+      <testResource>

+        <directory>../../../../src/etc/testcases</directory>

+        <filtering>true</filtering>

+      </testResource>

+      <testResource>

+        <directory>../../../../src/main</directory>

+        <filtering>true</filtering>

+        <excludes>

+          <exclude>**/*.java</exclude>

+        </excludes>

+      </testResource>

+    </testResources>

+    <sourceDirectory>../../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../../src/tests/junit</testSourceDirectory>

+    <outputDirectory>../../../../target/ant/classes</outputDirectory>

+    <testOutputDirectory>../../../../target/ant/testcases</testOutputDirectory>

+    <directory>../../../../target/ant</directory>

+  </build>

+</project>

diff --git a/trunk/src/etc/poms/pom.xml b/trunk/src/etc/poms/pom.xml
new file mode 100644
index 0000000..664094d
--- /dev/null
+++ b/trunk/src/etc/poms/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<!--

+  This POM has been created manually by the Ant Development Team.

+  Please contact us if you are not satisfied with the data contained in this POM.

+  URL : http://ant.apache.org

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

+xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>org.apache.ant</groupId>

+  <artifactId>ant-parent</artifactId>

+  <version>1.7.1-SNAPSHOT</version>

+  <packaging>pom</packaging>

+  <description>master POM</description>

+  <name>Apache Ant</name>

+  <url>http://ant.apache.org/</url>

+  <inceptionYear>2000</inceptionYear>

+  <organization>

+    <name>Apache Software Foundation</name>

+  </organization>

+  <distributionManagement>

+    <!-- Null out inherited apache distribution repo by default -->

+    <repository>

+      <id>dummy</id>

+      <name>Dummy to avoid accidental deploys</name>

+      <url></url>

+    </repository>

+  </distributionManagement>

+  <scm>

+    <connection>scm:svn:http://svn.apache.org/repos/asf/ant/core/trunk</connection>

+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/jant/core/trunk</developerConnection>

+    <url>http://svn.apache.org/repos/asf/ant/core/trunk</url>

+  </scm>

+  <mailingLists>

+    <mailingList>

+      <name>Ant Developers List</name>

+      <subscribe>dev-subscribe@ant.apache.org</subscribe>

+      <unsubscribe>dev-unsubscribe@ant.apache.org</unsubscribe>

+      <post>dev@ant.apache.org</post>

+      <archive>http://mail-archives.apache.org/mod_mbox/ant-dev</archive>

+    </mailingList>

+    <mailingList>

+      <name>Ant Users List</name>

+      <subscribe>user-subscribe@ant.apache.org</subscribe>

+      <unsubscribe>user-unsubscribe@ant.apache.org</unsubscribe>

+      <post>user@ant.apache.org</post>

+      <archive>http://mail-archives.apache.org/mod_mbox/ant-user</archive>

+    </mailingList>

+  </mailingLists>

+  <issueManagement>

+    <system>bugzilla</system>

+    <url>http://issues.apache.org/bugzilla/</url>

+  </issueManagement>

+  <modules>

+    <module>ant</module>

+    <module>ant-antlr</module>

+    <module>ant-apache-bcel</module>

+    <module>ant-apache-bsf</module>

+    <module>ant-apache-log4j</module>

+    <module>ant-apache-oro</module>

+    <module>ant-apache-regexp</module>

+    <module>ant-apache-resolver</module>

+    <module>ant-commons-logging</module>

+    <module>ant-commons-net</module>

+    <module>ant-jai</module>

+    <module>ant-javamail</module>

+    <module>ant-jdepend</module>

+    <module>ant-jmf</module>

+    <module>ant-jsch</module>

+    <module>ant-junit</module>

+    <module>ant-launcher</module>

+    <module>ant-netrexx</module>

+    <module>ant-nodeps</module>

+    <module>ant-starteam</module>

+    <module>ant-stylebook</module>

+    <module>ant-swing</module>

+    <module>ant-testutil</module>

+    <module>ant-trax</module>

+    <module>ant-weblogic</module>

+  </modules>

+  <dependencies>

+     <dependency>

+      <groupId>junit</groupId>

+      <artifactId>junit</artifactId>

+      <version>3.8.2</version>

+      <scope>test</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <sourceDirectory>../../../src/main</sourceDirectory>

+    <testSourceDirectory>../../../src/testcases</testSourceDirectory>

+    <outputDirectory>../../../target/classes</outputDirectory>

+    <testOutputDirectory>../../../target/testcases</testOutputDirectory>

+  </build>

+</project>

diff --git a/trunk/src/etc/tagdiff.xsl b/trunk/src/etc/tagdiff.xsl
new file mode 100644
index 0000000..5d430a7
--- /dev/null
+++ b/trunk/src/etc/tagdiff.xsl
@@ -0,0 +1,179 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!-- a stylesheet to display changelogs ala netbeans -->
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    version="1.0">
+  <xsl:param name="title"/>
+  <xsl:param name="module"/>
+  <xsl:param name="cvsweb"/>
+
+  <xsl:output method="html" indent="yes"/>
+
+  <!-- Copy standard document elements.  Elements that
+       should be ignored must be filtered by apply-templates
+       tags. -->
+  <xsl:template match="*">
+    <xsl:copy>
+      <xsl:copy-of select="attribute::*[. != '']"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="tagdiff">
+    <html>
+      <head>
+        <title><xsl:value-of select="$title"/></title>
+        <style type="text/css">
+          body, p {
+          font-family: verdana,arial,helvetica;
+          font-size: 80%;
+          color:#000000;
+          }
+	  .dateAndAuthor {
+          font-family: verdana,arial,helvetica;
+          font-size: 80%;
+          font-weight: bold;
+          text-align:left;
+          background:#a6caf0;
+	  }
+          tr, td{
+          font-family: verdana,arial,helvetica;
+          font-size: 80%;
+          background:#eeeee0;
+          }	  
+	  </style> 
+      </head>
+      <body link="#000000" alink="#000000" vlink="#000000" text="#000000">       
+          <h1>
+            <a name="top"><xsl:value-of select="$title"/></a>
+          </h1>
+          Tagdiff between <xsl:value-of select="@startTag"/> <xsl:value-of select="@startDate"/> and
+			<xsl:value-of select="@endTag"/> <xsl:value-of select="@endDate"/>
+          <p align="right">Designed for use with <a href="http://ant.apache.org/">Ant</a>.</p>
+          <hr size="2"/>
+	<a name="TOP"/>
+	<table width="100%">
+		<tr>
+			<td align="right">
+				<a href="#New">New Files</a> |
+				<a href="#Modified">Modified Files</a> |
+				<a href="#Removed">Removed Files</a>
+			</td>
+		</tr>
+	</table>
+        <table border="0" width="100%" cellpadding="3" cellspacing="1">
+		<xsl:call-template name="show-entries">
+			<xsl:with-param name="title">New Files</xsl:with-param>
+			<xsl:with-param name="anchor">New</xsl:with-param>
+			<xsl:with-param name="entries" select=".//entry[file/revision][not(file/prevrevision)]"/>
+		</xsl:call-template>
+
+		<xsl:call-template name="show-entries">
+			<xsl:with-param name="title">Modified Files</xsl:with-param>
+			<xsl:with-param name="anchor">Modified</xsl:with-param>
+			<xsl:with-param name="entries" select=".//entry[file/revision][file/prevrevision]"/>
+		</xsl:call-template>
+
+		<!-- change to entries select to address bug #36827 -->
+		<xsl:call-template name="show-entries">
+			<xsl:with-param name="title">Removed Files</xsl:with-param>
+			<xsl:with-param name="anchor">Removed</xsl:with-param>
+			<xsl:with-param name="entries" select=".//entry[not(file/revision)][file/prevrevision]"/>
+		</xsl:call-template>
+        </table>
+        
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="show-entries">
+	<xsl:param name="title"/>
+	<xsl:param name="anchor"/>
+	<xsl:param name="entries"/>
+	<tr>
+		<td colspan="2" class="dateAndAuthor">
+			<a>
+				<xsl:attribute name="name"><xsl:value-of select="$anchor"/></xsl:attribute>
+				<xsl:value-of select="$title"/> - <xsl:value-of select="count($entries)"/> entries
+			</a>
+			<a href="#TOP">(back to top)</a>
+		</td>
+	</tr>
+	<tr>
+		<td width="20">
+			<xsl:text>    </xsl:text>
+		</td>
+		<td>
+		        <ul>
+				<xsl:apply-templates select="$entries"/>
+			</ul>
+		</td>
+	</tr>
+  </xsl:template>  
+
+  <xsl:template match="entry">
+	<xsl:apply-templates select="file"/>
+  </xsl:template>
+
+  <xsl:template match="date">
+    <i><xsl:value-of select="."/></i>
+  </xsl:template>
+
+  <xsl:template match="time">
+    <i><xsl:value-of select="."/></i>
+  </xsl:template>
+
+  <xsl:template match="author">
+    <i>
+      <a>
+        <xsl:attribute name="href">mailto:<xsl:value-of select="."/></xsl:attribute>
+        <xsl:value-of select="."/>
+      </a>
+    </i>
+  </xsl:template>
+
+  <xsl:template match="file">
+    <li>
+      <a target="_new">
+        <xsl:attribute name="href"><xsl:value-of select="$cvsweb"/><xsl:value-of select="$module" />/<xsl:value-of select="name" /></xsl:attribute>
+        <xsl:value-of select="name" />
+      </a>
+      <xsl:if test="string-length(prevrevision) > 0 or string-length(revision) > 0">
+      <xsl:text> </xsl:text>
+      <a target="_new">
+        <xsl:choose>
+          <xsl:when test="string-length(prevrevision) = 0 ">
+            <xsl:attribute name="href"><xsl:value-of select="$cvsweb"/><xsl:value-of select="$module" />/<xsl:value-of select="name" />?rev=<xsl:value-of select="revision" />&amp;content-type=text/x-cvsweb-markup</xsl:attribute>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:attribute name="href"><xsl:value-of select="$cvsweb"/><xsl:value-of select="$module" />/<xsl:value-of select="name" />?r1=<xsl:value-of select="revision" />&amp;r2=<xsl:value-of select="prevrevision"/>&amp;diff_format=h</xsl:attribute>
+          </xsl:otherwise>
+        </xsl:choose> (<xsl:if test="count(prevrevision) &gt; 0"> <xsl:value-of select="prevrevision"/> --&gt; </xsl:if> <xsl:value-of select="revision"/>)
+      </a>
+      </xsl:if>
+    </li>
+  </xsl:template>
+
+  <!-- Any elements within a msg are processed,
+       so that we can preserve HTML tags. -->
+  <xsl:template match="msg">
+    <b><xsl:apply-templates/></b>
+  </xsl:template>
+  
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/asf-logo.gif b/trunk/src/etc/testcases/asf-logo.gif
new file mode 100644
index 0000000..22eb9d7
--- /dev/null
+++ b/trunk/src/etc/testcases/asf-logo.gif
Binary files differ
diff --git a/trunk/src/etc/testcases/core/antclassloader.xml b/trunk/src/etc/testcases/core/antclassloader.xml
new file mode 100644
index 0000000..61b3967
--- /dev/null
+++ b/trunk/src/etc/testcases/core/antclassloader.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<project name="antclassloader-test" basedir=".">

+

+    <property name="tmp.dir" location="tmp space"/>

+    <!-- ant for germans -->

+    <property name="tmp.dir.nonascii" value="&#0227;nt"/>

+    <property name="ext.dir.relative" value="ext"/>

+    <property name="main.jar" location="${tmp.dir}/main.jar"/>

+    <property name="ext.jar.relative" value="${ext.dir.relative}/ext.jar"/>

+    <property name="ext.jar" location="${tmp.dir}/${ext.jar.relative}"/>

+    <property name="build.sysclasspath" value="first"/>

+    <property name="main.jar.nonascii" location="${tmp.dir.nonascii}/main.jar"/>

+    <property name="ext.jar.nonascii" location="${tmp.dir.nonascii}/${ext.jar.relative}"/>

+    <target name="setup" depends="setup.withspace,setup.nonascii"/>

+

+    <target name="setup.withspace">

+        <mkdir dir="${tmp.dir}/${ext.dir.relative}"/>

+        <jar destfile="${main.jar}" whenempty="create">

+          <manifest>

+            <attribute name="Class-Path" value="${ext.jar.relative}"/>

+          </manifest>

+        </jar>

+        <jar destfile="${ext.jar}"/>

+    </target>

+    <target name="setup.nonascii">

+      <mkdir dir="${tmp.dir.nonascii}/${ext.dir.relative}"/>

+      <jar destfile="${main.jar.nonascii}" whenempty="create">

+        <manifest>

+          <attribute name="Class-Path" value="${ext.jar.relative}"/>

+        </manifest>

+      </jar>

+      <jar destfile="${ext.jar.nonascii}"/>

+

+    </target>

+

+    <target name="cleanup">

+        <delete dir="${tmp.dir}" quiet="true"/>

+        <delete dir="${tmp.dir.nonascii}" quiet="true"/>

+    </target>

+

+

+</project>

diff --git a/trunk/src/etc/testcases/core/case.xml b/trunk/src/etc/testcases/core/case.xml
new file mode 100644
index 0000000..ea4ac1d
--- /dev/null
+++ b/trunk/src/etc/testcases/core/case.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project name="parsing-test" basedir="." default="help">
+
+  <target name="help">
+    <echo>
+This build file is intended to be used for testing Ant
+    </echo>
+  </target>
+
+  <target name="case-sensitivity">
+    <concat>
+      <fileSet dir="." includes="parse.xml"/>
+    </concat>
+  </target>
+
+  <target name="taskcase">
+    <ecHO>Should fail</ecHO>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/containersrc/test/SpecialSeq.java b/trunk/src/etc/testcases/core/containersrc/test/SpecialSeq.java
new file mode 100644
index 0000000..ae6a3dd
--- /dev/null
+++ b/trunk/src/etc/testcases/core/containersrc/test/SpecialSeq.java
@@ -0,0 +1,67 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * 
+ */
+package test;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.taskdefs.Echo;
+import java.util.*;
+
+public class SpecialSeq extends Task implements TaskContainer {
+    /** Optional Vector holding the nested tasks */
+    private Vector nestedTasks = new Vector();
+
+    private FileSet fileset;
+    
+    private Echo nestedEcho;
+    
+    /**
+     * Add a nested task.
+     * <p>
+     * @param nestedTask  Nested task to execute
+     * <p>
+     */
+    public void addTask(Task nestedTask) {
+        nestedTasks.addElement(nestedTask);
+    }
+
+    /**
+     * Execute all nestedTasks.
+     */
+    public void execute() throws BuildException {
+        if (fileset == null || fileset.getDir(getProject()) == null) {
+            throw new BuildException("Fileset was not configured");
+        }
+        for (Enumeration e = nestedTasks.elements(); e.hasMoreElements();) {
+            Task nestedTask = (Task) e.nextElement();
+            nestedTask.perform();
+        }
+        nestedEcho.reconfigure();
+        nestedEcho.perform();
+    }
+
+    public void addFileset(FileSet fileset) {
+        this.fileset = fileset;
+    }
+    
+    public void addNested(Echo nestedEcho) {
+        this.nestedEcho = nestedEcho;
+    }
+}
diff --git a/trunk/src/etc/testcases/core/directoryscanner.xml b/trunk/src/etc/testcases/core/directoryscanner.xml
new file mode 100644
index 0000000..67f3394
--- /dev/null
+++ b/trunk/src/etc/testcases/core/directoryscanner.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="directoryscanner-test" basedir=".">
+
+    <property name="tmp.dir" location="tmp"/>
+
+    <target name="setup">
+        <mkdir dir="${tmp.dir}/alpha/beta/gamma"/>
+        <touch file="${tmp.dir}/alpha/beta/gamma/gamma.xml"/>
+        <touch file="${tmp.dir}/alpha/beta/beta.xml"/>
+    </target>
+
+    <target name="extended-setup" depends="setup">
+        <mkdir dir="${tmp.dir}/delta"/>
+        <touch file="${tmp.dir}/delta/delta.xml"/>
+    </target>
+
+    <target name="children-of-excluded-dir-setup" depends="extended-setup" />
+
+    <target name="cleanup">
+        <delete dir="${tmp.dir}" quiet="true"/>
+    </target>
+
+    <target name="symlink-setup" depends="setup">
+        <mkdir dir="${tmp.dir}/epsilon/gamma"/>
+        <delete dir="${tmp.dir}/alpha/beta"/>
+        <symlink link="${tmp.dir}/alpha/beta" resource="${tmp.dir}/epsilon"/>
+        <touch file="${tmp.dir}/alpha/beta/gamma/gamma.xml"/>
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/dispatch/dispatch.xml b/trunk/src/etc/testcases/core/dispatch/dispatch.xml
new file mode 100644
index 0000000..d529644
--- /dev/null
+++ b/trunk/src/etc/testcases/core/dispatch/dispatch.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project name="dispatch-test" default="disp">
+
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="disp">
+    <taskdef name="disptask"
+             classname="org.apache.tools.ant.taskdefs.PickOneTask">
+      <classpath refid="testclasses" />
+    </taskdef>
+    <disptask action="list"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/duplicate-target-imported.xml b/trunk/src/etc/testcases/core/duplicate-target-imported.xml
new file mode 100644
index 0000000..fc945f7
--- /dev/null
+++ b/trunk/src/etc/testcases/core/duplicate-target-imported.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project>
+    <target name="once">
+        <echo>once from imported</echo>
+    </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/duplicate-target.xml b/trunk/src/etc/testcases/core/duplicate-target.xml
new file mode 100644
index 0000000..0a29526
--- /dev/null
+++ b/trunk/src/etc/testcases/core/duplicate-target.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project>
+    <target name="once">
+        <echo>once</echo>
+    </target>
+
+    <target name="twice">
+        <echo>twice-a</echo>
+    </target>
+
+    <target name="twice">
+        <echo>twice-b</echo>
+    </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/duplicate-target2.xml b/trunk/src/etc/testcases/core/duplicate-target2.xml
new file mode 100644
index 0000000..6d96bca
--- /dev/null
+++ b/trunk/src/etc/testcases/core/duplicate-target2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project>
+
+    <import file="duplicate-target-imported.xml"/>
+
+    <target name="once">
+        <echo>once from buildfile</echo>
+    </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/executor.xml b/trunk/src/etc/testcases/core/executor.xml
new file mode 100644
index 0000000..080c8dc
--- /dev/null
+++ b/trunk/src/etc/testcases/core/executor.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project>
+  <target name="foo">
+    <echo>foo</echo>
+    <fail if="failfoo" message="failfoo" />
+  </target>
+  <target name="a" depends="foo">
+    <echo>a</echo>
+  </target>
+  <target name="b" depends="foo">
+    <echo>b</echo>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/extended-taskdef.xml b/trunk/src/etc/testcases/core/extended-taskdef.xml
new file mode 100644
index 0000000..58ca979
--- /dev/null
+++ b/trunk/src/etc/testcases/core/extended-taskdef.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="extended-taskdef" default="testRun">
+
+  <description>
+    Try and replicate a reported problem.
+
+  </description>
+  <property name="src" value="Foo.java"/>
+  <property name="taskdefs" value="tasks.properties"/>
+
+  <target name="write" >
+    <echo file="${src}">
+      import org.apache.tools.ant.BuildException;
+
+      public class Foo extends org.apache.tools.ant.taskdefs.WaitFor {
+
+        public void execute() {
+          throw  new BuildException("executing the Foo task");
+        }
+      }
+    </echo>
+    <propertyfile file="${taskdefs}">
+      <entry key="foo2" value="Foo"/>
+    </propertyfile>
+  </target>
+
+  <target name="compile" depends="write">
+    <javac srcdir="${basedir}" includes="${src}"/>
+  </target>
+
+  <target name="testRun" depends="compile">
+    <taskdef name="foo" classname="Foo"
+        classpath="${basedir}"/>
+    <foo maxwait="5" maxwaitunit="second"
+        timeoutproperty="foo">
+      <or/>
+    </foo>
+  </target>
+
+  <target name="testRun2" depends="compile">
+    <taskdef resource="${taskdefs}" classpath="${basedir}"/>
+    <foo2 maxwait="5" maxwaitunit="second"
+        timeoutproperty="foo">
+      <or/>
+    </foo2>
+  </target>
+
+
+  <target name="teardown">
+    <delete>
+      <fileset dir="${basedir}"
+          includes="${src},*.class"/>
+    </delete>
+    <delete file="${taskdefs}" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/immutable.xml b/trunk/src/etc/testcases/core/immutable.xml
new file mode 100644
index 0000000..26fda08
--- /dev/null
+++ b/trunk/src/etc/testcases/core/immutable.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project name="immutable-test" basedir="." default="test1">
+
+  <target name="test1">
+    <property name="test" value="original"/>
+    <available file="immutable.xml" property="test" value="override"/>
+  </target>
+
+  <target name="test2">
+    <tstamp/>
+    <tstamp prefix="start"/>
+  </target>
+
+  <target name="test3">
+    <property name="DSTAMP" value="original"/>
+    <tstamp/>
+  </target>
+
+  <target name="test4">
+    <property name="test" value="original"/>
+    <condition property="test" value="override">
+      <equals arg1="1" arg2="1"/>
+    </condition>
+  </target>
+
+  <target name="test5">
+    <property name="test" value="original"/>
+    <checksum file="immutable.xml" verifyProperty="test"/>
+  </target>
+
+  <target name="test6">
+    <property name="test1" value="original"/>
+    <property name="test2" value="original"/>
+    <!--  How to make this cross-platform? -->
+    <exec executable="cmd.exe" os="Windows 2000" outputproperty="test1" resultProperty="test2">
+      <arg line="/c dir"/>
+    </exec>
+  </target>
+
+  <target name="test7">
+    <property name="test" value="original"/>
+    <pathconvert targetos="unix" property="test" >
+      <path>
+        <pathelement location="/lib/weblogicaux.jar" />
+        <pathelement location="/classes" />
+        <pathelement location="/mssqlserver4/classes" />
+        <pathelement location="c:\winnt\System32" />
+      </path>
+    </pathconvert>
+  </target>
+
+  <target name="test8">
+    <antcall inheritAll="false" target="echo-target">
+      <param name="echo.value" value="Meep meep!" />
+    </antcall>
+  </target>
+
+  <target name="echo-target">
+    <echo message="Value of echo=${echo.value}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/include/basic/include.inc b/trunk/src/etc/testcases/core/include/basic/include.inc
new file mode 100644
index 0000000..960792d
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/basic/include.inc
@@ -0,0 +1,20 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<target name="test1">
+    <echo message="from included entity"/>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/basic/include.xml b/trunk/src/etc/testcases/core/include/basic/include.xml
new file mode 100644
index 0000000..2c131b1
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/basic/include.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "file:./include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git a/trunk/src/etc/testcases/core/include/basic/relative.xml b/trunk/src/etc/testcases/core/include/basic/relative.xml
new file mode 100644
index 0000000..697c841
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/basic/relative.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "./include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git "a/trunk/src/etc/testcases/core/include/frag\043ment/include.inc" "b/trunk/src/etc/testcases/core/include/frag\043ment/include.inc"
new file mode 100644
index 0000000..960792d
--- /dev/null
+++ "b/trunk/src/etc/testcases/core/include/frag\043ment/include.inc"
@@ -0,0 +1,20 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<target name="test1">
+    <echo message="from included entity"/>
+</target>
diff --git "a/trunk/src/etc/testcases/core/include/frag\043ment/include.xml" "b/trunk/src/etc/testcases/core/include/frag\043ment/include.xml"
new file mode 100644
index 0000000..400a15c
--- /dev/null
+++ "b/trunk/src/etc/testcases/core/include/frag\043ment/include.xml"
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "file:include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git "a/trunk/src/etc/testcases/core/include/frag\043ment/relative.xml" "b/trunk/src/etc/testcases/core/include/frag\043ment/relative.xml"
new file mode 100644
index 0000000..05bbc9e
--- /dev/null
+++ "b/trunk/src/etc/testcases/core/include/frag\043ment/relative.xml"
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git "a/trunk/src/etc/testcases/core/include/frag\043ment/simple.xml" "b/trunk/src/etc/testcases/core/include/frag\043ment/simple.xml"
new file mode 100644
index 0000000..d337234
--- /dev/null
+++ "b/trunk/src/etc/testcases/core/include/frag\043ment/simple.xml"
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project name="include-test" basedir="." default="test1">
+<target name="test1">
+    <echo message="from simple buildfile"/>
+</target>
+</project>
diff --git a/trunk/src/etc/testcases/core/include/included_file_parse_error/build.xml b/trunk/src/etc/testcases/core/include/included_file_parse_error/build.xml
new file mode 100644
index 0000000..d75747c
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/included_file_parse_error/build.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE project [
+    <!ENTITY included_file SYSTEM "file:./included_file.xml">
+]>
+
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+  </target>
+
+  &included_file;
+
+  <target name="test" depends="included-target">
+    <echo>test target ran.</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/include/included_file_parse_error/included_file.xml b/trunk/src/etc/testcases/core/include/included_file_parse_error/included_file.xml
new file mode 100644
index 0000000..5fbd3f5
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/included_file_parse_error/included_file.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<target name="included-target">
+  extraneous_text
+  <echo>included-target ran.</echo>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/included_file_task_error/build.xml b/trunk/src/etc/testcases/core/include/included_file_task_error/build.xml
new file mode 100644
index 0000000..d75747c
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/included_file_task_error/build.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE project [
+    <!ENTITY included_file SYSTEM "file:./included_file.xml">
+]>
+
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+  </target>
+
+  &included_file;
+
+  <target name="test" depends="included-target">
+    <echo>test target ran.</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/include/included_file_task_error/included_file.xml b/trunk/src/etc/testcases/core/include/included_file_task_error/included_file.xml
new file mode 100644
index 0000000..d40d397
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/included_file_task_error/included_file.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<target name="included-target">
+  <copy file="nonexistent-file" todir="/non/existent/dir"/>
+  <echo>included-target ran.</echo>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/including_file_parse_error/build.xml b/trunk/src/etc/testcases/core/include/including_file_parse_error/build.xml
new file mode 100644
index 0000000..7de5264
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/including_file_parse_error/build.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE project [
+    <!ENTITY included_file SYSTEM "file:./included_file.xml">
+]>
+
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+  </target>
+
+  &included_file;
+
+  extraneous_text
+
+  <target name="test" depends="included-target">
+    <echo>test target ran.</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/include/including_file_parse_error/included_file.xml b/trunk/src/etc/testcases/core/include/including_file_parse_error/included_file.xml
new file mode 100644
index 0000000..c607bbc
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/including_file_parse_error/included_file.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<target name="included-target">
+  <echo>included-target ran.</echo>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/including_file_task_error/build.xml b/trunk/src/etc/testcases/core/include/including_file_task_error/build.xml
new file mode 100644
index 0000000..687b8cf
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/including_file_task_error/build.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!DOCTYPE project [
+    <!ENTITY included_file SYSTEM "file:./included_file.xml">
+]>
+
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+  </target>
+
+  &included_file;
+
+  <target name="test" depends="included-target">
+    <copy file="nonexistent-file" todir="/non/existent/dir"/>
+    <echo>test target ran.</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/include/including_file_task_error/included_file.xml b/trunk/src/etc/testcases/core/include/including_file_task_error/included_file.xml
new file mode 100644
index 0000000..c607bbc
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/including_file_task_error/included_file.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<target name="included-target">
+  <echo>included-target ran.</echo>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/with space/include.inc b/trunk/src/etc/testcases/core/include/with space/include.inc
new file mode 100644
index 0000000..d8fd638
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/with space/include.inc
@@ -0,0 +1,19 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<target name="test1">
+    <echo message="from included entity in &apos;with space&apos;"/>
+</target>
diff --git a/trunk/src/etc/testcases/core/include/with space/include.xml b/trunk/src/etc/testcases/core/include/with space/include.xml
new file mode 100644
index 0000000..4b693cd
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/with space/include.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "file:include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git a/trunk/src/etc/testcases/core/include/with space/relative.xml b/trunk/src/etc/testcases/core/include/with space/relative.xml
new file mode 100644
index 0000000..81f502a
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/with space/relative.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<!DOCTYPE project [
+  <!ENTITY include SYSTEM "include.inc">
+]>
+
+<project name="include-test" basedir="." default="test1">
+    &include;
+</project>
diff --git a/trunk/src/etc/testcases/core/include/with space/simple.xml b/trunk/src/etc/testcases/core/include/with space/simple.xml
new file mode 100644
index 0000000..4092ce7
--- /dev/null
+++ b/trunk/src/etc/testcases/core/include/with space/simple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="include-test" basedir="." default="test1">
+  <target name="test1">
+    <echo message="from simple buildfile in &apos;with space&apos;"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/loaderref/loaderref.xml b/trunk/src/etc/testcases/core/loaderref/loaderref.xml
new file mode 100644
index 0000000..b06efe8
--- /dev/null
+++ b/trunk/src/etc/testcases/core/loaderref/loaderref.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<project name="loaderref-test" default="help">
+
+  <property name="src.dir" value="src"/>
+  <property name="classes.dir" value="classes"/>
+
+  <target name="help">
+    <echo>
+This build file is intended to be used for testing Ant
+    </echo>
+  </target>
+
+  <target name="clean">
+    <delete dir="${classes.dir}"/>
+  </target>
+
+  <target name="compile">
+    <mkdir dir="${classes.dir}"/>
+    <javac srcdir="${src.dir}" destdir="${classes.dir}"/>
+  </target>
+
+  <target name="testbadref" depends="compile" >
+    <taskdef loaderref="loaderref-test"
+             name="test1"
+             classname="Test1"
+             classpath="${classes.dir}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/core/loaderref/src/Task1.java b/trunk/src/etc/testcases/core/loaderref/src/Task1.java
new file mode 100644
index 0000000..cb374bd
--- /dev/null
+++ b/trunk/src/etc/testcases/core/loaderref/src/Task1.java
@@ -0,0 +1,21 @@
+/*
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+import org.apache.tools.ant.Task;
+
+public class Task1 extends Task {
+}
+
diff --git a/trunk/src/etc/testcases/core/location.xml b/trunk/src/etc/testcases/core/location.xml
new file mode 100644
index 0000000..7e8f639
--- /dev/null
+++ b/trunk/src/etc/testcases/core/location.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="location" default="all">
+  <target name="all">
+    <fail>Only use this build file from within tests</fail>
+  </target>
+
+  <target name="testPlainTask">
+    <echo id="echo">Hello</echo>
+  </target>
+
+  <target name="testStandaloneType">
+    <echo id="echo2">Hello</echo>
+    <fileset id="fs" dir="."/>
+  </target>
+
+  <target name="testConditionTask">
+    <condition property="foo" id="cond">
+      <equals arg1="bar" arg2="baz"/>
+    </condition>
+  </target>
+
+  <target name="define">
+    <property name="testclasses"
+      location="../../../../build/testcases" />
+    <taskdef name="echoloc"
+      classname="org.apache.tools.ant.LocationTest$EchoLocation">
+      <classpath>
+        <pathelement location="${testclasses}" />
+        <pathelement path="${java.class.path}"/>
+      </classpath>
+    </taskdef>
+  </target>
+
+  <target name="macrodef" depends="define">
+    <macrodef name="echoloc2" backtrace="false">
+      <sequential>
+        <echoloc/>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <target name="testMacrodefWrappedTask" depends="macrodef">
+    <echo id="echo3">Hello</echo>
+    <echoloc2/>
+  </target>
+
+  <target name="presetdef" depends="define">
+    <presetdef name="echoloc3">
+      <echoloc/>
+    </presetdef>
+  </target>
+
+  <target name="testPresetdefWrappedTask" depends="presetdef">
+    <echo id="echo4">Hello</echo>
+    <echoloc3/>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/core/taskcontainer.xml b/trunk/src/etc/testcases/core/taskcontainer.xml
new file mode 100644
index 0000000..3dca12e
--- /dev/null
+++ b/trunk/src/etc/testcases/core/taskcontainer.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="dont-run-this">
+
+  <property name="build.dir" value="build"/>
+  
+  <target name="dont-run-this">
+    <fail>This build file is supposed to be run by a Unit test</fail>
+  </target>
+ 
+
+  <target name="testPropertyExpansion">
+    <sequential>
+      <property name="foo" value="it worked"/>
+      <echo message="As attribute: ${foo}"/>
+      <echo>As nested text: ${foo}</echo>
+    </sequential>
+  </target>
+
+  <target name="testTaskdef">
+    <mkdir dir="${build.dir}"/>
+    <javac srcdir="containersrc" destdir="${build.dir}" debug="on"/>
+
+    <sequential>    
+      <taskdef name="sseq" classpath="${build.dir}" classname="test.SpecialSeq"/>
+      <sseq>
+        <fileset dir="."/>
+        <property name="foo" value="it worked"/>
+        <echo message="As attribute: ${foo}"/>
+        <echo>As nested text: ${foo}</echo>
+        <nested message="As nested task: ${foo}"/>
+      </sseq>
+    </sequential>
+  </target>
+
+  <target name="testCaseInsensitive">
+    <taskdef name="Prattle" classname="org.apache.tools.ant.taskdefs.Echo"/>  
+    <taskdef name="Seq"  
+             classname="org.apache.tools.ant.taskdefs.Sequential"/>  
+    <Prattle>hello</Prattle>  
+    <Seq>  
+      <Prattle> world</Prattle>  
+    </Seq>  
+  </target>  
+
+  <target name="cleanup">
+    <delete dir="${build.dir}"/>
+  </target>
+  
+</project>
diff --git a/trunk/src/etc/testcases/core/topleveltasks/notarget.xml b/trunk/src/etc/testcases/core/topleveltasks/notarget.xml
new file mode 100644
index 0000000..2543751
--- /dev/null
+++ b/trunk/src/etc/testcases/core/topleveltasks/notarget.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="foo">
+  <echo message="Called" />
+  <target name="foo" />
+</project>
diff --git a/trunk/src/etc/testcases/core/topleveltasks/targetlevelant.xml b/trunk/src/etc/testcases/core/topleveltasks/targetlevelant.xml
new file mode 100644
index 0000000..9b1bb1d
--- /dev/null
+++ b/trunk/src/etc/testcases/core/topleveltasks/targetlevelant.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project basedir="." default="foo">
+  <target name="foo">
+    <ant antfile="notarget.xml" />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/core/topleveltasks/toplevelant.xml b/trunk/src/etc/testcases/core/topleveltasks/toplevelant.xml
new file mode 100644
index 0000000..968ad6c
--- /dev/null
+++ b/trunk/src/etc/testcases/core/topleveltasks/toplevelant.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project basedir="." default="foo">
+  <ant antfile="notarget.xml" />
+  <target name="foo" />
+</project>
diff --git a/trunk/src/etc/testcases/core/unknownelement.xml b/trunk/src/etc/testcases/core/unknownelement.xml
new file mode 100644
index 0000000..74970ac
--- /dev/null
+++ b/trunk/src/etc/testcases/core/unknownelement.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project>
+  <target name="testMaybeConfigure">
+    <taskdef name="parent" 
+             classname="org.apache.tools.ant.UnknownElementTest$Parent"
+             loaderref="unknown.id">
+      <classpath>
+        <pathelement location="../../../../build/testcases"/>
+        <pathelement path="${java.class.path}"/>
+      </classpath>
+    </taskdef>
+    <taskdef name="child"
+             classname="org.apache.tools.ant.UnknownElementTest$Child"
+             loaderref="unknown.id"/>
+    <parent>
+      <child/>
+      <child/>
+    </parent>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/filters/build.xml b/trunk/src/etc/testcases/filters/build.xml
new file mode 100644
index 0000000..9ae69fc
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/build.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <target name="init">
+    <mkdir dir="result" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result"/>
+  </target>
+
+  <target name="testLineContains" depends="init">
+    <copy todir="result">
+      <fileset dir="input">
+        <include name="linecontains.test"/>
+      </fileset>
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.LineContains">
+          <param type="contains" value="beta"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+    <!--<fixcrlf srcdir="result" eol="lf">
+      <include name="linecontains.test"/>
+    </fixcrlf>-->
+  </target>
+  
+  <target name="testNegateLineContains" depends="init">
+    <copy file="input/linecontains.test"
+          tofile="result/negatelinecontains.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.LineContains">
+          <param type="negate" value="true"/>
+          <param type="contains" value="beta"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+    <fail>
+      <condition>
+        <not>
+          <filesmatch file1="result/negatelinecontains.test"
+                      file2="expected/negatelinecontains.test" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+  
+  <target name="testEscapeUnicode" depends="init">
+    <copy todir="result" encoding="UTF-8">
+      <fileset dir="input">
+        <include name="escapeunicode.test"/>
+      </fileset>
+      <filterchain>
+        <escapeunicode/>
+      </filterchain>
+    </copy>
+    <fixcrlf srcdir="result" eol="crlf">
+      <include name="escapeunicode.test"/>
+    </fixcrlf>
+  </target>
+
+  <target name="testStripJavaComments" depends="init">
+    <copy todir="result">
+      <fileset dir="input" includes="stripjavacomments.test" />
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.StripJavaComments" />
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testReplaceTokens" depends="init">
+    <copy todir="result">
+      <fileset dir="input" includes="replacetokens.test" />
+      <filterchain>
+        <replacetokens>
+          <token key="foo" value=""/>
+        </replacetokens>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testReplaceTokensPropertyFile" depends="init">
+    <copy tofile="result/replacetokensPropertyFile.test">
+      <fileset dir="input" includes="replacetokens.test" />
+      <filterchain>
+	<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
+          <param type="propertiesfile" value="${basedir}/input/sample.properties"/>
+    	</filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testNoAddNewLine" depends="init">
+    <concat destfile="result/nonl">This has no new lines</concat>
+    <copy file="result/nonl" tofile="result/nonl-copyfilter">
+      <filterchain><tokenfilter/></filterchain>
+    </copy>
+    <condition property="filterchain.files.are.same">
+      <filesmatch file1="result/nonl" file2="result/nonl-copyfilter"/>
+    </condition>
+    <fail unless="filterchain.files.are.same">File was modified</fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/filters/concat.xml b/trunk/src/etc/testcases/filters/concat.xml
new file mode 100644
index 0000000..7de1064
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/concat.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <target name="init">
+    <mkdir dir="result" />
+    <echo file="result/prepend.txt" message="this-should-be-the-first-line${line.separator}"/>
+    <echo file="result/append.txt" message="this-should-be-the-last-line${line.separator}"/>
+    <copy file="input/head-tail.test" tofile="input/concatfilter.test"/>
+    <fixcrlf srcDir="input" includes="concatfilter.test"/>
+    <!-- to be consistent on MacOS X.  fixcrlf uses CR while line.sep is LF -->
+    <fixcrlf srcDir="result" includes="append.txt,prepend.txt"/>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result"/>
+    <delete>
+      <fileset dir="input" includes="concatfilter.test"/>
+    </delete>
+  </target>
+
+
+  <target name="testFilterReaderNoArgs" depends="init">
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.FilterReaderNoArgs.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.ConcatFilter"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testFilterReaderPrepend" depends="init">
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.FilterReaderPrepend.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.ConcatFilter">
+          <param name="prepend" value="result/prepend.txt"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testFilterReaderAppend" depends="init">
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.FilterReaderAppend.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.ConcatFilter">
+          <param name="append" value="result/append.txt"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testFilterReaderPrependAppend" depends="init">
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.FilterReaderPrependAppend.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.ConcatFilter">
+          <param name="prepend" value="result/prepend.txt"/>
+          <param name="append"  value="result/append.txt"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testConcatFilter" depends="init">
+    <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/>
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.ConcatFilter.test">
+      <filterchain>
+        <concatfilter/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testConcatFilterPrepend" depends="init">
+    <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/>
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.ConcatFilterPrepend.test">
+      <filterchain>
+        <concatfilter prepend="result/prepend.txt"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testConcatFilterAppend" depends="init">
+    <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/>
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.ConcatFilterAppend.test">
+      <filterchain>
+        <concatfilter append="result/append.txt"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testConcatFilterPrependAppend" depends="init">
+    <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/>
+    <copy file="input/concatfilter.test"
+          tofile="result/concat.ConcatFilterPrependAppend.test">
+      <filterchain>
+        <concatfilter prepend="result/prepend.txt" append="result/append.txt"/>
+      </filterchain>
+    </copy>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/filters/dynamicfilter.xml b/trunk/src/etc/testcases/filters/dynamicfilter.xml
new file mode 100644
index 0000000..ed91e1d
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/dynamicfilter.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <target name="init">
+    <mkdir dir="result" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result"/>
+  </target>
+
+  <target name="dynamicfilter">
+    <path id="test-classes">
+      <pathelement location="../../../../build/testcases" />
+      <pathelement path="${java.class.path}" />
+    </path>
+    <typedef 
+      name="customfilter" 
+      classname="org.apache.tools.ant.filters.DynamicFilterTest$CustomFilter">
+      <classpath refid="test-classes"/>
+    </typedef>
+    
+    <concat destfile="result/input">
+      hello world
+    </concat>
+
+    <copy file="result/input" tofile="result/dynamicfilter">
+      <filterchain>
+        <customfilter replace="o" with="O"/>
+      </filterchain>
+    </copy>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/filters/expected/escapeunicode.test b/trunk/src/etc/testcases/filters/expected/escapeunicode.test
new file mode 100644
index 0000000..ffede99
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/escapeunicode.test
@@ -0,0 +1,9 @@
+#hebrew shalom olam (hello world)

+text.hebrew=\u05e9\u05dc\u05d5\u05dd \u05e2\u05d5\u05dc\u05dd

+#goethe gingko biloba

+text.german.1=Sp\u00fcrst du nicht an meinen Liedern,

+text.german.2=Da\u00df ich eins und doppelt bin ?

+# Francois Villon Ballade des Pendus

+text.french=Fr\u00e8res humains qui apr\u00e8s nous vivez

+# Usual IT example

+text.basic.latin=Hello World 

diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.head.test b/trunk/src/etc/testcases/filters/expected/head-tail.head.test
new file mode 100644
index 0000000..43d44e5
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.head.test
@@ -0,0 +1,10 @@
+Line  1
+Line  2
+Line  3
+Line  4
+Line  5
+Line  6
+Line  7
+Line  8
+Line  9
+Line 10
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.headAllSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.headAllSkip.test
new file mode 100644
index 0000000..eeffaa3
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.headAllSkip.test
@@ -0,0 +1,58 @@
+Line  3
+Line  4
+Line  5
+Line  6
+Line  7
+Line  8
+Line  9
+Line 10
+Line 11
+Line 12
+Line 13
+Line 14
+Line 15
+Line 16
+Line 17
+Line 18
+Line 19
+Line 20
+Line 21
+Line 22
+Line 23
+Line 24
+Line 25
+Line 26
+Line 27
+Line 28
+Line 29
+Line 30
+Line 31
+Line 32
+Line 33
+Line 34
+Line 35
+Line 36
+Line 37
+Line 38
+Line 39
+Line 40
+Line 41
+Line 42
+Line 43
+Line 44
+Line 45
+Line 46
+Line 47
+Line 48
+Line 49
+Line 50
+Line 51
+Line 52
+Line 53
+Line 54
+Line 55
+Line 56
+Line 57
+Line 58
+Line 59
+Line 60
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.headLines.test b/trunk/src/etc/testcases/filters/expected/head-tail.headLines.test
new file mode 100644
index 0000000..98fa9e8
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.headLines.test
@@ -0,0 +1,2 @@
+Line  1
+Line  2
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.headLinesSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.headLinesSkip.test
new file mode 100644
index 0000000..13cb234
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.headLinesSkip.test
@@ -0,0 +1,2 @@
+Line  3
+Line  4
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.headSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.headSkip.test
new file mode 100644
index 0000000..57f17d5
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.headSkip.test
@@ -0,0 +1,10 @@
+Line  3
+Line  4
+Line  5
+Line  6
+Line  7
+Line  8
+Line  9
+Line 10
+Line 11
+Line 12
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.headtail.test b/trunk/src/etc/testcases/filters/expected/head-tail.headtail.test
new file mode 100644
index 0000000..13cb234
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.headtail.test
@@ -0,0 +1,2 @@
+Line  3
+Line  4
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.tail.test b/trunk/src/etc/testcases/filters/expected/head-tail.tail.test
new file mode 100644
index 0000000..5793dc4
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.tail.test
@@ -0,0 +1,10 @@
+Line 51
+Line 52
+Line 53
+Line 54
+Line 55
+Line 56
+Line 57
+Line 58
+Line 59
+Line 60
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.tailAllSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.tailAllSkip.test
new file mode 100644
index 0000000..532cf01
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.tailAllSkip.test
@@ -0,0 +1,58 @@
+Line  1
+Line  2
+Line  3
+Line  4
+Line  5
+Line  6
+Line  7
+Line  8
+Line  9
+Line 10
+Line 11
+Line 12
+Line 13
+Line 14
+Line 15
+Line 16
+Line 17
+Line 18
+Line 19
+Line 20
+Line 21
+Line 22
+Line 23
+Line 24
+Line 25
+Line 26
+Line 27
+Line 28
+Line 29
+Line 30
+Line 31
+Line 32
+Line 33
+Line 34
+Line 35
+Line 36
+Line 37
+Line 38
+Line 39
+Line 40
+Line 41
+Line 42
+Line 43
+Line 44
+Line 45
+Line 46
+Line 47
+Line 48
+Line 49
+Line 50
+Line 51
+Line 52
+Line 53
+Line 54
+Line 55
+Line 56
+Line 57
+Line 58
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.tailLines.test b/trunk/src/etc/testcases/filters/expected/head-tail.tailLines.test
new file mode 100644
index 0000000..6650673
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.tailLines.test
@@ -0,0 +1,2 @@
+Line 59
+Line 60
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.tailLinesSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.tailLinesSkip.test
new file mode 100644
index 0000000..42746d1
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.tailLinesSkip.test
@@ -0,0 +1,2 @@
+Line 57
+Line 58
diff --git a/trunk/src/etc/testcases/filters/expected/head-tail.tailSkip.test b/trunk/src/etc/testcases/filters/expected/head-tail.tailSkip.test
new file mode 100644
index 0000000..070eeee
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/head-tail.tailSkip.test
@@ -0,0 +1,10 @@
+Line 49
+Line 50
+Line 51
+Line 52
+Line 53
+Line 54
+Line 55
+Line 56
+Line 57
+Line 58
diff --git a/trunk/src/etc/testcases/filters/expected/linecontains.test b/trunk/src/etc/testcases/filters/expected/linecontains.test
new file mode 100644
index 0000000..aabaa03
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/linecontains.test
@@ -0,0 +1,4 @@
+This is line 2 with beta.
+This is line 3 with beta.
+This is line 5 with beta.
+This is line 7 with beta.
diff --git a/trunk/src/etc/testcases/filters/expected/negatelinecontains.test b/trunk/src/etc/testcases/filters/expected/negatelinecontains.test
new file mode 100644
index 0000000..a1437e9
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/negatelinecontains.test
@@ -0,0 +1,3 @@
+This is line 1 with alpha.
+This is line 4 with gamma.
+This is line 6 with delta.
diff --git a/trunk/src/etc/testcases/filters/expected/replacetokens.test b/trunk/src/etc/testcases/filters/expected/replacetokens.test
new file mode 100644
index 0000000..e666476
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/replacetokens.test
@@ -0,0 +1,2 @@
+12
+3
diff --git a/trunk/src/etc/testcases/filters/expected/stripjavacomments.test b/trunk/src/etc/testcases/filters/expected/stripjavacomments.test
new file mode 100644
index 0000000..c8d0672
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/expected/stripjavacomments.test
@@ -0,0 +1,19 @@
+
+
+ 
+public class NormalLine {
+
+    private String withComment; 
+
+    
+    public void doNothing() {
+        
+        int i;
+        
+        int j;
+    }
+
+    private String url = "http://ant.apache.org/"; 
+    private String url2 = "\"http://ant.apache.org/\""; 
+
+}
diff --git a/trunk/src/etc/testcases/filters/head-tail.xml b/trunk/src/etc/testcases/filters/head-tail.xml
new file mode 100644
index 0000000..ab709ee
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/head-tail.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <target name="init">
+    <mkdir dir="result" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result"/>
+  </target>
+
+  <!-- Testcases for HeadFilter -->
+
+  <target name="testHead" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.head.test">
+      <filterchain>
+        <headfilter/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testHeadLines" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.headLines.test">
+      <filterchain>
+        <headfilter lines="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testHeadSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.headSkip.test">
+      <filterchain>
+        <headfilter skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testHeadLinesSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.headLinesSkip.test">
+      <filterchain>
+        <headfilter lines="2" skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testFilterReaderHeadLinesSkip" depends="init">
+    <copy file="input/head-tail.test" 
+          tofile="result/head-tail.filterReaderHeadLinesSkip.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.HeadFilter">
+          <param name="lines" value="2"/>
+          <param name="skip" value="2"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testHeadAllSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.headAllSkip.test">
+      <filterchain>
+        <headfilter lines="-1" skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <!-- Testcases for TailFilter -->
+
+  <target name="testTail" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.tail.test">
+      <filterchain>
+        <tailfilter/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testTailLines" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.tailLines.test">
+      <filterchain>
+        <tailfilter lines="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testTailSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.tailSkip.test">
+      <filterchain>
+        <tailfilter skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testTailLinesSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.tailLinesSkip.test">
+      <filterchain>
+        <tailfilter lines="2" skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testFilterReaderTailLinesSkip" depends="init">
+    <copy file="input/head-tail.test" 
+          tofile="result/head-tail.filterReaderTailLinesSkip.test">
+      <filterchain>
+        <filterreader classname="org.apache.tools.ant.filters.TailFilter">
+          <param name="lines" value="2"/>
+          <param name="skip" value="2"/>
+        </filterreader>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testTailAllSkip" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.tailAllSkip.test">
+      <filterchain>
+        <tailfilter lines="-1" skip="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <!-- Testcases for combined scenarios -->
+
+  <target name="testHeadTail" depends="init">
+    <copy file="input/head-tail.test" tofile="result/head-tail.headtail.test">
+      <filterchain>
+        <headfilter lines="4"/>
+        <tailfilter lines="2"/>
+      </filterchain>
+    </copy>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/filters/input/escapeunicode.test b/trunk/src/etc/testcases/filters/input/escapeunicode.test
new file mode 100644
index 0000000..1f01178
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/escapeunicode.test
@@ -0,0 +1,9 @@
+#hebrew shalom olam (hello world)

+text.hebrew=שלום עולם

+#goethe gingko biloba

+text.german.1=Spürst du nicht an meinen Liedern,

+text.german.2=Daß ich eins und doppelt bin ?

+# Francois Villon Ballade des Pendus

+text.french=Frères humains qui après nous vivez

+# Usual IT example

+text.basic.latin=Hello World 

diff --git a/trunk/src/etc/testcases/filters/input/head-tail.small.test b/trunk/src/etc/testcases/filters/input/head-tail.small.test
new file mode 100644
index 0000000..c91f1d7
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/head-tail.small.test
@@ -0,0 +1,5 @@
+Line  1
+Line  2
+Line  3
+Line  4
+Line  5
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/filters/input/head-tail.test b/trunk/src/etc/testcases/filters/input/head-tail.test
new file mode 100644
index 0000000..8fac760
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/head-tail.test
@@ -0,0 +1,60 @@
+Line  1
+Line  2
+Line  3
+Line  4
+Line  5
+Line  6
+Line  7
+Line  8
+Line  9
+Line 10
+Line 11
+Line 12
+Line 13
+Line 14
+Line 15
+Line 16
+Line 17
+Line 18
+Line 19
+Line 20
+Line 21
+Line 22
+Line 23
+Line 24
+Line 25
+Line 26
+Line 27
+Line 28
+Line 29
+Line 30
+Line 31
+Line 32
+Line 33
+Line 34
+Line 35
+Line 36
+Line 37
+Line 38
+Line 39
+Line 40
+Line 41
+Line 42
+Line 43
+Line 44
+Line 45
+Line 46
+Line 47
+Line 48
+Line 49
+Line 50
+Line 51
+Line 52
+Line 53
+Line 54
+Line 55
+Line 56
+Line 57
+Line 58
+Line 59
+Line 60
diff --git a/trunk/src/etc/testcases/filters/input/linecontains.test b/trunk/src/etc/testcases/filters/input/linecontains.test
new file mode 100644
index 0000000..c95b553
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/linecontains.test
@@ -0,0 +1,7 @@
+This is line 1 with alpha.
+This is line 2 with beta.
+This is line 3 with beta.
+This is line 4 with gamma.
+This is line 5 with beta.
+This is line 6 with delta.
+This is line 7 with beta.
diff --git a/trunk/src/etc/testcases/filters/input/replacetokens.test b/trunk/src/etc/testcases/filters/input/replacetokens.test
new file mode 100644
index 0000000..e920887
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/replacetokens.test
@@ -0,0 +1,2 @@
+1@foo@2
+3
diff --git a/trunk/src/etc/testcases/filters/input/sample.properties b/trunk/src/etc/testcases/filters/input/sample.properties
new file mode 100644
index 0000000..572e79d
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/sample.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+foo=
diff --git a/trunk/src/etc/testcases/filters/input/stripjavacomments.test b/trunk/src/etc/testcases/filters/input/stripjavacomments.test
new file mode 100644
index 0000000..37535bc
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/input/stripjavacomments.test
@@ -0,0 +1,30 @@
+/*
+ * Copyright text
+ * has to be removed
+ */
+
+/**
+ * JavaDoc text about the class.
+ * has to be removed
+ */ 
+public class NormalLine {
+
+    private String withComment; // this comment should be removed
+
+    /* this comment
+     * should be
+     * removed
+     */
+    public void doNothing() {
+        // this comment should be removed
+        int i;
+        /* this comment
+           should be removed
+        */
+        int j;
+    }
+
+    private String url = "http://ant.apache.org/"; // very difficult!
+    private String url2 = "\"http://ant.apache.org/\""; // even worse
+
+}
diff --git a/trunk/src/etc/testcases/filters/tokenfilter.xml b/trunk/src/etc/testcases/filters/tokenfilter.xml
new file mode 100644
index 0000000..e7b0b8b
--- /dev/null
+++ b/trunk/src/etc/testcases/filters/tokenfilter.xml
@@ -0,0 +1,359 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <target name="init">
+    <mkdir dir="result" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result"/>
+  </target>
+
+  <target name="tokenfilter">
+    <copy file="input/linecontains.test" tofile="result/file1">
+      <filterchain>
+        <tokenfilter/>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="trimignore">
+    <concat destfile="result/input">
+      Hello
+      
+      World
+    </concat>
+    <copy file="result/input" tofile="result/output" overwrite="yes">
+      <filterchain>
+        <tokenfilter delimoutput="-">
+          <trim/>
+          <ignoreblank/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+    <concat>
+      <filelist dir="." files="result/output"/>
+    </concat>
+  </target>
+
+  <target name="trimfile">
+    <concat destfile="result/trimfile">
+      This is the contents of the trimmed file.
+      This is the second line.
+      <filterchain>
+        <trim byline="no"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="trimfilebyline">
+    <concat destfile="result/trimfilebyline">
+      This is the contents of the trimmed file.
+      This is the second line.
+      <filterchain>
+        <trim/>
+        <tokenfilter delimoutput="\n"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="filterreplacestring">
+    <concat destfile="result/filterreplacestring">
+      This is foo bar
+      <filterchain>
+        <replacestring from="foo" to="the"/>
+        <replacestring from="bar" to="moon"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="filterreplacestrings">
+    <concat>
+      foo foo foo
+      <filterchain>
+        <replacestring from="foo" to="bar"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="stringtokenizer">
+    <concat destfile="result/input">
+      This is a number
+      of words
+    </concat>
+    <copy file="result/input" tofile="result/output" overwrite="yes">
+      <filterchain>
+        <tokenfilter delimoutput="#">
+          <stringtokenizer/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+    <concat>
+      <filelist dir="." files="result/output"/>
+    </concat>
+  </target>
+
+  <target name="unixlineoutput">
+    <concat destfile="result/unixlineoutput">
+      This is a number
+      of words
+      <filterchain>
+        <tokenfilter delimoutput="\n">
+          <stringtokenizer/>
+        </tokenfilter>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="doslineoutput">
+    <concat destfile="result/doslineoutput">
+      This is a number
+      of words
+      <filterchain>
+        <tokenfilter delimoutput="\r\n">
+          <stringtokenizer/>
+        </tokenfilter>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="filetokenizer">
+    <concat destfile="result/input">
+      This is a number
+      of words
+    </concat>
+    <copy file="result/input" tofile="result/filetokenizer">
+      <filterchain>
+        <tokenfilter>
+          <filetokenizer/>
+          <trim/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="replacestring">
+    <concat destfile="result/replacestring">
+      this is the sun
+      <filterchain>
+        <tokenfilter>
+            <replacestring from="sun" to="moon"/>
+        </tokenfilter>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="replacestrings">
+    <concat>
+      foo foo foo
+      <filterchain>
+        <tokenfilter>
+          <replacestring from="foo" to="bar"/>
+        </tokenfilter>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="containsstring">
+    <concat destfile="result/input">
+      this is a line contains foo
+      this line does not
+    </concat>
+    <copy file="result/input" tofile="result/containsstring">
+      <filterchain>
+        <tokenfilter>
+          <containsstring contains="foo"/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <!-- need to check for existance of regex -->
+  <target name="replaceregex">
+    <concat destfile="result/input">
+      hello Hello HELLO hello
+      cat Cat cat
+      Sun Sun Sun
+      WhiteSpace 	tab
+      This is a line with digits - 1234 -- there
+    </concat>
+    <copy file="result/input" tofile="result/replaceregex">
+      <filterchain>
+        <tokenfilter>
+          <replaceregex pattern="hello" replace="world" flags="gi"/>
+          <replaceregex pattern="cat" replace="dog" flags="g"/>
+          <replaceregex pattern="sun" replace="moon" flags="i"/>
+          <replaceregex pattern="WhiteSpace[ \t]+tab"
+                        replace="found WhiteSpace"/>
+          <replaceregex pattern="This is a line with dig.* ([0-9]+).*"
+                        replace="Found digits [\1]"/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="filterreplaceregex">
+    <concat destfile="result/filterreplaceregex">
+      hello Hello HELLO hello
+      <filterchain>
+        <replaceregex pattern="hello" replace="world" flags="gi"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="dollermatch">
+    <concat>
+      @hello@
+      <filterchain>
+        <replaceregex pattern="@([^@]*)@" replace="${\1}"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <!-- need to check for existance of regex -->
+  <target name="containsregex">
+    <concat destfile="result/input">
+      hello world
+      this is the moon
+      World here
+    </concat>
+    <copy file="result/input" tofile="result/containsregex">
+      <filterchain>
+        <tokenfilter>
+          <containsregex pattern="(hello|world)" flags="i"/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="filtercontainsregex">
+    <concat destfile="result/filtercontainsregex">
+      hello world
+      this is the moon
+      World here
+      <filterchain>
+        <tokenfilter>
+          <containsregex pattern="(hello|world)" flags="i"/>
+        </tokenfilter>
+      </filterchain>
+    </concat>
+  </target>
+
+
+  <!-- need to check for existance of regex -->
+  <target name="containsregex2">
+    <concat destfile="result/input">
+      SUITE(TestSuite, bits);
+      here
+    </concat>
+    <copy file="result/input" tofile="result/containsregex2">
+      <filterchain>
+        <tokenfilter>
+          <containsregex
+            pattern="^ *SUITE\(.*,\s*(.*)\s*\).*"
+            replace="void register_\1();"/>
+        </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="deletecharacters">
+    <concat destfile="result/deletechars">
+      This is some ### s
+      some ****
+      <filterchain>
+        <tokenfilter>
+          <deletecharacters chars="#"/>
+        </tokenfilter>
+        <deletecharacters chars="*"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="scriptfilter">
+    <concat destfile="result/input">
+      hello world
+    </concat>
+    <copy file="result/input" tofile="result/scriptfilter">
+      <filterchain>
+        <tokenfilter>
+          <scriptfilter language="javascript">
+            self.setToken(self.getToken().toUpperCase());
+          </scriptfilter>
+       </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="scriptfilter2">
+    <concat destfile="result/input">
+      hello moon
+    </concat>
+    <copy file="result/input" tofile="result/scriptfilter2">
+      <filterchain>
+        <scriptfilter language="javascript">
+          self.setToken(self.getToken().toUpperCase());
+        </scriptfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="customtokenfilter">
+    <path id="test-classes">
+      <pathelement location="../../../../build/testcases" />
+      <pathelement path="${java.class.path}" />
+    </path>
+
+
+    <typedef 
+      name="capitalize" 
+      classname="org.apache.tools.ant.filters.TokenFilterTest$Capitalize">
+      <classpath refid="test-classes"/>
+    </typedef>
+    
+    <concat destfile="result/input">
+      hello world
+    </concat>
+
+    <copy file="result/input" tofile="result/custom">
+      <filterchain>
+        <tokenfilter>
+          <stringtokenizer/>
+          <capitalize/>
+       </tokenfilter>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="hasscript">
+    <script language="javascript">
+      i = 1;
+    </script>
+  </target>
+  
+  <target name="hasregex">
+    <concat destfile="result/replaceregexp">
+      hello world
+    </concat>
+    <replaceregexp file="result/replaceregexp"
+                  match="hello( )world"
+                  replace="bye\1world"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/abstractcvstask.xml b/trunk/src/etc/testcases/taskdefs/abstractcvstask.xml
new file mode 100644
index 0000000..f65bf6e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/abstractcvstask.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="abstractcvstask-test" basedir="../../../../" 
+         default="all">
+
+  <property name="file" value="ant.properties.sample" />
+  <target name="all">
+    <cvs failonerror="true" command="status ${file}"/>
+    <cvs failonerror="true">
+      <commandline>
+        <argument value="up"/>
+        <argument value="-r"/>
+        <argument value="1.1"/>
+        <argument value="${file}"/>
+      </commandline>
+    </cvs>
+    <cvs failonerror="true" command="status ${file}"/>
+    <cvs failonerror="true">
+      <commandline>
+        <argument line="up -r HEAD ${file}" />
+      </commandline>
+    </cvs>
+    <cvs failonerror="true" command="status ${file}"/>
+  </target>
+
+  <target name="package-attribute">
+    <mkdir dir="tmpdir" />
+    <cvs cvsroot=":pserver:anoncvs@cvs.apache.org:/home/cvspublic"
+         package="ant/build.xml"
+         dest="tmpdir"
+         quiet="true" />
+  </target>
+
+  <target name="tag-attribute">
+    <mkdir dir="tmpdir" />
+    <cvs cvsroot=":pserver:anoncvs@cvs.apache.org:/home/cvspublic"
+         package="ant/build.xml"
+         dest="tmpdir"
+         quiet="true"
+         tag="ANT_141" />
+    <cvs cvsroot=":pserver:anoncvs@cvs.apache.org:/home/cvspublic"
+         package="ant/build.xml"
+         dest="tmpdir"
+         command="status"/>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="tmpdir" />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/ant.topleveltest.xml b/trunk/src/etc/testcases/taskdefs/ant.topleveltest.xml
new file mode 100644
index 0000000..65bc729
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/ant.topleveltest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <echo>Hello world</echo>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/ant.xml b/trunk/src/etc/testcases/taskdefs/ant.xml
new file mode 100644
index 0000000..0d2dc4c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/ant.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="ant-test" basedir="." default="test1">
+
+  <path id="inheritable">
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="cleanup">
+    <delete file="test1.log" />
+    <delete file="test2.log" />
+    <delete file="ant/test3.log" />
+    <delete file="ant/test4.log" />
+  </target>
+
+  <target name="all" depends="test1,test2,test3,test4"/>
+
+  <target name="test1">
+    <ant antfile="ant.xml" dir="." target="test1"/>
+  </target>
+
+  <target name="test2">
+    <antcall/>
+  </target>
+
+  <target name="test3">
+    <antcall target="test3"/>
+  </target>
+
+  <target name="test4">
+    <antcall target=""/>
+  </target>
+
+  <target name="test4b">
+    <antcall target="does-not-exist"/>
+  </target>
+
+  <target name="test5">
+    <antcall target="dummy"/>
+  </target>
+
+  <target name="test6">
+    <ant antfile="ant.xml" dir="." target="dummy"/>
+  </target>
+
+  <target name="dummy">
+  </target>
+
+  <target name="inheritBasedir">
+    <ant antfile="ant/ant.xml" target="dummy" inheritAll="true" />
+  </target>
+
+  <target name="doNotInheritBasedir">
+    <ant antfile="ant/ant.xml" target="dummy" inheritAll="false" />
+  </target>
+
+  <target name="explicitBasedir1">
+    <ant antfile="taskdefs/ant/ant.xml" target="dummy" inheritAll="true" 
+         dir=".." />
+  </target>
+
+  <target name="explicitBasedir2">
+    <ant antfile="taskdefs/ant/ant.xml" target="dummy" inheritAll="false" 
+         dir=".." />
+  </target>
+
+  <target name="tripleCall">
+    <ant antfile="ant/ant.xml" target="callback" inheritAll="false" />
+  </target>
+
+  <target name="testInherit">
+    <ant antfile="ant/references.xml" inheritRefs="true" target="dummy" />
+  </target>
+
+  <target name="testNoInherit">
+    <ant antfile="ant/references.xml" inheritRefs="false" target="dummy" />
+  </target>
+
+  <target name="testRename">
+    <ant antfile="ant/references.xml" inheritRefs="false" target="dummy">
+      <reference refid="path" torefid="newpath" />
+    </ant>
+  </target>
+
+  <target name="testInheritPath" description="try to pass a reference to a path, which refers itself to a second path">
+    <property name="rootdir" location="."/>
+    <path id="project.classpath">
+      <pathelement location="../classes"/>
+    </path>
+    <path id="test.classpath">
+      <pathelement location="${rootdir}/test/testframework.jar"/>
+      <path refid="project.classpath"/>
+    </path>
+    <ant antfile="ant/references.xml"  target="testInheritPath">
+      <reference refid="test.classpath"/>
+    </ant>
+  </target>
+
+  <target name="testLogfilePlacement">
+    <ant antfile="ant.xml" target="dummy" output="test1.log"
+         inheritall="false" />
+    <ant antfile="ant.xml" target="dummy" output="test2.log" />
+    <ant antfile="ant.xml" target="dummy" output="test3.log"
+         inheritall="false" dir="ant" />
+    <ant antfile="ant.xml" target="dummy" output="test4.log" 
+         dir="ant" />
+  </target>
+
+  <target name="testRefid">
+    <ant antfile="ant/references.xml" inheritRefs="false" target="dummy">
+      <property name="testprop" refid="inheritable" />
+    </ant>
+  </target>
+
+  <target name="test-property-override-inheritall-start">
+    <property name="test" value="1" />
+    <ant antfile="ant.xml"
+         target="test-property-override-inheritall-level-2"
+         inheritall="true">
+      <property name="test" value="2" />
+    </ant>
+  </target>
+
+  <target name="test-property-override-inheritall-level-2">
+    <property name="test" value="3" />
+    <ant antfile="ant.xml"
+         target="test-property-override-inheritall-level-3"
+         inheritall="true">
+      <property name="test" value="4" />
+    </ant>
+  </target>
+
+  <target name="test-property-override-inheritall-level-3">
+    <property name="test" value="5" />
+    <echo message="The value of test is ${test}" />
+  </target>
+
+  <target name="test-property-override-no-inheritall-start">
+    <property name="test" value="1" />
+    <ant antfile="ant.xml"
+         target="test-property-override-no-inheritall-level-2"
+         inheritall="false">
+      <property name="test" value="2" />
+    </ant>
+  </target>
+
+  <target name="test-property-override-no-inheritall-level-2">
+    <property name="test" value="3" />
+    <ant antfile="ant.xml"
+         target="test-property-override-no-inheritall-level-3"
+         inheritall="false">
+      <property name="test" value="4" />
+    </ant>
+  </target>
+
+  <target name="test-property-override-no-inheritall-level-3">
+    <property name="test" value="5" />
+    <echo message="The value of test is ${test}" />
+  </target>
+
+  <target name="test-propertyset">
+    <property name="test1" value="1"/>
+    <property name="test2" value="2"/>
+    <propertyset id="set">
+      <propertyref name="test1"/>
+      <mapper type="glob" from="*" to="*.x"/>
+    </propertyset>
+    <ant antfile="ant.xml" target="echo-for-propertyset-test" 
+         inheritall="false">
+      <propertyset refid="set"/>
+    </ant>
+  </target>
+
+  <target name="echo-for-propertyset-test">
+    <echo>test1 is ${test1}</echo>
+    <echo>test2 is ${test2}</echo>
+    <echo>test1.x is ${test1.x}</echo>
+  </target>
+
+  <target name="infinite-loop-via-depends">
+    <antcall target="dependent"/>
+  </target>
+
+  <target name="middleman" depends="infinite-loop-via-depends"/>
+  <target name="dependent" depends="middleman"/>
+  
+  <target name="multi-same-property">
+    <ant antfile="ant.xml" target="echo-for-multi-same">
+      <property name="prop" value="one"/>
+      <property name="prop" value="two"/>
+    </ant>
+  </target>
+
+  <target name="echo-for-multi-same">
+    <echo>prop is ${prop}</echo>
+  </target>
+
+  <target name="topleveltarget">
+    <ant antfile="ant.topleveltest.xml"/>
+  </target>
+
+  <target name="multiple-property-file-children">
+    <ant target="dummy" antfile="ant.xml">
+      <property file="foo.properties"/>
+      <property file="bar.properties"/>
+    </ant>
+  </target>
+
+  <target name="blank-target">
+    <ant antfile="ant.topleveltest.xml">
+      <target name="" />
+    </ant>
+  </target>
+
+  <target name="multiple-targets">
+    <ant antfile="ant.xml">
+      <target name="ta" />
+      <target name="tb" />
+      <target name="tc" />
+    </ant>
+  </target>
+
+  <target name="multiple-targets-2">
+    <ant antfile="ant.xml">
+      <target name="tb" />
+      <target name="da" />
+    </ant>
+  </target>
+
+  <target name="ta"><echo>ta</echo></target>
+  <target name="tb" depends="da,dc"><echo>tb</echo></target>
+  <target name="tc" depends="db,dc"><echo>tc</echo></target>
+
+  <target name="da"><echo>da</echo></target>
+  <target name="db"><echo>db</echo></target>
+  <target name="dc"><echo>dc</echo></target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/ant/ant.xml b/trunk/src/etc/testcases/taskdefs/ant/ant.xml
new file mode 100644
index 0000000..52c9a70
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/ant/ant.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="def" basedir=".">
+
+  <target name="def">
+    <fail>This build file should only be run from within the testcase</fail>
+  </target>
+
+  <target name="dummy">
+    <echo message="${basedir}" />
+  </target>
+
+  <target name="callback">
+    <ant antfile="../ant.xml" target="dummy" inheritAll="false" />
+  </target>
+
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/ant/references.xml b/trunk/src/etc/testcases/taskdefs/ant/references.xml
new file mode 100644
index 0000000..0f3a693
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/ant/references.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="def" basedir=".">
+
+  <path id="no-override" />
+
+  <target name="def">
+    <fail>This build file should only be run from within the testcase</fail>
+  </target>
+
+  <target name="dummy" />
+
+  <target name="testInheritPath">
+    <pathconvert refid="test.classpath" pathsep="${line.separator}" property="myprop"/>
+    <echo>${myprop}</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/antlib.current-test.xml b/trunk/src/etc/testcases/taskdefs/antlib.current-test.xml
new file mode 100644
index 0000000..0ad44db
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/antlib.current-test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib xmlns:c="ant:current">
+  <typedef name="echo2" classname="org.apache.tools.ant.taskdefs.Echo"/>
+  <presetdef name="preset.echo">
+    <typedef classname="org.apache.tools.ant.taskdefs.Echo"/>
+  </presetdef>
+  <c:preset.echo name="p"/>
+  <macrodef name="useecho2">
+    <sequential>
+      <c:echo2>Echo2 inside a macro</c:echo2>
+    </sequential>
+  </macrodef>
+</antlib>
diff --git a/trunk/src/etc/testcases/taskdefs/antlib.xml b/trunk/src/etc/testcases/taskdefs/antlib.xml
new file mode 100644
index 0000000..d1c4061
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/antlib.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test">
+
+  <property name="testcases.dir" location="../../../../build/testcases"/>
+
+  <path id="testclasses">
+    <pathelement location="${testcases.dir}" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="antlib.file">
+    <typedef file="test.antlib.xml"
+             classpathref="testclasses"/>
+    <mytask/>
+  </target>
+
+  <target name="antlib.resource">
+    <typedef resource="taskdefs/test.antlib.xml">
+        <classpath>
+            <!-- To load the task classes: -->
+            <path refid="testclasses"/>
+            <!-- For test.antlib.xml: -->
+            <pathelement location=".."/>
+            <!-- For test2.antlib.xml: -->
+            <pathelement location="${testcases.dir}/org/apache/tools/ant/taskdefs/test2-antlib.jar"/>
+        </classpath>
+    </typedef>
+    <mytask/>
+    <echo>-and-then-</echo>
+    <mytask2/>
+  </target>
+
+  <target name="ns.current">
+    <typedef file="antlib.current-test.xml" uri="abc"/>
+    <x:useecho2 xmlns:x="abc"/>
+    <x:preset.echo xmlns:x="abc" name="p"/>
+    <x:p xmlns:x="abc">Hello from x:p</x:p>
+  </target>
+
+  <target name="antlib_uri" >
+    <typedef uri="antlib:org.example.tasks" onerror="failall"/>
+  </target>
+
+  <target name="antlib_uri_auto" xmlns:ex="antlib:org.example.tasks">
+    <ex:simple>
+      <echo message="inside simple" />
+    </ex:simple>
+  </target>
+
+  <target name="antlib_uri_auto2" xmlns:ex="antlib://org/example/tasks/antlib2.xml">
+    <ex:simple>
+      <echo message="inside simple"/>
+    </ex:simple>
+  </target>
+  
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/antstructure.xml b/trunk/src/etc/testcases/taskdefs/antstructure.xml
new file mode 100644
index 0000000..516a973
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/antstructure.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="antstructure-test" basedir="." default="test1">
+
+  <target name="test1">
+    <antstructure/>
+  </target>
+
+  <target name="testCustomPrinter">
+    <typedef name="myprinter"
+             classname="org.apache.tools.ant.taskdefs.AntStructureTest$MyPrinter">
+      <classpath>
+        <pathelement path="${tests-classpath.value}"/>
+      </classpath>
+    </typedef>
+    <antstructure output="foo.dtd">
+      <myprinter/>
+    </antstructure>
+  </target>
+
+  <target name="tearDown">
+    <delete file="foo.dtd" quiet="true"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/apt.xml b/trunk/src/etc/testcases/taskdefs/apt.xml
new file mode 100644
index 0000000..6f59bf0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/apt.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project basedir=".">
+  <!-- apt tests -->
+
+  <property name="build.dir" location="aptbuild" />
+  <property name="classes.dir" location="${build.dir}/classes" />
+  <property name="classes2.dir" location="${build.dir}/classes2" />
+  <property name="preprocess.dir" location="${build.dir}/source" />
+  <property name="src" location="apt" />
+
+  <property name="AptExample.class" location="${classes.dir}/AptExample.class" />
+
+  <macrodef name="assertCompiled">
+    <attribute name="file" />
+    <sequential >
+      <fail  message="not found: @{file}">
+        <condition>
+          <not>
+            <available file="@{file}" />
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <presetdef name="assertAptExampleCompiled">
+    <assertCompiled file="${AptExample.class}"/>
+  </presetdef>
+
+  <target name="clean">
+    <delete dir="${build.dir}"/>
+  </target>
+
+  <target name="init">
+    <mkdir dir="${classes.dir}"/>
+    <mkdir dir="${classes2.dir}"/>
+    <mkdir dir="${preprocess.dir}"/>
+  </target>
+
+  <target name="testApt" depends="init">
+    <apt srcdir="${src}"
+         destdir="${classes.dir}"
+         debug="on"
+         compile="true"
+         preprocessdir="${preprocess.dir}">
+    </apt>
+    <assertAptExampleCompiled />
+  </target>
+
+  <target name="testAptFork" depends="init">
+    <apt srcdir="${src}"
+         destdir="${classes.dir}"
+         debug="on"
+         compile="true"
+         fork="true"
+         preprocessdir="${preprocess.dir}">
+    </apt>
+    <assertAptExampleCompiled />
+  </target>
+
+  <target name="testAptForkFalse" depends="init">
+    <apt srcdir="${src}"
+         destdir="${classes.dir}"
+         debug="on"
+         compile="true"
+         fork="false"
+         preprocessdir="${preprocess.dir}">
+    </apt>
+    <assertAptExampleCompiled />
+  </target>
+
+  <target name="testListAnnotationTypes" depends="init">
+    <apt srcdir="${src}"
+         destdir="${classes.dir}"
+         debug="on"
+         compile="true"
+         preprocessdir="${preprocess.dir}">
+         <compilerarg value="-XListAnnotationTypes" />
+         <compilerarg value="-Xlint:deprecation" /> 
+    </apt>
+  
+    <assertAptExampleCompiled />
+  </target>
+
+
+  <!-- use the factory we compiled. To avoid trouble
+    we deliver into a version in a new classpath, otherwise
+    the dependency logic will not run Apt-->
+  <target name="testAptNewFactory" depends="testApt">
+    <apt srcdir="${src}"
+         destdir="${classes2.dir}"
+         debug="on"
+         compile="true"
+         factory="DistributedAnnotationFactory"
+         preprocessdir="${preprocess.dir}">
+         <factorypath path="${classes.dir}" />
+         <option name="build.dir" value="${build.dir}" />
+    </apt>
+    <assertAptExampleCompiled />
+  </target>
+
+  <target name="testAptNewFactoryFork" depends="testApt">
+    <apt srcdir="${src}"
+         destdir="${classes2.dir}"
+         debug="on"
+         compile="true"
+         fork="true"
+         factory="DistributedAnnotationFactory"
+         preprocessdir="${preprocess.dir}">
+         <factorypath path="${classes.dir}" />
+         <option name="build.dir" value="${build.dir}" />
+    </apt>
+    <assertAptExampleCompiled />
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/apt/AptExample.java b/trunk/src/etc/testcases/taskdefs/apt/AptExample.java
new file mode 100644
index 0000000..9d6fcba
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/apt/AptExample.java
@@ -0,0 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/**
+ */
+@Distributed(
+        protocol="CORBA",
+        distribution=Distributed.DistributionTypes.FEDERATED
+        )
+public class AptExample {
+}
diff --git a/trunk/src/etc/testcases/taskdefs/apt/Distributed.java b/trunk/src/etc/testcases/taskdefs/apt/Distributed.java
new file mode 100644
index 0000000..ebc3467
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/apt/Distributed.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ */
+@Documented
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = ElementType.TYPE)
+public @interface Distributed  {
+
+    public DistributionTypes distribution() default DistributionTypes.LOCAL;
+
+    public String protocol() default "RMI";
+
+    public enum DistributionTypes { SINGLETON, LOCAL, FAULT_TOLERANT, FEDERATED, MOBILE};
+
+
+}
diff --git a/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationFactory.java b/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationFactory.java
new file mode 100644
index 0000000..a8fb633
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationFactory.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+import com.sun.mirror.apt.AnnotationProcessorFactory;
+import com.sun.mirror.apt.AnnotationProcessor;
+import com.sun.mirror.apt.AnnotationProcessorEnvironment;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.Arrays;
+import java.util.Collections;
+
+
+/**
+ * This was the first piece of Java1.5 code in the source tree.
+ * @since 20050-03-09T21:29:25Z
+ */
+public class DistributedAnnotationFactory implements AnnotationProcessorFactory {
+
+    private static final Collection<String> supportedAnnotations
+            = Collections.unmodifiableCollection(Arrays.asList("*"));
+
+    public Collection<String> supportedOptions() {
+        return Collections.emptySet();
+    }
+
+    public Collection<String> supportedAnnotationTypes() {
+        return supportedAnnotations;
+    }
+
+    public AnnotationProcessor getProcessorFor(
+            Set<com.sun.mirror.declaration.AnnotationTypeDeclaration> annotationTypeDeclarations,
+            AnnotationProcessorEnvironment env) {
+        return new DistributedAnnotationProcessor(env);
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationProcessor.java b/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationProcessor.java
new file mode 100644
index 0000000..f94ff7f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/apt/DistributedAnnotationProcessor.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//found in tools.jar, not the JRE runtime.
+import com.sun.mirror.apt.AnnotationProcessor;
+import com.sun.mirror.apt.AnnotationProcessorEnvironment;
+import com.sun.mirror.declaration.TypeDeclaration;
+import com.sun.mirror.declaration.ClassDeclaration;
+import com.sun.mirror.util.SimpleDeclarationVisitor;
+import static com.sun.mirror.util.DeclarationVisitors.*;
+
+import java.util.Map;
+
+/**
+ * Annotation processor outputs stuff
+ */
+
+public class DistributedAnnotationProcessor implements AnnotationProcessor {
+
+    public AnnotationProcessorEnvironment env;
+
+    public DistributedAnnotationProcessor(AnnotationProcessorEnvironment env) {
+        this.env = env;
+    }
+
+    public void echo(String text) {
+        env.getMessager().printNotice(text);
+    }
+
+    public void process() {
+        echo("DistributedAnnotationProcessor-is-go");
+
+        Map<String, String> options=env.getOptions();
+        for(String key:options.keySet()) {
+            echo("Option ["+key+"] = "+options.get(key));
+        }
+
+        //work time
+        for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
+            typeDecl.accept(getDeclarationScanner(new ClassVisitor(),
+                    NO_OP));
+        }
+    }
+
+    private class ClassVisitor extends SimpleDeclarationVisitor {
+        public void visitClassDeclaration(ClassDeclaration d) {
+            echo("visiting "+ d.getQualifiedName());
+        }
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/available.xml b/trunk/src/etc/testcases/taskdefs/available.xml
new file mode 100644
index 0000000..5b2fc4c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/available.xml
@@ -0,0 +1,274 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="available-test" basedir="." default="test1">
+
+  <target name="tearDown">
+    <delete dir="greatgrandparent"/>
+  </target>
+
+  <target name="test1">
+    <available/>
+  </target>
+
+  <target name="test2">
+    <available property="test"/>
+  </target>
+
+  <target name="test3">
+    <available file="test"/>
+  </target>
+
+  <target name="test4">
+    <available property="test" 
+               file="src/etc/testcases/taskdefs/this_file_does_not_exist"/>
+  </target>
+
+  <target name="test5">
+    <available property="test" 
+               file="available.xml"/>
+  </target>
+
+  <target name="test6">
+    <available property="test" 
+               resource="org/apache/tools/ant/taskdefs/this_resource_does_not_exist"/>
+  </target>
+
+  <target name="test7">
+    <available property="test" 
+               resource="org/apache/tools/ant/taskdefs/defaults.properties"/>
+  </target>
+
+  <target name="test8">
+    <available property="test" 
+               classname="org.apache.tools.ant.taskdefs.this_class_does_not_exist"/>
+  </target>
+
+  <target name="test9">
+    <available property="test" 
+               classname="org.apache.tools.ant.taskdefs.Ant"/>
+  </target>
+
+  <target name="test10">
+    <available property="test" 
+               file="available.xml"
+               resource="org/apache/tools/ant/taskdefs/defaults.properties"
+               classname="org.apache.tools.ant.taskdefs.Ant"/>
+  </target>
+  
+  <target name="test11">
+    <available property="test" 
+               file="src/etc/testcases/taskdefs/available.xml"
+               resource="org/apache/tools/ant/taskdefs/defaults.properties"
+               classname="org.apache.tools.ant.taskdefs.this_class_does_not_exist"/>
+  </target>  
+  
+  <target name="test12">
+    <available property="" 
+               file="available.xml"/>
+  </target>
+
+  <target name="test13">
+    <available property="test" 
+               file="" type="file" />
+  </target>
+
+  <target name="test13b">
+    <available property="test" 
+               file=""/>
+  </target>
+
+  <target name="test14">
+    <available property="test" 
+               resource=""/>
+  </target>
+
+  <target name="test15">
+    <available property="test" 
+               classname="org.apache.tools.ant.taskdefs.this_class_does_not_exist"/>
+  </target>
+
+  <target name="test16">
+    <available property="test" 
+               file="" type="dir"/>
+  </target>
+
+  <target name="test17">
+    <available property="test" 
+               file="../taskdefs" type="dir"/>
+  </target>
+
+  <target name="test18">
+    <available property="test" 
+               file="../this_dir_should_never_exist" type="dir"/>
+  </target>
+
+  <target name="test19">
+    <available property="test" 
+               file="available.xml" type="Foo"/>
+  </target>
+
+  <target name="test20">
+    <available property="test" ignoresystemclasses="true"
+               classname="java.awt.Graphics"/>
+  </target>
+
+  <target name="test21">
+    <available property="test" ignoresystemclasses="true"
+               classname="java.awt.Graphics">
+      <classpath>
+        <pathelement location="${java.home}/lib/rt.jar" />
+        <pathelement location="${java.home}/lib/classes.zip" />
+        <pathelement location="${java.home}/lib/graphics.jar" /> <!-- IBM JDK -->
+        <pathelement location="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes/classes.jar" />
+        <pathelement location="/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Classes/ui.jar" />
+      </classpath>
+    </available>
+  </target>
+
+  <target name="test22">
+    <available property="test" ignoresystemclasses="false"
+               classname="java.awt.Graphics"/>
+  </target>
+
+  <target name="test23">
+    <available property="test"
+               classname="java.awt.Graphics"/>
+  </target>
+
+  <target name="test24">
+    <!-- create a dummy file and look for it -->
+    <mkdir dir="${user.dir}/test"/>
+    <echo message="package test;public class test {}" file="${user.dir}/test/test.java"/>
+    <javac srcdir="${user.dir}" includes="test/test.java"/>
+    <jar destfile="${user.dir}/test.jar" basedir="${user.dir}" includes="test/test.class"/>
+    <available property="test"
+               classname="test.test" classpath="${user.dir}/test.jar"/>
+    <delete dir="${user.dir}/test"/>
+    <delete file="${user.dir}/test.jar"/>
+  </target>
+
+  <target name="searchInPathNotThere">
+    <available file="not_there" filepath="..:optional"
+               property="test" />
+  </target>
+
+  <target name="searchInPathIsThere">
+    <available file="pvcs.xml" filepath="..:optional"
+               property="test" />
+  </target>
+
+  <target name="testDoubleBasedir">
+    <echo>testing ${basedir}${file.separator}${ant.file}</echo>
+    <fail>
+      <condition>
+        <available file="${basedir}${file.separator}${ant.file}" />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="prep.parents">
+    <delete quiet="yes" dir="greatgrandparent"/>
+    <mkdir  dir="greatgrandparent/grandparent/parent/dir"/>
+    <touch  file="greatgrandparent/a.txt"/>
+    <touch  file="greatgrandparent/grandparent/b.txt"/>
+    <touch  file="greatgrandparent/grandparent/parent/c.txt"/>
+    <touch  file="greatgrandparent/grandparent/parent/dir/d.txt"/>
+    <property name="available.test.dir"
+              value="greatgrandparent/grandparent/parent/dir"/>
+  </target>
+  <target name="search-parents" depends="prep.parents">
+    <echo>testing greatgrandparent - should see</echo>
+
+    <fail>
+      <condition>
+        <not>
+          <available file="a.txt" searchparents="yes">
+            <filepath path="${available.test.dir}"/>
+          </available>
+        </not>
+      </condition>
+    </fail>
+
+    <echo>testing grandparent - should see</echo>
+    <fail>
+      <condition>
+        <not>
+          <available file="b.txt" searchparents="yes">
+            <filepath path="${available.test.dir}"/>
+          </available>
+        </not>
+      </condition>
+    </fail>
+
+    <echo>testing parent - should see</echo>
+    <fail>
+      <condition>
+        <not>
+          <available file="c.txt" searchparents="yes">
+            <filepath path="${available.test.dir}"/>
+          </available>
+        </not>
+      </condition>
+    </fail>
+
+    <echo>testing dir - should see</echo>
+    <fail>
+      <condition>
+        <not>
+          <available file="d.txt" searchparents="yes">
+            <filepath path="${available.test.dir}"/>
+          </available>
+        </not>
+      </condition>
+    </fail>
+
+  </target>
+
+  <target name="search-parents-not" depends="prep.parents">
+    <echo>testing grandparent - should not see</echo>
+    <fail>
+      <condition>
+        <available file="b.txt">
+          <filepath path="${available.test.dir}"/>
+        </available>
+      </condition>
+    </fail>
+
+    <echo>testing parent - should not see</echo>
+    <fail>
+      <condition>
+        <available file="c.txt">
+          <filepath path="${available.test.dir}"/>
+        </available>
+      </condition>
+    </fail>
+
+    <echo>testing dir - should see</echo>
+    <fail>
+      <condition>
+        <not>
+          <available file="d.txt">
+            <filepath path="${available.test.dir}"/>
+          </available>
+        </not>
+      </condition>
+    </fail>
+
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/bar.properties b/trunk/src/etc/testcases/taskdefs/bar.properties
new file mode 100644
index 0000000..c64b91e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/bar.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+bar=Bar
diff --git a/trunk/src/etc/testcases/taskdefs/basename.xml b/trunk/src/etc/testcases/taskdefs/basename.xml
new file mode 100644
index 0000000..c5fd2ab
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/basename.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <basename/>
+  </target>
+
+  <target name="test2">
+    <basename property="propname"/>
+  </target>
+
+  <target name="test3">
+    <basename file="filename"/>
+  </target>
+
+  <target name="test4">
+    <basename property="file.w.suf" file="${user.dir}/foo.txt"/>
+  </target>
+
+  <target name="test5">
+    <basename property="file.wo.suf" file="foo.txt" suffix="txt"/>
+  </target>
+
+  <target name="testMultipleDots">
+    <basename property="file.wo.suf" file="foo.bar.txt" suffix="txt"/>
+  </target>
+
+  <target name="testNoDots">
+    <basename property="file.wo.suf" file="foo.bartxt" suffix="txt"/>
+  </target>
+  
+  <target name="testValueEqualsSuffixWithDot">
+    <basename property="file.wo.suf" file=".txt" suffix=".txt"/>
+  </target>
+
+  <target name="testValueEqualsSuffixWithoutDot">
+    <basename property="file.wo.suf" file=".txt" suffix="txt"/>
+  </target>
+  
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/bunzip2.xml b/trunk/src/etc/testcases/taskdefs/bunzip2.xml
new file mode 100644
index 0000000..8da474b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/bunzip2.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project basedir="." default="cleanup">
+
+  <target name="realTest">
+    <bunzip2 src="expected/asf-logo-huge.tar.bz2" dest="asf-logo-huge.tar" />
+  </target>
+
+  <target name="realTestWithResource">
+    <bunzip2 dest="asf-logo-huge.tar">
+      <file file="expected/asf-logo-huge.tar.bz2"/>
+    </bunzip2>
+  </target>
+
+  <target name="cleanup">
+    <delete file="asf-logo-huge.tar" />
+    <delete file="expected/asf-logo-huge.tar" />
+  </target>
+
+  <target name="prepare">
+    <gunzip src="expected/asf-logo-huge.tar.gz"/>
+  </target>
+
+  <target name="testDocumentationClaimsOnCopy">
+    <copy todir=".">
+      <bzip2resource>
+        <file file="expected/asf-logo-huge.tar.bz2"/>
+      </bzip2resource>
+      <mapper type="glob" from="*.bz2" to="*"/>
+    </copy>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/bzip2.xml b/trunk/src/etc/testcases/taskdefs/bzip2.xml
new file mode 100644
index 0000000..1e7fe8f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/bzip2.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project basedir="." default="cleanup">
+
+  <target name="realTest">
+    <bzip2 src="expected/asf-logo-huge.tar" zipfile="asf-logo-huge.tar.bz2" />
+  </target>
+
+  <target name="realTestWithResource">
+    <bzip2 zipfile="asf-logo-huge.tar.bz2">
+      <file file="expected/asf-logo-huge.tar"/>
+    </bzip2>
+  </target>
+
+  <target name="testDateCheck">
+    <touch file="asf-logo.gif.bz2"/>
+    <bzip2 src="../asf-logo.gif" zipfile="asf-logo.gif.bz2" />
+  </target>
+
+  <target name="cleanup">
+    <delete file="asf-logo-huge.tar.bz2" />
+    <delete file="asf-logo.gif.bz2" />
+    <delete file="expected/asf-logo-huge.tar"/>
+  </target>
+
+  <target name="prepare">
+    <gunzip src="expected/asf-logo-huge.tar.gz"/>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/calltarget.xml b/trunk/src/etc/testcases/taskdefs/calltarget.xml
new file mode 100644
index 0000000..3ea76a1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/calltarget.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name ="calltarget-test" default="testinheritreffileset" basedir=".">
+    <property name="tmp.dir" value="tmp.dir" />
+    <target name="setup">
+        <mkdir dir="${tmp.dir}"/>
+    </target>
+    <target name="cleanup">
+        <delete dir="${tmp.dir}" quiet="true"/>
+    </target>
+    <target name="mytarget">
+      <pathconvert property="myproperty" targetos="unix" refid="myfileset"/>
+      <echo message="myproperty=${myproperty}"/>
+    </target>
+    <target name="testinheritreffileset">
+    <!-- this testcase should show that the fileset defined here
+    can be read in the called target -->
+      <fileset dir="." id="myfileset">
+        <include name="calltarget.xml"/>
+      </fileset>
+      <antcall target="mytarget" inheritrefs="true"/>
+    </target>
+    <target name="copytest2">
+       <copy file="${tmp.dir}/copytest.in" toFile="${tmp.dir}/copytest1.out" overwrite="true">
+          <filterset refid="foo"/>
+       </copy>
+    </target>
+    <target name="testinheritreffilterset" depends="setup">
+       <echo file="${tmp.dir}/copytest.in">@@foo@@</echo>
+       <filterset id="foo" begintoken="@@" endtoken="@@">
+          <filter token="foo" value="bar"/>
+       </filterset>
+       <antcall target="copytest2" inheritrefs="true"/>
+       <copy file="${tmp.dir}/copytest.in" toFile="${tmp.dir}/copytest2.out" overwrite="true">
+          <filterset refid="foo"/>
+       </copy>
+       <loadfile srcFile="${tmp.dir}/copytest2.out" property="copytest2"/>
+       <loadfile srcFile="${tmp.dir}/copytest1.out" property="copytest1"/>
+       <condition property="success">
+           <equals arg1="${copytest1}" arg2="${copytest2}"/>
+       </condition>
+       <fail message="filterset not properly passed across by antcall" unless="success"/>
+    </target>
+
+    <property name="multi" value="DEFAULT"/>
+    <target name="multi">
+        <echo>multi is ${multi}</echo>
+    </target>
+    <target name="call-multi">
+        <antcall target="multi">
+            <param name="multi" value="SET"/>
+        </antcall>
+    </target>
+
+    <target name="blank-target">
+        <antcall>
+            <target name="" />
+        </antcall>
+    </target>
+
+    <target name="multiple-targets">
+        <antcall>
+            <target name="ta" />
+            <target name="tb" />
+            <target name="tc" />
+        </antcall>
+    </target>
+
+    <target name="multiple-targets-2">
+      <ant antfile="ant.xml">
+        <target name="tb" />
+        <target name="da" />
+      </ant>
+    </target>
+
+    <target name="ta"><echo>ta</echo></target>
+    <target name="tb" depends="da,dc"><echo>tb</echo></target>
+    <target name="tc" depends="db,dc"><echo>tc</echo></target>
+
+    <target name="da"><echo>da</echo></target>
+    <target name="db"><echo>db</echo></target>
+    <target name="dc"><echo>dc</echo></target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/checksum.xml b/trunk/src/etc/testcases/taskdefs/checksum.xml
new file mode 100644
index 0000000..e82fb69
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/checksum.xml
@@ -0,0 +1,266 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <macrodef name="compare">
+    <attribute name="expected" />
+    <attribute name="output" />
+    <sequential>
+      <loadfile property="expected" srcfile="@{expected}">
+        <filterchain><striplinebreaks /></filterchain>
+      </loadfile>
+      <loadfile property="output" srcfile="@{output}">
+        <filterchain><striplinebreaks /></filterchain>
+      </loadfile>
+      <fail message="${output} not = ${expected}">
+        <condition>
+          <not>
+            <equals arg1="${output}" arg2="${expected}" />
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="testverify">
+    <attribute name="checknologo" default="false" />
+    <element name="stuff" implicit="true" />
+    <sequential>
+      <fail>
+        <condition>
+          <or>
+            <isset property="logo.MD5" />
+            <isset property="no.logo.MD5" />
+          </or>
+        </condition>
+      </fail>
+      <stuff />
+      <fail>
+        <condition>
+          <not>
+            <istrue value="${logo.MD5}" /> 
+          </not>
+        </condition>
+      </fail>
+      <fail>
+        <condition>
+          <and>
+            <istrue value="@{checknologo}" />
+            <not>
+              <isfalse value="${no.logo.MD5}" />
+            </not>
+          </and>
+        </condition>
+      </fail>
+      <fail>
+        <condition>
+          <and>
+            <isfalse value="@{checknologo}" />
+            <isset property="no.logo.MD5" />
+          </and>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="cleanup">
+    <delete file="../asf-logo.gif.MD5" />
+    <delete file="../asf-logo.gif.md5" />
+    <delete file="../asf-logo.gif.MD5SUM" />
+    <delete file="../asf-logo.gif.md5sum" />
+    <delete file="../asf-logo.gif.SVF" />
+    <delete file="../asf-logo.gif.svf" />
+    <delete file="../asf-logo.gif.pattern" />
+    <delete file="../asf-logo.gif.PATTERN" />
+    <delete>
+      <fileset dir="checksum">
+        <include name="**/*.MD5"/>
+      </fileset>
+    </delete>
+    <delete dir="checksum/checksums" />
+  </target>
+
+  <target name="createMd5">
+    <checksum file="../asf-logo.gif" fileext=".MD5" />
+    <compare expected="expected/asf-logo.gif.md5" output="../asf-logo.gif.MD5" />
+  </target>
+
+  <target name="createMD5SUMformat">
+    <checksum file="../asf-logo.gif" format="MD5SUM" fileext=".MD5SUM" />
+    <compare expected="expected/asf-logo.gif.md5sum" output="../asf-logo.gif.MD5SUM" />
+  </target>
+
+  <target name="createSVFformat">
+    <checksum file="../asf-logo.gif" format="SVF" fileext=".SVF" />
+    <compare expected="expected/asf-logo.gif.svf" output="../asf-logo.gif.SVF" />
+  </target>
+
+  <target name="createPattern">
+    <checksum file="../asf-logo.gif" pattern="foo{0}bar" fileext=".PATTERN" />
+    <compare expected="expected/asf-logo.gif.pattern" output="../asf-logo.gif.PATTERN" />
+  </target>
+
+  <target name="setProperty">
+    <checksum file="../asf-logo.gif" property="logo.MD5" />
+    <fail>
+      <condition>
+        <or>
+          <not>
+            <equals arg1="0541d3df42520911f268abc730f3afe0"
+                    arg2="${logo.MD5}" />
+          </not>
+          <available file="../asf-logo.gif.MD5" />
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="verifyAsTask">
+    <testverify checknologo="true">
+      <copy file="expected/asf-logo.gif.md5" todir=".." />
+      <checksum file="../asf-logo.gif" fileext=".md5"
+                verifyproperty="logo.MD5" />
+
+      <copy file="checksum.xml" tofile="../asf-logo.gif.MD5"
+            overwrite="true" />
+      <checksum file="../asf-logo.gif" fileext=".MD5"
+                verifyproperty="no.logo.MD5" />
+    </testverify>
+  </target>
+
+  <target name="verifyMD5SUMAsTask">
+    <testverify checknologo="true">
+      <copy file="expected/asf-logo.gif.md5sum" todir=".." />
+      <checksum file="../asf-logo.gif" fileext=".md5sum"
+                verifyproperty="logo.MD5" format="MD5SUM"/>
+
+      <copy file="checksum.xml" tofile="../asf-logo.gif.MD5SUM"
+            overwrite="true" />
+      <checksum file="../asf-logo.gif" fileext=".MD5SUM"
+                verifyproperty="no.logo.MD5" format="MD5SUM"/>
+    </testverify>
+  </target>
+
+  <target name="verifyAsCondition">
+    <testverify>
+      <copy file="expected/asf-logo.gif.md5" todir=".." />
+      <condition property="logo.MD5">
+        <checksum file="../asf-logo.gif" fileext=".md5" />
+      </condition>
+
+      <copy file="checksum.xml" tofile="../asf-logo.gif.MD5"
+            overwrite="true" />
+      <condition property="no.logo.MD5">
+        <checksum file="../asf-logo.gif" fileext=".MD5" />
+      </condition>
+    </testverify>
+  </target>
+
+  <target name="verifyFromProperty">
+    <fail>
+      <condition>
+        <isset property="verify" />
+      </condition>
+    </fail>
+    <checksum property="checksum" file="checksum.xml"/>
+    <checksum property="${checksum}" file="checksum.xml"
+              verifyproperty="verify"/>
+    <fail>
+      <condition>
+        <not>
+          <istrue value="${verify}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="verifyTotal">
+    <checksum totalproperty="total">
+      <fileset dir="${basedir}/checksum">
+        <exclude name="**/*.MD5"/>
+      </fileset>
+    </checksum>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="ef8f1477fcc9bf93832c1a74f629c626" arg2="${total}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="verifyTotalRC">
+    <checksum totalproperty="total">
+      <resources>
+        <fileset dir="${basedir}/checksum">
+          <exclude name="**/*.MD5"/>
+        </fileset>
+      </resources>
+    </checksum>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="ef8f1477fcc9bf93832c1a74f629c626" arg2="${total}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="verifyChecksumdir">
+    <checksum totalproperty="total" todir="${basedir}/checksum/checksums">
+      <fileset dir="${basedir}/checksum">
+        <exclude name="**/*.MD5"/>
+      </fileset>
+    </checksum>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="ef8f1477fcc9bf93832c1a74f629c626" arg2="${total}" />
+        </not>
+      </condition>
+    </fail>
+    <pathconvert property="srcdirfile">
+      <file file="checksum/foo/zap/Eenie.MD5" />
+    </pathconvert>
+    <pathconvert property="destdirfile">
+      <file file="checksum/checksums/foo/zap/Eenie.MD5" />
+    </pathconvert>
+    <fail message="Checksums should be written to ${destdirfile}">
+      <condition>
+        <not>
+          <available file="${destdirfile}" />
+        </not>
+      </condition>
+    </fail>
+    <fail message="Checksums should not be written to ${srcdirfile}">
+      <condition>
+        <available file="${srcdirfile}" />
+      </condition>
+    </fail>
+  </target>
+
+  <!-- bug report 25606 -->
+  <target name="verifyChecksumdirNoTotal">
+    <checksum todir="${basedir}/checksum/checksums">
+      <fileset dir="${basedir}/checksum">
+        <exclude name="**/*.MD5"/>
+      </fileset>
+    </checksum>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/checksum/foo/Bar b/trunk/src/etc/testcases/taskdefs/checksum/foo/Bar
new file mode 100755
index 0000000..c2bc8ee
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/checksum/foo/Bar
@@ -0,0 +1 @@
+Barbapapa
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/checksum/foo/zap/Eenie b/trunk/src/etc/testcases/taskdefs/checksum/foo/zap/Eenie
new file mode 100755
index 0000000..d689175
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/checksum/foo/zap/Eenie
@@ -0,0 +1 @@
+Meenie Minie Moe
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/classloader.xml b/trunk/src/etc/testcases/taskdefs/classloader.xml
new file mode 100644
index 0000000..02e47ab
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/classloader.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="classloader-test" default="main" basedir=".">
+
+  <target name="init">
+
+    <path id="myJars" >
+      <!-- both ant-junit.jar and junit.jar must be loaded from the same path -->
+      <pathelement path="${ant.home}/lib/ant-junit.jar" />
+      <pathelement path="${junit.jar}" />
+    </path>
+
+    <classloader classpathRef="myJars" 
+                 reverse="true" >
+      
+    </classloader>
+    <junit />
+  
+  </target>
+
+  <target name="main" depends="init">
+    <echo message="Found JUNIT" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/concat-input/A b/trunk/src/etc/testcases/taskdefs/concat-input/A
new file mode 100644
index 0000000..2e65efe
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/concat-input/A
@@ -0,0 +1 @@
+a
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/concat-input/B b/trunk/src/etc/testcases/taskdefs/concat-input/B
new file mode 100644
index 0000000..63d8dbd
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/concat-input/B
@@ -0,0 +1 @@
+b
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/concat.xml b/trunk/src/etc/testcases/taskdefs/concat.xml
new file mode 100644
index 0000000..c7f4e0b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/concat.xml
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="concat-test" basedir="." default="test1">
+
+  <property name="tmp.file" value="concat.tmp" />
+  <property name="tmp.file.2" value="concat.tmp.2" />
+
+  <property name="world" value="World" />
+
+  <target name="cleanup">
+    <delete file="TESTDEST"/>
+    <delete file="${tmp.file}"/>
+    <delete file="${tmp.file.2}"/>
+    <delete file="concat.line4"/>
+    <delete file="concat.noeol"/>
+    <delete file="concat.linecr"/>
+    <delete file="concat.utf8"/>
+    <delete file="concat.urls"/>
+  </target>
+
+  <target name="test1">
+    <concat>
+    </concat>
+  </target>
+
+  <target name="test2">
+    <concat destfile="">Hello, ${world}!</concat>
+  </target>
+
+  <target name="test3">
+    <concat destfile="${tmp.file}">Hello, ${world}!</concat>
+  </target>
+
+  <target name="test4">
+    <concat destfile="${tmp.file.2}">
+      <fileset dir="${basedir}" includes="${tmp.file}" />
+      <filelist dir="${basedir}" files="${tmp.file},${tmp.file}" />
+    </concat>
+  </target>
+
+  <target name="test5">
+    <concat>Hello, ${world}!</concat>
+  </target>
+
+  <target name="test6">
+    <concat destfile="TESTDEST" append="true">
+      <filelist dir="${basedir}" files="thisfiledoesnotexist"/>
+    </concat>
+    <available file="TESTDEST" property="TESTDEST.was.created"/>
+    <fail message="TESTDEST created for nonexistant files"
+          if="TESTDEST.was.created"/>
+  </target>
+
+  <target name="testConcatNoNewline">
+    <concat>
+      <fileset dir="concat-input"/>
+    </concat>
+  </target>
+
+  <target name="testConcatNoNewlineEncoding">
+    <concat encoding="ASCII">
+      <fileset dir="concat-input"/>
+    </concat>
+  </target>
+
+  <target name="testPath">
+    <concat destfile="${tmp.file.2}">
+      <path path="${tmp.file}"/>
+    </concat>
+  </target>
+
+  <target name="testAppend">
+    <concat destfile="${tmp.file.2}">
+      <path path="${tmp.file}"/>
+    </concat>
+    <concat destfile="${tmp.file.2}" append="true">
+      <path path="${tmp.file}"/>
+    </concat>
+  </target>
+
+  <target name="testfilter">
+    <concat destfile="${tmp.file}">@REPLACEME@</concat>
+    <concat>
+      <path path="${tmp.file}"/>
+      <filterchain>
+        <replacetokens>
+          <token key="REPLACEME" value="REPLACED"/>
+        </replacetokens>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="testnooverwrite">
+    <touch file="${tmp.file.2}"/>
+    <!-- concat.xml is now older than tmp.file.2
+         so the following should not do anything -->
+    <concat destfile="${tmp.file.2}" force="false">
+      <path path="concat.xml"/>
+    </concat>
+  </target>
+
+  <target name="testheaderfooter">
+    <concat>
+      <header filtering="false" trim="yes">
+        header
+      </header>
+      <path path="${tmp.file}"/>
+      <footer filtering="no">footer</footer>
+    </concat>
+  </target>
+
+  <target name="testfileheader">
+    <concat>
+      <header file="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+    </concat>
+  </target>
+
+  <target name="samefile">
+    <touch file="${tmp.file}"/>
+    <concat destfile="${tmp.file}">
+      <path path="${tmp.file}"/>
+    </concat>
+  </target>
+
+  <target name="testfilterinline">
+    <concat>
+      @REPLACEME@
+      <filterchain>
+        <replacetokens>
+          <token key="REPLACEME" value="REPLACED"/>
+        </replacetokens>
+      </filterchain>
+    </concat>
+  </target>
+  
+  <target name="testmultireader">
+    <concat destfile="${tmp.file}">Hello, World
+    </concat>
+    <concat destfile="${tmp.file.2}">Bye, World
+    </concat>
+    <concat>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <path path="${tmp.file}"/>
+      <!-- tailfilter seems to behave a little stange, place two
+           here in case the implementation changes -->
+      <path path="${tmp.file.2}"/>
+      <path path="${tmp.file.2}"/>
+      <filterchain>
+        <tailfilter lines="2"/>
+      </filterchain>
+    </concat>
+  </target>
+  
+  <target name="create-noel">
+    <concat destfile="concat.noeol">This has no end of line</concat>
+  </target>
+
+  <target name="testfixlastline" depends="create-noel">
+    <concat destfile="concat.line4" fixlastline="yes">
+      <path path="concat.noeol"/>
+      <path path="concat.noeol"/>
+      <path path="concat.noeol"/>
+      <path path="concat.noeol"/>
+    </concat>
+  </target>
+
+  <target name="testfixlastlineeol" depends="create-noel">
+    <concat destfile="concat.linecr" fixlastline="yes" eol="mac">
+      <path path="concat.noeol"/>
+      <path path="concat.noeol"/>
+    </concat>
+  </target>
+
+  <target name="testTranscoding">
+    <concat destfile="concat.utf8"
+            encoding="ISO8859_1" outputencoding="UTF8">
+      <path path="copy/input/iso8859-1"/>
+    </concat>
+  </target>
+
+  <target name="testResources" unless="offline">
+    <concat destfile="concat.urls" binary="true">
+      <url url="http://ant.apache.org" />
+      <url url="http://ant.apache.org" />
+    </concat>
+    <length property="expected">
+      <resources>
+        <url url="http://ant.apache.org" />
+        <url url="http://ant.apache.org" />
+      </resources>
+    </length>
+    <length property="actual">
+      <fileset file="concat.urls" />
+    </length>
+    <fail>
+      <condition>
+        <or>
+          <equals arg1="${actual}" arg2="0" />
+          <not>
+            <equals arg1="${actual}" arg2="${expected}" />
+          </not>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/condition.xml b/trunk/src/etc/testcases/taskdefs/condition.xml
new file mode 100644
index 0000000..81660ae
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/condition.xml
@@ -0,0 +1,521 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- test conditioning -->
+<project name="condition-test" basedir="." default="test1">
+
+  <target name="basic">
+    <condition property="basic">
+      <equals arg1="a" arg2="a" />
+    </condition>
+    <echo>${basic}</echo>
+  </target>
+
+  <target name="condition-incomplete">
+    <condition >
+      <equals arg1="a" arg2="a" />
+    </condition>
+  </target>
+
+  <target name="condition-empty">
+    <condition property="condition-empty"/>
+    <echo>${condition-empty}</echo>
+  </target>
+
+  <target name="shortcut">
+    <property name="shortcut" value="set"/>
+    <condition property="shortcut">
+      <equals arg1="a" arg2="a" />
+    </condition>
+    <echo>${shortcut}</echo>
+  </target>
+
+  <target name="dontset">
+    <condition property="dontset">
+      <equals arg1="a" arg2="b" />
+    </condition>
+    <echo>${dontset}</echo>
+  </target>
+
+  <target name="setvalue">
+    <condition property="setvalue" value="woowoo" >
+      <equals arg1="a" arg2="a" />
+    </condition>
+    <echo>${setvalue}</echo>
+  </target>
+
+  <target name="negation">
+    <condition property="negation">
+      <not>
+        <equals arg1="a" arg2="B" />
+      </not>
+    </condition>
+    <echo>${negation}</echo>
+  </target>
+
+  <target name="negationfalse">
+    <condition property="negationfalse">
+      <not>
+        <equals arg1="a" arg2="a" />
+      </not>
+    </condition>
+    <echo>${negationfalse}</echo>
+  </target>
+
+  <target name="negationincomplete">
+    <condition property="negationincomplete">
+      <not />
+    </condition>
+    <echo>${negationincomplete}</echo>
+  </target>
+
+  <target name="and">
+    <condition property="and">
+      <and>
+        <equals arg1="a" arg2="a" />
+        <equals arg1="B" arg2="B" />
+      </and>
+    </condition>
+    <echo>${and}</echo>
+  </target>
+
+  <target name="andfails">
+    <condition property="andfails">
+      <and>
+        <equals arg1="a" arg2="B" />
+        <equals arg1="B" arg2="a" />
+      </and>
+    </condition>
+    <echo>${andfails}</echo>
+  </target>
+
+  <target name="andincomplete">
+    <condition property="andincomplete">
+      <and>
+        <equals arg1="a" arg2="B" />
+      </and>
+    </condition>
+    <echo>${andincomplete}</echo>
+  </target>
+
+  <target name="andempty">
+    <condition property="andempty">
+      <and/>
+    </condition>
+    <echo>${andempty}</echo>
+  </target>
+
+  <target name="or">
+    <condition property="or">
+      <or>
+        <equals arg1="a" arg2="B" />
+        <equals arg1="B" arg2="B" />
+      </or>
+    </condition>
+    <echo>${or}</echo>
+  </target>
+
+  <target name="orincomplete">
+    <condition property="orincomplete">
+      <or>
+        <equals arg1="a" arg2="a" />
+      </or>
+    </condition>
+    <echo>${orincomplete}</echo>
+  </target>
+
+  <target name="orempty">
+    <condition property="orempty">
+      <or/>
+    </condition>
+    <echo>${orempty}</echo>
+  </target>
+
+  <target name="orfails">
+    <condition property="orfails">
+      <or>
+        <equals arg1="a" arg2="B" />
+        <equals arg1="B" arg2="a" />
+      </or>
+    </condition>
+    <echo>${orfails}</echo>
+  </target>
+
+  <target name="orboth">
+    <condition property="orboth">
+      <or>
+        <equals arg1="a" arg2="a" />
+        <equals arg1="B" arg2="B" />
+      </or>
+    </condition>
+    <echo>${orboth}</echo>
+  </target>
+
+  <target name="filesmatch-identical" >
+    <condition property="filesmatch-identical">
+        <filesmatch
+          file1="condition.xml"
+          file2="condition.xml" />
+    </condition>
+    <echo>${filesmatch-identical}</echo>
+  </target>
+
+  <target name="filesmatch-incomplete" >
+    <condition property="filesmatch-incomplete">
+        <filesmatch
+          file1="condition.xml"/>
+    </condition>
+    <echo>${filesmatch-incomplete}</echo>
+  </target>
+
+  <target name="filesmatch-oddsizes" >
+    <condition property="filesmatch-oddsizes">
+        <filesmatch
+          file1="condition.xml"
+          file2="property.xml" />
+    </condition>
+    <echo>${filesmatch-oddsizes}</echo>
+  </target>
+
+  <target name="filesmatch-existence" >
+    <condition property="filesmatch-existence">
+      <filesmatch
+        file1="condition.xml"
+        file2="this-file-doesnt-exist.xml" />
+    </condition>
+    <echo>${filesmatch-existence}</echo>
+  </target>
+
+  <target name="filesmatch-neitherexist">
+    <fail>
+      <condition>
+        <not>
+          <filesmatch file1="idonotexist" file2="andneitherdoi" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="filesmatch-different">
+    <echo file="match1.txt" message="012345676890" />
+    <echo file="match2.txt" message="012345676889" />
+    <condition property="filesmatch-different">
+      <filesmatch
+        file1="match1.txt"
+        file2="match2.txt" />
+    </condition>
+    <echo>${filesmatch-different}</echo>
+  </target>
+
+  <target name="filesmatch-match" >
+    <echo file="match3.txt" message="012345676890" />
+    <echo file="match4.txt" message="012345676890" />
+    <condition property="filesmatch-match">
+      <filesmatch
+        file1="match3.txt"
+        file2="match4.txt" />
+    </condition>
+    <echo>${filesmatch-match}</echo>
+  </target>
+
+  <target name="filesmatch-different-eol" >
+    <echo file="match7.txt" message="012345676890" />
+    <echo file="match8.txt" message="012345676890" />
+    <fixcrlf file="match7.txt" eol="cr" fixlast="true" />
+    <fixcrlf file="match8.txt" eol="lf" fixlast="true" />
+    <fail>
+      <condition>
+        <filesmatch file1="match7.txt" file2="match8.txt" />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="filesmatch-same-eol" >
+    <echo file="match9.txt" message="012345676890" />
+    <echo file="match10.txt" message="012345676890" />
+    <fixcrlf file="match9.txt" eol="crlf" fixlast="true" />
+    <fixcrlf file="match10.txt" eol="lf" fixlast="true" />
+    <fail>
+      <condition>
+        <not>
+          <filesmatch file1="match9.txt" file2="match10.txt" textfile="true" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="filesmatch-different-sizes">
+    <echo file="match5.txt" message="012345676890" />
+    <echo file="match6.txt" message="0123456768" />
+    <condition property="filesmatch-different-sizes">
+      <filesmatch
+        file1="match5.txt"
+        file2="match6.txt" />
+    </condition>
+    <echo>${filesmatch-different-sizes}</echo>
+  </target>
+
+  <target name="filesmatch-different-onemissing">
+    <condition property="filesmatch-different-sizes">
+      <filesmatch
+        file1="condition.xml"
+        file2="missing-file.txt" />
+    </condition>
+    <echo>${filesmatch-different-onemissing}</echo>
+  </target>
+
+  <target name="contains" >
+    <condition property="contains">
+      <contains
+        string="abcd"
+        substring="cd" />
+    </condition>
+    <echo>${contains}</echo>
+  </target>
+
+  <target name="contains-doesnt" >
+    <condition property="contains-doesnt">
+      <contains
+        string="abcd"
+        substring="CD" />
+    </condition>
+    <echo>${contains-doesnt}</echo>
+  </target>
+
+  <target name="contains-anycase" >
+    <condition property="contains-anycase">
+      <contains casesensitive="false"
+        string="abcd"
+        substring="CD" />
+    </condition>
+    <echo>${contains-anycase}</echo>
+  </target>
+
+  <target name="contains-incomplete1" >
+    <condition property="contains-incomplete1">
+      <contains
+        string="abcd" />
+    </condition>
+    <echo>${contains-incomplete1}</echo>
+  </target>
+
+  <target name="contains-incomplete2" >
+    <condition property="contains-incomplete2">
+      <contains
+        substring="CD" />
+    </condition>
+    <echo>${contains-incomplete2}</echo>
+  </target>
+
+  <target name="istrue" >
+    <property name="t" value="true" />
+    <property name="o" value="o" />
+    <property name="n" value="n" />
+    <condition property="istrue">
+      <and>
+        <istrue value="${t}" />
+        <istrue value="TRUE" />
+        <istrue value="yes" />
+        <istrue value="YeS" />
+        <istrue value="on" />
+        <istrue value="${o}${n}" />
+      </and>
+    </condition>
+    <echo>${istrue}</echo>
+  </target>
+
+  <target name="istrue-not" >
+    <condition property="istrue-not">
+      <istrue
+        value="this sentence is true" />
+    </condition>
+    <echo>${istrue-not}</echo>
+  </target>
+
+  <target name="istrue-false" >
+    <condition property="istrue-false">
+      <or>
+        <istrue value="false" />
+        <istrue value="" />
+      </or>
+    </condition>
+    <echo>${istrue-false}</echo>
+  </target>
+
+  <target name="istrue-incomplete" >
+    <condition property="istrue-incomplete">
+      <istrue />
+    </condition>
+    <echo>${istrue-incomplete}</echo>
+  </target>
+
+  <target name="isfalse-true" >
+    <property name="t" value="true" />
+    <condition property="isfalse-true">
+      <isfalse
+        value="${t}" />
+    </condition>
+    <echo>${isfalse-true}</echo>
+  </target>
+
+  <target name="isfalse-not" >
+    <condition property="isfalse-not">
+      <isfalse
+        value="this sentence is true" />
+    </condition>
+    <echo>${isfalse-not}</echo>
+  </target>
+
+  <target name="isfalse-false" >
+    <condition property="isfalse-false">
+      <isfalse
+        value="false" />
+    </condition>
+    <echo>${isfalse-false}</echo>
+  </target>
+
+  <target name="isfalse-incomplete" >
+    <condition property="isfalse-incomplete">
+      <isfalse />
+    </condition>
+    <echo>${isfalse-incomplete}</echo>
+  </target>
+
+  <target name="testElse">
+    <condition property="unset" value="foo">
+      <or />
+    </condition>
+    <condition property="value" value="foo" else="bar">
+      <and />
+    </condition>
+    <condition property="else" value="foo" else="bar">
+      <or />
+    </condition>
+    <fail>
+      <condition>
+        <or>
+          <isset property="unset" />
+          <not>
+            <and>
+              <equals arg1="${value}" arg2="foo" />
+              <equals arg1="${else}" arg2="bar" />
+            </and>
+          </not>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="resourcesmatch-error">
+    <condition property="errorexpected">
+      <resourcesmatch />
+    </condition>
+  </target>
+
+  <target name="resourcesmatch-match-empty">
+    <condition property="errorexpected">
+      <resourcesmatch>
+        <resources />
+      </resourcesmatch>
+    </condition>
+  </target>
+
+  <target name="resourcesmatch-match-one">
+    <condition property="errorexpected">
+      <resourcesmatch>
+        <string value="foo" />
+      </resourcesmatch>
+    </condition>
+  </target>
+
+  <target name="resourcesmatch-match-binary">
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch>
+            <string value="foo" />
+            <string value="foo" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="resourcesmatch-match-multiple-binary">
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch>
+            <string value="foo" />
+            <string value="foo" />
+            <string value="foo" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="resourcesmatch-differ">
+    <echo file="match11.txt" message="foo" />
+    <fixcrlf file="match11.txt" eol="crlf" fixlast="true" />
+    <fail>
+      <condition>
+        <resourcesmatch>
+          <file file="match11.txt" />
+          <string value="foo" />
+        </resourcesmatch>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="resourcesmatch-match-text">
+    <echo file="match11.txt" message="foo" />
+    <fixcrlf file="match11.txt" eol="crlf" />
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch astext="true">
+            <file file="match11.txt" />
+            <string value="foo" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="resourcesmatch-noneexist">
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch>
+            <resource name="foo" exists="false" />
+            <resource name="bar" exists="false" />
+            <resource name="baz" exists="false" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="cleanup" >
+    <delete>
+      <fileset dir="." includes="match?.txt,match??.txt" />
+    </delete>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/antversion.xml b/trunk/src/etc/testcases/taskdefs/conditions/antversion.xml
new file mode 100644
index 0000000..1a06c7e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/antversion.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="testantversion" default="testatleast">

+

+	<target name="testatleast">

+		<fail>

+			<condition>

+				<not>

+					<antversion atleast="1.7" />

+				</not>

+			</condition>

+      		Should be at least 1.7

+    	</fail>

+	</target>

+

+	<target name="testexactly">

+		<fail>

+			<condition>

+				<not>

+					<antversion exactly="1.8.0" />

+				</not>

+			</condition>

+			Should be exactly 1.8.0

+

+  		</fail>

+	</target>

+

+	<target name="testatleastfail">

+		<property name="version" value="1.8.9" />

+		<fail>

+			<condition>

+				<not>

+					<antversion atleast="1.9.0" />

+				</not>

+			</condition>

+  	  	Should be at least 1.9.0

+  		</fail>

+	</target>

+

+	<target name="testexactlyfail">

+		<property name="version" value="1.8.0" />

+		<fail>

+			<condition>

+				<not>

+					<antversion exactly="1.9.0" />

+				</not>

+			</condition>

+	  	  Should be exactly 1.9.0

+	  	</fail>

+	</target>

+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/isfailure.xml b/trunk/src/etc/testcases/taskdefs/conditions/isfailure.xml
new file mode 100644
index 0000000..b5d1a6a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/isfailure.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="testisfailure">
+
+  <target name="testisfailure">
+    <fail>
+      <condition>
+        <or>
+          <and>
+            <os family="openvms" />
+            <or>
+              <isfailure code="1" />
+              <isfailure code="3" />
+              <isfailure code="5" />
+              <isfailure code="7" />
+              <isfailure code="9" />
+              <not>
+                <and>
+                  <isfailure code="0" />
+                  <isfailure code="2" />
+                  <isfailure code="4" />
+                  <isfailure code="6" />
+                  <isfailure code="8" />
+                </and>
+              </not>
+            </or>
+          </and>
+          <and>
+            <not>
+              <os family="openvms" />
+            </not>
+            <or>
+              <isfailure code="0" />
+              <not>
+                <and>
+                  <isfailure code="1" />
+                  <isfailure code="10" />
+                  <isfailure code="50" />
+                  <isfailure code="100" />
+                  <isfailure code="255" />
+                </and>
+              </not>
+            </or>
+          </and>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/isfileselected.xml b/trunk/src/etc/testcases/taskdefs/conditions/isfileselected.xml
new file mode 100644
index 0000000..0626eed
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/isfileselected.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <macrodef name="pass">
+    <element name="conditions" implicit="yes"/>
+    <attribute name="failmessage"/>
+    <sequential>
+      <fail message="@{failmessage}">
+        <condition>
+          <not>
+            <conditions/>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="simple">
+    <pass failmessage="a simple test">
+      <isfileselected file="jars/pass.jar">
+        <signedselector/>
+      </isfileselected>
+    </pass>
+  </target>
+
+  <target name="name">
+    <pass failmessage="name did not match">
+      <isfileselected file="jars/nosign.jar">
+        <filename name="jars/nosign.jar"/>
+      </isfileselected>
+    </pass>
+  </target>
+
+  <target name="basedir">
+    <pass failmessage="name did not match with a basedir change">
+      <isfileselected file="jars/nosign.jar" basedir="jars">
+        <filename name="nosign.jar"/>
+      </isfileselected>
+    </pass>
+  </target>
+
+  <target name="type">
+    <pass failmessage="type selector did not work">
+      <isfileselected file="isfileselected.xml">
+        <type type="file"/>
+      </isfileselected>
+    </pass>
+  </target>
+
+  <target name="not.selector">
+    <fileset dir=".">
+      <isfileselected file="nosigned.jar"/>
+    </fileset>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/isreachable.xml b/trunk/src/etc/testcases/taskdefs/conditions/isreachable.xml
new file mode 100644
index 0000000..3f74aef
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/isreachable.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+<project name="isreachable">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+
+  <macrodef name="assertHostReachable">
+    <attribute name="host"/>
+    <sequential>
+      <fail message="not reachable: @{host}">
+        <condition>
+          <not>
+            <isreachable host="@{host}"/>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assertHostNotReachable">
+    <attribute name="host"/>
+    <sequential>
+      <fail message="unexpectedly reachable: @{host}">
+        <condition>
+          <isreachable host="@{host}"/>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assertUrlReachable">
+    <attribute name="url"/>
+    <sequential>
+      <fail message="not reachable: @{url}">
+        <condition>
+          <not>
+            <isreachable url="@{url}"/>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="testLocalhost">
+    <assertHostReachable host="localhost"/>
+  </target>
+
+  <!-- bugs in XPSP2 mean this is the only IPv4 loopback addr allowed  -->
+  <target name="testIpv4localhost">
+    <assertHostReachable host="127.0.0.1"/>
+  </target>
+
+  <target name="testBoth">
+    <condition property="both">
+      <isreachable host="localhost" url="http://localhost"/>
+    </condition>
+    <fail>Expected failure before here</fail>
+  </target>
+
+  <target name="testLocalhostURL">
+    <assertUrlReachable url="http://localhost"/>
+  </target>
+
+  <target name="testIpv4localhostURL">
+    <assertUrlReachable url="http://127.0.0.1/"/>
+  </target>
+
+  <target name="testFTPURL">
+    <assertUrlReachable url="ftp://localhost"/>
+  </target>
+
+  <target name="testFile">
+    <assertUrlReachable url="file://build.xml"/>
+  </target>
+
+  <target name="testBadURL">
+    <assertUrlReachable url="uuid:3349-4404-0ac0ddee"/>
+  </target>
+
+  <target name="testBadTimeout">
+    <condition property="testBadTimeout">
+      <isreachable host="localhost" timeout="-1"/>
+    </condition>
+  </target>
+
+  <target name="testNoTargets">
+    <condition property="none">
+      <isreachable/>
+    </condition>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/isreference.xml b/trunk/src/etc/testcases/taskdefs/conditions/isreference.xml
new file mode 100644
index 0000000..d1f86db
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/isreference.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="nope">
+  <path id="global-path-id"/>
+  <echo id="echo-id"/>
+
+  <target name="nope">
+    <fail>This build file should be run by a testcase</fail>
+  </target>
+
+  <target name="define">
+    <path id="target-path-id"/>
+  </target>
+
+  <target name="basic" depends="define">
+    <condition property="global-path">
+      <isreference refid="global-path-id"/>
+    </condition>
+    <condition property="target-path">
+      <isreference refid="target-path-id"/>
+    </condition>
+  </target>
+
+  <target name="isreference-incomplete">
+    <condition property="foo">
+      <isreference/>
+    </condition>
+  </target>
+
+  <target name="type">
+    <condition property="global-path">
+      <isreference refid="global-path-id" type="path"/>
+    </condition>
+    <condition property="global-path-as-fileset">
+      <isreference refid="global-path-id" type="fileset"/>
+    </condition>
+    <condition property="global-path-as-foo">
+      <isreference refid="global-path-id" type="foo"/>
+    </condition>
+    <condition property="global-echo">
+      <isreference refid="echo-id" type="echo"/>
+    </condition>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/issigned.xml b/trunk/src/etc/testcases/taskdefs/conditions/issigned.xml
new file mode 100644
index 0000000..7cbf328
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/issigned.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all">
+  
+  <target name="pass" description="check if a name of pass is ok">
+    <fail message="name of pass not seen in the signed pass.jar">
+      <condition>
+        <not>
+          <issigned file="jars/pass.jar" name="pass"/>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="password" description="check if a name of password is *not* ok">
+    <fail message="name of password is seen in the signed pass.jar">
+      <condition>
+        <issigned file="jars/pass.jar" name="password"/>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="apassword" description="check if the 8 letter shorting works">
+    <fail message="8 letter shorting does not work 1">
+      <condition>
+        <not>
+          <issigned file="jars/apassword.jar" name="apasswor"/>
+        </not>
+      </condition>
+    </fail>
+    <fail message="8 letter shorting does not work 2">
+      <condition>
+        <not>
+          <issigned file="jars/apassword.jar" name="apassword"/>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="allsigned" description="check the signed / not signed status">
+    <fail message="pass.jar should be signed">
+      <condition>
+        <not>
+          <issigned file="jars/pass.jar"/>
+        </not>
+      </condition>
+    </fail>
+    <fail message="nosign.jar should not be signed">
+      <condition>
+        <issigned file="jars/nosign.jar"/>
+      </condition>
+    </fail>
+
+    <fail message="apassword.jar should be signed">
+      <condition>
+        <not>
+          <issigned file="jars/apassword.jar"/>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/jars/apassword.jar b/trunk/src/etc/testcases/taskdefs/conditions/jars/apassword.jar
new file mode 100644
index 0000000..6bd4af1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/jars/apassword.jar
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/jars/nosign.jar b/trunk/src/etc/testcases/taskdefs/conditions/jars/nosign.jar
new file mode 100644
index 0000000..d1b7f8d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/jars/nosign.jar
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/jars/pass.jar b/trunk/src/etc/testcases/taskdefs/conditions/jars/pass.jar
new file mode 100644
index 0000000..cd49f15
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/jars/pass.jar
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/parsersupports.xml b/trunk/src/etc/testcases/taskdefs/conditions/parsersupports.xml
new file mode 100644
index 0000000..c80fd35
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/parsersupports.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<project name="parsersupports" >
+<!--
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+-->
+
+  <target name="testEmpty">
+    <condition property="empty">
+      <parsersupports />
+    </condition>
+    <fail>Expected failure before here</fail>
+  </target>
+
+  <target name="testBoth">
+    <condition property="both">
+      <parsersupports property="http://bar" feature="http://foo"/>
+    </condition>
+    <fail>Expected failure before here</fail>
+  </target>
+
+  <target name="testNamespaces">
+    <fail>
+    <condition >
+      <not>
+        <parsersupports feature="http://xml.org/sax/features/namespaces"/>
+      </not>
+    </condition>
+      Expected namespace support
+    </fail>
+  </target>
+
+  <target name="testPropertyInvalid">
+    <fail>
+      <condition>
+        <not>
+          <parsersupports
+            property="http://xml.org/sax/properties/declaration-handler"
+            value="undefined"/>
+        </not>
+      </condition>
+      Expected DTD declaration property settable.
+    </fail>
+  </target>
+
+  <target name="testPropertyNoValue">
+    <fail>
+      <condition>
+        <not>
+          <parsersupports
+            property="http://xml.org/sax/properties/declaration-handler"
+              />
+        </not>
+      </condition>
+      Expected no property
+    </fail>
+  </target>
+  
+  <target name="testUnknownProperty">
+    <fail>
+      <condition>
+          <parsersupports property="http://org.apache.ant/something"
+              value="undefined"/>
+      </condition>
+      Expected unsupported property.
+    </fail>
+  </target>
+  
+  <target name="testXercesProperty">
+    <fail>
+      <condition>
+        <not>
+          <parsersupports
+          property="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+            value="parsersupports.xml"/>
+        </not>
+      </condition>
+      Expected XSD support on Xerces.
+    </fail>
+  </target>
+  
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/typefound.xml b/trunk/src/etc/testcases/taskdefs/conditions/typefound.xml
new file mode 100644
index 0000000..054ca67
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/typefound.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="typefound">
+
+
+    <target name="testTask">
+        <condition property="testTask">
+            <typefound name="echo"/>
+        </condition>
+    </target>
+
+
+    <target name="testUndefined">
+        <condition property="testUndefined">
+            <typefound />
+        </condition>
+    </target>
+
+    <target name="testTaskThatIsntDefined">
+        <condition property="testTaskThatIsntDefined">
+            <typefound name="invalid-and-undefined-task-name"/>
+        </condition>
+    </target>
+
+    <target name="testTaskThatDoesntReallyExist">
+     <taskdef name="invalid-task-name" onerror="ignore"
+        classname="org.example.invalid.task.name.hopefully"/>
+        <condition property="testTaskThatDoesntReallyExist">
+            <typefound name="invalid-task-name"/>
+        </condition>
+    </target>
+
+    <target name="testType">
+        <condition property="testType">
+            <typefound name="path"/>
+        </condition>
+    </target>
+
+    <target name="testPreset">
+        <presetdef name="important-echo">
+            <echo level="error"/>
+        </presetdef>
+        <condition property="testPreset">
+            <typefound name="important-echo"/>
+        </condition>
+    </target>
+
+    <target name="testMacro">
+        <macrodef name="error-message">
+            <element name="text" optional="false"/>
+            <sequential>
+                <echo level="error">@{text}</echo>
+            </sequential>
+        </macrodef>
+        <condition property="testMacro">
+            <typefound name="error-message"/>
+        </condition>
+    </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/conditions/xor.xml b/trunk/src/etc/testcases/taskdefs/conditions/xor.xml
new file mode 100644
index 0000000..895dccd
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/conditions/xor.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all">
+
+<!-- 
+  Xor semantics
+  
+  in  out
+  ==  ===
+  00   0
+  01   1
+  10   1
+  00   0
+
+-->
+
+  <target name="testEmpty" >
+    <fail message="empty test">
+      <condition>
+          <xor/>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="test1" >
+    <fail message="testTrue">
+      <condition>
+        <not>
+          <xor>
+            <istrue value="true" />
+          </xor>
+        </not>
+      </condition>
+    </fail>
+  </target>
+  
+  <target name="test0" >
+    <fail message="testFalse">
+      <condition>
+          <xor>
+            <istrue value="" />
+          </xor>
+      </condition>
+    </fail>
+  </target>
+
+  
+  <target name="test10" >
+    <fail message="test10">
+      <condition>
+        <not>
+          <xor>
+            <istrue value="true" />
+            <istrue value="" />
+          </xor>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="test01" >
+    <fail message="test01">
+      <condition>
+        <not>
+          <xor>
+            <istrue value="" />
+            <istrue value="true" />
+          </xor>
+        </not>
+      </condition>
+    </fail>
+  </target>
+  
+  <target name="test00" >
+    <fail message="test10">
+      <condition>
+        <xor>
+            <istrue value="" />
+            <istrue value="" />
+        </xor>
+      </condition>
+    </fail>
+  </target>
+  
+  <target name="test11" >
+    <fail message="test11">
+      <condition>
+          <xor>
+            <istrue value="" />
+            <istrue value="" />
+          </xor>
+      </condition>
+    </fail>
+  </target>
+
+  
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/copy.filterset b/trunk/src/etc/testcases/taskdefs/copy.filterset
new file mode 100644
index 0000000..5563dd9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copy.filterset
@@ -0,0 +1 @@
+This is the @TITLE@.
diff --git a/trunk/src/etc/testcases/taskdefs/copy.xml b/trunk/src/etc/testcases/taskdefs/copy.xml
new file mode 100644
index 0000000..85cf7c2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copy.xml
@@ -0,0 +1,286 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="copy-test" basedir="." default="test1">
+
+  <target name="test1">
+    <copy file="copy.xml" tofile="copytest1.tmp" />
+  </target>
+
+  <target name="test2">
+    <copy file="copy.xml" todir="copytest1dir" overwrite="true"/>
+  </target>
+
+  <target name="filtertest">
+    <!-- check fix for bugzilla 23154 -->
+    <delete quiet="yes" file="copy.filter.out"/>
+    <delete quiet="yes" file="copy.filter.inp"/>
+    <concat destfile="copy.filter.inp">
+PRODUCT_VERSION=6.2.1.4
+PRODUCT_BUILD=6.5 (BLD_65036)
+PRODUCT_VERSION=6.2.1.4
+PRODUCT_BUILD=6.5 (BLD_65036)
+    </concat>
+    <copy file="copy.filter.inp" tofile="copy.filter.out">
+      <filterset begintoken="6" endtoken="4">
+        <filter token=".2.1." value="2.6.4" />
+      </filterset>
+    </copy>
+    <concat><path path="copy.filter.out"/></concat>
+  </target>
+
+  <target name="infinitetest">
+    <delete quiet="yes" file="copy.filter.out"/>
+    <delete quiet="yes" file="copy.filter.inp"/>
+    <concat destfile="copy.filter.inp">
+a=b=
+    </concat>
+    <copy file="copy.filter.inp" tofile="copy.filter.out">
+      <filterset begintoken="=" endtoken="=">
+        <filter token="b" value="=b="/>
+      </filterset>
+    </copy>
+    <concat><path path="copy.filter.out"/></concat>
+  </target>
+
+  <target name="test3">
+    <!-- create an empty file -->
+    <touch file="copytest3.tmp"/>
+    <!--wait -->
+    <sleep seconds="4"/>
+    <!-- copy a different file to two places -->
+    <copy file="copy.xml" tofile="copytest3a.tmp" overwrite="true"/>
+    <copy file="copy.xml" tofile="copytest3b.tmp" overwrite="true"/>
+    <!--wait -->
+    <sleep seconds="4"/>
+    <!-- copy an old file onto a newer file (should not work) -->
+    <copy file="copytest3.tmp" tofile="copytest3b.tmp" />
+    <!-- copy an older file onto a new one, should succeed -->
+    <copy file="copytest3.tmp" tofile="copytest3c.tmp"
+      overwrite="true"
+      preservelastmodified="true" />
+    <!-- copy a newer file onto an older one (should work) -->
+    <copy file="copytest3a.tmp" tofile="copytest3.tmp"
+      preservelastmodified="true" />
+    <!-- expected state :
+      3a.tmp==3.tmp==copy.xml
+      timeof(3a.tmp)==timeof(3.tmp)==now()-4
+      sizeof(3c)==0
+      timeof(3c.tmp)<timeof(3a.tmp);
+      3b.tmp==copy.xml
+    -->
+  </target>
+
+  <target name="test_single_file_fileset">
+    <copy tofile="copytest_single_file_fileset.tmp">
+      <fileset dir="." includes="copy.xml"/>
+    </copy>
+  </target>
+
+  <target name="test_single_file_path">
+    <copy tofile="copytest_single_file_path.tmp">
+      <path>
+        <pathelement location="copy.xml"/>
+      </path>
+    </copy>
+  </target>
+
+  <target name="testFilterSet">
+    <copy file="copy.filterset" tofile="copy.filterset.tmp">
+      <filterset>
+        <filter token="TITLE" value="Apache Ant Project"/>
+      </filterset>
+    </copy>
+  </target>
+
+  <target name="testFilterChain">
+    <copy file="copy.filterset" tofile="copy.filterchain.tmp">
+      <filterchain>
+        <replacetokens>
+          <token key="TITLE" value="Apache Ant Project"/>
+        </replacetokens>
+      </filterchain>
+    </copy>
+  </target>
+
+  <target name="testTranscoding">
+    <copy file="copy/input/iso8859-1" tofile="copytest1.tmp"
+          encoding="ISO8859_1" outputencoding="UTF8"/>
+  </target>
+
+  <target name="testMissingFileIgnore">
+    <copy file="not-there" tofile="copytest1.tmp"
+          failonerror="false"/>
+  </target>
+
+  <target name="testMissingFileBail">
+    <copy file="not-there" tofile="copytest1.tmp"
+          failonerror="true"/>
+  </target>
+
+  <target name="testMissingDirIgnore">
+    <copy todir="copytest1dir" failonerror="false">
+      <fileset dir="not-there"/>
+    </copy>
+  </target>
+
+  <target name="testMissingDirBail">
+    <copy todir="copytest1dir" failonerror="true">
+      <fileset dir="not-there"/>
+    </copy>
+  </target>
+
+  <property name="to.dir" value="copy-todir-tmp"/>
+  <property name="from.dir" value="copy-fromdir-tmp"/>
+
+  <target name="testResource.prepare">
+    <mkdir dir="${from.dir}"/>
+    <concat destfile="${from.dir}/file1.txt">This is file 1</concat>
+    <concat destfile="${from.dir}/file2.txt">This is file 2</concat>
+    <concat destfile="${from.dir}/file3.txt">This is file 3</concat>
+    <concat destfile="${from.dir}/fileNR.txt">This is file @NR@</concat>
+  </target>
+
+  <target name="testFileResourcePlain" depends="testResource.prepare">
+    <copy todir="${to.dir}" flatten="true">
+      <resources>
+        <file file="${from.dir}/file1.txt"/>
+        <file file="${from.dir}/file2.txt"/>
+        <file file="${from.dir}/file3.txt"/>
+      </resources>
+    </copy>
+  </target>
+
+  <target name="testFileResourceWithMapper" depends="testResource.prepare">
+    <copy todir="${to.dir}" flatten="true">
+      <resources>
+        <file file="${from.dir}/file1.txt"/>
+        <file file="${from.dir}/file2.txt"/>
+        <file file="${from.dir}/file3.txt"/>
+      </resources>
+      <regexpmapper from="^(.*)\.txt$$" to="\1.txt.bak"/>
+    </copy>
+  </target>
+
+  <target name="testFileResourceWithFilter" depends="testResource.prepare">
+    <copy todir="${to.dir}" flatten="true">
+      <resources>
+        <file file="${from.dir}/fileNR.txt"/>
+      </resources>
+      <filterset>
+        <filter token="NR" value="42"/>
+      </filterset>
+    </copy>
+  </target>
+
+  <target name="testResourcePlain">
+  </target>
+
+  <target name="testResourcePlainWithMapper">
+  </target>
+
+  <target name="testResourcePlainWithFilter">
+  </target>
+
+  <target name="testOnlineResources">
+  </target>
+
+  <target name="testPathAsResource" depends="testResource.prepare">
+    <copy todir="${to.dir}">
+      <path>
+        <fileset dir="${from.dir}"/>
+      </path>
+    </copy>
+  </target>
+
+  <target name="testZipfileset" depends="testResource.prepare">
+    <zip destfile="${from.dir}/test.zip" roundup="false">
+      <fileset dir="${from.dir}" excludes="*.zip"/>
+    </zip>
+    <copy todir="${to.dir}">
+      <zipfileset src="${from.dir}/test.zip"/>
+    </copy>
+  </target>
+
+  <target name="prepareDirset">
+    <touch mkdirs="true">
+      <filelist dir="${from.dir}/dirset">
+        <file name="a/x/foo" />
+        <file name="a/y/foo" />
+        <file name="a/z/foo" />
+        <file name="b/x/foo" />
+        <file name="b/y/foo" />
+        <file name="b/z/foo" />
+      </filelist>
+    </touch>
+    <fail>
+      <condition>
+        <or>
+          <resourcecount when="ne" count="9">
+            <dirset id="dirset" dir="${from.dir}/dirset" />
+          </resourcecount>
+          <resourcecount when="ne" count="6">
+            <fileset dir="${from.dir}/dirset" />
+          </resourcecount>
+        </or>
+      </condition>
+    </fail>
+    <delete dir="${to.dir}/dirset" />
+    <fail>
+      <condition>
+        <available file="${to.dir}/dirset" />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testDirset" depends="prepareDirset">
+    <copy todir="${to.dir}/dirset">
+      <resources refid="dirset" />
+    </copy>
+    <fail>
+      <condition>
+        <or>
+          <resourcecount when="ne" count="9">
+            <dirset dir="${to.dir}/dirset" />
+          </resourcecount>
+          <resourcecount when="ne" count="0">
+            <fileset dir="${to.dir}/dirset" />
+          </resourcecount>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="cleanup">
+    <delete file="copytest1.tmp"/>
+    <delete file="copytest3.tmp"/>
+    <delete file="copytest3a.tmp"/>
+    <delete file="copytest3b.tmp"/>
+    <delete file="copytest3c.tmp"/>
+    <delete file="copytest_single_file_fileset.tmp"/>
+    <delete file="copytest_single_file_path.tmp"/>
+    <delete file="copy.filterset.tmp"/>
+    <delete file="copy.filterchain.tmp"/>
+    <delete dir="copytest1dir"/>
+    <delete quiet="yes" file="copy.filter.out"/>
+    <delete quiet="yes" file="copy.filter.inp"/>
+    <delete dir="${from.dir}"/>
+    <delete dir="${to.dir}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/copy/expected/utf-8 b/trunk/src/etc/testcases/taskdefs/copy/expected/utf-8
new file mode 100644
index 0000000..c1949bc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copy/expected/utf-8
@@ -0,0 +1 @@
+äöüÄÖÜß
diff --git a/trunk/src/etc/testcases/taskdefs/copy/input/iso8859-1 b/trunk/src/etc/testcases/taskdefs/copy/input/iso8859-1
new file mode 100644
index 0000000..0904401
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copy/input/iso8859-1
@@ -0,0 +1 @@
+äöüÄÖÜß
diff --git a/trunk/src/etc/testcases/taskdefs/copydir.xml b/trunk/src/etc/testcases/taskdefs/copydir.xml
new file mode 100644
index 0000000..e8b38c9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copydir.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="copydir-test" basedir="." default="test1">
+
+  <target name="test1">
+    <copydir/>
+  </target>
+
+  <target name="test2">
+    <copydir src=""/>
+  </target>
+
+  <target name="test3">
+    <copydir dest=""/>
+  </target>
+
+  <target name="test4">
+    <copydir src="." 
+             dest="."/>
+  </target>
+
+  <target name="test5">
+    <mkdir dir="../taskdefs.tmp" />
+    <copydir src="." 
+             dest="../taskdefs.tmp"/>
+  </target>
+
+  <target name="test6">
+    <copydir src="." 
+             dest="template.xml"/>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="../taskdefs.tmp" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/copyfile.xml b/trunk/src/etc/testcases/taskdefs/copyfile.xml
new file mode 100644
index 0000000..9584295
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/copyfile.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="copyfile-test" basedir="." default="test1">
+
+  <target name="test1">
+    <copyfile/>
+  </target>
+
+  <target name="test2">
+    <copyfile src=""/>
+  </target>
+
+  <target name="test3">
+    <copyfile dest=""/>
+  </target>
+
+  <target name="test4">
+    <copyfile src="template.xml" 
+             dest="template.xml"/>
+  </target>
+
+  <target name="test5">
+    <copyfile src="copyfile.xml" 
+             dest="copyfile.tmp"/>
+  </target>
+
+  <target name="test6">
+    <delete file="testdir"/>
+    <mkdir dir="testdir" />
+    <copyfile src="copyfile.xml" 
+              dest="testdir"
+              forceoverwrite="true" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="testdir" />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/cvspass.xml b/trunk/src/etc/testcases/taskdefs/cvspass.xml
new file mode 100644
index 0000000..bbca110
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/cvspass.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="cvspass-test" basedir="." default="test1">
+
+  <taskdef name="cvspass" classname="org.apache.tools.ant.taskdefs.CVSPass"/>
+
+  <target name="test1">
+    <cvspass />
+  </target>
+ 
+  <target name="test2">
+    <cvspass
+      cvsroot=":pserver:anoncvs@jakarta.apache.org:/home/cvspublic"
+      passfile="testpassfile.tmp"
+    />
+  </target>
+ 
+  <!-- testPassFile -->
+  <target name="test3">
+    <cvspass
+      cvsroot=":pserver:anoncvs@jakarta.apache.org:/home/cvspublic"
+      password="anoncvs"
+      passfile="testpassfile.tmp"
+    />
+  </target>
+
+  <!-- testPassFileDuplicateEntry -->
+  <target name="test4">
+    <cvspass
+      cvsroot=":pserver:anoncvs@jakarta.apache.org:/home/cvspublic"
+      password="anoncvs"
+      passfile="testpassfile.tmp"
+    />
+    <cvspass
+      cvsroot=":pserver:anoncvs@jakarta.apache.org:/home/cvspublic"
+      password="anoncvs"
+      passfile="testpassfile.tmp"
+    />
+    <cvspass
+      cvsroot=":pserver:guest@cvs.tigris.org:/cvs"
+      password="guest"
+      passfile="testpassfile.tmp"
+    />
+  </target>
+
+  <!-- testPassFileMultipleEntry -->
+  <target name="test5">
+    <cvspass
+      cvsroot=":pserver:anoncvs@jakarta.apache.org:/home/cvspublic"
+      password="anoncvs"
+      passfile="testpassfile.tmp"
+    />
+    <cvspass
+      cvsroot=":pserver:anoncvs@xml.apache.org:/home/cvspublic"
+      password="anoncvs"
+      passfile="testpassfile.tmp"
+    />
+    <cvspass
+      cvsroot=":pserver:guest@cvs.tigris.org:/cvs"
+      password="guest"
+      passfile="testpassfile.tmp"
+    />
+  </target>
+
+  <target name="cleanup"> 
+    <delete file="testpassfile.tmp"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/defaultexcludes.xml b/trunk/src/etc/testcases/taskdefs/defaultexcludes.xml
new file mode 100644
index 0000000..4629250
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/defaultexcludes.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="echo-test" basedir="." default="test1">
+
+  <target name="cleanup">
+    <defaultexcludes default="true"/>
+  </target>
+
+  <target name="test1">
+    <defaultexcludes echo="true"/>
+  </target>
+
+  <target name="test2">
+    <defaultexcludes default="true" add="foo" echo="true"/>
+  </target>
+
+  <target name="test3">
+    <defaultexcludes default="true" remove="**/CVS" echo="true"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/delete.xml b/trunk/src/etc/testcases/taskdefs/delete.xml
new file mode 100644
index 0000000..014feb5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/delete.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="delete-test" basedir="." default="test1">
+
+  <property name="dirname" value="taskdefs.tmp" />
+  <property name="dir" location="${dirname}" />
+
+  <macrodef name="expectabsent">
+    <attribute name="target" default="${dir}"/>
+    <sequential>
+      <fail>
+        <condition>
+          <available file="@{target}" />
+        </condition>
+    </fail>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="expectdirsonly">
+    <sequential>
+      <fail>
+        <condition>
+          <or>
+            <resourcecount when="greater" count="0">
+              <fileset dir="${dir}" />
+            </resourcecount>
+            <not>
+              <resourcecount count="${srcdirs}">
+                <dirset dir="${dir}" />
+              </resourcecount>
+            </not>
+          </or>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="init">
+    <resourcecount property="srcdirs">
+      <dirset dir="${basedir}" />
+    </resourcecount>
+
+    <resourcecount property="srcsize">
+      <files includes="${basedir}/" />
+    </resourcecount>
+
+    <mkdir dir="${dir}" />
+
+    <copy todir="${dir}">
+      <fileset dir="${basedir}" excludes="${dirname},${dirname}/**" />
+    </copy>
+  </target>
+
+  <target name="test1">
+    <delete />
+  </target>
+
+  <target name="test2" depends="init">
+    <delete file="${dir}" />
+    <fail>
+      <condition>
+        <not>
+          <resourcecount count="${srcsize}">
+            <files includes="${dir}/" />
+          </resourcecount>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="test4" depends="init">
+    <delete dir="${dir}" />
+    <expectabsent />
+  </target>
+
+  <target name="test5" depends="init">
+    <delete dir="${dir}" includes="**" />
+    <expectdirsonly />
+  </target>
+
+  <target name="test6" depends="init">
+    <delete dir="${dir}" includes="**" includeemptydirs="true" />
+    <expectabsent />
+  </target>
+
+  <target name="test7" depends="init">
+    <delete>
+      <fileset id="fs" dir="${dir}" />
+    </delete>
+    <expectdirsonly />
+  </target>
+
+  <target name="test8" depends="init">
+    <delete includeemptydirs="true">
+      <fileset dir="${dir}" />
+    </delete>
+    <expectabsent />
+  </target>
+
+  <target name="test9" depends="init">
+    <delete>
+      <files includes="${dir}/**" />
+    </delete>
+    <expectabsent />
+  </target>
+
+  <target name="test10">
+    <delete>
+      <filelist dir="${dir}" files="test10absentfile" />
+    </delete>
+  </target>
+
+  <target name="test11">
+    <delete failonerror="false">
+      <fileset dir="thisdenotesadirectorythatwillneverexistblah" />
+    </delete>
+  </target>
+
+  <target name="test12">
+    <delete failonerror="false" includeemptydirs="true">
+      <fileset dir="thisdenotesadirectorythatwillneverexistblah" />
+    </delete>
+  </target>
+
+  <target name="test13" depends="init">
+    <delete includeemptydirs="true">
+      <fileset dir="${dir}" />
+      <fileset dir="${dir}" />
+    </delete>
+    <expectabsent />
+  </target>
+
+  <target name="test14" depends="init">
+	<delete quiet="false">
+		<fileset dir="${dir}" />
+		<fileset dir="${dir}" />
+	</delete>
+  </target>
+
+  <target name="test15" depends="init">
+	<delete quiet="true">
+		<fileset dir="${dir}" />
+		<fileset dir="${dir}" />
+	</delete>
+  </target>
+  <!-- Bugzilla 40313 -->
+  <target name="test16.init">
+    <mkdir dir="${dir}/CVS"/>
+    <touch file="${dir}/CVS/lala"/>
+    <mkdir dir="${dir}/subdir"/>
+  </target>
+
+  <target name="test16" depends="test16.init">
+    <delete defaultexcludes="false" dir="${dir}" includeemptydirs="true"/>
+    <expectabsent/>
+  </target>
+
+  <target name="test17" depends="test16.init">
+    <delete dir="${dir}" defaultexcludes="true" includeemptydirs="true"/>
+    <fail message="file in CVS dir deleted">
+      <condition>
+        <not>
+          <available file="${dir}/CVS/lala"/>
+        </not>
+      </condition>
+    </fail>
+    <expectabsent target="${dir}/subdir"/>
+  </target>
+
+
+  <target name="cleanup" depends="test4" />
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/deltree.xml b/trunk/src/etc/testcases/taskdefs/deltree.xml
new file mode 100644
index 0000000..c69d51f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/deltree.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="deltree-test" basedir="." default="test1">
+
+  <target name="test1">
+    <deltree/>
+  </target>
+
+  <target name="test2">
+    <deltree dir="taskdefs.tmp"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/dirname.xml b/trunk/src/etc/testcases/taskdefs/dirname.xml
new file mode 100644
index 0000000..1027db1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/dirname.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <dirname/>
+  </target>
+
+  <target name="test2">
+    <dirname property="propname"/>
+  </target>
+
+  <target name="test3">
+    <dirname file="filename"/>
+  </target>
+
+  <target name="test4">
+    <dirname property="local.dir" file="/usr/local/foo.txt"/>
+  </target>
+
+  <target name="test5">
+    <dirname property="base.dir" file="foo.txt"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/dynamictask.xml b/trunk/src/etc/testcases/taskdefs/dynamictask.xml
new file mode 100644
index 0000000..307181f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/dynamictask.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="dynamic-test" default="simple">
+
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="simple">
+    <taskdef name="dyna"
+             classname="org.apache.tools.ant.taskdefs.DynamicTask">
+      <classpath refid="testclasses" />
+    </taskdef>
+    <dyna prop1="1" prop2="2">
+      <sub prop3="3"/>
+      <anything prop4="4"/>
+    </dyna>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/echo.xml b/trunk/src/etc/testcases/taskdefs/echo.xml
new file mode 100644
index 0000000..5f2abd0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/echo.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="echo-test" basedir="." default="test1">
+
+  <property name="dest.dir" location="echo.dest"/>
+
+  <target name="init">
+    <mkdir dir="${dest.dir}" />
+  </target>
+
+  <target name="clean">
+    <delete dir="${dest.dir}"/>
+  </target>
+
+  <target name="test1">
+    <echo/>
+  </target>
+
+  <target name="test2">
+    <echo message="OUTPUT OF ECHO"/>
+  </target>
+
+  <target name="test3">
+    <echo>
+    This 
+    is
+    a 
+    multiline
+    message
+    </echo>
+  </target>
+
+  <macrodef name="assertContains">
+    <attribute name="expected" />
+    <attribute name="actual" />
+    <sequential>
+      <fail>
+        <condition>
+          <not>
+            <contains string="@{actual}" substring="@{expected}"></contains>
+          </not>
+        </condition>
+        Did not find @{expected} in @{actual}
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="testFile" depends="init">
+    <echo file="${dest.dir}/echo.txt">Simple text</echo>
+    <loadfile srcfile="${dest.dir}/echo.txt" property="echo" />
+    <assertContains actual="${echo}" expected="Simple text" />
+  </target>
+
+
+  <target name="testAppend" depends="init">
+    <echo file="${dest.dir}/echo.txt">Simple text</echo>
+    <echo file="${dest.dir}/echo.txt" append="true">Appended</echo>
+    <loadfile srcfile="${dest.dir}/echo.txt" property="echo"/>
+    <assertContains actual="${echo}" expected="Simple text"/>
+    <assertContains actual="${echo}" expected="Appended"/>
+  </target>
+
+  <target name="testEmptyEncoding" depends="init">
+    <echo file="${dest.dir}/echo.txt" encoding="">Simple text</echo>
+    <loadfile srcfile="${dest.dir}/echo.txt" property="echo"/>
+    <assertContains actual="${echo}" expected="Simple text"/>
+  </target>
+
+  <target name="testUTF16Encoding" depends="init">
+    <property name="char" value="&#169;" />
+    <echo file="${dest.dir}/echo16.txt" encoding="UTF-16">${char}</echo>
+    <loadfile srcfile="${dest.dir}/echo16.txt" property="echo16" encoding="UTF16"/>
+    <assertContains actual="${echo16}" expected="${char}"/>
+  </target>
+  
+  <target name="testUTF8Encoding" depends="init">
+    <property name="char" value="&#169;" />
+    <echo file="${dest.dir}/echo8.txt" encoding="UTF8">${char}</echo>
+    <loadfile srcfile="${dest.dir}/echo8.txt" property="echo" encoding="UTF8"/>
+    <assertContains actual="${echo}" expected="${char}"/>
+  </target>
+
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/echoxml.xml b/trunk/src/etc/testcases/taskdefs/echoxml.xml
new file mode 100644
index 0000000..ec53abb
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/echoxml.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <property name="file" location="echoed.xml" />
+  <target name="init">
+    <echoxml file="${file}">
+      <project>
+        <property name="foo" value="bar" />
+        <fail message="$$$${foo}=$${foo}">
+          <condition>
+            <istrue value="${mustfail}" />
+          </condition>
+        </fail>
+      </project>
+    </echoxml>
+  </target>
+  <target name="tearDown">
+    <delete file="${file}" />
+  </target>
+  <target name="testPass" depends="init">
+    <ant antfile="${file}" />
+  </target>
+  <target name="testFail" depends="init">
+    <ant antfile="${file}">
+      <property name="mustfail" value="true" />
+    </ant>
+  </target>
+  <target name="testEmpty">
+    <echoxml />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/email/mail.xml b/trunk/src/etc/testcases/taskdefs/email/mail.xml
new file mode 100644
index 0000000..c56fd40
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/email/mail.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="mail-test" basedir="." default="test1">
+
+  <target name="test1">
+    <!-- this test is supposed to bring a build exception because user and password is not allowed with plain encoding -->
+    <mail host="localhost" port="25" from="joe@abc.com" to="laura@xyz.com" subject="hello" encoding="plain" user="joe" password="secret">
+        <message>
+            Hi Laura, how are you doing ?
+        </message>
+    </mail>
+  </target>
+  <target name="test2">
+      <!-- this test is supposed to bring a build exception because SSL is not allowed with plain encoding -->
+      <mail host="localhost" port="465" from="joe@abc.com" to="laura@xyz.com" subject="hello" encoding="plain" ssl="true">
+          <message>
+              Hi Laura, how are you doing ?
+          </message>
+      </mail>
+    </target>
+
+
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/exec/exec.xml b/trunk/src/etc/testcases/taskdefs/exec/exec.xml
new file mode 100644
index 0000000..4a6157e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/exec/exec.xml
@@ -0,0 +1,385 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="exec-test" default="spawn" basedir=".">
+    <target name="init">
+        <!-- this property can be overriden programatically in the Java test case -->
+        <property name="timeToWait" value="10"/>
+        <!-- this property can be overriden programatically in the Java test case -->
+        <property name="logFile" value="${java.io.tmpdir}/spawn.log"/>
+        <property environment="env"/>
+        <!-- UNIX -->
+        <available file="sh" filepath="${env.PATH}" property="sh.executable"/>
+        <!-- CYGWIN -->
+        <available file="sh.exe" filepath="${env.PATH}" property="sh.exe.executable"/>
+        <condition property="test.can.run">
+            <or>
+                <isset property="sh.executable"/>
+                <isset property="sh.exe.executable"/>
+            </or>
+        </condition>
+        <!-- UNIX -->
+        <available file="wc" filepath="${env.PATH}" property="wc.executable"/>
+        <!-- CYGWIN -->
+        <available file="wc.exe" filepath="${env.PATH}" property="wc.exe.executable"/>
+        <condition property="wc.can.run">
+            <or>
+                <isset property="wc.executable"/>
+                <isset property="wc.exe.executable"/>
+            </or>
+        </condition>
+        <!-- UNIX -->
+        <available file="cat" filepath="${env.PATH}" property="cat.executable"/>
+        <!-- CYGWIN -->
+        <available file="cat.exe" filepath="${env.PATH}" property="cat.exe.executable"/>
+        <condition property="cat.can.run">
+            <or>
+                <isset property="cat.executable"/>
+                <isset property="cat.exe.executable"/>
+            </or>
+        </condition>
+    </target>
+
+    <target name="spawn" depends="init" if="test.can.run">
+        <exec executable="sh" spawn="true">
+            <arg value="spawn.sh"/>
+            <arg value="${timeToWait}" />
+            <arg value="${logFile}" />
+        </exec>
+    </target>
+
+    <target name="no-redirect" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirect1" depends="init" if="test.can.run">
+        <exec executable="sh" output="redirect.out">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirect2" depends="init" if="test.can.run">
+        <exec executable="sh" output="redirect.out" error="redirect.err">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirect3" depends="init" if="test.can.run">
+        <exec executable="sh" logerror="true"
+              output="redirect.out" outputproperty="redirect.out">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirect4" depends="init" if="test.can.run">
+        <exec executable="sh"
+              error="redirect.err" errorproperty="redirect.err"
+              output="redirect.out" outputproperty="redirect.out">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirect5" depends="init" if="wc.can.run">
+        <exec executable="wc" inputstring="x y z"
+              error="redirect.err" errorproperty="redirect.err"
+              output="redirect.out" outputproperty="redirect.out">
+            <arg value="-w"/>
+        </exec>
+    </target>
+
+    <target name="redirect6" depends="init" if="wc.can.run">
+        <echo file="redirect.in">x y z</echo>
+        <exec executable="wc" input="redirect.in"
+              error="redirect.err" errorproperty="redirect.err"
+              output="redirect.out" outputproperty="redirect.out">
+            <arg value="-w"/>
+        </exec>
+    </target>
+
+    <target name="redirect7" depends="init" if="wc.can.run">
+        <exec executable="wc" inputstring="x y z"
+              error="redirect.err"
+              output="redirect.out" outputproperty="redirect.out">
+            <arg value="-w"/>
+        </exec>
+    </target>
+
+    <target name="redirector1" description="fail"
+            depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+            <redirector output="redirector.out" />
+            <redirector output="whocares" />
+        </exec>
+    </target>
+
+    <target name="redirector2" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+            <redirector output="redirector.out" />
+        </exec>
+    </target>
+
+    <target name="redirector3" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+            <redirector output="redirector.out" error="redirector.err" />
+        </exec>
+    </target>
+
+    <target name="redirector4" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+            <redirector output="redirector.out" logerror="true"
+                        outputproperty="redirector.out" />
+        </exec>
+    </target>
+
+    <target name="redirector5" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector error="redirector.err" errorproperty="redirector.err"
+              output="redirector.out" outputproperty="redirector.out" />
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirector6" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+            </redirector>
+            <arg value="parrot.sh" />
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirector7" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+                <errorfilterchain>
+                    <replacestring from="err" to="ERROR!!!" />
+                </errorfilterchain>
+            </redirector>
+            <arg value="parrot.sh" />
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirector8" depends="init" if="wc.can.run">
+        <echo file="redirector.in">x y z</echo>
+        <exec executable="wc">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <inputmapper type="merge" to="redirector.in" />
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+            </redirector>
+            <arg value="-w"/>
+        </exec>
+    </target>
+
+    <target name="redirector9" depends="init" if="cat.can.run">
+        <echo file="redirector.in">blah before blah</echo>
+        <exec executable="cat">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <inputfilterchain>
+                    <replacestring from="before" to="after" />
+                </inputfilterchain>
+                <inputmapper type="merge" to="redirector.in" />
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+            </redirector>
+        </exec>
+    </target>
+
+    <target name="redirector10" depends="init" if="cat.can.run">
+        <echo file="redirector.in">blah before blah</echo>
+        <exec executable="cat">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <outputfilterchain>
+                    <replacestring from="before" to="after" />
+                </outputfilterchain>
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+            </redirector>
+            <arg value="redirector.in"/>
+        </exec>
+    </target>
+
+    <target name="redirector11" depends="init" if="cat.can.run">
+        <exec executable="cat">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err"
+                        inputstring="blah before blah">
+                <inputfilterchain>
+                    <replacestring from="before" to="after" />
+                </inputfilterchain>
+                <outputmapper type="merge" to="redirector.out" />
+                <errormapper type="merge" to="redirector.err" />
+            </redirector>
+        </exec>
+    </target>
+
+    <target name="redirector12" depends="init" if="cat.can.run">
+        <echo file="redirector.in">blah before blah</echo>
+        <exec executable="cat" output="redirector.out" error="redirector.err">
+            <redirector outputproperty="redirector.out"
+                        errorproperty="redirector.err">
+                <outputfilterchain>
+                    <replacestring from="before" to="after" />
+                </outputfilterchain>
+                <outputmapper type="glob" from="nomatch" to="nomatchout" />
+                <errormapper type="glob" from="nomatch" to="nomatcherr" />
+            </redirector>
+            <arg value="redirector.in"/>
+        </exec>
+    </target>
+
+    <target name="redirector13" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector>
+                <outputfilterchain>
+                    <replacestring from="out" to="OUTPUT???" />
+                </outputfilterchain>
+                <errorfilterchain>
+                    <replacestring from="err" to="ERROR!!!" />
+                </errorfilterchain>
+            </redirector>
+            <arg value="parrot.sh" />
+            <arg value="${ant.file}" />
+        </exec>
+    </target>
+
+    <target name="redirector14" depends="init" if="cat.can.run">
+        <exec executable="cat">
+            <redirector inputstring="blah before blah">
+                <outputfilterchain>
+                    <replacestring from="before" to="after" />
+                </outputfilterchain>
+                <outputmapper type="glob" from="nomatch" to="nomatchout" />
+                <errormapper type="glob" from="nomatch" to="nomatcherr" />
+            </redirector>
+        </exec>
+    </target>
+
+    <target name="redirector15" depends="init" if="cat.can.run">
+        <exec executable="cat">
+            <redirector input="input/iso8859-1" output="redirector.out"
+                        inputencoding="ISO8859_1" outputencoding="UTF8" />
+        </exec>
+    </target>
+
+    <target name="redirector16" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector inputstring="exit"
+                        output="redirector16.out" error="redirector16.err" />
+        </exec>
+        <condition property="16pass">
+            <and>
+                <available file="redirector16.out" type="file" />
+                <available file="redirector16.err" type="file" />
+            </and>
+        </condition>
+        <fail unless="16pass">Files were not created.</fail>
+    </target>
+
+    <target name="redirector17" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <redirector inputstring="exit" createemptyfiles="false"
+                        output="redirector17.out" error="redirector17.err" />
+        </exec>
+        <condition property="17fail">
+            <or>
+                <available file="redirector17.out" type="file" />
+                <available file="redirector17.err" type="file" />
+            </or>
+        </condition>
+        <fail if="17fail">Files were created.</fail>
+    </target>
+
+    <target name="redirector18" depends="init" if="test.can.run">
+        <exec executable="sh">
+            <arg value="parrot.sh"/>
+            <arg value="${ant.file}" />
+            <redirector alwayslog="true" logerror="true"
+                        outputproperty="redirector.out" />
+        </exec>
+        <fail message="property redirector.out has unexpected content">
+            <condition>
+                <not>
+                    <equals arg1="${ant.file} out" arg2="${redirector.out}" />
+                </not>
+            </condition>
+        </fail>
+    </target>
+
+    <!-- test will succeed as the OS wont match-->
+    <target name="testExecUnknownOS">
+      <exec executable="nonexistent-program-we-expect"
+        failonerror="true"
+        os="ZX81">
+      </exec>
+    </target>
+
+    <target name="testExecOSFamily">
+      <exec executable="uptime"
+        failonerror="true"
+        osFamily="unix">
+      </exec>
+      <exec executable="cmd.exe"
+        failonerror="true"
+        osFamily="winnt">
+        <arg value="/c" />
+        <arg value="time /t" />
+      </exec>
+    </target>    
+    
+    <target name="testExecInconsistentSettings">
+      <exec executable="nonexistent-program-we-expect"
+        failonerror="true"
+        osFamily="WIN9X"
+        os="linux unix">
+      </exec>
+    </target>
+    
+    <target name="cleanup">
+        <delete>
+            <fileset file="${logFile}" />
+            <fileset dir="${basedir}" includes="redirect*" />
+            <fileset dir="${basedir}" includes="redirector*" />
+        </delete>
+    </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/exec/expected/utf-8 b/trunk/src/etc/testcases/taskdefs/exec/expected/utf-8
new file mode 100644
index 0000000..c1949bc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/exec/expected/utf-8
@@ -0,0 +1 @@
+äöüÄÖÜß
diff --git a/trunk/src/etc/testcases/taskdefs/exec/input/iso8859-1 b/trunk/src/etc/testcases/taskdefs/exec/input/iso8859-1
new file mode 100644
index 0000000..0904401
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/exec/input/iso8859-1
@@ -0,0 +1 @@
+äöüÄÖÜß
diff --git a/trunk/src/etc/testcases/taskdefs/exec/parrot.sh b/trunk/src/etc/testcases/taskdefs/exec/parrot.sh
new file mode 100755
index 0000000..2467f23
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/exec/parrot.sh
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+for arg in "$@" ; do
+	echo $arg out
+	sleep 1
+	echo $arg err>&2
+done
diff --git a/trunk/src/etc/testcases/taskdefs/exec/spawn.sh b/trunk/src/etc/testcases/taskdefs/exec/spawn.sh
new file mode 100644
index 0000000..2cf0631
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/exec/spawn.sh
@@ -0,0 +1,29 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+sleeptime=10
+logfile=spawn.log
+if  [ $# -ge 1 ]; then
+   sleeptime=$1
+   echo $sleeptime
+fi
+if  [ $# -ge 2 ]; then
+   logfile=$2
+   echo $logfile
+fi
+echo hello
+rm  $logfile
+sleep $sleeptime
+echo bye bye > $logfile
+echo bye bye
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.bz2 b/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.bz2
new file mode 100644
index 0000000..7c2d215
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.bz2
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.gz b/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.gz
new file mode 100644
index 0000000..015471e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo-huge.tar.gz
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.bz2 b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.bz2
new file mode 100644
index 0000000..0e73d25
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.bz2
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.gz b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.gz
new file mode 100644
index 0000000..decc918
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.gz
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5 b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5
new file mode 100644
index 0000000..b56119b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5
@@ -0,0 +1 @@
+0541d3df42520911f268abc730f3afe0
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5sum b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5sum
new file mode 100644
index 0000000..56c49d3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.md5sum
@@ -0,0 +1 @@
+0541d3df42520911f268abc730f3afe0 *asf-logo.gif
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.pattern b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.pattern
new file mode 100644
index 0000000..3a6eb82
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.pattern
@@ -0,0 +1 @@
+foo0541d3df42520911f268abc730f3afe0bar
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.svf b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.svf
new file mode 100644
index 0000000..c7f8ec2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.svf
@@ -0,0 +1 @@
+MD5 (asf-logo.gif) = 0541d3df42520911f268abc730f3afe0
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar
new file mode 100644
index 0000000..fc0f790
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2 b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2
new file mode 100644
index 0000000..99a91fc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.bz2
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz
new file mode 100644
index 0000000..ddd23a2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.tar.gz
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.zip b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.zip
new file mode 100644
index 0000000..5f970d5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/asf-logo.gif.zip
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/expected/copy.filterset.filtered b/trunk/src/etc/testcases/taskdefs/expected/copy.filterset.filtered
new file mode 100644
index 0000000..ddbcf5d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/expected/copy.filterset.filtered
@@ -0,0 +1 @@
+This is the Apache Ant Project.
diff --git a/trunk/src/etc/testcases/taskdefs/fail.xml b/trunk/src/etc/testcases/taskdefs/fail.xml
new file mode 100644
index 0000000..0a6561e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fail.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="fail-test" basedir="." default="test1">
+
+  <target name="test1">
+    <fail/>
+  </target>
+
+  <target name="test2">
+    <fail message="test2"/>
+  </target>
+
+  <target name="testText">
+    <fail>testText</fail>
+  </target>
+  
+  <target name="testIf">
+    <fail if="foo" />
+  </target>
+
+  <target name="testUnless">
+    <fail unless="foo" />
+  </target>
+
+  <target name="testIfAndUnless">
+    <fail unless="unless" if="if"/>
+  </target>
+  
+  <target name="testNested1" description="should fail with default message">
+    <fail>
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested2" description="should pass">
+    <fail>
+      <condition>
+          <or />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested3" description="should fail">
+    <fail message="testNested3">
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested4a" description="should error">
+    <fail if="if">
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested4b" description="should error">
+    <fail unless="unless">
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested4c" description="should error">
+    <fail if="if" unless="unless">
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested5" description="should error">
+    <fail>
+      <condition>
+          <or />
+      </condition>
+      <condition>
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testNested6" description="should fail with message">
+    <fail>
+      <condition>
+          <and />
+      </condition>
+testNested6
+testNested6
+testNested6
+    </fail>
+  </target>
+
+  <target name="testNested7a" description="should error">
+    <fail>
+      <condition />
+    </fail>
+  </target>
+
+  <target name="testNested7b" description="should error">
+    <fail>
+      <condition>
+          <and />
+          <and />
+      </condition>
+    </fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/filter.xml b/trunk/src/etc/testcases/taskdefs/filter.xml
new file mode 100644
index 0000000..303efa7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/filter.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="filter-test" basedir="." default="test1">
+
+  <target name="test1">
+    <filter/>
+  </target>
+
+  <target name="test2">
+    <filter token=""/>
+  </target>
+
+  <target name="test3">
+    <filter value=""/>
+  </target>
+
+  <target name="test4">
+    <filter token="" value=""/>
+  </target>
+
+  <target name="test5">
+    <filter token="year" value="2000" />
+    <copy file="filter1.txt" tofile="filtered.tmp" filtering="yes" overwrite="yes" />
+  </target>
+
+  <target name="test6">
+    <filter token="year" value="2000" />
+    <copy todir="./taskdefs.tmp" filtering="yes" overwrite="yes">
+      <fileset dir="." includes="filter1.txt" />
+    </copy>
+  </target>
+
+  <target name="test7">
+    <filter token="ROOT" value="root" />
+    <copy file="filter2.txt" tofile="filtered.tmp" filtering="yes" overwrite="yes" />
+  </target>
+
+  <target name="test8">
+    <filter token="ROOT" value="root" />
+    <copy todir="./taskdefs.tmp" filtering="yes" overwrite="yes">
+      <fileset dir="." includes="filter2.txt"/>
+    </copy>
+  </target>
+
+  <target name="test9">
+    <filter filtersfile="filterdefs.properties" />
+    <copy todir="./taskdefs.tmp" filtering="yes" overwrite="yes">
+      <fileset dir="." includes="filter3.txt"/>
+    </copy>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="taskdefs.tmp" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/filter1.txt b/trunk/src/etc/testcases/taskdefs/filter1.txt
new file mode 100644
index 0000000..4e4f976
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/filter1.txt
@@ -0,0 +1 @@
+@year@
diff --git a/trunk/src/etc/testcases/taskdefs/filter2.txt b/trunk/src/etc/testcases/taskdefs/filter2.txt
new file mode 100644
index 0000000..dccd06b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/filter2.txt
@@ -0,0 +1 @@
+<%@ include file="@ROOT@/some/include.jsp"%>
diff --git a/trunk/src/etc/testcases/taskdefs/filter3.txt b/trunk/src/etc/testcases/taskdefs/filter3.txt
new file mode 100644
index 0000000..03d7d29
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/filter3.txt
@@ -0,0 +1 @@
+@property@
diff --git a/trunk/src/etc/testcases/taskdefs/filterdefs.properties b/trunk/src/etc/testcases/taskdefs/filterdefs.properties
new file mode 100644
index 0000000..f099df3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/filterdefs.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+property=included
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/build.xml b/trunk/src/etc/testcases/taskdefs/fixcrlf/build.xml
new file mode 100644
index 0000000..4547ec4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/build.xml
@@ -0,0 +1,329 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="fixcrlf" default="cleanup" basedir=".">
+  <target name="init">
+    <mkdir dir="result" />
+  </target>
+
+  <target name="cleanup">
+    <delete dir="result" />
+  </target>
+
+  <macrodef name="assertequal">
+    <attribute name="junk" default="" />
+    <attribute name="name" default="Junk@{junk}.java" />
+    <attribute name="file1" default="result/@{name}" />
+    <attribute name="file2" default="expected/@{name}" />
+    <sequential>
+      <fail message="@{file1} and @{file2} are different">
+        <condition>
+          <not>
+            <filesmatch file1="@{file1}" file2="@{file2}" />
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="test1" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk1.java"
+             javafiles="true" tab="add" eol="crlf" eof="asis" />
+    <assertequal junk="1" />
+  </target>
+
+  <target name="test2" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk2.java"
+             javafiles="true" tab="add" cr="add" eol="crlf" eof="asis" />
+    <assertequal junk="2" />
+  </target>
+
+  <target name="test3" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk3.java"
+             javafiles="true" tab="remove" eol="lf" eof="asis" />
+    <assertequal junk="3" />
+  </target>
+
+  <target name="test4" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk4.java"
+             javafiles="true" tab="remove" eol="lf" eof="asis" />
+    <assertequal junk="4" />
+  </target>
+
+  <target name="test5" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk5.java"
+             tab="remove" eol="lf" eof="asis" />
+    <assertequal junk="5" />
+  </target>
+
+  <target name="test6" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk6.java"
+             tab="add" cr="remove" eol="crlf" eof="asis" />
+    <assertequal junk="6" />
+  </target>
+
+  <target name="test7" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk7.java"
+             tab="add" cr="add" eof="asis" />
+    <assertequal junk="7" />
+  </target>
+
+  <target name="test8" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk8.java"
+             javafiles="true" tab="add" cr="add" eof="add" />
+    <assertequal junk="8" />
+  </target>
+
+  <target name="test9" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk9.java"
+             javafiles="true" tab="remove" cr="remove" eof="remove" />
+    <assertequal junk="9" />
+  </target>
+
+  <target name="testMacLines" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Mac2Unix" eol="lf" />
+    <assertequal name="Mac2Unix" />
+  </target>
+
+  <target name="testNoOverwrite" depends="test1">
+    <touch file="result/Junk1.java" millis="0" />
+    <fixcrlf srcdir="input" destdir="result"
+             includes="Junk1.java" preservelastmodified="false"
+             javafiles="true" tab="add" eol="crlf" eof="asis" />
+    <fail message="overwrote unchanged output file">Q
+      <condition>
+        <not>
+          <isfileselected file="result/Junk1.java">
+            <date when="equal" millis="0" />
+          </isfileselected>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testEncoding" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="input.crlf.utf16"
+             javafiles="false" cr="remove" encoding="UnicodeBig" />
+    <assertequal file1="result/input.crlf.utf16"
+                 file2="expected/input.lf.utf16" />
+  </target>
+
+  <target name="testOutputEncoding" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="input.crlf.utf16"
+             javafiles="false" eol="lf" encoding="UnicodeBig"
+             outputencoding="ascii" />
+    <assertequal file1="result/input.crlf.utf16"
+                 file2="expected/input.lf.ascii" />
+  </target>
+
+  <target name="testLongLines" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="longlines.crlf"
+             javafiles="false" cr="remove" />
+    <assertequal file1="result/longlines.crlf"
+                 file2="expected/longlines.lf" />
+  </target>
+
+  <target name="testCrCrLfSequence-unix" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="crcrlf" eol="lf" />
+    <assertequal file1="result/crcrlf"
+                 file2="expected/crcrlf.unix" />
+  </target>
+
+  <target name="testCrCrLfSequence-dos" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="crcrlf" eol="crlf" />
+    <assertequal file1="result/crcrlf"
+                 file2="expected/crcrlf.dos" />
+  </target>
+
+  <target name="testCrCrLfSequence-mac" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="crcrlf" eol="cr" />
+    <assertequal file1="result/crcrlf"
+                 file2="expected/crcrlf.mac" />
+  </target>
+
+  <target name="testFixlastDos" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="fixlastfalse.lf" eol="crlf" />
+    <assertequal file1="result/fixlastfalse.lf"
+                 file2="expected/fixlast.dos" />
+  </target>
+
+  <target name="testFixlastFalseMac" depends="init">
+    <fixcrlf srcdir="input" destdir="result"
+             includes="fixlastfalse.lf" eol="cr" fixlast="false" />
+    <assertequal file1="result/fixlastfalse.lf"
+                 file2="expected/fixlastfalse.mac" />
+  </target>
+
+  <!-- Bugzilla Report 20840 -->
+  <target name="createParentDirs" depends="init">
+    <fixcrlf srcdir="." destdir="result" includes="input/Junk1.java" />
+  </target>
+
+  <target name="testFixFile" depends="init">
+    <fixcrlf file="input/longlines.crlf" destdir="result" />
+    <fail message="didn't create output file">
+      <condition>
+        <not>
+          <available file="result/longlines.crlf" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testFixFileExclusive" depends="init">
+    <fixcrlf file="input/longlines.crlf" srcdir="input" destdir="result"/>
+  </target>
+
+  <target name="testPreserveLastModified" depends="init">
+    <fixcrlf file="input/longlines.crlf" destdir="result"
+             preservelastmodified="true" />
+    <fail>
+      <condition>
+        <not>
+          <uptodate srcfile="result/longlines.crlf"
+                    targetfile="input/longlines.crlf" />
+        </not>
+      </condition>
+    </fail>
+
+    <touch file="result/longlines.crlf" millis="0" />
+
+    <fixcrlf file="result/longlines.crlf" destdir="result" eol="lf"
+             preservelastmodified="true" />
+
+    <fileset id="fs" file="result/longlines.crlf">
+      <date when="equal" millis="0" />
+    </fileset>
+    <property name="fs" refid="fs" />
+    <fail unless="fs" />
+  </target>
+
+  <target name="testFilter1" depends="init">
+    <copy file="input/Junk1.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="add"
+                 eol="crlf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="1" />
+  </target>
+
+  <target name="testFilter2" depends="init">
+    <copy file="input/Junk2.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="add" cr="add" eol="crlf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="2" />
+  </target>
+
+  <target name="testFilter3" depends="init">
+    <copy file="input/Junk3.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="remove" eol="lf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="3" />
+  </target>
+
+  <target name="testFilter4" depends="init">
+    <copy file="input/Junk4.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="remove" eol="lf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="4" />
+  </target>
+
+  <target name="testFilter5" depends="init">
+    <copy file="input/Junk5.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf tab="remove" eol="lf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="5" />
+  </target>
+
+  <target name="testFilter6" depends="init">
+    <copy file="input/Junk6.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf tab="add" cr="remove" eol="crlf" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="6" />
+  </target>
+
+  <target name="testFilter7" depends="init">
+    <copy file="input/Junk7.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf tab="add" cr="add" eof="asis" />
+      </filterchain>
+    </copy>
+    <assertequal junk="7" />
+  </target>
+
+  <target name="testFilter8" depends="init">
+    <copy file="input/Junk8.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="add" cr="add" eof="add" />
+      </filterchain>
+    </copy>
+    <assertequal junk="8" />
+  </target>
+
+  <target name="testFilter9" depends="init">
+    <copy file="input/Junk9.java" todir="result" overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="remove" cr="remove" eof="remove" />
+      </filterchain>
+    </copy>
+    <assertequal junk="9" />
+  </target>
+
+  <target name="testCannotDoubleEof" depends="test8">
+    <fixcrlf file="result/Junk8.java"
+             javafiles="true" tab="add" cr="add" eof="add" />
+    <assertequal junk="8" />
+  </target>
+
+  <target name="testTabInLiteralInComment">
+    <copy file="input/tab_in_literal_in_comment" todir="result"
+          overwrite="true">
+      <filterchain>
+        <fixcrlf javafiles="true" tab="remove" eol="lf" fixlast="false" />
+      </filterchain>
+    </copy>
+    <assertequal name="tab_in_literal_in_comment" />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk1.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk1.java
new file mode 100644
index 0000000..7321b8d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk1.java
@@ -0,0 +1,12 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk2.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk2.java
new file mode 100644
index 0000000..7321b8d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk2.java
@@ -0,0 +1,12 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk3.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk3.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk3.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk4.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk4.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk4.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk5.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk5.java
new file mode 100644
index 0000000..bba01a5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk5.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have      a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '   ';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk6.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk6.java
new file mode 100644
index 0000000..7321b8d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk6.java
@@ -0,0 +1,12 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk7.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk7.java
new file mode 100644
index 0000000..7321b8d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk7.java
@@ -0,0 +1,12 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk8.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk8.java
new file mode 100644
index 0000000..82a8e84
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk8.java
@@ -0,0 +1,13 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

+
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk9.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk9.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Junk9.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Mac2Unix b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Mac2Unix
new file mode 100644
index 0000000..9ce4f53
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/Mac2Unix
@@ -0,0 +1,4 @@
+line1
+line2
+
+line3
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.dos b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.dos
new file mode 100644
index 0000000..bd956ea
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.dos
@@ -0,0 +1,2 @@
+1

+2

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.mac b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.mac
new file mode 100644
index 0000000..c359b10
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.mac
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.unix b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.unix
new file mode 100644
index 0000000..1191247
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/crcrlf.unix
@@ -0,0 +1,2 @@
+1
+2
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlast.dos b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlast.dos
new file mode 100644
index 0000000..319d4fc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlast.dos
@@ -0,0 +1,2 @@
+12345

+6789

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlastfalse.mac b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlastfalse.mac
new file mode 100644
index 0000000..6f7d6bf
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/fixlastfalse.mac
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.ascii b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.ascii
new file mode 100644
index 0000000..ac2dd81
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.ascii
@@ -0,0 +1,2 @@
+Line1
+Line2
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.utf16 b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.utf16
new file mode 100644
index 0000000..8ffb4e4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/input.lf.utf16
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/longlines.lf b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/longlines.lf
new file mode 100644
index 0000000..fdef172
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/longlines.lf
@@ -0,0 +1,2 @@
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+abc
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/tab_in_literal_in_comment b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/tab_in_literal_in_comment
new file mode 100644
index 0000000..553e9fc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/expected/tab_in_literal_in_comment
@@ -0,0 +1,2 @@
+// "    "
+
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk1.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk1.java
new file mode 100644
index 0000000..ad69747
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk1.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+	System.out.println("I have	a tab");
+	//	Here is a comment with an embedded tab
+	if (mybool) {	/* Here is a multi-line
+			   (with embedded'	'tab)
+	    Comment */char mychar = '	';	//<-tab->	<-
+	} // end of if (mybool)
+	
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk2.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk2.java
new file mode 100644
index 0000000..ad69747
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk2.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+	System.out.println("I have	a tab");
+	//	Here is a comment with an embedded tab
+	if (mybool) {	/* Here is a multi-line
+			   (with embedded'	'tab)
+	    Comment */char mychar = '	';	//<-tab->	<-
+	} // end of if (mybool)
+	
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk3.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk3.java
new file mode 100644
index 0000000..ad69747
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk3.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+	System.out.println("I have	a tab");
+	//	Here is a comment with an embedded tab
+	if (mybool) {	/* Here is a multi-line
+			   (with embedded'	'tab)
+	    Comment */char mychar = '	';	//<-tab->	<-
+	} // end of if (mybool)
+	
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk4.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk4.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk4.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk5.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk5.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk5.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk6.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk6.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk6.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk7.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk7.java
new file mode 100644
index 0000000..3427166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk7.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+        System.out.println("I have	a tab");
+        //      Here is a comment with an embedded tab
+        if (mybool) {   /* Here is a multi-line
+                           (with embedded'      'tab)
+            Comment */char mychar = '	';      //<-tab->       <-
+        } // end of if (mybool)
+        
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk8.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk8.java
new file mode 100644
index 0000000..ad69747
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk8.java
@@ -0,0 +1,12 @@
+public class Junk1 {
+    public boolean mybool;
+    public static void main (String[] args) {
+	System.out.println("I have	a tab");
+	//	Here is a comment with an embedded tab
+	if (mybool) {	/* Here is a multi-line
+			   (with embedded'	'tab)
+	    Comment */char mychar = '	';	//<-tab->	<-
+	} // end of if (mybool)
+	
+    } // end of main ()
+}
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk9.java b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk9.java
new file mode 100644
index 0000000..82a8e84
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Junk9.java
@@ -0,0 +1,13 @@
+public class Junk1 {

+    public boolean mybool;

+    public static void main (String[] args) {

+	System.out.println("I have	a tab");

+	//	Here is a comment with an embedded tab

+	if (mybool) {	/* Here is a multi-line

+			   (with embedded'	'tab)

+	    Comment */char mychar = '	';	//<-tab->	<-

+	} // end of if (mybool)

+	

+    } // end of main ()

+}

+
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Mac2Unix b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Mac2Unix
new file mode 100644
index 0000000..7da7c5e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/Mac2Unix
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/crcrlf b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/crcrlf
new file mode 100644
index 0000000..31e10f2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/crcrlf
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/fixlastfalse.lf b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/fixlastfalse.lf
new file mode 100644
index 0000000..330ca6f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/fixlastfalse.lf
@@ -0,0 +1,2 @@
+12345
+6789
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/input.crlf.utf16 b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/input.crlf.utf16
new file mode 100644
index 0000000..81ad581
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/input.crlf.utf16
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/longlines.crlf b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/longlines.crlf
new file mode 100644
index 0000000..f379d34
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/longlines.crlf
@@ -0,0 +1,2 @@
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

+abc

diff --git a/trunk/src/etc/testcases/taskdefs/fixcrlf/input/tab_in_literal_in_comment b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/tab_in_literal_in_comment
new file mode 100644
index 0000000..d8878c1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/fixcrlf/input/tab_in_literal_in_comment
@@ -0,0 +1,2 @@
+// "	"
+
diff --git a/trunk/src/etc/testcases/taskdefs/foo.properties b/trunk/src/etc/testcases/taskdefs/foo.properties
new file mode 100644
index 0000000..e4a8152
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/foo.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+foo=Foo
diff --git a/trunk/src/etc/testcases/taskdefs/get.xml b/trunk/src/etc/testcases/taskdefs/get.xml
new file mode 100644
index 0000000..0296244
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/get.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <get/>
+  </target>
+
+  <target name="test2">
+    <get src=""/>
+  </target>
+
+  <target name="test3">
+    <get src="" dest=""/>
+  </target>
+
+  <target name="test4">
+    <get src="" dest=""/>
+  </target>
+
+  <target name="test5">
+    <get src="http://www.apache.org/" dest=""/>
+  </target>
+
+  <target name="test6">
+    <get src="http://www.apache.org/" dest="get.tmp"/>
+
+    <fileset id="t6" file="get.tmp" />
+    <pathconvert property="t6" refid="t6" setonempty="false" />
+
+    <fail message="get failed">
+      <condition>
+        <not>
+          <isset property="t6" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testUseTimestamp" depends="-90s,-timestamp" />
+
+  <target name="-90s">
+    <property name="off" value="-90" />
+    <property name="unit" value="second" />
+  </target>
+
+  <target name="testUseTomorrow" depends="+1d,-timestamp" />
+
+  <target name="+1d">
+    <property name="off" value="1" />
+    <property name="unit" value="day" />
+  </target>
+
+  <target name="-timestamp">
+    <property name="pat" value="yyyyMMddHHmm" />
+
+    <tstamp>
+      <format property="dt" pattern="${pat}" offset="${off}" unit="${unit}" />
+    </tstamp>
+
+    <touch file="get.tmp" datetime="${dt}" pattern="${pat}" />
+
+    <get src="http://www.w3.org/MarkUp" dest="get.tmp"
+         usetimestamp="true" verbose="true" />
+
+    <fileset id="ts" file="get.tmp">
+      <date when="equal" datetime="${dt}" pattern="${pat}" />
+    </fileset>
+
+    <pathconvert property="ts" refid="ts" setonempty="false" />
+
+    <fail message="get w/ timestamp should have failed.">
+      <condition>
+        <not>
+          <isset property="ts" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="cleanup">
+    <delete>
+      <fileset dir="${basedir}" includes="get.tmp" />
+    </delete>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/gunzip.xml b/trunk/src/etc/testcases/taskdefs/gunzip.xml
new file mode 100644
index 0000000..ea75d54
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/gunzip.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <gunzip/>
+  </target>
+
+  <target name="test2">
+    <gunzip src=""/>
+  </target>
+
+  <target name="cleanup">
+    <delete file="asf-logo.gif" />
+  </target>
+
+  <target name="testGzipTask">
+    <ant antfile="gzip.xml" target="realTest" />
+    <gunzip src="asf-logo.gif.gz" dest="asf-logo.gif" />
+    <ant antfile="gzip.xml" target="cleanup" />
+  </target>
+
+  <target name="realTest">
+    <gunzip src="expected/asf-logo.gif.gz" dest="asf-logo.gif" />
+  </target>
+
+  <target name="realTestWithResource">
+    <gunzip dest="asf-logo.gif">
+      <file file="expected/asf-logo.gif.gz"/>
+    </gunzip>
+  </target>
+
+  <target name="testDocumentationClaimsOnCopy">
+    <copy todir=".">
+      <gzipresource>
+        <file file="expected/asf-logo.gif.gz"/>
+      </gzipresource>
+      <mapper type="glob" from="*.gz" to="*"/>
+    </copy>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/gzip.xml b/trunk/src/etc/testcases/taskdefs/gzip.xml
new file mode 100644
index 0000000..f1c4262
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/gzip.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <gzip/>
+  </target>
+
+  <target name="test2">
+    <gzip src=""/>
+  </target>
+
+  <target name="test3">
+    <gzip zipfile=""/>
+  </target>
+
+  <target name="test4">
+    <gzip src="gzip.xml" zipfile="." />
+  </target>
+
+  <target name="realTest">
+    <gzip src="../asf-logo.gif" zipfile="asf-logo.gif.gz" />
+  </target>
+
+  <target name="realTestWithResource">
+    <gzip zipfile="asf-logo.gif.gz">
+      <file file="../asf-logo.gif"/>
+    </gzip>    
+  </target>
+
+  <target name="testDateCheck">
+    <touch file="asf-logo.gif.gz"/>
+    <gzip src="../asf-logo.gif" zipfile="asf-logo.gif.gz" />
+  </target>
+
+  <target name="cleanup">
+    <delete file="asf-logo.gif.gz" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/a.xml b/trunk/src/etc/testcases/taskdefs/import/a.xml
new file mode 100644
index 0000000..cf4e7a5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/a.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="A">
+  <target name="x"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/b.xml b/trunk/src/etc/testcases/taskdefs/import/b.xml
new file mode 100644
index 0000000..f95cf01
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/b.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="B">
+   <import file="a.xml"/>
+   <target name="x" depends="A.x"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/bad.xml b/trunk/src/etc/testcases/taskdefs/import/bad.xml
new file mode 100644
index 0000000..a3a0647
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/bad.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+<<<
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/c.xml b/trunk/src/etc/testcases/taskdefs/import/c.xml
new file mode 100644
index 0000000..d92fbc7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/c.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="C">
+   <import file="a.xml"/>
+   <import file="b.xml"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/import.xml b/trunk/src/etc/testcases/taskdefs/import/import.xml
new file mode 100644
index 0000000..f84d8e3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/import.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="import-test" default="main" basedir=".">
+  <echo>Before import</echo>        
+
+  <import file="imported.xml"/>
+
+  <echo message="After import"/>
+  
+  <target name="import-init">
+     <echo message="In import-init" />
+  </target>
+
+  <target name="main" depends="imported">
+    <echo message="In main"/>
+  </target>
+
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/import_bad_import.xml b/trunk/src/etc/testcases/taskdefs/import/import_bad_import.xml
new file mode 100644
index 0000000..8ff5367
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/import_bad_import.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <import file="bad.xml"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/import_same_target.xml b/trunk/src/etc/testcases/taskdefs/import/import_same_target.xml
new file mode 100644
index 0000000..f2b1933
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/import_same_target.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <target name="t"/>
+  <target name="t"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/imported.xml b/trunk/src/etc/testcases/taskdefs/import/imported.xml
new file mode 100644
index 0000000..19dfdb0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/imported.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="imported-test" default="imported" basedir=".">
+
+  <echo message="In imported top"/>
+ 
+  <target name="imported" depends="import-init" >
+    <echo message="In imported target" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/importtargetfirst.xml b/trunk/src/etc/testcases/taskdefs/import/importtargetfirst.xml
new file mode 100644
index 0000000..835191b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/importtargetfirst.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <echo>Importing targetfirst</echo>
+  <import file="targetfirst.xml"/>
+  <echo>After importing</echo>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/recursive-selfimport.xml b/trunk/src/etc/testcases/taskdefs/import/recursive-selfimport.xml
new file mode 100644
index 0000000..5ce28d2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/recursive-selfimport.xml
@@ -0,0 +1,5 @@
+<project>
+  <echo>Before import: ${foo}</echo>
+  <property name="foo" value="bar"/>
+  <import file="./recursive-selfimport.xml"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/same_target.xml b/trunk/src/etc/testcases/taskdefs/import/same_target.xml
new file mode 100644
index 0000000..1a14fe5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/same_target.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <import file="import_same_target.xml"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential-inner.xml b/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential-inner.xml
new file mode 100644
index 0000000..cc2a681
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential-inner.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <target name="within-imported">
+    <property name="foo" value="bar"/>
+    <path id="baz">
+      <pathelement location="."/>
+    </path>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential.xml b/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential.xml
new file mode 100644
index 0000000..fdd68b0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/subdir/importinsequential.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <sequential>
+    <import file="importinsequential-inner.xml"/>
+  </sequential>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget-inner.xml b/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget-inner.xml
new file mode 100644
index 0000000..cd5086e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget-inner.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <property name="foo" value="bar"/>
+  <path id="baz">
+    <pathelement location="."/>
+  </path>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget.xml b/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget.xml
new file mode 100644
index 0000000..2dfa370
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/subdir/importintarget.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <target name="do-import">
+    <import file="importintarget-inner.xml"/>
+  </target>
+
+  <target name="no-import"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/subdir/serial.xml b/trunk/src/etc/testcases/taskdefs/import/subdir/serial.xml
new file mode 100644
index 0000000..360f9d1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/subdir/serial.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="serial">
+  <import file="../unnamed1.xml"/>
+  <import file="../unnamed2.xml"/>
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/import/symlinks/d1/p1.xml b/trunk/src/etc/testcases/taskdefs/import/symlinks/d1/p1.xml
new file mode 100644
index 0000000..d1b792c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/symlinks/d1/p1.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="p1" default="run">
+    <import file="../d2/p2.xml"/>
+    <import file="../d3b/p3.xml"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/symlinks/d2/p2.xml b/trunk/src/etc/testcases/taskdefs/import/symlinks/d2/p2.xml
new file mode 100644
index 0000000..51948c9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/symlinks/d2/p2.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="p2"/>
diff --git a/trunk/src/etc/testcases/taskdefs/import/symlinks/d3a/p3.xml b/trunk/src/etc/testcases/taskdefs/import/symlinks/d3a/p3.xml
new file mode 100644
index 0000000..3185845
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/symlinks/d3a/p3.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="p3"/>
diff --git a/trunk/src/etc/testcases/taskdefs/import/targetfirst.xml b/trunk/src/etc/testcases/taskdefs/import/targetfirst.xml
new file mode 100644
index 0000000..06c1fbe
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/targetfirst.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <target name="first"/>
+  <echo>After target first</echo>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/import/unnamed1.xml b/trunk/src/etc/testcases/taskdefs/import/unnamed1.xml
new file mode 100644
index 0000000..6fc7fde
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/unnamed1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="test">
+  <import file="unnamed2.xml"/>
+
+  <echo message="Unnamed1.xml" level="info"/>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/import/unnamed2.xml b/trunk/src/etc/testcases/taskdefs/import/unnamed2.xml
new file mode 100644
index 0000000..c0fd7c6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/unnamed2.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="test">
+  <echo message="Unnamed2.xml" level="info"/>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/import/unnamedImport.xml b/trunk/src/etc/testcases/taskdefs/import/unnamedImport.xml
new file mode 100644
index 0000000..13b3a85
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/import/unnamedImport.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="unnamed-import" default="test">
+
+  <import file="unnamed1.xml"/>
+
+  <target name="test">
+    <echo level="info">Tests import of unnamed projects</echo>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/initializeclass.xml b/trunk/src/etc/testcases/taskdefs/initializeclass.xml
new file mode 100644
index 0000000..6e07991
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/initializeclass.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="test" default="all">
+  <target name="all"/>
+
+  <target name="forked">
+    <java fork="true" output="forkedout" failonerror="true"
+          className="org.apache.tools.ant.taskdefs.dir1.B">
+
+      <classpath>
+        <pathelement path="../../../../build/testcases"/>
+        <pathelement location="${java.home}/lib/classes.zip" />
+      </classpath>
+    </java>
+  </target>
+
+  <target name="unforked">
+    <java className="org.apache.tools.ant.taskdefs.dir1.B">
+      <classpath>
+        <pathelement path="../../../../build/testcases"/>
+        <pathelement location="${java.home}/lib/classes.zip" />
+      </classpath>
+    </java>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/input.properties b/trunk/src/etc/testcases/taskdefs/input.properties
new file mode 100644
index 0000000..c0025a3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/input.properties
@@ -0,0 +1,25 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+Press\ Return\ key\ to\ continue...=test
+All\ data\ is\ going\ to\ be\ deleted\ from\ DB\ continue?=test
+All\ data\ is\ going\ to\ be\ deleted\ from\ db\ continue\ (y/n)?=y
+Please\ enter\ db-username\:=scott
+#
+# JDK 1.1 doesn't seem to handle blanks in the property key
+#
+Press_Return_key_to_continue...=test
+All_data_is_going_to_be_deleted_from_DB_continue?=test
+All_data_is_going_to_be_deleted_from_db_continue_(y/n)?=y
+Please_enter_db_username=scott
diff --git a/trunk/src/etc/testcases/taskdefs/input.stdin b/trunk/src/etc/testcases/taskdefs/input.stdin
new file mode 100644
index 0000000..3bd1f0e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/input.stdin
@@ -0,0 +1,2 @@
+foo
+bar
diff --git a/trunk/src/etc/testcases/taskdefs/input.xml b/trunk/src/etc/testcases/taskdefs/input.xml
new file mode 100644
index 0000000..d204b79
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/input.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="input-test" basedir="." default="test1">
+
+  <target name="test1">
+    <input>Press Return key to continue...</input>
+  </target>
+
+  <target name="test2">
+    <input message="Press Return key to continue..." />
+  </target>
+
+  <target name="test3">
+    <input message="All data is going to be deleted from DB continue?"
+           validargs="y,n"
+           />
+  </target>
+
+  <target name="test5">
+    <input message="All data is going to be deleted from db continue (y/n)?"
+           validargs="y,n"
+           />
+  </target>
+
+  <target name="test6">
+    <input message="Please enter db-username:"
+           addproperty="db.user"
+           />
+  </target>
+
+  <target name="testPropertyFileInlineHandler">
+    <input message="Press Return key to continue..." addproperty="test">
+      <handler type="propertyfile" />
+    </input>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${test}" arg2="test" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testDefaultInlineHandler">
+    <input message="Press Return key to continue..." addproperty="test">
+      <handler type="default" />
+    </input>
+    <fail message="$${test} = ${test}">
+      <condition>
+        <not>
+          <equals arg1="${test}" arg2="foo" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testGreedyInlineHandler">
+    <input message="Press Return key to continue..." addproperty="test">
+      <handler type="greedy" />
+    </input>
+    <loadfile srcFile="input.stdin" property="input" />
+    <fail message="$${test} = ${test}">
+      <condition>
+        <not>
+          <equals arg1="${test}" arg2="${input}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testGreedyInlineHandlerClassname">
+    <input message="Press Return key to continue..." addproperty="test">
+      <handler classname="org.apache.tools.ant.input.GreedyInputHandler" />
+    </input>
+    <loadfile srcFile="input.stdin" property="input" />
+    <fail message="$${test} = ${test}">
+      <condition>
+        <not>
+          <equals arg1="${test}" arg2="${input}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testGreedyInlineHandlerRefid">
+    <typedef name="greedy"
+             classname="org.apache.tools.ant.input.GreedyInputHandler" />
+    <greedy id="greedy" />
+
+    <input message="Press Return key to continue..." addproperty="test">
+      <handler refid="greedy" />
+    </input>
+    <loadfile srcFile="input.stdin" property="input" />
+    <fail message="$${test} = ${test}">
+      <condition>
+        <not>
+          <equals arg1="${test}" arg2="${input}" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/jar.xml b/trunk/src/etc/testcases/taskdefs/jar.xml
new file mode 100644
index 0000000..30858b2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/jar.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="jar-test" basedir="." default="test1">
+
+  <property name="tmp.jar" location="tmp.jar"/>
+  <property name="tmp.dir" location="jartmp"/>
+  <property name="tmp.zip" location="tmp.zip"/>
+  <property name="tmp1.dir" location="jartmp1"/>
+  <property name="tmp2.dir" location="jartmp2"/>
+
+  <target name="test1">
+    <jar/>
+  </target>
+
+  <target name="test2">
+    <jar
+    	jarfile="jar.tmp"
+    	manifest="none"
+    />
+  </target>
+
+  <target name="test3">
+    <jar
+    	destfile="jar.tmp"
+	whenempty="format C: /y" 
+    />
+  </target>
+
+  <target name="test4">
+   <jar
+    	destfile="${tmp.jar}"
+	basedir="."
+	includes="jar.xml"
+    />
+  </target>
+
+  <target name="testNoRecreateWithUpdate">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="jar.xml"
+         update="true"
+    />
+  </target>
+
+  <target name="testRecreateNewerFileSetup" depends="test4">
+    <touch file="jar.xml"/>
+  </target>
+
+  <target name="testRecreateWithoutUpdateAdditionalFiles">
+    <jar
+         destfile="${tmp.jar}"
+         includes="*.xml"
+         basedir="."
+    />
+  </target>
+
+  <target name="testRecreateWithUpdateAdditionalFiles">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="*.xml"
+         update="true"
+    />
+  </target>
+
+  <target name="testRecreateWithoutUpdateNewerFile">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="jar.xml"
+    />
+  </target>
+
+  <target name="testRecreateWithUpdateNewerFile">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="jar.xml"
+         update="true"
+    />
+  </target>
+
+  <target name="testManifestStaysIntact">
+    <mkdir dir="${tmp.dir}"/>
+    <manifest file="${tmp.dir}/manifest">
+      <attribute name="Foo" value="bar"/>
+    </manifest>
+    <jar destfile="${tmp.jar}" basedir="." includes="jar.xml"
+         manifest="${tmp.dir}/manifest"/>
+    <sleep seconds="3"/>
+    <touch file="jar.xml"/>
+    <jar destfile="${tmp.jar}" basedir="." includes="jar.xml"
+         update="true"/>
+    <unjar src="${tmp.jar}" dest="${tmp.dir}"/>
+  </target>    
+
+  <target name="testNoRecreateBasedirExcludesWithUpdate">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="j*.xml"
+         excludes="java.xml"
+         update="true"
+    />
+  </target>
+
+  <target name="testNoRecreateBasedirExcludesWithoutUpdate">
+    <jar
+         destfile="${tmp.jar}"
+         basedir="."
+         includes="j*.xml"
+         excludes="java.xml"
+    />
+  </target>
+
+  <target name="makezip">
+    <zip destfile="${tmp.zip}"
+         basedir="." includes="j*.xml"/>
+  </target>
+
+  <target name="testNoRecreateZipfilesetExcludesWithUpdate"
+          depends="makezip">
+    <jar destfile="${tmp.jar}"
+         update="true">
+      <zipfileset src="${tmp.zip}" excludes="java.xml"/>
+    </jar>
+  </target>
+
+  <target name="testNoRecreateZipfilesetExcludesWithoutUpdate"
+          depends="makezip">
+    <jar destfile="${tmp.jar}">
+      <zipfileset src="${tmp.zip}" excludes="java.xml"/>
+    </jar>
+  </target>
+
+  <target name="testRecreateZipfilesetWithoutUpdateAdditionalFiles"
+          depends="makezip">
+    <jar destfile="${tmp.jar}">
+      <zipfileset src="${tmp.zip}"/>
+    </jar>
+  </target>
+
+  <target name="testRecreateZipfilesetWithUpdateAdditionalFiles"
+          depends="makezip">
+    <jar destfile="${tmp.jar}"
+         update="true">
+      <zipfileset src="${tmp.zip}"/>
+    </jar>
+  </target>
+
+  <target name="testRecreateZipfilesetWithoutUpdateNewerFile"
+          depends="makezip">
+    <jar destfile="${tmp.jar}">
+      <zipfileset src="${tmp.zip}" includes="jar.xml"/>
+    </jar>
+  </target>
+
+  <target name="testRecreateZipfilesetWithUpdateNewerFile"
+          depends="makezip">
+    <jar destfile="${tmp.jar}"
+         update="true">
+      <zipfileset src="${tmp.zip}" includes="jar.xml"/>
+    </jar>
+  </target>
+
+  <target name="cleanup">
+    <delete file="${tmp.jar}" />
+    <delete file="${tmp.jar}2" />
+    <delete dir="${tmp.dir}"/>
+    <delete file="${tmp.zip}" />
+    <delete dir="${tmp1.dir}"/>
+    <delete dir="${tmp2.dir}"/>
+  </target>
+
+  <target name="testCreateWithEmptyFilesetSetUp">
+    <mkdir dir="${tmp1.dir}"/>
+    <mkdir dir="${tmp2.dir}"/>
+    <echo file="${tmp2.dir}/foo.txt" message="foo"/>
+  </target>
+
+  <target name="testCreateWithEmptyFileset">
+    <jar destfile="${tmp.jar}">
+      <fileset dir="${tmp1.dir}">
+        <include name="**/*.doesNotExist"/>
+      </fileset>
+      <fileset dir="${tmp2.dir}">
+        <include name="**/foo.txt"/>
+      </fileset>
+    </jar>
+  </target>
+
+  <!-- bug 17780 -->
+  <target name="testUpdateIfOnlyManifestHasChanged"
+          depends="test4">
+    <jar destfile="${tmp.jar}" update="true">
+      <manifest>
+        <attribute name="Foo" value="bar"/>
+      </manifest>
+    </jar>
+    <mkdir dir="${tmp.dir}"/>
+    <unzip src="${tmp.jar}" dest="${tmp.dir}"/>
+  </target>
+
+  <!-- bugs 10262 and 16972 -->
+  <target name="testIndexTests">
+    <mkdir dir="${tmp.dir}/META-INF"/>
+    <touch file="${tmp.dir}/META-INF/INDEX.LIST"/>
+    <touch file="${tmp.dir}/foo"/>
+    <mkdir dir="${tmp.dir}/sub"/>
+    <touch file="${tmp.dir}/sub/foo"/>
+    <jar destfile="${tmp.jar}" index="yes" basedir="${tmp.dir}"/>
+  </target>
+    <!-- bug 32802 -->
+  <target name="testManifestOnlyJar">
+    <mkdir dir="${tmp.dir}"/>  
+    <jar destfile="${tmp.jar}" duplicate="preserve">
+      <manifest>
+        <attribute name="Foo" value="bar"/>
+      </manifest>
+    </jar>
+    <mkdir dir="${tmp.dir}"/>
+    <unzip src="${tmp.jar}" dest="${tmp.dir}"/>
+
+  </target>
+
+  <!-- bug 37237 -->
+  <target name="testIndexJarsPlusJarMarker">
+    <mkdir dir="${tmp.dir}/a/b/c"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}"/>
+    <delete dir="${tmp.dir}/a" quiet="true"/>
+    <mkdir dir="${tmp.dir}/d/e/f"/>
+    <jar destfile="${tmp.jar}2" basedir="${tmp.dir}" index="true">
+      <indexjars>
+        <fileset file="${tmp.jar}"/>
+      </indexjars>
+    </jar>
+  </target>
+    
+  <target name="testNoVersionInfoNoStrict">
+    <mkdir dir="${tmp.dir}"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}"/>
+  </target>  
+
+  <target name="testNoVersionInfoFail">
+    <mkdir dir="${tmp.dir}"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}" strict="fail"/>
+  </target>  
+
+  <target name="testNoVersionInfoIgnore">
+    <mkdir dir="${tmp.dir}"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}" strict="ignore"/>
+  </target>  
+
+  <target name="testNoVersionInfoWarn">
+    <mkdir dir="${tmp.dir}"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}" strict="warn"/>
+  </target>  
+    
+  <!-- see http://java.sun.com/j2se/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning -->  
+  <target name="testHasVersionInfo">
+    <mkdir dir="${tmp.dir}"/>
+    <jar destfile="${tmp.jar}" basedir="${tmp.dir}" strict="fail">
+      <manifest>
+        <attribute name="Implementation-Title"   value="Packaging Version Test"/>
+        <attribute name="Implementation-Version" value="1.0"/>
+        <attribute name="Implementation-Vendor"  value="Apache Software Foundation"/>
+      </manifest>
+    </jar>
+  </target>  
+
+    
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/java.xml b/trunk/src/etc/testcases/taskdefs/java.xml
new file mode 100644
index 0000000..4465c11
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/java.xml
@@ -0,0 +1,397 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="java-test" basedir="." default="foo">
+  <fail unless="tests-classpath.value"
+      message="the property tests-classpath.value is required by this test" />
+  <!-- this property gets overridden programmatically-->
+  <property name="timeToWait" value="4"/>
+  <!-- this property gets overridden programmatically-->
+  <property name="logFile" value="spawn.log"/>
+  <property name="tmp" location="${java.io.tmpdir}"/>
+  <property name="app"
+    value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" />
+
+  <property name="app2"
+    value="org.apache.tools.ant.taskdefs.JavaTest$$ExceptingEntryPoint" />
+
+  <property name="spawnapp"
+    value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" />
+
+  <property name="pipeapp"
+    value="org.apache.tools.ant.taskdefs.JavaTest$$PipeEntryPoint" />
+
+  <target name="testNoJarNoClassname">
+    <java/>
+  </target>
+
+  <target name="testJarNoFork">
+    <java jar="test.jar" fork="false"/>
+  </target>
+
+
+  <target name="testJarAndClassName">
+    <java jar="test.jar" classname="${app}" />
+  </target>
+
+  <target name="testClassnameAndJar">
+    <java classname="${app}" jar="test.jar"  />
+  </target>
+
+  <target name="testRun">
+    <fail unless="tests-classpath.value" />
+    <java classname="${app}"
+      classpath="${tests-classpath.value}"/>
+  </target>
+
+  <target name="testRunFail">
+    <java classname="${app}"
+      classpath="${tests-classpath.value}"
+      >
+      <arg value="2"/>
+    </java>
+  </target>
+
+  <target name="testRunFailFoe">
+    <java classname="${app}"
+      classpath="${tests-classpath.value}"
+      failonerror="true">
+      <arg value="2"/>
+    </java>
+  </target>
+
+  <target name="testRunFailFoeFork">
+    <java classname="${app}"
+        classpath="${tests-classpath.value}"
+        failonerror="true"
+        fork="true">
+        <arg value="2"/>
+    </java>
+  </target>
+
+  <target name="testExcepting">
+    <java classname="${app2}"
+        classpath="${tests-classpath.value}"
+        >
+    </java>
+  </target>
+
+  <target name="testExceptingFork">
+    <java classname="${app2}"
+          classpath="${tests-classpath.value}"
+          fork="true">
+    </java>
+  </target>
+
+  <target name="testExceptingFoe">
+    <java classname="${app2}"
+        classpath="${tests-classpath.value}"
+        failonerror="true">
+    </java>
+  </target>
+
+  <target name="testExceptingFoeFork">
+    <java classname="${app2}"
+        classpath="${tests-classpath.value}"
+        failonerror="true"
+        fork="true">
+    </java>
+  </target>
+
+  <target name="testResultPropertyZero">
+    <java classname="${app}"
+        classpath="${tests-classpath.value}"
+        resultproperty="exitcode"
+        fork="true"
+        >
+    </java>
+    <echo message="exitcode = ${exitcode}"/>
+  </target>
+
+  <target name="testResultPropertyNonZero">
+    <java classname="${app}"
+        classpath="${tests-classpath.value}"
+        resultproperty="exitcode"
+        failonerror="false"
+        fork="true"
+        >
+        <arg value="2"/>
+    </java>
+    <echo message="exitcode = ${exitcode}"/>
+  </target>
+
+   <target name="testResultPropertyZeroNoFork">
+     <java classname="${app}"
+         classpath="${tests-classpath.value}"
+         resultproperty="exitcode"
+         fork="false"
+         >
+         <permissions/>
+     </java>
+     <echo message="exitcode = ${exitcode}"/>
+   </target>
+ 
+    <target name="testResultPropertyNonZeroNoFork">
+        <java classname="${app}"
+              classpath="${tests-classpath.value}"
+              resultproperty="exitcode"
+              failonerror="false"
+              fork="false">
+            <arg value="-1"/>
+            <permissions/>
+        </java>
+        <echo message="exitcode = ${exitcode}"/>
+    </target>
+
+    <target name="testRunFailWithFailOnError">
+      <java classname="${app}"
+        classpath="${tests-classpath.value}"
+        failonerror="true"
+        >
+        <arg value="2"/>
+      </java>
+    </target>
+
+    <target name="testRunSuccessWithFailOnError">
+      <java classname="${app}"
+        classpath="${tests-classpath.value}"
+        failonerror="true"
+        >
+        <arg value="0"/>
+      </java>
+    </target>
+
+    <target name="testSpawn">
+        <java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}">
+            <arg value="${timeToWait}"/>
+            <arg value="${logFile}" />
+        </java>
+    </target>
+
+    <!--redirection testcases don't want to run under junit unless forked-->
+    <target name="redirect1">
+        <property name="outfile" location="${tmp}/redirect.out" />
+
+        <java classname="${pipeapp}"
+              classpath="${tests-classpath.value}"
+              inputstring="foo"
+              fork="true"
+              output="${outfile}"
+              errorproperty="redirect.err">
+            <arg value="out" />
+        </java>
+
+        <!-- let dumb Windows catch up -->
+        <waitfor maxwait="30000">
+            <available file="${outfile}" />
+        </waitfor>
+        <waitfor maxwait="30000">
+            <length file="${outfile}" length="1" when="greater" />
+        </waitfor>
+
+        <loadfile property="redirect.out.contents" srcfile="${outfile}" />
+
+        <condition property="r1file">
+            <equals arg1="${redirect.out.contents}" arg2="foo" />
+        </condition>
+
+        <fail unless="r1file">${outfile}:
+&quot;${redirect.out.contents}&quot; expected &quot;foo&quot;</fail>
+
+        <condition property="r1prop">
+            <equals arg1="${redirect.err}" arg2="" />
+        </condition>
+
+        <fail unless="r1prop">
+redirect.err=&quot;${redirect.err}&quot; should be empty</fail>
+
+    </target>
+
+    <target name="redirect2" depends="redirect1">
+        <property name="outfile" location="${tmp}/redirect.out" />
+
+        <java classname="${pipeapp}"
+              classpath="${tests-classpath.value}"
+              inputstring="bar"
+              append="true"
+              fork="true"
+              output="${outfile}"
+              errorproperty="redirect.err">
+            <arg value="both" />
+        </java>
+
+        <!-- let dumb Windows catch up -->
+        <waitfor maxwait="30000">
+            <available file="${outfile}" />
+        </waitfor>
+        <waitfor maxwait="30000">
+            <length file="${outfile}" length="1" when="greater" />
+        </waitfor>
+        
+        
+        <loadfile property="redirect.out.contents2" srcfile="${outfile}" />
+
+        <condition property="r2file">
+            <equals arg1="${redirect.out.contents2}" arg2="foobar" />
+        </condition>
+
+        <fail unless="r2file">${outfile}:
+&quot;${redirect.out.contents2}&quot; expected &quot;foobar&quot;</fail>
+
+        <condition property="r2prop">
+            <!-- property should not change -->
+            <equals arg1="${redirect.err}" arg2="" />
+        </condition>
+
+        <fail unless="r2prop">
+redirect.err=&quot;${redirect.err}&quot; should be empty</fail>
+
+    </target>
+
+    <target name="redirect3">
+        <property name="outfile" location="${tmp}/redirect.out" />
+        <property name="errfile" location="${tmp}/redirect.err" />
+
+        <java classname="${pipeapp}"
+              classpath="${tests-classpath.value}"
+              inputstring="foo"
+              fork="true"
+              output="${outfile}"
+              error="${errfile}">
+            <arg value="both" />
+        </java>
+
+        <!-- let dumb Windows catch up -->
+        <waitfor>
+            <and>
+                <available file="${outfile}" />
+                <available file="${errfile}" />
+            </and>
+        </waitfor>
+
+        <loadfile property="redirect.out.contents" srcfile="${outfile}" />
+
+        <condition property="r3file">
+            <equals arg1="${redirect.out.contents}" arg2="foo" />
+        </condition>
+
+        <fail unless="r3file">${outfile}:
+&quot;${redirect.out.contents}&quot; expected &quot;foo&quot;</fail>
+
+        <condition property="r3match">
+            <filesmatch file1="${outfile}" file2="${errfile}" />
+        </condition>
+
+        <fail unless="r3file">${errfile} differs from ${outfile}</fail>
+
+    </target>
+
+    <target name="redirector1">
+        <property name="outfile" location="${tmp}/redirector.out" />
+        <property name="errfile" location="${tmp}/redirector.err" />
+
+        <java taskname="foo" classname="${pipeapp}" fork="true"
+              classpath="${tests-classpath.value}">
+            <redirector inputstring="foo"
+                        output="${outfile}"
+                        error="${errfile}"
+                        createemptyfiles="false" />
+            <arg value="out" />
+        </java>
+
+        <!-- let dumb Windows catch up -->
+        <waitfor>
+            <available file="${outfile}" />
+        </waitfor>
+
+        <loadfile property="redirector.out.contents" srcfile="${outfile}" />
+
+        <condition property="ror1out">
+            <equals arg1="${redirector.out.contents}" arg2="foo" />
+        </condition>
+
+        <fail unless="ror1out">${outfile}:
+&quot;${redirector.out.contents}&quot; expected &quot;foo&quot;</fail>
+
+        <condition property="ror1noerr">
+            <not>
+                <available file="${errfile}" />
+            </not>
+        </condition>
+        <fail unless="ror1noerr">${errfile} exists but should not</fail>
+    </target>
+
+    <target name="redirector2" depends="redirector1">
+        <property name="outfile" location="${tmp}/redirector.out" />
+        <property name="errfile" location="${tmp}/redirector.err" />
+
+        <!-- fork here; some VMs can be ill-behaved with files,
+            such as W!nd0ws -->
+        <java taskname="foo" classname="${pipeapp}" fork="true"
+              classpath="${tests-classpath.value}">
+            <redirector inputstring="foo"
+                        append="true"
+                        output="${outfile}"
+                        error="${errfile}"
+                        createemptyfiles="false">
+                <errorfilterchain>
+                    <replacestring from="foo" to="bar" />
+                </errorfilterchain>
+            </redirector>
+            <arg value="both" />
+        </java>
+
+        <!-- let dumb Windows catch up -->
+        <waitfor>
+            <and>
+                <available file="${outfile}" />
+                <available file="${errfile}" />
+            </and>
+        </waitfor>
+
+        <loadfile property="redirector.out.contents2"
+                  srcfile="${outfile}" />
+
+        <loadfile property="redirector.err.contents"
+                  srcfile="${errfile}" />
+
+        <condition property="ror2out">
+            <equals arg1="${redirector.out.contents2}" arg2="foofoo" />
+        </condition>
+
+        <fail unless="ror1out">${outfile}:
+&quot;${redirector.out.contents}&quot; expected &quot;foofoo&quot;</fail>
+
+        <condition property="ror2err">
+            <equals arg1="${redirector.err.contents}" arg2="bar" />
+        </condition>
+
+        <fail unless="ror1out">${errfile}:
+&quot;${redirector.err.contents}&quot; expected &quot;bar&quot;</fail>
+
+    </target>
+
+    <target name="cleanup">
+        <delete>
+            <fileset file="${logFile}" />
+            <fileset dir="${tmp}" includes="redirect*" />
+        </delete>
+    </target>
+
+    <target name="foo" />
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/javadoc/java/ClassToJavadoc.java b/trunk/src/etc/testcases/taskdefs/javadoc/java/ClassToJavadoc.java
new file mode 100755
index 0000000..a41bdc1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/javadoc/java/ClassToJavadoc.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package etc.testcases.taskdefs.javadoc.java;
+
+/**
+ * This is a simple class to provide grist for the javadoc mill
+ * while testing it.
+ */
+public class ClassToJavadoc {
+    /**
+     * @param anArgument A String that is ignored
+     */
+    public void methodToJavadoc(String anArgument) { }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() { return this.getClass().getName(); }
+    
+    /**
+     * @return An arbitrary string.
+     */
+    public String anotherString() {return "An arbitrary string.";}
+}
diff --git a/trunk/src/etc/testcases/taskdefs/javadoc/javadoc.xml b/trunk/src/etc/testcases/taskdefs/javadoc/javadoc.xml
new file mode 100755
index 0000000..12e3396
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/javadoc/javadoc.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!--
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+-->
+<project name="javadoc" basedir=".">
+  <path id="path.dirset">
+    <dirset dir="." />
+  </path>
+  <property name="javadoc" location="javadoc"/>
+
+  <target name="tearDown">
+    <delete dir="${javadoc}" quiet="true"/>
+  </target>
+
+  <target name="dirsetPath">
+    <javadoc sourcepathref="path.dirset" packagenames="*" destdir="${javadoc}" />
+  </target>
+
+  <target name="dirsetPathWithoutPackagenames">
+    <javadoc sourcepathref="path.dirset" destdir="${javadoc}" />
+  </target>
+
+  <target name="nestedDirsetPath">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <sourcepath refid="path.dirset" />
+    </javadoc>
+  </target>
+
+  <path id="path.fileset">
+    <pathelement location="."/>
+    <fileset dir="java/" id="fileset.inpath">
+      <include name="**/*.java" />
+    </fileset>
+  </path>
+
+  <target name="filesetPath">
+    <javadoc sourcepathref="path.fileset" packagenames="*" destdir="${javadoc}" />
+  </target>
+
+  <target name="nestedFilesetPath">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <sourcepath refid="path.fileset" />
+    </javadoc>
+  </target>
+
+  <target name="nestedFilesetRefInPath">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <fileset refid="fileset.inpath" />
+    </javadoc>
+  </target>
+
+  <target name="nestedFilesetNoPatterns">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <fileset dir="java/"/>
+    </javadoc>
+  </target>
+
+  <target name="doublyNestedFileset">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <sourcefiles>
+        <fileset dir="java/" includes="**/*.java"/>
+      </sourcefiles>
+    </javadoc>
+  </target>
+
+  <target name="doublyNestedFilesetNoPatterns">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <sourcefiles>
+        <fileset dir="java/"/>
+      </sourcefiles>
+    </javadoc>
+  </target>
+
+  <path id="path.filelist">
+    <pathelement location="."/>
+    <filelist dir="java/">
+      <file name="ClassToJavadoc.java" />
+    </filelist>
+  </path>
+
+  <target name="filelistPath">
+    <javadoc sourcepathref="path.filelist" packagenames="*"
+      destdir="${javadoc}" />
+  </target>
+
+  <target name="nestedFilelistPath">
+    <javadoc packagenames="*" destdir="${javadoc}">
+      <sourcepath refid="path.filelist" />
+    </javadoc>
+  </target>
+
+  <!-- this property is set when the tests are run using ant's build.xml -->
+  <property name="root" location="../../../../.."/>
+
+  <path id="path.pathelement.path">
+    <pathelement path="${root}/src" />
+  </path>
+
+  <target name="pathelementPath">
+    <javadoc sourcepathref="path.pathelement.path"
+      packagenames="etc.testcases.taskdefs.javadoc.*" destdir="${javadoc}" />
+  </target>
+
+  <path id="path.pathelement.location">
+    <pathelement location="."/>
+    <pathelement path="java/ClassToJavadoc.java" />
+  </path>
+
+  <target name="pathelementLocationPath">
+    <javadoc sourcepathref="path.pathelement.location"
+      packagenames="*" destdir="${javadoc}" />
+  </target>
+
+  <target name="nestedSource">
+    <javadoc destdir="${javadoc}">
+      <source file="java/ClassToJavadoc.java" />
+    </javadoc>
+  </target>
+
+  <fileset dir="java/" id="fileset.simple">
+    <include name="**/*.java" />
+  </fileset>
+
+  <target name="nestedFilesetRef">
+    <javadoc destdir="${javadoc}">
+      <fileset refid="fileset.simple" />
+    </javadoc>
+  </target>
+
+  <target name="nonJavaIncludes">
+    <delete dir="${javadoc}"/>
+    <mkdir dir="${javadoc}"/>
+    <echo file="${javadoc}/stuff1.java">public class stuff1 {}</echo>
+    <echo file="${javadoc}/stuff2.java">public class stuff2 {}</echo>
+    <echo file="${javadoc}/stuff.properties">x=4</echo>
+    <javadoc destdir="${javadoc}" failonerror="true">
+      <fileset dir="${javadoc}"/>
+    </javadoc>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/loadfile.xml b/trunk/src/etc/testcases/taskdefs/loadfile.xml
new file mode 100644
index 0000000..66c9ce4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/loadfile.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="loadfile-test" basedir="." default="testLoadAFile">
+
+
+  <target name="init">
+  </target>
+
+  <target name="testNoSourcefileDefined" depends="init">
+    <loadfile property="foo" />
+  </target>
+
+  <target name="testNoPropertyDefined"
+    depends="init">
+    <loadfile srcFile="somefile" />
+  </target>
+
+
+  <target name="testNoSourcefilefound"
+    depends="init">
+    <loadfile property="missing" srcFile="somefile" />
+  </target>
+
+  <target name="testFailOnError"
+    depends="init">
+    <loadfile
+      property="testFailOnError"
+      srcFile="somefile"
+      failonerror="false"/>
+  </target>
+
+  <target name="testLoadAFile"
+    depends="init">
+    <echo
+      message="What's it going to be then, eh?"
+      file="loadfile1.tmp"
+      />
+    <loadfile property="testLoadAFile" srcFile="loadfile1.tmp" />
+    <echo>${testLoadAFile}</echo>
+  </target>
+
+  <target name="testLoadAFileEnc"
+    depends="init">
+    <loadfile property="testLoadAFileEnc"
+      srcFile="loadfile.xml"
+      encoding="ISO-8859-1"/>
+  </target>
+
+  <target name="testEvalProps"
+    depends="init">
+    <property name="weather" value="rain" />
+    <echo
+      message="All these moments will be lost in time, like teardrops in the ${weather}"
+      file="loadfile1.tmp"
+      />
+    <loadfile property="testEvalProps"
+        srcFile="loadfile1.tmp">
+        <filterchain>
+          <expandproperties/>
+        </filterchain>
+    </loadfile>
+    <echo>${testEvalProps}</echo>
+  </target>
+
+  <target name="testFilterChain"
+    depends="init">
+      <echo file="loadfile1.tmp">#Line 1
+REM Line 2
+--Line 3
+Line 4
+Hello World!</echo>
+      <loadfile srcFile="loadfile1.tmp" 
+        property="testFilterChain">
+        <filterchain>
+          <headfilter lines="5"/>
+          <striplinecomments>
+            <comment value="--"/>
+            <comment value="REM "/>
+            <comment value="#"/>
+          </striplinecomments>
+          <filterreader classname="org.apache.tools.ant.filters.TailFilter">
+            <param name="lines" value="1"/>
+          </filterreader>
+          <linecontains>
+            <contains value="World!"/>
+          </linecontains>
+        </filterchain>
+      </loadfile>
+  </target>
+
+  <target name="testStripJavaComments"
+    depends="init">
+      <echo file="loadfile1.tmp">
+/*
+Comment "1"
+*/
+public class test1 {
+    //Some comment
+    int x = 1/2;
+    private static final String GREETING="*/Hello/*";
+    private static final String GREETING1="/*Hello*/";
+
+    public static void main( String args[] ) {
+    }
+}</echo>
+      <echo file="nocomments.tmp">
+
+public class test1 {
+    
+    int x = 1/2;
+    private static final String GREETING="*/Hello/*";
+    private static final String GREETING1="/*Hello*/";
+
+    public static void main( String args[] ) {
+    }
+}</echo>
+      <loadfile srcFile="loadfile1.tmp" 
+        property="testStripJavaComments">
+        <filterchain>
+          <stripjavacomments/>
+        </filterchain>
+      </loadfile>
+      <loadfile srcFile="nocomments.tmp" 
+        property="expected"/>
+  </target>
+
+  <target name="testOneLine"
+    depends="init">
+    <echo
+      message="1,&#10;2,&#13;3,&#13;&#10;4"
+      file="loadfile1.tmp"
+      />
+    <loadfile property="testOneLine"
+        srcFile="loadfile1.tmp">
+      <filterchain>
+        <striplinebreaks/>
+      </filterchain>
+    </loadfile>
+    <echo>${testOneLine}</echo>
+  </target>
+
+
+  <target name="cleanup">
+    <delete file="loadfile1.tmp"/>
+    <delete file="nocomments.tmp"/>
+  </target>
+
+  </project>
diff --git a/trunk/src/etc/testcases/taskdefs/loadproperties.xml b/trunk/src/etc/testcases/taskdefs/loadproperties.xml
new file mode 100644
index 0000000..094c647
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/loadproperties.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="loadproperties-test" 
+         basedir="." 
+         default="testPrefixedProperties">
+
+  <target name="init">
+  </target>
+
+  <target name="testPrefixedProperties" depends="init">
+    <property name="server" value="localhost"/>
+    <echo file="properties.tmp">
+#http.@PORT@ = 90
+http.@PORT@ = 80
+http.@SERVER@ = ${server}
+    </echo>
+    <loadproperties srcFile="properties.tmp">
+      <filterchain>
+        <striplinecomments>
+          <comment value="#"/>
+        </striplinecomments>
+        <prefixlines prefix="server1."/>
+        <replacetokens>
+          <token key="PORT" value="port"/>
+          <token key="SERVER" value="server"/>
+        </replacetokens>
+        <expandproperties/>
+      </filterchain>
+    </loadproperties>
+    <property name="server1.http.url" 
+      value="http://${server1.http.server}:${server1.http.port}"/>
+  </target>
+
+  <target name="write properties.tmp" depends="init">
+    <echo file="properties.tmp">
+#tpfr.a=a
+tpfr.a=A
+tpfr.b=b\
+       e
+tpfr.c=@C@
+    </echo>
+  </target>
+
+  <target name="testPropertiesFromResource" depends="write properties.tmp">
+    <loadproperties resource="properties.tmp" classpath="${basedir}">
+      <filterchain>
+        <replacetokens>
+          <token key="C" value="sea"/>
+        </replacetokens>
+      </filterchain>
+    </loadproperties>
+  </target>
+
+  <target name="testPropertiesFromFileSet" depends="write properties.tmp">
+    <loadproperties>
+      <fileset dir="${basedir}">
+        <include name="properties.tmp"/>
+      </fileset>
+      <filterchain>
+        <replacetokens>
+          <token key="C" value="sea"/>
+        </replacetokens>
+      </filterchain>
+    </loadproperties>
+  </target>
+
+  <target name="loadPropertiesCheck">
+    <condition property="testPropertiesFromResource.ok">
+        <equals arg1="Abesea" arg2="${tpfr.a}${tpfr.b}${tpfr.c}" />
+    </condition>
+    <fail unless="testPropertiesFromResource.ok">
+$${tpfr.a}$${tpfr.b}$${tpfr.c}=&quot;${tpfr.a}${tpfr.b}${tpfr.c}&quot;
+    </fail>
+  </target>
+
+  <target name="cleanup">
+    <delete file="properties.tmp"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/macrodef.xml b/trunk/src/etc/testcases/taskdefs/macrodef.xml
new file mode 100644
index 0000000..f7a356f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/macrodef.xml
@@ -0,0 +1,290 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+
+  <target name="simple">
+    <macrodef name="my.echo">
+      <attribute name="text"/>
+      <sequential>
+        <echo message="@{text}"/>
+      </sequential>
+    </macrodef>
+    <my.echo text="Hello World"/>
+  </target>
+
+  <target name="text">
+    <macrodef name="my.echo">
+      <attribute name="text"/>
+      <sequential>
+        <echo>@{text}</echo>
+      </sequential>
+    </macrodef>
+    <my.echo text="Inner Text"/>
+  </target>
+
+  <target name="duplicate.attribute">
+    <macrodef name="my.echo">
+      <attribute name="text"/>
+      <attribute name="text"/>
+      <sequential>
+        <echo>@{text}</echo>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <target name="duplicate.element">
+    <macrodef name="my.echo">
+      <element name="text"/>
+      <element name="text"/>
+      <sequential>
+        <text/>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <target name="uri">
+    <macrodef name="echo" uri="abc">
+      <attribute name="text"/>
+      <sequential>
+        <echo message="@{text}"/>
+      </sequential>
+    </macrodef>
+    <x:echo xmlns:x="abc" text="Hello World"/>
+  </target>
+
+  <target name="nested">
+    <macrodef name="nested">
+      <element name="nested"/>
+      <sequential>
+        <nested/>
+      </sequential>
+    </macrodef>
+
+    <nested>
+      <nested>
+        <echo>A nested element</echo>
+      </nested>
+    </nested>
+  </target>
+
+  <target name="double">
+    <macrodef name="double">
+      <attribute name="prop"/>
+      <sequential>
+        <echo>@@{prop} is '@{prop}', value of $${@{prop}} is '${@{prop}}'</echo>
+      </sequential>
+    </macrodef>
+    <property name="property" value="A property value"/>
+    <double prop="property"/>
+  </target>
+
+  <target name="ignorecase">
+    <macrodef name="ignore">
+      <attribute name="MyAttribute"/>
+      <sequential>
+        <echo>@{myattribute} is @{MYATTRIBUTE}</echo>
+      </sequential>
+    </macrodef>
+    <ignore myattribute="a"/>
+    <ignore Myattribute="b"/>
+  </target>
+
+  <target name="ignore-element-case">
+    <macrodef name="ignore">
+      <element name="MyElement"/>
+      <sequential>
+        <myElement/>
+        <MyElEmEnT/>
+      </sequential>
+    </macrodef>
+    <ignore>
+      <MYELEMENT>
+        <echo>nested element</echo>
+      </MYELEMENT>
+    </ignore>
+  </target>
+
+  <target name="textelement">
+    <macrodef name="echotest">
+      <text name="text" optional="yes"/>
+      <sequential>
+        <echo>@{text}</echo>
+      </sequential>
+    </macrodef>
+    <echotest>
+      Hello world
+    </echotest>
+  </target>
+
+  <target name="text.trim">
+    <macrodef name="echotest">
+      <text name="text" trim="yes"/>
+      <sequential>
+        <echo>[@{text}]</echo>
+      </sequential>
+    </macrodef>
+    <echotest>
+      Hello world
+    </echotest>
+  </target>
+
+  <target name="duplicatetextname">
+    <macrodef name="echotest">
+      <attribute name="text"/>
+      <text name="text"/>
+      <sequential>
+        <echo>@{text}</echo>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <target name="duplicatetextname2">
+    <macrodef name="echotest">
+      <text name="text"/>
+      <attribute name="text"/>
+      <sequential>
+        <echo>@{text}</echo>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <target name="escape">
+    <macrodef name="escape">
+      <attribute name="a"/>
+      <attribute name="b"/>
+      <sequential>
+        <echo>a@b or a@@b is @{a}@@@{b}</echo>
+      </sequential>
+    </macrodef>
+    <escape a="avalue" b="bvalue"/>
+  </target>
+
+  <target name="attribute.description">
+    <macrodef name="d">
+      <attribute name="description"/>
+      <attribute name="d" default="p"/>
+      <sequential>
+        <echo>description is @{description}</echo>
+      </sequential>
+    </macrodef>
+    <d description="hello world"/>
+  </target>
+
+  <target name="implicit">
+    <macrodef name="implicit">
+      <element name="implicit" implicit="yes"/>
+      <sequential>
+        <echo>Before implicit</echo>
+        <implicit/>
+        <echo>After implicit</echo>
+      </sequential>
+    </macrodef>
+
+    <implicit>
+      <echo>In implicit</echo>
+    </implicit>
+  </target>
+
+  <target name="implicit.notoptional">
+    <macrodef name="implicit">
+      <element name="implicit" implicit="yes"/>
+      <sequential>
+        <echo>Before implicit</echo>
+        <implicit/>
+        <echo>After implicit</echo>
+      </sequential>
+    </macrodef>
+
+    <implicit>
+    </implicit>
+  </target>
+
+  <target name="implicit.optional">
+    <macrodef name="implicit">
+      <element name="implicit" optional="yes" implicit="yes"/>
+      <sequential>
+        <echo>Before implicit</echo>
+        <implicit/>
+        <echo>After implicit</echo>
+      </sequential>
+    </macrodef>
+
+    <implicit>
+    </implicit>
+  </target>
+
+  <target name="implicit.explicit">
+    <macrodef name="implicit">
+      <element name="explicit" optional="yes"/>
+      <element name="implicit" optional="yes" implicit="yes"/>
+      <sequential>
+        <implicit/>
+        <explicit/>
+      </sequential>
+    </macrodef>
+  </target>
+
+  <property name="default.override" value="old"/>
+  <macrodef name="simple.override">
+    <attribute name="attr" default="${default.override}"/>
+    <sequential>
+      <echo>value is @{attr}</echo>
+    </sequential>
+  </macrodef>
+
+  <target name="override.default">
+    <antcall target="override.call">
+      <param name="default.override" value="new"/>
+    </antcall>
+  </target>
+
+  <target name="override.call">
+    <simple.override/>
+  </target>
+
+  <target name="backtraceoff">
+    <macrodef name="nobacktrace" backtrace="false">
+      <sequential>
+        <fail>This is a failure</fail>
+      </sequential>
+    </macrodef>
+    <nobacktrace/>
+  </target>
+  <target name="backtraceon">
+    <macrodef name="nobacktrace" backtrace="true">
+      <sequential>
+        <fail>This is a failure</fail>
+      </sequential>
+    </macrodef>
+    <nobacktrace/>
+  </target>
+
+  <target name="top-level-text">
+    <macrodef name="top">
+      <element name="em"/>
+      <sequential>
+        <echo><em/></echo>
+      </sequential>
+    </macrodef>
+    <top>
+      <em>
+        Hello World
+      </em>
+    </top>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/makeurl.xml b/trunk/src/etc/testcases/taskdefs/makeurl.xml
new file mode 100644
index 0000000..dafd00a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/makeurl.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="to-url" >
+
+
+  <target name="testEmpty">
+    <makeurl/>
+  </target>
+
+  <target name="testNoProperty">
+    <makeurl file="foo"/>
+  </target>
+
+  <target name="testNoFile">
+    <makeurl property="foo"/>
+  </target>
+    
+  <target name="testWorks">
+    <makeurl property="testWorks" file="foo" validate="false"/>
+    <fail unless="testWorks" />
+  </target>
+
+  <target name="testIllegalChars">
+    <makeurl property="testIllegalChars" file="fo o%" validate="false"/>
+  </target>
+  
+  <target name="testRoundTrip">
+    <makeurl property="testRoundTrip" file="${ant.file}"/>
+  </target>
+
+  <target name="testIllegalCombinations">
+    <makeurl property="testIllegalCombinations" file="foo" validate="false">
+      <fileset dir="." includes="*.xml" />
+    </makeurl>
+  </target>
+  
+  
+  <target name="testFileset">
+    <makeurl property="testFileset">
+      <fileset dir="." includes="*.xml" />
+    </makeurl>
+  </target>
+  
+  <target name="testFilesetSeparator">
+    <makeurl property="testFilesetSeparator" separator='","'>
+      <fileset dir="." includes="*.xml" />
+    </makeurl>
+  </target>
+
+  <target name="testValidation">
+    <makeurl property="testValidation" file="absent" validate="true"/>
+  </target>
+
+  <target name="testPath">
+    <path id="test.path">
+      <pathelement location="." />
+      <fileset dir="." includes="*.xml"/>
+    </path>
+    <makeurl property="testPath">
+      <path refid="test.path" />
+    </makeurl>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/manifest.xml b/trunk/src/etc/testcases/taskdefs/manifest.xml
new file mode 100644
index 0000000..b1faf50
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifest.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- Manifest tests build file
+     author: Conor MacNeill -->
+<project name="manifest-test" basedir="." default="test1">
+
+  <target name="test1">
+    <jar file="mftest1.jar" manifest="manifests/test1.mf"/>
+    <unjar src="mftest1.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+  
+  <target name="test2">
+    <jar file="mftest2.jar" manifest="manifests/test2.mf"/>
+    <unjar src="mftest2.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+  
+  <target name="test3">
+    <jar file="mftest3.jar" manifest="manifests/test3.mf"/>
+  </target>
+  
+  <target name="test4">
+    <jar file="mftest4.jar" manifest="manifests/test4.mf"/>
+  </target>
+  
+  <target name="test5">
+    <jar file="mftest5.jar" manifest="manifests/test5.mf"/>
+  </target>
+  
+  <target name="test6">
+    <jar file="mftest6.jar" manifest="manifests/test6.mf"/>
+  </target>
+  
+  <target name="test7">
+    <jar file="mftest7.jar" manifest="manifests/test7.mf"/>
+  </target>
+  
+  <target name="test8">
+    <jar file="mftest8.jar">
+      <manifest>
+        <attribute name="Class-Path" value="fubar"/>
+        <section name="Test">
+          <attribute name="TestAttr" value="Test"/>
+        </section>
+      </manifest>
+    </jar>
+    <unjar src="mftest8.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+
+  <target name="test9">
+    <jar file="mftest9.jar">
+      <manifest>
+        <attribute name="Class-Path" value="fubar"/>
+        <section name="Test">
+          <attribute name="Name" value="Test"/>
+        </section>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test10">
+    <jar file="mftest10.jar">
+      <manifest>
+        <attribute value="fubar"/>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test11">
+    <jar file="mftest11.jar">
+      <manifest>
+        <attribute name="Test"/>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test12">
+    <jar file="mftest12.jar">
+      <manifest>
+        <section>
+          <attribute name="TestAttr" value="Test"/>
+        </section>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test13">
+    <jar file="mftest13.jar">
+      <manifest>
+        <attribute name="Test" value="Test1"/>
+        <attribute name="Test" value="Test2"/>
+      </manifest>
+    </jar>
+  </target>
+
+  <target name="test14">
+    <jar file="mftest14.jar">
+      <manifest>
+        <attribute name="Class-path" value="Test1"/>
+        <attribute name="Class-path" value="Test2"/>
+        <attribute name="Class-Path" value="Test3"/>
+        <attribute name="class-Path" value="Test4"/>
+      </manifest>
+    </jar>
+    <unjar src="mftest14.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+
+  <target name="testNoFile">
+    <manifest />
+  </target>
+
+  <target name="testLongLine">
+    <jar file="mftestLongLine.jar">
+      <manifest>
+        <attribute name="Class-path" 
+                   value="${test.longline}"/>
+        <attribute name="${test.long68name}" value="${test.value}" />
+        <attribute name="${test.long70name}" value="${test.value}" />
+        <attribute name="${test.notlongname}" value="${test.value}" />
+      </manifest>
+    </jar>
+    <unjar src="mftestLongLine.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+
+  <target name="testOrder1">
+    <jar file="mftestOrder1.jar">
+      <manifest>
+        <section name="Test1">
+          <attribute name="TestAttr1" value="Test1"/>
+          <attribute name="TestAttr2" value="Test2"/>
+        </section>
+        <section name="Test2">
+          <attribute name="TestAttrx" value="Testx"/>
+        </section>
+      </manifest>
+    </jar>
+    <unjar src="mftestOrder1.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+
+  <target name="testOrder2">
+    <jar file="mftestOrder2.jar">
+      <manifest>
+        <section name="Test2">
+          <attribute name="TestAttrx" value="Testx"/>
+        </section>
+        <section name="Test1">
+          <attribute name="TestAttr2" value="Test2"/>
+          <attribute name="TestAttr1" value="Test1"/>
+        </section>
+      </manifest>
+    </jar>
+    <unjar src="mftestOrder2.jar" dest="manifests">
+      <patternset>
+        <include name="META-INF/MANIFEST.MF"/>
+      </patternset>
+    </unjar>
+  </target>
+  
+  <target name="testReplace">
+    <copy file="manifests/test2.mf" toFile="mftest.mf" />
+    <manifest file="mftest.mf" />
+  </target>
+
+  <target name="testUpdate">
+    <copy file="manifests/test2.mf" toFile="mftest.mf" />
+    <manifest file="mftest.mf" mode="update">
+      <attribute name="Foo" value="Bar" />
+    </manifest>
+
+    <copy file="manifests/test2.mf" toFile="mftest2.mf" />
+    <manifest file="mftest2.mf" mode="update">
+      <section name="Test">
+        <attribute name="Foo" value="Bar" />
+      </section>
+    </manifest>
+    <manifest file="mftest2.mf" mode="update">
+      <section name="Test">
+        <attribute name="Foo" value="Baz" />
+      </section>
+    </manifest>
+  </target>
+
+  <target name="testFrom">
+    <manifest file="mftestfrom.mf" >
+      <section name="Test">
+        <attribute name="before" value="before" />
+        <attribute name="From" value="illegal"/>
+        <attribute name="after" value="after" />
+      </section>
+    </manifest>
+  </target>
+  
+  <target name="testIllegalName">
+    <manifest file="mftestillegalname.mf">
+      <attribute name="has blank" value="value"/>
+    </manifest>
+  </target>
+
+  <target name="testIllegalNameInSection">
+    <manifest file="mftestillegalnameinsection.mf">
+      <section name="s1">
+        <attribute name="has blank" value="value"/>
+      </section>
+    </manifest>
+  </target>
+
+  <target name="testIllegalNameBegin">
+    <manifest file="mftestillegalnamebegin.mf">
+      <attribute name="-name" value="value"/>
+    </manifest>
+  </target>
+
+  <target name="testIllegalName2">
+    <manifest file="mftestillegalnamebegin.mf">
+      <attribute name="has.point" value="value"/>
+    </manifest>
+  </target>
+
+  <target name="testIllegalName3">
+    <manifest file="mftestillegalnamebegin.mf">
+      <attribute name="has*star" value="value"/>
+    </manifest>
+  </target>
+
+  <target name="clean">
+    <delete>
+      <fileset dir="." includes="mftest*"/>
+    </delete>
+    <delete dir="manifests/META-INF"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/manifestclasspath.xml b/trunk/src/etc/testcases/taskdefs/manifestclasspath.xml
new file mode 100644
index 0000000..c286213
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifestclasspath.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+

+<project name="manifestclasspath" default="tearDown">

+  <!-- hebrew -->

+  <property name="jom" value="&#1501;&#1493;&#1497;"/>

+  <!-- german -->

+  <property name="aent" value="&#227;nt"/> 

+  <target name="setUp">

+    <property name="tmp" location="${basedir}/${ant.project.name}.tmp" />

+    <mkdir dir="${tmp}" />

+  </target>

+

+  <target name="fullSetUp" depends="setUp">

+    <mkdir dir="${tmp}/lib" />

+    <touch file="${tmp}/lib/acme-core.jar" />

+    <touch file="${tmp}/lib/acme-pres.jar" />

+

+    <mkdir dir="${tmp}/classes/dsp-core/com/lgc/infra/core" />

+    <mkdir dir="${tmp}/classes/dsp-pres/com/lgc/infra/pres" />

+    <mkdir dir="${tmp}/classes/dsp-void" />

+    <mkdir dir="${tmp}/generated/dsp-core/com/lgc/infra/core/generated" />

+    <mkdir dir="${tmp}/generated/dsp-pres" />

+    <mkdir dir="${tmp}/generated/dsp-void" />

+    <mkdir dir="${tmp}/resources/dsp-core/com/lgc/infra/core" />

+    <mkdir dir="${tmp}/resources/dsp-pres/com/lgc/infra/pres" />

+    <mkdir dir="${tmp}/resources/dsp-void" />

+  </target>

+

+  <target name="tearDown">

+    <delete dir="${tmp}" />

+  </target>

+

+  <target name="test-bad-directory">

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classpath.jar">

+      <classpath />

+    </manifestclasspath>

+  </target>

+

+  <target name="test-bad-no-property" depends="setUp">

+    <manifestclasspath jarfile="${tmp}/classpath.jar">

+      <classpath />

+    </manifestclasspath>

+  </target>

+

+  <target name="test-bad-property-exists" depends="setUp">

+    <property name="jar.classpath" value="exists" />

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classpath.jar">

+      <classpath />

+    </manifestclasspath>

+  </target>

+

+  <target name="test-bad-no-jarfile" depends="setUp">

+    <manifestclasspath property="jar.classpath">

+      <classpath />

+    </manifestclasspath>

+  </target>

+

+  <target name="test-bad-no-classpath" depends="setUp">

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classpath.jar" />

+  </target>

+

+  <target name="test-pseudo-tahoe-refid" depends="fullSetUp">

+    <path id="classpath">

+      <!-- All the classes/ directories -->

+      <dirset dir="${tmp}/classes"   includes="dsp-*" />

+

+      <!-- All the JAXB generated/ directories -->

+      <dirset dir="${tmp}/generated" includes="dsp-*">

+        <!-- Add only non-empty directories to the classpath -->

+        <present targetdir="${tmp}/generated" present="both">

+          <mapper type="regexp" from="(.*)" to="\1/com" />

+        </present>

+      </dirset>

+

+      <!-- All the resources/ directories -->

+      <dirset dir="${tmp}/resources" includes="dsp-*">

+        <!-- Add only non-empty directories to the classpath -->

+        <present targetdir="${tmp}/resources" present="both">

+          <mapper type="regexp" from="(.*)" to="\1/com" />

+        </present>

+      </dirset>

+    </path>

+

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classpath.jar">

+      <classpath refid="classpath" />

+    </manifestclasspath>

+  </target>

+

+  <target name="test-pseudo-tahoe-nested" depends="fullSetUp">

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classpath.jar">

+      <classpath>

+        <!-- All the classes/ directories -->

+        <dirset dir="${tmp}/classes"   includes="dsp-*" />

+

+        <!-- All the JAXB generated/ directories -->

+        <dirset dir="${tmp}/generated" includes="dsp-*">

+          <!-- Add only non-empty directories to the classpath -->

+          <present targetdir="${tmp}/generated" present="both">

+            <mapper type="regexp" from="(.*)" to="\1/com" />

+          </present>

+        </dirset>

+

+        <!-- All the resources/ directories -->

+        <dirset dir="${tmp}/resources" includes="dsp-*">

+          <!-- Add only non-empty directories to the classpath -->

+          <present targetdir="${tmp}/resources" present="both">

+            <mapper type="regexp" from="(.*)" to="\1/com" />

+          </present>

+        </dirset>

+      </classpath>

+    </manifestclasspath>

+  </target>

+

+  <target name="test-parent-level1" depends="fullSetUp">

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classes/classpath.jar">

+      <classpath>

+        <dirset dir="${tmp}/classes"   includes="dsp-*" />

+        <dirset dir="${tmp}/generated" includes="dsp-*" />

+        <dirset dir="${tmp}/resources" includes="dsp-*" />

+      </classpath>

+    </manifestclasspath>

+  </target>

+

+  <target name="test-parent-level2" depends="fullSetUp">

+    <mkdir dir="${tmp}/classes/level2" />

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classes/level2/classpath.jar">

+      <classpath>

+        <dirset dir="${tmp}/classes"   includes="dsp-*" />

+        <dirset dir="${tmp}/generated" includes="dsp-*" />

+        <dirset dir="${tmp}/resources" includes="dsp-*" />

+      </classpath>

+    </manifestclasspath>

+  </target>

+

+  <target name="test-parent-level2-too-deep" depends="fullSetUp">

+    <mkdir dir="${tmp}/classes/level2" />

+    <manifestclasspath property="jar.classpath" maxParentLevels="1"

+                       jarfile="${tmp}/classes/level2/classpath.jar">

+      <classpath>

+        <dirset dir="${tmp}/classes"   includes="dsp-*" />

+        <dirset dir="${tmp}/generated" includes="dsp-*" />

+        <dirset dir="${tmp}/resources" includes="dsp-*" />

+      </classpath>

+    </manifestclasspath>

+  </target>

+

+  <target name="test-parent-level2-with-jars" depends="fullSetUp">

+    <mkdir dir="${tmp}/classes/level2" />

+    <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/classes/level2/classpath.jar">

+      <classpath>

+        <fileset dir="${tmp}/lib" includes="*.jar" />

+        <dirset dir="${tmp}/classes"   includes="dsp-*" />

+        <dirset dir="${tmp}/generated" includes="dsp-*" />

+        <dirset dir="${tmp}/resources" includes="dsp-*" />

+      </classpath>

+    </manifestclasspath>

+  </target>

+

+  <target name="international-german" depends="setUp">

+      <antcall target="run-two-jars">

+          <param name="ext.dir" value="${aent}"/>

+      </antcall>

+  </target>

+  <target name="international-hebrew" depends="setUp">

+      <antcall target="run-two-jars">

+          <param name="ext.dir" value="${jom}"/>

+      </antcall>

+  </target>

+  <target name="run-two-jars">

+     <mkdir dir="${tmp}/${ext.dir}"/>

+      <javac srcdir="manifestclasspath" destdir="${tmp}" />

+       <jar destfile="${tmp}/${ext.dir}/alpha.jar">

+          <fileset dir="${tmp}">

+              <include name="Alpha.class"/>

+          </fileset>

+       </jar>

+        <manifestclasspath property="jar.classpath"

+                       jarfile="${tmp}/beta.jar">

+        <classpath>

+           <pathelement location="${tmp}/beta.jar"/>

+           <pathelement location="${tmp}/${ext.dir}/alpha.jar"/>

+        </classpath>

+       </manifestclasspath>

+      <jar destfile="${tmp}/beta.jar" >

+          <fileset dir="${tmp}">

+              <include name="Beta.class"/>

+          </fileset>

+          <manifest>

+             <attribute name="Main-Class" value="Beta"/>

+             <attribute name="Class-Path" value="${jar.classpath}"/>

+          </manifest>

+      </jar>

+      <java fork="true" jar="${tmp}/beta.jar"/>

+    </target>

+</project>

diff --git a/trunk/src/etc/testcases/taskdefs/manifestclasspath/Alpha.java b/trunk/src/etc/testcases/taskdefs/manifestclasspath/Alpha.java
new file mode 100644
index 0000000..96124d5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifestclasspath/Alpha.java
@@ -0,0 +1,21 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class Alpha {
+    public String toString() {
+	return "alpha";
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/manifestclasspath/Beta.java b/trunk/src/etc/testcases/taskdefs/manifestclasspath/Beta.java
new file mode 100644
index 0000000..c1b446f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifestclasspath/Beta.java
@@ -0,0 +1,25 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class Beta extends Alpha {
+    public String toString() {
+	return "beta " + super.toString();
+    }
+    public static void main(String [] args) {
+	Beta myBeta = new Beta();
+	System.out.println(myBeta.toString());
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test1.mf b/trunk/src/etc/testcases/taskdefs/manifests/test1.mf
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test1.mf
@@ -0,0 +1 @@
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test2.mf b/trunk/src/etc/testcases/taskdefs/manifests/test2.mf
new file mode 100644
index 0000000..b8a88bd
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test2.mf
@@ -0,0 +1,2 @@
+Manifest-Version: 2.0
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test3.mf b/trunk/src/etc/testcases/taskdefs/manifests/test3.mf
new file mode 100644
index 0000000..6aa82cc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test3.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Header-without-colon maybe mistyped
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test4.mf b/trunk/src/etc/testcases/taskdefs/manifests/test4.mf
new file mode 100644
index 0000000..27afb18
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test4.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+
+ Can't start with a continuation line
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test5.mf b/trunk/src/etc/testcases/taskdefs/manifests/test5.mf
new file mode 100644
index 0000000..0fb8dea
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test5.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Name: test5 
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test6.mf b/trunk/src/etc/testcases/taskdefs/manifests/test6.mf
new file mode 100644
index 0000000..97988c6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test6.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+
+Test: test6
+Class-Path: fubar 
+
diff --git a/trunk/src/etc/testcases/taskdefs/manifests/test7.mf b/trunk/src/etc/testcases/taskdefs/manifests/test7.mf
new file mode 100644
index 0000000..72aace0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/manifests/test7.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Class-Path: fubar
+From: Jack 
+
diff --git a/trunk/src/etc/testcases/taskdefs/mkdir.xml b/trunk/src/etc/testcases/taskdefs/mkdir.xml
new file mode 100644
index 0000000..2ca4e20
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/mkdir.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <mkdir/>
+  </target>
+
+  <target name="test2">
+    <mkdir dir="template.xml"/>
+  </target>
+
+  <target name="test3">
+    <mkdir dir="testdir.tmp"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/move.xml b/trunk/src/etc/testcases/taskdefs/move.xml
new file mode 100644
index 0000000..911dff8
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/move.xml
@@ -0,0 +1,265 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="move-test" basedir="." default="testFilterSet">
+
+  <target name="testFilterSet">
+    <copy file="copy.filterset" tofile="move.filterset"/>
+    <move file="move.filterset" tofile="move.filterset.tmp">
+      <filterset>
+        <filter token="TITLE" value="Apache Ant Project"/>
+      </filterset>
+    </move>
+  </target>
+
+  <target name="testFilterChain">
+    <copy file="copy.filterset" tofile="move.filterchain"/>
+    <move file="move.filterchain" tofile="move.filterchain.tmp">
+      <filterchain>
+        <replacetokens>
+          <token key="TITLE" value="Apache Ant Project"/>
+        </replacetokens>
+      </filterchain>
+    </move>
+  </target>
+
+  <!-- Bugzilla Report 11732 -->
+  <target name="testDirectoryRemoval">
+    <mkdir dir="A/B"/>
+    <mkdir dir="A/C"/>
+    <mkdir dir="A/D"/>
+    <touch file="A/B/1"/>
+    <touch file="A/C/2"/>
+    <touch file="A/D/3"/>
+    <mkdir dir="E"/>
+    <move todir="E" includeemptydirs="true">
+      <fileset dir="A">
+        <include name="C"/>
+        <include name="D"/>
+        <include name="C/**"/>
+        <include name="D/**"/>
+      </fileset>
+    </move>
+  </target>
+
+  <!-- Bugzilla Report 18886 -->
+  <target name="testDirectoryRetaining">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <mkdir dir="E"/>
+    <move todir="E" includeemptydirs="true">
+      <fileset dir="A" includes="1"/>
+    </move>
+  </target>
+
+  <target name="testCompleteDirectoryMove">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <move todir="E">
+      <fileset dir="A"/>
+    </move>
+  </target>
+
+  <target name="testCompleteDirectoryMove2">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <move todir="E">
+      <path>
+        <fileset dir="A"/>
+      </path>
+    </move>
+  </target>
+
+  <target name="testPathElementMove">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <move todir="E" flatten="true">
+      <path>
+        <pathelement location="A/1"/>
+      </path>
+    </move>
+  </target>
+
+  <target name="testMoveFileAndFileset">
+    <mkdir dir="A" />
+    <touch>
+      <filelist dir="A" files="1,2,3" />
+    </touch>
+    <move todir="E" file="A/1">
+      <fileset dir="A" includes="2,3" />
+    </move>
+    <fail message="A unavailable">
+      <condition>
+        <not>
+          <available file="A" type="dir" />
+        </not>
+      </condition>
+    </fail>
+    <fail message="A/1 not moved">
+      <condition>
+        <or>
+          <available file="A/1" type="file" />
+          <not>
+            <available file="E/1" type="file" />
+          </not>
+        </or>
+      </condition>
+    </fail>
+    <fail message="A/2 not moved">
+      <condition>
+        <or>
+          <available file="A/2" type="file" />
+          <not>
+            <available file="E/2" type="file" />
+          </not>
+        </or>
+      </condition>
+    </fail>
+    <fail message="A/3 not moved">
+      <condition>
+        <or>
+          <available file="A/3" type="file" />
+          <not>
+            <available file="E/3" type="file" />
+          </not>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <macrodef name="verifymove">
+    <attribute name="newfile" />
+    <attribute name="olddir" />
+    <sequential>
+        <fail message="@{newfile} not available">
+          <condition>
+            <not>
+              <available file="@{newfile}" type="file" />
+            </not>
+          </condition>
+        </fail>
+        <fail message="@{olddir} remains">
+          <condition>
+            <available file="@{olddir}" type="dir" />
+          </condition>
+        </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="testCompleteDirectoryMoveToExistingDir">
+    <mkdir dir="A" />
+    <touch file="A/1" />
+    <mkdir dir="E" />
+    <touch file="E/2" />
+    <move todir="E">
+      <fileset dir="A" />
+    </move>
+    <verifymove newfile="E/1" olddir="A" />
+    <fail message="E/2 unavailable">
+      <condition>
+        <not>
+          <available file="E/2" type="file" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToFile">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <move file="A" tofile="E" />
+    <verifymove newfile="E/1" olddir="A" />
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToDir">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <move file="A" todir="E" />
+    <verifymove newfile="E/A/1" olddir="A" />
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileAndFileset">
+    <mkdir dir="A/1" />
+    <touch file="A/2" />
+    <move file="A/1" todir="E">
+      <fileset dir="A" includes="2" />
+    </move>
+    <fail message="A unavailable">
+      <condition>
+        <not>
+          <available file="A" type="dir" />
+        </not>
+      </condition>
+    </fail>
+    <fail message="E/1 unavailable">
+      <condition>
+        <not>
+          <available file="E/1" type="dir" />
+        </not>
+      </condition>
+    </fail>
+    <fail message="E/2 unavailable">
+      <condition>
+        <not>
+          <available file="E/2" type="file" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToExistingFile">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <touch file="E"/>
+    <move file="A" tofile="E" />
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToExistingDir">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <mkdir dir="E"/>
+    <move file="A" tofile="E" />
+    <verifymove newfile="E/1" olddir="A" />
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToDirWithExistingFile">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <mkdir dir="E"/>
+    <touch file="E/A"/>
+    <move file="A" todir="E" />
+  </target>
+
+  <target name="testCompleteDirectoryMoveFileToDirWithExistingDir">
+    <mkdir dir="A"/>
+    <touch file="A/1"/>
+    <mkdir dir="E"/>
+    <mkdir dir="E/A"/>
+    <move file="A" todir="E" />
+    <verifymove newfile="E/A/1" olddir="A" />
+  </target>
+
+  <target name="cleanup"> 
+    <delete file="move.filterset.tmp"/>
+    <delete file="move.filterchain.tmp"/>
+    <delete dir="A" />
+    <delete file="B" />
+    <delete dir="E" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/multimap.xml b/trunk/src/etc/testcases/taskdefs/multimap.xml
new file mode 100644
index 0000000..e236206
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/multimap.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" basedir=".">
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <mapper id="testmapper"
+          classname="org.apache.tools.ant.taskdefs.MultiMapTest$TestMapper"
+          classpathref="testclasses"/>
+
+  <property name="map.ext" value=".copy2"/>
+  <property name="rootScratchDir" value="test_multi_mapper_scratch_area"/>
+  <property name="baseScratchSrc" value="${rootScratchDir}/src"/>
+  <property name="baseScratchDest" value="${rootScratchDir}/dest"/>
+
+  <target name="setup">
+    <delete dir="${baseScratchSrc}"/>
+    <mkdir dir="${baseScratchSrc}"/>
+    <delete dir="${baseScratchDest}"/>
+    <mkdir dir="${baseScratchDest}"/>
+    <touch file="${baseScratchSrc}/somefile.txt"/>
+  </target>
+
+  <!-- test simple single file to multiple file move -->
+  <target name="multicopy" depends="setup">
+    <copy todir="${baseScratchDest}" enablemultiplemappings="true">
+      <fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
+      <mapper refid="testmapper"/>
+    </copy>
+    <condition property="multicopy.outcome">
+      <and>
+        <available file="${baseScratchDest}/somefile.txt"/>
+        <available file="${baseScratchDest}/somefile.txt${map.ext}"/>
+      </and>
+    </condition>
+    <fail unless="multicopy.outcome">multicopy failed</fail>
+  </target>
+
+  <target name="multimove" depends="setup">
+    <move todir="${baseScratchDest}" enablemultiplemappings="true">
+      <fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
+      <mapper refid="testmapper"/>
+    </move>
+    <condition property="test2.outcome">
+      <and>
+        <available file="${baseScratchDest}/somefile.txt"/>
+        <available file="${baseScratchDest}/somefile.txt${map.ext}"/>
+        <not>
+          <available file="${baseScratchSrc}/somefile.txt"/>
+        </not>
+        <not>
+          <available file="${baseScratchSrc}/somefile.txt${map.ext}"/>
+        </not>
+      </and>
+    </condition>
+    <fail unless="test2.outcome">mulitmove failed</fail>
+  </target>
+  
+  <!-- 
+       test traditional single file to single file copy explicitly telling
+       task to ignore multiple mappings
+       -->
+
+  <target name="singlecopy" depends="setup">
+    <copy todir="${baseScratchDest}" enablemultiplemappings="false">
+      <fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
+      <mapper refid="testmapper"/>
+    </copy>
+    <condition property="singlecopy.outcome">
+      <and>
+        <available file="${baseScratchDest}/somefile.txt"/>
+        <not>
+          <available file="${baseScratchDest}/somefile.txt${map.ext}"/>
+        </not>
+        <available file="${baseScratchSrc}/somefile.txt"/>
+      </and>
+    </condition>
+    <fail unless="singlecopy.outcome">singlecopy failed</fail>
+  </target>
+
+  <target name="singlemove" depends="setup">
+    <move todir="${baseScratchDest}" enablemultiplemappings="false">
+      <fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
+      <mapper refid="testmapper"/>
+    </move>
+    <condition property="singlemove.outcome">
+      <and>
+        <available file="${baseScratchDest}/somefile.txt"/>
+        <not>
+          <available file="${baseScratchDest}/somefile.txt${map.ext}"/>
+        </not>
+        <not>
+          <available file="${baseScratchSrc}/somefile.txt"/>
+        </not>
+      </and>
+    </condition>
+    <fail unless="singlemove.outcome">singlemove failed</fail>
+  </target>
+
+  <!-- test dir w/ file + empty dir multimap copy -->
+  <target name="copywithempty">
+    <delete dir="${baseScratchSrc}"/>
+    <mkdir dir="${baseScratchSrc}/dirwithfile"/>
+    <mkdir dir="${baseScratchSrc}/emptydir"/>
+    <touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/>
+
+    <delete dir="${baseScratchDest}"/>
+    <mkdir dir="${baseScratchDest}"/>
+
+    <copy todir="${baseScratchDest}" enablemultiplemappings="true">
+      <fileset dir="${baseScratchSrc}" includes="**/*"/>
+      <mapper refid="testmapper"/>
+    </copy>
+    <condition property="copywithempty.outcome">
+      <and>
+        <available file="${baseScratchDest}/dirwithfile"/>
+        <available file="${baseScratchDest}/dirwithfile${map.ext}"/>
+        <available file="${baseScratchDest}/dirwithfile/somefile.txt"/>
+        <available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/>
+        <not>
+          <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/>
+        </not>
+        <not>
+          <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/>
+        </not>
+        <available file="${baseScratchDest}/emptydir"/>
+        <available file="${baseScratchDest}/emptydir${map.ext}"/>
+      </and>
+    </condition>
+    <fail unless="copywithempty.outcome">copywithempty failed</fail>
+  </target>
+  <!-- test dir w/ file + empty dir multimap move -->
+  <target name="movewithempty">
+    <delete dir="${baseScratchSrc}"/>
+    <mkdir dir="${baseScratchSrc}/dirwithfile"/>
+    <mkdir dir="${baseScratchSrc}/emptydir"/>
+    <touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/>
+
+    <delete dir="${baseScratchDest}"/>
+    <mkdir dir="${baseScratchDest}"/>
+
+    <move todir="${baseScratchDest}" enablemultiplemappings="true">
+      <fileset dir="${baseScratchSrc}" includes="**/*"/>
+      <mapper refid="testmapper"/>
+    </move>
+    <condition property="movewithempty.outcome">
+      <and>
+        <available file="${baseScratchDest}/dirwithfile"/>
+        <available file="${baseScratchDest}/dirwithfile${map.ext}"/>
+        <available file="${baseScratchDest}/dirwithfile/somefile.txt"/>
+        <available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/>
+        <not>
+          <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/>
+        </not>
+        <not>
+          <available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/>
+        </not>
+        <available file="${baseScratchDest}/emptydir"/>
+        <available file="${baseScratchDest}/emptydir${map.ext}"/>
+        <not>
+          <available file="${baseScratchSrc}/dirwithfile"/>
+        </not>
+        <not>
+          <available file="${baseScratchSrc}/emptydir"/>
+        </not>
+      </and>
+    </condition>
+    <fail unless="movewithempty.outcome">movewithempty failed</fail>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="${rootScratchDir}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/nice.xml b/trunk/src/etc/testcases/taskdefs/nice.xml
new file mode 100644
index 0000000..e67ee19
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/nice.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="nice" basedir=".">
+
+<description>
+Test nicing. To make the test more complex we may be running in a nice mode
+to start with, and we want to restore that value at the end. So every test
+that succeeds must restore the saved value.
+</description>
+  <target name="noop">
+    <nice/>
+  </target>
+  
+  <target name="current">
+    <nice currentPriority="nice.now"/>
+    <fail unless="nice.now"/>
+  </target>
+
+  <target name="faster">
+    <nice newPriority="8" currentPriority="nice.old"/>
+    <nice currentPriority="nice.now"/>
+    <condition property="test.succeeded">
+      <equals arg1="${nice.now}" arg2="8" /> 
+    </condition>
+    <nice newPriority="${nice.old}"/>
+    <fail unless="test.succeeded"/>
+  </target>
+  
+  <target name="slower">
+    <nice newPriority="3" currentPriority="nice.old"/>
+    <nice currentPriority="nice.now"/>
+    <condition property="test.succeeded">
+      <equals arg1="${nice.now}" arg2="3" /> 
+    </condition>
+    <nice newPriority="${nice.old}"/>
+    <fail unless="test.succeeded"/>
+  </target>
+  
+  <target name="too_slow">
+    <nice currentPriority="nice.old"/>
+    <nice newPriority="0"/>
+    <nice newPriority="${nice.old}"/>
+  </target>
+
+  <target name="too_fast">
+    <nice currentPriority="nice.old"/>
+    <nice newPriority="20"/>
+    <nice newPriority="${nice.old}"/>
+  </target>
+  
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/WsdlToDotnet.xml b/trunk/src/etc/testcases/taskdefs/optional/WsdlToDotnet.xml
new file mode 100644
index 0000000..ca9b7d6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/WsdlToDotnet.xml
@@ -0,0 +1,242 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="wsdl-to-java-jtest" basedir="." default="init">
+
+
+  <property environment="env"/>
+  <property name="build.dir" location="wsdl/build"/>
+  <property name="cache.dir" location="${build.dir}/cache"/>
+  <property name="src.dir" location="${build.dir}/src"/>
+  <property name="classes.dir" location="${build.dir}/classes"/>
+  <property name="local.wsdl" 
+    location="wsdl/StockQuoteService.wsdl" />
+  <property name="out.csc" location="${src.dir}/out.cs"/>
+  <property name="out.app" location="${classes.dir}/out.dll"/>
+  <property name="out.type" value="module"/>
+  <property name="out.vbc" location="${src.dir}/out.vb"/>
+  <property name="endpoint"
+    value="http://nagoya.apache.org:5049/Axis/StockQuoteService.jws" />
+  <property name="endpoint.wsdl" 
+    value="http://nagoya.apache.org:5049/Axis/StockQuoteService.jws?wsdl" />
+  
+  <property name="vb.references" 
+    value="System.Web.dll,System.xml.dll,System.dll,System.Web.Services.dll"/>
+    
+  <target name="init" depends="validate">
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${cache.dir}"/>
+    <mkdir dir="${src.dir}"/>
+    <mkdir dir="${classes.dir}"/>
+  </target>
+  
+  <target name="probe_for_apps" >
+   <condition property="wsdl.found">
+      <or>
+        <available file="wsdl"     filepath="${env.PATH}" />
+        <available file="wsdl.exe" filepath="${env.PATH}" />
+        <available file="wsdl.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> wsdl.found=${wsdl.found}</echo>
+   <condition property="csc.found">
+      <or>
+        <available file="mcs"     filepath="${env.PATH}" />
+        <available file="csc"     filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> csc.found=${csc.found}</echo>
+   <condition property="vbc.found">
+      <or>
+        <available file="vbc"     filepath="${env.PATH}" />
+        <available file="vbc.exe" filepath="${env.PATH}" />
+        <available file="vbc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> vbc.found=${vbc.found}</echo>
+   <condition property="dotnetapps.found">
+      <and>
+        <isset property="csc.found"/>
+        <isset property="wsdl.found"/>
+      </and>
+    </condition>
+   <echo> dotnetapps.found=${dotnetapps.found}</echo>
+  </target>
+  
+  <target name="teardown">
+    <delete dir="${build.dir}"/>
+  </target>  
+
+  <target name="validate" depends="probe_for_apps" >
+    <fail unless="dotnetapps.found">Needed .net apps are missing</fail>
+  </target>  
+  
+  
+  <target name="testNoParams">
+    <wsdltodotnet/>
+  </target>
+
+  <target name="testNoSrc">
+    <wsdltodotnet destFile="${out.csc}"/>
+  </target>
+
+  <target name="testDestIsDir" depends="init">
+    <wsdltodotnet destFile="${build.dir}"
+      srcFile="${local.wsdl}"/>
+  </target>
+  
+  <target name="testBothSrc" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      url="${endpoint.wsdl}"
+      />
+  </target>
+
+  <target name="testSrcIsDir" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${build.dir}"
+      />
+  </target>
+
+  <target name="testSrcIsMissing" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${build.dir}/invalidfile.wsdl"
+      />
+  </target>
+  
+  <target name="testLocalWsdl" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      />
+    <csc 
+      srcDir="${src.dir}"
+      destFile="${out.app}"
+      targetType="${out.type}"
+      references="System.Web.Services.dll"
+      />
+    <available property="app.created" file="${out.app}"/>
+    <fail unless="app.created">No app created</fail>
+  </target>
+  
+  <target name="testLocalWsdlServer" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      server="true"
+      />
+    <csc 
+      srcDir="${src.dir}"
+      destFile="${out.app}"
+      targetType="${out.type}" 
+      fileAlign="512"
+      references="System.Web.Services.dll"
+      />
+    <available property="app.created" file="${out.app}"/>
+    <fail unless="app.created">No app created</fail>
+  </target>
+  
+  <target name="testInvalidExtraOps" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      extraOptions="/newOption:not-one-known-of"
+      />
+  </target>
+
+
+  
+  <target name="testLocalWsdlVB" depends="init" if="vbc.found">
+    <wsdltodotnet destFile="${out.vbc}"
+      language="VB"
+      srcFile="${local.wsdl}"
+      />
+    <vbc 
+      srcDir="${src.dir}"
+      destFile="${out.app}"
+      targetType="${out.type}"
+      references="${vb.references}"
+      >
+      
+      </vbc>
+    <available property="app.created" file="${out.app}"/>
+    <fail unless="app.created">No app created</fail>
+  </target>
+  
+  <target name="testLocalWsdlServerVB" 
+    depends="init" if="vbc.found">
+    <wsdltodotnet destFile="${out.vbc}"
+      language="VB"
+      srcFile="${local.wsdl}"
+      server="true"
+      />
+    <vbc 
+      srcDir="${src.dir}"
+      destFile="${out.app}"
+      targetType="${out.type}" 
+      optionExplicit="true"
+      optionStrict="false"
+      optionCompare="text"
+      references="${vb.references}"
+      />
+    <available property="app.created" file="${out.app}"/>
+    <fail unless="app.created">No app created</fail>
+  </target>
+  
+  <target name="testInvalidExtraOpsVB" depends="init">
+    <wsdltodotnet destFile="${out.vbc}"
+      language="VB"
+      srcFile="${local.wsdl}"
+      extraOptions="/newOption:not-one-known-of"
+      />
+  </target>
+
+
+  <target name="testideErrorsIgnoredWhenFalse" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      ideErrors="false"
+      >
+    </wsdltodotnet>
+  </target>
+
+  <target name="testSchemaMustBeSet" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      >
+      <schema/>
+    </wsdltodotnet>
+  </target>
+
+  <target name="testSchemaFileMustExist" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      >
+      <schema file="this-file-does-not-exist.xsd"/>
+    </wsdltodotnet>
+  </target>
+
+  <target name="testSchemaFileMustHaveOneOptionOnly" depends="init">
+    <wsdltodotnet destFile="${out.csc}"
+      srcFile="${local.wsdl}"
+      >
+      <schema file="WsdlToDotnet.xml"
+        url="http://ant.apache.org/xml/AntSchema.xsd"/>
+    </wsdltodotnet>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.g b/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.g
new file mode 100644
index 0000000..9f72493
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.g
@@ -0,0 +1,76 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+class CalcParser extends Parser;
+options {
+	buildAST = true;	// uses CommonAST by default
+}
+
+expr
+	:	mexpr (PLUS^ mexpr)* SEMI!
+	;
+
+mexpr
+	:	atom (STAR^ atom)*
+	;
+
+atom:	INT
+	;
+
+class CalcLexer extends Lexer;
+
+WS	:	(' '
+	|	'\t'
+	|	'\n'
+	|	'\r')
+		{ _ttype = Token.SKIP; }
+	;
+
+LPAREN:	'('
+	;
+
+RPAREN:	')'
+	;
+
+STAR:	'*'
+	;
+
+PLUS:	'+'
+	;
+
+SEMI:	';'
+	;
+
+protected
+DIGIT
+	:	'0'..'9'
+	;
+
+INT	:	(DIGIT)+
+	;
+
+class CalcTreeWalker extends TreeParser;
+
+expr returns [float r]
+{
+	float a,b;
+	r=0;
+}
+	:	#(PLUS a=expr b=expr)	{r = a+b;}
+	|	#(STAR a=expr b=expr)	{r = a*b;}
+	|	i:INT			{r = (float)Integer.parseInt(i.getText());}
+	;
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.xml b/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.xml
new file mode 100644
index 0000000..907a18e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/antlr/antlr.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="antlr-test" basedir="." default="test1">
+
+  <property name="tmp.dir" location="antlr.tmp"/>
+
+
+  <target name="setup">
+    <mkdir dir="${tmp.dir}"/>
+  </target>
+
+  <target name="test1">
+    <antlr/>
+  </target>
+
+  <target name="test2">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}"/>
+  </target>
+
+  <target name="test3" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}"/>
+    <fail>
+      <condition>
+        <!-- to prove each of these files exists;
+             ANTLR >= 2.7.6 leaves behind new (.smap) files as well. -->
+        <resourcecount when="ne" count="5">
+          <fileset dir="${tmp.dir}">
+            <include name="CalcParserTokenTypes.txt" />
+            <include name="CalcParserTokenTypes.java" />
+            <include name="CalcLexer.java" />
+            <include name="CalcParser.java" />
+            <include name="CalcTreeWalker.java" />
+          </fileset>
+        </resourcecount>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="test4" depends="setup">
+    <antlr target="java.g" outputdirectory="${tmp.dir}"/>
+    <antlr dir="${tmp.dir}" target="java.tree.g" outputdirectory="${tmp.dir}"/>
+  </target>
+
+  <target name="test5" depends="setup">
+    <antlr target="java.tree.g" outputdirectory="${tmp.dir}" fork="yes"/>
+  </target>
+
+  <target name="test6" depends="setup">
+    <antlr target="java.g" outputdirectory="${tmp.dir}" />
+    <antlr dir="${tmp.dir}"
+           target="java.tree.g"
+           outputdirectory="${tmp.dir}"
+           fork="yes"/>
+  </target>
+
+  <target name="test7">
+    <antlr target="antlr.xml"/>
+  </target>
+
+  <target name="test8" depends="setup">
+    <antlr target="extended.calc.g" outputdirectory="${tmp.dir}" glib="non-existant-file.g"/>
+  </target>
+
+  <target name="test9" depends="setup">
+    <!-- Note that I had to copy the grammars over to the temporary directory.  -->
+    <!-- This is because ANTLR expects the super grammar and its generated java -->
+    <!-- files to be in the same directory, which won't be the case if I use    -->
+    <!-- the output directory option. -->
+    <copy file="antlr.g" todir="${tmp.dir}"/>
+    <copy file="extended.calc.g" todir="${tmp.dir}"/>
+    <antlr target="${tmp.dir}/antlr.g"/>
+    <antlr target="${tmp.dir}/extended.calc.g" glib="${tmp.dir}/antlr.g"/>
+  </target>
+
+  <target name="test10" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}" html="yes"/>
+  </target>
+
+  <target name="test11" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}" diagnostic="yes"/>
+  </target>
+
+  <target name="test12" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}" trace="yes"/>
+  </target>
+
+  <target name="test13" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}" traceLexer="yes" traceParser="yes" traceTreeWalker="yes"/>
+  </target>
+
+  <!-- test9 will have been run before that -->
+  <target name="noRecompile">
+    <antlr target="${tmp.dir}/extended.calc.g" glib="${tmp.dir}/antlr.g"/>
+  </target>
+
+  <!-- test9 will have been run before that -->
+  <target name="normalRecompile">
+    <sleep seconds="2"/>
+    <touch file="${tmp.dir}/extended.calc.g"/>
+    <antlr target="${tmp.dir}/extended.calc.g" glib="${tmp.dir}/antlr.g"/>
+  </target>
+
+  <!-- test9 will have been run before that -->
+  <target name="supergrammarChangeRecompile">
+    <sleep seconds="2"/>
+    <touch file="${tmp.dir}/antlr.g"/>
+    <antlr target="${tmp.dir}/extended.calc.g" glib="${tmp.dir}/antlr.g"/>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="${tmp.dir}" />
+    <delete file="../../../../../../CalcParserTokenTypes.txt"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/antlr/extended.calc.g b/trunk/src/etc/testcases/taskdefs/optional/antlr/extended.calc.g
new file mode 100644
index 0000000..00c1993
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/antlr/extended.calc.g
@@ -0,0 +1,23 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Not really a great extension, but it is only a test after all!
+
+class ExtendedCalcParser extends CalcParser;
+
+exprList
+    : LPAREN (expr)* RPAREN
+    ;
diff --git a/trunk/src/etc/testcases/taskdefs/optional/antlr/java.g b/trunk/src/etc/testcases/taskdefs/optional/antlr/java.g
new file mode 100644
index 0000000..e585750
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/antlr/java.g
@@ -0,0 +1,1162 @@
+/** Java 1.2 Recognizer
+ *
+ * Run 'java Main <directory full of java files>'
+ *
+ * Contributing authors:
+ *		John Mitchell		johnm@non.net
+ *		Terence Parr		parrt@magelang.com
+ *		John Lilley			jlilley@empathy.com
+ *		Scott Stanchfield	thetick@magelang.com
+ *		Markus Mohnen       mohnen@informatik.rwth-aachen.de
+ *		Peter Williams		pwilliams@netdynamics.com
+ *
+ * Version 1.00 December 9, 1997 -- initial release
+ * Version 1.01 December 10, 1997
+ *		fixed bug in octal def (0..7 not 0..8)
+ * Version 1.10 August 1998 (parrt)
+ *		added tree construction
+ *		fixed definition of WS,comments for mac,pc,unix newlines
+ *		added unary plus
+ * Version 1.11 (Nov 20, 1998)
+ *		Added "shutup" option to turn off last ambig warning.
+ *		Fixed inner class def to allow named class defs as statements
+ *		synchronized requires compound not simple statement
+ *		add [] after builtInType DOT class in primaryExpression
+ *		"const" is reserved but not valid..removed from modifiers
+ * Version 1.12 (Feb 2, 1999)
+ *		Changed LITERAL_xxx to xxx in tree grammar.
+ *		Updated java.g to use tokens {...} now for 2.6.0 (new feature).
+ *
+ * Version 1.13 (Apr 23, 1999)
+ *		Didn't have (stat)? for else clause in tree parser.
+ *		Didn't gen ASTs for interface extends.  Updated tree parser too.
+ *		Updated to 2.6.0.
+ * Version 1.14 (Jun 20, 1999)
+ *		Allowed final/abstract on local classes.
+ *		Removed local interfaces from methods
+ *		Put instanceof precedence where it belongs...in relationalExpr
+ *			It also had expr not type as arg; fixed it.
+ *		Missing ! on SEMI in classBlock
+ *		fixed: (expr) + "string" was parsed incorrectly (+ as unary plus).
+ *		fixed: didn't like Object[].class in parser or tree parser
+ * Version 1.15 (Jun 26, 1999)
+ *		Screwed up rule with instanceof in it. :(  Fixed.
+ *		Tree parser didn't like (expr).something; fixed.
+ *		Allowed multiple inheritance in tree grammar. oops.
+ * Version 1.16 (August 22, 1999)
+ *		Extending an interface built a wacky tree: had extra EXTENDS.
+ *		Tree grammar didn't allow multiple superinterfaces.
+ *		Tree grammar didn't allow empty var initializer: {}
+ * Version 1.17 (October 12, 1999)
+ *		ESC lexer rule allowed 399 max not 377 max.
+ *		java.tree.g didn't handle the expression of synchronized
+ *			statements.
+ *
+ * BUG:
+ * 		Doesn't like boolean.class!
+ *
+ * class Test {
+ *   public static void main( String args[] ) {
+ *     if (boolean.class.equals(boolean.class)) {
+ *       System.out.println("works");
+ *     }
+ *   }
+ * }
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ */
+class JavaRecognizer extends Parser;
+options {
+	k = 2;                           // two token lookahead
+	exportVocab=Java;                // Call its vocabulary "Java"
+	codeGenMakeSwitchThreshold = 2;  // Some optimizations
+	codeGenBitsetTestThreshold = 3;
+	defaultErrorHandler = false;     // Don't generate parser error handlers
+	buildAST = true;
+}
+
+tokens {
+	BLOCK; MODIFIERS; OBJBLOCK; SLIST; CTOR_DEF; METHOD_DEF; VARIABLE_DEF; 
+	INSTANCE_INIT; STATIC_INIT; TYPE; CLASS_DEF; INTERFACE_DEF; 
+	PACKAGE_DEF; ARRAY_DECLARATOR; EXTENDS_CLAUSE; IMPLEMENTS_CLAUSE;
+	PARAMETERS; PARAMETER_DEF; LABELED_STAT; TYPECAST; INDEX_OP; 
+	POST_INC; POST_DEC; METHOD_CALL; EXPR; ARRAY_INIT; 
+	IMPORT; UNARY_MINUS; UNARY_PLUS; CASE_GROUP; ELIST; FOR_INIT; FOR_CONDITION; 
+	FOR_ITERATOR; EMPTY_STAT; FINAL="final"; ABSTRACT="abstract";
+}
+	
+// Compilation Unit: In Java, this is a single file.  This is the start
+//   rule for this parser
+compilationUnit
+	:	// A compilation unit starts with an optional package definition
+		(	packageDefinition
+		|	/* nothing */
+		)
+
+		// Next we have a series of zero or more import statements
+		( importDefinition )*
+
+		// Wrapping things up with any number of class or interface
+		//    definitions
+		( typeDefinition )*
+
+		EOF!
+	;
+
+
+// Package statement: "package" followed by an identifier.
+packageDefinition
+	options {defaultErrorHandler = true;} // let ANTLR handle errors
+	:	p:"package"^ {#p.setType(PACKAGE_DEF);} identifier SEMI!
+	;
+
+
+// Import statement: import followed by a package or class name
+importDefinition
+	options {defaultErrorHandler = true;}
+	:	i:"import"^ {#i.setType(IMPORT);} identifierStar SEMI!
+	;
+
+// A type definition in a file is either a class or interface definition.
+typeDefinition
+	options {defaultErrorHandler = true;}
+	:	m:modifiers!
+		( classDefinition[#m]
+		| interfaceDefinition[#m]
+		)
+	|	SEMI!
+	;
+
+/** A declaration is the creation of a reference or primitive-type variable
+ *  Create a separate Type/Var tree for each var in the var list.
+ */
+declaration!
+	:	m:modifiers t:typeSpec[false] v:variableDefinitions[#m,#t]
+		{#declaration = #v;}
+	;
+
+// A list of zero or more modifiers.  We could have used (modifier)* in
+//   place of a call to modifiers, but I thought it was a good idea to keep
+//   this rule separate so they can easily be collected in a Vector if
+//   someone so desires
+modifiers
+	:	( modifier )*
+		{#modifiers = #([MODIFIERS, "MODIFIERS"], #modifiers);}
+	;
+
+
+// A type specification is a type name with possible brackets afterwards
+//   (which would make it an array type).
+typeSpec[boolean addImagNode]
+	: classTypeSpec[addImagNode]
+	| builtInTypeSpec[addImagNode]
+	;
+
+// A class type specification is a class type with possible brackets afterwards
+//   (which would make it an array type).
+classTypeSpec[boolean addImagNode]
+	:	identifier (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+		{
+			if ( addImagNode ) {
+				#classTypeSpec = #(#[TYPE,"TYPE"], #classTypeSpec);
+			}
+		}
+	;
+
+// A builtin type specification is a builtin type with possible brackets
+// afterwards (which would make it an array type).
+builtInTypeSpec[boolean addImagNode]
+	:	builtInType (lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+		{
+			if ( addImagNode ) {
+				#builtInTypeSpec = #(#[TYPE,"TYPE"], #builtInTypeSpec);
+			}
+		}
+	;
+
+// A type name. which is either a (possibly qualified) class name or
+//   a primitive (builtin) type
+type
+	:	identifier
+	|	builtInType
+	;
+
+// The primitive types.
+builtInType
+	:	"void"
+	|	"boolean"
+	|	"byte"
+	|	"char"
+	|	"short"
+	|	"int"
+	|	"float"
+	|	"long"
+	|	"double"
+	;
+
+// A (possibly-qualified) java identifier.  We start with the first IDENT
+//   and expand its name by adding dots and following IDENTS
+identifier
+	:	IDENT  ( DOT^ IDENT )*
+	;
+
+identifierStar
+	:	IDENT
+		( DOT^ IDENT )*
+		( DOT^ STAR  )?
+	;
+
+
+// modifiers for Java classes, interfaces, class/instance vars and methods
+modifier
+	:	"private"
+	|	"public"
+	|	"protected"
+	|	"static"
+	|	"transient"
+	|	"final"
+	|	"abstract"
+	|	"native"
+	|	"threadsafe"
+	|	"synchronized"
+//	|	"const"			// reserved word; leave out
+	|	"volatile"
+	;
+
+
+// Definition of a Java class
+classDefinition![AST modifiers]
+	:	"class" IDENT
+		// it _might_ have a superclass...
+		sc:superClassClause
+		// it might implement some interfaces...
+		ic:implementsClause
+		// now parse the body of the class
+		cb:classBlock
+		{#classDefinition = #(#[CLASS_DEF,"CLASS_DEF"],
+							   modifiers,IDENT,sc,ic,cb);}
+	;
+
+superClassClause!
+	:	( "extends" id:identifier )?
+		{#superClassClause = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],id);}
+	;
+
+// Definition of a Java Interface
+interfaceDefinition![AST modifiers]
+	:	"interface" IDENT
+		// it might extend some other interfaces
+		ie:interfaceExtends
+		// now parse the body of the interface (looks like a class...)
+		cb:classBlock
+		{#interfaceDefinition = #(#[INTERFACE_DEF,"INTERFACE_DEF"],
+									modifiers,IDENT,ie,cb);}
+	;
+
+
+// This is the body of a class.  You can have fields and extra semicolons,
+// That's about it (until you see what a field is...)
+classBlock
+	:	LCURLY!
+			( field | SEMI! )*
+		RCURLY!
+		{#classBlock = #([OBJBLOCK, "OBJBLOCK"], #classBlock);}
+	;
+
+// An interface can extend several other interfaces...
+interfaceExtends
+	:	(
+		e:"extends"!
+		identifier ( COMMA! identifier )*
+		)?
+		{#interfaceExtends = #(#[EXTENDS_CLAUSE,"EXTENDS_CLAUSE"],
+							#interfaceExtends);}
+	;
+
+// A class can implement several interfaces...
+implementsClause
+	:	(
+			i:"implements"! identifier ( COMMA! identifier )*
+		)?
+		{#implementsClause = #(#[IMPLEMENTS_CLAUSE,"IMPLEMENTS_CLAUSE"],
+								 #implementsClause);}
+	;
+
+// Now the various things that can be defined inside a class or interface...
+// Note that not all of these are really valid in an interface (constructors,
+//   for example), and if this grammar were used for a compiler there would
+//   need to be some semantic checks to make sure we're doing the right thing...
+field!
+	:	// method, constructor, or variable declaration
+		mods:modifiers
+		(	h:ctorHead s:compoundStatement // constructor
+			{#field = #(#[CTOR_DEF,"CTOR_DEF"], mods, h, s);}
+
+		|	cd:classDefinition[#mods]       // inner class
+			{#field = #cd;}
+			
+		|	id:interfaceDefinition[#mods]   // inner interface
+			{#field = #id;}
+
+		|	t:typeSpec[false]  // method or variable declaration(s)
+			(	IDENT  // the name of the method
+
+				// parse the formal parameter declarations.
+				LPAREN! param:parameterDeclarationList RPAREN!
+
+				rt:returnTypeBrackersOnEndOfMethodHead[#t]
+
+				// get the list of exceptions that this method is declared to throw
+				(tc:throwsClause)?
+
+				( s2:compoundStatement | SEMI )
+				{#field = #(#[METHOD_DEF,"METHOD_DEF"],
+						     mods,
+							 #(#[TYPE,"TYPE"],rt),
+							 IDENT,
+							 param,
+							 tc,
+							 s2);}
+			|	v:variableDefinitions[#mods,#t] SEMI
+//				{#field = #(#[VARIABLE_DEF,"VARIABLE_DEF"], v);}
+				{#field = #v;}
+			)
+		)
+
+    // "static { ... }" class initializer
+	|	"static" s3:compoundStatement
+		{#field = #(#[STATIC_INIT,"STATIC_INIT"], s3);}
+
+    // "{ ... }" instance initializer
+	|	s4:compoundStatement
+		{#field = #(#[INSTANCE_INIT,"INSTANCE_INIT"], s4);}
+	;
+
+variableDefinitions[AST mods, AST t]
+	:	variableDeclarator[getASTFactory().dupTree(mods),
+						   getASTFactory().dupTree(t)]
+		(	COMMA!
+			variableDeclarator[getASTFactory().dupTree(mods),
+							   getASTFactory().dupTree(t)]
+		)*
+	;
+
+/** Declaration of a variable.  This can be a class/instance variable,
+ *   or a local variable in a method
+ * It can also include possible initialization.
+ */
+variableDeclarator![AST mods, AST t]
+	:	id:IDENT d:declaratorBrackets[t] v:varInitializer
+		{#variableDeclarator = #(#[VARIABLE_DEF,"VARIABLE_DEF"], mods, #(#[TYPE,"TYPE"],d), id, v);}
+	;
+
+declaratorBrackets[AST typ]
+	:	{#declaratorBrackets=typ;}
+		(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+	;
+
+varInitializer
+	:	( ASSIGN^ initializer )?
+	;
+
+// This is an initializer used to set up an array.
+arrayInitializer
+	:	lc:LCURLY^ {#lc.setType(ARRAY_INIT);}
+			(	initializer
+				(
+					// CONFLICT: does a COMMA after an initializer start a new
+					//           initializer or start the option ',' at end?
+					//           ANTLR generates proper code by matching
+					//			 the comma as soon as possible.
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:
+					COMMA! initializer
+				)*
+				(COMMA!)?
+			)?
+		RCURLY!
+	;
+
+
+// The two "things" that can initialize an array element are an expression
+//   and another (nested) array initializer.
+initializer
+	:	expression
+	|	arrayInitializer
+	;
+
+// This is the header of a method.  It includes the name and parameters
+//   for the method.
+//   This also watches for a list of exception classes in a "throws" clause.
+ctorHead
+	:	IDENT  // the name of the method
+
+		// parse the formal parameter declarations.
+		LPAREN! parameterDeclarationList RPAREN!
+
+		// get the list of exceptions that this method is declared to throw
+		(throwsClause)?
+	;
+
+// This is a list of exception classes that the method is declared to throw
+throwsClause
+	:	"throws"^ identifier ( COMMA! identifier )*
+	;
+
+
+returnTypeBrackersOnEndOfMethodHead[AST typ]
+	:	{#returnTypeBrackersOnEndOfMethodHead = typ;}
+		(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+	;
+
+// A list of formal parameters
+parameterDeclarationList
+	:	( parameterDeclaration ( COMMA! parameterDeclaration )* )?
+		{#parameterDeclarationList = #(#[PARAMETERS,"PARAMETERS"],
+									#parameterDeclarationList);}
+	;
+
+// A formal parameter.
+parameterDeclaration!
+	:	pm:parameterModifier t:typeSpec[false] id:IDENT
+		pd:parameterDeclaratorBrackets[#t]
+		{#parameterDeclaration = #(#[PARAMETER_DEF,"PARAMETER_DEF"],
+									pm, #([TYPE,"TYPE"],pd), id);}
+	;
+
+parameterDeclaratorBrackets[AST t]
+	:	{#parameterDeclaratorBrackets = t;}
+		(lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);} RBRACK!)*
+	;
+
+parameterModifier
+	:	(f:"final")?
+		{#parameterModifier = #(#[MODIFIERS,"MODIFIERS"], f);}
+	;
+
+// Compound statement.  This is used in many contexts:
+//   Inside a class definition prefixed with "static":
+//      it is a class initializer
+//   Inside a class definition without "static":
+//      it is an instance initializer
+//   As the body of a method
+//   As a completely indepdent braced block of code inside a method
+//      it starts a new scope for variable definitions
+
+compoundStatement
+	:	lc:LCURLY^ {#lc.setType(SLIST);}
+			// include the (possibly-empty) list of statements
+			(statement)*
+		RCURLY!
+	;
+
+
+statement
+	// A list of statements in curly braces -- start a new scope!
+	:	compoundStatement
+
+	// class definition
+	|	classDefinition[#[MODIFIERS, "MODIFIERS"]]
+
+	// final class definition
+	|	"final"! classDefinition[#(#[MODIFIERS, "MODIFIERS"],#[FINAL,"final"])]
+
+	// abstract class definition
+	|	"abstract"! classDefinition[#(#[MODIFIERS, "MODIFIERS"],#[ABSTRACT,"abstract"])]
+
+	// declarations are ambiguous with "ID DOT" relative to expression
+	// statements.  Must backtrack to be sure.  Could use a semantic
+	// predicate to test symbol table to see what the type was coming
+	// up, but that's pretty hard without a symbol table ;)
+	|	(declaration)=> declaration SEMI!
+
+	// An expression statement.  This could be a method call,
+	// assignment statement, or any other expression evaluated for
+	// side-effects.
+	|	expression SEMI!
+
+	// Attach a label to the front of a statement
+	|	IDENT c:COLON^ {#c.setType(LABELED_STAT);} statement
+
+	// If-else statement
+	|	"if"^ LPAREN! expression RPAREN! statement
+		(
+			// CONFLICT: the old "dangling-else" problem...
+			//           ANTLR generates proper code matching
+			//			 as soon as possible.  Hush warning.
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			"else"! statement
+		)?
+
+	// For statement
+	|	"for"^
+			LPAREN!
+				forInit SEMI!   // initializer
+				forCond	SEMI!   // condition test
+				forIter         // updater
+			RPAREN!
+			statement                     // statement to loop over
+
+	// While statement
+	|	"while"^ LPAREN! expression RPAREN! statement
+
+	// do-while statement
+	|	"do"^ statement "while"! LPAREN! expression RPAREN! SEMI!
+
+	// get out of a loop (or switch)
+	|	"break"^ (IDENT)? SEMI!
+
+	// do next iteration of a loop
+	|	"continue"^ (IDENT)? SEMI!
+
+	// Return an expression
+	|	"return"^ (expression)? SEMI!
+
+	// switch/case statement
+	|	"switch"^ LPAREN! expression RPAREN! LCURLY!
+			( casesGroup )*
+		RCURLY!
+
+	// exception try-catch block
+	|	tryBlock
+
+	// throw an exception
+	|	"throw"^ expression SEMI!
+
+	// synchronize a statement
+	|	"synchronized"^ LPAREN! expression RPAREN! compoundStatement
+
+	// empty statement
+	|	s:SEMI {#s.setType(EMPTY_STAT);}
+	;
+
+
+casesGroup
+	:	(	// CONFLICT: to which case group do the statements bind?
+			//           ANTLR generates proper code: it groups the
+			//           many "case"/"default" labels together then
+			//           follows them with the statements
+			options {
+				warnWhenFollowAmbig = false;
+			}
+			:
+			aCase
+		)+
+		caseSList
+		{#casesGroup = #([CASE_GROUP, "CASE_GROUP"], #casesGroup);}
+	;
+
+aCase
+	:	("case"^ expression | "default") COLON!
+	;
+
+caseSList
+	:	(statement)*
+		{#caseSList = #(#[SLIST,"SLIST"],#caseSList);}
+	;
+
+// The initializer for a for loop
+forInit
+		// if it looks like a declaration, it is
+	:	(	(declaration)=> declaration
+		// otherwise it could be an expression list...
+		|	expressionList
+		)?
+		{#forInit = #(#[FOR_INIT,"FOR_INIT"],#forInit);}
+	;
+
+forCond
+	:	(expression)?
+		{#forCond = #(#[FOR_CONDITION,"FOR_CONDITION"],#forCond);}
+	;
+
+forIter
+	:	(expressionList)?
+		{#forIter = #(#[FOR_ITERATOR,"FOR_ITERATOR"],#forIter);}
+	;
+
+// an exception handler try/catch block
+tryBlock
+	:	"try"^ compoundStatement
+		(handler)*
+		( "finally"^ compoundStatement )?
+	;
+
+
+// an exception handler
+handler
+	:	"catch"^ LPAREN! parameterDeclaration RPAREN! compoundStatement
+	;
+
+
+// expressions
+// Note that most of these expressions follow the pattern
+//   thisLevelExpression :
+//       nextHigherPrecedenceExpression
+//           (OPERATOR nextHigherPrecedenceExpression)*
+// which is a standard recursive definition for a parsing an expression.
+// The operators in java have the following precedences:
+//    lowest  (13)  = *= /= %= += -= <<= >>= >>>= &= ^= |=
+//            (12)  ?:
+//            (11)  ||
+//            (10)  &&
+//            ( 9)  |
+//            ( 8)  ^
+//            ( 7)  &
+//            ( 6)  == !=
+//            ( 5)  < <= > >=
+//            ( 4)  << >>
+//            ( 3)  +(binary) -(binary)
+//            ( 2)  * / %
+//            ( 1)  ++ -- +(unary) -(unary)  ~  !  (type)
+//                  []   () (method call)  . (dot -- identifier qualification)
+//                  new   ()  (explicit parenthesis)
+//
+// the last two are not usually on a precedence chart; I put them in
+// to point out that new has a higher precedence than '.', so you
+// can validy use
+//     new Frame().show()
+// 
+// Note that the above precedence levels map to the rules below...
+// Once you have a precedence chart, writing the appropriate rules as below
+//   is usually very straightfoward
+
+
+
+// the mother of all expressions
+expression
+	:	assignmentExpression
+		{#expression = #(#[EXPR,"EXPR"],#expression);}
+	;
+
+
+// This is a list of expressions.
+expressionList
+	:	expression (COMMA! expression)*
+		{#expressionList = #(#[ELIST,"ELIST"], expressionList);}
+	;
+
+
+// assignment expression (level 13)
+assignmentExpression
+	:	conditionalExpression
+		(	(	ASSIGN^
+            |   PLUS_ASSIGN^
+            |   MINUS_ASSIGN^
+            |   STAR_ASSIGN^
+            |   DIV_ASSIGN^
+            |   MOD_ASSIGN^
+            |   SR_ASSIGN^
+            |   BSR_ASSIGN^
+            |   SL_ASSIGN^
+            |   BAND_ASSIGN^
+            |   BXOR_ASSIGN^
+            |   BOR_ASSIGN^
+            )
+			assignmentExpression
+		)?
+	;
+
+
+// conditional test (level 12)
+conditionalExpression
+	:	logicalOrExpression
+		( QUESTION^ assignmentExpression COLON! conditionalExpression )?
+	;
+
+
+// logical or (||)  (level 11)
+logicalOrExpression
+	:	logicalAndExpression (LOR^ logicalAndExpression)*
+	;
+
+
+// logical and (&&)  (level 10)
+logicalAndExpression
+	:	inclusiveOrExpression (LAND^ inclusiveOrExpression)*
+	;
+
+
+// bitwise or non-short-circuiting or (|)  (level 9)
+inclusiveOrExpression
+	:	exclusiveOrExpression (BOR^ exclusiveOrExpression)*
+	;
+
+
+// exclusive or (^)  (level 8)
+exclusiveOrExpression
+	:	andExpression (BXOR^ andExpression)*
+	;
+
+
+// bitwise or non-short-circuiting and (&)  (level 7)
+andExpression
+	:	equalityExpression (BAND^ equalityExpression)*
+	;
+
+
+// equality/inequality (==/!=) (level 6)
+equalityExpression
+	:	relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+	;
+
+
+// boolean relational expressions (level 5)
+relationalExpression
+	:	shiftExpression
+		(	(	(	LT^
+				|	GT^
+				|	LE^
+				|	GE^
+				)
+				shiftExpression
+			)*
+		|	"instanceof"^ typeSpec[true]
+		)
+	;
+
+
+// bit shift expressions (level 4)
+shiftExpression
+	:	additiveExpression ((SL^ | SR^ | BSR^) additiveExpression)*
+	;
+
+
+// binary addition/subtraction (level 3)
+additiveExpression
+	:	multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+	;
+
+
+// multiplication/division/modulo (level 2)
+multiplicativeExpression
+	:	unaryExpression ((STAR^ | DIV^ | MOD^ ) unaryExpression)*
+	;
+
+unaryExpression
+	:	INC^ unaryExpression
+	|	DEC^ unaryExpression
+	|	MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+	|	PLUS^  {#PLUS.setType(UNARY_PLUS);} unaryExpression
+	|	unaryExpressionNotPlusMinus
+	;
+
+unaryExpressionNotPlusMinus
+	:	BNOT^ unaryExpression
+	|	LNOT^ unaryExpression
+
+	|	(	// subrule allows option to shut off warnings
+			options {
+				// "(int" ambig with postfixExpr due to lack of sequence
+				// info in linear approximate LL(k).  It's ok.  Shut up.
+				generateAmbigWarnings=false;
+			}
+		:	// If typecast is built in type, must be numeric operand
+			// Also, no reason to backtrack if type keyword like int, float...
+			lpb:LPAREN^ {#lpb.setType(TYPECAST);} builtInTypeSpec[true] RPAREN!
+			unaryExpression
+
+			// Have to backtrack to see if operator follows.  If no operator
+			// follows, it's a typecast.  No semantic checking needed to parse.
+			// if it _looks_ like a cast, it _is_ a cast; else it's a "(expr)"
+		|	(LPAREN classTypeSpec[true] RPAREN unaryExpressionNotPlusMinus)=>
+			lp:LPAREN^ {#lp.setType(TYPECAST);} classTypeSpec[true] RPAREN!
+			unaryExpressionNotPlusMinus
+
+		|	postfixExpression
+		)
+	;
+
+// qualified names, array expressions, method invocation, post inc/dec
+postfixExpression
+	:	primaryExpression // start with a primary
+
+		(	// qualified id (id.id.id.id...) -- build the name
+			DOT^ ( IDENT
+				| "this"
+				| "class"
+				| newExpression
+				| "super" LPAREN ( expressionList )? RPAREN
+				)
+			// the above line needs a semantic check to make sure "class"
+			//   is the _last_ qualifier.
+
+			// allow ClassName[].class
+		|	( lbc:LBRACK^ {#lbc.setType(ARRAY_DECLARATOR);} RBRACK! )+
+			DOT^ "class"
+
+			// an array indexing operation
+		|	lb:LBRACK^ {#lb.setType(INDEX_OP);} expression RBRACK!
+
+			// method invocation
+			// The next line is not strictly proper; it allows x(3)(4) or
+			//  x[2](4) which are not valid in Java.  If this grammar were used
+			//  to validate a Java program a semantic check would be needed, or
+			//   this rule would get really ugly...
+		|	lp:LPAREN^ {#lp.setType(METHOD_CALL);}
+				argList
+			RPAREN!
+		)*
+
+		// possibly add on a post-increment or post-decrement.
+		// allows INC/DEC on too much, but semantics can check
+		(	in:INC^ {#in.setType(POST_INC);}
+	 	|	de:DEC^ {#de.setType(POST_DEC);}
+		|	// nothing
+		)
+
+		// look for int.class and int[].class
+	|	builtInType 
+		( lbt:LBRACK^ {#lbt.setType(ARRAY_DECLARATOR);} RBRACK! )*
+		DOT^ "class"
+	;
+
+// the basic element of an expression
+primaryExpression
+	:	IDENT
+	|	newExpression
+	|	constant
+	|	"super"
+	|	"true"
+	|	"false"
+	|	"this"
+	|	"null"
+	|	LPAREN! assignmentExpression RPAREN!
+	;
+
+/** object instantiation.
+ *  Trees are built as illustrated by the following input/tree pairs:
+ *  
+ *  new T()
+ *  
+ *  new
+ *   |
+ *   T --  ELIST
+ *           |
+ *          arg1 -- arg2 -- .. -- argn
+ *  
+ *  new int[]
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *  
+ *  new int[] {1,2}
+ *
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR -- ARRAY_INIT
+ *                                  |
+ *                                EXPR -- EXPR
+ *                                  |      |
+ *                                  1      2
+ *  
+ *  new int[3]
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *                |
+ *              EXPR
+ *                |
+ *                3
+ *  
+ *  new int[1][2]
+ *  
+ *  new
+ *   |
+ *  int -- ARRAY_DECLARATOR
+ *               |
+ *         ARRAY_DECLARATOR -- EXPR
+ *               |              |
+ *             EXPR             1
+ *               |
+ *               2
+ *  
+ */
+newExpression
+	:	"new"^ type
+		(	LPAREN! argList RPAREN! (classBlock)?
+
+			//java 1.1
+			// Note: This will allow bad constructs like
+			//    new int[4][][3] {exp,exp}.
+			//    There needs to be a semantic check here...
+			// to make sure:
+			//   a) [ expr ] and [ ] are not mixed
+			//   b) [ expr ] and an init are not used together
+
+		|	newArrayDeclarator (arrayInitializer)?
+		)
+	;
+
+argList
+	:	(	expressionList
+		|	/*nothing*/
+			{#argList = #[ELIST,"ELIST"];}
+		)
+	;
+
+newArrayDeclarator
+	:	(
+			// CONFLICT:
+			// newExpression is a primaryExpression which can be
+			// followed by an array index reference.  This is ok,
+			// as the generated code will stay in this loop as
+			// long as it sees an LBRACK (proper behavior)
+			options {
+				warnWhenFollowAmbig = false;
+			}
+		:
+			lb:LBRACK^ {#lb.setType(ARRAY_DECLARATOR);}
+				(expression)?
+			RBRACK!
+		)+
+	;
+
+constant
+	:	NUM_INT
+	|	CHAR_LITERAL
+	|	STRING_LITERAL
+	|	NUM_FLOAT
+	;
+
+
+//----------------------------------------------------------------------------
+// The Java scanner
+//----------------------------------------------------------------------------
+class JavaLexer extends Lexer;
+
+options {
+	exportVocab=Java;      // call the vocabulary "Java"
+	testLiterals=false;    // don't automatically test for literals
+	k=4;                   // four characters of lookahead
+}
+
+
+
+// OPERATORS
+QUESTION		:	'?'		;
+LPAREN			:	'('		;
+RPAREN			:	')'		;
+LBRACK			:	'['		;
+RBRACK			:	']'		;
+LCURLY			:	'{'		;
+RCURLY			:	'}'		;
+COLON			:	':'		;
+COMMA			:	','		;
+//DOT			:	'.'		;
+ASSIGN			:	'='		;
+EQUAL			:	"=="	;
+LNOT			:	'!'		;
+BNOT			:	'~'		;
+NOT_EQUAL		:	"!="	;
+DIV				:	'/'		;
+DIV_ASSIGN		:	"/="	;
+PLUS			:	'+'		;
+PLUS_ASSIGN		:	"+="	;
+INC				:	"++"	;
+MINUS			:	'-'		;
+MINUS_ASSIGN	:	"-="	;
+DEC				:	"--"	;
+STAR			:	'*'		;
+STAR_ASSIGN		:	"*="	;
+MOD				:	'%'		;
+MOD_ASSIGN		:	"%="	;
+SR				:	">>"	;
+SR_ASSIGN		:	">>="	;
+BSR				:	">>>"	;
+BSR_ASSIGN		:	">>>="	;
+GE				:	">="	;
+GT				:	">"		;
+SL				:	"<<"	;
+SL_ASSIGN		:	"<<="	;
+LE				:	"<="	;
+LT				:	'<'		;
+BXOR			:	'^'		;
+BXOR_ASSIGN		:	"^="	;
+BOR				:	'|'		;
+BOR_ASSIGN		:	"|="	;
+LOR				:	"||"	;
+BAND			:	'&'		;
+BAND_ASSIGN		:	"&="	;
+LAND			:	"&&"	;
+SEMI			:	';'		;
+
+
+// Whitespace -- ignored
+WS	:	(	' '
+		|	'\t'
+		|	'\f'
+		// handle newlines
+		|	(	"\r\n"  // Evil DOS
+			|	'\r'    // Macintosh
+			|	'\n'    // Unix (the right way)
+			)
+			{ newline(); }
+		)
+		{ _ttype = Token.SKIP; }
+	;
+
+// Single-line comments
+SL_COMMENT
+	:	"//"
+		(~('\n'|'\r'))* ('\n'|'\r'('\n')?)
+		{$setType(Token.SKIP); newline();}
+	;
+
+// multiple-line comments
+ML_COMMENT
+	:	"/*"
+		(	/*	'\r' '\n' can be matched in one alternative or by matching
+				'\r' in one iteration and '\n' in another.  I am trying to
+				handle any flavor of newline that comes in, but the language
+				that allows both "\r\n" and "\r" and "\n" to all be valid
+				newline is ambiguous.  Consequently, the resulting grammar
+				must be ambiguous.  I'm shutting this warning off.
+			 */
+			options {
+				generateAmbigWarnings=false;
+			}
+		:
+			{ LA(2)!='/' }? '*'
+		|	'\r' '\n'		{newline();}
+		|	'\r'			{newline();}
+		|	'\n'			{newline();}
+		|	~('*'|'\n'|'\r')
+		)*
+		"*/"
+		{$setType(Token.SKIP);}
+	;
+
+
+// character literals
+CHAR_LITERAL
+	:	'\'' ( ESC | ~'\'' ) '\''
+	;
+
+// string literals
+STRING_LITERAL
+	:	'"' (ESC|~('"'|'\\'))* '"'
+	;
+
+
+// escape sequence -- note that this is protected; it can only be called
+//   from another lexer rule -- it will not ever directly return a token to
+//   the parser
+// There are various ambiguities hushed in this rule.  The optional
+// '0'...'9' digit matches should be matched here rather than letting
+// them go back to STRING_LITERAL to be matched.  ANTLR does the
+// right thing by matching immediately; hence, it's ok to shut off
+// the FOLLOW ambig warnings.
+protected
+ESC
+	:	'\\'
+		(	'n'
+		|	'r'
+		|	't'
+		|	'b'
+		|	'f'
+		|	'"'
+		|	'\''
+		|	'\\'
+		|	('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT 
+		|	('0'..'3')
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	('0'..'7')
+				(	
+					options {
+						warnWhenFollowAmbig = false;
+					}
+				:	'0'..'7'
+				)?
+			)?
+		|	('4'..'7')
+			(
+				options {
+					warnWhenFollowAmbig = false;
+				}
+			:	('0'..'9')
+			)?
+		)
+	;
+
+
+// hexadecimal digit (again, note it's protected!)
+protected
+HEX_DIGIT
+	:	('0'..'9'|'A'..'F'|'a'..'f')
+	;
+
+
+// a dummy rule to force vocabulary to be all characters (except special
+//   ones that ANTLR uses internally (0 to 2)
+protected
+VOCAB
+	:	'\3'..'\377'
+	;
+
+
+// an identifier.  Note that testLiterals is set to true!  This means
+// that after we match the rule, we look in the literals table to see
+// if it's a literal or really an identifer
+IDENT
+	options {testLiterals=true;}
+	:	('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'0'..'9'|'$')*
+	;
+
+
+// a numeric literal
+NUM_INT
+	{boolean isDecimal=false;}
+	:	'.' {_ttype = DOT;}
+			(('0'..'9')+ (EXPONENT)? (FLOAT_SUFFIX)? { _ttype = NUM_FLOAT; })?
+	|	(	'0' {isDecimal = true;} // special case for just '0'
+			(	('x'|'X')
+				(											// hex
+					// the 'e'|'E' and float suffix stuff look
+					// like hex digits, hence the (...)+ doesn't
+					// know when to stop: ambig.  ANTLR resolves
+					// it correctly by matching immediately.  It
+					// is therefor ok to hush warning.
+					options {
+						warnWhenFollowAmbig=false;
+					}
+				:	HEX_DIGIT
+				)+
+			|	('0'..'7')+									// octal
+			)?
+		|	('1'..'9') ('0'..'9')*  {isDecimal=true;}		// non-zero decimal
+		)
+		(	('l'|'L')
+		
+		// only check to see if it's a float if looks like decimal so far
+		|	{isDecimal}?
+			(	'.' ('0'..'9')* (EXPONENT)? (FLOAT_SUFFIX)?
+			|	EXPONENT (FLOAT_SUFFIX)?
+			|	FLOAT_SUFFIX
+			)
+			{ _ttype = NUM_FLOAT; }
+		)?
+	;
+
+
+// a couple protected methods to assist in matching floating point numbers
+protected
+EXPONENT
+	:	('e'|'E') ('+'|'-')? ('0'..'9')+
+	;
+
+
+protected
+FLOAT_SUFFIX
+	:	'f'|'F'|'d'|'D'
+	;
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/antlr/java.tree.g b/trunk/src/etc/testcases/taskdefs/optional/antlr/java.tree.g
new file mode 100644
index 0000000..f065c35
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/antlr/java.tree.g
@@ -0,0 +1,312 @@
+/** Java 1.2 AST Recognizer Grammar
+ *
+ * Author:
+ *	Terence Parr	parrt@jguru.com
+ *
+ * Version tracking now done with following ID:
+ *
+ * This grammar is in the PUBLIC DOMAIN
+ *
+ * BUGS
+ */
+class JavaTreeParser extends TreeParser;
+
+options {
+	importVocab = Java;
+}
+
+compilationUnit
+	:	(packageDefinition)?
+		(importDefinition)*
+		(typeDefinition)*
+	;
+
+packageDefinition
+	:	#( PACKAGE_DEF identifier )
+	;
+
+importDefinition
+	:	#( IMPORT identifierStar )
+	;
+
+typeDefinition
+	:	#(CLASS_DEF modifiers IDENT extendsClause implementsClause objBlock )
+	|	#(INTERFACE_DEF modifiers IDENT extendsClause interfaceBlock )
+	;
+
+typeSpec
+	:	#(TYPE typeSpecArray)
+	;
+
+typeSpecArray
+	:	#( ARRAY_DECLARATOR typeSpecArray )
+	|	type
+	;
+
+type:	identifier
+	|	builtInType
+	;
+
+builtInType
+    :   "void"
+    |   "boolean"
+    |   "byte"
+    |   "char"
+    |   "short"
+    |   "int"
+    |   "float"
+    |   "long"
+    |   "double"
+    ;
+
+modifiers
+	:	#( MODIFIERS (modifier)* )
+	;
+
+modifier
+    :   "private"
+    |   "public"
+    |   "protected"
+    |   "static"
+    |   "transient"
+    |   "final"
+    |   "abstract"
+    |   "native"
+    |   "threadsafe"
+    |   "synchronized"
+    |   "const"
+    |   "volatile"
+    ;
+
+extendsClause
+	:	#(EXTENDS_CLAUSE (identifier)* )
+	;
+
+implementsClause
+	:	#(IMPLEMENTS_CLAUSE (identifier)* )
+	;
+
+
+interfaceBlock
+	:	#(	OBJBLOCK
+			(	methodDecl
+			|	variableDef
+			)*
+		)
+	;
+	
+objBlock
+	:	#(	OBJBLOCK
+			(	ctorDef
+			|	methodDef
+			|	variableDef
+			|	typeDefinition
+			|	#(STATIC_INIT slist)
+			|	#(INSTANCE_INIT slist)
+			)*
+		)
+	;
+
+ctorDef
+	:	#(CTOR_DEF modifiers methodHead slist)
+	;
+
+methodDecl
+	:	#(METHOD_DEF modifiers typeSpec methodHead)
+	;
+
+methodDef
+	:	#(METHOD_DEF modifiers typeSpec methodHead (slist)?)
+	;
+
+variableDef
+	:	#(VARIABLE_DEF modifiers typeSpec variableDeclarator varInitializer)
+	;
+
+parameterDef
+	:	#(PARAMETER_DEF modifiers typeSpec IDENT )
+	;
+
+objectinitializer
+	:	#(INSTANCE_INIT slist)
+	;
+
+variableDeclarator
+	:	IDENT
+	|	LBRACK variableDeclarator
+	;
+
+varInitializer
+	:	#(ASSIGN initializer)
+	|
+	;
+
+initializer
+	:	expression
+	|	arrayInitializer
+	;
+
+arrayInitializer
+	:	#(ARRAY_INIT (initializer)*)
+	;
+
+methodHead
+	:	IDENT #( PARAMETERS (parameterDef)* ) (throwsClause)?
+	;
+
+throwsClause
+	:	#( "throws" (identifier)* )
+	;
+
+identifier
+	:	IDENT
+	|	#( DOT identifier IDENT )
+	;
+
+identifierStar
+	:	IDENT
+	|	#( DOT identifier (STAR|IDENT) )
+	;
+
+slist
+	:	#( SLIST (stat)* )
+	;
+
+stat:	typeDefinition
+	|	variableDef
+	|	expression
+	|	#(LABELED_STAT IDENT stat)
+	|	#("if" expression stat (stat)? )
+	|	#(	"for"
+			#(FOR_INIT (variableDef | elist)?)
+			#(FOR_CONDITION (expression)?)
+			#(FOR_ITERATOR (elist)?)
+			stat
+		)
+	|	#("while" expression stat)
+	|	#("do" stat expression)
+	|	#("break" (IDENT)? )
+	|	#("continue" (IDENT)? )
+	|	#("return" (expression)? )
+	|	#("switch" expression (caseGroup)*)
+	|	#("throw" expression)
+	|	#("synchronized" expression stat)
+	|	tryBlock
+	|	slist // nested SLIST
+	|	EMPTY_STAT
+	;
+
+caseGroup
+	:	#(CASE_GROUP (#("case" expression) | "default")+ slist)
+	;
+
+tryBlock
+	:	#( "try" slist (handler)* (#("finally" slist))? )
+	;
+
+handler
+	:	#( "catch" parameterDef slist )
+	;
+
+elist
+	:	#( ELIST (expression)* )
+	;
+
+expression
+	:	#(EXPR expr)
+	;
+
+expr:	#(QUESTION expr expr expr)	// trinary operator
+	|	#(ASSIGN expr expr)			// binary operators...
+	|	#(PLUS_ASSIGN expr expr)
+	|	#(MINUS_ASSIGN expr expr)
+	|	#(STAR_ASSIGN expr expr)
+	|	#(DIV_ASSIGN expr expr)
+	|	#(MOD_ASSIGN expr expr)
+	|	#(SR_ASSIGN expr expr)
+	|	#(BSR_ASSIGN expr expr)
+	|	#(SL_ASSIGN expr expr)
+	|	#(BAND_ASSIGN expr expr)
+	|	#(BXOR_ASSIGN expr expr)
+	|	#(BOR_ASSIGN expr expr)
+	|	#(LOR expr expr)
+	|	#(LAND expr expr)
+	|	#(BOR expr expr)
+	|	#(BXOR expr expr)
+	|	#(BAND expr expr)
+	|	#(NOT_EQUAL expr expr)
+	|	#(EQUAL expr expr)
+	|	#(LT expr expr)
+	|	#(GT expr expr)
+	|	#(LE expr expr)
+	|	#(GE expr expr)
+	|	#(SL expr expr)
+	|	#(SR expr expr)
+	|	#(BSR expr expr)
+	|	#(PLUS expr expr)
+	|	#(MINUS expr expr)
+	|	#(DIV expr expr)
+	|	#(MOD expr expr)
+	|	#(STAR expr expr)
+	|	#(INC expr)
+	|	#(DEC expr)
+	|	#(POST_INC expr)
+	|	#(POST_DEC expr)
+	|	#(BNOT expr)
+	|	#(LNOT expr)
+	|	#("instanceof" expr expr)
+	|	#(UNARY_MINUS expr)
+	|	#(UNARY_PLUS expr)
+	|	primaryExpression
+	;
+
+primaryExpression
+    :   IDENT
+    |   #(	DOT
+			(	expr
+				(	IDENT
+				|	arrayIndex
+				|	"this"
+				|	"class"
+				|	#( "new" IDENT elist )
+				)
+			|	#(ARRAY_DECLARATOR type)
+			|	builtInType ("class")?
+			)
+		)
+	|	arrayIndex
+	|	#(METHOD_CALL primaryExpression elist)
+	|	#(TYPECAST typeSpec expr)
+	|   newExpression
+	|   constant
+    |   "super"
+    |   "true"
+    |   "false"
+    |   "this"
+    |   "null"
+	|	typeSpec // type name used with instanceof
+	;
+
+arrayIndex
+	:	#(INDEX_OP primaryExpression expression)
+	;
+
+constant
+    :   NUM_INT
+    |   CHAR_LITERAL
+    |   STRING_LITERAL
+    |   NUM_FLOAT
+    ;
+
+newExpression
+	:	#(	"new" type
+			(	newArrayDeclarator (arrayInitializer)?
+			|	elist
+			)
+		)
+			
+	;
+
+newArrayDeclarator
+	:	#( ARRAY_DECLARATOR (newArrayDeclarator)? (expression)? )
+	;
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/depend.xml b/trunk/src/etc/testcases/taskdefs/optional/depend/depend.xml
new file mode 100644
index 0000000..ad316b1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/depend.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="depend" basedir="." default="help">
+  <property name="src1.dir" value="src1"/>
+  <property name="src2.dir" value="src2"/>
+  <property name="src3.dir" value="src3"/>
+  <property name="src4.dir" value="src4"/>
+  <property name="src5.dir" value="src5"/>
+
+  <property name="tempsrc.dir" value="working"/>
+  <property name="cache.dir" value="working"/>
+  <property name="classes.dir" value="classes"/>
+  <target name="help">
+    <echo>This buildfile is used as part of Ant's test suite.</echo>
+  </target>
+
+  <target name="basesetup" depends="clean">
+    <mkdir dir="${tempsrc.dir}"/>
+  </target>
+
+  <target name="src1setup" depends="basesetup">
+    <copy todir="${tempsrc.dir}">
+      <fileset dir="${src1.dir}"/>
+    </copy>
+  </target>
+
+  <target name="src2setup" depends="basesetup">
+    <copy todir="${tempsrc.dir}">
+      <fileset dir="${src2.dir}"/>
+    </copy>
+  </target>
+
+  <target name="src3setup" depends="basesetup">
+    <copy todir="${tempsrc.dir}">
+      <fileset dir="${src3.dir}"/>
+    </copy>
+  </target>
+
+  <target name="src4setup" depends="basesetup">
+    <copy todir="${tempsrc.dir}">
+      <fileset dir="${src4.dir}"/>
+    </copy>
+  </target>
+
+  <target name="src5setup" depends="basesetup">
+    <copy todir="${tempsrc.dir}">
+      <fileset dir="${src5.dir}"/>
+    </copy>
+  </target>
+
+  <target name="compile">
+    <mkdir dir="${classes.dir}"/>
+    <javac srcdir="${tempsrc.dir}" destdir="${classes.dir}"/>
+  </target>
+
+  <target name="clean">
+    <delete dir="${classes.dir}"/>
+    <delete dir="${tempsrc.dir}"/>
+  </target>
+
+  <target name="testdirect" depends="src1setup, compile">
+    <sleep seconds="3"/>
+    <delete file="${tempsrc.dir}/C.java"/>
+    <copy file="${src1.dir}/C.java" tofile="${tempsrc.dir}/C.java"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}"/>
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+
+  <target name="testclosure" depends="src1setup, compile">
+    <sleep seconds="3"/>
+    <delete file="${tempsrc.dir}/C.java"/>
+    <copy file="${src1.dir}/C.java" tofile="${tempsrc.dir}/C.java"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}" closure="yes"/>
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+
+  <target name="testbasicset" depends="src1setup, compile">
+    <classfileset id="result" dir="${classes.dir}" rootclass="A"/>
+  </target>
+
+  <target name="testsmallset" depends="src1setup, compile">
+    <classfileset id="result" dir="${classes.dir}" rootclass="B"/>
+  </target>
+
+  <target name="testresourcecollection" depends="testsmallset">
+    <fail>
+      <condition>
+        <not>
+          <and>
+            <resourcecount count="2" refid="result" />
+            <resourcecount count="1">
+              <intersect>
+                <resources refid="result" />
+                <file file="${classes.dir}/B.class" />
+              </intersect>
+            </resourcecount>
+            <resourcecount count="1">
+              <intersect>
+                <resources refid="result" />
+                <file file="${classes.dir}/C.class" />
+              </intersect>
+            </resourcecount>
+          </and>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testcomboset" depends="src1setup, compile">
+    <classfileset id="result" dir="${classes.dir}" rootclass="B">
+      <include name="**/C.class"/>
+    </classfileset>
+  </target>
+
+  <target name="testbyreference" depends="src1setup, compile">
+    <classfileset id="classSet" dir="${classes.dir}" rootclass="A">
+      <include name="**/C.class"/>
+    </classfileset>
+    <jar destfile="${tempsrc.dir}/test.jar">
+      <fileset refid="classSet"/>
+    </jar>
+  </target>
+
+  <target name="testmethodparam" depends="src1setup, compile">
+    <classfileset id="result" dir="${classes.dir}" rootclass="E"/>
+  </target>
+
+  <target name="testinner" depends="src2setup, compile">
+    <sleep seconds="3"/>
+    <delete file="${tempsrc.dir}/B.java"/>
+    <copy file="${src2.dir}/B.java" tofile="${tempsrc.dir}/B.java"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}" closure="yes"/>
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+
+  <target name="testinnerinner" depends="src3setup, compile">
+    <sleep seconds="3"/>
+    <delete file="${tempsrc.dir}/B.java"/>
+    <copy file="${src3.dir}/B.java" tofile="${tempsrc.dir}/B.java"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}" closure="yes"/>
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+
+  <target name="testmethodparaminner" depends="src4setup, compile">
+    <classfileset id="result" dir="${classes.dir}" rootclass="test.MethodParam"/>
+  </target>  
+
+  <target name="testnosource" depends="src1setup, compile">
+    <depend destdir="${classes.dir}" closure="yes"/>
+  </target>
+
+  <target name="testemptysource" depends="src1setup, compile">
+    <depend srcdir="" destdir="${classes.dir}" closure="yes"/>
+  </target>
+
+  <target name="testinnerclosure" depends="src4setup">
+    <mkdir dir="${classes.dir}"/>
+    <path id="path.compile">
+        <pathelement location="${classes.dir}"/>
+    </path>
+
+    <javac srcdir="${tempsrc.dir}" destdir="${classes.dir}"
+           classpathref="path.compile"/>
+
+    <sleep seconds="3"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}" 
+            closure="yes" dump="yes"
+            classpathref="path.compile"/>
+
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+
+  <target name="testcache" depends="src1setup, compile">
+    <depend cache="${cache.dir}" srcdir="${tempsrc.dir}" 
+            destdir="${classes.dir}" closure="yes"/>
+    <depend cache="${cache.dir}" srcdir="${tempsrc.dir}" 
+            destdir="${classes.dir}" closure="yes"/>
+  </target>
+
+  <target name="testnonpublic" depends="src5setup, compile">
+    <sleep seconds="3"/>
+    <delete file="${tempsrc.dir}/B.java"/>
+    <copy file="${src2.dir}/B.java" tofile="${tempsrc.dir}/B.java"/>
+    <depend srcdir="${tempsrc.dir}" destdir="${classes.dir}" closure="yes"/>
+    <fileset id="result" dir="${classes.dir}"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src1/A.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/A.java
new file mode 100644
index 0000000..dc6df23
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/A.java
@@ -0,0 +1,20 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class A extends B {
+    private D d = new D();
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src1/B.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/B.java
new file mode 100644
index 0000000..4be51f7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/B.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class B extends C {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src1/C.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/C.java
new file mode 100644
index 0000000..d2bfca9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/C.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class C {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src1/D.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/D.java
new file mode 100644
index 0000000..127de57
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/D.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class D {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src1/E.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/E.java
new file mode 100644
index 0000000..0efd613
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src1/E.java
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class E {
+    E() {
+        System.out.println(A.class);
+    }
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src2/A.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src2/A.java
new file mode 100644
index 0000000..02b35be
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src2/A.java
@@ -0,0 +1,21 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class A {
+    static private class Inner extends B {
+    }
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src2/B.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src2/B.java
new file mode 100644
index 0000000..bc7b7d2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src2/B.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class B {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src3/A.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src3/A.java
new file mode 100644
index 0000000..1d973b1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src3/A.java
@@ -0,0 +1,23 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class A {
+    static private class Inner {
+        static private class Inner2 extends B {
+        }
+    }
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src3/B.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src3/B.java
new file mode 100644
index 0000000..bc7b7d2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src3/B.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class B {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/ContainsOnlyInner.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/ContainsOnlyInner.java
new file mode 100644
index 0000000..d00254b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/ContainsOnlyInner.java
@@ -0,0 +1,24 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package test;
+
+public class ContainsOnlyInner {
+    void method1() {
+        System.out.println(Outer.Inner.class);
+    }    
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/MethodParam.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/MethodParam.java
new file mode 100644
index 0000000..276f016
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/MethodParam.java
@@ -0,0 +1,24 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package test;
+
+public class MethodParam {
+    void method1() {
+        System.out.print(ContainsOnlyInner.class);
+    }
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/Outer.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/Outer.java
new file mode 100644
index 0000000..0b70900
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src4/test/Outer.java
@@ -0,0 +1,23 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package test;
+
+public class Outer {
+    static class Inner {
+    }
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src5/A.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src5/A.java
new file mode 100644
index 0000000..19521a1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src5/A.java
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class A {
+    APrivate dependency = new APrivate();
+}
+
+class APrivate extends B {
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/depend/src5/B.java b/trunk/src/etc/testcases/taskdefs/optional/depend/src5/B.java
new file mode 100644
index 0000000..bc7b7d2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/depend/src5/B.java
@@ -0,0 +1,19 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+public class B {
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet.xml b/trunk/src/etc/testcases/taskdefs/optional/dotnet.xml
new file mode 100644
index 0000000..86a0088
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet.xml
@@ -0,0 +1,458 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="dotnet" basedir="." default="init">
+  <property environment="env"/>
+  <property name="build.dir" location="dotnet/build"/>
+  <property name="src.dir" location="dotnet"/>
+
+  <property name="out.csc" location="${src.dir}/out.cs"/>
+  <property name="out.app" location="${build.dir}/out.exe"/>
+  <property name="out.type" value="exe"/>
+
+  <target name="probe_for_apps" >
+   <condition property="ilasm.found">
+      <or>
+        <available file="ilasm"     filepath="${env.PATH}" />
+        <available file="ilasm.exe" filepath="${env.PATH}" />
+        <available file="ilasm.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> ilasm.found=${ilasm.found}</echo>
+   <condition property="csc.found">
+      <or>
+        <available file="csc"     filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.PATH}" />
+        <available file="csc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> csc.found=${csc.found}</echo>
+   <!-- visual basic compiler -->
+   <condition property="vbc.found">
+      <or>
+        <available file="vbc"     filepath="${env.PATH}" />
+        <available file="vbc.exe" filepath="${env.PATH}" />
+        <available file="vbc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> vbc.found=${vbc.found}</echo>
+   <!-- visual J# compiler -->
+   <condition property="jsharp.found">
+      <or>
+        <available file="vjc"     filepath="${env.PATH}" />
+        <available file="vjc.exe" filepath="${env.PATH}" />
+        <available file="vjc.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> jsharp.found=${jsharp.found}</echo>
+
+   <!-- Mono C# compiler -->
+   <condition property="mcs.found">
+      <available file="mcs"     filepath="${env.PATH}" />
+    </condition>
+   <echo> mcs.found=${mcs.found}</echo>
+
+   <!-- any C# compiler -->
+   <condition property="c#.found">
+      <or>
+        <isset property="csc.found"/>
+        <isset property="mcs.found"/>
+      </or>
+   </condition>
+
+   <!-- Mono's ilasm -->
+   <condition property="mono.ilasm.found">
+      <available file="ilasm"     filepath="${env.PATH}" />
+    </condition>
+   <echo> mono.ilasm.found=${mono.ilasm.found}</echo>
+
+   <condition property="ildasm.found">
+      <or>
+        <available file="ildasm"     filepath="${env.PATH}" />
+        <available file="ildasm.exe" filepath="${env.PATH}" />
+        <available file="ildasm.exe" filepath="${env.Path}" />
+      </or>
+    </condition>
+   <echo> ildasm.found=${ildasm.found}</echo>
+
+   <condition property="dotnetapps.found">
+      <or>
+        <and>
+          <isset property="mcs.found"/>
+          <isset property="mono.ilasm.found"/>
+        </and>
+        <and>
+          <isset property="csc.found"/>
+<!--         <isset property="vbc.found"/> -->
+          <isset property="ilasm.found"/>
+        </and>
+      </or>
+    </condition>
+   <echo> dotnetapps.found=${dotnetapps.found}</echo>
+
+   <condition property="mono.executable" value="mono">
+        <or>
+          <available file="mono"     filepath="${env.PATH}" />
+          <available file="mono.exe" filepath="${env.PATH}" />
+        </or>
+   </condition>
+   <property name="mono.executable" value="mint"/>
+
+   <!-- now set a prop of the compiler name to whatever we found -->
+   <condition property="cs.compiler" value="csc">
+      <isset property="csc.found"/>
+   </condition>
+
+   <condition property="cs.compiler" value="mcs">
+      <isset property="mcs.found"/>
+   </condition>
+
+  </target>
+
+  <target name="init" depends="probe_for_apps">
+    <mkdir dir="${build.dir}"/>
+  </target>
+
+  <target name="teardown">
+    <delete dir="${build.dir}"/>
+  </target>
+
+  <target name="validate_csc" depends="init">
+    <fail unless="c#.found">Needed C# compiler is missing</fail>
+  </target>
+
+  <target name="validate_ilasm" depends="init">
+    <fail unless="ilasm.found">Needed ilasm is missing</fail>
+  </target>
+
+  <target name="validate_jsharp" depends="init">
+    <fail unless="jsharp.found">No vjc on the path</fail>
+  </target>
+
+
+  <target name="testCSC" depends="testCSC-Mono,testCSC-MS"/>
+
+  <target name="testCSC-MS" depends="validate_csc" if="csc.found">
+    <property name="testCSC.exe"
+      location="${build.dir}/ExampleCsc.exe" />
+    <csc
+      destFile="${testCSC.exe}"
+      targetType="exe"
+      srcDir="${src.dir}"
+      >
+    </csc>
+    <available property="app.created" file="${testCSC.exe}"/>
+    <fail unless="app.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${testCSC.exe}" failonerror="true" />
+    <delete file="${testCSC.exe}"/>
+  </target>
+
+  <target name="testCSC-Mono" depends="validate_csc" if="mcs.found">
+    <property name="testCSC.exe"
+      location="${build.dir}/ExampleCsc.exe" />
+    <csc
+      destFile="${testCSC.exe}"
+      targetType="exe"
+      includedefaultreferences="true"
+      srcDir="${src.dir}"
+      >
+    </csc>
+    <available property="app.created" file="${testCSC.exe}"/>
+    <fail unless="app.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${mono.executable}" failonerror="true">
+      <arg value="${testCSC.exe}"/>
+    </exec>
+    <delete file="${testCSC.exe}"/>
+  </target>
+
+  <target name="testCSCResources" depends="testCSCResources-Mono,testCSCResources-MS"/>
+
+  <target name="testCSCResources-MS" depends="validate_csc" if="csc.found">
+    <property name="testCSCRes.exe"
+      location="${build.dir}/ExampleCscRes.exe" />
+    <csc
+      destFile="${testCSCRes.exe}"
+      targetType="exe"
+      srcDir="${src.dir}"
+      >
+      <resource file="${src.dir}/res.resources"/>
+    </csc>
+    <available property="app-res.created" file="${testCSCRes.exe}"/>
+    <fail unless="app-res.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${testCSCRes.exe}" failonerror="true" />
+    <delete file="${testCSCRes.exe}"/>
+    <csc
+      destFile="${testCSCRes.exe}"
+      targetType="exe"
+      srcDir="${src.dir}"
+      >
+      <resource namespace="some.namespace" embed="true">
+        <fileset file="${src.dir}/res.resources"/>
+      </resource>
+    </csc>
+    <available property="app-res-2.created" file="${testCSCRes.exe}"/>
+    <fail unless="app-res-2.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${testCSCRes.exe}" failonerror="true" />
+    <delete file="${testCSCRes.exe}"/>
+  </target>
+
+  <target name="testCSCResources-Mono" depends="validate_csc" if="mcs.found">
+    <property name="testCSCRes.exe"
+      location="${build.dir}/ExampleCscRes.exe" />
+    <csc
+      destFile="${testCSCRes.exe}"
+      targetType="exe"
+      includedefaultreferences="true"
+      srcDir="${src.dir}"
+      >
+      <resource file="${src.dir}/res.resources"/>
+    </csc>
+    <available property="app-res.created" file="${testCSCRes.exe}"/>
+    <fail unless="app-res.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${mono.executable}" failonerror="true">
+      <arg value="${testCSCRes.exe}"/>
+    </exec>
+    <delete file="${testCSCRes.exe}"/>
+  </target>
+
+  <target name="testCSCintrinsicFileset"
+          depends="testCSCintrinsicFileset-MS,testCSCintrinsicFileset-Mono"/>
+
+  <target name="testCSCintrinsicFileset-MS" depends="validate_csc" if="csc.found">
+    <property name="testCSC.exe"
+      location="${build.dir}/ExampleCsc.exe"/>
+    <csc
+      destFile="${testCSC.exe}"
+      targetType="exe"
+      srcDir="${src.dir}"
+      includes="**/*.cs"
+      >
+    </csc>
+    <available property="app.created" file="${testCSC.exe}"/>
+    <fail unless="app.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${testCSC.exe}" failonerror="true" />
+    <delete file="${testCSC.exe}"/>
+  </target>
+
+  <target name="testCSCintrinsicFileset-Mono" depends="validate_csc" if="mcs.found">
+    <property name="testCSC.exe"
+      location="${build.dir}/ExampleCsc.exe"/>
+    <csc
+      destFile="${testCSC.exe}"
+      targetType="exe"
+      srcDir="${src.dir}"
+      includes="**/*.cs"
+      includedefaultreferences="true"
+      >
+    </csc>
+    <available property="app.created" file="${testCSC.exe}"/>
+    <fail unless="app.created">No app ${testCSC.exe} created</fail>
+    <exec executable="${mono.executable}" failonerror="true">
+      <arg value="${testCSC.exe}"/>
+    </exec>
+    <delete file="${testCSC.exe}"/>
+  </target>
+
+  <target name="testCSCdll" depends="testCSCdll-MS,testCSCdll-Mono"/>
+
+  <target name="testCSCdll-MS" depends="validate_csc" if="csc.found">
+    <property name="testCSC.dll"
+      location="${build.dir}/Example2.dll" />
+    <csc
+      destFile="${testCSC.dll}"
+      targetType="library"
+      executable="csc"
+      >
+      <src dir="${src.dir}" includes="example2.cs"/>
+    </csc>
+    <available property="dll.created" file="${testCSC.dll}"/>
+    <fail unless="dll.created">No file ${testCSC.dll} created</fail>
+    <property name="testCSC2.dll"
+      location="${build.dir}/folder  with dir/Example3.dll" />
+    <mkdir dir="${build.dir}/folder  with dir"/>
+    <csc
+      destFile="${testCSC2.dll}"
+      targetType="library"
+      executable="csc"
+      >
+      <src dir="${src.dir}" includes="example3.cs"/>
+    </csc>
+    <available property="dll2.created" file="${testCSC2.dll}"/>
+    <fail unless="dll2.created">No file ${testCSC2.dll} created</fail>
+  </target>
+
+  <target name="testCSCdll-Mono" depends="validate_csc" if="mcs.found">
+    <property name="testCSC.dll"
+      location="${build.dir}/Example2.dll" />
+    <csc
+      destFile="${testCSC.dll}"
+      targetType="library"
+      includedefaultreferences="true"
+      >
+      <src dir="${src.dir}" includes="example2.cs"/>
+    </csc>
+    <available property="dll.created" file="${testCSC.dll}"/>
+    <fail unless="dll.created">No file ${testCSC.dll} created</fail>
+  </target>
+
+  <target name="testCscReferences"
+    depends="testCscReferences-MS,testCscReferences-Mono"/>
+
+  <target name="testCscReferences-MS" depends="validate_csc,testCSCdll-MS"
+          if="csc.found">
+    <property name="testCscReferences.exe"
+      location="${build.dir}/ExampleCsc2.exe" />
+    <csc
+      destFile="${testCscReferences.exe}"
+      targetType="exe"
+      >
+      <src file="${src.dir}/example.cs"/>
+      <reference file="${testCSC.dll}" />
+      <reference file="${testCSC2.dll}" />
+      <define name="RELEASE" />
+      <define name="DEBUG" if="undefined.property"/>
+      <define name="def3" unless="undefined.property"/>
+    </csc>
+    <available property="refapp.created" file="${testCscReferences.exe}"/>
+    <fail unless="refapp.created">No app ${testCscReferences.exe} created</fail>
+    <copy file="${testCSC2.dll}" todir="${build.dir}"/>
+    <exec executable="${testCscReferences.exe}" failonerror="true" />
+  </target>
+
+  <target name="testCscReferences-Mono" depends="validate_csc,testCSCdll-Mono"
+          if="mcs.found">
+    <property name="testCscReferences.exe"
+      location="${build.dir}/ExampleCsc2.exe" />
+    <csc
+      destFile="${testCscReferences.exe}"
+      targetType="exe"
+      includedefaultreferences="true"
+      >
+      <src file="${src.dir}/example.cs"/>
+      <reference file="${testCSC.dll}" />
+      <define name="RELEASE" />
+      <define name="DEBUG" if="undefined.property"/>
+      <define name="def3" unless="undefined.property"/>
+    </csc>
+    <available property="refapp.created" file="${testCscReferences.exe}"/>
+    <fail unless="refapp.created">No app ${testCscReferences.exe} created</fail>
+    <exec executable="${mono.executable}" failonerror="true">
+      <arg value="${testCscReferences.exe}"/>
+    </exec>
+  </target>
+
+  <target name="testILASM"
+    depends="testILASM-Mono,testILASM-MS"
+    if="ilasm.found"/>
+
+  <target name="ilasm" depends="validate_ilasm"
+      if="ilasm.found">
+    <property name="testILASM.exe"
+      location="${build.dir}/ExampleIlasm.exe" />
+    <ilasm
+      destFile="${testILASM.exe}"
+      targetType="exe"
+      >
+      <src dir="${src.dir}" includes="*.il"/>
+    </ilasm>
+    <available property="ilasm.created" file="${testILASM.exe}"/>
+    <fail unless="ilasm.created">No app ${testILASM.exe} created</fail>
+  </target>
+
+    <target name="testILASM-MS" depends="ilasm"
+      if="ilasm.found" unless="mono.ilasm.found">
+      <exec executable="${testILASM.exe}"
+        failonerror="true"/>
+    </target>
+
+    <target name="testILASM-Mono" depends="ilasm"
+      if="mono.ilasm.found">
+      <exec executable="${mono.executable}"
+        failonerror="true">
+        <arg value="${testILASM.exe}"/>
+      </exec>
+    </target>
+
+  <!-- not including this in the test as it creates an exe in the src dir -->
+
+  <target name="testIlasmNoDestFile"  depends="validate_ilasm">
+    <ilasm
+      targetType="exe"
+      >
+      <src dir="${src.dir}" includes="**/*.il"/>
+    </ilasm>
+  </target>
+
+  <!-- just here to look at fileset refid conversion by hand -->
+  <target name="echoFileset">
+    <fileset id="ilasm" dir="${src.dir}" includes="**/*.il" />
+    <property name="ilasm.string" refid="ilasm"/>
+    <echo>${ilasm.string}</echo>
+  </target>
+
+  <target name="testILDASM"   depends="testILASM" if="ildasm.found">
+    <property name="testILDASM.il"
+      location="${build.dir}/ExampleIldasm.il" />
+    <ildasm
+      srcFile="${testILASM.exe}"
+      destFile="${testILDASM.il}"
+      metadata="true"
+      header="true"
+      linenumbers="true"
+      encoding="ascii"
+      />
+    <available property="ildasm.created" file="${testILDASM.il}"/>
+    <fail unless="ildasm.created">No file ${testILDASM.il} created</fail>
+  </target>
+
+  <!-- this is an error -->
+  <target name="testILDASM_empty"   depends="validate_ilasm" >
+    <ildasm/>
+  </target>
+
+  <target name="jsharp" depends="init" if="jsharp.found" >
+    <property name="jsharp.exe"
+      location="${build.dir}/jsharp.exe" />
+    <jsharpc
+        destFile="${jsharp.exe}"
+        targetType="exe"
+        >
+      <src dir="${src.dir}" includes="*.java"/>
+    </jsharpc>
+    <exec executable="${jsharp.exe}" failonerror="true" />
+  </target>
+
+  <target name="testCSCresponseFile" depends="validate_csc" >
+    <property name="testCSCresponseFile.exe"
+      location="${build.dir}/testCSCresponseFile.exe" />
+    <csc
+      destFile="${testCSCresponseFile.exe}"
+      targetType="exe"
+      executable="${cs.compiler}"
+      useResponseFile="true"
+      srcDir="${src.dir}"
+      >
+    </csc>
+    <available property="app.created" file="${testCSCresponseFile.exe}"/>
+    <fail unless="app.created">No app ${testCSCresponseFile.exe} created</fail>
+    <delete file="${testCSCresponseFile.exe}"/>
+  </target>
+
+
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/HelloWorld.wsdl b/trunk/src/etc/testcases/taskdefs/optional/dotnet/HelloWorld.wsdl
new file mode 100644
index 0000000..2c56a66
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/HelloWorld.wsdl
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<definitions name="HelloWorld"
+targetNamespace="http://hello.jaxrpc.samples/"
+xmlns:tns="http://hello.jaxrpc.samples/"
+xmlns="http://schemas.xmlsoap.org/wsdl/"
+xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
+  <types />
+
+  <message name="sayHello">
+    <part name="String_1" type="xsd:string" />
+  </message>
+
+  <message name="sayHelloResponse">
+    <part name="result" type="xsd:string" />
+  </message>
+
+  <portType name="Hello">
+    <operation name="sayHello" parameterOrder="String_1">
+      <input message="tns:sayHello" />
+
+      <output message="tns:sayHelloResponse" />
+    </operation>
+  </portType>
+
+  <binding name="HelloBinding" type="tns:Hello">
+    <operation name="sayHello">
+      <input>
+        <soap:body
+        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+        use="encoded" namespace="http://hello.jaxrpc.samples/" />
+      </input>
+
+      <output>
+        <soap:body
+        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
+        use="encoded" namespace="http://hello.jaxrpc.samples/" />
+      </output>
+
+      <soap:operation soapAction="" />
+    </operation>
+
+    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
+    style="rpc" />
+  </binding>
+
+  <service name="HelloWorld">
+    <port name="HelloPort" binding="tns:HelloBinding">
+      <soap:address
+      location="http://localhost:8080/axis/Hello" />
+    </port>
+  </service>
+</definitions>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.cs b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.cs
new file mode 100644
index 0000000..b5cb879
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.cs
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+using System;
+
+public class Example {
+
+    public static void Main(String[] args) {
+            Example2.echo();
+            Example3.echo();
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.il b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.il
new file mode 100644
index 0000000..2aa6d62
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example.il
@@ -0,0 +1,92 @@
+//created from ildasm of example.cs
+//   Licensed to the Apache Software Foundation (ASF) under one or more
+//   contributor license agreements.  See the NOTICE file distributed with
+//   this work for additional information regarding copyright ownership.
+//   The ASF licenses this file to You under the Apache License, Version 2.0
+//   (the "License"); you may not use this file except in compliance with
+//   the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+
+
+.assembly extern /*23000001*/ mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 1:0:3300:0
+}
+.assembly /*20000001*/ example
+{
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom /*0C000001:0A000001*/ instance void [mscorlib/* 23000001 */]System.Diagnostics.DebuggableAttribute/* 01000002 */::.ctor(bool,
+  //                                                                                                                                  bool) /* 0A000001 */ = ( 01 00 00 01 00 00 ) 
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module example.exe
+// MVID: {641E4709-F7B6-4BB0-BC5D-49C2CF1F1CF8}
+.imagebase 0x00400000
+.subsystem 0x00000003
+.file alignment 512
+.corflags 0x00000001
+// Image base: 0x03180000
+//
+// ============== CLASS STRUCTURE DECLARATION ==================
+//
+.class /*02000002*/ public auto ansi beforefieldinit Example
+       extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
+{
+} // end of class Example
+
+
+// =============================================================
+
+
+// =============== GLOBAL FIELDS AND METHODS ===================
+
+
+// =============================================================
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+//   note that class flags, 'extends' and 'implements' clauses
+//          are provided here for information only
+
+.class /*02000002*/ public auto ansi beforefieldinit Example
+       extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
+{
+  .method /*06000001*/ public hidebysig static 
+          void  Main(string[] args) cil managed
+  // SIG: 00 01 01 1D 0E
+  {
+    .entrypoint
+    // Method begins at RVA 0x2050
+    // Code size       11 (0xb)
+    .maxstack  1
+    IL_0000:  /* 72   | (70)000001       */ ldstr      "hello, I look like Java, but I'm really .NET" /* 70000001 */
+    IL_0005:  /* 28   | (0A)000002       */ call       void [mscorlib/* 23000001 */]System.Console/* 01000003 */::WriteLine(string) /* 0A000002 */
+    IL_000a:  /* 2A   |                  */ ret
+  } // end of method Example::Main
+
+  .method /*06000002*/ public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  // SIG: 20 00 01
+  {
+    // Method begins at RVA 0x2068
+    // Code size       7 (0x7)
+    .maxstack  1
+    IL_0000:  /* 02   |                  */ ldarg.0
+    IL_0001:  /* 28   | (0A)000003       */ call       instance void [mscorlib/* 23000001 */]System.Object/* 01000001 */::.ctor() /* 0A000003 */
+    IL_0006:  /* 2A   |                  */ ret
+  } // end of method Example::.ctor
+
+} // end of class Example
+
+
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.cs b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.cs
new file mode 100644
index 0000000..0f45971
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.cs
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+using System;
+
+/**
+ * this is just here to create confusion
+ */
+public class Example2 {
+
+    public int some_variable=3;
+    
+    public static void echo() {
+        Console.WriteLine("hello, I look like Java, but I'm really .NET");
+    }
+    
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.il b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.il
new file mode 100644
index 0000000..6a5c02f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example2.il
@@ -0,0 +1,45 @@
+//   Licensed to the Apache Software Foundation (ASF) under one or more
+//   contributor license agreements.  See the NOTICE file distributed with
+//   this work for additional information regarding copyright ownership.
+//   The ASF licenses this file to You under the Apache License, Version 2.0
+//   (the "License"); you may not use this file except in compliance with
+//   the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+.class public auto ansi beforefieldinit Example2
+       extends [mscorlib]System.Object
+{
+} // end of class Example2
+
+// =============== CLASS MEMBERS DECLARATION ===================
+//   note that class flags, 'extends' and 'implements' clauses
+//          are provided here for information only
+
+.class public auto ansi beforefieldinit Example2
+       extends [mscorlib]System.Object
+{
+  .field public int32 some_variable
+  .method public hidebysig specialname rtspecialname 
+          instance void  .ctor() cil managed
+  {
+    // Code size       14 (0xe)
+    .maxstack  2
+    IL_0000:  ldarg.0
+    IL_0001:  ldc.i4.3
+    IL_0002:  stfld      int32 Example2::some_variable
+    IL_0007:  ldarg.0
+    IL_0008:  call       instance void [mscorlib]System.Object::.ctor()
+    IL_000d:  ret
+  } // end of method Example2::.ctor
+
+} // end of class Example2
+
+
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/example3.cs b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example3.cs
new file mode 100644
index 0000000..95f6981
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/example3.cs
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+using System;
+
+/**
+ * this is just here to create confusion
+ */
+public class Example3 {
+
+    public static void echo() {
+        Console.WriteLine("hello, I look like Java, but I'm really .NET");
+    }
+
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/jsharp.java b/trunk/src/etc/testcases/taskdefs/optional/dotnet/jsharp.java
new file mode 100644
index 0000000..e237034
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/jsharp.java
@@ -0,0 +1,29 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * 
+ */
+ 
+
+/**
+ * this is a j# class, not a java one.
+ */
+public class jsharp {
+    
+    public static void main(String args[]) {
+		System.out.println("hello, I look like Java, but I'm really J#");
+    }
+    
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/dotnet/res.resources b/trunk/src/etc/testcases/taskdefs/optional/dotnet/res.resources
new file mode 100644
index 0000000..20e265d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/dotnet/res.resources
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/optional/echoproperties.properties b/trunk/src/etc/testcases/taskdefs/optional/echoproperties.properties
new file mode 100644
index 0000000..4c970e7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/echoproperties.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+test.infile=true
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/echoproperties.xml b/trunk/src/etc/testcases/taskdefs/optional/echoproperties.xml
new file mode 100644
index 0000000..7b1b8bb
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/echoproperties.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="def" basedir=".">
+
+  <target name="def">
+  </target>
+
+  <target name="setup">
+    <property name="a.set" value="true" />
+    <property name="b.set" value="false" />
+  </target>
+
+  <target name="testEchoToLog" depends="setup">
+    <echoproperties />
+  </target>
+
+  <target name="testEchoWithEmptyPrefixToLog" depends="setup">
+    <echoproperties prefix=""/>
+  </target>
+
+  <target name="testEchoToLogXml" depends="setup">
+    <echoproperties format="xml" />
+  </target>
+
+  <target name="testReadAndEchoToLog" depends="setup">
+    <echoproperties srcfile="echoproperties.properties" />
+  </target>
+
+  <target name="testReadBadFile" depends="setup">
+    <echoproperties srcfile="." />
+  </target>
+
+  <target name="testReadBadFileFail" depends="setup">
+    <echoproperties srcfile="." failonerror="yes" />
+  </target>
+
+  <target name="testReadBadFileNoFail" depends="setup">
+    <echoproperties srcfile="." failonerror="no" />
+  </target>
+
+  <target name="testEchoToBadFile" depends="setup">
+    <echoproperties destfile="." />
+  </target>
+
+  <target name="testEchoToBadFileFail" depends="setup">
+    <echoproperties destfile="." failonerror="yes" />
+  </target>
+
+  <target name="testEchoToBadFileNoFail" depends="setup">
+    <echoproperties destfile="." failonerror="no" />
+  </target>
+
+  <target name="testEchoToGoodFile" depends="setup">
+    <echoproperties destfile="test.properties" />
+  </target>
+
+  <target name="testEchoToGoodFileXml" depends="setup">
+    <echoproperties destfile="test.xml" format="xml" />
+  </target>
+
+  <target name="testEchoToGoodFileFail" depends="setup">
+    <echoproperties destfile="test.properties" failonerror="yes" />
+  </target>
+
+  <target name="testEchoToGoodFileNoFail" depends="setup">
+    <echoproperties destfile="test.properties" failonerror="no" />
+  </target>
+
+  <target name="testEchoPrefix" depends="setup">
+    <echoproperties destfile="test-prefix.properties" prefix="a." />
+  </target>
+
+  <target name="testEchoPrefixAsPropertyset" depends="setup">
+    <echoproperties destfile="test-prefix.properties">
+      <propertyset>
+        <propertyref prefix="a."/>
+      </propertyset>
+    </echoproperties>
+  </target>
+
+  <target name="testEchoPrefixAsNegatedPropertyset" depends="setup">
+    <echoproperties destfile="test-prefix.properties">
+      <propertyset negate="true">
+        <propertyref prefix="b."/>
+      </propertyset>
+    </echoproperties>
+  </target>
+
+  <target name="testEchoPrefixAsDoublyNegatedPropertyset" depends="setup">
+    <echoproperties destfile="test-prefix.properties">
+      <propertyset negate="true">
+        <propertyset negate="true">
+          <propertyref prefix="a."/>
+        </propertyset>
+      </propertyset>
+    </echoproperties>
+  </target>
+
+  <target name="testWithPrefixAndRegex" depends="setup">
+    <echoproperties prefix="ant." regex=".*ant.*"/>
+  </target>
+
+  <target name="testWithEmptyPrefixAndRegex" depends="setup">
+    <echoproperties prefix="" regex=""/>
+  </target>
+
+  <target name="testWithRegex" depends="setup">
+    <echoproperties regex=".*ant.*"/>
+  </target>
+
+  <target name="cleanup">
+    <delete file="test.properties" failonerror="no" />
+    <delete file="test-prefix.properties" failonerror="no" />
+    <delete file="test.xml" failonerror="no" />
+  </target>
+
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/expected/de/template.txt b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/expected/de/template.txt
new file mode 100644
index 0000000..9a7af4e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/expected/de/template.txt
@@ -0,0 +1 @@
+Diese ist eine Demo Datei für die translate_Aufgabe @missing_token@.
diff --git a/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/resources_ger_DE.properties b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/resources_ger_DE.properties
new file mode 100644
index 0000000..7efe9b0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/resources_ger_DE.properties
@@ -0,0 +1,24 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+This=Diese
+is=ist
+a=eine
+demo=Demo
+file=Datei
+#note for people understanding german
+# \u00fc = u umlaut
+for=für
+the=die
+_task=_Aufgabe
diff --git a/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/template.txt b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/template.txt
new file mode 100644
index 0000000..cda413b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/input/template.txt
@@ -0,0 +1 @@
+@This@ @is@ @a@ @demo@ @file@ @for@ @the@ translate@_task@ @missing_token@.
diff --git a/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/translate.xml b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/translate.xml
new file mode 100644
index 0000000..a82e5fc
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/i18n/translate/translate.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="translate-test" default="test1" basedir=".">
+    <property name="input.dir" value="input"/>
+    <property name="output.dir" value="output"/>
+    <property name="expected.dir" value="expected"/>
+    <target name="setup">
+        <mkdir dir="${output.dir}/de"/>
+    </target>
+    <target name="test1" depends="setup">
+      <translate toDir="${output.dir}/de"
+        starttoken="@"
+        endtoken="@"
+        bundle="${input.dir}/resources"
+        bundlecountry="DE"
+        bundlelanguage="ger"
+        forceoverwrite="yes"
+        srcencoding="ISO8859_1"
+        destencoding="ISO8859_1"
+        bundleencoding="Cp1252">
+        <fileset dir="${input.dir}">
+            <include name="template.txt"/>
+        </fileset>
+      </translate>
+     </target>
+     <target name="cleanup">
+         <delete dir="${output.dir}" quiet="true"/>
+     </target>
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/image/image.xml b/trunk/src/etc/testcases/taskdefs/optional/image/image.xml
new file mode 100644
index 0000000..e30b390
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/image/image.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="image-test" default="main" basedir=".">
+
+   <target name="main" depends="testSimpleScale">
+   </target>
+
+    <target name="init">
+        <property name="src.dir" location="${basedir}/src"/>
+        <property name="dest.dir" location="${basedir}/dest"/>
+        <mkdir dir="${dest.dir}"/>
+    </target>
+    
+    <target name="cleanup">
+        <delete dir="${dest.dir}"/>   
+    </target>
+   
+   	<!-- this should produce a single file in the dest dir -->
+	 	<target name="testSimpleScale" depends="init">
+			<image includes="*.jpg" srcdir="${src.dir}" destdir="${dest.dir}" overwrite="no" failonerror="no">
+				<scale width="300" proportions="width"/>
+			</image>   
+		</target>   
+
+   	<!-- this should put some text in the log -->
+	 	<target name="testEchoToLog" depends="init">
+			<image includes="*.jpg" srcdir="${src.dir}" destdir="${dest.dir}" overwrite="no" failonerror="no">
+				<scale width="300" proportions="width"/>
+			</image>   
+		</target>   
+		
+   	<!-- this should produce a single file in the dest dir -->
+	 	<target name="testFailOnError" depends="init">
+			<image includes="*.jpg" srcdir="${src.dir}" destdir="${dest.dir}" overwrite="no" failonerror="yes">
+				<scale width="300" proportions="width"/>
+			</image>   
+		</target>   		
+		
+		<!-- this should produce a single file in the dest dir, overwriting any existing file -->
+		<target name="testOverwriteTrue" depends="init">
+			<image includes="*.jpg" srcdir="${src.dir}" destdir="${dest.dir}" overwrite="true" failonerror="no">
+				<scale width="300" proportions="width"/>
+			</image>   
+		</target>   
+
+		<!-- this should not overwrite the existing file -->
+		<target name="testOverwriteFalse" depends="init">
+			<image includes="*.jpg" srcdir="${src.dir}" destdir="${dest.dir}" overwrite="false" failonerror="no">
+				<scale width="300" proportions="width"/>
+			</image>   
+		</target>   
+   
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/image/src/badimage.jpg b/trunk/src/etc/testcases/taskdefs/optional/image/src/badimage.jpg
new file mode 100644
index 0000000..43a786e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/image/src/badimage.jpg
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/optional/image/src/largeimage.jpg b/trunk/src/etc/testcases/taskdefs/optional/image/src/largeimage.jpg
new file mode 100644
index 0000000..9104055
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/image/src/largeimage.jpg
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/optional/javah/build.xml b/trunk/src/etc/testcases/taskdefs/optional/javah/build.xml
new file mode 100644
index 0000000..9a14b39
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/javah/build.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="no">
+
+  <property name="out" location="output"/>
+  <property name="in" location="input"/>
+
+  <target name="no">
+    <fail>For tests only</fail>
+  </target>
+
+  <target name="setUp">
+    <mkdir dir="${out}"/>
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${out}"/>
+  </target>
+
+  <target name="compile" depends="setUp">
+    <javac srcdir="${in}" destdir="${out}"/>
+  </target>
+
+  <target name="simple-compile" depends="compile">
+    <javah destdir="${out}">
+      <class name="org.example.Foo"/>
+      <classpath>
+        <pathelement location="${out}"/>
+      </classpath>
+    </javah>
+  </target>
+	
+  <target name="test-fileset" depends="compile">
+  	<javah destdir="${out}">
+  	  <fileset dir="${out}">
+  		<include name="**/*.class"/>
+  	  </fileset>
+  	  <classpath>
+  		<pathelement location="${out}"/>
+  	  </classpath>
+  	</javah>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/javah/input/org/example/Foo.java b/trunk/src/etc/testcases/taskdefs/optional/javah/input/org/example/Foo.java
new file mode 100644
index 0000000..59d03f7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/javah/input/org/example/Foo.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.example;
+
+public class Foo {
+
+    public Foo() {}
+
+    public native String bar(Object baz);
+
+}
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jdepend/jdepend.xml b/trunk/src/etc/testcases/taskdefs/optional/jdepend/jdepend.xml
new file mode 100644
index 0000000..8418226
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jdepend/jdepend.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <property name="testclasses" location="../../../../../../build/testcases"/>
+  
+  <path id="all-test-classes.id">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <path id="example-classes.id">
+    <pathelement location="${testclasses}/org/apache/tools/ant/util/facade" />
+  </path>
+
+  <path id="test-classes.id">
+    <pathelement location="${testclasses}" />
+  </path>
+
+  <target name="simple">
+    <jdepend>
+      <classespath refid="example-classes.id"/>
+    </jdepend>
+  </target>
+
+  <target name="xml">
+    <jdepend format="xml">
+      <classespath refid="example-classes.id"/>
+    </jdepend>
+  </target>
+
+  <target name="fork">
+    <jdepend fork="yes" includeruntime="yes">
+      <classespath refid="example-classes.id"/>
+    </jdepend>
+  </target>
+
+  <target name="fork-xml">
+    <jdepend fork="yes" format="xml" includeruntime="yes">
+      <classespath refid="example-classes.id"/>
+    </jdepend>
+  </target>
+
+  <target name="fork-timeout">
+    <jdepend fork="yes" timeout="10" includeruntime="yes">
+      <classespath refid="test-classes.id"/>
+    </jdepend>
+  </target>
+
+  <target name="fork-timeout-not">
+    <jdepend fork="yes" timeout="100000" includeruntime="yes">
+      <classespath refid="example-classes.id"/>
+    </jdepend>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/1nvalid-classname.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/1nvalid-classname.jsp
new file mode 100644
index 0000000..f5b42e2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/1nvalid-classname.jsp
@@ -0,0 +1,25 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<%@ page language="java" %>
+<html>
+<head/>
+<body>
+
+my name is <%= this.getClass().getName()  %>
+
+</body>
+</html>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/WEB-INF/web.xml b/trunk/src/etc/testcases/taskdefs/optional/jsp/WEB-INF/web.xml
new file mode 100644
index 0000000..2ef199d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
+  "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
+<web-app/>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/default.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/default.jsp
new file mode 100644
index 0000000..c7296b2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/default.jsp
@@ -0,0 +1,25 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<%@ page language="java" %>
+<html>
+<head/>
+<body>
+
+It is now <%= System.currentTimeMillis() %>
+
+</body>
+</html>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/missing_tld.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/missing_tld.jsp
new file mode 100644
index 0000000..b837fb1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/missing_tld.jsp
@@ -0,0 +1,32 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<%@ page language="java" %>
+<%@ taglib uri="/WEB-INF/tlds/struts-bean.tld" prefix="bean" %>
+<%@ taglib uri="/WEB-INF/tlds/struts-html.tld" prefix="html" %>
+<%@ taglib uri="/WEB-INF/tlds/struts-template.tld" prefix="template" %>
+<html:html locale="true">
+<head>
+<title>shouldnt compile</title>
+<html:base/>
+</head>
+<body>
+
+This page should not compile because refers to TLDs that arent around.
+
+</body>
+
+</html:html>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/simple.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/simple.jsp
new file mode 100644
index 0000000..c7296b2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/simple.jsp
@@ -0,0 +1,25 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<%@ page language="java" %>
+<html>
+<head/>
+<body>
+
+It is now <%= System.currentTimeMillis() %>
+
+</body>
+</html>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/uriroot.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/uriroot.jsp
new file mode 100644
index 0000000..c7296b2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/uriroot.jsp
@@ -0,0 +1,25 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<%@ page language="java" %>
+<html>
+<head/>
+<body>
+
+It is now <%= System.currentTimeMillis() %>
+
+</body>
+</html>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jsp/xml.jsp b/trunk/src/etc/testcases/taskdefs/optional/jsp/xml.jsp
new file mode 100644
index 0000000..2d9a9ed
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jsp/xml.jsp
@@ -0,0 +1,32 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<?xml version="1.0" ?>
+<!-- :mode=xml:indentSize=2 -->
+<!-- note the lack of a language setting here. crimson whined when ISO-8859-1 was set,
+	 that it thought it was loading a file of type ISO_8859_1 and
+	 so there was a mismatch, even though the mismatch is only 
+	 between hyphen types -->
+<jsp:root
+  xmlns:jsp="http://java.sun.com/JSP/Page"
+  version="1.2"
+  >
+<jsp:directive.page language="java" />
+<jsp:directive.page contentType="application/xml" />
+<timestamp>
+<jsp:expression>System.currentTimeMillis()</jsp:expression>
+</timestamp>
+</jsp:root>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/jspc.xml b/trunk/src/etc/testcases/taskdefs/optional/jspc.xml
new file mode 100644
index 0000000..b0c1ef2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/jspc.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="jspc-test" default="main" basedir=".">
+
+   <target name="main" depends="testSimple">
+   </target>
+
+    <target name="init">
+        <property name="jsp.dir" location="jsp"/>
+        <property name="jsp.output.dir" location="${jsp.dir}/java"/>
+        <property name="jsp.verbosity" value="3"/>
+        <property name="jsp.compiler" value="jasper41"/>
+        <mkdir dir="${jsp.output.dir}"/>
+    </target>
+    
+    <target name="cleanup">
+        <delete dir="${jsp.output.dir}"/>   
+    </target>
+   
+   <!-- this should fail -->
+   <!-- it should not create an output file, but it does, which needs
+        cleanup -->
+   <target name="testNoTld" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           srcdir="${jsp.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <include
+               name="missing_tld.jsp"/>
+        </jspc>
+   </target>
+
+   <!-- this should compile to simple.java -->
+    <!-- also, stick to the default compiler here to ensure it still works-->
+   <target name="testSimple" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           srcdir="${jsp.dir}"
+           verbose="${jsp.verbosity}">
+            <include
+               name="simple.jsp"/>
+        </jspc>
+   </target>   
+
+    <!-- this should compile to uriroot.java -->
+    <target name="testUriroot" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           uriroot="${jsp.dir}"
+           srcdir="${jsp.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <include
+                name="uriroot.jsp"/>
+        </jspc>
+    </target> 
+   
+   <!-- this should compile an xml format jsp page to xml.java -->
+    <target name="testXml" depends="init">
+      <jspc
+        destdir="${jsp.output.dir}"
+        uriroot="${jsp.dir}"
+        srcdir="${jsp.dir}"
+        compiler="${jsp.compiler}"
+        verbose="${jsp.verbosity}">
+          <include name="xml.jsp"/>
+      </jspc>
+   </target>
+   
+   <!-- this should compile default.jsp to mangled(%default).java -->
+   <target name="testKeyword" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           srcdir="${jsp.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <include
+               name="default.jsp"/>
+        </jspc>
+   </target>  
+   
+   <!-- this should compile default.jsp to mangled(%default).java -->
+   <target name="testInvalidClassname" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           srcdir="${jsp.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <include
+               name="1nvalid-classname.jsp"/>
+        </jspc>
+   </target>  
+
+   <!-- non jsp pages should be ignored -->
+   <target name="testNotAJspFile" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           srcdir="${jsp.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <include
+               name="wrong_type.txt"/>
+        </jspc>
+   </target>
+   
+   <!-- test for webapp compilation -->
+   <target name="testWebapp" depends="init">
+        <jspc
+           destdir="${jsp.output.dir}"
+           compiler="${jsp.compiler}"
+           verbose="${jsp.verbosity}">
+            <webapp basedir="${jsp.dir}" />
+        </jspc>
+   </target>  
+   
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junit.xml b/trunk/src/etc/testcases/taskdefs/optional/junit.xml
new file mode 100644
index 0000000..074221a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junit.xml
@@ -0,0 +1,261 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="junit-test" basedir="." default="outputTests">
+  <property name="showoutput" value="false" />
+  <path id="test">
+    <pathelement path="${java.class.path}" />
+    <pathelement location="../../../../../build/testcases" />
+  </path>
+
+  <target name="cleanup">
+    <delete file="testlog.txt"/>
+    <delete dir="out" includeemptydirs="true" failonerror="false"/>
+  </target>
+
+  <target name="testForkedOutput">
+    <junit fork="yes" haltonerror="true" haltonfailure="true" 
+           showoutput="${showoutput}">
+      <test name="org.example.junit.Output" />
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="testNonForkedOutput">
+    <junit fork="false" haltonerror="true" haltonfailure="true"
+           showoutput="${showoutput}">
+      <test name="org.example.junit.Output" />
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="testForkedThreadedOutput">
+    <junit fork="yes" haltonerror="true" haltonfailure="true"
+           showoutput="${showoutput}">
+      <test name="org.example.junit.ThreadedOutput" />
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="testNonForkedThreadedOutput">
+    <junit fork="false" haltonerror="true" haltonfailure="true"
+           showoutput="${showoutput}">
+      <test name="org.example.junit.ThreadedOutput" />
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="outputTests" 
+          depends="testForkedOutput,testNonForkedOutput,testForkedThreadedOutput,testNonForkedThreadedOutput" />
+
+  <target name="crash">
+    <junit fork="true" errorproperty="crashed">
+      <test name="org.apache.tools.ant.taskdefs.optional.junit.VmCrash"/>
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="nocrash">
+    <junit fork="true" errorproperty="crashed">
+      <test name="org.apache.tools.ant.taskdefs.optional.junit.NoVmCrash"/>
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="timeout">
+    <junit fork="true" errorproperty="timeout" timeout="1000">
+      <test name="org.apache.tools.ant.taskdefs.optional.junit.Sleeper"/>
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="notimeout">
+    <junit fork="true" errorproperty="timeout" timeout="15000">
+      <test name="org.apache.tools.ant.taskdefs.optional.junit.Sleeper"/>
+      <classpath refid="test" />
+    </junit>
+  </target>
+
+  <target name="capture">
+    <property name="fork" value="false"/>
+    <junit fork="${fork}">
+      <test
+        name="org.apache.tools.ant.taskdefs.optional.junit.Printer"
+        outfile="testlog"/>
+      <formatter type="plain"/>
+      <classpath refid="test"/>
+    </junit>
+  </target>
+
+  <target name="captureToSummary">
+    <property name="fork" value="true"/>
+    <junit fork="${fork}" printSummary="withOutAndErr">
+      <test name="org.apache.tools.ant.taskdefs.optional.junit.Printer"/>
+      <classpath refid="test"/>
+    </junit>
+  </target>
+
+  <target name="testBatchTestForkOnceToDir">
+    <mkdir dir="out"/>
+    <junit fork="true" forkmode="once">
+      <formatter type="xml"/>
+      <classpath refid="test"/>
+      <batchtest todir="out">
+        <fileset dir="../../../../tests/junit">
+          <include
+            name="org/apache/tools/ant/taskdefs/optional/junit/*Test.java"/>
+          <exclude name="**/JUnitTaskTest.java"/>
+          <exclude name="**/JUnitReportTest.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+
+  <!-- Bugzilla Report 32973 -->
+  <target name="testBatchTestForkOnceExtension">
+    <mkdir dir="out"/>
+    <junit fork="true" forkmode="once">
+      <formatter type="xml" extension=".foo"/>
+      <classpath refid="test"/>
+      <batchtest todir="out">
+        <fileset dir="../../../../tests/junit">
+          <include
+            name="org/apache/tools/ant/taskdefs/optional/junit/*Test.java"/>
+          <exclude name="**/JUnitTaskTest.java"/>
+          <exclude name="**/JUnitReportTest.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+
+  <target name="testBatchTestForkOnceCustomFormatter">
+    <mkdir dir="out"/>
+    <junit fork="true" forkmode="once">
+      <formatter extension="foo"
+        classname="org.apache.tools.ant.taskdefs.optional.junit.TestFormatter"/>
+      <classpath refid="test"/>
+      <batchtest todir="out">
+        <fileset dir="../../../../tests/junit">
+          <include
+            name="org/apache/tools/ant/taskdefs/optional/junit/*Test.java"/>
+          <exclude name="**/JUnitTaskTest.java"/>
+          <exclude name="**/JUnitReportTest.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+
+  <target name="failureRecorder.prepare">
+    <property name="tmp.dir" value="out"/>
+    <mkdir dir="${tmp.dir}/org"/>
+    <echo file="${tmp.dir}/A.java">
+        import junit.framework.*;
+        public class A extends TestCase {
+            public A(String s) { super(s); }
+            public void test01() { System.out.println("A.test01"); }
+            public void test02() { System.out.println("A.test02"); fail(); }
+            public void test03() { System.out.println("A.test03"); fail(); }
+        }
+    </echo>
+    <echo file="${tmp.dir}/B.java">
+        import junit.framework.*;
+        public class B extends TestCase {
+            public B(String s) { super(s); }
+            public void test04() { System.out.println("B.test04"); fail(); }
+            public void test05() { System.out.println("B.test05"); }
+            public void test06() { System.out.println("B.test06"); }
+        }
+    </echo>
+    <echo file="${tmp.dir}/C.java">
+        import junit.framework.*;
+        public class C extends TestCase {
+            public C(String s) { super(s); }
+            public void test07() { System.out.println("C.test07"); }
+            public void test08() { System.out.println("C.test08"); }
+            public void test09() { System.out.println("C.test09"); }
+        }
+    </echo>
+    <echo file="${tmp.dir}/org/D.java">
+    	package org;
+        import junit.framework.*;
+        public class D extends TestCase {
+            public D(String s) { super(s); }
+            public void test10() { System.out.println("D.test10"); fail(); }
+        }
+    </echo>
+    <javac srcdir="${tmp.dir}" destdir="${tmp.dir}"/>
+  </target>
+
+  <target name="failureRecorder.internal">  
+    <property name="tmp.dir" value="out"/>
+    <delete>
+      <fileset dir="${tmp.dir}" includes="FailedTests*.class"/>
+    </delete>
+    <!-- compile the FailedTests class if present -->
+    <javac srcdir="${tmp.dir}" destdir="${tmp.dir}"/>
+    <available file="${tmp.dir}/FailedTests.class" property="hasFailingTests"/>
+    
+    <property name="ant.junit.failureCollector" value="${tmp.dir}/FailedTests"/>
+    <junit haltonerror="false" haltonfailure="false">
+      <classpath>
+        <pathelement location="${tmp.dir}"/>
+      </classpath>
+      <batchtest todir="${tmp.dir}" unless="hasFailingTests">
+        <fileset dir="${tmp.dir}" includes="**/*.java" excludes="**/FailedTests.*"/>
+        <!-- for initial creation of the FailingTests.java -->
+        <formatter type="failure"/>
+        <!-- I want to see something ... -->
+        <formatter type="plain" usefile="false"/>
+      </batchtest>
+      <test name="FailedTests" if="hasFailingTests">
+      	<!-- update the FailingTests.java -->
+        <formatter type="failure"/>
+        <!-- again, I want to see something -->
+        <formatter type="plain" usefile="false"/>
+      </test>
+    </junit>
+  </target>
+  
+  <target name="failureRecorder.runtest">
+  	<ant target="failureRecorder.internal"
+         antfile="junit.xml" 
+         inheritAll="false"
+         inheritRefs="false" 
+    />
+  </target>
+  
+  <target name="failureRecorder.fixing">
+    <property name="tmp.dir" value="out"/>
+    <echo file="${tmp.dir}/A.java">
+        import junit.framework.*;
+        public class A extends TestCase {
+            public A(String s) { super(s); }
+            public void test01() { System.out.println("A.test01"); }
+            public void test02() { System.out.println("A.test02"); }
+            public void test03() { System.out.println("A.test03"); }
+        }
+    </echo>
+  </target>
+  
+<target name="copy">
+  <mkdir dir="c:/temp/ant-log"/>
+  <copy file="out/${file}" tofile="c:/temp/ant-log/${nr}-${file}" failonerror="false"/>
+</target>
+
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junit/cdataoutput.xml b/trunk/src/etc/testcases/taskdefs/optional/junit/cdataoutput.xml
new file mode 100644
index 0000000..ab5409b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junit/cdataoutput.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project basedir=".">
+  <target name="run-junit">
+    <junit fork="true">
+      <classpath path="${tests-classpath.value}"/>
+      <sysproperty key="cdata.inner" value="true"/>
+      <test
+        name="org.apache.tools.ant.taskdefs.optional.junit.XMLFormatterWithCDATAOnSystemOut"/>
+      <formatter type="xml"/>
+    </junit>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junit/matches.xml b/trunk/src/etc/testcases/taskdefs/optional/junit/matches.xml
new file mode 100644
index 0000000..3d722a6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junit/matches.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<matches>

+  <foo>

+    <abc>

+      <foo/>

+      <foo/>

+    </abc>

+  </foo>

+</matches>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-frames.xsl b/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-frames.xsl
new file mode 100644
index 0000000..54d66c6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-frames.xsl
@@ -0,0 +1,879 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"

+    xmlns:lxslt="http://xml.apache.org/xslt"

+    xmlns:redirect="http://xml.apache.org/xalan/redirect"

+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"

+    extension-element-prefixes="redirect">

+<xsl:import href="junit-import.xsl"/>

+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>

+<xsl:decimal-format decimal-separator="." grouping-separator=","/>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+ -->

+

+<!--

+

+ Sample stylesheet to be used with Ant JUnitReport output.

+

+ It creates a set of HTML files a la javadoc where you can browse easily

+ through all packages and classes.

+

+-->

+<xsl:param name="output.dir" select="'.'"/>

+<xsl:param name="key1" select="'defaultValue1'"/>

+<xsl:param name="key2" select="'defaultValue2'"/>

+

+<xsl:template match="testsuites">

+    <!-- create the index.html -->

+    <redirect:write file="{$output.dir}/index.html">

+        <xsl:call-template name="index.html"/>

+    </redirect:write>

+

+    <!-- create the stylesheet.css -->

+    <redirect:write file="{$output.dir}/stylesheet.css">

+        <xsl:call-template name="stylesheet.css"/>

+    </redirect:write>

+

+    <!-- create the overview-packages.html at the root -->

+    <redirect:write file="{$output.dir}/overview-summary.html">

+        <xsl:apply-templates select="." mode="overview.packages"/>

+    </redirect:write>

+

+    <!-- create the all-packages.html at the root -->

+    <redirect:write file="{$output.dir}/overview-frame.html">

+        <xsl:apply-templates select="." mode="all.packages"/>

+    </redirect:write>

+

+    <!-- create the all-classes.html at the root -->

+    <redirect:write file="{$output.dir}/allclasses-frame.html">

+        <xsl:apply-templates select="." mode="all.classes"/>

+    </redirect:write>

+

+    <!-- create the all-tests.html at the root -->

+    <redirect:write file="{$output.dir}/all-tests.html">

+        <xsl:apply-templates select="." mode="all.tests"/>

+    </redirect:write>

+

+    <!-- create the alltests-fails.html at the root -->

+    <redirect:write file="{$output.dir}/alltests-fails.html">

+      <xsl:apply-templates select="." mode="all.tests">

+        <xsl:with-param name="type" select="'fails'"/>

+      </xsl:apply-templates>

+    </redirect:write>

+

+  <!-- create the alltests-errors.html at the root -->

+    <redirect:write file="{$output.dir}/alltests-errors.html">

+      <xsl:apply-templates select="." mode="all.tests">

+        <xsl:with-param name="type" select="'errors'"/>

+      </xsl:apply-templates>

+    </redirect:write>

+

+  <!-- process all packages -->

+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">

+        <xsl:call-template name="package">

+            <xsl:with-param name="name" select="@package"/>

+        </xsl:call-template>

+    </xsl:for-each>

+</xsl:template>

+    <xsl:template name="package">

+        <xsl:param name="name"/>

+        <xsl:variable name="package.dir">

+            <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>

+            <xsl:if test="$name = ''">.</xsl:if>

+        </xsl:variable>

+        <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->

+        <!-- create a classes-list.html in the package directory -->

+        <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">

+            <xsl:call-template name="classes.list">

+                <xsl:with-param name="name" select="$name"/>

+            </xsl:call-template>

+        </redirect:write>

+

+        <!-- create a package-summary.html in the package directory -->

+        <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">

+            <xsl:call-template name="package.summary">

+                <xsl:with-param name="name" select="$name"/>

+            </xsl:call-template>

+        </redirect:write>

+

+        <!-- for each class, creates a @name.html -->

+        <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->

+      <xsl:for-each select="/testsuites/testsuite[@package = $name]">

+        <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}.html">

+          <xsl:apply-templates select="." mode="class.details"/>

+        </redirect:write>

+        <xsl:if test="string-length(./system-out)!=0">

+          <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-out.txt">

+            <xsl:value-of disable-output-escaping="yes" select="./system-out"/>

+          </redirect:write>

+        </xsl:if>

+        <xsl:if test="string-length(./system-err)!=0">

+          <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-err.txt">

+            <xsl:value-of disable-output-escaping="yes" select="./system-err"/>

+          </redirect:write>

+        </xsl:if>

+        <xsl:if test="@failures != 0">

+          <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-fails.html">

+            <xsl:apply-templates select="." mode="class.details">

+              <xsl:with-param name="type" select="'fails'"/>

+            </xsl:apply-templates>

+          </redirect:write>

+        </xsl:if>

+        <xsl:if test="@errors != 0">

+          <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-errors.html">

+            <xsl:apply-templates select="." mode="class.details">

+              <xsl:with-param name="type" select="'errors'"/>

+            </xsl:apply-templates>

+          </redirect:write>

+        </xsl:if>

+      </xsl:for-each>

+    </xsl:template>

+

+

+<xsl:template name="index.html">

+<html>

+    <head>

+        <title>

+            Unit Test Results. key1=<xsl:value-of select="$key1"/>,key2=<xsl:value-of select="$key2"/>

+        </title>

+    </head>

+    <frameset cols="20%,80%">

+        <frameset rows="30%,70%">

+            <frame src="overview-frame.html" name="packageListFrame"/>

+            <frame src="allclasses-frame.html" name="classListFrame"/>

+        </frameset>

+        <frame src="overview-summary.html" name="classFrame"/>

+        <noframes>

+            <h2>Frame Alert</h2>

+            <p>

+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.

+            </p>

+        </noframes>

+    </frameset>

+</html>

+</xsl:template>

+

+<!-- this is the stylesheet css to use for nearly everything -->

+<xsl:template name="stylesheet.css">

+body {

+    font:normal 68% verdana,arial,helvetica;

+    color:#000000;

+}

+table tr td, table tr th {

+    font-size: 68%;

+}

+table.details tr th{

+    font-weight: bold;

+    text-align:left;

+    background:#a6caf0;

+}

+table.details tr td{

+    background:#eeeee0;

+}

+

+p {

+    line-height:1.5em;

+    margin-top:0.5em; margin-bottom:1.0em;

+}

+h1 {

+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica

+}

+h2 {

+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica

+}

+h3 {

+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica

+}

+h4 {

+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica

+}

+h5 {

+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica

+}

+h6 {

+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica

+}

+.Error {

+    font-weight:bold; color:red;

+}

+.Failure {

+    font-weight:bold; color:purple;

+}

+.Properties {

+  text-align:right;

+}

+</xsl:template>

+

+<!-- Create list of all/failed/errored tests -->

+<xsl:template match="testsuites" mode="all.tests">

+    <xsl:param name="type" select="'all'"/>

+    <html>

+	<xsl:variable name="title">

+	    <xsl:choose>

+		<xsl:when test="$type = 'fails'">

+		    <xsl:text>All Failures</xsl:text>

+		</xsl:when>

+		<xsl:when test="$type = 'errors'">

+		    <xsl:text>All Errors</xsl:text>

+		</xsl:when>

+		<xsl:otherwise>

+		    <xsl:text>All Tests</xsl:text>

+		</xsl:otherwise>

+	    </xsl:choose>

+	</xsl:variable>

+	<head>

+	    <title>Unit Test Results: <xsl:value-of select="$title"/></title>

+	    <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name"/>

+            </xsl:call-template>

+	</head>

+	<body>

+	    <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>

+            <xsl:call-template name="pageHeader"/>

+            <h2><xsl:value-of select="$title"/></h2>

+

+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+		<xsl:call-template name="testcase.test.header">

+		    <xsl:with-param name="show.class" select="'yes'"/>

+		</xsl:call-template>

+		<!--

+                test can even not be started at all (failure to load the class)

+		so report the error directly

+		-->

+              <xsl:if test="./error">

+                <tr class="Error">

+                  <td colspan="4">

+                    <xsl:apply-templates select="./error"/>

+                  </td>

+                </tr>

+              </xsl:if>

+              <xsl:choose>

+                <xsl:when test="$type = 'fails'">

+                  <xsl:apply-templates select=".//testcase[failure]" mode="print.test">

+                    <xsl:with-param name="show.class" select="'yes'"/>

+                  </xsl:apply-templates>

+                </xsl:when>

+                <xsl:when test="$type = 'errors'">

+                  <xsl:apply-templates select=".//testcase[error]" mode="print.test">

+                    <xsl:with-param name="show.class" select="'yes'"/>

+                  </xsl:apply-templates>

+                </xsl:when>

+                <xsl:otherwise>

+                  <xsl:apply-templates select=".//testcase" mode="print.test">

+                    <xsl:with-param name="show.class" select="'yes'"/>

+                  </xsl:apply-templates>

+                </xsl:otherwise>

+              </xsl:choose>

+            </table>

+        </body>

+    </html>

+</xsl:template>

+

+

+<!-- ======================================================================

+    This page is created for every testsuite class.

+    It prints a summary of the testsuite and detailed information about

+    testcase methods.

+     ====================================================================== -->

+<xsl:template match="testsuite" mode="class.details">

+    <xsl:param name="type" select="'all'"/>

+    <xsl:variable name="package.name" select="@package"/>

+    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>

+    <html>

+        <head>

+          <title>Unit Test Results: <xsl:value-of select="$class.name"/></title>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name" select="$package.name"/>

+            </xsl:call-template>

+       <script type="text/javascript" language="JavaScript">

+        var TestCases = new Array();

+        var cur;

+        <xsl:apply-templates select="properties"/>

+       </script>

+       <script type="text/javascript" language="JavaScript"><![CDATA[

+        function displayProperties (name) {

+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');

+          var doc = win.document;

+          doc.open();

+          doc.write("<html><head><title>Properties of " + name + "</title>");

+          doc.write("<style type=\"text/css\">");

+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");

+          doc.write("table tr td, table tr th { font-size: 68%; }");

+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");

+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");

+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");

+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");

+          doc.write("</style>");

+          doc.write("</head><body>");

+          doc.write("<h3>Properties of " + name + "</h3>");

+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");

+          doc.write("<table class='properties'>");

+          doc.write("<tr><th>Name</th><th>Value</th></tr>");

+          for (prop in TestCases[name]) {

+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");

+          }

+          doc.write("</table>");

+          doc.write("</body></html>");

+          doc.close();

+          win.focus();

+        }

+      ]]>

+      </script>

+        </head>

+        <body>

+            <xsl:call-template name="pageHeader"/>

+            <h3>Class <xsl:value-of select="$class.name"/></h3>

+

+

+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+                <xsl:call-template name="testsuite.test.header"/>

+                <xsl:apply-templates select="." mode="print.test"/>

+            </table>

+

+	    <xsl:choose>

+		<xsl:when test="$type = 'fails'">

+		    <h2>Failures</h2>

+		</xsl:when>

+		<xsl:when test="$type = 'errors'">

+		    <h2>Errors</h2>

+		</xsl:when>

+		<xsl:otherwise>

+		    <h2>Tests</h2>

+		</xsl:otherwise>

+	    </xsl:choose>

+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+		<xsl:call-template name="testcase.test.header"/>

+		<!--

+                test can even not be started at all (failure to load the class)

+		so report the error directly

+		-->

+                <xsl:if test="./error">

+                    <tr class="Error">

+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>

+                    </tr>

+                </xsl:if>

+		<xsl:choose>

+		    <xsl:when test="$type = 'fails'">

+			<xsl:apply-templates select="./testcase[failure]" mode="print.test"/>

+		    </xsl:when>

+		    <xsl:when test="$type = 'errors'">

+			<xsl:apply-templates select="./testcase[error]" mode="print.test"/>

+		    </xsl:when>

+		    <xsl:otherwise>

+			<xsl:apply-templates select="./testcase" mode="print.test"/>

+		    </xsl:otherwise>

+		</xsl:choose>

+            </table>

+            <div class="Properties">

+                <a>

+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>

+                    Properties &#187;

+                </a>

+            </div>

+            <xsl:if test="string-length(./system-out)!=0">

+                <div class="Properties">

+                    <a>

+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-out.txt</xsl:attribute>

+                        System.out &#187;

+                    </a>

+                </div>

+            </xsl:if>

+            <xsl:if test="string-length(./system-err)!=0">

+                <div class="Properties">

+                    <a>

+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-err.txt</xsl:attribute>

+                        System.err &#187;

+                    </a>

+                </div>

+            </xsl:if>

+        </body>

+    </html>

+</xsl:template>

+

+  <!--

+   Write properties into a JavaScript data structure.

+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)

+   -->

+  <xsl:template match="properties">

+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();

+    <xsl:for-each select="property">

+    <xsl:sort select="@name"/>

+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';

+    </xsl:for-each>

+  </xsl:template>

+

+

+<!-- ======================================================================

+    This page is created for every package.

+    It prints the name of all classes that belongs to this package.

+    @param name the package name to print classes.

+     ====================================================================== -->

+<!-- list of classes in a package -->

+<xsl:template name="classes.list">

+    <xsl:param name="name"/>

+    <html>

+        <head>

+            <title>Unit Test Classes: <xsl:value-of select="$name"/></title>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name" select="$name"/>

+            </xsl:call-template>

+        </head>

+        <body>

+            <table width="100%">

+                <tr>

+                    <td nowrap="nowrap">

+                        <h2><a href="package-summary.html" target="classFrame">

+                            <xsl:value-of select="$name"/>

+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>

+                        </a></h2>

+                    </td>

+                </tr>

+            </table>

+

+            <h2>Classes</h2>

+            <table width="100%">

+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">

+                    <xsl:sort select="@name"/>

+                    <tr>

+                        <td nowrap="nowrap">

+                            <a href="{@id}_{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>

+                        </td>

+                    </tr>

+                </xsl:for-each>

+            </table>

+        </body>

+    </html>

+</xsl:template>

+

+

+<!--

+    Creates an all-classes.html file that contains a link to all package-summary.html

+    on each class.

+-->

+<xsl:template match="testsuites" mode="all.classes">

+    <html>

+        <head>

+            <title>All Unit Test Classes</title>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name"/>

+            </xsl:call-template>

+        </head>

+        <body>

+            <h2>Classes</h2>

+            <table width="100%">

+                <xsl:apply-templates select="testsuite" mode="all.classes">

+                    <xsl:sort select="@name"/>

+                </xsl:apply-templates>

+            </table>

+        </body>

+    </html>

+</xsl:template>

+

+<xsl:template match="testsuite" mode="all.classes">

+    <xsl:variable name="package.name" select="@package"/>

+    <tr>

+        <td nowrap="nowrap">

+            <a target="classFrame">

+                <xsl:attribute name="href">

+                    <xsl:if test="not($package.name='')">

+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>

+                    </xsl:if><xsl:value-of select="@id"/>_<xsl:value-of select="@name"/><xsl:text>.html</xsl:text>

+                </xsl:attribute>

+                <xsl:value-of select="@name"/>

+            </a>

+        </td>

+    </tr>

+</xsl:template>

+

+

+<!--

+    Creates an html file that contains a link to all package-summary.html files on

+    each package existing on testsuites.

+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(

+-->

+<xsl:template match="testsuites" mode="all.packages">

+    <html>

+        <head>

+            <title>All Unit Test Packages</title>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name"/>

+            </xsl:call-template>

+        </head>

+        <body>

+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>

+            <h2>Packages</h2>

+            <table width="100%">

+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages">

+                    <xsl:sort select="@package"/>

+                </xsl:apply-templates>

+            </table>

+        </body>

+    </html>

+</xsl:template>

+

+<xsl:template match="testsuite" mode="all.packages">

+    <tr>

+        <td nowrap="nowrap">

+            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame">

+                <xsl:value-of select="@package"/>

+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>

+            </a>

+        </td>

+    </tr>

+</xsl:template>

+

+

+<xsl:template match="testsuites" mode="overview.packages">

+    <html>

+        <head>

+            <title>Unit Test Results: Summary</title>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name"/>

+            </xsl:call-template>

+        </head>

+        <body>

+        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>

+        <xsl:call-template name="pageHeader"/>

+        <h2>Summary</h2>

+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>

+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>

+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>

+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>

+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>

+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+        <tr valign="top">

+            <th>Tests</th>

+            <th>Failures</th>

+            <th>Errors</th>

+            <th>Success rate</th>

+            <th>Time</th>

+        </tr>

+        <tr valign="top">

+            <xsl:attribute name="class">

+                <xsl:choose>

+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>

+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>

+                    <xsl:otherwise>Pass</xsl:otherwise>

+                </xsl:choose>

+            </xsl:attribute>

+            <td><a title="Display all tests" href="all-tests.html"><xsl:value-of select="$testCount"/></a></td>

+            <td><a title="Display all failures" href="alltests-fails.html"><xsl:value-of select="$failureCount"/></a></td>

+            <td><a title="Display all errors" href="alltests-errors.html"><xsl:value-of select="$errorCount"/></a></td>

+            <td>

+                <xsl:call-template name="display-percent">

+                    <xsl:with-param name="value" select="$successRate"/>

+                </xsl:call-template>

+            </td>

+            <td>

+                <xsl:call-template name="display-time">

+                    <xsl:with-param name="value" select="$timeCount"/>

+                </xsl:call-template>

+            </td>

+        </tr>

+        </table>

+        <table border="0" width="95%">

+        <tr>

+        <td style="text-align: justify;">

+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.

+        </td>

+        </tr>

+        </table>

+

+        <h2>Packages</h2>

+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+            <xsl:call-template name="testsuite.test.header"/>

+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">

+                <xsl:sort select="@package" order="ascending"/>

+                <!-- get the node set containing all testsuites that have the same package -->

+                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/>

+                <tr valign="top">

+                    <!-- display a failure if there is any failure/error in the package -->

+                    <xsl:attribute name="class">

+                        <xsl:choose>

+                            <xsl:when test="sum($insamepackage/@errors) &gt; 0">Error</xsl:when>

+                            <xsl:when test="sum($insamepackage/@failures) &gt; 0">Failure</xsl:when>

+                            <xsl:otherwise>Pass</xsl:otherwise>

+                        </xsl:choose>

+                    </xsl:attribute>

+                    <td><a href="./{translate(@package,'.','/')}/package-summary.html">

+                        <xsl:value-of select="@package"/>

+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>

+                    </a></td>

+                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td>

+                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td>

+                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td>

+                    <td>

+                    <xsl:call-template name="display-time">

+                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/>

+                    </xsl:call-template>

+                    </td>

+                    <td><xsl:value-of select="$insamepackage/@timestamp"/></td>

+                    <td><xsl:value-of select="$insamepackage/@hostname"/></td>

+                </tr>

+            </xsl:for-each>

+        </table>

+        </body>

+        </html>

+</xsl:template>

+

+

+<xsl:template name="package.summary">

+    <xsl:param name="name"/>

+    <html>

+        <head>

+            <xsl:call-template name="create.stylesheet.link">

+                <xsl:with-param name="package.name" select="$name"/>

+            </xsl:call-template>

+        </head>

+        <body>

+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>

+            <xsl:call-template name="pageHeader"/>

+            <h3>Package <xsl:value-of select="$name"/></h3>

+

+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">

+                <xsl:call-template name="class.metrics.header"/>

+                <xsl:apply-templates select="." mode="print.metrics"/>

+            </table-->

+

+            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/>

+            <xsl:if test="count($insamepackage) &gt; 0">

+                <h2>Classes</h2>

+                <p>

+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">

+                    <xsl:call-template name="testsuite.test.header"/>

+                    <xsl:apply-templates select="$insamepackage" mode="print.test">

+                        <xsl:sort select="@name"/>

+                    </xsl:apply-templates>

+                </table>

+                </p>

+            </xsl:if>

+        </body>

+    </html>

+</xsl:template>

+

+

+<!--

+    transform string like a.b.c to ../../../

+    @param path the path to transform into a descending directory path

+-->

+<xsl:template name="path">

+    <xsl:param name="path"/>

+    <xsl:if test="contains($path,'.')">

+        <xsl:text>../</xsl:text>

+        <xsl:call-template name="path">

+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>

+        </xsl:call-template>

+    </xsl:if>

+    <xsl:if test="not(contains($path,'.')) and not($path = '')">

+        <xsl:text>../</xsl:text>

+    </xsl:if>

+</xsl:template>

+

+

+<!-- create the link to the stylesheet based on the package name -->

+<xsl:template name="create.stylesheet.link">

+    <xsl:param name="package.name"/>

+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>

+</xsl:template>

+

+

+<!-- Page HEADER -->

+<xsl:template name="pageHeader">

+    <h1>Unit Test Results</h1>

+    <table width="100%">

+    <tr>

+        <td align="left"></td>

+        <td align="right">Designed for use with <a href="http://www.junit.org/">JUnit</a> and <a href="http://ant.apache.org/">Ant</a>.</td>

+    </tr>

+    </table>

+    <hr size="1"/>

+</xsl:template>

+

+    <xsl:template name="testsuite.test.header">

+        <tr valign="top">

+            <th width="80%">Name</th>

+            <th>Tests</th>

+            <th>Errors</th>

+            <th>Failures</th>

+            <th nowrap="nowrap">Time(s)</th>

+            <th nowrap="nowrap">Time Stamp</th>

+            <th>Host</th>

+        </tr>

+    </xsl:template>

+<!-- method header -->

+<xsl:template name="testcase.test.header">

+    <xsl:param name="show.class" select="''"/>

+    <tr valign="top">

+	<xsl:if test="boolean($show.class)">

+	    <th>Class</th>

+	</xsl:if>

+        <th>Name</th>

+        <th>Status</th>

+        <th width="80%">Type</th>

+        <th nowrap="nowrap">Time(s)</th>

+    </tr>

+</xsl:template>

+

+

+<!-- class information -->

+<xsl:template match="testsuite" mode="print.test">

+    <tr valign="top">

+        <xsl:attribute name="class">

+            <xsl:choose>

+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>

+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>

+                <xsl:otherwise>Pass</xsl:otherwise>

+            </xsl:choose>

+        </xsl:attribute>

+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:value-of select="@name"/></a></td>

+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:apply-templates select="@tests"/></a></td>

+        <td>

+	    <xsl:choose>

+		<xsl:when test="@errors != 0">

+		    <a title="Display only errors" href="{@id}_{@name}-errors.html"><xsl:apply-templates select="@errors"/></a>

+		</xsl:when>

+		<xsl:otherwise>

+		    <xsl:apply-templates select="@errors"/>

+		</xsl:otherwise>

+	    </xsl:choose>

+	</td>

+        <td>

+	    <xsl:choose>

+		<xsl:when test="@failures != 0">

+		    <a title="Display only failures" href="{@id}_{@name}-fails.html"><xsl:apply-templates select="@failures"/></a>

+		</xsl:when>

+		<xsl:otherwise>

+		    <xsl:apply-templates select="@failures"/>

+		</xsl:otherwise>

+	    </xsl:choose>

+	</td>

+        <td><xsl:call-template name="display-time">

+                <xsl:with-param name="value" select="@time"/>

+            </xsl:call-template>

+        </td>

+        <td><xsl:apply-templates select="@timestamp"/></td>

+        <td><xsl:apply-templates select="@hostname"/></td>

+    </tr>

+</xsl:template>

+

+<xsl:template match="testcase" mode="print.test">

+    <xsl:param name="show.class" select="''"/>

+    <tr valign="top">

+        <xsl:attribute name="class">

+            <xsl:choose>

+                <xsl:when test="error">Error</xsl:when>

+                <xsl:when test="failure">Failure</xsl:when>

+                <xsl:otherwise>TableRowColor</xsl:otherwise>

+            </xsl:choose>

+        </xsl:attribute>

+	<xsl:variable name="class.href">

+	    <xsl:value-of select="concat(translate(../@package,'.','/'), '/', ../@id, '_', ../@name, '.html')"/>

+	</xsl:variable>

+	<xsl:if test="boolean($show.class)">

+	    <td><a href="{$class.href}"><xsl:value-of select="../@name"/></a></td>

+	</xsl:if>

+        <td>

+	    <a name="{@name}"/>

+	    <xsl:choose>

+		<xsl:when test="boolean($show.class)">

+		    <a href="{concat($class.href, '#', @name)}"><xsl:value-of select="@name"/></a>

+		</xsl:when>

+		<xsl:otherwise>

+		    <xsl:value-of select="@name"/>

+		</xsl:otherwise>

+	    </xsl:choose>

+	</td>

+        <xsl:choose>

+            <xsl:when test="failure">

+                <td>Failure</td>

+                <td><xsl:apply-templates select="failure"/></td>

+            </xsl:when>

+            <xsl:when test="error">

+                <td>Error</td>

+                <td><xsl:apply-templates select="error"/></td>

+            </xsl:when>

+            <xsl:otherwise>

+                <td>Success</td>

+                <td></td>

+            </xsl:otherwise>

+        </xsl:choose>

+        <td>

+            <xsl:call-template name="display-time">

+                <xsl:with-param name="value" select="@time"/>

+            </xsl:call-template>

+        </td>

+    </tr>

+</xsl:template>

+

+

+<!-- Note : the below template error and failure are the same style

+            so just call the same style store in the toolkit template -->

+<xsl:template match="failure">

+    <xsl:call-template name="display-failures"/>

+</xsl:template>

+

+<xsl:template match="error">

+    <xsl:call-template name="display-failures"/>

+</xsl:template>

+

+<!-- Style for the error and failure in the testcase template -->

+<xsl:template name="display-failures">

+    <xsl:choose>

+        <xsl:when test="not(@message)">N/A</xsl:when>

+        <xsl:otherwise>

+            <xsl:value-of select="@message"/>

+        </xsl:otherwise>

+    </xsl:choose>

+    <!-- display the stacktrace -->

+    <br/><br/>

+    <code>

+        <xsl:call-template name="br-replace">

+            <xsl:with-param name="word" select="."/>

+        </xsl:call-template>

+    </code>

+    <!-- the latter is better but might be problematic for non-21" monitors... -->

+    <!--pre><xsl:value-of select="."/></pre-->

+</xsl:template>

+

+<xsl:template name="JS-escape">

+    <xsl:param name="string"/>

+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>

+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>

+    <xsl:value-of select="$tmp2"/>

+</xsl:template>

+

+

+<!--

+    template that will convert a carriage return into a br tag

+    @param word the text from which to convert CR to BR tag

+-->

+<xsl:template name="br-replace">

+    <xsl:param name="word"/>

+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>

+</xsl:template>

+

+<xsl:template name="display-time">

+    <xsl:param name="value"/>

+    <xsl:value-of select="format-number($value,'0.000')"/>

+</xsl:template>

+

+<xsl:template name="display-percent">

+    <xsl:param name="value"/>

+    <xsl:value-of select="format-number($value,'0.00%')"/>

+</xsl:template>

+

+

+</xsl:stylesheet>

diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-import.xsl b/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-import.xsl
new file mode 100644
index 0000000..66709df
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport-with-include/junit-import.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"

+    xmlns:lxslt="http://xml.apache.org/xslt"

+    xmlns:redirect="http://xml.apache.org/xalan/redirect"

+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"

+    extension-element-prefixes="redirect">

+    <!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+     -->

+    <!-- class header -->

+</xsl:stylesheet>

diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport.xml
new file mode 100644
index 0000000..6b921d0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport.xml
@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="junitreport-test" basedir="." default="reports">
+
+    <property name="jrdir" location="junitreport"/>
+    <property name="outputdir" location="${jrdir}/test"/>
+
+    <!-- reports1 take care of transformation of 2 test result files and
+         produce reports according to the default format (frames)
+         needed for testNoFileJunitNoFrames -->
+    <target name="reports1">
+        <mkdir dir="${outputdir}"/>
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testEmptyFile">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="ZEROBYTES-*.xml"/>
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testIncompleteFile">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="INCOMPLETE-*.xml"/>
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testWrongElement">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="WRONGELEMENT-*.xml"/>
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testNamespace">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="NAMESPACE-*.xml"/>
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="clean">
+        <delete dir="${outputdir}"/>
+    </target>
+
+    <target name="testStackTraceLineBreaks">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testSpecialSignsInSrcPath">
+        <mkdir dir="${outputdir}/html"/>
+        <mkdir dir="${outputdir}/test# $$%§&amp;-!cases"/>
+        <copy todir="${outputdir}/test# $$%§&amp;-!cases">
+            <fileset dir="junitreport" includes="TEST-*.xml"/>
+        </copy>
+        <junitreport todir="${outputdir}/html">
+            <fileset dir="${outputdir}/test# $$%§&amp;-!cases">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testSpecialSignsInHtmlPath">
+        <mkdir dir="${outputdir}/html# $$%§&amp;-!report"/>
+        <mkdir dir="${outputdir}/test"/>
+        <copy todir="${outputdir}/test">
+            <fileset dir="junitreport" includes="TEST-*.xml"/>
+        </copy>
+        <junitreport todir="${outputdir}/html# $$%§&amp;-!report">
+            <fileset dir="${outputdir}/test">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html# $$%§&amp;-!report"/>
+        </junitreport>
+    </target>
+
+    <target name="testWithStyleFromClasspath">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"/>
+        </junitreport>
+    </target>
+
+    <target name="testNoFrames">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html" format="noframes"/>
+        </junitreport>
+    </target>
+
+    <target name="testWithStyleFromDir">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"
+                styledir="junitreport"
+                format="frames"/>
+        </junitreport>
+    </target>
+
+    <!-- bug report 40022 -->
+    <target name="testWithStyleFromDirAndXslImport">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"
+                styledir="junitreport-with-include"
+                format="frames"/>
+        </junitreport>
+    </target>
+
+    <target name="testWithParams">
+        <mkdir dir="${outputdir}/html"/>
+        <junitreport todir="${outputdir}">
+            <fileset dir="${jrdir}">
+                <include name="TEST-*.xml"/>
+            </fileset>
+            <report todir="${outputdir}/html"
+                styledir="junitreport"
+                format="frames">
+                <param name="key1" expression="value1"/>
+                <param name="key2" expression="value2"/>
+            </report>
+        </junitreport>
+        <concat>
+            <fileset file="${outputdir}/html/index.html"/>
+        </concat>        
+    </target>
+
+</project>
+        
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/INCOMPLETE-sampleproject.incomplete.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/INCOMPLETE-sampleproject.incomplete.xml
new file mode 100644
index 0000000..56af014
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/INCOMPLETE-sampleproject.incomplete.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<testsuite errors="0" failures="0" name="sampleproject.incomplete" tests="5" time="0.038">
+  </properties>
+  <testcase name="testEquals" time="0.0"></testcase>
+  <testcase name="testHashCode" time="0.0"></testcase>
+  <testcase name="testToString" time="0.0010"></testcase>
+  <testcase name="testgetUniqueString" time="0.0"></testcase>
+  <testcase name="testSerialization" time="0.024"></testcase>
+  <system-out><![CDATA[testEquals
+testHashCode
+testToString
+testgetUniqueString
+testSerialization
+]]></system-out>
+  <system-err>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/NAMESPACE-sampleproject.namespace.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/NAMESPACE-sampleproject.namespace.xml
new file mode 100644
index 0000000..41e7dbf
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/NAMESPACE-sampleproject.namespace.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<ns:testsuite errors="1" failures="1" name="sampleproject.namespace" tests="11" time="0.171" xmlns:ns="funny-namespace">
+  <properties>
+    <property name="testsrc" value="test/"></property>
+    <property name="java.runtime.name" value="Java(TM) 2 Runtime Environment, Standard Edition"></property>
+    <property name="sun.boot.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386"></property>
+    <property name="java.vm.version" value="1.3.1_03-b03"></property>
+    <property name="ant.version" value="Apache Ant version 1.5 compiled on July 9 2002"></property>
+    <property name="ant.java.version" value="1.3"></property>
+    <property name="java.vm.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.vendor.url" value="http://java.sun.com/"></property>
+    <property name="path.separator" value=":"></property>
+    <property name="java.vm.name" value="Java HotSpot(TM) Client VM"></property>
+    <property name="file.encoding.pkg" value="sun.io"></property>
+    <property name="classes" value="classes"></property>
+    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"></property>
+    <property name="user.dir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="java.runtime.version" value="1.3.1_03-b03"></property>
+    <property name="java.awt.graphicsenv" value="sun.awt.X11GraphicsEnvironment"></property>
+    <property name="basedir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="os.arch" value="i386"></property>
+    <property name="java.io.tmpdir" value="/tmp"></property>
+    <property name="line.separator" value="
+"></property>
+    <property name="java.vm.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.awt.fonts" value=""></property>
+    <property name="os.name" value="Linux"></property>
+    <property name="ant.home" value="/opt/jakarta-ant-1.5/"></property>
+    <property name="ant.project.name" value="sample"></property>
+    <property name="reportdir" value="reports"></property>
+    <property name="java.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386:/usr/java/jdk1.3.1_03/jre/lib/i386/native_threads/:/usr/java/jdk1.3.1_03/jre/lib/i386/client:/usr/java/jdk1.3.1_03/jre/../lib/i386"></property>
+    <property name="src" value="code/"></property>
+    <property name="debug" value="on"></property>
+    <property name="java.specification.name" value="Java Platform API Specification"></property>
+    <property name="java.class.version" value="47.0"></property>
+    <property name="os.version" value="2.4.18-5"></property>
+    <property name="ant.file" value="/home/jkf/programming/gretant_sourceforge/sampleproject/build.xml"></property>
+    <property name="unitreport" value="cl-unit.xml"></property>
+    <property name="user.home" value="/home/jkf"></property>
+    <property name="user.timezone" value="Europe/Amsterdam"></property>
+    <property name="java.awt.printerjob" value="sun.awt.motif.PSPrinterJob"></property>
+    <property name="java.specification.version" value="1.3"></property>
+    <property name="file.encoding" value="ISO-8859-15"></property>
+    <property name="java.class.path" value="/opt/jakarta-ant-1.5//lib/xml-apis.jar:/opt/jakarta-ant-1.5//lib/xercesImpl.jar:/opt/jakarta-ant-1.5//lib/xalan.jar:/opt/jakarta-ant-1.5//lib/optional.jar:/opt/jakarta-ant-1.5//lib/junit.jar:/opt/jakarta-ant-1.5//lib/Gretel.jar:/opt/jakarta-ant-1.5//lib/gretant.jar:/opt/jakarta-ant-1.5//lib/cup-runtime.jar:/opt/jakarta-ant-1.5//lib/bcel.jar:/opt/jakarta-ant-1.5//lib/ant.jar:/usr/java/jdk1.3/lib/tools.jar"></property>
+    <property name="user.name" value="jkf"></property>
+    <property name="coverreport" value="cl-cover.xml"></property>
+    <property name="java.vm.specification.version" value="1.0"></property>
+    <property name="java.home" value="/usr/java/jdk1.3.1_03/jre"></property>
+    <property name="java.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="user.language" value="en"></property>
+    <property name="java.vm.info" value="mixed mode"></property>
+    <property name="java.version" value="1.3.1_03"></property>
+    <property name="java.ext.dirs" value="/usr/java/jdk1.3.1_03/jre/lib/ext"></property>
+    <property name="sun.boot.class.path" value="/usr/java/jdk1.3.1_03/jre/lib/rt.jar:/usr/java/jdk1.3.1_03/jre/lib/i18n.jar:/usr/java/jdk1.3.1_03/jre/lib/sunrsasign.jar:/usr/java/jdk1.3.1_03/jre/classes"></property>
+    <property name="java.vendor" value="Sun Microsystems Inc."></property>
+    <property name="file.separator" value="/"></property>
+    <property name="testclasses" value="testclasses"></property>
+    <property name="java.vendor.url.bug" value="http://java.sun.com/cgi-bin/bugreport.cgi"></property>
+    <property name="sun.io.unicode.encoding" value="UnicodeLittle"></property>
+    <property name="sun.cpu.endian" value="little"></property>
+    <property name="gretclasses" value="gretclasses"></property>
+    <property name="user.region" value="US"></property>
+    <property name="sun.cpu.isalist" value=""></property>
+  </properties>
+  <testcase name="testEquals" time="0.014"></testcase>
+  <testcase name="testHashCode" time="0.0010"></testcase>
+  <testcase name="testToString" time="0.0010"></testcase>
+  <testcase name="testGetImageURL" time="0.0"></testcase>
+  <testcase name="testGetCountry" time="0.0010"></testcase>
+  <testcase name="testGetDenomination" time="0.0"></testcase>
+  <testcase name="testGetYear" time="0.0"></testcase>
+  <testcase name="testGetSubType" time="0.0"></testcase>
+  <testcase name="testFail" time="0.0080">
+    <failure message="DOEG" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: DOEG
+	at sampleproject.coins.CoinTest.testFail(CoinTest.java:229)
+</failure>
+  </testcase>
+  <testcase name="testException" time="0.0010">
+    <error message="RTE" type="java.lang.RuntimeException">java.lang.RuntimeException: RTE
+	at sampleproject.coins.CoinTest.testException(CoinTest.java:234)
+</error>
+  </testcase>
+  <testcase name="testSuccess" time="0.0"></testcase>
+  <system-out><![CDATA[testEquals
+testHashCode
+Hashcodes: 1434557225 1434557225 1434557226 1463186376 1434556908 1516980401 1434557225
+testToString
+<Coin=NL,1 Euro,1999,Var a/>
+<Coin=NL,1 Euro,1999,null/>
+testGetImageURL
+testGetCountry
+testGetDenomination
+testGetYear
+testGetSubType
+testFail
+testException
+testSuccess
+]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</ns:testsuite>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.coins.CoinTest.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.coins.CoinTest.xml
new file mode 100644
index 0000000..f4ce498
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.coins.CoinTest.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<testsuite errors="1" failures="1" name="sampleproject.coins.CoinTest" tests="11" time="0.171">
+  <properties>
+    <property name="testsrc" value="test/"></property>
+    <property name="java.runtime.name" value="Java(TM) 2 Runtime Environment, Standard Edition"></property>
+    <property name="sun.boot.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386"></property>
+    <property name="java.vm.version" value="1.3.1_03-b03"></property>
+    <property name="ant.version" value="Apache Ant version 1.5 compiled on July 9 2002"></property>
+    <property name="ant.java.version" value="1.3"></property>
+    <property name="java.vm.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.vendor.url" value="http://java.sun.com/"></property>
+    <property name="path.separator" value=":"></property>
+    <property name="java.vm.name" value="Java HotSpot(TM) Client VM"></property>
+    <property name="file.encoding.pkg" value="sun.io"></property>
+    <property name="classes" value="classes"></property>
+    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"></property>
+    <property name="user.dir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="java.runtime.version" value="1.3.1_03-b03"></property>
+    <property name="java.awt.graphicsenv" value="sun.awt.X11GraphicsEnvironment"></property>
+    <property name="basedir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="os.arch" value="i386"></property>
+    <property name="java.io.tmpdir" value="/tmp"></property>
+    <property name="line.separator" value="
+"></property>
+    <property name="java.vm.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.awt.fonts" value=""></property>
+    <property name="os.name" value="Linux"></property>
+    <property name="ant.home" value="/opt/jakarta-ant-1.5/"></property>
+    <property name="ant.project.name" value="sample"></property>
+    <property name="reportdir" value="reports"></property>
+    <property name="java.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386:/usr/java/jdk1.3.1_03/jre/lib/i386/native_threads/:/usr/java/jdk1.3.1_03/jre/lib/i386/client:/usr/java/jdk1.3.1_03/jre/../lib/i386"></property>
+    <property name="src" value="code/"></property>
+    <property name="debug" value="on"></property>
+    <property name="java.specification.name" value="Java Platform API Specification"></property>
+    <property name="java.class.version" value="47.0"></property>
+    <property name="os.version" value="2.4.18-5"></property>
+    <property name="ant.file" value="/home/jkf/programming/gretant_sourceforge/sampleproject/build.xml"></property>
+    <property name="unitreport" value="cl-unit.xml"></property>
+    <property name="user.home" value="/home/jkf"></property>
+    <property name="user.timezone" value="Europe/Amsterdam"></property>
+    <property name="java.awt.printerjob" value="sun.awt.motif.PSPrinterJob"></property>
+    <property name="java.specification.version" value="1.3"></property>
+    <property name="file.encoding" value="ISO-8859-15"></property>
+    <property name="java.class.path" value="/opt/jakarta-ant-1.5//lib/xml-apis.jar:/opt/jakarta-ant-1.5//lib/xercesImpl.jar:/opt/jakarta-ant-1.5//lib/xalan.jar:/opt/jakarta-ant-1.5//lib/optional.jar:/opt/jakarta-ant-1.5//lib/junit.jar:/opt/jakarta-ant-1.5//lib/Gretel.jar:/opt/jakarta-ant-1.5//lib/gretant.jar:/opt/jakarta-ant-1.5//lib/cup-runtime.jar:/opt/jakarta-ant-1.5//lib/bcel.jar:/opt/jakarta-ant-1.5//lib/ant.jar:/usr/java/jdk1.3/lib/tools.jar"></property>
+    <property name="user.name" value="jkf"></property>
+    <property name="coverreport" value="cl-cover.xml"></property>
+    <property name="java.vm.specification.version" value="1.0"></property>
+    <property name="java.home" value="/usr/java/jdk1.3.1_03/jre"></property>
+    <property name="java.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="user.language" value="en"></property>
+    <property name="java.vm.info" value="mixed mode"></property>
+    <property name="java.version" value="1.3.1_03"></property>
+    <property name="java.ext.dirs" value="/usr/java/jdk1.3.1_03/jre/lib/ext"></property>
+    <property name="sun.boot.class.path" value="/usr/java/jdk1.3.1_03/jre/lib/rt.jar:/usr/java/jdk1.3.1_03/jre/lib/i18n.jar:/usr/java/jdk1.3.1_03/jre/lib/sunrsasign.jar:/usr/java/jdk1.3.1_03/jre/classes"></property>
+    <property name="java.vendor" value="Sun Microsystems Inc."></property>
+    <property name="file.separator" value="/"></property>
+    <property name="testclasses" value="testclasses"></property>
+    <property name="java.vendor.url.bug" value="http://java.sun.com/cgi-bin/bugreport.cgi"></property>
+    <property name="sun.io.unicode.encoding" value="UnicodeLittle"></property>
+    <property name="sun.cpu.endian" value="little"></property>
+    <property name="gretclasses" value="gretclasses"></property>
+    <property name="user.region" value="US"></property>
+    <property name="sun.cpu.isalist" value=""></property>
+  </properties>
+  <testcase name="testEquals" time="0.014"></testcase>
+  <testcase name="testHashCode" time="0.0010"></testcase>
+  <testcase name="testToString" time="0.0010"></testcase>
+  <testcase name="testGetImageURL" time="0.0"></testcase>
+  <testcase name="testGetCountry" time="0.0010"></testcase>
+  <testcase name="testGetDenomination" time="0.0"></testcase>
+  <testcase name="testGetYear" time="0.0"></testcase>
+  <testcase name="testGetSubType" time="0.0"></testcase>
+  <testcase name="testFail" time="0.0080">
+    <failure message="DOEG" type="junit.framework.AssertionFailedError">junit.framework.AssertionFailedError: DOEG
+	at sampleproject.coins.CoinTest.testFail(CoinTest.java:229)
+</failure>
+  </testcase>
+  <testcase name="testException" time="0.0010">
+    <error message="RTE" type="java.lang.RuntimeException">java.lang.RuntimeException: RTE
+	at sampleproject.coins.CoinTest.testException(CoinTest.java:234)
+</error>
+  </testcase>
+  <testcase name="testSuccess" time="0.0"></testcase>
+  <system-out><![CDATA[testEquals
+testHashCode
+Hashcodes: 1434557225 1434557225 1434557226 1463186376 1434556908 1516980401 1434557225
+testToString
+<Coin=NL,1 Euro,1999,Var a/>
+<Coin=NL,1 Euro,1999,null/>
+testGetImageURL
+testGetCountry
+testGetDenomination
+testGetYear
+testGetSubType
+testFail
+testException
+testSuccess
+]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.util.UniqueStringTest.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.util.UniqueStringTest.xml
new file mode 100644
index 0000000..f4016c2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/TEST-sampleproject.util.UniqueStringTest.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<testsuite errors="0" failures="0" name="sampleproject.util.UniqueStringTest" tests="5" time="0.038">
+  <properties>
+    <property name="testsrc" value="test/"></property>
+    <property name="java.runtime.name" value="Java(TM) 2 Runtime Environment, Standard Edition"></property>
+    <property name="sun.boot.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386"></property>
+    <property name="java.vm.version" value="1.3.1_03-b03"></property>
+    <property name="ant.version" value="Apache Ant version 1.5 compiled on July 9 2002"></property>
+    <property name="ant.java.version" value="1.3"></property>
+    <property name="java.vm.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.vendor.url" value="http://java.sun.com/"></property>
+    <property name="path.separator" value=":"></property>
+    <property name="java.vm.name" value="Java HotSpot(TM) Client VM"></property>
+    <property name="file.encoding.pkg" value="sun.io"></property>
+    <property name="classes" value="classes"></property>
+    <property name="java.vm.specification.name" value="Java Virtual Machine Specification"></property>
+    <property name="user.dir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="java.runtime.version" value="1.3.1_03-b03"></property>
+    <property name="java.awt.graphicsenv" value="sun.awt.X11GraphicsEnvironment"></property>
+    <property name="basedir" value="/home/jkf/programming/gretant_sourceforge/sampleproject"></property>
+    <property name="os.arch" value="i386"></property>
+    <property name="java.io.tmpdir" value="/tmp"></property>
+    <property name="line.separator" value="
+"></property>
+    <property name="java.vm.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="java.awt.fonts" value=""></property>
+    <property name="os.name" value="Linux"></property>
+    <property name="ant.home" value="/opt/jakarta-ant-1.5/"></property>
+    <property name="ant.project.name" value="sample"></property>
+    <property name="reportdir" value="reports"></property>
+    <property name="java.library.path" value="/usr/java/jdk1.3.1_03/jre/lib/i386:/usr/java/jdk1.3.1_03/jre/lib/i386/native_threads/:/usr/java/jdk1.3.1_03/jre/lib/i386/client:/usr/java/jdk1.3.1_03/jre/../lib/i386"></property>
+    <property name="src" value="code/"></property>
+    <property name="debug" value="on"></property>
+    <property name="java.specification.name" value="Java Platform API Specification"></property>
+    <property name="java.class.version" value="47.0"></property>
+    <property name="os.version" value="2.4.18-5"></property>
+    <property name="ant.file" value="/home/jkf/programming/gretant_sourceforge/sampleproject/build.xml"></property>
+    <property name="unitreport" value="cl-unit.xml"></property>
+    <property name="user.home" value="/home/jkf"></property>
+    <property name="user.timezone" value="Europe/Amsterdam"></property>
+    <property name="java.awt.printerjob" value="sun.awt.motif.PSPrinterJob"></property>
+    <property name="java.specification.version" value="1.3"></property>
+    <property name="file.encoding" value="ISO-8859-15"></property>
+    <property name="java.class.path" value="/opt/jakarta-ant-1.5//lib/xml-apis.jar:/opt/jakarta-ant-1.5//lib/xercesImpl.jar:/opt/jakarta-ant-1.5//lib/xalan.jar:/opt/jakarta-ant-1.5//lib/optional.jar:/opt/jakarta-ant-1.5//lib/junit.jar:/opt/jakarta-ant-1.5//lib/Gretel.jar:/opt/jakarta-ant-1.5//lib/gretant.jar:/opt/jakarta-ant-1.5//lib/cup-runtime.jar:/opt/jakarta-ant-1.5//lib/bcel.jar:/opt/jakarta-ant-1.5//lib/ant.jar:/usr/java/jdk1.3/lib/tools.jar"></property>
+    <property name="user.name" value="jkf"></property>
+    <property name="coverreport" value="cl-cover.xml"></property>
+    <property name="java.vm.specification.version" value="1.0"></property>
+    <property name="java.home" value="/usr/java/jdk1.3.1_03/jre"></property>
+    <property name="java.specification.vendor" value="Sun Microsystems Inc."></property>
+    <property name="user.language" value="en"></property>
+    <property name="java.vm.info" value="mixed mode"></property>
+    <property name="java.version" value="1.3.1_03"></property>
+    <property name="java.ext.dirs" value="/usr/java/jdk1.3.1_03/jre/lib/ext"></property>
+    <property name="sun.boot.class.path" value="/usr/java/jdk1.3.1_03/jre/lib/rt.jar:/usr/java/jdk1.3.1_03/jre/lib/i18n.jar:/usr/java/jdk1.3.1_03/jre/lib/sunrsasign.jar:/usr/java/jdk1.3.1_03/jre/classes"></property>
+    <property name="java.vendor" value="Sun Microsystems Inc."></property>
+    <property name="file.separator" value="/"></property>
+    <property name="testclasses" value="testclasses"></property>
+    <property name="java.vendor.url.bug" value="http://java.sun.com/cgi-bin/bugreport.cgi"></property>
+    <property name="sun.io.unicode.encoding" value="UnicodeLittle"></property>
+    <property name="sun.cpu.endian" value="little"></property>
+    <property name="gretclasses" value="gretclasses"></property>
+    <property name="user.region" value="US"></property>
+    <property name="sun.cpu.isalist" value=""></property>
+  </properties>
+  <testcase name="testEquals" time="0.0"></testcase>
+  <testcase name="testHashCode" time="0.0"></testcase>
+  <testcase name="testToString" time="0.0010"></testcase>
+  <testcase name="testgetUniqueString" time="0.0"></testcase>
+  <testcase name="testSerialization" time="0.024"></testcase>
+  <system-out><![CDATA[testEquals
+testHashCode
+testToString
+testgetUniqueString
+testSerialization
+]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/WRONGELEMENT-sampleproject.wrongelement.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/WRONGELEMENT-sampleproject.wrongelement.xml
new file mode 100644
index 0000000..9cb5a14
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/WRONGELEMENT-sampleproject.wrongelement.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<wildebeast/>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/ZEROBYTES-sampleproject.package.xml b/trunk/src/etc/testcases/taskdefs/optional/junitreport/ZEROBYTES-sampleproject.package.xml
new file mode 100644
index 0000000..9f351c7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/ZEROBYTES-sampleproject.package.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
diff --git a/trunk/src/etc/testcases/taskdefs/optional/junitreport/junit-frames.xsl b/trunk/src/etc/testcases/taskdefs/optional/junitreport/junit-frames.xsl
new file mode 100644
index 0000000..ca313af
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/junitreport/junit-frames.xsl
@@ -0,0 +1,879 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="http://xml.apache.org/xalan/redirect"
+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator=","/>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ -->
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all packages and classes.
+
+-->
+<xsl:param name="output.dir" select="'.'"/>
+<xsl:param name="key1" select="'defaultValue1'"/>
+<xsl:param name="key2" select="'defaultValue2'"/>
+
+<xsl:template match="testsuites">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.packages"/>
+    </redirect:write>
+
+    <!-- create the all-packages.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.packages"/>
+    </redirect:write>
+
+    <!-- create the all-classes.html at the root -->
+    <redirect:write file="{$output.dir}/allclasses-frame.html">
+        <xsl:apply-templates select="." mode="all.classes"/>
+    </redirect:write>
+
+    <!-- create the all-tests.html at the root -->
+    <redirect:write file="{$output.dir}/all-tests.html">
+        <xsl:apply-templates select="." mode="all.tests"/>
+    </redirect:write>
+
+    <!-- create the alltests-fails.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-fails.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'fails'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- create the alltests-errors.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-errors.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'errors'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- process all packages -->
+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+        <xsl:call-template name="package">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="package">
+    <xsl:param name="name"/>
+    <xsl:variable name="package.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a classes-list.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-frame.html">
+        <xsl:call-template name="classes.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a package-summary.html in the package directory -->
+    <redirect:write file="{$output.dir}/{$package.dir}/package-summary.html">
+        <xsl:call-template name="package.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each class, creates a @name.html -->
+    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten -->
+  <xsl:for-each select="/testsuites/testsuite[@package = $name]">
+    <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}.html">
+      <xsl:apply-templates select="." mode="class.details"/>
+    </redirect:write>
+    <xsl:if test="string-length(./system-out)!=0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-out.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-out"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="string-length(./system-err)!=0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-err.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-err"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="@failures != 0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-fails.html">
+        <xsl:apply-templates select="." mode="class.details">
+          <xsl:with-param name="type" select="'fails'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="@errors != 0">
+      <redirect:write file="{$output.dir}/{$package.dir}/{@id}_{@name}-errors.html">
+        <xsl:apply-templates select="." mode="class.details">
+          <xsl:with-param name="type" select="'errors'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<html>
+    <head>
+        <title>
+            Unit Test Results. key1=<xsl:value-of select="$key1"/>,key2=<xsl:value-of select="$key2"/>
+        </title>
+    </head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="packageListFrame"/>
+            <frame src="allclasses-frame.html" name="classListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="classFrame"/>
+        <noframes>
+            <h2>Frame Alert</h2>
+            <p>
+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+            </p>
+        </noframes>
+    </frameset>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+}
+table tr td, table tr th {
+    font-size: 68%;
+}
+table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+}
+table.details tr td{
+    background:#eeeee0;
+}
+
+p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+}
+h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+}
+h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+}
+h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+}
+h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+.Error {
+    font-weight:bold; color:red;
+}
+.Failure {
+    font-weight:bold; color:purple;
+}
+.Properties {
+  text-align:right;
+}
+</xsl:template>
+
+<!-- Create list of all/failed/errored tests -->
+<xsl:template match="testsuites" mode="all.tests">
+    <xsl:param name="type" select="'all'"/>
+    <html>
+	<xsl:variable name="title">
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <xsl:text>All Failures</xsl:text>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <xsl:text>All Errors</xsl:text>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:text>All Tests</xsl:text>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</xsl:variable>
+	<head>
+	    <title>Unit Test Results: <xsl:value-of select="$title"/></title>
+	    <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+	</head>
+	<body>
+	    <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h2><xsl:value-of select="$title"/></h2>
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header">
+		    <xsl:with-param name="show.class" select="'yes'"/>
+		</xsl:call-template>
+		<!--
+                test can even not be started at all (failure to load the class)
+		so report the error directly
+		-->
+              <xsl:if test="./error">
+                <tr class="Error">
+                  <td colspan="4">
+                    <xsl:apply-templates select="./error"/>
+                  </td>
+                </tr>
+              </xsl:if>
+              <xsl:choose>
+                <xsl:when test="$type = 'fails'">
+                  <xsl:apply-templates select=".//testcase[failure]" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:when test="$type = 'errors'">
+                  <xsl:apply-templates select=".//testcase[error]" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:apply-templates select=".//testcase" mode="print.test">
+                    <xsl:with-param name="show.class" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:otherwise>
+              </xsl:choose>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every testsuite class.
+    It prints a summary of the testsuite and detailed information about
+    testcase methods.
+     ====================================================================== -->
+<xsl:template match="testsuite" mode="class.details">
+    <xsl:param name="type" select="'all'"/>
+    <xsl:variable name="package.name" select="@package"/>
+    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>
+    <html>
+        <head>
+          <title>Unit Test Results: <xsl:value-of select="$class.name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$package.name"/>
+            </xsl:call-template>
+       <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:apply-templates select="properties"/>
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style type=\"text/css\">");
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Class <xsl:value-of select="$class.name"/></h3>
+
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="testsuite.test.header"/>
+                <xsl:apply-templates select="." mode="print.test"/>
+            </table>
+
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <h2>Failures</h2>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <h2>Errors</h2>
+		</xsl:when>
+		<xsl:otherwise>
+		    <h2>Tests</h2>
+		</xsl:otherwise>
+	    </xsl:choose>
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header"/>
+		<!--
+                test can even not be started at all (failure to load the class)
+		so report the error directly
+		-->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+		<xsl:choose>
+		    <xsl:when test="$type = 'fails'">
+			<xsl:apply-templates select="./testcase[failure]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:when test="$type = 'errors'">
+			<xsl:apply-templates select="./testcase[error]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:otherwise>
+			<xsl:apply-templates select="./testcase" mode="print.test"/>
+		    </xsl:otherwise>
+		</xsl:choose>
+            </table>
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <xsl:if test="string-length(./system-out)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        System.out &#187;
+                    </a>
+                </div>
+            </xsl:if>
+            <xsl:if test="string-length(./system-err)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-err.txt</xsl:attribute>
+                        System.err &#187;
+                    </a>
+                </div>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every package.
+    It prints the name of all classes that belongs to this package.
+    @param name the package name to print classes.
+     ====================================================================== -->
+<!-- list of classes in a package -->
+<xsl:template name="classes.list">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <title>Unit Test Classes: <xsl:value-of select="$name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <h2><a href="package-summary.html" target="classFrame">
+                            <xsl:value-of select="$name"/>
+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>
+                        </a></h2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@id}_{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    Creates an all-classes.html file that contains a link to all package-summary.html
+    on each class.
+-->
+<xsl:template match="testsuites" mode="all.classes">
+    <html>
+        <head>
+            <title>All Unit Test Classes</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Classes</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite" mode="all.classes">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.classes">
+    <xsl:variable name="package.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="classFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($package.name='')">
+                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@id"/>_<xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all package-summary.html files on
+    each package existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed package :(
+-->
+<xsl:template match="testsuites" mode="all.packages">
+    <html>
+        <head>
+            <title>All Unit Test Packages</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2>
+            <h2>Packages</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages">
+                    <xsl:sort select="@package"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.packages">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame">
+                <xsl:value-of select="@package"/>
+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.packages">
+    <html>
+        <head>
+            <title>Unit Test Results: Summary</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute>
+        <xsl:call-template name="pageHeader"/>
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:otherwise>Pass</xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><a title="Display all tests" href="all-tests.html"><xsl:value-of select="$testCount"/></a></td>
+            <td><a title="Display all failures" href="alltests-fails.html"><xsl:value-of select="$failureCount"/></a></td>
+            <td><a title="Display all errors" href="alltests-errors.html"><xsl:value-of select="$errorCount"/></a></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.
+        </td>
+        </tr>
+        </table>
+
+        <h2>Packages</h2>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <!-- get the node set containing all testsuites that have the same package -->
+                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <tr valign="top">
+                    <!-- display a failure if there is any failure/error in the package -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="sum($insamepackage/@errors) &gt; 0">Error</xsl:when>
+                            <xsl:when test="sum($insamepackage/@failures) &gt; 0">Failure</xsl:when>
+                            <xsl:otherwise>Pass</xsl:otherwise>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="./{translate(@package,'.','/')}/package-summary.html">
+                        <xsl:value-of select="@package"/>
+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+                    </a></td>
+                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td>
+                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$insamepackage/@timestamp"/></td>
+                    <td><xsl:value-of select="$insamepackage/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="package.summary">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="package.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Package <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="class.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/>
+            <xsl:if test="count($insamepackage) &gt; 0">
+                <h2>Classes</h2>
+                <p>
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+                    <xsl:apply-templates select="$insamepackage" mode="print.test">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+                </p>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the package name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="package.name"/>
+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>
+</xsl:template>
+
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1>Unit Test Results</h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href="http://www.junit.org/">JUnit</a> and <a href="http://ant.apache.org/">Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <xsl:param name="show.class" select="''"/>
+    <tr valign="top">
+	<xsl:if test="boolean($show.class)">
+	    <th>Class</th>
+	</xsl:if>
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="@errors[.&gt; 0]">Error</xsl:when>
+                <xsl:when test="@failures[.&gt; 0]">Failure</xsl:when>
+                <xsl:otherwise>Pass</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:apply-templates select="@tests"/></a></td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="@errors != 0">
+		    <a title="Display only errors" href="{@id}_{@name}-errors.html"><xsl:apply-templates select="@errors"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="@errors"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="@failures != 0">
+		    <a title="Display only failures" href="{@id}_{@name}-fails.html"><xsl:apply-templates select="@failures"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="@failures"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td><xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <xsl:param name="show.class" select="''"/>
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+	<xsl:variable name="class.href">
+	    <xsl:value-of select="concat(translate(../@package,'.','/'), '/', ../@id, '_', ../@name, '.html')"/>
+	</xsl:variable>
+	<xsl:if test="boolean($show.class)">
+	    <td><a href="{$class.href}"><xsl:value-of select="../@name"/></a></td>
+	</xsl:if>
+        <td>
+	    <a name="{@name}"/>
+	    <xsl:choose>
+		<xsl:when test="boolean($show.class)">
+		    <a href="{concat($class.href, '#', @name)}"><xsl:value-of select="@name"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:value-of select="@name"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="@time"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!-- Note : the below template error and failure are the same style
+            so just call the same style store in the toolkit template -->
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<!-- Style for the error and failure in the testcase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/native2ascii/build.xml b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/build.xml
new file mode 100644
index 0000000..ec0165a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/build.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="no">
+
+  <property name="out" location="output"/>
+  <property name="in" location="input"/>
+
+  <target name="no">
+    <fail>For tests only</fail>
+  </target>
+
+  <target name="setUp">
+    <mkdir dir="${out}"/>
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${out}"/>
+  </target>
+
+  <target name="testIso8859-1" depends="setUp">
+    <native2ascii encoding="ISO8859-1" dest="${out}"
+                  src="${in}" includes="iso8859-1.*"/>
+  </target>
+</project>
+    
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/native2ascii/expected/iso8859-1.test b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/expected/iso8859-1.test
new file mode 100644
index 0000000..d60acc8
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/expected/iso8859-1.test
@@ -0,0 +1 @@
+\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df
diff --git a/trunk/src/etc/testcases/taskdefs/optional/native2ascii/input/iso8859-1.test b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/input/iso8859-1.test
new file mode 100644
index 0000000..d5b3934
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/native2ascii/input/iso8859-1.test
@@ -0,0 +1 @@
+äöüÄÖÜß
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/net/ftp.xml b/trunk/src/etc/testcases/taskdefs/optional/net/ftp.xml
new file mode 100644
index 0000000..aaf4b8e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/net/ftp.xml
@@ -0,0 +1,331 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="ftp-test" basedir=".">
+    <property file="../../../../../../ftp.properties"/>
+    <property environment="env"/>
+    <property file="${env.HOME}/ant-ftp.properties"/>
+    <property name="ftp.user" value="${user.name}"/>
+    <property name="ftp.host" value="localhost"/>
+    <property name="ftp.port" value="21" />
+    <property name="ftp.password" value="sunshine" />
+    <property name="ftp.filesep" value="/"/>
+    <property name="tmp.dir" location="tmp"/>
+    <property name="tmp.get.dir" location="tmp.get"/>
+    <property name="tmp.local" location="${tmp.get.dir}"/>
+    <property name="tmp.remote" location="${tmp.dir}"/>
+    <property name="tstamp.format" value="yyyy-MM-dd HH:mm"/>
+    <property name="server.timestamp.granularity.millis" value="60000"/>
+    <property name="ftp.server.timezone" value="GMT"/>
+    <property name="ftp.listing.file" value="/dev/null"/>
+    <property name="ftp.retries" value="2"/>
+
+    <fileset dir="${tmp.get.dir}" id="fileset-destination-with-selector">
+        <include name="alpha/**"/>
+        <filename name="**/alpha.xml" />
+    </fileset>
+    <fileset dir="${tmp.dir}" id="fileset-source-without-selector">
+        <include name="alpha/**"/>
+    </fileset>
+    <fileset dir="${tmp.get.dir}" id="fileset-destination-without-selector">
+        <include name="alpha/**"/>
+    </fileset>
+    <fileset dir="${tmp.get.dir}" id="fileset-destination-followsymlinks" followsymlinks="true">
+        <include name="alpha/**"/>
+    </fileset>
+    <fileset dir="${tmp.get.dir}" id="fileset-destination-nofollowsymlinks" followsymlinks="false">
+        <include name="alpha/**"/>
+    </fileset>
+
+    <filelist dir="${tmp.local}" id="timed-files" files="A.timed,B.timed,C.timed,D.timed"/>
+
+    <patternset id="timed-test-files">
+        <include name="A.timed"/>
+        <include name="B.timed"/>
+        <include name="C.timed"/>
+        <include name="D.timed"/>
+    </patternset>
+
+    <target name="setup">
+        <mkdir dir="${tmp.get.dir}"/>
+        <mkdir dir="${tmp.dir}/alpha/beta/gamma"/>
+        <touch file="${tmp.dir}/alpha/beta/gamma/gamma.xml"/>
+        <touch file="${tmp.dir}/alpha/beta/beta.xml"/>
+    </target>
+
+    <target name="ftp-get-with-selector">
+        <ftp action="get"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.dir}">
+            <fileset refid="fileset-destination-with-selector"/>
+        </ftp>
+    </target>
+    <target name="children-of-excluded-dir-setup" depends="setup">
+        <mkdir dir="${tmp.dir}/delta"/>
+        <touch file="${tmp.dir}/delta/delta.xml"/>
+    </target>
+    <target name="cleanup">
+        <delete dir="${tmp.dir}" quiet="true"/>
+        <delete dir="${tmp.get.dir}" quiet="true"/>
+    </target>
+    <target name="symlink-setup" depends="setup">
+        <mkdir dir="${tmp.dir}/epsilon/gamma"/>
+        <delete dir="${tmp.dir}/alpha/beta"/>
+        <symlink link="${tmp.dir}/alpha/beta" resource="${tmp.dir}/epsilon"/>
+        <touch file="${tmp.dir}/alpha/beta/gamma/gamma.xml"/>
+    </target>
+    <target name="ftp-get-directory-symbolic-link" depends="symlink-setup">
+        <ftp action="get"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.dir}"
+            >
+            <fileset refid="fileset-destination-followsymlinks"/>
+        </ftp>
+    </target>
+    <target name="ftp-get-directory-no-symbolic-link" depends="symlink-setup">
+        <ftp action="get"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.dir}"
+            >
+            <fileset refid="fileset-destination-nofollowsymlinks"/>
+        </ftp>
+    </target>
+    <target name="symlink-file-setup" depends="setup">
+        <delete file="${tmp.dir}/alpha/beta/gamma/gamma.xml"/>
+        <symlink link="${tmp.dir}/alpha/beta/gamma/gamma.xml"
+            resource="${tmp.dir}/alpha/beta/beta.xml"/>
+    </target>
+    <target name="ftp-delete">
+        <!-- this target can produce an error if the rmdir does not work -->
+        <!-- there can be problems with the rmdir action if the directories are not removed in a proper order -->
+        <!-- which means beginning by the leaves of the tree, going back to the trunk -->
+        <ftp action="del"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            remotedir="${tmp.dir}">
+            <fileset dir="${tmp.get.dir}">
+                <include name="**"/>
+            </fileset>
+        </ftp>
+        <ftp action="rmdir"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            remotedir="${tmp.dir}">
+            <fileset dir="${tmp.get.dir}">
+                <include name="**"/>
+            </fileset>
+        </ftp>
+    </target>   
+
+    <target name="timed.test.setup">
+        <touch>
+            <filelist refid="timed-files"/>
+        </touch>    
+        <ftp action="put"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            >
+            <fileset dir="${tmp.local}">
+                <patternset refid="timed-test-files"/>
+            </fileset>
+        </ftp>
+    </target>
+
+    <target name="timed.test.put.older">
+        <tstamp>
+            <format property="one.minute.older" pattern="${tstamp.format}" offset="-60" unit="second"/>
+        </tstamp>
+
+        <touch datetime="${one.minute.older}" pattern="${tstamp.format}" verbose="true">
+            <fileset dir="${tmp.remote}">
+                <include name="A.timed"/>
+            </fileset>
+        </touch>
+        <ftp action="put"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            newer="true"
+            serverTimeZoneConfig="${ftp.server.timezone}"
+            >
+            <fileset dir="${tmp.local}">
+                <patternset refid="timed-test-files"/>
+            </fileset>
+        </ftp>
+    </target>
+    <target name="timed.test.get.older">
+        <tstamp>
+            <format property="five.minutes.older" pattern="${tstamp.format}" offset="-5" unit="minute"/>
+        </tstamp>
+
+        <touch datetime="${five.minutes.older}" pattern="${tstamp.format}" verbose="true">
+            <fileset dir="${tmp.local}">
+                <include name="A.timed"/>
+                <include name="C.timed"/>
+                <include name="D.timed"/>
+            </fileset>
+        </touch>
+        <ftp action="get"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            preservelastmodified="true"
+            newer="true"
+            serverTimeZoneConfig="${ftp.server.timezone}"
+            >
+            <fileset dir="${tmp.local}">
+                <patternset refid="timed-test-files"/>
+            </fileset>
+        </ftp>
+    </target>
+    
+    <target name="configuration.1">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            serverTimeZoneConfig="${ftp.server.timezone}"
+            listing="${ftp.listing.file}"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>
+    <target name="configuration.2">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            serverTimeZoneConfig="${ftp.server.timezone}"
+            listing="${ftp.listing.file}"
+            systemTypeKey="WINDOWS"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>
+    <target name="configuration.3">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            defaultDateFormatConfig="yyyy/MM/dd HH:mm"
+            listing="${ftp.listing.file}"
+            systemTypeKey="UNIX"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>
+    <target name="configuration.lang.good">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            serverLanguageCodeConfig="de"
+            listing="${ftp.listing.file}"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>    
+    <target name="configuration.lang.bad">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            serverLanguageCodeConfig="QQ"
+            listing="${ftp.listing.file}"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>    
+    <target name="configuration.none">
+        <ftp action="list"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            listing="${ftp.listing.file}"
+            >
+             <fileset dir="${tmp.local}"/>
+         </ftp>
+    </target>
+    <target name="ftp-get-with-selector-retryable">
+        <ftp action="get"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.dir}"
+            retriesAllowed="${ftp.retries}"
+            >
+            <fileset refid="fileset-destination-with-selector"/>
+        </ftp>
+    </target>
+    <target name="test-initial-command">
+        <ftp action="put"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            initialSiteCommand="umask 222"
+            >
+            <fileset dir="${tmp.local}">
+                <patternset refid="timed-test-files"/>
+            </fileset>
+        </ftp>
+    </target>
+
+    <target name="test-site-action">
+        <ftp action="site"
+            server="${ftp.host}"
+            userid="${ftp.user}"
+            password="${ftp.password}"
+            separator="${ftp.filesep}"
+            remotedir="${tmp.remote}"
+            siteCommand="umask 222"
+            >
+        </ftp>
+    </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/perforce/changerenumbered.xml b/trunk/src/etc/testcases/taskdefs/optional/perforce/changerenumbered.xml
new file mode 100644
index 0000000..497f053
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/perforce/changerenumbered.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- author Antoine Levy-Lambert  -->
+<!-- this file demonstrates that p4.change will be modified by p4submit -->
+<!-- if the change number is modified by the Perforce daemon during the submission -->
+<project name="build1" default="runtest">
+  <target name="runtest">
+    <p4change/>
+    <property name="change1" value="${p4.change}" />
+    <echo>
+doing a first change ${change1}
+</echo>
+    <p4change/>
+    <property name="change2" value="${p4.change}" />
+    <echo>
+doing a second change ${change2}
+</echo>
+    <p4edit view="//depot/foobar" change="${change1}" />
+    <p4edit view="//depot/hello" change="${change2}" />
+    <echo>
+before submitting of hello change ${change2} p4.change is now ${p4.change}
+</echo>
+    <p4submit change="${change2}"/>
+    <echo>
+after submitting of hello p4.change is now ${p4.change}
+</echo>
+    <echo>
+before submitting of foobar change ${change1}
+</echo>
+    <p4submit change="${change1}"/>
+    <echo>
+after submitting of foobar p4.change is now ${p4.change}
+</echo>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/perforce/needsresolve.xml b/trunk/src/etc/testcases/taskdefs/optional/perforce/needsresolve.xml
new file mode 100644
index 0000000..00c90e5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/perforce/needsresolve.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- author Antoine Levy-Lambert -->
+<!-- this test shows that p4 submit can now indicate that a file needs to be resolved -->
+<!-- before running the test, edit this xml and change the 5 properties at the top to values which make sense on your system-->
+<!-- the test uses two Perforce client specs which must exist beforehand -->
+<!-- also using both client specs you should be able to edit the file ${depot_file_spec} -->
+<project name="testresolve" default= "test">
+  <property name="first_client" value="levyant_dev_ant"/>
+  <property name="first_client_root" value="C:\dev\depot"/>
+  <property name="second_client" value="levyant_cygwin_test"/>
+  <property name="second_client_root" value="C:\dev\test"/>
+  <property name="depot_file_spec" value="//depot/foobar"/>
+  <target name="test">
+    <p4change client="${first_client}"/>
+    <property name="change1" value="${p4.change}" />
+    <p4change client="${second_client}"/>
+    <property name="change2" value="${p4.change}" />
+    <sequential>
+      <antcall target="edit">
+	<param name="p4.client" value="${first_client}"/>
+	<param name="client_root" value="${first_client_root}"/>
+	<param name="change" value="${change1}"/>
+      </antcall>
+      <antcall target="edit">
+	<param name="p4.client" value="${second_client}"/>
+	<param name="client_root" value="${second_client_root}"/>
+	<param name="change" value="${change2}"/>
+      </antcall>
+      <antcall target="submit">
+	<param name="p4.client" value="${first_client}"/>
+	<param name="change" value="${change1}"/>
+      </antcall>
+      <antcall target="submit">
+	<param name="p4.client" value="${second_client}"/>
+	<param name="change" value="${change2}"/>
+      </antcall>
+    </sequential>
+  </target>
+  <target name="edit">
+    <echo>
+doing a  change ${change} on  client ${p4.client}
+</echo>
+    <p4edit change="${change}" view="${depot_file_spec}"/>
+    <mkdir dir="${client_root}/depot"/>
+    <echo file="${client_root}/depot/foobar">
+hello ${p4.client} ${change}
+</echo>
+  </target>
+  <target name="submit">
+    <p4submit change="${change}" needsresolveproperty="needsresolve" changeproperty="mychange"/>
+    <echo>
+p4.needsresolve ${p4.needsresolve} after submit
+        needsresolveproperty ${needsresolve} after submit
+        changeproperty ${mychange} after submit
+</echo>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/propertyfile.xml b/trunk/src/etc/testcases/taskdefs/optional/propertyfile.xml
new file mode 100644
index 0000000..a513681
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/propertyfile.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="propertyfile-test" default="main" basedir=".">
+
+   <property file="propertyfile.build.properties"/>
+
+   <target name="main">
+      <fail>
+         This file is for testing purposes only...
+         @see PropertyFileTest.java for more info.
+      </fail>
+   </target>
+
+   <target name="update-existing-properties">
+      <propertyfile
+          file="${test.propertyfile}"
+          comment="unit test for the property file task..." >
+        <entry  key="firstname" value="${firstname}" />
+        <entry  key="lastname"  value="${lastname}" />
+        <entry  key="email"     value="${email}" />
+        <entry  key="phone"     default="${phone}" />
+        <entry  key="age"       default="${age}" type="int"/>
+        <entry  key="date"      default="${date}" type="date"/>
+      </propertyfile>
+
+   </target>
+
+   <target name="exercise">
+     <propertyfile file="${test.propertyfile}">
+        <entry key="existing.prop"
+               type="int"
+               default="23"/>
+        <entry key="ethans.birth"
+               value="2002/01/21 12:18"
+               type="date"/>
+        <entry key="first.birthday"
+               value="1"
+               default="2002/01/21"
+               pattern="yyyy/MM/dd"
+               unit="year"
+               type="date"
+               operation="+"/>
+        <entry key="int.with.default"
+               value="1"
+               default="2"
+               operation="+"
+               type="int"/>
+        <entry key="int.without.value"
+               default="5"
+               operation="+"
+               type="int"/>
+        <entry key="int.without.default"
+               value="1"
+               operation="+"
+               type="int"/>
+        <entry key="string.with.default"
+               value="&gt;"
+               default="--"
+               operation="+"/>
+        <entry key="string.without.default"
+               value="."
+               operation="+"/>
+        <entry key="olderThanAWeek"
+               type="date"
+               default="0201"
+               operation="-"
+               value="8"
+               pattern="MMdd"/>
+     </propertyfile>
+     <property file="${test.propertyfile}"/>
+   </target>
+    <target name="createfile">
+       <echo file="${overwrite.test.propertyfile}">
+ foo=3
+       </echo>
+    </target>
+    <target name="bugDemo1" depends="createfile,bugDemoInit"/>
+    <target name="bugDemo2" depends="bugDemoInit">
+        <property file="${overwrite.test.propertyfile}"/>
+    </target>
+    <target name="bugDemoInit">
+       <propertyfile file="${overwrite.test.propertyfile}">
+          <entry key="foo" default="0" value="1" operation="+" type="int"/>
+       </propertyfile>
+    </target>
+
+</project>
+
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/pvcs.xml b/trunk/src/etc/testcases/taskdefs/optional/pvcs.xml
new file mode 100644
index 0000000..99bfcff
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/pvcs.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="pvcs-test" basedir="." default="test1">
+
+  <taskdef name="pvcs" classname="org.apache.tools.ant.taskdefs.Pvcs"/>
+
+  <target name="test1">
+    <pvcs/>
+  </target>
+
+  <target name="test2">
+    <pvcs pvcsbin="/home/tc/projects/pvcsant/src/etc/testcases/taskdefs" repository="/mnt/pvcs"/>
+  </target>
+
+  <target name="test3">
+    <pvcs pvcsbin="\home\cvs\pvcsant\src\etc\testcases\taskdefs" repository="/mnt/pvcs" pvcsproject="/qviknet"/>
+  </target>
+
+  <target name="test4">
+    <pvcs pvcsbin="\home\cvs\pvcsant\src\etc\testcases\taskdefs" repository="/mnt/pvcs" pvcsproject="/qviknet" workspace="/@/Public/buildws"/>
+  </target>
+
+  <target name="test5" description="Get the latest from PVCS">
+    <pvcs pvcsbin="/home/cvs/pvcsant/src/etc/testcases/taskdefs" 
+			 repository="//ct4serv2/pvcs/monitor"/>
+  </target>
+
+  <target name="test6" description="No pcli to be found">
+    <pvcs pvcsbin="/never/heard/of/a/directory/structure/like/this" 
+			 repository="//ct4serv2/pvcs/monitor"/>
+  </target>
+
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.properties b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.properties
new file mode 100644
index 0000000..d7f057e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+OldAbc=Def
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.xml b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.xml
new file mode 100644
index 0000000..878dd7c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="def" basedir=".">
+  <property name="tmpregexp" value="tmpregexp"/>
+  <target name="def">
+    <fail>This build file should only be run from within the testcase</fail>
+  </target>
+
+  <target name="setup">
+    <copy file="replaceregexp.properties" tofile="test.properties" />
+  </target>
+
+  <target name="setup-nl">
+    <copy file="replaceregexp2.properties" tofile="test.properties" />
+  </target>
+
+  <target name="testReplace" depends="setup">
+    <replaceregexp file="test.properties" byline="true">
+      <regexp pattern="Old(.*)=(.*)" />
+      <substitution expression="NewProp=\1\2" />
+    </replaceregexp>
+  </target>
+  <!-- use in conjunction with testDirectoryDateDoesNotChange to make sure something will happen -->
+  <target name="touchDirectory">
+    <mkdir dir="${tmpregexp}"/>
+    <copy file="replaceregexp.properties" tofile="${tmpregexp}/test.properties" />
+    <sleep seconds="2"/>
+  </target>
+  <target name="testDirectoryDateDoesNotChange">
+    <replaceregexp file="${tmpregexp}/test.properties" byline="true">
+      <regexp pattern="foo" />
+        <substitution expression="bar"/>
+      </replaceregexp>
+  </target>
+
+  <target name="testDontAddNewline1" depends="setup-nl">
+    <replaceregexp file="test.properties" byline="false">
+      <regexp pattern="Old(.*)=(.*)" />
+      <substitution expression="NewProp=\1\2" />
+    </replaceregexp>
+  </target>
+
+  <target name="testDontAddNewline2" depends="setup-nl">
+    <replaceregexp file="test.properties" byline="true">
+      <regexp pattern="Old(.*)=(.*)" />
+      <substitution expression="NewProp=\1\2" />
+    </replaceregexp>
+  </target>
+
+  <target name="cleanup">
+    <delete file="test.properties" />
+    <delete dir="${tmpregexp}" quiet="true"/>
+  </target>
+
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.properties b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.properties
new file mode 100644
index 0000000..ada7727
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+OldAbc=Def
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.result.properties b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.result.properties
new file mode 100644
index 0000000..6393cd7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/replaceregexp2.result.properties
@@ -0,0 +1,15 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+NewProp=AbcDef
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/schemavalidate.xml b/trunk/src/etc/testcases/taskdefs/optional/schemavalidate.xml
new file mode 100644
index 0000000..f43201e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/schemavalidate.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="validate" default="default" basedir=".">
+
+
+  <property name="doc.xsd" location="xml/doc.xsd"/>
+  <property name="doc-in-ns.xsd" location="xml/doc-in-ns.xsd"/>
+  <property name="namespace" value="http://apache.org/ant/doc/" />
+  
+  <property name="endpiece-ns-no-location.xml" 
+    location="xml/endpiece-ns-no-location.xml"/>
+
+  <target name="testNoNamespace">
+    <schemavalidate
+      noNamespaceFile="${doc.xsd}"
+      file="xml/endpiece-noSchema.xml">
+    </schemavalidate>
+  </target>
+
+  <target name="testNSMapping">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
+      <schema namespace="http://apache.org/ant/2" 
+        url="http://ant.apache.org/" />
+    </schemavalidate>
+  </target>
+
+  <target name="testNoEmptySchemaNamespace">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="" file="${doc-in-ns.xsd}" />
+    </schemavalidate>
+  </target>
+
+  <target name="testNoEmptySchemaLocation">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" />
+    </schemavalidate>
+  </target>
+  
+  <target name="testNoFile">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" file="${namespace}" />
+    </schemavalidate>
+  </target>  
+  
+  <target name="testNoDoubleSchemaLocation">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" url="${namespace}"/>
+    </schemavalidate>
+  </target>
+
+  <target name="testNoDuplicateSchema">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
+      <schema namespace="${namespace}" 
+        url="http://ant.apache.org/" />
+    </schemavalidate>
+  </target>  
+
+  <target name="testEqualsSchemasOK">
+    <schemavalidate
+      file="${endpiece-ns-no-location.xml}">
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
+    </schemavalidate>
+  </target>  
+  
+  <target name="testFileset">
+    <schemavalidate noNamespaceFile="${doc.xsd}"
+      >
+      <schema namespace="${namespace}" file="${doc-in-ns.xsd}" />
+      <fileset dir="xml" 
+        includes="endpiece.xml, endpiece-ns-no-location.xml, endpiece-no-schema.xml" />
+    </schemavalidate>
+  </target>  
+  
+  
+  <target name="default" depends="testNoNamespace,testNSMapping" />
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/script.xml b/trunk/src/etc/testcases/taskdefs/optional/script.xml
new file mode 100644
index 0000000..841f70d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/script.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="testproject" default="def" basedir=".">
+
+  <target name="def">
+    <fail>This build-file is intended to be run from the test cases</fail>
+  </target>
+
+  <target name="setup1">
+
+    <script language="javascript"> <![CDATA[
+
+      for (i=1; i<=10; i++) {
+        echo = testproject.createTask("echo");
+        setup1.addTask(echo);
+        echo.setMessage(i*i);
+      }
+
+    ]]> </script>
+
+  </target>
+
+  <target name="example1" depends="setup1"/>
+
+  <target name="useBeanshell">
+    <script language="beanshell"><![CDATA[
+       self.log("I'm here", org.apache.tools.ant.Project.MSG_INFO);
+    ]]></script>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/script/scriptdef.xml b/trunk/src/etc/testcases/taskdefs/optional/script/scriptdef.xml
new file mode 100644
index 0000000..0d051ea
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/script/scriptdef.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="testproject" default="def" basedir=".">
+
+  <target name="def">
+    <fail>This build-file is intended to be run from the test cases</fail>
+  </target>
+
+  <target name="simple">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <element name="fileset" type="fileset"/>
+      <![CDATA[
+        
+        project.log("Attribute attr1 = " + attributes.get("attr1"));
+        project.log("Fileset basedir = "
+          + elements.get("fileset").get(0).getDir(project));
+        
+      ]]>
+    </scriptdef>
+    
+    <fileset id="testfileset" dir="."/>
+    <scripttest attr1="test">
+      <fileset refid="testfileset"/>
+    </scripttest>
+  </target>
+
+  <target name="nolang">
+    <scriptdef name="nolang">
+      <![CDATA[
+        java.lang.System.out.println("Hello");
+      ]]>
+    </scriptdef>
+  </target>
+
+  <target name="noname">
+    <scriptdef language="javascript">
+      <![CDATA[
+        java.lang.System.out.println("Hello");
+      ]]>
+    </scriptdef>
+  </target>
+
+  <target name="nestedbyclassname">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <element name="fileset" classname="org.apache.tools.ant.types.FileSet"/>
+      <![CDATA[
+        
+        project.log("Attribute attr1 = " + attributes.get("attr1"));
+        project.log("Fileset basedir = "
+          + elements.get("fileset").get(0).getDir(project));
+        
+      ]]>
+    </scriptdef>
+    
+    <fileset id="testfileset" dir="."/>
+    <scripttest attr1="test">
+      <fileset refid="testfileset"/>
+    </scripttest>
+  </target>
+  
+  <target name="noelement">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <element name="fileset" type="fileset"/>
+      <![CDATA[
+        java.lang.System.out.println("Attribute attr1 = " + attributes.get("attr1"));
+      ]]>
+    </scriptdef>
+    
+    <scripttest attr1="test">
+    </scripttest>
+  </target>
+
+  <target name="exception">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <element name="fileset" classname="org.apache.tools.ant.types.FileSet"/>
+      <![CDATA[
+        
+        java.lang.System.out.println("Attribute attr1 = " + attributes.get("attr1"));
+        java.lang.System.out.println("Fileset basedir = "
+          + elements.get("fileset").get(0).getDir(project));
+        
+      ]]>
+    </scriptdef>
+    
+    <scripttest attr1="test">
+    </scripttest>
+  </target>
+  
+  <target name="doubledef">
+    <scriptdef name="task1" language="javascript">
+      <![CDATA[
+        project.log("Task1");
+      ]]>
+    </scriptdef>
+    <scriptdef name="task2" language="javascript">
+      <![CDATA[
+        project.log("Task2");
+      ]]>
+    </scriptdef>
+    <task1/>
+    <task2/>
+  </target>
+  
+  <target name="doubleAttributeDef">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <attribute name="attr1"/>
+    </scriptdef>
+  </target>
+  
+  <target name="property">
+    <scriptdef name="scripttest" language="javascript">
+      <attribute name="attr1"/>
+      <![CDATA[
+        
+        project.log("Attribute value = " + attributes.get("attr1"));
+      ]]>
+    </scriptdef>
+
+    <property name="testproperty" value="test"/>    
+    <scripttest attr1="${testproperty}">
+    </scripttest>
+  </target>
+
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/script_reference.xml b/trunk/src/etc/testcases/taskdefs/optional/script_reference.xml
new file mode 100644
index 0000000..82ccb1f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/script_reference.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test-reference" default="script">
+  <target name="script">
+    <script language="javascript">
+    </script>
+  </target>
+  <target name="def">
+    <taskdef name="my.echo" classname="org.apache.tools.ant.taskdefs.Echo"/>
+    <my.echo id="my.echo.ref" message="hello world"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/sos/sos.xml b/trunk/src/etc/testcases/taskdefs/optional/sos/sos.xml
new file mode 100644
index 0000000..982b47c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/sos/sos.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="sos-test" basedir="." default="sosget.1">
+
+    <!--
+    ===========================================================================
+     Test SOSGet missing attributes
+    ===========================================================================
+    -->
+    <target name="sosget.1">
+        <sosget/>
+    </target>
+
+    <target name="sosget.2">
+        <sosget sosserverpath="192.168.0.1:8888"/>
+    </target>
+
+    <target name="sosget.3">
+        <sosget sosserverpath="192.168.0.1:8888"
+            username="ant"/>
+    </target>
+
+    <target name="sosget.4">
+        <sosget sosserverpath="192.168.0.1:8888"
+            username="ant"
+            vssserverpath="\\server\vss\srcsafe.ini"/>
+    </target>
+
+    <!--
+    ===========================================================================
+     Test SOSCheckin missing attributes
+    ===========================================================================
+    -->
+    <target name="soscheckin.1">
+        <soscheckin/>
+    </target>
+
+    <target name="soscheckin.2">
+        <soscheckin sosserverpath="192.168.0.1:8888"/>
+    </target>
+
+    <target name="soscheckin.3">
+        <soscheckin sosserverpath="192.168.0.1:8888"
+            username="ant"/>
+    </target>
+
+    <target name="soscheckin.4">
+        <soscheckin sosserverpath="192.168.0.1:8888"
+            username="ant"
+            vssserverpath="\\server\vss\srcsafe.ini"/>
+    </target>
+
+    <!--
+    ===========================================================================
+     Test SOSCheckout missing attributes
+    ===========================================================================
+    -->
+    <target name="soscheckout.1">
+        <soscheckout/>
+    </target>
+
+    <target name="soscheckout.2">
+        <soscheckout sosserverpath="192.168.0.1:8888"/>
+    </target>
+
+    <target name="soscheckout.3">
+        <soscheckout sosserverpath="192.168.0.1:8888"
+            username="ant"/>
+    </target>
+
+    <target name="soscheckout.4">
+        <soscheckout sosserverpath="192.168.0.1:8888"
+            username="ant"
+            vssserverpath="\\server\vss\srcsafe.ini"/>
+    </target>
+
+    <!--
+    ===========================================================================
+     Test SOSLabel missing attributes
+    ===========================================================================
+    -->
+    <target name="soslabel.1">
+        <soslabel/>
+    </target>
+
+    <target name="soslabel.2">
+        <soslabel sosserverpath="192.168.0.1:8888"/>
+    </target>
+
+    <target name="soslabel.3">
+        <soslabel sosserverpath="192.168.0.1:8888"
+            username="ant"/>
+    </target>
+
+    <target name="soslabel.4">
+        <soslabel sosserverpath="192.168.0.1:8888"
+            username="ant"
+            vssserverpath="\\server\vss\srcsafe.ini"/>
+    </target>
+
+    <target name="soslabel.5">
+        <soslabel sosserverpath="192.168.0.1:8888"
+            username="ant"
+            vssserverpath="\\server\vss\srcsafe.ini"
+            projectpath="$/SourceRoot/Project"/>
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml b/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml
new file mode 100644
index 0000000..4c4881d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/unix/symlink.xml
@@ -0,0 +1,343 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!--
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+-->
+
+<project name="symlink-test" basedir="." default="all">
+
+  <!-- 
+       Since the symlink task and some of these targets rely on
+       calls to exec, it may be possible for the JVM to outrun the 
+       execution of the command line  system calls, so this value is
+       the number of seconds we give the operating system to
+       catch up before executing a task that depends on the 
+       completion of previous tasks. This delay is also added to
+       the end of each target so junit doesn't go testing things
+       before they have finnished (hopefully). Tweak if needed.
+  -->
+
+  <property name="delay" value="3"/>
+ 
+  <property name="tdir" value="${basedir}/test-working"/>
+
+  <target name="setup">
+      <delete dir="${tdir}"/>
+      <mkdir dir="${tdir}"/>
+  </target>
+
+  <target name="all"
+	      depends="setup, test-single, test-delete, test-record, test-recreate, teardown"/>
+	
+  <!-- test for action = single -->
+  <!-- 
+    Creates:
+         File: ${tdir}/symlink.test
+         Link: ${tdir}/singletest
+  -->
+  <target name="test-single">
+    <touch file="${tdir}/symlink.test"/>
+    <symlink resource="${tdir}/symlink.test" 
+             link="${tdir}/singletest" 
+             failonerror="yes"/>
+    <sleep seconds="${delay}"/> <!-- make sure OS has time to catch up -->
+    <available file="${tdir}/symlink.test" 
+               property="test.single.file.created"/>
+    <available file="${tdir}/singletest" 
+               property="test.single.link.created"/>
+  </target>
+
+
+
+  <!-- test for action = delete  (no calls to command line so no sleep) -->
+
+  <!-- 
+    Creates:
+         (none)
+    Deletes:
+         Link: ${tdir}/singletest
+  -->
+
+  <target name="test-delete">
+    <touch file="${tdir}/symlink.test"/>
+    <symlink resource="${tdir}/symlink.test" 
+             link="${tdir}/singletest" 
+             failonerror="yes"/>
+    <sleep seconds="${delay}"/> <!-- make sure OS has time to catch up -->
+
+    <symlink action="delete" link="${tdir}/singletest" failonerror="yes"/>
+    <symlink action="delete" link="${tdir}/symlink.test" failonerror="no"/>
+    <sleep seconds="${delay}"/> <!-- make sure OS has time to catch up -->
+
+    <available file="${tdir}/symlink.test" 
+               property="test.delete.file.still.there"/>
+    <available file="${tdir}/singletest" 
+               property="test.delete.link.still.there"
+               value="ERROR: link deletion failed"/>
+    
+  </target>
+
+
+
+  <!-- test for action = record -->
+
+  <!-- 
+    Creates:
+         Dir:  ${tdir}/symtest1
+         Dir:  ${tdir}/symtest1/symtest2
+         Dir:  ${tdir}/symtest1/symtest3
+         File: ${tdir}/symtest1/file1
+         File: ${tdir}/symtest1/symtest2/file2
+         File: ${tdir}/symtest1/symtest3/fileA
+         File: ${tdir}/symtest1/symtest3/fileB
+         File: ${tdir}/symtest1/symtest3/fileC
+         Link: ${tdir}/symtest1/link1==>${tdir}/symtest1/file1
+         Link: ${tdir}/symtest1/link2==>${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/symtest2/link3==>
+                                           ${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/dirlink==>${tdir}/symtest1/symtest3
+         Link: ${tdir}/symtest1/dirlink2==>${tdir}/symtest1/symtest3
+         Link: ${tdir}/symtest1/dirlink3==>${tdir}/symtest1/symtest3
+         File: ${tdir}/symtest1/recorded.links
+         File: ${tdir}/symtest1/symtest2/recorded.links
+    Deletes:
+         (none)
+  -->
+
+  <target name="test-record">
+
+    <mkdir dir="${tdir}/symtest1"/>
+    <mkdir dir="${tdir}/symtest1/symtest2"/>
+    <mkdir dir="${tdir}/symtest1/symtest3"/>
+    <touch file="${tdir}/symtest1/file1"/>
+    <touch file="${tdir}/symtest1/symtest2/file2"/>
+
+    <touch file="${tdir}/symtest1/symtest3/fileA"/>
+    <touch file="${tdir}/symtest1/symtest3/fileB"/>
+    <touch file="${tdir}/symtest1/symtest3/fileC"/>
+
+    <symlink resource="${tdir}/symtest1/file1" 
+             link="${tdir}/symtest1/link1" 
+             failonerror="no" />
+    <symlink resource="${tdir}/symtest1/symtest2/file2" 
+             link="${tdir}/symtest1/link2" 
+             failonerror="no" />
+    <symlink resource="${tdir}/symtest1/symtest2/file2" 
+             link="${tdir}/symtest1/symtest2/link3" 
+             failonerror="no" />
+    <symlink resource="${tdir}/symtest1/symtest3"
+             link="${tdir}/symtest1/dirlink"
+             failonerror="no" />
+    <symlink resource="${tdir}/symtest1/symtest3" 
+             link="${tdir}/symtest1/dirlink2"
+             failonerror="no"/>
+    <symlink resource="${tdir}/symtest1/symtest3" 
+             link="${tdir}/symtest1/dirlink3"
+             failonerror="no"/>
+
+    <sleep seconds="${delay}"/> <!-- make sure OS has time to catch up -->
+
+    <symlink action="record" linkfilename="recorded.links">
+       <fileset dir="${tdir}/symtest1" includes="**/**"/>
+    </symlink>
+
+    <sleep seconds="${delay}"/> <!-- make sure OS has time to catch up -->
+
+    <!-- Test to see if the directories were created -->
+
+    <available file="${tdir}/symtest1"
+               type="dir"
+               property="test.record.dir1.created"/>
+
+    <available file="${tdir}/symtest1/symtest2"
+               type="dir"
+               property="test.record.dir2.created"/>
+
+    <available file="${tdir}/symtest1/symtest3"
+               type="dir"
+               property="test.record.dir3.created"/>
+
+    <!-- Test to see if the Files were created -->
+
+    <available file="${tdir}/symtest1/file1"
+               property="test.record.file1.created"/>
+
+    <available file="${tdir}/symtest1/symtest2/file2"
+               property="test.record.file2.created"/>
+
+    <available file="${tdir}/symtest1/symtest3/fileA"
+               property="test.record.fileA.created"/>
+
+    <available file="${tdir}/symtest1/symtest3/fileB"
+               property="test.record.fileB.created"/>
+
+    <available file="${tdir}/symtest1/symtest3/fileC"
+               property="test.record.fileC.created"/>
+
+    <!-- Test to see if the links were created -->
+
+    <available file="${tdir}/symtest1/link1"
+               property="test.record.link1.created"/>
+
+    <available file="${tdir}/symtest1/link2"
+               property="test.record.link2.created"/>
+
+    <available file="${tdir}/symtest1/symtest2/link3"
+               property="test.record.link3.created"/>
+
+    <available file="${tdir}/symtest1/dirlink"
+               property="test.record.dirlink.created"/>
+
+    <!-- this is redundant for this test, but used in the recreate test -->
+
+    <available file="${tdir}/symtest1/dirlink2" 
+               property="test.record.dirlink2.created"/>
+
+    <!-- Test to see if the linkfiles were created -->
+
+    <available file="${tdir}/symtest1/recorded.links"
+               property="test.record.dir1.recorded"/>
+
+    <available file="${tdir}/symtest1/symtest2/recorded.links"
+               property="test.record.dir2.recorded"/>
+
+    <!-- THIS should not be set -->
+
+    <available file="${tdir}/symtest1/symtest3/recorded.links"
+               property="test.record.dir3.recorded"
+               value="ERROR: symtest3/recorded.links should not exist"/>
+
+
+  </target>
+
+  <!-- test for action = recreate -->
+
+  <!-- 
+    Deletes:
+         Link: ${tdir}/symtest1/link1==>${tdir}/symtest1/file1
+         Link: ${tdir}/symtest1/link2==>${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/symtest2/link3==>
+                                           ${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/dirlink==>${tdir}/symtest1/symtest3
+         Link: ${tdir}/symtest1/dirlink3==>${tdir}/symtest1/symtest3
+
+    Creates
+         Link: ${tdir}/symtest1/dirlink3==>${tdir}/symtest1/symtest2
+
+    Recreates:
+         Link: ${tdir}/symtest1/link1==>${tdir}/symtest1/file1
+         Link: ${tdir}/symtest1/link2==>${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/symtest2/link3==>
+                                           ${tdir}/symtest1/symtest2/file2
+         Link: ${tdir}/symtest1/dirlink==>${tdir}/symtest1/symtest3
+
+    Should Change:
+         Link: ${tdir}/symtest1/dirlink3==>${tdir}/symtest1/symtest2
+               to
+               ${tdir}/symtest1/dirlink3==>${tdir}/symtest1/symtest3
+
+    Should Not Create (bug 25181):
+         Link: ${tdir}/symtest1/symtest3/dirlink2==>${tdir}/symtest1/symtest3
+  -->
+
+  <target name="test-recreate" depends="test-record">
+
+    <symlink action="delete" link="${tdir}/symtest1/link1"/>
+    <symlink action="delete" link="${tdir}/symtest1/link2"/>
+    <symlink action="delete" link="${tdir}/symtest1/symtest2/link3"/>
+    <symlink action="delete" link="${tdir}/symtest1/dirlink"/>
+    <!-- dirlink2 intentionally not deleted to test bug 25181 -->
+    <symlink action="delete" link="${tdir}/symtest1/dirlink3"/>
+
+    <sleep seconds="${delay}"/>  <!-- make sure OS has time to catch up -->
+
+    <symlink resource="${tdir}/symtest1/symtest2" 
+             link="${tdir}/symtest1/dirlink3"
+             failonerror="no"/>
+
+    <sleep seconds="${delay}"/>  <!-- make sure OS has time to catch up -->
+
+    <available file="${tdir}/symtest1/link1"
+               property="test.recreate.link1.not.removed"
+               value="ERROR: rm -f symtest1/link1 failed"/>
+
+    <available file="${tdir}/symtest1/link2"
+               property="test.recreate.link2.not.removed"
+               value="ERROR: rm -f symtest1/link2 failed"/>
+
+    <available file="${tdir}/symtest1/symtest2/link3"
+               property="test.recreate.link3.not.removed"
+               value="ERROR: rm -f symtest1/symtest2/link3 failed"/>
+
+     <available file="${tdir}/symtest1/zdirlink"
+               property="test.recreate.zdirlink.not.removed"
+               value="ERROR: rm -f symtest1/zdirlink failed"/>
+
+    <sleep seconds="${delay}"/>  <!-- make sure OS has time to do the execs -->
+
+    <symlink action="recreate">
+      <fileset dir="${tdir}/symtest1" includes="**/recorded.links"/>
+    </symlink>
+
+    <sleep seconds="${delay}"/>  <!-- make sure OS has time to catch up -->
+
+    <available file="${tdir}/symtest1/link1"
+               property="test.recreate.link1.recreated"/>
+
+    <available file="${tdir}/symtest1/link2"
+               property="test.recreate.link2.recreated"/>
+
+    <available file="${tdir}/symtest1/symtest2/link3"
+               property="test.recreate.link3.recreated"/>
+
+    <available file="${tdir}/symtest1/dirlink"
+               property="test.recreate.dirlink.recreated"/>
+
+    <!-- this should not get set -->
+    <available file="${tdir}/symtest1/symtest3/symtest3" 
+               property="test.recreate.dirlink2.recreated.twice"
+               value="ERROR: dirlink2 was created a second time (bug 25181)"/>
+
+    <touch file="${tdir}/symtest1/dirlink3/WhereAmI"/>
+
+    <sleep seconds="${delay}"/>  <!-- make sure OS has time to do the execs -->
+
+    <available file="${tdir}/symtest1/symtest3/WhereAmI" 
+               property="test.recreate.dirlink3.was.altered"/>
+  </target>
+
+
+<!-- CALL THIS to clean things up afterwards -->
+
+  <target name="teardown">
+    <delete dir="${tdir}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/vss/vss.xml b/trunk/src/etc/testcases/taskdefs/optional/vss/vss.xml
new file mode 100644
index 0000000..7c6c0d3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/vss/vss.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="vss-test" basedir="." default="vssget.1">
+
+    <!--
+    ===========================================================================
+     Test required attributes
+    ===========================================================================
+    -->
+    <target name="vssget.1">
+        <vssget/>
+    </target>
+
+    <target name="vsslabel.1">
+        <vsslabel/>
+    </target>
+
+   <target name="vsslabel.2">
+        <vsslabel vsspath="$/SourceRoot/Project"/>
+    </target>
+
+    <target name="vsshistory.1">
+        <vsshistory/>
+    </target>
+
+    <target name="vsscheckin.1">
+        <vsscheckin/>
+    </target>
+
+    <target name="vsscheckout.1">
+        <vsscheckout/>
+    </target>
+
+    <target name="vsscheckout.2">
+        <vsscheckout
+            vsspath="$/SourceRoot/Project"
+            filetimestamp="blah"/>
+    </target>
+
+    <target name="vssadd.1">
+        <vssadd/>
+    </target>
+
+    <target name="vsscp.1">
+        <vsscp/>
+    </target>
+
+     <target name="vsscreate.1">
+        <vsscreate/>
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/wsdl/StockQuoteService.wsdl b/trunk/src/etc/testcases/taskdefs/optional/wsdl/StockQuoteService.wsdl
new file mode 100644
index 0000000..dd1292a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/wsdl/StockQuoteService.wsdl
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<wsdl:definitions targetNamespace="http://localhost:8080/axis/StockQuoteService.jws" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:impl="http://localhost:8080/axis/StockQuoteService.jws-impl" xmlns:intf="http://localhost:8080/axis/StockQuoteService.jws" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+  <wsdl:message name="getQuoteResponse">
+    <wsdl:part name="return" type="xsd:float"/>
+  </wsdl:message>
+  <wsdl:message name="getQuoteRequest">
+    <wsdl:part name="symbol" type="xsd:string"/>
+  </wsdl:message>
+  <wsdl:message name="Exception">
+  </wsdl:message>
+  <wsdl:portType name="StockQuoteService">
+    <wsdl:operation name="getQuote" parameterOrder="symbol">
+      <wsdl:input message="intf:getQuoteRequest"/>
+      <wsdl:output message="intf:getQuoteResponse"/>
+      <wsdl:fault message="intf:Exception" name="Exception"/>
+    </wsdl:operation>
+  </wsdl:portType>
+  <wsdl:binding name="StockQuoteServiceSoapBinding" type="intf:StockQuoteService">
+    <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+    <wsdl:operation name="getQuote">
+      <wsdlsoap:operation soapAction=""/>
+      <wsdl:input>
+        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/StockQuoteService.jws" use="encoded"/>
+      </wsdl:input>
+      <wsdl:output>
+        <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/axis/StockQuoteService.jws" use="encoded"/>
+      </wsdl:output>
+    </wsdl:operation>
+  </wsdl:binding>
+  <wsdl:service name="StockQuoteServiceService">
+    <wsdl:port binding="intf:StockQuoteServiceSoapBinding" name="StockQuoteService">
+      <wsdlsoap:address location="http://localhost:8080/axis/StockQuoteService.jws"/>
+    </wsdl:port>
+  </wsdl:service>
+</wsdl:definitions>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xalan-redirect-in.xsl b/trunk/src/etc/testcases/taskdefs/optional/xalan-redirect-in.xsl
new file mode 100644
index 0000000..f3b5d41
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xalan-redirect-in.xsl
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<xsl:stylesheet	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+	xmlns:lxslt="http://xml.apache.org/xslt"
+	xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
+	extension-element-prefixes="redirect">
+<!--
+This is a test to ensure that systemid is set correctly
+for a xsl...the behavior might be dependent on Xalan1
+and Xalan2...this will be a problem to erase the files :(
+Can take as a systemid the base for the xsl document or
+the base or the JVM working dir just like: new File("xalan-redirect-out.tmp")
+-->	
+<xsl:param name="xalan-version" select="'x'"/>
+
+<xsl:template match="/">
+<redirect:write file="./xalan{$xalan-version}-redirect-out.tmp">
+	<test>This should be written to the file</test>
+</redirect:write>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/about.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/about.xml
new file mode 100644
index 0000000..f6a9dab
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/about.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE doc PUBLIC
+  "-//stevo//DTD doc 1.0//EN"
+  "http://chemical/brothers"
+  >
+<doc>
+  <section title="About">
+  in the absence of technology, there is only marketing
+  </section>
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/apache.xsl b/trunk/src/etc/testcases/taskdefs/optional/xml/apache.xsl
new file mode 100644
index 0000000..120addf
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/apache.xsl
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                version="1.0">
+
+  <xsl:output method="xml"/>
+
+  <xsl:template match="/">
+    <authors>
+        <xsl:apply-templates/>
+    </authors>
+  </xsl:template>
+  <xsl:template match="author">
+    <author>
+      <xsl:attribute name="name">
+        <xsl:value-of select="@name"/>
+      </xsl:attribute>
+    </author>
+  </xsl:template> 
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/books.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/books.xml
new file mode 100644
index 0000000..f020828
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/books.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="iso-8859-1"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<books>

+  <book name="hamlet">

+      <author name="shakespeare"/>

+  </book>

+   <book name="the lord of rings">

+       <author name="tolkien"/>

+   </book>

+   <book name="le malade imaginaire">

+       <author name="moliere"/>

+   </book>

+</books>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/catalog b/trunk/src/etc/testcases/taskdefs/optional/xml/catalog
new file mode 100644
index 0000000..1c9bddf
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/catalog
@@ -0,0 +1,2 @@
+PUBLIC "-//stevo//DTD doc 1.0//EN" "doc.dtd"
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/doc-in-ns.xsd b/trunk/src/etc/testcases/taskdefs/optional/xml/doc-in-ns.xsd
new file mode 100644
index 0000000..b34147c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/doc-in-ns.xsd
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+	targetNamespace="http://apache.org/ant/doc/"
+	xmlns:tns="http://apache.org/ant/doc/"
+	elementFormDefault="qualified">
+	<xs:element name="doc">
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element ref="tns:section"/>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:element name="section">
+		<xs:complexType>
+			<xs:simpleContent>
+				<xs:extension base="xs:string">
+					<xs:attribute name="title" type="xs:string"/>
+				</xs:extension>
+			</xs:simpleContent>
+		</xs:complexType>
+	</xs:element>
+</xs:schema>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/doc.dtd b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.dtd
new file mode 100644
index 0000000..51629d5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.dtd
@@ -0,0 +1,24 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!ELEMENT doc (section) >
+<!ELEMENT section (#PCDATA)>
+<!ATTLIST section title CDATA #IMPLIED>
+
+
+
+
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsd b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsd
new file mode 100644
index 0000000..eeedbca
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsd
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xs:schema 
+  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+  elementFormDefault="qualified">
+  <xs:element name="doc">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element ref="section"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="section">
+    <xs:complexType>
+      <xs:simpleContent>
+        <xs:extension base="xs:string">
+          <xs:attribute name="title" type="xs:string"/>
+        </xs:extension>
+      </xs:simpleContent>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsl b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsl
new file mode 100644
index 0000000..3d9c2a4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/doc.xsl
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet 
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:template="struts template" 
+    version="1.0">
+<xsl:output method="text"/>
+<xsl:template match="/">
+<xsl:value-of select="/doc/section"/>
+</xsl:template> 
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/docwithentity.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/docwithentity.xml
new file mode 100644
index 0000000..6435c32
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/docwithentity.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE books [
+   <!ENTITY globaldefinitions SYSTEM "entity.xml">
+]>
+<books>
+   &globaldefinitions;
+   <book name="the lord of rings">
+       <author name="tolkien"/>
+   </book>
+   <book name="le malade imaginaire">
+       <author name="moliere"/>
+   </book>
+</books>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema-invalid.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema-invalid.xml
new file mode 100644
index 0000000..ec58085
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema-invalid.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- 
+    Invalid test XML file without any schema refeferences 
+-->
+<doc>
+    <section title="endpiece">
+        With a little luck, the network will pick me up. 
+        This is Ripley - last survivor of The Nostromo - signing off.
+    </section>
+    
+    <invalidelement/>
+    
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema.xml
new file mode 100644
index 0000000..7ae559d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-noSchema.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<!-- 
+    Test XML file without any schema refeferences 
+-->
+<doc>
+    <section title="endpiece">
+        With a little luck, the network will pick me up. 
+        This is Ripley - last survivor of The Nostromo - signing off.
+    </section>
+    
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-ns-no-location.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-ns-no-location.xml
new file mode 100644
index 0000000..3fe93c7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece-ns-no-location.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="doc-in-ns.xsd" xmlns="http://apache.org/ant/doc/">
+	<section title="endpiece">
+ With a little luck, the network will pick me up. 
+ This is Ripley - last survivor of The Nostromo - signing off.
+  </section>
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece.xml
new file mode 100644
index 0000000..3fe93c7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="doc-in-ns.xsd" xmlns="http://apache.org/ant/doc/">
+	<section title="endpiece">
+ With a little luck, the network will pick me up. 
+ This is Ripley - last survivor of The Nostromo - signing off.
+  </section>
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece2.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece2.xml
new file mode 100644
index 0000000..eec49f6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/endpiece2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<doc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+    xsi:noNamespaceSchemaLocation="doc.xsd"
+    xmlns="http://Massive/Attack+Mezzanine">
+  <section title="endpiece">
+ With a little luck, the network will pick me up. 
+ This is Ripley - last survivor of The Nostromo - signing off.
+ <illegal-element/>
+  </section>
+</doc>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/entity.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/entity.xml
new file mode 100644
index 0000000..b906514
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/entity.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+   <book name="hamlet">
+       <author name="shakespeare"/>
+   </book>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/iso-2022-jp.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/iso-2022-jp.xml
new file mode 100644
index 0000000..b325e6d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/iso-2022-jp.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="iso-2022-jp"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE test [
+  <!ELEMENT test (#PCDATA)>
+]>
+<test>
+ISO-2022-JP $B$N%U%!%$%k!#(B
+</test>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_include.xsl b/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_include.xsl
new file mode 100644
index 0000000..7774a46
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_include.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

+                version="1.0">

+

+  <xsl:template match="author">

+    <author>

+      <xsl:attribute name="name">

+        <xsl:value-of select="@name"/>

+      </xsl:attribute>

+    </author>

+  </xsl:template> 

+</xsl:stylesheet>

diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_with_include.xsl b/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_with_include.xsl
new file mode 100644
index 0000000..095fc8f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/stylesheet_with_include.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

+                version="1.0">

+

+  <xsl:output method="xml"/>

+  <xsl:include href="stylesheet_include.xsl"/>

+  <xsl:template match="/">

+    <authors>

+        <xsl:apply-templates/>

+    </authors>

+  </xsl:template>

+</xsl:stylesheet>

diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/test.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/test.xml
new file mode 100644
index 0000000..7f2abe0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/test.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root>
+  <a>this is the first line</a>
+  <b><c>not indented</c></b>
+  <b>
+    <c>indented</c>
+  </b>
+</root>
+  
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/test.xsl b/trunk/src/etc/testcases/taskdefs/optional/xml/test.xsl
new file mode 100644
index 0000000..8d28eb3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/test.xsl
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet	xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<!-- Copy every node and attributes recursively -->
+  <xsl:template match="node()|@*">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>  
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/utf-8.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/utf-8.xml
new file mode 100644
index 0000000..db442a3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/utf-8.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE test [
+  <!ELEMENT test (#PCDATA)>
+]>
+<test>
+Liberté, égalité, fraternité!
+</test>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xml/validate.xml b/trunk/src/etc/testcases/taskdefs/optional/xml/validate.xml
new file mode 100644
index 0000000..cade722
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xml/validate.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="validate" default="testValidate" basedir=".">
+
+ <target name="testValidate">
+    <xmlvalidate warn="false">
+      <fileset dir="." includes="about.xml"/>  
+       <dtd publicID="-//stevo//DTD doc 1.0//EN"
+         location="doc.dtd"/>
+    </xmlvalidate>
+  </target>
+  
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xmlvalidate.xml b/trunk/src/etc/testcases/taskdefs/optional/xmlvalidate.xml
new file mode 100644
index 0000000..cd7cc45
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xmlvalidate.xml
@@ -0,0 +1,208 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="validate" default="testValidate" basedir=".">
+
+  <target name="testValidate">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>  
+       <dtd publicID="-//stevo//DTD doc 1.0//EN"
+         location="xml/doc.dtd"/>
+    </xmlvalidate>
+  </target>
+  
+  <target name="testDeepValidate">
+    <ant dir="xml" 
+      antfile="validate.xml"
+      target="testValidate"/>
+  </target>
+
+  <target name="xmlcatalog">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <dtd publicID="-//stevo//DTD doc 1.0//EN"
+             location="doc.dtd"/>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+
+  <target name="xmlcatalogViaRefid">
+    <xmlcatalog classpath="xml" id="cat">
+      <dtd publicID="-//stevo//DTD doc 1.0//EN" location="doc.dtd"/>
+    </xmlcatalog>
+    <xmlvalidate warn="false">
+      <xmlcatalog refid="cat"/>
+      <fileset dir="xml" includes="**/about.xml"/>
+    </xmlvalidate>
+  </target>
+
+  <target name="xmlcatalognested">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <entity publicID = "bogusImage"
+                 location = "/i/dont/exist.jpg"/>
+        <xmlcatalog>
+          <dtd publicID="-//stevo//DTD doc 1.0//EN"
+               location="doc.dtd"/>
+        </xmlcatalog>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+
+  <!-- The -override tests should pass without resolver.jar -->
+  <target name="xmlcatalogfiles-override">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <catalogpath>
+          <fileset dir="xml" includes="catalog"/>
+        </catalogpath>
+        <dtd publicID="-//stevo//DTD doc 1.0//EN"
+             location="doc.dtd"/>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+ 
+  <target name="xmlcatalogpath-override">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <catalogpath>
+          <pathelement location="xml/catalog"/>
+        </catalogpath>
+        <dtd publicID="-//stevo//DTD doc 1.0//EN"
+          location="doc.dtd"/>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+ 
+  <target name="xmlcatalogfiles">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <catalogpath>
+          <fileset dir="xml" includes="catalog"/>
+        </catalogpath>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+ 
+  <target name="xmlcatalogpath">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="**/about.xml"/>
+      <xmlcatalog classpath="xml">
+        <catalogpath>
+          <pathelement location="xml/catalog"/>
+        </catalogpath>
+      </xmlcatalog>
+    </xmlvalidate>
+  </target>
+
+  <target name="testSchemaGood">
+    <xmlvalidate warn="false" lenient="no" >
+      <fileset dir="xml" includes="endpiece.xml"/>
+
+        <attribute name="http://xml.org/sax/features/validation"
+                   value="false"/>
+        <attribute name="http://apache.org/xml/features/validation/schema"
+                   value="false"/>
+
+    </xmlvalidate>
+  </target>
+
+  <target name="testSchemaBad">
+    <xmlvalidate warn="false">
+      <fileset dir="xml" includes="endpiece2.xml"/>
+      
+        <attribute name="http://xml.org/sax/features/validation"
+                   value="true"/>
+        <attribute name="http://apache.org/xml/features/validation/schema"
+                   value="true"/>
+    </xmlvalidate>
+  </target>
+    
+  <target name="testIso2022Jp">
+    <xmlvalidate warn="false" file="xml/iso-2022-jp.xml"/>
+  </target>
+
+  <target name="testUtf8">
+    <xmlvalidate warn="false" file="xml/utf-8.xml"/>
+  </target>
+
+
+  <!-- Tests property element with XML file that satisfies schema -->
+  <target name="testProperty.validXML">
+
+    <!-- Converts path to URL format -->
+    <pathconvert dirsep="/" property="xsd.file">
+    <path>
+    <pathelement location="xml/doc.xsd"/>
+    </path>
+    </pathconvert>
+
+    <xmlvalidate file="xml/endpiece-noSchema.xml" lenient="false"
+        failonerror="true" warn="true">
+
+        <attribute name="http://apache.org/xml/features/validation/schema"
+            value="true"/>
+
+        <property
+        name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+        value="${xsd.file}"/>
+    </xmlvalidate>
+  </target>
+
+
+  <!-- Tests property element with XML file that fails schema validation -->
+  <target name="testProperty.invalidXML">
+
+      <!-- Converts path to URL format -->
+      <pathconvert dirsep="/" property="xsd.file">
+          <path>
+              <pathelement location="xml/doc.xsd"/>
+          </path>
+      </pathconvert>
+
+      <xmlvalidate file="xml/endpiece-noSchema-invalid.xml" lenient="false"
+        failonerror="true" warn="true">
+
+        <attribute name="http://apache.org/xml/features/validation/schema"
+                   value="true"/>
+
+        <property
+            name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+            value="${xsd.file}"/>
+      </xmlvalidate>
+  </target>
+
+  <target name="testSchemaWithXSD">
+    <xmlvalidate warn="false" lenient="false" 
+        file="xml/endpiece-noSchema.xml">
+      
+        <attribute name="http://apache.org/xml/features/validation/schema"
+                   value="true"/>
+        <property
+            name="http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"
+            value="${xsd.file}"/>
+
+       </xmlvalidate>
+  </target>
+  
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xslt.xml b/trunk/src/etc/testcases/taskdefs/optional/xslt.xml
new file mode 100644
index 0000000..5e6bf0c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xslt.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xslt" default="xslt" basedir=".">
+  <property name="nonasciidir" value="xml/&#0227;nt"/>
+  <target name="init">
+      <mkdir dir="xml/out"/>
+  </target>
+
+  <target name="initNonAscii">
+      <mkdir dir="${nonasciidir}"/>
+      <copy todir="${nonasciidir}">
+        <fileset dir="xml">
+          <include name="docwithentity.xml"/>
+          <include name="entity.xml"/>
+        </fileset>
+      </copy>
+  </target>
+
+  <target name="teardown">
+      <delete dir="xml/out"/>
+      <delete dir="${nonasciidir}" quiet="true"/>
+  </target>
+  
+  <target name="testCatchNoDtd" depends="init">
+    <xslt basedir="xml" destdir="xml/out"
+           includes="about.xml"
+           extension=".txt"
+           style="xml/doc.xsl">
+     </xslt>
+  </target>
+  
+  <xmlcatalog id="xdocs.catalog">
+   <dtd publicID="-//stevo//DTD doc 1.0//EN"
+     location="xml/doc.dtd"/>
+  </xmlcatalog>  
+  
+  <target name="testCatalog" depends="init">
+    <xslt destdir="xml/out"
+           includes="about.xml"
+           extension=".txt"
+           style="xml/doc.xsl">
+       <xmlcatalog refid="xdocs.catalog"/>
+     </xslt>
+  </target>
+
+  <target name="testOutputProperty" depends="init">
+    <xslt in="xml/test.xml"
+           out="xml/out/test-out.xml"
+           style="xml/test.xsl">
+      <outputproperty name="method" value="xml"/>
+      <outputproperty name="standalone" value="yes"/>
+      <outputproperty name="encoding" value="iso8859_1"/>
+      <outputproperty name="indent" value="yes"/>
+    </xslt>
+  </target>
+  
+  
+  <target name="testFactory" depends="init">
+    <xslt in="xml/test.xml"
+           out="xml/out/test-out.xml"
+           style="xml/test.xsl">
+           <factory name="org.apache.xalan.processor.TransformerFactoryImpl"/>
+    </xslt>
+  </target>
+
+  <target name="testAttribute" depends="init">
+    <xslt in="xml/test.xml"
+           out="xml/out/test-out.xml"
+           style="xml/test.xsl">
+           <factory name="org.apache.xalan.processor.TransformerFactoryImpl">
+            <attribute name="http://xml.apache.org/xalan/features/optimize" value="true"/>
+           </factory>
+    </xslt>
+  </target>
+  <!-- inspired by bug report 37348 -->
+  <target name="testXMLWithEntitiesInNonAsciiPath" depends="initNonAscii">
+    <xslt in="${nonasciidir}/docwithentity.xml"
+           out="xml/out/test-out.xml"
+           style="xml/apache.xsl">
+    </xslt>
+  </target>
+  <target name="testStyleSheetWithInclude" depends="init">
+    <xslt in="xml/books.xml"
+           out="xml/out/test-out.xml"
+           style="xml/stylesheet_with_include.xsl">
+    </xslt>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xml b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xml
new file mode 100644
index 0000000..80d9336
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root>
+    <message>éàèïù</message>
+</root>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xsl b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xsl
new file mode 100644
index 0000000..f19bf82
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-encoding-in.xsl
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+<xsl:template match="/">
+    <root>
+    <xsl:for-each select="/root/message">
+        <message><xsl:value-of select="."/></message>
+    </xsl:for-each>
+    </root>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xml b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xml
new file mode 100644
index 0000000..a4b0247
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE project [
+    <!ENTITY include SYSTEM "xsltliaison-include.xml">
+]>
+<project>
+    &include;
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xsl b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xsl
new file mode 100644
index 0000000..852d38a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-in.xsl
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:include href="xsltliaison-include.xsl"/>
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xml b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xml
new file mode 100644
index 0000000..88713e4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- to be included by xsltliaison-include.xsl -->
+<task/>
diff --git a/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xsl b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xsl
new file mode 100644
index 0000000..986f1b3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/optional/xsltliaison-include.xsl
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<!-- to be included by xsltliaison-in.xsl -->
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/parallel.xml b/trunk/src/etc/testcases/taskdefs/parallel.xml
new file mode 100644
index 0000000..6c1681c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/parallel.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="parallel-test" basedir="." default="help">
+  <target name="testBasic">
+    <parallel>
+      <sequential>
+        <sleep seconds="1"/>
+        <echo message="${test.delayed}"/>
+      </sequential>
+      <echo message="${test.direct}"/>
+    </parallel>
+  </target>
+
+  <target name="testFail">
+    <parallel>
+      <sequential>
+        <sleep seconds="1"/>
+        <echo message="${test.delayed}"/>
+      </sequential>
+      <fail message="${test.failure}"/>
+    </parallel>
+  </target>
+
+  <target name="testThreadCount">
+    <echo>|1/</echo>
+    <parallel threadCount='1' pollInterval="60">
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="30"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="60"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="90"/>
+        <echo message="-"/>
+      </sequential>
+    </parallel>
+    <echo>|2/</echo>
+    <parallel threadCount='2' pollInterval="30">
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="30"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="60"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="90"/>
+        <echo message="-"/>
+      </sequential>
+    </parallel>
+    <echo>|3/</echo>
+    <parallel threadCount='3' pollInterval="30">
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="30"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="60"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="90"/>
+        <echo message="-"/>
+      </sequential>
+    </parallel>
+    <echo>|4/</echo>
+    <parallel threadCount='4' pollInterval="30">
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="30"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="60"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="90"/>
+        <echo message="-"/>
+      </sequential>
+    </parallel>
+    <echo>|4/</echo>
+    <parallel threadsPerProcessor='1' threadcount='4' pollInterval="30">
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="30"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="60"/>
+        <echo message="-"/>
+      </sequential>
+      <sequential>
+        <echo message="+"/>
+        <sleep milliseconds="90"/>
+        <echo message="-"/>
+      </sequential>
+    </parallel>
+    <echo>|</echo>
+    
+  </target>
+
+  <target name="testDemux">
+    <parallel>
+      <demuxtest/>
+      <demuxtest/>
+      <demuxtest/>
+      <demuxtest/>
+      <demuxtest/>
+    </parallel>
+  </target>
+  
+  <target name="help">
+    <echo>Test build file for the &lt;parallel&gt; task.</echo> 
+    <echo>Use the various targets to run the tests.</echo>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/pathconvert.xml b/trunk/src/etc/testcases/taskdefs/pathconvert.xml
new file mode 100755
index 0000000..1a00bd9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/pathconvert.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="pathconvert">
+
+    <path id="testpath">
+        <pathelement path="${ant.file}" />
+    </path>
+
+    <target name="testmap">
+        <pathconvert property="result" dirsep="#">
+            <path refid="testpath" />
+            <map from="${basedir}" to="test" />
+        </pathconvert>
+    </target>
+
+    <target name="testmapper">
+        <pathconvert property="result" dirsep="#">
+            <path refid="testpath" />
+            <mapper type="glob" from="${basedir}" to="test" />
+        </pathconvert>
+    </target>
+
+    <target name="testnotargetos">
+        <pathconvert property="result" refid="testpath" />
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/presetdef.xml b/trunk/src/etc/testcases/taskdefs/presetdef.xml
new file mode 100644
index 0000000..695747e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/presetdef.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <path id="test-classes">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+  
+  <target name="simple">
+    <presetdef name="my.echo">
+      <echo message="Hello world"/>
+    </presetdef>
+    <my.echo/>
+  </target>
+
+  <target name="text">
+    <presetdef name="my.echo">
+      <echo>Inner Text</echo>
+    </presetdef>
+    <my.echo/>
+  </target>
+
+  <target name="uri">
+    <presetdef name="echo" uri="abc">
+      <echo message="Hello world"/>
+    </presetdef>
+    <x:echo xmlns:x="abc"/>
+  </target>
+
+  <target name="defaulttest">
+    <taskdef name="defaulttest"
+             classname="org.apache.tools.ant.taskdefs.PreSetDefTest$DefaultTest"
+             classpathref="test-classes"/>
+    <presetdef name="d">
+      <defaulttest attribute="true"/>
+    </presetdef>
+    <d attribute="false"/>
+  </target>
+
+  <target name="doubledefault">
+    <taskdef name="defaulttest"
+             classname="org.apache.tools.ant.taskdefs.PreSetDefTest$DefaultTest"
+             classpathref="test-classes"/>
+    <presetdef name="d">
+      <defaulttest attribute="true"/>
+    </presetdef>
+    <presetdef name="dd">
+      <d attribute="false"/>
+    </presetdef>
+    <dd/>
+    <dd attribute="true"/>
+  </target>
+
+  <target name="antTypeTest">
+    <taskdef name="anttypetest"
+             classname="org.apache.tools.ant.taskdefs.PreSetDefTest$AntTypeTest"
+             classpathref="test-classes"/>
+    <presetdef name="java.fileset">
+      <fileset>
+        <include name="**/*.java"/>
+      </fileset>
+    </presetdef>
+    
+    <anttypetest>
+      <fileset ant-type="java.fileset" dir="."/>
+      <configured ant-type="java.fileset" dir="."/>
+    </anttypetest>
+  </target>
+
+  <target name="text.optional">
+    <presetdef name="echo.mytext">
+      <echo>MyText</echo>
+    </presetdef>
+    <echo.mytext/>
+    <echo.mytext>override text</echo.mytext>
+  </target>
+
+  <target name="element.order">
+    <presetdef name="el.order">
+      <sequential>
+        <echo>Line 1</echo>
+      </sequential>
+    </presetdef>
+    <el.order>
+      <echo>Line 2</echo>
+    </el.order>
+  </target>
+
+  <target name="element.order2">
+    <presetdef name="el.order">
+      <sequential>
+        <echo>Line 1</echo>
+      </sequential>
+    </presetdef>
+    <presetdef name="el.order2">
+      <el.order>
+        <echo>Line 2</echo>
+      </el.order>
+    </presetdef>
+    <el.order2>
+      <echo>Line 3</echo>
+    </el.order2>
+  </target>
+
+  <target name="correct_taskname_badattr">
+    <presetdef name="mytask">
+       <javac srcdir="whatever"/>
+    </presetdef>
+
+    <javac srcdir="whatever" badattr="whatever"/>
+  </target>
+
+  <target name="correct_taskname_badel">
+    <presetdef name="mytask">
+       <javac srcdir="whatever"/>
+    </presetdef>
+
+    <javac srcdir="whatever">
+      <badel/>
+    </javac>
+  </target>
+
+    <target name="presetdef-with-nested-element-twice">
+        <copy todir=".">
+            <fileset dir="." includes="nonexistent"/>
+        </copy>
+        <presetdef name="copy">
+            <copy verbose="true"/>
+        </presetdef>
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/property.xml b/trunk/src/etc/testcases/taskdefs/property.xml
new file mode 100644
index 0000000..6949fee
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="property-test" basedir="." default="test1">
+
+  <property name="tmp.dir" value="_tmpdir_"/>
+  <available property="java5+" classname="java.lang.Iterable"/>
+
+  <target name="tearDown">
+    <delete dir="${tmp.dir}"/>
+  </target>
+
+  <target name="test1">
+    <property environment="testenv"/>
+  </target>
+
+  <target name="test2">
+    <property name="testprop1" value="aa"/>
+    <property file="property1.properties"/>
+    <echo message="testprop1=${testprop1}, testprop3=${testprop3}, testprop4=${testprop4}"/>
+  </target>
+
+  <target name="test3">
+    <property file="property2.properties"/>
+  </target>
+
+  <target name="test4">
+    <property name="http.port" value="999" />
+    <property file="property3.properties"/>
+    <echo message="http.url is ${http.url}"/>
+  </target>
+
+  <target name="test5">
+    <property name="http.port" value="999" />
+    <property url="${test5.url}"/>
+    <echo message="http.url is ${http.url}"/>
+  </target>
+
+  <target name="prefix.success">
+    <property file="property3.properties" prefix="server1"/>
+  </target>
+
+  <target name="prefix.fail">
+    <property name="someprop" value="value" prefix="prefix"/>
+  </target>
+
+  <!-- caused an endless loop, PR 21825 -->
+  <target name="testCircularReference">
+    <property file="property4.properties"/>
+  </target>
+
+  <target name="thisIsNotACircularReference">
+    <property file="property5.properties"/>
+    <echo>b is ${b}</echo>
+  </target>
+
+  <target name="genXmlPropFile">
+    <mkdir dir="${tmp.dir}"/>  
+    <echo file="${tmp.dir}/props.xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
+&lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd&quot;&gt;
+&lt;properties version=&quot;1.0&quot;&gt;
+    &lt;comment&gt;
+        Example of property definition according to Suns DTD as
+        specified in the Java5 docs and http://java.sun.com/dtd/properties.dtd.
+    &lt;/comment&gt;
+    &lt;entry key=&quot;xml.one&quot;&gt;ONE&lt;/entry&gt;
+    &lt;entry key=&quot;xml.two&quot;&gt;TWO&lt;/entry&gt;
+&lt;/properties&gt;
+    </echo>  
+  </target>      
+
+  <target name="testXmlProperty.internal" depends="genXmlPropFile" if="java5+">
+      <property file="${tmp.dir}/props.xml"/>
+  </target>    
+  <target name="testXmlProperty" depends="testXmlProperty.internal"/>  
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/property1.properties b/trunk/src/etc/testcases/taskdefs/property1.properties
new file mode 100644
index 0000000..ef3ebd3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property1.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+testprop2=xx
+testprop3=${testprop2}yy
+testprop4=${testprop1}zz
diff --git a/trunk/src/etc/testcases/taskdefs/property2.properties b/trunk/src/etc/testcases/taskdefs/property2.properties
new file mode 100644
index 0000000..8125312
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property2.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+testprop1=aa${testprop2}bb
+testprop2=cc${testprop1}dd
+
diff --git a/trunk/src/etc/testcases/taskdefs/property3.properties b/trunk/src/etc/testcases/taskdefs/property3.properties
new file mode 100644
index 0000000..ac21612
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property3.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+http.port = 80
+http.url = http://localhost:${http.port}
+
+
diff --git a/trunk/src/etc/testcases/taskdefs/property4.properties b/trunk/src/etc/testcases/taskdefs/property4.properties
new file mode 100644
index 0000000..6552710
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property4.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+a=${a}
+b=${a}/b
diff --git a/trunk/src/etc/testcases/taskdefs/property5.properties b/trunk/src/etc/testcases/taskdefs/property5.properties
new file mode 100644
index 0000000..e1ebcd3
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/property5.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+a=A
+b=${a}/${c}/${a}
+c=${a}
diff --git a/trunk/src/etc/testcases/taskdefs/recorder.xml b/trunk/src/etc/testcases/taskdefs/recorder.xml
new file mode 100644
index 0000000..2f26000
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/recorder.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="recorder-test" default="all" basedir=".">
+
+    <property name="recin" location="recorder"/>
+    <property name="recdir" location="recorder-out"/>
+
+    <target name="all" depends="noappend,append,restart,deleterestart"/>
+
+    <target name="prepare">
+      <mkdir dir="${recdir}"/>
+    </target>
+
+    <target name="noappend">
+        <copy file="${recin}/rectest2.result" tofile="${recdir}/rectest1.log"/>
+        <record name="${recdir}/rectest1.log" action="start" />
+        <echo message="some message1"/>
+        <record name="${recdir}/rectest1.log" action="stop" />
+    </target>
+
+    <target name="append">
+        <copy file="${recin}/rectest1.result" tofile="${recdir}/rectest2.log"/>
+        <record name="${recdir}/rectest2.log" append="true" action="start"/>
+        <echo message="some message2"/>
+        <record name="${recdir}/rectest2.log" action="stop"/>
+    </target>
+
+    <target name="restart">
+        <record name="${recdir}/rectest3.log" action="start"/>
+        <echo message="some message1"/>
+        <record name="${recdir}/rectest3.log" action="stop"/>
+        <echo message="some message2"/>
+        <record name="${recdir}/rectest3.log" action="start"/>
+        <echo message="some message3"/>
+        <record name="${recdir}/rectest3.log" action="stop"/>
+    </target>
+
+    <target name="deleterestart">
+        <record name="${recdir}/rectest4.log" action="start"/>
+        <echo message="some message1"/>
+        <record name="${recdir}/rectest4.log" action="stop"/>
+        <delete file="${recdir}/rectest4.log"/>
+        <echo message="some message2"/>
+        <record name="${recdir}/rectest4.log" action="start"/>
+        <echo message="some message3"/>
+        <record name="${recdir}/rectest4.log" action="stop"/>
+    </target>
+
+
+    <target name="cleanup">
+       <delete dir="${recdir}"/>
+    </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/recorder/rectest1.result b/trunk/src/etc/testcases/taskdefs/recorder/rectest1.result
new file mode 100644
index 0000000..0f8013f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/recorder/rectest1.result
@@ -0,0 +1 @@
+     [echo] some message1
diff --git a/trunk/src/etc/testcases/taskdefs/recorder/rectest2.result b/trunk/src/etc/testcases/taskdefs/recorder/rectest2.result
new file mode 100644
index 0000000..80550fd
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/recorder/rectest2.result
@@ -0,0 +1,2 @@
+     [echo] some message1
+     [echo] some message2
diff --git a/trunk/src/etc/testcases/taskdefs/recorder/rectest3.result b/trunk/src/etc/testcases/taskdefs/recorder/rectest3.result
new file mode 100644
index 0000000..e496177
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/recorder/rectest3.result
@@ -0,0 +1,2 @@
+     [echo] some message1
+     [echo] some message3
diff --git a/trunk/src/etc/testcases/taskdefs/recorder/rectest4.result b/trunk/src/etc/testcases/taskdefs/recorder/rectest4.result
new file mode 100644
index 0000000..db6239e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/recorder/rectest4.result
@@ -0,0 +1 @@
+     [echo] some message3
diff --git a/trunk/src/etc/testcases/taskdefs/rename.xml b/trunk/src/etc/testcases/taskdefs/rename.xml
new file mode 100644
index 0000000..a23a81e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/rename.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="test1">
+    <rename/>
+  </target>
+
+  <target name="test2">
+    <rename src=""/>
+  </target>
+
+  <target name="test3">
+    <rename dest=""/>
+  </target>
+
+  <target name="test4">
+    <rename src="testdir" 
+            dest="testdir"/>
+  </target>
+
+  <target name="test5">
+    <rename src="template.xml" 
+            dest="."/>
+  </target>
+
+  <target name="test6">
+    <rename src="template.xml" 
+            dest="template.tmp"/>
+    <rename src="template.tmp" 
+            dest="template.xml"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/replace.xml b/trunk/src/etc/testcases/taskdefs/replace.xml
new file mode 100644
index 0000000..a321607
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/replace.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <property name="tmp.dir" location="replace/tmp"/>
+
+  <target name="test1">
+    <replace/>
+  </target>
+
+  <target name="test2">
+    <replace file=""/>
+  </target>
+
+  <target name="test3">
+    <replace file="template.xml"/>
+  </target>
+
+  <target name="test4">
+    <replace file="template.xml" token=""/>
+  </target>
+
+  <target name="test5">
+    <replace file="template.xml" 
+             token="dont_want_to_really_replace_something"/>
+  </target>
+
+  <target name="test6">
+    <replace file="template.xml">
+      <replacefilter />
+    </replace>
+  </target>
+
+  <target name="test7">
+    <replace file="template.xml">
+      <replacefilter token="" />
+    </replace>
+  </target>
+
+  <target name="test8">
+    <replace file="template.xml">
+      <replacefilter token="dont_want_to_really_replace_something" />
+    </replace>
+  </target>
+
+  <target name="test9-setup">
+    <!-- this fixing of line endings is necessary because the replace task is transforming the line endings -->
+    <!-- of the replacement tokens and values to the platform default -->
+    <!-- in certain cases (checkout done with cvs of cygwin, the line endings of the various files do not match-->
+    <!-- the system property line.separator -->
+    <copy file="replace/source.txt" tofile="${tmp.dir}/output.txt"/>
+    <copy file="replace/value.txt" tofile="${tmp.dir}/value.txt" />
+    <copy file="replace/result.txt" tofile="${tmp.dir}/result.txt" />
+    <fixcrlf srcdir="${tmp.dir}" includes="*.txt"/>
+  </target>
+  <target name="test9" depends="test9-setup">
+    <loadfile srcFile="${tmp.dir}/value.txt" property="content"/>
+    <replace file="${tmp.dir}/output.txt" token="@@@Replace this@@@" value="${content}"/>
+  </target>
+
+  <target name="cleanup">
+      <delete dir="${tmp.dir}" quiet="true"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/replace/result.txt b/trunk/src/etc/testcases/taskdefs/replace/result.txt
new file mode 100644
index 0000000..a74e06e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/replace/result.txt
@@ -0,0 +1,7 @@
+This is line one
+This is line two
+This is line three
+This is line four
+This is line five
+This is line six
+
diff --git a/trunk/src/etc/testcases/taskdefs/replace/source.txt b/trunk/src/etc/testcases/taskdefs/replace/source.txt
new file mode 100644
index 0000000..8d73f31
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/replace/source.txt
@@ -0,0 +1,4 @@
+This is line one
+This is line two
+This is line three
+@@@Replace this@@@
diff --git a/trunk/src/etc/testcases/taskdefs/replace/value.txt b/trunk/src/etc/testcases/taskdefs/replace/value.txt
new file mode 100644
index 0000000..c75b552
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/replace/value.txt
@@ -0,0 +1,3 @@
+This is line four
+This is line five
+This is line six
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/rmic/rmic.xml b/trunk/src/etc/testcases/taskdefs/rmic/rmic.xml
new file mode 100644
index 0000000..f1b1e59
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/rmic/rmic.xml
@@ -0,0 +1,332 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="rmic" default="teardown" basedir=".">
+
+  <property name="rmic.dir" location="." />
+  <property name="src.dir" location="${rmic.dir}/src"/>
+  <property name="build.dir" location="${rmic.dir}/build"/>
+
+  <target name="teardown">
+    <delete dir="${build.dir}"/>
+  </target>
+
+  <!-- init builds the java source -->
+  <target name="init" depends="probe-rmic">
+    <mkdir dir="${build.dir}"/>
+
+    <javac
+      destdir="${build.dir}"
+      srcdir="${src.dir}"
+      includes="Remote*.java">
+    </javac>
+
+    <presetdef name="base-rmic">
+      <rmic
+        base="${build.dir}"
+        verify="true"
+        includes="**/*.class"/>
+    </presetdef>
+
+    <presetdef name="rmic-bad-class">
+      <rmic
+        base="${build.dir}"
+        verify="false"
+        classname="unimplemented.class"
+        />
+    </presetdef>
+
+    <macrodef name="assertFileCreated">
+      <attribute name="file" />
+      <sequential>
+        <fail>Not found : ${build.dir}/@{file}
+          <condition>
+            <not><available file="${build.dir}/@{file}"/></not>
+          </condition>
+        </fail>
+      </sequential>
+    </macrodef>
+
+    <macrodef name="assertFileAbsent">
+      <attribute name="file" />
+      <sequential>
+        <fail>Expected to be missing : ${build.dir}/@{file}
+          <condition>
+            <available file="${build.dir}/@{file}"/>
+          </condition>
+        </fail>
+      </sequential>
+    </macrodef>
+
+    
+    <macrodef name="assertStubCompiled">
+      <sequential>
+        <assertFileCreated file="RemoteTimestampImpl_Stub.class"  />
+      </sequential>
+    </macrodef>
+
+    <macrodef name="assertSkelCompiled">
+      <sequential>
+        <assertFileCreated file="RemoteTimestampImpl_Skel.class"  />
+      </sequential>
+    </macrodef>
+
+    <macrodef name="assertSkelAbsent">
+      <sequential>
+        <assertFileAbsent file="RemoteTimestampImpl_Skel.class"  />
+      </sequential>
+    </macrodef>
+    
+    <macrodef name="assertBaseCompiled">
+      <sequential>
+        <assertStubCompiled />
+        <assertSkelCompiled />
+      </sequential>
+    </macrodef>
+
+    
+    <macrodef name="assertAntStubCompiled">
+      <sequential>
+        <assertFileCreated file="AntTimestamp_Stub.class"/>
+      </sequential>
+    </macrodef>
+    
+    <macrodef name="assertAntSkelCompiled">
+      <sequential>
+        <assertFileCreated file="AntTimestamp_Skel.class"/>
+      </sequential>
+    </macrodef>
+
+    <macrodef name="assertAntCompiled">
+      <sequential>
+        <assertAntStubCompiled />
+        <assertAntSkelCompiled />
+      </sequential>
+    </macrodef>
+
+  </target>
+  
+  <target name="probe-rmic">
+    <available property="kaffe.present" classname="jkaffe.rmi.rmic.RMIC"/>
+    <available property="rmic.present" classname="sun.rmi.rmic.Main"/>
+    <available property="wlrmic.present" classname="weblogic.rmic"/>
+    <condition property="rmic5.present">
+      <and>
+        <isset property="rmic.present"/>
+        <available classname="java.net.Proxy"/>
+      </and>
+    </condition>
+    <condition property="rmic6.present">
+      <and>
+        <isset property="rmic.present"/>
+        <available classname="java.util.ServiceLoader"/>
+      </and>
+    </condition>
+  </target>
+
+  <target name="testDefault" depends="init">
+    <base-rmic compiler="default"/>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testEmpty" depends="init">
+    <base-rmic compiler=""/>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testVersion11" depends="init">
+    <base-rmic compiler="default" stubversion="1.1" />
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testVersion12" depends="init">
+    <base-rmic compiler="default" stubversion="1.2" />
+    <assertStubCompiled/>
+    <assertSkelAbsent/>
+  </target>
+  
+  <target name="testVersionCompat" depends="init">
+    <base-rmic compiler="default" stubversion="compat" />
+    <assertBaseCompiled/>
+  </target>
+  
+  <target name="testRmic" if="rmic.present" depends="init">
+    <base-rmic compiler="sun"/>
+    <assertBaseCompiled/>
+  </target>
+
+
+  <target name="testRmicJArg" if="rmic.present" depends="init">
+    <base-rmic compiler="sun">
+      <compilerarg value="-J-mx256m" />
+    </base-rmic>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testKaffe" if="kaffe.present" depends="init">
+    <base-rmic
+      compiler="kaffe"
+      />
+    <assertBaseCompiled/>
+  </target>
+	
+<!-- weblogic.rmic doesn't work without a global CLASSPATH
+  <target name="testWlrmic" if="wlrmic.present" depends="init">
+    <base-rmic
+      compiler="weblogic"
+      />
+  </target>
+
+  <target name="testWlrmicJArg" if="wlrmic.present" depends="init">
+    <base-rmic
+        compiler="weblogic"
+        >
+      <compilerarg value="-J-mx256m" />
+    </base-rmic>
+  </target>
+-->
+  <target name="testForking" if="rmic.present" depends="init">
+    <base-rmic
+      compiler="forking"
+      />
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testBadName" if="rmic.present" depends="init">
+    <base-rmic
+      compiler="no-such-compiler"
+      />
+  </target>
+
+  <target name="testExplicitClass" if="rmic.present" depends="init">
+    <base-rmic
+        compiler="org.apache.tools.ant.taskdefs.rmic.SunRmic"
+        />
+    <assertBaseCompiled/>
+  </target>
+  
+  <target name="testWrongClass" if="rmic.present" depends="init">
+    <base-rmic
+      compiler="org.apache.tools.ant.BuildException"
+      />
+  </target>
+
+  <target name="testNoBase" depends="init">
+    <rmic
+      verify="true"
+      includes="**/*.class"/>
+  </target>
+
+  <target name="testBaseDoesntExist" depends="init">
+    <rmic
+      base="${build.dir}/classes"
+      verify="true"
+      includes="**/*.class"/>
+  </target>
+
+  <target name="testBaseIsntDir" depends="init">
+    <rmic
+      base="${ant.file}"
+      verify="true"
+      includes="**/*.class"/>
+  </target>
+
+  <target name="testFailingAdapter" depends="init">
+    <base-rmic
+      compiler="org.apache.tools.ant.taskdefs.rmic.RmicAdvancedTest$FailingRmicAdapter"
+      />
+  </target>
+  
+  <target name="compileAntTimestamp" depends="init">
+    <javac
+      destdir="${build.dir}"
+      srcdir="${src.dir}"
+      includes="Ant*.java">
+    </javac>
+  </target>
+
+  <target name="testAntClasspath" depends="compileAntTimestamp">
+    <base-rmic
+      compiler="default"
+      />
+    <assertAntCompiled/>
+  </target>
+
+  <target name="testForkingAntClasspath" if="rmic.present" depends="compileAntTimestamp">
+    <base-rmic
+      compiler="forking"
+      />
+    <assertAntCompiled />
+  </target>
+
+  <target name="testDefaultBadClass" depends="init">
+    <rmic-bad-class compiler="default"/>
+  </target>
+
+  <target name="testMagicProperty" depends="init">
+    <property name="build.rmic" value="no-such-adapter"/>
+    <base-rmic
+      />
+  </target>
+
+  <target name="testMagicPropertyOverridesEmptyString" depends="init">
+    <property name="build.rmic" value="no-such-adapter"/>
+    <base-rmic compiler=""
+      />
+  </target>
+
+  <target name="testMagicPropertyIsEmptyString" depends="init">
+    <property name="build.rmic" value=""/>
+    <base-rmic />
+    <assertBaseCompiled/>
+  </target>
+
+  <!--
+  This test stamps on the XML parser settings on java6, so it is disabled.
+  -->
+  <target name="testXnew" if="rmic5.present" unless="rmic6.present" depends="init">
+    <base-rmic compiler="sun">
+      <compilerarg value="-Xnew"/>
+    </base-rmic>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testXnewForked" if="rmic5.present" depends="init">
+    <base-rmic compiler="forking">
+      <compilerarg value="-Xnew"/>
+    </base-rmic>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testXnewCompiler" if="rmic5.present" depends="init">
+    <base-rmic compiler="xnew">
+    </base-rmic>
+    <assertBaseCompiled/>
+  </target>
+
+  <target name="testIDL" depends="init">
+    <base-rmic compiler="default" idl="true"/>
+    <assertFileCreated file="RemoteTimestamp.idl"/>
+  </target>
+
+  <target name="testIIOP" depends="init">
+    <base-rmic compiler="default" iiop="true"/>
+    <assertFileCreated file="_RemoteTimestamp_Stub.class"/>
+    <assertFileCreated file="_RemoteTimestampImpl_Tie.class"/>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/rmic/src/AntTimestamp.java b/trunk/src/etc/testcases/taskdefs/rmic/src/AntTimestamp.java
new file mode 100644
index 0000000..d9ba785
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/rmic/src/AntTimestamp.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Calendar;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.DateUtils;
+
+
+/**
+ * This class imports a dependency on the Ant runtime classes,
+ * so tests that classpath setup include them
+ */
+public class AntTimestamp implements RemoteTimestamp {
+
+
+    /**
+     * return the phase of the moon.
+     * Note the completely different semantics of the other implementation,
+     * which goes to show why signature is an inadequate way of verifying
+     * how well an interface is implemented.
+     *
+     * @return
+     * @throws RemoteException
+     */
+    public long when() throws RemoteException {
+        Calendar cal=Calendar.getInstance();
+        return DateUtils.getPhaseOfMoon(cal);
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestamp.java b/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestamp.java
new file mode 100644
index 0000000..1834e4a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestamp.java
@@ -0,0 +1,26 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * this is the interface we remote
+ */
+public interface RemoteTimestamp extends Remote {
+    long when() throws RemoteException ;
+}
+
diff --git a/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestampImpl.java b/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestampImpl.java
new file mode 100644
index 0000000..f361452
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/rmic/src/RemoteTimestampImpl.java
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * this is the implementation
+ */
+public class RemoteTimestampImpl implements RemoteTimestamp {
+
+    public long when() throws RemoteException {
+        return System.currentTimeMillis();
+    }
+}
diff --git a/trunk/src/etc/testcases/taskdefs/signjar.xml b/trunk/src/etc/testcases/taskdefs/signjar.xml
new file mode 100644
index 0000000..1d83aed
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/signjar.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="signjartest" default="help" basedir="..">
+
+  <property name="classes.dir" value="../../../build/classes"/>
+  <property name="sign.dir" location="signedjars" />
+  <property name="subdir" location="${sign.dir}/subdir" />
+  <property name="test.jar" location="${sign.dir}/signtest.jar" />
+  <property name="subdirtest.jar" location="${subdir}/signtest.jar" />
+  
+  
+  <macrodef name="assertSigned">
+    <attribute name="jar" default="${test.jar}" />
+    <sequential>
+      <fail message="not signed: @{jar}" >
+        <condition>
+          <not><issigned file="@{jar}" /></not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <presetdef name="sign-base">
+    <signjar alias="testonly" keystore="testkeystore"
+           storepass="apacheant"/>
+  </presetdef>
+
+  <presetdef name="verify-base">
+    <verifyjar keystore="testkeystore"
+           storepass="apacheant"/>
+  </presetdef>
+
+
+  
+  <presetdef name="sign">
+    <sign-base jar="${test.jar}" />
+  </presetdef>
+
+  <target name="init">
+    <mkdir dir="${sign.dir}" />
+    <mkdir dir="${subdir}" />
+  </target>
+  
+  <target name="jar" depends="init">
+    <jar jarfile="${test.jar}" basedir="${classes.dir}" includes="**/Task.class"/>
+  </target>  
+
+  
+  
+  <target name="clean">
+    <delete dir="${sign.dir}"/>
+  </target>
+
+  <target name="help">
+    <echo>This build is for use with Ant's test cases</echo>
+  </target>
+  
+  <target name="basic" depends="jar">
+    <sign />
+    <assertSigned/>             
+  </target>
+
+  <target name="sigfile" depends="jar">
+    <sign sigfile="TEST"/>
+    <assertSigned/>             
+  </target>
+
+  <target name="maxmemory" depends="jar">
+    <sign maxmemory="128m"/>
+    <assertSigned/>             
+  </target>
+
+  <target name="urlKeystoreFile" depends="jar">
+    <sign keystore="file://../testkeystore"
+       maxmemory="128m"/>
+    <assertSigned/>             
+  </target>
+
+  
+  <target name="urlKeystoreHTTP" depends="jar">
+    <sign
+      keystore="http://ant.apache.org/webtest/testkeystore"
+      />
+    <assertSigned/>             
+  </target>
+
+  <target name="preserveLastModified" depends="jar">
+    <touch file="${test.jar}" datetime="06/28/2000 2:02 pm"/>
+    <sign 
+    	preservelastmodified="true"/>
+    <assertSigned />
+    <fail message="preserveLastModified did not preserve the last modified time">
+      <condition>
+        <not>
+          <isfileselected file="${test.jar}" >
+            <date datetime="06/28/2000 2:02 pm" when="equal"/>
+          </isfileselected>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testFileset" depends="jar">
+    <sign-base>
+      <fileset file="${test.jar}" />
+    </sign-base>
+    <assertSigned/>
+  </target>
+
+  <target name="testFilesetAndJar" depends="jar">
+    <sign-base jar="${test.jar}" lazy="true">
+      <fileset file="${test.jar}" />
+    </sign-base>
+    <assertSigned/>
+  </target>
+  
+  <target name="testFilesetAndSignedJar" depends="jar">
+    <sign-base signedjar="${sign.dir}/newfile.jar">
+      <fileset file="${test.jar}" />
+    </sign-base>
+  </target>
+  
+  <target name="testPath" depends="jar">
+    <sign-base>
+      <path>
+        <fileset file="${test.jar}" />
+      </path>
+    </sign-base>
+    <assertSigned/>
+  </target>
+
+  <target name="testPathAndJar" depends="jar">
+    <sign-base jar="${test.jar}" lazy="true">
+      <path>
+        <fileset file="${test.jar}" />
+      </path>
+    </sign-base>
+    <assertSigned/>
+  </target>
+  
+  <target name="testPathAndSignedJar" depends="jar">
+    <sign-base signedjar="${sign.dir}/newfile.jar">
+      <path>
+        <fileset file="${test.jar}" />
+      </path>
+    </sign-base>
+  </target>
+  
+  <target name="testSignedJar" depends="jar">
+    <sign signedjar="${subdirtest.jar}"/>
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+
+  <target name="testDestDirAndSignedJar" depends="jar">
+    <sign destDir="${subdir}" signedjar="${sign.dir}/newfile.jar"/>
+  </target>
+
+  <target name="testDestDir" depends="jar">
+    <sign destDir="${subdir}" />
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+  
+  <target name="testDestDirFileset" depends="jar">
+    <sign-base destDir="${subdir}">
+      <fileset file="${test.jar}" />
+    </sign-base>
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+  
+  <target name="testDestDirPath" depends="jar">
+    <sign-base destDir="${subdir}">
+      <path>
+        <fileset file="${test.jar}" />
+      </path>
+    </sign-base>
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+  
+  <target name="testMapperNoDest" depends="jar">
+    <sign-base >
+      <flattenmapper />
+      <fileset file="${test.jar}" />
+    </sign-base>
+  </target>
+  
+  <target name="testMapperFileset" depends="jar">
+    <sign-base destDir="${subdir}">
+      <fileset file="${test.jar}" />
+      <flattenmapper />
+    </sign-base>
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+
+  <target name="testMapperPath" depends="jar">
+    <sign-base destDir="${subdir}">
+      <path>
+        <pathelement location="${test.jar}" />
+      </path>
+      <flattenmapper />
+    </sign-base>
+    <assertSigned jar="${subdirtest.jar}"/>
+  </target>
+
+  <target name="testTwoMappers" depends="jar">
+    <sign-base destDir="${subdir}">
+      <fileset file="${test.jar}" />
+      <flattenmapper />
+      <flattenmapper />
+    </sign-base>
+  </target>
+
+  <target name="testNoAlias" depends="jar">
+    <signjar keystore="testkeystore"
+       jar="${test.jar}"
+       storepass="apacheant"/>
+  </target>
+
+  <target name="testNoFiles" >
+    <sign-base />
+  </target>
+
+  <target name="testNoStorePass" depends="jar">
+    <signjar keystore="testkeystore"
+       alias="testonly"
+       jar="${test.jar}"/>
+  </target>
+
+  <target name="testTsaLocalhost" depends="jar">
+    <sign tsaurl="http://localhost:0/" />
+  </target>
+  
+  <target name="testSysProperty" depends="jar">
+    <sign>
+      <sysproperty key="ant.home" value="${ant.home}" />
+    </sign>
+    <assertSigned/>    
+  </target>
+  
+  <target name="testVerifyJar" depends="basic">
+    <verify-base jar="${test.jar}"/>
+  </target>
+
+  <target name="testVerifyJarCertificates" depends="basic">
+    <verify-base jar="${test.jar}" certificates="true" verbose="true"/>
+  </target>
+  
+  <target name="testVerifyJarUnsigned" depends="jar">
+    <verify-base jar="${test.jar}"/>
+  </target>
+  
+  <target name="testVerifyJarNotInKeystore" depends="basic">
+    <verifyjar jar="${test.jar}" certificates="true" verbose="true"/>
+  </target>
+    
+  <target name="testVerifyFileset" depends="basic">
+    <verify-base >
+      <fileset file="${test.jar}" />
+    </verify-base>
+  </target>
+
+  <target name="testVerifyPath" depends="basic">
+    <verify-base >
+      <path>
+        <pathelement location="${test.jar}" />
+      </path>
+    </verify-base>
+  </target>
+
+  <target name="testVerifyNoArgs">
+    <verify-base />
+  </target>
+  
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/skinconfig.dtd b/trunk/src/etc/testcases/taskdefs/skinconfig.dtd
new file mode 100644
index 0000000..ba1b4de
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/skinconfig.dtd
@@ -0,0 +1,19 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<!ELEMENT skinconfig (foo, bar?)>
+<!ELEMENT foo (#PCDATA)>
+<!ELEMENT bar (#PCDATA)>
diff --git a/trunk/src/etc/testcases/taskdefs/sleep.xml b/trunk/src/etc/testcases/taskdefs/sleep.xml
new file mode 100644
index 0000000..e161322
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/sleep.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="sleeptest" default="all" >
+
+    <target name="test1">
+        <sleep />
+    </target>
+
+    <target name="test2">
+        <sleep milliseconds="10"/>
+    </target>
+
+    <target name="test3">
+        <sleep seconds="2"/>
+    </target>
+
+    <target name="test4">
+        <sleep hours="1" minutes="-59" seconds="-58"/>
+    </target>
+
+    <target name="test5">
+        <sleep minutes="-59" seconds="-58"/>
+    </target>
+
+    <target name="test6">
+        <sleep minutes="-59" seconds="-58" failonerror="no"/>
+    </target>
+
+    <target name="all"
+        depends="test1,test2,test3,test4,test5" />
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/style/build.xml b/trunk/src/etc/testcases/taskdefs/style/build.xml
new file mode 100644
index 0000000..1b0d35e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/style/build.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xslt-test" basedir="." default="nothing">
+
+  <property name="out.dir" value="out"/>
+
+
+  <target name="setup">
+  </target>
+
+  <target name="teardown">
+      <delete dir="${out.dir}" failonerror="false" />
+  </target>
+  
+
+  <target name="testStyleIsSet">
+      <xslt in="data.xml" out="${out.dir}/out.xml"/>
+  </target>
+
+  <target name="testTransferParameterSet">
+      <property name="value" value="myvalue"/>
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="printParams.xsl">
+          <param name="set" expression="${value}"/>
+      </xslt>
+  </target>
+
+  <target name="testTransferParameterEmpty">
+      <property name="value" value=""/>
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="printParams.xsl">
+          <param name="empty" expression="${value}"/>
+      </xslt>
+  </target>
+
+  <target name="testTransferParameterUnset">
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="printParams.xsl">
+          <param name="undefined" expression="${value}"/>
+      </xslt>
+  </target>
+
+  <target name="testTransferParameterUnsetWithIf">
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="printParams.xsl">
+          <param name="undefined" expression="${value}" if="value" />
+      </xslt>
+  </target>
+
+  <target name="testDefaultMapper">
+    <property name="value" value="myvalue"/>
+    <xslt style="printParams.xsl" destDir="${out.dir}" basedir=".">
+      <param name="set" expression="${value}"/>
+    </xslt>
+  </target>
+
+  <target name="testCustomMapper">
+    <property name="value" value="myvalue"/>
+    <xslt style="printParams.xsl" destDir="${out.dir}" basedir=".">
+      <param name="set" expression="${value}"/>
+      <mapper type="glob" from="data.*" to="out.*"/>
+    </xslt>
+  </target>
+
+  <target name="testTypedMapper">
+    <property name="value" value="myvalue"/>
+    <xslt style="printParams.xsl" destDir="${out.dir}" basedir=".">
+      <param name="set" expression="${value}"/>
+      <globmapper from="data.*" to="out.*"/>
+    </xslt>
+  </target>
+
+  <target name="testExplicitFileset">
+    <property name="value" value="myvalue"/>
+    <xslt style="printParams.xsl" destDir="${out.dir}"
+          useImplicitFileset="false" basedir="..">
+      <param name="set" expression="${value}"/>
+      <fileset dir="."/>
+    </xslt>
+  </target>
+
+  <target name="testNewerStylesheet">
+      <antcall target="copyXsl">
+        <param name="xsl.value" value="old-value"/>
+      </antcall>
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="tmp.xsl"/>
+
+      <antcall target="copyXsl">
+        <param name="xsl.value" value="new-value"/>
+      </antcall>
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="tmp.xsl"/>
+      <delete file="tmp.xsl"/>
+  </target>
+
+  <target name="testDirectoryHierarchyWithDirMatching">
+    <mkdir dir="${out.dir}/src/level1/"/>
+    <copy file="data.xml" todir="${out.dir}/src/level1/"/>
+    <xslt basedir="${out.dir}/src" destdir="${out.dir}/dest"
+           style="printParams.xsl"/>
+  </target>
+
+  <target name="testDirsWithSpaces">
+    <mkdir dir="${out.dir}/s rc/"/>
+    <copy file="data.xml" todir="${out.dir}/s rc/"/>
+    <xslt basedir="${out.dir}/s rc" destdir="${out.dir}/d est"
+           style="printParams.xsl"/>
+  </target>
+
+  <target name="copyXsl" if="xsl.value">
+      <copy file="testNewerStylesheet.xsl" tofile="tmp.xsl" overwrite="true">
+          <filterchain><expandproperties/></filterchain>
+      </copy>
+  </target>
+
+  <target name="testWithStyleAttrAndResource">
+      <!-- also testing style as resources, with refid -->
+      <file id="xslFile" file="printParams.xsl"/>
+      <xslt in="data.xml" out="${out.dir}/out.xml" style="printParams.xsl">
+        <style refid="xslFile" />
+      </xslt>
+  </target>
+
+  <target name="testWithFileResource">
+      <xslt in="data.xml" out="${out.dir}/out.xml">
+          <style>
+              <file file="printParams.xsl"/>
+          </style>
+          <param name="set" expression="value"/>
+      </xslt>
+  </target>
+
+  <target name="testWithUrlResource">
+      <makeurl file="printParams.xsl" property="printParams.xsl.url"/>
+      <xslt in="data.xml" out="${out.dir}/out.xml">
+          <style>
+              <url url="${printParams.xsl.url}"/>
+          </style>
+          <param name="set" expression="value"/>
+      </xslt>
+  </target>
+
+  <target name="testFilenameAndFiledirAsParam">
+      <mkdir dir="${out.dir}/xml/dir"/>
+      <mkdir dir="${out.dir}/out"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/one.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/two.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/three.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/>
+      <xslt style="printFilename.xsl"
+            destdir="${out.dir}/out"
+            basedir="${out.dir}/xml"
+            includes="**/*.xml"
+            extension=".txt"
+
+            filenameparameter="filename"
+            filedirparameter="filedir"
+      />
+  </target>
+
+  <target name="testFilenameAsParam">
+      <mkdir dir="${out.dir}/xml/dir"/>
+      <mkdir dir="${out.dir}/out"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/one.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/two.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/three.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/>
+      <xslt style="printFilename.xsl"
+            destdir="${out.dir}/out"
+            basedir="${out.dir}/xml"
+            includes="**/*.xml"
+            extension=".txt"
+
+            filenameparameter="filename"
+      />
+  </target>
+
+  <target name="testFilenameAsParamNoSetting">
+      <mkdir dir="${out.dir}/xml/dir"/>
+      <mkdir dir="${out.dir}/out"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/one.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/two.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/three.xml"/>
+      <copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/>
+      <xslt style="printFilename.xsl"
+            destdir="${out.dir}/out"
+            basedir="${out.dir}/xml"
+            includes="**/*.xml"
+            extension=".txt"
+      /> <!-- without 'filenameparameter' to check, that the xsl:param is NOT set -->
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/style/data.xml b/trunk/src/etc/testcases/taskdefs/style/data.xml
new file mode 100644
index 0000000..21e2397
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/style/data.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<data/>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/style/printFilename.xsl b/trunk/src/etc/testcases/taskdefs/style/printFilename.xsl
new file mode 100644
index 0000000..7c79ab7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/style/printFilename.xsl
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+

+<xsl:stylesheet

+  version="1.0"

+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

+

+    <xsl:output indent="no" method="text"/>

+    <xsl:strip-space elements="*"/>

+

+    <xsl:param name="filename">-not-set-</xsl:param>

+    <xsl:param name="filedir">-not-set-</xsl:param>

+

+<!-- use the xsl-parameter -->

+<xsl:template match="/">

+    filename='<xsl:value-of select="$filename"/>'

+    filedir ='<xsl:value-of select="$filedir"/>'

+</xsl:template>

+

+<!-- delete the raw xml data -->

+<xsl:template match="*"/>

+

+</xsl:stylesheet>

diff --git a/trunk/src/etc/testcases/taskdefs/style/printParams.xsl b/trunk/src/etc/testcases/taskdefs/style/printParams.xsl
new file mode 100644
index 0000000..110e49c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/style/printParams.xsl
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:fo="http://www.w3.org/1999/XSL/Format">
+
+<!-- get the xsl-parameter -->
+<xsl:param name="set">set default value</xsl:param>
+<xsl:param name="empty">empty default value</xsl:param>
+<xsl:param name="undefined">undefined default value</xsl:param>
+
+<!-- use the xsl-parameter -->
+<xsl:template match="/">
+set='<xsl:value-of select="$set"/>'
+empty='<xsl:value-of select="$empty"/>'
+undefined='<xsl:value-of select="$undefined"/>'
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/style/testNewerStylesheet.xsl b/trunk/src/etc/testcases/taskdefs/style/testNewerStylesheet.xsl
new file mode 100644
index 0000000..dff8120
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/style/testNewerStylesheet.xsl
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<xsl:stylesheet
+  version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output method="text"/>
+
+<xsl:template match="/">
+${xsl.value}
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/taskdefs/subant.xml b/trunk/src/etc/testcases/taskdefs/subant.xml
new file mode 100644
index 0000000..7db547a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/subant.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="subant-test" basedir="." default="testgenericantfile">
+    <target name="testnodirs" depends="tearDown">
+        <subant genericantfile="subant/genericsubant.xml">
+            <dirset dir="." includes="subant-test*"/>
+        </subant>
+    </target>
+
+    <target name="testgenericantfile">
+        <subant genericantfile="subant/genericsubant.xml">
+            <dirset dir="subant" includes="subant-test*"/>
+        </subant>
+    </target>
+
+    <target name="testantfile">
+        <subant antfile="mysubant.xml">
+            <dirset dir="." includes="subant/subant-test*"/>
+        </subant>
+    </target>
+
+    <target name="multipleTargets">
+        <subant antfile="mysubant.xml">
+            <dirset dir="." includes="subant/subant-test*"/>
+            <target name="one"/>
+            <target name="two"/>
+        </subant>
+    </target>
+
+    <target name="multipleTargetsOneDoesntExist_FOEfalse">
+        <subant antfile="mysubant.xml" failonerror="false">
+            <dirset dir="." includes="subant/subant-test*"/>
+            <target name="one"/>
+            <target name="three"/>
+        </subant>
+    </target>
+
+    <target name="multipleTargetsOneDoesntExist_FOEtrue">
+        <subant antfile="mysubant.xml" failonerror="true">
+            <dirset dir="." includes="subant/subant-test*"/>
+            <target name="one"/>
+            <target name="three"/>
+        </subant>
+    </target>
+
+    <target name="tearDown">
+        <!-- nothing to do -->
+    </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/subant/genericsubant.xml b/trunk/src/etc/testcases/taskdefs/subant/genericsubant.xml
new file mode 100644
index 0000000..c5bfbe2
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/subant/genericsubant.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="genericsubant" basedir=".." default="mysubant">
+    <target name="mysubant">
+        <echo message="${basedir}"/>
+    </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml b/trunk/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml
new file mode 100644
index 0000000..ecc6288
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/subant/subant-test1/mysubant.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="mysubant" basedir="." default="mysubant">
+    <target name="mysubant">
+        <echo message="${basedir}"/>
+    </target>
+    <target name="one">
+        <echo message="test1-one"/>
+    </target>
+    <target name="two">
+        <echo message="test1-two"/>
+    </target>
+    <target name="three">
+        <echo message="test1-three"/>
+    </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml b/trunk/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml
new file mode 100644
index 0000000..5ee875f
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/subant/subant-test2/mysubant.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="subant" basedir=".." default="mysubant">
+    <target name="mysubant">
+        <echo message="${basedir}"/>
+    </target>
+    <target name="one">
+        <echo message="test2-one"/>
+    </target>
+    <target name="two">
+        <echo message="test2-two"/>
+    </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/sync.xml b/trunk/src/etc/testcases/taskdefs/sync.xml
new file mode 100644
index 0000000..c1d10d1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/sync.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="sync-test" default="not-me">
+  <property name="scratch" location="synctest"/>
+
+  <target name="not-me">
+    <fail>This file must be used from a test case</fail>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="${scratch}"/>
+  </target>
+
+  <target name="setup">
+    <property name="src" location="${scratch}/source"/>
+    <property name="dest" location="${scratch}/target"/>
+    <mkdir dir="${src}"/>
+    <mkdir dir="${dest}"/>
+  </target>
+
+  <target name="simplecopy" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}"/>
+    </sync>
+  </target>
+
+  <target name="copyandremove" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}"/>
+    </sync>
+  </target>
+
+  <target name="copyandremove-with-filelist" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <sync todir="${dest}">
+      <filelist dir="${src}">
+        <file name="a/b/c/d"/>
+        <file name="not-there"/>
+      </filelist>
+    </sync>
+  </target>
+
+  <target name="copyandremove-with-zipfileset" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <zip destfile="${src}/test.zip">
+      <fileset dir="${src}" excludes="*.zip"/>
+    </zip>
+    <sync todir="${dest}">
+      <zipfileset src="${src}/test.zip"/>
+    </sync>
+  </target>
+
+  <target name="copyandremove-emptypreserve" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}"/>
+      <preserveintarget/>
+    </sync>
+  </target>
+
+  <target name="emptycopy" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}" excludes="**/d"/>
+    </sync>
+  </target>
+
+  <target name="emptydircopy" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <sync todir="${dest}"
+         includeemptydirs="true">
+      <fileset dir="${src}" excludes="**/d"/>
+    </sync>
+  </target>
+
+  <target name="emptydircopyandremove" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e/f"/>
+    <sync todir="${dest}"
+         includeemptydirs="true">
+      <fileset dir="${src}" excludes="**/d"/>
+    </sync>
+  </target>
+
+  <target name="copynoremove" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}"/>
+      <preserveintarget>
+        <include name="e/f"/>
+      </preserveintarget>
+    </sync>
+  </target>
+
+  <target name="copynoremove-selectors" depends="setup">
+    <mkdir dir="${src}/a/b/c"/>
+    <touch file="${src}/a/b/c/d"/>
+    <mkdir dir="${dest}/e"/>
+    <touch file="${dest}/e/f"/>
+    <sync todir="${dest}">
+      <fileset dir="${src}"/>
+      <preserveintarget>
+        <filename name="e/f"/>
+      </preserveintarget>
+    </sync>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/tar.xml b/trunk/src/etc/testcases/taskdefs/tar.xml
new file mode 100644
index 0000000..dc92a75
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/tar.xml
@@ -0,0 +1,202 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="tar-test" basedir="." default="test1">
+
+  <target name="test1">
+    <tar/>
+  </target>
+
+  <target name="test2">
+    <tar tarfile=""/>
+  </target>
+
+  <target name="test3">
+    <tar basedir=""/>
+  </target>
+
+  <target name="test4">
+    <touch file="test4.tar"/>
+    <tar destfile="test4.tar"
+         basedir="."/>
+  </target>
+
+  <target name="test5">
+    <mkdir dir="test5dir"/>
+    <tar destfile="test5.tar"
+         basedir="."
+         includes="test5dir"/>
+  </target>
+
+  <target name="test6">
+    <tar destfile="blah" longfile="Foo"/>
+  </target>
+
+  <target name="test7">
+    <mkdir dir="test7dir"/>
+    <tar destfile="test7.tar">
+      <tarfileset dir="." prefix="test7-prefix/">
+        <include name="test7dir"/>
+      </tarfileset>
+      <tarfileset dir="." prefix="">
+        <include name="test7dir"/>
+      </tarfileset>
+    </tar>
+    <untar src="test7.tar" dest="."/>
+  </target>
+
+  <target name="test7UsingPlainFileSet">
+    <mkdir dir="test7dir"/>
+    <tar destfile="test7.tar">
+      <tarfileset dir="." prefix="test7-prefix/">
+        <include name="test7dir"/>
+      </tarfileset>
+      <fileset dir=".">
+        <include name="test7dir"/>
+      </fileset>
+    </tar>
+    <untar src="test7.tar" dest="."/>
+  </target>
+
+  <target name="test7UsingFileList">
+    <mkdir dir="test7dir"/>
+    <tar destfile="test7.tar">
+      <tarfileset dir="." prefix="test7-prefix/">
+        <include name="test7dir"/>
+      </tarfileset>
+      <filelist dir=".">
+        <file name="test7dir"/>
+      </filelist>
+    </tar>
+    <untar src="test7.tar" dest="."/>
+  </target>
+
+  <target name="test8">
+    <tar destfile="test8.tar">
+      <tarfileset dir="." fullpath="/test8.xml">
+        <include name="tar.xml"/>
+      </tarfileset>
+    </tar>
+    <untar src="test8.tar" dest="."/>
+  </target>
+
+  <target name="test8UsingZipFileset">
+    <tar destfile="test8.tar">
+      <zipfileset dir="." fullpath="/test8.xml">
+        <include name="tar.xml"/>
+      </zipfileset>
+    </tar>
+    <untar src="test8.tar" dest="."/>
+  </target>
+
+  <target name="test8UsingZipFilesetSrc">
+    <zip destfile="test7.tar" basedir="." includes="tar.xml"/>
+    <tar destfile="test8.tar">
+      <zipfileset src="test7.tar" fullpath="/test8.xml">
+        <include name="tar.xml"/>
+      </zipfileset>
+    </tar>
+    <untar src="test8.tar" dest="."/>
+  </target>
+
+  <target name="test8UsingTarFilesetSrc">
+    <tar destfile="test7.tar" basedir="." includes="tar.xml"/>
+    <tar destfile="test8.tar">
+      <tarfileset src="test7.tar" fullpath="/test8.xml">
+        <include name="tar.xml"/>
+      </tarfileset>
+    </tar>
+    <untar src="test8.tar" dest="."/>
+  </target>
+
+  <target name="test8UsingZipEntry">
+    <zip destfile="test7.tar">
+      <zipfileset dir="." includes="tar.xml" fullpath="/test8.xml"/>
+    </zip>
+    <tar destfile="test8.tar">
+      <zipentry archive="test7.tar" name="/test8.xml"/>
+    </tar>
+    <untar src="test8.tar" dest="."/>
+  </target>
+
+  <target name="test9">
+    <tar destfile="blah" compression="Foo"/>
+  </target>
+
+  <target name="test10">
+    <tar destfile="test10.tar.gz" compression="gzip">
+      <tarfileset dir="." fullpath="/test10.xml">
+        <include name="tar.xml"/>
+      </tarfileset>
+    </tar>
+    <untar src="test10.tar.gz" dest="." compression="gzip"/>
+  </target>
+
+  <target name="test11">
+    <tar destfile="test11.tar.bz2" compression="bzip2">
+      <tarfileset dir="." fullpath="/test11.xml">
+        <include name="tar.xml"/>
+      </tarfileset>
+    </tar>
+    <untar src="test11.tar.bz2" dest="." compression="bzip2"/>
+  </target>
+
+  <target name="cleanup"> 
+    <delete file="test4.tar"/>
+    <delete file="test5.tar"/>
+    <delete file="asf-logo.gif.tar"/>
+    <delete dir="testout"/>
+    <delete dir="test5dir"/>
+    <delete dir="test7dir"/>
+    <delete dir="test7-prefix"/>
+    <delete file="test7.tar"/>
+    <delete file="test8.tar"/>
+    <delete file="test8.xml"/>
+    <delete file="test10.tar.gz"/>
+    <delete file="test10.xml"/>
+    <delete file="test11.tar.bz2"/>
+    <delete file="test11.xml"/>
+    <delete file="asf-logo.gif.tar.gz"/>
+    <delete file="asf-logo.gif.tar.bz2"/>
+  </target>
+
+  <target name="feather">
+    <tar destfile="asf-logo.gif.tar"
+         basedir=".."
+         includes="asf-logo.gif" />
+    <tar destfile="asf-logo.gif.tar.gz"
+         basedir=".."
+         includes="asf-logo.gif" 
+         compression="gzip"/>
+    <tar destfile="asf-logo.gif.tar.bz2"
+         basedir=".."
+         includes="asf-logo.gif"
+         compression="bzip2" />
+  </target>
+
+  <target name="testGZipResource">
+    <mkdir dir="testout"/>
+    <tar destfile="testout/test.tar">
+      <gzipresource>
+        <file file="expected/asf-logo.gif.gz"/>
+      </gzipresource>
+    </tar>
+    <untar src="testout/test.tar" dest="testout"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/taskdef.xml b/trunk/src/etc/testcases/taskdefs/taskdef.xml
new file mode 100644
index 0000000..4b0658e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/taskdef.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <taskdef name="global"
+           classname="org.example.tasks.TaskdefTestContainerTask">
+    <classpath refid="testclasses" />
+  </taskdef>
+
+  <target name="test1">
+    <taskdef/>
+  </target>
+
+  <target name="test2">
+    <taskdef name=""/>
+  </target>
+
+  <target name="test3">
+    <taskdef classname=""/>
+  </target>
+
+  <target name="test4">
+    <taskdef name="" classname="oops"/>
+  </target>
+
+  <target name="test5">
+    <taskdef name="test" classname="org.apache.tools.ant.Project" />
+  </target>
+
+  <target name="test5a">
+    <taskdef name="test" classname="org.apache.tools.ant.taskdefs.Copy" />
+  </target>
+
+  <target name="test6">
+    <taskdef name="test6"
+             classname="org.example.tasks.TaskdefTestSimpleTask">
+      <classpath refid="testclasses" />
+    </taskdef>
+    <test6>
+      <echo message="worked" />
+    </test6>
+  </target>
+
+  <target name="test7">
+    <taskdef name="test7"
+             classname="org.example.tasks.TaskdefTestContainerTask">
+      <classpath refid="testclasses" />
+    </taskdef>
+    <test7>
+      <echo message="worked" />
+    </test7>
+  </target>
+
+  <target name="testGlobal">
+    <global>
+      <echo message="worked" />
+    </global>
+  </target>
+
+  <target name="testOverride">
+    <taskdef name="copy" classname="org.apache.tools.ant.taskdefs.Echo" />
+    <copy>In target</copy>
+    <sequential>
+      <copy>In TaskContainer</copy>
+    </sequential>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/template.xml b/trunk/src/etc/testcases/taskdefs/template.xml
new file mode 100644
index 0000000..9f351c7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/template.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
diff --git a/trunk/src/etc/testcases/taskdefs/test.antlib.xml b/trunk/src/etc/testcases/taskdefs/test.antlib.xml
new file mode 100644
index 0000000..37ff7f8
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/test.antlib.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib>
+  <typedef 
+    name="mytask" onerror="ignore"
+    classname="org.apache.tools.ant.taskdefs.AntlibTest$MyTask"/>
+</antlib>
diff --git a/trunk/src/etc/testcases/taskdefs/test2.antlib.xml b/trunk/src/etc/testcases/taskdefs/test2.antlib.xml
new file mode 100644
index 0000000..9a2509e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/test2.antlib.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib>
+  <typedef 
+    name="mytask2" onerror="ignore"
+    classname="org.apache.tools.ant.taskdefs.AntlibTest$MyTask2"/>
+</antlib>
diff --git a/trunk/src/etc/testcases/taskdefs/toplevelant.xml b/trunk/src/etc/testcases/taskdefs/toplevelant.xml
new file mode 100644
index 0000000..e6b466a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/toplevelant.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="ant-test" basedir="." default="bar">
+  <ant antfile="toplevelant.xml" target="foo"/>
+
+  <target name="foo"/>
+  <target name="bar"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/toplevelantcall.xml b/trunk/src/etc/testcases/taskdefs/toplevelantcall.xml
new file mode 100644
index 0000000..2ccabe7
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/toplevelantcall.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="ant-test" basedir="." default="bar">
+  <antcall target="foo"/>
+
+  <target name="foo"/>
+  <target name="bar"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/toplevelsubant.xml b/trunk/src/etc/testcases/taskdefs/toplevelsubant.xml
new file mode 100644
index 0000000..b7a3a35
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/toplevelsubant.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="ant-test" basedir="." default="bar">
+  <subant target="foo">
+    <fileset dir="." includes="toplevelsubant.xml"/>
+  </subant>
+
+  <target name="foo"/>
+  <target name="bar"/>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/touch.xml b/trunk/src/etc/testcases/taskdefs/touch.xml
new file mode 100644
index 0000000..3b426d9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/touch.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="cleanup" basedir=".">
+
+  <property name="mappermillis" value="1072224000000" />
+  
+  <selector id="map.selector">
+    <date millis="${mappermillis}" />
+  </selector>
+
+  <target name="cleanup">
+    <delete>
+      <fileset dir="." includes="touchtest*" />
+    </delete>
+  </target>
+
+  <target name="noSeconds">
+    <touch file="touchtest" datetime="06/24/2003 2:20 pm"/>
+  </target>
+
+  <target name="seconds">
+    <touch file="touchtest" datetime="06/24/2003 2:20:12 pm"/>
+  </target>
+
+  <target name="testNow">
+    <touch file="touchtest" />
+  </target>
+  
+  <target name="testMillis">
+    <!-- this one is about 21 years after the epoch -->
+    <!-- less than 20 years after the epoch, test does not pass on my Win2K/FAT -->
+    <!-- Antoine February 8, 2004 -->
+    <!-- see http://developer.java.sun.com/developer/bugParade/bugs/4177432.html -->
+    <!-- and http://developer.java.sun.com/developer/bugParade/bugs/4697792.html -->
+    <!-- not sure why -->
+    <touch file="touchtest" millis="662256000000" />
+  </target>
+  
+  <target name="test2000">
+    <!-- this number of milliseconds is 30 * 365 * 24 * 3600 * 1000 -->
+    <!-- so the corresponding time is at the end of 1999 -->
+    <touch file="touchtest" millis="946080000000" />
+  </target>
+  
+  <target name="testFilelist">
+    <touch millis="662256000000" >
+      <filelist dir="." files="touchtest"/>
+    </touch>
+  </target>
+
+  <target name="testFileset" depends="testNow">
+    <touch millis="946080000000" >
+      <fileset dir="." includes="touchtest"/>
+    </touch>
+  </target>
+
+  <target name="testResourceCollection">
+    <touch millis="1662256000000">
+      <file file="touchtest"/>
+    </touch>
+  </target>
+
+  <target name="testMappedFileset">
+    <touch file="touchtest" millis="${mappermillis}" />
+    <touch>
+      <fileset file="touchtest" />
+      <compositemapper>
+        <globmapper from="*" to="*foo" />
+        <globmapper from="*" to="*bar" />
+      </compositemapper>
+    </touch>
+
+    <fileset id="touchtest" file="touchtest">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <fileset id="touchtestfoo" file="touchtestfoo">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <fileset id="touchtestbar" file="touchtestbar">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <pathconvert property="touchtest" pathsep=" "
+                 refid="touchtest" setonempty="false" />
+
+    <pathconvert property="touchtestfoo" pathsep=" "
+                 refid="touchtestfoo" setonempty="false" />
+
+    <pathconvert property="touchtestbar" pathsep=" "
+                 refid="touchtestbar" setonempty="false" />
+
+    <fail>
+      <condition>
+        <not>
+          <and>
+            <isset property="touchtest" />
+            <isset property="touchtestfoo" />
+            <isset property="touchtestbar" />
+          </and>
+        </not>
+      </condition>
+    </fail>
+
+  </target>
+
+  <target name="testExplicitMappedFileset">
+    <touch file="touchtest" millis="${mappermillis}" />
+    <touch>
+      <fileset file="touchtest" />
+      <mapper>
+        <compositemapper>
+          <globmapper from="*" to="*foo" />
+          <globmapper from="*" to="*bar" />
+        </compositemapper>
+      </mapper>
+    </touch>
+
+    <fileset id="touchtest" file="touchtest">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <fileset id="touchtestfoo" file="touchtestfoo">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <fileset id="touchtestbar" file="touchtestbar">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <pathconvert property="touchtest" pathsep=" "
+                 refid="touchtest" setonempty="false" />
+
+    <pathconvert property="touchtestfoo" pathsep=" "
+                 refid="touchtestfoo" setonempty="false" />
+
+    <pathconvert property="touchtestbar" pathsep=" "
+                 refid="touchtestbar" setonempty="false" />
+
+    <fail>
+      <condition>
+        <not>
+          <and>
+            <isset property="touchtest" />
+            <isset property="touchtestfoo" />
+            <isset property="touchtestbar" />
+          </and>
+        </not>
+      </condition>
+    </fail>
+
+  </target>
+
+  <target name="testMappedFilelist">
+    <touch millis="${mappermillis}">
+      <filelist dir="." files="idonotexist" />
+      <mergemapper to="touchtest" />
+    </touch>
+
+    <fileset id="touchtest" file="touchtest">
+      <selector refid="map.selector" />
+    </fileset>
+
+    <pathconvert property="touchtest" pathsep=" "
+                 refid="touchtest" setonempty="false" />
+
+    <fail>
+      <condition>
+        <not>
+          <isset property="touchtest" />
+        </not>
+      </condition>
+    </fail>
+
+  </target>
+
+  <target name="testGoodPattern">
+    <touch file="touchtest" datetime="06242003142012GMTfoo" pattern="MMddyyyyHHmmssz'foo'" />
+
+    <fileset id="touchtest" file="touchtest">
+      <date millis="1056464412000" />
+    </fileset>
+
+    <pathconvert property="touchtest" pathsep=" "
+                 refid="touchtest" setonempty="false" />
+
+    <fail>
+      <condition>
+        <not>
+          <isset property="touchtest" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testBadPattern">
+    <touch file="touchtest" datetime="06242003142012GMTfoo" pattern="MMddyyyyHHmmssz'bar'" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/typeadapter.xml b/trunk/src/etc/testcases/taskdefs/typeadapter.xml
new file mode 100644
index 0000000..c2aa70e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/typeadapter.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="test" basedir="." default="invalid">
+  <property name="testcases.dir" location="../../../../build/testcases"/>
+  <path id="testclasses">
+    <pathelement location="${testcases.dir}" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="taskadapter">
+    <typedef name="myexec"
+             classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyExec"
+             classpathref="testclasses"
+             adapter="org.apache.tools.ant.TaskAdapter"/>
+    <myexec/>
+  </target>
+
+  <target name="runadapter">
+    <typedef
+      name="myrunnable"
+      classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyRunnable"
+      classpathref="testclasses"
+      adapter="org.apache.tools.ant.taskdefs.TypeAdapterTest$RunnableAdapter"/>
+    <myrunnable/>
+  </target>
+
+  <target name="runadaptererror">
+    <typedef
+      name="myrunnable"
+      classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyExec"
+      classpathref="testclasses"
+      adapter="org.apache.tools.ant.taskdefs.TypeAdapterTest$RunnableAdapter"/>
+    <myrunnable/>
+  </target>
+
+  <target name="delay">
+    <typedef
+      name="mytask"
+      classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyTask"
+      classpathref="testclasses"
+      onerror="ignore"/>
+    <mytask/>
+  </target>
+
+  <target name="onerror.report">
+    <typedef
+      name="mytask"
+      classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyTaskNotPresent"
+      classpathref="testclasses"
+      onerror="report"/>
+  </target>
+
+  <target name="onerror.ignore">
+    <typedef
+      name="mytask"
+      classname="org.apache.tools.ant.taskdefs.TypeAdapterTest$MyTaskNotPresent"
+      classpathref="testclasses"
+      onerror="ignore"/>
+  </target>
+
+
+</project>
+
diff --git a/trunk/src/etc/testcases/taskdefs/typedef.xml b/trunk/src/etc/testcases/taskdefs/typedef.xml
new file mode 100644
index 0000000..1c7922b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/typedef.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="test" basedir="." default="invalid">
+
+  <target name="invalid">
+    <fail>This file should only be run via a testcase</fail>
+  </target>
+
+  <target name="empty">
+    <typedef />
+  </target>
+
+  <target name="noClassname">
+    <typedef name="dummy" />
+  </target>
+
+  <target name="noName">
+    <typedef classname="org.example.types.TypedefTestType">
+      <classpath refid="testclasses" />
+    </typedef>
+  </target>
+
+  <target name="classNotFound">
+    <typedef name="" classname="oops"/>
+  </target>
+
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <typedef name="global"
+           classname="org.example.types.TypedefTestType">
+    <classpath refid="testclasses" />
+  </typedef>
+
+  <target name="testGlobal">
+    <global id="global" />
+  </target>
+
+  <target name="testLocal">
+    <typedef name="localtype"
+             classname="org.example.types.TypedefTestType">
+      <classpath refid="testclasses" />
+    </typedef>
+    <localtype id="local" />
+  </target>
+
+  <target name="double-notpresent">
+    <typedef name="mytask" classname="notpresent" onerror="ignore"/>
+    <typedef name="mytask" classname="notpresent" onerror="ignore"/>
+    <typedef name="mytask" classname="org.apache.tools.ant.taskdefs.Echo"
+             onerror="ignore"/>
+    <mytask>hi</mytask>
+  </target>
+  
+  <target name="noresourcefailall">
+  	<typedef resource="somenotpresentfile.properties" onerror="failall"/>
+  </target>
+  
+  <target name="noresourcefail">
+  	<typedef resource="somenotpresentfile.properties" onerror="fail"/>
+  </target>
+  
+  <target name="noresourcenotfail">
+  	<typedef resource="somenotpresentfile.properties" />
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/untar.xml b/trunk/src/etc/testcases/taskdefs/untar.xml
new file mode 100644
index 0000000..d546f34
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/untar.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project basedir="." default="cleanup">
+
+  <target name="cleanup">
+    <delete file="asf-logo.gif" />
+    <delete file="untartest.tar" />
+    <delete dir="untartestin"/>
+    <delete dir="untartestout"/>
+  </target>
+
+  <target name="testTarTask">
+    <ant antfile="tar.xml" target="feather" />
+    <untar src="asf-logo.gif.tar" dest="." />
+    <ant antfile="tar.xml" target="cleanup" />
+  </target>
+
+  <target name="testGzipTarTask">
+    <ant antfile="tar.xml" target="feather" />
+    <untar src="asf-logo.gif.tar.gz" dest="." compression="gzip" />
+    <ant antfile="tar.xml" target="cleanup" />
+  </target>
+
+  <target name="testBzip2TarTask">
+    <ant antfile="tar.xml" target="feather" />
+    <untar src="asf-logo.gif.tar.bz2" dest="." compression="bzip2"/>
+    <ant antfile="tar.xml" target="cleanup" />
+  </target>
+
+  <target name="realTest">
+    <untar src="expected/asf-logo.gif.tar" dest="." />
+  </target>
+
+  <target name="realGzipTest">
+    <untar src="expected/asf-logo.gif.tar.gz" dest="." compression="gzip" />
+  </target>
+
+  <target name="realBzip2Test">
+    <untar src="expected/asf-logo.gif.tar.bz2" dest="." compression="bzip2"/>
+  </target>
+
+
+  <target name="srcDirTest">
+    <untar src="." dest="." />
+  </target>
+
+  <target name="encoding">
+    <untar src="expected/asf-logo.gif.tar" dest="." encoding="foo"/>
+  </target>
+
+  <target name="resourceCollection">
+    <mkdir dir="untartestout"/>
+    <zip destfile="untartestout/test.zip">
+      <fileset dir="expected">
+        <include name="asf-logo.gif.tar"/>
+      </fileset>
+    </zip>
+    <untar dest=".">
+      <zipfileset src="untartestout/test.zip">
+        <include name="*.tar"/>
+      </zipfileset>
+    </untar>
+  </target>
+
+  <target name="prepareTestTar">
+    <mkdir dir="untartestin/1"/>
+    <mkdir dir="untartestin/2"/>
+    <touch file="untartestin/1/foo"/>
+    <touch file="untartestin/2/bar"/>
+    <copy todir="untartestin/2">
+      <fileset dir="expected" includes="*md5*"/>
+    </copy>
+    <tar destfile="untartest.tar" basedir="untartestin"/>
+  </target>
+
+  <target name="testDocumentationClaimsOnCopy" depends="prepareTestTar">
+    <copy todir="untartestout" preservelastmodified="true"> 
+      <tarfileset src="untartest.tar">
+        <patternset>
+          <include name="2/"/>
+        </patternset>
+      </tarfileset>
+    </copy>
+  </target>
+  
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/unzip.xml b/trunk/src/etc/testcases/taskdefs/unzip.xml
new file mode 100644
index 0000000..414afce
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/unzip.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="xxx-test" basedir="." default="test1">
+
+  <target name="cleanup">
+    <delete file="asf-logo.gif" />
+    <delete file="unziptest.zip"/>
+    <delete dir="unziptestin"/>
+    <delete dir="unziptestout"/>
+  </target>
+
+  <target name="test1">
+    <unzip/>
+  </target>
+
+  <target name="test2">
+    <unzip src=""/>
+  </target>
+
+  <target name="test3">
+    <unzip dest=""/>
+  </target>
+
+  <target name="testZipTask">
+    <ant antfile="zip.xml" target="feather" />
+    <unzip src="asf-logo.gif.zip" dest="." />
+    <ant antfile="zip.xml" target="cleanup" />
+  </target>
+
+  <target name="testUncompressedZipTask">
+    <ant antfile="zip.xml" target="uncompressed-feather" />
+    <unzip src="asf-logo.gif.zip" dest="." />
+    <ant antfile="zip.xml" target="cleanup" />
+  </target>
+
+  <target name="realTest">
+    <unzip src="expected/asf-logo.gif.zip" dest="." />
+  </target>
+
+  <target name="prepareTestZip">
+    <mkdir dir="unziptestin/1"/>
+    <mkdir dir="unziptestin/2"/>
+    <touch file="unziptestin/1/foo"/>
+    <touch file="unziptestin/2/bar"/>
+    <zip destfile="unziptest.zip" basedir="unziptestin"/>
+  </target>
+
+  <target name="testPatternSetExcludeOnly" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <exclude name="1/**"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <target name="testPatternSetIncludeOnly" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="2/**"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <target name="testPatternSetIncludeAndExclude" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="2/**"/>
+        <exclude name="2/**"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <target name="testTwoPatternSets" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="2/**"/>
+      </patternset>
+      <patternset>
+        <include name="3/**"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <target name="testTwoPatternSetsWithExcludes" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="2/**"/>
+      </patternset>
+      <patternset>
+        <exclude name="1/**"/>
+        <exclude name="2/**"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <target name="selfExtractingArchive">
+    <mkdir dir="unziptestout"/>
+    <unzip dest="unziptestout" src="zip/test.exe"/>
+  </target>
+
+  <!-- Bugzilla Report 20969 -->
+  <target name="testPatternSetSlashOnly" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="2/"/>
+      </patternset>
+    </unzip>
+  </target>
+
+  <!-- Bugzilla Report 10504 -->
+  <target name="encodingTest">
+    <mkdir dir="unziptestin"/>
+    <touch file="unziptestin/foo"/>
+    <zip zipfile="unziptest.zip" basedir="unziptestin" encoding="UnicodeBig"/>
+    <mkdir dir="unziptestout"/>
+    <unzip src="unziptest.zip" dest="unziptestout" encoding="UnicodeBig"/>
+  </target>
+
+  <!-- Bugzilla Report 21996 -->
+  <target name="testFlattenMapper" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="1/**"/>
+      </patternset>
+      <mapper type="flatten"/>
+    </unzip>
+  </target>
+
+  <!-- Bugzilla Report 21996 -->
+  <target name="testGlobMapper" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="1/**"/>
+      </patternset>
+      <mapper type="glob" from="*" to="*.txt"/>
+    </unzip>
+  </target>
+
+  <target name="testTwoMappers" depends="prepareTestZip">
+    <unzip dest="unziptestout" src="unziptest.zip">
+      <patternset>
+        <include name="1/**"/>
+      </patternset>
+      <mapper type="glob" from="*" to="*.txt"/>
+      <mapper type="flatten"/>      
+    </unzip>
+  </target>
+
+  <target name="testResourceCollection">
+    <unzip dest="unziptestout">
+      <patternset>
+        <include name="junit/**"/>
+      </patternset>
+      <restrict>
+        <path path="${java.class.path}"/>
+        <type type="file" xmlns="antlib:org.apache.tools.ant.types.resources.selectors"/>
+      </restrict>
+    </unzip>
+  </target>
+
+  <target name="testDocumentationClaimsOnCopy" depends="prepareTestZip">
+    <copy todir="unziptestout" preservelastmodified="true"> 
+      <zipfileset src="unziptest.zip">
+        <patternset>
+          <include name="2/"/>
+        </patternset>
+      </zipfileset>
+    </copy>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/uptodate.xml b/trunk/src/etc/testcases/taskdefs/uptodate.xml
new file mode 100755
index 0000000..6e6ce86
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/uptodate.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project basedir=".">
+
+  <target name="setUp">
+    <touch file="source"/>
+    <sleep seconds="3"/>
+    <touch file="target"/>
+  </target>
+
+  <target name="tearDown">
+    <delete file="source"/>
+    <delete file="target"/>
+  </target>
+
+  <target name="testFilesetUpToDate" depends="setUp">
+    <uptodate property="foo" targetfile="target">
+      <srcfiles dir="." includes="source"/>
+    </uptodate>
+  </target>
+
+  <target name="testFilesetOutOfDate" depends="setUp">
+    <uptodate property="foo" targetfile="source">
+      <srcfiles dir="." includes="target"/>
+    </uptodate>
+  </target>
+
+  <target name="testRCUpToDate" depends="setUp">
+    <uptodate property="foo" targetfile="target">
+      <srcresources>
+        <fileset dir="." includes="source"/>
+      </srcresources>
+    </uptodate>
+  </target>
+
+  <target name="testRCOutOfDate" depends="setUp">
+    <uptodate property="foo" targetfile="source">
+      <srcresources>
+        <fileset dir="." includes="target"/>
+      </srcresources>
+    </uptodate>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/war.xml b/trunk/src/etc/testcases/taskdefs/war.xml
new file mode 100644
index 0000000..d8bca49
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/war.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="war-test" basedir="." default="help">
+  <property name="working.dir" value="working"/>
+
+  <target name="help">
+    <echo message="Test file for the war task"/>
+  </target>
+
+  <target name="setup">
+    <mkdir dir="${working.dir}"/>
+  </target>
+  
+  <target name="testlibrefs" depends="setup">
+    <fileset id="test" dir="." includes="war.xml"/>
+    <war webxml="war.xml" destfile="${working.dir}/test.war">
+      <lib refid="test"/>
+    </war>
+    <unzip src="${working.dir}/test.war" dest="${working.dir}"/>
+  </target>
+  
+  <target name="clean">
+    <delete dir="${working.dir}"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/whichresource.xml b/trunk/src/etc/testcases/taskdefs/whichresource.xml
new file mode 100644
index 0000000..352e9c0
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/whichresource.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="fail">
+  <target name="fail">
+    <fail>Run via testcases only</fail>
+  </target>
+
+  <target name="testClassname">
+    <whichresource class="org.apache.tools.ant.Main"
+      property="antmain"/>
+  </target>
+
+  <target name="testResourcename">
+    <whichresource resource="org/apache/tools/ant/taskdefs/defaults.properties"
+      property="defaults"/>
+  </target>
+
+  <target name="testResourcenameWithLeadingSlash">
+    <whichresource resource="/org/apache/tools/ant/taskdefs/defaults.properties"
+      property="defaults"/>
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlns.xml b/trunk/src/etc/testcases/taskdefs/xmlns.xml
new file mode 100644
index 0000000..e699166
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlns.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" xmlns:other="this is the other uri"
+         other:attr="this should be ignored by ant">
+
+  <property name="testcases.dir" location="../../../../build/testcases"/>
+
+  <path id="testclasses">
+    <pathelement location="${testcases.dir}" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="xmlns" xmlns:test="this.is.another.test.uri">
+    <typedef classname="org.apache.tools.ant.taskdefs.XmlnsTest$MyTask"
+             classpathref="testclasses"
+             name="mytask"
+             uri="this.is.another.test.uri" />
+    <test:mytask/>
+  </target>
+
+  <target name="other" other:a="this is another attribute">
+    <echo other:g="abc" message="a message"/>
+  </target>
+
+  <target name="ns.attributes">
+    <taskdef name="my.echo" classname="org.apache.tools.ant.taskdefs.Echo"
+             uri="x-uri"/>
+    <x:my.echo x:message="hello world" xmlns:x="x-uri"/>
+  </target>
+
+  <target name="xmlns.file" xmlns:test="this.is.a.test.uri">
+    <typedef file="test.antlib.xml"
+             classpathref="testclasses"
+             uri="this.is.a.test.uri" />
+    <test:mytask/>
+  </target>
+
+  <target name="core">
+    <typedef file="test.antlib.xml"
+             classpathref="testclasses"
+             uri="antlib:org.apache.tools.ant" />
+    <mytask/>
+  </target>
+
+  <target name="excluded">
+    <typedef file="test.antlib.xml"
+             classpathref="testclasses"
+             uri="ant:notallowed" />
+  </target>
+
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty.xml
new file mode 100644
index 0000000..a19eb6c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="test" basedir=".">
+
+  <target name="test">
+    <xmlproperty file="xmlproperty_data.xml"/>
+  </target>
+
+  <target name="testdtd">
+    <xmlproperty file="xmlproperty_withdtd.xml"/>
+  </target>
+
+  <target name="testResource">
+    <loadfile srcfile="xmlproperty_data.xml" property="prop"/>
+    <xmlproperty>
+      <string value="${prop}"/>
+    </xmlproperty>
+  </target>
+
+  <target name="testneedscat">
+    <xmlproperty file="xmlproperty_needscat.xml">
+      <xmlcatalog>
+        <dtd publicId="-//FOO//DTD Skin Configuration V0.1//EN"
+             location="skinconfig.dtd"/>
+      </xmlcatalog>
+    </xmlproperty>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-input1.properties
new file mode 100644
index 0000000..d60cbab
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-input1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+properties.root=foo,bar
+properties.a.b.c=d
+properties.a.b=e
+properties.foo.bar=quux,quux1
+properties.foo.quux=bar
+properties.tag.value=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-original.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-original.properties
new file mode 100644
index 0000000..ce05e18
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-original.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root-tag.myattr=true
+root-tag.inner-tag=Text
+root-tag.inner-tag.someattr=val
+root-tag.a2.a3.a4=false
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-override.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-override.properties
new file mode 100644
index 0000000..33f8611
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-collapse-override.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Match value hardwired in code, NOT in the input...
+override.property.test=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-input1.properties
new file mode 100644
index 0000000..153ac76
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-input1.properties
@@ -0,0 +1,8 @@
+properties.root=foo,bar
+properties.a.b(c)=d
+properties.a.b=e
+properties.foo(bar)=quux
+properties.foo.bar=quux1
+properties.foo.quux=bar
+properties.tag(value)=foo
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-original.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-original.properties
new file mode 100644
index 0000000..47e0c2d
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-nocollapse-original.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root-tag(myattr)=true
+root-tag.inner-tag=Text
+root-tag.inner-tag(someattr)=val
+root-tag.a2.a3.a4=false
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-include.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-include.properties
new file mode 100644
index 0000000..d60cbab
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-include.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+properties.root=foo,bar
+properties.a.b.c=d
+properties.a.b=e
+properties.foo.bar=quux,quux1
+properties.foo.quux=bar
+properties.tag.value=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-input1.properties
new file mode 100644
index 0000000..46b807b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-input1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+properties.root=foo,bar
+properties.a.b.c=d
+properties.a.b=e
+properties.foo.bar=quux,quux1
+properties.foo.quux=bar
+properties.tag=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-override.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-override.properties
new file mode 100644
index 0000000..33f8611
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/keeproot-semantic-override.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Match value hardwired in code, NOT in the input...
+override.property.test=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-input1.properties
new file mode 100644
index 0000000..7cfd29e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-input1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root=foo,bar
+a.b.c=d
+a.b=e
+foo.bar=quux,quux1
+foo.quux=bar
+tag.value=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-original.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-original.properties
new file mode 100644
index 0000000..5842c38
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-collapse-original.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+inner-tag=Text
+inner-tag.someattr=val
+a2.a3.a4=false
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-input1.properties
new file mode 100644
index 0000000..3eca368
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-input1.properties
@@ -0,0 +1,7 @@
+root=foo,bar
+a.b(c)=d
+a.b=e
+foo(bar)=quux
+foo.bar=quux1
+foo.quux=bar
+tag(value)=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-multi.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-multi.properties
new file mode 100644
index 0000000..9ef90ef
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-multi.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+foo.bar=1,2,3,4
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-original.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-original.properties
new file mode 100644
index 0000000..550f213
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-nocollapse-original.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+inner-tag=Text
+inner-tag(someattr)=val
+a2.a3.a4=false
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-include-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-include-input1.properties
new file mode 100644
index 0000000..7cfd29e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-include-input1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root=foo,bar
+a.b.c=d
+a.b=e
+foo.bar=quux,quux1
+foo.quux=bar
+tag.value=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-input1.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-input1.properties
new file mode 100644
index 0000000..5dfcfb5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-input1.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+root=foo,bar
+a.b.c=d
+a.b=e
+foo.bar=quux,quux1
+foo.quux=bar
+tag=foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-locations.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-locations.properties
new file mode 100644
index 0000000..f945d7c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-locations.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+file=FILE.foo
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-paths.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-paths.properties
new file mode 100644
index 0000000..1bf51de
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-paths.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+foo=ID.path
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-references.properties b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-references.properties
new file mode 100644
index 0000000..e55913a
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/goldfiles/nokeeproot-semantic-references.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+property=foo
+foo.bar=foo
+foo.quux=foo
+foo.thunk=foo
+foo.property=ID.foo
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/input1.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/input1.xml
new file mode 100644
index 0000000..28328c5
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/input1.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<properties>
+  <root>foo</root>
+  <root>bar</root>
+  <a><b c="d">e</b></a>
+  <foo bar="quux">
+    <bar>quux1</bar>
+    <quux>bar</quux>
+  </foo>
+  <tag value="foo"/>
+</properties>
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/locations.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/locations.xml
new file mode 100644
index 0000000..d5cace8
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/locations.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<locations>
+  <file location="foo"/>
+</locations>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/multi.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/multi.xml
new file mode 100644
index 0000000..66904d6
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/multi.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<properties>
+  <foo>
+    <bar>1</bar>
+    <bar>2</bar>
+    <bar>3</bar>
+    <bar>4</bar>
+  </foo>
+</properties>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/original.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/original.xml
new file mode 100644
index 0000000..ef2603c
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/original.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root-tag myattr="true">
+  <inner-tag someattr="val">Text</inner-tag>
+  <a2><a3><a4>false</a4></a3></a2>
+</root-tag>
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/override.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/override.xml
new file mode 100644
index 0000000..c7da9c4
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/override.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root>
+  <override>
+    <!-- This property should not get set.  The
+         XmlPropertyTest code explicitly sets
+         override.property.test to foo to make
+         sure that attempts to reset it via
+         property file loads *fail*. -->
+    <property test="bar"/>
+  </override>
+</root>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/paths.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/paths.xml
new file mode 100644
index 0000000..83422d9
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/paths.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<paths>
+  <classpath pathid="foo">
+    <path value="bar"/>
+  </classpath>
+</paths>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/references.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/references.xml
new file mode 100644
index 0000000..7e88b7b
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty/inputs/references.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<references>
+  <property value="foo" id="foo.property"/>
+  <foo bar="${property}">
+    <quux refid="foo.property"/>
+    <thunk>${property}</thunk>
+  </foo>
+</references>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty_data.dtd b/trunk/src/etc/testcases/taskdefs/xmlproperty_data.dtd
new file mode 100644
index 0000000..5d75d6e
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty_data.dtd
@@ -0,0 +1,30 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!ELEMENT root-tag (inner-tag, a2, cdatatag)>
+<!ATTLIST root-tag myattr CDATA "">
+
+<!ELEMENT inner-tag (#PCDATA)>
+<!ATTLIST inner-tag someattr CDATA "">
+
+<!ELEMENT a2 (a3)>
+
+<!ELEMENT a3 (a4)>
+
+<!ELEMENT a4 (#PCDATA)>
+
+<!ELEMENT cdatatag (#PCDATA)>
+
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty_data.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty_data.xml
new file mode 100644
index 0000000..5f92221
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty_data.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+ <root-tag myattr="true">
+   <inner-tag someattr="val">Text</inner-tag>
+   <a2><a3><a4>false</a4></a3></a2>
+   <cdatatag><![CDATA[<test>]]></cdatatag>
+ </root-tag>
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty_needscat.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty_needscat.xml
new file mode 100644
index 0000000..942a183
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty_needscat.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE skinconfig PUBLIC "-//FOO//DTD Skin Configuration V0.1//EN" "http://example-no-dtd.com/dtd/skinconfig.dtd">
+<skinconfig>
+  <foo>true</foo>
+  <bar>false</bar>
+</skinconfig>
diff --git a/trunk/src/etc/testcases/taskdefs/xmlproperty_withdtd.xml b/trunk/src/etc/testcases/taskdefs/xmlproperty_withdtd.xml
new file mode 100644
index 0000000..1e96cdb
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/xmlproperty_withdtd.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE root-tag SYSTEM "xmlproperty_data.dtd">
+
+ <root-tag myattr="true">
+   <inner-tag someattr="val">Text</inner-tag>
+   <a2><a3><a4>false</a4></a3></a2>
+   <cdatatag><![CDATA[<test>]]></cdatatag>
+ </root-tag>
diff --git a/trunk/src/etc/testcases/taskdefs/zip.xml b/trunk/src/etc/testcases/taskdefs/zip.xml
new file mode 100644
index 0000000..b6fa113
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/zip.xml
@@ -0,0 +1,267 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="zip-test" basedir="." default="test1">
+
+  <target name="test1">
+    <zip/>
+  </target>
+
+  <target name="test2">
+    <zip destFile="zip.tmp"/>
+  </target>
+
+  <!-- Test when the zip file includes itself
+  when target file exists before the zip task is run -->
+  <target name="test3">
+    <touch file="test3.zip"/>
+    <zip destFile="test3.zip"
+         basedir="."/>
+  </target>
+
+  <!-- Test when the zip file includes itself
+  when target file does not exist before the zip task is run
+  <target name="test4">
+     <zip destFile="test4.zip"
+         basedir="."/>
+  </target>
+  -->
+
+  <target name="test5">
+    <zip zipfile="test5.zip" basedir="." >
+      <exclude name="test5.zip" />
+    </zip>
+  </target>
+
+  <target name="test6">
+    <zip destFile="test6.zip" basedir=".">
+      <include name="*.xml" />
+      <exclude name="zip.*" />
+    </zip>
+  </target>
+
+  <target name="test7">
+    <zip destFile="inner7.zip" basedir="." >
+      <exclude name="inner7.zip" />
+    </zip>
+    <zip destFile="test7.zip" basedir=".">
+      <exclude name="**/*.*" />
+      <zipfileset src="inner7.zip" />
+    </zip>
+  </target>
+
+  <target name="feather">
+    <zip destFile="asf-logo.gif.zip"
+         basedir=".."
+         includes="asf-logo.gif" />
+  </target>
+
+  <target name="uncompressed-feather">
+    <zip destFile="asf-logo.gif.zip"
+         basedir=".."
+         includes="asf-logo.gif" compress="false"/>
+  </target>
+
+  <!-- legacy attribute support -->
+  <target name="test8">
+    <zip zipfile="test8.zip" basedir="." >
+      <exclude name="test8.zip" />
+    </zip>
+  </target>
+
+  <target name="testZipgroupfileset">
+
+    <zip zipfile="zipgroupfileset.zip" basedir=".">
+      <zipgroupfileset dir="zip" 
+        includes="zipgroupfileset*.zip" 
+        excludes="zipgroupfileset3.zip" />
+      <include name="zip/zipgroupfileset3.zip" />
+    </zip>
+  </target>
+
+  <target name="testDuplicateFail">
+
+    <zip zipfile="duplicateFail.zip" basedir="." duplicate="fail">
+      <zipgroupfileset dir="duplicate" includes="duplicate*.zip" />
+    </zip>
+  </target>
+
+  <target name="testUpdateNotNecessary" depends="feather">
+    <zip destFile="asf-logo.gif.zip"
+         basedir=".."
+         includes="asf-logo.gif"
+         update="true" />
+  </target>
+
+  <target name="testUpdateIsNecessary" depends="feather">
+    <sleep seconds="5" />
+    <touch file="../dummyfile" />
+    <zip destFile="asf-logo.gif.zip"
+         basedir=".."
+         includes="asf-logo.gif,dummyfile"
+         update="true" />
+  </target>
+
+  <!-- Bugzilla Report 18403 -->
+  <target name="testPrefixAddsDir">
+    <zip destfile="test3.zip" filesonly="false">
+      <zipfileset dir="." prefix="test" includes="zip.xml"/>
+    </zip>
+  </target>
+
+  <!-- Bugzilla Report 19449 -->
+  <target name="testFilesOnlyDoesntCauseRecreateSetup">
+    <mkdir dir="ziptest"/>
+    <touch file="ziptest/ziptest"/>
+    <zip destfile="test3.zip" basedir="."
+         includes="ziptest/**" filesonly="true"/>
+  </target>
+
+  <!-- Bugzilla Report 19449 -->
+  <target name="testFilesOnlyDoesntCauseRecreate">
+    <zip destfile="test3.zip" basedir="."
+         includes="ziptest/**" filesonly="true"/>
+  </target>
+
+  <!-- Bugzilla Report 22865 -->
+  <target name="testEmptySkip">
+    <mkdir dir="ziptest"/>
+    <zip destfile="test3.zip" basedir="ziptest" whenempty="skip"/>
+    <fail message="archive should get skipped">
+      <condition>
+        <available file="test3.zip" />
+      </condition>
+    </fail>
+  </target>
+
+  <!-- Bugzilla Report 30365 -->
+  <target name="zipEmptyDir">
+    <mkdir dir="empty/empty2"/>
+    <zip destfile="test3.zip" basedir="empty" update="true"/>
+    <fail message="single-directory archive should be created">
+      <condition>
+        <or>
+          <not>
+            <available file="test3.zip" />
+          </not>
+          <resourcecount when="gt" count="0">
+            <zipfileset src="test3.zip" />
+          </resourcecount>
+          <resourcecount when="ne" count="1">
+            <restrict>
+              <exists xmlns="antlib:org.apache.tools.ant.types.resources.selectors" />
+              <zipentry zipfile="test3.zip" name="empty2/" />
+            </restrict>
+          </resourcecount>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <!-- Bugzilla Report 40258 -->
+  <target name="zipEmptyDirFilesOnly">
+    <mkdir dir="empty/empty2" />
+    <zip destfile="test3.zip" basedir="empty" update="true" filesonly="true" />
+    <fail message="archive should get skipped">
+      <condition>
+        <available file="test3.zip" />
+      </condition>
+    </fail>
+  </target>
+
+  <target name="zipEmptyCreate">
+    <mkdir dir="empty"/>
+    <zip destfile="test3.zip" basedir="empty" whenempty="create" includes="*.xyz"/>
+    <fail message="empty archive should be created">
+      <condition>
+        <or>
+          <not>
+           <available file="test3.zip" />
+          </not>
+          <resourcecount when="gt" count="0">
+            <zipfileset src="test3.zip" />
+          </resourcecount>
+        </or>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testCompressionLevel" depends="test6">
+    <length property="test6.length" file="test6.zip" />
+    <zip destFile="testLevel.zip" basedir="." level="9">
+      <include name="*.xml" />
+      <exclude name="zip.*" />
+    </zip>
+    <fail>
+      <condition>
+        <not>
+          <isfileselected file="testLevel.zip">
+            <size when="less" value="${test6.length}" />
+          </isfileselected>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <!-- Bugzilla Report 33412 -->
+  <target name="testDefaultExcludesAndUpdate">
+    <mkdir dir="ziptest"/>
+    <touch file="ziptest/ziptest~"/>
+    <zip destfile="test3.zip" basedir="ziptest" defaultexcludes="false"/>
+    <touch file="ziptest/ziptest2"/>
+    <zip destfile="test3.zip" basedir="ziptest"
+      defaultexcludes="false"
+      update="true"/>
+  </target>
+
+  <target name="testFileResource">
+    <zip destfile="test3.zip">
+      <file file="zip.xml"/>
+    </zip>
+  </target>
+
+  <target name="testNonFileResource">
+    <zip destfile="test3.zip">
+      <javaresource name="META-INF/MANIFEST.MF"/>
+    </zip>
+  </target>
+
+  <target name="testTarFileSet">
+    <ant antfile="tar.xml" target="feather"/>
+    <zip destfile="test3.zip">
+      <tarfileset src="asf-logo.gif.tar" filemode="446"/>
+    </zip>
+  </target>
+
+  <target name="cleanup">
+    <delete file="testLevel.zip"/>
+    <delete file="test3.zip"/>
+    <delete file="test4.zip"/>
+    <delete file="test5.zip"/>
+    <delete file="test6.zip"/>
+    <delete file="inner7.zip"/>
+    <delete file="test7.zip"/>
+    <delete file="test8.zip"/>
+    <delete file="asf-logo.gif.zip"/>
+    <delete file="zipgroupfileset.zip"/>
+    <delete file="../dummyfile" />
+    <delete dir="ziptest"/>
+    <delete dir="empty"/>
+    <ant antfile="tar.xml" target="cleanup"/>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/taskdefs/zip/test.exe b/trunk/src/etc/testcases/taskdefs/zip/test.exe
new file mode 100644
index 0000000..1372dff
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/zip/test.exe
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset1.zip b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset1.zip
new file mode 100644
index 0000000..f3b96ff
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset1.zip
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset2.zip b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset2.zip
new file mode 100644
index 0000000..89e09fd
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset2.zip
Binary files differ
diff --git a/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset3.zip b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset3.zip
new file mode 100644
index 0000000..dead9c1
--- /dev/null
+++ b/trunk/src/etc/testcases/taskdefs/zip/zipgroupfileset3.zip
Binary files differ
diff --git a/trunk/src/etc/testcases/testkeystore b/trunk/src/etc/testcases/testkeystore
new file mode 100644
index 0000000..2fd22c9
--- /dev/null
+++ b/trunk/src/etc/testcases/testkeystore
Binary files differ
diff --git a/trunk/src/etc/testcases/types/addtype.xml b/trunk/src/etc/testcases/types/addtype.xml
new file mode 100644
index 0000000..cc8ff24
--- /dev/null
+++ b/trunk/src/etc/testcases/types/addtype.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" basedir=".">
+
+  <target name="addpath">
+    <typedef name="mypath" classname="org.apache.tools.ant.types.Path"/>
+    <path>
+      <mypath path="build.xml"/>
+    </path>
+  </target>
+
+  <target name="addcondition">
+    <typedef name="mycondition"
+             classname="org.apache.tools.ant.taskdefs.condition.Equals"/>
+    <condition property="mycondition.set">
+      <mycondition arg1="string" arg2="string"/>
+    </condition>
+    <fail unless="mycondition.set"/>
+  </target>
+
+  <target name="addfilter">
+    <typedef name="headfilter2"
+             classname="org.apache.tools.ant.filters.HeadFilter"/>
+    <concat>This is line 1
+      This is line 2
+      This is line 3
+      <filterchain>
+        <headfilter2 lines="2"/>
+      </filterchain>
+    </concat>
+  </target>
+
+  <target name="addselector">
+    <typedef
+      name="myselector"
+      classname="org.apache.tools.ant.types.selectors.ContainsSelector"/>
+    <fileset id="myselector.test" dir="${basedir}" includes="*">
+      <myselector text="myselector"/>
+    </fileset>
+  </target>
+
+  <target name="init">
+    <property name="nested.package" value="org.apache.tools.ant.types."/>
+    <path id="test-classes">
+      <pathelement location="../../../../build/testcases" />
+      <pathelement path="${java.class.path}" />
+    </path>
+    <typedef loaderref="nested.loader" classpathref="test-classes"
+             name = "nested.a"
+             classname="${nested.package}AddTypeTest$AImpl"/>
+    <typedef loaderref="nested.loader"
+             name = "nested.b"
+             classname="${nested.package}AddTypeTest$BImpl"/>
+    <typedef loaderref="nested.loader"
+             name = "nested.c"
+             classname="${nested.package}AddTypeTest$CImpl"/>
+    <typedef loaderref="nested.loader"
+             name = "nested.ab"
+             classname="${nested.package}AddTypeTest$ABImpl"/>
+    <taskdef loaderref="nested.loader"
+             name = "nested.container" 
+             classname="${nested.package}AddTypeTest$NestedContainer"/>
+    <taskdef loaderref="nested.loader"
+             name = "nested.condition.task" 
+             classname="${nested.package}AddTypeTest$MyCondition"/>
+    <typedef loaderref="nested.loader"
+             name = "nested.condition.type" 
+             classname="${nested.package}AddTypeTest$MyCondition"/>
+    <typedef loaderref="nested.loader"
+             name = "myaddconfigured" 
+             classname="${nested.package}AddTypeTest$MyAddConfigured"/>
+    <typedef loaderref="nested.loader"
+             name = "myaddconfiguredvalue" 
+             classname="${nested.package}AddTypeTest$MyAddConfiguredValue"/>
+    <typedef loaderref="nested.loader"
+             name = "myvalue" 
+             classname="${nested.package}AddTypeTest$MyValue"/>
+  </target>
+
+  <target name="nested.a" depends="init">
+    <nested.container>
+      <nested.a/>
+    </nested.container>
+  </target>
+
+  <target name="nested.b" depends="init">
+    <nested.container>
+      <nested.b/>
+    </nested.container>
+  </target>
+  
+  <target name="nested.c" depends="init">
+    <nested.container>
+      <nested.c/>
+    </nested.container>
+  </target>
+
+  <target name="nested.ab" depends="init">
+    <nested.container>
+      <nested.ab/>
+    </nested.container>
+  </target>
+
+  <!-- tests for task adaptor -->
+  <target name="condition.type" depends="init">
+    <echo>before</echo>
+    <nested.condition.type/>
+    <echo>after</echo>
+  </target>
+
+  <target name="condition.task" depends="init">
+    <echo>before</echo>
+    <nested.condition.task/>
+    <echo>after</echo>
+  </target>
+
+  <target name="condition.condition.type" depends="init">
+    <condition property="condition.condition.type">
+      <nested.condition.type/>
+    </condition>
+  </target>
+
+  <target name="condition.condition.task" depends="init">
+    <condition property="condition.condition.task">
+      <nested.condition.task/>
+    </condition>
+  </target>
+
+  <target name="myaddconfigured" depends="init">
+    <myaddconfigured>
+      <myvalue>Value Set</myvalue>
+    </myaddconfigured>
+  </target>
+
+  <target name="myaddconfiguredvalue" depends="init">
+    <myaddconfiguredvalue>
+      <value>Value Set</value>
+    </myaddconfiguredvalue>
+  </target>
+
+  <target name="namespacetest" xmlns:prefix="uri">
+    <typedef name="eq" uri="uri"
+             classname="org.apache.tools.ant.taskdefs.condition.Equals"/>
+    <condition property="p">
+      <prefix:eq arg1="a" arg2="b"/>
+    </condition>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/assertions.xml b/trunk/src/etc/testcases/types/assertions.xml
new file mode 100644
index 0000000..a287213
--- /dev/null
+++ b/trunk/src/etc/testcases/types/assertions.xml
@@ -0,0 +1,202 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="assertions" basedir="." default="init">
+
+  <property name="build.dir" location="assertions/build"/>
+  <property name="src.dir" location="assertions"/>
+  <property name="classname" value="AssertionMain"/>
+  <property name="test.classname" value="AssertionTest"/>
+  
+  <path id="assert.classpath">
+    <pathelement location="${build.dir}"/>
+  </path>
+  
+  <target name="setup" >
+    <mkdir dir="${build.dir}"/>
+    <javac srcdir="${src.dir}"
+      includes="*.java"
+      source="1.4"
+      debug="true"
+      destdir="${build.dir}"
+      />
+  </target>
+  
+  <target name="teardown" >
+    <delete dir="${build.dir}"/>
+  </target>
+
+  <!-- if per-class assertions work, this run asserts -->
+  <target name="test-classname" depends="setup">
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enablesystemassertions="true">
+        <enable class="${classname}" />
+      </assertions>
+    </java>
+  </target>
+  
+  <!-- if package works, this run asserts -->
+  <target name="test-package" depends="setup">
+    <java fork="true"  failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enableSystemAssertions="false" >
+        <enable package="..." />
+      </assertions>
+    </java>
+  </target>
+
+  <!-- this test should run the app successfully -->
+  <target name="test-empty-assertions" depends="setup">
+    <java fork="true"  failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions/>
+    </java>
+  </target>  
+
+  <!-- this test should run the app successfully -->
+  <target name="test-disable" depends="setup">
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enableSystemAssertions="false" >
+        <enable package="..." />
+        <disable class="${classname}" />
+      </assertions>
+    </java>
+  </target>  
+
+  <!-- repeated settigns result in the last declaration winning
+    except that the rule 'classes win over packages takes priority
+    this run will assert -->
+  <target name="test-override" depends="setup">
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enableSystemAssertions="false" >
+        <enable package="..." />
+        <disable class="${classname}" />
+        <enable class="${classname}" />
+        <disable package="..." />
+      </assertions>
+    </java>
+  </target>  
+
+  <!-- repeated settigns result in the last declaration winning;
+    this run will not assert -->
+  <target name="test-override2" depends="setup">
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enableSystemAssertions="false" >
+        <enable package="..." />
+        <enable class="${classname}" />
+        <disable class="${classname}" />
+      </assertions>
+    </java>
+  </target>  
+  
+  <!-- if references work, this run asserts -->
+  <target name="test-references">
+  <assertions id="project.assertions" >
+    <enable package="org.apache.test" />
+    <disable package="org.apache.log4j"/>
+    <enable package="..."/>
+  </assertions>  
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions refid="project.assertions"/>
+    </java>
+  </target>
+  
+  <!-- when fork=false; we need to reject the construct -->
+  <target name="test-nofork" depends="setup">
+    <java fork="false" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enablesystemassertions="true">
+        <enable class="${classname}" />
+      </assertions>
+    </java>
+  </target>  
+
+  <!-- this throws a build error -->
+  <target name="test-multiple-assertions" depends="setup">
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions enablesystemassertions="true">
+        <enable class="${classname}" />
+      </assertions>
+      <assertions/>
+    </java>
+  </target>  
+  
+  <!-- should throw a build exception -->
+  <target name="test-reference-abuse" depends="setup">
+  <assertions id="project.assertions2" >
+    <enable package="org.apache.test" />
+    <disable package="org.apache.log4j"/>
+    <enable package="..."/>
+  </assertions>  
+    <java fork="true" failonerror="true"
+      classname="${classname}"
+      classpathref="assert.classpath">
+      <assertions refid="project.assertions2">
+        <disable class="${classname}" />
+      </assertions>      
+    </java>
+  </target>    
+  
+    
+  <target name="test-junit" depends="setup">
+    <junit fork="true" 
+      haltonerror="true" haltonfailure="true"
+      >
+      <classpath>
+        <path refid="assert.classpath"/>
+      </classpath>
+      <formatter type="plain"     usefile="false"/>
+      <assertions >
+        <enable class="${test.classname}" />
+      </assertions> 
+      <test name="${test.classname}"/>
+    </junit>
+  </target>
+    
+  <!-- This is here to show that setting it as a property works
+  so there is some defect in pass-on of assertions that
+  is causing the problem -->
+  <target name="test-junit-manual-setup" depends="setup">
+    <junit fork="true" 
+      haltonerror="true" haltonfailure="true"
+      >
+      <classpath>
+        <path refid="assert.classpath"/>
+      </classpath>
+      <formatter type="plain"     usefile="false"/>
+      <test name="${test.classname}"/>
+      <jvmarg value="-ea:AssertionTest"/>
+    </junit>
+  </target>  
+  
+</project>
diff --git a/trunk/src/etc/testcases/types/assertions/AssertionMain.java b/trunk/src/etc/testcases/types/assertions/AssertionMain.java
new file mode 100644
index 0000000..f4aa690
--- /dev/null
+++ b/trunk/src/etc/testcases/types/assertions/AssertionMain.java
@@ -0,0 +1,31 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * 
+ */
+ 
+
+/**
+ * this is an assertion tester
+ * It has a main() entry
+ */
+public class AssertionMain {
+    
+    public static void main(String args[]) {
+		assert true == false : "there exist no facts that are both true and false";
+		System.out.println("Assertions are disabled");
+    }
+    
+}
diff --git a/trunk/src/etc/testcases/types/assertions/AssertionTest.java b/trunk/src/etc/testcases/types/assertions/AssertionTest.java
new file mode 100644
index 0000000..19ed2df
--- /dev/null
+++ b/trunk/src/etc/testcases/types/assertions/AssertionTest.java
@@ -0,0 +1,45 @@
+/* 
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * 
+ */
+ 
+ import junit.framework.TestCase;
+
+/**
+ * this is an assertion tester for junit 
+ */
+public class AssertionTest extends TestCase {
+    
+	public AssertionTest(String name) {
+		super(name);
+	}
+	
+	public void testAssertRaised() {
+		try {
+			assert true == false;
+			fail("expected an assertion");
+		} catch(AssertionError asserto) {
+			//if we got here, all was well
+		}
+	}
+	
+	
+	public void testAssertNotRaised() {
+		assert(2+2==4);
+	}
+	
+    
+}
diff --git a/trunk/src/etc/testcases/types/description1.xml b/trunk/src/etc/testcases/types/description1.xml
new file mode 100644
index 0000000..86a2a16
--- /dev/null
+++ b/trunk/src/etc/testcases/types/description1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="main" basedir=".">
+  <description>Test Project Description</description>
+  <target name="main">
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/description2.xml b/trunk/src/etc/testcases/types/description2.xml
new file mode 100644
index 0000000..945bc20
--- /dev/null
+++ b/trunk/src/etc/testcases/types/description2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="main" basedir=".">
+  <description>Multi Line
+Project Description</description>
+  <target name="main">
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/description3.xml b/trunk/src/etc/testcases/types/description3.xml
new file mode 100644
index 0000000..af5dda1
--- /dev/null
+++ b/trunk/src/etc/testcases/types/description3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="main" basedir=".">
+  <description>Multi Instance </description>
+  <description>Project Description</description>
+  <target name="main">
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/description4.xml b/trunk/src/etc/testcases/types/description4.xml
new file mode 100644
index 0000000..22df9c2
--- /dev/null
+++ b/trunk/src/etc/testcases/types/description4.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="main" basedir=".">
+  <description>Multi Instance </description>
+  <target name="main">
+      <description>Nested Project Description</description>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/filelist.xml b/trunk/src/etc/testcases/types/filelist.xml
new file mode 100644
index 0000000..f854ddb
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filelist.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test">
+  <target name="simple">
+    <filelist id="filelist"
+              dir="${basedir}"
+              files="a"/>
+    <pathconvert targetos="unix" refid="filelist"
+                 property="property">
+      <map from="${basedir}" to="/abc"/>
+    </pathconvert>
+    <echo>${property}</echo>
+  </target>
+
+  <target name="double">
+    <filelist id="filelist"
+              dir="${basedir}"
+              files="a b"/>
+    <pathconvert targetos="unix" refid="filelist"
+                 property="property">
+      <map from="${basedir}" to="/abc"/>
+    </pathconvert>
+    <echo>${property}</echo>
+  </target>
+
+  <target name="nested">
+    <filelist id="filelist"
+              dir="${basedir}">
+      <file name="a"/>
+      <file name="b"/>
+    </filelist>
+    <pathconvert targetos="unix" refid="filelist"
+                 property="property">
+      <map from="${basedir}" to="/abc"/>
+    </pathconvert>
+    <echo>${property}</echo>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/filterset.xml b/trunk/src/etc/testcases/types/filterset.xml
new file mode 100644
index 0000000..bf291e7
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filterset.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="new" basedir=".">
+  <filterset id="testset.one">
+    <filter token="aaaa" value="1111"/>
+    <filter token="bbbb" value="2222"/>
+  </filterset>
+  
+  <filterset id="testset.two" beginToken="%" endToken="^">
+    <filter token="cccc" value="3333"/>
+    <filter token="dddd" value="4444"/>
+  </filterset>
+  
+  <target name="test1">
+    <delete file="dest1.txt"/>
+    <copy file="filterseta.txt" tofile="dest1.txt">
+        <filterset refid="testset.one"/> 
+    </copy>
+  </target>
+
+  <target name="test2">
+    <delete file="dest2.txt"/>
+    <copy file="filtersetb.txt" tofile="dest2.txt">
+        <filterset refid="testset.two"/> 
+    </copy>
+  </target>
+
+  <target name="test3">
+    <delete file="dest3.txt"/>
+    <copy file="filtersetc.txt" tofile="dest3.txt">
+        <filterset refid="testset.one"/> 
+        <filterset refid="testset.two"/> 
+    </copy>
+  </target>
+  
+  <target name="test-nested-filtersets">
+    <filterset id="1">
+      <filter token="token1" value="value1"/>
+    </filterset>
+    <filterset id="2">
+      <filterset refid="testset.one"/>
+    </filterset>
+    <filterset id="3">
+      <filterset id="4">
+        <filter token="token4" value="value4"/>
+      </filterset>
+    </filterset>
+    <filterset id="5">
+      <filterset refid="1"/>
+    </filterset>
+  </target>
+
+  <target name="testFiltersFileElement">
+    <copy file="filtersetd.txt" tofile="dest4.txt">
+      <filterset>
+        <filtersfile file="filtersfile1" />
+      </filterset>
+    </copy>
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch asText="true">
+            <file file="dest4.txt" />
+            <string value="FOO BAR @baz@ @blah@" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testFiltersFileAttribute">
+    <copy file="filtersetd.txt" tofile="dest5.txt">
+      <filterset filtersfile="filtersfile1" />
+    </copy>
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch asText="true">
+            <file file="dest5.txt" />
+            <string value="FOO BAR @baz@ @blah@" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testMultipleFiltersFiles">
+    <copy file="filtersetd.txt" tofile="dest6.txt">
+      <filterset filtersfile="filtersfile1">
+        <filtersfile file="filtersfile2" />
+      </filterset>
+    </copy>
+    <fail>
+      <condition>
+        <not>
+          <resourcesmatch asText="true">
+            <file file="dest6.txt" />
+            <string value="FOO BAR BAZ @blah@" />
+          </resourcesmatch>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testMissingFiltersFile">
+    <copy file="filtersetd.txt" tofile="dest7.txt">
+      <filterset filtersfile="nonexistentfiltersfile" />
+    </copy>
+  </target>
+
+  <target name="testAllowMissingFiltersFile">
+    <copy file="filtersetd.txt" tofile="dest8.txt">
+      <filterset filtersfile="nonexistentfiltersfile"
+                 onmissingfiltersfile="ignore" />
+    </copy>
+    <fail>
+      <condition>
+        <not>
+          <filesmatch file1="filtersetd.txt" file2="dest8.txt" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="cleanup">
+    <delete quiet="true">
+      <fileset dir="." includes="dest?.txt" />
+    </delete>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/filterseta.txt b/trunk/src/etc/testcases/types/filterseta.txt
new file mode 100644
index 0000000..4404995
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filterseta.txt
@@ -0,0 +1,2 @@
+This is a test file for filters @aaaa@
+It has two lines @bbbb@
diff --git a/trunk/src/etc/testcases/types/filtersetb.txt b/trunk/src/etc/testcases/types/filtersetb.txt
new file mode 100644
index 0000000..f49640a
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filtersetb.txt
@@ -0,0 +1,5 @@
+This is a test file for filters with non default markers
+@cccc@ - should not change
+%cccc^ - should change
+^dddd% - should not change
+%dddd^ - should change
diff --git a/trunk/src/etc/testcases/types/filtersetc.txt b/trunk/src/etc/testcases/types/filtersetc.txt
new file mode 100644
index 0000000..2522d35
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filtersetc.txt
@@ -0,0 +1,7 @@
+Combined filter test
+@aaaa@ - should change
+@bbbb@ - should change
+@cccc@ - should not change
+%cccc^ - should change
+^dddd% - should not change
+%dddd^ - should change
diff --git a/trunk/src/etc/testcases/types/filtersetd.txt b/trunk/src/etc/testcases/types/filtersetd.txt
new file mode 100644
index 0000000..45c4849
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filtersetd.txt
@@ -0,0 +1 @@
+@foo@ @bar@ @baz@ @blah@
diff --git a/trunk/src/etc/testcases/types/filtersfile1 b/trunk/src/etc/testcases/types/filtersfile1
new file mode 100644
index 0000000..20fe058
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filtersfile1
@@ -0,0 +1,2 @@
+foo=FOO
+bar=BAR
diff --git a/trunk/src/etc/testcases/types/filtersfile2 b/trunk/src/etc/testcases/types/filtersfile2
new file mode 100644
index 0000000..43c97f2
--- /dev/null
+++ b/trunk/src/etc/testcases/types/filtersfile2
@@ -0,0 +1 @@
+baz=BAZ
diff --git a/trunk/src/etc/testcases/types/flexinteger.xml b/trunk/src/etc/testcases/types/flexinteger.xml
new file mode 100644
index 0000000..aa10aa0
--- /dev/null
+++ b/trunk/src/etc/testcases/types/flexinteger.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" default="test" basedir=".">
+
+  <path id="testclasses">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="test">
+    <taskdef name="flexint"
+             classname="org.apache.tools.ant.types.FlexIntegerTest"
+             classpathref="testclasses"
+    />
+            
+    <flexint propname="flexint.value1" value="0xA"/>
+    <flexint propname="flexint.value2" value="010"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/gold/filterset1.txt b/trunk/src/etc/testcases/types/gold/filterset1.txt
new file mode 100644
index 0000000..975416f
--- /dev/null
+++ b/trunk/src/etc/testcases/types/gold/filterset1.txt
@@ -0,0 +1,2 @@
+This is a test file for filters 1111
+It has two lines 2222
diff --git a/trunk/src/etc/testcases/types/gold/filterset2.txt b/trunk/src/etc/testcases/types/gold/filterset2.txt
new file mode 100644
index 0000000..eaab021
--- /dev/null
+++ b/trunk/src/etc/testcases/types/gold/filterset2.txt
@@ -0,0 +1,5 @@
+This is a test file for filters with non default markers
+@cccc@ - should not change
+3333 - should change
+^dddd% - should not change
+4444 - should change
diff --git a/trunk/src/etc/testcases/types/gold/filterset3.txt b/trunk/src/etc/testcases/types/gold/filterset3.txt
new file mode 100644
index 0000000..3516e62
--- /dev/null
+++ b/trunk/src/etc/testcases/types/gold/filterset3.txt
@@ -0,0 +1,7 @@
+Combined filter test
+1111 - should change
+2222 - should change
+@cccc@ - should not change
+3333 - should change
+^dddd% - should not change
+4444 - should change
diff --git a/trunk/src/etc/testcases/types/mapper.xml b/trunk/src/etc/testcases/types/mapper.xml
new file mode 100644
index 0000000..1c842d9
--- /dev/null
+++ b/trunk/src/etc/testcases/types/mapper.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="copy-test" basedir="." default="test1">
+
+  <target name="test1">
+    <mkdir dir="copytest" />
+    <copy todir="copytest">
+      <fileset dir="../../../main">
+        <include name="**/taskdefs/*.java" />
+      </fileset>
+      <fileset dir="../../../tests/junit">
+        <include name="**/taskdefs/*.java" />
+      </fileset>
+      <mapper type="flatten" />
+    </copy>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="copytest" />
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/mappers/define.mapperresult.xml b/trunk/src/etc/testcases/types/mappers/define.mapperresult.xml
new file mode 100644
index 0000000..d9152a1
--- /dev/null
+++ b/trunk/src/etc/testcases/types/mappers/define.mapperresult.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <typedef name="mapperresult"
+           classpath="../../../../../build/testcases"
+           classname="org.apache.tools.ant.types.mappers.MapperResult"/>
+
+  <!-- this is what you get with no result -->           
+  <property name="no-results" value="&lt;NULL&gt;" />           
+</project>
diff --git a/trunk/src/etc/testcases/types/mappers/globmapper.xml b/trunk/src/etc/testcases/types/mappers/globmapper.xml
new file mode 100644
index 0000000..1666d81
--- /dev/null
+++ b/trunk/src/etc/testcases/types/mappers/globmapper.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <import file="define.mapperresult.xml"/>
+
+  <target name="handle.dirsep">
+    <mapperresult input="d\e/f/j.java" output="f/j.java">
+      <globmapper from="d/e\*" to="*" handledirsep="yes"/>
+    </mapperresult>
+  </target>
+  
+  <target name="ignore.case">
+    <mapperresult input="AbcDef.JaVa" output="bcDef.java.bak">
+      <globmapper from="a*.java" to="*.java.bak" casesensitive="no"/>
+    </mapperresult>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/mappers/regexpmapper.xml b/trunk/src/etc/testcases/types/mappers/regexpmapper.xml
new file mode 100644
index 0000000..a85c49c
--- /dev/null
+++ b/trunk/src/etc/testcases/types/mappers/regexpmapper.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <import file="define.mapperresult.xml"/>
+
+  <target name="ignore.case">
+    <mapperresult input="AbcDef.javA" output="bcDef.java.bak">
+      <regexpmapper from="a(.*).JaVa" to="\1.java.bak" casesensitive="no"/>
+    </mapperresult>
+  </target>
+
+  <target name="handle.dirsep">
+    <mapperresult input="d\e/f\j.java" output="f/j.java">
+      <regexpmapper from="d/e/(.*)" to="\1" handledirsep="yes"/>
+    </mapperresult>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/mappers/scriptmapper.xml b/trunk/src/etc/testcases/types/mappers/scriptmapper.xml
new file mode 100644
index 0000000..d3e7a8d
--- /dev/null
+++ b/trunk/src/etc/testcases/types/mappers/scriptmapper.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="scriptmapper">
+  <import file="define.mapperresult.xml"/>
+
+  
+  <target name="testSetSingle">
+    <mapperresult input="" output="a">
+      <scriptmapper language="javascript">
+        self.addMappedName("a");
+      </scriptmapper>
+    </mapperresult>
+  </target>
+
+  <target name="testClear">
+    <mapperresult input="" output="${no-results}">
+      <scriptmapper language="javascript">
+        self.addMappedName("a");
+        self.clear();
+      </scriptmapper>
+    </mapperresult>
+  </target>
+
+  <target name="testSetMultiple">
+    <mapperresult input="" output="a|b">
+      <scriptmapper language="javascript">
+        self.addMappedName("a");
+        self.addMappedName("b");
+      </scriptmapper>
+    </mapperresult>
+  </target>
+
+  <target name="testPassthrough">
+    <mapperresult input="a" output="A|a">
+      <scriptmapper language="javascript">
+        //relying on "a" to map to "A" on all locales.
+        self.addMappedName(source.toUpperCase());
+        self.addMappedName(source.toLowerCase());
+      </scriptmapper>
+    </mapperresult>
+  </target>
+  
+</project>
diff --git a/trunk/src/etc/testcases/types/poly.xml b/trunk/src/etc/testcases/types/poly.xml
new file mode 100644
index 0000000..cabf9ec
--- /dev/null
+++ b/trunk/src/etc/testcases/types/poly.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test" basedir=".">
+  
+  <property name="c" value="org.apache.tools.ant.types.PolyTest"/>
+  
+  <path id="test-c">
+    <pathelement location="../../../../build/testcases" />
+    <pathelement path="${java.class.path}" />
+  </path>
+
+  <target name="init">
+    <typedef loaderref="poly"   classpathref="test-c"
+             name = "myfileset" classname="${c}$MyFileSet"/>
+
+    <typedef loaderref="poly" classpathref="test-c"
+             name = "mypath"  classname="${c}$MyPath"/>
+
+    <typedef loaderref="poly" classpathref="test-c"
+             name = "mytask"  classname="${c}$MyTask"/>
+  </target>
+
+  <target name="fileset" depends="init">
+    <mytask>
+      <fileset dir="."/>
+    </mytask>
+  </target>
+
+  <target name="fileset-ant-type" depends="init">
+    <mytask>
+      <fileset ant-type="myfileset" dir="."/>
+    </mytask>
+  </target>
+
+  <target name="path" depends="init">
+    <mytask>
+      <path path="."/>
+    </mytask>
+  </target>
+
+  <target name="path-ant-type" depends="init">
+    <mytask>
+      <path ant-type="mypath" path="."/>
+    </mytask>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/propertyset.xml b/trunk/src/etc/testcases/types/propertyset.xml
new file mode 100644
index 0000000..b45ba9c
--- /dev/null
+++ b/trunk/src/etc/testcases/types/propertyset.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0"?>
+<!--
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+-->
+
+<project>
+  <property name="fooA" value="FooA"/>
+  <property name="barB" value="BarB"/>
+
+  <propertyset id="properties-starting-with-foo">
+    <propertyref prefix="foo"/>
+  </propertyset>
+  <propertyset id="properties-starting-with-bar">
+    <propertyref prefix="bar"/>
+  </propertyset>
+  <propertyset id="my-set">
+    <propertyset refid="properties-starting-with-foo"/>
+    <propertyset refid="properties-starting-with-bar"/>
+  </propertyset>
+  
+  <macrodef name="expect.equals">
+    <attribute name="test"/>
+    <attribute name="exp"/>
+    <attribute name="got"/>
+    <sequential>
+      <fail message=
+          "@{test} failed: expected &quot;@{exp}&quot; got &quot;@{got}&quot;">
+        <condition>
+          <not>
+            <equals arg1="@{exp}" arg2="@{got}"/>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <target name="reference-to-two-references">
+    <expect.equals
+      test="reference to two references"
+      exp="barB=BarB, fooA=FooA"
+      got="${toString:my-set}"/>
+  </target>
+
+  <target name="nested-mapped">
+    <propertyset id="nested-mapped">
+      <propertyset>
+        <propertyset refid="properties-starting-with-foo"/>
+        <globmapper from="foo*" to="boo*" />
+      </propertyset>
+      <propertyset>
+        <propertyset refid="properties-starting-with-bar"/>
+        <globmapper from="bar*" to="far*" />
+      </propertyset>
+    </propertyset>
+    <expect.equals
+      test="nested mapped propertysets"
+      exp="booA=FooA, farB=BarB"
+      got="${toString:nested-mapped}"/>
+  </target>
+
+  <target name="nested-mapped-mapped">
+    <propertyset id="nested-mapped-mapped">
+      <propertyset>
+        <propertyset refid="properties-starting-with-foo"/>
+        <globmapper from="foo*" to="boo*" />
+      </propertyset>
+      <propertyset>
+        <propertyset refid="properties-starting-with-bar"/>
+        <globmapper from="bar*" to="far*" />
+      </propertyset>
+      <mapper>
+        <globmapper from="boo*" to="hoo*" />
+        <globmapper from="far*" to="near*" />
+      </mapper>
+    </propertyset>
+    <expect.equals
+      test="nested mapped propertysets"
+      exp="hooA=FooA, nearB=BarB"
+      got="${toString:nested-mapped-mapped}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/quote1.xml b/trunk/src/etc/testcases/types/quote1.xml
new file mode 100644
index 0000000..8e77122
--- /dev/null
+++ b/trunk/src/etc/testcases/types/quote1.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+  <!-- I belong to:
+       org.apache.tools.ant.types.XMLCatalogBuildFileTest.java 
+       -->
+
+<para>
+  A stitch in time saves nine
+</para>
diff --git a/trunk/src/etc/testcases/types/quote2.xml b/trunk/src/etc/testcases/types/quote2.xml
new file mode 100644
index 0000000..ef9a3c3
--- /dev/null
+++ b/trunk/src/etc/testcases/types/quote2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+  <!-- I belong to:
+       org.apache.tools.ant.types.XMLCatalogBuildFileTest.java 
+       -->
+
+<para>
+  No news is good news
+</para>
+
diff --git a/trunk/src/etc/testcases/types/redirector.xml b/trunk/src/etc/testcases/types/redirector.xml
new file mode 100755
index 0000000..4784e9f
--- /dev/null
+++ b/trunk/src/etc/testcases/types/redirector.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="redirector" basedir=".">
+
+  <target name="test1" description="create ref">
+    <redirector id="test1" output="out" />
+  </target>
+
+  <target name="test2" depends="test1" description="fail">
+    <redirector refid="test1" output="out" />
+  </target>
+
+  <target name="test3" depends="test1" description="fail">
+    <redirector refid="test1">
+      <outputmapper type="flatten" />
+    </redirector>
+  </target>
+
+  <target name="test4" depends="test1" description="pass">
+    <redirector>
+      <outputmapper type="flatten" />
+    </redirector>
+  </target>
+
+  <target name="testLogInputString" depends="cat-check" if="can-cat">
+    <echo>
+        testLogInputString can-cat
+    </echo>
+    <exec executable="cat">
+      <redirector inputstring="foo" loginputstring="false" />
+    </exec>
+  </target>
+
+  <target name="testRefid" depends="cat-check" if="can-cat">
+    <fail message="Property testRefid.out is already set!">
+      <condition>
+        <isset property="testRefid.out" />
+      </condition>
+    </fail>
+    <redirector id="r" outputproperty="testRefid.out" inputstring="foo" />
+    <exec executable="cat">
+      <redirector refid="r" />
+    </exec>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${testRefid.out}" arg2="foo" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="cat-check">
+    <property environment="env" />
+    <condition property="can-cat">
+      <or>
+        <available file="cat" filepath="${env.PATH}" property="can-cat" />
+        <available file="cat.exe" filepath="${env.PATH}" property="can-cat" />
+        <available file="cat.exe" filepath="${env.Path}" property="can-cat" />
+      </or>
+    </condition>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/resources/comparators/build.xml b/trunk/src/etc/testcases/types/resources/comparators/build.xml
new file mode 100755
index 0000000..a3b20bc
--- /dev/null
+++ b/trunk/src/etc/testcases/types/resources/comparators/build.xml
@@ -0,0 +1,345 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="sort"
+         xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
+
+  <property name="dirname" value="work" />
+  <property name="dir" location="${dirname}" />
+  <property name="echolevel" value="debug" />
+
+  <target name="tearDown">
+    <delete dir="${dir}" />
+    <delete file="${zip}" />
+    <delete file="${jar}" deleteonexit="true" />
+    <delete file="${file}" />
+  </target>
+
+  <target name="sortsetup" unless="sortsetup.done">
+    <mkdir dir="${dir}" />
+
+    <echo file="${dir}/b" message="yyy" />
+    <echo file="${dir}/e" message="aaa" />
+    <sleep seconds="2" />
+    <echo file="${dir}/c" message="x" />
+    <echo file="${dir}/d" message="x" />
+    <sleep seconds="2" />
+    <echo file="${dir}/a" message="zz" />
+    <echo file="${dir}/f" message="zz" />
+
+    <mkdir dir="${dir}/a.dir" />
+    <mkdir dir="${dir}/b.dir" />
+    <mkdir dir="${dir}/c.dir" />
+
+    <macrodef name="mysort">
+      <attribute name="property" />
+      <attribute name="separator" default="," />
+      <element name="cmp" optional="true" implicit="true" />
+      <sequential>
+        <pathconvert property="@{property}" pathsep="@{separator}">
+          <sort>
+            <fileset dir="${dir}" includes="a,b,c" />
+            <cmp />
+          </sort>
+          <flattenmapper />
+        </pathconvert>
+        <echo level="${echolevel}">@{property}=${@{property}}</echo>
+      </sequential>
+    </macrodef>
+
+    <property name="sortsetup.done" value="true" />
+  </target>
+
+  <target name="testsortdefault" depends="sortsetup">
+    <mysort property="sortdf" />
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortdf}" arg2="a,b,c" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvdefault" depends="sortsetup">
+    <mysort property="sortdf-rev">
+      <rcmp:reverse />
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortdf-rev}" arg2="c,b,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testname" depends="sortsetup">
+    <mysort property="sortnm">
+      <rcmp:name />
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortnm}" arg2="a,b,c" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvname" depends="sortsetup">
+    <mysort property="sortnm-rev">
+      <rcmp:reverse>
+        <rcmp:name />
+      </rcmp:reverse>
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortnm-rev}" arg2="c,b,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testdate" depends="sortsetup">
+    <mysort property="sortlm">
+      <rcmp:date />
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortlm}" arg2="b,c,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvdate" depends="sortsetup">
+    <mysort property="sortlm-rev">
+      <rcmp:reverse>
+        <rcmp:date />
+      </rcmp:reverse>
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortlm-rev}" arg2="a,c,b" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testsize" depends="sortsetup">
+    <mysort property="sortsz">
+      <rcmp:size />
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortsz}" arg2="c,a,b" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvsize" depends="sortsetup">
+    <mysort property="sortsz-rev">
+      <rcmp:reverse>
+        <rcmp:size />
+      </rcmp:reverse>
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortsz-rev}" arg2="b,a,c" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testcontent" depends="sortsetup">
+    <mysort property="sortct">
+      <rcmp:content />
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortct}" arg2="c,b,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvcontent" depends="sortsetup">
+    <mysort property="sortct-rev">
+      <rcmp:reverse>
+        <rcmp:content />
+      </rcmp:reverse>
+    </mysort>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortct-rev}" arg2="a,b,c" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testexists" depends="sortsetup">
+    <pathconvert property="sortex" pathsep=",">
+      <sort>
+        <resources>
+          <file file="${dir}/a" />
+          <resource name="redherring" exists="false" />
+        </resources>
+        <rcmp:exists />
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortex}" arg2="redherring,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvexists" depends="sortsetup">
+    <pathconvert property="sortex-rev" pathsep=",">
+      <sort>
+        <resources>
+          <file file="${dir}/a" />
+          <resource name="redherring" exists="false" />
+        </resources>
+        <rcmp:reverse>
+          <rcmp:exists />
+        </rcmp:reverse>
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortex-rev}" arg2="a,redherring" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testtype" depends="sortsetup">
+    <pathconvert property="sorttp" pathsep=",">
+      <sort>
+        <resources>
+          <file file="${dir}/a" />
+          <file file="${dir}/a.dir" />
+        </resources>
+        <rcmp:type />
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sorttp}" arg2="a,a.dir" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testrvtype" depends="sortsetup">
+    <pathconvert property="sorttp-rev" pathsep=",">
+      <sort>
+        <resources>
+          <file file="${dir}/a" />
+          <file file="${dir}/a.dir" />
+        </resources>
+        <rcmp:reverse>
+          <rcmp:type />
+        </rcmp:reverse>
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sorttp-rev}" arg2="a.dir,a" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="forwardsort"
+    depends="testsortdefault,testname,testdate,testsize,testcontent,testexists,testtype" />
+
+  <target name="reversesort"
+    depends="testrvdefault,testrvname,testrvdate,testrvsize,testrvcontent,testrvexists,testrvtype" />
+
+  <target name="testcompoundsort1" depends="sortsetup">
+    <pathconvert property="sortcmp1" pathsep=",">
+      <sort>
+        <resources>
+          <file file="${dir}/c" />
+          <file file="${dir}/b.dir" />
+          <file file="${dir}/a" />
+          <file file="${dir}/c.dir" />
+          <file file="${dir}/b" />
+          <file file="${dir}/a.dir" />
+        </resources>
+        <rcmp:reverse>
+          <rcmp:type />
+        </rcmp:reverse>
+        <rcmp:name />
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortcmp1}" arg2="a.dir,b.dir,c.dir,a,b,c" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="testcompoundsort2" depends="sortsetup">
+    <pathconvert property="sortcmp2" pathsep=",">
+      <sort>
+        <files includes="${dir}/?" />
+        <rcmp:size />
+        <rcmp:content />
+        <rcmp:reverse>
+          <rcmp:name />
+        </rcmp:reverse>
+      </sort>
+      <flattenmapper />
+    </pathconvert>
+    <fail>
+      <condition>
+        <not>
+          <equals arg1="${sortcmp2}" arg2="d,c,f,a,e,b" />
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="compoundsort" depends="testcompoundsort1,testcompoundsort2" />
+
+  <target name="sort" depends="forwardsort,reversesort,compoundsort" />
+
+</project>
diff --git a/trunk/src/etc/testcases/types/resources/javaresource.xml b/trunk/src/etc/testcases/types/resources/javaresource.xml
new file mode 100755
index 0000000..8326762
--- /dev/null
+++ b/trunk/src/etc/testcases/types/resources/javaresource.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <target name="loadManifest">
+    <loadresource property="manifest">
+      <javaresource name="META-INF/MANIFEST.MF"/>
+    </loadresource>
+  </target>
+</project>
diff --git a/trunk/src/etc/testcases/types/resources/tarentry.xml b/trunk/src/etc/testcases/types/resources/tarentry.xml
new file mode 100755
index 0000000..09902ff
--- /dev/null
+++ b/trunk/src/etc/testcases/types/resources/tarentry.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="not me">
+  <target name="not me">
+    <fail>only use from within unit tests</fail>
+  </target>
+
+  <property name="testout" location="testout"/>
+  <target name="setUp">
+    <mkdir dir="${testout}"/>
+  </target>
+
+  <target name="uncompressSource" depends="setUp">
+    <ant antfile="../../taskdefs/tar.xml" target="feather" />
+    <copy todir="${testout}">
+      <tarentry name="asf-logo.gif">
+        <gzipresource>
+          <file file="../../taskdefs/expected/asf-logo.gif.tar.gz"/>
+        </gzipresource>
+      </tarentry>
+    </copy>
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${testout}"/>
+    <ant antfile="../../taskdefs/tar.xml" target="cleanup" />
+  </target>
+</project>
\ No newline at end of file
diff --git a/trunk/src/etc/testcases/types/selectors.xml b/trunk/src/etc/testcases/types/selectors.xml
new file mode 100644
index 0000000..71a7d80
--- /dev/null
+++ b/trunk/src/etc/testcases/types/selectors.xml
@@ -0,0 +1,367 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="selectors-test" basedir="." default="setupfiles">
+
+  <property name="etc.dir" value=".."/>
+  <property name="test.dir"
+          value="selectortest"/>
+  <property name="testregexpsrc.dir"
+          value="regexpseltestsrc"/>
+  <property name="testregexpdest.dir"
+          value="regexpseltestdest"/>
+  <property name="mirror.dir"
+          value="selectortest2"/>
+
+  <target name="setupfiles">
+    <mkdir dir="${test.dir}" />
+    <mkdir dir="${test.dir}/zip" />
+    <mkdir dir="${test.dir}/tar" />
+    <mkdir dir="${test.dir}/tar/gz" />
+    <mkdir dir="${test.dir}/tar/bz2" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.md5"
+            tofile="${test.dir}/asf-logo.gif.md5" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.bz2"
+            tofile="${test.dir}/asf-logo.gif.bz2" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.gz"
+            tofile="${test.dir}/asf-logo.gif.gz" />
+    <copy file="${etc.dir}/taskdefs/expected/copy.filterset.filtered"
+            tofile="${test.dir}/copy.filterset.filtered" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.zip"
+            tofile="${test.dir}/zip/asf-logo.gif.zip" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.tar"
+            tofile="${test.dir}/tar/asf-logo.gif.tar" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo-huge.tar.gz"
+            tofile="${test.dir}/tar/asf-logo-huge.tar.gz" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.tar.gz"
+            tofile="${test.dir}/tar/gz/asf-logo.gif.tar.gz" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo.gif.tar.bz2"
+            tofile="${test.dir}/tar/bz2/asf-logo.gif.tar.bz2" />
+    <copy file="${etc.dir}/taskdefs/expected/asf-logo-huge.tar.bz2"
+            tofile="${test.dir}/tar/bz2/asf-logo-huge.tar.bz2" />
+    <!-- Make linefeeds consistent between platforms -->
+    <fixcrlf srcdir="${test.dir}" includes="*.filtered" eol="lf"/>
+    <!-- Set a known base time for all files -->
+    <touch datetime="11/21/2001 4:55 AM">
+        <fileset dir="${test.dir}">
+            <include name="**/*"/>
+        </fileset>
+    </touch>
+    <!-- Then adjust individual ones -->
+    <touch file="${test.dir}/asf-logo.gif.bz2"
+            datetime="01/01/2001 12:00 AM"/>
+    <touch file="${test.dir}/asf-logo.gif.gz"
+            datetime="04/15/2002 2:30 PM"/>
+    <touch file="${test.dir}/zip/asf-logo.gif.zip"
+            datetime="05/10/2002 2:30 PM"/>
+    <touch file="${test.dir}/tar/asf-logo.gif.tar"
+            datetime="05/10/2002 2:29 PM"/>
+    <touch file="${test.dir}/tar/asf-logo-huge.tar.gz"
+            datetime="05/10/2002 2:29 AM"/>
+  </target>
+
+  <target name="cleanup">
+    <delete dir="${test.dir}" />
+  </target>
+
+  <target name="mirrorfiles">
+    <mkdir dir="${mirror.dir}" />
+    <mkdir dir="${mirror.dir}/zip" />
+    <mkdir dir="${mirror.dir}/tar" />
+    <mkdir dir="${mirror.dir}/tar/gz" />
+    <mkdir dir="${mirror.dir}/tar/bz2" />
+    <touch file="${mirror.dir}/asf-logo.gif.md5"/>
+    <touch file="${mirror.dir}/asf-logo.gif.bz2"/>
+    <sleep seconds="2"/>
+    <touch file="${mirror.dir}/zip/asf-logo.gif.zip"/>
+    <sleep seconds="3"/>
+    <touch file="${mirror.dir}/tar/asf-logo.gif.tar"/>
+    <sleep seconds="2"/>
+    <touch file="${mirror.dir}/tar/asf-logo-huge.tar.gz"/>
+    <touch file="${mirror.dir}/tar/gz/asf-logo.gif.tar.gz"/>
+    <touch file="${mirror.dir}/tar/bz2/asf-logo.gif.tar.bz2"/>
+    <touch file="${mirror.dir}/tar/bz2/asf-logo-huge.tar.bz2"/>
+  </target>
+
+  <target name="cleanup.mirrorfiles">
+    <delete dir="${mirror.dir}" />
+  </target>
+
+  <target name="cleanupregexp">
+    <delete dir="${testregexpsrc.dir}" />
+    <delete dir="${testregexpdest.dir}" />
+  </target>
+
+  <target name="containsregexp">
+    <mkdir dir="${testregexpsrc.dir}" />
+    <mkdir dir="${testregexpdest.dir}" />
+    <!-- Make two test files, shouldcopy.txt will get selected if everything works
+         shouldnotcopy.txt will not get selected for copy.  The test looks to see
+         that only one file is copied
+    -->
+    <echo message="Some testregexp text 2.0" file="${testregexpsrc.dir}/shouldcopy.txt" />
+    <echo message="Some testregexp text 20" file="${testregexpsrc.dir}/shouldnotcopy.txt" />
+    <copy todir="${testregexpdest.dir}">
+      <fileset dir="${testregexpsrc.dir}">
+        <include name="*.txt" />
+        <containsregexp expression="[0-9]\.[0,1,2]" />
+      </fileset>
+    </copy>
+  </target>
+
+  <!-- ==========  Test for ModifiedSelector  ========== -->
+
+  <target name="modifiedselectortest-makeDirty">
+      <!-- Load propertyfile generated by SelectorTest-class -->
+      <property file="ModifiedSelectorTest.properties"/>
+
+      <!-- Modify only timestamp -->
+      <touch file="${test.dir}/${f2name}" datetime="02/28/2003 9:55 AM"/>
+      <!-- Change content but keep timestamp -->
+      <echo file="${test.dir}/${f3name}" append="true" message="new content"/>
+      <touch file="${test.dir}/${f3name}" datetime="11/21/2001 4:55 AM"/>
+      <!-- Change content and timestamp -->
+      <echo file="${test.dir}/${f4name}" append="true" message="new content"/>
+  </target>
+
+  <target name="modifiedselectortest-scenario-clean">
+      <delete dir="${test.dir}"/>
+  </target>
+
+  <target name="modifiedselectortest-scenario-prepare">
+      <mkdir dir="${test.dir}/src"/>
+      <copy todir="${test.dir}/src">
+          <fileset dir="${ant.home}/lib" includes="ant.jar">
+              <type type="file"/>
+          </fileset>
+          <fileset dir="${ant.home}/bin">
+                <type type="file"/>
+          </fileset>
+      </copy>
+      <touch datetime="12/24/2002 4:00 pm">
+          <fileset dir="${test.dir}"/>
+      </touch>
+      <mkdir dir="${test.dir}/to-1"/>
+      <mkdir dir="${test.dir}/to-2"/>
+      <mkdir dir="${test.dir}/to-3"/>
+  </target>
+
+  <target name="modifiedselectortest-scenario-makeDirty">
+      <touch file="${test.dir}/src/ant.jar"/>
+      <echo file="${test.dir}/src/ant.bat" append="true" message="new-content"/>
+      <echo file="${test.dir}/src/antRun.pl" append="true" message="new-content"/>
+      <touch file="${test.dir}/src/antRun.pl" datetime="12/24/2002 4:00 pm"/>
+  </target>
+
+  <target name="modifiedselectortest-scenario-coreselector-defaults" depends="modifiedselectortest-scenario-prepare">
+      <!-- copy first time and create cachefile -->
+      <copy todir="${test.dir}/to-1">
+          <fileset dir="${test.dir}/src">
+              <modified/>
+          </fileset>
+      </copy>
+      <!-- copy second time: nothing should be copied -->
+      <copy todir="${test.dir}/to-2">
+          <fileset dir="${test.dir}/src">
+              <modified/>
+          </fileset>
+      </copy>
+      <!-- 'modify' the source files -->
+      <antcall target="modifiedselectortest-scenario-makeDirty"/>
+      <!-- copy third time: only the files with new CONTENT should be copied -->
+      <copy todir="${test.dir}/to-3">
+          <fileset dir="${test.dir}/src">
+              <modified/>
+          </fileset>
+      </copy>
+  </target>
+
+  <target name="modifiedselectortest-scenario-coreselector-settings" depends="modifiedselectortest-scenario-prepare">
+      <!-- copy first time and create cachefile -->
+      <copy todir="${test.dir}/to-1">
+          <fileset dir="${test.dir}/src">
+              <modified cache="propertyfile" algorithm="hashvalue" update="true">
+                  <param name="cache.cachefile" value="core.cache.properties" />
+              </modified>
+          </fileset>
+      </copy>
+      <!-- copy second time: nothing should be copied -->
+      <copy todir="${test.dir}/to-2">
+          <fileset dir="${test.dir}/src">
+              <modified cache="propertyfile" algorithm="hashvalue" update="true">
+                  <param name="cache.cachefile" value="core.cache.properties" />
+              </modified>
+          </fileset>
+      </copy>
+      <!-- 'modify' the source files -->
+      <antcall target="modifiedselectortest-scenario-makeDirty"/>
+      <!-- copy third time: only the files with new CONTENT should be copied -->
+      <copy todir="${test.dir}/to-3">
+          <fileset dir="${test.dir}/src">
+              <modified cache="propertyfile" algorithm="hashvalue" update="true">
+                  <param name="cache.cachefile" value="core.cache.properties" />
+              </modified>
+          </fileset>
+      </copy>
+  </target>
+
+  <target name="modifiedselectortest-scenario-customselector-settings" depends="modifiedselectortest-scenario-prepare">
+      <!-- copy first time and create cachefile -->
+      <copy todir="${test.dir}/to-1">
+          <fileset dir="${test.dir}/src">
+              <custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector">
+                  <param name="cache"      value="propertyfile"/>
+                  <param name="algorithm"  value="hashvalue"/>
+                  <param name="update"     value="true"/>
+                  <param name="cache.cachefile" value="core.cache.properties"/>
+              </custom>
+          </fileset>
+      </copy>
+      <!-- copy second time: nothing should be copied -->
+      <copy todir="${test.dir}/to-2">
+          <fileset dir="${test.dir}/src">
+              <custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector">
+                  <param name="cache"      value="propertyfile"/>
+                  <param name="algorithm"  value="hashvalue"/>
+                  <param name="update"     value="true"/>
+                  <param name="cache.cachefile" value="core.cache.properties"/>
+              </custom>
+          </fileset>
+      </copy>
+      <!-- 'modify' the source files -->
+      <antcall target="modifiedselectortest-scenario-makeDirty"/>
+      <!-- copy third time: only the files with new CONTENT should be copied -->
+      <copy todir="${test.dir}/to-3">
+          <fileset dir="${test.dir}/src">
+              <custom classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector">
+                  <param name="cache"      value="propertyfile"/>
+                  <param name="algorithm"  value="hashvalue"/>
+                  <param name="update"     value="true"/>
+                  <param name="cache.cachefile" value="core.cache.properties"/>
+              </custom>
+          </fileset>
+      </copy>
+  </target>
+
+  <target name="modifiedselectortest-customClasses" depends="modifiedselectortest-scenario-prepare">
+      <property name="pkg.live" value="org.apache.tools.ant.types.selectors.modifiedselector"/>
+      <property name="pkg.test" value="org.apache.tools.ant.types.selectors"/>
+      <fileset id="fs.mod" dir="${test.dir}/src">
+          <modified
+              algorithmclass="${pkg.test}.MockAlgorithm"
+              cacheclass="${pkg.test}.MockCache"
+              comparatorclass="${pkg.test}.MockComparator"
+          >
+              <classpath>
+                  <pathelement location="${build.tests.value}"/>
+              </classpath>
+          </modified>
+      </fileset>
+      <fileset id="fs.full" dir="${test.dir}/src"/>
+      <property name="fs.mod.value"  refid="fs.mod"/>
+      <property name="fs.full.value" refid="fs.full"/>
+  </target>
+
+  <target name="modifiedselectortest-ResourceSimple">
+    <fail message="Didnt get the required numbers of Resources.">
+      <condition>
+        <not>
+          <resourcecount when="equal" count="3">
+            <restrict>
+              <resources>
+                <file file="foo" />
+                <resource name="foo" />
+                <file file="foo" basedir="${basedir}" />
+              </resources>
+              <modified selres="true" xmlns="antlib:org.apache.tools.ant.types.resources.selectors"/>
+            </restrict>
+          </resourcecount>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="modifiedselectortest-ResourceSelresTrue">
+    <fail message="Got the Resource, but should.">
+      <condition>
+        <not>
+          <resourcecount when="equal" count="1">
+            <restrict>
+              <resources>
+                <resource name="notExisting" />
+              </resources>
+              <modified selres="true" xmlns="antlib:org.apache.tools.ant.types.resources.selectors"/>
+            </restrict>
+          </resourcecount>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="modifiedselectortest-ResourceSelresFalse">
+    <fail message="Got the Resource, but should not.">
+      <condition>
+        <not>
+          <resourcecount when="equal" count="0">
+            <restrict>
+              <resources>
+                <resource name="notExisting" />
+              </resources>
+              <modified selres="false" xmlns="antlib:org.apache.tools.ant.types.resources.selectors"/>
+            </restrict>
+          </resourcecount>
+        </not>
+      </condition>
+    </fail>
+  </target>
+
+  <target name="modifiedselectortest-scenario-resourceSimple" depends="modifiedselectortest-scenario-prepare">
+    <macrodef name="check">
+      <attribute name="count"/>
+      <attribute name="message"/>
+      <sequential>
+        <fail message="@{message}">
+          <condition>
+            <not>
+              <resourcecount when="equal" count="@{count}">
+                <restrict>
+                  <resources>
+                    <fileset dir="${test.dir}/src"/>
+                  </resources>
+                  <modified selres="false" xmlns="antlib:org.apache.tools.ant.types.resources.selectors"/>
+                </restrict>
+              </resourcecount>
+            </not>
+          </condition>
+        </fail>	
+      </sequential>
+    </macrodef>
+    <!-- select first time and create cachefile -->
+    <check count="14" message="Initial set of files not ok."/>
+
+    <!-- check second time: nothing should be selected -->
+    <check count="0" message="Selected files but shouldnt."/>
+
+    <!-- 'modify' the source files -->
+    <antcall target="modifiedselectortest-scenario-makeDirty"/>
+
+    <!-- copy third time: only the files with new CONTENT should be copied -->
+    <check count="2" message="Didnt select the 2 modified files."/>
+  </target>	
+
+</project>
diff --git a/trunk/src/etc/testcases/types/selectors/scriptselector.xml b/trunk/src/etc/testcases/types/selectors/scriptselector.xml
new file mode 100644
index 0000000..80afe30
--- /dev/null
+++ b/trunk/src/etc/testcases/types/selectors/scriptselector.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="scriptselector" default="def" basedir=".">
+
+  <property name="src.file" location="${ant.file}" />
+  
+  <macrodef name="testselected">
+    <element name="selector" implicit="yes" optional="true"/>
+    <attribute name="message"/>
+    <sequential>
+      <fail message="@{message} failed: file was not selected">
+        <condition>
+          <not>
+            <isfileselected file="{src.file}">
+              <selector/>
+            </isfileselected>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>  
+  
+  <macrodef name="testnoselected">
+    <element name="selector" implicit="yes" optional="true"/>
+    <attribute name="message"/>
+    <sequential>
+      <fail message="@{message} failed: file was selected">
+        <condition>
+          <isfileselected file="{src.file}">
+            <selector/>
+          </isfileselected>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>    
+
+  <!-- this is here to test the macro is well coded -->
+  <target name="testNoSelector">
+    <testselected message="testNoSelector" >
+    </testselected>
+  </target>
+
+  <target name="testNolanguage">
+    <testselected message="testNolanguage" >
+      <selector>
+        <scriptselector >
+          self.setSelected(true);
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>
+
+  <target name="testSelectionSetByDefault">
+    <testselected message="testSelectionSetByDefault" >
+      <selector>
+        <scriptselector language="javascript">
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>
+
+
+  <target name="testSelectionSetWorks">
+    <testselected message="testSelectionSetWorks" >
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected(false);
+          self.setSelected(true);
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>
+
+  <target name="testSelectionClearWorks">
+    <testnoselected message="testSelectionClearWorks">
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected(false);
+        </scriptselector>
+      </selector>
+    </testnoselected>
+  </target>
+  
+  <target name="testFileAttribute">
+    <testselected message="testFileAttribute" >
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected(file.equals(self.getFile()));
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>  
+
+  <target name="testFilenameAttribute">
+    <testselected message="testFilenameAttribute" >
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected(filename.equals(self.getFilename()));
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>    
+  
+  <target name="testBasedirAttribute">
+    <testselected message="testBasedirAttribute" >
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected(basedir.equals(self.getBasedir()));
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>
+  
+  <target name="notestFilenameLength">
+    <testselected message="notestFilenameLength" >
+      <selector>
+        <scriptselector language="javascript">
+          self.setSelected((filename.length%2)==0);
+        </scriptselector>
+      </selector>
+    </testselected>
+  </target>    
+</project>
diff --git a/trunk/src/etc/testcases/types/selectors/signedselector.xml b/trunk/src/etc/testcases/types/selectors/signedselector.xml
new file mode 100644
index 0000000..60fe940
--- /dev/null
+++ b/trunk/src/etc/testcases/types/selectors/signedselector.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <macrodef name="pass">
+    <element name="conditions" implicit="yes"/>
+    <attribute name="failmessage"/>
+    <sequential>
+      <fail message="@{failmessage}">
+        <condition>
+          <not>
+            <conditions/>
+          </not>
+        </condition>
+      </fail>
+    </sequential>
+  </macrodef>
+
+  <property name="issigned.dir" location="../../taskdefs/conditions/jars"/>
+  
+  <target name="selectsigned">
+    <pass failmessage="apassword.jar should be a signed file">
+      <isfileselected file="${issigned.dir}/apassword.jar">
+        <signedselector/>
+      </isfileselected>
+    </pass>
+  </target>
+
+  <target name="notselected">
+    <pass failmessage="nosign.jar should not be selected as a signed jar">
+      <not>
+        <isfileselected file="${issigned.dir}/nosign.jar">
+          <signedselector/>
+        </isfileselected>
+      </not>
+    </pass>
+  </target>
+
+  <target name="name">
+    <pass failmessage="apassword.jar should be a signed file with the name apassword">
+      <isfileselected file="${issigned.dir}/apassword.jar">
+        <signedselector name="apassword"/>
+      </isfileselected>
+    </pass>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/xmlcatalog.xml b/trunk/src/etc/testcases/types/xmlcatalog.xml
new file mode 100644
index 0000000..63269f7
--- /dev/null
+++ b/trunk/src/etc/testcases/types/xmlcatalog.xml
@@ -0,0 +1,150 @@
+<?xml version='1.0'?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE project>
+
+<project name="xmlcatalog" default="all" basedir=".">
+
+  <description>
+    This is to test XMLCatalog for external entity resolution from the
+    xslt task, both the simple case and using the document() function
+    to refer to a second file (which refers to the entity). This
+    buildfile is called by
+    org.apache.tools.ant.types.XMLCatalogBuildFileTest.java
+    Alternatively, you may try it out by hand by first removing the
+    comment symbols around the echo statements and then calling 
+    ant -buildfile xmlcatalog.xml
+  </description>
+
+  <property name="transformer" value = "xmlcatalog.xsl"/>
+
+  <target 
+    name    = "all" 
+    depends = "testentitynocatalog, testentitywithcatalog, 
+    testdocumentnocatalog, testdocumentwithcatalog"/>
+
+  <target 
+    name        = "testentitynocatalog"
+    description = "Test external entity resolver for simple XML
+document without using XMLCatalog">
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+    <xslt
+      basedir   = "${basedir}"
+      destdir   = "${basedir}"
+      extension = ".text"
+      style     = "${transformer}"
+      in        = "xmlcatalog1.xml"
+      out       = "result.out">
+      <param
+        name       = "outprop"
+        expression = "val1"/>
+    </xslt>
+    <property file = "result.out"/>
+    <!-- <echo message = "${val1}"/> -->
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+  </target>
+
+  <target 
+    name        = "testentitywithcatalog"
+    description = "Test external entity resolver for simple
+XML document using XMLCatalog">
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+    <xslt
+      basedir   = "${basedir}"
+      destdir   = "${basedir}"
+      extension = ".text"
+      style     = "${transformer}"
+      in        = "xmlcatalog1.xml"
+      out       = "result.out">
+      <param
+        name       = "outprop"
+        expression = "val2"/>
+      <xmlcatalog>
+        <entity 
+          publicId = "myquote"
+          location = "quote2.xml"/>
+      </xmlcatalog>
+    </xslt>
+    <property file = "result.out"/>
+    <!-- <echo message = "${val2}"/> -->
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+  </target>
+
+  <target 
+    name        = "testdocumentnocatalog"
+    description = "Test entity resolution in XML document called
+from XSLT document() function without using XMLCatalog">
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+    <xslt
+      basedir   = "${basedir}"
+      destdir   = "${basedir}"
+      extension = ".text"
+      style     = "${transformer}"
+      in        = "xmlcatalog2.xml"
+      out       = "result.out">
+      <param
+        name       = "outprop"
+        expression = "val3"/>
+    </xslt>
+    <property file = "result.out"/>
+    <!-- <echo message = "${val3}"/> -->
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+  </target>
+
+  <target 
+    name        = "testdocumentwithcatalog" 
+    description = "Test entity resolution in XML document called
+from XSLT document() function using XMLCatalog">
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+    <xslt
+      basedir   = "${basedir}"
+      destdir   = "${basedir}"
+      extension = ".text"
+      style     = "${transformer}"
+      in        = "xmlcatalog2.xml"
+      out       = "result.out">
+      <param
+        name       = "outprop"
+        expression = "val4"/>
+      <xmlcatalog>
+        <entity 
+          publicId = "myquote"
+          location = "quote2.xml"/>
+      </xmlcatalog>
+    </xslt>
+    <property file = "result.out"/>
+    <!-- <echo message = "${val4}"/> -->
+    <delete
+      quiet = "yes"
+      file  = "result.out"/>
+  </target>
+
+</project>
diff --git a/trunk/src/etc/testcases/types/xmlcatalog.xsl b/trunk/src/etc/testcases/types/xmlcatalog.xsl
new file mode 100644
index 0000000..a2c839c
--- /dev/null
+++ b/trunk/src/etc/testcases/types/xmlcatalog.xsl
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<xsl:stylesheet 
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  version="1.0">
+
+  <!-- I belong to:
+       org.apache.tools.ant.types.XMLCatalogBuildFileTest.java 
+       -->
+
+  <xsl:output method="text"/>
+
+  <!-- name of the output parameter to write -->
+  <xsl:param name="outprop">value</xsl:param>
+
+  <xsl:strip-space elements="*"/>
+
+  <xsl:template match="/">
+    <xsl:value-of select="$outprop"/>: <xsl:apply-templates select="/fragment/para"/>
+  </xsl:template>
+
+  <!-- This will only be matched in doc2.xml -->
+  <xsl:template match="Ref">
+    <xsl:apply-templates select="document(@file)/fragment/para"/>
+  </xsl:template>
+
+  <!-- This will only be matched in doc1.xml -->
+  <xsl:template match="text()">
+    <xsl:value-of select="normalize-space(.)"/>
+  </xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/etc/testcases/types/xmlcatalog1.xml b/trunk/src/etc/testcases/types/xmlcatalog1.xml
new file mode 100644
index 0000000..d4b5461
--- /dev/null
+++ b/trunk/src/etc/testcases/types/xmlcatalog1.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE fragment [
+  <!ENTITY quote PUBLIC "myquote" "quote1.xml">
+]>
+
+  <!-- I belong to:
+       org.apache.tools.ant.types.XMLCatalogBuildFileTest.java 
+       -->
+
+<fragment>
+  <para>
+      &quote;
+  </para>
+</fragment>
diff --git a/trunk/src/etc/testcases/types/xmlcatalog2.xml b/trunk/src/etc/testcases/types/xmlcatalog2.xml
new file mode 100644
index 0000000..9d2bed0
--- /dev/null
+++ b/trunk/src/etc/testcases/types/xmlcatalog2.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+  <!-- I belong to:
+       org.apache.tools.ant.types.XMLCatalogBuildFileTest.java 
+       -->
+
+<fragment>
+  <para>
+    <Ref file="xmlcatalog1.xml"/>
+  </para>
+</fragment>
diff --git a/trunk/src/etc/testcases/types/xmlfragment.xml b/trunk/src/etc/testcases/types/xmlfragment.xml
new file mode 100644
index 0000000..75214d6
--- /dev/null
+++ b/trunk/src/etc/testcases/types/xmlfragment.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project>
+  <typedef name="fragment"
+           classname="org.apache.tools.ant.util.XMLFragment"/>
+
+  <fragment id="nested-text">foo</fragment>
+
+  <fragment id="with-children">
+    <child1>foo</child1>
+    <child2 foo="bar"/>
+    <child3>
+      <child4/>
+    </child3>
+  </fragment>
+</project>
diff --git a/trunk/src/etc/yearcheck.sh b/trunk/src/etc/yearcheck.sh
new file mode 100755
index 0000000..1a510ff
--- /dev/null
+++ b/trunk/src/etc/yearcheck.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Simple shell script that checks whether changed files contain a copyright
+# statement for a given year.
+#
+# Rename (or symlink) this script to the year you want to check, i.e. name it
+# 2002 if you want to check for copyright statements that do not contain
+# the year 2002.
+#
+# Use this script instead of your usual cvs update command.
+#
+# Usage YEAR [precommit]
+#
+# If the optional all argument has been omitted, the proposal directory will
+# be skipped.
+#
+
+if [ -n "$TMP" ]; then
+  TEMP_DIR="$TMP"
+else
+  if [ -n "$TEMP" ]; then
+    TEMP_DIR="$TEMP"
+  else
+    TEMP_DIR=/tmp
+  fi
+fi
+
+YEAR=`basename $0`
+
+if [ $YEAR = yearcheck.sh ]; then
+    YEAR=`date -R | cut -d ' ' -f 4`
+fi
+
+precommit_call=false
+for arg in "$@" ; do
+  if [ "$arg" = "precommit" ] ; then
+    precommit_call=true
+  fi
+done
+
+if [ -d ".svn" ]; then
+  SCM_COMMAND=svn
+  if $precommit_call ; then
+    SCM_ARGS=status
+    CUT_ARGS="-c 8-"
+  else
+    SCM_ARGS=up
+    CUT_ARGS="-c 4-"
+  fi
+else
+  SCM_COMMAND=cvs
+  SCM_ARGS="-z3 update -dP"
+  CUT_ARGS="-d ' ' -f 2"
+fi
+
+"$SCM_COMMAND" $SCM_ARGS > "$TEMP_DIR"/update-prefilter
+
+# filter out boring lines
+if [ "$SCM_COMMAND" = "svn" ]; then
+  < "$TEMP_DIR"/update-prefilter fgrep -v 'At revision' | fgrep -v 'Updated to revision' | egrep -v '^\?' > "$TEMP_DIR"/update
+else
+  cp "$TEMP_DIR"/update-prefilter "$TEMP_DIR"/update
+fi
+
+cut $CUT_ARGS < "$TEMP_DIR"/update > "$TEMP_DIR"/changed-files
+
+echo "Changed:"
+echo "========"
+cat "$TEMP_DIR"/changed-files
+echo
+
+xargs fgrep -L Copyright < "$TEMP_DIR"/changed-files > "$TEMP_DIR"/no-copyright
+
+echo "No Copyright line"
+echo "================="
+cat "$TEMP_DIR"/no-copyright
+echo
+
+xargs egrep -L "Copyright.*$YEAR" < "$TEMP_DIR"/changed-files | cut -f 1 -d : > "$TEMP_DIR"/no-$YEAR
+
+echo "No Copyright line for year $YEAR"
+echo "================================"
+cat "$TEMP_DIR"/no-$YEAR
+
+rm "$TEMP_DIR"/no-$YEAR "$TEMP_DIR"/no-copyright "$TEMP_DIR"/changed-files "$TEMP_DIR"/update "$TEMP_DIR"/update-prefilter
diff --git a/trunk/src/main/org/apache/tools/ant/AntClassLoader.java b/trunk/src/main/org/apache/tools/ant/AntClassLoader.java
new file mode 100644
index 0000000..cd9206f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/AntClassLoader.java
@@ -0,0 +1,1461 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Locale;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.CollectionUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.launch.Locator;
+
+/**
+ * Used to load classes within ant with a different classpath from
+ * that used to start ant. Note that it is possible to force a class
+ * into this loader even when that class is on the system classpath by
+ * using the forceLoadClass method. Any subsequent classes loaded by that
+ * class will then use this loader rather than the system class loader.
+ *
+ * <p>
+ * Note that this classloader has a feature to allow loading
+ * in reverse order and for "isolation".
+ * Due to the fact that a number of
+ * methods in java.lang.ClassLoader are final (at least
+ * in java 1.4 getResources) this means that the
+ * class has to fake the given parent.
+ * </p>
+ *
+ */
+public class AntClassLoader extends ClassLoader implements SubBuildListener {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * An enumeration of all resources of a given name found within the
+     * classpath of this class loader. This enumeration is used by the
+     * ClassLoader.findResources method, which is in
+     * turn used by the ClassLoader.getResources method.
+     *
+     * @see AntClassLoader#findResources(String)
+     * @see java.lang.ClassLoader#getResources(String)
+     */
+    private class ResourceEnumeration implements Enumeration {
+        /**
+         * The name of the resource being searched for.
+         */
+        private String resourceName;
+
+        /**
+         * The index of the next classpath element to search.
+         */
+        private int pathElementsIndex;
+
+        /**
+         * The URL of the next resource to return in the enumeration. If this
+         * field is <code>null</code> then the enumeration has been completed,
+         * i.e., there are no more elements to return.
+         */
+        private URL nextResource;
+
+        /**
+         * Constructs a new enumeration of resources of the given name found
+         * within this class loader's classpath.
+         *
+         * @param name the name of the resource to search for.
+         */
+        ResourceEnumeration(String name) {
+            this.resourceName = name;
+            this.pathElementsIndex = 0;
+            findNextResource();
+        }
+
+        /**
+         * Indicates whether there are more elements in the enumeration to
+         * return.
+         *
+         * @return <code>true</code> if there are more elements in the
+         *         enumeration; <code>false</code> otherwise.
+         */
+        public boolean hasMoreElements() {
+            return (this.nextResource != null);
+        }
+
+        /**
+         * Returns the next resource in the enumeration.
+         *
+         * @return the next resource in the enumeration
+         */
+        public Object nextElement() {
+            URL ret = this.nextResource;
+            findNextResource();
+            return ret;
+        }
+
+        /**
+         * Locates the next resource of the correct name in the classpath and
+         * sets <code>nextResource</code> to the URL of that resource. If no
+         * more resources can be found, <code>nextResource</code> is set to
+         * <code>null</code>.
+         */
+        private void findNextResource() {
+            URL url = null;
+            while ((pathElementsIndex < pathComponents.size()) && (url == null)) {
+                try {
+                    File pathComponent = (File) pathComponents.elementAt(pathElementsIndex);
+                    url = getResourceURL(pathComponent, this.resourceName);
+                    pathElementsIndex++;
+                } catch (BuildException e) {
+                    // ignore path elements which are not valid relative to the
+                    // project
+                }
+            }
+            this.nextResource = url;
+        }
+    }
+
+    /**
+     * The size of buffers to be used in this classloader.
+     */
+    private static final int BUFFER_SIZE = 8192;
+
+    /**
+     * Number of array elements in a test array of strings
+     */
+    private static final int NUMBER_OF_STRINGS = 256;
+
+    /**
+     * The components of the classpath that the classloader searches
+     * for classes.
+     */
+    private Vector pathComponents  = new Vector();
+
+    /**
+     * The project to which this class loader belongs.
+     */
+    private Project project;
+
+    /**
+     * Indicates whether the parent class loader should be
+     * consulted before trying to load with this class loader.
+     */
+    private boolean parentFirst = true;
+
+    /**
+     * These are the package roots that are to be loaded by the parent class
+     * loader regardless of whether the parent class loader is being searched
+     * first or not.
+     */
+    private Vector systemPackages = new Vector();
+
+    /**
+     * These are the package roots that are to be loaded by this class loader
+     * regardless of whether the parent class loader is being searched first
+     * or not.
+     */
+    private Vector loaderPackages = new Vector();
+
+    /**
+     * Whether or not this classloader will ignore the base
+     * classloader if it can't find a class.
+     *
+     * @see #setIsolated(boolean)
+     */
+    private boolean ignoreBase = false;
+
+    /**
+     * The parent class loader, if one is given or can be determined.
+     */
+    private ClassLoader parent = null;
+
+    /**
+     * A hashtable of zip files opened by the classloader (File to ZipFile).
+     */
+    private Hashtable zipFiles = new Hashtable();
+
+    /** Static map of jar file/time to manifest class-path entries */
+    private static Map/*<String,String>*/ pathMap = Collections.synchronizedMap(new HashMap());
+
+    /**
+     * The context loader saved when setting the thread's current
+     * context loader.
+     */
+    private ClassLoader savedContextLoader = null;
+
+    /**
+     * Whether or not the context loader is currently saved.
+     */
+    private boolean isContextLoaderSaved = false;
+
+    /**
+     * Create an Ant ClassLoader for a given project, with
+     * a parent classloader and an initial classpath.
+     * @since Ant 1.7.
+     * @param parent the parent for this classloader.
+     * @param project The project to which this classloader is to
+     *                belong.
+     * @param classpath The classpath to use to load classes.
+     */
+    public AntClassLoader(ClassLoader parent, Project project, Path classpath) {
+        setParent(parent);
+        setClassPath(classpath);
+        setProject(project);
+    }
+
+    /**
+     * Create an Ant Class Loader
+     */
+    public AntClassLoader() {
+        setParent(null);
+    }
+
+    /**
+     * Creates a classloader for the given project using the classpath given.
+     *
+     * @param project The project to which this classloader is to belong.
+     *                Must not be <code>null</code>.
+     * @param classpath The classpath to use to load the classes.  This
+     *                is combined with the system classpath in a manner
+     *                determined by the value of ${build.sysclasspath}.
+     *                May be <code>null</code>, in which case no path
+     *                elements are set up to start with.
+     */
+    public AntClassLoader(Project project, Path classpath) {
+        setParent(null);
+        setProject(project);
+        setClassPath(classpath);
+    }
+
+    /**
+     * Creates a classloader for the given project using the classpath given.
+     *
+     * @param parent The parent classloader to which unsatisfied loading
+     *               attempts are delegated. May be <code>null</code>,
+     *               in which case the classloader which loaded this
+     *               class is used as the parent.
+     * @param project The project to which this classloader is to belong.
+     *                Must not be <code>null</code>.
+     * @param classpath the classpath to use to load the classes.
+     *                  May be <code>null</code>, in which case no path
+     *                  elements are set up to start with.
+     * @param parentFirst If <code>true</code>, indicates that the parent
+     *                    classloader should be consulted  before trying to
+     *                    load the a class through this loader.
+     */
+    public AntClassLoader(
+        ClassLoader parent, Project project, Path classpath, boolean parentFirst) {
+        this(project, classpath);
+        if (parent != null) {
+            setParent(parent);
+        }
+        setParentFirst(parentFirst);
+        addJavaLibraries();
+    }
+
+    /**
+     * Creates a classloader for the given project using the classpath given.
+     *
+     * @param project The project to which this classloader is to belong.
+     *                Must not be <code>null</code>.
+     * @param classpath The classpath to use to load the classes. May be
+     *                  <code>null</code>, in which case no path
+     *                  elements are set up to start with.
+     * @param parentFirst If <code>true</code>, indicates that the parent
+     *                    classloader should be consulted before trying to
+     *                    load the a class through this loader.
+     */
+    public AntClassLoader(Project project, Path classpath, boolean parentFirst) {
+        this(null, project, classpath, parentFirst);
+    }
+
+    /**
+     * Creates an empty class loader. The classloader should be configured
+     * with path elements to specify where the loader is to look for
+     * classes.
+     *
+     * @param parent The parent classloader to which unsatisfied loading
+     *               attempts are delegated. May be <code>null</code>,
+     *               in which case the classloader which loaded this
+     *               class is used as the parent.
+     * @param parentFirst If <code>true</code>, indicates that the parent
+     *                    classloader should be consulted before trying to
+     *                    load the a class through this loader.
+     */
+    public AntClassLoader(ClassLoader parent, boolean parentFirst) {
+        setParent(parent);
+        project = null;
+        this.parentFirst = parentFirst;
+    }
+
+    /**
+     * Set the project associated with this class loader
+     *
+     * @param project the project instance
+     */
+    public void setProject(Project project) {
+        this.project = project;
+        if (project != null) {
+            project.addBuildListener(this);
+        }
+    }
+
+    /**
+     * Set the classpath to search for classes to load. This should not be
+     * changed once the classloader starts to server classes
+     *
+     * @param classpath the search classpath consisting of directories and
+     *        jar/zip files.
+     */
+    public void setClassPath(Path classpath) {
+        pathComponents.removeAllElements();
+        if (classpath != null) {
+            Path actualClasspath = classpath.concatSystemClasspath("ignore");
+            String[] pathElements = actualClasspath.list();
+            for (int i = 0; i < pathElements.length; ++i) {
+                try {
+                    addPathElement(pathElements[i]);
+                } catch (BuildException e) {
+                    // ignore path elements which are invalid
+                    // relative to the project
+                }
+            }
+        }
+    }
+
+    /**
+     * Set the parent for this class loader. This is the class loader to which
+     * this class loader will delegate to load classes
+     *
+     * @param parent the parent class loader.
+     */
+    public void setParent(ClassLoader parent) {
+        this.parent = parent == null ? AntClassLoader.class.getClassLoader() : parent;
+    }
+
+    /**
+     * Control whether class lookup is delegated to the parent loader first
+     * or after this loader. Use with extreme caution. Setting this to
+     * false violates the class loader hierarchy and can lead to Linkage errors
+     *
+     * @param parentFirst if true, delegate initial class search to the parent
+     *                    classloader.
+     */
+    public void setParentFirst(boolean parentFirst) {
+        this.parentFirst = parentFirst;
+    }
+
+    /**
+     * Logs a message through the project object if one has been provided.
+     *
+     * @param message The message to log.
+     *                Should not be <code>null</code>.
+     *
+     * @param priority The logging priority of the message.
+     */
+    protected void log(String message, int priority) {
+        if (project != null) {
+            project.log(message, priority);
+        }
+    }
+
+    /**
+     * Sets the current thread's context loader to this classloader, storing
+     * the current loader value for later resetting.
+     */
+    public void setThreadContextLoader() {
+        if (isContextLoaderSaved) {
+            throw new BuildException("Context loader has not been reset");
+        }
+        if (LoaderUtils.isContextLoaderAvailable()) {
+            savedContextLoader = LoaderUtils.getContextClassLoader();
+            ClassLoader loader = this;
+            if (project != null && "only".equals(project.getProperty("build.sysclasspath"))) {
+                loader = this.getClass().getClassLoader();
+            }
+            LoaderUtils.setContextClassLoader(loader);
+            isContextLoaderSaved = true;
+        }
+    }
+
+    /**
+     * Resets the current thread's context loader to its original value.
+     */
+    public void resetThreadContextLoader() {
+        if (LoaderUtils.isContextLoaderAvailable() && isContextLoaderSaved) {
+            LoaderUtils.setContextClassLoader(savedContextLoader);
+            savedContextLoader = null;
+            isContextLoaderSaved = false;
+        }
+    }
+
+
+    /**
+     * Adds an element to the classpath to be searched.
+     *
+     * @param pathElement The path element to add. Must not be
+     *                    <code>null</code>.
+     *
+     * @exception BuildException if the given path element cannot be resolved
+     *                           against the project.
+     */
+    public void addPathElement(String pathElement) throws BuildException {
+        File pathComponent = project != null ? project.resolveFile(pathElement) : new File(
+                pathElement);
+        try {
+            addPathFile(pathComponent);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Add a path component.
+     * This simply adds the file, unlike addPathElement
+     * it does not open jar files and load files from
+     * their CLASSPATH entry in the manifest file.
+     * @param file the jar file or directory to add.
+     */
+    public void addPathComponent(File file) {
+        if (pathComponents.contains(file)) {
+            return;
+        }
+        pathComponents.addElement(file);
+    }
+
+    /**
+     * Add a file to the path.
+     * Reads the manifest, if available, and adds any additional class path jars
+     * specified in the manifest.
+     *
+     * @param pathComponent the file which is to be added to the path for
+     *                      this class loader
+     *
+     * @throws IOException if data needed from the file cannot be read.
+     */
+    protected void addPathFile(File pathComponent) throws IOException {
+        pathComponents.addElement(pathComponent);
+        if (pathComponent.isDirectory()) {
+            return;
+        }
+
+        String absPathPlusTimeAndLength = pathComponent.getAbsolutePath()
+                + pathComponent.lastModified() + "-" + pathComponent.length();
+        String classpath = (String) pathMap.get(absPathPlusTimeAndLength);
+        if (classpath == null) {
+            ZipFile jarFile = null;
+            InputStream manifestStream = null;
+            try {
+                jarFile = new ZipFile(pathComponent);
+                manifestStream = jarFile.getInputStream(new ZipEntry("META-INF/MANIFEST.MF"));
+
+                if (manifestStream == null) {
+                    return;
+                }
+                Reader manifestReader = new InputStreamReader(manifestStream, "UTF-8");
+                org.apache.tools.ant.taskdefs.Manifest manifest
+                        = new org.apache.tools.ant.taskdefs.Manifest(manifestReader);
+                classpath = manifest.getMainSection().getAttributeValue("Class-Path");
+            } catch (org.apache.tools.ant.taskdefs.ManifestException e) {
+                // ignore
+            } finally {
+                FileUtils.close(manifestStream);
+                if (jarFile != null) {
+                    jarFile.close();
+                }
+            }
+            if (classpath == null) {
+                classpath = "";
+            }
+            pathMap.put(absPathPlusTimeAndLength, classpath);
+        }
+
+        if (!"".equals(classpath)) {
+            URL baseURL = FILE_UTILS.getFileURL(pathComponent);
+            StringTokenizer st = new StringTokenizer(classpath);
+            while (st.hasMoreTokens()) {
+                String classpathElement = st.nextToken();
+                URL libraryURL = new URL(baseURL, classpathElement);
+                if (!libraryURL.getProtocol().equals("file")) {
+                    log("Skipping jar library " + classpathElement
+                            + " since only relative URLs are supported by this" + " loader",
+                            Project.MSG_VERBOSE);
+                    continue;
+                }
+                String decodedPath = Locator.decodeUri(libraryURL.getFile());
+                File libraryFile = new File(decodedPath);
+                if (libraryFile.exists() && !isInPath(libraryFile)) {
+                    addPathFile(libraryFile);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the classpath this classloader will consult.
+     *
+     * @return the classpath used for this classloader, with elements
+     *         separated by the path separator for the system.
+     */
+    public String getClasspath() {
+        StringBuffer sb = new StringBuffer();
+        boolean firstPass = true;
+        Enumeration componentEnum = pathComponents.elements();
+        while (componentEnum.hasMoreElements()) {
+            if (!firstPass) {
+                sb.append(System.getProperty("path.separator"));
+            } else {
+                firstPass = false;
+            }
+            sb.append(((File) componentEnum.nextElement()).getAbsolutePath());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Sets whether this classloader should run in isolated mode. In
+     * isolated mode, classes not found on the given classpath will
+     * not be referred to the parent class loader but will cause a
+     * ClassNotFoundException.
+     *
+     * @param isolated Whether or not this classloader should run in
+     *                 isolated mode.
+     */
+    public synchronized void setIsolated(boolean isolated) {
+        ignoreBase = isolated;
+    }
+
+    /**
+     * Forces initialization of a class in a JDK 1.1 compatible, albeit hacky
+     * way.
+     *
+     * @param theClass The class to initialize.
+     *                 Must not be <code>null</code>.
+     *
+     * @deprecated since 1.6.x.
+     *             Use Class.forName with initialize=true instead.
+     */
+    public static void initializeClass(Class theClass) {
+        // ***HACK*** We ask the VM to create an instance
+        // by voluntarily providing illegal arguments to force
+        // the VM to run the class' static initializer, while
+        // at the same time not running a valid constructor.
+
+        final Constructor[] cons = theClass.getDeclaredConstructors();
+        //At least one constructor is guaranteed to be there, but check anyway.
+        if (cons != null) {
+            if (cons.length > 0 && cons[0] != null) {
+                final String[] strs = new String[NUMBER_OF_STRINGS];
+                try {
+                    cons[0].newInstance((Object[]) strs);
+                    // Expecting an exception to be thrown by this call:
+                    // IllegalArgumentException: wrong number of Arguments
+                } catch (Exception e) {
+                    // Ignore - we are interested only in the side
+                    // effect - that of getting the static initializers
+                    // invoked.  As we do not want to call a valid
+                    // constructor to get this side effect, an
+                    // attempt is made to call a hopefully
+                    // invalid constructor - come on, nobody
+                    // would have a constructor that takes in
+                    // 256 String arguments ;-)
+                    // (In fact, they can't - according to JVM spec
+                    // section 4.10, the number of method parameters is limited
+                    // to 255 by the definition of a method descriptor.
+                    // Constructors count as methods here.)
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds a package root to the list of packages which must be loaded on the
+     * parent loader.
+     *
+     * All subpackages are also included.
+     *
+     * @param packageRoot The root of all packages to be included.
+     *                    Should not be <code>null</code>.
+     */
+    public void addSystemPackageRoot(String packageRoot) {
+        systemPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : "."));
+    }
+
+    /**
+     * Adds a package root to the list of packages which must be loaded using
+     * this loader.
+     *
+     * All subpackages are also included.
+     *
+     * @param packageRoot The root of all packages to be included.
+     *                    Should not be <code>null</code>.
+     */
+    public void addLoaderPackageRoot(String packageRoot) {
+        loaderPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : "."));
+    }
+
+    /**
+     * Loads a class through this class loader even if that class is available
+     * on the parent classpath.
+     *
+     * This ensures that any classes which are loaded by the returned class
+     * will use this classloader.
+     *
+     * @param classname The name of the class to be loaded.
+     *                  Must not be <code>null</code>.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     *                                   on this loader's classpath.
+     */
+    public Class forceLoadClass(String classname) throws ClassNotFoundException {
+        log("force loading " + classname, Project.MSG_DEBUG);
+
+        Class theClass = findLoadedClass(classname);
+
+        if (theClass == null) {
+            theClass = findClass(classname);
+        }
+        return theClass;
+    }
+
+    /**
+     * Loads a class through this class loader but defer to the parent class
+     * loader.
+     *
+     * This ensures that instances of the returned class will be compatible
+     * with instances which have already been loaded on the parent
+     * loader.
+     *
+     * @param classname The name of the class to be loaded.
+     *                  Must not be <code>null</code>.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     * on this loader's classpath.
+     */
+    public Class forceLoadSystemClass(String classname) throws ClassNotFoundException {
+        log("force system loading " + classname, Project.MSG_DEBUG);
+
+        Class theClass = findLoadedClass(classname);
+
+        if (theClass == null) {
+            theClass = findBaseClass(classname);
+        }
+        return theClass;
+    }
+
+    /**
+     * Returns a stream to read the requested resource name.
+     *
+     * @param name The name of the resource for which a stream is required.
+     *             Must not be <code>null</code>.
+     *
+     * @return a stream to the required resource or <code>null</code> if the
+     *         resource cannot be found on the loader's classpath.
+     */
+    public InputStream getResourceAsStream(String name) {
+        InputStream resourceStream = null;
+        if (isParentFirst(name)) {
+            resourceStream = loadBaseResource(name);
+            if (resourceStream != null) {
+                log("ResourceStream for " + name
+                    + " loaded from parent loader", Project.MSG_DEBUG);
+            } else {
+                resourceStream = loadResource(name);
+                if (resourceStream != null) {
+                    log("ResourceStream for " + name
+                        + " loaded from ant loader", Project.MSG_DEBUG);
+                }
+            }
+        } else {
+            resourceStream = loadResource(name);
+            if (resourceStream != null) {
+                log("ResourceStream for " + name + " loaded from ant loader", Project.MSG_DEBUG);
+            } else {
+                resourceStream = loadBaseResource(name);
+                if (resourceStream != null) {
+                    log("ResourceStream for " + name + " loaded from parent loader",
+                            Project.MSG_DEBUG);
+                }
+            }
+        }
+        if (resourceStream == null) {
+            log("Couldn't load ResourceStream for " + name, Project.MSG_DEBUG);
+        }
+        return resourceStream;
+    }
+
+    /**
+     * Returns a stream to read the requested resource name from this loader.
+     *
+     * @param name The name of the resource for which a stream is required.
+     *             Must not be <code>null</code>.
+     *
+     * @return a stream to the required resource or <code>null</code> if
+     *         the resource cannot be found on the loader's classpath.
+     */
+    private InputStream loadResource(String name) {
+        // we need to search the components of the path to see if we can
+        // find the class we want.
+        InputStream stream = null;
+
+        Enumeration e = pathComponents.elements();
+        while (e.hasMoreElements() && stream == null) {
+            File pathComponent = (File) e.nextElement();
+            stream = getResourceStream(pathComponent, name);
+        }
+        return stream;
+    }
+
+    /**
+     * Finds a system resource (which should be loaded from the parent
+     * classloader).
+     *
+     * @param name The name of the system resource to load.
+     *             Must not be <code>null</code>.
+     *
+     * @return a stream to the named resource, or <code>null</code> if
+     *         the resource cannot be found.
+     */
+    private InputStream loadBaseResource(String name) {
+        return parent == null ? getSystemResourceAsStream(name) : parent.getResourceAsStream(name);
+    }
+
+    /**
+     * Returns an inputstream to a given resource in the given file which may
+     * either be a directory or a zip file.
+     *
+     * @param file the file (directory or jar) in which to search for the
+     *             resource. Must not be <code>null</code>.
+     * @param resourceName The name of the resource for which a stream is
+     *                     required. Must not be <code>null</code>.
+     *
+     * @return a stream to the required resource or <code>null</code> if
+     *         the resource cannot be found in the given file.
+     */
+    private InputStream getResourceStream(File file, String resourceName) {
+        try {
+            ZipFile zipFile = (ZipFile) zipFiles.get(file);
+            if (zipFile == null && file.isDirectory()) {
+                File resource = new File(file, resourceName);
+                if (resource.exists()) {
+                    return new FileInputStream(resource);
+                }
+            } else {
+                if (zipFile == null) {
+                    if (file.exists()) {
+                        zipFile = new ZipFile(file);
+                        zipFiles.put(file, zipFile);
+                    } else {
+                        return null;
+                    }
+                    //to eliminate a race condition, retrieve the entry
+                    //that is in the hash table under that filename
+                    zipFile = (ZipFile) zipFiles.get(file);
+                }
+                ZipEntry entry = zipFile.getEntry(resourceName);
+                if (entry != null) {
+                    return zipFile.getInputStream(entry);
+                }
+            }
+        } catch (Exception e) {
+            log("Ignoring Exception " + e.getClass().getName() + ": " + e.getMessage()
+                    + " reading resource " + resourceName + " from " + file, Project.MSG_VERBOSE);
+        }
+        return null;
+    }
+
+    /**
+     * Tests whether or not the parent classloader should be checked for a
+     * resource before this one. If the resource matches both the "use parent
+     * classloader first" and the "use this classloader first" lists, the latter
+     * takes priority.
+     *
+     * @param resourceName
+     *            The name of the resource to check. Must not be
+     *            <code>null</code>.
+     *
+     * @return whether or not the parent classloader should be checked for a
+     *         resource before this one is.
+     */
+    private boolean isParentFirst(String resourceName) {
+        // default to the global setting and then see
+        // if this class belongs to a package which has been
+        // designated to use a specific loader first
+        // (this one or the parent one)
+
+        // XXX - shouldn't this always return false in isolated mode?
+
+        boolean useParentFirst = parentFirst;
+
+        for (Enumeration e = systemPackages.elements(); e.hasMoreElements();) {
+            String packageName = (String) e.nextElement();
+            if (resourceName.startsWith(packageName)) {
+                useParentFirst = true;
+                break;
+            }
+        }
+        for (Enumeration e = loaderPackages.elements(); e.hasMoreElements();) {
+            String packageName = (String) e.nextElement();
+            if (resourceName.startsWith(packageName)) {
+                useParentFirst = false;
+                break;
+            }
+        }
+        return useParentFirst;
+    }
+
+    /**
+     * Used for isolated resource seaching.
+     * @return the root classloader of AntClassLoader.
+     */
+    private ClassLoader getRootLoader() {
+        ClassLoader ret = getClass().getClassLoader();
+        while (ret != null && ret.getParent() != null) {
+            ret = ret.getParent();
+        }
+        return ret;
+    }
+
+    /**
+     * Finds the resource with the given name. A resource is
+     * some data (images, audio, text, etc) that can be accessed by class
+     * code in a way that is independent of the location of the code.
+     *
+     * @param name The name of the resource for which a stream is required.
+     *             Must not be <code>null</code>.
+     *
+     * @return a URL for reading the resource, or <code>null</code> if the
+     *         resource could not be found or the caller doesn't have
+     *         adequate privileges to get the resource.
+     */
+    public URL getResource(String name) {
+        // we need to search the components of the path to see if
+        // we can find the class we want.
+        URL url = null;
+        if (isParentFirst(name)) {
+            url = parent == null ? super.getResource(name) : parent.getResource(name);
+        }
+        if (url != null) {
+            log("Resource " + name + " loaded from parent loader", Project.MSG_DEBUG);
+        } else {
+            // try and load from this loader if the parent either didn't find
+            // it or wasn't consulted.
+            Enumeration e = pathComponents.elements();
+            while (e.hasMoreElements() && url == null) {
+                File pathComponent = (File) e.nextElement();
+                url = getResourceURL(pathComponent, name);
+                if (url != null) {
+                    log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG);
+                }
+            }
+        }
+        if (url == null && !isParentFirst(name)) {
+            // this loader was first but it didn't find it - try the parent
+            if (ignoreBase) {
+                url = getRootLoader() == null ? null : getRootLoader().getResource(name);
+            } else {
+                url = parent == null ? super.getResource(name) : parent.getResource(name);
+            }
+            if (url != null) {
+                log("Resource " + name + " loaded from parent loader", Project.MSG_DEBUG);
+            }
+        }
+        if (url == null) {
+            log("Couldn't load Resource " + name, Project.MSG_DEBUG);
+        }
+        return url;
+    }
+
+    /**
+     * Returns an enumeration of URLs representing all the resources with the
+     * given name by searching the class loader's classpath.
+     *
+     * @param name The resource name to search for.
+     *             Must not be <code>null</code>.
+     * @return an enumeration of URLs for the resources
+     * @exception IOException if I/O errors occurs (can't happen)
+     */
+    protected Enumeration/*<URL>*/ findResources(String name) throws IOException {
+        Enumeration/*<URL>*/ mine = new ResourceEnumeration(name);
+        Enumeration/*<URL>*/ base;
+        if (parent != null && parent != getParent()) {
+            // Delegate to the parent:
+            base = parent.getResources(name);
+            // Note: could cause overlaps in case ClassLoader.this.parent has matches.
+        } else {
+            // ClassLoader.this.parent is already delegated to from
+            // ClassLoader.getResources, no need:
+            base = new CollectionUtils.EmptyEnumeration();
+        }
+        if (isParentFirst(name)) {
+            // Normal case.
+            return CollectionUtils.append(base, mine);
+        }
+        if (ignoreBase) {
+            return getRootLoader() == null ? mine : CollectionUtils.append(mine, getRootLoader()
+                    .getResources(name));
+        }
+        // parent last:
+        return CollectionUtils.append(mine, base);
+    }
+
+    /**
+     * Returns the URL of a given resource in the given file which may
+     * either be a directory or a zip file.
+     *
+     * @param file The file (directory or jar) in which to search for
+     *             the resource. Must not be <code>null</code>.
+     * @param resourceName The name of the resource for which a stream
+     *                     is required. Must not be <code>null</code>.
+     *
+     * @return a stream to the required resource or <code>null</code> if the
+     *         resource cannot be found in the given file object.
+     */
+    protected URL getResourceURL(File file, String resourceName) {
+        try {
+            ZipFile zipFile = (ZipFile) zipFiles.get(file);
+            if (zipFile == null && file.isDirectory()) {
+                File resource = new File(file, resourceName);
+
+                if (resource.exists()) {
+                    try {
+                        return FILE_UTILS.getFileURL(resource);
+                    } catch (MalformedURLException ex) {
+                        return null;
+                    }
+                }
+            } else {
+                if (zipFile == null) {
+                    if (file.exists()) {
+                        zipFile = new ZipFile(file);
+                        zipFiles.put(file, zipFile);
+                    } else {
+                        return null;
+                    }
+                }
+                ZipEntry entry = zipFile.getEntry(resourceName);
+                if (entry != null) {
+                    try {
+                        return new URL("jar:" + FILE_UTILS.getFileURL(file) + "!/" + entry);
+                    } catch (MalformedURLException ex) {
+                        return null;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * Loads a class with this class loader.
+     *
+     * This class attempts to load the class in an order determined by whether
+     * or not the class matches the system/loader package lists, with the
+     * loader package list taking priority. If the classloader is in isolated
+     * mode, failure to load the class in this loader will result in a
+     * ClassNotFoundException.
+     *
+     * @param classname The name of the class to be loaded.
+     *                  Must not be <code>null</code>.
+     * @param resolve <code>true</code> if all classes upon which this class
+     *                depends are to be loaded.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     * on the system classpath (when not in isolated mode) or this loader's
+     * classpath.
+     */
+    protected synchronized Class loadClass(String classname, boolean resolve)
+            throws ClassNotFoundException {
+        // 'sync' is needed - otherwise 2 threads can load the same class
+        // twice, resulting in LinkageError: duplicated class definition.
+        // findLoadedClass avoids that, but without sync it won't work.
+
+        Class theClass = findLoadedClass(classname);
+        if (theClass != null) {
+            return theClass;
+        }
+        if (isParentFirst(classname)) {
+            try {
+                theClass = findBaseClass(classname);
+                log("Class " + classname + " loaded from parent loader " + "(parentFirst)",
+                        Project.MSG_DEBUG);
+            } catch (ClassNotFoundException cnfe) {
+                theClass = findClass(classname);
+                log("Class " + classname + " loaded from ant loader " + "(parentFirst)",
+                        Project.MSG_DEBUG);
+            }
+        } else {
+            try {
+                theClass = findClass(classname);
+                log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG);
+            } catch (ClassNotFoundException cnfe) {
+                if (ignoreBase) {
+                    throw cnfe;
+                }
+                theClass = findBaseClass(classname);
+                log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG);
+            }
+        }
+        if (resolve) {
+            resolveClass(theClass);
+        }
+        return theClass;
+    }
+
+    /**
+     * Converts the class dot notation to a filesystem equivalent for
+     * searching purposes.
+     *
+     * @param classname The class name in dot format (eg java.lang.Integer).
+     *                  Must not be <code>null</code>.
+     *
+     * @return the classname in filesystem format (eg java/lang/Integer.class)
+     */
+    private String getClassFilename(String classname) {
+        return classname.replace('.', '/') + ".class";
+    }
+
+    /**
+     * Define a class given its bytes
+     *
+     * @param container the container from which the class data has been read
+     *                  may be a directory or a jar/zip file.
+     *
+     * @param classData the bytecode data for the class
+     * @param classname the name of the class
+     *
+     * @return the Class instance created from the given data
+     *
+     * @throws IOException if the class data cannot be read.
+     */
+    protected Class defineClassFromData(File container, byte[] classData, String classname)
+            throws IOException {
+        definePackage(container, classname);
+        // XXX should instead make a new ProtectionDomain with a CodeSource
+        // corresponding to container.toURI().toURL() and the same
+        // PermissionCollection as Project.class.protectionDomain had
+        return defineClass(classname, classData, 0, classData.length, Project.class
+                .getProtectionDomain());
+    }
+
+    /**
+     * Define the package information associated with a class.
+     *
+     * @param container the file containing the class definition.
+     * @param className the class name of for which the package information
+     *        is to be determined.
+     *
+     * @exception IOException if the package information cannot be read from the
+     *            container.
+     */
+    protected void definePackage(File container, String className) throws IOException {
+        int classIndex = className.lastIndexOf('.');
+        if (classIndex == -1) {
+            return;
+        }
+        String packageName = className.substring(0, classIndex);
+        if (getPackage(packageName) != null) {
+            // already defined
+            return;
+        }
+        // define the package now
+        Manifest manifest = getJarManifest(container);
+
+        if (manifest == null) {
+            definePackage(packageName, null, null, null, null, null, null, null);
+        } else {
+            definePackage(container, packageName, manifest);
+        }
+    }
+
+    /**
+     * Get the manifest from the given jar, if it is indeed a jar and it has a
+     * manifest
+     *
+     * @param container the File from which a manifest is required.
+     *
+     * @return the jar's manifest or null is the container is not a jar or it
+     *         has no manifest.
+     *
+     * @exception IOException if the manifest cannot be read.
+     */
+    private Manifest getJarManifest(File container) throws IOException {
+        if (container.isDirectory()) {
+            return null;
+        }
+        JarFile jarFile = null;
+        try {
+            jarFile = new JarFile(container);
+            return jarFile.getManifest();
+        } finally {
+            if (jarFile != null) {
+                jarFile.close();
+            }
+        }
+    }
+
+    /**
+     * Define the package information when the class comes from a
+     * jar with a manifest
+     *
+     * @param container the jar file containing the manifest
+     * @param packageName the name of the package being defined.
+     * @param manifest the jar's manifest
+     */
+    protected void definePackage(File container, String packageName, Manifest manifest) {
+        String sectionName = packageName.replace('.', '/') + "/";
+
+        String specificationTitle = null;
+        String specificationVendor = null;
+        String specificationVersion = null;
+        String implementationTitle = null;
+        String implementationVendor = null;
+        String implementationVersion = null;
+        String sealedString = null;
+        URL sealBase = null;
+
+        Attributes sectionAttributes = manifest.getAttributes(sectionName);
+        if (sectionAttributes != null) {
+            specificationTitle = sectionAttributes.getValue(Name.SPECIFICATION_TITLE);
+            specificationVendor = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR);
+            specificationVersion = sectionAttributes.getValue(Name.SPECIFICATION_VERSION);
+            implementationTitle = sectionAttributes.getValue(Name.IMPLEMENTATION_TITLE);
+            implementationVendor = sectionAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
+            implementationVersion = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION);
+            sealedString = sectionAttributes.getValue(Name.SEALED);
+        }
+        Attributes mainAttributes = manifest.getMainAttributes();
+        if (mainAttributes != null) {
+            if (specificationTitle == null) {
+                specificationTitle = mainAttributes.getValue(Name.SPECIFICATION_TITLE);
+            }
+            if (specificationVendor == null) {
+                specificationVendor = mainAttributes.getValue(Name.SPECIFICATION_VENDOR);
+            }
+            if (specificationVersion == null) {
+                specificationVersion = mainAttributes.getValue(Name.SPECIFICATION_VERSION);
+            }
+            if (implementationTitle == null) {
+                implementationTitle = mainAttributes.getValue(Name.IMPLEMENTATION_TITLE);
+            }
+            if (implementationVendor == null) {
+                implementationVendor = mainAttributes.getValue(Name.IMPLEMENTATION_VENDOR);
+            }
+            if (implementationVersion == null) {
+                implementationVersion = mainAttributes.getValue(Name.IMPLEMENTATION_VERSION);
+            }
+            if (sealedString == null) {
+                sealedString = mainAttributes.getValue(Name.SEALED);
+            }
+        }
+        if (sealedString != null && sealedString.toLowerCase(Locale.ENGLISH).equals("true")) {
+            try {
+                sealBase = new URL(FileUtils.getFileUtils().toURI(container.getAbsolutePath()));
+            } catch (MalformedURLException e) {
+                // ignore
+            }
+        }
+        definePackage(packageName, specificationTitle, specificationVersion, specificationVendor,
+                implementationTitle, implementationVersion, implementationVendor, sealBase);
+    }
+
+    /**
+     * Reads a class definition from a stream.
+     *
+     * @param stream The stream from which the class is to be read.
+     *               Must not be <code>null</code>.
+     * @param classname The name of the class in the stream.
+     *                  Must not be <code>null</code>.
+     * @param container the file or directory containing the class.
+     *
+     * @return the Class object read from the stream.
+     *
+     * @exception IOException if there is a problem reading the class from the
+     * stream.
+     * @exception SecurityException if there is a security problem while
+     * reading the class from the stream.
+     */
+    private Class getClassFromStream(InputStream stream, String classname, File container)
+            throws IOException, SecurityException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int bytesRead = -1;
+        byte[] buffer = new byte[BUFFER_SIZE];
+
+        while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
+            baos.write(buffer, 0, bytesRead);
+        }
+        byte[] classData = baos.toByteArray();
+        return defineClassFromData(container, classData, classname);
+    }
+
+    /**
+     * Searches for and load a class on the classpath of this class loader.
+     *
+     * @param name The name of the class to be loaded. Must not be
+     *             <code>null</code>.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     *                                   on this loader's classpath.
+     */
+    public Class findClass(String name) throws ClassNotFoundException {
+        log("Finding class " + name, Project.MSG_DEBUG);
+        return findClassInComponents(name);
+    }
+
+    /**
+     * Indicate if the given file is in this loader's path
+     *
+     * @param component the file which is to be checked
+     *
+     * @return true if the file is in the class path
+     */
+    protected boolean isInPath(File component) {
+        for (Enumeration e = pathComponents.elements(); e.hasMoreElements();) {
+            File pathComponent = (File) e.nextElement();
+            if (pathComponent.equals(component)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Finds a class on the given classpath.
+     *
+     * @param name The name of the class to be loaded. Must not be
+     *             <code>null</code>.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     * on this loader's classpath.
+     */
+    private Class findClassInComponents(String name)
+        throws ClassNotFoundException {
+        // we need to search the components of the path to see if
+        // we can find the class we want.
+        InputStream stream = null;
+        String classFilename = getClassFilename(name);
+        try {
+            Enumeration e = pathComponents.elements();
+            while (e.hasMoreElements()) {
+                File pathComponent = (File) e.nextElement();
+                try {
+                    stream = getResourceStream(pathComponent, classFilename);
+                    if (stream != null) {
+                        log("Loaded from " + pathComponent + " "
+                            + classFilename, Project.MSG_DEBUG);
+                        return getClassFromStream(stream, name, pathComponent);
+                    }
+                } catch (SecurityException se) {
+                    throw se;
+                } catch (IOException ioe) {
+                    // ioe.printStackTrace();
+                    log("Exception reading component " + pathComponent + " (reason: "
+                            + ioe.getMessage() + ")", Project.MSG_VERBOSE);
+                }
+            }
+            throw new ClassNotFoundException(name);
+        } finally {
+            FileUtils.close(stream);
+        }
+    }
+
+    /**
+     * Finds a system class (which should be loaded from the same classloader
+     * as the Ant core).
+     *
+     * For JDK 1.1 compatibility, this uses the findSystemClass method if
+     * no parent classloader has been specified.
+     *
+     * @param name The name of the class to be loaded.
+     *             Must not be <code>null</code>.
+     *
+     * @return the required Class object
+     *
+     * @exception ClassNotFoundException if the requested class does not exist
+     * on this loader's classpath.
+     */
+    private Class findBaseClass(String name) throws ClassNotFoundException {
+        return parent == null ? findSystemClass(name) : parent.loadClass(name);
+    }
+
+    /**
+     * Cleans up any resources held by this classloader. Any open archive
+     * files are closed.
+     */
+    public synchronized void cleanup() {
+        for (Enumeration e = zipFiles.elements(); e.hasMoreElements();) {
+            ZipFile zipFile = (ZipFile) e.nextElement();
+            try {
+                zipFile.close();
+            } catch (IOException ioe) {
+                // ignore
+            }
+        }
+        zipFiles = new Hashtable();
+        if (project != null) {
+            project.removeBuildListener(this);
+        }
+        project = null;
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the buildStarted event
+     */
+    public void buildStarted(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Cleans up any resources held by this classloader at the end
+     * of a build.
+     *
+     * @param event the buildFinished event
+     */
+    public void buildFinished(BuildEvent event) {
+        cleanup();
+    }
+
+    /**
+     * Cleans up any resources held by this classloader at the end of
+     * a subbuild if it has been created for the subbuild's project
+     * instance.
+     *
+     * @param event the buildFinished event
+     *
+     * @since Ant 1.6.2
+     */
+    public void subBuildFinished(BuildEvent event) {
+        if (event.getProject() == project) {
+            cleanup();
+        }
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the buildStarted event
+     *
+     * @since Ant 1.6.2
+     */
+    public void subBuildStarted(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the targetStarted event
+     */
+    public void targetStarted(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the targetFinished event
+     */
+    public void targetFinished(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the taskStarted event
+     */
+    public void taskStarted(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the taskFinished event
+     */
+    public void taskFinished(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the messageLogged event
+     */
+    public void messageLogged(BuildEvent event) {
+        // Not significant for the class loader.
+    }
+
+    /**
+     * add any libraries that come with different java versions
+     * here
+     */
+    public void addJavaLibraries() {
+        Vector packages = JavaEnvUtils.getJrePackages();
+        Enumeration e = packages.elements();
+        while (e.hasMoreElements()) {
+            String packageName = (String) e.nextElement();
+            addSystemPackageRoot(packageName);
+        }
+    }
+
+    /**
+     * Returns a <code>String</code> representing this loader.
+     * @return the path that this classloader has.
+     */
+    public String toString() {
+        return "AntClassLoader[" + getClasspath() + "]";
+    }
+
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/AntTypeDefinition.java b/trunk/src/main/org/apache/tools/ant/AntTypeDefinition.java
new file mode 100644
index 0000000..a51482f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/AntTypeDefinition.java
@@ -0,0 +1,388 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Constructor;
+
+
+/**
+ * This class contains all the information
+ * on a particular ant type,
+ * the classname, adaptor and the class
+ * it should be assignable from.
+ * This type replaces the task/datatype split
+ * of pre ant 1.6.
+ *
+ */
+public class AntTypeDefinition {
+    private String      name;
+    private Class       clazz;
+    private Class       adapterClass;
+    private Class       adaptToClass;
+    private String      className;
+    private ClassLoader classLoader;
+    private boolean     restrict = false;
+
+    /**
+     * Set the restrict attribute.
+     * @param restrict the value to set.
+      */
+     public void setRestrict(boolean restrict) {
+         this.restrict = restrict;
+     }
+
+    /**
+     * Get the restrict attribute.
+      * @return the restrict attribute.
+      */
+    public boolean isRestrict() {
+        return restrict;
+    }
+
+    /**
+     * Set the definition's name.
+     * @param name the name of the definition.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Return the definition's name.
+     * @return the name of the definition.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Set the class of the definition.
+     * As a side-effect may set the classloader and classname.
+     * @param clazz the class of this definition.
+     */
+    public void setClass(Class clazz) {
+        this.clazz = clazz;
+        if (clazz == null) {
+            return;
+        }
+        this.classLoader = (classLoader == null)
+            ? clazz.getClassLoader() : classLoader;
+        this.className = (className == null) ? clazz.getName() : className;
+    }
+
+    /**
+     * Set the classname of the definition.
+     * @param className the classname of this definition.
+     */
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    /**
+     * Get the classname of the definition.
+     * @return the name of the class of this definition.
+     */
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Set the adapter class for this definition.
+     * This class is used to adapt the definitions class if
+     * required.
+     * @param adapterClass the adapterClass.
+     */
+    public void setAdapterClass(Class adapterClass) {
+        this.adapterClass = adapterClass;
+    }
+
+    /**
+     * Set the assignable class for this definition.
+     * @param adaptToClass the assignable class.
+     */
+
+    public void setAdaptToClass(Class adaptToClass) {
+        this.adaptToClass = adaptToClass;
+    }
+
+    /**
+     * Set the classloader to use to create an instance
+     * of the definition.
+     * @param classLoader the ClassLoader.
+     */
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    /**
+     * Get the classloader for this definition.
+     * @return the classloader for this definition.
+     */
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    /**
+     * Get the exposed class for this
+     * definition. This will be a proxy class
+     * (adapted class) if there is an adapter
+     * class and the definition class is not
+     * assignable from the assignable class.
+     * @param project the current project.
+     * @return the exposed class - may return null if upable to load the class
+     */
+    public Class getExposedClass(Project project) {
+        if (adaptToClass != null) {
+            Class z = getTypeClass(project);
+            if (z == null || adaptToClass.isAssignableFrom(z)) {
+                return z;
+            }
+        }
+        return (adapterClass == null) ? getTypeClass(project) :  adapterClass;
+    }
+
+    /**
+     * Get the definition class.
+     * @param project the current project.
+     * @return the type of the definition.
+     */
+    public Class getTypeClass(Project project) {
+        try {
+            return innerGetTypeClass();
+        } catch (NoClassDefFoundError ncdfe) {
+            project.log("Could not load a dependent class ("
+                        + ncdfe.getMessage() + ") for type "
+                        + name, Project.MSG_DEBUG);
+        } catch (ClassNotFoundException cnfe) {
+            project.log("Could not load class (" + className
+                        + ") for type " + name, Project.MSG_DEBUG);
+        }
+        return null;
+    }
+
+    /**
+     * Try and load a class, with no attempt to catch any fault.
+     * @return the class that implements this component
+     * @throws ClassNotFoundException if the class cannot be found.
+     * @throws NoClassDefFoundError   if the there is an error
+     *                                finding the class.
+     */
+    public Class innerGetTypeClass() throws ClassNotFoundException {
+        if (clazz != null) {
+            return clazz;
+        }
+        if (classLoader == null) {
+            clazz = Class.forName(className);
+        } else {
+            clazz = classLoader.loadClass(className);
+        }
+        return clazz;
+    }
+
+    /**
+     * Create an instance of the definition.
+     * The instance may be wrapped in a proxy class.
+     * @param project the current project.
+     * @return the created object.
+     */
+    public Object create(Project project) {
+        return icreate(project);
+    }
+
+    /**
+     * Create a component object based on
+     * its definition.
+     * @return the component as an <code>Object</code>.
+     */
+    private Object icreate(Project project) {
+        Class c = getTypeClass(project);
+        if (c == null) {
+            return null;
+        }
+        Object o = createAndSet(project, c);
+        if (o == null || adapterClass == null) {
+            return o;
+        }
+        if (adaptToClass != null) {
+            if (adaptToClass.isAssignableFrom(o.getClass())) {
+                return o;
+            }
+        }
+        TypeAdapter adapterObject = (TypeAdapter) createAndSet(
+            project, adapterClass);
+        if (adapterObject == null) {
+            return null;
+        }
+        adapterObject.setProxy(o);
+        return adapterObject;
+    }
+
+    /**
+     * Checks if the attributes are correct.
+     * <dl>
+     *   <li>if the class can be created.</li>
+     *   <li>if an adapter class can be created</li>
+     *   <li>if the type is assignable from adapto</li>
+     *   <li>if the type can be used with the adapter class</li>
+     * </dl>
+     * @param project the current project.
+     */
+    public void checkClass(Project project) {
+        if (clazz == null) {
+            clazz = getTypeClass(project);
+            if (clazz == null) {
+                throw new BuildException(
+                    "Unable to create class for " + getName());
+            }
+        }
+        // check adapter
+        if (adapterClass != null && (adaptToClass == null
+            || !adaptToClass.isAssignableFrom(clazz))) {
+            TypeAdapter adapter = (TypeAdapter) createAndSet(
+                project, adapterClass);
+            if (adapter == null) {
+                throw new BuildException("Unable to create adapter object");
+            }
+            adapter.checkProxyClass(clazz);
+        }
+    }
+
+    /**
+     * Get the constructor of the definition
+     * and invoke it.
+     * @return the instantiated <code>Object</code>.
+     */
+    private Object createAndSet(Project project, Class c) {
+        try {
+            Object o = innerCreateAndSet(c, project);
+            return o;
+        } catch (InvocationTargetException ex) {
+            Throwable t = ex.getTargetException();
+            throw new BuildException(
+                "Could not create type " + name + " due to " + t, t);
+        } catch (NoClassDefFoundError ncdfe) {
+            String msg = "Type " + name + ": A class needed by class "
+                + c + " cannot be found: " + ncdfe.getMessage();
+            throw new BuildException(msg, ncdfe);
+        } catch (NoSuchMethodException nsme) {
+            throw new BuildException("Could not create type " + name
+                    + " as the class " + c + " has no compatible constructor");
+        } catch (InstantiationException nsme) {
+            throw new BuildException("Could not create type "
+                    + name + " as the class " + c + " is abstract");
+        } catch (IllegalAccessException e) {
+            throw new BuildException("Could not create type "
+                    + name + " as the constructor " + c + " is not accessible");
+        } catch (Throwable t) {
+            throw new BuildException(
+                "Could not create type " + name + " due to " + t, t);
+        }
+    }
+
+    /**
+     * Inner implementation of the {@link #createAndSet(Project, Class)} logic, with no
+     * exception catching
+     * @param newclass class to create
+     * @param project the project to use
+     * @return a newly constructed and bound instance.
+     * @throws NoSuchMethodException  no good construtor.
+     * @throws InstantiationException cannot initialize the object.
+     * @throws IllegalAccessException cannot access the object.
+     * @throws InvocationTargetException error in invocation.
+     */
+    public Object innerCreateAndSet(Class newclass, Project project)
+            throws NoSuchMethodException,
+            InstantiationException,
+            IllegalAccessException,
+            InvocationTargetException {
+        Constructor ctor = null;
+        boolean noArg = false;
+        // DataType can have a "no arg" constructor or take a single
+        // Project argument.
+        try {
+            ctor = newclass.getConstructor(new Class[0]);
+            noArg = true;
+        } catch (NoSuchMethodException nse) {
+            //can throw the same exception, if there is no this(Project) ctor.
+            ctor = newclass.getConstructor(new Class[] {Project.class});
+            noArg = false;
+        }
+        //now we instantiate
+        Object o = ctor.newInstance(
+            ((noArg) ? new Object[0] : new Object[] {project}));
+
+        //set up project references.
+        project.setProjectReference(o);
+        return o;
+    }
+
+    /**
+     * Equality method for this definition (assumes the names are the same).
+     *
+     * @param other another definition.
+     * @param project the project the definition.
+     * @return true if the definitions are the same.
+     */
+    public boolean sameDefinition(AntTypeDefinition other, Project project) {
+        return (other != null && other.getClass() == getClass()
+            && other.getTypeClass(project).equals(getTypeClass(project))
+            && other.getExposedClass(project).equals(getExposedClass(project))
+            && other.restrict == restrict
+            && other.adapterClass == adapterClass
+            && other.adaptToClass == adaptToClass);
+    }
+
+    /**
+     * Similar definition;
+     * used to compare two definitions defined twice with the same
+     * name and the same types.
+     * The classloader may be different but have the same
+     * path so #sameDefinition cannot
+     * be used.
+     * @param other the definition to compare to.
+     * @param project the current project.
+     * @return true if the definitions are the same.
+     */
+    public boolean similarDefinition(AntTypeDefinition other, Project project) {
+        if (other == null
+            || getClass() != other.getClass()
+            || !getClassName().equals(other.getClassName())
+            || !extractClassname(adapterClass).equals(
+            extractClassname(other.adapterClass))
+            || !extractClassname(adaptToClass).equals(
+            extractClassname(other.adaptToClass))
+            || restrict != other.restrict) {
+            return false;
+        }
+        // all the names are the same: check if the class path of the loader
+        // is the same
+        ClassLoader oldLoader = other.getClassLoader();
+        ClassLoader newLoader = getClassLoader();
+        return oldLoader == newLoader
+            || (oldLoader instanceof AntClassLoader
+            && newLoader instanceof AntClassLoader
+            && ((AntClassLoader) oldLoader).getClasspath()
+            .equals(((AntClassLoader) newLoader).getClasspath()));
+    }
+
+    private String extractClassname(Class c) {
+        return (c == null) ? "<null>" : c.getClass().getName();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/BuildEvent.java b/trunk/src/main/org/apache/tools/ant/BuildEvent.java
new file mode 100644
index 0000000..65c927e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/BuildEvent.java
@@ -0,0 +1,203 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.util.EventObject;
+
+/**
+ * Class representing an event occurring during a build. An
+ * event is built by specifying either a project, a task or a target.
+ * A project level event will only have a project reference;
+ * a target level event will have project and target references;
+ * a task level event will have project, target and task references.
+ *
+ */
+public class BuildEvent extends EventObject {
+
+    private static final long serialVersionUID = 4538050075952288486L;
+
+    /** Project which emitted the event. */
+    private Project project;
+    /** Target which emitted the event, if specified. */
+    private Target target;
+    /** Task which emitted the event, if specified. */
+    private Task task;
+    /**
+     * Message associated with the event. This is only used for
+     * "messageLogged" events.
+     */
+    private String message;
+    /**
+     * The priority of the message, for "messageLogged" events.
+     */
+    private int priority = Project.MSG_VERBOSE;
+    /**
+     * The exception associated with this event, if any.
+     * This is only used for "messageLogged", "taskFinished", "targetFinished",
+     * and "buildFinished" events.
+     */
+    private Throwable exception;
+
+    /**
+     * Construct a BuildEvent for a project level event.
+     *
+     * @param project the project that emitted the event.
+     *                Should not be <code>null</code>.
+     */
+    public BuildEvent(Project project) {
+        super(project);
+        this.project = project;
+        this.target = null;
+        this.task = null;
+    }
+
+    /**
+     * Construct a BuildEvent for a target level event.
+     * The project associated with the event is derived
+     * from the given target.
+     *
+     * @param target the target that emitted the event.
+     *               Must not be <code>null</code>.
+     */
+    public BuildEvent(Target target) {
+        super(target);
+        this.project = target.getProject();
+        this.target = target;
+        this.task = null;
+    }
+
+    /**
+     * Construct a BuildEvent for a task level event.
+     * The project and target associated with the event
+     * are derived from the given task.
+     *
+     * @param task the task that emitted the event.
+     *             Must not be <code>null</code>.
+     */
+    public BuildEvent(Task task) {
+        super(task);
+        this.project = task.getProject();
+        this.target = task.getOwningTarget();
+        this.task = task;
+    }
+
+    /**
+     * Sets the message and priority associated with this event.
+     * This is used for "messageLogged" events.
+     *
+     * @param message the message to be associated with this event.
+     *                Should not be <code>null</code>.
+     * @param priority the priority to be associated with this event,
+     *                 as defined in the {@link Project Project} class.
+     *
+     * @see BuildListener#messageLogged(BuildEvent)
+     */
+    public void setMessage(String message, int priority) {
+        this.message = message;
+        this.priority = priority;
+    }
+
+    /**
+     * Sets the exception associated with this event. This is used
+     * for "messageLogged", "taskFinished", "targetFinished", and "buildFinished"
+     * events.
+     *
+     * @param exception The exception to be associated with this event.
+     *                  May be <code>null</code>.
+     *
+     * @see BuildListener#messageLogged(BuildEvent)
+     * @see BuildListener#taskFinished(BuildEvent)
+     * @see BuildListener#targetFinished(BuildEvent)
+     * @see BuildListener#buildFinished(BuildEvent)
+     */
+    public void setException(Throwable exception) {
+        this.exception = exception;
+    }
+
+    /**
+     * Returns the project that fired this event.
+     *
+     * @return the project that fired this event
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Returns the target that fired this event.
+     *
+     * @return the project that fired this event, or <code>null</code>
+     *          if this event is a project level event.
+     */
+    public Target getTarget() {
+        return target;
+    }
+
+    /**
+     * Returns the task that fired this event.
+     *
+     * @return the task that fired this event, or <code>null</code>
+     *         if this event is a project or target level event.
+     */
+    public Task getTask() {
+        return task;
+    }
+
+    /**
+     * Returns the logging message. This field will only be set
+     * for "messageLogged" events.
+     *
+     * @return the message associated with this event, or <code>null</code>
+     *         if no message has been set.
+     *
+     * @see BuildListener#messageLogged(BuildEvent)
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Returns the priority of the logging message. This field will only
+     * be set for "messageLogged" events. The meaning of this priority
+     * is as specified by the constants in the {@link Project Project} class.
+     *
+     * @return the priority associated with this event.
+     *
+     * @see BuildListener#messageLogged(BuildEvent)
+     */
+    public int getPriority() {
+        return priority;
+    }
+
+    /**
+     * Returns the exception that was thrown, if any. This field will only
+     * be set for "messageLogged", "taskFinished", "targetFinished", and "buildFinished"
+     * events.
+     *
+     * @return the exception associated with this exception, or
+     *         <code>null</code> if no exception has been set.
+     *
+     * @see BuildListener#messageLogged(BuildEvent)
+     * @see BuildListener#taskFinished(BuildEvent)
+     * @see BuildListener#targetFinished(BuildEvent)
+     * @see BuildListener#buildFinished(BuildEvent)
+     */
+    public Throwable getException() {
+        return exception;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/BuildException.java b/trunk/src/main/org/apache/tools/ant/BuildException.java
new file mode 100644
index 0000000..ff700e7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/BuildException.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * Signals an error condition during a build
+ */
+public class BuildException extends RuntimeException {
+
+    private static final long serialVersionUID = -5419014565354664240L;
+
+    /** Exception that might have caused this one. */
+    private Throwable cause;
+
+    /** Location in the build file where the exception occurred */
+    private Location location = Location.UNKNOWN_LOCATION;
+
+    /**
+     * Constructs a build exception with no descriptive information.
+     */
+    public BuildException() {
+        super();
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code>.
+     */
+    public BuildException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code> unless a cause is specified.
+     * @param cause The exception that might have caused this one.
+     *              May be <code>null</code>.
+     */
+    public BuildException(String message, Throwable cause) {
+        super(message);
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause and a location in a file.
+     *
+     * @param msg A description of or information about the exception.
+     *            Should not be <code>null</code> unless a cause is specified.
+     * @param cause The exception that might have caused this one.
+     *              May be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildException(String msg, Throwable cause, Location location) {
+        this(msg, cause);
+        this.location = location;
+    }
+
+    /**
+     * Constructs an exception with the given exception as a root cause.
+     *
+     * @param cause The exception that might have caused this one.
+     *              Should not be <code>null</code>.
+     */
+    public BuildException(Throwable cause) {
+        super(cause.toString());
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message and a
+     * location in a file.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildException(String message, Location location) {
+        super(message);
+        this.location = location;
+    }
+
+    /**
+     * Constructs an exception with the given exception as
+     * a root cause and a location in a file.
+     *
+     * @param cause The exception that might have caused this one.
+     *              Should not be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildException(Throwable cause, Location location) {
+        this(cause);
+        this.location = location;
+    }
+
+    /**
+     * Returns the nested exception, if any.
+     *
+     * @return the nested exception, or <code>null</code> if no
+     *         exception is associated with this one
+     */
+    public Throwable getException() {
+        return cause;
+    }
+
+    /**
+     * Returns the nested exception, if any.
+     *
+     * @return the nested exception, or <code>null</code> if no
+     *         exception is associated with this one
+     */
+    public Throwable getCause() {
+        return getException();
+    }
+
+    /**
+     * Returns the location of the error and the error message.
+     *
+     * @return the location of the error and the error message
+     */
+    public String toString() {
+        return location.toString() + getMessage();
+    }
+
+    /**
+     * Sets the file location where the error occurred.
+     *
+     * @param location The file location where the error occurred.
+     *                 Must not be <code>null</code>.
+     */
+    public void setLocation(Location location) {
+        this.location = location;
+    }
+
+    /**
+     * Returns the file location where the error occurred.
+     *
+     * @return the file location where the error occurred.
+     */
+    public Location getLocation() {
+        return location;
+    }
+
+    /**
+     * Prints the stack trace for this exception and any
+     * nested exception to <code>System.err</code>.
+     */
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Prints the stack trace of this exception and any nested
+     * exception to the specified PrintStream.
+     *
+     * @param ps The PrintStream to print the stack trace to.
+     *           Must not be <code>null</code>.
+     */
+    public void printStackTrace(PrintStream ps) {
+        synchronized (ps) {
+            super.printStackTrace(ps);
+            if (cause != null) {
+                ps.println("--- Nested Exception ---");
+                cause.printStackTrace(ps);
+            }
+        }
+    }
+
+    /**
+     * Prints the stack trace of this exception and any nested
+     * exception to the specified PrintWriter.
+     *
+     * @param pw The PrintWriter to print the stack trace to.
+     *           Must not be <code>null</code>.
+     */
+    public void printStackTrace(PrintWriter pw) {
+        synchronized (pw) {
+            super.printStackTrace(pw);
+            if (cause != null) {
+                pw.println("--- Nested Exception ---");
+                cause.printStackTrace(pw);
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/BuildListener.java b/trunk/src/main/org/apache/tools/ant/BuildListener.java
new file mode 100644
index 0000000..5801c98
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/BuildListener.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.util.EventListener;
+
+/**
+ * Instances of classes that implement this interface can register
+ * to be notified when things happened during a build.
+ *
+ * @see BuildEvent
+ * @see Project#addBuildListener(BuildListener)
+ *
+ */
+public interface BuildListener extends EventListener {
+
+    /**
+     * Signals that a build has started. This event
+     * is fired before any targets have started.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     */
+    void buildStarted(BuildEvent event);
+
+    /**
+     * Signals that the last target has finished. This event
+     * will still be fired if an error occurred during the build.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getException()
+     */
+    void buildFinished(BuildEvent event);
+
+    /**
+     * Signals that a target is starting.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getTarget()
+     */
+    void targetStarted(BuildEvent event);
+
+    /**
+     * Signals that a target has finished. This event will
+     * still be fired if an error occurred during the build.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getException()
+     */
+    void targetFinished(BuildEvent event);
+
+    /**
+     * Signals that a task is starting.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getTask()
+     */
+    void taskStarted(BuildEvent event);
+
+    /**
+     * Signals that a task has finished. This event will still
+     * be fired if an error occurred during the build.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getException()
+     */
+    void taskFinished(BuildEvent event);
+
+    /**
+     * Signals a message logging event.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getMessage()
+     * @see BuildEvent#getException()
+     * @see BuildEvent#getPriority()
+     */
+    void messageLogged(BuildEvent event);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/BuildLogger.java b/trunk/src/main/org/apache/tools/ant/BuildLogger.java
new file mode 100644
index 0000000..249d8f5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/BuildLogger.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.PrintStream;
+
+/**
+ * Interface used by Ant to log the build output.
+ *
+ * A build logger is a build listener which has the 'right' to send output to
+ * the ant log, which is usually <code>System.out</code> unless redirected by
+ * the <code>-logfile</code> option.
+ *
+ */
+public interface BuildLogger extends BuildListener {
+
+    /**
+     * Sets the highest level of message this logger should respond to.
+     *
+     * Only messages with a message level lower than or equal to the
+     * given level should be written to the log.
+     * <P>
+     * Constants for the message levels are in the
+     * {@link Project Project} class. The order of the levels, from least
+     * to most verbose, is <code>MSG_ERR</code>, <code>MSG_WARN</code>,
+     * <code>MSG_INFO</code>, <code>MSG_VERBOSE</code>,
+     * <code>MSG_DEBUG</code>.
+     *
+     * @param level the logging level for the logger.
+     */
+    void setMessageOutputLevel(int level);
+
+    /**
+     * Sets the output stream to which this logger is to send its output.
+     *
+     * @param output The output stream for the logger.
+     *               Must not be <code>null</code>.
+     */
+    void setOutputPrintStream(PrintStream output);
+
+    /**
+     * Sets this logger to produce emacs (and other editor) friendly output.
+     *
+     * @param emacsMode <code>true</code> if output is to be unadorned so that
+     *                  emacs and other editors can parse files names, etc.
+     */
+    void setEmacsMode(boolean emacsMode);
+
+    /**
+     * Sets the output stream to which this logger is to send error messages.
+     *
+     * @param err The error stream for the logger.
+     *            Must not be <code>null</code>.
+     */
+    void setErrorPrintStream(PrintStream err);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/ComponentHelper.java b/trunk/src/main/org/apache/tools/ant/ComponentHelper.java
new file mode 100644
index 0000000..0618c2a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/ComponentHelper.java
@@ -0,0 +1,1105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+import org.apache.tools.ant.taskdefs.Typedef;
+import org.apache.tools.ant.taskdefs.Definer;
+import org.apache.tools.ant.launch.Launcher;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Component creation and configuration.
+ *
+ * The class is based around handing component
+ * definitions in an AntTypeTable.
+ *
+ * The old task/type methods have been kept
+ * for backward compatibly.
+ * Project will just delegate its calls to this class.
+ *
+ * A very simple hook mechanism is provided that allows users to plug
+ * in custom code. It is also possible to replace the default behavior
+ * ( for example in an app embedding ant )
+ *
+ * @since Ant1.6
+ */
+public class ComponentHelper  {
+    /** Map of component name to lists of restricted definitions */
+    private Map          restrictedDefinitions = new HashMap();
+
+    /** Map from component name to anttypedefinition */
+    private AntTypeTable antTypeTable;
+
+    /** Map of tasks generated from antTypeTable */
+    private Hashtable taskClassDefinitions = new Hashtable();
+
+    /** flag to rebuild taskClassDefinitions */
+    private boolean rebuildTaskClassDefinitions = true;
+
+    /** Map of types generated from antTypeTable */
+    private Hashtable typeClassDefinitions = new Hashtable();
+
+    /** flag to rebuild typeClassDefinitions */
+    private boolean rebuildTypeClassDefinitions = true;
+
+    /** Set of namespaces that have been checked for antlibs */
+    private Set checkedNamespaces = new HashSet();
+
+    /**
+     * Stack of antlib contexts used to resolve definitions while
+     *   processing antlib
+     */
+    private Stack antLibStack = new Stack();
+
+    /** current antlib uri */
+    private String antLibCurrentUri = null;
+
+    /**
+     * this does not appear to be used anywhere in the Ant codebase
+     * even via its accessors
+     */
+    private ComponentHelper next;
+
+    /**
+     * Project that owns a component helper
+     */
+    private Project project;
+
+    /**
+     * Error string when the file taskdefs/defaults.properties cannot be found
+     */
+    private static final String ERROR_NO_TASK_LIST_LOAD = "Can't load default task list";
+
+    /**
+     * Error string when the typedefs/defaults.properties cannot be found
+     */
+    private static final String ERROR_NO_TYPE_LIST_LOAD = "Can't load default type list";
+
+    /**
+     * reference under which we register ourselves with a project -{@value}
+     */
+    public static final String COMPONENT_HELPER_REFERENCE = "ant.ComponentHelper";
+
+    /**
+     * string used to control build.syspath policy {@value}
+     */
+    private static final String BUILD_SYSCLASSPATH_ONLY = "only";
+
+    /**
+     * special name of ant's property task -{@value}. There is some
+     * contrived work here to enable this early.
+     */
+    private static final String ANT_PROPERTY_TASK = "property";
+
+    // {tasks, types}
+    private static Properties[] defaultDefinitions = new Properties[2];
+
+     /**
+     * Get the project.
+     * @return the project owner of this helper.
+     */
+     public Project getProject() {
+         return project;
+     }
+
+    /**
+     * Find a project component for a specific project, creating
+     * it if it does not exist.
+     * @param project the project.
+     * @return the project component for a specific project.
+     */
+    public static ComponentHelper getComponentHelper(Project project) {
+        if (project == null) {
+            return null;
+        }
+        // Singleton for now, it may change ( per/classloader )
+        ComponentHelper ph = (ComponentHelper) project.getReference(COMPONENT_HELPER_REFERENCE);
+        if (ph != null) {
+            return ph;
+        }
+        ph = new ComponentHelper();
+        ph.setProject(project);
+
+        project.addReference(COMPONENT_HELPER_REFERENCE, ph);
+        return ph;
+    }
+
+    /**
+     * Creates a new ComponentHelper instance.
+     */
+    protected ComponentHelper() {
+    }
+
+    /**
+     * Set the next chained component helper.
+     *
+     * @param next the next chained component helper.
+     */
+    public void setNext(ComponentHelper next) {
+        this.next = next;
+    }
+
+    /**
+     * Get the next chained component helper.
+     *
+     * @return the next chained component helper.
+     */
+    public ComponentHelper getNext() {
+        return next;
+    }
+
+    /**
+     * Sets the project for this component helper.
+     *
+     * @param project the project for this helper.
+     */
+    public void setProject(Project project) {
+        this.project = project;
+        antTypeTable = new AntTypeTable(project);
+    }
+
+    /**
+     * Used with creating child projects. Each child
+     * project inherits the component definitions
+     * from its parent.
+     * @param helper the component helper of the parent project.
+     */
+    public void initSubProject(ComponentHelper helper) {
+        // add the types of the parent project
+        AntTypeTable typeTable = helper.antTypeTable;
+        for (Iterator i = typeTable.values().iterator(); i.hasNext();) {
+            AntTypeDefinition def = (AntTypeDefinition) i.next();
+            antTypeTable.put(def.getName(), def);
+        }
+        // add the parsed namespaces of the parent project
+        for (Iterator i = helper.checkedNamespaces.iterator(); i.hasNext();) {
+            checkedNamespaces.add(i.next());
+        }
+
+        // Add the restricted definitions
+        for (Iterator i = helper.restrictedDefinitions.entrySet().iterator();
+             i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            restrictedDefinitions.put(
+                entry.getKey(), new ArrayList((List) entry.getValue()));
+        }
+    }
+
+    /**
+     * Factory method to create the components.
+     *
+     * This should be called by UnknownElement.
+     *
+     * @param ue The Unknown Element creating this component.
+     * @param ns Namespace URI. Also available as ue.getNamespace().
+     * @param componentType The component type,
+     *                       Also available as ue.getComponentName().
+     * @return the created component.
+     * @throws BuildException if an error occurs.
+     */
+    public Object createComponent(UnknownElement ue, String ns, String componentType)
+            throws BuildException {
+        Object component = createComponent(componentType);
+        if (component instanceof Task) {
+            Task task = (Task) component;
+            task.setLocation(ue.getLocation());
+            task.setTaskType(componentType);
+            task.setTaskName(ue.getTaskName());
+            task.setOwningTarget(ue.getOwningTarget());
+            task.init();
+        }
+        return component;
+    }
+
+    /**
+     * Create an object for a component.
+     *
+     * @param componentName the name of the component, if
+     *                      the component is in a namespace, the
+     *                      name is prefixed with the namespace uri and ":".
+     * @return the class if found or null if not.
+     */
+    public Object createComponent(String componentName) {
+        AntTypeDefinition def = getDefinition(componentName);
+        return def == null ? null : def.create(project);
+    }
+
+    /**
+     * Return the class of the component name.
+     *
+     * @param componentName the name of the component, if
+     *                      the component is in a namespace, the
+     *                      name is prefixed with the namespace uri and ":".
+     * @return the class if found or null if not.
+     */
+    public Class getComponentClass(String componentName) {
+        AntTypeDefinition def = getDefinition(componentName);
+        return def == null ? null : def.getExposedClass(project);
+    }
+
+    /**
+     * Return the antTypeDefinition for a componentName.
+     * @param componentName the name of the component.
+     * @return the ant definition or null if not present.
+     */
+    public AntTypeDefinition getDefinition(String componentName) {
+        checkNamespace(componentName);
+        return antTypeTable.getDefinition(componentName);
+    }
+
+    /**
+     * This method is initialization code implementing the original ant component
+     * loading from /org/apache/tools/ant/taskdefs/default.properties
+     * and /org/apache/tools/ant/types/default.properties.
+     */
+    public void initDefaultDefinitions() {
+        initTasks();
+        initTypes();
+    }
+
+    /**
+     * Adds a new task definition to the project.
+     * Attempting to override an existing definition with an
+     * equivalent one (i.e. with the same classname) results in
+     * a verbose log message. Attempting to override an existing definition
+     * with a different one results in a warning log message.
+     *
+     * @param taskName The name of the task to add.
+     *                 Must not be <code>null</code>.
+     * @param taskClass The full name of the class implementing the task.
+     *                  Must not be <code>null</code>.
+     *
+     * @exception BuildException if the class is unsuitable for being an Ant
+     *                           task. An error level message is logged before
+     *                           this exception is thrown.
+     *
+     * @see #checkTaskClass(Class)
+     */
+    public void addTaskDefinition(String taskName, Class taskClass) {
+        checkTaskClass(taskClass);
+        AntTypeDefinition def = new AntTypeDefinition();
+        def.setName(taskName);
+        def.setClassLoader(taskClass.getClassLoader());
+        def.setClass(taskClass);
+        def.setAdapterClass(TaskAdapter.class);
+        def.setClassName(taskClass.getName());
+        def.setAdaptToClass(Task.class);
+        updateDataTypeDefinition(def);
+    }
+
+    /**
+     * Checks whether or not a class is suitable for serving as Ant task.
+     * Ant task implementation classes must be public, concrete, and have
+     * a no-arg constructor.
+     *
+     * @param taskClass The class to be checked.
+     *                  Must not be <code>null</code>.
+     *
+     * @exception BuildException if the class is unsuitable for being an Ant
+     *                           task. An error level message is logged before
+     *                           this exception is thrown.
+     */
+    public void checkTaskClass(final Class taskClass) throws BuildException {
+        if (!Modifier.isPublic(taskClass.getModifiers())) {
+            final String message = taskClass + " is not public";
+            project.log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        }
+        if (Modifier.isAbstract(taskClass.getModifiers())) {
+            final String message = taskClass + " is abstract";
+            project.log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        }
+        try {
+            taskClass.getConstructor((Class[]) null);
+            // don't have to check for public, since
+            // getConstructor finds public constructors only.
+        } catch (NoSuchMethodException e) {
+            final String message = "No public no-arg constructor in " + taskClass;
+            project.log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        }
+        if (!Task.class.isAssignableFrom(taskClass)) {
+            TaskAdapter.checkTaskClass(taskClass, project);
+        }
+    }
+
+    /**
+     * Returns the current task definition hashtable. The returned hashtable is
+     * "live" and so should not be modified.
+     *
+     * @return a map of from task name to implementing class
+     *         (String to Class).
+     */
+    public Hashtable getTaskDefinitions() {
+        synchronized (taskClassDefinitions) {
+            synchronized (antTypeTable) {
+                if (rebuildTaskClassDefinitions) {
+                    taskClassDefinitions.clear();
+                    for (Iterator i = antTypeTable.keySet().iterator(); i.hasNext();) {
+                        String name = (String) i.next();
+                        Class clazz = antTypeTable.getExposedClass(name);
+                        if (clazz == null) {
+                            continue;
+                        }
+                        if (Task.class.isAssignableFrom(clazz)) {
+                            taskClassDefinitions.put(name, antTypeTable.getTypeClass(name));
+                        }
+                    }
+                    rebuildTaskClassDefinitions = false;
+                }
+            }
+        }
+        return taskClassDefinitions;
+    }
+
+    /**
+     * Returns the current type definition hashtable. The returned hashtable is
+     * "live" and so should not be modified.
+     *
+     * @return a map of from type name to implementing class
+     *         (String to Class).
+     */
+    public Hashtable getDataTypeDefinitions() {
+        synchronized (typeClassDefinitions) {
+            synchronized (antTypeTable) {
+                if (rebuildTypeClassDefinitions) {
+                    typeClassDefinitions.clear();
+                    for (Iterator i = antTypeTable.keySet().iterator(); i.hasNext();) {
+                        String name = (String) i.next();
+                        Class clazz = antTypeTable.getExposedClass(name);
+                        if (clazz == null) {
+                            continue;
+                        }
+                        if (!(Task.class.isAssignableFrom(clazz))) {
+                            typeClassDefinitions.put(name, antTypeTable.getTypeClass(name));
+                        }
+                    }
+                    rebuildTypeClassDefinitions = false;
+                }
+            }
+        }
+        return typeClassDefinitions;
+    }
+
+    /**
+     * This returns a list of restricted definitions for a name.
+     * @param componentName the name to use.
+     * @return the list of restricted definitions for a particular name.
+     */
+    public List getRestrictedDefinitions(String componentName) {
+        return (List) restrictedDefinitions.get(componentName);
+    }
+
+    /**
+     * Adds a new datatype definition.
+     * Attempting to override an existing definition with an
+     * equivalent one (i.e. with the same classname) results in
+     * a verbose log message. Attempting to override an existing definition
+     * with a different one results in a warning log message, but the
+     * definition is changed.
+     *
+     * @param typeName The name of the datatype.
+     *                 Must not be <code>null</code>.
+     * @param typeClass The full name of the class implementing the datatype.
+     *                  Must not be <code>null</code>.
+     */
+    public void addDataTypeDefinition(String typeName, Class typeClass) {
+        AntTypeDefinition def = new AntTypeDefinition();
+        def.setName(typeName);
+        def.setClass(typeClass);
+        updateDataTypeDefinition(def);
+        project.log(" +User datatype: " + typeName + "     " + typeClass.getName(),
+                Project.MSG_DEBUG);
+    }
+
+    /**
+     * Describe <code>addDataTypeDefinition</code> method here.
+     *
+     * @param def an <code>AntTypeDefinition</code> value.
+     */
+    public void addDataTypeDefinition(AntTypeDefinition def) {
+        if (!def.isRestrict()) {
+           updateDataTypeDefinition(def);
+        } else {
+            updateRestrictedDefinition(def);
+        }
+    }
+
+    /**
+     * Returns the current datatype definition hashtable. The returned
+     * hashtable is "live" and so should not be modified.
+     *
+     * @return a map of from datatype name to implementing class
+     *         (String to Class).
+     */
+    public Hashtable getAntTypeTable() {
+        return antTypeTable;
+    }
+
+    /**
+     * Creates a new instance of a task.
+     *
+     *  Called from Project.createTask(), which can be called by tasks.
+     *
+     * @param taskType The name of the task to create an instance of.
+     *                 Must not be <code>null</code>.
+     *
+     * @return an instance of the specified task, or <code>null</code> if
+     *         the task name is not recognised.
+     *
+     * @exception BuildException if the task name is recognised but task
+     *                           creation fails.
+     */
+    public Task createTask(String taskType) throws BuildException {
+        Task task = createNewTask(taskType);
+        if (task == null && taskType.equals(ANT_PROPERTY_TASK)) {
+            // quick fix for Ant.java use of property before
+            // initializing the project
+            addTaskDefinition(ANT_PROPERTY_TASK, org.apache.tools.ant.taskdefs.Property.class);
+            task = createNewTask(taskType);
+        }
+        return task;
+    }
+
+    /**
+     * Creates a new instance of a task.
+     * @since ant1.6
+     * @param taskType The name of the task to create an instance of.
+     *                 Must not be <code>null</code>.
+     *
+     * @return an instance of the specified task, or <code>null</code> if
+     *         the task name is not recognised.
+     *
+     * @exception BuildException if the task name is recognised but task
+     *                           creation fails.
+     */
+    private Task createNewTask(String taskType) throws BuildException {
+        Class c = getComponentClass(taskType);
+        if (c == null || !(Task.class.isAssignableFrom(c))) {
+            return null;
+        }
+        Object obj = createComponent(taskType);
+        if (obj == null) {
+            return null;
+        }
+        if (!(obj instanceof Task)) {
+            throw new BuildException("Expected a Task from '" + taskType
+                    + "' but got an instance of " + obj.getClass().getName() + " instead");
+        }
+        Task task = (Task) obj;
+        task.setTaskType(taskType);
+
+        // set default value, can be changed by the user
+        task.setTaskName(taskType);
+
+        project.log("   +Task: " + taskType, Project.MSG_DEBUG);
+        return task;
+    }
+
+    /**
+     * Creates a new instance of a data type.
+     *
+     * @param typeName The name of the data type to create an instance of.
+     *                 Must not be <code>null</code>.
+     *
+     * @return an instance of the specified data type, or <code>null</code> if
+     *         the data type name is not recognised.
+     *
+     * @exception BuildException if the data type name is recognised but
+     *                           instance creation fails.
+     */
+    public Object createDataType(String typeName) throws BuildException {
+        return createComponent(typeName);
+    }
+
+    /**
+     * Returns a description of the type of the given element.
+     * <p>
+     * This is useful for logging purposes.
+     *
+     * @param element The element to describe.
+     *                Must not be <code>null</code>.
+     *
+     * @return a description of the element type.
+     *
+     * @since Ant 1.6
+     */
+    public String getElementName(Object element) {
+        return getElementName(element, false);
+    }
+
+    /**
+     * Returns a description of the type of the given element.
+     * <p>
+     * This is useful for logging purposes.
+     *
+     * @param o     The element to describe.
+     *              Must not be <code>null</code>.
+     * @param brief whether to use a brief description.
+     * @return a description of the element type.
+     *
+     * @since Ant 1.7
+     */
+    public String getElementName(Object o, boolean brief) {
+        //  PR: I do not know what to do if the object class
+        //      has multiple defines
+        //      but this is for logging only...
+        Class elementClass = o.getClass();
+        String elementClassname = elementClass.getName();
+        for (Iterator i = antTypeTable.values().iterator(); i.hasNext();) {
+            AntTypeDefinition def = (AntTypeDefinition) i.next();
+            if (elementClassname.equals(def.getClassName())
+                    && (elementClass == def.getExposedClass(project))) {
+                String name = def.getName();
+                return brief ? name : "The <" + name + "> type";
+            }
+        }
+        return getUnmappedElementName(o.getClass(), brief);
+    }
+
+    /**
+     * Convenient way to get some element name even when you may not have a
+     * Project context.
+     * @param p       The optional Project instance.
+     * @param o       The element to describe.
+     *                Must not be <code>null</code>.
+     * @param brief   whether to use a brief description.
+     * @return a description of the element type.
+     * @since Ant 1.7
+     */
+    public static String getElementName(Project p, Object o, boolean brief) {
+        if (p == null) {
+            p = Project.getProject(o);
+        }
+        return p == null ? getUnmappedElementName(o.getClass(), brief) : getComponentHelper(p)
+                .getElementName(o, brief);
+    }
+
+    private static String getUnmappedElementName(Class c, boolean brief) {
+        if (brief) {
+            String name = c.getName();
+            return name.substring(name.lastIndexOf('.') + 1);
+        }
+        return c.toString();
+    }
+
+    /**
+     * Check if definition is a valid definition--it may be a
+     * definition of an optional task that does not exist.
+     * @param def the definition to test.
+     * @return true if exposed type of definition is present.
+     */
+    private boolean validDefinition(AntTypeDefinition def) {
+        return !(def.getTypeClass(project) == null || def.getExposedClass(project) == null);
+    }
+
+    /**
+     * Check if two definitions are the same.
+     * @param def  the new definition.
+     * @param old the old definition.
+     * @return true if the two definitions are the same.
+     */
+    private boolean sameDefinition(AntTypeDefinition def, AntTypeDefinition old) {
+        boolean defValid = validDefinition(def);
+        boolean sameValidity = (defValid == validDefinition(old));
+        //must have same validity; then if they are valid they must also be the same:
+        return sameValidity && (!defValid || def.sameDefinition(old, project));
+    }
+
+    /**
+      * update the restricted definition table with a new or
+      * modified definition.
+      */
+    private void updateRestrictedDefinition(AntTypeDefinition def) {
+        String name = def.getName();
+        synchronized (restrictedDefinitions) {
+            List list = (List) restrictedDefinitions.get(name);
+            if (list == null) {
+                list = new ArrayList();
+                restrictedDefinitions.put(name, list);
+            }
+            // Check if the classname is already present and remove it
+            // if it is
+            for (Iterator i = list.iterator(); i.hasNext();) {
+                AntTypeDefinition current = (AntTypeDefinition) i.next();
+                if (current.getClassName().equals(def.getClassName())) {
+                    i.remove();
+                    break;
+                }
+            }
+            list.add(def);
+        }
+    }
+
+    /**
+     * Update the component definition table with a new or
+     * modified definition.
+     * @param def the definition to update or insert.
+     */
+    private void updateDataTypeDefinition(AntTypeDefinition def) {
+        String name = def.getName();
+        synchronized (antTypeTable) {
+            rebuildTaskClassDefinitions = true;
+            rebuildTypeClassDefinitions = true;
+            AntTypeDefinition old = antTypeTable.getDefinition(name);
+            if (old != null) {
+                if (sameDefinition(def, old)) {
+                    return;
+                }
+                Class oldClass = antTypeTable.getExposedClass(name);
+                boolean isTask = oldClass != null && Task.class.isAssignableFrom(oldClass);
+                project.log("Trying to override old definition of "
+                        + (isTask ? "task " : "datatype ") + name, (def.similarDefinition(old,
+                        project)) ? Project.MSG_VERBOSE : Project.MSG_WARN);
+            }
+            project.log(" +Datatype " + name + " " + def.getClassName(), Project.MSG_DEBUG);
+            antTypeTable.put(name, def);
+        }
+    }
+
+    /**
+     * Called at the start of processing an antlib.
+     * @param uri the uri that is associated with this antlib.
+     */
+    public void enterAntLib(String uri) {
+        antLibCurrentUri = uri;
+        antLibStack.push(uri);
+    }
+
+    /**
+     * @return the current antlib uri.
+     */
+    public String getCurrentAntlibUri() {
+        return antLibCurrentUri;
+    }
+
+    /**
+     * Called at the end of processing an antlib.
+     */
+    public void exitAntLib() {
+        antLibStack.pop();
+        antLibCurrentUri = (antLibStack.size() == 0) ? null : (String) antLibStack.peek();
+    }
+
+    /**
+     * Load ant's tasks.
+     */
+    private void initTasks() {
+        ClassLoader classLoader = getClassLoader(null);
+        Properties props = getDefaultDefinitions(false);
+        Enumeration e = props.propertyNames();
+        while (e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            String className = props.getProperty(name);
+            AntTypeDefinition def = new AntTypeDefinition();
+            def.setName(name);
+            def.setClassName(className);
+            def.setClassLoader(classLoader);
+            def.setAdaptToClass(Task.class);
+            def.setAdapterClass(TaskAdapter.class);
+            antTypeTable.put(name, def);
+        }
+    }
+
+    private ClassLoader getClassLoader(ClassLoader classLoader) {
+        String buildSysclasspath = project.getProperty(MagicNames.BUILD_SYSCLASSPATH);
+        if (project.getCoreLoader() != null
+            && !(BUILD_SYSCLASSPATH_ONLY.equals(buildSysclasspath))) {
+            classLoader = project.getCoreLoader();
+        }
+        return classLoader;
+    }
+
+    /**
+     * Load default task or type definitions - just the names,
+     *  no class loading.
+     * Caches results between calls to reduce overhead.
+     * @param type true for typedefs, false for taskdefs
+     * @return a mapping from definition names to class names
+     * @throws BuildException if there was some problem loading
+     *                        or parsing the definitions list
+     */
+    private static synchronized Properties getDefaultDefinitions(boolean type)
+            throws BuildException {
+        int idx = type ? 1 : 0;
+        if (defaultDefinitions[idx] == null) {
+            String resource = type ? MagicNames.TYPEDEFS_PROPERTIES_RESOURCE
+                    : MagicNames.TASKDEF_PROPERTIES_RESOURCE;
+            String errorString = type ? ERROR_NO_TYPE_LIST_LOAD : ERROR_NO_TASK_LIST_LOAD;
+            InputStream in = null;
+            try {
+                in = ComponentHelper.class.getResourceAsStream(resource);
+                if (in == null) {
+                    throw new BuildException(errorString);
+                }
+                Properties p = new Properties();
+                p.load(in);
+                defaultDefinitions[idx] = p;
+            } catch (IOException e) {
+                throw new BuildException(errorString, e);
+            } finally {
+                FileUtils.close(in);
+            }
+        }
+        return defaultDefinitions[idx];
+    }
+
+    /**
+     * Load ant's datatypes.
+     */
+    private void initTypes() {
+        ClassLoader classLoader = getClassLoader(null);
+        Properties props = getDefaultDefinitions(true);
+        Enumeration e = props.propertyNames();
+        while (e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            String className = props.getProperty(name);
+            AntTypeDefinition def = new AntTypeDefinition();
+            def.setName(name);
+            def.setClassName(className);
+            def.setClassLoader(classLoader);
+            antTypeTable.put(name, def);
+        }
+    }
+
+    /**
+     * Called for each component name, check if the
+     * associated URI has been examined for antlibs.
+     * @param componentName the name of the component, which should include a URI
+     *                      prefix if it is in a namespace
+     */
+    private synchronized void checkNamespace(String componentName) {
+        String uri = ProjectHelper.extractUriFromComponentName(componentName);
+        if ("".equals(uri)) {
+            uri = ProjectHelper.ANT_CORE_URI;
+        }
+        if (!uri.startsWith(ProjectHelper.ANTLIB_URI)) {
+            return; // namespace that does not contain antlib
+        }
+        if (checkedNamespaces.contains(uri)) {
+            return; // Already processed
+        }
+        checkedNamespaces.add(uri);
+        Typedef definer = new Typedef();
+        definer.setProject(project);
+        definer.init();
+        definer.setURI(uri);
+        //there to stop error messages being "null"
+        definer.setTaskName(uri);
+        //if this is left out, bad things happen. like all build files break
+        //on the first element encountered.
+        definer.setResource(Definer.makeResourceFromURI(uri));
+        // a fishing expedition :- ignore errors if antlib not present
+        definer.setOnError(new Typedef.OnError(Typedef.OnError.POLICY_IGNORE));
+        definer.execute();
+    }
+
+    /**
+     * Handler called to do decent diagnosis on instantiation failure.
+     * @param componentName component name.
+     * @param type component type, used in error messages
+     * @return a string containing as much diagnostics info as possible.
+     */
+    public String diagnoseCreationFailure(String componentName, String type) {
+        StringWriter errorText = new StringWriter();
+        PrintWriter out = new PrintWriter(errorText);
+        out.println("Problem: failed to create " + type + " " + componentName);
+        //class of problem
+        boolean lowlevel = false;
+        boolean jars = false;
+        boolean definitions = false;
+        boolean antTask;
+        String home = System.getProperty(Launcher.USER_HOMEDIR);
+        File libDir = new File(home, Launcher.USER_LIBDIR);
+        String antHomeLib;
+        boolean probablyIDE = false;
+        String anthome = System.getProperty(MagicNames.ANT_HOME);
+        if (anthome != null) {
+            File antHomeLibDir = new File(anthome, "lib");
+            antHomeLib = antHomeLibDir.getAbsolutePath();
+        } else {
+            //running under an IDE that doesn't set ANT_HOME
+            probablyIDE = true;
+            antHomeLib = "ANT_HOME" + File.separatorChar + "lib";
+        }
+        StringBuffer dirListingText = new StringBuffer();
+        final String tab = "        -";
+        dirListingText.append(tab);
+        dirListingText.append(antHomeLib);
+        dirListingText.append('\n');
+        if (probablyIDE) {
+            dirListingText.append(tab);
+            dirListingText.append("the IDE Ant configuration dialogs");
+        } else {
+            dirListingText.append(tab);
+            dirListingText.append(libDir);
+            dirListingText.append('\n');
+            dirListingText.append(tab);
+            dirListingText.append("a directory added on the command line with the -lib argument");
+        }
+        String dirListing = dirListingText.toString();
+
+        //look up the name
+        AntTypeDefinition def = getDefinition(componentName);
+        if (def == null) {
+            //not a known type
+            printUnknownDefinition(out, componentName, dirListing);
+            definitions = true;
+        } else {
+            //we are defined, so it is an instantiation problem
+            final String classname = def.getClassName();
+            antTask = classname.startsWith("org.apache.tools.ant.");
+            boolean optional = classname.startsWith("org.apache.tools.ant.taskdefs.optional");
+            optional |= classname.startsWith("org.apache.tools.ant.types.optional");
+
+            //start with instantiating the class.
+            Class clazz = null;
+            try {
+                clazz = def.innerGetTypeClass();
+            } catch (ClassNotFoundException e) {
+                jars = true;
+                if (!optional) {
+                    definitions = true;
+                }
+                printClassNotFound(out, classname, optional, dirListing);
+            } catch (NoClassDefFoundError ncdfe) {
+                jars = true;
+                printNotLoadDependentClass(out, optional, ncdfe, dirListing);
+            }
+            //here we successfully loaded the class or failed.
+            if (clazz != null) {
+                //success: proceed with more steps
+                try {
+                    def.innerCreateAndSet(clazz, project);
+                    //hey, there is nothing wrong with us
+                    out.println("The component could be instantiated.");
+                } catch (NoSuchMethodException e) {
+                    lowlevel = true;
+                    out.println("Cause: The class " + classname
+                            + " has no compatible constructor.");
+
+                } catch (InstantiationException e) {
+                    lowlevel = true;
+                    out.println("Cause: The class " + classname
+                            + " is abstract and cannot be instantiated.");
+                } catch (IllegalAccessException e) {
+                    lowlevel = true;
+                    out.println("Cause: The constructor for " + classname
+                            + " is private and cannot be invoked.");
+                } catch (InvocationTargetException ex) {
+                    lowlevel = true;
+                    Throwable t = ex.getTargetException();
+                    out.println("Cause: The constructor threw the exception");
+                    out.println(t.toString());
+                    t.printStackTrace(out);
+                }  catch (NoClassDefFoundError ncdfe) {
+                    jars = true;
+                    out.println("Cause:  A class needed by class " + classname
+                            + " cannot be found: ");
+                    out.println("       " + ncdfe.getMessage());
+                    out.println("Action: Determine what extra JAR files are"
+                            + " needed, and place them in:");
+                    out.println(dirListing);
+                }
+            }
+            out.println();
+            out.println("Do not panic, this is a common problem.");
+            if (definitions) {
+                out.println("It may just be a typographical error in the build file "
+                        + "or the task/type declaration.");
+            }
+            if (jars) {
+                out.println("The commonest cause is a missing JAR.");
+            }
+            if (lowlevel) {
+                out.println("This is quite a low level problem, which may need "
+                        + "consultation with the author of the task.");
+                if (antTask) {
+                    out.println("This may be the Ant team. Please file a "
+                            + "defect or contact the developer team.");
+                } else {
+                    out.println("This does not appear to be a task bundled with Ant.");
+                    out.println("Please take it up with the supplier of the third-party " + type
+                            + ".");
+                    out.println("If you have written it yourself, you probably have a bug to fix.");
+                }
+            } else {
+                out.println();
+                out.println("This is not a bug; it is a configuration problem");
+            }
+        }
+        out.flush();
+        out.close();
+        return errorText.toString();
+    }
+
+    /**
+     * Print unknown definition.forking
+     */
+    private void printUnknownDefinition(PrintWriter out, String componentName, String dirListing) {
+        boolean isAntlib = componentName.indexOf(MagicNames.ANTLIB_PREFIX) == 0;
+        String uri = ProjectHelper.extractUriFromComponentName(componentName);
+        out.println("Cause: The name is undefined.");
+        out.println("Action: Check the spelling.");
+        out.println("Action: Check that any custom tasks/types have been declared.");
+        out.println("Action: Check that any <presetdef>/<macrodef>"
+                + " declarations have taken place.");
+        if (uri.length() > 0) {
+            List matches = antTypeTable.findMatches(uri);
+            if (matches.size() > 0) {
+                out.println();
+                out.println("The definitions in the namespace " + uri + " are:");
+                for (Iterator it = matches.iterator(); it.hasNext();) {
+                    AntTypeDefinition def = (AntTypeDefinition) it.next();
+                    String local = ProjectHelper.extractNameFromComponentName(def.getName());
+                    out.println("    " + local);
+                }
+            } else {
+                out.println("No types or tasks have been defined in this namespace yet");
+                if (isAntlib) {
+                    out.println();
+                    out.println("This appears to be an antlib declaration. ");
+                    out.println("Action: Check that the implementing library exists in one of:");
+                    out.println(dirListing);
+                }
+            }
+        }
+    }
+
+    /**
+     * Print class not found.
+     */
+    private void printClassNotFound(PrintWriter out, String classname, boolean optional,
+            String dirListing) {
+        out.println("Cause: the class " + classname + " was not found.");
+        if (optional) {
+            out.println("        This looks like one of Ant's optional components.");
+            out.println("Action: Check that the appropriate optional JAR exists in");
+            out.println(dirListing);
+        } else {
+            out.println("Action: Check that the component has been correctly declared");
+            out.println("        and that the implementing JAR is in one of:");
+            out.println(dirListing);
+        }
+    }
+
+    /**
+     * Print could not load dependent class.
+     */
+    private void printNotLoadDependentClass(PrintWriter out, boolean optional,
+            NoClassDefFoundError ncdfe, String dirListing) {
+        out.println("Cause: Could not load a dependent class "
+                    +  ncdfe.getMessage());
+        if (optional) {
+            out.println("       It is not enough to have Ant's optional JARs");
+            out.println("       you need the JAR files that the" + " optional tasks depend upon.");
+            out.println("       Ant's optional task dependencies are" + " listed in the manual.");
+        } else {
+            out.println("       This class may be in a separate JAR" + " that is not installed.");
+        }
+        out.println("Action: Determine what extra JAR files are"
+                + " needed, and place them in one of:");
+        out.println(dirListing);
+    }
+
+    /**
+     * Map that contains the component definitions.
+     */
+    private static class AntTypeTable extends Hashtable {
+        private static final long serialVersionUID = -3060442320477772028L;
+        private Project project;
+
+        AntTypeTable(Project project) {
+            this.project = project;
+        }
+
+        AntTypeDefinition getDefinition(String key) {
+            return (AntTypeDefinition) (super.get(key));
+        }
+
+        public Object get(Object key) {
+            return getTypeClass((String) key);
+        }
+
+        Object create(String name) {
+            AntTypeDefinition def = getDefinition(name);
+            return (def == null) ? null : def.create(project);
+        }
+
+        Class getTypeClass(String name) {
+            AntTypeDefinition def = getDefinition(name);
+            return (def == null) ? null : def.getTypeClass(project);
+        }
+
+        Class getExposedClass(String name) {
+            AntTypeDefinition def = getDefinition(name);
+            return def == null ? null : def.getExposedClass(project);
+        }
+
+        public boolean contains(Object clazz) {
+            boolean found = false;
+            if (clazz instanceof Class) {
+                for (Iterator i = values().iterator(); i.hasNext() && !found;) {
+                    found = (((AntTypeDefinition) (i.next())).getExposedClass(project) == clazz);
+                }
+            }
+            return found;
+        }
+
+        public boolean containsValue(Object value) {
+            return contains(value);
+        }
+
+        /**
+         * Create a list of all definitions that match a prefix, usually the URI
+         * of a library
+         * @param prefix prefix to match off
+         * @return the (possibly empty) list of definitions
+         */
+        public List/*<AntTypeDefinition>*/ findMatches(String prefix) {
+            ArrayList matches = new ArrayList();
+            for (Iterator i = values().iterator(); i.hasNext();) {
+                AntTypeDefinition def = (AntTypeDefinition) (i.next());
+                if (def.getName().startsWith(prefix)) {
+                    matches.add(def);
+                }
+            }
+            return matches;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DefaultLogger.java b/trunk/src/main/org/apache/tools/ant/DefaultLogger.java
new file mode 100644
index 0000000..05687c7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DefaultLogger.java
@@ -0,0 +1,373 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.Date;
+import java.text.DateFormat;
+
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Writes build events to a PrintStream. Currently, it
+ * only writes which targets are being executed, and
+ * any messages that get logged.
+ *
+ */
+public class DefaultLogger implements BuildLogger {
+    /**
+     * Size of left-hand column for right-justified task name.
+     * @see #messageLogged(BuildEvent)
+     */
+    public static final int LEFT_COLUMN_SIZE = 12;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** PrintStream to write non-error messages to */
+    protected PrintStream out;
+
+    /** PrintStream to write error messages to */
+    protected PrintStream err;
+
+    /** Lowest level of message to write out */
+    protected int msgOutputLevel = Project.MSG_ERR;
+
+    /** Time of the start of the build */
+    private long startTime = System.currentTimeMillis();
+
+    // CheckStyle:ConstantNameCheck OFF - bc
+    /** Line separator */
+    protected static final String lSep = StringUtils.LINE_SEP;
+    // CheckStyle:ConstantNameCheck ON
+
+    /** Whether or not to use emacs-style output */
+    protected boolean emacsMode = false;
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     * Sole constructor.
+     */
+    public DefaultLogger() {
+    }
+
+    /**
+     * Sets the highest level of message this logger should respond to.
+     *
+     * Only messages with a message level lower than or equal to the
+     * given level should be written to the log.
+     * <p>
+     * Constants for the message levels are in the
+     * {@link Project Project} class. The order of the levels, from least
+     * to most verbose, is <code>MSG_ERR</code>, <code>MSG_WARN</code>,
+     * <code>MSG_INFO</code>, <code>MSG_VERBOSE</code>,
+     * <code>MSG_DEBUG</code>.
+     * <p>
+     * The default message level for DefaultLogger is Project.MSG_ERR.
+     *
+     * @param level the logging level for the logger.
+     */
+    public void setMessageOutputLevel(int level) {
+        this.msgOutputLevel = level;
+    }
+
+    /**
+     * Sets the output stream to which this logger is to send its output.
+     *
+     * @param output The output stream for the logger.
+     *               Must not be <code>null</code>.
+     */
+    public void setOutputPrintStream(PrintStream output) {
+        this.out = new PrintStream(output, true);
+    }
+
+    /**
+     * Sets the output stream to which this logger is to send error messages.
+     *
+     * @param err The error stream for the logger.
+     *            Must not be <code>null</code>.
+     */
+    public void setErrorPrintStream(PrintStream err) {
+        this.err = new PrintStream(err, true);
+    }
+
+    /**
+     * Sets this logger to produce emacs (and other editor) friendly output.
+     *
+     * @param emacsMode <code>true</code> if output is to be unadorned so that
+     *                  emacs and other editors can parse files names, etc.
+     */
+    public void setEmacsMode(boolean emacsMode) {
+        this.emacsMode = emacsMode;
+    }
+
+    /**
+     * Responds to a build being started by just remembering the current time.
+     *
+     * @param event Ignored.
+     */
+    public void buildStarted(BuildEvent event) {
+        startTime = System.currentTimeMillis();
+    }
+
+    /**
+     * Prints whether the build succeeded or failed,
+     * any errors the occurred during the build, and
+     * how long the build took.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     */
+    public void buildFinished(BuildEvent event) {
+        Throwable error = event.getException();
+        StringBuffer message = new StringBuffer();
+        if (error == null) {
+            message.append(StringUtils.LINE_SEP);
+            message.append(getBuildSuccessfulMessage());
+        } else {
+            message.append(StringUtils.LINE_SEP);
+            message.append(getBuildFailedMessage());
+            message.append(StringUtils.LINE_SEP);
+
+            while (error instanceof BuildException) { // #43398
+                Throwable cause = ((BuildException) error).getCause();
+                if (cause != null && cause.toString().equals(error.getMessage())) {
+                    error = cause;
+                } else {
+                    break;
+                }
+            }
+
+            if (Project.MSG_VERBOSE <= msgOutputLevel
+                || !(error instanceof BuildException)) {
+                message.append(StringUtils.getStackTrace(error));
+            } else {
+                message.append(error.toString()).append(lSep);
+            }
+        }
+        message.append(StringUtils.LINE_SEP);
+        message.append("Total time: ");
+        message.append(formatTime(System.currentTimeMillis() - startTime));
+
+        String msg = message.toString();
+        if (error == null) {
+            printMessage(msg, out, Project.MSG_VERBOSE);
+        } else {
+            printMessage(msg, err, Project.MSG_ERR);
+        }
+        log(msg);
+    }
+
+    /**
+     * This is an override point: the message that indicates whether a build failed.
+     * Subclasses can change/enhance the message.
+     * @return The classic "BUILD FAILED"
+     */
+    protected String getBuildFailedMessage() {
+        return "BUILD FAILED";
+    }
+
+    /**
+     * This is an override point: the message that indicates that a build succeeded.
+     * Subclasses can change/enhance the message.
+     * @return The classic "BUILD SUCCESSFUL"
+     */
+    protected String getBuildSuccessfulMessage() {
+        return "BUILD SUCCESSFUL";
+    }
+
+    /**
+     * Logs a message to say that the target has started if this
+     * logger allows information-level messages.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+      */
+    public void targetStarted(BuildEvent event) {
+        if (Project.MSG_INFO <= msgOutputLevel
+            && !event.getTarget().getName().equals("")) {
+            String msg = StringUtils.LINE_SEP
+                + event.getTarget().getName() + ":";
+            printMessage(msg, out, event.getPriority());
+            log(msg);
+        }
+    }
+
+    /**
+     * No-op implementation.
+     *
+     * @param event Ignored.
+     */
+    public void targetFinished(BuildEvent event) {
+    }
+
+    /**
+     * No-op implementation.
+     *
+     * @param event Ignored.
+     */
+    public void taskStarted(BuildEvent event) {
+    }
+
+    /**
+     * No-op implementation.
+     *
+     * @param event Ignored.
+     */
+    public void taskFinished(BuildEvent event) {
+    }
+
+    /**
+     * Logs a message, if the priority is suitable.
+     * In non-emacs mode, task level messages are prefixed by the
+     * task name which is right-justified.
+     *
+     * @param event A BuildEvent containing message information.
+     *              Must not be <code>null</code>.
+     */
+    public void messageLogged(BuildEvent event) {
+        int priority = event.getPriority();
+        // Filter out messages based on priority
+        if (priority <= msgOutputLevel) {
+
+            StringBuffer message = new StringBuffer();
+            if (event.getTask() != null && !emacsMode) {
+                // Print out the name of the task if we're in one
+                String name = event.getTask().getTaskName();
+                String label = "[" + name + "] ";
+                int size = LEFT_COLUMN_SIZE - label.length();
+                StringBuffer tmp = new StringBuffer();
+                for (int i = 0; i < size; i++) {
+                    tmp.append(" ");
+                }
+                tmp.append(label);
+                label = tmp.toString();
+
+                BufferedReader r = null;
+                try {
+                    r = new BufferedReader(
+                            new StringReader(event.getMessage()));
+                    String line = r.readLine();
+                    boolean first = true;
+                    do {
+                        if (first) {
+                            if (line == null) {
+                                message.append(label);
+                                break;
+                            }
+                        } else {
+                            message.append(StringUtils.LINE_SEP);
+                        }
+                        first = false;
+                        message.append(label).append(line);
+                        line = r.readLine();
+                    } while (line != null);
+                } catch (IOException e) {
+                    // shouldn't be possible
+                    message.append(label).append(event.getMessage());
+                } finally {
+                    if (r != null) {
+                        FileUtils.close(r);
+                    }
+                }
+
+            } else {
+                //emacs mode or there is no task
+                message.append(event.getMessage());
+            }
+            Throwable ex = event.getException();
+            if (Project.MSG_DEBUG <= msgOutputLevel && ex != null) {
+                    message.append(StringUtils.getStackTrace(ex));
+            }
+
+            String msg = message.toString();
+            if (priority != Project.MSG_ERR) {
+                printMessage(msg, out, priority);
+            } else {
+                printMessage(msg, err, priority);
+            }
+            log(msg);
+        }
+    }
+
+    /**
+     * Convenience method to format a specified length of time.
+     *
+     * @param millis Length of time to format, in milliseconds.
+     *
+     * @return the time as a formatted string.
+     *
+     * @see DateUtils#formatElapsedTime(long)
+     */
+    protected static String formatTime(final long millis) {
+        return DateUtils.formatElapsedTime(millis);
+    }
+
+    /**
+     * Prints a message to a PrintStream.
+     *
+     * @param message  The message to print.
+     *                 Should not be <code>null</code>.
+     * @param stream   A PrintStream to print the message to.
+     *                 Must not be <code>null</code>.
+     * @param priority The priority of the message.
+     *                 (Ignored in this implementation.)
+     */
+    protected void printMessage(final String message,
+                                final PrintStream stream,
+                                final int priority) {
+        stream.println(message);
+    }
+
+    /**
+     * Empty implementation which allows subclasses to receive the
+     * same output that is generated here.
+     *
+     * @param message Message being logged. Should not be <code>null</code>.
+     */
+    protected void log(String message) {
+    }
+
+    /**
+     * Get the current time.
+     * @return the current time as a formatted string.
+     * @since Ant1.7.1
+     */
+    protected String getTimestamp() {
+        Date date = new Date(System.currentTimeMillis());
+        DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
+        String finishTime = formatter.format(date);
+        return finishTime;
+    }
+
+    /**
+     * Get the project name or null
+     * @param event the event
+     * @return the project that raised this event
+     * @since Ant1.7.1
+     */
+    protected String extractProjectName(BuildEvent event) {
+        Project project = event.getProject();
+        return (project != null) ? project.getName() : null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DemuxInputStream.java b/trunk/src/main/org/apache/tools/ant/DemuxInputStream.java
new file mode 100644
index 0000000..253ff85
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DemuxInputStream.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ *
+ * Passes input requests to the project object for demuxing into
+ * individual tasks and threads.
+ *
+ * @since Ant 1.6
+ */
+public class DemuxInputStream extends InputStream {
+
+    /**
+     * The project to from which to get input.
+     */
+    private Project project;
+
+    /**
+     * Create a DemuxInputStream for the given project
+     *
+     * @param project the project instance
+     */
+    public DemuxInputStream(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Read a byte from the project's demuxed input.
+     * @return the next byte
+     * @throws IOException on error
+     */
+    public int read() throws IOException {
+        byte[] buffer = new byte[1];
+        if (project.demuxInput(buffer, 0, 1) == -1) {
+            return -1;
+        }
+        return buffer[0];
+    }
+
+
+    /**
+     * Read bytes from the project's demuxed input.
+     * @param buffer an array of bytes to read into
+     * @param offset the offset in the array of bytes
+     * @param length the number of bytes in the array
+     * @return the number of bytes read
+     * @throws IOException on error
+     */
+    public int read(byte[] buffer, int offset, int length) throws IOException {
+        return project.demuxInput(buffer, offset, length);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DemuxOutputStream.java b/trunk/src/main/org/apache/tools/ant/DemuxOutputStream.java
new file mode 100644
index 0000000..7ad7f94
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DemuxOutputStream.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.WeakHashMap;
+
+/**
+ * Logs content written by a thread and forwards the buffers onto the
+ * project object which will forward the content to the appropriate
+ * task.
+ *
+ * @since 1.4
+ */
+public class DemuxOutputStream extends OutputStream {
+
+    /**
+     * A data class to store information about a buffer. Such information
+     * is stored on a per-thread basis.
+     */
+    private static class BufferInfo {
+        /**
+         * The per-thread output stream.
+         */
+        private ByteArrayOutputStream buffer;
+
+        /**
+         * Indicates we have just seen a carriage return. It may be part of
+         * a crlf pair or a single cr invoking processBuffer twice.
+         */
+         private boolean crSeen = false;
+    }
+
+    /** Maximum buffer size. */
+    private static final int MAX_SIZE = 1024;
+
+    /** Initial buffer size. */
+    private static final int INTIAL_SIZE = 132;
+
+    /** Carriage return */
+    private static final int CR = 0x0d;
+
+    /** Linefeed */
+    private static final int LF = 0x0a;
+
+    /** Mapping from thread to buffer (Thread to BufferInfo). */
+    private WeakHashMap buffers = new WeakHashMap();
+
+    /**
+     * The project to send output to.
+     */
+    private Project project;
+
+    /**
+     * Whether or not this stream represents an error stream.
+     */
+    private boolean isErrorStream;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param project The project instance for which output is being
+     *                demultiplexed. Must not be <code>null</code>.
+     * @param isErrorStream <code>true</code> if this is the error string,
+     *                      otherwise a normal output stream. This is
+     *                      passed to the project so it knows
+     *                      which stream it is receiving.
+     */
+    public DemuxOutputStream(Project project, boolean isErrorStream) {
+        this.project = project;
+        this.isErrorStream = isErrorStream;
+    }
+
+    /**
+     * Returns the buffer associated with the current thread.
+     *
+     * @return a BufferInfo for the current thread to write data to
+     */
+    private BufferInfo getBufferInfo() {
+        Thread current = Thread.currentThread();
+        BufferInfo bufferInfo = (BufferInfo) buffers.get(current);
+        if (bufferInfo == null) {
+            bufferInfo = new BufferInfo();
+            bufferInfo.buffer = new ByteArrayOutputStream(INTIAL_SIZE);
+            bufferInfo.crSeen = false;
+            buffers.put(current, bufferInfo);
+        }
+        return bufferInfo;
+    }
+
+    /**
+     * Resets the buffer for the current thread.
+     */
+    private void resetBufferInfo() {
+        Thread current = Thread.currentThread();
+        BufferInfo bufferInfo = (BufferInfo) buffers.get(current);
+        try {
+            bufferInfo.buffer.close();
+        } catch (IOException e) {
+            // Shouldn't happen
+        }
+        bufferInfo.buffer = new ByteArrayOutputStream();
+        bufferInfo.crSeen = false;
+    }
+
+    /**
+     * Removes the buffer for the current thread.
+     */
+    private void removeBuffer() {
+        Thread current = Thread.currentThread();
+        buffers.remove (current);
+    }
+
+    /**
+     * Writes the data to the buffer and flushes the buffer if a line
+     * separator is detected or if the buffer has reached its maximum size.
+     *
+     * @param cc data to log (byte).
+     * @exception IOException if the data cannot be written to the stream
+     */
+    public void write(int cc) throws IOException {
+        final byte c = (byte) cc;
+
+        BufferInfo bufferInfo = getBufferInfo();
+
+        if (c == '\n') {
+            // LF is always end of line (i.e. CRLF or single LF)
+            bufferInfo.buffer.write(cc);
+            processBuffer(bufferInfo.buffer);
+        } else {
+            if (bufferInfo.crSeen) {
+                // CR without LF - send buffer then add char
+                processBuffer(bufferInfo.buffer);
+            }
+            // add into buffer
+            bufferInfo.buffer.write(cc);
+        }
+        bufferInfo.crSeen = (c == '\r');
+        if (!bufferInfo.crSeen && bufferInfo.buffer.size() > MAX_SIZE) {
+            processBuffer(bufferInfo.buffer);
+        }
+    }
+
+    /**
+     * Converts the buffer to a string and sends it to the project.
+     *
+     * @param buffer the ByteArrayOutputStream used to collect the output
+     * until a line separator is seen.
+     *
+     * @see Project#demuxOutput(String,boolean)
+     */
+    protected void processBuffer(ByteArrayOutputStream buffer) {
+        String output = buffer.toString();
+        project.demuxOutput(output, isErrorStream);
+        resetBufferInfo();
+    }
+
+    /**
+     * Converts the buffer to a string and sends it to the project.
+     *
+     * @param buffer the ByteArrayOutputStream used to collect the output
+     * until a line separator is seen.
+     *
+     * @see Project#demuxOutput(String,boolean)
+     */
+    protected void processFlush(ByteArrayOutputStream buffer) {
+        String output = buffer.toString();
+        project.demuxFlush(output, isErrorStream);
+        resetBufferInfo();
+    }
+
+    /**
+     * Equivalent to flushing the stream.
+     *
+     * @exception IOException if there is a problem closing the stream.
+     *
+     * @see #flush
+     */
+    public void close() throws IOException {
+        flush();
+        removeBuffer();
+    }
+
+    /**
+     * Writes all remaining data in the buffer associated
+     * with the current thread to the project.
+     *
+     * @exception IOException if there is a problem flushing the stream.
+     */
+    public void flush() throws IOException {
+        BufferInfo bufferInfo = getBufferInfo();
+        if (bufferInfo.buffer.size() > 0) {
+            processFlush(bufferInfo.buffer);
+        }
+    }
+
+    /**
+     * Write a block of characters to the output stream
+     *
+     * @param b the array containing the data
+     * @param off the offset into the array where data starts
+     * @param len the length of block
+     *
+     * @throws IOException if the data cannot be written into the stream.
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // find the line breaks and pass other chars through in blocks
+        int offset = off;
+        int blockStartOffset = offset;
+        int remaining = len;
+        BufferInfo bufferInfo = getBufferInfo();
+        while (remaining > 0) {
+            while (remaining > 0 && b[offset] != LF && b[offset] != CR) {
+                offset++;
+                remaining--;
+            }
+            // either end of buffer or a line separator char
+            int blockLength = offset - blockStartOffset;
+            if (blockLength > 0) {
+                bufferInfo.buffer.write(b, blockStartOffset, blockLength);
+            }
+            while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) {
+                write(b[offset]);
+                offset++;
+                remaining--;
+            }
+            blockStartOffset = offset;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/Diagnostics.java b/trunk/src/main/org/apache/tools/ant/Diagnostics.java
new file mode 100644
index 0000000..4309731
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Diagnostics.java
@@ -0,0 +1,637 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.ant.util.ProxySetup;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.launch.Launcher;
+import org.xml.sax.XMLReader;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.SAXParser;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.PrintStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * A little diagnostic helper that output some information that may help
+ * in support. It should quickly give correct information about the
+ * jar existing in ant.home/lib and the jar versions...
+ *
+ * @since Ant 1.5
+ */
+public final class Diagnostics {
+
+    /** the version number for java 1.5 returned from JavaEnvUtils */
+    private static final int JAVA_1_5_NUMBER = 15;
+
+    /**
+     * value for which a difference between clock and temp file time triggers
+     * a warning.
+     * {@value}
+     */
+    private static final int BIG_DRIFT_LIMIT = 10000;
+
+    /**
+     * How big a test file to write.
+     * {@value}
+     */
+    private static final int TEST_FILE_SIZE = 32;
+    private static final int KILOBYTE = 1024;
+    private static final int SECONDS_PER_MILLISECOND = 1000;
+    private static final int SECONDS_PER_MINUTE = 60;
+    private static final int MINUTES_PER_HOUR = 60;
+    private static final String TEST_CLASS = "org.apache.tools.ant.taskdefs.optional.Test";
+
+    /**
+     * The error text when a security manager blocks access to a property.
+     * {@value}
+     */
+    protected static final String ERROR_PROPERTY_ACCESS_BLOCKED
+            = "Access to this property blocked by a security manager";
+
+    /** utility class */
+    private Diagnostics() {
+        // hidden constructor
+    }
+
+    /**
+     * Check if optional tasks are available. Not that it does not check
+     * for implementation version. Use <tt>validateVersion()</tt> for this.
+     * @return <tt>true</tt> if optional tasks are available.
+     */
+    public static boolean isOptionalAvailable() {
+        try {
+            Class.forName(TEST_CLASS);
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Check if core and optional implementation version do match.
+     * @throws BuildException if the implementation version of optional tasks
+     * does not match the core implementation version.
+     */
+    public static void validateVersion() throws BuildException {
+        try {
+            Class optional = Class.forName(TEST_CLASS);
+            String coreVersion = getImplementationVersion(Main.class);
+            String optionalVersion = getImplementationVersion(optional);
+
+            if (coreVersion != null && !coreVersion.equals(optionalVersion)) {
+                throw new BuildException("Invalid implementation version "
+                        + "between Ant core and Ant optional tasks.\n" + " core    : "
+                        + coreVersion + "\n" + " optional: " + optionalVersion);
+            }
+        } catch (ClassNotFoundException e) {
+            // ignore
+            ignoreThrowable(e);
+        }
+    }
+
+    /**
+     * return the list of jar files existing in ANT_HOME/lib
+     * and that must have been picked up by Ant script.
+     * @return the list of jar files existing in ant.home/lib or
+     * <tt>null</tt> if an error occurs.
+     */
+    public static File[] listLibraries() {
+        String home = System.getProperty(MagicNames.ANT_HOME);
+        if (home == null) {
+            return null;
+        }
+        File libDir = new File(home, "lib");
+        return listJarFiles(libDir);
+
+    }
+
+    /**
+     * get a list of all JAR files in a directory
+     * @param libDir directory
+     * @return array of files (or null for no such directory)
+     */
+    private static File[] listJarFiles(File libDir) {
+        FilenameFilter filter = new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+                return name.endsWith(".jar");
+            }
+        };
+        File[] files  = libDir.listFiles(filter);
+        return files;
+    }
+
+    /**
+     * main entry point for command line
+     * @param args command line arguments.
+     */
+    public static void main(String[] args) {
+        doReport(System.out);
+    }
+
+    /**
+     * Helper method to get the implementation version.
+     * @param clazz the class to get the information from.
+     * @return null if there is no package or implementation version.
+     * '?.?' for JDK 1.0 or 1.1.
+     */
+    private static String getImplementationVersion(Class clazz) {
+        return clazz.getPackage().getImplementationVersion();
+    }
+
+    /**
+     * what parser are we using.
+     * @return the classname of the parser
+     */
+    private static String getXmlParserName() {
+        SAXParser saxParser = getSAXParser();
+        if (saxParser == null) {
+            return "Could not create an XML Parser";
+        }
+        // check to what is in the classname
+        String saxParserName = saxParser.getClass().getName();
+        return saxParserName;
+    }
+
+    /**
+     * Create a JAXP SAXParser
+     * @return parser or null for trouble
+     */
+    private static SAXParser getSAXParser() {
+        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+        if (saxParserFactory == null) {
+            return null;
+        }
+        SAXParser saxParser = null;
+        try {
+            saxParser = saxParserFactory.newSAXParser();
+        } catch (Exception e) {
+            // ignore
+            ignoreThrowable(e);
+        }
+        return saxParser;
+    }
+
+    /**
+     * get the location of the parser
+     * @return path or null for trouble in tracking it down
+     */
+
+    private static String getXMLParserLocation() {
+        SAXParser saxParser = getSAXParser();
+        if (saxParser == null) {
+            return null;
+        }
+        String location = getClassLocation(saxParser.getClass());
+        return location;
+    }
+
+    private static String getNamespaceParserName() {
+        try {
+            XMLReader reader = JAXPUtils.getNamespaceXMLReader();
+            return reader.getClass().getName();
+        } catch (BuildException e) {
+            //ignore
+            ignoreThrowable(e);
+            return null;
+        }
+    }
+
+    private static String getNamespaceParserLocation() {
+        try {
+            XMLReader reader = JAXPUtils.getNamespaceXMLReader();
+            return getClassLocation(reader.getClass());
+        } catch (BuildException e) {
+            //ignore
+            ignoreThrowable(e);
+            return null;
+        }
+    }
+
+    /**
+     * ignore exceptions. This is to allow future
+     * implementations to log at a verbose level
+     * @param thrown
+     */
+    private static void ignoreThrowable(Throwable thrown) {
+    }
+
+    /**
+     * get the location of a class. Stolen from axis/webapps/happyaxis.jsp
+     * @param clazz
+     * @return the jar file or path where a class was found, or null
+     */
+
+    private static String getClassLocation(Class clazz) {
+        File f = LoaderUtils.getClassSource(clazz);
+        return f == null ? null : f.getAbsolutePath();
+    }
+
+
+    /**
+     * Print a report to the given stream.
+     * @param out the stream to print the report to.
+     */
+    public static void doReport(PrintStream out) {
+        out.println("------- Ant diagnostics report -------");
+        out.println(Main.getAntVersion());
+        header(out, "Implementation Version");
+
+        out.println("core tasks     : " + getImplementationVersion(Main.class));
+
+        Class optional = null;
+        try {
+            optional = Class.forName(TEST_CLASS);
+            out.println("optional tasks : " + getImplementationVersion(optional));
+        } catch (ClassNotFoundException e) {
+            ignoreThrowable(e);
+            out.println("optional tasks : not available");
+        }
+
+        header(out, "ANT PROPERTIES");
+        doReportAntProperties(out);
+
+        header(out, "ANT_HOME/lib jar listing");
+        doReportAntHomeLibraries(out);
+
+        header(out, "USER_HOME/.ant/lib jar listing");
+        doReportUserHomeLibraries(out);
+
+        header(out, "Tasks availability");
+        doReportTasksAvailability(out);
+
+        header(out, "org.apache.env.Which diagnostics");
+        doReportWhich(out);
+
+        header(out, "XML Parser information");
+        doReportParserInfo(out);
+
+        header(out, "System properties");
+        doReportSystemProperties(out);
+
+        header(out, "Temp dir");
+        doReportTempDir(out);
+
+        header(out, "Locale information");
+        doReportLocale(out);
+
+        header(out, "Proxy information");
+        doReportProxy(out);
+
+        out.println();
+    }
+
+    private static void header(PrintStream out, String section) {
+        out.println();
+        out.println("-------------------------------------------");
+        out.print(" ");
+        out.println(section);
+        out.println("-------------------------------------------");
+    }
+
+    /**
+     * Report a listing of system properties existing in the current vm.
+     * @param out the stream to print the properties to.
+     */
+    private static void doReportSystemProperties(PrintStream out) {
+        Properties sysprops = null;
+        try {
+            sysprops = System.getProperties();
+        } catch (SecurityException  e) {
+            ignoreThrowable(e);
+            out.println("Access to System.getProperties() blocked " + "by a security manager");
+        }
+        for (Enumeration keys = sysprops.propertyNames();
+            keys.hasMoreElements();) {
+            String key = (String) keys.nextElement();
+            String value = getProperty(key);
+            out.println(key + " : " + value);
+        }
+    }
+
+    /**
+     * Get the value of a system property. If a security manager
+     * blocks access to a property it fills the result in with an error
+     * @param key
+     * @return the system property's value or error text
+     * @see #ERROR_PROPERTY_ACCESS_BLOCKED
+     */
+    private static String getProperty(String key) {
+        String value;
+        try {
+            value = System.getProperty(key);
+        } catch (SecurityException e) {
+            value = ERROR_PROPERTY_ACCESS_BLOCKED;
+        }
+        return value;
+    }
+
+    /**
+     * Report the content of ANT_HOME/lib directory
+     * @param out the stream to print the content to
+     */
+    private static void doReportAntProperties(PrintStream out) {
+        Project p = new Project();
+        p.initProperties();
+        out.println(MagicNames.ANT_VERSION + ": " + p.getProperty(MagicNames.ANT_VERSION));
+        out.println(MagicNames.ANT_JAVA_VERSION + ": "
+                + p.getProperty(MagicNames.ANT_JAVA_VERSION));
+        out.println(MagicNames.ANT_LIB + ": " + p.getProperty(MagicNames.ANT_LIB));
+        out.println(MagicNames.ANT_HOME + ": " + p.getProperty(MagicNames.ANT_HOME));
+    }
+
+    /**
+     * Report the content of ANT_HOME/lib directory
+     * @param out the stream to print the content to
+     */
+    private static void doReportAntHomeLibraries(PrintStream out) {
+        out.println(MagicNames.ANT_HOME + ": " + System.getProperty(MagicNames.ANT_HOME));
+        File[] libs = listLibraries();
+        printLibraries(libs, out);
+    }
+
+    /**
+     * Report the content of ~/.ant/lib directory
+     *
+     * @param out the stream to print the content to
+     */
+    private static void doReportUserHomeLibraries(PrintStream out) {
+        String home = System.getProperty(Launcher.USER_HOMEDIR);
+        out.println("user.home: " + home);
+        File libDir = new File(home, Launcher.USER_LIBDIR);
+        File[] libs = listJarFiles(libDir);
+        printLibraries(libs, out);
+    }
+
+    /**
+     * list the libraries
+     * @param libs array of libraries (can be null)
+     * @param out output stream
+     */
+    private static void printLibraries(File[] libs, PrintStream out) {
+        if (libs == null) {
+            out.println("No such directory.");
+            return;
+        }
+        for (int i = 0; i < libs.length; i++) {
+            out.println(libs[i].getName() + " (" + libs[i].length() + " bytes)");
+        }
+    }
+
+
+    /**
+     * Call org.apache.env.Which if available
+     * @param out the stream to print the content to.
+     */
+    private static void doReportWhich(PrintStream out) {
+        Throwable error = null;
+        try {
+            Class which = Class.forName("org.apache.env.Which");
+            Method method = which.getMethod(
+                "main", new Class[] {String[].class});
+            method.invoke(null, new Object[]{new String[]{}});
+        } catch (ClassNotFoundException e) {
+            out.println("Not available.");
+            out.println("Download it at http://xml.apache.org/commons/");
+        } catch (InvocationTargetException e) {
+            error = e.getTargetException() == null ? e : e.getTargetException();
+        } catch (Throwable e) {
+            error = e;
+        }
+        // report error if something weird happens...this is diagnostic.
+        if (error != null) {
+            out.println("Error while running org.apache.env.Which");
+            error.printStackTrace();
+        }
+    }
+
+    /**
+     * Create a report about non-available tasks that are defined in the
+     * mapping but could not be found via lookup. It might generally happen
+     * because Ant requires multiple libraries to compile and one of them
+     * was missing when compiling Ant.
+     * @param out the stream to print the tasks report to
+     * <tt>null</tt> for a missing stream (ie mapping).
+     */
+    private static void doReportTasksAvailability(PrintStream out) {
+        InputStream is = Main.class.getResourceAsStream(
+                MagicNames.TASKDEF_PROPERTIES_RESOURCE);
+        if (is == null) {
+            out.println("None available");
+        } else {
+            Properties props = new Properties();
+            try {
+                props.load(is);
+                for (Enumeration keys = props.keys(); keys.hasMoreElements();) {
+                    String key = (String) keys.nextElement();
+                    String classname = props.getProperty(key);
+                    try {
+                        Class.forName(classname);
+                        props.remove(key);
+                    } catch (ClassNotFoundException e) {
+                        out.println(key + " : Not Available "
+                                + "(the implementation class is not present)");
+                    } catch (NoClassDefFoundError e) {
+                        String pkg = e.getMessage().replace('/', '.');
+                        out.println(key + " : Missing dependency " + pkg);
+                    } catch (LinkageError e) {
+                        out.println(key + " : Initialization error");
+                    }
+                }
+                if (props.size() == 0) {
+                    out.println("All defined tasks are available");
+                } else {
+                    out.println("A task being missing/unavailable should only "
+                            + "matter if you are trying to use it");
+                }
+            } catch (IOException e) {
+                out.println(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * tell the user about the XML parser
+     * @param out
+     */
+    private static void doReportParserInfo(PrintStream out) {
+        String parserName = getXmlParserName();
+        String parserLocation = getXMLParserLocation();
+        printParserInfo(out, "XML Parser", parserName, parserLocation);
+        printParserInfo(out, "Namespace-aware parser", getNamespaceParserName(),
+                getNamespaceParserLocation());
+    }
+
+    private static void printParserInfo(PrintStream out, String parserType, String parserName,
+            String parserLocation) {
+        if (parserName == null) {
+            parserName = "unknown";
+        }
+        if (parserLocation == null) {
+            parserLocation = "unknown";
+        }
+        out.println(parserType + " : " + parserName);
+        out.println(parserType + " Location: " + parserLocation);
+    }
+
+    /**
+     * try and create a temp file in our temp dir; this
+     * checks that it has space and access.
+     * We also do some clock reporting.
+     * @param out
+     */
+    private static void doReportTempDir(PrintStream out) {
+        String tempdir = System.getProperty("java.io.tmpdir");
+        if (tempdir == null) {
+            out.println("Warning: java.io.tmpdir is undefined");
+            return;
+        }
+        out.println("Temp dir is " + tempdir);
+        File tempDirectory = new File(tempdir);
+        if (!tempDirectory.exists()) {
+            out.println("Warning, java.io.tmpdir directory does not exist: " + tempdir);
+            return;
+        }
+        //create the file
+        long now = System.currentTimeMillis();
+        File tempFile = null;
+        FileOutputStream fileout = null;
+        try {
+            tempFile = File.createTempFile("diag", "txt", tempDirectory);
+            //do some writing to it
+            fileout = new FileOutputStream(tempFile);
+            byte[] buffer = new byte[KILOBYTE];
+            for (int i = 0; i < TEST_FILE_SIZE; i++) {
+                fileout.write(buffer);
+            }
+            fileout.close();
+            fileout = null;
+            long filetime = tempFile.lastModified();
+            tempFile.delete();
+            out.println("Temp dir is writeable");
+            long drift = filetime - now;
+            out.println("Temp dir alignment with system clock is " + drift + " ms");
+            if (Math.abs(drift) > BIG_DRIFT_LIMIT) {
+                out.println("Warning: big clock drift -maybe a network filesystem");
+            }
+        } catch (IOException e) {
+            ignoreThrowable(e);
+            out.println("Failed to create a temporary file in the temp dir " + tempdir);
+            out.println("File  " + tempFile + " could not be created/written to");
+        } finally {
+            FileUtils.close(fileout);
+            if (tempFile != null && tempFile.exists()) {
+                tempFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Report locale information
+     * @param out stream to print to
+     */
+    private static void doReportLocale(PrintStream out) {
+        //calendar stuff.
+        Calendar cal = Calendar.getInstance();
+        TimeZone tz = cal.getTimeZone();
+        out.println("Timezone "
+                + tz.getDisplayName()
+                + " offset="
+                + tz.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal
+                        .get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal
+                        .get(Calendar.DAY_OF_WEEK), ((cal.get(Calendar.HOUR_OF_DAY)
+                        * MINUTES_PER_HOUR + cal.get(Calendar.MINUTE))
+                        * SECONDS_PER_MINUTE + cal.get(Calendar.SECOND))
+                        * SECONDS_PER_MILLISECOND + cal.get(Calendar.MILLISECOND)));
+    }
+
+    /**
+     * print a property name="value" pair if the property is set;
+     * print nothing if it is null
+     * @param out stream to print on
+     * @param key property name
+     */
+    private static void printProperty(PrintStream out, String key) {
+        String value = getProperty(key);
+        if (value != null) {
+            out.print(key);
+            out.print(" = ");
+            out.print('"');
+            out.print(value);
+            out.println('"');
+        }
+    }
+
+    /**
+     * Report proxy information
+     *
+     * @param out stream to print to
+     * @since Ant1.7
+     */
+    private static void doReportProxy(PrintStream out) {
+        printProperty(out, ProxySetup.HTTP_PROXY_HOST);
+        printProperty(out, ProxySetup.HTTP_PROXY_PORT);
+        printProperty(out, ProxySetup.HTTP_PROXY_USERNAME);
+        printProperty(out, ProxySetup.HTTP_PROXY_PASSWORD);
+        printProperty(out, ProxySetup.HTTP_NON_PROXY_HOSTS);
+        printProperty(out, ProxySetup.HTTPS_PROXY_HOST);
+        printProperty(out, ProxySetup.HTTPS_PROXY_PORT);
+        printProperty(out, ProxySetup.HTTPS_NON_PROXY_HOSTS);
+        printProperty(out, ProxySetup.FTP_PROXY_HOST);
+        printProperty(out, ProxySetup.FTP_PROXY_PORT);
+        printProperty(out, ProxySetup.FTP_NON_PROXY_HOSTS);
+        printProperty(out, ProxySetup.SOCKS_PROXY_HOST);
+        printProperty(out, ProxySetup.SOCKS_PROXY_PORT);
+        printProperty(out, ProxySetup.SOCKS_PROXY_USERNAME);
+        printProperty(out, ProxySetup.SOCKS_PROXY_PASSWORD);
+
+        if (JavaEnvUtils.getJavaVersionNumber() < JAVA_1_5_NUMBER) {
+            return;
+        }
+        printProperty(out, ProxySetup.USE_SYSTEM_PROXIES);
+        final String proxyDiagClassname = "org.apache.tools.ant.util.java15.ProxyDiagnostics";
+        try {
+            Class proxyDiagClass = Class.forName(proxyDiagClassname);
+            Object instance = proxyDiagClass.newInstance();
+            out.println("Java1.5+ proxy settings:");
+            out.println(instance.toString());
+        } catch (ClassNotFoundException e) {
+            //not included, do nothing
+        } catch (IllegalAccessException e) {
+            //not included, do nothing
+        } catch (InstantiationException e) {
+            //not included, do nothing
+        } catch (NoClassDefFoundError e) {
+            // not included, to nothing
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java b/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java
new file mode 100644
index 0000000..98f0c67
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DirectoryScanner.java
@@ -0,0 +1,1713 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.SelectorScanner;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Class for scanning a directory for files/directories which match certain
+ * criteria.
+ * <p>
+ * These criteria consist of selectors and patterns which have been specified.
+ * With the selectors you can select which files you want to have included.
+ * Files which are not selected are excluded. With patterns you can include
+ * or exclude files based on their filename.
+ * <p>
+ * The idea is simple. A given directory is recursively scanned for all files
+ * and directories. Each file/directory is matched against a set of selectors,
+ * including special support for matching against filenames with include and
+ * and exclude patterns. Only files/directories which match at least one
+ * pattern of the include pattern list or other file selector, and don't match
+ * any pattern of the exclude pattern list or fail to match against a required
+ * selector will be placed in the list of files/directories found.
+ * <p>
+ * When no list of include patterns is supplied, "**" will be used, which
+ * means that everything will be matched. When no list of exclude patterns is
+ * supplied, an empty list is used, such that nothing will be excluded. When
+ * no selectors are supplied, none are applied.
+ * <p>
+ * The filename pattern matching is done as follows:
+ * The name to be matched is split up in path segments. A path segment is the
+ * name of a directory or file, which is bounded by
+ * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
+ * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
+ * "def","ghi" and "xyz.java".
+ * The same is done for the pattern against which should be matched.
+ * <p>
+ * The segments of the name and the pattern are then matched against each
+ * other. When '**' is used for a path segment in the pattern, it matches
+ * zero or more path segments of the name.
+ * <p>
+ * There is a special case regarding the use of <code>File.separator</code>s
+ * at the beginning of the pattern and the string to match:<br>
+ * When a pattern starts with a <code>File.separator</code>, the string
+ * to match must also start with a <code>File.separator</code>.
+ * When a pattern does not start with a <code>File.separator</code>, the
+ * string to match may not start with a <code>File.separator</code>.
+ * When one of these rules is not obeyed, the string will not
+ * match.
+ * <p>
+ * When a name path segment is matched against a pattern path segment, the
+ * following special characters can be used:<br>
+ * '*' matches zero or more characters<br>
+ * '?' matches one character.
+ * <p>
+ * Examples:
+ * <p>
+ * "**\*.class" matches all .class files/dirs in a directory tree.
+ * <p>
+ * "test\a??.java" matches all files/dirs which start with an 'a', then two
+ * more characters and then ".java", in a directory called test.
+ * <p>
+ * "**" matches everything in a directory tree.
+ * <p>
+ * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
+ * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
+ * <p>
+ * Case sensitivity may be turned off if necessary. By default, it is
+ * turned on.
+ * <p>
+ * Example of usage:
+ * <pre>
+ *   String[] includes = {"**\\*.class"};
+ *   String[] excludes = {"modules\\*\\**"};
+ *   ds.setIncludes(includes);
+ *   ds.setExcludes(excludes);
+ *   ds.setBasedir(new File("test"));
+ *   ds.setCaseSensitive(true);
+ *   ds.scan();
+ *
+ *   System.out.println("FILES:");
+ *   String[] files = ds.getIncludedFiles();
+ *   for (int i = 0; i < files.length; i++) {
+ *     System.out.println(files[i]);
+ *   }
+ * </pre>
+ * This will scan a directory called test for .class files, but excludes all
+ * files in all proper subdirectories of a directory called "modules"
+ *
+ */
+public class DirectoryScanner
+       implements FileScanner, SelectorScanner, ResourceFactory {
+
+    /** Is OpenVMS the operating system we're running on? */
+    private static final boolean ON_VMS = Os.isFamily("openvms");
+
+    /**
+     * Patterns which should be excluded by default.
+     *
+     * <p>Note that you can now add patterns to the list of default
+     * excludes.  Added patterns will not become part of this array
+     * that has only been kept around for backwards compatibility
+     * reasons.</p>
+     *
+     * @deprecated since 1.6.x.
+     *             Use the {@link #getDefaultExcludes getDefaultExcludes}
+     *             method instead.
+     */
+    protected static final String[] DEFAULTEXCLUDES = {
+        // Miscellaneous typical temporary files
+        "**/*~",
+        "**/#*#",
+        "**/.#*",
+        "**/%*%",
+        "**/._*",
+
+        // CVS
+        "**/CVS",
+        "**/CVS/**",
+        "**/.cvsignore",
+
+        // SCCS
+        "**/SCCS",
+        "**/SCCS/**",
+
+        // Visual SourceSafe
+        "**/vssver.scc",
+
+        // Subversion
+        "**/.svn",
+        "**/.svn/**",
+
+        // Mac
+        "**/.DS_Store"
+    };
+
+    /** Helper. */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** iterations for case-sensitive scanning. */
+    private static final boolean[] CS_SCAN_ONLY = new boolean[] {true};
+
+    /** iterations for non-case-sensitive scanning. */
+    private static final boolean[] CS_THEN_NON_CS = new boolean[] {true, false};
+
+    /**
+     * Patterns which should be excluded by default.
+     *
+     * @see #addDefaultExcludes()
+     */
+    private static Vector defaultExcludes = new Vector();
+    static {
+        resetDefaultExcludes();
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** The base directory to be scanned. */
+    protected File basedir;
+
+    /** The patterns for the files to be included. */
+    protected String[] includes;
+
+    /** The patterns for the files to be excluded. */
+    protected String[] excludes;
+
+    /** Selectors that will filter which files are in our candidate list. */
+    protected FileSelector[] selectors = null;
+
+    /**
+     * The files which matched at least one include and no excludes
+     * and were selected.
+     */
+    protected Vector filesIncluded;
+
+    /** The files which did not match any includes or selectors. */
+    protected Vector filesNotIncluded;
+
+    /**
+     * The files which matched at least one include and at least
+     * one exclude.
+     */
+    protected Vector filesExcluded;
+
+    /**
+     * The directories which matched at least one include and no excludes
+     * and were selected.
+     */
+    protected Vector dirsIncluded;
+
+    /** The directories which were found and did not match any includes. */
+    protected Vector dirsNotIncluded;
+
+    /**
+     * The directories which matched at least one include and at least one
+     * exclude.
+     */
+    protected Vector dirsExcluded;
+
+    /**
+     * The files which matched at least one include and no excludes and
+     * which a selector discarded.
+     */
+    protected Vector filesDeselected;
+
+    /**
+     * The directories which matched at least one include and no excludes
+     * but which a selector discarded.
+     */
+    protected Vector dirsDeselected;
+
+    /** Whether or not our results were built by a slow scan. */
+    protected boolean haveSlowResults = false;
+
+    /**
+     * Whether or not the file system should be treated as a case sensitive
+     * one.
+     */
+    protected boolean isCaseSensitive = true;
+
+    /**
+     * Whether a missing base directory is an error.
+     * @since Ant 1.7.1
+     */
+    protected boolean errorOnMissingDir = true;
+
+    /**
+     * Whether or not symbolic links should be followed.
+     *
+     * @since Ant 1.5
+     */
+    private boolean followSymlinks = true;
+
+    /** Whether or not everything tested so far has been included. */
+    protected boolean everythingIncluded = true;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Temporary table to speed up the various scanning methods.
+     *
+     * @since Ant 1.6
+     */
+    private Map fileListMap = new HashMap();
+
+    /**
+     * List of all scanned directories.
+     *
+     * @since Ant 1.6
+     */
+    private Set scannedDirs = new HashSet();
+
+    /**
+     * Set of all include patterns that are full file names and don't
+     * contain any wildcards.
+     *
+     * <p>If this instance is not case sensitive, the file names get
+     * turned to lower case.</p>
+     *
+     * <p>Gets lazily initialized on the first invocation of
+     * isIncluded or isExcluded and cleared at the end of the scan
+     * method (cleared in clearCaches, actually).</p>
+     *
+     * @since Ant 1.6.3
+     */
+    private Set includeNonPatterns = new HashSet();
+
+    /**
+     * Set of all include patterns that are full file names and don't
+     * contain any wildcards.
+     *
+     * <p>If this instance is not case sensitive, the file names get
+     * turned to lower case.</p>
+     *
+     * <p>Gets lazily initialized on the first invocation of
+     * isIncluded or isExcluded and cleared at the end of the scan
+     * method (cleared in clearCaches, actually).</p>
+     *
+     * @since Ant 1.6.3
+     */
+    private Set excludeNonPatterns = new HashSet();
+
+    /**
+     * Array of all include patterns that contain wildcards.
+     *
+     * <p>Gets lazily initialized on the first invocation of
+     * isIncluded or isExcluded and cleared at the end of the scan
+     * method (cleared in clearCaches, actually).</p>
+     *
+     * @since Ant 1.6.3
+     */
+    private String[] includePatterns;
+
+    /**
+     * Array of all exclude patterns that contain wildcards.
+     *
+     * <p>Gets lazily initialized on the first invocation of
+     * isIncluded or isExcluded and cleared at the end of the scan
+     * method (cleared in clearCaches, actually).</p>
+     *
+     * @since Ant 1.6.3
+     */
+    private String[] excludePatterns;
+
+    /**
+     * Have the non-pattern sets and pattern arrays for in- and
+     * excludes been initialized?
+     *
+     * @since Ant 1.6.3
+     */
+    private boolean areNonPatternSetsReady = false;
+
+    /**
+     * Scanning flag.
+     *
+     * @since Ant 1.6.3
+     */
+    private boolean scanning = false;
+
+    /**
+     * Scanning lock.
+     *
+     * @since Ant 1.6.3
+     */
+    private Object scanLock = new Object();
+
+    /**
+     * Slow scanning flag.
+     *
+     * @since Ant 1.6.3
+     */
+    private boolean slowScanning = false;
+
+    /**
+     * Slow scanning lock.
+     *
+     * @since Ant 1.6.3
+     */
+    private Object slowScanLock = new Object();
+
+    /**
+     * Exception thrown during scan.
+     *
+     * @since Ant 1.6.3
+     */
+    private IllegalStateException illegal = null;
+
+    /**
+     * Sole constructor.
+     */
+    public DirectoryScanner() {
+    }
+
+    /**
+     * Test whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     * <p>
+     * This is not a general purpose test and should only be used if you
+     * can live with false positives. For example, <code>pattern=**\a</code>
+     * and <code>str=b</code> will yield <code>true</code>.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     *
+     * @return whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     */
+    protected static boolean matchPatternStart(String pattern, String str) {
+        return SelectorUtils.matchPatternStart(pattern, str);
+    }
+
+    /**
+     * Test whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     * <p>
+     * This is not a general purpose test and should only be used if you
+     * can live with false positives. For example, <code>pattern=**\a</code>
+     * and <code>str=b</code> will yield <code>true</code>.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     * @return whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     */
+    protected static boolean matchPatternStart(String pattern, String str,
+                                               boolean isCaseSensitive) {
+        return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
+    }
+
+    /**
+     * Test whether or not a given path matches a given pattern.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     *
+     * @return <code>true</code> if the pattern matches against the string,
+     *         or <code>false</code> otherwise.
+     */
+    protected static boolean matchPath(String pattern, String str) {
+        return SelectorUtils.matchPath(pattern, str);
+    }
+
+    /**
+     * Test whether or not a given path matches a given pattern.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     * @return <code>true</code> if the pattern matches against the string,
+     *         or <code>false</code> otherwise.
+     */
+    protected static boolean matchPath(String pattern, String str,
+                                       boolean isCaseSensitive) {
+        return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
+    }
+
+    /**
+     * Test whether or not a string matches against a pattern.
+     * The pattern may contain two special characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param pattern The pattern to match against.
+     *                Must not be <code>null</code>.
+     * @param str     The string which must be matched against the pattern.
+     *                Must not be <code>null</code>.
+     *
+     * @return <code>true</code> if the string matches against the pattern,
+     *         or <code>false</code> otherwise.
+     */
+    public static boolean match(String pattern, String str) {
+        return SelectorUtils.match(pattern, str);
+    }
+
+    /**
+     * Test whether or not a string matches against a pattern.
+     * The pattern may contain two special characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param pattern The pattern to match against.
+     *                Must not be <code>null</code>.
+     * @param str     The string which must be matched against the pattern.
+     *                Must not be <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     *
+     * @return <code>true</code> if the string matches against the pattern,
+     *         or <code>false</code> otherwise.
+     */
+    protected static boolean match(String pattern, String str,
+                                   boolean isCaseSensitive) {
+        return SelectorUtils.match(pattern, str, isCaseSensitive);
+    }
+
+
+    /**
+     * Get the list of patterns that should be excluded by default.
+     *
+     * @return An array of <code>String</code> based on the current
+     *         contents of the <code>defaultExcludes</code>
+     *         <code>Vector</code>.
+     *
+     * @since Ant 1.6
+     */
+    public static String[] getDefaultExcludes() {
+        return (String[]) defaultExcludes.toArray(new String[defaultExcludes
+                                                             .size()]);
+    }
+
+    /**
+     * Add a pattern to the default excludes unless it is already a
+     * default exclude.
+     *
+     * @param s   A string to add as an exclude pattern.
+     * @return    <code>true</code> if the string was added;
+     *            <code>false</code> if it already existed.
+     *
+     * @since Ant 1.6
+     */
+    public static boolean addDefaultExclude(String s) {
+        if (defaultExcludes.indexOf(s) == -1) {
+            defaultExcludes.add(s);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Remove a string if it is a default exclude.
+     *
+     * @param s   The string to attempt to remove.
+     * @return    <code>true</code> if <code>s</code> was a default
+     *            exclude (and thus was removed);
+     *            <code>false</code> if <code>s</code> was not
+     *            in the default excludes list to begin with.
+     *
+     * @since Ant 1.6
+     */
+    public static boolean removeDefaultExclude(String s) {
+        return defaultExcludes.remove(s);
+    }
+
+    /**
+     * Go back to the hardwired default exclude patterns.
+     *
+     * @since Ant 1.6
+     */
+    public static void resetDefaultExcludes() {
+        defaultExcludes = new Vector();
+        for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
+            defaultExcludes.add(DEFAULTEXCLUDES[i]);
+        }
+    }
+
+    /**
+     * Set the base directory to be scanned. This is the directory which is
+     * scanned recursively. All '/' and '\' characters are replaced by
+     * <code>File.separatorChar</code>, so the separator used need not match
+     * <code>File.separatorChar</code>.
+     *
+     * @param basedir The base directory to scan.
+     */
+    public void setBasedir(String basedir) {
+        setBasedir(basedir == null ? (File) null
+            : new File(basedir.replace('/', File.separatorChar).replace(
+            '\\', File.separatorChar)));
+    }
+
+    /**
+     * Set the base directory to be scanned. This is the directory which is
+     * scanned recursively.
+     *
+     * @param basedir The base directory for scanning.
+     */
+    public synchronized void setBasedir(File basedir) {
+        this.basedir = basedir;
+    }
+
+    /**
+     * Return the base directory to be scanned.
+     * This is the directory which is scanned recursively.
+     *
+     * @return the base directory to be scanned.
+     */
+    public synchronized File getBasedir() {
+        return basedir;
+    }
+
+    /**
+     * Find out whether include exclude patterns are matched in a
+     * case sensitive way.
+     * @return whether or not the scanning is case sensitive.
+     * @since Ant 1.6
+     */
+    public synchronized boolean isCaseSensitive() {
+        return isCaseSensitive;
+    }
+
+    /**
+     * Set whether or not include and exclude patterns are matched
+     * in a case sensitive way.
+     *
+     * @param isCaseSensitive whether or not the file system should be
+     *                        regarded as a case sensitive one.
+     */
+    public synchronized void setCaseSensitive(boolean isCaseSensitive) {
+        this.isCaseSensitive = isCaseSensitive;
+    }
+
+    /**
+     * Sets whether or not a missing base directory is an error
+     *
+     * @param errorOnMissingDir whether or not a missing base directory
+     *                        is an error
+     * @since Ant 1.7.1
+     */
+    public void setErrorOnMissingDir(boolean errorOnMissingDir) {
+        this.errorOnMissingDir = errorOnMissingDir;
+    }
+
+    /**
+     * Get whether or not a DirectoryScanner follows symbolic links.
+     *
+     * @return flag indicating whether symbolic links should be followed.
+     *
+     * @since Ant 1.6
+     */
+    public synchronized boolean isFollowSymlinks() {
+        return followSymlinks;
+    }
+
+    /**
+     * Set whether or not symbolic links should be followed.
+     *
+     * @param followSymlinks whether or not symbolic links should be followed.
+     */
+    public synchronized void setFollowSymlinks(boolean followSymlinks) {
+        this.followSymlinks = followSymlinks;
+    }
+
+    /**
+     * Set the list of include patterns to use. All '/' and '\' characters
+     * are replaced by <code>File.separatorChar</code>, so the separator used
+     * need not match <code>File.separatorChar</code>.
+     * <p>
+     * When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @param includes A list of include patterns.
+     *                 May be <code>null</code>, indicating that all files
+     *                 should be included. If a non-<code>null</code>
+     *                 list is given, all elements must be
+     *                 non-<code>null</code>.
+     */
+    public synchronized void setIncludes(String[] includes) {
+        if (includes == null) {
+            this.includes = null;
+        } else {
+            this.includes = new String[includes.length];
+            for (int i = 0; i < includes.length; i++) {
+                this.includes[i] = normalizePattern(includes[i]);
+            }
+        }
+    }
+
+    /**
+     * Set the list of exclude patterns to use. All '/' and '\' characters
+     * are replaced by <code>File.separatorChar</code>, so the separator used
+     * need not match <code>File.separatorChar</code>.
+     * <p>
+     * When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @param excludes A list of exclude patterns.
+     *                 May be <code>null</code>, indicating that no files
+     *                 should be excluded. If a non-<code>null</code> list is
+     *                 given, all elements must be non-<code>null</code>.
+     */
+    public synchronized void setExcludes(String[] excludes) {
+        if (excludes == null) {
+            this.excludes = null;
+        } else {
+            this.excludes = new String[excludes.length];
+            for (int i = 0; i < excludes.length; i++) {
+                this.excludes[i] = normalizePattern(excludes[i]);
+            }
+        }
+    }
+
+    /**
+     * Add to the list of exclude patterns to use. All '/' and '\'
+     * characters are replaced by <code>File.separatorChar</code>, so
+     * the separator used need not match <code>File.separatorChar</code>.
+     * <p>
+     * When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @param excludes A list of exclude patterns.
+     *                 May be <code>null</code>, in which case the
+     *                 exclude patterns don't get changed at all.
+     *
+     * @since Ant 1.6.3
+     */
+    public synchronized void addExcludes(String[] excludes) {
+        if (excludes != null && excludes.length > 0) {
+            if (this.excludes != null && this.excludes.length > 0) {
+                String[] tmp = new String[excludes.length
+                                          + this.excludes.length];
+                System.arraycopy(this.excludes, 0, tmp, 0,
+                                 this.excludes.length);
+                for (int i = 0; i < excludes.length; i++) {
+                    tmp[this.excludes.length + i] =
+                        normalizePattern(excludes[i]);
+                }
+                this.excludes = tmp;
+            } else {
+                setExcludes(excludes);
+            }
+        }
+    }
+
+    /**
+     * All '/' and '\' characters are replaced by
+     * <code>File.separatorChar</code>, so the separator used need not
+     * match <code>File.separatorChar</code>.
+     *
+     * <p> When a pattern ends with a '/' or '\', "**" is appended.
+     *
+     * @since Ant 1.6.3
+     */
+    private static String normalizePattern(String p) {
+        String pattern = p.replace('/', File.separatorChar)
+            .replace('\\', File.separatorChar);
+        if (pattern.endsWith(File.separator)) {
+            pattern += "**";
+        }
+        return pattern;
+    }
+
+    /**
+     * Set the selectors that will select the filelist.
+     *
+     * @param selectors specifies the selectors to be invoked on a scan.
+     */
+    public synchronized void setSelectors(FileSelector[] selectors) {
+        this.selectors = selectors;
+    }
+
+    /**
+     * Return whether or not the scanner has included all the files or
+     * directories it has come across so far.
+     *
+     * @return <code>true</code> if all files and directories which have
+     *         been found so far have been included.
+     */
+    public synchronized boolean isEverythingIncluded() {
+        return everythingIncluded;
+    }
+
+    /**
+     * Scan for files which match at least one include pattern and don't match
+     * any exclude patterns. If there are selectors then the files must pass
+     * muster there, as well.  Scans under basedir, if set; otherwise the
+     * include patterns without leading wildcards specify the absolute paths of
+     * the files that may be included.
+     *
+     * @exception IllegalStateException if the base directory was set
+     *            incorrectly (i.e. if it doesn't exist or isn't a directory).
+     */
+    public void scan() throws IllegalStateException {
+        synchronized (scanLock) {
+            if (scanning) {
+                while (scanning) {
+                    try {
+                        scanLock.wait();
+                    } catch (InterruptedException e) {
+                        continue;
+                    }
+                }
+                if (illegal != null) {
+                    throw illegal;
+                }
+                return;
+            }
+            scanning = true;
+        }
+        try {
+            synchronized (this) {
+                illegal = null;
+                clearResults();
+
+                // set in/excludes to reasonable defaults if needed:
+                boolean nullIncludes = (includes == null);
+                includes = nullIncludes ? new String[] {"**"} : includes;
+                boolean nullExcludes = (excludes == null);
+                excludes = nullExcludes ? new String[0] : excludes;
+
+                if (basedir == null) {
+                    // if no basedir and no includes, nothing to do:
+                    if (nullIncludes) {
+                        return;
+                    }
+                } else {
+                    if (!basedir.exists()) {
+                        if (errorOnMissingDir) {
+                            illegal = new IllegalStateException(
+                                "basedir " + basedir + " does not exist");
+                        } else {
+                            // Nothing to do - basedir does not exist
+                            return;
+                        }
+                    }
+                    if (!basedir.isDirectory()) {
+                        illegal = new IllegalStateException("basedir " + basedir
+                                                            + " is not a directory");
+                    }
+                    if (illegal != null) {
+                        throw illegal;
+                    }
+                }
+                if (isIncluded("")) {
+                    if (!isExcluded("")) {
+                        if (isSelected("", basedir)) {
+                            dirsIncluded.addElement("");
+                        } else {
+                            dirsDeselected.addElement("");
+                        }
+                    } else {
+                        dirsExcluded.addElement("");
+                    }
+                } else {
+                    dirsNotIncluded.addElement("");
+                }
+                checkIncludePatterns();
+                clearCaches();
+                includes = nullIncludes ? null : includes;
+                excludes = nullExcludes ? null : excludes;
+            }
+        } finally {
+            synchronized (scanLock) {
+                scanning = false;
+                scanLock.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * This routine is actually checking all the include patterns in
+     * order to avoid scanning everything under base dir.
+     * @since Ant 1.6
+     */
+    private void checkIncludePatterns() {
+        Map newroots = new HashMap();
+        // put in the newroots map the include patterns without
+        // wildcard tokens
+        for (int i = 0; i < includes.length; i++) {
+            if (FileUtils.isAbsolutePath(includes[i])) {
+                //skip abs. paths not under basedir, if set:
+                if (basedir != null
+                    && !SelectorUtils.matchPatternStart(includes[i],
+                    basedir.getAbsolutePath(), isCaseSensitive())) {
+                    continue;
+                }
+            } else if (basedir == null) {
+                //skip non-abs. paths if basedir == null:
+                continue;
+            }
+            newroots.put(SelectorUtils.rtrimWildcardTokens(
+                includes[i]), includes[i]);
+        }
+        if (newroots.containsKey("") && basedir != null) {
+            // we are going to scan everything anyway
+            scandir(basedir, "", true);
+        } else {
+            // only scan directories that can include matched files or
+            // directories
+            Iterator it = newroots.entrySet().iterator();
+
+            File canonBase = null;
+            if (basedir != null) {
+                try {
+                    canonBase = basedir.getCanonicalFile();
+                } catch (IOException ex) {
+                    throw new BuildException(ex);
+                }
+            }
+            while (it.hasNext()) {
+                Map.Entry entry = (Map.Entry) it.next();
+                String currentelement = (String) entry.getKey();
+                if (basedir == null && !FileUtils.isAbsolutePath(currentelement)) {
+                    continue;
+                }
+                String originalpattern = (String) entry.getValue();
+                File myfile = new File(basedir, currentelement);
+
+                if (myfile.exists()) {
+                    // may be on a case insensitive file system.  We want
+                    // the results to show what's really on the disk, so
+                    // we need to double check.
+                    try {
+                        String path = (basedir == null)
+                            ? myfile.getCanonicalPath()
+                            : FILE_UTILS.removeLeadingPath(canonBase,
+                            myfile.getCanonicalFile());
+                        if (!path.equals(currentelement) || ON_VMS) {
+                            myfile = findFile(basedir, currentelement, true);
+                            if (myfile != null && basedir != null) {
+                                currentelement = FILE_UTILS.removeLeadingPath(
+                                    basedir, myfile);
+                            }
+                        }
+                    } catch (IOException ex) {
+                        throw new BuildException(ex);
+                    }
+                }
+                if ((myfile == null || !myfile.exists()) && !isCaseSensitive()) {
+                    File f = findFile(basedir, currentelement, false);
+                    if (f != null && f.exists()) {
+                        // adapt currentelement to the case we've
+                        // actually found
+                        currentelement = (basedir == null)
+                            ? f.getAbsolutePath()
+                            : FILE_UTILS.removeLeadingPath(basedir, f);
+                        myfile = f;
+                    }
+                }
+                if (myfile != null && myfile.exists()) {
+                    if (!followSymlinks
+                        && isSymlink(basedir, currentelement)) {
+                        continue;
+                    }
+                    if (myfile.isDirectory()) {
+                        if (isIncluded(currentelement)
+                            && currentelement.length() > 0) {
+                            accountForIncludedDir(currentelement, myfile, true);
+                        }  else {
+                            if (currentelement.length() > 0) {
+                                if (currentelement.charAt(currentelement
+                                                          .length() - 1)
+                                    != File.separatorChar) {
+                                    currentelement =
+                                        currentelement + File.separatorChar;
+                                }
+                            }
+                            scandir(myfile, currentelement, true);
+                        }
+                    } else {
+                        boolean included = isCaseSensitive()
+                            ? originalpattern.equals(currentelement)
+                            : originalpattern.equalsIgnoreCase(currentelement);
+                        if (included) {
+                            accountForIncludedFile(currentelement, myfile);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Clear the result caches for a scan.
+     */
+    protected synchronized void clearResults() {
+        filesIncluded    = new Vector();
+        filesNotIncluded = new Vector();
+        filesExcluded    = new Vector();
+        filesDeselected  = new Vector();
+        dirsIncluded     = new Vector();
+        dirsNotIncluded  = new Vector();
+        dirsExcluded     = new Vector();
+        dirsDeselected   = new Vector();
+        everythingIncluded = (basedir != null);
+        scannedDirs.clear();
+    }
+
+    /**
+     * Top level invocation for a slow scan. A slow scan builds up a full
+     * list of excluded/included files/directories, whereas a fast scan
+     * will only have full results for included files, as it ignores
+     * directories which can't possibly hold any included files/directories.
+     * <p>
+     * Returns immediately if a slow scan has already been completed.
+     */
+    protected void slowScan() {
+        synchronized (slowScanLock) {
+            if (haveSlowResults) {
+                return;
+            }
+            if (slowScanning) {
+                while (slowScanning) {
+                    try {
+                        slowScanLock.wait();
+                    } catch (InterruptedException e) {
+                        // Empty
+                    }
+                }
+                return;
+            }
+            slowScanning = true;
+        }
+        try {
+            synchronized (this) {
+
+                // set in/excludes to reasonable defaults if needed:
+                boolean nullIncludes = (includes == null);
+                includes = nullIncludes ? new String[] {"**"} : includes;
+                boolean nullExcludes = (excludes == null);
+                excludes = nullExcludes ? new String[0] : excludes;
+
+                String[] excl = new String[dirsExcluded.size()];
+                dirsExcluded.copyInto(excl);
+
+                String[] notIncl = new String[dirsNotIncluded.size()];
+                dirsNotIncluded.copyInto(notIncl);
+
+                processSlowScan(excl);
+                processSlowScan(notIncl);
+                clearCaches();
+                includes = nullIncludes ? null : includes;
+                excludes = nullExcludes ? null : excludes;
+            }
+        } finally {
+            synchronized (slowScanLock) {
+                haveSlowResults = true;
+                slowScanning = false;
+                slowScanLock.notifyAll();
+            }
+        }
+    }
+
+    private void processSlowScan(String[] arr) {
+        for (int i = 0; i < arr.length; i++) {
+            if (!couldHoldIncluded(arr[i])) {
+                scandir(new File(basedir, arr[i]),
+                        arr[i] + File.separator, false);
+            }
+        }
+    }
+
+    /**
+     * Scan the given directory for files and directories. Found files and
+     * directories are placed in their respective collections, based on the
+     * matching of includes, excludes, and the selectors.  When a directory
+     * is found, it is scanned recursively.
+     *
+     * @param dir   The directory to scan. Must not be <code>null</code>.
+     * @param vpath The path relative to the base directory (needed to
+     *              prevent problems with an absolute path when using
+     *              dir). Must not be <code>null</code>.
+     * @param fast  Whether or not this call is part of a fast scan.
+     *
+     * @see #filesIncluded
+     * @see #filesNotIncluded
+     * @see #filesExcluded
+     * @see #dirsIncluded
+     * @see #dirsNotIncluded
+     * @see #dirsExcluded
+     * @see #slowScan
+     */
+    protected void scandir(File dir, String vpath, boolean fast) {
+        if (dir == null) {
+            throw new BuildException("dir must not be null.");
+        }
+        String[] newfiles = dir.list();
+        if (newfiles == null) {
+            if (!dir.exists()) {
+                throw new BuildException(dir + " doesn't exist.");
+            } else if (!dir.isDirectory()) {
+                throw new BuildException(dir + " is not a directory.");
+            } else {
+                throw new BuildException("IO error scanning directory '"
+                                         + dir.getAbsolutePath() + "'");
+            }
+        }
+        scandir(dir, vpath, fast, newfiles);
+    }
+    private void scandir(File dir, String vpath, boolean fast, String[] newfiles) {
+        // avoid double scanning of directories, can only happen in fast mode
+        if (fast && hasBeenScanned(vpath)) {
+            return;
+        }
+        if (!followSymlinks) {
+            Vector noLinks = new Vector();
+            for (int i = 0; i < newfiles.length; i++) {
+                try {
+                    if (FILE_UTILS.isSymbolicLink(dir, newfiles[i])) {
+                        String name = vpath + newfiles[i];
+                        File file = new File(dir, newfiles[i]);
+                        (file.isDirectory()
+                            ? dirsExcluded : filesExcluded).addElement(name);
+                    } else {
+                        noLinks.addElement(newfiles[i]);
+                    }
+                } catch (IOException ioe) {
+                    String msg = "IOException caught while checking "
+                        + "for links, couldn't get canonical path!";
+                    // will be caught and redirected to Ant's logging system
+                    System.err.println(msg);
+                    noLinks.addElement(newfiles[i]);
+                }
+            }
+            newfiles = (String[]) (noLinks.toArray(new String[noLinks.size()]));
+        }
+        for (int i = 0; i < newfiles.length; i++) {
+            String name = vpath + newfiles[i];
+            File file = new File(dir, newfiles[i]);
+            String[] children = file.list();
+            if (children == null) { // probably file
+                if (isIncluded(name)) {
+                    accountForIncludedFile(name, file);
+                } else {
+                    everythingIncluded = false;
+                    filesNotIncluded.addElement(name);
+                }
+            } else { // dir
+                if (isIncluded(name)) {
+                    accountForIncludedDir(name, file, fast, children);
+                } else {
+                    everythingIncluded = false;
+                    dirsNotIncluded.addElement(name);
+                    if (fast && couldHoldIncluded(name)) {
+                        scandir(file, name + File.separator, fast, children);
+                    }
+                }
+                if (!fast) {
+                    scandir(file, name + File.separator, fast, children);
+                }
+            }
+        }
+    }
+
+    /**
+     * Process included file.
+     * @param name  path of the file relative to the directory of the FileSet.
+     * @param file  included File.
+     */
+    private void accountForIncludedFile(String name, File file) {
+        processIncluded(name, file, filesIncluded, filesExcluded, filesDeselected);
+    }
+
+    /**
+     * Process included directory.
+     * @param name path of the directory relative to the directory of
+     *             the FileSet.
+     * @param file directory as File.
+     * @param fast whether to perform fast scans.
+     */
+    private void accountForIncludedDir(String name, File file, boolean fast) {
+        processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected);
+        if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) {
+            scandir(file, name + File.separator, fast);
+        }
+    }
+    private void accountForIncludedDir(String name, File file, boolean fast, String[] children) {
+        processIncluded(name, file, dirsIncluded, dirsExcluded, dirsDeselected);
+        if (fast && couldHoldIncluded(name) && !contentsExcluded(name)) {
+            scandir(file, name + File.separator, fast, children);
+        }
+    }
+
+    private void processIncluded(String name, File file, Vector inc, Vector exc, Vector des) {
+
+        if (inc.contains(name) || exc.contains(name) || des.contains(name)) { return; }
+
+        boolean included = false;
+        if (isExcluded(name)) {
+            exc.add(name);
+        } else if (isSelected(name, file)) {
+            included = true;
+            inc.add(name);
+        } else {
+            des.add(name);
+        }
+        everythingIncluded &= included;
+    }
+
+    /**
+     * Test whether or not a name matches against at least one include
+     * pattern.
+     *
+     * @param name The name to match. Must not be <code>null</code>.
+     * @return <code>true</code> when the name matches against at least one
+     *         include pattern, or <code>false</code> otherwise.
+     */
+    protected boolean isIncluded(String name) {
+        ensureNonPatternSetsReady();
+
+        if (isCaseSensitive()
+            ? includeNonPatterns.contains(name)
+            : includeNonPatterns.contains(name.toUpperCase())) {
+            return true;
+        }
+        for (int i = 0; i < includePatterns.length; i++) {
+            if (matchPath(includePatterns[i], name, isCaseSensitive())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test whether or not a name matches the start of at least one include
+     * pattern.
+     *
+     * @param name The name to match. Must not be <code>null</code>.
+     * @return <code>true</code> when the name matches against the start of at
+     *         least one include pattern, or <code>false</code> otherwise.
+     */
+    protected boolean couldHoldIncluded(String name) {
+        for (int i = 0; i < includes.length; i++) {
+            if (matchPatternStart(includes[i], name, isCaseSensitive())
+                && isMorePowerfulThanExcludes(name, includes[i])
+                && isDeeper(includes[i], name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Verify that a pattern specifies files deeper
+     * than the level of the specified file.
+     * @param pattern the pattern to check.
+     * @param name the name to check.
+     * @return whether the pattern is deeper than the name.
+     * @since Ant 1.6.3
+     */
+    private boolean isDeeper(String pattern, String name) {
+        Vector p = SelectorUtils.tokenizePath(pattern);
+        Vector n = SelectorUtils.tokenizePath(name);
+        return p.contains("**") || p.size() > n.size();
+    }
+
+    /**
+     *  Find out whether one particular include pattern is more powerful
+     *  than all the excludes.
+     *  Note:  the power comparison is based on the length of the include pattern
+     *  and of the exclude patterns without the wildcards.
+     *  Ideally the comparison should be done based on the depth
+     *  of the match; that is to say how many file separators have been matched
+     *  before the first ** or the end of the pattern.
+     *
+     *  IMPORTANT : this function should return false "with care".
+     *
+     *  @param name the relative path to test.
+     *  @param includepattern one include pattern.
+     *  @return true if there is no exclude pattern more powerful than this include pattern.
+     *  @since Ant 1.6
+     */
+    private boolean isMorePowerfulThanExcludes(String name, String includepattern) {
+        String soughtexclude = name + File.separator + "**";
+        for (int counter = 0; counter < excludes.length; counter++) {
+            if (excludes[counter].equals(soughtexclude))  {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Test whether all contents of the specified directory must be excluded.
+     * @param name the directory name to check.
+     * @return whether all the specified directory's contents are excluded.
+     */
+    private boolean contentsExcluded(String name) {
+        name = (name.endsWith(File.separator)) ? name : name + File.separator;
+        for (int i = 0; i < excludes.length; i++) {
+            String e = excludes[i];
+            if (e.endsWith("**") && SelectorUtils.matchPath(
+                e.substring(0, e.length() - 2), name, isCaseSensitive())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test whether or not a name matches against at least one exclude
+     * pattern.
+     *
+     * @param name The name to match. Must not be <code>null</code>.
+     * @return <code>true</code> when the name matches against at least one
+     *         exclude pattern, or <code>false</code> otherwise.
+     */
+    protected boolean isExcluded(String name) {
+        ensureNonPatternSetsReady();
+
+        if (isCaseSensitive()
+            ? excludeNonPatterns.contains(name)
+            : excludeNonPatterns.contains(name.toUpperCase())) {
+            return true;
+        }
+        for (int i = 0; i < excludePatterns.length; i++) {
+            if (matchPath(excludePatterns[i], name, isCaseSensitive())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Test whether a file should be selected.
+     *
+     * @param name the filename to check for selecting.
+     * @param file the java.io.File object for this filename.
+     * @return <code>false</code> when the selectors says that the file
+     *         should not be selected, <code>true</code> otherwise.
+     */
+    protected boolean isSelected(String name, File file) {
+        if (selectors != null) {
+            for (int i = 0; i < selectors.length; i++) {
+                if (!selectors[i].isSelected(basedir, name, file)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Return the names of the files which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the files which matched at least one of the
+     *         include patterns and none of the exclude patterns.
+     */
+    public synchronized String[] getIncludedFiles() {
+        if (filesIncluded == null) {
+            throw new IllegalStateException("Must call scan() first");
+        }
+        String[] files = new String[filesIncluded.size()];
+        filesIncluded.copyInto(files);
+        Arrays.sort(files);
+        return files;
+    }
+
+    /**
+     * Return the count of included files.
+     * @return <code>int</code>.
+     * @since Ant 1.6.3
+     */
+    public synchronized int getIncludedFilesCount() {
+        if (filesIncluded == null) {
+            throw new IllegalStateException("Must call scan() first");
+        }
+        return filesIncluded.size();
+    }
+
+    /**
+     * Return the names of the files which matched none of the include
+     * patterns. The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.
+     *
+     * @return the names of the files which matched none of the include
+     *         patterns.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getNotIncludedFiles() {
+        slowScan();
+        String[] files = new String[filesNotIncluded.size()];
+        filesNotIncluded.copyInto(files);
+        return files;
+    }
+
+    /**
+     * Return the names of the files which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     * The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.
+     *
+     * @return the names of the files which matched at least one of the
+     *         include patterns and at least one of the exclude patterns.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getExcludedFiles() {
+        slowScan();
+        String[] files = new String[filesExcluded.size()];
+        filesExcluded.copyInto(files);
+        return files;
+    }
+
+    /**
+     * <p>Return the names of the files which were selected out and
+     * therefore not ultimately included.</p>
+     *
+     * <p>The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.</p>
+     *
+     * @return the names of the files which were deselected.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getDeselectedFiles() {
+        slowScan();
+        String[] files = new String[filesDeselected.size()];
+        filesDeselected.copyInto(files);
+        return files;
+    }
+
+    /**
+     * Return the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     */
+    public synchronized String[] getIncludedDirectories() {
+        if (dirsIncluded == null) {
+            throw new IllegalStateException("Must call scan() first");
+        }
+        String[] directories = new String[dirsIncluded.size()];
+        dirsIncluded.copyInto(directories);
+        Arrays.sort(directories);
+        return directories;
+    }
+
+    /**
+     * Return the count of included directories.
+     * @return <code>int</code>.
+     * @since Ant 1.6.3
+     */
+    public synchronized int getIncludedDirsCount() {
+        if (dirsIncluded == null) {
+            throw new IllegalStateException("Must call scan() first");
+        }
+        return dirsIncluded.size();
+    }
+
+    /**
+     * Return the names of the directories which matched none of the include
+     * patterns. The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.
+     *
+     * @return the names of the directories which matched none of the include
+     * patterns.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getNotIncludedDirectories() {
+        slowScan();
+        String[] directories = new String[dirsNotIncluded.size()];
+        dirsNotIncluded.copyInto(directories);
+        return directories;
+    }
+
+    /**
+     * Return the names of the directories which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     * The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.
+     *
+     * @return the names of the directories which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getExcludedDirectories() {
+        slowScan();
+        String[] directories = new String[dirsExcluded.size()];
+        dirsExcluded.copyInto(directories);
+        return directories;
+    }
+
+    /**
+     * <p>Return the names of the directories which were selected out and
+     * therefore not ultimately included.</p>
+     *
+     * <p>The names are relative to the base directory. This involves
+     * performing a slow scan if one has not already been completed.</p>
+     *
+     * @return the names of the directories which were deselected.
+     *
+     * @see #slowScan
+     */
+    public synchronized String[] getDeselectedDirectories() {
+        slowScan();
+        String[] directories = new String[dirsDeselected.size()];
+        dirsDeselected.copyInto(directories);
+        return directories;
+    }
+
+    /**
+     * Add default exclusions to the current exclusions set.
+     */
+    public synchronized void addDefaultExcludes() {
+        int excludesLength = excludes == null ? 0 : excludes.length;
+        String[] newExcludes;
+        newExcludes = new String[excludesLength + defaultExcludes.size()];
+        if (excludesLength > 0) {
+            System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
+        }
+        String[] defaultExcludesTemp = getDefaultExcludes();
+        for (int i = 0; i < defaultExcludesTemp.length; i++) {
+            newExcludes[i + excludesLength] =
+                defaultExcludesTemp[i].replace('/', File.separatorChar)
+                .replace('\\', File.separatorChar);
+        }
+        excludes = newExcludes;
+    }
+
+    /**
+     * Get the named resource.
+     * @param name path name of the file relative to the dir attribute.
+     *
+     * @return the resource with the given name.
+     * @since Ant 1.5.2
+     */
+    public synchronized Resource getResource(String name) {
+        return new FileResource(basedir, name);
+    }
+
+    /**
+     * Return a cached result of list performed on file, if
+     * available.  Invokes the method and caches the result otherwise.
+     *
+     * @param file File (dir) to list.
+     * @since Ant 1.6
+     */
+    private String[] list(File file) {
+        String[] files = (String[]) fileListMap.get(file);
+        if (files == null) {
+            files = file.list();
+            if (files != null) {
+                fileListMap.put(file, files);
+            }
+        }
+        return files;
+    }
+
+    /**
+     * From <code>base</code> traverse the filesystem in order to find
+     * a file that matches the given name.
+     *
+     * @param base base File (dir).
+     * @param path file path.
+     * @param cs whether to scan case-sensitively.
+     * @return File object that points to the file in question or null.
+     *
+     * @since Ant 1.6.3
+     */
+    private File findFile(File base, String path, boolean cs) {
+        if (FileUtils.isAbsolutePath(path)) {
+            if (base == null) {
+                String[] s = FILE_UTILS.dissect(path);
+                base = new File(s[0]);
+                path = s[1];
+            } else {
+                File f = FILE_UTILS.normalize(path);
+                String s = FILE_UTILS.removeLeadingPath(base, f);
+                if (s.equals(f.getAbsolutePath())) {
+                    //removing base from path yields no change; path not child of base
+                    return null;
+                }
+                path = s;
+            }
+        }
+        return findFile(base, SelectorUtils.tokenizePath(path), cs);
+    }
+
+    /**
+     * From <code>base</code> traverse the filesystem in order to find
+     * a file that matches the given stack of names.
+     *
+     * @param base base File (dir).
+     * @param pathElements Vector of path elements (dirs...file).
+     * @param cs whether to scan case-sensitively.
+     * @return File object that points to the file in question or null.
+     *
+     * @since Ant 1.6.3
+     */
+    private File findFile(File base, Vector pathElements, boolean cs) {
+        if (pathElements.size() == 0) {
+            return base;
+        }
+        String current = (String) pathElements.remove(0);
+        if (base == null) {
+            return findFile(new File(current), pathElements, cs);
+        }
+        if (!base.isDirectory()) {
+            return null;
+        }
+        String[] files = list(base);
+        if (files == null) {
+            throw new BuildException("IO error scanning directory "
+                                     + base.getAbsolutePath());
+        }
+        boolean[] matchCase = cs ? CS_SCAN_ONLY : CS_THEN_NON_CS;
+        for (int i = 0; i < matchCase.length; i++) {
+            for (int j = 0; j < files.length; j++) {
+                if (matchCase[i] ? files[j].equals(current)
+                                 : files[j].equalsIgnoreCase(current)) {
+                    return findFile(new File(base, files[j]), pathElements, cs);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Do we have to traverse a symlink when trying to reach path from
+     * basedir?
+     * @param base base File (dir).
+     * @param path file path.
+     * @since Ant 1.6
+     */
+    private boolean isSymlink(File base, String path) {
+        return isSymlink(base, SelectorUtils.tokenizePath(path));
+    }
+
+    /**
+     * Do we have to traverse a symlink when trying to reach path from
+     * basedir?
+     * @param base base File (dir).
+     * @param pathElements Vector of path elements (dirs...file).
+     * @since Ant 1.6
+     */
+    private boolean isSymlink(File base, Vector pathElements) {
+        if (pathElements.size() > 0) {
+            String current = (String) pathElements.remove(0);
+            try {
+                return FILE_UTILS.isSymbolicLink(base, current)
+                    || isSymlink(new File(base, current), pathElements);
+            } catch (IOException ioe) {
+                String msg = "IOException caught while checking "
+                    + "for links, couldn't get canonical path!";
+                // will be caught and redirected to Ant's logging system
+                System.err.println(msg);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Has the directory with the given path relative to the base
+     * directory already been scanned?
+     *
+     * <p>Registers the given directory as scanned as a side effect.</p>
+     *
+     * @since Ant 1.6
+     */
+    private boolean hasBeenScanned(String vpath) {
+        return !scannedDirs.add(vpath);
+    }
+
+    /**
+     * This method is of interest for testing purposes.  The returned
+     * Set is live and should not be modified.
+     * @return the Set of relative directory names that have been scanned.
+     */
+    /* package-private */ Set getScannedDirs() {
+        return scannedDirs;
+    }
+
+    /**
+     * Clear internal caches.
+     *
+     * @since Ant 1.6
+     */
+    private synchronized void clearCaches() {
+        fileListMap.clear();
+        includeNonPatterns.clear();
+        excludeNonPatterns.clear();
+        includePatterns = null;
+        excludePatterns = null;
+        areNonPatternSetsReady = false;
+    }
+
+    /**
+     * Ensure that the in|exclude &quot;patterns&quot;
+     * have been properly divided up.
+     *
+     * @since Ant 1.6.3
+     */
+    private synchronized void ensureNonPatternSetsReady() {
+        if (!areNonPatternSetsReady) {
+            includePatterns = fillNonPatternSet(includeNonPatterns, includes);
+            excludePatterns = fillNonPatternSet(excludeNonPatterns, excludes);
+            areNonPatternSetsReady = true;
+        }
+    }
+
+    /**
+     * Add all patterns that are not real patterns (do not contain
+     * wildcards) to the set and returns the real patterns.
+     *
+     * @param set Set to populate.
+     * @param patterns String[] of patterns.
+     * @since Ant 1.6.3
+     */
+    private String[] fillNonPatternSet(Set set, String[] patterns) {
+        ArrayList al = new ArrayList(patterns.length);
+        for (int i = 0; i < patterns.length; i++) {
+            if (!SelectorUtils.hasWildcards(patterns[i])) {
+                set.add(isCaseSensitive() ? patterns[i]
+                    : patterns[i].toUpperCase());
+            } else {
+                al.add(patterns[i]);
+            }
+        }
+        return set.size() == 0 ? patterns
+            : (String[]) al.toArray(new String[al.size()]);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicAttribute.java b/trunk/src/main/org/apache/tools/ant/DynamicAttribute.java
new file mode 100644
index 0000000..445c33e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicAttribute.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes
+ *
+ * @since Ant 1.5
+ */
+public interface DynamicAttribute {
+
+    /**
+     * Set a named attribute to the given value
+     *
+     * @param name the name of the attribute
+     * @param value the new value of the attribute
+     * @throws BuildException when any error occurs
+     */
+    void setDynamicAttribute(String name, String value)
+            throws BuildException;
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicAttributeNS.java b/trunk/src/main/org/apache/tools/ant/DynamicAttributeNS.java
new file mode 100644
index 0000000..7d6e84e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicAttributeNS.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes.
+ *
+ * @since Ant 1.7
+ */
+public interface DynamicAttributeNS {
+
+    /**
+     * Set a named attribute to the given value
+     *
+     * @param uri The namespace uri for this attribute, "" is
+     *            used if there is no namespace uri.
+     * @param localName The localname of this attribute.
+     * @param qName The qualified name for this attribute
+     * @param value The value of this attribute.
+     * @throws BuildException when any error occurs
+     */
+    void setDynamicAttribute(
+        String uri, String localName, String qName, String value)
+            throws BuildException;
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicConfigurator.java b/trunk/src/main/org/apache/tools/ant/DynamicConfigurator.java
new file mode 100644
index 0000000..e48062b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicConfigurator.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes and elements.
+ *
+ * @since Ant 1.5
+ */
+public interface DynamicConfigurator
+    extends DynamicAttribute, DynamicElement {
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicConfiguratorNS.java b/trunk/src/main/org/apache/tools/ant/DynamicConfiguratorNS.java
new file mode 100644
index 0000000..40b3d65
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicConfiguratorNS.java
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown attributes and elements.
+ *
+ * @since Ant 1.7
+ */
+public interface DynamicConfiguratorNS
+    extends DynamicAttributeNS, DynamicElementNS {
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicElement.java b/trunk/src/main/org/apache/tools/ant/DynamicElement.java
new file mode 100644
index 0000000..53e353f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicElement.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown elements.
+ *
+ * @since Ant 1.5
+ */
+public interface DynamicElement {
+
+    /**
+     * Create an element with the given name
+     *
+     * @param name the element nbame
+     * @throws BuildException when any error occurs
+     * @return the element created
+     */
+    Object createDynamicElement(String name) throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/DynamicElementNS.java b/trunk/src/main/org/apache/tools/ant/DynamicElementNS.java
new file mode 100644
index 0000000..57bfa53
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/DynamicElementNS.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Enables a task to control unknown elements.
+ *
+ * @since Ant 1.7
+ */
+public interface DynamicElementNS {
+    /**
+     * Create an element with the given name
+     *
+     * @param uri The namespace uri for this attribute.
+     * @param localName The localname of this attribute.
+     * @param qName The qualified name for this element.
+     * @throws BuildException when any error occurs
+     * @return the element created for this element.
+     */
+    Object createDynamicElement(
+        String uri, String localName, String qName) throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/Executor.java b/trunk/src/main/org/apache/tools/ant/Executor.java
new file mode 100755
index 0000000..6d92e7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Executor.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Target executor abstraction.
+ * @since Ant 1.6.3
+ */
+public interface Executor {
+
+    /**
+     * Execute the specified Targets for the specified Project.
+     * @param project       the Ant Project.
+     * @param targetNames   String[] of Target names as specified on the command line.
+     * @throws BuildException on error
+     */
+    void executeTargets(Project project, String[] targetNames)
+        throws BuildException;
+
+    /**
+     * Get the appropriate subproject Executor instance.
+     * @return an Executor instance.
+     */
+    Executor getSubProjectExecutor();
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/ExitException.java b/trunk/src/main/org/apache/tools/ant/ExitException.java
new file mode 100644
index 0000000..11e1bc8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/ExitException.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Used to report exit status of classes which call System.exit().
+ *
+ * @see org.apache.tools.ant.util.optional.NoExitSecurityManager
+ * @see org.apache.tools.ant.types.Permissions
+ *
+ */
+public class ExitException extends SecurityException {
+
+    private static final long serialVersionUID = 2772487854280543363L;
+
+    /** Status code */
+    private int status;
+
+    /**
+     * Constructs an exit exception.
+     * @param status the status code returned via System.exit()
+     */
+    public ExitException(int status) {
+        super("ExitException: status " + status);
+        this.status = status;
+    }
+
+    /**
+     * Constructs an exit exception.
+     * @param msg the message to be displayed.
+     * @param status the status code returned via System.exit()
+     */
+    public ExitException(String msg, int status) {
+        super(msg);
+        this.status = status;
+    }
+
+    /**
+     * The status code returned by System.exit()
+     *
+     * @return the status code returned by System.exit()
+     */
+    public int getStatus() {
+        return status;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/ExitStatusException.java b/trunk/src/main/org/apache/tools/ant/ExitStatusException.java
new file mode 100644
index 0000000..1eb5127
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/ExitStatusException.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * BuildException + exit status.
+ *
+ * @since Ant 1.7
+ */
+public class ExitStatusException extends BuildException {
+
+    private static final long serialVersionUID = 7760846806886585968L;
+
+    /** Status code */
+    private int status;
+
+    /**
+     * Constructs an <code>ExitStatusException</code>.
+     * @param status the associated status code
+     */
+    public ExitStatusException(int status) {
+        super();
+        this.status = status;
+    }
+
+    /**
+     * Constructs an <code>ExitStatusException</code>.
+     * @param msg the associated message
+     * @param status the associated status code
+     */
+    public ExitStatusException(String msg, int status) {
+        super(msg);
+        this.status = status;
+    }
+
+    /**
+     * Construct an exit status exception with location information too
+     * @param message error message
+     * @param status exit status
+     * @param location exit location
+     */
+    public ExitStatusException(String message, int status, Location location) {
+        super(message, location);
+        this.status = status;
+    }
+
+    /**
+     * Get the status code.
+     * @return <code>int</code>
+     */
+    public int getStatus() {
+        return status;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/FileScanner.java b/trunk/src/main/org/apache/tools/ant/FileScanner.java
new file mode 100644
index 0000000..a7cb9de
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/FileScanner.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.File;
+
+/**
+ * An interface used to describe the actions required of any type of
+ * directory scanner.
+ *
+ */
+public interface FileScanner {
+    /**
+     * Adds default exclusions to the current exclusions set.
+     */
+    void addDefaultExcludes();
+
+    /**
+     * Returns the base directory to be scanned.
+     * This is the directory which is scanned recursively.
+     *
+     * @return the base directory to be scanned
+     */
+    File getBasedir();
+
+    /**
+     * Returns the names of the directories which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the directories which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     */
+    String[] getExcludedDirectories();
+
+    /**
+     * Returns the names of the files which matched at least one of the
+     * include patterns and at least one of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the files which matched at least one of the
+     *         include patterns and at least one of the exclude patterns.
+     *
+     */
+    String[] getExcludedFiles();
+
+    /**
+     * Returns the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     */
+    String[] getIncludedDirectories();
+
+    /**
+     * Returns the names of the files which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the files which matched at least one of the
+     *         include patterns and none of the exclude patterns.
+     */
+    String[] getIncludedFiles();
+
+    /**
+     * Returns the names of the directories which matched none of the include
+     * patterns. The names are relative to the base directory.
+     *
+     * @return the names of the directories which matched none of the include
+     * patterns.
+     */
+    String[] getNotIncludedDirectories();
+
+    /**
+     * Returns the names of the files which matched none of the include
+     * patterns. The names are relative to the base directory.
+     *
+     * @return the names of the files which matched none of the include
+     *         patterns.
+     */
+    String[] getNotIncludedFiles();
+
+    /**
+     * Scans the base directory for files which match at least one include
+     * pattern and don't match any exclude patterns.
+     *
+     * @exception IllegalStateException if the base directory was set
+     *            incorrectly (i.e. if it is <code>null</code>, doesn't exist,
+     *            or isn't a directory).
+     */
+    void scan() throws IllegalStateException;
+
+    /**
+     * Sets the base directory to be scanned. This is the directory which is
+     * scanned recursively. All '/' and '\' characters should be replaced by
+     * <code>File.separatorChar</code>, so the separator used need not match
+     * <code>File.separatorChar</code>.
+     *
+     * @param basedir The base directory to scan.
+     *                Must not be <code>null</code>.
+     */
+    void setBasedir(String basedir);
+
+    /**
+     * Sets the base directory to be scanned. This is the directory which is
+     * scanned recursively.
+     *
+     * @param basedir The base directory for scanning.
+     *                Should not be <code>null</code>.
+     */
+    void setBasedir(File basedir);
+
+    /**
+     * Sets the list of exclude patterns to use.
+     *
+     * @param excludes A list of exclude patterns.
+     *                 May be <code>null</code>, indicating that no files
+     *                 should be excluded. If a non-<code>null</code> list is
+     *                 given, all elements must be non-<code>null</code>.
+     */
+    void setExcludes(String[] excludes);
+
+    /**
+     * Sets the list of include patterns to use.
+     *
+     * @param includes A list of include patterns.
+     *                 May be <code>null</code>, indicating that all files
+     *                 should be included. If a non-<code>null</code>
+     *                 list is given, all elements must be
+     * non-<code>null</code>.
+     */
+    void setIncludes(String[] includes);
+
+    /**
+     * Sets whether or not the file system should be regarded as case sensitive.
+     *
+     * @param isCaseSensitive whether or not the file system should be
+     *                        regarded as a case sensitive one
+     */
+    void setCaseSensitive(boolean isCaseSensitive);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java b/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java
new file mode 100644
index 0000000..7a99d90
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/IntrospectionHelper.java
@@ -0,0 +1,1625 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.taskdefs.PreSetDef;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Helper class that collects the methods a task or nested element
+ * holds to set attributes, create nested elements or hold PCDATA
+ * elements.
+ *
+ * It contains hashtables containing classes that use introspection
+ * to handle all the invocation of the project-component specific methods.
+ *
+ * This class is somewhat complex, as it implements the O/X mapping between
+ * Ant XML and Java class instances. This is not the best place for someone new
+ * to Ant to start contributing to the codebase, as a change here can break the
+ * entire system in interesting ways. Always run a full test of Ant before checking
+ * in/submitting changes to this file.
+ *
+ * The class is final and has a private constructor.
+ * To get an instance for a specific (class,project) combination,
+ * use {@link #getHelper(Project,Class)}.
+ * This may return an existing version, or a new one
+ * ...do not make any assumptions about its uniqueness, or its validity after the Project
+ * instance has finished its build.
+ *
+ */
+public final class IntrospectionHelper  {
+
+    /**
+     * Helper instances we've already created (Class.getName() to IntrospectionHelper).
+     */
+    private static final Map HELPERS = new Hashtable();
+
+    /**
+     * Map from primitive types to wrapper classes for use in
+     * createAttributeSetter (Class to Class). Note that char
+     * and boolean are in here even though they get special treatment
+     * - this way we only need to test for the wrapper class.
+     */
+    private static final Map PRIMITIVE_TYPE_MAP = new HashMap(8);
+
+    // Set up PRIMITIVE_TYPE_MAP
+    static {
+        Class[] primitives = {Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE,
+                              Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE};
+        Class[] wrappers = {Boolean.class, Byte.class, Character.class, Short.class,
+                            Integer.class, Long.class, Float.class, Double.class};
+        for (int i = 0; i < primitives.length; i++) {
+            PRIMITIVE_TYPE_MAP.put (primitives[i], wrappers[i]);
+        }
+    }
+
+    private static final int MAX_REPORT_NESTED_TEXT = 20;
+    private static final String ELLIPSIS = "...";
+
+    /**
+     * Map from attribute names to attribute types
+     * (String to Class).
+     */
+    private Hashtable attributeTypes = new Hashtable();
+
+    /**
+     * Map from attribute names to attribute setter methods
+     * (String to AttributeSetter).
+     */
+    private Hashtable attributeSetters = new Hashtable();
+
+    /**
+     * Map from attribute names to nested types
+     * (String to Class).
+     */
+    private Hashtable nestedTypes = new Hashtable();
+
+    /**
+     * Map from attribute names to methods to create nested types
+     * (String to NestedCreator).
+     */
+    private Hashtable nestedCreators = new Hashtable();
+
+    /**
+     * Vector of methods matching add[Configured](Class) pattern.
+     */
+    private List addTypeMethods = new ArrayList();
+
+    /**
+     * The method to invoke to add PCDATA.
+     */
+    private Method addText = null;
+
+    /**
+     * The class introspected by this instance.
+     */
+    private Class bean;
+
+    /**
+     * Sole constructor, which is private to ensure that all
+     * IntrospectionHelpers are created via {@link #getHelper(Class) getHelper}.
+     * Introspects the given class for bean-like methods.
+     * Each method is examined in turn, and the following rules are applied:
+     * <p>
+     * <ul>
+     * <li>If the method is <code>Task.setLocation(Location)</code>,
+     * <code>Task.setTaskType(String)</code>
+     * or <code>TaskContainer.addTask(Task)</code>, it is ignored. These
+     * methods are handled differently elsewhere.
+     * <li><code>void addText(String)</code> is recognised as the method for
+     * adding PCDATA to a bean.
+     * <li><code>void setFoo(Bar)</code> is recognised as a method for
+     * setting the value of attribute <code>foo</code>, so long as
+     * <code>Bar</code> is non-void and is not an array type. Non-String
+     * parameter types always overload String parameter types, but that is
+     * the only guarantee made in terms of priority.
+     * <li><code>Foo createBar()</code> is recognised as a method for
+     * creating a nested element called <code>bar</code> of type
+     * <code>Foo</code>, so long as <code>Foo</code> is not a primitive or
+     * array type.
+     * <li><code>void addConfiguredFoo(Bar)</code> is recognised as a
+     * method for storing a pre-configured element called
+     * <code>foo</code> and of type <code>Bar</code>, so long as
+     * <code>Bar</code> is not an array, primitive or String type.
+     * <code>Bar</code> must have an accessible constructor taking no
+     * arguments.
+     * <li><code>void addFoo(Bar)</code> is recognised as a method for storing
+     * an element called <code>foo</code> and of type <code>Bar</code>, so
+     * long as <code>Bar</code> is not an array, primitive or String type.
+     * <code>Bar</code> must have an accessible constructor taking no
+     * arguments. This is distinct from the 'addConfigured' idiom in that
+     * the nested element is added to the parent immediately after it is
+     * constructed; in practice this means that <code>addFoo(Bar)</code> should
+     * do little or nothing with its argument besides storing it for later use.
+     * </ul>
+     * Note that only one method is retained to create/set/addConfigured/add
+     * any element or attribute.
+     *
+     * @param bean The bean type to introspect.
+     *             Must not be <code>null</code>.
+     *
+     * @see #getHelper(Class)
+     */
+    private IntrospectionHelper(final Class bean) {
+        this.bean = bean;
+        Method[] methods = bean.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            final Method m = methods[i];
+            final String name = m.getName();
+            Class returnType = m.getReturnType();
+            Class[] args = m.getParameterTypes();
+
+            // check of add[Configured](Class) pattern
+            if (args.length == 1 && java.lang.Void.TYPE.equals(returnType)
+                    && ("add".equals(name) || "addConfigured".equals(name))) {
+                insertAddTypeMethod(m);
+                continue;
+            }
+            // not really user settable properties on tasks/project components
+            if (org.apache.tools.ant.ProjectComponent.class.isAssignableFrom(bean)
+                    && args.length == 1 && isHiddenSetMethod(name, args[0])) {
+                continue;
+            }
+            // hide addTask for TaskContainers
+            if (isContainer() && args.length == 1 && "addTask".equals(name)
+                    && org.apache.tools.ant.Task.class.equals(args[0])) {
+                continue;
+            }
+            if ("addText".equals(name) && java.lang.Void.TYPE.equals(returnType)
+                    && args.length == 1 && java.lang.String.class.equals(args[0])) {
+                addText = methods[i];
+            } else if (name.startsWith("set") && java.lang.Void.TYPE.equals(returnType)
+                    && args.length == 1 && !args[0].isArray()) {
+                String propName = getPropertyName(name, "set");
+                if (attributeSetters.get(propName) != null) {
+                    if (java.lang.String.class.equals(args[0])) {
+                        /*
+                            Ignore method m, as there is an overloaded
+                            form of this method that takes in a
+                            non-string argument, which gains higher
+                            priority.
+                        */
+                        continue;
+                    }
+                    /*
+                        If the argument is not a String and if there
+                        is an overloaded form of this method already defined,
+                        we just override that with the new one.
+                        This mechanism does not guarantee any specific order
+                        in which the methods will be selected: so any code
+                        that depends on the order in which "set" methods have
+                        been defined, is not guaranteed to be selected in any
+                        particular order.
+                    */
+                }
+                AttributeSetter as = createAttributeSetter(m, args[0], propName);
+                if (as != null) {
+                    attributeTypes.put(propName, args[0]);
+                    attributeSetters.put(propName, as);
+                }
+            } else if (name.startsWith("create") && !returnType.isArray()
+                    && !returnType.isPrimitive() && args.length == 0) {
+
+                String propName = getPropertyName(name, "create");
+                // Check if a create of this property is already present
+                // add takes preference over create for CB purposes
+                if (nestedCreators.get(propName) == null) {
+                    nestedTypes.put(propName, returnType);
+                    nestedCreators.put(propName, new CreateNestedCreator(m));
+                }
+            } else if (name.startsWith("addConfigured")
+                    && java.lang.Void.TYPE.equals(returnType) && args.length == 1
+                    && !java.lang.String.class.equals(args[0])
+                    && !args[0].isArray() && !args[0].isPrimitive()) {
+                try {
+                    Constructor constructor = null;
+                    try {
+                        constructor = args[0].getConstructor(new Class[] {});
+                    } catch (NoSuchMethodException ex) {
+                        constructor = args[0].getConstructor(new Class[] {Project.class});
+                    }
+                    String propName = getPropertyName(name, "addConfigured");
+                    nestedTypes.put(propName, args[0]);
+                    nestedCreators.put(propName, new AddNestedCreator(m,
+                        constructor, AddNestedCreator.ADD_CONFIGURED));
+                } catch (NoSuchMethodException nse) {
+                    // ignore
+                }
+            } else if (name.startsWith("add")
+                    && java.lang.Void.TYPE.equals(returnType) && args.length == 1
+                    && !java.lang.String.class.equals(args[0])
+                    && !args[0].isArray() && !args[0].isPrimitive()) {
+                try {
+                    Constructor constructor = null;
+                    try {
+                        constructor = args[0].getConstructor(new Class[] {});
+                    } catch (NoSuchMethodException ex) {
+                        constructor = args[0].getConstructor(new Class[] {Project.class});
+                    }
+                    String propName = getPropertyName(name, "add");
+                    if (nestedTypes.get(propName) != null) {
+                        /*
+                         *  Ignore this method as there is an addConfigured
+                         *  form of this method that has a higher
+                         *  priority
+                         */
+                        continue;
+                    }
+                    nestedTypes.put(propName, args[0]);
+                    nestedCreators.put(propName, new AddNestedCreator(m,
+                            constructor, AddNestedCreator.ADD));
+                } catch (NoSuchMethodException nse) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Certain set methods are part of the Ant core interface to tasks and
+     * therefore not to be considered for introspection
+     *
+     * @param name the name of the set method
+     * @param type the type of the set method's parameter
+     * @return true if the given set method is to be hidden.
+     */
+    private boolean isHiddenSetMethod(String name, Class type) {
+        if ("setLocation".equals(name) && org.apache.tools.ant.Location.class.equals(type)) {
+            return true;
+        }
+        if ("setTaskType".equals(name) && java.lang.String.class.equals(type)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a helper for the given class, either from the cache
+     * or by creating a new instance.
+     *
+     * @param c The class for which a helper is required.
+     *          Must not be <code>null</code>.
+     *
+     * @return a helper for the specified class
+     */
+    public static synchronized IntrospectionHelper getHelper(Class c) {
+        return getHelper(null, c);
+    }
+
+    /**
+     * Returns a helper for the given class, either from the cache
+     * or by creating a new instance.
+     *
+     * The method will make sure the helper will be cleaned up at the end of
+     * the project, and only one instance will be created for each class.
+     *
+     * @param p the project instance. Can be null, in which case the helper is not cached.
+     * @param c The class for which a helper is required.
+     *          Must not be <code>null</code>.
+     *
+     * @return a helper for the specified class
+     */
+    public static IntrospectionHelper getHelper(Project p, Class c) {
+        IntrospectionHelper ih = (IntrospectionHelper) HELPERS.get(c.getName());
+        // If a helper cannot be found, or if the helper is for another
+        // classloader, create a new IH
+        if (ih == null || ih.bean != c) {
+            ih = new IntrospectionHelper(c);
+            if (p != null) {
+                // #30162: do *not* cache this if there is no project, as we
+                // cannot guarantee that the cache will be cleared.
+                HELPERS.put(c.getName(), ih);
+            }
+        }
+        return ih;
+    }
+
+    /**
+     * Sets the named attribute in the given element, which is part of the
+     * given project.
+     *
+     * @param p The project containing the element. This is used when files
+     *          need to be resolved. Must not be <code>null</code>.
+     * @param element The element to set the attribute in. Must not be
+     *                <code>null</code>.
+     * @param attributeName The name of the attribute to set. Must not be
+     *                      <code>null</code>.
+     * @param value The value to set the attribute to. This may be interpreted
+     *              or converted to the necessary type if the setter method
+     *              doesn't accept an object of the supplied type.
+     *
+     * @exception BuildException if the introspected class doesn't support
+     *                           the given attribute, or if the setting
+     *                           method fails.
+     */
+    public void setAttribute(Project p, Object element, String attributeName,
+            Object value) throws BuildException {
+        AttributeSetter as = (AttributeSetter) attributeSetters.get(
+                attributeName.toLowerCase(Locale.US));
+        if (as == null && value != null) {
+            if (element instanceof DynamicAttributeNS) {
+                DynamicAttributeNS dc = (DynamicAttributeNS) element;
+                String uriPlusPrefix = ProjectHelper.extractUriFromComponentName(attributeName);
+                String uri = ProjectHelper.extractUriFromComponentName(uriPlusPrefix);
+                String localName = ProjectHelper.extractNameFromComponentName(attributeName);
+                String qName = "".equals(uri) ? localName : uri + ":" + localName;
+                dc.setDynamicAttribute(uri, localName, qName, value.toString());
+                return;
+            }
+            if (element instanceof DynamicAttribute) {
+                DynamicAttribute dc = (DynamicAttribute) element;
+                dc.setDynamicAttribute(attributeName.toLowerCase(Locale.US), value.toString());
+                return;
+            }
+            if (attributeName.indexOf(':') >= 0) {
+                return; // Ignore attribute from unknown uri's
+            }
+            String msg = getElementName(p, element)
+                    + " doesn't support the \"" + attributeName + "\" attribute.";
+            throw new UnsupportedAttributeException(msg, attributeName);
+        }
+        try {
+            as.setObject(p, element, value);
+        } catch (IllegalAccessException ie) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ie);
+        } catch (InvocationTargetException ite) {
+            throw extractBuildException(ite);
+        }
+    }
+
+    /**
+     * Sets the named attribute in the given element, which is part of the
+     * given project.
+     *
+     * @param p The project containing the element. This is used when files
+     *          need to be resolved. Must not be <code>null</code>.
+     * @param element The element to set the attribute in. Must not be
+     *                <code>null</code>.
+     * @param attributeName The name of the attribute to set. Must not be
+     *                      <code>null</code>.
+     * @param value The value to set the attribute to. This may be interpreted
+     *              or converted to the necessary type if the setter method
+     *              doesn't just take a string. Must not be <code>null</code>.
+     *
+     * @exception BuildException if the introspected class doesn't support
+     *                           the given attribute, or if the setting
+     *                           method fails.
+     */
+    public void setAttribute(Project p, Object element, String attributeName,
+                             String value) throws BuildException {
+        setAttribute(p, element, attributeName, (Object) value);
+    }
+
+    /**
+     * Adds PCDATA to an element, using the element's
+     * <code>void addText(String)</code> method, if it has one. If no
+     * such method is present, a BuildException is thrown if the
+     * given text contains non-whitespace.
+     *
+     * @param project The project which the element is part of.
+     *                Must not be <code>null</code>.
+     * @param element The element to add the text to.
+     *                Must not be <code>null</code>.
+     * @param text    The text to add.
+     *                Must not be <code>null</code>.
+     *
+     * @exception BuildException if non-whitespace text is provided and no
+     *                           method is available to handle it, or if
+     *                           the handling method fails.
+     */
+    public void addText(Project project, Object element, String text)
+        throws BuildException {
+        if (addText == null) {
+            text = text.trim();
+            // Element doesn't handle text content
+            if (text.length() == 0) {
+                // Only whitespace - ignore
+                return;
+            }
+            // Not whitespace - fail
+            throw new BuildException(project.getElementName(element)
+                    + " doesn't support nested text data (\"" + condenseText(text) + "\").");
+        }
+        try {
+            addText.invoke(element, new Object[] {text});
+        } catch (IllegalAccessException ie) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ie);
+        } catch (InvocationTargetException ite) {
+            throw extractBuildException(ite);
+        }
+    }
+
+    /**
+     * Utility method to throw a NotSupported exception
+     *
+     * @param project the Project instance.
+     * @param parent the object which doesn't support a requested element
+     * @param elementName the name of the Element which is trying to be created.
+     */
+    public void throwNotSupported(Project project, Object parent, String elementName) {
+        String msg = project.getElementName(parent)
+                + " doesn't support the nested \"" + elementName + "\" element.";
+        throw new UnsupportedElementException(msg, elementName);
+    }
+
+    /**
+     * Get the specific NestedCreator for a given project/parent/element combination
+     * @param project ant project
+     * @param parentUri URI of the parent.
+     * @param parent the parent class
+     * @param elementName element to work with. This can contain
+     *  a URI,localname tuple of of the form uri:localname
+     * @param child the bit of XML to work with
+     * @return a nested creator that can handle the child elements.
+     * @throws BuildException if the parent does not support child elements of that name
+     */
+    private NestedCreator getNestedCreator(
+        Project project, String parentUri, Object parent,
+        String elementName, UnknownElement child) throws BuildException {
+
+        String uri = ProjectHelper.extractUriFromComponentName(elementName);
+        String name = ProjectHelper.extractNameFromComponentName(elementName);
+
+        if (uri.equals(ProjectHelper.ANT_CORE_URI)) {
+            uri = "";
+        }
+        if (parentUri.equals(ProjectHelper.ANT_CORE_URI)) {
+            parentUri = "";
+        }
+        NestedCreator nc = null;
+        if (uri.equals(parentUri) || uri.length() == 0) {
+            nc = (NestedCreator) nestedCreators.get(name.toLowerCase(Locale.US));
+        }
+        if (nc == null) {
+            nc = createAddTypeCreator(project, parent, elementName);
+        }
+        if (nc == null && parent instanceof DynamicElementNS) {
+            DynamicElementNS dc = (DynamicElementNS) parent;
+            String qName = child == null ? name : child.getQName();
+            final Object nestedElement = dc.createDynamicElement(
+                    child == null ? "" : child.getNamespace(), name, qName);
+            if (nestedElement != null) {
+                nc = new NestedCreator(null) {
+                    Object create(Project project, Object parent, Object ignore) {
+                        return nestedElement;
+                    }
+                };
+            }
+        }
+        if (nc == null && parent instanceof DynamicElement) {
+            DynamicElement dc = (DynamicElement) parent;
+            final Object nestedElement = dc.createDynamicElement(name.toLowerCase(Locale.US));
+            if (nestedElement != null) {
+                nc = new NestedCreator(null) {
+                    Object create(Project project, Object parent, Object ignore) {
+                        return nestedElement;
+                    }
+                };
+            }
+        }
+        if (nc == null) {
+            throwNotSupported(project, parent, elementName);
+        }
+        return nc;
+    }
+
+    /**
+     * Creates a named nested element. Depending on the results of the
+     * initial introspection, either a method in the given parent instance
+     * or a simple no-arg constructor is used to create an instance of the
+     * specified element type.
+     *
+     * @param project Project to which the parent object belongs.
+     *                Must not be <code>null</code>. If the resulting
+     *                object is an instance of ProjectComponent, its
+     *                Project reference is set to this parameter value.
+     * @param parent  Parent object used to create the instance.
+     *                Must not be <code>null</code>.
+     * @param elementName Name of the element to create an instance of.
+     *                    Must not be <code>null</code>.
+     *
+     * @return an instance of the specified element type
+     * @deprecated since 1.6.x.
+     *             This is not a namespace aware method.
+     *
+     * @exception BuildException if no method is available to create the
+     *                           element instance, or if the creating method fails.
+     */
+    public Object createElement(Project project, Object parent, String elementName)
+            throws BuildException {
+        NestedCreator nc = getNestedCreator(project, "", parent, elementName, null);
+        try {
+            Object nestedElement = nc.create(project, parent, null);
+            if (project != null) {
+                project.setProjectReference(nestedElement);
+            }
+            return nestedElement;
+        } catch (IllegalAccessException ie) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ie);
+        } catch (InstantiationException ine) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ine);
+        } catch (InvocationTargetException ite) {
+            throw extractBuildException(ite);
+        }
+    }
+
+    /**
+     * returns an object that creates and stores an object
+     * for an element of a parent.
+     *
+     * @param project      Project to which the parent object belongs.
+     * @param parentUri    The namespace uri of the parent object.
+     * @param parent       Parent object used to create the creator object to
+     *                     create and store and instance of a subelement.
+     * @param elementName  Name of the element to create an instance of.
+     * @param ue           The unknown element associated with the element.
+     * @return a creator object to create and store the element instance.
+     */
+    public Creator getElementCreator(
+        Project project, String parentUri, Object parent, String elementName, UnknownElement ue) {
+        NestedCreator nc = getNestedCreator(project, parentUri, parent, elementName, ue);
+        return new Creator(project, parent, nc);
+    }
+
+    /**
+     * Indicates whether the introspected class is a dynamic one,
+     * supporting arbitrary nested elements and/or attributes.
+     *
+     * @return <code>true<code> if the introspected class is dynamic;
+     *         <code>false<code> otherwise.
+     * @since Ant 1.6.3
+     *
+     * @see DynamicElement
+     * @see DynamicElementNS
+     */
+    public boolean isDynamic() {
+        return DynamicElement.class.isAssignableFrom(bean)
+                || DynamicElementNS.class.isAssignableFrom(bean);
+    }
+
+    /**
+     * Indicates whether the introspected class is a task container,
+     * supporting arbitrary nested tasks/types.
+     *
+     * @return <code>true<code> if the introspected class is a container;
+     *         <code>false<code> otherwise.
+     * @since Ant 1.6.3
+     *
+     * @see TaskContainer
+     */
+    public boolean isContainer() {
+        return TaskContainer.class.isAssignableFrom(bean);
+    }
+
+    /**
+     * Indicates if this element supports a nested element of the
+     * given name.
+     *
+     * @param elementName the name of the nested element being checked
+     *
+     * @return true if the given nested element is supported
+     */
+    public boolean supportsNestedElement(String elementName) {
+        return supportsNestedElement("", elementName);
+    }
+
+    /**
+     * Indicate if this element supports a nested element of the
+     * given name.
+     *
+     * @param parentUri   the uri of the parent
+     * @param elementName the name of the nested element being checked
+     *
+     * @return true if the given nested element is supported
+     */
+    public boolean supportsNestedElement(String parentUri, String elementName) {
+        if (isDynamic() || addTypeMethods.size() > 0) {
+            return true;
+        }
+        return supportsReflectElement(parentUri, elementName);
+    }
+
+    /**
+     * Check if this element supports a nested element from refection.
+     *
+     * @param parentUri   the uri of the parent
+     * @param elementName the name of the nested element being checked
+     *
+     * @return true if the given nested element is supported
+     * @since Ant 1.8.0
+     */
+    public boolean supportsReflectElement(
+        String parentUri, String elementName) {
+        String name = ProjectHelper.extractNameFromComponentName(elementName);
+        if (!nestedCreators.containsKey(name.toLowerCase(Locale.US))) {
+            return false;
+        }
+        String uri = ProjectHelper.extractUriFromComponentName(elementName);
+        if (uri.equals(ProjectHelper.ANT_CORE_URI)) {
+            uri = "";
+        }
+        if ("".equals(uri)) {
+            return true;
+        }
+        if (parentUri.equals(ProjectHelper.ANT_CORE_URI)) {
+            parentUri = "";
+        }
+        return uri.equals(parentUri);
+    }
+
+    /**
+     * Stores a named nested element using a storage method determined
+     * by the initial introspection. If no appropriate storage method
+     * is available, this method returns immediately.
+     *
+     * @param project Ignored in this implementation.
+     *                May be <code>null</code>.
+     *
+     * @param parent  Parent instance to store the child in.
+     *                Must not be <code>null</code>.
+     *
+     * @param child   Child instance to store in the parent.
+     *                Should not be <code>null</code>.
+     *
+     * @param elementName  Name of the child element to store.
+     *                     May be <code>null</code>, in which case
+     *                     this method returns immediately.
+     *
+     * @exception BuildException if the storage method fails.
+     */
+    public void storeElement(Project project, Object parent, Object child,
+        String elementName) throws BuildException {
+        if (elementName == null) {
+            return;
+        }
+        NestedCreator ns = (NestedCreator) nestedCreators.get(elementName.toLowerCase(Locale.US));
+        if (ns == null) {
+            return;
+        }
+        try {
+            ns.store(parent, child);
+        } catch (IllegalAccessException ie) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ie);
+        } catch (InstantiationException ine) {
+            // impossible as getMethods should only return public methods
+            throw new BuildException(ine);
+        } catch (InvocationTargetException ite) {
+            throw extractBuildException(ite);
+        }
+    }
+
+    /**
+     * Helper method to extract the inner fault from an {@link InvocationTargetException}, and turn
+     * it into a BuildException. If it is already a BuildException, it is type cast and returned; if
+     * not a new BuildException is created containing the child as nested text.
+     * @param ite
+     * @return the nested exception
+     */
+    private static BuildException extractBuildException(InvocationTargetException ite) {
+        Throwable t = ite.getTargetException();
+        if (t instanceof BuildException) {
+            return (BuildException) t;
+        }
+        return new BuildException(t);
+    }
+
+    /**
+     * Returns the type of a named nested element.
+     *
+     * @param elementName The name of the element to find the type of.
+     *                    Must not be <code>null</code>.
+     *
+     * @return the type of the nested element with the specified name.
+     *         This will never be <code>null</code>.
+     *
+     * @exception BuildException if the introspected class does not
+     *                           support the named nested element.
+     */
+    public Class getElementType(String elementName) throws BuildException {
+        Class nt = (Class) nestedTypes.get(elementName);
+        if (nt == null) {
+            throw new UnsupportedElementException("Class "
+                    + bean.getName() + " doesn't support the nested \""
+                    + elementName + "\" element.", elementName);
+        }
+        return nt;
+    }
+
+    /**
+     * Returns the type of a named attribute.
+     *
+     * @param attributeName The name of the attribute to find the type of.
+     *                      Must not be <code>null</code>.
+     *
+     * @return the type of the attribute with the specified name.
+     *         This will never be <code>null</code>.
+     *
+     * @exception BuildException if the introspected class does not
+     *                           support the named attribute.
+     */
+    public Class getAttributeType(String attributeName) throws BuildException {
+        Class at = (Class) attributeTypes.get(attributeName);
+        if (at == null) {
+            throw new UnsupportedAttributeException("Class "
+                    + bean.getName() + " doesn't support the \""
+                    + attributeName + "\" attribute.", attributeName);
+        }
+        return at;
+    }
+
+    /**
+     * Returns the addText method when the introspected
+     * class supports nested text.
+     *
+     * @return the method on this introspected class that adds nested text.
+     *         Cannot be <code>null</code>.
+     * @throws BuildException if the introspected class does not
+     *         support the nested text.
+     * @since Ant 1.6.3
+     */
+    public Method getAddTextMethod() throws BuildException {
+        if (!supportsCharacters()) {
+            throw new BuildException("Class " + bean.getName()
+                    + " doesn't support nested text data.");
+        }
+        return addText;
+    }
+
+    /**
+     * Returns the adder or creator method of a named nested element.
+     *
+     * @param  elementName The name of the attribute to find the setter
+     *         method of. Must not be <code>null</code>.
+     * @return the method on this introspected class that adds or creates this
+     *         nested element. Can be <code>null</code> when the introspected
+     *         class is a dynamic configurator!
+     * @throws BuildException if the introspected class does not
+     *         support the named nested element.
+     * @since Ant 1.6.3
+     */
+    public Method getElementMethod(String elementName) throws BuildException {
+        Object creator = nestedCreators.get(elementName);
+        if (creator == null) {
+            throw new UnsupportedElementException("Class "
+                    + bean.getName() + " doesn't support the nested \""
+                    + elementName + "\" element.", elementName);
+        }
+        return ((NestedCreator) creator).method;
+    }
+
+    /**
+     * Returns the setter method of a named attribute.
+     *
+     * @param  attributeName The name of the attribute to find the setter
+     *         method of. Must not be <code>null</code>.
+     * @return the method on this introspected class that sets this attribute.
+     *         This will never be <code>null</code>.
+     * @throws BuildException if the introspected class does not
+     *         support the named attribute.
+     * @since Ant 1.6.3
+     */
+    public Method getAttributeMethod(String attributeName) throws BuildException {
+        Object setter = attributeSetters.get(attributeName);
+        if (setter == null) {
+            throw new UnsupportedAttributeException("Class "
+                    + bean.getName() + " doesn't support the \""
+                    + attributeName + "\" attribute.", attributeName);
+        }
+        return ((AttributeSetter) setter).method;
+    }
+
+    /**
+     * Returns whether or not the introspected class supports PCDATA.
+     *
+     * @return whether or not the introspected class supports PCDATA.
+     */
+    public boolean supportsCharacters() {
+        return addText != null;
+    }
+
+    /**
+     * Returns an enumeration of the names of the attributes supported by the introspected class.
+     *
+     * @return an enumeration of the names of the attributes supported by the introspected class.
+     * @see #getAttributeMap
+     */
+    public Enumeration getAttributes() {
+        return attributeSetters.keys();
+    }
+
+    /**
+     * Returns a read-only map of attributes supported by the introspected class.
+     *
+     * @return an attribute name to attribute <code>Class</code>
+     *         unmodifiable map. Can be empty, but never <code>null</code>.
+     * @since Ant 1.6.3
+     */
+    public Map getAttributeMap() {
+        return attributeTypes.isEmpty()
+            ? Collections.EMPTY_MAP : Collections.unmodifiableMap(attributeTypes);
+    }
+
+    /**
+     * Returns an enumeration of the names of the nested elements supported
+     * by the introspected class.
+     *
+     * @return an enumeration of the names of the nested elements supported
+     *         by the introspected class.
+     * @see #getNestedElementMap
+     */
+    public Enumeration getNestedElements() {
+        return nestedTypes.keys();
+    }
+
+    /**
+     * Returns a read-only map of nested elements supported
+     * by the introspected class.
+     *
+     * @return a nested-element name to nested-element <code>Class</code>
+     *         unmodifiable map. Can be empty, but never <code>null</code>.
+     * @since Ant 1.6.3
+     */
+    public Map getNestedElementMap() {
+        return nestedTypes.isEmpty()
+            ? Collections.EMPTY_MAP : Collections.unmodifiableMap(nestedTypes);
+    }
+
+    /**
+     * Returns a read-only list of extension points supported
+     * by the introspected class.
+     * <p>
+     * A task/type or nested element with void methods named <code>add()<code>
+     * or <code>addConfigured()</code>, taking a single class or interface
+     * argument, supports extensions point. This method returns the list of
+     * all these <em>void add[Configured](type)</em> methods.
+     *
+     * @return a list of void, single argument add() or addConfigured()
+     *         <code>Method<code>s of all supported extension points.
+     *         These methods are sorted such that if the argument type of a
+     *         method derives from another type also an argument of a method
+     *         of this list, the method with the most derived argument will
+     *         always appear first. Can be empty, but never <code>null</code>.
+     * @since Ant 1.6.3
+     */
+    public List getExtensionPoints() {
+        return addTypeMethods.isEmpty()
+                ? Collections.EMPTY_LIST : Collections.unmodifiableList(addTypeMethods);
+    }
+
+    /**
+     * Creates an implementation of AttributeSetter for the given
+     * attribute type. Conversions (where necessary) are automatically
+     * made for the following types:
+     * <ul>
+     * <li>String (left as it is)
+     * <li>Character/char (first character is used)
+     * <li>Boolean/boolean
+     * ({@link Project#toBoolean(String) Project.toBoolean(String)} is used)
+     * <li>Class (Class.forName is used)
+     * <li>File (resolved relative to the appropriate project)
+     * <li>Path (resolve relative to the appropriate project)
+     * <li>EnumeratedAttribute (uses its own
+     * {@link EnumeratedAttribute#setValue(String) setValue} method)
+     * <li>Other primitive types (wrapper classes are used with constructors
+     * taking String)
+     * </ul>
+     *
+     * If none of the above covers the given parameters, a constructor for the
+     * appropriate class taking a String parameter is used if it is available.
+     *
+     * @param m The method to invoke on the bean when the setter is invoked.
+     *          Must not be <code>null</code>.
+     * @param arg The type of the single argument of the bean's method.
+     *            Must not be <code>null</code>.
+     * @param attrName the name of the attribute for which the setter is being
+     *                 created.
+     *
+     * @return an appropriate AttributeSetter instance, or <code>null</code>
+     *         if no appropriate conversion is available.
+     */
+    private AttributeSetter createAttributeSetter(final Method m,
+                                                  Class arg,
+                                                  final String attrName) {
+        // use wrappers for primitive classes, e.g. int and
+        // Integer are treated identically
+        final Class reflectedArg = PRIMITIVE_TYPE_MAP.containsKey(arg)
+            ? (Class) PRIMITIVE_TYPE_MAP.get(arg) : arg;
+
+        // Object.class - it gets handled differently by AttributeSetter
+        if (java.lang.Object.class == reflectedArg) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException,
+                    IllegalAccessException {
+                    throw new BuildException(
+                        "Internal ant problem - this should not get called");
+                }
+            };
+        }
+        // simplest case - setAttribute expects String
+        if (java.lang.String.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException {
+                    m.invoke(parent, (Object[]) new String[] {value});
+                }
+            };
+        }
+        // char and Character get special treatment - take the first character
+        if (java.lang.Character.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException {
+                    if (value.length() == 0) {
+                        throw new BuildException("The value \"\" is not a "
+                                + "legal value for attribute \"" + attrName + "\"");
+                    }
+                    m.invoke(parent, (Object[]) new Character[] {new Character(value.charAt(0))});
+                }
+            };
+        }
+        // boolean and Boolean get special treatment because we have a nice method in Project
+        if (java.lang.Boolean.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException {
+                    m.invoke(parent, (Object[]) new Boolean[] {
+                            Project.toBoolean(value) ? Boolean.TRUE : Boolean.FALSE });
+                }
+            };
+        }
+        // Class doesn't have a String constructor but a decent factory method
+        if (java.lang.Class.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException, BuildException {
+                    try {
+                        m.invoke(parent, new Object[] {Class.forName(value)});
+                    } catch (ClassNotFoundException ce) {
+                        throw new BuildException(ce);
+                    }
+                }
+            };
+        }
+        // resolve relative paths through Project
+        if (java.io.File.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException {
+                    m.invoke(parent, new Object[] {p.resolveFile(value)});
+                }
+            };
+        }
+        // EnumeratedAttributes have their own helper class
+        if (EnumeratedAttribute.class.isAssignableFrom(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException, BuildException {
+                    try {
+                        EnumeratedAttribute ea = (EnumeratedAttribute) reflectedArg.newInstance();
+                        ea.setValue(value);
+                        m.invoke(parent, new Object[] {ea});
+                    } catch (InstantiationException ie) {
+                        throw new BuildException(ie);
+                    }
+                }
+            };
+        }
+
+        AttributeSetter setter = getEnumSetter(reflectedArg, m, arg);
+        if (setter != null) {
+            return setter;
+        }
+
+        if (java.lang.Long.class.equals(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                        throws InvocationTargetException, IllegalAccessException, BuildException {
+                    try {
+                        m.invoke(parent, new Object[] {
+                                new Long(StringUtils.parseHumanSizes(value)) });
+                    } catch (InvocationTargetException e) {
+                        throw e;
+                    } catch (IllegalAccessException e) {
+                        throw e;
+                    } catch (Exception e) {
+                        throw new BuildException(e);
+                    }
+                }
+            };
+        }
+        // worst case. look for a public String constructor and use it
+        // also supports new Whatever(Project, String) as for Path or Reference
+        // This is used (deliberately) for all primitives/wrappers other than
+        // char, boolean, and long.
+        boolean includeProject;
+        Constructor c;
+        try {
+            // First try with Project.
+            c = reflectedArg.getConstructor(new Class[] {Project.class, String.class});
+            includeProject = true;
+        } catch (NoSuchMethodException nme) {
+            // OK, try without.
+            try {
+                c = reflectedArg.getConstructor(new Class[] {String.class});
+                includeProject = false;
+            } catch (NoSuchMethodException nme2) {
+                // Well, no matching constructor.
+                return null;
+            }
+        }
+        final boolean finalIncludeProject = includeProject;
+        final Constructor finalConstructor = c;
+
+        return new AttributeSetter(m, arg) {
+            public void set(Project p, Object parent, String value)
+                    throws InvocationTargetException, IllegalAccessException, BuildException {
+                try {
+                    Object[] args = finalIncludeProject
+                            ? new Object[] {p, value} : new Object[] {value};
+
+                    Object attribute = finalConstructor.newInstance(args);
+                    if (p != null) {
+                        p.setProjectReference(attribute);
+                    }
+                    m.invoke(parent, new Object[] {attribute});
+                } catch (InstantiationException ie) {
+                    throw new BuildException(ie);
+                }
+            }
+        };
+    }
+
+    private AttributeSetter getEnumSetter(
+        final Class reflectedArg, final Method m, Class arg) {
+        Class enumClass = null;
+        try {
+            enumClass = Class.forName("java.lang.Enum");
+        } catch (ClassNotFoundException e) {
+            //ignore
+        }
+        if (enumClass != null && enumClass.isAssignableFrom(reflectedArg)) {
+            return new AttributeSetter(m, arg) {
+                public void set(Project p, Object parent, String value)
+                    throws InvocationTargetException, IllegalAccessException,
+                    BuildException {
+                    try {
+                        m.invoke(
+                            parent, new Object[] {
+                                reflectedArg.getMethod(
+                                    "valueOf", new Class[] {String.class}).
+                                invoke(null, new Object[] {value})});
+                    } catch (InvocationTargetException x) {
+                        //there is specific logic here for the value
+                        // being out of the allowed set of enumerations.
+                        if (x.getTargetException() instanceof IllegalArgumentException) {
+                            throw new BuildException(
+                                "'" + value + "' is not a permitted value for "
+                                + reflectedArg.getName());
+                        }
+                        //only if the exception is not an IllegalArgument do we
+                        // request the
+                        //BuildException via extractBuildException():
+                        throw extractBuildException(x);
+                    } catch (Exception x) {
+                        //any other failure of invoke() to work.
+                        throw new BuildException(x);
+                    }
+                }
+            };
+        }
+        return null;
+    }
+
+    /**
+     * Returns a description of the type of the given element in
+     * relation to a given project. This is used for logging purposes
+     * when the element is asked to cope with some data it has no way of handling.
+     *
+     * @param project The project the element is defined in. Must not be <code>null</code>.
+     *
+     * @param element The element to describe. Must not be <code>null</code>.
+     *
+     * @return a description of the element type
+     */
+    private String getElementName(Project project, Object element) {
+        return project.getElementName(element);
+    }
+
+    /**
+     * Extracts the name of a property from a method name by subtracting
+     * a given prefix and converting into lower case. It is up to calling
+     * code to make sure the method name does actually begin with the
+     * specified prefix - no checking is done in this method.
+     *
+     * @param methodName The name of the method in question. Must not be <code>null</code>.
+     * @param prefix     The prefix to remove. Must not be <code>null</code>.
+     *
+     * @return the lower-cased method name with the prefix removed.
+     */
+    private static String getPropertyName(String methodName, String prefix) {
+        return methodName.substring(prefix.length()).toLowerCase(Locale.US);
+    }
+
+    /**
+     * creator - allows use of create/store external
+     * to IntrospectionHelper.
+     * The class is final as it has a private constructor.
+     */
+    public static final class Creator {
+        private NestedCreator nestedCreator;
+        private Object parent;
+        private Project project;
+        private Object nestedObject;
+        private String polyType;
+
+        /**
+         * Creates a new Creator instance.
+         * This object is given to the UnknownElement to create
+         * objects for sub-elements. UnknownElement calls
+         * create to create an object, the object then gets
+         * configured and then UnknownElement calls store.
+         * SetPolyType may be used to override the type used
+         * to create the object with. SetPolyType gets called before create.
+         *
+         * @param project the current project
+         * @param parent  the parent object to create the object in
+         * @param nestedCreator the nested creator object to use
+         */
+        private Creator(Project project, Object parent, NestedCreator nestedCreator) {
+            this.project = project;
+            this.parent = parent;
+            this.nestedCreator = nestedCreator;
+        }
+
+        /**
+         * Used to override the class used to create the object.
+         *
+         * @param polyType a ant component type name
+         */
+        public void setPolyType(String polyType) {
+            this.polyType = polyType;
+        }
+
+        /**
+         * Create an object using this creator, which is determined by introspection.
+         *
+         * @return the created object
+         */
+        public Object create() {
+            if (polyType != null) {
+                if (!nestedCreator.isPolyMorphic()) {
+                    throw new BuildException(
+                            "Not allowed to use the polymorphic form for this element");
+                }
+                ComponentHelper helper = ComponentHelper.getComponentHelper(project);
+                nestedObject = helper.createComponent(polyType);
+                if (nestedObject == null) {
+                    throw new BuildException("Unable to create object of type " + polyType);
+                }
+            }
+            try {
+                nestedObject = nestedCreator.create(project, parent, nestedObject);
+                if (project != null) {
+                    project.setProjectReference(nestedObject);
+                }
+                return nestedObject;
+            } catch (IllegalAccessException ex) {
+                throw new BuildException(ex);
+            } catch (InstantiationException ex) {
+                throw new BuildException(ex);
+            } catch (IllegalArgumentException ex) {
+                if (polyType == null) {
+                    throw ex;
+                }
+                throw new BuildException("Invalid type used " + polyType);
+            } catch (InvocationTargetException ex) {
+                throw extractBuildException(ex);
+            }
+        }
+
+        /**
+         * @return the real object (used currently only for presetdef).
+         */
+        public Object getRealObject() {
+            return nestedCreator.getRealObject();
+        }
+
+        /**
+         * Stores the nested element object using a storage method determined by introspection.
+         *
+         */
+        public void store() {
+            try {
+                nestedCreator.store(parent, nestedObject);
+            } catch (IllegalAccessException ex) {
+                throw new BuildException(ex);
+            } catch (InstantiationException ex) {
+                throw new BuildException(ex);
+            } catch (IllegalArgumentException ex) {
+                if (polyType == null) {
+                    throw ex;
+                }
+                throw new BuildException("Invalid type used " + polyType);
+            } catch (InvocationTargetException ex) {
+                throw extractBuildException(ex);
+            }
+        }
+    }
+
+    /**
+     * Internal interface used to create nested elements. Not documented
+     * in detail for reasons of source code readability.
+     */
+    private abstract static class NestedCreator {
+        private Method method; // the method called to add/create the nested element
+
+        protected NestedCreator(Method m) {
+            method = m;
+        }
+        Method getMethod() {
+            return method;
+        }
+        boolean isPolyMorphic() {
+            return false;
+        }
+        Object getRealObject() {
+            return null;
+        }
+        abstract Object create(Project project, Object parent, Object child)
+                throws InvocationTargetException, IllegalAccessException, InstantiationException;
+
+        void store(Object parent, Object child)
+                 throws InvocationTargetException, IllegalAccessException, InstantiationException {
+            // DO NOTHING
+        }
+    }
+
+    private static class CreateNestedCreator extends NestedCreator {
+        CreateNestedCreator(Method m) {
+            super(m);
+        }
+
+        Object create(Project project, Object parent, Object ignore)
+                throws InvocationTargetException, IllegalAccessException {
+            return getMethod().invoke(parent, new Object[] {});
+        }
+    }
+
+    /** Version to use for addXXX and addConfiguredXXX */
+    private static class AddNestedCreator extends NestedCreator {
+
+        static final int ADD = 1;
+        static final int ADD_CONFIGURED = 2;
+
+        private Constructor constructor;
+        private int behavior; // ADD or ADD_CONFIGURED
+
+        AddNestedCreator(Method m, Constructor c, int behavior) {
+            super(m);
+            this.constructor = c;
+            this.behavior = behavior;
+        }
+
+        boolean isPolyMorphic() {
+            return true;
+        }
+
+        Object create(Project project, Object parent, Object child)
+                throws InvocationTargetException, IllegalAccessException, InstantiationException {
+            if (child == null) {
+                child = constructor.newInstance(
+                        constructor.getParameterTypes().length == 0
+                                ? new Object[] {} : new Object[] {project});
+            }
+            if (child instanceof PreSetDef.PreSetDefinition) {
+                child = ((PreSetDef.PreSetDefinition) child).createObject(project);
+            }
+            if (behavior == ADD) {
+                istore(parent, child);
+            }
+            return child;
+        }
+
+        void store(Object parent, Object child)
+                throws InvocationTargetException, IllegalAccessException, InstantiationException {
+            if (behavior == ADD_CONFIGURED) {
+                istore(parent, child);
+            }
+        }
+
+        private void istore(Object parent, Object child)
+                throws InvocationTargetException, IllegalAccessException, InstantiationException {
+            getMethod().invoke(parent, new Object[] {child});
+        }
+    }
+
+    /**
+     * Internal interface used to setting element attributes. Not documented
+     * in detail for reasons of source code readability.
+     */
+    private abstract static class AttributeSetter {
+        private Method method; // the method called to set the attribute
+        private Class type;
+        protected AttributeSetter(Method m, Class type) {
+            method = m;
+            this.type = type;
+        }
+        void setObject(Project p, Object parent, Object value)
+                throws InvocationTargetException, IllegalAccessException, BuildException {
+            if (type != null) {
+                Class useType = type;
+                if (type.isPrimitive()) {
+                    if (value == null) {
+                        throw new BuildException(
+                            "Attempt to set primitive "
+                            + getPropertyName(method.getName(), "set")
+                            + " to null on " + parent);
+                    }
+                    useType = (Class) PRIMITIVE_TYPE_MAP.get(type);
+                }
+                if (value == null || useType.isInstance(value)) {
+                    method.invoke(parent, new Object[] {value});
+                    return;
+                }
+            }
+            set(p, parent, value.toString());
+        }
+        abstract void set(Project p, Object parent, String value)
+                throws InvocationTargetException, IllegalAccessException, BuildException;
+    }
+
+    /**
+     * Clears the static cache of on build finished.
+     */
+    public static void clearCache() {
+        HELPERS.clear();
+    }
+
+    /**
+     * Create a NestedCreator for the given element.
+     * @param project owning project
+     * @param parent Parent object used to create the instance.
+     * @param elementName name of the element
+     * @return a nested creator, or null if there is no component of the given name, or it
+     *        has no matching add type methods
+     * @throws BuildException
+     */
+    private NestedCreator createAddTypeCreator(
+            Project project, Object parent, String elementName) throws BuildException {
+        if (addTypeMethods.size() == 0) {
+            return null;
+        }
+        ComponentHelper helper = ComponentHelper.getComponentHelper(project);
+
+        MethodAndObject restricted =  createRestricted(
+            helper, elementName, addTypeMethods);
+        MethodAndObject topLevel = createTopLevel(
+            helper, elementName, addTypeMethods);
+
+        if (restricted == null && topLevel == null) {
+            return null;
+        }
+
+        if (restricted != null && topLevel != null) {
+            throw new BuildException(
+                "ambiguous: type and component definitions for "
+                + elementName);
+        }
+
+        MethodAndObject methodAndObject
+            = restricted != null ? restricted : topLevel;
+
+        Object rObject = methodAndObject.object;
+        if (methodAndObject.object instanceof PreSetDef.PreSetDefinition) {
+            rObject = ((PreSetDef.PreSetDefinition) methodAndObject.object)
+                .createObject(project);
+        }
+        final Object nestedObject = methodAndObject.object;
+        final Object realObject = rObject;
+
+        return new NestedCreator(methodAndObject.method) {
+            Object create(Project project, Object parent, Object ignore)
+                    throws InvocationTargetException, IllegalAccessException {
+                if (!getMethod().getName().endsWith("Configured")) {
+                    getMethod().invoke(parent, new Object[] {realObject});
+                }
+                return nestedObject;
+            }
+
+            Object getRealObject() {
+                return realObject;
+            }
+
+            void store(Object parent, Object child) throws InvocationTargetException,
+                    IllegalAccessException, InstantiationException {
+                if (getMethod().getName().endsWith("Configured")) {
+                    getMethod().invoke(parent, new Object[] {realObject});
+                }
+            }
+        };
+    }
+
+    /**
+     * Inserts an add or addConfigured method into
+     * the addTypeMethods array. The array is
+     * ordered so that the more derived classes are first.
+     * If both add and addConfigured are present, the addConfigured will take priority.
+     * @param method the <code>Method</code> to insert.
+     */
+    private void insertAddTypeMethod(Method method) {
+        Class argClass = method.getParameterTypes()[0];
+        for (int c = 0; c < addTypeMethods.size(); ++c) {
+            Method current = (Method) addTypeMethods.get(c);
+            if (current.getParameterTypes()[0].equals(argClass)) {
+                if (method.getName().equals("addConfigured")) {
+                    // add configured replaces the add method
+                    addTypeMethods.set(c, method);
+                }
+                return; // Already present
+            }
+            if (current.getParameterTypes()[0].isAssignableFrom(argClass)) {
+                addTypeMethods.add(c, method);
+                return; // higher derived
+            }
+        }
+        addTypeMethods.add(method);
+    }
+
+    /**
+     * Search the list of methods to find the first method
+     * that has a parameter that accepts the nested element object.
+     * @param paramClass the <code>Class</code> type to search for.
+     * @param methods the <code>List</code> of methods to search.
+     * @return a matching <code>Method</code>; null if none found.
+     */
+    private Method findMatchingMethod(Class paramClass, List methods) {
+        if (paramClass == null) {
+            return null;
+        }
+        Class matchedClass = null;
+        Method matchedMethod = null;
+
+        for (int i = 0; i < methods.size(); ++i) {
+            Method method = (Method) methods.get(i);
+            Class  methodClass = method.getParameterTypes()[0];
+            if (methodClass.isAssignableFrom(paramClass)) {
+                if (matchedClass == null) {
+                    matchedClass = methodClass;
+                    matchedMethod = method;
+                } else if (!methodClass.isAssignableFrom(matchedClass)) {
+                    throw new BuildException("ambiguous: types " + matchedClass.getName() + " and "
+                            + methodClass.getName() + " match " + paramClass.getName());
+                }
+            }
+        }
+        return matchedMethod;
+    }
+
+    private String condenseText(final String text) {
+        if (text.length() <= MAX_REPORT_NESTED_TEXT) {
+            return text;
+        }
+        int ends = (MAX_REPORT_NESTED_TEXT - ELLIPSIS.length()) / 2;
+        return new StringBuffer(text).replace(ends, text.length() - ends, ELLIPSIS).toString();
+    }
+
+
+    private class MethodAndObject {
+        private Method method;
+        private Object object;
+        public MethodAndObject(Method method, Object object) {
+            this.method = method;
+            this.object = object;
+        }
+    }
+
+    /**
+     *
+     */
+    private AntTypeDefinition findRestrictedDefinition(
+        ComponentHelper helper, String componentName, List methods) {
+        AntTypeDefinition definition = null;
+        Class matchedDefinitionClass = null;
+
+        List definitions = helper.getRestrictedDefinitions(componentName);
+        if (definitions == null) {
+            return null;
+        }
+        for (int i = 0; i < definitions.size(); ++i) {
+            AntTypeDefinition d = (AntTypeDefinition) definitions.get(i);
+            Class exposedClass = d.getExposedClass(helper.getProject());
+            if (exposedClass == null) {
+                continue;
+            }
+            Method method  = findMatchingMethod(exposedClass, methods);
+            if (method == null) {
+                continue;
+            }
+            if (matchedDefinitionClass != null) {
+                throw new BuildException(
+                    "ambiguous: restricted definitions for "
+                    + componentName + " "
+                    + matchedDefinitionClass + " and " + exposedClass);
+            }
+            matchedDefinitionClass = exposedClass;
+            definition = d;
+        }
+        return definition;
+    }
+
+    private MethodAndObject createRestricted(
+        ComponentHelper helper, String elementName, List addTypeMethods) {
+
+        Project project = helper.getProject();
+
+        AntTypeDefinition restrictedDefinition =
+            findRestrictedDefinition(helper, elementName, addTypeMethods);
+
+        if (restrictedDefinition == null) {
+            return null;
+        }
+
+        Method addMethod = findMatchingMethod(
+            restrictedDefinition.getExposedClass(project), addTypeMethods);
+        if (addMethod == null) {
+            throw new BuildException(
+                "Ant Internal Error - contract mismatch for "
+                + elementName);
+        }
+        Object addedObject = restrictedDefinition.create(project);
+        if (addedObject == null) {
+            throw new BuildException(
+                "Failed to create object " + elementName
+                + " of type " + restrictedDefinition.getTypeClass(project));
+        }
+        return new MethodAndObject(addMethod, addedObject);
+    }
+
+    private MethodAndObject createTopLevel(
+        ComponentHelper helper, String elementName, List methods) {
+        Class clazz = helper.getComponentClass(elementName);
+        if (clazz == null) {
+            return null;
+        }
+        Method addMethod = findMatchingMethod(clazz, addTypeMethods);
+        if (addMethod == null) {
+            return null;
+        }
+        Object addedObject = helper.createComponent(elementName);
+        return new MethodAndObject(addMethod, addedObject);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/Location.java b/trunk/src/main/org/apache/tools/ant/Location.java
new file mode 100644
index 0000000..7ad3119
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Location.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.Serializable;
+import org.apache.tools.ant.util.FileUtils;
+import org.xml.sax.Locator;
+
+/**
+ * Stores the location of a piece of text within a file (file name,
+ * line number and column number). Note that the column number is
+ * currently ignored.
+ *
+ */
+public class Location implements Serializable {
+
+    /** Name of the file. */
+    private String fileName;
+    /** Line number within the file. */
+    private int lineNumber;
+    /** Column number within the file. */
+    private int columnNumber;
+
+    /** Location to use when one is needed but no information is available */
+    public static final Location UNKNOWN_LOCATION = new Location();
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Creates an "unknown" location.
+     */
+    private Location() {
+        this(null, 0, 0);
+    }
+
+    /**
+     * Creates a location consisting of a file name but no line number or
+     * column number.
+     *
+     * @param fileName The name of the file. May be <code>null</code>,
+     *                 in which case the location is equivalent to
+     *                 {@link #UNKNOWN_LOCATION UNKNOWN_LOCATION}.
+     */
+    public Location(String fileName) {
+        this(fileName, 0, 0);
+    }
+
+    /**
+     * Creates a location from the SAX locator using the system ID as
+     * the filename.
+     *
+     * @param loc Must not be <code>null</code>.
+     *
+     * @since Ant 1.6
+     */
+    public Location(Locator loc) {
+        this(loc.getSystemId(), loc.getLineNumber(), loc.getColumnNumber());
+    }
+
+    /**
+     * Creates a location consisting of a file name, line number and
+     * column number.
+     *
+     * @param fileName The name of the file. May be <code>null</code>,
+     *                 in which case the location is equivalent to
+     *                 {@link #UNKNOWN_LOCATION UNKNOWN_LOCATION}.
+     *
+     * @param lineNumber Line number within the file. Use 0 for unknown
+     *                   positions within a file.
+     * @param columnNumber Column number within the line.
+     */
+    public Location(String fileName, int lineNumber, int columnNumber) {
+        if (fileName != null && fileName.startsWith("file:")) {
+            this.fileName = FILE_UTILS.fromURI(fileName);
+        } else {
+            this.fileName = fileName;
+        }
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    }
+
+    /**
+     * @return the filename portion of the location
+     * @since Ant 1.6
+     */
+    public String getFileName() {
+        return fileName;
+    }
+
+    /**
+     * @return the line number
+     * @since Ant 1.6
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    /**
+     * @return the column number
+     * @since Ant 1.7
+     */
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    /**
+     * Returns the file name, line number, a colon and a trailing space.
+     * An error message can be appended easily. For unknown locations, an
+     * empty string is returned.
+     *
+     * @return a String of the form <code>"fileName:lineNumber: "</code>
+     *         if both file name and line number are known,
+     *         <code>"fileName: "</code> if only the file name is known,
+     *         and the empty string for unknown locations.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+
+        if (fileName != null) {
+            buf.append(fileName);
+
+            if (lineNumber != 0) {
+                buf.append(":");
+                buf.append(lineNumber);
+            }
+
+            buf.append(": ");
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Equality operation.
+     * @param other the object to compare to.
+     * @return true if the other object contains the same information
+     *              as this object.
+     * @since Ant 1.6.3
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (!(other.getClass() == getClass())) {
+            return false;
+        }
+        return toString().equals(other.toString());
+    }
+
+    /**
+     * Hash operation.
+     * @return a hash code value for this location.
+     * @since Ant 1.6.3
+     */
+    public int hashCode() {
+        return toString().hashCode();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/MagicNames.java b/trunk/src/main/org/apache/tools/ant/MagicNames.java
new file mode 100644
index 0000000..97f852a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/MagicNames.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.launch.Launcher;
+
+/**
+ * Magic names used within Ant.
+ *
+ * Not all magic names are here yet.
+ *
+ * @since Ant 1.6
+ */
+public final class MagicNames {
+
+    private MagicNames() {
+    }
+
+    /**
+     * prefix for antlib URIs:
+     * {@value}
+     */
+    public static final String ANTLIB_PREFIX = "antlib:";
+
+    /**
+     * Ant version property.
+     * Value: {@value}
+     */
+    public static final String ANT_VERSION = "ant.version";
+
+    /**
+     * System classpath policy.
+     * Value: {@value}
+     */
+    public static final String BUILD_SYSCLASSPATH = "build.sysclasspath";
+
+    /**
+     * The name of the script repository used by the script repo task.
+     * Value {@value}
+     */
+    public static final String SCRIPT_REPOSITORY = "org.apache.ant.scriptrepo";
+
+    /**
+     * The name of the reference to the System Class Loader.
+     * Value {@value}
+     **/
+    public static final String SYSTEM_LOADER_REF = "ant.coreLoader";
+
+    /**
+     * Name of the property which can provide an override of the repository dir.
+     * for the libraries task
+     * Value {@value}
+     */
+    public static final String REPOSITORY_DIR_PROPERTY = "ant.maven.repository.dir";
+
+    /**
+     * Name of the property which can provide an override of the repository URL.
+     * for the libraries task
+     * Value {@value}
+     */
+    public static final String REPOSITORY_URL_PROPERTY = "ant.maven.repository.url";
+
+    /**
+     * name of the resource that taskdefs are stored under.
+     * Value: {@value}
+     */
+    public static final String TASKDEF_PROPERTIES_RESOURCE =
+            "/org/apache/tools/ant/taskdefs/defaults.properties";
+
+    /**
+     * name of the resource that typedefs are stored under.
+     * Value: {@value}
+     */
+    public static final String TYPEDEFS_PROPERTIES_RESOURCE =
+            "/org/apache/tools/ant/types/defaults.properties";
+
+    /**
+     * Reference to the current Ant executor.
+     * Value: {@value}
+     */
+    public static final String ANT_EXECUTOR_REFERENCE = "ant.executor";
+
+    /**
+     * Property defining the classname of an executor.
+     * Value: {@value}
+     */
+    public static final String ANT_EXECUTOR_CLASSNAME = "ant.executor.class";
+
+    /**
+     * property name for basedir of the project.
+     * Value: {@value}
+     */
+    public static final String PROJECT_BASEDIR = "basedir";
+
+    /**
+     * property for ant file name.
+     * Value: {@value}
+     */
+    public static final String ANT_FILE = "ant.file";
+
+    /**
+     * Property used to store the java version ant is running in.
+     * Value: {@value}
+     * @since Ant 1.7
+     */
+    public static final String ANT_JAVA_VERSION = "ant.java.version";
+
+    /**
+     * Property used to store the location of ant.
+     * Value: {@value}
+     * @since Ant 1.7
+     */
+    public static final String ANT_HOME = Launcher.ANTHOME_PROPERTY;
+
+    /**
+     * Property used to store the location of the ant library (typically the ant.jar file.)
+     * Value: {@value}
+     * @since Ant 1.7
+     */
+    public static final String ANT_LIB = "ant.core.lib";
+
+    /**
+     * property for regular expression implementation.
+     * Value: {@value}
+     */
+    public static final String REGEXP_IMPL = "ant.regexp.regexpimpl";
+
+    /**
+     * property that provides the default value for javac's and
+     * javadoc's source attribute.
+     * @since Ant 1.7
+     * Value: {@value}
+     */
+    public static final String BUILD_JAVAC_SOURCE = "ant.build.javac.source";
+
+    /**
+     * property that provides the default value for javac's target attribute.
+     * @since Ant 1.7
+     * Value: {@value}
+     */
+    public static final String BUILD_JAVAC_TARGET = "ant.build.javac.target";
+
+    /**
+     * Name of the magic property that controls classloader reuse.
+     * @since Ant 1.4.
+     * Value: {@value}
+     */
+    public static final String REFID_CLASSPATH_REUSE_LOADER = "ant.reuse.loader";
+
+    /**
+     * Prefix used to store classloader references.
+     * Value: {@value}
+     */
+    public static final String REFID_CLASSPATH_LOADER_PREFIX = "ant.loader.";
+
+    /**
+     * Reference used to store the property helper.
+     * Value: {@value}
+     */
+    public static final String REFID_PROPERTY_HELPER = "ant.PropertyHelper";
+
+    /**
+     * Name of JVM system property which provides the name of the ProjectHelper class to use.
+     * Value: {@value}
+     */
+    public static final String PROJECT_HELPER_CLASS = "org.apache.tools.ant.ProjectHelper";
+
+    /**
+     * The service identifier in jars which provide ProjectHelper implementations.
+     * Value: {@value}
+     */
+    public static final String PROJECT_HELPER_SERVICE =
+        "META-INF/services/org.apache.tools.ant.ProjectHelper";
+
+    /**
+     * Name of ProjectHelper reference that we add to a project.
+     * Value: {@value}
+     */
+    public static final String REFID_PROJECT_HELPER = "ant.projectHelper";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/Main.java b/trunk/src/main/org/apache/tools/ant/Main.java
new file mode 100644
index 0000000..00fb063
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Main.java
@@ -0,0 +1,1138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.launch.AntMain;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ProxySetup;
+
+
+/**
+ * Command line entry point into Ant. This class is entered via the
+ * canonical `public static void main` entry point and reads the
+ * command line arguments. It then assembles and executes an Ant
+ * project.
+ * <p>
+ * If you integrating Ant into some other tool, this is not the class
+ * to use as an entry point. Please see the source code of this
+ * class to see how it manipulates the Ant project classes.
+ *
+ */
+public class Main implements AntMain {
+
+    /**
+     * A Set of args are are handled by the launcher and should
+     * not be seen by Main.
+     */
+    private static final Set LAUNCH_COMMANDS = new HashSet();
+    static {
+        LAUNCH_COMMANDS.add("-lib");
+        LAUNCH_COMMANDS.add("-cp");
+        LAUNCH_COMMANDS.add("-noclasspath");
+        LAUNCH_COMMANDS.add("--noclasspath");
+        LAUNCH_COMMANDS.add("-nouserlib");
+        LAUNCH_COMMANDS.add("-main");
+    }
+
+    /** The default build file name. {@value} */
+    public static final String DEFAULT_BUILD_FILENAME = "build.xml";
+
+    /** Our current message output status. Follows Project.MSG_XXX. */
+    private int msgOutputLevel = Project.MSG_INFO;
+
+    /** File that we are using for configuration. */
+    private File buildFile; /* null */
+
+    /** Stream to use for logging. */
+    private static PrintStream out = System.out;
+
+    /** Stream that we are using for logging error messages. */
+    private static PrintStream err = System.err;
+
+    /** The build targets. */
+    private Vector targets = new Vector();
+
+    /** Set of properties that can be used by tasks. */
+    private Properties definedProps = new Properties();
+
+    /** Names of classes to add as listeners to project. */
+    private Vector listeners = new Vector(1);
+
+    /** File names of property files to load on startup. */
+    private Vector propertyFiles = new Vector(1);
+
+    /** Indicates whether this build is to support interactive input */
+    private boolean allowInput = true;
+
+    /** keep going mode */
+    private boolean keepGoingMode = false;
+
+    /**
+     * The Ant logger class. There may be only one logger. It will have
+     * the right to use the 'out' PrintStream. The class must implements the
+     * BuildLogger interface.
+     */
+    private String loggerClassname = null;
+
+    /**
+     * The Ant InputHandler class.  There may be only one input
+     * handler.
+     */
+    private String inputHandlerClassname = null;
+
+    /**
+     * Whether or not output to the log is to be unadorned.
+     */
+    private boolean emacsMode = false;
+
+    /**
+     * Whether or not this instance has successfully been
+     * constructed and is ready to run.
+     */
+    private boolean readyToRun = false;
+
+    /**
+     * Whether or not we should only parse and display the project help
+     * information.
+     */
+    private boolean projectHelp = false;
+
+    /**
+     * Whether or not a logfile is being used. This is used to
+     * check if the output streams must be closed.
+     */
+    private static boolean isLogFileUsed = false;
+
+    /**
+     * optional thread priority
+     */
+    private Integer threadPriority = null;
+
+    /**
+     * proxy flag: default is false
+     */
+    private boolean proxy = false;
+
+    /**
+     * Prints the message of the Throwable if it (the message) is not
+     * <code>null</code>.
+     *
+     * @param t Throwable to print the message of.
+     *          Must not be <code>null</code>.
+     */
+    private static void printMessage(Throwable t) {
+        String message = t.getMessage();
+        if (message != null) {
+            System.err.println(message);
+        }
+    }
+
+    /**
+     * Creates a new instance of this class using the
+     * arguments specified, gives it any extra user properties which have been
+     * specified, and then runs the build using the classloader provided.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     * @param additionalUserProperties Any extra properties to use in this
+     *        build. May be <code>null</code>, which is the equivalent to
+     *        passing in an empty set of properties.
+     * @param coreLoader Classloader used for core classes. May be
+     *        <code>null</code> in which case the system classloader is used.
+     */
+    public static void start(String[] args, Properties additionalUserProperties,
+                             ClassLoader coreLoader) {
+        Main m = new Main();
+        m.startAnt(args, additionalUserProperties, coreLoader);
+    }
+
+    /**
+     * Start Ant
+     * @param args command line args
+     * @param additionalUserProperties properties to set beyond those that
+     *        may be specified on the args list
+     * @param coreLoader - not used
+     *
+     * @since Ant 1.6
+     */
+    public void startAnt(String[] args, Properties additionalUserProperties,
+                         ClassLoader coreLoader) {
+
+        try {
+            Diagnostics.validateVersion();
+            processArgs(args);
+        } catch (Throwable exc) {
+            handleLogfile();
+            printMessage(exc);
+            exit(1);
+            return;
+        }
+
+        if (additionalUserProperties != null) {
+            for (Enumeration e = additionalUserProperties.keys();
+                    e.hasMoreElements();) {
+                String key = (String) e.nextElement();
+                String property = additionalUserProperties.getProperty(key);
+                definedProps.put(key, property);
+            }
+        }
+
+        // expect the worst
+        int exitCode = 1;
+        try {
+            try {
+                runBuild(coreLoader);
+                exitCode = 0;
+            } catch (ExitStatusException ese) {
+                exitCode = ese.getStatus();
+                if (exitCode != 0) {
+                    throw ese;
+                }
+            }
+        } catch (BuildException be) {
+            if (err != System.err) {
+                printMessage(be);
+            }
+        } catch (Throwable exc) {
+            exc.printStackTrace();
+            printMessage(exc);
+        } finally {
+            handleLogfile();
+        }
+        exit(exitCode);
+    }
+
+    /**
+     * This operation is expected to call {@link System#exit(int)}, which
+     * is what the base version does.
+     * However, it is possible to do something else.
+     * @param exitCode code to exit with
+     */
+    protected void exit(int exitCode) {
+        System.exit(exitCode);
+    }
+
+    /**
+     * Close logfiles, if we have been writing to them.
+     *
+     * @since Ant 1.6
+     */
+    private static void handleLogfile() {
+        if (isLogFileUsed) {
+            FileUtils.close(out);
+            FileUtils.close(err);
+        }
+    }
+
+    /**
+     * Command line entry point. This method kicks off the building
+     * of a project object and executes a build using either a given
+     * target or the default target.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     */
+    public static void main(String[] args) {
+        start(args, null, null);
+    }
+
+    /**
+     * Constructor used when creating Main for later arg processing
+     * and startup
+     */
+    public Main() {
+    }
+
+    /**
+     * Sole constructor, which parses and deals with command line
+     * arguments.
+     *
+     * @param args Command line arguments. Must not be <code>null</code>.
+     *
+     * @exception BuildException if the specified build file doesn't exist
+     *                           or is a directory.
+     *
+     * @deprecated since 1.6.x
+     */
+    protected Main(String[] args) throws BuildException {
+        processArgs(args);
+    }
+
+    /**
+     * Process command line arguments.
+     * When ant is started from Launcher, launcher-only arguments do not get
+     * passed through to this routine.
+     *
+     * @param args the command line arguments.
+     *
+     * @since Ant 1.6
+     */
+    private void processArgs(String[] args) {
+        String searchForThis = null;
+        PrintStream logTo = null;
+
+        // cycle through given args
+
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+
+            if (arg.equals("-help") || arg.equals("-h")) {
+                printUsage();
+                return;
+            } else if (arg.equals("-version")) {
+                printVersion();
+                return;
+            } else if (arg.equals("-diagnostics")) {
+                Diagnostics.doReport(System.out);
+                return;
+            } else if (arg.equals("-quiet") || arg.equals("-q")) {
+                msgOutputLevel = Project.MSG_WARN;
+            } else if (arg.equals("-verbose") || arg.equals("-v")) {
+                printVersion();
+                msgOutputLevel = Project.MSG_VERBOSE;
+            } else if (arg.equals("-debug") || arg.equals("-d")) {
+                printVersion();
+                msgOutputLevel = Project.MSG_DEBUG;
+            } else if (arg.equals("-noinput")) {
+                allowInput = false;
+            } else if (arg.equals("-logfile") || arg.equals("-l")) {
+                try {
+                    File logFile = new File(args[i + 1]);
+                    i++;
+                    logTo = new PrintStream(new FileOutputStream(logFile));
+                    isLogFileUsed = true;
+                } catch (IOException ioe) {
+                    String msg = "Cannot write on the specified log file. "
+                        + "Make sure the path exists and you have write "
+                        + "permissions.";
+                    throw new BuildException(msg);
+                } catch (ArrayIndexOutOfBoundsException aioobe) {
+                    String msg = "You must specify a log file when "
+                        + "using the -log argument";
+                    throw new BuildException(msg);
+                }
+            } else if (arg.equals("-buildfile") || arg.equals("-file")
+                       || arg.equals("-f")) {
+                i = handleArgBuildFile(args, i);
+            } else if (arg.equals("-listener")) {
+                i = handleArgListener(args, i);
+            } else if (arg.startsWith("-D")) {
+                i = handleArgDefine(args, i);
+            } else if (arg.equals("-logger")) {
+                i = handleArgLogger(args, i);
+            } else if (arg.equals("-inputhandler")) {
+                i = handleArgInputHandler(args, i);
+            } else if (arg.equals("-emacs") || arg.equals("-e")) {
+                emacsMode = true;
+            } else if (arg.equals("-projecthelp") || arg.equals("-p")) {
+                // set the flag to display the targets and quit
+                projectHelp = true;
+            } else if (arg.equals("-find") || arg.equals("-s")) {
+                // eat up next arg if present, default to build.xml
+                if (i < args.length - 1) {
+                    searchForThis = args[++i];
+                } else {
+                    searchForThis = DEFAULT_BUILD_FILENAME;
+                }
+            } else if (arg.startsWith("-propertyfile")) {
+                i = handleArgPropertyFile(args, i);
+            } else if (arg.equals("-k") || arg.equals("-keep-going")) {
+                keepGoingMode = true;
+            } else if (arg.equals("-nice")) {
+                i = handleArgNice(args, i);
+            } else if (LAUNCH_COMMANDS.contains(arg)) {
+                //catch script/ant mismatch with a meaningful message
+                //we could ignore it, but there are likely to be other
+                //version problems, so we stamp down on the configuration now
+                String msg = "Ant's Main method is being handed "
+                        + "an option " + arg + " that is only for the launcher class."
+                        + "\nThis can be caused by a version mismatch between "
+                        + "the ant script/.bat file and Ant itself.";
+                throw new BuildException(msg);
+            } else if (arg.equals("-autoproxy")) {
+                proxy = true;
+            } else if (arg.startsWith("-")) {
+                // we don't have any more args to recognize!
+                String msg = "Unknown argument: " + arg;
+                System.err.println(msg);
+                printUsage();
+                throw new BuildException("");
+            } else {
+                // if it's no other arg, it may be the target
+                targets.addElement(arg);
+            }
+        }
+
+        // if buildFile was not specified on the command line,
+        if (buildFile == null) {
+            // but -find then search for it
+            if (searchForThis != null) {
+                buildFile = findBuildFile(System.getProperty("user.dir"),
+                                          searchForThis);
+            } else {
+                buildFile = new File(DEFAULT_BUILD_FILENAME);
+            }
+        }
+
+        // make sure buildfile exists
+        if (!buildFile.exists()) {
+            System.out.println("Buildfile: " + buildFile + " does not exist!");
+            throw new BuildException("Build failed");
+        }
+
+        // make sure it's not a directory (this falls into the ultra
+        // paranoid lets check everything category
+
+        if (buildFile.isDirectory()) {
+            System.out.println("What? Buildfile: " + buildFile + " is a dir!");
+            throw new BuildException("Build failed");
+        }
+
+        // Normalize buildFile for re-import detection
+        buildFile =
+            FileUtils.getFileUtils().normalize(buildFile.getAbsolutePath());
+
+        // Load the property files specified by -propertyfile
+        loadPropertyFiles();
+
+        if (msgOutputLevel >= Project.MSG_INFO) {
+            System.out.println("Buildfile: " + buildFile);
+        }
+
+        if (logTo != null) {
+            out = logTo;
+            err = logTo;
+            System.setOut(out);
+            System.setErr(err);
+        }
+        readyToRun = true;
+    }
+
+    // --------------------------------------------------------
+    //    Methods for handling the command line arguments
+    // --------------------------------------------------------
+
+    /** Handle the -buildfile, -file, -f argument */
+    private int handleArgBuildFile(String[] args, int pos) {
+        try {
+            buildFile = new File(
+                args[++pos].replace('/', File.separatorChar));
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must specify a buildfile when using the -buildfile argument");
+        }
+        return pos;
+    }
+
+    /** Handle -listener argument */
+    private int handleArgListener(String[] args, int pos) {
+        try {
+            listeners.addElement(args[pos + 1]);
+            pos++;
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            String msg = "You must specify a classname when "
+                + "using the -listener argument";
+            throw new BuildException(msg);
+        }
+        return pos;
+    }
+
+    /** Handler -D argument */
+    private int handleArgDefine(String[] args, int argPos) {
+        /* Interestingly enough, we get to here when a user
+         * uses -Dname=value. However, in some cases, the OS
+         * goes ahead and parses this out to args
+         *   {"-Dname", "value"}
+         * so instead of parsing on "=", we just make the "-D"
+         * characters go away and skip one argument forward.
+         *
+         * I don't know how to predict when the JDK is going
+         * to help or not, so we simply look for the equals sign.
+         */
+        String arg = args[argPos];
+        String name = arg.substring(2, arg.length());
+        String value = null;
+        int posEq = name.indexOf("=");
+        if (posEq > 0) {
+            value = name.substring(posEq + 1);
+            name = name.substring(0, posEq);
+        } else if (argPos < args.length - 1) {
+            value = args[++argPos];
+        } else {
+            throw new BuildException("Missing value for property "
+                                     + name);
+        }
+        definedProps.put(name, value);
+        return argPos;
+    }
+
+    /** Handle the -logger argument. */
+    private int handleArgLogger(String[] args, int pos) {
+        if (loggerClassname != null) {
+            throw new BuildException(
+                "Only one logger class may be specified.");
+        }
+        try {
+            loggerClassname = args[++pos];
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must specify a classname when using the -logger argument");
+        }
+        return pos;
+    }
+
+    /** Handle the -inputhandler argument. */
+    private int handleArgInputHandler(String[] args, int pos) {
+        if (inputHandlerClassname != null) {
+            throw new BuildException("Only one input handler class may "
+                                     + "be specified.");
+        }
+        try {
+            inputHandlerClassname = args[++pos];
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException("You must specify a classname when"
+                                     + " using the -inputhandler"
+                                     + " argument");
+        }
+        return pos;
+    }
+
+    /** Handle the -propertyfile argument. */
+    private int handleArgPropertyFile(String[] args, int pos) {
+        try {
+            propertyFiles.addElement(args[++pos]);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            String msg = "You must specify a property filename when "
+                + "using the -propertyfile argument";
+            throw new BuildException(msg);
+        }
+        return pos;
+    }
+
+    /** Handle the -nice argument. */
+    private int handleArgNice(String[] args, int pos) {
+        try {
+            threadPriority = Integer.decode(args[++pos]);
+        } catch (ArrayIndexOutOfBoundsException aioobe) {
+            throw new BuildException(
+                "You must supply a niceness value (1-10)"
+                + " after the -nice option");
+        } catch (NumberFormatException e) {
+            throw new BuildException("Unrecognized niceness value: "
+                                     + args[pos]);
+        }
+
+        if (threadPriority.intValue() < Thread.MIN_PRIORITY
+            || threadPriority.intValue() > Thread.MAX_PRIORITY) {
+            throw new BuildException(
+                "Niceness value is out of the range 1-10");
+        }
+        return pos;
+    }
+
+    // --------------------------------------------------------
+    //    other methods
+    // --------------------------------------------------------
+
+    /** Load the property files specified by -propertyfile */
+    private void loadPropertyFiles() {
+        for (int propertyFileIndex = 0;
+             propertyFileIndex < propertyFiles.size();
+             propertyFileIndex++) {
+            String filename
+                = (String) propertyFiles.elementAt(propertyFileIndex);
+            Properties props = new Properties();
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(filename);
+                props.load(fis);
+            } catch (IOException e) {
+                System.out.println("Could not load property file "
+                                   + filename + ": " + e.getMessage());
+            } finally {
+                FileUtils.close(fis);
+            }
+
+            // ensure that -D properties take precedence
+            Enumeration propertyNames = props.propertyNames();
+            while (propertyNames.hasMoreElements()) {
+                String name = (String) propertyNames.nextElement();
+                if (definedProps.getProperty(name) == null) {
+                    definedProps.put(name, props.getProperty(name));
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper to get the parent file for a given file.
+     * <p>
+     * Added to simulate File.getParentFile() from JDK 1.2.
+     * @deprecated since 1.6.x
+     *
+     * @param file   File to find parent of. Must not be <code>null</code>.
+     * @return       Parent file or null if none
+     */
+    private File getParentFile(File file) {
+        File parent = file.getParentFile();
+
+        if (parent != null && msgOutputLevel >= Project.MSG_VERBOSE) {
+            System.out.println("Searching in " + parent.getAbsolutePath());
+        }
+
+        return parent;
+    }
+
+    /**
+     * Search parent directories for the build file.
+     * <p>
+     * Takes the given target as a suffix to append to each
+     * parent directory in search of a build file.  Once the
+     * root of the file-system has been reached an exception
+     * is thrown.
+     *
+     * @param start  Leaf directory of search.
+     *               Must not be <code>null</code>.
+     * @param suffix  Suffix filename to look for in parents.
+     *                Must not be <code>null</code>.
+     *
+     * @return A handle to the build file if one is found
+     *
+     * @exception BuildException if no build file is found
+     */
+    private File findBuildFile(String start, String suffix)
+         throws BuildException {
+        if (msgOutputLevel >= Project.MSG_INFO) {
+            System.out.println("Searching for " + suffix + " ...");
+        }
+
+        File parent = new File(new File(start).getAbsolutePath());
+        File file = new File(parent, suffix);
+
+        // check if the target file exists in the current directory
+        while (!file.exists()) {
+            // change to parent directory
+            parent = getParentFile(parent);
+
+            // if parent is null, then we are at the root of the fs,
+            // complain that we can't find the build file.
+            if (parent == null) {
+                throw new BuildException("Could not locate a build file!");
+            }
+
+            // refresh our file handle
+            file = new File(parent, suffix);
+        }
+
+        return file;
+    }
+
+    /**
+     * Executes the build. If the constructor for this instance failed
+     * (e.g. returned after issuing a warning), this method returns
+     * immediately.
+     *
+     * @param coreLoader The classloader to use to find core classes.
+     *                   May be <code>null</code>, in which case the
+     *                   system classloader is used.
+     *
+     * @exception BuildException if the build fails
+     */
+    private void runBuild(ClassLoader coreLoader) throws BuildException {
+
+        if (!readyToRun) {
+            return;
+        }
+
+        final Project project = new Project();
+        project.setCoreLoader(coreLoader);
+
+        Throwable error = null;
+
+        try {
+            addBuildListeners(project);
+            addInputHandler(project);
+
+            PrintStream savedErr = System.err;
+            PrintStream savedOut = System.out;
+            InputStream savedIn = System.in;
+
+            // use a system manager that prevents from System.exit()
+            SecurityManager oldsm = null;
+            oldsm = System.getSecurityManager();
+
+                //SecurityManager can not be installed here for backwards
+                //compatibility reasons (PD). Needs to be loaded prior to
+                //ant class if we are going to implement it.
+                //System.setSecurityManager(new NoExitSecurityManager());
+            try {
+                if (allowInput) {
+                    project.setDefaultInputStream(System.in);
+                }
+                System.setIn(new DemuxInputStream(project));
+                System.setOut(new PrintStream(new DemuxOutputStream(project, false)));
+                System.setErr(new PrintStream(new DemuxOutputStream(project, true)));
+
+
+                if (!projectHelp) {
+                    project.fireBuildStarted();
+                }
+
+                // set the thread priorities
+                if (threadPriority != null) {
+                    try {
+                        project.log("Setting Ant's thread priority to "
+                                + threadPriority, Project.MSG_VERBOSE);
+                        Thread.currentThread().setPriority(threadPriority.intValue());
+                    } catch (SecurityException swallowed) {
+                        //we cannot set the priority here.
+                        project.log("A security manager refused to set the -nice value");
+                    }
+                }
+
+
+
+                project.init();
+
+                // set user-define properties
+                Enumeration e = definedProps.keys();
+                while (e.hasMoreElements()) {
+                    String arg = (String) e.nextElement();
+                    String value = (String) definedProps.get(arg);
+                    project.setUserProperty(arg, value);
+                }
+
+                project.setUserProperty(MagicNames.ANT_FILE,
+                                        buildFile.getAbsolutePath());
+
+                project.setKeepGoingMode(keepGoingMode);
+                if (proxy) {
+                    //proxy setup if enabled
+                    ProxySetup proxySetup = new ProxySetup(project);
+                    proxySetup.enableProxies();
+                }
+
+                ProjectHelper.configureProject(project, buildFile);
+
+                if (projectHelp) {
+                    printDescription(project);
+                    printTargets(project, msgOutputLevel > Project.MSG_INFO);
+                    return;
+                }
+
+                // make sure that we have a target to execute
+                if (targets.size() == 0) {
+                    if (project.getDefaultTarget() != null) {
+                        targets.addElement(project.getDefaultTarget());
+                    }
+                }
+
+                project.executeTargets(targets);
+            } finally {
+                // put back the original security manager
+                //The following will never eval to true. (PD)
+                if (oldsm != null) {
+                    System.setSecurityManager(oldsm);
+                }
+
+                System.setOut(savedOut);
+                System.setErr(savedErr);
+                System.setIn(savedIn);
+            }
+        } catch (RuntimeException exc) {
+            error = exc;
+            throw exc;
+        } catch (Error e) {
+            error = e;
+            throw e;
+        } finally {
+            if (!projectHelp) {
+                project.fireBuildFinished(error);
+            } else if (error != null) {
+                project.log(error.toString(), Project.MSG_ERR);
+            }
+        }
+    }
+
+    /**
+     * Adds the listeners specified in the command line arguments,
+     * along with the default listener, to the specified project.
+     *
+     * @param project The project to add listeners to.
+     *                Must not be <code>null</code>.
+     */
+    protected void addBuildListeners(Project project) {
+
+        // Add the default listener
+        project.addBuildListener(createLogger());
+
+        for (int i = 0; i < listeners.size(); i++) {
+            String className = (String) listeners.elementAt(i);
+            BuildListener listener =
+                    (BuildListener) ClasspathUtils.newInstance(className,
+                            Main.class.getClassLoader(), BuildListener.class);
+            project.setProjectReference(listener);
+
+            project.addBuildListener(listener);
+        }
+    }
+
+    /**
+     * Creates the InputHandler and adds it to the project.
+     *
+     * @param project the project instance.
+     *
+     * @exception BuildException if a specified InputHandler
+     *                           implementation could not be loaded.
+     */
+    private void addInputHandler(Project project) throws BuildException {
+        InputHandler handler = null;
+        if (inputHandlerClassname == null) {
+            handler = new DefaultInputHandler();
+        } else {
+            handler = (InputHandler) ClasspathUtils.newInstance(
+                    inputHandlerClassname, Main.class.getClassLoader(),
+                    InputHandler.class);
+            project.setProjectReference(handler);
+        }
+        project.setInputHandler(handler);
+    }
+
+    // XXX: (Jon Skeet) Any reason for writing a message and then using a bare
+    // RuntimeException rather than just using a BuildException here? Is it
+    // in case the message could end up being written to no loggers (as the
+    // loggers could have failed to be created due to this failure)?
+    /**
+     * Creates the default build logger for sending build events to the ant
+     * log.
+     *
+     * @return the logger instance for this build.
+     */
+    private BuildLogger createLogger() {
+        BuildLogger logger = null;
+        if (loggerClassname != null) {
+            try {
+                logger = (BuildLogger) ClasspathUtils.newInstance(
+                        loggerClassname, Main.class.getClassLoader(),
+                        BuildLogger.class);
+            } catch (BuildException e) {
+                System.err.println("The specified logger class "
+                    + loggerClassname
+                    + " could not be used because " + e.getMessage());
+                throw new RuntimeException();
+            }
+        } else {
+            logger = new DefaultLogger();
+        }
+
+        logger.setMessageOutputLevel(msgOutputLevel);
+        logger.setOutputPrintStream(out);
+        logger.setErrorPrintStream(err);
+        logger.setEmacsMode(emacsMode);
+
+        return logger;
+    }
+
+    /**
+     * Prints the usage information for this class to <code>System.out</code>.
+     */
+    private static void printUsage() {
+        String lSep = System.getProperty("line.separator");
+        StringBuffer msg = new StringBuffer();
+        msg.append("ant [options] [target [target2 [target3] ...]]" + lSep);
+        msg.append("Options: " + lSep);
+        msg.append("  -help, -h              print this message" + lSep);
+        msg.append("  -projecthelp, -p       print project help information" + lSep);
+        msg.append("  -version               print the version information and exit" + lSep);
+        msg.append("  -diagnostics           print information that might be helpful to" + lSep);
+        msg.append("                         diagnose or report problems." + lSep);
+        msg.append("  -quiet, -q             be extra quiet" + lSep);
+        msg.append("  -verbose, -v           be extra verbose" + lSep);
+        msg.append("  -debug, -d             print debugging information" + lSep);
+        msg.append("  -emacs, -e             produce logging information without adornments"
+                   + lSep);
+        msg.append("  -lib <path>            specifies a path to search for jars and classes"
+                   + lSep);
+        msg.append("  -logfile <file>        use given file for log" + lSep);
+        msg.append("    -l     <file>                ''" + lSep);
+        msg.append("  -logger <classname>    the class which is to perform logging" + lSep);
+        msg.append("  -listener <classname>  add an instance of class as a project listener"
+                   + lSep);
+        msg.append("  -noinput               do not allow interactive input" + lSep);
+        msg.append("  -buildfile <file>      use given buildfile" + lSep);
+        msg.append("    -file    <file>              ''" + lSep);
+        msg.append("    -f       <file>              ''" + lSep);
+        msg.append("  -D<property>=<value>   use value for given property" + lSep);
+        msg.append("  -keep-going, -k        execute all targets that do not depend" + lSep);
+        msg.append("                         on failed target(s)" + lSep);
+        msg.append("  -propertyfile <name>   load all properties from file with -D" + lSep);
+        msg.append("                         properties taking precedence" + lSep);
+        msg.append("  -inputhandler <class>  the class which will handle input requests" + lSep);
+        msg.append("  -find <file>           (s)earch for buildfile towards the root of" + lSep);
+        msg.append("    -s  <file>           the filesystem and use it" + lSep);
+        msg.append("  -nice  number          A niceness value for the main thread:" + lSep
+                   + "                         1 (lowest) to 10 (highest); 5 is the default"
+                   + lSep);
+        msg.append("  -nouserlib             Run ant without using the jar files from" + lSep
+                   + "                         ${user.home}/.ant/lib" + lSep);
+        msg.append("  -noclasspath           Run ant without using CLASSPATH" + lSep);
+        msg.append("  -autoproxy             Java1.5+: use the OS proxy settings"
+                + lSep);
+        msg.append("  -main <class>          override Ant's normal entry point");
+        System.out.println(msg.toString());
+    }
+
+    /**
+     * Prints the Ant version information to <code>System.out</code>.
+     *
+     * @exception BuildException if the version information is unavailable
+     */
+    private static void printVersion() throws BuildException {
+        System.out.println(getAntVersion());
+    }
+
+    /**
+     * Cache of the Ant version information when it has been loaded.
+     */
+    private static String antVersion = null;
+
+    /**
+     * Returns the Ant version information, if available. Once the information
+     * has been loaded once, it's cached and returned from the cache on future
+     * calls.
+     *
+     * @return the Ant version information as a String
+     *         (always non-<code>null</code>)
+     *
+     * @exception BuildException if the version information is unavailable
+     */
+    public static synchronized String getAntVersion() throws BuildException {
+        if (antVersion == null) {
+            try {
+                Properties props = new Properties();
+                InputStream in =
+                    Main.class.getResourceAsStream("/org/apache/tools/ant/version.txt");
+                props.load(in);
+                in.close();
+
+                StringBuffer msg = new StringBuffer();
+                msg.append("Apache Ant version ");
+                msg.append(props.getProperty("VERSION"));
+                msg.append(" compiled on ");
+                msg.append(props.getProperty("DATE"));
+                antVersion = msg.toString();
+            } catch (IOException ioe) {
+                throw new BuildException("Could not load the version information:"
+                                         + ioe.getMessage());
+            } catch (NullPointerException npe) {
+                throw new BuildException("Could not load the version information.");
+            }
+        }
+        return antVersion;
+    }
+
+     /**
+      * Prints the description of a project (if there is one) to
+      * <code>System.out</code>.
+      *
+      * @param project The project to display a description of.
+      *                Must not be <code>null</code>.
+      */
+    private static void printDescription(Project project) {
+       if (project.getDescription() != null) {
+          project.log(project.getDescription());
+       }
+    }
+
+    /**
+     * Targets in imported files with a project name
+     * and not overloaded by the main build file will
+     * be in the target map twice. This method
+     * removes the duplicate target.
+     * @param targets the targets to filter.
+     * @return the filtered targets.
+     */
+    private static Map removeDuplicateTargets(Map targets) {
+        Map locationMap = new HashMap();
+        for (Iterator i = targets.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            String name = (String) entry.getKey();
+            Target target = (Target) entry.getValue();
+            Target otherTarget =
+                (Target) locationMap.get(target.getLocation());
+            // Place this entry in the location map if
+            //  a) location is not in the map
+            //  b) location is in map, but it's name is longer
+            //     (an imported target will have a name. prefix)
+            if (otherTarget == null
+                || otherTarget.getName().length() > name.length()) {
+                locationMap.put(
+                    target.getLocation(), target); // Smallest name wins
+            }
+        }
+        Map ret = new HashMap();
+        for (Iterator i = locationMap.values().iterator(); i.hasNext();) {
+            Target target = (Target) i.next();
+            ret.put(target.getName(), target);
+        }
+        return ret;
+    }
+
+    /**
+     * Prints a list of all targets in the specified project to
+     * <code>System.out</code>, optionally including subtargets.
+     *
+     * @param project The project to display a description of.
+     *                Must not be <code>null</code>.
+     * @param printSubTargets Whether or not subtarget names should also be
+     *                        printed.
+     */
+    private static void printTargets(Project project, boolean printSubTargets) {
+        // find the target with the longest name
+        int maxLength = 0;
+        Map ptargets = removeDuplicateTargets(project.getTargets());
+        String targetName;
+        String targetDescription;
+        Target currentTarget;
+        // split the targets in top-level and sub-targets depending
+        // on the presence of a description
+        Vector topNames = new Vector();
+        Vector topDescriptions = new Vector();
+        Vector subNames = new Vector();
+
+        for (Iterator i = ptargets.values().iterator(); i.hasNext();) {
+            currentTarget = (Target) i.next();
+            targetName = currentTarget.getName();
+            if (targetName.equals("")) {
+                continue;
+            }
+            targetDescription = currentTarget.getDescription();
+            // maintain a sorted list of targets
+            if (targetDescription == null) {
+                int pos = findTargetPosition(subNames, targetName);
+                subNames.insertElementAt(targetName, pos);
+            } else {
+                int pos = findTargetPosition(topNames, targetName);
+                topNames.insertElementAt(targetName, pos);
+                topDescriptions.insertElementAt(targetDescription, pos);
+                if (targetName.length() > maxLength) {
+                    maxLength = targetName.length();
+                }
+            }
+        }
+
+        printTargets(project, topNames, topDescriptions, "Main targets:",
+                     maxLength);
+        //if there were no main targets, we list all subtargets
+        //as it means nothing has a description
+        if (topNames.size() == 0) {
+            printSubTargets = true;
+        }
+        if (printSubTargets) {
+            printTargets(project, subNames, null, "Other targets:", 0);
+        }
+
+        String defaultTarget = project.getDefaultTarget();
+        if (defaultTarget != null && !"".equals(defaultTarget)) {
+            // shouldn't need to check but...
+            project.log("Default target: " + defaultTarget);
+        }
+    }
+
+    /**
+     * Searches for the correct place to insert a name into a list so as
+     * to keep the list sorted alphabetically.
+     *
+     * @param names The current list of names. Must not be <code>null</code>.
+     * @param name  The name to find a place for.
+     *              Must not be <code>null</code>.
+     *
+     * @return the correct place in the list for the given name
+     */
+    private static int findTargetPosition(Vector names, String name) {
+        int res = names.size();
+        for (int i = 0; i < names.size() && res == names.size(); i++) {
+            if (name.compareTo((String) names.elementAt(i)) < 0) {
+                res = i;
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Writes a formatted list of target names to <code>System.out</code>
+     * with an optional description.
+     *
+     *
+     * @param project the project instance.
+     * @param names The names to be printed.
+     *              Must not be <code>null</code>.
+     * @param descriptions The associated target descriptions.
+     *                     May be <code>null</code>, in which case
+     *                     no descriptions are displayed.
+     *                     If non-<code>null</code>, this should have
+     *                     as many elements as <code>names</code>.
+     * @param heading The heading to display.
+     *                Should not be <code>null</code>.
+     * @param maxlen The maximum length of the names of the targets.
+     *               If descriptions are given, they are padded to this
+     *               position so they line up (so long as the names really
+     *               <i>are</i> shorter than this).
+     */
+    private static void printTargets(Project project, Vector names,
+                                     Vector descriptions, String heading,
+                                     int maxlen) {
+        // now, start printing the targets and their descriptions
+        String lSep = System.getProperty("line.separator");
+        // got a bit annoyed that I couldn't find a pad function
+        String spaces = "    ";
+        while (spaces.length() <= maxlen) {
+            spaces += spaces;
+        }
+        StringBuffer msg = new StringBuffer();
+        msg.append(heading + lSep + lSep);
+        for (int i = 0; i < names.size(); i++) {
+            msg.append(" ");
+            msg.append(names.elementAt(i));
+            if (descriptions != null) {
+                msg.append(
+                    spaces.substring(0, maxlen - ((String) names.elementAt(i)).length() + 2));
+                msg.append(descriptions.elementAt(i));
+            }
+            msg.append(lSep);
+        }
+        project.log(msg.toString(), Project.MSG_WARN);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/NoBannerLogger.java b/trunk/src/main/org/apache/tools/ant/NoBannerLogger.java
new file mode 100644
index 0000000..956e3c5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/NoBannerLogger.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Extends DefaultLogger to strip out empty targets.
+ *
+ */
+public class NoBannerLogger extends DefaultLogger {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Name of the current target, if it should
+     * be displayed on the next message. This is
+     * set when a target starts building, and reset
+     * to <code>null</code> after the first message for
+     * the target is logged.
+     */
+    protected String targetName;
+    // CheckStyle:VisibilityModifier ON
+
+    /** Sole constructor. */
+    public NoBannerLogger() {
+    }
+
+    /**
+     * Notes the name of the target so it can be logged
+     * if it generates any messages.
+     *
+     * @param event A BuildEvent containing target information.
+     *              Must not be <code>null</code>.
+     */
+    public void targetStarted(BuildEvent event) {
+        targetName = extractTargetName(event);
+    }
+
+    /**
+     * Override point, extract the target name
+     * @param event the event to work on
+     * @return the target name to print
+     * @since Ant1.7.1
+     */
+    protected String extractTargetName(BuildEvent event) {
+        return event.getTarget().getName();
+    }
+
+    /**
+     * Resets the current target name to <code>null</code>.
+     *
+     * @param event Ignored in this implementation.
+     */
+    public void targetFinished(BuildEvent event) {
+        targetName = null;
+    }
+
+    /**
+     * Logs a message for a target if it is of an appropriate
+     * priority, also logging the name of the target if this
+     * is the first message which needs to be logged for the
+     * target.
+     *
+     * @param event A BuildEvent containing message information.
+     *              Must not be <code>null</code>.
+     */
+    public void messageLogged(BuildEvent event) {
+
+        if (event.getPriority() > msgOutputLevel
+            || null == event.getMessage()
+            || "".equals(event.getMessage().trim())) {
+                return;
+        }
+
+        if (null != targetName) {
+            out.println(StringUtils.LINE_SEP + targetName + ":");
+            targetName = null;
+        }
+
+        super.messageLogged(event);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/PathTokenizer.java b/trunk/src/main/org/apache/tools/ant/PathTokenizer.java
new file mode 100644
index 0000000..10d3e37
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/PathTokenizer.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * A Path tokenizer takes a path and returns the components that make up
+ * that path.
+ *
+ * The path can use path separators of either ':' or ';' and file separators
+ * of either '/' or '\'.
+ *
+ */
+public class PathTokenizer {
+    /**
+     * A tokenizer to break the string up based on the ':' or ';' separators.
+     */
+    private StringTokenizer tokenizer;
+
+    /**
+     * A String which stores any path components which have been read ahead
+     * due to DOS filesystem compensation.
+     */
+    private String lookahead = null;
+
+    /**
+     * A boolean that determines if we are running on Novell NetWare, which
+     * exhibits slightly different path name characteristics (multi-character
+     * volume / drive names)
+     */
+    private boolean onNetWare = Os.isFamily("netware");
+
+    /**
+     * Flag to indicate whether or not we are running on a platform with a
+     * DOS style filesystem
+     */
+    private boolean dosStyleFilesystem;
+
+    /**
+     * Constructs a path tokenizer for the specified path.
+     *
+     * @param path The path to tokenize. Must not be <code>null</code>.
+     */
+    public PathTokenizer(String path) {
+        if (onNetWare) {
+            // For NetWare, use the boolean=true mode, so we can use delimiter
+            // information to make a better decision later.
+            tokenizer = new StringTokenizer(path, ":;", true);
+        } else {
+            // on Windows and Unix, we can ignore delimiters and still have
+            // enough information to tokenize correctly.
+            tokenizer = new StringTokenizer(path, ":;", false);
+        }
+        dosStyleFilesystem = File.pathSeparatorChar == ';';
+    }
+
+    /**
+     * Tests if there are more path elements available from this tokenizer's
+     * path. If this method returns <code>true</code>, then a subsequent call
+     * to nextToken will successfully return a token.
+     *
+     * @return <code>true</code> if and only if there is at least one token
+     * in the string after the current position; <code>false</code> otherwise.
+     */
+    public boolean hasMoreTokens() {
+        if (lookahead != null) {
+            return true;
+        }
+
+        return tokenizer.hasMoreTokens();
+    }
+
+    /**
+     * Returns the next path element from this tokenizer.
+     *
+     * @return the next path element from this tokenizer.
+     *
+     * @exception NoSuchElementException if there are no more elements in this
+     *            tokenizer's path.
+     */
+    public String nextToken() throws NoSuchElementException {
+        String token = null;
+        if (lookahead != null) {
+            token = lookahead;
+            lookahead = null;
+        } else {
+            token = tokenizer.nextToken().trim();
+        }
+
+        if (!onNetWare) {
+            if (token.length() == 1 && Character.isLetter(token.charAt(0))
+                                    && dosStyleFilesystem
+                                    && tokenizer.hasMoreTokens()) {
+                // we are on a dos style system so this path could be a drive
+                // spec. We look at the next token
+                String nextToken = tokenizer.nextToken().trim();
+                if (nextToken.startsWith("\\") || nextToken.startsWith("/")) {
+                    // we know we are on a DOS style platform and the next path
+                    // starts with a slash or backslash, so we know this is a
+                    // drive spec
+                    token += ":" + nextToken;
+                } else {
+                    // store the token just read for next time
+                    lookahead = nextToken;
+                }
+            }
+        } else {
+            // we are on NetWare, tokenizing is handled a little differently,
+            // due to the fact that NetWare has multiple-character volume names.
+            if (token.equals(File.pathSeparator) || token.equals(":")) {
+                // ignore ";" and get the next token
+                token = tokenizer.nextToken().trim();
+            }
+
+            if (tokenizer.hasMoreTokens()) {
+                // this path could be a drive spec, so look at the next token
+                String nextToken = tokenizer.nextToken().trim();
+
+                // make sure we aren't going to get the path separator next
+                if (!nextToken.equals(File.pathSeparator)) {
+                    if (nextToken.equals(":")) {
+                        if (!token.startsWith("/") && !token.startsWith("\\")
+                            && !token.startsWith(".")
+                            && !token.startsWith("..")) {
+                            // it indeed is a drive spec, get the next bit
+                            String oneMore = tokenizer.nextToken().trim();
+                            if (!oneMore.equals(File.pathSeparator)) {
+                                token += ":" + oneMore;
+                            } else {
+                                token += ":";
+                                lookahead = oneMore;
+                            }
+                        }
+                        // implicit else: ignore the ':' since we have either a
+                        // UNIX or a relative path
+                    } else {
+                        // store the token just read for next time
+                        lookahead = nextToken;
+                    }
+                }
+            }
+        }
+        return token;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/Project.java b/trunk/src/main/org/apache/tools/ant/Project.java
new file mode 100644
index 0000000..e92dbce
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Project.java
@@ -0,0 +1,2382 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.helper.DefaultExecutor;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Description;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Central representation of an Ant project. This class defines an
+ * Ant project with all of its targets, tasks and various other
+ * properties. It also provides the mechanism to kick off a build using
+ * a particular target name.
+ * <p>
+ * This class also encapsulates methods which allow files to be referred
+ * to using abstract path names which are translated to native system
+ * file paths at runtime.
+ *
+ */
+public class Project implements ResourceFactory {
+    private static final String LINE_SEP = System.getProperty("line.separator");
+
+    /** Message priority of &quot;error&quot;. */
+    public static final int MSG_ERR = 0;
+    /** Message priority of &quot;warning&quot;. */
+    public static final int MSG_WARN = 1;
+    /** Message priority of &quot;information&quot;. */
+    public static final int MSG_INFO = 2;
+    /** Message priority of &quot;verbose&quot;. */
+    public static final int MSG_VERBOSE = 3;
+    /** Message priority of &quot;debug&quot;. */
+    public static final int MSG_DEBUG = 4;
+
+    /**
+     * Constant for the &quot;visiting&quot; state, used when
+     * traversing a DFS of target dependencies.
+     */
+    private static final String VISITING = "VISITING";
+    /**
+     * Constant for the &quot;visited&quot; state, used when
+     * traversing a DFS of target dependencies.
+     */
+    private static final String VISITED = "VISITED";
+
+    /**
+     * Version constant for Java 1.0 .
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link JavaEnvUtils#JAVA_1_0} instead.
+     */
+    public static final String JAVA_1_0 = JavaEnvUtils.JAVA_1_0;
+    /**
+     * Version constant for Java 1.1 .
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link JavaEnvUtils#JAVA_1_1} instead.
+     */
+    public static final String JAVA_1_1 = JavaEnvUtils.JAVA_1_1;
+    /**
+     * Version constant for Java 1.2 .
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link JavaEnvUtils#JAVA_1_2} instead.
+     */
+    public static final String JAVA_1_2 = JavaEnvUtils.JAVA_1_2;
+    /**
+     * Version constant for Java 1.3 .
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link JavaEnvUtils#JAVA_1_3} instead.
+     */
+    public static final String JAVA_1_3 = JavaEnvUtils.JAVA_1_3;
+    /**
+     * Version constant for Java 1.4 .
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link JavaEnvUtils#JAVA_1_4} instead.
+     */
+    public static final String JAVA_1_4 = JavaEnvUtils.JAVA_1_4;
+
+    /** Default filter start token. */
+    public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
+    /** Default filter end token. */
+    public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
+
+    /** Instance of a utility class to use for file operations. */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Name of this project. */
+    private String name;
+    /** Description for this project (if any). */
+    private String description;
+
+
+    /** Map of references within the project (paths etc) (String to Object). */
+    private Hashtable references = new AntRefTable();
+
+    /** Map of id references - used for indicating broken build files */
+    private HashMap idReferences = new HashMap();
+
+    /** the parent project for old id resolution (if inheritreferences is set) */
+    private Project parentIdProject = null;
+
+    /** Name of the project's default target. */
+    private String defaultTarget;
+
+    /** Map from target names to targets (String to Target). */
+    private Hashtable targets = new Hashtable();
+    /** Set of global filters. */
+    private FilterSet globalFilterSet = new FilterSet();
+    {
+        // Initialize the globalFileSet's project
+        globalFilterSet.setProject(this);
+    }
+
+    /**
+     * Wrapper around globalFilterSet. This collection only ever
+     * contains one FilterSet, but the wrapper is needed in order to
+     * make it easier to use the FileUtils interface.
+     */
+    private FilterSetCollection globalFilters
+        = new FilterSetCollection(globalFilterSet);
+
+    /** Project base directory. */
+    private File baseDir;
+
+    /** List of listeners to notify of build events. */
+    private Vector listeners = new Vector();
+
+    /**
+     * The Ant core classloader--may be <code>null</code> if using
+     * parent classloader.
+     */
+    private ClassLoader coreLoader = null;
+
+    /** Records the latest task to be executed on a thread. */
+    private Map/*<Thread,Task>*/ threadTasks = Collections.synchronizedMap(new WeakHashMap());
+
+    /** Records the latest task to be executed on a thread group. */
+    private Map/*<ThreadGroup,Task>*/ threadGroupTasks
+        = Collections.synchronizedMap(new WeakHashMap());
+
+    /**
+     * Called to handle any input requests.
+     */
+    private InputHandler inputHandler = null;
+
+    /**
+     * The default input stream used to read any input.
+     */
+    private InputStream defaultInputStream = null;
+
+    /**
+     * Keep going flag.
+     */
+    private boolean keepGoingMode = false;
+
+    /**
+     * Flag which catches Listeners which try to use System.out or System.err .
+     */
+    private boolean loggingMessage = false;
+
+    /**
+     * Set the input handler.
+     *
+     * @param handler the InputHandler instance to use for gathering input.
+     */
+    public void setInputHandler(InputHandler handler) {
+        inputHandler = handler;
+    }
+
+    /**
+     * Set the default System input stream. Normally this stream is set to
+     * System.in. This inputStream is used when no task input redirection is
+     * being performed.
+     *
+     * @param defaultInputStream the default input stream to use when input
+     *        is requested.
+     * @since Ant 1.6
+     */
+    public void setDefaultInputStream(InputStream defaultInputStream) {
+        this.defaultInputStream = defaultInputStream;
+    }
+
+    /**
+     * Get this project's input stream.
+     *
+     * @return the InputStream instance in use by this Project instance to
+     * read input.
+     */
+    public InputStream getDefaultInputStream() {
+        return defaultInputStream;
+    }
+
+    /**
+     * Retrieve the current input handler.
+     *
+     * @return the InputHandler instance currently in place for the project
+     *         instance.
+     */
+    public InputHandler getInputHandler() {
+        return inputHandler;
+    }
+
+    /**
+     * Create a new Ant project.
+     */
+    public Project() {
+        inputHandler = new DefaultInputHandler();
+    }
+
+    /**
+     * Create and initialize a subproject. By default the subproject will be of
+     * the same type as its parent. If a no-arg constructor is unavailable, the
+     * <code>Project</code> class will be used.
+     * @return a Project instance configured as a subproject of this Project.
+     * @since Ant 1.7
+     */
+    public Project createSubProject() {
+        Project subProject = null;
+        try {
+            subProject = (Project) (getClass().newInstance());
+        } catch (Exception e) {
+            subProject = new Project();
+        }
+        initSubProject(subProject);
+        return subProject;
+    }
+
+    /**
+     * Initialize a subproject.
+     * @param subProject the subproject to initialize.
+     */
+    public void initSubProject(Project subProject) {
+        ComponentHelper.getComponentHelper(subProject)
+            .initSubProject(ComponentHelper.getComponentHelper(this));
+        subProject.setDefaultInputStream(getDefaultInputStream());
+        subProject.setKeepGoingMode(this.isKeepGoingMode());
+        subProject.setExecutor(getExecutor().getSubProjectExecutor());
+    }
+
+    /**
+     * Initialise the project.
+     *
+     * This involves setting the default task definitions and loading the
+     * system properties.
+     *
+     * @exception BuildException if the default task list cannot be loaded.
+     */
+    public void init() throws BuildException {
+        initProperties();
+
+        ComponentHelper.getComponentHelper(this).initDefaultDefinitions();
+    }
+
+    /**
+     * Initializes the properties.
+     * @exception BuildException if an vital property could not be set.
+     * @since Ant 1.7
+     */
+    public void initProperties() throws BuildException {
+        setJavaVersionProperty();
+        setSystemProperties();
+        setPropertyInternal(MagicNames.ANT_VERSION, Main.getAntVersion());
+        setAntLib();
+    }
+
+    /**
+     * Set a property to the location of ant.jar.
+     * Use the locator to find the location of the Project.class, and
+     * if this is not null, set the property {@link MagicNames#ANT_LIB}
+     * to the result
+     */
+    private void setAntLib() {
+        File antlib = org.apache.tools.ant.launch.Locator.getClassSource(
+            Project.class);
+        if (antlib != null) {
+            setPropertyInternal(MagicNames.ANT_LIB, antlib.getAbsolutePath());
+        }
+    }
+    /**
+     * Factory method to create a class loader for loading classes from
+     * a given path.
+     *
+     * @param path the path from which classes are to be loaded.
+     *
+     * @return an appropriate classloader.
+     */
+    public AntClassLoader createClassLoader(Path path) {
+        return new AntClassLoader(
+            getClass().getClassLoader(), this, path);
+    }
+
+    /**
+     * Factory method to create a class loader for loading classes from
+     * a given path.
+     *
+     * @param parent the parent classloader for the new loader.
+     * @param path the path from which classes are to be loaded.
+     *
+     * @return an appropriate classloader.
+     */
+    public AntClassLoader createClassLoader(
+        ClassLoader parent, Path path) {
+        return new AntClassLoader(parent, this, path);
+    }
+
+    /**
+     * Set the core classloader for the project. If a <code>null</code>
+     * classloader is specified, the parent classloader should be used.
+     *
+     * @param coreLoader The classloader to use for the project.
+     *                   May be <code>null</code>.
+     */
+    public void setCoreLoader(ClassLoader coreLoader) {
+        this.coreLoader = coreLoader;
+    }
+
+    /**
+     * Return the core classloader to use for this project.
+     * This may be <code>null</code>, indicating that
+     * the parent classloader should be used.
+     *
+     * @return the core classloader to use for this project.
+     *
+     */
+    public ClassLoader getCoreLoader() {
+        return coreLoader;
+    }
+
+    /**
+     * Add a build listener to the list. This listener will
+     * be notified of build events for this project.
+     *
+     * @param listener The listener to add to the list.
+     *                 Must not be <code>null</code>.
+     */
+    public synchronized void addBuildListener(BuildListener listener) {
+        // If the listeners already has this listener, do nothing
+        if (listeners.contains(listener)) {
+            return;
+        }
+        // create a new Vector to avoid ConcurrentModificationExc when
+        // the listeners get added/removed while we are in fire
+        Vector newListeners = getBuildListeners();
+        newListeners.addElement(listener);
+        listeners = newListeners;
+    }
+
+    /**
+     * Remove a build listener from the list. This listener
+     * will no longer be notified of build events for this project.
+     *
+     * @param listener The listener to remove from the list.
+     *                 Should not be <code>null</code>.
+     */
+    public synchronized void removeBuildListener(BuildListener listener) {
+        // create a new Vector to avoid ConcurrentModificationExc when
+        // the listeners get added/removed while we are in fire
+        Vector newListeners = getBuildListeners();
+        newListeners.removeElement(listener);
+        listeners = newListeners;
+    }
+
+    /**
+     * Return a copy of the list of build listeners for the project.
+     *
+     * @return a list of build listeners for the project
+     */
+    public Vector getBuildListeners() {
+        return (Vector) listeners.clone();
+    }
+
+    /**
+     * Write a message to the log with the default log level
+     * of MSG_INFO .
+     * @param message The text to log. Should not be <code>null</code>.
+     */
+
+    public void log(String message) {
+        log(message, MSG_INFO);
+    }
+
+    /**
+     * Write a project level message to the log with the given log level.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     */
+    public void log(String message, int msgLevel) {
+        log(message, null, msgLevel);
+    }
+
+    /**
+     * Write a project level message to the log with the given log level.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param throwable The exception causing this log, may be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     * @since 1.7
+     */
+    public void log(String message, Throwable throwable, int msgLevel) {
+        fireMessageLogged(this, message, throwable, msgLevel);
+    }
+
+    /**
+     * Write a task level message to the log with the given log level.
+     * @param task The task to use in the log. Must not be <code>null</code>.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     */
+    public void log(Task task, String message, int msgLevel) {
+        fireMessageLogged(task, message, null, msgLevel);
+    }
+
+    /**
+     * Write a task level message to the log with the given log level.
+     * @param task The task to use in the log. Must not be <code>null</code>.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param throwable The exception causing this log, may be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     * @since 1.7
+     */
+    public void log(Task task, String message, Throwable throwable, int msgLevel) {
+        fireMessageLogged(task, message, throwable, msgLevel);
+    }
+
+    /**
+     * Write a target level message to the log with the given log level.
+     * @param target The target to use in the log.
+     *               Must not be <code>null</code>.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     */
+    public void log(Target target, String message, int msgLevel) {
+        log(target, message, null, msgLevel);
+    }
+
+    /**
+     * Write a target level message to the log with the given log level.
+     * @param target The target to use in the log.
+     *               Must not be <code>null</code>.
+     * @param message The text to log. Should not be <code>null</code>.
+     * @param throwable The exception causing this log, may be <code>null</code>.
+     * @param msgLevel The log priority level to use.
+     * @since 1.7
+     */
+    public void log(Target target, String message, Throwable throwable,
+            int msgLevel) {
+        fireMessageLogged(target, message, throwable, msgLevel);
+    }
+
+    /**
+     * Return the set of global filters.
+     *
+     * @return the set of global filters.
+     */
+    public FilterSet getGlobalFilterSet() {
+        return globalFilterSet;
+    }
+
+    /**
+     * Set a property. Any existing property of the same name
+     * is overwritten, unless it is a user property.
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     */
+    public void setProperty(String name, String value) {
+        PropertyHelper.getPropertyHelper(this).setProperty(name, value, true);
+    }
+
+    /**
+     * Set a property if no value currently exists. If the property
+     * exists already, a message is logged and the method returns with
+     * no other effect.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @since 1.5
+     */
+    public void setNewProperty(String name, String value) {
+        PropertyHelper.getPropertyHelper(this).setNewProperty(name, value);
+    }
+
+    /**
+     * Set a user property, which cannot be overwritten by
+     * set/unset property calls. Any previous value is overwritten.
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @see #setProperty(String,String)
+     */
+    public void setUserProperty(String name, String value) {
+        PropertyHelper.getPropertyHelper(this).setUserProperty(name, value);
+    }
+
+    /**
+     * Set a user property, which cannot be overwritten by set/unset
+     * property calls. Any previous value is overwritten. Also marks
+     * these properties as properties that have not come from the
+     * command line.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @see #setProperty(String,String)
+     */
+    public void setInheritedProperty(String name, String value) {
+        PropertyHelper.getPropertyHelper(this).setInheritedProperty(name, value);
+    }
+
+    /**
+     * Set a property unless it is already defined as a user property
+     * (in which case the method returns silently).
+     *
+     * @param name The name of the property.
+     *             Must not be <code>null</code>.
+     * @param value The property value. Must not be <code>null</code>.
+     */
+    private void setPropertyInternal(String name, String value) {
+        PropertyHelper.getPropertyHelper(this).setProperty(name, value, false);
+    }
+
+    /**
+     * Return the value of a property, if it is set.
+     *
+     * @param propertyName The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+    public String getProperty(String propertyName) {
+        Object value = PropertyHelper.getPropertyHelper(this).getProperty(propertyName);
+        return value == null ? null : String.valueOf(value);
+    }
+
+    /**
+     * Replace ${} style constructions in the given value with the
+     * string value of the corresponding data types.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>.
+     *
+     * @return the given string with embedded property names replaced
+     *         by values, or <code>null</code> if the given string is
+     *         <code>null</code>.
+     *
+     * @exception BuildException if the given value has an unclosed
+     *                           property name, e.g. <code>${xxx</code>.
+     */
+    public String replaceProperties(String value) throws BuildException {
+        return PropertyHelper.getPropertyHelper(this).replaceProperties(null, value, null);
+    }
+
+    /**
+     * Return the value of a user property, if it is set.
+     *
+     * @param propertyName The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+     public String getUserProperty(String propertyName) {
+        return (String) PropertyHelper.getPropertyHelper(this).getUserProperty(propertyName);
+    }
+
+    /**
+     * Return a copy of the properties table.
+     * @return a hashtable containing all properties
+     *         (including user properties).
+     */
+    public Hashtable getProperties() {
+        return PropertyHelper.getPropertyHelper(this).getProperties();
+    }
+
+    /**
+     * Return a copy of the user property hashtable.
+     * @return a hashtable containing just the user properties.
+     */
+    public Hashtable getUserProperties() {
+        return PropertyHelper.getPropertyHelper(this).getUserProperties();
+    }
+
+    /**
+     * Copy all user properties that have been set on the command
+     * line or a GUI tool from this instance to the Project instance
+     * given as the argument.
+     *
+     * <p>To copy all &quot;user&quot; properties, you will also have to call
+     * {@link #copyInheritedProperties copyInheritedProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.5
+     */
+    public void copyUserProperties(Project other) {
+        PropertyHelper.getPropertyHelper(this).copyUserProperties(other);
+    }
+
+    /**
+     * Copy all user properties that have not been set on the
+     * command line or a GUI tool from this instance to the Project
+     * instance given as the argument.
+     *
+     * <p>To copy all &quot;user&quot; properties, you will also have to call
+     * {@link #copyUserProperties copyUserProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.5
+     */
+    public void copyInheritedProperties(Project other) {
+        PropertyHelper.getPropertyHelper(this).copyInheritedProperties(other);
+    }
+
+    /**
+     * Set the default target of the project.
+     *
+     * @param defaultTarget The name of the default target for this project.
+     *                      May be <code>null</code>, indicating that there is
+     *                      no default target.
+     *
+     * @deprecated since 1.5.x.
+     *             Use setDefault.
+     * @see #setDefault(String)
+     */
+    public void setDefaultTarget(String defaultTarget) {
+        this.defaultTarget = defaultTarget;
+    }
+
+    /**
+     * Return the name of the default target of the project.
+     * @return name of the default target or
+     *         <code>null</code> if no default has been set.
+     */
+    public String getDefaultTarget() {
+        return defaultTarget;
+    }
+
+    /**
+     * Set the default target of the project.
+     *
+     * @param defaultTarget The name of the default target for this project.
+     *                      May be <code>null</code>, indicating that there is
+     *                      no default target.
+     */
+    public void setDefault(String defaultTarget) {
+        this.defaultTarget = defaultTarget;
+    }
+
+    /**
+     * Set the name of the project, also setting the user
+     * property <code>ant.project.name</code>.
+     *
+     * @param name The name of the project.
+     *             Must not be <code>null</code>.
+     */
+    public void setName(String name) {
+        setUserProperty("ant.project.name",  name);
+        this.name = name;
+    }
+
+    /**
+     * Return the project name, if one has been set.
+     *
+     * @return the project name, or <code>null</code> if it hasn't been set.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Set the project description.
+     *
+     * @param description The description of the project.
+     *                    May be <code>null</code>.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Return the project description, if one has been set.
+     *
+     * @return the project description, or <code>null</code> if it hasn't
+     *         been set.
+     */
+    public String getDescription() {
+        if (description == null) {
+            description = Description.getDescription(this);
+        }
+        return description;
+    }
+
+    /**
+     * Add a filter to the set of global filters.
+     *
+     * @param token The token to filter.
+     *              Must not be <code>null</code>.
+     * @param value The replacement value.
+     *              Must not be <code>null</code>.
+     * @deprecated since 1.4.x.
+     *             Use getGlobalFilterSet().addFilter(token,value)
+     *
+     * @see #getGlobalFilterSet()
+     * @see FilterSet#addFilter(String,String)
+     */
+    public void addFilter(String token, String value) {
+        if (token == null) {
+            return;
+        }
+        globalFilterSet.addFilter(new FilterSet.Filter(token, value));
+    }
+
+    /**
+     * Return a hashtable of global filters, mapping tokens to values.
+     *
+     * @return a hashtable of global filters, mapping tokens to values
+     *         (String to String).
+     *
+     * @deprecated since 1.4.x
+     *             Use getGlobalFilterSet().getFilterHash().
+     *
+     * @see #getGlobalFilterSet()
+     * @see FilterSet#getFilterHash()
+     */
+    public Hashtable getFilters() {
+        // we need to build the hashtable dynamically
+        return globalFilterSet.getFilterHash();
+    }
+
+    /**
+     * Set the base directory for the project, checking that
+     * the given filename exists and is a directory.
+     *
+     * @param baseD The project base directory.
+     *              Must not be <code>null</code>.
+     *
+     * @exception BuildException if the directory if invalid.
+     */
+    public void setBasedir(String baseD) throws BuildException {
+        setBaseDir(new File(baseD));
+    }
+
+    /**
+     * Set the base directory for the project, checking that
+     * the given file exists and is a directory.
+     *
+     * @param baseDir The project base directory.
+     *                Must not be <code>null</code>.
+     * @exception BuildException if the specified file doesn't exist or
+     *                           isn't a directory.
+     */
+    public void setBaseDir(File baseDir) throws BuildException {
+        baseDir = FILE_UTILS.normalize(baseDir.getAbsolutePath());
+        if (!baseDir.exists()) {
+            throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+                + " does not exist");
+        }
+        if (!baseDir.isDirectory()) {
+            throw new BuildException("Basedir " + baseDir.getAbsolutePath()
+                + " is not a directory");
+        }
+        this.baseDir = baseDir;
+        setPropertyInternal(MagicNames.PROJECT_BASEDIR, this.baseDir.getPath());
+        String msg = "Project base dir set to: " + this.baseDir;
+         log(msg, MSG_VERBOSE);
+    }
+
+    /**
+     * Return the base directory of the project as a file object.
+     *
+     * @return the project base directory, or <code>null</code> if the
+     *         base directory has not been successfully set to a valid value.
+     */
+    public File getBaseDir() {
+        if (baseDir == null) {
+            try {
+                setBasedir(".");
+            } catch (BuildException ex) {
+                ex.printStackTrace();
+            }
+        }
+        return baseDir;
+    }
+
+    /**
+     * Set &quot;keep-going&quot; mode. In this mode Ant will try to execute
+     * as many targets as possible. All targets that do not depend
+     * on failed target(s) will be executed.  If the keepGoing settor/getter
+     * methods are used in conjunction with the <code>ant.executor.class</code>
+     * property, they will have no effect.
+     * @param keepGoingMode &quot;keep-going&quot; mode
+     * @since Ant 1.6
+     */
+    public void setKeepGoingMode(boolean keepGoingMode) {
+        this.keepGoingMode = keepGoingMode;
+    }
+
+    /**
+     * Return the keep-going mode.  If the keepGoing settor/getter
+     * methods are used in conjunction with the <code>ant.executor.class</code>
+     * property, they will have no effect.
+     * @return &quot;keep-going&quot; mode
+     * @since Ant 1.6
+     */
+    public boolean isKeepGoingMode() {
+        return this.keepGoingMode;
+    }
+
+    /**
+     * Return the version of Java this class is running under.
+     * @return the version of Java as a String, e.g. "1.1" .
+     * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
+     * @deprecated since 1.5.x.
+     *             Use org.apache.tools.ant.util.JavaEnvUtils instead.
+     */
+    public static String getJavaVersion() {
+        return JavaEnvUtils.getJavaVersion();
+    }
+
+    /**
+     * Set the <code>ant.java.version</code> property and tests for
+     * unsupported JVM versions. If the version is supported,
+     * verbose log messages are generated to record the Java version
+     * and operating system name.
+     *
+     * @exception BuildException if this Java version is not supported.
+     *
+     * @see org.apache.tools.ant.util.JavaEnvUtils#getJavaVersion
+     */
+    public void setJavaVersionProperty() throws BuildException {
+        String javaVersion = JavaEnvUtils.getJavaVersion();
+        setPropertyInternal(MagicNames.ANT_JAVA_VERSION, javaVersion);
+
+        // sanity check
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_0)
+                || JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_1))  {
+            throw new BuildException("Ant cannot work on Java 1.0 / 1.1");
+        }
+        log("Detected Java version: " + javaVersion + " in: "
+            + System.getProperty("java.home"), MSG_VERBOSE);
+
+        log("Detected OS: " + System.getProperty("os.name"), MSG_VERBOSE);
+    }
+
+    /**
+     * Add all system properties which aren't already defined as
+     * user properties to the project properties.
+     */
+    public void setSystemProperties() {
+        Properties systemP = System.getProperties();
+        Enumeration e = systemP.propertyNames();
+        while (e.hasMoreElements()) {
+            String propertyName = (String) e.nextElement();
+            String value = systemP.getProperty(propertyName);
+            if (value != null) {
+                this.setPropertyInternal(propertyName, value);
+            }
+        }
+    }
+
+    /**
+     * Add a new task definition to the project.
+     * Attempting to override an existing definition with an
+     * equivalent one (i.e. with the same classname) results in
+     * a verbose log message. Attempting to override an existing definition
+     * with a different one results in a warning log message and
+     * invalidates any tasks which have already been created with the
+     * old definition.
+     *
+     * @param taskName The name of the task to add.
+     *                 Must not be <code>null</code>.
+     * @param taskClass The full name of the class implementing the task.
+     *                  Must not be <code>null</code>.
+     *
+     * @exception BuildException if the class is unsuitable for being an Ant
+     *                           task. An error level message is logged before
+     *                           this exception is thrown.
+     *
+     * @see #checkTaskClass(Class)
+     */
+    public void addTaskDefinition(String taskName, Class taskClass)
+         throws BuildException {
+        ComponentHelper.getComponentHelper(this).addTaskDefinition(taskName,
+                taskClass);
+    }
+
+    /**
+     * Check whether or not a class is suitable for serving as Ant task.
+     * Ant task implementation classes must be public, concrete, and have
+     * a no-arg constructor.
+     *
+     * @param taskClass The class to be checked.
+     *                  Must not be <code>null</code>.
+     *
+     * @exception BuildException if the class is unsuitable for being an Ant
+     *                           task. An error level message is logged before
+     *                           this exception is thrown.
+     */
+    public void checkTaskClass(final Class taskClass) throws BuildException {
+        ComponentHelper.getComponentHelper(this).checkTaskClass(taskClass);
+
+        if (!Modifier.isPublic(taskClass.getModifiers())) {
+            final String message = taskClass + " is not public";
+            log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        }
+        if (Modifier.isAbstract(taskClass.getModifiers())) {
+            final String message = taskClass + " is abstract";
+            log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        }
+        try {
+            taskClass.getConstructor((Class[]) null);
+            // don't have to check for public, since
+            // getConstructor finds public constructors only.
+        } catch (NoSuchMethodException e) {
+            final String message = "No public no-arg constructor in "
+                + taskClass;
+            log(message, Project.MSG_ERR);
+            throw new BuildException(message);
+        } catch (LinkageError e) {
+            String message = "Could not load " + taskClass + ": " + e;
+            log(message, Project.MSG_ERR);
+            throw new BuildException(message, e);
+        }
+        if (!Task.class.isAssignableFrom(taskClass)) {
+            TaskAdapter.checkTaskClass(taskClass, this);
+        }
+    }
+
+    /**
+     * Return the current task definition hashtable. The returned hashtable is
+     * &quot;live&quot; and so should not be modified.
+     *
+     * @return a map of from task name to implementing class
+     *         (String to Class).
+     */
+    public Hashtable getTaskDefinitions() {
+        return ComponentHelper.getComponentHelper(this).getTaskDefinitions();
+    }
+
+    /**
+     * Add a new datatype definition.
+     * Attempting to override an existing definition with an
+     * equivalent one (i.e. with the same classname) results in
+     * a verbose log message. Attempting to override an existing definition
+     * with a different one results in a warning log message, but the
+     * definition is changed.
+     *
+     * @param typeName The name of the datatype.
+     *                 Must not be <code>null</code>.
+     * @param typeClass The full name of the class implementing the datatype.
+     *                  Must not be <code>null</code>.
+     */
+    public void addDataTypeDefinition(String typeName, Class typeClass) {
+        ComponentHelper.getComponentHelper(this).addDataTypeDefinition(typeName,
+                typeClass);
+    }
+
+    /**
+     * Return the current datatype definition hashtable. The returned
+     * hashtable is &quot;live&quot; and so should not be modified.
+     *
+     * @return a map of from datatype name to implementing class
+     *         (String to Class).
+     */
+    public Hashtable getDataTypeDefinitions() {
+        return ComponentHelper.getComponentHelper(this).getDataTypeDefinitions();
+    }
+
+    /**
+     * Add a <em>new</em> target to the project.
+     *
+     * @param target The target to be added to the project.
+     *               Must not be <code>null</code>.
+     *
+     * @exception BuildException if the target already exists in the project
+     *
+     * @see Project#addOrReplaceTarget(Target)
+     */
+    public void addTarget(Target target) throws BuildException {
+        addTarget(target.getName(), target);
+    }
+
+    /**
+     * Add a <em>new</em> target to the project.
+     *
+     * @param targetName The name to use for the target.
+     *             Must not be <code>null</code>.
+     * @param target The target to be added to the project.
+     *               Must not be <code>null</code>.
+     *
+     * @exception BuildException if the target already exists in the project.
+     *
+     * @see Project#addOrReplaceTarget(String, Target)
+     */
+     public void addTarget(String targetName, Target target)
+         throws BuildException {
+         if (targets.get(targetName) != null) {
+             throw new BuildException("Duplicate target: `" + targetName + "'");
+         }
+         addOrReplaceTarget(targetName, target);
+     }
+
+    /**
+     * Add a target to the project, or replaces one with the same
+     * name.
+     *
+     * @param target The target to be added or replaced in the project.
+     *               Must not be <code>null</code>.
+     */
+    public void addOrReplaceTarget(Target target) {
+        addOrReplaceTarget(target.getName(), target);
+    }
+
+    /**
+     * Add a target to the project, or replaces one with the same
+     * name.
+     *
+     * @param targetName The name to use for the target.
+     *                   Must not be <code>null</code>.
+     * @param target The target to be added or replaced in the project.
+     *               Must not be <code>null</code>.
+     */
+    public void addOrReplaceTarget(String targetName, Target target) {
+        String msg = " +Target: " + targetName;
+        log(msg, MSG_DEBUG);
+        target.setProject(this);
+        targets.put(targetName, target);
+    }
+
+    /**
+     * Return the hashtable of targets. The returned hashtable
+     * is &quot;live&quot; and so should not be modified.
+     * @return a map from name to target (String to Target).
+     */
+    public Hashtable getTargets() {
+        return targets;
+    }
+
+    /**
+     * Create a new instance of a task, adding it to a list of
+     * created tasks for later invalidation. This causes all tasks
+     * to be remembered until the containing project is removed
+     * @param taskType The name of the task to create an instance of.
+     *                 Must not be <code>null</code>.
+     *
+     * @return an instance of the specified task, or <code>null</code> if
+     *         the task name is not recognised.
+     *
+     * @exception BuildException if the task name is recognised but task
+     *                           creation fails.
+     */
+    public Task createTask(String taskType) throws BuildException {
+        return ComponentHelper.getComponentHelper(this).createTask(taskType);
+    }
+
+    /**
+     * Create a new instance of a data type.
+     *
+     * @param typeName The name of the data type to create an instance of.
+     *                 Must not be <code>null</code>.
+     *
+     * @return an instance of the specified data type, or <code>null</code> if
+     *         the data type name is not recognised.
+     *
+     * @exception BuildException if the data type name is recognised but
+     *                           instance creation fails.
+     */
+    public Object createDataType(String typeName) throws BuildException {
+        return ComponentHelper.getComponentHelper(this).createDataType(typeName);
+    }
+
+    /**
+     * Set the Executor instance for this Project.
+     * @param e the Executor to use.
+     */
+    public void setExecutor(Executor e) {
+        addReference(MagicNames.ANT_EXECUTOR_REFERENCE, e);
+    }
+
+    /**
+     * Get this Project's Executor (setting it if necessary).
+     * @return an Executor instance.
+     */
+    public Executor getExecutor() {
+        Object o = getReference(MagicNames.ANT_EXECUTOR_REFERENCE);
+        if (o == null) {
+            String classname = getProperty(MagicNames.ANT_EXECUTOR_CLASSNAME);
+            if (classname == null) {
+                classname = DefaultExecutor.class.getName();
+            }
+            log("Attempting to create object of type " + classname, MSG_DEBUG);
+            try {
+                o = Class.forName(classname, true, coreLoader).newInstance();
+            } catch (ClassNotFoundException seaEnEfEx) {
+                //try the current classloader
+                try {
+                    o = Class.forName(classname).newInstance();
+                } catch (Exception ex) {
+                    log(ex.toString(), MSG_ERR);
+                }
+            } catch (Exception ex) {
+                log(ex.toString(), MSG_ERR);
+            }
+            if (o == null) {
+                throw new BuildException(
+                    "Unable to obtain a Target Executor instance.");
+            }
+            setExecutor((Executor) o);
+        }
+        return (Executor) o;
+    }
+
+    /**
+     * Execute the specified sequence of targets, and the targets
+     * they depend on.
+     *
+     * @param names A vector of target name strings to execute.
+     *              Must not be <code>null</code>.
+     *
+     * @exception BuildException if the build failed.
+     */
+    public void executeTargets(Vector names) throws BuildException {
+        getExecutor().executeTargets(this,
+            (String[]) (names.toArray(new String[names.size()])));
+    }
+
+    /**
+     * Demultiplex output so that each task receives the appropriate
+     * messages. If the current thread is not currently executing a task,
+     * the message is logged directly.
+     *
+     * @param output Message to handle. Should not be <code>null</code>.
+     * @param isWarning Whether the text represents an warning (<code>true</code>)
+     *        or information (<code>false</code>).
+     */
+    public void demuxOutput(String output, boolean isWarning) {
+        Task task = getThreadTask(Thread.currentThread());
+        if (task == null) {
+            log(output, isWarning ? MSG_WARN : MSG_INFO);
+        } else {
+            if (isWarning) {
+                task.handleErrorOutput(output);
+            } else {
+                task.handleOutput(output);
+            }
+        }
+    }
+
+    /**
+     * Read data from the default input stream. If no default has been
+     * specified, System.in is used.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @since Ant 1.6
+     */
+    public int defaultInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (defaultInputStream != null) {
+            System.out.flush();
+            return defaultInputStream.read(buffer, offset, length);
+        } else {
+            throw new EOFException("No input provided for project");
+        }
+    }
+
+    /**
+     * Demux an input request to the correct task.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @since Ant 1.6
+     */
+    public int demuxInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        Task task = getThreadTask(Thread.currentThread());
+        if (task == null) {
+            return defaultInput(buffer, offset, length);
+        } else {
+            return task.handleInput(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Demultiplex flush operations so that each task receives the appropriate
+     * messages. If the current thread is not currently executing a task,
+     * the message is logged directly.
+     *
+     * @since Ant 1.5.2
+     *
+     * @param output Message to handle. Should not be <code>null</code>.
+     * @param isError Whether the text represents an error (<code>true</code>)
+     *        or information (<code>false</code>).
+     */
+    public void demuxFlush(String output, boolean isError) {
+        Task task = getThreadTask(Thread.currentThread());
+        if (task == null) {
+            fireMessageLogged(this, output, isError ? MSG_ERR : MSG_INFO);
+        } else {
+            if (isError) {
+                task.handleErrorFlush(output);
+            } else {
+                task.handleFlush(output);
+            }
+        }
+    }
+
+    /**
+     * Execute the specified target and any targets it depends on.
+     *
+     * @param targetName The name of the target to execute.
+     *                   Must not be <code>null</code>.
+     *
+     * @exception BuildException if the build failed.
+     */
+    public void executeTarget(String targetName) throws BuildException {
+
+        // sanity check ourselves, if we've been asked to build nothing
+        // then we should complain
+
+        if (targetName == null) {
+            String msg = "No target specified";
+            throw new BuildException(msg);
+        }
+
+        // Sort and run the dependency tree.
+        // Sorting checks if all the targets (and dependencies)
+        // exist, and if there is any cycle in the dependency
+        // graph.
+        executeSortedTargets(topoSort(targetName, targets, false));
+    }
+
+    /**
+     * Execute a <code>Vector</code> of sorted targets.
+     * @param sortedTargets   the aforementioned <code>Vector</code>.
+     * @throws BuildException on error.
+     */
+    public void executeSortedTargets(Vector sortedTargets)
+        throws BuildException {
+        Set succeededTargets = new HashSet();
+        BuildException buildException = null; // first build exception
+        for (Enumeration iter = sortedTargets.elements();
+             iter.hasMoreElements();) {
+            Target curtarget = (Target) iter.nextElement();
+            boolean canExecute = true;
+            for (Enumeration depIter = curtarget.getDependencies();
+                 depIter.hasMoreElements();) {
+                String dependencyName = ((String) depIter.nextElement());
+                if (!succeededTargets.contains(dependencyName)) {
+                    canExecute = false;
+                    log(curtarget,
+                        "Cannot execute '" + curtarget.getName() + "' - '"
+                        + dependencyName + "' failed or was not executed.",
+                        MSG_ERR);
+                    break;
+                }
+            }
+            if (canExecute) {
+                Throwable thrownException = null;
+                try {
+                    curtarget.performTasks();
+                    succeededTargets.add(curtarget.getName());
+                } catch (RuntimeException ex) {
+                    if (!(keepGoingMode)) {
+                        throw ex; // throw further
+                    }
+                    thrownException = ex;
+                } catch (Throwable ex) {
+                    if (!(keepGoingMode)) {
+                        throw new BuildException(ex);
+                    }
+                    thrownException = ex;
+                }
+                if (thrownException != null) {
+                    if (thrownException instanceof BuildException) {
+                        log(curtarget,
+                            "Target '" + curtarget.getName()
+                            + "' failed with message '"
+                            + thrownException.getMessage() + "'.", MSG_ERR);
+                        // only the first build exception is reported
+                        if (buildException == null) {
+                            buildException = (BuildException) thrownException;
+                        }
+                    } else {
+                        log(curtarget,
+                            "Target '" + curtarget.getName()
+                            + "' failed with message '"
+                            + thrownException.getMessage() + "'.", MSG_ERR);
+                        thrownException.printStackTrace(System.err);
+                        if (buildException == null) {
+                            buildException =
+                                new BuildException(thrownException);
+                        }
+                    }
+                }
+            }
+        }
+        if (buildException != null) {
+            throw buildException;
+        }
+    }
+
+    /**
+     * Return the canonical form of a filename.
+     * <p>
+     * If the specified file name is relative it is resolved
+     * with respect to the given root directory.
+     *
+     * @param fileName The name of the file to resolve.
+     *                 Must not be <code>null</code>.
+     *
+     * @param rootDir  The directory respective to which relative file names
+     *                 are resolved. May be <code>null</code>, in which case
+     *                 the current directory is used.
+     *
+     * @return the resolved File.
+     *
+     * @deprecated since 1.4.x
+     */
+    public File resolveFile(String fileName, File rootDir) {
+        return FILE_UTILS.resolveFile(rootDir, fileName);
+    }
+
+    /**
+     * Return the canonical form of a filename.
+     * <p>
+     * If the specified file name is relative it is resolved
+     * with respect to the project's base directory.
+     *
+     * @param fileName The name of the file to resolve.
+     *                 Must not be <code>null</code>.
+     *
+     * @return the resolved File.
+     *
+     */
+    public File resolveFile(String fileName) {
+        return FILE_UTILS.resolveFile(baseDir, fileName);
+    }
+
+    /**
+     * Translate a path into its native (platform specific) format.
+     * <p>
+     * This method uses PathTokenizer to separate the input path
+     * into its components. This handles DOS style paths in a relatively
+     * sensible way. The file separators are then converted to their platform
+     * specific versions.
+     *
+     * @param toProcess The path to be translated.
+     *                  May be <code>null</code>.
+     *
+     * @return the native version of the specified path or
+     *         an empty string if the path is <code>null</code> or empty.
+     *
+     * @deprecated since 1.7
+     *             Use FileUtils.translatePath instead.
+     *
+     * @see PathTokenizer
+     */
+    public static String translatePath(String toProcess) {
+        return FileUtils.translatePath(toProcess);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination.
+     * No filtering is performed.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(String sourceFile, String destFile)
+          throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination
+     * specifying if token filtering should be used.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(String sourceFile, String destFile, boolean filtering)
+        throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering should be used and if
+     * source files may overwrite newer destination files.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(String sourceFile, String destFile, boolean filtering,
+                         boolean overwrite) throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null, overwrite);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering should be used, if
+     * source files may overwrite newer destination files, and if the
+     * last modified time of the resulting file should be set to
+     * that of the source file.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(String sourceFile, String destFile, boolean filtering,
+                         boolean overwrite, boolean preserveLastModified)
+        throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null, overwrite, preserveLastModified);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination.
+     * No filtering is performed.
+     *
+     * @param sourceFile File to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile File to copy to.
+     *                 Must not be <code>null</code>.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(File sourceFile, File destFile) throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination
+     * specifying if token filtering should be used.
+     *
+     * @param sourceFile File to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile File to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     *
+     * @exception IOException if the copying fails.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(File sourceFile, File destFile, boolean filtering)
+        throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering should be used and if
+     * source files may overwrite newer destination files.
+     *
+     * @param sourceFile File to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile File to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     *
+     * @exception IOException if the file cannot be copied.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(File sourceFile, File destFile, boolean filtering,
+                         boolean overwrite) throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null, overwrite);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering should be used, if
+     * source files may overwrite newer destination files, and if the
+     * last modified time of the resulting file should be set to
+     * that of the source file.
+     *
+     * @param sourceFile File to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile File to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filtering Whether or not token filtering should be used during
+     *                  the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     *
+     * @exception IOException if the file cannot be copied.
+     *
+     * @deprecated since 1.4.x
+     */
+    public void copyFile(File sourceFile, File destFile, boolean filtering,
+                         boolean overwrite, boolean preserveLastModified)
+        throws IOException {
+        FILE_UTILS.copyFile(sourceFile, destFile,
+            filtering ? globalFilters : null, overwrite, preserveLastModified);
+    }
+
+    /**
+     * Call File.setLastModified(long time) on Java above 1.1, and logs
+     * a warning on Java 1.1.
+     *
+     * @param file The file to set the last modified time on.
+     *             Must not be <code>null</code>.
+     *
+     * @param time the required modification time.
+     *
+     * @deprecated since 1.4.x
+     *
+     * @exception BuildException if the last modified time cannot be set
+     *                           despite running on a platform with a version
+     *                           above 1.1.
+     */
+    public void setFileLastModified(File file, long time)
+         throws BuildException {
+        FILE_UTILS.setFileLastModified(file, time);
+        log("Setting modification time for " + file, MSG_VERBOSE);
+    }
+
+    /**
+     * Return the boolean equivalent of a string, which is considered
+     * <code>true</code> if either <code>"on"</code>, <code>"true"</code>,
+     * or <code>"yes"</code> is found, ignoring case.
+     *
+     * @param s The string to convert to a boolean value.
+     *
+     * @return <code>true</code> if the given string is <code>"on"</code>,
+     *         <code>"true"</code> or <code>"yes"</code>, or
+     *         <code>false</code> otherwise.
+     */
+    public static boolean toBoolean(String s) {
+        return ("on".equalsIgnoreCase(s)
+                || "true".equalsIgnoreCase(s)
+                || "yes".equalsIgnoreCase(s));
+    }
+
+    /**
+     * Get the Project instance associated with the specified object.
+     * @param o the object to query.
+     * @return Project instance, if any.
+     * @since Ant 1.7.1
+     */
+    public static Project getProject(Object o) {
+        if (o instanceof ProjectComponent) {
+            return ((ProjectComponent) o).getProject();
+        }
+        try {
+            Method m = o.getClass().getMethod("getProject", (Class[]) null);
+            if (Project.class == m.getReturnType()) {
+                return (Project) m.invoke(o, (Object[]) null);
+            }
+        } catch (Exception e) {
+            //too bad
+        }
+        return null;
+    }
+
+    /**
+     * Topologically sort a set of targets.  Equivalent to calling
+     * <code>topoSort(new String[] {root}, targets, true)</code>.
+     *
+     * @param root The name of the root target. The sort is created in such
+     *             a way that the sequence of Targets up to the root
+     *             target is the minimum possible such sequence.
+     *             Must not be <code>null</code>.
+     * @param targetTable A Hashtable mapping names to Targets.
+     *                Must not be <code>null</code>.
+     * @return a Vector of ALL Target objects in sorted order.
+     * @exception BuildException if there is a cyclic dependency among the
+     *                           targets, or if a named target does not exist.
+     */
+    public final Vector topoSort(String root, Hashtable targetTable)
+        throws BuildException {
+        return topoSort(new String[] {root}, targetTable, true);
+    }
+
+    /**
+     * Topologically sort a set of targets.  Equivalent to calling
+     * <code>topoSort(new String[] {root}, targets, returnAll)</code>.
+     *
+     * @param root The name of the root target. The sort is created in such
+     *             a way that the sequence of Targets up to the root
+     *             target is the minimum possible such sequence.
+     *             Must not be <code>null</code>.
+     * @param targetTable A Hashtable mapping names to Targets.
+     *                Must not be <code>null</code>.
+     * @param returnAll <code>boolean</code> indicating whether to return all
+     *                  targets, or the execution sequence only.
+     * @return a Vector of Target objects in sorted order.
+     * @exception BuildException if there is a cyclic dependency among the
+     *                           targets, or if a named target does not exist.
+     * @since Ant 1.6.3
+     */
+    public final Vector topoSort(String root, Hashtable targetTable,
+                                 boolean returnAll) throws BuildException {
+        return topoSort(new String[] {root}, targetTable, returnAll);
+    }
+
+    /**
+     * Topologically sort a set of targets.
+     *
+     * @param root <code>String[]</code> containing the names of the root targets.
+     *             The sort is created in such a way that the ordered sequence of
+     *             Targets is the minimum possible such sequence to the specified
+     *             root targets.
+     *             Must not be <code>null</code>.
+     * @param targetTable A map of names to targets (String to Target).
+     *                Must not be <code>null</code>.
+     * @param returnAll <code>boolean</code> indicating whether to return all
+     *                  targets, or the execution sequence only.
+     * @return a Vector of Target objects in sorted order.
+     * @exception BuildException if there is a cyclic dependency among the
+     *                           targets, or if a named target does not exist.
+     * @since Ant 1.6.3
+     */
+    public final Vector topoSort(String[] root, Hashtable targetTable,
+                                 boolean returnAll) throws BuildException {
+        Vector ret = new Vector();
+        Hashtable state = new Hashtable();
+        Stack visiting = new Stack();
+
+        // We first run a DFS based sort using each root as a starting node.
+        // This creates the minimum sequence of Targets to the root node(s).
+        // We then do a sort on any remaining unVISITED targets.
+        // This is unnecessary for doing our build, but it catches
+        // circular dependencies or missing Targets on the entire
+        // dependency tree, not just on the Targets that depend on the
+        // build Target.
+
+        for (int i = 0; i < root.length; i++) {
+            String st = (String) (state.get(root[i]));
+            if (st == null) {
+                tsort(root[i], targetTable, state, visiting, ret);
+            } else if (st == VISITING) {
+                throw new RuntimeException("Unexpected node in visiting state: "
+                    + root[i]);
+            }
+        }
+        StringBuffer buf = new StringBuffer("Build sequence for target(s)");
+
+        for (int j = 0; j < root.length; j++) {
+            buf.append((j == 0) ? " `" : ", `").append(root[j]).append('\'');
+        }
+        buf.append(" is " + ret);
+        log(buf.toString(), MSG_VERBOSE);
+
+        Vector complete = (returnAll) ? ret : new Vector(ret);
+        for (Enumeration en = targetTable.keys(); en.hasMoreElements();) {
+            String curTarget = (String) en.nextElement();
+            String st = (String) state.get(curTarget);
+            if (st == null) {
+                tsort(curTarget, targetTable, state, visiting, complete);
+            } else if (st == VISITING) {
+                throw new RuntimeException("Unexpected node in visiting state: "
+                    + curTarget);
+            }
+        }
+        log("Complete build sequence is " + complete, MSG_VERBOSE);
+        return ret;
+    }
+
+    /**
+     * Perform a single step in a recursive depth-first-search traversal of
+     * the target dependency tree.
+     * <p>
+     * The current target is first set to the &quot;visiting&quot; state, and
+     * pushed onto the &quot;visiting&quot; stack.
+     * <p>
+     * An exception is then thrown if any child of the current node is in the
+     * visiting state, as that implies a circular dependency. The exception
+     * contains details of the cycle, using elements of the &quot;visiting&quot;
+     * stack.
+     * <p>
+     * If any child has not already been &quot;visited&quot;, this method is
+     * called recursively on it.
+     * <p>
+     * The current target is then added to the ordered list of targets. Note
+     * that this is performed after the children have been visited in order
+     * to get the correct order. The current target is set to the
+     * &quot;visited&quot; state.
+     * <p>
+     * By the time this method returns, the ordered list contains the sequence
+     * of targets up to and including the current target.
+     *
+     * @param root The current target to inspect.
+     *             Must not be <code>null</code>.
+     * @param targetTable A mapping from names to targets (String to Target).
+     *                Must not be <code>null</code>.
+     * @param state   A mapping from target names to states (String to String).
+     *                The states in question are &quot;VISITING&quot; and
+     *                &quot;VISITED&quot;. Must not be <code>null</code>.
+     * @param visiting A stack of targets which are currently being visited.
+     *                 Must not be <code>null</code>.
+     * @param ret     The list to add target names to. This will end up
+     *                containing the complete list of dependencies in
+     *                dependency order.
+     *                Must not be <code>null</code>.
+     *
+     * @exception BuildException if a non-existent target is specified or if
+     *                           a circular dependency is detected.
+     */
+    private void tsort(String root, Hashtable targetTable,
+                             Hashtable state, Stack visiting,
+                             Vector ret)
+        throws BuildException {
+        state.put(root, VISITING);
+        visiting.push(root);
+
+        Target target = (Target) targetTable.get(root);
+
+        // Make sure we exist
+        if (target == null) {
+            StringBuffer sb = new StringBuffer("Target \"");
+            sb.append(root);
+            sb.append("\" does not exist in the project \"");
+            sb.append(name);
+            sb.append("\". ");
+            visiting.pop();
+            if (!visiting.empty()) {
+                String parent = (String) visiting.peek();
+                sb.append("It is used from target \"");
+                sb.append(parent);
+                sb.append("\".");
+            }
+            throw new BuildException(new String(sb));
+        }
+        for (Enumeration en = target.getDependencies(); en.hasMoreElements();) {
+            String cur = (String) en.nextElement();
+            String m = (String) state.get(cur);
+            if (m == null) {
+                // Not been visited
+                tsort(cur, targetTable, state, visiting, ret);
+            } else if (m == VISITING) {
+                // Currently visiting this node, so have a cycle
+                throw makeCircularException(cur, visiting);
+            }
+        }
+        String p = (String) visiting.pop();
+        if (root != p) {
+            throw new RuntimeException("Unexpected internal error: expected to "
+                + "pop " + root + " but got " + p);
+        }
+        state.put(root, VISITED);
+        ret.addElement(target);
+    }
+
+    /**
+     * Build an appropriate exception detailing a specified circular
+     * dependency.
+     *
+     * @param end The dependency to stop at. Must not be <code>null</code>.
+     * @param stk A stack of dependencies. Must not be <code>null</code>.
+     *
+     * @return a BuildException detailing the specified circular dependency.
+     */
+    private static BuildException makeCircularException(String end, Stack stk) {
+        StringBuffer sb = new StringBuffer("Circular dependency: ");
+        sb.append(end);
+        String c;
+        do {
+            c = (String) stk.pop();
+            sb.append(" <- ");
+            sb.append(c);
+        } while (!c.equals(end));
+        return new BuildException(new String(sb));
+    }
+
+    /**
+     * Inherit the id references.
+     * @param parent the parent project of this project.
+     */
+    public void inheritIDReferences(Project parent) {
+        parentIdProject = parent;
+    }
+
+    /**
+     * Add an id reference.
+     * Used for broken build files.
+     * @param id the id to set.
+     * @param value the value to set it to (Unknown element in this case.
+     */
+    public void addIdReference(String id, Object value) {
+        idReferences.put(id, value);
+    }
+
+    /**
+     * Add a reference to the project.
+     *
+     * @param referenceName The name of the reference. Must not be <code>null</code>.
+     * @param value The value of the reference.
+     */
+    public void addReference(String referenceName, Object value) {
+        synchronized (references) {
+            Object old = ((AntRefTable) references).getReal(referenceName);
+            if (old == value) {
+                // no warning, this is not changing anything
+                return;
+            }
+            if (old != null && !(old instanceof UnknownElement)) {
+                log("Overriding previous definition of reference to " + referenceName,
+                    MSG_VERBOSE);
+            }
+            log("Adding reference: " + referenceName, MSG_DEBUG);
+            references.put(referenceName, value);
+        }
+    }
+
+    /**
+     * Return a map of the references in the project (String to Object).
+     * The returned hashtable is &quot;live&quot; and so must not be modified.
+     *
+     * @return a map of the references in the project (String to Object).
+     */
+    public Hashtable getReferences() {
+        return references;
+    }
+
+    /**
+     * Look up a reference by its key (ID).
+     *
+     * @param key The key for the desired reference.
+     *            Must not be <code>null</code>.
+     *
+     * @return the reference with the specified ID, or <code>null</code> if
+     *         there is no such reference in the project.
+     */
+    public Object getReference(String key) {
+        Object ret = references.get(key);
+        if (ret != null) {
+            return ret;
+        }
+        if (!key.equals(MagicNames.REFID_PROPERTY_HELPER)) {
+            try {
+                if (PropertyHelper.getPropertyHelper(this).containsProperties(key)) {
+                    log("Unresolvable reference " + key
+                            + " might be a misuse of property expansion syntax.", MSG_WARN);
+                }
+            } catch (Exception e) {
+                //ignore
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Return a description of the type of the given element, with
+     * special handling for instances of tasks and data types.
+     * <p>
+     * This is useful for logging purposes.
+     *
+     * @param element The element to describe.
+     *                Must not be <code>null</code>.
+     *
+     * @return a description of the element type.
+     *
+     * @since 1.95, Ant 1.5
+     */
+    public String getElementName(Object element) {
+        return ComponentHelper.getComponentHelper(this).getElementName(element);
+    }
+
+    /**
+     * Send a &quot;build started&quot; event
+     * to the build listeners for this project.
+     */
+    public void fireBuildStarted() {
+        BuildEvent event = new BuildEvent(this);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.buildStarted(event);
+        }
+    }
+
+    /**
+     * Send a &quot;build finished&quot; event to the build listeners
+     * for this project.
+     * @param exception an exception indicating a reason for a build
+     *                  failure. May be <code>null</code>, indicating
+     *                  a successful build.
+     */
+    public void fireBuildFinished(Throwable exception) {
+        BuildEvent event = new BuildEvent(this);
+        event.setException(exception);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.buildFinished(event);
+        }
+        // Inform IH to clear the cache
+        IntrospectionHelper.clearCache();
+    }
+
+    /**
+     * Send a &quot;subbuild started&quot; event to the build listeners for
+     * this project.
+     *
+     * @since Ant 1.6.2
+     */
+    public void fireSubBuildStarted() {
+        BuildEvent event = new BuildEvent(this);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            Object listener = iter.next();
+            if (listener instanceof SubBuildListener) {
+                ((SubBuildListener) listener).subBuildStarted(event);
+            }
+        }
+    }
+
+    /**
+     * Send a &quot;subbuild finished&quot; event to the build listeners for
+     * this project.
+     * @param exception an exception indicating a reason for a build
+     *                  failure. May be <code>null</code>, indicating
+     *                  a successful build.
+     *
+     * @since Ant 1.6.2
+     */
+    public void fireSubBuildFinished(Throwable exception) {
+        BuildEvent event = new BuildEvent(this);
+        event.setException(exception);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            Object listener = iter.next();
+            if (listener instanceof SubBuildListener) {
+                ((SubBuildListener) listener).subBuildFinished(event);
+            }
+        }
+    }
+
+    /**
+     * Send a &quot;target started&quot; event to the build listeners
+     * for this project.
+     *
+     * @param target The target which is starting to build.
+     *               Must not be <code>null</code>.
+     */
+    protected void fireTargetStarted(Target target) {
+        BuildEvent event = new BuildEvent(target);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.targetStarted(event);
+        }
+    }
+
+    /**
+     * Send a &quot;target finished&quot; event to the build listeners
+     * for this project.
+     *
+     * @param target    The target which has finished building.
+     *                  Must not be <code>null</code>.
+     * @param exception an exception indicating a reason for a build
+     *                  failure. May be <code>null</code>, indicating
+     *                  a successful build.
+     */
+    protected void fireTargetFinished(Target target, Throwable exception) {
+        BuildEvent event = new BuildEvent(target);
+        event.setException(exception);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.targetFinished(event);
+        }
+    }
+
+    /**
+     * Send a &quot;task started&quot; event to the build listeners
+     * for this project.
+     *
+     * @param task The target which is starting to execute.
+     *               Must not be <code>null</code>.
+     */
+    protected void fireTaskStarted(Task task) {
+        // register this as the current task on the current thread.
+        registerThreadTask(Thread.currentThread(), task);
+        BuildEvent event = new BuildEvent(task);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.taskStarted(event);
+        }
+    }
+
+    /**
+     * Send a &quot;task finished&quot; event to the build listeners for this
+     * project.
+     *
+     * @param task      The task which has finished executing.
+     *                  Must not be <code>null</code>.
+     * @param exception an exception indicating a reason for a build
+     *                  failure. May be <code>null</code>, indicating
+     *                  a successful build.
+     */
+    protected void fireTaskFinished(Task task, Throwable exception) {
+        registerThreadTask(Thread.currentThread(), null);
+        System.out.flush();
+        System.err.flush();
+        BuildEvent event = new BuildEvent(task);
+        event.setException(exception);
+        Iterator iter = listeners.iterator();
+        while (iter.hasNext()) {
+            BuildListener listener = (BuildListener) iter.next();
+            listener.taskFinished(event);
+        }
+    }
+
+    /**
+     * Send a &quot;message logged&quot; event to the build listeners
+     * for this project.
+     *
+     * @param event    The event to send. This should be built up with the
+     *                 appropriate task/target/project by the caller, so that
+     *                 this method can set the message and priority, then send
+     *                 the event. Must not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param priority The priority of the message.
+     */
+    private void fireMessageLoggedEvent(BuildEvent event, String message,
+                                        int priority) {
+
+        if (message.endsWith(StringUtils.LINE_SEP)) {
+            int endIndex = message.length() - StringUtils.LINE_SEP.length();
+            event.setMessage(message.substring(0, endIndex), priority);
+        } else {
+            event.setMessage(message, priority);
+        }
+        synchronized (this) {
+            if (loggingMessage) {
+                /*
+                 * One of the Listeners has attempted to access
+                 * System.err or System.out.
+                 *
+                 * We used to throw an exception in this case, but
+                 * sometimes Listeners can't prevent it(like our own
+                 * Log4jListener which invokes getLogger() which in
+                 * turn wants to write to the console).
+                 *
+                 * @see http://marc.theaimsgroup.com/?t=110538624200006&r=1&w=2
+                 *
+                 * We now (Ant 1.7 and 1.6.3) simply swallow the message.
+                 */
+                return;
+            }
+            try {
+                loggingMessage = true;
+                Iterator iter = listeners.iterator();
+                while (iter.hasNext()) {
+                    BuildListener listener = (BuildListener) iter.next();
+                    listener.messageLogged(event);
+                }
+            } finally {
+                loggingMessage = false;
+            }
+        }
+    }
+
+    /**
+     * Send a &quot;message logged&quot; project level event
+     * to the build listeners for this project.
+     *
+     * @param project  The project generating the event.
+     *                 Should not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param priority The priority of the message.
+     */
+    protected void fireMessageLogged(Project project, String message,
+                                     int priority) {
+        fireMessageLogged(project, message, null, priority);
+    }
+
+    /**
+     * Send a &quot;message logged&quot; project level event
+     * to the build listeners for this project.
+     *
+     * @param project  The project generating the event.
+     *                 Should not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param throwable The exception that caused this message. May be <code>null</code>.
+     * @param priority The priority of the message.
+     * @since 1.7
+     */
+    protected void fireMessageLogged(Project project, String message,
+            Throwable throwable, int priority) {
+        BuildEvent event = new BuildEvent(project);
+        event.setException(throwable);
+        fireMessageLoggedEvent(event, message, priority);
+    }
+
+    /**
+     * Send a &quot;message logged&quot; target level event
+     * to the build listeners for this project.
+     *
+     * @param target   The target generating the event.
+     *                 Must not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param priority The priority of the message.
+     */
+    protected void fireMessageLogged(Target target, String message,
+                                     int priority) {
+        fireMessageLogged(target, message, null, priority);
+    }
+
+    /**
+     * Send a &quot;message logged&quot; target level event
+     * to the build listeners for this project.
+     *
+     * @param target   The target generating the event.
+     *                 Must not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param throwable The exception that caused this message. May be <code>null</code>.
+     * @param priority The priority of the message.
+     * @since 1.7
+     */
+    protected void fireMessageLogged(Target target, String message,
+            Throwable throwable, int priority) {
+        BuildEvent event = new BuildEvent(target);
+        event.setException(throwable);
+        fireMessageLoggedEvent(event, message, priority);
+    }
+
+    /**
+     * Send a &quot;message logged&quot; task level event
+     * to the build listeners for this project.
+     *
+     * @param task     The task generating the event.
+     *                 Must not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param priority The priority of the message.
+     */
+    protected void fireMessageLogged(Task task, String message, int priority) {
+        fireMessageLogged(task, message, null, priority);
+    }
+
+    /**
+     * Send a &quot;message logged&quot; task level event
+     * to the build listeners for this project.
+     *
+     * @param task     The task generating the event.
+     *                 Must not be <code>null</code>.
+     * @param message  The message to send. Should not be <code>null</code>.
+     * @param throwable The exception that caused this message. May be <code>null</code>.
+     * @param priority The priority of the message.
+     * @since 1.7
+     */
+    protected void fireMessageLogged(Task task, String message,
+            Throwable throwable, int priority) {
+        BuildEvent event = new BuildEvent(task);
+        event.setException(throwable);
+        fireMessageLoggedEvent(event, message, priority);
+    }
+
+    /**
+     * Register a task as the current task for a thread.
+     * If the task is null, the thread's entry is removed.
+     *
+     * @param thread the thread on which the task is registered.
+     * @param task the task to be registered.
+     * @since Ant 1.5
+     */
+    public synchronized void registerThreadTask(Thread thread, Task task) {
+        if (task != null) {
+            threadTasks.put(thread, task);
+            threadGroupTasks.put(thread.getThreadGroup(), task);
+        } else {
+            threadTasks.remove(thread);
+            threadGroupTasks.remove(thread.getThreadGroup());
+        }
+    }
+
+    /**
+     * Get the current task associated with a thread, if any.
+     *
+     * @param thread the thread for which the task is required.
+     * @return the task which is currently registered for the given thread or
+     *         null if no task is registered.
+     */
+    public Task getThreadTask(Thread thread) {
+        Task task = (Task) threadTasks.get(thread);
+        if (task == null) {
+            ThreadGroup group = thread.getThreadGroup();
+            while (task == null && group != null) {
+                task = (Task) threadGroupTasks.get(group);
+                group = group.getParent();
+            }
+        }
+        return task;
+    }
+
+
+    // Should move to a separate public class - and have API to add
+    // listeners, etc.
+    private static class AntRefTable extends Hashtable {
+
+        AntRefTable() {
+            super();
+        }
+
+        /** Returns the unmodified original object.
+         * This method should be called internally to
+         * get the &quot;real&quot; object.
+         * The normal get method will do the replacement
+         * of UnknownElement (this is similar with the JDNI
+         * refs behavior).
+         */
+        private Object getReal(Object key) {
+            return super.get(key);
+        }
+
+        /** Get method for the reference table.
+         *  It can be used to hook dynamic references and to modify
+         * some references on the fly--for example for delayed
+         * evaluation.
+         *
+         * It is important to make sure that the processing that is
+         * done inside is not calling get indirectly.
+         *
+         * @param key lookup key.
+         * @return mapped value.
+         */
+        public Object get(Object key) {
+            //System.out.println("AntRefTable.get " + key);
+            Object o = getReal(key);
+            if (o instanceof UnknownElement) {
+                // Make sure that
+                UnknownElement ue = (UnknownElement) o;
+                ue.maybeConfigure();
+                o = ue.getRealThing();
+            }
+            return o;
+        }
+    }
+
+    /**
+     * Set a reference to this Project on the parameterized object.
+     * Need to set the project before other set/add elements
+     * are called.
+     * @param obj the object to invoke setProject(this) on.
+     */
+    public final void setProjectReference(final Object obj) {
+        if (obj instanceof ProjectComponent) {
+            ((ProjectComponent) obj).setProject(this);
+            return;
+        }
+        try {
+            Method method =
+                obj.getClass().getMethod(
+                    "setProject", new Class[] {Project.class});
+            if (method != null) {
+                method.invoke(obj, new Object[] {this});
+            }
+        } catch (Throwable e) {
+            // ignore this if the object does not have
+            // a set project method or the method
+            // is private/protected.
+        }
+    }
+
+    /**
+     * Resolve the file relative to the project's basedir and return it as a
+     * FileResource.
+     * @param name the name of the file to resolve.
+     * @return the file resource.
+     * @since Ant 1.7
+     */
+    public Resource getResource(String name) {
+        return new FileResource(getBaseDir(), name);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/ProjectComponent.java b/trunk/src/main/org/apache/tools/ant/ProjectComponent.java
new file mode 100644
index 0000000..5d1a8ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/ProjectComponent.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+
+/**
+ * Base class for components of a project, including tasks and data types.
+ * Provides common facilities.
+ *
+ */
+public abstract class ProjectComponent implements Cloneable {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Project object of this component.
+     * @deprecated since 1.6.x.
+     *             You should not be directly accessing this variable directly.
+     *             You should access project object via the getProject()
+     *             or setProject() accessor/mutators.
+     */
+    protected Project project;
+
+    /**
+     * Location within the build file of this task definition.
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     *             Please use the {@link #getLocation()} method.
+     */
+    protected Location location = Location.UNKNOWN_LOCATION;
+
+    /**
+     * Description of this component, if any.
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     */
+    protected String description;
+    // CheckStyle:VisibilityModifier ON
+
+    /** Sole constructor. */
+    public ProjectComponent() {
+    }
+
+    /**
+     * Sets the project object of this component. This method is used by
+     * Project when a component is added to it so that the component has
+     * access to the functions of the project. It should not be used
+     * for any other purpose.
+     *
+     * @param project Project in whose scope this component belongs.
+     *                Must not be <code>null</code>.
+     */
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Returns the project to which this component belongs.
+     *
+     * @return the components's project.
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Returns the file/location where this task was defined.
+     *
+     * @return the file/location where this task was defined.
+     *         Should not return <code>null</code>. Location.UNKNOWN_LOCATION
+     *         is used for unknown locations.
+     *
+     * @see Location#UNKNOWN_LOCATION
+     */
+    public Location getLocation() {
+        return location;
+    }
+
+    /**
+     * Sets the file/location where this task was defined.
+     *
+     * @param location The file/location where this task was defined.
+     *                 Should not be <code>null</code>--use
+     *                 Location.UNKNOWN_LOCATION if the location isn't known.
+     *
+     * @see Location#UNKNOWN_LOCATION
+     */
+    public void setLocation(Location location) {
+        this.location = location;
+    }
+
+    /**
+     * Sets a description of the current action. This may be used for logging
+     * purposes.
+     *
+     * @param desc Description of the current action.
+     *             May be <code>null</code>, indicating that no description is
+     *             available.
+     *
+     */
+    public void setDescription(String desc) {
+        description = desc;
+    }
+
+    /**
+     * Returns the description of the current action.
+     *
+     * @return the description of the current action, or <code>null</code> if
+     *         no description is available.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Logs a message with the default (INFO) priority.
+     *
+     * @param msg The message to be logged. Should not be <code>null</code>.
+     */
+    public void log(String msg) {
+        log(msg, Project.MSG_INFO);
+    }
+
+    /**
+     * Logs a message with the given priority.
+     *
+     * @param msg The message to be logged. Should not be <code>null</code>.
+     * @param msgLevel the message priority at which this message is
+     *                 to be logged.
+     */
+    public void log(String msg, int msgLevel) {
+        if (getProject() != null) {
+            getProject().log(msg, msgLevel);
+        } else {
+            // 'reasonable' default, if the component is used without
+            // a Project ( for example as a standalone Bean ).
+            // Most ant components can be used this way.
+            if (msgLevel <= Project.MSG_INFO) {
+                System.err.println(msg);
+            }
+        }
+    }
+    /**
+     * @since Ant 1.7
+     * @return a shallow copy of this projectcomponent.
+     * @throws CloneNotSupportedException does not happen,
+     *                                    but is declared to allow subclasses to do so.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        ProjectComponent pc = (ProjectComponent) super.clone();
+        pc.setLocation(getLocation());
+        pc.setProject(getProject());
+        return pc;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/ProjectHelper.java b/trunk/src/main/org/apache/tools/ant/ProjectHelper.java
new file mode 100644
index 0000000..f390b95
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/ProjectHelper.java
@@ -0,0 +1,510 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+
+import org.xml.sax.AttributeList;
+
+import org.apache.tools.ant.helper.ProjectHelper2;
+import org.apache.tools.ant.util.LoaderUtils;
+
+/**
+ * Configures a Project (complete with Targets and Tasks) based on
+ * a XML build file. It'll rely on a plugin to do the actual processing
+ * of the xml file.
+ *
+ * This class also provide static wrappers for common introspection.
+ *
+ * All helper plugins must provide backward compatibility with the
+ * original ant patterns, unless a different behavior is explicitly
+ * specified. For example, if namespace is used on the &lt;project&gt; tag
+ * the helper can expect the entire build file to be namespace-enabled.
+ * Namespaces or helper-specific tags can provide meta-information to
+ * the helper, allowing it to use new ( or different policies ).
+ *
+ * However, if no namespace is used the behavior should be exactly
+ * identical with the default helper.
+ *
+ */
+public class ProjectHelper {
+    /** The URI for ant name space */
+    public static final String ANT_CORE_URI    = "antlib:org.apache.tools.ant";
+
+    /** The URI for antlib current definitions */
+    public static final String ANT_CURRENT_URI      = "ant:current";
+
+    /** The URI for defined types/tasks - the format is antlib:<package> */
+    public static final String ANTLIB_URI     = "antlib:";
+
+    /** Polymorphic attribute  */
+    public static final String ANT_TYPE = "ant-type";
+
+    /**
+     * Name of JVM system property which provides the name of the
+     * ProjectHelper class to use.
+     */
+    public static final String HELPER_PROPERTY = MagicNames.PROJECT_HELPER_CLASS;
+
+    /**
+     * The service identifier in jars which provide Project Helper
+     * implementations.
+     */
+    public static final String SERVICE_ID = MagicNames.PROJECT_HELPER_SERVICE;
+
+    /**
+     * name of project helper reference that we add to a project
+     */
+    public static final String PROJECTHELPER_REFERENCE = MagicNames.REFID_PROJECT_HELPER;
+
+    /**
+     * Configures the project with the contents of the specified XML file.
+     *
+     * @param project The project to configure. Must not be <code>null</code>.
+     * @param buildFile An XML file giving the project's configuration.
+     *                  Must not be <code>null</code>.
+     *
+     * @exception BuildException if the configuration is invalid or cannot be read
+     */
+    public static void configureProject(Project project, File buildFile) throws BuildException {
+        ProjectHelper helper = ProjectHelper.getProjectHelper();
+        project.addReference(PROJECTHELPER_REFERENCE, helper);
+        helper.parse(project, buildFile);
+    }
+
+    /** Default constructor */
+    public ProjectHelper() {
+    }
+
+    // -------------------- Common properties  --------------------
+    // The following properties are required by import ( and other tasks
+    // that read build files using ProjectHelper ).
+
+    // A project helper may process multiple files. We'll keep track
+    // of them - to avoid loops and to allow caching. The caching will
+    // probably accelerate things like <antCall>.
+    // The key is the absolute file, the value is a processed tree.
+    // Since the tree is composed of UE and RC - it can be reused !
+    // protected Hashtable processedFiles=new Hashtable();
+
+    private Vector importStack = new Vector();
+
+    // Temporary - until we figure a better API
+    /** EXPERIMENTAL WILL_CHANGE
+     *
+     */
+//    public Hashtable getProcessedFiles() {
+//        return processedFiles;
+//    }
+
+    /** EXPERIMENTAL WILL_CHANGE
+     *  Import stack.
+     *  Used to keep track of imported files. Error reporting should
+     *  display the import path.
+     *
+     * @return the stack of import source objects.
+     */
+    public Vector getImportStack() {
+        return importStack;
+    }
+
+    // --------------------  Parse method  --------------------
+    /**
+     * Parses the project file, configuring the project as it goes.
+     *
+     * @param project The project for the resulting ProjectHelper to configure.
+     *                Must not be <code>null</code>.
+     * @param source The source for XML configuration. A helper must support
+     *               at least File, for backward compatibility. Helpers may
+     *               support URL, InputStream, etc or specialized types.
+     *
+     * @since Ant1.5
+     * @exception BuildException if the configuration is invalid or cannot
+     *                           be read
+     */
+    public void parse(Project project, Object source) throws BuildException {
+        throw new BuildException("ProjectHelper.parse() must be implemented "
+            + "in a helper plugin " + this.getClass().getName());
+    }
+
+    /**
+     * Discovers a project helper instance. Uses the same patterns
+     * as JAXP, commons-logging, etc: a system property, a JDK1.3
+     * service discovery, default.
+     *
+     * @return a ProjectHelper, either a custom implementation
+     * if one is available and configured, or the default implementation
+     * otherwise.
+     *
+     * @exception BuildException if a specified helper class cannot
+     * be loaded/instantiated.
+     */
+    public static ProjectHelper getProjectHelper() throws BuildException {
+        // Identify the class loader we will be using. Ant may be
+        // in a webapp or embedded in a different app
+        ProjectHelper helper = null;
+
+        // First, try the system property
+        String helperClass = System.getProperty(HELPER_PROPERTY);
+        try {
+            if (helperClass != null) {
+                helper = newHelper(helperClass);
+            }
+        } catch (SecurityException e) {
+            System.out.println("Unable to load ProjectHelper class \""
+                + helperClass + " specified in system property "
+                + HELPER_PROPERTY);
+        }
+
+        // A JDK1.3 'service' ( like in JAXP ). That will plug a helper
+        // automatically if in CLASSPATH, with the right META-INF/services.
+        if (helper == null) {
+            try {
+                ClassLoader classLoader = LoaderUtils.getContextClassLoader();
+                InputStream is = null;
+                if (classLoader != null) {
+                    is = classLoader.getResourceAsStream(SERVICE_ID);
+                }
+                if (is == null) {
+                    is = ClassLoader.getSystemResourceAsStream(SERVICE_ID);
+                }
+                if (is != null) {
+                    // This code is needed by EBCDIC and other strange systems.
+                    // It's a fix for bugs reported in xerces
+                    InputStreamReader isr;
+                    try {
+                        isr = new InputStreamReader(is, "UTF-8");
+                    } catch (java.io.UnsupportedEncodingException e) {
+                        isr = new InputStreamReader(is);
+                    }
+                    BufferedReader rd = new BufferedReader(isr);
+
+                    String helperClassName = rd.readLine();
+                    rd.close();
+
+                    if (helperClassName != null && !"".equals(helperClassName)) {
+                        helper = newHelper(helperClassName);
+                    }
+                }
+            } catch (Exception ex) {
+                System.out.println("Unable to load ProjectHelper from service " + SERVICE_ID);
+            }
+        }
+        return helper == null ? new ProjectHelper2() : helper;
+    }
+
+    /**
+     * Creates a new helper instance from the name of the class.
+     * It'll first try the thread class loader, then Class.forName()
+     * will load from the same loader that loaded this class.
+     *
+     * @param helperClass The name of the class to create an instance
+     *                    of. Must not be <code>null</code>.
+     *
+     * @return a new instance of the specified class.
+     *
+     * @exception BuildException if the class cannot be found or
+     * cannot be appropriate instantiated.
+     */
+    private static ProjectHelper newHelper(String helperClass)
+        throws BuildException {
+        ClassLoader classLoader = LoaderUtils.getContextClassLoader();
+        try {
+            Class clazz = null;
+            if (classLoader != null) {
+                try {
+                    clazz = classLoader.loadClass(helperClass);
+                } catch (ClassNotFoundException ex) {
+                    // try next method
+                }
+            }
+            if (clazz == null) {
+                clazz = Class.forName(helperClass);
+            }
+            return ((ProjectHelper) clazz.newInstance());
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * JDK1.1 compatible access to the context class loader. Cut & paste from JAXP.
+     *
+     * @deprecated since 1.6.x.
+     *             Use LoaderUtils.getContextClassLoader()
+     *
+     * @return the current context class loader, or <code>null</code>
+     * if the context class loader is unavailable.
+     */
+    public static ClassLoader getContextClassLoader() {
+        return LoaderUtils.isContextLoaderAvailable() ? LoaderUtils.getContextClassLoader() : null;
+    }
+
+    // -------------------- Static utils, used by most helpers ----------------
+
+    /**
+     * Configures an object using an introspection handler.
+     *
+     * @param target The target object to be configured.
+     *               Must not be <code>null</code>.
+     * @param attrs  A list of attributes to configure within the target.
+     *               Must not be <code>null</code>.
+     * @param project The project containing the target.
+     *                Must not be <code>null</code>.
+     *
+     * @deprecated since 1.6.x.
+     *             Use IntrospectionHelper for each property.
+     *
+     * @exception BuildException if any of the attributes can't be handled by
+     *                           the target
+     */
+    public static void configure(Object target, AttributeList attrs,
+                                 Project project) throws BuildException {
+        if (target instanceof TypeAdapter) {
+            target = ((TypeAdapter) target).getProxy();
+        }
+        IntrospectionHelper ih = IntrospectionHelper.getHelper(project, target.getClass());
+
+        for (int i = 0, length = attrs.getLength(); i < length; i++) {
+            // reflect these into the target
+            String value = replaceProperties(project, attrs.getValue(i), project.getProperties());
+            try {
+                ih.setAttribute(project, target, attrs.getName(i).toLowerCase(Locale.US), value);
+            } catch (BuildException be) {
+                // id attribute must be set externally
+                if (!attrs.getName(i).equals("id")) {
+                    throw be;
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds the content of #PCDATA sections to an element.
+     *
+     * @param project The project containing the target.
+     *                Must not be <code>null</code>.
+     * @param target  The target object to be configured.
+     *                Must not be <code>null</code>.
+     * @param buf A character array of the text within the element.
+     *            Will not be <code>null</code>.
+     * @param start The start element in the array.
+     * @param count The number of characters to read from the array.
+     *
+     * @exception BuildException if the target object doesn't accept text
+     */
+    public static void addText(Project project, Object target, char[] buf,
+        int start, int count) throws BuildException {
+        addText(project, target, new String(buf, start, count));
+    }
+
+    /**
+     * Adds the content of #PCDATA sections to an element.
+     *
+     * @param project The project containing the target.
+     *                Must not be <code>null</code>.
+     * @param target  The target object to be configured.
+     *                Must not be <code>null</code>.
+     * @param text    Text to add to the target.
+     *                May be <code>null</code>, in which case this
+     *                method call is a no-op.
+     *
+     * @exception BuildException if the target object doesn't accept text
+     */
+    public static void addText(Project project, Object target, String text)
+        throws BuildException {
+
+        if (text == null) {
+            return;
+        }
+        if (target instanceof TypeAdapter) {
+            target = ((TypeAdapter) target).getProxy();
+        }
+        IntrospectionHelper.getHelper(project, target.getClass()).addText(project, target, text);
+    }
+
+    /**
+     * Stores a configured child element within its parent object.
+     *
+     * @param project Project containing the objects.
+     *                May be <code>null</code>.
+     * @param parent  Parent object to add child to.
+     *                Must not be <code>null</code>.
+     * @param child   Child object to store in parent.
+     *                Should not be <code>null</code>.
+     * @param tag     Name of element which generated the child.
+     *                May be <code>null</code>, in which case
+     *                the child is not stored.
+     */
+    public static void storeChild(Project project, Object parent, Object child, String tag) {
+        IntrospectionHelper ih = IntrospectionHelper.getHelper(project, parent.getClass());
+        ih.storeElement(project, parent, child, tag);
+    }
+
+    /**
+     * Replaces <code>${xxx}</code> style constructions in the given value with
+     * the string value of the corresponding properties.
+     *
+     * @param project The project containing the properties to replace.
+     *                Must not be <code>null</code>.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     *
+     * @deprecated since 1.6.x.
+     *             Use project.replaceProperties().
+     * @since 1.5
+     */
+     public static String replaceProperties(Project project, String value) throws BuildException {
+        // needed since project properties are not accessible
+         return project.replaceProperties(value);
+     }
+
+    /**
+     * Replaces <code>${xxx}</code> style constructions in the given value
+     * with the string value of the corresponding data types.
+     *
+     * @param project The container project. This is used solely for
+     *                logging purposes. Must not be <code>null</code>.
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     * @param keys  Mapping (String to String) of property names to their
+     *              values. Must not be <code>null</code>.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     * @deprecated since 1.6.x.
+     *             Use PropertyHelper.
+     */
+     public static String replaceProperties(Project project, String value, Hashtable keys)
+             throws BuildException {
+        PropertyHelper ph = PropertyHelper.getPropertyHelper(project);
+        return ph.replaceProperties(null, value, keys);
+    }
+
+    /**
+     * Parses a string containing <code>${xxx}</code> style property
+     * references into two lists. The first list is a collection
+     * of text fragments, while the other is a set of string property names.
+     * <code>null</code> entries in the first list indicate a property
+     * reference from the second list.
+     *
+     * @param value     Text to parse. Must not be <code>null</code>.
+     * @param fragments List to add text fragments to.
+     *                  Must not be <code>null</code>.
+     * @param propertyRefs List to add property names to.
+     *                     Must not be <code>null</code>.
+     *
+     * @deprecated since 1.6.x.
+     *             Use PropertyHelper.
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing <code>}</code>
+     */
+    public static void parsePropertyString(String value, Vector fragments, Vector propertyRefs)
+            throws BuildException {
+        PropertyHelper.parsePropertyStringDefault(value, fragments, propertyRefs);
+    }
+
+    /**
+     * Map a namespaced {uri,name} to an internal string format.
+     * For BC purposes the names from the ant core uri will be
+     * mapped to "name", other names will be mapped to
+     * uri + ":" + name.
+     * @param uri   The namepace URI
+     * @param name  The localname
+     * @return      The stringified form of the ns name
+     */
+    public static String genComponentName(String uri, String name) {
+        if (uri == null || uri.equals("") || uri.equals(ANT_CORE_URI)) {
+            return name;
+        }
+        return uri + ":" + name;
+    }
+
+    /**
+     * extract a uri from a component name
+     *
+     * @param componentName  The stringified form for {uri, name}
+     * @return               The uri or "" if not present
+     */
+    public static String extractUriFromComponentName(String componentName) {
+        if (componentName == null) {
+            return "";
+        }
+        int index = componentName.lastIndexOf(':');
+        if (index == -1) {
+            return "";
+        }
+        return componentName.substring(0, index);
+    }
+
+    /**
+     * extract the element name from a component name
+     *
+     * @param componentName  The stringified form for {uri, name}
+     * @return               The element name of the component
+     */
+    public static String extractNameFromComponentName(String componentName) {
+        int index = componentName.lastIndexOf(':');
+        if (index == -1) {
+            return componentName;
+        }
+        return componentName.substring(index + 1);
+    }
+
+    /**
+     * Add location to build exception.
+     * @param ex the build exception, if the build exception
+     *           does not include
+     * @param newLocation the location of the calling task (may be null)
+     * @return a new build exception based in the build exception with
+     *         location set to newLocation. If the original exception
+     *         did not have a location, just return the build exception
+     */
+    public static BuildException addLocationToBuildException(
+            BuildException ex, Location newLocation) {
+        if (ex.getLocation() == null || ex.getMessage() == null) {
+            return ex;
+        }
+        String errorMessage
+            = "The following error occurred while executing this line:"
+            + System.getProperty("line.separator")
+            + ex.getLocation().toString()
+            + ex.getMessage();
+        if (newLocation == null) {
+            return new BuildException(errorMessage, ex);
+        }
+        return new BuildException(errorMessage, ex, newLocation);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/PropertyHelper.java b/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
new file mode 100644
index 0000000..c0f926d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/PropertyHelper.java
@@ -0,0 +1,999 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Collection;
+
+import org.apache.tools.ant.property.NullReturn;
+import org.apache.tools.ant.property.GetProperty;
+import org.apache.tools.ant.property.ParseNextProperty;
+import org.apache.tools.ant.property.PropertyExpander;
+import org.apache.tools.ant.property.ParseProperties;
+
+/* ISSUES:
+ - ns param. It could be used to provide "namespaces" for properties, which
+ may be more flexible.
+ - Object value. In ant1.5 String is used for Properties - but it would be nice
+ to support generic Objects (the property remains immutable - you can't change
+ the associated object). This will also allow JSP-EL style setting using the
+ Object if an attribute contains only the property (name="${property}" could
+ avoid Object->String->Object conversion)
+ - Currently we "chain" only for get and set property (probably most users
+ will only need that - if they need more they can replace the top helper).
+ Need to discuss this and find if we need more.
+ */
+
+/* update for impending Ant 1.8:
+
+   - I can't see any reason for ns and would like to deprecate it.
+   - Replacing chaining with delegates for certain behavioral aspects.
+   - Object value seems valuable as outlined.
+
+ */
+
+/** NOT FINAL. API MAY CHANGE
+ *
+ * Deals with properties - substitution, dynamic properties, etc.
+ *
+ * This is the same code as in Ant1.5. The main addition is the ability
+ * to chain multiple PropertyHelpers and to replace the default.
+ *
+ * @since Ant 1.6
+ */
+public class PropertyHelper implements GetProperty {
+
+    //  --------------------------------------------------------
+    //
+    //    The property delegate interfaces
+    //
+    //  --------------------------------------------------------
+
+    /**
+     * Marker interface for a PropertyHelper delegate.
+     * @since Ant 1.8
+     */
+    public interface Delegate {
+    }
+
+    /**
+     * Describes an entity capable of evaluating a property name for value.
+     * @since Ant 1.8
+     */
+    public interface PropertyEvaluator extends Delegate {
+        /**
+         * Evaluate a property.
+         * @param property the property's String "identifier".
+         * @param propertyHelper the invoking PropertyHelper.
+         * @return Object value.
+         */
+        Object evaluate(String property, PropertyHelper propertyHelper);
+    }
+
+    /**
+     * Describes an entity capable of setting a property to a value.
+     * @since Ant 1.8
+     */
+    public interface PropertySetter extends Delegate {
+        /**
+         * Set a *new" property.
+         * @param property the property's String "identifier".
+         * @param value    the value to set.
+         * @param propertyHelper the invoking PropertyHelper.
+         * @return true if this entity 'owns' the property.
+         */
+        boolean setNew(
+            String property, Object value, PropertyHelper propertyHelper);
+
+        /**
+         * Set a property.
+         * @param property the property's String "identifier".
+         * @param value    the value to set.
+         * @param propertyHelper the invoking PropertyHelper.
+         * @return true if this entity 'owns' the property.
+         */
+        boolean set(
+            String property, Object value, PropertyHelper propertyHelper);
+    }
+
+
+    //  --------------------------------------------------------
+    //
+    //    The predefined property delegates
+    //
+    //  --------------------------------------------------------
+
+    private static final PropertyEvaluator TO_STRING = new PropertyEvaluator() {
+        private String prefix = "toString:";
+        public Object evaluate(String property, PropertyHelper propertyHelper) {
+            Object o = null;
+            if (property.startsWith(prefix) && propertyHelper.getProject() != null) {
+                o = propertyHelper.getProject().getReference(property.substring(prefix.length()));
+            }
+            return o == null ? null : o.toString();
+        }
+    };
+
+    private static final PropertyExpander DEFAULT_EXPANDER = new PropertyExpander() {
+        public String parsePropertyName(
+            String s, ParsePosition pos, ParseNextProperty notUsed) {
+            int index = pos.getIndex();
+            if (s.indexOf("${", index) == index) {
+                int end = s.indexOf('}', index);
+                if (end < 0) {
+                    throw new BuildException("Syntax error in property: " + s);
+                }
+                int start = index + 2;
+                pos.setIndex(end + 1);
+                return s.substring(start, end);
+            }
+            return null;
+        }
+    };
+
+    /** dummy */
+    private static final PropertyExpander SKIP_DOUBLE_DOLLAR
+        = new PropertyExpander() {
+            // CheckStyle:LineLengthCheck OFF see too long
+            /**
+             * {@inheritDoc}
+             * @see org.apache.tools.ant.PropertyHelper.PropertyExpander#parsePropertyName(java.lang.String, java.text.ParsePosition, org.apache.tools.ant.PropertyHelper)
+             */
+            // CheckStyle:LineLengthCheck ON
+            public String parsePropertyName(
+                String s, ParsePosition pos, ParseNextProperty notUsed) {
+                //System.out.println("parseproperty " + s);
+                int index = pos.getIndex();
+                if (s.indexOf("$$", index) == index) {
+                    pos.setIndex(++index);
+                }
+                return null;
+            }
+        };
+
+    private Project project;
+    private PropertyHelper next;
+    private Hashtable delegates = new Hashtable();
+
+    /** Project properties map (usually String to String). */
+    private Hashtable properties = new Hashtable();
+
+    /**
+     * Map of "user" properties (as created in the Ant task, for example).
+     * Note that these key/value pairs are also always put into the
+     * project properties, so only the project properties need to be queried.
+     */
+    private Hashtable userProperties = new Hashtable();
+
+    /**
+     * Map of inherited "user" properties - that are those "user"
+     * properties that have been created by tasks and not been set
+     * from the command line or a GUI tool.
+     */
+    private Hashtable inheritedProperties = new Hashtable();
+
+    /**
+     * Default constructor.
+     */
+    protected PropertyHelper() {
+        add(TO_STRING);
+        add(SKIP_DOUBLE_DOLLAR);
+        add(DEFAULT_EXPANDER);
+    }
+
+    //  --------------------------------------------------------
+    //
+    //    Some helper static methods to get and set properties
+    //
+    //  --------------------------------------------------------
+
+    /**
+     * A helper static method to get a property
+     * from a particular project.
+     * @param project the project in question.
+     * @param name the property name
+     * @return the value of the property if present, null otherwise.
+     * @since Ant 1.8
+     */
+    public static Object getProperty(Project project, String name) {
+        return PropertyHelper.getPropertyHelper(project)
+            .getProperty(name);
+    }
+
+    /**
+     * A helper static method to set a property
+     * from a particular project.
+     * @param project the project in question.
+     * @param name the property name
+     * @param value the value to use.
+     * @since Ant 1.8
+     */
+    public static void setProperty(Project project, String name, Object value) {
+        PropertyHelper.getPropertyHelper(project)
+            .setProperty(name, value, true);
+    }
+
+    /**
+     * A helper static method to set a new property
+     * from a particular project.
+     * @param project the project in question.
+     * @param name the property name
+     * @param value the value to use.
+     * @since Ant 1.8
+     */
+    public static void setNewProperty(
+        Project project, String name, Object value) {
+        PropertyHelper.getPropertyHelper(project)
+            .setNewProperty(name, value);
+    }
+
+    //override facility for subclasses to put custom hashtables in
+
+    // --------------------  Hook management  --------------------
+
+    /**
+     * Set the project for which this helper is performing property resolution.
+     *
+     * @param p the project instance.
+     */
+    public void setProject(Project p) {
+        this.project = p;
+    }
+
+    /**
+     * Get this PropertyHelper's Project.
+     * @return Project
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     *  There are 2 ways to hook into property handling:
+     *  - you can replace the main PropertyHelper. The replacement is required
+     * to support the same semantics (of course :-)
+     *
+     *  - you can chain a property helper capable of storing some properties.
+     *  Again, you are required to respect the immutability semantics (at
+     *  least for non-dynamic properties)
+     *
+     * @param next the next property helper in the chain.
+     * @deprecated
+     */
+    public void setNext(PropertyHelper next) {
+        this.next = next;
+    }
+
+    /**
+     * Get the next property helper in the chain.
+     *
+     * @return the next property helper.
+     * @deprecated
+     */
+    public PropertyHelper getNext() {
+        return next;
+    }
+
+    /**
+     * Factory method to create a property processor.
+     * Users can provide their own or replace it using "ant.PropertyHelper"
+     * reference. User tasks can also add themselves to the chain, and provide
+     * dynamic properties.
+     *
+     * @param project the project for which the property helper is required.
+     *
+     * @return the project's property helper.
+     */
+    public static synchronized PropertyHelper getPropertyHelper(Project project) {
+        PropertyHelper helper
+                = (PropertyHelper) project.getReference(MagicNames.REFID_PROPERTY_HELPER);
+        if (helper != null) {
+            return helper;
+        }
+        helper = new PropertyHelper();
+        helper.setProject(project);
+
+        project.addReference(MagicNames.REFID_PROPERTY_HELPER, helper);
+        return helper;
+    }
+
+    /**
+     * Get the expanders.
+     * @return the exapanders.
+     */
+    public Collection getExpanders() {
+        return getDelegates(PropertyExpander.class);
+    }
+
+
+    // --------------------  Methods to override  --------------------
+
+    /**
+     * Sets a property. Any existing property of the same name
+     * is overwritten, unless it is a user property. Will be called
+     * from setProperty().
+     *
+     * If all helpers return false, the property will be saved in
+     * the default properties table by setProperty.
+     *
+     * @param ns   The namespace that the property is in (currently
+     *             not used.
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @param inherited True if this property is inherited (an [sub]ant[call] property).
+     * @param user      True if this property is a user property.
+     * @param isNew     True is this is a new property.
+     * @return true if this helper has stored the property, false if it
+     *    couldn't. Each helper should delegate to the next one (unless it
+     *    has a good reason not to).
+     * @deprecated PropertyHelper chaining is deprecated.
+     */
+    public boolean setPropertyHook(String ns, String name,
+                                   Object value,
+                                   boolean inherited, boolean user,
+                                   boolean isNew) {
+        if (getNext() != null) {
+            boolean subst = getNext().setPropertyHook(ns, name, value, inherited, user, isNew);
+            // If next has handled the property
+            if (subst) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Get a property. If all hooks return null, the default
+     * tables will be used.
+     *
+     * @param ns namespace of the sought property.
+     * @param name name of the sought property.
+     * @param user True if this is a user property.
+     * @return The property, if returned by a hook, or null if none.
+     * @deprecated PropertyHelper chaining is deprecated.
+     */
+    public Object getPropertyHook(String ns, String name, boolean user) {
+        if (getNext() != null) {
+            Object o = getNext().getPropertyHook(ns, name, user);
+            if (o != null) {
+                return o;
+            }
+        }
+        // Experimental/Testing, will be removed
+        if (name.startsWith("toString:")) {
+            name = name.substring("toString:".length());
+            Object v = project.getReference(name);
+            return (v == null) ? null : v.toString();
+        }
+        return null;
+    }
+
+    // -------------------- Optional methods   --------------------
+    // You can override those methods if you want to optimize or
+    // do advanced things (like support a special syntax).
+    // The methods do not chain - you should use them when embedding ant
+    // (by replacing the main helper)
+
+    /**
+     * Parses a string containing <code>${xxx}</code> style property
+     * references into two lists. The first list is a collection
+     * of text fragments, while the other is a set of string property names.
+     * <code>null</code> entries in the first list indicate a property
+     * reference from the second list.
+     *
+     * It can be overridden with a more efficient or customized version.
+     *
+     * @param value     Text to parse. Must not be <code>null</code>.
+     * @param fragments List to add text fragments to.
+     *                  Must not be <code>null</code>.
+     * @param propertyRefs List to add property names to.
+     *                     Must not be <code>null</code>.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @deprecated We can do better than this.
+     */
+    public void parsePropertyString(String value, Vector fragments,
+                                    Vector propertyRefs) throws BuildException {
+        parsePropertyStringDefault(value, fragments, propertyRefs);
+    }
+
+    /**
+     * Replaces <code>${xxx}</code> style constructions in the given value
+     * with the string value of the corresponding data types.
+     *
+     * @param ns    The namespace for the property.
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     * @param keys  Mapping (String to String) of property names to their
+     *              values. If <code>null</code>, only project properties will
+     *              be used.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     */
+    public String replaceProperties(String ns, String value, Hashtable keys) throws BuildException {
+        return replaceProperties(value);
+    }
+
+    /**
+     * Replaces <code>${xxx}</code> style constructions in the given value
+     * with the string value of the corresponding data types.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     */
+    public String replaceProperties(String value) throws BuildException {
+        Object o = parseProperties(value);
+        return o == null || o instanceof String ? (String) o : o.toString();
+    }
+
+    /**
+     * Decode properties from a String representation.  If the entire
+     * contents of the String resolve to a single property, that value
+     * is returned.  Otherwise a String is returned.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     *
+     * @exception BuildException if the string contains an opening
+     *                           <code>${</code> without a closing
+     *                           <code>}</code>
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     */
+    public Object parseProperties(String value) throws BuildException {
+        return new ParseProperties(getProject(), getExpanders(), this)
+            .parseProperties(value);
+    }
+
+    /**
+     * Learn whether a String contains replaceable properties.
+     * @param value the String to check.
+     * @return <code>true</code> if <code>value</code> contains property notation.
+     */
+    public boolean containsProperties(String value) {
+        return new ParseProperties(getProject(), getExpanders(), this)
+            .containsProperties(value);
+    }
+
+    // -------------------- Default implementation  --------------------
+    // Methods used to support the default behavior and provide backward
+    // compatibility. Some will be deprecated, you should avoid calling them.
+
+    /**
+     * Default implementation of setProperty. Will be called from Project.
+     * This is the original 1.5 implementation, with calls to the hook
+     * added.
+     * @param ns      The namespace for the property (currently not used).
+     * @param name    The name of the property.
+     * @param value   The value to set the property to.
+     * @param verbose If this is true output extra log messages.
+     * @return true if the property is set.
+     * @deprecated namespaces are unnecessary.
+     */
+    public boolean setProperty(String ns, String name, Object value, boolean verbose) {
+        return setProperty(name, value, verbose);
+    }
+
+    /**
+     * Default implementation of setProperty. Will be called from Project.
+     *  This is the original 1.5 implementation, with calls to the hook
+     *  added.
+     *  @param name    The name of the property.
+     *  @param value   The value to set the property to.
+     *  @param verbose If this is true output extra log messages.
+     *  @return true if the property is set.
+     */
+    public synchronized boolean setProperty(String name, Object value, boolean verbose) {
+        for (Iterator iter = getDelegates(PropertySetter.class).iterator();
+             iter.hasNext();) {
+            PropertySetter setter = (PropertySetter) iter.next();
+            if (setter.set(name, value, this)) {
+                return true;
+            }
+        }
+        // user (CLI) properties take precedence
+        if (null != userProperties.get(name)) {
+            if (verbose) {
+                project.log("Override ignored for user property \"" + name
+                        + "\"", Project.MSG_VERBOSE);
+            }
+            return false;
+        }
+
+//        boolean done = setPropertyHook(ns, name, value, false, false, false);
+//        if (done) {
+//            return true;
+//        }
+
+        if (null != properties.get(name) && verbose) {
+            project.log("Overriding previous definition of property \"" + name
+                    + "\"", Project.MSG_VERBOSE);
+        }
+
+        if (verbose) {
+            project.log("Setting project property: " + name + " -> "
+                    + value, Project.MSG_DEBUG);
+        }
+        if (name != null && value != null) {
+            properties.put(name, value);
+        }
+        return true;
+    }
+
+    /**
+     * Sets a property if no value currently exists. If the property
+     * exists already, a message is logged and the method returns with
+     * no other effect.
+     *
+     * @param ns   The namespace for the property (currently not used).
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @since Ant 1.6
+     * @deprecated namespaces are unnecessary.
+     */
+    public void setNewProperty(String ns, String name, Object value) {
+        setNewProperty(name, value);
+    }
+
+    /**
+     * Sets a property if no value currently exists. If the property
+     * exists already, a message is logged and the method returns with
+     * no other effect.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @since Ant 1.8
+     */
+    public synchronized void setNewProperty(String name, Object value) {
+        for (Iterator iter = getDelegates(PropertySetter.class).iterator();
+             iter.hasNext();) {
+            PropertySetter setter = (PropertySetter) iter.next();
+            if (setter.setNew(name, value, this)) {
+                return;
+            }
+        }
+        if (null != properties.get(name)) {
+            project.log("Override ignored for property \"" + name + "\"", Project.MSG_VERBOSE);
+            return;
+        }
+//        boolean done = setPropertyHook(ns, name, value, false, false, true);
+//        if (done) {
+//            return;
+//        }
+        project.log("Setting project property: " + name + " -> " + value, Project.MSG_DEBUG);
+        if (name != null && value != null) {
+            properties.put(name, value);
+        }
+    }
+
+    /**
+     * Sets a user property, which cannot be overwritten by
+     * set/unset property calls. Any previous value is overwritten.
+     * @param ns   The namespace for the property (currently not used).
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @deprecated namespaces are unnecessary.
+     */
+    public void setUserProperty(String ns, String name, Object value) {
+        setUserProperty(name, value);
+    }
+
+    /**
+     * Sets a user property, which cannot be overwritten by
+     * set/unset property calls. Any previous value is overwritten.
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     */
+    public synchronized void setUserProperty(String name, Object value) {
+        project.log("Setting ro project property: " + name + " -> " + value, Project.MSG_DEBUG);
+        userProperties.put(name, value);
+
+//        boolean done = setPropertyHook(ns, name, value, false, true, false);
+//        if (done) {
+//            return;
+//        }
+        properties.put(name, value);
+    }
+
+    /**
+     * Sets an inherited user property, which cannot be overwritten by set/unset
+     * property calls. Any previous value is overwritten. Also marks
+     * these properties as properties that have not come from the
+     * command line.
+     *
+     * @param ns   The namespace for the property (currently not used).
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     * @deprecated namespaces are unnecessary.
+     */
+    public void setInheritedProperty(String ns, String name, Object value) {
+        setInheritedProperty(name, value);
+    }
+
+    /**
+     * Sets an inherited user property, which cannot be overwritten by set/unset
+     * property calls. Any previous value is overwritten. Also marks
+     * these properties as properties that have not come from the
+     * command line.
+     *
+     * @param name The name of property to set.
+     *             Must not be <code>null</code>.
+     * @param value The new value of the property.
+     *              Must not be <code>null</code>.
+     */
+    public synchronized void setInheritedProperty(String name, Object value) {
+        inheritedProperties.put(name, value);
+
+        project.log("Setting ro project property: " + name + " -> " + value, Project.MSG_DEBUG);
+        userProperties.put(name, value);
+
+//        boolean done = setPropertyHook(ns, name, value, true, false, false);
+//        if (done) {
+//            return;
+//        }
+        properties.put(name, value);
+    }
+
+    // -------------------- Getting properties  --------------------
+
+    /**
+     * Returns the value of a property, if it is set.  You can override
+     * this method in order to plug your own storage.
+     *
+     * @param ns   The namespace for the property (currently not used).
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     * @deprecated namespaces are unnecessary.
+     */
+    public synchronized Object getProperty(String ns, String name) {
+        return getProperty(name);
+    }
+
+    /**
+     * Returns the value of a property, if it is set.  You can override
+     * this method in order to plug your own storage.
+     *
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+    public synchronized Object getProperty(String name) {
+        if (name == null) {
+            return null;
+        }
+        for (Iterator iter = getDelegates(PropertyEvaluator.class).iterator(); iter.hasNext();) {
+            Object o = ((PropertyEvaluator) iter.next()).evaluate(name, this);
+            if (o != null) {
+                if (o instanceof NullReturn) {
+                    return null;
+                }
+                return o;
+            }
+        }
+//        Object o = getPropertyHook(ns, name, false);
+//        if (o != null) {
+//            return o;
+//        }
+        return properties.get(name);
+    }
+
+    /**
+     * Returns the value of a user property, if it is set.
+     *
+     * @param ns   The namespace for the property (currently not used).
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     * @deprecated namespaces are unnecessary.
+     */
+    public Object getUserProperty(String ns, String name) {
+        return getUserProperty(name);
+    }
+
+    /**
+     * Returns the value of a user property, if it is set.
+     *
+     * @param name The name of the property.
+     *             May be <code>null</code>, in which case
+     *             the return value is also <code>null</code>.
+     * @return the property value, or <code>null</code> for no match
+     *         or if a <code>null</code> name is provided.
+     */
+    public synchronized Object getUserProperty(String name) {
+        if (name == null) {
+            return null;
+        }
+/*
+        Object o = getPropertyHook(ns, name, true);
+        if (o != null) {
+            return o;
+        }
+*/
+        return userProperties.get(name);
+    }
+
+    // -------------------- Access to property tables  --------------------
+    // This is used to support ant call and similar tasks. It should be
+    // deprecated, it is possible to use a better (more efficient)
+    // mechanism to preserve the context.
+
+    /**
+     * Returns a copy of the properties table.
+     * @return a hashtable containing all properties (including user properties).
+     */
+    public Hashtable getProperties() {
+        //avoid concurrent modification:
+        synchronized (properties) {
+            return new Hashtable(properties);
+        }
+        // There is a better way to save the context. This shouldn't
+        // delegate to next, it's for backward compatibility only.
+    }
+
+    /**
+     * Returns a copy of the user property hashtable
+     * @return a hashtable containing just the user properties
+     */
+    public Hashtable getUserProperties() {
+        //avoid concurrent modification:
+        synchronized (userProperties) {
+            return new Hashtable(userProperties);
+        }
+    }
+
+    /**
+     * special back door for subclasses, internal access to the hashtables
+     * @return the live hashtable of all properties
+     */
+    protected Hashtable getInternalProperties() {
+        return properties;
+    }
+
+    /**
+     * special back door for subclasses, internal access to the hashtables
+     *
+     * @return the live hashtable of user properties
+     */
+    protected Hashtable getInternalUserProperties() {
+        return userProperties;
+    }
+
+    /**
+     * special back door for subclasses, internal access to the hashtables
+     *
+     * @return the live hashtable inherited properties
+     */
+    protected Hashtable getInternalInheritedProperties() {
+        return inheritedProperties;
+    }
+
+    /**
+     * Copies all user properties that have not been set on the
+     * command line or a GUI tool from this instance to the Project
+     * instance given as the argument.
+     *
+     * <p>To copy all "user" properties, you will also have to call
+     * {@link #copyUserProperties copyUserProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.6
+     */
+    public void copyInheritedProperties(Project other) {
+        //avoid concurrent modification:
+        synchronized (inheritedProperties) {
+            Enumeration e = inheritedProperties.keys();
+            while (e.hasMoreElements()) {
+                String arg = e.nextElement().toString();
+                if (other.getUserProperty(arg) != null) {
+                    continue;
+                }
+                Object value = inheritedProperties.get(arg);
+                other.setInheritedProperty(arg, value.toString());
+            }
+        }
+    }
+
+    /**
+     * Copies all user properties that have been set on the command
+     * line or a GUI tool from this instance to the Project instance
+     * given as the argument.
+     *
+     * <p>To copy all "user" properties, you will also have to call
+     * {@link #copyInheritedProperties copyInheritedProperties}.</p>
+     *
+     * @param other the project to copy the properties to.  Must not be null.
+     *
+     * @since Ant 1.6
+     */
+    public void copyUserProperties(Project other) {
+        //avoid concurrent modification:
+        synchronized (userProperties) {
+            Enumeration e = userProperties.keys();
+            while (e.hasMoreElements()) {
+                Object arg = e.nextElement();
+                if (inheritedProperties.containsKey(arg)) {
+                    continue;
+                }
+                Object value = userProperties.get(arg);
+                other.setUserProperty(arg.toString(), value.toString());
+            }
+        }
+    }
+
+    // -------------------- Property parsing  --------------------
+    // Moved from ProjectHelper. You can override the static method -
+    // this is used for backward compatibility (for code that calls
+    // the parse method in ProjectHelper).
+
+    /**
+     * Default parsing method. It is here only to support backward compatibility
+     * for the static ProjectHelper.parsePropertyString().
+     */
+    static void parsePropertyStringDefault(String value, Vector fragments, Vector propertyRefs)
+            throws BuildException {
+        int prev = 0;
+        int pos;
+        //search for the next instance of $ from the 'prev' position
+        while ((pos = value.indexOf("$", prev)) >= 0) {
+
+            //if there was any text before this, add it as a fragment
+            //TODO, this check could be modified to go if pos>prev;
+            //seems like this current version could stick empty strings
+            //into the list
+            if (pos > 0) {
+                fragments.addElement(value.substring(prev, pos));
+            }
+            //if we are at the end of the string, we tack on a $
+            //then move past it
+            if (pos == (value.length() - 1)) {
+                fragments.addElement("$");
+                prev = pos + 1;
+            } else if (value.charAt(pos + 1) != '{') {
+                //peek ahead to see if the next char is a property or not
+                //not a property: insert the char as a literal
+                /*
+                fragments.addElement(value.substring(pos + 1, pos + 2));
+                prev = pos + 2;
+                */
+                if (value.charAt(pos + 1) == '$') {
+                    //backwards compatibility two $ map to one mode
+                    fragments.addElement("$");
+                    prev = pos + 2;
+                } else {
+                    //new behaviour: $X maps to $X for all values of X!='$'
+                    fragments.addElement(value.substring(pos, pos + 2));
+                    prev = pos + 2;
+                }
+            } else {
+                //property found, extract its name or bail on a typo
+                int endName = value.indexOf('}', pos);
+                if (endName < 0) {
+                    throw new BuildException("Syntax error in property: " + value);
+                }
+                String propertyName = value.substring(pos + 2, endName);
+                fragments.addElement(null);
+                propertyRefs.addElement(propertyName);
+                prev = endName + 1;
+            }
+        }
+        //no more $ signs found
+        //if there is any tail to the file, append it
+        if (prev < value.length()) {
+            fragments.addElement(value.substring(prev));
+        }
+    }
+
+    /**
+     * Add the specified delegate object to this PropertyHelper.
+     * Delegates are processed in LIFO order.
+     * @param delegate the delegate to add.
+     * @since Ant 1.8
+     */
+    public synchronized void add(Delegate delegate) {
+        for (Iterator iter = getDelegateInterfaces(delegate).iterator(); iter.hasNext();) {
+            Object key = iter.next();
+            List list = (List) delegates.get(key);
+            if (list == null) {
+                list = new ArrayList();
+                delegates.put(key, list);
+            }
+            if (list.contains(delegate)) {
+                list.remove(delegate);
+            }
+            list.add(0, delegate);
+        }
+    }
+
+    /**
+     * Get the Collection of delegates of the specified type.
+     * @param type delegate type.
+     * @return Collection.
+     * @since Ant 1.8
+     */
+    protected synchronized List getDelegates(Class type) {
+        return delegates.containsKey(type)
+                ? (List) new ArrayList((List) delegates.get(type)) : Collections.EMPTY_LIST;
+    }
+
+    /**
+     * Get all Delegate interfaces (excluding Delegate itself) from the specified Delegate.
+     * @param d the Delegate to inspect.
+     * @return Set<Class>
+     * @since Ant 1.8
+     */
+    protected Set getDelegateInterfaces(Delegate d) {
+        HashSet result = new HashSet();
+        Class c = d.getClass();
+        while (c != null) {
+            Class[] ifs = c.getInterfaces();
+            for (int i = 0; i < ifs.length; i++) {
+                if (Delegate.class.isAssignableFrom(ifs[i])) {
+                    result.add(ifs[i]);
+                }
+            }
+            c = c.getSuperclass();
+        }
+        result.remove(Delegate.class);
+        return result;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java b/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java
new file mode 100644
index 0000000..be1de7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/RuntimeConfigurable.java
@@ -0,0 +1,475 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Iterator;
+
+import org.apache.tools.ant.util.CollectionUtils;
+import org.xml.sax.AttributeList;
+import org.xml.sax.helpers.AttributeListImpl;
+
+/**
+ * Wrapper class that holds the attributes of an element, its children, and
+ * any text within it. It then takes care of configuring that element at
+ * runtime.
+ *
+ */
+public class RuntimeConfigurable implements Serializable {
+
+    /** Empty Hashtable. */
+    private static final Hashtable EMPTY_HASHTABLE = new Hashtable(0);
+
+    /** Name of the element to configure. */
+    private String elementTag = null;
+
+    /** List of child element wrappers. */
+    private List/*<RuntimeConfigurable>*/ children = null;
+
+    /** The element to configure. It is only used during
+     * maybeConfigure.
+     */
+    private transient Object wrappedObject = null;
+
+    /** the creator used to make the wrapped object */
+    private transient IntrospectionHelper.Creator creator;
+
+    /**
+     * XML attributes for the element.
+     * @deprecated since 1.6.x
+     */
+    private transient AttributeList attributes;
+
+    /** Attribute names and values. While the XML spec doesn't require
+     *  preserving the order ( AFAIK ), some ant tests do rely on the
+     *  exact order. The following code is copied from AttributeImpl.
+     *  We could also just use SAX2 Attributes and convert to SAX1 ( DOM
+     *  attribute Nodes can also be stored in SAX2 Attributes )
+     *  XXX under JDK 1.4 you can just use a LinkedHashMap for this purpose -jglick
+     * The only exception to this order is the treatment of
+     * refid. A number of datatypes check if refid is set
+     * when other attributes are set. This check will not
+     * work if the build script has the other attribute before
+     * the "refid" attribute, so now (ANT 1.7) the refid
+     * attribute will be processed first.
+     */
+    private List/*<String>*/ attributeNames = null;
+
+    /** Map of attribute names to values */
+    private Map/*<String,String>*/ attributeMap = null;
+
+    /** Text appearing within the element. */
+    private StringBuffer characters = null;
+
+    /** Indicates if the wrapped object has been configured */
+    private boolean proxyConfigured = false;
+
+    /** the polymorphic type */
+    private String polyType = null;
+
+    /** the "id" of this Element if it has one */
+    private String id = null;
+
+    /**
+     * Sole constructor creating a wrapper for the specified object.
+     *
+     * @param proxy The element to configure. Must not be <code>null</code>.
+     * @param elementTag The tag name generating this element.
+     */
+    public RuntimeConfigurable(Object proxy, String elementTag) {
+        setProxy(proxy);
+        setElementTag(elementTag);
+        // Most likely an UnknownElement
+        if (proxy instanceof Task) {
+            ((Task) proxy).setRuntimeConfigurableWrapper(this);
+        }
+    }
+
+    /**
+     * Sets the element to configure.
+     *
+     * @param proxy The element to configure. Must not be <code>null</code>.
+     */
+    public synchronized void setProxy(Object proxy) {
+        wrappedObject = proxy;
+        proxyConfigured = false;
+    }
+
+    /**
+     * Sets the creator of the element to be configured
+     * used to store the element in the parent.
+     *
+     * @param creator the creator object.
+     */
+    synchronized void setCreator(IntrospectionHelper.Creator creator) {
+        this.creator = creator;
+    }
+
+    /**
+     * Get the object for which this RuntimeConfigurable holds the configuration
+     * information.
+     *
+     * @return the object whose configure is held by this instance.
+     */
+    public synchronized Object getProxy() {
+        return wrappedObject;
+    }
+
+    /**
+     * Returns the id for this element.
+     * @return the id.
+     */
+    public synchronized String getId() {
+        return id;
+    }
+
+    /**
+     * Get the polymorphic type for this element.
+     * @return the ant component type name, null if not set.
+     */
+    public synchronized String getPolyType() {
+        return polyType;
+    }
+
+    /**
+     * Set the polymorphic type for this element.
+     * @param polyType the ant component type name, null if not set.
+     */
+    public synchronized void setPolyType(String polyType) {
+        this.polyType = polyType;
+    }
+
+    /**
+     * Sets the attributes for the wrapped element.
+     *
+     * @deprecated since 1.6.x.
+     * @param attributes List of attributes defined in the XML for this
+     *                   element. May be <code>null</code>.
+     */
+    public synchronized void setAttributes(AttributeList attributes) {
+        this.attributes = new AttributeListImpl(attributes);
+        for (int i = 0; i < attributes.getLength(); i++) {
+            setAttribute(attributes.getName(i), attributes.getValue(i));
+        }
+    }
+
+    /**
+     * Set an attribute to a given value.
+     *
+     * @param name the name of the attribute.
+     * @param value the attribute's value.
+     */
+    public synchronized void setAttribute(String name, String value) {
+        if (name.equalsIgnoreCase(ProjectHelper.ANT_TYPE)) {
+            this.polyType = value;
+        } else {
+            if (attributeNames == null) {
+                attributeNames = new ArrayList();
+                attributeMap = new HashMap();
+            }
+            if (name.toLowerCase(Locale.US).equals("refid")) {
+                attributeNames.add(0, name);
+            } else {
+                attributeNames.add(name);
+            }
+            attributeMap.put(name, value);
+            if (name.equals("id")) {
+                this.id = value;
+            }
+        }
+    }
+
+    /**
+     * Delete an attribute.  Not for the faint of heart.
+     * @param name the name of the attribute to be removed.
+     */
+    public synchronized void removeAttribute(String name) {
+        attributeNames.remove(name);
+        attributeMap.remove(name);
+    }
+
+    /**
+     * Return the attribute map.
+     *
+     * @return Attribute name to attribute value map.
+     * @since Ant 1.6
+     */
+    public synchronized Hashtable getAttributeMap() {
+        return (attributeMap == null)
+            ? EMPTY_HASHTABLE : new Hashtable(attributeMap);
+    }
+
+    /**
+     * Returns the list of attributes for the wrapped element.
+     *
+     * @deprecated Deprecated since Ant 1.6 in favor of {@link #getAttributeMap}.
+     * @return An AttributeList representing the attributes defined in the
+     *         XML for this element. May be <code>null</code>.
+     */
+    public synchronized AttributeList getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Adds a child element to the wrapped element.
+     *
+     * @param child The child element wrapper to add to this one.
+     *              Must not be <code>null</code>.
+     */
+    public synchronized void addChild(RuntimeConfigurable child) {
+        children = (children == null) ? new ArrayList() : children;
+        children.add(child);
+    }
+
+    /**
+     * Returns the child wrapper at the specified position within the list.
+     *
+     * @param index The index of the child to return.
+     *
+     * @return The child wrapper at position <code>index</code> within the
+     *         list.
+     */
+    synchronized RuntimeConfigurable getChild(int index) {
+        return (RuntimeConfigurable) children.get(index);
+    }
+
+    /**
+     * Returns an enumeration of all child wrappers.
+     * @return an enumeration of the child wrappers.
+     * @since Ant 1.6
+     */
+    public synchronized Enumeration getChildren() {
+        return (children == null) ? new CollectionUtils.EmptyEnumeration()
+            : Collections.enumeration(children);
+    }
+
+    /**
+     * Adds characters from #PCDATA areas to the wrapped element.
+     *
+     * @param data Text to add to the wrapped element.
+     *        Should not be <code>null</code>.
+     */
+    public synchronized void addText(String data) {
+        if (data.length() == 0) {
+            return;
+        }
+        characters = (characters == null)
+            ? new StringBuffer(data) : characters.append(data);
+    }
+
+    /**
+     * Adds characters from #PCDATA areas to the wrapped element.
+     *
+     * @param buf A character array of the text within the element.
+     *            Must not be <code>null</code>.
+     * @param start The start element in the array.
+     * @param count The number of characters to read from the array.
+     *
+     */
+    public synchronized void addText(char[] buf, int start, int count) {
+        if (count == 0) {
+            return;
+        }
+        characters = ((characters == null)
+            ? new StringBuffer(count) : characters).append(buf, start, count);
+    }
+
+    /**
+     * Get the text content of this element. Various text chunks are
+     * concatenated, there is no way ( currently ) of keeping track of
+     * multiple fragments.
+     *
+     * @return the text content of this element.
+     * @since Ant 1.6
+     */
+    public synchronized StringBuffer getText() {
+        return (characters == null) ? new StringBuffer(0) : characters;
+    }
+
+    /**
+     * Set the element tag.
+     * @param elementTag The tag name generating this element.
+     */
+    public synchronized void setElementTag(String elementTag) {
+        this.elementTag = elementTag;
+    }
+
+    /**
+     * Returns the tag name of the wrapped element.
+     *
+     * @return The tag name of the wrapped element. This is unlikely
+     *         to be <code>null</code>, but may be.
+     */
+    public synchronized String getElementTag() {
+        return elementTag;
+    }
+
+    /**
+     * Configures the wrapped element and all its children.
+     * The attributes and text for the wrapped element are configured,
+     * and then each child is configured and added. Each time the
+     * wrapper is configured, the attributes and text for it are
+     * reset.
+     *
+     * If the element has an <code>id</code> attribute, a reference
+     * is added to the project as well.
+     *
+     * @param p The project containing the wrapped element.
+     *          Must not be <code>null</code>.
+     *
+     * @exception BuildException if the configuration fails, for instance due
+     *            to invalid attributes or children, or text being added to
+     *            an element which doesn't accept it.
+     */
+    public void maybeConfigure(Project p) throws BuildException {
+        maybeConfigure(p, true);
+    }
+
+    /**
+     * Configures the wrapped element.  The attributes and text for
+     * the wrapped element are configured.  Each time the wrapper is
+     * configured, the attributes and text for it are reset.
+     *
+     * If the element has an <code>id</code> attribute, a reference
+     * is added to the project as well.
+     *
+     * @param p The project containing the wrapped element.
+     *          Must not be <code>null</code>.
+     *
+     * @param configureChildren ignored.
+
+     *
+     * @exception BuildException if the configuration fails, for instance due
+     *            to invalid attributes , or text being added to
+     *            an element which doesn't accept it.
+     */
+    public synchronized void maybeConfigure(Project p, boolean configureChildren)
+        throws BuildException {
+
+        if (proxyConfigured) {
+            return;
+        }
+
+        // Configure the object
+        Object target = (wrappedObject instanceof TypeAdapter)
+            ? ((TypeAdapter) wrappedObject).getProxy() : wrappedObject;
+
+        IntrospectionHelper ih =
+            IntrospectionHelper.getHelper(p, target.getClass());
+
+        if (attributeNames != null) {
+            for (int i = 0; i < attributeNames.size(); i++) {
+                String name = (String) attributeNames.get(i);
+                String value = (String) attributeMap.get(name);
+
+                // reflect these into the target
+                Object attrValue = PropertyHelper.getPropertyHelper(p).parseProperties(value);
+                try {
+                    ih.setAttribute(p, target, name, attrValue);
+                } catch (UnsupportedAttributeException be) {
+                    // id attribute must be set externally
+                    if (name.equals("id")) {
+                        // Do nothing
+                    } else  if (getElementTag() == null) {
+                        throw be;
+                    } else {
+                        throw new BuildException(
+                            getElementTag() +  " doesn't support the \""
+                            + be.getAttribute() + "\" attribute", be);
+                    }
+                } catch (BuildException be) {
+                    if (name.equals("id")) {
+                        // Assume that this is an not supported attribute type
+                        // thrown for example by a dymanic attribute task
+                        // Do nothing
+                    } else {
+                        throw be;
+                    }
+                }
+            }
+        }
+
+        if (characters != null) {
+            ProjectHelper.addText(p, wrappedObject, characters.substring(0));
+        }
+
+        if (id != null) {
+            p.addReference(id, wrappedObject);
+        }
+        proxyConfigured = true;
+    }
+
+    /**
+     * Reconfigure the element, even if it has already been configured.
+     *
+     * @param p the project instance for this configuration.
+     */
+    public void reconfigure(Project p) {
+        proxyConfigured = false;
+        maybeConfigure(p);
+    }
+
+
+    /**
+     * Apply presets, attributes and text are set if not currently set.
+     * Nested elements are prepended.
+     *
+     * @param r a <code>RuntimeConfigurable</code> value.
+     */
+    public void applyPreSet(RuntimeConfigurable r) {
+        // Attributes
+        if (r.attributeMap != null) {
+            for (Iterator i = r.attributeMap.keySet().iterator(); i.hasNext();) {
+                String name = (String) i.next();
+                if (attributeMap == null || attributeMap.get(name) == null) {
+                    setAttribute(name, (String) r.attributeMap.get(name));
+                }
+            }
+        }
+        // poly type
+
+        polyType = (polyType == null) ? r.polyType : polyType;
+
+        // Children (this is a shadow of UnknownElement#children)
+        if (r.children != null) {
+            List newChildren = new ArrayList();
+            newChildren.addAll(r.children);
+            if (children != null) {
+                newChildren.addAll(children);
+            }
+            children = newChildren;
+        }
+
+        // Text
+        if (r.characters != null) {
+            if (characters == null
+                || characters.toString().trim().length() == 0) {
+                characters = new StringBuffer(r.characters.toString());
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/SubBuildListener.java b/trunk/src/main/org/apache/tools/ant/SubBuildListener.java
new file mode 100644
index 0000000..196a88b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/SubBuildListener.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Instances of classes that implement this interface can register
+ * to be also notified when things happened during a subbuild.
+ *
+ * <p>A subbuild is a separate project instance created by the
+ * <code>&lt;ant&gt;</code> task family.  These project instances will
+ * never fire the buildStarted and buildFinished events, but they will
+ * fire subBuildStarted/ and subBuildFinished.  The main project
+ * instance - the one created by running Ant in the first place - will
+ * never invoke one of the methods of this interface.</p>
+ *
+ * @see BuildEvent
+ * @see Project#addBuildListener(BuildListener)
+ *
+ * @since Ant 1.6.2
+ */
+public interface SubBuildListener extends BuildListener {
+
+    /**
+     * Signals that a subbuild has started. This event
+     * is fired before any targets have started.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     */
+    void subBuildStarted(BuildEvent event);
+
+    /**
+     * Signals that the last target has finished. This event
+     * will still be fired if an error occurred during the build.
+     *
+     * @param event An event with any relevant extra information.
+     *              Must not be <code>null</code>.
+     *
+     * @see BuildEvent#getException()
+     */
+    void subBuildFinished(BuildEvent event);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/Target.java b/trunk/src/main/org/apache/tools/ant/Target.java
new file mode 100644
index 0000000..cf09934
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Target.java
@@ -0,0 +1,451 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Class to implement a target object with required parameters.
+ *
+ */
+public class Target implements TaskContainer {
+
+    /** Name of this target. */
+    private String name;
+
+    /** The "if" condition to test on execution. */
+    private String ifCondition = "";
+
+    /** The "unless" condition to test on execution. */
+    private String unlessCondition = "";
+
+    /** List of targets this target is dependent on. */
+    private List dependencies = null;
+
+    /** Children of this target (tasks and data types). */
+    private List children = new ArrayList();
+
+    /** Since Ant 1.6.2 */
+    private Location location = Location.UNKNOWN_LOCATION;
+
+    /** Project this target belongs to. */
+    private Project project;
+
+    /** Description of this target, if any. */
+    private String description = null;
+
+    /** Default constructor. */
+    public Target() {
+        //empty
+    }
+
+    /**
+     * Cloning constructor.
+     * @param other the Target to clone.
+     */
+    public Target(Target other) {
+        this.name = other.name;
+        this.ifCondition = other.ifCondition;
+        this.unlessCondition = other.unlessCondition;
+        this.dependencies = other.dependencies;
+        this.location = other.location;
+        this.project = other.project;
+        this.description = other.description;
+        // The children are added to after this cloning
+        this.children = other.children;
+    }
+
+    /**
+     * Sets the project this target belongs to.
+     *
+     * @param project The project this target belongs to.
+     *                Must not be <code>null</code>.
+     */
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Returns the project this target belongs to.
+     *
+     * @return The project this target belongs to, or <code>null</code> if
+     *         the project has not been set yet.
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Sets the location of this target's definition.
+     *
+     * @param location   <code>Location</code>
+     * @since 1.6.2
+     */
+    public void setLocation(Location location) {
+        this.location = location;
+    }
+
+    /**
+     * Get the location of this target's definition.
+     *
+     * @return <code>Location</code>
+     * @since 1.6.2
+     */
+    public Location getLocation() {
+        return location;
+    }
+
+    /**
+     * Sets the list of targets this target is dependent on.
+     * The targets themselves are not resolved at this time.
+     *
+     * @param depS A comma-separated list of targets this target
+     *             depends on. Must not be <code>null</code>.
+     */
+    public void setDepends(String depS) {
+        if (depS.length() > 0) {
+            StringTokenizer tok =
+                new StringTokenizer(depS, ",", true);
+            while (tok.hasMoreTokens()) {
+                String token = tok.nextToken().trim();
+
+                // Make sure the dependency is not empty string
+                if ("".equals(token) || ",".equals(token)) {
+                    throw new BuildException("Syntax Error: depends " + "attribute of target \""
+                            + getName() + "\" has an empty string as dependency.");
+                }
+
+                addDependency(token);
+
+                // Make sure that depends attribute does not
+                // end in a ,
+                if (tok.hasMoreTokens()) {
+                    token = tok.nextToken();
+                    if (!tok.hasMoreTokens() || !",".equals(token)) {
+                        throw new BuildException("Syntax Error: Depend "
+                                + "attribute for target \"" + getName()
+                                + "\" ends with a , character");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the name of this target.
+     *
+     * @param name The name of this target. Should not be <code>null</code>.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of this target.
+     *
+     * @return the name of this target, or <code>null</code> if the
+     *         name has not been set yet.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Adds a task to this target.
+     *
+     * @param task The task to be added. Must not be <code>null</code>.
+     */
+    public void addTask(Task task) {
+        children.add(task);
+    }
+
+    /**
+     * Adds the wrapper for a data type element to this target.
+     *
+     * @param r The wrapper for the data type element to be added.
+     *          Must not be <code>null</code>.
+     */
+    public void addDataType(RuntimeConfigurable r) {
+        children.add(r);
+    }
+
+    /**
+     * Returns the current set of tasks to be executed by this target.
+     *
+     * @return an array of the tasks currently within this target
+     */
+    public Task[] getTasks() {
+        List tasks = new ArrayList(children.size());
+        Iterator it = children.iterator();
+        while (it.hasNext()) {
+            Object o = it.next();
+            if (o instanceof Task) {
+                tasks.add(o);
+            }
+        }
+        return (Task[]) tasks.toArray(new Task[tasks.size()]);
+    }
+
+    /**
+     * Adds a dependency to this target.
+     *
+     * @param dependency The name of a target this target is dependent on.
+     *                   Must not be <code>null</code>.
+     */
+    public void addDependency(String dependency) {
+        if (dependencies == null) {
+            dependencies = new ArrayList(2);
+        }
+        dependencies.add(dependency);
+    }
+
+    /**
+     * Returns an enumeration of the dependencies of this target.
+     *
+     * @return an enumeration of the dependencies of this target
+     */
+    public Enumeration getDependencies() {
+        return Collections
+                .enumeration(dependencies == null ? Collections.EMPTY_LIST : dependencies);
+    }
+
+    /**
+     * Does this target depend on the named target?
+     * @param other the other named target.
+     * @return true if the target does depend on the named target
+     * @since Ant 1.6
+     */
+    public boolean dependsOn(String other) {
+        Project p = getProject();
+        Hashtable t = p == null ? null : p.getTargets();
+        return p != null && p.topoSort(getName(), t, false).contains(t.get(other));
+    }
+
+    /**
+     * Sets the "if" condition to test on execution. This is the
+     * name of a property to test for existence - if the property
+     * is not set, the task will not execute. The property goes
+     * through property substitution once before testing, so if
+     * property <code>foo</code> has value <code>bar</code>, setting
+     * the "if" condition to <code>${foo}_x</code> will mean that the
+     * task will only execute if property <code>bar_x</code> is set.
+     *
+     * @param property The property condition to test on execution.
+     *                 May be <code>null</code>, in which case
+     *                 no "if" test is performed.
+     */
+    public void setIf(String property) {
+        ifCondition = property == null ? "" : property;
+    }
+
+    /**
+     * Returns the "if" property condition of this target.
+     *
+     * @return the "if" property condition or <code>null</code> if no
+     *         "if" condition had been defined.
+     * @since 1.6.2
+     */
+    public String getIf() {
+        return "".equals(ifCondition) ? null : ifCondition;
+    }
+
+    /**
+     * Sets the "unless" condition to test on execution. This is the
+     * name of a property to test for existence - if the property
+     * is set, the task will not execute. The property goes
+     * through property substitution once before testing, so if
+     * property <code>foo</code> has value <code>bar</code>, setting
+     * the "unless" condition to <code>${foo}_x</code> will mean that the
+     * task will only execute if property <code>bar_x</code> isn't set.
+     *
+     * @param property The property condition to test on execution.
+     *                 May be <code>null</code>, in which case
+     *                 no "unless" test is performed.
+     */
+    public void setUnless(String property) {
+        unlessCondition = property == null ? "" : property;
+    }
+
+    /**
+     * Returns the "unless" property condition of this target.
+     *
+     * @return the "unless" property condition or <code>null</code>
+     *         if no "unless" condition had been defined.
+     * @since 1.6.2
+     */
+    public String getUnless() {
+        return "".equals(unlessCondition) ? null : unlessCondition;
+    }
+
+    /**
+     * Sets the description of this target.
+     *
+     * @param description The description for this target.
+     *                    May be <code>null</code>, indicating that no
+     *                    description is available.
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Returns the description of this target.
+     *
+     * @return the description of this target, or <code>null</code> if no
+     *         description is available.
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * Returns the name of this target.
+     *
+     * @return the name of this target, or <code>null</code> if the
+     *         name has not been set yet.
+     */
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * Executes the target if the "if" and "unless" conditions are
+     * satisfied. Dependency checking should be done before calling this
+     * method, as it does no checking of its own. If either the "if"
+     * or "unless" test prevents this target from being executed, a verbose
+     * message is logged giving the reason. It is recommended that clients
+     * of this class call performTasks rather than this method so that
+     * appropriate build events are fired.
+     *
+     * @exception BuildException if any of the tasks fail or if a data type
+     *                           configuration fails.
+     *
+     * @see #performTasks()
+     * @see #setIf(String)
+     * @see #setUnless(String)
+     */
+    public void execute() throws BuildException {
+        if (testIfCondition() && testUnlessCondition()) {
+            for (int taskPosition = 0; taskPosition < children.size(); ++taskPosition) {
+                Object o = children.get(taskPosition);
+                if (o instanceof Task) {
+                    Task task = (Task) o;
+                    task.perform();
+                } else {
+                    ((RuntimeConfigurable) o).maybeConfigure(project);
+                }
+            }
+        } else if (!testIfCondition()) {
+            project.log(this, "Skipped because property '" + project.replaceProperties(ifCondition)
+                    + "' not set.", Project.MSG_VERBOSE);
+        } else {
+            project.log(this, "Skipped because property '"
+                    + project.replaceProperties(unlessCondition) + "' set.", Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * Performs the tasks within this target (if the conditions are met),
+     * firing target started/target finished messages around a call to
+     * execute.
+     *
+     * @see #execute()
+     */
+    public final void performTasks() {
+        RuntimeException thrown = null;
+        project.fireTargetStarted(this);
+        try {
+            execute();
+        } catch (RuntimeException exc) {
+            thrown = exc;
+            throw exc;
+        } finally {
+            project.fireTargetFinished(this, thrown);
+        }
+    }
+
+    /**
+     * Replaces all occurrences of the given task in the list
+     * of children with the replacement data type wrapper.
+     *
+     * @param el The task to replace.
+     *           Must not be <code>null</code>.
+     * @param o  The data type wrapper to replace <code>el</code> with.
+     */
+    void replaceChild(Task el, RuntimeConfigurable o) {
+        int index;
+        while ((index = children.indexOf(el)) >= 0) {
+            children.set(index, o);
+        }
+    }
+
+    /**
+     * Replaces all occurrences of the given task in the list
+     * of children with the replacement task.
+     *
+     * @param el The task to replace.
+     *           Must not be <code>null</code>.
+     * @param o  The task to replace <code>el</code> with.
+     */
+    void replaceChild(Task el, Task o) {
+        int index;
+        while ((index = children.indexOf(el)) >= 0) {
+            children.set(index, o);
+        }
+    }
+
+    /**
+     * Tests whether or not the "if" condition is satisfied.
+     *
+     * @return whether or not the "if" condition is satisfied. If no
+     *         condition (or an empty condition) has been set,
+     *         <code>true</code> is returned.
+     *
+     * @see #setIf(String)
+     */
+    private boolean testIfCondition() {
+        if ("".equals(ifCondition)) {
+            return true;
+        }
+        String test = project.replaceProperties(ifCondition);
+        return project.getProperty(test) != null;
+    }
+
+    /**
+     * Tests whether or not the "unless" condition is satisfied.
+     *
+     * @return whether or not the "unless" condition is satisfied. If no
+     *         condition (or an empty condition) has been set,
+     *         <code>true</code> is returned.
+     *
+     * @see #setUnless(String)
+     */
+    private boolean testUnlessCondition() {
+        if ("".equals(unlessCondition)) {
+            return true;
+        }
+        String test = project.replaceProperties(unlessCondition);
+        return project.getProperty(test) == null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/Task.java b/trunk/src/main/org/apache/tools/ant/Task.java
new file mode 100644
index 0000000..c8254da
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/Task.java
@@ -0,0 +1,482 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.dispatch.DispatchUtils;
+
+import java.util.Enumeration;
+import java.io.IOException;
+
+/**
+ * Base class for all tasks.
+ *
+ * Use Project.createTask to create a new task instance rather than
+ * using this class directly for construction.
+ *
+ * @see Project#createTask
+ */
+public abstract class Task extends ProjectComponent {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Target this task belongs to, if any.
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     *             Please use the {@link #getOwningTarget()} method.
+     */
+    protected Target target;
+
+    /**
+     * Name of this task to be used for logging purposes.
+     * This defaults to the same as the type, but may be
+     * overridden by the user. For instance, the name "java"
+     * isn't terribly descriptive for a task used within
+     * another task - the outer task code can probably
+     * provide a better one.
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     *             Please use the {@link #getTaskName()} method.
+     */
+    protected String taskName;
+
+    /**
+     * Type of this task.
+     *
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     *             Please use the {@link #getTaskType()} method.
+     */
+    protected String taskType;
+
+    /**
+     * Wrapper for this object, used to configure it at runtime.
+     *
+     * @deprecated since 1.6.x.
+     *             You should not be accessing this variable directly.
+     *             Please use the {@link #getWrapper()} method.
+     */
+    protected RuntimeConfigurable wrapper;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Whether or not this task is invalid. A task becomes invalid
+     * if a conflicting class is specified as the implementation for
+     * its type.
+     */
+    private boolean invalid;
+
+    /** Sole constructor. */
+    public Task() {
+    }
+
+    /**
+     * Sets the target container of this task.
+     *
+     * @param target Target in whose scope this task belongs.
+     *               May be <code>null</code>, indicating a top-level task.
+     */
+    public void setOwningTarget(Target target) {
+        this.target = target;
+    }
+
+    /**
+     * Returns the container target of this task.
+     *
+     * @return The target containing this task, or <code>null</code> if
+     *         this task is a top-level task.
+     */
+    public Target getOwningTarget() {
+        return target;
+    }
+
+    /**
+     * Sets the name to use in logging messages.
+     *
+     * @param name The name to use in logging messages.
+     *             Should not be <code>null</code>.
+     */
+    public void setTaskName(String name) {
+        this.taskName = name;
+    }
+
+    /**
+     * Returns the name to use in logging messages.
+     *
+     * @return the name to use in logging messages.
+     */
+    public String getTaskName() {
+        return taskName;
+    }
+
+    /**
+     * Sets the name with which the task has been invoked.
+     *
+     * @param type The name the task has been invoked as.
+     *             Should not be <code>null</code>.
+     */
+    public void setTaskType(String type) {
+        this.taskType = type;
+    }
+
+    /**
+     * Called by the project to let the task initialize properly.
+     * The default implementation is a no-op.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void init() throws BuildException {
+    }
+
+    /**
+     * Called by the project to let the task do its work. This method may be
+     * called more than once, if the task is invoked more than once.
+     * For example,
+     * if target1 and target2 both depend on target3, then running
+     * "ant target1 target2" will run all tasks in target3 twice.
+     *
+     * @exception BuildException if something goes wrong with the build.
+     */
+    public void execute() throws BuildException {
+    }
+
+    /**
+     * Returns the wrapper used for runtime configuration.
+     *
+     * @return the wrapper used for runtime configuration. This
+     *         method will generate a new wrapper (and cache it)
+     *         if one isn't set already.
+     */
+    public RuntimeConfigurable getRuntimeConfigurableWrapper() {
+        if (wrapper == null) {
+            wrapper = new RuntimeConfigurable(this, getTaskName());
+        }
+        return wrapper;
+    }
+
+    /**
+     * Sets the wrapper to be used for runtime configuration.
+     *
+     * This method should be used only by the ProjectHelper and Ant internals.
+     * It is public to allow helper plugins to operate on tasks, normal tasks
+     * should never use it.
+     *
+     * @param wrapper The wrapper to be used for runtime configuration.
+     *                May be <code>null</code>, in which case the next call
+     *                to getRuntimeConfigurableWrapper will generate a new
+     *                wrapper.
+     */
+    public void setRuntimeConfigurableWrapper(RuntimeConfigurable wrapper) {
+        this.wrapper = wrapper;
+    }
+
+    // XXX: (Jon Skeet) The comment "if it hasn't been done already" may
+    // not be strictly true. wrapper.maybeConfigure() won't configure the same
+    // attributes/text more than once, but it may well add the children again,
+    // unless I've missed something.
+    /**
+     * Configures this task - if it hasn't been done already.
+     * If the task has been invalidated, it is replaced with an
+     * UnknownElement task which uses the new definition in the project.
+     *
+     * @exception BuildException if the task cannot be configured.
+     */
+    public void maybeConfigure() throws BuildException {
+        if (!invalid) {
+            if (wrapper != null) {
+                wrapper.maybeConfigure(getProject());
+            }
+        } else {
+            getReplacement();
+        }
+    }
+
+    /**
+     * Force the task to be reconfigured from its RuntimeConfigurable.
+     */
+    public void reconfigure() {
+        if (wrapper != null) {
+            wrapper.reconfigure(getProject());
+        }
+    }
+
+    /**
+     * Handles output by logging it with the INFO priority.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleOutput(String output) {
+        log(output, Project.MSG_INFO);
+    }
+
+    /**
+     * Handles output by logging it with the INFO priority.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     *
+     * @since Ant 1.5.2
+     */
+    protected void handleFlush(String output) {
+        handleOutput(output);
+    }
+
+    /**
+     * Handle an input request by this task.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @since Ant 1.6
+     */
+    protected int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        return getProject().defaultInput(buffer, offset, length);
+    }
+
+    /**
+     * Handles an error output by logging it with the WARN priority.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     */
+    protected void handleErrorOutput(String output) {
+        log(output, Project.MSG_WARN);
+    }
+
+    /**
+     * Handles an error line by logging it with the WARN priority.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     *
+     * @since Ant 1.5.2
+     */
+    protected void handleErrorFlush(String output) {
+        handleErrorOutput(output);
+    }
+
+    /**
+     * Logs a message with the default (INFO) priority.
+     *
+     * @param msg The message to be logged. Should not be <code>null</code>.
+     */
+    public void log(String msg) {
+        log(msg, Project.MSG_INFO);
+    }
+
+    /**
+     * Logs a message with the given priority. This delegates
+     * the actual logging to the project.
+     *
+     * @param msg The message to be logged. Should not be <code>null</code>.
+     * @param msgLevel The message priority at which this message is to
+     *                 be logged.
+     */
+    public void log(String msg, int msgLevel) {
+        if (getProject() != null) {
+            getProject().log(this, msg, msgLevel);
+        } else {
+            super.log(msg, msgLevel);
+        }
+    }
+
+    /**
+     * Logs a message with the given priority. This delegates
+     * the actual logging to the project.
+     *
+     * @param t The exception to be logged. Should not be <code>null</code>.
+     * @param msgLevel The message priority at which this message is to
+     *                 be logged.
+     * @since 1.7
+     */
+    public void log(Throwable t, int msgLevel) {
+        if (t != null) {
+            log(t.getMessage(), t, msgLevel);
+        }
+    }
+
+    /**
+     * Logs a message with the given priority. This delegates
+     * the actual logging to the project.
+     *
+     * @param msg The message to be logged. Should not be <code>null</code>.
+     * @param t The exception to be logged. May be <code>null</code>.
+     * @param msgLevel The message priority at which this message is to
+     *                 be logged.
+     * @since 1.7
+     */
+    public void log(String msg, Throwable t, int msgLevel) {
+        if (getProject() != null) {
+            getProject().log(this, msg, t, msgLevel);
+        } else {
+            super.log(msg, msgLevel);
+        }
+    }
+
+    /**
+     * Performs this task if it's still valid, or gets a replacement
+     * version and performs that otherwise.
+     *
+     * Performing a task consists of firing a task started event,
+     * configuring the task, executing it, and then firing task finished
+     * event. If a runtime exception is thrown, the task finished event
+     * is still fired, but with the exception as the cause.
+     */
+    public final void perform() {
+        if (!invalid) {
+            getProject().fireTaskStarted(this);
+            Throwable reason = null;
+            try {
+                maybeConfigure();
+                DispatchUtils.execute(this);
+            } catch (BuildException ex) {
+                if (ex.getLocation() == Location.UNKNOWN_LOCATION) {
+                    ex.setLocation(getLocation());
+                }
+                reason = ex;
+                throw ex;
+            } catch (Exception ex) {
+                reason = ex;
+                BuildException be = new BuildException(ex);
+                be.setLocation(getLocation());
+                throw be;
+            } catch (Error ex) {
+                reason = ex;
+                throw ex;
+            } finally {
+                getProject().fireTaskFinished(this, reason);
+            }
+        } else {
+            UnknownElement ue = getReplacement();
+            Task task = ue.getTask();
+            task.perform();
+        }
+    }
+
+    /**
+     * Marks this task as invalid. Any further use of this task
+     * will go through a replacement with the updated definition.
+     */
+    final void markInvalid() {
+        invalid = true;
+    }
+
+    /**
+     * Has this task been marked invalid?
+     *
+     * @return true if this task is no longer valid. A new task should be
+     * configured in this case.
+     *
+     * @since Ant 1.5
+     */
+    protected final boolean isInvalid() {
+        return invalid;
+    }
+
+    /**
+     * Replacement element used if this task is invalidated.
+     */
+    private UnknownElement replacement;
+
+    /**
+     * Creates an UnknownElement that can be used to replace this task.
+     * Once this has been created once, it is cached and returned by
+     * future calls.
+     *
+     * @return the UnknownElement instance for the new definition of this task.
+     */
+    private UnknownElement getReplacement() {
+        if (replacement == null) {
+            replacement = new UnknownElement(taskType);
+            replacement.setProject(getProject());
+            replacement.setTaskType(taskType);
+            replacement.setTaskName(taskName);
+            replacement.setLocation(location);
+            replacement.setOwningTarget(target);
+            replacement.setRuntimeConfigurableWrapper(wrapper);
+            wrapper.setProxy(replacement);
+            replaceChildren(wrapper, replacement);
+            target.replaceChild(this, replacement);
+            replacement.maybeConfigure();
+        }
+        return replacement;
+    }
+
+    /**
+     * Recursively adds an UnknownElement instance for each child
+     * element of replacement.
+     *
+     * @since Ant 1.5.1
+     */
+    private void replaceChildren(RuntimeConfigurable wrapper,
+                                 UnknownElement parentElement) {
+        Enumeration e = wrapper.getChildren();
+        while (e.hasMoreElements()) {
+            RuntimeConfigurable childWrapper =
+                (RuntimeConfigurable) e.nextElement();
+            UnknownElement childElement =
+                new UnknownElement(childWrapper.getElementTag());
+            parentElement.addChild(childElement);
+            childElement.setProject(getProject());
+            childElement.setRuntimeConfigurableWrapper(childWrapper);
+            childWrapper.setProxy(childElement);
+            replaceChildren(childWrapper, childElement);
+        }
+    }
+
+    /**
+     * Return the type of task.
+     *
+     * @return the type of task.
+     */
+    public String getTaskType() {
+        return taskType;
+    }
+
+    /**
+     * Return the runtime configurable structure for this task.
+     *
+     * @return the runtime structure for this task.
+     */
+    protected RuntimeConfigurable getWrapper() {
+        return wrapper;
+    }
+
+    /**
+     * Bind a task to another; use this when configuring a newly created
+     * task to do work on behalf of another.
+     * Project, OwningTarget, TaskName, Location and Description are all copied
+     *
+     * Important: this method does not call {@link Task#init()}.
+     * If you are creating a task to delegate work to, call {@link Task#init()}
+     * to initialize it.
+     *
+     * @param owner owning target
+     * @since Ant1.7
+     */
+    public final void bindToOwner(Task owner) {
+        setProject(owner.getProject());
+        setOwningTarget(owner.getOwningTarget());
+        setTaskName(owner.getTaskName());
+        setDescription(owner.getDescription());
+        setLocation(owner.getLocation());
+        setTaskType(owner.getTaskType());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/TaskAdapter.java b/trunk/src/main/org/apache/tools/ant/TaskAdapter.java
new file mode 100644
index 0000000..c73d436
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/TaskAdapter.java
@@ -0,0 +1,181 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.lang.reflect.Method;
+import org.apache.tools.ant.dispatch.Dispatchable;
+import org.apache.tools.ant.dispatch.DispatchUtils;
+
+/**
+ * Uses introspection to "adapt" an arbitrary Bean which doesn't
+ * itself extend Task, but still contains an execute method and optionally
+ * a setProject method.
+ *
+ */
+public class TaskAdapter extends Task implements TypeAdapter {
+
+    /** Object to act as a proxy for. */
+    private Object proxy;
+
+    /**
+     * No-arg constructor for reflection.
+     */
+    public TaskAdapter() {
+    }
+
+    /**
+     * Constructor for given proxy.
+     * So you could write easier code
+     * <pre>
+     * myTaskContainer.addTask( new TaskAdapter(myProxy) );
+     * </pre>
+     *
+     * @param proxy The object which Ant should use as task.
+     */
+    public TaskAdapter(Object proxy) {
+        this();
+        setProxy(proxy);
+    }
+
+    /**
+     * Checks whether or not a class is suitable to be adapted by TaskAdapter.
+     * If the class is of type Dispatchable, the check is not performed because
+     * the method that will be executed will be determined only at runtime of
+     * the actual task and not during parse time.
+     *
+     * This only checks conditions which are additionally required for
+     * tasks adapted by TaskAdapter. Thus, this method should be called by
+     * Project.checkTaskClass.
+     *
+     * Throws a BuildException and logs as Project.MSG_ERR for
+     * conditions that will cause the task execution to fail.
+     * Logs other suspicious conditions with Project.MSG_WARN.
+     *
+     * @param taskClass Class to test for suitability.
+     *                  Must not be <code>null</code>.
+     * @param project   Project to log warnings/errors to.
+     *                  Must not be <code>null</code>.
+     *
+     * @see Project#checkTaskClass(Class)
+     */
+    public static void checkTaskClass(final Class taskClass,
+                                      final Project project) {
+        if (!Dispatchable.class.isAssignableFrom(taskClass)) {
+            // don't have to check for interface, since then
+            // taskClass would be abstract too.
+            try {
+                final Method executeM = taskClass.getMethod("execute", (Class[]) null);
+                // don't have to check for public, since
+                // getMethod finds public method only.
+                // don't have to check for abstract, since then
+                // taskClass would be abstract too.
+                if (!Void.TYPE.equals(executeM.getReturnType())) {
+                    final String message = "return type of execute() should be "
+                        + "void but was \"" + executeM.getReturnType() + "\" in "
+                        + taskClass;
+                    project.log(message, Project.MSG_WARN);
+                }
+            } catch (NoSuchMethodException e) {
+                final String message = "No public execute() in " + taskClass;
+                project.log(message, Project.MSG_ERR);
+                throw new BuildException(message);
+            } catch (LinkageError e) {
+                String message = "Could not load " + taskClass + ": " + e;
+                project.log(message, Project.MSG_ERR);
+                throw new BuildException(message, e);
+            }
+        }
+    }
+
+    /**
+     * Check if the proxy class is a valid class to use
+     * with this adapter.
+     * The class must have a public no-arg "execute()" method.
+     * @param proxyClass the class to check.
+     */
+    public void checkProxyClass(Class proxyClass) {
+        checkTaskClass(proxyClass, getProject());
+    }
+
+    /**
+     * Executes the proxied task.
+     *
+     * @exception BuildException if the project could not be set
+     * or the method could not be executed.
+     */
+    public void execute() throws BuildException {
+        try {
+            Method setLocationM = proxy.getClass().getMethod(
+                "setLocation", new Class[] {Location.class});
+            if (setLocationM != null) {
+                setLocationM.invoke(proxy, new Object[] {getLocation()});
+            }
+        } catch (NoSuchMethodException e) {
+            // ignore this if the class being used as a task does not have
+            // a set location method.
+        } catch (Exception ex) {
+            log("Error setting location in " + proxy.getClass(),
+                Project.MSG_ERR);
+            throw new BuildException(ex);
+        }
+
+        try {
+            Method setProjectM = proxy.getClass().getMethod(
+                "setProject", new Class[] {Project.class});
+            if (setProjectM != null) {
+                setProjectM.invoke(proxy, new Object[] {getProject()});
+            }
+        } catch (NoSuchMethodException e) {
+            // ignore this if the class being used as a task does not have
+            // a set project method.
+        } catch (Exception ex) {
+            log("Error setting project in " + proxy.getClass(),
+                Project.MSG_ERR);
+            throw new BuildException(ex);
+        }
+
+        try {
+            DispatchUtils.execute(proxy);
+        } catch (BuildException be) {
+            throw be;
+        } catch (Exception ex) {
+            log("Error in " + proxy.getClass(), Project.MSG_VERBOSE);
+            throw new BuildException(ex);
+        }
+    }
+
+    /**
+     * Sets the target object to proxy for.
+     *
+     * @param o The target object. Must not be <code>null</code>.
+     */
+    public void setProxy(Object o) {
+        this.proxy = o;
+    }
+
+    /**
+     * Returns the target object being proxied.
+     *
+     * @return the target proxy object.
+     */
+    public Object getProxy() {
+        return proxy;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/TaskConfigurationChecker.java b/trunk/src/main/org/apache/tools/ant/TaskConfigurationChecker.java
new file mode 100644
index 0000000..39ea0d0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/TaskConfigurationChecker.java
@@ -0,0 +1,113 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant;

+

+import java.util.ArrayList;

+import java.util.Iterator;

+import java.util.List;

+

+/**

+ * <p>Helper class for the check of the configuration of a given task.

+ * This class provides methods for making assumptions about the task configuration.

+ * After collecting all violations with <tt>assert*</tt> and <tt>fail</tt>

+ * methods the <tt>checkErrors</tt> will throw a BuildException with all collected

+ * messages or does nothing if there wasn't any error.</p>

+ *

+ * <p>Example:</p>

+ *

+ * <pre>

+ *     public class MyTask extends Task {

+ *         ...

+ *         public void execute() {

+ *             TaskConfigurationChecker checker = TaskConfigurationChecker(this);

+ *             checker.assertConfig(

+ *                 srcdir != null,

+ *                 "Attribute 'srcdir' must be set.

+ *             );

+ *             checker.assertConfig(

+ *                 srcdir.exists(),

+ *                 "Srcdir (" + srcdir + ") must exist."

+ *             );

+ *             if (someComplexCondition()) {

+ *                 fail("Complex condition failed.");

+ *             }

+ *             checker.checkErrors();

+ *         }

+ *     }

+ * </pre>

+ *

+ * @see <a href="http://martinfowler.com/eaaDev/Notification.html">Notification Pattern</a>

+ */

+public class TaskConfigurationChecker {

+

+    /** List of all collected error messages. */

+    private List/*<String>*/ errors = new ArrayList();

+

+    /** Task for which the configuration should be checked. */

+    private Task task;

+

+    /**

+     * Constructor.

+     * @param task which task should be checked

+     */

+    public TaskConfigurationChecker(Task task) {

+        this.task = task;

+    }

+

+    /**

+     * Asserts that a condition is true.

+     * @param condition     which condition to check

+     * @param errormessage  errormessage to throw if a condition failed

+     */

+    public void assertConfig(boolean condition, String errormessage) {

+        if (!condition) {

+            errors.add(errormessage);

+        }

+    }

+

+    /**

+     * Registers an error.

+     * @param errormessage the message for the registered error

+     */

+    public void fail(String errormessage) {

+        errors.add(errormessage);

+    }

+

+    /**

+     * Checks if there are any collected errors and throws a BuildException

+     * with all messages if there was one or more.

+     * @throws BuildException if one or more errors were registered

+     */

+    public void checkErrors() throws BuildException {

+        if (!errors.isEmpty()) {

+            StringBuffer sb = new StringBuffer();

+            sb.append("Configurationerror on <");

+            sb.append(task.getTaskName());

+            sb.append(">:");

+            sb.append(System.getProperty("line.separator"));

+            for (Iterator it = errors.iterator(); it.hasNext();) {

+                String msg = (String) it.next();

+                sb.append("- ");

+                sb.append(msg);

+                sb.append(System.getProperty("line.separator"));

+            }

+            throw new BuildException(sb.toString(), task.getLocation());

+        }

+    }

+

+}

diff --git a/trunk/src/main/org/apache/tools/ant/TaskContainer.java b/trunk/src/main/org/apache/tools/ant/TaskContainer.java
new file mode 100644
index 0000000..f742e9e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/TaskContainer.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Interface for objects which can contain tasks.
+ * <p>
+ * It is recommended that implementations call perform rather than
+ * execute for the tasks they contain, as this method ensures that the
+ * appropriate BuildEvents will be generated.
+ *
+ * @see Task#perform
+ * @see Task#execute
+ * @see BuildEvent
+ *
+ */
+public interface TaskContainer {
+    /**
+     * Adds a task to this task container
+     *
+     * @param task The task to be added to this container.
+     *             Must not be <code>null</code>.
+     */
+    void addTask(Task task);
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/TypeAdapter.java b/trunk/src/main/org/apache/tools/ant/TypeAdapter.java
new file mode 100644
index 0000000..c9d4a28
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/TypeAdapter.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+/**
+ * Used to wrap types.
+ *
+ */
+public interface TypeAdapter {
+
+    /**
+     * Sets the project
+     *
+     * @param p the project instance.
+     */
+    void setProject(Project p);
+
+    /**
+     * Gets the project
+     *
+     * @return the project instance.
+     */
+    Project getProject();
+
+    /**
+     * Sets the proxy object, whose methods are going to be
+     * invoked by ant.
+     * A proxy object is normally the object defined by
+     * a &lt;typedef/&gt; task that is adapted by the "adapter"
+     * attribute.
+     *
+     * @param o The target object. Must not be <code>null</code>.
+     */
+    void setProxy(Object o);
+
+    /**
+     * Returns the proxy object.
+     *
+     * @return the target proxy object
+     */
+    Object getProxy();
+
+    /**
+     * Check if the proxy class is compatible with this adapter - i.e.
+     * the adapter will be able to adapt instances of the give class.
+     *
+     * @param proxyClass the class to be checked.
+     */
+    void checkProxyClass(Class proxyClass);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/UnknownElement.java b/trunk/src/main/org/apache/tools/ant/UnknownElement.java
new file mode 100644
index 0000000..9273243
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/UnknownElement.java
@@ -0,0 +1,672 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import org.apache.tools.ant.taskdefs.PreSetDef;
+
+/**
+ * Wrapper class that holds all the information necessary to create a task
+ * or data type that did not exist when Ant started, or one which
+ * has had its definition updated to use a different implementation class.
+ *
+ */
+public class UnknownElement extends Task {
+
+    /**
+     * Holds the name of the task/type or nested child element of a
+     * task/type that hasn't been defined at parser time or has
+     * been redefined since original creation.
+     */
+    private String elementName;
+
+    /**
+     * Holds the namespace of the element.
+     */
+    private String namespace = "";
+
+    /**
+     * Holds the namespace qname of the element.
+     */
+    private String qname;
+
+    /**
+     * The real object after it has been loaded.
+     */
+    private Object realThing;
+
+    /**
+     * List of child elements (UnknownElements).
+     */
+    private List/*<UnknownElement>*/ children = null;
+
+    /** Specifies if a predefined definition has been done */
+    private boolean presetDefed = false;
+
+    /**
+     * Creates an UnknownElement for the given element name.
+     *
+     * @param elementName The name of the unknown element.
+     *                    Must not be <code>null</code>.
+     */
+    public UnknownElement (String elementName) {
+        this.elementName = elementName;
+    }
+
+    /**
+     * @return the list of nested UnknownElements for this UnknownElement.
+     */
+    public List getChildren() {
+        return children;
+    }
+
+    /**
+     * Returns the name of the XML element which generated this unknown
+     * element.
+     *
+     * @return the name of the XML element which generated this unknown
+     *         element.
+     */
+    public String getTag() {
+        return elementName;
+    }
+
+    /** Return the namespace of the XML element associated with this component.
+     *
+     * @return Namespace URI used in the xmlns declaration.
+     */
+    public String getNamespace() {
+        return namespace;
+    }
+
+    /**
+     * Set the namespace of the XML element associated with this component.
+     * This method is typically called by the XML processor.
+     * If the namespace is "ant:current", the component helper
+     * is used to get the current antlib uri.
+     *
+     * @param namespace URI used in the xmlns declaration.
+     */
+    public void setNamespace(String namespace) {
+        if (namespace.equals(ProjectHelper.ANT_CURRENT_URI)) {
+            ComponentHelper helper = ComponentHelper.getComponentHelper(
+                getProject());
+            namespace = helper.getCurrentAntlibUri();
+        }
+        this.namespace = namespace == null ? "" : namespace;
+    }
+
+    /** Return the qname of the XML element associated with this component.
+     *
+     * @return namespace Qname used in the element declaration.
+     */
+    public String getQName() {
+        return qname;
+    }
+
+    /** Set the namespace qname of the XML element.
+     * This method is typically called by the XML processor.
+     *
+     * @param qname the qualified name of the element
+     */
+    public void setQName(String qname) {
+        this.qname = qname;
+    }
+
+
+    /**
+     * Get the RuntimeConfigurable instance for this UnknownElement, containing
+     * the configuration information.
+     *
+     * @return the configuration info.
+     */
+    public RuntimeConfigurable getWrapper() {
+        return super.getWrapper();
+    }
+
+    /**
+     * Creates the real object instance and child elements, then configures
+     * the attributes and text of the real object. This unknown element
+     * is then replaced with the real object in the containing target's list
+     * of children.
+     *
+     * @exception BuildException if the configuration fails
+     */
+    public void maybeConfigure() throws BuildException {
+        if (realThing != null) {
+            return;
+        }
+        configure(makeObject(this, getWrapper()));
+    }
+
+    /**
+     * Configure the given object from this UnknownElement
+     *
+     * @param realObject the real object this UnknownElement is representing.
+     *
+     */
+    public void configure(Object realObject) {
+        realThing = realObject;
+
+        getWrapper().setProxy(realThing);
+        Task task = null;
+        if (realThing instanceof Task) {
+            task = (Task) realThing;
+
+            task.setRuntimeConfigurableWrapper(getWrapper());
+
+            // For Script example that modifies id'ed tasks in other
+            // targets to work. *very* Ugly
+            // The reference is replaced by RuntimeConfigurable
+            if (getWrapper().getId() != null) {
+                this.getOwningTarget().replaceChild(this, (Task) realThing);
+            }
+       }
+
+
+        // configure attributes of the object and it's children. If it is
+        // a task container, defer the configuration till the task container
+        // attempts to use the task
+
+        if (task != null) {
+            task.maybeConfigure();
+        } else {
+            getWrapper().maybeConfigure(getProject());
+        }
+
+        handleChildren(realThing, getWrapper());
+    }
+
+    /**
+     * Handles output sent to System.out by this task or its real task.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleOutput(String output) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleOutput(output);
+        } else {
+            super.handleOutput(output);
+        }
+    }
+
+    /**
+     * Delegate to realThing if present and if it as task.
+     * @see Task#handleInput(byte[], int, int)
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @since Ant 1.6
+     */
+    protected int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (realThing instanceof Task) {
+            return ((Task) realThing).handleInput(buffer, offset, length);
+        } else {
+            return super.handleInput(buffer, offset, length);
+        }
+
+    }
+    /**
+     * Handles output sent to System.out by this task or its real task.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     */
+    protected void handleFlush(String output) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleFlush(output);
+        } else {
+            super.handleFlush(output);
+        }
+    }
+
+    /**
+     * Handles error output sent to System.err by this task or its real task.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     */
+    protected void handleErrorOutput(String output) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleErrorOutput(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+
+    /**
+     * Handles error output sent to System.err by this task or its real task.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     */
+    protected void handleErrorFlush(String output) {
+        if (realThing instanceof Task) {
+            ((Task) realThing).handleErrorOutput(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+    /**
+     * Executes the real object if it's a task. If it's not a task
+     * (e.g. a data type) then this method does nothing.
+     */
+    public void execute() {
+        if (realThing == null) {
+            // plain impossible to get here, maybeConfigure should
+            // have thrown an exception.
+            throw new BuildException("Could not create task of type: "
+                                     + elementName, getLocation());
+        }
+        try {
+            if (realThing instanceof Task) {
+                ((Task) realThing).execute();
+            }
+        } finally {
+            // Finished executing the task, null it to allow
+            // GC do its job
+            // If this UE is used again, a new "realthing" will be made
+            realThing = null;
+            getWrapper().setProxy(null);
+        }
+    }
+
+    /**
+     * Adds a child element to this element.
+     *
+     * @param child The child element to add. Must not be <code>null</code>.
+     */
+    public void addChild(UnknownElement child) {
+        if (children == null) {
+            children = new ArrayList();
+        }
+        children.add(child);
+    }
+
+    /**
+     * Creates child elements, creates children of the children
+     * (recursively), and sets attributes of the child elements.
+     *
+     * @param parent The configured object for the parent.
+     *               Must not be <code>null</code>.
+     *
+     * @param parentWrapper The wrapper containing child wrappers
+     *                      to be configured. Must not be <code>null</code>
+     *                      if there are any children.
+     *
+     * @exception BuildException if the children cannot be configured.
+     */
+    protected void handleChildren(
+        Object parent,
+        RuntimeConfigurable parentWrapper)
+        throws BuildException {
+        if (parent instanceof TypeAdapter) {
+            parent = ((TypeAdapter) parent).getProxy();
+        }
+
+        String parentUri = getNamespace();
+        Class parentClass = parent.getClass();
+        IntrospectionHelper ih = IntrospectionHelper.getHelper(getProject(), parentClass);
+
+
+        if (children != null) {
+            Iterator it = children.iterator();
+            for (int i = 0; it.hasNext(); i++) {
+                RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
+                UnknownElement child = (UnknownElement) it.next();
+                try {
+                    if (!handleChild(
+                            parentUri, ih, parent, child, childWrapper)) {
+                        if (!(parent instanceof TaskContainer)) {
+                            ih.throwNotSupported(getProject(), parent,
+                                                 child.getTag());
+                        } else {
+                            // a task container - anything could happen - just add the
+                            // child to the container
+                            TaskContainer container = (TaskContainer) parent;
+                            container.addTask(child);
+                        }
+                    }
+                } catch (UnsupportedElementException ex) {
+                    throw new BuildException(
+                        parentWrapper.getElementTag()
+                        + " doesn't support the nested \"" + ex.getElement()
+                        + "\" element.", ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * @return the component name - uses ProjectHelper#genComponentName()
+     */
+    protected String getComponentName() {
+        return ProjectHelper.genComponentName(getNamespace(), getTag());
+    }
+
+    /**
+     * This is used then the realobject of the UE is a PreSetDefinition.
+     * This is also used when a presetdef is used on a presetdef
+     * The attributes, elements and text are applied to this
+     * UE.
+     *
+     * @param u an UnknownElement containing the attributes, elements and text
+     */
+    public void applyPreSet(UnknownElement u) {
+        if (presetDefed) {
+            return;
+        }
+        // Do the runtime
+        getWrapper().applyPreSet(u.getWrapper());
+        if (u.children != null) {
+            List newChildren = new ArrayList();
+            newChildren.addAll(u.children);
+            if (children != null) {
+                newChildren.addAll(children);
+            }
+            children = newChildren;
+        }
+        presetDefed = true;
+    }
+
+    /**
+     * Creates a named task or data type. If the real object is a task,
+     * it is configured up to the init() stage.
+     *
+     * @param ue The unknown element to create the real object for.
+     *           Must not be <code>null</code>.
+     * @param w  Ignored in this implementation.
+     *
+     * @return the task or data type represented by the given unknown element.
+     */
+    protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) {
+        ComponentHelper helper = ComponentHelper.getComponentHelper(
+            getProject());
+        String name = ue.getComponentName();
+        Object o = helper.createComponent(ue, ue.getNamespace(), name);
+        if (o == null) {
+            throw getNotFoundException("task or type", name);
+        }
+        if (o instanceof PreSetDef.PreSetDefinition) {
+            PreSetDef.PreSetDefinition def = (PreSetDef.PreSetDefinition) o;
+            o = def.createObject(ue.getProject());
+            if (o == null) {
+                throw getNotFoundException(
+                    "preset " + name,
+                    def.getPreSets().getComponentName());
+            }
+            ue.applyPreSet(def.getPreSets());
+            if (o instanceof Task) {
+                Task task = (Task) o;
+                task.setTaskType(ue.getTaskType());
+                task.setTaskName(ue.getTaskName());
+                task.init();
+            }
+        }
+        if (o instanceof UnknownElement) {
+            o = ((UnknownElement) o).makeObject((UnknownElement) o, w);
+        }
+        if (o instanceof Task) {
+            ((Task) o).setOwningTarget(getOwningTarget());
+        }
+        if (o instanceof ProjectComponent) {
+            ((ProjectComponent) o).setLocation(getLocation());
+        }
+        return o;
+    }
+
+    /**
+     * Creates a named task and configures it up to the init() stage.
+     *
+     * @param ue The UnknownElement to create the real task for.
+     *           Must not be <code>null</code>.
+     * @param w  Ignored.
+     *
+     * @return the task specified by the given unknown element, or
+     *         <code>null</code> if the task name is not recognised.
+     */
+    protected Task makeTask(UnknownElement ue, RuntimeConfigurable w) {
+        Task task = getProject().createTask(ue.getTag());
+
+        if (task != null) {
+            task.setLocation(getLocation());
+            // UnknownElement always has an associated target
+            task.setOwningTarget(getOwningTarget());
+            task.init();
+        }
+        return task;
+    }
+
+    /**
+     * Returns a very verbose exception for when a task/data type cannot
+     * be found.
+     *
+     * @param what The kind of thing being created. For example, when
+     *             a task name could not be found, this would be
+     *             <code>"task"</code>. Should not be <code>null</code>.
+     * @param name The name of the element which could not be found.
+     *             Should not be <code>null</code>.
+     *
+     * @return a detailed description of what might have caused the problem.
+     */
+    protected BuildException getNotFoundException(String what,
+                                                  String name) {
+        ComponentHelper helper = ComponentHelper.getComponentHelper(getProject());
+        String msg = helper.diagnoseCreationFailure(name, what);
+        return new BuildException(msg, getLocation());
+    }
+
+    /**
+     * Returns the name to use in logging messages.
+     *
+     * @return the name to use in logging messages.
+     */
+    public String getTaskName() {
+        //return elementName;
+        return realThing == null
+            || !(realThing instanceof Task) ? super.getTaskName()
+                                            : ((Task) realThing).getTaskName();
+    }
+
+    /**
+     * Returns the task instance after it has been created and if it is a task.
+     *
+     * @return a task instance or <code>null</code> if the real object is not
+     *         a task.
+     */
+    public Task getTask() {
+        if (realThing instanceof Task) {
+            return (Task) realThing;
+        }
+        return null;
+    }
+
+    /**
+     * Return the configured object
+     *
+     * @return the real thing whatever it is
+     *
+     * @since ant 1.6
+     */
+    public Object getRealThing() {
+        return realThing;
+    }
+
+    /**
+     * Set the configured object
+     * @param realThing the configured object
+     * @since ant 1.7
+     */
+    public void setRealThing(Object realThing) {
+        this.realThing = realThing;
+    }
+
+    /**
+     * Try to create a nested element of <code>parent</code> for the
+     * given tag.
+     *
+     * @return whether the creation has been successful
+     */
+    private boolean handleChild(
+        String parentUri,
+        IntrospectionHelper ih,
+        Object parent, UnknownElement child,
+        RuntimeConfigurable childWrapper) {
+        String childName = ProjectHelper.genComponentName(
+            child.getNamespace(), child.getTag());
+        if (ih.supportsNestedElement(parentUri, childName)) {
+            IntrospectionHelper.Creator creator =
+                ih.getElementCreator(
+                    getProject(), parentUri, parent, childName, child);
+            creator.setPolyType(childWrapper.getPolyType());
+            Object realChild = creator.create();
+            if (realChild instanceof PreSetDef.PreSetDefinition) {
+                PreSetDef.PreSetDefinition def =
+                    (PreSetDef.PreSetDefinition) realChild;
+                realChild = creator.getRealObject();
+                child.applyPreSet(def.getPreSets());
+            }
+            childWrapper.setCreator(creator);
+            childWrapper.setProxy(realChild);
+            if (realChild instanceof Task) {
+                Task childTask = (Task) realChild;
+                childTask.setRuntimeConfigurableWrapper(childWrapper);
+                childTask.setTaskName(childName);
+                childTask.setTaskType(childName);
+            }
+            if (realChild instanceof ProjectComponent) {
+                ((ProjectComponent) realChild).setLocation(child.getLocation());
+            }
+            childWrapper.maybeConfigure(getProject());
+            child.handleChildren(realChild, childWrapper);
+            creator.store();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * like contents equals, but ignores project
+     * @param obj the object to check against
+     * @return true if this unknownelement has the same contents the other
+     */
+    public boolean similar(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (!getClass().getName().equals(obj.getClass().getName())) {
+            return false;
+        }
+        UnknownElement other = (UnknownElement) obj;
+        // Are the names the same ?
+        if (!equalsString(elementName, other.elementName)) {
+            return false;
+        }
+        if (!namespace.equals(other.namespace)) {
+            return false;
+        }
+        if (!qname.equals(other.qname)) {
+            return false;
+        }
+        // Are attributes the same ?
+        if (!getWrapper().getAttributeMap().equals(
+                other.getWrapper().getAttributeMap())) {
+            return false;
+        }
+        // Is the text the same?
+        //   Need to use equals on the string and not
+        //   on the stringbuffer as equals on the string buffer
+        //   does not compare the contents.
+        if (!getWrapper().getText().toString().equals(
+                other.getWrapper().getText().toString())) {
+            return false;
+        }
+        // Are the sub elements the same ?
+        if (children == null || children.size() == 0) {
+            return other.children == null || other.children.size() == 0;
+        }
+        if (other.children == null) {
+            return false;
+        }
+        if (children.size() != other.children.size()) {
+            return false;
+        }
+        for (int i = 0; i < children.size(); ++i) {
+            UnknownElement child = (UnknownElement) children.get(i);
+            if (!child.similar(other.children.get(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean equalsString(String a, String b) {
+        return (a == null) ? (b == null) : a.equals(b);
+    }
+
+    /**
+     * Make a copy of the unknown element and set it in the new project.
+     * @param newProject the project to create the UE in.
+     * @return the copied UE.
+     */
+    public UnknownElement copy(Project newProject) {
+        UnknownElement ret = new UnknownElement(getTag());
+        ret.setNamespace(getNamespace());
+        ret.setProject(newProject);
+        ret.setQName(getQName());
+        ret.setTaskType(getTaskType());
+        ret.setTaskName(getTaskName());
+        ret.setLocation(getLocation());
+        if (getOwningTarget() == null) {
+            Target t = new Target();
+            t.setProject(getProject());
+            ret.setOwningTarget(t);
+        } else {
+            ret.setOwningTarget(getOwningTarget());
+        }
+        RuntimeConfigurable copyRC = new RuntimeConfigurable(
+            ret, getTaskName());
+        copyRC.setPolyType(getWrapper().getPolyType());
+        Map m = getWrapper().getAttributeMap();
+        for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            copyRC.setAttribute(
+                (String) entry.getKey(), (String) entry.getValue());
+        }
+        copyRC.addText(getWrapper().getText().toString());
+
+        for (Enumeration e = getWrapper().getChildren(); e.hasMoreElements();) {
+            RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement();
+            UnknownElement ueChild = (UnknownElement) r.getProxy();
+            UnknownElement copyChild = ueChild.copy(newProject);
+            copyRC.addChild(copyChild.getWrapper());
+            ret.addChild(copyChild);
+        }
+        return ret;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/UnsupportedAttributeException.java b/trunk/src/main/org/apache/tools/ant/UnsupportedAttributeException.java
new file mode 100644
index 0000000..7d082d2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/UnsupportedAttributeException.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Used to report attempts to set an unsupported attribute
+ *
+ * @since Ant 1.6.3
+ */
+public class UnsupportedAttributeException extends BuildException {
+
+    private String attribute;
+
+    /**
+     * Constructs an unsupported attribute exception.
+     * @param msg       The string containing the message.
+     * @param attribute The unsupported attribute.
+     */
+    public UnsupportedAttributeException(String msg, String attribute) {
+        super(msg);
+        this.attribute = attribute;
+    }
+
+    /**
+     * Get the attribute that is wrong.
+     *
+     * @return the attribute name.
+     */
+    public String getAttribute() {
+        return attribute;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/UnsupportedElementException.java b/trunk/src/main/org/apache/tools/ant/UnsupportedElementException.java
new file mode 100644
index 0000000..a03bb47
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/UnsupportedElementException.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * Used to report attempts to set an unsupported element
+ * When the attempt to set the element is made,
+ * the code does not not know the name of the task/type
+ * based on a mapping from the classname to the task/type.
+ * However one class may be used by a lot of task/types.
+ * This exception may be caught by code that does know
+ * the task/type and it will reset the message to the
+ * correct message.
+ * This will be done once (in the case of a recursive
+ * call to handlechildren).
+ *
+ * @since Ant 1.6.3
+ */
+public class UnsupportedElementException extends BuildException {
+
+    private String element;
+
+    /**
+     * Constructs an unsupported element exception.
+     * @param msg The string containing the message.
+     * @param element The name of the incorrect element.
+     */
+    public UnsupportedElementException(String msg, String element) {
+        super(msg);
+        this.element = element;
+    }
+
+    /**
+     * Get the element that is wrong.
+     *
+     * @return the element name.
+     */
+    public String getElement() {
+        return element;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/XmlLogger.java b/trunk/src/main/org/apache/tools/ant/XmlLogger.java
new file mode 100644
index 0000000..d5ba6b3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/XmlLogger.java
@@ -0,0 +1,462 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Writer;
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.Enumeration;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+/**
+ * Generates a file in the current directory with
+ * an XML description of what happened during a build.
+ * The default filename is "log.xml", but this can be overridden
+ * with the property <code>XmlLogger.file</code>.
+ *
+ * This implementation assumes in its sanity checking that only one
+ * thread runs a particular target/task at a time. This is enforced
+ * by the way that parallel builds and antcalls are done - and
+ * indeed all but the simplest of tasks could run into problems
+ * if executed in parallel.
+ *
+ * @see Project#addBuildListener(BuildListener)
+ */
+public class XmlLogger implements BuildLogger {
+
+    private int msgOutputLevel = Project.MSG_DEBUG;
+    private PrintStream outStream;
+
+    /** DocumentBuilder to use when creating the document to start with. */
+    private static DocumentBuilder builder = getDocumentBuilder();
+
+    /**
+     * Returns a default DocumentBuilder instance or throws an
+     * ExceptionInInitializerError if it can't be created.
+     *
+     * @return a default DocumentBuilder instance.
+     */
+    private static DocumentBuilder getDocumentBuilder() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        } catch (Exception exc) {
+            throw new ExceptionInInitializerError(exc);
+        }
+    }
+
+    /** XML element name for a build. */
+    private static final String BUILD_TAG = "build";
+
+    /** XML element name for a target. */
+    private static final String TARGET_TAG = "target";
+
+    /** XML element name for a task. */
+    private static final String TASK_TAG = "task";
+
+    /** XML element name for a message. */
+    private static final String MESSAGE_TAG = "message";
+
+    /** XML attribute name for a name. */
+    private static final String NAME_ATTR = "name";
+
+    /** XML attribute name for a time. */
+    private static final String TIME_ATTR = "time";
+
+    /** XML attribute name for a message priority. */
+    private static final String PRIORITY_ATTR = "priority";
+
+    /** XML attribute name for a file location. */
+    private static final String LOCATION_ATTR = "location";
+
+    /** XML attribute name for an error description. */
+    private static final String ERROR_ATTR = "error";
+
+    /** XML element name for a stack trace. */
+    private static final String STACKTRACE_TAG = "stacktrace";
+
+    /** The complete log document for this build. */
+    private Document doc = builder.newDocument();
+
+    /** Mapping for when tasks started (Task to TimedElement). */
+    private Hashtable tasks = new Hashtable();
+
+    /** Mapping for when targets started (Task to TimedElement). */
+    private Hashtable targets = new Hashtable();
+
+    /**
+     * Mapping of threads to stacks of elements
+     * (Thread to Stack of TimedElement).
+     */
+    private Hashtable threadStacks = new Hashtable();
+
+    /**
+     * When the build started.
+     */
+    private TimedElement buildElement = null;
+
+    /** Utility class representing the time an element started. */
+    private static class TimedElement {
+        /**
+         * Start time in milliseconds
+         * (as returned by <code>System.currentTimeMillis()</code>).
+         */
+        private long startTime;
+        /** Element created at the start time. */
+        private Element element;
+        public String toString() {
+            return element.getTagName() + ":" + element.getAttribute("name");
+        }
+    }
+
+    /**
+     *  Constructs a new BuildListener that logs build events to an XML file.
+     */
+    public XmlLogger() {
+    }
+
+    /**
+     * Fired when the build starts, this builds the top-level element for the
+     * document and remembers the time of the start of the build.
+     *
+     * @param event Ignored.
+     */
+    public void buildStarted(BuildEvent event) {
+        buildElement = new TimedElement();
+        buildElement.startTime = System.currentTimeMillis();
+        buildElement.element = doc.createElement(BUILD_TAG);
+    }
+
+    /**
+     * Fired when the build finishes, this adds the time taken and any
+     * error stacktrace to the build element and writes the document to disk.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void buildFinished(BuildEvent event) {
+        long totalTime = System.currentTimeMillis() - buildElement.startTime;
+        buildElement.element.setAttribute(TIME_ATTR, DefaultLogger.formatTime(totalTime));
+
+        if (event.getException() != null) {
+            buildElement.element.setAttribute(ERROR_ATTR, event.getException().toString());
+            // print the stacktrace in the build file it is always useful...
+            // better have too much info than not enough.
+            Throwable t = event.getException();
+            Text errText = doc.createCDATASection(StringUtils.getStackTrace(t));
+            Element stacktrace = doc.createElement(STACKTRACE_TAG);
+            stacktrace.appendChild(errText);
+            buildElement.element.appendChild(stacktrace);
+        }
+        String outFilename = event.getProject().getProperty("XmlLogger.file");
+        if (outFilename == null) {
+            outFilename = "log.xml";
+        }
+        String xslUri = event.getProject().getProperty("ant.XmlLogger.stylesheet.uri");
+        if (xslUri == null) {
+            xslUri = "log.xsl";
+        }
+        Writer out = null;
+        try {
+            // specify output in UTF8 otherwise accented characters will blow
+            // up everything
+            OutputStream stream = outStream;
+            if (stream == null) {
+                stream = new FileOutputStream(outFilename);
+            }
+            out = new OutputStreamWriter(stream, "UTF8");
+            out.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+            if (xslUri.length() > 0) {
+                out.write("<?xml-stylesheet type=\"text/xsl\" href=\"" + xslUri + "\"?>\n\n");
+            }
+            new DOMElementWriter().write(buildElement.element, out, 0, "\t");
+            out.flush();
+        } catch (IOException exc) {
+            throw new BuildException("Unable to write log file", exc);
+        } finally {
+            FileUtils.close(out);
+        }
+        buildElement = null;
+    }
+
+    /**
+     * Returns the stack of timed elements for the current thread.
+     * @return the stack of timed elements for the current thread
+     */
+    private Stack getStack() {
+        Stack threadStack = (Stack) threadStacks.get(Thread.currentThread());
+        if (threadStack == null) {
+            threadStack = new Stack();
+            threadStacks.put(Thread.currentThread(), threadStack);
+        }
+        /* For debugging purposes uncomment:
+        org.w3c.dom.Comment s = doc.createComment("stack=" + threadStack);
+        buildElement.element.appendChild(s);
+         */
+        return threadStack;
+    }
+
+    /**
+     * Fired when a target starts building, this pushes a timed element
+     * for the target onto the stack of elements for the current thread,
+     * remembering the current time and the name of the target.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void targetStarted(BuildEvent event) {
+        Target target = event.getTarget();
+        TimedElement targetElement = new TimedElement();
+        targetElement.startTime = System.currentTimeMillis();
+        targetElement.element = doc.createElement(TARGET_TAG);
+        targetElement.element.setAttribute(NAME_ATTR, target.getName());
+        targets.put(target, targetElement);
+        getStack().push(targetElement);
+    }
+
+    /**
+     * Fired when a target finishes building, this adds the time taken
+     * and any error stacktrace to the appropriate target element in the log.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void targetFinished(BuildEvent event) {
+        Target target = event.getTarget();
+        TimedElement targetElement = (TimedElement) targets.get(target);
+        if (targetElement != null) {
+            long totalTime = System.currentTimeMillis() - targetElement.startTime;
+            targetElement.element.setAttribute(TIME_ATTR, DefaultLogger.formatTime(totalTime));
+
+            TimedElement parentElement = null;
+            Stack threadStack = getStack();
+            if (!threadStack.empty()) {
+                TimedElement poppedStack = (TimedElement) threadStack.pop();
+                if (poppedStack != targetElement) {
+                    throw new RuntimeException("Mismatch - popped element = " + poppedStack
+                            + " finished target element = " + targetElement);
+                }
+                if (!threadStack.empty()) {
+                    parentElement = (TimedElement) threadStack.peek();
+                }
+            }
+            if (parentElement == null) {
+                buildElement.element.appendChild(targetElement.element);
+            } else {
+                parentElement.element.appendChild(targetElement.element);
+            }
+        }
+        targets.remove(target);
+    }
+
+    /**
+     * Fired when a task starts building, this pushes a timed element
+     * for the task onto the stack of elements for the current thread,
+     * remembering the current time and the name of the task.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void taskStarted(BuildEvent event) {
+        TimedElement taskElement = new TimedElement();
+        taskElement.startTime = System.currentTimeMillis();
+        taskElement.element = doc.createElement(TASK_TAG);
+
+        Task task = event.getTask();
+        String name = event.getTask().getTaskName();
+        if (name == null) {
+            name = "";
+        }
+        taskElement.element.setAttribute(NAME_ATTR, name);
+        taskElement.element.setAttribute(LOCATION_ATTR, event.getTask().getLocation().toString());
+        tasks.put(task, taskElement);
+        getStack().push(taskElement);
+    }
+
+    /**
+     * Fired when a task finishes building, this adds the time taken
+     * and any error stacktrace to the appropriate task element in the log.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void taskFinished(BuildEvent event) {
+        Task task = event.getTask();
+        TimedElement taskElement = (TimedElement) tasks.get(task);
+        if (taskElement == null) {
+            throw new RuntimeException("Unknown task " + task + " not in " + tasks);
+        }
+        long totalTime = System.currentTimeMillis() - taskElement.startTime;
+        taskElement.element.setAttribute(TIME_ATTR, DefaultLogger.formatTime(totalTime));
+        Target target = task.getOwningTarget();
+        TimedElement targetElement = null;
+        if (target != null) {
+            targetElement = (TimedElement) targets.get(target);
+        }
+        if (targetElement == null) {
+            buildElement.element.appendChild(taskElement.element);
+        } else {
+            targetElement.element.appendChild(taskElement.element);
+        }
+        Stack threadStack = getStack();
+        if (!threadStack.empty()) {
+            TimedElement poppedStack = (TimedElement) threadStack.pop();
+            if (poppedStack != taskElement) {
+                throw new RuntimeException("Mismatch - popped element = " + poppedStack
+                        + " finished task element = " + taskElement);
+            }
+        }
+        tasks.remove(task);
+    }
+
+    /**
+     * Get the TimedElement associated with a task.
+     *
+     * Where the task is not found directly, search for unknown elements which
+     * may be hiding the real task
+     */
+    private TimedElement getTaskElement(Task task) {
+        TimedElement element = (TimedElement) tasks.get(task);
+        if (element != null) {
+            return element;
+        }
+        for (Enumeration e = tasks.keys(); e.hasMoreElements();) {
+            Task key = (Task) e.nextElement();
+            if (key instanceof UnknownElement) {
+                if (((UnknownElement) key).getTask() == task) {
+                    return (TimedElement) tasks.get(key);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Fired when a message is logged, this adds a message element to the
+     * most appropriate parent element (task, target or build) and records
+     * the priority and text of the message.
+     *
+     * @param event An event with any relevant extra information.
+     *              Will not be <code>null</code>.
+     */
+    public void messageLogged(BuildEvent event) {
+        int priority = event.getPriority();
+        if (priority > msgOutputLevel) {
+            return;
+        }
+        Element messageElement = doc.createElement(MESSAGE_TAG);
+
+        String name = "debug";
+        switch (priority) {
+            case Project.MSG_ERR:
+                name = "error";
+                break;
+            case Project.MSG_WARN:
+                name = "warn";
+                break;
+            case Project.MSG_INFO:
+                name = "info";
+                break;
+            default:
+                name = "debug";
+                break;
+        }
+        messageElement.setAttribute(PRIORITY_ATTR, name);
+
+        Throwable ex = event.getException();
+        if (Project.MSG_DEBUG <= msgOutputLevel && ex != null) {
+            Text errText = doc.createCDATASection(StringUtils.getStackTrace(ex));
+            Element stacktrace = doc.createElement(STACKTRACE_TAG);
+            stacktrace.appendChild(errText);
+            buildElement.element.appendChild(stacktrace);
+        }
+        Text messageText = doc.createCDATASection(event.getMessage());
+        messageElement.appendChild(messageText);
+
+        TimedElement parentElement = null;
+
+        Task task = event.getTask();
+
+        Target target = event.getTarget();
+        if (task != null) {
+            parentElement = getTaskElement(task);
+        }
+        if (parentElement == null && target != null) {
+            parentElement = (TimedElement) targets.get(target);
+        }
+        if (parentElement != null) {
+            parentElement.element.appendChild(messageElement);
+        } else {
+            buildElement.element.appendChild(messageElement);
+        }
+    }
+
+    // -------------------------------------------------- BuildLogger interface
+
+    /**
+     * Set the logging level when using this as a Logger
+     *
+     * @param level the logging level -
+     *        see {@link org.apache.tools.ant.Project#MSG_ERR Project}
+     *        class for level definitions
+     */
+    public void setMessageOutputLevel(int level) {
+        msgOutputLevel = level;
+    }
+
+    /**
+     * Set the output stream to which logging output is sent when operating
+     * as a logger.
+     *
+     * @param output the output PrintStream.
+     */
+    public void setOutputPrintStream(PrintStream output) {
+        this.outStream = new PrintStream(output, true);
+    }
+
+    /**
+     * Ignore emacs mode, as it has no meaning in XML format
+     *
+     * @param emacsMode true if logger should produce emacs compatible
+     *        output
+     */
+    public void setEmacsMode(boolean emacsMode) {
+    }
+
+    /**
+     * Ignore error print stream. All output will be written to
+     * either the XML log file or the PrintStream provided to
+     * setOutputPrintStream
+     *
+     * @param err the stream we are going to ignore.
+     */
+    public void setErrorPrintStream(PrintStream err) {
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/antlib.xml b/trunk/src/main/org/apache/tools/ant/antlib.xml
new file mode 100644
index 0000000..d274d09
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/antlib.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+  <!--
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+-->
+<antlib>
+  <!--
+       This is the ant lib definition for ant.
+       Currently it only contains componentdefinitions (restricted
+       types that are not allowed at the top level)
+       - conditions, selectors and comparators
+       (those that are not top-level types (taskdefs or typedefs).
+       defined in defaults.properties of taskdefs and types
+       packages).
+
+       This is currently experimental and it is most
+       likely that these definitions will be placed
+       in a Java Ant definition class.
+  -->
+  <!-- conditions -->
+  <componentdef name="and" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.And"/>
+  <componentdef name="contains" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Contains"/>
+  <componentdef name="equals" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Equals"/>
+  <componentdef name="filesmatch" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.FilesMatch"/>
+  <componentdef name="hasfreespace" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.HasFreeSpace"/>
+  <componentdef name="hasmethod" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.HasMethod"/>
+  <componentdef name="http" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Http"/>
+  <componentdef name="isfailure" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsFailure"/>
+  <componentdef name="isfalse" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsFalse"/>
+  <componentdef name="isreachable" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsReachable"/>
+  <componentdef name="isreference" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsReference"/>
+  <componentdef name="isset" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsSet"/>
+  <componentdef name="issigned" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsSigned"/>
+  <componentdef name="istrue" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.IsTrue"/>
+  <componentdef name="matches" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Matches"/>
+  <componentdef name="not" onerror="ignore"
+       classname="org.apache.tools.ant.types.resources.selectors.Not"/>
+  <componentdef name="or" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Or"/>
+  <componentdef name="os" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Os"/>
+  <componentdef name="parsersupports" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.ParserSupports"/>
+  <componentdef name="resourcecontains" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.ResourceContains"/>
+  <componentdef name="resourcesmatch" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.ResourcesMatch"/>
+  <componentdef name="socket" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Socket"/>
+  <componentdef name="typefound" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.TypeFound"/>
+  <componentdef name="xor" onerror="ignore"
+       classname="org.apache.tools.ant.taskdefs.condition.Xor"/>
+
+  <!-- selectors -->
+  <componentdef name="and" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.And" />
+  <componentdef name="compare" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Compare" />
+  <componentdef name="contains" onerror="ignore"
+    classname="org.apache.tools.ant.types.selectors.ContainsSelector" />
+  <componentdef name="containsregexp" onerror="ignore"
+    classname="org.apache.tools.ant.types.selectors.ContainsRegexpSelector" />
+  <componentdef name="date" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Date" />
+  <componentdef name="exists" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Exists" />
+  <componentdef name="instanceof" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.InstanceOf" />
+  <componentdef name="majority" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Majority" />
+  <componentdef name="modified" onerror="ignore"
+    classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector" />
+  <componentdef name="name" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Name" />
+  <componentdef name="none" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.None" />
+  <componentdef name="not" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Not" />
+  <componentdef name="or" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Or" />
+  <componentdef name="size" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Size" />
+  <componentdef name="type" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.selectors.Type" />
+
+
+  <!-- comparators -->
+  <componentdef name="name" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Name" />
+  <componentdef name="size" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Size" />
+  <componentdef name="date" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Date" />
+  <componentdef name="exists" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Exists" />
+  <componentdef name="type" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Type" />
+  <componentdef name="content" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Content" />
+  <componentdef name="reverse" onerror="ignore"
+    classname="org.apache.tools.ant.types.resources.comparators.Reverse" />
+
+</antlib>
+
diff --git a/trunk/src/main/org/apache/tools/ant/defaultManifest.mf b/trunk/src/main/org/apache/tools/ant/defaultManifest.mf
new file mode 100644
index 0000000..fd30a23
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/defaultManifest.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+Ant-Version: Apache Ant ${project.version}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/dispatch/DispatchTask.java b/trunk/src/main/org/apache/tools/ant/dispatch/DispatchTask.java
new file mode 100644
index 0000000..817b90c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/dispatch/DispatchTask.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.dispatch;
+
+import org.apache.tools.ant.Task;
+
+/**
+ * Tasks extending this class may contain multiple actions.
+ * The method that is invoked for execution depends upon the
+ * value of the action attribute of the task.
+ * <br/>
+ * Example:<br/>
+ * &lt;mytask action=&quot;list&quot;/&gt; will invoke the method
+ * with the signature public void list() in mytask's class.
+ * If the action attribute is not defined in the task or is empty,
+ * the execute() method will be called.
+ */
+public abstract class DispatchTask extends Task implements Dispatchable {
+    private String action;
+
+    /**
+     * Get the action parameter name.
+     * @return the <code>String</code> "action" by default (can be overridden).
+     */
+    public String getActionParameterName() {
+        return "action";
+    }
+
+    /**
+     * Set the action.
+     * @param action the method name.
+     */
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    /**
+     * Get the action.
+     * @return the action.
+     */
+    public String getAction() {
+        return action;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/dispatch/DispatchUtils.java b/trunk/src/main/org/apache/tools/ant/dispatch/DispatchUtils.java
new file mode 100644
index 0000000..5614be2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/dispatch/DispatchUtils.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.dispatch;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.Task;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Determines and Executes the action method for the task.
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF - (bc)
+public class DispatchUtils {
+    /**
+     * Determines and Executes the action method for the task.
+     * @param task the task to execute.
+     * @throws BuildException on error.
+     */
+    public static final void execute(Object task) throws BuildException {
+        String methodName = "execute";
+        Dispatchable dispatchable = null;
+        try {
+            if (task instanceof Dispatchable) {
+                dispatchable = (Dispatchable) task;
+            } else if (task instanceof UnknownElement) {
+                UnknownElement ue = (UnknownElement) task;
+                Object realThing = ue.getRealThing();
+                if (realThing != null
+                    && realThing instanceof Dispatchable
+                    && realThing instanceof Task) {
+                    dispatchable = (Dispatchable) realThing;
+                }
+            }
+            if (dispatchable != null) {
+                String mName = null;
+                try {
+                    final String name = dispatchable.getActionParameterName();
+                    if (name != null && name.trim().length() > 0) {
+                        mName = "get" + name.trim().substring(0, 1).toUpperCase();
+                        if (name.length() > 1) {
+                            mName += name.substring(1);
+                        }
+                        final Class c = dispatchable.getClass();
+                        final Method actionM = c.getMethod(mName, new Class[0]);
+                        if (actionM != null) {
+                            final Object o = actionM.invoke(dispatchable, (Object[]) null);
+                            if (o != null) {
+                                final String s = o.toString();
+                                if (s != null && s.trim().length() > 0) {
+                                    methodName = s.trim();
+                                    Method executeM = null;
+                                    executeM = dispatchable.getClass().getMethod(
+                                        methodName, new Class[0]);
+                                    if (executeM == null) {
+                                        throw new BuildException(
+                                            "No public " + methodName + "() in "
+                                            + dispatchable.getClass());
+                                    }
+                                    executeM.invoke(dispatchable, (Object[]) null);
+                                    if (task instanceof UnknownElement) {
+                                        ((UnknownElement) task).setRealThing(null);
+                                    }
+                                } else {
+                                    throw new BuildException(
+                                        "Dispatchable Task attribute '" + name.trim()
+                                        + "' not set or value is empty.");
+                                }
+                            } else {
+                                    throw new BuildException(
+                                        "Dispatchable Task attribute '" + name.trim()
+                                        + "' not set or value is empty.");
+                            }
+                        }
+                    } else {
+                        throw new BuildException(
+                            "Action Parameter Name must not be empty for Dispatchable Task.");
+                    }
+                } catch (NoSuchMethodException nsme) {
+                    throw new BuildException("No public " + mName + "() in " + task.getClass());
+                }
+            } else {
+                Method executeM = null;
+                executeM = task.getClass().getMethod(methodName, new Class[0]);
+                if (executeM == null) {
+                    throw new BuildException("No public " + methodName + "() in "
+                        + task.getClass());
+                }
+                executeM.invoke(task, (Object[]) null);
+                if (task instanceof UnknownElement) {
+                    ((UnknownElement) task).setRealThing(null);
+                }
+            }
+        } catch (InvocationTargetException ie) {
+            Throwable t = ie.getTargetException();
+            if (t instanceof BuildException) {
+                throw ((BuildException) t);
+            } else {
+                throw new BuildException(t);
+            }
+        } catch (NoSuchMethodException e) {
+            throw new BuildException(e);
+        } catch (IllegalAccessException e) {
+            throw new BuildException(e);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/dispatch/Dispatchable.java b/trunk/src/main/org/apache/tools/ant/dispatch/Dispatchable.java
new file mode 100644
index 0000000..41684f4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/dispatch/Dispatchable.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.dispatch;
+
+/**
+ * Classes implementing this interface specify the
+ * name of the parameter that contains the name
+ * of the task's method to execute.
+ */
+public interface Dispatchable {
+    /**
+     * Get the name of the parameter.
+     * @return the name of the parameter that contains the name of the method.
+     */
+    String getActionParameterName();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/BaseFilterReader.java b/trunk/src/main/org/apache/tools/ant/filters/BaseFilterReader.java
new file mode 100644
index 0000000..13ece34
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/BaseFilterReader.java
@@ -0,0 +1,198 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Base class for core filter readers.
+ *
+ */
+public abstract class BaseFilterReader extends FilterReader {
+    /** Buffer size used when reading */
+    private static final int BUFFER_SIZE = 8192;
+
+    /** Have the parameters passed been interpreted? */
+    private boolean initialized = false;
+
+    /** The Ant project this filter is part of. */
+    private Project project = null;
+
+    /**
+     * Constructor used by Ant's introspection mechanism.
+     * The original filter reader is only used for chaining
+     * purposes, never for filtering purposes (and indeed
+     * it would be useless for filtering purposes, as it has
+     * no real data to filter). ChainedReaderHelper uses
+     * this placeholder instance to create a chain of real filters.
+     */
+    public BaseFilterReader() {
+        super(new StringReader(""));
+        FileUtils.close(this);
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     *
+     */
+    public BaseFilterReader(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Reads characters into a portion of an array.  This method will block
+     * until some input is available, an I/O error occurs, or the end of the
+     * stream is reached.
+     *
+     * @param      cbuf  Destination buffer to write characters to.
+     *                   Must not be <code>null</code>.
+     * @param      off   Offset at which to start storing characters.
+     * @param      len   Maximum number of characters to read.
+     *
+     * @return     the number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public final int read(final char[] cbuf, final int off,
+                          final int len) throws IOException {
+        for (int i = 0; i < len; i++) {
+            final int ch = read();
+            if (ch == -1) {
+                if (i == 0) {
+                    return -1;
+                } else {
+                    return i;
+                }
+            }
+            cbuf[off + i] = (char) ch;
+        }
+        return len;
+    }
+
+    /**
+     * Skips characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    the number of characters actually skipped
+     *
+     * @exception  IllegalArgumentException  If <code>n</code> is negative.
+     * @exception  IOException  If an I/O error occurs
+     */
+    public final long skip(final long n)
+        throws IOException, IllegalArgumentException {
+        if (n < 0L) {
+            throw new IllegalArgumentException("skip value is negative");
+        }
+
+        for (long i = 0; i < n; i++) {
+            if (read() == -1) {
+                return i;
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Sets the initialized status.
+     *
+     * @param initialized Whether or not the filter is initialized.
+     */
+    protected final void setInitialized(final boolean initialized) {
+        this.initialized = initialized;
+    }
+
+    /**
+     * Returns the initialized status.
+     *
+     * @return whether or not the filter is initialized
+     */
+    protected final boolean getInitialized() {
+        return initialized;
+    }
+
+    /**
+     * Sets the project to work with.
+     *
+     * @param project The project this filter is part of.
+     *                Should not be <code>null</code>.
+     */
+    public final void setProject(final Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Returns the project this filter is part of.
+     *
+     * @return the project this filter is part of
+     */
+    protected final Project getProject() {
+        return project;
+    }
+
+    /**
+     * Reads a line of text ending with '\n' (or until the end of the stream).
+     * The returned String retains the '\n'.
+     *
+     * @return the line read, or <code>null</code> if the end of the stream
+     * has already been reached
+     *
+     * @exception IOException if the underlying reader throws one during
+     *                        reading
+     */
+    protected final String readLine() throws IOException {
+        int ch = in.read();
+
+        if (ch == -1) {
+            return null;
+        }
+
+        StringBuffer line = new StringBuffer();
+
+        while (ch != -1) {
+            line.append ((char) ch);
+            if (ch == '\n') {
+                break;
+            }
+            ch = in.read();
+        }
+        return line.toString();
+    }
+
+    /**
+     * Reads to the end of the stream, returning the contents as a String.
+     *
+     * @return the remaining contents of the reader, as a String
+     *
+     * @exception IOException if the underlying reader throws one during
+     *            reading
+     */
+    protected final String readFully() throws IOException {
+        return FileUtils.readFully(in, BUFFER_SIZE);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/BaseParamFilterReader.java b/trunk/src/main/org/apache/tools/ant/filters/BaseParamFilterReader.java
new file mode 100644
index 0000000..288aa9a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/BaseParamFilterReader.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.Reader;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Parameterizable;
+
+/**
+ * Parameterized base class for core filter readers.
+ *
+ */
+public abstract class BaseParamFilterReader
+    extends BaseFilterReader
+    implements Parameterizable {
+    /** The passed in parameter array. */
+    private Parameter[] parameters;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public BaseParamFilterReader() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public BaseParamFilterReader(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Sets the parameters used by this filter, and sets
+     * the filter to an uninitialized status.
+     *
+     * @param parameters The parameters to be used by this filter.
+     *                   Should not be <code>null</code>.
+     */
+    public final void setParameters(final Parameter[] parameters) {
+        this.parameters = parameters;
+        setInitialized(false);
+    }
+
+    /**
+     * Returns the parameters to be used by this filter.
+     *
+     * @return the parameters to be used by this filter
+     */
+    protected final Parameter[] getParameters() {
+        return parameters;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/ChainableReader.java b/trunk/src/main/org/apache/tools/ant/filters/ChainableReader.java
new file mode 100644
index 0000000..6706039
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/ChainableReader.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.Reader;
+
+/**
+ * Interface indicating that a reader may be chained to another one.
+ *
+ */
+public interface ChainableReader {
+    /**
+     * Returns a reader with the same configuration as this one,
+     * but filtering input from the specified reader.
+     *
+     * @param rdr the reader which the returned reader should be filtering
+     *
+     * @return a reader with the same configuration as this one, but
+     *         filtering input from the specified reader
+     */
+    Reader chain(Reader rdr);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/ClassConstants.java b/trunk/src/main/org/apache/tools/ant/filters/ClassConstants.java
new file mode 100644
index 0000000..0bf7649
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/ClassConstants.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Assembles the constants declared in a Java class in
+ * <code>key1=value1(line separator)key2=value2</code>
+ * format.
+ *<p>
+ * Notes:
+ * <ol>
+ * <li>This filter uses the BCEL external toolkit.
+ * <li>This assembles only those constants that are not created
+ * using the syntax <code>new whatever()</code>
+ * <li>This assembles constants declared using the basic datatypes
+ * and String only.</li>
+ * <li>The access modifiers of the declared constants do not matter.</li>
+ *</ol>
+ * Example:<br>
+ * <pre>&lt;classconstants/&gt;</pre>
+ * Or:
+ * <pre>&lt;filterreader
+ *    classname=&quot;org.apache.tools.ant.filters.ClassConstants&quot;/&gt;</pre>
+ */
+public final class ClassConstants
+    extends BaseFilterReader
+    implements ChainableReader {
+    /** Data that must be read from, if not null. */
+    private String queuedData = null;
+
+    /** Helper Class to be invoked via reflection. */
+    private static final String JAVA_CLASS_HELPER =
+        "org.apache.tools.ant.filters.util.JavaClassHelper";
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public ClassConstants() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader. The contents of the passed-in reader
+     * are expected to be the name of the class from which to produce a
+     * list of constants.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public ClassConstants(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Reads and assembles the constants declared in a class file.
+     *
+     * @return the next character in the list of constants, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading, or if the constants for the specified class cannot
+     * be read (for example due to the class not being found).
+     */
+    public int read() throws IOException {
+
+        int ch = -1;
+
+        if (queuedData != null && queuedData.length() == 0) {
+            queuedData = null;
+        }
+
+        if (queuedData != null) {
+            ch = queuedData.charAt(0);
+            queuedData = queuedData.substring(1);
+            if (queuedData.length() == 0) {
+                queuedData = null;
+            }
+        } else {
+            final String clazz = readFully();
+            if (clazz == null || clazz.length() == 0) {
+                ch = -1;
+            } else {
+                final byte[] bytes = clazz.getBytes("ISO-8859-1");
+                try {
+                    final Class javaClassHelper =
+                        Class.forName(JAVA_CLASS_HELPER);
+                    if (javaClassHelper != null) {
+                        final Class[] params = {
+                            byte[].class
+                        };
+                        final Method getConstants =
+                            javaClassHelper.getMethod("getConstants", params);
+                        final Object[] args = {
+                            bytes
+                        };
+                        // getConstants is a static method, no need to
+                        // pass in the object
+                        final StringBuffer sb = (StringBuffer)
+                                getConstants.invoke(null, args);
+                        if (sb.length() > 0) {
+                            queuedData = sb.toString();
+                            return read();
+                        }
+                    }
+                } catch (NoClassDefFoundError ex) {
+                    throw ex;
+                } catch (RuntimeException ex) {
+                    throw ex;
+                } catch (InvocationTargetException ex) {
+                    Throwable t = ex.getTargetException();
+                    if (t instanceof NoClassDefFoundError) {
+                        throw (NoClassDefFoundError) t;
+                    }
+                    if (t instanceof RuntimeException) {
+                        throw (RuntimeException) t;
+                    }
+                    throw new BuildException(t);
+                } catch (Exception ex) {
+                    throw new BuildException(ex);
+                }
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Creates a new ClassConstants using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        ClassConstants newFilter = new ClassConstants(rdr);
+        return newFilter;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/ConcatFilter.java b/trunk/src/main/org/apache/tools/ant/filters/ConcatFilter.java
new file mode 100644
index 0000000..3d0943b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/ConcatFilter.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Concats a file before and/or after the file.
+ *
+ * <p>Example:<pre>
+ * <copy todir="build">
+ *     <fileset dir="src" includes="*.java"/>
+ *     <filterchain>
+ *         <concatfilter prepend="apache-license-java.txt"/>
+ *     </filterchain>
+ * </copy>
+ * </pre>
+ * Copies all java sources from <i>src</i> to <i>build</i> and adds the
+ * content of <i>apache-license-java.txt</i> add the beginning of each
+ * file.</p>
+ *
+ * @since 1.6
+ * @version 2003-09-23
+ */
+public final class ConcatFilter extends BaseParamFilterReader
+    implements ChainableReader {
+
+    /** File to add before the content. */
+    private File prepend;
+
+    /** File to add after the content. */
+    private File append;
+
+    /** Reader for prepend-file. */
+    private Reader prependReader = null;
+
+    /** Reader for append-file. */
+    private Reader appendReader = null;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public ConcatFilter() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public ConcatFilter(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream. If the desired
+     * number of lines have already been read, the resulting stream is
+     * effectively at an end. Otherwise, the next character from the
+     * underlying stream is read and returned.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        // do the "singleton" initialization
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        // The readers return -1 if they end. So simply read the "prepend"
+        // after that the "content" and at the end the "append" file.
+        if (prependReader != null) {
+            ch = prependReader.read();
+            if (ch == -1) {
+                // I am the only one so I have to close the reader
+                prependReader.close();
+                prependReader = null;
+            }
+        }
+        if (ch == -1) {
+            ch = super.read();
+        }
+        if (ch == -1) {
+            // don't call super.close() because that reader is used
+            // on other places ...
+            if (appendReader != null) {
+                ch = appendReader.read();
+                if (ch == -1) {
+                    // I am the only one so I have to close the reader
+                    appendReader.close();
+                    appendReader = null;
+                }
+            }
+        }
+
+        return ch;
+    }
+
+    /**
+     * Sets <i>prepend</i> attribute.
+     * @param prepend new value
+     */
+    public void setPrepend(final File prepend) {
+        this.prepend = prepend;
+    }
+
+    /**
+     * Returns <i>prepend</i> attribute.
+     * @return prepend attribute
+     */
+    public File getPrepend() {
+        return prepend;
+    }
+
+    /**
+     * Sets <i>append</i> attribute.
+     * @param append new value
+     */
+    public void setAppend(final File append) {
+        this.append = append;
+    }
+
+    /**
+     * Returns <i>append</i> attribute.
+     * @return append attribute
+     */
+    public File getAppend() {
+        return append;
+    }
+
+    /**
+     * Creates a new ConcatReader using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        ConcatFilter newFilter = new ConcatFilter(rdr);
+        newFilter.setPrepend(getPrepend());
+        newFilter.setAppend(getAppend());
+        // Usually the initialized is set to true. But here it must not.
+        // Because the prepend and append readers have to be instantiated
+        // on runtime
+        //newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Scans the parameters list for the "lines" parameter and uses
+     * it to set the number of lines to be returned in the filtered stream.
+     * also scan for skip parameter.
+     */
+    private void initialize() throws IOException {
+        // get parameters
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if ("prepend".equals(params[i].getName())) {
+                    setPrepend(new File(params[i].getValue()));
+                    continue;
+                }
+                if ("append".equals(params[i].getName())) {
+                    setAppend(new File(params[i].getValue()));
+                    continue;
+                }
+            }
+        }
+        if (prepend != null) {
+            if (!prepend.isAbsolute()) {
+                prepend = new File(getProject().getBaseDir(), prepend.getPath());
+            }
+            prependReader = new BufferedReader(new FileReader(prepend));
+        }
+        if (append != null) {
+            if (!append.isAbsolute()) {
+                append = new File(getProject().getBaseDir(), append.getPath());
+            }
+            appendReader = new BufferedReader(new FileReader(append));
+        }
+   }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/EscapeUnicode.java b/trunk/src/main/org/apache/tools/ant/filters/EscapeUnicode.java
new file mode 100644
index 0000000..558ad34
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/EscapeUnicode.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This method converts non-latin characters to unicode escapes.
+ * Useful to load properties containing non latin
+ * Example:
+ *
+ * <pre>&lt;escapeunicode&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader
+        classname=&quot;org.apache.tools.ant.filters.EscapeUnicode&quot;/&gt;
+ *  </pre>
+ *
+ * @since Ant 1.6
+ */
+public class EscapeUnicode
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    //this field will hold unnnn right after reading a non latin character
+    //afterwards it will be truncated of one char every call to read
+    private StringBuffer unicodeBuf;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public EscapeUnicode() {
+        super();
+        unicodeBuf = new StringBuffer();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public EscapeUnicode(final Reader in) {
+        super(in);
+        unicodeBuf = new StringBuffer();
+    }
+
+    /**
+     * Returns the next character in the filtered stream, converting non latin
+     * characters to unicode escapes.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws
+     * an IOException during reading
+     */
+    public final int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+        if (unicodeBuf.length() == 0) {
+            ch = in.read();
+            if (ch != -1) {
+                char achar = (char) ch;
+                if (achar >= '\u0080') {
+                    unicodeBuf = new StringBuffer("u0000");
+                    String s = Integer.toHexString(ch);
+                    //replace the last 0s by the chars contained in s
+                    for (int i = 0; i < s.length(); i++) {
+                        unicodeBuf.setCharAt(unicodeBuf.length()
+                                             - s.length() + i,
+                                             s.charAt(i));
+                    }
+                    ch = '\\';
+                }
+            }
+        } else {
+            ch = (int) unicodeBuf.charAt(0);
+            unicodeBuf.deleteCharAt(0);
+        }
+        return ch;
+    }
+
+    /**
+     * Creates a new EscapeUnicode using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public final Reader chain(final Reader rdr) {
+        EscapeUnicode newFilter = new EscapeUnicode(rdr);
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Parses the parameters (currently unused)
+     */
+    private void initialize() {
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/filters/ExpandProperties.java b/trunk/src/main/org/apache/tools/ant/filters/ExpandProperties.java
new file mode 100644
index 0000000..a07ce5b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/ExpandProperties.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.Project;
+
+/**
+ * Expands Ant properties, if any, in the data.
+ * <p>
+ * Example:<br>
+ * <pre>&lt;expandproperties/&gt;</pre>
+ * Or:
+ * <pre>&lt;filterreader
+ *    classname=&quot;org.apache.tools.ant.filters.ExpandProperties&quot;/&gt;</pre>
+ *
+ */
+public final class ExpandProperties
+    extends BaseFilterReader
+    implements ChainableReader {
+    /** Data that must be read from, if not null. */
+    private String queuedData = null;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public ExpandProperties() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public ExpandProperties(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream. The original
+     * stream is first read in fully, and the Ant properties are expanded.
+     * The results of this expansion are then queued so they can be read
+     * character-by-character.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+
+        int ch = -1;
+
+        if (queuedData != null && queuedData.length() == 0) {
+            queuedData = null;
+        }
+
+        if (queuedData != null) {
+            ch = queuedData.charAt(0);
+            queuedData = queuedData.substring(1);
+            if (queuedData.length() == 0) {
+                queuedData = null;
+            }
+        } else {
+            queuedData = readFully();
+            if (queuedData == null || queuedData.length() == 0) {
+                ch = -1;
+            } else {
+                Project project = getProject();
+                queuedData = project.replaceProperties(queuedData);
+                return read();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Creates a new ExpandProperties filter using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        ExpandProperties newFilter = new ExpandProperties(rdr);
+        newFilter.setProject(getProject());
+        return newFilter;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/FixCrLfFilter.java b/trunk/src/main/org/apache/tools/ant/filters/FixCrLfFilter.java
new file mode 100755
index 0000000..1b88d5f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/FixCrLfFilter.java
@@ -0,0 +1,1008 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Converts text to local OS formatting conventions, as well as repair text
+ * damaged by misconfigured or misguided editors or file transfer programs.
+ * <p>
+ * This filter can take the following arguments:
+ * <ul>
+ * <li>eof
+ * <li>eol
+ * <li>fixlast
+ * <li>javafiles
+ * <li>tab
+ * <li>tablength
+ * </ul>
+ * None of which are required.
+ * <p>
+ * This version generalises the handling of EOL characters, and allows for
+ * CR-only line endings (the standard on Mac systems prior to OS X). Tab
+ * handling has also been generalised to accommodate any tabwidth from 2 to 80,
+ * inclusive. Importantly, it can leave untouched any literal TAB characters
+ * embedded within Java string or character constants.
+ * <p>
+ * <em>Caution:</em> run with care on carefully formatted files. This may
+ * sound obvious, but if you don't specify asis, presume that your files are
+ * going to be modified. If "tabs" is "add" or "remove", whitespace characters
+ * may be added or removed as necessary. Similarly, for EOLs, eol="asis"
+ * actually means convert to your native O/S EOL convention while eol="crlf" or
+ * cr="add" can result in CR characters being removed in one special case
+ * accommodated, i.e., CRCRLF is regarded as a single EOL to handle cases where
+ * other programs have converted CRLF into CRCRLF.
+ *
+ * <P>
+ * Example:
+ *
+ * <pre>
+ * &lt;&lt;fixcrlf tab=&quot;add&quot; eol=&quot;crlf&quot; eof=&quot;asis&quot;/&gt;
+ * </pre>
+ *
+ * Or:
+ *
+ * <pre>
+ * &lt;filterreader classname=&quot;org.apache.tools.ant.filters.FixCrLfFilter&quot;&gt;
+ *   &lt;param eol=&quot;crlf&quot; tab=&quot;asis&quot;/&gt;
+ *  &lt;/filterreader&gt;
+ * </pre>
+ *
+ */
+public final class FixCrLfFilter extends BaseParamFilterReader implements ChainableReader {
+    private static final int DEFAULT_TAB_LENGTH = 8;
+    private static final int MIN_TAB_LENGTH = 2;
+    private static final int MAX_TAB_LENGTH = 80;
+    private static final char CTRLZ = '\u001A';
+
+    private int tabLength = DEFAULT_TAB_LENGTH;
+
+    private CrLf eol;
+
+    private AddAsisRemove ctrlz;
+
+    private AddAsisRemove tabs;
+
+    private boolean javafiles = false;
+
+    private boolean fixlast = true;
+
+    private boolean initialized = false;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public FixCrLfFilter() {
+        super();
+    }
+
+    /**
+     * Create a new filtered reader.
+     *
+     * @param in
+     *            A Reader object providing the underlying stream. Must not be
+     *            <code>null</code>.
+     * @throws IOException on error.
+     */
+    public FixCrLfFilter(final Reader in) throws IOException {
+        super(in);
+    }
+
+    // Instance initializer: Executes just after the super() call in this
+    // class's constructor.
+    {
+        tabs = AddAsisRemove.ASIS;
+        if (Os.isFamily("mac") && !Os.isFamily("unix")) {
+            ctrlz = AddAsisRemove.REMOVE;
+            setEol(CrLf.MAC);
+        } else if (Os.isFamily("dos")) {
+            ctrlz = AddAsisRemove.ASIS;
+            setEol(CrLf.DOS);
+        } else {
+            ctrlz = AddAsisRemove.REMOVE;
+            setEol(CrLf.UNIX);
+        }
+    }
+
+    /**
+     * Create a new FixCrLfFilter using the passed in Reader for instantiation.
+     *
+     * @param rdr
+     *            A Reader object providing the underlying stream. Must not be
+     *            <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering the
+     *         specified reader.
+     */
+    public Reader chain(final Reader rdr) {
+        try {
+            FixCrLfFilter newFilter = new FixCrLfFilter(rdr);
+
+            newFilter.setJavafiles(getJavafiles());
+            newFilter.setEol(getEol());
+            newFilter.setTab(getTab());
+            newFilter.setTablength(getTablength());
+            newFilter.setEof(getEof());
+            newFilter.setFixlast(getFixlast());
+            newFilter.initInternalFilters();
+
+            return newFilter;
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Get how DOS EOF (control-z) characters are being handled.
+     *
+     * @return values:
+     *         <ul>
+     *         <li>add: ensure that there is an eof at the end of the file
+     *         <li>asis: leave eof characters alone
+     *         <li>remove: remove any eof character found at the end
+     *         </ul>
+     */
+    public AddAsisRemove getEof() {
+        // Return copy so that the call must call setEof() to change the state
+        // of fixCRLF
+        return ctrlz.newInstance();
+    }
+
+    /**
+     * Get how EndOfLine characters are being handled.
+     *
+     * @return values:
+     *         <ul>
+     *         <li>asis: convert line endings to your O/S convention
+     *         <li>cr: convert line endings to CR
+     *         <li>lf: convert line endings to LF
+     *         <li>crlf: convert line endings to CRLF
+     *         </ul>
+     */
+    public CrLf getEol() {
+        // Return copy so that the call must call setEol() to change the state
+        // of fixCRLF
+        return eol.newInstance();
+    }
+
+    /**
+     * Get whether a missing EOL be added to the final line of the stream.
+     *
+     * @return true if a filtered file will always end with an EOL
+     */
+    public boolean getFixlast() {
+        return fixlast;
+    }
+
+    /**
+     * Get whether the stream is to be treated as though it contains Java
+     * source.
+     * <P>
+     * This attribute is only used in assocation with the &quot;<i><b>tab</b></i>&quot;
+     * attribute. Tabs found in Java literals are protected from changes by this
+     * filter.
+     *
+     * @return true if whitespace in Java character and string literals is
+     *         ignored.
+     */
+    public boolean getJavafiles() {
+        return javafiles;
+    }
+
+    /**
+     * Return how tab characters are being handled.
+     *
+     * @return values:
+     *         <ul>
+     *         <li>add: convert sequences of spaces which span a tab stop to
+     *         tabs
+     *         <li>asis: leave tab and space characters alone
+     *         <li>remove: convert tabs to spaces
+     *         </ul>
+     */
+    public AddAsisRemove getTab() {
+        // Return copy so that the caller must call setTab() to change the state
+        // of fixCRLF.
+        return tabs.newInstance();
+    }
+
+    /**
+     * Get the tab length to use.
+     *
+     * @return the length of tab in spaces
+     */
+    public int getTablength() {
+        return tabLength;
+    }
+
+    private static String calculateEolString(CrLf eol) {
+        // Calculate the EOL string per the current config
+        if (eol == CrLf.ASIS) {
+            return System.getProperty("line.separator");
+        }
+        if (eol == CrLf.CR || eol == CrLf.MAC) {
+            return "\r";
+        }
+        if (eol == CrLf.CRLF || eol == CrLf.DOS) {
+            return "\r\n";
+        }
+        // assume (eol == CrLf.LF || eol == CrLf.UNIX)
+        return "\n";
+    }
+
+    /**
+     * Wrap the input stream with the internal filters necessary to perform the
+     * configuration settings.
+     */
+    private void initInternalFilters() {
+
+        // If I'm removing an EOF character, do so first so that the other
+        // filters don't see that character.
+        in = (ctrlz == AddAsisRemove.REMOVE) ? new RemoveEofFilter(in) : in;
+
+        // Change all EOL characters to match the calculated EOL string. If
+        // configured to do so, append a trailing EOL so that the file ends on
+        // a EOL.
+        in = new NormalizeEolFilter(in, calculateEolString(eol), getFixlast());
+
+        if (tabs != AddAsisRemove.ASIS) {
+            // If filtering Java source, prevent changes to whitespace in
+            // character and string literals.
+            if (getJavafiles()) {
+                in = new MaskJavaTabLiteralsFilter(in);
+            }
+            // Add/Remove tabs
+            in = (tabs == AddAsisRemove.ADD) ? (Reader) new AddTabFilter(in, getTablength())
+                    : (Reader) new RemoveTabFilter(in, getTablength());
+        }
+        // Add missing EOF character
+        in = (ctrlz == AddAsisRemove.ADD) ? new AddEofFilter(in) : in;
+        initialized = true;
+    }
+
+    /**
+     * Return the next character in the filtered stream.
+     *
+     * @return the next character in the resulting stream, or -1 if the end of
+     *         the resulting stream has been reached.
+     *
+     * @exception IOException
+     *                if the underlying stream throws an IOException during
+     *                reading.
+     */
+    public synchronized int read() throws IOException {
+        if (!initialized) {
+            initInternalFilters();
+        }
+        return in.read();
+    }
+
+    /**
+     * Specify how DOS EOF (control-z) characters are to be handled.
+     *
+     * @param attr
+     *            valid values:
+     *            <ul>
+     *            <li>add: ensure that there is an eof at the end of the file
+     *            <li>asis: leave eof characters alone
+     *            <li>remove: remove any eof character found at the end
+     *            </ul>
+     */
+    public void setEof(AddAsisRemove attr) {
+        ctrlz = attr.resolve();
+    }
+
+    /**
+     * Specify how end of line (EOL) characters are to be handled.
+     *
+     * @param attr
+     *            valid values:
+     *            <ul>
+     *            <li>asis: convert line endings to your O/S convention
+     *            <li>cr: convert line endings to CR
+     *            <li>lf: convert line endings to LF
+     *            <li>crlf: convert line endings to CRLF
+     *            </ul>
+     */
+    public void setEol(CrLf attr) {
+        eol = attr.resolve();
+    }
+
+    /**
+     * Specify whether a missing EOL will be added to the final line of input.
+     *
+     * @param fixlast
+     *            if true a missing EOL will be appended.
+     */
+    public void setFixlast(boolean fixlast) {
+        this.fixlast = fixlast;
+    }
+
+    /**
+     * Indicate whether this stream contains Java source.
+     *
+     * This attribute is only used in assocation with the &quot;<i><b>tab</b></i>&quot;
+     * attribute.
+     *
+     * @param javafiles
+     *            set to true to prevent this filter from changing tabs found in
+     *            Java literals.
+     */
+    public void setJavafiles(boolean javafiles) {
+        this.javafiles = javafiles;
+    }
+
+    /**
+     * Specify how tab characters are to be handled.
+     *
+     * @param attr
+     *            valid values:
+     *            <ul>
+     *            <li>add: convert sequences of spaces which span a tab stop to
+     *            tabs
+     *            <li>asis: leave tab and space characters alone
+     *            <li>remove: convert tabs to spaces
+     *            </ul>
+     */
+    public void setTab(AddAsisRemove attr) {
+        tabs = attr.resolve();
+    }
+
+    /**
+     * Specify tab length in characters.
+     *
+     * @param tabLength
+     *            specify the length of tab in spaces. Valid values are between
+     *            2 and 80 inclusive. The default for this parameter is 8.
+     * @throws IOException on error.
+     */
+    public void setTablength(int tabLength) throws IOException {
+        if (tabLength < MIN_TAB_LENGTH
+            || tabLength > MAX_TAB_LENGTH) {
+            throw new IOException(
+                "tablength must be between " + MIN_TAB_LENGTH
+                + " and " + MAX_TAB_LENGTH);
+        }
+        this.tabLength = tabLength;
+    }
+
+    /**
+     * This filter reader redirects all read I/O methods through its own read()
+     * method.
+     *
+     * <P>
+     * The input stream is already buffered by the copy task so this doesn't
+     * significantly impact performance while it makes writing the individual
+     * fix filters much easier.
+     * </P>
+     */
+    private static class SimpleFilterReader extends Reader {
+        private static final int PREEMPT_BUFFER_LENGTH = 16;
+        private Reader in;
+
+        private int[] preempt = new int[PREEMPT_BUFFER_LENGTH];
+
+        private int preemptIndex = 0;
+
+        public SimpleFilterReader(Reader in) {
+            this.in = in;
+        }
+
+        public void push(char c) {
+            push((int) c);
+        }
+
+        public void push(int c) {
+            try {
+                preempt[preemptIndex++] = c;
+            } catch (ArrayIndexOutOfBoundsException e) {
+                int[] p2 = new int[preempt.length * 2];
+                System.arraycopy(preempt, 0, p2, 0, preempt.length);
+                preempt = p2;
+                push(c);
+            }
+        }
+
+        public void push(char[] cs, int start, int length) {
+            for (int i = start + length - 1; i >= start;) {
+                push(cs[i--]);
+            }
+        }
+
+        public void push(char[] cs) {
+            push(cs, 0, cs.length);
+        }
+
+        public void push(String s) {
+            push(s.toCharArray());
+        }
+
+        /**
+         * Does this filter want to block edits on the last character returned
+         * by read()?
+         */
+        public boolean editsBlocked() {
+            return in instanceof SimpleFilterReader && ((SimpleFilterReader) in).editsBlocked();
+        }
+
+        public int read() throws java.io.IOException {
+            return preemptIndex > 0 ? preempt[--preemptIndex] : in.read();
+        }
+
+        public void close() throws java.io.IOException {
+            in.close();
+        }
+
+        public void reset() throws IOException {
+            in.reset();
+        }
+
+        public boolean markSupported() {
+            return in.markSupported();
+        }
+
+        public boolean ready() throws java.io.IOException {
+            return in.ready();
+        }
+
+        public void mark(int i) throws java.io.IOException {
+            in.mark(i);
+        }
+
+        public long skip(long i) throws java.io.IOException {
+            return in.skip(i);
+        }
+
+        public int read(char[] buf) throws java.io.IOException {
+            return read(buf, 0, buf.length);
+        }
+
+        public int read(char[] buf, int start, int length) throws java.io.IOException {
+            int count = 0;
+            int c = 0;
+
+            // CheckStyle:InnerAssignment OFF - leave alone
+            while (length-- > 0 && (c = this.read()) != -1) {
+                buf[start++] = (char) c;
+                count++;
+            }
+            // if at EOF with no characters in the buffer, return EOF
+            return (count == 0 && c == -1) ? -1 : count;
+        }
+    }
+
+    private static class MaskJavaTabLiteralsFilter extends SimpleFilterReader {
+        private boolean editsBlocked = false;
+
+        private static final int JAVA = 1;
+
+        private static final int IN_CHAR_CONST = 2;
+
+        private static final int IN_STR_CONST = 3;
+
+        private static final int IN_SINGLE_COMMENT = 4;
+
+        private static final int IN_MULTI_COMMENT = 5;
+
+        private static final int TRANS_TO_COMMENT = 6;
+
+        private static final int TRANS_FROM_MULTI = 8;
+
+        private int state;
+
+        public MaskJavaTabLiteralsFilter(Reader in) {
+            super(in);
+            state = JAVA;
+        }
+
+        public boolean editsBlocked() {
+            return editsBlocked || super.editsBlocked();
+        }
+
+        public int read() throws IOException {
+            int thisChar = super.read();
+            // Mask, block from being edited, all characters in constants.
+            editsBlocked = (state == IN_CHAR_CONST || state == IN_STR_CONST);
+
+            switch (state) {
+            case JAVA:
+                // The current character is always emitted.
+                switch (thisChar) {
+                case '\'':
+                    state = IN_CHAR_CONST;
+                    break;
+                case '"':
+                    state = IN_STR_CONST;
+                    break;
+                case '/':
+                    state = TRANS_TO_COMMENT;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            case IN_CHAR_CONST:
+                switch (thisChar) {
+                case '\'':
+                    state = JAVA;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            case IN_STR_CONST:
+                switch (thisChar) {
+                case '"':
+                    state = JAVA;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            case IN_SINGLE_COMMENT:
+                // The current character is always emitted.
+                switch (thisChar) {
+                case '\n':
+                case '\r': // EOL
+                    state = JAVA;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            case IN_MULTI_COMMENT:
+                // The current character is always emitted.
+                switch (thisChar) {
+                case '*':
+                    state = TRANS_FROM_MULTI;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            case TRANS_TO_COMMENT:
+                // The current character is always emitted.
+                switch (thisChar) {
+                case '*':
+                    state = IN_MULTI_COMMENT;
+                    break;
+                case '/':
+                    state = IN_SINGLE_COMMENT;
+                    break;
+                case '\'':
+                    state = IN_CHAR_CONST;
+                    break;
+                case '"':
+                    state = IN_STR_CONST;
+                    break;
+                default:
+                    state = JAVA;
+                }
+                break;
+            case TRANS_FROM_MULTI:
+                // The current character is always emitted.
+                switch (thisChar) {
+                case '/':
+                    state = JAVA;
+                    break;
+                default:
+                    // Fall tru
+                }
+                break;
+            default:
+                // Fall tru
+            }
+            return thisChar;
+        }
+    }
+
+    private static class NormalizeEolFilter extends SimpleFilterReader {
+        private boolean previousWasEOL;
+
+        private boolean fixLast;
+
+        private int normalizedEOL = 0;
+
+        private char[] eol = null;
+
+        public NormalizeEolFilter(Reader in, String eolString, boolean fixLast) {
+            super(in);
+            eol = eolString.toCharArray();
+            this.fixLast = fixLast;
+        }
+
+        public int read() throws IOException {
+            int thisChar = super.read();
+
+            if (normalizedEOL == 0) {
+                int numEOL = 0;
+                boolean atEnd = false;
+                switch (thisChar) {
+                case CTRLZ:
+                    int c = super.read();
+                    if (c == -1) {
+                        atEnd = true;
+                        if (fixLast && !previousWasEOL) {
+                            numEOL = 1;
+                            push(thisChar);
+                        }
+                    } else {
+                        push(c);
+                    }
+                    break;
+                case -1:
+                    atEnd = true;
+                    if (fixLast && !previousWasEOL) {
+                        numEOL = 1;
+                    }
+                    break;
+                case '\n':
+                    // EOL was "\n"
+                    numEOL = 1;
+                    break;
+                case '\r':
+                    numEOL = 1;
+                    int c1 = super.read();
+                    int c2 = super.read();
+
+                    if (c1 == '\r' && c2 == '\n') {
+                        // EOL was "\r\r\n"
+                    } else if (c1 == '\r') {
+                        // EOL was "\r\r" - handle as two consecutive "\r" and
+                        // "\r"
+                        numEOL = 2;
+                        push(c2);
+                    } else if (c1 == '\n') {
+                        // EOL was "\r\n"
+                        push(c2);
+                    } else {
+                        // EOL was "\r"
+                        push(c2);
+                        push(c1);
+                    }
+                default:
+                    // Fall tru
+                }
+                if (numEOL > 0) {
+                    while (numEOL-- > 0) {
+                        push(eol);
+                        normalizedEOL += eol.length;
+                    }
+                    previousWasEOL = true;
+                    thisChar = read();
+                } else if (!atEnd) {
+                    previousWasEOL = false;
+                }
+            } else {
+                normalizedEOL--;
+            }
+            return thisChar;
+        }
+    }
+
+    private static class AddEofFilter extends SimpleFilterReader {
+        private int lastChar = -1;
+
+        public AddEofFilter(Reader in) {
+            super(in);
+        }
+
+        public int read() throws IOException {
+            int thisChar = super.read();
+
+            // if source is EOF but last character was NOT ctrl-z, return ctrl-z
+            if (thisChar == -1) {
+                if (lastChar != CTRLZ) {
+                    lastChar = CTRLZ;
+                    return lastChar;
+                }
+            } else {
+                lastChar = thisChar;
+            }
+            return thisChar;
+        }
+    }
+
+    private static class RemoveEofFilter extends SimpleFilterReader {
+        private int lookAhead = -1;
+
+        public RemoveEofFilter(Reader in) {
+            super(in);
+
+            try {
+                lookAhead = in.read();
+            } catch (IOException e) {
+                lookAhead = -1;
+            }
+        }
+
+        public int read() throws IOException {
+            int lookAhead2 = super.read();
+
+            // If source at EOF and lookAhead is ctrl-z, return EOF (NOT ctrl-z)
+            if (lookAhead2 == -1 && lookAhead == CTRLZ) {
+                return -1;
+            }
+            // Return current look-ahead
+            int i = lookAhead;
+            lookAhead = lookAhead2;
+            return i;
+        }
+    }
+
+    private static class AddTabFilter extends SimpleFilterReader {
+        private int columnNumber = 0;
+
+        private int tabLength = 0;
+
+        public AddTabFilter(Reader in, int tabLength) {
+            super(in);
+            this.tabLength = tabLength;
+        }
+
+        public int read() throws IOException {
+            int c = super.read();
+
+            switch (c) {
+            case '\r':
+            case '\n':
+                columnNumber = 0;
+                break;
+            case ' ':
+                columnNumber++;
+                if (!editsBlocked()) {
+                    int colNextTab = ((columnNumber + tabLength - 1) / tabLength) * tabLength;
+                    int countSpaces = 1;
+                    int numTabs = 0;
+
+                    scanWhitespace: while ((c = super.read()) != -1) {
+                        switch (c) {
+                        case ' ':
+                            if (++columnNumber == colNextTab) {
+                                numTabs++;
+                                countSpaces = 0;
+                                colNextTab += tabLength;
+                            } else {
+                                countSpaces++;
+                            }
+                            break;
+                        case '\t':
+                            columnNumber = colNextTab;
+                            numTabs++;
+                            countSpaces = 0;
+                            colNextTab += tabLength;
+                            break;
+                        default:
+                            push(c);
+                            break scanWhitespace;
+                        }
+                    }
+                    while (countSpaces-- > 0) {
+                        push(' ');
+                        columnNumber--;
+                    }
+                    while (numTabs-- > 0) {
+                        push('\t');
+                        columnNumber -= tabLength;
+                    }
+                    c = super.read();
+                    switch (c) {
+                    case ' ':
+                        columnNumber++;
+                        break;
+                    case '\t':
+                        columnNumber += tabLength;
+                        break;
+                    default:
+                        // Fall tru
+                    }
+                }
+                break;
+            case '\t':
+                columnNumber = ((columnNumber + tabLength - 1) / tabLength) * tabLength;
+                break;
+            default:
+                columnNumber++;
+            }
+            return c;
+        }
+    }
+
+    private static class RemoveTabFilter extends SimpleFilterReader {
+        private int columnNumber = 0;
+
+        private int tabLength = 0;
+
+        public RemoveTabFilter(Reader in, int tabLength) {
+            super(in);
+
+            this.tabLength = tabLength;
+        }
+
+        public int read() throws IOException {
+            int c = super.read();
+
+            switch (c) {
+            case '\r':
+            case '\n':
+                columnNumber = 0;
+                break;
+            case '\t':
+                int width = tabLength - columnNumber % tabLength;
+
+                if (!editsBlocked()) {
+                    for (; width > 1; width--) {
+                        push(' ');
+                    }
+                    c = ' ';
+                }
+                columnNumber += width;
+                break;
+            default:
+                columnNumber++;
+            }
+            return c;
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values "asis", "add" and "remove".
+     */
+    public static class AddAsisRemove extends EnumeratedAttribute {
+        private static final AddAsisRemove ASIS = newInstance("asis");
+
+        private static final AddAsisRemove ADD = newInstance("add");
+
+        private static final AddAsisRemove REMOVE = newInstance("remove");
+
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"add", "asis", "remove"};
+        }
+
+        /**
+         * Equality depending in the index.
+         * @param other the object to test equality against.
+         * @return true if the object has the same index as this.
+         */
+        public boolean equals(Object other) {
+            return other instanceof AddAsisRemove
+                    && getIndex() == ((AddAsisRemove) other).getIndex();
+        }
+
+        /**
+         * Hashcode depending on the index.
+         * @return the index as the hashcode.
+         */
+        public int hashCode() {
+            return getIndex();
+        }
+
+        AddAsisRemove resolve() throws IllegalStateException {
+            if (this.equals(ASIS)) {
+                return ASIS;
+            }
+            if (this.equals(ADD)) {
+                return ADD;
+            }
+            if (this.equals(REMOVE)) {
+                return REMOVE;
+            }
+            throw new IllegalStateException("No replacement for " + this);
+        }
+
+        // Works like clone() but doesn't show up in the Javadocs
+        private AddAsisRemove newInstance() {
+            return newInstance(getValue());
+        }
+
+        /**
+         * Create an instance of this enumerated value based on the string value.
+         * @param value the value to use.
+         * @return an enumerated instance.
+         */
+        public static AddAsisRemove newInstance(String value) {
+            AddAsisRemove a = new AddAsisRemove();
+            a.setValue(value);
+            return a;
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values "asis", "cr", "lf" and "crlf".
+     */
+    public static class CrLf extends EnumeratedAttribute {
+        private static final CrLf ASIS = newInstance("asis");
+
+        private static final CrLf CR = newInstance("cr");
+
+        private static final CrLf CRLF = newInstance("crlf");
+
+        private static final CrLf DOS = newInstance("dos");
+
+        private static final CrLf LF = newInstance("lf");
+
+        private static final CrLf MAC = newInstance("mac");
+
+        private static final CrLf UNIX = newInstance("unix");
+
+        /**
+         * @see EnumeratedAttribute#getValues
+         */
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"asis", "cr", "lf", "crlf", "mac", "unix", "dos"};
+        }
+
+        /**
+         * Equality depending in the index.
+         * @param other the object to test equality against.
+         * @return true if the object has the same index as this.
+         */
+        public boolean equals(Object other) {
+            return other instanceof CrLf && getIndex() == ((CrLf) other).getIndex();
+        }
+
+        /**
+         * Hashcode depending on the index.
+         * @return the index as the hashcode.
+         */
+        public int hashCode() {
+            return getIndex();
+        }
+
+        CrLf resolve() {
+            if (this.equals(ASIS)) {
+                return ASIS;
+            }
+            if (this.equals(CR) || this.equals(MAC)) {
+                return CR;
+            }
+            if (this.equals(CRLF) || this.equals(DOS)) {
+                return CRLF;
+            }
+            if (this.equals(LF) || this.equals(UNIX)) {
+                return LF;
+            }
+            throw new IllegalStateException("No replacement for " + this);
+        }
+
+        // Works like clone() but doesn't show up in the Javadocs
+        private CrLf newInstance() {
+            return newInstance(getValue());
+        }
+
+        /**
+         * Create an instance of this enumerated value based on the string value.
+         * @param value the value to use.
+         * @return an enumerated instance.
+         */
+        public static CrLf newInstance(String value) {
+            CrLf c = new CrLf();
+            c.setValue(value);
+            return c;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/HeadFilter.java b/trunk/src/main/org/apache/tools/ant/filters/HeadFilter.java
new file mode 100644
index 0000000..41eee03
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/HeadFilter.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.util.LineTokenizer;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Reads the first <code>n</code> lines of a stream.
+ * (Default is first 10 lines.)
+ * <p>
+ * Example:
+ * <pre>&lt;headfilter lines=&quot;3&quot;/&gt;</pre>
+ * Or:
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.HeadFilter&quot;&gt;
+ *    &lt;param name=&quot;lines&quot; value=&quot;3&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class HeadFilter extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the number of lines to be returned. */
+    private static final String LINES_KEY = "lines";
+
+    /** Parameter name for the number of lines to be skipped. */
+    private static final String SKIP_KEY = "skip";
+
+    /** Number of lines currently read in. */
+    private long linesRead = 0;
+
+    /** Default number of lines to show */
+    private static final int DEFAULT_NUM_LINES = 10;
+
+    /** Number of lines to be returned in the filtered stream. */
+    private long lines = DEFAULT_NUM_LINES;
+
+    /** Number of lines to be skipped. */
+    private long skip = 0;
+
+    /** A line tokenizer */
+    private LineTokenizer lineTokenizer = null;
+
+    /** the current line from the input stream */
+    private String    line      = null;
+    /** the position in the current line */
+    private int       linePos   = 0;
+
+    /** Whether this filter is finished */
+    private boolean eof;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public HeadFilter() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public HeadFilter(final Reader in) {
+        super(in);
+        lineTokenizer = new LineTokenizer();
+        lineTokenizer.setIncludeDelims(true);
+    }
+
+    /**
+     * Returns the next character in the filtered stream. If the desired
+     * number of lines have already been read, the resulting stream is
+     * effectively at an end. Otherwise, the next character from the
+     * underlying stream is read and returned.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        while (line == null || line.length() == 0) {
+            line = lineTokenizer.getToken(in);
+            if (line == null) {
+                return -1;
+            }
+            line = headFilter(line);
+            if (eof) {
+                return -1;
+            }
+            linePos = 0;
+        }
+
+        int ch = line.charAt(linePos);
+        linePos++;
+        if (linePos == line.length()) {
+            line = null;
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the number of lines to be returned in the filtered stream.
+     *
+     * @param lines the number of lines to be returned in the filtered stream
+     */
+    public void setLines(final long lines) {
+        this.lines = lines;
+    }
+
+    /**
+     * Returns the number of lines to be returned in the filtered stream.
+     *
+     * @return the number of lines to be returned in the filtered stream
+     */
+    private long getLines() {
+        return lines;
+    }
+
+    /**
+     * Sets the number of lines to be skipped in the filtered stream.
+     *
+     * @param skip the number of lines to be skipped in the filtered stream
+     */
+    public void setSkip(final long skip) {
+        this.skip = skip;
+    }
+
+    /**
+     * Returns the number of lines to be skipped in the filtered stream.
+     *
+     * @return the number of lines to be skipped in the filtered stream
+     */
+    private long getSkip() {
+        return skip;
+    }
+
+    /**
+     * Creates a new HeadFilter using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        HeadFilter newFilter = new HeadFilter(rdr);
+        newFilter.setLines(getLines());
+        newFilter.setSkip(getSkip());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Scans the parameters list for the "lines" parameter and uses
+     * it to set the number of lines to be returned in the filtered stream.
+     * also scan for skip parameter.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (LINES_KEY.equals(params[i].getName())) {
+                    lines = Long.parseLong(params[i].getValue());
+                    continue;
+                }
+                if (SKIP_KEY.equals(params[i].getName())) {
+                    skip = Long.parseLong(params[i].getValue());
+                    continue;
+                }
+            }
+        }
+    }
+
+    /**
+     * implements a head filter on the input stream
+     */
+    private String headFilter(String line) {
+        linesRead++;
+        if (skip > 0) {
+            if ((linesRead - 1) < skip) {
+                return null;
+            }
+        }
+
+        if (lines > 0) {
+            if (linesRead > (lines + skip)) {
+                eof = true;
+                return null;
+            }
+        }
+        return line;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/LineContains.java b/trunk/src/main/org/apache/tools/ant/filters/LineContains.java
new file mode 100644
index 0000000..fdfc03d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/LineContains.java
@@ -0,0 +1,243 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Filter which includes only those lines that contain all the user-specified
+ * strings.
+ *
+ * Example:
+ *
+ * <pre>&lt;linecontains&gt;
+ *   &lt;contains value=&quot;foo&quot;&gt;
+ *   &lt;contains value=&quot;bar&quot;&gt;
+ * &lt;/linecontains&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContains&quot;&gt;
+ *    &lt;param type=&quot;contains&quot; value=&quot;foo&quot;/&gt;
+ *    &lt;param type=&quot;contains&quot; value=&quot;bar&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ * This will include only those lines that contain <code>foo</code> and
+ * <code>bar</code>.
+ *
+ */
+public final class LineContains
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the words to filter on. */
+    private static final String CONTAINS_KEY = "contains";
+
+    /** Parameter name for the words to filter on. */
+    private static final String NEGATE_KEY = "negate";
+
+    /** Vector that holds the strings that input lines must contain. */
+    private Vector contains = new Vector();
+
+    /**
+     * Remaining line to be read from this filter, or <code>null</code> if
+     * the next call to <code>read()</code> should read the original stream
+     * to find the next matching line.
+     */
+    private String line = null;
+
+    private boolean negate = false;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public LineContains() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public LineContains(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, only including
+     * lines from the original stream which contain all of the specified words.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        if (line != null) {
+            ch = line.charAt(0);
+            if (line.length() == 1) {
+                line = null;
+            } else {
+                line = line.substring(1);
+            }
+        } else {
+            final int containsSize = contains.size();
+
+            for (line = readLine(); line != null; line = readLine()) {
+                boolean matches = true;
+                for (int i = 0; matches && i < containsSize; i++) {
+                    String containsStr = (String) contains.elementAt(i);
+                    matches = line.indexOf(containsStr) >= 0;
+                }
+                if (matches ^ isNegated()) {
+                    break;
+                }
+            }
+            if (line != null) {
+                return read();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Adds a <code>contains</code> element.
+     *
+     * @param contains The <code>contains</code> element to add.
+     *                 Must not be <code>null</code>.
+     */
+    public void addConfiguredContains(final Contains contains) {
+        this.contains.addElement(contains.getValue());
+    }
+
+    /**
+     * Set the negation mode.  Default false (no negation).
+     * @param b the boolean negation mode to set.
+     */
+    public void setNegate(boolean b) {
+        negate = b;
+    }
+
+    /**
+     * Find out whether we have been negated.
+     * @return boolean negation flag.
+     */
+    public boolean isNegated() {
+        return negate;
+    }
+
+    /**
+     * Sets the vector of words which must be contained within a line read
+     * from the original stream in order for it to match this filter.
+     *
+     * @param contains A vector of words which must be contained within a line
+     * in order for it to match in this filter. Must not be <code>null</code>.
+     */
+    private void setContains(final Vector contains) {
+        this.contains = contains;
+    }
+
+    /**
+     * Returns the vector of words which must be contained within a line read
+     * from the original stream in order for it to match this filter.
+     *
+     * @return the vector of words which must be contained within a line read
+     * from the original stream in order for it to match this filter. The
+     * returned object is "live" - in other words, changes made to the
+     * returned object are mirrored in the filter.
+     */
+    private Vector getContains() {
+        return contains;
+    }
+
+    /**
+     * Creates a new LineContains using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        LineContains newFilter = new LineContains(rdr);
+        newFilter.setContains(getContains());
+        newFilter.setNegate(isNegated());
+        return newFilter;
+    }
+
+    /**
+     * Parses the parameters to add user-defined contains strings.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (CONTAINS_KEY.equals(params[i].getType())) {
+                    contains.addElement(params[i].getValue());
+                } else if (NEGATE_KEY.equals(params[i].getType())) {
+                    setNegate(Project.toBoolean(params[i].getValue()));
+                }
+            }
+        }
+    }
+
+    /**
+     * Holds a contains element
+     */
+    public static class Contains {
+
+        /** User defined contains string */
+        private String value;
+
+        /**
+         * Sets the contains string
+         *
+         * @param contains The contains string to set.
+         *                 Must not be <code>null</code>.
+         */
+        public final void setValue(String contains) {
+            value = contains;
+        }
+
+        /**
+         * Returns the contains string.
+         *
+         * @return the contains string for this element
+         */
+        public final String getValue() {
+            return value;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/LineContainsRegExp.java b/trunk/src/main/org/apache/tools/ant/filters/LineContainsRegExp.java
new file mode 100644
index 0000000..49ef34d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/LineContainsRegExp.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.util.regexp.Regexp;
+
+/**
+ * Filter which includes only those lines that contain the user-specified
+ * regular expression matching strings.
+ *
+ * Example:
+ * <pre>&lt;linecontainsregexp&gt;
+ *   &lt;regexp pattern=&quot;foo*&quot;&gt;
+ * &lt;/linecontainsregexp&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.LineContainsRegExp&quot;&gt;
+ *    &lt;param type=&quot;regexp&quot; value=&quot;foo*&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ * This will fetch all those lines that contain the pattern <code>foo</code>
+ *
+ */
+public final class LineContainsRegExp
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the regular expression to filter on. */
+    private static final String REGEXP_KEY = "regexp";
+
+    /** Parameter name for the words to filter on. */
+    private static final String NEGATE_KEY = "negate";
+
+    /** Vector that holds the expressions that input lines must contain. */
+    private Vector regexps = new Vector();
+
+    /**
+     * Remaining line to be read from this filter, or <code>null</code> if
+     * the next call to <code>read()</code> should read the original stream
+     * to find the next matching line.
+     */
+    private String line = null;
+
+    private boolean negate = false;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public LineContainsRegExp() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public LineContainsRegExp(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, only including
+     * lines from the original stream which match all of the specified
+     * regular expressions.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        if (line != null) {
+            ch = line.charAt(0);
+            if (line.length() == 1) {
+                line = null;
+            } else {
+                line = line.substring(1);
+            }
+        } else {
+            final int regexpsSize = regexps.size();
+
+            for (line = readLine(); line != null; line = readLine()) {
+                boolean matches = true;
+                for (int i = 0; matches && i < regexpsSize; i++) {
+                    RegularExpression regexp
+                        = (RegularExpression) regexps.elementAt(i);
+                    Regexp re = regexp.getRegexp(getProject());
+                    matches = re.matches(line);
+                }
+                if (matches ^ isNegated()) {
+                    break;
+                }
+            }
+            if (line != null) {
+                return read();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Adds a <code>regexp</code> element.
+     *
+     * @param regExp The <code>regexp</code> element to add.
+     *               Must not be <code>null</code>.
+     */
+    public void addConfiguredRegexp(final RegularExpression regExp) {
+        this.regexps.addElement(regExp);
+    }
+
+    /**
+     * Sets the vector of regular expressions which must be contained within
+     * a line read from the original stream in order for it to match this
+     * filter.
+     *
+     * @param regexps A vector of regular expressions which must be contained
+     * within a line in order for it to match in this filter. Must not be
+     * <code>null</code>.
+     */
+    private void setRegexps(final Vector regexps) {
+        this.regexps = regexps;
+    }
+
+    /**
+     * Returns the vector of regular expressions which must be contained within
+     * a line read from the original stream in order for it to match this
+     * filter.
+     *
+     * @return the vector of regular expressions which must be contained within
+     * a line read from the original stream in order for it to match this
+     * filter. The returned object is "live" - in other words, changes made to
+     * the returned object are mirrored in the filter.
+     */
+    private Vector getRegexps() {
+        return regexps;
+    }
+
+    /**
+     * Creates a new LineContainsRegExp using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        LineContainsRegExp newFilter = new LineContainsRegExp(rdr);
+        newFilter.setRegexps(getRegexps());
+        newFilter.setNegate(isNegated());
+        return newFilter;
+    }
+
+    /**
+     * Set the negation mode.  Default false (no negation).
+     * @param b the boolean negation mode to set.
+     */
+    public void setNegate(boolean b) {
+        negate = b;
+    }
+
+    /**
+     * Find out whether we have been negated.
+     * @return boolean negation flag.
+     */
+    public boolean isNegated() {
+        return negate;
+    }
+
+    /**
+     * Parses parameters to add user defined regular expressions.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (REGEXP_KEY.equals(params[i].getType())) {
+                    String pattern = params[i].getValue();
+                    RegularExpression regexp = new RegularExpression();
+                    regexp.setPattern(pattern);
+                    regexps.addElement(regexp);
+                } else if (NEGATE_KEY.equals(params[i].getType())) {
+                    setNegate(Project.toBoolean(params[i].getValue()));
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/PrefixLines.java b/trunk/src/main/org/apache/tools/ant/filters/PrefixLines.java
new file mode 100644
index 0000000..babb824
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/PrefixLines.java
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Attaches a prefix to every line.
+ *
+ * Example:
+ * <pre>&lt;prefixlines prefix=&quot;Foo&quot;/&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.PrefixLines&quot;&gt;
+ *  &lt;param name=&quot;prefix&quot; value=&quot;Foo&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class PrefixLines
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the prefix. */
+    private static final String PREFIX_KEY = "prefix";
+
+    /** The prefix to be used. */
+    private String prefix = null;
+
+    /** Data that must be read from, if not null. */
+    private String queuedData = null;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public PrefixLines() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public PrefixLines(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream. One line is read
+     * from the original input, and the prefix added. The resulting
+     * line is then used until it ends, at which point the next original line
+     * is read, etc.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        if (queuedData != null && queuedData.length() == 0) {
+            queuedData = null;
+        }
+
+        if (queuedData != null) {
+            ch = queuedData.charAt(0);
+            queuedData = queuedData.substring(1);
+            if (queuedData.length() == 0) {
+                queuedData = null;
+            }
+        } else {
+            queuedData = readLine();
+            if (queuedData == null) {
+                ch = -1;
+            } else {
+                if (prefix != null) {
+                    queuedData = prefix + queuedData;
+                }
+                return read();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the prefix to add at the start of each input line.
+     *
+     * @param prefix The prefix to add at the start of each input line.
+     *               May be <code>null</code>, in which case no prefix
+     *               is added.
+     */
+    public void setPrefix(final String prefix) {
+        this.prefix = prefix;
+    }
+
+    /**
+     * Returns the prefix which will be added at the start of each input line.
+     *
+     * @return the prefix which will be added at the start of each input line
+     */
+    private String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * Creates a new PrefixLines filter using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        PrefixLines newFilter = new PrefixLines(rdr);
+        newFilter.setPrefix(getPrefix());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Initializes the prefix if it is available from the parameters.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (PREFIX_KEY.equals(params[i].getName())) {
+                    prefix = params[i].getValue();
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/ReplaceTokens.java b/trunk/src/main/org/apache/tools/ant/filters/ReplaceTokens.java
new file mode 100644
index 0000000..dcffe11
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/ReplaceTokens.java
@@ -0,0 +1,374 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Replaces tokens in the original input with user-supplied values.
+ *
+ * Example:
+ *
+ * <pre>&lt;replacetokens begintoken=&quot;#&quot; endtoken=&quot;#&quot;&gt;
+ *   &lt;token key=&quot;DATE&quot; value=&quot;${TODAY}&quot;/&gt;
+ * &lt;/replacetokens&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname="org.apache.tools.ant.filters.ReplaceTokens"&gt;
+ *   &lt;param type="tokenchar" name="begintoken" value="#"/&gt;
+ *   &lt;param type="tokenchar" name="endtoken" value="#"/&gt;
+ *   &lt;param type="token" name="DATE" value="${TODAY}"/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class ReplaceTokens
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Default "begin token" character. */
+    private static final char DEFAULT_BEGIN_TOKEN = '@';
+
+    /** Default "end token" character. */
+    private static final char DEFAULT_END_TOKEN = '@';
+
+    /** Data to be used before reading from stream again */
+    private String queuedData = null;
+
+    /** replacement test from a token */
+    private String replaceData = null;
+
+    /** Index into replacement data */
+    private int replaceIndex = -1;
+
+    /** Index into queue data */
+    private int queueIndex = -1;
+
+    /** Hashtable to hold the replacee-replacer pairs (String to String). */
+    private Hashtable hash = new Hashtable();
+
+    /** Character marking the beginning of a token. */
+    private char beginToken = DEFAULT_BEGIN_TOKEN;
+
+    /** Character marking the end of a token. */
+    private char endToken = DEFAULT_END_TOKEN;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public ReplaceTokens() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public ReplaceTokens(final Reader in) {
+        super(in);
+    }
+
+    private int getNextChar() throws IOException {
+        if (queueIndex != -1) {
+            final int ch = queuedData.charAt(queueIndex++);
+            if (queueIndex >= queuedData.length()) {
+                queueIndex = -1;
+            }
+            return ch;
+        }
+
+        return in.read();
+    }
+
+    /**
+     * Returns the next character in the filtered stream, replacing tokens
+     * from the original stream.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        if (replaceIndex != -1) {
+            final int ch = replaceData.charAt(replaceIndex++);
+            if (replaceIndex >= replaceData.length()) {
+                replaceIndex = -1;
+            }
+            return ch;
+        }
+
+        int ch = getNextChar();
+
+        if (ch == beginToken) {
+            final StringBuffer key = new StringBuffer("");
+            do  {
+                ch = getNextChar();
+                if (ch != -1) {
+                    key.append((char) ch);
+                } else {
+                    break;
+                }
+            } while (ch != endToken);
+
+            if (ch == -1) {
+                if (queuedData == null || queueIndex == -1) {
+                    queuedData = key.toString();
+                } else {
+                    queuedData
+                        = key.toString() + queuedData.substring(queueIndex);
+                }
+                queueIndex = 0;
+                return beginToken;
+            } else {
+                key.setLength(key.length() - 1);
+
+                final String replaceWith = (String) hash.get(key.toString());
+                if (replaceWith != null) {
+                    if (replaceWith.length() > 0) {
+                        replaceData = replaceWith;
+                        replaceIndex = 0;
+                    }
+                    return read();
+                } else {
+                    String newData = key.toString() + endToken;
+                    if (queuedData == null || queueIndex == -1) {
+                        queuedData = newData;
+                    } else {
+                        queuedData = newData + queuedData.substring(queueIndex);
+                    }
+                    queueIndex = 0;
+                    return beginToken;
+                }
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the "begin token" character.
+     *
+     * @param beginToken the character used to denote the beginning of a token
+     */
+    public void setBeginToken(final char beginToken) {
+        this.beginToken = beginToken;
+    }
+
+    /**
+     * Returns the "begin token" character.
+     *
+     * @return the character used to denote the beginning of a token
+     */
+    private char getBeginToken() {
+        return beginToken;
+    }
+
+    /**
+     * Sets the "end token" character.
+     *
+     * @param endToken the character used to denote the end of a token
+     */
+    public void setEndToken(final char endToken) {
+        this.endToken = endToken;
+    }
+
+    /**
+     * Returns the "end token" character.
+     *
+     * @return the character used to denote the end of a token
+     */
+    private char getEndToken() {
+        return endToken;
+    }
+
+    /**
+     * Adds a token element to the map of tokens to replace.
+     *
+     * @param token The token to add to the map of replacements.
+     *              Must not be <code>null</code>.
+     */
+    public void addConfiguredToken(final Token token) {
+        hash.put(token.getKey(), token.getValue());
+    }
+
+    /**
+     * Returns properties from a specified properties file.
+     *
+     * @param fileName The file to load properties from.
+     */
+    private Properties getPropertiesFromFile (String fileName) {
+        FileInputStream in = null;
+        Properties props = new Properties();
+        try {
+            in = new FileInputStream(fileName);
+            props.load(in);
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } finally {
+            FileUtils.close(in);
+        }
+
+        return props;
+    }
+
+    /**
+     * Sets the map of tokens to replace.
+     *
+     * @param hash A map (String->String) of token keys to replacement
+     * values. Must not be <code>null</code>.
+     */
+    private void setTokens(final Hashtable hash) {
+        this.hash = hash;
+    }
+
+    /**
+     * Returns the map of tokens which will be replaced.
+     *
+     * @return a map (String->String) of token keys to replacement
+     * values
+     */
+    private Hashtable getTokens() {
+        return hash;
+    }
+
+    /**
+     * Creates a new ReplaceTokens using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        ReplaceTokens newFilter = new ReplaceTokens(rdr);
+        newFilter.setBeginToken(getBeginToken());
+        newFilter.setEndToken(getEndToken());
+        newFilter.setTokens(getTokens());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Initializes tokens and loads the replacee-replacer hashtable.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (params[i] != null) {
+                    final String type = params[i].getType();
+                    if ("tokenchar".equals(type)) {
+                        final String name = params[i].getName();
+                        String value = params[i].getValue();
+                        if ("begintoken".equals(name)) {
+                            if (value.length() == 0) {
+                                throw new BuildException("Begin token cannot "
+                                    + "be empty");
+                            }
+                            beginToken = params[i].getValue().charAt(0);
+                        } else if ("endtoken".equals(name)) {
+                            if (value.length() == 0) {
+                                throw new BuildException("End token cannot "
+                                    + "be empty");
+                            }
+                            endToken = params[i].getValue().charAt(0);
+                        }
+                    } else if ("token".equals(type)) {
+                        final String name = params[i].getName();
+                        final String value = params[i].getValue();
+                        hash.put(name, value);
+                    } else if ("propertiesfile".equals(type)) {
+                        Properties props = getPropertiesFromFile(params[i].getValue());
+                        for (Enumeration e = props.keys(); e.hasMoreElements();) {
+                            String key = (String) e.nextElement();
+                            String value = props.getProperty(key);
+                            hash.put(key, value);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Holds a token
+     */
+    public static class Token {
+
+        /** Token key */
+        private String key;
+
+        /** Token value */
+        private String value;
+
+        /**
+         * Sets the token key
+         *
+         * @param key The key for this token. Must not be <code>null</code>.
+         */
+        public final void setKey(String key) {
+            this.key = key;
+        }
+
+        /**
+         * Sets the token value
+         *
+         * @param value The value for this token. Must not be <code>null</code>.
+         */
+        public final void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * Returns the key for this token.
+         *
+         * @return the key for this token
+         */
+        public final String getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value for this token.
+         *
+         * @return the value for this token
+         */
+        public final String getValue() {
+            return value;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/StringInputStream.java b/trunk/src/main/org/apache/tools/ant/filters/StringInputStream.java
new file mode 100644
index 0000000..e150e96
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/StringInputStream.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.StringReader;
+
+import org.apache.tools.ant.util.ReaderInputStream;
+
+/**
+ * Wraps a String as an InputStream.
+ *
+ */
+public class StringInputStream extends ReaderInputStream {
+
+    /**
+     * Composes a stream from a String
+     *
+     * @param source The string to read from. Must not be <code>null</code>.
+     */
+    public StringInputStream(String source) {
+        super(new StringReader(source));
+    }
+
+    /**
+     * Composes a stream from a String with the specified encoding
+     *
+     * @param source The string to read from. Must not be <code>null</code>.
+     * @param encoding The encoding scheme.  Also must not be <code>null</code>.
+     */
+    public StringInputStream(String source, String encoding) {
+        super(new StringReader(source), encoding);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/StripJavaComments.java b/trunk/src/main/org/apache/tools/ant/filters/StripJavaComments.java
new file mode 100644
index 0000000..65bccd7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/StripJavaComments.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * This is a Java comment and string stripper reader that filters
+ * those lexical tokens out for purposes of simple Java parsing.
+ * (if you have more complex Java parsing needs, use a real lexer).
+ * Since this class heavily relies on the single char read function,
+ * you are recommended to make it work on top of a buffered reader.
+ *
+ */
+public final class StripJavaComments
+    extends BaseFilterReader
+    implements ChainableReader {
+
+    /**
+     * The read-ahead character, used for effectively pushing a single
+     * character back. A value of -1 indicates that no character is in the
+     * buffer.
+     */
+    private int readAheadCh = -1;
+
+    /**
+     * Whether or not the parser is currently in the middle of a string
+     * literal.
+     */
+    private boolean inString = false;
+
+    /**
+     * Whether or not the last char has been a backslash.
+     */
+    private boolean quoted = false;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public StripJavaComments() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public StripJavaComments(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, not including
+     * Java comments.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        int ch = -1;
+        if (readAheadCh != -1) {
+            ch = readAheadCh;
+            readAheadCh = -1;
+        } else {
+            ch = in.read();
+            if (ch == '"' && !quoted) {
+                inString = !inString;
+                quoted = false;
+            } else if (ch == '\\') {
+                quoted = !quoted;
+            } else {
+                quoted = false;
+                if (!inString) {
+                    if (ch == '/') {
+                        ch = in.read();
+                        if (ch == '/') {
+                            while (ch != '\n' && ch != -1 && ch != '\r') {
+                                ch = in.read();
+                            }
+                        } else if (ch == '*') {
+                            while (ch != -1) {
+                                ch = in.read();
+                                if (ch == '*') {
+                                    ch = in.read();
+                                    while (ch == '*') {
+                                        ch = in.read();
+                                    }
+
+                                    if (ch == '/') {
+                                        ch = read();
+                                        break;
+                                    }
+                                }
+                            }
+                        } else {
+                            readAheadCh = ch;
+                            ch = '/';
+                        }
+                    }
+                }
+            }
+        }
+
+        return ch;
+    }
+
+    /**
+     * Creates a new StripJavaComments using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+
+    public Reader chain(final Reader rdr) {
+        StripJavaComments newFilter = new StripJavaComments(rdr);
+        return newFilter;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/StripLineBreaks.java b/trunk/src/main/org/apache/tools/ant/filters/StripLineBreaks.java
new file mode 100644
index 0000000..1ebda63
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/StripLineBreaks.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Filter to flatten the stream to a single line.
+ *
+ * Example:
+ *
+ * <pre>&lt;striplinebreaks/&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader
+ *   classname=&quot;org.apache.tools.ant.filters.StripLineBreaks&quot;/&gt;</pre>
+ *
+ */
+public final class StripLineBreaks
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /**
+     * Line-breaking characters.
+     * What should we do on funny IBM mainframes with odd line endings?
+     */
+    private static final String DEFAULT_LINE_BREAKS = "\r\n";
+
+    /** Parameter name for the line-breaking characters parameter. */
+    private static final String LINE_BREAKS_KEY = "linebreaks";
+
+    /** The characters that are recognized as line breaks. */
+    private String lineBreaks = DEFAULT_LINE_BREAKS;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public StripLineBreaks() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public StripLineBreaks(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, only including
+     * characters not in the set of line-breaking characters.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = in.read();
+        while (ch != -1) {
+            if (lineBreaks.indexOf(ch) == -1) {
+                break;
+            } else {
+                ch = in.read();
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the line-breaking characters.
+     *
+     * @param lineBreaks A String containing all the characters to be
+     *                   considered as line-breaking.
+     */
+    public void setLineBreaks(final String lineBreaks) {
+        this.lineBreaks = lineBreaks;
+    }
+
+    /**
+     * Returns the line-breaking characters as a String.
+     *
+     * @return a String containing all the characters considered as
+     *         line-breaking
+     */
+    private String getLineBreaks() {
+        return lineBreaks;
+    }
+
+    /**
+     * Creates a new StripLineBreaks using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        StripLineBreaks newFilter = new StripLineBreaks(rdr);
+        newFilter.setLineBreaks(getLineBreaks());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Parses the parameters to set the line-breaking characters.
+     */
+    private void initialize() {
+        String userDefinedLineBreaks = null;
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (LINE_BREAKS_KEY.equals(params[i].getName())) {
+                    userDefinedLineBreaks = params[i].getValue();
+                    break;
+                }
+            }
+        }
+        if (userDefinedLineBreaks != null) {
+            lineBreaks = userDefinedLineBreaks;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/StripLineComments.java b/trunk/src/main/org/apache/tools/ant/filters/StripLineComments.java
new file mode 100644
index 0000000..5488849
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/StripLineComments.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Vector;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * This filter strips line comments.
+ *
+ * Example:
+ *
+ * <pre>&lt;striplinecomments&gt;
+ *   &lt;comment value=&quot;#&quot;/&gt;
+ *   &lt;comment value=&quot;--&quot;/&gt;
+ *   &lt;comment value=&quot;REM &quot;/&gt;
+ *   &lt;comment value=&quot;rem &quot;/&gt;
+ *   &lt;comment value=&quot;//&quot;/&gt;
+ * &lt;/striplinecomments&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader
+ *      classname=&quot;org.apache.tools.ant.filters.StripLineComments&quot;&gt;
+ *   &lt;param type=&quot;comment&quot; value="#&quot;/&gt;
+ *   &lt;param type=&quot;comment&quot; value=&quot;--&quot;/&gt;
+ *   &lt;param type=&quot;comment&quot; value=&quot;REM &quot;/&gt;
+ *   &lt;param type=&quot;comment&quot; value=&quot;rem &quot;/&gt;
+ *   &lt;param type=&quot;comment&quot; value=&quot;//&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class StripLineComments
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the comment prefix. */
+    private static final String COMMENTS_KEY = "comment";
+
+    /** Vector that holds the comment prefixes. */
+    private Vector comments = new Vector();
+
+    /** The line that has been read ahead. */
+    private String line = null;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public StripLineComments() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public StripLineComments(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, only including
+     * lines from the original stream which don't start with any of the
+     * specified comment prefixes.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        if (line != null) {
+            ch = line.charAt(0);
+            if (line.length() == 1) {
+                line = null;
+            } else {
+                line = line.substring(1);
+            }
+        } else {
+            line = readLine();
+            final int commentsSize = comments.size();
+
+            while (line != null) {
+                for (int i = 0; i < commentsSize; i++) {
+                    String comment = (String) comments.elementAt(i);
+                    if (line.startsWith(comment)) {
+                        line = null;
+                        break;
+                    }
+                }
+
+                if (line == null) {
+                    // line started with comment
+                    line = readLine();
+                } else {
+                    break;
+                }
+            }
+
+            if (line != null) {
+                return read();
+            }
+        }
+
+        return ch;
+    }
+
+    /**
+     * Adds a <code>comment</code> element to the list of prefixes.
+     *
+     * @param comment The <code>comment</code> element to add to the
+     * list of comment prefixes to strip. Must not be <code>null</code>.
+     */
+    public void addConfiguredComment(final Comment comment) {
+        comments.addElement(comment.getValue());
+    }
+
+    /**
+     * Sets the list of comment prefixes to strip.
+     *
+     * @param comments A list of strings, each of which is a prefix
+     * for a comment line. Must not be <code>null</code>.
+     */
+    private void setComments(final Vector comments) {
+        this.comments = comments;
+    }
+
+    /**
+     * Returns the list of comment prefixes to strip.
+     *
+     * @return the list of comment prefixes to strip.
+     */
+    private Vector getComments() {
+        return comments;
+    }
+
+    /**
+     * Creates a new StripLineComments using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        StripLineComments newFilter = new StripLineComments(rdr);
+        newFilter.setComments(getComments());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Parses the parameters to set the comment prefixes.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (COMMENTS_KEY.equals(params[i].getType())) {
+                    comments.addElement(params[i].getValue());
+                }
+            }
+        }
+    }
+
+    /**
+     * The class that holds a comment representation.
+     */
+    public static class Comment {
+
+        /** The prefix for a line comment. */
+        private String value;
+
+        /**
+         * Sets the prefix for this type of line comment.
+         *
+         * @param comment The prefix for a line comment of this type.
+         * Must not be <code>null</code>.
+         */
+        public final void setValue(String comment) {
+            if (value != null) {
+                throw new IllegalStateException("Comment value already set.");
+            }
+            value = comment;
+        }
+
+        /**
+         * Returns the prefix for this type of line comment.
+         *
+         * @return the prefix for this type of line comment.
+         */
+        public final String getValue() {
+            return value;
+        }
+
+        /**
+         * Alt. syntax to set the prefix for this type of line comment.
+         *
+         * @param comment The prefix for a line comment of this type.
+         * Must not be <code>null</code>.
+         */
+        public void addText(String comment) {
+            setValue(comment);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/TabsToSpaces.java b/trunk/src/main/org/apache/tools/ant/filters/TabsToSpaces.java
new file mode 100644
index 0000000..453899c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/TabsToSpaces.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Converts tabs to spaces.
+ *
+ * Example:
+ *
+ * <pre>&lt;tabtospaces tablength=&quot;8&quot;/&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.TabsToSpaces&quot;&gt;
+ *   &lt;param name=&quot;tablength&quot; value=&quot;8&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class TabsToSpaces
+    extends BaseParamFilterReader
+    implements ChainableReader {
+    /** The default tab length. */
+    private static final int DEFAULT_TAB_LENGTH = 8;
+
+    /** Parameter name for the length of a tab. */
+    private static final String TAB_LENGTH_KEY = "tablength";
+
+    /** Tab length in this filter. */
+    private int tabLength = DEFAULT_TAB_LENGTH;
+
+    /** The number of spaces still to be read to represent the last-read tab. */
+    private int spacesRemaining = 0;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public TabsToSpaces() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public TabsToSpaces(final Reader in) {
+        super(in);
+    }
+
+    /**
+     * Returns the next character in the filtered stream, converting tabs
+     * to the specified number of spaces.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        int ch = -1;
+
+        if (spacesRemaining > 0) {
+            spacesRemaining--;
+            ch = ' ';
+        } else {
+            ch = in.read();
+            if (ch == '\t') {
+                spacesRemaining = tabLength - 1;
+                ch = ' ';
+            }
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the tab length.
+     *
+     * @param tabLength the number of spaces to be used when converting a tab.
+     */
+    public void setTablength(final int tabLength) {
+        this.tabLength = tabLength;
+    }
+
+    /**
+     * Returns the tab length.
+     *
+     * @return the number of spaces used when converting a tab
+     */
+    private int getTablength() {
+        return tabLength;
+    }
+
+    /**
+     * Creates a new TabsToSpaces using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        TabsToSpaces newFilter = new TabsToSpaces(rdr);
+        newFilter.setTablength(getTablength());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Parses the parameters to set the tab length.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (params[i] != null) {
+                    if (TAB_LENGTH_KEY.equals(params[i].getName())) {
+                        tabLength = Integer.parseInt(params[i].getValue());
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/TailFilter.java b/trunk/src/main/org/apache/tools/ant/filters/TailFilter.java
new file mode 100644
index 0000000..09281f3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/TailFilter.java
@@ -0,0 +1,242 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.LinkedList;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.util.LineTokenizer;
+
+/**
+ * Reads the last <code>n</code> lines of a stream. (Default is last10 lines.)
+ *
+ * Example:
+ *
+ * <pre>&lt;tailfilter lines=&quot;3&quot;/&gt;</pre>
+ *
+ * Or:
+ *
+ * <pre>&lt;filterreader classname=&quot;org.apache.tools.ant.filters.TailFilter&quot;&gt;
+ *   &lt;param name=&quot;lines&quot; value=&quot;3&quot;/&gt;
+ * &lt;/filterreader&gt;</pre>
+ *
+ */
+public final class TailFilter extends BaseParamFilterReader
+    implements ChainableReader {
+    /** Parameter name for the number of lines to be returned. */
+    private static final String LINES_KEY = "lines";
+
+    /** Parameter name for the number of lines to be skipped. */
+    private static final String SKIP_KEY = "skip";
+
+    /** Default number of lines to show */
+    private static final int DEFAULT_NUM_LINES = 10;
+
+    /** Number of lines to be returned in the filtered stream. */
+    private long lines = DEFAULT_NUM_LINES;
+
+    /** Number of lines to be skipped. */
+    private long skip = 0;
+
+    /** Whether or not read-ahead been completed. */
+    private boolean completedReadAhead = false;
+
+    /** A line tokenizer */
+    private LineTokenizer lineTokenizer = null;
+
+    /** the current line from the input stream */
+    private String    line      = null;
+    /** the position in the current line */
+    private int       linePos   = 0;
+
+    private LinkedList lineList = new LinkedList();
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public TailFilter() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public TailFilter(final Reader in) {
+        super(in);
+        lineTokenizer = new LineTokenizer();
+        lineTokenizer.setIncludeDelims(true);
+    }
+
+    /**
+     * Returns the next character in the filtered stream. If the read-ahead
+     * has been completed, the next character in the buffer is returned.
+     * Otherwise, the stream is read to the end and buffered (with the buffer
+     * growing as necessary), then the appropriate position in the buffer is
+     * set to read from.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+    public int read() throws IOException {
+        if (!getInitialized()) {
+            initialize();
+            setInitialized(true);
+        }
+
+        while (line == null || line.length() == 0) {
+            line = lineTokenizer.getToken(in);
+            line = tailFilter(line);
+            if (line == null) {
+                return -1;
+            }
+            linePos = 0;
+        }
+
+        int ch = line.charAt(linePos);
+        linePos++;
+        if (linePos == line.length()) {
+            line = null;
+        }
+        return ch;
+    }
+
+    /**
+     * Sets the number of lines to be returned in the filtered stream.
+     *
+     * @param lines the number of lines to be returned in the filtered stream
+     */
+    public void setLines(final long lines) {
+        this.lines = lines;
+    }
+
+    /**
+     * Returns the number of lines to be returned in the filtered stream.
+     *
+     * @return the number of lines to be returned in the filtered stream
+     */
+    private long getLines() {
+        return lines;
+    }
+
+    /**
+     * Sets the number of lines to be skipped in the filtered stream.
+     *
+     * @param skip the number of lines to be skipped in the filtered stream
+     */
+    public void setSkip(final long skip) {
+        this.skip = skip;
+    }
+
+    /**
+     * Returns the number of lines to be skipped in the filtered stream.
+     *
+     * @return the number of lines to be skipped in the filtered stream
+     */
+    private long getSkip() {
+        return skip;
+    }
+
+    /**
+     * Creates a new TailFilter using the passed in
+     * Reader for instantiation.
+     *
+     * @param rdr A Reader object providing the underlying stream.
+     *            Must not be <code>null</code>.
+     *
+     * @return a new filter based on this configuration, but filtering
+     *         the specified reader
+     */
+    public Reader chain(final Reader rdr) {
+        TailFilter newFilter = new TailFilter(rdr);
+        newFilter.setLines(getLines());
+        newFilter.setSkip(getSkip());
+        newFilter.setInitialized(true);
+        return newFilter;
+    }
+
+    /**
+     * Scans the parameters list for the "lines" parameter and uses
+     * it to set the number of lines to be returned in the filtered stream.
+     * also scan for "skip" parameter.
+     */
+    private void initialize() {
+        Parameter[] params = getParameters();
+        if (params != null) {
+            for (int i = 0; i < params.length; i++) {
+                if (LINES_KEY.equals(params[i].getName())) {
+                    setLines(Long.parseLong(params[i].getValue()));
+                    continue;
+                }
+                if (SKIP_KEY.equals(params[i].getName())) {
+                    skip = Long.parseLong(params[i].getValue());
+                    continue;
+                }
+            }
+        }
+    }
+
+    /**
+     * implement a tail filter on a stream of lines.
+     * line = null is the end of the stream.
+     * @return "" while reading in the lines,
+     *         line while outputting the lines
+     *         null at the end of outputting the lines
+     */
+    private String tailFilter(String line) {
+        if (!completedReadAhead) {
+            if (line != null) {
+                lineList.add(line);
+                if (lines == -1) {
+                    if (lineList.size() > skip) {
+                        return (String) lineList.removeFirst();
+                    }
+                } else {
+                    long linesToKeep = lines + (skip > 0 ? skip : 0);
+                    if (linesToKeep < lineList.size()) {
+                        lineList.removeFirst();
+                    }
+                }
+                return "";
+            }
+            completedReadAhead = true;
+            if (skip > 0) {
+                for (int i = 0; i < skip; ++i) {
+                    lineList.removeLast();
+                }
+            }
+            if (lines > -1) {
+                while (lineList.size() > lines) {
+                    lineList.removeFirst();
+                }
+            }
+        }
+        if (lineList.size() > 0) {
+            return (String) lineList.removeFirst();
+        }
+        return null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/TokenFilter.java b/trunk/src/main/org/apache/tools/ant/filters/TokenFilter.java
new file mode 100644
index 0000000..81515e2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/TokenFilter.java
@@ -0,0 +1,726 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Vector;
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.types.Substitution;
+import org.apache.tools.ant.util.Tokenizer;
+import org.apache.tools.ant.util.LineTokenizer;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.regexp.Regexp;
+
+/**
+ * This splits up input into tokens and passes
+ * the tokens to a sequence of filters.
+ *
+ * @since Ant 1.6
+ * @see BaseFilterReader
+ * @see ChainableReader
+ * @see org.apache.tools.ant.DynamicConfigurator
+ */
+public class TokenFilter extends BaseFilterReader
+    implements ChainableReader {
+    /**
+     * string filters implement this interface
+     */
+    public interface Filter {
+        /**
+         * filter and/of modify a string
+         *
+         * @param string the string to filter
+         * @return the modified string or null if the
+         *         string did not pass the filter
+         */
+        String filter(String string);
+    }
+
+
+    /** string filters */
+    private Vector    filters   = new Vector();
+    /** the tokenizer to use on the input stream */
+    private Tokenizer tokenizer = null;
+    /** the output token termination */
+    private String    delimOutput = null;
+    /** the current string token from the input stream */
+    private String    line      = null;
+    /** the position in the current string token */
+    private int       linePos   = 0;
+
+    /**
+     * Constructor for "dummy" instances.
+     *
+     * @see BaseFilterReader#BaseFilterReader()
+     */
+    public TokenFilter() {
+        super();
+    }
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in A Reader object providing the underlying stream.
+     *           Must not be <code>null</code>.
+     */
+    public TokenFilter(final Reader in) {
+        super(in);
+    }
+
+
+    /**
+     * Returns the next character in the filtered stream, only including
+     * lines from the original stream which match all of the specified
+     * regular expressions.
+     *
+     * @return the next character in the resulting stream, or -1
+     * if the end of the resulting stream has been reached
+     *
+     * @exception IOException if the underlying stream throws an IOException
+     * during reading
+     */
+
+    public int read() throws IOException {
+        if (tokenizer == null) {
+            tokenizer = new LineTokenizer();
+        }
+        while (line == null || line.length() == 0) {
+            line = tokenizer.getToken(in);
+            if (line == null) {
+                return -1;
+            }
+            for (Enumeration e = filters.elements(); e.hasMoreElements();) {
+                Filter filter = (Filter) e.nextElement();
+                line = filter.filter(line);
+                if (line == null) {
+                    break;
+                }
+            }
+            linePos = 0;
+            if (line != null) {
+                if (tokenizer.getPostToken().length() != 0) {
+                    if (delimOutput != null) {
+                        line = line + delimOutput;
+                    } else {
+                        line = line + tokenizer.getPostToken();
+                    }
+                }
+            }
+        }
+        int ch = line.charAt(linePos);
+        linePos++;
+        if (linePos == line.length()) {
+            line = null;
+        }
+        return ch;
+    }
+
+    /**
+     * Creates a new TokenFilter using the passed in
+     * Reader for instantiation.
+     *
+     * @param reader A Reader object providing the underlying stream.
+     *
+     * @return a new filter based on this configuration
+     */
+
+    public final Reader chain(final Reader reader) {
+        TokenFilter newFilter = new TokenFilter(reader);
+        newFilter.filters = filters;
+        newFilter.tokenizer = tokenizer;
+        newFilter.delimOutput = delimOutput;
+        newFilter.setProject(getProject());
+        return newFilter;
+    }
+
+    /**
+     * set the output delimiter.
+     * @param delimOutput replaces the delim string returned by the
+     *                    tokenizer, if present.
+     */
+
+    public void setDelimOutput(String delimOutput) {
+        this.delimOutput = resolveBackSlash(delimOutput);
+    }
+
+    // -----------------------------------------
+    //  Predefined tokenizers
+    // -----------------------------------------
+
+    /**
+     * add a line tokenizer - this is the default.
+     * @param tokenizer the line tokenizer
+     */
+
+    public void addLineTokenizer(LineTokenizer tokenizer) {
+        add(tokenizer);
+    }
+
+    /**
+     * add a string tokenizer
+     * @param tokenizer the string tokenizer
+     */
+
+    public void addStringTokenizer(StringTokenizer tokenizer) {
+        add(tokenizer);
+    }
+
+    /**
+     * add a file tokenizer
+     * @param tokenizer the file tokenizer
+     */
+    public void addFileTokenizer(FileTokenizer tokenizer) {
+        add(tokenizer);
+    }
+
+    /**
+     * add an arbitrary tokenizer
+     * @param tokenizer the tokenizer to all, only one allowed
+     */
+
+    public void add(Tokenizer tokenizer) {
+        if (this.tokenizer != null) {
+            throw new BuildException("Only one tokenizer allowed");
+        }
+        this.tokenizer = tokenizer;
+    }
+
+    // -----------------------------------------
+    //  Predefined filters
+    // -----------------------------------------
+
+    /**
+     * replace string filter
+     * @param filter the replace string filter
+     */
+    public void addReplaceString(ReplaceString filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * contains string filter
+     * @param filter the contains string filter
+     */
+    public void addContainsString(ContainsString filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * replace regex filter
+     * @param filter the replace regex filter
+     */
+    public void addReplaceRegex(ReplaceRegex filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * contains regex filter
+     * @param filter the contains regex filter
+     */
+    public void addContainsRegex(ContainsRegex filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * trim filter
+     * @param filter the trim filter
+     */
+    public void addTrim(Trim filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * ignore blank filter
+     * @param filter the ignore blank filter
+     */
+    public void addIgnoreBlank(IgnoreBlank filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * delete chars
+     * @param filter the delete characters filter
+     */
+    public void addDeleteCharacters(DeleteCharacters filter) {
+        filters.addElement(filter);
+    }
+
+    /**
+     * Add an arbitrary filter
+     * @param filter the filter to add
+     */
+    public void add(Filter filter) {
+        filters.addElement(filter);
+    }
+
+
+    // --------------------------------------------
+    //
+    //      Tokenizer Classes (impls moved to oata.util)
+    //
+    // --------------------------------------------
+
+    /**
+     * class to read the complete input into a string
+     */
+    public static class FileTokenizer
+        extends org.apache.tools.ant.util.FileTokenizer {
+    }
+
+    /**
+     * class to tokenize the input as areas separated
+     * by white space, or by a specified list of
+     * delim characters. Behaves like java.util.StringTokenizer.
+     * if the stream starts with delim characters, the first
+     * token will be an empty string (unless the treat delims
+     * as tokens flag is set).
+     */
+    public static class StringTokenizer
+        extends org.apache.tools.ant.util.StringTokenizer {
+    }
+
+    // --------------------------------------------
+    //
+    //      Filter classes
+    //
+    // --------------------------------------------
+
+    /**
+     * Abstract class that converts derived filter classes into
+     * ChainableReaderFilter's
+     */
+    public abstract static class ChainableReaderFilter extends ProjectComponent
+        implements ChainableReader, Filter {
+        private boolean byLine = true;
+
+        /**
+         * set whether to use filetokenizer or line tokenizer
+         * @param byLine if true use a linetokenizer (default) otherwise
+         *               use a filetokenizer
+         */
+        public void setByLine(boolean byLine) {
+            this.byLine = byLine;
+        }
+
+        /**
+         * Chain a tokenfilter reader to a reader,
+         *
+         * @param reader the input reader object
+         * @return the chained reader object
+         */
+        public Reader chain(Reader reader) {
+            TokenFilter tokenFilter = new TokenFilter(reader);
+            if (!byLine) {
+                tokenFilter.add(new FileTokenizer());
+            }
+            tokenFilter.add(this);
+            return tokenFilter;
+        }
+    }
+
+    /**
+     * Simple replace string filter.
+     */
+    public static class ReplaceString extends ChainableReaderFilter {
+        private String from;
+        private String to;
+
+        /**
+         * the from attribute
+         *
+         * @param from the string to replace
+         */
+        public void setFrom(String from) {
+            this.from = from;
+        }
+
+        /**
+         * the to attribute
+         *
+         * @param to the string to replace 'from' with
+         */
+        public void setTo(String to) {
+            this.to = to;
+        }
+
+        /**
+         * Filter a string 'line' replacing from with to
+         * (C&P from the Replace task)
+         * @param line the string to be filtered
+         * @return the filtered line
+         */
+        public String filter(String line) {
+            if (from == null) {
+                throw new BuildException("Missing from in stringreplace");
+            }
+            StringBuffer ret = new StringBuffer();
+            int start = 0;
+            int found = line.indexOf(from);
+            while (found >= 0) {
+                // write everything up to the from
+                if (found > start) {
+                    ret.append(line.substring(start, found));
+                }
+
+                // write the replacement to
+                if (to != null) {
+                    ret.append(to);
+                }
+
+                // search again
+                start = found + from.length();
+                found = line.indexOf(from, start);
+            }
+
+            // write the remaining characters
+            if (line.length() > start) {
+                ret.append(line.substring(start, line.length()));
+            }
+
+            return ret.toString();
+        }
+    }
+
+    /**
+     * Simple filter to filter lines contains strings
+     */
+    public static class ContainsString extends ProjectComponent
+        implements Filter {
+        private String contains;
+
+        /**
+         * the contains attribute
+         * @param contains the string that the token should contain
+         */
+        public void setContains(String contains) {
+            this.contains = contains;
+        }
+
+        /**
+         * Filter strings that contain the contains attribute
+         *
+         * @param string the string to be filtered
+         * @return null if the string does not contain "contains",
+         *              string otherwise
+         */
+        public String filter(String string) {
+            if (contains == null) {
+                throw new BuildException("Missing contains in containsstring");
+            }
+            if (string.indexOf(contains) > -1) {
+                return string;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * filter to replace regex.
+     */
+    public static class ReplaceRegex extends ChainableReaderFilter {
+        private String             from;
+        private String             to;
+        private RegularExpression  regularExpression;
+        private Substitution       substitution;
+        private boolean            initialized = false;
+        private String             flags = "";
+        private int                options;
+        private Regexp             regexp;
+
+        /**
+         * the from attribute
+         * @param from the regex string
+         */
+        public void setPattern(String from) {
+            this.from = from;
+        }
+        /**
+         * the to attribute
+         * @param to the replacement string
+         */
+        public void setReplace(String to) {
+            this.to = to;
+        }
+
+        /**
+         * @param flags the regex flags
+         */
+        public void setFlags(String flags) {
+            this.flags = flags;
+        }
+
+        private void initialize() {
+            if (initialized) {
+                return;
+            }
+            options = convertRegexOptions(flags);
+            if (from == null) {
+                throw new BuildException("Missing pattern in replaceregex");
+            }
+            regularExpression = new RegularExpression();
+            regularExpression.setPattern(from);
+            regexp = regularExpression.getRegexp(getProject());
+            if (to == null) {
+                to = "";
+            }
+            substitution = new Substitution();
+            substitution.setExpression(to);
+        }
+
+        /**
+         * @param line the string to modify
+         * @return the modified string
+         */
+        public String filter(String line) {
+            initialize();
+
+            if (!regexp.matches(line, options)) {
+                return line;
+            }
+            return regexp.substitute(
+                line, substitution.getExpression(getProject()), options);
+        }
+    }
+
+    /**
+     * filter to filter tokens matching regular expressions.
+     */
+    public static class ContainsRegex extends ChainableReaderFilter {
+        private String             from;
+        private String             to;
+        private RegularExpression  regularExpression;
+        private Substitution       substitution;
+        private boolean            initialized = false;
+        private String             flags = "";
+        private int                options;
+        private Regexp             regexp;
+
+
+        /**
+         * @param from the regex pattern
+         */
+        public void setPattern(String from) {
+            this.from = from;
+        }
+
+        /**
+         * @param to the replacement string
+         */
+        public void setReplace(String to) {
+            this.to = to;
+        }
+
+        /**
+         * @param flags the regex flags
+         */
+        public void setFlags(String flags) {
+            this.flags = flags;
+        }
+
+        private void initialize() {
+            if (initialized) {
+                return;
+            }
+            options = convertRegexOptions(flags);
+            if (from == null) {
+                throw new BuildException("Missing from in containsregex");
+            }
+            regularExpression = new RegularExpression();
+            regularExpression.setPattern(from);
+            regexp = regularExpression.getRegexp(getProject());
+            if (to == null) {
+                return;
+            }
+            substitution = new Substitution();
+            substitution.setExpression(to);
+        }
+
+        /**
+         * apply regex and substitution on a string
+         * @param string the string to apply filter on
+         * @return the filtered string
+         */
+        public String filter(String string) {
+            initialize();
+            if (!regexp.matches(string, options)) {
+                return null;
+            }
+            if (substitution == null) {
+                return string;
+            }
+            return regexp.substitute(
+                string, substitution.getExpression(getProject()), options);
+        }
+    }
+
+    /** Filter to trim white space */
+    public static class Trim extends ChainableReaderFilter {
+        /**
+         * @param line the string to be trimmed
+         * @return the trimmed string
+         */
+        public String filter(String line) {
+            return line.trim();
+        }
+    }
+
+
+
+    /** Filter remove empty tokens */
+    public static class IgnoreBlank extends ChainableReaderFilter {
+        /**
+         * @param line the line to modify
+         * @return the trimmed line
+         */
+        public String filter(String line) {
+            if (line.trim().length() == 0) {
+                return null;
+            }
+            return line;
+        }
+    }
+
+    /**
+     * Filter to delete characters
+     */
+    public static class DeleteCharacters extends ProjectComponent
+        implements Filter, ChainableReader {
+        // Attributes
+        /** the list of characters to remove from the input */
+        private String deleteChars = "";
+
+        /**
+         * Set the list of characters to delete
+         * @param deleteChars the list of characters
+         */
+        public void setChars(String deleteChars) {
+            this.deleteChars = resolveBackSlash(deleteChars);
+        }
+
+        /**
+         * remove characters from a string
+         * @param string the string to remove the characters from
+         * @return the converted string
+         */
+        public String filter(String string) {
+            StringBuffer output = new StringBuffer(string.length());
+            for (int i = 0; i < string.length(); ++i) {
+                char ch = string.charAt(i);
+                if (!(isDeleteCharacter(ch))) {
+                    output.append(ch);
+                }
+            }
+            return output.toString();
+        }
+
+        /**
+         * factory method to provide a reader that removes
+         * the characters from a reader as part of a filter
+         * chain
+         * @param reader the reader object
+         * @return the chained reader object
+         */
+        public Reader chain(Reader reader) {
+            return new BaseFilterReader(reader) {
+                /**
+                 * @return the next non delete character
+                 */
+                public int read()
+                    throws IOException {
+                    while (true) {
+                        int c = in.read();
+                        if (c == -1) {
+                            return c;
+                        }
+                        if (!(isDeleteCharacter((char) c))) {
+                            return c;
+                        }
+                    }
+                }
+            };
+        }
+
+        /**
+         *  check if the character c is to be deleted
+         *
+         * @param c char to test
+         * @return true if the supplied char is in the list to be stripped.
+         */
+        private boolean isDeleteCharacter(char c) {
+            for (int d = 0; d < deleteChars.length(); ++d) {
+                if (deleteChars.charAt(d) ==  c) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    // --------------------------------------------------------
+    //  static utility methods - could be placed somewhere else
+    // --------------------------------------------------------
+
+    /**
+     * xml does not do "c" like interpretation of strings.
+     * i.e. \n\r\t etc.
+     * this method processes \n, \r, \t, \f, \\
+     * also subs \s -> " \n\r\t\f"
+     * a trailing '\' will be ignored
+     *
+     * @param input raw string with possible embedded '\'s
+     * @return converted string
+     */
+    public static String resolveBackSlash(String input) {
+        return StringUtils.resolveBackSlash(input);
+    }
+
+    /**
+     * convert regex option flag characters to regex options
+     * <dl>
+     *   <li>g -  Regexp.REPLACE_ALL</li>
+     *   <li>i -  Regexp.MATCH_CASE_INSENSITIVE</li>
+     *   <li>m -  Regexp.MATCH_MULTILINE</li>
+     *   <li>s -  Regexp.MATCH_SINGLELINE</li>
+     * </dl>
+     * @param flags the string containing the flags
+     * @return the Regexp option bits
+     */
+    public static int convertRegexOptions(String flags) {
+        if (flags == null) {
+            return 0;
+        }
+        int options = 0;
+        if (flags.indexOf('g') != -1) {
+            options |= Regexp.REPLACE_ALL;
+        }
+        if (flags.indexOf('i') != -1) {
+            options |= Regexp.MATCH_CASE_INSENSITIVE;
+        }
+        if (flags.indexOf('m') != -1) {
+            options |= Regexp.MATCH_MULTILINE;
+        }
+        if (flags.indexOf('s') != -1) {
+            options |= Regexp.MATCH_SINGLELINE;
+        }
+        return options;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/util/ChainReaderHelper.java b/trunk/src/main/org/apache/tools/ant/filters/util/ChainReaderHelper.java
new file mode 100644
index 0000000..aa76c2f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/util/ChainReaderHelper.java
@@ -0,0 +1,237 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters.util;
+
+import java.io.FilterReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Vector;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.filters.BaseFilterReader;
+import org.apache.tools.ant.filters.ChainableReader;
+import org.apache.tools.ant.types.AntFilterReader;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Parameterizable;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Process a FilterReader chain.
+ *
+ */
+public final class ChainReaderHelper {
+
+    // default buffer size
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * The primary reader to which the reader chain is to be attached.
+     */
+    public Reader primaryReader;
+
+    /**
+     * The size of the buffer to be used.
+     */
+    public int bufferSize = DEFAULT_BUFFER_SIZE;
+
+    /**
+     * Chain of filters
+     */
+    public Vector filterChains = new Vector();
+
+    /** The Ant project */
+    private Project project = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Sets the primary reader
+     * @param rdr the reader object
+     */
+    public void setPrimaryReader(Reader rdr) {
+        primaryReader = rdr;
+    }
+
+    /**
+     * Set the project to work with
+     * @param project the current project
+     */
+    public void setProject(final Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Get the project
+     *
+     * @return the current project
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Sets the buffer size to be used.  Defaults to 8192,
+     * if this method is not invoked.
+     * @param size the buffer size to use
+     */
+    public void setBufferSize(int size) {
+        bufferSize = size;
+    }
+
+    /**
+     * Sets the collection of filter reader sets
+     *
+     * @param fchain the filter chains collection
+     */
+    public void setFilterChains(Vector fchain) {
+        filterChains = fchain;
+    }
+
+    /**
+     * Assemble the reader
+     * @return the assembled reader
+     * @exception BuildException if an error occurs
+     */
+    public Reader getAssembledReader() throws BuildException {
+        if (primaryReader == null) {
+            throw new BuildException("primaryReader must not be null.");
+        }
+
+        Reader instream = primaryReader;
+        final int filterReadersCount = filterChains.size();
+        final Vector finalFilters = new Vector();
+
+        for (int i = 0; i < filterReadersCount; i++) {
+            final FilterChain filterchain =
+                (FilterChain) filterChains.elementAt(i);
+            final Vector filterReaders = filterchain.getFilterReaders();
+            final int readerCount = filterReaders.size();
+            for (int j = 0; j < readerCount; j++) {
+                finalFilters.addElement(filterReaders.elementAt(j));
+            }
+        }
+
+        final int filtersCount = finalFilters.size();
+
+        if (filtersCount > 0) {
+            for (int i = 0; i < filtersCount; i++) {
+                Object o = finalFilters.elementAt(i);
+
+                if (o instanceof AntFilterReader) {
+                    final AntFilterReader filter
+                        = (AntFilterReader) finalFilters.elementAt(i);
+                    final String className = filter.getClassName();
+                    final Path classpath = filter.getClasspath();
+                    final Project pro = filter.getProject();
+                    if (className != null) {
+                        try {
+                            Class clazz = null;
+                            if (classpath == null) {
+                                clazz = Class.forName(className);
+                            } else {
+                                AntClassLoader al
+                                    = pro.createClassLoader(classpath);
+                                clazz = Class.forName(className, true, al);
+                            }
+                            if (clazz != null) {
+                                if (!FilterReader.class.isAssignableFrom(clazz)) {
+                                    throw new BuildException(className
+                                        + " does not extend java.io.FilterReader");
+                                }
+                                final Constructor[] constructors =
+                                    clazz.getConstructors();
+                                int j = 0;
+                                boolean consPresent = false;
+                                for (; j < constructors.length; j++) {
+                                    Class[] types = constructors[j]
+                                                      .getParameterTypes();
+                                    if (types.length == 1
+                                        && types[0].isAssignableFrom(Reader.class)) {
+                                        consPresent = true;
+                                        break;
+                                    }
+                                }
+                                if (!consPresent) {
+                                    throw new BuildException(className
+                                        + " does not define a public constructor"
+                                        + " that takes in a Reader as its "
+                                        + "single argument.");
+                                }
+                                final Reader[] rdr = {instream};
+                                instream =
+                                    (Reader) constructors[j].newInstance((Object[]) rdr);
+                                setProjectOnObject(instream);
+                                if (Parameterizable.class.isAssignableFrom(clazz)) {
+                                    final Parameter[] params = filter.getParams();
+                                    ((Parameterizable)
+                                        instream).setParameters(params);
+                                }
+                            }
+                        } catch (final ClassNotFoundException cnfe) {
+                            throw new BuildException(cnfe);
+                        } catch (final InstantiationException ie) {
+                            throw new BuildException(ie);
+                        } catch (final IllegalAccessException iae) {
+                            throw new BuildException(iae);
+                        } catch (final InvocationTargetException ite) {
+                            throw new BuildException(ite);
+                        }
+                    }
+                } else if (o instanceof ChainableReader) {
+                    setProjectOnObject(o);
+                    instream = ((ChainableReader) o).chain(instream);
+                    setProjectOnObject(instream);
+                }
+            }
+        }
+        return instream;
+    }
+
+    /**
+     * helper method to set the project on an object.
+     * the reflection setProject does not work for anonymous/protected/private
+     * classes, even if they have public methods.
+     */
+    private void setProjectOnObject(Object obj) {
+        if (project == null) {
+            return;
+        }
+        if (obj instanceof BaseFilterReader) {
+            ((BaseFilterReader) obj).setProject(project);
+            return;
+        }
+        project.setProjectReference(obj);
+    }
+
+    /**
+     * Read data from the reader and return the
+     * contents as a string.
+     * @param rdr the reader object
+     * @return the contents of the file as a string
+     * @exception IOException if an error occurs
+     */
+    public String readFully(Reader rdr)
+        throws IOException {
+        return FileUtils.readFully(rdr, bufferSize);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/filters/util/JavaClassHelper.java b/trunk/src/main/org/apache/tools/ant/filters/util/JavaClassHelper.java
new file mode 100644
index 0000000..1b1c64c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/filters/util/JavaClassHelper.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.filters.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.ConstantValue;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+/**
+ * Helper class that filters constants from a Java Class
+ *
+ */
+public final class JavaClassHelper {
+    /** System specific line separator. */
+    private static final String LS = System.getProperty("line.separator");
+
+    /**
+     * Get the constants declared in a file as name=value
+     *
+     * @param bytes the class as a array of bytes
+     * @return a StringBuffer contains the name=value pairs
+     * @exception IOException if an error occurs
+     */
+    public static StringBuffer getConstants(byte[] bytes)
+        throws IOException {
+        final StringBuffer sb = new StringBuffer();
+        final ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
+        final ClassParser parser = new ClassParser(bis, "");
+        final JavaClass javaClass = parser.parse();
+        final Field[] fields = javaClass.getFields();
+        for (int i = 0; i < fields.length; i++) {
+            final Field field = fields[i];
+            if (field != null) {
+                final ConstantValue cv = field.getConstantValue();
+                if (cv != null) {
+                    String cvs = cv.toString();
+                    //Remove start and end quotes if field is a String
+                    if (cvs.startsWith("\"") && cvs.endsWith("\"")) {
+                        cvs = cvs.substring(1, cvs.length() - 1);
+                    }
+                    sb.append(field.getName());
+                    sb.append('=');
+                    sb.append(cvs);
+                    sb.append(LS);
+                }
+            }
+        }
+        return sb;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/helper/AntXMLContext.java b/trunk/src/main/org/apache/tools/ant/helper/AntXMLContext.java
new file mode 100644
index 0000000..dc2d404
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/AntXMLContext.java
@@ -0,0 +1,367 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.helper;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.RuntimeConfigurable;
+
+
+/**
+ * Context information for the ant processing.
+ *
+ */
+public class AntXMLContext {
+    /** The project to configure. */
+    private Project project;
+
+    /** The configuration file to parse. */
+    private File buildFile;
+
+    /** Vector with all the targets, in the order they are
+     * defined. Project maintains a Hashtable, which is not ordered.
+     * This will allow description to know the original order.
+     */
+    private Vector targetVector = new Vector();
+
+    /**
+     * Parent directory of the build file. Used for resolving entities
+     * and setting the project's base directory.
+     */
+    private File buildFileParent;
+
+    /** Name of the current project */
+    private String currentProjectName;
+
+    /**
+     * Locator for the configuration file parser.
+     * Used for giving locations of errors etc.
+     */
+    private Locator locator;
+
+     /**
+      * Target that all other targets will depend upon implicitly.
+      *
+      * <p>This holds all tasks and data type definitions that have
+      * been placed outside of targets.</p>
+      */
+    private Target implicitTarget = new Target();
+
+    /** Current target ( no need for a stack as the processing model
+        allows only one level of target ) */
+    private Target currentTarget = null;
+
+    /** The stack of RuntimeConfigurable2 wrapping the
+        objects.
+    */
+    private Vector wStack = new Vector();
+
+    /**
+     * Indicates whether the project tag attributes are to be ignored
+     * when processing a particular build file.
+     */
+    private boolean ignoreProjectTag = false;
+
+    /** Keeps track of prefix -> uri mapping during parsing */
+    private Map prefixMapping = new HashMap();
+
+
+    /** Keeps track of targets in files */
+    private Map currentTargets = null;
+
+    /**
+     * constructor
+     * @param project the project to which this antxml context belongs to
+     */
+    public AntXMLContext(Project project) {
+        this.project = project;
+        implicitTarget.setProject(project);
+        implicitTarget.setName("");
+        targetVector.addElement(implicitTarget);
+    }
+
+    /**
+     * sets the build file to which the XML context belongs
+     * @param buildFile  ant build file
+     */
+    public void setBuildFile(File buildFile) {
+        this.buildFile = buildFile;
+        this.buildFileParent = new File(buildFile.getParent());
+        implicitTarget.setLocation(new Location(buildFile.getAbsolutePath()));
+    }
+
+    /**
+     * find out the build file
+     * @return  the build file to which the xml context belongs
+     */
+    public File getBuildFile() {
+        return buildFile;
+    }
+
+    /**
+     * find out the parent build file of this build file
+     * @return the parent build file of this build file
+     */
+    public File getBuildFileParent() {
+        return buildFileParent;
+    }
+
+    /**
+     * find out the project to which this antxml context belongs
+     * @return project
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * find out the current project name
+     * @return current project name
+     */
+    public String getCurrentProjectName() {
+        return currentProjectName;
+    }
+
+    /**
+     * set the name of the current project
+     * @param name name of the current project
+     */
+    public void setCurrentProjectName(String name) {
+        this.currentProjectName = name;
+    }
+
+    /**
+     * get the current runtime configurable wrapper
+     * can return null
+     * @return runtime configurable wrapper
+     */
+    public RuntimeConfigurable currentWrapper() {
+        if (wStack.size() < 1) {
+            return null;
+        }
+        return (RuntimeConfigurable) wStack.elementAt(wStack.size() - 1);
+    }
+
+    /**
+     * get the runtime configurable wrapper of the parent project
+     * can return null
+     * @return runtime configurable wrapper  of the parent project
+     */
+    public RuntimeConfigurable parentWrapper() {
+        if (wStack.size() < 2) {
+            return null;
+        }
+        return (RuntimeConfigurable) wStack.elementAt(wStack.size() - 2);
+    }
+
+    /**
+     * add a runtime configurable wrapper to the internal stack
+     * @param wrapper runtime configurable wrapper
+     */
+    public void pushWrapper(RuntimeConfigurable wrapper) {
+        wStack.addElement(wrapper);
+    }
+
+    /**
+     * remove a runtime configurable wrapper from the stack
+     */
+    public void popWrapper() {
+        if (wStack.size() > 0) {
+            wStack.removeElementAt(wStack.size() - 1);
+        }
+    }
+
+    /**
+     * access the stack of wrappers
+     * @return the stack of wrappers
+     */
+    public Vector getWrapperStack() {
+        return wStack;
+    }
+
+    /**
+     * add a new target
+     * @param target target to add
+     */
+    public void addTarget(Target target) {
+        targetVector.addElement(target);
+        currentTarget = target;
+    }
+
+    /**
+     * get the current target
+     * @return current target
+     */
+    public Target getCurrentTarget() {
+        return currentTarget;
+    }
+
+    /**
+     * get the implicit target
+     * @return implicit target
+     */
+    public Target getImplicitTarget() {
+        return implicitTarget;
+    }
+
+    /**
+     * sets the current target
+     * @param target current target
+     */
+    public void setCurrentTarget(Target target) {
+        this.currentTarget = target;
+    }
+
+    /**
+     * sets the implicit target
+     * @param target the implicit target
+     */
+    public void setImplicitTarget(Target target) {
+        this.implicitTarget = target;
+    }
+
+    /**
+     * access the vector of targets
+     * @return vector of targets
+     */
+    public Vector getTargets() {
+        return targetVector;
+    }
+
+    /**
+     * Scans an attribute list for the <code>id</code> attribute and
+     * stores a reference to the target object in the project if an
+     * id is found.
+     * <p>
+     * This method was moved out of the configure method to allow
+     * it to be executed at parse time.
+     * @param element the current element
+     * @param attr attributes of the current element
+     */
+    public void configureId(Object element, Attributes attr) {
+        String id = attr.getValue("id");
+        if (id != null) {
+            project.addIdReference(id, element);
+        }
+    }
+
+    /**
+     * access the locator
+     * @return locator
+     */
+    public Locator getLocator() {
+        return locator;
+    }
+
+    /**
+     * sets the locator
+     * @param locator locator
+     */
+    public void setLocator(Locator locator) {
+        this.locator = locator;
+    }
+
+    /**
+     * tells whether the project tag is being ignored
+     * @return whether the project tag is being ignored
+     */
+    public boolean isIgnoringProjectTag() {
+        return ignoreProjectTag;
+    }
+
+    /**
+     *  sets the flag to ignore the project tag
+     * @param flag to ignore the project tag
+     */
+    public void setIgnoreProjectTag(boolean flag) {
+        this.ignoreProjectTag = flag;
+    }
+
+    /**
+     * Called during parsing, stores the prefix to uri mapping.
+     *
+     * @param prefix a namespace prefix
+     * @param uri    a namespace uri
+     */
+    public void startPrefixMapping(String prefix, String uri) {
+        List list = (List) prefixMapping.get(prefix);
+        if (list == null) {
+            list = new ArrayList();
+            prefixMapping.put(prefix, list);
+        }
+        list.add(uri);
+    }
+
+    /**
+     * End of prefix to uri mapping.
+     *
+     * @param prefix the namespace prefix
+     */
+    public void endPrefixMapping(String prefix) {
+        List list = (List) prefixMapping.get(prefix);
+        if (list == null || list.size() == 0) {
+            return; // Should not happen
+        }
+        list.remove(list.size() - 1);
+    }
+
+    /**
+     * prefix to namespace uri mapping
+     *
+     * @param prefix the prefix to map
+     * @return the uri for this prefix, null if not present
+     */
+    public String getPrefixMapping(String prefix) {
+        List list = (List) prefixMapping.get(prefix);
+        if (list == null || list.size() == 0) {
+            return null;
+        }
+        return (String) list.get(list.size() - 1);
+    }
+
+    /**
+     * Get the targets in the current source file.
+     * @return the current targets.
+     */
+    public Map getCurrentTargets() {
+        return currentTargets;
+    }
+
+    /**
+     * Set the map of the targets in the current source file.
+     * @param currentTargets a map of targets.
+     */
+    public void setCurrentTargets(Map currentTargets) {
+        this.currentTargets = currentTargets;
+    }
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/helper/DefaultExecutor.java b/trunk/src/main/org/apache/tools/ant/helper/DefaultExecutor.java
new file mode 100755
index 0000000..d4099b4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/DefaultExecutor.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.helper;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Executor;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Default Target executor implementation. Runs each target individually
+ * (including all of its dependencies). If an error occurs, behavior is
+ * determined by the Project's "keep-going" mode.
+ * @since Ant 1.6.3
+ */
+public class DefaultExecutor implements Executor {
+
+    private static final SingleCheckExecutor SUB_EXECUTOR = new SingleCheckExecutor();
+
+    /** {@inheritDoc}. */
+    public void executeTargets(Project project, String[] targetNames)
+        throws BuildException {
+        BuildException thrownException = null;
+        for (int i = 0; i < targetNames.length; i++) {
+            try {
+                project.executeTarget(targetNames[i]);
+            } catch (BuildException ex) {
+                if (project.isKeepGoingMode()) {
+                    thrownException = ex;
+                } else {
+                    throw ex;
+                }
+            }
+        }
+        if (thrownException != null) {
+            throw thrownException;
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public Executor getSubProjectExecutor() {
+        return SUB_EXECUTOR;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/helper/IgnoreDependenciesExecutor.java b/trunk/src/main/org/apache/tools/ant/helper/IgnoreDependenciesExecutor.java
new file mode 100755
index 0000000..7ab8727
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/IgnoreDependenciesExecutor.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.helper;
+
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Executor;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+
+/**
+ * Target executor implementation that ignores dependencies. Runs each
+ * target by calling <code>target.performTasks()</code> directly. If an
+ * error occurs, behavior is determined by the Project's "keep-going" mode.
+ * To be used when you know what you're doing.
+ *
+ * @since Ant 1.7.1
+ */
+public class IgnoreDependenciesExecutor implements Executor {
+
+    private static final SingleCheckExecutor SUB_EXECUTOR = new SingleCheckExecutor();
+
+    /** {@inheritDoc}. */
+    public void executeTargets(Project project, String[] targetNames)
+        throws BuildException {
+        Hashtable targets = project.getTargets();
+        BuildException thrownException = null;
+        for (int i = 0; i < targetNames.length; i++) {
+            try {
+                Target t = (Target) targets.get(targetNames[i]);
+                if (t == null) {
+                  throw new BuildException("Unknown target " + targetNames[i]);
+                }
+                t.performTasks();
+            } catch (BuildException ex) {
+                if (project.isKeepGoingMode()) {
+                    thrownException = ex;
+                } else {
+                    throw ex;
+                }
+            }
+        }
+        if (thrownException != null) {
+            throw thrownException;
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public Executor getSubProjectExecutor() {
+        return SUB_EXECUTOR;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/helper/ProjectHelper2.java b/trunk/src/main/org/apache/tools/ant/helper/ProjectHelper2.java
new file mode 100644
index 0000000..e7cc449
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/ProjectHelper2.java
@@ -0,0 +1,1044 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.helper;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * Sax2 based project reader
+ *
+ */
+public class ProjectHelper2 extends ProjectHelper {
+    /** Reference holding the (ordered) target Vector */
+    public static final String REFID_TARGETS = "ant.targets";
+
+    /* Stateless */
+
+    // singletons - since all state is in the context
+    private static AntHandler elementHandler = new ElementHandler();
+    private static AntHandler targetHandler = new TargetHandler();
+    private static AntHandler mainHandler = new MainHandler();
+    private static AntHandler projectHandler = new ProjectHandler();
+
+    /** Specific to ProjectHelper2 so not a true Ant "magic name:" */
+    private static final String REFID_CONTEXT = "ant.parsing.context";
+
+    /**
+     * helper for path -> URI and URI -> path conversions.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Parse an unknown element from a url
+     *
+     * @param project the current project
+     * @param source  the url containing the task
+     * @return a configured task
+     * @exception BuildException if an error occurs
+     */
+    public UnknownElement parseUnknownElement(Project project, URL source) throws BuildException {
+        Target dummyTarget = new Target();
+        dummyTarget.setProject(project);
+
+        AntXMLContext context = new AntXMLContext(project);
+        context.addTarget(dummyTarget);
+        context.setImplicitTarget(dummyTarget);
+
+        parse(context.getProject(), source, new RootHandler(context, elementHandler));
+        Task[] tasks = dummyTarget.getTasks();
+        if (tasks.length != 1) {
+            throw new BuildException("No tasks defined");
+        }
+        return (UnknownElement) tasks[0];
+    }
+
+    /**
+     * Parse a source xml input.
+     *
+     * @param project the current project
+     * @param source  the xml source
+     * @exception BuildException if an error occurs
+     */
+    public void parse(Project project, Object source) throws BuildException {
+        getImportStack().addElement(source);
+        AntXMLContext context = null;
+        context = (AntXMLContext) project.getReference(REFID_CONTEXT);
+        if (context == null) {
+            context = new AntXMLContext(project);
+            project.addReference(REFID_CONTEXT, context);
+            project.addReference(REFID_TARGETS, context.getTargets());
+        }
+        if (getImportStack().size() > 1) {
+            // we are in an imported file.
+            context.setIgnoreProjectTag(true);
+            Target currentTarget = context.getCurrentTarget();
+            Target currentImplicit = context.getImplicitTarget();
+            Map    currentTargets = context.getCurrentTargets();
+            try {
+                Target newCurrent = new Target();
+                newCurrent.setProject(project);
+                newCurrent.setName("");
+                context.setCurrentTarget(newCurrent);
+                context.setCurrentTargets(new HashMap());
+                context.setImplicitTarget(newCurrent);
+                parse(project, source, new RootHandler(context, mainHandler));
+                newCurrent.execute();
+            } finally {
+                context.setCurrentTarget(currentTarget);
+                context.setImplicitTarget(currentImplicit);
+                context.setCurrentTargets(currentTargets);
+            }
+        } else {
+            // top level file
+            context.setCurrentTargets(new HashMap());
+            parse(project, source, new RootHandler(context, mainHandler));
+            // Execute the top-level target
+            context.getImplicitTarget().execute();
+        }
+    }
+
+    /**
+     * Parses the project file, configuring the project as it goes.
+     *
+     * @param project the current project
+     * @param source  the xml source
+     * @param handler the root handler to use (contains the current context)
+     * @exception BuildException if the configuration is invalid or cannot
+     *                           be read
+     */
+    public void parse(Project project, Object source, RootHandler handler) throws BuildException {
+
+        AntXMLContext context = handler.context;
+
+        File buildFile = null;
+        URL  url = null;
+        String buildFileName = null;
+
+        if (source instanceof File) {
+            buildFile = (File) source;
+            buildFile = FILE_UTILS.normalize(buildFile.getAbsolutePath());
+            context.setBuildFile(buildFile);
+            buildFileName = buildFile.toString();
+//         } else if (source instanceof InputStream ) {
+        } else if (source instanceof URL) {
+            url = (URL) source;
+            buildFileName = url.toString();
+//         } else if (source instanceof InputSource ) {
+        } else {
+            throw new BuildException("Source " + source.getClass().getName()
+                    + " not supported by this plugin");
+        }
+        InputStream inputStream = null;
+        InputSource inputSource = null;
+
+        try {
+            /**
+             * SAX 2 style parser used to parse the given file.
+             */
+            XMLReader parser = JAXPUtils.getNamespaceXMLReader();
+
+            String uri = null;
+            if (buildFile != null) {
+                uri = FILE_UTILS.toURI(buildFile.getAbsolutePath());
+                inputStream = new FileInputStream(buildFile);
+            } else {
+                inputStream = url.openStream();
+                uri = url.toString(); // ?? OK ??
+            }
+
+            inputSource = new InputSource(inputStream);
+            if (uri != null) {
+                inputSource.setSystemId(uri);
+            }
+            project.log("parsing buildfile " + buildFileName + " with URI = " + uri,
+                    Project.MSG_VERBOSE);
+
+            DefaultHandler hb = handler;
+
+            parser.setContentHandler(hb);
+            parser.setEntityResolver(hb);
+            parser.setErrorHandler(hb);
+            parser.setDTDHandler(hb);
+            parser.parse(inputSource);
+        } catch (SAXParseException exc) {
+            Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc
+                    .getColumnNumber());
+
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                BuildException be = (BuildException) t;
+                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+                    be.setLocation(location);
+                }
+                throw be;
+            }
+            throw new BuildException(exc.getMessage(), t == null ? exc : t, location);
+        } catch (SAXException exc) {
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                throw (BuildException) t;
+            }
+            throw new BuildException(exc.getMessage(), t == null ? exc : t);
+        } catch (FileNotFoundException exc) {
+            throw new BuildException(exc);
+        } catch (UnsupportedEncodingException exc) {
+              throw new BuildException("Encoding of project file " + buildFileName + " is invalid.",
+                    exc);
+        } catch (IOException exc) {
+            throw new BuildException("Error reading project file " + buildFileName + ": "
+                    + exc.getMessage(), exc);
+        } finally {
+            FileUtils.close(inputStream);
+        }
+    }
+
+    /**
+     * Returns main handler
+     * @return main handler
+     */
+    protected static AntHandler getMainHandler() {
+        return mainHandler;
+    }
+
+    /**
+     * Sets main handler
+     * @param handler  new main handler
+     */
+    protected static void setMainHandler(AntHandler handler) {
+        mainHandler = handler;
+    }
+
+    /**
+     * Returns project handler
+     * @return project handler
+     */
+    protected static AntHandler getProjectHandler() {
+        return projectHandler;
+    }
+
+    /**
+     * Sets project handler
+     * @param handler  new project handler
+     */
+    protected static void setProjectHandler(AntHandler handler) {
+        projectHandler = handler;
+    }
+
+    /**
+     * Returns target handler
+     * @return target handler
+     */
+    protected static AntHandler getTargetHandler() {
+        return targetHandler;
+    }
+
+    /**
+     * Sets target handler
+     * @param handler  new target handler
+     */
+    protected static void setTargetHandler(AntHandler handler) {
+        targetHandler = handler;
+    }
+
+    /**
+     * Returns element handler
+     * @return element handler
+     */
+    protected static AntHandler getElementHandler() {
+        return elementHandler;
+    }
+
+    /**
+     * Sets element handler
+     * @param handler  new element handler
+     */
+    protected static void setElementHandler(AntHandler handler) {
+        elementHandler = handler;
+    }
+
+    /**
+     * The common superclass for all SAX event handlers used to parse
+     * the configuration file.
+     *
+     * The context will hold all state information. At each time
+     * there is one active handler for the current element. It can
+     * use onStartChild() to set an alternate handler for the child.
+     */
+    public static class AntHandler  {
+        /**
+         * Handles the start of an element. This base implementation does
+         * nothing.
+         *
+         * @param uri the namespace URI for the tag
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name of the element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The context that this element is in.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+        }
+
+        /**
+         * Handles the start of an element. This base implementation just
+         * throws an exception - you must override this method if you expect
+         * child elements.
+         *
+         * @param uri The namespace uri for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return a handler (in the derived classes)
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            throw new SAXParseException("Unexpected element \"" + qname + " \"", context
+                    .getLocator());
+        }
+
+        /**
+         * Handle the end of a element.
+         *
+         * @param uri the namespace uri of the element
+         * @param tag the tag of the element
+         * @param qname the qualified name of the element
+         * @param context the current context
+         * @exception SAXParseException if an error occurs
+         */
+        public void onEndChild(String uri, String tag, String qname, AntXMLContext context)
+                throws SAXParseException {
+        }
+
+        /**
+         * This method is called when this element and all elements nested into it have been
+         * handled. I.e., this happens at the &lt;/end_tag_of_the_element&gt;.
+         * @param uri the namespace uri for this element
+         * @param tag the element name
+         * @param context the current context
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+        }
+
+        /**
+         * Handles text within an element. This base implementation just
+         * throws an exception, you must override it if you expect content.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void characters(char[] buf, int start, int count, AntXMLContext context)
+                throws SAXParseException {
+            String s = new String(buf, start, count).trim();
+
+            if (s.length() > 0) {
+                throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator());
+            }
+        }
+
+        /**
+         * Will be called every time a namespace is reached.
+         * It'll verify if the ns was processed, and if not load the task definitions.
+         * @param uri The namespace uri.
+         */
+        protected void checkNamespace(String uri) {
+        }
+    }
+
+    /**
+     * Handler for ant processing. Uses a stack of AntHandlers to
+     * implement each element ( the original parser used a recursive behavior,
+     * with the implicit execution stack )
+     */
+    public static class RootHandler extends DefaultHandler {
+        private Stack antHandlers = new Stack();
+        private AntHandler currentHandler = null;
+        private AntXMLContext context;
+
+        /**
+         * Creates a new RootHandler instance.
+         *
+         * @param context The context for the handler.
+         * @param rootHandler The handler for the root element.
+         */
+        public RootHandler(AntXMLContext context, AntHandler rootHandler) {
+            currentHandler = rootHandler;
+            antHandlers.push(currentHandler);
+            this.context = context;
+        }
+
+        /**
+         * Returns the current ant handler object.
+         * @return the current ant handler.
+         */
+        public AntHandler getCurrentAntHandler() {
+            return currentHandler;
+        }
+
+        /**
+         * Resolves file: URIs relative to the build file.
+         *
+         * @param publicId The public identifier, or <code>null</code>
+         *                 if none is available. Ignored in this
+         *                 implementation.
+         * @param systemId The system identifier provided in the XML
+         *                 document. Will not be <code>null</code>.
+         * @return an inputsource for this identifier
+         */
+        public InputSource resolveEntity(String publicId, String systemId) {
+
+            context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
+
+            if (systemId.startsWith("file:")) {
+                String path = FILE_UTILS.fromURI(systemId);
+
+                File file = new File(path);
+                if (!file.isAbsolute()) {
+                    file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path);
+                    context.getProject().log(
+                            "Warning: '" + systemId + "' in " + context.getBuildFile()
+                                    + " should be expressed simply as '" + path.replace('\\', '/')
+                                    + "' for compliance with other XML tools", Project.MSG_WARN);
+                }
+                context.getProject().log("file=" + file, Project.MSG_DEBUG);
+                try {
+                    InputSource inputSource = new InputSource(new FileInputStream(file));
+                    inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
+                    return inputSource;
+                } catch (FileNotFoundException fne) {
+                    context.getProject().log(file.getAbsolutePath() + " could not be found",
+                            Project.MSG_WARN);
+                }
+
+            }
+            // use default if not file or file not found
+            context.getProject().log("could not resolve systemId", Project.MSG_DEBUG);
+            return null;
+        }
+
+        /**
+         * Handles the start of a project element. A project handler is created
+         * and initialised with the element name and attributes.
+         *
+         * @param uri The namespace uri for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception org.xml.sax.SAXParseException if the tag given is not
+         *                              <code>"project"</code>
+         */
+        public void startElement(String uri, String tag, String qname, Attributes attrs)
+                throws SAXParseException {
+            AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context);
+            antHandlers.push(currentHandler);
+            currentHandler = next;
+            currentHandler.onStartElement(uri, tag, qname, attrs, context);
+        }
+
+        /**
+         * Sets the locator in the project helper for future reference.
+         *
+         * @param locator The locator used by the parser.
+         *                Will not be <code>null</code>.
+         */
+        public void setDocumentLocator(Locator locator) {
+            context.setLocator(locator);
+        }
+
+        /**
+         * Handles the end of an element. Any required clean-up is performed
+         * by the onEndElement() method and then the original handler is restored to the parser.
+         *
+         * @param uri  The namespace URI for this element.
+         * @param name The name of the element which is ending.
+         *             Will not be <code>null</code>.
+         * @param qName The qualified name for this element.
+         *
+         * @exception SAXException in case of error (not thrown in this implementation)
+         */
+        public void endElement(String uri, String name, String qName) throws SAXException {
+            currentHandler.onEndElement(uri, name, context);
+            AntHandler prev = (AntHandler) antHandlers.pop();
+            currentHandler = prev;
+            if (currentHandler != null) {
+                currentHandler.onEndChild(uri, name, qName, context);
+            }
+        }
+
+        /**
+         * Handle text within an element, calls currentHandler.characters.
+         *
+         * @param buf  A character array of the test.
+         * @param start The start offset in the array.
+         * @param count The number of characters to read.
+         * @exception SAXParseException if an error occurs
+         */
+        public void characters(char[] buf, int start, int count) throws SAXParseException {
+            currentHandler.characters(buf, start, count, context);
+        }
+
+        /**
+         * Start a namespace prefix to uri mapping
+         *
+         * @param prefix the namespace prefix
+         * @param uri the namespace uri
+         */
+        public void startPrefixMapping(String prefix, String uri) {
+            context.startPrefixMapping(prefix, uri);
+        }
+
+        /**
+         * End a namepace prefix to uri mapping
+         *
+         * @param prefix the prefix that is not mapped anymore
+         */
+        public void endPrefixMapping(String prefix) {
+            context.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * The main handler - it handles the &lt;project&gt; tag.
+     *
+     * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
+     */
+    public static class MainHandler extends AntHandler {
+
+        /**
+         * Handle the project tag
+         *
+         * @param uri The namespace uri.
+         * @param name The element tag.
+         * @param qname The element qualified name.
+         * @param attrs The attributes of the element.
+         * @param context The current context.
+         * @return The project handler that handles subelements of project
+         * @exception SAXParseException if the qualified name is not "project".
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            if (name.equals("project")
+                && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
+                return ProjectHelper2.projectHandler;
+            }
+//            if (context.importlevel > 0) {
+//                // we are in an imported file. Allow top-level <target>.
+//                if (qname.equals( "target" ) )
+//                    return ProjectHelper2.targetHandler;
+//            }
+            if (name.equals(qname)) {
+                throw new SAXParseException("Unexpected element \"{" + uri
+                    + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator());
+            }
+            throw new SAXParseException("Unexpected element \"" + qname
+                    + "\" " + name, context.getLocator());
+        }
+    }
+
+    /**
+     * Handler for the top level "project" element.
+     */
+    public static class ProjectHandler extends AntHandler {
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"default"</code>,
+         * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if an unexpected attribute is
+         *            encountered or if the <code>"default"</code> attribute
+         *            is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            String baseDir = null;
+            boolean nameAttributeSet = false;
+
+            Project project = context.getProject();
+            // Set the location of the implicit target associated with the project tag
+            context.getImplicitTarget().setLocation(new Location(context.getLocator()));
+
+            /** XXX I really don't like this - the XML processor is still
+             * too 'involved' in the processing. A better solution (IMO)
+             * would be to create UE for Project and Target too, and
+             * then process the tree and have Project/Target deal with
+             * its attributes ( similar with Description ).
+             *
+             * If we eventually switch to ( or add support for ) DOM,
+             * things will work smoothly - UE can be avoided almost completely
+             * ( it could still be created on demand, for backward compatibility )
+             */
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    continue; // Ignore attributes from unknown uris
+                }
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("default")) {
+                    if (value != null && !value.equals("")) {
+                        if (!context.isIgnoringProjectTag()) {
+                            project.setDefault(value);
+                        }
+                    }
+                } else if (key.equals("name")) {
+                    if (value != null) {
+                        context.setCurrentProjectName(value);
+                        nameAttributeSet = true;
+                        if (!context.isIgnoringProjectTag()) {
+                            project.setName(value);
+                            project.addReference(value, project);
+                        }
+                    }
+                } else if (key.equals("id")) {
+                    if (value != null) {
+                        // What's the difference between id and name ?
+                        if (!context.isIgnoringProjectTag()) {
+                            project.addReference(value, project);
+                        }
+                    }
+                } else if (key.equals("basedir")) {
+                    if (!context.isIgnoringProjectTag()) {
+                        baseDir = value;
+                    }
+                } else {
+                    // XXX ignore attributes in a different NS ( maybe store them ? )
+                    throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i)
+                            + "\"", context.getLocator());
+                }
+            }
+
+            // XXX Move to Project ( so it is shared by all helpers )
+            String antFileProp = "ant.file." + context.getCurrentProjectName();
+            String dup = project.getProperty(antFileProp);
+            if (dup != null && nameAttributeSet) {
+                File dupFile = new File(dup);
+                if (context.isIgnoringProjectTag() && !dupFile.equals(context.getBuildFile())) {
+                    project.log("Duplicated project name in import. Project "
+                            + context.getCurrentProjectName() + " defined first in " + dup
+                            + " and again in " + context.getBuildFile(), Project.MSG_WARN);
+                }
+            }
+            if (context.getBuildFile() != null && nameAttributeSet) {
+                project.setUserProperty(
+                        MagicNames.ANT_FILE + "." + context.getCurrentProjectName(), context
+                                .getBuildFile().toString());
+            }
+            if (context.isIgnoringProjectTag()) {
+                // no further processing
+                return;
+            }
+            // set explicitly before starting ?
+            if (project.getProperty("basedir") != null) {
+                project.setBasedir(project.getProperty("basedir"));
+            } else {
+                // Default for baseDir is the location of the build file.
+                if (baseDir == null) {
+                    project.setBasedir(context.getBuildFileParent().getAbsolutePath());
+                } else {
+                    // check whether the user has specified an absolute path
+                    if ((new File(baseDir)).isAbsolute()) {
+                        project.setBasedir(baseDir);
+                    } else {
+                        project.setBaseDir(FILE_UTILS.resolveFile(context.getBuildFileParent(),
+                                baseDir));
+                    }
+                }
+            }
+            project.addTarget("", context.getImplicitTarget());
+            context.setCurrentTarget(context.getImplicitTarget());
+        }
+
+        /**
+         * Handles the start of a top-level element within the project. An
+         * appropriate handler is created and initialised with the details
+         * of the element.
+         *
+         * @param uri The namespace URI for this element.
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The context for this element.
+         * @return a target or an element handler.
+         *
+         * @exception org.xml.sax.SAXParseException if the tag given is not
+         *            <code>"taskdef"</code>, <code>"typedef"</code>,
+         *            <code>"property"</code>, <code>"target"</code>
+         *            or a data type definition
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
+                    ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
+        }
+    }
+
+    /**
+     * Handler for "target" elements.
+     */
+    public static class TargetHandler extends AntHandler {
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"name"</code>,
+         * <code>"depends"</code>, <code>"if"</code>,
+         * <code>"unless"</code>, <code>"id"</code> and
+         * <code>"description"</code>.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if an unexpected attribute is encountered
+         *            or if the <code>"name"</code> attribute is missing.
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            String name = null;
+            String depends = "";
+
+            Project project = context.getProject();
+            Target target = new Target();
+            target.setProject(project);
+            target.setLocation(new Location(context.getLocator()));
+            context.addTarget(target);
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    continue; // Ignore attributes from unknown uris
+                }
+                String key = attrs.getLocalName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                    if ("".equals(name)) {
+                        throw new BuildException("name attribute must " + "not be empty");
+                    }
+                } else if (key.equals("depends")) {
+                    depends = value;
+                } else if (key.equals("if")) {
+                    target.setIf(value);
+                } else if (key.equals("unless")) {
+                    target.setUnless(value);
+                } else if (key.equals("id")) {
+                    if (value != null && !value.equals("")) {
+                        context.getProject().addReference(value, target);
+                    }
+                } else if (key.equals("description")) {
+                    target.setDescription(value);
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
+                            .getLocator());
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("target element appears without a name attribute",
+                        context.getLocator());
+            }
+
+            // Check if this target is in the current build file
+            if (context.getCurrentTargets().get(name) != null) {
+                throw new BuildException("Duplicate target '" + name + "'", target.getLocation());
+            }
+            Hashtable projectTargets = project.getTargets();
+            boolean   usedTarget = false;
+            // If the name has not already been defined define it
+            if (projectTargets.containsKey(name)) {
+                project.log("Already defined in main or a previous import, ignore " + name,
+                        Project.MSG_VERBOSE);
+            } else {
+                target.setName(name);
+                context.getCurrentTargets().put(name, target);
+                project.addOrReplaceTarget(name, target);
+                usedTarget = true;
+            }
+            if (depends.length() > 0) {
+                target.setDepends(depends);
+            }
+            if (context.isIgnoringProjectTag() && context.getCurrentProjectName() != null
+                    && context.getCurrentProjectName().length() != 0) {
+                // In an impored file (and not completely
+                // ignoring the project tag)
+                String newName = context.getCurrentProjectName() + "." + name;
+                Target newTarget = usedTarget ? new Target(target) : target;
+                newTarget.setName(newName);
+                context.getCurrentTargets().put(newName, newTarget);
+                project.addOrReplaceTarget(newName, newTarget);
+            }
+        }
+
+        /**
+         * Handles the start of an element within a target.
+         *
+         * @param uri The namespace URI for this element.
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return an element handler.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return ProjectHelper2.elementHandler;
+        }
+
+        /**
+         * Handle the end of the project, sets the current target of the
+         * context to be the implicit target.
+         *
+         * @param uri The namespace URI of the element.
+         * @param tag The name of the element.
+         * @param context The current context.
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+            context.setCurrentTarget(context.getImplicitTarget());
+        }
+    }
+
+    /**
+     * Handler for all project elements ( tasks, data types )
+     */
+    public static class ElementHandler extends AntHandler {
+
+        /**
+         * Constructor.
+         */
+        public ElementHandler() {
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         * @param context The current context.
+         *
+         * @exception SAXParseException in case of error (not thrown in
+         *                              this implementation)
+         */
+        public void onStartElement(String uri, String tag, String qname, Attributes attrs,
+                                   AntXMLContext context) throws SAXParseException {
+            RuntimeConfigurable parentWrapper = context.currentWrapper();
+            Object parent = null;
+
+            if (parentWrapper != null) {
+                parent = parentWrapper.getProxy();
+            }
+
+            /* UnknownElement is used for tasks and data types - with
+               delayed eval */
+            UnknownElement task = new UnknownElement(tag);
+            task.setProject(context.getProject());
+            task.setNamespace(uri);
+            task.setQName(qname);
+            task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag));
+            task.setTaskName(qname);
+
+            Location location = new Location(context.getLocator().getSystemId(), context
+                    .getLocator().getLineNumber(), context.getLocator().getColumnNumber());
+            task.setLocation(location);
+            task.setOwningTarget(context.getCurrentTarget());
+
+            if (parent != null) {
+                // Nested element
+                ((UnknownElement) parent).addChild(task);
+            }  else {
+                // Task included in a target ( including the default one ).
+                context.getCurrentTarget().addTask(task);
+            }
+
+            context.configureId(task, attrs);
+
+            // container.addTask(task);
+            // This is a nop in UE: task.init();
+
+            RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName());
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String name = attrs.getLocalName(i);
+                String attrUri = attrs.getURI(i);
+                if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
+                    name = attrUri + ":" + attrs.getQName(i);
+                }
+                String value = attrs.getValue(i);
+                // PR: Hack for ant-type value
+                //  an ant-type is a component name which can
+                // be namespaced, need to extract the name
+                // and convert from qualified name to uri/name
+                if (ANT_TYPE.equals(name)
+                        || (ANT_CORE_URI.equals(attrUri)
+                            && ANT_TYPE.equals(attrs.getLocalName(i)))) {
+                    name = ANT_TYPE;
+                    int index = value.indexOf(":");
+                    if (index >= 0) {
+                        String prefix = value.substring(0, index);
+                        String mappedUri = context.getPrefixMapping(prefix);
+                        if (mappedUri == null) {
+                            throw new BuildException("Unable to find XML NS prefix \"" + prefix
+                                    + "\"");
+                        }
+                        value = ProjectHelper.genComponentName(mappedUri, value
+                                .substring(index + 1));
+                    }
+                }
+                wrapper.setAttribute(name, value);
+            }
+            if (parentWrapper != null) {
+                parentWrapper.addChild(wrapper);
+            }
+            context.pushWrapper(wrapper);
+        }
+
+        /**
+         * Adds text to the task, using the wrapper
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         * @param context The current context.
+         *
+         * @exception SAXParseException if the element doesn't support text
+         *
+         * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
+         */
+        public void characters(char[] buf, int start, int count,
+                               AntXMLContext context) throws SAXParseException {
+            RuntimeConfigurable wrapper = context.currentWrapper();
+            wrapper.addText(buf, start, count);
+        }
+
+        /**
+         * Handles the start of an element within a target. Task containers
+         * will always use another task handler, and all other tasks
+         * will always use a nested element handler.
+         *
+         * @param uri The namespace URI for this element.
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param qname The qualified name for this element.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         * @param context The current context.
+         * @return The handler for elements.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
+                                       AntXMLContext context) throws SAXParseException {
+            return ProjectHelper2.elementHandler;
+        }
+
+        /**
+         * Handles the end of the element. This pops the wrapper from
+         * the context.
+         *
+         * @param uri The namespace URI for the element.
+         * @param tag The name of the element.
+         * @param context The current context.
+         */
+        public void onEndElement(String uri, String tag, AntXMLContext context) {
+            context.popWrapper();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java b/trunk/src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java
new file mode 100644
index 0000000..c72f08e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java
@@ -0,0 +1,1025 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.helper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Locale;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TypeAdapter;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.AttributeList;
+import org.xml.sax.DocumentHandler;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.XMLReaderAdapter;
+
+/**
+ * Original helper.
+ *
+ */
+public class ProjectHelperImpl extends ProjectHelper {
+
+    /**
+     * helper for path -> URI and URI -> path conversions.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * SAX 1 style parser used to parse the given file. This may
+     * in fact be a SAX 2 XMLReader wrapped in an XMLReaderAdapter.
+     */
+    private org.xml.sax.Parser parser;
+
+    /** The project to configure. */
+    private Project project;
+
+    /** The configuration file to parse. */
+    private File buildFile;
+
+    /**
+     * Parent directory of the build file. Used for resolving entities
+     * and setting the project's base directory.
+     */
+    private File buildFileParent;
+
+    /**
+     * Locator for the configuration file parser.
+     * Used for giving locations of errors etc.
+     */
+    private Locator locator;
+
+    /**
+     * Target that all other targets will depend upon implicitly.
+     *
+     * <p>This holds all tasks and data type definitions that have
+     * been placed outside of targets.</p>
+     */
+    private Target implicitTarget = new Target();
+
+    /**
+     * default constructor
+     */
+    public ProjectHelperImpl() {
+        implicitTarget.setName("");
+    }
+
+    /**
+     * Parses the project file, configuring the project as it goes.
+     *
+     * @param project project instance to be configured.
+     * @param source the source from which the project is read.
+     * @exception BuildException if the configuration is invalid or cannot
+     *                           be read.
+     */
+    public void parse(Project project, Object source) throws BuildException {
+        if (!(source instanceof File)) {
+            throw new BuildException("Only File source supported by "
+                + "default plugin");
+        }
+        File bFile = (File) source;
+        FileInputStream inputStream = null;
+        InputSource inputSource = null;
+
+        this.project = project;
+        this.buildFile = new File(bFile.getAbsolutePath());
+        buildFileParent = new File(this.buildFile.getParent());
+
+        try {
+            try {
+                parser = JAXPUtils.getParser();
+            } catch (BuildException e) {
+                parser = new XMLReaderAdapter(JAXPUtils.getXMLReader());
+            }
+            String uri = FILE_UTILS.toURI(bFile.getAbsolutePath());
+            inputStream = new FileInputStream(bFile);
+            inputSource = new InputSource(inputStream);
+            inputSource.setSystemId(uri);
+            project.log("parsing buildfile " + bFile + " with URI = " + uri, Project.MSG_VERBOSE);
+            HandlerBase hb = new RootHandler(this);
+            parser.setDocumentHandler(hb);
+            parser.setEntityResolver(hb);
+            parser.setErrorHandler(hb);
+            parser.setDTDHandler(hb);
+            parser.parse(inputSource);
+        } catch (SAXParseException exc) {
+            Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc
+                    .getColumnNumber());
+
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                BuildException be = (BuildException) t;
+                if (be.getLocation() == Location.UNKNOWN_LOCATION) {
+                    be.setLocation(location);
+                }
+                throw be;
+            }
+            throw new BuildException(exc.getMessage(), t, location);
+        } catch (SAXException exc) {
+            Throwable t = exc.getException();
+            if (t instanceof BuildException) {
+                throw (BuildException) t;
+            }
+            throw new BuildException(exc.getMessage(), t);
+        } catch (FileNotFoundException exc) {
+            throw new BuildException(exc);
+        } catch (UnsupportedEncodingException exc) {
+            throw new BuildException("Encoding of project file is invalid.", exc);
+        } catch (IOException exc) {
+            throw new BuildException("Error reading project file: " + exc.getMessage(), exc);
+        } finally {
+            FileUtils.close(inputStream);
+        }
+    }
+
+    /**
+     * The common superclass for all SAX event handlers used to parse
+     * the configuration file. Each method just throws an exception,
+     * so subclasses should override what they can handle.
+     *
+     * Each type of XML element (task, target, etc.) in Ant has
+     * a specific subclass.
+     *
+     * In the constructor, this class takes over the handling of SAX
+     * events from the parent handler and returns
+     * control back to the parent in the endElement method.
+     */
+    static class AbstractHandler extends HandlerBase {
+        // CheckStyle:VisibilityModifier OFF - bc
+
+        /**
+         * Previous handler for the document.
+         * When the next element is finished, control returns
+         * to this handler.
+         */
+        protected DocumentHandler parentHandler;
+
+        /** Helper impl. With non-static internal classes, the compiler will generate
+            this automatically - but this will fail with some compilers ( reporting
+            "Expecting to find object/array on stack" ). If we pass it
+            explicitly it'll work with more compilers.
+        */
+        ProjectHelperImpl helperImpl;
+        // CheckStyle:VisibilityModifier ON
+
+        /**
+         * Creates a handler and sets the parser to use it
+         * for the current element.
+         *
+         * @param helperImpl the ProjectHelperImpl instance associated
+         *                   with this handler.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         */
+        public AbstractHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
+            this.parentHandler = parentHandler;
+            this.helperImpl = helperImpl;
+
+            // Start handling SAX events
+            helperImpl.parser.setDocumentHandler(this);
+        }
+
+        /**
+         * Handles the start of an element. This base implementation just
+         * throws an exception.
+         *
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void startElement(String tag, AttributeList attrs) throws SAXParseException {
+            throw new SAXParseException("Unexpected element \"" + tag + "\"", helperImpl.locator);
+        }
+
+        /**
+         * Handles text within an element. This base implementation just
+         * throws an exception.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         *
+         * @exception SAXParseException if this method is not overridden, or in
+         *                              case of error in an overridden version
+         */
+        public void characters(char[] buf, int start, int count) throws SAXParseException {
+            String s = new String(buf, start, count).trim();
+
+            if (s.length() > 0) {
+                throw new SAXParseException("Unexpected text \"" + s + "\"", helperImpl.locator);
+            }
+        }
+
+        /**
+         * Handles the end of an element. Any required clean-up is performed
+         * by the finished() method and then the original handler is restored to
+         * the parser.
+         *
+         * @param name The name of the element which is ending.
+         *             Will not be <code>null</code>.
+         *
+         * @exception SAXException in case of error (not thrown in
+         *                         this implementation)
+         */
+        public void endElement(String name) throws SAXException {
+            // Let parent resume handling SAX events
+            helperImpl.parser.setDocumentHandler(parentHandler);
+        }
+    }
+
+    /**
+     * Handler for the root element. Its only child must be the "project" element.
+     */
+    static class RootHandler extends HandlerBase {
+        // CheckStyle:VisibilityModifier OFF - bc
+        ProjectHelperImpl helperImpl;
+        // CheckStyle:VisibilityModifier ON
+
+        public RootHandler(ProjectHelperImpl helperImpl) {
+            this.helperImpl = helperImpl;
+        }
+
+        /**
+         * Resolves file: URIs relative to the build file.
+         *
+         * @param publicId The public identifier, or <code>null</code>
+         *                 if none is available. Ignored in this
+         *                 implementation.
+         * @param systemId The system identifier provided in the XML
+         *                 document. Will not be <code>null</code>.
+         */
+        public InputSource resolveEntity(String publicId, String systemId) {
+
+            helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
+
+            if (systemId.startsWith("file:")) {
+                String path = FILE_UTILS.fromURI(systemId);
+
+                File file = new File(path);
+                if (!file.isAbsolute()) {
+                    file = FILE_UTILS.resolveFile(helperImpl.buildFileParent, path);
+                    helperImpl.project.log("Warning: '" + systemId + "' in " + helperImpl.buildFile
+                            + " should be expressed simply as '" + path.replace('\\', '/')
+                            + "' for compliance with other XML tools", Project.MSG_WARN);
+                }
+                try {
+                    InputSource inputSource = new InputSource(new FileInputStream(file));
+                    inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
+                    return inputSource;
+                } catch (FileNotFoundException fne) {
+                    helperImpl.project.log(file.getAbsolutePath() + " could not be found",
+                            Project.MSG_WARN);
+                }
+            }
+            // use default if not file or file not found
+            return null;
+        }
+
+        /**
+         * Handles the start of a project element. A project handler is created
+         * and initialised with the element name and attributes.
+         *
+         * @param tag The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if the tag given is not
+         *                              <code>"project"</code>
+         */
+        public void startElement(String tag, AttributeList attrs) throws SAXParseException {
+            if (tag.equals("project")) {
+                new ProjectHandler(helperImpl, this).init(tag, attrs);
+            } else {
+                throw new SAXParseException("Config file is not of expected " + "XML type",
+                        helperImpl.locator);
+            }
+        }
+
+        /**
+         * Sets the locator in the project helper for future reference.
+         *
+         * @param locator The locator used by the parser.
+         *                Will not be <code>null</code>.
+         */
+        public void setDocumentLocator(Locator locator) {
+            helperImpl.locator = locator;
+        }
+    }
+
+    /**
+     * Handler for the top level "project" element.
+     */
+    static class ProjectHandler extends AbstractHandler {
+
+        /**
+         * Constructor which just delegates to the superconstructor.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         */
+        public ProjectHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
+            super(helperImpl, parentHandler);
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"default"</code>,
+         * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
+         *
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         *
+         * @exception SAXParseException if an unexpected attribute is
+         *            encountered or if the <code>"default"</code> attribute
+         *            is missing.
+         */
+        public void init(String tag, AttributeList attrs) throws SAXParseException {
+            String def = null;
+            String name = null;
+            String id = null;
+            String baseDir = null;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("default")) {
+                    def = value;
+                } else if (key.equals("name")) {
+                    name = value;
+                } else if (key.equals("id")) {
+                    id = value;
+                } else if (key.equals("basedir")) {
+                    baseDir = value;
+                } else {
+                    throw new SAXParseException(
+                            "Unexpected attribute \"" + attrs.getName(i)
+                            + "\"", helperImpl.locator);
+                }
+            }
+
+            if (def != null && !def.equals("")) {
+                helperImpl.project.setDefaultTarget(def);
+            } else {
+                throw new BuildException("The default attribute is required");
+            }
+
+            if (name != null) {
+                helperImpl.project.setName(name);
+                helperImpl.project.addReference(name, helperImpl.project);
+            }
+
+            if (id != null) {
+                helperImpl.project.addReference(id, helperImpl.project);
+            }
+
+            if (helperImpl.project.getProperty("basedir") != null) {
+                helperImpl.project.setBasedir(helperImpl.project.getProperty("basedir"));
+            } else {
+                if (baseDir == null) {
+                    helperImpl.project.setBasedir(helperImpl.buildFileParent.getAbsolutePath());
+                } else {
+                    // check whether the user has specified an absolute path
+                    if ((new File(baseDir)).isAbsolute()) {
+                        helperImpl.project.setBasedir(baseDir);
+                    } else {
+                        File resolvedBaseDir = FILE_UTILS.resolveFile(helperImpl.buildFileParent,
+                                baseDir);
+                        helperImpl.project.setBaseDir(resolvedBaseDir);
+                    }
+                }
+            }
+
+            helperImpl.project.addTarget("", helperImpl.implicitTarget);
+        }
+
+        /**
+         * Handles the start of a top-level element within the project. An
+         * appropriate handler is created and initialised with the details
+         * of the element.
+         *
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if the tag given is not
+         *            <code>"taskdef"</code>, <code>"typedef"</code>,
+         *            <code>"property"</code>, <code>"target"</code>
+         *            or a data type definition
+         */
+        public void startElement(String name, AttributeList attrs) throws SAXParseException {
+            if (name.equals("target")) {
+                handleTarget(name, attrs);
+            } else {
+                handleElement(helperImpl, this, helperImpl.implicitTarget, name, attrs);
+            }
+        }
+
+        /**
+         * Handles a target definition element by creating a target handler
+         * and initialising is with the details of the element.
+         *
+         * @param tag The name of the element to be handled.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element to be handled.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if an error occurs initialising
+         *                              the handler
+         */
+        private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
+            new TargetHandler(helperImpl, this).init(tag, attrs);
+        }
+    }
+
+    /**
+     * Handler for "target" elements.
+     */
+    static class TargetHandler extends AbstractHandler {
+        private Target target;
+
+        /**
+         * Constructor which just delegates to the superconstructor.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         */
+        public TargetHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
+            super(helperImpl, parentHandler);
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. The attributes which
+         * this handler can deal with are: <code>"name"</code>,
+         * <code>"depends"</code>, <code>"if"</code>,
+         * <code>"unless"</code>, <code>"id"</code> and
+         * <code>"description"</code>.
+         *
+         * @param tag Name of the element which caused this handler
+         *            to be created. Should not be <code>null</code>.
+         *            Ignored in this implementation.
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         *
+         * @exception SAXParseException if an unexpected attribute is encountered
+         *            or if the <code>"name"</code> attribute is missing.
+         */
+        public void init(String tag, AttributeList attrs) throws SAXParseException {
+            String name = null;
+            String depends = "";
+            String ifCond = null;
+            String unlessCond = null;
+            String id = null;
+            String description = null;
+
+            for (int i = 0; i < attrs.getLength(); i++) {
+                String key = attrs.getName(i);
+                String value = attrs.getValue(i);
+
+                if (key.equals("name")) {
+                    name = value;
+                    if (name.equals("")) {
+                        throw new BuildException("name attribute must not" + " be empty",
+                                new Location(helperImpl.locator));
+                    }
+                } else if (key.equals("depends")) {
+                    depends = value;
+                } else if (key.equals("if")) {
+                    ifCond = value;
+                } else if (key.equals("unless")) {
+                    unlessCond = value;
+                } else if (key.equals("id")) {
+                    id = value;
+                } else if (key.equals("description")) {
+                    description = value;
+                } else {
+                    throw new SAXParseException("Unexpected attribute \"" + key + "\"",
+                            helperImpl.locator);
+                }
+            }
+
+            if (name == null) {
+                throw new SAXParseException("target element appears without a name attribute",
+                        helperImpl.locator);
+            }
+
+            target = new Target();
+
+            // implicit target must be first on dependency list
+            target.addDependency("");
+
+            target.setName(name);
+            target.setIf(ifCond);
+            target.setUnless(unlessCond);
+            target.setDescription(description);
+            helperImpl.project.addTarget(name, target);
+
+            if (id != null && !id.equals("")) {
+                helperImpl.project.addReference(id, target);
+            }
+
+            // take care of dependencies
+
+            if (depends.length() > 0) {
+                target.setDepends(depends);
+            }
+        }
+
+        /**
+         * Handles the start of an element within a target.
+         *
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public void startElement(String name, AttributeList attrs) throws SAXParseException {
+            handleElement(helperImpl, this, target, name, attrs);
+        }
+    }
+
+    /**
+     * Start a new DataTypeHandler if element is known to be a
+     * data-type and a TaskHandler otherwise.
+     *
+     * <p>Factored out of TargetHandler.</p>
+     *
+     * @since Ant 1.6
+     */
+    private static void handleElement(ProjectHelperImpl helperImpl, DocumentHandler parent,
+            Target target, String elementName, AttributeList attrs) throws SAXParseException {
+        if (elementName.equals("description")) {
+            new DescriptionHandler(helperImpl, parent);
+        } else if (helperImpl.project.getDataTypeDefinitions().get(elementName) != null) {
+            new DataTypeHandler(helperImpl, parent, target).init(elementName, attrs);
+        } else {
+            new TaskHandler(helperImpl, parent, target, null, target).init(elementName, attrs);
+        }
+    }
+
+    /**
+     * Handler for "description" elements.
+     */
+    static class DescriptionHandler extends AbstractHandler {
+
+        /**
+         * Constructor which just delegates to the superconstructor.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         */
+        public DescriptionHandler(ProjectHelperImpl helperImpl,
+                                  DocumentHandler parentHandler) {
+            super(helperImpl, parentHandler);
+        }
+
+        /**
+         * Adds the text as description to the project.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         */
+        public void characters(char[] buf, int start, int count) {
+            String text = new String(buf, start, count);
+            String currentDescription = helperImpl.project.getDescription();
+            if (currentDescription == null) {
+                helperImpl.project.setDescription(text);
+            } else {
+                helperImpl.project.setDescription(currentDescription + text);
+            }
+        }
+
+    }
+
+    /**
+     * Handler for all task elements.
+     */
+    static class TaskHandler extends AbstractHandler {
+        /** Containing target, if any. */
+        private Target target;
+
+        /**
+         * Container for the task, if any. If target is
+         * non-<code>null</code>, this must be too.
+         */
+        private TaskContainer container;
+
+        /**
+         * Task created by this handler.
+         */
+        private Task task;
+
+        /**
+         * Wrapper for the parent element, if any. The wrapper for this
+         * element will be added to this wrapper as a child.
+         */
+        private RuntimeConfigurable parentWrapper;
+
+        /**
+         * Wrapper for this element which takes care of actually configuring
+         * the element, if this element is contained within a target.
+         * Otherwise the configuration is performed with the configure method.
+         * @see ProjectHelper#configure(Object,AttributeList,Project)
+         */
+        private RuntimeConfigurable wrapper = null;
+
+        /**
+         * Constructor.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         *
+         * @param container     Container for the element.
+         *                      Must not be <code>null</code>.
+         *
+         * @param parentWrapper Wrapper for the parent element, if any.
+         *                      May be <code>null</code>.
+         *
+         * @param target        Target this element is part of.
+         *                      Must not be <code>null</code>.
+         */
+        public TaskHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler,
+                           TaskContainer container,
+                           RuntimeConfigurable parentWrapper, Target target) {
+            super(helperImpl, parentHandler);
+            this.container = container;
+            this.parentWrapper = parentWrapper;
+            this.target = target;
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         *
+         * @param tag Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         *
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         *
+         * @exception SAXParseException in case of error (not thrown in
+         *                              this implementation)
+         */
+        public void init(String tag, AttributeList attrs) throws SAXParseException {
+            try {
+                task = helperImpl.project.createTask(tag);
+            } catch (BuildException e) {
+                // swallow here, will be thrown again in
+                // UnknownElement.maybeConfigure if the problem persists.
+            }
+            if (task == null) {
+                task = new UnknownElement(tag);
+                task.setProject(helperImpl.project);
+                //XXX task.setTaskType(tag);
+                task.setTaskName(tag);
+            }
+            task.setLocation(new Location(helperImpl.locator));
+            helperImpl.configureId(task, attrs);
+
+            task.setOwningTarget(target);
+            container.addTask(task);
+            task.init();
+            wrapper = task.getRuntimeConfigurableWrapper();
+            wrapper.setAttributes(attrs);
+            if (parentWrapper != null) {
+                parentWrapper.addChild(wrapper);
+            }
+        }
+
+        /**
+         * Adds text to the task, using the wrapper.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         */
+        public void characters(char[] buf, int start, int count) {
+            wrapper.addText(buf, start, count);
+        }
+
+        /**
+         * Handles the start of an element within a target. Task containers
+         * will always use another task handler, and all other tasks
+         * will always use a nested element handler.
+         *
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public void startElement(String name, AttributeList attrs) throws SAXParseException {
+            if (task instanceof TaskContainer) {
+                // task can contain other tasks - no other nested elements possible
+                new TaskHandler(helperImpl, this, (TaskContainer) task, wrapper, target).init(name,
+                        attrs);
+            } else {
+                new NestedElementHandler(helperImpl, this, task, wrapper, target).init(name, attrs);
+            }
+        }
+    }
+
+    /**
+     * Handler for all nested properties.
+     */
+    static class NestedElementHandler extends AbstractHandler {
+        /** Parent object (task/data type/etc). */
+        private Object parent;
+
+        /** The nested element itself. */
+        private Object child;
+
+        /**
+         * Wrapper for the parent element, if any. The wrapper for this
+         * element will be added to this wrapper as a child.
+         */
+        private RuntimeConfigurable parentWrapper;
+
+        /**
+         * Wrapper for this element which takes care of actually configuring
+         * the element, if a parent wrapper is provided.
+         * Otherwise the configuration is performed with the configure method.
+         * @see ProjectHelper#configure(Object,AttributeList,Project)
+         */
+        private RuntimeConfigurable childWrapper = null;
+
+        /** Target this element is part of, if any. */
+        private Target target;
+
+        /**
+         * Constructor.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         *
+         * @param parent        Parent of this element (task/data type/etc).
+         *                      Must not be <code>null</code>.
+         *
+         * @param parentWrapper Wrapper for the parent element, if any.
+         *                      Must not be <code>null</code>.
+         *
+         * @param target        Target this element is part of.
+         *                      Must not be <code>null</code>.
+         */
+        public NestedElementHandler(ProjectHelperImpl helperImpl,
+                                    DocumentHandler parentHandler,
+                                    Object parent,
+                                    RuntimeConfigurable parentWrapper,
+                                    Target target) {
+            super(helperImpl, parentHandler);
+
+            if (parent instanceof TypeAdapter) {
+                this.parent = ((TypeAdapter) parent).getProxy();
+            } else {
+                this.parent = parent;
+            }
+            this.parentWrapper = parentWrapper;
+            this.target = target;
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         *
+         * @param propType Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         *
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         *
+         * @exception SAXParseException in case of error, such as a
+         *            BuildException being thrown during configuration.
+         */
+        public void init(String propType, AttributeList attrs) throws SAXParseException {
+            Class parentClass = parent.getClass();
+            IntrospectionHelper ih = IntrospectionHelper.getHelper(helperImpl.project, parentClass);
+
+            try {
+                String elementName = propType.toLowerCase(Locale.US);
+                if (parent instanceof UnknownElement) {
+                    UnknownElement uc = new UnknownElement(elementName);
+                    uc.setProject(helperImpl.project);
+                    ((UnknownElement) parent).addChild(uc);
+                    child = uc;
+                } else {
+                    child = ih.createElement(helperImpl.project, parent, elementName);
+                }
+                helperImpl.configureId(child, attrs);
+
+                childWrapper = new RuntimeConfigurable(child, propType);
+                childWrapper.setAttributes(attrs);
+                parentWrapper.addChild(childWrapper);
+            } catch (BuildException exc) {
+                throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
+            }
+        }
+
+        /**
+         * Adds text to the element, using the wrapper.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         */
+        public void characters(char[] buf, int start, int count) {
+            childWrapper.addText(buf, start, count);
+        }
+
+        /**
+         * Handles the start of an element within this one. Task containers
+         * will always use a task handler, and all other elements
+         * will always use another nested element handler.
+         *
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the appropriate child handler
+         */
+        public void startElement(String name, AttributeList attrs) throws SAXParseException {
+            if (child instanceof TaskContainer) {
+                // taskcontainer nested element can contain other tasks - no other
+                // nested elements possible
+                new TaskHandler(helperImpl, this, (TaskContainer) child, childWrapper, target)
+                        .init(name, attrs);
+            } else {
+                new NestedElementHandler(helperImpl, this, child, childWrapper, target).init(name,
+                        attrs);
+            }
+        }
+    }
+
+    /**
+     * Handler for all data types directly subordinate to project or target.
+     */
+    static class DataTypeHandler extends AbstractHandler {
+        /** Parent target, if any. */
+        private Target target;
+
+        /** The element being configured. */
+        private Object element;
+
+        /** Wrapper for this element, if it's part of a target. */
+        private RuntimeConfigurable wrapper = null;
+
+        /**
+         * Constructor with a target specified.
+         *
+         * @param parentHandler The handler which should be restored to the
+         *                      parser at the end of the element.
+         *                      Must not be <code>null</code>.
+         *
+         * @param target The parent target of this element.
+         *               Must not be <code>null</code>.
+         */
+        public DataTypeHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler,
+                Target target) {
+            super(helperImpl, parentHandler);
+            this.target = target;
+        }
+
+        /**
+         * Initialisation routine called after handler creation
+         * with the element name and attributes. This configures
+         * the element with its attributes and sets it up with
+         * its parent container (if any). Nested elements are then
+         * added later as the parser encounters them.
+         *
+         * @param propType Name of the element which caused this handler
+         *            to be created. Must not be <code>null</code>.
+         *
+         * @param attrs Attributes of the element which caused this
+         *              handler to be created. Must not be <code>null</code>.
+         *
+         * @exception SAXParseException in case of error, such as a
+         *            BuildException being thrown during configuration.
+         */
+        public void init(String propType, AttributeList attrs) throws SAXParseException {
+            try {
+                element = helperImpl.project.createDataType(propType);
+                if (element == null) {
+                    throw new BuildException("Unknown data type " + propType);
+                }
+                wrapper = new RuntimeConfigurable(element, propType);
+                wrapper.setAttributes(attrs);
+                target.addDataType(wrapper);
+            } catch (BuildException exc) {
+                throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
+            }
+        }
+
+        /**
+         * Adds text to the using the wrapper.
+         *
+         * @param buf A character array of the text within the element.
+         *            Will not be <code>null</code>.
+         * @param start The start element in the array.
+         * @param count The number of characters to read from the array.
+         *
+         * @see ProjectHelper#addText(Project,Object,char[],int,int)
+         */
+        public void characters(char[] buf, int start, int count) {
+            wrapper.addText(buf, start, count);
+        }
+
+        /**
+         * Handles the start of an element within this one.
+         * This will always use a nested element handler.
+         *
+         * @param name The name of the element being started.
+         *            Will not be <code>null</code>.
+         * @param attrs Attributes of the element being started.
+         *              Will not be <code>null</code>.
+         *
+         * @exception SAXParseException if an error occurs when initialising
+         *                              the child handler
+         */
+        public void startElement(String name, AttributeList attrs) throws SAXParseException {
+            new NestedElementHandler(helperImpl, this, element, wrapper, target).init(name, attrs);
+        }
+    }
+
+    /**
+     * Scans an attribute list for the <code>id</code> attribute and
+     * stores a reference to the target object in the project if an
+     * id is found.
+     * <p>
+     * This method was moved out of the configure method to allow
+     * it to be executed at parse time.
+     *
+     * @see #configure(Object,AttributeList,Project)
+     */
+    private void configureId(Object target, AttributeList attr) {
+        String id = attr.getValue("id");
+        if (id != null) {
+            project.addReference(id, target);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/helper/SingleCheckExecutor.java b/trunk/src/main/org/apache/tools/ant/helper/SingleCheckExecutor.java
new file mode 100755
index 0000000..44c9503
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/helper/SingleCheckExecutor.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.helper;
+
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Executor;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * "Single-check" Target executor implementation.
+ * Differs from {@link DefaultExecutor} in that the dependencies for all
+ * targets are computed together, so that shared dependencies are run just once.
+ * @since Ant 1.6.3
+ */
+public class SingleCheckExecutor implements Executor {
+
+    /** {@inheritDoc}. */
+    public void executeTargets(Project project, String[] targetNames)
+        throws BuildException {
+            project.executeSortedTargets(
+                project.topoSort(targetNames, project.getTargets(), false));
+    }
+
+    /** {@inheritDoc}. */
+    public Executor getSubProjectExecutor() {
+        return this;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/DefaultInputHandler.java b/trunk/src/main/org/apache/tools/ant/input/DefaultInputHandler.java
new file mode 100644
index 0000000..3bbee97
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/DefaultInputHandler.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Prompts on System.err, reads input from System.in
+ *
+ * @since Ant 1.5
+ */
+public class DefaultInputHandler implements InputHandler {
+
+    /**
+     * Empty no-arg constructor
+     */
+    public DefaultInputHandler() {
+    }
+
+    /**
+     * Prompts and requests input.  May loop until a valid input has
+     * been entered.
+     * @param request the request to handle
+     * @throws BuildException if not possible to read from console
+     */
+    public void handleInput(InputRequest request) throws BuildException {
+        String prompt = getPrompt(request);
+        BufferedReader r = null;
+        try {
+            r = new BufferedReader(new InputStreamReader(getInputStream()));
+            do {
+                System.err.println(prompt);
+                System.err.flush();
+                try {
+                    String input = r.readLine();
+                    request.setInput(input);
+                } catch (IOException e) {
+                    throw new BuildException("Failed to read input from"
+                                             + " Console.", e);
+                }
+            } while (!request.isInputValid());
+        } finally {
+            if (r != null) {
+                try {
+                    r.close();
+                } catch (IOException e) {
+                    throw new BuildException("Failed to close input.", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Constructs user prompt from a request.
+     *
+     * <p>This implementation adds (choice1,choice2,choice3,...) to the
+     * prompt for <code>MultipleChoiceInputRequest</code>s.</p>
+     *
+     * @param request the request to construct the prompt for.
+     *                Must not be <code>null</code>.
+     * @return the prompt to ask the user
+     */
+    protected String getPrompt(InputRequest request) {
+        String prompt = request.getPrompt();
+        String def = request.getDefaultValue();
+        if (request instanceof MultipleChoiceInputRequest) {
+            StringBuffer sb = new StringBuffer(prompt);
+            sb.append(" (");
+            Enumeration e =
+                ((MultipleChoiceInputRequest) request).getChoices().elements();
+            boolean first = true;
+            while (e.hasMoreElements()) {
+                if (!first) {
+                    sb.append(", ");
+                }
+                String next = (String) e.nextElement();
+                if (next.equals(def)) {
+                    sb.append('[');
+                }
+                sb.append(next);
+                if (next.equals(def)) {
+                    sb.append(']');
+                }
+                first = false;
+            }
+            sb.append(")");
+            return sb.toString();
+        } else if (def != null) {
+            return prompt + " [" + def + "]";
+        } else {
+            return prompt;
+        }
+    }
+
+    /**
+     * Returns the input stream from which the user input should be read.
+     * @return the input stream from which the user input should be read.
+     */
+    protected InputStream getInputStream() {
+        return System.in;
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/input/GreedyInputHandler.java b/trunk/src/main/org/apache/tools/ant/input/GreedyInputHandler.java
new file mode 100644
index 0000000..e4b0ed3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/GreedyInputHandler.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+import java.io.InputStream;
+import java.io.ByteArrayOutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.StreamPumper;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Prompts on System.err, reads input from System.in until EOF
+ *
+ * @since Ant 1.7
+ */
+public class GreedyInputHandler extends DefaultInputHandler {
+
+    private static final int BUFFER_SIZE = 1024;
+
+    /**
+     * Empty no-arg constructor
+     */
+    public GreedyInputHandler() {
+    }
+
+    /**
+     * Prompts and requests input.
+     * @param request the request to handle
+     * @throws BuildException if not possible to read from console,
+     *         or if input is invalid.
+     */
+    public void handleInput(InputRequest request) throws BuildException {
+        String prompt = getPrompt(request);
+        InputStream in = null;
+        try {
+            in = getInputStream();
+            System.err.println(prompt);
+            System.err.flush();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            StreamPumper p = new StreamPumper(in, baos);
+            Thread t = new Thread(p);
+            t.start();
+            try {
+                t.join();
+            } catch (InterruptedException e) {
+                try {
+                    t.join();
+                } catch (InterruptedException e2) {
+                    // Ignore
+                }
+            }
+            request.setInput(new String(baos.toByteArray()));
+            if (!(request.isInputValid())) {
+                throw new BuildException(
+                    "Received invalid console input");
+            }
+            if (p.getException() != null) {
+                throw new BuildException(
+                    "Failed to read input from console", p.getException());
+            }
+        } finally {
+            FileUtils.close(in);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/InputHandler.java b/trunk/src/main/org/apache/tools/ant/input/InputHandler.java
new file mode 100644
index 0000000..aea60fc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/InputHandler.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+/**
+ * Plugin to Ant to handle requests for user input.
+ *
+ * @since Ant 1.5
+ */
+public interface InputHandler {
+
+    /**
+     * Handle the request encapsulated in the argument.
+     *
+     * <p>Precondition: the request.getPrompt will return a non-null
+     * value.</p>
+     *
+     * <p>Postcondition: request.getInput will return a non-null
+     * value, request.isInputValid will return true.</p>
+     * @param request the request to be processed
+     * @throws org.apache.tools.ant.BuildException if the input cannot be read from the console
+     */
+    void handleInput(InputRequest request)
+        throws org.apache.tools.ant.BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/InputRequest.java b/trunk/src/main/org/apache/tools/ant/input/InputRequest.java
new file mode 100644
index 0000000..8a6dd83
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/InputRequest.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+/**
+ * Encapsulates an input request.
+ *
+ * @since Ant 1.5
+ */
+public class InputRequest {
+    private String prompt;
+    private String input;
+    private String defaultValue;
+
+    /**
+     * Construct an InputRequest.
+     * @param prompt The prompt to show to the user.  Must not be null.
+     */
+    public InputRequest(String prompt) {
+        if (prompt == null) {
+            throw new IllegalArgumentException("prompt must not be null");
+        }
+
+        this.prompt = prompt;
+    }
+
+    /**
+     * Retrieves the prompt text.
+     * @return the prompt.
+     */
+    public String getPrompt() {
+        return prompt;
+    }
+
+    /**
+     * Sets the user provided input.
+     * @param input the string to be used for input.
+     */
+    public void setInput(String input) {
+        this.input = input;
+    }
+
+    /**
+     * Is the user input valid?
+     * @return true if it is.
+     */
+    public boolean isInputValid() {
+        return true;
+    }
+
+    /**
+     * Retrieves the user input.
+     * @return the user input.
+     */
+    public String getInput() {
+        return input;
+    }
+
+    /**
+     * Gets a configured default value.
+     * @return the default value.
+     * @since Ant 1.7.0
+     */
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    /**
+     * Configures a default value.
+     * @param d the value to set.
+     * @since Ant 1.7.0
+     */
+    public void setDefaultValue(String d) {
+        defaultValue = d;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/MultipleChoiceInputRequest.java b/trunk/src/main/org/apache/tools/ant/input/MultipleChoiceInputRequest.java
new file mode 100644
index 0000000..0a0e97a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/MultipleChoiceInputRequest.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+import java.util.Vector;
+
+/**
+ * Encapsulates an input request.
+ *
+ * @since Ant 1.5
+ */
+public class MultipleChoiceInputRequest extends InputRequest {
+    private Vector choices = new Vector();
+
+    /**
+     * @param prompt The prompt to show to the user.  Must not be null.
+     * @param choices holds all input values that are allowed.
+     *                Must not be null.
+     */
+    public MultipleChoiceInputRequest(String prompt, Vector choices) {
+        super(prompt);
+        if (choices == null) {
+            throw new IllegalArgumentException("choices must not be null");
+        }
+        this.choices = choices;
+    }
+
+    /**
+     * @return The possible values.
+     */
+    public Vector getChoices() {
+        return choices;
+    }
+
+    /**
+     * @return true if the input is one of the allowed values.
+     */
+    public boolean isInputValid() {
+        return choices.contains(getInput()) || ("".equals(getInput()) && getDefaultValue() != null);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/PropertyFileInputHandler.java b/trunk/src/main/org/apache/tools/ant/input/PropertyFileInputHandler.java
new file mode 100644
index 0000000..a9797ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/PropertyFileInputHandler.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.input;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Reads input from a property file, the file name is read from the
+ * system property ant.input.properties, the prompt is the key for input.
+ *
+ * @since Ant 1.5
+ */
+public class PropertyFileInputHandler implements InputHandler {
+    private Properties props = null;
+
+    /**
+     * Name of the system property we expect to hold the file name.
+     */
+    public static final String FILE_NAME_KEY = "ant.input.properties";
+
+    /**
+     * Empty no-arg constructor.
+     */
+    public PropertyFileInputHandler() {
+    }
+
+    /**
+     * Picks up the input from a property, using the prompt as the
+     * name of the property.
+     * @param request an input request.
+     *
+     * @exception BuildException if no property of that name can be found.
+     */
+    public void handleInput(InputRequest request) throws BuildException {
+        readProps();
+
+        Object o = props.get(request.getPrompt());
+        if (o == null) {
+            throw new BuildException("Unable to find input for \'"
+                                     + request.getPrompt() + "\'");
+        }
+        request.setInput(o.toString());
+        if (!request.isInputValid()) {
+            throw new BuildException("Found invalid input " + o
+                                     + " for \'" + request.getPrompt() + "\'");
+        }
+    }
+
+    /**
+     * Reads the properties file if it hasn't already been read.
+     */
+    private synchronized void readProps() throws BuildException {
+        if (props == null) {
+            String propsFile = System.getProperty(FILE_NAME_KEY);
+            if (propsFile == null) {
+                throw new BuildException("System property "
+                                         + FILE_NAME_KEY
+                                         + " for PropertyFileInputHandler not"
+                                         + " set");
+            }
+
+            props = new Properties();
+
+            try {
+                props.load(new FileInputStream(propsFile));
+            } catch (IOException e) {
+                throw new BuildException("Couldn't load " + propsFile, e);
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/input/SecureInputHandler.java b/trunk/src/main/org/apache/tools/ant/input/SecureInputHandler.java
new file mode 100644
index 0000000..71d1cfd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/input/SecureInputHandler.java
@@ -0,0 +1,60 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant.input;

+

+import org.apache.tools.ant.BuildException;

+import org.apache.tools.ant.util.ReflectUtil;

+

+/**

+ * Prompts and requests input.  May loop until a valid input has

+ * been entered. Doesn't echo input (requires Java6). If Java6 is not

+ * available, fallsback to the DefaultHandler (insecure).

+ * @since Ant 1.7.1

+ */

+public class SecureInputHandler extends DefaultInputHandler {

+

+    /**

+     * Default no-args constructor

+     */

+    public SecureInputHandler() {

+    }

+

+    /**

+     * Handle the input

+     * @param request the request to handle

+     * @throws BuildException if not possible to read from console

+     */

+    public void handleInput(InputRequest request) throws BuildException {

+        String prompt = getPrompt(request);

+        try {

+            Class system = Class.forName("java.lang.System");

+            Object console = ReflectUtil.invokeStatic(system, "console");

+            do {

+                char[] input = (char[]) ReflectUtil.invoke(

+                    console, "readPassword", String.class, prompt,

+                    Object[].class, (Object[]) null);

+                request.setInput(new String(input));

+                /* for security zero char array after retrieving value */

+                java.util.Arrays.fill(input, ' ');

+            } while (!request.isInputValid());

+        } catch (Exception e) {

+            /* Java6 not present use default handler */

+            super.handleInput(request);

+        }

+    }

+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/launch/AntMain.java b/trunk/src/main/org/apache/tools/ant/launch/AntMain.java
new file mode 100644
index 0000000..4703eaa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/launch/AntMain.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.launch;
+
+import java.util.Properties;
+
+/**
+ * Interface used to bridge to the actual Main class without any
+ * messy reflection
+ *
+ * @since Ant 1.6
+ */
+public interface AntMain {
+    /**
+     * Start Ant.
+     *
+     * @param args command line args
+     * @param additionalUserProperties properties to set beyond those that
+     *        may be specified on the args list
+     * @param coreLoader - not used
+     *
+     * @since Ant 1.6
+     */
+    void startAnt(String[] args, Properties additionalUserProperties,
+                  ClassLoader coreLoader);
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/launch/LaunchException.java b/trunk/src/main/org/apache/tools/ant/launch/LaunchException.java
new file mode 100644
index 0000000..41b0fc5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/launch/LaunchException.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.launch;
+
+/**
+ * Signals an error condition during launching
+ *
+ * @since Ant 1.6
+ */
+public class LaunchException extends Exception {
+
+    /**
+     * Constructs an exception with the given descriptive message.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code>.
+     */
+    public LaunchException(String message) {
+        super(message);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/launch/Launcher.java b/trunk/src/main/org/apache/tools/ant/launch/Launcher.java
new file mode 100644
index 0000000..c0d033c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/launch/Launcher.java
@@ -0,0 +1,407 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.launch;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.MalformedURLException;
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+
+
+/**
+ * This is a launcher for Ant.
+ *
+ * @since Ant 1.6
+ */
+public class Launcher {
+
+    /**
+     * The Ant Home (installation) Directory property.
+     * {@value}
+     */
+    public static final String ANTHOME_PROPERTY = "ant.home";
+
+    /**
+     * The Ant Library Directory property.
+     * {@value}
+     */
+    public static final String ANTLIBDIR_PROPERTY = "ant.library.dir";
+
+    /**
+     * The directory name of the per-user ant directory.
+     * {@value}
+     */
+    public static final String ANT_PRIVATEDIR = ".ant";
+
+    /**
+     * The name of a per-user library directory.
+     * {@value}
+     */
+    public static final String ANT_PRIVATELIB = "lib";
+
+    /**
+     * launch diagnostics flag; for debugging trouble at launch time.
+     */
+    public static boolean launchDiag = false;
+
+    /**
+     * The location of a per-user library directory.
+     * <p>
+     * It's value is the concatenation of {@link #ANT_PRIVATEDIR}
+     * with {@link #ANT_PRIVATELIB}, with an appropriate file separator
+     * in between. For example, on Unix, it's <code>.ant/lib</code>.
+     */
+    public static final String USER_LIBDIR =
+        ANT_PRIVATEDIR + File.separatorChar + ANT_PRIVATELIB;
+
+    /**
+     * The startup class that is to be run.
+     * {@value}
+     */
+    public static final String MAIN_CLASS = "org.apache.tools.ant.Main";
+
+    /**
+     * System property with user home directory.
+     * {@value}
+     */
+    public static final String USER_HOMEDIR = "user.home";
+
+    /**
+     * System property with application classpath.
+     * {@value}
+     */
+    private static final String JAVA_CLASS_PATH = "java.class.path";
+
+    /**
+     * Exit code on trouble
+     */
+    protected static final int EXIT_CODE_ERROR = 2;
+
+    /**
+     * Entry point for starting command line Ant.
+     *
+     * @param  args commandline arguments
+     */
+    public static void main(String[] args) {
+        int exitCode;
+        try {
+            Launcher launcher = new Launcher();
+            exitCode = launcher.run(args);
+        } catch (LaunchException e) {
+            exitCode = EXIT_CODE_ERROR;
+            System.err.println(e.getMessage());
+        } catch (Throwable t) {
+            exitCode = EXIT_CODE_ERROR;
+            t.printStackTrace(System.err);
+        }
+        if (exitCode != 0) {
+            if (launchDiag) {
+                System.out.println("Exit code: "+exitCode);
+            }
+            System.exit(exitCode);
+        }
+    }
+
+
+    /**
+     * Add a CLASSPATH or -lib to lib path urls.
+     *
+     * @param path        the classpath or lib path to add to the libPathULRLs
+     * @param getJars     if true and a path is a directory, add the jars in
+     *                    the directory to the path urls
+     * @param libPathURLs the list of paths to add to
+     * @throws MalformedURLException if we can't create a URL
+     */
+    private void addPath(String path, boolean getJars, List libPathURLs)
+            throws MalformedURLException {
+        StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator);
+        while (tokenizer.hasMoreElements()) {
+            String elementName = tokenizer.nextToken();
+            File element = new File(elementName);
+            if (elementName.indexOf('%') != -1 && !element.exists()) {
+                continue;
+            }
+            if (getJars && element.isDirectory()) {
+                // add any jars in the directory
+                URL[] dirURLs = Locator.getLocationURLs(element);
+                for (int j = 0; j < dirURLs.length; ++j) {
+                    if (launchDiag) { System.out.println("adding library JAR: " + dirURLs[j]);}
+                    libPathURLs.add(dirURLs[j]);
+                }
+            }
+
+            URL url = Locator.fileToURL(element);
+            if (launchDiag) { System.out.println("adding library URL: " + url) ;}
+            libPathURLs.add(url);
+        }
+    }
+
+    /**
+     * Run the launcher to launch Ant.
+     *
+     * @param args the command line arguments
+     * @return an exit code. As the normal ant main calls exit when it ends,
+     *         this is for handling failures at bind-time
+     * @throws MalformedURLException if the URLs required for the classloader
+     *            cannot be created.
+     * @throws LaunchException for launching problems
+     */
+    private int run(String[] args)
+            throws LaunchException, MalformedURLException {
+        String antHomeProperty = System.getProperty(ANTHOME_PROPERTY);
+        File antHome = null;
+
+        File sourceJar = Locator.getClassSource(getClass());
+        File jarDir = sourceJar.getParentFile();
+        String mainClassname = MAIN_CLASS;
+
+        if (antHomeProperty != null) {
+            antHome = new File(antHomeProperty);
+        }
+
+        if (antHome == null || !antHome.exists()) {
+            antHome = jarDir.getParentFile();
+            setProperty(ANTHOME_PROPERTY, antHome.getAbsolutePath());
+        }
+
+        if (!antHome.exists()) {
+            throw new LaunchException("Ant home is set incorrectly or "
+                + "ant could not be located (estimated value="+antHome.getAbsolutePath()+")");
+        }
+
+        List libPaths = new ArrayList();
+        String cpString = null;
+        List argList = new ArrayList();
+        String[] newArgs;
+        boolean  noUserLib = false;
+        boolean  noClassPath = false;
+
+        for (int i = 0; i < args.length; ++i) {
+            if (args[i].equals("-lib")) {
+                if (i == args.length - 1) {
+                    throw new LaunchException("The -lib argument must "
+                        + "be followed by a library location");
+                }
+                libPaths.add(args[++i]);
+            } else if (args[i].equals("-cp")) {
+                if (i == args.length - 1) {
+                    throw new LaunchException("The -cp argument must "
+                        + "be followed by a classpath expression");
+                }
+                if (cpString != null) {
+                    throw new LaunchException("The -cp argument must "
+                        + "not be repeated");
+                }
+                cpString = args[++i];
+            } else if (args[i].equals("--nouserlib") || args[i].equals("-nouserlib")) {
+                noUserLib = true;
+            } else if (args[i].equals("--launchdiag")) {
+                launchDiag = true;
+            } else if (args[i].equals("--noclasspath") || args[i].equals("-noclasspath")) {
+                noClassPath = true;
+            } else if (args[i].equals("-main")) {
+                if (i == args.length - 1) {
+                    throw new LaunchException("The -main argument must "
+                            + "be followed by a library location");
+                }
+                mainClassname = args[++i];
+            } else {
+                argList.add(args[i]);
+            }
+        }
+
+        logPath("Launcher JAR",sourceJar);
+        logPath("Launcher JAR directory", sourceJar.getParentFile());
+        logPath("java.home", new File(System.getProperty("java.home")));
+
+        //decide whether to copy the existing arg set, or
+        //build a new one from the list of all args excluding the special
+        //operations that only we handle
+        if (argList.size() == args.length) {
+            newArgs = args;
+        } else {
+            newArgs = (String[]) argList.toArray(new String[argList.size()]);
+        }
+
+        URL[] libURLs    = getLibPathURLs(
+            noClassPath ? null : cpString, libPaths);
+        URL[] systemURLs = getSystemURLs(jarDir);
+        URL[] userURLs   = noUserLib ? new URL[0] : getUserURLs();
+
+        File toolsJAR = Locator.getToolsJar();
+        logPath("tools.jar",toolsJAR);
+        URL[] jars = getJarArray(
+            libURLs, userURLs, systemURLs, toolsJAR);
+
+        // now update the class.path property
+        StringBuffer baseClassPath
+            = new StringBuffer(System.getProperty(JAVA_CLASS_PATH));
+        if (baseClassPath.charAt(baseClassPath.length() - 1)
+                == File.pathSeparatorChar) {
+            baseClassPath.setLength(baseClassPath.length() - 1);
+        }
+
+        for (int i = 0; i < jars.length; ++i) {
+            baseClassPath.append(File.pathSeparatorChar);
+            baseClassPath.append(Locator.fromURI(jars[i].toString()));
+        }
+
+        setProperty(JAVA_CLASS_PATH, baseClassPath.toString());
+
+        URLClassLoader loader = new URLClassLoader(jars);
+        Thread.currentThread().setContextClassLoader(loader);
+        Class mainClass = null;
+        int exitCode = 0;
+        Throwable thrown=null;
+        try {
+            mainClass = loader.loadClass(mainClassname);
+            AntMain main = (AntMain) mainClass.newInstance();
+            main.startAnt(newArgs, null, null);
+        } catch (InstantiationException ex) {
+            System.err.println(
+                "Incompatible version of " + mainClassname + " detected");
+            File mainJar = Locator.getClassSource(mainClass);
+            System.err.println(
+                "Location of this class " + mainJar);
+            thrown = ex;
+        } catch (ClassNotFoundException cnfe) {
+            System.err.println(
+                    "Failed to locate" + mainClassname);
+            thrown = cnfe;
+        } catch (Throwable t) {
+            t.printStackTrace(System.err);
+            thrown=t;
+        }
+        if(thrown!=null) {
+            System.err.println(ANTHOME_PROPERTY+": "+antHome.getAbsolutePath());
+            System.err.println("Classpath: " + baseClassPath.toString());
+            System.err.println("Launcher JAR: " + sourceJar.getAbsolutePath());
+            System.err.println("Launcher Directory: " + jarDir.getAbsolutePath());
+            exitCode = EXIT_CODE_ERROR;
+        }
+        return exitCode;
+    }
+
+    /**
+     * Get the list of -lib enties and -cp entry into
+     * a URL array.
+     * @param cpString the classpath string
+     * @param libPaths the list of -lib entries.
+     * @return an array of URLs.
+     * @throws MalformedURLException if the URLs  cannot be created.
+     */
+    private URL[] getLibPathURLs(String cpString, List libPaths)
+        throws MalformedURLException {
+        List libPathURLs = new ArrayList();
+
+        if (cpString != null) {
+            addPath(cpString, false, libPathURLs);
+        }
+
+        for (Iterator i = libPaths.iterator(); i.hasNext();) {
+            String libPath = (String) i.next();
+            addPath(libPath, true, libPathURLs);
+        }
+
+        return  (URL[]) libPathURLs.toArray(new URL[libPathURLs.size()]);
+    }
+
+    /**
+     * Get the jar files in ANT_HOME/lib.
+     * determine ant library directory for system jars: use property
+     * or default using location of ant-launcher.jar
+     * @param antLauncherDir the dir that ant-launcher ran from
+     * @return the URLs
+     * @throws MalformedURLException if the URLs cannot be created.
+     */
+    private URL[] getSystemURLs(File antLauncherDir) throws MalformedURLException {
+        File antLibDir = null;
+        String antLibDirProperty = System.getProperty(ANTLIBDIR_PROPERTY);
+        if (antLibDirProperty != null) {
+            antLibDir = new File(antLibDirProperty);
+        }
+        if ((antLibDir == null) || !antLibDir.exists()) {
+            antLibDir = antLauncherDir;
+            setProperty(ANTLIBDIR_PROPERTY, antLibDir.getAbsolutePath());
+        }
+        return Locator.getLocationURLs(antLibDir);
+    }
+
+    /**
+     * Get the jar files in user.home/.ant/lib
+     * @return the URLS from the user's lib dir
+     * @throws MalformedURLException if the URLs cannot be created.
+     */
+    private URL[] getUserURLs() throws MalformedURLException {
+        File userLibDir
+            = new File(System.getProperty(USER_HOMEDIR), USER_LIBDIR);
+
+        return Locator.getLocationURLs(userLibDir);
+    }
+
+    /**
+     * Combine the various jar sources into a single array of jars.
+     * @param libJars the jars specified in -lib command line options
+     * @param userJars the jars in ~/.ant/lib
+     * @param systemJars the jars in $ANT_HOME/lib
+     * @param toolsJar   the tools.jar file
+     * @return a combined array
+     * @throws MalformedURLException if there is a problem.
+     */
+    private URL[] getJarArray (
+        URL[] libJars, URL[] userJars, URL[] systemJars, File toolsJar)
+        throws MalformedURLException {
+        int numJars = libJars.length + userJars.length + systemJars.length;
+        if (toolsJar != null) {
+            numJars++;
+        }
+        URL[] jars = new URL[numJars];
+        System.arraycopy(libJars, 0, jars, 0, libJars.length);
+        System.arraycopy(userJars, 0, jars, libJars.length, userJars.length);
+        System.arraycopy(systemJars, 0, jars, userJars.length + libJars.length,
+            systemJars.length);
+
+        if (toolsJar != null) {
+            jars[jars.length - 1] = Locator.fileToURL(toolsJar);
+        }
+        return jars;
+    }
+
+    /**
+     * set a system property, optionally log what is going on
+     * @param name property name
+     * @param value value
+     */
+    private void setProperty(String name, String value) {
+        if (launchDiag) {
+            System.out.println("Setting \"" + name + "\" to \"" + value + "\"");
+        }
+        System.setProperty(name, value);
+    }
+
+    private void logPath(String name,File path) {
+        if(launchDiag) {
+            System.out.println(name+"= \""+path+"\"");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/launch/Locator.java b/trunk/src/main/org/apache/tools/ant/launch/Locator.java
new file mode 100644
index 0000000..160f25b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/launch/Locator.java
@@ -0,0 +1,549 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.launch;
+
+import java.net.MalformedURLException;
+
+import java.net.URL;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+// CheckStyle:LineLengthCheck OFF - urls are long!
+/**
+ * The Locator is a utility class which is used to find certain items
+ * in the environment.
+ *
+ * It is used at boot time in the launcher, and cannot make use of any of Ant's other classes.
+ *
+ * This is a surprisingly brittle piece of code, and has had lots of bugs filed against it.
+ * {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=42275">running ant off a network share can cause Ant to fail</a>}
+ * {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=8031">use File.toURI().toURL().toExternalForm()</a>}
+ * {@link <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=42222">Locator implementation not encoding URI strings properly: spaces in paths</a>}
+ * It also breaks Eclipse 3.3 Betas
+ * {@link <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=183283">Exception if installation path has spaces</a>}
+ *
+ * Be very careful when making changes to this class, as a break will upset a lot of people.
+ * @since Ant 1.6
+ */
+// CheckStyle:LineLengthCheck ON - urls are long!
+public final class Locator {
+
+    private static final int NIBBLE = 4;
+    private static final int NIBBLE_MASK   = 0xF;
+
+    private static final int ASCII_SIZE = 128;
+
+    private static final int BYTE_SIZE = 256;
+
+    private static final int WORD = 16;
+
+    private static final int SPACE = 0x20;
+    private static final int DEL = 0x7F;
+
+    /**
+     * encoding used to represent URIs
+     */
+    public static final String URI_ENCODING = "UTF-8";
+    // stolen from org.apache.xerces.impl.XMLEntityManager#getUserDir()
+    // of the Xerces-J team
+    // which ASCII characters need to be escaped
+    private static boolean[] gNeedEscaping = new boolean[ASCII_SIZE];
+    // the first hex character if a character needs to be escaped
+    private static char[] gAfterEscaping1 = new char[ASCII_SIZE];
+    // the second hex character if a character needs to be escaped
+    private static char[] gAfterEscaping2 = new char[ASCII_SIZE];
+    private static char[] gHexChs = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+    /** Error string used when an invalid uri is seen */
+    public static final String ERROR_NOT_FILE_URI
+        = "Can only handle valid file: URIs, not ";
+
+    // initialize the above 3 arrays
+    static {
+        for (int i = 0; i < SPACE; i++) {
+            gNeedEscaping[i] = true;
+            gAfterEscaping1[i] = gHexChs[i >> NIBBLE];
+            gAfterEscaping2[i] = gHexChs[i & NIBBLE_MASK];
+        }
+        gNeedEscaping[DEL] = true;
+        gAfterEscaping1[DEL] = '7';
+        gAfterEscaping2[DEL] = 'F';
+        char[] escChs = {' ', '<', '>', '#', '%', '"', '{', '}',
+                         '|', '\\', '^', '~', '[', ']', '`'};
+        int len = escChs.length;
+        char ch;
+        for (int i = 0; i < len; i++) {
+            ch = escChs[i];
+            gNeedEscaping[ch] = true;
+            gAfterEscaping1[ch] = gHexChs[ch >> NIBBLE];
+            gAfterEscaping2[ch] = gHexChs[ch & NIBBLE_MASK];
+        }
+    }
+    /**
+     * Not instantiable
+     */
+    private Locator() {
+    }
+
+    /**
+     * Find the directory or jar file the class has been loaded from.
+     *
+     * @param c the class whose location is required.
+     * @return the file or jar with the class or null if we cannot
+     *         determine the location.
+     *
+     * @since Ant 1.6
+     */
+    public static File getClassSource(Class c) {
+        String classResource = c.getName().replace('.', '/') + ".class";
+        return getResourceSource(c.getClassLoader(), classResource);
+    }
+
+    /**
+     * Find the directory or jar a given resource has been loaded from.
+     *
+     * @param c the classloader to be consulted for the source.
+     * @param resource the resource whose location is required.
+     *
+     * @return the file with the resource source or null if
+     *         we cannot determine the location.
+     *
+     * @since Ant 1.6
+     */
+    public static File getResourceSource(ClassLoader c, String resource) {
+        if (c == null) {
+            c = Locator.class.getClassLoader();
+        }
+        URL url = null;
+        if (c == null) {
+            url = ClassLoader.getSystemResource(resource);
+        } else {
+            url = c.getResource(resource);
+        }
+        if (url != null) {
+            String u = url.toString();
+            try {
+                if (u.startsWith("jar:file:")) {
+                    return new File(fromJarURI(u));
+                } else if (u.startsWith("file:")) {
+                    int tail = u.indexOf(resource);
+                    String dirName = u.substring(0, tail);
+                    return new File(fromURI(dirName));
+                }
+            } catch (IllegalArgumentException e) {
+                //unable to determine the URI for reasons unknown.
+                return null;
+            }
+        }
+        return null;
+    }
+
+
+
+    /**
+     * Constructs a file path from a <code>file:</code> URI.
+     *
+     * <p>Will be an absolute path if the given URI is absolute.</p>
+     *
+     * <p>Prior to Java 1.4,
+     * swallows '%' that are not followed by two characters.</p>
+     *
+     * See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a>
+     * which makes some mention of how
+     * characters not supported by URI Reference syntax should be escaped.
+     *
+     * @param uri the URI designating a file in the local filesystem.
+     * @return the local file system path for the file.
+     * @throws IllegalArgumentException if the URI is malformed or not a legal file: URL
+     * @since Ant 1.6
+     */
+    public static String fromURI(String uri) {
+        // #buzilla8031: first try Java 1.4.
+        String result = null;
+        //result = fromUriJava14(uri);
+        if (result == null) {
+            result = fromURIJava13(uri);
+        }
+        return result;
+    }
+
+
+    /**
+     * Java1.4+ code to extract the path from the URI.
+     * @param uri
+     * @return null if a conversion was not possible
+     */
+    private static String fromUriJava14(String uri) {
+        Class uriClazz = null;
+        try {
+            uriClazz = Class.forName("java.net.URI");
+        } catch (ClassNotFoundException cnfe) {
+            // Fine, Java 1.3 or earlier, do it by hand.
+            return null;
+        }
+        // Also check for properly formed URIs. Ant formerly recommended using
+        // nonsense URIs such as "file:./foo.xml" in XML includes. You shouldn't
+        // do that (just "foo.xml" is correct) but for compatibility we special-case
+        // things when the path is not absolute, and fall back to the old parsing behavior.
+        if (uriClazz != null && uri.startsWith("file:/")) {
+            try {
+                java.lang.reflect.Method createMethod
+                        = uriClazz.getMethod("create", new Class[]{String.class});
+                Object uriObj = createMethod.invoke(null, new Object[]{encodeURI(uri)});
+                java.lang.reflect.Constructor fileConst
+                        = File.class.getConstructor(new Class[]{uriClazz});
+                File f = (File) fileConst.newInstance(new Object[]{uriObj});
+                //bug #42227 forgot to decode before returning
+                return decodeUri(f.getAbsolutePath());
+            } catch (java.lang.reflect.InvocationTargetException e) {
+                Throwable e2 = e.getTargetException();
+                if (e2 instanceof IllegalArgumentException) {
+                    // Bad URI, pass this on.
+                    // no, this is downgraded to a warning after various
+                    // JRE bugs surfaced. Hand off
+                    // to our built in code on a failure
+                    //throw new IllegalArgumentException(
+                    //   "Bad URI " + uri + ":" + e2.getMessage(), e2);
+                    e2.printStackTrace();
+
+                } else {
+                    // Unexpected target exception? Should not happen.
+                    e2.printStackTrace();
+                }
+            } catch (Exception e) {
+                // Reflection problems? Should not happen, debug.
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+
+
+
+    /**
+     * This method is public for testing; we may delete it without any warning -it is not part of Ant's stable API.
+     * @param uri uri to expand
+     * @return the decoded URI
+     * @since Ant1.7.1
+     */
+    public static String fromURIJava13(String uri) {
+        // Fallback method for Java 1.3 or earlier.
+
+        URL url = null;
+        try {
+            url = new URL(uri);
+        } catch (MalformedURLException emYouEarlEx) {
+            // Ignore malformed exception
+        }
+        if (url == null || !("file".equals(url.getProtocol()))) {
+            throw new IllegalArgumentException(ERROR_NOT_FILE_URI + uri);
+        }
+        StringBuffer buf = new StringBuffer(url.getHost());
+        if (buf.length() > 0) {
+            buf.insert(0, File.separatorChar).insert(0, File.separatorChar);
+        }
+        String file = url.getFile();
+        int queryPos = file.indexOf('?');
+        buf.append((queryPos < 0) ? file : file.substring(0, queryPos));
+
+        uri = buf.toString().replace('/', File.separatorChar);
+
+        if (File.pathSeparatorChar == ';' && uri.startsWith("\\") && uri.length() > 2
+            && Character.isLetter(uri.charAt(1)) && uri.lastIndexOf(':') > -1) {
+            uri = uri.substring(1);
+        }
+        String path = null;
+        try {
+            path = decodeUri(uri);
+            //consider adding the current directory. This is not done when
+            //the path is a UNC name
+            String cwd = System.getProperty("user.dir");
+            int posi = cwd.indexOf(':');
+            boolean pathStartsWithFileSeparator = path.startsWith(File.separator);
+            boolean pathStartsWithUNC = path.startsWith("" + File.separator + File.separator);
+            if ((posi > 0) && pathStartsWithFileSeparator && !pathStartsWithUNC) {
+                path = cwd.substring(0, posi + 1) + path;
+            }
+        } catch (UnsupportedEncodingException exc) {
+            // not sure whether this is clean, but this method is
+            // declared not to throw exceptions.
+            throw new IllegalStateException(
+                "Could not convert URI " + uri + " to path: "
+                + exc.getMessage());
+        }
+        return path;
+    }
+
+    /**
+     * Crack a JAR URI.
+     * This method is public for testing; we may delete it without any warning -it is not part of Ant's stable API.
+     * @param uri uri to expand; contains jar: somewhere in it
+     * @return the decoded URI
+     * @since Ant1.7.1
+     */
+    public static String fromJarURI(String uri) {
+        int pling = uri.indexOf('!');
+        String jarName = uri.substring("jar:".length(), pling);
+        return fromURI(jarName);
+    }
+
+    /**
+     * Decodes an Uri with % characters.
+     * The URI is escaped
+     * @param uri String with the uri possibly containing % characters.
+     * @return The decoded Uri
+     * @throws UnsupportedEncodingException if UTF-8 is not available
+     * @since Ant 1.7
+     */
+    public static String decodeUri(String uri) throws UnsupportedEncodingException {
+        if (uri.indexOf('%') == -1) {
+            return uri;
+        }
+        ByteArrayOutputStream sb = new ByteArrayOutputStream(uri.length());
+        CharacterIterator iter = new StringCharacterIterator(uri);
+        for (char c = iter.first(); c != CharacterIterator.DONE;
+             c = iter.next()) {
+            if (c == '%') {
+                char c1 = iter.next();
+                if (c1 != CharacterIterator.DONE) {
+                    int i1 = Character.digit(c1, WORD);
+                    char c2 = iter.next();
+                    if (c2 != CharacterIterator.DONE) {
+                        int i2 = Character.digit(c2, WORD);
+                        sb.write((char) ((i1 << NIBBLE) + i2));
+                    }
+                }
+            } else {
+                sb.write(c);
+            }
+        }
+        return sb.toString(URI_ENCODING);
+    }
+
+    /**
+     * Encodes an Uri with % characters.
+     * The URI is escaped
+     * @param path String to encode.
+     * @return The encoded string, according to URI norms
+     * @throws UnsupportedEncodingException if UTF-8 is not available
+     * @since Ant 1.7
+     */
+    public static String encodeURI(String path) throws UnsupportedEncodingException {
+        int i = 0;
+        int len = path.length();
+        int ch = 0;
+        StringBuffer sb = null;
+        for (; i < len; i++) {
+            ch = path.charAt(i);
+            // if it's not an ASCII character, break here, and use UTF-8 encoding
+            if (ch >= ASCII_SIZE) {
+                break;
+            }
+            if (gNeedEscaping[ch]) {
+                if (sb == null) {
+                    sb = new StringBuffer(path.substring(0, i));
+                }
+                sb.append('%');
+                sb.append(gAfterEscaping1[ch]);
+                sb.append(gAfterEscaping2[ch]);
+                // record the fact that it's escaped
+            } else if (sb != null) {
+                sb.append((char) ch);
+            }
+        }
+
+        // we saw some non-ascii character
+        if (i < len) {
+            if (sb == null) {
+                sb = new StringBuffer(path.substring(0, i));
+            }
+            // get UTF-8 bytes for the remaining sub-string
+            byte[] bytes = null;
+            byte b;
+            bytes = path.substring(i).getBytes(URI_ENCODING);
+            len = bytes.length;
+
+            // for each byte
+            for (i = 0; i < len; i++) {
+                b = bytes[i];
+                // for non-ascii character: make it positive, then escape
+                if (b < 0) {
+                    ch = b + BYTE_SIZE;
+                    sb.append('%');
+                    sb.append(gHexChs[ch >> NIBBLE]);
+                    sb.append(gHexChs[ch & NIBBLE_MASK]);
+                } else if (gNeedEscaping[b]) {
+                    sb.append('%');
+                    sb.append(gAfterEscaping1[b]);
+                    sb.append(gAfterEscaping2[b]);
+                } else {
+                    sb.append((char) b);
+                }
+            }
+        }
+        return sb == null ? path : sb.toString();
+    }
+
+    /**
+     * Convert a File to a URL.
+     * File.toURL() does not encode characters like #.
+     * File.toURI() has been introduced in java 1.4, so
+     * ANT cannot use it (except by reflection)
+     * FileUtils.toURI() cannot be used by Locator.java
+     * Implemented this way.
+     * File.toURL() adds file: and changes '\' to '/' for dos OSes
+     * encodeURI converts characters like ' ' and '#' to %DD
+     * @param file the file to convert
+     * @return URL the converted File
+     * @throws MalformedURLException on error
+     */
+    public static URL fileToURL(File file)
+        throws MalformedURLException {
+        try {
+            return new URL(encodeURI(file.toURL().toString()));
+        } catch (UnsupportedEncodingException ex) {
+            throw new MalformedURLException(ex.toString());
+        }
+    }
+
+    /**
+     * Get the File necessary to load the Sun compiler tools. If the classes
+     * are available to this class, then no additional URL is required and
+     * null is returned. This may be because the classes are explicitly in the
+     * class path or provided by the JVM directly.
+     *
+     * @return the tools jar as a File if required, null otherwise.
+     */
+    public static File getToolsJar() {
+        // firstly check if the tools jar is already in the classpath
+        boolean toolsJarAvailable = false;
+        try {
+            // just check whether this throws an exception
+            Class.forName("com.sun.tools.javac.Main");
+            toolsJarAvailable = true;
+        } catch (Exception e) {
+            try {
+                Class.forName("sun.tools.javac.Main");
+                toolsJarAvailable = true;
+            } catch (Exception e2) {
+                // ignore
+            }
+        }
+        if (toolsJarAvailable) {
+            return null;
+        }
+        // couldn't find compiler - try to find tools.jar
+        // based on java.home setting
+        String libToolsJar
+            = File.separator + "lib" + File.separator + "tools.jar";
+        String javaHome = System.getProperty("java.home");
+        File toolsJar = new File(javaHome + libToolsJar);
+        if (toolsJar.exists()) {
+            // Found in java.home as given
+            return toolsJar;
+        }
+        if (javaHome.toLowerCase(Locale.US).endsWith(File.separator + "jre")) {
+            javaHome = javaHome.substring(
+                0, javaHome.length() - "/jre".length());
+            toolsJar = new File(javaHome + libToolsJar);
+        }
+        if (!toolsJar.exists()) {
+            System.out.println("Unable to locate tools.jar. "
+                 + "Expected to find it in " + toolsJar.getPath());
+            return null;
+        }
+        return toolsJar;
+    }
+
+    /**
+     * Get an array of URLs representing all of the jar files in the
+     * given location. If the location is a file, it is returned as the only
+     * element of the array. If the location is a directory, it is scanned for
+     * jar files.
+     *
+     * @param location the location to scan for Jars.
+     *
+     * @return an array of URLs for all jars in the given location.
+     *
+     * @exception MalformedURLException if the URLs for the jars cannot be
+     *            formed.
+     */
+    public static URL[] getLocationURLs(File location)
+         throws MalformedURLException {
+        return getLocationURLs(location, new String[]{".jar"});
+    }
+
+    /**
+     * Get an array of URLs representing all of the files of a given set of
+     * extensions in the given location. If the location is a file, it is
+     * returned as the only element of the array. If the location is a
+     * directory, it is scanned for matching files.
+     *
+     * @param location the location to scan for files.
+     * @param extensions an array of extension that are to match in the
+     *        directory search.
+     *
+     * @return an array of URLs of matching files.
+     * @exception MalformedURLException if the URLs for the files cannot be
+     *            formed.
+     */
+    public static URL[] getLocationURLs(File location,
+                                        final String[] extensions)
+         throws MalformedURLException {
+        URL[] urls = new URL[0];
+
+        if (!location.exists()) {
+            return urls;
+        }
+        if (!location.isDirectory()) {
+            urls = new URL[1];
+            String path = location.getPath();
+            String littlePath = path.toLowerCase(Locale.US);
+            for (int i = 0; i < extensions.length; ++i) {
+                if (littlePath.endsWith(extensions[i])) {
+                    urls[0] = fileToURL(location);
+                    break;
+                }
+            }
+            return urls;
+        }
+        File[] matches = location.listFiles(
+            new FilenameFilter() {
+                public boolean accept(File dir, String name) {
+                    String littleName = name.toLowerCase(Locale.US);
+                    for (int i = 0; i < extensions.length; ++i) {
+                        if (littleName.endsWith(extensions[i])) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            });
+        urls = new URL[matches.length];
+        for (int i = 0; i < matches.length; ++i) {
+            urls[i] = fileToURL(matches[i]);
+        }
+        return urls;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java b/trunk/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java
new file mode 100644
index 0000000..39c96cc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/AnsiColorLogger.java
@@ -0,0 +1,243 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.listener;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Properties;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+
+/**
+ * Uses ANSI Color Code Sequences to colorize messages
+ * sent to the console.
+ *
+ * If used with the -logfile option, the output file
+ * will contain all the necessary escape codes to
+ * display the text in colorized mode when displayed
+ * in the console using applications like cat, more,
+ * etc.
+ *
+ * This is designed to work on terminals that support ANSI
+ * color codes.  It works on XTerm, ETerm, Mindterm, etc.
+ * It also works on Win9x (with ANSI.SYS loaded.)
+ *
+ * NOTE:
+ * It doesn't work on WinNT's COMMAND.COM even with
+ * ANSI.SYS loaded.
+ *
+ * The default colors used for differentiating
+ * the message levels can be changed by editing the
+ * /org/apache/tools/ant/listener/defaults.properties
+ * file.
+ * This file contains 5 key/value pairs:
+ * AnsiColorLogger.ERROR_COLOR=2;31
+ * AnsiColorLogger.WARNING_COLOR=2;35
+ * AnsiColorLogger.INFO_COLOR=2;36
+ * AnsiColorLogger.VERBOSE_COLOR=2;32
+ * AnsiColorLogger.DEBUG_COLOR=2;34
+ *
+ * Another option is to pass a system variable named
+ * ant.logger.defaults, with value set to the path of
+ * the file that contains user defined Ansi Color
+ * Codes, to the <B>java</B> command using -D option.
+ *
+ * To change these colors use the following chart:
+ *
+ *      <B>ANSI COLOR LOGGER CONFIGURATION</B>
+ *
+ * Format for AnsiColorLogger.*=
+ *  Attribute;Foreground;Background
+ *
+ *  Attribute is one of the following:
+ *  0 -> Reset All Attributes (return to normal mode)
+ *  1 -> Bright (Usually turns on BOLD)
+ *  2 -> Dim
+ *  3 -> Underline
+ *  5 -> link
+ *  7 -> Reverse
+ *  8 -> Hidden
+ *
+ *  Foreground is one of the following:
+ *  30 -> Black
+ *  31 -> Red
+ *  32 -> Green
+ *  33 -> Yellow
+ *  34 -> Blue
+ *  35 -> Magenta
+ *  36 -> Cyan
+ *  37 -> White
+ *
+ *  Background is one of the following:
+ *  40 -> Black
+ *  41 -> Red
+ *  42 -> Green
+ *  43 -> Yellow
+ *  44 -> Blue
+ *  45 -> Magenta
+ *  46 -> Cyan
+ *  47 -> White
+ *
+ */
+public class AnsiColorLogger extends DefaultLogger {
+    // private static final int ATTR_NORMAL = 0;
+    // private static final int ATTR_BRIGHT = 1;
+    private static final int ATTR_DIM = 2;
+    // private static final int ATTR_UNDERLINE = 3;
+    // private static final int ATTR_BLINK = 5;
+    // private static final int ATTR_REVERSE = 7;
+    // private static final int ATTR_HIDDEN = 8;
+
+    // private static final int FG_BLACK = 30;
+    private static final int FG_RED = 31;
+    private static final int FG_GREEN = 32;
+    // private static final int FG_YELLOW = 33;
+    private static final int FG_BLUE = 34;
+    private static final int FG_MAGENTA = 35;
+    private static final int FG_CYAN = 36;
+    // private static final int FG_WHITE = 37;
+
+    // private static final int BG_BLACK = 40;
+    // private static final int BG_RED = 41;
+    // private static final int BG_GREEN = 42;
+    // private static final int BG_YELLOW = 44;
+    // private static final int BG_BLUE = 44;
+    // private static final int BG_MAGENTA = 45;
+    // private static final int BG_CYAN = 46;
+    // private static final int BG_WHITE = 47;
+
+    private static final String PREFIX = "\u001b[";
+    private static final String SUFFIX = "m";
+    private static final char SEPARATOR = ';';
+    private static final String END_COLOR = PREFIX + SUFFIX;
+
+    private String errColor
+        = PREFIX + ATTR_DIM + SEPARATOR + FG_RED + SUFFIX;
+    private String warnColor
+        = PREFIX + ATTR_DIM + SEPARATOR + FG_MAGENTA + SUFFIX;
+    private String infoColor
+        = PREFIX + ATTR_DIM + SEPARATOR + FG_CYAN + SUFFIX;
+    private String verboseColor
+        = PREFIX + ATTR_DIM + SEPARATOR + FG_GREEN + SUFFIX;
+    private String debugColor
+        = PREFIX + ATTR_DIM + SEPARATOR + FG_BLUE + SUFFIX;
+
+    private boolean colorsSet = false;
+
+    /**
+     * Set the colors to use from a property file specified by the
+     * special ant property ant.logger.defaults
+     */
+    private void setColors() {
+        String userColorFile = System.getProperty("ant.logger.defaults");
+        String systemColorFile =
+            "/org/apache/tools/ant/listener/defaults.properties";
+
+        InputStream in = null;
+
+        try {
+            Properties prop = new Properties();
+
+            if (userColorFile != null) {
+                in = new FileInputStream(userColorFile);
+            } else {
+                in = getClass().getResourceAsStream(systemColorFile);
+            }
+
+            if (in != null) {
+                prop.load(in);
+            }
+
+            String errC = prop.getProperty("AnsiColorLogger.ERROR_COLOR");
+            String warn = prop.getProperty("AnsiColorLogger.WARNING_COLOR");
+            String info = prop.getProperty("AnsiColorLogger.INFO_COLOR");
+            String verbose = prop.getProperty("AnsiColorLogger.VERBOSE_COLOR");
+            String debug = prop.getProperty("AnsiColorLogger.DEBUG_COLOR");
+            if (errC != null) {
+                errColor = PREFIX + errC + SUFFIX;
+            }
+            if (warn != null) {
+                warnColor = PREFIX + warn + SUFFIX;
+            }
+            if (info != null) {
+                infoColor = PREFIX + info + SUFFIX;
+            }
+            if (verbose != null) {
+                verboseColor = PREFIX + verbose + SUFFIX;
+            }
+            if (debug != null) {
+                debugColor = PREFIX + debug + SUFFIX;
+            }
+        } catch (IOException ioe) {
+            //Ignore - we will use the defaults.
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {
+                    //Ignore - We do not want this to stop the build.
+                }
+            }
+        }
+    }
+
+    /**
+     * @see DefaultLogger#printMessage
+     */
+    /** {@inheritDoc}. */
+    protected void printMessage(final String message,
+                                      final PrintStream stream,
+                                      final int priority) {
+        if (message != null && stream != null) {
+            if (!colorsSet) {
+                setColors();
+                colorsSet = true;
+            }
+
+            final StringBuffer msg = new StringBuffer(message);
+            switch (priority) {
+                case Project.MSG_ERR:
+                    msg.insert(0, errColor);
+                    msg.append(END_COLOR);
+                    break;
+                case Project.MSG_WARN:
+                    msg.insert(0, warnColor);
+                    msg.append(END_COLOR);
+                    break;
+                case Project.MSG_INFO:
+                    msg.insert(0, infoColor);
+                    msg.append(END_COLOR);
+                    break;
+                case Project.MSG_VERBOSE:
+                    msg.insert(0, verboseColor);
+                    msg.append(END_COLOR);
+                    break;
+                case Project.MSG_DEBUG:
+                    // Fall through
+                default:
+                    msg.insert(0, debugColor);
+                    msg.append(END_COLOR);
+                    break;
+            }
+            final String strmessage = msg.toString();
+            stream.println(strmessage);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/BigProjectLogger.java b/trunk/src/main/org/apache/tools/ant/listener/BigProjectLogger.java
new file mode 100644
index 0000000..c21df3c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/BigProjectLogger.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.listener;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.NoBannerLogger;
+import org.apache.tools.ant.SubBuildListener;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.StringUtils;
+
+import java.io.File;
+
+/**
+ * This is a special logger that is designed to make it easier to work
+ * with big projects, those that use imports and
+ * subant to build complex systems.
+ *
+ * @since Ant1.7.1
+ */
+
+public class BigProjectLogger extends NoBannerLogger implements SubBuildListener {
+
+    /**
+     * Header string for the log.
+     * {@value}
+     */
+    public static final String HEADER
+        = "======================================================================";
+    /**
+     * Footer string for the log.
+     * {@value}
+     */
+    public static final String FOOTER = HEADER;
+
+    /**
+    * This is an override point: the message that indicates whether
+    * a build failed. Subclasses can change/enhance the
+    * message.
+    *
+    * @return The classic "BUILD FAILED" plus a timestamp
+    */
+    protected String getBuildFailedMessage() {
+        return super.getBuildFailedMessage() + TimestampedLogger.SPACER + getTimestamp();
+    }
+
+    /**
+     * This is an override point: the message that indicates that
+     * a build succeeded. Subclasses can change/enhance the
+     * message.
+     *
+     * @return The classic "BUILD SUCCESSFUL" plus a timestamp
+     */
+    protected String getBuildSuccessfulMessage() {
+        return super.getBuildSuccessfulMessage() + TimestampedLogger.SPACER + getTimestamp();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param event
+     */
+    public void buildStarted(BuildEvent event) {
+        super.buildStarted(event);
+        subBuildStarted(event);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param event
+     */
+    public void buildFinished(BuildEvent event) {
+        subBuildFinished(event);
+        super.buildFinished(event);
+    }
+
+    /**
+     * Override point, extract the target name
+     *
+     * @param event the event to work on
+     * @return the target name -including the owning project name (if non-null)
+     */
+    protected String extractTargetName(BuildEvent event) {
+        String targetName = event.getTarget().getName();
+        String projectName = extractProjectName(event);
+        if (projectName != null && targetName != null) {
+            return projectName + '.' + targetName;
+        } else {
+            return targetName;
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param event An event with any relevant extra information. Must not be <code>null</code>.
+     */
+    public void subBuildStarted(BuildEvent event) {
+        String name = extractNameOrDefault(event);
+        Project project = event.getProject();
+
+        File base = project == null ? null : project.getBaseDir();
+        String path =
+            (base == null)
+            ? "With no base directory"
+            : "In " + base.getAbsolutePath();
+        printMessage(StringUtils.LINE_SEP + getHeader()
+                + StringUtils.LINE_SEP + "Entering project " + name
+                        + StringUtils.LINE_SEP + path
+                        + StringUtils.LINE_SEP + getFooter(),
+                out,
+                event.getPriority());
+    }
+
+    /**
+     * Get the name of an event
+     *
+     * @param event the event name
+     * @return the name or a default string
+     */
+    protected String extractNameOrDefault(BuildEvent event) {
+        String name = extractProjectName(event);
+        if (name == null) {
+            name = "";
+        } else {
+            name = '"' + name + '"';
+        }
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    public void subBuildFinished(BuildEvent event) {
+        String name = extractNameOrDefault(event);
+        String failed = event.getException() != null ? "failing " : "";
+        printMessage(StringUtils.LINE_SEP + getHeader()
+                + StringUtils.LINE_SEP + "Exiting " + failed + "project "
+                + name
+                + StringUtils.LINE_SEP + getFooter(),
+                out,
+                event.getPriority());
+    }
+
+    /**
+     * Override point: return the header string for the entry/exit message
+     * @return the header string
+     */
+    protected String getHeader() {
+        return HEADER;
+    }
+
+    /**
+     * Override point: return the footer string for the entry/exit message
+     * @return the footer string
+     */
+    protected String getFooter() {
+        return FOOTER;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/CommonsLoggingListener.java b/trunk/src/main/org/apache/tools/ant/listener/CommonsLoggingListener.java
new file mode 100644
index 0000000..c48087a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/CommonsLoggingListener.java
@@ -0,0 +1,332 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.listener;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogConfigurationException;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.BuildLogger;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+
+import java.io.PrintStream;
+
+/**
+ * Jakarta Commons Logging listener.
+ * Note: do not use the SimpleLog as your logger implementation as it
+ * causes an infinite loop since it writes to System.err, which Ant traps
+ * and reroutes to the logger/listener layer.
+ *
+ * The following names are used for the log:
+ *  org.apache.tools.ant.Project.PROJECT_NAME  - for project events
+ *  org.apache.tools.ant.Target.TARGET_NAME - for target events
+ *  TASK_CLASS_NAME.TARGET_NAME - for events in individual targets.
+ *
+ * In all target and project names we replace "." and " " with "-".
+ *
+ * TODO: we should use the advanced context logging features (and expose them
+ * in c-l first :-)
+ * TODO: this is _very_ inefficient. Switching the out and tracking the logs
+ * can be optimized a lot - but may require few more changes to the core.
+ *
+ * @since Ant 1.5
+ */
+public class CommonsLoggingListener implements BuildListener, BuildLogger {
+
+    /** Indicates if the listener was initialized. */
+    private boolean initialized = false;
+
+    private LogFactory logFactory;
+
+    /**
+     * name of the category under which target events are logged
+     */
+    public static final String TARGET_LOG = "org.apache.tools.ant.Target";
+    /**
+     * name of the category under which project events are logged
+     */
+    public static final String PROJECT_LOG = "org.apache.tools.ant.Project";
+
+    /**
+     * Construct the listener and make sure that a LogFactory
+     * can be obtained.
+     */
+    public CommonsLoggingListener() {
+    }
+
+    private Log getLog(String cat, String suffix) {
+        if (suffix != null) {
+            suffix = suffix.replace('.', '-');
+            suffix = suffix.replace(' ', '-');
+            cat = cat + "." + suffix;
+        }
+        PrintStream tmpOut = System.out;
+        PrintStream tmpErr = System.err;
+        System.setOut(out);
+        System.setErr(err);
+
+        if (!initialized) {
+            try {
+                logFactory = LogFactory.getFactory();
+            } catch (LogConfigurationException e) {
+                e.printStackTrace(System.err);
+                return null;
+            }
+        }
+
+        initialized = true;
+        Log log = logFactory.getInstance(cat);
+        System.setOut(tmpOut);
+        System.setErr(tmpErr);
+        return log;
+    }
+
+    /** {@inheritDoc}. */
+    public void buildStarted(BuildEvent event) {
+        String categoryString = PROJECT_LOG;
+        Log log = getLog(categoryString, null);
+
+        if (initialized) {
+            realLog(log, "Build started.", Project.MSG_INFO, null);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public void buildFinished(BuildEvent event) {
+        if (initialized) {
+            String categoryString = PROJECT_LOG;
+            Log log = getLog(categoryString, event.getProject().getName());
+
+            if (event.getException() == null) {
+                realLog(log, "Build finished.", Project.MSG_INFO, null);
+            } else {
+                realLog(log, "Build finished with error.", Project.MSG_ERR,
+                        event.getException());
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#targetStarted
+     */
+    /** {@inheritDoc}. */
+    public void targetStarted(BuildEvent event) {
+        if (initialized) {
+            Log log = getLog(TARGET_LOG,
+                    event.getTarget().getName());
+            // Since task log category includes target, we don't really
+            // need this message
+            realLog(log, "Start: " + event.getTarget().getName(),
+                    Project.MSG_VERBOSE, null);
+        }
+    }
+
+    /**
+     * @see BuildListener#targetFinished
+     */
+    /** {@inheritDoc}. */
+    public void targetFinished(BuildEvent event) {
+        if (initialized) {
+            String targetName = event.getTarget().getName();
+            Log log = getLog(TARGET_LOG,
+                    event.getTarget().getName());
+            if (event.getException() == null) {
+                realLog(log, "Target end: " + targetName, Project.MSG_DEBUG, null);
+            } else {
+                realLog(log, "Target \"" + targetName
+                        + "\" finished with error.", Project.MSG_ERR,
+                        event.getException());
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#taskStarted
+     */
+    /** {@inheritDoc}. */
+    public void taskStarted(BuildEvent event) {
+        if (initialized) {
+            Task task = event.getTask();
+            Object real = task;
+            if (task instanceof UnknownElement) {
+                Object realObj = ((UnknownElement) task).getTask();
+                if (realObj != null) {
+                    real = realObj;
+                }
+            }
+            Log log = getLog(real.getClass().getName(), null);
+            if (log.isTraceEnabled()) {
+                realLog(log, "Task \"" + task.getTaskName() + "\" started ",
+                        Project.MSG_VERBOSE, null);
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#taskFinished
+     */
+    /** {@inheritDoc}. */
+    public void taskFinished(BuildEvent event) {
+        if (initialized) {
+            Task task = event.getTask();
+            Object real = task;
+            if (task instanceof UnknownElement) {
+                Object realObj = ((UnknownElement) task).getTask();
+                if (realObj != null) {
+                    real = realObj;
+                }
+            }
+            Log log = getLog(real.getClass().getName(), null);
+            if (event.getException() == null) {
+                if (log.isTraceEnabled()) {
+                    realLog(log, "Task \"" + task.getTaskName() + "\" finished.",
+                            Project.MSG_VERBOSE, null);
+                }
+            } else {
+                realLog(log, "Task \"" + task.getTaskName()
+                        + "\" finished with error.", Project.MSG_ERR,
+                        event.getException());
+            }
+        }
+    }
+
+
+    /**
+     * @see BuildListener#messageLogged
+     */
+    /** {@inheritDoc}. */
+    public void messageLogged(BuildEvent event) {
+        if (initialized) {
+            Object categoryObject = event.getTask();
+            String categoryString = null;
+            String categoryDetail = null;
+
+            if (categoryObject == null) {
+                categoryObject = event.getTarget();
+                if (categoryObject == null) {
+                    categoryObject = event.getProject();
+                    categoryString = PROJECT_LOG;
+                    categoryDetail = event.getProject().getName();
+                } else {
+                    categoryString = TARGET_LOG;
+                    categoryDetail = event.getTarget().getName();
+                }
+            } else {
+                // It's a task - append the target
+                if (event.getTarget() != null) {
+                    categoryString = categoryObject.getClass().getName();
+                    categoryDetail = event.getTarget().getName();
+                } else {
+                    categoryString = categoryObject.getClass().getName();
+                }
+
+            }
+
+            Log log = getLog(categoryString, categoryDetail);
+            int priority = event.getPriority();
+            String message = event.getMessage();
+            realLog(log, message, priority , null);
+        }
+    }
+
+    private void realLog(Log log, String message, int priority, Throwable t) {
+        PrintStream tmpOut = System.out;
+        PrintStream tmpErr = System.err;
+        System.setOut(out);
+        System.setErr(err);
+        switch (priority) {
+            case Project.MSG_ERR:
+                if (t == null) {
+                    log.error(message);
+                } else {
+                    log.error(message, t);
+                }
+                break;
+            case Project.MSG_WARN:
+                if (t == null) {
+                    log.warn(message);
+                } else {
+                    log.warn(message, t);
+                }
+                break;
+            case Project.MSG_INFO:
+                if (t == null) {
+                    log.info(message);
+                } else {
+                    log.info(message, t);
+                }
+                break;
+            case Project.MSG_VERBOSE:
+                log.debug(message);
+                break;
+            case Project.MSG_DEBUG:
+                log.debug(message);
+                break;
+            default:
+                log.error(message);
+                break;
+        }
+        System.setOut(tmpOut);
+        System.setErr(tmpErr);
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    PrintStream out = System.out;
+    PrintStream err = System.err;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the the output level.
+     * This is not used, the logger config is used instead.
+     * @param level ignored
+     */
+    public void setMessageOutputLevel(int level) {
+        // Use the logger config
+    }
+
+    /**
+     * Set the output print stream.
+     * @param output the output stream
+     */
+    public void setOutputPrintStream(PrintStream output) {
+        this.out = output;
+    }
+
+    /**
+     * Set emacs mode.
+     * This is ignored.
+     * @param emacsMode ignored
+     */
+    public void setEmacsMode(boolean emacsMode) {
+        // Doesn't make sense for c-l. Use the logger config
+    }
+
+    /**
+     * Set the error print stream.
+     * @param err the error stream
+     */
+    public void setErrorPrintStream(PrintStream err) {
+        this.err = err;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/Log4jListener.java b/trunk/src/main/org/apache/tools/ant/listener/Log4jListener.java
new file mode 100644
index 0000000..059d1e5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/Log4jListener.java
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.listener;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.NullEnumeration;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+
+
+/**
+ *  Listener which sends events to Log4j logging system
+ *
+ */
+public class Log4jListener implements BuildListener {
+
+    /** Indicates if the listener was initialized. */
+    private boolean initialized = false;
+
+    /**
+     * log category we log into
+     */
+    public static final String LOG_ANT = "org.apache.tools.ant";
+
+    /**
+     * Construct the listener and make sure there is a valid appender.
+     */
+    public Log4jListener() {
+        initialized = false;
+        Logger log = Logger.getLogger(LOG_ANT);
+        Logger rootLog = Logger.getRootLogger();
+        if (!(rootLog.getAllAppenders() instanceof NullEnumeration)) {
+            initialized = true;
+        } else {
+            log.error("No log4j.properties in build area");
+        }
+    }
+
+    /**
+     * @see BuildListener#buildStarted
+     */
+    /** {@inheritDoc}. */
+    public void buildStarted(BuildEvent event) {
+        if (initialized) {
+            Logger log = Logger.getLogger(Project.class.getName());
+            log.info("Build started.");
+        }
+    }
+
+    /**
+     * @see BuildListener#buildFinished
+     */
+    /** {@inheritDoc}. */
+    public void buildFinished(BuildEvent event) {
+        if (initialized) {
+            Logger log = Logger.getLogger(Project.class.getName());
+            if (event.getException() == null) {
+                log.info("Build finished.");
+            } else {
+                log.error("Build finished with error.", event.getException());
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#targetStarted
+     */
+    /** {@inheritDoc}. */
+    public void targetStarted(BuildEvent event) {
+        if (initialized) {
+            Logger log = Logger.getLogger(Target.class.getName());
+            log.info("Target \"" + event.getTarget().getName() + "\" started.");
+        }
+    }
+
+    /**
+     * @see BuildListener#targetFinished
+     */
+    /** {@inheritDoc}. */
+    public void targetFinished(BuildEvent event) {
+        if (initialized) {
+            String targetName = event.getTarget().getName();
+            Logger cat = Logger.getLogger(Target.class.getName());
+            if (event.getException() == null) {
+                cat.info("Target \"" + targetName + "\" finished.");
+            } else {
+                cat.error("Target \"" + targetName
+                    + "\" finished with error.", event.getException());
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#taskStarted
+     */
+    /** {@inheritDoc}. */
+    public void taskStarted(BuildEvent event) {
+        if (initialized) {
+            Task task = event.getTask();
+            Logger log = Logger.getLogger(task.getClass().getName());
+            log.info("Task \"" + task.getTaskName() + "\" started.");
+        }
+    }
+
+    /**
+     * @see BuildListener#taskFinished
+     */
+    /** {@inheritDoc}. */
+    public void taskFinished(BuildEvent event) {
+        if (initialized) {
+            Task task = event.getTask();
+            Logger log = Logger.getLogger(task.getClass().getName());
+            if (event.getException() == null) {
+                log.info("Task \"" + task.getTaskName() + "\" finished.");
+            } else {
+                log.error("Task \"" + task.getTaskName()
+                    + "\" finished with error.", event.getException());
+            }
+        }
+    }
+
+    /**
+     * @see BuildListener#messageLogged
+     */
+    /** {@inheritDoc}. */
+    public void messageLogged(BuildEvent event) {
+        if (initialized) {
+            Object categoryObject = event.getTask();
+            if (categoryObject == null) {
+                categoryObject = event.getTarget();
+                if (categoryObject == null) {
+                    categoryObject = event.getProject();
+                }
+            }
+
+            Logger log
+                = Logger.getLogger(categoryObject.getClass().getName());
+            switch (event.getPriority()) {
+                case Project.MSG_ERR:
+                    log.error(event.getMessage());
+                    break;
+                case Project.MSG_WARN:
+                    log.warn(event.getMessage());
+                    break;
+                case Project.MSG_INFO:
+                    log.info(event.getMessage());
+                    break;
+                case Project.MSG_VERBOSE:
+                    log.debug(event.getMessage());
+                    break;
+                case Project.MSG_DEBUG:
+                    log.debug(event.getMessage());
+                    break;
+                default:
+                    log.error(event.getMessage());
+                    break;
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/MailLogger.java b/trunk/src/main/org/apache/tools/ant/listener/MailLogger.java
new file mode 100644
index 0000000..60732b0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/MailLogger.java
@@ -0,0 +1,344 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.listener;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.email.EmailAddress;
+import org.apache.tools.ant.taskdefs.email.Message;
+import org.apache.tools.ant.taskdefs.email.Mailer;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.mail.MailMessage;
+
+/**
+ *  Buffers log messages from DefaultLogger, and sends an e-mail with the
+ *  results. The following Project properties are used to send the mail.
+ *  <ul>
+ *    <li> MailLogger.mailhost [default: localhost] - Mail server to use</li>
+ *    <li> MailLogger.port [default: 25] - Default port for SMTP </li>
+ *    <li> MailLogger.from [required] - Mail "from" address</li>
+ *    <li> MailLogger.failure.notify [default: true] - Send build failure
+ *    e-mails?</li>
+ *    <li> MailLogger.success.notify [default: true] - Send build success
+ *    e-mails?</li>
+ *    <li> MailLogger.failure.to [required if failure mail to be sent] - Address
+ *    to send failure messages to</li>
+ *    <li> MailLogger.success.to [required if success mail to be sent] - Address
+ *    to send success messages to</li>
+ *    <li> MailLogger.failure.subject [default: "Build Failure"] - Subject of
+ *    failed build</li>
+ *    <li> MailLogger.success.subject [default: "Build Success"] - Subject of
+ *    successful build</li>
+ *  </ul>
+ *  These properties are set using standard Ant property setting mechanisms
+ *  (&lt;property&gt;, command-line -D, etc). Ant properties can be overridden
+ *  by specifying the filename of a properties file in the <i>
+ *  MailLogger.properties.file property</i> . Any properties defined in that
+ *  file will override Ant properties.
+ *
+ */
+public class MailLogger extends DefaultLogger {
+    /** Buffer in which the message is constructed prior to sending */
+    private StringBuffer buffer = new StringBuffer();
+
+    /**
+     *  Sends an e-mail with the log results.
+     *
+     * @param event the build finished event
+     */
+    public void buildFinished(BuildEvent event) {
+        super.buildFinished(event);
+
+        Project project = event.getProject();
+        Hashtable properties = project.getProperties();
+
+        // overlay specified properties file (if any), which overrides project
+        // settings
+        Properties fileProperties = new Properties();
+        String filename = (String) properties.get("MailLogger.properties.file");
+        if (filename != null) {
+            InputStream is = null;
+            try {
+                is = new FileInputStream(filename);
+                fileProperties.load(is);
+            } catch (IOException ioe) {
+                // ignore because properties file is not required
+            } finally {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+        }
+
+        for (Enumeration e = fileProperties.keys(); e.hasMoreElements();) {
+            String key = (String) e.nextElement();
+            String value = fileProperties.getProperty(key);
+            properties.put(key, project.replaceProperties(value));
+        }
+
+        boolean success = (event.getException() == null);
+        String prefix = success ? "success" : "failure";
+
+        try {
+            boolean notify = Project.toBoolean(getValue(properties,
+                    prefix + ".notify", "on"));
+
+            if (!notify) {
+                return;
+            }
+            Values values = new Values()
+                .mailhost(getValue(properties, "mailhost", "localhost"))
+                .port(Integer.parseInt(
+                          getValue(
+                              properties, "port",
+                              String.valueOf(MailMessage.DEFAULT_PORT))))
+                .user(getValue(properties, "user", ""))
+                .password(getValue(properties, "password", ""))
+                .ssl(Project.toBoolean(getValue(properties,
+                                                "ssl", "off")))
+                .from(getValue(properties, "from", null))
+                .replytoList(getValue(properties, "replyto", ""))
+                .toList(getValue(properties, prefix + ".to", null))
+                .subject(getValue(
+                             properties, prefix + ".subject",
+                             (success) ? "Build Success" : "Build Failure"));
+            if (values.user().equals("")
+                && values.password().equals("")
+                && !values.ssl()) {
+                sendMail(values, buffer.substring(0));
+            } else {
+                sendMimeMail(
+                    event.getProject(), values, buffer.substring(0));
+            }
+        } catch (Exception e) {
+            System.out.println("MailLogger failed to send e-mail!");
+            e.printStackTrace(System.err);
+        }
+    }
+
+    private static class Values {
+        private String mailhost;
+        public String mailhost() {
+            return mailhost;
+        }
+        public Values mailhost(String mailhost) {
+            this.mailhost = mailhost;
+            return this;
+        }
+        private int port;
+        public int port() {
+            return port;
+        }
+        public Values port(int port) {
+            this.port = port;
+            return this;
+        }
+        private String user;
+        public String user() {
+            return user;
+        }
+        public Values user(String user) {
+            this.user = user;
+            return this;
+        }
+        private String password;
+        public String password() {
+            return password;
+        }
+        public Values password(String password) {
+            this.password = password;
+            return this;
+        }
+        private boolean ssl;
+        public boolean ssl() {
+            return ssl;
+        }
+        public Values ssl(boolean ssl) {
+            this.ssl = ssl;
+            return this;
+        }
+        private String from;
+        public String from() {
+            return from;
+        }
+        public Values from(String from) {
+            this.from = from;
+            return this;
+        }
+        private String replytoList;
+        public String replytoList() {
+            return replytoList;
+        }
+        public Values replytoList(String replytoList) {
+            this.replytoList = replytoList;
+            return this;
+        }
+        private String toList;
+        public String toList() {
+            return toList;
+        }
+        public Values toList(String toList) {
+            this.toList = toList;
+            return this;
+        }
+        private String subject;
+        public String subject() {
+            return subject;
+        }
+        public Values subject(String subject) {
+            this.subject = subject;
+            return this;
+        }
+    }
+
+    /**
+     *  Receives and buffers log messages.
+     *
+     * @param message the message being logger
+     */
+    protected void log(String message) {
+        buffer.append(message).append(StringUtils.LINE_SEP);
+    }
+
+
+    /**
+     *  Gets the value of a property.
+     *
+     * @param  properties     Properties to obtain value from
+     * @param  name           suffix of property name. "MailLogger." will be
+     *      prepended internally.
+     * @param  defaultValue   value returned if not present in the properties.
+     *      Set to null to make required.
+     * @return                The value of the property, or default value.
+     * @exception  Exception  thrown if no default value is specified and the
+     *      property is not present in properties.
+     */
+    private String getValue(Hashtable properties, String name,
+                            String defaultValue) throws Exception {
+        String propertyName = "MailLogger." + name;
+        String value = (String) properties.get(propertyName);
+
+        if (value == null) {
+            value = defaultValue;
+        }
+
+        if (value == null) {
+            throw new Exception("Missing required parameter: " + propertyName);
+        }
+
+        return value;
+    }
+
+
+    /**
+     *  Send the mail
+     * @param  values           the various values.
+     * @param  message          mail body
+     * @exception  IOException  thrown if sending message fails
+     */
+    private void sendMail(Values values, String message) throws IOException {
+        MailMessage mailMessage = new MailMessage(
+            values.mailhost(), values.port());
+        mailMessage.setHeader("Date", DateUtils.getDateForHeader());
+
+        mailMessage.from(values.from());
+        if (!values.replytoList().equals("")) {
+            StringTokenizer t = new StringTokenizer(
+                values.replytoList(), ", ", false);
+            while (t.hasMoreTokens()) {
+                mailMessage.replyto(t.nextToken());
+            }
+        }
+        StringTokenizer t = new StringTokenizer(values.toList(), ", ", false);
+        while (t.hasMoreTokens()) {
+            mailMessage.to(t.nextToken());
+        }
+
+        mailMessage.setSubject(values.subject());
+
+        PrintStream ps = mailMessage.getPrintStream();
+        ps.println(message);
+
+        mailMessage.sendAndClose();
+    }
+    /**
+     *  Send the mail  (MimeMail)
+     * @param  project          current ant project
+     * @param  values           various values
+     * @param  message          mail body
+     */
+    private void sendMimeMail(Project project, Values values, String message) {
+        // convert the replyTo string into a vector of emailaddresses
+        Mailer mailer = null;
+        try {
+            mailer = (Mailer) ClasspathUtils.newInstance(
+                    "org.apache.tools.ant.taskdefs.email.MimeMailer",
+                    MailLogger.class.getClassLoader(), Mailer.class);
+        } catch (BuildException e) {
+            Throwable t = e.getCause() == null ? e : e.getCause();
+            log("Failed to initialise MIME mail: " + t.getMessage());
+            return;
+        }
+        Vector replyToList = vectorizeEmailAddresses(values.replytoList());
+        mailer.setHost(values.mailhost());
+        mailer.setPort(values.port());
+        mailer.setUser(values.user());
+        mailer.setPassword(values.password());
+        mailer.setSSL(values.ssl());
+        Message mymessage = new Message(message);
+        mymessage.setProject(project);
+        mailer.setMessage(mymessage);
+        mailer.setFrom(new EmailAddress(values.from()));
+        mailer.setReplyToList(replyToList);
+        Vector toList = vectorizeEmailAddresses(values.toList());
+        mailer.setToList(toList);
+        mailer.setCcList(new Vector());
+        mailer.setBccList(new Vector());
+        mailer.setFiles(new Vector());
+        mailer.setSubject(values.subject());
+        mailer.send();
+    }
+    private Vector vectorizeEmailAddresses(String listString) {
+        Vector emailList = new Vector();
+        StringTokenizer tokens = new StringTokenizer(listString, ",");
+        while (tokens.hasMoreTokens()) {
+            emailList.addElement(new EmailAddress(tokens.nextToken()));
+        }
+        return emailList;
+    }
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/listener/ProfileLogger.java b/trunk/src/main/org/apache/tools/ant/listener/ProfileLogger.java
new file mode 100644
index 0000000..5517b76
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/ProfileLogger.java
@@ -0,0 +1,112 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant.listener;

+

+import java.util.Date;

+import java.util.HashMap;

+import java.util.Map;

+

+import org.apache.tools.ant.BuildEvent;

+import org.apache.tools.ant.DefaultLogger;

+import org.apache.tools.ant.util.StringUtils;

+

+/**

+ * This is a special logger that is designed to profile builds.

+ *

+ * @since Ant1.8

+ */

+public class ProfileLogger extends DefaultLogger {

+

+    private Map profileData = new HashMap(); // <Object, Date>

+

+    /**

+     * Logs a message to say that the target has started.

+     *

+     * @param event

+     *            An event with any relevant extra information. Must not be

+     *            <code>null</code>.

+     */

+    public void targetStarted(BuildEvent event) {

+        Date now = new Date();

+        String name = "Target " + event.getTarget().getName();

+        logStart(event, now, name);

+        profileData.put(event.getTarget(), now);

+    }

+

+    /**

+     * Logs a message to say that the target has finished.

+     *

+     * @param event

+     *            An event with any relevant extra information. Must not be

+     *            <code>null</code>.

+     */

+    public void targetFinished(BuildEvent event) {

+        Date start = (Date) profileData.remove(event.getTarget());

+        String name = "Target " + event.getTarget().getName();

+        logFinish(event, start, name);

+    }

+

+    /**

+     * Logs a message to say that the task has started.

+     *

+     * @param event

+     *            An event with any relevant extra information. Must not be

+     *            <code>null</code>.

+     */

+    public void taskStarted(BuildEvent event) {

+        String name = event.getTask().getTaskName();

+        Date now = new Date();

+        logStart(event, now, name);

+        profileData.put(event.getTask(), now);

+    }

+

+    /**

+     * Logs a message to say that the task has finished.

+     *

+     * @param event

+     *            An event with any relevant extra information. Must not be

+     *            <code>null</code>.

+     */

+    public void taskFinished(BuildEvent event) {

+        Date start = (Date) profileData.remove(event.getTask());

+        String name = event.getTask().getTaskName();

+        logFinish(event, start, name);

+    }

+

+    private void logFinish(BuildEvent event, Date start, String name) {

+        Date now = new Date();

+        String msg = null;

+        if (start != null) {

+            long diff = now.getTime() - start.getTime();

+            msg = StringUtils.LINE_SEP + name + ": finished" + now + " ("

+                    + diff + "ms)";

+        } else {

+            msg = StringUtils.LINE_SEP + name + ": finished" + now

+                    + " (unknown duration, start not detected)";

+        }

+        printMessage(msg, out, event.getPriority());

+        log(msg);

+    }

+

+    private void logStart(BuildEvent event, Date start, String name) {

+        String msg = StringUtils.LINE_SEP + name + ": started " + start;

+        printMessage(msg, out, event.getPriority());

+        log(msg);

+    }

+

+}

diff --git a/trunk/src/main/org/apache/tools/ant/listener/TimestampedLogger.java b/trunk/src/main/org/apache/tools/ant/listener/TimestampedLogger.java
new file mode 100644
index 0000000..91296e3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/TimestampedLogger.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.listener;
+
+import org.apache.tools.ant.DefaultLogger;
+
+/**
+ * Like a normal logger, except with timed outputs
+ */
+public class TimestampedLogger extends DefaultLogger {
+
+    /**
+     * what appears between the old message and the new
+     */
+    public static final String SPACER = " - at ";
+
+
+    /**
+     * This is an override point: the message that indicates whether a build failed.
+     * Subclasses can change/enhance the message.
+     *
+     * @return The classic "BUILD FAILED" plus a timestamp
+     */
+    protected String getBuildFailedMessage() {
+        return super.getBuildFailedMessage() + SPACER + getTimestamp();
+    }
+
+    /**
+     * This is an override point: the message that indicates that a build succeeded.
+     * Subclasses can change/enhance the message.
+     *
+     * @return The classic "BUILD SUCCESSFUL" plus a timestamp
+     */
+    protected String getBuildSuccessfulMessage() {
+        return super.getBuildSuccessfulMessage() + SPACER + getTimestamp();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/listener/defaults.properties b/trunk/src/main/org/apache/tools/ant/listener/defaults.properties
new file mode 100644
index 0000000..2994382
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/listener/defaults.properties
@@ -0,0 +1,58 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+####################################################
+#
+#           ANSI COLOR LOGGER CONFIGURATION
+#
+# Format for AnsiColorLogger.*=
+#  Attribute;Foreground;Background
+#
+#  Attribute is one of the following:
+#  0 -> Reset All Attributes (return to normal mode)
+#  1 -> Bright (Usually turns on BOLD)
+#  2 -> Dim
+#  3 -> Underline
+#  5 -> link
+#  7 -> Reverse
+#  8 -> Hidden
+#
+#  Foreground is one of the following:
+#  30 -> Black
+#  31 -> Red
+#  32 -> Green
+#  33 -> Yellow
+#  34 -> Blue
+#  35 -> Magenta
+#  36 -> Cyan
+#  37 -> White
+#
+#  Background is one of the following:
+#  40 -> Black
+#  41 -> Red
+#  42 -> Green
+#  43 -> Yellow
+#  44 -> Blue
+#  45 -> Magenta
+#  46 -> Cyan
+#  47 -> White
+#
+####################################################
+
+AnsiColorLogger.ERROR_COLOR=2;31
+AnsiColorLogger.WARNING_COLOR=2;35
+AnsiColorLogger.INFO_COLOR=2;36
+AnsiColorLogger.VERBOSE_COLOR=2;32
+AnsiColorLogger.DEBUG_COLOR=2;34
diff --git a/trunk/src/main/org/apache/tools/ant/loader/AntClassLoader2.java b/trunk/src/main/org/apache/tools/ant/loader/AntClassLoader2.java
new file mode 100644
index 0000000..1a4cac6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/loader/AntClassLoader2.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.loader;
+
+import org.apache.tools.ant.AntClassLoader;
+
+/**
+ * @deprecated since 1.7
+ *             Just use {@link AntClassLoader} itself.
+ */
+public class AntClassLoader2 extends AntClassLoader {
+    /** No args constructor. */
+    public AntClassLoader2() {
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/property/GetProperty.java b/trunk/src/main/org/apache/tools/ant/property/GetProperty.java
new file mode 100644
index 0000000..2ca2baa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/GetProperty.java
@@ -0,0 +1,28 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+/** Interface to a class (normally PropertyHelper) to get a property */
+public interface GetProperty {
+    /**
+     * Returns the value of a property if it is set.
+     * @param name name of the property.
+     * @return the property value, or null for no match or for name being null.
+     */
+    Object getProperty(String name);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/property/NullReturn.java b/trunk/src/main/org/apache/tools/ant/property/NullReturn.java
new file mode 100644
index 0000000..2012afe
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/NullReturn.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+/** Class to represent a null and to stop the chain of lookups. */
+public final class NullReturn {
+    /** a value to use in a property helper to stop looking properties */
+    public static final NullReturn NULL = new NullReturn();
+
+    /** Private constructor */
+    private NullReturn() {
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/property/ParseNextProperty.java b/trunk/src/main/org/apache/tools/ant/property/ParseNextProperty.java
new file mode 100644
index 0000000..72dda73
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/ParseNextProperty.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+import java.text.ParsePosition;
+
+import org.apache.tools.ant.Project;
+
+/** Interface to parse a property */
+public interface ParseNextProperty {
+    /**
+     * Get the current project.
+     * @return the current ant project.
+     */
+    Project getProject();
+
+    /**
+     * Return any property that can be parsed from the specified position
+     * in the specified String.
+     * @param value String to parse
+     * @param pos ParsePosition
+     * @return Object or null if no property is at the current location.
+     */
+    Object parseNextProperty(String value, ParsePosition pos);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/property/ParseProperties.java b/trunk/src/main/org/apache/tools/ant/property/ParseProperties.java
new file mode 100644
index 0000000..afb2586
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/ParseProperties.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+import java.text.ParsePosition;
+import java.util.Collection;
+import java.util.Iterator;
+import org.apache.tools.ant.Project;
+
+/**
+ * Parse properties using a collection of expanders.
+ */
+public class ParseProperties implements ParseNextProperty {
+
+    private final Project project;
+    private final GetProperty getProperty;
+    private final Collection expanders;
+
+    /**
+     * Constructor with a getProperty.
+     * @param project the current ant project.
+     * @param expanders a sequence of exapanders
+     * @param getProperty property resolver.
+     */
+    public ParseProperties(
+        Project project, Collection expanders, GetProperty getProperty) {
+        this.project = project;
+        this.expanders = expanders;
+        this.getProperty = getProperty;
+    }
+
+    /**
+     * Get the project.
+     * @return the current ant project.
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Decode properties from a String representation.  If the entire
+     * contents of the String resolve to a single property, that value
+     * is returned.  Otherwise a String is returned.
+     *
+     * @param value The string to be scanned for property references.
+     *              May be <code>null</code>, in which case this
+     *              method returns immediately with no effect.
+     *
+     * @return the original string with the properties replaced, or
+     *         <code>null</code> if the original string is <code>null</code>.
+     */
+    public Object parseProperties(String value) {
+        if (value == null || "".equals(value) || value.indexOf('$') == -1) {
+            return value;
+        }
+        ParsePosition pos = new ParsePosition(0);
+        Object o = parseNextProperty(value, pos);
+        if (o != null && pos.getIndex() == value.length()) {
+            return o;
+        }
+        StringBuffer sb = new StringBuffer(value.length() * 2);
+        if (o == null) {
+            sb.append(value.charAt(pos.getIndex()));
+            pos.setIndex(pos.getIndex() + 1);
+        } else {
+            sb.append(o);
+        }
+        while (pos.getIndex() < value.length()) {
+            o = parseNextProperty(value, pos);
+            if (o == null) {
+                sb.append(value.charAt(pos.getIndex()));
+                pos.setIndex(pos.getIndex() + 1);
+            } else {
+                sb.append(o);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Learn whether a String contains replaceable properties.
+     * @param value the String to check.
+     * @return <code>true</code> if <code>value</code> contains property notation.
+     */
+    public boolean containsProperties(String value) {
+        if (value == null) {
+            return false;
+        }
+        for (ParsePosition pos = new ParsePosition(0); pos.getIndex() < value.length();) {
+            if (parsePropertyName(value, pos) != null) {
+                return true;
+            }
+            pos.setIndex(pos.getIndex() + 1);
+        }
+        return false;
+    }
+
+    /**
+     * Return any property that can be parsed from the specified position
+     * in the specified String.
+     * @param value String to parse
+     * @param pos ParsePosition
+     * @return Object or null if no property is at the current location.
+     */
+    public Object parseNextProperty(String value, ParsePosition pos) {
+        int start = pos.getIndex();
+        String propertyName = parsePropertyName(value, pos);
+        if (propertyName != null) {
+            Object result = getProperty(propertyName);
+            if (result != null) {
+                return result;
+            }
+            if (project != null) {
+                project.log(
+                    "Property \"" + propertyName
+                    + "\" has not been set", Project.MSG_VERBOSE);
+            }
+            return value.substring(start, pos.getIndex());
+        }
+        return null;
+    }
+
+    private String parsePropertyName(String value, ParsePosition pos) {
+        for (Iterator iter = expanders.iterator(); iter.hasNext();) {
+            String propertyName = ((PropertyExpander) iter.next())
+                .parsePropertyName(value, pos, this);
+            if (propertyName == null) {
+                continue;
+            }
+            return propertyName;
+        }
+        return null;
+    }
+
+    private Object getProperty(String propertyName) {
+        return getProperty.getProperty(propertyName);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/property/PropertyExpander.java b/trunk/src/main/org/apache/tools/ant/property/PropertyExpander.java
new file mode 100644
index 0000000..0fe44ee
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/PropertyExpander.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+import org.apache.tools.ant.PropertyHelper;
+
+import java.text.ParsePosition;
+
+/** Interface to a class (normally PropertyHelper) to get a property */
+public interface PropertyExpander extends PropertyHelper.Delegate {
+    /**
+     * Parse the next property name.
+     * @param s the String to parse.
+     * @param pos the ParsePosition in use.
+     * @param parseNextProperty parse next property
+     * @return parsed String if any, else <code>null</code>.
+     */
+    String parsePropertyName(
+        String s, ParsePosition pos, ParseNextProperty parseNextProperty);
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/property/ResolvePropertyMap.java b/trunk/src/main/org/apache/tools/ant/property/ResolvePropertyMap.java
new file mode 100644
index 0000000..2ec9724
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/ResolvePropertyMap.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.property;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collection;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+
+/**
+ *  Class to resolve properties in a map.
+ */
+public class ResolvePropertyMap implements GetProperty {
+    private final Set       seen = new HashSet();
+    private final ParseProperties parseProperties;
+    private final GetProperty    master;
+    private Map map;
+
+    /**
+     * Constructor with a master getproperty and a collection of expanders.
+     * @param project the current ant project.
+     * @param master the master property holder (usually PropertyHelper)
+     * @param expanders a collection of expanders (usually from PropertyHelper).
+     */
+    public ResolvePropertyMap(
+        Project project, GetProperty master, Collection expanders) {
+        this.master = master;
+        this.parseProperties = new ParseProperties(project, expanders, this);
+    }
+
+    /**
+     * Returns the value of a property if it is set.
+     * @param name name of the property.
+     * @return the property value, or null for no match or for name being null.
+     */
+    public Object getProperty(String name) {
+        if (seen.contains(name)) {
+            throw new BuildException(
+                "Property " + name + " was circularly " + "defined.");
+        }
+        // Note: the master overrides (even if the name is subsequently
+        //       prefixed)
+        Object masterProperty = master.getProperty(name);
+        if (masterProperty != null) {
+            return masterProperty;
+        }
+        try {
+            seen.add(name);
+            return parseProperties.parseProperties((String) map.get(name));
+        } finally {
+            seen.remove(name);
+        }
+    }
+
+    /**
+     * The action method - resolves all the properties in a map.
+     * @param map the map to resolve properties in.
+     */
+    public void resolveAllProperties(Map map) {
+        this.map = map; // The map gets used in the getProperty callback
+        for (Iterator i = map.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            Object result = getProperty(key);
+            String value = result == null ? "" : result.toString();
+            map.put(key, value);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/property/package.html b/trunk/src/main/org/apache/tools/ant/property/package.html
new file mode 100644
index 0000000..7a497ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/property/package.html
@@ -0,0 +1,19 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<body>
+  Contains helper classes for ant properties.
+</body>
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractCvsTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractCvsTask.java
new file mode 100644
index 0000000..a9a5bc8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractCvsTask.java
@@ -0,0 +1,832 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * original Cvs.java 1.20
+ *
+ *  NOTE: This implementation has been moved here from Cvs.java with
+ *  the addition of some accessors for extensibility.  Another task
+ *  can extend this with some customized output processing.
+ *
+ * @since Ant 1.5
+ */
+public abstract class AbstractCvsTask extends Task {
+    /**
+     * Default compression level to use, if compression is enabled via
+     * setCompression( true ).
+     */
+    public static final int DEFAULT_COMPRESSION_LEVEL = 3;
+    private static final int MAXIMUM_COMRESSION_LEVEL = 9;
+
+    private Commandline cmd = new Commandline();
+
+    /** list of Commandline children */
+    private Vector vecCommandlines = new Vector();
+
+    /**
+     * the CVSROOT variable.
+     */
+    private String cvsRoot;
+
+    /**
+     * the CVS_RSH variable.
+     */
+    private String cvsRsh;
+
+    /**
+     * the package/module to check out.
+     */
+    private String cvsPackage;
+    /**
+     * the tag
+     */
+    private String tag;
+    /**
+     * the default command.
+     */
+    private static final String DEFAULT_COMMAND = "checkout";
+    /**
+     * the CVS command to execute.
+     */
+    private String command = null;
+
+    /**
+     * suppress information messages.
+     */
+    private boolean quiet = false;
+
+    /**
+     * suppress all messages.
+     */
+    private boolean reallyquiet = false;
+
+    /**
+     * compression level to use.
+     */
+    private int compression = 0;
+
+    /**
+     * report only, don't change any files.
+     */
+    private boolean noexec = false;
+
+    /**
+     * CVS port
+     */
+    private int port = 0;
+
+    /**
+     * CVS password file
+     */
+    private File passFile = null;
+
+    /**
+     * the directory where the checked out files should be placed.
+     */
+    private File dest;
+
+    /** whether or not to append stdout/stderr to existing files */
+    private boolean append = false;
+
+    /**
+     * the file to direct standard output from the command.
+     */
+    private File output;
+
+    /**
+     * the file to direct standard error from the command.
+     */
+    private File error;
+
+    /**
+     * If true it will stop the build if cvs exits with error.
+     * Default is false. (Iulian)
+     */
+    private boolean failOnError = false;
+
+    /**
+     * Create accessors for the following, to allow different handling of
+     * the output.
+     */
+    private ExecuteStreamHandler executeStreamHandler;
+    private OutputStream outputStream;
+    private OutputStream errorStream;
+
+    /** empty no-arg constructor*/
+    public AbstractCvsTask() {
+        super();
+    }
+
+    /**
+     * sets the handler
+     * @param handler a handler able of processing the output and error streams from the cvs exe
+     */
+    public void setExecuteStreamHandler(ExecuteStreamHandler handler) {
+        this.executeStreamHandler = handler;
+    }
+
+    /**
+     * find the handler and instantiate it if it does not exist yet
+     * @return handler for output and error streams
+     */
+    protected ExecuteStreamHandler getExecuteStreamHandler() {
+
+        if (this.executeStreamHandler == null) {
+            setExecuteStreamHandler(new PumpStreamHandler(getOutputStream(),
+                                                          getErrorStream()));
+        }
+
+        return this.executeStreamHandler;
+    }
+
+    /**
+     * sets a stream to which the output from the cvs executable should be sent
+     * @param outputStream stream to which the stdout from cvs should go
+     */
+    protected void setOutputStream(OutputStream outputStream) {
+
+        this.outputStream = outputStream;
+    }
+
+    /**
+     * access the stream to which the stdout from cvs should go
+     * if this stream has already been set, it will be returned
+     * if the stream has not yet been set, if the attribute output
+     * has been set, the output stream will go to the output file
+     * otherwise the output will go to ant's logging system
+     * @return output stream to which cvs' stdout should go to
+     */
+    protected OutputStream getOutputStream() {
+
+        if (this.outputStream == null) {
+
+            if (output != null) {
+                try {
+                    setOutputStream(new PrintStream(
+                                        new BufferedOutputStream(
+                                            new FileOutputStream(output
+                                                                 .getPath(),
+                                                                 append))));
+                } catch (IOException e) {
+                    throw new BuildException(e, getLocation());
+                }
+            } else {
+                setOutputStream(new LogOutputStream(this, Project.MSG_INFO));
+            }
+        }
+
+        return this.outputStream;
+    }
+
+    /**
+     * sets a stream to which the stderr from the cvs exe should go
+     * @param errorStream an output stream willing to process stderr
+     */
+    protected void setErrorStream(OutputStream errorStream) {
+
+        this.errorStream = errorStream;
+    }
+
+    /**
+     * access the stream to which the stderr from cvs should go
+     * if this stream has already been set, it will be returned
+     * if the stream has not yet been set, if the attribute error
+     * has been set, the output stream will go to the file denoted by the error attribute
+     * otherwise the stderr output will go to ant's logging system
+     * @return output stream to which cvs' stderr should go to
+     */
+    protected OutputStream getErrorStream() {
+
+        if (this.errorStream == null) {
+
+            if (error != null) {
+
+                try {
+                    setErrorStream(new PrintStream(
+                                       new BufferedOutputStream(
+                                           new FileOutputStream(error.getPath(),
+                                                                append))));
+                } catch (IOException e) {
+                    throw new BuildException(e, getLocation());
+                }
+            } else {
+                setErrorStream(new LogOutputStream(this, Project.MSG_WARN));
+            }
+        }
+
+        return this.errorStream;
+    }
+
+    /**
+     * Sets up the environment for toExecute and then runs it.
+     * @param toExecute the command line to execute
+     * @throws BuildException if failonError is set to true and the cvs command fails
+     */
+    protected void runCommand(Commandline toExecute) throws BuildException {
+        // XXX: we should use JCVS (www.ice.com/JCVS) instead of
+        // command line execution so that we don't rely on having
+        // native CVS stuff around (SM)
+
+        // We can't do it ourselves as jCVS is GPLed, a third party task
+        // outside of jakarta repositories would be possible though (SB).
+
+        Environment env = new Environment();
+
+        if (port > 0) {
+            Environment.Variable var = new Environment.Variable();
+            var.setKey("CVS_CLIENT_PORT");
+            var.setValue(String.valueOf(port));
+            env.addVariable(var);
+        }
+
+        /**
+         * Need a better cross platform integration with <cvspass>, so
+         * use the same filename.
+         */
+        if (passFile == null) {
+
+            File defaultPassFile = new File(
+                System.getProperty("cygwin.user.home",
+                    System.getProperty("user.home"))
+                + File.separatorChar + ".cvspass");
+
+            if (defaultPassFile.exists()) {
+                this.setPassfile(defaultPassFile);
+            }
+        }
+
+        if (passFile != null) {
+            if (passFile.isFile() && passFile.canRead()) {
+                Environment.Variable var = new Environment.Variable();
+                var.setKey("CVS_PASSFILE");
+                var.setValue(String.valueOf(passFile));
+                env.addVariable(var);
+                log("Using cvs passfile: " + String.valueOf(passFile),
+                    Project.MSG_VERBOSE);
+            } else if (!passFile.canRead()) {
+                log("cvs passfile: " + String.valueOf(passFile)
+                    + " ignored as it is not readable",
+                    Project.MSG_WARN);
+            } else {
+                log("cvs passfile: " + String.valueOf(passFile)
+                    + " ignored as it is not a file",
+                    Project.MSG_WARN);
+            }
+        }
+
+        if (cvsRsh != null) {
+            Environment.Variable var = new Environment.Variable();
+            var.setKey("CVS_RSH");
+            var.setValue(String.valueOf(cvsRsh));
+            env.addVariable(var);
+        }
+
+        //
+        // Just call the getExecuteStreamHandler() and let it handle
+        //     the semantics of instantiation or retrieval.
+        //
+        Execute exe = new Execute(getExecuteStreamHandler(), null);
+
+        exe.setAntRun(getProject());
+        if (dest == null) {
+            dest = getProject().getBaseDir();
+        }
+
+        if (!dest.exists()) {
+            dest.mkdirs();
+        }
+
+        exe.setWorkingDirectory(dest);
+        exe.setCommandline(toExecute.getCommandline());
+        exe.setEnvironment(env.getVariables());
+
+        try {
+            String actualCommandLine = executeToString(exe);
+
+            log(actualCommandLine, Project.MSG_VERBOSE);
+            int retCode = exe.execute();
+            log("retCode=" + retCode, Project.MSG_DEBUG);
+
+            if (failOnError && Execute.isFailure(retCode)) {
+                throw new BuildException("cvs exited with error code "
+                                         + retCode
+                                         + StringUtils.LINE_SEP
+                                         + "Command line was ["
+                                         + actualCommandLine + "]",
+                                         getLocation());
+            }
+        } catch (IOException e) {
+            if (failOnError) {
+                throw new BuildException(e, getLocation());
+            }
+            log("Caught exception: " + e.getMessage(), Project.MSG_WARN);
+        } catch (BuildException e) {
+            if (failOnError) {
+                throw(e);
+            }
+            Throwable t = e.getException();
+            if (t == null) {
+                t = e;
+            }
+            log("Caught exception: " + t.getMessage(), Project.MSG_WARN);
+        } catch (Exception e) {
+            if (failOnError) {
+                throw new BuildException(e, getLocation());
+            }
+            log("Caught exception: " + e.getMessage(), Project.MSG_WARN);
+        }
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if failonerror is set to true and the
+     * cvs command fails.
+     */
+    public void execute() throws BuildException {
+
+        String savedCommand = getCommand();
+
+        if (this.getCommand() == null && vecCommandlines.size() == 0) {
+            // re-implement legacy behaviour:
+            this.setCommand(AbstractCvsTask.DEFAULT_COMMAND);
+        }
+
+        String c = this.getCommand();
+        Commandline cloned = null;
+        if (c != null) {
+            cloned = (Commandline) cmd.clone();
+            cloned.createArgument(true).setLine(c);
+            this.addConfiguredCommandline(cloned, true);
+        }
+
+        try {
+            for (int i = 0; i < vecCommandlines.size(); i++) {
+                this.runCommand((Commandline) vecCommandlines.elementAt(i));
+            }
+        } finally {
+            if (cloned != null) {
+                removeCommandline(cloned);
+            }
+            setCommand(savedCommand);
+            FileUtils.close(outputStream);
+            FileUtils.close(errorStream);
+        }
+    }
+
+    private String executeToString(Execute execute) {
+
+        String cmdLine = Commandline.describeCommand(execute
+                .getCommandline());
+        StringBuffer stringBuffer = removeCvsPassword(cmdLine);
+
+        String newLine = StringUtils.LINE_SEP;
+        String[] variableArray = execute.getEnvironment();
+
+        if (variableArray != null) {
+            stringBuffer.append(newLine);
+            stringBuffer.append(newLine);
+            stringBuffer.append("environment:");
+            stringBuffer.append(newLine);
+            for (int z = 0; z < variableArray.length; z++) {
+                stringBuffer.append(newLine);
+                stringBuffer.append("\t");
+                stringBuffer.append(variableArray[z]);
+            }
+        }
+
+        return stringBuffer.toString();
+    }
+
+    /**
+     * Removes the cvs password from the command line, if given on the command
+     * line. This password can be given on the command line in the cvsRoot
+     * -d:pserver:user:password@server:path
+     * It has to be noted that the password may be omitted altogether.
+     * @param cmdLine the CVS command line
+     * @return a StringBuffer where the password has been removed (if available)
+     */
+    private StringBuffer removeCvsPassword(String cmdLine) {
+        StringBuffer stringBuffer = new StringBuffer(cmdLine);
+
+        int start = cmdLine.indexOf("-d:");
+
+        if (start >= 0) {
+            int stop = cmdLine.indexOf("@", start);
+            int startproto = cmdLine.indexOf(":", start);
+            int startuser = cmdLine.indexOf(":", startproto + 1);
+            int startpass = cmdLine.indexOf(":", startuser + 1);
+            stop = cmdLine.indexOf("@", start);
+            if (stop >= 0 && startpass > startproto && startpass < stop) {
+                for (int i = startpass + 1; i < stop; i++) {
+                    stringBuffer.replace(i, i + 1, "*");
+                }
+            }
+        }
+        return stringBuffer;
+    }
+
+    /**
+     * The CVSROOT variable.
+     *
+     * @param root
+     *            the CVSROOT variable
+     */
+    public void setCvsRoot(String root) {
+
+        // Check if not real cvsroot => set it to null
+        if (root != null) {
+            if (root.trim().equals("")) {
+                root = null;
+            }
+        }
+
+        this.cvsRoot = root;
+    }
+
+    /**
+     * access the CVSROOT variable
+     * @return CVSROOT
+     */
+    public String getCvsRoot() {
+
+        return this.cvsRoot;
+    }
+
+    /**
+     * The CVS_RSH variable.
+     *
+     * @param rsh the CVS_RSH variable
+     */
+    public void setCvsRsh(String rsh) {
+        // Check if not real cvsrsh => set it to null
+        if (rsh != null) {
+            if (rsh.trim().equals("")) {
+                rsh = null;
+            }
+        }
+
+        this.cvsRsh = rsh;
+    }
+
+    /**
+     * access the CVS_RSH variable
+     * @return the CVS_RSH variable
+     */
+    public String getCvsRsh() {
+
+        return this.cvsRsh;
+    }
+
+    /**
+     * Port used by CVS to communicate with the server.
+     *
+     * @param port port of CVS
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * access the port of CVS
+     * @return the port of CVS
+     */
+    public int getPort() {
+
+        return this.port;
+    }
+
+    /**
+     * Password file to read passwords from.
+     *
+     * @param passFile password file to read passwords from
+     */
+    public void setPassfile(File passFile) {
+        this.passFile = passFile;
+    }
+
+    /**
+     * find the password file
+     * @return password file
+     */
+    public File getPassFile() {
+
+        return this.passFile;
+    }
+
+    /**
+     * The directory where the checked out files should be placed.
+     *
+     * <p>Note that this is different from CVS's -d command line
+     * switch as Ant will never shorten pathnames to avoid empty
+     * directories.</p>
+     *
+     * @param dest directory where the checked out files should be placed
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    /**
+     * get the file where the checked out files should be placed
+     *
+     * @return directory where the checked out files should be placed
+     */
+    public File getDest() {
+
+        return this.dest;
+    }
+
+    /**
+     * The package/module to operate upon.
+     *
+     * @param p package or module to operate upon
+     */
+    public void setPackage(String p) {
+        this.cvsPackage = p;
+    }
+
+    /**
+     * access the package or module to operate upon
+     *
+     * @return package/module
+     */
+    public String getPackage() {
+
+        return this.cvsPackage;
+    }
+    /**
+     * tag or branch
+     * @return tag or branch
+     * @since ant 1.6.1
+     */
+    public String getTag() {
+        return tag;
+    }
+
+    /**
+     * The tag of the package/module to operate upon.
+     * @param p tag
+     */
+    public void setTag(String p) {
+        // Check if not real tag => set it to null
+        if (p != null && p.trim().length() > 0) {
+            tag = p;
+            addCommandArgument("-r" + p);
+        }
+    }
+
+    /**
+     * This needs to be public to allow configuration
+     *      of commands externally.
+     * @param arg command argument
+     */
+    public void addCommandArgument(String arg) {
+        this.addCommandArgument(cmd, arg);
+    }
+
+    /**
+     * This method adds a command line argument to an external command.
+     *
+     * I do not understand what this method does in this class ???
+     * particularly not why it is public ????
+     * AntoineLL July 23d 2003
+     *
+     * @param c  command line to which one argument should be added
+     * @param arg argument to add
+     */
+    public void addCommandArgument(Commandline c, String arg) {
+        c.createArgument().setValue(arg);
+    }
+
+
+    /**
+     * Use the most recent revision no later than the given date.
+     * @param p a date as string in a format that the CVS executable
+     * can understand see man cvs
+     */
+    public void setDate(String p) {
+        if (p != null && p.trim().length() > 0) {
+            addCommandArgument("-D");
+            addCommandArgument(p);
+        }
+    }
+
+    /**
+     * The CVS command to execute.
+     *
+     * This should be deprecated, it is better to use the Commandline class ?
+     * AntoineLL July 23d 2003
+     *
+     * @param c a command as string
+     */
+    public void setCommand(String c) {
+        this.command = c;
+    }
+    /**
+     * accessor to a command line as string
+     *
+     * This should be deprecated
+     * AntoineLL July 23d 2003
+     *
+     * @return command line as string
+     */
+    public String getCommand() {
+        return this.command;
+    }
+
+    /**
+     * If true, suppress informational messages.
+     * @param q  if true, suppress informational messages
+     */
+    public void setQuiet(boolean q) {
+        quiet = q;
+    }
+
+    /**
+     * If true, suppress all messages.
+     * @param q  if true, suppress all messages
+     * @since Ant 1.6
+     */
+    public void setReallyquiet(boolean q) {
+        reallyquiet = q;
+    }
+
+
+    /**
+     * If true, report only and don't change any files.
+     *
+     * @param ne if true, report only and do not change any files.
+     */
+    public void setNoexec(boolean ne) {
+        noexec = ne;
+    }
+
+    /**
+     * The file to direct standard output from the command.
+     * @param output a file to which stdout should go
+     */
+    public void setOutput(File output) {
+        this.output = output;
+    }
+
+    /**
+     * The file to direct standard error from the command.
+     *
+     * @param error a file to which stderr should go
+     */
+    public void setError(File error) {
+        this.error = error;
+    }
+
+    /**
+     * Whether to append output/error when redirecting to a file.
+     * @param value true indicated you want to append
+     */
+    public void setAppend(boolean value) {
+        this.append = value;
+    }
+
+    /**
+     * Stop the build process if the command exits with
+     * a return code other than 0.
+     * Defaults to false.
+     * @param failOnError stop the build process if the command exits with
+     * a return code other than 0
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * Configure a commandline element for things like cvsRoot, quiet, etc.
+     * @param c the command line which will be configured
+     * if the commandline is initially null, the function is a noop
+     * otherwise the function append to the commandline arguments concerning
+     * <ul>
+     * <li>
+     * cvs package
+     * </li>
+     * <li>
+     * compression
+     * </li>
+     * <li>
+     * quiet or reallyquiet
+     * </li>
+     * <li>cvsroot</li>
+     * <li>noexec</li>
+     * </ul>
+     */
+    protected void configureCommandline(Commandline c) {
+        if (c == null) {
+            return;
+        }
+        c.setExecutable("cvs");
+        if (cvsPackage != null) {
+            c.createArgument().setLine(cvsPackage);
+        }
+        if (this.compression > 0
+            && this.compression <= MAXIMUM_COMRESSION_LEVEL) {
+            c.createArgument(true).setValue("-z" + this.compression);
+        }
+        if (quiet && !reallyquiet) {
+            c.createArgument(true).setValue("-q");
+        }
+        if (reallyquiet) {
+            c.createArgument(true).setValue("-Q");
+        }
+        if (noexec) {
+            c.createArgument(true).setValue("-n");
+        }
+        if (cvsRoot != null) {
+            c.createArgument(true).setLine("-d" + cvsRoot);
+        }
+    }
+
+    /**
+     * remove a particular command from a vector of command lines
+     * @param c command line which should be removed
+     */
+    protected void removeCommandline(Commandline c) {
+        vecCommandlines.removeElement(c);
+    }
+
+    /**
+     * Adds direct command-line to execute.
+     * @param c command line to execute
+     */
+    public void addConfiguredCommandline(Commandline c) {
+        this.addConfiguredCommandline(c, false);
+    }
+
+    /**
+     * Configures and adds the given Commandline.
+     * @param c commandline to insert
+     * @param insertAtStart If true, c is
+     * inserted at the beginning of the vector of command lines
+    */
+    public void addConfiguredCommandline(Commandline c,
+                                         boolean insertAtStart) {
+        if (c == null) {
+            return;
+        }
+        this.configureCommandline(c);
+        if (insertAtStart) {
+            vecCommandlines.insertElementAt(c, 0);
+        } else {
+            vecCommandlines.addElement(c);
+        }
+    }
+
+    /**
+    * If set to a value 1-9 it adds -zN to the cvs command line, else
+    * it disables compression.
+     * @param level compression level 1 to 9
+    */
+    public void setCompressionLevel(int level) {
+        this.compression = level;
+    }
+
+    /**
+     * If true, this is the same as compressionlevel="3".
+     *
+     * @param usecomp If true, turns on compression using default
+     * level, AbstractCvsTask.DEFAULT_COMPRESSION_LEVEL.
+     */
+    public void setCompression(boolean usecomp) {
+        setCompressionLevel(usecomp
+            ? AbstractCvsTask.DEFAULT_COMPRESSION_LEVEL : 0);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractJarSignerTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractJarSignerTask.java
new file mode 100644
index 0000000..09e03d4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/AbstractJarSignerTask.java
@@ -0,0 +1,379 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.RedirectorElement;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * This is factored out from {@link SignJar}; a base class that can be used
+ * for both signing and verifying JAR files using jarsigner
+ */
+
+public abstract class AbstractJarSignerTask extends Task {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * The name of the jar file.
+     */
+    protected File jar;
+    /**
+     * The alias of signer.
+     */
+    protected String alias;
+    /**
+     * The url or path of keystore file.
+     */
+    protected String keystore;
+    /**
+     * password for the store
+     */
+    protected String storepass;
+    /**
+     * type of store,-storetype param
+     */
+    protected String storetype;
+    /**
+     * password for the key in the store
+     */
+    protected String keypass;
+    /**
+     * verbose output
+     */
+    protected boolean verbose;
+    /**
+     * The maximum amount of memory to use for Jar signer
+     */
+    protected String maxMemory;
+    /**
+     * the filesets of the jars to sign
+     */
+    protected Vector filesets = new Vector();
+    /**
+     * name of JDK program we are looking for
+     */
+    protected static final String JARSIGNER_COMMAND = "jarsigner";
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * redirector used to talk to the jarsigner program
+     */
+    private RedirectorElement redirector;
+
+    /**
+     * Java declarations -J-Dname=value
+     */
+    private Environment sysProperties = new Environment();
+
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_NO_SOURCE = "jar must be set through jar attribute "
+            + "or nested filesets";
+
+    /**
+     * Path holding all non-filesets of filesystem resources we want to sign.
+     *
+     * @since Ant 1.7
+     */
+    private Path path = null;
+
+    /**
+     * Set the maximum memory to be used by the jarsigner process
+     *
+     * @param max a string indicating the maximum memory according to the JVM
+     *            conventions (e.g. 128m is 128 Megabytes)
+     */
+    public void setMaxmemory(String max) {
+        maxMemory = max;
+    }
+
+    /**
+     * the jar file to sign; required
+     *
+     * @param jar the jar file to sign
+     */
+    public void setJar(final File jar) {
+        this.jar = jar;
+    }
+
+    /**
+     * the alias to sign under; required
+     *
+     * @param alias the alias to sign under
+     */
+    public void setAlias(final String alias) {
+        this.alias = alias;
+    }
+
+    /**
+     * keystore location; required
+     *
+     * @param keystore the keystore location
+     */
+    public void setKeystore(final String keystore) {
+        this.keystore = keystore;
+    }
+
+    /**
+     * password for keystore integrity; required
+     *
+     * @param storepass the password for the keystore
+     */
+    public void setStorepass(final String storepass) {
+        this.storepass = storepass;
+    }
+
+    /**
+     * keystore type; optional
+     *
+     * @param storetype the keystore type
+     */
+    public void setStoretype(final String storetype) {
+        this.storetype = storetype;
+    }
+
+    /**
+     * password for private key (if different); optional
+     *
+     * @param keypass the password for the key (if different)
+     */
+    public void setKeypass(final String keypass) {
+        this.keypass = keypass;
+    }
+
+    /**
+     * Enable verbose output when signing ; optional: default false
+     *
+     * @param verbose if true enable verbose output
+     */
+    public void setVerbose(final boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Adds a set of files to sign
+     *
+     * @param set a set of files to sign
+     * @since Ant 1.4
+     */
+    public void addFileset(final FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Add a system property.
+     *
+     * @param sysp system property.
+     */
+    public void addSysproperty(Environment.Variable sysp) {
+        sysProperties.addVariable(sysp);
+    }
+
+    /**
+     * Adds a path of files to sign.
+     *
+     * @return a path of files to sign.
+     * @since Ant 1.7
+     */
+    public Path createPath() {
+        if (path == null) {
+            path = new Path(getProject());
+        }
+        return path.createPath();
+    }
+
+    /**
+     * init processing logic; this is retained through our execution(s)
+     */
+    protected void beginExecution() {
+
+        redirector = createRedirector();
+    }
+
+    /**
+     * any cleanup logic
+     */
+    protected void endExecution() {
+        redirector = null;
+    }
+
+    /**
+     * Create the redirector to use, if any.
+     *
+     * @return a configured RedirectorElement.
+     */
+    private RedirectorElement createRedirector() {
+        RedirectorElement result = new RedirectorElement();
+        if (storepass != null) {
+            StringBuffer input = new StringBuffer(storepass).append('\n');
+            if (keypass != null) {
+                input.append(keypass).append('\n');
+            }
+            result.setInputString(input.toString());
+            result.setLogInputString(false);
+        }
+        return result;
+    }
+
+    /**
+     * get the redirector. Non-null between invocations of
+     * {@link #beginExecution()} and {@link #endExecution()}
+     * @return a redirector or null
+     */
+    public RedirectorElement getRedirector() {
+        return redirector;
+    }
+
+    /**
+     * these are options common to signing and verifying
+     * @param cmd  command to configure
+     */
+    protected void setCommonOptions(final ExecTask cmd) {
+        if (maxMemory != null) {
+            addValue(cmd, "-J-Xmx" + maxMemory);
+        }
+
+        if (verbose) {
+            addValue(cmd, "-verbose");
+        }
+
+        //now patch in all system properties
+        Vector props = sysProperties.getVariablesVector();
+        Enumeration e = props.elements();
+        while (e.hasMoreElements()) {
+            Environment.Variable variable = (Environment.Variable) e.nextElement();
+            declareSysProperty(cmd, variable);
+        }
+    }
+
+    /**
+     *
+     * @param cmd command to configure
+     * @param property property to set
+     * @throws BuildException if the property is not correctly defined.
+     */
+    protected void declareSysProperty(
+        ExecTask cmd, Environment.Variable property) throws BuildException {
+        addValue(cmd, "-J-D" + property.getContent());
+    }
+
+
+    /**
+     * bind to a keystore if the attributes are there
+     * @param cmd command to configure
+     */
+    protected void bindToKeystore(final ExecTask cmd) {
+        if (null != keystore) {
+            // is the keystore a file
+            addValue(cmd, "-keystore");
+            String loc;
+            File keystoreFile = getProject().resolveFile(keystore);
+            if (keystoreFile.exists()) {
+                loc = keystoreFile.getPath();
+            } else {
+                // must be a URL - just pass as is
+                loc = keystore;
+            }
+            addValue(cmd, loc);
+        }
+        if (null != storetype) {
+            addValue(cmd, "-storetype");
+            addValue(cmd, storetype);
+        }
+    }
+
+    /**
+     * create the jarsigner executable task
+     * @return a task set up with the executable of jarsigner, failonerror=true
+     * and bound to our redirector
+     */
+    protected ExecTask createJarSigner() {
+        final ExecTask cmd = new ExecTask(this);
+        cmd.setExecutable(JavaEnvUtils.getJdkExecutable(JARSIGNER_COMMAND));
+        cmd.setTaskType(JARSIGNER_COMMAND);
+        cmd.setFailonerror(true);
+        cmd.addConfiguredRedirector(redirector);
+        return cmd;
+    }
+
+    /**
+     * clone our filesets vector, and patch in the jar attribute as a new
+     * fileset, if is defined
+     * @return a vector of FileSet instances
+     */
+    protected Vector createUnifiedSources() {
+        Vector sources = (Vector) filesets.clone();
+        if (jar != null) {
+            //we create a fileset with the source file.
+            //this lets us combine our logic for handling output directories,
+            //mapping etc.
+            FileSet sourceJar = new FileSet();
+            sourceJar.setProject(getProject());
+            sourceJar.setFile(jar);
+            sourceJar.setDir(jar.getParentFile());
+            sources.add(sourceJar);
+        }
+        return sources;
+    }
+
+    /**
+     * clone our path and add all explicitly specified FileSets as
+     * well, patch in the jar attribute as a new fileset if it is
+     * defined.
+     * @return a path that contains all files to sign
+     * @since Ant 1.7
+     */
+    protected Path createUnifiedSourcePath() {
+        Path p = path == null ? new Path(getProject()) : (Path) path.clone();
+        Vector s = createUnifiedSources();
+        Enumeration e = s.elements();
+        while (e.hasMoreElements()) {
+            p.add((FileSet) e.nextElement());
+        }
+        return p;
+    }
+
+    /**
+     * Has either a path or a fileset been specified?
+     * @return true if a path or fileset has been specified.
+     * @since Ant 1.7
+     */
+    protected boolean hasResources() {
+        return path != null || filesets.size() > 0;
+    }
+
+    /**
+     * add a value argument to a command
+     * @param cmd command to manipulate
+     * @param value value to add
+     */
+    protected void addValue(final ExecTask cmd, String value) {
+        cmd.createArg().setValue(value);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Ant.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Ant.java
new file mode 100644
index 0000000..fcbe410
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Ant.java
@@ -0,0 +1,783 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.Set;
+import java.util.HashSet;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Main;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Build a sub-project.
+ *
+ *  <pre>
+ *  &lt;target name=&quot;foo&quot; depends=&quot;init&quot;&gt;
+ *    &lt;ant antfile=&quot;build.xml&quot; target=&quot;bar&quot; &gt;
+ *      &lt;property name=&quot;property1&quot; value=&quot;aaaaa&quot; /&gt;
+ *      &lt;property name=&quot;foo&quot; value=&quot;baz&quot; /&gt;
+ *    &lt;/ant&gt;</span>
+ *  &lt;/target&gt;</span>
+ *
+ *  &lt;target name=&quot;bar&quot; depends=&quot;init&quot;&gt;
+ *    &lt;echo message=&quot;prop is ${property1} ${foo}&quot; /&gt;
+ *  &lt;/target&gt;
+ * </pre>
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="control"
+ */
+public class Ant extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** the basedir where is executed the build file */
+    private File dir = null;
+
+    /**
+     * the build.xml file (can be absolute) in this case dir will be
+     * ignored
+     */
+    private String antFile = null;
+
+    /** the output */
+    private String output = null;
+
+    /** should we inherit properties from the parent ? */
+    private boolean inheritAll = true;
+
+    /** should we inherit references from the parent ? */
+    private boolean inheritRefs = false;
+
+    /** the properties to pass to the new project */
+    private Vector properties = new Vector();
+
+    /** the references to pass to the new project */
+    private Vector references = new Vector();
+
+    /** the temporary project created to run the build file */
+    private Project newProject;
+
+    /** The stream to which output is to be written. */
+    private PrintStream out = null;
+
+    /** the sets of properties to pass to the new project */
+    private Vector propertySets = new Vector();
+
+    /** the targets to call on the new project */
+    private Vector targets = new Vector();
+
+    /** whether the target attribute was specified **/
+    private boolean targetAttributeSet = false;
+
+    /**
+     * simple constructor
+     */
+    public Ant() {
+        //default
+    }
+
+    /**
+     * create a task bound to its creator
+     * @param owner owning task
+     */
+    public Ant(Task owner) {
+        bindToOwner(owner);
+    }
+
+
+    /**
+     * If true, pass all properties to the new Ant project.
+     * Defaults to true.
+     * @param value if true pass all properties to the new Ant project.
+     */
+    public void setInheritAll(boolean value) {
+        inheritAll = value;
+    }
+
+    /**
+     * If true, pass all references to the new Ant project.
+     * Defaults to false.
+     * @param value if true, pass all references to the new Ant project
+     */
+    public void setInheritRefs(boolean value) {
+        inheritRefs = value;
+    }
+
+    /**
+     * Creates a Project instance for the project to call.
+     */
+    public void init() {
+        newProject = getProject().createSubProject();
+        newProject.setJavaVersionProperty();
+    }
+
+    /**
+     * Called in execute or createProperty (via getNewProject())
+     * if newProject is null.
+     *
+     * <p>This can happen if the same instance of this task is run
+     * twice as newProject is set to null at the end of execute (to
+     * save memory and help the GC).</p>
+     * <p>calls init() again</p>
+     *
+     */
+    private void reinit() {
+        init();
+    }
+
+    /**
+     * Attaches the build listeners of the current project to the new
+     * project, configures a possible logfile, transfers task and
+     * data-type definitions, transfers properties (either all or just
+     * the ones specified as user properties to the current project,
+     * depending on inheritall), transfers the input handler.
+     */
+    private void initializeProject() {
+        newProject.setInputHandler(getProject().getInputHandler());
+
+        Iterator iter = getBuildListeners();
+        while (iter.hasNext()) {
+            newProject.addBuildListener((BuildListener) iter.next());
+        }
+
+        if (output != null) {
+            File outfile = null;
+            if (dir != null) {
+                outfile = FILE_UTILS.resolveFile(dir, output);
+            } else {
+                outfile = getProject().resolveFile(output);
+            }
+            try {
+                out = new PrintStream(new FileOutputStream(outfile));
+                DefaultLogger logger = new DefaultLogger();
+                logger.setMessageOutputLevel(Project.MSG_INFO);
+                logger.setOutputPrintStream(out);
+                logger.setErrorPrintStream(out);
+                newProject.addBuildListener(logger);
+            } catch (IOException ex) {
+                log("Ant: Can't set output to " + output);
+            }
+        }
+        // set user-defined properties
+        getProject().copyUserProperties(newProject);
+
+        if (!inheritAll) {
+           // set Ant's built-in properties separately,
+           // because they are not being inherited.
+           newProject.initProperties();
+
+        } else {
+            // set all properties from calling project
+            addAlmostAll(getProject().getProperties());
+        }
+
+        Enumeration e = propertySets.elements();
+        while (e.hasMoreElements()) {
+            PropertySet ps = (PropertySet) e.nextElement();
+            addAlmostAll(ps.getProperties());
+        }
+    }
+
+    /**
+     * Handles output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param outputToHandle The string output to output.
+     * @see Task#handleOutput(String)
+     * @since Ant 1.5
+     */
+    public void handleOutput(String outputToHandle) {
+        if (newProject != null) {
+            newProject.demuxOutput(outputToHandle, false);
+        } else {
+            super.handleOutput(outputToHandle);
+        }
+    }
+
+    /**
+     * Handles input.
+     * Deleate to the created project, if present, otherwise
+     * call the super class.
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @see Task#handleInput(byte[], int, int)
+     * @since Ant 1.6
+     */
+    public int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (newProject != null) {
+            return newProject.demuxInput(buffer, offset, length);
+        }
+        return super.handleInput(buffer, offset, length);
+    }
+
+    /**
+     * Handles output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param toFlush The string to output.
+     * @see Task#handleFlush(String)
+     * @since Ant 1.5.2
+     */
+    public void handleFlush(String toFlush) {
+        if (newProject != null) {
+            newProject.demuxFlush(toFlush, false);
+        } else {
+            super.handleFlush(toFlush);
+        }
+    }
+
+    /**
+     * Handle error output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param errorOutputToHandle The string to output.
+     *
+     * @see Task#handleErrorOutput(String)
+     * @since Ant 1.5
+     */
+    public void handleErrorOutput(String errorOutputToHandle) {
+        if (newProject != null) {
+            newProject.demuxOutput(errorOutputToHandle, true);
+        } else {
+            super.handleErrorOutput(errorOutputToHandle);
+        }
+    }
+
+    /**
+     * Handle error output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param errorOutputToFlush The string to output.
+     * @see Task#handleErrorFlush(String)
+     * @since Ant 1.5.2
+     */
+    public void handleErrorFlush(String errorOutputToFlush) {
+        if (newProject != null) {
+            newProject.demuxFlush(errorOutputToFlush, true);
+        } else {
+            super.handleErrorFlush(errorOutputToFlush);
+        }
+    }
+
+    /**
+     * Do the execution.
+     * @throws BuildException if a target tries to call itself;
+     * probably also if a BuildException is thrown by the new project.
+     */
+    public void execute() throws BuildException {
+        File savedDir = dir;
+        String savedAntFile = antFile;
+        Vector locals = new Vector(targets);
+        try {
+            getNewProject();
+
+            if (dir == null && inheritAll) {
+                dir = getProject().getBaseDir();
+            }
+
+            initializeProject();
+
+            if (dir != null) {
+                newProject.setBaseDir(dir);
+                if (savedDir != null) {
+                    // has been set explicitly
+                    newProject.setInheritedProperty(MagicNames.PROJECT_BASEDIR,
+                                                    dir.getAbsolutePath());
+                }
+            } else {
+                dir = getProject().getBaseDir();
+            }
+
+            overrideProperties();
+
+            if (antFile == null) {
+                antFile = Main.DEFAULT_BUILD_FILENAME;
+            }
+
+            File file = FILE_UTILS.resolveFile(dir, antFile);
+            antFile = file.getAbsolutePath();
+
+            log("calling target(s) "
+                + ((locals.size() > 0) ? locals.toString() : "[default]")
+                + " in build file " + antFile, Project.MSG_VERBOSE);
+            newProject.setUserProperty(MagicNames.ANT_FILE , antFile);
+
+            String thisAntFile = getProject().getProperty(MagicNames.ANT_FILE);
+            // Are we trying to call the target in which we are defined (or
+            // the build file if this is a top level task)?
+            if (thisAntFile != null
+                && file.equals(getProject().resolveFile(thisAntFile))
+                && getOwningTarget() != null) {
+
+                if (getOwningTarget().getName().equals("")) {
+                    if (getTaskName().equals("antcall")) {
+                        throw new BuildException("antcall must not be used at"
+                                                 + " the top level.");
+                    }
+                    throw new BuildException(getTaskName() + " task at the"
+                                + " top level must not invoke"
+                                + " its own build file.");
+                }
+            }
+
+            try {
+                ProjectHelper.configureProject(newProject, file);
+            } catch (BuildException ex) {
+                throw ProjectHelper.addLocationToBuildException(
+                    ex, getLocation());
+            }
+
+            if (locals.size() == 0) {
+                String defaultTarget = newProject.getDefaultTarget();
+                if (defaultTarget != null) {
+                    locals.add(defaultTarget);
+                }
+            }
+
+            if (newProject.getProperty(MagicNames.ANT_FILE)
+                .equals(getProject().getProperty(MagicNames.ANT_FILE))
+                && getOwningTarget() != null) {
+
+                String owningTargetName = getOwningTarget().getName();
+
+                if (locals.contains(owningTargetName)) {
+                    throw new BuildException(getTaskName() + " task calling "
+                                             + "its own parent target.");
+                }
+                boolean circular = false;
+                for (Iterator it = locals.iterator();
+                     !circular && it.hasNext();) {
+                    Target other =
+                        (Target) (getProject().getTargets().get(it.next()));
+                    circular |= (other != null
+                                 && other.dependsOn(owningTargetName));
+                }
+                if (circular) {
+                    throw new BuildException(getTaskName()
+                                             + " task calling a target"
+                                             + " that depends on"
+                                             + " its parent target \'"
+                                             + owningTargetName
+                                             + "\'.");
+                }
+            }
+
+            addReferences();
+
+            if (locals.size() > 0 && !(locals.size() == 1
+                                       && "".equals(locals.get(0)))) {
+                BuildException be = null;
+                try {
+                    log("Entering " + antFile + "...", Project.MSG_VERBOSE);
+                    newProject.fireSubBuildStarted();
+                    newProject.executeTargets(locals);
+                } catch (BuildException ex) {
+                    be = ProjectHelper
+                        .addLocationToBuildException(ex, getLocation());
+                    throw be;
+                } finally {
+                    log("Exiting " + antFile + ".", Project.MSG_VERBOSE);
+                    newProject.fireSubBuildFinished(be);
+                }
+            }
+        } finally {
+            // help the gc
+            newProject = null;
+            Enumeration e = properties.elements();
+            while (e.hasMoreElements()) {
+                Property p = (Property) e.nextElement();
+                p.setProject(null);
+            }
+
+            if (output != null && out != null) {
+                try {
+                    out.close();
+                } catch (final Exception ex) {
+                    //ignore
+                }
+            }
+            dir = savedDir;
+            antFile = savedAntFile;
+        }
+    }
+
+    /**
+     * Override the properties in the new project with the one
+     * explicitly defined as nested elements here.
+     * @throws BuildException under unknown circumstances.
+     */
+    private void overrideProperties() throws BuildException {
+        // remove duplicate properties - last property wins
+        // Needed for backward compatibility
+        Set set = new HashSet();
+        for (int i = properties.size() - 1; i >= 0; --i) {
+            Property p = (Property) properties.get(i);
+            if (p.getName() != null && !p.getName().equals("")) {
+                if (set.contains(p.getName())) {
+                    properties.remove(i);
+                } else {
+                    set.add(p.getName());
+                }
+            }
+        }
+        Enumeration e = properties.elements();
+        while (e.hasMoreElements()) {
+            Property p = (Property) e.nextElement();
+            p.setProject(newProject);
+            p.execute();
+        }
+        getProject().copyInheritedProperties(newProject);
+    }
+
+    /**
+     * Add the references explicitly defined as nested elements to the
+     * new project.  Also copy over all references that don't override
+     * existing references in the new project if inheritrefs has been
+     * requested.
+     * @throws BuildException if a reference does not have a refid.
+     */
+    private void addReferences() throws BuildException {
+        Hashtable thisReferences
+            = (Hashtable) getProject().getReferences().clone();
+        Hashtable newReferences = newProject.getReferences();
+        Enumeration e;
+        if (references.size() > 0) {
+            for (e = references.elements(); e.hasMoreElements();) {
+                Reference ref = (Reference) e.nextElement();
+                String refid = ref.getRefId();
+                if (refid == null) {
+                    throw new BuildException("the refid attribute is required"
+                                             + " for reference elements");
+                }
+                if (!thisReferences.containsKey(refid)) {
+                    log("Parent project doesn't contain any reference '"
+                        + refid + "'",
+                        Project.MSG_WARN);
+                    continue;
+                }
+
+                thisReferences.remove(refid);
+                String toRefid = ref.getToRefid();
+                if (toRefid == null) {
+                    toRefid = refid;
+                }
+                copyReference(refid, toRefid);
+            }
+        }
+
+        // Now add all references that are not defined in the
+        // subproject, if inheritRefs is true
+        if (inheritRefs) {
+            for (e = thisReferences.keys(); e.hasMoreElements();) {
+                String key = (String) e.nextElement();
+                if (newReferences.containsKey(key)) {
+                    continue;
+                }
+                copyReference(key, key);
+                newProject.inheritIDReferences(getProject());
+            }
+        }
+    }
+
+    /**
+     * Try to clone and reconfigure the object referenced by oldkey in
+     * the parent project and add it to the new project with the key newkey.
+     *
+     * <p>If we cannot clone it, copy the referenced object itself and
+     * keep our fingers crossed.</p>
+     * @param oldKey the reference id in the current project.
+     * @param newKey the reference id in the new project.
+     */
+    private void copyReference(String oldKey, String newKey) {
+        Object orig = getProject().getReference(oldKey);
+        if (orig == null) {
+            log("No object referenced by " + oldKey + ". Can't copy to "
+                + newKey,
+                Project.MSG_WARN);
+            return;
+        }
+
+        Class c = orig.getClass();
+        Object copy = orig;
+        try {
+            Method cloneM = c.getMethod("clone", new Class[0]);
+            if (cloneM != null) {
+                copy = cloneM.invoke(orig, new Object[0]);
+                log("Adding clone of reference " + oldKey, Project.MSG_DEBUG);
+            }
+        } catch (Exception e) {
+            // not Clonable
+        }
+
+
+        if (copy instanceof ProjectComponent) {
+            ((ProjectComponent) copy).setProject(newProject);
+        } else {
+            try {
+                Method setProjectM =
+                    c.getMethod("setProject", new Class[] {Project.class});
+                if (setProjectM != null) {
+                    setProjectM.invoke(copy, new Object[] {newProject});
+                }
+            } catch (NoSuchMethodException e) {
+                // ignore this if the class being referenced does not have
+                // a set project method.
+            } catch (Exception e2) {
+                String msg = "Error setting new project instance for "
+                    + "reference with id " + oldKey;
+                throw new BuildException(msg, e2, getLocation());
+            }
+        }
+        newProject.addReference(newKey, copy);
+    }
+
+    /**
+     * Copies all properties from the given table to the new project -
+     * omitting those that have already been set in the new project as
+     * well as properties named basedir or ant.file.
+     * @param props properties <code>Hashtable</code> to copy to the
+     * new project.
+     * @since Ant 1.6
+     */
+    private void addAlmostAll(Hashtable props) {
+        Enumeration e = props.keys();
+        while (e.hasMoreElements()) {
+            String key = e.nextElement().toString();
+            if (MagicNames.PROJECT_BASEDIR.equals(key) || MagicNames.ANT_FILE.equals(key)) {
+                // basedir and ant.file get special treatment in execute()
+                continue;
+            }
+
+            String value = props.get(key).toString();
+            // don't re-set user properties, avoid the warning message
+            if (newProject.getProperty(key) == null) {
+                // no user property
+                newProject.setNewProperty(key, value);
+            }
+        }
+    }
+
+    /**
+     * The directory to use as a base directory for the new Ant project.
+     * Defaults to the current project's basedir, unless inheritall
+     * has been set to false, in which case it doesn't have a default
+     * value. This will override the basedir setting of the called project.
+     * @param dir new directory as <code>File</code>.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * The build file to use. Defaults to "build.xml". This file is expected
+     * to be a filename relative to the dir attribute given.
+     * @param antFile the <code>String</code> build file name.
+     */
+    public void setAntfile(String antFile) {
+        // @note: it is a string and not a file to handle relative/absolute
+        // otherwise a relative file will be resolved based on the current
+        // basedir.
+        this.antFile = antFile;
+    }
+
+    /**
+     * The target of the new Ant project to execute.
+     * Defaults to the new project's default target.
+     * @param targetToAdd the name of the target to invoke.
+     */
+    public void setTarget(String targetToAdd) {
+        if (targetToAdd.equals("")) {
+            throw new BuildException("target attribute must not be empty");
+        }
+        targets.add(targetToAdd);
+        targetAttributeSet = true;
+    }
+
+    /**
+     * Set the filename to write the output to. This is relative to the value
+     * of the dir attribute if it has been set or to the base directory of the
+     * current project otherwise.
+     * @param outputFile the name of the file to which the output should go.
+     */
+    public void setOutput(String outputFile) {
+        this.output = outputFile;
+    }
+
+    /**
+     * Property to pass to the new project.
+     * The property is passed as a 'user property'.
+     * @return the created <code>Property</code> object.
+     */
+    public Property createProperty() {
+        Property p = new Property(true, getProject());
+        p.setProject(getNewProject());
+        p.setTaskName("property");
+        properties.addElement(p);
+        return p;
+    }
+
+    /**
+     * Add a Reference element identifying a data type to carry
+     * over to the new project.
+     * @param ref <code>Reference</code> to add.
+     */
+    public void addReference(Reference ref) {
+        references.addElement(ref);
+    }
+
+    /**
+     * Add a target to this Ant invocation.
+     * @param t the <code>TargetElement</code> to add.
+     * @since Ant 1.6.3
+     */
+    public void addConfiguredTarget(TargetElement t) {
+        if (targetAttributeSet) {
+            throw new BuildException(
+                "nested target is incompatible with the target attribute");
+        }
+        String name = t.getName();
+        if (name.equals("")) {
+            throw new BuildException("target name must not be empty");
+        }
+        targets.add(name);
+    }
+
+    /**
+     * Add a set of properties to pass to the new project.
+     *
+     * @param ps <code>PropertySet</code> to add.
+     * @since Ant 1.6
+     */
+    public void addPropertyset(PropertySet ps) {
+        propertySets.addElement(ps);
+    }
+
+    /**
+     * Get the (sub)-Project instance currently in use.
+     * @return Project
+     * @since Ant 1.7
+     */
+    protected Project getNewProject() {
+        if (newProject == null) {
+            reinit();
+        }
+        return newProject;
+    }
+
+    /**
+     * @since Ant 1.6.2
+     */
+    private Iterator getBuildListeners() {
+        return getProject().getBuildListeners().iterator();
+    }
+
+    /**
+     * Helper class that implements the nested &lt;reference&gt;
+     * element of &lt;ant&gt; and &lt;antcall&gt;.
+     */
+    public static class Reference
+        extends org.apache.tools.ant.types.Reference {
+
+        /** Creates a reference to be configured by Ant. */
+        public Reference() {
+                super();
+        }
+
+        private String targetid = null;
+
+        /**
+         * Set the id that this reference to be stored under in the
+         * new project.
+         *
+         * @param targetid the id under which this reference will be passed to
+         *        the new project. */
+        public void setToRefid(String targetid) {
+            this.targetid = targetid;
+        }
+
+        /**
+         * Get the id under which this reference will be stored in the new
+         * project.
+         *
+         * @return the id of the reference in the new project.
+         */
+        public String getToRefid() {
+            return targetid;
+        }
+    }
+
+    /**
+     * Helper class that implements the nested &lt;target&gt;
+     * element of &lt;ant&gt; and &lt;antcall&gt;.
+     * @since Ant 1.6.3
+     */
+    public static class TargetElement {
+        private String name;
+
+        /**
+         * Default constructor.
+         */
+        public TargetElement() {
+                //default
+        }
+
+        /**
+         * Set the name of this TargetElement.
+         * @param name   the <code>String</code> target name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the name of this TargetElement.
+         * @return <code>String</code>.
+         */
+        public String getName() {
+            return name;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java b/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java
new file mode 100644
index 0000000..3d3b2a0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/AntStructure.java
@@ -0,0 +1,469 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Creates a partial DTD for Ant from the currently known tasks.
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="xml"
+ */
+public class AntStructure extends Task {
+
+    private static final String LINE_SEP
+        = System.getProperty("line.separator");
+
+    private File output;
+    private StructurePrinter printer = new DTDPrinter();
+
+    /**
+     * The output file.
+     * @param output the output file
+     */
+    public void setOutput(File output) {
+        this.output = output;
+    }
+
+    /**
+     * The StructurePrinter to use.
+     * @param p the printer to use.
+     * @since Ant 1.7
+     */
+    public void add(StructurePrinter p) {
+        printer = p;
+    }
+
+    /**
+     * Build the antstructure DTD.
+     *
+     * @exception BuildException if the DTD cannot be written.
+     */
+    public void execute() throws BuildException {
+
+        if (output == null) {
+            throw new BuildException("output attribute is required", getLocation());
+        }
+
+        PrintWriter out = null;
+        try {
+            try {
+                out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(output), "UTF8"));
+            } catch (UnsupportedEncodingException ue) {
+                /*
+                 * Plain impossible with UTF8, see
+                 * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html
+                 *
+                 * fallback to platform specific anyway.
+                 */
+                out = new PrintWriter(new FileWriter(output));
+            }
+
+            printer.printHead(out, getProject(),
+                              getProject().getTaskDefinitions(),
+                              getProject().getDataTypeDefinitions());
+
+            printer.printTargetDecl(out);
+
+            Enumeration dataTypes = getProject().getDataTypeDefinitions().keys();
+            while (dataTypes.hasMoreElements()) {
+                String typeName = (String) dataTypes.nextElement();
+                printer.printElementDecl(
+                    out, getProject(), typeName,
+                    (Class) getProject().getDataTypeDefinitions().get(typeName));
+            }
+
+            Enumeration tasks = getProject().getTaskDefinitions().keys();
+            while (tasks.hasMoreElements()) {
+                String tName = (String) tasks.nextElement();
+                printer.printElementDecl(out, getProject(), tName,
+                                         (Class) getProject().getTaskDefinitions().get(tName));
+            }
+
+            printer.printTail(out);
+
+        } catch (IOException ioe) {
+            throw new BuildException("Error writing "
+                                     + output.getAbsolutePath(), ioe, getLocation());
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
+    }
+
+    /**
+     * Writes the actual structure information.
+     *
+     * <p>{@link #printHead}, {@link #printTargetDecl} and {@link #printTail}
+     * are called exactly once, {@link #printElementDecl} once for
+     * each declared task and type.</p>
+     */
+    public static interface StructurePrinter {
+        /**
+         * Prints the header of the generated output.
+         *
+         * @param out PrintWriter to write to.
+         * @param p Project instance for the current task
+         * @param tasks map (name to implementing class)
+         * @param types map (name to implementing class)
+         * data types.
+         */
+        void printHead(PrintWriter out, Project p, Hashtable tasks,
+                       Hashtable types);
+
+        /**
+         * Prints the definition for the target element.
+         * @param out PrintWriter to write to.
+         */
+        void printTargetDecl(PrintWriter out);
+
+        /**
+         * Print the definition for a given element.
+         *
+         * @param out PrintWriter to write to.
+         * @param p Project instance for the current task
+         * @param name element name.
+         * @param element class of the defined element.
+         */
+        void printElementDecl(PrintWriter out, Project p, String name,
+                              Class element);
+
+        /**
+         * Prints the trailer.
+         * @param out PrintWriter to write to.
+         */
+        void printTail(PrintWriter out);
+    }
+
+    private static class DTDPrinter implements StructurePrinter {
+
+        private static final String BOOLEAN = "%boolean;";
+        private static final String TASKS = "%tasks;";
+        private static final String TYPES = "%types;";
+
+        private Hashtable visited = new Hashtable();
+
+        public void printTail(PrintWriter out) {
+            visited.clear();
+        }
+
+        public void printHead(PrintWriter out, Project p, Hashtable tasks, Hashtable types) {
+            printHead(out, tasks.keys(), types.keys());
+        }
+
+
+        /**
+         * Prints the header of the generated output.
+         *
+         * <p>Basically this prints the XML declaration, defines some
+         * entities and the project element.</p>
+         */
+        private void printHead(PrintWriter out, Enumeration tasks,
+                               Enumeration types) {
+            out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
+            out.println("<!ENTITY % boolean \"(true|false|on|off|yes|no)\">");
+            out.print("<!ENTITY % tasks \"");
+            boolean first = true;
+            while (tasks.hasMoreElements()) {
+                String tName = (String) tasks.nextElement();
+                if (!first) {
+                    out.print(" | ");
+                } else {
+                    first = false;
+                }
+                out.print(tName);
+            }
+            out.println("\">");
+            out.print("<!ENTITY % types \"");
+            first = true;
+            while (types.hasMoreElements()) {
+                String typeName = (String) types.nextElement();
+                if (!first) {
+                    out.print(" | ");
+                } else {
+                    first = false;
+                }
+                out.print(typeName);
+            }
+            out.println("\">");
+
+            out.println("");
+
+            out.print("<!ELEMENT project (target | ");
+            out.print(TASKS);
+            out.print(" | ");
+            out.print(TYPES);
+            out.println(")*>");
+            out.println("<!ATTLIST project");
+            out.println("          name    CDATA #IMPLIED");
+            out.println("          default CDATA #IMPLIED");
+            out.println("          basedir CDATA #IMPLIED>");
+            out.println("");
+        }
+
+        /**
+         * Prints the definition for the target element.
+         */
+        public void printTargetDecl(PrintWriter out) {
+            out.print("<!ELEMENT target (");
+            out.print(TASKS);
+            out.print(" | ");
+            out.print(TYPES);
+            out.println(")*>");
+            out.println("");
+
+            out.println("<!ATTLIST target");
+            out.println("          id          ID    #IMPLIED");
+            out.println("          name        CDATA #REQUIRED");
+            out.println("          if          CDATA #IMPLIED");
+            out.println("          unless      CDATA #IMPLIED");
+            out.println("          depends     CDATA #IMPLIED");
+            out.println("          description CDATA #IMPLIED>");
+            out.println("");
+        }
+
+        /**
+         * Print the definition for a given element.
+         */
+        public void printElementDecl(PrintWriter out, Project p,
+                                     String name, Class element) {
+
+            if (visited.containsKey(name)) {
+                return;
+            }
+            visited.put(name, "");
+
+            IntrospectionHelper ih = null;
+            try {
+                ih = IntrospectionHelper.getHelper(p, element);
+            } catch (Throwable t) {
+                /*
+                 * XXX - failed to load the class properly.
+                 *
+                 * should we print a warning here?
+                 */
+                return;
+            }
+
+            StringBuffer sb = new StringBuffer("<!ELEMENT ");
+            sb.append(name).append(" ");
+
+            if (org.apache.tools.ant.types.Reference.class.equals(element)) {
+                sb.append("EMPTY>").append(LINE_SEP);
+                sb.append("<!ATTLIST ").append(name);
+                sb.append(LINE_SEP).append("          id ID #IMPLIED");
+                sb.append(LINE_SEP).append("          refid IDREF #IMPLIED");
+                sb.append(">").append(LINE_SEP);
+                out.println(sb);
+                return;
+            }
+
+            Vector v = new Vector();
+            if (ih.supportsCharacters()) {
+                v.addElement("#PCDATA");
+            }
+
+            if (TaskContainer.class.isAssignableFrom(element)) {
+                v.addElement(TASKS);
+            }
+
+            Enumeration e = ih.getNestedElements();
+            while (e.hasMoreElements()) {
+                v.addElement(e.nextElement());
+            }
+
+            if (v.isEmpty()) {
+                sb.append("EMPTY");
+            } else {
+                sb.append("(");
+                final int count = v.size();
+                for (int i = 0; i < count; i++) {
+                    if (i != 0) {
+                        sb.append(" | ");
+                    }
+                    sb.append(v.elementAt(i));
+                }
+                sb.append(")");
+                if (count > 1 || !v.elementAt(0).equals("#PCDATA")) {
+                    sb.append("*");
+                }
+            }
+            sb.append(">");
+            out.println(sb);
+
+            sb = new StringBuffer("<!ATTLIST ");
+            sb.append(name);
+            sb.append(LINE_SEP).append("          id ID #IMPLIED");
+
+            e = ih.getAttributes();
+            while (e.hasMoreElements()) {
+                String attrName = (String) e.nextElement();
+                if ("id".equals(attrName)) {
+                    continue;
+                }
+
+                sb.append(LINE_SEP).append("          ")
+                    .append(attrName).append(" ");
+                Class type = ih.getAttributeType(attrName);
+                if (type.equals(java.lang.Boolean.class)
+                    || type.equals(java.lang.Boolean.TYPE)) {
+                    sb.append(BOOLEAN).append(" ");
+                } else if (Reference.class.isAssignableFrom(type)) {
+                    sb.append("IDREF ");
+                } else if (EnumeratedAttribute.class.isAssignableFrom(type)) {
+                    try {
+                        EnumeratedAttribute ea =
+                            (EnumeratedAttribute) type.newInstance();
+                        String[] values = ea.getValues();
+                        if (values == null
+                            || values.length == 0
+                            || !areNmtokens(values)) {
+                            sb.append("CDATA ");
+                        } else {
+                            sb.append("(");
+                            for (int i = 0; i < values.length; i++) {
+                                if (i != 0) {
+                                    sb.append(" | ");
+                                }
+                                sb.append(values[i]);
+                            }
+                            sb.append(") ");
+                        }
+                    } catch (InstantiationException ie) {
+                        sb.append("CDATA ");
+                    } catch (IllegalAccessException ie) {
+                        sb.append("CDATA ");
+                    }
+                } else if (type.getSuperclass() != null
+                           && type.getSuperclass().getName().equals("java.lang.Enum")) {
+                    try {
+                        Object[] values = (Object[]) type.getMethod("values", (Class[])  null)
+                            .invoke(null, (Object[]) null);
+                        if (values.length == 0) {
+                            sb.append("CDATA ");
+                        } else {
+                            sb.append('(');
+                            for (int i = 0; i < values.length; i++) {
+                                if (i != 0) {
+                                    sb.append(" | ");
+                                }
+                                sb.append(type.getMethod("name", (Class[]) null)
+                                          .invoke(values[i], (Object[]) null));
+                            }
+                            sb.append(") ");
+                        }
+                    } catch (Exception x) {
+                        sb.append("CDATA ");
+                    }
+                } else {
+                    sb.append("CDATA ");
+                }
+                sb.append("#IMPLIED");
+            }
+            sb.append(">").append(LINE_SEP);
+            out.println(sb);
+
+            final int count = v.size();
+            for (int i = 0; i < count; i++) {
+                String nestedName = (String) v.elementAt(i);
+                if (!"#PCDATA".equals(nestedName)
+                    && !TASKS.equals(nestedName)
+                    && !TYPES.equals(nestedName)) {
+                    printElementDecl(out, p, nestedName, ih.getElementType(nestedName));
+                }
+            }
+        }
+
+        /**
+         * Does this String match the XML-NMTOKEN production?
+         * @param s the string to test
+         * @return true if the string matches the XML-NMTOKEN
+         */
+        public static final boolean isNmtoken(String s) {
+            final int length = s.length();
+            for (int i = 0; i < length; i++) {
+                char c = s.charAt(i);
+                // XXX - we are committing CombiningChar and Extender here
+                if (!Character.isLetterOrDigit(c)
+                    && c != '.' && c != '-' && c != '_' && c != ':') {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Do the Strings all match the XML-NMTOKEN production?
+         *
+         * <p>Otherwise they are not suitable as an enumerated attribute,
+         * for example.</p>
+         * @param s the array of string to test
+         * @return true if all the strings in the array math XML-NMTOKEN
+         */
+        public static final boolean areNmtokens(String[] s) {
+            for (int i = 0; i < s.length; i++) {
+                if (!isNmtoken(s[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Does this String match the XML-NMTOKEN production?
+     * @param s the string to test
+     * @return true if the string matches the XML-NMTOKEN
+     */
+    protected boolean isNmtoken(String s) {
+        return DTDPrinter.isNmtoken(s);
+    }
+
+    /**
+     * Do the Strings all match the XML-NMTOKEN production?
+     *
+     * <p>Otherwise they are not suitable as an enumerated attribute,
+     * for example.</p>
+     * @param s the array of string to test
+     * @return true if all the strings in the array math XML-NMTOKEN
+     */
+    protected boolean areNmtokens(String[] s) {
+        return DTDPrinter.areNmtokens(s);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Antlib.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Antlib.java
new file mode 100644
index 0000000..7f1e560
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Antlib.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.helper.ProjectHelper2;
+import org.apache.tools.ant.UnknownElement;
+
+
+/**
+ * Antlib task. It does not
+ * occur in an ant build file. It is the root element
+ * an antlib xml file.
+ *
+ * @since Ant 1.6
+ */
+public class Antlib extends Task implements TaskContainer {
+    //
+    // Static
+    //
+
+    /** The name of this task */
+    public static final String TAG = "antlib";
+
+    /**
+     * Static method to read an ant lib definition from
+     * a url.
+     *
+     * @param project   the current project
+     * @param antlibUrl the url to read the definitions from
+     * @param uri       the uri that the antlib is to be placed in
+     * @return   the ant lib task
+     */
+    public static Antlib createAntlib(Project project, URL antlibUrl,
+                                      String uri) {
+        // Check if we can contact the URL
+        try {
+            antlibUrl.openConnection().connect();
+        } catch (IOException ex) {
+            throw new BuildException(
+                "Unable to find " + antlibUrl, ex);
+        }
+        ComponentHelper helper =
+            ComponentHelper.getComponentHelper(project);
+        helper.enterAntLib(uri);
+        try {
+            // Should be safe to parse
+            ProjectHelper2 parser = new ProjectHelper2();
+            UnknownElement ue =
+                parser.parseUnknownElement(project, antlibUrl);
+            // Check name is "antlib"
+            if (!(ue.getTag().equals(TAG))) {
+                throw new BuildException(
+                    "Unexpected tag " + ue.getTag() + " expecting "
+                    + TAG, ue.getLocation());
+            }
+            Antlib antlib = new Antlib();
+            antlib.setProject(project);
+            antlib.setLocation(ue.getLocation());
+            antlib.setTaskName("antlib");
+            antlib.init();
+            ue.configure(antlib);
+            return antlib;
+        } finally {
+            helper.exitAntLib();
+        }
+    }
+
+
+    //
+    // Instance
+    //
+    private ClassLoader classLoader;
+    private String      uri = "";
+    private List  tasks = new ArrayList();
+
+    /**
+     * Set the class loader for this antlib.
+     * This class loader is used for any tasks that
+     * derive from Definer.
+     *
+     * @param classLoader the class loader
+     */
+    protected void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    /**
+     * Set the URI for this antlib.
+     * @param uri the namespace uri
+     */
+    protected void  setURI(String uri) {
+        this.uri = uri;
+    }
+
+    private ClassLoader getClassLoader() {
+        if (classLoader == null) {
+            classLoader = Antlib.class.getClassLoader();
+        }
+        return classLoader;
+    }
+
+    /**
+     * add a task to the list of tasks
+     *
+     * @param nestedTask Nested task to execute in antlib
+     */
+    public void addTask(Task nestedTask) {
+        tasks.add(nestedTask);
+    }
+
+    /**
+     * Execute the nested tasks, setting the classloader for
+     * any tasks that derive from Definer.
+     */
+    public void execute() {
+        for (Iterator i = tasks.iterator(); i.hasNext();) {
+            UnknownElement ue = (UnknownElement) i.next();
+            setLocation(ue.getLocation());
+            ue.maybeConfigure();
+            Object configuredObject = ue.getRealThing();
+            if (configuredObject == null) {
+                continue;
+            }
+            if (!(configuredObject instanceof AntlibDefinition)) {
+                throw new BuildException(
+                    "Invalid task in antlib " + ue.getTag()
+                    + " " + configuredObject.getClass() + " does not "
+                    + "extend org.apache.tools.ant.taskdefs.AntlibDefinition");
+            }
+            AntlibDefinition def = (AntlibDefinition) configuredObject;
+            def.setURI(uri);
+            def.setAntlibClassLoader(getClassLoader());
+            def.init();
+            def.execute();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/AntlibDefinition.java b/trunk/src/main/org/apache/tools/ant/taskdefs/AntlibDefinition.java
new file mode 100644
index 0000000..3ef31e3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/AntlibDefinition.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.Task;
+
+/**
+ * Base class for tasks that that can be used in antlibs.
+ * For handling uri and class loading.
+ *
+ * @since Ant 1.6
+ */
+public class AntlibDefinition extends Task {
+
+    private String uri = "";
+    private ClassLoader antlibClassLoader;
+
+    /**
+     * The URI for this definition.
+     * If the URI is "antlib:org.apache.tools.ant",
+     * (this is the default uri)
+     * the uri will be set to "".
+     * URIs that start with "ant:" are reserved
+     * and are not allowed in this context.
+     * @param uri the namespace URI
+     * @throws BuildException if a reserved URI is used
+     */
+    public void setURI(String uri) throws BuildException {
+        if (uri.equals(ProjectHelper.ANT_CORE_URI)) {
+            uri = "";
+        }
+        if (uri.startsWith("ant:")) {
+            throw new BuildException("Attempt to use a reserved URI " + uri);
+        }
+        this.uri = uri;
+    }
+
+    /**
+     * The URI for this definition.
+     * @return The URI for this defintion.
+     */
+    public String getURI() {
+        return uri;
+    }
+
+    /**
+     * Set the class loader of the loading object
+     *
+     * @param classLoader a <code>ClassLoader</code> value
+     */
+    public void setAntlibClassLoader(ClassLoader classLoader) {
+        this.antlibClassLoader = classLoader;
+    }
+
+    /**
+     * The current antlib classloader
+     * @return the antlib classloader for the definition, this
+     *         is null if the definition is not used in an antlib.
+     */
+    public ClassLoader getAntlibClassLoader() {
+        return antlibClassLoader;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Apt.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Apt.java
new file mode 100644
index 0000000..857fd0e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Apt.java
@@ -0,0 +1,265 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.compilers.AptExternalCompilerAdapter;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import java.util.Vector;
+import java.io.File;
+
+/**
+ * Apt Task for running the Annotation processing tool for JDK 1.5.  It derives
+ * from the existing Javac task, and forces the compiler based on whether we're
+ * executing internally, or externally.
+ *
+ * @since Ant 1.7
+ */
+
+
+public class Apt
+        extends Javac {
+    private boolean compile = true;
+    private String factory;
+    private Path factoryPath;
+    private Vector options = new Vector();
+    private File preprocessDir;
+    /** The name of the apt tool. */
+    public static final String EXECUTABLE_NAME = "apt";
+    /** An warning message when ignoring compiler attribute. */
+    public static final String ERROR_IGNORING_COMPILER_OPTION
+        = "Ignoring compiler attribute for the APT task, as it is fixed";
+    /** A warning message if used with java < 1.5. */
+    public static final String ERROR_WRONG_JAVA_VERSION
+        = "Apt task requires Java 1.5+";
+
+    /**
+     * exposed for debug messages
+     */
+    public static final String WARNING_IGNORING_FORK =
+        "Apt only runs in its own JVM; fork=false option ignored";
+
+    /**
+     * The nested option element.
+     */
+    public static final class Option {
+        private String name;
+        private String value;
+
+        /** Constructor for Option */
+        public Option() {
+            //default
+        }
+
+        /**
+         * Get the name attribute.
+         * @return the name attribute.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the name attribute.
+         * @param name the name of the option.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the value attribute.
+         * @return the value attribute.
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * Set the value attribute.
+         * @param value the value of the option.
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+    }
+
+    /**
+     * Construtor for Apt task.
+     * This sets the apt compiler adapter as the compiler in the super class.
+     */
+    public Apt() {
+        super();
+        super.setCompiler(AptExternalCompilerAdapter.class.getName());
+        super.setFork(true);
+    }
+
+    /**
+     * Get the name of the apt executable.
+     *
+     * @return the name of the executable.
+     */
+    public String getAptExecutable() {
+        return JavaEnvUtils.getJdkExecutable(EXECUTABLE_NAME);
+    }
+
+    /**
+     * Set the compiler.
+     * This is not allowed and a warning log message is made.
+     * @param compiler not used.
+     */
+    public void setCompiler(String compiler) {
+        log(ERROR_IGNORING_COMPILER_OPTION, Project.MSG_WARN);
+    }
+
+    /**
+     * Set the fork attribute.
+     * Non-forking APT is highly classpath dependent and appears to be too
+     * brittle to work. The sole reason this attribute is retained
+     * is the superclass does it
+     * @param fork if false; warn the option is ignored.
+     */
+    public void setFork(boolean fork) {
+        if (!fork) {
+            log(WARNING_IGNORING_FORK, Project.MSG_WARN);
+        }
+    }
+
+    /**
+     * Get the compiler class name.
+     * @return the compiler class name.
+     */
+    public String getCompiler() {
+        return super.getCompiler();
+    }
+
+    /**
+     * Get the compile option for the apt compiler.
+     * If this is false the "-nocompile" argument will be used.
+     * @return the value of the compile option.
+     */
+    public boolean isCompile() {
+        return compile;
+    }
+
+    /**
+     * Set the compile option for the apt compiler.
+     * Default value is true.
+     * @param compile if true set the compile option.
+     */
+    public void setCompile(boolean compile) {
+        this.compile = compile;
+    }
+
+    /**
+     * Get the factory option for the apt compiler.
+     * If this is non-null the "-factory" argument will be used.
+     * @return the value of the factory option.
+     */
+    public String getFactory() {
+        return factory;
+    }
+
+    /**
+     * Set the factory option for the apt compiler.
+     * Default value is null.
+     * @param factory the classname of the factory.
+     */
+    public void setFactory(String factory) {
+        this.factory = factory;
+    }
+
+    /**
+     * Add a reference to a path to the factoryPath attribute.
+     * @param ref a reference to a path.
+     */
+    public void setFactoryPathRef(Reference ref) {
+        createFactoryPath().setRefid(ref);
+    }
+
+    /**
+     * Add a path to the factoryPath attribute.
+     * @return a path to be configured.
+     */
+    public Path createFactoryPath() {
+        if (factoryPath == null) {
+            factoryPath = new Path(getProject());
+        }
+        return factoryPath.createPath();
+    }
+
+    /**
+     * Get the factory path attribute.
+     * If this is not null, the "-factorypath" argument will be used.
+     * The default value is null.
+     * @return the factory path attribute.
+     */
+    public Path getFactoryPath() {
+        return factoryPath;
+    }
+
+    /**
+     * Create a nested option.
+     * @return an option to be configured.
+     */
+    public Option createOption() {
+        Option opt = new Option();
+        options.add(opt);
+        return opt;
+    }
+
+    /**
+     * Get the options to the compiler.
+     * Each option will use '"-E" name ["=" value]' argument.
+     * @return the options.
+     */
+    public Vector getOptions() {
+        return options;
+    }
+
+    /**
+     * Get the preprocessdir attribute.
+     * This corresponds to the "-s" argument.
+     * The default value is null.
+     * @return the preprocessdir attribute.
+     */
+    public File getPreprocessDir() {
+        return preprocessDir;
+    }
+
+    /**
+     * Set the preprocessdir attribute.
+     * @param preprocessDir where to place processor generated source files.
+     */
+    public void setPreprocessDir(File preprocessDir) {
+        this.preprocessDir = preprocessDir;
+    }
+
+    /**
+     * Do the compilation.
+     * @throws BuildException on error.
+     */
+    public void execute()
+            throws BuildException {
+        super.execute();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Available.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Available.java
new file mode 100644
index 0000000..1af6aaa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Available.java
@@ -0,0 +1,517 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Will set the given property if the requested resource is available at
+ * runtime. This task may also be used as a condition by the condition task.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="control"
+ */
+public class Available extends Task implements Condition {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private String property;
+    private String classname;
+    private String filename;
+    private File file;
+    private Path filepath;
+    private String resource;
+    private FileDir type;
+    private Path classpath;
+    private AntClassLoader loader;
+    private Object value = "true";
+    private boolean isTask = false;
+    private boolean ignoreSystemclasses = false;
+    private boolean searchParents   = false;
+
+    /**
+     * Set the searchParents attribute.
+     * This controls the behaviour of the the "file" type.
+     * If true, the path, parent path and grandparent path are
+     * searched for the file. If false, only the path is seached.
+     * The default value is false.
+     * @param searchParents the value to set.
+     */
+    public void setSearchParents(boolean  searchParents) {
+        this.searchParents = searchParents;
+    }
+
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        createClasspath().append(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Set the path to use when looking for a file.
+     *
+     * @param filepath a Path instance containing the search path for files.
+     */
+    public void setFilepath(Path filepath) {
+        createFilepath().append(filepath);
+    }
+
+    /**
+     * Path to search for file resources.
+     *
+     * @return a new Path instance which Ant will configure with a file search
+     *         path.
+     */
+    public Path createFilepath() {
+        if (this.filepath == null) {
+            this.filepath = new Path(getProject());
+        }
+        return this.filepath.createPath();
+    }
+
+    /**
+     * Set the name of the property which will be set if the particular resource
+     * is available.
+     *
+     * @param property the name of the property to set.
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * Set the value to be given to the property if the desired resource is
+     * available.
+     *
+     * @param value the value to be given.
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Set the value to be given to the property if the desired resource is
+     * available.
+     *
+     * @param value the value to be given.
+     */
+    public void setValue(String value) {
+        setValue((Object) value);
+    }
+
+    /**
+     * Set a classname of a class which must be available to set the given
+     * property.
+     *
+     * @param classname the name of the class required.
+     */
+    public void setClassname(String classname) {
+        if (!"".equals(classname)) {
+            this.classname = classname;
+        }
+    }
+
+    /**
+     * Set the file which must be present in the file system to set the given
+     * property.
+     *
+     * @param file the name of the file which is required.
+     */
+    public void setFile(File file) {
+        this.file = file;
+        this.filename = FILE_UTILS.removeLeadingPath(getProject().getBaseDir(), file);
+    }
+
+    /**
+     * Set the name of a Java resource which is required to set the property.
+     *
+     * @param resource the name of a resource which is required to be available.
+     */
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+
+    /**
+     * @deprecated since 1.5.x.
+     *             setType(String) is deprecated and is replaced with
+     *             setType(Available.FileDir) to make Ant's Introspection
+     *             mechanism do the work and also to encapsulate operations on
+     *             the type in its own class.
+     * @param type the type of resource
+     */
+    public void setType(String type) {
+        log("DEPRECATED - The setType(String) method has been deprecated."
+            + " Use setType(Available.FileDir) instead.",
+            Project.MSG_WARN);
+        this.type = new FileDir();
+        this.type.setValue(type);
+    }
+
+    /**
+     * Set what type of file is required - either directory or file.
+     *
+     * @param type an instance of the FileDir enumeratedAttribute indicating
+     *             whether the file required is to be a directory or a plain
+     *             file.
+     */
+    public void setType(FileDir type) {
+        this.type = type;
+    }
+
+    /**
+     * Set whether the search for classes should ignore the runtime classes and
+     * just use the given classpath.
+     *
+     * @param ignore true if system classes are to be ignored.
+     */
+    public void setIgnoresystemclasses(boolean ignore) {
+        this.ignoreSystemclasses = ignore;
+    }
+
+    /**
+     * Entry point when operating as a task.
+     *
+     * @exception BuildException if the task is not configured correctly.
+     */
+    public void execute() throws BuildException {
+        if (property == null) {
+            throw new BuildException("property attribute is required",
+                                     getLocation());
+        }
+
+        isTask = true;
+        try {
+            if (eval()) {
+                PropertyHelper ph = PropertyHelper.getPropertyHelper(getProject());
+                Object oldvalue = ph.getProperty(property);
+                if (null != oldvalue && !oldvalue.equals(value)) {
+                    log("DEPRECATED - <available> used to override an existing"
+                        + " property."
+                        + StringUtils.LINE_SEP
+                        + "  Build file should not reuse the same property"
+                        + " name for different values.",
+                        Project.MSG_WARN);
+                }
+                // NB: this makes use of Project#setProperty rather than Project#setNewProperty
+                //     due to backwards compatiblity reasons
+                ph.setProperty(property, value, true);
+            }
+        } finally {
+            isTask = false;
+        }
+    }
+
+    /**
+     * Evaluate the availability of a resource.
+     *
+     * @return boolean is the resource is available.
+     * @exception BuildException if the condition is not configured correctly
+     */
+    public boolean eval() throws BuildException {
+        try {
+            if (classname == null && file == null && resource == null) {
+                throw new BuildException("At least one of (classname|file|"
+                                         + "resource) is required", getLocation());
+            }
+            if (type != null) {
+                if (file == null) {
+                    throw new BuildException("The type attribute is only valid "
+                                             + "when specifying the file "
+                                             + "attribute.", getLocation());
+                }
+            }
+            if (classpath != null) {
+                classpath.setProject(getProject());
+                this.loader = getProject().createClassLoader(classpath);
+            }
+            String appendix = "";
+            if (isTask) {
+                appendix = " to set property " + property;
+            } else {
+                setTaskName("available");
+            }
+            if ((classname != null) && !checkClass(classname)) {
+                log("Unable to load class " + classname + appendix,
+                    Project.MSG_VERBOSE);
+                return false;
+            }
+            if ((file != null) && !checkFile()) {
+                StringBuffer buf = new StringBuffer("Unable to find ");
+                if (type != null) {
+                    buf.append(type).append(' ');
+                }
+                buf.append(filename).append(appendix);
+                log(buf.toString(), Project.MSG_VERBOSE);
+                return false;
+            }
+            if ((resource != null) && !checkResource(resource)) {
+                log("Unable to load resource " + resource + appendix,
+                    Project.MSG_VERBOSE);
+                return false;
+            }
+        } finally {
+            if (loader != null) {
+                loader.cleanup();
+                loader = null;
+            }
+            if (!isTask) {
+                setTaskName(null);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Search for file/directory either relative to project's
+     * basedir or in the path given as filepath.
+     *
+     * <p>filepath can be a list of directory and/or file names (gen'd
+     * via <fileset>)</p>
+     *
+     * <p>look for:</p><ul>
+     *   <li>full-pathname specified == path in list</li>
+     *   <li>full-pathname specified == parent dir of path in list</li>
+     *   <li>simple name specified   == path in list</li>
+     *   <li>simple name specified   == path in list + name</li>
+     *   <li>simple name specified   == parent dir + name</li>
+     *   <li>simple name specified   == parent of parent dir + name</li>
+     * </ul>
+     */
+    private boolean checkFile() {
+        if (filepath == null) {
+            return checkFile(file, filename);
+        } else {
+            String[] paths = filepath.list();
+            for (int i = 0; i < paths.length; ++i) {
+                log("Searching " + paths[i], Project.MSG_VERBOSE);
+                File path = new File(paths[i]);
+
+                // **   full-pathname specified == path in list
+                // **   simple name specified   == path in list
+                if (path.exists()
+                    && (filename.equals(paths[i])
+                        || filename.equals(path.getName()))) {
+                    if (type == null) {
+                        log("Found: " + path, Project.MSG_VERBOSE);
+                        return true;
+                    } else if (type.isDir()
+                               && path.isDirectory()) {
+                        log("Found directory: " + path, Project.MSG_VERBOSE);
+                        return true;
+                    } else if (type.isFile()
+                               && path.isFile()) {
+                        log("Found file: " + path, Project.MSG_VERBOSE);
+                        return true;
+                    }
+                    // not the requested type
+                    return false;
+                }
+                File parent = path.getParentFile();
+                // **   full-pathname specified == parent dir of path in list
+                if (parent != null && parent.exists()
+                    && filename.equals(parent.getAbsolutePath())) {
+                    if (type == null) {
+                        log("Found: " + parent, Project.MSG_VERBOSE);
+                        return true;
+                    } else if (type.isDir()) {
+                        log("Found directory: " + parent, Project.MSG_VERBOSE);
+                        return true;
+                    }
+                    // not the requested type
+                    return false;
+                }
+                // **   simple name specified   == path in list + name
+                if (path.exists() && path.isDirectory()) {
+                    if (checkFile(new File(path, filename),
+                                  filename + " in " + path)) {
+                        return true;
+                    }
+                }
+
+                // **   simple name specified   == parent dir + name
+                while (searchParents && parent != null && parent.exists()) {
+                    if (checkFile(new File(parent, filename),
+                                  filename + " in " + parent)) {
+                        return true;
+                    }
+                    parent = parent.getParentFile();
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Check if a given file exists and matches the required type.
+     */
+    private boolean checkFile(File f, String text) {
+        if (type != null) {
+            if (type.isDir()) {
+                if (f.isDirectory()) {
+                    log("Found directory: " + text, Project.MSG_VERBOSE);
+                }
+                return f.isDirectory();
+            } else if (type.isFile()) {
+                if (f.isFile()) {
+                    log("Found file: " + text, Project.MSG_VERBOSE);
+                }
+                return f.isFile();
+            }
+        }
+        if (f.exists()) {
+            log("Found: " + text, Project.MSG_VERBOSE);
+        }
+        return f.exists();
+    }
+
+    /**
+     * Check if a given resource can be loaded.
+     */
+    private boolean checkResource(String resource) {
+        if (loader != null) {
+            return (loader.getResourceAsStream(resource) != null);
+        } else {
+            ClassLoader cL = this.getClass().getClassLoader();
+            if (cL != null) {
+                return (cL.getResourceAsStream(resource) != null);
+            } else {
+                return
+                    (ClassLoader.getSystemResourceAsStream(resource) != null);
+            }
+        }
+    }
+
+    /**
+     * Check if a given class can be loaded.
+     */
+    private boolean checkClass(String classname) {
+        try {
+            if (ignoreSystemclasses) {
+                loader = getProject().createClassLoader(classpath);
+                loader.setParentFirst(false);
+                loader.addJavaLibraries();
+                if (loader != null) {
+                    try {
+                        loader.findClass(classname);
+                    } catch (SecurityException se) {
+                        // class found but restricted name; this is
+                        // actually the case we're looking for in JDK 1.3+,
+                        // so catch the exception and return
+                        return true;
+                    }
+                } else {
+                    return false;
+                }
+            } else if (loader != null) {
+                loader.loadClass(classname);
+            } else {
+                ClassLoader l = this.getClass().getClassLoader();
+                // Can return null to represent the bootstrap class loader.
+                // see API docs of Class.getClassLoader.
+                if (l != null) {
+                    Class.forName(classname, true, l);
+                } else {
+                    Class.forName(classname);
+                }
+            }
+            return true;
+        } catch (ClassNotFoundException e) {
+            log("class \"" + classname + "\" was not found",
+                Project.MSG_DEBUG);
+            return false;
+        } catch (NoClassDefFoundError e) {
+            log("Could not load dependent class \"" + e.getMessage()
+                + "\" for class \"" + classname + "\"",
+                Project.MSG_DEBUG);
+            return false;
+        }
+    }
+
+    /**
+     * EnumeratedAttribute covering the file types to be checked for, either
+     * file or dir.
+     */
+    public static class FileDir extends EnumeratedAttribute {
+
+        private static final String[] VALUES = {"file", "dir"};
+
+        /**
+         * @see EnumeratedAttribute#getValues
+         */
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return VALUES;
+        }
+
+        /**
+         * Indicate if the value specifies a directory.
+         *
+         * @return true if the value specifies a directory.
+         */
+        public boolean isDir() {
+            return "dir".equalsIgnoreCase(getValue());
+        }
+
+        /**
+         * Indicate if the value specifies a file.
+         *
+         * @return true if the value specifies a file.
+         */
+        public boolean isFile() {
+            return "file".equalsIgnoreCase(getValue());
+        }
+
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/BUnzip2.java b/trunk/src/main/org/apache/tools/ant/taskdefs/BUnzip2.java
new file mode 100644
index 0000000..2f13626
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/BUnzip2.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+
+import java.io.BufferedInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.bzip2.CBZip2InputStream;
+
+/**
+ * Expands a file that has been compressed with the BZIP2
+ * algorithm. Normally used to compress non-compressed archives such
+ * as TAR files.
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="packaging"
+ */
+
+public class BUnzip2 extends Unpack {
+
+    private static final int BUFFER_SIZE = 8 * 1024;
+
+    private static final String DEFAULT_EXTENSION = ".bz2";
+
+    /**
+     * Get the default extension.
+     * @return the string ".bz2"
+     */
+    protected String getDefaultExtension() {
+        return DEFAULT_EXTENSION;
+    }
+
+    /**
+     * Do the unbzipping.
+     */
+    protected void extract() {
+        if (source.lastModified() > dest.lastModified()) {
+            log("Expanding " + source.getAbsolutePath() + " to "
+                + dest.getAbsolutePath());
+
+            FileOutputStream out = null;
+            CBZip2InputStream zIn = null;
+            InputStream fis = null;
+            BufferedInputStream bis = null;
+            try {
+                out = new FileOutputStream(dest);
+                fis = srcResource.getInputStream();
+                bis = new BufferedInputStream(fis);
+                int b = bis.read();
+                if (b != 'B') {
+                    throw new BuildException("Invalid bz2 file.", getLocation());
+                }
+                b = bis.read();
+                if (b != 'Z') {
+                    throw new BuildException("Invalid bz2 file.", getLocation());
+                }
+                zIn = new CBZip2InputStream(bis);
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int count = 0;
+                do {
+                    out.write(buffer, 0, count);
+                    count = zIn.read(buffer, 0, buffer.length);
+                } while (count != -1);
+            } catch (IOException ioe) {
+                String msg = "Problem expanding bzip2 " + ioe.getMessage();
+                throw new BuildException(msg, ioe, getLocation());
+            } finally {
+                FileUtils.close(bis);
+                FileUtils.close(fis);
+                FileUtils.close(out);
+                FileUtils.close(zIn);
+            }
+        }
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;gunzip&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true if this class supports non file resources.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(BUnzip2.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/BZip2.java b/trunk/src/main/org/apache/tools/ant/taskdefs/BZip2.java
new file mode 100644
index 0000000..59785c4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/BZip2.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.bzip2.CBZip2OutputStream;
+
+/**
+ * Compresses a file with the BZIP2 algorithm. Normally used to compress
+ * non-compressed archives such as TAR files.
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="packaging"
+ */
+
+public class BZip2 extends Pack {
+    /**
+     * Compress the zipFile.
+     */
+    protected void pack() {
+        CBZip2OutputStream zOut = null;
+        try {
+            BufferedOutputStream bos =
+                new BufferedOutputStream(new FileOutputStream(zipFile));
+            bos.write('B');
+            bos.write('Z');
+            zOut = new CBZip2OutputStream(bos);
+            zipResource(getSrcResource(), zOut);
+        } catch (IOException ioe) {
+            String msg = "Problem creating bzip2 " + ioe.getMessage();
+            throw new BuildException(msg, ioe, getLocation());
+        } finally {
+            FileUtils.close(zOut);
+        }
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;bzip2&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true if this task support non file resources.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(BZip2.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Basename.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Basename.java
new file mode 100644
index 0000000..9d87b2e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Basename.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Sets a property to the base name of a specified file, optionally minus a
+ * suffix.
+ *
+ * This task can accept the following attributes:
+ * <ul>
+ * <li>file
+ * <li>property
+ * <li>suffix
+ * </ul>
+ * The <b>file</b> and <b>property</b> attributes are required. The
+ * <b>suffix</b> attribute can be specified either with or without
+ * the &quot;.&quot;, and the result will be the same (ie., the
+ * returned file name will be minus the .suffix).
+ * <p>
+ * When this task executes, it will set the specified property to the
+ * value of the last element in the specified file. If file is a
+ * directory, the basename will be the last directory element. If file
+ * is a full-path filename, the basename will be the simple file name.
+ * If a suffix is specified, and the specified file ends in that suffix,
+ * the basename will be the simple file name without the suffix.
+ *
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="property"
+ */
+
+public class Basename extends Task {
+    private File file;
+    private String property;
+    private String suffix;
+
+    /**
+     * file or directory to get base name from
+     * @param file file or directory to get base name from
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+    * Property to set base name to.
+     * @param property name of property
+    */
+    public void setProperty(String property) {
+        this.property  = property;
+    }
+
+    /**
+    * Optional suffix to remove from base name.
+     * @param suffix suffix to remove from base name
+    */
+    public void setSuffix(String suffix) {
+        this.suffix = suffix;
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if required attributes are not supplied
+     * property and attribute are required attributes
+     */
+    public void execute() throws BuildException {
+        if (property == null) {
+            throw new BuildException("property attribute required", getLocation());
+        }
+        if (file == null) {
+            throw new BuildException("file attribute required", getLocation());
+        }
+        String value = file.getName();
+        if (suffix != null && value.endsWith(suffix)) {
+            // if the suffix does not starts with a '.' and the
+            // char preceding the suffix is a '.', we assume the user
+            // wants to remove the '.' as well (see docs)
+            int pos = value.length() - suffix.length();
+            if (pos > 0 && suffix.charAt(0) != '.'
+                && value.charAt(pos - 1) == '.') {
+                pos--;
+            }
+            value = value.substring(0, pos);
+        }
+        getProject().setNewProperty(property, value);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/BuildNumber.java b/trunk/src/main/org/apache/tools/ant/taskdefs/BuildNumber.java
new file mode 100644
index 0000000..4a9b0aa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/BuildNumber.java
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Read, increment, and write a build number in a file
+ * It will first
+ * attempt to read a build number from a file, then set the property
+ * "build.number" to the value that was read in (or 0 if no such value). Then
+ * it will increment the build number by one and write it back out into the
+ * file.
+ *
+ * @since Ant 1.5
+ * @ant.task name="buildnumber"
+ */
+public class BuildNumber
+     extends Task {
+    /**
+     * The name of the property in which the build number is stored.
+     */
+    private static final String DEFAULT_PROPERTY_NAME = "build.number";
+
+    /** The default filename to use if no file specified.  */
+    private static final String DEFAULT_FILENAME = DEFAULT_PROPERTY_NAME;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** The File in which the build number is stored.  */
+    private File myFile;
+
+
+    /**
+     * The file in which the build number is stored. Defaults to
+     * "build.number" if not specified.
+     *
+     * @param file the file in which build number is stored.
+     */
+    public void setFile(final File file) {
+        myFile = file;
+    }
+
+
+    /**
+     * Run task.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute()
+         throws BuildException {
+        File savedFile = myFile; // may be altered in validate
+
+        validate();
+
+        final Properties properties = loadProperties();
+        final int buildNumber = getBuildNumber(properties);
+
+        properties.put(DEFAULT_PROPERTY_NAME,
+            String.valueOf(buildNumber + 1));
+
+        // Write the properties file back out
+        FileOutputStream output = null;
+
+        try {
+            output = new FileOutputStream(myFile);
+
+            final String header = "Build Number for ANT. Do not edit!";
+
+            properties.store(output, header);
+        } catch (final IOException ioe) {
+            final String message = "Error while writing " + myFile;
+
+            throw new BuildException(message, ioe);
+        } finally {
+            if (null != output) {
+                try {
+                    output.close();
+                } catch (final IOException ioe) {
+                    log("error closing output stream " + ioe, Project.MSG_ERR);
+                }
+            }
+            myFile = savedFile;
+        }
+
+        //Finally set the property
+        getProject().setNewProperty(DEFAULT_PROPERTY_NAME,
+            String.valueOf(buildNumber));
+    }
+
+
+    /**
+     * Utility method to retrieve build number from properties object.
+     *
+     * @param properties the properties to retrieve build number from
+     * @return the build number or if no number in properties object
+     * @throws BuildException if build.number property is not an integer
+     */
+    private int getBuildNumber(final Properties properties)
+         throws BuildException {
+        final String buildNumber =
+            properties.getProperty(DEFAULT_PROPERTY_NAME, "0").trim();
+
+        // Try parsing the line into an integer.
+        try {
+            return Integer.parseInt(buildNumber);
+        } catch (final NumberFormatException nfe) {
+            final String message =
+                myFile + " contains a non integer build number: " + buildNumber;
+            throw new BuildException(message, nfe);
+        }
+    }
+
+
+    /**
+     * Utility method to load properties from file.
+     *
+     * @return the loaded properties
+     * @throws BuildException
+     */
+    private Properties loadProperties()
+         throws BuildException {
+        FileInputStream input = null;
+
+        try {
+            final Properties properties = new Properties();
+
+            input = new FileInputStream(myFile);
+            properties.load(input);
+            return properties;
+        } catch (final IOException ioe) {
+            throw new BuildException(ioe);
+        } finally {
+            if (null != input) {
+                try {
+                    input.close();
+                } catch (final IOException ioe) {
+                    log("error closing input stream " + ioe, Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Validate that the task parameters are valid.
+     *
+     * @throws BuildException if parameters are invalid
+     */
+    private void validate()
+         throws BuildException {
+        if (null == myFile) {
+            myFile = FILE_UTILS.resolveFile(getProject().getBaseDir(), DEFAULT_FILENAME);
+        }
+
+        if (!myFile.exists()) {
+            try {
+                FILE_UTILS.createNewFile(myFile);
+            } catch (final IOException ioe) {
+                final String message =
+                    myFile + " doesn't exist and new file can't be created.";
+                throw new BuildException(message, ioe);
+            }
+        }
+
+        if (!myFile.canRead()) {
+            final String message = "Unable to read from " + myFile + ".";
+            throw new BuildException(message);
+        }
+
+        if (!myFile.canWrite()) {
+            final String message = "Unable to write to " + myFile + ".";
+            throw new BuildException(message);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/CVSPass.java b/trunk/src/main/org/apache/tools/ant/taskdefs/CVSPass.java
new file mode 100644
index 0000000..9bc9563
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/CVSPass.java
@@ -0,0 +1,171 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Adds an new entry to a CVS password file.
+ *
+ *
+ * @since Ant 1.4
+ *
+ * @ant.task category="scm"
+ */
+public class CVSPass extends Task {
+    /** CVS Root */
+    private String cvsRoot = null;
+    /** Password file to add password to */
+    private File passFile = null;
+    /** Password to add to file */
+    private String password = null;
+
+    /** Array contain char conversion data */
+    private final char[] shifts = {
+          0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
+         16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
+        114, 120,  53,  79,  96, 109,  72, 108,  70,  64,  76,  67, 116,  74,  68,  87,
+        111,  52,  75, 119,  49,  34,  82,  81,  95,  65, 112,  86, 118, 110, 122, 105,
+         41,  57,  83,  43,  46, 102,  40,  89,  38, 103,  45,  50,  42, 123,  91,  35,
+        125,  55,  54,  66, 124, 126,  59,  47,  92,  71, 115,  78,  88, 107, 106,  56,
+         36, 121, 117, 104, 101, 100,  69,  73,  99,  63,  94,  93,  39,  37,  61,  48,
+         58, 113,  32,  90,  44,  98,  60,  51,  33,  97,  62,  77,  84,  80,  85, 223,
+        225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190,
+        199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, 226, 193,
+        174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, 161, 179, 160, 212,
+        207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246,
+        192, 159, 244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176,
+        227, 231, 219, 169, 175, 156, 206, 198, 129, 164, 150, 210, 154, 177, 134, 127,
+        182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195,
+        243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152
+    };
+
+    /**
+     * Create a CVS task using the default cvspass file location.
+     */
+    public CVSPass() {
+        passFile = new File(
+            System.getProperty("cygwin.user.home",
+                System.getProperty("user.home"))
+            + File.separatorChar + ".cvspass");
+    }
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public final void execute() throws BuildException {
+        if (cvsRoot == null) {
+            throw new BuildException("cvsroot is required");
+        }
+        if (password == null) {
+            throw new BuildException("password is required");
+        }
+
+        log("cvsRoot: " + cvsRoot, Project.MSG_DEBUG);
+        log("password: " + password, Project.MSG_DEBUG);
+        log("passFile: " + passFile, Project.MSG_DEBUG);
+
+        BufferedReader reader = null;
+        PrintWriter writer = null;
+        try {
+            StringBuffer buf = new StringBuffer();
+
+            if (passFile.exists()) {
+                reader = new BufferedReader(new FileReader(passFile));
+
+                String line = null;
+
+                while ((line = reader.readLine()) != null) {
+                    if (!line.startsWith(cvsRoot)) {
+                        buf.append(line).append(StringUtils.LINE_SEP);
+                    }
+                }
+            }
+
+            String pwdfile = buf.toString() + cvsRoot + " A"
+                + mangle(password);
+
+            log("Writing -> " + pwdfile , Project.MSG_DEBUG);
+
+            writer = new PrintWriter(new FileWriter(passFile));
+
+            writer.println(pwdfile);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    private final String mangle(String password) {
+        StringBuffer buf = new StringBuffer();
+        for (int i = 0; i < password.length(); i++) {
+            buf.append(shifts[password.charAt(i)]);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * The CVS repository to add an entry for.
+     *
+     * @param cvsRoot the CVS repository
+     */
+    public void setCvsroot(String cvsRoot) {
+        this.cvsRoot = cvsRoot;
+    }
+
+    /**
+     * Password file to add the entry to.
+     *
+     * @param passFile the password file.
+     */
+    public void setPassfile(File passFile) {
+        this.passFile = passFile;
+    }
+
+    /**
+     * Password to be added to the password file.
+     *
+     * @param password the password.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/CallTarget.java b/trunk/src/main/org/apache/tools/ant/taskdefs/CallTarget.java
new file mode 100644
index 0000000..a6b3f67
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/CallTarget.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.PropertySet;
+
+/**
+ * Call another target in the same project.
+ *
+ *  <pre>
+ *    &lt;target name="foo"&gt;
+ *      &lt;antcall target="bar"&gt;
+ *        &lt;param name="property1" value="aaaaa" /&gt;
+ *        &lt;param name="foo" value="baz" /&gt;
+ *       &lt;/antcall&gt;
+ *    &lt;/target&gt;
+ *
+ *    &lt;target name="bar" depends="init"&gt;
+ *      &lt;echo message="prop is ${property1} ${foo}" /&gt;
+ *    &lt;/target&gt;
+ * </pre>
+ *
+ * <p>This only works as expected if neither property1 nor foo are
+ * defined in the project itself.
+ *
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="antcall" category="control"
+ */
+public class CallTarget extends Task {
+
+    private Ant callee;
+    // must match the default value of Ant#inheritAll
+    private boolean inheritAll = true;
+    // must match the default value of Ant#inheritRefs
+    private boolean inheritRefs = false;
+
+    private boolean targetSet = false;
+
+    /**
+     * If true, pass all properties to the new Ant project.
+     * Defaults to true.
+     * @param inherit <code>boolean</code> flag.
+     */
+    public void setInheritAll(boolean inherit) {
+       inheritAll = inherit;
+    }
+
+    /**
+     * If true, pass all references to the new Ant project.
+     * Defaults to false.
+     * @param inheritRefs <code>boolean</code> flag.
+     */
+    public void setInheritRefs(boolean inheritRefs) {
+        this.inheritRefs = inheritRefs;
+    }
+
+    /**
+     * Initialize this task by creating new instance of the ant task and
+     * configuring it by calling its own init method.
+     */
+    public void init() {
+        callee = new Ant(this);
+        callee.init();
+    }
+
+    /**
+     * Delegate the work to the ant task instance, after setting it up.
+     * @throws BuildException on validation failure or if the target didn't
+     * execute.
+     */
+    public void execute() throws BuildException {
+        if (callee == null) {
+            init();
+        }
+        if (!targetSet) {
+            throw new BuildException(
+                "Attribute target or at least one nested target is required.",
+                 getLocation());
+        }
+        callee.setAntfile(getProject().getProperty("ant.file"));
+        callee.setInheritAll(inheritAll);
+        callee.setInheritRefs(inheritRefs);
+        callee.execute();
+    }
+
+    /**
+     * Create a new Property to pass to the invoked target(s).
+     * @return a <code>Property</code> object.
+     */
+    public Property createParam() {
+        if (callee == null) {
+            init();
+        }
+        return callee.createProperty();
+    }
+
+    /**
+     * Reference element identifying a data type to carry
+     * over to the invoked target.
+     * @param r the specified <code>Ant.Reference</code>.
+     * @since Ant 1.5
+     */
+    public void addReference(Ant.Reference r) {
+        if (callee == null) {
+            init();
+        }
+        callee.addReference(r);
+    }
+
+    /**
+     * Set of properties to pass to the new project.
+     * @param ps the <code>PropertySet</code> to pass.
+     * @since Ant 1.6
+     */
+    public void addPropertyset(PropertySet ps) {
+        if (callee == null) {
+            init();
+        }
+        callee.addPropertyset(ps);
+    }
+
+    /**
+     * Set target to execute.
+     * @param target the name of the target to execute.
+     */
+    public void setTarget(String target) {
+        if (callee == null) {
+            init();
+        }
+        callee.setTarget(target);
+        targetSet = true;
+    }
+
+    /**
+     * Add a target to the list of targets to invoke.
+     * @param t <code>Ant.TargetElement</code> representing the target.
+     * @since Ant 1.6.3
+     */
+    public void addConfiguredTarget(Ant.TargetElement t) {
+        if (callee == null) {
+            init();
+        }
+        callee.addConfiguredTarget(t);
+        targetSet = true;
+    }
+
+    /**
+     * Handles output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param output The string output to output.
+     * @see Task#handleOutput(String)
+     * @since Ant 1.5
+     */
+    public void handleOutput(String output) {
+        if (callee != null) {
+            callee.handleOutput(output);
+        } else {
+            super.handleOutput(output);
+        }
+    }
+
+    /**
+     * Handles input.
+     * Deleate to the created project, if present, otherwise
+     * call the super class.
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @see Task#handleInput(byte[], int, int)
+     * @since Ant 1.6
+     */
+    public int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (callee != null) {
+            return callee.handleInput(buffer, offset, length);
+        }
+        return super.handleInput(buffer, offset, length);
+    }
+
+    /**
+     * Handles output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param output The string to output.
+     * @see Task#handleFlush(String)
+     * @since Ant 1.5.2
+     */
+    public void handleFlush(String output) {
+        if (callee != null) {
+            callee.handleFlush(output);
+        } else {
+            super.handleFlush(output);
+        }
+    }
+
+    /**
+     * Handle error output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param output The string to output.
+     *
+     * @see Task#handleErrorOutput(String)
+     * @since Ant 1.5
+     */
+    public void handleErrorOutput(String output) {
+        if (callee != null) {
+            callee.handleErrorOutput(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+    /**
+     * Handle error output.
+     * Send it the the new project if is present, otherwise
+     * call the super class.
+     * @param output The string to output.
+     * @see Task#handleErrorFlush(String)
+     * @since Ant 1.5.2
+     */
+    public void handleErrorFlush(String output) {
+        if (callee != null) {
+            callee.handleErrorFlush(output);
+        } else {
+            super.handleErrorFlush(output);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Checksum.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Checksum.java
new file mode 100644
index 0000000..2d5c882
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Checksum.java
@@ -0,0 +1,692 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.Arrays;
+import java.text.MessageFormat;
+import java.text.ParseException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.selectors.Type;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Used to create or verify file checksums.
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="control"
+ */
+public class Checksum extends MatchingTask implements Condition {
+
+    private static final int NIBBLE = 4;
+    private static final int WORD = 16;
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final int BYTE_MASK = 0xFF;
+
+    private static class FileUnion extends Restrict {
+        private Union u;
+        FileUnion() {
+            u = new Union();
+            super.add(u);
+            super.add(Type.FILE);
+        }
+        public void add(ResourceCollection rc) {
+            u.add(rc);
+        }
+    }
+
+    /**
+     * File for which checksum is to be calculated.
+     */
+    private File file = null;
+
+    /**
+     * Root directory in which the checksum files will be written.
+     * If not specified, the checksum files will be written
+     * in the same directory as each file.
+     */
+    private File todir;
+
+    /**
+     * MessageDigest algorithm to be used.
+     */
+    private String algorithm = "MD5";
+    /**
+     * MessageDigest Algorithm provider
+     */
+    private String provider = null;
+    /**
+     * File Extension that is be to used to create or identify
+     * destination file
+     */
+    private String fileext;
+    /**
+     * Holds generated checksum and gets set as a Project Property.
+     */
+    private String property;
+    /**
+     * Holds checksums for all files (both calculated and cached on disk).
+     * Key:   java.util.File (source file)
+     * Value: java.lang.String (digest)
+     */
+    private Map allDigests = new HashMap();
+    /**
+     * Holds relative file names for all files (always with a forward slash).
+     * This is used to calculate the total hash.
+     * Key:   java.util.File (source file)
+     * Value: java.lang.String (relative file name)
+     */
+    private Map relativeFilePaths = new HashMap();
+    /**
+     * Property where totalChecksum gets set.
+     */
+    private String totalproperty;
+    /**
+     * Whether or not to create a new file.
+     * Defaults to <code>false</code>.
+     */
+    private boolean forceOverwrite;
+    /**
+     * Contains the result of a checksum verification. ("true" or "false")
+     */
+    private String verifyProperty;
+    /**
+     * Resource Collection.
+     */
+    private FileUnion resources = null;
+    /**
+     * Stores SourceFile, DestFile pairs and SourceFile, Property String pairs.
+     */
+    private Hashtable includeFileMap = new Hashtable();
+    /**
+     * Message Digest instance
+     */
+    private MessageDigest messageDigest;
+    /**
+     * is this task being used as a nested condition element?
+     */
+    private boolean isCondition;
+    /**
+     * Size of the read buffer to use.
+     */
+    private int readBufferSize = BUFFER_SIZE;
+
+    /**
+     * Formater for the checksum file.
+     */
+    private MessageFormat format = FormatElement.getDefault().getFormat();
+
+    /**
+     * Sets the file for which the checksum is to be calculated.
+     * @param file a <code>File</code> value
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Sets the root directory where checksum files will be
+     * written/read
+     * @param todir the directory to write to
+     * @since Ant 1.6
+     */
+    public void setTodir(File todir) {
+        this.todir = todir;
+    }
+
+    /**
+     * Specifies the algorithm to be used to compute the checksum.
+     * Defaults to "MD5". Other popular algorithms like "SHA" may be used as well.
+     * @param algorithm a <code>String</code> value
+     */
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Sets the MessageDigest algorithm provider to be used
+     * to calculate the checksum.
+     * @param provider a <code>String</code> value
+     */
+    public void setProvider(String provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Sets the file extension that is be to used to
+     * create or identify destination file.
+     * @param fileext a <code>String</code> value
+     */
+    public void setFileext(String fileext) {
+        this.fileext = fileext;
+    }
+
+    /**
+     * Sets the property to hold the generated checksum.
+     * @param property a <code>String</code> value
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * Sets the property to hold the generated total checksum
+     * for all files.
+     * @param totalproperty a <code>String</code> value
+     *
+     * @since Ant 1.6
+     */
+    public void setTotalproperty(String totalproperty) {
+        this.totalproperty = totalproperty;
+    }
+
+    /**
+     * Sets the verify property.  This project property holds
+     * the result of a checksum verification - "true" or "false"
+     * @param verifyProperty a <code>String</code> value
+     */
+    public void setVerifyproperty(String verifyProperty) {
+        this.verifyProperty = verifyProperty;
+    }
+
+    /**
+     * Whether or not to overwrite existing file irrespective of
+     * whether it is newer than
+     * the source file.  Defaults to false.
+     * @param forceOverwrite a <code>boolean</code> value
+     */
+    public void setForceOverwrite(boolean forceOverwrite) {
+        this.forceOverwrite = forceOverwrite;
+    }
+
+    /**
+     * The size of the read buffer to use.
+     * @param size an <code>int</code> value
+     */
+    public void setReadBufferSize(int size) {
+        this.readBufferSize = size;
+    }
+
+    /**
+     * Select the in/output pattern via a well know format name.
+     * @param e an <code>enumerated</code> value
+     *
+     * @since 1.7.0
+     */
+    public void setFormat(FormatElement e) {
+        format = e.getFormat();
+    }
+
+    /**
+     * Specify the pattern to use as a MessageFormat pattern.
+     *
+     * <p>{0} gets replaced by the checksum, {1} by the filename.</p>
+     * @param p a <code>String</code> value
+     *
+     * @since 1.7.0
+     */
+    public void setPattern(String p) {
+        format = new MessageFormat(p);
+    }
+
+    /**
+     * Files to generate checksums for.
+     * @param set a fileset of files to generate checksums for.
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Add a resource collection.
+     * @param rc the ResourceCollection to add.
+     */
+    public void add(ResourceCollection rc) {
+        if (rc == null) {
+            return;
+        }
+        resources = (resources == null) ? new FileUnion() : resources;
+        resources.add(rc);
+    }
+
+    /**
+     * Calculate the checksum(s).
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        isCondition = false;
+        boolean value = validateAndExecute();
+        if (verifyProperty != null) {
+            getProject().setNewProperty(
+                verifyProperty,
+                (value ? Boolean.TRUE.toString() : Boolean.FALSE.toString()));
+        }
+    }
+
+    /**
+     * Calculate the checksum(s)
+     *
+     * @return Returns true if the checksum verification test passed,
+     * false otherwise.
+     * @throws BuildException on error
+     */
+    public boolean eval() throws BuildException {
+        isCondition = true;
+        return validateAndExecute();
+    }
+
+    /**
+     * Validate attributes and get down to business.
+     */
+    private boolean validateAndExecute() throws BuildException {
+        String savedFileExt = fileext;
+
+        if (file == null && (resources == null || resources.size() == 0)) {
+            throw new BuildException(
+                "Specify at least one source - a file or a resource collection.");
+        }
+        if (!(resources == null || resources.isFilesystemOnly())) {
+            throw new BuildException("Can only calculate checksums for file-based resources.");
+        }
+        if (file != null && file.exists() && file.isDirectory()) {
+            throw new BuildException("Checksum cannot be generated for directories");
+        }
+        if (file != null && totalproperty != null) {
+            throw new BuildException("File and Totalproperty cannot co-exist.");
+        }
+        if (property != null && fileext != null) {
+            throw new BuildException("Property and FileExt cannot co-exist.");
+        }
+        if (property != null) {
+            if (forceOverwrite) {
+                throw new BuildException(
+                    "ForceOverwrite cannot be used when Property is specified");
+            }
+            int ct = 0;
+            if (resources != null) {
+                ct += resources.size();
+            }
+            if (file != null) {
+                ct++;
+            }
+            if (ct > 1) {
+                throw new BuildException(
+                    "Multiple files cannot be used when Property is specified");
+            }
+        }
+        if (verifyProperty != null) {
+            isCondition = true;
+        }
+        if (verifyProperty != null && forceOverwrite) {
+            throw new BuildException("VerifyProperty and ForceOverwrite cannot co-exist.");
+        }
+        if (isCondition && forceOverwrite) {
+            throw new BuildException(
+                "ForceOverwrite cannot be used when conditions are being used.");
+        }
+        messageDigest = null;
+        if (provider != null) {
+            try {
+                messageDigest = MessageDigest.getInstance(algorithm, provider);
+            } catch (NoSuchAlgorithmException noalgo) {
+                throw new BuildException(noalgo, getLocation());
+            } catch (NoSuchProviderException noprovider) {
+                throw new BuildException(noprovider, getLocation());
+            }
+        } else {
+            try {
+                messageDigest = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException noalgo) {
+                throw new BuildException(noalgo, getLocation());
+            }
+        }
+        if (messageDigest == null) {
+            throw new BuildException("Unable to create Message Digest", getLocation());
+        }
+        if (fileext == null) {
+            fileext = "." + algorithm;
+        } else if (fileext.trim().length() == 0) {
+            throw new BuildException("File extension when specified must not be an empty string");
+        }
+        try {
+            if (resources != null) {
+                for (Iterator i = resources.iterator(); i.hasNext();) {
+                    FileResource fr = (FileResource) i.next();
+                    File src = fr.getFile();
+                    if (totalproperty != null || todir != null) {
+                        // Use '/' to calculate digest based on file name.
+                        // This is required in order to get the same result
+                        // on different platforms.
+                        relativeFilePaths.put(src, fr.getName().replace(File.separatorChar, '/'));
+                    }
+                    addToIncludeFileMap(src);
+                }
+            }
+            if (file != null) {
+                if (totalproperty != null || todir != null) {
+                    relativeFilePaths.put(
+                        file, file.getName().replace(File.separatorChar, '/'));
+                }
+                addToIncludeFileMap(file);
+            }
+            return generateChecksums();
+        } finally {
+            fileext = savedFileExt;
+            includeFileMap.clear();
+        }
+    }
+
+    /**
+     * Add key-value pair to the hashtable upon which
+     * to later operate upon.
+     */
+    private void addToIncludeFileMap(File file) throws BuildException {
+        if (file.exists()) {
+            if (property == null) {
+                File checksumFile = getChecksumFile(file);
+                if (forceOverwrite || isCondition
+                    || (file.lastModified() > checksumFile.lastModified())) {
+                    includeFileMap.put(file, checksumFile);
+                } else {
+                    log(file + " omitted as " + checksumFile + " is up to date.",
+                        Project.MSG_VERBOSE);
+                    if (totalproperty != null) {
+                        // Read the checksum from disk.
+                        String checksum = readChecksum(checksumFile);
+                        byte[] digest = decodeHex(checksum.toCharArray());
+                        allDigests.put(file, digest);
+                    }
+                }
+            } else {
+                includeFileMap.put(file, property);
+            }
+        } else {
+            String message = "Could not find file "
+                + file.getAbsolutePath()
+                + " to generate checksum for.";
+            log(message);
+            throw new BuildException(message, getLocation());
+        }
+    }
+
+    private File getChecksumFile(File file) {
+        File directory;
+        if (todir != null) {
+            // A separate directory was explicitly declared
+            String path = (String) relativeFilePaths.get(file);
+            if (path == null) {
+                //bug 37386. this should not occur, but it has, once.
+                throw new BuildException(
+                    "Internal error: "
+                    + "relativeFilePaths could not match file"
+                    + file + "\n"
+                    + "please file a bug report on this");
+            }
+            directory = new File(todir, path).getParentFile();
+            // Create the directory, as it might not exist.
+            directory.mkdirs();
+        } else {
+            // Just use the same directory as the file itself.
+            // This directory will exist
+            directory = file.getParentFile();
+        }
+        File checksumFile = new File(directory, file.getName() + fileext);
+        return checksumFile;
+    }
+
+    /**
+     * Generate checksum(s) using the message digest created earlier.
+     */
+    private boolean generateChecksums() throws BuildException {
+        boolean checksumMatches = true;
+        FileInputStream fis = null;
+        FileOutputStream fos = null;
+        byte[] buf = new byte[readBufferSize];
+        try {
+            for (Enumeration e = includeFileMap.keys(); e.hasMoreElements();) {
+                messageDigest.reset();
+                File src = (File) e.nextElement();
+                if (!isCondition) {
+                    log("Calculating " + algorithm + " checksum for " + src, Project.MSG_VERBOSE);
+                }
+                fis = new FileInputStream(src);
+                DigestInputStream dis = new DigestInputStream(fis,
+                                                              messageDigest);
+                while (dis.read(buf, 0, readBufferSize) != -1) {
+                    // Empty statement
+                }
+                dis.close();
+                fis.close();
+                fis = null;
+                byte[] fileDigest = messageDigest.digest ();
+                if (totalproperty != null) {
+                    allDigests.put(src, fileDigest);
+                }
+                String checksum = createDigestString(fileDigest);
+                //can either be a property name string or a file
+                Object destination = includeFileMap.get(src);
+                if (destination instanceof java.lang.String) {
+                    String prop = (String) destination;
+                    if (isCondition) {
+                        checksumMatches
+                            = checksumMatches && checksum.equals(property);
+                    } else {
+                        getProject().setNewProperty(prop, checksum);
+                    }
+                } else if (destination instanceof java.io.File) {
+                    if (isCondition) {
+                        File existingFile = (File) destination;
+                        if (existingFile.exists()) {
+                            try {
+                                String suppliedChecksum =
+                                    readChecksum(existingFile);
+                                checksumMatches = checksumMatches
+                                    && checksum.equals(suppliedChecksum);
+                            } catch (BuildException be) {
+                                // file is on wrong format, swallow
+                                checksumMatches = false;
+                            }
+                        } else {
+                            checksumMatches = false;
+                        }
+                    } else {
+                        File dest = (File) destination;
+                        fos = new FileOutputStream(dest);
+                        fos.write(format.format(new Object[] {
+                                                    checksum,
+                                                    src.getName(),
+                                                }).getBytes());
+                        fos.write(StringUtils.LINE_SEP.getBytes());
+                        fos.close();
+                        fos = null;
+                    }
+                }
+            }
+            if (totalproperty != null) {
+                // Calculate the total checksum
+                // Convert the keys (source files) into a sorted array.
+                Set keys = allDigests.keySet();
+                Object[] keyArray = keys.toArray();
+                // File is Comparable, so sorting is trivial
+                Arrays.sort(keyArray);
+                // Loop over the checksums and generate a total hash.
+                messageDigest.reset();
+                for (int i = 0; i < keyArray.length; i++) {
+                    File src = (File) keyArray[i];
+
+                    // Add the digest for the file content
+                    byte[] digest = (byte[]) allDigests.get(src);
+                    messageDigest.update(digest);
+
+                    // Add the file path
+                    String fileName = (String) relativeFilePaths.get(src);
+                    messageDigest.update(fileName.getBytes());
+                }
+                String totalChecksum = createDigestString(messageDigest.digest());
+                getProject().setNewProperty(totalproperty, totalChecksum);
+            }
+        } catch (Exception e) {
+            throw new BuildException(e, getLocation());
+        } finally {
+            FileUtils.close(fis);
+            FileUtils.close(fos);
+        }
+        return checksumMatches;
+    }
+
+    private String createDigestString(byte[] fileDigest) {
+        StringBuffer checksumSb = new StringBuffer();
+        for (int i = 0; i < fileDigest.length; i++) {
+            String hexStr = Integer.toHexString(BYTE_MASK & fileDigest[i]);
+            if (hexStr.length() < 2) {
+                checksumSb.append("0");
+            }
+            checksumSb.append(hexStr);
+        }
+        return checksumSb.toString();
+    }
+
+    /**
+     * Converts an array of characters representing hexadecimal values into an
+     * array of bytes of those same values. The returned array will be half the
+     * length of the passed array, as it takes two characters to represent any
+     * given byte. An exception is thrown if the passed char array has an odd
+     * number of elements.
+     *
+     * NOTE: This code is copied from jakarta-commons codec.
+     * @param data an array of characters representing hexadecimal values
+     * @return the converted array of bytes
+     * @throws BuildException on error
+     */
+    public static byte[] decodeHex(char[] data) throws BuildException {
+        int l = data.length;
+
+        if ((l & 0x01) != 0) {
+            throw new BuildException("odd number of characters.");
+        }
+
+        byte[] out = new byte[l >> 1];
+
+        // two characters form the hex value.
+        for (int i = 0, j = 0; j < l; i++) {
+            int f = Character.digit(data[j++], WORD) << NIBBLE;
+            f = f | Character.digit(data[j++], WORD);
+            out[i] = (byte) (f & BYTE_MASK);
+        }
+
+        return out;
+    }
+
+    /**
+     * reads the checksum from a file using the specified format.
+     *
+     * @since 1.7
+     */
+    private String readChecksum(File f) {
+        BufferedReader diskChecksumReader = null;
+        try {
+            diskChecksumReader = new BufferedReader(new FileReader(f));
+            Object[] result = format.parse(diskChecksumReader.readLine());
+            if (result == null || result.length == 0 || result[0] == null) {
+                throw new BuildException("failed to find a checksum");
+            }
+            return (String) result[0];
+        } catch (IOException e) {
+            throw new BuildException("Couldn't read checksum file " + f, e);
+        } catch (ParseException e) {
+            throw new BuildException("Couldn't read checksum file " + f, e);
+        } finally {
+            FileUtils.close(diskChecksumReader);
+        }
+    }
+
+    /**
+     * Helper class for the format attribute.
+     *
+     * @since 1.7
+     */
+    public static class FormatElement extends EnumeratedAttribute {
+        private static HashMap formatMap = new HashMap();
+        private static final String CHECKSUM = "CHECKSUM";
+        private static final String MD5SUM = "MD5SUM";
+        private static final String SVF = "SVF";
+
+        static {
+            formatMap.put(CHECKSUM, new MessageFormat("{0}"));
+            formatMap.put(MD5SUM, new MessageFormat("{0} *{1}"));
+            formatMap.put(SVF, new MessageFormat("MD5 ({1}) = {0}"));
+        }
+
+        /** Constructor for FormatElement */
+        public FormatElement() {
+            super();
+        }
+
+        /**
+         * Get the default value - CHECKSUM.
+         * @return the defaul value.
+         */
+        public static FormatElement getDefault() {
+            FormatElement e = new FormatElement();
+            e.setValue(CHECKSUM);
+            return e;
+        }
+
+        /**
+         * Convert this enumerated type to a <code>MessageFormat</code>.
+         * @return a <code>MessageFormat</code> object.
+         */
+        public MessageFormat getFormat() {
+            return (MessageFormat) formatMap.get(getValue());
+        }
+
+        /**
+         * Get the valid values.
+         * @return an array of values.
+         */
+        public String[] getValues() {
+            return new String[] {CHECKSUM, MD5SUM, SVF};
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Chmod.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Chmod.java
new file mode 100644
index 0000000..a915467
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Chmod.java
@@ -0,0 +1,259 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.PatternSet;
+
+/**
+ * Chmod equivalent for unix-like environments.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ * @todo Refactor so it does not extend from ExecuteOn and then turn around
+ *       and unsupport several attributes.
+ */
+public class Chmod extends ExecuteOn {
+
+    private FileSet defaultSet = new FileSet();
+    private boolean defaultSetDefined = false;
+    private boolean havePerm = false;
+
+    /**
+     * Chmod task for setting file and directory permissions.
+     */
+    public Chmod() {
+        super.setExecutable("chmod");
+        super.setParallel(true);
+        super.setSkipEmptyFilesets(true);
+    }
+
+    /**
+     * Set the project of this task.
+     * Calls the super class and sets the project on dhe default FileSet.
+     * @param project the project for this task.
+     * @see org.apache.tools.ant.ProjectComponent#setProject
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        defaultSet.setProject(project);
+    }
+
+    /**
+     * The file or single directory of which the permissions must be changed.
+     * @param src the source file or directory.
+     */
+    public void setFile(File src) {
+        FileSet fs = new FileSet();
+        fs.setFile(src);
+        addFileset(fs);
+    }
+
+    /**
+     * The directory which holds the files whose permissions must be changed.
+     * @param src the directory.
+     */
+    public void setDir(File src) {
+        defaultSet.setDir(src);
+    }
+
+    /**
+     * Set the new permissions.
+     * @param perm the new permissions.
+     */
+    public void setPerm(String perm) {
+        createArg().setValue(perm);
+        havePerm = true;
+    }
+
+    /**
+     * Add a name entry on the include list.
+     * @return a NameEntry to be configured.
+     */
+    public PatternSet.NameEntry createInclude() {
+        defaultSetDefined = true;
+        return defaultSet.createInclude();
+    }
+
+    /**
+     * Add a name entry on the exclude list.
+     * @return a nameentry to be configured.
+     */
+    public PatternSet.NameEntry createExclude() {
+        defaultSetDefined = true;
+        return defaultSet.createExclude();
+    }
+
+    /**
+     * Add a set of patterns.
+     * @return a patternset to be configured.
+     */
+    public PatternSet createPatternSet() {
+        defaultSetDefined = true;
+        return defaultSet.createPatternSet();
+    }
+
+    /**
+     * Sets the set of include patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param includes the string containing the include patterns.
+     */
+    public void setIncludes(String includes) {
+        defaultSetDefined = true;
+        defaultSet.setIncludes(includes);
+    }
+
+    /**
+     * Sets the set of exclude patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param excludes the string containing the exclude patterns.
+     */
+    public void setExcludes(String excludes) {
+        defaultSetDefined = true;
+        defaultSet.setExcludes(excludes);
+    }
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+     *                           should be used, "false"|"off"|"no" when they
+     *                           shouldn't be used.
+     */
+    public void setDefaultexcludes(boolean useDefaultExcludes) {
+        defaultSetDefined = true;
+        defaultSet.setDefaultexcludes(useDefaultExcludes);
+    }
+
+    /**
+     * Check the attributes and nested elements.
+     */
+    protected void checkConfiguration() {
+        if (!havePerm) {
+            throw new BuildException("Required attribute perm not set in chmod",
+                                     getLocation());
+        }
+
+        if (defaultSetDefined && defaultSet.getDir(getProject()) != null) {
+            addFileset(defaultSet);
+        }
+        super.checkConfiguration();
+    }
+
+    /**
+     * Carry out the chmoding.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        /*
+         * In Ant 1.1, <chmod dir="foo" /> means, change the permissions
+         * of directory foo, not anything inside of it.  This is the case the
+         * second branch of the if statement below catches for backwards
+         * compatibility.
+         */
+        if (defaultSetDefined || defaultSet.getDir(getProject()) == null) {
+            try {
+                super.execute();
+            } finally {
+                if (defaultSetDefined && defaultSet.getDir(getProject()) != null) {
+                    filesets.removeElement(defaultSet);
+                }
+            }
+        } else if (isValidOs()) {
+            // we are chmodding the given directory
+            Execute execute = prepareExec();
+            Commandline cloned = (Commandline) cmdl.clone();
+            cloned.createArgument().setValue(defaultSet.getDir(getProject())
+                                             .getPath());
+            try {
+                execute.setCommandline(cloned.getCommandline());
+                runExecute(execute);
+            } catch (IOException e) {
+                throw new BuildException("Execute failed: " + e, e, getLocation());
+            } finally {
+                // close the output file if required
+                logFlush();
+            }
+        }
+    }
+
+    /**
+     * Set the executable.
+     * This is not allowed for Chmod.
+     * @param e ignored.
+     * @throws BuildException always.
+     * @ant.attribute ignore="true"
+     */
+    public void setExecutable(String e) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the executable attribute", getLocation());
+    }
+
+    /**
+     * Set the command.
+     * This is not allowed for Chmod.
+     * @param cmdl ignored.
+     * @throws BuildException always.
+     * @ant.attribute ignore="true"
+     */
+    public void setCommand(Commandline cmdl) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the command attribute", getLocation());
+    }
+
+    /**
+     * This is not allowed for Chmod.
+     * @param skip ignored.
+     * @throws BuildException always.
+     * @ant.attribute ignore="true"
+     */
+    public void setSkipEmptyFilesets(boolean skip) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the skipemptyfileset attribute", getLocation());
+    }
+
+    /**
+     * This is not allowed for Chmod.
+     * @param b ignored.
+     * @throws BuildException always.
+     * @ant.attribute ignore="true"
+     */
+    public void setAddsourcefile(boolean b) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the addsourcefile attribute", getLocation());
+    }
+
+    /**
+     * Check if the os is valid.
+     * Always include unix.
+     * @return true if the os is valid.
+     */
+    protected boolean isValidOs() {
+        return Os.isFamily(Os.FAMILY_UNIX) && super.isValidOs();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Classloader.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Classloader.java
new file mode 100644
index 0000000..643cd96
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Classloader.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.Path;
+
+import java.io.File;
+
+/**
+ * EXPERIMENTAL
+ * Create or modifies ClassLoader. The required pathRef parameter
+ * will be used to add classpath elements.
+ *
+ * The classpath is a regular path. Currently only file components are
+ * supported (future extensions may allow URLs).
+ *
+ * You can modify the core loader by not specifying any name or using
+ * "ant.coreLoader". (the core loader is used to load system ant
+ * tasks and for taskdefs that don't specify an explicit path).
+ *
+ * Taskdef and typedef can use the loader you create if the name follows
+ * the "ant.loader.NAME" pattern. NAME will be used as a pathref when
+ * calling taskdef.
+ *
+ * This tasks will not modify the core loader if "build.sysclasspath=only"
+ *
+ * The typical use is:
+ * <pre>
+ *  &lt;path id="ant.deps" &gt;
+ *     &lt;fileset dir="myDir" &gt;
+ *        &lt;include name="junit.jar, bsf.jar, js.jar, etc"/&gt;
+ *     &lt;/fileset&gt;
+ *  &lt;/path&gt;
+ *
+ *  &lt;classloader pathRef="ant.deps" /&gt;
+ *
+ * </pre>
+ *
+ */
+public class Classloader extends Task {
+    /** @see MagicNames#SYSTEM_LOADER_REF */
+    public static final String SYSTEM_LOADER_REF = MagicNames.SYSTEM_LOADER_REF;
+
+    private String name = null;
+    private Path classpath;
+    private boolean reset = false;
+    private boolean parentFirst = true;
+    private String parentName = null;
+
+    /**
+     * Default constructor
+     */
+    public Classloader() {
+    }
+
+    /** Name of the loader. If none, the default loader will be modified
+     *
+     * @param name the name of this loader
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Reset the classloader, if it already exists. A new loader will
+     * be created and all the references to the old one will be removed.
+     * (it is not possible to remove paths from a loader). The new
+     * path will be used.
+     *
+     * @param b true if the loader is to be reset.
+     */
+    public void setReset(boolean b) {
+        this.reset = b;
+    }
+
+    /**
+     * Set reverse attribute.
+     * @param b if true reverse the normal classloader lookup.
+     */
+    public void setReverse(boolean b) {
+        this.parentFirst = !b;
+    }
+
+    /**
+     * Set reverse attribute.
+     * @param b if true reverse the normal classloader lookup.
+     */
+    public void setParentFirst(boolean b) {
+        this.parentFirst = b;
+    }
+
+    /**
+     * Set the name of the parent.
+     * @param name the parent name.
+     */
+    public void setParentName(String name) {
+        this.parentName = name;
+    }
+
+
+    /** Specify which path will be used. If the loader already exists
+     *  and is an AntClassLoader (or any other loader we can extend),
+     *  the path will be added to the loader.
+     * @param pathRef a reference to a path.
+     * @throws BuildException if there is a problem.
+     */
+    public void setClasspathRef(Reference pathRef) throws BuildException {
+        classpath = (Path) pathRef.getReferencedObject(getProject());
+    }
+
+    /**
+     * Set the classpath to be used when searching for component being defined
+     *
+     * @param classpath an Ant Path object containing the classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Create a classpath.
+     * @return a path for configuration.
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(null);
+        }
+        return this.classpath.createPath();
+    }
+
+
+    /**
+     * do the classloader manipulation.
+     */
+    public void execute() {
+        try {
+            // Gump friendly - don't mess with the core loader if only classpath
+            if ("only".equals(getProject().getProperty("build.sysclasspath"))
+                && (name == null || SYSTEM_LOADER_REF.equals(name))) {
+                log("Changing the system loader is disabled "
+                    + "by build.sysclasspath=only", Project.MSG_WARN);
+                return;
+            }
+
+            String loaderName = (name == null) ? SYSTEM_LOADER_REF : name;
+
+            Object obj = getProject().getReference(loaderName);
+            if (reset) {
+                // Are any other references held ? Can we 'close' the loader
+                // so it removes the locks on jars ?
+                obj = null; // a new one will be created.
+            }
+
+            // XXX maybe use reflection to addPathElement (other patterns ?)
+            if (obj != null && !(obj instanceof AntClassLoader)) {
+                log("Referenced object is not an AntClassLoader",
+                        Project.MSG_ERR);
+                return;
+            }
+
+            AntClassLoader acl = (AntClassLoader) obj;
+
+            if (acl == null) {
+                // Construct a new class loader
+                Object parent = null;
+                if (parentName != null) {
+                    parent = getProject().getReference(parentName);
+                    if (!(parent instanceof ClassLoader)) {
+                        parent = null;
+                    }
+                }
+                // TODO: allow user to request the system or no parent
+                if (parent == null) {
+                    parent = this.getClass().getClassLoader();
+                }
+
+                if (name == null) {
+                    // The core loader must be reverse
+                    //reverse=true;
+                }
+                getProject().log("Setting parent loader " + name + " "
+                    + parent + " " + parentFirst, Project.MSG_DEBUG);
+
+                // The param is "parentFirst"
+                acl = new AntClassLoader((ClassLoader) parent,
+                         getProject(), classpath, parentFirst);
+
+                getProject().addReference(loaderName, acl);
+
+                if (name == null) {
+                    // This allows the core loader to load optional tasks
+                    // without delegating
+                    acl.addLoaderPackageRoot("org.apache.tools.ant.taskdefs.optional");
+                    getProject().setCoreLoader(acl);
+                }
+            }
+            if (classpath != null) {
+                String[] list = classpath.list();
+                for (int i = 0; i < list.length; i++) {
+                    File f = new File(list[i]);
+                    if (f.exists()) {
+                        acl.addPathElement(f.getAbsolutePath());
+                        log("Adding to class loader " +  acl + " " + f.getAbsolutePath(),
+                                Project.MSG_DEBUG);
+                    }
+                }
+            }
+
+            // XXX add exceptions
+
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Componentdef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Componentdef.java
new file mode 100644
index 0000000..9352462
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Componentdef.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Adds a compenent definition to the current project.
+ * used in the current project. Two attributes are needed, the name that identifies
+ * this compenent uniquely, and the full name of the class (
+ * including the packages) that
+ * implements this component.</p>
+ * @since Ant 1.8
+ * @ant.task category="internal"
+ */
+public class Componentdef extends Definer {
+
+    /**
+     * Default constructor.
+     * Creates a new ComponentDef instance.
+     * Sets the restrict attribute to true.
+     */
+
+    public Componentdef() {
+        setRestrict(true);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Concat.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Concat.java
new file mode 100644
index 0000000..fb56a70
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Concat.java
@@ -0,0 +1,933 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FileList;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.StringResource;
+import org.apache.tools.ant.types.resources.selectors.Not;
+import org.apache.tools.ant.types.resources.selectors.Exists;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.util.ConcatResourceInputStream;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ReaderInputStream;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * This class contains the 'concat' task, used to concatenate a series
+ * of files into a single stream. The destination of this stream may
+ * be the system console, or a file. The following is a sample
+ * invocation:
+ *
+ * <pre>
+ * &lt;concat destfile=&quot;${build.dir}/index.xml&quot;
+ *   append=&quot;false&quot;&gt;
+ *
+ *   &lt;fileset dir=&quot;${xml.root.dir}&quot;
+ *     includes=&quot;*.xml&quot; /&gt;
+ *
+ * &lt;/concat&gt;
+ * </pre>
+ *
+ */
+public class Concat extends Task implements ResourceCollection {
+
+    // The size of buffers to be used
+    private static final int BUFFER_SIZE = 8192;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private static final ResourceSelector EXISTS = new Exists();
+    private static final ResourceSelector NOT_EXISTS = new Not(EXISTS);
+
+    /**
+     * sub element points to a file or contains text
+     */
+    public static class TextElement extends ProjectComponent {
+        private String   value = "";
+        private boolean  trimLeading = false;
+        private boolean  trim = false;
+        private boolean  filtering = true;
+        private String   encoding = null;
+
+        /**
+         * whether to filter the text in this element
+         * or not.
+         *
+         * @param filtering true if the text should be filtered.
+         *                  the default value is true.
+         */
+        public void setFiltering(boolean filtering) {
+            this.filtering = filtering;
+        }
+
+        /** return the filtering attribute */
+        private boolean getFiltering() {
+            return filtering;
+        }
+
+        /**
+         * The encoding of the text element
+         *
+         * @param encoding the name of the charset used to encode
+         */
+        public void setEncoding(String encoding) {
+            this.encoding = encoding;
+        }
+
+        /**
+         * set the text using a file
+         * @param file the file to use
+         * @throws BuildException if the file does not exist, or cannot be
+         *                        read
+         */
+        public void setFile(File file) throws BuildException {
+            // non-existing files are not allowed
+            if (!file.exists()) {
+                throw new BuildException("File " + file + " does not exist.");
+            }
+
+            BufferedReader reader = null;
+            try {
+                if (this.encoding == null) {
+                    reader = new BufferedReader(new FileReader(file));
+                } else {
+                    reader = new BufferedReader(
+                        new InputStreamReader(new FileInputStream(file),
+                                              this.encoding));
+                }
+                value = FileUtils.safeReadFully(reader);
+            } catch (IOException ex) {
+                throw new BuildException(ex);
+            } finally {
+                FileUtils.close(reader);
+            }
+        }
+
+        /**
+         * set the text using inline
+         * @param value the text to place inline
+         */
+        public void addText(String value) {
+            this.value += getProject().replaceProperties(value);
+        }
+
+        /**
+         * s:^\s*:: on each line of input
+         * @param strip if true do the trim
+         */
+        public void setTrimLeading(boolean strip) {
+            this.trimLeading = strip;
+        }
+
+        /**
+         * whether to call text.trim()
+         * @param trim if true trim the text
+         */
+        public void setTrim(boolean trim) {
+            this.trim = trim;
+        }
+
+        /**
+         * @return the text, after possible trimming
+         */
+        public String getValue() {
+            if (value == null) {
+                value = "";
+            }
+            if (value.trim().length() == 0) {
+                value = "";
+            }
+            if (trimLeading) {
+                char[] current = value.toCharArray();
+                StringBuffer b = new StringBuffer(current.length);
+                boolean startOfLine = true;
+                int pos = 0;
+                while (pos < current.length) {
+                    char ch = current[pos++];
+                    if (startOfLine) {
+                        if (ch == ' ' || ch == '\t') {
+                            continue;
+                        }
+                        startOfLine = false;
+                    }
+                    b.append(ch);
+                    if (ch == '\n' || ch == '\r') {
+                        startOfLine = true;
+                    }
+                }
+                value = b.toString();
+            }
+            if (trim) {
+                value = value.trim();
+            }
+            return value;
+        }
+    }
+
+    private interface ReaderFactory {
+        Reader getReader(Object o) throws IOException;
+    }
+
+    /**
+     * This class reads from each of the source files in turn.
+     * The concatentated result can then be filtered as
+     * a single stream.
+     */
+    private final class MultiReader extends Reader {
+        private Reader reader = null;
+        private int    lastPos = 0;
+        private char[] lastChars = new char[eolString.length()];
+        private boolean needAddSeparator = false;
+        private Iterator readerSources;
+        private ReaderFactory factory;
+
+        private MultiReader(Iterator readerSources, ReaderFactory factory) {
+            this.readerSources = readerSources;
+            this.factory = factory;
+        }
+
+        private Reader getReader() throws IOException {
+            if (reader == null && readerSources.hasNext()) {
+                reader = factory.getReader(readerSources.next());
+                Arrays.fill(lastChars, (char) 0);
+            }
+            return reader;
+        }
+
+        private void nextReader() throws IOException {
+            close();
+            reader = null;
+        }
+
+        /**
+         * Read a character from the current reader object. Advance
+         * to the next if the reader is finished.
+         * @return the character read, -1 for EOF on the last reader.
+         * @exception IOException - possibly thrown by the read for a reader
+         *            object.
+         */
+        public int read() throws IOException {
+            if (needAddSeparator) {
+                int ret = eolString.charAt(lastPos++);
+                if (lastPos >= eolString.length()) {
+                    lastPos = 0;
+                    needAddSeparator = false;
+                }
+                return ret;
+            }
+            while (getReader() != null) {
+                int ch = getReader().read();
+                if (ch == -1) {
+                    nextReader();
+                    if (isFixLastLine() && isMissingEndOfLine()) {
+                        needAddSeparator = true;
+                        lastPos = 0;
+                    }
+                } else {
+                    addLastChar((char) ch);
+                    return ch;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Read into the buffer <code>cbuf</code>.
+         * @param cbuf The array to be read into.
+         * @param off The offset.
+         * @param len The length to read.
+         * @exception IOException - possibly thrown by the reads to the
+         *            reader objects.
+         */
+        public int read(char[] cbuf, int off, int len)
+            throws IOException {
+
+            int amountRead = 0;
+            while (getReader() != null || needAddSeparator) {
+                if (needAddSeparator) {
+                    cbuf[off] = eolString.charAt(lastPos++);
+                    if (lastPos >= eolString.length()) {
+                        lastPos = 0;
+                        needAddSeparator = false;
+                    }
+                    len--;
+                    off++;
+                    amountRead++;
+                    if (len == 0) {
+                        return amountRead;
+                    }
+                    continue;
+                }
+                int nRead = getReader().read(cbuf, off, len);
+                if (nRead == -1 || nRead == 0) {
+                    nextReader();
+                    if (isFixLastLine() && isMissingEndOfLine()) {
+                        needAddSeparator = true;
+                        lastPos = 0;
+                    }
+                } else {
+                    if (isFixLastLine()) {
+                        for (int i = nRead;
+                                 i > (nRead - lastChars.length);
+                                 --i) {
+                            if (i <= 0) {
+                                break;
+                            }
+                            addLastChar(cbuf[off + i - 1]);
+                        }
+                    }
+                    len -= nRead;
+                    off += nRead;
+                    amountRead += nRead;
+                    if (len == 0) {
+                        return amountRead;
+                    }
+                }
+            }
+            if (amountRead == 0) {
+                return -1;
+            } else {
+                return amountRead;
+            }
+        }
+
+        /**
+         * Close the current reader
+         */
+        public void close() throws IOException {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+
+        /**
+         * if checking for end of line at end of file
+         * add a character to the lastchars buffer
+         */
+        private void addLastChar(char ch) {
+            for (int i = lastChars.length - 2; i >= 0; --i) {
+                lastChars[i] = lastChars[i + 1];
+            }
+            lastChars[lastChars.length - 1] = ch;
+        }
+
+        /**
+         * return true if the lastchars buffer does
+         * not contain the lineseparator
+         */
+        private boolean isMissingEndOfLine() {
+            for (int i = 0; i < lastChars.length; ++i) {
+                if (lastChars[i] != eolString.charAt(i)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean isFixLastLine() {
+            return fixLastLine && textBuffer == null;
+        }
+    }
+
+    private final class ConcatResource extends Resource {
+        private ResourceCollection c;
+
+        private ConcatResource(ResourceCollection c) {
+            this.c = c;
+        }
+        public InputStream getInputStream() throws IOException {
+            if (binary) {
+                ConcatResourceInputStream result = new ConcatResourceInputStream(c);
+                result.setManagingComponent(this);
+                return result;
+            }
+            Reader resourceReader = getFilteredReader(
+                    new MultiReader(c.iterator(), resourceReaderFactory));
+            Reader rdr;
+            if (header == null && footer == null) {
+                rdr = resourceReader;
+            } else {
+                int readerCount = 1;
+                if (header != null) {
+                    readerCount++;
+                }
+                if (footer != null) {
+                    readerCount++;
+                }
+                Reader[] readers = new Reader[readerCount];
+                int pos = 0;
+                if (header != null) {
+                    readers[pos] = new StringReader(header.getValue());
+                    if (header.getFiltering()) {
+                        readers[pos] = getFilteredReader(readers[pos]);
+                    }
+                    pos++;
+                }
+                readers[pos++] = resourceReader;
+                if (footer != null) {
+                    readers[pos] = new StringReader(footer.getValue());
+                    if (footer.getFiltering()) {
+                        readers[pos] = getFilteredReader(readers[pos]);
+                    }
+                }
+                rdr = new MultiReader(Arrays.asList(readers).iterator(),
+                        identityReaderFactory);
+            }
+            return outputEncoding == null ? new ReaderInputStream(rdr)
+                    : new ReaderInputStream(rdr, outputEncoding);
+        }
+        public String getName() {
+            return "concat (" + String.valueOf(c) + ")";
+        }
+    }
+
+    // Attributes.
+
+    /**
+     * The destination of the stream. If <code>null</code>, the system
+     * console is used.
+     */
+    private File destinationFile;
+
+    /**
+     * Whether or not the stream should be appended if the destination file
+     * exists.
+     * Defaults to <code>false</code>.
+     */
+    private boolean append;
+
+    /**
+     * Stores the input file encoding.
+     */
+    private String encoding;
+
+    /** Stores the output file encoding. */
+    private String outputEncoding;
+
+    /** Stores the binary attribute */
+    private boolean binary;
+
+    // Child elements.
+
+    /**
+     * This buffer stores the text within the 'concat' element.
+     */
+    private StringBuffer textBuffer;
+
+    /**
+     * Stores a collection of file sets and/or file lists, used to
+     * select multiple files for concatenation.
+     */
+    private ResourceCollection rc;
+
+    /** for filtering the concatenated */
+    private Vector filterChains;
+    /** ignore dates on input files */
+    private boolean forceOverwrite = true;
+    /** String to place at the start of the concatented stream */
+    private TextElement footer;
+    /** String to place at the end of the concatented stream */
+    private TextElement header;
+    /** add missing line.separator to files **/
+    private boolean fixLastLine = false;
+    /** endofline for fixlast line */
+    private String eolString;
+    /** outputwriter */
+    private Writer outputWriter = null;
+
+    private ReaderFactory resourceReaderFactory  = new ReaderFactory() {
+        public Reader getReader(Object o) throws IOException {
+            InputStream is = ((Resource) o).getInputStream();
+            return new BufferedReader(encoding == null
+                ? new InputStreamReader(is)
+                : new InputStreamReader(is, encoding));
+        }
+    };
+
+    private ReaderFactory identityReaderFactory = new ReaderFactory() {
+        public Reader getReader(Object o) {
+            return (Reader) o;
+        }
+    };
+
+    /**
+     * Construct a new Concat task.
+     */
+    public Concat() {
+        reset();
+    }
+
+    /**
+     * Reset state to default.
+     */
+    public void reset() {
+        append = false;
+        forceOverwrite = true;
+        destinationFile = null;
+        encoding = null;
+        outputEncoding = null;
+        fixLastLine = false;
+        filterChains = null;
+        footer = null;
+        header = null;
+        binary = false;
+        outputWriter = null;
+        textBuffer = null;
+        eolString = StringUtils.LINE_SEP;
+        rc = null;
+    }
+
+    // Attribute setters.
+
+    /**
+     * Sets the destination file, or uses the console if not specified.
+     * @param destinationFile the destination file
+     */
+    public void setDestfile(File destinationFile) {
+        this.destinationFile = destinationFile;
+    }
+
+    /**
+     * Sets the behavior when the destination file exists. If set to
+     * <code>true</code> the stream data will be appended to the
+     * existing file, otherwise the existing file will be
+     * overwritten. Defaults to <code>false</code>.
+     * @param append if true append to the file.
+     */
+    public void setAppend(boolean append) {
+        this.append = append;
+    }
+
+    /**
+     * Sets the character encoding
+     * @param encoding the encoding of the input stream and unless
+     *        outputencoding is set, the outputstream.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+        if (outputEncoding == null) {
+            outputEncoding = encoding;
+        }
+    }
+
+    /**
+     * Sets the character encoding for outputting
+     * @param outputEncoding the encoding for the output file
+     * @since Ant 1.6
+     */
+    public void setOutputEncoding(String outputEncoding) {
+        this.outputEncoding = outputEncoding;
+    }
+
+    /**
+     * Force overwrite existing destination file
+     * @param force if true always overwrite, otherwise only overwrite
+     *              if the output file is older any of the input files.
+     * @since Ant 1.6
+     */
+    public void setForce(boolean force) {
+        this.forceOverwrite = force;
+    }
+
+    // Nested element creators.
+
+    /**
+     * Path of files to concatenate.
+     * @return the path used for concatenating
+     * @since Ant 1.6
+     */
+     public Path createPath() {
+        Path path = new Path(getProject());
+        add(path);
+        return path;
+    }
+
+    /**
+     * Set of files to concatenate.
+     * @param set the set of files
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * List of files to concatenate.
+     * @param list the list of files
+     */
+    public void addFilelist(FileList list) {
+        add(list);
+    }
+
+    /**
+     * Add an arbitrary ResourceCollection.
+     * @param c the ResourceCollection to add.
+     * @since Ant 1.7
+     */
+    public synchronized void add(ResourceCollection c) {
+        if (rc == null) {
+            rc = c;
+            return;
+        }
+        if (!(rc instanceof Resources)) {
+            Resources newRc = new Resources();
+            newRc.setProject(getProject());
+            newRc.add(rc);
+            rc = newRc;
+        }
+        ((Resources) rc).add(c);
+    }
+
+    /**
+     * Adds a FilterChain.
+     * @param filterChain a filterchain to filter the concatenated input
+     * @since Ant 1.6
+     */
+    public void addFilterChain(FilterChain filterChain) {
+        if (filterChains == null) {
+            filterChains = new Vector();
+        }
+        filterChains.addElement(filterChain);
+    }
+
+    /**
+     * This method adds text which appears in the 'concat' element.
+     * @param text the text to be concated.
+     */
+    public void addText(String text) {
+        if (textBuffer == null) {
+            // Initialize to the size of the first text fragment, with
+            // the hopes that it's the only one.
+            textBuffer = new StringBuffer(text.length());
+        }
+
+        // Append the fragment -- we defer property replacement until
+        // later just in case we get a partial property in a fragment.
+        textBuffer.append(text);
+    }
+
+    /**
+     * Add a header to the concatenated output
+     * @param headerToAdd the header
+     * @since Ant 1.6
+     */
+    public void addHeader(TextElement headerToAdd) {
+        this.header = headerToAdd;
+    }
+
+    /**
+     * Add a footer to the concatenated output
+     * @param footerToAdd the footer
+     * @since Ant 1.6
+     */
+    public void addFooter(TextElement footerToAdd) {
+        this.footer = footerToAdd;
+    }
+
+    /**
+     * Append line.separator to files that do not end
+     * with a line.separator, default false.
+     * @param fixLastLine if true make sure each input file has
+     *                    new line on the concatenated stream
+     * @since Ant 1.6
+     */
+    public void setFixLastLine(boolean fixLastLine) {
+        this.fixLastLine = fixLastLine;
+    }
+
+    /**
+     * Specify the end of line to find and to add if
+     * not present at end of each input file. This attribute
+     * is used in conjunction with fixlastline.
+     * @param crlf the type of new line to add -
+     *              cr, mac, lf, unix, crlf, or dos
+     * @since Ant 1.6
+     */
+    public void setEol(FixCRLF.CrLf crlf) {
+        String s = crlf.getValue();
+        if (s.equals("cr") || s.equals("mac")) {
+            eolString = "\r";
+        } else if (s.equals("lf") || s.equals("unix")) {
+            eolString = "\n";
+        } else if (s.equals("crlf") || s.equals("dos")) {
+            eolString = "\r\n";
+        }
+    }
+
+    /**
+     * Set the output writer. This is to allow
+     * concat to be used as a nested element.
+     * @param outputWriter the output writer.
+     * @since Ant 1.6
+     */
+    public void setWriter(Writer outputWriter) {
+        this.outputWriter = outputWriter;
+    }
+
+    /**
+     * Set the binary attribute. If true, concat will concatenate the files
+     * byte for byte. This mode does not allow any filtering or other
+     * modifications to the input streams. The default value is false.
+     * @since Ant 1.6.2
+     * @param binary if true, enable binary mode.
+     */
+    public void setBinary(boolean binary) {
+        this.binary = binary;
+    }
+
+    /**
+     * Execute the concat task.
+     */
+    public void execute() {
+        validate();
+        if (binary && destinationFile == null) {
+            throw new BuildException(
+                "destfile attribute is required for binary concatenation");
+        }
+        ResourceCollection c = getResources();
+        if (isUpToDate(c)) {
+            log(destinationFile + " is up-to-date.", Project.MSG_VERBOSE);
+            return;
+        }
+        if (c.size() == 0) {
+            return;
+        }
+        OutputStream out;
+        if (destinationFile == null) {
+            // Log using WARN so it displays in 'quiet' mode.
+            out = new LogOutputStream(this, Project.MSG_WARN);
+        } else {
+            try {
+                // ensure that the parent dir of dest file exists
+                File parent = destinationFile.getParentFile();
+                if (!parent.exists()) {
+                    parent.mkdirs();
+                }
+                // use getPath() for pre-JDK 1.4 compatibility:
+                out = new FileOutputStream(destinationFile.getPath(), append);
+            } catch (Throwable t) {
+                throw new BuildException("Unable to open "
+                    + destinationFile + " for writing", t);
+            }
+        }
+        InputStream catStream;
+        try {
+            catStream = new ConcatResource(c).getInputStream();
+        } catch (IOException e) {
+            throw new BuildException("error getting concatenated resource content", e);
+        }
+        pump(catStream, out);
+    }
+
+    /**
+     * Implement ResourceCollection.
+     * @return Iterator<Resource>.
+     */
+    public Iterator iterator() {
+        validate();
+        return Collections.singletonList(new ConcatResource(getResources())).iterator();
+    }
+
+    /**
+     * Implement ResourceCollection.
+     * @return 1.
+     */
+    public int size() {
+        return 1;
+    }
+
+    /**
+     * Implement ResourceCollection.
+     * @return false.
+     */
+    public boolean isFilesystemOnly() {
+        return false;
+    }
+
+    /**
+     * Validate configuration options.
+     */
+    private void validate() {
+
+        // treat empty nested text as no text
+        sanitizeText();
+
+        // if binary check if incompatible attributes are used
+        if (binary) {
+            if (textBuffer != null) {
+                throw new BuildException(
+                    "Nested text is incompatible with binary concatenation");
+            }
+            if (encoding != null || outputEncoding != null) {
+                throw new BuildException(
+                    "Setting input or output encoding is incompatible with binary"
+                    + " concatenation");
+            }
+            if (filterChains != null) {
+                throw new BuildException(
+                    "Setting filters is incompatible with binary concatenation");
+            }
+            if (fixLastLine) {
+                throw new BuildException(
+                    "Setting fixlastline is incompatible with binary concatenation");
+            }
+            if (header != null || footer != null) {
+                throw new BuildException(
+                    "Nested header or footer is incompatible with binary concatenation");
+            }
+        }
+        if (destinationFile != null && outputWriter != null) {
+            throw new BuildException(
+                "Cannot specify both a destination file and an output writer");
+        }
+        // Sanity check our inputs.
+        if (rc == null && textBuffer == null) {
+            // Nothing to concatenate!
+            throw new BuildException(
+                "At least one resource must be provided, or some text.");
+        }
+        if (rc != null && textBuffer != null) {
+            // If using resources, disallow inline text. This is similar to
+            // using GNU 'cat' with file arguments--stdin is simply ignored.
+            throw new BuildException(
+                "Cannot include inline text when using resources.");
+        }
+    }
+
+    /**
+     * Get the resources to concatenate.
+     */
+    private ResourceCollection getResources() {
+        if (rc == null) {
+            return new StringResource(getProject(), textBuffer.toString());
+        }
+        Restrict noexistRc = new Restrict();
+        noexistRc.add(NOT_EXISTS);
+        noexistRc.add(rc);
+        for (Iterator i = noexistRc.iterator(); i.hasNext();) {
+            log(i.next() + " does not exist.", Project.MSG_ERR);
+        }
+        if (destinationFile != null) {
+            for (Iterator i = rc.iterator(); i.hasNext();) {
+                Object o = i.next();
+                if (o instanceof FileResource) {
+                    File f = ((FileResource) o).getFile();
+                    if (FILE_UTILS.fileNameEquals(f, destinationFile)) {
+                        throw new BuildException("Input file \""
+                            + f + "\" is the same as the output file.");
+                    }
+                }
+            }
+        }
+        Restrict result = new Restrict();
+        result.add(EXISTS);
+        result.add(rc);
+        return result;
+    }
+
+    private boolean isUpToDate(ResourceCollection c) {
+        if (destinationFile == null || forceOverwrite) {
+            return false;
+        }
+        for (Iterator i = c.iterator(); i.hasNext();) {
+            Resource r = (Resource) i.next();
+            if (r.getLastModified() == 0L
+                 || r.getLastModified() > destinationFile.lastModified()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Treat empty nested text as no text.
+     *
+     * <p>Depending on the XML parser, addText may have been called
+     * for &quot;ignorable whitespace&quot; as well.</p>
+     */
+    private void sanitizeText() {
+        if (textBuffer != null && "".equals(textBuffer.toString().trim())) {
+            textBuffer = null;
+        }
+    }
+
+    /**
+     * Transfer the contents of <code>in</code> to <code>out</code>.
+     * @param in InputStream
+     * @param out OutputStream
+     */
+    private void pump(InputStream in, OutputStream out) {
+        Thread t = new Thread(new StreamPumper(in, out));
+        t.start();
+        try {
+            t.join();
+        } catch (InterruptedException e) {
+            try {
+                t.join();
+            } catch (InterruptedException ee) {
+                // Empty
+            }
+        } finally {
+            FileUtils.close(in);
+            FileUtils.close(out);
+        }
+    }
+
+    private Reader getFilteredReader(Reader r) {
+        if (filterChains == null) {
+            return r;
+        }
+        ChainReaderHelper helper = new ChainReaderHelper();
+        helper.setBufferSize(BUFFER_SIZE);
+        helper.setPrimaryReader(r);
+        helper.setFilterChains(filterChains);
+        helper.setProject(getProject());
+        //used to be a BufferedReader here, but we should be buffering lower:
+        return helper.getAssembledReader();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ConditionTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ConditionTask.java
new file mode 100644
index 0000000..60904e0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ConditionTask.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+
+/**
+ * Task to set a property conditionally using &lt;uptodate&gt;, &lt;available&gt;,
+ * and many other supported conditions.
+ *
+ * <p>This task supports boolean logic as well as pluggable conditions
+ * to decide, whether a property should be set.</p>
+ *
+ * <p>This task does not extend Task to take advantage of
+ * ConditionBase.</p>
+ *
+ * @since Ant 1.4
+ *
+ * @ant.task category="control"
+ */
+public class ConditionTask extends ConditionBase {
+
+    private String property = null;
+    private Object value = "true";
+    private Object alternative = null;
+
+    /**
+     * Constructor, names this task "condition".
+     */
+    public ConditionTask() {
+        super("condition");
+    }
+
+    /**
+     * The name of the property to set. Required.
+     * @param p the name of the property
+     * @since Ant 1.4
+     */
+    public void setProperty(String p) {
+        property = p;
+    }
+
+    /**
+     * The value for the property to set, if condition evaluates to true.
+     * Defaults to "true".
+     * @param value the (Object) value of the property
+     * @since Ant 1.8
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * The value for the property to set, if condition evaluates to true.
+     * Defaults to "true".
+     * @param v the value of the property
+     * @since Ant 1.4
+     */
+    public void setValue(String v) {
+        setValue((Object) v);
+    }
+
+    /**
+     * The value for the property to set, if condition evaluates to false.
+     * If this attribute is not specified, the property will not be set.
+     * @param alt the alternate value of the property.
+     * @since Ant 1.8
+     */
+    public void setElse(Object alt) {
+        alternative = alt;
+    }
+
+    /**
+     * The value for the property to set, if condition evaluates to false.
+     * If this attribute is not specified, the property will not be set.
+     * @param e the alternate value of the property.
+     * @since Ant 1.6.3
+     */
+    public void setElse(String e) {
+        setElse((Object) e);
+    }
+
+    /**
+     * See whether our nested condition holds and set the property.
+     *
+     * @since Ant 1.4
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        if (countConditions() > 1) {
+            throw new BuildException("You must not nest more than one condition into <"
+                    + getTaskName() + ">");
+        }
+        if (countConditions() < 1) {
+            throw new BuildException("You must nest a condition into <" + getTaskName() + ">");
+        }
+        if (property == null) {
+            throw new BuildException("The property attribute is required.");
+        }
+        Condition c = (Condition) getConditions().nextElement();
+        if (c.eval()) {
+            log("Condition true; setting " + property + " to " + value, Project.MSG_DEBUG);
+            PropertyHelper.getPropertyHelper(getProject()).setNewProperty(property, value);
+        } else if (alternative != null) {
+            log("Condition false; setting " + property + " to " + alternative, Project.MSG_DEBUG);
+            PropertyHelper.getPropertyHelper(getProject()).setNewProperty(property, alternative);
+        } else {
+            log("Condition false; not setting " + property, Project.MSG_DEBUG);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Copy.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Copy.java
new file mode 100644
index 0000000..8bc06b1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Copy.java
@@ -0,0 +1,1025 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.ResourceUtils;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.ant.util.FlatFileNameMapper;
+
+/**
+ * Copies a file or directory to a new file
+ * or directory.  Files are only copied if the source file is newer
+ * than the destination file, or when the destination file does not
+ * exist.  It is possible to explicitly overwrite existing files.</p>
+ *
+ * <p>This implementation is based on Arnout Kuiper's initial design
+ * document, the following mailing list discussions, and the
+ * copyfile/copydir tasks.</p>
+ *
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="filesystem"
+ */
+public class Copy extends Task {
+    static final File NULL_FILE_PLACEHOLDER = new File("/NULL_FILE");
+    static final String LINE_SEPARATOR = System.getProperty("line.separator");
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected File file = null;     // the source file
+    protected File destFile = null; // the destination file
+    protected File destDir = null;  // the destination directory
+    protected Vector rcs = new Vector();
+
+    private boolean enableMultipleMappings = false;
+    protected boolean filtering = false;
+    protected boolean preserveLastModified = false;
+    protected boolean forceOverwrite = false;
+    protected boolean flatten = false;
+    protected int verbosity = Project.MSG_VERBOSE;
+    protected boolean includeEmpty = true;
+    protected boolean failonerror = true;
+
+    protected Hashtable fileCopyMap = new Hashtable();
+    protected Hashtable dirCopyMap = new Hashtable();
+    protected Hashtable completeDirMap = new Hashtable();
+
+    protected Mapper mapperElement = null;
+    protected FileUtils fileUtils;
+    //CheckStyle:VisibilityModifier ON
+    private Vector filterChains = new Vector();
+    private Vector filterSets = new Vector();
+    private String inputEncoding = null;
+    private String outputEncoding = null;
+    private long granularity = 0;
+
+    /**
+     * Copy task constructor.
+     */
+    public Copy() {
+        fileUtils = FileUtils.getFileUtils();
+        granularity = fileUtils.getFileTimestampGranularity();
+    }
+
+    /**
+     * Get the FileUtils for this task.
+     * @return the fileutils object.
+     */
+    protected FileUtils getFileUtils() {
+        return fileUtils;
+    }
+
+    /**
+     * Set a single source file to copy.
+     * @param file the file to copy.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Set the destination file.
+     * @param destFile the file to copy to.
+     */
+    public void setTofile(File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * Set the destination directory.
+     * @param destDir the destination directory.
+     */
+    public void setTodir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Add a FilterChain.
+     * @return a filter chain object.
+     */
+    public FilterChain createFilterChain() {
+        FilterChain filterChain = new FilterChain();
+        filterChains.addElement(filterChain);
+        return filterChain;
+    }
+
+    /**
+     * Add a filterset.
+     * @return a filter set object.
+     */
+    public FilterSet createFilterSet() {
+        FilterSet filterSet = new FilterSet();
+        filterSets.addElement(filterSet);
+        return filterSet;
+    }
+
+    /**
+     * Give the copied files the same last modified time as the original files.
+     * @param preserve a boolean string.
+     * @deprecated since 1.5.x.
+     *             setPreserveLastModified(String) has been deprecated and
+     *             replaced with setPreserveLastModified(boolean) to
+     *             consistently let the Introspection mechanism work.
+     */
+    public void setPreserveLastModified(String preserve) {
+        setPreserveLastModified(Project.toBoolean(preserve));
+    }
+
+    /**
+     * Give the copied files the same last modified time as the original files.
+     * @param preserve if true preserve the modified time; default is false.
+     */
+    public void setPreserveLastModified(boolean preserve) {
+        preserveLastModified = preserve;
+    }
+
+    /**
+     * Get whether to give the copied files the same last modified time as
+     * the original files.
+     * @return the whether destination files will inherit the modification
+     *         times of the corresponding source files.
+     * @since 1.32, Ant 1.5
+     */
+    public boolean getPreserveLastModified() {
+        return preserveLastModified;
+    }
+
+    /**
+     * Get the filtersets being applied to this operation.
+     *
+     * @return a vector of FilterSet objects.
+     */
+    protected Vector getFilterSets() {
+        return filterSets;
+    }
+
+    /**
+     * Get the filterchains being applied to this operation.
+     *
+     * @return a vector of FilterChain objects.
+     */
+    protected Vector getFilterChains() {
+        return filterChains;
+    }
+
+    /**
+     * Set filtering mode.
+     * @param filtering if true enable filtering; default is false.
+     */
+    public void setFiltering(boolean filtering) {
+        this.filtering = filtering;
+    }
+
+    /**
+     * Set overwrite mode regarding existing destination file(s).
+     * @param overwrite if true force overwriting of destination file(s)
+     *                  even if the destination file(s) are younger than
+     *                  the corresponding source file. Default is false.
+     */
+    public void setOverwrite(boolean overwrite) {
+        this.forceOverwrite = overwrite;
+    }
+
+    /**
+     * Set whether files copied from directory trees will be "flattened"
+     * into a single directory.  If there are multiple files with
+     * the same name in the source directory tree, only the first
+     * file will be copied into the "flattened" directory, unless
+     * the forceoverwrite attribute is true.
+     * @param flatten if true flatten the destination directory. Default
+     *                is false.
+     */
+    public void setFlatten(boolean flatten) {
+        this.flatten = flatten;
+    }
+
+    /**
+     * Set verbose mode. Used to force listing of all names of copied files.
+     * @param verbose whether to output the names of copied files.
+     *                Default is false.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbosity = verbose ? Project.MSG_INFO : Project.MSG_VERBOSE;
+    }
+
+    /**
+     * Set whether to copy empty directories.
+     * @param includeEmpty if true copy empty directories. Default is true.
+     */
+    public void setIncludeEmptyDirs(boolean includeEmpty) {
+        this.includeEmpty = includeEmpty;
+    }
+
+    /**
+     * Set method of handling mappers that return multiple
+     * mappings for a given source path.
+     * @param enableMultipleMappings If true the task will
+     *        copy to all the mappings for a given source path, if
+     *        false, only the first file or directory is
+     *        processed.
+     *        By default, this setting is false to provide backward
+     *        compatibility with earlier releases.
+     * @since Ant 1.6
+     */
+    public void setEnableMultipleMappings(boolean enableMultipleMappings) {
+        this.enableMultipleMappings = enableMultipleMappings;
+    }
+
+    /**
+     * Get whether multiple mapping is enabled.
+     * @return true if multiple mapping is enabled; false otherwise.
+     */
+    public boolean isEnableMultipleMapping() {
+        return enableMultipleMappings;
+    }
+
+    /**
+     * Set whether to fail when errors are encountered. If false, note errors
+     * to the output but keep going. Default is true.
+     * @param failonerror true or false.
+     */
+    public void setFailOnError(boolean failonerror) {
+        this.failonerror = failonerror;
+    }
+
+    /**
+     * Add a set of files to copy.
+     * @param set a set of files to copy.
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Add a collection of files to copy.
+     * @param res a resource collection to copy.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection res) {
+        rcs.add(res);
+    }
+
+    /**
+     * Define the mapper to map source to destination files.
+     * @return a mapper to be configured.
+     * @exception BuildException if more than one mapper is defined.
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper",
+                                     getLocation());
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+    /**
+     * Add a nested filenamemapper.
+     * @param fileNameMapper the mapper to add.
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+    /**
+     * Set the character encoding.
+     * @param encoding the character encoding.
+     * @since 1.32, Ant 1.5
+     */
+    public void setEncoding(String encoding) {
+        this.inputEncoding = encoding;
+        if (outputEncoding == null) {
+            outputEncoding = encoding;
+        }
+    }
+
+    /**
+     * Get the character encoding to be used.
+     * @return the character encoding, <code>null</code> if not set.
+     *
+     * @since 1.32, Ant 1.5
+     */
+    public String getEncoding() {
+        return inputEncoding;
+    }
+
+    /**
+     * Set the character encoding for output files.
+     * @param encoding the output character encoding.
+     * @since Ant 1.6
+     */
+    public void setOutputEncoding(String encoding) {
+        this.outputEncoding = encoding;
+    }
+
+    /**
+     * Get the character encoding for output files.
+     * @return the character encoding for output files,
+     * <code>null</code> if not set.
+     *
+     * @since Ant 1.6
+     */
+    public String getOutputEncoding() {
+        return outputEncoding;
+    }
+
+    /**
+     * Set the number of milliseconds leeway to give before deciding a
+     * target is out of date.
+     *
+     * <p>Default is 1 second, or 2 seconds on DOS systems.</p>
+     * @param granularity the granularity used to decide if a target is out of
+     *                    date.
+     * @since Ant 1.6.2
+     */
+    public void setGranularity(long granularity) {
+        this.granularity = granularity;
+    }
+
+    /**
+     * Perform the copy operation.
+     * @exception BuildException if an error occurs.
+     */
+    public void execute() throws BuildException {
+        File savedFile = file; // may be altered in validateAttributes
+        File savedDestFile = destFile;
+        File savedDestDir = destDir;
+        ResourceCollection savedRc = null;
+        if (file == null && destFile != null && rcs.size() == 1) {
+            // will be removed in validateAttributes
+            savedRc = (ResourceCollection) rcs.elementAt(0);
+        }
+        // make sure we don't have an illegal set of options
+        validateAttributes();
+
+        try {
+            // deal with the single file
+            copySingleFile();
+
+            // deal with the ResourceCollections
+
+            /* for historical and performance reasons we have to do
+               things in a rather complex way.
+
+               (1) Move is optimized to move directories if a fileset
+               has been included completely, therefore FileSets need a
+               special treatment.  This is also required to support
+               the failOnError semantice (skip filesets with broken
+               basedir but handle the remaining collections).
+
+               (2) We carry around a few protected methods that work
+               on basedirs and arrays of names.  To optimize stuff, all
+               resources with the same basedir get collected in
+               separate lists and then each list is handled in one go.
+            */
+
+            HashMap filesByBasedir = new HashMap();
+            HashMap dirsByBasedir = new HashMap();
+            HashSet baseDirs = new HashSet();
+            ArrayList nonFileResources = new ArrayList();
+            for (int i = 0; i < rcs.size(); i++) {
+                ResourceCollection rc = (ResourceCollection) rcs.elementAt(i);
+
+                // Step (1) - beware of the ZipFileSet
+                if (rc instanceof FileSet && rc.isFilesystemOnly()) {
+                    FileSet fs = (FileSet) rc;
+                    DirectoryScanner ds = null;
+                    try {
+                        ds = fs.getDirectoryScanner(getProject());
+                    } catch (BuildException e) {
+                        if (failonerror
+                            || !getMessage(e).endsWith(" not found.")) {
+                            throw e;
+                        } else {
+                            log("Warning: " + getMessage(e), Project.MSG_ERR);
+                            continue;
+                        }
+                    }
+                    File fromDir = fs.getDir(getProject());
+
+                    String[] srcFiles = ds.getIncludedFiles();
+                    String[] srcDirs = ds.getIncludedDirectories();
+                    if (!flatten && mapperElement == null
+                        && ds.isEverythingIncluded() && !fs.hasPatterns()) {
+                        completeDirMap.put(fromDir, destDir);
+                    }
+                    add(fromDir, srcFiles, filesByBasedir);
+                    add(fromDir, srcDirs, dirsByBasedir);
+                    baseDirs.add(fromDir);
+                } else { // not a fileset or contains non-file resources
+
+                    if (!rc.isFilesystemOnly() && !supportsNonFileResources()) {
+                        throw new BuildException(
+                                   "Only FileSystem resources are supported.");
+                    }
+
+                    Iterator resources = rc.iterator();
+                    while (resources.hasNext()) {
+                        Resource r = (Resource) resources.next();
+                        if (!r.isExists()) {
+                            continue;
+                        }
+
+                        File baseDir = NULL_FILE_PLACEHOLDER;
+                        String name = r.getName();
+                        if (r instanceof FileResource) {
+                            FileResource fr = (FileResource) r;
+                            baseDir = getKeyFile(fr.getBaseDir());
+                            if (fr.getBaseDir() == null) {
+                                name = fr.getFile().getAbsolutePath();
+                            }
+                        }
+
+                        // copying of dirs is trivial and can be done
+                        // for non-file resources as well as for real
+                        // files.
+                        if (r.isDirectory() || r instanceof FileResource) {
+                            add(baseDir, name,
+                                r.isDirectory() ? dirsByBasedir
+                                                : filesByBasedir);
+                            baseDirs.add(baseDir);
+                        } else { // a not-directory file resource
+                            // needs special treatment
+                            nonFileResources.add(r);
+                        }
+                    }
+                }
+            }
+
+            iterateOverBaseDirs(baseDirs, dirsByBasedir, filesByBasedir);
+
+            // do all the copy operations now...
+            try {
+                doFileOperations();
+            } catch (BuildException e) {
+                if (!failonerror) {
+                    log("Warning: " + getMessage(e), Project.MSG_ERR);
+                } else {
+                    throw e;
+                }
+            }
+
+            if (nonFileResources.size() > 0) {
+                Resource[] nonFiles =
+                    (Resource[]) nonFileResources.toArray(new Resource[nonFileResources.size()]);
+                // restrict to out-of-date resources
+                Map map = scan(nonFiles, destDir);
+                try {
+                    doResourceOperations(map);
+                } catch (BuildException e) {
+                    if (!failonerror) {
+                        log("Warning: " + getMessage(e), Project.MSG_ERR);
+                    } else {
+                        throw e;
+                    }
+                }
+            }
+        } finally {
+            // clean up again, so this instance can be used a second
+            // time
+            file = savedFile;
+            destFile = savedDestFile;
+            destDir = savedDestDir;
+            if (savedRc != null) {
+                rcs.insertElementAt(savedRc, 0);
+            }
+            fileCopyMap.clear();
+            dirCopyMap.clear();
+            completeDirMap.clear();
+        }
+    }
+
+    /************************************************************************
+     **  protected and private methods
+     ************************************************************************/
+
+    private void copySingleFile() {
+        // deal with the single file
+        if (file != null) {
+            if (file.exists()) {
+                if (destFile == null) {
+                    destFile = new File(destDir, file.getName());
+                }
+                if (forceOverwrite || !destFile.exists()
+                    || (file.lastModified() - granularity
+                        > destFile.lastModified())) {
+                    fileCopyMap.put(file.getAbsolutePath(),
+                                    new String[] {destFile.getAbsolutePath()});
+                } else {
+                    log(file + " omitted as " + destFile
+                        + " is up to date.", Project.MSG_VERBOSE);
+                }
+            } else {
+                String message = "Warning: Could not find file "
+                    + file.getAbsolutePath() + " to copy.";
+                if (!failonerror) {
+                    log(message, Project.MSG_ERR);
+                } else {
+                    throw new BuildException(message);
+                }
+            }
+        }
+    }
+    private void iterateOverBaseDirs(
+        HashSet baseDirs, HashMap dirsByBasedir, HashMap filesByBasedir) {
+        Iterator iter = baseDirs.iterator();
+        while (iter.hasNext()) {
+            File f = (File) iter.next();
+            List files = (List) filesByBasedir.get(f);
+            List dirs = (List) dirsByBasedir.get(f);
+
+            String[] srcFiles = new String[0];
+            if (files != null) {
+                srcFiles = (String[]) files.toArray(srcFiles);
+            }
+            String[] srcDirs = new String[0];
+            if (dirs != null) {
+                srcDirs = (String[]) dirs.toArray(srcDirs);
+            }
+            scan(f == NULL_FILE_PLACEHOLDER ? null : f, destDir, srcFiles,
+                 srcDirs);
+        }
+    }
+
+    /**
+     * Ensure we have a consistent and legal set of attributes, and set
+     * any internal flags necessary based on different combinations
+     * of attributes.
+     * @exception BuildException if an error occurs.
+     */
+    protected void validateAttributes() throws BuildException {
+        if (file == null && rcs.size() == 0) {
+            throw new BuildException(
+                "Specify at least one source--a file or a resource collection.");
+        }
+        if (destFile != null && destDir != null) {
+            throw new BuildException(
+                "Only one of tofile and todir may be set.");
+        }
+        if (destFile == null && destDir == null) {
+            throw new BuildException("One of tofile or todir must be set.");
+        }
+        if (file != null && file.isDirectory()) {
+            throw new BuildException("Use a resource collection to copy directories.");
+        }
+        if (destFile != null && rcs.size() > 0) {
+            if (rcs.size() > 1) {
+                throw new BuildException(
+                    "Cannot concatenate multiple files into a single file.");
+            } else {
+                ResourceCollection rc = (ResourceCollection) rcs.elementAt(0);
+                if (!rc.isFilesystemOnly()) {
+                    throw new BuildException("Only FileSystem resources are"
+                                             + " supported when concatenating"
+                                             + " files.");
+                }
+                if (rc.size() == 0) {
+                    throw new BuildException(
+                        "Cannot perform operation from directory to file.");
+                } else if (rc.size() == 1) {
+                    FileResource r = (FileResource) rc.iterator().next();
+                    if (file == null) {
+                        file = r.getFile();
+                        rcs.removeElementAt(0);
+                    } else {
+                        throw new BuildException(
+                            "Cannot concatenate multiple files into a single file.");
+                    }
+                } else {
+                    throw new BuildException(
+                        "Cannot concatenate multiple files into a single file.");
+                }
+            }
+        }
+        if (destFile != null) {
+            destDir = destFile.getParentFile();
+        }
+    }
+
+    /**
+     * Compares source files to destination files to see if they should be
+     * copied.
+     *
+     * @param fromDir  The source directory.
+     * @param toDir    The destination directory.
+     * @param files    A list of files to copy.
+     * @param dirs     A list of directories to copy.
+     */
+    protected void scan(File fromDir, File toDir, String[] files,
+                        String[] dirs) {
+        FileNameMapper mapper = getMapper();
+        buildMap(fromDir, toDir, files, mapper, fileCopyMap);
+
+        if (includeEmpty) {
+            buildMap(fromDir, toDir, dirs, mapper, dirCopyMap);
+        }
+    }
+
+    /**
+     * Compares source resources to destination files to see if they
+     * should be copied.
+     *
+     * @param fromResources  The source resources.
+     * @param toDir          The destination directory.
+     *
+     * @return a Map with the out-of-date resources as keys and an
+     * array of target file names as values.
+     *
+     * @since Ant 1.7
+     */
+    protected Map scan(Resource[] fromResources, File toDir) {
+        return buildMap(fromResources, toDir, getMapper());
+    }
+
+    /**
+     * Add to a map of files/directories to copy.
+     *
+     * @param fromDir the source directory.
+     * @param toDir   the destination directory.
+     * @param names   a list of filenames.
+     * @param mapper  a <code>FileNameMapper</code> value.
+     * @param map     a map of source file to array of destination files.
+     */
+    protected void buildMap(File fromDir, File toDir, String[] names,
+                            FileNameMapper mapper, Hashtable map) {
+        String[] toCopy = null;
+        if (forceOverwrite) {
+            Vector v = new Vector();
+            for (int i = 0; i < names.length; i++) {
+                if (mapper.mapFileName(names[i]) != null) {
+                    v.addElement(names[i]);
+                }
+            }
+            toCopy = new String[v.size()];
+            v.copyInto(toCopy);
+        } else {
+            SourceFileScanner ds = new SourceFileScanner(this);
+            toCopy = ds.restrict(names, fromDir, toDir, mapper, granularity);
+        }
+        for (int i = 0; i < toCopy.length; i++) {
+            File src = new File(fromDir, toCopy[i]);
+            String[] mappedFiles = mapper.mapFileName(toCopy[i]);
+
+            if (!enableMultipleMappings) {
+                map.put(src.getAbsolutePath(),
+                        new String[] {new File(toDir, mappedFiles[0]).getAbsolutePath()});
+            } else {
+                // reuse the array created by the mapper
+                for (int k = 0; k < mappedFiles.length; k++) {
+                    mappedFiles[k] = new File(toDir, mappedFiles[k]).getAbsolutePath();
+                }
+                map.put(src.getAbsolutePath(), mappedFiles);
+            }
+        }
+    }
+
+    /**
+     * Create a map of resources to copy.
+     *
+     * @param fromResources  The source resources.
+     * @param toDir   the destination directory.
+     * @param mapper  a <code>FileNameMapper</code> value.
+     * @return a map of source resource to array of destination files.
+     * @since Ant 1.7
+     */
+    protected Map buildMap(Resource[] fromResources, final File toDir,
+                           FileNameMapper mapper) {
+        HashMap map = new HashMap();
+        Resource[] toCopy = null;
+        if (forceOverwrite) {
+            Vector v = new Vector();
+            for (int i = 0; i < fromResources.length; i++) {
+                if (mapper.mapFileName(fromResources[i].getName()) != null) {
+                    v.addElement(fromResources[i]);
+                }
+            }
+            toCopy = new Resource[v.size()];
+            v.copyInto(toCopy);
+        } else {
+            toCopy =
+                ResourceUtils.selectOutOfDateSources(this, fromResources,
+                                                     mapper,
+                                                     new ResourceFactory() {
+                           public Resource getResource(String name) {
+                               return new FileResource(toDir, name);
+                           }
+                                                     },
+                                                     granularity);
+        }
+        for (int i = 0; i < toCopy.length; i++) {
+            String[] mappedFiles = mapper.mapFileName(toCopy[i].getName());
+
+            if (!enableMultipleMappings) {
+                map.put(toCopy[i],
+                        new String[] {new File(toDir, mappedFiles[0]).getAbsolutePath()});
+            } else {
+                // reuse the array created by the mapper
+                for (int k = 0; k < mappedFiles.length; k++) {
+                    mappedFiles[k] = new File(toDir, mappedFiles[k]).getAbsolutePath();
+                }
+                map.put(toCopy[i], mappedFiles);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Actually does the file (and possibly empty directory) copies.
+     * This is a good method for subclasses to override.
+     */
+    protected void doFileOperations() {
+        if (fileCopyMap.size() > 0) {
+            log("Copying " + fileCopyMap.size()
+                + " file" + (fileCopyMap.size() == 1 ? "" : "s")
+                + " to " + destDir.getAbsolutePath());
+
+            Enumeration e = fileCopyMap.keys();
+            while (e.hasMoreElements()) {
+                String fromFile = (String) e.nextElement();
+                String[] toFiles = (String[]) fileCopyMap.get(fromFile);
+
+                for (int i = 0; i < toFiles.length; i++) {
+                    String toFile = toFiles[i];
+
+                    if (fromFile.equals(toFile)) {
+                        log("Skipping self-copy of " + fromFile, verbosity);
+                        continue;
+                    }
+                    try {
+                        log("Copying " + fromFile + " to " + toFile, verbosity);
+
+                        FilterSetCollection executionFilters =
+                            new FilterSetCollection();
+                        if (filtering) {
+                            executionFilters
+                                .addFilterSet(getProject().getGlobalFilterSet());
+                        }
+                        for (Enumeration filterEnum = filterSets.elements();
+                            filterEnum.hasMoreElements();) {
+                            executionFilters
+                                .addFilterSet((FilterSet) filterEnum.nextElement());
+                        }
+                        fileUtils.copyFile(fromFile, toFile, executionFilters,
+                                           filterChains, forceOverwrite,
+                                           preserveLastModified, inputEncoding,
+                                           outputEncoding, getProject());
+                    } catch (IOException ioe) {
+                        String msg = "Failed to copy " + fromFile + " to " + toFile
+                            + " due to " + getDueTo(ioe);
+                        File targetFile = new File(toFile);
+                        if (targetFile.exists() && !targetFile.delete()) {
+                            msg += " and I couldn't delete the corrupt " + toFile;
+                        }
+                        if (failonerror) {
+                            throw new BuildException(msg, ioe, getLocation());
+                        }
+                        log(msg, Project.MSG_ERR);
+                    }
+                }
+            }
+        }
+        if (includeEmpty) {
+            Enumeration e = dirCopyMap.elements();
+            int createCount = 0;
+            while (e.hasMoreElements()) {
+                String[] dirs = (String[]) e.nextElement();
+                for (int i = 0; i < dirs.length; i++) {
+                    File d = new File(dirs[i]);
+                    if (!d.exists()) {
+                        if (!d.mkdirs()) {
+                            log("Unable to create directory "
+                                + d.getAbsolutePath(), Project.MSG_ERR);
+                        } else {
+                            createCount++;
+                        }
+                    }
+                }
+            }
+            if (createCount > 0) {
+                log("Copied " + dirCopyMap.size()
+                    + " empty director"
+                    + (dirCopyMap.size() == 1 ? "y" : "ies")
+                    + " to " + createCount
+                    + " empty director"
+                    + (createCount == 1 ? "y" : "ies") + " under "
+                    + destDir.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Actually does the resource copies.
+     * This is a good method for subclasses to override.
+     * @param map a map of source resource to array of destination files.
+     * @since Ant 1.7
+     */
+    protected void doResourceOperations(Map map) {
+        if (map.size() > 0) {
+            log("Copying " + map.size()
+                + " resource" + (map.size() == 1 ? "" : "s")
+                + " to " + destDir.getAbsolutePath());
+
+            Iterator iter = map.keySet().iterator();
+            while (iter.hasNext()) {
+                Resource fromResource = (Resource) iter.next();
+                String[] toFiles = (String[]) map.get(fromResource);
+
+                for (int i = 0; i < toFiles.length; i++) {
+                    String toFile = toFiles[i];
+
+                    try {
+                        log("Copying " + fromResource + " to " + toFile,
+                            verbosity);
+
+                        FilterSetCollection executionFilters =
+                            new FilterSetCollection();
+                        if (filtering) {
+                            executionFilters
+                                .addFilterSet(getProject().getGlobalFilterSet());
+                        }
+                        for (Enumeration filterEnum = filterSets.elements();
+                            filterEnum.hasMoreElements();) {
+                            executionFilters
+                                .addFilterSet((FilterSet) filterEnum.nextElement());
+                        }
+                        ResourceUtils.copyResource(fromResource,
+                                                   new FileResource(destDir,
+                                                                    toFile),
+                                                   executionFilters,
+                                                   filterChains,
+                                                   forceOverwrite,
+                                                   preserveLastModified,
+                                                   inputEncoding,
+                                                   outputEncoding,
+                                                   getProject());
+                    } catch (IOException ioe) {
+                        String msg = "Failed to copy " + fromResource
+                            + " to " + toFile
+                            + " due to " + getDueTo(ioe);
+                        File targetFile = new File(toFile);
+                        if (targetFile.exists() && !targetFile.delete()) {
+                            msg += " and I couldn't delete the corrupt " + toFile;
+                        }
+                        if (failonerror) {
+                            throw new BuildException(msg, ioe, getLocation());
+                        }
+                        log(msg, Project.MSG_ERR);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>&lt;copy&gt; can while &lt;move&gt; can't since we don't
+     * know how to remove non-file resources.</p>
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;copy&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true if this task supports non file resources.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(Copy.class);
+    }
+
+    /**
+     * Adds the given strings to a list contained in the given map.
+     * The file is the key into the map.
+     */
+    private static void add(File baseDir, String[] names, Map m) {
+        if (names != null) {
+            baseDir = getKeyFile(baseDir);
+            List l = (List) m.get(baseDir);
+            if (l == null) {
+                l = new ArrayList(names.length);
+                m.put(baseDir, l);
+            }
+            l.addAll(java.util.Arrays.asList(names));
+        }
+    }
+
+    /**
+     * Adds the given string to a list contained in the given map.
+     * The file is the key into the map.
+     */
+    private static void add(File baseDir, String name, Map m) {
+        if (name != null) {
+            add(baseDir, new String[] {name}, m);
+        }
+    }
+
+    /**
+     * Either returns its argument or a plaeholder if the argument is null.
+     */
+    private static File getKeyFile(File f) {
+        return f == null ? NULL_FILE_PLACEHOLDER : f;
+    }
+
+    /**
+     * returns the mapper to use based on nested elements or the
+     * flatten attribute.
+     */
+    private FileNameMapper getMapper() {
+        FileNameMapper mapper = null;
+        if (mapperElement != null) {
+            mapper = mapperElement.getImplementation();
+        } else if (flatten) {
+            mapper = new FlatFileNameMapper();
+        } else {
+            mapper = new IdentityMapper();
+        }
+        return mapper;
+    }
+
+    /**
+     * Handle getMessage() for exceptions.
+     * @param ex the exception to handle
+     * @return ex.getMessage() if ex.getMessage() is not null
+     *         otherwise return ex.toString()
+     */
+    private String getMessage(Exception ex) {
+        return ex.getMessage() == null ? ex.toString() : ex.getMessage();
+    }
+
+    /**
+     * Returns a reason for failure based on
+     * the exception thrown.
+     * If the exception is not IOException output the class name,
+     * output the message
+     * if the exception is MalformedInput add a little note.
+     */
+    private String getDueTo(Exception ex) {
+        boolean baseIOException = ex.getClass() == IOException.class;
+        StringBuffer message = new StringBuffer();
+        if (!baseIOException || ex.getMessage() == null) {
+            message.append(ex.getClass().getName());
+        }
+        if (ex.getMessage() != null) {
+            if (!baseIOException) {
+                message.append(" ");
+            }
+            message.append(ex.getMessage());
+        }
+        if (ex.getClass().getName().indexOf("MalformedInput") != -1) {
+            message.append(LINE_SEPARATOR);
+            message.append(
+                "This is normally due to the input file containing invalid");
+             message.append(LINE_SEPARATOR);
+            message.append("bytes for the character encoding used : ");
+            message.append(
+                (inputEncoding == null
+                 ? fileUtils.getDefaultEncoding() : inputEncoding));
+            message.append(LINE_SEPARATOR);
+        }
+        return message.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/CopyPath.java b/trunk/src/main/org/apache/tools/ant/taskdefs/CopyPath.java
new file mode 100644
index 0000000..cd3c3de
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/CopyPath.java
@@ -0,0 +1,206 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Copy the contents of a path to a destination, using the mapper of choice
+ *
+ * @since Ant 1.7
+ *
+ * @ant.task category="filesystem"
+ */
+
+public class CopyPath extends Task {
+
+    // Error messages
+    /** No destdir attribute */
+    public static final String ERROR_NO_DESTDIR = "No destDir specified";
+
+    /** No path  */
+    public static final String ERROR_NO_PATH = "No path specified";
+
+    /** No mapper  */
+    public static final String ERROR_NO_MAPPER = "No mapper specified";
+
+    // fileutils
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    // --- Fields --
+    private FileNameMapper mapper;
+
+    private Path path;
+
+    private File destDir;
+
+    // TODO not read, yet in a public setter
+    private long granularity = FILE_UTILS.getFileTimestampGranularity();
+
+    private boolean preserveLastModified = false;
+
+    /**
+     * The dest dir attribute.
+     * @param destDir the value of the destdir attribute.
+     */
+    public void setDestDir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * add a mapper
+     *
+     * @param newmapper the mapper to add.
+     */
+    public void add(FileNameMapper newmapper) {
+        if (mapper != null) {
+            throw new BuildException("Only one mapper allowed");
+        }
+        mapper = newmapper;
+    }
+
+    /**
+     * Set the path to be used when running the Java class.
+     *
+     * @param s
+     *            an Ant Path object containing the path.
+     */
+    public void setPath(Path s) {
+        createPath().append(s);
+    }
+
+    /**
+     * Set the path to use by reference.
+     *
+     * @param r
+     *            a reference to an existing path.
+     */
+    public void setPathRef(Reference r) {
+        createPath().setRefid(r);
+    }
+
+    /**
+     * Create a path.
+     *
+     * @return a path to be configured.
+     */
+    public Path createPath() {
+        if (path == null) {
+            path = new Path(getProject());
+        }
+        return path;
+    }
+
+    /**
+     * Set the number of milliseconds leeway to give before deciding a
+     * target is out of date.
+     * TODO: This is not yet used.
+     * @param granularity the granularity used to decide if a target is out of
+     *                    date.
+     */
+    public void setGranularity(long granularity) {
+        this.granularity = granularity;
+    }
+
+    /**
+     * Give the copied files the same last modified time as the original files.
+     * @param preserveLastModified if true preserve the modified time;
+     *                             default is false.
+     */
+    public void setPreserveLastModified(boolean preserveLastModified) {
+        this.preserveLastModified = preserveLastModified;
+    }
+
+    /**
+     * Ensure we have a consistent and legal set of attributes, and set any
+     * internal flags necessary based on different combinations of attributes.
+     *
+     * @throws BuildException
+     *             if an error occurs.
+     */
+    protected void validateAttributes() throws BuildException {
+        if (destDir == null) {
+            throw new BuildException(ERROR_NO_DESTDIR);
+        }
+        if (mapper == null) {
+            throw new BuildException(ERROR_NO_MAPPER);
+        }
+        if (path == null) {
+            throw new BuildException(ERROR_NO_PATH);
+        }
+    }
+
+    /**
+     * This is a very minimal derivative of the nomal copy logic.
+     *
+     * @throws BuildException
+     *             if something goes wrong with the build.
+     */
+    public void execute() throws BuildException {
+        validateAttributes();
+        String[] sourceFiles = path.list();
+        if (sourceFiles.length == 0) {
+            log("Path is empty", Project.MSG_VERBOSE);
+            return;
+        }
+
+        for (int sources = 0; sources < sourceFiles.length; sources++) {
+
+            String sourceFileName = sourceFiles[sources];
+            File sourceFile = new File(sourceFileName);
+            String[] toFiles = (String[]) mapper.mapFileName(sourceFileName);
+
+            for (int i = 0; i < toFiles.length; i++) {
+                String destFileName = toFiles[i];
+                File destFile = new File(destDir, destFileName);
+
+                if (sourceFile.equals(destFile)) {
+                    log("Skipping self-copy of " + sourceFileName, Project.MSG_VERBOSE);
+                    continue;
+                }
+                if (sourceFile.isDirectory()) {
+                    log("Skipping directory " + sourceFileName);
+                    continue;
+                }
+                try {
+                    log("Copying " + sourceFile + " to " + destFile, Project.MSG_VERBOSE);
+
+                    FILE_UTILS.copyFile(sourceFile, destFile, null, null, false,
+                            preserveLastModified, null, null, getProject());
+                } catch (IOException ioe) {
+                    String msg = "Failed to copy " + sourceFile + " to " + destFile + " due to "
+                            + ioe.getMessage();
+                    if (destFile.exists() && !destFile.delete()) {
+                        msg += " and I couldn't delete the corrupt " + destFile;
+                    }
+                    throw new BuildException(msg, ioe, getLocation());
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Copydir.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Copydir.java
new file mode 100644
index 0000000..173e67e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Copydir.java
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+
+/**
+ * Copies a directory.
+ *
+ * @since Ant 1.1
+ *
+ * @deprecated The copydir task is deprecated since Ant 1.2.  Use copy instead.
+ */
+
+public class Copydir extends MatchingTask {
+
+    private File srcDir;
+    private File destDir;
+    private boolean filtering = false;
+    private boolean flatten = false;
+    private boolean forceOverwrite = false;
+    private Hashtable filecopyList = new Hashtable();
+
+    /**
+     * The src attribute
+     *
+     * @param src the source file
+     */
+    public void setSrc(File src) {
+        srcDir = src;
+    }
+
+    /**
+     * The dest attribute
+     *
+     * @param dest the destination file
+     */
+    public void setDest(File dest) {
+        destDir = dest;
+    }
+
+    /**
+     * The filtering attribute.
+     * Default  is false.
+     * @param filter if true use filtering
+     */
+    public void setFiltering(boolean filter) {
+        filtering = filter;
+    }
+
+    /**
+     * The flattening attribute.
+     * Default  is false.
+     * @param flatten if true use flattening
+     */
+    public void setFlatten(boolean flatten) {
+        this.flatten = flatten;
+    }
+
+    /**
+     * The forceoverwrite attribute.
+     * Default  is false.
+     * @param force if true overwrite even if the destination file
+     *              is newer that the source file
+     */
+    public void setForceoverwrite(boolean force) {
+        forceOverwrite = force;
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        log("DEPRECATED - The copydir task is deprecated.  Use copy instead.");
+
+        if (srcDir == null) {
+            throw new BuildException("src attribute must be set!",
+                                     getLocation());
+        }
+
+        if (!srcDir.exists()) {
+            throw new BuildException("srcdir " + srcDir.toString()
+                                     + " does not exist!", getLocation());
+        }
+
+        if (destDir == null) {
+            throw new BuildException("The dest attribute must be set.",
+                                     getLocation());
+        }
+
+        if (srcDir.equals(destDir)) {
+            log("Warning: src == dest", Project.MSG_WARN);
+        }
+
+        DirectoryScanner ds = super.getDirectoryScanner(srcDir);
+
+        try {
+            String[] files = ds.getIncludedFiles();
+            scanDir(srcDir, destDir, files);
+            if (filecopyList.size() > 0) {
+                log("Copying " + filecopyList.size() + " file"
+                    + (filecopyList.size() == 1 ? "" : "s")
+                    + " to " + destDir.getAbsolutePath());
+                Enumeration e = filecopyList.keys();
+                while (e.hasMoreElements()) {
+                    String fromFile = (String) e.nextElement();
+                    String toFile = (String) filecopyList.get(fromFile);
+                    try {
+                        getProject().copyFile(fromFile, toFile, filtering,
+                                         forceOverwrite);
+                    } catch (IOException ioe) {
+                        String msg = "Failed to copy " + fromFile + " to "
+                            + toFile + " due to " + ioe.getMessage();
+                        throw new BuildException(msg, ioe, getLocation());
+                    }
+                }
+            }
+        } finally {
+            filecopyList.clear();
+        }
+    }
+
+    private void scanDir(File from, File to, String[] files) {
+        for (int i = 0; i < files.length; i++) {
+            String filename = files[i];
+            File srcFile = new File(from, filename);
+            File destFile;
+            if (flatten) {
+                destFile = new File(to, new File(filename).getName());
+            } else {
+                destFile = new File(to, filename);
+            }
+            if (forceOverwrite
+                || (srcFile.lastModified() > destFile.lastModified())) {
+                filecopyList.put(srcFile.getAbsolutePath(),
+                                 destFile.getAbsolutePath());
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Copyfile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Copyfile.java
new file mode 100644
index 0000000..e7452a6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Copyfile.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Copies a file.
+ *
+ * @since Ant 1.1
+ *
+ * @deprecated The copyfile task is deprecated since Ant 1.2.  Use
+ * copy instead.
+ */
+
+public class Copyfile extends Task {
+
+    private File srcFile;
+    private File destFile;
+    private boolean filtering = false;
+    private boolean forceOverwrite = false;
+
+    /**
+     * Set the source file.
+     * @param src the source file.
+     */
+    public void setSrc(File src) {
+        srcFile = src;
+    }
+
+    /**
+     * The forceoverwrite attribute.
+     * Default  is false.
+     * @param force if true overwrite even if the destination file
+     *              is newer that the source file
+     */
+    public void setForceoverwrite(boolean force) {
+        forceOverwrite = force;
+    }
+
+    /**
+     * Set the destination file.
+     * @param dest the destination file.
+     */
+    public void setDest(File dest) {
+        destFile = dest;
+    }
+
+    /**
+     * The filtering attribute.
+     * Default  is false.
+     * @param filter if true use filtering
+     */
+    public void setFiltering(String filter) {
+        filtering = Project.toBoolean(filter);
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        log("DEPRECATED - The copyfile task is deprecated.  Use copy instead.");
+
+        if (srcFile == null) {
+            throw new BuildException("The src attribute must be present.",
+                                     getLocation());
+        }
+
+        if (!srcFile.exists()) {
+            throw new BuildException("src " + srcFile.toString()
+                                     + " does not exist.", getLocation());
+        }
+
+        if (destFile == null) {
+            throw new BuildException("The dest attribute must be present.",
+                                     getLocation());
+        }
+
+        if (srcFile.equals(destFile)) {
+            log("Warning: src == dest", Project.MSG_WARN);
+        }
+
+        if (forceOverwrite
+            || srcFile.lastModified() > destFile.lastModified()) {
+            try {
+                getProject().copyFile(srcFile, destFile, filtering, forceOverwrite);
+            } catch (IOException ioe) {
+                String msg = "Error copying file: " + srcFile.getAbsolutePath()
+                    + " due to " + ioe.getMessage();
+                throw new BuildException(msg);
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Cvs.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Cvs.java
new file mode 100644
index 0000000..822a4ea
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Cvs.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Performs operations on a CVS repository.
+ *
+ * original 1.20
+ *
+ *  NOTE: This implementation has been moved to AbstractCvsTask with
+ *  the addition of some accessors for extensibility.
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="scm"
+ */
+public class Cvs extends AbstractCvsTask {
+
+    /**
+     * CVS Task - now implemented by the Abstract CVS Task base class
+     */
+    public Cvs() {
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/DefBase.java b/trunk/src/main/org/apache/tools/ant/taskdefs/DefBase.java
new file mode 100644
index 0000000..b52bbb7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/DefBase.java
@@ -0,0 +1,167 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+/**
+ * Base class for Definitions handling uri and class loading.
+ * (This was part of Definer)
+ *
+ * @since Ant 1.6
+ */
+public abstract class DefBase extends AntlibDefinition {
+    private ClassLoader createdLoader;
+    private ClasspathUtils.Delegate cpDelegate;
+
+    /**
+     * Check if classpath attributes have been set.
+     * (to be called before getCpDelegate() is used.
+     * @return true if cpDelegate has been created.
+     */
+    protected boolean hasCpDelegate() {
+        return cpDelegate != null;
+    }
+
+    /**
+     * @param reverseLoader if true a delegated loader will take precedence over
+     *                      the parent
+     * @deprecated since 1.6.x.
+     *             stop using this attribute
+     * @ant.attribute ignore="true"
+     */
+    public void setReverseLoader(boolean reverseLoader) {
+        getDelegate().setReverseLoader(reverseLoader);
+        log("The reverseloader attribute is DEPRECATED. It will be removed",
+            Project.MSG_WARN);
+    }
+
+    /**
+     * @return the classpath for this definition
+     */
+    public Path getClasspath() {
+        return getDelegate().getClasspath();
+    }
+
+    /**
+     * @return the reverse loader attribute of the classpath delegate.
+     */
+    public boolean isReverseLoader() {
+        return getDelegate().isReverseLoader();
+    }
+
+    /**
+     * Returns the loader id of the class path Delegate.
+     * @return the loader id
+     */
+    public String getLoaderId() {
+        return getDelegate().getClassLoadId();
+    }
+
+    /**
+     * Returns the class path id of the class path delegate.
+     * @return the class path id
+     */
+    public String getClasspathId() {
+        return getDelegate().getClassLoadId();
+    }
+
+    /**
+     * Set the classpath to be used when searching for component being defined.
+     *
+     * @param classpath an Ant Path object containing the classpath.
+     */
+    public void setClasspath(Path classpath) {
+        getDelegate().setClasspath(classpath);
+    }
+
+    /**
+     * Create the classpath to be used when searching for component being
+     * defined.
+     * @return the classpath of the this definition
+     */
+    public Path createClasspath() {
+        return getDelegate().createClasspath();
+    }
+
+    /**
+     * Set a reference to a classpath to use when loading the files.
+     * To actually share the same loader, set loaderref as well
+     * @param r the reference to the classpath
+     */
+    public void setClasspathRef(Reference r) {
+        getDelegate().setClasspathref(r);
+    }
+
+    /**
+     * Use the reference to locate the loader. If the loader is not
+     * found, the specified classpath will be used and registered
+     * with the specified name.
+     *
+     * This allows multiple taskdef/typedef to use the same class loader,
+     * so they can be used together, eliminating the need to
+     * put them in the CLASSPATH.
+     *
+     * @param r the reference to locate the loader.
+     * @since Ant 1.5
+     */
+    public void setLoaderRef(Reference r) {
+        getDelegate().setLoaderRef(r);
+    }
+
+    /**
+     * create a classloader for this definition
+     * @return the classloader from the cpDelegate
+     */
+    protected ClassLoader createLoader() {
+        if (getAntlibClassLoader() != null && cpDelegate == null) {
+            return getAntlibClassLoader();
+        }
+        if (createdLoader == null) {
+            createdLoader = getDelegate().getClassLoader();
+            // need to load Task via system classloader or the new
+            // task we want to define will never be a Task but always
+            // be wrapped into a TaskAdapter.
+            ((AntClassLoader) createdLoader)
+                .addSystemPackageRoot("org.apache.tools.ant");
+        }
+        return createdLoader;
+    }
+
+    /**
+     * @see org.apache.tools.ant.Task#init()
+     * @throws BuildException on error.
+     * @since Ant 1.6
+     */
+    public void init() throws BuildException {
+        super.init();
+    }
+
+    private ClasspathUtils.Delegate getDelegate() {
+        if (cpDelegate == null) {
+            cpDelegate = ClasspathUtils.getDelegate(this);
+        }
+        return cpDelegate;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/DefaultExcludes.java b/trunk/src/main/org/apache/tools/ant/taskdefs/DefaultExcludes.java
new file mode 100644
index 0000000..2e399ff
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/DefaultExcludes.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Alters the default excludes for the <strong>entire</strong> build..
+ *
+ * @since Ant 1.6
+ *
+ * @ant.task category="utility"
+ */
+public class DefaultExcludes extends Task {
+    private String add = "";
+    private String remove = "";
+    private boolean defaultrequested = false;
+    private boolean echo = false;
+
+    // by default, messages are always displayed
+    private int logLevel = Project.MSG_WARN;
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        if (!defaultrequested && add.equals("") && remove.equals("") && !echo) {
+            throw new BuildException("<defaultexcludes> task must set "
+                + "at least one attribute (echo=\"false\""
+                + " doesn't count since that is the default");
+        }
+        if (defaultrequested) {
+            DirectoryScanner.resetDefaultExcludes();
+        }
+        if (!add.equals("")) {
+            DirectoryScanner.addDefaultExclude(add);
+        }
+        if (!remove.equals("")) {
+            DirectoryScanner.removeDefaultExclude(remove);
+        }
+        if (echo) {
+            StringBuffer message
+                = new StringBuffer("Current Default Excludes:");
+            message.append(StringUtils.LINE_SEP);
+            String[] excludes = DirectoryScanner.getDefaultExcludes();
+            for (int i = 0; i < excludes.length; i++) {
+                message.append("  ");
+                message.append(excludes[i]);
+                message.append(StringUtils.LINE_SEP);
+            }
+            log(message.toString(), logLevel);
+        }
+    }
+
+    /**
+     * go back to standard default patterns
+     *
+     * @param def if true go back to default patterns
+     */
+    public void setDefault(boolean def) {
+        defaultrequested = def;
+    }
+    /**
+     * Pattern to add to the default excludes
+     *
+     * @param add Sets the value for the pattern to exclude.
+     */
+    public void setAdd(String add) {
+        this.add = add;
+    }
+
+     /**
+     * Pattern to remove from the default excludes.
+     *
+     * @param remove Sets the value for the pattern that
+     *            should no longer be excluded.
+     */
+    public void setRemove(String remove) {
+        this.remove = remove;
+    }
+
+    /**
+     * If true, echo the default excludes.
+     *
+     * @param echo whether or not to echo the contents of
+     *             the default excludes.
+     */
+    public void setEcho(boolean echo) {
+        this.echo = echo;
+    }
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Definer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Definer.java
new file mode 100644
index 0000000..a4ab2c8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Definer.java
@@ -0,0 +1,652 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Base class for Taskdef and Typedef - handles all
+ * the attributes for Typedef. The uri and class
+ * handling is handled by DefBase
+ *
+ * @since Ant 1.4
+ */
+public abstract class Definer extends DefBase {
+
+    /**
+     * the extension of an antlib file for autoloading.
+     * {@value[
+     */
+    private static final String ANTLIB_XML = "/antlib.xml";
+
+    private static class ResourceStack extends ThreadLocal {
+        public Object initialValue() {
+            return new HashMap();
+        }
+        Map getStack() {
+            return (Map) get();
+        }
+    }
+    private static ResourceStack resourceStack = new ResourceStack();
+    private String name;
+    private String classname;
+    private File file;
+    private String resource;
+    private boolean restrict = false;
+
+    private   int    format = Format.PROPERTIES;
+    private   boolean definerSet = false;
+    private   int         onError = OnError.FAIL;
+    private   String      adapter;
+    private   String      adaptTo;
+
+    private   Class       adapterClass;
+    private   Class       adaptToClass;
+
+    /**
+     * Enumerated type for onError attribute
+     *
+     * @see EnumeratedAttribute
+     */
+    public static class OnError extends EnumeratedAttribute {
+        /** Enumerated values */
+        public static final int  FAIL = 0, REPORT = 1, IGNORE = 2, FAIL_ALL = 3;
+
+        /**
+         * text value of onerror option {@value}
+         */
+        public static final String POLICY_FAIL = "fail";
+        /**
+         * text value of onerror option {@value}
+         */
+        public static final String POLICY_REPORT = "report";
+        /**
+         * text value of onerror option {@value}
+         */
+        public static final String POLICY_IGNORE = "ignore";
+        /**
+         * text value of onerror option {@value}
+         */
+        public static final String POLICY_FAILALL = "failall";
+
+        /**
+         * Constructor
+         */
+        public OnError() {
+            super();
+        }
+
+        /**
+         * Constructor using a string.
+         * @param value the value of the attribute
+         */
+        public OnError(String value) {
+            setValue(value);
+        }
+
+        /**
+         * get the values
+         * @return an array of the allowed values for this attribute.
+         */
+        public String[] getValues() {
+            return new String[] {POLICY_FAIL, POLICY_REPORT, POLICY_IGNORE, POLICY_FAILALL};
+        }
+    }
+
+    /**
+     * Enumerated type for format attribute
+     *
+     * @see EnumeratedAttribute
+     */
+    public static class Format extends EnumeratedAttribute {
+        /** Enumerated values */
+        public static final int PROPERTIES = 0, XML = 1;
+
+        /**
+         * get the values
+         * @return an array of the allowed values for this attribute.
+         */
+        public String[] getValues() {
+            return new String[] {"properties", "xml"};
+        }
+    }
+
+    /**
+     * The restrict attribute.
+     * If this is true, only use this definition in add(X).
+     * @param restrict the value to set.
+     */
+     protected void setRestrict(boolean restrict) {
+         this.restrict = restrict;
+     }
+
+
+    /**
+     * What to do if there is an error in loading the class.
+     * <dl>
+     *   <li>error - throw build exception</li>
+     *   <li>report - output at warning level</li>
+     *   <li>ignore - output at debug level</li>
+     * </dl>
+     *
+     * @param onError an <code>OnError</code> value
+     */
+    public void setOnError(OnError onError) {
+        this.onError = onError.getIndex();
+    }
+
+    /**
+     * Sets the format of the file or resource
+     * @param format the enumerated value - xml or properties
+     */
+    public void setFormat(Format format) {
+        this.format = format.getIndex();
+    }
+
+    /**
+     * @return the name for this definition
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the file containing definitions
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * @return the resource containing definitions
+     */
+    public String getResource() {
+        return resource;
+    }
+
+
+    /**
+     * Run the definition.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        ClassLoader al = createLoader();
+
+        if (!definerSet) {
+            //we arent fully defined yet. this is an error unless
+            //we are in an antlib, in which case the resource name is determined
+            //automatically.
+            //NB: URIs in the ant core package will be "" at this point.
+            if (getURI() == null) {
+                throw new BuildException(
+                        "name, file or resource attribute of "
+                                + getTaskName() + " is undefined",
+                        getLocation());
+            }
+
+            if (getURI().startsWith(MagicNames.ANTLIB_PREFIX)) {
+                //convert the URI to a resource
+                String uri1 = getURI();
+                setResource(makeResourceFromURI(uri1));
+            } else {
+                throw new BuildException(
+                        "Only antlib URIs can be located from the URI alone,"
+                                + "not the URI " + getURI());
+            }
+        }
+
+        if (name != null) {
+            if (classname == null) {
+                throw new BuildException(
+                    "classname attribute of " + getTaskName() + " element "
+                    + "is undefined", getLocation());
+            }
+            addDefinition(al, name, classname);
+        } else {
+            if (classname != null) {
+                String msg = "You must not specify classname "
+                    + "together with file or resource.";
+                throw new BuildException(msg, getLocation());
+            }
+            Enumeration/*<URL>*/ urls = null;
+            if (file != null) {
+                final URL url = fileToURL();
+                if (url == null) {
+                    return;
+                }
+                urls = new Enumeration() {
+                    private boolean more = true;
+                    public boolean hasMoreElements() {
+                        return more;
+                    }
+                    public Object nextElement() throws NoSuchElementException {
+                        if (more) {
+                            more = false;
+                            return url;
+                        } else {
+                            throw new NoSuchElementException();
+                        }
+                    }
+                };
+            } else {
+                urls = resourceToURLs(al);
+            }
+
+            while (urls.hasMoreElements()) {
+                URL url = (URL) urls.nextElement();
+
+                int fmt = this.format;
+                if (url.toString().toLowerCase(Locale.US).endsWith(".xml")) {
+                    fmt = Format.XML;
+                }
+
+                if (fmt == Format.PROPERTIES) {
+                    loadProperties(al, url);
+                    break;
+                } else {
+                    if (resourceStack.getStack().get(url) != null) {
+                        log("Warning: Recursive loading of " + url
+                            + " ignored"
+                            + " at " + getLocation()
+                            + " originally loaded at "
+                            + resourceStack.getStack().get(url),
+                            Project.MSG_WARN);
+                    } else {
+                        try {
+                            resourceStack.getStack().put(url, getLocation());
+                            loadAntlib(al, url);
+                        } finally {
+                            resourceStack.getStack().remove(url);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This is where the logic to map from a URI to an antlib resource
+     * is kept.
+     * @param uri the xml namespace uri that to convert.
+     * @return the name of a resource. It may not exist
+     */
+
+    public static String makeResourceFromURI(String uri) {
+        String path = uri.substring(MagicNames.ANTLIB_PREFIX.length());
+        String resource;
+        if (path.startsWith("//")) {
+            //handle new style full paths to an antlib, in which
+            //all but the forward slashes are allowed.
+            resource = path.substring("//".length());
+            if (!resource.endsWith(".xml")) {
+                //if we haven't already named an XML file, it gets antlib.xml
+                resource = resource + ANTLIB_XML;
+            }
+        } else {
+            //convert from a package to a path
+            resource = path.replace('.', '/') + ANTLIB_XML;
+        }
+        return resource;
+    }
+
+    /**
+     * Convert a file to a file: URL.
+     *
+     * @return the URL, or null if it isn't valid and the active error policy
+     * is not to raise a fault
+     * @throws BuildException if the file is missing/not a file and the
+     * policy requires failure at this point.
+     */
+    private URL fileToURL() {
+        String message = null;
+        if (!(file.exists())) {
+            message = "File " + file + " does not exist";
+        }
+        if (message == null && !(file.isFile())) {
+            message = "File " + file + " is not a file";
+        }
+        try {
+            if (message == null) {
+                return file.toURL();
+            }
+        } catch (Exception ex) {
+            message =
+                "File " + file + " cannot use as URL: "
+                + ex.toString();
+        }
+        // Here if there is an error
+        switch (onError) {
+            case OnError.FAIL_ALL:
+                throw new BuildException(message);
+            case OnError.FAIL:
+                // Fall Through
+            case OnError.REPORT:
+                log(message, Project.MSG_WARN);
+                break;
+            case OnError.IGNORE:
+                // log at a lower level
+                log(message, Project.MSG_VERBOSE);
+                break;
+            default:
+                // Ignore the problem
+                break;
+        }
+        return null;
+    }
+
+    private Enumeration/*<URL>*/ resourceToURLs(ClassLoader classLoader) {
+        Enumeration ret;
+        try {
+            ret = classLoader.getResources(resource);
+        } catch (IOException e) {
+            throw new BuildException(
+                "Could not fetch resources named " + resource,
+                e, getLocation());
+        }
+        if (!ret.hasMoreElements()) {
+            String message = "Could not load definitions from resource "
+                + resource + ". It could not be found.";
+            switch (onError) {
+                case OnError.FAIL_ALL:
+                    throw new BuildException(message);
+                case OnError.FAIL:
+                case OnError.REPORT:
+                    log(message, Project.MSG_WARN);
+                    break;
+                case OnError.IGNORE:
+                    log(message, Project.MSG_VERBOSE);
+                    break;
+                default:
+                    // Ignore the problem
+                    break;
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Load type definitions as properties from a URL.
+     *
+     * @param al the classloader to use
+     * @param url the url to get the definitions from
+     */
+    protected void loadProperties(ClassLoader al, URL url) {
+        InputStream is = null;
+        try {
+            is = url.openStream();
+            if (is == null) {
+                log("Could not load definitions from " + url,
+                    Project.MSG_WARN);
+                return;
+            }
+            Properties props = new Properties();
+            props.load(is);
+            Enumeration keys = props.keys();
+            while (keys.hasMoreElements()) {
+                name = ((String) keys.nextElement());
+                classname = props.getProperty(name);
+                addDefinition(al, name, classname);
+            }
+        } catch (IOException ex) {
+            throw new BuildException(ex, getLocation());
+        } finally {
+            FileUtils.close(is);
+        }
+    }
+
+    /**
+     * Load an antlib from a URL.
+     *
+     * @param classLoader the classloader to use.
+     * @param url the url to load the definitions from.
+     */
+    private void loadAntlib(ClassLoader classLoader, URL url) {
+        try {
+            Antlib antlib = Antlib.createAntlib(getProject(), url, getURI());
+            antlib.setClassLoader(classLoader);
+            antlib.setURI(getURI());
+            antlib.execute();
+        } catch (BuildException ex) {
+            throw ProjectHelper.addLocationToBuildException(
+                ex, getLocation());
+        }
+    }
+
+    /**
+     * Name of the property file  to load
+     * ant name/classname pairs from.
+     * @param file the file
+     */
+    public void setFile(File file) {
+        if (definerSet) {
+            tooManyDefinitions();
+        }
+        definerSet = true;
+        this.file = file;
+    }
+
+    /**
+     * Name of the property resource to load
+     * ant name/classname pairs from.
+     * @param res the resource to use
+     */
+    public void setResource(String res) {
+        if (definerSet) {
+            tooManyDefinitions();
+        }
+        definerSet = true;
+        this.resource = res;
+    }
+
+    /**
+     * Antlib attribute, sets resource and uri.
+     * uri is set the antlib value and, resource is set
+     * to the antlib.xml resource in the classpath.
+     * For example antlib="antlib:org.acme.bland.cola"
+     * corresponds to uri="antlib:org.acme.bland.cola"
+     * resource="org/acme/bland/cola/antlib.xml".
+     * ASF Bugzilla Bug 31999
+     * @param antlib the value to set.
+     */
+    public void setAntlib(String antlib) {
+        if (definerSet) {
+            tooManyDefinitions();
+        }
+        if (!antlib.startsWith("antlib:")) {
+            throw new BuildException(
+                "Invalid antlib attribute - it must start with antlib:");
+        }
+        setURI(antlib);
+        this.resource = antlib.substring("antlib:".length()).replace('.', '/')
+            + "/antlib.xml";
+        definerSet = true;
+    }
+
+    /**
+     * Name of the definition
+     * @param name the name of the definition
+     */
+    public void setName(String name) {
+        if (definerSet) {
+            tooManyDefinitions();
+        }
+        definerSet = true;
+        this.name = name;
+    }
+
+    /**
+     * Returns the classname of the object we are defining.
+     * May be <code>null</code>.
+     * @return the class name
+     */
+    public String getClassname() {
+        return classname;
+    }
+
+    /**
+     * The full class name of the object being defined.
+     * Required, unless file or resource have
+     * been specified.
+     * @param classname the name of the class
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * Set the class name of the adapter class.
+     * An adapter class is used to proxy the
+     * definition class. It is used if the
+     * definition class is not assignable to
+     * the adaptto class, or if the adaptto
+     * class is not present.
+     *
+     * @param adapter the name of the adapter class
+     */
+
+    public void setAdapter(String adapter) {
+        this.adapter = adapter;
+    }
+
+    /**
+     * Set the adapter class.
+     *
+     * @param adapterClass the class to use to adapt the definition class
+     */
+    protected void setAdapterClass(Class adapterClass) {
+        this.adapterClass = adapterClass;
+    }
+
+    /**
+     * Set the classname of the class that the definition
+     * must be compatible with, either directly or
+     * by use of the adapter class.
+     *
+     * @param adaptTo the name of the adaptto class
+     */
+    public void setAdaptTo(String adaptTo) {
+        this.adaptTo = adaptTo;
+    }
+
+    /**
+     * Set the class for adaptToClass, to be
+     * used by derived classes, used instead of
+     * the adaptTo attribute.
+     *
+     * @param adaptToClass the class for adapto.
+     */
+    protected void setAdaptToClass(Class adaptToClass) {
+        this.adaptToClass = adaptToClass;
+    }
+
+
+    /**
+     * Add a definition using the attributes of Definer
+     *
+     * @param al the ClassLoader to use
+     * @param name the name of the definition
+     * @param classname the classname of the definition
+     * @exception BuildException if an error occurs
+     */
+    protected void addDefinition(ClassLoader al, String name, String classname)
+        throws BuildException {
+        Class cl = null;
+        try {
+            try {
+                name = ProjectHelper.genComponentName(getURI(), name);
+
+                if (onError != OnError.IGNORE) {
+                    cl = Class.forName(classname, true, al);
+                }
+
+                if (adapter != null) {
+                    adapterClass = Class.forName(adapter, true, al);
+                }
+
+                if (adaptTo != null) {
+                    adaptToClass = Class.forName(adaptTo, true, al);
+                }
+
+                AntTypeDefinition def = new AntTypeDefinition();
+                def.setName(name);
+                def.setClassName(classname);
+                def.setClass(cl);
+                def.setAdapterClass(adapterClass);
+                def.setAdaptToClass(adaptToClass);
+                def.setRestrict(restrict);
+                def.setClassLoader(al);
+                if (cl != null) {
+                    def.checkClass(getProject());
+                }
+                ComponentHelper.getComponentHelper(getProject())
+                    .addDataTypeDefinition(def);
+            } catch (ClassNotFoundException cnfe) {
+                String msg = getTaskName() + " class " + classname
+                    + " cannot be found";
+                throw new BuildException(msg, cnfe, getLocation());
+            } catch (NoClassDefFoundError ncdfe) {
+                String msg = getTaskName() + " A class needed by class "
+                    + classname + " cannot be found: " + ncdfe.getMessage();
+                throw new BuildException(msg, ncdfe, getLocation());
+            }
+        } catch (BuildException ex) {
+            switch (onError) {
+                case OnError.FAIL_ALL:
+                case OnError.FAIL:
+                    throw ex;
+                case OnError.REPORT:
+                    log(ex.getLocation() + "Warning: " + ex.getMessage(),
+                        Project.MSG_WARN);
+                    break;
+                default:
+                    log(ex.getLocation() + ex.getMessage(),
+                        Project.MSG_DEBUG);
+            }
+        }
+    }
+
+    /**
+     * handle too many definitions by raising an exception.
+     * @throws BuildException always.
+     */
+    private void tooManyDefinitions() {
+        throw new BuildException(
+            "Only one of the attributes name, file and resource"
+            + " can be set", getLocation());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java
new file mode 100644
index 0000000..c439d3e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Delete.java
@@ -0,0 +1,740 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Comparator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Sort;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+import org.apache.tools.ant.types.resources.comparators.Reverse;
+import org.apache.tools.ant.types.resources.comparators.FileSystem;
+import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
+import org.apache.tools.ant.types.resources.selectors.Exists;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.selectors.OrSelector;
+import org.apache.tools.ant.types.selectors.AndSelector;
+import org.apache.tools.ant.types.selectors.NotSelector;
+import org.apache.tools.ant.types.selectors.DateSelector;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.NoneSelector;
+import org.apache.tools.ant.types.selectors.SizeSelector;
+import org.apache.tools.ant.types.selectors.DepthSelector;
+import org.apache.tools.ant.types.selectors.DependSelector;
+import org.apache.tools.ant.types.selectors.ExtendSelector;
+import org.apache.tools.ant.types.selectors.SelectSelector;
+import org.apache.tools.ant.types.selectors.PresentSelector;
+import org.apache.tools.ant.types.selectors.ContainsSelector;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+import org.apache.tools.ant.types.selectors.MajoritySelector;
+import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * Deletes a file or directory, or set of files defined by a fileset.
+ * The original delete task would delete a file, or a set of files
+ * using the include/exclude syntax.  The deltree task would delete a
+ * directory tree.  This task combines the functionality of these two
+ * originally distinct tasks.
+ * <p>Currently Delete extends MatchingTask.  This is intended <i>only</i>
+ * to provide backwards compatibility for a release.  The future position
+ * is to use nested filesets exclusively.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="filesystem"
+ */
+public class Delete extends MatchingTask {
+    private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
+    private static final ResourceComparator REVERSE_FILESYSTEM = new Reverse(new FileSystem());
+    private static final ResourceSelector EXISTS = new Exists();
+
+    private static class ReverseDirs implements ResourceCollection {
+        static final Comparator REVERSE = new Comparator() {
+            public int compare(Object foo, Object bar) {
+                return ((Comparable) foo).compareTo(bar) * -1;
+            }
+        };
+        private File basedir;
+        private String[] dirs;
+        ReverseDirs(File basedir, String[] dirs) {
+            this.basedir = basedir;
+            this.dirs = dirs;
+            Arrays.sort(this.dirs, REVERSE);
+        }
+        public Iterator iterator() {
+            return new FileResourceIterator(basedir, dirs);
+        }
+        public boolean isFilesystemOnly() { return true; }
+        public int size() { return dirs.length; }
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected File file = null;
+    protected File dir = null;
+    protected Vector filesets = new Vector();
+    protected boolean usedMatchingTask = false;
+    // by default, remove matching empty dirs
+    protected boolean includeEmpty = false;
+
+    private int verbosity = Project.MSG_VERBOSE;
+    private boolean quiet = false;
+    private boolean failonerror = true;
+    private boolean deleteOnExit = false;
+    private Resources rcs = null;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the name of a single file to be removed.
+     *
+     * @param file the file to be deleted
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Set the directory from which files are to be deleted
+     *
+     * @param dir the directory path.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+        getImplicitFileSet().setDir(dir);
+    }
+
+    /**
+     * If true, list all names of deleted files.
+     *
+     * @param verbose "true" or "on"
+     */
+    public void setVerbose(boolean verbose) {
+        if (verbose) {
+            this.verbosity = Project.MSG_INFO;
+        } else {
+            this.verbosity = Project.MSG_VERBOSE;
+        }
+    }
+
+    /**
+     * If true and the file does not exist, do not display a diagnostic
+     * message or modify the exit status to reflect an error.
+     * This means that if a file or directory cannot be deleted,
+     * then no error is reported. This setting emulates the
+     * -f option to the Unix &quot;rm&quot; command.
+     * Default is false meaning things are &quot;noisy&quot;
+     * @param quiet "true" or "on"
+     */
+    public void setQuiet(boolean quiet) {
+        this.quiet = quiet;
+        if (quiet) {
+            this.failonerror = false;
+        }
+    }
+
+    /**
+     * If false, note errors but continue.
+     *
+     * @param failonerror true or false
+     */
+     public void setFailOnError(boolean failonerror) {
+         this.failonerror = failonerror;
+     }
+
+    /**
+     * If true, on failure to delete, note the error and set
+     * the deleteonexit flag, and continue
+     *
+     * @param deleteOnExit true or false
+     */
+     public void setDeleteOnExit(boolean deleteOnExit) {
+         this.deleteOnExit = deleteOnExit;
+     }
+
+
+    /**
+     * If true, delete empty directories.
+     * @param includeEmpty if true delete empty directories (only
+     *                     for filesets). Default is false.
+     */
+    public void setIncludeEmptyDirs(boolean includeEmpty) {
+        this.includeEmpty = includeEmpty;
+    }
+
+   /**
+    * Adds a set of files to be deleted.
+    * @param set the set of files to be deleted
+    */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Add an arbitrary ResourceCollection to be deleted.
+     * @param rc the filesystem-only ResourceCollection.
+     */
+    public void add(ResourceCollection rc) {
+        if (rc == null) {
+            return;
+        }
+        rcs = (rcs == null) ? new Resources() : rcs;
+        rcs.add(rc);
+    }
+
+    /**
+     * add a name entry on the include list
+     * @return a NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createInclude() {
+        usedMatchingTask = true;
+        return super.createInclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createIncludesFile() {
+        usedMatchingTask = true;
+        return super.createIncludesFile();
+    }
+
+    /**
+     * add a name entry on the exclude list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createExclude() {
+        usedMatchingTask = true;
+        return super.createExclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createExcludesFile() {
+        usedMatchingTask = true;
+        return super.createExcludesFile();
+    }
+
+    /**
+     * add a set of patterns
+     * @return PatternSet object to be configured
+     */
+    public PatternSet createPatternSet() {
+        usedMatchingTask = true;
+        return super.createPatternSet();
+    }
+
+    /**
+     * Sets the set of include patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param includes the string containing the include patterns
+     */
+    public void setIncludes(String includes) {
+        usedMatchingTask = true;
+        super.setIncludes(includes);
+    }
+
+    /**
+     * Sets the set of exclude patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param excludes the string containing the exclude patterns
+     */
+    public void setExcludes(String excludes) {
+        usedMatchingTask = true;
+        super.setExcludes(excludes);
+    }
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+     *                           should be used, "false"|"off"|"no" when they
+     *                           shouldn't be used.
+     */
+    public void setDefaultexcludes(boolean useDefaultExcludes) {
+        usedMatchingTask = true;
+        super.setDefaultexcludes(useDefaultExcludes);
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param includesfile A string containing the filename to fetch
+     * the include patterns from.
+     */
+    public void setIncludesfile(File includesfile) {
+        usedMatchingTask = true;
+        super.setIncludesfile(includesfile);
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param excludesfile A string containing the filename to fetch
+     * the include patterns from.
+     */
+    public void setExcludesfile(File excludesfile) {
+        usedMatchingTask = true;
+        super.setExcludesfile(excludesfile);
+    }
+
+    /**
+     * Sets case sensitivity of the file system
+     *
+     * @param isCaseSensitive "true"|"on"|"yes" if file system is case
+     *                           sensitive, "false"|"off"|"no" when not.
+     */
+    public void setCaseSensitive(boolean isCaseSensitive) {
+        usedMatchingTask = true;
+        super.setCaseSensitive(isCaseSensitive);
+    }
+
+    /**
+     * Sets whether or not symbolic links should be followed.
+     *
+     * @param followSymlinks whether or not symbolic links should be followed
+     */
+    public void setFollowSymlinks(boolean followSymlinks) {
+        usedMatchingTask = true;
+        super.setFollowSymlinks(followSymlinks);
+    }
+
+    /**
+     * add a "Select" selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addSelector(SelectSelector selector) {
+        usedMatchingTask = true;
+        super.addSelector(selector);
+    }
+
+    /**
+     * add an "And" selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addAnd(AndSelector selector) {
+        usedMatchingTask = true;
+        super.addAnd(selector);
+    }
+
+    /**
+     * add an "Or" selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addOr(OrSelector selector) {
+        usedMatchingTask = true;
+        super.addOr(selector);
+    }
+
+    /**
+     * add a "Not" selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addNot(NotSelector selector) {
+        usedMatchingTask = true;
+        super.addNot(selector);
+    }
+
+    /**
+     * add a "None" selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addNone(NoneSelector selector) {
+        usedMatchingTask = true;
+        super.addNone(selector);
+    }
+
+    /**
+     * add a majority selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addMajority(MajoritySelector selector) {
+        usedMatchingTask = true;
+        super.addMajority(selector);
+    }
+
+    /**
+     * add a selector date entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addDate(DateSelector selector) {
+        usedMatchingTask = true;
+        super.addDate(selector);
+    }
+
+    /**
+     * add a selector size entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addSize(SizeSelector selector) {
+        usedMatchingTask = true;
+        super.addSize(selector);
+    }
+
+    /**
+     * add a selector filename entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addFilename(FilenameSelector selector) {
+        usedMatchingTask = true;
+        super.addFilename(selector);
+    }
+
+    /**
+     * add an extended selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addCustom(ExtendSelector selector) {
+        usedMatchingTask = true;
+        super.addCustom(selector);
+    }
+
+    /**
+     * add a contains selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addContains(ContainsSelector selector) {
+        usedMatchingTask = true;
+        super.addContains(selector);
+    }
+
+    /**
+     * add a present selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addPresent(PresentSelector selector) {
+        usedMatchingTask = true;
+        super.addPresent(selector);
+    }
+
+    /**
+     * add a depth selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addDepth(DepthSelector selector) {
+        usedMatchingTask = true;
+        super.addDepth(selector);
+    }
+
+    /**
+     * add a depends selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addDepend(DependSelector selector) {
+        usedMatchingTask = true;
+        super.addDepend(selector);
+    }
+
+    /**
+     * add a regular expression selector entry on the selector list
+     * @param selector the selector to be added
+     */
+    public void addContainsRegexp(ContainsRegexpSelector selector) {
+        usedMatchingTask = true;
+        super.addContainsRegexp(selector);
+    }
+
+    /**
+     * add the modified selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addModified(ModifiedSelector selector) {
+        usedMatchingTask = true;
+        super.addModified(selector);
+    }
+
+    /**
+     * add an arbitrary selector
+     * @param selector the selector to be added
+     * @since Ant 1.6
+     */
+    public void add(FileSelector selector) {
+        usedMatchingTask = true;
+        super.add(selector);
+    }
+
+    /**
+     * Delete the file(s).
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        if (usedMatchingTask) {
+            log("DEPRECATED - Use of the implicit FileSet is deprecated.  "
+                + "Use a nested fileset element instead.", quiet ? Project.MSG_VERBOSE : verbosity);
+        }
+
+        if (file == null && dir == null && filesets.size() == 0 && rcs == null) {
+            throw new BuildException("At least one of the file or dir "
+                                     + "attributes, or a nested resource collection, "
+                                     + "must be set.");
+        }
+
+        if (quiet && failonerror) {
+            throw new BuildException("quiet and failonerror cannot both be "
+                                     + "set to true", getLocation());
+        }
+
+        // delete the single file
+        if (file != null) {
+            if (file.exists()) {
+                if (file.isDirectory()) {
+                    log("Directory " + file.getAbsolutePath()
+                        + " cannot be removed using the file attribute.  "
+                        + "Use dir instead.", quiet ? Project.MSG_VERBOSE : verbosity);
+                } else {
+                    log("Deleting: " + file.getAbsolutePath());
+
+                    if (!delete(file)) {
+                        handle("Unable to delete file " + file.getAbsolutePath());
+                    }
+                }
+            } else {
+                log("Could not find file " + file.getAbsolutePath()
+                    + " to delete.", quiet ? Project.MSG_VERBOSE : verbosity);
+            }
+        }
+
+        // delete the directory
+        if (dir != null && dir.exists() && dir.isDirectory()
+            && !usedMatchingTask) {
+            /*
+               If verbosity is MSG_VERBOSE, that mean we are doing
+               regular logging (backwards as that sounds).  In that
+               case, we want to print one message about deleting the
+               top of the directory tree.  Otherwise, the removeDir
+               method will handle messages for _all_ directories.
+             */
+            if (verbosity == Project.MSG_VERBOSE) {
+                log("Deleting directory " + dir.getAbsolutePath());
+            }
+            removeDir(dir);
+        }
+        Resources resourcesToDelete = new Resources();
+        resourcesToDelete.setProject(getProject());
+        Resources filesetDirs = new Resources();
+        filesetDirs.setProject(getProject());
+        FileSet implicit = null;
+        if (usedMatchingTask && dir != null && dir.isDirectory()) {
+            //add the files from the default fileset:
+            implicit = getImplicitFileSet();
+            implicit.setProject(getProject());
+            filesets.add(implicit);
+        }
+
+        for (int i = 0, size = filesets.size(); i < size; i++) {
+            FileSet fs = (FileSet) filesets.get(i);
+            if (fs.getProject() == null) {
+                log("Deleting fileset with no project specified;"
+                    + " assuming executing project", Project.MSG_VERBOSE);
+                fs = (FileSet) fs.clone();
+                fs.setProject(getProject());
+            }
+            File fsDir = fs.getDir();
+            if (fsDir == null) {
+                throw new BuildException(
+                        "File or Resource without directory or file specified");
+            } else if (!fsDir.isDirectory()) {
+                handle("Directory does not exist:" + fsDir);
+            } else {
+                resourcesToDelete.add(fs);
+                if (includeEmpty) {
+                    filesetDirs.add(new ReverseDirs(fsDir, fs
+                            .getDirectoryScanner().getIncludedDirectories()));
+                }
+            }
+        }
+        resourcesToDelete.add(filesetDirs);
+        if (rcs != null) {
+            // sort first to files, then dirs
+            Restrict exists = new Restrict();
+            exists.add(EXISTS);
+            exists.add(rcs);
+            Sort s = new Sort();
+            s.add(REVERSE_FILESYSTEM);
+            s.add(exists);
+            resourcesToDelete.add(s);
+        }
+        try {
+            if (resourcesToDelete.isFilesystemOnly()) {
+                for (Iterator iter = resourcesToDelete.iterator(); iter.hasNext();) {
+                    FileResource r = (FileResource) iter.next();
+                    // nonexistent resources could only occur if we already
+                    // deleted something from a fileset:
+                    if (!r.isExists()) {
+                        continue;
+                    }
+                    if (!(r.isDirectory()) || r.getFile().list().length == 0) {
+                        log("Deleting " + r, verbosity);
+                        if (!delete(r.getFile()) && failonerror) {
+                            handle("Unable to delete "
+                                + (r.isDirectory() ? "directory " : "file ") + r);
+                        }
+                    }
+                }
+            } else {
+                 handle(getTaskName() + " handles only filesystem resources");
+            }
+        } catch (Exception e) {
+            handle(e);
+        } finally {
+            if (implicit != null) {
+                filesets.remove(implicit);
+            }
+        }
+    }
+
+//************************************************************************
+//  protected and private methods
+//************************************************************************
+
+    private void handle(String msg) {
+        handle(new BuildException(msg));
+    }
+
+    private void handle(Exception e) {
+        if (failonerror) {
+            throw (e instanceof BuildException)
+                ? (BuildException) e : new BuildException(e);
+        }
+        log(e, quiet ? Project.MSG_VERBOSE : verbosity);
+    }
+
+    /**
+     * Accommodate Windows bug encountered in both Sun and IBM JDKs.
+     * Others possible. If the delete does not work, call System.gc(),
+     * wait a little and try again.
+     */
+    private boolean delete(File f) {
+        if (!f.delete()) {
+            if (Os.isFamily("windows")) {
+                System.gc();
+            }
+            try {
+                Thread.sleep(DELETE_RETRY_SLEEP_MILLIS);
+            } catch (InterruptedException ex) {
+                // Ignore Exception
+            }
+            if (!f.delete()) {
+                if (deleteOnExit) {
+                    int level = quiet ? Project.MSG_VERBOSE : Project.MSG_INFO;
+                    log("Failed to delete " + f + ", calling deleteOnExit."
+                        + " This attempts to delete the file when the Ant jvm"
+                        + " has exited and might not succeed.", level);
+                    f.deleteOnExit();
+                    return true;
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Delete a directory
+     *
+     * @param d the directory to delete
+     */
+    protected void removeDir(File d) {
+        String[] list = d.list();
+        if (list == null) {
+            list = new String[0];
+        }
+        for (int i = 0; i < list.length; i++) {
+            String s = list[i];
+            File f = new File(d, s);
+            if (f.isDirectory()) {
+                removeDir(f);
+            } else {
+                log("Deleting " + f.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
+                if (!delete(f)) {
+                    handle("Unable to delete file " + f.getAbsolutePath());
+                }
+            }
+        }
+        log("Deleting directory " + d.getAbsolutePath(), verbosity);
+        if (!delete(d)) {
+            handle("Unable to delete directory " + dir.getAbsolutePath());
+        }
+    }
+
+    /**
+     * remove an array of files in a directory, and a list of subdirectories
+     * which will only be deleted if 'includeEmpty' is true
+     * @param d directory to work from
+     * @param files array of files to delete; can be of zero length
+     * @param dirs array of directories to delete; can of zero length
+     */
+    protected void removeFiles(File d, String[] files, String[] dirs) {
+        if (files.length > 0) {
+            log("Deleting " + files.length + " files from "
+                + d.getAbsolutePath(), quiet ? Project.MSG_VERBOSE : verbosity);
+            for (int j = 0; j < files.length; j++) {
+                File f = new File(d, files[j]);
+                log("Deleting " + f.getAbsolutePath(),
+                        quiet ? Project.MSG_VERBOSE : verbosity);
+                if (!delete(f)) {
+                    handle("Unable to delete file " + f.getAbsolutePath());
+                }
+            }
+        }
+
+        if (dirs.length > 0 && includeEmpty) {
+            int dirCount = 0;
+            for (int j = dirs.length - 1; j >= 0; j--) {
+                File currDir = new File(d, dirs[j]);
+                String[] dirFiles = currDir.list();
+                if (dirFiles == null || dirFiles.length == 0) {
+                    log("Deleting " + currDir.getAbsolutePath(),
+                            quiet ? Project.MSG_VERBOSE : verbosity);
+                    if (!delete(currDir)) {
+                        handle("Unable to delete directory "
+                                + currDir.getAbsolutePath());
+                    } else {
+                        dirCount++;
+                    }
+                }
+            }
+
+            if (dirCount > 0) {
+                log("Deleted "
+                     + dirCount
+                     + " director" + (dirCount == 1 ? "y" : "ies")
+                     + " form " + d.getAbsolutePath(),
+                     quiet ? Project.MSG_VERBOSE : verbosity);
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Deltree.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Deltree.java
new file mode 100644
index 0000000..5fb0221
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Deltree.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @deprecated The deltree task is deprecated since Ant 1.2.  Use
+ * delete instead.
+ */
+
+public class Deltree extends Task {
+
+    private File dir;
+
+    /**
+     * Set the directory to be deleted
+     *
+     * @param dir the root of the tree to be removed.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * Do the work.
+     *
+     * @exception BuildException if the task is not configured correctly or
+     * the tree cannot be removed.
+     */
+    public void execute() throws BuildException {
+        log("DEPRECATED - The deltree task is deprecated.  "
+            + "Use delete instead.");
+
+        if (dir == null) {
+            throw new BuildException("dir attribute must be set!", getLocation());
+        }
+
+        if (dir.exists()) {
+            if (!dir.isDirectory()) {
+                if (!dir.delete()) {
+                    throw new BuildException("Unable to delete directory "
+                                             + dir.getAbsolutePath(),
+                                             getLocation());
+                }
+                return;
+            }
+
+            log("Deleting: " + dir.getAbsolutePath());
+
+            try {
+                removeDir(dir);
+            } catch (IOException ioe) {
+                String msg = "Unable to delete " + dir.getAbsolutePath();
+                throw new BuildException(msg, getLocation());
+            }
+        }
+    }
+
+    private void removeDir(File dir) throws IOException {
+
+        // check to make sure that the given dir isn't a symlink
+        // the comparison of absolute path and canonical path
+        // catches this
+
+        //        if (dir.getCanonicalPath().equals(dir.getAbsolutePath())) {
+        // (costin) It will not work if /home/costin is symlink to
+        // /da0/home/costin ( taz for example )
+        String[] list = dir.list();
+        for (int i = 0; i < list.length; i++) {
+            String s = list[i];
+            File f = new File(dir, s);
+            if (f.isDirectory()) {
+                removeDir(f);
+            } else {
+                if (!f.delete()) {
+                    throw new BuildException("Unable to delete file "
+                                             + f.getAbsolutePath());
+                }
+            }
+        }
+        if (!dir.delete()) {
+            throw new BuildException("Unable to delete directory "
+                                     + dir.getAbsolutePath());
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/DependSet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/DependSet.java
new file mode 100644
index 0000000..62d16aa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/DependSet.java
@@ -0,0 +1,256 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Iterator;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FileList;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.TimeComparison;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.selectors.Not;
+import org.apache.tools.ant.types.resources.selectors.Exists;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.resources.comparators.Reverse;
+import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
+
+/**
+ * Examines and removes out of date target files.  If any of the target files
+ * are out of date with respect to any of the source files, all target
+ * files are removed.  This is useful where dependencies cannot be
+ * computed (for example, dynamically interpreted parameters or files
+ * that need to stay in synch but are not directly linked) or where
+ * the ant task in question could compute them but does not (for
+ * example, the linked DTD for an XML file using the XSLT task).
+ *
+ * nested arguments:
+ * <ul>
+ * <li>sources        (resource union describing the source resources to examine)
+ * <li>srcfileset     (fileset describing the source files to examine)
+ * <li>srcfilelist    (filelist describing the source files to examine)
+ * <li>targets        (path describing the target files to examine)
+ * <li>targetfileset  (fileset describing the target files to examine)
+ * <li>targetfilelist (filelist describing the target files to examine)
+ * </ul>
+ * At least one of both source and target entities is required.
+ * <p>
+ * This task will examine each of the sources against each of the target files. If
+ * any target files are out of date with respect to any of the sources, all targets
+ * are removed. If any sources or targets do not exist, all targets are removed.
+ * Hint: If missing files should be ignored, specify them as include patterns
+ * in filesets, rather than using filelists.
+ * </p><p>
+ * This task attempts to optimize speed of dependency checking
+ * by comparing only the dates of the oldest target file and the newest source.
+ * </p><p>
+ * Example uses:
+ * <ul><li>
+ * Record the fact that an XML file must be up to date with respect to its XSD
+ * (Schema file), even though the XML file itself includes no reference to its XSD.
+ * </li><li>
+ * Record the fact that an XSL stylesheet includes other sub-stylesheets
+ * </li><li>
+ * Record the fact that java files must be recompiled if the ant build file changes
+ * </li></ul>
+ *
+ * @ant.task category="filesystem"
+ * @since Ant 1.4
+ */
+public class DependSet extends MatchingTask {
+
+    private static final ResourceSelector NOT_EXISTS = new Not(new Exists());
+    private static final ResourceComparator DATE
+        = new org.apache.tools.ant.types.resources.comparators.Date();
+    private static final ResourceComparator REVERSE_DATE = new Reverse(DATE);
+
+    private static final class NonExistent extends Restrict {
+        private NonExistent(ResourceCollection rc) {
+            super.add(rc);
+            super.add(NOT_EXISTS);
+        }
+    }
+
+    private static final class HideMissingBasedir
+        implements ResourceCollection {
+        private FileSet fs;
+
+        private HideMissingBasedir(FileSet fs) {
+            this.fs = fs;
+        }
+        public Iterator iterator() {
+            return basedirExists() ? fs.iterator() : Resources.EMPTY_ITERATOR;
+        }
+        public int size() {
+            return basedirExists() ? fs.size() : 0;
+        }
+        public boolean isFilesystemOnly() {
+            return true;
+        }
+        private boolean basedirExists() {
+            File basedir = fs.getDir();
+            //trick to evoke "basedir not set" if null:
+            return basedir == null || basedir.exists();
+        }
+    }
+
+    private Union sources = null;
+    private Path targets = null;
+
+    /**
+     * Create a nested sources element.
+     * @return a Union instance.
+     */
+    public synchronized Union createSources() {
+        sources = (sources == null) ? new Union() : sources;
+        return sources;
+    }
+
+    /**
+     * Add a set of source files.
+     * @param fs the FileSet to add.
+     */
+    public void addSrcfileset(FileSet fs) {
+        createSources().add(fs);
+    }
+
+    /**
+     * Add a list of source files.
+     * @param fl the FileList to add.
+     */
+    public void addSrcfilelist(FileList fl) {
+        createSources().add(fl);
+    }
+
+    /**
+     * Create a nested targets element.
+     * @return a Union instance.
+     */
+    public synchronized Path createTargets() {
+        targets = (targets == null) ? new Path(getProject()) : targets;
+        return targets;
+    }
+
+    /**
+     * Add a set of target files.
+     * @param fs the FileSet to add.
+     */
+    public void addTargetfileset(FileSet fs) {
+        createTargets().add(new HideMissingBasedir(fs));
+    }
+
+    /**
+     * Add a list of target files.
+     * @param fl the FileList to add.
+     */
+    public void addTargetfilelist(FileList fl) {
+        createTargets().add(fl);
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException if errors occur.
+     */
+    public void execute() throws BuildException {
+        if (sources == null) {
+          throw new BuildException(
+              "At least one set of source resources must be specified");
+        }
+        if (targets == null) {
+          throw new BuildException(
+              "At least one set of target files must be specified");
+        }
+        //no sources = nothing to compare; no targets = nothing to delete:
+        if (sources.size() > 0 && targets.size() > 0 && !uptodate(sources, targets)) {
+           log("Deleting all target files.", Project.MSG_VERBOSE);
+           Delete delete = new Delete();
+           delete.bindToOwner(this);
+           delete.add(targets);
+           delete.perform();
+        }
+    }
+
+    private boolean uptodate(ResourceCollection src, ResourceCollection target) {
+        org.apache.tools.ant.types.resources.selectors.Date datesel
+            = new org.apache.tools.ant.types.resources.selectors.Date();
+        datesel.setMillis(System.currentTimeMillis());
+        datesel.setWhen(TimeComparison.AFTER);
+        logFuture(targets, datesel);
+
+        int neTargets = new NonExistent(targets).size();
+        if (neTargets > 0) {
+            log(neTargets + " nonexistent targets", Project.MSG_VERBOSE);
+            return false;
+        }
+        FileResource oldestTarget = (FileResource) getOldest(targets);
+        log(oldestTarget + " is oldest target file", Project.MSG_VERBOSE);
+
+        logFuture(sources, datesel);
+
+        int neSources = new NonExistent(sources).size();
+        if (neSources > 0) {
+            log(neSources + " nonexistent sources", Project.MSG_VERBOSE);
+            return false;
+        }
+        Resource newestSource = (Resource) getNewest(sources);
+        log(newestSource.toLongString() + " is newest source", Project.MSG_VERBOSE);
+        return oldestTarget.getLastModified() >= newestSource.getLastModified();
+    }
+
+    private void logFuture(ResourceCollection rc, ResourceSelector rsel) {
+        Restrict r = new Restrict();
+        r.add(rsel);
+        r.add(rc);
+        for (Iterator i = r.iterator(); i.hasNext();) {
+            log("Warning: " + i.next() + " modified in the future.", Project.MSG_WARN);
+        }
+    }
+
+    private Resource getXest(ResourceCollection rc, ResourceComparator c) {
+        Iterator i = rc.iterator();
+        if (!i.hasNext()) {
+            return null;
+
+        }
+        Resource xest = (Resource) i.next();
+        while (i.hasNext()) {
+            Resource next = (Resource) i.next();
+            if (c.compare(xest, next) < 0) {
+                xest = next;
+            }
+        }
+        return xest;
+    }
+
+    private Resource getOldest(ResourceCollection rc) {
+        return getXest(rc, REVERSE_DATE);
+    }
+
+    private Resource getNewest(ResourceCollection rc) {
+        return getXest(rc, DATE);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/DiagnosticsTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/DiagnosticsTask.java
new file mode 100644
index 0000000..c745cfb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/DiagnosticsTask.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Diagnostics;
+import org.apache.tools.ant.Task;
+
+/**
+ * This is a task that hands off work to the Diagnostics module.
+ * It lets you run diagnostics in an IDE.
+ */
+public class DiagnosticsTask extends Task {
+
+    private static final String[] ARGS = new String[0];
+
+    /**
+     * Execute the task.
+     * This delegates to the Diagnostics class.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        Diagnostics.main(ARGS);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Dirname.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Dirname.java
new file mode 100644
index 0000000..b7081bf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Dirname.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Determines the directory name of the specified file.
+ *
+ * This task can accept the following attributes:
+ * <ul>
+ * <li>file
+ * <li>property
+ * </ul>
+ * Both <b>file</b> and <b>property</b> are required.
+ * <p>
+ * When this task executes, it will set the specified property to the
+ * value of the specified file up to, but not including, the last path
+ * element. If file is a file, the directory will be the current
+ * directory.
+ *
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="property"
+ */
+
+public class Dirname extends Task {
+    private File file;
+    private String property;
+
+    /**
+     * Path to take the dirname of.
+     * @param file a <code>File</code> value
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * The name of the property to set.
+     * @param property the name of the property
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * Execute this task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (property == null) {
+            throw new BuildException("property attribute required", getLocation());
+        }
+        if (file == null) {
+            throw new BuildException("file attribute required", getLocation());
+        } else {
+            String value = file.getParent();
+            getProject().setNewProperty(property, value);
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Ear.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Ear.java
new file mode 100644
index 0000000..f7f9ca6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Ear.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.zip.ZipOutputStream;
+
+/**
+ * Creates a EAR archive. Based on WAR task
+ *
+ * @since Ant 1.4
+ *
+ * @ant.task category="packaging"
+ */
+public class Ear extends Jar {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File deploymentDescriptor;
+    private boolean descriptorAdded;
+    private static final String XML_DESCRIPTOR_PATH = "META-INF/application.xml";
+
+    /**
+     * Create an Ear task.
+     */
+    public Ear() {
+        super();
+        archiveType = "ear";
+        emptyBehavior = "create";
+    }
+
+    /**
+     * Set the destination file.
+     * @param earFile the destination file
+     * @deprecated since 1.5.x.
+     *             Use setDestFile(destfile) instead.
+     */
+    public void setEarfile(File earFile) {
+        setDestFile(earFile);
+    }
+
+    /**
+     * File to incorporate as application.xml.
+     * @param descr the descriptor file
+     */
+    public void setAppxml(File descr) {
+        deploymentDescriptor = descr;
+        if (!deploymentDescriptor.exists()) {
+            throw new BuildException("Deployment descriptor: "
+                                     + deploymentDescriptor
+                                     + " does not exist.");
+        }
+
+        // Create a ZipFileSet for this file, and pass it up.
+        ZipFileSet fs = new ZipFileSet();
+        fs.setFile(deploymentDescriptor);
+        fs.setFullpath(XML_DESCRIPTOR_PATH);
+        super.addFileset(fs);
+    }
+
+
+    /**
+     * Adds zipfileset.
+     *
+     * @param fs zipfileset to add
+     */
+    public void addArchives(ZipFileSet fs) {
+        // We just set the prefix for this fileset, and pass it up.
+        // Do we need to do this? LH
+        fs.setPrefix("/");
+        super.addFileset(fs);
+    }
+
+
+    /**
+     * Initialize the output stream.
+     * @param zOut the zip output stream.
+     * @throws IOException on I/O errors
+     * @throws BuildException on other errors
+     */
+    protected void initZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+        // If no webxml file is specified, it's an error.
+        if (deploymentDescriptor == null && !isInUpdateMode()) {
+            throw new BuildException("appxml attribute is required", getLocation());
+        }
+
+        super.initZipOutputStream(zOut);
+    }
+
+    /**
+     * Overridden from Zip class to deal with application.xml
+     * @param file the file to add to the archive
+     * @param zOut the stream to write to
+     * @param vPath the name this entry shall have in the archive
+     * @param mode the Unix permissions to set.
+     * @throws IOException on error
+     */
+    protected void zipFile(File file, ZipOutputStream zOut, String vPath,
+                           int mode)
+        throws IOException {
+        // If the file being added is META-INF/application.xml, we
+        // warn if it's not the one specified in the "appxml"
+        // attribute - or if it's being added twice, meaning the same
+        // file is specified by the "appxml" attribute and in a
+        // <fileset> element.
+        String vPathLowerCase = vPath.toLowerCase(Locale.ENGLISH);
+        if (XML_DESCRIPTOR_PATH.equals(vPathLowerCase))  {
+            if (deploymentDescriptor != null
+                || !FILE_UTILS.fileNameEquals(deploymentDescriptor, file)
+                || descriptorAdded) {
+                log("Warning: selected " + archiveType
+                    + " files include a " + XML_DESCRIPTOR_PATH + " which will"
+                    + " be ignored (please use appxml attribute to "
+                    + archiveType + " task)",
+                        Project.MSG_WARN);
+            } else {
+                super.zipFile(file, zOut, vPath, mode);
+                descriptorAdded = true;
+            }
+        } else {
+            super.zipFile(file, zOut, vPath, mode);
+        }
+    }
+
+    /**
+     * Make sure we don't think we already have a application.xml next
+     * time this task gets executed.
+     */
+    protected void cleanUp() {
+        descriptorAdded = false;
+        super.cleanUp();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Echo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Echo.java
new file mode 100644
index 0000000..f724293
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Echo.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.FileOutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.LogLevel;
+
+/**
+ * Writes a message to the Ant logging facilities.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="utility"
+ */
+public class Echo extends Task {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String message = "";
+    protected File file = null;
+    protected boolean append = false;
+    /** encoding; set to null or empty means 'default' */
+    private String encoding = "";
+
+    // by default, messages are always displayed
+    protected int logLevel = Project.MSG_WARN;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        if (file == null) {
+            log(message, logLevel);
+        } else {
+            Writer out = null;
+            try {
+                String filename = file.getAbsolutePath();
+                if (encoding == null || encoding.length() == 0) {
+                    out = new FileWriter(filename, append);
+                } else {
+                    out = new BufferedWriter(
+                            new OutputStreamWriter(
+                                new FileOutputStream(filename, append), encoding));
+                }
+                out.write(message, 0, message.length());
+            } catch (IOException ioe) {
+                throw new BuildException(ioe, getLocation());
+            } finally {
+                FileUtils.close(out);
+            }
+        }
+    }
+
+    /**
+     * Message to write.
+     *
+     * @param msg Sets the value for the message variable.
+     */
+    public void setMessage(String msg) {
+        this.message = msg;
+    }
+
+    /**
+     * File to write to.
+     * @param file the file to write to, if not set, echo to
+     *             standard output
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * If true, append to existing file.
+     * @param append if true, append to existing file, default
+     *               is false.
+     */
+    public void setAppend(boolean append) {
+        this.append = append;
+    }
+
+    /**
+     * Set a multiline message.
+     * @param msg the CDATA text to append to the output text
+     */
+    public void addText(String msg) {
+        message += getProject().replaceProperties(msg);
+    }
+
+    /**
+     * Set the logging level. Level should be one of
+     * <ul>
+     *  <li>error</li>
+     *  <li>warning</li>
+     *  <li>info</li>
+     *  <li>verbose</li>
+     *  <li>debug</li>
+     * </ul>
+     * <p>The default is &quot;warning&quot; to ensure that messages are
+     * displayed by default when using the -quiet command line option.</p>
+     * @param echoLevel the logging level
+     */
+    public void setLevel(EchoLevel echoLevel) {
+        logLevel = echoLevel.getLevel();
+    }
+
+    /**
+     * Declare the encoding to use when outputting to a file;
+     * Use "" for the platform's default encoding.
+     * @param encoding the character encoding to use.
+     * @since 1.7
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * The enumerated values for the level attribute.
+     */
+    public static class EchoLevel extends LogLevel {
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/EchoXML.java b/trunk/src/main/org/apache/tools/ant/taskdefs/EchoXML.java
new file mode 100755
index 0000000..dfcaf2a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/EchoXML.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.XMLFragment;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+/**
+ * Echo XML.
+ *
+ * Known limitations:
+ * <ol>
+ * <li>Currently no XMLNS support</li>
+ * <li>Processing Instructions get ignored</li>
+ * <li>Encoding is always UTF-8</li>
+ * </ol>
+ *
+ * @since Ant 1.7
+ */
+public class EchoXML extends XMLFragment {
+
+    private File file;
+    private boolean append;
+    private static final String ERROR_NO_XML = "No nested XML specified";
+
+    /**
+     * Set the output file.
+     * @param f the output file.
+     */
+    public void setFile(File f) {
+        file = f;
+    }
+
+    /**
+     * Set whether to append the output file.
+     * @param b boolean append flag.
+     */
+    public void setAppend(boolean b) {
+        append = b;
+    }
+
+    /**
+     * Execute the task.
+     */
+    public void execute() {
+        DOMElementWriter writer = new DOMElementWriter(!append);
+        OutputStream os = null;
+        try {
+            if (file != null) {
+                os = new FileOutputStream(file.getAbsolutePath(), append);
+            } else {
+                os = new LogOutputStream(this, Project.MSG_INFO);
+            }
+            Node n = getFragment().getFirstChild();
+            if (n == null) {
+                throw new BuildException(ERROR_NO_XML);
+            }
+            writer.write((Element) n, os);
+        } catch (BuildException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new BuildException(e);
+        } finally {
+            FileUtils.close(os);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Exec.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Exec.java
new file mode 100644
index 0000000..c1d354b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Exec.java
@@ -0,0 +1,280 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Executes a given command if the os platform is appropriate.
+ *
+ * <p><strong>As of Ant 1.2, this class is no longer the
+ * implementation of Ant's &lt;exec&gt; task - it is considered to be
+ * dead code by the Ant developers and is unmaintained.  Don't use
+ * it.</strong></p>
+ *
+ * @deprecated since 1.2.
+ *             delegate to {@link org.apache.tools.ant.taskdefs.Execute Execute}
+ *             instead.
+ */
+public class Exec extends Task {
+    private String os;
+    private String out;
+    private File dir;
+    private String command;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected PrintWriter fos = null;
+    // CheckStyle:VisibilityModifier ON
+    private boolean failOnError = false;
+
+    /**
+     * Constructor for Exec.
+     * Prints a warning message to std error.
+     */
+    public Exec() {
+        System.err.println("As of Ant 1.2 released in October 2000, "
+            + "the Exec class");
+        System.err.println("is considered to be dead code by the Ant "
+            + "developers and is unmaintained.");
+        System.err.println("Don\'t use it!");
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        run(command);
+    }
+
+    /**
+     * Execute the command.
+     * @param command the command to exec
+     * @return the exit value of the command
+     * @throws BuildException on error
+     */
+    protected int run(String command) throws BuildException {
+
+        int err = -1; // assume the worst
+
+        // test if os match
+        String myos = System.getProperty("os.name");
+        log("Myos = " + myos, Project.MSG_VERBOSE);
+        if ((os != null) && (os.indexOf(myos) < 0)) {
+            // this command will be executed only on the specified OS
+            log("Not found in " + os, Project.MSG_VERBOSE);
+            return 0;
+        }
+
+        // default directory to the project's base directory
+        if (dir == null) {
+          dir = getProject().getBaseDir();
+        }
+
+        if (myos.toLowerCase().indexOf("windows") >= 0) {
+            if (!dir.equals(getProject().resolveFile("."))) {
+                if (myos.toLowerCase().indexOf("nt") >= 0) {
+                    command = "cmd /c cd " + dir + " && " + command;
+                } else {
+                    String ant = getProject().getProperty(MagicNames.ANT_HOME);
+                    if (ant == null) {
+                        throw new BuildException("Property '" + MagicNames.ANT_HOME + "' not "
+                            + "found", getLocation());
+                    }
+
+                    String antRun = getProject().resolveFile(ant + "/bin/antRun.bat").toString();
+                    command = antRun + " " + dir + " " + command;
+                }
+            }
+        } else {
+            String ant = getProject().getProperty(MagicNames.ANT_HOME);
+            if (ant == null) {
+              throw new BuildException("Property '" + MagicNames.ANT_HOME + "' not found",
+                                       getLocation());
+            }
+            String antRun = getProject().resolveFile(ant + "/bin/antRun").toString();
+
+            command = antRun + " " + dir + " " + command;
+        }
+
+        try {
+            // show the command
+            log(command, Project.MSG_VERBOSE);
+
+            // exec command on system runtime
+            Process proc = Runtime.getRuntime().exec(command);
+
+            if (out != null)  {
+                fos = new PrintWriter(new FileWriter(out));
+                log("Output redirected to " + out, Project.MSG_VERBOSE);
+            }
+
+            // copy input and error to the output stream
+            StreamPumper inputPumper =
+                new StreamPumper(proc.getInputStream(), Project.MSG_INFO);
+            StreamPumper errorPumper =
+                new StreamPumper(proc.getErrorStream(), Project.MSG_WARN);
+
+            // starts pumping away the generated output/error
+            inputPumper.start();
+            errorPumper.start();
+
+            // Wait for everything to finish
+            proc.waitFor();
+            inputPumper.join();
+            errorPumper.join();
+            proc.destroy();
+
+            // close the output file if required
+            logFlush();
+
+            // check its exit value
+            err = proc.exitValue();
+            if (err != 0) {
+                if (failOnError) {
+                    throw new BuildException("Exec returned: " + err, getLocation());
+                } else {
+                    log("Result: " + err, Project.MSG_ERR);
+                }
+            }
+        } catch (IOException ioe) {
+            throw new BuildException("Error exec: " + command, ioe, getLocation());
+        } catch (InterruptedException ex) {
+            //ignore
+        }
+
+        return err;
+    }
+
+    /**
+     * Set the directory.
+     * @param d a <code>String</code> value
+     */
+    public void setDir(String d) {
+        this.dir = getProject().resolveFile(d);
+    }
+
+    /**
+     * Set the Operating System that this exec is to run in.
+     * @param os a <code>String</code> value
+     */
+    public void setOs(String os) {
+        this.os = os;
+    }
+
+    /**
+     * Set the command to exec.
+     * @param command a <code>String</code> value
+     */
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    /**
+     * Set the output filename.
+     * @param out a <code>String</code> value
+     */
+    public void setOutput(String out) {
+        this.out = out;
+    }
+
+    /**
+     * Set the failOnError attribute.
+     * Default is false.
+     * @param fail a <code>boolean</code> value
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * Log an output message.
+     * @param line the line to putput
+     * @param messageLevel the level of logging - ignored
+     *                     if output is going to a file
+     */
+    protected void outputLog(String line, int messageLevel) {
+        if (fos == null) {
+            log(line, messageLevel);
+        } else {
+            fos.println(line);
+        }
+    }
+
+    /**
+     * Close output.
+     */
+    protected void logFlush() {
+        if (fos != null) {
+          fos.close();
+        }
+    }
+
+    // Inner class for continually pumping the input stream during
+    // Process's runtime.
+    class StreamPumper extends Thread {
+        private BufferedReader din;
+        private int messageLevel;
+        private boolean endOfStream = false;
+        private static final int SLEEP_TIME = 5;
+
+        public StreamPumper(InputStream is, int messageLevel) {
+            this.din = new BufferedReader(new InputStreamReader(is));
+            this.messageLevel = messageLevel;
+        }
+
+        public void pumpStream() throws IOException {
+            if (!endOfStream) {
+                String line = din.readLine();
+
+                if (line != null) {
+                    outputLog(line, messageLevel);
+                } else {
+                    endOfStream = true;
+                }
+            }
+        }
+
+        public void run() {
+            try {
+                try {
+                    while (!endOfStream) {
+                        pumpStream();
+                        sleep(SLEEP_TIME);
+                    }
+                } catch (InterruptedException ie) {
+                    //ignore
+                }
+                din.close();
+            } catch (IOException ioe) {
+                // ignore
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ExecTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
new file mode 100644
index 0000000..dcddb5e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
@@ -0,0 +1,713 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.Locale;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.RedirectorElement;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Executes a given command if the os platform is appropriate.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="control"
+ */
+public class ExecTask extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private String os;
+    private String osFamily;
+
+    private File dir;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean failOnError = false;
+    protected boolean newEnvironment = false;
+    private Long timeout = null;
+    private Environment env = new Environment();
+    protected Commandline cmdl = new Commandline();
+    private String resultProperty;
+    private boolean failIfExecFails = true;
+    private String executable;
+    private boolean resolveExecutable = false;
+    private boolean searchPath = false;
+    private boolean spawn = false;
+    private boolean incompatibleWithSpawn = false;
+
+    //include locally for screening purposes
+    private String inputString;
+    private File input;
+    private File output;
+    private File error;
+
+    protected Redirector redirector = new Redirector(this);
+    protected RedirectorElement redirectorElement;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Controls whether the VM (1.3 and above) is used to execute the
+     * command
+     */
+    private boolean vmLauncher = true;
+
+
+    /**
+     * Create an instance.
+     * Needs to be configured by binding to a project.
+     */
+    public ExecTask() {
+    }
+
+    /**
+     * create an instance that is helping another task.
+     * Project, OwningTarget, TaskName and description are all
+     * pulled out
+     * @param owner task that we belong to
+     */
+    public ExecTask(Task owner) {
+        bindToOwner(owner);
+    }
+
+    /**
+     * Set whether or not you want the process to be spawned.
+     * Default is false.
+     * @param spawn if true you do not want Ant to wait for the end of the process.
+     * @since Ant 1.6
+     */
+    public void setSpawn(boolean spawn) {
+        this.spawn = spawn;
+    }
+
+    /**
+     * Set the timeout in milliseconds after which the process will be killed.
+     *
+     * @param value timeout in milliseconds.
+     *
+     * @since Ant 1.5
+     */
+    public void setTimeout(Long value) {
+        timeout = value;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the timeout in milliseconds after which the process will be killed.
+     *
+     * @param value timeout in milliseconds.
+     */
+    public void setTimeout(Integer value) {
+        setTimeout(
+            (Long) ((value == null) ? null : new Long(value.intValue())));
+    }
+
+    /**
+     * Set the name of the executable program.
+     * @param value the name of the executable program.
+     */
+    public void setExecutable(String value) {
+        this.executable = value;
+        cmdl.setExecutable(value);
+    }
+
+    /**
+     * Set the working directory of the process.
+     * @param d the working directory of the process.
+     */
+    public void setDir(File d) {
+        this.dir = d;
+    }
+
+    /**
+     * List of operating systems on which the command may be executed.
+     * @param os list of operating systems on which the command may be executed.
+     */
+    public void setOs(String os) {
+        this.os = os;
+    }
+
+    /**
+     * Sets a command line.
+     * @param cmdl command line.
+     * @ant.attribute ignore="true"
+     */
+    public void setCommand(Commandline cmdl) {
+        log("The command attribute is deprecated.\n"
+            + "Please use the executable attribute and nested arg elements.",
+            Project.MSG_WARN);
+        this.cmdl = cmdl;
+    }
+
+    /**
+     * File the output of the process is redirected to. If error is not
+     * redirected, it too will appear in the output.
+     *
+     * @param out name of a file to which output should be sent.
+     */
+    public void setOutput(File out) {
+        this.output = out;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the input file to use for the task.
+     *
+     * @param input name of a file from which to get input.
+     */
+    public void setInput(File input) {
+        if (inputString != null) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        this.input = input;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the string to use as input.
+     *
+     * @param inputString the string which is used as the input source.
+     */
+    public void setInputString(String inputString) {
+        if (input != null) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        this.inputString = inputString;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Controls whether error output of exec is logged. This is only useful when
+     * output is being redirected and error output is desired in the Ant log.
+     *
+     * @param logError set to true to log error output in the normal ant log.
+     */
+    public void setLogError(boolean logError) {
+        redirector.setLogError(logError);
+        incompatibleWithSpawn |= logError;
+    }
+
+    /**
+     * Set the File to which the error stream of the process should be redirected.
+     *
+     * @param error a file to which stderr should be sent.
+     *
+     * @since Ant 1.6
+     */
+    public void setError(File error) {
+        this.error = error;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Sets the property name whose value should be set to the output of
+     * the process.
+     *
+     * @param outputProp name of property.
+     */
+    public void setOutputproperty(String outputProp) {
+        redirector.setOutputProperty(outputProp);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Sets the name of the property whose value should be set to the error of
+     * the process.
+     *
+     * @param errorProperty name of property.
+     *
+     * @since Ant 1.6
+     */
+    public void setErrorProperty(String errorProperty) {
+        redirector.setErrorProperty(errorProperty);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Fail if the command exits with a non-zero return code.
+     *
+     * @param fail if true fail the command on non-zero return code.
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+        incompatibleWithSpawn |= fail;
+    }
+
+    /**
+     * Do not propagate old environment when new environment variables are specified.
+     *
+     * @param newenv if true, do not propagate old environment
+     * when new environment variables are specified.
+     */
+    public void setNewenvironment(boolean newenv) {
+        newEnvironment = newenv;
+    }
+
+    /**
+     * Set whether to attempt to resolve the executable to a file.
+     *
+     * @param resolveExecutable if true, attempt to resolve the
+     * path of the executable.
+     */
+    public void setResolveExecutable(boolean resolveExecutable) {
+        this.resolveExecutable = resolveExecutable;
+    }
+
+    /**
+     * Set whether to search nested, then
+     * system PATH environment variables for the executable.
+     *
+     * @param searchPath if true, search PATHs.
+     */
+    public void setSearchPath(boolean searchPath) {
+        this.searchPath = searchPath;
+    }
+
+    /**
+     * Indicates whether to attempt to resolve the executable to a
+     * file.
+     * @return the resolveExecutable flag
+     *
+     * @since Ant 1.6
+     */
+    public boolean getResolveExecutable() {
+        return resolveExecutable;
+    }
+
+    /**
+     * Add an environment variable to the launched process.
+     *
+     * @param var new environment variable.
+     */
+    public void addEnv(Environment.Variable var) {
+        env.addVariable(var);
+    }
+
+    /**
+     * Adds a command-line argument.
+     *
+     * @return new command line argument created.
+     */
+    public Commandline.Argument createArg() {
+        return cmdl.createArgument();
+    }
+
+    /**
+     * Sets the name of a property in which the return code of the
+     * command should be stored. Only of interest if failonerror=false.
+     *
+     * @since Ant 1.5
+     *
+     * @param resultProperty name of property.
+     */
+    public void setResultProperty(String resultProperty) {
+        this.resultProperty = resultProperty;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Helper method to set result property to the
+     * passed in value if appropriate.
+     *
+     * @param result value desired for the result property value.
+     */
+    protected void maybeSetResultPropertyValue(int result) {
+        if (resultProperty != null) {
+            String res = Integer.toString(result);
+            getProject().setNewProperty(resultProperty, res);
+        }
+    }
+
+    /**
+     * Set whether to stop the build if program cannot be started.
+     * Defaults to true.
+     *
+     * @param flag stop the build if program cannot be started.
+     *
+     * @since Ant 1.5
+     */
+    public void setFailIfExecutionFails(boolean flag) {
+        failIfExecFails = flag;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set whether output should be appended to or overwrite an existing file.
+     * Defaults to false.
+     *
+     * @param append if true append is desired.
+     *
+     * @since 1.30, Ant 1.5
+     */
+    public void setAppend(boolean append) {
+        redirector.setAppend(append);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Add a <code>RedirectorElement</code> to this task.
+     *
+     * @param redirectorElement   <code>RedirectorElement</code>.
+     * @since Ant 1.6.2
+     */
+    public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+        if (this.redirectorElement != null) {
+            throw new BuildException("cannot have > 1 nested <redirector>s");
+        }
+        this.redirectorElement = redirectorElement;
+        incompatibleWithSpawn = true;
+    }
+
+
+    /**
+     * Restrict this execution to a single OS Family
+     * @param osFamily the family to restrict to.
+     */
+    public void setOsFamily(String osFamily) {
+        this.osFamily = osFamily.toLowerCase(Locale.US);
+    }
+
+
+    /**
+     * The method attempts to figure out where the executable is so that we can feed
+     * the full path. We first try basedir, then the exec dir, and then
+     * fallback to the straight executable name (i.e. on the path).
+     *
+     * @param exec the name of the executable.
+     * @param mustSearchPath if true, the executable will be looked up in
+     * the PATH environment and the absolute path is returned.
+     *
+     * @return the executable as a full path if it can be determined.
+     *
+     * @since Ant 1.6
+     */
+    protected String resolveExecutable(String exec, boolean mustSearchPath) {
+        if (!resolveExecutable) {
+            return exec;
+        }
+        // try to find the executable
+        File executableFile = getProject().resolveFile(exec);
+        if (executableFile.exists()) {
+            return executableFile.getAbsolutePath();
+        }
+        // now try to resolve against the dir if given
+        if (dir != null) {
+            executableFile = FILE_UTILS.resolveFile(dir, exec);
+            if (executableFile.exists()) {
+                return executableFile.getAbsolutePath();
+            }
+        }
+        // couldn't find it - must be on path
+        if (mustSearchPath) {
+            Path p = null;
+            String[] environment = env.getVariables();
+            if (environment != null) {
+                for (int i = 0; i < environment.length; i++) {
+                    if (isPath(environment[i])) {
+                        p = new Path(getProject(), getPath(environment[i]));
+                        break;
+                    }
+                }
+            }
+            if (p == null) {
+                Vector envVars = Execute.getProcEnvironment();
+                Enumeration e = envVars.elements();
+                while (e.hasMoreElements()) {
+                    String line = (String) e.nextElement();
+                    if (isPath(line)) {
+                        p = new Path(getProject(), getPath(line));
+                        break;
+                    }
+                }
+            }
+            if (p != null) {
+                String[] dirs = p.list();
+                for (int i = 0; i < dirs.length; i++) {
+                    executableFile
+                        = FILE_UTILS.resolveFile(new File(dirs[i]), exec);
+                    if (executableFile.exists()) {
+                        return executableFile.getAbsolutePath();
+                    }
+                }
+            }
+        }
+        // mustSearchPath is false, or no PATH or not found - keep our
+        // fingers crossed.
+        return exec;
+    }
+
+    /**
+     * Do the work.
+     *
+     * @throws BuildException in a number of circumstances:
+     * <ul>
+     * <li>if failIfExecFails is set to true and the process cannot be started</li>
+     * <li>the java13command launcher can send build exceptions</li>
+     * <li>this list is not exhaustive or limitative</li>
+     * </ul>
+     */
+    public void execute() throws BuildException {
+        // Quick fail if this is not a valid OS for the command
+        if (!isValidOs()) {
+            return;
+        }
+        File savedDir = dir; // possibly altered in prepareExec
+        cmdl.setExecutable(resolveExecutable(executable, searchPath));
+        checkConfiguration();
+        try {
+            runExec(prepareExec());
+        } finally {
+            dir = savedDir;
+        }
+    }
+
+    /**
+     * Has the user set all necessary attributes?
+     * @throws BuildException if there are missing required parameters.
+     */
+    protected void checkConfiguration() throws BuildException {
+        if (cmdl.getExecutable() == null) {
+            throw new BuildException("no executable specified", getLocation());
+        }
+        if (dir != null && !dir.exists()) {
+            throw new BuildException("The directory " + dir + " does not exist");
+        }
+        if (dir != null && !dir.isDirectory()) {
+            throw new BuildException(dir + " is not a directory");
+        }
+        if (spawn && incompatibleWithSpawn) {
+            getProject().log("spawn does not allow attributes related to input, "
+            + "output, error, result", Project.MSG_ERR);
+            getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
+            getProject().log("finally, spawn is not compatible "
+                + "with a nested I/O <redirector>", Project.MSG_ERR);
+            throw new BuildException("You have used an attribute "
+                + "or nested element which is not compatible with spawn");
+        }
+        setupRedirector();
+    }
+
+    /**
+     * Set up properties on the redirector that we needed to store locally.
+     */
+    protected void setupRedirector() {
+        redirector.setInput(input);
+        redirector.setInputString(inputString);
+        redirector.setOutput(output);
+        redirector.setError(error);
+    }
+
+    /**
+     * Is this the OS the user wanted?
+     * @return boolean.
+     * <ul>
+     * <li>
+     * <li><code>true</code> if the os and osfamily attributes are null.</li>
+     * <li><code>true</code> if osfamily is set, and the os family and must match
+     * that of the current OS, according to the logic of
+     * {@link Os#isOs(String, String, String, String)}, and the result of the
+     * <code>os</code> attribute must also evaluate true.
+     * </li>
+     * <li>
+     * <code>true</code> if os is set, and the system.property os.name
+     * is found in the os attribute,</li>
+     * <li><code>false</code> otherwise.</li>
+     * </ul>
+     */
+    protected boolean isValidOs() {
+        //hand osfamily off to Os class, if set
+        if (osFamily != null && !Os.isOs(osFamily, null, null, null)) {
+            return false;
+        }
+        //the Exec OS check is different from Os.isOs(), which
+        //probes for a specific OS. Instead it searches the os field
+        //for the current os.name
+        String myos = System.getProperty("os.name");
+        log("Current OS is " + myos, Project.MSG_VERBOSE);
+        if ((os != null) && (os.indexOf(myos) < 0)) {
+            // this command will be executed only on the specified OS
+            log("This OS, " + myos
+                    + " was not found in the specified list of valid OSes: " + os,
+                    Project.MSG_VERBOSE);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set whether to launch new process with VM, otherwise use the OS's shell.
+     * Default value is true.
+     * @param vmLauncher true if we want to launch new process with VM,
+     * false if we want to use the OS's shell.
+     */
+    public void setVMLauncher(boolean vmLauncher) {
+        this.vmLauncher = vmLauncher;
+    }
+
+    /**
+     * Create an Execute instance with the correct working directory set.
+     *
+     * @return an instance of the Execute class.
+     *
+     * @throws BuildException under unknown circumstances.
+     */
+    protected Execute prepareExec() throws BuildException {
+        // default directory to the project's base directory
+        if (dir == null) {
+            dir = getProject().getBaseDir();
+        }
+        if (redirectorElement != null) {
+            redirectorElement.configure(redirector);
+        }
+        Execute exe = new Execute(createHandler(), createWatchdog());
+        exe.setAntRun(getProject());
+        exe.setWorkingDirectory(dir);
+        exe.setVMLauncher(vmLauncher);
+        exe.setSpawn(spawn);
+        String[] environment = env.getVariables();
+        if (environment != null) {
+            for (int i = 0; i < environment.length; i++) {
+                log("Setting environment variable: " + environment[i],
+                    Project.MSG_VERBOSE);
+            }
+        }
+        exe.setNewenvironment(newEnvironment);
+        exe.setEnvironment(environment);
+        return exe;
+    }
+
+    /**
+     * A Utility method for this classes and subclasses to run an
+     * Execute instance (an external command).
+     *
+     * @param exe instance of the execute class.
+     *
+     * @throws IOException in case of problem to attach to the stdin/stdout/stderr
+     * streams of the process.
+     */
+    protected final void runExecute(Execute exe) throws IOException {
+        int returnCode = -1; // assume the worst
+
+        if (!spawn) {
+            returnCode = exe.execute();
+
+            //test for and handle a forced process death
+            if (exe.killedProcess()) {
+                String msg = "Timeout: killed the sub-process";
+                if (failOnError) {
+                    throw new BuildException(msg);
+                } else {
+                    log(msg, Project.MSG_WARN);
+                }
+            }
+            maybeSetResultPropertyValue(returnCode);
+            redirector.complete();
+            if (Execute.isFailure(returnCode)) {
+                if (failOnError) {
+                    throw new BuildException(getTaskType() + " returned: "
+                        + returnCode, getLocation());
+                } else {
+                    log("Result: " + returnCode, Project.MSG_ERR);
+                }
+            }
+        } else {
+            exe.spawn();
+        }
+    }
+
+    /**
+     * Run the command using the given Execute instance. This may be
+     * overridden by subclasses.
+     *
+     * @param exe instance of Execute to run.
+     *
+     * @throws BuildException if the new process could not be started
+     * only if failIfExecFails is set to true (the default).
+     */
+    protected void runExec(Execute exe) throws BuildException {
+        // show the command
+        log(cmdl.describeCommand(), Project.MSG_VERBOSE);
+
+        exe.setCommandline(cmdl.getCommandline());
+        try {
+            runExecute(exe);
+        } catch (IOException e) {
+            if (failIfExecFails) {
+                throw new BuildException("Execute failed: " + e.toString(), e,
+                                         getLocation());
+            } else {
+                log("Execute failed: " + e.toString(), Project.MSG_ERR);
+            }
+        } finally {
+            // close the output file if required
+            logFlush();
+        }
+    }
+
+    /**
+     * Create the StreamHandler to use with our Execute instance.
+     *
+     * @return instance of ExecuteStreamHandler.
+     *
+     * @throws BuildException under unknown circumstances.
+     */
+    protected ExecuteStreamHandler createHandler() throws BuildException {
+        return redirector.createHandler();
+    }
+
+    /**
+     * Create the Watchdog to kill a runaway process.
+     *
+     * @return instance of ExecuteWatchdog.
+     *
+     * @throws BuildException under unknown circumstances.
+     */
+    protected ExecuteWatchdog createWatchdog() throws BuildException {
+        return (timeout == null)
+            ? null : new ExecuteWatchdog(timeout.longValue());
+    }
+
+    /**
+     * Flush the output stream - if there is one.
+     */
+    protected void logFlush() {
+    }
+
+    private boolean isPath(String line) {
+        return line.startsWith("PATH=")
+            || line.startsWith("Path=");
+    }
+
+    private String getPath(String line) {
+        return line.substring("PATH=".length());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Execute.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Execute.java
new file mode 100644
index 0000000..da5dce0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Execute.java
@@ -0,0 +1,1239 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Runs an external program.
+ *
+ * @since Ant 1.2
+ *
+ */
+public class Execute {
+
+    private static final int ONE_SECOND = 1000;
+
+    /** Invalid exit code.
+     * set to {@link Integer#MAX_VALUE}
+     */
+    public static final int INVALID = Integer.MAX_VALUE;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private String[] cmdl = null;
+    private String[] env = null;
+    private int exitValue = INVALID;
+    private ExecuteStreamHandler streamHandler;
+    private ExecuteWatchdog watchdog;
+    private File workingDirectory = null;
+    private Project project = null;
+    private boolean newEnvironment = false;
+    //TODO: nothing appears to read this but is set using a public setter.
+    private boolean spawn = false;
+
+
+    /** Controls whether the VM is used to launch commands, where possible. */
+    private boolean useVMLauncher = true;
+
+    private static String antWorkingDirectory = System.getProperty("user.dir");
+    private static CommandLauncher vmLauncher = null;
+    private static CommandLauncher shellLauncher = null;
+    private static Vector procEnvironment = null;
+
+    /** Used to destroy processes when the VM exits. */
+    private static ProcessDestroyer processDestroyer = new ProcessDestroyer();
+
+    /** Used for replacing env variables */
+    private static boolean environmentCaseInSensitive = false;
+
+    /*
+     * Builds a command launcher for the OS and JVM we are running under.
+     */
+    static {
+        // Try using a JDK 1.3 launcher
+        try {
+            if (!Os.isFamily("os/2")) {
+                vmLauncher = new Java13CommandLauncher();
+            }
+        } catch (NoSuchMethodException exc) {
+            // Ignore and keep trying
+        }
+        if (Os.isFamily("mac") && !Os.isFamily("unix")) {
+            // Mac
+            shellLauncher = new MacCommandLauncher(new CommandLauncher());
+        } else if (Os.isFamily("os/2")) {
+            // OS/2
+            shellLauncher = new OS2CommandLauncher(new CommandLauncher());
+        } else if (Os.isFamily("windows")) {
+            environmentCaseInSensitive = true;
+            CommandLauncher baseLauncher = new CommandLauncher();
+
+            if (!Os.isFamily("win9x")) {
+                // Windows XP/2000/NT
+                shellLauncher = new WinNTCommandLauncher(baseLauncher);
+            } else {
+                // Windows 98/95 - need to use an auxiliary script
+                shellLauncher
+                    = new ScriptCommandLauncher("bin/antRun.bat", baseLauncher);
+            }
+        } else if (Os.isFamily("netware")) {
+
+            CommandLauncher baseLauncher = new CommandLauncher();
+
+            shellLauncher
+                = new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher);
+        } else if (Os.isFamily("openvms")) {
+            // OpenVMS
+            try {
+                shellLauncher = new VmsCommandLauncher();
+            } catch (NoSuchMethodException exc) {
+            // Ignore and keep trying
+            }
+        } else {
+            // Generic
+            shellLauncher = new ScriptCommandLauncher("bin/antRun",
+                new CommandLauncher());
+        }
+    }
+
+    /**
+     * Set whether or not you want the process to be spawned.
+     * Default is not spawned.
+     *
+     * @param spawn if true you do not want Ant
+     *              to wait for the end of the process.
+     *
+     * @since Ant 1.6
+     */
+    public void setSpawn(boolean spawn) {
+        this.spawn = spawn;
+    }
+
+    /**
+     * Find the list of environment variables for this process.
+     *
+     * @return a vector containing the environment variables.
+     * The vector elements are strings formatted like variable = value.
+     */
+    public static synchronized Vector getProcEnvironment() {
+        if (procEnvironment != null) {
+            return procEnvironment;
+        }
+        procEnvironment = new Vector();
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            Execute exe = new Execute(new PumpStreamHandler(out));
+            exe.setCommandline(getProcEnvCommand());
+            // Make sure we do not recurse forever
+            exe.setNewenvironment(true);
+            int retval = exe.execute();
+            if (retval != 0) {
+                // Just try to use what we got
+            }
+            BufferedReader in =
+                new BufferedReader(new StringReader(toString(out)));
+
+            if (Os.isFamily("openvms")) {
+                procEnvironment = addVMSLogicals(procEnvironment, in);
+                return procEnvironment;
+            }
+            String var = null;
+            String line, lineSep = StringUtils.LINE_SEP;
+            while ((line = in.readLine()) != null) {
+                if (line.indexOf('=') == -1) {
+                    // Chunk part of previous env var (UNIX env vars can
+                    // contain embedded new lines).
+                    if (var == null) {
+                        var = lineSep + line;
+                    } else {
+                        var += lineSep + line;
+                    }
+                } else {
+                    // New env var...append the previous one if we have it.
+                    if (var != null) {
+                        procEnvironment.addElement(var);
+                    }
+                    var = line;
+                }
+            }
+            // Since we "look ahead" before adding, there's one last env var.
+            if (var != null) {
+                procEnvironment.addElement(var);
+            }
+        } catch (java.io.IOException exc) {
+            exc.printStackTrace();
+            // Just try to see how much we got
+        }
+        return procEnvironment;
+    }
+
+    /**
+     * This is the operation to get our environment.
+     * It is a notorious troublespot pre-Java1.5, and should be approached
+     * with extreme caution.
+     * @return
+     */
+    private static String[] getProcEnvCommand() {
+        if (Os.isFamily("os/2")) {
+            // OS/2 - use same mechanism as Windows 2000
+            return new String[] {"cmd", "/c", "set" };
+        } else if (Os.isFamily("windows")) {
+            // Determine if we're running under XP/2000/NT or 98/95
+            if (Os.isFamily("win9x")) {
+                // Windows 98/95
+                return new String[] {"command.com", "/c", "set" };
+            } else {
+                // Windows XP/2000/NT/2003
+                return new String[] {"cmd", "/c", "set" };
+            }
+        } else if (Os.isFamily("z/os") || Os.isFamily("unix")) {
+            // On most systems one could use: /bin/sh -c env
+
+            // Some systems have /bin/env, others /usr/bin/env, just try
+            String[] cmd = new String[1];
+            if (new File("/bin/env").canRead()) {
+                cmd[0] = "/bin/env";
+            } else if (new File("/usr/bin/env").canRead()) {
+                cmd[0] = "/usr/bin/env";
+            } else {
+                // rely on PATH
+                cmd[0] = "env";
+            }
+            return cmd;
+        } else if (Os.isFamily("netware") || Os.isFamily("os/400")) {
+            // rely on PATH
+            return new String[] {"env"};
+        } else if (Os.isFamily("openvms")) {
+            return new String[] {"show", "logical"};
+        } else {
+            // MAC OS 9 and previous
+            //TODO: I have no idea how to get it, someone must fix it
+            return null;
+        }
+    }
+
+    /**
+     * ByteArrayOutputStream#toString doesn't seem to work reliably on
+     * OS/390, at least not the way we use it in the execution
+     * context.
+     *
+     * @param bos the output stream that one wants to read.
+     * @return the output stream as a string, read with
+     * special encodings in the case of z/os and os/400.
+     *
+     * @since Ant 1.5
+     */
+    public static String toString(ByteArrayOutputStream bos) {
+        if (Os.isFamily("z/os")) {
+            try {
+                return bos.toString("Cp1047");
+            } catch (java.io.UnsupportedEncodingException e) {
+                //noop default encoding used
+            }
+        } else if (Os.isFamily("os/400")) {
+            try {
+                return bos.toString("Cp500");
+            } catch (java.io.UnsupportedEncodingException e) {
+                //noop default encoding used
+            }
+        }
+        return bos.toString();
+    }
+
+    /**
+     * Creates a new execute object using <code>PumpStreamHandler</code> for
+     * stream handling.
+     */
+    public Execute() {
+        this(new PumpStreamHandler(), null);
+    }
+
+    /**
+     * Creates a new execute object.
+     *
+     * @param streamHandler the stream handler used to handle the input and
+     *        output streams of the subprocess.
+     */
+    public Execute(ExecuteStreamHandler streamHandler) {
+        this(streamHandler, null);
+    }
+
+    /**
+     * Creates a new execute object.
+     *
+     * @param streamHandler the stream handler used to handle the input and
+     *        output streams of the subprocess.
+     * @param watchdog a watchdog for the subprocess or <code>null</code> to
+     *        to disable a timeout for the subprocess.
+     */
+    public Execute(ExecuteStreamHandler streamHandler,
+                   ExecuteWatchdog watchdog) {
+        setStreamHandler(streamHandler);
+        this.watchdog = watchdog;
+        //By default, use the shell launcher for VMS
+        //
+        if (Os.isFamily("openvms")) {
+            useVMLauncher = false;
+        }
+    }
+
+    /**
+     * Set the stream handler to use.
+     * @param streamHandler ExecuteStreamHandler.
+     * @since Ant 1.6
+     */
+    public void setStreamHandler(ExecuteStreamHandler streamHandler) {
+        this.streamHandler = streamHandler;
+    }
+
+    /**
+     * Returns the commandline used to create a subprocess.
+     *
+     * @return the commandline used to create a subprocess.
+     */
+    public String[] getCommandline() {
+        return cmdl;
+    }
+
+    /**
+     * Sets the commandline of the subprocess to launch.
+     *
+     * @param commandline the commandline of the subprocess to launch.
+     */
+    public void setCommandline(String[] commandline) {
+        cmdl = commandline;
+    }
+
+    /**
+     * Set whether to propagate the default environment or not.
+     *
+     * @param newenv whether to propagate the process environment.
+     */
+    public void setNewenvironment(boolean newenv) {
+        newEnvironment = newenv;
+    }
+
+    /**
+     * Returns the environment used to create a subprocess.
+     *
+     * @return the environment used to create a subprocess.
+     */
+    public String[] getEnvironment() {
+        return (env == null || newEnvironment)
+            ? env : patchEnvironment();
+    }
+
+    /**
+     * Sets the environment variables for the subprocess to launch.
+     *
+     * @param env array of Strings, each element of which has
+     * an environment variable settings in format <em>key=value</em>.
+     */
+    public void setEnvironment(String[] env) {
+        this.env = env;
+    }
+
+    /**
+     * Sets the working directory of the process to execute.
+     *
+     * <p>This is emulated using the antRun scripts unless the OS is
+     * Windows NT in which case a cmd.exe is spawned,
+     * or MRJ and setting user.dir works, or JDK 1.3 and there is
+     * official support in java.lang.Runtime.
+     *
+     * @param wd the working directory of the process.
+     */
+    public void setWorkingDirectory(File wd) {
+        workingDirectory =
+            (wd == null || wd.getAbsolutePath().equals(antWorkingDirectory))
+            ? null : wd;
+    }
+
+    /**
+     * Return the working directory.
+     * @return the directory as a File.
+     * @since Ant 1.7
+     */
+    public File getWorkingDirectory() {
+        return workingDirectory == null ? new File(antWorkingDirectory)
+                                        : workingDirectory;
+    }
+
+    /**
+     * Set the name of the antRun script using the project's value.
+     *
+     * @param project the current project.
+     *
+     * @throws BuildException not clear when it is going to throw an exception, but
+     * it is the method's signature.
+     */
+    public void setAntRun(Project project) throws BuildException {
+        this.project = project;
+    }
+
+    /**
+     * Launch this execution through the VM, where possible, rather than through
+     * the OS's shell. In some cases and operating systems using the shell will
+     * allow the shell to perform additional processing such as associating an
+     * executable with a script, etc.
+     *
+     * @param useVMLauncher true if exec should launch through the VM,
+     *                   false if the shell should be used to launch the
+     *                   command.
+     */
+    public void setVMLauncher(boolean useVMLauncher) {
+        this.useVMLauncher = useVMLauncher;
+    }
+
+    /**
+     * Creates a process that runs a command.
+     *
+     * @param project the Project, only used for logging purposes, may be null.
+     * @param command the command to run.
+     * @param env the environment for the command.
+     * @param dir the working directory for the command.
+     * @param useVM use the built-in exec command for JDK 1.3 if available.
+     * @return the process started.
+     * @throws IOException forwarded from the particular launcher used.
+     *
+     * @since Ant 1.5
+     */
+    public static Process launch(Project project, String[] command,
+                                 String[] env, File dir, boolean useVM)
+        throws IOException {
+        if (dir != null && !dir.exists()) {
+            throw new BuildException(dir + " doesn't exist.");
+        }
+        CommandLauncher launcher
+            = ((useVM && vmLauncher != null) ? vmLauncher : shellLauncher);
+        return launcher.exec(project, command, env, dir);
+    }
+
+    /**
+     * Runs a process defined by the command line and returns its exit status.
+     *
+     * @return the exit status of the subprocess or <code>INVALID</code>.
+     * @exception java.io.IOException The exception is thrown, if launching
+     *            of the subprocess failed.
+     */
+    public int execute() throws IOException {
+        if (workingDirectory != null && !workingDirectory.exists()) {
+            throw new BuildException(workingDirectory + " doesn't exist.");
+        }
+        final Process process = launch(project, getCommandline(),
+                                       getEnvironment(), workingDirectory,
+                                       useVMLauncher);
+        try {
+            streamHandler.setProcessInputStream(process.getOutputStream());
+            streamHandler.setProcessOutputStream(process.getInputStream());
+            streamHandler.setProcessErrorStream(process.getErrorStream());
+        } catch (IOException e) {
+            process.destroy();
+            throw e;
+        }
+        streamHandler.start();
+
+        try {
+            // add the process to the list of those to destroy if the VM exits
+            //
+            processDestroyer.add(process);
+
+            if (watchdog != null) {
+                watchdog.start(process);
+            }
+            waitFor(process);
+
+            if (watchdog != null) {
+                watchdog.stop();
+            }
+            streamHandler.stop();
+            closeStreams(process);
+
+            if (watchdog != null) {
+                watchdog.checkException();
+            }
+            return getExitValue();
+        } catch (ThreadDeath t) {
+            // #31928: forcibly kill it before continuing.
+            process.destroy();
+            throw t;
+        } finally {
+            // remove the process to the list of those to destroy if
+            // the VM exits
+            //
+            processDestroyer.remove(process);
+        }
+    }
+
+    /**
+     * Starts a process defined by the command line.
+     * Ant will not wait for this process, nor log its output.
+     *
+     * @throws java.io.IOException The exception is thrown, if launching
+     *            of the subprocess failed.
+     * @since Ant 1.6
+     */
+    public void spawn() throws IOException {
+        if (workingDirectory != null && !workingDirectory.exists()) {
+            throw new BuildException(workingDirectory + " doesn't exist.");
+        }
+        final Process process = launch(project, getCommandline(),
+                                       getEnvironment(), workingDirectory,
+                                       useVMLauncher);
+        if (Os.isFamily("windows")) {
+            try {
+                Thread.sleep(ONE_SECOND);
+            } catch (InterruptedException e) {
+                project.log("interruption in the sleep after having spawned a"
+                            + " process", Project.MSG_VERBOSE);
+            }
+        }
+        OutputStream dummyOut = new OutputStream() {
+            public void write(int b) throws IOException {
+            }
+        };
+
+        ExecuteStreamHandler handler = new PumpStreamHandler(dummyOut);
+        handler.setProcessErrorStream(process.getErrorStream());
+        handler.setProcessOutputStream(process.getInputStream());
+        handler.start();
+        process.getOutputStream().close();
+
+        project.log("spawned process " + process.toString(),
+                    Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Wait for a given process.
+     *
+     * @param process the process one wants to wait for.
+     */
+    protected void waitFor(Process process) {
+        try {
+            process.waitFor();
+            setExitValue(process.exitValue());
+        } catch (InterruptedException e) {
+            process.destroy();
+        }
+    }
+
+    /**
+     * Set the exit value.
+     *
+     * @param value exit value of the process.
+     */
+    protected void setExitValue(int value) {
+        exitValue = value;
+    }
+
+    /**
+     * Query the exit value of the process.
+     * @return the exit value or Execute.INVALID if no exit value has
+     * been received.
+     */
+    public int getExitValue() {
+        return exitValue;
+    }
+
+    /**
+     * Checks whether <code>exitValue</code> signals a failure on the current
+     * system (OS specific).
+     *
+     * <p><b>Note</b> that this method relies on the conventions of
+     * the OS, it will return false results if the application you are
+     * running doesn't follow these conventions.  One notable
+     * exception is the Java VM provided by HP for OpenVMS - it will
+     * return 0 if successful (like on any other platform), but this
+     * signals a failure on OpenVMS.  So if you execute a new Java VM
+     * on OpenVMS, you cannot trust this method.</p>
+     *
+     * @param exitValue the exit value (return code) to be checked.
+     * @return <code>true</code> if <code>exitValue</code> signals a failure.
+     */
+    public static boolean isFailure(int exitValue) {
+        //on openvms even exit value signals failure;
+        // for other platforms nonzero exit value signals failure
+        return Os.isFamily("openvms")
+            ? (exitValue % 2 == 0) : (exitValue != 0);
+    }
+
+    /**
+     * Did this execute return in a failure.
+     * @see #isFailure(int)
+     * @return true if and only if the exit code is interpreted as a failure
+     * @since Ant1.7
+     */
+    public boolean isFailure() {
+        return isFailure(getExitValue());
+    }
+
+    /**
+     * Test for an untimely death of the process.
+     * @return true if a watchdog had to kill the process.
+     * @since Ant 1.5
+     */
+    public boolean killedProcess() {
+        return watchdog != null && watchdog.killedProcess();
+    }
+
+    /**
+     * Patch the current environment with the new values from the user.
+     * @return the patched environment.
+     */
+    private String[] patchEnvironment() {
+        // On OpenVMS Runtime#exec() doesn't support the environment array,
+        // so we only return the new values which then will be set in
+        // the generated DCL script, inheriting the parent process environment
+        if (Os.isFamily("openvms")) {
+            return env;
+        }
+        Vector osEnv = (Vector) getProcEnvironment().clone();
+        for (int i = 0; i < env.length; i++) {
+            String keyValue = env[i];
+            // Get key including "="
+            String key = keyValue.substring(0, keyValue.indexOf('=') + 1);
+            if (environmentCaseInSensitive) {
+                // Nb: using default locale as key is a env name
+                key = key.toLowerCase();
+            }
+            int size = osEnv.size();
+            // Find the key in the current enviroment copy
+            // and remove it.
+            for (int j = 0; j < size; j++) {
+                String osEnvItem = (String) osEnv.elementAt(j);
+                String convertedItem = environmentCaseInSensitive
+                    ? osEnvItem.toLowerCase() : osEnvItem;
+                if (convertedItem.startsWith(key)) {
+                    osEnv.removeElementAt(j);
+                    if (environmentCaseInSensitive) {
+                        // Use the original casiness of the key
+                        keyValue = osEnvItem.substring(0, key.length())
+                            + keyValue.substring(key.length());
+                    }
+                    break;
+                }
+            }
+            // Add the key to the enviromnent copy
+            osEnv.addElement(keyValue);
+        }
+        return (String[]) (osEnv.toArray(new String[osEnv.size()]));
+    }
+
+    /**
+     * A utility method that runs an external command.  Writes the output and
+     * error streams of the command to the project log.
+     *
+     * @param task      The task that the command is part of.  Used for logging
+     * @param cmdline   The command to execute.
+     *
+     * @throws BuildException if the command does not exit successfully.
+     */
+    public static void runCommand(Task task, String[] cmdline)
+        throws BuildException {
+        try {
+            task.log(Commandline.describeCommand(cmdline),
+                     Project.MSG_VERBOSE);
+            Execute exe = new Execute(
+                new LogStreamHandler(task, Project.MSG_INFO, Project.MSG_ERR));
+            exe.setAntRun(task.getProject());
+            exe.setCommandline(cmdline);
+            int retval = exe.execute();
+            if (isFailure(retval)) {
+                throw new BuildException(cmdline[0]
+                    + " failed with return code " + retval, task.getLocation());
+            }
+        } catch (java.io.IOException exc) {
+            throw new BuildException("Could not launch " + cmdline[0] + ": "
+                + exc, task.getLocation());
+        }
+    }
+
+    /**
+     * Close the streams belonging to the given Process.
+     * @param process   the <code>Process</code>.
+     */
+    public static void closeStreams(Process process) {
+        FileUtils.close(process.getInputStream());
+        FileUtils.close(process.getOutputStream());
+        FileUtils.close(process.getErrorStream());
+    }
+
+    /**
+     * This method is VMS specific and used by getProcEnvironment().
+     *
+     * Parses VMS logicals from <code>in</code> and adds them to
+     * <code>environment</code>.  <code>in</code> is expected to be the
+     * output of "SHOW LOGICAL".  The method takes care of parsing the output
+     * correctly as well as making sure that a logical defined in multiple
+     * tables only gets added from the highest order table.  Logicals with
+     * multiple equivalence names are mapped to a variable with multiple
+     * values separated by a comma (,).
+     */
+    private static Vector addVMSLogicals(Vector environment, BufferedReader in)
+        throws IOException {
+        HashMap logicals = new HashMap();
+        String logName = null, logValue = null, newLogName;
+        String line = null;
+        // CheckStyle:MagicNumber OFF
+        while ((line = in.readLine()) != null) {
+            // parse the VMS logicals into required format ("VAR=VAL[,VAL2]")
+            if (line.startsWith("\t=")) {
+                // further equivalence name of previous logical
+                if (logName != null) {
+                    logValue += "," + line.substring(4, line.length() - 1);
+                }
+            } else if (line.startsWith("  \"")) {
+                // new logical?
+                if (logName != null) {
+                    logicals.put(logName, logValue);
+                }
+                int eqIndex = line.indexOf('=');
+                newLogName = line.substring(3, eqIndex - 2);
+                if (logicals.containsKey(newLogName)) {
+                    // already got this logical from a higher order table
+                    logName = null;
+                } else {
+                    logName = newLogName;
+                    logValue = line.substring(eqIndex + 3, line.length() - 1);
+                }
+            }
+        }
+        // CheckStyle:MagicNumber ON
+        // Since we "look ahead" before adding, there's one last env var.
+        if (logName != null) {
+            logicals.put(logName, logValue);
+        }
+        for (Iterator i = logicals.keySet().iterator(); i.hasNext();) {
+            String logical = (String) i.next();
+            environment.add(logical + "=" + logicals.get(logical));
+        }
+        return environment;
+    }
+
+    /**
+     * A command launcher for a particular JVM/OS platform.  This class is
+     * a general purpose command launcher which can only launch commands in
+     * the current working directory.
+     */
+    private static class CommandLauncher {
+        /**
+         * Launches the given command in a new process.
+         *
+         * @param project       The project that the command is part of.
+         * @param cmd           The command to execute.
+         * @param env           The environment for the new process.  If null,
+         *                      the environment of the current process is used.
+         * @return the created Process.
+         * @throws IOException if attempting to run a command in a
+         * specific directory.
+         */
+        public Process exec(Project project, String[] cmd, String[] env)
+             throws IOException {
+            if (project != null) {
+                project.log("Execute:CommandLauncher: "
+                    + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
+            }
+            return Runtime.getRuntime().exec(cmd, env);
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         *
+         * @param project       The project that the command is part of.
+         * @param cmd           The command to execute.
+         * @param env           The environment for the new process.  If null,
+         *                      the environment of the current process is used.
+         * @param workingDir    The directory to start the command in.  If null,
+         *                      the current directory is used.
+         * @return the created Process.
+         * @throws IOException  if trying to change directory.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            if (workingDir == null) {
+                return exec(project, cmd, env);
+            }
+            throw new IOException("Cannot execute a process in different "
+                + "directory under this JVM");
+        }
+    }
+
+    /**
+     * A command launcher for JDK/JRE 1.3 (and higher).  Uses the built-in
+     * Runtime.exec() command.
+     */
+    private static class Java13CommandLauncher extends CommandLauncher {
+        private Method myExecWithCWD;
+
+        public Java13CommandLauncher() throws NoSuchMethodException {
+            // Locate method Runtime.exec(String[] cmdarray,
+            //                            String[] envp, File dir)
+            myExecWithCWD = Runtime.class.getMethod("exec",
+                new Class[] {String[].class, String[].class, File.class});
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir the working directory where the command
+         * should run.
+         * @return the created Process.
+         * @throws IOException probably forwarded from Runtime#exec.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            try {
+                if (project != null) {
+                    project.log("Execute:Java13CommandLauncher: "
+                        + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
+                }
+                return (Process) myExecWithCWD.invoke(Runtime.getRuntime(),
+                   /* the arguments: */ new Object[] {cmd, env, workingDir});
+            } catch (InvocationTargetException exc) {
+                Throwable realexc = exc.getTargetException();
+                if (realexc instanceof ThreadDeath) {
+                    throw (ThreadDeath) realexc;
+                } else if (realexc instanceof IOException) {
+                    throw (IOException) realexc;
+                } else {
+                    throw new BuildException("Unable to execute command",
+                                             realexc);
+                }
+            } catch (Exception exc) {
+                // IllegalAccess, IllegalArgument, ClassCast
+                throw new BuildException("Unable to execute command", exc);
+            }
+        }
+    }
+
+    /**
+     * A command launcher that proxies another command launcher.
+     *
+     * Sub-classes override exec(args, env, workdir).
+     */
+    private static class CommandLauncherProxy extends CommandLauncher {
+        private CommandLauncher myLauncher;
+
+        CommandLauncherProxy(CommandLauncher launcher) {
+            myLauncher = launcher;
+        }
+
+        /**
+         * Launches the given command in a new process.  Delegates this
+         * method to the proxied launcher.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env)
+            throws IOException {
+            return myLauncher.exec(project, cmd, env);
+        }
+    }
+
+    /**
+     * A command launcher for OS/2 that uses 'cmd.exe' when launching
+     * commands in directories other than the current working
+     * directory.
+     *
+     * <p>Unlike Windows NT and friends, OS/2's cd doesn't support the
+     * /d switch to change drives and directories in one go.</p>
+     */
+    private static class OS2CommandLauncher extends CommandLauncherProxy {
+        OS2CommandLauncher(CommandLauncher launcher) {
+            super(launcher);
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            File commandDir = workingDir;
+            if (workingDir == null) {
+                if (project != null) {
+                    commandDir = project.getBaseDir();
+                } else {
+                    return exec(project, cmd, env);
+                }
+            }
+            // Use cmd.exe to change to the specified drive and
+            // directory before running the command
+            final int preCmdLength = 7;
+            final String cmdDir = commandDir.getAbsolutePath();
+            String[] newcmd = new String[cmd.length + preCmdLength];
+            // CheckStyle:MagicNumber OFF - do not bother
+            newcmd[0] = "cmd";
+            newcmd[1] = "/c";
+            newcmd[2] = cmdDir.substring(0, 2);
+            newcmd[3] = "&&";
+            newcmd[4] = "cd";
+            newcmd[5] = cmdDir.substring(2);
+            newcmd[6] = "&&";
+            // CheckStyle:MagicNumber ON
+            System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
+
+            return exec(project, newcmd, env);
+        }
+    }
+
+    /**
+     * A command launcher for Windows XP/2000/NT that uses 'cmd.exe' when
+     * launching commands in directories other than the current working
+     * directory.
+     */
+    private static class WinNTCommandLauncher extends CommandLauncherProxy {
+        WinNTCommandLauncher(CommandLauncher launcher) {
+            super(launcher);
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            File commandDir = workingDir;
+            if (workingDir == null) {
+                if (project != null) {
+                    commandDir = project.getBaseDir();
+                } else {
+                    return exec(project, cmd, env);
+                }
+            }
+            // Use cmd.exe to change to the specified directory before running
+            // the command
+            final int preCmdLength = 6;
+            String[] newcmd = new String[cmd.length + preCmdLength];
+            // CheckStyle:MagicNumber OFF - do not bother
+            newcmd[0] = "cmd";
+            newcmd[1] = "/c";
+            newcmd[2] = "cd";
+            newcmd[3] = "/d";
+            newcmd[4] = commandDir.getAbsolutePath();
+            newcmd[5] = "&&";
+            // CheckStyle:MagicNumber ON
+            System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
+
+            return exec(project, newcmd, env);
+        }
+    }
+
+    /**
+     * A command launcher for Mac that uses a dodgy mechanism to change
+     * working directory before launching commands.
+     */
+    private static class MacCommandLauncher extends CommandLauncherProxy {
+        MacCommandLauncher(CommandLauncher launcher) {
+            super(launcher);
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            if (workingDir == null) {
+                return exec(project, cmd, env);
+            }
+            System.getProperties().put("user.dir", workingDir.getAbsolutePath());
+            try {
+                return exec(project, cmd, env);
+            } finally {
+                System.getProperties().put("user.dir", antWorkingDirectory);
+            }
+        }
+    }
+
+    /**
+     * A command launcher that uses an auxiliary script to launch commands
+     * in directories other than the current working directory.
+     */
+    private static class ScriptCommandLauncher extends CommandLauncherProxy {
+        ScriptCommandLauncher(String script, CommandLauncher launcher) {
+            super(launcher);
+            myScript = script;
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            if (project == null) {
+                if (workingDir == null) {
+                    return exec(project, cmd, env);
+                }
+                throw new IOException("Cannot locate antRun script: "
+                    + "No project provided");
+            }
+            // Locate the auxiliary script
+            String antHome = project.getProperty(MagicNames.ANT_HOME);
+            if (antHome == null) {
+                throw new IOException("Cannot locate antRun script: "
+                    + "Property '" + MagicNames.ANT_HOME + "' not found");
+            }
+            String antRun =
+                FILE_UTILS.resolveFile(project.getBaseDir(),
+                        antHome + File.separator + myScript).toString();
+
+            // Build the command
+            File commandDir = workingDir;
+            if (workingDir == null) {
+                commandDir = project.getBaseDir();
+            }
+            String[] newcmd = new String[cmd.length + 2];
+            newcmd[0] = antRun;
+            newcmd[1] = commandDir.getAbsolutePath();
+            System.arraycopy(cmd, 0, newcmd, 2, cmd.length);
+
+            return exec(project, newcmd, env);
+        }
+
+        private String myScript;
+    }
+
+    /**
+     * A command launcher that uses an auxiliary perl script to launch commands
+     * in directories other than the current working directory.
+     */
+    private static class PerlScriptCommandLauncher
+        extends CommandLauncherProxy {
+        private String myScript;
+
+        PerlScriptCommandLauncher(String script, CommandLauncher launcher) {
+            super(launcher);
+            myScript = script;
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            if (project == null) {
+                if (workingDir == null) {
+                    return exec(project, cmd, env);
+                }
+                throw new IOException("Cannot locate antRun script: "
+                    + "No project provided");
+            }
+            // Locate the auxiliary script
+            String antHome = project.getProperty(MagicNames.ANT_HOME);
+            if (antHome == null) {
+                throw new IOException("Cannot locate antRun script: "
+                    + "Property '" + MagicNames.ANT_HOME + "' not found");
+            }
+            String antRun =
+                FILE_UTILS.resolveFile(project.getBaseDir(),
+                        antHome + File.separator + myScript).toString();
+
+            // Build the command
+            File commandDir = workingDir;
+            if (workingDir == null) {
+                commandDir = project.getBaseDir();
+            }
+            // CheckStyle:MagicNumber OFF
+            String[] newcmd = new String[cmd.length + 3];
+            newcmd[0] = "perl";
+            newcmd[1] = antRun;
+            newcmd[2] = commandDir.getAbsolutePath();
+            System.arraycopy(cmd, 0, newcmd, 3, cmd.length);
+            // CheckStyle:MagicNumber ON
+
+            return exec(project, newcmd, env);
+        }
+    }
+
+    /**
+     * A command launcher for VMS that writes the command to a temporary DCL
+     * script before launching commands.  This is due to limitations of both
+     * the DCL interpreter and the Java VM implementation.
+     */
+    private static class VmsCommandLauncher extends Java13CommandLauncher {
+
+        public VmsCommandLauncher() throws NoSuchMethodException {
+            super();
+        }
+
+        /**
+         * Launches the given command in a new process.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env)
+            throws IOException {
+            File cmdFile = createCommandFile(cmd, env);
+            Process p
+                = super.exec(project, new String[] {cmdFile.getPath()}, env);
+            deleteAfter(cmdFile, p);
+            return p;
+        }
+
+        /**
+         * Launches the given command in a new process, in the given working
+         * directory.  Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this
+         * method only works if <code>workingDir</code> is null or the logical
+         * JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
+         * @param project the Ant project.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @param workingDir working directory where the command should run.
+         * @return the created Process.
+         * @throws IOException forwarded from the exec method of the
+         * command launcher.
+         */
+        public Process exec(Project project, String[] cmd, String[] env,
+                            File workingDir) throws IOException {
+            File cmdFile = createCommandFile(cmd, env);
+            Process p = super.exec(project, new String[] {cmdFile.getPath()},
+                                   env, workingDir);
+            deleteAfter(cmdFile, p);
+            return p;
+        }
+
+        /*
+         * Writes the command into a temporary DCL script and returns the
+         * corresponding File object.  The script will be deleted on exit.
+         * @param cmd the command line to execute as an array of strings.
+         * @param env the environment to set as an array of strings.
+         * @return the command File.
+         * @throws IOException if errors are encountered creating the file.
+         */
+        private File createCommandFile(String[] cmd, String[] env)
+            throws IOException {
+            File script = FILE_UTILS.createTempFile("ANT", ".COM", null, true, true);
+            PrintWriter out = null;
+            try {
+                out = new PrintWriter(new FileWriter(script));
+
+                // add the environment as logicals to the DCL script
+                if (env != null) {
+                    int eqIndex;
+                    for (int i = 0; i < env.length; i++) {
+                        eqIndex = env[i].indexOf('=');
+                        if (eqIndex != -1) {
+                            out.print("$ DEFINE/NOLOG ");
+                            out.print(env[i].substring(0, eqIndex));
+                            out.print(" \"");
+                            out.print(env[i].substring(eqIndex + 1));
+                            out.println('\"');
+                        }
+                    }
+                }
+                out.print("$ " + cmd[0]);
+                for (int i = 1; i < cmd.length; i++) {
+                    out.println(" -");
+                    out.print(cmd[i]);
+                }
+            } finally {
+                if (out != null) {
+                    out.close();
+                }
+            }
+            return script;
+        }
+
+        private void deleteAfter(final File f, final Process p) {
+            new Thread() {
+                public void run() {
+                    try {
+                        p.waitFor();
+                    } catch (InterruptedException e) {
+                        //ignore
+                    }
+                    FileUtils.delete(f);
+                }
+            }
+            .start();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
new file mode 100644
index 0000000..6803eb8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
@@ -0,0 +1,330 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.TimeoutObserver;
+import org.apache.tools.ant.util.Watchdog;
+
+/**
+ * Execute a Java class.
+ * @since Ant 1.2
+ */
+public class ExecuteJava implements Runnable, TimeoutObserver {
+
+    private Commandline javaCommand = null;
+    private Path classpath = null;
+    private CommandlineJava.SysProperties sysProperties = null;
+    private Permissions  perm = null;
+    private Method main = null;
+    private Long timeout = null;
+    private volatile Throwable caught = null;
+    private volatile boolean timedOut = false;
+    private Thread thread = null;
+
+    /**
+     * Set the Java "command" for this ExecuteJava.
+     * @param javaCommand the classname and arguments in a Commandline.
+     */
+    public void setJavaCommand(Commandline javaCommand) {
+        this.javaCommand = javaCommand;
+    }
+
+    /**
+     * Set the classpath to be used when running the Java class.
+     *
+     * @param p an Ant Path object containing the classpath.
+     */
+    public void setClasspath(Path p) {
+        classpath = p;
+    }
+
+    /**
+     * Set the system properties to use when running the Java class.
+     * @param s CommandlineJava system properties.
+     */
+    public void setSystemProperties(CommandlineJava.SysProperties s) {
+        sysProperties = s;
+    }
+
+    /**
+     * Set the permissions for the application run.
+     * @param permissions the Permissions to use.
+     * @since Ant 1.6
+     */
+    public void setPermissions(Permissions permissions) {
+        perm = permissions;
+    }
+
+    /**
+     * Set the stream to which all output (System.out as well as System.err)
+     * will be written.
+     * @param out the PrintStream where output should be sent.
+     * @deprecated since 1.4.x.
+     *             manage output at the task level.
+     */
+    public void setOutput(PrintStream out) {
+    }
+
+    /**
+     * Set the timeout for this ExecuteJava.
+     * @param timeout timeout as Long.
+     * @since Ant 1.5
+     */
+    public void setTimeout(Long timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * Execute the Java class against the specified Ant Project.
+     * @param project the Project to use.
+     * @throws BuildException on error.
+     */
+    public void execute(Project project) throws BuildException {
+        final String classname = javaCommand.getExecutable();
+
+        AntClassLoader loader = null;
+        try {
+            if (sysProperties != null) {
+                sysProperties.setSystem();
+            }
+            Class target = null;
+            try {
+                if (classpath == null) {
+                    target = Class.forName(classname);
+                } else {
+                    loader = project.createClassLoader(classpath);
+                    loader.setParent(project.getCoreLoader());
+                    loader.setParentFirst(false);
+                    loader.addJavaLibraries();
+                    loader.setIsolated(true);
+                    loader.setThreadContextLoader();
+                    loader.forceLoadClass(classname);
+                    target = Class.forName(classname, true, loader);
+                }
+            } catch (ClassNotFoundException e) {
+                throw new BuildException("Could not find " + classname + "."
+                                         + " Make sure you have it in your"
+                                         + " classpath");
+            }
+            main = target.getMethod("main", new Class[] {String[].class});
+            if (main == null) {
+                throw new BuildException("Could not find main() method in "
+                                         + classname);
+            }
+            if ((main.getModifiers() & Modifier.STATIC) == 0) {
+                throw new BuildException("main() method in " + classname
+                    + " is not declared static");
+            }
+            if (timeout == null) {
+                run();
+            } else {
+                thread = new Thread(this, "ExecuteJava");
+                Task currentThreadTask
+                    = project.getThreadTask(Thread.currentThread());
+                // XXX is the following really necessary? it is in the same thread group...
+                project.registerThreadTask(thread, currentThreadTask);
+                // if we run into a timeout, the run-away thread shall not
+                // make the VM run forever - if no timeout occurs, Ant's
+                // main thread will still be there to let the new thread
+                // finish
+                thread.setDaemon(true);
+                Watchdog w = new Watchdog(timeout.longValue());
+                w.addTimeoutObserver(this);
+                synchronized (this) {
+                    thread.start();
+                    w.start();
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        // ignore
+                    }
+                    if (timedOut) {
+                        project.log("Timeout: sub-process interrupted",
+                                    Project.MSG_WARN);
+                    } else {
+                        thread = null;
+                        w.stop();
+                    }
+                }
+            }
+            if (caught != null) {
+                throw caught;
+            }
+        } catch (BuildException e) {
+            throw e;
+        } catch (SecurityException e) {
+            throw e;
+        } catch (ThreadDeath e) {
+            // XXX could perhaps also call thread.stop(); not sure if anyone cares
+            throw e;
+        } catch (Throwable e) {
+            throw new BuildException(e);
+        } finally {
+            if (loader != null) {
+                loader.resetThreadContextLoader();
+                loader.cleanup();
+                loader = null;
+            }
+            if (sysProperties != null) {
+                sysProperties.restoreSystem();
+            }
+        }
+    }
+
+    /**
+     * Run this ExecuteJava in a Thread.
+     * @since Ant 1.5
+     */
+    public void run() {
+        final Object[] argument = {javaCommand.getArguments()};
+        try {
+            if (perm != null) {
+                perm.setSecurityManager();
+            }
+            main.invoke(null, argument);
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if (!(t instanceof InterruptedException)) {
+                caught = t;
+            } /* else { swallow, probably due to timeout } */
+        } catch (Throwable t) {
+            caught = t;
+        } finally {
+            if (perm != null) {
+                perm.restoreSecurityManager();
+            }
+            synchronized (this) {
+                notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Mark timeout as having occurred.
+     * @param w the responsible Watchdog.
+     * @since Ant 1.5
+     */
+    public synchronized void timeoutOccured(Watchdog w) {
+        if (thread != null) {
+            timedOut = true;
+            thread.interrupt();
+        }
+        notifyAll();
+    }
+
+    /**
+     * Get whether the process was killed.
+     * @return <code>true</code> if the process was killed, false otherwise.
+     * @since 1.19, Ant 1.5
+     */
+    public synchronized boolean killedProcess() {
+        return timedOut;
+    }
+
+    /**
+     * Run the Java command in a separate VM, this does not give you
+     * the full flexibility of the Java task, but may be enough for
+     * simple needs.
+     * @param pc the ProjectComponent to use for logging, etc.
+     * @return the exit status of the subprocess.
+     * @throws BuildException on error.
+     * @since Ant 1.6.3
+     */
+    public int fork(ProjectComponent pc) throws BuildException {
+        CommandlineJava cmdl = new CommandlineJava();
+        cmdl.setClassname(javaCommand.getExecutable());
+        String[] args = javaCommand.getArguments();
+        for (int i = 0; i < args.length; i++) {
+            cmdl.createArgument().setValue(args[i]);
+        }
+        if (classpath != null) {
+            cmdl.createClasspath(pc.getProject()).append(classpath);
+        }
+        if (sysProperties != null) {
+            cmdl.addSysproperties(sysProperties);
+        }
+        Redirector redirector = new Redirector(pc);
+        Execute exe
+            = new Execute(redirector.createHandler(),
+                          timeout == null
+                          ? null
+                          : new ExecuteWatchdog(timeout.longValue()));
+        exe.setAntRun(pc.getProject());
+        if (Os.isFamily("openvms")) {
+            setupCommandLineForVMS(exe, cmdl.getCommandline());
+        } else {
+            exe.setCommandline(cmdl.getCommandline());
+        }
+        try {
+            int rc = exe.execute();
+            redirector.complete();
+            return rc;
+        } catch (IOException e) {
+            throw new BuildException(e);
+        } finally {
+            timedOut = exe.killedProcess();
+        }
+    }
+
+    /**
+     * On VMS platform, we need to create a special java options file
+     * containing the arguments and classpath for the java command.
+     * The special file is supported by the "-V" switch on the VMS JVM.
+     *
+     * @param exe the Execute instance to alter.
+     * @param command the command-line.
+     */
+    public static void setupCommandLineForVMS(Execute exe, String[] command) {
+        //Use the VM launcher instead of shell launcher on VMS
+        exe.setVMLauncher(true);
+        File vmsJavaOptionFile = null;
+        try {
+            String [] args = new String[command.length - 1];
+            System.arraycopy(command, 1, args, 0, command.length - 1);
+            vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args);
+            //we mark the file to be deleted on exit.
+            //the alternative would be to cache the filename and delete
+            //after execution finished, which is much better for long-lived runtimes
+            //though spawning complicates things...
+            vmsJavaOptionFile.deleteOnExit();
+            String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()};
+            exe.setCommandline(vmsCmd);
+        } catch (IOException e) {
+            throw new BuildException("Failed to create a temporary file for \"-V\" switch");
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
new file mode 100644
index 0000000..6e58e69
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteOn.java
@@ -0,0 +1,753 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.AbstractFileSet;
+import org.apache.tools.ant.types.DirSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileList;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+
+/**
+ * Executes a given command, supplying a set of files as arguments.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="control" name="apply"
+ */
+public class ExecuteOn extends ExecTask {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    // filesets has been protected so we need to keep that even after
+    // switching to resource collections.  In fact, they will still
+    // get a different treatment form the other resource collections
+    // even in execute since we have some subtle special features like
+    // switching type to "dir" when we encounter a DirSet that would
+    // be more difficult to achieve otherwise.
+
+    protected Vector filesets = new Vector(); // contains AbstractFileSet
+                                              // (both DirSet and FileSet)
+    private Union resources = null;
+    private boolean relative = false;
+    private boolean parallel = false;
+    private boolean forwardSlash = false;
+    protected String type = FileDirBoth.FILE;
+    protected Commandline.Marker srcFilePos = null;
+    private boolean skipEmpty = false;
+    protected Commandline.Marker targetFilePos = null;
+    protected Mapper mapperElement = null;
+    protected FileNameMapper mapper = null;
+    protected File destDir = null;
+    private int maxParallel = -1;
+    private boolean addSourceFile = true;
+    private boolean verbose = false;
+    private boolean ignoreMissing = true;
+    private boolean force = false;
+
+    /**
+     * Has &lt;srcfile&gt; been specified before &lt;targetfile&gt;
+     */
+    protected boolean srcIsFirst = true;
+
+    // CheckStyle:VisibilityModifier ON
+    /**
+     * Add a set of files upon which to operate.
+     * @param set the FileSet to add.
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Add a set of directories upon which to operate.
+     *
+     * @param  set the DirSet to add.
+     *
+     * @since Ant 1.6
+     */
+    public void addDirset(DirSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Add a list of source files upon which to operate.
+     * @param list the FileList to add.
+     */
+    public void addFilelist(FileList list) {
+        add(list);
+    }
+
+    /**
+     * Add a collection of resources upon which to operate.
+     * @param rc resource collection to add.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        if (resources == null) {
+            resources = new Union();
+        }
+        resources.add(rc);
+    }
+
+    /**
+     * Set whether the filenames should be passed on the command line as
+     * absolute or relative pathnames. Paths are relative to the base
+     * directory of the corresponding fileset for source files or the
+     * dest attribute for target files.
+     * @param relative whether to pass relative pathnames.
+     */
+    public void setRelative(boolean relative) {
+        this.relative = relative;
+    }
+
+
+    /**
+     * Set whether to execute in parallel mode.
+     * If true, run the command only once, appending all files as arguments.
+     * If false, command will be executed once for every file. Defaults to false.
+     * @param parallel whether to run in parallel.
+     */
+    public void setParallel(boolean parallel) {
+        this.parallel = parallel;
+    }
+
+    /**
+     * Set whether the command works only on files, directories or both.
+     * @param type a FileDirBoth EnumeratedAttribute.
+     */
+    public void setType(FileDirBoth type) {
+        this.type = type.getValue();
+    }
+
+    /**
+     * Set whether empty filesets will be skipped.  If true and
+     * no source files have been found or are newer than their
+     * corresponding target files, the command will not be run.
+     * @param skip whether to skip empty filesets.
+     */
+    public void setSkipEmptyFilesets(boolean skip) {
+        skipEmpty = skip;
+    }
+
+    /**
+     * Specify the directory where target files are to be placed.
+     * @param destDir the File object representing the destination directory.
+     */
+    public void setDest(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Set whether the source and target file names on Windows and OS/2
+     * must use the forward slash as file separator.
+     * @param forwardSlash whether the forward slash will be forced.
+     */
+    public void setForwardslash(boolean forwardSlash) {
+        this.forwardSlash = forwardSlash;
+    }
+
+    /**
+     * Limit the command line length by passing at maximum this many
+     * sourcefiles at once to the command.
+     *
+     * <p>Set to &lt;= 0 for unlimited - this is the default.</p>
+     *
+     * @param max <code>int</code> maximum number of sourcefiles
+     *            passed to the executable.
+     *
+     * @since Ant 1.6
+     */
+    public void setMaxParallel(int max) {
+        maxParallel = max;
+    }
+
+    /**
+     * Set whether to send the source file name on the command line.
+     *
+     * <p>Defaults to <code>true</code>.
+     *
+     * @param b whether to add the source file to the command line.
+     *
+     * @since Ant 1.6
+     */
+    public void setAddsourcefile(boolean b) {
+        addSourceFile = b;
+    }
+
+    /**
+     * Set whether to operate in verbose mode.
+     * If true, a verbose summary will be printed after execution.
+     * @param b whether to operate in verbose mode.
+     *
+     * @since Ant 1.6
+     */
+    public void setVerbose(boolean b) {
+        verbose = b;
+    }
+
+    /**
+     * Set whether to ignore nonexistent files from filelists.
+     * @param b whether to ignore missing files.
+     *
+     * @since Ant 1.6.2
+     */
+    public void setIgnoremissing(boolean b) {
+        ignoreMissing = b;
+    }
+
+    /**
+     * Set whether to bypass timestamp comparisons for target files.
+     * @param b whether to bypass timestamp comparisons.
+     *
+     * @since Ant 1.6.3
+     */
+    public void setForce(boolean b) {
+        force = b;
+    }
+
+    /**
+     * Create a placeholder indicating where on the command line
+     * the name of the source file should be inserted.
+     * @return <code>Commandline.Marker</code>.
+     */
+    public Commandline.Marker createSrcfile() {
+        if (srcFilePos != null) {
+            throw new BuildException(getTaskType() + " doesn\'t support multiple "
+                                     + "srcfile elements.", getLocation());
+        }
+        srcFilePos = cmdl.createMarker();
+        return srcFilePos;
+    }
+
+    /**
+     * Create a placeholder indicating where on the command line
+     * the name of the target file should be inserted.
+     * @return <code>Commandline.Marker</code>.
+     */
+    public Commandline.Marker createTargetfile() {
+        if (targetFilePos != null) {
+            throw new BuildException(getTaskType() + " doesn\'t support multiple "
+                                     + "targetfile elements.", getLocation());
+        }
+        targetFilePos = cmdl.createMarker();
+        srcIsFirst = (srcFilePos != null);
+        return targetFilePos;
+    }
+
+    /**
+     * Create a nested Mapper element to use for mapping
+     * source files to target files.
+     * @return <code>Mapper</code>.
+     * @throws BuildException if more than one mapper is defined.
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper",
+                                     getLocation());
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+    /**
+     * Add a nested FileNameMapper.
+     * @param fileNameMapper the mapper to add.
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+    /**
+     * Check the configuration of this ExecuteOn instance.
+     */
+    protected void checkConfiguration() {
+//     * @TODO using taskName here is brittle, as a user could override it.
+//     *       this should probably be modified to use the classname instead.
+        if ("execon".equals(getTaskName())) {
+            log("!! execon is deprecated. Use apply instead. !!");
+        }
+        super.checkConfiguration();
+        if (filesets.size() == 0 && resources == null) {
+            throw new BuildException("no resources specified",
+                                     getLocation());
+        }
+        if (targetFilePos != null && mapperElement == null) {
+            throw new BuildException("targetfile specified without mapper",
+                                     getLocation());
+        }
+        if (destDir != null && mapperElement == null) {
+            throw new BuildException("dest specified without mapper",
+                                     getLocation());
+        }
+        if (mapperElement != null) {
+            mapper = mapperElement.getImplementation();
+        }
+    }
+
+    /**
+     * Create the ExecuteStreamHandler instance that will be used
+     * during execution.
+     * @return <code>ExecuteStreamHandler</code>.
+     * @throws BuildException on error.
+     */
+    protected ExecuteStreamHandler createHandler() throws BuildException {
+        //if we have a RedirectorElement, return a decoy
+        return (redirectorElement == null)
+            ? super.createHandler() : new PumpStreamHandler();
+    }
+
+    /**
+     * Set up the I/O Redirector.
+     */
+    protected void setupRedirector() {
+        super.setupRedirector();
+        redirector.setAppendProperties(true);
+    }
+
+    /**
+     * Run the specified Execute object.
+     * @param exe the Execute instance representing the external process.
+     * @throws BuildException on error
+     */
+    protected void runExec(Execute exe) throws BuildException {
+        int totalFiles = 0;
+        int totalDirs = 0;
+        boolean haveExecuted = false;
+        try {
+            Vector fileNames = new Vector();
+            Vector baseDirs = new Vector();
+            for (int i = 0; i < filesets.size(); i++) {
+                String currentType = type;
+                AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i);
+                if (fs instanceof DirSet) {
+                    if (!FileDirBoth.DIR.equals(type)) {
+                        log("Found a nested dirset but type is " + type + ". "
+                            + "Temporarily switching to type=\"dir\" on the"
+                            + " assumption that you really did mean"
+                            + " <dirset> not <fileset>.", Project.MSG_DEBUG);
+                        currentType = FileDirBoth.DIR;
+                    }
+                }
+                File base = fs.getDir(getProject());
+
+                DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+
+                if (!FileDirBoth.DIR.equals(currentType)) {
+                    String[] s = getFiles(base, ds);
+                    for (int j = 0; j < s.length; j++) {
+                        totalFiles++;
+                        fileNames.addElement(s[j]);
+                        baseDirs.addElement(base);
+                    }
+                }
+                if (!FileDirBoth.FILE.equals(currentType)) {
+                    String[] s = getDirs(base, ds);
+                    for (int j = 0; j < s.length; j++) {
+                        totalDirs++;
+                        fileNames.addElement(s[j]);
+                        baseDirs.addElement(base);
+                    }
+                }
+                if (fileNames.size() == 0 && skipEmpty) {
+                    logSkippingFileset(currentType, ds, base);
+                    continue;
+                }
+                if (!parallel) {
+                    String[] s = new String[fileNames.size()];
+                    fileNames.copyInto(s);
+                    for (int j = 0; j < s.length; j++) {
+                        String[] command = getCommandline(s[j], base);
+                        log(Commandline.describeCommand(command),
+                            Project.MSG_VERBOSE);
+                        exe.setCommandline(command);
+
+                        if (redirectorElement != null) {
+                            setupRedirector();
+                            redirectorElement.configure(redirector, s[j]);
+                        }
+                        if (redirectorElement != null || haveExecuted) {
+                            // need to reset the stream handler to restart
+                            // reading of pipes;
+                            // go ahead and do it always w/ nested redirectors
+                            exe.setStreamHandler(redirector.createHandler());
+                        }
+                        runExecute(exe);
+                        haveExecuted = true;
+                    }
+                    fileNames.removeAllElements();
+                    baseDirs.removeAllElements();
+                }
+            }
+
+            if (resources != null) {
+                Iterator iter = resources.iterator();
+                while (iter.hasNext()) {
+                    Resource res = (Resource) iter.next();
+
+                    if (!res.isExists() && ignoreMissing) {
+                        continue;
+                    }
+
+                    File base = null;
+                    String name = res.getName();
+                    if (res instanceof FileResource) {
+                        FileResource fr = (FileResource) res;
+                        base = fr.getBaseDir();
+                        if (base == null) {
+                            name = fr.getFile().getAbsolutePath();
+                        }
+                    }
+
+                    if (restrict(new String[] {name}, base).length == 0) {
+                        continue;
+                    }
+
+                    if ((!res.isDirectory() || !res.isExists())
+                        && !FileDirBoth.DIR.equals(type)) {
+                        totalFiles++;
+                    } else if (res.isDirectory()
+                               && !FileDirBoth.FILE.equals(type)) {
+                        totalDirs++;
+                    } else {
+                        continue;
+                    }
+
+                    baseDirs.add(base);
+                    fileNames.add(name);
+
+                    if (!parallel) {
+                        String[] command = getCommandline(name, base);
+                        log(Commandline.describeCommand(command),
+                            Project.MSG_VERBOSE);
+                        exe.setCommandline(command);
+
+                        if (redirectorElement != null) {
+                            setupRedirector();
+                            redirectorElement.configure(redirector, name);
+                        }
+                        if (redirectorElement != null || haveExecuted) {
+                            // need to reset the stream handler to restart
+                            // reading of pipes;
+                            // go ahead and do it always w/ nested redirectors
+                            exe.setStreamHandler(redirector.createHandler());
+                        }
+                        runExecute(exe);
+                        haveExecuted = true;
+                        fileNames.removeAllElements();
+                        baseDirs.removeAllElements();
+                    }
+                }
+            }
+            if (parallel && (fileNames.size() > 0 || !skipEmpty)) {
+                runParallel(exe, fileNames, baseDirs);
+                haveExecuted = true;
+            }
+            if (haveExecuted) {
+                log("Applied " + cmdl.getExecutable() + " to "
+                    + totalFiles + " file"
+                    + (totalFiles != 1 ? "s" : "") + " and "
+                    + totalDirs + " director"
+                    + (totalDirs != 1 ? "ies" : "y") + ".",
+                    verbose ? Project.MSG_INFO : Project.MSG_VERBOSE);
+            }
+        } catch (IOException e) {
+            throw new BuildException("Execute failed: " + e, e, getLocation());
+        } finally {
+            // close the output file if required
+            logFlush();
+            redirector.setAppendProperties(false);
+            redirector.setProperties();
+        }
+    }
+
+    /**
+     * log a message for skipping a fileset.
+     * @param currentType the current type.
+     * @param ds the directory scanner.
+     * @param base the dir base
+     */
+    private void logSkippingFileset(
+        String currentType, DirectoryScanner ds, File base) {
+        int includedCount
+            = ((!FileDirBoth.DIR.equals(currentType))
+               ? ds.getIncludedFilesCount() : 0)
+            + ((!FileDirBoth.FILE.equals(currentType))
+               ? ds.getIncludedDirsCount() : 0);
+
+        log("Skipping fileset for directory " + base + ". It is "
+            + ((includedCount > 0) ? "up to date." : "empty."),
+             verbose ? Project.MSG_INFO : Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Construct the command line for parallel execution.
+     *
+     * @param srcFiles The filenames to add to the commandline.
+     * @param baseDirs filenames are relative to this dir.
+     * @return the command line in the form of a String[].
+     */
+    protected String[] getCommandline(String[] srcFiles, File[] baseDirs) {
+        final char fileSeparator = File.separatorChar;
+        Vector targets = new Vector();
+        if (targetFilePos != null) {
+            Hashtable addedFiles = new Hashtable();
+            for (int i = 0; i < srcFiles.length; i++) {
+                String[] subTargets = mapper.mapFileName(srcFiles[i]);
+                if (subTargets != null) {
+                    for (int j = 0; j < subTargets.length; j++) {
+                        String name = null;
+                        if (!relative) {
+                            name = (new File(destDir, subTargets[j])).getAbsolutePath();
+                        } else {
+                            name = subTargets[j];
+                        }
+                        if (forwardSlash && fileSeparator != '/') {
+                            name = name.replace(fileSeparator, '/');
+                        }
+                        if (!addedFiles.contains(name)) {
+                            targets.addElement(name);
+                            addedFiles.put(name, name);
+                        }
+                    }
+                }
+            }
+        }
+        String[] targetFiles = new String[targets.size()];
+        targets.copyInto(targetFiles);
+
+        if (!addSourceFile) {
+            srcFiles = new String[0];
+        }
+        String[] orig = cmdl.getCommandline();
+        String[] result
+            = new String[orig.length + srcFiles.length + targetFiles.length];
+
+        int srcIndex = orig.length;
+        if (srcFilePos != null) {
+            srcIndex = srcFilePos.getPosition();
+        }
+        if (targetFilePos != null) {
+            int targetIndex = targetFilePos.getPosition();
+
+            if (srcIndex < targetIndex
+                || (srcIndex == targetIndex && srcIsFirst)) {
+
+                // 0 --> srcIndex
+                System.arraycopy(orig, 0, result, 0, srcIndex);
+
+                // srcIndex --> targetIndex
+                System.arraycopy(orig, srcIndex, result,
+                                 srcIndex + srcFiles.length,
+                                 targetIndex - srcIndex);
+
+                // targets are already absolute file names
+                System.arraycopy(targetFiles, 0, result,
+                                 targetIndex + srcFiles.length,
+                                 targetFiles.length);
+
+                // targetIndex --> end
+                System.arraycopy(orig, targetIndex, result,
+                    targetIndex + srcFiles.length + targetFiles.length,
+                    orig.length - targetIndex);
+            } else {
+                // 0 --> targetIndex
+                System.arraycopy(orig, 0, result, 0, targetIndex);
+
+                // targets are already absolute file names
+                System.arraycopy(targetFiles, 0, result,
+                                 targetIndex,
+                                 targetFiles.length);
+
+                // targetIndex --> srcIndex
+                System.arraycopy(orig, targetIndex, result,
+                                 targetIndex + targetFiles.length,
+                                 srcIndex - targetIndex);
+
+                // srcIndex --> end
+                System.arraycopy(orig, srcIndex, result,
+                    srcIndex + srcFiles.length + targetFiles.length,
+                    orig.length - srcIndex);
+                srcIndex += targetFiles.length;
+            }
+
+        } else { // no targetFilePos
+
+            // 0 --> srcIndex
+            System.arraycopy(orig, 0, result, 0, srcIndex);
+            // srcIndex --> end
+            System.arraycopy(orig, srcIndex, result,
+                             srcIndex + srcFiles.length,
+                             orig.length - srcIndex);
+        }
+        // fill in source file names
+        for (int i = 0; i < srcFiles.length; i++) {
+            if (!relative) {
+                result[srcIndex + i] =
+                    (new File(baseDirs[i], srcFiles[i])).getAbsolutePath();
+            } else {
+                result[srcIndex + i] = srcFiles[i];
+            }
+            if (forwardSlash && fileSeparator != '/') {
+                result[srcIndex + i] =
+                    result[srcIndex + i].replace(fileSeparator, '/');
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Construct the command line for serial execution.
+     *
+     * @param srcFile The filename to add to the commandline.
+     * @param baseDir filename is relative to this dir.
+     * @return the command line in the form of a String[].
+     */
+    protected String[] getCommandline(String srcFile, File baseDir) {
+        return getCommandline(new String[] {srcFile}, new File[] {baseDir});
+    }
+
+    /**
+     * Return the list of files from this DirectoryScanner that should
+     * be included on the command line.
+     * @param baseDir the File base directory.
+     * @param ds the DirectoryScanner to use for file scanning.
+     * @return a String[] containing the filenames.
+     */
+    protected String[] getFiles(File baseDir, DirectoryScanner ds) {
+        return restrict(ds.getIncludedFiles(), baseDir);
+    }
+
+    /**
+     * Return the list of Directories from this DirectoryScanner that
+     * should be included on the command line.
+     * @param baseDir the File base directory.
+     * @param ds the DirectoryScanner to use for file scanning.
+     * @return a String[] containing the directory names.
+     */
+    protected String[] getDirs(File baseDir, DirectoryScanner ds) {
+        return restrict(ds.getIncludedDirectories(), baseDir);
+    }
+
+    /**
+     * Return the list of files or directories from this FileList that
+     * should be included on the command line.
+     * @param list the FileList to check.
+     * @return a String[] containing the directory names.
+     *
+     * @since Ant 1.6.2
+     */
+    protected String[] getFilesAndDirs(FileList list) {
+        return restrict(list.getFiles(getProject()), list.getDir(getProject()));
+    }
+
+    private String[] restrict(String[] s, File baseDir) {
+        return (mapper == null || force) ? s
+            : new SourceFileScanner(this).restrict(s, baseDir, destDir, mapper);
+    }
+
+    /**
+     * Run the command in "parallel" mode, making sure that at most
+     * maxParallel sourcefiles get passed on the command line.
+     * @param exe the Executable to use.
+     * @param fileNames the Vector of filenames.
+     * @param baseDirs the Vector of base directories corresponding to fileNames.
+     * @throws IOException  on I/O errors.
+     * @throws BuildException on other errors.
+     * @since Ant 1.6
+     */
+    protected void runParallel(Execute exe, Vector fileNames,
+                               Vector baseDirs)
+        throws IOException, BuildException {
+        String[] s = new String[fileNames.size()];
+        fileNames.copyInto(s);
+        File[] b = new File[baseDirs.size()];
+        baseDirs.copyInto(b);
+
+        if (maxParallel <= 0
+            || s.length == 0 /* this is skipEmpty == false */) {
+            String[] command = getCommandline(s, b);
+            log(Commandline.describeCommand(command), Project.MSG_VERBOSE);
+            exe.setCommandline(command);
+            runExecute(exe);
+        } else {
+            int stillToDo = fileNames.size();
+            int currentOffset = 0;
+            while (stillToDo > 0) {
+                int currentAmount = Math.min(stillToDo, maxParallel);
+                String[] cs = new String[currentAmount];
+                System.arraycopy(s, currentOffset, cs, 0, currentAmount);
+                File[] cb = new File[currentAmount];
+                System.arraycopy(b, currentOffset, cb, 0, currentAmount);
+                String[] command = getCommandline(cs, cb);
+                log(Commandline.describeCommand(command), Project.MSG_VERBOSE);
+                exe.setCommandline(command);
+                if (redirectorElement != null) {
+                    setupRedirector();
+                    redirectorElement.configure(redirector, null);
+                }
+                if (redirectorElement != null || currentOffset > 0) {
+                    // need to reset the stream handler to restart
+                    // reading of pipes;
+                    // go ahead and do it always w/ nested redirectors
+                    exe.setStreamHandler(redirector.createHandler());
+                }
+                runExecute(exe);
+
+                stillToDo -= currentAmount;
+                currentOffset += currentAmount;
+            }
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values "file", "dir" and "both"
+     * for the type attribute.
+     */
+    public static class FileDirBoth extends EnumeratedAttribute {
+        /** File value */
+        public static final String FILE = "file";
+        /** Dir value */
+        public static final String DIR = "dir";
+        /**
+         * @see EnumeratedAttribute#getValues
+         */
+        /** {@inheritDoc}. */
+       public String[] getValues() {
+            return new String[] {FILE, DIR, "both"};
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteStreamHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteStreamHandler.java
new file mode 100644
index 0000000..1c5f973
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteStreamHandler.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Used by <code>Execute</code> to handle input and output stream of
+ * subprocesses.
+ *
+ * @since Ant 1.2
+ */
+public interface ExecuteStreamHandler {
+
+    /**
+     * Install a handler for the input stream of the subprocess.
+     *
+     * @param os output stream to write to the standard input stream of the
+     *           subprocess
+     * @throws IOException on error
+     */
+    void setProcessInputStream(OutputStream os) throws IOException;
+
+    /**
+     * Install a handler for the error stream of the subprocess.
+     *
+     * @param is input stream to read from the error stream from the subprocess
+     * @throws IOException on error
+     */
+    void setProcessErrorStream(InputStream is) throws IOException;
+
+    /**
+     * Install a handler for the output stream of the subprocess.
+     *
+     * @param is input stream to read from the error stream from the subprocess
+     * @throws IOException on error
+     */
+    void setProcessOutputStream(InputStream is) throws IOException;
+
+    /**
+     * Start handling of the streams.
+     * @throws IOException on error
+     */
+    void start() throws IOException;
+
+    /**
+     * Stop handling of the streams - will not be restarted.
+     */
+    void stop();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java
new file mode 100644
index 0000000..cc3933e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.TimeoutObserver;
+import org.apache.tools.ant.util.Watchdog;
+
+/**
+ * Destroys a process running for too long.
+ * For example:
+ * <pre>
+ * ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);
+ * Execute exec = new Execute(myloghandler, watchdog);
+ * exec.setCommandLine(mycmdline);
+ * int exitvalue = exec.execute();
+ * if (Execute.isFailure(exitvalue) &amp;&amp; watchdog.killedProcess()) {
+ *              // it was killed on purpose by the watchdog
+ * }
+ * </pre>
+
+ * @see Execute
+ * @see org.apache.tools.ant.util.Watchdog
+ * @since Ant 1.2
+ */
+public class ExecuteWatchdog implements TimeoutObserver {
+
+    /** the process to execute and watch for duration */
+    private Process process;
+
+    /** say whether or not the watchdog is currently monitoring a process */
+    private volatile boolean watch = false;
+
+    /** exception that might be thrown during the process execution */
+    private Exception caught = null;
+
+    /** say whether or not the process was killed due to running overtime */
+    private volatile boolean killedProcess = false;
+
+    /** will tell us whether timeout has occurred */
+    private Watchdog watchdog;
+
+    /**
+     * Creates a new watchdog with a given timeout.
+     *
+     * @param timeout the timeout for the process in milliseconds.
+     * It must be greater than 0.
+     */
+    public ExecuteWatchdog(long timeout) {
+        watchdog = new Watchdog(timeout);
+        watchdog.addTimeoutObserver(this);
+    }
+
+    /**
+     * @param timeout the timeout value to use in milliseconds.
+     * @see #ExecuteWatchdog(long)
+     * @deprecated since 1.5.x.
+     *             Use constructor with a long type instead.
+     * (1.4.x compatibility)
+     */
+    public ExecuteWatchdog(int timeout) {
+        this((long) timeout);
+    }
+
+    /**
+     * Watches the given process and terminates it, if it runs for too long.
+     * All information from the previous run are reset.
+     * @param process the process to monitor. It cannot be <tt>null</tt>
+     * @throws IllegalStateException if a process is still being monitored.
+     */
+    public synchronized void start(Process process) {
+        if (process == null) {
+            throw new NullPointerException("process is null.");
+        }
+        if (this.process != null) {
+            throw new IllegalStateException("Already running.");
+        }
+        this.caught = null;
+        this.killedProcess = false;
+        this.watch = true;
+        this.process = process;
+        watchdog.start();
+    }
+
+    /**
+     * Stops the watcher. It will notify all threads possibly waiting
+     * on this object.
+     */
+    public synchronized void stop() {
+        watchdog.stop();
+        cleanUp();
+    }
+
+    /**
+     * Called after watchdog has finished.
+     * This can be called in the watchdog thread
+     * @param w the watchdog
+     */
+    public synchronized void timeoutOccured(Watchdog w) {
+        try {
+            try {
+                // We must check if the process was not stopped
+                // before being here
+                process.exitValue();
+            } catch (IllegalThreadStateException itse) {
+                // the process is not terminated, if this is really
+                // a timeout and not a manual stop then kill it.
+                if (watch) {
+                    killedProcess = true;
+                    process.destroy();
+                }
+            }
+        } catch (Exception e) {
+            caught = e;
+        } finally {
+            cleanUp();
+        }
+    }
+
+    /**
+     * reset the monitor flag and the process.
+     */
+    protected synchronized void cleanUp() {
+        watch = false;
+        process = null;
+    }
+
+    /**
+     * This method will rethrow the exception that was possibly caught during
+     * the run of the process. It will only remains valid once the process has
+     * been terminated either by 'error', timeout or manual intervention.
+     * Information will be discarded once a new process is ran.
+     * @throws  BuildException  a wrapped exception over the one that was
+     * silently swallowed and stored during the process run.
+     */
+    public synchronized void checkException() throws BuildException {
+        if (caught != null) {
+            throw new BuildException("Exception in ExecuteWatchdog.run: "
+                                     + caught.getMessage(), caught);
+        }
+    }
+
+    /**
+     * Indicates whether or not the watchdog is still monitoring the process.
+     * @return  <tt>true</tt> if the process is still running, otherwise
+     *          <tt>false</tt>.
+     */
+    public boolean isWatching() {
+        return watch;
+    }
+
+    /**
+     * Indicates whether the last process run was killed on timeout or not.
+     * @return  <tt>true</tt> if the process was killed otherwise
+     *          <tt>false</tt>.
+     */
+    public boolean killedProcess() {
+        return killedProcess;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Exit.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Exit.java
new file mode 100644
index 0000000..0fe817b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Exit.java
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ExitStatusException;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+
+/**
+ * Exits the active build, giving an additional message
+ * if available.
+ *
+ * The <code>if</code> and <code>unless</code> attributes make the
+ * failure conditional -both probe for the named property being defined.
+ * The <code>if</code> tests for the property being defined, the
+ * <code>unless</code> for a property being undefined.
+ *
+ * If both attributes are set, then the test fails only if both tests
+ * are true. i.e.
+ * <pre>fail := defined(ifProperty) && !defined(unlessProperty)</pre>
+ *
+ * A single nested<code>&lt;condition&gt;</code> element can be specified
+ * instead of using <code>if</code>/<code>unless</code> (a combined
+ * effect can be achieved using <code>isset</code> conditions).
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="fail" category="control"
+ */
+public class Exit extends Task {
+
+    private static class NestedCondition extends ConditionBase implements Condition {
+        public boolean eval() {
+            if (countConditions() != 1) {
+                throw new BuildException(
+                    "A single nested condition is required.");
+            }
+            return ((Condition) (getConditions().nextElement())).eval();
+        }
+    }
+
+    private String message;
+    private String ifCondition, unlessCondition;
+    private NestedCondition nestedCondition;
+    private Integer status;
+
+    /**
+     * A message giving further information on why the build exited.
+     *
+     * @param value message to output
+     */
+    public void setMessage(String value) {
+        this.message = value;
+    }
+
+    /**
+     * Only fail if a property of the given name exists in the current project.
+     * @param c property name
+     */
+    public void setIf(String c) {
+        ifCondition = c;
+    }
+
+    /**
+     * Only fail if a property of the given name does not
+     * exist in the current project.
+     * @param c property name
+     */
+    public void setUnless(String c) {
+        unlessCondition = c;
+    }
+
+    /**
+     * Set the status code to associate with the thrown Exception.
+     * @param i   the <code>int</code> status
+     */
+    public void setStatus(int i) {
+        status = new Integer(i);
+    }
+
+    /**
+     * Throw a <code>BuildException</code> to exit (fail) the build.
+     * If specified, evaluate conditions:
+     * A single nested condition is accepted, but requires that the
+     * <code>if</code>/<code>unless</code> attributes be omitted.
+     * If the nested condition evaluates to true, or the
+     * ifCondition is true or unlessCondition is false, the build will exit.
+     * The error message is constructed from the text fields, from
+     * the nested condition (if specified), or finally from
+     * the if and unless parameters (if present).
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        boolean fail = (nestedConditionPresent()) ? testNestedCondition()
+                     : (testIfCondition() && testUnlessCondition());
+        if (fail) {
+            String text = null;
+            if (message != null && message.trim().length() > 0) {
+                text = message.trim();
+            } else {
+                if (ifCondition != null && ifCondition.length() > 0
+                    && getProject().getProperty(ifCondition) != null) {
+                    text = "if=" + ifCondition;
+                }
+                if (unlessCondition != null && unlessCondition.length() > 0
+                    && getProject().getProperty(unlessCondition) == null) {
+                    if (text == null) {
+                        text = "";
+                    } else {
+                        text += " and ";
+                    }
+                    text += "unless=" + unlessCondition;
+                }
+                if (nestedConditionPresent()) {
+                    text = "condition satisfied";
+                } else {
+                    if (text == null) {
+                        text = "No message";
+                    }
+                }
+            }
+            log("failing due to " + text, Project.MSG_DEBUG);
+            throw ((status == null) ? new BuildException(text)
+             : new ExitStatusException(text, status.intValue()));
+        }
+    }
+
+    /**
+     * Set a multiline message.
+     * @param msg the message to display
+     */
+    public void addText(String msg) {
+        if (message == null) {
+            message = "";
+        }
+        message += getProject().replaceProperties(msg);
+    }
+
+    /**
+     * Add a condition element.
+     * @return <code>ConditionBase</code>.
+     * @since Ant 1.6.2
+     */
+    public ConditionBase createCondition() {
+        if (nestedCondition != null) {
+            throw new BuildException("Only one nested condition is allowed.");
+        }
+        nestedCondition = new NestedCondition();
+        return nestedCondition;
+    }
+
+    /**
+     * test the if condition
+     * @return true if there is no if condition, or the named property exists
+     */
+    private boolean testIfCondition() {
+        if (ifCondition == null || "".equals(ifCondition)) {
+            return true;
+        }
+        return getProject().getProperty(ifCondition) != null;
+    }
+
+    /**
+     * test the unless condition
+     * @return true if there is no unless condition,
+     *  or there is a named property but it doesn't exist
+     */
+    private boolean testUnlessCondition() {
+        if (unlessCondition == null || "".equals(unlessCondition)) {
+            return true;
+        }
+        return getProject().getProperty(unlessCondition) == null;
+    }
+
+    /**
+     * test the nested condition
+     * @return true if there is none, or it evaluates to true
+     */
+    private boolean testNestedCondition() {
+        boolean result = nestedConditionPresent();
+
+        if (result && ifCondition != null || unlessCondition != null) {
+            throw new BuildException("Nested conditions "
+                + "not permitted in conjunction with if/unless attributes");
+        }
+
+        return result && nestedCondition.eval();
+    }
+
+    /**
+     * test whether there is a nested condition.
+     * @return <code>boolean</code>.
+     */
+    private boolean nestedConditionPresent() {
+        return (nestedCondition != null);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Expand.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Expand.java
new file mode 100644
index 0000000..269b1b7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Expand.java
@@ -0,0 +1,399 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipFile;
+
+/**
+ * Unzip a file.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ *           name="unzip"
+ *           name="unjar"
+ *           name="unwar"
+ */
+public class Expand extends Task {
+    private static final int BUFFER_SIZE = 1024;
+    private File dest; //req
+    private File source; // req
+    private boolean overwrite = true;
+    private Mapper mapperElement = null;
+    private Vector patternsets = new Vector();
+    private Union resources = new Union();
+    private boolean resourcesSpecified = false;
+
+    private static final String NATIVE_ENCODING = "native-encoding";
+
+    private String encoding = "UTF8";
+    /** Error message when more that one mapper is defined */
+    public static final String ERROR_MULTIPLE_MAPPERS = "Cannot define more than one mapper";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Do the work.
+     *
+     * @exception BuildException Thrown in unrecoverable error.
+     */
+    public void execute() throws BuildException {
+        if ("expand".equals(getTaskType())) {
+            log("!! expand is deprecated. Use unzip instead. !!");
+        }
+
+        if (source == null && !resourcesSpecified) {
+            throw new BuildException("src attribute and/or resources must be "
+                                     + "specified");
+        }
+
+        if (dest == null) {
+            throw new BuildException(
+                "Dest attribute must be specified");
+        }
+
+        if (dest.exists() && !dest.isDirectory()) {
+            throw new BuildException("Dest must be a directory.", getLocation());
+        }
+
+        if (source != null) {
+            if (source.isDirectory()) {
+                throw new BuildException("Src must not be a directory."
+                    + " Use nested filesets instead.", getLocation());
+            } else {
+                expandFile(FILE_UTILS, source, dest);
+            }
+        }
+        Iterator iter = resources.iterator();
+        while (iter.hasNext()) {
+            Resource r = (Resource) iter.next();
+            if (!r.isExists()) {
+                continue;
+            }
+
+            if (r instanceof FileResource) {
+                expandFile(FILE_UTILS, ((FileResource) r).getFile(), dest);
+            } else {
+                expandResource(r, dest);
+            }
+        }
+    }
+
+    /**
+     * This method is to be overridden by extending unarchival tasks.
+     *
+     * @param fileUtils the fileUtils
+     * @param srcF      the source file
+     * @param dir       the destination directory
+     */
+    protected void expandFile(FileUtils fileUtils, File srcF, File dir) {
+        log("Expanding: " + srcF + " into " + dir, Project.MSG_INFO);
+        ZipFile zf = null;
+        FileNameMapper mapper = getMapper();
+        try {
+            zf = new ZipFile(srcF, encoding);
+            Enumeration e = zf.getEntries();
+            while (e.hasMoreElements()) {
+                ZipEntry ze = (ZipEntry) e.nextElement();
+                extractFile(fileUtils, srcF, dir, zf.getInputStream(ze),
+                            ze.getName(), new Date(ze.getTime()),
+                            ze.isDirectory(), mapper);
+            }
+
+            log("expand complete", Project.MSG_VERBOSE);
+        } catch (IOException ioe) {
+            throw new BuildException(
+                "Error while expanding " + srcF.getPath()
+                + "\n" + ioe.toString(),
+                ioe);
+        } finally {
+            ZipFile.closeQuietly(zf);
+        }
+    }
+
+    /**
+     * This method is to be overridden by extending unarchival tasks.
+     *
+     * @param srcR      the source resource
+     * @param dir       the destination directory
+     */
+    protected void expandResource(Resource srcR, File dir) {
+        throw new BuildException("only filesystem based resources are"
+                                 + " supported by this task.");
+    }
+
+    /**
+     * get a mapper for a file
+     * @return a filenamemapper for a file
+     */
+    protected FileNameMapper getMapper() {
+        FileNameMapper mapper = null;
+        if (mapperElement != null) {
+            mapper = mapperElement.getImplementation();
+        } else {
+            mapper = new IdentityMapper();
+        }
+        return mapper;
+    }
+
+    // CheckStyle:ParameterNumberCheck OFF - bc
+    /**
+     * extract a file to a directory
+     * @param fileUtils             a fileUtils object
+     * @param srcF                  the source file
+     * @param dir                   the destination directory
+     * @param compressedInputStream the input stream
+     * @param entryName             the name of the entry
+     * @param entryDate             the date of the entry
+     * @param isDirectory           if this is true the entry is a directory
+     * @param mapper                the filename mapper to use
+     * @throws IOException on error
+     */
+    protected void extractFile(FileUtils fileUtils, File srcF, File dir,
+                               InputStream compressedInputStream,
+                               String entryName, Date entryDate,
+                               boolean isDirectory, FileNameMapper mapper)
+                               throws IOException {
+
+        if (patternsets != null && patternsets.size() > 0) {
+            String name = entryName.replace('/', File.separatorChar)
+                .replace('\\', File.separatorChar);
+            boolean included = false;
+            Set includePatterns = new HashSet();
+            Set excludePatterns = new HashSet();
+            for (int v = 0, size = patternsets.size(); v < size; v++) {
+                PatternSet p = (PatternSet) patternsets.elementAt(v);
+                String[] incls = p.getIncludePatterns(getProject());
+                if (incls == null || incls.length == 0) {
+                    // no include pattern implicitly means includes="**"
+                    incls = new String[] {"**"};
+                }
+
+                for (int w = 0; w < incls.length; w++) {
+                    String pattern = incls[w].replace('/', File.separatorChar)
+                        .replace('\\', File.separatorChar);
+                    if (pattern.endsWith(File.separator)) {
+                        pattern += "**";
+                    }
+                    includePatterns.add(pattern);
+                }
+
+                String[] excls = p.getExcludePatterns(getProject());
+                if (excls != null) {
+                    for (int w = 0; w < excls.length; w++) {
+                        String pattern = excls[w]
+                            .replace('/', File.separatorChar)
+                            .replace('\\', File.separatorChar);
+                        if (pattern.endsWith(File.separator)) {
+                            pattern += "**";
+                        }
+                        excludePatterns.add(pattern);
+                    }
+                }
+            }
+
+            for (Iterator iter = includePatterns.iterator();
+                 !included && iter.hasNext();) {
+                String pattern = (String) iter.next();
+                included = SelectorUtils.matchPath(pattern, name);
+            }
+
+            for (Iterator iter = excludePatterns.iterator();
+                 included && iter.hasNext();) {
+                String pattern = (String) iter.next();
+                included = !SelectorUtils.matchPath(pattern, name);
+            }
+
+            if (!included) {
+                //Do not process this file
+                return;
+            }
+        }
+        String[] mappedNames = mapper.mapFileName(entryName);
+        if (mappedNames == null || mappedNames.length == 0) {
+            mappedNames = new String[] {entryName};
+        }
+        File f = fileUtils.resolveFile(dir, mappedNames[0]);
+        try {
+            if (!overwrite && f.exists()
+                && f.lastModified() >= entryDate.getTime()) {
+                log("Skipping " + f + " as it is up-to-date",
+                    Project.MSG_DEBUG);
+                return;
+            }
+
+            log("expanding " + entryName + " to " + f,
+                Project.MSG_VERBOSE);
+            // create intermediary directories - sometimes zip don't add them
+            File dirF = f.getParentFile();
+            if (dirF != null) {
+                dirF.mkdirs();
+            }
+
+            if (isDirectory) {
+                f.mkdirs();
+            } else {
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int length = 0;
+                FileOutputStream fos = null;
+                try {
+                    fos = new FileOutputStream(f);
+
+                    while ((length =
+                            compressedInputStream.read(buffer)) >= 0) {
+                        fos.write(buffer, 0, length);
+                    }
+
+                    fos.close();
+                    fos = null;
+                } finally {
+                    FileUtils.close(fos);
+                }
+            }
+
+            fileUtils.setFileLastModified(f, entryDate.getTime());
+        } catch (FileNotFoundException ex) {
+            log("Unable to expand to file " + f.getPath(), Project.MSG_WARN);
+        }
+
+    }
+    // CheckStyle:ParameterNumberCheck ON
+
+    /**
+     * Set the destination directory. File will be unzipped into the
+     * destination directory.
+     *
+     * @param d Path to the directory.
+     */
+    public void setDest(File d) {
+        this.dest = d;
+    }
+
+    /**
+     * Set the path to zip-file.
+     *
+     * @param s Path to zip-file.
+     */
+    public void setSrc(File s) {
+        this.source = s;
+    }
+
+    /**
+     * Should we overwrite files in dest, even if they are newer than
+     * the corresponding entries in the archive?
+     * @param b a <code>boolean</code> value
+     */
+    public void setOverwrite(boolean b) {
+        overwrite = b;
+    }
+
+    /**
+     * Add a patternset.
+     * @param set a pattern set
+     */
+    public void addPatternset(PatternSet set) {
+        patternsets.addElement(set);
+    }
+
+    /**
+     * Add a fileset
+     * @param set a file set
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Add a resource collection.
+     * @param rc a resource collection.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        resourcesSpecified = true;
+        resources.add(rc);
+    }
+
+    /**
+     * Defines the mapper to map source entries to destination files.
+     * @return a mapper to be configured
+     * @exception BuildException if more than one mapper is defined
+     * @since Ant1.7
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException(ERROR_MULTIPLE_MAPPERS,
+                                     getLocation());
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+    /**
+     * A nested filenamemapper
+     * @param fileNameMapper the mapper to add
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+
+    /**
+     * Sets the encoding to assume for file names and comments.
+     *
+     * <p>Set to <code>native-encoding</code> if you want your
+     * platform's native encoding, defaults to UTF8.</p>
+     * @param encoding the name of the character encoding
+     * @since Ant 1.6
+     */
+    public void setEncoding(String encoding) {
+        if (NATIVE_ENCODING.equals(encoding)) {
+            encoding = null;
+        }
+        this.encoding = encoding;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Filter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Filter.java
new file mode 100644
index 0000000..48fd19f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Filter.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Sets a token filter that is used by the file copy tasks
+ * to do token substitution. Sets multiple tokens by
+ * reading these from a file.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+public class Filter extends Task {
+
+    private String token;
+    private String value;
+    private File filtersFile;
+
+    /**
+     * The token string without @ delimiters.
+     * @param token token to set
+     */
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    /**
+     * The string that should replace the token during filtered copies.
+     * @param value token replace value
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * The file from which the filters must be read.
+     * This file must be a formatted as a property file.
+     *
+     * @param filtersFile filter file
+     */
+    public void setFiltersfile(File filtersFile) {
+        this.filtersFile = filtersFile;
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        boolean isFiltersFromFile =
+            filtersFile != null && token == null && value == null;
+        boolean isSingleFilter =
+            filtersFile == null && token != null && value != null;
+
+        if (!isFiltersFromFile && !isSingleFilter) {
+            throw new BuildException("both token and value parameters, or "
+                                     + "only a filtersFile parameter is "
+                                     + "required", getLocation());
+        }
+
+        if (isSingleFilter) {
+            getProject().getGlobalFilterSet().addFilter(token, value);
+        }
+
+        if (isFiltersFromFile) {
+            readFilters();
+        }
+    }
+
+    /**
+     * Read the filters.
+     * @throws BuildException on error
+     */
+    protected void readFilters() throws BuildException {
+        log("Reading filters from " + filtersFile, Project.MSG_VERBOSE);
+        getProject().getGlobalFilterSet().readFiltersFromFile(filtersFile);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java b/trunk/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java
new file mode 100644
index 0000000..f110e4b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/FixCRLF.java
@@ -0,0 +1,689 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.filters.FixCrLfFilter;
+import org.apache.tools.ant.filters.ChainableReader;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Converts text source files to local OS formatting conventions, as
+ * well as repair text files damaged by misconfigured or misguided editors or
+ * file transfer programs.
+ * <p>
+ * This task can take the following arguments:
+ * <ul>
+ * <li>srcdir
+ * <li>destdir
+ * <li>include
+ * <li>exclude
+ * <li>cr
+ * <li>eol
+ * <li>tab
+ * <li>eof
+ * <li>encoding
+ * <li>targetencoding
+ * </ul>
+ * Of these arguments, only <b>sourcedir</b> is required.
+ * <p>
+ * When this task executes, it will scan the srcdir based on the include
+ * and exclude properties.
+ * <p>
+ * This version generalises the handling of EOL characters, and allows
+ * for CR-only line endings (the standard on Mac systems prior to OS X).
+ * Tab handling has also been generalised to accommodate any tabwidth
+ * from 2 to 80, inclusive.  Importantly, it will leave untouched any
+ * literal TAB characters embedded within string or character constants.
+ * <p>
+ * <em>Warning:</em> do not run on binary files.
+ * <em>Caution:</em> run with care on carefully formatted files.
+ * This may sound obvious, but if you don't specify asis, presume that
+ * your files are going to be modified.  If "tabs" is "add" or "remove",
+ * whitespace characters may be added or removed as necessary.  Similarly,
+ * for CR's - in fact "eol"="crlf" or cr="add" can result in cr
+ * characters being removed in one special case accommodated, i.e.,
+ * CRCRLF is regarded as a single EOL to handle cases where other
+ * programs have converted CRLF into CRCRLF.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+
+public class FixCRLF extends MatchingTask implements ChainableReader {
+
+    private static final String FIXCRLF_ERROR = "<fixcrlf> error: ";
+    /** error string for using srcdir and file */
+    public static final String ERROR_FILE_AND_SRCDIR
+        = FIXCRLF_ERROR + "srcdir and file are mutually exclusive";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private boolean preserveLastModified = false;
+    private File srcDir;
+    private File destDir = null;
+    private File file;
+    private FixCrLfFilter filter = new FixCrLfFilter();
+    private Vector fcv = null;
+
+    /**
+     * Encoding to assume for the files
+     */
+    private String encoding = null;
+
+    /**
+     * Encoding to use for output files
+     */
+    private String outputEncoding = null;
+
+
+    /**
+     * Chain this task as a reader.
+     * @param rdr Reader to chain.
+     * @return a Reader.
+     * @since Ant 1.7?
+     */
+    public final Reader chain(final Reader rdr) {
+        return filter.chain(rdr);
+    }
+
+    /**
+     * Set the source dir to find the source text files.
+     * @param srcDir the source directory.
+     */
+    public void setSrcdir(File srcDir) {
+        this.srcDir = srcDir;
+    }
+
+    /**
+     * Set the destination where the fixed files should be placed.
+     * Default is to replace the original file.
+     * @param destDir the destination directory.
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Set to true if modifying Java source files.
+     * @param javafiles whether modifying Java files.
+     */
+    public void setJavafiles(boolean javafiles) {
+        filter.setJavafiles(javafiles);
+    }
+
+    /**
+     * Set a single file to convert.
+     * @since Ant 1.6.3
+     * @param file the file to convert.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Specify how EndOfLine characters are to be handled.
+     *
+     * @param attr valid values:
+     * <ul>
+     * <li>asis: leave line endings alone
+     * <li>cr: convert line endings to CR
+     * <li>lf: convert line endings to LF
+     * <li>crlf: convert line endings to CRLF
+     * </ul>
+     */
+    public void setEol(CrLf attr) {
+        filter.setEol(FixCrLfFilter.CrLf.newInstance(attr.getValue()));
+    }
+
+    /**
+     * Specify how carriage return (CR) characters are to be handled.
+     *
+     * @param attr valid values:
+     * <ul>
+     * <li>add: ensure that there is a CR before every LF
+     * <li>asis: leave CR characters alone
+     * <li>remove: remove all CR characters
+     * </ul>
+     *
+     * @deprecated since 1.4.x.
+     *             Use {@link #setEol setEol} instead.
+     */
+    public void setCr(AddAsisRemove attr) {
+        log("DEPRECATED: The cr attribute has been deprecated,",
+            Project.MSG_WARN);
+        log("Please use the eol attribute instead", Project.MSG_WARN);
+        String option = attr.getValue();
+        CrLf c = new CrLf();
+        if (option.equals("remove")) {
+            c.setValue("lf");
+        } else if (option.equals("asis")) {
+            c.setValue("asis");
+        } else {
+            // must be "add"
+            c.setValue("crlf");
+        }
+        setEol(c);
+    }
+
+    /**
+     * Specify how tab characters are to be handled.
+     *
+     * @param attr valid values:
+     * <ul>
+     * <li>add: convert sequences of spaces which span a tab stop to tabs
+     * <li>asis: leave tab and space characters alone
+     * <li>remove: convert tabs to spaces
+     * </ul>
+     */
+    public void setTab(AddAsisRemove attr) {
+        filter.setTab(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue()));
+    }
+
+    /**
+     * Specify tab length in characters.
+     *
+     * @param tlength specify the length of tab in spaces.
+     * @throws BuildException on error.
+     */
+    public void setTablength(int tlength) throws BuildException {
+        try {
+            filter.setTablength(tlength);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Specify how DOS EOF (control-z) characters are to be handled.
+     *
+     * @param attr valid values:
+     * <ul>
+     * <li>add: ensure that there is an eof at the end of the file
+     * <li>asis: leave eof characters alone
+     * <li>remove: remove any eof character found at the end
+     * </ul>
+     */
+    public void setEof(AddAsisRemove attr) {
+        filter.setEof(FixCrLfFilter.AddAsisRemove.newInstance(attr.getValue()));
+    }
+
+    /**
+     * Specifies the encoding Ant expects the files to be
+     * in--defaults to the platforms default encoding.
+     * @param encoding String encoding name.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Specifies the encoding that the files are
+     * to be written in--same as input encoding by default.
+     * @param outputEncoding String outputEncoding name.
+     */
+    public void setOutputEncoding(String outputEncoding) {
+        this.outputEncoding = outputEncoding;
+    }
+
+    /**
+     * Specify whether a missing EOL will be added
+     * to the final line of a file.
+     * @param fixlast whether to fix the last line.
+     */
+    public void setFixlast(boolean fixlast) {
+        filter.setFixlast(fixlast);
+    }
+
+    /**
+     * Set whether to preserve the last modified time as the original files.
+     * @param preserve true if timestamps should be preserved.
+     * @since Ant 1.6.3
+     */
+    public void setPreserveLastModified(boolean preserve) {
+        preserveLastModified = preserve;
+    }
+
+    /**
+     * Executes the task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        // first off, make sure that we've got a srcdir and destdir
+        validate();
+
+        // log options used
+        String enc = encoding == null ? "default" : encoding;
+        log("options:"
+            + " eol=" + filter.getEol().getValue()
+            + " tab=" + filter.getTab().getValue()
+            + " eof=" + filter.getEof().getValue()
+            + " tablength=" + filter.getTablength()
+            + " encoding=" + enc
+            + " outputencoding="
+            + (outputEncoding == null ? enc : outputEncoding),
+            Project.MSG_VERBOSE);
+
+        DirectoryScanner ds = super.getDirectoryScanner(srcDir);
+        String[] files = ds.getIncludedFiles();
+
+        for (int i = 0; i < files.length; i++) {
+            processFile(files[i]);
+        }
+    }
+
+    private void validate() throws BuildException {
+        if (file != null) {
+            if (srcDir != null) {
+                throw new BuildException(ERROR_FILE_AND_SRCDIR);
+            }
+            //patch file into the fileset
+            fileset.setFile(file);
+            //set our parent dir
+            srcDir = file.getParentFile();
+        }
+        if (srcDir == null) {
+            throw new BuildException(
+                FIXCRLF_ERROR + "srcdir attribute must be set!");
+        }
+        if (!srcDir.exists()) {
+            throw new BuildException(
+                FIXCRLF_ERROR + "srcdir does not exist: '" + srcDir + "'");
+        }
+        if (!srcDir.isDirectory()) {
+            throw new BuildException(
+                FIXCRLF_ERROR + "srcdir is not a directory: '" + srcDir + "'");
+        }
+        if (destDir != null) {
+            if (!destDir.exists()) {
+                throw new BuildException(
+                    FIXCRLF_ERROR + "destdir does not exist: '"
+                    + destDir + "'");
+            }
+            if (!destDir.isDirectory()) {
+                throw new BuildException(
+                    FIXCRLF_ERROR + "destdir is not a directory: '"
+                    + destDir + "'");
+            }
+        }
+    }
+
+    private void processFile(String file) throws BuildException {
+        File srcFile = new File(srcDir, file);
+        long lastModified = srcFile.lastModified();
+        File destD = destDir == null ? srcDir : destDir;
+
+        if (fcv == null) {
+            FilterChain fc = new FilterChain();
+            fc.add(filter);
+            fcv = new Vector(1);
+            fcv.add(fc);
+        }
+        File tmpFile = FILE_UTILS.createTempFile("fixcrlf", "", null, true, false);
+        try {
+            FILE_UTILS.copyFile(srcFile, tmpFile, null, fcv, false, false,
+                encoding, outputEncoding == null ? encoding : outputEncoding,
+                getProject());
+
+            File destFile = new File(destD, file);
+
+            boolean destIsWrong = true;
+            if (destFile.exists()) {
+                // Compare the destination with the temp file
+                log("destFile exists", Project.MSG_DEBUG);
+                destIsWrong = !FILE_UTILS.contentEquals(destFile, tmpFile);
+                log(destFile + (destIsWrong ? " is being written"
+                    : " is not written, as the contents are identical"),
+                    Project.MSG_DEBUG);
+            }
+            if (destIsWrong) {
+                FILE_UTILS.rename(tmpFile, destFile);
+                if (preserveLastModified) {
+                    log("preserved lastModified", Project.MSG_DEBUG);
+                    FILE_UTILS.setFileLastModified(destFile, lastModified);
+                }
+                tmpFile = null;
+            }
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Deprecated, the functionality has been moved to filters.FixCrLfFilter.
+     * @deprecated since 1.7.0.
+     */
+    protected class OneLiner implements Enumeration {
+        private static final int UNDEF = -1;
+        private static final int NOTJAVA = 0;
+        private static final int LOOKING = 1;
+        private static final int INBUFLEN = 8192;
+        private static final int LINEBUFLEN = 200;
+        private static final char CTRLZ = '\u001A';
+
+        private int state = filter.getJavafiles() ? LOOKING : NOTJAVA;
+
+        private StringBuffer eolStr = new StringBuffer(LINEBUFLEN);
+        private StringBuffer eofStr = new StringBuffer();
+
+        private BufferedReader reader;
+        private StringBuffer line = new StringBuffer();
+        private boolean reachedEof = false;
+        private File srcFile;
+
+        /**
+         * Constructor.
+         * @param srcFile the file to read.
+         * @throws BuildException if there is an error.
+         */
+        public OneLiner(File srcFile)
+            throws BuildException {
+            this.srcFile = srcFile;
+            try {
+                reader = new BufferedReader(
+                    ((encoding == null) ? new FileReader(srcFile)
+                    : new InputStreamReader(
+                    new FileInputStream(srcFile), encoding)), INBUFLEN);
+
+                nextLine();
+            } catch (IOException e) {
+                throw new BuildException(srcFile + ": " + e.getMessage(),
+                                         e, getLocation());
+            }
+        }
+
+        /**
+         * Move to the next line.
+         * @throws BuildException if there is an error.
+         */
+        protected void nextLine()
+            throws BuildException {
+            int ch = -1;
+            int eolcount = 0;
+
+            eolStr = new StringBuffer();
+            line = new StringBuffer();
+
+            try {
+                ch = reader.read();
+                while (ch != -1 && ch != '\r' && ch != '\n') {
+                    line.append((char) ch);
+                    ch = reader.read();
+                }
+
+                if (ch == -1 && line.length() == 0) {
+                    // Eof has been reached
+                    reachedEof = true;
+                    return;
+                }
+
+                switch ((char) ch) {
+                case '\r':
+                    // Check for \r, \r\n and \r\r\n
+                    // Regard \r\r not followed by \n as two lines
+                    ++eolcount;
+                    eolStr.append('\r');
+                    reader.mark(2);
+                    ch = reader.read();
+                    switch (ch) {
+                    case '\r':
+                        ch = reader.read();
+                        if ((char) (ch) == '\n') {
+                            eolcount += 2;
+                            eolStr.append("\r\n");
+                        } else {
+                            reader.reset();
+                        }
+                        break;
+                    case '\n':
+                        ++eolcount;
+                        eolStr.append('\n');
+                        break;
+                    case -1:
+                        // don't reposition when we've reached the end
+                        // of the stream
+                        break;
+                    default:
+                        reader.reset();
+                        break;
+                    } // end of switch ((char)(ch = reader.read()))
+                    break;
+
+                case '\n':
+                    ++eolcount;
+                    eolStr.append('\n');
+                    break;
+                default:
+                    // Fall tru
+                } // end of switch ((char) ch)
+
+                // if at eolcount == 0 and trailing characters of string
+                // are CTRL-Zs, set eofStr
+                if (eolcount == 0) {
+                    int i = line.length();
+                    while (--i >= 0 && line.charAt(i) == CTRLZ) {
+                        // keep searching for the first ^Z
+                    }
+                    if (i < line.length() - 1) {
+                        // Trailing characters are ^Zs
+                        // Construct new line and eofStr
+                        eofStr.append(line.toString().substring(i + 1));
+                        if (i < 0) {
+                            line.setLength(0);
+                            reachedEof = true;
+                        } else {
+                            line.setLength(i + 1);
+                        }
+                    }
+
+                } // end of if (eolcount == 0)
+
+            } catch (IOException e) {
+                throw new BuildException(srcFile + ": " + e.getMessage(),
+                                         e, getLocation());
+            }
+        }
+
+        /**
+         * get the eof string.
+         * @return the eof string.
+         */
+        public String getEofStr() {
+            return eofStr.substring(0);
+        }
+
+        /**
+         * get the state.
+         * @return the state.
+         */
+        public int getState() {
+            return state;
+        }
+
+        /**
+         * Set the state.
+         * @param state the value to use.
+         */
+        public void setState(int state) {
+            this.state = state;
+        }
+
+        /**
+         * @return true if there is more elements.
+         */
+        public boolean hasMoreElements() {
+            return !reachedEof;
+        }
+
+        /**
+         * get the next element.
+         * @return the next element.
+         * @throws NoSuchElementException if there is no more.
+         */
+        public Object nextElement()
+            throws NoSuchElementException {
+            if (!hasMoreElements()) {
+                throw new NoSuchElementException("OneLiner");
+            }
+            BufferLine tmpLine =
+                    new BufferLine(line.toString(), eolStr.substring(0));
+            nextLine();
+            return tmpLine;
+        }
+
+        /**
+         * Close the reader.
+         * @throws IOException if there is an error.
+         */
+        public void close() throws IOException {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+
+        class BufferLine {
+            private int next = 0;
+            private int column = 0;
+            private int lookahead = UNDEF;
+            private String line;
+            private String eolStr;
+
+            public BufferLine(String line, String eolStr)
+                throws BuildException {
+                next = 0;
+                column = 0;
+                this.line = line;
+                this.eolStr = eolStr;
+            }
+
+            public int getNext() {
+                return next;
+            }
+
+            public void setNext(int next) {
+                this.next = next;
+            }
+
+            public int getLookahead() {
+                return lookahead;
+            }
+
+            public void setLookahead(int lookahead) {
+                this.lookahead = lookahead;
+            }
+
+            public char getChar(int i) {
+                return line.charAt(i);
+            }
+
+            public char getNextChar() {
+                return getChar(next);
+            }
+
+            public char getNextCharInc() {
+                return getChar(next++);
+            }
+
+            public int getColumn() {
+                return column;
+            }
+
+            public void setColumn(int col) {
+                column = col;
+            }
+
+            public int incColumn() {
+                return column++;
+            }
+
+            public int length() {
+                return line.length();
+            }
+
+            public int getEolLength() {
+                return eolStr.length();
+            }
+
+            public String getLineString() {
+                return line;
+            }
+
+            public String getEol() {
+                return eolStr;
+            }
+
+            public String substring(int begin) {
+                return line.substring(begin);
+            }
+
+            public String substring(int begin, int end) {
+                return line.substring(begin, end);
+            }
+
+            public void setState(int state) {
+                OneLiner.this.setState(state);
+            }
+
+            public int getState() {
+                return OneLiner.this.getState();
+            }
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values "asis", "add" and "remove".
+     */
+    public static class AddAsisRemove extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"add", "asis", "remove"};
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values "asis", "cr", "lf" and "crlf".
+     */
+    public static class CrLf extends EnumeratedAttribute {
+        /**
+         * @see EnumeratedAttribute#getValues
+         */
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"asis", "cr", "lf", "crlf",
+                                 "mac", "unix", "dos"};
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/GUnzip.java b/trunk/src/main/org/apache/tools/ant/taskdefs/GUnzip.java
new file mode 100644
index 0000000..30e70cc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/GUnzip.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Expands a file that has been compressed with the GZIP
+ * algorithm. Normally used to compress non-compressed archives such
+ * as TAR files.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+
+public class GUnzip extends Unpack {
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final String DEFAULT_EXTENSION = ".gz";
+
+    /**
+     * Get the default extension.
+     * @return the value ".gz"
+     */
+    protected String getDefaultExtension() {
+        return DEFAULT_EXTENSION;
+    }
+
+    /**
+     * Implement the gunzipping.
+     */
+    protected void extract() {
+        if (source.lastModified() > dest.lastModified()) {
+            log("Expanding " + source.getAbsolutePath() + " to "
+                        + dest.getAbsolutePath());
+
+            FileOutputStream out = null;
+            GZIPInputStream zIn = null;
+            InputStream fis = null;
+            try {
+                out = new FileOutputStream(dest);
+                fis = srcResource.getInputStream();
+                zIn = new GZIPInputStream(fis);
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int count = 0;
+                do {
+                    out.write(buffer, 0, count);
+                    count = zIn.read(buffer, 0, buffer.length);
+                } while (count != -1);
+            } catch (IOException ioe) {
+                String msg = "Problem expanding gzip " + ioe.getMessage();
+                throw new BuildException(msg, ioe, getLocation());
+            } finally {
+                FileUtils.close(fis);
+                FileUtils.close(out);
+                FileUtils.close(zIn);
+            }
+        }
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;gunzip&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true if this task supports non file resources.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(GUnzip.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/GZip.java b/trunk/src/main/org/apache/tools/ant/taskdefs/GZip.java
new file mode 100644
index 0000000..5d02b20
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/GZip.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPOutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Compresses a file with the GZIP algorithm. Normally used to compress
+ * non-compressed archives such as TAR files.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+
+public class GZip extends Pack {
+    /**
+     * perform the GZip compression operation.
+     */
+    protected void pack() {
+        GZIPOutputStream zOut = null;
+        try {
+            zOut = new GZIPOutputStream(new FileOutputStream(zipFile));
+            zipResource(getSrcResource(), zOut);
+        } catch (IOException ioe) {
+            String msg = "Problem creating gzip " + ioe.getMessage();
+            throw new BuildException(msg, ioe, getLocation());
+        } finally {
+            FileUtils.close(zOut);
+        }
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;gzip&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true if this case supports non file resources.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(GZip.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/GenerateKey.java b/trunk/src/main/org/apache/tools/ant/taskdefs/GenerateKey.java
new file mode 100644
index 0000000..9624989
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/GenerateKey.java
@@ -0,0 +1,419 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Generates a key in a keystore.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="genkey" category="java"
+ */
+public class GenerateKey extends Task {
+
+    /**
+     * A DistinguishedName parameter.
+     * This is a nested element in a dname nested element.
+     */
+    public static class DnameParam {
+        private String name;
+        private String value;
+
+        /**
+         * Set the name attribute.
+         * @param name a <code>String</code> value
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the name attribute.
+         * @return the name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the value attribute.
+         * @param value a <code>String</code> value
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * Get the value attribute.
+         * @return the value.
+         */
+        public String getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * A class corresponding to the dname nested element.
+     */
+    public static class DistinguishedName {
+        private Vector params = new Vector();
+
+        /**
+         * Create a param nested element.
+         * @return a DnameParam object to be configured.
+         */
+        public Object createParam() {
+            DnameParam param = new DnameParam();
+            params.addElement(param);
+
+            return param;
+        }
+
+        /**
+         * Get the nested parameters.
+         * @return an enumeration of the nested parameters.
+         */
+        public Enumeration getParams() {
+            return params.elements();
+        }
+
+        /**
+         * Generate a string rep of this distinguished name.
+         * The format is each of the parameters (name = value)
+         * separated by ','.
+         * This is used on the command line.
+         * @return a string rep of this name
+         */
+        public String toString() {
+            final int size = params.size();
+            final StringBuffer sb = new StringBuffer();
+            boolean firstPass = true;
+
+            for (int i = 0; i < size; i++) {
+                if (!firstPass) {
+                    sb.append(" ,");
+                }
+                firstPass = false;
+
+                final DnameParam param = (DnameParam) params.elementAt(i);
+                sb.append(encode(param.getName()));
+                sb.append('=');
+                sb.append(encode(param.getValue()));
+            }
+
+            return sb.toString();
+        }
+
+        /**
+         * Encode a name or value.
+         * The encoded result is the same as the input string
+         * except that each ',' is replaced by a '\,'.
+         * @param string the value to be encoded
+         * @return the encoded value.
+         */
+        public String encode(final String string) {
+            int end = string.indexOf(',');
+
+            if (-1 == end) {
+              return string;
+            }
+
+            final StringBuffer sb = new StringBuffer();
+
+            int start = 0;
+
+            while (-1 != end) {
+                sb.append(string.substring(start, end));
+                sb.append("\\,");
+                start = end + 1;
+                end = string.indexOf(',', start);
+            }
+
+            sb.append(string.substring(start));
+
+            return sb.toString();
+        }
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * The alias of signer.
+     */
+    protected String alias;
+
+    /**
+     * The name of keystore file.
+     */
+    protected String keystore;
+    protected String storepass;
+    protected String storetype;
+    protected String keypass;
+
+    protected String sigalg;
+    protected String keyalg;
+    protected String dname;
+    protected DistinguishedName expandedDname;
+    protected int keysize;
+    protected int validity;
+    protected boolean verbose;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Distinguished name list.
+     *
+     * @return Distinguished name container.
+     * @throws BuildException If specified more than once or dname
+     *                        attribute is used.
+     */
+    public DistinguishedName createDname() throws BuildException {
+        if (null != expandedDname) {
+            throw new BuildException("DName sub-element can only be "
+                                     + "specified once.");
+        }
+        if (null != dname) {
+            throw new BuildException("It is not possible to specify dname "
+                                    + " both as attribute and element.");
+        }
+        expandedDname = new DistinguishedName();
+        return expandedDname;
+    }
+
+    /**
+     * The distinguished name for entity.
+     *
+     * @param dname distinguished name
+     */
+    public void setDname(final String dname) {
+        if (null != expandedDname) {
+            throw new BuildException("It is not possible to specify dname "
+                                    + " both as attribute and element.");
+        }
+        this.dname = dname;
+    }
+
+    /**
+     * The alias to add under.
+     *
+     * @param alias alias to add under
+     */
+    public void setAlias(final String alias) {
+        this.alias = alias;
+    }
+
+    /**
+     * Keystore location.
+     *
+     * @param keystore location
+     */
+    public void setKeystore(final String keystore) {
+        this.keystore = keystore;
+    }
+
+    /**
+     * Password for keystore integrity.
+     * Must be at least 6 characters long.
+     * @param storepass password
+     */
+    public void setStorepass(final String storepass) {
+        this.storepass = storepass;
+    }
+
+    /**
+     * Keystore type.
+     *
+     * @param storetype type
+     */
+    public void setStoretype(final String storetype) {
+        this.storetype = storetype;
+    }
+
+    /**
+     * Password for private key (if different).
+     *
+     * @param keypass password
+     */
+    public void setKeypass(final String keypass) {
+        this.keypass = keypass;
+    }
+
+    /**
+     * The algorithm to use in signing.
+     *
+     * @param sigalg algorithm
+     */
+    public void setSigalg(final String sigalg) {
+        this.sigalg = sigalg;
+    }
+
+    /**
+     * The method to use when generating name-value pair.
+     * @param keyalg algorithm
+     */
+    public void setKeyalg(final String keyalg) {
+        this.keyalg = keyalg;
+    }
+
+    /**
+     * Indicates the size of key generated.
+     *
+     * @param keysize size of key
+     * @throws BuildException If not an Integer
+     * @todo Could convert this to a plain Integer setter.
+     */
+    public void setKeysize(final String keysize) throws BuildException {
+        try {
+            this.keysize = Integer.parseInt(keysize);
+        } catch (final NumberFormatException nfe) {
+            throw new BuildException("KeySize attribute should be a integer");
+        }
+    }
+
+    /**
+     * Indicates how many days certificate is valid.
+     *
+     * @param validity days valid
+     * @throws BuildException If not an Integer
+     */
+    public void setValidity(final String validity) throws BuildException {
+        try {
+            this.validity = Integer.parseInt(validity);
+        } catch (final NumberFormatException nfe) {
+            throw new BuildException("Validity attribute should be a integer");
+        }
+    }
+
+    /**
+     * If true, verbose output when signing.
+     * @param verbose verbose or not
+     */
+    public void setVerbose(final boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+
+        if (null == alias) {
+            throw new BuildException("alias attribute must be set");
+        }
+
+        if (null == storepass) {
+            throw new BuildException("storepass attribute must be set");
+        }
+
+        if (null == dname && null == expandedDname) {
+            throw new BuildException("dname must be set");
+        }
+
+        final StringBuffer sb = new StringBuffer();
+
+        sb.append("-genkey ");
+
+        if (verbose) {
+            sb.append("-v ");
+        }
+
+        sb.append("-alias \"");
+        sb.append(alias);
+        sb.append("\" ");
+
+        if (null != dname) {
+            sb.append("-dname \"");
+            sb.append(dname);
+            sb.append("\" ");
+        }
+
+        if (null != expandedDname) {
+            sb.append("-dname \"");
+            sb.append(expandedDname);
+            sb.append("\" ");
+        }
+
+        if (null != keystore) {
+            sb.append("-keystore \"");
+            sb.append(keystore);
+            sb.append("\" ");
+        }
+
+        if (null != storepass) {
+            sb.append("-storepass \"");
+            sb.append(storepass);
+            sb.append("\" ");
+        }
+
+        if (null != storetype) {
+            sb.append("-storetype \"");
+            sb.append(storetype);
+            sb.append("\" ");
+        }
+
+        sb.append("-keypass \"");
+        if (null != keypass) {
+            sb.append(keypass);
+        } else {
+            sb.append(storepass);
+        }
+        sb.append("\" ");
+
+        if (null != sigalg) {
+            sb.append("-sigalg \"");
+            sb.append(sigalg);
+            sb.append("\" ");
+        }
+
+        if (null != keyalg) {
+            sb.append("-keyalg \"");
+            sb.append(keyalg);
+            sb.append("\" ");
+        }
+
+
+        if (0 < keysize) {
+            sb.append("-keysize \"");
+            sb.append(keysize);
+            sb.append("\" ");
+        }
+
+        if (0 < validity) {
+            sb.append("-validity \"");
+            sb.append(validity);
+            sb.append("\" ");
+        }
+
+        log("Generating Key for " + alias);
+        final ExecTask cmd = new ExecTask(this);
+        cmd.setExecutable(JavaEnvUtils.getJdkExecutable("keytool"));
+        Commandline.Argument arg = cmd.createArg();
+        arg.setLine(sb.toString());
+        cmd.setFailonerror(true);
+        cmd.setTaskName(getTaskName());
+        cmd.execute();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Get.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Get.java
new file mode 100644
index 0000000..ea8fc1a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Get.java
@@ -0,0 +1,449 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Date;
+
+/**
+ * Gets a particular file from a URL source.
+ * Options include verbose reporting, timestamp based fetches and controlling
+ * actions on failures. NB: access through a firewall only works if the whole
+ * Java runtime is correctly configured.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="network"
+ */
+public class Get extends Task {
+    private static final int NUMBER_RETRIES = 3;
+    private static final int DOTS_PER_LINE = 50;
+    private static final int BIG_BUFFER_SIZE = 100 * 1024;
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private URL source; // required
+    private File dest; // required
+    private boolean verbose = false;
+    private boolean useTimestamp = false; //off by default
+    private boolean ignoreErrors = false;
+    private String uname = null;
+    private String pword = null;
+
+
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException Thrown in unrecoverable error.
+     */
+    public void execute() throws BuildException {
+
+        //set up logging
+        int logLevel = Project.MSG_INFO;
+        DownloadProgress progress = null;
+        if (verbose) {
+            progress = new VerboseProgress(System.out);
+        }
+
+        //execute the get
+        try {
+            doGet(logLevel, progress);
+        } catch (IOException ioe) {
+            log("Error getting " + source + " to " + dest);
+            if (!ignoreErrors) {
+                throw new BuildException(ioe, getLocation());
+            }
+        }
+    }
+
+    /**
+     * make a get request, with the supplied progress and logging info.
+     * All the other config parameters are set at the task level,
+     * source, dest, ignoreErrors, etc.
+     * @param logLevel level to log at, see {@link Project#log(String, int)}
+     * @param progress progress callback; null for no-callbacks
+     * @return true for a successful download, false otherwise.
+     * The return value is only relevant when {@link #ignoreErrors} is true, as
+     * when false all failures raise BuildExceptions.
+     * @throws IOException for network trouble
+     * @throws BuildException for argument errors, or other trouble when ignoreErrors
+     * is false.
+     */
+    public boolean doGet(int logLevel, DownloadProgress progress)
+            throws IOException {
+        checkAttributes();
+
+        //dont do any progress, unless asked
+        if (progress == null) {
+            progress = new NullProgress();
+        }
+        log("Getting: " + source, logLevel);
+        log("To: " + dest.getAbsolutePath(), logLevel);
+
+        //set the timestamp to the file date.
+        long timestamp = 0;
+
+        boolean hasTimestamp = false;
+        if (useTimestamp && dest.exists()) {
+            timestamp = dest.lastModified();
+            if (verbose) {
+                Date t = new Date(timestamp);
+                log("local file date : " + t.toString(), logLevel);
+            }
+            hasTimestamp = true;
+        }
+
+        //set up the URL connection
+        URLConnection connection = source.openConnection();
+        //modify the headers
+        //NB: things like user authentication could go in here too.
+        if (hasTimestamp) {
+            connection.setIfModifiedSince(timestamp);
+        }
+        // prepare Java 1.1 style credentials
+        if (uname != null || pword != null) {
+            String up = uname + ":" + pword;
+            String encoding;
+            //we do not use the sun impl for portability,
+            //and always use our own implementation for consistent
+            //testing
+            Base64Converter encoder = new Base64Converter();
+            encoding = encoder.encode(up.getBytes());
+            connection.setRequestProperty ("Authorization",
+                    "Basic " + encoding);
+        }
+
+        //connect to the remote site (may take some time)
+        connection.connect();
+        //next test for a 304 result (HTTP only)
+        if (connection instanceof HttpURLConnection) {
+            HttpURLConnection httpConnection
+                    = (HttpURLConnection) connection;
+            long lastModified = httpConnection.getLastModified();
+            if (httpConnection.getResponseCode()
+                    == HttpURLConnection.HTTP_NOT_MODIFIED
+                || (lastModified != 0 && hasTimestamp
+                && timestamp >= lastModified)) {
+                //not modified so no file download. just return
+                //instead and trace out something so the user
+                //doesn't think that the download happened when it
+                //didn't
+                log("Not modified - so not downloaded", logLevel);
+                return false;
+            }
+            // test for 401 result (HTTP only)
+            if (httpConnection.getResponseCode()
+                    == HttpURLConnection.HTTP_UNAUTHORIZED)  {
+                String message = "HTTP Authorization failure";
+                if (ignoreErrors) {
+                    log(message, logLevel);
+                    return false;
+                } else {
+                    throw new BuildException(message);
+                }
+            }
+
+        }
+
+        //REVISIT: at this point even non HTTP connections may
+        //support the if-modified-since behaviour -we just check
+        //the date of the content and skip the write if it is not
+        //newer. Some protocols (FTP) don't include dates, of
+        //course.
+
+        InputStream is = null;
+        for (int i = 0; i < NUMBER_RETRIES; i++) {
+            //this three attempt trick is to get round quirks in different
+            //Java implementations. Some of them take a few goes to bind
+            //property; we ignore the first couple of such failures.
+            try {
+                is = connection.getInputStream();
+                break;
+            } catch (IOException ex) {
+                log("Error opening connection " + ex, logLevel);
+            }
+        }
+        if (is == null) {
+            log("Can't get " + source + " to " + dest, logLevel);
+            if (ignoreErrors) {
+                return false;
+            }
+            throw new BuildException("Can't get " + source + " to " + dest,
+                    getLocation());
+        }
+
+        FileOutputStream fos = new FileOutputStream(dest);
+        progress.beginDownload();
+        boolean finished = false;
+        try {
+            byte[] buffer = new byte[BIG_BUFFER_SIZE];
+            int length;
+            while ((length = is.read(buffer)) >= 0) {
+                fos.write(buffer, 0, length);
+                progress.onTick();
+            }
+            finished = true;
+        } finally {
+            FileUtils.close(fos);
+            FileUtils.close(is);
+
+            // we have started to (over)write dest, but failed.
+            // Try to delete the garbage we'd otherwise leave
+            // behind.
+            if (!finished) {
+                dest.delete();
+            }
+        }
+        progress.endDownload();
+
+        //if (and only if) the use file time option is set, then
+        //the saved file now has its timestamp set to that of the
+        //downloaded file
+        if (useTimestamp)  {
+            long remoteTimestamp = connection.getLastModified();
+            if (verbose)  {
+                Date t = new Date(remoteTimestamp);
+                log("last modified = " + t.toString()
+                        + ((remoteTimestamp == 0)
+                        ? " - using current time instead"
+                        : ""), logLevel);
+            }
+            if (remoteTimestamp != 0) {
+                FILE_UTILS.setFileLastModified(dest, remoteTimestamp);
+            }
+        }
+
+        //successful download
+        return true;
+    }
+
+    /**
+     * Check the attributes.
+     */
+    private void checkAttributes() {
+        if (source == null) {
+            throw new BuildException("src attribute is required", getLocation());
+        }
+
+        if (dest == null) {
+            throw new BuildException("dest attribute is required", getLocation());
+        }
+
+        if (dest.exists() && dest.isDirectory()) {
+            throw new BuildException("The specified destination is a directory",
+                    getLocation());
+        }
+
+        if (dest.exists() && !dest.canWrite()) {
+            throw new BuildException("Can't write to " + dest.getAbsolutePath(),
+                    getLocation());
+        }
+    }
+
+    /**
+     * Set the URL to get.
+     *
+     * @param u URL for the file.
+     */
+    public void setSrc(URL u) {
+        this.source = u;
+    }
+
+    /**
+     * Where to copy the source file.
+     *
+     * @param dest Path to file.
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    /**
+     * If true, show verbose progress information.
+     *
+     * @param v if "true" then be verbose
+     */
+    public void setVerbose(boolean v) {
+        verbose = v;
+    }
+
+    /**
+     * If true, log errors but do not treat as fatal.
+     *
+     * @param v if "true" then don't report download errors up to ant
+     */
+    public void setIgnoreErrors(boolean v) {
+        ignoreErrors = v;
+    }
+
+    /**
+     * If true, conditionally download a file based on the timestamp
+     * of the local copy.
+     *
+     * <p>In this situation, the if-modified-since header is set so
+     * that the file is only fetched if it is newer than the local
+     * file (or there is no local file) This flag is only valid on
+     * HTTP connections, it is ignored in other cases.  When the flag
+     * is set, the local copy of the downloaded file will also have
+     * its timestamp set to the remote file time.</p>
+     *
+     * <p>Note that remote files of date 1/1/1970 (GMT) are treated as
+     * 'no timestamp', and web servers often serve files with a
+     * timestamp in the future by replacing their timestamp with that
+     * of the current time. Also, inter-computer clock differences can
+     * cause no end of grief.</p>
+     * @param v "true" to enable file time fetching
+     */
+    public void setUseTimestamp(boolean v) {
+        useTimestamp = v;
+    }
+
+
+    /**
+     * Username for basic auth.
+     *
+     * @param u username for authentication
+     */
+    public void setUsername(String u) {
+        this.uname = u;
+    }
+
+    /**
+     * password for the basic authentication.
+     *
+     * @param p password for authentication
+     */
+    public void setPassword(String p) {
+        this.pword = p;
+    }
+
+    /**
+     * Provide this for Backward Compatibility.
+     */
+    protected static class Base64Converter
+        extends org.apache.tools.ant.util.Base64Converter {
+    }
+
+    /**
+     * Interface implemented for reporting
+     * progess of downloading.
+     */
+    public interface DownloadProgress {
+        /**
+         * begin a download
+         */
+        void beginDownload();
+
+        /**
+         * tick handler
+         *
+         */
+        void onTick();
+
+        /**
+         * end a download
+         */
+        void endDownload();
+    }
+
+    /**
+     * do nothing with progress info
+     */
+    public static class NullProgress implements DownloadProgress {
+
+        /**
+         * begin a download
+         */
+        public void beginDownload() {
+
+        }
+
+        /**
+         * tick handler
+         *
+         */
+        public void onTick() {
+        }
+
+        /**
+         * end a download
+         */
+        public void endDownload() {
+
+        }
+    }
+
+    /**
+     * verbose progress system prints to some output stream
+     */
+    public static class VerboseProgress implements DownloadProgress  {
+        private int dots = 0;
+        // CheckStyle:VisibilityModifier OFF - bc
+        PrintStream out;
+        // CheckStyle:VisibilityModifier ON
+
+        /**
+         * Construct a verbose progress reporter.
+         * @param out the output stream.
+         */
+        public VerboseProgress(PrintStream out) {
+            this.out = out;
+        }
+
+        /**
+         * begin a download
+         */
+        public void beginDownload() {
+            dots = 0;
+        }
+
+        /**
+         * tick handler
+         *
+         */
+        public void onTick() {
+            out.print(".");
+            if (dots++ > DOTS_PER_LINE) {
+                out.flush();
+                dots = 0;
+            }
+        }
+
+        /**
+         * end a download
+         */
+        public void endDownload() {
+            out.println();
+            out.flush();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ImportTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ImportTask.java
new file mode 100644
index 0000000..702a3ad
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ImportTask.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+import java.util.Vector;
+
+/**
+ * Task to import another build file into the current project.
+ * <p>
+ * It must be 'top level'. On execution it will read another Ant file
+ * into the same Project.
+ * </p>
+ * <p>
+ * <b>Important</b>: we have not finalized how relative file references
+ * will be resolved in deep/complex build hierarchies - such as what happens
+ * when an imported file imports another file. Use absolute references for
+ * enhanced build file stability, especially in the imported files.
+ * </p>
+ * <p>Examples:</p>
+ * <pre>
+ * &lt;import file="../common-targets.xml"/&gt;
+ * </pre>
+ * <p>Import targets from a file in a parent directory.</p>
+ * <pre>
+ * &lt;import file="${deploy-platform}.xml"/&gt;
+ * </pre>
+ * <p>Import the project defined by the property <code>deploy-platform</code>.</p>
+ *
+ * @since Ant1.6
+ * @ant.task category="control"
+ */
+public class ImportTask extends Task {
+    private String file;
+    private boolean optional;
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * sets the optional attribute
+     *
+     * @param optional if true ignore files that are not present,
+     *                 default is false
+     */
+    public void setOptional(boolean optional) {
+        this.optional = optional;
+    }
+
+    /**
+     * the name of the file to import. How relative paths are resolved is still
+     * in flux: use absolute paths for safety.
+     * @param file the name of the file
+     */
+    public void setFile(String file) {
+        // I don't think we can use File - different rules
+        // for relative paths.
+        this.file = file;
+    }
+
+    /**
+     *  This relies on the task order model.
+     *
+     */
+    public void execute() {
+        if (file == null) {
+            throw new BuildException("import requires file attribute");
+        }
+        if (getOwningTarget() == null
+            || !"".equals(getOwningTarget().getName())) {
+            throw new BuildException("import only allowed as a top-level task");
+        }
+
+        ProjectHelper helper =
+                (ProjectHelper) getProject().
+                    getReference(ProjectHelper.PROJECTHELPER_REFERENCE);
+
+        if (helper == null) {
+            // this happens if the projecthelper was not registered with the project.
+            throw new BuildException("import requires support in ProjectHelper");
+        }
+
+        Vector importStack = helper.getImportStack();
+
+        if (importStack.size() == 0) {
+            // this happens if ant is used with a project
+            // helper that doesn't set the import.
+            throw new BuildException("import requires support in ProjectHelper");
+        }
+
+        if (getLocation() == null || getLocation().getFileName() == null) {
+            throw new BuildException("Unable to get location of import task");
+        }
+
+        File buildFile = new File(getLocation().getFileName()).getAbsoluteFile();
+
+        // Paths are relative to the build file they're imported from,
+        // *not* the current directory (same as entity includes).
+
+        File buildFileParent = new File(buildFile.getParent());
+        File importedFile = FILE_UTILS.resolveFile(buildFileParent, file);
+
+        getProject().log("Importing file " + importedFile + " from "
+                         + buildFile.getAbsolutePath(), Project.MSG_VERBOSE);
+
+        if (!importedFile.exists()) {
+            String message =
+                "Cannot find " + file + " imported from "
+                + buildFile.getAbsolutePath();
+            if (optional) {
+                getProject().log(message, Project.MSG_VERBOSE);
+                return;
+            } else {
+                throw new BuildException(message);
+            }
+        }
+
+        if (importStack.contains(importedFile)) {
+            getProject().log(
+                "Skipped already imported file:\n   "
+                + importedFile + "\n", Project.MSG_VERBOSE);
+            return;
+        }
+
+        try {
+            helper.parse(getProject(), importedFile);
+        } catch (BuildException ex) {
+            throw ProjectHelper.addLocationToBuildException(
+                ex, getLocation());
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Input.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Input.java
new file mode 100644
index 0000000..72479c4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Input.java
@@ -0,0 +1,256 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.GreedyInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.input.InputRequest;
+import org.apache.tools.ant.input.MultipleChoiceInputRequest;
+import org.apache.tools.ant.input.PropertyFileInputHandler;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Reads an input line from the console.
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="control"
+ */
+public class Input extends Task {
+
+    /**
+     * Represents an InputHandler.
+     */
+    public class Handler extends DefBase {
+
+        private String refid = null;
+        private HandlerType type = null;
+        private String classname = null;
+
+        /**
+         * Specify that the handler is a reference on the project;
+         * this allows the use of a custom inputhandler.
+         * @param refid the String refid.
+         */
+        public void setRefid(String refid) {
+            this.refid = refid;
+        }
+        /**
+         * Get the refid of this Handler.
+         * @return String refid.
+         */
+        public String getRefid() {
+            return refid;
+        }
+        /**
+         * Set the InputHandler classname.
+         * @param classname the String classname.
+         */
+        public void setClassname(String classname) {
+            this.classname = classname;
+        }
+        /**
+         * Get the classname of the InputHandler.
+         * @return String classname.
+         */
+        public String getClassname() {
+            return classname;
+        }
+        /**
+         * Set the handler type.
+         * @param type a HandlerType.
+         */
+        public void setType(HandlerType type) {
+            this.type = type;
+        }
+        /**
+         * Get the handler type.
+         * @return a HandlerType object.
+         */
+        public HandlerType getType() {
+            return type;
+        }
+        private InputHandler getInputHandler() {
+            if (type != null) {
+               return type.getInputHandler();
+            }
+            if (refid != null) {
+               try {
+                   return (InputHandler) (getProject().getReference(refid));
+               } catch (ClassCastException e) {
+                   throw new BuildException(
+                       refid + " does not denote an InputHandler", e);
+               }
+            }
+            if (classname != null) {
+               return (InputHandler) (ClasspathUtils.newInstance(classname,
+                   createLoader(), InputHandler.class));
+            }
+            throw new BuildException(
+                "Must specify refid, classname or type");
+        }
+    }
+
+    /**
+     * EnumeratedAttribute representing the built-in input handler types:
+     * "default", "propertyfile", "greedy".
+     */
+    public static class HandlerType extends EnumeratedAttribute {
+        private static final String[] VALUES
+            = {"default", "propertyfile", "greedy"};
+
+        private static final InputHandler[] HANDLERS
+            = {new DefaultInputHandler(),
+               new PropertyFileInputHandler(),
+               new GreedyInputHandler()};
+
+        /** {@inheritDoc} */
+        public String[] getValues() {
+            return VALUES;
+        }
+        private InputHandler getInputHandler() {
+            return HANDLERS[getIndex()];
+        }
+    }
+
+    private String validargs = null;
+    private String message = "";
+    private String addproperty = null;
+    private String defaultvalue = null;
+    private Handler handler = null;
+    private boolean messageAttribute;
+
+    /**
+     * Defines valid input parameters as comma separated strings. If set, input
+     * task will reject any input not defined as accepted and requires the user
+     * to reenter it. Validargs are case sensitive. If you want 'a' and 'A' to
+     * be accepted you need to define both values as accepted arguments.
+     *
+     * @param validargs A comma separated String defining valid input args.
+     */
+    public void setValidargs (String validargs) {
+        this.validargs = validargs;
+    }
+
+    /**
+     * Defines the name of a property to be created from input. Behaviour is
+     * according to property task which means that existing properties
+     * cannot be overridden.
+     *
+     * @param addproperty Name for the property to be created from input
+     */
+    public void setAddproperty (String addproperty) {
+        this.addproperty = addproperty;
+    }
+
+    /**
+     * Sets the Message which gets displayed to the user during the build run.
+     * @param message The message to be displayed.
+     */
+    public void setMessage (String message) {
+        this.message = message;
+        messageAttribute = true;
+    }
+
+    /**
+     * Defines the default value of the property to be created from input.
+     * Property value will be set to default if not input is received.
+     *
+     * @param defaultvalue Default value for the property if no input
+     * is received
+     */
+    public void setDefaultvalue (String defaultvalue) {
+        this.defaultvalue = defaultvalue;
+    }
+
+    /**
+     * Set a multiline message.
+     * @param msg The message to be displayed.
+     */
+    public void addText(String msg) {
+        if (messageAttribute && "".equals(msg.trim())) {
+            return;
+        }
+        message += getProject().replaceProperties(msg);
+    }
+
+    /**
+     * No arg constructor.
+     */
+    public Input () {
+    }
+
+    /**
+     * Actual method executed by ant.
+     * @throws BuildException on error
+     */
+    public void execute () throws BuildException {
+        if (addproperty != null
+            && getProject().getProperty(addproperty) != null) {
+            log("skipping " + getTaskName() + " as property " + addproperty
+                + " has already been set.");
+            return;
+        }
+
+        InputRequest request = null;
+        if (validargs != null) {
+            Vector accept = StringUtils.split(validargs, ',');
+            request = new MultipleChoiceInputRequest(message, accept);
+        } else {
+            request = new InputRequest(message);
+        }
+        request.setDefaultValue(defaultvalue);
+
+        InputHandler h = handler == null
+            ? getProject().getInputHandler()
+            : handler.getInputHandler();
+
+        h.handleInput(request);
+
+        String value = request.getInput();
+        if ((value == null || value.trim().length() == 0)
+            && defaultvalue != null) {
+            value = defaultvalue;
+        }
+        if (addproperty != null && value != null) {
+            getProject().setNewProperty(addproperty, value);
+        }
+    }
+
+    /**
+     * Create a nested handler element.
+     * @return a Handler for this Input task.
+     */
+    public Handler createHandler() {
+        if (handler != null) {
+            throw new BuildException(
+                "Cannot define > 1 nested input handler");
+        }
+        handler = new Handler();
+        return handler;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/JDBCTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/JDBCTask.java
new file mode 100644
index 0000000..1a0e138
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/JDBCTask.java
@@ -0,0 +1,472 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Locale;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Handles JDBC configuration needed by SQL type tasks.
+ * <p>
+ * The following example class prints the contents of the first column of each row in TableName.
+ *</p>
+ *<code><pre>
+package examples;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.JDBCTask;
+
+public class SQLExampleTask extends JDBCTask {
+
+    private String tableName;
+
+    public void execute() throws BuildException {
+        Connection conn = getConnection();
+        Statement stmt=null;
+        try {
+            if (tableName == null) {
+                throw new BuildException("TableName must be specified",location);
+            }
+            String sql = "SELECT * FROM "+tableName;
+            stmt= conn.createStatement();
+            ResultSet rs = stmt.executeQuery(sql);
+            while (rs.next()) {
+                log(rs.getObject(1).toString());
+            }
+        } catch (SQLException e) {
+
+        } finally {
+            if (stmt != null) {
+                try {stmt.close();}catch (SQLException ingore) {}
+            }
+            if (conn != null) {
+                try {conn.close();}catch (SQLException ingore) {}
+            }
+        }
+    }
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+}
+
+
+</pre></code>
+
+
+
+ * @since Ant 1.5
+ *
+ */
+
+public abstract class JDBCTask extends Task {
+    private static final int HASH_TABLE_SIZE = 3;
+
+    /**
+     * Used for caching loaders / driver. This is to avoid
+     * getting an OutOfMemoryError when calling this task
+     * multiple times in a row.
+     */
+    private static Hashtable loaderMap = new Hashtable(HASH_TABLE_SIZE);
+
+    private boolean caching = true;
+
+    private Path classpath;
+
+    private AntClassLoader loader;
+
+    /**
+     * Autocommit flag. Default value is false
+     */
+    private boolean autocommit = false;
+
+    /**
+     * DB driver.
+     */
+    private String driver = null;
+
+    /**
+     * DB url.
+     */
+    private String url = null;
+
+    /**
+     * User name.
+     */
+    private String userId = null;
+
+    /**
+     * Password
+     */
+    private String password = null;
+
+    /**
+     * RDBMS Product needed for this SQL.
+     **/
+    private String rdbms = null;
+
+    /**
+     * RDBMS Version needed for this SQL.
+     **/
+    private String version = null;
+
+    /**
+     * Sets the classpath for loading the driver.
+     * @param classpath The classpath to set
+     */
+    public void setClasspath(Path classpath) {
+        this.classpath = classpath;
+    }
+
+    /**
+     * Caching loaders / driver. This is to avoid
+     * getting an OutOfMemoryError when calling this task
+     * multiple times in a row; default: true
+     * @param enable a <code>boolean</code> value
+     */
+    public void setCaching(boolean enable) {
+        caching = enable;
+    }
+
+    /**
+     * Add a path to the classpath for loading the driver.
+     * @return a path to be configured
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Set the classpath for loading the driver
+     * using the classpath reference.
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Class name of the JDBC driver; required.
+     * @param driver The driver to set
+     */
+    public void setDriver(String driver) {
+        this.driver = driver.trim();
+    }
+
+    /**
+     * Sets the database connection URL; required.
+     * @param url The url to set
+     */
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * Sets the password; required.
+     * @param password The password to set
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Auto commit flag for database connection;
+     * optional, default false.
+     * @param autocommit The autocommit to set
+     */
+    public void setAutocommit(boolean autocommit) {
+        this.autocommit = autocommit;
+    }
+
+    /**
+     * Execute task only if the lower case product name
+     * of the DB matches this
+     * @param rdbms The rdbms to set
+     */
+    public void setRdbms(String rdbms) {
+        this.rdbms = rdbms;
+    }
+
+    /**
+     * Sets the version string, execute task only if
+     * rdbms version match; optional.
+     * @param version The version to set
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * Verify we are connected to the correct RDBMS
+     * @param conn the jdbc connection
+     * @return true if we are connected to the correct RDBMS
+     */
+    protected boolean isValidRdbms(Connection conn) {
+        if (rdbms == null && version == null) {
+            return true;
+        }
+
+        try {
+            DatabaseMetaData dmd = conn.getMetaData();
+
+            if (rdbms != null) {
+                String theVendor = dmd.getDatabaseProductName().toLowerCase();
+
+                log("RDBMS = " + theVendor, Project.MSG_VERBOSE);
+                if (theVendor == null || theVendor.indexOf(rdbms) < 0) {
+                    log("Not the required RDBMS: " + rdbms, Project.MSG_VERBOSE);
+                    return false;
+                }
+            }
+
+            if (version != null) {
+                String theVersion = dmd.getDatabaseProductVersion().toLowerCase(Locale.ENGLISH);
+
+                log("Version = " + theVersion, Project.MSG_VERBOSE);
+                if (theVersion == null
+                        || !(theVersion.startsWith(version)
+                        || theVersion.indexOf(" " + version) >= 0)) {
+                    log("Not the required version: \"" + version + "\"", Project.MSG_VERBOSE);
+                    return false;
+                }
+            }
+        } catch (SQLException e) {
+            // Could not get the required information
+            log("Failed to obtain required RDBMS information", Project.MSG_ERR);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the cache of loaders and drivers.
+     * @return a hashtable
+     */
+    protected static Hashtable getLoaderMap() {
+        return loaderMap;
+    }
+
+    /**
+     * Get the classloader used to create a driver.
+     * @return the classloader
+     */
+    protected AntClassLoader getLoader() {
+        return loader;
+    }
+
+    /**
+     * Creates a new Connection as using the driver, url, userid and password
+     * specified.
+     *
+     * The calling method is responsible for closing the connection.
+     *
+     * @return Connection the newly created connection.
+     * @throws BuildException if the UserId/Password/Url is not set or there
+     * is no suitable driver or the driver fails to load.
+     */
+    protected Connection getConnection() throws BuildException {
+        if (userId == null) {
+            throw new BuildException("UserId attribute must be set!", getLocation());
+        }
+        if (password == null) {
+            throw new BuildException("Password attribute must be set!", getLocation());
+        }
+        if (url == null) {
+            throw new BuildException("Url attribute must be set!", getLocation());
+        }
+        try {
+
+            log("connecting to " + getUrl(), Project.MSG_VERBOSE);
+            Properties info = new Properties();
+            info.put("user", getUserId());
+            info.put("password", getPassword());
+            Connection conn = getDriver().connect(getUrl(), info);
+
+            if (conn == null) {
+                // Driver doesn't understand the URL
+                throw new SQLException("No suitable Driver for " + url);
+            }
+
+            conn.setAutoCommit(autocommit);
+            return conn;
+        } catch (SQLException e) {
+            throw new BuildException(e, getLocation());
+        }
+
+    }
+
+    /**
+     * Gets an instance of the required driver.
+     * Uses the ant class loader and the optionally the provided classpath.
+     * @return Driver
+     * @throws BuildException
+     */
+    private Driver getDriver() throws BuildException {
+        if (driver == null) {
+            throw new BuildException("Driver attribute must be set!", getLocation());
+        }
+
+        Driver driverInstance = null;
+        try {
+            Class dc;
+            if (classpath != null) {
+                // check first that it is not already loaded otherwise
+                // consecutive runs seems to end into an OutOfMemoryError
+                // or it fails when there is a native library to load
+                // several times.
+                // this is far from being perfect but should work
+                // in most cases.
+                synchronized (loaderMap) {
+                    if (caching) {
+                        loader = (AntClassLoader) loaderMap.get(driver);
+                    }
+                    if (loader == null) {
+                        log("Loading " + driver
+                            + " using AntClassLoader with classpath "
+                            + classpath, Project.MSG_VERBOSE);
+                        loader = getProject().createClassLoader(classpath);
+                        if (caching) {
+                            loaderMap.put(driver, loader);
+                        }
+                    } else {
+                        log("Loading " + driver
+                            + " using a cached AntClassLoader.",
+                                Project.MSG_VERBOSE);
+                    }
+                }
+                dc = loader.loadClass(driver);
+            } else {
+                log("Loading " + driver + " using system loader.",
+                    Project.MSG_VERBOSE);
+                dc = Class.forName(driver);
+            }
+            driverInstance = (Driver) dc.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new BuildException(
+                    "Class Not Found: JDBC driver " + driver + " could not be loaded",
+                    e,
+                    getLocation());
+        } catch (IllegalAccessException e) {
+            throw new BuildException(
+                    "Illegal Access: JDBC driver " + driver + " could not be loaded",
+                    e,
+                    getLocation());
+        } catch (InstantiationException e) {
+            throw new BuildException(
+                    "Instantiation Exception: JDBC driver " + driver + " could not be loaded",
+                    e,
+                    getLocation());
+        }
+        return driverInstance;
+    }
+
+
+    /**
+     * Set the caching attribute.
+     * @param value a <code>boolean</code> value
+     */
+    public void isCaching(boolean value) {
+        caching = value;
+    }
+
+    /**
+     * Gets the classpath.
+     * @return Returns a Path
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Gets the autocommit.
+     * @return Returns a boolean
+     */
+    public boolean isAutocommit() {
+        return autocommit;
+    }
+
+    /**
+     * Gets the url.
+     * @return Returns a String
+     */
+    public String getUrl() {
+        return url;
+    }
+
+    /**
+     * Gets the userId.
+     * @return Returns a String
+     */
+    public String getUserId() {
+        return userId;
+    }
+
+    /**
+     * Set the user name for the connection; required.
+     * @param userId The userId to set
+     */
+    public void setUserid(String userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * Gets the password.
+     * @return Returns a String
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * Gets the rdbms.
+     * @return Returns a String
+     */
+    public String getRdbms() {
+        return rdbms;
+    }
+
+    /**
+     * Gets the version.
+     * @return Returns a String
+     */
+    public String getVersion() {
+        return version;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Jar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Jar.java
new file mode 100644
index 0000000..0806713
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Jar.java
@@ -0,0 +1,1061 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Manifest.Section;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.ant.types.spi.Service;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.zip.JarMarker;
+import org.apache.tools.zip.ZipExtraField;
+import org.apache.tools.zip.ZipOutputStream;
+
+/**
+ * Creates a JAR archive.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+public class Jar extends Zip {
+    /** The index file name. */
+    private static final String INDEX_NAME = "META-INF/INDEX.LIST";
+
+    /** The manifest file name. */
+    private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+    /**
+     * List of all known SPI Services
+     */
+    private List serviceList = new ArrayList();
+
+    /** merged manifests added through addConfiguredManifest */
+    private Manifest configuredManifest;
+
+    /** shadow of the above if upToDate check alters the value */
+    private Manifest savedConfiguredManifest;
+
+    /**  merged manifests added through filesets */
+    private Manifest filesetManifest;
+
+    /**
+     * Manifest of original archive, will be set to null if not in
+     * update mode.
+     */
+    private Manifest originalManifest;
+
+    /**
+     *  whether to merge fileset manifests;
+     *  value is true if filesetmanifest is 'merge' or 'mergewithoutmain'
+     */
+    private FilesetManifestConfig filesetManifestConfig;
+
+    /**
+     * whether to merge the main section of fileset manifests;
+     * value is true if filesetmanifest is 'merge'
+     */
+    private boolean mergeManifestsMain = true;
+
+    /** the manifest specified by the 'manifest' attribute **/
+    private Manifest manifest;
+
+    /** The encoding to use when reading in a manifest file */
+    private String manifestEncoding;
+
+    /**
+     * The file found from the 'manifest' attribute.  This can be
+     * either the location of a manifest, or the name of a jar added
+     * through a fileset.  If its the name of an added jar, the
+     * manifest is looked for in META-INF/MANIFEST.MF
+     */
+    private File manifestFile;
+
+    /** jar index is JDK 1.3+ only */
+    private boolean index = false;
+
+    /**
+     * whether to really create the archive in createEmptyZip, will
+     * get set in getResourcesToAdd.
+     */
+    private boolean createEmpty = false;
+
+    /**
+     * Stores all files that are in the root of the archive (i.e. that
+     * have a name that doesn't contain a slash) so they can get
+     * listed in the index.
+     *
+     * Will not be filled unless the user has asked for an index.
+     *
+     * @since Ant 1.6
+     */
+    private Vector rootEntries;
+
+    /**
+     * Path containing jars that shall be indexed in addition to this archive.
+     *
+     * @since Ant 1.6.2
+     */
+    private Path indexJars;
+
+    // CheckStyle:LineLength OFF - Link is too long.
+    /**
+     * Strict mode for checking rules of the JAR-Specification.
+     * @see http://java.sun.com/j2se/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning
+     */
+    private StrictMode strict = new StrictMode("ignore");
+
+    // CheckStyle:LineLength ON
+
+    /**
+     * Extra fields needed to make Solaris recognize the archive as a jar file.
+     *
+     * @since Ant 1.6.3
+     */
+    private static final ZipExtraField[] JAR_MARKER = new ZipExtraField[] {
+        JarMarker.getInstance()
+    };
+
+    /** constructor */
+    public Jar() {
+        super();
+        archiveType = "jar";
+        emptyBehavior = "create";
+        setEncoding("UTF8");
+        rootEntries = new Vector();
+    }
+
+    /**
+     * Not used for jar files.
+     * @param we not used
+     * @ant.attribute ignore="true"
+     */
+    public void setWhenempty(WhenEmpty we) {
+        log("JARs are never empty, they contain at least a manifest file",
+            Project.MSG_WARN);
+    }
+
+    /**
+     * Indicates if a jar file should be created when it would only contain a
+     * manifest file.
+     * Possible values are: <code>fail</code> (throw an exception
+     * and halt the build); <code>skip</code> (do not create
+     * any archive, but issue a warning); <code>create</code>
+     * (make an archive with only a manifest file).
+     * Default is <code>create</code>;
+     * @param we a <code>WhenEmpty</code> enumerated value
+     */
+    public void setWhenmanifestonly(WhenEmpty we) {
+        emptyBehavior = we.getValue();
+    }
+
+    /**
+     * Activate the strict mode. When set to <i>true</i> a BuildException
+     * will be thrown if the Jar-Packaging specification was broken.
+     * @param strict New value of the strict mode.
+     * @since Ant 1.7.1
+     */
+    public void setStrict(StrictMode strict) {
+        this.strict = strict;
+    }
+
+    /**
+     * Set the destination file.
+     * @param jarFile the destination file
+     * @deprecated since 1.5.x.
+     *             Use setDestFile(File) instead.
+     */
+    public void setJarfile(File jarFile) {
+        setDestFile(jarFile);
+    }
+
+    /**
+     * Set whether or not to create an index list for classes.
+     * This may speed up classloading in some cases.
+     * @param flag a <code>boolean</code> value
+     */
+    public void setIndex(boolean flag) {
+        index = flag;
+    }
+
+    /**
+     * The character encoding to use in the manifest file.
+     *
+     * @param manifestEncoding the character encoding
+     */
+    public void setManifestEncoding(String manifestEncoding) {
+        this.manifestEncoding = manifestEncoding;
+    }
+
+    /**
+     * Allows the manifest for the archive file to be provided inline
+     * in the build file rather than in an external file.
+     *
+     * @param newManifest an embedded manifest element
+     * @throws ManifestException on error
+     */
+    public void addConfiguredManifest(Manifest newManifest)
+        throws ManifestException {
+        if (configuredManifest == null) {
+            configuredManifest = newManifest;
+        } else {
+            configuredManifest.merge(newManifest);
+        }
+        savedConfiguredManifest = configuredManifest;
+    }
+
+    /**
+     * The manifest file to use. This can be either the location of a manifest,
+     * or the name of a jar added through a fileset. If its the name of an added
+     * jar, the task expects the manifest to be in the jar at META-INF/MANIFEST.MF.
+     *
+     * @param manifestFile the manifest file to use.
+     */
+    public void setManifest(File manifestFile) {
+        if (!manifestFile.exists()) {
+            throw new BuildException("Manifest file: " + manifestFile
+                                     + " does not exist.", getLocation());
+        }
+
+        this.manifestFile = manifestFile;
+    }
+
+    private Manifest getManifest(File manifestFile) {
+
+        Manifest newManifest = null;
+        FileInputStream fis = null;
+        InputStreamReader isr = null;
+        try {
+            fis = new FileInputStream(manifestFile);
+            if (manifestEncoding == null) {
+                isr = new InputStreamReader(fis);
+            } else {
+                isr = new InputStreamReader(fis, manifestEncoding);
+            }
+            newManifest = getManifest(isr);
+        } catch (UnsupportedEncodingException e) {
+            throw new BuildException("Unsupported encoding while reading manifest: "
+                                     + e.getMessage(), e);
+        } catch (IOException e) {
+            throw new BuildException("Unable to read manifest file: "
+                                     + manifestFile
+                                     + " (" + e.getMessage() + ")", e);
+        } finally {
+            FileUtils.close(isr);
+        }
+        return newManifest;
+    }
+
+    /**
+     * @return null if jarFile doesn't contain a manifest, the
+     * manifest otherwise.
+     * @since Ant 1.5.2
+     */
+    private Manifest getManifestFromJar(File jarFile) throws IOException {
+        ZipFile zf = null;
+        try {
+            zf = new ZipFile(jarFile);
+
+            // must not use getEntry as "well behaving" applications
+            // must accept the manifest in any capitalization
+            Enumeration e = zf.entries();
+            while (e.hasMoreElements()) {
+                ZipEntry ze = (ZipEntry) e.nextElement();
+                if (ze.getName().equalsIgnoreCase(MANIFEST_NAME)) {
+                    InputStreamReader isr =
+                        new InputStreamReader(zf.getInputStream(ze), "UTF-8");
+                    return getManifest(isr);
+                }
+            }
+            return null;
+        } finally {
+            if (zf != null) {
+                try {
+                    zf.close();
+                } catch (IOException e) {
+                    // XXX - log an error?  throw an exception?
+                }
+            }
+        }
+    }
+
+    private Manifest getManifest(Reader r) {
+
+        Manifest newManifest = null;
+        try {
+            newManifest = new Manifest(r);
+        } catch (ManifestException e) {
+            log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
+            throw new BuildException("Invalid Manifest: " + manifestFile,
+                                     e, getLocation());
+        } catch (IOException e) {
+            throw new BuildException("Unable to read manifest file"
+                                     + " (" + e.getMessage() + ")", e);
+        }
+        return newManifest;
+    }
+
+    /**
+     * Behavior when a Manifest is found in a zipfileset or zipgroupfileset file.
+     * Valid values are "skip", "merge", and "mergewithoutmain".
+     * "merge" will merge all of manifests together, and merge this into any
+     * other specified manifests.
+     * "mergewithoutmain" merges everything but the Main section of the manifests.
+     * Default value is "skip".
+     *
+     * Note: if this attribute's value is not "skip", the created jar will not
+     * be readable by using java.util.jar.JarInputStream
+     *
+     * @param config setting for found manifest behavior.
+     */
+    public void setFilesetmanifest(FilesetManifestConfig config) {
+        filesetManifestConfig = config;
+        mergeManifestsMain = "merge".equals(config.getValue());
+
+        if (filesetManifestConfig != null
+            && !filesetManifestConfig.getValue().equals("skip")) {
+
+            doubleFilePass = true;
+        }
+    }
+
+    /**
+     * Adds a zipfileset to include in the META-INF directory.
+     *
+     * @param fs zipfileset to add
+     */
+    public void addMetainf(ZipFileSet fs) {
+        // We just set the prefix for this fileset, and pass it up.
+        fs.setPrefix("META-INF/");
+        super.addFileset(fs);
+    }
+
+    /**
+     * Add a path to index jars.
+     * @param p a path
+     * @since Ant 1.6.2
+     */
+    public void addConfiguredIndexJars(Path p) {
+        if (indexJars == null) {
+            indexJars = new Path(getProject());
+        }
+        indexJars.append(p);
+    }
+
+    /**
+     * A nested SPI service element.
+     * @param service the nested element.
+     * @since Ant 1.7
+     */
+    public void addConfiguredService(Service service) {
+        // Check if the service is configured correctly
+        service.check();
+        serviceList.add(service);
+    }
+
+    /**
+     * Write SPI Information to JAR
+     */
+    private void writeServices(ZipOutputStream zOut) throws IOException {
+        Iterator serviceIterator;
+        Service service;
+
+        serviceIterator = serviceList.iterator();
+        while (serviceIterator.hasNext()) {
+           service = (Service) serviceIterator.next();
+           //stolen from writeManifest
+           super.zipFile(service.getAsStream(), zOut,
+                         "META-INF/services/" + service.getType(),
+                         System.currentTimeMillis(), null,
+                         ZipFileSet.DEFAULT_FILE_MODE);
+        }
+    }
+
+
+    /**
+     * Initialize the zip output stream.
+     * @param zOut the zip output stream
+     * @throws IOException on I/O errors
+     * @throws BuildException on other errors
+     */
+    protected void initZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+
+        if (!skipWriting) {
+            Manifest jarManifest = createManifest();
+            writeManifest(zOut, jarManifest);
+            writeServices(zOut);
+        }
+    }
+
+    private Manifest createManifest()
+        throws BuildException {
+        try {
+            Manifest finalManifest = Manifest.getDefaultManifest();
+
+            if (manifest == null) {
+                if (manifestFile != null) {
+                    // if we haven't got the manifest yet, attempt to
+                    // get it now and have manifest be the final merge
+                    manifest = getManifest(manifestFile);
+                }
+            }
+
+            /*
+             * Precedence: manifestFile wins over inline manifest,
+             * over manifests read from the filesets over the original
+             * manifest.
+             *
+             * merge with null argument is a no-op
+             */
+
+            if (isInUpdateMode()) {
+                finalManifest.merge(originalManifest);
+            }
+            finalManifest.merge(filesetManifest);
+            finalManifest.merge(configuredManifest);
+            finalManifest.merge(manifest, !mergeManifestsMain);
+
+            return finalManifest;
+
+        } catch (ManifestException e) {
+            log("Manifest is invalid: " + e.getMessage(), Project.MSG_ERR);
+            throw new BuildException("Invalid Manifest", e, getLocation());
+        }
+    }
+
+    private void writeManifest(ZipOutputStream zOut, Manifest manifest)
+        throws IOException {
+        for (Enumeration e = manifest.getWarnings();
+             e.hasMoreElements();) {
+            log("Manifest warning: " + e.nextElement(),
+                Project.MSG_WARN);
+        }
+
+        zipDir(null, zOut, "META-INF/", ZipFileSet.DEFAULT_DIR_MODE,
+               JAR_MARKER);
+        // time to write the manifest
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        OutputStreamWriter osw = new OutputStreamWriter(baos, Manifest.JAR_ENCODING);
+        PrintWriter writer = new PrintWriter(osw);
+        manifest.write(writer);
+        writer.close();
+
+        ByteArrayInputStream bais =
+            new ByteArrayInputStream(baos.toByteArray());
+        super.zipFile(bais, zOut, MANIFEST_NAME,
+                      System.currentTimeMillis(), null,
+                      ZipFileSet.DEFAULT_FILE_MODE);
+        super.initZipOutputStream(zOut);
+    }
+
+    /**
+     * Finalize the zip output stream.
+     * This creates an index list if the index attribute is true.
+     * @param zOut the zip output stream
+     * @throws IOException on I/O errors
+     * @throws BuildException on other errors
+     */
+    protected void finalizeZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+
+        if (index) {
+            createIndexList(zOut);
+        }
+    }
+
+    /**
+     * Create the index list to speed up classloading.
+     * This is a JDK 1.3+ specific feature and is enabled by default. See
+     * <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#JAR%20Index">
+     * the JAR index specification</a> for more details.
+     *
+     * @param zOut the zip stream representing the jar being built.
+     * @throws IOException thrown if there is an error while creating the
+     * index and adding it to the zip stream.
+     */
+    private void createIndexList(ZipOutputStream zOut) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        // encoding must be UTF8 as specified in the specs.
+        PrintWriter writer = new PrintWriter(new OutputStreamWriter(baos,
+                                                                    "UTF8"));
+
+        // version-info blankline
+        writer.println("JarIndex-Version: 1.0");
+        writer.println();
+
+        // header newline
+        writer.println(zipFile.getName());
+
+        writeIndexLikeList(new ArrayList(addedDirs.keySet()),
+                           rootEntries, writer);
+        writer.println();
+
+        if (indexJars != null) {
+            Manifest mf = createManifest();
+            Manifest.Attribute classpath =
+                mf.getMainSection().getAttribute(Manifest.ATTRIBUTE_CLASSPATH);
+            String[] cpEntries = null;
+            if (classpath != null && classpath.getValue() != null) {
+                StringTokenizer tok = new StringTokenizer(classpath.getValue(),
+                                                          " ");
+                cpEntries = new String[tok.countTokens()];
+                int c = 0;
+                while (tok.hasMoreTokens()) {
+                    cpEntries[c++] = tok.nextToken();
+                }
+            }
+            String[] indexJarEntries = indexJars.list();
+            for (int i = 0; i < indexJarEntries.length; i++) {
+                String name = findJarName(indexJarEntries[i], cpEntries);
+                if (name != null) {
+                    ArrayList dirs = new ArrayList();
+                    ArrayList files = new ArrayList();
+                    grabFilesAndDirs(indexJarEntries[i], dirs, files);
+                    if (dirs.size() + files.size() > 0) {
+                        writer.println(name);
+                        writeIndexLikeList(dirs, files, writer);
+                        writer.println();
+                    }
+                }
+            }
+        }
+
+        writer.close();
+        ByteArrayInputStream bais =
+            new ByteArrayInputStream(baos.toByteArray());
+        super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis(), null,
+                      ZipFileSet.DEFAULT_FILE_MODE);
+    }
+
+    /**
+     * Overridden from Zip class to deal with manifests and index lists.
+     * @param is the input stream
+     * @param zOut the zip output stream
+     * @param vPath the name this entry shall have in the archive
+     * @param lastModified last modification time for the entry.
+     * @param fromArchive the original archive we are copying this
+     *                    entry from, will be null if we are not copying from an archive.
+     * @param mode the Unix permissions to set.
+     * @throws IOException on error
+     */
+    protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath,
+                           long lastModified, File fromArchive, int mode)
+        throws IOException {
+        if (MANIFEST_NAME.equalsIgnoreCase(vPath))  {
+            if (!doubleFilePass || skipWriting) {
+                filesetManifest(fromArchive, is);
+            }
+        } else if (INDEX_NAME.equalsIgnoreCase(vPath) && index) {
+            log("Warning: selected " + archiveType
+                + " files include a META-INF/INDEX.LIST which will"
+                + " be replaced by a newly generated one.", Project.MSG_WARN);
+        } else {
+            if (index && vPath.indexOf("/") == -1) {
+                rootEntries.addElement(vPath);
+            }
+            super.zipFile(is, zOut, vPath, lastModified, fromArchive, mode);
+        }
+    }
+
+    private void filesetManifest(File file, InputStream is) throws IOException {
+        if (manifestFile != null && manifestFile.equals(file)) {
+            // If this is the same name specified in 'manifest', this
+            // is the manifest to use
+            log("Found manifest " + file, Project.MSG_VERBOSE);
+            try {
+                if (is != null) {
+                    InputStreamReader isr;
+                    if (manifestEncoding == null) {
+                        isr = new InputStreamReader(is);
+                    } else {
+                        isr = new InputStreamReader(is, manifestEncoding);
+                    }
+                    manifest = getManifest(isr);
+                } else {
+                    manifest = getManifest(file);
+                }
+            } catch (UnsupportedEncodingException e) {
+                throw new BuildException("Unsupported encoding while reading "
+                    + "manifest: " + e.getMessage(), e);
+            }
+        } else if (filesetManifestConfig != null
+                    && !filesetManifestConfig.getValue().equals("skip")) {
+            // we add this to our group of fileset manifests
+            log("Found manifest to merge in file " + file,
+                Project.MSG_VERBOSE);
+
+            try {
+                Manifest newManifest = null;
+                if (is != null) {
+                    InputStreamReader isr;
+                    if (manifestEncoding == null) {
+                        isr = new InputStreamReader(is);
+                    } else {
+                        isr = new InputStreamReader(is, manifestEncoding);
+                    }
+                    newManifest = getManifest(isr);
+                } else {
+                    newManifest = getManifest(file);
+                }
+
+                if (filesetManifest == null) {
+                    filesetManifest = newManifest;
+                } else {
+                    filesetManifest.merge(newManifest);
+                }
+            } catch (UnsupportedEncodingException e) {
+                throw new BuildException("Unsupported encoding while reading "
+                    + "manifest: " + e.getMessage(), e);
+            } catch (ManifestException e) {
+                log("Manifest in file " + file + " is invalid: "
+                    + e.getMessage(), Project.MSG_ERR);
+                throw new BuildException("Invalid Manifest", e, getLocation());
+            }
+        } else {
+            // assuming 'skip' otherwise
+            // don't warn if skip has been requested explicitly, warn if user
+            // didn't set the attribute
+
+            // Hide warning also as it makes no sense since
+            // the filesetmanifest attribute itself has been
+            // hidden
+
+            //int logLevel = filesetManifestConfig == null ?
+            //    Project.MSG_WARN : Project.MSG_VERBOSE;
+            //log("File " + file
+            //    + " includes a META-INF/MANIFEST.MF which will be ignored. "
+            //    + "To include this file, set filesetManifest to a value other "
+            //    + "than 'skip'.", logLevel);
+        }
+    }
+
+    /**
+     * Collect the resources that are newer than the corresponding
+     * entries (or missing) in the original archive.
+     *
+     * <p>If we are going to recreate the archive instead of updating
+     * it, all resources should be considered as new, if a single one
+     * is.  Because of this, subclasses overriding this method must
+     * call <code>super.getResourcesToAdd</code> and indicate with the
+     * third arg if they already know that the archive is
+     * out-of-date.</p>
+     *
+     * @param rcs The resource collections to grab resources from
+     * @param zipFile intended archive file (may or may not exist)
+     * @param needsUpdate whether we already know that the archive is
+     * out-of-date.  Subclasses overriding this method are supposed to
+     * set this value correctly in their call to
+     * super.getResourcesToAdd.
+     * @return an array of resources to add for each fileset passed in as well
+     *         as a flag that indicates whether the archive is uptodate.
+     *
+     * @exception BuildException if it likes
+     */
+    protected ArchiveState getResourcesToAdd(ResourceCollection[] rcs,
+                                             File zipFile,
+                                             boolean needsUpdate)
+        throws BuildException {
+
+        // need to handle manifest as a special check
+        if (zipFile.exists()) {
+            // if it doesn't exist, it will get created anyway, don't
+            // bother with any up-to-date checks.
+
+            try {
+                originalManifest = getManifestFromJar(zipFile);
+                if (originalManifest == null) {
+                    log("Updating jar since the current jar has no manifest",
+                        Project.MSG_VERBOSE);
+                    needsUpdate = true;
+                } else {
+                    Manifest mf = createManifest();
+                    if (!mf.equals(originalManifest)) {
+                        log("Updating jar since jar manifest has changed",
+                            Project.MSG_VERBOSE);
+                        needsUpdate = true;
+                    }
+                }
+            } catch (Throwable t) {
+                log("error while reading original manifest in file: "
+                    + zipFile.toString() + t.getMessage(),
+                    Project.MSG_WARN);
+                needsUpdate = true;
+            }
+
+        } else {
+            // no existing archive
+            needsUpdate = true;
+        }
+
+        createEmpty = needsUpdate;
+        return super.getResourcesToAdd(rcs, zipFile, needsUpdate);
+    }
+
+    /**
+     * Create an empty jar file.
+     * @param zipFile the file to create
+     * @return true for historic reasons
+     * @throws BuildException on error
+     */
+    protected boolean createEmptyZip(File zipFile) throws BuildException {
+        if (!createEmpty) {
+            return true;
+        }
+
+        if (emptyBehavior.equals("skip")) {
+                log("Warning: skipping " + archiveType + " archive "
+                    + zipFile + " because no files were included.",
+                    Project.MSG_WARN);
+                return true;
+        } else if (emptyBehavior.equals("fail")) {
+            throw new BuildException("Cannot create " + archiveType
+                                     + " archive " + zipFile
+                                     + ": no files were included.",
+                                     getLocation());
+        }
+
+        ZipOutputStream zOut = null;
+        try {
+            log("Building MANIFEST-only jar: "
+                + getDestFile().getAbsolutePath());
+            zOut = new ZipOutputStream(new FileOutputStream(getDestFile()));
+
+            zOut.setEncoding(getEncoding());
+            if (isCompress()) {
+                zOut.setMethod(ZipOutputStream.DEFLATED);
+            } else {
+                zOut.setMethod(ZipOutputStream.STORED);
+            }
+            initZipOutputStream(zOut);
+            finalizeZipOutputStream(zOut);
+        } catch (IOException ioe) {
+            throw new BuildException("Could not create almost empty JAR archive"
+                                     + " (" + ioe.getMessage() + ")", ioe,
+                                     getLocation());
+        } finally {
+            // Close the output stream.
+            FileUtils.close(zOut);
+            createEmpty = false;
+        }
+        return true;
+    }
+
+    /**
+     * Make sure we don't think we already have a MANIFEST next time this task
+     * gets executed.
+     *
+     * @see Zip#cleanUp
+     */
+    protected void cleanUp() {
+        super.cleanUp();
+        checkJarSpec();
+
+        // we want to save this info if we are going to make another pass
+        if (!doubleFilePass || !skipWriting) {
+            manifest = null;
+            configuredManifest = savedConfiguredManifest;
+            filesetManifest = null;
+            originalManifest = null;
+        }
+        rootEntries.removeAllElements();
+    }
+
+    // CheckStyle:LineLength OFF - Link is too long.
+    /**
+     * Check against packaging spec
+     * @see http://java.sun.com/j2se/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersioning
+     */
+    // CheckStyle:LineLength ON
+    private void checkJarSpec() {
+        String br = System.getProperty("line.separator");
+        StringBuffer message = new StringBuffer();
+        Section mainSection = (configuredManifest == null)
+                            ? null
+                            : configuredManifest.getMainSection();
+
+        if (mainSection == null) {
+            message.append("No Implementation-Title set.");
+            message.append("No Implementation-Version set.");
+            message.append("No Implementation-Vendor set.");
+        } else {
+            if (mainSection.getAttribute("Implementation-Title") == null) {
+                message.append("No Implementation-Title set.");
+            }
+            if (mainSection.getAttribute("Implementation-Version") == null) {
+                message.append("No Implementation-Version set.");
+            }
+            if (mainSection.getAttribute("Implementation-Vendor") == null) {
+                message.append("No Implementation-Vendor set.");
+            }
+        }
+
+        if (message.length() > 0) {
+            message.append(br);
+            message.append("Location: ").append(getLocation());
+            message.append(br);
+            if (strict.getValue().equalsIgnoreCase("fail")) {
+                throw new BuildException(message.toString(), getLocation());
+            } else {
+                log(message.toString(), strict.getLogLevel());
+            }
+        }
+    }
+
+    /**
+     * reset to default values.
+     *
+     * @see Zip#reset
+     *
+     * @since 1.44, Ant 1.5
+     */
+    public void reset() {
+        super.reset();
+        emptyBehavior = "create";
+        configuredManifest = null;
+        filesetManifestConfig = null;
+        mergeManifestsMain = false;
+        manifestFile = null;
+        index = false;
+    }
+
+    /**
+     * The manifest config enumerated type.
+     */
+    public static class FilesetManifestConfig extends EnumeratedAttribute {
+        /**
+         * Get the list of valid strings.
+         * @return the list of values - "skip", "merge" and "mergewithoutmain"
+         */
+        public String[] getValues() {
+            return new String[] {"skip", "merge", "mergewithoutmain"};
+        }
+    }
+
+    /**
+     * Writes the directory entries from the first and the filenames
+     * from the second list to the given writer, one entry per line.
+     *
+     * @param dirs a list of directories
+     * @param files a list of files
+     * @param writer the writer to write to
+     * @throws IOException on error
+     * @since Ant 1.6.2
+     */
+    protected final void writeIndexLikeList(List dirs, List files,
+                                            PrintWriter writer)
+        throws IOException {
+        // JarIndex is sorting the directories by ascending order.
+        // it has no value but cosmetic since it will be read into a
+        // hashtable by the classloader, but we'll do so anyway.
+        Collections.sort(dirs);
+        Collections.sort(files);
+        Iterator iter = dirs.iterator();
+        while (iter.hasNext()) {
+            String dir = (String) iter.next();
+
+            // try to be smart, not to be fooled by a weird directory name
+            dir = dir.replace('\\', '/');
+            if (dir.startsWith("./")) {
+                dir = dir.substring(2);
+            }
+            while (dir.startsWith("/")) {
+                dir = dir.substring(1);
+            }
+            int pos = dir.lastIndexOf('/');
+            if (pos != -1) {
+                dir = dir.substring(0, pos);
+            }
+
+            // looks like nothing from META-INF should be added
+            // and the check is not case insensitive.
+            // see sun.misc.JarIndex
+            if (dir.startsWith("META-INF")) {
+                continue;
+            }
+            // name newline
+            writer.println(dir);
+        }
+
+        iter = files.iterator();
+        while (iter.hasNext()) {
+            writer.println(iter.next());
+        }
+    }
+
+    /**
+     * try to guess the name of the given file.
+     *
+     * <p>If this jar has a classpath attribute in its manifest, we
+     * can assume that it will only require an index of jars listed
+     * there.  try to find which classpath entry is most likely the
+     * one the given file name points to.</p>
+     *
+     * <p>In the absence of a classpath attribute, assume the other
+     * files will be placed inside the same directory as this jar and
+     * use their basename.</p>
+     *
+     * <p>if there is a classpath and the given file doesn't match any
+     * of its entries, return null.</p>
+     *
+     * @param fileName the name to look for
+     * @param classpath the classpath to look in (may be null)
+     * @return the matching entry, or null if the file is not found
+     * @since Ant 1.6.2
+     */
+    protected static String findJarName(String fileName,
+                                              String[] classpath) {
+        if (classpath == null) {
+            return (new File(fileName)).getName();
+        }
+        fileName = fileName.replace(File.separatorChar, '/');
+        TreeMap matches = new TreeMap(new Comparator() {
+                // longest match comes first
+                public int compare(Object o1, Object o2) {
+                    if (o1 instanceof String && o2 instanceof String) {
+                        return ((String) o2).length()
+                            - ((String) o1).length();
+                    }
+                    return 0;
+                }
+            });
+
+        for (int i = 0; i < classpath.length; i++) {
+            if (fileName.endsWith(classpath[i])) {
+                matches.put(classpath[i], classpath[i]);
+            } else {
+                int slash = classpath[i].indexOf("/");
+                String candidate = classpath[i];
+                while (slash > -1) {
+                    candidate = candidate.substring(slash + 1);
+                    if (fileName.endsWith(candidate)) {
+                        matches.put(candidate, classpath[i]);
+                        break;
+                    }
+                    slash = candidate.indexOf("/");
+                }
+            }
+        }
+
+        return matches.size() == 0
+            ? null : (String) matches.get(matches.firstKey());
+    }
+
+    /**
+     * Grab lists of all root-level files and all directories
+     * contained in the given archive.
+     * @param file the zip file to examine
+     * @param dirs where to place the directories found
+     * @param files where to place the files found
+     * @since Ant 1.7
+     * @throws IOException on error
+     */
+    protected static void grabFilesAndDirs(String file, List dirs,
+                                                 List files)
+        throws IOException {
+        org.apache.tools.zip.ZipFile zf = null;
+        try {
+            zf = new org.apache.tools.zip.ZipFile(file, "utf-8");
+            Enumeration entries = zf.getEntries();
+            HashSet dirSet = new HashSet();
+            while (entries.hasMoreElements()) {
+                org.apache.tools.zip.ZipEntry ze =
+                    (org.apache.tools.zip.ZipEntry) entries.nextElement();
+                String name = ze.getName();
+                // META-INF would be skipped anyway, avoid index for
+                // manifest-only jars.
+                if (!name.startsWith("META-INF/")) {
+                    if (ze.isDirectory()) {
+                        dirSet.add(name);
+                    } else if (name.indexOf("/") == -1) {
+                        files.add(name);
+                    } else {
+                        // a file, not in the root
+                        // since the jar may be one without directory
+                        // entries, add the parent dir of this file as
+                        // well.
+                        dirSet.add(name.substring(0,
+                                                  name.lastIndexOf("/") + 1));
+                    }
+                }
+            }
+            dirs.addAll(dirSet);
+        } finally {
+            if (zf != null) {
+                zf.close();
+            }
+        }
+    }
+
+    /** The strict enumerated type. */
+    public static class StrictMode extends EnumeratedAttribute {
+        /** Public no arg constructor. */
+        public StrictMode() {
+        }
+        /**
+         * Constructor with an arg.
+         * @param value the enumerated value as a string.
+         */
+        public StrictMode(String value) {
+            setValue(value);
+        }
+        /**
+         * Get List of valid strings.
+         * @return the list of values.
+         */
+        public String[] getValues() {
+            return new String[]{"fail", "warn", "ignore"};
+        }
+        /**
+         * @return The log level according to the strict mode.
+         */
+        public int getLogLevel() {
+            return (getValue().equals("ignore")) ? Project.MSG_VERBOSE : Project.MSG_WARN;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Java.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Java.java
new file mode 100644
index 0000000..433402e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Java.java
@@ -0,0 +1,956 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ExitException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.ExitStatusException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.Assertions;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.types.RedirectorElement;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.KeepAliveInputStream;
+
+/**
+ * Launcher for Java applications. Allows use of
+ * the same JVM for the called application thus resulting in much
+ * faster operation.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="java"
+ */
+public class Java extends Task {
+
+    private CommandlineJava cmdl = new CommandlineJava();
+    private Environment env = new Environment();
+    private boolean fork = false;
+    private boolean newEnvironment = false;
+    private File dir = null;
+    private boolean failOnError = false;
+    private Long timeout = null;
+
+    //include locally for screening purposes
+    private String inputString;
+    private File input;
+    private File output;
+    private File error;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Redirector redirector = new Redirector(this);
+    protected RedirectorElement redirectorElement;
+    // CheckStyle:VisibilityModifier ON
+
+    private String resultProperty;
+    private Permissions perm = null;
+
+    private boolean spawn = false;
+    private boolean incompatibleWithSpawn = false;
+
+    /**
+     * Normal constructor
+     */
+    public Java() {
+    }
+
+    /**
+     * create a bound task
+     * @param owner owner
+     */
+    public Java(Task owner) {
+        bindToOwner(owner);
+    }
+
+    /**
+     * Do the execution.
+     * @throws BuildException if failOnError is set to true and the application
+     * returns a nonzero result code.
+     */
+    public void execute() throws BuildException {
+        File savedDir = dir;
+        Permissions savedPermissions = perm;
+
+        int err = -1;
+        try {
+            checkConfiguration();
+            err = executeJava();
+            if (err != 0) {
+                if (failOnError) {
+                    throw new ExitStatusException("Java returned: " + err,
+                            err,
+                            getLocation());
+                } else {
+                    log("Java Result: " + err, Project.MSG_ERR);
+                }
+            }
+            maybeSetResultPropertyValue(err);
+        } finally {
+            dir = savedDir;
+            perm = savedPermissions;
+        }
+    }
+
+    /**
+     * Do the execution and return a return code.
+     *
+     * @return the return code from the execute java class if it was
+     * executed in a separate VM (fork = "yes") or a security manager was
+     * installed that prohibits ExitVM (default).
+     *
+     * @throws BuildException if required parameters are missing.
+     */
+    public int executeJava() throws BuildException {
+        return executeJava(getCommandLine());
+    }
+
+    /**
+     * Check configuration.
+     * @throws BuildException if required parameters are missing.
+     */
+    protected void checkConfiguration() throws BuildException {
+        String classname = getCommandLine().getClassname();
+        if (classname == null && getCommandLine().getJar() == null) {
+            throw new BuildException("Classname must not be null.");
+        }
+        if (!fork && getCommandLine().getJar() != null) {
+            throw new BuildException("Cannot execute a jar in non-forked mode."
+                                     + " Please set fork='true'. ");
+        }
+        if (spawn && !fork) {
+            throw new BuildException("Cannot spawn a java process in non-forked mode."
+                                     + " Please set fork='true'. ");
+        }
+        if (getCommandLine().getClasspath() != null
+            && getCommandLine().getJar() != null) {
+            log("When using 'jar' attribute classpath-settings are ignored. "
+                + "See the manual for more information.", Project.MSG_VERBOSE);
+        }
+        if (spawn && incompatibleWithSpawn) {
+            getProject().log("spawn does not allow attributes related to input, "
+            + "output, error, result", Project.MSG_ERR);
+            getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
+            getProject().log("finally, spawn is not compatible "
+                + "with a nested I/O <redirector>", Project.MSG_ERR);
+            throw new BuildException("You have used an attribute "
+                + "or nested element which is not compatible with spawn");
+        }
+        if (getCommandLine().getAssertions() != null && !fork) {
+            log("Assertion statements are currently ignored in non-forked mode");
+        }
+        if (fork) {
+            if (perm != null) {
+                log("Permissions can not be set this way in forked mode.", Project.MSG_WARN);
+            }
+            log(getCommandLine().describeCommand(), Project.MSG_VERBOSE);
+        } else {
+            if (getCommandLine().getVmCommand().size() > 1) {
+                log("JVM args ignored when same JVM is used.",
+                    Project.MSG_WARN);
+            }
+            if (dir != null) {
+                log("Working directory ignored when same JVM is used.",
+                    Project.MSG_WARN);
+            }
+            if (newEnvironment || null != env.getVariables()) {
+                log("Changes to environment variables are ignored when same "
+                    + "JVM is used.", Project.MSG_WARN);
+            }
+            if (getCommandLine().getBootclasspath() != null) {
+                log("bootclasspath ignored when same JVM is used.",
+                    Project.MSG_WARN);
+            }
+            if (perm == null) {
+                perm = new Permissions(true);
+                log("running " + this.getCommandLine().getClassname()
+                    + " with default permissions (exit forbidden)", Project.MSG_VERBOSE);
+            }
+            log("Running in same VM " + getCommandLine().describeJavaCommand(),
+                Project.MSG_VERBOSE);
+        }
+        setupRedirector();
+    }
+
+    /**
+     * Execute the specified CommandlineJava.
+     * @param commandLine CommandLineJava instance.
+     * @return the exit value of the process if forked, 0 otherwise.
+     */
+    protected int executeJava(CommandlineJava commandLine) {
+        try {
+            if (fork) {
+                if (!spawn) {
+                    return fork(commandLine.getCommandline());
+                } else {
+                    spawn(commandLine.getCommandline());
+                    return 0;
+                }
+            } else {
+                try {
+                    run(commandLine);
+                    return 0;
+                } catch (ExitException ex) {
+                    return ex.getStatus();
+                }
+            }
+        } catch (BuildException e) {
+            if (e.getLocation() == null && getLocation() != null) {
+                e.setLocation(getLocation());
+            }
+            if (failOnError) {
+                throw e;
+            } else {
+                log(e);
+                return -1;
+            }
+        } catch (ThreadDeath t) {
+            throw t; // cf. NB #47191
+        } catch (Throwable t) {
+            if (failOnError) {
+                throw new BuildException(t, getLocation());
+            } else {
+                log(t);
+                return -1;
+            }
+        }
+    }
+
+    /**
+     * Set whether or not you want the process to be spawned;
+     * default is not spawned.
+     * @param spawn if true you do not want Ant to wait for the end of the process.
+     * @since Ant 1.6
+     */
+    public void setSpawn(boolean spawn) {
+        this.spawn = spawn;
+    }
+
+    /**
+     * Set the classpath to be used when running the Java class.
+     *
+     * @param s an Ant Path object containing the classpath.
+     */
+    public void setClasspath(Path s) {
+        createClasspath().append(s);
+    }
+
+    /**
+     * Add a path to the classpath.
+     *
+     * @return created classpath.
+     */
+    public Path createClasspath() {
+        return getCommandLine().createClasspath(getProject()).createPath();
+    }
+
+    /**
+     * Add a path to the bootclasspath.
+     * @since Ant 1.6
+     *
+     * @return created bootclasspath.
+     */
+    public Path createBootclasspath() {
+        return getCommandLine().createBootclasspath(getProject()).createPath();
+    }
+
+    /**
+     * Set the permissions for the application run inside the same JVM.
+     * @since Ant 1.6
+     * @return Permissions.
+     */
+    public Permissions createPermissions() {
+        perm = (perm == null) ? new Permissions() : perm;
+        return perm;
+    }
+
+    /**
+     * Set the classpath to use by reference.
+     *
+     * @param r a reference to an existing classpath.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Set the location of the JAR file to execute.
+     *
+     * @param jarfile the jarfile to execute.
+     *
+     * @throws BuildException if there is also a main class specified.
+     */
+    public void setJar(File jarfile) throws BuildException {
+        if (getCommandLine().getClassname() != null) {
+            throw new BuildException("Cannot use 'jar' and 'classname' "
+                                     + "attributes in same command.");
+        }
+        getCommandLine().setJar(jarfile.getAbsolutePath());
+    }
+
+    /**
+     * Set the Java class to execute.
+     *
+     * @param s the name of the main class.
+     *
+     * @throws BuildException if the jar attribute has been set.
+     */
+    public void setClassname(String s) throws BuildException {
+        if (getCommandLine().getJar() != null) {
+            throw new BuildException("Cannot use 'jar' and 'classname' "
+                                     + "attributes in same command");
+        }
+        getCommandLine().setClassname(s);
+    }
+
+    /**
+     * Deprecated: use nested arg instead.
+     * Set the command line arguments for the class.
+     *
+     * @param s arguments.
+     *
+     * @ant.attribute ignore="true"
+     */
+    public void setArgs(String s) {
+        log("The args attribute is deprecated. "
+            + "Please use nested arg elements.", Project.MSG_WARN);
+        getCommandLine().createArgument().setLine(s);
+    }
+
+    /**
+     * If set, system properties will be copied to the cloned VM--as
+     * well as the bootclasspath unless you have explicitly specified
+     * a bootclaspath.
+     *
+     * <p>Doesn't have any effect unless fork is true.</p>
+     * @param cloneVm if true copy system properties.
+     * @since Ant 1.7
+     */
+    public void setCloneVm(boolean cloneVm) {
+        getCommandLine().setCloneVm(cloneVm);
+    }
+
+    /**
+     * Add a command-line argument.
+     *
+     * @return created argument.
+     */
+    public Commandline.Argument createArg() {
+        return getCommandLine().createArgument();
+    }
+
+    /**
+     * Set the name of the property in which the return code of the
+     * command should be stored. Only of interest if failonerror=false.
+     *
+     * @param resultProperty name of property.
+     *
+     * @since Ant 1.6
+     */
+    public void setResultProperty(String resultProperty) {
+        this.resultProperty = resultProperty;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Helper method to set result property to the
+     * passed in value if appropriate.
+     *
+     * @param result the exit code
+     */
+    protected void maybeSetResultPropertyValue(int result) {
+        String res = Integer.toString(result);
+        if (resultProperty != null) {
+            getProject().setNewProperty(resultProperty, res);
+        }
+    }
+
+    /**
+     * If true, execute in a new VM.
+     *
+     * @param s do you want to run Java in a new VM.
+     */
+    public void setFork(boolean s) {
+        this.fork = s;
+    }
+
+    /**
+     * Set the command line arguments for the JVM.
+     *
+     * @param s jvmargs.
+     */
+    public void setJvmargs(String s) {
+        log("The jvmargs attribute is deprecated. "
+            + "Please use nested jvmarg elements.", Project.MSG_WARN);
+        getCommandLine().createVmArgument().setLine(s);
+    }
+
+    /**
+     * Adds a JVM argument.
+     *
+     * @return JVM argument created.
+     */
+    public Commandline.Argument createJvmarg() {
+        return getCommandLine().createVmArgument();
+    }
+
+    /**
+     * Set the command used to start the VM (only if forking).
+     *
+     * @param s command to start the VM.
+     */
+    public void setJvm(String s) {
+        getCommandLine().setVm(s);
+    }
+
+    /**
+     * Add a system property.
+     *
+     * @param sysp system property.
+     */
+    public void addSysproperty(Environment.Variable sysp) {
+        getCommandLine().addSysproperty(sysp);
+    }
+
+    /**
+     * Add a set of properties as system properties.
+     *
+     * @param sysp set of properties to add.
+     *
+     * @since Ant 1.6
+     */
+    public void addSyspropertyset(PropertySet sysp) {
+        getCommandLine().addSyspropertyset(sysp);
+    }
+
+    /**
+     * If true, then fail if the command exits with a
+     * returncode other than zero.
+     *
+     * @param fail if true fail the build when the command exits with a
+     * nonzero returncode.
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+        incompatibleWithSpawn |= fail;
+    }
+
+    /**
+     * Set the working directory of the process.
+     *
+     * @param d working directory.
+     *
+     */
+    public void setDir(File d) {
+        this.dir = d;
+    }
+
+    /**
+     * Set the File to which the output of the process is redirected.
+     *
+     * @param out the output File.
+     */
+    public void setOutput(File out) {
+        this.output = out;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the input to use for the task.
+     *
+     * @param input name of the input file.
+     */
+    public void setInput(File input) {
+        if (inputString != null) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        this.input = input;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the string to use as input.
+     *
+     * @param inputString the string which is used as the input source.
+     */
+    public void setInputString(String inputString) {
+        if (input != null) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        this.inputString = inputString;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set whether error output of exec is logged. This is only useful
+     * when output is being redirected and error output is desired in the
+     * Ant log.
+     *
+     * @param logError get in the ant log the messages coming from stderr
+     * in the case that fork = true.
+     */
+    public void setLogError(boolean logError) {
+        redirector.setLogError(logError);
+        incompatibleWithSpawn |= logError;
+    }
+
+    /**
+     * Set the File to which the error stream of the process is redirected.
+     *
+     * @param error file getting the error stream.
+     *
+     * @since Ant 1.6
+     */
+    public void setError(File error) {
+        this.error = error;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the property name whose value should be set to the output of
+     * the process.
+     *
+     * @param outputProp property name.
+     *
+     */
+    public void setOutputproperty(String outputProp) {
+        redirector.setOutputProperty(outputProp);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the property name whose value should be set to the error of
+     * the process.
+     *
+     * @param errorProperty property name.
+     *
+     * @since Ant 1.6
+     */
+    public void setErrorProperty(String errorProperty) {
+        redirector.setErrorProperty(errorProperty);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Corresponds to -mx or -Xmx depending on VM version.
+     *
+     * @param max max memory parameter.
+     */
+    public void setMaxmemory(String max) {
+        getCommandLine().setMaxmemory(max);
+    }
+
+    /**
+     * Set the JVM version.
+     * @param value JVM version.
+     */
+    public void setJVMVersion(String value) {
+        getCommandLine().setVmversion(value);
+    }
+
+    /**
+     * Add an environment variable.
+     *
+     * <p>Will be ignored if we are not forking a new VM.
+     *
+     * @param var new environment variable.
+     *
+     * @since Ant 1.5
+     */
+    public void addEnv(Environment.Variable var) {
+        env.addVariable(var);
+    }
+
+    /**
+     * If true, use a completely new environment.
+     *
+     * <p>Will be ignored if we are not forking a new VM.
+     *
+     * @param newenv if true, use a completely new environment.
+     *
+     * @since Ant 1.5
+     */
+    public void setNewenvironment(boolean newenv) {
+        newEnvironment = newenv;
+    }
+
+    /**
+     * If true, append output to existing file.
+     *
+     * @param append if true, append output to existing file.
+     *
+     * @since Ant 1.5
+     */
+    public void setAppend(boolean append) {
+        redirector.setAppend(append);
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Set the timeout in milliseconds after which the process will be killed.
+     *
+     * @param value timeout in milliseconds.
+     *
+     * @since Ant 1.5
+     */
+    public void setTimeout(Long value) {
+        timeout = value;
+        incompatibleWithSpawn |= timeout != null;
+    }
+
+    /**
+     * Add assertions to enable in this program (if fork=true).
+     * @param asserts assertion set.
+     * @since Ant 1.6
+     */
+    public void addAssertions(Assertions asserts) {
+        if (getCommandLine().getAssertions() != null) {
+            throw new BuildException("Only one assertion declaration is allowed");
+        }
+        getCommandLine().setAssertions(asserts);
+    }
+
+    /**
+     * Add a <code>RedirectorElement</code> to this task.
+     * @param redirectorElement   <code>RedirectorElement</code>.
+     */
+    public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+        if (this.redirectorElement != null) {
+            throw new BuildException("cannot have > 1 nested redirectors");
+        }
+        this.redirectorElement = redirectorElement;
+        incompatibleWithSpawn = true;
+    }
+
+    /**
+     * Pass output sent to System.out to specified output file.
+     *
+     * @param output a string of output on its way to the handlers.
+     *
+     * @since Ant 1.5
+     */
+    protected void handleOutput(String output) {
+        if (redirector.getOutputStream() != null) {
+            redirector.handleOutput(output);
+        } else {
+            super.handleOutput(output);
+        }
+    }
+
+    /**
+     * Handle an input request by this task.
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     *
+     * @exception IOException if the data cannot be read.
+     * @since Ant 1.6
+     */
+    public int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        // Should work whether or not redirector.inputStream == null:
+        return redirector.handleInput(buffer, offset, length);
+    }
+
+    /**
+     * Pass output sent to System.out to specified output file.
+     *
+     * @param output string of output on its way to its handlers.
+     *
+     * @since Ant 1.5.2
+     */
+    protected void handleFlush(String output) {
+        if (redirector.getOutputStream() != null) {
+            redirector.handleFlush(output);
+        } else {
+            super.handleFlush(output);
+        }
+    }
+
+    /**
+     * Handle output sent to System.err.
+     *
+     * @param output string of stderr.
+     *
+     * @since Ant 1.5
+     */
+    protected void handleErrorOutput(String output) {
+        if (redirector.getErrorStream() != null) {
+            redirector.handleErrorOutput(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+    /**
+     * Handle output sent to System.err and flush the stream.
+     *
+     * @param output string of stderr.
+     *
+     * @since Ant 1.5.2
+     */
+    protected void handleErrorFlush(String output) {
+        if (redirector.getErrorStream() != null) {
+            redirector.handleErrorFlush(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+    /**
+     * Set up properties on the redirector that we needed to store locally.
+     */
+    protected void setupRedirector() {
+        redirector.setInput(input);
+        redirector.setInputString(inputString);
+        redirector.setOutput(output);
+        redirector.setError(error);
+        if (redirectorElement != null) {
+            redirectorElement.configure(redirector);
+        }
+        if (!spawn && input == null && inputString == null) {
+            // #24918: send standard input to the process by default.
+            redirector.setInputStream(
+                new KeepAliveInputStream(getProject().getDefaultInputStream()));
+        }
+    }
+
+    /**
+     * Executes the given classname with the given arguments as it
+     * were a command line application.
+     * @param command CommandlineJava.
+     */
+    private void run(CommandlineJava command) throws BuildException {
+        try {
+            ExecuteJava exe = new ExecuteJava();
+            exe.setJavaCommand(command.getJavaCommand());
+            exe.setClasspath(command.getClasspath());
+            exe.setSystemProperties(command.getSystemProperties());
+            exe.setPermissions(perm);
+            exe.setTimeout(timeout);
+            redirector.createStreams();
+            exe.execute(getProject());
+            redirector.complete();
+            if (exe.killedProcess()) {
+                throw new BuildException("Timeout: killed the sub-process");
+            }
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Executes the given classname with the given arguments in a separate VM.
+     * @param command String[] of command-line arguments.
+     */
+    private int fork(String[] command) throws BuildException {
+        Execute exe
+            = new Execute(redirector.createHandler(), createWatchdog());
+        setupExecutable(exe, command);
+
+        try {
+            int rc = exe.execute();
+            redirector.complete();
+            if (exe.killedProcess()) {
+                throw new BuildException("Timeout: killed the sub-process");
+            }
+            return rc;
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+    /**
+     * Executes the given classname with the given arguments in a separate VM.
+     * @param command String[] of command-line arguments.
+     */
+    private void spawn(String[] command) throws BuildException {
+        Execute exe = new Execute();
+        setupExecutable(exe, command);
+        try {
+            exe.spawn();
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+    /**
+     * Do all configuration for an executable that
+     * is common across the {@link #fork(String[])} and
+     * {@link #spawn(String[])} methods.
+     * @param exe executable.
+     * @param command command to execute.
+     */
+    private void setupExecutable(Execute exe, String[] command) {
+        exe.setAntRun(getProject());
+        setupWorkingDir(exe);
+        setupEnvironment(exe);
+        setupCommandLine(exe, command);
+    }
+
+    /**
+     * Set up our environment variables.
+     * @param exe executable.
+     */
+    private void setupEnvironment(Execute exe) {
+        String[] environment = env.getVariables();
+        if (environment != null) {
+            for (int i = 0; i < environment.length; i++) {
+                log("Setting environment variable: " + environment[i],
+                    Project.MSG_VERBOSE);
+            }
+        }
+        exe.setNewenvironment(newEnvironment);
+        exe.setEnvironment(environment);
+    }
+
+    /**
+     * Set the working dir of the new process.
+     * @param exe executable.
+     * @throws BuildException if the dir doesn't exist.
+     */
+    private void setupWorkingDir(Execute exe) {
+        if (dir == null) {
+            dir = getProject().getBaseDir();
+        } else if (!dir.exists() || !dir.isDirectory()) {
+            throw new BuildException(dir.getAbsolutePath()
+                                     + " is not a valid directory",
+                                     getLocation());
+        }
+        exe.setWorkingDirectory(dir);
+    }
+
+    /**
+     * Set the command line for the exe.
+     * On VMS, hands off to {@link #setupCommandLineForVMS(Execute, String[])}.
+     * @param exe executable.
+     * @param command command to execute.
+     */
+    private void setupCommandLine(Execute exe, String[] command) {
+        //On VMS platform, we need to create a special java options file
+        //containing the arguments and classpath for the java command.
+        //The special file is supported by the "-V" switch on the VMS JVM.
+        if (Os.isFamily("openvms")) {
+            setupCommandLineForVMS(exe, command);
+        } else {
+            exe.setCommandline(command);
+        }
+    }
+
+    /**
+     * On VMS platform, we need to create a special java options file
+     * containing the arguments and classpath for the java command.
+     * The special file is supported by the "-V" switch on the VMS JVM.
+     *
+     * @param exe executable.
+     * @param command command to execute.
+     */
+    private void setupCommandLineForVMS(Execute exe, String[] command) {
+        ExecuteJava.setupCommandLineForVMS(exe, command);
+    }
+
+    /**
+     * Executes the given classname with the given arguments as if it
+     * were a command line application.
+     *
+     * @param classname the name of the class to run.
+     * @param args  arguments for the class.
+     * @throws BuildException in case of IOException in the execution.
+     */
+    protected void run(String classname, Vector args) throws BuildException {
+        CommandlineJava cmdj = new CommandlineJava();
+        cmdj.setClassname(classname);
+        for (int i = 0; i < args.size(); i++) {
+            cmdj.createArgument().setValue((String) args.elementAt(i));
+        }
+        run(cmdj);
+    }
+
+    /**
+     * Clear out the arguments to this java task.
+     */
+    public void clearArgs() {
+        getCommandLine().clearJavaArgs();
+    }
+
+    /**
+     * Create the Watchdog to kill a runaway process.
+     *
+     * @return new watchdog.
+     *
+     * @throws BuildException under unknown circumstances.
+     *
+     * @since Ant 1.5
+     */
+    protected ExecuteWatchdog createWatchdog() throws BuildException {
+        if (timeout == null) {
+            return null;
+        }
+        return new ExecuteWatchdog(timeout.longValue());
+    }
+
+    /**
+     * Log the specified Throwable.
+     * @param t the Throwable to log.
+     * @since 1.6.2
+     */
+    private void log(Throwable t) {
+        StringWriter sw = new StringWriter();
+        PrintWriter w = new PrintWriter(sw);
+        t.printStackTrace(w);
+        w.close();
+        log(sw.toString(), Project.MSG_ERR);
+    }
+
+    /**
+     * Accessor to the command line.
+     *
+     * @return the current command line.
+     * @since 1.6.3
+     */
+    public CommandlineJava getCommandLine() {
+        return cmdl;
+    }
+
+    /**
+     * Get the system properties of the command line.
+     *
+     * @return the current properties of this java invocation.
+     * @since 1.6.3
+     */
+    public CommandlineJava.SysProperties getSysProperties() {
+        return getCommandLine().getSystemProperties();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java
new file mode 100644
index 0000000..420ccd1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Javac.java
@@ -0,0 +1,1174 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter;
+import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.GlobPatternMapper;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+
+/**
+ * Compiles Java source files. This task can take the following
+ * arguments:
+ * <ul>
+ * <li>sourcedir
+ * <li>destdir
+ * <li>deprecation
+ * <li>classpath
+ * <li>bootclasspath
+ * <li>extdirs
+ * <li>optimize
+ * <li>debug
+ * <li>encoding
+ * <li>target
+ * <li>depend
+ * <li>verbose
+ * <li>failonerror
+ * <li>includeantruntime
+ * <li>includejavaruntime
+ * <li>source
+ * <li>compiler
+ * </ul>
+ * Of these arguments, the <b>sourcedir</b> and <b>destdir</b> are required.
+ * <p>
+ * When this task executes, it will recursively scan the sourcedir and
+ * destdir looking for Java source files to compile. This task makes its
+ * compile decision based on timestamp.
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="java"
+ */
+
+public class Javac extends MatchingTask {
+
+    private static final String FAIL_MSG
+        = "Compile failed; see the compiler error output for details.";
+
+    private static final String JAVAC16 = "javac1.6";
+    private static final String JAVAC15 = "javac1.5";
+    private static final String JAVAC14 = "javac1.4";
+    private static final String JAVAC13 = "javac1.3";
+    private static final String JAVAC12 = "javac1.2";
+    private static final String JAVAC11 = "javac1.1";
+    private static final String MODERN = "modern";
+    private static final String CLASSIC = "classic";
+    private static final String EXTJAVAC = "extJavac";
+
+    private static final String PACKAGE_INFO_JAVA = "package-info.java";
+    private static final String PACKAGE_INFO_CLASS = "package-info.class";
+
+    private Path src;
+    private File destDir;
+    private Path compileClasspath;
+    private Path compileSourcepath;
+    private String encoding;
+    private boolean debug = false;
+    private boolean optimize = false;
+    private boolean deprecation = false;
+    private boolean depend = false;
+    private boolean verbose = false;
+    private String targetAttribute;
+    private Path bootclasspath;
+    private Path extdirs;
+    private boolean includeAntRuntime = true;
+    private boolean includeJavaRuntime = false;
+    private boolean fork = false;
+    private String forkedExecutable = null;
+    private boolean nowarn = false;
+    private String memoryInitialSize;
+    private String memoryMaximumSize;
+    private FacadeTaskHelper facade = null;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean failOnError = true;
+    protected boolean listFiles = false;
+    protected File[] compileList = new File[0];
+    // CheckStyle:VisibilityModifier ON
+
+    private String source;
+    private String debugLevel;
+    private File tmpDir;
+    private String updatedProperty;
+    private String errorProperty;
+    private boolean taskSuccess = true; // assume the best
+    private boolean includeDestClasses = true;
+    private List    updateDirList = new ArrayList();
+
+    /**
+     * Javac task for compilation of Java files.
+     */
+    public Javac() {
+        facade = new FacadeTaskHelper(assumedJavaVersion());
+    }
+
+    private String assumedJavaVersion() {
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)) {
+            return JAVAC12;
+        } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
+            return JAVAC13;
+        } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4)) {
+            return JAVAC14;
+        } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_5)) {
+            return JAVAC15;
+        } else if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_6)) {
+            return JAVAC16;
+        } else {
+            return CLASSIC;
+        }
+    }
+
+    /**
+     * Get the value of debugLevel.
+     * @return value of debugLevel.
+     */
+    public String getDebugLevel() {
+        return debugLevel;
+    }
+
+    /**
+     * Keyword list to be appended to the -g command-line switch.
+     *
+     * This will be ignored by all implementations except modern
+     * and classic(ver >= 1.2). Legal values are none or a
+     * comma-separated list of the following keywords: lines, vars,
+     * and source. If debuglevel is not specified, by default, :none
+     * will be appended to -g. If debug is not turned on, this attribute
+     * will be ignored.
+     *
+     * @param v  Value to assign to debugLevel.
+     */
+    public void setDebugLevel(String  v) {
+        this.debugLevel = v;
+    }
+
+    /**
+     * Get the value of source.
+     * @return value of source.
+     */
+    public String getSource() {
+        return source != null
+            ? source : getProject().getProperty(MagicNames.BUILD_JAVAC_SOURCE);
+    }
+
+    /**
+     * Value of the -source command-line switch; will be ignored
+     * by all implementations except modern and jikes.
+     *
+     * If you use this attribute together with jikes, you must make
+     * sure that your version of jikes supports the -source switch.
+     * Legal values are 1.3, 1.4, 1.5, and 5 - by default, no
+     * -source argument will be used at all.
+     *
+     * @param v  Value to assign to source.
+     */
+    public void setSource(String  v) {
+        this.source = v;
+    }
+
+    /**
+     * Adds a path for source compilation.
+     *
+     * @return a nested src element.
+     */
+    public Path createSrc() {
+        if (src == null) {
+            src = new Path(getProject());
+        }
+        return src.createPath();
+    }
+
+    /**
+     * Recreate src.
+     *
+     * @return a nested src element.
+     */
+    protected Path recreateSrc() {
+        src = null;
+        return createSrc();
+    }
+
+    /**
+     * Set the source directories to find the source Java files.
+     * @param srcDir the source directories as a path
+     */
+    public void setSrcdir(Path srcDir) {
+        if (src == null) {
+            src = srcDir;
+        } else {
+            src.append(srcDir);
+        }
+    }
+
+    /**
+     * Gets the source dirs to find the source java files.
+     * @return the source directories as a path
+     */
+    public Path getSrcdir() {
+        return src;
+    }
+
+    /**
+     * Set the destination directory into which the Java source
+     * files should be compiled.
+     * @param destDir the destination director
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Gets the destination directory into which the java source files
+     * should be compiled.
+     * @return the destination directory
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * Set the sourcepath to be used for this compilation.
+     * @param sourcepath the source path
+     */
+    public void setSourcepath(Path sourcepath) {
+        if (compileSourcepath == null) {
+            compileSourcepath = sourcepath;
+        } else {
+            compileSourcepath.append(sourcepath);
+        }
+    }
+
+    /**
+     * Gets the sourcepath to be used for this compilation.
+     * @return the source path
+     */
+    public Path getSourcepath() {
+        return compileSourcepath;
+    }
+
+    /**
+     * Adds a path to sourcepath.
+     * @return a sourcepath to be configured
+     */
+    public Path createSourcepath() {
+        if (compileSourcepath == null) {
+            compileSourcepath = new Path(getProject());
+        }
+        return compileSourcepath.createPath();
+    }
+
+    /**
+     * Adds a reference to a source path defined elsewhere.
+     * @param r a reference to a source path
+     */
+    public void setSourcepathRef(Reference r) {
+        createSourcepath().setRefid(r);
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     *
+     * @param classpath an Ant Path object containing the compilation classpath.
+     */
+    public void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        } else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Gets the classpath to be used for this compilation.
+     * @return the class path
+     */
+    public Path getClasspath() {
+        return compileClasspath;
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a class path to be configured
+     */
+    public Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Sets the bootclasspath that will be used to compile the classes
+     * against.
+     * @param bootclasspath a path to use as a boot class path (may be more
+     *                      than one)
+     */
+    public void setBootclasspath(Path bootclasspath) {
+        if (this.bootclasspath == null) {
+            this.bootclasspath = bootclasspath;
+        } else {
+            this.bootclasspath.append(bootclasspath);
+        }
+    }
+
+    /**
+     * Gets the bootclasspath that will be used to compile the classes
+     * against.
+     * @return the boot path
+     */
+    public Path getBootclasspath() {
+        return bootclasspath;
+    }
+
+    /**
+     * Adds a path to the bootclasspath.
+     * @return a path to be configured
+     */
+    public Path createBootclasspath() {
+        if (bootclasspath == null) {
+            bootclasspath = new Path(getProject());
+        }
+        return bootclasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     */
+    public void setBootClasspathRef(Reference r) {
+        createBootclasspath().setRefid(r);
+    }
+
+    /**
+     * Sets the extension directories that will be used during the
+     * compilation.
+     * @param extdirs a path
+     */
+    public void setExtdirs(Path extdirs) {
+        if (this.extdirs == null) {
+            this.extdirs = extdirs;
+        } else {
+            this.extdirs.append(extdirs);
+        }
+    }
+
+    /**
+     * Gets the extension directories that will be used during the
+     * compilation.
+     * @return the extension directories as a path
+     */
+    public Path getExtdirs() {
+        return extdirs;
+    }
+
+    /**
+     * Adds a path to extdirs.
+     * @return a path to be configured
+     */
+    public Path createExtdirs() {
+        if (extdirs == null) {
+            extdirs = new Path(getProject());
+        }
+        return extdirs.createPath();
+    }
+
+    /**
+     * If true, list the source files being handed off to the compiler.
+     * @param list if true list the source files
+     */
+    public void setListfiles(boolean list) {
+        listFiles = list;
+    }
+
+    /**
+     * Get the listfiles flag.
+     * @return the listfiles flag
+     */
+    public boolean getListfiles() {
+        return listFiles;
+    }
+
+    /**
+     * Indicates whether the build will continue
+     * even if there are compilation errors; defaults to true.
+     * @param fail if true halt the build on failure
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * @ant.attribute ignore="true"
+     * @param proceed inverse of failoferror
+     */
+    public void setProceed(boolean proceed) {
+        failOnError = !proceed;
+    }
+
+    /**
+     * Gets the failonerror flag.
+     * @return the failonerror flag
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Indicates whether source should be
+     * compiled with deprecation information; defaults to off.
+     * @param deprecation if true turn on deprecation information
+     */
+    public void setDeprecation(boolean deprecation) {
+        this.deprecation = deprecation;
+    }
+
+    /**
+     * Gets the deprecation flag.
+     * @return the deprecation flag
+     */
+    public boolean getDeprecation() {
+        return deprecation;
+    }
+
+    /**
+     * The initial size of the memory for the underlying VM
+     * if javac is run externally; ignored otherwise.
+     * Defaults to the standard VM memory setting.
+     * (Examples: 83886080, 81920k, or 80m)
+     * @param memoryInitialSize string to pass to VM
+     */
+    public void setMemoryInitialSize(String memoryInitialSize) {
+        this.memoryInitialSize = memoryInitialSize;
+    }
+
+    /**
+     * Gets the memoryInitialSize flag.
+     * @return the memoryInitialSize flag
+     */
+    public String getMemoryInitialSize() {
+        return memoryInitialSize;
+    }
+
+    /**
+     * The maximum size of the memory for the underlying VM
+     * if javac is run externally; ignored otherwise.
+     * Defaults to the standard VM memory setting.
+     * (Examples: 83886080, 81920k, or 80m)
+     * @param memoryMaximumSize string to pass to VM
+     */
+    public void setMemoryMaximumSize(String memoryMaximumSize) {
+        this.memoryMaximumSize = memoryMaximumSize;
+    }
+
+    /**
+     * Gets the memoryMaximumSize flag.
+     * @return the memoryMaximumSize flag
+     */
+    public String getMemoryMaximumSize() {
+        return memoryMaximumSize;
+    }
+
+    /**
+     * Set the Java source file encoding name.
+     * @param encoding the source file encoding
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Gets the java source file encoding name.
+     * @return the source file encoding name
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Indicates whether source should be compiled
+     * with debug information; defaults to off.
+     * @param debug if true compile with debug information
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Gets the debug flag.
+     * @return the debug flag
+     */
+    public boolean getDebug() {
+        return debug;
+    }
+
+    /**
+     * If true, compiles with optimization enabled.
+     * @param optimize if true compile with optimization enabled
+     */
+    public void setOptimize(boolean optimize) {
+        this.optimize = optimize;
+    }
+
+    /**
+     * Gets the optimize flag.
+     * @return the optimize flag
+     */
+    public boolean getOptimize() {
+        return optimize;
+    }
+
+    /**
+     * Enables dependency-tracking for compilers
+     * that support this (jikes and classic).
+     * @param depend if true enable dependency-tracking
+     */
+    public void setDepend(boolean depend) {
+        this.depend = depend;
+    }
+
+    /**
+     * Gets the depend flag.
+     * @return the depend flag
+     */
+    public boolean getDepend() {
+        return depend;
+    }
+
+    /**
+     * If true, asks the compiler for verbose output.
+     * @param verbose if true, asks the compiler for verbose output
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Gets the verbose flag.
+     * @return the verbose flag
+     */
+    public boolean getVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Sets the target VM that the classes will be compiled for. Valid
+     * values depend on the compiler, for jdk 1.4 the valid values are
+     * "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "5" and "6".
+     * @param target the target VM
+     */
+    public void setTarget(String target) {
+        this.targetAttribute = target;
+    }
+
+    /**
+     * Gets the target VM that the classes will be compiled for.
+     * @return the target VM
+     */
+    public String getTarget() {
+        return targetAttribute != null
+            ? targetAttribute
+            : getProject().getProperty(MagicNames.BUILD_JAVAC_TARGET);
+    }
+
+    /**
+     * If true, includes Ant's own classpath in the classpath.
+     * @param include if true, includes Ant's own classpath in the classpath
+     */
+    public void setIncludeantruntime(boolean include) {
+        includeAntRuntime = include;
+    }
+
+    /**
+     * Gets whether or not the ant classpath is to be included in the classpath.
+     * @return whether or not the ant classpath is to be included in the classpath
+     */
+    public boolean getIncludeantruntime() {
+        return includeAntRuntime;
+    }
+
+    /**
+     * If true, includes the Java runtime libraries in the classpath.
+     * @param include if true, includes the Java runtime libraries in the classpath
+     */
+    public void setIncludejavaruntime(boolean include) {
+        includeJavaRuntime = include;
+    }
+
+    /**
+     * Gets whether or not the java runtime should be included in this
+     * task's classpath.
+     * @return the includejavaruntime attribute
+     */
+    public boolean getIncludejavaruntime() {
+        return includeJavaRuntime;
+    }
+
+    /**
+     * If true, forks the javac compiler.
+     *
+     * @param f "true|false|on|off|yes|no"
+     */
+    public void setFork(boolean f) {
+        fork = f;
+    }
+
+    /**
+     * Sets the name of the javac executable.
+     *
+     * <p>Ignored unless fork is true or extJavac has been specified
+     * as the compiler.</p>
+     * @param forkExec the name of the executable
+     */
+    public void setExecutable(String forkExec) {
+        forkedExecutable = forkExec;
+    }
+
+    /**
+     * The value of the executable attribute, if any.
+     *
+     * @since Ant 1.6
+     * @return the name of the java executable
+     */
+    public String getExecutable() {
+        return forkedExecutable;
+    }
+
+    /**
+     * Is this a forked invocation of JDK's javac?
+     * @return true if this is a forked invocation
+     */
+    public boolean isForkedJavac() {
+        return fork || "extJavac".equals(getCompiler());
+    }
+
+    /**
+     * The name of the javac executable to use in fork-mode.
+     *
+     * <p>This is either the name specified with the executable
+     * attribute or the full path of the javac compiler of the VM Ant
+     * is currently running in - guessed by Ant.</p>
+     *
+     * <p>You should <strong>not</strong> invoke this method if you
+     * want to get the value of the executable command - use {@link
+     * #getExecutable getExecutable} for this.</p>
+     * @return the name of the javac executable
+     */
+    public String getJavacExecutable() {
+        if (forkedExecutable == null && isForkedJavac()) {
+            forkedExecutable = getSystemJavac();
+        } else if (forkedExecutable != null && !isForkedJavac()) {
+            forkedExecutable = null;
+        }
+        return forkedExecutable;
+    }
+
+    /**
+     * If true, enables the -nowarn option.
+     * @param flag if true, enable the -nowarn option
+     */
+    public void setNowarn(boolean flag) {
+        this.nowarn = flag;
+    }
+
+    /**
+     * Should the -nowarn option be used.
+     * @return true if the -nowarn option should be used
+     */
+    public boolean getNowarn() {
+        return nowarn;
+    }
+
+    /**
+     * Adds an implementation specific command-line argument.
+     * @return a ImplementationSpecificArgument to be configured
+     */
+    public ImplementationSpecificArgument createCompilerArg() {
+        ImplementationSpecificArgument arg =
+            new ImplementationSpecificArgument();
+        facade.addImplementationArgument(arg);
+        return arg;
+    }
+
+    /**
+     * Get the additional implementation specific command line arguments.
+     * @return array of command line arguments, guaranteed to be non-null.
+     */
+    public String[] getCurrentCompilerArgs() {
+        String chosen = facade.getExplicitChoice();
+        try {
+            // make sure facade knows about magic properties and fork setting
+            String appliedCompiler = getCompiler();
+            facade.setImplementation(appliedCompiler);
+
+            String[] result = facade.getArgs();
+
+            String altCompilerName = getAltCompilerName(facade.getImplementation());
+
+            if (result.length == 0 && altCompilerName != null) {
+                facade.setImplementation(altCompilerName);
+                result = facade.getArgs();
+            }
+
+            return result;
+
+        } finally {
+            facade.setImplementation(chosen);
+        }
+    }
+
+    private String getAltCompilerName(String anImplementation) {
+        if (JAVAC16.equalsIgnoreCase(anImplementation)
+                || JAVAC15.equalsIgnoreCase(anImplementation)
+                || JAVAC14.equalsIgnoreCase(anImplementation)
+                || JAVAC13.equalsIgnoreCase(anImplementation)) {
+            return MODERN;
+        }
+        if (JAVAC12.equalsIgnoreCase(anImplementation)
+                || JAVAC11.equalsIgnoreCase(anImplementation)) {
+            return CLASSIC;
+        }
+        if (MODERN.equalsIgnoreCase(anImplementation)) {
+            String nextSelected = assumedJavaVersion();
+            if (JAVAC16.equalsIgnoreCase(nextSelected)
+                    || JAVAC15.equalsIgnoreCase(nextSelected)
+                    || JAVAC14.equalsIgnoreCase(nextSelected)
+                    || JAVAC13.equalsIgnoreCase(nextSelected)) {
+                return nextSelected;
+            }
+        }
+        if (CLASSIC.equals(anImplementation)) {
+            return assumedJavaVersion();
+        }
+        if (EXTJAVAC.equalsIgnoreCase(anImplementation)) {
+            return assumedJavaVersion();
+        }
+        return null;
+    }
+
+    /**
+     * Where Ant should place temporary files.
+     *
+     * @since Ant 1.6
+     * @param tmpDir the temporary directory
+     */
+    public void setTempdir(File tmpDir) {
+        this.tmpDir = tmpDir;
+    }
+
+    /**
+     * Where Ant should place temporary files.
+     *
+     * @since Ant 1.6
+     * @return the temporary directory
+     */
+    public File getTempdir() {
+        return tmpDir;
+    }
+
+    /**
+     * The property to set on compliation success.
+     * This property will not be set if the compilation
+     * fails, or if there are no files to compile.
+     * @param updatedProperty the property name to use.
+     * @since Ant 1.7.1.
+     */
+    public void setUpdatedProperty(String updatedProperty) {
+        this.updatedProperty = updatedProperty;
+    }
+
+    /**
+     * The property to set on compliation failure.
+     * This property will be set if the compilation
+     * fails.
+     * @param errorProperty the property name to use.
+     * @since Ant 1.7.1.
+     */
+    public void setErrorProperty(String errorProperty) {
+        this.errorProperty = errorProperty;
+    }
+
+    /**
+     * This property controls whether to include the
+     * destination classes directory in the classpath
+     * given to the compiler.
+     * The default value is "true".
+     * @param includeDestClasses the value to use.
+     */
+    public void setIncludeDestClasses(boolean includeDestClasses) {
+        this.includeDestClasses = includeDestClasses;
+    }
+
+    /**
+     * Get the value of the includeDestClasses property.
+     * @return the value.
+     */
+    public boolean isIncludeDestClasses() {
+        return includeDestClasses;
+    }
+
+    /**
+     * Get the result of the javac task (success or failure).
+     * @return true if compilation succeeded, or
+     *         was not neccessary, false if the compilation failed.
+     */
+    public boolean getTaskSuccess() {
+        return taskSuccess;
+    }
+
+    /**
+     * Executes the task.
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        checkParameters();
+        resetFileLists();
+
+        // scan source directories and dest directory to build up
+        // compile lists
+        String[] list = src.list();
+        for (int i = 0; i < list.length; i++) {
+            File srcDir = getProject().resolveFile(list[i]);
+            if (!srcDir.exists()) {
+                throw new BuildException("srcdir \""
+                                         + srcDir.getPath()
+                                         + "\" does not exist!", getLocation());
+            }
+
+            DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+            String[] files = ds.getIncludedFiles();
+
+            scanDir(srcDir, destDir != null ? destDir : srcDir, files);
+        }
+
+        compile();
+        if (updatedProperty != null
+            && taskSuccess
+            && compileList.length != 0) {
+            getProject().setNewProperty(updatedProperty, "true");
+        }
+    }
+
+    /**
+     * Clear the list of files to be compiled and copied..
+     */
+    protected void resetFileLists() {
+        compileList = new File[0];
+    }
+
+    /**
+     * Scans the directory looking for source files to be compiled.
+     * The results are returned in the class variable compileList
+     *
+     * @param srcDir   The source directory
+     * @param destDir  The destination directory
+     * @param files    An array of filenames
+     */
+    protected void scanDir(File srcDir, File destDir, String[] files) {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("*.java");
+        m.setTo("*.class");
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        File[] newFiles = sfs.restrictAsFiles(files, srcDir, destDir, m);
+
+        newFiles = removePackageInfoFiles(newFiles, srcDir, destDir);
+        if (newFiles.length > 0) {
+            File[] newCompileList
+                = new File[compileList.length + newFiles.length];
+            System.arraycopy(compileList, 0, newCompileList, 0,
+                    compileList.length);
+            System.arraycopy(newFiles, 0, newCompileList,
+                    compileList.length, newFiles.length);
+            compileList = newCompileList;
+        }
+    }
+
+    /**
+     * Gets the list of files to be compiled.
+     * @return the list of files as an array
+     */
+    public File[] getFileList() {
+        return compileList;
+    }
+
+    /**
+     * Is the compiler implementation a jdk compiler
+     *
+     * @param compilerImpl the name of the compiler implementation
+     * @return true if compilerImpl is "modern", "classic",
+     * "javac1.1", "javac1.2", "javac1.3", "javac1.4", "javac1.5" or
+     * "javac1.6".
+     */
+    protected boolean isJdkCompiler(String compilerImpl) {
+        return MODERN.equals(compilerImpl)
+            || CLASSIC.equals(compilerImpl)
+            || JAVAC16.equals(compilerImpl)
+            || JAVAC15.equals(compilerImpl)
+            || JAVAC14.equals(compilerImpl)
+            || JAVAC13.equals(compilerImpl)
+            || JAVAC12.equals(compilerImpl)
+            || JAVAC11.equals(compilerImpl);
+    }
+
+    /**
+     * @return the executable name of the java compiler
+     */
+    protected String getSystemJavac() {
+        return JavaEnvUtils.getJdkExecutable("javac");
+    }
+
+    /**
+     * Choose the implementation for this particular task.
+     * @param compiler the name of the compiler
+     * @since Ant 1.5
+     */
+    public void setCompiler(String compiler) {
+        facade.setImplementation(compiler);
+    }
+
+    /**
+     * The implementation for this particular task.
+     *
+     * <p>Defaults to the build.compiler property but can be overridden
+     * via the compiler and fork attributes.</p>
+     *
+     * <p>If fork has been set to true, the result will be extJavac
+     * and not classic or java1.2 - no matter what the compiler
+     * attribute looks like.</p>
+     *
+     * @see #getCompilerVersion
+     * @return the compiler.
+     * @since Ant 1.5
+     */
+    public String getCompiler() {
+        String compilerImpl = getCompilerVersion();
+        if (fork) {
+            if (isJdkCompiler(compilerImpl)) {
+                compilerImpl = "extJavac";
+            } else {
+                log("Since compiler setting isn't classic or modern, "
+                    + "ignoring fork setting.", Project.MSG_WARN);
+            }
+        }
+        return compilerImpl;
+    }
+
+    /**
+     * The implementation for this particular task.
+     *
+     * <p>Defaults to the build.compiler property but can be overridden
+     * via the compiler attribute.</p>
+     *
+     * <p>This method does not take the fork attribute into
+     * account.</p>
+     *
+     * @see #getCompiler
+     * @return the compiler.
+     *
+     * @since Ant 1.5
+     */
+    public String getCompilerVersion() {
+        facade.setMagicValue(getProject().getProperty("build.compiler"));
+        return facade.getImplementation();
+    }
+
+    /**
+     * Check that all required attributes have been set and nothing
+     * silly has been entered.
+     *
+     * @since Ant 1.5
+     * @exception BuildException if an error occurs
+     */
+    protected void checkParameters() throws BuildException {
+        if (src == null) {
+            throw new BuildException("srcdir attribute must be set!",
+                                     getLocation());
+        }
+        if (src.size() == 0) {
+            throw new BuildException("srcdir attribute must be set!",
+                                     getLocation());
+        }
+
+        if (destDir != null && !destDir.isDirectory()) {
+            throw new BuildException("destination directory \""
+                                     + destDir
+                                     + "\" does not exist "
+                                     + "or is not a directory", getLocation());
+        }
+    }
+
+    /**
+     * Perform the compilation.
+     *
+     * @since Ant 1.5
+     */
+    protected void compile() {
+        String compilerImpl = getCompiler();
+
+        if (compileList.length > 0) {
+            log("Compiling " + compileList.length + " source file"
+                + (compileList.length == 1 ? "" : "s")
+                + (destDir != null ? " to " + destDir : ""));
+
+            if (listFiles) {
+                for (int i = 0; i < compileList.length; i++) {
+                  String filename = compileList[i].getAbsolutePath();
+                  log(filename);
+                }
+            }
+
+            CompilerAdapter adapter =
+                CompilerAdapterFactory.getCompiler(compilerImpl, this);
+
+            // now we need to populate the compiler adapter
+            adapter.setJavac(this);
+
+            // finally, lets execute the compiler!!
+            if (adapter.execute()) {
+                // Success - check
+                for (Iterator i = updateDirList.iterator(); i.hasNext();) {
+                    File file = (File) i.next();
+                    file.setLastModified(System.currentTimeMillis());
+                }
+            } else {
+                // Fail path
+                this.taskSuccess = false;
+                if (errorProperty != null) {
+                    getProject().setNewProperty(
+                        errorProperty, "true");
+                }
+                if (failOnError) {
+                    throw new BuildException(FAIL_MSG, getLocation());
+                } else {
+                    log(FAIL_MSG, Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds an "compiler" attribute to Commandline$Attribute used to
+     * filter command line attributes based on the current
+     * implementation.
+     */
+    public class ImplementationSpecificArgument extends
+        org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
+
+        /**
+         * @param impl the name of the compiler
+         */
+        public void setCompiler(String impl) {
+            super.setImplementation(impl);
+        }
+    }
+
+    // ----------------------------------------------------------------
+    //  Code to remove package-info.java files from compilation
+    //  Since Ant 1.7.1.
+    //
+    //    package-info.java are files that contain package level
+    //    annotations. They may or may not have corresponding .class
+    //    files.
+    //
+    //    The following code uses the algorithm:
+    //     * on entry we have the files that need to be compiled
+    //     * if the filename is not package-info.java compile it
+    //     * if a corresponding .class file exists compile it
+    //     * if the corresponding class directory does not exist compile it
+    //     * if the corresponding directory lastmodifed time is
+    //       older than the java file, compile the java file and
+    //       touch the corresponding class directory (on successful
+    //       compilation).
+    //
+    // ----------------------------------------------------------------
+    private File[] removePackageInfoFiles(
+        File[] newFiles, File srcDir, File destDir) {
+        if (!hasPackageInfo(newFiles)) {
+            return newFiles;
+        }
+        List ret = new ArrayList();
+        for (int i = 0; i < newFiles.length; ++i) {
+            if (needsCompilePackageFile(newFiles[i], srcDir, destDir)) {
+                ret.add(newFiles[i]);
+            }
+        }
+        return (File[]) ret.toArray(new File[0]);
+    }
+
+    private boolean hasPackageInfo(File[] newFiles) {
+        for (int i = 0; i < newFiles.length; ++i) {
+            if (newFiles[i].getName().equals(PACKAGE_INFO_JAVA)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean needsCompilePackageFile(
+        File file, File srcDir, File destDir) {
+        if (!file.getName().equals(PACKAGE_INFO_JAVA)) {
+            return true;
+        }
+        // return true if destDir contains the file
+        String rel = relativePath(srcDir, file);
+        File destFile = new File(destDir, rel);
+        File parent = destFile.getParentFile();
+        destFile = new File(parent, PACKAGE_INFO_CLASS);
+        File sourceFile = new File(srcDir, rel);
+        if (destFile.exists()) {
+            return true;
+        }
+        // Dest file does not exist
+        // Compile Source file if sourceFile is newer that destDir
+        // TODO - use fs
+        if (sourceFile.lastModified()
+            > destFile.getParentFile().lastModified()) {
+            updateDirList.add(destFile.getParentFile());
+            return true;
+        }
+        return false;
+    }
+
+    private String relativePath(File src, File file) {
+        return file.getAbsolutePath().substring(
+            src.getAbsolutePath().length() + 1);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Javadoc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Javadoc.java
new file mode 100644
index 0000000..5074a41
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Javadoc.java
@@ -0,0 +1,2432 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.DirSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Generates Javadoc documentation for a collection
+ * of source code.
+ *
+ * <p>Current known limitations are:
+ *
+ * <p><ul>
+ *    <li>patterns must be of the form "xxx.*", every other pattern doesn't
+ *        work.
+ *    <li>there is no control on arguments sanity since they are left
+ *        to the Javadoc implementation.
+ * </ul>
+ *
+ * <p>If no <code>doclet</code> is set, then the <code>version</code> and
+ * <code>author</code> are by default <code>"yes"</code>.
+ *
+ * <p>Note: This task is run on another VM because the Javadoc code calls
+ * <code>System.exit()</code> which would break Ant functionality.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="java"
+ */
+public class Javadoc extends Task {
+    // Whether *this VM* is 1.4+ (but also check executable != null).
+
+    private static final boolean JAVADOC_4 =
+        !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+        && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3);
+
+    private static final boolean JAVADOC_5 = JAVADOC_4
+        && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4);
+
+    /**
+     * Inner class used to manage doclet parameters.
+     */
+    public class DocletParam {
+        /** The parameter name */
+        private String name;
+
+        /** The parameter value */
+        private String value;
+
+        /**
+         * Set the name of the parameter.
+         *
+         * @param name the name of the doclet parameter
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the parameter name.
+         *
+         * @return the parameter's name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the parameter value.
+         *
+         * Note that only string values are supported. No resolution of file
+         * paths is performed.
+         *
+         * @param value the parameter value.
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * Get the parameter value.
+         *
+         * @return the parameter value.
+         */
+        public String getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * A project aware class used for Javadoc extensions which take a name
+     * and a path such as doclet and taglet arguments.
+     *
+     */
+    public static class ExtensionInfo extends ProjectComponent {
+        /** The name of the extension */
+        private String name;
+
+        /** The optional path to use to load the extension */
+        private Path path;
+
+        /**
+         * Set the name of the extension
+         *
+         * @param name the extension's name.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the name of the extension.
+         *
+         * @return the extension's name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the path to use when loading the component.
+         *
+         * @param path a Path instance containing the classpath to use.
+         */
+        public void setPath(Path path) {
+            if (this.path == null) {
+                this.path = path;
+            } else {
+                this.path.append(path);
+            }
+        }
+
+        /**
+         * Get the extension's path.
+         *
+         * @return the path to be used to load the extension.
+         * May be <code>null</code>
+         */
+        public Path getPath() {
+            return path;
+        }
+
+        /**
+         * Create an empty nested path to be configured by Ant with the
+         * classpath for the extension.
+         *
+         * @return a new Path instance to be configured.
+         */
+        public Path createPath() {
+            if (path == null) {
+                path = new Path(getProject());
+            }
+            return path.createPath();
+        }
+
+        /**
+         * Adds a reference to a CLASSPATH defined elsewhere.
+         *
+         * @param r the reference containing the path.
+         */
+        public void setPathRef(Reference r) {
+            createPath().setRefid(r);
+        }
+    }
+
+    /**
+     * This class stores info about doclets.
+     *
+     */
+    public class DocletInfo extends ExtensionInfo {
+
+        /** Collection of doclet parameters. */
+        private Vector params = new Vector();
+
+        /**
+         * Create a doclet parameter to be configured by Ant.
+         *
+         * @return a new DocletParam instance to be configured.
+         */
+        public DocletParam createParam() {
+            DocletParam param = new DocletParam();
+            params.addElement(param);
+
+            return param;
+        }
+
+        /**
+         * Get the doclet's parameters.
+         *
+         * @return an Enumeration of DocletParam instances.
+         */
+        public Enumeration getParams() {
+            return params.elements();
+        }
+    }
+
+    /**
+     * Used to track info about the packages to be javadoc'd
+     */
+    public static class PackageName {
+        /** The package name */
+        private String name;
+
+        /**
+         * Set the name of the package
+         *
+         * @param name the package name.
+         */
+        public void setName(String name) {
+            this.name = name.trim();
+        }
+
+        /**
+         * Get the package name.
+         *
+         * @return the package's name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Return a string rep for this object.
+         * @return the package name.
+         */
+        public String toString() {
+            return getName();
+        }
+    }
+
+    /**
+     * This class is used to manage the source files to be processed.
+     */
+    public static class SourceFile {
+        /** The source file */
+        private File file;
+
+        /**
+         * Default constructor
+         */
+        public SourceFile() {
+            //empty
+        }
+
+        /**
+         * Constructor specifying the source file directly
+         *
+         * @param file the source file
+         */
+        public SourceFile(File file) {
+            this.file = file;
+        }
+
+        /**
+         * Set the source file.
+         *
+         * @param file the source file.
+         */
+        public void setFile(File file) {
+            this.file = file;
+        }
+
+        /**
+         * Get the source file.
+         *
+         * @return the source file.
+         */
+        public File getFile() {
+            return file;
+        }
+    }
+
+    /**
+     * An HTML element in the Javadoc.
+     *
+     * This class is used for those Javadoc elements which contain HTML such as
+     * footers, headers, etc.
+     */
+    public static class Html {
+        /** The text for the element */
+        private StringBuffer text = new StringBuffer();
+
+        /**
+         * Add text to the element.
+         *
+         * @param t the text to be added.
+         */
+        public void addText(String t) {
+            text.append(t);
+        }
+
+        /**
+         * Get the current text for the element.
+         *
+         * @return the current text.
+         */
+        public String getText() {
+            return text.substring(0);
+        }
+    }
+
+    /**
+     * EnumeratedAttribute implementation supporting the Javadoc scoping
+     * values.
+     */
+    public static class AccessType extends EnumeratedAttribute {
+        /**
+         * @return the allowed values for the access type.
+         */
+        public String[] getValues() {
+            // Protected first so if any GUI tool offers a default
+            // based on enum #0, it will be right.
+            return new String[] {"protected", "public", "package", "private"};
+        }
+    }
+
+    /**
+     * Holds a collection of ResourceCollections.
+     *
+     * <p>A separate kind of container is needed since this task
+     * contains special handling for FileSets that has to occur at
+     * task runtime.</p>
+     */
+    public class ResourceCollectionContainer {
+        private ArrayList rcs = new ArrayList();
+        /**
+         * Add a resource collection to the container.
+         * @param rc the collection to add.
+         */
+        public void add(ResourceCollection rc) {
+            rcs.add(rc);
+        }
+
+        /**
+         * Get an iterator on the collection.
+         * @return an iterator.
+         */
+        private Iterator iterator() {
+            return rcs.iterator();
+        }
+    }
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** The command line built to execute Javadoc. */
+    private Commandline cmd = new Commandline();
+
+    /**
+     * Utility method to add an argument to the command line conditionally
+     * based on the given flag.
+     *
+     * @param b the flag which controls if the argument is added.
+     * @param arg the argument value.
+     */
+    private void addArgIf(boolean b, String arg) {
+        if (b) {
+            cmd.createArgument().setValue(arg);
+        }
+    }
+
+    /**
+     * Utility method to add a Javadoc argument.
+     *
+     * @param key the argument name.
+     * @param value the argument value.
+     */
+    private void addArgIfNotEmpty(String key, String value) {
+        if (value != null && value.length() != 0) {
+            cmd.createArgument().setValue(key);
+            cmd.createArgument().setValue(value);
+        } else {
+            log("Warning: Leaving out empty argument '" + key + "'",
+                Project.MSG_WARN);
+        }
+    }
+
+    /**
+     * Flag which indicates if the task should fail if there is a
+     * Javadoc error.
+     */
+    private boolean failOnError = false;
+    private Path sourcePath = null;
+    private File destDir = null;
+    private Vector sourceFiles = new Vector();
+    private Vector packageNames = new Vector();
+    private Vector excludePackageNames = new Vector(1);
+    private boolean author = true;
+    private boolean version = true;
+    private DocletInfo doclet = null;
+    private Path classpath = null;
+    private Path bootclasspath = null;
+    private String group = null;
+    private String packageList = null;
+    private Vector links = new Vector();
+    private Vector groups = new Vector();
+    private Vector tags = new Vector();
+    private boolean useDefaultExcludes = true;
+    private Html doctitle = null;
+    private Html header = null;
+    private Html footer = null;
+    private Html bottom = null;
+    private boolean useExternalFile = false;
+    private String source = null;
+    private boolean linksource = false;
+    private boolean breakiterator = false;
+    private String noqualifier;
+    private boolean includeNoSourcePackages = false;
+    private boolean old = false;
+    private String executable = null;
+
+    private ResourceCollectionContainer nestedSourceFiles
+        = new ResourceCollectionContainer();
+    private Vector packageSets = new Vector();
+
+    /**
+     * Work around command line length limit by using an external file
+     * for the sourcefiles.
+     *
+     * @param b true if an external file is to be used.
+     */
+    public void setUseExternalFile(boolean b) {
+        useExternalFile = b;
+    }
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+     *                           should be used, "false"|"off"|"no" when they
+     *                           shouldn't be used.
+     */
+    public void setDefaultexcludes(boolean useDefaultExcludes) {
+        this.useDefaultExcludes = useDefaultExcludes;
+    }
+
+    /**
+     * Set the maximum memory to be used by the javadoc process
+     *
+     * @param max a string indicating the maximum memory according to the
+     *        JVM conventions (e.g. 128m is 128 Megabytes)
+     */
+    public void setMaxmemory(String max) {
+        cmd.createArgument().setValue("-J-Xmx" + max);
+    }
+
+    /**
+     * Set an additional parameter on the command line
+     *
+     * @param add the additional command line parameter for the javadoc task.
+     */
+    public void setAdditionalparam(String add) {
+        cmd.createArgument().setLine(add);
+    }
+
+    /**
+     * Adds a command-line argument.
+     * @return a command-line argument to configure
+     * @since Ant 1.6
+     */
+    public Commandline.Argument createArg() {
+        return cmd.createArgument();
+    }
+
+    /**
+     * Specify where to find source file
+     *
+     * @param src a Path instance containing the various source directories.
+     */
+    public void setSourcepath(Path src) {
+        if (sourcePath == null) {
+            sourcePath = src;
+        } else {
+            sourcePath.append(src);
+        }
+    }
+
+    /**
+     * Create a path to be configured with the locations of the source
+     * files.
+     *
+     * @return a new Path instance to be configured by the Ant core.
+     */
+    public Path createSourcepath() {
+        if (sourcePath == null) {
+            sourcePath = new Path(getProject());
+        }
+        return sourcePath.createPath();
+    }
+
+    /**
+     * Adds a reference to a CLASSPATH defined elsewhere.
+     *
+     * @param r the reference containing the source path definition.
+     */
+    public void setSourcepathRef(Reference r) {
+        createSourcepath().setRefid(r);
+    }
+
+    /**
+     * Set the directory where the Javadoc output will be generated.
+     *
+     * @param dir the destination directory.
+     */
+    public void setDestdir(File dir) {
+        destDir = dir;
+        cmd.createArgument().setValue("-d");
+        cmd.createArgument().setFile(destDir);
+    }
+
+    /**
+     * Set the list of source files to process.
+     *
+     * @param src a comma separated list of source files.
+     */
+    public void setSourcefiles(String src) {
+        StringTokenizer tok = new StringTokenizer(src, ",");
+        while (tok.hasMoreTokens()) {
+            String f = tok.nextToken();
+            SourceFile sf = new SourceFile();
+            sf.setFile(getProject().resolveFile(f.trim()));
+            addSource(sf);
+        }
+    }
+
+    /**
+     * Add a single source file.
+     *
+     * @param sf the source file to be processed.
+     */
+    public void addSource(SourceFile sf) {
+        sourceFiles.addElement(sf);
+    }
+
+    /**
+     * Set the package names to be processed.
+     *
+     * @param packages a comma separated list of packages specs
+     *        (may be wildcarded).
+     *
+     * @see #addPackage for wildcard information.
+     */
+    public void setPackagenames(String packages) {
+        StringTokenizer tok = new StringTokenizer(packages, ",");
+        while (tok.hasMoreTokens()) {
+            String p = tok.nextToken();
+            PackageName pn = new PackageName();
+            pn.setName(p);
+            addPackage(pn);
+        }
+    }
+
+    /**
+     * Add a single package to be processed.
+     *
+     * If the package name ends with &quot;.*&quot; the Javadoc task
+     * will find and process all subpackages.
+     *
+     * @param pn the package name, possibly wildcarded.
+     */
+    public void addPackage(PackageName pn) {
+        packageNames.addElement(pn);
+    }
+
+    /**
+     * Set the list of packages to be excluded.
+     *
+     * @param packages a comma separated list of packages to be excluded.
+     *        This may not include wildcards.
+     */
+    public void setExcludePackageNames(String packages) {
+        StringTokenizer tok = new StringTokenizer(packages, ",");
+        while (tok.hasMoreTokens()) {
+            String p = tok.nextToken();
+            PackageName pn = new PackageName();
+            pn.setName(p);
+            addExcludePackage(pn);
+        }
+    }
+
+    /**
+     * Add a package to be excluded from the Javadoc run.
+     *
+     * @param pn the name of the package (wildcards are not permitted).
+     */
+    public void addExcludePackage(PackageName pn) {
+        excludePackageNames.addElement(pn);
+    }
+
+    /**
+     * Specify the file containing the overview to be included in the generated
+     * documentation.
+     *
+     * @param f the file containing the overview.
+     */
+    public void setOverview(File f) {
+        cmd.createArgument().setValue("-overview");
+        cmd.createArgument().setFile(f);
+    }
+
+    /**
+     * Indicate whether only public classes and members are to be included in
+     * the scope processed
+     *
+     * @param b true if scope is to be public.
+     */
+    public void setPublic(boolean b) {
+        addArgIf(b, "-public");
+    }
+
+    /**
+     * Indicate whether only protected and public classes and members are to
+     * be included in the scope processed
+     *
+     * @param b true if scope is to be protected.
+     */
+    public void setProtected(boolean b) {
+        addArgIf(b, "-protected");
+    }
+
+    /**
+     * Indicate whether only package, protected and public classes and
+     * members are to be included in the scope processed
+     *
+     * @param b true if scope is to be package level.
+     */
+    public void setPackage(boolean b) {
+        addArgIf(b, "-package");
+    }
+
+    /**
+     * Indicate whether all classes and
+     * members are to be included in the scope processed
+     *
+     * @param b true if scope is to be private level.
+     */
+    public void setPrivate(boolean b) {
+        addArgIf(b, "-private");
+    }
+
+    /**
+     * Set the scope to be processed. This is an alternative to the
+     * use of the setPublic, setPrivate, etc methods. It gives better build
+     * file control over what scope is processed.
+     *
+     * @param at the scope to be processed.
+     */
+    public void setAccess(AccessType at) {
+        cmd.createArgument().setValue("-" + at.getValue());
+    }
+
+    /**
+     * Set the class that starts the doclet used in generating the
+     * documentation.
+     *
+     * @param docletName the name of the doclet class.
+     */
+    public void setDoclet(String docletName) {
+        if (doclet == null) {
+            doclet = new DocletInfo();
+            doclet.setProject(getProject());
+        }
+        doclet.setName(docletName);
+    }
+
+    /**
+     * Set the classpath used to find the doclet class.
+     *
+     * @param docletPath the doclet classpath.
+     */
+    public void setDocletPath(Path docletPath) {
+        if (doclet == null) {
+            doclet = new DocletInfo();
+            doclet.setProject(getProject());
+        }
+        doclet.setPath(docletPath);
+    }
+
+    /**
+     * Set the classpath used to find the doclet class by reference.
+     *
+     * @param r the reference to the Path instance to use as the doclet
+     *        classpath.
+     */
+    public void setDocletPathRef(Reference r) {
+        if (doclet == null) {
+            doclet = new DocletInfo();
+            doclet.setProject(getProject());
+        }
+        doclet.createPath().setRefid(r);
+    }
+
+    /**
+     * Create a doclet to be used in the documentation generation.
+     *
+     * @return a new DocletInfo instance to be configured.
+     */
+    public DocletInfo createDoclet() {
+        if (doclet == null) {
+            doclet = new DocletInfo();
+        }
+        return doclet;
+    }
+
+    /**
+     * Add a taglet
+     *
+     * @param tagletInfo information about the taglet.
+     */
+    public void addTaglet(ExtensionInfo tagletInfo) {
+        tags.addElement(tagletInfo);
+    }
+
+    /**
+     * Indicate whether Javadoc should produce old style (JDK 1.1)
+     * documentation.
+     *
+     * This is not supported by JDK 1.1 and has been phased out in JDK 1.4
+     *
+     * @param b if true attempt to generate old style documentation.
+     */
+    public void setOld(boolean b) {
+        old = b;
+    }
+
+    /**
+     * Set the classpath to be used for this Javadoc run.
+     *
+     * @param path an Ant Path object containing the compilation
+     *        classpath.
+     */
+    public void setClasspath(Path path) {
+        if (classpath == null) {
+            classpath = path;
+        } else {
+            classpath.append(path);
+        }
+    }
+
+    /**
+     * Create a Path to be configured with the classpath to use
+     *
+     * @return a new Path instance to be configured with the classpath.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Adds a reference to a CLASSPATH defined elsewhere.
+     *
+     * @param r the reference to an instance defining the classpath.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Set the boot classpath to use.
+     *
+     * @param path the boot classpath.
+     */
+    public void setBootclasspath(Path path) {
+        if (bootclasspath == null) {
+            bootclasspath = path;
+        } else {
+            bootclasspath.append(path);
+        }
+    }
+
+    /**
+     * Create a Path to be configured with the boot classpath
+     *
+     * @return a new Path instance to be configured with the boot classpath.
+     */
+    public Path createBootclasspath() {
+        if (bootclasspath == null) {
+            bootclasspath = new Path(getProject());
+        }
+        return bootclasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a CLASSPATH defined elsewhere.
+     *
+     * @param r the reference to an instance defining the bootclasspath.
+     */
+    public void setBootClasspathRef(Reference r) {
+        createBootclasspath().setRefid(r);
+    }
+
+    /**
+     * Set the location of the extensions directories.
+     *
+     * @param path the string version of the path.
+     * @deprecated since 1.5.x.
+     *             Use the {@link #setExtdirs(Path)} version.
+     */
+    public void setExtdirs(String path) {
+        cmd.createArgument().setValue("-extdirs");
+        cmd.createArgument().setValue(path);
+    }
+
+    /**
+     * Set the location of the extensions directories.
+     *
+     * @param path a path containing the extension directories.
+     */
+    public void setExtdirs(Path path) {
+        cmd.createArgument().setValue("-extdirs");
+        cmd.createArgument().setPath(path);
+    }
+
+    /**
+     * Run javadoc in verbose mode
+     *
+     * @param b true if operation is to be verbose.
+     */
+    public void setVerbose(boolean b) {
+        addArgIf(b, "-verbose");
+    }
+
+    /**
+     * Set the local to use in documentation generation.
+     *
+     * @param locale the locale to use.
+     */
+    public void setLocale(String locale) {
+        // createArgument(true) is necessary to make sure -locale
+        // is the first argument (required in 1.3+).
+        cmd.createArgument(true).setValue(locale);
+        cmd.createArgument(true).setValue("-locale");
+    }
+
+    /**
+     * Set the encoding name of the source files,
+     *
+     * @param enc the name of the encoding for the source files.
+     */
+    public void setEncoding(String enc) {
+        cmd.createArgument().setValue("-encoding");
+        cmd.createArgument().setValue(enc);
+    }
+
+    /**
+     * Include the version tag in the generated documentation.
+     *
+     * @param b true if the version tag should be included.
+     */
+    public void setVersion(boolean b) {
+        this.version = b;
+    }
+
+    /**
+     * Generate the &quot;use&quot page for each package.
+     *
+     * @param b true if the use page should be generated.
+     */
+    public void setUse(boolean b) {
+        addArgIf(b, "-use");
+    }
+
+
+    /**
+     * Include the author tag in the generated documentation.
+     *
+     * @param b true if the author tag should be included.
+     */
+    public void setAuthor(boolean b) {
+        author = b;
+    }
+
+    /**
+     * Generate a split index
+     *
+     * @param b true if the index should be split into a file per letter.
+     */
+    public void setSplitindex(boolean b) {
+        addArgIf(b, "-splitindex");
+    }
+
+    /**
+     * Set the title to be placed in the HTML &lt;title&gt; tag of the
+     * generated documentation.
+     *
+     * @param title the window title to use.
+     */
+    public void setWindowtitle(String title) {
+        addArgIfNotEmpty("-windowtitle", title);
+    }
+
+    /**
+     * Set the title of the generated overview page.
+     *
+     * @param doctitle the Document title.
+     */
+    public void setDoctitle(String doctitle) {
+        Html h = new Html();
+        h.addText(doctitle);
+        addDoctitle(h);
+    }
+
+    /**
+     * Add a document title to use for the overview page.
+     *
+     * @param text the HTML element containing the document title.
+     */
+    public void addDoctitle(Html text) {
+        doctitle = text;
+    }
+
+    /**
+     * Set the header text to be placed at the top of each output file.
+     *
+     * @param header the header text
+     */
+    public void setHeader(String header) {
+        Html h = new Html();
+        h.addText(header);
+        addHeader(h);
+    }
+
+    /**
+     * Set the header text to be placed at the top of each output file.
+     *
+     * @param text the header text
+     */
+    public void addHeader(Html text) {
+        header = text;
+    }
+
+    /**
+     * Set the footer text to be placed at the bottom of each output file.
+     *
+     * @param footer the footer text.
+     */
+    public void setFooter(String footer) {
+        Html h = new Html();
+        h.addText(footer);
+        addFooter(h);
+    }
+
+    /**
+     * Set the footer text to be placed at the bottom of each output file.
+     *
+     * @param text the footer text.
+     */
+    public void addFooter(Html text) {
+        footer = text;
+    }
+
+    /**
+     * Set the text to be placed at the bottom of each output file.
+     *
+     * @param bottom the bottom text.
+     */
+    public void setBottom(String bottom) {
+        Html h = new Html();
+        h.addText(bottom);
+        addBottom(h);
+    }
+
+    /**
+     * Set the text to be placed at the bottom of each output file.
+     *
+     * @param text the bottom text.
+     */
+    public void addBottom(Html text) {
+        bottom = text;
+    }
+
+    /**
+     * Link to docs at "url" using package list at "url2"
+     * - separate the URLs by using a space character.
+     *
+     * @param src the offline link specification (url and package list)
+     */
+    public void setLinkoffline(String src) {
+        LinkArgument le = createLink();
+        le.setOffline(true);
+        String linkOfflineError = "The linkoffline attribute must include"
+            + " a URL and a package-list file location separated by a"
+            + " space";
+        if (src.trim().length() == 0) {
+            throw new BuildException(linkOfflineError);
+        }
+        StringTokenizer tok = new StringTokenizer(src, " ", false);
+        le.setHref(tok.nextToken());
+
+        if (!tok.hasMoreTokens()) {
+            throw new BuildException(linkOfflineError);
+        }
+        le.setPackagelistLoc(getProject().resolveFile(tok.nextToken()));
+    }
+
+    /**
+     * Group specified packages together in overview page.
+     *
+     * @param src the group packages - a command separated list of group specs,
+     *        each one being a group name and package specification separated
+     *        by a space.
+     */
+    public void setGroup(String src) {
+        group = src;
+    }
+
+    /**
+     * Create links to Javadoc output at the given URL.
+     * @param src the URL to link to
+     */
+    public void setLink(String src) {
+        createLink().setHref(src);
+    }
+
+    /**
+     * Control deprecation infromation
+     *
+     * @param b If true, do not include deprecated information.
+     */
+    public void setNodeprecated(boolean b) {
+        addArgIf(b, "-nodeprecated");
+    }
+
+    /**
+     * Control deprecated list generation
+     *
+     * @param b if true, do not generate deprecated list.
+     */
+    public void setNodeprecatedlist(boolean b) {
+        addArgIf(b, "-nodeprecatedlist");
+    }
+
+    /**
+     * Control class tree generation.
+     *
+     * @param b if true, do not generate class hierarchy.
+     */
+    public void setNotree(boolean b) {
+        addArgIf(b, "-notree");
+    }
+
+    /**
+     * Control generation of index.
+     *
+     * @param b if true, do not generate index.
+     */
+    public void setNoindex(boolean b) {
+        addArgIf(b, "-noindex");
+    }
+
+    /**
+     * Control generation of help link.
+     *
+     * @param b if true, do not generate help link
+     */
+    public void setNohelp(boolean b) {
+        addArgIf(b, "-nohelp");
+    }
+
+    /**
+     * Control generation of the navigation bar.
+     *
+     * @param b if true, do not generate navigation bar.
+     */
+    public void setNonavbar(boolean b) {
+        addArgIf(b, "-nonavbar");
+    }
+
+    /**
+     * Control warnings about serial tag.
+     *
+     * @param b if true, generate warning about the serial tag.
+     */
+    public void setSerialwarn(boolean b) {
+        addArgIf(b, "-serialwarn");
+    }
+
+    /**
+     * Specifies the CSS stylesheet file to use.
+     *
+     * @param f the file with the CSS to use.
+     */
+    public void setStylesheetfile(File f) {
+        cmd.createArgument().setValue("-stylesheetfile");
+        cmd.createArgument().setFile(f);
+    }
+
+    /**
+     * Specifies the HTML help file to use.
+     *
+     * @param f the file containing help content.
+     */
+    public void setHelpfile(File f) {
+        cmd.createArgument().setValue("-helpfile");
+        cmd.createArgument().setFile(f);
+    }
+
+    /**
+     * Output file encoding name.
+     *
+     * @param enc name of the encoding to use.
+     */
+    public void setDocencoding(String enc) {
+        cmd.createArgument().setValue("-docencoding");
+        cmd.createArgument().setValue(enc);
+    }
+
+    /**
+     * The name of a file containing the packages to process.
+     *
+     * @param src the file containing the package list.
+     */
+    public void setPackageList(String src) {
+        packageList = src;
+    }
+
+    /**
+     * Create link to Javadoc output at the given URL.
+     *
+     * @return link argument to configure
+     */
+    public LinkArgument createLink() {
+        LinkArgument la = new LinkArgument();
+        links.addElement(la);
+        return la;
+    }
+
+    /**
+     * Represents a link triplet (href, whether link is offline,
+     * location of the package list if off line)
+     */
+    public class LinkArgument {
+        private String href;
+        private boolean offline = false;
+        private File packagelistLoc;
+        private boolean resolveLink = false;
+
+        /** Constructor for LinkArguement */
+        public LinkArgument() {
+            //empty
+        }
+
+        /**
+         * Set the href attribute.
+         * @param hr a <code>String</code> value
+         */
+        public void setHref(String hr) {
+            href = hr;
+        }
+
+        /**
+         * Get the href attribute.
+         * @return the href attribute.
+         */
+        public String getHref() {
+            return href;
+        }
+
+        /**
+         * Set the packetlist location attribute.
+         * @param src a <code>File</code> value
+         */
+        public void setPackagelistLoc(File src) {
+            packagelistLoc = src;
+        }
+
+        /**
+         * Get the packetList location attribute.
+         * @return the packetList location attribute.
+         */
+        public File getPackagelistLoc() {
+            return packagelistLoc;
+        }
+
+        /**
+         * Set the offline attribute.
+         * @param offline a <code>boolean</code> value
+         */
+        public void setOffline(boolean offline) {
+            this.offline = offline;
+        }
+
+        /**
+         * Get the linkOffline attribute.
+         * @return the linkOffline attribute.
+         */
+        public boolean isLinkOffline() {
+            return offline;
+        }
+
+        /**
+         * Sets whether Ant should resolve the link attribute relative
+         * to the current basedir.
+         * @param resolve a <code>boolean</code> value
+         */
+        public void setResolveLink(boolean resolve) {
+            this.resolveLink = resolve;
+        }
+
+        /**
+         * should Ant resolve the link attribute relative to the
+         * current basedir?
+         * @return the resolveLink attribute.
+         */
+        public boolean shouldResolveLink() {
+            return resolveLink;
+        }
+
+    }
+
+    /**
+     * Creates and adds a -tag argument. This is used to specify
+     * custom tags. This argument is only available for Javadoc 1.4,
+     * and will generate a verbose message (and then be ignored)
+     * when run on Java versions below 1.4.
+     * @return tag argument to be configured
+     */
+    public TagArgument createTag() {
+        TagArgument ta = new TagArgument();
+        tags.addElement (ta);
+        return ta;
+    }
+
+    /**
+     * Scope element verbose names. (Defined here as fields
+     * cannot be static in inner classes.) The first letter
+     * from each element is used to build up the scope string.
+     */
+    static final String[] SCOPE_ELEMENTS = {
+        "overview", "packages", "types", "constructors",
+        "methods", "fields"
+    };
+
+    /**
+     * Class representing a -tag argument.
+     */
+    public class TagArgument extends FileSet {
+        /** Name of the tag. */
+        private String name = null;
+        /** Whether or not the tag is enabled. */
+        private boolean enabled = true;
+        /**
+         * Scope string of the tag. This will form the middle
+         * argument of the -tag parameter when the tag is enabled
+         * (with an X prepended for and is parsed from human-readable form.
+         */
+        private String scope = "a";
+
+        /** Sole constructor. */
+        public TagArgument () {
+            //empty
+        }
+
+        /**
+         * Sets the name of the tag.
+         *
+         * @param name The name of the tag.
+         *             Must not be <code>null</code> or empty.
+         */
+        public void setName (String name) {
+            this.name = name;
+        }
+
+        /**
+         * Sets the scope of the tag. This is in comma-separated
+         * form, with each element being one of "all" (the default),
+         * "overview", "packages", "types", "constructors", "methods",
+         * "fields". The elements are treated in a case-insensitive
+         * manner.
+         *
+         * @param verboseScope The scope of the tag.
+         *                     Must not be <code>null</code>,
+         *                     should not be empty.
+         *
+         * @exception BuildException if all is specified along with
+         * other elements, if any elements are repeated, if no
+         * elements are specified, or if any unrecognised elements are
+         * specified.
+         */
+        public void setScope (String verboseScope) throws BuildException {
+            verboseScope = verboseScope.toLowerCase(Locale.US);
+
+            boolean[] elements = new boolean[SCOPE_ELEMENTS.length];
+
+            boolean gotAll = false;
+            boolean gotNotAll = false;
+
+            // Go through the tokens one at a time, updating the
+            // elements array and issuing warnings where appropriate.
+            StringTokenizer tok = new StringTokenizer (verboseScope, ",");
+            while (tok.hasMoreTokens()) {
+                String next = tok.nextToken().trim();
+                if (next.equals("all")) {
+                    if (gotAll) {
+                        getProject().log ("Repeated tag scope element: all",
+                                          Project.MSG_VERBOSE);
+                    }
+                    gotAll = true;
+                } else {
+                    int i;
+                    for (i = 0; i < SCOPE_ELEMENTS.length; i++) {
+                        if (next.equals (SCOPE_ELEMENTS[i])) {
+                            break;
+                        }
+                    }
+                    if (i == SCOPE_ELEMENTS.length) {
+                        throw new BuildException ("Unrecognised scope element: "
+                                                  + next);
+                    } else {
+                        if (elements[i]) {
+                            getProject().log ("Repeated tag scope element: "
+                                              + next, Project.MSG_VERBOSE);
+                        }
+                        elements[i] = true;
+                        gotNotAll = true;
+                    }
+                }
+            }
+
+            if (gotNotAll && gotAll) {
+                throw new BuildException ("Mixture of \"all\" and other scope "
+                                          + "elements in tag parameter.");
+            }
+            if (!gotNotAll && !gotAll) {
+                throw new BuildException ("No scope elements specified in tag "
+                                          + "parameter.");
+            }
+            if (gotAll) {
+                this.scope = "a";
+            } else {
+                StringBuffer buff = new StringBuffer (elements.length);
+                for (int i = 0; i < elements.length; i++) {
+                    if (elements[i]) {
+                        buff.append (SCOPE_ELEMENTS[i].charAt(0));
+                    }
+                }
+                this.scope = buff.toString();
+            }
+        }
+
+        /**
+         * Sets whether or not the tag is enabled.
+         *
+         * @param enabled Whether or not this tag is enabled.
+         */
+        public void setEnabled (boolean enabled) {
+            this.enabled = enabled;
+        }
+
+        /**
+         * Returns the -tag parameter this argument represented.
+         * @return the -tag parameter as a string
+         * @exception BuildException if either the name or description
+         *                           is <code>null</code> or empty.
+         */
+        public String getParameter() throws BuildException {
+            if (name == null || name.equals("")) {
+                throw new BuildException ("No name specified for custom tag.");
+            }
+            if (getDescription() != null) {
+                return name + ":" + (enabled ? "" : "X")
+                    + scope + ":" + getDescription();
+            } else if (!enabled || !"a".equals(scope)) {
+                return name + ":" + (enabled ? "" : "X") + scope;
+            } else {
+                return name;
+            }
+        }
+    }
+
+    /**
+     * Separates packages on the overview page into whatever
+     * groups you specify, one group per table.
+     * @return a group argument to be configured
+     */
+    public GroupArgument createGroup() {
+        GroupArgument ga = new GroupArgument();
+        groups.addElement(ga);
+        return ga;
+    }
+
+
+    /**
+     * A class corresponding to the group nested element.
+     */
+    public class GroupArgument {
+        private Html title;
+        private Vector packages = new Vector();
+
+        /** Constructor for GroupArgument */
+        public GroupArgument() {
+            //empty
+        }
+
+        /**
+         * Set the title attribute using a string.
+         * @param src a <code>String</code> value
+         */
+        public void setTitle(String src) {
+            Html h = new Html();
+            h.addText(src);
+            addTitle(h);
+        }
+        /**
+         * Set the title attribute using a nested Html value.
+         * @param text a <code>Html</code> value
+         */
+        public void addTitle(Html text) {
+            title = text;
+        }
+
+        /**
+         * Get the title.
+         * @return the title
+         */
+        public String getTitle() {
+            return title != null ? title.getText() : null;
+        }
+
+        /**
+         * Set the packages to Javadoc on.
+         * @param src a comma separated list of packages
+         */
+        public void setPackages(String src) {
+            StringTokenizer tok = new StringTokenizer(src, ",");
+            while (tok.hasMoreTokens()) {
+                String p = tok.nextToken();
+                PackageName pn = new PackageName();
+                pn.setName(p);
+                addPackage(pn);
+            }
+        }
+        /**
+         * Add a package nested element.
+         * @param pn a nested element specifing the package.
+         */
+        public void addPackage(PackageName pn) {
+            packages.addElement(pn);
+        }
+
+        /**
+         * Get the packages as a collon separated list.
+         * @return the packages as a string
+         */
+        public String getPackages() {
+            StringBuffer p = new StringBuffer();
+            for (int i = 0; i < packages.size(); i++) {
+                if (i > 0) {
+                    p.append(":");
+                }
+                p.append(packages.elementAt(i).toString());
+            }
+            return p.toString();
+        }
+    }
+
+    /**
+     * Charset for cross-platform viewing of generated documentation.
+     * @param src the name of the charset
+     */
+    public void setCharset(String src) {
+        this.addArgIfNotEmpty("-charset", src);
+    }
+
+    /**
+     * Should the build process fail if Javadoc fails (as indicated by
+     * a non zero return code)?
+     *
+     * <p>Default is false.</p>
+     * @param b a <code>boolean</code> value
+     */
+    public void setFailonerror(boolean b) {
+        failOnError = b;
+    }
+
+    /**
+     * Enables the -source switch, will be ignored if Javadoc is not
+     * the 1.4 version.
+     * @param source a <code>String</code> value
+     * @since Ant 1.5
+     */
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    /**
+     * Sets the actual executable command to invoke, instead of the binary
+     * <code>javadoc</code> found in Ant's JDK.
+     * @param executable the command to invoke.
+     * @since Ant 1.6.3
+     */
+    public void setExecutable(String executable) {
+        this.executable = executable;
+    }
+
+    /**
+     * Adds a packageset.
+     *
+     * <p>All included directories will be translated into package
+     * names be converting the directory separator into dots.</p>
+     * @param packageSet a directory set
+     * @since 1.5
+     */
+    public void addPackageset(DirSet packageSet) {
+        packageSets.addElement(packageSet);
+    }
+
+    /**
+     * Adds a fileset.
+     *
+     * <p>All included files will be added as sourcefiles.  The task
+     * will automatically add
+     * <code>includes=&quot;**&#47;*.java&quot;</code> to the
+     * fileset.</p>
+     * @param fs a file set
+     * @since 1.5
+     */
+    public void addFileset(FileSet fs) {
+        createSourceFiles().add(fs);
+    }
+
+    /**
+     * Adds a container for resource collections.
+     *
+     * <p>All included files will be added as sourcefiles.</p>
+     * @return the source files to configure.
+     * @since 1.7
+     */
+    public ResourceCollectionContainer createSourceFiles() {
+        return nestedSourceFiles;
+    }
+
+    /**
+     * Enables the -linksource switch, will be ignored if Javadoc is not
+     * the 1.4 version. Default is false
+     * @param b a <code>String</code> value
+     * @since Ant 1.6
+     */
+    public void setLinksource(boolean b) {
+        this.linksource = b;
+    }
+
+    /**
+     * Enables the -linksource switch, will be ignored if Javadoc is not
+     * the 1.4 version. Default is false
+     * @param b a <code>String</code> value
+     * @since Ant 1.6
+     */
+    public void setBreakiterator(boolean b) {
+        this.breakiterator = b;
+    }
+
+    /**
+     * Enables the -noqualifier switch, will be ignored if Javadoc is not
+     * the 1.4 version.
+     * @param noqualifier the parameter to the -noqualifier switch
+     * @since Ant 1.6
+     */
+    public void setNoqualifier(String noqualifier) {
+        this.noqualifier = noqualifier;
+    }
+
+    /**
+     * If set to true, Ant will also accept packages that only hold
+     * package.html files but no Java sources.
+     * @param b a <code>boolean</code> value.
+     * @since Ant 1.6.3
+     */
+    public void setIncludeNoSourcePackages(boolean b) {
+        this.includeNoSourcePackages = b;
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        checkTaskName();
+
+        Vector packagesToDoc = new Vector();
+        Path sourceDirs = new Path(getProject());
+
+        checkPackageAndSourcePath();
+
+        if (sourcePath != null) {
+            sourceDirs.addExisting(sourcePath);
+        }
+
+        parsePackages(packagesToDoc, sourceDirs);
+        checkPackages(packagesToDoc, sourceDirs);
+
+        Vector sourceFilesToDoc = (Vector) sourceFiles.clone();
+        addSourceFiles(sourceFilesToDoc);
+
+        checkPackagesToDoc(packagesToDoc, sourceFilesToDoc);
+
+        log("Generating Javadoc", Project.MSG_INFO);
+
+        Commandline toExecute = (Commandline) cmd.clone();
+        if (executable != null) {
+            toExecute.setExecutable(executable);
+        } else {
+            toExecute.setExecutable(JavaEnvUtils.getJdkExecutable("javadoc"));
+        }
+
+        //  Javadoc arguments
+        generalJavadocArguments(toExecute);  // general Javadoc arguments
+        doSourcePath(toExecute, sourceDirs); // sourcepath
+        doDoclet(toExecute);   // arguments for default doclet
+        doBootPath(toExecute); // bootpath
+        doLinks(toExecute);    // links arguments
+        doGroup(toExecute);    // group attribute
+        doGroups(toExecute);  // groups attribute
+
+        // Javadoc 1.4 parameters
+        if (JAVADOC_4 || executable != null) {
+            doJava14(toExecute);
+            if (breakiterator && (doclet == null || JAVADOC_5)) {
+                toExecute.createArgument().setValue("-breakiterator");
+            }
+        } else {
+            doNotJava14();
+        }
+        // Javadoc 1.2/1.3 parameters:
+        if (!JAVADOC_4 || executable != null) {
+            if (old) {
+                toExecute.createArgument().setValue("-1.1");
+            }
+        } else {
+            if (old) {
+                log("Javadoc 1.4 doesn't support the -1.1 switch anymore",
+                    Project.MSG_WARN);
+            }
+        }
+        // If using an external file, write the command line options to it
+        if (useExternalFile && JAVADOC_4) {
+            writeExternalArgs(toExecute);
+        }
+
+        File tmpList = null;
+        PrintWriter srcListWriter = null;
+
+        try {
+            /**
+             * Write sourcefiles and package names to a temporary file
+             * if requested.
+             */
+            if (useExternalFile) {
+                tmpList = FILE_UTILS.createTempFile("javadoc", "", null, true, true);
+                toExecute.createArgument()
+                    .setValue("@" + tmpList.getAbsolutePath());
+                srcListWriter = new PrintWriter(
+                    new FileWriter(tmpList.getAbsolutePath(),
+                                   true));
+            }
+
+            doSourceAndPackageNames(
+                toExecute, packagesToDoc, sourceFilesToDoc,
+                useExternalFile, tmpList, srcListWriter);
+        } catch (IOException e) {
+            tmpList.delete();
+            throw new BuildException("Error creating temporary file",
+                                     e, getLocation());
+        } finally {
+            if (srcListWriter != null) {
+                srcListWriter.close();
+            }
+        }
+
+        if (packageList != null) {
+            toExecute.createArgument().setValue("@" + packageList);
+        }
+        log(toExecute.describeCommand(), Project.MSG_VERBOSE);
+
+        log("Javadoc execution", Project.MSG_INFO);
+
+        JavadocOutputStream out = new JavadocOutputStream(Project.MSG_INFO);
+        JavadocOutputStream err = new JavadocOutputStream(Project.MSG_WARN);
+        Execute exe = new Execute(new PumpStreamHandler(out, err));
+        exe.setAntRun(getProject());
+
+        /*
+         * No reason to change the working directory as all filenames and
+         * path components have been resolved already.
+         *
+         * Avoid problems with command line length in some environments.
+         */
+        exe.setWorkingDirectory(null);
+        try {
+            exe.setCommandline(toExecute.getCommandline());
+            int ret = exe.execute();
+            if (ret != 0 && failOnError) {
+                throw new BuildException("Javadoc returned " + ret,
+                                         getLocation());
+            }
+        } catch (IOException e) {
+            throw new BuildException("Javadoc failed: " + e, e, getLocation());
+        } finally {
+            if (tmpList != null) {
+                tmpList.delete();
+                tmpList = null;
+            }
+
+            out.logFlush();
+            err.logFlush();
+            try {
+                out.close();
+                err.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+    }
+
+    private void checkTaskName() {
+        if ("javadoc2".equals(getTaskType())) {
+            log("Warning: the task name <javadoc2> is deprecated."
+                + " Use <javadoc> instead.",
+                Project.MSG_WARN);
+        }
+    }
+
+    private void checkPackageAndSourcePath() {
+        if (packageList != null && sourcePath == null) {
+            String msg = "sourcePath attribute must be set when "
+                + "specifying packagelist.";
+            throw new BuildException(msg);
+        }
+    }
+
+    private void checkPackages(Vector packagesToDoc, Path sourceDirs) {
+        if (packagesToDoc.size() != 0 && sourceDirs.size() == 0) {
+            String msg = "sourcePath attribute must be set when "
+                + "specifying package names.";
+            throw new BuildException(msg);
+        }
+    }
+
+    private void checkPackagesToDoc(
+        Vector packagesToDoc, Vector sourceFilesToDoc) {
+        if (packageList == null && packagesToDoc.size() == 0
+            && sourceFilesToDoc.size() == 0) {
+            throw new BuildException("No source files and no packages have "
+                                     + "been specified.");
+        }
+    }
+
+    private void doSourcePath(Commandline toExecute, Path sourceDirs) {
+        if (sourceDirs.size() > 0) {
+            toExecute.createArgument().setValue("-sourcepath");
+            toExecute.createArgument().setPath(sourceDirs);
+        }
+    }
+
+    private void generalJavadocArguments(Commandline toExecute) {
+        if (doctitle != null) {
+            toExecute.createArgument().setValue("-doctitle");
+            toExecute.createArgument().setValue(expand(doctitle.getText()));
+        }
+        if (header != null) {
+            toExecute.createArgument().setValue("-header");
+            toExecute.createArgument().setValue(expand(header.getText()));
+        }
+        if (footer != null) {
+            toExecute.createArgument().setValue("-footer");
+            toExecute.createArgument().setValue(expand(footer.getText()));
+        }
+        if (bottom != null) {
+            toExecute.createArgument().setValue("-bottom");
+            toExecute.createArgument().setValue(expand(bottom.getText()));
+        }
+
+        if (classpath == null) {
+            classpath = (new Path(getProject())).concatSystemClasspath("last");
+        } else {
+            classpath = classpath.concatSystemClasspath("ignore");
+        }
+
+        if (classpath.size() > 0) {
+            toExecute.createArgument().setValue("-classpath");
+            toExecute.createArgument().setPath(classpath);
+        }
+
+        if (version && doclet == null) {
+            toExecute.createArgument().setValue("-version");
+        }
+        if (author && doclet == null) {
+            toExecute.createArgument().setValue("-author");
+        }
+
+        if (doclet == null && destDir == null) {
+            throw new BuildException("destdir attribute must be set!");
+        }
+    }
+
+    private void doDoclet(Commandline toExecute) {
+        if (doclet != null) {
+            if (doclet.getName() == null) {
+                throw new BuildException("The doclet name must be "
+                                         + "specified.", getLocation());
+            } else {
+                toExecute.createArgument().setValue("-doclet");
+                toExecute.createArgument().setValue(doclet.getName());
+                if (doclet.getPath() != null) {
+                    Path docletPath
+                        = doclet.getPath().concatSystemClasspath("ignore");
+                    if (docletPath.size() != 0) {
+                        toExecute.createArgument().setValue("-docletpath");
+                        toExecute.createArgument().setPath(docletPath);
+                    }
+                }
+                for (Enumeration e = doclet.getParams();
+                     e.hasMoreElements();) {
+                    DocletParam param = (DocletParam) e.nextElement();
+                    if (param.getName() == null) {
+                        throw new BuildException("Doclet parameters must "
+                                                 + "have a name");
+                    }
+
+                    toExecute.createArgument().setValue(param.getName());
+                    if (param.getValue() != null) {
+                        toExecute.createArgument()
+                            .setValue(param.getValue());
+                    }
+                }
+            }
+        }
+    }
+
+    private void writeExternalArgs(Commandline toExecute) {
+        // If using an external file, write the command line options to it
+        File optionsTmpFile = null;
+        PrintWriter optionsListWriter = null;
+        try {
+            optionsTmpFile = FILE_UTILS.createTempFile(
+                "javadocOptions", "", null, true, true);
+            String[] listOpt = toExecute.getArguments();
+            toExecute.clearArgs();
+            toExecute.createArgument().setValue(
+                "@" + optionsTmpFile.getAbsolutePath());
+            optionsListWriter = new PrintWriter(
+                new FileWriter(optionsTmpFile.getAbsolutePath(), true));
+            for (int i = 0; i < listOpt.length; i++) {
+                String string = listOpt[i];
+                if (string.startsWith("-J-")) {
+                    toExecute.createArgument().setValue(string);
+                } else  {
+                    if (string.startsWith("-")) {
+                        optionsListWriter.print(string);
+                        optionsListWriter.print(" ");
+                    } else {
+                        optionsListWriter.println(quoteString(string));
+                    }
+                }
+            }
+            optionsListWriter.close();
+        } catch (IOException ex) {
+            if (optionsTmpFile != null) {
+                optionsTmpFile.delete();
+            }
+            throw new BuildException(
+                "Error creating or writing temporary file for javadoc options",
+                ex, getLocation());
+        } finally {
+            FILE_UTILS.close(optionsListWriter);
+        }
+    }
+
+    private void doBootPath(Commandline toExecute) {
+        Path bcp = new Path(getProject());
+        if (bootclasspath != null) {
+            bcp.append(bootclasspath);
+        }
+        bcp = bcp.concatSystemBootClasspath("ignore");
+        if (bcp.size() > 0) {
+            toExecute.createArgument().setValue("-bootclasspath");
+            toExecute.createArgument().setPath(bcp);
+        }
+    }
+
+    private void doLinks(Commandline toExecute) {
+        if (links.size() != 0) {
+            for (Enumeration e = links.elements(); e.hasMoreElements();) {
+                LinkArgument la = (LinkArgument) e.nextElement();
+
+                if (la.getHref() == null || la.getHref().length() == 0) {
+                    log("No href was given for the link - skipping",
+                        Project.MSG_VERBOSE);
+                    continue;
+                }
+                String link = null;
+                if (la.shouldResolveLink()) {
+                    File hrefAsFile =
+                        getProject().resolveFile(la.getHref());
+                    if (hrefAsFile.exists()) {
+                        try {
+                            link = FILE_UTILS.getFileURL(hrefAsFile)
+                                .toExternalForm();
+                        } catch (MalformedURLException ex) {
+                            // should be impossible
+                            log("Warning: link location was invalid "
+                                + hrefAsFile, Project.MSG_WARN);
+                        }
+                    }
+                }
+                if (link == null) {
+                    // is the href a valid URL
+                    try {
+                        URL base = new URL("file://.");
+                        new URL(base, la.getHref());
+                        link = la.getHref();
+                    } catch (MalformedURLException mue) {
+                        // ok - just skip
+                        log("Link href \"" + la.getHref()
+                            + "\" is not a valid url - skipping link",
+                            Project.MSG_WARN);
+                        continue;
+                    }
+                }
+
+                if (la.isLinkOffline()) {
+                    File packageListLocation = la.getPackagelistLoc();
+                    if (packageListLocation == null) {
+                        throw new BuildException("The package list"
+                                                 + " location for link "
+                                                 + la.getHref()
+                                                 + " must be provided "
+                                                 + "because the link is "
+                                                 + "offline");
+                    }
+                    File packageListFile =
+                        new File(packageListLocation, "package-list");
+                    if (packageListFile.exists()) {
+                        try {
+                            String packageListURL =
+                                FILE_UTILS.getFileURL(packageListLocation)
+                                .toExternalForm();
+                            toExecute.createArgument()
+                                .setValue("-linkoffline");
+                            toExecute.createArgument()
+                                .setValue(link);
+                            toExecute.createArgument()
+                                .setValue(packageListURL);
+                        } catch (MalformedURLException ex) {
+                            log("Warning: Package list location was "
+                                + "invalid " + packageListLocation,
+                                Project.MSG_WARN);
+                        }
+                    } else {
+                        log("Warning: No package list was found at "
+                            + packageListLocation, Project.MSG_VERBOSE);
+                    }
+                } else {
+                    toExecute.createArgument().setValue("-link");
+                    toExecute.createArgument().setValue(link);
+                }
+            }
+        }
+    }
+
+    private void doGroup(Commandline toExecute) {
+        // add the single group arguments
+        // Javadoc 1.2 rules:
+        //   Multiple -group args allowed.
+        //   Each arg includes 3 strings: -group [name] [packagelist].
+        //   Elements in [packagelist] are colon-delimited.
+        //   An element in [packagelist] may end with the * wildcard.
+
+        // Ant javadoc task rules for group attribute:
+        //   Args are comma-delimited.
+        //   Each arg is 2 space-delimited strings.
+        //   E.g., group="XSLT_Packages org.apache.xalan.xslt*,
+        //                XPath_Packages org.apache.xalan.xpath*"
+        if (group != null) {
+            StringTokenizer tok = new StringTokenizer(group, ",", false);
+            while (tok.hasMoreTokens()) {
+                String grp = tok.nextToken().trim();
+                int space = grp.indexOf(" ");
+                if (space > 0) {
+                    String name = grp.substring(0, space);
+                    String pkgList = grp.substring(space + 1);
+                    toExecute.createArgument().setValue("-group");
+                    toExecute.createArgument().setValue(name);
+                    toExecute.createArgument().setValue(pkgList);
+                }
+            }
+        }
+    }
+
+    // add the group arguments
+    private void doGroups(Commandline toExecute) {
+        if (groups.size() != 0) {
+            for (Enumeration e = groups.elements(); e.hasMoreElements();) {
+                GroupArgument ga = (GroupArgument) e.nextElement();
+                String title = ga.getTitle();
+                String packages = ga.getPackages();
+                if (title == null || packages == null) {
+                    throw new BuildException("The title and packages must "
+                                             + "be specified for group "
+                                             + "elements.");
+                }
+                toExecute.createArgument().setValue("-group");
+                toExecute.createArgument().setValue(expand(title));
+                toExecute.createArgument().setValue(packages);
+            }
+        }
+    }
+
+    // Do java1.4 arguments
+    private void doJava14(Commandline toExecute) {
+        for (Enumeration e = tags.elements(); e.hasMoreElements();) {
+            Object element = e.nextElement();
+            if (element instanceof TagArgument) {
+                TagArgument ta = (TagArgument) element;
+                File tagDir = ta.getDir(getProject());
+                if (tagDir == null) {
+                    // The tag element is not used as a fileset,
+                    // but specifies the tag directly.
+                    toExecute.createArgument().setValue ("-tag");
+                    toExecute.createArgument()
+                        .setValue (ta.getParameter());
+                } else {
+                    // The tag element is used as a
+                    // fileset. Parse all the files and create
+                    // -tag arguments.
+                    DirectoryScanner tagDefScanner =
+                        ta.getDirectoryScanner(getProject());
+                    String[] files = tagDefScanner.getIncludedFiles();
+                    for (int i = 0; i < files.length; i++) {
+                        File tagDefFile = new File(tagDir, files[i]);
+                        try {
+                            BufferedReader in
+                                = new BufferedReader(
+                                    new FileReader(tagDefFile)
+                                                     );
+                            String line = null;
+                            while ((line = in.readLine()) != null) {
+                                toExecute.createArgument()
+                                    .setValue("-tag");
+                                toExecute.createArgument()
+                                    .setValue(line);
+                            }
+                            in.close();
+                        } catch (IOException ioe) {
+                            throw new BuildException(
+                                "Couldn't read "
+                                + " tag file from "
+                                + tagDefFile.getAbsolutePath(), ioe);
+                        }
+                    }
+                }
+            } else {
+                ExtensionInfo tagletInfo = (ExtensionInfo) element;
+                toExecute.createArgument().setValue("-taglet");
+                toExecute.createArgument().setValue(tagletInfo
+                                                    .getName());
+                if (tagletInfo.getPath() != null) {
+                    Path tagletPath = tagletInfo.getPath()
+                        .concatSystemClasspath("ignore");
+                    if (tagletPath.size() != 0) {
+                        toExecute.createArgument()
+                            .setValue("-tagletpath");
+                        toExecute.createArgument().setPath(tagletPath);
+                    }
+                }
+            }
+        }
+
+        String sourceArg = source != null ? source
+            : getProject().getProperty(MagicNames.BUILD_JAVAC_SOURCE);
+        if (sourceArg != null) {
+            toExecute.createArgument().setValue("-source");
+            toExecute.createArgument().setValue(sourceArg);
+        }
+
+        if (linksource && doclet == null) {
+            toExecute.createArgument().setValue("-linksource");
+        }
+        if (noqualifier != null && doclet == null) {
+            toExecute.createArgument().setValue("-noqualifier");
+            toExecute.createArgument().setValue(noqualifier);
+        }
+    }
+
+    private void doNotJava14() {
+        // Not 1.4+.
+        if (!tags.isEmpty()) {
+            log("-tag and -taglet options not supported on Javadoc < 1.4",
+                Project.MSG_VERBOSE);
+        }
+        if (source != null) {
+            log("-source option not supported on Javadoc < 1.4",
+                Project.MSG_VERBOSE);
+        }
+        if (linksource) {
+            log("-linksource option not supported on Javadoc < 1.4",
+                Project.MSG_VERBOSE);
+        }
+        if (breakiterator) {
+            log("-breakiterator option not supported on Javadoc < 1.4",
+                Project.MSG_VERBOSE);
+        }
+        if (noqualifier != null) {
+            log("-noqualifier option not supported on Javadoc < 1.4",
+                Project.MSG_VERBOSE);
+        }
+    }
+
+    private void doSourceAndPackageNames(
+        Commandline toExecute,
+        Vector packagesToDoc,
+        Vector sourceFilesToDoc,
+        boolean useExternalFile,
+        File    tmpList,
+        PrintWriter srcListWriter)
+        throws IOException {
+        Enumeration e = packagesToDoc.elements();
+        while (e.hasMoreElements()) {
+            String packageName = (String) e.nextElement();
+            if (useExternalFile) {
+                srcListWriter.println(packageName);
+            } else {
+                toExecute.createArgument().setValue(packageName);
+            }
+        }
+
+        e = sourceFilesToDoc.elements();
+        while (e.hasMoreElements()) {
+            SourceFile sf = (SourceFile) e.nextElement();
+            String sourceFileName = sf.getFile().getAbsolutePath();
+            if (useExternalFile) {
+                // XXX what is the following doing?
+                //     should it run if !javadoc4 && executable != null?
+                if (JAVADOC_4 && sourceFileName.indexOf(" ") > -1) {
+                    String name = sourceFileName;
+                    if (File.separatorChar == '\\') {
+                        name = sourceFileName.replace(File.separatorChar, '/');
+                    }
+                    srcListWriter.println("\"" + name + "\"");
+                } else {
+                    srcListWriter.println(sourceFileName);
+                }
+            } else {
+                toExecute.createArgument().setValue(sourceFileName);
+            }
+        }
+    }
+
+    /**
+     * Quote a string to place in a @ file.
+     * @param str the string to quote
+     * @return the quoted string, if there is no need to quote the string,
+     *         return the original string.
+     */
+    private String quoteString(String str) {
+        if (str.indexOf(' ') == -1
+            && str.indexOf('\'') == -1
+            && str.indexOf('"') == -1) {
+            return str;
+        }
+        if (str.indexOf('\'') == -1) {
+            return quoteString(str, '\'');
+        } else {
+            return quoteString(str, '"');
+        }
+    }
+
+    private String quoteString(String str, char delim) {
+        StringBuffer buf = new StringBuffer(str.length() * 2);
+        buf.append(delim);
+        if (str.indexOf('\\') != -1) {
+            str = replace(str, '\\', "\\\\");
+        }
+        if (str.indexOf(delim) != -1) {
+            str = replace(str, delim, "\\" + delim);
+        }
+        buf.append(str);
+        buf.append(delim);
+        return buf.toString();
+    }
+
+    private String replace(String str, char fromChar, String toString) {
+        StringBuffer buf = new StringBuffer(str.length() * 2);
+        for (int i = 0; i < str.length(); ++i) {
+            char ch = str.charAt(i);
+            if (ch == fromChar) {
+                buf.append(toString);
+            } else {
+                buf.append(ch);
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Add the files matched by the nested source files to the Vector
+     * as SourceFile instances.
+     *
+     * @since 1.7
+     */
+    private void addSourceFiles(Vector sf) {
+        Iterator e = nestedSourceFiles.iterator();
+        while (e.hasNext()) {
+            ResourceCollection rc = (ResourceCollection) e.next();
+            if (!rc.isFilesystemOnly()) {
+                throw new BuildException("only file system based resources are"
+                                         + " supported by javadoc");
+            }
+            if (rc instanceof FileSet) {
+                FileSet fs = (FileSet) rc;
+                if (!fs.hasPatterns() && !fs.hasSelectors()) {
+                    FileSet fs2 = (FileSet) fs.clone();
+                    fs2.createInclude().setName("**/*.java");
+                    if (includeNoSourcePackages) {
+                        fs2.createInclude().setName("**/package.html");
+                    }
+                    rc = fs2;
+                }
+            }
+            Iterator iter = rc.iterator();
+            while (iter.hasNext()) {
+                sf.addElement(new SourceFile(((FileResource) iter.next())
+                                             .getFile()));
+            }
+        }
+    }
+
+    /**
+     * Add the directories matched by the nested dirsets to the Vector
+     * and the base directories of the dirsets to the Path.  It also
+     * handles the packages and excludepackages attributes and
+     * elements.
+     *
+     * @since 1.5
+     */
+    private void parsePackages(Vector pn, Path sp) {
+        Vector addedPackages = new Vector();
+        Vector dirSets = (Vector) packageSets.clone();
+
+        // for each sourcePath entry, add a directoryset with includes
+        // taken from packagenames attribute and nested package
+        // elements and excludes taken from excludepackages attribute
+        // and nested excludepackage elements
+        if (sourcePath != null) {
+            PatternSet ps = new PatternSet();
+            if (packageNames.size() > 0) {
+                Enumeration e = packageNames.elements();
+                while (e.hasMoreElements()) {
+                    PackageName p = (PackageName) e.nextElement();
+                    String pkg = p.getName().replace('.', '/');
+                    if (pkg.endsWith("*")) {
+                        pkg += "*";
+                    }
+                    ps.createInclude().setName(pkg);
+                }
+            } else {
+                ps.createInclude().setName("**");
+            }
+
+            Enumeration e = excludePackageNames.elements();
+            while (e.hasMoreElements()) {
+                PackageName p = (PackageName) e.nextElement();
+                String pkg = p.getName().replace('.', '/');
+                if (pkg.endsWith("*")) {
+                    pkg += "*";
+                }
+                ps.createExclude().setName(pkg);
+            }
+
+
+            String[] pathElements = sourcePath.list();
+            for (int i = 0; i < pathElements.length; i++) {
+                File dir = new File(pathElements[i]);
+                if (dir.isDirectory()) {
+                    DirSet ds = new DirSet();
+                    ds.setDefaultexcludes(useDefaultExcludes);
+                    ds.setDir(dir);
+                    ds.createPatternSet().addConfiguredPatternset(ps);
+                    dirSets.addElement(ds);
+                } else {
+                    log("Skipping " + pathElements[i]
+                        + " since it is no directory.", Project.MSG_WARN);
+                }
+            }
+        }
+
+        Enumeration e = dirSets.elements();
+        while (e.hasMoreElements()) {
+            DirSet ds = (DirSet) e.nextElement();
+            File baseDir = ds.getDir(getProject());
+            log("scanning " + baseDir + " for packages.", Project.MSG_DEBUG);
+            DirectoryScanner dsc = ds.getDirectoryScanner(getProject());
+            String[] dirs = dsc.getIncludedDirectories();
+            boolean containsPackages = false;
+            for (int i = 0; i < dirs.length; i++) {
+                // are there any java files in this directory?
+                File pd = new File(baseDir, dirs[i]);
+                String[] files = pd.list(new FilenameFilter () {
+                        public boolean accept(File dir1, String name) {
+                            return name.endsWith(".java")
+                                || (includeNoSourcePackages
+                                    && name.equals("package.html"));
+                        }
+                    });
+
+                if (files.length > 0) {
+                    if ("".equals(dirs[i])) {
+                        log(baseDir
+                            + " contains source files in the default package,"
+                            + " you must specify them as source files"
+                            + " not packages.",
+                            Project.MSG_WARN);
+                    } else {
+                        containsPackages = true;
+                        String packageName =
+                            dirs[i].replace(File.separatorChar, '.');
+                        if (!addedPackages.contains(packageName)) {
+                            addedPackages.addElement(packageName);
+                            pn.addElement(packageName);
+                        }
+                    }
+                }
+            }
+            if (containsPackages) {
+                // We don't need to care for duplicates here,
+                // Path.list does it for us.
+                sp.createPathElement().setLocation(baseDir);
+            } else {
+                log(baseDir + " doesn\'t contain any packages, dropping it.",
+                    Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+    private class JavadocOutputStream extends LogOutputStream {
+        JavadocOutputStream(int level) {
+            super(Javadoc.this, level);
+        }
+
+        //
+        // Override the logging of output in order to filter out Generating
+        // messages.  Generating messages are set to a priority of VERBOSE
+        // unless they appear after what could be an informational message.
+        //
+        private String queuedLine = null;
+        protected void processLine(String line, int messageLevel) {
+            if (messageLevel == Project.MSG_INFO
+                && line.startsWith("Generating ")) {
+                if (queuedLine != null) {
+                    super.processLine(queuedLine, Project.MSG_VERBOSE);
+                }
+                queuedLine = line;
+            } else {
+                if (queuedLine != null) {
+                    if (line.startsWith("Building ")) {
+                        super.processLine(queuedLine, Project.MSG_VERBOSE);
+                    } else {
+                        super.processLine(queuedLine, Project.MSG_INFO);
+                    }
+                    queuedLine = null;
+                }
+                super.processLine(line, messageLevel);
+            }
+        }
+
+
+        protected void logFlush() {
+            if (queuedLine != null) {
+                super.processLine(queuedLine, Project.MSG_VERBOSE);
+                queuedLine = null;
+            }
+        }
+    }
+
+    /**
+     * Convenience method to expand properties.
+     * @param content the string to expand
+     * @return the converted string
+     */
+    protected String expand(String content) {
+        return getProject().replaceProperties(content);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Jikes.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Jikes.java
new file mode 100644
index 0000000..a96d61d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Jikes.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Random;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Encapsulates a Jikes compiler, by directly executing an external
+ * process.
+ *
+ * <p><strong>As of Ant 1.2, this class is considered to be dead code
+ * by the Ant developers and is unmaintained.  Don't use
+ * it.</strong></p>
+ *
+ * @deprecated since 1.2.
+ *             Merged into the class Javac.
+ */
+public class Jikes {
+    // There have been reports that 300 files could be compiled
+    // on a command line so 250 is a conservative approach
+    private static final int MAX_FILES_ON_COMMAND_LINE = 250;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected JikesOutputParser jop;
+    protected String command;
+    protected Project project;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructs a new Jikes object.
+     * @param jop      Parser to send jike's output to
+     * @param command  name of jikes executable
+     * @param project  the current project
+     */
+    protected Jikes(JikesOutputParser jop, String command, Project project) {
+        super();
+
+        System.err.println("As of Ant 1.2 released in October 2000, "
+            + "the Jikes class");
+        System.err.println("is considered to be dead code by the Ant "
+            + "developers and is unmaintained.");
+        System.err.println("Don\'t use it!");
+
+        this.jop = jop;
+        this.command = command;
+        this.project = project;
+    }
+
+    /**
+     * Do the compile with the specified arguments.
+     * @param args - arguments to pass to process on command line
+     */
+    protected void compile(String[] args) {
+        String[] commandArray = null;
+        File tmpFile = null;
+
+        try {
+            String myos = System.getProperty("os.name");
+
+            // Windows has a 32k limit on total arg size, so
+            // create a temporary file to store all the arguments
+
+            if (myos.toLowerCase().indexOf("windows") >= 0
+                && args.length > MAX_FILES_ON_COMMAND_LINE) {
+                PrintWriter out = null;
+                try {
+                    String tempFileName = "jikes"
+                        + (new Random(System.currentTimeMillis())).nextLong();
+                    tmpFile = new File(tempFileName);
+                    out = new PrintWriter(new FileWriter(tmpFile));
+                    for (int i = 0; i < args.length; i++) {
+                        out.println(args[i]);
+                    }
+                    out.flush();
+                    commandArray = new String[] {command,
+                                               "@" + tmpFile.getAbsolutePath()};
+                } catch (IOException e) {
+                    throw new BuildException("Error creating temporary file",
+                                             e);
+                } finally {
+                    FileUtils.close(out);
+                }
+            } else {
+                commandArray = new String[args.length + 1];
+                commandArray[0] = command;
+                System.arraycopy(args, 0, commandArray, 1, args.length);
+            }
+
+            // We assume, that everything jikes writes goes to
+            // standard output, not to standard error. The option
+            // -Xstdout that is given to Jikes in Javac.doJikesCompile()
+            // should guarantee this. At least I hope so. :)
+            try {
+                Execute exe = new Execute(jop);
+                exe.setAntRun(project);
+                exe.setWorkingDirectory(project.getBaseDir());
+                exe.setCommandline(commandArray);
+                exe.execute();
+            } catch (IOException e) {
+                throw new BuildException("Error running Jikes compiler", e);
+            }
+        } finally {
+            if (tmpFile != null) {
+                tmpFile.delete();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/JikesOutputParser.java b/trunk/src/main/org/apache/tools/ant/taskdefs/JikesOutputParser.java
new file mode 100644
index 0000000..5d94bff
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/JikesOutputParser.java
@@ -0,0 +1,182 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Parses output from jikes and
+ * passes errors and warnings
+ * into the right logging channels of Project.
+ *
+ * <p><strong>As of Ant 1.2, this class is considered to be dead code
+ * by the Ant developers and is unmaintained.  Don't use
+ * it.</strong></p>
+ *
+ * @deprecated since 1.2.
+ *             Use Jikes' exit value to detect compilation failure.
+ */
+public class JikesOutputParser implements ExecuteStreamHandler {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Task task;
+    protected boolean errorFlag = false; // no errors so far
+    protected int errors;
+    protected int warnings;
+    protected boolean error = false;
+    protected boolean emacsMode;
+
+    protected BufferedReader br;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Ignore.
+     * @param os ignored
+     */
+    public void setProcessInputStream(OutputStream os) {
+    }
+
+    /**
+     * Ignore.
+     * @param is ignored
+     */
+    public void setProcessErrorStream(InputStream is) {
+    }
+
+    /**
+     * Set the inputstream
+     * @param is the input stream
+     * @throws IOException on error
+     */
+    public void setProcessOutputStream(InputStream is) throws IOException {
+        br = new BufferedReader(new InputStreamReader(is));
+    }
+
+    /**
+     * Invokes parseOutput.
+     * @throws IOException on error
+     */
+    public void start() throws IOException {
+        parseOutput(br);
+    }
+
+    /**
+     * Ignore.
+     */
+    public void stop() {
+    }
+
+    /**
+     * Construct a new Parser object
+     * @param task      task in which context we are called
+     * @param emacsMode if true output in emacs mode
+     */
+    protected JikesOutputParser(Task task, boolean emacsMode) {
+        super();
+
+        System.err.println("As of Ant 1.2 released in October 2000, the "
+            + "JikesOutputParser class");
+        System.err.println("is considered to be dead code by the Ant "
+            + "developers and is unmaintained.");
+        System.err.println("Don\'t use it!");
+
+        this.task = task;
+        this.emacsMode = emacsMode;
+    }
+
+    /**
+     * Parse the output of a jikes compiler
+     * @param reader - Reader used to read jikes's output
+     * @throws IOException on error
+     */
+    protected void parseOutput(BufferedReader reader) throws IOException {
+       if (emacsMode) {
+           parseEmacsOutput(reader);
+       } else {
+           parseStandardOutput(reader);
+       }
+    }
+
+    private void parseStandardOutput(BufferedReader reader) throws IOException {
+        String line;
+        String lower;
+        // We assume, that every output, jikes does, stands for an error/warning
+        // XXX
+        // Is this correct?
+
+        // TODO:
+        // A warning line, that shows code, which contains a variable
+        // error will cause some trouble. The parser should definitely
+        // be much better.
+
+        while ((line = reader.readLine()) != null) {
+            lower = line.toLowerCase();
+            if (line.trim().equals("")) {
+                continue;
+            }
+            if (lower.indexOf("error") != -1) {
+                setError(true);
+            } else if (lower.indexOf("warning") != -1) {
+                setError(false);
+                   } else {
+                // If we don't know the type of the line
+                // and we are in emacs mode, it will be
+                // an error, because in this mode, jikes won't
+                // always print "error", but sometimes other
+                // keywords like "Syntax". We should look for
+                // all those keywords.
+                if (emacsMode) {
+                    setError(true);
+                }
+            }
+            log(line);
+        }
+    }
+
+    private void parseEmacsOutput(BufferedReader reader) throws IOException {
+       // This may change, if we add advanced parsing capabilities.
+       parseStandardOutput(reader);
+    }
+
+    private void setError(boolean err) {
+        error = err;
+        if (error) {
+            errorFlag = true;
+        }
+    }
+
+    private void log(String line) {
+       if (!emacsMode) {
+           task.log("", (error ? Project.MSG_ERR : Project.MSG_WARN));
+       }
+       task.log(line, (error ? Project.MSG_ERR : Project.MSG_WARN));
+    }
+
+    /**
+     * Indicate if there were errors during the compile
+     * @return if errors occurred
+     */
+    protected boolean getErrorFlag() {
+        return errorFlag;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/KeySubst.java b/trunk/src/main/org/apache/tools/ant/taskdefs/KeySubst.java
new file mode 100644
index 0000000..97f3dbb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/KeySubst.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Keyword substitution. Input file is written to output file.
+ * Do not make input file same as output file.
+ * Keywords in input files look like this: @foo@. See the docs for the
+ * setKeys method to understand how to do the substitutions.
+ *
+ * @since Ant 1.1
+ * @deprecated KeySubst is deprecated since Ant 1.1. Use Filter + Copy
+ * instead.
+ */
+public class KeySubst extends Task {
+    private File source = null;
+    private File dest = null;
+    private String sep = "*";
+    private Hashtable replacements = new Hashtable();
+
+    /**
+     * Do the execution.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        log("!! KeySubst is deprecated. Use Filter + Copy instead. !!");
+        log("Performing Substitutions");
+        if (source == null || dest == null) {
+            log("Source and destinations must not be null");
+            return;
+        }
+        BufferedReader br = null;
+        BufferedWriter bw = null;
+        try {
+            br = new BufferedReader(new FileReader(source));
+            dest.delete();
+            bw = new BufferedWriter(new FileWriter(dest));
+
+            String line = null;
+            String newline = null;
+            line = br.readLine();
+            while (line != null) {
+                if (line.length() == 0) {
+                    bw.newLine();
+                } else {
+                    newline = KeySubst.replace(line, replacements);
+                    bw.write(newline);
+                    bw.newLine();
+                }
+                line = br.readLine();
+            }
+            bw.flush();
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } finally {
+            if (bw != null) {
+                try {
+                    bw.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Set the source file.
+     * @param s the source file
+     */
+    public void setSrc(File s) {
+        this.source = s;
+    }
+
+    /**
+     * Set the destination file.
+     * @param dest the destination file
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    /**
+     * Sets the separator between name=value arguments
+     * in setKeys(). By default it is "*".
+     * @param sep the separator string
+     */
+    public void setSep(String sep) {
+        this.sep = sep;
+    }
+    /**
+     * Sets the keys.
+     *
+     * Format string is like this:
+     *   <p>
+     *   name=value*name2=value
+     *   <p>
+     *   Names are case sensitive.
+     *   <p>
+     *   Use the setSep() method to change the * to something else
+     *   if you need to use * as a name or value.
+     * @param keys a <code>String</code> value
+     */
+    public void setKeys(String keys) {
+        if (keys != null && keys.length() > 0) {
+            StringTokenizer tok =
+            new StringTokenizer(keys, this.sep, false);
+            while (tok.hasMoreTokens()) {
+                String token = tok.nextToken().trim();
+                StringTokenizer itok =
+                new StringTokenizer(token, "=", false);
+
+                String name = itok.nextToken();
+                String value = itok.nextToken();
+                replacements.put(name, value);
+            }
+        }
+    }
+
+
+    /**
+     * A test method.
+     * @param args not used
+     */
+    public static void main(String[] args) {
+        try {
+            Hashtable hash = new Hashtable();
+            hash.put("VERSION", "1.0.3");
+            hash.put("b", "ffff");
+            System.out.println(KeySubst.replace("$f ${VERSION} f ${b} jj $",
+                                                hash));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Does replacement on text using the hashtable of keys.
+     * @param origString an input string
+     * @param keys       mapping of keys to values
+     * @return the string with the replacements in it.
+     * @throws BuildException on error
+     */
+    public static String replace(String origString, Hashtable keys)
+        throws BuildException {
+        StringBuffer finalString = new StringBuffer();
+        int index = 0;
+        int i = 0;
+        String key = null;
+        // CheckStyle:MagicNumber OFF
+        while ((index = origString.indexOf("${", i)) > -1) {
+            key = origString.substring(index + 2, origString.indexOf("}",
+                                       index + 3));
+            finalString.append (origString.substring(i, index));
+            if (keys.containsKey(key)) {
+                finalString.append (keys.get(key));
+            } else {
+                finalString.append ("${");
+                finalString.append (key);
+                finalString.append ("}");
+            }
+            i = index + 3 + key.length();
+        }
+        // CheckStyle:MagicNumber ON
+        finalString.append (origString.substring(i));
+        return finalString.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Length.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Length.java
new file mode 100755
index 0000000..27abda1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Length.java
@@ -0,0 +1,330 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Comparison;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.PropertyOutputStream;
+
+/**
+ * Gets lengths:  of files/resources, byte size; of strings, length (optionally trimmed).
+ * The task is overloaded in this way for semantic reasons, much like Available.
+ * @since Ant 1.6.3
+ */
+public class Length extends Task implements Condition {
+
+    private static final String ALL = "all";
+    private static final String EACH = "each";
+    private static final String STRING = "string";
+
+    private static final String LENGTH_REQUIRED
+        = "Use of the Length condition requires that the length attribute be set.";
+
+    private String property;
+    private String string;
+    private Boolean trim;
+    private String mode = ALL;
+    private Comparison when = Comparison.EQUAL;
+    private Long length;
+    private Resources resources;
+
+    /**
+     * The property in which the length will be stored.
+     * @param property the <code>String</code> property key.
+     */
+    public synchronized void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * Set the single file for this task.
+     * @param file the <code>File</code> whose length to retrieve.
+     */
+    public synchronized void setFile(File file) {
+        add(new FileResource(file));
+    }
+
+    /**
+     * Add a FileSet.
+     * @param fs the <code>FileSet</code> to add.
+     */
+    public synchronized void add(FileSet fs) {
+        add((ResourceCollection) fs);
+    }
+
+    /**
+     * Add a ResourceCollection.
+     * @param c the <code>ResourceCollection</code> to add.
+     * @since Ant 1.7
+     */
+    public synchronized void add(ResourceCollection c) {
+        if (c == null) {
+            return;
+        }
+        resources = (resources == null) ? new Resources() : resources;
+        resources.add(c);
+    }
+
+    /**
+     * Set the target count number for use as a Condition.
+     * @param ell the long length to compare with.
+     */
+    public synchronized void setLength(long ell) {
+        length = new Long(ell);
+    }
+
+    /**
+     * Set the comparison for use as a Condition.
+     * @param w EnumeratedAttribute When.
+     * @see org.apache.tools.ant.types.Comparison
+     */
+    public synchronized void setWhen(When w) {
+        setWhen((Comparison) w);
+    }
+
+    /**
+     * Set the comparison for use as a Condition.
+     * @param c Comparison.
+     * @see org.apache.tools.ant.types.Comparison
+     * @since Ant 1.7
+     */
+    public synchronized void setWhen(Comparison c) {
+        when = c;
+    }
+
+    /**
+     * Set the execution mode for working with files.
+     * @param m the <code>FileMode</code> to use.
+     */
+    public synchronized void setMode(FileMode m) {
+        this.mode = m.getValue();
+    }
+
+    /**
+     * Set the string whose length to get.
+     * @param string <code>String</code>.
+     */
+    public synchronized void setString(String string) {
+        this.string = string;
+        this.mode = STRING;
+    }
+
+    /**
+     * Set whether to trim in string mode.
+     * @param trim <code>boolean</code>.
+     */
+    public synchronized void setTrim(boolean trim) {
+        this.trim = trim ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Learn whether strings will be trimmed.
+     * @return boolean trim setting.
+     */
+    public boolean getTrim() {
+        return trim != null && trim.booleanValue();
+    }
+
+    /**
+     * Execute the length task.
+     */
+    public void execute() {
+        validate();
+        PrintStream ps = new PrintStream((property != null)
+            ? (OutputStream) new PropertyOutputStream(getProject(), property)
+            : (OutputStream) new LogOutputStream(this, Project.MSG_INFO));
+
+        if (STRING.equals(mode)) {
+            ps.print(getLength(string, getTrim()));
+            ps.close();
+        } else if (EACH.equals(mode)) {
+            handleResources(new EachHandler(ps));
+        } else if (ALL.equals(mode)) {
+            handleResources(new AllHandler(ps));
+        }
+    }
+
+    /**
+     * Fulfill the condition contract.
+     * @return true if the condition is true.
+     * @throws BuildException if an error occurs.
+     */
+    public boolean eval() {
+        validate();
+        if (length == null) {
+            throw new BuildException(LENGTH_REQUIRED);
+        }
+        Long ell;
+        if (STRING.equals(mode)) {
+            ell = new Long(getLength(string, getTrim()));
+        } else {
+            AccumHandler h = new AccumHandler();
+            handleResources(h);
+            ell = new Long(h.getAccum());
+        }
+        return when.evaluate(ell.compareTo(length));
+    }
+
+    private void validate() {
+        if (string != null) {
+            if (resources != null) {
+                throw new BuildException("the string length function"
+                    + " is incompatible with the file/resource length function");
+            }
+            if (!(STRING.equals(mode))) {
+                throw new BuildException("the mode attribute is for use"
+                    + " with the file/resource length function");
+            }
+        } else if (resources != null) {
+            if (!(EACH.equals(mode) || ALL.equals(mode))) {
+                throw new BuildException("invalid mode setting for"
+                    + " file/resource length function: \"" + mode + "\"");
+            } else if (trim != null) {
+                throw new BuildException("the trim attribute is"
+                    + " for use with the string length function only");
+            }
+        } else {
+            throw new BuildException("you must set either the string attribute"
+                + " or specify one or more files using the file attribute or"
+                + " nested resource collections");
+        }
+    }
+
+    private void handleResources(Handler h) {
+        for (Iterator i = resources.iterator(); i.hasNext();) {
+            Resource r = (Resource) i.next();
+            if (!r.isExists()) {
+                log(r + " does not exist", Project.MSG_ERR);
+            } else if (r.isDirectory()) {
+                log(r + " is a directory; length unspecified",
+                    Project.MSG_ERR);
+            } else {
+                h.handle(r);
+            }
+        }
+        h.complete();
+    }
+
+    private static long getLength(String s, boolean t) {
+        return (t ? s.trim() : s).length();
+    }
+
+    /** EnumeratedAttribute operation mode */
+    public static class FileMode extends EnumeratedAttribute {
+        static final String[] MODES = new String[] {EACH, ALL};
+
+        /**
+         * Return the possible values for FileMode.
+         * @return <code>String[]</code>.
+         */
+        public String[] getValues() {
+            return MODES;
+        }
+
+    }
+
+    /**
+     * EnumeratedAttribute for the when attribute.
+     */
+    public static class When extends Comparison {
+        //extend Comparison; retain for BC only
+    }
+
+    private abstract class Handler {
+        private PrintStream ps;
+        Handler(PrintStream ps) {
+            this.ps = ps;
+        }
+
+        protected PrintStream getPs() {
+            return ps;
+        }
+
+        protected abstract void handle(Resource r);
+
+        void complete() {
+            FileUtils.close(ps);
+        }
+    }
+
+    private class EachHandler extends Handler {
+        EachHandler(PrintStream ps) {
+            super(ps);
+        }
+        protected void handle(Resource r) {
+            getPs().print(r.toString());
+            getPs().print(" : ");
+            //when writing to the log, we'll see what's happening:
+            long size = r.getSize();
+            if (size == Resource.UNKNOWN_SIZE) {
+                getPs().println("unknown");
+            } else {
+                getPs().println(size);
+            }
+       }
+    }
+
+    private class AccumHandler extends Handler {
+        private long accum = 0L;
+
+        AccumHandler() {
+            super(null);
+        }
+        protected AccumHandler(PrintStream ps) {
+            super(ps);
+        }
+        protected long getAccum() {
+            return accum;
+        }
+        protected synchronized void handle(Resource r) {
+            long size = r.getSize();
+            if (size == Resource.UNKNOWN_SIZE) {
+                log("Size unknown for " + r.toString(), Project.MSG_WARN);
+            } else {
+                accum += size;
+            }
+        }
+    }
+
+    private class AllHandler extends AccumHandler {
+        AllHandler(PrintStream ps) {
+            super(ps);
+        }
+        void complete() {
+            getPs().print(getAccum());
+            super.complete();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/LoadFile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadFile.java
new file mode 100644
index 0000000..235bca4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadFile.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.types.resources.FileResource;
+
+
+/**
+ * Load a file into a property
+ *
+ * @since Ant 1.5
+ * @ant.task category="utility"
+ */
+public class LoadFile extends LoadResource {
+
+    /**
+     * Sets the file to load.
+     *
+     * @param srcFile The new SrcFile value
+     */
+    public final void setSrcFile(final File srcFile) {
+        addConfigured(new FileResource(srcFile));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java
new file mode 100644
index 0000000..dfd98b4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadProperties.java
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.JavaResource;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Load a file's contents as Ant properties.
+ *
+ * @since Ant 1.5
+ * @ant.task category="utility"
+ */
+public class LoadProperties extends Task {
+
+    /**
+     * Source resource.
+     */
+    private Resource src = null;
+
+    /**
+     * Holds filterchains
+     */
+    private final Vector filterChains = new Vector();
+
+    /**
+     * Encoding to use for input; defaults to the platform's default encoding.
+     */
+    private String encoding = null;
+
+    /**
+     * Set the file to load.
+     *
+     * @param srcFile The new SrcFile value
+     */
+    public final void setSrcFile(final File srcFile) {
+        addConfigured(new FileResource(srcFile));
+    }
+
+    /**
+     * Set the resource name of a property file to load.
+     *
+     * @param resource resource on classpath
+     */
+    public void setResource(String resource) {
+        getRequiredJavaResource().setName(resource);
+    }
+
+    /**
+     * Encoding to use for input, defaults to the platform's default
+     * encoding. <p>
+     *
+     * For a list of possible values see
+     * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">
+     * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html
+     * </a>.</p>
+     *
+     * @param encoding The new Encoding value
+     */
+    public final void setEncoding(final String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Set the classpath to use when looking up a resource.
+     * @param classpath to add to any existing classpath
+     */
+    public void setClasspath(Path classpath) {
+        getRequiredJavaResource().setClasspath(classpath);
+    }
+
+    /**
+     * Add a classpath to use when looking up a resource.
+     * @return The classpath to be configured
+     */
+    public Path createClasspath() {
+        return getRequiredJavaResource().createClasspath();
+    }
+
+    /**
+     * Set the classpath to use when looking up a resource,
+     * given as reference to a &lt;path&gt; defined elsewhere
+     * @param r The reference value
+     */
+    public void setClasspathRef(Reference r) {
+        getRequiredJavaResource().setClasspathRef(r);
+    }
+
+    /**
+     * get the classpath used by this <code>LoadProperties</code>.
+     * @return The classpath
+     */
+    public Path getClasspath() {
+        return getRequiredJavaResource().getClasspath();
+    }
+
+    /**
+     * load Ant properties from the source file or resource
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public final void execute() throws BuildException {
+        //validation
+        if (src == null) {
+            throw new BuildException("A source resource is required.");
+        }
+        if (!src.isExists()) {
+            if (src instanceof JavaResource) {
+                // dreaded backwards compatibility
+                log("Unable to find resource " + src, Project.MSG_WARN);
+                return;
+            }
+            throw new BuildException("Source resource does not exist: " + src);
+        }
+        BufferedInputStream bis = null;
+        Reader instream = null;
+        ByteArrayInputStream tis = null;
+
+        try {
+            bis = new BufferedInputStream(src.getInputStream());
+            if (encoding == null) {
+                instream = new InputStreamReader(bis);
+            } else {
+                instream = new InputStreamReader(bis, encoding);
+            }
+            ChainReaderHelper crh = new ChainReaderHelper();
+            crh.setPrimaryReader(instream);
+            crh.setFilterChains(filterChains);
+            crh.setProject(getProject());
+            instream = crh.getAssembledReader();
+
+            String text = crh.readFully(instream);
+
+            if (text != null && text.length() != 0) {
+                if (!text.endsWith("\n")) {
+                    text = text + "\n";
+                }
+                if (encoding == null) {
+                    tis = new ByteArrayInputStream(text.getBytes());
+                } else {
+                    tis = new ByteArrayInputStream(text.getBytes(encoding));
+                }
+                final Properties props = new Properties();
+                props.load(tis);
+
+                Property propertyTask = new Property();
+                propertyTask.bindToOwner(this);
+                propertyTask.addProperties(props);
+            }
+        } catch (final IOException ioe) {
+            throw new BuildException("Unable to load file: " + ioe, ioe, getLocation());
+        } finally {
+            FileUtils.close(bis);
+            FileUtils.close(tis);
+        }
+    }
+
+    /**
+     * Adds a FilterChain.
+     * @param filter the filter to add
+     */
+    public final void addFilterChain(FilterChain filter) {
+        filterChains.addElement(filter);
+    }
+
+    /**
+     * Set the source resource.
+     * @param a the resource to load as a single element Resource collection.
+     * @since Ant 1.7
+     */
+    public synchronized void addConfigured(ResourceCollection a) {
+        if (src != null) {
+            throw new BuildException("only a single source is supported");
+        }
+        if (a.size() != 1) {
+            throw new BuildException(
+                    "only single-element resource collections are supported");
+        }
+        src = (Resource) a.iterator().next();
+    }
+
+    private synchronized JavaResource getRequiredJavaResource() {
+        if (src == null) {
+            src = new JavaResource();
+            src.setProject(getProject());
+        } else if (!(src instanceof JavaResource)) {
+            throw new BuildException("expected a java resource as source");
+        }
+        return (JavaResource) src;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/LoadResource.java b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadResource.java
new file mode 100755
index 0000000..0e58568
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/LoadResource.java
@@ -0,0 +1,234 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Load a resource into a property
+ *
+ * @since Ant 1.7
+ * @ant.task category="utility"
+ */
+public class LoadResource extends Task {
+
+    /**
+     * The resource to load.
+     */
+    private Resource src;
+
+    /**
+     * what to do when it goes pear-shaped
+     */
+    private boolean failOnError = true;
+
+    /**
+     * suppress error message if it goes pear-shaped, sets failOnError=false
+     */
+    private boolean quiet = false;
+
+    /**
+     * Encoding to use for filenames, defaults to the platform's default
+     * encoding.
+     */
+    private String encoding = null;
+
+    /**
+     * name of property
+     */
+    private String property = null;
+
+    /**
+     * Holds FilterChains
+     */
+    private final Vector filterChains = new Vector();
+
+    /**
+     * Encoding to use for input, defaults to the platform's default
+     * encoding. <p>
+     *
+     * For a list of possible values see
+     * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">
+     * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html
+     * </a>.</p>
+     *
+     * @param encoding The new Encoding value
+     */
+
+    public final void setEncoding(final String encoding) {
+        this.encoding = encoding;
+    }
+
+
+    /**
+     * Property name to save to.
+     *
+     * @param property The new Property value
+     */
+    public final void setProperty(final String property) {
+        this.property = property;
+    }
+
+    /**
+     * If true, fail on load error.
+     *
+     * @param fail The new Failonerror value
+     */
+    public final void setFailonerror(final boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * If true, suppress the load error report and set the
+     * the failonerror value to false.
+     * @param quiet The new Quiet value
+     */
+    public void setQuiet(final boolean quiet) {
+        this.quiet = quiet;
+        if (quiet) {
+            this.failOnError = false;
+        }
+    }
+
+    /**
+     * read in a source file to a property
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public final void execute()
+        throws BuildException {
+        //validation
+        if (src == null) {
+            throw new BuildException("source resource not defined");
+        }
+        if (property == null) {
+            throw new BuildException("output property not defined");
+        }
+        if (quiet && failOnError) {
+            throw new BuildException("quiet and failonerror cannot both be "
+                                     + "set to true");
+        }
+        if (!src.isExists()) {
+            String message = src + " doesn't exist";
+            if (failOnError) {
+                throw new BuildException(message);
+            } else {
+                log(message, quiet ? Project.MSG_WARN : Project.MSG_ERR);
+                return;
+            }
+        }
+        InputStream is = null;
+        BufferedInputStream bis = null;
+        Reader instream = null;
+        log("loading " + src + " into property " + property,
+            Project.MSG_VERBOSE);
+        try {
+            final long len = src.getSize();
+            log("resource size = "
+                + (len != Resource.UNKNOWN_SIZE ? String.valueOf(len)
+                   : "unknown"), Project.MSG_DEBUG);
+            //discard most of really big resources
+            final int size = (int) len;
+            //open up the resource
+            is = src.getInputStream();
+            bis = new BufferedInputStream(is);
+            if (encoding == null) {
+                instream = new InputStreamReader(bis);
+            } else {
+                instream = new InputStreamReader(bis, encoding);
+            }
+
+            String text = "";
+            if (size != 0) {
+                ChainReaderHelper crh = new ChainReaderHelper();
+                if (len != Resource.UNKNOWN_SIZE) {
+                    crh.setBufferSize(size);
+                }
+                crh.setPrimaryReader(instream);
+                crh.setFilterChains(filterChains);
+                crh.setProject(getProject());
+                instream = crh.getAssembledReader();
+
+                text = crh.readFully(instream);
+            } else {
+                log("Do not set property " + property + " as its length is 0.");
+            }
+
+            if (text != null) {
+                if (text.length() > 0) {
+                    getProject().setNewProperty(property, text);
+                    log("loaded " + text.length() + " characters",
+                        Project.MSG_VERBOSE);
+                    log(property + " := " + text, Project.MSG_DEBUG);
+                }
+            }
+
+        } catch (final IOException ioe) {
+            final String message = "Unable to load resource: "
+                + ioe.toString();
+            if (failOnError) {
+                throw new BuildException(message, ioe, getLocation());
+            } else {
+                log(message, quiet ? Project.MSG_VERBOSE : Project.MSG_ERR);
+            }
+        } catch (final BuildException be) {
+            if (failOnError) {
+                throw be;
+            } else {
+                log(be.getMessage(),
+                    quiet ? Project.MSG_VERBOSE : Project.MSG_ERR);
+            }
+        } finally {
+            FileUtils.close(is);
+        }
+    }
+
+    /**
+     * Add the FilterChain element.
+     * @param filter the filter to add
+     */
+    public final void addFilterChain(FilterChain filter) {
+        filterChains.addElement(filter);
+    }
+
+    /**
+     * Set the source resource.
+     * @param a the resource to load as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        if (a.size() != 1) {
+            throw new BuildException("only single argument resource collections"
+                                     + " are supported");
+        }
+        src = (Resource) a.iterator().next();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/LogOutputStream.java b/trunk/src/main/org/apache/tools/ant/taskdefs/LogOutputStream.java
new file mode 100644
index 0000000..b2c3468
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/LogOutputStream.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.LineOrientedOutputStream;
+
+/**
+ * Logs each line written to this stream to the log system of ant.
+ *
+ * Tries to be smart about line separators.<br>
+ *
+ * @since Ant 1.2
+ */
+public class LogOutputStream extends LineOrientedOutputStream {
+
+    private ProjectComponent pc;
+    private int level = Project.MSG_INFO;
+
+    /**
+     * Create a new LogOutputStream for the specified ProjectComponent.
+     *
+     * @param pc the project component for whom to log
+     * @since Ant 1.7.1
+     */
+    public LogOutputStream(ProjectComponent pc) {
+        this.pc = pc;
+    }
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param task the task for whom to log
+     * @param level loglevel used to log data written to this stream.
+     */
+    public LogOutputStream(Task task, int level) {
+        this((ProjectComponent) task, level);
+    }
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param pc the project component for whom to log
+     * @param level loglevel used to log data written to this stream.
+     * @since Ant 1.6.3
+     */
+    public LogOutputStream(ProjectComponent pc, int level) {
+        this(pc);
+        this.level = level;
+    }
+
+    /**
+     * Converts the buffer to a string and sends it to <code>processLine</code>
+     */
+    protected void processBuffer() {
+        try {
+            super.processBuffer();
+        } catch (IOException e) {
+            // impossible since *our* processLine doesn't throw an IOException
+            throw new RuntimeException("Impossible IOException caught: " + e);
+        }
+    }
+
+    /**
+     * Logs a line to the log system of ant.
+     *
+     * @param line the line to log.
+     */
+    protected void processLine(String line) {
+        processLine(line, level);
+    }
+
+    /**
+     * Logs a line to the log system of ant.
+     *
+     * @param line the line to log.
+     * @param level the logging level to use.
+     */
+    protected void processLine(String line, int level) {
+        pc.log(line, level);
+    }
+
+    /**
+     * Get the level.
+     * @return the log level.
+     */
+    public int getMessageLevel() {
+        return level;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/LogStreamHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/LogStreamHandler.java
new file mode 100644
index 0000000..ac95719
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/LogStreamHandler.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+
+/**
+ * Logs standard output and error of a subprocess to the log system of ant.
+ *
+ * @since Ant 1.2
+ */
+public class LogStreamHandler extends PumpStreamHandler {
+
+    /**
+     * Creates log stream handler
+     *
+     * @param task the task for whom to log
+     * @param outlevel the loglevel used to log standard output
+     * @param errlevel the loglevel used to log standard error
+     */
+    public LogStreamHandler(Task task, int outlevel, int errlevel) {
+        this((ProjectComponent) task, outlevel, errlevel);
+    }
+
+    /**
+     * Creates log stream handler
+     *
+     * @param pc the project component for whom to log
+     * @param outlevel the loglevel used to log standard output
+     * @param errlevel the loglevel used to log standard error
+     */
+    public LogStreamHandler(ProjectComponent pc, int outlevel, int errlevel) {
+        super(new LogOutputStream(pc, outlevel),
+              new LogOutputStream(pc, errlevel));
+    }
+
+    /**
+     * Stop the log stream handler.
+     */
+    public void stop() {
+        super.stop();
+        try {
+            getErr().close();
+            getOut().close();
+        } catch (IOException e) {
+            // plain impossible
+            throw new BuildException(e);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/MacroDef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
new file mode 100644
index 0000000..8b1db97
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
@@ -0,0 +1,830 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Locale;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * Describe class <code>MacroDef</code> here.
+ *
+ * @since Ant 1.6
+ */
+public class MacroDef extends AntlibDefinition  {
+
+    private NestedSequential nestedSequential;
+    private String     name;
+    private boolean    backTrace = true;
+    private List       attributes = new ArrayList();
+    private Map        elements   = new HashMap();
+    private String     textName   = null;
+    private Text       text       = null;
+    private boolean    hasImplicitElement = false;
+
+    /**
+     * Name of the definition
+     * @param name the name of the definition
+     */
+     public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Add the text element.
+     * @param text the nested text element to add
+     * @since ant 1.6.1
+     */
+    public void addConfiguredText(Text text) {
+        if (this.text != null) {
+            throw new BuildException(
+                "Only one nested text element allowed");
+        }
+        if (text.getName() == null) {
+            throw new BuildException(
+                "the text nested element needed a \"name\" attribute");
+        }
+        // Check if used by attributes
+        for (Iterator i = attributes.iterator(); i.hasNext();) {
+            Attribute attribute = (Attribute) i.next();
+            if (text.getName().equals(attribute.getName())) {
+                throw new BuildException(
+                    "the name \"" + text.getName()
+                    + "\" is already used as an attribute");
+            }
+        }
+        this.text = text;
+        this.textName = text.getName();
+    }
+
+    /**
+     * @return the nested text element
+     * @since ant 1.6.1
+     */
+    public Text getText() {
+        return text;
+    }
+
+    /**
+     * Set the backTrace attribute.
+     *
+     * @param backTrace if true and the macro instance generates
+     *                  an error, a backtrace of the location within
+     *                  the macro and call to the macro will be output.
+     *                  if false, only the location of the call to the
+     *                  macro will be shown. Default is true.
+     * @since ant 1.7
+     */
+    public void setBackTrace(boolean backTrace) {
+        this.backTrace = backTrace;
+    }
+
+    /**
+     * @return the backTrace attribute.
+     * @since ant 1.7
+     */
+    public boolean getBackTrace() {
+        return backTrace;
+    }
+
+    /**
+     * This is the sequential nested element of the macrodef.
+     *
+     * @return a sequential element to be configured.
+     */
+    public NestedSequential createSequential() {
+        if (this.nestedSequential != null) {
+            throw new BuildException("Only one sequential allowed");
+        }
+        this.nestedSequential = new NestedSequential();
+        return this.nestedSequential;
+    }
+
+    /**
+     * The class corresponding to the sequential nested element.
+     * This is a simple task container.
+     */
+    public static class NestedSequential implements TaskContainer {
+        private List nested = new ArrayList();
+
+        /**
+         * Add a task or type to the container.
+         *
+         * @param task an unknown element.
+         */
+        public void addTask(Task task) {
+            nested.add(task);
+        }
+
+        /**
+         * @return the list of unknown elements
+         */
+        public List getNested() {
+            return nested;
+        }
+
+        /**
+         * A compare function to compare this with another
+         * NestedSequential.
+         * It calls similar on the nested unknown elements.
+         *
+         * @param other the nested sequential to compare with.
+         * @return true if they are similar, false otherwise
+         */
+        public boolean similar(NestedSequential other) {
+            if (nested.size() != other.nested.size()) {
+                return false;
+            }
+            for (int i = 0; i < nested.size(); ++i) {
+                UnknownElement me = (UnknownElement) nested.get(i);
+                UnknownElement o = (UnknownElement) other.nested.get(i);
+                if (!me.similar(o)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Convert the nested sequential to an unknown element
+     * @return the nested sequential as an unknown element.
+     */
+    public UnknownElement getNestedTask() {
+        UnknownElement ret = new UnknownElement("sequential");
+        ret.setTaskName("sequential");
+        ret.setNamespace("");
+        ret.setQName("sequential");
+        new RuntimeConfigurable(ret, "sequential");
+        for (int i = 0; i < nestedSequential.getNested().size(); ++i) {
+            UnknownElement e =
+                (UnknownElement) nestedSequential.getNested().get(i);
+            ret.addChild(e);
+            ret.getWrapper().addChild(e.getWrapper());
+        }
+        return ret;
+    }
+
+    /**
+     * Gets this macro's attribute (and define?) list.
+     *
+     * @return the nested Attributes
+     */
+    public List getAttributes() {
+        return attributes;
+    }
+
+    /**
+     * Gets this macro's elements.
+     *
+     * @return the map nested elements, keyed by element name, with
+     *         {@link TemplateElement} values.
+     */
+    public Map getElements() {
+        return elements;
+    }
+
+    /**
+     * Check if a character is a valid character for an element or
+     * attribute name.
+     *
+     * @param c the character to check
+     * @return true if the character is a letter or digit or '.' or '-'
+     *         attribute name
+     */
+    public static boolean isValidNameCharacter(char c) {
+        // ? is there an xml api for this ?
+        return Character.isLetterOrDigit(c) || c == '.' || c == '-';
+    }
+
+    /**
+     * Check if a string is a valid name for an element or attribute.
+     *
+     * @param name the string to check
+     * @return true if the name consists of valid name characters
+     */
+    private static boolean isValidName(String name) {
+        if (name.length() == 0) {
+            return false;
+        }
+        for (int i = 0; i < name.length(); ++i) {
+            if (!isValidNameCharacter(name.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Add an attribute element.
+     *
+     * @param attribute an attribute nested element.
+     */
+    public void addConfiguredAttribute(Attribute attribute) {
+        if (attribute.getName() == null) {
+            throw new BuildException(
+                "the attribute nested element needed a \"name\" attribute");
+        }
+        if (attribute.getName().equals(textName)) {
+            throw new BuildException(
+                "the name \"" + attribute.getName()
+                + "\" has already been used by the text element");
+        }
+        for (int i = 0; i < attributes.size(); ++i) {
+            Attribute att = (Attribute) attributes.get(i);
+            if (att.getName().equals(attribute.getName())) {
+                throw new BuildException(
+                    "the name \"" + attribute.getName()
+                        + "\" has already been used in "
+                        + "another attribute element");
+            }
+        }
+        attributes.add(attribute);
+    }
+
+    /**
+     * Add an element element.
+     *
+     * @param element an element nested element.
+     */
+    public void addConfiguredElement(TemplateElement element) {
+        if (element.getName() == null) {
+            throw new BuildException(
+                "the element nested element needed a \"name\" attribute");
+        }
+        if (elements.get(element.getName()) != null) {
+            throw new BuildException(
+                "the element " + element.getName()
+                + " has already been specified");
+        }
+        if (hasImplicitElement
+            || (element.isImplicit() && elements.size() != 0)) {
+            throw new BuildException(
+                "Only one element allowed when using implicit elements");
+        }
+        hasImplicitElement = element.isImplicit();
+        elements.put(element.getName(), element);
+    }
+
+    /**
+     * Create a new ant type based on the embedded tasks and types.
+     */
+    public void execute() {
+        if (nestedSequential == null) {
+            throw new BuildException("Missing sequential element");
+        }
+        if (name == null) {
+            throw new BuildException("Name not specified");
+        }
+
+        name = ProjectHelper.genComponentName(getURI(), name);
+
+        MyAntTypeDefinition def = new MyAntTypeDefinition(this);
+        def.setName(name);
+        def.setClass(MacroInstance.class);
+
+        ComponentHelper helper = ComponentHelper.getComponentHelper(
+            getProject());
+
+        helper.addDataTypeDefinition(def);
+        log("creating macro  " + name, Project.MSG_VERBOSE);
+    }
+
+
+    /**
+     * An attribute for the MacroDef task.
+     *
+     */
+    public static class Attribute {
+        private String name;
+        private String defaultValue;
+        private String description;
+
+        /**
+         * The name of the attribute.
+         *
+         * @param name the name of the attribute
+         */
+        public void setName(String name) {
+            if (!isValidName(name)) {
+                throw new BuildException(
+                    "Illegal name [" + name + "] for attribute");
+            }
+            this.name = name.toLowerCase(Locale.US);
+        }
+
+        /**
+         * @return the name of the attribute
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * The default value to use if the parameter is not
+         * used in the templated instance.
+         *
+         * @param defaultValue the default value
+         */
+        public void setDefault(String defaultValue) {
+            this.defaultValue = defaultValue;
+        }
+
+        /**
+         * @return the default value, null if not set
+         */
+        public String getDefault() {
+            return defaultValue;
+        }
+
+        /**
+         * @param desc Description of the element.
+         * @since ant 1.6.1
+         */
+        public void setDescription(String desc) {
+            description = desc;
+        }
+
+        /**
+         * @return the description of the element, or <code>null</code> if
+         *         no description is available.
+         * @since ant 1.6.1
+         */
+        public String getDescription() {
+            return description;
+        }
+
+        /**
+         * equality method
+         *
+         * @param obj an <code>Object</code> value
+         * @return a <code>boolean</code> value
+         */
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (obj.getClass() != getClass()) {
+                return false;
+            }
+            Attribute other = (Attribute) obj;
+            if (name == null) {
+                if (other.name != null) {
+                    return false;
+                }
+            } else if (!name.equals(other.name)) {
+                return false;
+            }
+            if (defaultValue == null) {
+                if (other.defaultValue != null) {
+                    return false;
+                }
+            } else if (!defaultValue.equals(other.defaultValue)) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * @return a hash code value for this object.
+         */
+        public int hashCode() {
+            return objectHashCode(defaultValue) + objectHashCode(name);
+        }
+    }
+
+    /**
+     * A nested text element for the MacroDef task.
+     * @since ant 1.6.1
+     */
+    public static class Text {
+        private String  name;
+        private boolean optional;
+        private boolean trim;
+        private String  description;
+        private String  defaultString;
+
+        /**
+         * The name of the attribute.
+         *
+         * @param name the name of the attribute
+         */
+        public void setName(String name) {
+            if (!isValidName(name)) {
+                throw new BuildException(
+                    "Illegal name [" + name + "] for attribute");
+            }
+            this.name = name.toLowerCase(Locale.US);
+        }
+
+        /**
+         * @return the name of the attribute
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * The optional attribute of the text element.
+         *
+         * @param optional if true this is optional
+         */
+        public void setOptional(boolean optional) {
+            this.optional = optional;
+        }
+
+        /**
+         * @return true if the text is optional
+         */
+        public boolean getOptional() {
+            return optional;
+        }
+
+        /**
+         * The trim attribute of the text element.
+         *
+         * @param trim if true this String.trim() is called on
+         *             the contents of the text element.
+         */
+        public void setTrim(boolean trim) {
+            this.trim = trim;
+        }
+
+        /**
+         * @return true if the text is trim
+         */
+        public boolean getTrim() {
+            return trim;
+        }
+
+        /**
+         * @param desc Description of the text.
+         */
+        public void setDescription(String desc) {
+            description = desc;
+        }
+
+        /**
+         * @return the description of the text, or <code>null</code> if
+         *         no description is available.
+         */
+        public String getDescription() {
+            return description;
+        }
+
+        /**
+         * @param defaultString default text for the string.
+         */
+        public void setDefault(String defaultString) {
+            this.defaultString = defaultString;
+        }
+
+        /**
+         * @return the default text if set, null otherwise.
+         */
+        public String getDefault() {
+            return defaultString;
+        }
+
+        /**
+         * equality method
+         *
+         * @param obj an <code>Object</code> value
+         * @return a <code>boolean</code> value
+         */
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (obj.getClass() != getClass()) {
+                return false;
+            }
+            Text other = (Text) obj;
+            return safeCompare(name, other.name)
+                && optional == other.optional
+                && trim == other.trim
+                && safeCompare(defaultString, other.defaultString);
+        }
+
+        /**
+         * @return a hash code value for this object.
+         */
+        public int hashCode() {
+            return objectHashCode(name);
+        }
+    }
+
+    private static boolean safeCompare(Object a, Object b) {
+        return a == null ? b == null : a.equals(b);
+    }
+
+    /**
+     * A nested element for the MacroDef task.
+     */
+    public static class TemplateElement {
+
+        private String name;
+        private String description;
+        private boolean optional = false;
+        private boolean implicit = false;
+
+        /**
+         * Sets the name of this element.
+         *
+         * @param name the name of the element
+         */
+        public void setName(String name) {
+            if (!isValidName(name)) {
+                throw new BuildException(
+                    "Illegal name [" + name + "] for macro element");
+            }
+            this.name = name.toLowerCase(Locale.US);
+        }
+
+        /**
+         * Gets the name of this element.
+         *
+         * @return the name of the element.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Sets a textual description of this element,
+         * for build documentation purposes only.
+         *
+         * @param desc Description of the element.
+         * @since ant 1.6.1
+         */
+        public void setDescription(String desc) {
+            description = desc;
+        }
+
+        /**
+         * Gets the description of this element.
+         *
+         * @return the description of the element, or <code>null</code> if
+         *         no description is available.
+         * @since ant 1.6.1
+         */
+        public String getDescription() {
+            return description;
+        }
+
+        /**
+         * Sets whether this element is optional.
+         *
+         * @param optional if true this element may be left out, default
+         *                 is false.
+         */
+        public void setOptional(boolean optional) {
+            this.optional = optional;
+        }
+
+        /**
+         * Gets whether this element is optional.
+         *
+         * @return the optional attribute
+         */
+        public boolean isOptional() {
+            return optional;
+        }
+
+        /**
+         * Sets whether this element is implicit.
+         *
+         * @param implicit if true this element may be left out, default
+         *                 is false.
+         */
+        public void setImplicit(boolean implicit) {
+            this.implicit = implicit;
+        }
+
+        /**
+         * Gets whether this element is implicit.
+         *
+         * @return the implicit attribute
+         */
+        public boolean isImplicit() {
+            return implicit;
+        }
+
+        /**
+         * equality method.
+         *
+         * @param obj an <code>Object</code> value
+         * @return a <code>boolean</code> value
+         */
+        public boolean equals(Object obj) {
+            if (obj == this) {
+              return true;
+            }
+            if (obj == null || !obj.getClass().equals(getClass())) {
+                return false;
+            }
+            TemplateElement t = (TemplateElement) obj;
+            return
+                (name == null ? t.name == null : name.equals(t.name))
+                && optional == t.optional
+                && implicit == t.implicit;
+        }
+
+        /**
+         * @return a hash code value for this object.
+         */
+        public int hashCode() {
+            return objectHashCode(name)
+                + (optional ? 1 : 0) + (implicit ? 1 : 0);
+        }
+
+    } // END static class TemplateElement
+
+    /**
+     * same or similar equality method for macrodef, ignores project and
+     * runtime info.
+     *
+     * @param obj an <code>Object</code> value
+     * @param same if true test for sameness, otherwise just similiar
+     * @return a <code>boolean</code> value
+     */
+    private boolean sameOrSimilar(Object obj, boolean same) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+        if (!obj.getClass().equals(getClass())) {
+            return false;
+        }
+        MacroDef other = (MacroDef) obj;
+        if (name == null) {
+            return other.name == null;
+        }
+        if (!name.equals(other.name)) {
+            return false;
+        }
+        // Allow two macro definitions with the same location
+        // to be treated as similar - bugzilla 31215
+        if (other.getLocation() != null
+            && other.getLocation().equals(getLocation())
+            && !same) {
+            return true;
+        }
+        if (text == null) {
+            if (other.text != null) {
+                return false;
+            }
+        } else {
+            if (!text.equals(other.text)) {
+                return false;
+            }
+        }
+        if (getURI() == null || getURI().equals("")
+            || getURI().equals(ProjectHelper.ANT_CORE_URI)) {
+            if (!(other.getURI() == null || other.getURI().equals("")
+                  || other.getURI().equals(ProjectHelper.ANT_CORE_URI))) {
+                return false;
+            }
+        } else {
+            if (!getURI().equals(other.getURI())) {
+                return false;
+            }
+        }
+
+        if (!nestedSequential.similar(other.nestedSequential)) {
+            return false;
+        }
+        if (!attributes.equals(other.attributes)) {
+            return false;
+        }
+        if (!elements.equals(other.elements)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Similar method for this definition
+     *
+     * @param obj another definition
+     * @return true if the definitions are similar
+     */
+    public boolean similar(Object obj) {
+        return sameOrSimilar(obj, false);
+    }
+
+    /**
+     * Equality method for this definition
+     *
+     * @param obj another definition
+     * @return true if the definitions are the same
+     */
+    public boolean sameDefinition(Object obj) {
+        return sameOrSimilar(obj, true);
+    }
+
+    /**
+     * extends AntTypeDefinition, on create
+     * of the object, the template macro definition
+     * is given.
+     */
+    private static class MyAntTypeDefinition extends AntTypeDefinition {
+        private MacroDef macroDef;
+
+        /**
+         * Creates a new <code>MyAntTypeDefinition</code> instance.
+         *
+         * @param macroDef a <code>MacroDef</code> value
+         */
+        public MyAntTypeDefinition(MacroDef macroDef) {
+            this.macroDef = macroDef;
+        }
+
+        /**
+         * Create an instance of the definition.
+         * The instance may be wrapped in a proxy class.
+         * @param project the current project
+         * @return the created object
+         */
+        public Object create(Project project) {
+            Object o = super.create(project);
+            if (o == null) {
+                return null;
+            }
+            ((MacroInstance) o).setMacroDef(macroDef);
+            return o;
+        }
+
+        /**
+         * Equality method for this definition
+         *
+         * @param other another definition
+         * @param project the current project
+         * @return true if the definitions are the same
+         */
+        public boolean sameDefinition(AntTypeDefinition other, Project project) {
+            if (!super.sameDefinition(other, project)) {
+                return false;
+            }
+            MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
+            return macroDef.sameDefinition(otherDef.macroDef);
+        }
+
+        /**
+         * Similar method for this definition
+         *
+         * @param other another definition
+         * @param project the current project
+         * @return true if the definitions are the same
+         */
+        public boolean similarDefinition(
+            AntTypeDefinition other, Project project) {
+            if (!super.similarDefinition(other, project)) {
+                return false;
+            }
+            MyAntTypeDefinition otherDef = (MyAntTypeDefinition) other;
+            return macroDef.similar(otherDef.macroDef);
+        }
+    }
+
+    private static int objectHashCode(Object o) {
+        if (o == null) {
+            return 0;
+        } else {
+            return o.hashCode();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java b/trunk/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
new file mode 100644
index 0000000..3917101
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
@@ -0,0 +1,408 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicAttribute;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.RuntimeConfigurable;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * The class to be placed in the ant type definition.
+ * It is given a pointer to the template definition,
+ * and makes a copy of the unknown element, substituting
+ * the parameter values in attributes and text.
+ * @since Ant 1.6
+ */
+public class MacroInstance extends Task implements DynamicAttribute, TaskContainer {
+    private MacroDef macroDef;
+    private Map      map = new HashMap();
+    private Map      nsElements = null;
+    private Map      presentElements;
+    private Hashtable localAttributes;
+    private String    text = null;
+    private String    implicitTag =     null;
+    private List      unknownElements = new ArrayList();
+
+    /**
+     * Called from MacroDef.MyAntTypeDefinition#create()
+     *
+     * @param macroDef a <code>MacroDef</code> value
+     */
+    public void setMacroDef(MacroDef macroDef) {
+        this.macroDef = macroDef;
+    }
+
+    /**
+     * @return the macro definition object for this macro instance.
+     */
+    public MacroDef getMacroDef() {
+        return macroDef;
+    }
+
+    /**
+     * A parameter name value pair as a xml attribute.
+     *
+     * @param name the name of the attribute
+     * @param value the value of the attribute
+     */
+    public void setDynamicAttribute(String name, String value) {
+        map.put(name, value);
+    }
+
+    /**
+     * Method present for BC purposes.
+     * @param name not used
+     * @return nothing
+     * @deprecated since 1.6.x.
+     * @throws BuildException always
+     */
+    public Object createDynamicElement(String name) throws BuildException {
+        throw new BuildException("Not implemented any more");
+    }
+
+    private Map getNsElements() {
+        if (nsElements == null) {
+            nsElements = new HashMap();
+            for (Iterator i = macroDef.getElements().entrySet().iterator();
+                 i.hasNext();) {
+                Map.Entry entry = (Map.Entry) i.next();
+                nsElements.put((String) entry.getKey(),
+                               entry.getValue());
+                MacroDef.TemplateElement te = (MacroDef.TemplateElement)
+                    entry.getValue();
+                if (te.isImplicit()) {
+                    implicitTag = te.getName();
+                }
+            }
+        }
+        return nsElements;
+    }
+
+    /**
+     * Add a unknownElement for the macro instances nested elements.
+     *
+     * @param nestedTask a nested element.
+     */
+    public void addTask(Task nestedTask) {
+        unknownElements.add(nestedTask);
+    }
+
+    private void processTasks() {
+        if (implicitTag != null) {
+            return;
+        }
+        for (Iterator i = unknownElements.iterator(); i.hasNext();) {
+            UnknownElement ue = (UnknownElement) i.next();
+            String name = ProjectHelper.extractNameFromComponentName(
+                ue.getTag()).toLowerCase(Locale.US);
+            if (getNsElements().get(name) == null) {
+                throw new BuildException("unsupported element " + name);
+            }
+            if (presentElements.get(name) != null) {
+                throw new BuildException("Element " + name + " already present");
+            }
+            presentElements.put(name, ue);
+        }
+    }
+
+    /**
+     * Embedded element in macro instance
+     */
+    public static class Element implements TaskContainer {
+        private List unknownElements = new ArrayList();
+
+        /**
+         * Add an unknown element (to be snipped into the macroDef instance)
+         *
+         * @param nestedTask an unknown element
+         */
+        public void addTask(Task nestedTask) {
+            unknownElements.add(nestedTask);
+        }
+
+        /**
+         * @return the list of unknown elements
+         */
+        public List getUnknownElements() {
+            return unknownElements;
+        }
+    }
+
+    private static final int STATE_NORMAL         = 0;
+    private static final int STATE_EXPECT_BRACKET = 1;
+    private static final int STATE_EXPECT_NAME    = 2;
+
+    private String macroSubs(String s, Map macroMapping) {
+        if (s == null) {
+            return null;
+        }
+        StringBuffer ret = new StringBuffer();
+        StringBuffer macroName = null;
+
+        int state = STATE_NORMAL;
+        for (int i = 0; i < s.length(); ++i) {
+            char ch = s.charAt(i);
+            switch (state) {
+                case STATE_NORMAL:
+                    if (ch == '@') {
+                        state = STATE_EXPECT_BRACKET;
+                    } else {
+                        ret.append(ch);
+                    }
+                    break;
+                case STATE_EXPECT_BRACKET:
+                    if (ch == '{') {
+                        state = STATE_EXPECT_NAME;
+                        macroName = new StringBuffer();
+                    } else if (ch == '@') {
+                        state = STATE_NORMAL;
+                        ret.append('@');
+                    } else {
+                        state = STATE_NORMAL;
+                        ret.append('@');
+                        ret.append(ch);
+                    }
+                    break;
+                case STATE_EXPECT_NAME:
+                    if (ch == '}') {
+                        state = STATE_NORMAL;
+                        String name = macroName.toString().toLowerCase(Locale.US);
+                        String value = (String) macroMapping.get(name);
+                        if (value == null) {
+                            ret.append("@{");
+                            ret.append(name);
+                            ret.append("}");
+                        } else {
+                            ret.append(value);
+                        }
+                        macroName = null;
+                    } else {
+                        macroName.append(ch);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+        switch (state) {
+            case STATE_NORMAL:
+                break;
+            case STATE_EXPECT_BRACKET:
+                ret.append('@');
+                break;
+            case STATE_EXPECT_NAME:
+                ret.append("@{");
+                ret.append(macroName.toString());
+                break;
+            default:
+                break;
+        }
+
+        return ret.toString();
+    }
+
+    /**
+     * Set the text contents for the macro.
+     * @param text the text to be added to the macro.
+     */
+
+    public void addText(String text) {
+        this.text = text;
+    }
+
+    private UnknownElement copy(UnknownElement ue, boolean nested) {
+        UnknownElement ret = new UnknownElement(ue.getTag());
+        ret.setNamespace(ue.getNamespace());
+        ret.setProject(getProject());
+        ret.setQName(ue.getQName());
+        ret.setTaskType(ue.getTaskType());
+        ret.setTaskName(ue.getTaskName());
+        ret.setLocation(
+            macroDef.getBackTrace() ? ue.getLocation() : getLocation());
+        if (getOwningTarget() == null) {
+            Target t = new Target();
+            t.setProject(getProject());
+            ret.setOwningTarget(t);
+        } else {
+            ret.setOwningTarget(getOwningTarget());
+        }
+        RuntimeConfigurable rc = new RuntimeConfigurable(
+            ret, ue.getTaskName());
+        rc.setPolyType(ue.getWrapper().getPolyType());
+        Map m = ue.getWrapper().getAttributeMap();
+        for (Iterator i = m.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            rc.setAttribute(
+                (String) entry.getKey(),
+                macroSubs((String) entry.getValue(), localAttributes));
+        }
+        rc.addText(macroSubs(ue.getWrapper().getText().toString(),
+                             localAttributes));
+
+        Enumeration e = ue.getWrapper().getChildren();
+        while (e.hasMoreElements()) {
+            RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement();
+            UnknownElement unknownElement = (UnknownElement) r.getProxy();
+            String tag = unknownElement.getTaskType();
+            if (tag != null) {
+                tag = tag.toLowerCase(Locale.US);
+            }
+            MacroDef.TemplateElement templateElement =
+                (MacroDef.TemplateElement) getNsElements().get(tag);
+            if (templateElement == null || nested) {
+                UnknownElement child = copy(unknownElement, nested);
+                rc.addChild(child.getWrapper());
+                ret.addChild(child);
+            } else if (templateElement.isImplicit()) {
+                if (unknownElements.size() == 0 && !templateElement.isOptional()) {
+                    throw new BuildException(
+                        "Missing nested elements for implicit element "
+                        + templateElement.getName());
+                }
+                for (Iterator i = unknownElements.iterator();
+                     i.hasNext();) {
+                    UnknownElement child
+                        = copy((UnknownElement) i.next(), true);
+                    rc.addChild(child.getWrapper());
+                    ret.addChild(child);
+                }
+            } else {
+                UnknownElement presentElement =
+                    (UnknownElement) presentElements.get(tag);
+                if (presentElement == null) {
+                    if (!templateElement.isOptional()) {
+                        throw new BuildException(
+                            "Required nested element "
+                            + templateElement.getName() + " missing");
+                    }
+                    continue;
+                }
+                String presentText =
+                    presentElement.getWrapper().getText().toString();
+                if (!"".equals(presentText)) {
+                    rc.addText(macroSubs(presentText, localAttributes));
+                }
+                List list = presentElement.getChildren();
+                if (list != null) {
+                    for (Iterator i = list.iterator();
+                         i.hasNext();) {
+                        UnknownElement child
+                            = copy((UnknownElement) i.next(), true);
+                        rc.addChild(child.getWrapper());
+                        ret.addChild(child);
+                    }
+                }
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Execute the templates instance.
+     * Copies the unknown element, substitutes the attributes,
+     * and calls perform on the unknown element.
+     *
+     */
+    public void execute() {
+        presentElements = new HashMap();
+        getNsElements();
+        processTasks();
+        localAttributes = new Hashtable();
+        Set copyKeys = new HashSet(map.keySet());
+        for (Iterator i = macroDef.getAttributes().iterator(); i.hasNext();) {
+            MacroDef.Attribute attribute = (MacroDef.Attribute) i.next();
+            String value = (String) map.get(attribute.getName());
+            if (value == null && "description".equals(attribute.getName())) {
+                value = getDescription();
+            }
+            if (value == null) {
+                value = attribute.getDefault();
+                value = macroSubs(value, localAttributes);
+            }
+            if (value == null) {
+                throw new BuildException(
+                    "required attribute " + attribute.getName() + " not set");
+            }
+            localAttributes.put(attribute.getName(), value);
+            copyKeys.remove(attribute.getName());
+        }
+        if (copyKeys.contains("id")) {
+            copyKeys.remove("id");
+        }
+        if (macroDef.getText() != null) {
+            if (text == null) {
+                String defaultText =  macroDef.getText().getDefault();
+                if (!macroDef.getText().getOptional() && defaultText == null) {
+                    throw new BuildException(
+                        "required text missing");
+                }
+                text = defaultText == null ? "" : defaultText;
+            }
+            if (macroDef.getText().getTrim()) {
+                text = text.trim();
+            }
+            localAttributes.put(macroDef.getText().getName(), text);
+        } else {
+            if (text != null && !text.trim().equals("")) {
+                throw new BuildException(
+                    "The \"" + getTaskName() + "\" macro does not support"
+                    + " nested text data.");
+            }
+        }
+        if (copyKeys.size() != 0) {
+            throw new BuildException(
+                "Unknown attribute" + (copyKeys.size() > 1 ? "s " : " ")
+                + copyKeys);
+        }
+
+        // need to set the project on unknown element
+        UnknownElement c = copy(macroDef.getNestedTask(), false);
+        c.init();
+        try {
+            c.perform();
+        } catch (BuildException ex) {
+            if (macroDef.getBackTrace()) {
+                throw ProjectHelper.addLocationToBuildException(
+                    ex, getLocation());
+            } else {
+                ex.setLocation(getLocation());
+                throw ex;
+            }
+        } finally {
+            presentElements = null;
+            localAttributes = null;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/MakeUrl.java b/trunk/src/main/org/apache/tools/ant/taskdefs/MakeUrl.java
new file mode 100644
index 0000000..4dbc35e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/MakeUrl.java
@@ -0,0 +1,297 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+
+import java.io.File;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This task takes file and turns them into a URL, which it then assigns
+ * to a property. Use when for setting up RMI codebases.
+ * <p/>
+ * nested filesets are supported; if present, these are turned into the
+ * url with the given separator between them (default = " ").
+ *
+ * @ant.task category="core" name="makeurl"
+ */
+
+public class MakeUrl extends Task {
+
+    /**
+     * name of the property to set
+     */
+    private String property;
+
+    /**
+     * name of a file to turn into a URL
+     */
+    private File file;
+
+    /**
+     * separator char
+     */
+    private String separator = " ";
+
+    /**
+     * filesets of nested files to add to this url
+     */
+    private List filesets = new LinkedList();
+
+    /**
+     * paths to add
+     */
+    private List paths = new LinkedList();
+
+    /**
+     * validation flag
+     */
+    private boolean validate = true;
+
+    // error message strings
+    /** Missing file */
+    public static final String ERROR_MISSING_FILE = "A source file is missing :";
+    /** No property defined */
+    public static final String ERROR_NO_PROPERTY = "No property defined";
+    /** No files defined */
+    public static final String ERROR_NO_FILES = "No files defined";
+
+    /**
+     * set the name of a property to fill with the URL
+     *
+     * @param property the name of the property.
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * the name of a file to be converted into a URL
+     *
+     * @param file the file to be converted.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * a fileset of jar files to include in the URL, each
+     * separated by the separator
+     *
+     * @param fileset the fileset to be added.
+     */
+    public void addFileSet(FileSet fileset) {
+        filesets.add(fileset);
+    }
+
+    /**
+     * set the separator for the multi-url option.
+     *
+     * @param separator the separator to use.
+     */
+    public void setSeparator(String separator) {
+        this.separator = separator;
+    }
+
+    /**
+     * set this flag to trigger validation that every named file exists.
+     * Optional: default=true
+     *
+     * @param validate a <code>boolean</code> value.
+     */
+    public void setValidate(boolean validate) {
+        this.validate = validate;
+    }
+
+    /**
+     * add a path to the URL. All elements in the path
+     * will be converted to individual URL entries
+     *
+     * @param path a path value.
+     */
+    public void addPath(Path path) {
+        paths.add(path);
+    }
+
+    /**
+     * convert the filesets to urls.
+     *
+     * @return null for no files
+     */
+    private String filesetsToURL() {
+        if (filesets.isEmpty()) {
+            return "";
+        }
+        int count = 0;
+        StringBuffer urls = new StringBuffer();
+        ListIterator list = filesets.listIterator();
+        while (list.hasNext()) {
+            FileSet set = (FileSet) list.next();
+            DirectoryScanner scanner = set.getDirectoryScanner(getProject());
+            String[] files = scanner.getIncludedFiles();
+            for (int i = 0; i < files.length; i++) {
+                File f = new File(scanner.getBasedir(), files[i]);
+                validateFile(f);
+                String asUrl = toURL(f);
+                urls.append(asUrl);
+                log(asUrl, Project.MSG_DEBUG);
+                urls.append(separator);
+                count++;
+            }
+        }
+        //at this point there is one trailing space to remove, if the list is not empty.
+        return stripTrailingSeparator(urls, count);
+    }
+
+    /**
+     * convert the string buffer to a string, potentially stripping
+     * out any trailing separator
+     *
+     * @param urls  URL buffer
+     * @param count number of URL entries
+     * @return trimmed string, or empty string
+     */
+    private String stripTrailingSeparator(StringBuffer urls,
+                                          int count) {
+        if (count > 0) {
+            urls.delete(urls.length() - separator.length(), urls.length());
+            return new String(urls);
+        } else {
+            return "";
+        }
+    }
+
+
+    /**
+     * convert all paths to URLs
+     *
+     * @return the paths as a separated list of URLs
+     */
+    private String pathsToURL() {
+        if (paths.isEmpty()) {
+            return "";
+        }
+        int count = 0;
+        StringBuffer urls = new StringBuffer();
+        ListIterator list = paths.listIterator();
+        while (list.hasNext()) {
+            Path path = (Path) list.next();
+            String[] elements = path.list();
+            for (int i = 0; i < elements.length; i++) {
+                File f = new File(elements[i]);
+                validateFile(f);
+                String asUrl = toURL(f);
+                urls.append(asUrl);
+                log(asUrl, Project.MSG_DEBUG);
+                urls.append(separator);
+                count++;
+            }
+        }
+        //at this point there is one trailing space to remove, if the list is not empty.
+        return stripTrailingSeparator(urls, count);
+    }
+
+    /**
+     * verify that the file exists, if {@link #validate} is set
+     *
+     * @param fileToCheck file that may need to exist
+     * @throws BuildException with text beginning {@link #ERROR_MISSING_FILE}
+     */
+    private void validateFile(File fileToCheck) {
+        if (validate && !fileToCheck.exists()) {
+            throw new BuildException(ERROR_MISSING_FILE + fileToCheck.toString());
+        }
+    }
+
+    /**
+     * Create the url
+     *
+     * @throws org.apache.tools.ant.BuildException
+     *          if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        validate();
+        //now exit here if the property is already set
+        if (getProject().getProperty(property) != null) {
+            return;
+        }
+        String url;
+        String filesetURL = filesetsToURL();
+        if (file != null) {
+            validateFile(file);
+            url = toURL(file);
+            //and add any files if also defined
+            if (filesetURL.length() > 0) {
+                url = url + separator + filesetURL;
+            }
+        } else {
+            url = filesetURL;
+        }
+        //add path URLs
+        String pathURL = pathsToURL();
+        if (pathURL.length() > 0) {
+            if (url.length() > 0) {
+                url = url + separator + pathURL;
+            } else {
+                url = pathURL;
+            }
+        }
+        log("Setting " + property + " to URL " + url, Project.MSG_VERBOSE);
+        getProject().setNewProperty(property, url);
+    }
+
+    /**
+     * check for errors
+     * @throws BuildException if we are not configured right
+     */
+    private void validate() {
+        //validation
+        if (property == null) {
+            throw new BuildException(ERROR_NO_PROPERTY);
+        }
+        if (file == null && filesets.isEmpty() && paths.isEmpty()) {
+            throw new BuildException(ERROR_NO_FILES);
+        }
+    }
+
+    /**
+     * convert a file to a URL;
+     *
+     * @param fileToConvert
+     * @return the file converted to a URL
+     */
+    private String toURL(File fileToConvert) {
+        String url;
+        //create the URL
+        //ant equivalent of  fileToConvert.toURI().toURL().toExternalForm();
+        url = FileUtils.getFileUtils().toURI(fileToConvert.getAbsolutePath());
+
+        return url;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Manifest.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Manifest.java
new file mode 100644
index 0000000..f10063e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Manifest.java
@@ -0,0 +1,1074 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Holds the data of a jar manifest.
+ *
+ * Manifests are processed according to the
+ * {@link <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html">Jar
+ * file specification.</a>}.
+ * Specifically, a manifest element consists of
+ * a set of attributes and sections. These sections in turn may contain
+ * attributes. Note in particular that this may result in manifest lines
+ * greater than 72 bytes being wrapped and continued on the next
+ * line. If an application can not handle the continuation mechanism, it
+ * is a defect in the application, not this task.
+ *
+ *
+ * @since Ant 1.4
+ */
+public class Manifest {
+    /** The standard manifest version header */
+    public static final String ATTRIBUTE_MANIFEST_VERSION
+        = "Manifest-Version";
+
+    /** The standard Signature Version header */
+    public static final String ATTRIBUTE_SIGNATURE_VERSION
+        = "Signature-Version";
+
+    /** The Name Attribute is the first in a named section */
+    public static final String ATTRIBUTE_NAME = "Name";
+
+    /** The From Header is disallowed in a Manifest */
+    public static final String ATTRIBUTE_FROM = "From";
+
+    /** The Class-Path Header is special - it can be duplicated */
+    public static final String ATTRIBUTE_CLASSPATH = "Class-Path";
+
+    /** Default Manifest version if one is not specified */
+    public static final  String DEFAULT_MANIFEST_VERSION = "1.0";
+
+    /** The max length of a line in a Manifest */
+    public static final int MAX_LINE_LENGTH = 72;
+
+    /**
+     * Max length of a line section which is continued. Need to allow
+     * for the CRLF.
+     */
+    public static final int MAX_SECTION_LENGTH = MAX_LINE_LENGTH - 2;
+
+    /** The End-Of-Line marker in manifests */
+    public static final String EOL = "\r\n";
+    /** Error for attributes */
+    public static final String ERROR_FROM_FORBIDDEN = "Manifest attributes should not start "
+                        + "with \"" + ATTRIBUTE_FROM + "\" in \"";
+
+    /** Encoding to be used for JAR files. */
+    public static final String JAR_ENCODING = "UTF-8";
+
+    /**
+     * An attribute for the manifest.
+     * Those attributes that are not nested into a section will be added to the "Main" section.
+     */
+    public static class Attribute {
+
+        /**
+         * Maximum length of the name to have the value starting on the same
+         * line as the name. This to stay under 72 bytes total line length
+         * (including CRLF).
+         */
+        private static final int MAX_NAME_VALUE_LENGTH = 68;
+
+        /**
+         * Maximum length of the name according to the jar specification.
+         * In this case the first line will have 74 bytes total line length
+         * (including CRLF). This conflicts with the 72 bytes total line length
+         * max, but is the only possible conclusion from the manifest specification, if
+         * names with 70 bytes length are allowed, have to be on the first line, and
+         * have to be followed by ": ".
+         */
+        private static final int MAX_NAME_LENGTH = 70;
+
+        /** The attribute's name */
+        private String name = null;
+
+        /** The attribute's value */
+        private Vector values = new Vector();
+
+        /**
+         * For multivalued attributes, this is the index of the attribute
+         * currently being defined.
+         */
+        private int currentIndex = 0;
+
+        /**
+         * Construct an empty attribute */
+        public Attribute() {
+        }
+
+        /**
+         * Construct an attribute by parsing a line from the Manifest
+         *
+         * @param line the line containing the attribute name and value
+         *
+         * @throws ManifestException if the line is not valid
+         */
+        public Attribute(String line) throws ManifestException {
+            parse(line);
+        }
+
+        /**
+         * Construct a manifest by specifying its name and value
+         *
+         * @param name the attribute's name
+         * @param value the Attribute's value
+         */
+        public Attribute(String name, String value) {
+            this.name = name;
+            setValue(value);
+        }
+
+        /**
+         * @see java.lang.Object#hashCode
+         * @return a hashcode based on the key and values.
+         */
+        public int hashCode() {
+            int hashCode = 0;
+
+            if (name != null) {
+                hashCode += getKey().hashCode();
+            }
+
+            hashCode += values.hashCode();
+            return hashCode;
+        }
+
+        /**
+         * @param rhs the object to check for equality.
+         * @see java.lang.Object#equals
+         * @return true if the key and values are the same.
+         */
+        public boolean equals(Object rhs) {
+            if (rhs == null || rhs.getClass() != getClass()) {
+                return false;
+            }
+
+            if (rhs == this) {
+                return true;
+            }
+
+            Attribute rhsAttribute = (Attribute) rhs;
+            String lhsKey = getKey();
+            String rhsKey = rhsAttribute.getKey();
+            if ((lhsKey == null && rhsKey != null)
+                 || (lhsKey != null && !lhsKey.equals(rhsKey))) {
+                return false;
+            }
+
+            return values.equals(rhsAttribute.values);
+        }
+
+        /**
+         * Parse a line into name and value pairs
+         *
+         * @param line the line to be parsed
+         *
+         * @throws ManifestException if the line does not contain a colon
+         * separating the name and value
+         */
+        public void parse(String line) throws ManifestException {
+            int index = line.indexOf(": ");
+            if (index == -1) {
+                throw new ManifestException("Manifest line \"" + line
+                    + "\" is not valid as it does not "
+                    + "contain a name and a value separated by ': ' ");
+            }
+            name = line.substring(0, index);
+            setValue(line.substring(index + 2));
+        }
+
+        /**
+         * Set the Attribute's name; required
+         *
+         * @param name the attribute's name
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the Attribute's name
+         *
+         * @return the attribute's name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Get the attribute's Key - its name in lower case.
+         *
+         * @return the attribute's key.
+         */
+        public String getKey() {
+            if (name == null) {
+                return null;
+            }
+            return name.toLowerCase();
+        }
+
+        /**
+         * Set the Attribute's value; required
+         *
+         * @param value the attribute's value
+         */
+        public void setValue(String value) {
+            if (currentIndex >= values.size()) {
+                values.addElement(value);
+                currentIndex = values.size() - 1;
+            } else {
+                values.setElementAt(value, currentIndex);
+            }
+        }
+
+        /**
+         * Get the Attribute's value.
+         *
+         * @return the attribute's value.
+         */
+        public String getValue() {
+            if (values.size() == 0) {
+                return null;
+            }
+
+            String fullValue = "";
+            for (Enumeration e = getValues(); e.hasMoreElements();) {
+                String value = (String) e.nextElement();
+                fullValue += value + " ";
+            }
+            return fullValue.trim();
+        }
+
+        /**
+         * Add a new value to this attribute - making it multivalued.
+         *
+         * @param value the attribute's additional value
+         */
+        public void addValue(String value) {
+            currentIndex++;
+            setValue(value);
+        }
+
+        /**
+         * Get all the attribute's values.
+         *
+         * @return an enumeration of the attributes values
+         */
+        public Enumeration getValues() {
+            return values.elements();
+        }
+
+        /**
+         * Add a continuation line from the Manifest file.
+         *
+         * When lines are too long in a manifest, they are continued on the
+         * next line by starting with a space. This method adds the continuation
+         * data to the attribute value by skipping the first character.
+         *
+         * @param line the continuation line.
+         */
+        public void addContinuation(String line) {
+            String currentValue = (String) values.elementAt(currentIndex);
+            setValue(currentValue + line.substring(1));
+        }
+
+        /**
+         * Write the attribute out to a print writer.
+         *
+         * @param writer the Writer to which the attribute is written
+         *
+         * @throws IOException if the attribute value cannot be written
+         */
+        public void write(PrintWriter writer) throws IOException {
+            for (Enumeration e = getValues(); e.hasMoreElements();) {
+                writeValue(writer, (String) e.nextElement());
+            }
+        }
+
+        /**
+         * Write a single attribute value out
+         *
+         * @param writer the Writer to which the attribute is written
+         * @param value the attribute value
+         *
+         * @throws IOException if the attribute value cannot be written
+         */
+        private void writeValue(PrintWriter writer, String value)
+             throws IOException {
+            String line = null;
+            int nameLength = name.getBytes(JAR_ENCODING).length;
+            if (nameLength > MAX_NAME_VALUE_LENGTH) {
+                if (nameLength > MAX_NAME_LENGTH) {
+                    throw new IOException("Unable to write manifest line "
+                            + name + ": " + value);
+                }
+                writer.print(name + ": " + EOL);
+                line = " " + value;
+            } else {
+                line = name + ": " + value;
+            }
+            while (line.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH) {
+                // try to find a MAX_LINE_LENGTH byte section
+                int breakIndex = MAX_SECTION_LENGTH;
+                if (breakIndex >= line.length()) {
+                    breakIndex = line.length() - 1;
+                }
+                String section = line.substring(0, breakIndex);
+                while (section.getBytes(JAR_ENCODING).length > MAX_SECTION_LENGTH
+                     && breakIndex > 0) {
+                    breakIndex--;
+                    section = line.substring(0, breakIndex);
+                }
+                if (breakIndex == 0) {
+                    throw new IOException("Unable to write manifest line "
+                        + name + ": " + value);
+                }
+                writer.print(section + EOL);
+                line = " " + line.substring(breakIndex);
+            }
+            writer.print(line + EOL);
+        }
+    }
+
+    /**
+     * A manifest section - you can nest attribute elements into sections.
+     * A section consists of a set of attribute values,
+     * separated from other sections by a blank line.
+     */
+    public static class Section {
+        /** Warnings for this section */
+        private Vector warnings = new Vector();
+
+        /**
+         * The section's name if any. The main section in a
+         * manifest is unnamed.
+         */
+        private String name = null;
+
+        /** The section's attributes.*/
+        private Hashtable attributes = new Hashtable();
+
+        /** Index used to retain the attribute ordering */
+        private Vector attributeIndex = new Vector();
+
+        /**
+         * The name of the section; optional -default is the main section.
+         * @param name the section's name
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the Section's name.
+         *
+         * @return the section's name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Read a section through a reader.
+         *
+         * @param reader the reader from which the section is read
+         *
+         * @return the name of the next section if it has been read as
+         *         part of this section - This only happens if the
+         *         Manifest is malformed.
+         *
+         * @throws ManifestException if the section is not valid according
+         *         to the JAR spec
+         * @throws IOException if the section cannot be read from the reader.
+         */
+        public String read(BufferedReader reader)
+             throws ManifestException, IOException {
+            Attribute attribute = null;
+            while (true) {
+                String line = reader.readLine();
+                if (line == null || line.length() == 0) {
+                    return null;
+                }
+                if (line.charAt(0) == ' ') {
+                    // continuation line
+                    if (attribute == null) {
+                        if (name != null) {
+                            // a continuation on the first line is a
+                            // continuation of the name - concatenate this
+                            // line and the name
+                            name += line.substring(1);
+                        } else {
+                            throw new ManifestException("Can't start an "
+                                + "attribute with a continuation line " + line);
+                        }
+                    } else {
+                        attribute.addContinuation(line);
+                    }
+                } else {
+                    attribute = new Attribute(line);
+                    String nameReadAhead = addAttributeAndCheck(attribute);
+                    // refresh attribute in case of multivalued attributes.
+                    attribute = getAttribute(attribute.getKey());
+                    if (nameReadAhead != null) {
+                        return nameReadAhead;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Merge in another section
+         *
+         * @param section the section to be merged with this one.
+         *
+         * @throws ManifestException if the sections cannot be merged.
+         */
+        public void merge(Section section) throws ManifestException {
+            if (name == null && section.getName() != null
+                || name != null
+                && !(name.equalsIgnoreCase(section.getName()))) {
+                throw new ManifestException("Unable to merge sections "
+                    + "with different names");
+            }
+
+            Enumeration e = section.getAttributeKeys();
+            Attribute classpathAttribute = null;
+            while (e.hasMoreElements()) {
+                String attributeName = (String) e.nextElement();
+                Attribute attribute = section.getAttribute(attributeName);
+                if (attributeName.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) {
+                    if (classpathAttribute == null) {
+                        classpathAttribute = new Attribute();
+                        classpathAttribute.setName(ATTRIBUTE_CLASSPATH);
+                    }
+                    Enumeration cpe = attribute.getValues();
+                    while (cpe.hasMoreElements()) {
+                        String value = (String) cpe.nextElement();
+                        classpathAttribute.addValue(value);
+                    }
+                } else {
+                    // the merge file always wins
+                    storeAttribute(attribute);
+                }
+            }
+
+            if (classpathAttribute != null) {
+                // the merge file *always* wins, even for Class-Path
+                storeAttribute(classpathAttribute);
+            }
+
+            // add in the warnings
+            Enumeration warnEnum = section.warnings.elements();
+            while (warnEnum.hasMoreElements()) {
+                warnings.addElement(warnEnum.nextElement());
+            }
+        }
+
+        /**
+         * Write the section out to a print writer.
+         *
+         * @param writer the Writer to which the section is written
+         *
+         * @throws IOException if the section cannot be written
+         */
+        public void write(PrintWriter writer) throws IOException {
+            if (name != null) {
+                Attribute nameAttr = new Attribute(ATTRIBUTE_NAME, name);
+                nameAttr.write(writer);
+            }
+            Enumeration e = getAttributeKeys();
+            while (e.hasMoreElements()) {
+                String key = (String) e.nextElement();
+                Attribute attribute = getAttribute(key);
+                attribute.write(writer);
+            }
+            writer.print(EOL);
+        }
+
+        /**
+         * Get a attribute of the section
+         *
+         * @param attributeName the name of the attribute
+         * @return a Manifest.Attribute instance if the attribute is
+         *         single-valued, otherwise a Vector of Manifest.Attribute
+         *         instances.
+         */
+        public Attribute getAttribute(String attributeName) {
+            return (Attribute) attributes.get(attributeName.toLowerCase());
+        }
+
+        /**
+         * Get the attribute keys.
+         *
+         * @return an Enumeration of Strings, each string being the lower case
+         *         key of an attribute of the section.
+         */
+        public Enumeration getAttributeKeys() {
+            return attributeIndex.elements();
+        }
+
+        /**
+         * Get the value of the attribute with the name given.
+         *
+         * @param attributeName the name of the attribute to be returned.
+         *
+         * @return the attribute's value or null if the attribute does not exist
+         *         in the section
+         */
+        public String getAttributeValue(String attributeName) {
+            Attribute attribute = getAttribute(attributeName.toLowerCase());
+            if (attribute == null) {
+                return null;
+            }
+            return attribute.getValue();
+        }
+
+        /**
+         * Remove the given attribute from the section
+         *
+         * @param attributeName the name of the attribute to be removed.
+         */
+        public void removeAttribute(String attributeName) {
+            String key = attributeName.toLowerCase();
+            attributes.remove(key);
+            attributeIndex.removeElement(key);
+        }
+
+        /**
+         * Add an attribute to the section.
+         *
+         * @param attribute the attribute to be added to the section
+         *
+         * @exception ManifestException if the attribute is not valid.
+         */
+        public void addConfiguredAttribute(Attribute attribute)
+             throws ManifestException {
+            String check = addAttributeAndCheck(attribute);
+            if (check != null) {
+                throw new BuildException("Specify the section name using "
+                    + "the \"name\" attribute of the <section> element rather "
+                    + "than using a \"Name\" manifest attribute");
+            }
+        }
+
+        /**
+         * Add an attribute to the section
+         *
+         * @param attribute the attribute to be added.
+         *
+         * @return the value of the attribute if it is a name
+         *         attribute - null other wise
+         *
+         * @exception ManifestException if the attribute already
+         *            exists in this section.
+         */
+        public String addAttributeAndCheck(Attribute attribute)
+             throws ManifestException {
+            if (attribute.getName() == null || attribute.getValue() == null) {
+                throw new BuildException("Attributes must have name and value");
+            }
+            if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_NAME)) {
+                warnings.addElement("\"" + ATTRIBUTE_NAME + "\" attributes "
+                    + "should not occur in the main section and must be the "
+                    + "first element in all other sections: \""
+                    + attribute.getName() + ": " + attribute.getValue() + "\"");
+                return attribute.getValue();
+            }
+
+            if (attribute.getKey().startsWith(ATTRIBUTE_FROM.toLowerCase())) {
+                warnings.addElement(ERROR_FROM_FORBIDDEN
+                    + attribute.getName() + ": " + attribute.getValue() + "\"");
+            } else {
+                // classpath attributes go into a vector
+                String attributeKey = attribute.getKey();
+                if (attributeKey.equalsIgnoreCase(ATTRIBUTE_CLASSPATH)) {
+                    Attribute classpathAttribute =
+                        (Attribute) attributes.get(attributeKey);
+
+                    if (classpathAttribute == null) {
+                        storeAttribute(attribute);
+                    } else {
+                        warnings.addElement("Multiple Class-Path attributes "
+                            + "are supported but violate the Jar "
+                            + "specification and may not be correctly "
+                            + "processed in all environments");
+                        Enumeration e = attribute.getValues();
+                        while (e.hasMoreElements()) {
+                            String value = (String) e.nextElement();
+                            classpathAttribute.addValue(value);
+                        }
+                    }
+                } else if (attributes.containsKey(attributeKey)) {
+                    throw new ManifestException("The attribute \""
+                        + attribute.getName() + "\" may not occur more "
+                        + "than once in the same section");
+                } else {
+                    storeAttribute(attribute);
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Clone this section
+         *
+         * @return the cloned Section
+         * @since Ant 1.5.2
+         */
+        public Object clone() {
+            Section cloned = new Section();
+            cloned.setName(name);
+            Enumeration e = getAttributeKeys();
+            while (e.hasMoreElements()) {
+                String key = (String) e.nextElement();
+                Attribute attribute = getAttribute(key);
+                cloned.storeAttribute(new Attribute(attribute.getName(),
+                                                    attribute.getValue()));
+            }
+            return cloned;
+        }
+
+        /**
+         * Store an attribute and update the index.
+         *
+         * @param attribute the attribute to be stored
+         */
+        private void storeAttribute(Attribute attribute) {
+            if (attribute == null) {
+                return;
+            }
+            String attributeKey = attribute.getKey();
+            attributes.put(attributeKey, attribute);
+            if (!attributeIndex.contains(attributeKey)) {
+                attributeIndex.addElement(attributeKey);
+            }
+        }
+
+        /**
+         * Get the warnings for this section.
+         *
+         * @return an Enumeration of warning strings.
+         */
+        public Enumeration getWarnings() {
+            return warnings.elements();
+        }
+
+        /**
+         * @see java.lang.Object#hashCode
+         * @return a hash value based on the attributes.
+         */
+        public int hashCode() {
+            return attributes.hashCode();
+        }
+
+        /**
+         * @see java.lang.Object#equals
+         * @param rhs the object to check for equality.
+         * @return true if the attributes are the same.
+         */
+        public boolean equals(Object rhs) {
+            if (rhs == null || rhs.getClass() != getClass()) {
+                return false;
+            }
+
+            if (rhs == this) {
+                return true;
+            }
+
+            Section rhsSection = (Section) rhs;
+
+            return attributes.equals(rhsSection.attributes);
+        }
+    }
+
+
+    /** The version of this manifest */
+    private String manifestVersion = DEFAULT_MANIFEST_VERSION;
+
+    /** The main section of this manifest */
+    private Section mainSection = new Section();
+
+    /** The named sections of this manifest */
+    private Hashtable sections = new Hashtable();
+
+    /** Index of sections - used to retain order of sections in manifest */
+    private Vector sectionIndex = new Vector();
+
+    /**
+     * Construct a manifest from Ant's default manifest file.
+     *
+     * @return the default manifest.
+     * @exception BuildException if there is a problem loading the
+     *            default manifest
+     */
+    public static Manifest getDefaultManifest() throws BuildException {
+        InputStream in = null;
+        InputStreamReader insr = null;
+        try {
+            String defManifest = "/org/apache/tools/ant/defaultManifest.mf";
+            in = Manifest.class.getResourceAsStream(defManifest);
+            if (in == null) {
+                throw new BuildException("Could not find default manifest: "
+                    + defManifest);
+            }
+            try {
+                insr = new InputStreamReader(in, "UTF-8");
+                Manifest defaultManifest = new Manifest(insr);
+                Attribute createdBy = new Attribute("Created-By",
+                    System.getProperty("java.vm.version") + " ("
+                    + System.getProperty("java.vm.vendor") + ")");
+                defaultManifest.getMainSection().storeAttribute(createdBy);
+                return defaultManifest;
+            } catch (UnsupportedEncodingException e) {
+                insr = new InputStreamReader(in);
+                return new Manifest(insr);
+            }
+        } catch (ManifestException e) {
+            throw new BuildException("Default manifest is invalid !!", e);
+        } catch (IOException e) {
+            throw new BuildException("Unable to read default manifest", e);
+        } finally {
+            FileUtils.close(insr);
+            FileUtils.close(in);
+        }
+    }
+
+    /** Construct an empty manifest */
+    public Manifest() {
+        manifestVersion = null;
+    }
+
+    /**
+     * Read a manifest file from the given reader
+     *
+     * @param r is the reader from which the Manifest is read
+     *
+     * @throws ManifestException if the manifest is not valid according
+     *         to the JAR spec
+     * @throws IOException if the manifest cannot be read from the reader.
+     */
+    public Manifest(Reader r) throws ManifestException, IOException {
+        BufferedReader reader = new BufferedReader(r);
+        // This should be the manifest version
+        String nextSectionName = mainSection.read(reader);
+        String readManifestVersion
+            = mainSection.getAttributeValue(ATTRIBUTE_MANIFEST_VERSION);
+        if (readManifestVersion != null) {
+            manifestVersion = readManifestVersion;
+            mainSection.removeAttribute(ATTRIBUTE_MANIFEST_VERSION);
+        }
+
+        String line = null;
+        while ((line = reader.readLine()) != null) {
+            if (line.length() == 0) {
+                continue;
+            }
+
+            Section section = new Section();
+            if (nextSectionName == null) {
+                Attribute sectionName = new Attribute(line);
+                if (!sectionName.getName().equalsIgnoreCase(ATTRIBUTE_NAME)) {
+                    throw new ManifestException("Manifest sections should "
+                        + "start with a \"" + ATTRIBUTE_NAME
+                        + "\" attribute and not \""
+                        + sectionName.getName() + "\"");
+                }
+                nextSectionName = sectionName.getValue();
+            } else {
+                // we have already started reading this section
+                // this line is the first attribute. set it and then
+                // let the normal read handle the rest
+                Attribute firstAttribute = new Attribute(line);
+                section.addAttributeAndCheck(firstAttribute);
+            }
+
+            section.setName(nextSectionName);
+            nextSectionName = section.read(reader);
+            addConfiguredSection(section);
+        }
+    }
+
+    /**
+     * Add a section to the manifest
+     *
+     * @param section the manifest section to be added
+     *
+     * @exception ManifestException if the secti0on is not valid.
+     */
+    public void addConfiguredSection(Section section)
+         throws ManifestException {
+        String sectionName = section.getName();
+        if (sectionName == null) {
+            throw new BuildException("Sections must have a name");
+        }
+        sections.put(sectionName, section);
+        if (!sectionIndex.contains(sectionName)) {
+            sectionIndex.addElement(sectionName);
+        }
+    }
+
+    /**
+     * Add an attribute to the manifest - it is added to the main section.
+     *
+     * @param attribute the attribute to be added.
+     *
+     * @exception ManifestException if the attribute is not valid.
+     */
+    public void addConfiguredAttribute(Attribute attribute)
+         throws ManifestException {
+        if (attribute.getKey() == null || attribute.getValue() == null) {
+            throw new BuildException("Attributes must have name and value");
+        }
+        if (attribute.getKey().equalsIgnoreCase(ATTRIBUTE_MANIFEST_VERSION)) {
+            manifestVersion = attribute.getValue();
+        } else {
+            mainSection.addConfiguredAttribute(attribute);
+        }
+    }
+
+    /**
+     * Merge the contents of the given manifest into this manifest
+     *
+     * @param other the Manifest to be merged with this one.
+     *
+     * @throws ManifestException if there is a problem merging the
+     *         manifest according to the Manifest spec.
+     */
+    public void merge(Manifest other) throws ManifestException {
+        merge(other, false);
+    }
+
+    /**
+     * Merge the contents of the given manifest into this manifest
+     *
+     * @param other the Manifest to be merged with this one.
+     * @param overwriteMain whether to overwrite the main section
+     *        of the current manifest
+     *
+     * @throws ManifestException if there is a problem merging the
+     *         manifest according to the Manifest spec.
+     */
+    public void merge(Manifest other, boolean overwriteMain)
+         throws ManifestException {
+        if (other != null) {
+             if (overwriteMain) {
+                 mainSection = (Section) other.mainSection.clone();
+             } else {
+                 mainSection.merge(other.mainSection);
+             }
+
+             if (other.manifestVersion != null) {
+                 manifestVersion = other.manifestVersion;
+             }
+
+             Enumeration e = other.getSectionNames();
+             while (e.hasMoreElements()) {
+                 String sectionName = (String) e.nextElement();
+                 Section ourSection = (Section) sections.get(sectionName);
+                 Section otherSection
+                    = (Section) other.sections.get(sectionName);
+                 if (ourSection == null) {
+                     if (otherSection != null) {
+                         addConfiguredSection((Section) otherSection.clone());
+                     }
+                 } else {
+                     ourSection.merge(otherSection);
+                 }
+             }
+         }
+    }
+
+    /**
+    * Write the manifest out to a print writer.
+    *
+    * @param writer the Writer to which the manifest is written
+    *
+    * @throws IOException if the manifest cannot be written
+    */
+    public void write(PrintWriter writer) throws IOException {
+        writer.print(ATTRIBUTE_MANIFEST_VERSION + ": " + manifestVersion + EOL);
+        String signatureVersion
+            = mainSection.getAttributeValue(ATTRIBUTE_SIGNATURE_VERSION);
+        if (signatureVersion != null) {
+            writer.print(ATTRIBUTE_SIGNATURE_VERSION + ": "
+                + signatureVersion + EOL);
+            mainSection.removeAttribute(ATTRIBUTE_SIGNATURE_VERSION);
+        }
+        mainSection.write(writer);
+
+        // add it back
+        if (signatureVersion != null) {
+            try {
+                Attribute svAttr = new Attribute(ATTRIBUTE_SIGNATURE_VERSION,
+                    signatureVersion);
+                mainSection.addConfiguredAttribute(svAttr);
+            } catch (ManifestException e) {
+                // shouldn't happen - ignore
+            }
+        }
+
+        Enumeration e = sectionIndex.elements();
+        while (e.hasMoreElements()) {
+            String sectionName = (String) e.nextElement();
+            Section section = getSection(sectionName);
+            section.write(writer);
+        }
+    }
+
+    /**
+     * Convert the manifest to its string representation
+     *
+     * @return a multiline string with the Manifest as it
+     *         appears in a Manifest file.
+     */
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        try {
+            write(new PrintWriter(sw));
+        } catch (IOException e) {
+            return null;
+        }
+        return sw.toString();
+    }
+
+    /**
+     * Get the warnings for this manifest.
+     *
+     * @return an enumeration of warning strings
+     */
+    public Enumeration getWarnings() {
+        Vector warnings = new Vector();
+
+        Enumeration warnEnum = mainSection.getWarnings();
+        while (warnEnum.hasMoreElements()) {
+            warnings.addElement(warnEnum.nextElement());
+        }
+
+        // create a vector and add in the warnings for all the sections
+        Enumeration e = sections.elements();
+        while (e.hasMoreElements()) {
+            Section section = (Section) e.nextElement();
+            Enumeration e2 = section.getWarnings();
+            while (e2.hasMoreElements()) {
+                warnings.addElement(e2.nextElement());
+            }
+        }
+
+        return warnings.elements();
+    }
+
+    /**
+     * @see java.lang.Object#hashCode
+     * @return a hashcode based on the version, main and sections.
+     */
+    public int hashCode() {
+        int hashCode = 0;
+
+        if (manifestVersion != null) {
+            hashCode += manifestVersion.hashCode();
+        }
+        hashCode += mainSection.hashCode();
+        hashCode += sections.hashCode();
+
+        return hashCode;
+    }
+
+    /**
+     * @see java.lang.Object#equals
+     * @param rhs the object to check for equality.
+     * @return true if the version, main and sections are the same.
+     */
+    public boolean equals(Object rhs) {
+        if (rhs == null || rhs.getClass() != getClass()) {
+            return false;
+        }
+
+        if (rhs == this) {
+            return true;
+        }
+
+        Manifest rhsManifest = (Manifest) rhs;
+        if (manifestVersion == null) {
+            if (rhsManifest.manifestVersion != null) {
+                return false;
+            }
+        } else if (!manifestVersion.equals(rhsManifest.manifestVersion)) {
+            return false;
+        }
+
+        if (!mainSection.equals(rhsManifest.mainSection)) {
+            return false;
+        }
+
+        return sections.equals(rhsManifest.sections);
+    }
+
+    /**
+     * Get the version of the manifest
+     *
+     * @return the manifest's version string
+     */
+    public String getManifestVersion() {
+        return manifestVersion;
+    }
+
+    /**
+     * Get the main section of the manifest
+     *
+     * @return the main section of the manifest
+     */
+    public Section getMainSection() {
+        return mainSection;
+    }
+
+    /**
+     * Get a particular section from the manifest
+     *
+     * @param name the name of the section desired.
+     * @return the specified section or null if that section
+     * does not exist in the manifest
+     */
+    public Section getSection(String name) {
+        return (Section) sections.get(name);
+    }
+
+    /**
+     * Get the section names in this manifest.
+     *
+     * @return an Enumeration of section names
+     */
+    public Enumeration getSectionNames() {
+        return sectionIndex.elements();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestClassPath.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestClassPath.java
new file mode 100644
index 0000000..f980620
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestClassPath.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.launch.Locator;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Converts a Path into a property suitable as a Manifest classpath.
+ *
+ * @since Ant 1.7
+ *
+ * @ant.task category="property"
+ */
+public class ManifestClassPath extends Task {
+
+    /** The property name to hold the classpath value. */
+    private String name;
+
+    /** The directory the classpath will be relative from. */
+    private File dir;
+
+    /** The maximum parent directory level to traverse. */
+    private int maxParentLevels = 2;
+
+    /** The classpath to convert. */
+    private Path path;
+
+    /**
+     * Sets a property, which must not already exist, with a space
+     * separated list of files and directories relative to the jar
+     * file's parent directory.
+     */
+    public void execute() {
+        if (name == null) {
+          throw new BuildException("Missing 'property' attribute!");
+        }
+        if (dir == null) {
+          throw new BuildException("Missing 'jarfile' attribute!");
+        }
+        if (getProject().getProperty(name) != null) {
+          throw new BuildException("Property '" + name + "' already set!");
+        }
+        if (path == null) {
+            throw new BuildException("Missing nested <classpath>!");
+        }
+
+        // Normalize the reference directory (containing the jar)
+        final FileUtils fileUtils = FileUtils.getFileUtils();
+        dir = fileUtils.normalize(dir.getAbsolutePath());
+
+        // Create as many directory prefixes as parent levels to traverse,
+        // in addition to the reference directory itself
+        File currDir = dir;
+        String[] dirs = new String[maxParentLevels + 1];
+        for (int i = 0; i < maxParentLevels + 1; ++i) {
+            dirs[i] = currDir.getAbsolutePath() + File.separatorChar;
+            currDir = currDir.getParentFile();
+            if (currDir == null) {
+                maxParentLevels = i + 1;
+                break;
+            }
+        }
+
+        String[] elements = path.list();
+        StringBuffer buffer = new StringBuffer();
+        StringBuffer element = new StringBuffer();
+        for (int i = 0; i < elements.length; ++i) {
+            // Normalize the current file
+            File pathEntry = new File(elements[i]);
+            pathEntry = fileUtils.normalize(pathEntry.getAbsolutePath());
+            String fullPath = pathEntry.getAbsolutePath();
+
+            // Find the longest prefix shared by the current file
+            // and the reference directory.
+            String relPath = null;
+            for (int j = 0; j <= maxParentLevels; ++j) {
+                String dir = dirs[j];
+                if (!fullPath.startsWith(dir)) {
+                    continue;
+                }
+
+                // We have a match! Add as many ../ as parent
+                // directory traversed to get the relative path
+                element.setLength(0);
+                for (int k = 0; k < j; ++k) {
+                    element.append("..");
+                    element.append(File.separatorChar);
+                }
+                element.append(fullPath.substring(dir.length()));
+                relPath = element.toString();
+                break;
+            }
+
+            // No match, so bail out!
+            if (relPath == null) {
+                throw new BuildException(
+                    "No suitable relative path from "
+                    + dir + " to " + fullPath);
+            }
+
+            // Manifest's ClassPath: attribute always uses forward
+            // slashes '/', and is space-separated. Ant will properly
+            // format it on 72 columns with proper line continuation
+            if (File.separatorChar != '/') {
+                relPath = relPath.replace(File.separatorChar, '/');
+            }
+            if (pathEntry.isDirectory()) {
+                relPath = relPath + '/';
+            }
+            try {
+                relPath = Locator.encodeURI(relPath);
+            } catch (UnsupportedEncodingException exc) {
+                throw new BuildException(exc);
+            }
+            buffer.append(relPath);
+            buffer.append(' ');
+        }
+
+        // Finally assign the property with the manifest classpath
+        getProject().setNewProperty(name, buffer.toString().trim());
+    }
+
+    /**
+     * Sets the property name to hold the classpath value.
+     *
+     * @param  name the property name
+     */
+    public void setProperty(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The JAR file to contain the classpath attribute in its manifest.
+     *
+     * @param  jarfile the JAR file. Need not exist yet, but its parent
+     *         directory must exist on the other hand.
+     */
+    public void setJarFile(File jarfile) {
+        File parent = jarfile.getParentFile();
+        if (!parent.isDirectory()) {
+            throw new BuildException("Jar's directory not found: " + parent);
+        }
+        this.dir = parent;
+    }
+
+    /**
+     * Sets the maximum parent directory levels allowed when computing
+     * a relative path.
+     *
+     * @param  levels the max level. Defaults to 2.
+     */
+    public void setMaxParentLevels(int levels) {
+        this.maxParentLevels = levels;
+    }
+
+    /**
+     * Adds the classpath to convert.
+     *
+     * @param  path the classpath to convert.
+     */
+    public void addClassPath(Path path) {
+        this.path = path;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestException.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestException.java
new file mode 100644
index 0000000..c4e7213
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestException.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Exception thrown indicating problems in a JAR Manifest
+ *
+ * @since Ant 1.4
+ */
+public class ManifestException extends Exception {
+
+    private static final long serialVersionUID = 7685634200457515207L;
+
+    /**
+     * Constructs an exception with the given descriptive message.
+     * @param msg Description of or information about the exception.
+     */
+    public ManifestException(String msg) {
+        super(msg);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java
new file mode 100644
index 0000000..9948056
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ManifestTask.java
@@ -0,0 +1,261 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Manifest.Attribute;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Creates a manifest file for inclusion in a JAR, Ant task wrapper
+ * around {@link Manifest Manifest}.  This task can be used to write a
+ * Manifest file, optionally replacing or updating an existing file.
+ *
+ * @since Ant 1.5
+ *
+ * @ant.task category="java"
+ */
+public class ManifestTask extends Task {
+
+    /**
+     * Specifies the valid characters which can be used in attribute names.
+     * {@value}
+     */
+    public static final String VALID_ATTRIBUTE_CHARS =
+        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345679-_";
+
+    /**
+     * Holds the real data.
+     */
+    private Manifest nestedManifest = new Manifest();
+
+    /**
+     * The file to which the manifest should be written when used as a task
+     */
+    private File manifestFile;
+
+    /**
+     * The mode with which the manifest file is written
+     */
+    private Mode mode;
+
+    /**
+     * The encoding of the manifest file
+     */
+    private String encoding;
+
+    /**
+     * Helper class for Manifest's mode attribute.
+     */
+    public static class Mode extends EnumeratedAttribute {
+        /**
+         * Get Allowed values for the mode attribute.
+         *
+         * @return a String array of the allowed values.
+         */
+        public String[] getValues() {
+            return new String[] {"update", "replace"};
+        }
+    }
+
+    /**
+     * Default constructor
+     */
+    public ManifestTask() {
+        mode = new Mode();
+        mode.setValue("replace");
+    }
+
+    /**
+     * Add a section to the manifest
+     *
+     * @param section the manifest section to be added
+     *
+     * @exception ManifestException if the section is not valid.
+     */
+    public void addConfiguredSection(Manifest.Section section)
+         throws ManifestException {
+        Enumeration attributeKeys = section.getAttributeKeys();
+        while (attributeKeys.hasMoreElements()) {
+            Attribute attribute = section.getAttribute(
+                (String) attributeKeys.nextElement());
+            checkAttribute(attribute);
+        }
+        nestedManifest.addConfiguredSection(section);
+    }
+
+    /**
+     * Add an attribute to the manifest - it is added to the main section.
+     *
+     * @param attribute the attribute to be added.
+     *
+     * @exception ManifestException if the attribute is not valid.
+     */
+    public void addConfiguredAttribute(Manifest.Attribute attribute)
+         throws ManifestException {
+        checkAttribute(attribute);
+        nestedManifest.addConfiguredAttribute(attribute);
+    }
+
+    /**
+     * Checks the attribute agains the Jar-specification.
+     *
+     * Jar-Specification <i>"Name-Value pairs and Sections"</i>: <pre>
+     *   name:       alphanum *headerchar
+     *   alphanum:   {A-Z} | {a-z} | {0-9}
+     *   headerchar: alphanum | - | _
+     * </pre>
+     * So the resulting regexp would be <tt>[A-Za-z0-9][A-Za-z0-9-_]*</tt>.
+     *
+     * Because of JDK 1.2 compliance and the possible absence of a
+     * regexp matcher we can not use regexps here. Instead we have to
+     * check each character.
+     *
+     * @param attribute The attribute to check
+     * @throws BuildException if the check fails
+     */
+    private void checkAttribute(Manifest.Attribute attribute) throws BuildException {
+        String name = attribute.getName();
+        char ch = name.charAt(0);
+
+        if (ch == '-' || ch == '_') {
+            throw new BuildException("Manifest attribute names must not start with '" + ch + "'.");
+        }
+
+        for (int i = 0; i < name.length(); i++) {
+            ch = name.charAt(i);
+            if (VALID_ATTRIBUTE_CHARS.indexOf(ch) < 0) {
+                throw new BuildException("Manifest attribute names must not contain '" + ch + "'");
+            }
+        }
+    }
+
+    /**
+     * The name of the manifest file to create/update.
+     * Required if used as a task.
+     * @param f the Manifest file to be written
+     */
+    public void setFile(File f) {
+        manifestFile = f;
+    }
+
+    /**
+     * The encoding to use for reading in an existing manifest file
+     * @param encoding the manifest file encoding.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Update policy: either "update" or "replace"; default is "replace".
+     * @param m the mode value - update or replace.
+     */
+    public void setMode(Mode m) {
+        mode = m;
+    }
+
+    /**
+     * Create or update the Manifest when used as a task.
+     *
+     * @throws BuildException if the manifest cannot be written.
+     */
+    public void execute() throws BuildException {
+        if (manifestFile == null) {
+            throw new BuildException("the file attribute is required");
+        }
+
+        Manifest toWrite = Manifest.getDefaultManifest();
+        Manifest current = null;
+        BuildException error = null;
+
+        if (manifestFile.exists()) {
+            FileInputStream fis = null;
+            InputStreamReader isr = null;
+            try {
+                fis = new FileInputStream(manifestFile);
+                if (encoding == null) {
+                    isr = new InputStreamReader(fis, "UTF-8");
+                } else {
+                    isr = new InputStreamReader(fis, encoding);
+                }
+                current = new Manifest(isr);
+            } catch (ManifestException m) {
+                error = new BuildException("Existing manifest " + manifestFile
+                                           + " is invalid", m, getLocation());
+            } catch (IOException e) {
+                error = new BuildException("Failed to read " + manifestFile,
+                                           e, getLocation());
+            } finally {
+                FileUtils.close(isr);
+            }
+        }
+
+        //look for and print warnings
+        for (Enumeration e = nestedManifest.getWarnings();
+                e.hasMoreElements();) {
+            log("Manifest warning: " + (String) e.nextElement(),
+                    Project.MSG_WARN);
+        }
+        try {
+            if (mode.getValue().equals("update") && manifestFile.exists()) {
+                if (current != null) {
+                    toWrite.merge(current);
+                } else if (error != null) {
+                    throw error;
+                }
+            }
+
+            toWrite.merge(nestedManifest);
+        } catch (ManifestException m) {
+            throw new BuildException("Manifest is invalid", m, getLocation());
+        }
+
+        if (toWrite.equals(current)) {
+            log("Manifest has not changed, do not recreate",
+                Project.MSG_VERBOSE);
+            return;
+        }
+
+        PrintWriter w = null;
+        try {
+            FileOutputStream fos = new FileOutputStream(manifestFile);
+            OutputStreamWriter osw = new OutputStreamWriter(fos, Manifest.JAR_ENCODING);
+            w = new PrintWriter(osw);
+            toWrite.write(w);
+        } catch (IOException e) {
+            throw new BuildException("Failed to write " + manifestFile,
+                                     e, getLocation());
+        } finally {
+            FileUtils.close(w);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java
new file mode 100644
index 0000000..ec4fa6a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/MatchingTask.java
@@ -0,0 +1,445 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.selectors.AndSelector;
+import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
+import org.apache.tools.ant.types.selectors.ContainsSelector;
+import org.apache.tools.ant.types.selectors.DateSelector;
+import org.apache.tools.ant.types.selectors.DependSelector;
+import org.apache.tools.ant.types.selectors.DepthSelector;
+import org.apache.tools.ant.types.selectors.DifferentSelector;
+import org.apache.tools.ant.types.selectors.ExtendSelector;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+import org.apache.tools.ant.types.selectors.MajoritySelector;
+import org.apache.tools.ant.types.selectors.NoneSelector;
+import org.apache.tools.ant.types.selectors.NotSelector;
+import org.apache.tools.ant.types.selectors.OrSelector;
+import org.apache.tools.ant.types.selectors.PresentSelector;
+import org.apache.tools.ant.types.selectors.SelectSelector;
+import org.apache.tools.ant.types.selectors.SelectorContainer;
+import org.apache.tools.ant.types.selectors.SizeSelector;
+import org.apache.tools.ant.types.selectors.TypeSelector;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * This is an abstract task that should be used by all those tasks that
+ * require to include or exclude files based on pattern matching.
+ *
+ * @since Ant 1.1
+ */
+
+public abstract class MatchingTask extends Task implements SelectorContainer {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected FileSet fileset = new FileSet();
+    // CheckStyle:VisibilityModifier ON
+
+    /** {@inheritDoc}. */
+    public void setProject(Project project) {
+        super.setProject(project);
+        fileset.setProject(project);
+    }
+
+    /**
+     * add a name entry on the include list
+     * @return a NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createInclude() {
+        return fileset.createInclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createIncludesFile() {
+        return fileset.createIncludesFile();
+    }
+
+    /**
+     * add a name entry on the exclude list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createExclude() {
+        return fileset.createExclude();
+    }
+
+    /**
+     * add a name entry on the include files list
+     * @return an NameEntry object to be configured
+     */
+    public PatternSet.NameEntry createExcludesFile() {
+        return fileset.createExcludesFile();
+    }
+
+    /**
+     * add a set of patterns
+     * @return PatternSet object to be configured
+     */
+    public PatternSet createPatternSet() {
+        return fileset.createPatternSet();
+    }
+
+    /**
+     * Sets the set of include patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param includes the string containing the include patterns
+     */
+    public void setIncludes(String includes) {
+        fileset.setIncludes(includes);
+    }
+
+    // CheckStyle:MethodNameCheck OFF - bc
+    /**
+     * Set this to be the items in the base directory that you want to be
+     * included. You can also specify "*" for the items (ie: items="*")
+     * and it will include all the items in the base directory.
+     *
+     * @param itemString the string containing the files to include.
+     */
+    public void XsetItems(String itemString) {
+        log("The items attribute is deprecated. "
+            + "Please use the includes attribute.", Project.MSG_WARN);
+        if (itemString == null || itemString.equals("*")
+            || itemString.equals(".")) {
+            createInclude().setName("**");
+        } else {
+            StringTokenizer tok = new StringTokenizer(itemString, ", ");
+            while (tok.hasMoreTokens()) {
+                String pattern = tok.nextToken().trim();
+                if (pattern.length() > 0) {
+                    createInclude().setName(pattern + "/**");
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the set of exclude patterns. Patterns may be separated by a comma
+     * or a space.
+     *
+     * @param excludes the string containing the exclude patterns
+     */
+    public void setExcludes(String excludes) {
+        fileset.setExcludes(excludes);
+    }
+
+    /**
+     * List of filenames and directory names to not include. They should be
+     * either , or " " (space) separated. The ignored files will be logged.
+     *
+     * @param ignoreString the string containing the files to ignore.
+     */
+    public void XsetIgnore(String ignoreString) {
+        log("The ignore attribute is deprecated."
+            + "Please use the excludes attribute.", Project.MSG_WARN);
+        if (ignoreString != null && ignoreString.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(ignoreString, ", ",
+                                                      false);
+            while (tok.hasMoreTokens()) {
+                createExclude().setName("**/" + tok.nextToken().trim() + "/**");
+            }
+        }
+    }
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
+     *                           should be used, "false"|"off"|"no" when they
+     *                           shouldn't be used.
+     */
+    public void setDefaultexcludes(boolean useDefaultExcludes) {
+        fileset.setDefaultexcludes(useDefaultExcludes);
+    }
+
+    /**
+     * Returns the directory scanner needed to access the files to process.
+     * @param baseDir the base directory to use with the fileset
+     * @return a directory scanner
+     */
+    protected DirectoryScanner getDirectoryScanner(File baseDir) {
+        fileset.setDir(baseDir);
+        return fileset.getDirectoryScanner(getProject());
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param includesfile A string containing the filename to fetch
+     * the include patterns from.
+     */
+    public void setIncludesfile(File includesfile) {
+        fileset.setIncludesfile(includesfile);
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param excludesfile A string containing the filename to fetch
+     * the include patterns from.
+     */
+    public void setExcludesfile(File excludesfile) {
+        fileset.setExcludesfile(excludesfile);
+    }
+
+    /**
+     * Sets case sensitivity of the file system
+     *
+     * @param isCaseSensitive "true"|"on"|"yes" if file system is case
+     *                           sensitive, "false"|"off"|"no" when not.
+     */
+    public void setCaseSensitive(boolean isCaseSensitive) {
+        fileset.setCaseSensitive(isCaseSensitive);
+    }
+
+    /**
+     * Sets whether or not symbolic links should be followed.
+     *
+     * @param followSymlinks whether or not symbolic links should be followed
+     */
+    public void setFollowSymlinks(boolean followSymlinks) {
+        fileset.setFollowSymlinks(followSymlinks);
+    }
+
+    /**
+     * Indicates whether there are any selectors here.
+     *
+     * @return whether any selectors are in this container
+     */
+    public boolean hasSelectors() {
+        return fileset.hasSelectors();
+    }
+
+    /**
+     * Gives the count of the number of selectors in this container
+     *
+     * @return the number of selectors in this container
+     */
+    public int selectorCount() {
+        return fileset.selectorCount();
+    }
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return an array of selectors in this container
+     */
+    public FileSelector[] getSelectors(Project p) {
+        return fileset.getSelectors(p);
+    }
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     *
+     * @return an enumerator that goes through each of the selectors
+     */
+    public Enumeration selectorElements() {
+        return fileset.selectorElements();
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new selector to add
+     */
+    public void appendSelector(FileSelector selector) {
+        fileset.appendSelector(selector);
+    }
+
+    /* Methods below all add specific selectors */
+
+    /**
+     * add a "Select" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSelector(SelectSelector selector) {
+        fileset.addSelector(selector);
+    }
+
+    /**
+     * add an "And" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addAnd(AndSelector selector) {
+        fileset.addAnd(selector);
+    }
+
+    /**
+     * add an "Or" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addOr(OrSelector selector) {
+        fileset.addOr(selector);
+    }
+
+    /**
+     * add a "Not" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNot(NotSelector selector) {
+        fileset.addNot(selector);
+    }
+
+    /**
+     * add a "None" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNone(NoneSelector selector) {
+        fileset.addNone(selector);
+    }
+
+    /**
+     * add a majority selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addMajority(MajoritySelector selector) {
+        fileset.addMajority(selector);
+    }
+
+    /**
+     * add a selector date entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDate(DateSelector selector) {
+        fileset.addDate(selector);
+    }
+
+    /**
+     * add a selector size entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSize(SizeSelector selector) {
+        fileset.addSize(selector);
+    }
+
+    /**
+     * add a selector filename entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addFilename(FilenameSelector selector) {
+        fileset.addFilename(selector);
+    }
+
+    /**
+     * add an extended selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addCustom(ExtendSelector selector) {
+        fileset.addCustom(selector);
+    }
+
+    /**
+     * add a contains selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContains(ContainsSelector selector) {
+        fileset.addContains(selector);
+    }
+
+    /**
+     * add a present selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addPresent(PresentSelector selector) {
+        fileset.addPresent(selector);
+    }
+
+    /**
+     * add a depth selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepth(DepthSelector selector) {
+        fileset.addDepth(selector);
+    }
+
+    /**
+     * add a depends selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepend(DependSelector selector) {
+        fileset.addDepend(selector);
+    }
+
+    /**
+     * add a regular expression selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContainsRegexp(ContainsRegexpSelector selector) {
+        fileset.addContainsRegexp(selector);
+    }
+
+    /**
+     * add a type selector entry on the type list
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addDifferent(DifferentSelector selector) {
+        fileset.addDifferent(selector);
+    }
+
+    /**
+     * add a type selector entry on the type list
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addType(TypeSelector selector) {
+        fileset.addType(selector);
+    }
+
+    /**
+     * add the modified selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addModified(ModifiedSelector selector) {
+        fileset.addModified(selector);
+    }
+
+    /**
+     * add an arbitary selector
+     * @param selector the selector to add
+     * @since Ant 1.6
+     */
+    public void add(FileSelector selector) {
+        fileset.add(selector);
+    }
+
+    /**
+     * Accessor for the implicit fileset.
+     * @return the implicit fileset
+     * @since Ant 1.5.2
+     */
+    protected final FileSet getImplicitFileSet() {
+        return fileset;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Mkdir.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Mkdir.java
new file mode 100644
index 0000000..6b0fe38
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Mkdir.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+
+/**
+ * Creates a given directory.
+ * Creates a directory and any non-existent parent directories, when
+ * necessary
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+
+public class Mkdir extends Task {
+
+    private static final int MKDIR_RETRY_SLEEP_MILLIS = 10;
+    /**
+     * our little directory
+     */
+    private File dir;
+
+    /**
+     * create the directory and all parents
+     * @throws BuildException if dir is somehow invalid, or creation failed.
+     */
+    public void execute() throws BuildException {
+        if (dir == null) {
+            throw new BuildException("dir attribute is required", getLocation());
+        }
+
+        if (dir.isFile()) {
+            throw new BuildException("Unable to create directory as a file "
+                                     + "already exists with that name: "
+                                     + dir.getAbsolutePath());
+        }
+
+        if (!dir.exists()) {
+            boolean result = mkdirs(dir);
+            if (!result) {
+                String msg = "Directory " + dir.getAbsolutePath()
+                    + " creation was not successful for an unknown reason";
+                throw new BuildException(msg, getLocation());
+            }
+            log("Created dir: " + dir.getAbsolutePath());
+        } else {
+            log("Skipping " + dir.getAbsolutePath()
+                + " because it already exists.", Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * the directory to create; required.
+     *
+     * @param dir the directory to be made.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+    /**
+     * Attempt to fix possible race condition when creating
+     * directories on WinXP. If the mkdirs does not work,
+     * wait a little and try again.
+     */
+    private boolean mkdirs(File f) {
+        if (!f.mkdirs()) {
+            try {
+                Thread.sleep(MKDIR_RETRY_SLEEP_MILLIS);
+                return f.mkdirs();
+            } catch (InterruptedException ex) {
+                return f.mkdirs();
+            }
+        }
+        return true;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Move.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Move.java
new file mode 100644
index 0000000..30d6d01
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Move.java
@@ -0,0 +1,349 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+
+/**
+ * Moves a file or directory to a new file or directory.
+ * By default, the
+ * destination file is overwritten if it already exists.
+ * When <i>overwrite</i> is
+ * turned off, then files are only moved if the source file is
+ * newer than the destination file, or when the destination file does
+ * not exist.
+ *
+ * <p>Source files and directories are only deleted when the file or
+ * directory has been copied to the destination successfully.  Filtering
+ * also works.</p>
+ *
+ * <p>This implementation is based on Arnout Kuiper's initial design
+ * document, the following mailing list discussions, and the
+ * copyfile/copydir tasks.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="filesystem"
+ */
+public class Move extends Copy {
+
+    /**
+     * Constructor of object.
+     * This sets the forceOverwrite attribute of the Copy parent class
+     * to true.
+     *
+     */
+    public Move() {
+        super();
+        setOverwrite(true);
+    }
+
+    /** {@inheritDoc}. */
+    protected void validateAttributes() throws BuildException {
+        if (file != null && file.isDirectory()) {
+            if ((destFile != null && destDir != null)
+                || (destFile == null && destDir == null)) {
+                throw new BuildException("One and only one of tofile and todir must be set.");
+            }
+            destFile = destFile == null ? new File(destDir, file.getName()) : destFile;
+            destDir = destDir == null ? destFile.getParentFile() : destDir;
+
+            completeDirMap.put(file, destFile);
+            file = null;
+        } else {
+            super.validateAttributes();
+        }
+    }
+
+//************************************************************************
+//  protected and private methods
+//************************************************************************
+
+    /**
+     * Override copy's doFileOperations to move the files instead of copying them.
+     */
+    protected void doFileOperations() {
+        //Attempt complete directory renames, if any, first.
+        if (completeDirMap.size() > 0) {
+            for (Iterator fromDirs = completeDirMap.keySet().iterator(); fromDirs.hasNext();) {
+                File fromDir = (File) fromDirs.next();
+                File toDir = (File) completeDirMap.get(fromDir);
+                boolean renamed = false;
+                try {
+                    log("Attempting to rename dir: " + fromDir + " to " + toDir, verbosity);
+                    renamed = renameFile(fromDir, toDir, filtering, forceOverwrite);
+                } catch (IOException ioe) {
+                    String msg = "Failed to rename dir " + fromDir
+                            + " to " + toDir + " due to " + ioe.getMessage();
+                    throw new BuildException(msg, ioe, getLocation());
+                }
+                if (!renamed) {
+                    FileSet fs = new FileSet();
+                    fs.setProject(getProject());
+                    fs.setDir(fromDir);
+                    addFileset(fs);
+                    DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+                    String[] files = ds.getIncludedFiles();
+                    String[] dirs = ds.getIncludedDirectories();
+                    scan(fromDir, toDir, files, dirs);
+                }
+            }
+        }
+        int moveCount = fileCopyMap.size();
+        if (moveCount > 0) {   // files to move
+            log("Moving " + moveCount + " file" + ((moveCount == 1) ? "" : "s")
+                    + " to " + destDir.getAbsolutePath());
+
+            for (Iterator fromFiles = fileCopyMap.keySet().iterator(); fromFiles.hasNext();) {
+                String fromFile = (String) fromFiles.next();
+                File f = new File(fromFile);
+                boolean selfMove = false;
+                if (f.exists()) { //Is this file still available to be moved?
+                    String[] toFiles = (String[]) fileCopyMap.get(fromFile);
+                    for (int i = 0; i < toFiles.length; i++) {
+                        String toFile = (String) toFiles[i];
+
+                        if (fromFile.equals(toFile)) {
+                            log("Skipping self-move of " + fromFile, verbosity);
+                            selfMove = true;
+
+                            // if this is the last time through the loop then
+                            // move will not occur, but that's what we want
+                            continue;
+                        }
+                        File d = new File(toFile);
+                        if ((i + 1) == toFiles.length && !selfMove) {
+                            // Only try to move if this is the last mapped file
+                            // and one of the mappings isn't to itself
+                            moveFile(f, d, filtering, forceOverwrite);
+                        } else {
+                            copyFile(f, d, filtering, forceOverwrite);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (includeEmpty) {
+            int createCount = 0;
+            for (Iterator fromDirNames = dirCopyMap.keySet().iterator(); fromDirNames.hasNext();) {
+                String fromDirName = (String) fromDirNames.next();
+                String[] toDirNames = (String[]) dirCopyMap.get(fromDirName);
+                boolean selfMove = false;
+                for (int i = 0; i < toDirNames.length; i++) {
+                    if (fromDirName.equals(toDirNames[i])) {
+                        log("Skipping self-move of " + fromDirName, verbosity);
+                        selfMove = true;
+                        continue;
+                    }
+                    File d = new File(toDirNames[i]);
+                    if (!d.exists()) {
+                        if (!d.mkdirs()) {
+                            log("Unable to create directory "
+                                    + d.getAbsolutePath(), Project.MSG_ERR);
+                        } else {
+                            createCount++;
+                        }
+                    }
+                }
+                File fromDir = new File(fromDirName);
+                if (!selfMove && okToDelete(fromDir)) {
+                    deleteDir(fromDir);
+                }
+            }
+            if (createCount > 0) {
+                log("Moved " + dirCopyMap.size()
+                        + " empty director"
+                        + (dirCopyMap.size() == 1 ? "y" : "ies")
+                        + " to " + createCount
+                        + " empty director"
+                        + (createCount == 1 ? "y" : "ies") + " under "
+                        + destDir.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Try to move the file via a rename, but if this fails or filtering
+     * is enabled, copy the file then delete the sourceFile.
+     */
+    private void moveFile(File fromFile, File toFile, boolean filtering, boolean overwrite) {
+        boolean moved = false;
+        try {
+            log("Attempting to rename: " + fromFile + " to " + toFile, verbosity);
+            moved = renameFile(fromFile, toFile, filtering, forceOverwrite);
+        } catch (IOException ioe) {
+            String msg = "Failed to rename " + fromFile
+                + " to " + toFile + " due to " + ioe.getMessage();
+            throw new BuildException(msg, ioe, getLocation());
+        }
+
+        if (!moved) {
+            copyFile(fromFile, toFile, filtering, overwrite);
+            if (!fromFile.delete()) {
+                throw new BuildException("Unable to delete " + "file "
+                        + fromFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Copy fromFile to toFile.
+     * @param fromFile
+     * @param toFile
+     * @param filtering
+     * @param overwrite
+     */
+    private void copyFile(File fromFile, File toFile, boolean filtering, boolean overwrite) {
+        try {
+            log("Copying " + fromFile + " to " + toFile, verbosity);
+
+            FilterSetCollection executionFilters = new FilterSetCollection();
+            if (filtering) {
+                executionFilters.addFilterSet(getProject().getGlobalFilterSet());
+            }
+            for (Iterator filterIter = getFilterSets().iterator(); filterIter.hasNext();) {
+                executionFilters.addFilterSet((FilterSet) filterIter.next());
+            }
+            getFileUtils().copyFile(fromFile, toFile, executionFilters,
+                                    getFilterChains(),
+                                    forceOverwrite,
+                                    getPreserveLastModified(),
+                                    getEncoding(),
+                                    getOutputEncoding(),
+                                    getProject());
+        } catch (IOException ioe) {
+            String msg = "Failed to copy " + fromFile
+                    + " to " + toFile + " due to " + ioe.getMessage();
+            throw new BuildException(msg, ioe, getLocation());
+        }
+    }
+
+    /**
+     * Its only ok to delete a directory tree if there are no files in it.
+     * @param d the directory to check
+     * @return true if a deletion can go ahead
+     */
+    protected boolean okToDelete(File d) {
+        String[] list = d.list();
+        if (list == null) {
+            return false;
+        }     // maybe io error?
+
+        for (int i = 0; i < list.length; i++) {
+            String s = list[i];
+            File f = new File(d, s);
+            if (f.isDirectory()) {
+                if (!okToDelete(f)) {
+                    return false;
+                }
+            } else {
+                return false;   // found a file
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Go and delete the directory tree.
+     * @param d the directory to delete
+     */
+    protected void deleteDir(File d) {
+        deleteDir(d, false);
+    }
+
+    /**
+     * Go and delete the directory tree.
+     * @param d the directory to delete
+     * @param deleteFiles whether to delete files
+     */
+    protected void deleteDir(File d, boolean deleteFiles) {
+        String[] list = d.list();
+        if (list == null) {
+            return;
+        }      // on an io error list() can return null
+
+        for (int i = 0; i < list.length; i++) {
+            String s = list[i];
+            File f = new File(d, s);
+            if (f.isDirectory()) {
+                deleteDir(f);
+            } else if (deleteFiles && !(f.delete())) {
+                throw new BuildException("Unable to delete file " + f.getAbsolutePath());
+            } else {
+                throw new BuildException("UNEXPECTED ERROR - The file "
+                        + f.getAbsolutePath() + " should not exist!");
+            }
+        }
+        log("Deleting directory " + d.getAbsolutePath(), verbosity);
+        if (!d.delete()) {
+            throw new BuildException("Unable to delete directory " + d.getAbsolutePath());
+        }
+    }
+
+    /**
+     * Attempts to rename a file from a source to a destination.
+     * If overwrite is set to true, this method overwrites existing file
+     * even if the destination file is newer.  Otherwise, the source file is
+     * renamed only if the destination file is older than it.
+     * Method then checks if token filtering is used.  If it is, this method
+     * returns false assuming it is the responsibility to the copyFile method.
+     *
+     * @param sourceFile the file to rename
+     * @param destFile   the destination file
+     * @param filtering  if true, filtering is in operation, file will
+     *                   be copied/deleted instead of renamed
+     * @param overwrite  if true force overwrite even if destination file
+     *                   is newer than source file
+     * @return true if the file was renamed
+     * @exception IOException if an error occurs
+     * @exception BuildException if an error occurs
+     */
+    protected boolean renameFile(File sourceFile, File destFile, boolean filtering,
+                                 boolean overwrite) throws IOException, BuildException {
+        if (destFile.isDirectory() || filtering || getFilterSets().size() > 0
+                || getFilterChains().size() > 0) {
+            return false;
+        }
+        // identical logic lives in FileUtils.rename():
+        File parent = destFile.getParentFile();
+        if (parent != null && !parent.exists()) {
+            parent.mkdirs();
+        } else if (destFile.isFile()) {
+            sourceFile = getFileUtils().normalize(sourceFile.getAbsolutePath()).getCanonicalFile();
+            destFile = getFileUtils().normalize(destFile.getAbsolutePath());
+            if (destFile.equals(sourceFile)) {
+                //no point in renaming a file to its own canonical version...
+                return true;
+            }
+            if (!(sourceFile.equals(destFile.getCanonicalFile()) || destFile.delete())) {
+                throw new BuildException("Unable to remove existing file " + destFile);
+            }
+        }
+        return sourceFile.renameTo(destFile);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Nice.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Nice.java
new file mode 100644
index 0000000..265a3e3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Nice.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * A task to provide "nice-ness" to the current thread, and/or to
+ * query the current value.
+ * Examples:
+ * <pre> &lt;nice currentPriority="current.value" &gt;</pre><p>
+ * Set <code>currentPriority</code> to the current priority
+ * <pre> &lt;nice newPriority="10" &gt;</pre><p>
+ * Raise the priority of the build process (But not forked programs)
+ * <pre> &lt;nice currentPriority="old" newPriority="3" &gt;</pre><p>
+ * Lower the priority of the build process (But not forked programs), and save
+ * the old value to the property <code>old</code>.
+ *
+ * @ant.task name="nice" category="control"
+ */
+public class Nice extends Task {
+
+    /**
+     * the new priority
+     */
+    private Integer newPriority;
+
+    /**
+     * the current priority
+     */
+    private String currentPriority;
+
+
+
+    /**
+     * Execute the task
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+
+        Thread self = Thread.currentThread();
+        int priority = self.getPriority();
+        if (currentPriority != null) {
+            String current = Integer.toString(priority);
+            getProject().setNewProperty(currentPriority, current);
+        }
+        //if there is a new priority, and it is different, change it
+        if (newPriority != null && priority != newPriority.intValue()) {
+            try {
+                self.setPriority(newPriority.intValue());
+            } catch (SecurityException e) {
+                //catch permissions denial and keep going
+                log("Unable to set new priority -a security manager is in the way",
+                        Project.MSG_WARN);
+            } catch (IllegalArgumentException iae) {
+                throw new BuildException("Priority out of range", iae);
+            }
+        }
+    }
+
+    /**
+     * The name of a property to set to the value of the current
+     * thread priority. Optional
+     * @param currentPriority the property name.
+     */
+    public void setCurrentPriority(String currentPriority) {
+        this.currentPriority = currentPriority;
+    }
+
+    /**
+     * the new priority, in the range 1-10.
+     * @param newPriority the new priority value.
+     */
+    public void setNewPriority(int newPriority) {
+        if (newPriority < Thread.MIN_PRIORITY || newPriority > Thread.MAX_PRIORITY) {
+            throw new BuildException("The thread priority is out of the range 1-10");
+        }
+        this.newPriority = new Integer(newPriority);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Pack.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Pack.java
new file mode 100644
index 0000000..7735666
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Pack.java
@@ -0,0 +1,210 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * Abstract Base class for pack tasks.
+ *
+ * @since Ant 1.5
+ */
+
+public abstract class Pack extends Task {
+    private static final int BUFFER_SIZE = 8 * 1024;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected File zipFile;
+    protected File source;
+    // CheckStyle:VisibilityModifier ON
+    private Resource src;
+
+    /**
+     * the required destination file.
+     * @param zipFile the destination file
+     */
+    public void setZipfile(File zipFile) {
+        this.zipFile = zipFile;
+    }
+
+    /**
+     * the required destination file.
+     * @param zipFile the destination file
+     */
+    public void setDestfile(File zipFile) {
+        setZipfile(zipFile);
+    }
+
+    /**
+     * the file to compress; required.
+     * @param src the source file
+     */
+    public void setSrc(File src) {
+        setSrcResource(new FileResource(src));
+    }
+
+    /**
+     * The resource to pack; required.
+     * @param src resource to expand
+     */
+    public void setSrcResource(Resource src) {
+        if (src.isDirectory()) {
+            throw new BuildException("the source can't be a directory");
+        }
+        if (src instanceof FileResource) {
+            source = ((FileResource) src).getFile();
+        } else if (!supportsNonFileResources()) {
+            throw new BuildException("Only FileSystem resources are"
+                                     + " supported.");
+        }
+        this.src = src;
+    }
+
+    /**
+     * Set the source resource.
+     * @param a the resource to pack as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        if (a.size() == 0) {
+            throw new BuildException("No resource selected, " + getTaskName()
+                    + " needs exactly one resource.");
+        }
+        if (a.size() != 1) {
+            throw new BuildException(getTaskName()
+                    + " cannot handle multiple resources at once. (" + a.size()
+                    + " resources were selected.)");
+        }
+        setSrcResource((Resource) a.iterator().next());
+    }
+
+    /**
+     * validation routine
+     * @throws BuildException if anything is invalid
+     */
+    private void validate() throws BuildException {
+        if (zipFile == null) {
+            throw new BuildException("zipfile attribute is required", getLocation());
+        }
+
+        if (zipFile.isDirectory()) {
+            throw new BuildException("zipfile attribute must not "
+                                    + "represent a directory!", getLocation());
+        }
+
+        if (getSrcResource() == null) {
+            throw new BuildException("src attribute or nested resource is"
+                                     + " required", getLocation());
+        }
+    }
+
+    /**
+     * validate, then hand off to the subclass
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        validate();
+
+        Resource s = getSrcResource();
+        if (!s.isExists()) {
+            log("Nothing to do: " + s.toString()
+                + " doesn't exist.");
+        } else if (zipFile.lastModified() < s.getLastModified()) {
+            log("Building: " + zipFile.getAbsolutePath());
+            pack();
+        } else {
+            log("Nothing to do: " + zipFile.getAbsolutePath()
+                + " is up to date.");
+        }
+    }
+
+    /**
+     * zip a stream to an output stream
+     * @param in   the stream to zip
+     * @param zOut the output stream
+     * @throws IOException
+     */
+    private void zipFile(InputStream in, OutputStream zOut)
+        throws IOException {
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int count = 0;
+        do {
+            zOut.write(buffer, 0, count);
+            count = in.read(buffer, 0, buffer.length);
+        } while (count != -1);
+    }
+
+    /**
+     * zip a file to an output stream
+     * @param file the file to zip
+     * @param zOut the output stream
+     * @throws IOException on error
+     */
+    protected void zipFile(File file, OutputStream zOut)
+        throws IOException {
+        zipResource(new FileResource(file), zOut);
+    }
+
+    /**
+     * zip a resource to an output stream
+     * @param resource the resource to zip
+     * @param zOut the output stream
+     * @throws IOException on error
+     */
+    protected void zipResource(Resource resource, OutputStream zOut)
+        throws IOException {
+        InputStream rIn = resource.getInputStream();
+        try {
+            zipFile(rIn, zOut);
+        } finally {
+            rIn.close();
+        }
+    }
+
+    /**
+     * subclasses must implement this method to do their compression
+     */
+    protected abstract void pack();
+
+    /**
+     * The source resource.
+     * @return the source.
+     * @since Ant 1.7
+     */
+    public Resource getSrcResource() {
+        return src;
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns false.</p>
+     * @return false.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return false;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Parallel.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Parallel.java
new file mode 100644
index 0000000..9ebdf9c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Parallel.java
@@ -0,0 +1,490 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.List;
+import java.util.ArrayList;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Executes the contained tasks in separate threads, continuing
+ * once all are completed.
+ * <p>
+ * New behavior allows for the ant script to specify a maximum number of
+ * threads that will be executed in parallel.  One should be very careful about
+ * using the <code>waitFor</code> task when specifying <code>threadCount</code>
+ * as it can cause deadlocks if the number of threads is too small or if one of
+ * the nested tasks fails to execute completely.  The task selection algorithm
+ * will insure that the tasks listed before a task have started before that
+ * task is started, but it will not insure a successful completion of those
+ * tasks or that those tasks will finish first (i.e. it's a classic race
+ * condition).
+ * </p>
+ * @since Ant 1.4
+ *
+ * @ant.task category="control"
+ */
+public class Parallel extends Task
+                      implements TaskContainer {
+
+    private static final int NUMBER_TRIES = 100;
+
+    /** Class which holds a list of tasks to execute */
+    public static class TaskList implements TaskContainer {
+        /** Collection holding the nested tasks */
+        private List tasks = new ArrayList();
+
+        /**
+         * Add a nested task to execute parallel (asynchron).
+         * <p>
+         * @param nestedTask  Nested task to be executed in parallel.
+         *                    must not be null.
+         */
+        public void addTask(Task nestedTask) {
+            tasks.add(nestedTask);
+        }
+    }
+
+    /** Collection holding the nested tasks */
+    private Vector nestedTasks = new Vector();
+
+    /** Semaphore to notify of completed threads */
+    private final Object semaphore = new Object();
+
+    /** Total number of threads to run */
+    private int numThreads = 0;
+
+    /** Total number of threads per processor to run.  */
+    private int numThreadsPerProcessor = 0;
+
+    /** The timeout period in milliseconds */
+    private long timeout;
+
+    /** Indicates threads are still running and new threads can be issued */
+    private volatile boolean stillRunning;
+
+    /** Indicates that the execution timedout */
+    private boolean timedOut;
+
+    /**
+     * Indicates whether failure of any of the nested tasks should end
+     * execution
+     */
+    private boolean failOnAny;
+
+    /** The dameon task list if any */
+    private TaskList daemonTasks;
+
+    /** Accumulation of exceptions messages from all nested tasks */
+    private StringBuffer exceptionMessage;
+
+    /** Number of exceptions from nested tasks */
+    private int numExceptions = 0;
+
+    /** The first exception encountered */
+    private Throwable firstException;
+
+    /** The location of the first exception */
+    private Location firstLocation;
+
+    /**
+     * Add a group of daemon threads
+     * @param daemonTasks The tasks to be executed as daemon.
+     */
+    public void addDaemons(TaskList daemonTasks) {
+        if (this.daemonTasks != null) {
+            throw new BuildException("Only one daemon group is supported");
+        }
+        this.daemonTasks = daemonTasks;
+    }
+
+    /**
+     * Interval to poll for completed threads when threadCount or
+     * threadsPerProcessor is specified.  Integer in milliseconds.; optional
+     *
+     * @param pollInterval New value of property pollInterval.
+     */
+    public void setPollInterval(int pollInterval) {
+    }
+
+    /**
+     * Control whether a failure in a nested task halts execution. Note that
+     * the task will complete but existing threads will continue to run - they
+     * are not stopped
+     *
+     * @param failOnAny if true any nested task failure causes parallel to
+     *        complete.
+     */
+    public void setFailOnAny(boolean failOnAny) {
+        this.failOnAny = failOnAny;
+    }
+
+    /**
+     * Add a nested task to execute in parallel.
+     * @param nestedTask  Nested task to be executed in parallel
+     */
+    public void addTask(Task nestedTask) {
+        nestedTasks.addElement(nestedTask);
+    }
+
+    /**
+     * Dynamically generates the number of threads to execute based on the
+     * number of available processors (via
+     * <code>java.lang.Runtime.availableProcessors()</code>). Requires a J2SE
+     * 1.4 VM, and it will overwrite the value set in threadCount.
+     * If used in a 1.1, 1.2, or 1.3 VM then the task will defer to
+     * <code>threadCount</code>.; optional
+     * @param numThreadsPerProcessor Number of threads to create per available
+     *        processor.
+     *
+     */
+    public void setThreadsPerProcessor(int numThreadsPerProcessor) {
+        this.numThreadsPerProcessor = numThreadsPerProcessor;
+    }
+
+    /**
+     * Statically determine the maximum number of tasks to execute
+     * simultaneously.  If there are less tasks than threads then all will be
+     * executed at once, if there are more then only <code>threadCount</code>
+     * tasks will be executed at one time.  If <code>threadsPerProcessor</code>
+     * is set and the JVM is at least a 1.4 VM then this value is
+     * ignored.; optional
+     *
+     * @param numThreads total number of threads.
+     *
+     */
+    public void setThreadCount(int numThreads) {
+        this.numThreads = numThreads;
+    }
+
+    /**
+     * Sets the timeout on this set of tasks. If the timeout is reached
+     * before the other threads complete, the execution of this
+     * task completes with an exception.
+     *
+     * Note that existing threads continue to run.
+     *
+     * @param timeout timeout in milliseconds.
+     */
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+
+
+    /**
+     * Execute the parallel tasks
+     *
+     * @exception BuildException if any of the threads failed.
+     */
+    public void execute() throws BuildException {
+        updateThreadCounts();
+        if (numThreads == 0) {
+            numThreads = nestedTasks.size();
+        }
+        spinThreads();
+    }
+
+    /**
+     * Determine the number of threads based on the number of processors
+     */
+    private void updateThreadCounts() {
+        if (numThreadsPerProcessor != 0) {
+            int numProcessors = getNumProcessors();
+            if (numProcessors != 0) {
+                numThreads = numProcessors * numThreadsPerProcessor;
+            }
+        }
+    }
+
+    private void processExceptions(TaskRunnable[] runnables) {
+        if (runnables == null) {
+            return;
+        }
+        for (int i = 0; i < runnables.length; ++i) {
+            Throwable t = runnables[i].getException();
+            if (t != null) {
+                numExceptions++;
+                if (firstException == null) {
+                    firstException = t;
+                }
+                if (t instanceof BuildException
+                    && firstLocation == Location.UNKNOWN_LOCATION) {
+                    firstLocation = ((BuildException) t).getLocation();
+                }
+                exceptionMessage.append(StringUtils.LINE_SEP);
+                exceptionMessage.append(t.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Spin up required threads with a maximum number active at any given time.
+     *
+     * @exception BuildException if any of the threads failed.
+     */
+    private void spinThreads() throws BuildException {
+        final int numTasks = nestedTasks.size();
+        TaskRunnable[] runnables = new TaskRunnable[numTasks];
+        stillRunning = true;
+        timedOut = false;
+        boolean interrupted = false;
+
+        int threadNumber = 0;
+        for (Enumeration e = nestedTasks.elements(); e.hasMoreElements();
+             threadNumber++) {
+            Task nestedTask = (Task) e.nextElement();
+            runnables[threadNumber]
+                = new TaskRunnable(nestedTask);
+        }
+
+        final int maxRunning = numTasks < numThreads ? numTasks : numThreads;
+        TaskRunnable[] running = new TaskRunnable[maxRunning];
+
+        threadNumber = 0;
+        ThreadGroup group = new ThreadGroup("parallel");
+
+        TaskRunnable[] daemons = null;
+        if (daemonTasks != null && daemonTasks.tasks.size() != 0) {
+            daemons = new TaskRunnable[daemonTasks.tasks.size()];
+        }
+
+        synchronized (semaphore) {
+            // When we leave this block we can be sure all data is really
+            // stored in main memory before the new threads start, the new
+            // threads will for sure load the data from main memory.
+            //
+            // This probably is slightly paranoid.
+        }
+
+        synchronized (semaphore) {
+            // start any daemon threads
+            if (daemons != null) {
+                for (int i = 0; i < daemons.length; ++i) {
+                    daemons[i] = new TaskRunnable((Task) daemonTasks.tasks.get(i));
+                    Thread daemonThread =  new Thread(group, daemons[i]);
+                    daemonThread.setDaemon(true);
+                    daemonThread.start();
+                }
+            }
+
+            // now run main threads in limited numbers...
+            // start initial batch of threads
+            for (int i = 0; i < maxRunning; ++i) {
+                running[i] = runnables[threadNumber++];
+                Thread thread =  new Thread(group, running[i]);
+                thread.start();
+            }
+
+            if (timeout != 0) {
+                // start the timeout thread
+                Thread timeoutThread = new Thread() {
+                    public synchronized void run() {
+                        try {
+                            wait(timeout);
+                            synchronized (semaphore) {
+                                stillRunning = false;
+                                timedOut = true;
+                                semaphore.notifyAll();
+                            }
+                        } catch (InterruptedException e) {
+                            // ignore
+                        }
+                    }
+                };
+                timeoutThread.start();
+            }
+
+            try {
+                // now find available running slots for the remaining threads
+                outer: while (threadNumber < numTasks && stillRunning) {
+                    for (int i = 0; i < maxRunning; i++) {
+                        if (running[i] == null || running[i].isFinished()) {
+                            running[i] = runnables[threadNumber++];
+                            Thread thread = new Thread(group, running[i]);
+                            thread.start();
+                            // continue on outer while loop to get another
+                            // available slot
+                            continue outer;
+                        }
+                    }
+
+                    // if we got here all slots in use, so sleep until
+                    // something happens
+                    semaphore.wait();
+                }
+
+                // are all threads finished
+                outer2: while (stillRunning) {
+                    for (int i = 0; i < maxRunning; ++i) {
+                        if (running[i] != null && !running[i].isFinished()) {
+                            // System.out.println("Thread " + i + " is still
+                            // alive ");
+                            // still running - wait for it
+                            semaphore.wait();
+                            continue outer2;
+                        }
+                    }
+                    stillRunning = false;
+                }
+            } catch (InterruptedException ie) {
+                interrupted = true;
+            }
+
+            killAll(running);
+        }
+
+        if (interrupted) {
+            throw new BuildException("Parallel execution interrupted.");
+        }
+        if (timedOut) {
+            throw new BuildException("Parallel execution timed out");
+        }
+
+        // now did any of the threads throw an exception
+        exceptionMessage = new StringBuffer();
+        numExceptions = 0;
+        firstException = null;
+        firstLocation = Location.UNKNOWN_LOCATION;
+        processExceptions(daemons);
+        processExceptions(runnables);
+
+        if (numExceptions == 1) {
+            if (firstException instanceof BuildException) {
+                throw (BuildException) firstException;
+            } else {
+                throw new BuildException(firstException);
+            }
+        } else if (numExceptions > 1) {
+            throw new BuildException(exceptionMessage.toString(),
+                                     firstLocation);
+        }
+    }
+
+    /**
+     * Doesn't do anything if all threads where already gone,
+     * else it tries to interrupt the threads 100 times.
+     * @param running The list of tasks that may currently be running.
+     */
+    private void killAll(TaskRunnable[] running) {
+        boolean oneAlive;
+        int tries = 0;
+        do {
+            oneAlive = false;
+            for (int i = 0; i < running.length; i++) {
+                if (running[i] != null && !running[i].isFinished()) {
+                    running[i].interrupt();
+                    Thread.yield();
+                    oneAlive = true;
+                }
+            }
+            if (oneAlive) {
+                tries++;
+                Thread.yield();
+            }
+        } while (oneAlive && tries < NUMBER_TRIES);
+    }
+
+    /**
+     * Determine the number of processors. Only effective on Java 1.4+
+     *
+     * @return the number of processors available or 0 if not determinable.
+     */
+    private int getNumProcessors() {
+        try {
+            Class[] paramTypes = {};
+            Method availableProcessors =
+                Runtime.class.getMethod("availableProcessors", paramTypes);
+
+            Object[] args = {};
+            Integer ret = (Integer) availableProcessors.invoke(Runtime.getRuntime(), args);
+            return ret.intValue();
+        } catch (Exception e) {
+            // return a bogus number
+            return 0;
+        }
+    }
+
+    /**
+     * thread that execs a task
+     */
+    private class TaskRunnable implements Runnable {
+        private Throwable exception;
+        private Task task;
+        private boolean finished;
+        private volatile Thread thread;
+
+        /**
+         * Construct a new TaskRunnable.<p>
+         *
+         * @param task the Task to be executed in a separate thread
+         */
+        TaskRunnable(Task task) {
+            this.task = task;
+        }
+
+        /**
+         * Executes the task within a thread and takes care about
+         * Exceptions raised within the task.
+         */
+        public void run() {
+            try {
+                thread = Thread.currentThread();
+                task.perform();
+            } catch (Throwable t) {
+                exception = t;
+                if (failOnAny) {
+                    stillRunning = false;
+                }
+            } finally {
+                synchronized (semaphore) {
+                    finished = true;
+                    semaphore.notifyAll();
+                }
+            }
+        }
+
+        /**
+         * get any exception that got thrown during execution;
+         * @return an exception or null for no exception/not yet finished
+         */
+        public Throwable getException() {
+            return exception;
+        }
+
+        /**
+         * Provides the indicator that the task has been finished.
+         * @return Returns true when the task is finished.
+         */
+        boolean isFinished() {
+            return finished;
+        }
+
+        void interrupt() {
+            thread.interrupt();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Patch.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Patch.java
new file mode 100644
index 0000000..47fc116
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Patch.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Patches a file by applying a 'diff' file to it; requires "patch" to be
+ * on the execution path.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="utility"
+ */
+public class Patch extends Task {
+
+    private File originalFile;
+    private File directory;
+    private boolean havePatchfile = false;
+    private Commandline cmd = new Commandline();
+
+    /**
+     * The file to patch; optional if it can be inferred from
+     * the diff file
+     * @param file the file to patch
+     */
+    public void setOriginalfile(File file) {
+        originalFile = file;
+    }
+
+    /**
+     * The name of a file to send the output to, instead of patching
+     * the file(s) in place; optional.
+     * @param file the file to send the output to
+     * @since Ant 1.6
+     */
+    public void setDestfile(File file) {
+        if (file != null) {
+            cmd.createArgument().setValue("-o");
+            cmd.createArgument().setFile(file);
+        }
+    }
+
+    /**
+     * The file containing the diff output; required.
+     * @param file the file containing the diff output
+     */
+    public void setPatchfile(File file) {
+        if (!file.exists()) {
+            throw new BuildException("patchfile " + file + " doesn\'t exist",
+                                     getLocation());
+        }
+        cmd.createArgument().setValue("-i");
+        cmd.createArgument().setFile(file);
+        havePatchfile = true;
+    }
+
+    /**
+     * flag to create backups; optional, default=false
+     * @param backups if true create backups
+     */
+    public void setBackups(boolean backups) {
+        if (backups) {
+            cmd.createArgument().setValue("-b");
+        }
+    }
+
+    /**
+     * flag to ignore whitespace differences; default=false
+     * @param ignore if true ignore whitespace differences
+     */
+    public void setIgnorewhitespace(boolean ignore) {
+        if (ignore) {
+            cmd.createArgument().setValue("-l");
+        }
+    }
+
+    /**
+     * Strip the smallest prefix containing <i>num</i> leading slashes
+     * from filenames.
+     *
+     * <p>patch's <i>-p</i> option.
+     * @param num number of lines to strip
+     * @exception BuildException if num is < 0, or other errors
+     */
+    public void setStrip(int num) throws BuildException {
+        if (num < 0) {
+            throw new BuildException("strip has to be >= 0", getLocation());
+        }
+        cmd.createArgument().setValue("-p" + num);
+    }
+
+    /**
+     * Work silently unless an error occurs; optional, default=false
+     * @param q if true suppress set the -s option on the patch command
+     */
+    public void setQuiet(boolean q) {
+        if (q) {
+            cmd.createArgument().setValue("-s");
+        }
+    }
+
+    /**
+     * Assume patch was created with old and new files swapped; optional,
+     * default=false
+     * @param r if true set the -R option on the patch command
+     */
+    public void setReverse(boolean r) {
+        if (r) {
+            cmd.createArgument().setValue("-R");
+        }
+    }
+
+    /**
+     * The directory to run the patch command in, defaults to the
+     * project's base directory.
+     * @param directory the directory to run the patch command in
+     * @since Ant 1.5
+     */
+    public void setDir(File directory) {
+        this.directory = directory;
+    }
+
+    /**
+     * execute patch
+     * @throws BuildException when it all goes a bit pear shaped
+     */
+    public void execute() throws BuildException {
+        if (!havePatchfile) {
+            throw new BuildException("patchfile argument is required",
+                                     getLocation());
+        }
+        Commandline toExecute = (Commandline) cmd.clone();
+        toExecute.setExecutable("patch");
+
+        if (originalFile != null) {
+            toExecute.createArgument().setFile(originalFile);
+        }
+
+        Execute exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
+                                                       Project.MSG_WARN),
+                                  null);
+        exe.setCommandline(toExecute.getCommandline());
+
+        if (directory != null) {
+            if (directory.exists() && directory.isDirectory()) {
+                exe.setWorkingDirectory(directory);
+            } else if (!directory.isDirectory()) {
+                throw new BuildException(directory + " is not a directory.",
+                                         getLocation());
+            } else {
+                throw new BuildException("directory " + directory
+                                         + " doesn\'t exist", getLocation());
+            }
+        } else {
+            exe.setWorkingDirectory(getProject().getBaseDir());
+        }
+
+        log(toExecute.describeCommand(), Project.MSG_VERBOSE);
+        try {
+            exe.execute();
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/PathConvert.java b/trunk/src/main/org/apache/tools/ant/taskdefs/PathConvert.java
new file mode 100644
index 0000000..2a229bc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/PathConvert.java
@@ -0,0 +1,487 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.List;
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileNameMapper;
+
+/**
+ * Converts path and classpath information to a specific target OS
+ * format. The resulting formatted path is placed into the specified property.
+ *
+ * @since Ant 1.4
+ * @ant.task category="utility"
+ */
+public class PathConvert extends Task {
+
+    /**
+     * Set if we're running on windows
+     */
+    private static boolean onWindows = Os.isFamily("dos");
+
+    // Members
+    /**
+     * Path to be converted
+     */
+    private Union path = null;
+    /**
+     * Reference to path/fileset to convert
+     */
+    private Reference refid = null;
+    /**
+     * The target OS type
+     */
+    private String targetOS = null;
+    /**
+     * Set when targetOS is set to windows
+     */
+    private boolean targetWindows = false;
+    /**
+     * Set if we should create a new property even if the result is empty
+     */
+    private boolean setonempty = true;
+    /**
+     * The property to receive the conversion
+     */
+    private String property = null;
+    /**
+     * Path prefix map
+     */
+    private Vector prefixMap = new Vector();
+    /**
+     * User override on path sep char
+     */
+    private String pathSep = null;
+    /**
+     * User override on directory sep char
+     */
+    private String dirSep = null;
+
+    /** Filename mapper */
+    private Mapper mapper = null;
+
+    /**
+     * Construct a new instance of the PathConvert task.
+     */
+    public PathConvert() {
+    }
+
+    /**
+     * Helper class, holds the nested &lt;map&gt; values. Elements will look like
+     * this: &lt;map from=&quot;d:&quot; to=&quot;/foo&quot;/&gt;
+     *
+     * When running on windows, the prefix comparison will be case
+     * insensitive.
+     */
+    public class MapEntry {
+
+        // Members
+        private String from = null;
+        private String to = null;
+
+        /**
+         * Set the &quot;from&quot; attribute of the map entry.
+         * @param from the prefix string to search for; required.
+         * Note that this value is case-insensitive when the build is
+         * running on a Windows platform and case-sensitive when running on
+         * a Unix platform.
+         */
+        public void setFrom(String from) {
+            this.from = from;
+        }
+
+        /**
+         * Set the replacement text to use when from is matched; required.
+         * @param to new prefix.
+         */
+        public void setTo(String to) {
+            this.to = to;
+        }
+
+        /**
+         * Apply this map entry to a given path element.
+         *
+         * @param elem Path element to process.
+         * @return String Updated path element after mapping.
+         */
+        public String apply(String elem) {
+            if (from == null || to == null) {
+                throw new BuildException("Both 'from' and 'to' must be set "
+                     + "in a map entry");
+            }
+            // If we're on windows, then do the comparison ignoring case
+            // and treat the two directory characters the same
+            String cmpElem =
+                onWindows ? elem.toLowerCase().replace('\\', '/') : elem;
+            String cmpFrom =
+                onWindows ? from.toLowerCase().replace('\\', '/') : from;
+
+            // If the element starts with the configured prefix, then
+            // convert the prefix to the configured 'to' value.
+
+            return cmpElem.startsWith(cmpFrom)
+                ? to + elem.substring(from.length()) : elem;
+        }
+    }
+
+    /**
+     * An enumeration of supported targets:
+     * "windows", "unix", "netware", and "os/2".
+     */
+    public static class TargetOs extends EnumeratedAttribute {
+        /**
+         * @return the list of values for this enumerated attribute.
+         */
+        public String[] getValues() {
+            return new String[]{"windows", "unix", "netware", "os/2", "tandem"};
+        }
+    }
+
+    /**
+     * Create a nested path element.
+     * @return a Path to be used by Ant reflection.
+     */
+    public Path createPath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        Path result = new Path(getProject());
+        add(result);
+        return result;
+    }
+
+    /**
+     * Add an arbitrary ResourceCollection.
+     * @param rc the ResourceCollection to add.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        getPath().add(rc);
+    }
+
+    private synchronized Union getPath() {
+        if (path == null) {
+            path = new Union();
+            path.setProject(getProject());
+        }
+        return path;
+    }
+
+    /**
+     * Create a nested MAP element.
+     * @return a Map to configure.
+     */
+    public MapEntry createMap() {
+        MapEntry entry = new MapEntry();
+        prefixMap.addElement(entry);
+        return entry;
+    }
+
+    /**
+     * Set targetos to a platform to one of
+     * "windows", "unix", "netware", or "os/2";
+     * current platform settings are used by default.
+     * @param target the target os.
+     * @deprecated since 1.5.x.
+     *             Use the method taking a TargetOs argument instead.
+     * @see #setTargetos(PathConvert.TargetOs)
+     */
+    public void setTargetos(String target) {
+        TargetOs to = new TargetOs();
+        to.setValue(target);
+        setTargetos(to);
+    }
+
+    /**
+     * Set targetos to a platform to one of
+     * "windows", "unix", "netware", or "os/2";
+     * current platform settings are used by default.
+     * @param target the target os
+     *
+     * @since Ant 1.5
+     */
+    public void setTargetos(TargetOs target) {
+        targetOS = target.getValue();
+
+        // Currently, we deal with only two path formats: Unix and Windows
+        // And Unix is everything that is not Windows
+
+        // for NetWare and OS/2, piggy-back on Windows, since in the
+        // validateSetup code, the same assumptions can be made as
+        // with windows - that ; is the path separator
+
+        targetWindows = !targetOS.equals("unix") && !targetOS.equals("tandem");
+    }
+
+    /**
+     * Set whether the specified property will be set if the result
+     * is the empty string.
+     * @param setonempty true or false.
+     *
+     * @since Ant 1.5
+     */
+     public void setSetonempty(boolean setonempty) {
+         this.setonempty = setonempty;
+     }
+
+    /**
+     * Set the name of the property into which the converted path will be placed.
+     * @param p the property name.
+     */
+    public void setProperty(String p) {
+        property = p;
+    }
+
+    /**
+     * Add a reference to a Path, FileSet, DirSet, or FileList defined elsewhere.
+     * @param r the reference to a path, fileset, dirset or filelist.
+     */
+    public void setRefid(Reference r) {
+        if (path != null) {
+            throw noChildrenAllowed();
+        }
+        refid = r;
+    }
+
+    /**
+     * Set the default path separator string; defaults to current JVM
+     * {@link java.io.File#pathSeparator File.pathSeparator}.
+     * @param sep path separator string.
+     */
+    public void setPathSep(String sep) {
+        pathSep = sep;
+    }
+
+
+    /**
+     * Set the default directory separator string;
+     * defaults to current JVM {@link java.io.File#separator File.separator}.
+     * @param sep directory separator string.
+     */
+    public void setDirSep(String sep) {
+        dirSep = sep;
+    }
+
+    /**
+     * Learn whether the refid attribute of this element been set.
+     * @return true if refid is valid.
+     */
+    public boolean isReference() {
+        return refid != null;
+    }
+
+    /**
+     * Do the execution.
+     * @throws BuildException if something is invalid.
+     */
+    public void execute() throws BuildException {
+        Union savedPath = path;
+        String savedPathSep = pathSep; // may be altered in validateSetup
+        String savedDirSep = dirSep; // may be altered in validateSetup
+
+        try {
+            // If we are a reference, create a Path from the reference
+            if (isReference()) {
+                Object o = refid.getReferencedObject(getProject());
+                if (!(o instanceof ResourceCollection)) {
+                    throw new BuildException("refid '" + refid.getRefId()
+                        + "' does not refer to a resource collection.");
+                }
+                getPath().add((ResourceCollection) o);
+            }
+            validateSetup(); // validate our setup
+
+            // Currently, we deal with only two path formats: Unix and Windows
+            // And Unix is everything that is not Windows
+            // (with the exception for NetWare and OS/2 below)
+
+            // for NetWare and OS/2, piggy-back on Windows, since here and
+            // in the apply code, the same assumptions can be made as with
+            // windows - that \\ is an OK separator, and do comparisons
+            // case-insensitive.
+            String fromDirSep = onWindows ? "\\" : "/";
+
+            StringBuffer rslt = new StringBuffer();
+
+            // Get the list of path components in canonical form
+            String[] elems = path.list();
+
+            if (mapper != null) {
+                FileNameMapper impl = mapper.getImplementation();
+                List ret = new ArrayList();
+                for (int i = 0; i < elems.length; ++i) {
+                    String[] mapped = impl.mapFileName(elems[i]);
+                    for (int m = 0; mapped != null && m < mapped.length; ++m) {
+                        ret.add(mapped[m]);
+                    }
+                }
+                elems = (String[]) ret.toArray(new String[ret.size()]);
+            }
+            for (int i = 0; i < elems.length; i++) {
+                String elem = mapElement(elems[i]); // Apply the path prefix map
+
+                // Now convert the path and file separator characters from the
+                // current os to the target os.
+
+                if (i != 0) {
+                    rslt.append(pathSep);
+                }
+                StringTokenizer stDirectory =
+                    new StringTokenizer(elem, fromDirSep, true);
+
+                while (stDirectory.hasMoreTokens()) {
+                    String token = stDirectory.nextToken();
+                    rslt.append(fromDirSep.equals(token) ? dirSep : token);
+                }
+            }
+            // Place the result into the specified property,
+            // unless setonempty == false
+            if (setonempty || rslt.length() > 0) {
+                String value = rslt.toString();
+                if (property == null) {
+                    log(value);
+                } else {
+                    log("Set property " + property + " = " + value,
+                        Project.MSG_VERBOSE);
+                    getProject().setNewProperty(property, value);
+                }
+            }
+        } finally {
+            path = savedPath;
+            dirSep = savedDirSep;
+            pathSep = savedPathSep;
+        }
+    }
+
+    /**
+     * Apply the configured map to a path element. The map is used to convert
+     * between Windows drive letters and Unix paths. If no map is configured,
+     * then the input string is returned unchanged.
+     *
+     * @param elem The path element to apply the map to.
+     * @return String Updated element.
+     */
+    private String mapElement(String elem) {
+
+        int size = prefixMap.size();
+
+        if (size != 0) {
+
+            // Iterate over the map entries and apply each one.
+            // Stop when one of the entries actually changes the element.
+
+            for (int i = 0; i < size; i++) {
+                MapEntry entry = (MapEntry) prefixMap.elementAt(i);
+                String newElem = entry.apply(elem);
+
+                // Note I'm using "!=" to see if we got a new object back from
+                // the apply method.
+
+                if (newElem != elem) {
+                    elem = newElem;
+                    break; // We applied one, so we're done
+                }
+            }
+        }
+        return elem;
+    }
+
+    /**
+     * Add a mapper to convert the file names.
+     *
+     * @param mapper a <code>Mapper</code> value.
+     */
+    public void addMapper(Mapper mapper) {
+        if (this.mapper != null) {
+            throw new BuildException(
+                "Cannot define more than one mapper");
+        }
+        this.mapper = mapper;
+    }
+
+    /**
+     * Add a nested filenamemapper.
+     * @param fileNameMapper the mapper to add.
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        Mapper m = new Mapper(getProject());
+        m.add(fileNameMapper);
+        addMapper(m);
+    }
+
+    /**
+     * Validate that all our parameters have been properly initialized.
+     *
+     * @throws BuildException if something is not set up properly.
+     */
+    private void validateSetup() throws BuildException {
+
+        if (path == null) {
+            throw new BuildException("You must specify a path to convert");
+        }
+        // Determine the separator strings.  The dirsep and pathsep attributes
+        // override the targetOS settings.
+        String dsep = File.separator;
+        String psep = File.pathSeparator;
+
+        if (targetOS != null) {
+            psep = targetWindows ? ";" : ":";
+            dsep = targetWindows ? "\\" : "/";
+        }
+        if (pathSep != null) {
+            // override with pathsep=
+            psep = pathSep;
+        }
+        if (dirSep != null) {
+            // override with dirsep=
+            dsep = dirSep;
+        }
+        pathSep = psep;
+        dirSep = dsep;
+    }
+
+    /**
+     * Creates an exception that indicates that this XML element must not have
+     * child elements if the refid attribute is set.
+     * @return BuildException.
+     */
+    private BuildException noChildrenAllowed() {
+        return new BuildException("You must not specify nested "
+             + "elements when using the refid attribute.");
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java
new file mode 100644
index 0000000..fe57704
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/PreSetDef.java
@@ -0,0 +1,275 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.UnknownElement;
+
+/**
+ * The preset definition task generates a new definition
+ * based on a current definition with some attributes or
+ * elements preset.
+ * <pre>
+ * &lt;presetdef name="my.javac"&gt;
+ *   &lt;javac deprecation="${deprecation}" debug="${debug}"/&gt;
+ * &lt;/presetdef&gt;
+ * &lt;my.javac srcdir="src" destdir="classes"/&gt;
+ * </pre>
+ *
+ * @since Ant 1.6
+ */
+public class PreSetDef extends AntlibDefinition implements TaskContainer {
+    private UnknownElement nestedTask;
+    private String         name;
+
+    /**
+     * Set the name of this definition.
+     * @param name the name of the definition.
+     */
+     public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Add a nested task to predefine attributes and elements on.
+     * @param nestedTask  Nested task/type to extend.
+     */
+    public void addTask(Task nestedTask) {
+        if (this.nestedTask != null) {
+            throw new BuildException("Only one nested element allowed");
+        }
+        if (!(nestedTask instanceof UnknownElement)) {
+            throw new BuildException(
+                "addTask called with a task that is not an unknown element");
+        }
+        this.nestedTask = (UnknownElement) nestedTask;
+    }
+
+
+    /**
+     * Make a new definition.
+     */
+    public void execute() {
+        if (nestedTask == null) {
+            throw new BuildException("Missing nested element");
+        }
+        if (name == null) {
+            throw new BuildException("Name not specified");
+        }
+        name = ProjectHelper.genComponentName(getURI(), name);
+
+        ComponentHelper helper = ComponentHelper.getComponentHelper(
+            getProject());
+
+        String componentName = ProjectHelper.genComponentName(
+            nestedTask.getNamespace(), nestedTask.getTag());
+
+        AntTypeDefinition def = helper.getDefinition(componentName);
+        if (def == null) {
+            throw new BuildException(
+                "Unable to find typedef " + componentName);
+        }
+        PreSetDefinition newDef = new PreSetDefinition(def, nestedTask);
+
+        newDef.setName(name);
+
+        helper.addDataTypeDefinition(newDef);
+        log("defining preset " + name, Project.MSG_VERBOSE);
+    }
+
+    /**
+     * This class contains the unknown element and the object
+     * that is predefined.
+     * @see AntTypeDefinition
+     */
+    public static class PreSetDefinition extends AntTypeDefinition {
+        private AntTypeDefinition parent;
+        private UnknownElement    element;
+
+        /**
+         * Creates a new <code>PresetDefinition</code> instance.
+         *
+         * @param parent The parent of this predefinition.
+         * @param el     The predefined attributes, nested elements and text.
+         */
+        public PreSetDefinition(AntTypeDefinition parent, UnknownElement el) {
+            if (parent instanceof PreSetDefinition) {
+                PreSetDefinition p = (PreSetDefinition) parent;
+                el.applyPreSet(p.element);
+                parent = p.parent;
+            }
+            this.parent = parent;
+            this.element = el;
+        }
+
+        /**
+         * Override so that it is not allowed.
+         *
+         * @param clazz a <code>Class</code> value.
+         */
+        public void setClass(Class clazz) {
+            throw new BuildException("Not supported");
+        }
+
+        /**
+         * Override so that it is not allowed.
+         *
+         * @param className a <code>String</code> value.
+         */
+        public void setClassName(String className) {
+            throw new BuildException("Not supported");
+        }
+
+        /**
+         * Get the classname of the definition.
+         * @return the name of the class of this definition.
+         */
+        public String getClassName() {
+            return parent.getClassName();
+        }
+
+        /**
+         * Set the adapter class for this definition.
+         * NOT Supported
+         * @param adapterClass the adapterClass.
+         */
+        public void setAdapterClass(Class adapterClass) {
+            throw new BuildException("Not supported");
+        }
+
+        /**
+         * Set the assignable class for this definition.
+         * NOT SUPPORTED
+         * @param adaptToClass the assignable class.
+         */
+        public void setAdaptToClass(Class adaptToClass) {
+            throw new BuildException("Not supported");
+        }
+
+        /**
+         * Set the classloader to use to create an instance
+         * of the definition.
+         * NOT SUPPORTED
+         * @param classLoader the classLoader.
+         */
+        public void setClassLoader(ClassLoader classLoader) {
+            throw new BuildException("Not supported");
+        }
+
+        /**
+         * Get the classloader for this definition.
+         * @return the classloader for this definition.
+         */
+        public ClassLoader getClassLoader() {
+            return parent.getClassLoader();
+        }
+
+        /**
+         * Get the exposed class for this definition.
+         * @param project the current project.
+         * @return the exposed class.
+         */
+        public Class getExposedClass(Project project) {
+            return parent.getExposedClass(project);
+        }
+
+        /**
+         * Get the definition class.
+         * @param project the current project.
+         * @return the type of the definition.
+         */
+        public Class getTypeClass(Project project) {
+            return parent.getTypeClass(project);
+        }
+
+
+        /**
+         * Check if the attributes are correct.
+         * @param project the current project.
+         */
+        public void checkClass(Project project) {
+            parent.checkClass(project);
+        }
+
+        /**
+         * Create an instance of the definition. The instance may be wrapped
+         * in a proxy class. This is a special version of create for
+         * IntrospectionHelper and UnknownElement.
+         * @param project the current project.
+         * @return the created object.
+         */
+        public Object createObject(Project project) {
+            return parent.create(project);
+        }
+
+        /**
+         * Get the preset values.
+         * @return the predefined attributes, elements and text as
+         *         an UnknownElement.
+         */
+        public UnknownElement getPreSets() {
+            return element;
+        }
+
+        /**
+         * Fake create an object, used by IntrospectionHelper and UnknownElement
+         * to see that this is a predefined object.
+         *
+         * @param project the current project.
+         * @return this object.
+         */
+        public Object create(Project project) {
+            return this;
+        }
+
+        /**
+         * Equality method for this definition.
+         *
+         * @param other another definition.
+         * @param project the current project.
+         * @return true if the definitions are the same.
+         */
+        public boolean sameDefinition(AntTypeDefinition other, Project project) {
+            return (other != null && other.getClass() == getClass() && parent != null
+                && parent.sameDefinition(((PreSetDefinition) other).parent, project)
+                && element.similar(((PreSetDefinition) other).element));
+        }
+
+        /**
+         * Similar method for this definition.
+         *
+         * @param other another definition.
+         * @param project the current project.
+         * @return true if the definitions are similar.
+         */
+        public boolean similarDefinition(
+            AntTypeDefinition other, Project project) {
+            return (other != null && other.getClass().getName().equals(
+                getClass().getName()) && parent != null
+                && parent.similarDefinition(((PreSetDefinition) other).parent, project)
+                && element.similar(((PreSetDefinition) other).element));
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java
new file mode 100644
index 0000000..b776349
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ProcessDestroyer.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Destroys all registered <code>Process</code>es when the VM exits.
+ *
+ * @since Ant 1.5
+ */
+class ProcessDestroyer implements Runnable {
+    private static final int THREAD_DIE_TIMEOUT = 20000;
+    private Vector processes = new Vector();
+    // methods to register and unregister shutdown hooks
+    private Method addShutdownHookMethod;
+    private Method removeShutdownHookMethod;
+    private ProcessDestroyerImpl destroyProcessThread = null;
+
+    // whether or not this ProcessDestroyer has been registered as a
+    // shutdown hook
+    private boolean added = false;
+    // whether or not this ProcessDestroyer is currently running as
+    // shutdown hook
+    private boolean running = false;
+
+    private class ProcessDestroyerImpl extends Thread {
+        private boolean shouldDestroy = true;
+
+        public ProcessDestroyerImpl() {
+            super("ProcessDestroyer Shutdown Hook");
+        }
+        public void run() {
+            if (shouldDestroy) {
+                ProcessDestroyer.this.run();
+            }
+        }
+
+        public void setShouldDestroy(boolean shouldDestroy) {
+            this.shouldDestroy = shouldDestroy;
+        }
+    }
+
+    /**
+     * Constructs a <code>ProcessDestroyer</code> and obtains
+     * <code>Runtime.addShutdownHook()</code> and
+     * <code>Runtime.removeShutdownHook()</code> through reflection. The
+     * ProcessDestroyer manages a list of processes to be destroyed when the
+     * VM exits. If a process is added when the list is empty,
+     * this <code>ProcessDestroyer</code> is registered as a shutdown hook. If
+     * removing a process results in an empty list, the
+     * <code>ProcessDestroyer</code> is removed as a shutdown hook.
+     */
+    ProcessDestroyer() {
+        try {
+            // check to see if the shutdown hook methods exists
+            // (support pre-JDK 1.3 and Non-Sun VMs)
+            Class[] paramTypes = {Thread.class};
+            addShutdownHookMethod =
+                Runtime.class.getMethod("addShutdownHook", paramTypes);
+
+            removeShutdownHookMethod =
+                Runtime.class.getMethod("removeShutdownHook", paramTypes);
+            // wait to add shutdown hook as needed
+        } catch (NoSuchMethodException e) {
+            // it just won't be added as a shutdown hook... :(
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Registers this <code>ProcessDestroyer</code> as a shutdown hook,
+     * uses reflection to ensure pre-JDK 1.3 compatibility.
+     */
+    private void addShutdownHook() {
+        if (addShutdownHookMethod != null && !running) {
+            destroyProcessThread = new ProcessDestroyerImpl();
+            Object[] args = {destroyProcessThread};
+            try {
+                addShutdownHookMethod.invoke(Runtime.getRuntime(), args);
+                added = true;
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                Throwable t = e.getTargetException();
+                if (t != null && t.getClass() == IllegalStateException.class) {
+                    // shutdown already is in progress
+                    running = true;
+                } else {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes this <code>ProcessDestroyer</code> as a shutdown hook,
+     * uses reflection to ensure pre-JDK 1.3 compatibility
+     */
+    private void removeShutdownHook() {
+        if (removeShutdownHookMethod != null && added && !running) {
+            Object[] args = {destroyProcessThread};
+            try {
+                Boolean removed =
+                    (Boolean) removeShutdownHookMethod.invoke(
+                        Runtime.getRuntime(),
+                        args);
+                if (!removed.booleanValue()) {
+                    System.err.println("Could not remove shutdown hook");
+                }
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                Throwable t = e.getTargetException();
+                if (t != null && t.getClass() == IllegalStateException.class) {
+                    // shutdown already is in progress
+                    running = true;
+                } else {
+                    e.printStackTrace();
+                }
+            }
+            // start the hook thread, a unstarted thread may not be
+            // eligible for garbage collection
+            // Cf.: http://developer.java.sun.com/developer/bugParade/bugs/4533087.html
+            destroyProcessThread.setShouldDestroy(false);
+            if (!destroyProcessThread.getThreadGroup().isDestroyed()) {
+                // start() would throw IllegalThreadStateException from
+                // ThreadGroup.add if it were destroyed
+                destroyProcessThread.start();
+            }
+            // this should return quickly, since it basically is a NO-OP.
+            try {
+                destroyProcessThread.join(THREAD_DIE_TIMEOUT);
+            } catch (InterruptedException ie) {
+                // the thread didn't die in time
+                // it should not kill any processes unexpectedly
+            }
+            destroyProcessThread = null;
+            added = false;
+        }
+    }
+
+    /**
+     * Returns whether or not the ProcessDestroyer is registered as
+     * as shutdown hook
+     * @return true if this is currently added as shutdown hook
+     */
+    public boolean isAddedAsShutdownHook() {
+        return added;
+    }
+
+    /**
+     * Returns <code>true</code> if the specified <code>Process</code> was
+     * successfully added to the list of processes to destroy upon VM exit.
+     *
+     * @param   process the process to add
+     * @return  <code>true</code> if the specified <code>Process</code> was
+     *          successfully added
+     */
+    public boolean add(Process process) {
+        synchronized (processes) {
+            // if this list is empty, register the shutdown hook
+            if (processes.size() == 0) {
+                addShutdownHook();
+            }
+            processes.addElement(process);
+            return processes.contains(process);
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if the specified <code>Process</code> was
+     * successfully removed from the list of processes to destroy upon VM exit.
+     *
+     * @param   process the process to remove
+     * @return  <code>true</code> if the specified <code>Process</code> was
+     *          successfully removed
+     */
+    public boolean remove(Process process) {
+        synchronized (processes) {
+            boolean processRemoved = processes.removeElement(process);
+            if (processRemoved && processes.size() == 0) {
+                removeShutdownHook();
+            }
+            return processRemoved;
+        }
+    }
+
+    /**
+     * Invoked by the VM when it is exiting.
+     */
+    public void run() {
+        synchronized (processes) {
+            running = true;
+            Enumeration e = processes.elements();
+            while (e.hasMoreElements()) {
+                ((Process) e.nextElement()).destroy();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Property.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Property.java
new file mode 100644
index 0000000..0eb3bb1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Property.java
@@ -0,0 +1,651 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.property.ResolvePropertyMap;
+
+/**
+ * Sets a property by name, or set of properties (from file or
+ * resource) in the project.  </p>
+ * Properties are immutable: whoever sets a property first freezes it for the
+ * rest of the build; they are most definitely not variable.
+ * <p>There are five ways to set properties:</p>
+ * <ul>
+ *   <li>By supplying both the <i>name</i> and <i>value</i> attribute.</li>
+ *   <li>By supplying both the <i>name</i> and <i>refid</i> attribute.</li>
+ *   <li>By setting the <i>file</i> attribute with the filename of the property
+ *     file to load. This property file has the format as defined by the file used
+ *     in the class java.util.Properties.</li>
+ *   <li>By setting the <i>resource</i> attribute with the resource name of the
+ *     property file to load. This property file has the format as defined by the
+ *     file used in the class java.util.Properties.</li>
+ *   <li>By setting the <i>environment</i> attribute with a prefix to use.
+ *     Properties will be defined for every environment variable by
+ *     prefixing the supplied name and a period to the name of the variable.</li>
+ * </ul>
+ * <p>Although combinations of these ways are possible, only one should be used
+ * at a time. Problems might occur with the order in which properties are set, for
+ * instance.</p>
+ * <p>The value part of the properties being set, might contain references to other
+ * properties. These references are resolved at the time these properties are set.
+ * This also holds for properties loaded from a property file.</p>
+ * Properties are case sensitive.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.attribute.group name="name" description="One of these, when using the name attribute"
+ * @ant.attribute.group name="noname" description="One of these, when not using the name attribute"
+ * @ant.task category="property"
+ */
+public class Property extends Task {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String name;
+    protected String value;
+    protected File file;
+    protected URL url;
+    protected String resource;
+    protected Path classpath;
+    protected String env;
+    protected Reference ref;
+    protected String prefix;
+    private Project fallback;
+    private Object untypedValue;
+
+    protected boolean userProperty; // set read-only properties
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for Property.
+     */
+    public Property() {
+        this(false);
+    }
+
+    /**
+     * Constructor for Property.
+     * @param userProperty if true this is a user property
+     * @since Ant 1.5
+     */
+    protected Property(boolean userProperty) {
+        this(userProperty, null);
+    }
+
+    /**
+     * Constructor for Property.
+     * @param userProperty if true this is a user property
+     * @param fallback a project to use to look for references if the reference is
+     *                 not in the current project
+     * @since Ant 1.5
+     */
+    protected Property(boolean userProperty, Project fallback) {
+        this.userProperty = userProperty;
+        this.fallback = fallback;
+    }
+
+    /**
+     * The name of the property to set.
+     * @param name property name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get the property name.
+     * @return the property name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the property to the absolute filename of the
+     * given file. If the value of this attribute is an absolute path, it
+     * is left unchanged (with / and \ characters converted to the
+     * current platforms conventions). Otherwise it is taken as a path
+     * relative to the project's basedir and expanded.
+     * @param location path to set
+     *
+     * @ant.attribute group="name"
+     */
+    public void setLocation(File location) {
+        setValue(location.getAbsolutePath());
+    }
+
+    /* the following method is first in source so IH will pick it up first:
+     * Hopefully we'll never get any classes compiled by wise-guy compilers that behave otherwise...
+     */
+
+    /**
+     * Set the value of the property.
+     * @param value the value to use.
+     */
+    public void setValue(Object value) {
+        this.untypedValue = value;
+        //preserve protected string value for subclasses :(
+        this.value = value == null ? null : value.toString();
+    }
+
+    /**
+     * Set the value of the property as a String.
+     * @param value value to assign
+     *
+     * @ant.attribute group="name"
+     */
+    public void setValue(String value) {
+        setValue((Object) value);
+    }
+
+    /**
+     * Get the property value.
+     * @return the property value
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Filename of a property file to load.
+     * @param file filename
+     *
+     * @ant.attribute group="noname"
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Get the file attribute.
+     * @return the file attribute
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * The url from which to load properties.
+     * @param url url string
+     *
+     * @ant.attribute group="noname"
+     */
+    public void setUrl(URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Get the url attribute.
+     * @return the url attribute
+     */
+    public URL getUrl() {
+        return url;
+    }
+
+    /**
+     * Prefix to apply to properties loaded using <code>file</code>
+     * or <code>resource</code>.
+     * A "." is appended to the prefix if not specified.
+     * @param prefix prefix string
+     * @since Ant 1.5
+     */
+    public void setPrefix(String prefix) {
+        this.prefix = prefix;
+        if (!prefix.endsWith(".")) {
+            this.prefix += ".";
+        }
+    }
+
+    /**
+     * Get the prefix attribute.
+     * @return the prefix attribute
+     * @since Ant 1.5
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * Sets a reference to an Ant datatype
+     * declared elsewhere.
+     * Only yields reasonable results for references
+     * PATH like structures or properties.
+     * @param ref reference
+     *
+     * @ant.attribute group="name"
+     */
+    public void setRefid(Reference ref) {
+        this.ref = ref;
+    }
+
+    /**
+     * Get the refid attribute.
+     * @return the refid attribute
+     */
+    public Reference getRefid() {
+        return ref;
+    }
+
+    /**
+     * The resource name of a property file to load
+     * @param resource resource on classpath
+     *
+     * @ant.attribute group="noname"
+     */
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+
+    /**
+     * Get the resource attribute.
+     * @return the resource attribute
+     */
+    public String getResource() {
+        return resource;
+    }
+
+    /**
+     * Prefix to use when retrieving environment variables.
+     * Thus if you specify environment=&quot;myenv&quot;
+     * you will be able to access OS-specific
+     * environment variables via property names &quot;myenv.PATH&quot; or
+     * &quot;myenv.TERM&quot;.
+     * <p>
+     * Note that if you supply a property name with a final
+     * &quot;.&quot; it will not be doubled. ie environment=&quot;myenv.&quot; will still
+     * allow access of environment variables through &quot;myenv.PATH&quot; and
+     * &quot;myenv.TERM&quot;. This functionality is currently only implemented
+     * on select platforms. Feel free to send patches to increase the number of platforms
+     * this functionality is supported on ;).<br>
+     * Note also that properties are case sensitive, even if the
+     * environment variables on your operating system are not, e.g. it
+     * will be ${env.Path} not ${env.PATH} on Windows 2000.
+     * @param env prefix
+     *
+     * @ant.attribute group="noname"
+     */
+    public void setEnvironment(String env) {
+        this.env = env;
+    }
+
+    /**
+     * Get the environment attribute.
+     * @return the environment attribute
+     * @since Ant 1.5
+     */
+    public String getEnvironment() {
+        return env;
+    }
+
+    /**
+     * The classpath to use when looking up a resource.
+     * @param classpath to add to any existing classpath
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * The classpath to use when looking up a resource.
+     * @return a path to be configured
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * the classpath to use when looking up a resource,
+     * given as reference to a &lt;path&gt; defined elsewhere
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Get the classpath used when looking up a resource.
+     * @return the classpath
+     * @since Ant 1.5
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * @param userProperty ignored
+     * @deprecated since 1.5.x.
+     *             This was never a supported feature and has been
+     *             deprecated without replacement.
+     * @ant.attribute ignore="true"
+     */
+    public void setUserProperty(boolean userProperty) {
+        log("DEPRECATED: Ignoring request to set user property in Property"
+            + " task.", Project.MSG_WARN);
+    }
+
+    /**
+     * get the value of this property
+     * @return the current value or the empty string
+     */
+    public String toString() {
+        return value == null ? "" : value;
+    }
+
+    /**
+     * set the property in the project to the value.
+     * if the task was give a file, resource or env attribute
+     * here is where it is loaded
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (getProject() == null) {
+            throw new IllegalStateException("project has not been set");
+        }
+
+        if (name != null) {
+            if (untypedValue == null && ref == null) {
+                throw new BuildException("You must specify value, location or "
+                                         + "refid with the name attribute",
+                                         getLocation());
+            }
+        } else {
+            if (url == null && file == null && resource == null && env == null) {
+                throw new BuildException("You must specify url, file, resource or "
+                                         + "environment when not using the "
+                                         + "name attribute", getLocation());
+            }
+        }
+
+        if (url == null && file == null && resource == null && prefix != null) {
+            throw new BuildException("Prefix is only valid when loading from "
+                                     + "a url, file or resource", getLocation());
+        }
+
+        if (name != null && untypedValue != null) {
+            addProperty(name, untypedValue);
+        }
+
+        if (file != null) {
+            loadFile(file);
+        }
+
+        if (url != null) {
+            loadUrl(url);
+        }
+
+        if (resource != null) {
+            loadResource(resource);
+        }
+
+        if (env != null) {
+            loadEnvironment(env);
+        }
+
+        if ((name != null) && (ref != null)) {
+            try {
+                addProperty(name,
+                            ref.getReferencedObject(getProject()).toString());
+            } catch (BuildException be) {
+                if (fallback != null) {
+                    addProperty(name,
+                                ref.getReferencedObject(fallback).toString());
+                } else {
+                    throw be;
+                }
+            }
+        }
+    }
+
+    /**
+     * load properties from a url
+     * @param url url to load from
+     * @throws BuildException on error
+     */
+    protected void loadUrl(URL url) throws BuildException {
+        Properties props = new Properties();
+        log("Loading " + url, Project.MSG_VERBOSE);
+        try {
+            InputStream is = url.openStream();
+            try {
+                loadProperties(props, is, url.getFile().endsWith(".xml"));
+            } finally {
+                if (is != null) {
+                    is.close();
+                }
+            }
+            addProperties(props);
+        } catch (IOException ex) {
+            throw new BuildException(ex, getLocation());
+        }
+    }
+
+    /**
+     * Loads the properties defined in the InputStream into the given
+     * property. On Java5+ it supports reading from XML based property
+     * definition.
+     * @param props The property object to load into
+     * @param is    The input stream from where to load
+     * @param isXml <tt>true</tt> if we should try to load from xml
+     * @throws IOException if something goes wrong
+     * @since 1.7.1
+     * @see http://java.sun.com/dtd/properties.dtd
+     * @see java.util.Properties#loadFromXML(InputStream)
+     */
+    private void loadProperties(
+        Properties props, InputStream is, boolean isXml) throws IOException {
+        if (isXml) {
+            // load the xml based property definition
+            // use reflection because of bwc to Java 1.3
+            try {
+                Method loadXmlMethod = props.getClass().getMethod("loadFromXML",
+                        new Class[] {InputStream.class});
+                loadXmlMethod.invoke(props, new Object[] {is});
+            } catch (NoSuchMethodException e) {
+                e.printStackTrace();
+                log("Can not load xml based property definition on Java < 5");
+            } catch (Exception e) {
+                // no-op
+                e.printStackTrace();
+            }
+        } else {
+            // load ".properties" format
+            props.load(is);
+        }
+    }
+
+    /**
+     * load properties from a file
+     * @param file file to load
+     * @throws BuildException on error
+     */
+    protected void loadFile(File file) throws BuildException {
+        Properties props = new Properties();
+        log("Loading " + file.getAbsolutePath(), Project.MSG_VERBOSE);
+        try {
+            if (file.exists()) {
+                FileInputStream  fis = null;
+                try {
+                    fis = new FileInputStream(file);
+                    loadProperties(props, fis, file.getName().endsWith(".xml"));
+                } finally {
+                    FileUtils.close(fis);
+                }
+                addProperties(props);
+            } else {
+                log("Unable to find property file: " + file.getAbsolutePath(),
+                        Project.MSG_VERBOSE);
+            }
+        } catch (IOException ex) {
+            throw new BuildException(ex, getLocation());
+        }
+    }
+
+    /**
+     * load properties from a resource in the current classpath
+     * @param name name of resource to load
+     */
+    protected void loadResource(String name) {
+        Properties props = new Properties();
+        log("Resource Loading " + name, Project.MSG_VERBOSE);
+        InputStream is = null;
+        try {
+            ClassLoader cL = null;
+
+            if (classpath != null) {
+                cL = getProject().createClassLoader(classpath);
+            } else {
+                cL = this.getClass().getClassLoader();
+            }
+
+            if (cL == null) {
+                is = ClassLoader.getSystemResourceAsStream(name);
+            } else {
+                is = cL.getResourceAsStream(name);
+            }
+
+            if (is != null) {
+                loadProperties(props, is, name.endsWith(".xml"));
+                addProperties(props);
+            } else {
+                log("Unable to find resource " + name, Project.MSG_WARN);
+            }
+        } catch (IOException ex) {
+            throw new BuildException(ex, getLocation());
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * load the environment values
+     * @param prefix prefix to place before them
+     */
+    protected void loadEnvironment(String prefix) {
+        Properties props = new Properties();
+        if (!prefix.endsWith(".")) {
+            prefix += ".";
+        }
+        log("Loading Environment " + prefix, Project.MSG_VERBOSE);
+        Vector osEnv = Execute.getProcEnvironment();
+        for (Enumeration e = osEnv.elements(); e.hasMoreElements();) {
+            String entry = (String) e.nextElement();
+            int pos = entry.indexOf('=');
+            if (pos == -1) {
+                log("Ignoring: " + entry, Project.MSG_WARN);
+            } else {
+                props.put(prefix + entry.substring(0, pos),
+                entry.substring(pos + 1));
+            }
+        }
+        addProperties(props);
+    }
+
+    /**
+     * iterate through a set of properties,
+     * resolve them then assign them
+     * @param props the properties to iterate over
+     */
+    protected void addProperties(Properties props) {
+        HashMap m = new HashMap(props);
+        resolveAllProperties(m);
+        for (Iterator it = m.keySet().iterator(); it.hasNext();) {
+            Object k = it.next();
+            if (k instanceof String) {
+                String propertyName = (String) k;
+                if (prefix != null) {
+                    propertyName = prefix + propertyName;
+                }
+                addProperty(propertyName, m.get(k));
+            }
+        }
+    }
+
+    /**
+     * add a name value pair to the project property set
+     * @param n name of property
+     * @param v value to set
+     */
+    protected void addProperty(String n, String v) {
+        addProperty(n, (Object) v);
+    }
+
+    /**
+     * add a name value pair to the project property set
+     * @param n name of property
+     * @param v value to set
+     * @since Ant 1.8
+     */
+    protected void addProperty(String n, Object v) {
+        PropertyHelper ph = PropertyHelper.getPropertyHelper(getProject());
+        if (userProperty) {
+            if (ph.getUserProperty(n) == null) {
+                ph.setInheritedProperty(n, v);
+            } else {
+                log("Override ignored for " + n, Project.MSG_VERBOSE);
+            }
+        } else {
+            ph.setNewProperty(n, v);
+        }
+    }
+
+    /**
+     * resolve properties inside a properties hashtable
+     * @param props properties object to resolve
+     */
+    private void resolveAllProperties(Map props) throws BuildException {
+        PropertyHelper propertyHelper
+            = (PropertyHelper) PropertyHelper.getPropertyHelper(getProject());
+        new ResolvePropertyMap(
+            getProject(),
+            propertyHelper,
+            propertyHelper.getExpanders()).resolveAllProperties(props);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
new file mode 100644
index 0000000..5e8867a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/PropertyHelperTask.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.PropertyHelper;
+import org.apache.tools.ant.Task;
+
+/**
+ * This task is designed to allow the user to install a different
+ * PropertyHelper on the current Project. This task also allows the
+ * installation of PropertyHelper delegates on either the newly installed
+ * or existing PropertyHelper.
+ * @since Ant 1.8
+ */
+public class PropertyHelperTask extends Task {
+    /**
+     * Nested delegate for refid usage.
+     */
+    public final class DelegateElement {
+        private String refid;
+
+        private DelegateElement() {
+        }
+
+        /**
+         * Get the refid.
+         * @return String
+         */
+        public String getRefid() {
+            return refid;
+        }
+
+        /**
+         * Set the refid.
+         * @param refid the String to set
+         */
+        public void setRefid(String refid) {
+            this.refid = refid;
+        }
+
+        private PropertyHelper.Delegate resolve() {
+            if (refid == null) {
+                throw new BuildException("refid required for generic delegate");
+            }
+            return (PropertyHelper.Delegate) getProject().getReference(refid);
+        }
+    }
+
+    private PropertyHelper propertyHelper;
+    private List delegates;
+
+    /**
+     * Add a new PropertyHelper to be set on the Project.
+     * @param propertyHelper the PropertyHelper to set.
+     */
+    public synchronized void addConfigured(PropertyHelper propertyHelper) {
+        if (this.propertyHelper != null) {
+            throw new BuildException("Only one PropertyHelper can be installed");
+        }
+        this.propertyHelper = propertyHelper;
+    }
+
+    /**
+     * Add a PropertyHelper delegate to the existing or new PropertyHelper.
+     * @param delegate the delegate to add.
+     */
+    public synchronized void addConfigured(PropertyHelper.Delegate delegate) {
+        getAddDelegateList().add(delegate);
+    }
+
+    /**
+     * Add a nested &lt;delegate refid="foo" /&gt; element.
+     * @return DelegateElement
+     */
+    public DelegateElement createDelegate() {
+        DelegateElement result = new DelegateElement();
+        getAddDelegateList().add(result);
+        return result;
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        if (getProject() == null) {
+            throw new BuildException("Project instance not set");
+        }
+        if (propertyHelper == null && delegates == null) {
+            throw new BuildException("Either a new PropertyHelper"
+                    + " or one or more PropertyHelper delegates are required");
+        }
+        PropertyHelper ph = propertyHelper;
+        if (ph == null) {
+            ph = PropertyHelper.getPropertyHelper(getProject());
+        } else {
+            ph = propertyHelper;
+        }
+        synchronized (ph) {
+            if (delegates != null) {
+                for (Iterator iter = delegates.iterator(); iter.hasNext();) {
+                    Object o = iter.next();
+                    PropertyHelper.Delegate delegate = o instanceof DelegateElement
+                            ? ((DelegateElement) o).resolve() : (PropertyHelper.Delegate) o;
+                    log("Adding PropertyHelper delegate " + delegate, Project.MSG_DEBUG);
+                    ph.add(delegate);
+                }
+            }
+        }
+        if (propertyHelper != null) {
+            log("Installing PropertyHelper " + propertyHelper, Project.MSG_DEBUG);
+            // TODO copy existing properties to new PH?
+            getProject().addReference(MagicNames.REFID_PROPERTY_HELPER, propertyHelper);
+        }
+    }
+
+    private synchronized List getAddDelegateList() {
+        if (delegates == null) {
+            delegates = new ArrayList();
+        }
+        return delegates;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java
new file mode 100644
index 0000000..a1524b3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/PumpStreamHandler.java
@@ -0,0 +1,232 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Copies standard output and error of subprocesses to standard output and
+ * error of the parent process.
+ *
+ * @since Ant 1.2
+ */
+public class PumpStreamHandler implements ExecuteStreamHandler {
+
+    private Thread outputThread;
+    private Thread errorThread;
+    private StreamPumper inputPump;
+
+    private OutputStream out;
+    private OutputStream err;
+    private InputStream input;
+
+    /**
+     * Construct a new <code>PumpStreamHandler</code>.
+     * @param out the output <code>OutputStream</code>.
+     * @param err the error <code>OutputStream</code>.
+     * @param input the input <code>InputStream</code>.
+     */
+    public PumpStreamHandler(OutputStream out, OutputStream err,
+                             InputStream input) {
+        this.out = out;
+        this.err = err;
+        this.input = input;
+    }
+
+    /**
+     * Construct a new <code>PumpStreamHandler</code>.
+     * @param out the output <code>OutputStream</code>.
+     * @param err the error <code>OutputStream</code>.
+     */
+    public PumpStreamHandler(OutputStream out, OutputStream err) {
+        this(out, err, null);
+    }
+
+    /**
+     * Construct a new <code>PumpStreamHandler</code>.
+     * @param outAndErr the output/error <code>OutputStream</code>.
+     */
+    public PumpStreamHandler(OutputStream outAndErr) {
+        this(outAndErr, outAndErr);
+    }
+
+    /**
+     * Construct a new <code>PumpStreamHandler</code>.
+     */
+    public PumpStreamHandler() {
+        this(System.out, System.err);
+    }
+
+    /**
+     * Set the <code>InputStream</code> from which to read the
+     * standard output of the process.
+     * @param is the <code>InputStream</code>.
+     */
+    public void setProcessOutputStream(InputStream is) {
+        createProcessOutputPump(is, out);
+    }
+
+    /**
+     * Set the <code>InputStream</code> from which to read the
+     * standard error of the process.
+     * @param is the <code>InputStream</code>.
+     */
+    public void setProcessErrorStream(InputStream is) {
+        if (err != null) {
+            createProcessErrorPump(is, err);
+        }
+    }
+
+    /**
+     * Set the <code>OutputStream</code> by means of which
+     * input can be sent to the process.
+     * @param os the <code>OutputStream</code>.
+     */
+    public void setProcessInputStream(OutputStream os) {
+        if (input != null) {
+            inputPump = createInputPump(input, os, true);
+        } else {
+            try {
+                os.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Start the <code>Thread</code>s.
+     */
+    public void start() {
+        outputThread.start();
+        errorThread.start();
+        if (inputPump != null) {
+            Thread inputThread = new Thread(inputPump);
+            inputThread.setDaemon(true);
+            inputThread.start();
+        }
+    }
+
+    /**
+     * Stop pumping the streams.
+     */
+    public void stop() {
+        try {
+            outputThread.join();
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        try {
+            errorThread.join();
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        if (inputPump != null) {
+            inputPump.stop();
+        }
+
+        try {
+            err.flush();
+        } catch (IOException e) {
+            // ignore
+        }
+        try {
+            out.flush();
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    /**
+     * Get the error stream.
+     * @return <code>OutputStream</code>.
+     */
+    protected OutputStream getErr() {
+        return err;
+    }
+
+    /**
+     * Get the output stream.
+     * @return <code>OutputStream</code>.
+     */
+    protected OutputStream getOut() {
+        return out;
+    }
+
+    /**
+     * Create the pump to handle process output.
+     * @param is the <code>InputStream</code>.
+     * @param os the <code>OutputStream</code>.
+     */
+    protected void createProcessOutputPump(InputStream is, OutputStream os) {
+        outputThread = createPump(is, os);
+    }
+
+    /**
+     * Create the pump to handle error output.
+     * @param is the input stream to copy from.
+     * @param os the output stream to copy to.
+     */
+    protected void createProcessErrorPump(InputStream is, OutputStream os) {
+        errorThread = createPump(is, os);
+    }
+
+    /**
+     * Creates a stream pumper to copy the given input stream to the
+     * given output stream.
+     * @param is the input stream to copy from.
+     * @param os the output stream to copy to.
+     * @return a thread object that does the pumping.
+     */
+    protected Thread createPump(InputStream is, OutputStream os) {
+        return createPump(is, os, false);
+    }
+
+    /**
+     * Creates a stream pumper to copy the given input stream to the
+     * given output stream.
+     * @param is the input stream to copy from.
+     * @param os the output stream to copy to.
+     * @param closeWhenExhausted if true close the inputstream.
+     * @return a thread object that does the pumping.
+     */
+    protected Thread createPump(InputStream is, OutputStream os,
+                                boolean closeWhenExhausted) {
+        final Thread result
+            = new Thread(new StreamPumper(is, os, closeWhenExhausted));
+        result.setDaemon(true);
+        return result;
+    }
+
+    /**
+     * Creates a stream pumper to copy the given input stream to the
+     * given output stream. Used for standard input.
+     * @since Ant 1.6.3
+     */
+    /*protected*/ StreamPumper createInputPump(InputStream is, OutputStream os,
+                                boolean closeWhenExhausted) {
+        StreamPumper pumper = new StreamPumper(is, os, closeWhenExhausted);
+        pumper.setAutoflush(true);
+        return pumper;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Recorder.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Recorder.java
new file mode 100644
index 0000000..a0c090f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Recorder.java
@@ -0,0 +1,313 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Hashtable;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.SubBuildListener;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.LogLevel;
+
+/**
+ * Adds a listener to the current build process that records the
+ * output to a file.
+ * <p>Several recorders can exist at the same time.  Each recorder is
+ * associated with a file.  The filename is used as a unique identifier for
+ * the recorders.  The first call to the recorder task with an unused filename
+ * will create a recorder (using the parameters provided) and add it to the
+ * listeners of the build.  All subsequent calls to the recorder task using
+ * this filename will modify that recorders state (recording or not) or other
+ * properties (like logging level).</p>
+ * <p>Some technical issues: the file's print stream is flushed for &quot;finished&quot;
+ * events (buildFinished, targetFinished and taskFinished), and is closed on
+ * a buildFinished event.</p>
+ * @see RecorderEntry
+ * @version 0.5
+ * @since Ant 1.4
+ * @ant.task name="record" category="utility"
+ */
+public class Recorder extends Task implements SubBuildListener {
+
+    //////////////////////////////////////////////////////////////////////
+    // ATTRIBUTES
+
+    /** The name of the file to record to. */
+    private String filename = null;
+    /**
+     * Whether or not to append. Need Boolean to record an unset state (null).
+     */
+    private Boolean append = null;
+    /**
+     * Whether to start or stop recording. Need Boolean to record an unset
+     * state (null).
+     */
+    private Boolean start = null;
+    /** The level to log at. A level of -1 means not initialized yet. */
+    private int loglevel = -1;
+    /** Strip task banners if true.  */
+    private boolean emacsMode = false;
+    /** The list of recorder entries. */
+    private static Hashtable recorderEntries = new Hashtable();
+
+    //////////////////////////////////////////////////////////////////////
+    // CONSTRUCTORS / INITIALIZERS
+
+    /**
+     * Overridden so we can add the task as build listener.
+     *
+     * @since Ant 1.7
+     */
+    public void init() {
+        getProject().addBuildListener(this);
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // ACCESSOR METHODS
+
+    /**
+     * Sets the name of the file to log to, and the name of the recorder
+     * entry.
+     *
+     * @param fname File name of logfile.
+     */
+    public void setName(String fname) {
+        filename = fname;
+    }
+
+
+    /**
+     * Sets the action for the associated recorder entry.
+     *
+     * @param action The action for the entry to take: start or stop.
+     */
+    public void setAction(ActionChoices action) {
+        if (action.getValue().equalsIgnoreCase("start")) {
+            start = Boolean.TRUE;
+        } else {
+            start = Boolean.FALSE;
+        }
+    }
+
+
+    /**
+     * Whether or not the logger should append to a previous file.
+     * @param append if true, append to a previous file.
+     */
+    public void setAppend(boolean append) {
+        this.append = (append ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+
+    /**
+     * Set emacs mode.
+     * @param emacsMode if true use emacs mode
+     */
+    public void setEmacsMode(boolean emacsMode) {
+        this.emacsMode = emacsMode;
+    }
+
+
+    /**
+     * Sets the level to which this recorder entry should log to.
+     * @param level the level to set.
+     * @see VerbosityLevelChoices
+     */
+    public void setLoglevel(VerbosityLevelChoices level) {
+        loglevel = level.getLevel();
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // CORE / MAIN BODY
+
+    /**
+     * The main execution.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (filename == null) {
+            throw new BuildException("No filename specified");
+        }
+
+        getProject().log("setting a recorder for name " + filename,
+            Project.MSG_DEBUG);
+
+        // get the recorder entry
+        RecorderEntry recorder = getRecorder(filename, getProject());
+        // set the values on the recorder
+        recorder.setMessageOutputLevel(loglevel);
+        recorder.setEmacsMode(emacsMode);
+        if (start != null) {
+            if (start.booleanValue()) {
+                recorder.reopenFile();
+                recorder.setRecordState(start);
+            } else {
+                recorder.setRecordState(start);
+                recorder.closeFile();
+            }
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // INNER CLASSES
+
+    /**
+     * A list of possible values for the <code>setAction()</code> method.
+     * Possible values include: start and stop.
+     */
+    public static class ActionChoices extends EnumeratedAttribute {
+        private static final String[] VALUES = {"start", "stop"};
+
+        /**
+         * @see EnumeratedAttribute#getValues()
+         */
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return VALUES;
+        }
+    }
+
+
+    /**
+     * A list of possible values for the <code>setLoglevel()</code> method.
+     * Possible values include: error, warn, info, verbose, debug.
+     */
+    public static class VerbosityLevelChoices extends LogLevel {
+    }
+
+
+    /**
+     * Gets the recorder that's associated with the passed in name. If the
+     * recorder doesn't exist, then a new one is created.
+     * @param name the name of the recoder
+     * @param proj the current project
+     * @return a recorder
+     * @throws BuildException on error
+     */
+    protected RecorderEntry getRecorder(String name, Project proj)
+         throws BuildException {
+        Object o = recorderEntries.get(name);
+        RecorderEntry entry;
+
+        if (o == null) {
+            // create a recorder entry
+            entry = new RecorderEntry(name);
+
+            if (append == null) {
+                entry.openFile(false);
+            } else {
+                entry.openFile(append.booleanValue());
+            }
+            entry.setProject(proj);
+            recorderEntries.put(name, entry);
+        } else {
+            entry = (RecorderEntry) o;
+        }
+        return entry;
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void buildStarted(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void subBuildStarted(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void targetStarted(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void targetFinished(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void taskStarted(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void taskFinished(BuildEvent event) {
+    }
+
+    /**
+     * Empty implementation required by SubBuildListener interface.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void messageLogged(BuildEvent event) {
+    }
+
+    /**
+     * Cleans recorder registry.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void buildFinished(BuildEvent event) {
+        cleanup();
+    }
+
+    /**
+     * Cleans recorder registry, if this is the subbuild the task has
+     * been created in.
+     * @param event ignored.
+     * @since Ant 1.7
+     */
+    public void subBuildFinished(BuildEvent event) {
+        if (event.getProject() == getProject()) {
+            cleanup();
+        }
+    }
+
+    /**
+     * cleans recorder registry and removes itself from BuildListener list.
+     *
+     * @since Ant 1.7
+     */
+    private void cleanup() {
+        recorderEntries.clear();
+        getProject().removeBuildListener(this);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java b/trunk/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java
new file mode 100644
index 0000000..dbf1f12
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/RecorderEntry.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildLogger;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.SubBuildListener;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * This is a class that represents a recorder. This is the listener to the
+ * build process.
+ *
+ * @since Ant 1.4
+ */
+public class RecorderEntry implements BuildLogger, SubBuildListener {
+
+    //////////////////////////////////////////////////////////////////////
+    // ATTRIBUTES
+
+    /** The name of the file associated with this recorder entry.  */
+    private String filename = null;
+    /** The state of the recorder (recorder on or off).  */
+    private boolean record = true;
+    /** The current verbosity level to record at.  */
+    private int loglevel = Project.MSG_INFO;
+    /** The output PrintStream to record to.  */
+    private PrintStream out = null;
+    /** The start time of the last know target.  */
+    private long targetStartTime = 0L;
+    /** Strip task banners if true.  */
+    private boolean emacsMode = false;
+    /** project instance the recorder is associated with */
+    private Project project;
+
+    //////////////////////////////////////////////////////////////////////
+    // CONSTRUCTORS / INITIALIZERS
+
+    /**
+     * @param name The name of this recorder (used as the filename).
+     */
+    protected RecorderEntry(String name) {
+        targetStartTime = System.currentTimeMillis();
+        filename = name;
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // ACCESSOR METHODS
+
+    /**
+     * @return the name of the file the output is sent to.
+     */
+    public String getFilename() {
+        return filename;
+    }
+
+    /**
+     * Turns off or on this recorder.
+     *
+     * @param state true for on, false for off, null for no change.
+     */
+    public void setRecordState(Boolean state) {
+        if (state != null) {
+            flush();
+            record = state.booleanValue();
+        }
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#buildStarted(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void buildStarted(BuildEvent event) {
+        log("> BUILD STARTED", Project.MSG_DEBUG);
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#buildFinished(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void buildFinished(BuildEvent event) {
+        log("< BUILD FINISHED", Project.MSG_DEBUG);
+
+        if (record && out != null) {
+            Throwable error = event.getException();
+
+            if (error == null) {
+                out.println(StringUtils.LINE_SEP + "BUILD SUCCESSFUL");
+            } else {
+                out.println(StringUtils.LINE_SEP + "BUILD FAILED"
+                            + StringUtils.LINE_SEP);
+                error.printStackTrace(out);
+            }
+        }
+        cleanup();
+    }
+
+    /**
+     * Cleans up any resources held by this recorder entry at the end
+     * of a subbuild if it has been created for the subbuild's project
+     * instance.
+     *
+     * @param event the buildFinished event
+     *
+     * @since Ant 1.6.2
+     */
+    public void subBuildFinished(BuildEvent event) {
+        if (event.getProject() == project) {
+            cleanup();
+        }
+    }
+
+    /**
+     * Empty implementation to satisfy the BuildListener interface.
+     *
+     * @param event the buildStarted event
+     *
+     * @since Ant 1.6.2
+     */
+    public void subBuildStarted(BuildEvent event) {
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#targetStarted(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void targetStarted(BuildEvent event) {
+        log(">> TARGET STARTED -- " + event.getTarget(), Project.MSG_DEBUG);
+        log(StringUtils.LINE_SEP + event.getTarget().getName() + ":",
+            Project.MSG_INFO);
+        targetStartTime = System.currentTimeMillis();
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#targetFinished(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void targetFinished(BuildEvent event) {
+        log("<< TARGET FINISHED -- " + event.getTarget(), Project.MSG_DEBUG);
+
+        String time = formatTime(System.currentTimeMillis() - targetStartTime);
+
+        log(event.getTarget() + ":  duration " + time, Project.MSG_VERBOSE);
+        flush();
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#taskStarted(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void taskStarted(BuildEvent event) {
+        log(">>> TASK STARTED -- " + event.getTask(), Project.MSG_DEBUG);
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#taskFinished(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void taskFinished(BuildEvent event) {
+        log("<<< TASK FINISHED -- " + event.getTask(), Project.MSG_DEBUG);
+        flush();
+    }
+
+    /**
+     * @see org.apache.tools.ant.BuildListener#messageLogged(BuildEvent)
+     */
+    /** {@inheritDoc}. */
+    public void messageLogged(BuildEvent event) {
+        log("--- MESSAGE LOGGED", Project.MSG_DEBUG);
+
+        StringBuffer buf = new StringBuffer();
+
+        if (event.getTask() != null) {
+            String name = event.getTask().getTaskName();
+
+            if (!emacsMode) {
+                String label = "[" + name + "] ";
+                int size = DefaultLogger.LEFT_COLUMN_SIZE - label.length();
+
+                for (int i = 0; i < size; i++) {
+                    buf.append(" ");
+                }
+                buf.append(label);
+            }
+        }
+        buf.append(event.getMessage());
+
+        log(buf.toString(), event.getPriority());
+    }
+
+
+    /**
+     * The thing that actually sends the information to the output.
+     *
+     * @param mesg The message to log.
+     * @param level The verbosity level of the message.
+     */
+    private void log(String mesg, int level) {
+        if (record && (level <= loglevel) && out != null) {
+            out.println(mesg);
+        }
+    }
+
+    private void flush() {
+        if (record && out != null) {
+            out.flush();
+        }
+    }
+
+    /**
+     * @see BuildLogger#setMessageOutputLevel(int)
+     */
+    /** {@inheritDoc}. */
+    public void setMessageOutputLevel(int level) {
+        if (level >= Project.MSG_ERR && level <= Project.MSG_DEBUG) {
+            loglevel = level;
+        }
+    }
+
+    /**
+     * @see BuildLogger#setOutputPrintStream(PrintStream)
+     */
+    /** {@inheritDoc}. */
+    public void setOutputPrintStream(PrintStream output) {
+        closeFile();
+        out = output;
+    }
+
+
+    /**
+     * @see BuildLogger#setEmacsMode(boolean)
+     */
+    /** {@inheritDoc}. */
+    public void setEmacsMode(boolean emacsMode) {
+        this.emacsMode = emacsMode;
+    }
+
+
+    /**
+     * @see BuildLogger#setErrorPrintStream(PrintStream)
+     */
+    /** {@inheritDoc}. */
+    public void setErrorPrintStream(PrintStream err) {
+        setOutputPrintStream(err);
+    }
+
+
+    private static String formatTime(long millis) {
+        // CheckStyle:MagicNumber OFF
+        long seconds = millis / 1000;
+        long minutes = seconds / 60;
+
+
+        if (minutes > 0) {
+            return Long.toString(minutes) + " minute"
+                 + (minutes == 1 ? " " : "s ")
+                 + Long.toString(seconds % 60) + " second"
+                 + (seconds % 60 == 1 ? "" : "s");
+        } else {
+            return Long.toString(seconds) + " second"
+                 + (seconds % 60 == 1 ? "" : "s");
+        }
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Set the project associated with this recorder entry.
+     *
+     * @param project the project instance
+     *
+     * @since 1.6.2
+     */
+    public void setProject(Project project) {
+        this.project = project;
+        if (project != null) {
+            project.addBuildListener(this);
+        }
+    }
+
+    /**
+     * @since 1.6.2
+     */
+    public void cleanup() {
+        closeFile();
+        if (project != null) {
+            project.removeBuildListener(this);
+        }
+        project = null;
+    }
+
+    /**
+     * Initially opens the file associated with this recorder.
+     * Used by Recorder.
+     * @param append Indicates if output must be appended to the logfile or that
+     * the logfile should be overwritten.
+     * @throws BuildException
+     * @since 1.6.3
+     */
+    void openFile(boolean append) throws BuildException {
+        openFileImpl(append);
+    }
+
+    /**
+     * Closes the file associated with this recorder.
+     * Used by Recorder.
+     * @since 1.6.3
+     */
+    void closeFile() {
+        if (out != null) {
+            out.close();
+            out = null;
+        }
+    }
+
+    /**
+     * Re-opens the file associated with this recorder.
+     * Used by Recorder.
+     * @throws BuildException
+     * @since 1.6.3
+     */
+    void reopenFile() throws BuildException {
+        openFileImpl(true);
+    }
+
+    private void openFileImpl(boolean append) throws BuildException {
+        if (out == null) {
+            try {
+                out = new PrintStream(new FileOutputStream(filename, append));
+            } catch (IOException ioe) {
+                throw new BuildException("Problems opening file using a "
+                                         + "recorder entry", ioe);
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java
new file mode 100644
index 0000000..0c70a9e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Redirector.java
@@ -0,0 +1,839 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.PipedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+import org.apache.tools.ant.util.ReaderInputStream;
+import org.apache.tools.ant.util.LeadPipeInputStream;
+import org.apache.tools.ant.util.LazyFileOutputStream;
+import org.apache.tools.ant.util.OutputStreamFunneler;
+import org.apache.tools.ant.util.ConcatFileInputStream;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+
+/**
+ * The Redirector class manages the setup and connection of
+ * input and output redirection for an Ant project component.
+ *
+ * @since Ant 1.6
+ */
+public class Redirector {
+    private static final int STREAMPUMPER_WAIT_INTERVAL = 1000;
+
+    private static final String DEFAULT_ENCODING
+        = System.getProperty("file.encoding");
+
+    private class PropertyOutputStream extends ByteArrayOutputStream {
+        private String property;
+        private boolean closed = false;
+
+        PropertyOutputStream(String property) {
+            super();
+            this.property = property;
+        }
+
+        public void close() throws IOException {
+            if (!closed && !(append && appendProperties)) {
+                setPropertyFromBAOS(this, property);
+                closed = true;
+            }
+        }
+    }
+
+    /**
+     * The file(s) from which standard input is being taken.
+     * If &gt; 1, files' content will be concatenated in the order received.
+     */
+    private File[] input;
+
+    /**
+     * The file(s) receiving standard output. Will also receive standard error
+     * unless standard error is redirected or logError is true.
+     */
+    private File[] out;
+
+    /**
+     * The file(s) to which standard error is being redirected
+     */
+    private File[] error;
+
+    /**
+      * Indicates if standard error should be logged to Ant's log system
+      * rather than the output. This has no effect if standard error is
+      * redirected to a file or property.
+      */
+    private boolean logError = false;
+
+    /**
+     * Buffer used to capture output for storage into a property
+     */
+    private PropertyOutputStream baos = null;
+
+    /**
+     * Buffer used to capture error output for storage into a property
+     */
+    private PropertyOutputStream errorBaos = null;
+
+    /** The name of the property into which output is to be stored */
+    private String outputProperty;
+
+    /** The name of the property into which error output is to be stored */
+    private String errorProperty;
+
+    /** String from which input is taken */
+    private String inputString;
+
+    /** Flag which indicates if error and output files are to be appended. */
+    private boolean append = false;
+
+    /** Flag which indicates that output should be always sent to the log */
+    private boolean alwaysLog = false;
+
+    /** Flag which indicates whether files should be created even when empty. */
+    private boolean createEmptyFiles = true;
+
+    /** The task for which this redirector is working */
+    private ProjectComponent managingTask;
+
+    /** The stream for output data */
+    private OutputStream outputStream = null;
+
+    /** The stream for error output */
+    private OutputStream errorStream = null;
+
+    /** The stream for input */
+    private InputStream inputStream = null;
+
+    /** Stream which is used for line oriented output */
+    private PrintStream outPrintStream = null;
+
+    /** Stream which is used for line oriented error output */
+    private PrintStream errorPrintStream = null;
+
+    /** The output filter chains */
+    private Vector outputFilterChains;
+
+    /** The error filter chains */
+    private Vector errorFilterChains;
+
+    /** The input filter chains */
+    private Vector inputFilterChains;
+
+    /** The output encoding */
+    private String outputEncoding = DEFAULT_ENCODING;
+
+    /** The error encoding */
+    private String errorEncoding = DEFAULT_ENCODING;
+
+    /** The input encoding */
+    private String inputEncoding = DEFAULT_ENCODING;
+
+    /** Whether to complete properties settings **/
+    private boolean appendProperties = true;
+
+    /** The thread group used for starting <code>StreamPumper</code> threads */
+    private ThreadGroup threadGroup = new ThreadGroup("redirector");
+
+    /** whether to log the inputstring */
+    private boolean logInputString = true;
+
+    /**
+     * Create a redirector instance for the given task
+     *
+     * @param managingTask the task for which the redirector is to work
+     */
+    public Redirector(Task managingTask) {
+        this((ProjectComponent) managingTask);
+    }
+
+    /**
+     * Create a redirector instance for the given task
+     *
+     * @param managingTask the project component for which the
+     * redirector is to work
+     * @since Ant 1.6.3
+     */
+    public Redirector(ProjectComponent managingTask) {
+        this.managingTask = managingTask;
+    }
+
+    /**
+     * Set the input to use for the task
+     *
+     * @param input the file from which input is read.
+     */
+    public void setInput(File input) {
+        setInput((input == null) ? null : new File[] {input});
+    }
+
+    /**
+     * Set the input to use for the task
+     *
+     * @param input the files from which input is read.
+     */
+    public synchronized void setInput(File[] input) {
+        this.input = input;
+    }
+
+    /**
+     * Set the string to use as input
+     *
+     * @param inputString the string which is used as the input source
+     */
+    public synchronized void setInputString(String inputString) {
+        this.inputString = inputString;
+    }
+
+    /**
+     * Set whether to include the value of the input string in log messages.
+     * Defaults to true.
+     * @param logInputString true or false.
+     * @since Ant 1.7
+     */
+    public void setLogInputString(boolean logInputString) {
+        this.logInputString = logInputString;
+    }
+
+    /**
+     * Set a stream to use as input.
+     *
+     * @param inputStream the stream from which input will be read
+     * @since Ant 1.6.3
+     */
+    /*public*/ void setInputStream(InputStream inputStream) {
+        this.inputStream = inputStream;
+    }
+
+    /**
+     * File the output of the process is redirected to. If error is not
+     * redirected, it too will appear in the output
+     *
+     * @param out the file to which output stream is written
+     */
+    public void setOutput(File out) {
+        setOutput((out == null) ? null : new File[] {out});
+    }
+
+    /**
+     * Files the output of the process is redirected to. If error is not
+     * redirected, it too will appear in the output
+     *
+     * @param out the files to which output stream is written
+     */
+    public synchronized void setOutput(File[] out) {
+        this.out = out;
+    }
+
+    /**
+     * Set the output encoding.
+     *
+     * @param outputEncoding   <code>String</code>.
+     */
+    public synchronized void setOutputEncoding(String outputEncoding) {
+        if (outputEncoding == null) {
+            throw new IllegalArgumentException(
+                "outputEncoding must not be null");
+        } else {
+            this.outputEncoding = outputEncoding;
+        }
+    }
+
+    /**
+     * Set the error encoding.
+     *
+     * @param errorEncoding   <code>String</code>.
+     */
+    public synchronized void setErrorEncoding(String errorEncoding) {
+        if (errorEncoding == null) {
+            throw new IllegalArgumentException(
+                "errorEncoding must not be null");
+        } else {
+            this.errorEncoding = errorEncoding;
+        }
+    }
+
+    /**
+     * Set the input encoding.
+     *
+     * @param inputEncoding   <code>String</code>.
+     */
+    public synchronized void setInputEncoding(String inputEncoding) {
+        if (inputEncoding == null) {
+            throw new IllegalArgumentException(
+                "inputEncoding must not be null");
+        } else {
+            this.inputEncoding = inputEncoding;
+        }
+    }
+
+    /**
+     * Controls whether error output of exec is logged. This is only useful
+     * when output is being redirected and error output is desired in the
+     * Ant log
+     *
+     * @param logError if true the standard error is sent to the Ant log system
+     *        and not sent to output.
+     */
+    public synchronized void setLogError(boolean logError) {
+        this.logError = logError;
+    }
+
+    /**
+     * This <code>Redirector</code>'s subordinate
+     * <code>PropertyOutputStream</code>s will not set their respective
+     * properties <code>while (appendProperties && append)</code>.
+     *
+     * @param appendProperties whether to append properties.
+     */
+    public synchronized void setAppendProperties(boolean appendProperties) {
+        this.appendProperties = appendProperties;
+    }
+
+    /**
+     * Set the file to which standard error is to be redirected.
+     *
+     * @param error the file to which error is to be written
+     */
+    public void setError(File error) {
+        setError((error == null) ? null : new File[] {error});
+    }
+
+    /**
+     * Set the files to which standard error is to be redirected.
+     *
+     * @param error the file to which error is to be written
+     */
+    public synchronized void setError(File[] error) {
+        this.error = error;
+    }
+
+    /**
+     * Property name whose value should be set to the output of
+     * the process.
+     *
+     * @param outputProperty the name of the property to be set with the
+     *        task's output.
+     */
+    public synchronized void setOutputProperty(String outputProperty) {
+        if (outputProperty == null
+         || !(outputProperty.equals(this.outputProperty))) {
+            this.outputProperty = outputProperty;
+            baos = null;
+        }
+    }
+
+    /**
+     * Whether output should be appended to or overwrite an existing file.
+     * Defaults to false.
+     *
+     * @param append if true output and error streams are appended to their
+     *        respective files, if specified.
+     */
+    public synchronized void setAppend(boolean append) {
+        this.append = append;
+    }
+
+    /**
+     * If true, (error and non-error) output will be "teed", redirected
+     * as specified while being sent to Ant's logging mechanism as if no
+     * redirection had taken place.  Defaults to false.
+     * @param alwaysLog <code>boolean</code>
+     * @since Ant 1.6.3
+     */
+    public synchronized void setAlwaysLog(boolean alwaysLog) {
+        this.alwaysLog = alwaysLog;
+    }
+
+    /**
+     * Whether output and error files should be created even when empty.
+     * Defaults to true.
+     * @param createEmptyFiles <code>boolean</code>.
+     */
+    public synchronized void setCreateEmptyFiles(boolean createEmptyFiles) {
+        this.createEmptyFiles = createEmptyFiles;
+    }
+
+    /**
+     * Property name whose value should be set to the error of
+     * the process.
+     *
+     * @param errorProperty the name of the property to be set
+     *        with the error output.
+     */
+    public synchronized void setErrorProperty(String errorProperty) {
+        if (errorProperty == null
+         || !(errorProperty.equals(this.errorProperty))) {
+            this.errorProperty = errorProperty;
+            errorBaos = null;
+        }
+    }
+
+    /**
+     * Set the input <code>FilterChain</code>s.
+     *
+     * @param inputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
+     */
+    public synchronized void setInputFilterChains(Vector inputFilterChains) {
+        this.inputFilterChains = inputFilterChains;
+    }
+
+    /**
+     * Set the output <code>FilterChain</code>s.
+     *
+     * @param outputFilterChains <code>Vector</code> containing <code>FilterChain</code>.
+     */
+    public synchronized void setOutputFilterChains(Vector outputFilterChains) {
+        this.outputFilterChains = outputFilterChains;
+    }
+
+    /**
+     * Set the error <code>FilterChain</code>s.
+     *
+     * @param errorFilterChains <code>Vector</code> containing <code>FilterChain</code>.
+     */
+    public synchronized void setErrorFilterChains(Vector errorFilterChains) {
+        this.errorFilterChains = errorFilterChains;
+    }
+
+    /**
+     * Set a property from a ByteArrayOutputStream
+     *
+     * @param baos contains the property value.
+     * @param propertyName the property name.
+     *
+     * @exception IOException if the value cannot be read form the stream.
+     */
+    private void setPropertyFromBAOS(ByteArrayOutputStream baos,
+                                     String propertyName) throws IOException {
+
+        BufferedReader in
+            = new BufferedReader(new StringReader(Execute.toString(baos)));
+        String line = null;
+        StringBuffer val = new StringBuffer();
+        while ((line = in.readLine()) != null) {
+            if (val.length() != 0) {
+                val.append(StringUtils.LINE_SEP);
+            }
+            val.append(line);
+        }
+        managingTask.getProject().setNewProperty(propertyName, val.toString());
+    }
+
+    /**
+     * Create the input, error and output streams based on the
+     * configuration options.
+     */
+    public synchronized void createStreams() {
+        outStreams();
+        errorStreams();
+        if (alwaysLog || outputStream == null) {
+            OutputStream outputLog
+                = new LogOutputStream(managingTask, Project.MSG_INFO);
+            outputStream = (outputStream == null)
+                ? outputLog : new TeeOutputStream(outputLog, outputStream);
+        }
+        if (alwaysLog || errorStream == null) {
+            OutputStream errorLog
+                = new LogOutputStream(managingTask, Project.MSG_WARN);
+            errorStream = (errorStream == null)
+                ? errorLog : new TeeOutputStream(errorLog, errorStream);
+        }
+        if ((outputFilterChains != null && outputFilterChains.size() > 0)
+            || !(outputEncoding.equalsIgnoreCase(inputEncoding))) {
+            try {
+                LeadPipeInputStream snk = new LeadPipeInputStream();
+                snk.setManagingComponent(managingTask);
+
+                InputStream outPumpIn = snk;
+
+                Reader reader = new InputStreamReader(outPumpIn, inputEncoding);
+
+                if (outputFilterChains != null && outputFilterChains.size() > 0) {
+                    ChainReaderHelper helper = new ChainReaderHelper();
+                    helper.setProject(managingTask.getProject());
+                    helper.setPrimaryReader(reader);
+                    helper.setFilterChains(outputFilterChains);
+                    reader = helper.getAssembledReader();
+                }
+                outPumpIn = new ReaderInputStream(reader, outputEncoding);
+
+                Thread t = new Thread(threadGroup, new StreamPumper(
+                    outPumpIn, outputStream, true), "output pumper");
+                t.setPriority(Thread.MAX_PRIORITY);
+                outputStream = new PipedOutputStream(snk);
+                t.start();
+            } catch (IOException eyeOhEx) {
+                throw new BuildException(
+                    "error setting up output stream", eyeOhEx);
+            }
+        }
+
+        if ((errorFilterChains != null && errorFilterChains.size() > 0)
+            || !(errorEncoding.equalsIgnoreCase(inputEncoding))) {
+            try {
+                LeadPipeInputStream snk = new LeadPipeInputStream();
+                snk.setManagingComponent(managingTask);
+
+                InputStream errPumpIn = snk;
+
+                Reader reader = new InputStreamReader(errPumpIn, inputEncoding);
+
+                if (errorFilterChains != null && errorFilterChains.size() > 0) {
+                    ChainReaderHelper helper = new ChainReaderHelper();
+                    helper.setProject(managingTask.getProject());
+                    helper.setPrimaryReader(reader);
+                    helper.setFilterChains(errorFilterChains);
+                    reader = helper.getAssembledReader();
+                }
+                errPumpIn = new ReaderInputStream(reader, errorEncoding);
+
+                Thread t = new Thread(threadGroup, new StreamPumper(
+                    errPumpIn, errorStream, true), "error pumper");
+                t.setPriority(Thread.MAX_PRIORITY);
+                errorStream = new PipedOutputStream(snk);
+                t.start();
+            } catch (IOException eyeOhEx) {
+                throw new BuildException(
+                    "error setting up error stream", eyeOhEx);
+            }
+        }
+
+        // if input files are specified, inputString and inputStream are ignored;
+        // classes that work with redirector attributes can enforce
+        // whatever warnings are needed
+        if (input != null && input.length > 0) {
+            managingTask.log("Redirecting input from file"
+                + ((input.length == 1) ? "" : "s"), Project.MSG_VERBOSE);
+            try {
+                inputStream = new ConcatFileInputStream(input);
+            } catch (IOException eyeOhEx) {
+                throw new BuildException(eyeOhEx);
+            }
+            ((ConcatFileInputStream) inputStream).setManagingComponent(managingTask);
+        } else if (inputString != null) {
+            StringBuffer buf = new StringBuffer("Using input ");
+            if (logInputString) {
+                buf.append('"').append(inputString).append('"');
+            } else {
+                buf.append("string");
+            }
+            managingTask.log(buf.toString(), Project.MSG_VERBOSE);
+            inputStream = new ByteArrayInputStream(inputString.getBytes());
+        }
+
+        if (inputStream != null
+            && inputFilterChains != null && inputFilterChains.size() > 0) {
+            ChainReaderHelper helper = new ChainReaderHelper();
+            helper.setProject(managingTask.getProject());
+            try {
+                helper.setPrimaryReader(
+                    new InputStreamReader(inputStream, inputEncoding));
+            } catch (IOException eyeOhEx) {
+                throw new BuildException(
+                    "error setting up input stream", eyeOhEx);
+            }
+            helper.setFilterChains(inputFilterChains);
+            inputStream = new ReaderInputStream(
+                helper.getAssembledReader(), inputEncoding);
+        }
+    }
+
+    /** outStreams */
+    private void outStreams() {
+        if (out != null && out.length > 0) {
+            String logHead = new StringBuffer("Output ").append(
+                ((append) ? "appended" : "redirected")).append(
+                " to ").toString();
+            outputStream = foldFiles(out, logHead, Project.MSG_VERBOSE);
+        }
+        if (outputProperty != null) {
+            if (baos == null) {
+                baos = new PropertyOutputStream(outputProperty);
+                managingTask.log("Output redirected to property: "
+                    + outputProperty, Project.MSG_VERBOSE);
+            }
+            //shield it from being closed by a filtering StreamPumper
+            OutputStream keepAliveOutput = new KeepAliveOutputStream(baos);
+            outputStream = (outputStream == null) ? keepAliveOutput
+                : new TeeOutputStream(outputStream, keepAliveOutput);
+        } else {
+            baos = null;
+        }
+    }
+
+    private void errorStreams() {
+        if (error != null && error.length > 0) {
+            String logHead = new StringBuffer("Error ").append(
+                ((append) ? "appended" : "redirected")).append(
+                " to ").toString();
+            errorStream = foldFiles(error, logHead, Project.MSG_VERBOSE);
+        } else if (!(logError || outputStream == null)) {
+            long funnelTimeout = 0L;
+            OutputStreamFunneler funneler
+                = new OutputStreamFunneler(outputStream, funnelTimeout);
+            try {
+                outputStream = funneler.getFunnelInstance();
+                errorStream = funneler.getFunnelInstance();
+            } catch (IOException eyeOhEx) {
+                throw new BuildException(
+                    "error splitting output/error streams", eyeOhEx);
+            }
+        }
+        if (errorProperty != null) {
+            if (errorBaos == null) {
+                errorBaos = new PropertyOutputStream(errorProperty);
+                managingTask.log("Error redirected to property: " + errorProperty,
+                    Project.MSG_VERBOSE);
+            }
+            //shield it from being closed by a filtering StreamPumper
+            OutputStream keepAliveError = new KeepAliveOutputStream(errorBaos);
+            errorStream = (error == null || error.length == 0) ? keepAliveError
+                : new TeeOutputStream(errorStream, keepAliveError);
+        } else {
+            errorBaos = null;
+        }
+    }
+
+    /**
+     * Create the StreamHandler to use with our Execute instance.
+     *
+     * @return the execute stream handler to manage the input, output and
+     * error streams.
+     *
+     * @throws BuildException if the execute stream handler cannot be created.
+     */
+    public synchronized ExecuteStreamHandler createHandler()
+        throws BuildException {
+        createStreams();
+        return new PumpStreamHandler(outputStream, errorStream, inputStream);
+    }
+
+    /**
+     * Pass output sent to System.out to specified output.
+     *
+     * @param output the data to be output
+     */
+    protected synchronized void handleOutput(String output) {
+        if (outPrintStream == null) {
+            outPrintStream = new PrintStream(outputStream);
+        }
+        outPrintStream.print(output);
+    }
+
+    /**
+     * Handle an input request
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read
+     *
+     * @return the number of bytes read
+     *
+     * @exception IOException if the data cannot be read
+     */
+    protected synchronized int handleInput(byte[] buffer, int offset,
+                                           int length) throws IOException {
+        if (inputStream == null) {
+            return managingTask.getProject().defaultInput(buffer, offset,
+                                                          length);
+        } else {
+            return inputStream.read(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Process data due to a flush operation.
+     *
+     * @param output the data being flushed.
+     */
+    protected synchronized void handleFlush(String output) {
+        if (outPrintStream == null) {
+            outPrintStream = new PrintStream(outputStream);
+        }
+        outPrintStream.print(output);
+        outPrintStream.flush();
+    }
+
+    /**
+     * Process error output
+     *
+     * @param output the error output data.
+     */
+    protected synchronized void handleErrorOutput(String output) {
+        if (errorPrintStream == null) {
+            errorPrintStream = new PrintStream(errorStream);
+        }
+        errorPrintStream.print(output);
+    }
+
+    /**
+     * Handle a flush operation on the error stream
+     *
+     * @param output the error information being flushed.
+     */
+    protected synchronized void handleErrorFlush(String output) {
+        if (errorPrintStream == null) {
+            errorPrintStream = new PrintStream(errorStream);
+        }
+        errorPrintStream.print(output);
+    }
+
+    /**
+     * Get the output stream for the redirector
+     *
+     * @return the redirector's output stream or null if no output
+     *         has been configured
+     */
+    public synchronized OutputStream getOutputStream() {
+        return outputStream;
+    }
+
+    /**
+     * Get the error stream for the redirector
+     *
+     * @return the redirector's error stream or null if no output
+     *         has been configured
+     */
+    public synchronized OutputStream getErrorStream() {
+        return errorStream;
+    }
+
+    /**
+     * Get the input stream for the redirector
+     *
+     * @return the redirector's input stream or null if no output
+     *         has been configured
+     */
+    public synchronized InputStream getInputStream() {
+        return inputStream;
+    }
+
+    /**
+     * Complete redirection.
+     *
+     * This operation will close any streams and create any specified
+     * property values.
+     *
+     * @throws IOException if the output properties cannot be read from their
+     * output streams.
+     */
+    public synchronized void complete() throws IOException {
+        System.out.flush();
+        System.err.flush();
+
+        if (inputStream != null) {
+            inputStream.close();
+        }
+
+        outputStream.flush();
+        outputStream.close();
+
+        errorStream.flush();
+        errorStream.close();
+
+        //wait for the StreamPumpers to finish
+        while (threadGroup.activeCount() > 0) {
+            try {
+                managingTask.log("waiting for " + threadGroup.activeCount()
+                    + " Threads:", Project.MSG_DEBUG);
+                Thread[] thread = new Thread[threadGroup.activeCount()];
+                threadGroup.enumerate(thread);
+                for (int i = 0; i < thread.length && thread[i] != null; i++) {
+                    try {
+                        managingTask.log(thread[i].toString(), Project.MSG_DEBUG);
+                    } catch (NullPointerException enPeaEx) {
+                        // Ignore exception
+                    }
+                }
+                wait(STREAMPUMPER_WAIT_INTERVAL);
+            } catch (InterruptedException eyeEx) {
+                Thread[] thread = new Thread[threadGroup.activeCount()];
+                threadGroup.enumerate(thread);
+                for (int i = 0; i < thread.length && thread[i] != null; i++) {
+                    thread[i].interrupt();
+                }
+            }
+        }
+
+        setProperties();
+
+        inputStream = null;
+        outputStream = null;
+        errorStream = null;
+        outPrintStream = null;
+        errorPrintStream = null;
+   }
+
+    /**
+     * Notify the <code>Redirector</code> that it is now okay
+     * to set any output and/or error properties.
+     */
+    public synchronized void setProperties() {
+        if (baos != null) {
+            try {
+                baos.close();
+            } catch (IOException eyeOhEx) {
+                // Ignore exception
+            }
+        }
+        if (errorBaos != null) {
+            try {
+                errorBaos.close();
+            } catch (IOException eyeOhEx) {
+                // Ignore exception
+            }
+        }
+    }
+
+    private OutputStream foldFiles(File[] file, String logHead, int loglevel) {
+        OutputStream result
+            = new LazyFileOutputStream(file[0], append, createEmptyFiles);
+
+        managingTask.log(logHead + file[0], loglevel);
+        char[] c = new char[logHead.length()];
+        Arrays.fill(c, ' ');
+        String indent = new String(c);
+
+        for (int i = 1; i < file.length; i++) {
+            outputStream = new TeeOutputStream(outputStream,
+                new LazyFileOutputStream(file[i], append, createEmptyFiles));
+            managingTask.log(indent + file[i], loglevel);
+        }
+        return result;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Rename.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Rename.java
new file mode 100644
index 0000000..ed02ecf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Rename.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Renames a file.
+ *
+ * @deprecated The rename task is deprecated since Ant 1.2.  Use move instead.
+ * @since Ant 1.1
+ */
+public class Rename extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File src;
+    private File dest;
+    private boolean replace = true;
+
+
+    /**
+     * Sets the file to be renamed.
+     * @param src the file to rename
+     */
+    public void setSrc(File src) {
+        this.src = src;
+    }
+
+    /**
+     * Sets the new name of the file.
+     * @param dest the new name of the file.
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    /**
+     * Sets whether an existing file should be replaced.
+     * @param replace <code>on</code>, if an existing file should be replaced.
+     */
+    public void setReplace(String replace) {
+        this.replace = Project.toBoolean(replace);
+    }
+
+
+    /**
+     * Renames the file <code>src</code> to <code>dest</code>
+     * @exception org.apache.tools.ant.BuildException The exception is
+     * thrown, if the rename operation fails.
+     */
+    public void execute() throws BuildException {
+        log("DEPRECATED - The rename task is deprecated.  Use move instead.");
+
+        if (dest == null) {
+            throw new BuildException("dest attribute is required", getLocation());
+        }
+
+        if (src == null) {
+            throw new BuildException("src attribute is required", getLocation());
+        }
+
+        if (!replace && dest.exists()) {
+            throw new BuildException(dest + " already exists.");
+        }
+
+        try {
+            FILE_UTILS.rename(src, dest);
+        } catch (IOException e) {
+            throw new BuildException("Unable to rename " + src + " to "
+                + dest, e, getLocation());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Replace.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Replace.java
new file mode 100644
index 0000000..ee8e487
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Replace.java
@@ -0,0 +1,832 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Replaces all occurrences of one or more string tokens with given
+ * values in the indicated files. Each value can be either a string
+ * or the value of a property available in a designated property file.
+ * If you want to replace a text that crosses line boundaries, you
+ * must use a nested <code>&lt;replacetoken&gt;</code> element.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+public class Replace extends MatchingTask {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File src = null;
+    private NestedString token = null;
+    private NestedString value = new NestedString();
+
+    private File propertyFile = null;
+    private File replaceFilterFile = null;
+    private Properties properties = null;
+    private Vector replacefilters = new Vector();
+
+    private File dir = null;
+
+    private int fileCount;
+    private int replaceCount;
+    private boolean summary = false;
+
+    /** The encoding used to read and write files - if null, uses default */
+    private String encoding = null;
+
+    /**
+     * An inline string to use as the replacement text.
+     */
+    public class NestedString {
+
+        private StringBuffer buf = new StringBuffer();
+
+        /**
+         * The text of the element.
+         *
+         * @param val the string to add
+         */
+        public void addText(String val) {
+            buf.append(val);
+        }
+
+        /**
+         * @return the text
+         */
+        public String getText() {
+            return buf.toString();
+        }
+    }
+
+    /**
+     * A filter to apply.
+     */
+    public class Replacefilter {
+        private String token;
+        private String value;
+        private String replaceValue;
+        private String property;
+
+        private StringBuffer inputBuffer;
+        private StringBuffer outputBuffer = new StringBuffer();
+
+        /**
+         * Validate the filter's configuration.
+         * @throws BuildException if any part is invalid.
+         */
+        public void validate() throws BuildException {
+            //Validate mandatory attributes
+            if (token == null) {
+                String message = "token is a mandatory attribute "
+                    + "of replacefilter.";
+                throw new BuildException(message);
+            }
+
+            if ("".equals(token)) {
+                String message = "The token attribute must not be an empty "
+                    + "string.";
+                throw new BuildException(message);
+            }
+
+            //value and property are mutually exclusive attributes
+            if ((value != null) && (property != null)) {
+                String message = "Either value or property "
+                    + "can be specified, but a replacefilter "
+                    + "element cannot have both.";
+                throw new BuildException(message);
+            }
+
+            if ((property != null)) {
+                //the property attribute must have access to a property file
+                if (propertyFile == null) {
+                    String message = "The replacefilter's property attribute "
+                        + "can only be used with the replacetask's "
+                        + "propertyFile attribute.";
+                    throw new BuildException(message);
+                }
+
+                //Make sure property exists in property file
+                if (properties == null
+                    || properties.getProperty(property) == null) {
+                    String message = "property \"" + property
+                        + "\" was not found in " + propertyFile.getPath();
+                    throw new BuildException(message);
+                }
+            }
+
+            replaceValue = getReplaceValue();
+        }
+
+        /**
+         * Get the replacement value for this filter token.
+         * @return the replacement value
+         */
+        public String getReplaceValue() {
+            if (property != null) {
+                return properties.getProperty(property);
+            } else if (value != null) {
+                return value;
+            } else if (Replace.this.value != null) {
+                return Replace.this.value.getText();
+            } else {
+                //Default is empty string
+                return "";
+            }
+        }
+
+        /**
+         * Set the token to replace.
+         * @param token <code>String</code> token.
+         */
+        public void setToken(String token) {
+            this.token = token;
+        }
+
+        /**
+         * Get the string to search for.
+         * @return current <code>String</code> token.
+         */
+        public String getToken() {
+            return token;
+        }
+
+        /**
+         * The replacement string; required if <code>property<code>
+         * is not set.
+         * @param value <code>String</code> value to replace.
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * Get replacement <code>String</code>.
+         * @return replacement or null.
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * Set the name of the property whose value is to serve as
+         * the replacement value; required if <code>value</code> is not set.
+         * @param property property name.
+         */
+        public void setProperty(String property) {
+            this.property = property;
+        }
+
+        /**
+         * Get the name of the property whose value is to serve as
+         * the replacement value.
+         * @return property or null.
+         */
+        public String getProperty() {
+            return property;
+        }
+
+        /**
+         * Retrieves the output buffer of this filter. The filter guarantees
+         * that data is only appended to the end of this StringBuffer.
+         * @return The StringBuffer containing the output of this filter.
+         */
+        StringBuffer getOutputBuffer() {
+            return outputBuffer;
+        }
+
+        /**
+         * Sets the input buffer for this filter.
+         * The filter expects from the component providing the input that data
+         * is only added by that component to the end of this StringBuffer.
+         * This StringBuffer will be modified by this filter, and expects that
+         * another component will only apped to this StringBuffer.
+         * @param input The input for this filter.
+         */
+        void setInputBuffer(StringBuffer input) {
+            inputBuffer = input;
+        }
+
+        /**
+         * Processes the buffer as far as possible. Takes into account that
+         * appended data may make it possible to replace the end of the already
+         * received data, when the token is split over the "old" and the "new"
+         * part.
+         * @return true if some data has been made available in the
+         *         output buffer.
+         */
+        boolean process() {
+            if (inputBuffer.length() > token.length()) {
+                int pos = replace();
+                pos = Math.max((inputBuffer.length() - token.length()), pos);
+                outputBuffer.append(inputBuffer.substring(0, pos));
+                inputBuffer.delete(0, pos);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Processes the buffer to the end. Does not take into account that
+         * appended data may make it possible to replace the end of the already
+         * received data.
+         */
+        void flush() {
+            replace();
+            // Avoid runtime problem on pre 1.4 when compiling post 1.4
+            outputBuffer.append(inputBuffer.toString());
+            inputBuffer.delete(0, inputBuffer.length());
+        }
+
+        /**
+         * Performs the replace operation.
+         * @return The position of the last character that was inserted as
+         *         replacement.
+         */
+        private int replace() {
+            int found = inputBuffer.toString().indexOf(token);
+            int pos = -1;
+            while (found >= 0) {
+                inputBuffer.replace(found, found + token.length(),
+                        replaceValue);
+                pos = found + replaceValue.length();
+                found = inputBuffer.toString().indexOf(token, pos);
+                ++replaceCount;
+            }
+            return pos;
+        }
+    }
+
+    /**
+     * Class reading a file in small chunks, and presenting these chunks in
+     * a StringBuffer. Compatible with the Replacefilter.
+     * @since 1.7
+     */
+    private class FileInput {
+        private StringBuffer outputBuffer;
+        private Reader reader;
+        private char[] buffer;
+        private static final int BUFF_SIZE = 4096;
+
+        /**
+         * Constructs the input component. Opens the file for reading.
+         * @param source The file to read from.
+         * @throws IOException When the file cannot be read from.
+         */
+        FileInput(File source) throws IOException {
+            outputBuffer = new StringBuffer();
+            buffer = new char[BUFF_SIZE];
+            if (encoding == null) {
+                reader = new BufferedReader(new FileReader(source));
+            } else {
+                reader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(source), encoding));
+            }
+        }
+
+        /**
+         * Retrieves the output buffer of this filter. The component guarantees
+         * that data is only appended to the end of this StringBuffer.
+         * @return The StringBuffer containing the output of this filter.
+         */
+        StringBuffer getOutputBuffer() {
+            return outputBuffer;
+        }
+
+        /**
+         * Reads some data from the file.
+         * @return true when the end of the file has not been reached.
+         * @throws IOException When the file cannot be read from.
+         */
+        boolean readChunk() throws IOException {
+            int bufferLength = 0;
+            bufferLength = reader.read(buffer);
+            if (bufferLength < 0) {
+                return false;
+            }
+            outputBuffer.append(new String(buffer, 0, bufferLength));
+            return true;
+        }
+
+        /**
+         * Closes the file.
+         * @throws IOException When the file cannot be closed.
+         */
+        void close() throws IOException {
+            reader.close();
+        }
+
+        /**
+         * Closes file but doesn't throw exception
+         */
+        void closeQuietly() {
+            FileUtils.close(reader);
+        }
+
+    }
+
+    /**
+     * Component writing a file in chunks, taking the chunks from the
+     * Replacefilter.
+     * @since 1.7
+     */
+    private class FileOutput {
+        private StringBuffer inputBuffer;
+        private Writer writer;
+
+        /**
+         * Constructs the output component. Opens the file for writing.
+         * @param out The file to read to.
+         * @throws IOException When the file cannot be read from.
+         */
+        FileOutput(File out) throws IOException {
+                if (encoding == null) {
+                    writer = new BufferedWriter(new FileWriter(out));
+                } else {
+                    writer = new BufferedWriter(new OutputStreamWriter
+                            (new FileOutputStream(out), encoding));
+                }
+        }
+
+        /**
+         * Sets the input buffer for this component.
+         * The filter expects from the component providing the input that data
+         * is only added by that component to the end of this StringBuffer.
+         * This StringBuffer will be modified by this filter, and expects that
+         * another component will only append to this StringBuffer.
+         * @param input The input for this filter.
+         */
+        void setInputBuffer(StringBuffer input) {
+            inputBuffer = input;
+        }
+
+        /**
+         * Writes the buffer as far as possible.
+         * @return false to be inline with the Replacefilter.
+         * (Yes defining an interface crossed my mind, but would publish the
+         * internal behavior.)
+         * @throws IOException when the output cannot be written.
+         */
+        boolean process() throws IOException {
+            writer.write(inputBuffer.toString());
+            inputBuffer.delete(0, inputBuffer.length());
+            return false;
+        }
+
+        /**
+         * Processes the buffer to the end.
+         * @throws IOException when the output cannot be flushed.
+         */
+        void flush() throws IOException {
+            process();
+            writer.flush();
+        }
+
+        /**
+         * Closes the file.
+         * @throws IOException When the file cannot be closed.
+         */
+        void close() throws IOException {
+            writer.close();
+        }
+
+        /**
+         * Closes file but doesn't throw exception
+         */
+        void closeQuietly() {
+            FileUtils.close(writer);
+        }
+    }
+
+    /**
+     * Do the execution.
+     * @throws BuildException if we cant build
+     */
+    public void execute() throws BuildException {
+
+        Vector savedFilters = (Vector) replacefilters.clone();
+        Properties savedProperties =
+            properties == null ? null : (Properties) properties.clone();
+
+        if (token != null) {
+            // line separators in values and tokens are "\n"
+            // in order to compare with the file contents, replace them
+            // as needed
+            StringBuffer val = new StringBuffer(value.getText());
+            stringReplace(val, "\r\n", "\n");
+            stringReplace(val, "\n", StringUtils.LINE_SEP);
+            StringBuffer tok = new StringBuffer(token.getText());
+            stringReplace(tok, "\r\n", "\n");
+            stringReplace(tok, "\n", StringUtils.LINE_SEP);
+            Replacefilter firstFilter = createPrimaryfilter();
+            firstFilter.setToken(tok.toString());
+            firstFilter.setValue(val.toString());
+        }
+
+        try {
+            if (replaceFilterFile != null) {
+                Properties props = getProperties(replaceFilterFile);
+                Enumeration e = props.keys();
+                while (e.hasMoreElements()) {
+                    String tok =  e.nextElement().toString();
+                    Replacefilter replaceFilter = createReplacefilter();
+                    replaceFilter.setToken(tok);
+                    replaceFilter.setValue(props.getProperty(tok));
+                }
+            }
+
+            validateAttributes();
+
+            if (propertyFile != null) {
+                properties = getProperties(propertyFile);
+            }
+
+            validateReplacefilters();
+            fileCount = 0;
+            replaceCount = 0;
+
+            if (src != null) {
+                processFile(src);
+            }
+
+            if (dir != null) {
+                DirectoryScanner ds = super.getDirectoryScanner(dir);
+                String[] srcs = ds.getIncludedFiles();
+
+                for (int i = 0; i < srcs.length; i++) {
+                    File file = new File(dir, srcs[i]);
+                    processFile(file);
+                }
+            }
+
+            if (summary) {
+                log("Replaced " + replaceCount + " occurrences in "
+                    + fileCount + " files.", Project.MSG_INFO);
+            }
+        } finally {
+            replacefilters = savedFilters;
+            properties = savedProperties;
+        } // end of finally
+
+    }
+
+    /**
+     * Validate attributes provided for this task in .xml build file.
+     *
+     * @exception BuildException if any supplied attribute is invalid or any
+     * mandatory attribute is missing.
+     */
+    public void validateAttributes() throws BuildException {
+        if (src == null && dir == null) {
+            String message = "Either the file or the dir attribute "
+                + "must be specified";
+            throw new BuildException(message, getLocation());
+        }
+        if (propertyFile != null && !propertyFile.exists()) {
+            String message = "Property file " + propertyFile.getPath()
+                + " does not exist.";
+            throw new BuildException(message, getLocation());
+        }
+        if (token == null && replacefilters.size() == 0) {
+            String message = "Either token or a nested replacefilter "
+                + "must be specified";
+            throw new BuildException(message, getLocation());
+        }
+        if (token != null && "".equals(token.getText())) {
+            String message = "The token attribute must not be an empty string.";
+            throw new BuildException(message, getLocation());
+        }
+    }
+
+    /**
+     * Validate nested elements.
+     *
+     * @exception BuildException if any supplied attribute is invalid or any
+     * mandatory attribute is missing.
+     */
+    public void validateReplacefilters()
+            throws BuildException {
+        for (int i = 0; i < replacefilters.size(); i++) {
+            Replacefilter element =
+                (Replacefilter) replacefilters.elementAt(i);
+            element.validate();
+        }
+    }
+
+    /**
+     * Load a properties file.
+     * @param propertyFile the file to load the properties from.
+     * @return loaded <code>Properties</code> object.
+     * @throws BuildException if the file could not be found or read.
+     */
+    public Properties getProperties(File propertyFile) throws BuildException {
+        Properties props = new Properties();
+
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(propertyFile);
+            props.load(in);
+        } catch (FileNotFoundException e) {
+            String message = "Property file (" + propertyFile.getPath()
+                + ") not found.";
+            throw new BuildException(message);
+        } catch (IOException e) {
+            String message = "Property file (" + propertyFile.getPath()
+                + ") cannot be loaded.";
+            throw new BuildException(message);
+        } finally {
+            FileUtils.close(in);
+        }
+
+        return props;
+    }
+
+    /**
+     * Perform the replacement on the given file.
+     *
+     * The replacement is performed on a temporary file which then
+     * replaces the original file.
+     *
+     * @param src the source <code>File</code>.
+     */
+    private void processFile(File src) throws BuildException {
+        if (!src.exists()) {
+            throw new BuildException("Replace: source file " + src.getPath()
+                                     + " doesn't exist", getLocation());
+        }
+
+        File temp = null;
+        FileInput in = null;
+        FileOutput out = null;
+        try {
+            in = new FileInput(src);
+
+            temp = FILE_UTILS.createTempFile("rep", ".tmp",
+                    src.getParentFile(), false, true);
+            out = new FileOutput(temp);
+
+            int repCountStart = replaceCount;
+
+            logFilterChain(src.getPath());
+
+            out.setInputBuffer(buildFilterChain(in.getOutputBuffer()));
+
+            while (in.readChunk()) {
+                if (processFilterChain()) {
+                    out.process();
+                }
+            }
+
+            flushFilterChain();
+
+            out.flush();
+            in.close();
+            in = null;
+            out.close();
+            out = null;
+
+            boolean changes = (replaceCount != repCountStart);
+            if (changes) {
+                fileCount++;
+                FILE_UTILS.rename(temp, src);
+                temp = null;
+            }
+        } catch (IOException ioe) {
+            throw new BuildException("IOException in " + src + " - "
+                    + ioe.getClass().getName() + ":"
+                    + ioe.getMessage(), ioe, getLocation());
+        } finally {
+            if (null != in) {
+                in.closeQuietly();
+            }
+            if (null != out) {
+                out.closeQuietly();
+            }
+            if (temp != null) {
+                if (!temp.delete()) {
+                    temp.deleteOnExit();
+                }
+            }
+        }
+    }
+
+    /**
+     * Flushes all filters.
+     */
+    private void flushFilterChain() {
+        for (int i = 0; i < replacefilters.size(); i++) {
+            Replacefilter filter = (Replacefilter) replacefilters.elementAt(i);
+            filter.flush();
+        }
+    }
+
+    /**
+     * Performs the normal processing of the filters.
+     * @return true if the filter chain produced new output.
+     */
+    private boolean processFilterChain() {
+        for (int i = 0; i < replacefilters.size(); i++) {
+            Replacefilter filter = (Replacefilter) replacefilters.elementAt(i);
+            if (!filter.process()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Creates the chain of filters to operate.
+     * @param inputBuffer <code>StringBuffer</code> containing the input for the
+     *                    first filter.
+     * @return <code>StringBuffer</code> containing the output of the last filter.
+     */
+    private StringBuffer buildFilterChain(StringBuffer inputBuffer) {
+        StringBuffer buf = inputBuffer;
+        for (int i = 0; i < replacefilters.size(); i++) {
+            Replacefilter filter = (Replacefilter) replacefilters.elementAt(i);
+            filter.setInputBuffer(buf);
+            buf = filter.getOutputBuffer();
+        }
+        return buf;
+    }
+
+    /**
+     * Logs the chain of filters to operate on the file.
+     * @param filename <code>String</code>.
+     */
+    private void logFilterChain(String filename) {
+        for (int i = 0; i < replacefilters.size(); i++) {
+            Replacefilter filter = (Replacefilter) replacefilters.elementAt(i);
+            log("Replacing in " + filename + ": " + filter.getToken()
+                    + " --> " + filter.getReplaceValue(), Project.MSG_VERBOSE);
+        }
+    }
+    /**
+     * Set the source file; required unless <code>dir</code> is set.
+     * @param file source <code>File</code>.
+     */
+    public void setFile(File file) {
+        this.src = file;
+    }
+
+    /**
+     * Indicates whether a summary of the replace operation should be
+     * produced, detailing how many token occurrences and files were
+     * processed; optional, default=<code>false</code>.
+     *
+     * @param summary <code>boolean</code> whether a summary of the
+     *                replace operation should be logged.
+     */
+    public void setSummary(boolean summary) {
+        this.summary = summary;
+    }
+
+
+    /**
+     * Sets the name of a property file containing filters; optional.
+     * Each property will be treated as a replacefilter where token is the name
+     * of the property and value is the value of the property.
+     * @param replaceFilterFile <code>File</code> to load.
+     */
+    public void setReplaceFilterFile(File replaceFilterFile) {
+        this.replaceFilterFile = replaceFilterFile;
+    }
+
+    /**
+     * The base directory to use when replacing a token in multiple files;
+     * required if <code>file</code> is not defined.
+     * @param dir <code>File</code> representing the base directory.
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * Set the string token to replace; required unless a nested
+     * <code>replacetoken</code> element or the <code>replacefilterfile</code>
+     * attribute is used.
+     * @param token token <code>String</code>.
+     */
+    public void setToken(String token) {
+        createReplaceToken().addText(token);
+    }
+
+    /**
+     * Set the string value to use as token replacement;
+     * optional, default is the empty string "".
+     * @param value replacement value.
+     */
+    public void setValue(String value) {
+        createReplaceValue().addText(value);
+    }
+
+    /**
+     * Set the file encoding to use on the files read and written by the task;
+     * optional, defaults to default JVM encoding.
+     *
+     * @param encoding the encoding to use on the files.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Create a token to filter as the text of a nested element.
+     * @return nested token <code>NestedString</code> to configure.
+     */
+    public NestedString createReplaceToken() {
+        if (token == null) {
+            token = new NestedString();
+        }
+        return token;
+    }
+
+    /**
+     * Create a string to replace the token as the text of a nested element.
+     * @return replacement value <code>NestedString</code> to configure.
+     */
+    public NestedString createReplaceValue() {
+        return value;
+    }
+
+    /**
+     * The name of a property file from which properties specified using nested
+     * <code>&lt;replacefilter&gt;</code> elements are drawn; required only if
+     * the <i>property</i> attribute of <code>&lt;replacefilter&gt;</code> is used.
+     * @param propertyFile <code>File</code> to load.
+     */
+    public void setPropertyFile(File propertyFile) {
+        this.propertyFile = propertyFile;
+    }
+
+    /**
+     * Add a nested &lt;replacefilter&gt; element.
+     * @return a nested <code>Replacefilter</code> object to be configured.
+     */
+    public Replacefilter createReplacefilter() {
+        Replacefilter filter = new Replacefilter();
+        replacefilters.addElement(filter);
+        return filter;
+    }
+
+    /**
+     * Adds the token and value as first &lt;replacefilter&gt; element.
+     * The token and value are always processed first.
+     * @return a nested <code>Replacefilter</code> object to be configured.
+     */
+    private Replacefilter createPrimaryfilter() {
+        Replacefilter filter = new Replacefilter();
+        replacefilters.insertElementAt(filter, 0);
+        return filter;
+    }
+
+    /**
+     * Replace occurrences of str1 in StringBuffer str with str2.
+     */
+    private void stringReplace(StringBuffer str, String str1, String str2) {
+        int found = str.toString().indexOf(str1);
+        while (found >= 0) {
+            str.replace(found, found + str1.length(), str2);
+            found = str.toString().indexOf(str1, found + str2.length());
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java b/trunk/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java
new file mode 100755
index 0000000..6592c05
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/ResourceCount.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.Comparison;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Count resources from a ResourceCollection, storing to a property or
+ * writing to the log.  Can also be used as a Condition.
+ * @since Ant 1.7
+ */
+public class ResourceCount extends Task implements Condition {
+
+    private static final String ONE_NESTED_MESSAGE
+        = "ResourceCount can count resources from exactly one nested ResourceCollection.";
+
+    private static final String COUNT_REQUIRED
+        = "Use of the ResourceCount condition requires that the count attribute be set.";
+
+    private ResourceCollection rc;
+    private Comparison when = Comparison.EQUAL;
+    private Integer count;
+    private String property;
+
+    /**
+     * Add the ResourceCollection to count.
+     * @param r the ResourceCollection to count.
+     * @throws BuildException if already set.
+     */
+    public void add(ResourceCollection r) {
+        if (rc != null) {
+            throw new BuildException(ONE_NESTED_MESSAGE);
+        }
+        rc = r;
+    }
+
+    /**
+     * Set the ResourceCollection reference.
+     * @param r the Reference.
+     */
+    public void setRefid(Reference r) {
+        Object o = r.getReferencedObject();
+        if (!(o instanceof ResourceCollection)) {
+            throw new BuildException(r.getRefId()
+                + " doesn\'t denote a ResourceCollection");
+        }
+        add((ResourceCollection) o);
+    }
+
+    /**
+     * Execute as a Task.
+     */
+    public void execute() {
+        if (rc == null) {
+            throw new BuildException(ONE_NESTED_MESSAGE);
+        }
+        if (property == null) {
+            log("resource count = " + rc.size());
+        } else {
+            getProject().setNewProperty(property, Integer.toString(rc.size()));
+        }
+    }
+
+    /**
+     * Fulfill the condition contract.
+     * @return true if the specified ResourceCollection satisfies the set criteria.
+     * @throws BuildException if an error occurs.
+     */
+    public boolean eval() {
+        if (rc == null) {
+            throw new BuildException(ONE_NESTED_MESSAGE);
+        }
+        if (count == null) {
+            throw new BuildException(COUNT_REQUIRED);
+        }
+        return when.evaluate(new Integer(rc.size()).compareTo(count));
+    }
+
+    /**
+     * Set the target count number for use as a Condition.
+     * @param c number of Resources as int.
+     */
+    public void setCount(int c) {
+        count = new Integer(c);
+    }
+
+    /**
+     * Set the comparison for use as a Condition.
+     * @param c Comparison (an EnumeratedAttribute) When.
+     * @see org.apache.tools.ant.types.Comparison
+     */
+    public void setWhen(Comparison c) {
+        when = c;
+    }
+
+    /**
+     * Set the name of the property to set in task mode.
+     * @param p the property name to set.
+     */
+    public void setProperty(String p) {
+        property = p;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Retry.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Retry.java
new file mode 100644
index 0000000..200259e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Retry.java
@@ -0,0 +1,89 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant.taskdefs;

+

+import org.apache.tools.ant.BuildException;

+import org.apache.tools.ant.Project;

+import org.apache.tools.ant.Task;

+import org.apache.tools.ant.TaskContainer;

+import org.apache.tools.ant.util.StringUtils;

+

+/**

+ * Retries the nested task a set number of times

+ * @since Ant 1.7.1

+ */

+public class Retry extends Task implements TaskContainer {

+

+    /**

+     * task to execute n times

+     */

+    private Task nestedTask;

+

+    /**

+     * set retryCount to 1 by default

+     */

+    private int retryCount = 1;

+

+    /**

+     * set the task

+     * @param t the task to retry.

+     */

+    public synchronized void addTask(Task t) {

+        if (nestedTask != null) {

+            throw new BuildException(

+                "The retry task container accepts a single nested task"

+                + " (which may be a sequential task container)");

+        }

+        nestedTask = t;

+    }

+

+    /**

+     * set the number of times to retry the task

+     * @param n the number to use.

+     */

+    public void setRetryCount(int n) {

+        retryCount = n;

+    }

+

+    /**

+     * perform the work

+     * @throws BuildException if there is an error.

+     */

+    public void execute() throws BuildException {

+        StringBuffer errorMessages = new StringBuffer();

+        for (int i = 0; i <= retryCount; i++) {

+            try {

+                nestedTask.perform();

+                break;

+            } catch (Exception e) {

+                errorMessages.append(e.getMessage());

+                if (i >= retryCount) {

+                    StringBuffer exceptionMessage = new StringBuffer();

+                    exceptionMessage.append("Task [").append(nestedTask.getTaskName());

+                    exceptionMessage.append("] failed after [").append(retryCount);

+                    exceptionMessage.append("] attempts; giving up.").append(StringUtils.LINE_SEP);

+                    exceptionMessage.append("Error messages:").append(StringUtils.LINE_SEP);

+                    exceptionMessage.append(errorMessages);

+                    throw new BuildException(exceptionMessage.toString(), getLocation());

+                }

+                log("Attempt [" + i + "]: error occurred; retrying...", e, Project.MSG_INFO);

+                errorMessages.append(StringUtils.LINE_SEP);

+            }

+        }

+    }

+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Rmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Rmic.java
new file mode 100644
index 0000000..830b525
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Rmic.java
@@ -0,0 +1,717 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.rmi.Remote;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.rmic.RmicAdapter;
+import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+
+/**
+ * Runs the rmic compiler against classes.</p>
+ * <p>Rmic can be run on a single class (as specified with the classname
+ * attribute) or a number of classes at once (all classes below base that
+ * are neither _Stub nor _Skel classes).  If you want to rmic a single
+ * class and this class is a class nested into another class, you have to
+ * specify the classname in the form <code>Outer$$Inner</code> instead of
+ * <code>Outer.Inner</code>.</p>
+ * <p>It is possible to refine the set of files that are being rmiced. This can
+ * be done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>,
+ * <i>excludesfile</i> and <i>defaultexcludes</i>
+ * attributes. With the <i>includes</i> or <i>includesfile</i> attribute you
+ * specify the files you want to have included by using patterns. The
+ * <i>exclude</i> or <i>excludesfile</i> attribute is used to specify
+ * the files you want to have excluded. This is also done with patterns. And
+ * finally with the <i>defaultexcludes</i> attribute, you can specify whether
+ * you want to use default exclusions or not. See the section on
+ * directory based tasks</a>, on how the
+ * inclusion/exclusion of files works, and how to write patterns.</p>
+ * <p>This task forms an implicit FileSet and
+ * supports all attributes of <code>&lt;fileset&gt;</code>
+ * (<code>dir</code> becomes <code>base</code>) as well as the nested
+ * <code>&lt;include&gt;</code>, <code>&lt;exclude&gt;</code> and
+ * <code>&lt;patternset&gt;</code> elements.</p>
+ * <p>It is possible to use different compilers. This can be selected
+ * with the &quot;build.rmic&quot; property or the <code>compiler</code>
+ * attribute. <a name="compilervalues">There are three choices</a>:</p>
+ * <ul>
+ *   <li>sun (the standard compiler of the JDK)</li>
+ *   <li>kaffe (the standard compiler of
+ *       {@link <a href="http://www.kaffe.org">Kaffe</a>})</li>
+ *   <li>weblogic</li>
+ * </ul>
+ *
+ * <p> The <a href="http://dione.zcu.cz/~toman40/miniRMI/">miniRMI</a>
+ * project contains a compiler implementation for this task as well,
+ * please consult miniRMI's documentation to learn how to use it.</p>
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="java"
+ */
+
+public class Rmic extends MatchingTask {
+
+    /** rmic failed message */
+    public static final String ERROR_RMIC_FAILED
+            = "Rmic failed; see the compiler error output for details.";
+
+    private File baseDir;
+    private String classname;
+    private File sourceBase;
+    private String stubVersion;
+    private Path compileClasspath;
+    private Path extDirs;
+    private boolean verify = false;
+    private boolean filtering = false;
+
+    private boolean iiop = false;
+    private String  iiopOpts;
+    private boolean idl  = false;
+    private String  idlOpts;
+    private boolean debug  = false;
+    private boolean includeAntRuntime = true;
+    private boolean includeJavaRuntime = false;
+
+    private Vector compileList = new Vector();
+
+    private ClassLoader loader = null;
+
+    private FacadeTaskHelper facade;
+    /** unable to verify message */
+    public static final String ERROR_UNABLE_TO_VERIFY_CLASS = "Unable to verify class ";
+    /** could not be found message */
+    public static final String ERROR_NOT_FOUND = ". It could not be found.";
+    /** not defined message */
+    public static final String ERROR_NOT_DEFINED = ". It is not defined.";
+    /** loaded error message */
+    public static final String ERROR_LOADING_CAUSED_EXCEPTION = ". Loading caused Exception: ";
+    /** base not exists message */
+    public static final String ERROR_NO_BASE_EXISTS = "base does not exist: ";
+    /** base not a directory message */
+    public static final String ERROR_NOT_A_DIR = "base is not a directory:";
+    /** base attribute not set message */
+    public static final String ERROR_BASE_NOT_SET = "base attribute must be set!";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Constructor for Rmic.
+     */
+    public Rmic() {
+        facade = new FacadeTaskHelper(RmicAdapterFactory.DEFAULT_COMPILER);
+    }
+
+    /**
+     * Sets the location to store the compiled files; required
+     * @param base the location to store the compiled files
+     */
+    public void setBase(File base) {
+        this.baseDir = base;
+    }
+
+    /**
+     * Gets the base directory to output generated class.
+     * @return the location of the compiled files
+     */
+
+    public File getBase() {
+        return this.baseDir;
+    }
+
+    /**
+     * Sets the class to run <code>rmic</code> against;
+     * optional
+     * @param classname the name of the class for rmic to create code for
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * Gets the class name to compile.
+     * @return the name of the class to compile
+     */
+    public String getClassname() {
+        return classname;
+    }
+
+    /**
+     * optional directory to save generated source files to.
+     * @param sourceBase the directory to save source files to.
+     */
+    public void setSourceBase(File sourceBase) {
+        this.sourceBase = sourceBase;
+    }
+
+    /**
+     * Gets the source dirs to find the source java files.
+     * @return sourceBase the directory containing the source files.
+     */
+    public File getSourceBase() {
+        return sourceBase;
+    }
+
+    /**
+     * Specify the JDK version for the generated stub code.
+     * Specify &quot;1.1&quot; to pass the &quot;-v1.1&quot; option to rmic.</td>
+     * @param stubVersion the JDK version
+     */
+    public void setStubVersion(String stubVersion) {
+        this.stubVersion = stubVersion;
+    }
+
+    /**
+     * Gets the JDK version for the generated stub code.
+     * @return stubVersion
+     */
+    public String getStubVersion() {
+        return stubVersion;
+    }
+
+    /**
+     * Sets token filtering [optional], default=false
+     * @param filter turn on token filtering
+     */
+    public void setFiltering(boolean filter) {
+        this.filtering = filter;
+    }
+
+    /**
+     * Gets whether token filtering is set
+     * @return filtering
+     */
+    public boolean getFiltering() {
+        return filtering;
+    }
+
+    /**
+     * Generate debug info (passes -g to rmic);
+     * optional, defaults to false
+     * @param debug turn on debug info
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Gets the debug flag.
+     * @return debug
+     */
+    public boolean getDebug() {
+        return debug;
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     * @param classpath the classpath used for this compilation
+     */
+    public synchronized void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        } else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Creates a nested classpath element.
+     * @return classpath
+     */
+    public synchronized Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath.createPath();
+    }
+
+    /**
+     * Adds to the classpath a reference to
+     * a &lt;path&gt; defined elsewhere.
+     * @param pathRef the reference to add to the classpath
+     */
+    public void setClasspathRef(Reference pathRef) {
+        createClasspath().setRefid(pathRef);
+    }
+
+    /**
+     * Gets the classpath.
+     * @return the classpath
+     */
+    public Path getClasspath() {
+        return compileClasspath;
+    }
+
+    /**
+     * Flag to enable verification so that the classes
+     * found by the directory match are
+     * checked to see if they implement java.rmi.Remote.
+     * optional; This defaults to false if not set.
+     * @param verify turn on verification for classes
+     */
+    public void setVerify(boolean verify) {
+        this.verify = verify;
+    }
+
+    /**
+     * Get verify flag.
+     * @return verify
+     */
+    public boolean getVerify() {
+        return verify;
+    }
+
+    /**
+     * Indicates that IIOP compatible stubs should
+     * be generated; optional, defaults to false
+     * if not set.
+     * @param iiop generate IIOP compatible stubs
+     */
+    public void setIiop(boolean iiop) {
+        this.iiop = iiop;
+    }
+
+    /**
+     * Gets iiop flags.
+     * @return iiop
+     */
+    public boolean getIiop() {
+        return iiop;
+    }
+
+    /**
+     * Set additional arguments for iiop
+     * @param iiopOpts additional arguments for iiop
+     */
+    public void setIiopopts(String iiopOpts) {
+        this.iiopOpts = iiopOpts;
+    }
+
+    /**
+     * Gets additional arguments for iiop.
+     * @return iiopOpts
+     */
+    public String getIiopopts() {
+        return iiopOpts;
+    }
+
+    /**
+     * Indicates that IDL output should be
+     * generated.  This defaults to false
+     * if not set.
+     * @param idl generate IDL output
+     */
+    public void setIdl(boolean idl) {
+        this.idl = idl;
+    }
+
+    /**
+     * Gets IDL flags.
+     * @return the idl flag
+     */
+    public boolean getIdl() {
+        return idl;
+    }
+
+    /**
+     * pass additional arguments for IDL compile
+     * @param idlOpts additional IDL arguments
+     */
+    public void setIdlopts(String idlOpts) {
+        this.idlOpts = idlOpts;
+    }
+
+    /**
+     * Gets additional arguments for idl compile.
+     * @return the idl options
+     */
+    public String getIdlopts() {
+        return idlOpts;
+    }
+
+    /**
+     * Gets file list to compile.
+     * @return the list of files to compile.
+     */
+    public Vector getFileList() {
+        return compileList;
+    }
+
+    /**
+     * Sets whether or not to include ant's own classpath in this task's
+     * classpath.
+     * Optional; default is <code>true</code>.
+     * @param include if true include ant's classpath
+     */
+    public void setIncludeantruntime(boolean include) {
+        includeAntRuntime = include;
+    }
+
+    /**
+     * Gets whether or not the ant classpath is to be included in the
+     * task's classpath.
+     * @return true if ant's classpath is to be included
+     */
+    public boolean getIncludeantruntime() {
+        return includeAntRuntime;
+    }
+
+    /**
+     * task's classpath.
+     * Enables or disables including the default run-time
+     * libraries from the executing VM; optional,
+     * defaults to false
+     * @param include if true include default run-time libraries
+     */
+    public void setIncludejavaruntime(boolean include) {
+        includeJavaRuntime = include;
+    }
+
+    /**
+     * Gets whether or not the java runtime should be included in this
+     * task's classpath.
+     * @return true if default run-time libraries are included
+     */
+    public boolean getIncludejavaruntime() {
+        return includeJavaRuntime;
+    }
+
+    /**
+     * Sets the extension directories that will be used during the
+     * compilation; optional.
+     * @param extDirs the extension directories to be used
+     */
+    public synchronized void setExtdirs(Path extDirs) {
+        if (this.extDirs == null) {
+            this.extDirs = extDirs;
+        } else {
+            this.extDirs.append(extDirs);
+        }
+    }
+
+    /**
+     * Maybe creates a nested extdirs element.
+     * @return path object to be configured with the extension directories
+     */
+    public synchronized Path createExtdirs() {
+        if (extDirs == null) {
+            extDirs = new Path(getProject());
+        }
+        return extDirs.createPath();
+    }
+
+    /**
+     * Gets the extension directories that will be used during the
+     * compilation.
+     * @return the extension directories to be used
+     */
+    public Path getExtdirs() {
+        return extDirs;
+    }
+
+    /**
+     * @return the compile list.
+     */
+    public Vector getCompileList() {
+        return compileList;
+    }
+
+    /**
+     * Sets the compiler implementation to use; optional,
+     * defaults to the value of the <code>build.rmic</code> property,
+     * or failing that, default compiler for the current VM
+     * @param compiler the compiler implemention to use
+     * @since Ant 1.5
+     */
+    public void setCompiler(String compiler) {
+        if (compiler.length() > 0) {
+            facade.setImplementation(compiler);
+        }
+    }
+
+    /**
+     * get the name of the current compiler
+     * @return the name of the compiler
+     * @since Ant 1.5
+     */
+    public String getCompiler() {
+        facade.setMagicValue(getProject().getProperty("build.rmic"));
+        return facade.getImplementation();
+    }
+
+    /**
+     * Adds an implementation specific command line argument.
+     * @return an object to be configured with a command line argument
+     * @since Ant 1.5
+     */
+    public ImplementationSpecificArgument createCompilerArg() {
+        ImplementationSpecificArgument arg = new ImplementationSpecificArgument();
+        facade.addImplementationArgument(arg);
+        return arg;
+    }
+
+    /**
+     * Get the additional implementation specific command line arguments.
+     * @return array of command line arguments, guaranteed to be non-null.
+     * @since Ant 1.5
+     */
+    public String[] getCurrentCompilerArgs() {
+        getCompiler();
+        return facade.getArgs();
+    }
+
+    /**
+     * execute by creating an instance of an implementation
+     * class and getting to do the work
+     * @throws org.apache.tools.ant.BuildException
+     * if there's a problem with baseDir or RMIC
+     */
+    public void execute() throws BuildException {
+        if (baseDir == null) {
+            throw new BuildException(ERROR_BASE_NOT_SET, getLocation());
+        }
+        if (!baseDir.exists()) {
+            throw new BuildException(ERROR_NO_BASE_EXISTS + baseDir, getLocation());
+        }
+        if (!baseDir.isDirectory()) {
+            throw new BuildException(ERROR_NOT_A_DIR + baseDir, getLocation());
+        }
+        if (verify) {
+            log("Verify has been turned on.", Project.MSG_VERBOSE);
+        }
+        RmicAdapter adapter = RmicAdapterFactory.getRmic(getCompiler(), this);
+
+        // now we need to populate the compiler adapter
+        adapter.setRmic(this);
+
+        Path classpath = adapter.getClasspath();
+        loader = getProject().createClassLoader(classpath);
+
+        try {
+            // scan base dirs to build up compile lists only if a
+            // specific classname is not given
+            if (classname == null) {
+                DirectoryScanner ds = this.getDirectoryScanner(baseDir);
+                String[] files = ds.getIncludedFiles();
+                scanDir(baseDir, files, adapter.getMapper());
+            } else {
+                // otherwise perform a timestamp comparison - at least
+                String path = classname.replace('.', File.separatorChar) + ".class";
+                File f = new File(baseDir, path);
+                if (f.isFile()) {
+                    scanDir(baseDir, new String[] {path}, adapter.getMapper());
+                } else {
+                    // Does not exist, so checking whether it is up to date makes no sense.
+                    // Compilation will fail later anyway, but tests expect a certain output.
+                    compileList.add(classname);
+                }
+            }
+            int fileCount = compileList.size();
+            if (fileCount > 0) {
+                log("RMI Compiling " + fileCount + " class" + (fileCount > 1 ? "es" : "") + " to "
+                        + baseDir, Project.MSG_INFO);
+                // finally, lets execute the compiler!!
+                if (!adapter.execute()) {
+                    throw new BuildException(ERROR_RMIC_FAILED, getLocation());
+                }
+            }
+            /*
+             * Move the generated source file to the base directory.  If
+             * base directory and sourcebase are the same, the generated
+             * sources are already in place.
+             */
+            if (null != sourceBase && !baseDir.equals(sourceBase)
+                && fileCount > 0) {
+                if (idl) {
+                    log("Cannot determine sourcefiles in idl mode, ", Project.MSG_WARN);
+                    log("sourcebase attribute will be ignored.", Project.MSG_WARN);
+                } else {
+                    for (int j = 0; j < fileCount; j++) {
+                        moveGeneratedFile(baseDir, sourceBase, (String) compileList.elementAt(j),
+                                adapter);
+                    }
+                }
+            }
+        } finally {
+            compileList.removeAllElements();
+        }
+    }
+
+    /**
+     * Move the generated source file(s) to the base directory
+     *
+     * @throws org.apache.tools.ant.BuildException When error
+     * copying/removing files.
+     */
+    private void moveGeneratedFile(File baseDir, File sourceBaseFile, String classname,
+            RmicAdapter adapter) throws BuildException {
+        String classFileName = classname.replace('.', File.separatorChar) + ".class";
+        String[] generatedFiles = adapter.getMapper().mapFileName(classFileName);
+
+        for (int i = 0; i < generatedFiles.length; i++) {
+            final String generatedFile = generatedFiles[i];
+            if (!generatedFile.endsWith(".class")) {
+                // don't know how to handle that - a IDL file doesn't
+                // have a corresponding Java source for example.
+                continue;
+            }
+            String sourceFileName = StringUtils.removeSuffix(generatedFile, ".class");
+
+            File oldFile = new File(baseDir, sourceFileName);
+            if (!oldFile.exists()) {
+                // no source file generated, nothing to move
+                continue;
+            }
+
+            File newFile = new File(sourceBaseFile, sourceFileName);
+            try {
+                if (filtering) {
+                    FILE_UTILS.copyFile(oldFile, newFile, new FilterSetCollection(getProject()
+                            .getGlobalFilterSet()));
+                } else {
+                    FILE_UTILS.copyFile(oldFile, newFile);
+                }
+                oldFile.delete();
+            } catch (IOException ioe) {
+                String msg = "Failed to copy " + oldFile + " to " + newFile + " due to "
+                        + ioe.getMessage();
+                throw new BuildException(msg, ioe, getLocation());
+            }
+        }
+    }
+
+    /**
+     * Scans the directory looking for class files to be compiled.
+     * The result is returned in the class variable compileList.
+     * @param baseDir the base direction
+     * @param files   the list of files to scan
+     * @param mapper  the mapper of files to target files
+     */
+    protected void scanDir(File baseDir, String[] files, FileNameMapper mapper) {
+        String[] newFiles = files;
+        if (idl) {
+            log("will leave uptodate test to rmic implementation in idl mode.",
+                Project.MSG_VERBOSE);
+        } else if (iiop && iiopOpts != null && iiopOpts.indexOf("-always") > -1) {
+            log("no uptodate test as -always option has been specified", Project.MSG_VERBOSE);
+        } else {
+            SourceFileScanner sfs = new SourceFileScanner(this);
+            newFiles = sfs.restrict(files, baseDir, baseDir, mapper);
+        }
+        for (int i = 0; i < newFiles.length; i++) {
+            String name = newFiles[i].replace(File.separatorChar, '.');
+            name = name.substring(0, name.lastIndexOf(".class"));
+            compileList.addElement(name);
+        }
+    }
+
+    /**
+     * Load named class and test whether it can be rmic'ed
+     * @param classname the name of the class to be tested
+     * @return true if the class can be rmic'ed
+     */
+    public boolean isValidRmiRemote(String classname) {
+        try {
+            Class testClass = loader.loadClass(classname);
+            // One cannot RMIC an interface for "classic" RMI (JRMP)
+            if (testClass.isInterface() && !iiop && !idl) {
+                return false;
+            }
+            return isValidRmiRemote(testClass);
+        } catch (ClassNotFoundException e) {
+            log(ERROR_UNABLE_TO_VERIFY_CLASS + classname + ERROR_NOT_FOUND, Project.MSG_WARN);
+        } catch (NoClassDefFoundError e) {
+            log(ERROR_UNABLE_TO_VERIFY_CLASS + classname + ERROR_NOT_DEFINED, Project.MSG_WARN);
+        } catch (Throwable t) {
+            log(ERROR_UNABLE_TO_VERIFY_CLASS + classname + ERROR_LOADING_CAUSED_EXCEPTION
+                    + t.getMessage(), Project.MSG_WARN);
+        }
+        // we only get here if an exception has been thrown
+        return false;
+    }
+
+    /**
+     * Returns the topmost interface that extends Remote for a given
+     * class - if one exists.
+     * @param testClass the class to be tested
+     * @return the topmost interface that extends Remote, or null if there
+     *         is none.
+     */
+    public Class getRemoteInterface(Class testClass) {
+        if (Remote.class.isAssignableFrom(testClass)) {
+            Class [] interfaces = testClass.getInterfaces();
+            if (interfaces != null) {
+                for (int i = 0; i < interfaces.length; i++) {
+                    if (Remote.class.isAssignableFrom(interfaces[i])) {
+                        return interfaces[i];
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Check to see if the class or (super)interfaces implement
+     * java.rmi.Remote.
+     */
+    private boolean isValidRmiRemote (Class testClass) {
+        return getRemoteInterface(testClass) != null;
+    }
+
+    /**
+     * Classloader for the user-specified classpath.
+     * @return the classloader
+     */
+    public ClassLoader getLoader() {
+        return loader;
+    }
+
+    /**
+     * Adds an "compiler" attribute to Commandline$Attribute used to
+     * filter command line attributes based on the current
+     * implementation.
+     */
+    public class ImplementationSpecificArgument extends
+            org.apache.tools.ant.util.facade.ImplementationSpecificArgument {
+        /**
+         * Only pass the specified argument if the
+         * chosen compiler implementation matches the
+         * value of this attribute. Legal values are
+         * the same as those in the above list of
+         * valid compilers.)
+         * @param impl the compiler to be used.
+         */
+        public void setCompiler(String impl) {
+            super.setImplementation(impl);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/SQLExec.java b/trunk/src/main/org/apache/tools/ant/taskdefs/SQLExec.java
new file mode 100644
index 0000000..4a0ac32
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/SQLExec.java
@@ -0,0 +1,793 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.StringReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Types;
+
+/**
+ * Executes a series of SQL statements on a database using JDBC.
+ *
+ * <p>Statements can
+ * either be read in from a text file using the <i>src</i> attribute or from
+ * between the enclosing SQL tags.</p>
+ *
+ * <p>Multiple statements can be provided, separated by semicolons (or the
+ * defined <i>delimiter</i>). Individual lines within the statements can be
+ * commented using either --, // or REM at the start of the line.</p>
+ *
+ * <p>The <i>autocommit</i> attribute specifies whether auto-commit should be
+ * turned on or off whilst executing the statements. If auto-commit is turned
+ * on each statement will be executed and committed. If it is turned off the
+ * statements will all be executed as one transaction.</p>
+ *
+ * <p>The <i>onerror</i> attribute specifies how to proceed when an error occurs
+ * during the execution of one of the statements.
+ * The possible values are: <b>continue</b> execution, only show the error;
+ * <b>stop</b> execution and commit transaction;
+ * and <b>abort</b> execution and transaction and fail task.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="sql" category="database"
+ */
+public class SQLExec extends JDBCTask {
+
+    /**
+     * delimiters we support, "normal" and "row"
+     */
+    public static class DelimiterType extends EnumeratedAttribute {
+        /** The enumerated strings */
+        public static final String NORMAL = "normal", ROW = "row";
+        /** @return the enumerated strings */
+        public String[] getValues() {
+            return new String[] {NORMAL, ROW};
+        }
+    }
+
+    private int goodSql = 0;
+
+    private int totalSql = 0;
+
+    /**
+     * Database connection
+     */
+    private Connection conn = null;
+
+    /**
+     * files to load
+     */
+    private Union resources;
+
+    /**
+     * SQL statement
+     */
+    private Statement statement = null;
+
+    /**
+     * SQL input file
+     */
+    private File srcFile = null;
+
+    /**
+     * SQL input command
+     */
+    private String sqlCommand = "";
+
+    /**
+     * SQL transactions to perform
+     */
+    private Vector transactions = new Vector();
+
+    /**
+     * SQL Statement delimiter
+     */
+    private String delimiter = ";";
+
+    /**
+     * The delimiter type indicating whether the delimiter will
+     * only be recognized on a line by itself
+     */
+    private String delimiterType = DelimiterType.NORMAL;
+
+    /**
+     * Print SQL results.
+     */
+    private boolean print = false;
+
+    /**
+     * Print header columns.
+     */
+    private boolean showheaders = true;
+
+    /**
+     * Print SQL stats (rows affected)
+     */
+    private boolean showtrailers = true;
+
+    /**
+     * Results Output file.
+     */
+    private File output = null;
+
+
+    /**
+     * Action to perform if an error is found
+     **/
+    private String onError = "abort";
+
+    /**
+     * Encoding to use when reading SQL statements from a file
+     */
+    private String encoding = null;
+
+    /**
+     * Append to an existing file or overwrite it?
+     */
+    private boolean append = false;
+
+    /**
+     * Keep the format of a sql block?
+     */
+    private boolean keepformat = false;
+
+    /**
+     * Argument to Statement.setEscapeProcessing
+     *
+     * @since Ant 1.6
+     */
+    private boolean escapeProcessing = true;
+
+    /**
+     * should properties be expanded in text?
+     * false for backwards compatibility
+     *
+     * @since Ant 1.7
+     */
+    private boolean expandProperties = true;
+
+    /**
+     * should we print raw BLOB data?
+     * @since Ant 1.7.1
+     */
+    private boolean rawBlobs;
+
+    /**
+     * Set the name of the SQL file to be run.
+     * Required unless statements are enclosed in the build file
+     * @param srcFile the file containing the SQL command.
+     */
+    public void setSrc(File srcFile) {
+        this.srcFile = srcFile;
+    }
+
+    /**
+     * Enable property expansion inside nested text
+     *
+     * @param expandProperties if true expand properties.
+     * @since Ant 1.7
+     */
+    public void setExpandProperties(boolean expandProperties) {
+        this.expandProperties = expandProperties;
+    }
+
+    /**
+     * is property expansion inside inline text enabled?
+     *
+     * @return true if properties are to be expanded.
+     * @since Ant 1.7
+     */
+    public boolean getExpandProperties() {
+        return expandProperties;
+    }
+
+    /**
+     * Set an inline SQL command to execute.
+     * NB: Properties are not expanded in this text unless {@link #expandProperties}
+     * is set.
+     * @param sql an inline string containing the SQL command.
+     */
+    public void addText(String sql) {
+        //there is no need to expand properties here as that happens when Transaction.addText is
+        //called; to do so here would be an error.
+        this.sqlCommand += sql;
+    }
+
+    /**
+     * Adds a set of files (nested fileset attribute).
+     * @param set a set of files contains SQL commands, each File is run in
+     *            a separate transaction.
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Adds a collection of resources (nested element).
+     * @param rc a collection of resources containing SQL commands,
+     * each resource is run in a separate transaction.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        if (rc == null) {
+            throw new BuildException("Cannot add null ResourceCollection");
+        }
+        synchronized (this) {
+            if (resources == null) {
+                resources = new Union();
+            }
+        }
+        resources.add(rc);
+    }
+
+    /**
+     * Add a SQL transaction to execute
+     * @return a Transaction to be configured.
+     */
+    public Transaction createTransaction() {
+        Transaction t = new Transaction();
+        transactions.addElement(t);
+        return t;
+    }
+
+    /**
+     * Set the file encoding to use on the SQL files read in
+     *
+     * @param encoding the encoding to use on the files
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Set the delimiter that separates SQL statements. Defaults to &quot;;&quot;;
+     * optional
+     *
+     * <p>For example, set this to "go" and delimitertype to "ROW" for
+     * Sybase ASE or MS SQL Server.</p>
+     * @param delimiter the separator.
+     */
+    public void setDelimiter(String delimiter) {
+        this.delimiter = delimiter;
+    }
+
+    /**
+     * Set the delimiter type: "normal" or "row" (default "normal").
+     *
+     * <p>The delimiter type takes two values - normal and row. Normal
+     * means that any occurrence of the delimiter terminate the SQL
+     * command whereas with row, only a line containing just the
+     * delimiter is recognized as the end of the command.</p>
+     * @param delimiterType the type of delimiter - "normal" or "row".
+     */
+    public void setDelimiterType(DelimiterType delimiterType) {
+        this.delimiterType = delimiterType.getValue();
+    }
+
+    /**
+     * Print result sets from the statements;
+     * optional, default false
+     * @param print if true print result sets.
+     */
+    public void setPrint(boolean print) {
+        this.print = print;
+    }
+
+    /**
+     * Print headers for result sets from the
+     * statements; optional, default true.
+     * @param showheaders if true print headers of result sets.
+     */
+    public void setShowheaders(boolean showheaders) {
+        this.showheaders = showheaders;
+    }
+
+    /**
+     * Print trailing info (rows affected) for the SQL
+     * Addresses Bug/Request #27446
+     * @param showtrailers if true prints the SQL rows affected
+     * @since Ant 1.7
+     */
+    public void setShowtrailers(boolean showtrailers) {
+        this.showtrailers = showtrailers;
+    }
+
+    /**
+     * Set the output file;
+     * optional, defaults to the Ant log.
+     * @param output the output file to use for logging messages.
+     */
+    public void setOutput(File output) {
+        this.output = output;
+    }
+
+    /**
+     * whether output should be appended to or overwrite
+     * an existing file.  Defaults to false.
+     *
+     * @since Ant 1.5
+     * @param append if true append to an existing file.
+     */
+    public void setAppend(boolean append) {
+        this.append = append;
+    }
+
+
+    /**
+     * Action to perform when statement fails: continue, stop, or abort
+     * optional; default &quot;abort&quot;
+     * @param action the action to perform on statement failure.
+     */
+    public void setOnerror(OnError action) {
+        this.onError = action.getValue();
+    }
+
+    /**
+     * whether or not format should be preserved.
+     * Defaults to false.
+     *
+     * @param keepformat The keepformat to set
+     */
+    public void setKeepformat(boolean keepformat) {
+        this.keepformat = keepformat;
+    }
+
+    /**
+     * Set escape processing for statements.
+     * @param enable if true enable escape processing, default is true.
+     * @since Ant 1.6
+     */
+    public void setEscapeProcessing(boolean enable) {
+        escapeProcessing = enable;
+    }
+
+    /**
+     * Set whether to print raw BLOBs rather than their string (hex) representations.
+     * @param rawBlobs whether to print raw BLOBs.
+     * @since Ant 1.7.1
+     */
+    public void setRawBlobs(boolean rawBlobs) {
+        this.rawBlobs = rawBlobs;
+    }
+
+    /**
+     * Load the sql file and then execute it
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        Vector savedTransaction = (Vector) transactions.clone();
+        String savedSqlCommand = sqlCommand;
+
+        sqlCommand = sqlCommand.trim();
+
+        try {
+            if (srcFile == null && sqlCommand.length() == 0 && resources == null) {
+                if (transactions.size() == 0) {
+                    throw new BuildException("Source file or resource collection, "
+                                             + "transactions or sql statement "
+                                             + "must be set!", getLocation());
+                }
+            }
+
+            if (srcFile != null && !srcFile.isFile()) {
+                throw new BuildException("Source file " + srcFile
+                        + " is not a file!", getLocation());
+            }
+
+            if (resources != null) {
+                // deal with the resources
+                Iterator iter = resources.iterator();
+                while (iter.hasNext()) {
+                    Resource r = (Resource) iter.next();
+                    // Make a transaction for each resource
+                    Transaction t = createTransaction();
+                    t.setSrcResource(r);
+                }
+            }
+
+            // Make a transaction group for the outer command
+            Transaction t = createTransaction();
+            t.setSrc(srcFile);
+            t.addText(sqlCommand);
+            conn = getConnection();
+            if (!isValidRdbms(conn)) {
+                return;
+            }
+            try {
+                statement = conn.createStatement();
+                statement.setEscapeProcessing(escapeProcessing);
+
+                PrintStream out = System.out;
+                try {
+                    if (output != null) {
+                        log("Opening PrintStream to output file " + output, Project.MSG_VERBOSE);
+                        out = new PrintStream(new BufferedOutputStream(
+                                new FileOutputStream(output.getAbsolutePath(), append)));
+                    }
+
+                    // Process all transactions
+                    for (Enumeration e = transactions.elements();
+                         e.hasMoreElements();) {
+
+                        ((Transaction) e.nextElement()).runTransaction(out);
+                        if (!isAutocommit()) {
+                            log("Committing transaction", Project.MSG_VERBOSE);
+                            conn.commit();
+                        }
+                    }
+                } finally {
+                    FileUtils.close(out);
+                }
+            } catch (IOException e) {
+                closeQuietly();
+                throw new BuildException(e, getLocation());
+            } catch (SQLException e) {
+                closeQuietly();
+                throw new BuildException(e, getLocation());
+            } finally {
+                try {
+                    if (statement != null) {
+                        statement.close();
+                    }
+                } catch (SQLException ex) {
+                    // ignore
+                }
+                try {
+                    if (conn != null) {
+                        conn.close();
+                    }
+                } catch (SQLException ex) {
+                    // ignore
+                }
+            }
+
+            log(goodSql + " of " + totalSql + " SQL statements executed successfully");
+        } finally {
+            transactions = savedTransaction;
+            sqlCommand = savedSqlCommand;
+        }
+    }
+
+    /**
+     * read in lines and execute them
+     * @param reader the reader contains sql lines.
+     * @param out the place to output results.
+     * @throws SQLException on sql problems
+     * @throws IOException on io problems
+     */
+    protected void runStatements(Reader reader, PrintStream out)
+        throws SQLException, IOException {
+        StringBuffer sql = new StringBuffer();
+        String line;
+
+        BufferedReader in = new BufferedReader(reader);
+
+        while ((line = in.readLine()) != null) {
+            if (!keepformat) {
+                line = line.trim();
+            }
+            if (expandProperties) {
+                line = getProject().replaceProperties(line);
+            }
+            if (!keepformat) {
+                if (line.startsWith("//")) {
+                    continue;
+                }
+                if (line.startsWith("--")) {
+                    continue;
+                }
+                StringTokenizer st = new StringTokenizer(line);
+                if (st.hasMoreTokens()) {
+                    String token = st.nextToken();
+                    if ("REM".equalsIgnoreCase(token)) {
+                        continue;
+                    }
+                }
+            }
+
+            sql.append(keepformat ? "\n" : " ").append(line);
+
+            // SQL defines "--" as a comment to EOL
+            // and in Oracle it may contain a hint
+            // so we cannot just remove it, instead we must end it
+            if (!keepformat && line.indexOf("--") >= 0) {
+                sql.append("\n");
+            }
+            if ((delimiterType.equals(DelimiterType.NORMAL) && StringUtils.endsWith(sql, delimiter))
+                    || (delimiterType.equals(DelimiterType.ROW) && line.equals(delimiter))) {
+                execSQL(sql.substring(0, sql.length() - delimiter.length()), out);
+                sql.replace(0, sql.length(), "");
+            }
+        }
+        // Catch any statements not followed by ;
+        if (sql.length() > 0) {
+            execSQL(sql.toString(), out);
+        }
+    }
+
+    /**
+     * Exec the sql statement.
+     * @param sql the SQL statement to execute
+     * @param out the place to put output
+     * @throws SQLException on SQL problems
+     */
+    protected void execSQL(String sql, PrintStream out) throws SQLException {
+        // Check and ignore empty statements
+        if ("".equals(sql.trim())) {
+            return;
+        }
+
+        ResultSet resultSet = null;
+        try {
+            totalSql++;
+            log("SQL: " + sql, Project.MSG_VERBOSE);
+
+            boolean ret;
+            int updateCount = 0, updateCountTotal = 0;
+
+            ret = statement.execute(sql);
+            updateCount = statement.getUpdateCount();
+            resultSet = statement.getResultSet();
+            do {
+                if (!ret) {
+                    if (updateCount != -1) {
+                        updateCountTotal += updateCount;
+                    }
+                } else if (print) {
+                    printResults(resultSet, out);
+                }
+                ret = statement.getMoreResults();
+                if (ret) {
+                    updateCount = statement.getUpdateCount();
+                    resultSet = statement.getResultSet();
+                }
+            } while (ret);
+
+            log(updateCountTotal + " rows affected", Project.MSG_VERBOSE);
+
+            if (print && showtrailers) {
+                out.println(updateCountTotal + " rows affected");
+            }
+            SQLWarning warning = conn.getWarnings();
+            while (warning != null) {
+                log(warning + " sql warning", Project.MSG_VERBOSE);
+                warning = warning.getNextWarning();
+            }
+            conn.clearWarnings();
+            goodSql++;
+        } catch (SQLException e) {
+            log("Failed to execute: " + sql, Project.MSG_ERR);
+            if (!onError.equals("continue")) {
+                throw e;
+            }
+            log(e.toString(), Project.MSG_ERR);
+        } finally {
+            if (resultSet != null) {
+                try {
+                    resultSet.close();
+                } catch (SQLException e) {
+                    //ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * print any results in the statement
+     * @deprecated since 1.6.x.
+     *             Use {@link #printResults(java.sql.ResultSet, java.io.PrintStream)
+     *             the two arg version} instead.
+     * @param out the place to print results
+     * @throws SQLException on SQL problems.
+     */
+    protected void printResults(PrintStream out) throws SQLException {
+        ResultSet rs = statement.getResultSet();
+        try {
+            printResults(rs, out);
+        } finally {
+            if (rs != null) {
+                rs.close();
+            }
+        }
+    }
+
+    /**
+     * print any results in the result set.
+     * @param rs the resultset to print information about
+     * @param out the place to print results
+     * @throws SQLException on SQL problems.
+     * @since Ant 1.6.3
+     */
+    protected void printResults(ResultSet rs, PrintStream out) throws SQLException {
+        if (rs != null) {
+            log("Processing new result set.", Project.MSG_VERBOSE);
+            ResultSetMetaData md = rs.getMetaData();
+            int columnCount = md.getColumnCount();
+            if (columnCount > 0) {
+                if (showheaders) {
+                    out.print(md.getColumnName(1));
+                    for (int col = 2; col <= columnCount; col++) {
+                         out.write(',');
+                         out.print(md.getColumnName(col));
+                    }
+                    out.println();
+                }
+                while (rs.next()) {
+                    printValue(rs, 1, out);
+                    for (int col = 2; col <= columnCount; col++) {
+                        out.write(',');
+                        printValue(rs, col, out);
+                    }
+                    out.println();
+                }
+            }
+        }
+        out.println();
+    }
+
+    private void printValue(ResultSet rs, int col, PrintStream out)
+            throws SQLException {
+        if (rawBlobs && rs.getMetaData().getColumnType(col) == Types.BLOB) {
+            new StreamPumper(rs.getBlob(col).getBinaryStream(), out).run();
+        } else {
+            out.print(rs.getString(col));
+        }
+    }
+
+    /*
+     * Closes an unused connection after an error and doesn't rethrow
+     * a possible SQLException
+     * @since Ant 1.7
+     */
+    private void closeQuietly() {
+        if (!isAutocommit() && conn != null && onError.equals("abort")) {
+            try {
+                conn.rollback();
+            } catch (SQLException ex) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * The action a task should perform on an error,
+     * one of "continue", "stop" and "abort"
+     */
+    public static class OnError extends EnumeratedAttribute {
+        /** @return the enumerated values */
+        public String[] getValues() {
+            return new String[] {"continue", "stop", "abort"};
+        }
+    }
+
+    /**
+     * Contains the definition of a new transaction element.
+     * Transactions allow several files or blocks of statements
+     * to be executed using the same JDBC connection and commit
+     * operation in between.
+     */
+    public class Transaction {
+        private Resource tSrcResource = null;
+        private String tSqlCommand = "";
+
+        /**
+         * Set the source file attribute.
+         * @param src the source file
+         */
+        public void setSrc(File src) {
+            //there are places (in this file, and perhaps elsewhere, where it is assumed
+            //that null is an acceptable parameter.
+            if (src != null) {
+                setSrcResource(new FileResource(src));
+            }
+        }
+
+        /**
+         * Set the source resource attribute.
+         * @param src the source file
+         * @since Ant 1.7
+         */
+        public void setSrcResource(Resource src) {
+            if (tSrcResource != null) {
+                throw new BuildException("only one resource per transaction");
+            }
+            tSrcResource = src;
+        }
+
+        /**
+         * Set inline text
+         * @param sql the inline text
+         */
+        public void addText(String sql) {
+            if (sql != null) {
+                this.tSqlCommand += sql;
+            }
+        }
+
+        /**
+         * Set the source resource.
+         * @param a the source resource collection.
+         * @since Ant 1.7
+         */
+        public void addConfigured(ResourceCollection a) {
+            if (a.size() != 1) {
+                throw new BuildException("only single argument resource "
+                                         + "collections are supported.");
+            }
+            setSrcResource((Resource) a.iterator().next());
+        }
+
+        /**
+         *
+         */
+        private void runTransaction(PrintStream out)
+            throws IOException, SQLException {
+            if (tSqlCommand.length() != 0) {
+                log("Executing commands", Project.MSG_INFO);
+                runStatements(new StringReader(tSqlCommand), out);
+            }
+
+            if (tSrcResource != null) {
+                log("Executing resource: " + tSrcResource.toString(),
+                    Project.MSG_INFO);
+                InputStream is = null;
+                Reader reader = null;
+                try {
+                    is = tSrcResource.getInputStream();
+                    reader = (encoding == null) ? new InputStreamReader(is)
+                        : new InputStreamReader(is, encoding);
+                    runStatements(reader, out);
+                } finally {
+                    FileUtils.close(is);
+                    FileUtils.close(reader);
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/SendEmail.java b/trunk/src/main/org/apache/tools/ant/taskdefs/SendEmail.java
new file mode 100644
index 0000000..58d5cdc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/SendEmail.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.taskdefs.email.EmailTask;
+
+/**
+ * A task to send SMTP email.
+ * This task can send mail using either plain
+ * text, UU encoding or Mime format mail depending on what is available.
+ * Attachments may be sent using nested FileSet
+ * elements.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task name="mail" category="network"
+ */
+public class SendEmail extends EmailTask {
+    /**
+     * Sets the mailport parameter of this build task.
+     * @param value mail port name.
+     *
+     * @deprecated since 1.5.x.
+     *             Use {@link #setMailport(int)} instead.
+     */
+    public void setMailport(Integer value) {
+        setMailport(value.intValue());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Sequential.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Sequential.java
new file mode 100644
index 0000000..6ef641b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Sequential.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+
+/**
+ * Sequential is a container task - it can contain other Ant tasks. The nested
+ * tasks are simply executed in sequence. Sequential's primary use is to support
+ * the sequential execution of a subset of tasks within the {@link Parallel Parallel Task}
+
+ * <p>
+ * The sequential task has no attributes and does not support any nested
+ * elements apart from Ant tasks. Any valid Ant task may be embedded within the
+ * sequential task.</p>
+ *
+ * @since Ant 1.4
+ * @ant.task category="control"
+ */
+public class Sequential extends Task implements TaskContainer {
+
+    /** Optional Vector holding the nested tasks */
+    private Vector nestedTasks = new Vector();
+
+    /**
+     * Add a nested task to Sequential.
+     * <p>
+     * @param nestedTask  Nested task to execute Sequential
+     * <p>
+     */
+    public void addTask(Task nestedTask) {
+        nestedTasks.addElement(nestedTask);
+    }
+
+    /**
+     * Execute all nestedTasks.
+     *
+     * @throws BuildException if one of the nested tasks fails.
+     */
+    public void execute() throws BuildException {
+        for (Iterator i = nestedTasks.iterator(); i.hasNext();) {
+            Task nestedTask = (Task) i.next();
+            nestedTask.perform();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/SignJar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/SignJar.java
new file mode 100644
index 0000000..4a30b6d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/SignJar.java
@@ -0,0 +1,500 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.IsSigned;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.FileNameMapper;
+
+/**
+ * Signs JAR or ZIP files with the javasign command line tool. The tool detailed
+ * dependency checking: files are only signed if they are not signed. The
+ * <tt>signjar</tt> attribute can point to the file to generate; if this file
+ * exists then its modification date is used as a cue as to whether to resign
+ * any JAR file.
+ *
+ * Timestamp driven signing is based on the unstable and inadequately documented
+ * information in the Java1.5 docs
+ * @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/time-of-signing-beta1.html">
+ * beta documentation</a>
+ * @ant.task category="java"
+ * @since Ant 1.1
+ */
+public class SignJar extends AbstractJarSignerTask {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * name to a signature file
+     */
+    protected String sigfile;
+
+    /**
+     * name of a single jar
+     */
+    protected File signedjar;
+
+    /**
+     * flag for internal sf signing
+     */
+    protected boolean internalsf;
+
+    /**
+     * sign sections only?
+     */
+    protected boolean sectionsonly;
+
+    /**
+     * flag to preserve timestamp on modified files
+     */
+    private boolean preserveLastModified;
+
+    /**
+     * Whether to assume a jar which has an appropriate .SF file in is already
+     * signed.
+     */
+    protected boolean lazy;
+
+    /**
+     * the output directory when using paths.
+     */
+    protected File destDir;
+
+    /**
+     * mapper for todir work
+     */
+    private FileNameMapper mapper;
+
+    /**
+     * URL for a tsa; null implies no tsa support
+     */
+    protected String tsaurl;
+
+    /**
+     * alias for the TSA in the keystore
+     */
+    protected String tsacert;
+
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_TODIR_AND_SIGNEDJAR
+            = "'destdir' and 'signedjar' cannot both be set";
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_TOO_MANY_MAPPERS = "Too many mappers";
+    /**
+     * error string for unit test verification {@value}
+     */
+    public static final String ERROR_SIGNEDJAR_AND_PATHS
+        = "You cannot specify the signed JAR when using paths or filesets";
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_BAD_MAP = "Cannot map source file to anything sensible: ";
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_MAPPER_WITHOUT_DEST
+        = "The destDir attribute is required if a mapper is set";
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_NO_ALIAS = "alias attribute must be set";
+    /**
+     * error string for unit test verification: {@value}
+     */
+    public static final String ERROR_NO_STOREPASS = "storepass attribute must be set";
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * name of .SF/.DSA file; optional
+     *
+     * @param sigfile the name of the .SF/.DSA file
+     */
+    public void setSigfile(final String sigfile) {
+        this.sigfile = sigfile;
+    }
+
+    /**
+     * name of signed JAR file; optional
+     *
+     * @param signedjar the name of the signed jar file
+     */
+    public void setSignedjar(final File signedjar) {
+        this.signedjar = signedjar;
+    }
+
+    /**
+     * Flag to include the .SF file inside the signature; optional; default
+     * false
+     *
+     * @param internalsf if true include the .SF file inside the signature
+     */
+    public void setInternalsf(final boolean internalsf) {
+        this.internalsf = internalsf;
+    }
+
+    /**
+     * flag to compute hash of entire manifest; optional, default false
+     *
+     * @param sectionsonly flag to compute hash of entire manifest
+     */
+    public void setSectionsonly(final boolean sectionsonly) {
+        this.sectionsonly = sectionsonly;
+    }
+
+    /**
+     * flag to control whether the presence of a signature file means a JAR is
+     * signed; optional, default false
+     *
+     * @param lazy flag to control whether the presence of a signature
+     */
+    public void setLazy(final boolean lazy) {
+        this.lazy = lazy;
+    }
+
+    /**
+     * Optionally sets the output directory to be used.
+     *
+     * @param destDir the directory in which to place signed jars
+     * @since Ant 1.7
+     */
+    public void setDestDir(File destDir) {
+        this.destDir = destDir;
+    }
+
+
+    /**
+     * add a mapper to determine file naming policy. Only used with toDir
+     * processing.
+     *
+     * @param newMapper the mapper to add.
+     * @since Ant 1.7
+     */
+    public void add(FileNameMapper newMapper) {
+        if (mapper != null) {
+            throw new BuildException(ERROR_TOO_MANY_MAPPERS);
+        }
+        mapper = newMapper;
+    }
+
+    /**
+     * get the active mapper; may be null
+     * @return mapper or null
+     * @since Ant 1.7
+     */
+    public FileNameMapper getMapper() {
+        return mapper;
+    }
+
+    /**
+     * get the -tsaurl url
+     * @return url or null
+     * @since Ant 1.7
+     */
+    public String getTsaurl() {
+        return tsaurl;
+    }
+
+    /**
+     *
+     * @param tsaurl the tsa url.
+     * @since Ant 1.7
+     */
+    public void setTsaurl(String tsaurl) {
+        this.tsaurl = tsaurl;
+    }
+
+    /**
+     * get the -tsacert option
+     * @since Ant 1.7
+     * @return a certificate alias or null
+     */
+    public String getTsacert() {
+        return tsacert;
+    }
+
+    /**
+     * set the alias in the keystore of the TSA to use;
+     * @param tsacert the cert alias.
+     */
+    public void setTsacert(String tsacert) {
+        this.tsacert = tsacert;
+    }
+
+    /**
+     * sign the jar(s)
+     *
+     * @throws BuildException on errors
+     */
+    public void execute() throws BuildException {
+        //validation logic
+        final boolean hasJar = jar != null;
+        final boolean hasSignedJar = signedjar != null;
+        final boolean hasDestDir = destDir != null;
+        final boolean hasMapper = mapper != null;
+
+        if (!hasJar && !hasResources()) {
+            throw new BuildException(ERROR_NO_SOURCE);
+        }
+        if (null == alias) {
+            throw new BuildException(ERROR_NO_ALIAS);
+        }
+
+        if (null == storepass) {
+            throw new BuildException(ERROR_NO_STOREPASS);
+        }
+
+        if (hasDestDir && hasSignedJar) {
+            throw new BuildException(ERROR_TODIR_AND_SIGNEDJAR);
+        }
+
+
+        if (hasResources() && hasSignedJar) {
+            throw new BuildException(ERROR_SIGNEDJAR_AND_PATHS);
+        }
+
+        //this isnt strictly needed, but by being fussy now,
+        //we can change implementation details later
+        if (!hasDestDir && hasMapper) {
+            throw new BuildException(ERROR_MAPPER_WITHOUT_DEST);
+        }
+
+        beginExecution();
+
+
+        try {
+            //special case single jar handling with signedjar attribute set
+            if (hasJar && hasSignedJar) {
+                // single jar processing
+                signOneJar(jar, signedjar);
+                //return here.
+                return;
+            }
+
+            //the rest of the method treats single jar like
+            //a nested path with one file
+
+            Path sources = createUnifiedSourcePath();
+            //set up our mapping policy
+            FileNameMapper destMapper;
+            if (hasMapper) {
+                destMapper = mapper;
+            } else {
+                //no mapper? use the identity policy
+                destMapper = new IdentityMapper();
+            }
+
+
+            //at this point the paths are set up with lists of files,
+            //and the mapper is ready to map from source dirs to dest files
+            //now we iterate through every JAR giving source and dest names
+            // deal with the paths
+            Iterator iter = sources.iterator();
+            while (iter.hasNext()) {
+                FileResource fr = (FileResource) iter.next();
+
+                //calculate our destination directory; it is either the destDir
+                //attribute, or the base dir of the fileset (for in situ updates)
+                File toDir = hasDestDir ? destDir : fr.getBaseDir();
+
+                //determine the destination filename via the mapper
+                String[] destFilenames = destMapper.mapFileName(fr.getName());
+                if (destFilenames == null || destFilenames.length != 1) {
+                    //we only like simple mappers.
+                    throw new BuildException(ERROR_BAD_MAP + fr.getFile());
+                }
+                File destFile = new File(toDir, destFilenames[0]);
+                signOneJar(fr.getFile(), destFile);
+            }
+        } finally {
+            endExecution();
+        }
+    }
+
+    /**
+     * Sign one jar.
+     * <p/>
+     * The signing only takes place if {@link #isUpToDate(File, File)} indicates
+     * that it is needed.
+     *
+     * @param jarSource source to sign
+     * @param jarTarget target; may be null
+     * @throws BuildException
+     */
+    private void signOneJar(File jarSource, File jarTarget)
+            throws BuildException {
+
+
+        File targetFile = jarTarget;
+        if (targetFile == null) {
+            targetFile = jarSource;
+        }
+        if (isUpToDate(jarSource, targetFile)) {
+            return;
+        }
+
+        long lastModified = jarSource.lastModified();
+        final ExecTask cmd = createJarSigner();
+
+        setCommonOptions(cmd);
+
+        bindToKeystore(cmd);
+        if (null != sigfile) {
+            addValue(cmd, "-sigfile");
+            String value = this.sigfile;
+            addValue(cmd, value);
+        }
+
+        //DO NOT SET THE -signedjar OPTION if source==dest
+        //unless you like fielding hotspot crash reports
+        if (!jarSource.equals(targetFile)) {
+            addValue(cmd, "-signedjar");
+            addValue(cmd, targetFile.getPath());
+        }
+
+        if (internalsf) {
+            addValue(cmd, "-internalsf");
+        }
+
+        if (sectionsonly) {
+            addValue(cmd, "-sectionsonly");
+        }
+
+        //add -tsa operations if declared
+        addTimestampAuthorityCommands(cmd);
+
+        //JAR source is required
+        addValue(cmd, jarSource.getPath());
+
+        //alias is required for signing
+        addValue(cmd, alias);
+
+        log("Signing JAR: "
+            + jarSource.getAbsolutePath()
+            + " to "
+            + targetFile.getAbsolutePath()
+            + " as " + alias);
+
+        cmd.execute();
+
+        // restore the lastModified attribute
+        if (preserveLastModified) {
+            targetFile.setLastModified(lastModified);
+        }
+    }
+
+    /**
+     * If the tsa parameters are set, this passes them to the command.
+     * There is no validation of java version, as third party JDKs
+     * may implement this on earlier/later jarsigner implementations.
+     * @param cmd the exec task.
+     */
+    private void addTimestampAuthorityCommands(final ExecTask cmd) {
+        if (tsaurl != null) {
+            addValue(cmd, "-tsa");
+            addValue(cmd, tsaurl);
+        }
+        if (tsacert != null) {
+            addValue(cmd, "-tsacert");
+            addValue(cmd, tsacert);
+        }
+    }
+
+    /**
+     * Compare a jar file with its corresponding signed jar. The logic for this
+     * is complex, and best explained in the source itself. Essentially if
+     * either file doesnt exist, or the destfile has an out of date timestamp,
+     * then the return value is false.
+     * <p/>
+     * If we are signing ourself, the check {@link #isSigned(File)} is used to
+     * trigger the process.
+     *
+     * @param jarFile       the unsigned jar file
+     * @param signedjarFile the result signed jar file
+     * @return true if the signedjarFile is considered up to date
+     */
+    protected boolean isUpToDate(File jarFile, File signedjarFile) {
+        if (null == jarFile || !jarFile.exists()) {
+            //these are pathological cases, but retained in case somebody
+            //subclassed us.
+            return false;
+        }
+
+        //we normally compare destination with source
+        File destFile = signedjarFile;
+        if (destFile == null) {
+            //but if no dest is specified, compare source to source
+            destFile = jarFile;
+        }
+
+        //if, by any means, the destfile and source match,
+        if (jarFile.equals(destFile)) {
+            if (lazy) {
+                //we check the presence of signatures on lazy signing
+                return isSigned(jarFile);
+            }
+            //unsigned or non-lazy self signings are always false
+            return false;
+        }
+
+        //if they are different, the timestamps are used
+        return FILE_UTILS.isUpToDate(jarFile, destFile);
+    }
+
+    /**
+     * test for a file being signed, by looking for a signature in the META-INF
+     * directory with our alias.
+     *
+     * @param file the file to be checked
+     * @return true if the file is signed
+     * @see IsSigned#isSigned(File, String)
+     */
+    protected boolean isSigned(File file) {
+        try {
+            return IsSigned.isSigned(file, alias);
+        } catch (IOException e) {
+            //just log this
+            log(e.toString(), Project.MSG_VERBOSE);
+            return false;
+        }
+    }
+
+    /**
+     * true to indicate that the signed jar modification date remains the same
+     * as the original. Defaults to false
+     *
+     * @param preserveLastModified if true preserve the last modified time
+     */
+    public void setPreserveLastModified(boolean preserveLastModified) {
+        this.preserveLastModified = preserveLastModified;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Sleep.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Sleep.java
new file mode 100644
index 0000000..7b0a058
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Sleep.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Sleep, or pause, for a period of time.
+ *
+ * A task for sleeping a short period of time, useful when a
+ * build or deployment process requires an interval between tasks.
+ *<p>
+ * A negative value can be supplied to any of attributes provided the total sleep time
+ * is positive, pending fundamental changes in physics and JVM
+ * execution times</p>
+ * Note that sleep times are always hints to be interpreted by the OS how it feels
+ * small times may either be ignored or rounded up to a minimum timeslice. Note
+ * also that the system clocks often have a fairly low granularity too, which complicates
+ * measuring how long a sleep actually took.</p>
+ *
+ * @since Ant 1.4
+ * @ant.task category="utility"
+ */
+
+public class Sleep extends Task {
+    /**
+     * failure flag
+     */
+    private boolean failOnError = true;
+
+    /**
+     * sleep seconds
+     */
+    private int seconds = 0;
+
+    /**
+     * sleep hours
+     */
+    private int hours = 0;
+    /**
+     * sleep minutes
+     */
+    private int minutes = 0;
+
+    /**
+     * sleep milliseconds
+     */
+    private int milliseconds = 0;
+
+
+
+    /**
+     * Creates new instance
+     */
+    public Sleep() {
+    }
+
+
+    /**
+     * seconds to add to the sleep time
+     *
+     * @param seconds The new Seconds value
+     */
+    public void setSeconds(int seconds) {
+        this.seconds = seconds;
+    }
+
+
+    /**
+     * hours to add to the sleep time.
+     *
+     * @param hours The new Hours value
+     */
+    public void setHours(int hours) {
+        this.hours = hours;
+    }
+
+
+    /**
+     * minutes to add to the sleep time
+     *
+     * @param minutes The new Minutes value
+     */
+    public void setMinutes(int minutes) {
+        this.minutes = minutes;
+    }
+
+
+    /**
+     * milliseconds to add to the sleep time
+     *
+     * @param milliseconds The new Milliseconds value
+     */
+    public void setMilliseconds(int milliseconds) {
+        this.milliseconds = milliseconds;
+    }
+
+
+    /**
+     * sleep for a period of time
+     *
+     * @param millis time to sleep
+     */
+    public void doSleep(long millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException ie) {
+            // Ignore Exception
+        }
+    }
+
+
+    /**
+     * flag controlling whether to break the build on an error.
+     *
+     * @param failOnError The new FailOnError value
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+
+    /**
+     * return time to sleep
+     *
+     * @return sleep time. if below 0 then there is an error
+     */
+
+    private long getSleepTime() {
+        // CheckStyle:MagicNumber OFF
+        return ((((long) hours * 60) + minutes) * 60 + seconds) * 1000
+            + milliseconds;
+        // CheckStyle:MagicNumber ON
+    }
+
+
+    /**
+     * verify parameters
+     *
+     * @throws BuildException if something is invalid
+     */
+    public void validate()
+        throws BuildException {
+        if (getSleepTime() < 0) {
+            throw new BuildException("Negative sleep periods are not "
+                                     + "supported");
+        }
+    }
+
+
+    /**
+     * Executes this build task. Throws org.apache.tools.ant.BuildException
+     * if there is an error during task execution.
+     *
+     * @exception BuildException Description of Exception
+     */
+    public void execute()
+        throws BuildException {
+        try {
+            validate();
+            long sleepTime = getSleepTime();
+            log("sleeping for " + sleepTime + " milliseconds",
+                Project.MSG_VERBOSE);
+            doSleep(sleepTime);
+        } catch (Exception e) {
+            if (failOnError) {
+                throw new BuildException(e);
+            } else {
+                String text = e.toString();
+                log(text, Project.MSG_ERR);
+            }
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java b/trunk/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java
new file mode 100644
index 0000000..6de3fc0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java
@@ -0,0 +1,180 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Copies all data from an input stream to an output stream.
+ *
+ * @since Ant 1.2
+ */
+public class StreamPumper implements Runnable {
+
+    private static final int SMALL_BUFFER_SIZE = 128;
+
+    private InputStream is;
+    private OutputStream os;
+    private volatile boolean finish;
+    private volatile boolean finished;
+    private boolean closeWhenExhausted;
+    private boolean autoflush = false;
+    private Exception exception = null;
+    private int bufferSize = SMALL_BUFFER_SIZE;
+    private boolean started = false;
+
+    /**
+     * Create a new StreamPumper.
+     *
+     * @param is input stream to read data from
+     * @param os output stream to write data to.
+     * @param closeWhenExhausted if true, the output stream will be closed when
+     *        the input is exhausted.
+     */
+    public StreamPumper(InputStream is, OutputStream os, boolean closeWhenExhausted) {
+        this.is = is;
+        this.os = os;
+        this.closeWhenExhausted = closeWhenExhausted;
+    }
+
+    /**
+     * Create a new StreamPumper.
+     *
+     * @param is input stream to read data from
+     * @param os output stream to write data to.
+     */
+    public StreamPumper(InputStream is, OutputStream os) {
+        this(is, os, false);
+    }
+
+    /**
+     * Set whether data should be flushed through to the output stream.
+     * @param autoflush if true, push through data; if false, let it be buffered
+     * @since Ant 1.6.3
+     */
+    /*package*/ void setAutoflush(boolean autoflush) {
+        this.autoflush = autoflush;
+    }
+
+    /**
+     * Copies data from the input stream to the output stream.
+     *
+     * Terminates as soon as the input stream is closed or an error occurs.
+     */
+    public void run() {
+        synchronized (this) {
+            started = true;
+        }
+        finished = false;
+        finish = false;
+
+        final byte[] buf = new byte[bufferSize];
+
+        int length;
+        try {
+            while (true) {
+                length = is.read(buf);
+                if ((length <= 0) || finish) {
+                    break;
+                }
+                os.write(buf, 0, length);
+                if (autoflush) {
+                    os.flush();
+                }
+            }
+            os.flush();
+        } catch (Exception e) {
+            synchronized (this) {
+                exception = e;
+            }
+        } finally {
+            if (closeWhenExhausted) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            finished = true;
+            synchronized (this) {
+                notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Tells whether the end of the stream has been reached.
+     * @return true is the stream has been exhausted.
+     */
+    public boolean isFinished() {
+        return finished;
+    }
+
+    /**
+     * This method blocks until the StreamPumper finishes.
+     * @throws InterruptedException if interrupted.
+     * @see #isFinished()
+     */
+    public synchronized void waitFor() throws InterruptedException {
+        while (!isFinished()) {
+            wait();
+        }
+    }
+
+    /**
+     * Set the size in bytes of the read buffer.
+     * @param bufferSize the buffer size to use.
+     * @throws IllegalStateException if the StreamPumper is already running.
+     */
+    public synchronized void setBufferSize(int bufferSize) {
+        if (started) {
+            throw new IllegalStateException("Cannot set buffer size on a running StreamPumper");
+        }
+        this.bufferSize = bufferSize;
+    }
+
+    /**
+     * Get the size in bytes of the read buffer.
+     * @return the int size of the read buffer.
+     */
+    public synchronized int getBufferSize() {
+        return bufferSize;
+    }
+
+    /**
+     * Get the exception encountered, if any.
+     * @return the Exception encountered.
+     */
+    public synchronized Exception getException() {
+        return exception;
+    }
+
+    /**
+     * Stop the pumper as soon as possible.
+     * Note that it may continue to block on the input stream
+     * but it will really stop the thread as soon as it gets EOF
+     * or any byte, and it will be marked as finished.
+     * @since Ant 1.6.3
+     */
+    /*package*/ synchronized void stop() {
+        finish = true;
+        notifyAll();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/SubAnt.java b/trunk/src/main/org/apache/tools/ant/taskdefs/SubAnt.java
new file mode 100644
index 0000000..71336a3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/SubAnt.java
@@ -0,0 +1,607 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.DirSet;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FileList;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+
+import org.apache.tools.ant.taskdefs.Ant.TargetElement;
+
+
+/**
+ * Calls a given target for all defined sub-builds. This is an extension
+ * of ant for bulk project execution.
+ * <p>
+ * <h2> Use with directories </h2>
+ * <p>
+ * subant can be used with directory sets to execute a build from different directories.
+ * 2 different options are offered
+ * </p>
+ * <ul>
+ * <li>
+ * run the same build file /somepath/otherpath/mybuild.xml
+ * with different base directories use the genericantfile attribute
+ * </li>
+ * <li>if you want to run directory1/build.xml, directory2/build.xml, ....
+ * use the antfile attribute. The base directory does not get set by the subant task in this case,
+ * because you can specify it in each build file.
+ * </li>
+ * </ul>
+ * @since Ant1.6
+ * @ant.task name="subant" category="control"
+ */
+public class SubAnt
+             extends Task {
+
+    private Path buildpath;
+
+    private Ant ant = null;
+    private String subTarget = null;
+    private String antfile = "build.xml";
+    private File genericantfile = null;
+    private boolean verbose = false;
+    private boolean inheritAll = false;
+    private boolean inheritRefs = false;
+    private boolean failOnError = true;
+    private String output  = null;
+
+    private Vector properties = new Vector();
+    private Vector references = new Vector();
+    private Vector propertySets = new Vector();
+
+    /** the targets to call on the new project */
+    private Vector/*<TargetElement>*/ targets = new Vector();
+
+    /**
+     * Pass output sent to System.out to the new project.
+     *
+     * @param output a line of output
+     * @since Ant 1.6.2
+     */
+    public void handleOutput(String output) {
+        if (ant != null) {
+            ant.handleOutput(output);
+        } else {
+            super.handleOutput(output);
+        }
+    }
+
+    /**
+     * Process input into the ant task
+     *
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read
+     *
+     * @return the number of bytes read
+     *
+     * @exception IOException if the data cannot be read
+     *
+     * @see Task#handleInput(byte[], int, int)
+     *
+     * @since Ant 1.6.2
+     */
+    public int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (ant != null) {
+            return ant.handleInput(buffer, offset, length);
+        } else {
+            return super.handleInput(buffer, offset, length);
+        }
+    }
+
+    /**
+     * Pass output sent to System.out to the new project.
+     *
+     * @param output The output to log. Should not be <code>null</code>.
+     *
+     * @since Ant 1.6.2
+     */
+    public void handleFlush(String output) {
+        if (ant != null) {
+            ant.handleFlush(output);
+        } else {
+            super.handleFlush(output);
+        }
+    }
+
+    /**
+     * Pass output sent to System.err to the new project.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     *
+     * @since Ant 1.6.2
+     */
+    public void handleErrorOutput(String output) {
+        if (ant != null) {
+            ant.handleErrorOutput(output);
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+    /**
+     * Pass output sent to System.err to the new project.
+     *
+     * @param output The error output to log. Should not be <code>null</code>.
+     *
+     * @since Ant 1.6.2
+     */
+    public void handleErrorFlush(String output) {
+        if (ant != null) {
+            ant.handleErrorFlush(output);
+        } else {
+            super.handleErrorFlush(output);
+        }
+    }
+
+    /**
+     * Runs the various sub-builds.
+     */
+    public void execute() {
+        if (buildpath == null) {
+            throw new BuildException("No buildpath specified");
+        }
+
+        final String[] filenames = buildpath.list();
+        final int count = filenames.length;
+        if (count < 1) {
+            log("No sub-builds to iterate on", Project.MSG_WARN);
+            return;
+        }
+/*
+    //REVISIT: there must be cleaner way of doing this, if it is merited at all
+        if (subTarget == null) {
+            subTarget = getOwningTarget().getName();
+        }
+*/
+        BuildException buildException = null;
+        for (int i = 0; i < count; ++i) {
+            File file = null;
+            String subdirPath = null;
+            Throwable thrownException = null;
+            try {
+                File directory = null;
+                file = new File(filenames[i]);
+                if (file.isDirectory()) {
+                    if (verbose) {
+                        subdirPath = file.getPath();
+                        log("Entering directory: " + subdirPath + "\n", Project.MSG_INFO);
+                    }
+                    if (genericantfile != null) {
+                        directory = file;
+                        file = genericantfile;
+                    } else {
+                        file = new File(file, antfile);
+                    }
+                }
+                execute(file, directory);
+                if (verbose && subdirPath != null) {
+                    log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO);
+                }
+            } catch (RuntimeException ex) {
+                if (!(getProject().isKeepGoingMode())) {
+                    if (verbose && subdirPath != null) {
+                        log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO);
+                    }
+                    throw ex; // throw further
+                }
+                thrownException = ex;
+            } catch (Throwable ex) {
+                if (!(getProject().isKeepGoingMode())) {
+                    if (verbose && subdirPath != null) {
+                        log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO);
+                    }
+                    throw new BuildException(ex);
+                }
+                thrownException = ex;
+            }
+            if (thrownException != null) {
+                if (thrownException instanceof BuildException) {
+                    log("File '" + file
+                        + "' failed with message '"
+                        + thrownException.getMessage() + "'.", Project.MSG_ERR);
+                    // only the first build exception is reported
+                    if (buildException == null) {
+                        buildException = (BuildException) thrownException;
+                    }
+                } else {
+                    log("Target '" + file
+                        + "' failed with message '"
+                        + thrownException.getMessage() + "'.", Project.MSG_ERR);
+                    thrownException.printStackTrace(System.err);
+                    if (buildException == null) {
+                        buildException =
+                            new BuildException(thrownException);
+                    }
+                }
+                if (verbose && subdirPath != null) {
+                    log("Leaving directory: " + subdirPath + "\n", Project.MSG_INFO);
+                }
+            }
+        }
+        // check if one of the builds failed in keep going mode
+        if (buildException != null) {
+            throw buildException;
+        }
+    }
+
+    /**
+     * Runs the given target on the provided build file.
+     *
+     * @param  file the build file to execute
+     * @param  directory the directory of the current iteration
+     * @throws BuildException is the file cannot be found, read, is
+     *         a directory, or the target called failed, but only if
+     *         <code>failOnError</code> is <code>true</code>. Otherwise,
+     *         a warning log message is simply output.
+     */
+    private void execute(File file, File directory)
+                throws BuildException {
+        if (!file.exists() || file.isDirectory() || !file.canRead()) {
+            String msg = "Invalid file: " + file;
+            if (failOnError) {
+                throw new BuildException(msg);
+            }
+            log(msg, Project.MSG_WARN);
+            return;
+        }
+
+        ant = createAntTask(directory);
+        String antfilename = file.getAbsolutePath();
+        ant.setAntfile(antfilename);
+        for (int i = 0; i < targets.size(); i++) {
+            TargetElement targetElement = (TargetElement) targets.get(i);
+            ant.addConfiguredTarget(targetElement);
+        }
+
+        try {
+            ant.execute();
+        } catch (BuildException e) {
+            if (failOnError) {
+                throw e;
+            }
+            log("Failure for target '" + subTarget
+               + "' of: " +  antfilename + "\n"
+               + e.getMessage(), Project.MSG_WARN);
+        } catch (Throwable e) {
+            if (failOnError) {
+                throw new BuildException(e);
+            }
+            log("Failure for target '" + subTarget
+                + "' of: " + antfilename + "\n"
+                + e.toString(),
+                Project.MSG_WARN);
+        } finally {
+            ant = null;
+        }
+    }
+
+    /**
+     * This method builds the file name to use in conjunction with directories.
+     *
+     * <p>Defaults to "build.xml".
+     * If <code>genericantfile</code> is set, this attribute is ignored.</p>
+     *
+     * @param  antfile the short build file name. Defaults to "build.xml".
+     */
+    public void setAntfile(String antfile) {
+        this.antfile = antfile;
+    }
+
+    /**
+     * This method builds a file path to use in conjunction with directories.
+     *
+     * <p>Use <code>genericantfile</code>, in order to run the same build file
+     * with different basedirs.</p>
+     * If this attribute is set, <code>antfile</code> is ignored.
+     *
+     * @param afile (path of the generic ant file, absolute or relative to
+     *               project base directory)
+     * */
+    public void setGenericAntfile(File afile) {
+        this.genericantfile = afile;
+    }
+
+    /**
+     * Sets whether to fail with a build exception on error, or go on.
+     *
+     * @param  failOnError the new value for this boolean flag.
+     */
+    public void setFailonerror(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * The target to call on the different sub-builds. Set to "" to execute
+     * the default target.
+     * @param target the target
+     * <p>
+     */
+    //     REVISIT: Defaults to the target name that contains this task if not specified.
+    public void setTarget(String target) {
+        this.subTarget = target;
+    }
+
+    /**
+     * Add a target to this Ant invocation.
+     * @param t the <code>TargetElement</code> to add.
+     * @since Ant 1.7
+     */
+    public void addConfiguredTarget(TargetElement t) {
+        String name = t.getName();
+        if ("".equals(name)) {
+            throw new BuildException("target name must not be empty");
+        }
+        targets.add(t);
+    }
+
+    /**
+     * Enable/ disable verbose log messages showing when each sub-build path is entered/ exited.
+     * The default value is "false".
+     * @param on true to enable verbose mode, false otherwise (default).
+     */
+    public void setVerbose(boolean on) {
+        this.verbose = on;
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * <code>output</code> attribute.
+     *
+     * @param  s the filename to write the output to.
+     */
+    public void setOutput(String s) {
+        this.output = s;
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * <code>inheritall</code> attribute.
+     *
+     * @param  b the new value for this boolean flag.
+     */
+    public void setInheritall(boolean b) {
+        this.inheritAll = b;
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * <code>inheritrefs</code> attribute.
+     *
+     * @param  b the new value for this boolean flag.
+     */
+    public void setInheritrefs(boolean b) {
+        this.inheritRefs = b;
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * nested <code>&lt;property&gt;</code> element.
+     *
+     * @param  p the property to pass on explicitly to the sub-build.
+     */
+    public void addProperty(Property p) {
+        properties.addElement(p);
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * nested <code>&lt;reference&gt;</code> element.
+     *
+     * @param  r the reference to pass on explicitly to the sub-build.
+     */
+    public void addReference(Ant.Reference r) {
+        references.addElement(r);
+    }
+
+    /**
+     * Corresponds to <code>&lt;ant&gt;</code>'s
+     * nested <code>&lt;propertyset&gt;</code> element.
+     * @param ps the propertset
+     */
+    public void addPropertyset(PropertySet ps) {
+        propertySets.addElement(ps);
+    }
+
+    /**
+     * Adds a directory set to the implicit build path.
+     * <p>
+     * <em>Note that the directories will be added to the build path
+     * in no particular order, so if order is significant, one should
+     * use a file list instead!</em>
+     *
+     * @param  set the directory set to add.
+     */
+    public void addDirset(DirSet set) {
+        add(set);
+    }
+
+    /**
+     * Adds a file set to the implicit build path.
+     * <p>
+     * <em>Note that the directories will be added to the build path
+     * in no particular order, so if order is significant, one should
+     * use a file list instead!</em>
+     *
+     * @param  set the file set to add.
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Adds an ordered file list to the implicit build path.
+     * <p>
+     * <em>Note that contrary to file and directory sets, file lists
+     * can reference non-existent files or directories!</em>
+     *
+     * @param  list the file list to add.
+     */
+    public void addFilelist(FileList list) {
+        add(list);
+    }
+
+    /**
+     * Adds a resource collection to the implicit build path.
+     *
+     * @param  rc the resource collection to add.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        getBuildpath().add(rc);
+    }
+
+    /**
+     * Set the buildpath to be used to find sub-projects.
+     *
+     * @param  s an Ant Path object containing the buildpath.
+     */
+    public void setBuildpath(Path s) {
+        getBuildpath().append(s);
+    }
+
+    /**
+     * Creates a nested build path, and add it to the implicit build path.
+     *
+     * @return the newly created nested build path.
+     */
+    public Path createBuildpath() {
+        return getBuildpath().createPath();
+    }
+
+    /**
+     * Creates a nested <code>&lt;buildpathelement&gt;</code>,
+     * and add it to the implicit build path.
+     *
+     * @return the newly created nested build path element.
+     */
+    public Path.PathElement createBuildpathElement() {
+        return getBuildpath().createPathElement();
+    }
+
+    /**
+     * Gets the implicit build path, creating it if <code>null</code>.
+     *
+     * @return the implicit build path.
+     */
+    private Path getBuildpath() {
+        if (buildpath == null) {
+            buildpath = new Path(getProject());
+        }
+        return buildpath;
+    }
+
+    /**
+     * Buildpath to use, by reference.
+     *
+     * @param  r a reference to an Ant Path object containing the buildpath.
+     */
+    public void setBuildpathRef(Reference r) {
+        createBuildpath().setRefid(r);
+    }
+
+    /**
+     * Creates the &lt;ant&gt; task configured to run a specific target.
+     *
+     * @param directory : if not null the directory where the build should run
+     *
+     * @return the ant task, configured with the explicit properties and
+     *         references necessary to run the sub-build.
+     */
+    private Ant createAntTask(File directory) {
+        Ant antTask = new Ant(this);
+        antTask.init();
+        if (subTarget != null && subTarget.length() > 0) {
+            antTask.setTarget(subTarget);
+        }
+
+
+        if (output != null) {
+            antTask.setOutput(output);
+        }
+
+        if (directory != null) {
+            antTask.setDir(directory);
+        }
+
+        antTask.setInheritAll(inheritAll);
+        for (Enumeration i = properties.elements(); i.hasMoreElements();) {
+            copyProperty(antTask.createProperty(), (Property) i.nextElement());
+        }
+
+        for (Enumeration i = propertySets.elements(); i.hasMoreElements();) {
+            antTask.addPropertyset((PropertySet) i.nextElement());
+        }
+
+        antTask.setInheritRefs(inheritRefs);
+        for (Enumeration i = references.elements(); i.hasMoreElements();) {
+            antTask.addReference((Ant.Reference) i.nextElement());
+        }
+
+        return antTask;
+    }
+
+    /**
+     * Assigns an Ant property to another.
+     *
+     * @param  to the destination property whose content is modified.
+     * @param  from the source property whose content is copied.
+     */
+    private static void copyProperty(Property to, Property from) {
+        to.setName(from.getName());
+
+        if (from.getValue() != null) {
+            to.setValue(from.getValue());
+        }
+        if (from.getFile() != null) {
+            to.setFile(from.getFile());
+        }
+        if (from.getResource() != null) {
+            to.setResource(from.getResource());
+        }
+        if (from.getPrefix() != null) {
+            to.setPrefix(from.getPrefix());
+        }
+        if (from.getRefid() != null) {
+            to.setRefid(from.getRefid());
+        }
+        if (from.getEnvironment() != null) {
+            to.setEnvironment(from.getEnvironment());
+        }
+        if (from.getClasspath() != null) {
+            to.setClasspath(from.getClasspath());
+        }
+    }
+
+} // END class SubAnt
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Sync.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Sync.java
new file mode 100644
index 0000000..51549a3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Sync.java
@@ -0,0 +1,472 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.AbstractFileSet;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.NoneSelector;
+
+/**
+ * Synchronize a local target directory from the files defined
+ * in one or more filesets.
+ *
+ * <p>Uses a &lt;copy&gt; task internally, but forbidding the use of
+ * mappers and filter chains. Files of the destination directory not
+ * present in any of the source fileset are removed.</p>
+ *
+ * @since Ant 1.6
+ *
+ * revised by <a href="mailto:daniel.armbrust@mayo.edu">Dan Armbrust</a>
+ * to remove orphaned directories.
+ *
+ * @ant.task category="filesystem"
+ */
+public class Sync extends Task {
+
+    // Same as regular <copy> task... see at end-of-file!
+    private MyCopy myCopy;
+
+    // Similar to a fileset, but doesn't allow dir attribute to be set
+    private SyncTarget syncTarget;
+
+    // Override Task#init
+    /**
+     * Initialize the sync task.
+     * @throws BuildException if there is a problem.
+     * @see Task#init()
+     */
+    public void init()
+        throws BuildException {
+        // Instantiate it
+        myCopy = new MyCopy();
+        configureTask(myCopy);
+
+        // Default config of <mycopy> for our purposes.
+        myCopy.setFiltering(false);
+        myCopy.setIncludeEmptyDirs(false);
+        myCopy.setPreserveLastModified(true);
+    }
+
+    private void configureTask(Task helper) {
+        helper.setProject(getProject());
+        helper.setTaskName(getTaskName());
+        helper.setOwningTarget(getOwningTarget());
+        helper.init();
+    }
+
+    // Override Task#execute
+    /**
+     * Execute the sync task.
+     * @throws BuildException if there is an error.
+     * @see Task#execute()
+     */
+    public void execute()
+        throws BuildException {
+        // The destination of the files to copy
+        File toDir = myCopy.getToDir();
+
+        // The complete list of files to copy
+        Set allFiles = myCopy.nonOrphans;
+
+        // If the destination directory didn't already exist,
+        // or was empty, then no previous file removal is necessary!
+        boolean noRemovalNecessary = !toDir.exists() || toDir.list().length < 1;
+
+        // Copy all the necessary out-of-date files
+        log("PASS#1: Copying files to " + toDir, Project.MSG_DEBUG);
+        myCopy.execute();
+
+        // Do we need to perform further processing?
+        if (noRemovalNecessary) {
+            log("NO removing necessary in " + toDir, Project.MSG_DEBUG);
+            return; // nope ;-)
+        }
+
+        // Get rid of all files not listed in the source filesets.
+        log("PASS#2: Removing orphan files from " + toDir, Project.MSG_DEBUG);
+        int[] removedFileCount = removeOrphanFiles(allFiles, toDir);
+        logRemovedCount(removedFileCount[0], "dangling director", "y", "ies");
+        logRemovedCount(removedFileCount[1], "dangling file", "", "s");
+
+        // Get rid of empty directories on the destination side
+        if (!myCopy.getIncludeEmptyDirs()) {
+            log("PASS#3: Removing empty directories from " + toDir,
+                Project.MSG_DEBUG);
+            int removedDirCount = removeEmptyDirectories(toDir, false);
+            logRemovedCount(removedDirCount, "empty director", "y", "ies");
+        }
+    }
+
+    private void logRemovedCount(int count, String prefix,
+                                 String singularSuffix, String pluralSuffix) {
+        File toDir = myCopy.getToDir();
+
+        String what = (prefix == null) ? "" : prefix;
+        what += (count < 2) ? singularSuffix : pluralSuffix;
+
+        if (count > 0) {
+            log("Removed " + count + " " + what + " from " + toDir,
+                Project.MSG_INFO);
+        } else {
+            log("NO " + what + " to remove from " + toDir,
+                Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * Removes all files and folders not found as keys of a table
+     * (used as a set!).
+     *
+     * <p>If the provided file is a directory, it is recursively
+     * scanned for orphaned files which will be removed as well.</p>
+     *
+     * <p>If the directory is an orphan, it will also be removed.</p>
+     *
+     * @param  nonOrphans the table of all non-orphan <code>File</code>s.
+     * @param  file the initial file or directory to scan or test.
+     * @return the number of orphaned files and directories actually removed.
+     * Position 0 of the array is the number of orphaned directories.
+     * Position 1 of the array is the number or orphaned files.
+     */
+    private int[] removeOrphanFiles(Set nonOrphans, File toDir) {
+        int[] removedCount = new int[] {0, 0};
+        String[] excls =
+            (String[]) nonOrphans.toArray(new String[nonOrphans.size() + 1]);
+        // want to keep toDir itself
+        excls[nonOrphans.size()] = "";
+
+        DirectoryScanner ds = null;
+        if (syncTarget != null) {
+            FileSet fs = new FileSet();
+            fs.setDir(toDir);
+            fs.setCaseSensitive(syncTarget.isCaseSensitive());
+            fs.setFollowSymlinks(syncTarget.isFollowSymlinks());
+
+            // preserveInTarget would find all files we want to keep,
+            // but we need to find all that we want to delete - so the
+            // meaning of all patterns and selectors must be inverted
+            PatternSet ps = syncTarget.mergePatterns(getProject());
+            fs.appendExcludes(ps.getIncludePatterns(getProject()));
+            fs.appendIncludes(ps.getExcludePatterns(getProject()));
+            fs.setDefaultexcludes(!syncTarget.getDefaultexcludes());
+
+            // selectors are implicitly ANDed in DirectoryScanner.  To
+            // revert their logic we wrap them into a <none> selector
+            // instead.
+            FileSelector[] s = syncTarget.getSelectors(getProject());
+            if (s.length > 0) {
+                NoneSelector ns = new NoneSelector();
+                for (int i = 0; i < s.length; i++) {
+                    ns.appendSelector(s[i]);
+                }
+                fs.appendSelector(ns);
+            }
+            ds = fs.getDirectoryScanner(getProject());
+        } else {
+            ds = new DirectoryScanner();
+            ds.setBasedir(toDir);
+        }
+        ds.addExcludes(excls);
+
+        ds.scan();
+        String[] files = ds.getIncludedFiles();
+        for (int i = 0; i < files.length; i++) {
+            File f = new File(toDir, files[i]);
+            log("Removing orphan file: " + f, Project.MSG_DEBUG);
+            f.delete();
+            ++removedCount[1];
+        }
+        String[] dirs = ds.getIncludedDirectories();
+        // ds returns the directories in lexicographic order.
+        // iterating through the array backwards means we are deleting
+        // leaves before their parent nodes - thus making sure (well,
+        // more likely) that the directories are empty when we try to
+        // delete them.
+        for (int i = dirs.length - 1; i >= 0; --i) {
+            File f = new File(toDir, dirs[i]);
+            if (f.list().length < 1) {
+            log("Removing orphan directory: " + f, Project.MSG_DEBUG);
+            f.delete();
+            ++removedCount[0];
+            }
+        }
+        return removedCount;
+    }
+
+    /**
+     * Removes all empty directories from a directory.
+     *
+     * <p><em>Note that a directory that contains only empty
+     * directories, directly or not, will be removed!</em></p>
+     *
+     * <p>Recurses depth-first to find the leaf directories
+     * which are empty and removes them, then unwinds the
+     * recursion stack, removing directories which have
+     * become empty themselves, etc...</p>
+     *
+     * @param  dir the root directory to scan for empty directories.
+     * @param  removeIfEmpty whether to remove the root directory
+     *         itself if it becomes empty.
+     * @return the number of empty directories actually removed.
+     */
+    private int removeEmptyDirectories(File dir, boolean removeIfEmpty) {
+        int removedCount = 0;
+        if (dir.isDirectory()) {
+            File[] children = dir.listFiles();
+            for (int i = 0; i < children.length; ++i) {
+                File file = children[i];
+                // Test here again to avoid method call for non-directories!
+                if (file.isDirectory()) {
+                    removedCount += removeEmptyDirectories(file, true);
+                }
+            }
+            if (children.length > 0) {
+                // This directory may have become empty...
+                // We need to re-query its children list!
+                children = dir.listFiles();
+            }
+            if (children.length < 1 && removeIfEmpty) {
+                log("Removing empty directory: " + dir, Project.MSG_DEBUG);
+                dir.delete();
+                ++removedCount;
+            }
+        }
+        return removedCount;
+    }
+
+
+    //
+    // Various copy attributes/subelements of <copy> passed thru to <mycopy>
+    //
+
+    /**
+     * Sets the destination directory.
+     * @param destDir the destination directory
+     */
+    public void setTodir(File destDir) {
+        myCopy.setTodir(destDir);
+    }
+
+    /**
+     * Used to force listing of all names of copied files.
+     * @param verbose if true force listing of all names of copied files.
+     */
+    public void setVerbose(boolean verbose) {
+        myCopy.setVerbose(verbose);
+    }
+
+    /**
+     * Overwrite any existing destination file(s).
+     * @param overwrite if true overwrite any existing destination file(s).
+     */
+    public void setOverwrite(boolean overwrite) {
+        myCopy.setOverwrite(overwrite);
+    }
+
+    /**
+     * Used to copy empty directories.
+     * @param includeEmpty If true copy empty directories.
+     */
+    public void setIncludeEmptyDirs(boolean includeEmpty) {
+        myCopy.setIncludeEmptyDirs(includeEmpty);
+    }
+
+    /**
+     * If false, note errors to the output but keep going.
+     * @param failonerror true or false
+     */
+    public void setFailOnError(boolean failonerror) {
+        myCopy.setFailOnError(failonerror);
+    }
+
+    /**
+     * Adds a set of files to copy.
+     * @param set a fileset
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Adds a collection of filesystem resources to copy.
+     * @param rc a resource collection
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        myCopy.add(rc);
+    }
+
+    /**
+     * The number of milliseconds leeway to give before deciding a
+     * target is out of date.
+     *
+     * <p>Default is 0 milliseconds, or 2 seconds on DOS systems.</p>
+     * @param granularity a <code>long</code> value
+     * @since Ant 1.6.2
+     */
+    public void setGranularity(long granularity) {
+        myCopy.setGranularity(granularity);
+    }
+
+    /**
+     * A container for patterns and selectors that can be used to
+     * specify files that should be kept in the target even if they
+     * are not present in any source directory.
+     *
+     * <p>You must not invoke this method more than once.</p>
+     * @param s a preserveintarget nested element
+     * @since Ant 1.7
+     */
+    public void addPreserveInTarget(SyncTarget s) {
+        if (syncTarget != null) {
+            throw new BuildException("you must not specify multiple "
+                                     + "preserveintarget elements.");
+        }
+        syncTarget = s;
+    }
+
+    /**
+     * Subclass Copy in order to access it's file/dir maps.
+     */
+    public static class MyCopy extends Copy {
+
+        // List of files that must be copied, irrelevant from the
+        // fact that they are newer or not than the destination.
+        private Set nonOrphans = new HashSet();
+
+        /** Constructor for MyCopy. */
+        public MyCopy() {
+        }
+
+        /**
+         * @see Copy#scan(File, File, String[], String[])
+         */
+        /** {@inheritDoc} */
+        protected void scan(File fromDir, File toDir, String[] files,
+                            String[] dirs) {
+            assertTrue("No mapper", mapperElement == null);
+
+            super.scan(fromDir, toDir, files, dirs);
+
+            for (int i = 0; i < files.length; ++i) {
+                nonOrphans.add(files[i]);
+            }
+            for (int i = 0; i < dirs.length; ++i) {
+                nonOrphans.add(dirs[i]);
+            }
+        }
+
+        /**
+         * @see Copy#scan(Resource[], File)
+         */
+        /** {@inheritDoc} */
+        protected Map scan(Resource[] resources, File toDir) {
+            assertTrue("No mapper", mapperElement == null);
+
+            Map m = super.scan(resources, toDir);
+
+            Iterator iter = m.keySet().iterator();
+            while (iter.hasNext()) {
+                nonOrphans.add(((Resource) iter.next()).getName());
+            }
+            return m;
+        }
+
+        /**
+         * Get the destination directory.
+         * @return the destination directory
+         */
+        public File getToDir() {
+            return destDir;
+        }
+
+        /**
+         * Get the includeEmptyDirs attribute.
+         * @return true if emptyDirs are to be included
+         */
+        public boolean getIncludeEmptyDirs() {
+            return includeEmpty;
+        }
+
+        /**
+         * Yes, we can.
+         * @return true always.
+         * @since Ant 1.7
+         */
+        protected boolean supportsNonFileResources() {
+            return true;
+        }
+    }
+
+    /**
+     * Inner class used to hold exclude patterns and selectors to save
+     * stuff that happens to live in the target directory but should
+     * not get removed.
+     *
+     * @since Ant 1.7
+     */
+    public static class SyncTarget extends AbstractFileSet {
+
+        /**
+         * Constructor for SyncTarget.
+         * This just changes the default value of "defaultexcludes" from
+         * true to false.
+         */
+        public SyncTarget() {
+            super();
+        }
+
+        /**
+         * Override AbstractFileSet#setDir(File) to disallow
+         * setting the directory.
+         * @param dir ignored
+         * @throws BuildException always
+         */
+        public void setDir(File dir) throws BuildException {
+            throw new BuildException("preserveintarget doesn't support the dir "
+                                     + "attribute");
+        }
+
+    }
+
+    /**
+     * Pseudo-assert method.
+     */
+    private static void assertTrue(String message, boolean condition) {
+        if (!condition) {
+            throw new BuildException("Assertion Error: " + message);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Tar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Tar.java
new file mode 100644
index 0000000..4a08a6d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Tar.java
@@ -0,0 +1,952 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.zip.GZIPOutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.ArchiveFileSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.ArchiveResource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.types.resources.TarResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.MergingMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.bzip2.CBZip2OutputStream;
+import org.apache.tools.tar.TarConstants;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarOutputStream;
+
+/**
+ * Creates a tar archive.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+public class Tar extends MatchingTask {
+    private static final int BUFFER_SIZE = 8 * 1024;
+
+    /**
+     * @deprecated since 1.5.x.
+     *             Tar.WARN is deprecated and is replaced with
+     *             Tar.TarLongFileMode.WARN
+     */
+    public static final String WARN = "warn";
+    /**
+     * @deprecated since 1.5.x.
+     *             Tar.FAIL is deprecated and is replaced with
+     *             Tar.TarLongFileMode.FAIL
+     */
+    public static final String FAIL = "fail";
+    /**
+     * @deprecated since 1.5.x.
+     *             Tar.TRUNCATE is deprecated and is replaced with
+     *             Tar.TarLongFileMode.TRUNCATE
+     */
+    public static final String TRUNCATE = "truncate";
+    /**
+     * @deprecated since 1.5.x.
+     *             Tar.GNU is deprecated and is replaced with
+     *             Tar.TarLongFileMode.GNU
+     */
+    public static final String GNU = "gnu";
+    /**
+     * @deprecated since 1.5.x.
+     *             Tar.OMIT is deprecated and is replaced with
+     *             Tar.TarLongFileMode.OMIT
+     */
+    public static final String OMIT = "omit";
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    File tarFile;
+    File baseDir;
+
+    private TarLongFileMode longFileMode = new TarLongFileMode();
+
+    // need to keep the package private version for backwards compatibility
+    Vector filesets = new Vector();
+    // we must keep two lists since other classes may modify the
+    // filesets Vector (it is package private) without us noticing
+    private Vector resourceCollections = new Vector();
+
+    Vector fileSetFiles = new Vector();
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Indicates whether the user has been warned about long files already.
+     */
+    private boolean longWarningGiven = false;
+
+    private TarCompressionMethod compression = new TarCompressionMethod();
+
+    /**
+     * Add a new fileset with the option to specify permissions
+     * @return the tar fileset to be used as the nested element.
+     */
+    public TarFileSet createTarFileSet() {
+        TarFileSet fs = new TarFileSet();
+        fs.setProject(getProject());
+        filesets.addElement(fs);
+        return fs;
+    }
+
+    /**
+     * Add a collection of resources to archive.
+     * @param res a resource collection to archive.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection res) {
+        resourceCollections.add(res);
+    }
+
+    /**
+     * Set is the name/location of where to create the tar file.
+     * @param tarFile the location of the tar file.
+     * @deprecated since 1.5.x.
+     *             For consistency with other tasks, please use setDestFile().
+     */
+    public void setTarfile(File tarFile) {
+        this.tarFile = tarFile;
+    }
+
+    /**
+     * Set is the name/location of where to create the tar file.
+     * @since Ant 1.5
+     * @param destFile The output of the tar
+     */
+    public void setDestFile(File destFile) {
+        this.tarFile = destFile;
+    }
+
+    /**
+     * This is the base directory to look in for things to tar.
+     * @param baseDir the base directory.
+     */
+    public void setBasedir(File baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * Set how to handle long files, those with a path&gt;100 chars.
+     * Optional, default=warn.
+     * <p>
+     * Allowable values are
+     * <ul>
+     * <li>  truncate - paths are truncated to the maximum length
+     * <li>  fail - paths greater than the maximum cause a build exception
+     * <li>  warn - paths greater than the maximum cause a warning and GNU is used
+     * <li>  gnu - GNU extensions are used for any paths greater than the maximum.
+     * <li>  omit - paths greater than the maximum are omitted from the archive
+     * </ul>
+     * @param mode the mode string to handle long files.
+     * @deprecated since 1.5.x.
+     *             setLongFile(String) is deprecated and is replaced with
+     *             setLongFile(Tar.TarLongFileMode) to make Ant's Introspection
+     *             mechanism do the work and also to encapsulate operations on
+     *             the mode in its own class.
+     */
+    public void setLongfile(String mode) {
+        log("DEPRECATED - The setLongfile(String) method has been deprecated."
+            + " Use setLongfile(Tar.TarLongFileMode) instead.");
+        this.longFileMode = new TarLongFileMode();
+        longFileMode.setValue(mode);
+    }
+
+    /**
+     * Set how to handle long files, those with a path&gt;100 chars.
+     * Optional, default=warn.
+     * <p>
+     * Allowable values are
+     * <ul>
+     * <li>  truncate - paths are truncated to the maximum length
+     * <li>  fail - paths greater than the maximum cause a build exception
+     * <li>  warn - paths greater than the maximum cause a warning and GNU is used
+     * <li>  gnu - GNU extensions are used for any paths greater than the maximum.
+     * <li>  omit - paths greater than the maximum are omitted from the archive
+     * </ul>
+     * @param mode the mode to handle long file names.
+     */
+    public void setLongfile(TarLongFileMode mode) {
+        this.longFileMode = mode;
+    }
+
+    /**
+     * Set compression method.
+     * Allowable values are
+     * <ul>
+     * <li>  none - no compression
+     * <li>  gzip - Gzip compression
+     * <li>  bzip2 - Bzip2 compression
+     * </ul>
+     * @param mode the compression method.
+     */
+    public void setCompression(TarCompressionMethod mode) {
+        this.compression = mode;
+    }
+
+    /**
+     * do the business
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (tarFile == null) {
+            throw new BuildException("tarfile attribute must be set!",
+                                     getLocation());
+        }
+
+        if (tarFile.exists() && tarFile.isDirectory()) {
+            throw new BuildException("tarfile is a directory!",
+                                     getLocation());
+        }
+
+        if (tarFile.exists() && !tarFile.canWrite()) {
+            throw new BuildException("Can not write to the specified tarfile!",
+                                     getLocation());
+        }
+
+        Vector savedFileSets = (Vector) filesets.clone();
+        try {
+            if (baseDir != null) {
+                if (!baseDir.exists()) {
+                    throw new BuildException("basedir does not exist!",
+                                             getLocation());
+                }
+
+                // add the main fileset to the list of filesets to process.
+                TarFileSet mainFileSet = new TarFileSet(fileset);
+                mainFileSet.setDir(baseDir);
+                filesets.addElement(mainFileSet);
+            }
+
+            if (filesets.size() == 0 && resourceCollections.size() == 0) {
+                throw new BuildException("You must supply either a basedir "
+                                         + "attribute or some nested resource"
+                                         + " collections.",
+                                         getLocation());
+            }
+
+            // check if tar is out of date with respect to each
+            // fileset
+            boolean upToDate = true;
+            for (Enumeration e = filesets.elements(); e.hasMoreElements();) {
+                upToDate &= check((TarFileSet) e.nextElement());
+            }
+            for (Enumeration e = resourceCollections.elements();
+                 e.hasMoreElements();) {
+                upToDate &= check((ResourceCollection) e.nextElement());
+            }
+
+            if (upToDate) {
+                log("Nothing to do: " + tarFile.getAbsolutePath()
+                    + " is up to date.", Project.MSG_INFO);
+                return;
+            }
+
+            log("Building tar: " + tarFile.getAbsolutePath(), Project.MSG_INFO);
+
+            TarOutputStream tOut = null;
+            try {
+                tOut = new TarOutputStream(
+                    compression.compress(
+                        new BufferedOutputStream(
+                            new FileOutputStream(tarFile))));
+                tOut.setDebug(true);
+                if (longFileMode.isTruncateMode()) {
+                    tOut.setLongFileMode(TarOutputStream.LONGFILE_TRUNCATE);
+                } else if (longFileMode.isFailMode()
+                            || longFileMode.isOmitMode()) {
+                    tOut.setLongFileMode(TarOutputStream.LONGFILE_ERROR);
+                } else {
+                    // warn or GNU
+                    tOut.setLongFileMode(TarOutputStream.LONGFILE_GNU);
+                }
+
+                longWarningGiven = false;
+                for (Enumeration e = filesets.elements();
+                     e.hasMoreElements();) {
+                    tar((TarFileSet) e.nextElement(), tOut);
+                }
+                for (Enumeration e = resourceCollections.elements();
+                     e.hasMoreElements();) {
+                    tar((ResourceCollection) e.nextElement(), tOut);
+                }
+            } catch (IOException ioe) {
+                String msg = "Problem creating TAR: " + ioe.getMessage();
+                throw new BuildException(msg, ioe, getLocation());
+            } finally {
+                FileUtils.close(tOut);
+            }
+        } finally {
+            filesets = savedFileSets;
+        }
+    }
+
+    /**
+     * tar a file
+     * @param file the file to tar
+     * @param tOut the output stream
+     * @param vPath the path name of the file to tar
+     * @param tarFileSet the fileset that the file came from.
+     * @throws IOException on error
+     */
+    protected void tarFile(File file, TarOutputStream tOut, String vPath,
+                           TarFileSet tarFileSet)
+        throws IOException {
+        if (file.equals(tarFile)) {
+            // If the archive is built for the first time and it is
+            // matched by a resource collection, then it hasn't been
+            // found in check (it hasn't been there) but will be
+            // included now.
+            //
+            // for some strange reason the old code would simply skip
+            // the entry and not fail, do the same now for backwards
+            // compatibility reasons.  Without this, the which4j build
+            // fails in Gump
+            return;
+        }
+        tarResource(new FileResource(file), tOut, vPath, tarFileSet);
+    }
+
+    /**
+     * tar a resource
+     * @param r the resource to tar
+     * @param tOut the output stream
+     * @param vPath the path name of the file to tar
+     * @param tarFileSet the fileset that the file came from, may be null.
+     * @throws IOException on error
+     * @since Ant 1.7
+     */
+    protected void tarResource(Resource r, TarOutputStream tOut, String vPath,
+                               TarFileSet tarFileSet)
+        throws IOException {
+
+        if (!r.isExists()) {
+            return;
+        }
+
+        if (tarFileSet != null) {
+            String fullpath = tarFileSet.getFullpath(this.getProject());
+            if (fullpath.length() > 0) {
+                vPath = fullpath;
+            } else {
+                // don't add "" to the archive
+                if (vPath.length() <= 0) {
+                    return;
+                }
+
+                String prefix = tarFileSet.getPrefix(this.getProject());
+                // '/' is appended for compatibility with the zip task.
+                if (prefix.length() > 0 && !prefix.endsWith("/")) {
+                    prefix = prefix + "/";
+                }
+                vPath = prefix + vPath;
+            }
+
+            if (vPath.startsWith("/")
+                && !tarFileSet.getPreserveLeadingSlashes()) {
+                int l = vPath.length();
+                if (l <= 1) {
+                    // we would end up adding "" to the archive
+                    return;
+                }
+                vPath = vPath.substring(1, l);
+            }
+        }
+
+        if (r.isDirectory() && !vPath.endsWith("/")) {
+            vPath += "/";
+        }
+
+        if (vPath.length() >= TarConstants.NAMELEN) {
+            if (longFileMode.isOmitMode()) {
+                log("Omitting: " + vPath, Project.MSG_INFO);
+                return;
+            } else if (longFileMode.isWarnMode()) {
+                log("Entry: " + vPath + " longer than "
+                    + TarConstants.NAMELEN + " characters.",
+                    Project.MSG_WARN);
+                if (!longWarningGiven) {
+                    log("Resulting tar file can only be processed "
+                        + "successfully by GNU compatible tar commands",
+                        Project.MSG_WARN);
+                    longWarningGiven = true;
+                }
+            } else if (longFileMode.isFailMode()) {
+                throw new BuildException("Entry: " + vPath
+                        + " longer than " + TarConstants.NAMELEN
+                        + "characters.", getLocation());
+            }
+        }
+
+        TarEntry te = new TarEntry(vPath);
+        te.setModTime(r.getLastModified());
+        // preserve permissions
+        if (r instanceof ArchiveResource) {
+            ArchiveResource ar = (ArchiveResource) r;
+            te.setMode(ar.getMode());
+            if (r instanceof TarResource) {
+                TarResource tr = (TarResource) r;
+                te.setUserName(tr.getUserName());
+                te.setUserId(tr.getUid());
+                te.setGroupName(tr.getGroup());
+                te.setGroupId(tr.getGid());
+            }
+        }
+
+        if (!r.isDirectory()) {
+            if (r.size() > TarConstants.MAXSIZE) {
+                throw new BuildException(
+                    "Resource: " + r + " larger than "
+                    + TarConstants.MAXSIZE + " bytes.");
+            }
+            te.setSize(r.getSize());
+            // override permissions if set explicitly
+            if (tarFileSet != null && tarFileSet.hasFileModeBeenSet()) {
+                te.setMode(tarFileSet.getMode());
+            }
+        } else if (tarFileSet != null && tarFileSet.hasDirModeBeenSet()) {
+            // override permissions if set explicitly
+            te.setMode(tarFileSet.getDirMode(this.getProject()));
+        }
+
+        if (tarFileSet != null) {
+            // only override permissions if set explicitly
+            if (tarFileSet.hasUserNameBeenSet()) {
+                te.setUserName(tarFileSet.getUserName());
+            }
+            if (tarFileSet.hasGroupBeenSet()) {
+                te.setGroupName(tarFileSet.getGroup());
+            }
+            if (tarFileSet.hasUserIdBeenSet()) {
+                te.setUserId(tarFileSet.getUid());
+            }
+            if (tarFileSet.hasGroupIdBeenSet()) {
+                te.setGroupId(tarFileSet.getGid());
+            }
+        }
+
+        InputStream in = null;
+        try {
+            tOut.putNextEntry(te);
+
+            if (!r.isDirectory()) {
+                in = r.getInputStream();
+
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int count = 0;
+                do {
+                    tOut.write(buffer, 0, count);
+                    count = in.read(buffer, 0, buffer.length);
+                } while (count != -1);
+            }
+
+            tOut.closeEntry();
+        } finally {
+            FileUtils.close(in);
+        }
+    }
+
+    /**
+     * Is the archive up to date in relationship to a list of files.
+     * @param files the files to check
+     * @return true if the archive is up to date.
+     * @deprecated since 1.5.x.
+     *             use the two-arg version instead.
+     */
+    protected boolean archiveIsUpToDate(String[] files) {
+        return archiveIsUpToDate(files, baseDir);
+    }
+
+    /**
+     * Is the archive up to date in relationship to a list of files.
+     * @param files the files to check
+     * @param dir   the base directory for the files.
+     * @return true if the archive is up to date.
+     * @since Ant 1.5.2
+     */
+    protected boolean archiveIsUpToDate(String[] files, File dir) {
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        MergingMapper mm = new MergingMapper();
+        mm.setTo(tarFile.getAbsolutePath());
+        return sfs.restrict(files, dir, null, mm).length == 0;
+    }
+
+    /**
+     * Is the archive up to date in relationship to a list of files.
+     * @param r the files to check
+     * @return true if the archive is up to date.
+     * @since Ant 1.7
+     */
+    protected boolean archiveIsUpToDate(Resource r) {
+        return SelectorUtils.isOutOfDate(new FileResource(tarFile), r,
+                                         FileUtils.getFileUtils()
+                                         .getFileTimestampGranularity());
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;tar&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true for this task.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(Tar.class);
+    }
+
+    /**
+     * Checks whether the archive is out-of-date with respect to the resources
+     * of the given collection.
+     *
+     * <p>Also checks that either all collections only contain file
+     * resources or this class supports non-file collections.</p>
+     *
+     * <p>And - in case of file-collections - ensures that the archive won't
+     * contain itself.</p>
+     *
+     * @param rc the resource collection to check
+     * @return whether the archive is up-to-date
+     * @since Ant 1.7
+     */
+    protected boolean check(ResourceCollection rc) {
+        boolean upToDate = true;
+        if (isFileFileSet(rc)) {
+            FileSet fs = (FileSet) rc;
+            upToDate = check(fs.getDir(getProject()), getFileNames(fs));
+        } else if (!rc.isFilesystemOnly() && !supportsNonFileResources()) {
+            throw new BuildException("only filesystem resources are supported");
+        } else if (rc.isFilesystemOnly()) {
+            HashSet basedirs = new HashSet();
+            HashMap basedirToFilesMap = new HashMap();
+            Iterator iter = rc.iterator();
+            while (iter.hasNext()) {
+                FileResource r = (FileResource) iter.next();
+                File base = r.getBaseDir();
+                if (base == null) {
+                    base = Copy.NULL_FILE_PLACEHOLDER;
+                }
+                basedirs.add(base);
+                Vector files = (Vector) basedirToFilesMap.get(base);
+                if (files == null) {
+                    files = new Vector();
+                    basedirToFilesMap.put(base, new Vector());
+                }
+                files.add(r.getName());
+            }
+            iter = basedirs.iterator();
+            while (iter.hasNext()) {
+                File base = (File) iter.next();
+                Vector f = (Vector) basedirToFilesMap.get(base);
+                String[] files = (String[]) f.toArray(new String[f.size()]);
+                upToDate &=
+                    check(base == Copy.NULL_FILE_PLACEHOLDER ? null : base,
+                          files);
+            }
+        } else { // non-file resources
+            Iterator iter = rc.iterator();
+            while (upToDate && iter.hasNext()) {
+                Resource r = (Resource) iter.next();
+                upToDate = archiveIsUpToDate(r);
+            }
+        }
+        return upToDate;
+    }
+
+    /**
+     * Checks whether the archive is out-of-date with respect to the
+     * given files, ensures that the archive won't contain itself.</p>
+     *
+     * @param basedir base directory for file names
+     * @param files array of relative file names
+     * @return whether the archive is up-to-date
+     * @since Ant 1.7
+     */
+    protected boolean check(File basedir, String[] files) {
+        boolean upToDate = true;
+        if (!archiveIsUpToDate(files, basedir)) {
+            upToDate = false;
+        }
+
+        for (int i = 0; i < files.length; ++i) {
+            if (tarFile.equals(new File(basedir, files[i]))) {
+                throw new BuildException("A tar file cannot include "
+                                         + "itself", getLocation());
+            }
+        }
+        return upToDate;
+    }
+
+    /**
+     * Adds the resources contained in this collection to the archive.
+     *
+     * <p>Uses the file based methods for file resources for backwards
+     * compatibility.</p>
+     *
+     * @param rc the collection containing resources to add
+     * @param tOut stream writing to the archive.
+     * @throws IOException on error.
+     * @since Ant 1.7
+     */
+    protected void tar(ResourceCollection rc, TarOutputStream tOut)
+        throws IOException {
+        ArchiveFileSet afs = null;
+        if (rc instanceof ArchiveFileSet) {
+            afs = (ArchiveFileSet) rc;
+        }
+        if (afs != null && afs.size() > 1
+            && afs.getFullpath(this.getProject()).length() > 0) {
+            throw new BuildException("fullpath attribute may only "
+                                     + "be specified for "
+                                     + "filesets that specify a "
+                                     + "single file.");
+        }
+        TarFileSet tfs = asTarFileSet(afs);
+
+        if (isFileFileSet(rc)) {
+            FileSet fs = (FileSet) rc;
+            String[] files = getFileNames(fs);
+            for (int i = 0; i < files.length; i++) {
+                File f = new File(fs.getDir(getProject()), files[i]);
+                String name = files[i].replace(File.separatorChar, '/');
+                tarFile(f, tOut, name, tfs);
+            }
+        } else if (rc.isFilesystemOnly()) {
+            Iterator iter = rc.iterator();
+            while (iter.hasNext()) {
+                FileResource r = (FileResource) iter.next();
+                File f = r.getFile();
+                if (f == null) {
+                    f = new File(r.getBaseDir(), r.getName());
+                }
+                tarFile(f, tOut, f.getName(), tfs);
+            }
+        } else { // non-file resources
+            Iterator iter = rc.iterator();
+            while (iter.hasNext()) {
+                Resource r = (Resource) iter.next();
+                tarResource(r, tOut, r.getName(), tfs);
+            }
+        }
+    }
+
+    /**
+     * whether the given resource collection is a (subclass of)
+     * FileSet that only contains file system resources.
+     * @param rc the resource collection to check.
+     * @return true if the collection is a fileset.
+     * @since Ant 1.7
+     */
+    protected static final boolean isFileFileSet(ResourceCollection rc) {
+        return rc instanceof FileSet && rc.isFilesystemOnly();
+    }
+
+    /**
+     * Grabs all included files and directors from the FileSet and
+     * returns them as an array of (relative) file names.
+     * @param fs the fileset to operate on.
+     * @return a list of the filenames.
+     * @since Ant 1.7
+     */
+    protected static final String[] getFileNames(FileSet fs) {
+        DirectoryScanner ds = fs.getDirectoryScanner(fs.getProject());
+        String[] directories = ds.getIncludedDirectories();
+        String[] filesPerSe = ds.getIncludedFiles();
+        String[] files = new String [directories.length + filesPerSe.length];
+        System.arraycopy(directories, 0, files, 0, directories.length);
+        System.arraycopy(filesPerSe, 0, files, directories.length,
+                         filesPerSe.length);
+        return files;
+    }
+
+    /**
+     * Copies fullpath, prefix and permission attributes from the
+     * ArchiveFileSet to a new TarFileSet (or returns it unchanged if
+     * it already is a TarFileSet).
+     *
+     * @param archiveFileSet fileset to copy attributes from, may be null
+     * @return a new TarFileSet.
+     * @since Ant 1.7
+     */
+    protected TarFileSet asTarFileSet(ArchiveFileSet archiveFileSet) {
+        TarFileSet tfs = null;
+        if (archiveFileSet != null && archiveFileSet instanceof TarFileSet) {
+            tfs = (TarFileSet) archiveFileSet;
+        } else {
+            tfs = new TarFileSet();
+            tfs.setProject(getProject());
+            if (archiveFileSet != null) {
+                tfs.setPrefix(archiveFileSet.getPrefix(getProject()));
+                tfs.setFullpath(archiveFileSet.getFullpath(getProject()));
+                if (archiveFileSet.hasFileModeBeenSet()) {
+                    tfs.integerSetFileMode(archiveFileSet
+                                           .getFileMode(getProject()));
+                }
+                if (archiveFileSet.hasDirModeBeenSet()) {
+                    tfs.integerSetDirMode(archiveFileSet
+                                          .getDirMode(getProject()));
+                }
+
+                if (archiveFileSet
+                    instanceof org.apache.tools.ant.types.TarFileSet) {
+                    org.apache.tools.ant.types.TarFileSet t =
+                        (org.apache.tools.ant.types.TarFileSet) archiveFileSet;
+                    if (t.hasUserNameBeenSet()) {
+                        tfs.setUserName(t.getUserName());
+                    }
+                    if (t.hasGroupBeenSet()) {
+                        tfs.setGroup(t.getGroup());
+                    }
+                    if (t.hasUserIdBeenSet()) {
+                        tfs.setUid(t.getUid());
+                    }
+                    if (t.hasGroupIdBeenSet()) {
+                        tfs.setGid(t.getGid());
+                    }
+                }
+            }
+        }
+        return tfs;
+    }
+
+    /**
+     * This is a FileSet with the option to specify permissions
+     * and other attributes.
+     */
+    public static class TarFileSet
+        extends org.apache.tools.ant.types.TarFileSet {
+        private String[] files = null;
+
+        private boolean preserveLeadingSlashes = false;
+
+        /**
+         * Creates a new <code>TarFileSet</code> instance.
+         * Using a fileset as a constructor argument.
+         *
+         * @param fileset a <code>FileSet</code> value
+         */
+        public TarFileSet(FileSet fileset) {
+            super(fileset);
+        }
+
+        /**
+         * Creates a new <code>TarFileSet</code> instance.
+         *
+         */
+        public TarFileSet() {
+            super();
+        }
+
+        /**
+         *  Get a list of files and directories specified in the fileset.
+         * @param p the current project.
+         * @return a list of file and directory names, relative to
+         *    the baseDir for the project.
+         */
+        public String[] getFiles(Project p) {
+            if (files == null) {
+                files = getFileNames(this);
+            }
+
+            return files;
+        }
+
+        /**
+         * A 3 digit octal string, specify the user, group and
+         * other modes in the standard Unix fashion;
+         * optional, default=0644
+         * @param octalString a 3 digit octal string.
+         */
+        public void setMode(String octalString) {
+            setFileMode(octalString);
+        }
+
+        /**
+         * @return the current mode.
+         */
+        public int getMode() {
+            return getFileMode(this.getProject());
+        }
+
+        /**
+         * Flag to indicates whether leading `/'s should
+         * be preserved in the file names.
+         * Optional, default is <code>false</code>.
+         * @param b the leading slashes flag.
+         */
+        public void setPreserveLeadingSlashes(boolean b) {
+            this.preserveLeadingSlashes = b;
+        }
+
+        /**
+         * @return the leading slashes flag.
+         */
+        public boolean getPreserveLeadingSlashes() {
+            return preserveLeadingSlashes;
+        }
+    }
+
+    /**
+     * Set of options for long file handling in the task.
+     *
+     */
+    public static class TarLongFileMode extends EnumeratedAttribute {
+
+        /** permissible values for longfile attribute */
+        public static final String
+            WARN = "warn",
+            FAIL = "fail",
+            TRUNCATE = "truncate",
+            GNU = "gnu",
+            OMIT = "omit";
+
+        private final String[] validModes = {WARN, FAIL, TRUNCATE, GNU, OMIT};
+
+        /** Constructor, defaults to "warn" */
+        public TarLongFileMode() {
+            super();
+            setValue(WARN);
+        }
+
+        /**
+         * @return the possible values for this enumerated type.
+         */
+        public String[] getValues() {
+            return validModes;
+        }
+
+        /**
+         * @return true if value is "truncate".
+         */
+        public boolean isTruncateMode() {
+            return TRUNCATE.equalsIgnoreCase(getValue());
+        }
+
+        /**
+         * @return true if value is "warn".
+         */
+        public boolean isWarnMode() {
+            return WARN.equalsIgnoreCase(getValue());
+        }
+
+        /**
+         * @return true if value is "gnu".
+         */
+        public boolean isGnuMode() {
+            return GNU.equalsIgnoreCase(getValue());
+        }
+
+        /**
+         * @return true if value is "fail".
+         */
+        public boolean isFailMode() {
+            return FAIL.equalsIgnoreCase(getValue());
+        }
+
+        /**
+         * @return true if value is "omit".
+         */
+        public boolean isOmitMode() {
+            return OMIT.equalsIgnoreCase(getValue());
+        }
+    }
+
+    /**
+     * Valid Modes for Compression attribute to Tar Task
+     *
+     */
+    public static final class TarCompressionMethod extends EnumeratedAttribute {
+
+        // permissible values for compression attribute
+        /**
+         *    No compression
+         */
+        private static final String NONE = "none";
+        /**
+         *    GZIP compression
+         */
+        private static final String GZIP = "gzip";
+        /**
+         *    BZIP2 compression
+         */
+        private static final String BZIP2 = "bzip2";
+
+
+        /**
+         * Default constructor
+         */
+        public TarCompressionMethod() {
+            super();
+            setValue(NONE);
+        }
+
+        /**
+         *  Get valid enumeration values.
+         *  @return valid enumeration values
+         */
+        public String[] getValues() {
+            return new String[] {NONE, GZIP, BZIP2 };
+        }
+
+        /**
+         *  This method wraps the output stream with the
+         *     corresponding compression method
+         *
+         *  @param ostream output stream
+         *  @return output stream with on-the-fly compression
+         *  @exception IOException thrown if file is not writable
+         */
+        private OutputStream compress(final OutputStream ostream)
+            throws IOException {
+            final String v = getValue();
+            if (GZIP.equals(v)) {
+                return new GZIPOutputStream(ostream);
+            } else {
+                if (BZIP2.equals(v)) {
+                    ostream.write('B');
+                    ostream.write('Z');
+                    return new CBZip2OutputStream(ostream);
+                }
+            }
+            return ostream;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/TaskOutputStream.java b/trunk/src/main/org/apache/tools/ant/taskdefs/TaskOutputStream.java
new file mode 100644
index 0000000..e0ed8f3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/TaskOutputStream.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import org.apache.tools.ant.Task;
+
+/**
+ * Redirects text written to a stream thru the standard
+ * ant logging mechanism. This class is useful for integrating
+ * with tools that write to System.out and System.err. For example,
+ * the following will cause all text written to System.out to be
+ * logged with "info" priority:
+ * <pre>System.setOut(new PrintStream(new TaskOutputStream(project, Project.MSG_INFO)));</pre>
+ *
+ * <p><strong>As of Ant 1.2, this class is considered to be dead code
+ * by the Ant developers and is unmaintained.  Don't use
+ * it.</strong></p>
+ *
+ * @deprecated since 1.2.x.
+ * Use LogOutputStream instead.
+ */
+
+public class TaskOutputStream extends OutputStream {
+
+    private Task task;
+    private StringBuffer line;
+    private int msgOutputLevel;
+
+    /**
+     * Constructs a new JavacOutputStream with the given project
+     * as the output source for messages.
+     */
+
+    TaskOutputStream(Task task, int msgOutputLevel) {
+        System.err.println("As of Ant 1.2 released in October 2000, the "
+            + "TaskOutputStream class");
+        System.err.println("is considered to be dead code by the Ant "
+            + "developers and is unmaintained.");
+        System.err.println("Don\'t use it!");
+
+        this.task = task;
+        this.msgOutputLevel = msgOutputLevel;
+
+        line = new StringBuffer();
+    }
+
+    /**
+     * Write a character to the output stream. This method looks
+     * to make sure that there isn't an error being reported and
+     * will flush each line of input out to the project's log stream.
+     * @param c the character to write
+     * @throws IOException on error
+     */
+
+    public void write(int c) throws IOException {
+        char cc = (char) c;
+        if (cc == '\r' || cc == '\n') {
+            // line feed
+            if (line.length() > 0) {
+                processLine();
+            }
+        } else {
+            line.append(cc);
+        }
+    }
+
+    /**
+     * Processes a line of input and determines if an error occurred.
+     */
+
+    private void processLine() {
+        String s = line.toString();
+        task.log(s, msgOutputLevel);
+        line = new StringBuffer();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Taskdef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Taskdef.java
new file mode 100644
index 0000000..7c6dbda
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Taskdef.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskAdapter;
+
+/**
+ * Adds a task definition to the current project, such that this new task can be
+ * used in the current project. Two attributes are needed, the name that identifies
+ * this task uniquely, and the full name of the class (including the packages) that
+ * implements this task.</p>
+ * <p>You can also define a group of tasks at once using the file or
+ * resource attributes.  These attributes point to files in the format of
+ * Java property files.  Each line defines a single task in the
+ * format:</p>
+ * <pre>
+ * taskname=fully.qualified.java.classname
+ * </pre>
+ * @since Ant 1.1
+ * @ant.task category="internal"
+ */
+public class Taskdef extends Typedef {
+
+    /**
+     * Default constructor.
+     * Creates a new Taskdef instance.
+     * This sets the adapter and the adaptto classes to
+     * TaskAdapter and Task.
+     */
+
+    public Taskdef() {
+        setAdapterClass(TaskAdapter.class);
+        setAdaptToClass(Task.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/TempFile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/TempFile.java
new file mode 100644
index 0000000..f768361
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/TempFile.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ *  This task sets a property to  the name of a temporary file.
+ *  Unlike {@link File#createTempFile}, this task does not actually create the
+ *  temporary file, but it does guarantee that the file did not
+ *  exist when the task was executed.
+ * <p>
+ * Examples
+ * <pre>&lt;tempfile property="temp.file" /&gt;</pre>
+ * create a temporary file
+ * <pre>&lt;tempfile property="temp.file" suffix=".xml" /&gt;</pre>
+ * create a temporary file with the .xml suffix.
+ * <pre>&lt;tempfile property="temp.file" destDir="build"/&gt;</pre>
+ * create a temp file in the build subdir
+ *@since       Ant 1.5
+ *@ant.task
+ */
+
+public class TempFile extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Name of property to set.
+     */
+    private String property;
+
+    /**
+     * Directory to create the file in. Can be null.
+     */
+    private File destDir = null;
+
+    /**
+     * Prefix for the file.
+     */
+    private String prefix;
+
+    /**
+     * Suffix for the file.
+     */
+    private String suffix = "";
+
+    /** deleteOnExit flag */
+    private boolean deleteOnExit;
+
+    /** createFile flag */
+    private boolean createFile;
+
+    /**
+     * Sets the property you wish to assign the temporary file to.
+     *
+     * @param  property  The property to set
+     * @ant.attribute group="required"
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+
+    /**
+     * Sets the destination directory. If not set,
+     * the basedir directory is used instead.
+     *
+     * @param  destDir  The new destDir value
+     */
+    public void setDestDir(File destDir) {
+        this.destDir = destDir;
+    }
+
+
+    /**
+     * Sets the optional prefix string for the temp file.
+     *
+     * @param  prefix  string to prepend to generated string
+     */
+    public void setPrefix(String prefix) {
+        this.prefix = prefix;
+    }
+
+
+    /**
+     * Sets the optional suffix string for the temp file.
+     *
+     * @param  suffix  suffix including any "." , e.g ".xml"
+     */
+    public void setSuffix(String suffix) {
+        this.suffix = suffix;
+    }
+
+    /**
+     * Set whether the tempfile created by this task should be set
+     * for deletion on normal VM exit.
+     * @param deleteOnExit boolean flag.
+     */
+    public void setDeleteOnExit(boolean deleteOnExit) {
+        this.deleteOnExit = deleteOnExit;
+    }
+
+    /**
+     * Learn whether deleteOnExit is set for this tempfile task.
+     * @return boolean deleteOnExit flag.
+     */
+    public boolean isDeleteOnExit() {
+        return deleteOnExit;
+    }
+
+    /**
+     * If set the file is actually created, if not just a name is created.
+     * @param createFile boolean flag.
+     */
+    public void setCreateFile(boolean createFile) {
+        this.createFile = createFile;
+    }
+
+    /**
+     * Learn whether createFile flag is set for this tempfile task.
+     * @return the createFile flag.
+     */
+    public boolean isCreateFile() {
+        return createFile;
+    }
+
+    /**
+     * Creates the temporary file.
+     *
+     *@exception  BuildException  if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        if (property == null || property.length() == 0) {
+            throw new BuildException("no property specified");
+        }
+        if (destDir == null) {
+            destDir = getProject().resolveFile(".");
+        }
+        File tfile = FILE_UTILS.createTempFile(prefix, suffix, destDir,
+                    deleteOnExit, createFile);
+        getProject().setNewProperty(property, tfile.toString());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Touch.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Touch.java
new file mode 100644
index 0000000..90f32c1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Touch.java
@@ -0,0 +1,379 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.FileList;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Touchable;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.FileNameMapper;
+
+/**
+ * Touch a file and/or fileset(s) and/or filelist(s);
+ * corresponds to the Unix touch command.
+ *
+ * <p>If the file to touch doesn't exist, an empty one is created.</p>
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+public class Touch extends Task {
+
+    private interface DateFormatFactory {
+        DateFormat getPrimaryFormat();
+        DateFormat getFallbackFormat();
+    }
+
+    private static final DateFormatFactory DEFAULT_DF_FACTORY
+        = new DateFormatFactory() {
+        /*
+         * The initial version used DateFormat.SHORT for the
+         * time format, which ignores seconds.  If we want
+         * seconds as well, we need DateFormat.MEDIUM, which
+         * in turn would break all old build files.
+         *
+         * First try to parse with DateFormat.SHORT and if
+         * that fails with MEDIUM - throw an exception if both
+         * fail.
+         */
+        public DateFormat getPrimaryFormat() {
+            return DateFormat.getDateTimeInstance(DateFormat.SHORT,
+                DateFormat.SHORT, Locale.US);
+        }
+        public DateFormat getFallbackFormat() {
+            return DateFormat.getDateTimeInstance(DateFormat.SHORT,
+                DateFormat.MEDIUM, Locale.US);
+        }
+    };
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File file;
+    private long millis = -1;
+    private String dateTime;
+    private Vector filesets = new Vector();
+    private Union resources;
+    private boolean dateTimeConfigured;
+    private boolean mkdirs;
+    private boolean verbose = true;
+    private FileNameMapper fileNameMapper = null;
+    private DateFormatFactory dfFactory = DEFAULT_DF_FACTORY;
+
+    /**
+     * Construct a new <code>Touch</code> task.
+     */
+    public Touch() {
+    }
+
+    /**
+     * Sets a single source file to touch.  If the file does not exist
+     * an empty file will be created.
+     * @param file the <code>File</code> to touch.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Set the new modification time of file(s) touched
+     * in milliseconds since midnight Jan 1 1970. Optional, default=now.
+     * @param millis the <code>long</code> timestamp to use.
+     */
+    public void setMillis(long millis) {
+        this.millis = millis;
+    }
+
+    /**
+     * Set the new modification time of file(s) touched
+     * in the format &quot;MM/DD/YYYY HH:MM AM <i>or</i> PM&quot;
+     * or &quot;MM/DD/YYYY HH:MM:SS AM <i>or</i> PM&quot;.
+     * Optional, default=now.
+     * @param dateTime the <code>String</code> date in the specified format.
+     */
+    public void setDatetime(String dateTime) {
+        if (this.dateTime != null) {
+            log("Resetting datetime attribute to " + dateTime, Project.MSG_VERBOSE);
+        }
+        this.dateTime = dateTime;
+        dateTimeConfigured = false;
+    }
+
+    /**
+     * Set whether nonexistent parent directories should be created
+     * when touching new files.
+     * @param mkdirs <code>boolean</code> whether to create parent directories.
+     * @since Ant 1.6.3
+     */
+    public void setMkdirs(boolean mkdirs) {
+        this.mkdirs = mkdirs;
+    }
+
+    /**
+     * Set whether the touch task will report every file it creates;
+     * defaults to <code>true</code>.
+     * @param verbose <code>boolean</code> flag.
+     * @since Ant 1.6.3
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Set the format of the datetime attribute.
+     * @param pattern the <code>SimpleDateFormat</code>-compatible format pattern.
+     * @since Ant 1.6.3
+     */
+    public void setPattern(final String pattern) {
+        dfFactory = new DateFormatFactory() {
+            public DateFormat getPrimaryFormat() {
+                return new SimpleDateFormat(pattern);
+            }
+            public DateFormat getFallbackFormat() {
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Add a <code>Mapper</code>.
+     * @param mapper the <code>Mapper</code> to add.
+     * @since Ant 1.6.3
+     */
+    public void addConfiguredMapper(Mapper mapper) {
+        add(mapper.getImplementation());
+    }
+
+    /**
+     * Add a <code>FileNameMapper</code>.
+     * @param fileNameMapper the <code>FileNameMapper</code> to add.
+     * @since Ant 1.6.3
+     * @throws BuildException if multiple mappers are added.
+     */
+    public void add(FileNameMapper fileNameMapper) throws BuildException {
+        if (this.fileNameMapper != null) {
+            throw new BuildException("Only one mapper may be added to the "
+                + getTaskName() + " task.");
+        }
+        this.fileNameMapper = fileNameMapper;
+    }
+
+    /**
+     * Add a set of files to touch.
+     * @param set the <code>Fileset</code> to add.
+     */
+    public void addFileset(FileSet set) {
+        filesets.add(set);
+        add(set);
+    }
+
+    /**
+     * Add a filelist to touch.
+     * @param list the <code>Filelist</code> to add.
+     */
+    public void addFilelist(FileList list) {
+        add(list);
+    }
+
+    /**
+     * Add a collection of resources to touch.
+     * @param rc the collection to add.
+     * @since Ant 1.7
+     */
+    public synchronized void add(ResourceCollection rc) {
+        resources = resources == null ? new Union() : resources;
+        resources.add(rc);
+    }
+
+    /**
+     * Check that this task has been configured properly.
+     * @throws BuildException if configuration errors are detected.
+     * @since Ant 1.6.3
+     */
+    protected synchronized void checkConfiguration() throws BuildException {
+        if (file == null && resources == null) {
+            throw new BuildException("Specify at least one source"
+                                   + "--a file or resource collection.");
+        }
+        if (file != null && file.exists() && file.isDirectory()) {
+            throw new BuildException("Use a resource collection to touch directories.");
+        }
+        if (dateTime != null && !dateTimeConfigured) {
+            long workmillis = millis;
+            if ("now".equalsIgnoreCase(dateTime)) {
+                workmillis = System.currentTimeMillis();
+            } else {
+                DateFormat df = dfFactory.getPrimaryFormat();
+                ParseException pe = null;
+                try {
+                    workmillis = df.parse(dateTime).getTime();
+                } catch (ParseException peOne) {
+                    df = dfFactory.getFallbackFormat();
+                    if (df == null) {
+                        pe = peOne;
+                    } else {
+                        try {
+                            workmillis = df.parse(dateTime).getTime();
+                        } catch (ParseException peTwo) {
+                            pe = peTwo;
+                        }
+                    }
+                }
+                if (pe != null) {
+                    throw new BuildException(pe.getMessage(), pe, getLocation());
+                }
+                if (workmillis < 0) {
+                    throw new BuildException("Date of " + dateTime
+                            + " results in negative " + "milliseconds value "
+                            + "relative to epoch " + "(January 1, 1970, "
+                            + "00:00:00 GMT).");
+                }
+            }
+            log("Setting millis to " + workmillis + " from datetime attribute",
+                    ((millis < 0) ? Project.MSG_DEBUG : Project.MSG_VERBOSE));
+            setMillis(workmillis);
+            // only set if successful to this point:
+            dateTimeConfigured = true;
+        }
+    }
+
+    /**
+     * Execute the touch operation.
+     *
+     * @throws BuildException
+     *             if an error occurs.
+     */
+    public void execute() throws BuildException {
+        checkConfiguration();
+        touch();
+    }
+
+    /**
+     * Does the actual work; assumes everything has been checked by now.
+     * @throws BuildException if an error occurs.
+     */
+    protected void touch() throws BuildException {
+        long defaultTimestamp = getTimestamp();
+
+        if (file != null) {
+            touch(new FileResource(file.getParentFile(), file.getName()),
+                  defaultTimestamp);
+        }
+        if (resources == null) {
+            return;
+        }
+        // deal with the resource collections
+        Iterator iter = resources.iterator();
+        while (iter.hasNext()) {
+            Resource r = (Resource) iter.next();
+            if (!(r instanceof Touchable)) {
+                throw new BuildException("Can't touch " + r);
+            }
+            touch(r, defaultTimestamp);
+        }
+
+        // deal with filesets in a special way since the task
+        // originally also used the directories and Union won't return
+        // them.
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            File fromDir = fs.getDir(getProject());
+
+            String[] srcDirs = ds.getIncludedDirectories();
+
+            for (int j = 0; j < srcDirs.length; j++) {
+                touch(new FileResource(fromDir, srcDirs[j]), defaultTimestamp);
+            }
+        }
+    }
+
+    /**
+     * Touch a single file with the current timestamp (this.millis). This method
+     * does not interact with any nested mappers and remains for reasons of
+     * backwards-compatibility only.
+     * @param file file to touch
+     * @throws BuildException on error
+     * @deprecated since 1.6.x.
+     */
+    protected void touch(File file) {
+        touch(file, getTimestamp());
+    }
+
+    private long getTimestamp() {
+        return (millis < 0) ? System.currentTimeMillis() : millis;
+    }
+
+    private void touch(Resource r, long defaultTimestamp) {
+        if (fileNameMapper == null) {
+            if (r instanceof FileResource) {
+                // use this to create file and deal with non-writable files
+                touch(((FileResource) r).getFile(), defaultTimestamp);
+            } else {
+                ((Touchable) r).touch(defaultTimestamp);
+            }
+        } else {
+            String[] mapped = fileNameMapper.mapFileName(r.getName());
+            if (mapped != null && mapped.length > 0) {
+                long modTime = defaultTimestamp;
+                if (millis < 0 && r.isExists()) {
+                    modTime = r.getLastModified();
+                }
+                for (int i = 0; i < mapped.length; i++) {
+                    touch(getProject().resolveFile(mapped[i]), modTime);
+                }
+            }
+        }
+    }
+
+    private void touch(File file, long modTime) {
+        if (!file.exists()) {
+            log("Creating " + file,
+                ((verbose) ? Project.MSG_INFO : Project.MSG_VERBOSE));
+            try {
+                FILE_UTILS.createNewFile(file, mkdirs);
+            } catch (IOException ioe) {
+                throw new BuildException("Could not create " + file, ioe,
+                                         getLocation());
+            }
+        }
+        if (!file.canWrite()) {
+            throw new BuildException("Can not change modification date of "
+                                     + "read-only file " + file);
+        }
+        FILE_UTILS.setFileLastModified(file, modTime);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Transform.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Transform.java
new file mode 100644
index 0000000..5a01402
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Transform.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Has been merged into ExecuteOn, empty class for backwards compatibility.
+ * We leave that in case that external programs access this class direclty,
+ * for example via
+ *   <tt> Transform tr = (Transform) getProject().createTask("apply") </tt>
+ *
+ * @ant.task ignore="true"
+ */
+public class Transform extends ExecuteOn {
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Truncate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Truncate.java
new file mode 100755
index 0000000..671bd54
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Truncate.java
@@ -0,0 +1,204 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Set the length of one or more files, as the intermittently available
+ * <code>truncate</code> Unix utility/function.
+ * @since Ant 1.7.1
+ */
+public class Truncate extends Task {
+
+    private static final int BUFFER_SIZE = 1024;
+
+    private static final Long ZERO = new Long(0L);
+
+    private static final String NO_CHILD = "No files specified.";
+
+    private static final String INVALID_LENGTH = "Cannot truncate to length ";
+
+    private static final String READ_WRITE = "rw";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private static final byte[] FILL_BUFFER = new byte[BUFFER_SIZE];
+
+    private Path path;
+    private boolean create = true;
+    private boolean mkdirs = false;
+
+    private Long length;
+    private Long adjust;
+
+    /**
+     * Set a single target File.
+     * @param f the single File
+     */
+    public void setFile(File f) {
+        add(new FileResource(f));
+    }
+
+    /**
+     * Add a nested (filesystem-only) ResourceCollection.
+     * @param rc the ResourceCollection to add.
+     */
+    public void add(ResourceCollection rc) {
+        getPath().add(rc);
+    }
+
+    /**
+     * Set the amount by which files' lengths should be adjusted.
+     * It is permissible to append K / M / G / T / P.
+     * @param adjust (positive or negative) adjustment amount.
+     */
+    public void setAdjust(Long adjust) {
+        this.adjust = adjust;
+    }
+
+    /**
+     * Set the length to which files should be set.
+     * It is permissible to append K / M / G / T / P.
+     * @param length (positive) adjustment amount.
+     */
+    public void setLength(Long length) {
+        this.length = length;
+        if (length != null && length.longValue() < 0) {
+            throw new BuildException(INVALID_LENGTH + length);
+        }
+    }
+
+    /**
+     * Set whether to create nonexistent files.
+     * @param create boolean, default <code>true</code>.
+     */
+    public void setCreate(boolean create) {
+        this.create = create;
+    }
+
+    /**
+     * Set whether, when creating nonexistent files, nonexistent directories
+     * should also be created.
+     * @param mkdirs boolean, default <code>false</code>.
+     */
+    public void setMkdirs(boolean mkdirs) {
+        this.mkdirs = mkdirs;
+    }
+
+    /** {@inheritDoc}. */
+    public void execute() {
+        if (length != null && adjust != null) {
+            throw new BuildException(
+                    "length and adjust are mutually exclusive options");
+        }
+        if (length == null && adjust == null) {
+            length = ZERO;
+        }
+        if (path == null) {
+            throw new BuildException(NO_CHILD);
+        }
+        for (Iterator it = path.iterator(); it.hasNext();) {
+            File f = ((FileResource) it.next()).getFile();
+            if (shouldProcess(f)) {
+                process(f);
+            }
+        }
+    }
+
+    private boolean shouldProcess(File f) {
+        if (f.isFile()) {
+            return true;
+        }
+        if (!create) {
+            return false;
+        }
+        Exception exception = null;
+        try {
+            if (FILE_UTILS.createNewFile(f, mkdirs)) {
+                return true;
+            }
+        } catch (IOException e) {
+            exception = e;
+        }
+        String msg = "Unable to create " + f;
+        if (exception == null) {
+            log(msg, Project.MSG_WARN);
+            return false;
+        }
+        throw new BuildException(msg, exception);
+    }
+
+    private void process(File f) {
+        long len = f.length();
+        long newLength = length == null
+                ? len + adjust.longValue() : length.longValue();
+
+        if (len == newLength) {
+            //nothing to do!
+            return;
+        }
+        RandomAccessFile raf = null;
+        try {
+            raf = new RandomAccessFile(f, READ_WRITE);
+        } catch (Exception e) {
+            throw new BuildException("Could not open " + f + " for writing", e);
+        }
+        try {
+            if (newLength > len) {
+                long pos = len;
+                raf.seek(pos);
+                while (pos < newLength) {
+                    long writeCount = Math.min(FILL_BUFFER.length,
+                            newLength - pos);
+                    raf.write(FILL_BUFFER, 0, (int) writeCount);
+                    pos += writeCount;
+                }
+            } else {
+                raf.setLength(newLength);
+            }
+        } catch (IOException e) {
+            throw new BuildException("Exception working with " + raf, e);
+        } finally {
+            try {
+                raf.close();
+            } catch (IOException e) {
+                log("Caught " + e + " closing " + raf, Project.MSG_WARN);
+            }
+        }
+    }
+
+    private synchronized Path getPath() {
+        if (path == null) {
+            path = new Path(getProject());
+        }
+        return path;
+    }
+
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Tstamp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
new file mode 100644
index 0000000..bf2f2b2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Tstamp.java
@@ -0,0 +1,340 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Sets properties to the current time, or offsets from the current time.
+ * The default properties are TSTAMP, DSTAMP and TODAY;
+ *
+ * @since Ant 1.1
+ * @ant.task category="utility"
+ */
+public class Tstamp extends Task {
+
+    private Vector customFormats = new Vector();
+    private String prefix = "";
+
+    /**
+     * Set a prefix for the properties. If the prefix does not end with a "."
+     * one is automatically added.
+     * @param prefix the prefix to use.
+     * @since Ant 1.5
+     */
+    public void setPrefix(String prefix) {
+        this.prefix = prefix;
+        if (!this.prefix.endsWith(".")) {
+            this.prefix += ".";
+        }
+    }
+
+    /**
+     * create the timestamps. Custom ones are done before
+     * the standard ones, to get their retaliation in early.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        try {
+            Date d = new Date();
+
+            Enumeration i = customFormats.elements();
+            while (i.hasMoreElements()) {
+                CustomFormat cts = (CustomFormat) i.nextElement();
+                cts.execute(getProject(), d, getLocation());
+            }
+
+            SimpleDateFormat dstamp = new SimpleDateFormat ("yyyyMMdd");
+            setProperty("DSTAMP", dstamp.format(d));
+
+            SimpleDateFormat tstamp = new SimpleDateFormat ("HHmm");
+            setProperty("TSTAMP", tstamp.format(d));
+
+            SimpleDateFormat today
+                = new SimpleDateFormat ("MMMM d yyyy", Locale.US);
+            setProperty("TODAY", today.format(d));
+
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * create a custom format with the current prefix.
+     * @return a ready to fill-in format
+     */
+    public CustomFormat createFormat() {
+        CustomFormat cts = new CustomFormat();
+        customFormats.addElement(cts);
+        return cts;
+    }
+
+    /**
+     * helper that encapsulates prefix logic and property setting
+     * policy (i.e. we use setNewProperty instead of setProperty).
+     */
+    private void setProperty(String name, String value) {
+        getProject().setNewProperty(prefix + name, value);
+    }
+
+    /**
+     * This nested element that allows a property to be set
+     * to the current date and time in a given format.
+     * The date/time patterns are as defined in the
+     * Java SimpleDateFormat class.
+     * The format element also allows offsets to be applied to
+     * the time to generate different time values.
+     * @todo consider refactoring out into a re-usable element.
+     */
+    public class CustomFormat {
+        private TimeZone timeZone;
+        private String propertyName;
+        private String pattern;
+        private String language;
+        private String country;
+        private String variant;
+        private int offset = 0;
+        private int field = Calendar.DATE;
+
+        /**
+         * Create a format
+         */
+        public CustomFormat() {
+        }
+
+        /**
+         *  The property to receive the date/time string in the given pattern
+         * @param propertyName the name of the property.
+         */
+        public void setProperty(String propertyName) {
+            this.propertyName = propertyName;
+        }
+
+        /**
+         * The date/time pattern to be used. The values are as
+         * defined by the Java SimpleDateFormat class.
+         * @param pattern the pattern to use.
+         * @see java.text.SimpleDateFormat
+         */
+        public void setPattern(String pattern) {
+            this.pattern = pattern;
+        }
+
+        /**
+         * The locale used to create date/time string.
+         * The general form is "language, country, variant" but
+         * either variant or variant and country may be omitted.
+         * For more information please refer to documentation
+         * for the java.util.Locale  class.
+         * @param locale the locale to use.
+         * @see java.util.Locale
+         */
+        public void setLocale(String locale) {
+            StringTokenizer st = new StringTokenizer(locale, " \t\n\r\f,");
+            try {
+                language = st.nextToken();
+                if (st.hasMoreElements()) {
+                    country = st.nextToken();
+                    if (st.hasMoreElements()) {
+                        variant = st.nextToken();
+                        if (st.hasMoreElements()) {
+                            throw new BuildException("bad locale format",
+                                                      getLocation());
+                        }
+                    }
+                } else {
+                    country = "";
+                }
+            } catch (NoSuchElementException e) {
+                throw new BuildException("bad locale format", e,
+                                         getLocation());
+            }
+        }
+
+        /**
+         * The timezone to use for displaying time.
+         * The values are as defined by the Java TimeZone class.
+         * @param id the timezone value.
+         * @see java.util.TimeZone
+         */
+        public void setTimezone(String id) {
+            timeZone = TimeZone.getTimeZone(id);
+        }
+
+        /**
+         * The numeric offset to the current time.
+         * @param offset the offset to use.
+         */
+        public void setOffset(int offset) {
+            this.offset = offset;
+        }
+
+        /**
+         * Set the unit type (using String).
+         * @param unit the unit to use.
+         * @deprecated since 1.5.x.
+         *             setUnit(String) is deprecated and is replaced with
+         *             setUnit(Tstamp.Unit) to make Ant's
+         *             Introspection mechanism do the work and also to
+         *             encapsulate operations on the unit in its own
+         *             class.
+         */
+        public void setUnit(String unit) {
+            log("DEPRECATED - The setUnit(String) method has been deprecated."
+                + " Use setUnit(Tstamp.Unit) instead.");
+            Unit u = new Unit();
+            u.setValue(unit);
+            field = u.getCalendarField();
+        }
+
+        /**
+         * The unit of the offset to be applied to the current time.
+         * Valid Values are
+         * <ul>
+         *    <li>millisecond</li>
+         *    <li>second</li>
+         *    <li>minute</li>
+         *    <li>hour</li>
+         *    <li>day</li>
+         *    <li>week</li>
+         *    <li>month</li>
+         *    <li>year</li>
+         * </ul>
+         * The default unit is day.
+         * @param unit the unit to use.
+         */
+        public void setUnit(Unit unit) {
+            field = unit.getCalendarField();
+        }
+
+        /**
+         * validate parameter and execute the format.
+         * @param project project to set property in.
+         * @param date date to use as a starting point.
+         * @param location line in file (for errors)
+         */
+        public void execute(Project project, Date date, Location location) {
+            if (propertyName == null) {
+                throw new BuildException("property attribute must be provided",
+                                         location);
+            }
+
+            if (pattern == null) {
+                throw new BuildException("pattern attribute must be provided",
+                                         location);
+            }
+
+            SimpleDateFormat sdf;
+            if (language == null) {
+                sdf = new SimpleDateFormat(pattern);
+            } else if (variant == null) {
+                sdf = new SimpleDateFormat(pattern,
+                                           new Locale(language, country));
+            } else {
+                sdf = new SimpleDateFormat(pattern,
+                                           new Locale(language, country,
+                                                      variant));
+            }
+            if (offset != 0) {
+                Calendar calendar = Calendar.getInstance();
+                calendar.setTime(date);
+                calendar.add(field, offset);
+                date = calendar.getTime();
+            }
+            if (timeZone != null) {
+                sdf.setTimeZone(timeZone);
+            }
+            Tstamp.this.setProperty(propertyName, sdf.format(date));
+        }
+    }
+
+    /**
+     * set of valid units to use for time offsets.
+     */
+    public static class Unit extends EnumeratedAttribute {
+
+        private static final String MILLISECOND = "millisecond";
+        private static final String SECOND = "second";
+        private static final String MINUTE = "minute";
+        private static final String HOUR = "hour";
+        private static final String DAY = "day";
+        private static final String WEEK = "week";
+        private static final String MONTH = "month";
+        private static final String YEAR = "year";
+
+        private static final String[] UNITS = {
+                                                MILLISECOND,
+                                                SECOND,
+                                                MINUTE,
+                                                HOUR,
+                                                DAY,
+                                                WEEK,
+                                                MONTH,
+                                                YEAR
+                                              };
+
+        private Map calendarFields = new HashMap();
+
+        /** Constructor for Unit enumerated type. */
+        public Unit() {
+            calendarFields.put(MILLISECOND,
+                               new Integer(Calendar.MILLISECOND));
+            calendarFields.put(SECOND, new Integer(Calendar.SECOND));
+            calendarFields.put(MINUTE, new Integer(Calendar.MINUTE));
+            calendarFields.put(HOUR, new Integer(Calendar.HOUR_OF_DAY));
+            calendarFields.put(DAY, new Integer(Calendar.DATE));
+            calendarFields.put(WEEK, new Integer(Calendar.WEEK_OF_YEAR));
+            calendarFields.put(MONTH, new Integer(Calendar.MONTH));
+            calendarFields.put(YEAR, new Integer(Calendar.YEAR));
+        }
+
+        /**
+         * Convert the value to int unit value.
+         * @return an int value.
+         */
+        public int getCalendarField() {
+            String key = getValue().toLowerCase();
+            Integer i = (Integer) calendarFields.get(key);
+            return i.intValue();
+        }
+
+        /**
+         * Get the valid values.
+         * @return the value values.
+         */
+        public String[] getValues() {
+            return UNITS;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Typedef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Typedef.java
new file mode 100644
index 0000000..87276e2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Typedef.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+
+
+/**
+ *
+ * Adds a data type definition to the current project.
+ * Two attributes are
+ * needed, the name that identifies this data type uniquely, and the full
+ * name of the class (including the packages) that implements this
+ * type.
+ * <p>You can also define a group of data types at once using the file or
+ * resource attributes.  These attributes point to files in the format of
+ * Java property files.   Each line defines a single data type in the
+ * format:</p>
+ * <pre>
+ * typename=fully.qualified.java.classname
+ * </pre>
+ * <p>Typedef should be used to add your own types to the system. Data
+ * types are things likepaths or filesets that can be defined at
+ * the project level and referenced via their ID attribute.</p>
+ * <p>Custom data types usually need custom tasks to put them to good use.</p>
+ *
+ * @since Ant 1.4
+ * @ant.task category="internal"
+ */
+public class Typedef extends Definer {
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Unpack.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Unpack.java
new file mode 100644
index 0000000..9cfbc4b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Unpack.java
@@ -0,0 +1,192 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * Abstract Base class for unpack tasks.
+ *
+ * @since Ant 1.5
+ */
+
+public abstract class Unpack extends Task {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected File source;
+    protected File dest;
+    protected Resource srcResource;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * @deprecated since 1.5.x.
+     *             setSrc(String) is deprecated and is replaced with
+     *             setSrc(File) to make Ant's Introspection
+     *             mechanism do the work and also to encapsulate operations on
+     *             the type in its own class.
+     * @ant.attribute ignore="true"
+     * @param src a <code>String</code> value
+     */
+    public void setSrc(String src) {
+        log("DEPRECATED - The setSrc(String) method has been deprecated."
+            + " Use setSrc(File) instead.");
+        setSrc(getProject().resolveFile(src));
+    }
+
+    /**
+     * @deprecated since 1.5.x.
+     *             setDest(String) is deprecated and is replaced with
+     *             setDest(File) to make Ant's Introspection
+     *             mechanism do the work and also to encapsulate operations on
+     *             the type in its own class.
+     * @ant.attribute ignore="true"
+     * @param dest a <code>String</code> value
+     */
+    public void setDest(String dest) {
+        log("DEPRECATED - The setDest(String) method has been deprecated."
+            + " Use setDest(File) instead.");
+        setDest(getProject().resolveFile(dest));
+    }
+
+    /**
+     * The file to expand; required.
+     * @param src file to expand
+     */
+    public void setSrc(File src) {
+        setSrcResource(new FileResource(src));
+    }
+
+    /**
+     * The resource to expand; required.
+     * @param src resource to expand
+     */
+    public void setSrcResource(Resource src) {
+        if (!src.isExists()) {
+            throw new BuildException(
+                "the archive " + src.getName() + " doesn't exist");
+        }
+        if (src.isDirectory()) {
+            throw new BuildException(
+                "the archive " + src.getName() + " can't be a directory");
+        }
+        if (src instanceof FileResource) {
+            source = ((FileResource) src).getFile();
+        } else if (!supportsNonFileResources()) {
+            throw new BuildException(
+                "The source " + src.getName()
+                + " is not a FileSystem "
+                + "Only FileSystem resources are"
+                + " supported.");
+        }
+        srcResource = src;
+    }
+
+    /**
+     * Set the source Archive resource.
+     * @param a the archive as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        if (a.size() != 1) {
+            throw new BuildException("only single argument resource collections"
+                                     + " are supported as archives");
+        }
+        setSrcResource((Resource) a.iterator().next());
+    }
+
+    /**
+     * The destination file or directory; optional.
+     * @param dest destination file or directory
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    private void validate() throws BuildException {
+        if (srcResource == null) {
+            throw new BuildException("No Src specified", getLocation());
+        }
+
+        if (dest == null) {
+            dest = new File(source.getParent());
+        }
+
+        if (dest.isDirectory()) {
+            String defaultExtension = getDefaultExtension();
+            createDestFile(defaultExtension);
+        }
+    }
+
+    private void createDestFile(String defaultExtension) {
+        String sourceName = source.getName();
+        int len = sourceName.length();
+        if (defaultExtension != null
+            && len > defaultExtension.length()
+            && defaultExtension.equalsIgnoreCase(
+                sourceName.substring(len - defaultExtension.length()))) {
+            dest = new File(dest, sourceName.substring(0,
+                                                       len - defaultExtension.length()));
+        } else {
+            dest = new File(dest, sourceName);
+        }
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        File savedDest = dest; // may be altered in validate
+        try {
+            validate();
+            extract();
+        } finally {
+            dest = savedDest;
+        }
+    }
+
+    /**
+     * Get the extension.
+     * This is to be overridden by subclasses.
+     * @return the default extension.
+     */
+    protected abstract String getDefaultExtension();
+
+    /**
+     * Do the uncompressing.
+     * This is to be overridden by subclasses.
+     */
+    protected abstract void extract();
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns false.</p>
+     * @return false for this task.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return false;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Untar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Untar.java
new file mode 100644
index 0000000..3a864c8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Untar.java
@@ -0,0 +1,223 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.bzip2.CBZip2InputStream;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
+
+
+
+/**
+ * Untar a file.
+ * <p>For JDK 1.1 &quot;last modified time&quot; field is set to current time instead of being
+ * carried from the archive file.</p>
+ * <p>PatternSets are used to select files to extract
+ * <I>from</I> the archive.  If no patternset is used, all files are extracted.
+ * </p>
+ * <p>FileSet>s may be used to select archived files
+ * to perform unarchival upon.
+ * </p>
+ * <p>File permissions will not be restored on extracted files.</p>
+ * <p>The untar task recognizes the long pathname entries used by GNU tar.<p>
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+public class Untar extends Expand {
+    /**
+     *   compression method
+     */
+    private UntarCompressionMethod compression = new UntarCompressionMethod();
+
+    /**
+     * Set decompression algorithm to use; default=none.
+     *
+     * Allowable values are
+     * <ul>
+     *   <li>none - no compression
+     *   <li>gzip - Gzip compression
+     *   <li>bzip2 - Bzip2 compression
+     * </ul>
+     *
+     * @param method compression method
+     */
+    public void setCompression(UntarCompressionMethod method) {
+        compression = method;
+    }
+
+    /**
+     * No encoding support in Untar.
+     * @param encoding not used
+     * @throws BuildException always
+     * @since Ant 1.6
+     */
+    public void setEncoding(String encoding) {
+        throw new BuildException("The " + getTaskName()
+                                 + " task doesn't support the encoding"
+                                 + " attribute", getLocation());
+    }
+
+    /**
+     * @see Expand#expandFile(FileUtils, File, File)
+     */
+    /** {@inheritDoc} */
+    protected void expandFile(FileUtils fileUtils, File srcF, File dir) {
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(srcF);
+            expandStream(srcF.getPath(), fis, dir);
+        } catch (IOException ioe) {
+            throw new BuildException("Error while expanding " + srcF.getPath(),
+                                     ioe, getLocation());
+        } finally {
+            FileUtils.close(fis);
+        }
+    }
+
+    /**
+     * This method is to be overridden by extending unarchival tasks.
+     *
+     * @param srcR      the source resource
+     * @param dir       the destination directory
+     * @since Ant 1.7
+     */
+    protected void expandResource(Resource srcR, File dir) {
+        InputStream i = null;
+        try {
+            i = srcR.getInputStream();
+            expandStream(srcR.getName(), i, dir);
+        } catch (IOException ioe) {
+            throw new BuildException("Error while expanding " + srcR.getName(),
+                                     ioe, getLocation());
+        } finally {
+            FileUtils.close(i);
+        }
+    }
+
+    /**
+     * @since Ant 1.7
+     */
+    private void expandStream(String name, InputStream stream, File dir)
+        throws IOException {
+        TarInputStream tis = null;
+        try {
+            tis =
+                new TarInputStream(compression.decompress(name,
+                                                          new BufferedInputStream(stream)));
+            log("Expanding: " + name + " into " + dir, Project.MSG_INFO);
+            TarEntry te = null;
+            FileNameMapper mapper = getMapper();
+            while ((te = tis.getNextEntry()) != null) {
+                extractFile(FileUtils.getFileUtils(), null, dir, tis,
+                            te.getName(), te.getModTime(),
+                            te.isDirectory(), mapper);
+            }
+            log("expand complete", Project.MSG_VERBOSE);
+        } finally {
+            FileUtils.close(tis);
+        }
+    }
+
+    /**
+     * Valid Modes for Compression attribute to Untar Task
+     *
+     */
+    public static final class UntarCompressionMethod
+        extends EnumeratedAttribute {
+
+        // permissible values for compression attribute
+        /**
+         *  No compression
+         */
+        private static final String NONE = "none";
+        /**
+         *  GZIP compression
+         */
+        private static final String GZIP = "gzip";
+        /**
+         *  BZIP2 compression
+         */
+        private static final String BZIP2 = "bzip2";
+
+
+        /**
+         *  Constructor
+         */
+        public UntarCompressionMethod() {
+            super();
+            setValue(NONE);
+        }
+
+        /**
+         * Get valid enumeration values
+         *
+         * @return valid values
+         */
+        public String[] getValues() {
+            return new String[] {NONE, GZIP, BZIP2};
+        }
+
+        /**
+         *  This method wraps the input stream with the
+         *     corresponding decompression method
+         *
+         *  @param name provides location information for BuildException
+         *  @param istream input stream
+         *  @return input stream with on-the-fly decompression
+         *  @exception IOException thrown by GZIPInputStream constructor
+         *  @exception BuildException thrown if bzip stream does not
+         *     start with expected magic values
+         */
+        public InputStream decompress(final String name,
+                                       final InputStream istream)
+            throws IOException, BuildException {
+            final String v = getValue();
+            if (GZIP.equals(v)) {
+                return new GZIPInputStream(istream);
+            } else {
+                if (BZIP2.equals(v)) {
+                    final char[] magic = new char[] {'B', 'Z'};
+                    for (int i = 0; i < magic.length; i++) {
+                        if (istream.read() != magic[i]) {
+                            throw new BuildException(
+                                                     "Invalid bz2 file." + name);
+                        }
+                    }
+                    return new CBZip2InputStream(istream);
+                }
+            }
+            return istream;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/UpToDate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/UpToDate.java
new file mode 100644
index 0000000..6059be3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/UpToDate.java
@@ -0,0 +1,269 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.MergingMapper;
+import org.apache.tools.ant.util.ResourceUtils;
+import org.apache.tools.ant.util.SourceFileScanner;
+
+/**
+ * Sets the given property if the specified target has a timestamp
+ * greater than all of the source files.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="control"
+ */
+
+public class UpToDate extends Task implements Condition {
+
+    private String property;
+    private String value;
+    private File sourceFile;
+    private File targetFile;
+    private Vector sourceFileSets = new Vector();
+    private Union sourceResources = new Union();
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Mapper mapperElement = null;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * The property to set if the target file is more up-to-date than
+     * (each of) the source file(s).
+     *
+     * @param property the name of the property to set if Target is up-to-date.
+     */
+    public void setProperty(final String property) {
+        this.property = property;
+    }
+
+    /**
+     * The value to set the named property to if the target file is more
+     * up-to-date than (each of) the source file(s). Defaults to 'true'.
+     *
+     * @param value the value to set the property to if Target is up-to-date
+     */
+    public void setValue(final String value) {
+        this.value = value;
+    }
+
+    /**
+     * Returns the value, or "true" if a specific value wasn't provided.
+     */
+    private String getValue() {
+        return (value != null) ? value : "true";
+    }
+
+    /**
+     * The file which must be more up-to-date than (each of) the source file(s)
+     * if the property is to be set.
+     *
+     * @param file the file we are checking against.
+     */
+    public void setTargetFile(final File file) {
+        this.targetFile = file;
+    }
+
+    /**
+     * The file that must be older than the target file
+     * if the property is to be set.
+     *
+     * @param file the file we are checking against the target file.
+     */
+    public void setSrcfile(final File file) {
+        this.sourceFile = file;
+    }
+
+    /**
+     * Nested &lt;srcfiles&gt; element.
+     * @param fs the source files
+     */
+    public void addSrcfiles(final FileSet fs) {
+        sourceFileSets.addElement(fs);
+    }
+
+    /**
+     * Nested resource collections as sources.
+     * @return the source resources to configure.
+     * @since Ant 1.7
+     */
+    public Union createSrcResources() {
+        return sourceResources;
+    }
+
+    /**
+     * Defines the FileNameMapper to use (nested mapper element).
+     * @return a mapper to be configured
+     * @throws BuildException if more than one mapper is defined
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper",
+                                     getLocation());
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+    /**
+     * A nested filenamemapper
+     * @param fileNameMapper the mapper to add
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+    /**
+     * Evaluate (all) target and source file(s) to
+     * see if the target(s) is/are up-to-date.
+     * @return true if the target(s) is/are up-to-date
+     */
+    public boolean eval() {
+        if (sourceFileSets.size() == 0 && sourceResources.size() == 0
+            && sourceFile == null) {
+            throw new BuildException("At least one srcfile or a nested "
+                                     + "<srcfiles> or <srcresources> element "
+                                     + "must be set.");
+        }
+
+        if ((sourceFileSets.size() > 0 || sourceResources.size() > 0)
+            && sourceFile != null) {
+            throw new BuildException("Cannot specify both the srcfile "
+                                     + "attribute and a nested <srcfiles> "
+                                     + "or <srcresources> element.");
+        }
+
+        if (targetFile == null && mapperElement == null) {
+            throw new BuildException("The targetfile attribute or a nested "
+                                     + "mapper element must be set.");
+        }
+
+        // if the target file is not there, then it can't be up-to-date
+        if (targetFile != null && !targetFile.exists()) {
+            log("The targetfile \"" + targetFile.getAbsolutePath()
+                    + "\" does not exist.", Project.MSG_VERBOSE);
+            return false;
+        }
+
+        // if the source file isn't there, throw an exception
+        if (sourceFile != null && !sourceFile.exists()) {
+            throw new BuildException(sourceFile.getAbsolutePath()
+                                     + " not found.");
+        }
+
+        boolean upToDate = true;
+        if (sourceFile != null) {
+            if (mapperElement == null) {
+                upToDate = targetFile.lastModified() >= sourceFile.lastModified();
+            } else {
+                SourceFileScanner sfs = new SourceFileScanner(this);
+                upToDate = sfs.restrict(new String[] {sourceFile.getAbsolutePath()},
+                                  null, null,
+                                  mapperElement.getImplementation()).length == 0;
+            }
+        }
+
+        // filesets are separate from the rest for performance
+        // reasons.  If we use the code for union below, we'll always
+        // scan all filesets, even if we know the target is out of
+        // date after the first test.
+        Enumeration e = sourceFileSets.elements();
+        while (upToDate && e.hasMoreElements()) {
+            FileSet fs = (FileSet) e.nextElement();
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            upToDate = scanDir(fs.getDir(getProject()),
+                                           ds.getIncludedFiles());
+        }
+
+        if (upToDate) {
+            Resource[] r = sourceResources.listResources();
+            upToDate = ResourceUtils.selectOutOfDateSources(
+                        this, r, getMapper(), getProject()).length == 0;
+        }
+
+        return upToDate;
+    }
+
+
+    /**
+     * Sets property to true if target file(s) have a more recent timestamp
+     * than (each of) the corresponding source file(s).
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (property == null) {
+            throw new BuildException("property attribute is required.",
+                                     getLocation());
+        }
+        boolean upToDate = eval();
+        if (upToDate) {
+            getProject().setNewProperty(property, getValue());
+            if (mapperElement == null) {
+                log("File \"" + targetFile.getAbsolutePath()
+                    + "\" is up-to-date.", Project.MSG_VERBOSE);
+            } else {
+                log("All target files are up-to-date.",
+                    Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+    /**
+     * Scan a directory for files to check for "up to date"ness
+     * @param srcDir the directory
+     * @param files the files to scan for
+     * @return true if the files are up to date
+     */
+    protected boolean scanDir(File srcDir, String[] files) {
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        FileNameMapper mapper = getMapper();
+        File dir = srcDir;
+        if (mapperElement == null) {
+            dir = null;
+        }
+        return sfs.restrict(files, srcDir, dir, mapper).length == 0;
+    }
+
+    private FileNameMapper getMapper() {
+        FileNameMapper mapper = null;
+        if (mapperElement == null) {
+            MergingMapper mm = new MergingMapper();
+            mm.setTo(targetFile.getAbsolutePath());
+            mapper = mm;
+        } else {
+            mapper = mapperElement.getImplementation();
+        }
+        return mapper;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/VerifyJar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/VerifyJar.java
new file mode 100644
index 0000000..0e5296c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/VerifyJar.java
@@ -0,0 +1,208 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.filters.ChainableReader;
+import org.apache.tools.ant.types.RedirectorElement;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.resources.FileResource;
+
+import java.util.Iterator;
+import java.io.File;
+import java.io.Reader;
+import java.io.IOException;
+
+/**
+ * JAR verification task.
+ * For every JAR passed in, we fork jarsigner to verify
+ * that it is correctly signed. This is more rigorous than just checking for
+ * the existence of a signature; the entire certification chain is tested
+ * @since Ant 1.7
+ */
+
+public class VerifyJar extends AbstractJarSignerTask {
+    /**
+     * no file message {@value}
+     */
+    public static final String ERROR_NO_FILE = "Not found :";
+
+    /**
+     * The string we look for in the text to indicate direct verification
+     */
+    private static final String VERIFIED_TEXT = "jar verified.";
+
+    /**
+     * certification flag
+     */
+    private boolean certificates = false;
+    private BufferingOutputFilter outputCache = new BufferingOutputFilter();
+    /** Error output if there is a failure to verify the jar. */
+    public static final String ERROR_NO_VERIFY = "Failed to verify ";
+
+    /**
+     * Ask for certificate information to be printed
+     * @param certificates if true print certificates.
+     */
+    public void setCertificates(boolean certificates) {
+        this.certificates = certificates;
+    }
+
+    /**
+     * verify our jar files
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        //validation logic
+        final boolean hasJar = jar != null;
+
+        if (!hasJar && !hasResources()) {
+            throw new BuildException(ERROR_NO_SOURCE);
+        }
+
+        beginExecution();
+
+        //patch the redirector to save output to a file
+        RedirectorElement redirector = getRedirector();
+        redirector.setAlwaysLog(true);
+        FilterChain outputFilterChain = redirector.createOutputFilterChain();
+        outputFilterChain.add(outputCache);
+
+        try {
+            Path sources = createUnifiedSourcePath();
+            Iterator iter = sources.iterator();
+            while (iter.hasNext()) {
+                FileResource fr = (FileResource) iter.next();
+                verifyOneJar(fr.getFile());
+            }
+
+        } finally {
+            endExecution();
+        }
+
+    }
+
+    /**
+     * verify a JAR.
+     * @param jar the jar to verify.
+     * @throws BuildException if the file could not be verified
+     */
+    private void verifyOneJar(File jar) {
+        if (!jar.exists()) {
+            throw new BuildException(ERROR_NO_FILE + jar);
+        }
+        final ExecTask cmd = createJarSigner();
+
+        setCommonOptions(cmd);
+        bindToKeystore(cmd);
+
+        //verify special operations
+        addValue(cmd, "-verify");
+
+        if (certificates) {
+            addValue(cmd, "-certs");
+        }
+
+        //JAR  is required
+        addValue(cmd, jar.getPath());
+
+        log("Verifying JAR: " + jar.getAbsolutePath());
+        outputCache.clear();
+        BuildException ex = null;
+        try {
+            cmd.execute();
+        } catch (BuildException e) {
+            ex = e;
+        }
+        String results = outputCache.toString();
+        //deal with jdk1.4.2 bug:
+        if (ex != null) {
+            if (results.indexOf("zip file closed") >= 0) {
+                log("You are running " + JARSIGNER_COMMAND + " against a JVM with"
+                    + " a known bug that manifests as an IllegalStateException.",
+                    Project.MSG_WARN);
+            } else {
+                throw ex;
+            }
+        }
+        if (results.indexOf(VERIFIED_TEXT) < 0) {
+            throw new BuildException(ERROR_NO_VERIFY + jar);
+        }
+    }
+
+    /**
+     * we are not thread safe here. Do not use on multiple threads at the same time.
+     */
+    private static class BufferingOutputFilter implements ChainableReader {
+
+        private BufferingOutputFilterReader buffer;
+
+        public Reader chain(Reader rdr) {
+            buffer = new BufferingOutputFilterReader(rdr);
+            return buffer;
+        }
+
+        public String toString() {
+            return buffer.toString();
+        }
+
+        public void clear() {
+            if (buffer != null) {
+                buffer.clear();
+            }
+        }
+    }
+
+    /**
+     * catch the output of the buffer
+     */
+    private static class BufferingOutputFilterReader extends Reader {
+
+        private Reader next;
+
+        private StringBuffer buffer = new StringBuffer();
+
+        public BufferingOutputFilterReader(Reader next) {
+            this.next = next;
+        }
+
+        public int read(char[] cbuf, int off, int len) throws IOException {
+            //hand down
+            int result = next.read(cbuf, off, len);
+            //cache
+            buffer.append(cbuf, off, len);
+            //return
+            return result;
+        }
+
+        public void close() throws IOException {
+            next.close();
+        }
+
+        public String toString() {
+            return buffer.toString();
+        }
+
+        public void clear() {
+            buffer = new StringBuffer();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/WaitFor.java b/trunk/src/main/org/apache/tools/ant/taskdefs/WaitFor.java
new file mode 100644
index 0000000..e4f404b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/WaitFor.java
@@ -0,0 +1,275 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Wait for an external event to occur.
+ *
+ * Wait for an external process to start or to complete some
+ * task. This is useful with the <code>parallel</code> task to
+ * synchronize the execution of tests with server startup.
+ *
+ * The following attributes can be specified on a waitfor task:
+ * <ul>
+ * <li>maxwait - maximum length of time to wait before giving up</li>
+ * <li>maxwaitunit - The unit to be used to interpret maxwait attribute</li>
+ * <li>checkevery - amount of time to sleep between each check</li>
+ * <li>checkeveryunit - The unit to be used to interpret checkevery attribute</li>
+ * <li>timeoutproperty - name of a property to set if maxwait has been exceeded.</li>
+ * </ul>
+ *
+ * The maxwaitunit and checkeveryunit are allowed to have the following values:
+ * millisecond, second, minute, hour, day and week. The default is millisecond.
+ *
+ * For programmatic use/subclassing, there are two methods that may be overrridden,
+ * <code>processSuccess</code> and <code>processTimeout</code>
+ * @since Ant 1.5
+ *
+ * @ant.task category="control"
+ */
+public class WaitFor extends ConditionBase {
+    /** a millisecond */
+    public static final long ONE_MILLISECOND = 1L;
+    /** a second in milliseconds */
+    public static final long ONE_SECOND = 1000L;
+    /** a minute in milliseconds */
+    public static final long ONE_MINUTE = ONE_SECOND * 60L;
+    /** an hour in milliseconds */
+    public static final long ONE_HOUR   = ONE_MINUTE * 60L;
+    /** a day in milliseconds */
+    public static final long ONE_DAY    = ONE_HOUR * 24L;
+    /** a week in milliseconds */
+    public static final long ONE_WEEK   = ONE_DAY * 7L;
+
+    /** default wait time */
+    public static final long DEFAULT_MAX_WAIT_MILLIS = ONE_MINUTE * 3L;
+    /** default check time */
+    public static final long DEFAULT_CHECK_MILLIS = 500L;
+
+    /** default max wait time in the current unit*/
+    private long maxWait = DEFAULT_MAX_WAIT_MILLIS;
+    private long maxWaitMultiplier = ONE_MILLISECOND;
+    /**
+     * check time in the current unit
+     */
+    private long checkEvery = DEFAULT_CHECK_MILLIS;
+    private long checkEveryMultiplier = ONE_MILLISECOND;
+    private String timeoutProperty;
+
+    /**
+     * Constructor, names this task "waitfor".
+     */
+    public WaitFor() {
+        super("waitfor");
+    }
+
+
+    /**
+     * Constructor that takes the name of the task in the task name.
+     *
+     * @param taskName the name of the task.
+     * @since Ant 1.8
+     */
+    public WaitFor(String taskName) {
+        super(taskName);
+    }
+
+    /**
+     * Set the maximum length of time to wait.
+     * @param time a <code>long</code> value
+     */
+    public void setMaxWait(long time) {
+        maxWait = time;
+    }
+
+
+    /**
+     * Set the max wait time unit
+     * @param unit an enumerated <code>Unit</code> value
+     */
+    public void setMaxWaitUnit(Unit unit) {
+        maxWaitMultiplier = unit.getMultiplier();
+    }
+
+
+
+    /**
+     * Set the time between each check
+     * @param time a <code>long</code> value
+     */
+    public void setCheckEvery(long time) {
+        checkEvery = time;
+    }
+
+    /**
+     * Set the check every time unit
+     * @param unit an enumerated <code>Unit</code> value
+     */
+    public void setCheckEveryUnit(Unit unit) {
+        checkEveryMultiplier = unit.getMultiplier();
+    }
+
+    /**
+     * Name the property to set after a timeout.
+     * @param p the property name
+     */
+    public void setTimeoutProperty(String p) {
+        timeoutProperty = p;
+    }
+
+    /**
+     * Check repeatedly for the specified conditions until they become
+     * true or the timeout expires.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (countConditions() > 1) {
+            throw new BuildException("You must not nest more than one "
+                                     + "condition into "
+                                     + getTaskName());
+        }
+        if (countConditions() < 1) {
+            throw new BuildException("You must nest a condition into "
+                                     + getTaskName());
+        }
+        Condition c = (Condition) getConditions().nextElement();
+        try {
+            long maxWaitMillis = calculateMaxWaitMillis();
+            long checkEveryMillis = calculateCheckEveryMillis();
+            long start = System.currentTimeMillis();
+            long end = start + maxWaitMillis;
+
+            while (System.currentTimeMillis() < end) {
+                if (c.eval()) {
+                    processSuccess();
+                    return;
+                }
+                Thread.sleep(checkEveryMillis);
+            }
+        } catch (InterruptedException e) {
+            log("Task " + getTaskName()
+                    + " interrupted, treating as timed out.");
+        }
+        processTimeout();
+    }
+
+    /**
+     * Get the check wait time, in milliseconds.
+     * @since Ant 1.8
+     * @return how long to wait between checks
+     */
+    public long calculateCheckEveryMillis() {
+        return checkEvery * checkEveryMultiplier;
+    }
+
+    /**
+     * Get the maxiumum wait time, in milliseconds.
+     * @since Ant 1.8
+     * @return how long to wait before timing out
+     */
+    public long calculateMaxWaitMillis() {
+        return maxWait * maxWaitMultiplier;
+    }
+
+    /**
+     * Actions to be taken on a successful waitfor.
+     * This is an override point. The base implementation does nothing.
+     * @since Ant1.7
+     */
+    protected void processSuccess() {
+        log(getTaskName() + ": condition was met", Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Actions to be taken on an unsuccessful wait.
+     * This is an override point. It is where the timeout processing takes place.
+     * The base implementation sets the timeoutproperty if there was a timeout
+     * and the property was defined.
+     * @since Ant1.7
+     */
+    protected void processTimeout() {
+        log(getTaskName() + ": timeout", Project.MSG_VERBOSE);
+        if (timeoutProperty != null) {
+            getProject().setNewProperty(timeoutProperty, "true");
+        }
+    }
+
+    /**
+     * The enumeration of units:
+     * millisecond, second, minute, hour, day, week
+     * @todo we use timestamps in many places, why not factor this out
+     */
+    public static class Unit extends EnumeratedAttribute {
+
+        /** millisecond string */
+        public static final String MILLISECOND = "millisecond";
+        /** second string */
+        public static final String SECOND = "second";
+        /** minute string */
+        public static final String MINUTE = "minute";
+        /** hour string */
+        public static final String HOUR = "hour";
+        /** day string */
+        public static final String DAY = "day";
+        /** week string */
+        public static final String WEEK = "week";
+
+        private static final String[] UNITS = {
+            MILLISECOND, SECOND, MINUTE, HOUR, DAY, WEEK
+        };
+
+        private Map timeTable = new HashMap();
+
+        /** Constructor the Unit enumerated type. */
+        public Unit() {
+            timeTable.put(MILLISECOND, new Long(1L));
+            timeTable.put(SECOND,      new Long(ONE_SECOND));
+            timeTable.put(MINUTE,      new Long(ONE_MINUTE));
+            timeTable.put(HOUR,        new Long(ONE_HOUR));
+            timeTable.put(DAY,         new Long(ONE_DAY));
+            timeTable.put(WEEK,        new Long(ONE_WEEK));
+        }
+
+        /**
+         * Convert the value to a multipler (millisecond to unit).
+         * @return a multipler (a long value)
+         */
+        public long getMultiplier() {
+            String key = getValue().toLowerCase();
+            Long l = (Long) timeTable.get(key);
+            return l.longValue();
+        }
+
+        /**
+         * @see EnumeratedAttribute#getValues()
+         */
+        /** {@inheritDoc} */
+        public String[] getValues() {
+            return UNITS;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/War.java b/trunk/src/main/org/apache/tools/ant/taskdefs/War.java
new file mode 100644
index 0000000..9940a44
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/War.java
@@ -0,0 +1,230 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Locale;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.zip.ZipOutputStream;
+
+
+/**
+ * An extension of &lt;jar&gt; to create a WAR archive.
+ * Contains special treatment for files that should end up in the
+ * <code>WEB-INF/lib</code>, <code>WEB-INF/classes</code> or
+ * <code>WEB-INF</code> directories of the Web Application Archive.</p>
+ * <p>(The War task is a shortcut for specifying the particular layout of a WAR file.
+ * The same thing can be accomplished by using the <i>prefix</i> and <i>fullpath</i>
+ * attributes of zipfilesets in a Zip or Jar task.)</p>
+ * <p>The extended zipfileset element from the zip task
+ * (with attributes <i>prefix</i>, <i>fullpath</i>, and <i>src</i>)
+ * is available in the War task.</p>
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="packaging"
+ * @see Jar
+ */
+public class War extends Jar {
+
+    /**
+     * our web.xml deployment descriptor
+     */
+    private File deploymentDescriptor;
+
+    /**
+     * flag set if the descriptor is added
+     */
+    private boolean needxmlfile = true;
+    private File addedWebXmlFile;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    /** path to web.xml file */
+    private static final String XML_DESCRIPTOR_PATH = "WEB-INF/web.xml";
+    /** lower case version for comparisons */
+    private static final String XML_DESCRIPTOR_PATH_LC =
+            XML_DESCRIPTOR_PATH.toLowerCase(Locale.ENGLISH);
+
+    /** Constructor for the War Task. */
+    public War() {
+        super();
+        archiveType = "war";
+        emptyBehavior = "create";
+    }
+
+    /**
+     * <i>Deprecated<i> name of the file to create
+     * -use <tt>destfile</tt> instead.
+     * @param warFile the destination file
+     * @deprecated since 1.5.x.
+     *             Use setDestFile(File) instead
+     * @ant.attribute ignore="true"
+     */
+    public void setWarfile(File warFile) {
+        setDestFile(warFile);
+    }
+
+    /**
+     * set the deployment descriptor to use (WEB-INF/web.xml);
+     * required unless <tt>update=true</tt>
+     * @param descr the deployment descriptor file
+     */
+    public void setWebxml(File descr) {
+        deploymentDescriptor = descr;
+        if (!deploymentDescriptor.exists()) {
+            throw new BuildException("Deployment descriptor: "
+                                     + deploymentDescriptor
+                                     + " does not exist.");
+        }
+
+        // Create a ZipFileSet for this file, and pass it up.
+        ZipFileSet fs = new ZipFileSet();
+        fs.setFile(deploymentDescriptor);
+        fs.setFullpath(XML_DESCRIPTOR_PATH);
+        super.addFileset(fs);
+    }
+
+
+    /**
+     * Set the policy on the web.xml file, that is, whether or not it is needed
+     * @param needxmlfile whether a web.xml file is needed. Default: true
+     */
+    public void setNeedxmlfile(boolean needxmlfile) {
+        this.needxmlfile = needxmlfile;
+    }
+
+    /**
+     * add files under WEB-INF/lib/
+     * @param fs the zip file set to add
+     */
+
+    public void addLib(ZipFileSet fs) {
+        // We just set the prefix for this fileset, and pass it up.
+        fs.setPrefix("WEB-INF/lib/");
+        super.addFileset(fs);
+    }
+
+    /**
+     * add files under WEB-INF/classes
+     * @param fs the zip file set to add
+     */
+    public void addClasses(ZipFileSet fs) {
+        // We just set the prefix for this fileset, and pass it up.
+        fs.setPrefix("WEB-INF/classes/");
+        super.addFileset(fs);
+    }
+
+    /**
+     * files to add under WEB-INF;
+     * @param fs the zip file set to add
+     */
+    public void addWebinf(ZipFileSet fs) {
+        // We just set the prefix for this fileset, and pass it up.
+        fs.setPrefix("WEB-INF/");
+        super.addFileset(fs);
+    }
+
+    /**
+     * override of  parent; validates configuration
+     * before initializing the output stream.
+     * @param zOut the zip output stream
+     * @throws IOException on output error
+     * @throws BuildException if invalid configuration
+     */
+    protected void initZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+        super.initZipOutputStream(zOut);
+    }
+
+    /**
+     * Overridden from Zip class to deal with web.xml
+     *
+     * Here are cases that can arise
+     * -not a web.xml file : add
+     * -first web.xml : add, remember we added it
+     * -same web.xml again: skip
+     * -alternate web.xml : warn and skip
+     *
+     * @param file the file to add to the archive
+     * @param zOut the stream to write to
+     * @param vPath the name this entry shall have in the archive
+     * @param mode the Unix permissions to set.
+     * @throws IOException on output error
+     */
+    protected void zipFile(File file, ZipOutputStream zOut, String vPath,
+                           int mode)
+        throws IOException {
+        // If the file being added is WEB-INF/web.xml, we warn if it's
+        // not the one specified in the "webxml" attribute - or if
+        // it's being added twice, meaning the same file is specified
+        // by the "webxml" attribute and in a <fileset> element.
+        String vPathLowerCase = vPath.toLowerCase(Locale.ENGLISH);
+        //by default, we add the file.
+        boolean addFile = true;
+        if (XML_DESCRIPTOR_PATH_LC.equals(vPathLowerCase)) {
+            //a web.xml file was found. See if it is a duplicate or not
+            if (addedWebXmlFile != null) {
+                //a second web.xml file, so skip it
+                addFile = false;
+                //check to see if we warn or not
+                if (!FILE_UTILS.fileNameEquals(addedWebXmlFile, file)) {
+                    log("Warning: selected " + archiveType
+                            + " files include a second " + XML_DESCRIPTOR_PATH
+                            + " which will be ignored.\n"
+                            + "The duplicate entry is at " + file + '\n'
+                            + "The file that will be used is "
+                            + addedWebXmlFile,
+                            Project.MSG_WARN);
+                }
+            } else {
+                //no added file, yet
+                addedWebXmlFile = file;
+                //there is no web.xml file, so add it
+                addFile = true;
+                //and remember that we did
+                deploymentDescriptor = file;
+            }
+        }
+        if (addFile) {
+            super.zipFile(file, zOut, vPath, mode);
+        }
+    }
+
+
+    /**
+     * Make sure we don't think we already have a web.xml next time this task
+     * gets executed.
+     */
+    protected void cleanUp() {
+        if (addedWebXmlFile == null
+            && deploymentDescriptor == null
+            && needxmlfile
+            && !isInUpdateMode()
+            && hasUpdatedFile()) {
+            throw new BuildException("No WEB-INF/web.xml file was added.\n"
+                    + "If this is your intent, set needxmlfile='false' ");
+        }
+        addedWebXmlFile = null;
+        super.cleanUp();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/WhichResource.java b/trunk/src/main/org/apache/tools/ant/taskdefs/WhichResource.java
new file mode 100644
index 0000000..e24819b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/WhichResource.java
@@ -0,0 +1,192 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.AntClassLoader;
+
+import java.net.URL;
+
+/**
+ * Find a class or resource on the supplied classpath, or the
+ * system classpath if none is supplied. The named property is set if
+ * the item can be found. For example
+ * <pre>
+ * &lt;whichresource resource="/log4j.properties"
+ *   property="log4j.url" &gt;
+ * </pre>
+ * @since Ant 1.6
+ * @ant.attribute.group name="oneof" description="Exactly one of these two"
+ */
+public class WhichResource extends Task {
+    /**
+     * our classpath
+     */
+    private Path classpath;
+
+    /**
+     * class to look for
+     */
+    private String classname;
+
+    /**
+     * resource to look for
+     */
+    private String resource;
+
+    /**
+     * property to set
+     */
+    private String property;
+
+
+    /**
+     * Set the classpath to be used for this compilation.
+     * @param cp the classpath to be used.
+     */
+    public void setClasspath(Path cp) {
+        if (classpath == null) {
+            classpath = cp;
+        } else {
+            classpath.append(cp);
+        }
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a classpath to be configured.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Set the classpath to use by reference.
+     *
+     * @param r a reference to an existing classpath.
+     * @since Ant 1.7.1
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * validate
+     */
+    private void validate() {
+        int setcount = 0;
+        if (classname != null) {
+            setcount++;
+        }
+        if (resource != null) {
+            setcount++;
+        }
+
+
+        if (setcount == 0) {
+            throw new BuildException(
+                    "One of classname or resource must be specified");
+        }
+        if (setcount > 1) {
+            throw new BuildException(
+                    "Only one of classname or resource can be specified");
+        }
+        if (property == null) {
+            throw new BuildException("No property defined");
+        }
+    }
+
+    /**
+     * execute it
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        validate();
+        if (classpath != null) {
+            getProject().log("using user supplied classpath: " + classpath,
+                    Project.MSG_DEBUG);
+            classpath = classpath.concatSystemClasspath("ignore");
+        } else {
+            classpath = new Path(getProject());
+            classpath = classpath.concatSystemClasspath("only");
+            getProject().log("using system classpath: " + classpath, Project.MSG_DEBUG);
+        }
+        AntClassLoader loader;
+        loader = new AntClassLoader(getProject().getCoreLoader(),
+                    getProject(),
+                    classpath, false);
+        String loc = null;
+        if (classname != null) {
+            //convert a class name into a resource
+            resource = classname.replace('.', '/') + ".class";
+        }
+
+        if (resource == null) {
+            throw new BuildException("One of class or resource is required");
+        }
+
+        if (resource.startsWith("/")) {
+            resource = resource.substring(1);
+        }
+
+        log("Searching for " + resource, Project.MSG_VERBOSE);
+        URL url;
+        url = loader.getResource(resource);
+        if (url != null) {
+            //set the property
+            loc = url.toExternalForm();
+            getProject().setNewProperty(property, loc);
+        }
+    }
+
+    /**
+     * name the resource to look for
+     * @param resource the name of the resource to look for.
+     * @ant.attribute group="oneof"
+     */
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+
+    /**
+     * name the class to look for
+     * @param classname the name of the class to look for.
+     * @ant.attribute group="oneof"
+     */
+    public void setClass(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * the property to fill with the URL of the resource or class
+     * @param property the property to be set.
+     * @ant.attribute group="required"
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java
new file mode 100644
index 0000000..71e1def
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+/**
+ * Proxy interface for XSLT processors.
+ *
+ * @see XSLTProcess
+ * @since Ant 1.1
+ */
+public interface XSLTLiaison {
+
+    /**
+     * the file protocol prefix for systemid.
+     * This file protocol must be appended to an absolute path.
+     * Typically: <tt>FILE_PROTOCOL_PREFIX + file.getAbsolutePath()</tt>
+     * Note that on Windows, an extra '/' must be appended to the
+     * protocol prefix so that there is always 3 consecutive slashes.
+     * @since Ant 1.4
+     */
+    String FILE_PROTOCOL_PREFIX = "file://";
+
+    /**
+     * set the stylesheet to use for the transformation.
+     * @param stylesheet the stylesheet to be used for transformation.
+     * @throws Exception thrown if any problems happens.
+     * @since Ant 1.4
+     */
+    void setStylesheet(File stylesheet) throws Exception;
+
+    /**
+     * Add a parameter to be set during the XSL transformation.
+     * @param name the parameter name.
+     * @param expression the parameter value as an expression string.
+     * @throws Exception thrown if any problems happens.
+     * @since Ant 1.3
+     */
+    void addParam(String name, String expression) throws Exception;
+
+    /**
+     * Perform the transformation of a file into another.
+     * @param infile the input file, probably an XML one. :-)
+     * @param outfile the output file resulting from the transformation
+     * @throws Exception thrown if any problems happens.
+     * @see #setStylesheet(File)
+     * @since Ant 1.4
+     */
+    void transform(File infile, File outfile) throws Exception;
+
+} //-- XSLTLiaison
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java
new file mode 100644
index 0000000..831aff5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Extended Proxy interface for XSLT processors.
+ *
+ * @see XSLTProcess
+ * @since Ant 1.6
+ */
+public interface XSLTLiaison2 extends XSLTLiaison {
+    /**
+     * Configure the liasion from the XSLTProcess task
+     * @param xsltTask the XSLTProcess task
+     */
+    void configure(XSLTProcess xsltTask);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison3.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison3.java
new file mode 100644
index 0000000..963093f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison3.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Extends Proxy interface for XSLT processors.
+ *
+ * @see XSLTProcess
+ * @since Ant 1.7
+ */
+public interface XSLTLiaison3 extends XSLTLiaison2 {
+    /**
+     * sets the stylesheet to use as a resource
+     * @param stylesheet the stylesheet to use as a resource
+     * @throws Exception if the stylesheet cannot be loaded
+     */
+    void setStylesheet(Resource stylesheet) throws Exception;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLogger.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLogger.java
new file mode 100644
index 0000000..4dadebc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLogger.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Interface to log messages for XSLT
+ * @since Ant 1.5
+ */
+public interface XSLTLogger {
+    /**
+     * Log a message.
+     * @param msg the message to log
+     */
+    void log(String msg);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLoggerAware.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLoggerAware.java
new file mode 100644
index 0000000..edf0fce
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTLoggerAware.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Interface for a class that one can set an XSLTLogger on.
+ * @since Ant 1.5
+ */
+public interface XSLTLoggerAware {
+    /**
+     * Set the logger for this class.
+     * @param l the logger
+     */
+    void setLogger(XSLTLogger l);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
new file mode 100644
index 0000000..5f3295b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
@@ -0,0 +1,1188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Processes a set of XML documents via XSLT. This is
+ * useful for building views of XML based documentation.
+ *
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task name="xslt" category="xml"
+ */
+
+public class XSLTProcess extends MatchingTask implements XSLTLogger {
+    /** destination directory */
+    private File destDir = null;
+
+    /** where to find the source XML file, default is the project's basedir */
+    private File baseDir = null;
+
+    /** XSL stylesheet as a filename */
+    private String xslFile = null;
+
+    /** XSL stylesheet as a {@link org.apache.tools.ant.types.Resource} */
+    private Resource xslResource = null;
+
+    /** extension of the files produced by XSL processing */
+    private String targetExtension = ".html";
+
+    /** name for XSL parameter containing the filename */
+    private String fileNameParameter = null;
+
+    /** name for XSL parameter containing the file directory */
+    private String fileDirParameter = null;
+
+    /** additional parameters to be passed to the stylesheets */
+    private Vector params = new Vector();
+
+    /** Input XML document to be used */
+    private File inFile = null;
+
+    /** Output file */
+    private File outFile = null;
+
+    /** The name of the XSL processor to use */
+    private String processor;
+
+    /** Classpath to use when trying to load the XSL processor */
+    private Path classpath = null;
+
+    /** The Liason implementation to use to communicate with the XSL
+     *  processor */
+    private XSLTLiaison liaison;
+
+    /** Flag which indicates if the stylesheet has been loaded into
+     *  the processor */
+    private boolean stylesheetLoaded = false;
+
+    /** force output of target files even if they already exist */
+    private boolean force = false;
+
+    /** XSL output properties to be used */
+    private Vector outputProperties = new Vector();
+
+    /** for resolving entities such as dtds */
+    private XMLCatalog xmlCatalog = new XMLCatalog();
+
+    /** Name of the TRAX Liaison class */
+    private static final String TRAX_LIAISON_CLASS =
+                        "org.apache.tools.ant.taskdefs.optional.TraXLiaison";
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Whether to style all files in the included directories as well.
+     *
+     * @since Ant 1.5
+     */
+    private boolean performDirectoryScan = true;
+
+    /**
+     * factory element for TraX processors only
+     * @since Ant 1.6
+     */
+    private Factory factory = null;
+
+    /**
+     * whether to reuse Transformer if transforming multiple files.
+     * @since 1.5.2
+     */
+    private boolean reuseLoadedStylesheet = true;
+
+    /**
+     * AntClassLoader for the nested &lt;classpath&gt; - if set.
+     *
+     * <p>We keep this here in order to reset the context classloader
+     * in execute.  We can't use liaison.getClass().getClassLoader()
+     * since the actual liaison class may have been loaded by a loader
+     * higher up (system classloader, for example).</p>
+     *
+     * @since Ant 1.6.2
+     */
+    private AntClassLoader loader = null;
+
+    /**
+     * Mapper to use when a set of files gets processed.
+     *
+     * @since Ant 1.6.2
+     */
+    private Mapper mapperElement = null;
+
+    /**
+     * Additional resource collections to process.
+     *
+     * @since Ant 1.7
+     */
+    private Union resources = new Union();
+
+    /**
+     * Whether to use the implicit fileset.
+     *
+     * @since Ant 1.7
+     */
+    private boolean useImplicitFileset = true;
+
+    /**
+     * The default processor is trax
+     * @since Ant 1.7
+     */
+    public static final String PROCESSOR_TRAX = "trax";
+
+    /**
+     * Creates a new XSLTProcess Task.
+     */
+    public XSLTProcess() {
+    } //-- XSLTProcess
+
+    /**
+     * Whether to style all files in the included directories as well;
+     * optional, default is true.
+     *
+     * @param b true if files in included directories are processed.
+     * @since Ant 1.5
+     */
+    public void setScanIncludedDirectories(boolean b) {
+        performDirectoryScan = b;
+    }
+
+    /**
+     * Controls whether the stylesheet is reloaded for every transform.
+     *
+     * <p>Setting this to true may get around a bug in certain
+     * Xalan-J versions, default is false.</p>
+     * @param b a <code>boolean</code> value
+     * @since Ant 1.5.2
+     */
+    public void setReloadStylesheet(boolean b) {
+        reuseLoadedStylesheet = !b;
+    }
+
+    /**
+     * Defines the mapper to map source to destination files.
+     * @param mapper the mapper to use
+     * @exception BuildException if more than one mapper is defined
+     * @since Ant 1.6.2
+     */
+    public void addMapper(Mapper mapper) {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper", getLocation());
+        }
+        mapperElement = mapper;
+    }
+
+    /**
+     * Adds a collection of resources to style in addition to the
+     * given file or the implicit fileset.
+     *
+     * @param rc the collection of resources to style
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        resources.add(rc);
+    }
+
+    /**
+     * Add a nested &lt;style&gt; element.
+     * @param rc the configured Resources object represented as &lt;style&gt;.
+     * @since Ant 1.7
+     */
+    public void addConfiguredStyle(Resources rc) {
+        if (rc.size() != 1) {
+            throw new BuildException(
+                    "The style element must be specified with exactly one nested resource.");
+        }
+        setXslResource((Resource) rc.iterator().next());
+    }
+
+    /**
+     * API method to set the XSL Resource.
+     * @param xslResource Resource to set as the stylesheet.
+     * @since Ant 1.7
+     */
+    public void setXslResource(Resource xslResource) {
+        this.xslResource = xslResource;
+    }
+
+    /**
+     * Adds a nested filenamemapper.
+     * @param fileNameMapper the mapper to add
+     * @exception BuildException if more than one mapper is defined
+     * @since Ant 1.7.0
+     */
+    public void add(FileNameMapper fileNameMapper) throws BuildException {
+       Mapper mapper = new Mapper(getProject());
+       mapper.add(fileNameMapper);
+       addMapper(mapper);
+    }
+
+    /**
+     * Executes the task.
+     *
+     * @exception BuildException if there is an execution problem.
+     * @todo validate that if either in or our is defined, then both are
+     */
+    public void execute() throws BuildException {
+        if ("style".equals(getTaskType())) {
+            log("Warning: the task name <style> is deprecated. Use <xslt> instead.",
+                    Project.MSG_WARN);
+        }
+        File savedBaseDir = baseDir;
+
+        DirectoryScanner scanner;
+        String[]         list;
+        String[]         dirs;
+
+        String baseMessage =
+            "specify the stylesheet either as a filename in style attribute "
+            + "or as a nested resource";
+
+        if (xslResource == null && xslFile == null) {
+            throw new BuildException(baseMessage, getLocation());
+        }
+        if (xslResource != null && xslFile != null) {
+            throw new BuildException(baseMessage + " but not as both", getLocation());
+        }
+        if (inFile != null && !inFile.exists()) {
+            throw new BuildException("input file " + inFile + " does not exist", getLocation());
+        }
+        try {
+            Resource styleResource;
+            if (baseDir == null) {
+                baseDir = getProject().getBaseDir();
+            }
+            liaison = getLiaison();
+
+            // check if liaison wants to log errors using us as logger
+            if (liaison instanceof XSLTLoggerAware) {
+                ((XSLTLoggerAware) liaison).setLogger(this);
+            }
+            log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
+
+            if (xslFile != null) {
+                // If we enter here, it means that the stylesheet is supplied
+                // via style attribute
+                File stylesheet = getProject().resolveFile(xslFile);
+                if (!stylesheet.exists()) {
+                    stylesheet = FILE_UTILS.resolveFile(baseDir, xslFile);
+                    /*
+                     * shouldn't throw out deprecation warnings before we know,
+                     * the wrong version has been used.
+                     */
+                    if (stylesheet.exists()) {
+                        log("DEPRECATED - the 'style' attribute should be "
+                            + "relative to the project's");
+                        log("             basedir, not the tasks's basedir.");
+                    }
+                }
+                FileResource fr = new FileResource();
+                fr.setProject(getProject());
+                fr.setFile(stylesheet);
+                styleResource = fr;
+            } else {
+                styleResource = xslResource;
+            }
+            // if we have an in file and out then process them
+            if (inFile != null && outFile != null) {
+                process(inFile, outFile, styleResource);
+                return;
+            }
+            /*
+             * if we get here, in and out have not been specified, we are
+             * in batch processing mode.
+             */
+
+            //-- make sure destination directory exists...
+            checkDest();
+
+            if (useImplicitFileset) {
+                scanner = getDirectoryScanner(baseDir);
+                log("Transforming into " + destDir, Project.MSG_INFO);
+
+                // Process all the files marked for styling
+                list = scanner.getIncludedFiles();
+                for (int i = 0; i < list.length; ++i) {
+                    process(baseDir, list[i], destDir, styleResource);
+                }
+                if (performDirectoryScan) {
+                    // Process all the directories marked for styling
+                    dirs = scanner.getIncludedDirectories();
+                    for (int j = 0; j < dirs.length; ++j) {
+                        list = new File(baseDir, dirs[j]).list();
+                        for (int i = 0; i < list.length; ++i) {
+                            process(baseDir, dirs[j] + File.separator + list[i], destDir,
+                                    styleResource);
+                        }
+                    }
+                }
+            } else { // only resource collections, there better be some
+                if (resources.size() == 0) {
+                    throw new BuildException("no resources specified");
+                }
+            }
+            processResources(styleResource);
+        } finally {
+            if (loader != null) {
+                loader.resetThreadContextLoader();
+                loader.cleanup();
+                loader = null;
+            }
+            liaison = null;
+            stylesheetLoaded = false;
+            baseDir = savedBaseDir;
+        }
+    }
+
+    /**
+     * Set whether to check dependencies, or always generate;
+     * optional, default is false.
+     *
+     * @param force true if always generate.
+     */
+    public void setForce(boolean force) {
+        this.force = force;
+    }
+
+    /**
+     * Set the base directory;
+     * optional, default is the project's basedir.
+     *
+     * @param dir the base directory
+     **/
+    public void setBasedir(File dir) {
+        baseDir = dir;
+    }
+
+    /**
+     * Set the destination directory into which the XSL result
+     * files should be copied to;
+     * required, unless <tt>in</tt> and <tt>out</tt> are
+     * specified.
+     * @param dir the name of the destination directory
+     **/
+    public void setDestdir(File dir) {
+        destDir = dir;
+    }
+
+    /**
+     * Set the desired file extension to be used for the target;
+     * optional, default is html.
+     * @param name the extension to use
+     **/
+    public void setExtension(String name) {
+        targetExtension = name;
+    }
+
+    /**
+     * Name of the stylesheet to use - given either relative
+     * to the project's basedir or as an absolute path; required.
+     *
+     * @param xslFile the stylesheet to use
+     */
+    public void setStyle(String xslFile) {
+        this.xslFile = xslFile;
+    }
+
+    /**
+     * Set the optional classpath to the XSL processor
+     *
+     * @param classpath the classpath to use when loading the XSL processor
+     */
+    public void setClasspath(Path classpath) {
+        createClasspath().append(classpath);
+    }
+
+    /**
+     * Set the optional classpath to the XSL processor
+     *
+     * @return a path instance to be configured by the Ant core.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Set the reference to an optional classpath to the XSL processor
+     *
+     * @param r the id of the Ant path instance to act as the classpath
+     *          for loading the XSL processor
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Set the name of the XSL processor to use; optional, default trax.
+     * Other values are "xalan" for Xalan1
+     *
+     * @param processor the name of the XSL processor
+     */
+    public void setProcessor(String processor) {
+        this.processor = processor;
+    }
+
+    /**
+     * Whether to use the implicit fileset.
+     *
+     * <p>Set this to false if you want explicit control with nested
+     * resource collections.</p>
+     * @param useimplicitfileset set to true if you want to use implicit fileset
+     * @since Ant 1.7
+     */
+    public void setUseImplicitFileset(boolean useimplicitfileset) {
+        useImplicitFileset = useimplicitfileset;
+    }
+
+    /**
+     * Add the catalog to our internal catalog
+     *
+     * @param xmlCatalog the XMLCatalog instance to use to look up DTDs
+     */
+    public void addConfiguredXMLCatalog(XMLCatalog xmlCatalog) {
+        this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog);
+    }
+
+    /**
+     * Pass the filename of the current processed file as a xsl parameter
+     * to the transformation. This value sets the name of that xsl parameter.
+     *
+     * @param fileNameParameter name of the xsl parameter retrieving the
+     *                          current file name
+     */
+    public void setFileNameParameter(String fileNameParameter) {
+        this.fileNameParameter = fileNameParameter;
+    }
+
+    /**
+     * Pass the directory name of the current processed file as a xsl parameter
+     * to the transformation. This value sets the name of that xsl parameter.
+     *
+     * @param fileDirParameter name of the xsl parameter retrieving the
+     *                         current file directory
+     */
+    public void setFileDirParameter(String fileDirParameter) {
+        this.fileDirParameter = fileDirParameter;
+    }
+
+    /**
+     * Load processor here instead of in setProcessor - this will be
+     * called from within execute, so we have access to the latest
+     * classpath.
+     *
+     * @param proc the name of the processor to load.
+     * @exception Exception if the processor cannot be loaded.
+     */
+    private void resolveProcessor(String proc) throws Exception {
+        String classname;
+        if (proc.equals(PROCESSOR_TRAX)) {
+            classname = TRAX_LIAISON_CLASS;
+        } else {
+            //anything else is a classname
+            classname = proc;
+        }
+        Class clazz = loadClass(classname);
+        liaison = (XSLTLiaison) clazz.newInstance();
+    }
+
+    /**
+     * Load named class either via the system classloader or a given
+     * custom classloader.
+     *
+     * As a side effect, the loader is set as the thread context classloader
+     * @param classname the name of the class to load.
+     * @return the requested class.
+     * @exception Exception if the class could not be loaded.
+     */
+    private Class loadClass(String classname) throws Exception {
+        if (classpath == null) {
+            return Class.forName(classname);
+        }
+        loader = getProject().createClassLoader(classpath);
+        loader.setThreadContextLoader();
+        return Class.forName(classname, true, loader);
+    }
+
+    /**
+     * Specifies the output name for the styled result from the
+     * <tt>in</tt> attribute; required if <tt>in</tt> is set
+     *
+     * @param outFile the output File instance.
+     */
+    public void setOut(File outFile) {
+        this.outFile = outFile;
+    }
+
+    /**
+     * specifies a single XML document to be styled. Should be used
+     * with the <tt>out</tt> attribute; ; required if <tt>out</tt> is set
+     *
+     * @param inFile the input file
+     */
+    public void setIn(File inFile) {
+        this.inFile = inFile;
+    }
+
+    /**
+     * Throws a BuildException if the destination directory hasn't
+     * been specified.
+     * @since Ant 1.7
+     */
+    private void checkDest() {
+        if (destDir == null) {
+            String msg = "destdir attributes must be set!";
+            throw new BuildException(msg);
+        }
+    }
+
+    /**
+     * Styles all existing resources.
+     *
+     * @param stylesheet style sheet to use
+     * @since Ant 1.7
+     */
+    private void processResources(Resource stylesheet) {
+        Iterator iter = resources.iterator();
+        while (iter.hasNext()) {
+            Resource r = (Resource) iter.next();
+            if (!r.isExists()) {
+                continue;
+            }
+            File base = baseDir;
+            String name = r.getName();
+            if (r instanceof FileResource) {
+                FileResource f = (FileResource) r;
+                base = f.getBaseDir();
+                if (base == null) {
+                    name = f.getFile().getAbsolutePath();
+                }
+            }
+            process(base, name, destDir, stylesheet);
+        }
+    }
+
+    /**
+     * Processes the given input XML file and stores the result
+     * in the given resultFile.
+     *
+     * @param baseDir the base directory for resolving files.
+     * @param xmlFile the input file
+     * @param destDir the destination directory
+     * @param stylesheet the stylesheet to use.
+     * @exception BuildException if the processing fails.
+     */
+    private void process(File baseDir, String xmlFile, File destDir, Resource stylesheet)
+            throws BuildException {
+
+        File   outF = null;
+        File   inF = null;
+
+        try {
+            long styleSheetLastModified = stylesheet.getLastModified();
+            inF = new File(baseDir, xmlFile);
+
+            if (inF.isDirectory()) {
+                log("Skipping " + inF + " it is a directory.", Project.MSG_VERBOSE);
+                return;
+            }
+            FileNameMapper mapper = null;
+            if (mapperElement != null) {
+                mapper = mapperElement.getImplementation();
+            } else {
+                mapper = new StyleMapper();
+            }
+
+            String[] outFileName = mapper.mapFileName(xmlFile);
+            if (outFileName == null || outFileName.length == 0) {
+                log("Skipping " + inFile + " it cannot get mapped to output.", Project.MSG_VERBOSE);
+                return;
+            } else if (outFileName == null || outFileName.length > 1) {
+                log("Skipping " + inFile + " its mapping is ambiguos.", Project.MSG_VERBOSE);
+                return;
+            }
+            outF = new File(destDir, outFileName[0]);
+
+            if (force || inF.lastModified() > outF.lastModified()
+                    || styleSheetLastModified > outF.lastModified()) {
+                ensureDirectoryFor(outF);
+                log("Processing " + inF + " to " + outF);
+                configureLiaison(stylesheet);
+                setLiaisonDynamicFileParameters(liaison, inF);
+                liaison.transform(inF, outF);
+            }
+        } catch (Exception ex) {
+            // If failed to process document, must delete target document,
+            // or it will not attempt to process it the second time
+            log("Failed to process " + inFile, Project.MSG_INFO);
+            if (outF != null) {
+                outF.delete();
+            }
+
+            throw new BuildException(ex);
+        }
+
+    } //-- processXML
+
+    /**
+     * Process the input file to the output file with the given stylesheet.
+     *
+     * @param inFile the input file to process.
+     * @param outFile the destination file.
+     * @param stylesheet the stylesheet to use.
+     * @exception BuildException if the processing fails.
+     */
+    private void process(File inFile, File outFile, Resource stylesheet) throws BuildException {
+        try {
+            long styleSheetLastModified = stylesheet.getLastModified();
+            log("In file " + inFile + " time: " + inFile.lastModified(), Project.MSG_DEBUG);
+            log("Out file " + outFile + " time: " + outFile.lastModified(), Project.MSG_DEBUG);
+            log("Style file " + xslFile + " time: " + styleSheetLastModified, Project.MSG_DEBUG);
+            if (force || inFile.lastModified() >= outFile.lastModified()
+                    || styleSheetLastModified >= outFile.lastModified()) {
+                ensureDirectoryFor(outFile);
+                log("Processing " + inFile + " to " + outFile, Project.MSG_INFO);
+                configureLiaison(stylesheet);
+                setLiaisonDynamicFileParameters(liaison, inFile);
+                liaison.transform(inFile, outFile);
+            } else {
+                log("Skipping input file " + inFile + " because it is older than output file "
+                        + outFile + " and so is the stylesheet " + stylesheet, Project.MSG_DEBUG);
+            }
+        } catch (Exception ex) {
+            log("Failed to process " + inFile, Project.MSG_INFO);
+            if (outFile != null) {
+                outFile.delete();
+            }
+            throw new BuildException(ex);
+        }
+    }
+
+    /**
+     * Ensure the directory exists for a given file
+     *
+     * @param targetFile the file for which the directories are required.
+     * @exception BuildException if the directories cannot be created.
+     */
+    private void ensureDirectoryFor(File targetFile) throws BuildException {
+        File directory = targetFile.getParentFile();
+        if (!directory.exists()) {
+            if (!directory.mkdirs()) {
+                throw new BuildException("Unable to create directory: "
+                        + directory.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Get the factory instance configured for this processor
+     *
+     * @return the factory instance in use
+     */
+    public Factory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Get the XML catalog containing entity definitions
+     *
+     * @return the XML catalog for the task.
+     */
+    public XMLCatalog getXMLCatalog() {
+        xmlCatalog.setProject(getProject());
+        return xmlCatalog;
+    }
+
+    /**
+     * Get an enumeration on the outputproperties.
+     * @return the outputproperties
+     */
+    public Enumeration getOutputProperties() {
+        return outputProperties.elements();
+    }
+
+    /**
+     * Get the Liason implementation to use in processing.
+     *
+     * @return an instance of the XSLTLiason interface.
+     */
+    protected XSLTLiaison getLiaison() {
+        // if processor wasn't specified, see if TraX is available.  If not,
+        // default it to xalan, depending on which is in the classpath
+        if (liaison == null) {
+            if (processor != null) {
+                try {
+                    resolveProcessor(processor);
+                } catch (Exception e) {
+                    throw new BuildException(e);
+                }
+            } else {
+                try {
+                    resolveProcessor(PROCESSOR_TRAX);
+                } catch (Throwable e1) {
+                    e1.printStackTrace();
+                    throw new BuildException(e1);
+                }
+            }
+        }
+        return liaison;
+    }
+
+    /**
+     * Create an instance of an XSL parameter for configuration by Ant.
+     *
+     * @return an instance of the Param class to be configured.
+     */
+    public Param createParam() {
+        Param p = new Param();
+        params.addElement(p);
+        return p;
+    }
+
+    /**
+     * The Param inner class used to store XSL parameters
+     */
+    public static class Param {
+        /** The parameter name */
+        private String name = null;
+
+        /** The parameter's value */
+        private String expression = null;
+
+        private String ifProperty;
+        private String unlessProperty;
+        private Project project;
+
+        /**
+         * Set the current project
+         *
+         * @param project the current project
+         */
+        public void setProject(Project project) {
+            this.project = project;
+        }
+
+        /**
+         * Set the parameter name.
+         *
+         * @param name the name of the parameter.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * The parameter value
+         * NOTE : was intended to be an XSL expression.
+         * @param expression the parameter's value.
+         */
+        public void setExpression(String expression) {
+            this.expression = expression;
+        }
+
+        /**
+         * Get the parameter name
+         *
+         * @return the parameter name
+         * @exception BuildException if the name is not set.
+         */
+        public String getName() throws BuildException {
+            if (name == null) {
+                throw new BuildException("Name attribute is missing.");
+            }
+            return name;
+        }
+
+        /**
+         * Get the parameter's value
+         *
+         * @return the parameter value
+         * @exception BuildException if the value is not set.
+         */
+        public String getExpression() throws BuildException {
+            if (expression == null) {
+                throw new BuildException("Expression attribute is missing.");
+            }
+            return expression;
+        }
+
+        /**
+         * Set whether this param should be used.  It will be
+         * used if the property has been set, otherwise it won't.
+         * @param ifProperty name of property
+         */
+        public void setIf(String ifProperty) {
+            this.ifProperty = ifProperty;
+        }
+
+        /**
+         * Set whether this param should NOT be used. It
+         * will not be used if the property has been set, otherwise it
+         * will be used.
+         * @param unlessProperty name of property
+         */
+        public void setUnless(String unlessProperty) {
+            this.unlessProperty = unlessProperty;
+        }
+
+        /**
+         * Ensures that the param passes the conditions placed
+         * on it with <code>if</code> and <code>unless</code> properties.
+         * @return true if the task passes the "if" and "unless" parameters
+         */
+        public boolean shouldUse() {
+            if (ifProperty != null && project.getProperty(ifProperty) == null) {
+                return false;
+            }
+            if (unlessProperty != null && project.getProperty(unlessProperty) != null) {
+                return false;
+            }
+            return true;
+        }
+    } // Param
+
+    /**
+     * Create an instance of an output property to be configured.
+     * @return the newly created output property.
+     * @since Ant 1.5
+     */
+    public OutputProperty createOutputProperty() {
+        OutputProperty p = new OutputProperty();
+        outputProperties.addElement(p);
+        return p;
+    }
+
+    /**
+     * Specify how the result tree should be output as specified
+     * in the <a href="http://www.w3.org/TR/xslt#output">
+     * specification</a>.
+     * @since Ant 1.5
+     */
+    public static class OutputProperty {
+        /** output property name */
+        private String name;
+
+        /** output property value */
+        private String value;
+
+        /**
+         * @return the output property name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * set the name for this property
+         * @param name A non-null String that specifies an
+         * output property name, which may be namespace qualified.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * @return the output property value.
+         */
+        public String getValue() {
+            return value;
+        }
+
+        /**
+         * set the value for this property
+         * @param value The non-null string value of the output property.
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+    }
+
+    /**
+     * Initialize internal instance of XMLCatalog
+     * @throws BuildException on error
+     */
+    public void init() throws BuildException {
+        super.init();
+        xmlCatalog.setProject(getProject());
+    }
+
+    /**
+     * Loads the stylesheet and set xsl:param parameters.
+     *
+     * @param stylesheet the file from which to load the stylesheet.
+     * @exception BuildException if the stylesheet cannot be loaded.
+     * @deprecated since Ant 1.7
+     */
+    protected void configureLiaison(File stylesheet) throws BuildException {
+        FileResource fr = new FileResource();
+        fr.setProject(getProject());
+        fr.setFile(stylesheet);
+        configureLiaison(fr);
+    }
+
+    /**
+     * Loads the stylesheet and set xsl:param parameters.
+     *
+     * @param stylesheet the resource from which to load the stylesheet.
+     * @exception BuildException if the stylesheet cannot be loaded.
+     * @since Ant 1.7
+     */
+    protected void configureLiaison(Resource stylesheet) throws BuildException {
+        if (stylesheetLoaded && reuseLoadedStylesheet) {
+            return;
+        }
+        stylesheetLoaded = true;
+
+        try {
+            log("Loading stylesheet " + stylesheet, Project.MSG_INFO);
+            // We call liason.configure() and then liaison.setStylesheet()
+            // so that the internal variables of liaison can be set up
+            if (liaison instanceof XSLTLiaison2) {
+                ((XSLTLiaison2) liaison).configure(this);
+            }
+            if (liaison instanceof XSLTLiaison3) {
+                // If we are here we can set the stylesheet as a
+                // resource
+                ((XSLTLiaison3) liaison).setStylesheet(stylesheet);
+            } else {
+                // If we are here we cannot set the stylesheet as
+                // a resource, but we can set it as a file. So,
+                // we make an attempt to get it as a file
+                if (stylesheet instanceof FileProvider) {
+                    liaison.setStylesheet(((FileProvider) stylesheet).getFile());
+                } else {
+                    throw new BuildException(liaison.getClass().toString()
+                            + " accepts the stylesheet only as a file", getLocation());
+                }
+            }
+            for (Enumeration e = params.elements(); e.hasMoreElements();) {
+                Param p = (Param) e.nextElement();
+                if (p.shouldUse()) {
+                    liaison.addParam(p.getName(), p.getExpression());
+                }
+            }
+        } catch (Exception ex) {
+            log("Failed to transform using stylesheet " + stylesheet, Project.MSG_INFO);
+            throw new BuildException(ex);
+        }
+    }
+
+    /**
+     * Sets file parameter(s) for directory and filename if the attribute
+     * 'filenameparameter' or 'filedirparameter' are set in the task.
+     *
+     * @param  liaison    to change parameters for
+     * @param  inFile     to get the additional file information from
+     * @throws Exception  if an exception occurs on filename lookup
+     *
+     * @since Ant 1.7
+     */
+    private void setLiaisonDynamicFileParameters(
+        XSLTLiaison liaison, File inFile) throws Exception {
+        if (fileNameParameter != null) {
+            liaison.addParam(fileNameParameter, inFile.getName());
+        }
+        if (fileDirParameter != null) {
+            String fileName = FileUtils.getRelativePath(baseDir, inFile);
+            File file = new File(fileName);
+            // Give always a slash as file separator, so the stylesheet could be sure about that
+            // Use '.' so a dir+"/"+name would not result in an absolute path
+            liaison.addParam(fileDirParameter, file.getParent() != null ? file.getParent().replace(
+                    '\\', '/') : ".");
+        }
+    }
+
+    /**
+     * Create the factory element to configure a trax liaison.
+     * @return the newly created factory element.
+     * @throws BuildException if the element is created more than one time.
+     */
+    public Factory createFactory() throws BuildException {
+        if (factory != null) {
+            throw new BuildException("'factory' element must be unique");
+        }
+        factory = new Factory();
+        return factory;
+    }
+
+    /**
+     * The factory element to configure a transformer factory
+     * @since Ant 1.6
+     */
+    public static class Factory {
+
+        /** the factory class name to use for TraXLiaison */
+        private String name;
+
+        /**
+         * the list of factory attributes to use for TraXLiaison
+         */
+        private Vector attributes = new Vector();
+
+        /**
+         * @return the name of the factory.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the name of the factory
+         * @param name the name of the factory.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Create an instance of a factory attribute.
+         * @param attr the newly created factory attribute
+         */
+        public void addAttribute(Attribute attr) {
+            attributes.addElement(attr);
+        }
+
+        /**
+         * return the attribute elements.
+         * @return the enumeration of attributes
+         */
+        public Enumeration getAttributes() {
+            return attributes.elements();
+        }
+
+        /**
+         * A JAXP factory attribute. This is mostly processor specific, for
+         * example for Xalan 2.3+, the following attributes could be set:
+         * <ul>
+         *  <li>http://xml.apache.org/xalan/features/optimize (true|false) </li>
+         *  <li>http://xml.apache.org/xalan/features/incremental (true|false) </li>
+         * </ul>
+         */
+        public static class Attribute implements DynamicConfigurator {
+
+            /** attribute name, mostly processor specific */
+            private String name;
+
+            /** attribute value, often a boolean string */
+            private Object value;
+
+            /**
+             * @return the attribute name.
+             */
+            public String getName() {
+                return name;
+            }
+
+            /**
+             * @return the output property value.
+             */
+            public Object getValue() {
+                return value;
+            }
+
+            /**
+             * Not used.
+             * @param name not used
+             * @return null
+             * @throws BuildException never
+             */
+            public Object createDynamicElement(String name) throws BuildException {
+                return null;
+            }
+
+            /**
+             * Set an attribute.
+             * Only "name" and "value" are supported as names.
+             * @param name the name of the attribute
+             * @param value the value of the attribute
+             * @throws BuildException on error
+             */
+            public void setDynamicAttribute(String name, String value) throws BuildException {
+                // only 'name' and 'value' exist.
+                if ("name".equalsIgnoreCase(name)) {
+                    this.name = value;
+                } else if ("value".equalsIgnoreCase(name)) {
+                    // a value must be of a given type
+                    // say boolean|integer|string that are mostly used.
+                    if ("true".equalsIgnoreCase(value)) {
+                        this.value = Boolean.TRUE;
+                    } else if ("false".equalsIgnoreCase(value)) {
+                        this.value = Boolean.FALSE;
+                    } else {
+                        try {
+                            this.value = new Integer(value);
+                        } catch (NumberFormatException e) {
+                            this.value = value;
+                        }
+                    }
+                } else {
+                    throw new BuildException("Unsupported attribute: " + name);
+                }
+            }
+        } // -- class Attribute
+    } // -- class Factory
+
+    /**
+     * Mapper implementation of the "traditional" way &lt;xslt&gt;
+     * mapped filenames.
+     *
+     * <p>If the file has an extension, chop it off.  Append whatever
+     * the user has specified as extension or ".html".</p>
+     *
+     * @since Ant 1.6.2
+     */
+    private class StyleMapper implements FileNameMapper {
+        public void setFrom(String from) {
+        }
+        public void setTo(String to) {
+        }
+        public String[] mapFileName(String xmlFile) {
+            int dotPos = xmlFile.lastIndexOf('.');
+            if (dotPos > 0) {
+                xmlFile = xmlFile.substring(0, dotPos);
+            }
+            return new String[] {xmlFile + targetExtension};
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/XmlProperty.java b/trunk/src/main/org/apache/tools/ant/taskdefs/XmlProperty.java
new file mode 100644
index 0000000..adc8fae
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/XmlProperty.java
@@ -0,0 +1,773 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+import org.xml.sax.EntityResolver;
+
+/**
+ * Loads property values from a valid XML file, generating the
+ * property names from the file's element and attribute names.
+ *
+ * <p>Example:</p>
+ * <pre>
+ *   &lt;root-tag myattr="true"&gt;
+ *     &lt;inner-tag someattr="val"&gt;Text&lt;/inner-tag&gt;
+ *     &lt;a2&gt;&lt;a3&gt;&lt;a4&gt;false&lt;/a4&gt;&lt;/a3&gt;&lt;/a2&gt;
+ *     &lt;x&gt;x1&lt;/x&gt;
+ *     &lt;x&gt;x2&lt;/x&gt;
+ *   &lt;/root-tag&gt;
+ *</pre>
+ *
+ * <p>this generates the following properties:</p>
+ *
+ * <pre>
+ *  root-tag(myattr)=true
+ *  root-tag.inner-tag=Text
+ *  root-tag.inner-tag(someattr)=val
+ *  root-tag.a2.a3.a4=false
+ *  root-tag.x=x1,x2
+ * </pre>
+ *
+ * <p>The <i>collapseAttributes</i> property of this task can be set
+ * to true (the default is false) which will instead result in the
+ * following properties (note the difference in names of properties
+ * corresponding to XML attributes):</p>
+ *
+ * <pre>
+ *  root-tag.myattr=true
+ *  root-tag.inner-tag=Text
+ *  root-tag.inner-tag.someattr=val
+ *  root-tag.a2.a3.a4=false
+ *  root-tag.x=x1,x2
+ * </pre>
+ *
+ * <p>Optionally, to more closely mirror the abilities of the Property
+ * task, a selected set of attributes can be treated specially.  To
+ * enable this behavior, the "semanticAttributes" property of this task
+ * must be set to true (it defaults to false).  If this attribute is
+ * specified, the following attributes take on special meaning
+ * (setting this to true implicitly sets collapseAttributes to true as
+ * well):</p>
+ *
+ * <ul>
+ *  <li><b>value</b>: Identifies a text value for a property.</li>
+ *  <li><b>location</b>: Identifies a file location for a property.</li>
+ *  <li><b>id</b>: Sets an id for a property</li>
+ *  <li><b>refid</b>: Sets a property to the value of another property
+ *       based upon the provided id</li>
+ *  <li><b>pathid</b>: Defines a path rather than a property with
+ *       the given id.</li>
+ * </ul>
+ *
+ * <p>For example, with keepRoot = false, the following properties file:</p>
+ *
+ * <pre>
+ * &lt;root-tag&gt;
+ *   &lt;build&gt;
+ *   &lt;build folder="build"&gt;
+ *     &lt;classes id="build.classes" location="${build.folder}/classes"/&gt;
+ *     &lt;reference refid="build.classes"/&gt;
+ *   &lt;/build&gt;
+ *   &lt;compile&gt;
+ *     &lt;classpath pathid="compile.classpath"&gt;
+ *       &lt;pathelement location="${build.classes}"/&gt;
+ *     &lt;/classpath&gt;
+ *   &lt;/compile&gt;
+ *   &lt;run-time&gt;
+ *     &lt;jars&gt;*.jar&lt;/jars&gt;
+ *     &lt;classpath pathid="run-time.classpath"&gt;
+ *       &lt;path refid="compile.classpath"/&gt;
+ *       &lt;pathelement path="${run-time.jars}"/&gt;
+ *     &lt;/classpath&gt;
+ *   &lt;/run-time&gt;
+ * &lt;/root-tag&gt;
+ * </pre>
+ *
+ * <p>is equivalent to the following entries in a build file:</p>
+ *
+ * <pre>
+ * &lt;property name="build" location="build"/&gt;
+ * &lt;property name="build.classes" location="${build.location}/classes"/&gt;
+ * &lt;property name="build.reference" refid="build.classes"/&gt;
+ *
+ * &lt;property name="run-time.jars" value="*.jar/&gt;
+ *
+ * &lt;classpath id="compile.classpath"&gt;
+ *   &lt;pathelement location="${build.classes}"/&gt;
+ * &lt;/classpath&gt;
+ *
+ * &lt;classpath id="run-time.classpath"&gt;
+ *   &lt;path refid="compile.classpath"/&gt;
+ *   &lt;pathelement path="${run-time.jars}"/&gt;
+ * &lt;/classpath&gt;
+ * </pre>
+ *
+ * <p> This task <i>requires</i> the following attributes:</p>
+ *
+ * <ul>
+ * <li><b>file</b>: The name of the file to load.</li>
+ * </ul>
+ *
+ * <p>This task supports the following attributes:</p>
+ *
+ * <ul>
+ * <li><b>prefix</b>: Optionally specify a prefix applied to
+ *     all properties loaded.  Defaults to an empty string.</li>
+ * <li><b>keepRoot</b>: Indicate whether the root xml element
+ *     is kept as part of property name.  Defaults to true.</li>
+ * <li><b>validate</b>: Indicate whether the xml file is validated.
+ *     Defaults to false.</li>
+ * <li><b>collapseAttributes</b>: Indicate whether attributes are
+ *     stored in property names with parens or with period
+ *     delimiters.  Defaults to false, meaning properties
+ *     are stored with parens (i.e., foo(attr)).</li>
+ * <li><b>semanticAttributes</b>: Indicate whether attributes
+ *     named "location", "value", "refid" and "path"
+ *     are interpreted as ant properties.  Defaults
+ *     to false.</li>
+ * <li><b>rootDirectory</b>: Indicate the directory to use
+ *     as the root directory for resolving location
+ *     properties.  Defaults to the directory
+ *     of the project using the task.</li>
+ * <li><b>includeSemanticAttribute</b>: Indicate whether to include
+ *     the semantic attribute ("location" or "value") as
+ *     part of the property name.  Defaults to false.</li>
+ * </ul>
+ *
+ * @ant.task name="xmlproperty" category="xml"
+ */
+public class XmlProperty extends org.apache.tools.ant.Task {
+
+    private Resource src;
+    private String prefix = "";
+    private boolean keepRoot = true;
+    private boolean validate = false;
+    private boolean collapseAttributes = false;
+    private boolean semanticAttributes = false;
+    private boolean includeSemanticAttribute = false;
+    private File rootDirectory = null;
+    private Hashtable addedAttributes = new Hashtable();
+    private XMLCatalog xmlCatalog = new XMLCatalog();
+    private String delimiter = ",";
+
+    private static final String ID = "id";
+    private static final String REF_ID = "refid";
+    private static final String LOCATION = "location";
+    private static final String VALUE = "value";
+    private static final String PATH = "path";
+    private static final String PATHID = "pathid";
+    private static final String[] ATTRIBUTES = new String[] {
+            ID, REF_ID, LOCATION, VALUE, PATH, PATHID
+    };
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Constructor.
+     */
+    public XmlProperty() {
+        super();
+    }
+
+    /**
+     * Initializes the task.
+     */
+
+    public void init() {
+        super.init();
+        xmlCatalog.setProject(getProject());
+    }
+
+    /**
+     * @return the xmlCatalog as the entityresolver.
+     */
+    protected EntityResolver getEntityResolver() {
+        return xmlCatalog;
+    }
+
+    /**
+     * Run the task.
+     * @throws BuildException The exception raised during task execution.
+     * @todo validate the source file is valid before opening, print a better error message
+     * @todo add a verbose level log message listing the name of the file being loaded
+     */
+    public void execute() throws BuildException {
+        Resource r = getResource();
+
+        if (r == null) {
+            throw new BuildException("XmlProperty task requires a source resource");
+        }
+        try {
+            log("Loading " + src, Project.MSG_VERBOSE);
+
+            if (r.isExists()) {
+
+              DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+              factory.setValidating(validate);
+              factory.setNamespaceAware(false);
+              DocumentBuilder builder = factory.newDocumentBuilder();
+              builder.setEntityResolver(getEntityResolver());
+              Document document = null;
+              if (src instanceof FileResource) {
+                  document = builder.parse(((FileResource) src).getFile());
+              } else {
+                  document = builder.parse(src.getInputStream());
+              }
+              Element topElement = document.getDocumentElement();
+
+              // Keep a hashtable of attributes added by this task.
+              // This task is allow to override its own properties
+              // but not other properties.  So we need to keep track
+              // of which properties we've added.
+              addedAttributes = new Hashtable();
+
+              if (keepRoot) {
+                  addNodeRecursively(topElement, prefix, null);
+              } else {
+                  NodeList topChildren = topElement.getChildNodes();
+                  int numChildren = topChildren.getLength();
+                  for (int i = 0; i < numChildren; i++) {
+                    addNodeRecursively(topChildren.item(i), prefix, null);
+                  }
+              }
+            } else {
+                log("Unable to find property resource: " + r, Project.MSG_VERBOSE);
+            }
+
+        } catch (SAXException sxe) {
+            // Error generated during parsing
+            Exception x = sxe;
+            if (sxe.getException() != null) {
+                x = sxe.getException();
+            }
+            throw new BuildException("Failed to load " + src, x);
+        } catch (ParserConfigurationException pce) {
+            // Parser with specified options can't be built
+            throw new BuildException(pce);
+        } catch (IOException ioe) {
+            // I/O error
+            throw new BuildException("Failed to load " + src, ioe);
+        }
+    }
+
+    /** Iterate through all nodes in the tree. */
+    private void addNodeRecursively(Node node, String prefix, Object container) {
+        // Set the prefix for this node to include its tag name.
+        String nodePrefix = prefix;
+        if (node.getNodeType() != Node.TEXT_NODE) {
+            if (prefix.trim().length() > 0) {
+                nodePrefix += ".";
+            }
+            nodePrefix += node.getNodeName();
+        }
+        // Pass the container to the processing of this node,
+        Object nodeObject = processNode(node, nodePrefix, container);
+
+        // now, iterate through children.
+        if (node.hasChildNodes()) {
+            NodeList nodeChildren = node.getChildNodes();
+            int numChildren = nodeChildren.getLength();
+
+            for (int i = 0; i < numChildren; i++) {
+                // For each child, pass the object added by
+                // processNode to its children -- in other word, each
+                // object can pass information along to its children.
+                addNodeRecursively(nodeChildren.item(i), nodePrefix, nodeObject);
+            }
+        }
+    }
+
+    void addNodeRecursively(org.w3c.dom.Node node, String prefix) {
+        addNodeRecursively(node, prefix, null);
+    }
+
+    /**
+     * Process the given node, adding any required attributes from
+     * this child node alone -- but <em>not</em> processing any
+     * children.
+     *
+     * @param node the XML Node to parse
+     * @param prefix A string to prepend to any properties that get
+     * added by this node.
+     * @param container Optionally, an object that a parent node
+     * generated that this node might belong to.  For example, this
+     * node could be within a node that generated a Path.
+     * @return the Object created by this node.  Generally, this is
+     * either a String if this node resulted in setting an attribute,
+     * or a Path.
+     */
+    public Object processNode (Node node, String prefix, Object container) {
+
+        // Parse the attribute(s) and text of this node, adding
+        // properties for each.
+        // if the "path" attribute is specified, then return the created path
+        // which will be passed to the children of this node.
+        Object addedPath = null;
+
+        // The value of an id attribute of this node.
+        String id = null;
+
+        if (node.hasAttributes()) {
+
+            NamedNodeMap nodeAttributes = node.getAttributes();
+
+            // Is there an id attribute?
+            Node idNode = nodeAttributes.getNamedItem(ID);
+            id = semanticAttributes && idNode != null ? idNode.getNodeValue() : null;
+
+            // Now, iterate through the attributes adding them.
+            for (int i = 0; i < nodeAttributes.getLength(); i++) {
+
+                Node attributeNode = nodeAttributes.item(i);
+
+                if (!semanticAttributes) {
+                    String attributeName = getAttributeName(attributeNode);
+                    String attributeValue = getAttributeValue(attributeNode);
+                    addProperty(prefix + attributeName, attributeValue, null);
+                } else {
+                    String nodeName = attributeNode.getNodeName();
+                    String attributeValue = getAttributeValue(attributeNode);
+
+                    Path containingPath =
+                        ((container != null) && (container instanceof Path))
+                        ? (Path) container
+                        : null;
+                    /*
+                     * The main conditional logic -- if the attribute
+                     * is somehow "special" (i.e., it has known
+                     * semantic meaning) then deal with it
+                     * appropriately.
+                     */
+                    if (nodeName.equals(ID)) {
+                        // ID has already been found above.
+                        continue;
+                    }
+                    if (containingPath != null && nodeName.equals(PATH)) {
+                        // A "path" attribute for a node within a Path object.
+                        containingPath.setPath(attributeValue);
+                    } else if (container instanceof Path && nodeName.equals(REF_ID)) {
+                        // A "refid" attribute for a node within a Path object.
+                        containingPath.setPath(attributeValue);
+                    } else if (container instanceof Path && nodeName.equals(LOCATION)) {
+                        // A "location" attribute for a node within a
+                        // Path object.
+                        containingPath.setLocation(resolveFile(attributeValue));
+                    } else if (nodeName.equals(PATHID)) {
+                        // A node identifying a new path
+                        if (container != null) {
+                            throw new BuildException("XmlProperty does not support nested paths");
+                        }
+                        addedPath = new Path(getProject());
+                        getProject().addReference(attributeValue, addedPath);
+                    } else {
+                        // An arbitrary attribute.
+                        String attributeName = getAttributeName(attributeNode);
+                        addProperty(prefix + attributeName, attributeValue, id);
+                    }
+                }
+            }
+        }
+        String nodeText = null;
+        boolean emptyNode = false;
+        boolean semanticEmptyOverride = false;
+        if (node.getNodeType() == Node.ELEMENT_NODE
+                && semanticAttributes
+                && node.hasAttributes()
+                && (node.getAttributes().getNamedItem(VALUE) != null
+                        || node.getAttributes().getNamedItem(LOCATION) != null
+                        || node.getAttributes().getNamedItem(REF_ID) != null
+                        || node.getAttributes().getNamedItem(PATH) != null || node.getAttributes()
+                        .getNamedItem(PATHID) != null)) {
+            semanticEmptyOverride = true;
+        }
+        if (node.getNodeType() == Node.TEXT_NODE) {
+            // For the text node, add a property.
+            nodeText = getAttributeValue(node);
+        } else if (node.getNodeType() == Node.ELEMENT_NODE
+                && node.getChildNodes().getLength() == 1
+                && node.getFirstChild().getNodeType() == Node.CDATA_SECTION_NODE) {
+
+            nodeText = node.getFirstChild().getNodeValue();
+            if ("".equals(nodeText) && !semanticEmptyOverride) {
+                emptyNode = true;
+            }
+        } else if (node.getNodeType() == Node.ELEMENT_NODE
+               && node.getChildNodes().getLength() == 0
+               && !semanticEmptyOverride) {
+            nodeText = "";
+            emptyNode = true;
+        } else if (node.getNodeType() == Node.ELEMENT_NODE
+               && node.getChildNodes().getLength() == 1
+               && node.getFirstChild().getNodeType() == Node.TEXT_NODE
+               && "".equals(node.getFirstChild().getNodeValue())
+               && !semanticEmptyOverride) {
+            nodeText = "";
+            emptyNode = true;
+        }
+        if (nodeText != null) {
+            // If the containing object was a String, then use it as the ID.
+            if (semanticAttributes && id == null && container instanceof String) {
+                id = (String) container;
+            }
+            if (nodeText.trim().length() != 0 || emptyNode) {
+                addProperty(prefix, nodeText, id);
+            }
+        }
+        // Return the Path we added or the ID of this node for
+        // children to reference if needed.  Path objects are
+        // definitely used by child path elements, and ID may be used
+        // for a child text node.
+        return (addedPath != null ? addedPath : id);
+    }
+
+    /**
+     * Actually add the given property/value to the project
+     * after writing a log message.
+     */
+    private void addProperty (String name, String value, String id) {
+        String msg = name + ":" + value;
+        if (id != null) {
+            msg += ("(id=" + id + ")");
+        }
+        log(msg, Project.MSG_DEBUG);
+
+        if (addedAttributes.containsKey(name)) {
+            // If this attribute was added by this task, then
+            // we append this value to the existing value.
+            // We use the setProperty method which will
+            // forcibly override the property if it already exists.
+            // We need to put these properties into the project
+            // when we read them, though (instead of keeping them
+            // outside of the project and batch adding them at the end)
+            // to allow other properties to reference them.
+            value = (String) addedAttributes.get(name) + getDelimiter() + value;
+            getProject().setProperty(name, value);
+            addedAttributes.put(name, value);
+        } else if (getProject().getProperty(name) == null) {
+            getProject().setNewProperty(name, value);
+            addedAttributes.put(name, value);
+        } else {
+            log("Override ignored for property " + name, Project.MSG_VERBOSE);
+        }
+        if (id != null) {
+            getProject().addReference(id, value);
+        }
+    }
+
+    /**
+     * Return a reasonable attribute name for the given node.
+     * If we are using semantic attributes or collapsing
+     * attributes, the returned name is ".nodename".
+     * Otherwise, we return "(nodename)".  This is long-standing
+     * (and default) &lt;xmlproperty&gt; behavior.
+     */
+    private String getAttributeName (Node attributeNode) {
+        String attributeName = attributeNode.getNodeName();
+
+        if (semanticAttributes) {
+            // Never include the "refid" attribute as part of the
+            // attribute name.
+            if (attributeName.equals(REF_ID)) {
+                return "";
+            }
+            // Otherwise, return it appended unless property to hide it is set.
+            if (!isSemanticAttribute(attributeName) || includeSemanticAttribute) {
+                return "." + attributeName;
+            }
+            return "";
+        }
+        return collapseAttributes ? "." + attributeName : "(" + attributeName + ")";
+    }
+
+    /**
+     * Return whether the provided attribute name is recognized or not.
+     */
+    private static boolean isSemanticAttribute (String attributeName) {
+        for (int i = 0; i < ATTRIBUTES.length; i++) {
+            if (attributeName.equals(ATTRIBUTES[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return the value for the given attribute.
+     * If we are not using semantic attributes, its just the
+     * literal string value of the attribute.
+     *
+     * <p>If we <em>are</em> using semantic attributes, then first
+     * dependent properties are resolved (i.e., ${foo} is resolved
+     * based on the foo property value), and then an appropriate data
+     * type is used.  In particular, location-based properties are
+     * resolved to absolute file names.  Also for refid values, look
+     * up the referenced object from the project.</p>
+     */
+    private String getAttributeValue (Node attributeNode) {
+        String nodeValue = attributeNode.getNodeValue().trim();
+        if (semanticAttributes) {
+            String attributeName = attributeNode.getNodeName();
+            nodeValue = getProject().replaceProperties(nodeValue);
+            if (attributeName.equals(LOCATION)) {
+                File f = resolveFile(nodeValue);
+                return f.getPath();
+            }
+            if (attributeName.equals(REF_ID)) {
+                Object ref = getProject().getReference(nodeValue);
+                if (ref != null) {
+                    return ref.toString();
+                }
+            }
+        }
+        return nodeValue;
+    }
+
+    /**
+     * The XML file to parse; required.
+     * @param src the file to parse
+     */
+    public void setFile(File src) {
+        setSrcResource(new FileResource(src));
+    }
+
+    /**
+     * The resource to pack; required.
+     * @param src resource to expand
+     */
+    public void setSrcResource(Resource src) {
+        if (src.isDirectory()) {
+            throw new BuildException("the source can't be a directory");
+        }
+        if (src instanceof FileResource && !supportsNonFileResources()) {
+            throw new BuildException("Only FileSystem resources are supported.");
+        }
+        this.src = src;
+    }
+
+    /**
+     * Set the source resource.
+     * @param a the resource to pack as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        if (a.size() != 1) {
+            throw new BuildException(
+                    "only single argument resource collections are supported as archives");
+        }
+        setSrcResource((Resource) a.iterator().next());
+    }
+
+    /**
+     * the prefix to prepend to each property
+     * @param prefix the prefix to prepend to each property
+     */
+    public void setPrefix(String prefix) {
+        this.prefix = prefix.trim();
+    }
+
+    /**
+     * flag to include the xml root tag as a
+     * first value in the property name; optional,
+     * default is true
+     * @param keepRoot if true (default), include the xml root tag
+     */
+    public void setKeeproot(boolean keepRoot) {
+        this.keepRoot = keepRoot;
+    }
+
+    /**
+     * flag to validate the XML file; optional, default false
+     * @param validate if true validate the XML file, default false
+     */
+    public void setValidate(boolean validate) {
+        this.validate = validate;
+    }
+
+    /**
+     * flag to treat attributes as nested elements;
+     * optional, default false
+     * @param collapseAttributes if true treat attributes as nested elements
+     */
+    public void setCollapseAttributes(boolean collapseAttributes) {
+        this.collapseAttributes = collapseAttributes;
+    }
+
+    /**
+     * Attribute to enable special handling of attributes - see ant manual.
+     * @param semanticAttributes if true enable the special handling.
+     */
+    public void setSemanticAttributes(boolean semanticAttributes) {
+        this.semanticAttributes = semanticAttributes;
+    }
+
+    /**
+     * The directory to use for resolving file references.
+     * Ignored if semanticAttributes is not set to true.
+     * @param rootDirectory the directory.
+     */
+    public void setRootDirectory(File rootDirectory) {
+        this.rootDirectory = rootDirectory;
+    }
+
+    /**
+     * Include the semantic attribute name as part of the property name.
+     * Ignored if semanticAttributes is not set to true.
+     * @param includeSemanticAttribute if true include the sematic attribute
+     *                                 name.
+     */
+    public void setIncludeSemanticAttribute(boolean includeSemanticAttribute) {
+        this.includeSemanticAttribute = includeSemanticAttribute;
+    }
+
+    /**
+     * add an XMLCatalog as a nested element; optional.
+     * @param catalog the XMLCatalog to use
+     */
+    public void addConfiguredXMLCatalog(XMLCatalog catalog) {
+        xmlCatalog.addConfiguredXMLCatalog(catalog);
+    }
+
+    /* Expose members for extensibility */
+
+    /**
+     * @return the file attribute.
+     */
+    protected File getFile () {
+        return src instanceof FileResource ? ((FileResource) src).getFile() : null;
+    }
+
+    /**
+     * @return the resource.
+     */
+    protected Resource getResource() {
+        // delegate this way around to support subclasses that
+        // overwrite getFile
+        File f = getFile();
+        return f == null ? src : src instanceof FileResource
+                && ((FileResource) src).getFile().equals(f) ? src : new FileResource(f);
+    }
+
+    /**
+     * @return the prefix attribute.
+     */
+    protected String getPrefix () {
+        return this.prefix;
+    }
+
+    /**
+     * @return the keeproot attribute.
+     */
+    protected boolean getKeeproot () {
+        return this.keepRoot;
+    }
+
+    /**
+     * @return the validate attribute.
+     */
+    protected boolean getValidate () {
+        return this.validate;
+    }
+
+    /**
+     * @return the collapse attributes attribute.
+     */
+    protected boolean getCollapseAttributes () {
+        return this.collapseAttributes;
+    }
+
+    /**
+     * @return the semantic attributes attribute.
+     */
+    protected boolean getSemanticAttributes () {
+        return this.semanticAttributes;
+    }
+
+    /**
+     * @return the root directory attribute.
+     */
+    protected File getRootDirectory () {
+        return this.rootDirectory;
+    }
+
+    /**
+     * @return the include semantic attribute.
+     */
+    protected boolean getIncludeSementicAttribute () {
+        return this.includeSemanticAttribute;
+    }
+
+    /**
+     * Let project resolve the file - or do it ourselves if
+     * rootDirectory has been set.
+     */
+    private File resolveFile(String fileName) {
+        return FILE_UTILS.resolveFile(rootDirectory == null ? getProject().getBaseDir()
+                : rootDirectory, fileName);
+    }
+
+    /**
+     * Whether this task can deal with non-file resources.
+     *
+     * <p>This implementation returns true only if this task is
+     * &lt;xmlproperty&gt;.  Any subclass of this class that also wants to
+     * support non-file resources needs to override this method.  We
+     * need to do so for backwards compatibility reasons since we
+     * can't expect subclasses to support resources.</p>
+     * @return true for this task.
+     * @since Ant 1.7
+     */
+    protected boolean supportsNonFileResources() {
+        return getClass().equals(XmlProperty.class);
+    }
+
+    /**
+     * Get the current delimiter.
+     * @return delimiter
+     */
+    public String getDelimiter() {
+        return delimiter;
+    }
+
+    /**
+     * Sets a new delimiter.
+     * @param delimiter new value
+     * @since Ant 1.7.1
+     */
+    public void setDelimiter(String delimiter) {
+        this.delimiter = delimiter;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java b/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java
new file mode 100644
index 0000000..8e04932
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/Zip.java
@@ -0,0 +1,1756 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.zip.CRC32;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.FileScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.ArchiveFileSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.ZipFileSet;
+import org.apache.tools.ant.types.ZipScanner;
+import org.apache.tools.ant.types.resources.ArchiveResource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.GlobPatternMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.MergingMapper;
+import org.apache.tools.ant.util.ResourceUtils;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipExtraField;
+import org.apache.tools.zip.ZipFile;
+import org.apache.tools.zip.ZipOutputStream;
+
+/**
+ * Create a Zip file.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="packaging"
+ */
+public class Zip extends MatchingTask {
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final int ROUNDUP_MILLIS = 1999; // 2 seconds - 1
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    protected File zipFile;
+    // use to scan own archive
+    private ZipScanner zs;
+    private File baseDir;
+    protected Hashtable entries = new Hashtable();
+    private Vector groupfilesets = new Vector();
+    private Vector filesetsFromGroupfilesets = new Vector();
+    protected String duplicate = "add";
+    private boolean doCompress = true;
+    private boolean doUpdate = false;
+    // shadow of the above if the value is altered in execute
+    private boolean savedDoUpdate = false;
+    private boolean doFilesonly = false;
+    protected String archiveType = "zip";
+
+    // For directories:
+    private static final long EMPTY_CRC = new CRC32 ().getValue ();
+    protected String emptyBehavior = "skip";
+    private Vector resources = new Vector();
+    protected Hashtable addedDirs = new Hashtable();
+    private Vector addedFiles = new Vector();
+
+    protected boolean doubleFilePass = false;
+    protected boolean skipWriting = false;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    // CheckStyle:VisibilityModifier ON
+
+    // This boolean is set if the task detects that the
+    // target is outofdate and has written to the target file.
+    private boolean updatedFile = false;
+
+    /**
+     * true when we are adding new files into the Zip file, as opposed
+     * to adding back the unchanged files
+     */
+    private boolean addingNewFiles = false;
+
+    /**
+     * Encoding to use for filenames, defaults to the platform's
+     * default encoding.
+     */
+    private String encoding;
+
+    /**
+     * Whether the original compression of entries coming from a ZIP
+     * archive should be kept (for example when updating an archive).
+     *
+     * @since Ant 1.6
+     */
+    private boolean keepCompression = false;
+
+    /**
+     * Whether the file modification times will be rounded up to the
+     * next even number of seconds.
+     *
+     * @since Ant 1.6.2
+     */
+    private boolean roundUp = true;
+
+    /**
+     * Comment for the archive.
+     * @since Ant 1.6.3
+     */
+    private String comment = "";
+
+    private int level = ZipOutputStream.DEFAULT_COMPRESSION;
+
+    /**
+     * This is the name/location of where to
+     * create the .zip file.
+     * @param zipFile the path of the zipFile
+     * @deprecated since 1.5.x.
+     *             Use setDestFile(File) instead.
+     * @ant.attribute ignore="true"
+     */
+    public void setZipfile(File zipFile) {
+        setDestFile(zipFile);
+    }
+
+    /**
+     * This is the name/location of where to
+     * create the file.
+     * @param file the path of the zipFile
+     * @since Ant 1.5
+     * @deprecated since 1.5.x.
+     *             Use setDestFile(File) instead.
+     * @ant.attribute ignore="true"
+     */
+    public void setFile(File file) {
+        setDestFile(file);
+    }
+
+
+    /**
+     * The file to create; required.
+     * @since Ant 1.5
+     * @param destFile The new destination File
+     */
+    public void setDestFile(File destFile) {
+       this.zipFile = destFile;
+    }
+
+    /**
+     * The file to create.
+     * @return the destination file
+     * @since Ant 1.5.2
+     */
+    public File getDestFile() {
+        return zipFile;
+    }
+
+
+    /**
+     * Directory from which to archive files; optional.
+     * @param baseDir the base directory
+     */
+    public void setBasedir(File baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * Whether we want to compress the files or only store them;
+     * optional, default=true;
+     * @param c if true, compress the files
+     */
+    public void setCompress(boolean c) {
+        doCompress = c;
+    }
+
+    /**
+     * Whether we want to compress the files or only store them;
+     * @return true if the files are to be compressed
+     * @since Ant 1.5.2
+     */
+    public boolean isCompress() {
+        return doCompress;
+    }
+
+    /**
+     * If true, emulate Sun's jar utility by not adding parent directories;
+     * optional, defaults to false.
+     * @param f if true, emulate sun's jar by not adding parent directories
+     */
+    public void setFilesonly(boolean f) {
+        doFilesonly = f;
+    }
+
+    /**
+     * If true, updates an existing file, otherwise overwrite
+     * any existing one; optional defaults to false.
+     * @param c if true, updates an existing zip file
+     */
+    public void setUpdate(boolean c) {
+        doUpdate = c;
+        savedDoUpdate = c;
+    }
+
+    /**
+     * Are we updating an existing archive?
+     * @return true if updating an existing archive
+     */
+    public boolean isInUpdateMode() {
+        return doUpdate;
+    }
+
+    /**
+     * Adds a set of files.
+     * @param set the fileset to add
+     */
+    public void addFileset(FileSet set) {
+        add(set);
+    }
+
+    /**
+     * Adds a set of files that can be
+     * read from an archive and be given a prefix/fullpath.
+     * @param set the zipfileset to add
+     */
+    public void addZipfileset(ZipFileSet set) {
+        add(set);
+    }
+
+    /**
+     * Add a collection of resources to be archived.
+     * @param a the resources to archive
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection a) {
+        resources.add(a);
+    }
+
+    /**
+     * Adds a group of zip files.
+     * @param set the group (a fileset) to add
+     */
+    public void addZipGroupFileset(FileSet set) {
+        groupfilesets.addElement(set);
+    }
+
+    /**
+     * Sets behavior for when a duplicate file is about to be added -
+     * one of <code>add</code>, <code>preserve</code> or <code>fail</code>.
+     * Possible values are: <code>add</code> (keep both
+     * of the files); <code>preserve</code> (keep the first version
+     * of the file found); <code>fail</code> halt a problem
+     * Default for zip tasks is <code>add</code>
+     * @param df a <code>Duplicate</code> enumerated value
+     */
+    public void setDuplicate(Duplicate df) {
+        duplicate = df.getValue();
+    }
+
+    /**
+     * Possible behaviors when there are no matching files for the task:
+     * "fail", "skip", or "create".
+     */
+    public static class WhenEmpty extends EnumeratedAttribute {
+        /**
+         * The string values for the enumerated value
+         * @return the values
+         */
+        public String[] getValues() {
+            return new String[] {"fail", "skip", "create"};
+        }
+    }
+
+    /**
+     * Sets behavior of the task when no files match.
+     * Possible values are: <code>fail</code> (throw an exception
+     * and halt the build); <code>skip</code> (do not create
+     * any archive, but issue a warning); <code>create</code>
+     * (make an archive with no entries).
+     * Default for zip tasks is <code>skip</code>;
+     * for jar tasks, <code>create</code>.
+     * @param we a <code>WhenEmpty</code> enumerated value
+     */
+    public void setWhenempty(WhenEmpty we) {
+        emptyBehavior = we.getValue();
+    }
+
+    /**
+     * Encoding to use for filenames, defaults to the platform's
+     * default encoding.
+     *
+     * <p>For a list of possible values see <a
+     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.</p>
+     * @param encoding the encoding name
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Encoding to use for filenames.
+     * @return the name of the encoding to use
+     * @since Ant 1.5.2
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Whether the original compression of entries coming from a ZIP
+     * archive should be kept (for example when updating an archive).
+     * Default is false.
+     * @param keep if true, keep the original compression
+     * @since Ant 1.6
+     */
+    public void setKeepCompression(boolean keep) {
+        keepCompression = keep;
+    }
+
+    /**
+     * Comment to use for archive.
+     *
+     * @param comment The content of the comment.
+     * @since Ant 1.6.3
+     */
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    /**
+     * Comment of the archive
+     *
+     * @return Comment of the archive.
+     * @since Ant 1.6.3
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Set the compression level to use.  Default is
+     * ZipOutputStream.DEFAULT_COMPRESSION.
+     * @param level compression level.
+     * @since Ant 1.7
+     */
+    public void setLevel(int level) {
+        this.level = level;
+    }
+
+    /**
+     * Get the compression level.
+     * @return compression level.
+     * @since Ant 1.7
+     */
+    public int getLevel() {
+        return level;
+    }
+
+    /**
+     * Whether the file modification times will be rounded up to the
+     * next even number of seconds.
+     *
+     * <p>Zip archives store file modification times with a
+     * granularity of two seconds, so the times will either be rounded
+     * up or down.  If you round down, the archive will always seem
+     * out-of-date when you rerun the task, so the default is to round
+     * up.  Rounding up may lead to a different type of problems like
+     * JSPs inside a web archive that seem to be slightly more recent
+     * than precompiled pages, rendering precompilation useless.</p>
+     * @param r a <code>boolean</code> value
+     * @since Ant 1.6.2
+     */
+    public void setRoundUp(boolean r) {
+        roundUp = r;
+    }
+
+    /**
+     * validate and build
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+
+        if (doubleFilePass) {
+            skipWriting = true;
+            executeMain();
+            skipWriting = false;
+            executeMain();
+        } else {
+            executeMain();
+        }
+    }
+
+    /**
+     * Get the value of the updatedFile attribute.
+     * This should only be called after executeMain has been
+     * called.
+     * @return true if executeMain has written to the zip file.
+     */
+    protected boolean hasUpdatedFile() {
+        return updatedFile;
+    }
+
+    /**
+     * Build the zip file.
+     * This is called twice if doubleFilePass is true.
+     * @throws BuildException on error
+     */
+    public void executeMain() throws BuildException {
+
+        checkAttributesAndElements();
+
+        // Renamed version of original file, if it exists
+        File renamedFile = null;
+        addingNewFiles = true;
+
+        processDoUpdate();
+        processGroupFilesets();
+
+        // collect filesets to pass them to getResourcesToAdd
+        Vector vfss = new Vector();
+        if (baseDir != null) {
+            FileSet fs = (FileSet) getImplicitFileSet().clone();
+            fs.setDir(baseDir);
+            vfss.addElement(fs);
+        }
+        for (int i = 0; i < resources.size(); i++) {
+            ResourceCollection rc = (ResourceCollection) resources.elementAt(i);
+            vfss.addElement(rc);
+        }
+
+        ResourceCollection[] fss = new ResourceCollection[vfss.size()];
+        vfss.copyInto(fss);
+        boolean success = false;
+        try {
+            // can also handle empty archives
+            ArchiveState state = getResourcesToAdd(fss, zipFile, false);
+
+            // quick exit if the target is up to date
+            if (!state.isOutOfDate()) {
+                return;
+            }
+            updatedFile = true;
+            if (!zipFile.exists() && state.isWithoutAnyResources()) {
+                createEmptyZip(zipFile);
+                return;
+            }
+            Resource[][] addThem = state.getResourcesToAdd();
+
+            if (doUpdate) {
+                renamedFile = renameFile();
+            }
+
+            String action = doUpdate ? "Updating " : "Building ";
+
+            log(action + archiveType + ": " + zipFile.getAbsolutePath());
+
+            ZipOutputStream zOut = null;
+            try {
+                if (!skipWriting) {
+                    zOut = new ZipOutputStream(zipFile);
+
+                    zOut.setEncoding(encoding);
+                    zOut.setMethod(doCompress
+                        ? ZipOutputStream.DEFLATED : ZipOutputStream.STORED);
+                    zOut.setLevel(level);
+                }
+                initZipOutputStream(zOut);
+
+                // Add the explicit resource collections to the archive.
+                for (int i = 0; i < fss.length; i++) {
+                    if (addThem[i].length != 0) {
+                        addResources(fss[i], addThem[i], zOut);
+                    }
+                }
+
+                if (doUpdate) {
+                    addingNewFiles = false;
+                    ZipFileSet oldFiles = new ZipFileSet();
+                    oldFiles.setProject(getProject());
+                    oldFiles.setSrc(renamedFile);
+                    oldFiles.setDefaultexcludes(false);
+
+                    for (int i = 0; i < addedFiles.size(); i++) {
+                        PatternSet.NameEntry ne = oldFiles.createExclude();
+                        ne.setName((String) addedFiles.elementAt(i));
+                    }
+                    DirectoryScanner ds =
+                        oldFiles.getDirectoryScanner(getProject());
+                    ((ZipScanner) ds).setEncoding(encoding);
+
+                    String[] f = ds.getIncludedFiles();
+                    Resource[] r = new Resource[f.length];
+                    for (int i = 0; i < f.length; i++) {
+                        r[i] = ds.getResource(f[i]);
+                    }
+
+                    if (!doFilesonly) {
+                        String[] d = ds.getIncludedDirectories();
+                        Resource[] dr = new Resource[d.length];
+                        for (int i = 0; i < d.length; i++) {
+                            dr[i] = ds.getResource(d[i]);
+                        }
+                        Resource[] tmp = r;
+                        r = new Resource[tmp.length + dr.length];
+                        System.arraycopy(dr, 0, r, 0, dr.length);
+                        System.arraycopy(tmp, 0, r, dr.length, tmp.length);
+                    }
+                    addResources(oldFiles, r, zOut);
+                }
+                if (zOut != null) {
+                    zOut.setComment(comment);
+                }
+                finalizeZipOutputStream(zOut);
+
+                // If we've been successful on an update, delete the
+                // temporary file
+                if (doUpdate) {
+                    if (!renamedFile.delete()) {
+                        log ("Warning: unable to delete temporary file "
+                            + renamedFile.getName(), Project.MSG_WARN);
+                    }
+                }
+                success = true;
+            } finally {
+                // Close the output stream.
+                closeZout(zOut, success);
+            }
+        } catch (IOException ioe) {
+            String msg = "Problem creating " + archiveType + ": "
+                + ioe.getMessage();
+
+            // delete a bogus ZIP file (but only if it's not the original one)
+            if ((!doUpdate || renamedFile != null) && !zipFile.delete()) {
+                msg += " (and the archive is probably corrupt but I could not "
+                    + "delete it)";
+            }
+
+            if (doUpdate && renamedFile != null) {
+                try {
+                    FILE_UTILS.rename(renamedFile, zipFile);
+                } catch (IOException e) {
+                    msg += " (and I couldn't rename the temporary file "
+                            + renamedFile.getName() + " back)";
+                }
+            }
+
+            throw new BuildException(msg, ioe, getLocation());
+        } finally {
+            cleanUp();
+        }
+    }
+
+    /** rename the zip file. */
+    private File renameFile() {
+        File renamedFile = FILE_UTILS.createTempFile(
+            "zip", ".tmp", zipFile.getParentFile(), true, false);
+        try {
+            FILE_UTILS.rename(zipFile, renamedFile);
+        } catch (SecurityException e) {
+            throw new BuildException(
+                "Not allowed to rename old file ("
+                + zipFile.getAbsolutePath()
+                + ") to temporary file");
+        } catch (IOException e) {
+            throw new BuildException(
+                "Unable to rename old file ("
+                + zipFile.getAbsolutePath()
+                + ") to temporary file");
+        }
+        return renamedFile;
+    }
+
+    /** Close zout */
+    private void closeZout(ZipOutputStream zOut, boolean success)
+        throws IOException {
+        if (zOut == null) {
+            return;
+        }
+        try {
+            zOut.close();
+        } catch (IOException ex) {
+            // If we're in this finally clause because of an
+            // exception, we don't really care if there's an
+            // exception when closing the stream. E.g. if it
+            // throws "ZIP file must have at least one entry",
+            // because an exception happened before we added
+            // any files, then we must swallow this
+            // exception. Otherwise, the error that's reported
+            // will be the close() error, which is not the
+            // real cause of the problem.
+            if (success) {
+                throw ex;
+            }
+        }
+    }
+
+    /** Check the attributes and elements */
+    private void checkAttributesAndElements() {
+        if (baseDir == null && resources.size() == 0
+            && groupfilesets.size() == 0 && "zip".equals(archiveType)) {
+            throw new BuildException("basedir attribute must be set, "
+                                     + "or at least one "
+                                     + "resource collection must be given!");
+        }
+
+        if (zipFile == null) {
+            throw new BuildException("You must specify the "
+                                     + archiveType + " file to create!");
+        }
+
+        if (zipFile.exists() && !zipFile.isFile()) {
+            throw new BuildException(zipFile + " is not a file.");
+        }
+
+        if (zipFile.exists() && !zipFile.canWrite()) {
+            throw new BuildException(zipFile + " is read-only.");
+        }
+    }
+
+    /** Process doupdate */
+    private void processDoUpdate() {
+        // Whether or not an actual update is required -
+        // we don't need to update if the original file doesn't exist
+        if (doUpdate && !zipFile.exists()) {
+            doUpdate = false;
+            log("ignoring update attribute as " + archiveType
+                + " doesn't exist.", Project.MSG_DEBUG);
+        }
+    }
+
+    /** Process groupfilesets */
+    private void processGroupFilesets() {
+        // Add the files found in groupfileset to fileset
+        for (int i = 0; i < groupfilesets.size(); i++) {
+
+            log("Processing groupfileset ", Project.MSG_VERBOSE);
+            FileSet fs = (FileSet) groupfilesets.elementAt(i);
+            FileScanner scanner = fs.getDirectoryScanner(getProject());
+            String[] files = scanner.getIncludedFiles();
+            File basedir = scanner.getBasedir();
+            for (int j = 0; j < files.length; j++) {
+
+                log("Adding file " + files[j] + " to fileset",
+                    Project.MSG_VERBOSE);
+                ZipFileSet zf = new ZipFileSet();
+                zf.setProject(getProject());
+                zf.setSrc(new File(basedir, files[j]));
+                add(zf);
+                filesetsFromGroupfilesets.addElement(zf);
+            }
+        }
+    }
+
+    /**
+     * Indicates if the task is adding new files into the archive as opposed to
+     * copying back unchanged files from the backup copy
+     * @return true if adding new files
+     */
+    protected final boolean isAddingNewFiles() {
+        return addingNewFiles;
+    }
+
+    /**
+     * Add the given resources.
+     *
+     * @param fileset may give additional information like fullpath or
+     * permissions.
+     * @param resources the resources to add
+     * @param zOut the stream to write to
+     * @throws IOException on error
+     *
+     * @since Ant 1.5.2
+     */
+    protected final void addResources(FileSet fileset, Resource[] resources,
+                                      ZipOutputStream zOut)
+        throws IOException {
+
+        String prefix = "";
+        String fullpath = "";
+        int dirMode = ArchiveFileSet.DEFAULT_DIR_MODE;
+        int fileMode = ArchiveFileSet.DEFAULT_FILE_MODE;
+
+        ArchiveFileSet zfs = null;
+        if (fileset instanceof ArchiveFileSet) {
+            zfs = (ArchiveFileSet) fileset;
+            prefix = zfs.getPrefix(getProject());
+            fullpath = zfs.getFullpath(getProject());
+            dirMode = zfs.getDirMode(getProject());
+            fileMode = zfs.getFileMode(getProject());
+        }
+
+        if (prefix.length() > 0 && fullpath.length() > 0) {
+            throw new BuildException("Both prefix and fullpath attributes must"
+                                     + " not be set on the same fileset.");
+        }
+
+        if (resources.length != 1 && fullpath.length() > 0) {
+            throw new BuildException("fullpath attribute may only be specified"
+                                     + " for filesets that specify a single"
+                                     + " file.");
+        }
+
+        if (prefix.length() > 0) {
+            if (!prefix.endsWith("/") && !prefix.endsWith("\\")) {
+                prefix += "/";
+            }
+            addParentDirs(null, prefix, zOut, "", dirMode);
+        }
+
+        ZipFile zf = null;
+        try {
+            boolean dealingWithFiles = false;
+            File base = null;
+
+            if (zfs == null || zfs.getSrc(getProject()) == null) {
+                dealingWithFiles = true;
+                base = fileset.getDir(getProject());
+            } else if (zfs instanceof ZipFileSet) {
+                zf = new ZipFile(zfs.getSrc(getProject()), encoding);
+            }
+
+            for (int i = 0; i < resources.length; i++) {
+                String name = null;
+                if (fullpath.length() > 0) {
+                    name = fullpath;
+                } else {
+                    name = resources[i].getName();
+                }
+                name = name.replace(File.separatorChar, '/');
+
+                if ("".equals(name)) {
+                    continue;
+                }
+                if (resources[i].isDirectory() && !name.endsWith("/")) {
+                    name = name + "/";
+                }
+
+                if (!doFilesonly && !dealingWithFiles
+                    && resources[i].isDirectory()
+                    && !zfs.hasDirModeBeenSet()) {
+                    int nextToLastSlash = name.lastIndexOf("/",
+                                                           name.length() - 2);
+                    if (nextToLastSlash != -1) {
+                        addParentDirs(base, name.substring(0,
+                                                           nextToLastSlash + 1),
+                                      zOut, prefix, dirMode);
+                    }
+                    if (zf != null) {
+                        ZipEntry ze = zf.getEntry(resources[i].getName());
+                        addParentDirs(base, name, zOut, prefix,
+                                      ze.getUnixMode());
+                    } else {
+                        ArchiveResource tr = (ArchiveResource) resources[i];
+                        addParentDirs(base, name, zOut, prefix,
+                                      tr.getMode());
+                    }
+
+                } else {
+                    addParentDirs(base, name, zOut, prefix, dirMode);
+                }
+
+                if (!resources[i].isDirectory() && dealingWithFiles) {
+                    File f = FILE_UTILS.resolveFile(base,
+                                                   resources[i].getName());
+                    zipFile(f, zOut, prefix + name, fileMode);
+                } else if (!resources[i].isDirectory()) {
+                    if (zf != null) {
+                    ZipEntry ze = zf.getEntry(resources[i].getName());
+
+                    if (ze != null) {
+                        boolean oldCompress = doCompress;
+                        if (keepCompression) {
+                            doCompress = (ze.getMethod() == ZipEntry.DEFLATED);
+                        }
+                        InputStream is = null;
+                        try {
+                            is = zf.getInputStream(ze);
+                            zipFile(is, zOut, prefix + name,
+                                    ze.getTime(), zfs.getSrc(getProject()),
+                                    zfs.hasFileModeBeenSet() ? fileMode
+                                    : ze.getUnixMode());
+                        } finally {
+                            doCompress = oldCompress;
+                            FileUtils.close(is);
+                        }
+                    }
+                    } else {
+                        ArchiveResource tr = (ArchiveResource) resources[i];
+                        InputStream is = null;
+                        try {
+                            is = tr.getInputStream();
+                            zipFile(is, zOut, prefix + name,
+                                    resources[i].getLastModified(),
+                                    zfs.getSrc(getProject()),
+                                    zfs.hasFileModeBeenSet() ? fileMode
+                                    : tr.getMode());
+                        } finally {
+                            FileUtils.close(is);
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (zf != null) {
+                zf.close();
+            }
+        }
+    }
+
+    /**
+     * Add the given resources.
+     *
+     * @param rc may give additional information like fullpath or
+     * permissions.
+     * @param resources the resources to add
+     * @param zOut the stream to write to
+     * @throws IOException on error
+     *
+     * @since Ant 1.7
+     */
+    protected final void addResources(ResourceCollection rc,
+                                      Resource[] resources,
+                                      ZipOutputStream zOut)
+        throws IOException {
+        if (rc instanceof FileSet) {
+            addResources((FileSet) rc, resources, zOut);
+            return;
+        }
+        for (int i = 0; i < resources.length; i++) {
+            String name = resources[i].getName().replace(File.separatorChar,
+                                                         '/');
+            if ("".equals(name)) {
+                continue;
+            }
+            if (resources[i].isDirectory() && doFilesonly) {
+                continue;
+            }
+            File base = null;
+            if (resources[i] instanceof FileResource) {
+                base = ((FileResource) resources[i]).getBaseDir();
+            }
+            if (resources[i].isDirectory()) {
+                if (!name.endsWith("/")) {
+                    name = name + "/";
+                }
+            }
+
+            addParentDirs(base, name, zOut, "",
+                          ArchiveFileSet.DEFAULT_DIR_MODE);
+
+            if (!resources[i].isDirectory()) {
+                if (resources[i] instanceof FileResource) {
+                    File f = ((FileResource) resources[i]).getFile();
+                    zipFile(f, zOut, name, ArchiveFileSet.DEFAULT_FILE_MODE);
+                } else {
+                    InputStream is = null;
+                    try {
+                        is = resources[i].getInputStream();
+                        zipFile(is, zOut, name,
+                                resources[i].getLastModified(),
+                                null, ArchiveFileSet.DEFAULT_FILE_MODE);
+                    } finally {
+                        FileUtils.close(is);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * method for subclasses to override
+     * @param zOut the zip output stream
+     * @throws IOException on output error
+     * @throws BuildException on other errors
+     */
+    protected void initZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+    }
+
+    /**
+     * method for subclasses to override
+     * @param zOut the zip output stream
+     * @throws IOException on output error
+     * @throws BuildException on other errors
+     */
+    protected void finalizeZipOutputStream(ZipOutputStream zOut)
+        throws IOException, BuildException {
+    }
+
+    /**
+     * Create an empty zip file
+     * @param zipFile the zip file
+     * @return true for historic reasons
+     * @throws BuildException on error
+     */
+    protected boolean createEmptyZip(File zipFile) throws BuildException {
+        // In this case using java.util.zip will not work
+        // because it does not permit a zero-entry archive.
+        // Must create it manually.
+        log("Note: creating empty " + archiveType + " archive " + zipFile,
+            Project.MSG_INFO);
+        OutputStream os = null;
+        try {
+            os = new FileOutputStream(zipFile);
+            // CheckStyle:MagicNumber OFF
+            // Cf. PKZIP specification.
+            byte[] empty = new byte[22];
+            empty[0] = 80; // P
+            empty[1] = 75; // K
+            empty[2] = 5;
+            empty[3] = 6;
+            // remainder zeros
+            // CheckStyle:MagicNumber ON
+            os.write(empty);
+        } catch (IOException ioe) {
+            throw new BuildException("Could not create empty ZIP archive "
+                                     + "(" + ioe.getMessage() + ")", ioe,
+                                     getLocation());
+        } finally {
+            FileUtils.close(os);
+        }
+        return true;
+    }
+
+    /**
+     * @since Ant 1.5.2
+     */
+    private synchronized ZipScanner getZipScanner() {
+        if (zs == null) {
+            zs = new ZipScanner();
+            zs.setEncoding(encoding);
+            zs.setSrc(zipFile);
+        }
+        return zs;
+    }
+
+    /**
+     * Collect the resources that are newer than the corresponding
+     * entries (or missing) in the original archive.
+     *
+     * <p>If we are going to recreate the archive instead of updating
+     * it, all resources should be considered as new, if a single one
+     * is.  Because of this, subclasses overriding this method must
+     * call <code>super.getResourcesToAdd</code> and indicate with the
+     * third arg if they already know that the archive is
+     * out-of-date.</p>
+     *
+     * <p>This method first delegates to getNonFileSetResourceToAdd
+     * and then invokes the FileSet-arg version.  All this to keep
+     * backwards compatibility for subclasses that don't know how to
+     * deal with non-FileSet ResourceCollections.</p>
+     *
+     * @param rcs The resource collections to grab resources from
+     * @param zipFile intended archive file (may or may not exist)
+     * @param needsUpdate whether we already know that the archive is
+     * out-of-date.  Subclasses overriding this method are supposed to
+     * set this value correctly in their call to
+     * <code>super.getResourcesToAdd</code>.
+     * @return an array of resources to add for each fileset passed in as well
+     *         as a flag that indicates whether the archive is uptodate.
+     *
+     * @exception BuildException if it likes
+     * @since Ant 1.7
+     */
+    protected ArchiveState getResourcesToAdd(ResourceCollection[] rcs,
+                                             File zipFile,
+                                             boolean needsUpdate)
+        throws BuildException {
+        ArrayList filesets = new ArrayList();
+        ArrayList rest = new ArrayList();
+        for (int i = 0; i < rcs.length; i++) {
+            if (rcs[i] instanceof FileSet) {
+                filesets.add(rcs[i]);
+            } else {
+                rest.add(rcs[i]);
+            }
+        }
+        ResourceCollection[] rc = (ResourceCollection[])
+            rest.toArray(new ResourceCollection[rest.size()]);
+        ArchiveState as = getNonFileSetResourcesToAdd(rc, zipFile,
+                                                      needsUpdate);
+
+        FileSet[] fs = (FileSet[]) filesets.toArray(new FileSet[filesets
+                                                                .size()]);
+        ArchiveState as2 = getResourcesToAdd(fs, zipFile, as.isOutOfDate());
+        if (!as.isOutOfDate() && as2.isOutOfDate()) {
+            /*
+             * Bad luck.
+             *
+             * There are resources in the filesets that make the
+             * archive out of date, but not in the non-fileset
+             * resources. We need to rescan the non-FileSets to grab
+             * all of them now.
+             */
+            as = getNonFileSetResourcesToAdd(rc, zipFile, true);
+        }
+
+        Resource[][] toAdd = new Resource[rcs.length][];
+        int fsIndex = 0;
+        int restIndex = 0;
+        for (int i = 0; i < rcs.length; i++) {
+            if (rcs[i] instanceof FileSet) {
+                toAdd[i] = as2.getResourcesToAdd()[fsIndex++];
+            } else {
+                toAdd[i] = as.getResourcesToAdd()[restIndex++];
+            }
+        }
+        return new ArchiveState(as2.isOutOfDate(), toAdd);
+    }
+
+    /**
+     * Collect the resources that are newer than the corresponding
+     * entries (or missing) in the original archive.
+     *
+     * <p>If we are going to recreate the archive instead of updating
+     * it, all resources should be considered as new, if a single one
+     * is.  Because of this, subclasses overriding this method must
+     * call <code>super.getResourcesToAdd</code> and indicate with the
+     * third arg if they already know that the archive is
+     * out-of-date.</p>
+     *
+     * @param filesets The filesets to grab resources from
+     * @param zipFile intended archive file (may or may not exist)
+     * @param needsUpdate whether we already know that the archive is
+     * out-of-date.  Subclasses overriding this method are supposed to
+     * set this value correctly in their call to
+     * <code>super.getResourcesToAdd</code>.
+     * @return an array of resources to add for each fileset passed in as well
+     *         as a flag that indicates whether the archive is uptodate.
+     *
+     * @exception BuildException if it likes
+     */
+    protected ArchiveState getResourcesToAdd(FileSet[] filesets,
+                                             File zipFile,
+                                             boolean needsUpdate)
+        throws BuildException {
+
+        Resource[][] initialResources = grabResources(filesets);
+        if (isEmpty(initialResources)) {
+            if (needsUpdate && doUpdate) {
+                /*
+                 * This is a rather hairy case.
+                 *
+                 * One of our subclasses knows that we need to update the
+                 * archive, but at the same time, there are no resources
+                 * known to us that would need to be added.  Only the
+                 * subclass seems to know what's going on.
+                 *
+                 * This happens if <jar> detects that the manifest has changed,
+                 * for example.  The manifest is not part of any resources
+                 * because of our support for inline <manifest>s.
+                 *
+                 * If we invoke createEmptyZip like Ant 1.5.2 did,
+                 * we'll loose all stuff that has been in the original
+                 * archive (bugzilla report 17780).
+                 */
+                return new ArchiveState(true, initialResources);
+            }
+
+            if (emptyBehavior.equals("skip")) {
+                if (doUpdate) {
+                    log(archiveType + " archive " + zipFile
+                        + " not updated because no new files were included.",
+                        Project.MSG_VERBOSE);
+                } else {
+                    log("Warning: skipping " + archiveType + " archive "
+                        + zipFile + " because no files were included.",
+                        Project.MSG_WARN);
+                }
+            } else if (emptyBehavior.equals("fail")) {
+                throw new BuildException("Cannot create " + archiveType
+                                         + " archive " + zipFile
+                                         + ": no files were included.",
+                                         getLocation());
+            } else {
+                // Create.
+                if (!zipFile.exists())  {
+                    needsUpdate = true;
+                }
+            }
+            return new ArchiveState(needsUpdate, initialResources);
+        }
+
+        // initialResources is not empty
+
+        if (!zipFile.exists()) {
+            return new ArchiveState(true, initialResources);
+        }
+
+        if (needsUpdate && !doUpdate) {
+            // we are recreating the archive, need all resources
+            return new ArchiveState(true, initialResources);
+        }
+
+        Resource[][] newerResources = new Resource[filesets.length][];
+
+        for (int i = 0; i < filesets.length; i++) {
+            if (!(fileset instanceof ZipFileSet)
+                || ((ZipFileSet) fileset).getSrc(getProject()) == null) {
+                File base = filesets[i].getDir(getProject());
+
+                for (int j = 0; j < initialResources[i].length; j++) {
+                    File resourceAsFile =
+                        FILE_UTILS.resolveFile(base,
+                                              initialResources[i][j].getName());
+                    if (resourceAsFile.equals(zipFile)) {
+                        throw new BuildException("A zip file cannot include "
+                                                 + "itself", getLocation());
+                    }
+                }
+            }
+        }
+
+        for (int i = 0; i < filesets.length; i++) {
+            if (initialResources[i].length == 0) {
+                newerResources[i] = new Resource[] {};
+                continue;
+            }
+
+            FileNameMapper myMapper = new IdentityMapper();
+            if (filesets[i] instanceof ZipFileSet) {
+                ZipFileSet zfs = (ZipFileSet) filesets[i];
+                if (zfs.getFullpath(getProject()) != null
+                    && !zfs.getFullpath(getProject()).equals("")) {
+                    // in this case all files from origin map to
+                    // the fullPath attribute of the zipfileset at
+                    // destination
+                    MergingMapper fm = new MergingMapper();
+                    fm.setTo(zfs.getFullpath(getProject()));
+                    myMapper = fm;
+
+                } else if (zfs.getPrefix(getProject()) != null
+                           && !zfs.getPrefix(getProject()).equals("")) {
+                    GlobPatternMapper gm = new GlobPatternMapper();
+                    gm.setFrom("*");
+                    String prefix = zfs.getPrefix(getProject());
+                    if (!prefix.endsWith("/") && !prefix.endsWith("\\")) {
+                        prefix += "/";
+                    }
+                    gm.setTo(prefix + "*");
+                    myMapper = gm;
+                }
+            }
+
+            Resource[] resources = initialResources[i];
+            if (doFilesonly) {
+                resources = selectFileResources(resources);
+            }
+
+            newerResources[i] =
+                ResourceUtils.selectOutOfDateSources(this,
+                                                     resources,
+                                                     myMapper,
+                                                     getZipScanner());
+            needsUpdate = needsUpdate || (newerResources[i].length > 0);
+
+            if (needsUpdate && !doUpdate) {
+                // we will return initialResources anyway, no reason
+                // to scan further.
+                break;
+            }
+        }
+
+        if (needsUpdate && !doUpdate) {
+            // we are recreating the archive, need all resources
+            return new ArchiveState(true, initialResources);
+        }
+
+        return new ArchiveState(needsUpdate, newerResources);
+    }
+
+    /**
+     * Collect the resources that are newer than the corresponding
+     * entries (or missing) in the original archive.
+     *
+     * <p>If we are going to recreate the archive instead of updating
+     * it, all resources should be considered as new, if a single one
+     * is.  Because of this, subclasses overriding this method must
+     * call <code>super.getResourcesToAdd</code> and indicate with the
+     * third arg if they already know that the archive is
+     * out-of-date.</p>
+     *
+     * @param rcs The filesets to grab resources from
+     * @param zipFile intended archive file (may or may not exist)
+     * @param needsUpdate whether we already know that the archive is
+     * out-of-date.  Subclasses overriding this method are supposed to
+     * set this value correctly in their call to
+     * <code>super.getResourcesToAdd</code>.
+     * @return an array of resources to add for each fileset passed in as well
+     *         as a flag that indicates whether the archive is uptodate.
+     *
+     * @exception BuildException if it likes
+     */
+    protected ArchiveState getNonFileSetResourcesToAdd(ResourceCollection[] rcs,
+                                                       File zipFile,
+                                                       boolean needsUpdate)
+        throws BuildException {
+        /*
+         * Backwards compatibility forces us to repeat the logic of
+         * getResourcesToAdd(FileSet[], ...) here once again.
+         */
+
+        Resource[][] initialResources = grabNonFileSetResources(rcs);
+        if (isEmpty(initialResources)) {
+            // no emptyBehavior handling since the FileSet version
+            // will take care of it.
+            return new ArchiveState(needsUpdate, initialResources);
+        }
+
+        // initialResources is not empty
+
+        if (!zipFile.exists()) {
+            return new ArchiveState(true, initialResources);
+        }
+
+        if (needsUpdate && !doUpdate) {
+            // we are recreating the archive, need all resources
+            return new ArchiveState(true, initialResources);
+        }
+
+        Resource[][] newerResources = new Resource[rcs.length][];
+
+        for (int i = 0; i < rcs.length; i++) {
+            if (initialResources[i].length == 0) {
+                newerResources[i] = new Resource[] {};
+                continue;
+            }
+
+            for (int j = 0; j < initialResources[i].length; j++) {
+                if (initialResources[i][j] instanceof FileResource
+                    && zipFile.equals(((FileResource)
+                                       initialResources[i][j]).getFile())) {
+                    throw new BuildException("A zip file cannot include "
+                                             + "itself", getLocation());
+                }
+            }
+
+            Resource[] rs = initialResources[i];
+            if (doFilesonly) {
+                rs = selectFileResources(rs);
+            }
+
+            newerResources[i] =
+                ResourceUtils.selectOutOfDateSources(this,
+                                                     rs,
+                                                     new IdentityMapper(),
+                                                     getZipScanner());
+            needsUpdate = needsUpdate || (newerResources[i].length > 0);
+
+            if (needsUpdate && !doUpdate) {
+                // we will return initialResources anyway, no reason
+                // to scan further.
+                break;
+            }
+        }
+
+        if (needsUpdate && !doUpdate) {
+            // we are recreating the archive, need all resources
+            return new ArchiveState(true, initialResources);
+        }
+
+        return new ArchiveState(needsUpdate, newerResources);
+    }
+
+    /**
+     * Fetch all included and not excluded resources from the sets.
+     *
+     * <p>Included directories will precede included files.</p>
+     * @param filesets an array of filesets
+     * @return the resources included
+     * @since Ant 1.5.2
+     */
+    protected Resource[][] grabResources(FileSet[] filesets) {
+        Resource[][] result = new Resource[filesets.length][];
+        for (int i = 0; i < filesets.length; i++) {
+            boolean skipEmptyNames = true;
+            if (filesets[i] instanceof ZipFileSet) {
+                ZipFileSet zfs = (ZipFileSet) filesets[i];
+                skipEmptyNames = zfs.getPrefix(getProject()).equals("")
+                    && zfs.getFullpath(getProject()).equals("");
+            }
+            DirectoryScanner rs =
+                filesets[i].getDirectoryScanner(getProject());
+            if (rs instanceof ZipScanner) {
+                ((ZipScanner) rs).setEncoding(encoding);
+            }
+            Vector resources = new Vector();
+            if (!doFilesonly) {
+                String[] directories = rs.getIncludedDirectories();
+                for (int j = 0; j < directories.length; j++) {
+                    if (!"".equals(directories[j]) || !skipEmptyNames) {
+                        resources.addElement(rs.getResource(directories[j]));
+                    }
+                }
+            }
+            String[] files = rs.getIncludedFiles();
+            for (int j = 0; j < files.length; j++) {
+                if (!"".equals(files[j]) || !skipEmptyNames) {
+                    resources.addElement(rs.getResource(files[j]));
+                }
+            }
+
+            result[i] = new Resource[resources.size()];
+            resources.copyInto(result[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Fetch all included and not excluded resources from the collections.
+     *
+     * <p>Included directories will precede included files.</p>
+     * @param rcs an array of resource collections
+     * @return the resources included
+     * @since Ant 1.7
+     */
+    protected Resource[][] grabNonFileSetResources(ResourceCollection[] rcs) {
+        Resource[][] result = new Resource[rcs.length][];
+        for (int i = 0; i < rcs.length; i++) {
+            Iterator iter = rcs[i].iterator();
+            ArrayList rs = new ArrayList();
+            int lastDir = 0;
+            while (iter.hasNext()) {
+                Resource r = (Resource) iter.next();
+                if (r.isExists()) {
+                    if (r.isDirectory()) {
+                        rs.add(lastDir++, r);
+                    } else {
+                        rs.add(r);
+                    }
+                }
+            }
+            result[i] = (Resource[]) rs.toArray(new Resource[rs.size()]);
+        }
+        return result;
+    }
+
+    /**
+     * Add a directory to the zip stream.
+     * @param dir  the directort to add to the archive
+     * @param zOut the stream to write to
+     * @param vPath the name this entry shall have in the archive
+     * @param mode the Unix permissions to set.
+     * @throws IOException on error
+     * @since Ant 1.5.2
+     */
+    protected void zipDir(File dir, ZipOutputStream zOut, String vPath,
+                          int mode)
+        throws IOException {
+        zipDir(dir, zOut, vPath, mode, null);
+    }
+
+    /**
+     * Add a directory to the zip stream.
+     * @param dir  the directort to add to the archive
+     * @param zOut the stream to write to
+     * @param vPath the name this entry shall have in the archive
+     * @param mode the Unix permissions to set.
+     * @param extra ZipExtraFields to add
+     * @throws IOException on error
+     * @since Ant 1.6.3
+     */
+    protected void zipDir(File dir, ZipOutputStream zOut, String vPath,
+                          int mode, ZipExtraField[] extra)
+        throws IOException {
+        if (doFilesonly) {
+            log("skipping directory " + vPath + " for file-only archive",
+                    Project.MSG_VERBOSE);
+            return;
+        }
+        if (addedDirs.get(vPath) != null) {
+            // don't add directories we've already added.
+            // no warning if we try, it is harmless in and of itself
+            return;
+        }
+
+        log("adding directory " + vPath, Project.MSG_VERBOSE);
+        addedDirs.put(vPath, vPath);
+
+        if (!skipWriting) {
+            ZipEntry ze = new ZipEntry (vPath);
+            if (dir != null && dir.exists()) {
+                // ZIPs store time with a granularity of 2 seconds, round up
+                ze.setTime(dir.lastModified() + (roundUp ? ROUNDUP_MILLIS : 0));
+            } else {
+                // ZIPs store time with a granularity of 2 seconds, round up
+                ze.setTime(System.currentTimeMillis()
+                           + (roundUp ? ROUNDUP_MILLIS : 0));
+            }
+            ze.setSize (0);
+            ze.setMethod (ZipEntry.STORED);
+            // This is faintly ridiculous:
+            ze.setCrc (EMPTY_CRC);
+            ze.setUnixMode(mode);
+
+            if (extra != null) {
+                ze.setExtraFields(extra);
+            }
+
+            zOut.putNextEntry(ze);
+        }
+    }
+
+    /**
+     * Adds a new entry to the archive, takes care of duplicates as well.
+     *
+     * @param in the stream to read data for the entry from.
+     * @param zOut the stream to write to.
+     * @param vPath the name this entry shall have in the archive.
+     * @param lastModified last modification time for the entry.
+     * @param fromArchive the original archive we are copying this
+     * entry from, will be null if we are not copying from an archive.
+     * @param mode the Unix permissions to set.
+     *
+     * @since Ant 1.5.2
+     * @throws IOException on error
+     */
+    protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath,
+                           long lastModified, File fromArchive, int mode)
+        throws IOException {
+        if (entries.contains(vPath)) {
+
+            if (duplicate.equals("preserve")) {
+                log(vPath + " already added, skipping", Project.MSG_INFO);
+                return;
+            } else if (duplicate.equals("fail")) {
+                throw new BuildException("Duplicate file " + vPath
+                                         + " was found and the duplicate "
+                                         + "attribute is 'fail'.");
+            } else {
+                // duplicate equal to add, so we continue
+                log("duplicate file " + vPath
+                    + " found, adding.", Project.MSG_VERBOSE);
+            }
+        } else {
+            log("adding entry " + vPath, Project.MSG_VERBOSE);
+        }
+
+        entries.put(vPath, vPath);
+
+        if (!skipWriting) {
+            ZipEntry ze = new ZipEntry(vPath);
+            ze.setTime(lastModified);
+            ze.setMethod(doCompress ? ZipEntry.DEFLATED : ZipEntry.STORED);
+
+            /*
+             * ZipOutputStream.putNextEntry expects the ZipEntry to
+             * know its size and the CRC sum before you start writing
+             * the data when using STORED mode - unless it is seekable.
+             *
+             * This forces us to process the data twice.
+             */
+            if (!zOut.isSeekable() && !doCompress) {
+                long size = 0;
+                CRC32 cal = new CRC32();
+                if (!in.markSupported()) {
+                    // Store data into a byte[]
+                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+                    byte[] buffer = new byte[BUFFER_SIZE];
+                    int count = 0;
+                    do {
+                        size += count;
+                        cal.update(buffer, 0, count);
+                        bos.write(buffer, 0, count);
+                        count = in.read(buffer, 0, buffer.length);
+                    } while (count != -1);
+                    in = new ByteArrayInputStream(bos.toByteArray());
+
+                } else {
+                    in.mark(Integer.MAX_VALUE);
+                    byte[] buffer = new byte[BUFFER_SIZE];
+                    int count = 0;
+                    do {
+                        size += count;
+                        cal.update(buffer, 0, count);
+                        count = in.read(buffer, 0, buffer.length);
+                    } while (count != -1);
+                    in.reset();
+                }
+                ze.setSize(size);
+                ze.setCrc(cal.getValue());
+            }
+
+            ze.setUnixMode(mode);
+            zOut.putNextEntry(ze);
+
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int count = 0;
+            do {
+                if (count != 0) {
+                    zOut.write(buffer, 0, count);
+                }
+                count = in.read(buffer, 0, buffer.length);
+            } while (count != -1);
+        }
+        addedFiles.addElement(vPath);
+    }
+
+    /**
+     * Method that gets called when adding from <code>java.io.File</code> instances.
+     *
+     * <p>This implementation delegates to the six-arg version.</p>
+     *
+     * @param file the file to add to the archive
+     * @param zOut the stream to write to
+     * @param vPath the name this entry shall have in the archive
+     * @param mode the Unix permissions to set.
+     * @throws IOException on error
+     *
+     * @since Ant 1.5.2
+     */
+    protected void zipFile(File file, ZipOutputStream zOut, String vPath,
+                           int mode)
+        throws IOException {
+        if (file.equals(zipFile)) {
+            throw new BuildException("A zip file cannot include itself",
+                                     getLocation());
+        }
+
+        FileInputStream fIn = new FileInputStream(file);
+        try {
+            // ZIPs store time with a granularity of 2 seconds, round up
+            zipFile(fIn, zOut, vPath,
+                    file.lastModified() + (roundUp ? ROUNDUP_MILLIS : 0),
+                    null, mode);
+        } finally {
+            fIn.close();
+        }
+    }
+
+    /**
+     * Ensure all parent dirs of a given entry have been added.
+     * @param baseDir the base directory to use (may be null)
+     * @param entry   the entry name to create directories from
+     * @param zOut    the stream to write to
+     * @param prefix  a prefix to place on the created entries
+     * @param dirMode the directory mode
+     * @throws IOException on error
+     * @since Ant 1.5.2
+     */
+    protected final void addParentDirs(File baseDir, String entry,
+                                       ZipOutputStream zOut, String prefix,
+                                       int dirMode)
+        throws IOException {
+        if (!doFilesonly) {
+            Stack directories = new Stack();
+            int slashPos = entry.length();
+
+            while ((slashPos = entry.lastIndexOf('/', slashPos - 1)) != -1) {
+                String dir = entry.substring(0, slashPos + 1);
+                if (addedDirs.get(prefix + dir) != null) {
+                    break;
+                }
+                directories.push(dir);
+            }
+
+            while (!directories.isEmpty()) {
+                String dir = (String) directories.pop();
+                File f = null;
+                if (baseDir != null) {
+                    f = new File(baseDir, dir);
+                } else {
+                    f = new File(dir);
+                }
+                zipDir(f, zOut, prefix + dir, dirMode);
+            }
+        }
+    }
+
+    /**
+     * Do any clean up necessary to allow this instance to be used again.
+     *
+     * <p>When we get here, the Zip file has been closed and all we
+     * need to do is to reset some globals.</p>
+     *
+     * <p>This method will only reset globals that have been changed
+     * during execute(), it will not alter the attributes or nested
+     * child elements.  If you want to reset the instance so that you
+     * can later zip a completely different set of files, you must use
+     * the reset method.</p>
+     *
+     * @see #reset
+     */
+    protected void cleanUp() {
+        addedDirs.clear();
+        addedFiles.removeAllElements();
+        entries.clear();
+        addingNewFiles = false;
+        doUpdate = savedDoUpdate;
+        Enumeration e = filesetsFromGroupfilesets.elements();
+        while (e.hasMoreElements()) {
+            ZipFileSet zf = (ZipFileSet) e.nextElement();
+            resources.removeElement(zf);
+        }
+        filesetsFromGroupfilesets.removeAllElements();
+    }
+
+    /**
+     * Makes this instance reset all attributes to their default
+     * values and forget all children.
+     *
+     * @since Ant 1.5
+     *
+     * @see #cleanUp
+     */
+    public void reset() {
+        resources.removeAllElements();
+        zipFile = null;
+        baseDir = null;
+        groupfilesets.removeAllElements();
+        duplicate = "add";
+        archiveType = "zip";
+        doCompress = true;
+        emptyBehavior = "skip";
+        doUpdate = false;
+        doFilesonly = false;
+        encoding = null;
+    }
+
+    /**
+     * Check is the resource arrays are empty.
+     * @param r the arrays to check
+     * @return true if all individual arrays are empty
+     *
+     * @since Ant 1.5.2
+     */
+    protected static final boolean isEmpty(Resource[][] r) {
+        for (int i = 0; i < r.length; i++) {
+            if (r[i].length > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Drops all non-file resources from the given array.
+     * @param orig the resources to filter
+     * @return the filters resources
+     * @since Ant 1.6
+     */
+    protected Resource[] selectFileResources(Resource[] orig) {
+        if (orig.length == 0) {
+            return orig;
+        }
+
+        Vector v = new Vector(orig.length);
+        for (int i = 0; i < orig.length; i++) {
+            if (!orig[i].isDirectory()) {
+                v.addElement(orig[i]);
+            } else {
+                log("Ignoring directory " + orig[i].getName()
+                    + " as only files will be added.", Project.MSG_VERBOSE);
+            }
+        }
+
+        if (v.size() != orig.length) {
+            Resource[] r = new Resource[v.size()];
+            v.copyInto(r);
+            return r;
+        }
+        return orig;
+    }
+
+    /**
+     * Possible behaviors when a duplicate file is added:
+     * "add", "preserve" or "fail"
+     */
+    public static class Duplicate extends EnumeratedAttribute {
+        /**
+         * @see EnumeratedAttribute#getValues()
+         */
+        /** {@inheritDoc} */
+        public String[] getValues() {
+            return new String[] {"add", "preserve", "fail"};
+        }
+    }
+
+    /**
+     * Holds the up-to-date status and the out-of-date resources of
+     * the original archive.
+     *
+     * @since Ant 1.5.3
+     */
+    public static class ArchiveState {
+        private boolean outOfDate;
+        private Resource[][] resourcesToAdd;
+
+        ArchiveState(boolean state, Resource[][] r) {
+            outOfDate = state;
+            resourcesToAdd = r;
+        }
+
+        /**
+         * Return the outofdate status.
+         * @return the outofdate status
+         */
+        public boolean isOutOfDate() {
+            return outOfDate;
+        }
+
+        /**
+         * Get the resources to add.
+         * @return the resources to add
+         */
+        public Resource[][] getResourcesToAdd() {
+            return resourcesToAdd;
+        }
+        /**
+         * find out if there are absolutely no resources to add
+         * @since Ant 1.6.3
+         * @return true if there are no resources to add
+         */
+        public boolean isWithoutAnyResources() {
+            if (resourcesToAdd == null)  {
+                return true;
+            }
+            for (int counter = 0; counter < resourcesToAdd.length; counter++) {
+                if (resourcesToAdd[counter] != null) {
+                    if (resourcesToAdd[counter].length > 0) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptCompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptCompilerAdapter.java
new file mode 100644
index 0000000..119df94
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptCompilerAdapter.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Apt;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Vector;
+
+
+/**
+ * The implementation of the apt compiler for JDK 1.5
+ * <p/>
+ * As usual, the low level entry points for Java tools are neither documented or
+ * stable; this entry point may change from that of 1.5.0_01-b08 without any
+ * warning at all. The IDE decompile of the tool entry points is as follows:
+ * <pre>
+ * public class Main {
+ * public Main() ;
+ * <p/>
+ * public static transient void main(String... strings) ;
+ * <p/>
+ * public static transient int process(String... strings);
+ * <p/>
+ * public static transient int process(PrintWriter printWriter,
+ *      String... strings) ;
+ * public static transient int process(
+ *      AnnotationProcessorFactory annotationProcessorFactory,
+ *      String... strings) ;
+ * <p/>
+ * public static transient int process(
+ *      AnnotationProcessorFactory annotationProcessorFactory,
+ *      PrintWriter printWriter,
+ *      String... strings);
+ * private static transient int processing(
+ *      AnnotationProcessorFactory annotationProcessorFactory,
+ *      PrintWriter printWriter,
+ *      String... strings) ;
+ * }
+ * </pre>
+ *
+ * This Adapter is designed to run Apt in-JVM, an option that is not actually
+ * exposed to end-users, because it was too brittle during beta testing; classpath
+ * problems being the core issue.
+ *
+ *
+ *
+ * @since Ant 1.7
+ */
+public class AptCompilerAdapter extends DefaultCompilerAdapter {
+
+    /**
+     * Integer returned by the Apt compiler to indicate success.
+     */
+    private static final int APT_COMPILER_SUCCESS = 0;
+    /**
+     * class in tools.jar that implements APT
+     */
+    public static final String APT_ENTRY_POINT = "com.sun.tools.apt.Main";
+
+    /**
+     * method used to compile.
+     */
+    public static final String APT_METHOD_NAME = "process";
+
+    /**
+     * Get the facade task that fronts this adapter
+     *
+     * @return task instance
+     * @see DefaultCompilerAdapter#getJavac()
+     */
+    protected Apt getApt() {
+        return (Apt) getJavac();
+    }
+
+    /**
+     * Using the front end arguments, set up the command line to run Apt
+     *
+     * @param apt task
+     * @param cmd command that is set up with the various switches from the task
+     *            options
+     */
+    static void setAptCommandlineSwitches(Apt apt, Commandline cmd) {
+
+        if (!apt.isCompile()) {
+            cmd.createArgument().setValue("-nocompile");
+        }
+
+        // Process the factory class
+        String factory = apt.getFactory();
+        if (factory != null) {
+            cmd.createArgument().setValue("-factory");
+            cmd.createArgument().setValue(factory);
+        }
+
+        // Process the factory path
+        Path factoryPath = apt.getFactoryPath();
+        if (factoryPath != null) {
+            cmd.createArgument().setValue("-factorypath");
+            cmd.createArgument().setPath(factoryPath);
+        }
+
+        File preprocessDir = apt.getPreprocessDir();
+        if (preprocessDir != null) {
+            cmd.createArgument().setValue("-s");
+            cmd.createArgument().setFile(preprocessDir);
+        }
+
+        // Process the processor options
+        Vector options = apt.getOptions();
+        Enumeration elements = options.elements();
+        Apt.Option opt;
+        StringBuffer arg = null;
+        while (elements.hasMoreElements()) {
+            opt = (Apt.Option) elements.nextElement();
+            arg = new StringBuffer();
+            arg.append("-A").append(opt.getName());
+            if (opt.getValue() != null) {
+                arg.append("=").append(opt.getValue());
+            }
+            cmd.createArgument().setValue(arg.toString());
+        }
+    }
+
+    /**
+     * using our front end task, set up the command line switches
+     *
+     * @param cmd command line to set up
+     */
+    protected void setAptCommandlineSwitches(Commandline cmd) {
+        Apt apt = getApt();
+        setAptCommandlineSwitches(apt, cmd);
+    }
+
+    /**
+     * Run the compilation.
+     * @return true on success.
+     * @throws BuildException if the compilation has problems.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using apt compiler", Project.MSG_VERBOSE);
+        //set up the javac options
+        Commandline cmd = setupModernJavacCommand();
+        //then add the Apt options
+        setAptCommandlineSwitches(cmd);
+
+        //finally invoke APT
+        // Use reflection to be able to build on all JDKs:
+        try {
+            Class c = Class.forName(APT_ENTRY_POINT);
+            Object compiler = c.newInstance();
+            Method compile = c.getMethod(APT_METHOD_NAME,
+                    new Class[]{(new String[]{}).getClass()});
+            int result = ((Integer) compile.invoke
+                    (compiler, new Object[]{cmd.getArguments()}))
+                    .intValue();
+            return (result == APT_COMPILER_SUCCESS);
+        } catch (BuildException be) {
+            //rethrow build exceptions
+            throw be;
+        } catch (Exception ex) {
+            //cast everything else to a build exception
+            throw new BuildException("Error starting apt compiler",
+                    ex, location);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptExternalCompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptExternalCompilerAdapter.java
new file mode 100644
index 0000000..dadb55b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/AptExternalCompilerAdapter.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Apt;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the apt compiler for JDK 1.5 using an external process
+ *
+ * @since Ant 1.7
+ */
+public class AptExternalCompilerAdapter extends DefaultCompilerAdapter {
+
+
+    /**
+     * Get the facade task that fronts this adapter
+     *
+     * @return task instance
+     * @see DefaultCompilerAdapter#getJavac()
+     */
+    protected Apt getApt() {
+        return (Apt) getJavac();
+    }
+
+    /**
+     * Performs a compile using the Javac externally.
+     * @return true  the compilation was successful.
+     * @throws BuildException if there is a problem.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using external apt compiler", Project.MSG_VERBOSE);
+
+
+        // Setup the apt executable
+        Apt apt = getApt();
+        Commandline cmd = new Commandline();
+        cmd.setExecutable(apt.getAptExecutable());
+        setupModernJavacCommandlineSwitches(cmd);
+        AptCompilerAdapter.setAptCommandlineSwitches(apt, cmd);
+        int firstFileName = cmd.size();
+        //add the files
+        logAndAddFilesToCompile(cmd);
+
+        //run
+        return 0 == executeExternalCompile(cmd.getCommandline(),
+                firstFileName,
+                true);
+
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapter.java
new file mode 100644
index 0000000..5a275b8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapter.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Javac;
+
+/**
+ * The interface that all compiler adapters must adhere to.
+ *
+ * <p>A compiler adapter is an adapter that interprets the javac's
+ * parameters in preparation to be passed off to the compiler this
+ * adapter represents.  As all the necessary values are stored in the
+ * Javac task itself, the only thing all adapters need is the javac
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ * @since Ant 1.3
+ */
+
+public interface CompilerAdapter {
+
+    /**
+     * Sets the compiler attributes, which are stored in the Javac task.
+     * @param attributes the compiler attributes
+     */
+    void setJavac(Javac attributes);
+
+    /**
+     * Executes the task.
+     *
+     * @return has the compilation been successful
+     * @throws BuildException on error
+     */
+    boolean execute() throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapterFactory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapterFactory.java
new file mode 100644
index 0000000..8cf2bb4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/CompilerAdapterFactory.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Creates the necessary compiler adapter, given basic criteria.
+ *
+ * @since Ant 1.3
+ */
+public final class CompilerAdapterFactory {
+    private static final String MODERN_COMPILER = "com.sun.tools.javac.Main";
+
+    /** This is a singleton -- can't create instances!! */
+    private CompilerAdapterFactory() {
+    }
+
+    /**
+     * Based on the parameter passed in, this method creates the necessary
+     * factory desired.
+     *
+     * The current mapping for compiler names are as follows:
+     * <ul><li>jikes = jikes compiler
+     * <li>classic, javac1.1, javac1.2 = the standard compiler from JDK
+     * 1.1/1.2
+     * <li>modern, javac1.3, javac1.4, javac1.5 = the compiler of JDK 1.3+
+     * <li>jvc, microsoft = the command line compiler from Microsoft's SDK
+     * for Java / Visual J++
+     * <li>kjc = the kopi compiler</li>
+     * <li>gcj = the gcj compiler from gcc</li>
+     * <li>sj, symantec = the Symantec Java compiler</li>
+     * <li><i>a fully qualified classname</i> = the name of a compiler
+     * adapter
+     * </ul>
+     *
+     * @param compilerType either the name of the desired compiler, or the
+     * full classname of the compiler's adapter.
+     * @param task a task to log through.
+     * @return the compiler adapter
+     * @throws BuildException if the compiler type could not be resolved into
+     * a compiler adapter.
+     */
+    public static CompilerAdapter getCompiler(String compilerType, Task task)
+        throws BuildException {
+            boolean isClassicCompilerSupported = true;
+            //as new versions of java come out, add them to this test
+            if (!JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+                && !JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
+                isClassicCompilerSupported = false;
+            }
+
+            if (compilerType.equalsIgnoreCase("jikes")) {
+                return new Jikes();
+            }
+            if (compilerType.equalsIgnoreCase("extJavac")) {
+                return new JavacExternal();
+            }
+            if (compilerType.equalsIgnoreCase("classic")
+                || compilerType.equalsIgnoreCase("javac1.1")
+                || compilerType.equalsIgnoreCase("javac1.2")) {
+                if (isClassicCompilerSupported) {
+                    return new Javac12();
+                } else {
+                    task.log("This version of java does "
+                                             + "not support the classic "
+                                             + "compiler; upgrading to modern",
+                                             Project.MSG_WARN);
+                    compilerType = "modern";
+                }
+            }
+            //on java<=1.3 the modern falls back to classic if it is not found
+            //but on java>=1.4 we just bail out early
+            if (compilerType.equalsIgnoreCase("modern")
+                || compilerType.equalsIgnoreCase("javac1.3")
+                || compilerType.equalsIgnoreCase("javac1.4")
+                || compilerType.equalsIgnoreCase("javac1.5")
+                || compilerType.equalsIgnoreCase("javac1.6")) {
+                // does the modern compiler exist?
+                if (doesModernCompilerExist()) {
+                    return new Javac13();
+                } else {
+                    if (isClassicCompilerSupported) {
+                        task.log("Modern compiler not found - looking for "
+                                 + "classic compiler", Project.MSG_WARN);
+                        return new Javac12();
+                    } else {
+                        throw new BuildException("Unable to find a javac "
+                                                 + "compiler;\n"
+                                                 + MODERN_COMPILER
+                                                 + " is not on the "
+                                                 + "classpath.\n"
+                                                 + "Perhaps JAVA_HOME does not"
+                                                 + " point to the JDK.\n"
+                                + "It is currently set to \""
+                                + JavaEnvUtils.getJavaHome()
+                                + "\"");
+                    }
+                }
+            }
+
+            if (compilerType.equalsIgnoreCase("jvc")
+                || compilerType.equalsIgnoreCase("microsoft")) {
+                return new Jvc();
+            }
+            if (compilerType.equalsIgnoreCase("kjc")) {
+                return new Kjc();
+            }
+            if (compilerType.equalsIgnoreCase("gcj")) {
+                return new Gcj();
+            }
+            if (compilerType.equalsIgnoreCase("sj")
+                || compilerType.equalsIgnoreCase("symantec")) {
+                return new Sj();
+            }
+            return resolveClassName(compilerType);
+        }
+
+    /**
+     * query for the Modern compiler existing
+     * @return true if classic os on the classpath
+     */
+    private static boolean doesModernCompilerExist() {
+        try {
+            Class.forName(MODERN_COMPILER);
+            return true;
+        } catch (ClassNotFoundException cnfe) {
+            try {
+                ClassLoader cl = CompilerAdapterFactory.class.getClassLoader();
+                if (cl != null) {
+                    cl.loadClass(MODERN_COMPILER);
+                    return true;
+                }
+            } catch (ClassNotFoundException cnfe2) {
+                // Ignore Exception
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tries to resolve the given classname into a compiler adapter.
+     * Throws a fit if it can't.
+     *
+     * @param className The fully qualified classname to be created.
+     * @throws BuildException This is the fit that is thrown if className
+     * isn't an instance of CompilerAdapter.
+     */
+    private static CompilerAdapter resolveClassName(String className)
+        throws BuildException {
+        return (CompilerAdapter) ClasspathUtils.newInstance(className,
+                CompilerAdapterFactory.class.getClassLoader(),
+                CompilerAdapter.class);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java
new file mode 100644
index 0000000..13275cc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java
@@ -0,0 +1,648 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+//Java5 style
+//import static org.apache.tools.ant.util.StringUtils.LINE_SEP;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.Javac;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * This is the default implementation for the CompilerAdapter interface.
+ * Currently, this is a cut-and-paste of the original javac task.
+ *
+ * @since Ant 1.3
+ */
+public abstract class DefaultCompilerAdapter implements CompilerAdapter {
+    private static final int COMMAND_LINE_LIMIT = 4096;  // 4K
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    protected Path src;
+    protected File destDir;
+    protected String encoding;
+    protected boolean debug = false;
+    protected boolean optimize = false;
+    protected boolean deprecation = false;
+    protected boolean depend = false;
+    protected boolean verbose = false;
+    protected String target;
+    protected Path bootclasspath;
+    protected Path extdirs;
+    protected Path compileClasspath;
+    protected Path compileSourcepath;
+    protected Project project;
+    protected Location location;
+    protected boolean includeAntRuntime;
+    protected boolean includeJavaRuntime;
+    protected String memoryInitialSize;
+    protected String memoryMaximumSize;
+
+    protected File[] compileList;
+    protected Javac attributes;
+
+    //must keep for subclass BC, though unused:
+    // CheckStyle:ConstantNameCheck OFF - bc
+    protected static final String lSep = StringUtils.LINE_SEP;
+
+    // CheckStyle:ConstantNameCheck ON
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the Javac instance which contains the configured compilation
+     * attributes.
+     *
+     * @param attributes a configured Javac task.
+     */
+    public void setJavac(Javac attributes) {
+        this.attributes = attributes;
+        src = attributes.getSrcdir();
+        destDir = attributes.getDestdir();
+        encoding = attributes.getEncoding();
+        debug = attributes.getDebug();
+        optimize = attributes.getOptimize();
+        deprecation = attributes.getDeprecation();
+        depend = attributes.getDepend();
+        verbose = attributes.getVerbose();
+        target = attributes.getTarget();
+        bootclasspath = attributes.getBootclasspath();
+        extdirs = attributes.getExtdirs();
+        compileList = attributes.getFileList();
+        compileClasspath = attributes.getClasspath();
+        compileSourcepath = attributes.getSourcepath();
+        project = attributes.getProject();
+        location = attributes.getLocation();
+        includeAntRuntime = attributes.getIncludeantruntime();
+        includeJavaRuntime = attributes.getIncludejavaruntime();
+        memoryInitialSize = attributes.getMemoryInitialSize();
+        memoryMaximumSize = attributes.getMemoryMaximumSize();
+    }
+
+    /**
+     * Get the Javac task instance associated with this compiler adapter
+     *
+     * @return the configured Javac task instance used by this adapter.
+     */
+    public Javac getJavac() {
+        return attributes;
+    }
+
+    /**
+     * Get the project this compiler adapter was created in.
+     * @return the owner project
+     * @since Ant 1.6
+     */
+    protected Project getProject() {
+        return project;
+    }
+
+    /**
+     * Builds the compilation classpath.
+     * @return the compilation class path
+     */
+    protected Path getCompileClasspath() {
+        Path classpath = new Path(project);
+
+        // add dest dir to classpath so that previously compiled and
+        // untouched classes are on classpath
+
+        if (destDir != null && getJavac().isIncludeDestClasses()) {
+            classpath.setLocation(destDir);
+        }
+
+        // Combine the build classpath with the system classpath, in an
+        // order determined by the value of build.sysclasspath
+
+        Path cp = compileClasspath;
+        if (cp == null) {
+            cp = new Path(project);
+        }
+        if (includeAntRuntime) {
+            classpath.addExisting(cp.concatSystemClasspath("last"));
+        } else {
+            classpath.addExisting(cp.concatSystemClasspath("ignore"));
+        }
+
+        if (includeJavaRuntime) {
+            classpath.addJavaRuntime();
+        }
+
+        return classpath;
+    }
+
+    /**
+     * Get the command line arguments for the switches.
+     * @param cmd the command line
+     * @return the command line
+     */
+    protected Commandline setupJavacCommandlineSwitches(Commandline cmd) {
+        return setupJavacCommandlineSwitches(cmd, false);
+    }
+
+    /**
+     * Does the command line argument processing common to classic and
+     * modern.  Doesn't add the files to compile.
+     * @param cmd the command line
+     * @param useDebugLevel if true set set the debug level with the -g switch
+     * @return the command line
+     */
+    protected Commandline setupJavacCommandlineSwitches(Commandline cmd,
+                                                        boolean useDebugLevel) {
+        Path classpath = getCompileClasspath();
+        // For -sourcepath, use the "sourcepath" value if present.
+        // Otherwise default to the "srcdir" value.
+        Path sourcepath = null;
+        if (compileSourcepath != null) {
+            sourcepath = compileSourcepath;
+        } else {
+            sourcepath = src;
+        }
+
+        String memoryParameterPrefix = assumeJava11() ? "-J-" : "-J-X";
+        if (memoryInitialSize != null) {
+            if (!attributes.isForkedJavac()) {
+                attributes.log("Since fork is false, ignoring "
+                               + "memoryInitialSize setting.",
+                               Project.MSG_WARN);
+            } else {
+                cmd.createArgument().setValue(memoryParameterPrefix
+                                              + "ms" + memoryInitialSize);
+            }
+        }
+
+        if (memoryMaximumSize != null) {
+            if (!attributes.isForkedJavac()) {
+                attributes.log("Since fork is false, ignoring "
+                               + "memoryMaximumSize setting.",
+                               Project.MSG_WARN);
+            } else {
+                cmd.createArgument().setValue(memoryParameterPrefix
+                                              + "mx" + memoryMaximumSize);
+            }
+        }
+
+        if (attributes.getNowarn()) {
+            cmd.createArgument().setValue("-nowarn");
+        }
+
+        if (deprecation) {
+            cmd.createArgument().setValue("-deprecation");
+        }
+
+        if (destDir != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(destDir);
+        }
+
+        cmd.createArgument().setValue("-classpath");
+
+        // Just add "sourcepath" to classpath ( for JDK1.1 )
+        // as well as "bootclasspath" and "extdirs"
+        if (assumeJava11()) {
+            Path cp = new Path(project);
+
+            Path bp = getBootClassPath();
+            if (bp.size() > 0) {
+                cp.append(bp);
+            }
+
+            if (extdirs != null) {
+                cp.addExtdirs(extdirs);
+            }
+            cp.append(classpath);
+            cp.append(sourcepath);
+            cmd.createArgument().setPath(cp);
+        } else {
+            cmd.createArgument().setPath(classpath);
+            // If the buildfile specifies sourcepath="", then don't
+            // output any sourcepath.
+            if (sourcepath.size() > 0) {
+                cmd.createArgument().setValue("-sourcepath");
+                cmd.createArgument().setPath(sourcepath);
+            }
+            if (target != null) {
+                cmd.createArgument().setValue("-target");
+                cmd.createArgument().setValue(target);
+            }
+
+            Path bp = getBootClassPath();
+            if (bp.size() > 0) {
+                cmd.createArgument().setValue("-bootclasspath");
+                cmd.createArgument().setPath(bp);
+            }
+
+            if (extdirs != null && extdirs.size() > 0) {
+                cmd.createArgument().setValue("-extdirs");
+                cmd.createArgument().setPath(extdirs);
+            }
+        }
+
+        if (encoding != null) {
+            cmd.createArgument().setValue("-encoding");
+            cmd.createArgument().setValue(encoding);
+        }
+        if (debug) {
+            if (useDebugLevel && !assumeJava11()) {
+                String debugLevel = attributes.getDebugLevel();
+                if (debugLevel != null) {
+                    cmd.createArgument().setValue("-g:" + debugLevel);
+                } else {
+                    cmd.createArgument().setValue("-g");
+                }
+            } else {
+                cmd.createArgument().setValue("-g");
+            }
+        } else if (getNoDebugArgument() != null) {
+            cmd.createArgument().setValue(getNoDebugArgument());
+        }
+        if (optimize) {
+            cmd.createArgument().setValue("-O");
+        }
+
+        if (depend) {
+            if (assumeJava11()) {
+                cmd.createArgument().setValue("-depend");
+            } else if (assumeJava12()) {
+                cmd.createArgument().setValue("-Xdepend");
+            } else {
+                attributes.log("depend attribute is not supported by the "
+                               + "modern compiler", Project.MSG_WARN);
+            }
+        }
+
+        if (verbose) {
+            cmd.createArgument().setValue("-verbose");
+        }
+
+        addCurrentCompilerArgs(cmd);
+
+        return cmd;
+    }
+
+    /**
+     * Does the command line argument processing for modern.  Doesn't
+     * add the files to compile.
+     * @param cmd the command line
+     * @return the command line
+     */
+    protected Commandline setupModernJavacCommandlineSwitches(Commandline cmd) {
+        setupJavacCommandlineSwitches(cmd, true);
+        if (attributes.getSource() != null && !assumeJava13()) {
+            cmd.createArgument().setValue("-source");
+            String source = attributes.getSource();
+            if (source.equals("1.1") || source.equals("1.2")) {
+                // support for -source 1.1 and -source 1.2 has been
+                // added with JDK 1.4.2 - and isn't present in 1.5.0
+                // or 1.6.0 either
+                cmd.createArgument().setValue("1.3");
+            } else {
+                cmd.createArgument().setValue(source);
+            }
+        } else if ((assumeJava15() || assumeJava16())
+                   && attributes.getTarget() != null) {
+            String t = attributes.getTarget();
+            if (t.equals("1.1") || t.equals("1.2") || t.equals("1.3")
+                || t.equals("1.4")) {
+                String s = t;
+                if (t.equals("1.1")) {
+                    // 1.5.0 doesn't support -source 1.1
+                    s = "1.2";
+                }
+                attributes.log("", Project.MSG_WARN);
+                attributes.log("          WARNING", Project.MSG_WARN);
+                attributes.log("", Project.MSG_WARN);
+                attributes.log("The -source switch defaults to 1.5 in JDK 1.5 and 1.6.",
+                               Project.MSG_WARN);
+                attributes.log("If you specify -target " + t
+                               + " you now must also specify -source " + s
+                               + ".", Project.MSG_WARN);
+                attributes.log("Ant will implicitly add -source " + s
+                               + " for you.  Please change your build file.",
+                               Project.MSG_WARN);
+                cmd.createArgument().setValue("-source");
+                cmd.createArgument().setValue(s);
+            }
+        }
+        return cmd;
+    }
+
+    /**
+     * Does the command line argument processing for modern and adds
+     * the files to compile as well.
+     * @return the command line
+     */
+    protected Commandline setupModernJavacCommand() {
+        Commandline cmd = new Commandline();
+        setupModernJavacCommandlineSwitches(cmd);
+
+        logAndAddFilesToCompile(cmd);
+        return cmd;
+    }
+
+    /**
+     * Set up the command line.
+     * @return the command line
+     */
+    protected Commandline setupJavacCommand() {
+        return setupJavacCommand(false);
+    }
+
+    /**
+     * Does the command line argument processing for classic and adds
+     * the files to compile as well.
+     * @param debugLevelCheck if true set the debug level with the -g switch
+     * @return the command line
+     */
+    protected Commandline setupJavacCommand(boolean debugLevelCheck) {
+        Commandline cmd = new Commandline();
+        setupJavacCommandlineSwitches(cmd, debugLevelCheck);
+        logAndAddFilesToCompile(cmd);
+        return cmd;
+    }
+
+    /**
+     * Logs the compilation parameters, adds the files to compile and logs the
+     * &quot;niceSourceList&quot;
+     * @param cmd the command line
+     */
+    protected void logAndAddFilesToCompile(Commandline cmd) {
+        attributes.log("Compilation " + cmd.describeArguments(),
+                       Project.MSG_VERBOSE);
+
+        StringBuffer niceSourceList = new StringBuffer("File");
+        if (compileList.length != 1) {
+            niceSourceList.append("s");
+        }
+        niceSourceList.append(" to be compiled:");
+
+        niceSourceList.append(StringUtils.LINE_SEP);
+
+        for (int i = 0; i < compileList.length; i++) {
+            String arg = compileList[i].getAbsolutePath();
+            cmd.createArgument().setValue(arg);
+            niceSourceList.append("    ");
+            niceSourceList.append(arg);
+            niceSourceList.append(StringUtils.LINE_SEP);
+        }
+
+        attributes.log(niceSourceList.toString(), Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Do the compile with the specified arguments.
+     * @param args - arguments to pass to process on command line
+     * @param firstFileName - index of the first source file in args,
+     * if the index is negative, no temporary file will ever be
+     * created, but this may hit the command line length limit on your
+     * system.
+     * @return the exit code of the compilation
+     */
+    protected int executeExternalCompile(String[] args, int firstFileName) {
+        return executeExternalCompile(args, firstFileName, true);
+    }
+
+    /**
+     * Do the compile with the specified arguments.
+     * @param args - arguments to pass to process on command line
+     * @param firstFileName - index of the first source file in args,
+     * if the index is negative, no temporary file will ever be
+     * created, but this may hit the command line length limit on your
+     * system.
+     * @param quoteFiles - if set to true, filenames containing
+     * spaces will be quoted when they appear in the external file.
+     * This is necessary when running JDK 1.4's javac and probably
+     * others.
+     * @return the exit code of the compilation
+     *
+     * @since Ant 1.6
+     */
+    protected int executeExternalCompile(String[] args, int firstFileName,
+                                         boolean quoteFiles) {
+        String[] commandArray = null;
+        File tmpFile = null;
+
+        try {
+            /*
+             * Many system have been reported to get into trouble with
+             * long command lines - no, not only Windows ;-).
+             *
+             * POSIX seems to define a lower limit of 4k, so use a temporary
+             * file if the total length of the command line exceeds this limit.
+             */
+            if (Commandline.toString(args).length() > COMMAND_LINE_LIMIT
+                && firstFileName >= 0) {
+                PrintWriter out = null;
+                try {
+                    tmpFile = FILE_UTILS.createTempFile(
+                        "files", "", getJavac().getTempdir(), true, true);
+                    out = new PrintWriter(new FileWriter(tmpFile));
+                    for (int i = firstFileName; i < args.length; i++) {
+                        if (quoteFiles && args[i].indexOf(" ") > -1) {
+                            args[i] = args[i].replace(File.separatorChar, '/');
+                            out.println("\"" + args[i] + "\"");
+                        } else {
+                            out.println(args[i]);
+                        }
+                    }
+                    out.flush();
+                    commandArray = new String[firstFileName + 1];
+                    System.arraycopy(args, 0, commandArray, 0, firstFileName);
+                    commandArray[firstFileName] = "@" + tmpFile;
+                } catch (IOException e) {
+                    throw new BuildException("Error creating temporary file",
+                                             e, location);
+                } finally {
+                    FileUtils.close(out);
+                }
+            } else {
+                commandArray = args;
+            }
+
+            try {
+                Execute exe = new Execute(
+                                  new LogStreamHandler(attributes,
+                                                       Project.MSG_INFO,
+                                                       Project.MSG_WARN));
+                if (Os.isFamily("openvms")) {
+                    //Use the VM launcher instead of shell launcher on VMS
+                    //for java
+                    exe.setVMLauncher(true);
+                }
+                exe.setAntRun(project);
+                exe.setWorkingDirectory(project.getBaseDir());
+                exe.setCommandline(commandArray);
+                exe.execute();
+                return exe.getExitValue();
+            } catch (IOException e) {
+                throw new BuildException("Error running " + args[0]
+                        + " compiler", e, location);
+            }
+        } finally {
+            if (tmpFile != null) {
+                tmpFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Add extdirs to classpath
+     * @param classpath the classpath to use
+     * @deprecated since 1.5.x.
+     *             Use org.apache.tools.ant.types.Path#addExtdirs instead.
+     */
+    protected void addExtdirsToClasspath(Path classpath) {
+        classpath.addExtdirs(extdirs);
+    }
+
+    /**
+     * Adds the command line arguments specific to the current implementation.
+     * @param cmd the command line to use
+     */
+    protected void addCurrentCompilerArgs(Commandline cmd) {
+        cmd.addArguments(getJavac().getCurrentCompilerArgs());
+    }
+
+    /**
+     * Shall we assume JDK 1.1 command line switches?
+     * @return true if jdk 1.1
+     * @since Ant 1.5
+     */
+    protected boolean assumeJava11() {
+        return "javac1.1".equals(attributes.getCompilerVersion());
+    }
+
+    /**
+     * Shall we assume JDK 1.2 command line switches?
+     * @return true if jdk 1.2
+     * @since Ant 1.5
+     */
+    protected boolean assumeJava12() {
+        return "javac1.2".equals(attributes.getCompilerVersion())
+            || ("classic".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2))
+            || ("extJavac".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2));
+    }
+
+    /**
+     * Shall we assume JDK 1.3 command line switches?
+     * @return true if jdk 1.3
+     * @since Ant 1.5
+     */
+    protected boolean assumeJava13() {
+        return "javac1.3".equals(attributes.getCompilerVersion())
+            || ("classic".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3))
+            || ("modern".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3))
+            || ("extJavac".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3));
+    }
+
+    /**
+     * Shall we assume JDK 1.4 command line switches?
+     * @return true if jdk 1.4
+     * @since Ant 1.6.3
+     */
+    protected boolean assumeJava14() {
+        return "javac1.4".equals(attributes.getCompilerVersion())
+            || ("classic".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4))
+            || ("modern".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4))
+            || ("extJavac".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_4));
+    }
+
+    /**
+     * Shall we assume JDK 1.5 command line switches?
+     * @return true if JDK 1.5
+     * @since Ant 1.6.3
+     */
+    protected boolean assumeJava15() {
+        return "javac1.5".equals(attributes.getCompilerVersion())
+            || ("classic".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_5))
+            || ("modern".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_5))
+            || ("extJavac".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_5));
+    }
+
+    /**
+     * Shall we assume JDK 1.6 command line switches?
+     * @return true if JDK 1.6
+     * @since Ant 1.7
+     */
+    protected boolean assumeJava16() {
+        return "javac1.6".equals(attributes.getCompilerVersion())
+            || ("classic".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_6))
+            || ("modern".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_6))
+            || ("extJavac".equals(attributes.getCompilerVersion())
+                && JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_6));
+    }
+
+    /**
+     * Combines a user specified bootclasspath with the system
+     * bootclasspath taking build.sysclasspath into account.
+     *
+     * @return a non-null Path instance that combines the user
+     * specified and the system bootclasspath.
+     */
+    protected Path getBootClassPath() {
+        Path bp = new Path(project);
+        if (bootclasspath != null) {
+            bp.append(bootclasspath);
+        }
+        return bp.concatSystemBootClasspath("ignore");
+    }
+
+    /**
+     * The argument the compiler wants to see if the debug attribute
+     * has been set to false.
+     *
+     * <p>A return value of <code>null</code> means no argument at all.</p>
+     *
+     * @return "-g:none" unless we expect to invoke a JDK 1.1 compiler.
+     *
+     * @since Ant 1.6.3
+     */
+    protected String getNoDebugArgument() {
+        return assumeJava11() ? null : "-g:none";
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java
new file mode 100644
index 0000000..160d3fc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Gcj.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the gcj compiler.
+ * This is primarily a cut-and-paste from the jikes.
+ *
+ * @since Ant 1.4
+ */
+public class Gcj extends DefaultCompilerAdapter {
+
+    /**
+     * Performs a compile using the gcj compiler.
+     * @return true if the compilation succeeded
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        Commandline cmd;
+        attributes.log("Using gcj compiler", Project.MSG_VERBOSE);
+        cmd = setupGCJCommand();
+
+        int firstFileName = cmd.size();
+        logAndAddFilesToCompile(cmd);
+
+        return
+            executeExternalCompile(cmd.getCommandline(), firstFileName) == 0;
+    }
+
+    /**
+     * Set up the gcj commandline.
+     * @return the command line
+     */
+    protected Commandline setupGCJCommand() {
+        Commandline cmd = new Commandline();
+        Path classpath = new Path(project);
+
+        // gcj doesn't support bootclasspath dir (-bootclasspath)
+        // so we'll emulate it for compatibility and convenience.
+        Path p = getBootClassPath();
+        if (p.size() > 0) {
+            classpath.append(p);
+        }
+
+        // gcj doesn't support an extension dir (-extdir)
+        // so we'll emulate it for compatibility and convenience.
+        classpath.addExtdirs(extdirs);
+
+        classpath.append(getCompileClasspath());
+
+        // Gcj has no option for source-path so we
+        // will add it to classpath.
+        if (compileSourcepath != null) {
+            classpath.append(compileSourcepath);
+        } else {
+            classpath.append(src);
+        }
+
+        String exec = getJavac().getExecutable();
+        cmd.setExecutable(exec == null ? "gcj" : exec);
+
+        if (destDir != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(destDir);
+
+            if (!destDir.exists() && !destDir.mkdirs()) {
+                throw new BuildException("Can't make output directories. "
+                                         + "Maybe permission is wrong. ");
+            }
+        }
+
+        cmd.createArgument().setValue("-classpath");
+        cmd.createArgument().setPath(classpath);
+
+        if (encoding != null) {
+            cmd.createArgument().setValue("--encoding=" + encoding);
+        }
+        if (debug) {
+            cmd.createArgument().setValue("-g1");
+        }
+        if (optimize) {
+            cmd.createArgument().setValue("-O");
+        }
+
+        /**
+         *  gcj should be set for generate class.
+         * ... if no 'compile to native' argument is passed
+         */
+        if (!isNativeBuild()) {
+            cmd.createArgument().setValue("-C");
+        }
+
+        addCurrentCompilerArgs(cmd);
+
+        return cmd;
+    }
+
+    /**
+     * Whether any of the arguments given via &lt;compilerarg&gt;
+     * implies that compilation to native code is requested.
+     * @return true if compilation to native code is requested
+     * @since Ant 1.6.2
+     */
+    public boolean isNativeBuild() {
+        boolean nativeBuild = false;
+        String[] additionalArguments = getJavac().getCurrentCompilerArgs();
+        int argsLength = 0;
+        while (!nativeBuild && argsLength < additionalArguments.length) {
+            int conflictLength = 0;
+            while (!nativeBuild
+                   && conflictLength < CONFLICT_WITH_DASH_C.length) {
+                nativeBuild = (additionalArguments[argsLength].startsWith
+                               (CONFLICT_WITH_DASH_C[conflictLength]));
+                conflictLength++;
+            }
+            argsLength++;
+        }
+        return nativeBuild;
+    }
+
+    private static final String [] CONFLICT_WITH_DASH_C = {
+        "-o" , "--main=", "-D", "-fjni", "-L"
+    };
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac12.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac12.java
new file mode 100644
index 0000000..290fe70
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac12.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the javac compiler for JDK 1.2
+ * This is primarily a cut-and-paste from the original javac task before it
+ * was refactored.
+ *
+ * @since Ant 1.3
+ */
+public class Javac12 extends DefaultCompilerAdapter {
+    protected static final String CLASSIC_COMPILER_CLASSNAME = "sun.tools.javac.Main";
+
+    /**
+     * Run the compilation.
+     * @return true if the compiler ran with a zero exit result (ok)
+     * @exception BuildException if the compilation has problems.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using classic compiler", Project.MSG_VERBOSE);
+        Commandline cmd = setupJavacCommand(true);
+
+        OutputStream logstr = new LogOutputStream(attributes, Project.MSG_WARN);
+        try {
+            // Create an instance of the compiler, redirecting output to
+            // the project log
+            Class c = Class.forName(CLASSIC_COMPILER_CLASSNAME);
+            Constructor cons =
+                c.getConstructor(new Class[] {OutputStream.class,
+                                              String.class});
+            Object compiler
+                = cons.newInstance(new Object[] {logstr, "javac"});
+
+            // Call the compile() method
+            Method compile = c.getMethod("compile",
+                                         new Class [] {String[].class});
+            Boolean ok =
+                (Boolean) compile.invoke(compiler,
+                                        new Object[] {cmd.getArguments()});
+            return ok.booleanValue();
+        } catch (ClassNotFoundException ex) {
+            throw new BuildException("Cannot use classic compiler , as it is "
+                                        + "not available. \n"
+                                        + " A common solution is "
+                                        + "to set the environment variable"
+                                        + " JAVA_HOME to your jdk directory.\n"
+                                        + "It is currently set to \""
+                                        + JavaEnvUtils.getJavaHome()
+                                        + "\"",
+                                        location);
+        } catch (Exception ex) {
+            if (ex instanceof BuildException) {
+                throw (BuildException) ex;
+            } else {
+                throw new BuildException("Error starting classic compiler: ",
+                                         ex, location);
+            }
+        } finally {
+            FileUtils.close(logstr);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac13.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac13.java
new file mode 100644
index 0000000..300de87
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Javac13.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * The implementation of the javac compiler for JDK 1.3
+ * This is primarily a cut-and-paste from the original javac task before it
+ * was refactored.
+ *
+ * @since Ant 1.3
+ */
+public class Javac13 extends DefaultCompilerAdapter {
+
+    /**
+     * Integer returned by the "Modern" jdk1.3 compiler to indicate success.
+     */
+    private static final int MODERN_COMPILER_SUCCESS = 0;
+
+    /**
+     * Run the compilation.
+     * @return true if the compiler ran with a zero exit result (ok)
+     * @exception BuildException if the compilation has problems.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using modern compiler", Project.MSG_VERBOSE);
+        Commandline cmd = setupModernJavacCommand();
+
+        // Use reflection to be able to build on all JDKs >= 1.1:
+        try {
+            Class c = Class.forName ("com.sun.tools.javac.Main");
+            Object compiler = c.newInstance ();
+            Method compile = c.getMethod ("compile",
+                new Class [] {(new String [] {}).getClass ()});
+            int result = ((Integer) compile.invoke
+                          (compiler, new Object[] {cmd.getArguments()}))
+                .intValue ();
+            return (result == MODERN_COMPILER_SUCCESS);
+        } catch (Exception ex) {
+            if (ex instanceof BuildException) {
+                throw (BuildException) ex;
+            } else {
+                throw new BuildException("Error starting modern compiler",
+                                         ex, location);
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java
new file mode 100644
index 0000000..ddc349e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import java.io.IOException;
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Performs a compile using javac externally.
+ *
+ * @since Ant 1.4
+ */
+public class JavacExternal extends DefaultCompilerAdapter {
+
+    /**
+     * Performs a compile using the Javac externally.
+     * @return true if the compilation succeeded
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using external javac compiler", Project.MSG_VERBOSE);
+
+        Commandline cmd = new Commandline();
+        cmd.setExecutable(getJavac().getJavacExecutable());
+        if (!assumeJava11() && !assumeJava12()) {
+            setupModernJavacCommandlineSwitches(cmd);
+        } else {
+            setupJavacCommandlineSwitches(cmd, true);
+        }
+        int firstFileName = assumeJava11() ? -1 : cmd.size();
+        logAndAddFilesToCompile(cmd);
+        //On VMS platform, we need to create a special java options file
+        //containing the arguments and classpath for the javac command.
+        //The special file is supported by the "-V" switch on the VMS JVM.
+        if (Os.isFamily("openvms")) {
+            return execOnVMS(cmd, firstFileName);
+        }
+        return
+                executeExternalCompile(cmd.getCommandline(), firstFileName,
+                        true)
+                == 0;
+    }
+
+    /**
+     * helper method to execute our command on VMS.
+     * @param cmd
+     * @param firstFileName
+     * @return
+     */
+    private boolean execOnVMS(Commandline cmd, int firstFileName) {
+        File vmsFile = null;
+        try {
+            vmsFile = JavaEnvUtils.createVmsJavaOptionFile(cmd.getArguments());
+            String[] commandLine = {cmd.getExecutable(),
+                                    "-V",
+                                    vmsFile.getPath()};
+            return 0 == executeExternalCompile(commandLine,
+                            firstFileName,
+                            true);
+
+        } catch (IOException e) {
+            throw new BuildException("Failed to create a temporary file for \"-V\" switch");
+        } finally {
+            FileUtils.delete(vmsFile);
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java
new file mode 100644
index 0000000..9356b74
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jikes.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the jikes compiler.
+ * This is primarily a cut-and-paste from the original javac task before it
+ * was refactored.
+ *
+ * @since Ant 1.3
+ */
+public class Jikes extends DefaultCompilerAdapter {
+
+    /**
+     * Performs a compile using the Jikes compiler from IBM.
+     * Mostly of this code is identical to doClassicCompile()
+     * However, it does not support all options like
+     * extdirs, deprecation and so on, because
+     * there is no option in jikes and I don't understand
+     * what they should do.
+     *
+     * It has been successfully tested with jikes &gt;1.10.
+     * @return true if the compilation succeeded
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using jikes compiler", Project.MSG_VERBOSE);
+
+        Commandline cmd = new Commandline();
+
+        // For -sourcepath, use the "sourcepath" value if present.
+        // Otherwise default to the "srcdir" value.
+        Path sourcepath = null;
+        if (compileSourcepath != null) {
+            sourcepath = compileSourcepath;
+        } else {
+            sourcepath = src;
+        }
+        // If the buildfile specifies sourcepath="", then don't
+        // output any sourcepath.
+        if (sourcepath.size() > 0) {
+            cmd.createArgument().setValue("-sourcepath");
+            cmd.createArgument().setPath(sourcepath);
+        }
+
+        Path classpath = new Path(project);
+
+        if (bootclasspath == null || bootclasspath.size() == 0) {
+            // no bootclasspath, therefore, get one from the java runtime
+            includeJavaRuntime = true;
+        } else {
+            // there is a bootclasspath stated.  By default, the
+            // includeJavaRuntime is false.  If the user has stated a
+            // bootclasspath and said to include the java runtime, it's on
+            // their head!
+        }
+        classpath.append(getCompileClasspath());
+
+        // if the user has set JIKESPATH we should add the contents as well
+        String jikesPath = System.getProperty("jikes.class.path");
+        if (jikesPath != null) {
+            classpath.append(new Path(project, jikesPath));
+        }
+
+        if (extdirs != null && extdirs.size() > 0) {
+            cmd.createArgument().setValue("-extdirs");
+            cmd.createArgument().setPath(extdirs);
+        }
+
+        String exec = getJavac().getExecutable();
+        cmd.setExecutable(exec == null ? "jikes" : exec);
+
+        if (deprecation) {
+            cmd.createArgument().setValue("-deprecation");
+        }
+
+        if (destDir != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(destDir);
+        }
+
+        cmd.createArgument().setValue("-classpath");
+        cmd.createArgument().setPath(classpath);
+
+        if (encoding != null) {
+            cmd.createArgument().setValue("-encoding");
+            cmd.createArgument().setValue(encoding);
+        }
+        if (debug) {
+            String debugLevel = attributes.getDebugLevel();
+            if (debugLevel != null) {
+                cmd.createArgument().setValue("-g:" + debugLevel);
+            } else {
+                cmd.createArgument().setValue("-g");
+            }
+        } else {
+            cmd.createArgument().setValue("-g:none");
+        }
+        if (optimize) {
+            cmd.createArgument().setValue("-O");
+        }
+        if (verbose) {
+            cmd.createArgument().setValue("-verbose");
+        }
+        if (depend) {
+            cmd.createArgument().setValue("-depend");
+        }
+
+        if (target != null) {
+            cmd.createArgument().setValue("-target");
+            cmd.createArgument().setValue(target);
+        }
+
+        addPropertyParams(cmd);
+
+        if (attributes.getSource() != null) {
+            cmd.createArgument().setValue("-source");
+            String source = attributes.getSource();
+            if (source.equals("1.1") || source.equals("1.2")) {
+                // support for -source 1.1 and -source 1.2 has been
+                // added with JDK 1.4.2, Jikes doesn't like it
+                attributes.log("Jikes doesn't support '-source " + source
+                        + "', will use '-source 1.3' instead");
+                cmd.createArgument().setValue("1.3");
+            } else {
+                cmd.createArgument().setValue(source);
+            }
+        }
+        addCurrentCompilerArgs(cmd);
+
+        int firstFileName = cmd.size();
+
+        Path boot = getBootClassPath();
+        if (boot.size() > 0) {
+            cmd.createArgument().setValue("-bootclasspath");
+            cmd.createArgument().setPath(boot);
+        }
+        logAndAddFilesToCompile(cmd);
+
+        return executeExternalCompile(cmd.getCommandline(), firstFileName) == 0;
+    }
+
+    private void addPropertyParams(Commandline cmd) {
+        /**
+         * XXX
+         * Perhaps we shouldn't use properties for these
+         * three options (emacs mode, warnings and pedantic),
+         * but include it in the javac directive?
+         */
+
+        /**
+         * Jikes has the nice feature to print error
+         * messages in a form readable by emacs, so
+         * that emacs can directly set the cursor
+         * to the place, where the error occurred.
+         */
+        String emacsProperty = project.getProperty("build.compiler.emacs");
+        if (emacsProperty != null && Project.toBoolean(emacsProperty)) {
+            cmd.createArgument().setValue("+E");
+        }
+
+        /**
+         * Jikes issues more warnings that javac, for
+         * example, when you have files in your classpath
+         * that don't exist. As this is often the case, these
+         * warning can be pretty annoying.
+         */
+        String warningsProperty = project.getProperty("build.compiler.warnings");
+        if (warningsProperty != null) {
+            attributes.log("!! the build.compiler.warnings property is " + "deprecated. !!",
+                    Project.MSG_WARN);
+            attributes.log("!! Use the nowarn attribute instead. !!", Project.MSG_WARN);
+            if (!Project.toBoolean(warningsProperty)) {
+                cmd.createArgument().setValue("-nowarn");
+            }
+        }
+        if (attributes.getNowarn()) {
+            cmd.createArgument().setValue("-nowarn");
+        }
+
+        /**
+         * Jikes can issue pedantic warnings.
+         */
+        String pedanticProperty = project.getProperty("build.compiler.pedantic");
+        if (pedanticProperty != null && Project.toBoolean(pedanticProperty)) {
+            cmd.createArgument().setValue("+P");
+        }
+
+        /**
+         * Jikes supports something it calls "full dependency
+         * checking", see the jikes documentation for differences
+         * between -depend and +F.
+         */
+        String fullDependProperty = project.getProperty("build.compiler.fulldepend");
+        if (fullDependProperty != null
+            && Project.toBoolean(fullDependProperty)) {
+            cmd.createArgument().setValue("+F");
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jvc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jvc.java
new file mode 100644
index 0000000..38586ab
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Jvc.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the jvc compiler from microsoft.
+ * This is primarily a cut-and-paste from the original javac task before it
+ * was refactored.
+ *
+ * @since Ant 1.3
+ */
+public class Jvc extends DefaultCompilerAdapter {
+
+    /**
+     * Run the compilation.
+     * @return true if the compiler ran with a zero exit result (ok)
+     * @exception BuildException if the compilation has problems.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using jvc compiler", Project.MSG_VERBOSE);
+
+        Path classpath = new Path(project);
+
+        // jvc doesn't support bootclasspath dir (-bootclasspath)
+        // so we'll emulate it for compatibility and convenience.
+        Path p = getBootClassPath();
+        if (p.size() > 0) {
+            classpath.append(p);
+        }
+
+        if (includeJavaRuntime) {
+            // jvc doesn't support an extension dir (-extdir)
+            // so we'll emulate it for compatibility and convenience.
+            classpath.addExtdirs(extdirs);
+        }
+
+        classpath.append(getCompileClasspath());
+
+        // jvc has no option for source-path so we
+        // will add it to classpath.
+        if (compileSourcepath != null) {
+            classpath.append(compileSourcepath);
+        } else {
+            classpath.append(src);
+        }
+
+        Commandline cmd = new Commandline();
+        String exec = getJavac().getExecutable();
+        cmd.setExecutable(exec == null ? "jvc" : exec);
+
+        if (destDir != null) {
+            cmd.createArgument().setValue("/d");
+            cmd.createArgument().setFile(destDir);
+        }
+
+        // Add the Classpath before the "internal" one.
+        cmd.createArgument().setValue("/cp:p");
+        cmd.createArgument().setPath(classpath);
+
+        boolean msExtensions = true;
+        String mse = getProject().getProperty("build.compiler.jvc.extensions");
+        if (mse != null) {
+            msExtensions = Project.toBoolean(mse);
+        }
+
+        if (msExtensions) {
+            // Enable MS-Extensions and ...
+            cmd.createArgument().setValue("/x-");
+            // ... do not display a Message about this.
+            cmd.createArgument().setValue("/nomessage");
+        }
+
+        // Do not display Logo
+        cmd.createArgument().setValue("/nologo");
+
+        if (debug) {
+            cmd.createArgument().setValue("/g");
+        }
+        if (optimize) {
+            cmd.createArgument().setValue("/O");
+        }
+        if (verbose) {
+            cmd.createArgument().setValue("/verbose");
+        }
+
+        addCurrentCompilerArgs(cmd);
+
+        int firstFileName = cmd.size();
+        logAndAddFilesToCompile(cmd);
+
+        return
+            executeExternalCompile(cmd.getCommandline(), firstFileName) == 0;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java
new file mode 100644
index 0000000..68b5ba1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Kjc.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the Java compiler for KJC.
+ * This is primarily a cut-and-paste from Jikes.java and
+ * DefaultCompilerAdapter.
+ *
+ * @since Ant 1.4
+ */
+public class Kjc extends DefaultCompilerAdapter {
+
+    /**
+     * Run the compilation.
+     * @return true if the compilation succeeded
+     * @exception BuildException if the compilation has problems.
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using kjc compiler", Project.MSG_VERBOSE);
+        Commandline cmd = setupKjcCommand();
+        cmd.setExecutable("at.dms.kjc.Main");
+        ExecuteJava ej = new ExecuteJava();
+        ej.setJavaCommand(cmd);
+        return ej.fork(getJavac()) == 0;
+    }
+
+    /**
+     * setup kjc command arguments.
+     * @return the command line
+     */
+    protected Commandline setupKjcCommand() {
+        Commandline cmd = new Commandline();
+
+        // generate classpath, because kjc doesn't support sourcepath.
+        Path classpath = getCompileClasspath();
+
+        if (deprecation) {
+            cmd.createArgument().setValue("-deprecation");
+        }
+
+        if (destDir != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(destDir);
+        }
+
+        // generate the clsspath
+        cmd.createArgument().setValue("-classpath");
+
+        Path cp = new Path(project);
+
+        // kjc don't have bootclasspath option.
+        Path p = getBootClassPath();
+        if (p.size() > 0) {
+            cp.append(p);
+        }
+
+        if (extdirs != null) {
+            cp.addExtdirs(extdirs);
+        }
+
+        cp.append(classpath);
+        if (compileSourcepath != null) {
+            cp.append(compileSourcepath);
+        } else {
+            cp.append(src);
+        }
+
+        cmd.createArgument().setPath(cp);
+
+        // kjc-1.5A doesn't support -encoding option now.
+        // but it will be supported near the feature.
+        if (encoding != null) {
+            cmd.createArgument().setValue("-encoding");
+            cmd.createArgument().setValue(encoding);
+        }
+
+        if (debug) {
+            cmd.createArgument().setValue("-g");
+        }
+
+        if (optimize) {
+            cmd.createArgument().setValue("-O2");
+        }
+
+        if (verbose) {
+            cmd.createArgument().setValue("-verbose");
+        }
+
+        addCurrentCompilerArgs(cmd);
+
+        logAndAddFilesToCompile(cmd);
+        return cmd;
+    }
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Sj.java b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Sj.java
new file mode 100644
index 0000000..0dcc0e4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/compilers/Sj.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the sj compiler.
+ * Uses the defaults for DefaultCompilerAdapter
+ *
+ * @since Ant 1.4
+ */
+public class Sj extends DefaultCompilerAdapter {
+
+    /**
+     * Performs a compile using the sj compiler from Symantec.
+     * @return true if the compilation succeeded
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        attributes.log("Using symantec java compiler", Project.MSG_VERBOSE);
+
+        Commandline cmd = setupJavacCommand();
+        String exec = getJavac().getExecutable();
+        cmd.setExecutable(exec == null ? "sj" : exec);
+
+        int firstFileName = cmd.size() - compileList.length;
+
+        return
+            executeExternalCompile(cmd.getCommandline(), firstFileName) == 0;
+    }
+
+    /**
+     * Returns null since sj either has -g for debug=true or no
+     * argument at all.
+     * @return null.
+     * @since Ant 1.6.3
+     */
+    protected String getNoDebugArgument() {
+        return null;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/And.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/And.java
new file mode 100644
index 0000000..aef3ecf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/And.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * &lt;and&gt; condition container.
+ *
+ * <p>Iterates over all conditions and returns false as soon as one
+ * evaluates to false.</p>
+ *
+ * @since Ant 1.4
+ */
+public class And extends ConditionBase implements Condition {
+
+    /**
+     * @return true if all the contained conditions evaluates to true
+     * @exception BuildException if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        Enumeration e = getConditions();
+        while (e.hasMoreElements()) {
+            Condition c = (Condition) e.nextElement();
+            if (!c.eval()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/AntVersion.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/AntVersion.java
new file mode 100644
index 0000000..b220d94
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/AntVersion.java
@@ -0,0 +1,171 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.DeweyDecimal;
+
+/**
+ * An Ant version condition.
+ * @since Ant 1.7
+ */
+public class AntVersion extends Task implements Condition {
+
+    private String atLeast = null;
+    private String exactly = null;
+    private String propertyname = null;
+
+    /**
+     * Run as a task.
+     * @throws BuildException if an error occurs.
+     */
+    public void execute() throws BuildException {
+        if (propertyname == null) {
+            throw new BuildException("'property' must be set.");
+        }
+        if (atLeast != null || exactly != null) {
+            // If condition values are set, evaluate the condition
+            if (eval()) {
+                getProject().setNewProperty(propertyname, getVersion().toString());
+            }
+        } else {
+            // Raw task
+            getProject().setNewProperty(propertyname, getVersion().toString());
+        }
+    }
+
+    /**
+     * Evalute the condition.
+     * @return true if the condition is true.
+     * @throws BuildException if an error occurs.
+     */
+    public boolean eval() throws BuildException {
+        validate();
+        DeweyDecimal actual = getVersion();
+        if (null != atLeast) {
+            return actual.isGreaterThanOrEqual(new DeweyDecimal(atLeast));
+        }
+        if (null != exactly) {
+            return actual.isEqual(new DeweyDecimal(exactly));
+        }
+        //default
+        return false;
+    }
+
+    private void validate() throws BuildException {
+        if (atLeast != null && exactly != null) {
+            throw new BuildException("Only one of atleast or exactly may be set.");
+        }
+        if (null == atLeast && null == exactly) {
+            throw new BuildException("One of atleast or exactly must be set.");
+        }
+        if (atLeast != null) {
+            try {
+                new DeweyDecimal(atLeast);
+            } catch (NumberFormatException e) {
+                throw new BuildException(
+                    "The 'atleast' attribute is not a Dewey Decimal eg 1.1.0 : "
+                    + atLeast);
+            }
+        } else {
+            try {
+                new DeweyDecimal(exactly);
+            } catch (NumberFormatException e) {
+                throw new BuildException(
+                    "The 'exactly' attribute is not a Dewey Decimal eg 1.1.0 : "
+                    + exactly);
+            }
+        }
+    }
+
+    private DeweyDecimal getVersion() {
+        Project p = new Project();
+        p.init();
+        char[] versionString = p.getProperty("ant.version").toCharArray();
+        StringBuffer sb = new StringBuffer();
+        boolean foundFirstDigit = false;
+        for (int i = 0; i < versionString.length; i++) {
+            if (Character.isDigit(versionString[i])) {
+                sb.append(versionString[i]);
+                foundFirstDigit = true;
+            }
+            if (versionString[i] == '.' && foundFirstDigit) {
+                sb.append(versionString[i]);
+            }
+            if (Character.isLetter(versionString[i]) && foundFirstDigit) {
+                break;
+            }
+        }
+        return new DeweyDecimal(sb.toString());
+    }
+
+    /**
+     * Get the atleast attribute.
+     * @return the atleast attribute.
+     */
+    public String getAtLeast() {
+        return atLeast;
+    }
+
+    /**
+     * Set the atleast attribute.
+     * This is of the form major.minor.point.
+     * For example 1.7.0.
+     * @param atLeast the version to check against.
+     */
+    public void setAtLeast(String atLeast) {
+        this.atLeast = atLeast;
+    }
+
+    /**
+     * Get the exactly attribute.
+     * @return the exactly attribute.
+     */
+    public String getExactly() {
+        return exactly;
+    }
+
+    /**
+     * Set the exactly attribute.
+     * This is of the form major.minor.point.
+     * For example 1.7.0.
+     * @param exactly the version to check against.
+     */
+    public void setExactly(String exactly) {
+        this.exactly = exactly;
+    }
+
+    /**
+     * Get the name of the property to hold the ant version.
+     * @return the name of the property.
+     */
+    public String getProperty() {
+        return propertyname;
+    }
+
+    /**
+     * Set the name of the property to hold the ant version.
+     * @param propertyname the name of the property.
+     */
+    public void setProperty(String propertyname) {
+        this.propertyname = propertyname;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Condition.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Condition.java
new file mode 100644
index 0000000..62adbf3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Condition.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Interface for conditions to use inside the &lt;condition&gt; task.
+ *
+ */
+public interface Condition {
+    /**
+     * Is this condition true?
+     * @return true if the condition is true
+     * @exception BuildException if an error occurs
+     */
+    boolean eval() throws BuildException;
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
new file mode 100644
index 0000000..78adf47
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
@@ -0,0 +1,280 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.Available;
+import org.apache.tools.ant.taskdefs.Checksum;
+import org.apache.tools.ant.taskdefs.UpToDate;
+
+/**
+ * Baseclass for the &lt;condition&gt; task as well as several
+ * conditions - ensures that the types of conditions inside the task
+ * and the "container" conditions are in sync.
+ *
+ * @since Ant 1.4
+ */
+public abstract class ConditionBase extends ProjectComponent {
+
+    /**
+     * name of the component
+     */
+    private String taskName = "condition";
+
+    /**
+     *
+     */
+    private Vector conditions = new Vector();
+
+    /**
+     * Simple constructor.
+     */
+    protected ConditionBase() {
+        taskName = "component";
+    }
+
+    /**
+     * Constructor that takes the name of the task in the task name.
+     * @param taskName the name of the task.
+     * @since Ant 1.7
+     */
+    protected ConditionBase(String taskName) {
+        this.taskName = taskName;
+    }
+
+    /**
+     * Count the conditions.
+     *
+     * @return the number of conditions in the container
+     * @since 1.1
+     */
+    protected int countConditions() {
+        return conditions.size();
+    }
+
+    /**
+     * Iterate through all conditions.
+     *
+     * @return an enumeration to use for iteration
+     * @since 1.1
+     */
+    protected final Enumeration getConditions() {
+        return conditions.elements();
+    }
+
+    /**
+     * Sets the name to use in logging messages.
+     *
+     * @param name The name to use in logging messages.
+     *             Should not be <code>null</code>.
+     * @since Ant 1.7
+     */
+    public void setTaskName(String name) {
+        this.taskName = name;
+    }
+
+    /**
+     * Returns the name to use in logging messages.
+     *
+     * @return the name to use in logging messages.
+     * @since Ant 1.7
+     */
+    public String getTaskName() {
+        return taskName;
+    }
+
+    /**
+     * Add an &lt;available&gt; condition.
+     * @param a an available condition
+     * @since 1.1
+     */
+    public void addAvailable(Available a) {
+        conditions.addElement(a);
+    }
+
+    /**
+     * Add an &lt;checksum&gt; condition.
+     *
+     * @param c a Checksum condition
+     * @since 1.4, Ant 1.5
+     */
+    public void addChecksum(Checksum c) {
+        conditions.addElement(c);
+    }
+
+    /**
+     * Add an &lt;uptodate&gt; condition.
+     *
+     * @param u an UpToDate condition
+     * @since 1.1
+     */
+    public void addUptodate(UpToDate u) {
+        conditions.addElement(u);
+    }
+
+    /**
+     * Add an &lt;not&gt; condition "container".
+     *
+     * @param n a Not condition
+     * @since 1.1
+     */
+    public void addNot(Not n) {
+        conditions.addElement(n);
+    }
+
+    /**
+     * Add an &lt;and&gt; condition "container".
+     *
+     * @param a an And condition
+     * @since 1.1
+     */
+    public void addAnd(And a) {
+        conditions.addElement(a);
+    }
+
+    /**
+     * Add an &lt;or&gt; condition "container".
+     *
+     * @param o an Or condition
+     * @since 1.1
+     */
+    public void addOr(Or o) {
+        conditions.addElement(o);
+    }
+
+    /**
+     * Add an &lt;equals&gt; condition.
+     *
+     * @param e an Equals condition
+     * @since 1.1
+     */
+    public void addEquals(Equals e) {
+        conditions.addElement(e);
+    }
+
+    /**
+     * Add an &lt;os&gt; condition.
+     *
+     * @param o an Os condition
+     * @since 1.1
+     */
+    public void addOs(Os o) {
+        conditions.addElement(o);
+    }
+
+    /**
+     * Add an &lt;isset&gt; condition.
+     *
+     * @param i an IsSet condition
+     * @since Ant 1.5
+     */
+    public void addIsSet(IsSet i) {
+        conditions.addElement(i);
+    }
+
+    /**
+     * Add an &lt;http&gt; condition.
+     *
+     * @param h an Http condition
+     * @since Ant 1.5
+     */
+    public void addHttp(Http h) {
+        conditions.addElement(h);
+    }
+
+    /**
+     * Add a &lt;socket&gt; condition.
+     *
+     * @param s a Socket condition
+     * @since Ant 1.5
+     */
+    public void addSocket(Socket s) {
+        conditions.addElement(s);
+    }
+
+    /**
+     * Add a &lt;filesmatch&gt; condition.
+     *
+     * @param test a FilesMatch condition
+     * @since Ant 1.5
+     */
+    public void addFilesMatch(FilesMatch test) {
+        conditions.addElement(test);
+    }
+
+    /**
+     * Add a &lt;contains&gt; condition.
+     *
+     * @param test a Contains condition
+     * @since Ant 1.5
+     */
+    public void addContains(Contains test) {
+        conditions.addElement(test);
+    }
+
+    /**
+     * Add a &lt;istrue&gt; condition.
+     *
+     * @param test an IsTrue condition
+     * @since Ant 1.5
+     */
+    public void addIsTrue(IsTrue test) {
+        conditions.addElement(test);
+    }
+
+    /**
+     * Add a &lt;isfalse&gt; condition.
+     *
+     * @param test an IsFalse condition
+     * @since Ant 1.5
+     */
+    public void addIsFalse(IsFalse test) {
+        conditions.addElement(test);
+    }
+
+    /**
+     * Add an &lt;isreference&gt; condition.
+     *
+     * @param i an IsReference condition
+     * @since Ant 1.6
+     */
+    public void addIsReference(IsReference i) {
+        conditions.addElement(i);
+    }
+
+    /**
+     * Add an &lt;isfileselected&gt; condition.
+     * @param test the condition
+     */
+    public void addIsFileSelected(IsFileSelected test) {
+        conditions.addElement(test);
+    }
+
+    /**
+     * Add an arbitrary condition
+     * @param c a condition
+     * @since Ant 1.6
+     */
+    public void add(Condition c) {
+        conditions.addElement(c);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Contains.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Contains.java
new file mode 100644
index 0000000..8830a39
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Contains.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Is one string part of another string?
+ *
+ *
+ * @since Ant 1.5
+ */
+public class Contains implements Condition {
+
+    private String string, subString;
+    private boolean caseSensitive = true;
+
+    /**
+     * The string to search in.
+     * @param string the string to search in
+     * @since Ant 1.5
+     */
+    public void setString(String string) {
+        this.string = string;
+    }
+
+    /**
+     * The string to search for.
+     * @param subString the string to search for
+     * @since Ant 1.5
+     */
+    public void setSubstring(String subString) {
+        this.subString = subString;
+    }
+
+    /**
+     * Whether to search ignoring case or not.
+     * @param b if false, ignore case
+     * @since Ant 1.5
+     */
+    public void setCasesensitive(boolean b) {
+        caseSensitive = b;
+    }
+
+    /**
+     * @since Ant 1.5
+     * @return true if the substring is within the string
+     * @exception BuildException if the attributes are not set correctly
+     */
+    public boolean eval() throws BuildException {
+        if (string == null || subString == null) {
+            throw new BuildException("both string and substring are required "
+                                     + "in contains");
+        }
+
+        return caseSensitive
+            ? string.indexOf(subString) > -1
+            : string.toLowerCase().indexOf(subString.toLowerCase()) > -1;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Equals.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Equals.java
new file mode 100644
index 0000000..d214550
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Equals.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Simple comparison condition.
+ *
+ * @since Ant 1.4
+ */
+public class Equals implements Condition {
+    private static final int REQUIRED = 1 | 2;
+
+    private Object arg1, arg2;
+    private boolean trim = false;
+    private boolean caseSensitive = true;
+    private int args;
+
+    /**
+     * Set the first argument
+     * @param arg1 the first argument.
+     * @since Ant 1.8
+     */
+    public void setArg1(Object arg1) {
+        if (arg1 instanceof String) {
+            setArg1((String) arg1);
+        } else {
+            setArg1Internal(arg1);
+        }
+    }
+
+    /**
+     * Set the first string
+     *
+     * @param a1 the first string
+     */
+    public void setArg1(String a1) {
+        setArg1Internal(a1);
+    }
+
+    private void setArg1Internal(Object arg1) {
+        this.arg1 = arg1;
+        args |= 1;
+    }
+
+    /**
+     * Set the second argument
+     * @param arg2 the second argument.
+     * @since Ant 1.8
+     */
+    public void setArg2(Object arg2) {
+        if (arg2 instanceof String) {
+            setArg2((String) arg2);
+        } else {
+            setArg2Internal(arg2);
+        }
+    }
+
+    /**
+     * Set the second string
+     *
+     * @param a2 the second string
+     */
+    public void setArg2(String a2) {
+        setArg2Internal(a2);
+    }
+
+    private void setArg2Internal(Object arg2) {
+        this.arg2 = arg2;
+        args |= 2;
+    }
+
+    /**
+     * Should we want to trim the arguments before comparing them?
+     * @param b if true trim the arguments
+     * @since Ant 1.5
+     */
+    public void setTrim(boolean b) {
+        trim = b;
+    }
+
+    /**
+     * Should the comparison be case sensitive?
+     * @param b if true use a case sensitive comparison (this is the
+     *          default)
+     * @since Ant 1.5
+     */
+    public void setCasesensitive(boolean b) {
+        caseSensitive = b;
+    }
+
+    /**
+     * @return true if the two strings are equal
+     * @exception BuildException if the attributes are not set correctly
+     */
+    public boolean eval() throws BuildException {
+        if ((args & REQUIRED) != REQUIRED) {
+            throw new BuildException("both arg1 and arg2 are required in equals");
+        }
+
+        if (arg1 instanceof String && trim) {
+            arg1 = ((String) arg1).trim();
+        }
+        if (arg2 instanceof String && trim) {
+            arg2 = ((String) arg2).trim();
+        }
+        if (arg1 instanceof String && arg2 instanceof String) {
+            String s1 = (String) arg1;
+            String s2 = (String) arg2;
+            return caseSensitive ? s1.equals(s2) : s1.equalsIgnoreCase(s2);
+        }
+        return arg1 == arg2 || arg1 != null && arg1.equals(arg2);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/FilesMatch.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/FilesMatch.java
new file mode 100644
index 0000000..57faf7d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/FilesMatch.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ package org.apache.tools.ant.taskdefs.condition;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Compares two files for equality based on size and
+ * content. Timestamps are not at all looked at.
+ *
+ * @since Ant 1.5
+ */
+
+public class FilesMatch implements Condition {
+
+    /**
+     * Helper that provides the file comparison method.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * files to compare
+     */
+    private File file1, file2;
+
+    private boolean textfile = false;
+
+
+    /**
+     * Sets the File1 attribute
+     *
+     * @param file1 The new File1 value
+     */
+    public void setFile1(File file1) {
+        this.file1 = file1;
+    }
+
+
+    /**
+     * Sets the File2 attribute
+     *
+     * @param file2 The new File2 value
+     */
+    public void setFile2(File file2) {
+        this.file2 = file2;
+    }
+
+    /**
+     * Set whether to ignore line endings when comparing files.
+     * @param textfile whether to ignore line endings.
+     */
+    public void setTextfile(boolean textfile) {
+        this.textfile = textfile;
+    }
+
+    /**
+     * comparison method of the interface
+     *
+     * @return true if the files are equal
+     * @exception BuildException if it all went pear-shaped
+     */
+    public boolean eval()
+        throws BuildException {
+
+        //validate
+        if (file1 == null || file2 == null) {
+            throw new BuildException("both file1 and file2 are required in "
+                                     + "filesmatch");
+        }
+
+        //#now match the files
+        boolean matches = false;
+        try {
+            matches = FILE_UTILS.contentEquals(file1, file2, textfile);
+        } catch (IOException ioe) {
+            throw new BuildException("when comparing files: "
+                + ioe.getMessage(), ioe);
+        }
+        return matches;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasFreeSpace.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasFreeSpace.java
new file mode 100644
index 0000000..7afe87f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasFreeSpace.java
@@ -0,0 +1,101 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+

+package org.apache.tools.ant.taskdefs.condition;

+

+import java.io.File;

+

+import org.apache.tools.ant.BuildException;

+import org.apache.tools.ant.util.JavaEnvUtils;

+import org.apache.tools.ant.util.ReflectWrapper;

+import org.apache.tools.ant.util.StringUtils;

+

+/**

+ * &lt;hasfreespace&gt;

+ * <p>Condition returns true if selected partition

+ * has the requested space, false otherwise.</p>

+ * @since Ant 1.7

+ */

+public class HasFreeSpace implements Condition {

+

+    private String partition;

+    private String needed;

+

+    /**

+     * Evaluate the condition.

+     * @return true if there enough free space.

+     * @throws BuildException if there is a problem.

+     */

+    public boolean eval() throws BuildException {

+        validate();

+        try {

+            if (JavaEnvUtils.isAtLeastJavaVersion("1.6")) {

+                //reflection to avoid bootstrap/build problems

+                File fs = new File(partition);

+                ReflectWrapper w = new ReflectWrapper(fs);

+                long free = ((Long) w.invoke("getFreeSpace")).longValue();

+                return free >= StringUtils.parseHumanSizes(needed);

+            } else {

+                throw new BuildException("HasFreeSpace condition not supported on Java5 or less.");

+            }

+        } catch (Exception e) {

+            throw new BuildException(e);

+        }

+    }

+

+    private void validate() throws BuildException {

+        if (null == partition) {

+            throw new BuildException("Please set the partition attribute.");

+        }

+        if (null == needed) {

+            throw new BuildException("Please set the needed attribute.");

+        }

+    }

+

+    /**

+     * The partition/device to check

+     * @return the partition.

+     */

+    public String getPartition() {

+        return partition;

+    }

+

+    /**

+     * Set the partition name.

+     * @param partition the name to use.

+     */

+    public void setPartition(String partition) {

+        this.partition = partition;

+    }

+

+    /**

+     * The amount of free space required

+     * @return the amount required

+     */

+    public String getNeeded() {

+        return needed;

+    }

+

+    /**

+     * Set the amount of space required.

+     * @param needed the amount required.

+     */

+    public void setNeeded(String needed) {

+        this.needed = needed;

+    }

+}

diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasMethod.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasMethod.java
new file mode 100644
index 0000000..ddc73d7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/HasMethod.java
@@ -0,0 +1,183 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+
+/**
+ * test for a method
+ */
+public class HasMethod extends ProjectComponent implements Condition {
+    private String classname;
+    private String method;
+    private String field;
+    private Path classpath;
+    private AntClassLoader loader;
+    private boolean ignoreSystemClasses = false;
+
+
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        createClasspath().append(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Set the classname attribute.
+     * @param classname the name of the class to check.
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * Set the name of the method.
+     * @param method the name of the method to check.
+     */
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    /**
+     * Set the name of the field.
+     * @param field the name of the field to check.
+     */
+    public void setField(String field) {
+        this.field = field;
+    }
+
+    /**
+     * Set whether to ignore system classes when looking for the class.
+     * @param ignoreSystemClasses a <code>boolean</code> value.
+     */
+    public void setIgnoreSystemClasses(boolean ignoreSystemClasses) {
+        this.ignoreSystemClasses = ignoreSystemClasses;
+    }
+
+    /**
+     * Check if a given class can be loaded.
+     */
+    private Class loadClass(String classname) {
+        try {
+            if (ignoreSystemClasses) {
+                loader = getProject().createClassLoader(classpath);
+                loader.setParentFirst(false);
+                loader.addJavaLibraries();
+                if (loader != null) {
+                    try {
+                        return loader.findClass(classname);
+                    } catch (SecurityException se) {
+                        // class found but restricted name; this is
+                        // actually the case we're looking for in JDK 1.3+,
+                        // so catch the exception and return
+                        return null;
+                    }
+                } else {
+                    return null;
+                }
+            } else if (loader != null) {
+                return loader.loadClass(classname);
+            } else {
+                ClassLoader l = this.getClass().getClassLoader();
+                // Can return null to represent the bootstrap class loader.
+                // see API docs of Class.getClassLoader.
+                if (l != null) {
+                    return Class.forName(classname, true, l);
+                } else {
+                    return Class.forName(classname);
+                }
+            }
+        } catch (ClassNotFoundException e) {
+            throw new BuildException("class \"" + classname + "\" was not found");
+        } catch (NoClassDefFoundError e) {
+            throw new BuildException("Could not load dependent class \"" + e.getMessage()
+                    + "\" for class \"" + classname + "\"");
+        }
+    }
+
+
+    /** {@inheritDoc}. */
+    public boolean eval() throws BuildException {
+        if (classname == null) {
+            throw new BuildException("No classname defined");
+        }
+        Class clazz = loadClass(classname);
+        if (method != null) {
+            return isMethodFound(clazz);
+        }
+        if (field != null) {
+            return isFieldFound(clazz);
+        }
+        throw new BuildException("Neither method nor field defined");
+    }
+
+    private boolean isFieldFound(Class clazz) {
+        Field[] fields = clazz.getDeclaredFields();
+        for (int i = 0; i < fields.length; i++) {
+            Field fieldEntry = fields[i];
+            if (fieldEntry.getName().equals(field)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isMethodFound(Class clazz) {
+        Method[] methods = clazz.getDeclaredMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method methodEntry = methods[i];
+            if (methodEntry.getName().equals(method)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Http.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Http.java
new file mode 100644
index 0000000..e0ef3ce
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Http.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Condition to wait for a HTTP request to succeed. Its attribute(s) are:
+ *   url - the URL of the request.
+ *   errorsBeginAt - number at which errors begin at; default=400.
+ * @since Ant 1.5
+ */
+public class Http extends ProjectComponent implements Condition {
+    private static final int ERROR_BEGINS = 400;
+    private String spec = null;
+
+    /**
+     * Set the url attribute
+     * @param url the url of the request
+     */
+    public void setUrl(String url) {
+        spec = url;
+    }
+
+    private int errorsBeginAt = ERROR_BEGINS;
+
+    /**
+     * Set the errorsBeginAt attribute
+     * @param errorsBeginAt number at which errors begin at, default is
+     *                      400
+     */
+    public void setErrorsBeginAt(int errorsBeginAt) {
+        this.errorsBeginAt = errorsBeginAt;
+    }
+
+    /**
+     * @return true if the HTTP request succeeds
+     * @exception BuildException if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        if (spec == null) {
+            throw new BuildException("No url specified in http condition");
+        }
+        log("Checking for " + spec, Project.MSG_VERBOSE);
+        try {
+            URL url = new URL(spec);
+            try {
+                URLConnection conn = url.openConnection();
+                if (conn instanceof HttpURLConnection) {
+                    HttpURLConnection http = (HttpURLConnection) conn;
+                    int code = http.getResponseCode();
+                    log("Result code for " + spec + " was " + code,
+                        Project.MSG_VERBOSE);
+                    if (code > 0 && code < errorsBeginAt) {
+                        return true;
+                    }
+                    return false;
+                }
+            } catch (java.io.IOException e) {
+                return false;
+            }
+        } catch (MalformedURLException e) {
+            throw new BuildException("Badly formed URL: " + spec, e);
+        }
+        return true;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFailure.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFailure.java
new file mode 100755
index 0000000..b0ffb9e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFailure.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.taskdefs.Execute;
+
+/**
+ * Condition to test a return-code for failure.
+ * @since Ant 1.7
+ */
+public class IsFailure implements Condition {
+    private int code;
+
+    /**
+     * Set the return code to check.
+     * @param c the return code.
+     */
+    public void setCode(int c) {
+        code = c;
+    }
+
+    /**
+     * Get the return code that will be checked by this IsFailure condition.
+     * @return return code as int.
+     */
+    public int getCode() {
+        return code;
+    }
+
+    /**
+     * Fulfill the condition interface.
+     * @return the result of evaluating the specified return code.
+     */
+    public boolean eval() {
+        return Execute.isFailure(code);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFalse.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFalse.java
new file mode 100644
index 0000000..0b3e69b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFalse.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Condition that tests whether a given string evals to false
+ *
+ * @since Ant 1.5
+ */
+public class IsFalse extends ProjectComponent implements Condition {
+    /**
+     * what we eval
+     */
+    private Boolean value = null;
+
+    /**
+     * set the value to be tested; let ant eval it to true/false
+     * @param value the value to test
+     */
+    public void setValue(boolean value) {
+        this.value = value ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * @return the inverted value;
+     * @throws BuildException if someone forgot to spec a value
+     */
+    public boolean eval() throws BuildException {
+        if (value == null) {
+            throw new BuildException("Nothing to test for falsehood");
+        }
+        return !value.booleanValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFileSelected.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFileSelected.java
new file mode 100644
index 0000000..cbf7021
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsFileSelected.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import java.io.File;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.AbstractSelectorContainer;
+
+/**
+ * This is a condition that checks to see if a file passes an embedded selector.
+ */
+public class IsFileSelected extends AbstractSelectorContainer implements Condition {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File file;
+    private File baseDir;
+
+    /**
+     * The file to check.
+     * @param file the file to check if if passes the embedded selector.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * The base directory to use.
+     * @param baseDir the base directory to use, if null use the project's
+     *                basedir.
+     */
+    public void setBaseDir(File baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * validate the parameters.
+     */
+    public void validate() {
+        if (selectorCount() != 1) {
+            throw new BuildException("Only one selector allowed");
+        }
+        super.validate();
+    }
+
+    /**
+     * Evaluate the selector with the file.
+     * @return true if the file is selected by the embedded selector.
+     */
+    public boolean eval() {
+        if (file == null) {
+            throw new BuildException("file attribute not set");
+        }
+        validate();
+        File myBaseDir = baseDir;
+        if (myBaseDir == null) {
+            myBaseDir = getProject().getBaseDir();
+        }
+
+        FileSelector f = getSelectors(getProject())[0];
+        return f.isSelected(
+            myBaseDir, FILE_UTILS.removeLeadingPath(myBaseDir, file), file);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReachable.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReachable.java
new file mode 100644
index 0000000..fed4994
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReachable.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+
+/**
+ * Test for a host being reachable using ICMP "ping" packets & echo operations.
+ * Ping packets are very reliable for assessing reachability in a LAN or WAN,
+ * but they do not get through any well-configured firewall. Echo (port 7) may.
+ * <p/>
+ * This condition turns unknown host exceptions into false conditions. This is
+ * because on a laptop, DNS is one of the first services lost when the network
+ * goes; you are implicitly offline.
+ * <p/>
+ * If a URL is supplied instead of a host, the hostname is extracted and used in
+ * the test--all other parts of the URL are discarded.
+ * <p/>
+ * The test may not work through firewalls; that is, something may be reachable
+ * using a protocol such as HTTP, while the lower level ICMP packets get dropped
+ * on the floor. Similarly, a host may be detected as reachable with ICMP, but not
+ * reachable on other ports (i.e. port 80), because of firewalls.
+ * <p/>
+ * Requires Java1.5+ to work properly. On Java1.4 and earlier, if a hostname
+ * can be resolved, the destination is assumed to be reachable.
+ *
+ * @since Ant 1.7
+ */
+public class IsReachable extends ProjectComponent implements Condition {
+
+    private static final int SECOND = 1000; // millis per second
+    private String host;
+    private String url;
+
+    /**
+     * The default timeout.
+     */
+    public static final int DEFAULT_TIMEOUT = 30;
+    private int timeout = DEFAULT_TIMEOUT;
+    /**
+     * Error when no hostname is defined
+     */
+    public static final String ERROR_NO_HOSTNAME = "No hostname defined";
+    /**
+     * Error when invalid timeout value is defined
+     */
+    public static final String ERROR_BAD_TIMEOUT = "Invalid timeout value";
+    /**
+     * Unknown host message is seen.
+     */
+    private static final String WARN_UNKNOWN_HOST = "Unknown host: ";
+    /**
+     * Network error message is seen.
+     */
+    public static final String ERROR_ON_NETWORK = "network error to ";
+    /** Error message when url and host are specified. */
+    public static final String ERROR_BOTH_TARGETS
+        = "Both url and host have been specified";
+    /** Error message when no reachably test avail. */
+    public static final String MSG_NO_REACHABLE_TEST
+        = "cannot do a proper reachability test on this Java version";
+    /** Error message when an invalid url is used. */
+    public static final String ERROR_BAD_URL = "Bad URL ";
+    /** Error message when no hostname in url. */
+    public static final String ERROR_NO_HOST_IN_URL = "No hostname in URL ";
+    /** The method name to look for in InetAddress */
+    public static final String METHOD_NAME = "isReachable";
+
+    /**
+     * Set the host to ping.
+     *
+     * @param host the host to ping.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Set the URL from which to extract the hostname.
+     *
+     * @param url a URL object.
+     */
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * Set the timeout for the reachability test in seconds.
+     *
+     * @param timeout the timeout in seconds.
+     */
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * emptyness test
+     *
+     * @param string param to check
+     *
+     * @return true if it is empty
+     */
+    private boolean empty(String string) {
+        return string == null || string.length() == 0;
+    }
+
+    private static Class[] parameterTypes = {Integer.TYPE};
+
+    /**
+     * Evaluate the condition.
+     *
+     * @return true if the condition is true.
+     *
+     * @throws org.apache.tools.ant.BuildException
+     *          if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        if (empty(host) && empty(url)) {
+            throw new BuildException(ERROR_NO_HOSTNAME);
+        }
+        if (timeout < 0) {
+            throw new BuildException(ERROR_BAD_TIMEOUT);
+        }
+        String target = host;
+        if (!empty(url)) {
+            if (!empty(host)) {
+                throw new BuildException(ERROR_BOTH_TARGETS);
+            }
+            try {
+                //get the host of a url
+                URL realURL = new URL(url);
+                target = realURL.getHost();
+                if (empty(target)) {
+                    throw new BuildException(ERROR_NO_HOST_IN_URL + url);
+                }
+            } catch (MalformedURLException e) {
+                throw new BuildException(ERROR_BAD_URL + url, e);
+            }
+        }
+        log("Probing host " + target, Project.MSG_VERBOSE);
+        InetAddress address;
+        try {
+            address = InetAddress.getByName(target);
+        } catch (UnknownHostException e1) {
+            log(WARN_UNKNOWN_HOST + target);
+            return false;
+        }
+        log("Host address = " + address.getHostAddress(),
+                Project.MSG_VERBOSE);
+        boolean reachable;
+        //Java1.5: reachable = address.isReachable(timeout * 1000);
+        Method reachableMethod = null;
+        try {
+            reachableMethod = InetAddress.class.getMethod(METHOD_NAME,
+                    parameterTypes);
+            Object[] params = new Object[1];
+            params[0] = new Integer(timeout * SECOND);
+            try {
+                reachable = ((Boolean) reachableMethod.invoke(address, params))
+                        .booleanValue();
+            } catch (IllegalAccessException e) {
+                //utterly implausible, but catered for anyway
+                throw new BuildException("When calling " + reachableMethod);
+            } catch (InvocationTargetException e) {
+                //assume this is an IOexception about un readability
+                Throwable nested = e.getTargetException();
+                log(ERROR_ON_NETWORK + target + ": " + nested.toString());
+                //any kind of fault: not reachable.
+                reachable = false;
+            }
+        } catch (NoSuchMethodException e) {
+            //java1.4 or earlier
+            log("Not found: InetAddress." + METHOD_NAME, Project.MSG_VERBOSE);
+            log(MSG_NO_REACHABLE_TEST);
+            reachable = true;
+
+        }
+
+        log("host is" + (reachable ? "" : " not") + " reachable", Project.MSG_VERBOSE);
+        return reachable;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReference.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReference.java
new file mode 100644
index 0000000..836d437
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsReference.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Condition that tests whether a given reference has been defined.
+ *
+ * <p>Optionally tests whether it is of a given type/class.</p>
+ *
+ * @since Ant 1.6
+ */
+public class IsReference extends ProjectComponent implements Condition {
+    private Reference ref;
+    private String type;
+
+    /**
+     * Set the refid attribute.
+     *
+     * @param r a Reference value
+     */
+    public void setRefid(Reference r) {
+        ref = r;
+    }
+
+    /**
+     * Set the type attribute. This is optional attribute.
+     *
+     * @param type an ant component type name
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * @return true if the reference exists and if type is set, if
+     *              the reference is the same type
+     * @exception BuildException if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        if (ref == null) {
+            throw new BuildException("No reference specified for isreference "
+                                     + "condition");
+        }
+
+        Object o = getProject().getReference(ref.getRefId());
+
+        if (o == null) {
+            return false;
+        } else if (type == null) {
+            return true;
+        } else {
+            Class typeClass =
+                (Class) getProject().getDataTypeDefinitions().get(type);
+
+            if (typeClass == null) {
+                typeClass =
+                    (Class) getProject().getTaskDefinitions().get(type);
+            }
+
+            if (typeClass == null) {
+                // don't know the type, should throw exception instead?
+                return false;
+            }
+
+            return typeClass.isAssignableFrom(o.getClass());
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSet.java
new file mode 100644
index 0000000..d4a5914
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSet.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Condition that tests whether a given property has been set.
+ *
+ * @since Ant 1.5
+ */
+public class IsSet extends ProjectComponent implements Condition {
+    private String property;
+
+    /**
+     * Set the property attribute
+     *
+     * @param p the property name
+     */
+    public void setProperty(String p) {
+        property = p;
+    }
+
+    /**
+     * @return true if the property exists
+     * @exception BuildException if the property attribute is not set
+     */
+    public boolean eval() throws BuildException {
+        if (property == null) {
+            throw new BuildException("No property specified for isset " + "condition");
+        }
+        return getProject().getProperty(property) != null;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSigned.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSigned.java
new file mode 100644
index 0000000..59d5a3a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsSigned.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipFile;
+
+/**
+ * Checks whether a jarfile is signed: if the name of the
+ * signature is passed, the file is checked for presence of that
+ * particular signature; otherwise the file is checked for the
+ * existence of any signature.
+ */
+public class IsSigned extends DataType implements Condition {
+
+    private static final String SIG_START = "META-INF/";
+    private static final String SIG_END = ".SF";
+    private static final int    SHORT_SIG_LIMIT = 8;
+
+    private String name;
+    private File file;
+
+    /**
+     * The jarfile that is to be tested for the presence
+     * of a signature.
+     * @param file jarfile to be tested.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+   /**
+     * The signature name to check jarfile for.
+     * @param name signature to look for.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns <code>true</code> if the file exists and is signed with
+     * the signature specified, or, if <code>name</code> wasn't
+     * specified, if the file contains a signature.
+     * @param zipFile the zipfile to check
+     * @param name the signature to check (may be killed)
+     * @return true if the file is signed.
+     * @throws IOException on error
+     */
+    public static boolean isSigned(File zipFile, String name)
+        throws IOException {
+        ZipFile jarFile = null;
+        try {
+            jarFile = new ZipFile(zipFile);
+            if (null == name) {
+                Enumeration entries = jarFile.getEntries();
+                while (entries.hasMoreElements()) {
+                    String eName = ((ZipEntry) entries.nextElement()).getName();
+                    if (eName.startsWith(SIG_START)
+                        && eName.endsWith(SIG_END)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+            boolean shortSig = jarFile.getEntry(SIG_START
+                        + name.toUpperCase()
+                        + SIG_END) != null;
+            boolean longSig = false;
+            if (name.length() > SHORT_SIG_LIMIT) {
+                longSig = jarFile.getEntry(
+                    SIG_START
+                    + name.substring(0, SHORT_SIG_LIMIT).toUpperCase()
+                    + SIG_END) != null;
+            }
+
+            return shortSig || longSig;
+        } finally {
+            ZipFile.closeQuietly(jarFile);
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if the file exists and is signed with
+     * the signature specified, or, if <code>name</code> wasn't
+     * specified, if the file contains a signature.
+     * @return true if the file is signed.
+     */
+    public boolean eval() {
+        if (file == null) {
+            throw new BuildException("The file attribute must be set.");
+        }
+        if (!file.exists()) {
+            log("The file \"" + file.getAbsolutePath()
+                + "\" does not exist.", Project.MSG_VERBOSE);
+            return false;
+        }
+
+        boolean r = false;
+        try {
+            r = isSigned(file, name);
+        } catch (IOException e) {
+            log("Got IOException reading file \"" + file.getAbsolutePath()
+                + "\"" + e, Project.MSG_WARN);
+        }
+
+        if (r) {
+            log("File \"" + file.getAbsolutePath() + "\" is signed.",
+                Project.MSG_VERBOSE);
+        }
+        return r;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsTrue.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsTrue.java
new file mode 100644
index 0000000..753b441
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/IsTrue.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Condition that tests whether a given string evals to true
+ *
+ * @since Ant 1.5
+ */
+public class IsTrue extends ProjectComponent implements Condition {
+    /**
+     * what we eval
+     */
+    private Boolean value = null;
+
+    /**
+     * set the value to be tested; let ant eval it to true/false
+     * @param value the value to test
+     */
+    public void setValue(boolean value) {
+        this.value = value ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * @return the value
+     * @throws BuildException if someone forgot to spec a value
+     */
+    public boolean eval() throws BuildException {
+        if (value == null) {
+            throw new BuildException("Nothing to test for truth");
+        }
+        return value.booleanValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Matches.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Matches.java
new file mode 100644
index 0000000..9a97441
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Matches.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.regexp.Regexp;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+
+/**
+ * Simple regular expression condition.
+ *
+ * @since Ant 1.7
+ */
+public class Matches extends ProjectComponent implements Condition {
+
+    private String  string;
+    private boolean caseSensitive = true;
+    private boolean multiLine = false;
+    private boolean singleLine = false;
+    private RegularExpression regularExpression;
+
+    /**
+     * Set the string
+     *
+     * @param string the string to match
+     */
+    public void setString(String string) {
+        this.string = string;
+    }
+
+    /**
+     * Set the regular expression to match against
+     *
+     * @param pattern the regular expression pattern
+     */
+    public void setPattern(String pattern) {
+        if (regularExpression != null) {
+            throw new BuildException(
+                "Only one regular expression is allowed.");
+        }
+        regularExpression = new RegularExpression();
+        regularExpression.setPattern(pattern);
+    }
+
+    /**
+     * A regular expression.
+     * You can use this element to refer to a previously
+     * defined regular expression datatype instance
+     * @param regularExpression the regular expression object
+     *                          to be configured as an element
+     */
+    public void addRegexp(RegularExpression regularExpression) {
+        if (this.regularExpression != null) {
+            throw new BuildException(
+                "Only one regular expression is allowed.");
+        }
+        this.regularExpression = regularExpression;
+    }
+
+    /**
+     * Whether to ignore case or not.
+     * @param b if false, ignore case.
+     * @since Ant 1.7
+     */
+    public void setCasesensitive(boolean b) {
+        caseSensitive = b;
+    }
+
+    /**
+     * Whether to match should be multiline.
+     * @param b the value to set.
+     */
+    public void setMultiline(boolean b) {
+        multiLine = b;
+    }
+
+    /**
+     * Whether to treat input as singleline ('.' matches newline).
+     * Corresponsds to java.util.regex.Pattern.DOTALL.
+     * @param b the value to set.
+     */
+    public void setSingleLine(boolean b) {
+        singleLine = b;
+    }
+
+    /**
+     * @return true if the string matches the regular expression pattern
+     * @exception BuildException if the attributes are not set correctly
+     */
+    public boolean eval() throws BuildException {
+        if (string == null) {
+            throw new BuildException(
+                "Parameter string is required in matches.");
+        }
+        if (regularExpression == null) {
+            throw new BuildException("Missing pattern in matches.");
+        }
+        int options = RegexpMatcher.MATCH_DEFAULT;
+        if (!caseSensitive) {
+            options = options | RegexpMatcher.MATCH_CASE_INSENSITIVE;
+        }
+        if (multiLine) {
+            options = options | RegexpMatcher.MATCH_MULTILINE;
+        }
+        if (singleLine) {
+            options = options | RegexpMatcher.MATCH_SINGLELINE;
+        }
+        Regexp regexp = regularExpression.getRegexp(getProject());
+        return regexp.matches(string, options);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Not.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Not.java
new file mode 100644
index 0000000..a39dcbb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Not.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * &lt;not&gt; condition.
+ *
+ * Evaluates to true if the single condition nested into it is false
+ * and vice versa.
+ *
+ * @since Ant 1.4
+ */
+public class Not extends ConditionBase implements Condition {
+
+    /**
+     * Evaluate condition
+     *
+     * @return true if the condition is true.
+     * @throws BuildException if the condition is not configured correctly.
+     */
+    public boolean eval() throws BuildException {
+        if (countConditions() > 1) {
+            throw new BuildException("You must not nest more than one "
+                + "condition into <not>");
+        }
+        if (countConditions() < 1) {
+            throw new BuildException("You must nest a condition into <not>");
+        }
+        return !((Condition) getConditions().nextElement()).eval();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Or.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Or.java
new file mode 100644
index 0000000..5566eb2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Or.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * &lt;or&gt; condition container.
+ *
+ * <p>Iterates over all conditions and returns true as soon as one
+ * evaluates to true.</p>
+ *
+ * @since Ant 1.4
+ */
+public class Or extends ConditionBase implements Condition {
+
+    /**
+     * @return true if any of the contained conditions evaluate to true
+     * @exception BuildException if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        Enumeration e = getConditions();
+        while (e.hasMoreElements()) {
+            Condition c = (Condition) e.nextElement();
+            if (c.eval()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Os.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Os.java
new file mode 100644
index 0000000..5059185
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Os.java
@@ -0,0 +1,312 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.util.Locale;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Condition that tests the OS type.
+ *
+ * @since Ant 1.4
+ */
+public class Os implements Condition {
+    private static final String OS_NAME =
+        System.getProperty("os.name").toLowerCase(Locale.US);
+    private static final String OS_ARCH =
+        System.getProperty("os.arch").toLowerCase(Locale.US);
+    private static final String OS_VERSION =
+        System.getProperty("os.version").toLowerCase(Locale.US);
+    private static final String PATH_SEP =
+        System.getProperty("path.separator");
+
+    /**
+     * OS family to look for
+     */
+    private String family;
+    /**
+     * Name of OS
+     */
+    private String name;
+    /**
+     * version of OS
+     */
+    private String version;
+    /**
+     * OS architecture
+     */
+    private String arch;
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_WINDOWS = "windows";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_9X = "win9x";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_NT = "winnt";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_OS2 = "os/2";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_NETWARE = "netware";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_DOS = "dos";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_MAC = "mac";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_TANDEM = "tandem";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_UNIX = "unix";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_VMS = "openvms";
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_ZOS = "z/os";
+    /** OS family that can be tested for. {@value} */
+    public static final String FAMILY_OS400 = "os/400";
+
+    /**
+     * Default constructor
+     *
+     */
+    public Os() {
+        //default
+    }
+
+    /**
+     * Constructor that sets the family attribute
+     * @param family a String value
+     */
+    public Os(String family) {
+        setFamily(family);
+    }
+
+    /**
+     * Sets the desired OS family type
+     *
+     * @param f      The OS family type desired<br />
+     *               Possible values:<br />
+     *               <ul>
+     *               <li>dos</li>
+     *               <li>mac</li>
+     *               <li>netware</li>
+     *               <li>os/2</li>
+     *               <li>tandem</li>
+     *               <li>unix</li>
+     *               <li>windows</li>
+     *               <li>win9x</li>
+     *               <li>z/os</li>
+     *               <li>os/400</li>
+     *               </ul>
+     */
+    public void setFamily(String f) {
+        family = f.toLowerCase(Locale.US);
+    }
+
+    /**
+     * Sets the desired OS name
+     *
+     * @param name   The OS name
+     */
+    public void setName(String name) {
+        this.name = name.toLowerCase(Locale.US);
+    }
+
+    /**
+     * Sets the desired OS architecture
+     *
+     * @param arch   The OS architecture
+     */
+    public void setArch(String arch) {
+        this.arch = arch.toLowerCase(Locale.US);
+    }
+
+    /**
+     * Sets the desired OS version
+     *
+     * @param version   The OS version
+     */
+    public void setVersion(String version) {
+        this.version = version.toLowerCase(Locale.US);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the type of
+     * that set in setFamily.
+     * @return true if the os matches.
+     * @throws BuildException if there is an error.
+     * @see Os#setFamily(String)
+     */
+    public boolean eval() throws BuildException {
+        return isOs(family, name, arch, version);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the
+     * given OS family.
+     * @param family the family to check for
+     * @return true if the OS matches
+     * @since 1.5
+     */
+    public static boolean isFamily(String family) {
+        return isOs(family, null, null, null);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the
+     * given OS name.
+     *
+     * @param name the OS name to check for
+     * @return true if the OS matches
+     * @since 1.7
+     */
+    public static boolean isName(String name) {
+        return isOs(null, name, null, null);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the
+     * given OS architecture.
+     *
+     * @param arch the OS architecture to check for
+     * @return true if the OS matches
+     * @since 1.7
+     */
+    public static boolean isArch(String arch) {
+        return isOs(null, null, arch, null);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the
+     * given OS version.
+     *
+     * @param version the OS version to check for
+     * @return true if the OS matches
+     * @since 1.7
+     */
+    public static boolean isVersion(String version) {
+        return isOs(null, null, null, version);
+    }
+
+    /**
+     * Determines if the OS on which Ant is executing matches the
+     * given OS family, name, architecture and version
+     *
+     * @param family   The OS family
+     * @param name   The OS name
+     * @param arch   The OS architecture
+     * @param version   The OS version
+     * @return true if the OS matches
+     * @since 1.7
+     */
+    public static boolean isOs(String family, String name, String arch,
+                               String version) {
+        boolean retValue = false;
+
+        if (family != null || name != null || arch != null
+            || version != null) {
+
+            boolean isFamily = true;
+            boolean isName = true;
+            boolean isArch = true;
+            boolean isVersion = true;
+
+            if (family != null) {
+
+                //windows probing logic relies on the word 'windows' in
+                //the OS
+                boolean isWindows = OS_NAME.indexOf(FAMILY_WINDOWS) > -1;
+                boolean is9x = false;
+                boolean isNT = false;
+                if (isWindows) {
+                    //there are only four 9x platforms that we look for
+                    is9x = (OS_NAME.indexOf("95") >= 0
+                            || OS_NAME.indexOf("98") >= 0
+                            || OS_NAME.indexOf("me") >= 0
+                            //wince isn't really 9x, but crippled enough to
+                            //be a muchness. Ant doesnt run on CE, anyway.
+                            || OS_NAME.indexOf("ce") >= 0);
+                    isNT = !is9x;
+                }
+                if (family.equals(FAMILY_WINDOWS)) {
+                    isFamily = isWindows;
+                } else if (family.equals(FAMILY_9X)) {
+                    isFamily = isWindows && is9x;
+                } else if (family.equals(FAMILY_NT)) {
+                    isFamily = isWindows && isNT;
+                } else if (family.equals(FAMILY_OS2)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_OS2) > -1;
+                } else if (family.equals(FAMILY_NETWARE)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_NETWARE) > -1;
+                } else if (family.equals(FAMILY_DOS)) {
+                    isFamily = PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE);
+                } else if (family.equals(FAMILY_MAC)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_MAC) > -1;
+                } else if (family.equals(FAMILY_TANDEM)) {
+                    isFamily = OS_NAME.indexOf("nonstop_kernel") > -1;
+                } else if (family.equals(FAMILY_UNIX)) {
+                    isFamily = PATH_SEP.equals(":")
+                        && !isFamily(FAMILY_VMS)
+                        && (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x"));
+                } else if (family.equals(FAMILY_ZOS)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_ZOS) > -1
+                        || OS_NAME.indexOf("os/390") > -1;
+                } else if (family.equals(FAMILY_OS400)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_OS400) > -1;
+                } else if (family.equals(FAMILY_VMS)) {
+                    isFamily = OS_NAME.indexOf(FAMILY_VMS) > -1;
+                } else {
+                    throw new BuildException(
+                        "Don\'t know how to detect os family \""
+                        + family + "\"");
+                }
+            }
+            if (name != null) {
+                isName = name.equals(OS_NAME);
+            }
+            if (arch != null) {
+                isArch = arch.equals(OS_ARCH);
+            }
+            if (version != null) {
+                isVersion = version.equals(OS_VERSION);
+            }
+            retValue = isFamily && isName && isArch && isVersion;
+        }
+        return retValue;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ParserSupports.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ParserSupports.java
new file mode 100644
index 0000000..5b41af3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ParserSupports.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.JAXPUtils;
+
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Test for the XML parser supporting a particular feature
+ * @since Ant 1.7
+ */
+public class ParserSupports extends ProjectComponent implements Condition {
+
+    private String feature;
+    private String property;
+    private String value;
+    // Error messages
+    /** error - combined attributes not allowed */
+    public static final String ERROR_BOTH_ATTRIBUTES =
+            "Property and feature attributes are exclusive";
+    /** feature */
+    public static final String FEATURE = "feature";
+    /** property */
+    public static final String PROPERTY = "property";
+
+    /** error - not recognized */
+    public static final String NOT_RECOGNIZED =
+            " not recognized: ";
+    /** error - not supported */
+    public static final String NOT_SUPPORTED =
+            " not supported: ";
+    /** error - missing attribute */
+    public static final String ERROR_NO_ATTRIBUTES =
+        "Neither feature or property are set";
+    /** error - no value */
+    public static final String ERROR_NO_VALUE =
+        "A value is needed when testing for property support";
+
+    /**
+     * Feature to probe for.
+     * @param feature the feature to probe for.
+     */
+    public void setFeature(String feature) {
+        this.feature = feature;
+    }
+
+    /**
+     * Property to probe for
+     * @param property the property to probe for.
+     */
+    public void setProperty(String property) {
+        this.property = property;
+    }
+
+    /**
+     * Optional value to set.
+     * Converted to a boolean value when setting a property
+     * @param value the value to set.
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /** {@inheritDoc}. */
+    public boolean eval() throws BuildException {
+        if (feature != null && property != null) {
+            throw new BuildException(ERROR_BOTH_ATTRIBUTES);
+        }
+        if (feature == null && property == null) {
+            throw new BuildException(ERROR_NO_ATTRIBUTES);
+        }
+        //pick a value that is good for everything
+        if (feature != null) {
+            return evalFeature();
+        }
+        if (value == null) {
+            throw new BuildException(ERROR_NO_VALUE);
+        }
+        return evalProperty();
+    }
+
+    /**
+     * Get our reader
+     * @return a reader
+     */
+    private XMLReader getReader() {
+        JAXPUtils.getParser();
+        return JAXPUtils.getXMLReader();
+    }
+
+    /**
+     * Set a feature
+     * @return true if the feature could be set
+     */
+    public boolean evalFeature() {
+        XMLReader reader = getReader();
+        if (value == null) {
+            value = "true";
+        }
+        boolean v = Project.toBoolean(value);
+        try {
+            reader.setFeature(feature, v);
+        } catch (SAXNotRecognizedException e) {
+            log(FEATURE + NOT_RECOGNIZED + feature, Project.MSG_VERBOSE);
+            return false;
+        } catch (SAXNotSupportedException e) {
+            log(FEATURE + NOT_SUPPORTED + feature, Project.MSG_VERBOSE);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Set a property
+     * @return true if the feature could be set
+     */
+    public boolean evalProperty() {
+        XMLReader reader = getReader();
+        try {
+            reader.setProperty(property, value);
+        } catch (SAXNotRecognizedException e) {
+            log(PROPERTY + NOT_RECOGNIZED + property, Project.MSG_VERBOSE);
+            return false;
+        } catch (SAXNotSupportedException e) {
+            log(PROPERTY + NOT_SUPPORTED + property, Project.MSG_VERBOSE);
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourceContains.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourceContains.java
new file mode 100644
index 0000000..f636ad0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourceContains.java
@@ -0,0 +1,165 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant.taskdefs.condition;

+

+import java.io.BufferedReader;

+import java.io.File;

+import java.io.IOException;

+import java.io.InputStreamReader;

+

+import org.apache.tools.ant.BuildException;

+import org.apache.tools.ant.Project;

+import org.apache.tools.ant.types.Resource;

+import org.apache.tools.ant.types.ResourceCollection;

+import org.apache.tools.ant.types.resources.FileResource;

+import org.apache.tools.ant.util.FileUtils;

+

+/**

+ * &lt;resourcecontains&gt;

+ * Is a string contained in a resource (file currently)?

+ * @since Ant 1.7.1

+ */

+public class ResourceContains implements Condition {

+

+    private Project project;

+    private String substring;

+    private Resource resource;

+    private String refid;

+    private boolean casesensitive = true;

+

+    /**

+     * Set this condition's Project.

+     * @param project Project

+     */

+    public void setProject(Project project) {

+        this.project = project;

+    }

+

+    /**

+     * Get this condition's Project.

+     * @return Project

+     */

+    public Project getProject() {

+        return project;

+    }

+

+    /**

+     * Sets the resource to search

+     * @param r the value to use.

+     */

+    public void setResource(String r) {

+        this.resource = new FileResource(new File(r));

+    }

+

+    /**

+     * Sets the refid to search; should indicate a resource directly

+     * or by way of a single-element ResourceCollection.

+     * @param refid the value to use.

+     */

+    public void setRefid(String refid) {

+        this.refid = refid;

+    }

+

+    private void resolveRefid() {

+        try {

+            if (getProject() == null) {

+                throw new BuildException("Cannot retrieve refid; project unset");

+            }

+            Object o = getProject().getReference(refid);

+            if (!(o instanceof Resource)) {

+                if (o instanceof ResourceCollection) {

+                    ResourceCollection rc = (ResourceCollection) o;

+                    if (rc.size() == 1) {

+                        o = rc.iterator().next();

+                    }

+                } else {

+                    throw new BuildException(

+                        "Illegal value at '" + refid + "': " + String.valueOf(o));

+                }

+            }

+            this.resource = (Resource) o;

+        } finally {

+            refid = null;

+        }

+    }

+

+    /**

+     * Sets the substring to look for

+     * @param substring the value to use.

+     */

+    public void setSubstring(String substring) {

+        this.substring = substring;

+    }

+

+    /**

+     * Sets case sensitivity attribute.

+     * @param casesensitive the value to use.

+     */

+    public void setCasesensitive(boolean casesensitive) {

+        this.casesensitive = casesensitive;

+    }

+

+    private void validate() {

+        if (resource != null && refid != null) {

+            throw new BuildException("Cannot set both resource and refid");

+        }

+        if (resource == null && refid != null) {

+            resolveRefid();

+        }

+        if (resource == null || substring == null) {

+            throw new BuildException("both resource and substring are required "

+                                     + "in <resourcecontains>");

+        }

+    }

+

+    /**

+     * Evaluates the condition.

+     * @return true if the substring is contained in the resource

+     * @throws BuildException if there is a problem.

+     */

+    public synchronized boolean eval() throws BuildException {

+        validate();

+

+        if (substring.length() == 0) {

+            if (getProject() != null) {

+                getProject().log("Substring is empty; returning true",

+                                 Project.MSG_VERBOSE);

+            }

+            return true;

+        }

+        if (resource.getSize() == 0) {

+            return false;

+        }

+

+        BufferedReader reader = null;

+        try {

+            reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));

+            String contents = FileUtils.safeReadFully(reader);

+            String sub = substring;

+            if (!casesensitive) {

+                contents = contents.toLowerCase();

+                sub = sub.toLowerCase();

+            }

+            return contents.indexOf(sub) >= 0;

+        } catch (IOException e) {

+            throw new BuildException("There was a problem accessing resource : " + resource);

+        } finally {

+            FileUtils.close(reader);

+        }

+    }

+}

diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourcesMatch.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourcesMatch.java
new file mode 100644
index 0000000..bc764fb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/ResourcesMatch.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.ResourceUtils;
+
+/**
+ * Compares resources for equality based on size and content.
+ * All resources specified must match; no resource collections
+ * specified is an error condition; if resource collections are
+ * specified, but yield fewer than two elements, the condition
+ * evaluates to <code>true</code>.
+ * @since Ant 1.7
+ */
+public class ResourcesMatch implements Condition {
+
+    private Union resources = null;
+    private boolean asText = false;
+
+    /**
+     * Set whether to treat resources as if they were text files,
+     * ignoring line endings.
+     * @param asText whether to ignore line endings.
+     */
+    public void setAsText(boolean asText) {
+        this.asText = asText;
+    }
+
+    /**
+     * Add a resource collection.
+     * @param rc the resource collection to add.
+     */
+    public void add(ResourceCollection rc) {
+        if (rc == null) {
+            return;
+        }
+        resources = resources == null ? new Union() : resources;
+        resources.add(rc);
+    }
+
+    /**
+     * Verify that all resources match.
+     * @return true if all resources are equal.
+     * @exception BuildException if there is an error.
+     */
+    public boolean eval() throws BuildException {
+        if (resources == null) {
+            throw new BuildException(
+                "You must specify one or more nested resource collections");
+        }
+        if (resources.size() > 1) {
+            Iterator i = resources.iterator();
+            Resource r1 = (Resource) i.next();
+            Resource r2 = null;
+
+            while (i.hasNext()) {
+                r2 = (Resource) i.next();
+                try {
+                    if (!ResourceUtils.contentEquals(r1, r2, asText)) {
+                        return false;
+                    }
+                } catch (IOException ioe) {
+                    throw new BuildException("when comparing resources "
+                        + r1.toString() + " and " + r2.toString(), ioe);
+                }
+                r1 = r2;
+            }
+        }
+        return true;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Socket.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Socket.java
new file mode 100644
index 0000000..24137e0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Socket.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Condition to wait for a TCP/IP socket to have a listener. Its attributes are:
+ *   server - the name of the server.
+ *   port - the port number of the socket.
+ *
+ * @since Ant 1.5
+ */
+public class Socket extends ProjectComponent implements Condition {
+    private String server = null;
+    private int port = 0;
+
+    /**
+     * Set the server attribute
+     *
+     * @param server the server name
+     */
+    public void setServer(String server) {
+        this.server = server;
+    }
+
+    /**
+     * Set the port attribute
+     *
+     * @param port the port number of the socket
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * @return true if a socket can be created
+     * @exception BuildException if the attributes are not set
+     */
+    public boolean eval() throws BuildException {
+        if (server == null) {
+            throw new BuildException("No server specified in socket "
+                                     + "condition");
+        }
+        if (port == 0) {
+            throw new BuildException("No port specified in socket condition");
+        }
+        log("Checking for listener at " + server + ":" + port,
+            Project.MSG_VERBOSE);
+        java.net.Socket s = null;
+        try {
+            s = new java.net.Socket(server, port);
+        } catch (IOException e) {
+            return false;
+        } finally {
+          if (s != null) {
+            try {
+              s.close();
+            } catch (IOException ioe) {
+              // Intentionally left blank
+            }
+          }
+        }
+        return true;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/TypeFound.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/TypeFound.java
new file mode 100644
index 0000000..b69b852
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/TypeFound.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.Project;
+
+/**
+ * looks for a task or other Ant type that exists. Existence is defined as
+ * the type is defined, and its implementation class is present. This
+ * will work for datatypes and preset, script and macro definitions.
+ */
+public class TypeFound extends ProjectComponent implements Condition {
+
+    private String name;
+    private String uri;
+
+    /**
+     * the task or other type to look for
+     * @param name the name of the type
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * The URI for this definition.
+     * @param uri the namespace URI. If this is not set, use the
+     *            default ant namespace.
+     */
+    public void setURI(String uri) {
+        this.uri = uri;
+    }
+
+    /**
+     * test for a task or other ant type existing in the current project
+     * @param typename the name of the type
+     * @return true if the typename exists
+     */
+    protected boolean doesTypeExist(String typename) {
+
+        ComponentHelper helper =
+            ComponentHelper.getComponentHelper(getProject());
+        String componentName = ProjectHelper.genComponentName(uri, typename);
+        AntTypeDefinition def = helper.getDefinition(componentName);
+        if (def == null) {
+            return false;
+        }
+        //now verify that the class has an implementation
+        boolean found = def.getExposedClass(getProject()) != null;
+        if (!found) {
+            String text = helper.diagnoseCreationFailure(componentName, "type");
+            log(text, Project.MSG_VERBOSE);
+        }
+        return found;
+    }
+
+
+    /**
+     * Is this condition true?
+     * @return true if the condition is true
+     * @exception BuildException if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        if (name == null) {
+            throw new BuildException("No type specified");
+        }
+        return doesTypeExist(name);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Xor.java b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Xor.java
new file mode 100644
index 0000000..9f14bdb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/condition/Xor.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildException;
+
+import java.util.Enumeration;
+
+/**
+ * The <tt>Xor</tt> condition type to exclusive or operations.
+ * This does not shortcut stuff.
+ * @since Ant 1.7
+ */
+public class Xor extends ConditionBase implements Condition {
+
+    /**
+     * Evaluate the contained conditions.
+     * @return the result of xoring the conditions together.
+     * @throws org.apache.tools.ant.BuildException
+     *          if an error occurs.
+     */
+    public boolean eval() throws BuildException {
+        Enumeration e = getConditions();
+        //initial state is false.
+        boolean state = false;
+        while (e.hasMoreElements()) {
+            Condition c = (Condition) e.nextElement();
+            //every condition is xored against the previous one
+            state ^= c.eval();
+        }
+        return state;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CVSEntry.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CVSEntry.java
new file mode 100644
index 0000000..b1a9a12
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CVSEntry.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.util.Date;
+import java.util.Vector;
+
+/**
+ * CVS Entry.
+ *
+ */
+public class CVSEntry {
+    private Date date;
+    private String author;
+    private final String comment;
+    private final Vector files = new Vector();
+
+    /**
+     * Creates a new instance of a CVSEntry
+     * @param date the date
+     * @param author the author
+     * @param comment a comment to be added to the revision
+     */
+    public CVSEntry(final Date date, final String author, final String comment) {
+        this.date = date;
+        this.author = author;
+        this.comment = comment;
+    }
+
+    /**
+     * Adds a file to the CVSEntry
+     * @param file the file to add
+     * @param revision the revision
+     */
+    public void addFile(final String file, final String revision) {
+        files.addElement(new RCSFile(file, revision));
+    }
+
+    /**
+     * Adds a file to the CVSEntry
+     * @param file the file to add
+     * @param revision the revision
+     * @param previousRevision the previous revision
+     */
+    public void addFile(final String file, final String revision, final String previousRevision) {
+        files.addElement(new RCSFile(file, revision, previousRevision));
+    }
+
+    /**
+     * Gets the date of the CVSEntry
+     * @return the date
+     */
+    public Date getDate() {
+        return date;
+    }
+
+    /**
+     * Sets the author of the CVSEntry
+     * @param author the author
+     */
+    public void setAuthor(final String author) {
+        this.author = author;
+    }
+
+    /**
+     * Gets the author of the CVSEntry
+     * @return the author
+     */
+    public String getAuthor() {
+        return author;
+    }
+
+    /**
+     * Gets the comment for the CVSEntry
+     * @return the comment
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Gets the files in this CVSEntry
+     * @return the files
+     */
+    public Vector getFiles() {
+        return files;
+    }
+
+    /**
+     * Gets a String containing author, date, files and comment
+     * @return a string representation of this CVSEntry
+     */
+    public String toString() {
+        return getAuthor() + "\n" + getDate() + "\n" + getFiles() + "\n"
+            + getComment();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java
new file mode 100644
index 0000000..a1f0336
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParser.java
@@ -0,0 +1,266 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * A class used to parse the output of the CVS log command.
+ *
+ */
+class ChangeLogParser {
+    //private static final int GET_ENTRY = 0;
+    private static final int GET_FILE = 1;
+    private static final int GET_DATE = 2;
+    private static final int GET_COMMENT = 3;
+    private static final int GET_REVISION = 4;
+    private static final int GET_PREVIOUS_REV = 5;
+
+// FIXME formatters are not thread-safe
+
+    /** input format for dates read in from cvs log */
+    private static final SimpleDateFormat INPUT_DATE
+        = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.US);
+    /**
+     * New formatter used to parse CVS date/timestamp.
+     */
+    private static final SimpleDateFormat CVS1129_INPUT_DATE =
+        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
+
+    static {
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        INPUT_DATE.setTimeZone(utc);
+        CVS1129_INPUT_DATE.setTimeZone(utc);
+    }
+
+    //The following is data used while processing stdout of CVS command
+    private String file;
+    private String date;
+    private String author;
+    private String comment;
+    private String revision;
+    private String previousRevision;
+
+    private int status = GET_FILE;
+
+    /** rcs entries */
+    private final Hashtable entries = new Hashtable();
+
+    /**
+     * Get a list of rcs entries as an array.
+     *
+     * @return a list of rcs entries as an array
+     */
+    public CVSEntry[] getEntrySetAsArray() {
+        final CVSEntry[] array = new CVSEntry[ entries.size() ];
+        int i = 0;
+        for (Enumeration e = entries.elements(); e.hasMoreElements();) {
+            array[i++] = (CVSEntry) e.nextElement();
+        }
+        return array;
+    }
+
+    /**
+     * Receive notification about the process writing
+     * to standard output.
+     * @param line the line to process
+     */
+    public void stdout(final String line) {
+        switch(status) {
+            case GET_FILE:
+                // make sure attributes are reset when
+                // working on a 'new' file.
+                reset();
+                processFile(line);
+                break;
+            case GET_REVISION:
+                processRevision(line);
+                break;
+
+            case GET_DATE:
+                processDate(line);
+                break;
+
+            case GET_COMMENT:
+                processComment(line);
+                break;
+
+            case GET_PREVIOUS_REV:
+                processGetPreviousRevision(line);
+                break;
+
+            default:
+                // Do nothing
+                break;
+        }
+    }
+
+    /**
+     * Process a line while in "GET_COMMENT" state.
+     *
+     * @param line the line
+     */
+    private void processComment(final String line) {
+        final String lineSeparator = System.getProperty("line.separator");
+        if (line.equals(
+                "=============================================================================")) {
+            //We have ended changelog for that particular file
+            //so we can save it
+            final int end
+                = comment.length() - lineSeparator.length(); //was -1
+            comment = comment.substring(0, end);
+            saveEntry();
+            status = GET_FILE;
+        } else if (line.equals("----------------------------")) {
+            final int end
+                = comment.length() - lineSeparator.length(); //was -1
+            comment = comment.substring(0, end);
+            status = GET_PREVIOUS_REV;
+        } else {
+            comment += line + lineSeparator;
+        }
+    }
+
+    /**
+     * Process a line while in "GET_FILE" state.
+     *
+     * @param line the line to process
+     */
+    private void processFile(final String line) {
+        if (line.startsWith("Working file:")) {
+            // CheckStyle:MagicNumber OFF
+            file = line.substring(14, line.length());
+            // CheckStyle:MagicNumber ON
+            status = GET_REVISION;
+        }
+    }
+
+    /**
+     * Process a line while in "REVISION" state.
+     *
+     * @param line the line to process
+     */
+    private void processRevision(final String line) {
+        if (line.startsWith("revision")) {
+            // CheckStyle:MagicNumber OFF
+            revision = line.substring(9);
+            // CheckStyle:MagicNumber ON
+            status = GET_DATE;
+        } else if (line.startsWith("======")) {
+            //There were no revisions in this changelog
+            //entry so lets move onto next file
+            status = GET_FILE;
+        }
+    }
+
+    /**
+     * Process a line while in "DATE" state.
+     *
+     * @param line the line to process
+     */
+    private void processDate(final String line) {
+        if (line.startsWith("date:")) {
+            // The date format is using a - format since 1.12.9 so we have:
+            // 1.12.9-: 'date: YYYY/mm/dd HH:mm:ss;  author: name;'
+            // 1.12.9+: 'date: YYYY-mm-dd HH:mm:ss Z;  author: name'
+            int endOfDateIndex = line.indexOf(';');
+            date = line.substring("date: ".length(), endOfDateIndex);
+
+            int startOfAuthorIndex = line.indexOf("author: ", endOfDateIndex + 1);
+            int endOfAuthorIndex = line.indexOf(';', startOfAuthorIndex + 1);
+            author = line.substring("author: ".length() + startOfAuthorIndex, endOfAuthorIndex);
+
+            status = GET_COMMENT;
+
+            //Reset comment to empty here as we can accumulate multiple lines
+            //in the processComment method
+            comment = "";
+        }
+    }
+
+    /**
+     * Process a line while in "GET_PREVIOUS_REVISION" state.
+     *
+     * @param line the line to process
+     */
+    private void processGetPreviousRevision(final String line) {
+        if (!line.startsWith("revision ")) {
+            throw new IllegalStateException("Unexpected line from CVS: "
+                + line);
+        }
+        previousRevision = line.substring("revision ".length());
+
+        saveEntry();
+
+        revision = previousRevision;
+        status = GET_DATE;
+    }
+
+    /**
+     * Utility method that saves the current entry.
+     */
+    private void saveEntry() {
+        final String entryKey = date + author + comment;
+        CVSEntry entry;
+        if (!entries.containsKey(entryKey)) {
+            Date dateObject = parseDate(date);
+            entry = new CVSEntry(dateObject, author, comment);
+            entries.put(entryKey, entry);
+        } else {
+            entry = (CVSEntry) entries.get(entryKey);
+        }
+
+        entry.addFile(file, revision, previousRevision);
+    }
+
+    /**
+     * Parse date out from expected format.
+     *
+     * @param date the string holding date
+     * @return the date object or null if unknown date format
+     */
+    private Date parseDate(final String date) {
+        try {
+            return INPUT_DATE.parse(date);
+        } catch (ParseException e) {
+            try {
+                return CVS1129_INPUT_DATE.parse(date);
+            } catch (ParseException e2) {
+                throw new IllegalStateException("Invalid date format: " + date);
+            }
+        }
+    }
+
+    /**
+     * Reset all internal attributes except status.
+     */
+    public void reset() {
+        this.file = null;
+        this.date = null;
+        this.author = null;
+        this.comment = null;
+        this.revision = null;
+        this.previousRevision = null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogTask.java
new file mode 100644
index 0000000..e829090
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogTask.java
@@ -0,0 +1,421 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.AbstractCvsTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Examines the output of cvs log and group related changes together.
+ *
+ * It produces an XML output representing the list of changes.
+ * <pre>
+ * <font color=#0000ff>&lt;!-- Root element --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> changelog <font color=#ff00ff>
+ * (entry</font><font color=#ff00ff>+</font><font color=#ff00ff>)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- CVS Entry --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> entry <font color=#ff00ff>
+ * (date,author,file</font><font color=#ff00ff>+</font><font color=#ff00ff>,msg)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- Date of cvs entry --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> date <font color=#ff00ff>(#PCDATA)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- Author of change --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> author <font color=#ff00ff>(#PCDATA)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- List of files affected --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> msg <font color=#ff00ff>(#PCDATA)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- File changed --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> file <font color=#ff00ff>
+ * (name,revision,prevrevision</font><font color=#ff00ff>?</font>
+ * <font color=#ff00ff>)</font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- Name of the file --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> name <font color=#ff00ff>(#PCDATA)
+ * </font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- Revision number --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> revision <font color=#ff00ff>
+ * (#PCDATA)</font><font color=#6a5acd>&gt;</font>
+ * <font color=#0000ff>&lt;!-- Previous revision number --&gt;</font>
+ * <font color=#6a5acd>&lt;!ELEMENT</font> prevrevision <font color=#ff00ff>
+ * (#PCDATA)</font><font color=#6a5acd>&gt;</font>
+ * </pre>
+ *
+ * @since Ant 1.5
+ * @ant.task name="cvschangelog" category="scm"
+ */
+public class ChangeLogTask extends AbstractCvsTask {
+    /** User list */
+    private File usersFile;
+
+    /** User list */
+    private Vector cvsUsers = new Vector();
+
+    /** Input dir */
+    private File inputDir;
+
+    /** Output file */
+    private File destFile;
+
+    /** The earliest date at which to start processing entries.  */
+    private Date startDate;
+
+    /** The latest date at which to stop processing entries.  */
+    private Date endDate;
+
+    /**
+     * Filesets containing list of files against which the cvs log will be
+     * performed. If empty then all files in the working directory will
+     * be checked.
+     */
+    private final Vector filesets = new Vector();
+
+
+    /**
+     * Set the base dir for cvs.
+     *
+     * @param inputDir The new dir value
+     */
+    public void setDir(final File inputDir) {
+        this.inputDir = inputDir;
+    }
+
+
+    /**
+     * Set the output file for the log.
+     *
+     * @param destFile The new destfile value
+     */
+    public void setDestfile(final File destFile) {
+        this.destFile = destFile;
+    }
+
+
+    /**
+     * Set a lookup list of user names & addresses
+     *
+     * @param usersFile The file containing the users info.
+     */
+    public void setUsersfile(final File usersFile) {
+        this.usersFile = usersFile;
+    }
+
+
+    /**
+     * Add a user to list changelog knows about.
+     *
+     * @param user the user
+     */
+    public void addUser(final CvsUser user) {
+        cvsUsers.addElement(user);
+    }
+
+
+    /**
+     * Set the date at which the changelog should start.
+     *
+     * @param start The date at which the changelog should start.
+     */
+    public void setStart(final Date start) {
+        this.startDate = start;
+    }
+
+
+    /**
+     * Set the date at which the changelog should stop.
+     *
+     * @param endDate The date at which the changelog should stop.
+     */
+    public void setEnd(final Date endDate) {
+        this.endDate = endDate;
+    }
+
+
+    /**
+     * Set the number of days worth of log entries to process.
+     *
+     * @param days the number of days of log to process.
+     */
+    public void setDaysinpast(final int days) {
+        // CheckStyle:MagicNumber OFF
+        final long time = System.currentTimeMillis()
+             - (long) days * 24 * 60 * 60 * 1000;
+        // CheckStyle:MagicNumber ON
+
+        setStart(new Date(time));
+    }
+
+
+    /**
+     * Adds a set of files about which cvs logs will be generated.
+     *
+     * @param fileSet a set of files about which cvs logs will be generated.
+     */
+    public void addFileset(final FileSet fileSet) {
+        filesets.addElement(fileSet);
+    }
+
+
+    /**
+     * Execute task
+     *
+     * @exception BuildException if something goes wrong executing the
+     *            cvs command
+     */
+    public void execute() throws BuildException {
+        File savedDir = inputDir; // may be altered in validate
+
+        try {
+
+            validate();
+            final Properties userList = new Properties();
+
+            loadUserlist(userList);
+
+            for (int i = 0, size = cvsUsers.size(); i < size; i++) {
+                final CvsUser user = (CvsUser) cvsUsers.get(i);
+                user.validate();
+                userList.put(user.getUserID(), user.getDisplayname());
+            }
+
+            setCommand("log");
+
+            if (getTag() != null) {
+                CvsVersion myCvsVersion = new CvsVersion();
+                myCvsVersion.setProject(getProject());
+                myCvsVersion.setTaskName("cvsversion");
+                myCvsVersion.setCvsRoot(getCvsRoot());
+                myCvsVersion.setCvsRsh(getCvsRsh());
+                myCvsVersion.setPassfile(getPassFile());
+                myCvsVersion.setDest(inputDir);
+                myCvsVersion.execute();
+                if (myCvsVersion.supportsCvsLogWithSOption()) {
+                    addCommandArgument("-S");
+                }
+            }
+            if (null != startDate) {
+                final SimpleDateFormat outputDate =
+                    new SimpleDateFormat("yyyy-MM-dd");
+
+                // We want something of the form: -d ">=YYYY-MM-dd"
+                final String dateRange = ">=" + outputDate.format(startDate);
+
+                // Supply '-d' as a separate argument - Bug# 14397
+                addCommandArgument("-d");
+                addCommandArgument(dateRange);
+            }
+
+            // Check if list of files to check has been specified
+            if (!filesets.isEmpty()) {
+                final Enumeration e = filesets.elements();
+
+                while (e.hasMoreElements()) {
+                    final FileSet fileSet = (FileSet) e.nextElement();
+                    final DirectoryScanner scanner =
+                        fileSet.getDirectoryScanner(getProject());
+                    final String[] files = scanner.getIncludedFiles();
+
+                    for (int i = 0; i < files.length; i++) {
+                        addCommandArgument(files[i]);
+                    }
+                }
+            }
+
+            final ChangeLogParser parser = new ChangeLogParser();
+            final RedirectingStreamHandler handler =
+                new RedirectingStreamHandler(parser);
+
+            log(getCommand(), Project.MSG_VERBOSE);
+
+            setDest(inputDir);
+            setExecuteStreamHandler(handler);
+            try {
+                super.execute();
+            } finally {
+                final String errors = handler.getErrors();
+
+                if (null != errors) {
+                    log(errors, Project.MSG_ERR);
+                }
+            }
+            final CVSEntry[] entrySet = parser.getEntrySetAsArray();
+            final CVSEntry[] filteredEntrySet = filterEntrySet(entrySet);
+
+            replaceAuthorIdWithName(userList, filteredEntrySet);
+
+            writeChangeLog(filteredEntrySet);
+
+        } finally {
+            inputDir = savedDir;
+        }
+    }
+
+    /**
+     * Validate the parameters specified for task.
+     *
+     * @throws BuildException if fails validation checks
+     */
+    private void validate()
+         throws BuildException {
+        if (null == inputDir) {
+            inputDir = getProject().getBaseDir();
+        }
+        if (null == destFile) {
+            final String message = "Destfile must be set.";
+
+            throw new BuildException(message);
+        }
+        if (!inputDir.exists()) {
+            final String message = "Cannot find base dir "
+                 + inputDir.getAbsolutePath();
+
+            throw new BuildException(message);
+        }
+        if (null != usersFile && !usersFile.exists()) {
+            final String message = "Cannot find user lookup list "
+                 + usersFile.getAbsolutePath();
+
+            throw new BuildException(message);
+        }
+    }
+
+    /**
+     * Load the userlist from the userList file (if specified) and add to
+     * list of users.
+     *
+     * @param userList the file of users
+     * @throws BuildException if file can not be loaded for some reason
+     */
+    private void loadUserlist(final Properties userList)
+         throws BuildException {
+        if (null != usersFile) {
+            try {
+                userList.load(new FileInputStream(usersFile));
+            } catch (final IOException ioe) {
+                throw new BuildException(ioe.toString(), ioe);
+            }
+        }
+    }
+
+    /**
+     * Filter the specified entries according to an appropriate rule.
+     *
+     * @param entrySet the entry set to filter
+     * @return the filtered entry set
+     */
+    private CVSEntry[] filterEntrySet(final CVSEntry[] entrySet) {
+        final Vector results = new Vector();
+
+        for (int i = 0; i < entrySet.length; i++) {
+            final CVSEntry cvsEntry = entrySet[i];
+            final Date date = cvsEntry.getDate();
+
+            //bug#30471
+            //this is caused by Date.after throwing a NullPointerException
+            //for some reason there's no date set in the CVSEntry
+            //Java 1.3.1 API
+            //http://java.sun.com/j2se/1.3/docs/api/java/util/Date.html#after(java.util.Date)
+            //doesn't throw NullPointerException
+            //Java 1.4.2 + 1.5 API
+            //http://java.sun.com/j2se/1.4.2/docs/api/java/util/Date.html#after(java.util.Date)
+            //according to the docs it doesn't throw, according to the bug report it does
+            //http://java.sun.com/j2se/1.5.0/docs/api/java/util/Date.html#after(java.util.Date)
+            //according to the docs it does throw
+
+            //for now skip entries which are missing a date
+            if (null == date) {
+                continue;
+            }
+
+            if (null != startDate && startDate.after(date)) {
+                //Skip dates that are too early
+                continue;
+            }
+            if (null != endDate && endDate.before(date)) {
+                //Skip dates that are too late
+                continue;
+            }
+            results.addElement(cvsEntry);
+        }
+
+        final CVSEntry[] resultArray = new CVSEntry[results.size()];
+
+        results.copyInto(resultArray);
+        return resultArray;
+    }
+
+    /**
+     * replace all known author's id's with their maven specified names
+     */
+    private void replaceAuthorIdWithName(final Properties userList,
+                                         final CVSEntry[] entrySet) {
+        for (int i = 0; i < entrySet.length; i++) {
+
+            final CVSEntry entry = entrySet[ i ];
+            if (userList.containsKey(entry.getAuthor())) {
+                entry.setAuthor(userList.getProperty(entry.getAuthor()));
+            }
+        }
+    }
+
+    /**
+     * Print changelog to file specified in task.
+     *
+     * @param entrySet the entry set to write.
+     * @throws BuildException if there is an error writing changelog.
+     */
+    private void writeChangeLog(final CVSEntry[] entrySet)
+         throws BuildException {
+        FileOutputStream output = null;
+
+        try {
+            output = new FileOutputStream(destFile);
+
+            final PrintWriter writer =
+                new PrintWriter(new OutputStreamWriter(output, "UTF-8"));
+
+            final ChangeLogWriter serializer = new ChangeLogWriter();
+
+            serializer.printChangeLog(writer, entrySet);
+        } catch (final UnsupportedEncodingException uee) {
+            getProject().log(uee.toString(), Project.MSG_ERR);
+        } catch (final IOException ioe) {
+            throw new BuildException(ioe.toString(), ioe);
+        } finally {
+            FileUtils.close(output);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriter.java
new file mode 100644
index 0000000..17ae1b4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriter.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Enumeration;
+import java.util.TimeZone;
+
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DOMUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Class used to generate an XML changelog.
+ *
+ */
+public class ChangeLogWriter {
+    /** output format for dates written to xml file */
+    private static final SimpleDateFormat OUTPUT_DATE
+        = new SimpleDateFormat("yyyy-MM-dd");
+    /** output format for times written to xml file */
+    private static final SimpleDateFormat OUTPUT_TIME
+        = new SimpleDateFormat("HH:mm");
+    /** stateless helper for writing the XML document */
+    private static final DOMElementWriter DOM_WRITER = new DOMElementWriter();
+
+    static {
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        OUTPUT_DATE.setTimeZone(utc);
+        OUTPUT_TIME.setTimeZone(utc);
+    }
+
+    /**
+     * Print out the specified entries.
+     *
+     * @param output writer to which to send output.
+     * @param entries the entries to be written.
+     */
+    public void printChangeLog(final PrintWriter output,
+                               final CVSEntry[] entries) {
+        try {
+            output.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            Document doc = DOMUtils.newDocument();
+            Element root = doc.createElement("changelog");
+            DOM_WRITER.openElement(root, output, 0, "\t");
+            output.println();
+            for (int i = 0; i < entries.length; i++) {
+                final CVSEntry entry = entries[i];
+
+                printEntry(doc, output, entry);
+            }
+            DOM_WRITER.closeElement(root, output, 0, "\t", true);
+            output.flush();
+            output.close();
+        } catch (IOException e) {
+            throw new org.apache.tools.ant.BuildException(e);
+        }
+    }
+
+
+    /**
+     * Print out an individual entry in changelog.
+     *
+     * @param doc Document used to create elements.
+     * @param entry the entry to print
+     * @param output writer to which to send output.
+     */
+    private void printEntry(Document doc, final PrintWriter output,
+                            final CVSEntry entry) throws IOException {
+        Element ent = doc.createElement("entry");
+        DOMUtils.appendTextElement(ent, "date",
+                                   OUTPUT_DATE.format(entry.getDate()));
+        DOMUtils.appendTextElement(ent, "time",
+                                   OUTPUT_TIME.format(entry.getDate()));
+        DOMUtils.appendCDATAElement(ent, "author", entry.getAuthor());
+
+        final Enumeration enumeration = entry.getFiles().elements();
+
+        while (enumeration.hasMoreElements()) {
+            final RCSFile file = (RCSFile) enumeration.nextElement();
+
+            Element f = DOMUtils.createChildElement(ent, "file");
+            DOMUtils.appendCDATAElement(f, "name", file.getName());
+            DOMUtils.appendTextElement(f, "revision", file.getRevision());
+
+            final String previousRevision = file.getPreviousRevision();
+            if (previousRevision != null) {
+                DOMUtils.appendTextElement(f, "prevrevision",
+                                           previousRevision);
+            }
+        }
+        DOMUtils.appendCDATAElement(ent, "msg", entry.getComment());
+        DOM_WRITER.write(ent, output, 1, "\t");
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java
new file mode 100644
index 0000000..afb3cb3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagDiff.java
@@ -0,0 +1,479 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.Vector;
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.AbstractCvsTask;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DOMUtils;
+import org.apache.tools.ant.util.FileUtils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Examines the output of cvs rdiff between two tags.
+ *
+ * It produces an XML output representing the list of changes.
+ * <PRE>
+ * &lt;!-- Root element --&gt;
+ * &lt;!ELEMENT tagdiff ( entry+ ) &gt;
+ * &lt;!-- Start tag of the report --&gt;
+ * &lt;!ATTLIST tagdiff startTag NMTOKEN #IMPLIED &gt;
+ * &lt;!-- End tag of the report --&gt;
+ * &lt;!ATTLIST tagdiff endTag NMTOKEN #IMPLIED &gt;
+ * &lt;!-- Start date of the report --&gt;
+ * &lt;!ATTLIST tagdiff startDate NMTOKEN #IMPLIED &gt;
+ * &lt;!-- End date of the report --&gt;
+ * &lt;!ATTLIST tagdiff endDate NMTOKEN #IMPLIED &gt;
+ *
+ * &lt;!-- CVS tag entry --&gt;
+ * &lt;!ELEMENT entry ( file ) &gt;
+ * &lt;!-- File added, changed or removed --&gt;
+ * &lt;!ELEMENT file ( name, revision?, prevrevision? ) &gt;
+ * &lt;!-- Name of the file --&gt;
+ * &lt;!ELEMENT name ( #PCDATA ) &gt;
+ * &lt;!-- Revision number --&gt;
+ * &lt;!ELEMENT revision ( #PCDATA ) &gt;
+ * &lt;!-- Previous revision number --&gt;
+ * &lt;!ELEMENT prevrevision ( #PCDATA ) &gt;
+ * </PRE>
+ *
+ * @since Ant 1.5
+ * @ant.task name="cvstagdiff"
+ */
+public class CvsTagDiff extends AbstractCvsTask {
+
+    /**
+     * Used to create the temp file for cvs log
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** stateless helper for writing the XML document */
+    private static final DOMElementWriter DOM_WRITER = new DOMElementWriter();
+
+    /**
+     * Token to identify the word file in the rdiff log
+     */
+    static final String FILE_STRING = "File ";
+    /**
+     * Token to identify the word file in the rdiff log
+     */
+    static final String TO_STRING = " to ";
+    /**
+     * Token to identify a new file in the rdiff log
+     */
+    static final String FILE_IS_NEW = " is new;";
+    /**
+     * Token to identify the revision
+     */
+    static final String REVISION = "revision ";
+
+    /**
+     * Token to identify a modified file in the rdiff log
+     */
+    static final String FILE_HAS_CHANGED = " changed from revision ";
+
+    /**
+     * Token to identify a removed file in the rdiff log
+     */
+    static final String FILE_WAS_REMOVED = " is removed";
+
+    /**
+     * The cvs package/module to analyse
+     */
+    private String mypackage;
+
+    /**
+     * The earliest tag from which diffs are to be included in the report.
+     */
+    private String mystartTag;
+
+    /**
+     * The latest tag from which diffs are to be included in the report.
+     */
+    private String myendTag;
+
+    /**
+     * The earliest date from which diffs are to be included in the report.
+     */
+    private String mystartDate;
+
+    /**
+     * The latest date from which diffs are to be included in the report.
+     */
+    private String myendDate;
+
+    /**
+     * The file in which to write the diff report.
+     */
+    private File mydestfile;
+
+    /**
+     * The package/module to analyze.
+     * @param p the name of the package to analyse
+     */
+    public void setPackage(String p) {
+        mypackage = p;
+    }
+
+    /**
+     * Set the start tag.
+     *
+     * @param s the start tag.
+     */
+    public void setStartTag(String s) {
+        mystartTag = s;
+    }
+
+    /**
+     * Set the start date.
+     *
+     * @param s the start date.
+     */
+    public void setStartDate(String s) {
+        mystartDate = s;
+    }
+
+    /**
+     * Set the end tag.
+     *
+     * @param s the end tag.
+     */
+    public void setEndTag(String s) {
+        myendTag = s;
+    }
+
+    /**
+     * Set the end date.
+     *
+     * @param s the end date.
+     */
+    public void setEndDate(String s) {
+        myendDate = s;
+    }
+
+    /**
+     * Set the output file for the diff.
+     *
+     * @param f the output file for the diff.
+     */
+    public void setDestFile(File f) {
+        mydestfile = f;
+    }
+
+    /**
+     * Execute task.
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+        // validate the input parameters
+        validate();
+
+        // build the rdiff command
+        addCommandArgument("rdiff");
+        addCommandArgument("-s");
+        if (mystartTag != null) {
+            addCommandArgument("-r");
+            addCommandArgument(mystartTag);
+        } else {
+            addCommandArgument("-D");
+            addCommandArgument(mystartDate);
+        }
+        if (myendTag != null) {
+            addCommandArgument("-r");
+            addCommandArgument(myendTag);
+        } else {
+            addCommandArgument("-D");
+            addCommandArgument(myendDate);
+        }
+        // support multiple packages
+        StringTokenizer myTokenizer = new StringTokenizer(mypackage);
+        while (myTokenizer.hasMoreTokens()) {
+            addCommandArgument(myTokenizer.nextToken());
+        }
+        // force command not to be null
+        setCommand("");
+        File tmpFile = null;
+        try {
+            tmpFile = FILE_UTILS.createTempFile("cvstagdiff", ".log", null, true, true);
+            setOutput(tmpFile);
+
+            // run the cvs command
+            super.execute();
+
+            // parse the rdiff
+            CvsTagEntry[] entries = parseRDiff(tmpFile);
+
+            // write the tag diff
+            writeTagDiff(entries);
+
+        } finally {
+            if (tmpFile != null) {
+                tmpFile.delete();
+            }
+        }
+    }
+
+    /**
+     * Parse the tmpFile and return and array of CvsTagEntry to be
+     * written in the output.
+     *
+     * @param tmpFile the File containing the output of the cvs rdiff command
+     * @return the entries in the output
+     * @exception BuildException if an error occurs
+     */
+    private CvsTagEntry[] parseRDiff(File tmpFile) throws BuildException {
+        // parse the output of the command
+        BufferedReader reader = null;
+
+        try {
+            reader = new BufferedReader(new FileReader(tmpFile));
+
+            // entries are of the form:
+            //CVS 1.11
+            // File module/filename is new; current revision 1.1
+            //CVS 1.11.9
+            // File module/filename is new; cvstag_2003_11_03_2  revision 1.1
+            // or
+            // File module/filename changed from revision 1.4 to 1.6
+            // or
+            // File module/filename is removed; not included in
+            // release tag SKINLF_12
+            //CVS 1.11.9
+            // File testantoine/antoine.bat is removed; TESTANTOINE_1 revision 1.1.1.1
+            //
+            // get rid of 'File module/"
+            String toBeRemoved = FILE_STRING + mypackage + "/";
+            int headerLength = toBeRemoved.length();
+            Vector entries = new Vector();
+
+            String line = reader.readLine();
+
+            while (null != line) {
+                if (line.length() > headerLength) {
+                    if (line.startsWith(toBeRemoved)) {
+                        line = line.substring(headerLength);
+                    } else {
+                        line = line.substring(FILE_STRING.length());
+                    }
+
+                    // use || in a perl like fashion
+                    boolean processed
+                        =  doFileIsNew(entries, line)
+                        || doFileHasChanged(entries, line)
+                        || doFileWasRemoved(entries, line);
+                }
+                line = reader.readLine();
+            }
+
+            CvsTagEntry[] array = new CvsTagEntry[entries.size()];
+            entries.copyInto(array);
+
+            return array;
+        } catch (IOException e) {
+            throw new BuildException("Error in parsing", e);
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    log(e.toString(), Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+    private boolean doFileIsNew(Vector entries, String line) {
+        int index = line.indexOf(FILE_IS_NEW);
+        if (index == -1) {
+            return false;
+        }
+        // it is a new file
+        // set the revision but not the prevrevision
+        String filename = line.substring(0, index);
+        String rev = null;
+        int indexrev = line.indexOf(REVISION, index);
+        if (indexrev != -1) {
+            rev = line.substring(indexrev + REVISION.length());
+        }
+        CvsTagEntry entry = new CvsTagEntry(filename, rev);
+        entries.addElement(entry);
+        log(entry.toString(), Project.MSG_VERBOSE);
+        return true;
+    }
+
+    private boolean doFileHasChanged(Vector entries, String line) {
+        int index = line.indexOf(FILE_HAS_CHANGED);
+        if (index == -1) {
+            return false;
+        }
+        // it is a modified file
+        // set the revision and the prevrevision
+        String filename = line.substring(0, index);
+        int revSeparator = line.indexOf(" to ", index);
+        String prevRevision =
+            line.substring(index + FILE_HAS_CHANGED.length(),
+                           revSeparator);
+        String revision = line.substring(revSeparator + TO_STRING.length());
+        CvsTagEntry entry = new CvsTagEntry(filename,
+                                            revision,
+                                            prevRevision);
+        entries.addElement(entry);
+        log(entry.toString(), Project.MSG_VERBOSE);
+        return true;
+    }
+
+    private boolean doFileWasRemoved(Vector entries, String line) {
+        int index = line.indexOf(FILE_WAS_REMOVED);
+        if (index == -1) {
+            return false;
+        }
+        // it is a removed file
+        String filename = line.substring(0, index);
+        String rev = null;
+        int indexrev = line.indexOf(REVISION, index);
+        if (indexrev != -1) {
+            rev = line.substring(indexrev + REVISION.length());
+        }
+        CvsTagEntry entry = new CvsTagEntry(filename, null, rev);
+        entries.addElement(entry);
+        log(entry.toString(), Project.MSG_VERBOSE);
+        return true;
+    }
+
+    /**
+     * Write the rdiff log.
+     *
+     * @param entries a <code>CvsTagEntry[]</code> value
+     * @exception BuildException if an error occurs
+     */
+    private void writeTagDiff(CvsTagEntry[] entries) throws BuildException {
+        FileOutputStream output = null;
+        try {
+            output = new FileOutputStream(mydestfile);
+            PrintWriter writer = new PrintWriter(
+                                     new OutputStreamWriter(output, "UTF-8"));
+            writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            Document doc = DOMUtils.newDocument();
+            Element root = doc.createElement("tagdiff");
+            if (mystartTag != null) {
+                root.setAttribute("startTag", mystartTag);
+            } else {
+                root.setAttribute("startDate", mystartDate);
+            }
+            if (myendTag != null) {
+                root.setAttribute("endTag", myendTag);
+            } else {
+                root.setAttribute("endDate", myendDate);
+            }
+
+            root.setAttribute("cvsroot", getCvsRoot());
+            root.setAttribute("package", mypackage);
+            DOM_WRITER.openElement(root, writer, 0, "\t");
+            writer.println();
+            for (int i = 0, c = entries.length; i < c; i++) {
+                writeTagEntry(doc, writer, entries[i]);
+            }
+            DOM_WRITER.closeElement(root, writer, 0, "\t", true);
+            writer.flush();
+            writer.close();
+        } catch (UnsupportedEncodingException uee) {
+            log(uee.toString(), Project.MSG_ERR);
+        } catch (IOException ioe) {
+            throw new BuildException(ioe.toString(), ioe);
+        } finally {
+            if (null != output) {
+                try {
+                    output.close();
+                } catch (IOException ioe) {
+                    log(ioe.toString(), Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+    /**
+     * Write a single entry to the given writer.
+     *
+     * @param doc Document used to create elements.
+     * @param writer a <code>PrintWriter</code> value
+     * @param entry a <code>CvsTagEntry</code> value
+     */
+    private void writeTagEntry(Document doc, PrintWriter writer,
+                               CvsTagEntry entry)
+        throws IOException {
+        Element ent = doc.createElement("entry");
+        Element f = DOMUtils.createChildElement(ent, "file");
+        DOMUtils.appendCDATAElement(f, "name", entry.getFile());
+        if (entry.getRevision() != null) {
+            DOMUtils.appendTextElement(f, "revision", entry.getRevision());
+        }
+        if (entry.getPreviousRevision() != null) {
+            DOMUtils.appendTextElement(f, "prevrevision",
+                                       entry.getPreviousRevision());
+        }
+        DOM_WRITER.write(ent, writer, 1, "\t");
+    }
+
+    /**
+     * Validate the parameters specified for task.
+     *
+     * @exception BuildException if a parameter is not correctly set
+     */
+    private void validate() throws BuildException {
+        if (null == mypackage) {
+            throw new BuildException("Package/module must be set.");
+        }
+
+        if (null == mydestfile) {
+            throw new BuildException("Destfile must be set.");
+        }
+
+        if (null == mystartTag && null == mystartDate) {
+            throw new BuildException("Start tag or start date must be set.");
+        }
+
+        if (null != mystartTag && null != mystartDate) {
+            throw new BuildException("Only one of start tag and start date "
+                                     + "must be set.");
+        }
+
+        if (null == myendTag && null == myendDate) {
+            throw new BuildException("End tag or end date must be set.");
+        }
+
+        if (null != myendTag && null != myendDate) {
+            throw new BuildException("Only one of end tag and end date must "
+                                     + "be set.");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagEntry.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagEntry.java
new file mode 100644
index 0000000..6e349c7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsTagEntry.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+/**
+ * Holds the information of a line of rdiff
+ */
+public class CvsTagEntry {
+
+    /** the filename */
+    private String filename;
+
+    /** the previous revision */
+    private String prevRevision;
+
+    /** the revision */
+    private String revision;
+
+    /**
+     * Creates a new CvsTagEntry
+     * @param filename the filename to add
+     */
+    public CvsTagEntry(final String filename) {
+        this(filename, null, null);
+    }
+
+    /**
+     * Creates a new CvsTagEntry
+     * @param filename the filename to add
+     * @param revision the revision
+     */
+    public CvsTagEntry(final String filename, final String revision) {
+        this(filename, revision, null);
+    }
+
+    /**
+     * Creates a new CvsTagEntry
+     * @param filename the filename to add
+     * @param revision the revision
+     * @param prevRevision the previous revision
+     */
+    public CvsTagEntry(final String filename, final String revision,
+                       final String prevRevision) {
+        this.filename = filename;
+        this.revision = revision;
+        this.prevRevision = prevRevision;
+    }
+
+    /**
+     * Gets the filename for this CvsTagEntry
+     * @return the filename
+     */
+    public String getFile() {
+        return filename;
+    }
+
+    /**
+     * Gets the revision for this CvsTagEntry
+     * @return the revision
+     */
+    public String getRevision() {
+        return revision;
+    }
+
+    /**
+     * Gets the previous revision for this CvsTagEntry
+     * @return the previous revision
+     */
+    public String getPreviousRevision() {
+        return prevRevision;
+    }
+
+    /**
+     * Gets a String containing filename and difference from previous version
+     * @return a string representation of this CVSTagEntry
+     */
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(filename);
+        if (revision == null) {
+            buffer.append(" was removed");
+            if (prevRevision != null) {
+                buffer.append("; previous revision was ").append(prevRevision);
+            }
+        } else if (prevRevision == null) {
+            buffer.append(" is new; current revision is ")
+                .append(revision);
+        } else {
+            buffer.append(" has changed from ")
+                .append(prevRevision).append(" to ").append(revision);
+        }
+        return buffer.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsUser.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsUser.java
new file mode 100644
index 0000000..85a2fc6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsUser.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Represents a CVS user with a userID and a full name.
+ *
+ */
+public class CvsUser {
+    /** The user's Id */
+    private String userID;
+    /** The user's full name */
+    private String displayName;
+
+
+    /**
+     * Set the user's fullname
+     *
+     * @param displayName the user's full name
+     */
+    public void setDisplayname(final String displayName) {
+        this.displayName = displayName;
+    }
+
+
+    /**
+     * Set the user's id
+     *
+     * @param userID the user's new id value.
+     */
+    public void setUserid(final String userID) {
+        this.userID = userID;
+    }
+
+
+    /**
+     * Get the user's id.
+     *
+     * @return The userID value
+     */
+    public String getUserID() {
+        return userID;
+    }
+
+
+    /**
+     * Get the user's full name
+     *
+     * @return the user's full name
+     */
+    public String getDisplayname() {
+        return displayName;
+    }
+
+
+    /**
+     * Validate that this object is configured.
+     *
+     * @exception BuildException if the instance has not be correctly
+     *            configured.
+     */
+    public void validate() throws BuildException {
+        if (null == userID) {
+            final String message = "Username attribute must be set.";
+
+            throw new BuildException(message);
+        }
+        if (null == displayName) {
+            final String message =
+                "Displayname attribute must be set for userID " + userID;
+
+            throw new BuildException(message);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsVersion.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsVersion.java
new file mode 100644
index 0000000..b4a60a9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/CvsVersion.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import org.apache.tools.ant.taskdefs.AbstractCvsTask;
+
+import java.io.ByteArrayOutputStream;
+import java.util.StringTokenizer;
+
+/**
+ * this task allows to find out the client and the server version of a
+ * CVS installation
+ *
+ * example usage :
+ * &lt;cvsversion
+ * cvsRoot=&quot;:pserver:anoncvs@cvs.apache.org:/home/cvspublic&quot;
+ * passfile=&quot;c:/programme/cygwin/home/antoine/.cvspass&quot;
+ * clientversionproperty=&quot;apacheclient&quot;
+ * serverversionproperty=&quot;apacheserver&quot;   /&gt;
+ *
+ * the task can be used also in the API by calling its execute method,
+ * then calling getServerVersion and/or getClientVersion
+ *
+ * @ant.task category="scm"
+ * @since ant 1.6.1
+ */
+public class CvsVersion extends AbstractCvsTask {
+    static final long VERSION_1_11_2 = 11102;
+    static final long MULTIPLY = 100;
+    private String clientVersion;
+    private String serverVersion;
+    private String clientVersionProperty;
+    private String serverVersionProperty;
+
+    /**
+     * Get the CVS client version
+     * @return CVS client version
+     */
+    public String getClientVersion() {
+        return clientVersion;
+    }
+    /**
+     * Get the CVS server version
+     * @return CVS server version
+     */
+    public String getServerVersion() {
+        return serverVersion;
+    }
+    /**
+     * Set a property where to store the CVS client version
+     * @param clientVersionProperty  property for CVS client version
+     */
+    public void setClientVersionProperty(String clientVersionProperty) {
+        this.clientVersionProperty = clientVersionProperty;
+    }
+
+    /**
+     * Set a property where to store the CVS server version
+     * @param serverVersionProperty  property for CVS server version
+     */
+    public void setServerVersionProperty(String serverVersionProperty) {
+        this.serverVersionProperty = serverVersionProperty;
+    }
+    /**
+     * Find out if the server version supports log with S option
+     * @return  boolean indicating if the server version supports log with S option
+     */
+    public boolean supportsCvsLogWithSOption() {
+        if (serverVersion == null) {
+            return false;
+        }
+        StringTokenizer tokenizer = new StringTokenizer(serverVersion, ".");
+        long counter = MULTIPLY * MULTIPLY;
+        long version = 0;
+        while (tokenizer.hasMoreTokens()) {
+            String s = tokenizer.nextToken();
+            int i = 0;
+            for (i = 0; i < s.length(); i++) {
+                if (!Character.isDigit(s.charAt(i))) {
+                    break;
+                }
+            }
+            String s2 = s.substring(0, i);
+            version = version + counter * Long.parseLong(s2);
+            if (counter == 1) {
+                break;
+            }
+            counter = counter / MULTIPLY;
+        }
+        return (version >= VERSION_1_11_2);
+    }
+    /**
+     * the execute method running CvsVersion
+     */
+    public void execute() {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        this.setOutputStream(bos);
+        ByteArrayOutputStream berr = new ByteArrayOutputStream();
+        this.setErrorStream(berr);
+        setCommand("version");
+        super.execute();
+        String output = bos.toString();
+        StringTokenizer st = new StringTokenizer(output);
+        boolean client = false;
+        boolean server = false;
+        boolean cvs = false;
+        while (st.hasMoreTokens()) {
+            String currentToken = st.nextToken();
+            if (currentToken.equals("Client:")) {
+                client = true;
+            } else if (currentToken.equals("Server:")) {
+                server = true;
+            } else if (currentToken.equals("(CVS)")) {
+                cvs = true;
+            }
+            if (client && cvs) {
+                if (st.hasMoreTokens()) {
+                    clientVersion = st.nextToken();
+                }
+                client = false;
+                cvs = false;
+            } else if (server && cvs) {
+                if (st.hasMoreTokens()) {
+                    serverVersion = st.nextToken();
+                }
+                server = false;
+                cvs = false;
+            }
+
+        }
+        if (clientVersionProperty != null) {
+            getProject().setNewProperty(clientVersionProperty, clientVersion);
+        }
+        if (serverVersionProperty != null) {
+            getProject().setNewProperty(serverVersionProperty, serverVersion);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RCSFile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RCSFile.java
new file mode 100644
index 0000000..70a8cf3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RCSFile.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+/**
+ * Represents a RCS File change.
+ *
+ */
+class RCSFile {
+    private String name;
+    private String revision;
+    private String previousRevision;
+
+
+    RCSFile(final String name, final String rev) {
+        this(name, rev, null);
+    }
+
+
+    RCSFile(final String name,
+                  final String revision,
+                  final String previousRevision) {
+        this.name = name;
+        this.revision = revision;
+        if (!revision.equals(previousRevision)) {
+            this.previousRevision = previousRevision;
+        }
+    }
+
+    /**
+     * Gets the name of the RCSFile
+     * @return name of the file
+     */
+    String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the revision number of the RCSFile
+     * @return the revision number (as String)
+     */
+    String getRevision() {
+        return revision;
+    }
+
+    /**
+     * Gets the previous revision of the RCSFile
+     * @return the previous revision number (as String)
+     */
+    String getPreviousRevision() {
+        return previousRevision;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingOutputStream.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingOutputStream.java
new file mode 100644
index 0000000..f2b61cf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingOutputStream.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import org.apache.tools.ant.util.LineOrientedOutputStream;
+
+/**
+ * A dummy stream that just passes stuff to the parser.
+ */
+class RedirectingOutputStream extends LineOrientedOutputStream {
+    private final ChangeLogParser parser;
+
+    /**
+     * Creates a new instance of this class.
+     *
+     * @param parser the parser to which output is sent.
+     */
+    public RedirectingOutputStream(final ChangeLogParser parser) {
+        this.parser = parser;
+    }
+
+    /**
+     * Logs a line to the log system of ant.
+     *
+     * @param line the line to log.
+     */
+    protected void processLine(final String line) {
+        parser.stdout(line);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingStreamHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingStreamHandler.java
new file mode 100644
index 0000000..309eb21
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/cvslib/RedirectingStreamHandler.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+
+/**
+ * A dummy stream handler that just passes stuff to the parser.
+ *
+ */
+class RedirectingStreamHandler
+     extends PumpStreamHandler {
+    RedirectingStreamHandler(final ChangeLogParser parser) {
+        super(new RedirectingOutputStream(parser),
+            new ByteArrayOutputStream());
+    }
+
+
+    String getErrors() {
+        try {
+            final ByteArrayOutputStream error
+                = (ByteArrayOutputStream) getErr();
+
+            return error.toString("ASCII");
+        } catch (final Exception e) {
+            return null;
+        }
+    }
+
+
+    public void stop() {
+        super.stop();
+        try {
+            getErr().close();
+            getOut().close();
+        } catch (final IOException e) {
+            // plain impossible
+            throw new BuildException(e);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties b/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
new file mode 100644
index 0000000..f0488dc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/defaults.properties
@@ -0,0 +1,234 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# standard ant tasks
+ant=org.apache.tools.ant.taskdefs.Ant
+antcall=org.apache.tools.ant.taskdefs.CallTarget
+antstructure=org.apache.tools.ant.taskdefs.AntStructure
+antversion=org.apache.tools.ant.taskdefs.condition.AntVersion
+apply=org.apache.tools.ant.taskdefs.Transform
+available=org.apache.tools.ant.taskdefs.Available
+basename=org.apache.tools.ant.taskdefs.Basename
+buildnumber=org.apache.tools.ant.taskdefs.BuildNumber
+bunzip2=org.apache.tools.ant.taskdefs.BUnzip2
+bzip2=org.apache.tools.ant.taskdefs.BZip2
+checksum=org.apache.tools.ant.taskdefs.Checksum
+chmod=org.apache.tools.ant.taskdefs.Chmod
+classloader=org.apache.tools.ant.taskdefs.Classloader
+componentdef=org.apache.tools.ant.taskdefs.Componentdef
+concat=org.apache.tools.ant.taskdefs.Concat
+condition=org.apache.tools.ant.taskdefs.ConditionTask
+copy=org.apache.tools.ant.taskdefs.Copy
+cvs=org.apache.tools.ant.taskdefs.Cvs
+cvschangelog=org.apache.tools.ant.taskdefs.cvslib.ChangeLogTask
+cvspass=org.apache.tools.ant.taskdefs.CVSPass
+cvstagdiff=org.apache.tools.ant.taskdefs.cvslib.CvsTagDiff
+cvsversion=org.apache.tools.ant.taskdefs.cvslib.CvsVersion
+defaultexcludes=org.apache.tools.ant.taskdefs.DefaultExcludes
+delete=org.apache.tools.ant.taskdefs.Delete
+dependset=org.apache.tools.ant.taskdefs.DependSet
+diagnostics=org.apache.tools.ant.taskdefs.DiagnosticsTask
+dirname=org.apache.tools.ant.taskdefs.Dirname
+ear=org.apache.tools.ant.taskdefs.Ear
+echo=org.apache.tools.ant.taskdefs.Echo
+exec=org.apache.tools.ant.taskdefs.ExecTask
+fail=org.apache.tools.ant.taskdefs.Exit
+filter=org.apache.tools.ant.taskdefs.Filter
+fixcrlf=org.apache.tools.ant.taskdefs.FixCRLF
+genkey=org.apache.tools.ant.taskdefs.GenerateKey
+get=org.apache.tools.ant.taskdefs.Get
+gunzip=org.apache.tools.ant.taskdefs.GUnzip
+gzip=org.apache.tools.ant.taskdefs.GZip
+import=org.apache.tools.ant.taskdefs.ImportTask
+input=org.apache.tools.ant.taskdefs.Input
+jar=org.apache.tools.ant.taskdefs.Jar
+java=org.apache.tools.ant.taskdefs.Java
+javac=org.apache.tools.ant.taskdefs.Javac
+javadoc=org.apache.tools.ant.taskdefs.Javadoc
+length=org.apache.tools.ant.taskdefs.Length
+loadfile=org.apache.tools.ant.taskdefs.LoadFile
+loadproperties=org.apache.tools.ant.taskdefs.LoadProperties
+loadresource=org.apache.tools.ant.taskdefs.LoadResource
+macrodef=org.apache.tools.ant.taskdefs.MacroDef
+mail=org.apache.tools.ant.taskdefs.email.EmailTask
+manifest=org.apache.tools.ant.taskdefs.ManifestTask
+manifestclasspath=org.apache.tools.ant.taskdefs.ManifestClassPath
+mkdir=org.apache.tools.ant.taskdefs.Mkdir
+move=org.apache.tools.ant.taskdefs.Move
+nice=org.apache.tools.ant.taskdefs.Nice
+parallel=org.apache.tools.ant.taskdefs.Parallel
+patch=org.apache.tools.ant.taskdefs.Patch
+pathconvert=org.apache.tools.ant.taskdefs.PathConvert
+presetdef=org.apache.tools.ant.taskdefs.PreSetDef
+property=org.apache.tools.ant.taskdefs.Property
+propertyhelper=org.apache.tools.ant.taskdefs.PropertyHelperTask
+record=org.apache.tools.ant.taskdefs.Recorder
+replace=org.apache.tools.ant.taskdefs.Replace
+retry=org.apache.tools.ant.taskdefs.Retry
+rmic=org.apache.tools.ant.taskdefs.Rmic
+sequential=org.apache.tools.ant.taskdefs.Sequential
+signjar=org.apache.tools.ant.taskdefs.SignJar
+sleep=org.apache.tools.ant.taskdefs.Sleep
+sql=org.apache.tools.ant.taskdefs.SQLExec
+subant=org.apache.tools.ant.taskdefs.SubAnt
+sync=org.apache.tools.ant.taskdefs.Sync
+tar=org.apache.tools.ant.taskdefs.Tar
+taskdef=org.apache.tools.ant.taskdefs.Taskdef
+tempfile=org.apache.tools.ant.taskdefs.TempFile
+touch=org.apache.tools.ant.taskdefs.Touch
+tstamp=org.apache.tools.ant.taskdefs.Tstamp
+truncate=org.apache.tools.ant.taskdefs.Truncate
+typedef=org.apache.tools.ant.taskdefs.Typedef
+unjar=org.apache.tools.ant.taskdefs.Expand
+untar=org.apache.tools.ant.taskdefs.Untar
+unwar=org.apache.tools.ant.taskdefs.Expand
+unzip=org.apache.tools.ant.taskdefs.Expand
+uptodate=org.apache.tools.ant.taskdefs.UpToDate
+waitfor=org.apache.tools.ant.taskdefs.WaitFor
+war=org.apache.tools.ant.taskdefs.War
+whichresource=org.apache.tools.ant.taskdefs.WhichResource
+xmlproperty=org.apache.tools.ant.taskdefs.XmlProperty
+xslt=org.apache.tools.ant.taskdefs.XSLTProcess
+zip=org.apache.tools.ant.taskdefs.Zip
+
+# optional tasks
+antlr=org.apache.tools.ant.taskdefs.optional.ANTLR
+apt=org.apache.tools.ant.taskdefs.Apt
+attrib=org.apache.tools.ant.taskdefs.optional.windows.Attrib
+blgenclient=org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient
+cab=org.apache.tools.ant.taskdefs.optional.Cab
+cccheckin=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckin
+cccheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCCheckout
+cclock=org.apache.tools.ant.taskdefs.optional.clearcase.CCLock
+ccmcheckin=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckin
+ccmcheckintask=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckinDefault
+ccmcheckout=org.apache.tools.ant.taskdefs.optional.ccm.CCMCheckout
+ccmcreatetask=org.apache.tools.ant.taskdefs.optional.ccm.CCMCreateTask
+ccmkattr=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkattr
+ccmkbl=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkbl
+ccmkdir=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkdir
+ccmkelem=org.apache.tools.ant.taskdefs.optional.clearcase.CCMkelem
+ccmklabel=org.apache.tools.ant.taskdefs.optional.clearcase.CCMklabel
+ccmklbtype=org.apache.tools.ant.taskdefs.optional.clearcase.CCMklbtype
+ccmreconfigure=org.apache.tools.ant.taskdefs.optional.ccm.CCMReconfigure
+ccrmtype=org.apache.tools.ant.taskdefs.optional.clearcase.CCRmtype
+ccuncheckout=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnCheckout
+ccunlock=org.apache.tools.ant.taskdefs.optional.clearcase.CCUnlock
+ccupdate=org.apache.tools.ant.taskdefs.optional.clearcase.CCUpdate
+chgrp=org.apache.tools.ant.taskdefs.optional.unix.Chgrp
+chown=org.apache.tools.ant.taskdefs.optional.unix.Chown
+csc=org.apache.tools.ant.taskdefs.optional.dotnet.CSharp
+ddcreator=org.apache.tools.ant.taskdefs.optional.ejb.DDCreator
+depend=org.apache.tools.ant.taskdefs.optional.depend.Depend
+echoproperties=org.apache.tools.ant.taskdefs.optional.EchoProperties
+echoxml=org.apache.tools.ant.taskdefs.EchoXML
+ejbc=org.apache.tools.ant.taskdefs.optional.ejb.Ejbc
+ejbjar=org.apache.tools.ant.taskdefs.optional.ejb.EjbJar
+ftp=org.apache.tools.ant.taskdefs.optional.net.FTP
+funtest=org.apache.tools.ant.taskdefs.optional.testing.Funtest
+ilasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ilasm
+ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm
+image=org.apache.tools.ant.taskdefs.optional.image.Image
+importtypelib=org.apache.tools.ant.taskdefs.optional.dotnet.ImportTypelib
+iplanet-ejbc=org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbcTask
+jarlib-available=org.apache.tools.ant.taskdefs.optional.extension.JarLibAvailableTask
+jarlib-display=org.apache.tools.ant.taskdefs.optional.extension.JarLibDisplayTask
+jarlib-manifest=org.apache.tools.ant.taskdefs.optional.extension.JarLibManifestTask
+jarlib-resolve=org.apache.tools.ant.taskdefs.optional.extension.JarLibResolveTask
+javacc=org.apache.tools.ant.taskdefs.optional.javacc.JavaCC
+javah=org.apache.tools.ant.taskdefs.optional.Javah
+jdepend=org.apache.tools.ant.taskdefs.optional.jdepend.JDependTask
+jjdoc=org.apache.tools.ant.taskdefs.optional.javacc.JJDoc
+jjtree=org.apache.tools.ant.taskdefs.optional.javacc.JJTree
+jsharpc=org.apache.tools.ant.taskdefs.optional.dotnet.JSharp
+junit=org.apache.tools.ant.taskdefs.optional.junit.JUnitTask
+junitreport=org.apache.tools.ant.taskdefs.optional.junit.XMLResultAggregator
+makeurl=org.apache.tools.ant.taskdefs.MakeUrl
+native2ascii=org.apache.tools.ant.taskdefs.optional.Native2Ascii
+netrexxc=org.apache.tools.ant.taskdefs.optional.NetRexxC
+p4add=org.apache.tools.ant.taskdefs.optional.perforce.P4Add
+p4change=org.apache.tools.ant.taskdefs.optional.perforce.P4Change
+p4counter=org.apache.tools.ant.taskdefs.optional.perforce.P4Counter
+p4delete=org.apache.tools.ant.taskdefs.optional.perforce.P4Delete
+p4edit=org.apache.tools.ant.taskdefs.optional.perforce.P4Edit
+p4fstat=org.apache.tools.ant.taskdefs.optional.perforce.P4Fstat
+p4have=org.apache.tools.ant.taskdefs.optional.perforce.P4Have
+p4integrate=org.apache.tools.ant.taskdefs.optional.perforce.P4Integrate
+p4label=org.apache.tools.ant.taskdefs.optional.perforce.P4Label
+p4labelsync=org.apache.tools.ant.taskdefs.optional.perforce.P4Labelsync
+p4reopen=org.apache.tools.ant.taskdefs.optional.perforce.P4Reopen
+p4resolve=org.apache.tools.ant.taskdefs.optional.perforce.P4Resolve
+p4revert=org.apache.tools.ant.taskdefs.optional.perforce.P4Revert
+p4submit=org.apache.tools.ant.taskdefs.optional.perforce.P4Submit
+p4sync=org.apache.tools.ant.taskdefs.optional.perforce.P4Sync
+propertyfile=org.apache.tools.ant.taskdefs.optional.PropertyFile
+pvcs=org.apache.tools.ant.taskdefs.optional.pvcs.Pvcs
+replaceregexp=org.apache.tools.ant.taskdefs.optional.ReplaceRegExp
+resourcecount=org.apache.tools.ant.taskdefs.ResourceCount
+rexec=org.apache.tools.ant.taskdefs.optional.net.RExecTask
+rpm=org.apache.tools.ant.taskdefs.optional.Rpm
+schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate
+scp=org.apache.tools.ant.taskdefs.optional.ssh.Scp
+script=org.apache.tools.ant.taskdefs.optional.Script
+scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef
+serverdeploy=org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+setproxy=org.apache.tools.ant.taskdefs.optional.net.SetProxy
+soscheckin=org.apache.tools.ant.taskdefs.optional.sos.SOSCheckin
+soscheckout=org.apache.tools.ant.taskdefs.optional.sos.SOSCheckout
+sosget=org.apache.tools.ant.taskdefs.optional.sos.SOSGet
+soslabel=org.apache.tools.ant.taskdefs.optional.sos.SOSLabel
+sound=org.apache.tools.ant.taskdefs.optional.sound.SoundTask
+splash=org.apache.tools.ant.taskdefs.optional.splash.SplashTask
+sshexec=org.apache.tools.ant.taskdefs.optional.ssh.SSHExec
+stcheckin=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamCheckin
+stcheckout=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamCheckout
+stlabel=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamLabel
+stlist=org.apache.tools.ant.taskdefs.optional.starteam.StarTeamList
+stylebook=org.apache.tools.ant.taskdefs.optional.StyleBook
+symlink=org.apache.tools.ant.taskdefs.optional.unix.Symlink
+telnet=org.apache.tools.ant.taskdefs.optional.net.TelnetTask
+translate=org.apache.tools.ant.taskdefs.optional.i18n.Translate
+vbc=org.apache.tools.ant.taskdefs.optional.dotnet.VisualBasicCompile
+verifyjar=org.apache.tools.ant.taskdefs.VerifyJar
+vssadd=org.apache.tools.ant.taskdefs.optional.vss.MSVSSADD
+vsscheckin=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKIN
+vsscheckout=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCHECKOUT
+vsscp=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCP
+vsscreate=org.apache.tools.ant.taskdefs.optional.vss.MSVSSCREATE
+vssget=org.apache.tools.ant.taskdefs.optional.vss.MSVSSGET
+vsshistory=org.apache.tools.ant.taskdefs.optional.vss.MSVSSHISTORY
+vsslabel=org.apache.tools.ant.taskdefs.optional.vss.MSVSSLABEL
+wljspc=org.apache.tools.ant.taskdefs.optional.jsp.WLJspc
+wlrun=org.apache.tools.ant.taskdefs.optional.ejb.WLRun
+wlstop=org.apache.tools.ant.taskdefs.optional.ejb.WLStop
+wsdltodotnet=org.apache.tools.ant.taskdefs.optional.dotnet.WsdlToDotnet
+xmlvalidate=org.apache.tools.ant.taskdefs.optional.XMLValidateTask
+
+
+# deprecated ant tasks (kept for back compatibility)
+copydir=org.apache.tools.ant.taskdefs.Copydir
+copyfile=org.apache.tools.ant.taskdefs.Copyfile
+copypath=org.apache.tools.ant.taskdefs.CopyPath
+deltree=org.apache.tools.ant.taskdefs.Deltree
+execon=org.apache.tools.ant.taskdefs.ExecuteOn
+javadoc2=org.apache.tools.ant.taskdefs.Javadoc
+jlink=org.apache.tools.ant.taskdefs.optional.jlink.JlinkTask
+jspc=org.apache.tools.ant.taskdefs.optional.jsp.JspC
+mimemail=org.apache.tools.ant.taskdefs.optional.net.MimeMail
+rename=org.apache.tools.ant.taskdefs.Rename
+renameext=org.apache.tools.ant.taskdefs.optional.RenameExtensions
+starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut
+style=org.apache.tools.ant.taskdefs.XSLTProcess
+WsdlToDotnet=org.apache.tools.ant.taskdefs.optional.dotnet.WsdlToDotnet
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java
new file mode 100644
index 0000000..bc76ff9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailAddress.java
@@ -0,0 +1,197 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+/**
+ * Holds an email address.
+ *
+ * @since Ant 1.5
+ */
+public class EmailAddress {
+    private String name;
+    private String address;
+
+
+    /** Creates an empty email address  */
+    public EmailAddress() {
+    }
+
+
+    /**
+     * Creates a new email address based on the given string
+     *
+     * @param email the email address (with or without <>)
+     * Acceptable forms include:
+     *    address
+     *    <address>
+     *    name <address>
+     *    <address> name
+     *    (name) address
+     *    address (name)
+     */
+    // Make a limited attempt to extract a sanitized name and email address
+    // Algorithm based on the one found in Ant's MailMessage.java
+    public EmailAddress(String email) {
+        final int minLen = 9;
+        int len = email.length();
+
+        // shortcut for "<address>"
+        if (len > minLen) {
+            if ((email.charAt(0) == '<' || email.charAt(1) == '<')
+            && (email.charAt(len - 1) == '>' || email.charAt(len - 2) == '>')) {
+                this.address = trim(email, true);
+                return;
+            }
+        }
+
+        int paramDepth = 0;
+        int start = 0;
+        int end = 0;
+        int nStart = 0;
+        int nEnd = 0;
+
+        for (int i = 0; i < len; i++) {
+            char c = email.charAt(i);
+            if (c == '(') {
+                paramDepth++;
+                if (start == 0) {
+                    end = i;  // support "address (name)"
+                    nStart = i + 1;
+                }
+            } else if (c == ')') {
+                paramDepth--;
+                if (end == 0) {
+                    start = i + 1;  // support "(name) address"
+                    nEnd = i;
+                }
+            } else if (paramDepth == 0 && c == '<') {
+                if (start == 0) {
+                    nEnd = i;
+                }
+                start = i + 1;
+            } else if (paramDepth == 0 && c == '>') {
+                end = i;
+                if (end != len - 1) {
+                    nStart = i + 1;
+                }
+            }
+        }
+
+        // DEBUG: System.out.println( email );
+        if (end == 0) {
+            end = len;
+        }
+        // DEBUG: System.out.println( "address: " + start + " " + end );
+        if (nEnd == 0) {
+            nEnd = len;
+        }
+        // DEBUG: System.out.println( "name: " + nStart + " " + nEnd );
+
+        this.address = trim(email.substring(start, end), true);
+        this.name = trim(email.substring(nStart, nEnd), false);
+
+        // if the two substrings are longer than the original, then name
+        // contains address - so reset the name to null
+        if (this.name.length() + this.address.length() > len) {
+            this.name = null;
+        }
+    }
+
+    /**
+     *  A specialised trim() that trims whitespace,
+     *  '(', ')', '"', '<', '>' from the start and end of strings
+     */
+    private String trim(String t, boolean trimAngleBrackets) {
+        int start = 0;
+        int end = t.length();
+        boolean trim = false;
+        do {
+            trim = false;
+            if (t.charAt(end - 1) == ')'
+                || (t.charAt(end - 1) == '>' && trimAngleBrackets)
+                || (t.charAt(end - 1) == '"' && t.charAt(end - 2) != '\\')
+                || t.charAt(end - 1) <= '\u0020') {
+                trim = true;
+                end--;
+            }
+            if (t.charAt(start) == '('
+                || (t.charAt(start) == '<' && trimAngleBrackets)
+                || t.charAt(start) == '"'
+                || t.charAt(start) <= '\u0020') {
+                trim = true;
+                start++;
+            }
+        } while (trim);
+        return t.substring(start, end);
+    }
+
+
+    /**
+     * Sets the personal / display name of the address
+     *
+     * @param name the display name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+
+    /**
+     * Sets the email address
+     *
+     * @param address the actual email address (without <>)
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+
+    /**
+     * Constructs a string "name &lt;address&gt;" or "address"
+     *
+     * @return a string representation of the address
+     */
+    public String toString() {
+        if (name == null) {
+            return address;
+        } else {
+            return name + " <" + address + ">";
+        }
+    }
+
+
+    /**
+     * Returns the address
+     *
+     * @return the address part
+     */
+    public String getAddress() {
+        return address;
+    }
+
+
+    /**
+     * Returns the display name
+     *
+     * @return the display name part
+     */
+    public String getName() {
+        return name;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java
new file mode 100644
index 0000000..e144ba3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/EmailTask.java
@@ -0,0 +1,582 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+/**
+ * A task to send SMTP email. This is a refactoring of the SendMail and
+ * MimeMail tasks such that both are within a single task.
+ *
+ * @since Ant 1.5
+ * @ant.task name="mail" category="network"
+ */
+public class EmailTask extends Task {
+    private static final int SMTP_PORT = 25;
+
+    /** Constant to show that the best available mailer should be used.  */
+    public static final String AUTO = "auto";
+    /** Constant to allow the Mime mailer to be requested  */
+    public static final String MIME = "mime";
+    /** Constant to allow the UU mailer to be requested  */
+    public static final String UU = "uu";
+    /** Constant to allow the plaintext mailer to be requested  */
+    public static final String PLAIN = "plain";
+
+    /**
+     * Enumerates the encoding constants.
+     */
+    public static class Encoding extends EnumeratedAttribute {
+        /**
+         * finds the valid encoding values
+         *
+         * @return a list of valid entries
+         */
+        public String[] getValues() {
+            return new String[] {AUTO, MIME, UU, PLAIN};
+        }
+    }
+
+    private String encoding = AUTO;
+    /** host running SMTP  */
+    private String host = "localhost";
+    private int port = SMTP_PORT;
+    /** subject field  */
+    private String subject = null;
+    /** any text  */
+    private Message message = null;
+    /** failure flag */
+    private boolean failOnError = true;
+    private boolean includeFileNames = false;
+    private String messageMimeType = null;
+    /* special headers */
+    /** sender  */
+    private EmailAddress from = null;
+    /** replyto */
+    private Vector replyToList = new Vector();
+    /** TO recipients  */
+    private Vector toList = new Vector();
+    /** CC (Carbon Copy) recipients  */
+    private Vector ccList = new Vector();
+    /** BCC (Blind Carbon Copy) recipients  */
+    private Vector bccList = new Vector();
+
+    /** generic headers */
+    private Vector headers = new Vector();
+
+    /** file list  */
+    private Path attachments = null;
+    /** Character set for MimeMailer*/
+    private String charset = null;
+    /** User for SMTP auth */
+    private String user = null;
+    /** Password for SMTP auth */
+    private String password = null;
+    /** indicate if the user wishes SSL-TLS */
+    private boolean ssl = false;
+
+    /**
+     * Set the user for SMTP auth; this requires JavaMail.
+     * @param user the String username.
+     * @since Ant 1.6
+     */
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    /**
+     * Set the password for SMTP auth; this requires JavaMail.
+     * @param password the String password.
+     * @since Ant 1.6
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Set whether to send data over SSL.
+     * @param ssl boolean; if true SSL will be used.
+     * @since Ant 1.6
+     */
+    public void setSSL(boolean ssl) {
+        this.ssl = ssl;
+    }
+
+    /**
+     * Set the preferred encoding method.
+     *
+     * @param encoding The encoding (one of AUTO, MIME, UU, PLAIN).
+     */
+    public void setEncoding(Encoding encoding) {
+        this.encoding = encoding.getValue();
+    }
+
+    /**
+     * Set the mail server port.
+     *
+     * @param port The port to use.
+     */
+    public void setMailport(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Set the host.
+     *
+     * @param host The host to connect to.
+     */
+    public void setMailhost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Set the subject line of the email.
+     *
+     * @param subject Subject of this email.
+     */
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    /**
+     * Shorthand method to set the message.
+     *
+     * @param message Message body of this email.
+     */
+    public void setMessage(String message) {
+        if (this.message != null) {
+            throw new BuildException("Only one message can be sent in an "
+                 + "email");
+        }
+        this.message = new Message(message);
+        this.message.setProject(getProject());
+    }
+
+    /**
+     * Shorthand method to set the message from a file.
+     *
+     * @param file The file from which to take the message.
+     */
+    public void setMessageFile(File file) {
+        if (this.message != null) {
+            throw new BuildException("Only one message can be sent in an "
+                 + "email");
+        }
+        this.message = new Message(file);
+        this.message.setProject(getProject());
+    }
+
+    /**
+     * Shorthand method to set type of the text message, text/plain by default
+     * but text/html or text/xml is quite feasible.
+     *
+     * @param type The new MessageMimeType value.
+     */
+    public void setMessageMimeType(String type) {
+        this.messageMimeType = type;
+    }
+
+    /**
+     * Add a message element.
+     *
+     * @param message The message object.
+     * @throws BuildException if a message has already been added.
+     */
+    public void addMessage(Message message) throws BuildException {
+        if (this.message != null) {
+            throw new BuildException(
+                "Only one message can be sent in an email");
+        }
+        this.message = message;
+    }
+
+    /**
+     * Add a from address element.
+     *
+     * @param address The address to send from.
+     */
+    public void addFrom(EmailAddress address) {
+        if (this.from != null) {
+            throw new BuildException("Emails can only be from one address");
+        }
+        this.from = address;
+    }
+
+    /**
+     * Shorthand to set the from address element.
+     *
+     * @param address The address to send mail from.
+     */
+    public void setFrom(String address) {
+        if (this.from != null) {
+            throw new BuildException("Emails can only be from one address");
+        }
+        this.from = new EmailAddress(address);
+    }
+
+    /**
+     * Add a replyto address element.
+     *
+     * @param address The address to reply to.
+     * @since Ant 1.6
+     */
+    public void addReplyTo(EmailAddress address) {
+        this.replyToList.add(address);
+    }
+
+    /**
+     * Shorthand to set the replyto address element.
+     *
+     * @param address The address to which replies should be directed.
+     * @since Ant 1.6
+     */
+    public void setReplyTo(String address) {
+        this.replyToList.add(new EmailAddress(address));
+    }
+
+    /**
+     * Add a to address element.
+     *
+     * @param address An email address.
+     */
+    public void addTo(EmailAddress address) {
+        toList.addElement(address);
+    }
+
+    /**
+     * Shorthand to set the "to" address element.
+     *
+     * @param list Comma-separated list of addresses.
+     */
+    public void setToList(String list) {
+        StringTokenizer tokens = new StringTokenizer(list, ",");
+
+        while (tokens.hasMoreTokens()) {
+            toList.addElement(new EmailAddress(tokens.nextToken()));
+        }
+    }
+
+    /**
+     * Add a "cc" address element.
+     *
+     * @param address The email address.
+     */
+    public void addCc(EmailAddress address) {
+        ccList.addElement(address);
+    }
+
+    /**
+     * Shorthand to set the "cc" address element.
+     *
+     * @param list Comma separated list of addresses.
+     */
+    public void setCcList(String list) {
+        StringTokenizer tokens = new StringTokenizer(list, ",");
+
+        while (tokens.hasMoreTokens()) {
+            ccList.addElement(new EmailAddress(tokens.nextToken()));
+        }
+    }
+
+    /**
+     * Add a "bcc" address element.
+     *
+     * @param address The email address.
+     */
+    public void addBcc(EmailAddress address) {
+        bccList.addElement(address);
+    }
+
+    /**
+     * Shorthand to set the "bcc" address element.
+     *
+     * @param list comma separated list of addresses.
+     */
+    public void setBccList(String list) {
+        StringTokenizer tokens = new StringTokenizer(list, ",");
+
+        while (tokens.hasMoreTokens()) {
+            bccList.addElement(new EmailAddress(tokens.nextToken()));
+        }
+    }
+
+    /**
+     * Set whether BuildExceptions should be passed back to the core.
+     *
+     * @param failOnError The new FailOnError value.
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * Set the list of files to be attached.
+     *
+     * @param filenames Comma-separated list of files.
+     */
+    public void setFiles(String filenames) {
+        StringTokenizer t = new StringTokenizer(filenames, ", ");
+
+        while (t.hasMoreTokens()) {
+            createAttachments()
+                .add(new FileResource(getProject().resolveFile(t.nextToken())));
+        }
+    }
+
+    /**
+     * Add a set of files (nested fileset attribute).
+     *
+     * @param fs The fileset.
+     */
+    public void addFileset(FileSet fs) {
+        createAttachments().add(fs);
+    }
+
+    /**
+     * Creates a Path as container for attachments.  Supports any
+     * filesystem resource-collections that way.
+     * @return the path to be configured.
+     * @since Ant 1.7
+     */
+    public Path createAttachments() {
+        if (attachments == null) {
+            attachments = new Path(getProject());
+        }
+        return attachments.createPath();
+    }
+
+    /**
+     * Create a nested header element.
+     * @return a Header instance.
+     */
+    public Header createHeader() {
+        Header h = new Header();
+        headers.add(h);
+        return h;
+    }
+
+    /**
+     * Set whether to include filenames.
+     *
+     * @param includeFileNames Whether to include filenames in the text of the
+     *      message.
+     */
+    public void setIncludefilenames(boolean includeFileNames) {
+        this.includeFileNames = includeFileNames;
+    }
+
+    /**
+     * Get whether file names should be included.
+     *
+     * @return Identifies whether file names should be included.
+     */
+    public boolean getIncludeFileNames() {
+        return includeFileNames;
+    }
+
+    /**
+     * Send an email.
+     */
+    public void execute() {
+        Message savedMessage = message;
+
+        try {
+            Mailer mailer = null;
+
+            // prepare for the auto select mechanism
+            boolean autoFound = false;
+            // try MIME format
+            if (encoding.equals(MIME)
+                 || (encoding.equals(AUTO) && !autoFound)) {
+                try {
+                    mailer = (Mailer) ClasspathUtils.newInstance(
+                            "org.apache.tools.ant.taskdefs.email.MimeMailer",
+                            EmailTask.class.getClassLoader(), Mailer.class);
+                    autoFound = true;
+                    log("Using MIME mail", Project.MSG_VERBOSE);
+                } catch (BuildException e) {
+                    logBuildException("Failed to initialise MIME mail: ", e);
+                    return;
+                }
+            }
+            // SMTP auth only allowed with MIME mail
+            if (!autoFound && ((user != null) || (password != null))
+                && (encoding.equals(UU) || encoding.equals(PLAIN))) {
+                throw new BuildException("SMTP auth only possible with MIME mail");
+            }
+            // SSL only allowed with MIME mail
+            if (!autoFound  && (ssl)
+                && (encoding.equals(UU) || encoding.equals(PLAIN))) {
+                throw new BuildException("SSL only possible with MIME mail");
+            }
+            // try UU format
+            if (encoding.equals(UU)
+                 || (encoding.equals(AUTO) && !autoFound)) {
+                try {
+                    mailer = (Mailer) ClasspathUtils.newInstance(
+                            "org.apache.tools.ant.taskdefs.email.UUMailer",
+                            EmailTask.class.getClassLoader(), Mailer.class);
+                    autoFound = true;
+                    log("Using UU mail", Project.MSG_VERBOSE);
+                } catch (BuildException e) {
+                    logBuildException("Failed to initialise UU mail: ", e);
+                    return;
+                }
+            }
+            // try plain format
+            if (encoding.equals(PLAIN)
+                 || (encoding.equals(AUTO) && !autoFound)) {
+                mailer = new PlainMailer();
+                autoFound = true;
+                log("Using plain mail", Project.MSG_VERBOSE);
+            }
+            // a valid mailer must be present by now
+            if (mailer == null) {
+                throw new BuildException("Failed to initialise encoding: "
+                     + encoding);
+            }
+            // a valid message is required
+            if (message == null) {
+                message = new Message();
+                message.setProject(getProject());
+            }
+            // an address to send from is required
+            if (from == null || from.getAddress() == null) {
+                throw new BuildException("A from element is required");
+            }
+            // at least one address to send to/cc/bcc is required
+            if (toList.isEmpty() && ccList.isEmpty() && bccList.isEmpty()) {
+                throw new BuildException("At least one of to, cc or bcc must "
+                     + "be supplied");
+            }
+            // set the mimetype if not done already (and required)
+            if (messageMimeType != null) {
+                if (message.isMimeTypeSpecified()) {
+                    throw new BuildException("The mime type can only be "
+                         + "specified in one location");
+                }
+                message.setMimeType(messageMimeType);
+            }
+            // set the character set if not done already (and required)
+            if (charset != null) {
+                if (message.getCharset() != null) {
+                    throw new BuildException("The charset can only be "
+                         + "specified in one location");
+                }
+                message.setCharset(charset);
+            }
+
+            // identify which files should be attached
+            Vector files = new Vector();
+            if (attachments != null) {
+                Iterator iter = attachments.iterator();
+
+                while (iter.hasNext()) {
+                    FileResource fr = (FileResource) iter.next();
+                    files.addElement(fr.getFile());
+                }
+            }
+            // let the user know what's going to happen
+            log("Sending email: " + subject, Project.MSG_INFO);
+            log("From " + from, Project.MSG_VERBOSE);
+            log("ReplyTo " + replyToList, Project.MSG_VERBOSE);
+            log("To " + toList, Project.MSG_VERBOSE);
+            log("Cc " + ccList, Project.MSG_VERBOSE);
+            log("Bcc " + bccList, Project.MSG_VERBOSE);
+
+            // pass the params to the mailer
+            mailer.setHost(host);
+            mailer.setPort(port);
+            mailer.setUser(user);
+            mailer.setPassword(password);
+            mailer.setSSL(ssl);
+            mailer.setMessage(message);
+            mailer.setFrom(from);
+            mailer.setReplyToList(replyToList);
+            mailer.setToList(toList);
+            mailer.setCcList(ccList);
+            mailer.setBccList(bccList);
+            mailer.setFiles(files);
+            mailer.setSubject(subject);
+            mailer.setTask(this);
+            mailer.setIncludeFileNames(includeFileNames);
+            mailer.setHeaders(headers);
+
+            // send the email
+            mailer.send();
+
+            // let the user know what happened
+            int count = files.size();
+
+            log("Sent email with " + count + " attachment"
+                 + (count == 1 ? "" : "s"), Project.MSG_INFO);
+        } catch (BuildException e) {
+            logBuildException("Failed to send email: ", e);
+            if (failOnError) {
+                throw e;
+            }
+        } catch (Exception e) {
+          log("Failed to send email: " + e.getMessage(), Project.MSG_WARN);
+          if (failOnError) {
+            throw new BuildException(e);
+          }
+        } finally {
+            message = savedMessage;
+        }
+    }
+
+    private void logBuildException(String reason, BuildException e) {
+        Throwable t = e.getCause() == null ? e : e.getCause();
+        log(reason + t.getMessage(), Project.MSG_WARN);
+    }
+
+    /**
+     * Sets the character set of mail message.
+     * Will be ignored if mimeType contains ....; Charset=... substring or
+     * encoding is not a <code>mime</code>.
+     * @param charset the character encoding to use.
+     * @since Ant 1.6
+     */
+    public void setCharset(String charset) {
+        this.charset = charset;
+    }
+
+    /**
+     * Returns the character set of mail message.
+     *
+     * @return Charset of mail message.
+     * @since Ant 1.6
+     */
+    public String getCharset() {
+        return charset;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/Header.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Header.java
new file mode 100755
index 0000000..6bcfb66
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Header.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.email;
+
+/**
+ * Class representing a generic e-mail header.
+ * @since Ant 1.7
+ */
+public class Header {
+    private String name;
+    private String value;
+
+    /**
+     * Set the name of this Header.
+     * @param name the name to set.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get the name of this Header.
+     * @return name as String.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Set the value of this Header.
+     * @param value the value to set.
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the value of this Header.
+     * @return value as String.
+     */
+    public String getValue() {
+        return value;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java
new file mode 100644
index 0000000..b9a6456
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Mailer.java
@@ -0,0 +1,220 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.DateUtils;
+
+/**
+ * Base class for the various emailing implementations.
+ *
+ * @since Ant 1.5
+ */
+public abstract class Mailer {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String host = null;
+    protected int port = -1;
+    protected String user = null;
+    protected String password = null;
+    // CheckStyle:MemberNameCheck OFF - bc
+    protected boolean SSL = false;
+    // CheckStyle:MemberNameCheck ON
+    protected Message message;
+    protected EmailAddress from;
+    protected Vector replyToList = null;
+    protected Vector toList = null;
+    protected Vector ccList = null;
+    protected Vector bccList = null;
+    protected Vector files = null;
+    protected String subject = null;
+    protected Task task;
+    protected boolean includeFileNames = false;
+    protected Vector headers = null;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the mail server.
+     *
+     * @param host the mail server name.
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Set the smtp port.
+     *
+     * @param port the SMTP port.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Set the user for smtp auth.
+     *
+     * @param user the username.
+     * @since Ant 1.6
+     */
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    /**
+     * Set the password for smtp auth.
+     *
+     * @param password the authentication password.
+     * @since Ant 1.6
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Set whether to send the mail through SSL.
+     *
+     * @param ssl if true use SSL transport.
+     * @since Ant 1.6
+     */
+    public void setSSL(boolean ssl) {
+        this.SSL = ssl;
+    }
+
+    /**
+     * Set the message.
+     *
+     * @param m the message content.
+     */
+    public void setMessage(Message m) {
+        this.message = m;
+    }
+
+    /**
+     * Set the address to send from.
+     *
+     * @param from the sender.
+     */
+    public void setFrom(EmailAddress from) {
+        this.from = from;
+    }
+
+    /**
+     * Set the replyto addresses.
+     *
+     * @param list a vector of reployTo addresses.
+     * @since Ant 1.6
+     */
+    public void setReplyToList(Vector list) {
+        this.replyToList = list;
+    }
+
+    /**
+     * Set the to addresses.
+     *
+     * @param list a vector of recipient addresses.
+     */
+    public void setToList(Vector list) {
+        this.toList = list;
+    }
+
+    /**
+     * Set the cc addresses.
+     *
+     * @param list a vector of cc addresses.
+     */
+    public void setCcList(Vector list) {
+        this.ccList = list;
+    }
+
+    /**
+     * Set the bcc addresses.
+     *
+     * @param list a vector of the bcc addresses.
+     */
+    public void setBccList(Vector list) {
+        this.bccList = list;
+    }
+
+    /**
+     * Set the files to attach.
+     *
+     * @param files list of files to attach to the email.
+     */
+    public void setFiles(Vector files) {
+        this.files = files;
+    }
+
+    /**
+     * Set the subject.
+     *
+     * @param subject the subject line.
+     */
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    /**
+     * Set the owning task.
+     *
+     * @param task the owning task instance.
+     */
+    public void setTask(Task task) {
+        this.task = task;
+    }
+
+    /**
+     * Indicate whether filenames should be listed in the body.
+     *
+     * @param b if true list attached file names in the body content.
+     */
+    public void setIncludeFileNames(boolean b) {
+        this.includeFileNames = b;
+    }
+
+    /**
+     * Set the generic headers to add to the email.
+     * @param v a Vector presumed to contain Header objects.
+     * @since Ant 1.7
+     */
+    public void setHeaders(Vector v) {
+        this.headers = v;
+    }
+
+    /**
+     * Send the email.
+     *
+     * @throws BuildException if the email can't be sent.
+     */
+    public abstract void send()
+         throws BuildException;
+
+    /**
+     * Return the current Date in a format suitable for a SMTP date
+     * header.
+     *
+     * @return the current date in SMTP suitable format.
+     *
+     * @since Ant 1.5
+     */
+    protected final String getDate() {
+        return DateUtils.getDateForHeader();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/Message.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Message.java
new file mode 100644
index 0000000..391387b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/Message.java
@@ -0,0 +1,169 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Class representing an email message.
+ *
+ * @since Ant 1.5
+ */
+public class Message extends ProjectComponent {
+    private File messageSource = null;
+    private StringBuffer buffer = new StringBuffer();
+    private String mimeType = "text/plain";
+    private boolean specified = false;
+    private String charset = null;
+
+    /** Creates a new empty message  */
+    public Message() {
+    }
+
+
+    /**
+     * Creates a new message based on the given string
+     *
+     * @param text the message
+     */
+    public Message(String text) {
+        addText(text);
+    }
+
+
+    /**
+     * Creates a new message using the contents of the given file.
+     *
+     * @param file the source of the message
+     */
+    public Message(File file) {
+        messageSource = file;
+    }
+
+
+    /**
+     * Adds a textual part of the message
+     *
+     * @param text some text to add
+     */
+    public void addText(String text) {
+        buffer.append(text);
+    }
+
+
+    /**
+     * Sets the source file of the message
+     *
+     * @param src the source of the message
+     */
+    public void setSrc(File src) {
+        this.messageSource = src;
+    }
+
+
+    /**
+     * Sets the content type for the message
+     *
+     * @param mimeType a mime type e.g. "text/plain"
+     */
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+        specified = true;
+    }
+
+
+    /**
+     * Returns the content type
+     *
+     * @return the mime type
+     */
+    public String getMimeType() {
+        return mimeType;
+    }
+
+
+    /**
+     * Prints the message onto an output stream
+     *
+     * @param ps The print stream to write to
+     * @throws IOException if an error occurs
+     */
+    public void print(PrintStream ps)
+         throws IOException {
+        // We need character encoding aware printing here.
+        // So, using PrintWriter over OutputStreamWriter instead of PrintStream
+        PrintWriter out
+            = charset != null ? new PrintWriter(new OutputStreamWriter(ps, charset))
+                              : new PrintWriter(ps);
+        if (messageSource != null) {
+            // Read message from a file
+            FileReader freader = new FileReader(messageSource);
+
+            try {
+                BufferedReader in = new BufferedReader(freader);
+                String line = null;
+                while ((line = in.readLine()) != null) {
+                    out.println(getProject().replaceProperties(line));
+                }
+            } finally {
+                freader.close();
+            }
+        } else {
+            out.println(getProject().replaceProperties(buffer.substring(0)));
+        }
+        out.flush();
+    }
+
+
+    /**
+     * Returns true if the mimeType has been set.
+     *
+     * @return false if the default value is in use
+     */
+    public boolean isMimeTypeSpecified() {
+        return specified;
+    }
+
+    /**
+     * Sets the character set of mail message.
+     * Will be ignored if mimeType contains ....; Charset=... substring.
+     * @param charset the character set name.
+     * @since Ant 1.6
+     */
+    public void setCharset(String charset) {
+      this.charset = charset;
+    }
+    /**
+     * Returns the charset of mail message.
+     *
+     * @return Charset of mail message.
+     * @since Ant 1.6
+     */
+    public String getCharset() {
+      return charset;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java
new file mode 100644
index 0000000..a6c15da
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/MimeMailer.java
@@ -0,0 +1,289 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+
+import java.security.Provider;
+import java.security.Security;
+
+import javax.activation.DataHandler;
+import javax.activation.FileDataSource;
+
+import javax.mail.Message;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.Authenticator;
+import javax.mail.MessagingException;
+import javax.mail.PasswordAuthentication;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMultipart;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.AddressException;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Uses the JavaMail classes to send Mime format email.
+ *
+ * @since Ant 1.5
+ */
+public class MimeMailer extends Mailer {
+    private static final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
+
+    /** Default character set */
+    private static final String DEFAULT_CHARSET
+        = System.getProperty("file.encoding");
+
+    // To work properly with national charsets we have to use
+    // implementation of interface javax.activation.DataSource
+    /**
+     * String data source implementation.
+     * @since Ant 1.6
+     */
+    class StringDataSource implements javax.activation.DataSource {
+        private String data = null;
+        private String type = null;
+        private String charset = null;
+        private ByteArrayOutputStream out;
+
+        public InputStream getInputStream() throws IOException {
+            if (data == null && out == null) {
+                throw new IOException("No data");
+            }
+            if (out != null) {
+                String encodedOut = out.toString(charset);
+                data = (data != null) ? data.concat(encodedOut) : encodedOut;
+                out = null;
+            }
+            return new ByteArrayInputStream(data.getBytes(charset));
+        }
+
+        public OutputStream getOutputStream() throws IOException {
+            out = (out == null) ? new ByteArrayOutputStream() : out;
+            return out;
+        }
+
+        public void setContentType(String type) {
+            this.type = type.toLowerCase();
+        }
+
+        public String getContentType() {
+            if (type != null && type.indexOf("charset") > 0
+                && type.startsWith("text/")) {
+                return type;
+            }
+            // Must be like "text/plain; charset=windows-1251"
+            return new StringBuffer(type != null ? type : "text/plain").append(
+                "; charset=").append(charset).toString();
+        }
+
+        public String getName() {
+            return "StringDataSource";
+        }
+
+        public void setCharset(String charset) {
+            this.charset = charset;
+        }
+
+        public String getCharset() {
+            return charset;
+        }
+    }
+
+    /**
+     * Send the email.
+     *
+     * @throws BuildException if the email can't be sent.
+     */
+    public void send() {
+        try {
+            Properties props = new Properties();
+
+            props.put("mail.smtp.host", host);
+            props.put("mail.smtp.port", String.valueOf(port));
+
+            // Aside, the JDK is clearly unaware of the Scottish
+            // 'session', which involves excessive quantities of
+            // alcohol :-)
+            Session sesh;
+            Authenticator auth;
+            if (SSL) {
+                try {
+                    Provider p = (Provider) Class.forName(
+                        "com.sun.net.ssl.internal.ssl.Provider").newInstance();
+                    Security.addProvider(p);
+                } catch (Exception e) {
+                    throw new BuildException("could not instantiate ssl "
+                        + "security provider, check that you have JSSE in "
+                        + "your classpath");
+                }
+                // SMTP provider
+                props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
+                props.put("mail.smtp.socketFactory.fallback", "false");
+            }
+            if (user == null && password == null) {
+                sesh = Session.getDefaultInstance(props, null);
+            } else {
+                props.put("mail.smtp.auth", "true");
+                auth = new SimpleAuthenticator(user, password);
+                sesh = Session.getInstance(props, auth);
+            }
+            //create the message
+            MimeMessage msg = new MimeMessage(sesh);
+            MimeMultipart attachments = new MimeMultipart();
+
+            //set the sender
+            if (from.getName() == null) {
+                msg.setFrom(new InternetAddress(from.getAddress()));
+            } else {
+                msg.setFrom(new InternetAddress(from.getAddress(),
+                    from.getName()));
+            }
+            // set the reply to addresses
+            msg.setReplyTo(internetAddresses(replyToList));
+            msg.setRecipients(Message.RecipientType.TO,
+                internetAddresses(toList));
+            msg.setRecipients(Message.RecipientType.CC,
+                internetAddresses(ccList));
+            msg.setRecipients(Message.RecipientType.BCC,
+                internetAddresses(bccList));
+
+            // Choosing character set of the mail message
+            // First: looking it from MimeType
+            String charset = parseCharSetFromMimeType(message.getMimeType());
+            if (charset != null) {
+                // Assign/reassign message charset from MimeType
+                message.setCharset(charset);
+            } else {
+                // Next: looking if charset having explicit definition
+                charset = message.getCharset();
+                if (charset == null) {
+                    // Using default
+                    charset = DEFAULT_CHARSET;
+                    message.setCharset(charset);
+                }
+            }
+            // Using javax.activation.DataSource paradigm
+            StringDataSource sds = new StringDataSource();
+            sds.setContentType(message.getMimeType());
+            sds.setCharset(charset);
+
+            if (subject != null) {
+                msg.setSubject(subject, charset);
+            }
+            msg.addHeader("Date", getDate());
+
+            for (Iterator iter = headers.iterator(); iter.hasNext();) {
+                Header h = (Header) iter.next();
+                msg.addHeader(h.getName(), h.getValue());
+            }
+            PrintStream out = new PrintStream(sds.getOutputStream());
+            message.print(out);
+            out.close();
+
+            MimeBodyPart textbody = new MimeBodyPart();
+            textbody.setDataHandler(new DataHandler(sds));
+            attachments.addBodyPart(textbody);
+
+            Enumeration e = files.elements();
+
+            while (e.hasMoreElements()) {
+                File file = (File) e.nextElement();
+
+                MimeBodyPart body;
+
+                body = new MimeBodyPart();
+                if (!file.exists() || !file.canRead()) {
+                    throw new BuildException("File \"" + file.getAbsolutePath()
+                         + "\" does not exist or is not "
+                         + "readable.");
+                }
+                FileDataSource fileData = new FileDataSource(file);
+                DataHandler fileDataHandler = new DataHandler(fileData);
+
+                body.setDataHandler(fileDataHandler);
+                body.setFileName(file.getName());
+                attachments.addBodyPart(body);
+            }
+            msg.setContent(attachments);
+            Transport.send(msg);
+        } catch (MessagingException e) {
+            throw new BuildException("Problem while sending mime mail:", e);
+        } catch (IOException e) {
+            throw new BuildException("Problem while sending mime mail:", e);
+        }
+    }
+
+    private static InternetAddress[] internetAddresses(Vector list)
+        throws AddressException, UnsupportedEncodingException {
+        InternetAddress[] addrs = new InternetAddress[list.size()];
+
+        for (int i = 0; i < list.size(); ++i) {
+            EmailAddress addr = (EmailAddress) list.elementAt(i);
+
+            String name = addr.getName();
+            addrs[i] = (name == null)
+                ? new InternetAddress(addr.getAddress())
+                : new InternetAddress(addr.getAddress(), name);
+        }
+        return addrs;
+    }
+
+    private String parseCharSetFromMimeType(String type) {
+        if (type == null) {
+            return null;
+        }
+        int pos = type.indexOf("charset");
+        if (pos < 0) {
+          return null;
+        }
+        // Assuming mime type in form "text/XXXX; charset=XXXXXX"
+        StringTokenizer token = new StringTokenizer(type.substring(pos), "=; ");
+        token.nextToken(); // Skip 'charset='
+        return token.nextToken();
+    }
+
+    static class SimpleAuthenticator extends Authenticator {
+        private String user = null;
+        private String password = null;
+        public SimpleAuthenticator(String user, String password) {
+            this.user = user;
+            this.password = password;
+        }
+        public PasswordAuthentication getPasswordAuthentication() {
+
+            return new PasswordAuthentication(user, password);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java
new file mode 100644
index 0000000..8d85ef2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/PlainMailer.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.mail.MailMessage;
+
+/**
+ * Class responsible for sending email through raw protocol methods.
+ *
+ * @since Ant 1.5
+ */
+class PlainMailer extends Mailer {
+    /**
+     * Sends the email using the apache MailMessage class.
+     *
+     * @see org.apache.tools.mail.MailMessage
+     */
+    public void send() {
+        try {
+            MailMessage mailMessage = new MailMessage(host, port);
+
+            mailMessage.from(from.toString());
+
+            Enumeration e;
+
+            e = replyToList.elements();
+            while (e.hasMoreElements()) {
+                mailMessage.replyto(e.nextElement().toString());
+            }
+            e = toList.elements();
+            while (e.hasMoreElements()) {
+                mailMessage.to(e.nextElement().toString());
+            }
+            e = ccList.elements();
+            while (e.hasMoreElements()) {
+                mailMessage.cc(e.nextElement().toString());
+            }
+            e = bccList.elements();
+            while (e.hasMoreElements()) {
+                mailMessage.bcc(e.nextElement().toString());
+            }
+            if (subject != null) {
+                mailMessage.setSubject(subject);
+            }
+            mailMessage.setHeader("Date", getDate());
+            if (message.getCharset() != null) {
+                mailMessage.setHeader("Content-Type", message.getMimeType()
+                    + "; charset=\"" + message.getCharset() + "\"");
+            } else {
+                mailMessage.setHeader("Content-Type", message.getMimeType());
+            }
+            e = headers.elements();
+            while (e.hasMoreElements()) {
+                Header h = (Header) e.nextElement();
+                mailMessage.setHeader(h.getName(), h.getValue());
+            }
+            PrintStream out = mailMessage.getPrintStream();
+            message.print(out);
+
+            e = files.elements();
+            while (e.hasMoreElements()) {
+                attach((File) e.nextElement(), out);
+            }
+            mailMessage.sendAndClose();
+        } catch (IOException ioe) {
+            throw new BuildException("IO error sending mail", ioe);
+        }
+
+    }
+
+    /**
+     * Attaches a file to this email
+     *
+     * @param file The file to attache
+     * @param out The message stream to add to
+     * @throws IOException if errors occur
+     */
+    protected void attach(File file, PrintStream out)
+         throws IOException {
+        if (!file.exists() || !file.canRead()) {
+            throw new BuildException("File \"" + file.getName()
+                 + "\" does not exist or is not "
+                 + "readable.");
+        }
+
+        if (includeFileNames) {
+            out.println();
+
+            String filename = file.getName();
+            int filenamelength = filename.length();
+
+            out.println(filename);
+            for (int star = 0; star < filenamelength; star++) {
+                out.print('=');
+            }
+            out.println();
+        }
+
+        int length;
+        final int maxBuf = 1024;
+        byte[] buf = new byte[maxBuf];
+        FileInputStream finstr = new FileInputStream(file);
+
+        try {
+            BufferedInputStream in = new BufferedInputStream(finstr, buf.length);
+
+            while ((length = in.read(buf)) != -1) {
+                out.write(buf, 0, length);
+            }
+        } finally {
+            finstr.close();
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/email/UUMailer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/email/UUMailer.java
new file mode 100644
index 0000000..90f16bc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/email/UUMailer.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.email;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.UUEncoder;
+
+/**
+ * An emailer that uuencodes attachments.
+ *
+ * @since Ant 1.5
+ */
+class UUMailer extends PlainMailer {
+    protected void attach(File file, PrintStream out)
+         throws IOException {
+        if (!file.exists() || !file.canRead()) {
+            throw new BuildException("File \"" + file.getName()
+                 + "\" does not exist or is not "
+                 + "readable.");
+        }
+
+        FileInputStream finstr = new FileInputStream(file);
+
+        try {
+            BufferedInputStream in = new BufferedInputStream(finstr);
+            UUEncoder encoder = new UUEncoder(file.getName());
+
+            encoder.encode(in, out);
+
+        } finally {
+            finstr.close();
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java
new file mode 100644
index 0000000..008fc15
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ANTLR.java
@@ -0,0 +1,437 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ *  Invokes the ANTLR Translator generator on a grammar file.
+ *
+ */
+public class ANTLR extends Task {
+
+    private CommandlineJava commandline = new CommandlineJava();
+
+    /** the file to process */
+    private File targetFile;
+
+    /** where to output the result */
+    private File outputDirectory;
+
+    /** an optional super grammar file */
+    private File superGrammar;
+
+    /** optional flag to enable html output */
+    private boolean html;
+
+    /** optional flag to print out a diagnostic file */
+    private boolean diagnostic;
+
+    /** optional flag to add trace methods */
+    private boolean trace;
+
+    /** optional flag to add trace methods to the parser only */
+    private boolean traceParser;
+
+    /** optional flag to add trace methods to the lexer only */
+    private boolean traceLexer;
+
+    /** optional flag to add trace methods to the tree walker only */
+    private boolean traceTreeWalker;
+
+    /** working directory */
+    private File workingdir = null;
+
+    /** captures ANTLR's output */
+    private ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+    /** The debug attribute */
+    private boolean debug;
+
+
+    /** Instance of a utility class to use for file operations. */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Constructor for ANTLR task. */
+    public ANTLR() {
+        commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
+        commandline.setClassname("antlr.Tool");
+    }
+
+    /**
+     * The grammar file to process.
+     * @param target the gramer file
+     */
+    public void setTarget(File target) {
+        log("Setting target to: " + target.toString(), Project.MSG_VERBOSE);
+        this.targetFile = target;
+    }
+
+    /**
+     * The directory to write the generated files to.
+     * @param outputDirectory the output directory
+     */
+    public void setOutputdirectory(File outputDirectory) {
+        log("Setting output directory to: " + outputDirectory.toString(), Project.MSG_VERBOSE);
+        this.outputDirectory = outputDirectory;
+    }
+
+    /**
+     * Sets an optional super grammar file.
+     * Use setGlib(File superGrammar) instead.
+     * @param superGrammar the super grammar filename
+     * @deprecated  since ant 1.6
+     */
+    public void setGlib(String superGrammar) {
+        String sg = null;
+        if (Os.isFamily("dos")) {
+            sg = superGrammar.replace('\\', '/');
+        } else {
+            sg = superGrammar;
+        }
+        setGlib(FILE_UTILS.resolveFile(getProject().getBaseDir(), sg));
+    }
+    /**
+     * Sets an optional super grammar file
+     * @param superGrammar the super grammar file
+     * @since ant 1.6
+     */
+    public void setGlib(File superGrammar) {
+        this.superGrammar = superGrammar;
+    }
+    /**
+     * Sets a flag to enable ParseView debugging
+     * @param enable a <code>boolean</code> value
+     */
+    public void setDebug(boolean enable) {
+        this.debug = enable;
+    }
+
+    /**
+     * If true, emit html
+     * @param enable a <code>boolean</code> value
+     */
+    public void setHtml(boolean enable) {
+        html = enable;
+    }
+
+    /**
+     * Sets a flag to emit diagnostic text
+     * @param enable a <code>boolean</code> value
+     */
+    public void setDiagnostic(boolean enable) {
+        diagnostic = enable;
+    }
+
+    /**
+     * If true, enables all tracing.
+     * @param enable a <code>boolean</code> value
+     */
+    public void setTrace(boolean enable) {
+        trace = enable;
+    }
+
+    /**
+     * If true, enables parser tracing.
+     * @param enable a <code>boolean</code> value
+     */
+    public void setTraceParser(boolean enable) {
+        traceParser = enable;
+    }
+
+    /**
+     * If true, enables lexer tracing.
+     * @param enable a <code>boolean</code> value
+     */
+    public void setTraceLexer(boolean enable) {
+        traceLexer = enable;
+    }
+
+    /**
+     * Sets a flag to allow the user to enable tree walker tracing
+     * @param enable a <code>boolean</code> value
+     */
+    public void setTraceTreeWalker(boolean enable) {
+        traceTreeWalker = enable;
+    }
+
+    // we are forced to fork ANTLR since there is a call
+    // to System.exit() and there is nothing we can do
+    // right now to avoid this. :-( (SBa)
+    // I'm not removing this method to keep backward compatibility
+    /**
+     * @ant.attribute ignore="true"
+     * @param s a <code>boolean</code> value
+     */
+    public void setFork(boolean s) {
+        //this.fork = s;
+    }
+
+    /**
+     * The working directory of the process
+     * @param d the working directory
+     */
+    public void setDir(File d) {
+        this.workingdir = d;
+    }
+
+    /**
+     * Adds a classpath to be set
+     * because a directory might be given for Antlr debug.
+     * @return a path to be configured
+     */
+    public Path createClasspath() {
+        return commandline.createClasspath(getProject()).createPath();
+    }
+
+    /**
+     * Adds a new JVM argument.
+     * @return  create a new JVM argument so that any argument can be passed to the JVM.
+     * @see #setFork(boolean)
+     */
+    public Commandline.Argument createJvmarg() {
+        return commandline.createVmArgument();
+    }
+
+    /**
+     * Adds the jars or directories containing Antlr
+     * this should make the forked JVM work without having to
+     * specify it directly.
+     * @throws BuildException on error
+     */
+    public void init() throws BuildException {
+        addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class");
+    }
+
+    /**
+     * Search for the given resource and add the directory or archive
+     * that contains it to the classpath.
+     *
+     * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+     * getResource doesn't contain the name of the archive.</p>
+     * @param resource the resource name to search for
+     */
+    protected void addClasspathEntry(String resource) {
+        /*
+         * pre Ant 1.6 this method used to call getClass().getResource
+         * while Ant 1.6 will call ClassLoader.getResource().
+         *
+         * The difference is that Class.getResource expects a leading
+         * slash for "absolute" resources and will strip it before
+         * delegating to ClassLoader.getResource - so we now have to
+         * emulate Class's behavior.
+         */
+        if (resource.startsWith("/")) {
+            resource = resource.substring(1);
+        } else {
+            resource = "org/apache/tools/ant/taskdefs/optional/"
+                + resource;
+        }
+
+        File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
+                                               resource);
+        if (f != null) {
+            log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+            createClasspath().setLocation(f);
+        } else {
+            log("Couldn\'t find " + resource, Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        validateAttributes();
+
+        //TODO: use ANTLR to parse the grammar file to do this.
+        File generatedFile = getGeneratedFile();
+        boolean targetIsOutOfDate =
+            targetFile.lastModified() > generatedFile.lastModified();
+        boolean superGrammarIsOutOfDate  = superGrammar != null
+                && (superGrammar.lastModified() > generatedFile.lastModified());
+        if (targetIsOutOfDate || superGrammarIsOutOfDate) {
+            if (targetIsOutOfDate) {
+                log("Compiling " + targetFile + " as it is newer than "
+                    + generatedFile, Project.MSG_VERBOSE);
+            } else {
+                log("Compiling " + targetFile + " as " + superGrammar
+                    + " is newer than " + generatedFile, Project.MSG_VERBOSE);
+            }
+            populateAttributes();
+            commandline.createArgument().setValue(targetFile.toString());
+
+            log(commandline.describeCommand(), Project.MSG_VERBOSE);
+            int err = run(commandline.getCommandline());
+            if (err != 0) {
+                throw new BuildException("ANTLR returned: " + err, getLocation());
+            } else {
+                String output = bos.toString();
+                if (output.indexOf("error:") > -1) {
+                    throw new BuildException("ANTLR signaled an error: "
+                                             + output, getLocation());
+                }
+            }
+        } else {
+            log("Skipped grammar file. Generated file " + generatedFile
+                + " is newer.", Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * A refactored method for populating all the command line arguments based
+     * on the user-specified attributes.
+     */
+    private void populateAttributes() {
+        commandline.createArgument().setValue("-o");
+        commandline.createArgument().setValue(outputDirectory.toString());
+        if (superGrammar != null) {
+            commandline.createArgument().setValue("-glib");
+            commandline.createArgument().setValue(superGrammar.toString());
+        }
+        if (html) {
+            commandline.createArgument().setValue("-html");
+        }
+        if (diagnostic) {
+            commandline.createArgument().setValue("-diagnostic");
+        }
+        if (trace) {
+            commandline.createArgument().setValue("-trace");
+        }
+        if (traceParser) {
+            commandline.createArgument().setValue("-traceParser");
+        }
+        if (traceLexer) {
+            commandline.createArgument().setValue("-traceLexer");
+        }
+        if (traceTreeWalker) {
+            if (is272()) {
+                commandline.createArgument().setValue("-traceTreeParser");
+            } else {
+                commandline.createArgument().setValue("-traceTreeWalker");
+            }
+        }
+        if (debug) {
+            commandline.createArgument().setValue("-debug");
+        }
+    }
+
+    private void validateAttributes() throws BuildException {
+        if (targetFile == null || !targetFile.isFile()) {
+            throw new BuildException("Invalid target: " + targetFile);
+        }
+
+        // if no output directory is specified, used the target's directory
+        if (outputDirectory == null) {
+            setOutputdirectory(new File(targetFile.getParent()));
+        }
+        if (!outputDirectory.isDirectory()) {
+            throw new BuildException("Invalid output directory: " + outputDirectory);
+        }
+    }
+
+    private File getGeneratedFile() throws BuildException {
+        String generatedFileName = null;
+        try {
+            BufferedReader in = new BufferedReader(new FileReader(targetFile));
+            String line;
+            while ((line = in.readLine()) != null) {
+                int extendsIndex = line.indexOf(" extends ");
+                if (line.startsWith("class ") && extendsIndex > -1) {
+                    generatedFileName = line.substring(
+                        "class ".length(), extendsIndex).trim();
+                    break;
+                }
+            }
+            in.close();
+        } catch (Exception e) {
+            throw new BuildException("Unable to determine generated class", e);
+        }
+        if (generatedFileName == null) {
+            throw new BuildException("Unable to determine generated class");
+        }
+        return new File(outputDirectory, generatedFileName
+                        + (html ? ".html" : ".java"));
+    }
+
+    /** execute in a forked VM */
+    private int run(String[] command) throws BuildException {
+        PumpStreamHandler psh =
+            new PumpStreamHandler(new LogOutputStream(this, Project.MSG_INFO),
+                                  new TeeOutputStream(
+                                                      new LogOutputStream(this,
+                                                                          Project.MSG_WARN),
+                                                      bos)
+                                  );
+        Execute exe = new Execute(psh, null);
+        exe.setAntRun(getProject());
+        if (workingdir != null) {
+            exe.setWorkingDirectory(workingdir);
+        }
+        exe.setCommandline(command);
+        try {
+            return exe.execute();
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        } finally {
+            FileUtils.close(bos);
+        }
+    }
+
+    /**
+     * Whether the antlr version is 2.7.2 (or higher).
+     *
+     * @return true if the version of Antlr present is 2.7.2 or later.
+     * @since Ant 1.6
+     */
+    protected boolean is272() {
+        AntClassLoader l = null;
+        try {
+            l = getProject().createClassLoader(commandline.getClasspath());
+            l.loadClass("antlr.Version");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        } finally {
+            if (l != null) {
+                l.cleanup();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java
new file mode 100644
index 0000000..4bfb054
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java
@@ -0,0 +1,350 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.StreamPumper;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * Create a CAB archive.
+ *
+ */
+
+public class Cab extends MatchingTask {
+    private static final int DEFAULT_RESULT = -99;
+    private File cabFile;
+    private File baseDir;
+    private Vector filesets = new Vector();
+    private boolean doCompress = true;
+    private boolean doVerbose = false;
+    private String cmdOptions;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String archiveType = "cab";
+    // CheckStyle:VisibilityModifier ON
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * The name/location of where to create the .cab file.
+     * @param cabFile the location of the cab file.
+     */
+    public void setCabfile(File cabFile) {
+        this.cabFile = cabFile;
+    }
+
+    /**
+     * Base directory to look in for files to CAB.
+     * @param baseDir base directory for files to cab.
+     */
+    public void setBasedir(File baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * If true, compress the files otherwise only store them.
+     * @param compress a <code>boolean</code> value.
+     */
+    public void setCompress(boolean compress) {
+        doCompress = compress;
+    }
+
+    /**
+     * If true, display cabarc output.
+     * @param verbose a <code>boolean</code> value.
+     */
+    public void setVerbose(boolean verbose) {
+        doVerbose = verbose;
+    }
+
+    /**
+     * Sets additional cabarc options that are not supported directly.
+     * @param options cabarc command line options.
+     */
+    public void setOptions(String options) {
+        cmdOptions = options;
+    }
+
+    /**
+     * Adds a set of files to archive.
+     * @param set a set of files to archive.
+     */
+    public void addFileset(FileSet set) {
+        if (filesets.size() > 0) {
+            throw new BuildException("Only one nested fileset allowed");
+        }
+        filesets.addElement(set);
+    }
+
+    /*
+     * I'm not fond of this pattern: "sub-method expected to throw
+     * task-cancelling exceptions".  It feels too much like programming
+     * for side-effects to me...
+     */
+    /**
+     * Check if the attributes and nested elements are correct.
+     * @throws BuildException on error.
+     */
+    protected void checkConfiguration() throws BuildException {
+        if (baseDir == null && filesets.size() == 0) {
+            throw new BuildException("basedir attribute or one "
+                                     + "nested fileset is required!",
+                                     getLocation());
+        }
+        if (baseDir != null && !baseDir.exists()) {
+            throw new BuildException("basedir does not exist!", getLocation());
+        }
+        if (baseDir != null && filesets.size() > 0) {
+            throw new BuildException(
+                "Both basedir attribute and a nested fileset is not allowed");
+        }
+        if (cabFile == null) {
+            throw new BuildException("cabfile attribute must be set!",
+                                     getLocation());
+        }
+    }
+
+    /**
+     * Create a new exec delegate.  The delegate task is populated so that
+     * it appears in the logs to be the same task as this one.
+     * @return the delegate.
+     * @throws BuildException on error.
+     */
+    protected ExecTask createExec() throws BuildException {
+        ExecTask exec = new ExecTask(this);
+        return exec;
+    }
+
+    /**
+     * Check to see if the target is up to date with respect to input files.
+     * @param files the list of files to check.
+     * @return true if the cab file is newer than its dependents.
+     */
+    protected boolean isUpToDate(Vector files) {
+        boolean upToDate = true;
+        for (int i = 0; i < files.size() && upToDate; i++) {
+            String file = files.elementAt(i).toString();
+            if (FILE_UTILS.resolveFile(baseDir, file).lastModified()
+                    > cabFile.lastModified()) {
+                upToDate = false;
+            }
+        }
+        return upToDate;
+    }
+
+    /**
+     * Creates a list file.  This temporary file contains a list of all files
+     * to be included in the cab, one file per line.
+     *
+     * <p>This method expects to only be called on Windows and thus
+     * quotes the file names.</p>
+     * @param files the list of files to use.
+     * @return the list file created.
+     * @throws IOException if there is an error.
+     */
+    protected File createListFile(Vector files)
+        throws IOException {
+        File listFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
+
+        PrintWriter writer = new PrintWriter(new FileOutputStream(listFile));
+
+        int size = files.size();
+        for (int i = 0; i < size; i++) {
+            writer.println('\"' + files.elementAt(i).toString() + '\"');
+        }
+        writer.close();
+
+        return listFile;
+    }
+
+    /**
+     * Append all files found by a directory scanner to a vector.
+     * @param files the vector to append the files to.
+     * @param ds the scanner to get the files from.
+     */
+    protected void appendFiles(Vector files, DirectoryScanner ds) {
+        String[] dsfiles = ds.getIncludedFiles();
+
+        for (int i = 0; i < dsfiles.length; i++) {
+            files.addElement(dsfiles[i]);
+        }
+    }
+
+    /**
+     * Get the complete list of files to be included in the cab.  Filenames
+     * are gathered from the fileset if it has been added, otherwise from the
+     * traditional include parameters.
+     * @return the list of files.
+     * @throws BuildException if there is an error.
+     */
+    protected Vector getFileList() throws BuildException {
+        Vector files = new Vector();
+
+        if (baseDir != null) {
+            // get files from old methods - includes and nested include
+            appendFiles(files, super.getDirectoryScanner(baseDir));
+        } else {
+            FileSet fs = (FileSet) filesets.elementAt(0);
+            baseDir = fs.getDir();
+            appendFiles(files, fs.getDirectoryScanner(getProject()));
+        }
+
+        return files;
+    }
+
+    /**
+     * execute this task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+
+        checkConfiguration();
+
+        Vector files = getFileList();
+
+        // quick exit if the target is up to date
+        if (isUpToDate(files)) {
+            return;
+        }
+
+        log("Building " + archiveType + ": " + cabFile.getAbsolutePath());
+
+        if (!Os.isFamily("windows")) {
+            log("Using listcab/libcabinet", Project.MSG_VERBOSE);
+
+            StringBuffer sb = new StringBuffer();
+
+            Enumeration fileEnum = files.elements();
+
+            while (fileEnum.hasMoreElements()) {
+                sb.append(fileEnum.nextElement()).append("\n");
+            }
+            sb.append("\n").append(cabFile.getAbsolutePath()).append("\n");
+
+            try {
+                Process p = Execute.launch(getProject(),
+                                           new String[] {"listcab"}, null,
+                                           baseDir != null ? baseDir
+                                                   : getProject().getBaseDir(),
+                                           true);
+                OutputStream out = p.getOutputStream();
+
+                // Create the stream pumpers to forward listcab's stdout and stderr to the log
+                // note: listcab is an interactive program, and issues prompts for every new line.
+                //       Therefore, make it show only with verbose logging turned on.
+                LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE);
+                LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR);
+                StreamPumper    outPump = new StreamPumper(p.getInputStream(), outLog);
+                StreamPumper    errPump = new StreamPumper(p.getErrorStream(), errLog);
+
+                // Pump streams asynchronously
+                (new Thread(outPump)).start();
+                (new Thread(errPump)).start();
+
+                out.write(sb.toString().getBytes());
+                out.flush();
+                out.close();
+
+                // A wild default for when the thread is interrupted
+                int result = DEFAULT_RESULT;
+
+                try {
+                    // Wait for the process to finish
+                    result = p.waitFor();
+
+                    // Wait for the end of output and error streams
+                    outPump.waitFor();
+                    outLog.close();
+                    errPump.waitFor();
+                    errLog.close();
+                } catch (InterruptedException ie) {
+                    log("Thread interrupted: " + ie);
+                }
+
+                // Informative summary message in case of errors
+                if (Execute.isFailure(result)) {
+                    log("Error executing listcab; error code: " + result);
+                }
+            } catch (IOException ex) {
+                String msg = "Problem creating " + cabFile + " " + ex.getMessage();
+                throw new BuildException(msg, getLocation());
+            }
+        } else {
+            try {
+                File listFile = createListFile(files);
+                ExecTask exec = createExec();
+                File outFile = null;
+
+                // die if cabarc fails
+                exec.setFailonerror(true);
+                exec.setDir(baseDir);
+
+                if (!doVerbose) {
+                    outFile = FILE_UTILS.createTempFile("ant", "", null, true, true);
+                    exec.setOutput(outFile);
+                }
+
+                exec.setExecutable("cabarc");
+                exec.createArg().setValue("-r");
+                exec.createArg().setValue("-p");
+
+                if (!doCompress) {
+                    exec.createArg().setValue("-m");
+                    exec.createArg().setValue("none");
+                }
+
+                if (cmdOptions != null) {
+                    exec.createArg().setLine(cmdOptions);
+                }
+
+                exec.createArg().setValue("n");
+                exec.createArg().setFile(cabFile);
+                exec.createArg().setValue("@" + listFile.getAbsolutePath());
+
+                exec.execute();
+
+                if (outFile != null) {
+                    outFile.delete();
+                }
+
+                listFile.delete();
+            } catch (IOException ioe) {
+                String msg = "Problem creating " + cabFile + " " + ioe.getMessage();
+                throw new BuildException(msg, getLocation());
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java
new file mode 100644
index 0000000..dd21aa8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/EchoProperties.java
@@ -0,0 +1,540 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Collections;
+import java.util.Iterator;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.util.CollectionUtils;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ *  Displays all the current properties in the build. The output can be sent to
+ *  a file if desired. <P>
+ *
+ *  Attribute "destfile" defines a file to send the properties to. This can be
+ *  processed as a standard property file later. <P>
+ *
+ *  Attribute "prefix" defines a prefix which is used to filter the properties
+ *  only those properties starting with this prefix will be echoed. <P>
+ *
+ *  By default, the "failonerror" attribute is enabled. If an error occurs while
+ *  writing the properties to a file, and this attribute is enabled, then a
+ *  BuildException will be thrown. If disabled, then IO errors will be reported
+ *  as a log statement, but no error will be thrown. <P>
+ *
+ *  Examples: <pre>
+ *  &lt;echoproperties  /&gt;
+ * </pre> Report the current properties to the log. <P>
+ *
+ *  <pre>
+ *  &lt;echoproperties destfile="my.properties" /&gt;
+ * </pre> Report the current properties to the file "my.properties", and will
+ *  fail the build if the file could not be created or written to. <P>
+ *
+ *  <pre>
+ *  &lt;echoproperties destfile="my.properties" failonerror="false"
+ *      prefix="ant" /&gt;
+ * </pre> Report all properties beginning with 'ant' to the file
+ *  "my.properties", and will log a message if the file could not be created or
+ *  written to, but will still allow the build to continue.
+ *
+ *@since      Ant 1.5
+ */
+public class EchoProperties extends Task {
+
+    /**
+     * the properties element.
+     */
+    private static final String PROPERTIES = "properties";
+
+    /**
+     * the property element.
+     */
+    private static final String PROPERTY = "property";
+
+    /**
+     * name attribute for property, testcase and testsuite elements.
+     */
+    private static final String ATTR_NAME = "name";
+
+    /**
+     * value attribute for property elements.
+     */
+    private static final String ATTR_VALUE = "value";
+
+    /**
+     * the input file.
+     */
+    private File inFile = null;
+
+    /**
+     *  File object pointing to the output file. If this is null, then
+     *  we output to the project log, not to a file.
+     */
+    private File destfile = null;
+
+    /**
+     *  If this is true, then errors generated during file output will become
+     *  build errors, and if false, then such errors will be logged, but not
+     *  thrown.
+     */
+    private boolean failonerror = true;
+
+    private Vector propertySets = new Vector();
+
+    private String format = "text";
+
+    private String prefix;
+
+    /**
+     * @since Ant 1.7
+     */
+    private String regex;
+
+    /**
+     * Sets the input file.
+     *
+     * @param file  the input file
+     */
+    public void setSrcfile(File file) {
+        inFile = file;
+    }
+
+    /**
+     *  Set a file to store the property output.  If this is never specified,
+     *  then the output will be sent to the Ant log.
+     *
+     *@param destfile file to store the property output
+     */
+    public void setDestfile(File destfile) {
+        this.destfile = destfile;
+    }
+
+
+    /**
+     * If true, the task will fail if an error occurs writing the properties
+     * file, otherwise errors are just logged.
+     *
+     *@param  failonerror  <tt>true</tt> if IO exceptions are reported as build
+     *      exceptions, or <tt>false</tt> if IO exceptions are ignored.
+     */
+    public void setFailOnError(boolean failonerror) {
+        this.failonerror = failonerror;
+    }
+
+
+    /**
+     *  If the prefix is set, then only properties which start with this
+     *  prefix string will be recorded. If regex is not set and  if this
+     *  is never set, or it is set to an empty string or <tt>null</tt>,
+     *  then all properties will be recorded. <P>
+     *
+     *  For example, if the attribute is set as:
+     *    <PRE>&lt;echoproperties  prefix="ant." /&gt;</PRE>
+     *  then the property "ant.home" will be recorded, but "ant-example"
+     *  will not.
+     *
+     * @param  prefix  The new prefix value
+     */
+    public void setPrefix(String prefix) {
+        if (prefix != null && prefix.length() != 0) {
+            this.prefix = prefix;
+            PropertySet ps = new PropertySet();
+            ps.setProject(getProject());
+            ps.appendPrefix(prefix);
+            addPropertyset(ps);
+        }
+    }
+
+    /**
+     *  If the regex is set, then only properties whose names match it
+     *  will be recorded.  If prefix is not set and if this is never set,
+     *  or it is set to an empty string or <tt>null</tt>, then all
+     *  properties will be recorded.<P>
+     *
+     *  For example, if the attribute is set as:
+     *    <PRE>&lt;echoproperties  prefix=".*ant.*" /&gt;</PRE>
+     *  then the properties "ant.home" and "user.variant" will be recorded,
+     *  but "ant-example" will not.
+     *
+     * @param  regex  The new regex value
+     *
+     * @since Ant 1.7
+     */
+    public void setRegex(String regex) {
+        if (regex != null && regex.length() != 0) {
+            this.regex = regex;
+            PropertySet ps = new PropertySet();
+            ps.setProject(getProject());
+            ps.appendRegex(regex);
+            addPropertyset(ps);
+        }
+    }
+
+    /**
+     * A set of properties to write.
+     * @param ps the property set to write
+     * @since Ant 1.6
+     */
+    public void addPropertyset(PropertySet ps) {
+        propertySets.addElement(ps);
+    }
+
+    /**
+     * Set the output format - xml or text.
+     * @param ea an enumerated <code>FormatAttribute</code> value
+     */
+    public void setFormat(FormatAttribute ea) {
+        format = ea.getValue();
+    }
+
+    /**
+     * A enumerated type for the format attribute.
+     * The values are "xml" and "text".
+     */
+    public static class FormatAttribute extends EnumeratedAttribute {
+        private String [] formats = new String[]{"xml", "text"};
+
+        /**
+         * @see EnumeratedAttribute#getValues()
+         * @return accepted values
+         */
+        public String[] getValues() {
+            return formats;
+        }
+    }
+
+    /**
+     *  Run the task.
+     *
+     *@exception  BuildException  trouble, probably file IO
+     */
+    public void execute() throws BuildException {
+        if (prefix != null && regex != null) {
+            throw new BuildException("Please specify either prefix"
+                    + " or regex, but not both", getLocation());
+        }
+        //copy the properties file
+        Hashtable allProps = new Hashtable();
+
+        /* load properties from file if specified, otherwise
+        use Ant's properties */
+        if (inFile == null && propertySets.size() == 0) {
+            // add ant properties
+            allProps.putAll(getProject().getProperties());
+        } else if (inFile != null) {
+            if (inFile.exists() && inFile.isDirectory()) {
+                String message = "srcfile is a directory!";
+                if (failonerror) {
+                    throw new BuildException(message, getLocation());
+                } else {
+                    log(message, Project.MSG_ERR);
+                }
+                return;
+            }
+
+            if (inFile.exists() && !inFile.canRead()) {
+                String message = "Can not read from the specified srcfile!";
+                if (failonerror) {
+                    throw new BuildException(message, getLocation());
+                } else {
+                    log(message, Project.MSG_ERR);
+                }
+                return;
+            }
+
+            FileInputStream in = null;
+            try {
+                in = new FileInputStream(inFile);
+                Properties props = new Properties();
+                props.load(in);
+                allProps.putAll(props);
+            } catch (FileNotFoundException fnfe) {
+                String message =
+                    "Could not find file " + inFile.getAbsolutePath();
+                if (failonerror) {
+                    throw new BuildException(message, fnfe, getLocation());
+                } else {
+                    log(message, Project.MSG_WARN);
+                }
+                return;
+            } catch (IOException ioe) {
+                String message =
+                    "Could not read file " + inFile.getAbsolutePath();
+                if (failonerror) {
+                    throw new BuildException(message, ioe, getLocation());
+                } else {
+                    log(message, Project.MSG_WARN);
+                }
+                return;
+            } finally {
+                FileUtils.close(in);
+            }
+        }
+
+        Enumeration e = propertySets.elements();
+        while (e.hasMoreElements()) {
+            PropertySet ps = (PropertySet) e.nextElement();
+            allProps.putAll(ps.getProperties());
+        }
+
+        OutputStream os = null;
+        try {
+            if (destfile == null) {
+                os = new ByteArrayOutputStream();
+                saveProperties(allProps, os);
+                log(os.toString(), Project.MSG_INFO);
+            } else {
+                if (destfile.exists() && destfile.isDirectory()) {
+                    String message = "destfile is a directory!";
+                    if (failonerror) {
+                        throw new BuildException(message, getLocation());
+                    } else {
+                        log(message, Project.MSG_ERR);
+                    }
+                    return;
+                }
+
+                if (destfile.exists() && !destfile.canWrite()) {
+                    String message =
+                        "Can not write to the specified destfile!";
+                    if (failonerror) {
+                        throw new BuildException(message, getLocation());
+                    } else {
+                        log(message, Project.MSG_ERR);
+                    }
+                    return;
+                }
+                os = new FileOutputStream(this.destfile);
+                saveProperties(allProps, os);
+            }
+        } catch (IOException ioe) {
+            if (failonerror) {
+                throw new BuildException(ioe, getLocation());
+            } else {
+                log(ioe.getMessage(), Project.MSG_INFO);
+            }
+        } finally {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException ex) {
+                    //ignore
+                }
+            }
+        }
+    }
+
+
+    /**
+     *  Send the key/value pairs in the hashtable to the given output stream.
+     *  Only those properties matching the <tt>prefix</tt> constraint will be
+     *  sent to the output stream.
+     *  The output stream will be closed when this method returns.
+     *
+     * @param  allProps         propfile to save
+     * @param  os               output stream
+     * @throws IOException      on output errors
+     * @throws BuildException   on other errors
+     */
+    protected void saveProperties(Hashtable allProps, OutputStream os)
+        throws IOException, BuildException {
+        final List keyList = new ArrayList(allProps.keySet());
+        Collections.sort(keyList);
+        Properties props = new Properties() {
+            private static final long serialVersionUID = 5090936442309201654L;
+            public Enumeration keys() {
+                return CollectionUtils.asEnumeration(keyList.iterator());
+            }
+            public Set entrySet() {
+                Set result = super.entrySet();
+                if (JavaEnvUtils.isKaffe()) {
+                    TreeSet t = new TreeSet(new Comparator() {
+                        public int compare(Object o1, Object o2) {
+                            String key1 = (String) ((Map.Entry) o1).getKey();
+                            String key2 = (String) ((Map.Entry) o2).getKey();
+                            return key1.compareTo(key2);
+                        }
+                    });
+                    t.addAll(result);
+                    result = t;
+                }
+                return result;
+            }
+        };
+        for (int i = 0; i < keyList.size(); i++) {
+            String name = keyList.get(i).toString();
+            String value = allProps.get(name).toString();
+            props.setProperty(name, value);
+        }
+        if ("text".equals(format)) {
+            jdkSaveProperties(props, os, "Ant properties");
+        } else if ("xml".equals(format)) {
+            xmlSaveProperties(props, os);
+        }
+    }
+
+    /**
+     * a tuple for the sort list.
+     */
+    private static final class Tuple implements Comparable {
+        private String key;
+        private String value;
+
+        private Tuple(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        /**
+         * Compares this object with the specified object for order.
+         * @param o the Object to be compared.
+         * @return a negative integer, zero, or a positive integer as this object is
+         *         less than, equal to, or greater than the specified object.
+         * @throws ClassCastException if the specified object's type prevents it
+         *                            from being compared to this Object.
+         */
+        public int compareTo(Object o) {
+            Tuple that = (Tuple) o;
+            return key.compareTo(that.key);
+        }
+    }
+
+    private List sortProperties(Properties props) {
+        //sort the list. Makes SCM and manual diffs easier.
+        List sorted = new ArrayList(props.size());
+        Enumeration e = props.propertyNames();
+        while (e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            sorted.add(new Tuple(name, props.getProperty(name)));
+        }
+        Collections.sort(sorted);
+        return sorted;
+    }
+
+    /**
+     * Output the properties as xml output.
+     * @param props the properties to save
+     * @param os    the output stream to write to (Note this gets closed)
+     * @throws IOException on error in writing to the stream
+     */
+    protected void xmlSaveProperties(Properties props,
+                                     OutputStream os) throws IOException {
+        // create XML document
+        Document doc = getDocumentBuilder().newDocument();
+        Element rootElement = doc.createElement(PROPERTIES);
+
+        List sorted = sortProperties(props);
+
+
+        // output properties
+        Iterator iten = sorted.iterator();
+        while (iten.hasNext()) {
+            Tuple tuple = (Tuple) iten.next();
+            Element propElement = doc.createElement(PROPERTY);
+            propElement.setAttribute(ATTR_NAME, tuple.key);
+            propElement.setAttribute(ATTR_VALUE, tuple.value);
+            rootElement.appendChild(propElement);
+        }
+
+        Writer wri = null;
+        try {
+            wri = new OutputStreamWriter(os, "UTF8");
+            wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+            (new DOMElementWriter()).write(rootElement, wri, 0, "\t");
+            wri.flush();
+        } catch (IOException ioe) {
+            throw new BuildException("Unable to write XML file", ioe);
+        } finally {
+            FileUtils.close(wri);
+        }
+    }
+
+    /**
+     *  JDK 1.2 allows for the safer method
+     *  <tt>Properties.store(OutputStream, String)</tt>, which throws an
+     *  <tt>IOException</tt> on an output error.
+     *
+     *@param props the properties to record
+     *@param os record the properties to this output stream
+     *@param header prepend this header to the property output
+     *@exception IOException on an I/O error during a write.
+     */
+    protected void jdkSaveProperties(Properties props, OutputStream os,
+                                     String header) throws IOException {
+       try {
+           props.store(os, header);
+
+       } catch (IOException ioe) {
+           throw new BuildException(ioe, getLocation());
+       } finally {
+           if (os != null) {
+               try {
+                   os.close();
+               } catch (IOException ioex) {
+                   log("Failed to close output stream");
+               }
+           }
+       }
+    }
+
+
+    /**
+     * Uses the DocumentBuilderFactory to get a DocumentBuilder instance.
+     *
+     * @return   The DocumentBuilder instance
+     */
+    private static DocumentBuilder getDocumentBuilder() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        } catch (Exception e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java
new file mode 100755
index 0000000..bd5e3de
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Javah.java
@@ -0,0 +1,488 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.javah.JavahAdapter;
+import org.apache.tools.ant.taskdefs.optional.javah.JavahAdapterFactory;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+import org.apache.tools.ant.util.facade.ImplementationSpecificArgument;
+
+/**
+ * Generates JNI header files using javah.
+ *
+ * This task can take the following arguments:
+ * <ul>
+ * <li>classname - the fully-qualified name of a class</li>
+ * <li>outputFile - Concatenates the resulting header or source files for all
+ *     the classes listed into this file</li>
+ * <li>destdir - Sets the directory where javah saves the header files or the
+ *     stub files</li>
+ * <li>classpath</li>
+ * <li>bootclasspath</li>
+ * <li>force - Specifies that output files should always be written
+       (JDK1.2 only)</li>
+ * <li>old - Specifies that old JDK1.0-style header files should be generated
+ *     (otherwise output file contain JNI-style native method
+ *      function prototypes) (JDK1.2 only)</li>
+ * <li>stubs - generate C declarations from the Java object file (used with old)</li>
+ * <li>verbose - causes javah to print a message to stdout concerning the status
+ *     of the generated files</li>
+ * <li>extdirs - Override location of installed extensions</li>
+ * </ul>
+ * Of these arguments, either <b>outputFile</b> or <b>destdir</b> is required,
+ * but not both. More than one classname may be specified, using a comma-separated
+ * list or by using <code>&lt;class name="xxx"&gt;</code> elements within the task.
+ * <p>
+ * When this task executes, it will generate C header and source files that
+ * are needed to implement native methods.
+ *
+ */
+
+public class Javah extends Task {
+
+    private Vector classes = new Vector(2);
+    private String cls;
+    private File destDir;
+    private Path classpath = null;
+    private File outputFile = null;
+    private boolean verbose = false;
+    private boolean force   = false;
+    private boolean old     = false;
+    private boolean stubs   = false;
+    private Path bootclasspath;
+    //private Path extdirs;
+    private FacadeTaskHelper facade = null;
+    private Vector files = new Vector();
+
+    /**
+     * No arg constructor.
+     */
+    public Javah() {
+        facade = new FacadeTaskHelper(JavahAdapterFactory.getDefault());
+    }
+
+    /**
+     * the fully-qualified name of the class (or classes, separated by commas).
+     * @param cls the classname (or classnames).
+     */
+    public void setClass(String cls) {
+        this.cls = cls;
+    }
+
+    /**
+     * Adds class to process.
+     * @return a <code>ClassArgument</code> to be configured.
+     */
+    public ClassArgument createClass() {
+        ClassArgument ga = new ClassArgument();
+        classes.addElement(ga);
+        return ga;
+    }
+
+    /**
+     * A class corresponding the the nested "class" element.
+     * It contains a "name" attribute.
+     */
+    public class ClassArgument {
+        private String name;
+
+        /** Constructor for ClassArgument. */
+        public ClassArgument() {
+        }
+
+        /**
+         * Set the name attribute.
+         * @param name the name attribute.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Get the name attribute.
+         * @return the name attribute.
+         */
+        public String getName() {
+            return name;
+        }
+    }
+
+    /**
+     * Add a fileset.
+     * @param fs the fileset to add.
+     */
+    public void addFileSet(FileSet fs) {
+        files.add(fs);
+    }
+
+    /**
+     * Names of the classes to process.
+     * @return the array of classes.
+     * @since Ant 1.6.3
+     */
+    public String[] getClasses() {
+        ArrayList al = new ArrayList();
+        if (cls != null) {
+            StringTokenizer tok = new StringTokenizer(cls, ",", false);
+            while (tok.hasMoreTokens()) {
+                al.add(tok.nextToken().trim());
+            }
+        }
+
+        if (files.size() > 0) {
+            for (Enumeration e = files.elements(); e.hasMoreElements();) {
+                FileSet fs = (FileSet) e.nextElement();
+                String[] includedClasses = fs.getDirectoryScanner(
+                    getProject()).getIncludedFiles();
+                for (int i = 0; i < includedClasses.length; i++) {
+                    String className =
+                        includedClasses[i].replace('\\', '.').replace('/', '.')
+                        .substring(0, includedClasses[i].length() - 6);
+                    al.add(className);
+                }
+            }
+        }
+        Enumeration e = classes.elements();
+        while (e.hasMoreElements()) {
+            ClassArgument arg = (ClassArgument) e.nextElement();
+            al.add(arg.getName());
+        }
+        return (String[]) al.toArray(new String[al.size()]);
+    }
+
+    /**
+     * Set the destination directory into which the Java source
+     * files should be compiled.
+     * @param destDir the destination directory.
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * The destination directory, if any.
+     * @return the destination directory.
+     * @since Ant 1.6.3
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * the classpath to use.
+     * @param src the classpath.
+     */
+    public void setClasspath(Path src) {
+        if (classpath == null) {
+            classpath = src;
+        } else {
+            classpath.append(src);
+        }
+    }
+
+    /**
+     * Path to use for classpath.
+     * @return a path to be configured.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath.
+     * @todo this needs to be documented in the HTML docs.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * The classpath to use.
+     * @return the classpath.
+     * @since Ant 1.6.3
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * location of bootstrap class files.
+     * @param src the bootstrap classpath.
+     */
+    public void setBootclasspath(Path src) {
+        if (bootclasspath == null) {
+            bootclasspath = src;
+        } else {
+            bootclasspath.append(src);
+        }
+    }
+
+    /**
+     * Adds path to bootstrap class files.
+     * @return a path to be configured.
+     */
+    public Path createBootclasspath() {
+        if (bootclasspath == null) {
+            bootclasspath = new Path(getProject());
+        }
+        return bootclasspath.createPath();
+    }
+
+    /**
+     * To the bootstrap path, this adds a reference to a classpath defined elsewhere.
+     * @param r a reference to a classpath
+     * @todo this needs to be documented in the HTML.
+     */
+    public void setBootClasspathRef(Reference r) {
+        createBootclasspath().setRefid(r);
+    }
+
+    /**
+     * The bootclasspath to use.
+     * @return the bootclass path.
+     * @since Ant 1.6.3
+     */
+    public Path getBootclasspath() {
+        return bootclasspath;
+    }
+
+    /**
+     * Concatenates the resulting header or source files for all
+     * the classes listed into this file.
+     * @param outputFile the output file.
+     */
+    public void setOutputFile(File outputFile) {
+        this.outputFile = outputFile;
+    }
+
+    /**
+     * The destination file, if any.
+     * @return the destination file.
+     * @since Ant 1.6.3
+     */
+    public File getOutputfile() {
+        return outputFile;
+    }
+
+    /**
+     * If true, output files should always be written (JDK1.2 only).
+     * @param force the value to use.
+     */
+    public void setForce(boolean force) {
+        this.force = force;
+    }
+
+    /**
+     * Whether output files should always be written.
+     * @return the force attribute.
+     * @since Ant 1.6.3
+     */
+    public boolean getForce() {
+        return force;
+    }
+
+    /**
+     * If true, specifies that old JDK1.0-style header files should be
+     * generated.
+     * (otherwise output file contain JNI-style native method function
+     *  prototypes) (JDK1.2 only).
+     * @param old if true use old 1.0 style header files.
+     */
+    public void setOld(boolean old) {
+        this.old = old;
+    }
+
+    /**
+     * Whether old JDK1.0-style header files should be generated.
+     * @return the old attribute.
+     * @since Ant 1.6.3
+     */
+    public boolean getOld() {
+        return old;
+    }
+
+    /**
+     * If true, generate C declarations from the Java object file (used with old).
+     * @param stubs if true, generated C declarations.
+     */
+    public void setStubs(boolean stubs) {
+        this.stubs = stubs;
+    }
+
+    /**
+     * Whether C declarations from the Java object file should be generated.
+     * @return the stubs attribute.
+     * @since Ant 1.6.3
+     */
+    public boolean getStubs() {
+        return stubs;
+    }
+
+    /**
+     * If true, causes Javah to print a message concerning
+     * the status of the generated files.
+     * @param verbose if true, do verbose printing.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Whether verbose output should get generated.
+     * @return the verbose attribute.
+     * @since Ant 1.6.3
+     */
+    public boolean getVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Choose the implementation for this particular task.
+     * @param impl the name of the implemenation.
+     * @since Ant 1.6.3
+     */
+    public void setImplementation(String impl) {
+        if ("default".equals(impl)) {
+            facade.setImplementation(JavahAdapterFactory.getDefault());
+        } else {
+            facade.setImplementation(impl);
+        }
+    }
+
+    /**
+     * Adds an implementation specific command-line argument.
+     * @return a ImplementationSpecificArgument to be configured.
+     *
+     * @since Ant 1.6.3
+     */
+    public ImplementationSpecificArgument createArg() {
+        ImplementationSpecificArgument arg =
+            new ImplementationSpecificArgument();
+        facade.addImplementationArgument(arg);
+        return arg;
+    }
+
+    /**
+     * Returns the (implementation specific) settings given as nested
+     * arg elements.
+     * @return the arguments.
+     * @since Ant 1.6.3
+     */
+    public String[] getCurrentArgs() {
+        return facade.getArgs();
+    }
+
+    /**
+     * Execute the task
+     *
+     * @throws BuildException is there is a problem in the task execution.
+     */
+    public void execute() throws BuildException {
+        // first off, make sure that we've got a srcdir
+
+        if ((cls == null) && (classes.size() == 0) && (files.size() == 0)) {
+            throw new BuildException("class attribute must be set!",
+                getLocation());
+        }
+
+        if ((cls != null) && (classes.size() > 0) && (files.size() > 0)) {
+            throw new BuildException("set class attribute OR class element OR fileset, "
+                + "not 2 or more of them.", getLocation());
+        }
+
+        if (destDir != null) {
+            if (!destDir.isDirectory()) {
+                throw new BuildException("destination directory \"" + destDir
+                    + "\" does not exist or is not a directory", getLocation());
+            }
+            if (outputFile != null) {
+                throw new BuildException("destdir and outputFile are mutually "
+                    + "exclusive", getLocation());
+            }
+        }
+
+        if (classpath == null) {
+            classpath = (new Path(getProject())).concatSystemClasspath("last");
+        } else {
+            classpath = classpath.concatSystemClasspath("ignore");
+        }
+
+        JavahAdapter ad =
+            JavahAdapterFactory.getAdapter(facade.getImplementation(),
+                                           this);
+        if (!ad.compile(this)) {
+            throw new BuildException("compilation failed");
+        }
+    }
+
+    /**
+     * Logs the compilation parameters, adds the files to compile and logs the
+     * &quot;niceSourceList&quot;
+     * @param cmd the command line.
+     */
+    public void logAndAddFiles(Commandline cmd) {
+        logAndAddFilesToCompile(cmd);
+    }
+
+    /**
+     * Logs the compilation parameters, adds the files to compile and logs the
+     * &quot;niceSourceList&quot;
+     * @param cmd the command line to add parameters to.
+     */
+    protected void logAndAddFilesToCompile(Commandline cmd) {
+        log("Compilation " + cmd.describeArguments(),
+            Project.MSG_VERBOSE);
+
+        StringBuffer niceClassList = new StringBuffer();
+        String[] c = getClasses();
+        for (int i = 0; i < c.length; i++) {
+            cmd.createArgument().setValue(c[i]);
+            niceClassList.append("    ");
+            niceClassList.append(c[i]);
+            niceClassList.append(StringUtils.LINE_SEP);
+        }
+
+        StringBuffer prefix = new StringBuffer("Class");
+        if (c.length > 1) {
+            prefix.append("es");
+        }
+        prefix.append(" to be compiled:");
+        prefix.append(StringUtils.LINE_SEP);
+
+        log(prefix.toString() + niceClassList.toString(), Project.MSG_VERBOSE);
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java
new file mode 100644
index 0000000..1282ceb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Native2Ascii.java
@@ -0,0 +1,300 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapter;
+import org.apache.tools.ant.taskdefs.optional.native2ascii.Native2AsciiAdapterFactory;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.SourceFileScanner;
+import org.apache.tools.ant.util.facade.FacadeTaskHelper;
+import org.apache.tools.ant.util.facade.ImplementationSpecificArgument;
+
+/**
+ * Converts files from native encodings to ASCII.
+ *
+ * @since Ant 1.2
+ */
+public class Native2Ascii extends MatchingTask {
+
+    private boolean reverse = false;  // convert from ascii back to native
+    private String encoding = null;   // encoding to convert to/from
+    private File srcDir = null;       // Where to find input files
+    private File destDir = null;      // Where to put output files
+    private String extension = null;  // Extension of output files if different
+
+    private Mapper mapper;
+    private FacadeTaskHelper facade = null;
+
+    /** No args constructor */
+    public Native2Ascii() {
+        facade = new FacadeTaskHelper(Native2AsciiAdapterFactory.getDefault());
+    }
+
+    /**
+     * Flag the conversion to run in the reverse sense,
+     * that is Ascii to Native encoding.
+     *
+     * @param reverse True if the conversion is to be reversed,
+     *                otherwise false;
+     */
+    public void setReverse(boolean reverse) {
+        this.reverse = reverse;
+    }
+
+    /**
+     * The value of the reverse attribute.
+     * @return the reverse attribute.
+     * @since Ant 1.6.3
+     */
+    public boolean getReverse() {
+        return reverse;
+    }
+
+    /**
+     * Set the encoding to translate to/from.
+     * If unset, the default encoding for the JVM is used.
+     *
+     * @param encoding String containing the name of the Native
+     *                 encoding to convert from or to.
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * The value of the encoding attribute.
+     * @return the encoding attribute.
+     * @since Ant 1.6.3
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Set the source directory in which to find files to convert.
+     *
+     * @param srcDir directory to find input file in.
+     */
+    public void setSrc(File srcDir) {
+        this.srcDir = srcDir;
+    }
+
+
+    /**
+     * Set the destination directory to place converted files into.
+     *
+     * @param destDir directory to place output file into.
+     */
+    public void setDest(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Set the extension which converted files should have.
+     * If unset, files will not be renamed.
+     *
+     * @param ext File extension to use for converted files.
+     */
+    public void setExt(String ext) {
+        this.extension = ext;
+    }
+
+    /**
+     * Choose the implementation for this particular task.
+     * @param impl the name of the implemenation
+     * @since Ant 1.6.3
+     */
+    public void setImplementation(String impl) {
+        if ("default".equals(impl)) {
+            facade.setImplementation(Native2AsciiAdapterFactory.getDefault());
+        } else {
+            facade.setImplementation(impl);
+        }
+    }
+
+    /**
+     * Defines the FileNameMapper to use (nested mapper element).
+     *
+     * @return the mapper to use for file name translations.
+     *
+     * @throws BuildException if more than one mapper is defined.
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapper != null) {
+            throw new BuildException("Cannot define more than one mapper",
+                                     getLocation());
+        }
+        mapper = new Mapper(getProject());
+        return mapper;
+    }
+
+    /**
+     * A nested filenamemapper
+     * @param fileNameMapper the mapper to add
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+    /**
+     * Adds an implementation specific command-line argument.
+     * @return a ImplementationSpecificArgument to be configured
+     *
+     * @since Ant 1.6.3
+     */
+    public ImplementationSpecificArgument createArg() {
+        ImplementationSpecificArgument arg =
+            new ImplementationSpecificArgument();
+        facade.addImplementationArgument(arg);
+        return arg;
+    }
+
+    /**
+     * Execute the task
+     *
+     * @throws BuildException is there is a problem in the task execution.
+     */
+    public void execute() throws BuildException {
+
+        DirectoryScanner scanner = null; // Scanner to find our inputs
+        String[] files;                  // list of files to process
+
+        // default srcDir to basedir
+        if (srcDir == null) {
+            srcDir = getProject().resolveFile(".");
+        }
+
+        // Require destDir
+        if (destDir == null) {
+            throw new BuildException("The dest attribute must be set.");
+        }
+
+        // if src and dest dirs are the same, require the extension
+        // to be set, so we don't stomp every file.  One could still
+        // include a file with the same extension, but ....
+        if (srcDir.equals(destDir) && extension == null && mapper == null) {
+            throw new BuildException("The ext attribute or a mapper must be set if"
+                                     + " src and dest dirs are the same.");
+        }
+
+        FileNameMapper m = null;
+        if (mapper == null) {
+            if (extension == null) {
+                m = new IdentityMapper();
+            } else {
+                m = new ExtMapper();
+            }
+        } else {
+            m = mapper.getImplementation();
+        }
+
+        scanner = getDirectoryScanner(srcDir);
+        files = scanner.getIncludedFiles();
+        SourceFileScanner sfs = new SourceFileScanner(this);
+        files = sfs.restrict(files, srcDir, destDir, m);
+        int count = files.length;
+        if (count == 0) {
+            return;
+        }
+        String message = "Converting " + count + " file"
+            + (count != 1 ? "s" : "") + " from ";
+        log(message + srcDir + " to " + destDir);
+        for (int i = 0; i < files.length; i++) {
+            convert(files[i], m.mapFileName(files[i])[0]);
+        }
+    }
+
+    /**
+     * Convert a single file.
+     *
+     * @param srcName name of the input file.
+     * @param destName name of the input file.
+     */
+    private void convert(String srcName, String destName)
+        throws BuildException {
+        File srcFile;                         // File to convert
+        File destFile;                        // where to put the results
+
+        // Build the full file names
+        srcFile = new File(srcDir, srcName);
+        destFile = new File(destDir, destName);
+
+        // Make sure we're not about to clobber something
+        if (srcFile.equals(destFile)) {
+            throw new BuildException("file " + srcFile
+                                     + " would overwrite its self");
+        }
+
+        // Make intermediate directories if needed
+        // XXX JDK 1.1 doesn't have File.getParentFile,
+        String parentName = destFile.getParent();
+        if (parentName != null) {
+            File parentFile = new File(parentName);
+
+            if ((!parentFile.exists()) && (!parentFile.mkdirs())) {
+                throw new BuildException("cannot create parent directory "
+                                         + parentName);
+            }
+        }
+
+        log("converting " + srcName, Project.MSG_VERBOSE);
+        Native2AsciiAdapter ad =
+            Native2AsciiAdapterFactory.getAdapter(facade.getImplementation(),
+                                                  this);
+        if (!ad.convert(this, srcFile, destFile)) {
+            throw new BuildException("conversion failed");
+        }
+    }
+
+    /**
+     * Returns the (implementation specific) settings given as nested
+     * arg elements.
+     * @return the arguments.
+     * @since Ant 1.6.3
+     */
+    public String[] getCurrentArgs() {
+        return facade.getArgs();
+    }
+
+    private class ExtMapper implements FileNameMapper {
+
+        public void setFrom(String s) {
+        }
+        public void setTo(String s) {
+        }
+
+        public String[] mapFileName(String fileName) {
+            int lastDot = fileName.lastIndexOf('.');
+            if (lastDot >= 0) {
+                return new String[] {fileName.substring(0, lastDot)
+                                         + extension};
+            } else {
+                return new String[] {fileName + extension};
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java
new file mode 100644
index 0000000..9f798ea
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/NetRexxC.java
@@ -0,0 +1,963 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import netrexx.lang.Rexx;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.util.FileUtils;
+
+// CheckStyle:InnerAssignmentCheck OFF - used too much in the file to be removed
+/**
+ * Compiles NetRexx source files.
+ * This task can take the following
+ * arguments:
+ * <ul>
+ * <li>binary</li>
+ * <li>classpath</li>
+ * <li>comments</li>
+ * <li>compile</li>
+ * <li>console</li>
+ * <li>crossref</li>
+ * <li>decimal</li>
+ * <li>destdir</li>
+ * <li>diag</li>
+ * <li>explicit</li>
+ * <li>format</li>
+ * <li>keep</li>
+ * <li>logo</li>
+ * <li>replace</li>
+ * <li>savelog</li>
+ * <li>srcdir</li>
+ * <li>sourcedir</li>
+ * <li>strictargs</li>
+ * <li>strictassign</li>
+ * <li>strictcase</li>
+ * <li>strictimport</li>
+ * <li>symbols</li>
+ * <li>time</li>
+ * <li>trace</li>
+ * <li>utf8</li>
+ * <li>verbose</li>
+ * <li>suppressMethodArgumentNotUsed</li>
+ * <li>suppressPrivatePropertyNotUsed</li>
+ * <li>suppressVariableNotUsed</li>
+ * <li>suppressExceptionNotSignalled</li>
+ * <li>suppressDeprecation</li>
+ * </ul>
+ * Of these arguments, the <b>srcdir</b> argument is required.
+ *
+ * <p>When this task executes, it will recursively scan the srcdir
+ * looking for NetRexx source files to compile. This task makes its
+ * compile decision based on timestamp.
+ * <p>Before files are compiled they and any other file in the
+ * srcdir will be copied to the destdir allowing support files to be
+ * located properly in the classpath. The reason for copying the source files
+ * before the compile is that NetRexxC has only two destinations for classfiles:
+ * <ol>
+ * <li>The current directory, and,</li>
+ * <li>The directory the source is in (see sourcedir option)
+ * </ol>
+ *
+ */
+public class NetRexxC extends MatchingTask {
+
+    // variables to hold arguments
+    private boolean binary;
+    private String classpath;
+    private boolean comments;
+    private boolean compact = true; // should be the default, as it integrates better in ant.
+    private boolean compile = true;
+    private boolean console;
+    private boolean crossref;
+    private boolean decimal = true;
+    private File destDir;
+    private boolean diag;
+    private boolean explicit;
+    private boolean format;
+    private boolean keep;
+    private boolean logo = true;
+    private boolean replace;
+    private boolean savelog;
+    private File srcDir;
+    private boolean sourcedir = true; // ?? Should this be the default for ant?
+    private boolean strictargs;
+    private boolean strictassign;
+    private boolean strictcase;
+    private boolean strictimport;
+    private boolean strictprops;
+    private boolean strictsignal;
+    private boolean symbols;
+    private boolean time;
+    private String trace = "trace2";
+    private boolean utf8;
+    private String verbose = "verbose3";
+    private boolean suppressMethodArgumentNotUsed = false;
+    private boolean suppressPrivatePropertyNotUsed = false;
+    private boolean suppressVariableNotUsed = false;
+    private boolean suppressExceptionNotSignalled = false;
+    private boolean suppressDeprecation = false;
+
+    // constants for the messages to suppress by flags and their corresponding properties
+    static final String MSG_METHOD_ARGUMENT_NOT_USED
+        = "Warning: Method argument is not used";
+    static final String MSG_PRIVATE_PROPERTY_NOT_USED
+        = "Warning: Private property is defined but not used";
+    static final String MSG_VARIABLE_NOT_USED
+        = "Warning: Variable is set but not used";
+    static final String MSG_EXCEPTION_NOT_SIGNALLED
+        = "is in SIGNALS list but is not signalled within the method";
+    static final String MSG_DEPRECATION = "has been deprecated";
+
+    // other implementation variables
+    private Vector compileList = new Vector();
+    private Hashtable filecopyList = new Hashtable();
+
+    /**
+     * Set whether literals are treated as binary, rather than NetRexx types.
+     * @param binary a <code>boolean</code> value.
+     */
+    public void setBinary(boolean binary) {
+        this.binary = binary;
+    }
+
+
+    /**
+     * Set the classpath used for NetRexx compilation.
+     * @param classpath the classpath to use.
+     */
+    public void setClasspath(String classpath) {
+        this.classpath = classpath;
+    }
+
+
+    /**
+     * Set whether comments are passed through to the generated java source.
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is false
+     * @param comments a <code>boolean</code> value.
+     */
+    public void setComments(boolean comments) {
+        this.comments = comments;
+    }
+
+
+    /**
+     * Set whether error messages come out in compact or verbose format. Valid
+     * true values are "on" or "true". Anything else sets the flag to false.
+     * The default value is false
+     * @param compact a <code>boolean</code> value.
+     */
+    public void setCompact(boolean compact) {
+        this.compact = compact;
+    }
+
+
+    /**
+     * Set whether the NetRexx compiler should compile the generated java code
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is true. Setting this flag to false, will
+     * automatically set the keep flag to true.
+     * @param compile a <code>boolean</code> value.
+     */
+    public void setCompile(boolean compile) {
+        this.compile = compile;
+        if (!this.compile && !this.keep) {
+            this.keep = true;
+        }
+    }
+
+
+    /**
+     * Set whether or not messages should be displayed on the 'console' Valid
+     * true values are "on" or "true". Anything else sets the flag to false.
+     * The default value is true.
+     * @param console a <code>boolean</code> value.
+     */
+    public void setConsole(boolean console) {
+        this.console = console;
+    }
+
+
+    /**
+     * Whether variable cross references are generated.
+     * @param crossref a <code>boolean</code> value.
+     */
+    public void setCrossref(boolean crossref) {
+        this.crossref = crossref;
+    }
+
+
+    /**
+     * Set whether decimal arithmetic should be used for the netrexx code.
+     * Binary arithmetic is used when this flag is turned off. Valid true
+     * values are "on" or "true". Anything else sets the flag to false. The
+     * default value is true.
+     * @param decimal a <code>boolean</code> value.
+     */
+    public void setDecimal(boolean decimal) {
+        this.decimal = decimal;
+    }
+
+
+    /**
+     * Set the destination directory into which the NetRexx source files
+     * should be copied and then compiled.
+     * @param destDirName the destination directory.
+     */
+    public void setDestDir(File destDirName) {
+        destDir = destDirName;
+    }
+
+
+    /**
+     * Whether diagnostic information about the compile is generated
+     * @param diag a <code>boolean</code> value.
+     */
+    public void setDiag(boolean diag) {
+        this.diag = diag;
+    }
+
+
+    /**
+     * Sets whether variables must be declared explicitly before use. Valid
+     * true values are "on" or "true". Anything else sets the flag to false.
+     * The default value is false.
+     * @param explicit a <code>boolean</code> value.
+     */
+    public void setExplicit(boolean explicit) {
+        this.explicit = explicit;
+    }
+
+
+    /**
+     * Whether the generated java code is formatted nicely or left to match
+     * NetRexx line numbers for call stack debugging.
+     * @param format a <code>boolean</code> value.
+     */
+    public void setFormat(boolean format) {
+        this.format = format;
+    }
+
+
+    /**
+     * Whether the generated java code is produced Valid true values are "on"
+     * or "true". Anything else sets the flag to false. The default value is
+     * false.
+     * @param java a <code>boolean</code> value.
+     */
+    public void setJava(boolean java) {
+        log("The attribute java is currently unused.", Project.MSG_WARN);
+    }
+
+
+    /**
+     * Sets whether the generated java source file should be kept after
+     * compilation. The generated files will have an extension of .java.keep,
+     * <b>not</b> .java Valid true values are "on" or "true". Anything else
+     * sets the flag to false. The default value is false.
+     * @param keep a <code>boolean</code> value.
+     */
+    public void setKeep(boolean keep) {
+        this.keep = keep;
+    }
+
+
+    /**
+     * Whether the compiler text logo is displayed when compiling.
+     * @param logo a <code>boolean</code> value.
+     */
+    public void setLogo(boolean logo) {
+        this.logo = logo;
+    }
+
+
+    /**
+     * Whether the generated .java file should be replaced when compiling
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is false.
+     * @param replace a <code>boolean</code> value.
+     */
+    public void setReplace(boolean replace) {
+        this.replace = replace;
+    }
+
+
+    /**
+     * Sets whether the compiler messages will be written to NetRexxC.log as
+     * well as to the console Valid true values are "on" or "true". Anything
+     * else sets the flag to false. The default value is false.
+     * @param savelog a <code>boolean</code> value.
+     */
+    public void setSavelog(boolean savelog) {
+        this.savelog = savelog;
+    }
+
+
+    /**
+     * Tells the NetRexx compiler to store the class files in the same
+     * directory as the source files. The alternative is the working directory
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is true.
+     * @param sourcedir a <code>boolean</code> value.
+     */
+    public void setSourcedir(boolean sourcedir) {
+        this.sourcedir = sourcedir;
+    }
+
+
+    /**
+     * Set the source dir to find the source Java files.
+     * @param srcDirName the source directory.
+     */
+    public void setSrcDir(File srcDirName) {
+        srcDir = srcDirName;
+    }
+
+
+    /**
+     * Tells the NetRexx compiler that method calls always need parentheses,
+     * even if no arguments are needed, e.g. <code>aStringVar.getBytes</code>
+     * vs. <code>aStringVar.getBytes()</code> Valid true values are "on" or
+     * "true". Anything else sets the flag to false. The default value is
+     * false.
+     * @param strictargs a <code>boolean</code> value.
+     */
+    public void setStrictargs(boolean strictargs) {
+        this.strictargs = strictargs;
+    }
+
+
+    /**
+     * Tells the NetRexx compile that assignments must match exactly on type.
+     * @param strictassign a <code>boolean</code> value.
+     */
+    public void setStrictassign(boolean strictassign) {
+        this.strictassign = strictassign;
+    }
+
+
+    /**
+     * Specifies whether the NetRexx compiler should be case sensitive or not.
+     * @param strictcase a <code>boolean</code> value.
+     */
+    public void setStrictcase(boolean strictcase) {
+        this.strictcase = strictcase;
+    }
+
+
+    /**
+     * Sets whether classes need to be imported explicitly using an <code>import</code>
+     * statement. By default the NetRexx compiler will import certain packages
+     * automatically Valid true values are "on" or "true". Anything else sets
+     * the flag to false. The default value is false.
+     * @param strictimport a <code>boolean</code> value.
+     */
+    public void setStrictimport(boolean strictimport) {
+        this.strictimport = strictimport;
+    }
+
+
+    /**
+     * Sets whether local properties need to be qualified explicitly using
+     * <code>this</code> Valid true values are "on" or "true". Anything else
+     * sets the flag to false. The default value is false.
+     * @param strictprops a <code>boolean</code> value.
+     */
+    public void setStrictprops(boolean strictprops) {
+        this.strictprops = strictprops;
+    }
+
+
+    /**
+     * Whether the compiler should force catching of exceptions by explicitly
+     * named types.
+     * @param strictsignal a <code>boolean</code> value.
+     */
+    public void setStrictsignal(boolean strictsignal) {
+        this.strictsignal = strictsignal;
+    }
+
+
+    /**
+     * Sets whether debug symbols should be generated into the class file
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is false.
+     * @param symbols a <code>boolean</code> value.
+     */
+    public void setSymbols(boolean symbols) {
+        this.symbols = symbols;
+    }
+
+
+    /**
+     * Asks the NetRexx compiler to print compilation times to the console
+     * Valid true values are "on" or "true". Anything else sets the flag to
+     * false. The default value is false.
+     * @param time a <code>boolean</code> value.
+     */
+    public void setTime(boolean time) {
+        this.time = time;
+    }
+
+    /**
+     * Turns on or off tracing and directs the resultant trace output Valid
+     * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
+     * "trace2".
+     * @param trace the value to set.
+     */
+    public void setTrace(TraceAttr trace) {
+        this.trace = trace.getValue();
+    }
+
+    /**
+     * Turns on or off tracing and directs the resultant trace output Valid
+     * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
+     * "trace2".
+     * @param trace the value to set.
+     */
+    public void setTrace(String trace) {
+        TraceAttr t = new TraceAttr();
+
+        t.setValue(trace);
+        setTrace(t);
+    }
+
+
+    /**
+     * Tells the NetRexx compiler that the source is in UTF8 Valid true values
+     * are "on" or "true". Anything else sets the flag to false. The default
+     * value is false.
+     * @param utf8 a <code>boolean</code> value.
+     */
+    public void setUtf8(boolean utf8) {
+        this.utf8 = utf8;
+    }
+
+
+    /**
+     * Whether lots of warnings and error messages should be generated
+     * @param verbose the value to set - verbose&lt;level&gt; or noverbose.
+     */
+    public void setVerbose(VerboseAttr verbose) {
+        this.verbose = verbose.getValue();
+    }
+
+
+    /**
+     * Whether lots of warnings and error messages should be generated
+     * @param verbose the value to set - verbose&lt;level&gt; or noverbose.
+     */
+    public void setVerbose(String verbose) {
+        VerboseAttr v = new VerboseAttr();
+
+        v.setValue(verbose);
+        setVerbose(v);
+    }
+
+    /**
+     * Whether the task should suppress the "Method argument is not used" in
+     * strictargs-Mode, which can not be suppressed by the compiler itself.
+     * The warning is logged as verbose message, though.
+     * @param suppressMethodArgumentNotUsed a <code>boolean</code> value.
+     */
+    public void setSuppressMethodArgumentNotUsed(boolean suppressMethodArgumentNotUsed) {
+        this.suppressMethodArgumentNotUsed = suppressMethodArgumentNotUsed;
+    }
+
+
+    /**
+     * Whether the task should suppress the "Private property is defined but
+     * not used" in strictargs-Mode, which can be quite annoying while
+     * developing. The warning is logged as verbose message, though.
+     * @param suppressPrivatePropertyNotUsed a <code>boolean</code> value.
+     */
+    public void setSuppressPrivatePropertyNotUsed(boolean suppressPrivatePropertyNotUsed) {
+        this.suppressPrivatePropertyNotUsed = suppressPrivatePropertyNotUsed;
+    }
+
+
+    /**
+     * Whether the task should suppress the "Variable is set but not used" in
+     * strictargs-Mode. Be careful with this one! The warning is logged as
+     * verbose message, though.
+     * @param suppressVariableNotUsed a <code>boolean</code> value.
+     */
+    public void setSuppressVariableNotUsed(boolean suppressVariableNotUsed) {
+        this.suppressVariableNotUsed = suppressVariableNotUsed;
+    }
+
+
+    /**
+     * Whether the task should suppress the "FooException is in SIGNALS list
+     * but is not signalled within the method", which is sometimes rather
+     * useless. The warning is logged as verbose message, though.
+     * @param suppressExceptionNotSignalled a <code>boolean</code> value.
+     */
+    public void setSuppressExceptionNotSignalled(boolean suppressExceptionNotSignalled) {
+        this.suppressExceptionNotSignalled = suppressExceptionNotSignalled;
+    }
+
+
+    /**
+     * Tells whether we should filter out any deprecation-messages
+     * of the compiler out.
+     * @param suppressDeprecation a <code>boolean</code> value.
+     */
+    public void setSuppressDeprecation(boolean suppressDeprecation) {
+        this.suppressDeprecation = suppressDeprecation;
+    }
+
+
+    /**
+     * init-Method sets defaults from Properties. That way, when ant is called
+     * with arguments like -Dant.netrexxc.verbose=verbose5 one can easily take
+     * control of all netrexxc-tasks.
+     */
+    public void init() {
+        String p;
+
+        if ((p = getProject().getProperty("ant.netrexxc.binary")) != null) {
+            this.binary = Project.toBoolean(p);
+        }
+        // classpath makes no sense
+        if ((p = getProject().getProperty("ant.netrexxc.comments")) != null) {
+            this.comments = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.compact")) != null) {
+            this.compact = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.compile")) != null) {
+            this.compile = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.console")) != null) {
+            this.console = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.crossref")) != null) {
+            this.crossref = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.decimal")) != null) {
+            this.decimal = Project.toBoolean(p);
+            // destDir
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.diag")) != null) {
+            this.diag = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.explicit")) != null) {
+            this.explicit = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.format")) != null) {
+            this.format = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.keep")) != null) {
+            this.keep = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.logo")) != null) {
+            this.logo = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.replace")) != null) {
+            this.replace = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.savelog")) != null) {
+            this.savelog = Project.toBoolean(p);
+            // srcDir
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.sourcedir")) != null) {
+            this.sourcedir = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictargs")) != null) {
+            this.strictargs = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictassign")) != null) {
+            this.strictassign = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictcase")) != null) {
+            this.strictcase = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictimport")) != null) {
+            this.strictimport = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictprops")) != null) {
+            this.strictprops = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.strictsignal")) != null) {
+            this.strictsignal = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.symbols")) != null) {
+            this.symbols = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.time")) != null) {
+            this.time = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.trace")) != null) {
+            setTrace(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.utf8")) != null) {
+            this.utf8 = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.verbose")) != null) {
+            setVerbose(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.suppressMethodArgumentNotUsed")) != null) {
+            this.suppressMethodArgumentNotUsed = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.suppressPrivatePropertyNotUsed")) != null) {
+            this.suppressPrivatePropertyNotUsed = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.suppressVariableNotUsed")) != null) {
+            this.suppressVariableNotUsed = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.suppressExceptionNotSignalled")) != null) {
+            this.suppressExceptionNotSignalled = Project.toBoolean(p);
+        }
+        if ((p = getProject().getProperty("ant.netrexxc.suppressDeprecation")) != null) {
+            this.suppressDeprecation = Project.toBoolean(p);
+        }
+    }
+
+
+    /**
+     * Executes the task - performs the actual compiler call.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+
+        // first off, make sure that we've got a srcdir and destdir
+        if (srcDir == null || destDir == null) {
+            throw new BuildException("srcDir and destDir attributes must be set!");
+        }
+
+        // scan source and dest dirs to build up both copy lists and
+        // compile lists
+        //        scanDir(srcDir, destDir);
+        DirectoryScanner ds = getDirectoryScanner(srcDir);
+
+        String[] files = ds.getIncludedFiles();
+
+        scanDir(srcDir, destDir, files);
+
+        // copy the source and support files
+        copyFilesToDestination();
+
+        // compile the source files
+        if (compileList.size() > 0) {
+            log("Compiling " + compileList.size() + " source file"
+                 + (compileList.size() == 1 ? "" : "s")
+                 + " to " + destDir);
+            doNetRexxCompile();
+        }
+    }
+
+
+    /**
+     * Scans the directory looking for source files to be compiled and support
+     * files to be copied.
+     */
+    private void scanDir(File srcDir, File destDir, String[] files) {
+        for (int i = 0; i < files.length; i++) {
+            File srcFile = new File(srcDir, files[i]);
+            File destFile = new File(destDir, files[i]);
+            String filename = files[i];
+            // if it's a non source file, copy it if a later date than the
+            // dest
+            // if it's a source file, see if the destination class file
+            // needs to be recreated via compilation
+            if (filename.toLowerCase().endsWith(".nrx")) {
+                File classFile =
+                    new File(destDir,
+                    filename.substring(0, filename.lastIndexOf('.')) + ".class");
+
+                if (!compile || srcFile.lastModified() > classFile.lastModified()) {
+                    filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath());
+                    compileList.addElement(destFile.getAbsolutePath());
+                }
+            } else {
+                if (srcFile.lastModified() > destFile.lastModified()) {
+                    filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath());
+                }
+            }
+        }
+    }
+
+
+    /** Copy eligible files from the srcDir to destDir  */
+    private void copyFilesToDestination() {
+        if (filecopyList.size() > 0) {
+            log("Copying " + filecopyList.size() + " file"
+                 + (filecopyList.size() == 1 ? "" : "s")
+                 + " to " + destDir.getAbsolutePath());
+
+            Enumeration e = filecopyList.keys();
+
+            while (e.hasMoreElements()) {
+                String fromFile = (String) e.nextElement();
+                String toFile = (String) filecopyList.get(fromFile);
+
+                try {
+                    FileUtils.getFileUtils().copyFile(fromFile, toFile);
+                } catch (IOException ioe) {
+                    String msg = "Failed to copy " + fromFile + " to " + toFile
+                         + " due to " + ioe.getMessage();
+
+                    throw new BuildException(msg, ioe);
+                }
+            }
+        }
+    }
+
+
+    /** Performs a compile using the NetRexx 1.1.x compiler  */
+    private void doNetRexxCompile() throws BuildException {
+        log("Using NetRexx compiler", Project.MSG_VERBOSE);
+
+        String classpath = getCompileClasspath();
+        StringBuffer compileOptions = new StringBuffer();
+
+        // create an array of strings for input to the compiler: one array
+        // comes from the compile options, the other from the compileList
+        String[] compileOptionsArray = getCompileOptionsAsArray();
+        String[] fileListArray = new String[compileList.size()];
+        Enumeration e = compileList.elements();
+        int j = 0;
+
+        while (e.hasMoreElements()) {
+            fileListArray[j] = (String) e.nextElement();
+            j++;
+        }
+        // create a single array of arguments for the compiler
+        String[] compileArgs = new String[compileOptionsArray.length + fileListArray.length];
+
+        for (int i = 0; i < compileOptionsArray.length; i++) {
+            compileArgs[i] = compileOptionsArray[i];
+        }
+        for (int i = 0; i < fileListArray.length; i++) {
+            compileArgs[i + compileOptionsArray.length] = fileListArray[i];
+        }
+
+        // print nice output about what we are doing for the log
+        compileOptions.append("Compilation args: ");
+        for (int i = 0; i < compileOptionsArray.length; i++) {
+            compileOptions.append(compileOptionsArray[i]);
+            compileOptions.append(" ");
+        }
+        log(compileOptions.toString(), Project.MSG_VERBOSE);
+
+        String eol = System.getProperty("line.separator");
+        StringBuffer niceSourceList = new StringBuffer("Files to be compiled:" + eol);
+
+        for (int i = 0; i < compileList.size(); i++) {
+            niceSourceList.append("    ");
+            niceSourceList.append(compileList.elementAt(i).toString());
+            niceSourceList.append(eol);
+        }
+
+        log(niceSourceList.toString(), Project.MSG_VERBOSE);
+
+        // need to set java.class.path property and restore it later
+        // since the NetRexx compiler has no option for the classpath
+        String currentClassPath = System.getProperty("java.class.path");
+        Properties currentProperties = System.getProperties();
+
+        currentProperties.put("java.class.path", classpath);
+
+        try {
+            StringWriter out = new StringWriter();
+            int rc =
+                COM.ibm.netrexx.process.NetRexxC.main(new Rexx(compileArgs), new PrintWriter(out));
+            String sdir = srcDir.getAbsolutePath();
+            String ddir = destDir.getAbsolutePath();
+            boolean doReplace = !(sdir.equals(ddir));
+            int dlen = ddir.length();
+            String l;
+            BufferedReader in = new BufferedReader(new StringReader(out.toString()));
+
+            log("replacing destdir '" + ddir + "' through sourcedir '"
+                + sdir + "'", Project.MSG_VERBOSE);
+            while ((l = in.readLine()) != null) {
+                int idx;
+
+                while (doReplace && ((idx = l.indexOf(ddir)) != -1)) {
+                    // path is mentioned in the message
+                    l = (new StringBuffer(l)).replace(idx, idx + dlen, sdir).toString();
+                }
+                // verbose level logging for suppressed messages
+                if (suppressMethodArgumentNotUsed
+                    && l.indexOf(MSG_METHOD_ARGUMENT_NOT_USED) != -1) {
+                    log(l, Project.MSG_VERBOSE);
+                } else if (suppressPrivatePropertyNotUsed
+                    && l.indexOf(MSG_PRIVATE_PROPERTY_NOT_USED) != -1) {
+                    log(l, Project.MSG_VERBOSE);
+                } else if (suppressVariableNotUsed
+                    && l.indexOf(MSG_VARIABLE_NOT_USED) != -1) {
+                    log(l, Project.MSG_VERBOSE);
+                } else if (suppressExceptionNotSignalled
+                    && l.indexOf(MSG_EXCEPTION_NOT_SIGNALLED) != -1) {
+                    log(l, Project.MSG_VERBOSE);
+                } else if (suppressDeprecation
+                    && l.indexOf(MSG_DEPRECATION) != -1) {
+                    log(l, Project.MSG_VERBOSE);
+                } else if (l.indexOf("Error:") != -1) {
+                    // error level logging for compiler errors
+                    log(l, Project.MSG_ERR);
+                } else if (l.indexOf("Warning:") != -1) {
+                    // warning for all warning messages
+                    log(l, Project.MSG_WARN);
+                } else {
+                    log(l, Project.MSG_INFO); // info level for the rest.
+                }
+            }
+            if (rc > 1) {
+                throw new BuildException("Compile failed, messages should "
+                    + "have been provided.");
+            }
+        } catch (IOException ioe) {
+            throw new BuildException("Unexpected IOException while "
+                + "playing with Strings", ioe);
+        } finally {
+            // need to reset java.class.path property
+            // since the NetRexx compiler has no option for the classpath
+            currentProperties = System.getProperties();
+            currentProperties.put("java.class.path", currentClassPath);
+        }
+
+    }
+
+
+    /** Builds the compilation classpath.  */
+    private String getCompileClasspath() {
+        StringBuffer classpath = new StringBuffer();
+
+        // add dest dir to classpath so that previously compiled and
+        // untouched classes are on classpath
+        classpath.append(destDir.getAbsolutePath());
+
+        // add our classpath to the mix
+        if (this.classpath != null) {
+            addExistingToClasspath(classpath, this.classpath);
+        }
+
+        // add the system classpath
+        // addExistingToClasspath(classpath,System.getProperty("java.class.path"));
+        return classpath.toString();
+    }
+
+
+    /** This  */
+    private String[] getCompileOptionsAsArray() {
+        Vector options = new Vector();
+
+        options.addElement(binary ? "-binary" : "-nobinary");
+        options.addElement(comments ? "-comments" : "-nocomments");
+        options.addElement(compile ? "-compile" : "-nocompile");
+        options.addElement(compact ? "-compact" : "-nocompact");
+        options.addElement(console ? "-console" : "-noconsole");
+        options.addElement(crossref ? "-crossref" : "-nocrossref");
+        options.addElement(decimal ? "-decimal" : "-nodecimal");
+        options.addElement(diag ? "-diag" : "-nodiag");
+        options.addElement(explicit ? "-explicit" : "-noexplicit");
+        options.addElement(format ? "-format" : "-noformat");
+        options.addElement(keep ? "-keep" : "-nokeep");
+        options.addElement(logo ? "-logo" : "-nologo");
+        options.addElement(replace ? "-replace" : "-noreplace");
+        options.addElement(savelog ? "-savelog" : "-nosavelog");
+        options.addElement(sourcedir ? "-sourcedir" : "-nosourcedir");
+        options.addElement(strictargs ? "-strictargs" : "-nostrictargs");
+        options.addElement(strictassign ? "-strictassign" : "-nostrictassign");
+        options.addElement(strictcase ? "-strictcase" : "-nostrictcase");
+        options.addElement(strictimport ? "-strictimport" : "-nostrictimport");
+        options.addElement(strictprops ? "-strictprops" : "-nostrictprops");
+        options.addElement(strictsignal ? "-strictsignal" : "-nostrictsignal");
+        options.addElement(symbols ? "-symbols" : "-nosymbols");
+        options.addElement(time ? "-time" : "-notime");
+        options.addElement("-" + trace);
+        options.addElement(utf8 ? "-utf8" : "-noutf8");
+        options.addElement("-" + verbose);
+
+        String[] results = new String[options.size()];
+
+        options.copyInto(results);
+        return results;
+    }
+
+
+    /**
+     * Takes a classpath-like string, and adds each element of this string to
+     * a new classpath, if the components exist. Components that don't exist,
+     * aren't added. We do this, because jikes issues warnings for
+     * non-existant files/dirs in his classpath, and these warnings are pretty
+     * annoying.
+     *
+     * @param target - target classpath
+     * @param source - source classpath to get file objects.
+     */
+    private void addExistingToClasspath(StringBuffer target, String source) {
+        StringTokenizer tok = new StringTokenizer(source,
+            System.getProperty("path.separator"), false);
+
+        while (tok.hasMoreTokens()) {
+            File f = getProject().resolveFile(tok.nextToken());
+
+            if (f.exists()) {
+                target.append(File.pathSeparator);
+                target.append(f.getAbsolutePath());
+            } else {
+                log("Dropping from classpath: "
+                    + f.getAbsolutePath(), Project.MSG_VERBOSE);
+            }
+        }
+
+    }
+
+
+    /**
+     * Enumerated class corresponding to the trace attribute.
+     */
+    public static class TraceAttr extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{"trace", "trace1", "trace2", "notrace"};
+        }
+    }
+
+    /**
+     * Enumerated class corresponding to the verbose attribute.
+     */
+    public static class VerboseAttr extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{"verbose", "verbose0", "verbose1",
+                "verbose2", "verbose3", "verbose4",
+                "verbose5", "noverbose"};
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
new file mode 100644
index 0000000..bc03f75
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/PropertyFile.java
@@ -0,0 +1,666 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ *Modifies settings in a property file.
+ *
+ * <p>
+ *The following is an example of its usage:
+ *    <ul>&lt;target name="setState"&gt;<br>
+ *    <ul>&lt;property<br>
+ *        <ul>name="header"<br>
+ *        value="##Generated file - do not modify!"/&gt;<br>
+ *      &lt;propertyfile file="apropfile.properties" comment="${header}"&gt;<br>
+ *        &lt;entry key="product.version.major" type="int"  value="5"/&gt;<br>
+ *        &lt;entry key="product.version.minor" type="int"  value="0"/&gt;<br>
+ *        &lt;entry key="product.build.major"   type="int"  value="0" /&gt;<br>
+ *        &lt;entry key="product.build.minor"   type="int"  operation="+" /&gt;<br>
+ *        &lt;entry key="product.build.date"    type="date" value="now" /&gt;<br>
+ *        &lt;entry key="intSet" type="int" operation="=" value="681"/&gt;<br>
+ *        &lt;entry key="intDec" type="int" operation="-"/&gt;<br>
+ *        &lt;entry key="StringEquals" type="string" value="testValue"/&gt;<br>
+ *     &lt;/propertyfile&gt;<br></ul>
+ *   &lt;/target&gt;</ul><p>
+ *
+ *The &lt;propertyfile&gt; task must have:<br>
+ *    <ul><li>file</li></ul>
+ *Other parameters are:<br>
+ *    <ul><li>comment, key, operation, type and value (the final four being
+ *            eliminated shortly)</li></ul>
+ *
+ *The &lt;entry&gt; task must have:<br>
+ *    <ul><li>key</li></ul>
+ *Other parameters are:<br>
+ *    <ul><li>operation</li>
+ *        <li>type</li>
+ *        <li>value</li>
+ *        <li>default</li>
+ *        <li>unit</li>
+ *    </ul>
+ *
+ *If type is unspecified, it defaults to string
+ *
+ *Parameter values:<br>
+ *    <ul><li>operation:</li>
+ *        <ul><li>"=" (set -- default)</li>
+ *        <li>"-" (dec)</li>
+ *        <li>"+" (inc)</li>
+ *
+ *    <li>type:</li>
+ *        <ul><li>"int"</li>
+ *        <li>"date"</li>
+ *        <li>"string"</li></ul></ul>
+ *
+ *    <li>value:</li>
+ *      <ul><li>holds the default value, if the property
+ *              was not found in property file</li>
+ *          <li>"now" In case of type "date", the
+ *              value "now" will be replaced by the current
+ *              date/time and used even if a valid date was
+ *              found in the property file.</li></ul>
+ *
+ *
+ *String property types can only use the "=" operation.
+ *Int property types can only use the "=", "-" or "+" operations.<p>
+ *
+ *The message property is used for the property file header, with "\\" being
+ *a newline delimiter character.
+ *
+ */
+public class PropertyFile extends Task {
+
+    /* ========================================================================
+    *
+    * Instance variables.
+    */
+
+    // Use this to prepend a message to the properties file
+    private String              comment;
+
+    private Properties          properties;
+    private File                propertyfile;
+
+    private Vector entries = new Vector();
+
+    /* ========================================================================
+    *
+    * Constructors
+    */
+
+    /* ========================================================================
+    *
+    * Methods
+    */
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+        checkParameters();
+        readFile();
+        executeOperation();
+        writeFile();
+    }
+
+    /**
+     * The entry nested element.
+     * @return an entry nested element to be configured.
+     */
+    public Entry createEntry() {
+        Entry e = new Entry();
+        entries.addElement(e);
+        return e;
+    }
+
+    private void executeOperation() throws BuildException {
+        for (Enumeration e = entries.elements(); e.hasMoreElements();) {
+            Entry entry = (Entry) e.nextElement();
+            entry.executeOn(properties);
+        }
+    }
+
+    private void readFile() throws BuildException {
+        // Create the PropertyFile
+        properties = new Properties();
+        try {
+            if (propertyfile.exists()) {
+                log("Updating property file: "
+                    + propertyfile.getAbsolutePath());
+                FileInputStream fis = null;
+                try {
+                    fis = new FileInputStream(propertyfile);
+                    BufferedInputStream bis = new BufferedInputStream(fis);
+                    properties.load(bis);
+                } finally {
+                    if (fis != null) {
+                        fis.close();
+                    }
+                }
+            } else {
+                log("Creating new property file: "
+                    + propertyfile.getAbsolutePath());
+                FileOutputStream out = null;
+                try {
+                    out = new FileOutputStream(propertyfile.getAbsolutePath());
+                    out.flush();
+                } finally {
+                    if (out != null) {
+                        out.close();
+                    }
+                }
+            }
+        } catch (IOException ioe) {
+            throw new BuildException(ioe.toString());
+        }
+    }
+
+    private void checkParameters() throws BuildException {
+        if (!checkParam(propertyfile)) {
+            throw new BuildException("file token must not be null.", getLocation());
+        }
+    }
+
+    /**
+     * Location of the property file to be edited; required.
+     * @param file the property file.
+     */
+    public void setFile(File file) {
+        propertyfile = file;
+    }
+
+    /**
+     * optional header comment for the file
+     * @param hdr the string to use for the comment.
+     */
+    public void setComment(String hdr) {
+        comment = hdr;
+    }
+
+    private void writeFile() throws BuildException {
+        BufferedOutputStream bos = null;
+        try {
+            bos = new BufferedOutputStream(new FileOutputStream(propertyfile));
+            properties.store(bos, comment);
+        } catch (IOException ioe) {
+            throw new BuildException(ioe, getLocation());
+        } finally {
+            FileUtils.close(bos);
+        }
+    }
+
+    private boolean checkParam(File param) {
+        return !(param == null);
+    }
+
+    /**
+     * Instance of this class represents nested elements of
+     * a task propertyfile.
+     */
+    public static class Entry {
+        private static final int DEFAULT_INT_VALUE = 0;
+        private static final String DEFAULT_DATE_VALUE = "now";
+        private static final String DEFAULT_STRING_VALUE = "";
+
+        private String              key = null;
+        private int                 type = Type.STRING_TYPE;
+        private int                 operation = Operation.EQUALS_OPER;
+        private String              value = null;
+        private String              defaultValue = null;
+        private String              newValue = null;
+        private String              pattern = null;
+        private int                 field = Calendar.DATE;
+
+        /**
+         * Name of the property name/value pair
+         * @param value the key.
+         */
+        public void setKey(String value) {
+            this.key = value;
+        }
+
+        /**
+         * Value to set (=), to add (+) or subtract (-)
+         * @param value the value.
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * operation to apply.
+         * &quot;+&quot; or &quot;=&quot;
+         *(default) for all datatypes; &quot;-&quot; for date and int only)\.
+         * @param value the operation enumerated value.
+         */
+        public void setOperation(Operation value) {
+            this.operation = Operation.toOperation(value.getValue());
+        }
+
+        /**
+         * Regard the value as : int, date or string (default)
+         * @param value the type enumerated value.
+         */
+        public void setType(Type value) {
+            this.type = Type.toType(value.getValue());
+        }
+
+        /**
+         * Initial value to set for a property if it is not
+         * already defined in the property file.
+         * For type date, an additional keyword is allowed: &quot;now&quot;
+         * @param value the default value.
+         */
+        public void setDefault(String value) {
+            this.defaultValue = value;
+        }
+
+        /**
+         * For int and date type only. If present, Values will
+         * be parsed and formatted accordingly.
+         * @param value the pattern to use.
+         */
+        public void setPattern(String value) {
+            this.pattern = value;
+        }
+
+        /**
+         * The unit of the value to be applied to date +/- operations.
+         *            Valid Values are:
+         *            <ul>
+         *               <li>millisecond</li>
+         *               <li>second</li>
+         *               <li>minute</li>
+         *               <li>hour</li>
+         *               <li>day (default)</li>
+         *               <li>week</li>
+         *               <li>month</li>
+         *               <li>year</li>
+         *            </ul>
+         *            This only applies to date types using a +/- operation.
+         * @param unit the unit enumerated value.
+         * @since Ant 1.5
+         */
+        public void setUnit(PropertyFile.Unit unit) {
+            field = unit.getCalendarField();
+        }
+
+        /**
+         * Apply the nested element to the properties.
+         * @param props the properties to apply the entry on.
+         * @throws BuildException if there is an error.
+         */
+        protected void executeOn(Properties props) throws BuildException {
+            checkParameters();
+
+            // type may be null because it wasn't set
+            String oldValue = (String) props.get(key);
+            try {
+                if (type == Type.INTEGER_TYPE) {
+                    executeInteger(oldValue);
+                } else if (type == Type.DATE_TYPE) {
+                    executeDate(oldValue);
+                } else if (type == Type.STRING_TYPE) {
+                    executeString(oldValue);
+                } else {
+                    throw new BuildException("Unknown operation type: "
+                        + type);
+                }
+            } catch (NullPointerException npe) {
+                // Default to string type
+                // which means do nothing
+                npe.printStackTrace();
+            }
+
+            if (newValue == null) {
+                newValue = "";
+            }
+
+            // Insert as a string by default
+            props.put(key, newValue);
+        }
+
+        /**
+        * Handle operations for type <code>date</code>.
+        *
+        * @param oldValue the current value read from the property file or
+        *                 <code>null</code> if the <code>key</code> was
+        *                 not contained in the property file.
+        */
+        private void executeDate(String oldValue) throws BuildException {
+            Calendar currentValue = Calendar.getInstance();
+
+            if (pattern == null) {
+              pattern = "yyyy/MM/dd HH:mm";
+            }
+            DateFormat fmt = new SimpleDateFormat(pattern);
+
+            String currentStringValue = getCurrentValue(oldValue);
+            if (currentStringValue == null) {
+                currentStringValue = DEFAULT_DATE_VALUE;
+            }
+
+            if ("now".equals(currentStringValue)) {
+                currentValue.setTime(new Date());
+            } else {
+                try {
+                    currentValue.setTime(fmt.parse(currentStringValue));
+                } catch (ParseException pe)  {
+                    // swallow
+                }
+            }
+
+            if (operation != Operation.EQUALS_OPER) {
+                int offset = 0;
+                try {
+                    offset = Integer.parseInt(value);
+                    if (operation == Operation.DECREMENT_OPER) {
+                        offset = -1 * offset;
+                    }
+                } catch (NumberFormatException e) {
+                    throw new BuildException("Value not an integer on " + key);
+                }
+                currentValue.add(field, offset);
+            }
+
+            newValue = fmt.format(currentValue.getTime());
+        }
+
+
+        /**
+        * Handle operations for type <code>int</code>.
+        *
+        * @param oldValue the current value read from the property file or
+        *                 <code>null</code> if the <code>key</code> was
+        *                 not contained in the property file.
+        */
+        private void executeInteger(String oldValue) throws BuildException {
+            int currentValue = DEFAULT_INT_VALUE;
+            int newV  = DEFAULT_INT_VALUE;
+
+
+            DecimalFormat fmt = (pattern != null) ? new DecimalFormat(pattern)
+                                                    : new DecimalFormat();
+            try {
+                String curval = getCurrentValue(oldValue);
+                if (curval != null) {
+                    currentValue = fmt.parse(curval).intValue();
+                } else {
+                    currentValue = 0;
+                }
+            } catch (NumberFormatException nfe) {
+                // swallow
+            } catch (ParseException pe)  {
+                // swallow
+            }
+
+            if (operation == Operation.EQUALS_OPER) {
+                newV = currentValue;
+            } else {
+                int operationValue = 1;
+                if (value != null) {
+                    try {
+                        operationValue = fmt.parse(value).intValue();
+                    } catch (NumberFormatException nfe) {
+                        // swallow
+                    } catch (ParseException pe)  {
+                        // swallow
+                    }
+                }
+
+                if (operation == Operation.INCREMENT_OPER) {
+                    newV = currentValue + operationValue;
+                } else if (operation == Operation.DECREMENT_OPER) {
+                    newV = currentValue - operationValue;
+                }
+            }
+
+            this.newValue = fmt.format(newV);
+        }
+
+        /**
+        * Handle operations for type <code>string</code>.
+        *
+        * @param oldValue the current value read from the property file or
+        *                 <code>null</code> if the <code>key</code> was
+        *                 not contained in the property file.
+        */
+        private void executeString(String oldValue) throws BuildException {
+            String newV  = DEFAULT_STRING_VALUE;
+
+            String currentValue = getCurrentValue(oldValue);
+
+            if (currentValue == null) {
+                currentValue = DEFAULT_STRING_VALUE;
+            }
+
+            if (operation == Operation.EQUALS_OPER) {
+                newV = currentValue;
+            } else if (operation == Operation.INCREMENT_OPER) {
+                newV = currentValue + value;
+            }
+            this.newValue = newV;
+        }
+
+        /**
+         * Check if parameter combinations can be supported
+         * @todo make sure the 'unit' attribute is only specified on date
+         *      fields
+         */
+        private void checkParameters() throws BuildException {
+            if (type == Type.STRING_TYPE
+                && operation == Operation.DECREMENT_OPER) {
+                throw new BuildException("- is not supported for string "
+                    + "properties (key:" + key + ")");
+            }
+            if (value == null && defaultValue == null) {
+                throw new BuildException("\"value\" and/or \"default\" "
+                    + "attribute must be specified (key:" + key + ")");
+            }
+            if (key == null) {
+                throw new BuildException("key is mandatory");
+            }
+            if (type == Type.STRING_TYPE && pattern != null) {
+                throw new BuildException("pattern is not supported for string "
+                    + "properties (key:" + key + ")");
+            }
+        }
+
+        private String getCurrentValue(String oldValue) {
+            String ret = null;
+            if (operation == Operation.EQUALS_OPER) {
+                // If only value is specified, the property is set to it
+                // regardless of its previous value.
+                if (value != null && defaultValue == null) {
+                    ret = value;
+                }
+
+                // If only default is specified and the property previously
+                // existed in the property file, it is unchanged.
+                if (value == null && defaultValue != null && oldValue != null) {
+                    ret = oldValue;
+                }
+
+                // If only default is specified and the property did not
+                // exist in the property file, the property is set to default.
+                if (value == null && defaultValue != null && oldValue == null) {
+                    ret = defaultValue;
+                }
+
+                // If value and default are both specified and the property
+                // previously existed in the property file, the property
+                // is set to value.
+                if (value != null && defaultValue != null && oldValue != null) {
+                    ret = value;
+                }
+
+                // If value and default are both specified and the property
+                // did not exist in the property file, the property is set
+                // to default.
+                if (value != null && defaultValue != null && oldValue == null) {
+                    ret = defaultValue;
+                }
+            } else {
+                ret = (oldValue == null) ? defaultValue : oldValue;
+            }
+
+            return ret;
+        }
+
+        /**
+         * Enumerated attribute with the values "+", "-", "="
+         */
+        public static class Operation extends EnumeratedAttribute {
+
+            // Property type operations
+            /** + */
+            public static final int INCREMENT_OPER =   0;
+            /** - */
+            public static final int DECREMENT_OPER =   1;
+            /** = */
+            public static final int EQUALS_OPER =      2;
+
+            /** {@inheritDoc}. */
+            public String[] getValues() {
+                return new String[] {"+", "-", "="};
+            }
+
+            /**
+             * Convert string to index.
+             * @param oper the string to convert.
+             * @return the index.
+             */
+            public static int toOperation(String oper) {
+                if ("+".equals(oper)) {
+                    return INCREMENT_OPER;
+                } else if ("-".equals(oper)) {
+                    return DECREMENT_OPER;
+                }
+                return EQUALS_OPER;
+            }
+        }
+
+        /**
+         * Enumerated attribute with the values "int", "date" and "string".
+         */
+        public static class Type extends EnumeratedAttribute {
+
+            // Property types
+            /** int */
+            public static final int INTEGER_TYPE =     0;
+            /** date */
+            public static final int DATE_TYPE =        1;
+            /** string */
+            public static final int STRING_TYPE =      2;
+
+            /** {@inheritDoc} */
+            public String[] getValues() {
+                return new String[] {"int", "date", "string"};
+            }
+
+            /**
+             * Convert string to index.
+             * @param type the string to convert.
+             * @return the index.
+             */
+            public static int toType(String type) {
+                if ("int".equals(type)) {
+                    return INTEGER_TYPE;
+                } else if ("date".equals(type)) {
+                    return DATE_TYPE;
+                }
+                return STRING_TYPE;
+            }
+        }
+    }
+
+    /**
+     * Borrowed from Tstamp
+     * @todo share all this time stuff across many tasks as a datetime datatype
+     * @since Ant 1.5
+     */
+    public static class Unit extends EnumeratedAttribute {
+
+        private static final String MILLISECOND = "millisecond";
+        private static final String SECOND = "second";
+        private static final String MINUTE = "minute";
+        private static final String HOUR = "hour";
+        private static final String DAY = "day";
+        private static final String WEEK = "week";
+        private static final String MONTH = "month";
+        private static final String YEAR = "year";
+
+        private static final String[] UNITS
+            = {MILLISECOND, SECOND, MINUTE, HOUR,
+               DAY, WEEK, MONTH, YEAR };
+
+        private Map calendarFields = new HashMap();
+
+        /** no arg constructor */
+        public Unit() {
+            calendarFields.put(MILLISECOND,
+                                    new Integer(Calendar.MILLISECOND));
+            calendarFields.put(SECOND, new Integer(Calendar.SECOND));
+            calendarFields.put(MINUTE, new Integer(Calendar.MINUTE));
+            calendarFields.put(HOUR, new Integer(Calendar.HOUR_OF_DAY));
+            calendarFields.put(DAY, new Integer(Calendar.DATE));
+            calendarFields.put(WEEK, new Integer(Calendar.WEEK_OF_YEAR));
+            calendarFields.put(MONTH, new Integer(Calendar.MONTH));
+            calendarFields.put(YEAR, new Integer(Calendar.YEAR));
+        }
+
+        /**
+         * Convert the value to a Calendar field index.
+         * @return the calander value.
+         */
+        public int getCalendarField() {
+            String key = getValue().toLowerCase();
+            Integer i = (Integer) calendarFields.get(key);
+            return i.intValue();
+        }
+
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return UNITS;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java
new file mode 100644
index 0000000..2ed53d5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/RenameExtensions.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Task to rename files based on extension. This task has the following
+ * properties which can be set:
+ * <ul>
+ * <li>fromExtension: </li>
+ * <li>toExtension: </li>
+ * <li>srcDir: </li>
+ * <li>replace: </li>
+ * </ul>
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.Move;
+import org.apache.tools.ant.types.Mapper;
+
+/**
+ *
+ * @version 1.2
+ *
+ * @deprecated since 1.5.x.
+ *             Use &lt;move&gt; instead
+ */
+public class RenameExtensions extends MatchingTask {
+
+    private String fromExtension = "";
+    private String toExtension = "";
+    private boolean replace = false;
+    private File srcDir;
+
+    private Mapper.MapperType globType;
+
+
+    /** Creates new RenameExtensions */
+    public RenameExtensions() {
+        super();
+        globType = new Mapper.MapperType();
+        globType.setValue("glob");
+    }
+
+    /**
+     * The string that files must end in to be renamed
+     *
+     * @param from the extension of files being renamed.
+     */
+    public void setFromExtension(String from) {
+        fromExtension = from;
+    }
+
+    /**
+     * The string that renamed files will end with on
+     * completion
+     *
+     * @param to the extension of the renamed files.
+     */
+    public void setToExtension(String to) {
+        toExtension = to;
+    }
+
+    /**
+     * store replace attribute - this determines whether the target file
+     * should be overwritten if present
+     *
+     * @param replace if true overwrite any target files that exist.
+     */
+    public void setReplace(boolean replace) {
+        this.replace = replace;
+    }
+
+    /**
+     * Set the source dir to find the files to be renamed.
+     *
+     * @param srcDir the source directory.
+     */
+    public void setSrcDir(File srcDir) {
+        this.srcDir = srcDir;
+    }
+
+    /**
+     * Executes the task.
+     *
+     * @throws BuildException is there is a problem in the task execution.
+     */
+    public void execute() throws BuildException {
+
+        // first off, make sure that we've got a from and to extension
+        if (fromExtension == null || toExtension == null || srcDir == null) {
+            throw new BuildException("srcDir, fromExtension and toExtension "
+                + "attributes must be set!");
+        }
+
+        log("DEPRECATED - The renameext task is deprecated.  Use move instead.",
+            Project.MSG_WARN);
+        log("Replace this with:", Project.MSG_INFO);
+        log("<move todir=\"" + srcDir + "\" overwrite=\"" + replace + "\">",
+            Project.MSG_INFO);
+        log("  <fileset dir=\"" + srcDir + "\" />", Project.MSG_INFO);
+        log("  <mapper type=\"glob\"", Project.MSG_INFO);
+        log("          from=\"*" + fromExtension + "\"", Project.MSG_INFO);
+        log("          to=\"*" + toExtension + "\" />", Project.MSG_INFO);
+        log("</move>", Project.MSG_INFO);
+        log("using the same patterns on <fileset> as you\'ve used here",
+            Project.MSG_INFO);
+
+        Move move = new Move();
+        move.bindToOwner(this);
+        move.setOwningTarget(getOwningTarget());
+        move.setTaskName(getTaskName());
+        move.setLocation(getLocation());
+        move.setTodir(srcDir);
+        move.setOverwrite(replace);
+
+        fileset.setDir(srcDir);
+        move.addFileset(fileset);
+
+        Mapper me = move.createMapper();
+        me.setType(globType);
+        me.setFrom("*" + fromExtension);
+        me.setTo("*" + toExtension);
+
+        move.execute();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
new file mode 100644
index 0000000..01baa44
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ReplaceRegExp.java
@@ -0,0 +1,543 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.types.Substitution;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.regexp.Regexp;
+
+/**
+ * Performs regular expression string replacements in a text
+ * file.  The input file(s) must be able to be properly processed by
+ * a Reader instance.  That is, they must be text only, no binary.
+ *
+ * The syntax of the regular expression depends on the implementation that
+ * you choose to use. The system property <code>ant.regexp.regexpimpl</code>
+ * will be the classname of the implementation that will be used (the default
+ * is <code>org.apache.tools.ant.util.regexp.JakartaOroRegexp</code> and
+ * requires the Jakarta Oro Package).
+ *
+ * <pre>
+ * For jdk  &lt;= 1.3, there are two available implementations:
+ *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
+ *        Requires  the jakarta-oro package
+ *
+ *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
+ *        Requires the jakarta-regexp package
+ *
+ * For jdk &gt;= 1.4 an additional implementation is available:
+ *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
+ *        Requires the jdk 1.4 built in regular expression package.
+ *
+ * Usage:
+ *
+ *   Call Syntax:
+ *
+ *     &lt;replaceregexp file="file"
+ *                    match="pattern"
+ *                    replace="pattern"
+ *                    flags="options"?
+ *                    byline="true|false"? &gt;
+ *       regexp?
+ *       substitution?
+ *       fileset*
+ *     &lt;/replaceregexp&gt;
+ *
+ *    NOTE: You must have either the file attribute specified, or at least one fileset subelement
+ *    to operation on.  You may not have the file attribute specified if you nest fileset elements
+ *    inside this task.  Also, you cannot specify both match and a regular expression subelement at
+ *    the same time, nor can you specify the replace attribute and the substitution subelement at
+ *    the same time.
+ *
+ *   Attributes:
+ *
+ *     file    --&gt; A single file to operation on (mutually exclusive
+ *                    with the fileset subelements)
+ *     match   --&gt; The Regular expression to match
+ *     replace --&gt; The Expression replacement string
+ *     flags   --&gt; The options to give to the replacement
+ *                 g = Substitute all occurrences. default is to replace only the first one
+ *                 i = Case insensitive match
+ *
+ *     byline  --&gt; Should this file be processed a single line at a time (default is false)
+ *                 "true" indicates to perform replacement on a line by line basis
+ *                 "false" indicates to perform replacement on the whole file at once.
+ *
+ *  Example:
+ *
+ *     The following call could be used to replace an old property name in a ".properties"
+ *     file with a new name.  In the replace attribute, you can refer to any part of the
+ *     match expression in parenthesis using backslash followed by a number like '\1'.
+ *
+ *     &lt;replaceregexp file="test.properties"
+ *                    match="MyProperty=(.*)"
+ *                    replace="NewProperty=\1"
+ *                    byline="true" /&gt;
+ *
+ * </pre>
+ *
+ */
+public class ReplaceRegExp extends Task {
+
+    private File file;
+    private String flags;
+    private boolean byline;
+    private Vector filesets; // Keep jdk 1.1 compliant so others can use this
+    private RegularExpression regex;
+    private Substitution subs;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Encoding to assume for the files
+     */
+    private String encoding = null;
+
+    /** Default Constructor  */
+    public ReplaceRegExp() {
+        super();
+        this.file = null;
+        this.filesets = new Vector();
+        this.flags = "";
+        this.byline = false;
+
+        this.regex = null;
+        this.subs = null;
+    }
+
+
+    /**
+     * file for which the regular expression should be replaced;
+     * required unless a nested fileset is supplied.
+     * @param file The file for which the reg exp should be replaced.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+
+    /**
+     * the regular expression pattern to match in the file(s);
+     * required if no nested &lt;regexp&gt; is used
+     * @param match the match attribute.
+     */
+    public void setMatch(String match) {
+        if (regex != null) {
+            throw new BuildException("Only one regular expression is allowed");
+        }
+
+        regex = new RegularExpression();
+        regex.setPattern(match);
+    }
+
+
+    /**
+     * The substitution pattern to place in the file(s) in place
+     * of the regular expression.
+     * Required if no nested &lt;substitution&gt; is used
+     * @param replace the replace attribute
+     */
+
+    public void setReplace(String replace) {
+        if (subs != null) {
+            throw new BuildException("Only one substitution expression is "
+                                     + "allowed");
+        }
+
+        subs = new Substitution();
+        subs.setExpression(replace);
+    }
+
+    /**
+     * The flags to use when matching the regular expression.  For more
+     * information, consult the Perl5 syntax.
+     * <ul>
+     *  <li>g : Global replacement.  Replace all occurrences found
+     *  <li>i : Case Insensitive.  Do not consider case in the match
+     *  <li>m : Multiline.  Treat the string as multiple lines of input,
+     *         using "^" and "$" as the start or end of any line, respectively,
+     *         rather than start or end of string.
+     *  <li> s : Singleline.  Treat the string as a single line of input, using
+     *        "." to match any character, including a newline, which normally,
+     *        it would not match.
+     *</ul>
+     * @param flags the flags attribute
+     */
+    public void setFlags(String flags) {
+        this.flags = flags;
+    }
+
+
+    /**
+     * Process the file(s) one line at a time, executing the replacement
+     * on one line at a time.  This is useful if you
+     * want to only replace the first occurrence of a regular expression on
+     * each line, which is not easy to do when processing the file as a whole.
+     * Defaults to <i>false</i>.</td>
+     * @param byline the byline attribute as a string
+     * @deprecated since 1.6.x.
+     *             Use setByLine(boolean).
+     */
+    public void setByLine(String byline) {
+        Boolean res = Boolean.valueOf(byline);
+
+        if (res == null) {
+            res = Boolean.FALSE;
+        }
+        this.byline = res.booleanValue();
+    }
+
+    /**
+     * Process the file(s) one line at a time, executing the replacement
+     * on one line at a time.  This is useful if you
+     * want to only replace the first occurrence of a regular expression on
+     * each line, which is not easy to do when processing the file as a whole.
+     * Defaults to <i>false</i>.</td>
+     * @param byline the byline attribute
+     */
+    public void setByLine(boolean byline) {
+        this.byline = byline;
+    }
+
+
+    /**
+     * Specifies the encoding Ant expects the files to be in -
+     * defaults to the platforms default encoding.
+     * @param encoding the encoding attribute
+     *
+     * @since Ant 1.6
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * list files to apply the replacement to
+     * @param set the fileset element
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+
+    /**
+     * A regular expression.
+     * You can use this element to refer to a previously
+     * defined regular expression datatype instance
+     * @return the regular expression object to be configured as an element
+     */
+    public RegularExpression createRegexp() {
+        if (regex != null) {
+            throw new BuildException("Only one regular expression is allowed.");
+        }
+
+        regex = new RegularExpression();
+        return regex;
+    }
+
+
+    /**
+     * A substitution pattern.  You can use this element to refer to a previously
+     * defined substitution pattern datatype instance.
+     * @return the substitution pattern object to be configured as an element
+     */
+    public Substitution createSubstitution() {
+        if (subs != null) {
+            throw new BuildException("Only one substitution expression is "
+                                     + "allowed");
+        }
+
+        subs = new Substitution();
+        return subs;
+    }
+
+
+    /**
+     * Invoke a regular expression (r) on a string (input) using
+     * substitutions (s) for a matching regex.
+     *
+     * @param r a regular expression
+     * @param s a Substitution
+     * @param input the string to do the replacement on
+     * @param options The options for the regular expression
+     * @return the replacement result
+     */
+    protected String doReplace(RegularExpression r,
+                               Substitution s,
+                               String input,
+                               int options) {
+        String res = input;
+        Regexp regexp = r.getRegexp(getProject());
+
+        if (regexp.matches(input, options)) {
+            log("Found match; substituting", Project.MSG_DEBUG);
+            res = regexp.substitute(input, s.getExpression(getProject()),
+                                    options);
+        }
+
+        return res;
+    }
+
+
+    /**
+     *  Perform the replacement on a file
+     *
+     * @param f the file to perform the relacement on
+     * @param options the regular expressions options
+     * @exception IOException if an error occurs
+     */
+    protected void doReplace(File f, int options)
+         throws IOException {
+        File temp = FILE_UTILS.createTempFile("replace", ".txt", null, true, true);
+
+        Reader r = null;
+        Writer w = null;
+
+        try {
+            if (encoding == null) {
+                r = new FileReader(f);
+                w = new FileWriter(temp);
+            } else {
+                r = new InputStreamReader(new FileInputStream(f), encoding);
+                w = new OutputStreamWriter(new FileOutputStream(temp),
+                                           encoding);
+            }
+
+            BufferedReader br = new BufferedReader(r);
+            BufferedWriter bw = new BufferedWriter(w);
+            PrintWriter pw = new PrintWriter(bw);
+
+            boolean changes = false;
+
+            log("Replacing pattern '" + regex.getPattern(getProject())
+                + "' with '" + subs.getExpression(getProject())
+                + "' in '" + f.getPath() + "'" + (byline ? " by line" : "")
+                + (flags.length() > 0 ? " with flags: '" + flags + "'" : "")
+                + ".", Project.MSG_VERBOSE);
+
+            if (byline) {
+                StringBuffer linebuf = new StringBuffer();
+                String line = null;
+                String res = null;
+                int c;
+                boolean hasCR = false;
+
+                do {
+                    c = br.read();
+
+                    if (c == '\r') {
+                        if (hasCR) {
+                            // second CR -> EOL + possibly empty line
+                            line = linebuf.toString();
+                            res  = doReplace(regex, subs, line, options);
+
+                            if (!res.equals(line)) {
+                                changes = true;
+                            }
+
+                            pw.print(res);
+                            pw.print('\r');
+
+                            linebuf = new StringBuffer();
+                            // hasCR is still true (for the second one)
+                        } else {
+                            // first CR in this line
+                            hasCR = true;
+                        }
+                    } else if (c == '\n') {
+                        // LF -> EOL
+                        line = linebuf.toString();
+                        res  = doReplace(regex, subs, line, options);
+
+                        if (!res.equals(line)) {
+                            changes = true;
+                        }
+
+                        pw.print(res);
+                        if (hasCR) {
+                            pw.print('\r');
+                            hasCR = false;
+                        }
+                        pw.print('\n');
+
+                        linebuf = new StringBuffer();
+                    } else { // any other char
+                        if ((hasCR) || (c < 0)) {
+                            // Mac-style linebreak or EOF (or both)
+                            line = linebuf.toString();
+                            res  = doReplace(regex, subs, line, options);
+
+                            if (!res.equals(line)) {
+                                changes = true;
+                            }
+
+                            pw.print(res);
+                            if (hasCR) {
+                                pw.print('\r');
+                                hasCR = false;
+                            }
+
+                            linebuf = new StringBuffer();
+                        }
+
+                        if (c >= 0) {
+                            linebuf.append((char) c);
+                        }
+                    }
+                } while (c >= 0);
+
+                pw.flush();
+            } else {
+                String buf = FileUtils.safeReadFully(br);
+
+                String res = doReplace(regex, subs, buf, options);
+
+                if (!res.equals(buf)) {
+                    changes = true;
+                }
+
+                pw.print(res);
+                pw.flush();
+            }
+
+            r.close();
+            r = null;
+            w.close();
+            w = null;
+
+            if (changes) {
+                log("File has changed; saving the updated file", Project.MSG_VERBOSE);
+                try {
+                    FILE_UTILS.rename(temp, f);
+                    temp = null;
+                } catch (IOException e) {
+                    throw new BuildException("Couldn't rename temporary file "
+                                             + temp, getLocation());
+                }
+            } else {
+                log("No change made", Project.MSG_DEBUG);
+            }
+        } finally {
+            FileUtils.close(r);
+            FileUtils.close(w);
+            if (temp != null) {
+                temp.delete();
+            }
+        }
+    }
+
+
+    /**
+     * Execute the task
+     *
+     * @throws BuildException is there is a problem in the task execution.
+     */
+    public void execute() throws BuildException {
+        if (regex == null) {
+            throw new BuildException("No expression to match.");
+        }
+        if (subs == null) {
+            throw new BuildException("Nothing to replace expression with.");
+        }
+
+        if (file != null && filesets.size() > 0) {
+            throw new BuildException("You cannot supply the 'file' attribute "
+                                     + "and filesets at the same time.");
+        }
+
+        int options = 0;
+
+        if (flags.indexOf('g') != -1) {
+            options |= Regexp.REPLACE_ALL;
+        }
+
+        if (flags.indexOf('i') != -1) {
+            options |= Regexp.MATCH_CASE_INSENSITIVE;
+        }
+
+        if (flags.indexOf('m') != -1) {
+            options |= Regexp.MATCH_MULTILINE;
+        }
+
+        if (flags.indexOf('s') != -1) {
+            options |= Regexp.MATCH_SINGLELINE;
+        }
+
+        if (file != null && file.exists()) {
+            try {
+                doReplace(file, options);
+            } catch (IOException e) {
+                log("An error occurred processing file: '"
+                    + file.getAbsolutePath() + "': " + e.toString(),
+                    Project.MSG_ERR);
+            }
+        } else if (file != null) {
+            log("The following file is missing: '"
+                + file.getAbsolutePath() + "'", Project.MSG_ERR);
+        }
+
+        int sz = filesets.size();
+
+        for (int i = 0; i < sz; i++) {
+            FileSet fs = (FileSet) (filesets.elementAt(i));
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+
+            String[] files = ds.getIncludedFiles();
+
+            for (int j = 0; j < files.length; j++) {
+                File f = new File(fs.getDir(getProject()), files[j]);
+
+                if (f.exists()) {
+                    try {
+                        doReplace(f, options);
+                    } catch (Exception e) {
+                        log("An error occurred processing file: '"
+                            + f.getAbsolutePath() + "': " + e.toString(),
+                            Project.MSG_ERR);
+                    }
+                } else {
+                    log("The following file is missing: '"
+                        + f.getAbsolutePath() + "'", Project.MSG_ERR);
+                }
+            }
+        }
+    }
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java
new file mode 100644
index 0000000..95fa3ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Rpm.java
@@ -0,0 +1,367 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Invokes the rpm tool to build a Linux installation file.
+ *
+ */
+public class Rpm extends Task {
+
+    private static final String PATH1 = "PATH=";
+    private static final String PATH2 = "Path=";
+    private static final String PATH3 = "path=";
+    private static final int PATH_LEN = PATH1.length();
+
+    /**
+     * the spec file
+     */
+    private String specFile;
+
+    /**
+     * the rpm top dir
+     */
+    private File topDir;
+
+    /**
+     * the rpm command to use
+     */
+    private String command = "-bb";
+
+    /**
+     * The executable to use for building the packages.
+     * @since Ant 1.6
+     */
+    private String rpmBuildCommand = null;
+
+    /**
+     * clean BUILD directory
+     */
+    private boolean cleanBuildDir = false;
+
+    /**
+     * remove spec file
+     */
+    private boolean removeSpec = false;
+
+    /**
+     * remove sources
+     */
+    private boolean removeSource = false;
+
+    /**
+     * the file to direct standard output from the command
+     */
+    private File output;
+
+    /**
+     * the file to direct standard error from the command
+     */
+    private File error;
+
+    /**
+     * Halt on error return value from rpm build.
+     */
+    private boolean failOnError = false;
+
+    /**
+     * Don't show output of RPM build command on console. This does not affect
+     * the printing of output and error messages to files.
+     */
+    private boolean quiet = false;
+
+    /**
+     * Execute the task
+     *
+     * @throws BuildException is there is a problem in the task execution.
+     */
+    public void execute() throws BuildException {
+
+        Commandline toExecute = new Commandline();
+
+        toExecute.setExecutable(rpmBuildCommand == null
+                                ? guessRpmBuildCommand()
+                                : rpmBuildCommand);
+        if (topDir != null) {
+            toExecute.createArgument().setValue("--define");
+            toExecute.createArgument().setValue("_topdir" + topDir);
+        }
+
+        toExecute.createArgument().setLine(command);
+
+        if (cleanBuildDir) {
+            toExecute.createArgument().setValue("--clean");
+        }
+        if (removeSpec) {
+            toExecute.createArgument().setValue("--rmspec");
+        }
+        if (removeSource) {
+            toExecute.createArgument().setValue("--rmsource");
+        }
+
+        toExecute.createArgument().setValue("SPECS/" + specFile);
+
+        ExecuteStreamHandler streamhandler = null;
+        OutputStream outputstream = null;
+        OutputStream errorstream = null;
+        if (error == null && output == null) {
+            if (!quiet) {
+                streamhandler = new LogStreamHandler(this, Project.MSG_INFO,
+                                                     Project.MSG_WARN);
+            } else {
+                streamhandler = new LogStreamHandler(this, Project.MSG_DEBUG,
+                                                     Project.MSG_DEBUG);
+            }
+        } else {
+            if (output != null) {
+                try {
+                    BufferedOutputStream bos
+                        = new BufferedOutputStream(new FileOutputStream(output));
+                    outputstream = new PrintStream(bos);
+                } catch (IOException e) {
+                    throw new BuildException(e, getLocation());
+                }
+            } else if (!quiet) {
+                outputstream = new LogOutputStream(this, Project.MSG_INFO);
+            } else {
+                outputstream = new LogOutputStream(this, Project.MSG_DEBUG);
+            }
+            if (error != null) {
+                try {
+                    BufferedOutputStream bos
+                        = new BufferedOutputStream(new FileOutputStream(error));
+                    errorstream = new PrintStream(bos);
+                }  catch (IOException e) {
+                    throw new BuildException(e, getLocation());
+                }
+            } else if (!quiet) {
+                errorstream = new LogOutputStream(this, Project.MSG_WARN);
+            } else {
+                errorstream = new LogOutputStream(this, Project.MSG_DEBUG);
+            }
+            streamhandler = new PumpStreamHandler(outputstream, errorstream);
+        }
+
+        Execute exe = getExecute(toExecute, streamhandler);
+        try {
+            log("Building the RPM based on the " + specFile + " file");
+            int returncode = exe.execute();
+            if (Execute.isFailure(returncode)) {
+                String msg = "'" + toExecute.getExecutable()
+                    + "' failed with exit code " + returncode;
+                if (failOnError) {
+                    throw new BuildException(msg);
+                } else {
+                    log(msg, Project.MSG_ERR);
+                }
+            }
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        } finally {
+            FileUtils.close(outputstream);
+            FileUtils.close(errorstream);
+        }
+    }
+
+    /**
+     * The directory which will have the expected
+     * subdirectories, SPECS, SOURCES, BUILD, SRPMS ; optional.
+     * If this isn't specified,
+     * the <tt>baseDir</tt> value is used
+     *
+     * @param td the directory containing the normal RPM directories.
+     */
+    public void setTopDir(File td) {
+        this.topDir = td;
+    }
+
+    /**
+     * What command to issue to the rpm build tool; optional.
+     * The default is "-bb"
+     * @param c the command to use.
+     */
+    public void setCommand(String c) {
+        this.command = c;
+    }
+
+    /**
+     * The name of the spec File to use; required.
+     * @param sf the spec file name to use.
+     */
+    public void setSpecFile(String sf) {
+        if ((sf == null) || (sf.trim().length() == 0)) {
+            throw new BuildException("You must specify a spec file", getLocation());
+        }
+        this.specFile = sf;
+    }
+
+    /**
+     * Flag (optional, default=false) to remove
+     * the generated files in the BUILD directory
+     * @param cbd a <code>boolean</code> value.
+     */
+    public void setCleanBuildDir(boolean cbd) {
+        cleanBuildDir = cbd;
+    }
+
+    /**
+     * Flag (optional, default=false) to remove the spec file from SPECS
+     * @param rs a <code>boolean</code> value.
+     */
+    public void setRemoveSpec(boolean rs) {
+        removeSpec = rs;
+    }
+
+    /**
+     * Flag (optional, default=false)
+     * to remove the sources after the build.
+     * See the <tt>--rmsource</tt>  option of rpmbuild.
+     * @param rs a <code>boolean</code> value.
+     */
+    public void setRemoveSource(boolean rs) {
+        removeSource = rs;
+    }
+
+    /**
+     * Optional file to save stdout to.
+     * @param output the file to save stdout to.
+     */
+    public void setOutput(File output) {
+        this.output = output;
+    }
+
+    /**
+     * Optional file to save stderr to
+     * @param error the file to save error output to.
+     */
+    public void setError(File error) {
+        this.error = error;
+    }
+
+    /**
+     * The executable to run when building; optional.
+     * The default is <code>rpmbuild</code>.
+     *
+     * @since Ant 1.6
+     * @param c the rpm build executable
+     */
+    public void setRpmBuildCommand(String c) {
+        this.rpmBuildCommand = c;
+    }
+
+    /**
+     * If <code>true</code>, stop the build process when the rpmbuild command
+     * exits with an error status.
+     * @param value <code>true</code> if it should halt, otherwise
+     * <code>false</code>. The default is <code>false</code>.
+     *
+     * @since Ant 1.6.3
+     */
+    public void setFailOnError(boolean value) {
+        failOnError = value;
+    }
+
+    /**
+     * If true, output from the RPM build command will only be logged to DEBUG.
+     * @param value <code>false</code> if output should be logged, otherwise
+     * <code>true</code>. The default is <code>false</code>.
+     *
+     * @since Ant 1.6.3
+     */
+    public void setQuiet(boolean value) {
+        quiet = value;
+    }
+
+    /**
+     * Checks whether <code>rpmbuild</code> is on the PATH and returns
+     * the absolute path to it - falls back to <code>rpm</code>
+     * otherwise.
+     *
+     * @return the command used to build RPM's
+     *
+     * @since 1.6
+     */
+    protected String guessRpmBuildCommand() {
+        Vector env = Execute.getProcEnvironment();
+        String path = null;
+        for (Enumeration e = env.elements(); e.hasMoreElements();) {
+            String var = (String) e.nextElement();
+            if (var.startsWith(PATH1) || var.startsWith(PATH2) || var.startsWith(PATH3)) {
+                path = var.substring(PATH_LEN);
+                break;
+            }
+        }
+
+        if (path != null) {
+            Path p = new Path(getProject(), path);
+            String[] pElements = p.list();
+            for (int i = 0; i < pElements.length; i++) {
+                File f = new File(pElements[i],
+                                  "rpmbuild"
+                                  + (Os.isFamily("dos") ? ".exe" : ""));
+                if (f.canRead()) {
+                    return f.getAbsolutePath();
+                }
+            }
+        }
+
+        return "rpm";
+    }
+
+    /**
+     * Get the execute object.
+     * @param toExecute the command line to use.
+     * @param streamhandler the stream handler to use.
+     * @return the execute object.
+     * @since Ant 1.6.3
+     */
+    protected Execute getExecute(Commandline toExecute,
+                                 ExecuteStreamHandler streamhandler) {
+        Execute exe = new Execute(streamhandler, null);
+
+        exe.setAntRun(getProject());
+        if (topDir == null) {
+            topDir = getProject().getBaseDir();
+        }
+        exe.setWorkingDirectory(topDir);
+
+        exe.setCommandline(toExecute.getCommandline());
+        return exe;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java
new file mode 100644
index 0000000..c61f960
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/SchemaValidate.java
@@ -0,0 +1,528 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.XmlConstants;
+import org.xml.sax.XMLReader;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.ParserConfigurationException;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.io.File;
+import java.net.MalformedURLException;
+
+/**
+ * Validate XML Schema documents.
+ * This task validates XML schema documents. It requires an XML parser
+ * that handles the relevant SAx, Xerces or JAXP options.
+ *
+ * To resolve remote referencies, Ant may need its proxy set up, using the
+ * setproxy task.
+ *
+ * Hands off most of the work to its parent, {@link XMLValidateTask}
+ * @since Ant1.7
+ */
+
+public class SchemaValidate extends XMLValidateTask {
+
+    /** map of all declared schemas; we catch and complain about redefinitions */
+    private HashMap schemaLocations = new HashMap();
+
+    /** full checking of a schema */
+    private boolean fullChecking = true;
+
+    /**
+     * flag to disable DTD support. Best left enabled.
+     */
+    private boolean disableDTD = false;
+
+    /**
+     * default URL for nonamespace schemas
+     */
+    private SchemaLocation anonymousSchema;
+
+    // Error strings
+    /** SAX1 not supported */
+    public static final String ERROR_SAX_1 = "SAX1 parsers are not supported";
+
+    /** schema features not supported */
+    public static final String ERROR_NO_XSD_SUPPORT
+        = "Parser does not support Xerces or JAXP schema features";
+
+    /** too many default schemas */
+    public static final String ERROR_TOO_MANY_DEFAULT_SCHEMAS
+        = "Only one of defaultSchemaFile and defaultSchemaURL allowed";
+
+    /** unable to create parser */
+    public static final String ERROR_PARSER_CREATION_FAILURE
+        = "Could not create parser";
+
+    /** adding schema */
+    public static final String MESSAGE_ADDING_SCHEMA = "Adding schema ";
+
+    /** Duplicate declaration of schema  */
+    public static final String ERROR_DUPLICATE_SCHEMA
+        = "Duplicate declaration of schema ";
+
+    /**
+     * Called by the project to let the task initialize properly. The default
+     * implementation is a no-op.
+     *
+     * @throws BuildException if something goes wrong with the build
+     */
+    public void init() throws BuildException {
+        super.init();
+        //validating
+        setLenient(false);
+    }
+
+    /**
+     * Turn on XSD support in Xerces.
+     * @return true on success, false on failure
+     */
+    public boolean enableXercesSchemaValidation() {
+        try {
+            setFeature(XmlConstants.FEATURE_XSD, true);
+            //set the schema source for the doc
+            setNoNamespaceSchemaProperty(XmlConstants.PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION);
+        } catch (BuildException e) {
+            log(e.toString(), Project.MSG_VERBOSE);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * set nonamespace handling up for xerces or other parsers
+     * @param property name of the property to set
+     */
+    private void setNoNamespaceSchemaProperty(String property) {
+        String anonSchema = getNoNamespaceSchemaURL();
+        if (anonSchema != null) {
+            setProperty(property, anonSchema);
+        }
+    }
+
+    /**
+     * Set schema attributes in a JAXP 1.2 engine.
+     * @see <A href="http://java.sun.com/xml/jaxp/change-requests-11.html">
+     * JAXP 1.2 Approved CHANGES</A>
+     * @return true on success, false on failure
+     */
+    public boolean enableJAXP12SchemaValidation() {
+        try {
+            //enable XSD
+            setProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_LANGUAGE, XmlConstants.URI_XSD);
+            //set the schema source for the doc
+            setNoNamespaceSchemaProperty(XmlConstants.FEATURE_JAXP12_SCHEMA_SOURCE);
+        } catch (BuildException e) {
+            log(e.toString(), Project.MSG_VERBOSE);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * add the schema
+     * @param location the schema location.
+     * @throws BuildException if there is no namespace, or if there already
+     * is a declaration of this schema with a different value
+     */
+    public void addConfiguredSchema(SchemaLocation location) {
+        log("adding schema " + location, Project.MSG_DEBUG);
+        location.validateNamespace();
+        SchemaLocation old = (SchemaLocation) schemaLocations.get(location.getNamespace());
+        if (old != null && !old.equals(location)) {
+            throw new BuildException(ERROR_DUPLICATE_SCHEMA + location);
+        }
+        schemaLocations.put(location.getNamespace(), location);
+    }
+
+    /**
+     * enable full schema checking. Slower but better.
+     * @param fullChecking a <code>boolean</code> value.
+     */
+    public void setFullChecking(boolean fullChecking) {
+        this.fullChecking = fullChecking;
+    }
+
+    /**
+     * create a schema location to hold the anonymous
+     * schema
+     */
+    protected void createAnonymousSchema() {
+        if (anonymousSchema == null) {
+            anonymousSchema = new SchemaLocation();
+        }
+        anonymousSchema.setNamespace("(no namespace)");
+    }
+
+    /**
+     * identify the URL of the default schema
+     * @param defaultSchemaURL the URL of the default schema.
+     */
+    public void setNoNamespaceURL(String defaultSchemaURL) {
+        createAnonymousSchema();
+        this.anonymousSchema.setUrl(defaultSchemaURL);
+    }
+
+    /**
+     * identify a file containing the default schema
+     * @param defaultSchemaFile the location of the default schema.
+     */
+    public void setNoNamespaceFile(File defaultSchemaFile) {
+        createAnonymousSchema();
+        this.anonymousSchema.setFile(defaultSchemaFile);
+    }
+
+    /**
+     * flag to disable DTD support.
+     * @param disableDTD a <code>boolean</code> value.
+     */
+    public void setDisableDTD(boolean disableDTD) {
+        this.disableDTD = disableDTD;
+    }
+
+    /**
+     * init the parser : load the parser class, and set features if necessary It
+     * is only after this that the reader is valid
+     *
+     * @throws BuildException if something went wrong
+     */
+    protected void initValidator() {
+        super.initValidator();
+        //validate the parser type
+        if (isSax1Parser()) {
+            throw new BuildException(ERROR_SAX_1);
+        }
+
+        //enable schema
+        //setFeature(XmlConstants.FEATURE_VALIDATION, false);
+        setFeature(XmlConstants.FEATURE_NAMESPACES, true);
+        if (!enableXercesSchemaValidation() && !enableJAXP12SchemaValidation()) {
+            //couldnt use the xerces or jaxp calls
+            throw new BuildException(ERROR_NO_XSD_SUPPORT);
+        }
+
+        //enable schema checking
+        setFeature(XmlConstants.FEATURE_XSD_FULL_VALIDATION, fullChecking);
+
+        //turn off DTDs if desired
+        setFeatureIfSupported(XmlConstants.FEATURE_DISALLOW_DTD, disableDTD);
+
+        //schema declarations go in next
+        addSchemaLocations();
+    }
+
+    /**
+     * Create a reader if the use of the class did not specify another one.
+     * The reason to not use {@link JAXPUtils#getXMLReader()} was to
+     * create our own factory with our own options.
+     * @return a default XML parser
+     */
+    protected XMLReader createDefaultReader() {
+        SAXParserFactory factory = SAXParserFactory.newInstance();
+        factory.setValidating(true);
+        factory.setNamespaceAware(true);
+        XMLReader reader = null;
+        try {
+            SAXParser saxParser = factory.newSAXParser();
+            reader = saxParser.getXMLReader();
+        } catch (ParserConfigurationException e) {
+            throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
+        } catch (SAXException e) {
+            throw new BuildException(ERROR_PARSER_CREATION_FAILURE, e);
+        }
+        return reader;
+    }
+
+    /**
+     * build a string list of all schema locations, then set the relevant
+     * property.
+     */
+    protected void addSchemaLocations() {
+        Iterator it = schemaLocations.values().iterator();
+        StringBuffer buffer = new StringBuffer();
+        int count = 0;
+        while (it.hasNext()) {
+            if (count > 0) {
+                buffer.append(' ');
+            }
+            SchemaLocation schemaLocation = (SchemaLocation) it.next();
+            String tuple = schemaLocation.getURIandLocation();
+            buffer.append(tuple);
+            log("Adding schema " + tuple, Project.MSG_VERBOSE);
+            count++;
+        }
+        if (count > 0) {
+            setProperty(XmlConstants.PROPERTY_SCHEMA_LOCATION, buffer.toString());
+        }
+
+    }
+
+    /**
+     * get the URL of the no namespace schema
+     * @return the schema URL
+     */
+    protected String getNoNamespaceSchemaURL() {
+        if (anonymousSchema == null) {
+            return null;
+        } else {
+            return anonymousSchema.getSchemaLocationURL();
+        }
+    }
+
+    /**
+     * set a feature if it is supported, log at verbose level if
+     * not
+     * @param feature the feature.
+     * @param value a <code>boolean</code> value.
+     */
+    protected void setFeatureIfSupported(String feature, boolean value) {
+        try {
+            getXmlReader().setFeature(feature, value);
+        } catch (SAXNotRecognizedException e) {
+            log("Not recognizied: " + feature, Project.MSG_VERBOSE);
+        } catch (SAXNotSupportedException e) {
+            log("Not supported: " + feature, Project.MSG_VERBOSE);
+        }
+    }
+
+    /**
+     * handler called on successful file validation.
+     *
+     * @param fileProcessed number of files processed.
+     */
+    protected void onSuccessfulValidation(int fileProcessed) {
+        log(fileProcessed + MESSAGE_FILES_VALIDATED, Project.MSG_VERBOSE);
+    }
+
+    /**
+     * representation of a schema location. This is a URI plus either a file or
+     * a url
+     */
+    public static class SchemaLocation {
+        private String namespace;
+
+        private File file;
+
+        private String url;
+
+        /** No namespace URI */
+        public static final String ERROR_NO_URI = "No namespace URI";
+
+        /** Both URL and File were given for schema */
+        public static final String ERROR_TWO_LOCATIONS
+            = "Both URL and File were given for schema ";
+
+        /** File not found */
+        public static final String ERROR_NO_FILE = "File not found: ";
+
+        /** Cannot make URL */
+        public static final String ERROR_NO_URL_REPRESENTATION
+            = "Cannot make a URL of ";
+
+        /** No location provided */
+        public static final String ERROR_NO_LOCATION
+            = "No file or URL supplied for the schema ";
+
+        /** No arg constructor */
+        public SchemaLocation() {
+        }
+
+        /**
+         * Get the namespace.
+         * @return the namespace.
+         */
+        public String getNamespace() {
+            return namespace;
+        }
+
+        /**
+         * set the namespace of this schema. Any URI
+         * @param namespace the namespace to use.
+         */
+        public void setNamespace(String namespace) {
+            this.namespace = namespace;
+        }
+
+        /**
+         * Get the file.
+         * @return the file containing the schema.
+         */
+        public File getFile() {
+            return file;
+        }
+
+        /**
+         * identify a file that contains this namespace's schema.
+         * The file must exist.
+         * @param file the file contains the schema.
+         */
+        public void setFile(File file) {
+            this.file = file;
+        }
+
+        /**
+         * The URL containing the schema.
+         * @return the URL string.
+         */
+        public String getUrl() {
+            return url;
+        }
+
+        /**
+         * identify a URL that hosts the schema.
+         * @param url the URL string.
+         */
+        public void setUrl(String url) {
+            this.url = url;
+        }
+
+        /**
+         * get the URL of the schema
+         * @return a URL to the schema
+         * @throws BuildException if not
+         */
+        public String getSchemaLocationURL() {
+            boolean hasFile = file != null;
+            boolean hasURL = isSet(url);
+            //error if both are empty, or both are set
+            if (!hasFile && !hasURL) {
+                throw new BuildException(ERROR_NO_LOCATION + namespace);
+            }
+            if (hasFile && hasURL) {
+                throw new BuildException(ERROR_TWO_LOCATIONS + namespace);
+            }
+            String schema = url;
+            if (hasFile) {
+                if (!file.exists()) {
+                    throw new BuildException(ERROR_NO_FILE + file);
+                }
+
+                try {
+                    schema = FileUtils.getFileUtils().getFileURL(file).toString();
+                } catch (MalformedURLException e) {
+                    //this is almost implausible, but required handling
+                    throw new BuildException(ERROR_NO_URL_REPRESENTATION + file, e);
+                }
+            }
+            return schema;
+        }
+
+        /**
+         * validate the fields then create a "uri location" string
+         *
+         * @return string of uri and location
+         * @throws BuildException if there is an error.
+         */
+        public String getURIandLocation() throws BuildException {
+            validateNamespace();
+            StringBuffer buffer = new StringBuffer();
+            buffer.append(namespace);
+            buffer.append(' ');
+            buffer.append(getSchemaLocationURL());
+            return new String(buffer);
+        }
+
+        /**
+         * assert that a namespace is valid
+         * @throws BuildException if not
+         */
+        public void validateNamespace() {
+            if (!isSet(getNamespace())) {
+                throw new BuildException(ERROR_NO_URI);
+            }
+        }
+
+        /**
+         * check that a property is set
+         * @param property string to check
+         * @return true if it is not null or empty
+         */
+        private boolean isSet(String property) {
+            return property != null && property.length() != 0;
+        }
+
+        /**
+         * equality test checks namespace, location and filename. All must match,
+         * @param o object to compare against
+         * @return true iff the objects are considered equal in value
+         */
+
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof SchemaLocation)) {
+                return false;
+            }
+
+            final SchemaLocation schemaLocation = (SchemaLocation) o;
+
+            if (file != null ? !file.equals(schemaLocation.file) : schemaLocation.file != null) {
+                return false;
+            }
+            if (namespace != null ? !namespace.equals(schemaLocation.namespace)
+                    : schemaLocation.namespace != null) {
+                return false;
+            }
+            if (url != null ? !url.equals(schemaLocation.url) : schemaLocation.url != null) {
+                return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * Generate a hashcode depending on the namespace, url and file name.
+         * @return the hashcode.
+         */
+        public int hashCode() {
+            int result;
+            // CheckStyle:MagicNumber OFF
+            result = (namespace != null ? namespace.hashCode() : 0);
+            result = 29 * result + (file != null ? file.hashCode() : 0);
+            result = 29 * result + (url != null ? url.hashCode() : 0);
+            // CheckStyle:MagicNumber OFF
+            return result;
+        }
+
+        /**
+         * Returns a string representation of the object for error messages
+         * and the like
+         * @return a string representation of the object.
+         */
+        public String toString() {
+            StringBuffer buffer = new StringBuffer();
+            buffer.append(namespace != null ? namespace : "(anonymous)");
+            buffer.append(' ');
+            buffer.append(url != null ? (url + " ") : "");
+            buffer.append(file != null ? file.getAbsolutePath() : "");
+            return buffer.toString();
+        }
+    } //SchemaLocation
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
new file mode 100644
index 0000000..74930f2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Executes a script.
+ *
+ * @ant.task name="script"
+ */
+public class Script extends Task {
+
+    private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+    /**
+     * Set the project.
+     * @param project the project that this task belongs to.
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        helper.setProjectComponent(this);
+    }
+
+    /**
+     * Run the script using the helper object.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        helper.getScriptRunner().executeScript("ANT");
+    }
+
+    /**
+     * Defines the manager.
+     *
+     * @param manager the scripting manager.
+     */
+    public void setManager(String manager) {
+        helper.setManager(manager);
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        helper.setLanguage(language);
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param fileName the name of the file containing the script source.
+     */
+    public void setSrc(String fileName) {
+        helper.setSrc(new File(fileName));
+    }
+
+    /**
+     * Set the script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        helper.addText(text);
+    }
+
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        helper.setClasspath(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        return helper.createClasspath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        helper.setClasspathRef(r);
+    }
+
+    /**
+     * Set the setbeans attribute.
+     * If this is true, &lt;script&gt; will create variables in the
+     * script instance for all
+     * properties, targets and references of the current project.
+     * It this is false, only the project and self variables will
+     * be set.
+     * The default is true.
+     * @param setBeans the value to set.
+     */
+    public void setSetBeans(boolean setBeans) {
+        helper.setSetBeans(setBeans);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/StyleBook.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/StyleBook.java
new file mode 100644
index 0000000..cd4e6ed
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/StyleBook.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+
+/**
+ * Executes the Apache Stylebook documentation generator.
+ * Unlike the commandline version of this tool, all three arguments
+ * are required to run stylebook.
+ * <p>
+ * Being extended from &lt;Java&gt;, all the parent's attributes
+ * and options are available. Do not set any apart from the <tt>classpath</tt>
+ * as they are not guaranteed to be there in future.
+ * @todo stop extending from Java.
+ * @deprecated since 1.7.
+ *             This task is considered unsupported by the Ant developers
+ */
+public class StyleBook extends Java {
+    // CheckStyle:VisibilityModifier OFF - bc
+    // CheckStyle:MemberNameCheck OFF - bc
+    protected File m_targetDirectory;
+    protected File m_skinDirectory;
+    protected String m_loaderConfig;
+    protected File m_book;
+    // CheckStyle:MemberNameCheck ON
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     * Constructor
+     */
+    public StyleBook() {
+        setClassname("org.apache.stylebook.StyleBook");
+        setFork(true);
+        setFailonerror(true);
+    }
+
+    /**
+     * Set the book xml file that the documentation generation starts from;
+     * required.
+     * @param book the source file
+     */
+
+    public void setBook(final File book) {
+        m_book = book;
+    }
+
+
+    /**
+     * Set the directory that contains the stylebook skin;
+     * required.
+     * @param skinDirectory the location of the stylebook skin
+     */
+    public void setSkinDirectory(final File skinDirectory) {
+        m_skinDirectory = skinDirectory;
+    }
+
+
+    /**
+     * Set the destination directory where the documentation is generated;
+     * required.
+     * @param targetDirectory the document output directory
+     */
+    public void setTargetDirectory(final File targetDirectory) {
+        m_targetDirectory = targetDirectory;
+    }
+
+    /**
+     * A loader configuration to send to stylebook; optional.
+     * @param loaderConfig the configuration to use.
+     */
+    public void setLoaderConfig(final String loaderConfig) {
+        m_loaderConfig = loaderConfig;
+    }
+
+
+    /**
+     * call the program
+     * @throws BuildException if there is a problem.
+     */
+    public void execute()
+         throws BuildException {
+
+        if (null == m_targetDirectory) {
+            throw new BuildException("TargetDirectory attribute not set.");
+        }
+
+        if (null == m_skinDirectory) {
+            throw new BuildException("SkinDirectory attribute not set.");
+        }
+
+        if (null == m_book) {
+            throw new BuildException("book attribute not set.");
+        }
+
+        createArg().setValue("targetDirectory=" + m_targetDirectory);
+        createArg().setValue(m_book.toString());
+        createArg().setValue(m_skinDirectory.toString());
+        if (null != m_loaderConfig) {
+            createArg().setValue("loaderConfig=" + m_loaderConfig);
+        }
+
+        super.execute();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
new file mode 100644
index 0000000..547d578
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
@@ -0,0 +1,569 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.net.URL;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.TransformerConfigurationException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.XSLTLiaison3;
+import org.apache.tools.ant.taskdefs.XSLTLogger;
+import org.apache.tools.ant.taskdefs.XSLTLoggerAware;
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * Concrete liaison for XSLT processor implementing TraX. (ie JAXP 1.1)
+ *
+ * @since Ant 1.3
+ */
+public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware {
+
+    /**
+     * Helper for transforming filenames to URIs.
+     *
+     * @since Ant 1.7
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * The current <code>Project</code>
+     */
+    private Project project;
+
+    /**
+     * the name of the factory implementation class to use
+     * or null for default JAXP lookup.
+     */
+    private String factoryName = null;
+
+    /** The trax TransformerFactory */
+    private TransformerFactory tfactory = null;
+
+    /** stylesheet to use for transformation */
+    private Resource stylesheet;
+
+    private XSLTLogger logger;
+
+    /** possible resolver for publicIds */
+    private EntityResolver entityResolver;
+
+    /** transformer to use for processing files */
+    private Transformer transformer;
+
+    /** The In memory version of the stylesheet */
+    private Templates templates;
+
+    /**
+     * The modification time of the stylesheet from which the templates
+     * are read
+     */
+    private long templatesModTime;
+
+    /** possible resolver for URIs */
+    private URIResolver uriResolver;
+
+    /** transformer output properties */
+    private Vector outputProperties = new Vector();
+
+    /** stylesheet parameters */
+    private Hashtable params = new Hashtable();
+
+    /** factory attributes */
+    private Vector attributes = new Vector();
+
+    /**
+     * Constructor for TraXLiaison.
+     * @throws Exception never
+     */
+    public TraXLiaison() throws Exception {
+    }
+
+    /**
+     * Set the stylesheet file.
+     * @param stylesheet a <code>File</code> value
+     * @throws Exception on error
+     */
+    public void setStylesheet(File stylesheet) throws Exception {
+        FileResource fr = new FileResource();
+        fr.setProject(project);
+        fr.setFile(stylesheet);
+        setStylesheet(fr);
+    }
+
+    /**
+     * Set the stylesheet file.
+     * @param stylesheet a {@link org.apache.tools.ant.types.Resource} value
+     * @throws Exception on error
+     */
+    public void setStylesheet(Resource stylesheet) throws Exception {
+        if (this.stylesheet != null) {
+            // resetting the stylesheet - reset transformer
+            transformer = null;
+
+            // do we need to reset templates as well
+            if (!this.stylesheet.equals(stylesheet)
+                || (stylesheet.getLastModified() != templatesModTime)) {
+                templates = null;
+            }
+        }
+        this.stylesheet = stylesheet;
+    }
+
+    /**
+     * Transform an input file.
+     * @param infile the file to transform
+     * @param outfile the result file
+     * @throws Exception on error
+     */
+    public void transform(File infile, File outfile) throws Exception {
+        if (transformer == null) {
+            createTransformer();
+        }
+
+        InputStream fis = null;
+        OutputStream fos = null;
+        try {
+            fis = new BufferedInputStream(new FileInputStream(infile));
+            fos = new BufferedOutputStream(new FileOutputStream(outfile));
+            StreamResult res = new StreamResult(fos);
+            // not sure what could be the need of this...
+            res.setSystemId(JAXPUtils.getSystemId(outfile));
+            Source src = getSource(fis, infile);
+
+            // set parameters on each transformation, maybe something has changed
+            //(e.g. value of file name parameter)
+            setTransformationParameters();
+
+            transformer.transform(src, res);
+        } finally {
+            // make sure to close all handles, otherwise the garbage
+            // collector will close them...whenever possible and
+            // Windows may complain about not being able to delete files.
+            try {
+                if (fis != null) {
+                    fis.close();
+                }
+            } catch (IOException ignored) {
+                // ignore
+            }
+            try {
+                if (fos != null) {
+                    fos.close();
+                }
+            } catch (IOException ignored) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Get the source instance from the stream and id of the file.
+     * @param is the stream containing the stylesheet data.
+     * @param infile the file that will be used for the systemid.
+     * @return the configured source instance matching the stylesheet.
+     * @throws ParserConfigurationException if a parser cannot be created which
+     * satisfies the requested configuration.
+     * @throws SAXException in case of problem detected by the SAX parser.
+     */
+    private Source getSource(InputStream is, File infile)
+        throws ParserConfigurationException, SAXException {
+        // todo: is this comment still relevant ??
+        // FIXME: need to use a SAXSource as the source for the transform
+        // so we can plug in our own entity resolver
+        Source src = null;
+        if (entityResolver != null) {
+            if (getFactory().getFeature(SAXSource.FEATURE)) {
+                SAXParserFactory spFactory = SAXParserFactory.newInstance();
+                spFactory.setNamespaceAware(true);
+                XMLReader reader = spFactory.newSAXParser().getXMLReader();
+                reader.setEntityResolver(entityResolver);
+                src = new SAXSource(reader, new InputSource(is));
+            } else {
+                throw new IllegalStateException("xcatalog specified, but "
+                    + "parser doesn't support SAX");
+            }
+        } else {
+            // WARN: Don't use the StreamSource(File) ctor. It won't work with
+            // xalan prior to 2.2 because of systemid bugs.
+            src = new StreamSource(is);
+        }
+        src.setSystemId(JAXPUtils.getSystemId(infile));
+        return src;
+    }
+
+    private Source getSource(InputStream is, Resource resource)
+        throws ParserConfigurationException, SAXException {
+        // todo: is this comment still relevant ??
+        // FIXME: need to use a SAXSource as the source for the transform
+        // so we can plug in our own entity resolver
+        Source src = null;
+        if (entityResolver != null) {
+            if (getFactory().getFeature(SAXSource.FEATURE)) {
+                SAXParserFactory spFactory = SAXParserFactory.newInstance();
+                spFactory.setNamespaceAware(true);
+                XMLReader reader = spFactory.newSAXParser().getXMLReader();
+                reader.setEntityResolver(entityResolver);
+                src = new SAXSource(reader, new InputSource(is));
+            } else {
+                throw new IllegalStateException("xcatalog specified, but "
+                    + "parser doesn't support SAX");
+            }
+        } else {
+            // WARN: Don't use the StreamSource(File) ctor. It won't work with
+            // xalan prior to 2.2 because of systemid bugs.
+            src = new StreamSource(is);
+        }
+        // The line below is a hack: the system id must an URI, but it is not
+        // cleat to get the URI of an resource, so just set the name of the
+        // resource as a system id
+        src.setSystemId(resourceToURI(resource));
+        return src;
+    }
+
+    private String resourceToURI(Resource resource) {
+        if (resource instanceof FileResource) {
+            File f = ((FileResource) resource).getFile();
+            return FILE_UTILS.toURI(f.getAbsolutePath());
+        }
+        if (resource instanceof URLResource) {
+            URL u = ((URLResource) resource).getURL();
+            return String.valueOf(u);
+        } else {
+            return resource.getName();
+        }
+    }
+
+    /**
+     * Read in templates from the stylesheet
+     */
+    private void readTemplates()
+        throws IOException, TransformerConfigurationException,
+               ParserConfigurationException, SAXException {
+
+        // Use a stream so that you can close it yourself quickly
+        // and avoid keeping the handle until the object is garbaged.
+        // (always keep control), otherwise you won't be able to delete
+        // the file quickly on windows.
+        InputStream xslStream = null;
+        try {
+            xslStream
+                = new BufferedInputStream(stylesheet.getInputStream());
+            templatesModTime = stylesheet.getLastModified();
+            Source src = getSource(xslStream, stylesheet);
+            templates = getFactory().newTemplates(src);
+        } finally {
+            if (xslStream != null) {
+                xslStream.close();
+            }
+        }
+    }
+
+    /**
+     * Create a new transformer based on the liaison settings
+     * @throws Exception thrown if there is an error during creation.
+     * @see #setStylesheet(java.io.File)
+     * @see #addParam(java.lang.String, java.lang.String)
+     * @see #setOutputProperty(java.lang.String, java.lang.String)
+     */
+    private void createTransformer() throws Exception {
+        if (templates == null) {
+            readTemplates();
+        }
+
+        transformer = templates.newTransformer();
+
+        // configure the transformer...
+        transformer.setErrorListener(this);
+        if (uriResolver != null) {
+            transformer.setURIResolver(uriResolver);
+        }
+        for (int i = 0; i < outputProperties.size(); i++) {
+            final String[] pair = (String[]) outputProperties.elementAt(i);
+            transformer.setOutputProperty(pair[0], pair[1]);
+        }
+    }
+
+    /**
+     * Sets the paramters for the transformer.
+     */
+    private void setTransformationParameters() {
+        for (final Enumeration enumeration = params.keys();
+             enumeration.hasMoreElements();) {
+            final String name = (String) enumeration.nextElement();
+            final String value = (String) params.get(name);
+            transformer.setParameter(name, value);
+        }
+    }
+
+    /**
+     * return the Transformer factory associated to this liaison.
+     * @return the Transformer factory associated to this liaison.
+     * @throws BuildException thrown if there is a problem creating
+     * the factory.
+     * @see #setFactory(String)
+     * @since Ant 1.5.2
+     */
+    private TransformerFactory getFactory() throws BuildException {
+        if (tfactory != null) {
+            return tfactory;
+        }
+        // not initialized yet, so create the factory
+        if (factoryName == null) {
+            tfactory = TransformerFactory.newInstance();
+        } else {
+            try {
+                Class clazz = Class.forName(factoryName);
+                tfactory = (TransformerFactory) clazz.newInstance();
+            } catch (Exception e) {
+                throw new BuildException(e);
+            }
+        }
+        tfactory.setErrorListener(this);
+
+        // specific attributes for the transformer
+        for (int i = 0; i < attributes.size(); i++) {
+            final Object[] pair = (Object[]) attributes.elementAt(i);
+            tfactory.setAttribute((String) pair[0], pair[1]);
+        }
+
+        if (uriResolver != null) {
+            tfactory.setURIResolver(uriResolver);
+        }
+        return tfactory;
+    }
+
+
+    /**
+     * Set the factory name to use instead of JAXP default lookup.
+     * @param name the fully qualified class name of the factory to use
+     * or null for the default JAXP look up mechanism.
+     * @since Ant 1.6
+     */
+    public void setFactory(String name) {
+        factoryName = name;
+    }
+
+    /**
+     * Set a custom attribute for the JAXP factory implementation.
+     * @param name the attribute name.
+     * @param value the value of the attribute, usually a boolean
+     * string or object.
+     * @since Ant 1.6
+     */
+    public void setAttribute(String name, Object value) {
+        final Object[] pair = new Object[]{name, value};
+        attributes.addElement(pair);
+    }
+
+    /**
+     * Set the output property for the current transformer.
+     * Note that the stylesheet must be set prior to calling
+     * this method.
+     * @param name the output property name.
+     * @param value the output property value.
+     * @since Ant 1.5
+     * @since Ant 1.5
+     */
+    public void setOutputProperty(String name, String value) {
+        final String[] pair = new String[]{name, value};
+        outputProperties.addElement(pair);
+    }
+
+    /**
+     * Set the class to resolve entities during the transformation.
+     * @param aResolver the resolver class.
+     */
+    public void setEntityResolver(EntityResolver aResolver) {
+        entityResolver = aResolver;
+    }
+
+    /**
+     * Set the class to resolve URIs during the transformation
+     * @param aResolver a <code>EntityResolver</code> value
+     */
+    public void setURIResolver(URIResolver aResolver) {
+        uriResolver = aResolver;
+    }
+
+    /**
+     * Add a parameter.
+     * @param name the name of the parameter
+     * @param value the value of the parameter
+     */
+    public void addParam(String name, String value) {
+        params.put(name, value);
+    }
+
+    /**
+     * Set a logger.
+     * @param l a logger.
+     */
+    public void setLogger(XSLTLogger l) {
+        logger = l;
+    }
+
+    /**
+     * Log an error.
+     * @param e the exception to log.
+     */
+    public void error(TransformerException e) {
+        logError(e, "Error");
+    }
+
+    /**
+     * Log a fatal error.
+     * @param e the exception to log.
+     */
+    public void fatalError(TransformerException e) {
+        logError(e, "Fatal Error");
+        throw new BuildException("Fatal error during transformation", e);
+    }
+
+    /**
+     * Log a warning.
+     * @param e the exception to log.
+     */
+    public void warning(TransformerException e) {
+        logError(e, "Warning");
+    }
+
+    private void logError(TransformerException e, String type) {
+        if (logger == null) {
+            return;
+        }
+
+        StringBuffer msg = new StringBuffer();
+        SourceLocator locator = e.getLocator();
+        if (locator != null) {
+            String systemid = locator.getSystemId();
+            if (systemid != null) {
+                String url = systemid;
+                if (url.startsWith("file:")) {
+                    url = FileUtils.getFileUtils().fromURI(url);
+                }
+                msg.append(url);
+            } else {
+                msg.append("Unknown file");
+            }
+            int line = locator.getLineNumber();
+            if (line != -1) {
+                msg.append(":");
+                msg.append(line);
+                int column = locator.getColumnNumber();
+                if (column != -1) {
+                    msg.append(":");
+                    msg.append(column);
+                }
+            }
+        }
+        msg.append(": ");
+        msg.append(type);
+        msg.append("! ");
+        msg.append(e.getMessage());
+        if (e.getCause() != null) {
+            msg.append(" Cause: ");
+            msg.append(e.getCause());
+        }
+
+        logger.log(msg.toString());
+    }
+
+    // kept for backwards compatibility
+    /**
+     * @param file the filename to use for the systemid
+     * @return the systemid
+     * @deprecated since 1.5.x.
+     *             Use org.apache.tools.ant.util.JAXPUtils#getSystemId instead.
+     */
+    protected String getSystemId(File file) {
+        return JAXPUtils.getSystemId(file);
+    }
+
+
+    /**
+     * Specific configuration for the TRaX liaison.
+     * @param xsltTask the XSLTProcess task instance from which this liasion
+     *        is to be configured.
+     */
+    public void configure(XSLTProcess xsltTask) {
+        project = xsltTask.getProject();
+        XSLTProcess.Factory factory = xsltTask.getFactory();
+        if (factory != null) {
+            setFactory(factory.getName());
+
+            // configure factory attributes
+            for (Enumeration attrs = factory.getAttributes();
+                    attrs.hasMoreElements();) {
+                XSLTProcess.Factory.Attribute attr =
+                        (XSLTProcess.Factory.Attribute) attrs.nextElement();
+                setAttribute(attr.getName(), attr.getValue());
+            }
+        }
+
+        XMLCatalog xmlCatalog = xsltTask.getXMLCatalog();
+        // use XMLCatalog as the entity resolver and URI resolver
+        if (xmlCatalog != null) {
+            setEntityResolver(xmlCatalog);
+            setURIResolver(xmlCatalog);
+        }
+
+
+        // configure output properties
+        for (Enumeration props = xsltTask.getOutputProperties();
+                props.hasMoreElements();) {
+            XSLTProcess.OutputProperty prop
+                = (XSLTProcess.OutputProperty) props.nextElement();
+            setOutputProperty(prop.getName(), prop.getValue());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
new file mode 100644
index 0000000..962ba75
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/XMLValidateTask.java
@@ -0,0 +1,745 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.DTDLocation;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.ant.util.XmlConstants;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.ParserAdapter;
+
+/**
+ * Checks XML files are valid (or only well formed). The
+ * task uses the SAX2 parser implementation provided by JAXP by default
+ * (probably the one that is used by Ant itself), but one can specify any
+ * SAX1/2 parser if needed.
+ *
+ */
+public class XMLValidateTask extends Task {
+
+    /**
+     * helper for path -> URI and URI -> path conversions.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    protected static final String INIT_FAILED_MSG =
+        "Could not start xml validation: ";
+
+    // ant task properties
+    // defaults
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean failOnError = true;
+    protected boolean warn = true;
+    protected boolean lenient = false;
+    protected String readerClassName = null;
+
+    /** file to be validated */
+    protected File file = null;
+    /** sets of file to be validated */
+    protected Vector filesets = new Vector();
+    protected Path classpath;
+
+    /**
+     * the parser is viewed as a SAX2 XMLReader. If a SAX1 parser is specified,
+     * it's wrapped in an adapter that make it behave as a XMLReader.
+     * a more 'standard' way of doing this would be to use the JAXP1.1 SAXParser
+     * interface.
+     */
+    protected XMLReader xmlReader = null;
+    // XMLReader used to validation process
+    protected ValidatorErrorHandler errorHandler = new ValidatorErrorHandler();
+    // to report sax parsing errors
+    // CheckStyle:VisibilityModifier ON
+
+    /** The vector to store all attributes (features) to be set on the parser. **/
+    private Vector attributeList = new Vector();
+
+    /**
+     * List of properties.
+     */
+    private final Vector propertyList = new Vector();
+
+    private XMLCatalog xmlCatalog = new XMLCatalog();
+    /** Message for sucessfull validation */
+    public static final String MESSAGE_FILES_VALIDATED
+        = " file(s) have been successfully validated.";
+
+    /**
+     * Specify how parser error are to be handled.
+     * Optional, default is <code>true</code>.
+     * <p>
+     * If set to <code>true</code> (default), throw a buildException if the
+     * parser yields an error.
+     * @param fail if set to <code>false</code> do not fail on error
+     */
+    public void setFailOnError(boolean fail) {
+        failOnError = fail;
+    }
+
+    /**
+     * Specify how parser error are to be handled.
+     * <p>
+     * If set to <code>true</true> (default), log a warn message for each SAX warn event.
+     * @param bool if set to <code>false</code> do not send warnings
+     */
+    public void setWarn(boolean bool) {
+        warn = bool;
+    }
+
+    /**
+     * Specify whether the parser should be validating. Default
+     * is <code>true</code>.
+     * <p>
+     * If set to false, the validation will fail only if the parsed document
+     * is not well formed XML.
+     * <p>
+     * this option is ignored if the specified class
+     * with {@link #setClassName(String)} is not a SAX2 XMLReader.
+     * @param bool if set to <code>false</code> only fail on malformed XML
+     */
+    public void setLenient(boolean bool) {
+        lenient = bool;
+    }
+
+    /**
+     * Specify the class name of the SAX parser to be used. (optional)
+     * @param className should be an implementation of SAX2
+     * <code>org.xml.sax.XMLReader</code> or SAX2 <code>org.xml.sax.Parser</code>.
+     * <p> if className is an implementation of
+     * <code>org.xml.sax.Parser</code>, {@link #setLenient(boolean)},
+     * will be ignored.
+     * <p> if not set, the default will be used.
+     * @see org.xml.sax.XMLReader
+     * @see org.xml.sax.Parser
+     */
+    public void setClassName(String className) {
+        readerClassName = className;
+    }
+
+    /**
+     * Specify the classpath to be searched to load the parser (optional)
+     * @param classpath the classpath to load the parser
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * @see #setClasspath
+     * @return the classpath created
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Where to find the parser class; optional.
+     * @see #setClasspath
+     * @param r reference to a classpath defined elsewhere
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * specify the file to be checked; optional.
+     * @param file the file to be checked
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * add an XMLCatalog as a nested element; optional.
+     * @param catalog XMLCatalog to use
+     */
+    public void addConfiguredXMLCatalog(XMLCatalog catalog) {
+        xmlCatalog.addConfiguredXMLCatalog(catalog);
+    }
+
+    /**
+     * specify a set of file to be checked
+     * @param set the fileset to check
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Add an attribute nested element. This is used for setting arbitrary
+     * features of the SAX parser.
+     * Valid attributes
+     * <a href=
+     * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+     * >include</a>
+     * @return attribute created
+     * @since ant1.6
+     */
+    public Attribute createAttribute() {
+        final Attribute feature = new Attribute();
+        attributeList.addElement(feature);
+        return feature;
+    }
+
+    /**
+     * Creates a property.
+     *
+     * @return a property.
+     * @since ant 1.6.2
+     */
+    public Property createProperty() {
+        final Property prop = new Property();
+        propertyList.addElement(prop);
+        return prop;
+    }
+
+    /**
+     * Called by the project to let the task initialize properly.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void init() throws BuildException {
+        super.init();
+        xmlCatalog.setProject(getProject());
+    }
+
+    /**
+     * Create a DTD location record; optional.
+     * This stores the location of a DTD. The DTD is identified
+     * by its public Id.
+     * @return created DTD location
+     */
+    public DTDLocation createDTD() {
+        DTDLocation dtdLocation = new DTDLocation();
+        xmlCatalog.addDTD(dtdLocation);
+        return dtdLocation;
+    }
+    /**
+     * accessor to the xmlCatalog used in the task
+     * @return xmlCatalog reference
+     */
+    protected EntityResolver getEntityResolver() {
+        return xmlCatalog;
+    }
+
+    /**
+     * get the XML reader. Non-null only after {@link #initValidator()}.
+     * If the reader is an instance of  {@link ParserAdapter} then
+     * the parser is a SAX1 parser, and you cannot call
+     * {@link #setFeature(String, boolean)} or {@link #setProperty(String, String)}
+     * on it.
+     * @return the XML reader or null.
+     */
+    protected XMLReader getXmlReader() {
+        return xmlReader;
+    }
+
+    /**
+     * execute the task
+     * @throws BuildException if <code>failonerror</code> is true and an error happens
+     */
+    public void execute() throws BuildException {
+
+        int fileProcessed = 0;
+        if (file == null && (filesets.size() == 0)) {
+            throw new BuildException(
+                "Specify at least one source - " + "a file or a fileset.");
+        }
+
+
+
+        if (file != null) {
+            if (file.exists() && file.canRead() && file.isFile()) {
+                doValidate(file);
+                fileProcessed++;
+            } else {
+                String errorMsg = "File " + file + " cannot be read";
+                if (failOnError) {
+                    throw new BuildException(errorMsg);
+                } else {
+                    log(errorMsg, Project.MSG_ERR);
+                }
+            }
+        }
+
+        for (int i = 0; i < filesets.size(); i++) {
+
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            String[] files = ds.getIncludedFiles();
+
+            for (int j = 0; j < files.length; j++) {
+                File srcFile = new File(fs.getDir(getProject()), files[j]);
+                doValidate(srcFile);
+                fileProcessed++;
+            }
+        }
+        onSuccessfulValidation(fileProcessed);
+    }
+
+    /**
+     * handler called on successful file validation.
+     * @param fileProcessed number of files processed.
+     */
+    protected void onSuccessfulValidation(int fileProcessed) {
+        log(fileProcessed + MESSAGE_FILES_VALIDATED);
+    }
+
+    /**
+     * init the parser :
+     * load the parser class, and set features if necessary
+     * It is only after this that the reader is valid
+     * @throws BuildException if something went wrong
+     */
+    protected void initValidator() {
+
+        xmlReader = createXmlReader();
+
+        xmlReader.setEntityResolver(getEntityResolver());
+        xmlReader.setErrorHandler(errorHandler);
+
+        if (!isSax1Parser()) {
+            // turn validation on
+            if (!lenient) {
+                setFeature(XmlConstants.FEATURE_VALIDATION, true);
+            }
+            // set the feature from the attribute list
+            for (int i = 0; i < attributeList.size(); i++) {
+                Attribute feature = (Attribute) attributeList.elementAt(i);
+                setFeature(feature.getName(), feature.getValue());
+
+            }
+            // Sets properties
+            for (int i = 0; i < propertyList.size(); i++) {
+                final Property prop = (Property) propertyList.elementAt(i);
+                setProperty(prop.getName(), prop.getValue());
+            }
+        }
+    }
+
+    /**
+     * test that returns true if we are using a SAX1 parser.
+     * @return true when a SAX1 parser is in use
+     */
+    protected boolean isSax1Parser() {
+        return (xmlReader instanceof ParserAdapter);
+    }
+
+    /**
+     * create the XML reader.
+     * This is one by instantiating anything specified by {@link #readerClassName},
+     * falling back to a default reader if not.
+     * If the returned reader is an instance of {@link ParserAdapter} then
+     * we have created and wrapped a SAX1 parser.
+     * @return the new XMLReader.
+     */
+    protected XMLReader createXmlReader() {
+        Object reader = null;
+        if (readerClassName == null) {
+            reader = createDefaultReaderOrParser();
+        } else {
+
+            Class readerClass = null;
+            try {
+                // load the parser class
+                if (classpath != null) {
+                    AntClassLoader loader =
+                        getProject().createClassLoader(classpath);
+                    readerClass = Class.forName(readerClassName, true, loader);
+                } else {
+                    readerClass = Class.forName(readerClassName);
+                }
+
+                reader = readerClass.newInstance();
+            } catch (ClassNotFoundException e) {
+                throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+            } catch (InstantiationException e) {
+                throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+            } catch (IllegalAccessException e) {
+                throw new BuildException(INIT_FAILED_MSG + readerClassName, e);
+            }
+        }
+
+        // then check it implements XMLReader
+        XMLReader newReader;
+        if (reader instanceof XMLReader) {
+            newReader = (XMLReader) reader;
+            log(
+                "Using SAX2 reader " + reader.getClass().getName(),
+                Project.MSG_VERBOSE);
+        } else {
+
+            // see if it is a SAX1 Parser
+            if (reader instanceof Parser) {
+                newReader = new ParserAdapter((Parser) reader);
+                log(
+                    "Using SAX1 parser " + reader.getClass().getName(),
+                    Project.MSG_VERBOSE);
+            } else {
+                throw new BuildException(
+                    INIT_FAILED_MSG
+                        + reader.getClass().getName()
+                        + " implements nor SAX1 Parser nor SAX2 XMLReader.");
+            }
+        }
+        return newReader;
+    }
+
+    /**
+     *
+     * @return
+     */
+    private Object createDefaultReaderOrParser() {
+        Object reader;
+        try {
+            reader = createDefaultReader();
+        } catch (BuildException exc) {
+            reader = JAXPUtils.getParser();
+        }
+        return reader;
+    }
+
+    /**
+     * create a reader if the use of the class did not specify another one.
+     * If a BuildException is thrown, the caller may revert to an alternate
+     * reader.
+     * @return a new reader.
+     * @throws BuildException if something went wrong
+     */
+    protected XMLReader createDefaultReader() {
+        return JAXPUtils.getXMLReader();
+    }
+
+    /**
+     * Set a feature on the parser.
+     * @param feature the name of the feature to set
+     * @param value the value of the feature
+     * @throws BuildException if the feature was not supported
+     */
+    protected void setFeature(String feature, boolean value)
+        throws BuildException {
+        log("Setting feature " + feature + "=" + value, Project.MSG_DEBUG);
+        try {
+            xmlReader.setFeature(feature, value);
+        } catch (SAXNotRecognizedException e) {
+            throw new BuildException(
+                "Parser "
+                    + xmlReader.getClass().getName()
+                    + " doesn't recognize feature "
+                    + feature,
+                e,
+                getLocation());
+        } catch (SAXNotSupportedException e) {
+            throw new BuildException(
+                "Parser "
+                    + xmlReader.getClass().getName()
+                    + " doesn't support feature "
+                    + feature,
+                e,
+                getLocation());
+        }
+    }
+
+    /**
+     * Sets a property.
+     *
+     * @param name a property name
+     * @param value a property value.
+     * @throws BuildException if an error occurs.
+     * @throws BuildException if the property was not supported
+     */
+    protected void setProperty(String name, String value) throws BuildException {
+        // Validates property
+        if (name == null || value == null) {
+            throw new BuildException("Property name and value must be specified.");
+        }
+
+        try {
+            xmlReader.setProperty(name, value);
+        } catch (SAXNotRecognizedException e) {
+            throw new BuildException(
+                "Parser "
+                    + xmlReader.getClass().getName()
+                    + " doesn't recognize property "
+                    + name,
+                e,
+                getLocation());
+        } catch (SAXNotSupportedException e) {
+            throw new BuildException(
+                "Parser "
+                    + xmlReader.getClass().getName()
+                    + " doesn't support property "
+                    + name,
+                e,
+                getLocation());
+        }
+    }
+
+    /**
+     * parse the file
+     * @param afile the file to validate.
+     * @return true if the file validates.
+     */
+    protected boolean doValidate(File afile) {
+        //for every file, we have a new instance of the validator
+        initValidator();
+        boolean result = true;
+        try {
+            log("Validating " + afile.getName() + "... ", Project.MSG_VERBOSE);
+            errorHandler.init(afile);
+            InputSource is = new InputSource(new FileInputStream(afile));
+            String uri = FILE_UTILS.toURI(afile.getAbsolutePath());
+            is.setSystemId(uri);
+            xmlReader.parse(is);
+        } catch (SAXException ex) {
+            log("Caught when validating: " + ex.toString(), Project.MSG_DEBUG);
+            if (failOnError) {
+                throw new BuildException(
+                    "Could not validate document " + afile);
+            }
+            log("Could not validate document " + afile + ": " + ex.toString());
+            result = false;
+        } catch (IOException ex) {
+            throw new BuildException(
+                "Could not validate document " + afile,
+                ex);
+        }
+        if (errorHandler.getFailure()) {
+            if (failOnError) {
+                throw new BuildException(
+                    afile + " is not a valid XML document.");
+            }
+            result = false;
+            log(afile + " is not a valid XML document", Project.MSG_ERR);
+        }
+        return result;
+    }
+
+    /**
+     * ValidatorErrorHandler role :
+     * <ul>
+     * <li> log SAX parse exceptions,
+     * <li> remember if an error occurred
+     * </ul>
+     */
+    protected class ValidatorErrorHandler implements ErrorHandler {
+
+        // CheckStyle:VisibilityModifier OFF - bc
+        protected File currentFile = null;
+        protected String lastErrorMessage = null;
+        protected boolean failed = false;
+        // CheckStyle:VisibilityModifier ON
+        /**
+         * initialises the class
+         * @param file file used
+         */
+        public void init(File file) {
+            currentFile = file;
+            failed = false;
+        }
+        /**
+         * did an error happen during last parsing ?
+         * @return did an error happen during last parsing ?
+         */
+        public boolean getFailure() {
+            return failed;
+        }
+
+        /**
+         * record a fatal error
+         * @param exception the fatal error
+         */
+        public void fatalError(SAXParseException exception) {
+            failed = true;
+            doLog(exception, Project.MSG_ERR);
+        }
+        /**
+         * receive notification of a recoverable error
+         * @param exception the error
+         */
+        public void error(SAXParseException exception) {
+            failed = true;
+            doLog(exception, Project.MSG_ERR);
+        }
+        /**
+         * receive notification of a warning
+         * @param exception the warning
+         */
+        public void warning(SAXParseException exception) {
+            // depending on implementation, XMLReader can yield hips of warning,
+            // only output then if user explicitly asked for it
+            if (warn) {
+                doLog(exception, Project.MSG_WARN);
+            }
+        }
+
+        private void doLog(SAXParseException e, int logLevel) {
+
+            log(getMessage(e), logLevel);
+        }
+
+        private String getMessage(SAXParseException e) {
+            String sysID = e.getSystemId();
+            if (sysID != null) {
+                String name = sysID;
+                if (sysID.startsWith("file:")) {
+                    try {
+                        name = FILE_UTILS.fromURI(sysID);
+                    } catch (Exception ex) {
+                        // if this is not a valid file: just use the uri
+                    }
+                }
+                int line = e.getLineNumber();
+                int col = e.getColumnNumber();
+                return  name
+                    + (line == -1
+                       ? ""
+                       : (":" + line + (col == -1 ? "" : (":" + col))))
+                    + ": "
+                    + e.getMessage();
+            }
+            return e.getMessage();
+        }
+    }
+
+    /**
+     * The class to create to set a feature of the parser.
+     * @since ant1.6
+     */
+    public static class Attribute {
+        /** The name of the attribute to set.
+         *
+         * Valid attributes <a href=
+         * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+         * >include.</a>
+         */
+        private String attributeName = null;
+
+        /**
+         * The value of the feature.
+         **/
+        private boolean attributeValue;
+
+        /**
+         * Set the feature name.
+         * @param name the name to set
+         */
+        public void setName(String name) {
+            attributeName = name;
+        }
+        /**
+         * Set the feature value to true or false.
+         * @param value feature value
+         */
+        public void setValue(boolean value) {
+            attributeValue = value;
+        }
+
+        /**
+         * Gets the attribute name.
+         * @return the feature name
+         */
+        public String getName() {
+            return attributeName;
+        }
+
+        /**
+         * Gets the attribute value.
+         * @return the feature value
+         */
+        public boolean getValue() {
+            return attributeValue;
+        }
+    }
+
+    /**
+     * A Parser property.
+     * See <a href="http://xml.apache.org/xerces-j/properties.html">
+     * XML parser properties</a> for usable properties
+     * @since ant 1.6.2
+     */
+    public static final class Property {
+
+        private String name;
+        private String value;
+        /**
+         * accessor to the name of the property
+         * @return name of the property
+         */
+        public String getName() {
+            return name;
+        }
+        /**
+         * setter for the name of the property
+         * @param name name of the property
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * getter for the value of the property
+         * @return value of the property
+         */
+        public String getValue() {
+            return value;
+        }
+        /**
+         * sets the value of the property
+         * @param value value of the property
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+    } // Property
+
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java
new file mode 100644
index 0000000..a279835
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheck.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import java.io.File;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+
+
+/**
+ * Class common to all check commands (checkout, checkin,checkin default task);
+ * @ant.task ignore="true"
+ */
+public class CCMCheck extends Continuus {
+
+    private File file = null;
+    private String comment = null;
+    private String task = null;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    protected Vector filesets = new Vector();
+
+    // CheckStyle:VisibilityModifier ON
+
+    /** Constructor for CCMCheck. */
+    public CCMCheck() {
+        super();
+    }
+
+    /**
+     * Get the value of file.
+     * @return value of file.
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * Sets the path to the file that the command will operate on.
+     * @param v  Value to assign to file.
+     */
+    public void setFile(File v) {
+        log("working file " + v, Project.MSG_VERBOSE);
+        this.file = v;
+    }
+
+    /**
+     * Get the value of comment.
+     * @return value of comment.
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Specifies a comment.
+     * @param v  Value to assign to comment.
+     */
+    public void setComment(String v) {
+        this.comment = v;
+    }
+
+
+    /**
+     * Get the value of task.
+     * @return value of task.
+     */
+    public String getTask() {
+        return task;
+    }
+
+    /**
+     * Specifies the task number used to check
+     * in the file (may use 'default').
+     * @param v  Value to assign to task.
+     */
+    public void setTask(String v) {
+        this.task = v;
+    }
+
+
+    /**
+     * Adds a set of files to copy.
+     * @param set the set of files
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute ccm and then calls Exec's run method
+     * to execute the command line.
+     * </p>
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+
+        if (file == null && filesets.size() == 0) {
+            throw new BuildException(
+                "Specify at least one source - a file or a fileset.");
+        }
+
+        if (file != null && file.exists() && file.isDirectory()) {
+            throw new BuildException("CCMCheck cannot be generated for directories");
+        }
+
+        if (file != null  && filesets.size() > 0) {
+            throw new BuildException("Choose between file and fileset !");
+        }
+
+        if (getFile() != null) {
+            doit();
+            return;
+        }
+
+        int sizeofFileSet = filesets.size();
+        for (int i = 0; i < sizeofFileSet; i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            String[] srcFiles = ds.getIncludedFiles();
+            for (int j = 0; j < srcFiles.length; j++) {
+                File src = new File(fs.getDir(getProject()), srcFiles[j]);
+                setFile(src);
+                doit();
+            }
+        }
+    }
+
+    /**
+     * check the file given by getFile().
+     */
+    private void doit() {
+        Commandline commandLine = new Commandline();
+
+        // build the command line from what we got the format is
+        // ccm co /t .. files
+        // as specified in the CCM.EXE help
+
+        commandLine.setExecutable(getCcmCommand());
+        commandLine.createArgument().setValue(getCcmAction());
+
+        checkOptions(commandLine);
+
+        int result = run(commandLine);
+        if (Execute.isFailure(result)) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+
+        if (getTask() != null) {
+            cmd.createArgument().setValue(FLAG_TASK);
+            cmd.createArgument().setValue(getTask());
+        }
+
+        if (getFile() != null) {
+            cmd.createArgument().setValue(file.getAbsolutePath());
+        }
+    }
+
+    /**
+     * -comment flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "/comment";
+
+    /**
+     *  -task flag -- associate checkout task with task
+     */
+    public static final String FLAG_TASK = "/task";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java
new file mode 100644
index 0000000..ff7472c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckin.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+import java.util.Date;
+
+/**
+ * Performs Continuus checkin command.
+ *
+ */
+public class CCMCheckin extends CCMCheck {
+
+    /**
+     * Default constructor - setup checkin command
+     */
+    public CCMCheckin() {
+        super();
+        setCcmAction(COMMAND_CHECKIN);
+        setComment("Checkin " + new Date());
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java
new file mode 100644
index 0000000..2fe2a2a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckinDefault.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+/**
+ * Performs Continuus Checkin Default task command.
+ *
+ * @ant.task name="ccmcheckintask" category="scm"
+ */
+public class CCMCheckinDefault extends CCMCheck {
+
+    /** Constructor for CCMCheckinDefault. */
+    public CCMCheckinDefault() {
+        super();
+        setCcmAction(COMMAND_CHECKIN);
+        setTask(DEFAULT_TASK);
+    }
+
+    /** The default task */
+    public static final String DEFAULT_TASK = "default";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java
new file mode 100644
index 0000000..44bbc6b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCheckout.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+/**
+ * Performs Continuus checkout command.
+ *
+ */
+public class CCMCheckout extends CCMCheck {
+
+    /**
+     * default constructor
+     */
+    public CCMCheckout() {
+        super();
+        setCcmAction(COMMAND_CHECKOUT);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java
new file mode 100644
index 0000000..518bfdb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMCreateTask.java
@@ -0,0 +1,334 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Creates new Continuus ccm task and sets it as the default.
+ *
+ * @ant.task name="ccmcreatetask" category="scm"
+ */
+public class CCMCreateTask extends Continuus implements ExecuteStreamHandler {
+
+    private String comment = null;
+    private String platform = null;
+    private String resolver = null;
+    private String release = null;
+    private String subSystem = null;
+    private String task = null;
+
+    /**
+     * Constructor for CCMCreateTask.
+     */
+    public CCMCreateTask() {
+        super();
+        setCcmAction(COMMAND_CREATE_TASK);
+    }
+
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute ccm and then calls Exec's run method
+     * to execute the command line.
+     * </p>
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        int result = 0;
+
+        // build the command line from what we got the format
+        // as specified in the CCM.EXE help
+        commandLine.setExecutable(getCcmCommand());
+        commandLine.createArgument().setValue(getCcmAction());
+
+        checkOptions(commandLine);
+
+        result = run(commandLine, this);
+        if (Execute.isFailure(result)) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+
+        //create task ok, set this task as the default one
+        Commandline commandLine2 = new Commandline();
+        commandLine2.setExecutable(getCcmCommand());
+        commandLine2.createArgument().setValue(COMMAND_DEFAULT_TASK);
+        commandLine2.createArgument().setValue(getTask());
+
+        log(commandLine.describeCommand(), Project.MSG_DEBUG);
+
+        result = run(commandLine2);
+        if (result != 0) {
+            String msg = "Failed executing: " + commandLine2.toString();
+            throw new BuildException(msg, getLocation());
+        }
+
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue("\"" + getComment() + "\"");
+        }
+
+        if (getPlatform() != null) {
+            cmd.createArgument().setValue(FLAG_PLATFORM);
+            cmd.createArgument().setValue(getPlatform());
+        } // end of if ()
+
+        if (getResolver() != null) {
+            cmd.createArgument().setValue(FLAG_RESOLVER);
+            cmd.createArgument().setValue(getResolver());
+        } // end of if ()
+
+        if (getSubSystem() != null) {
+            cmd.createArgument().setValue(FLAG_SUBSYSTEM);
+            cmd.createArgument().setValue("\"" + getSubSystem() + "\"");
+        } // end of if ()
+
+        if (getRelease() != null) {
+            cmd.createArgument().setValue(FLAG_RELEASE);
+            cmd.createArgument().setValue(getRelease());
+        } // end of if ()
+    }
+
+
+    /**
+     * Get the value of comment.
+     * @return value of comment.
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Specifies a comment.
+     *
+     * @param v  Value to assign to comment.
+     */
+    public void setComment(String v) {
+        this.comment = v;
+    }
+
+
+    /**
+     * Get the value of platform.
+     * @return value of platform.
+     */
+    public String getPlatform() {
+        return platform;
+    }
+
+    /**
+     * Specifies the target platform.
+     *
+     * @param v  Value to assign to platform.
+     */
+    public void setPlatform(String v) {
+        this.platform = v;
+    }
+
+
+    /**
+     * Get the value of resolver.
+     * @return value of resolver.
+     */
+    public String getResolver() {
+        return resolver;
+    }
+
+    /**
+     * Specifies the resolver.
+     *
+     * @param v  Value to assign to resolver.
+     */
+    public void setResolver(String v) {
+        this.resolver = v;
+    }
+
+
+    /**
+     * Get the value of release.
+     * @return value of release.
+     */
+    public String getRelease() {
+        return release;
+    }
+
+    /**
+     * Specify the CCM release.
+     *
+     * @param v  Value to assign to release.
+     */
+    public void setRelease(String v) {
+        this.release = v;
+    }
+
+    /**
+     * Get the value of subSystem.
+     * @return value of subSystem.
+     */
+    public String getSubSystem() {
+        return subSystem;
+    }
+
+    /**
+     * Specifies the subsystem.
+     *
+     * @param v  Value to assign to subSystem.
+     */
+    public void setSubSystem(String v) {
+        this.subSystem = v;
+    }
+
+
+    /**
+     * Get the value of task.
+     * @return value of task.
+     */
+    public String getTask() {
+        return task;
+    }
+
+    /**
+     * Specifies the task number used to checkin
+     * the file (may use 'default').
+     *
+     * @param v  Value to assign to task.
+     */
+    public void setTask(String v) {
+        this.task = v;
+    }
+
+    /**
+     * /comment -- comments associated to the task
+     */
+    public static final String FLAG_COMMENT = "/synopsis";
+
+    /**
+     *  /platform flag -- target platform
+     */
+    public static final String FLAG_PLATFORM = "/plat";
+
+    /**
+     * /resolver flag
+     */
+    public static final String FLAG_RESOLVER = "/resolver";
+
+    /**
+     * /release flag
+     */
+    public static final String FLAG_RELEASE = "/release";
+
+    /**
+     * /release flag
+     */
+    public static final String FLAG_SUBSYSTEM = "/subsystem";
+
+    /**
+     *  -task flag -- associate checkout task with task
+     */
+    public static final String FLAG_TASK = "/task";
+
+
+    // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
+
+    /**
+     *
+     * @throws IOException on error
+     */
+    public void start() throws IOException {
+    }
+
+    /**
+     *
+     */
+    public void stop() {
+    }
+
+    /**
+     *
+     * @param param1 the output stream
+     * @exception java.io.IOException on error
+     */
+    public void setProcessInputStream(OutputStream param1) throws IOException {
+    }
+
+    /**
+     *
+     * @param is the input stream
+     * @exception java.io.IOException on error
+     */
+    public void setProcessErrorStream(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        String s = reader.readLine();
+        if (s != null) {
+            log("err " + s, Project.MSG_DEBUG);
+        } // end of if ()
+    }
+
+    /**
+     * read the output stream to retrieve the new task number.
+     * @param is InputStream
+     * @throws IOException on error
+     */
+    public void setProcessOutputStream(InputStream is) throws IOException {
+
+        String buffer = "";
+        try {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+            buffer = reader.readLine();
+            if (buffer != null) {
+                log("buffer:" + buffer, Project.MSG_DEBUG);
+                String taskstring = buffer.substring(buffer.indexOf(' ')).trim();
+                taskstring = taskstring.substring(0, taskstring.lastIndexOf(' ')).trim();
+                setTask(taskstring);
+                log("task is " + getTask(), Project.MSG_DEBUG);
+            } // end of if ()
+        } catch (NullPointerException npe) {
+            log("error procession stream , null pointer exception", Project.MSG_ERR);
+            npe.printStackTrace();
+            throw new BuildException(npe.getClass().getName());
+        } catch (Exception e) {
+            log("error procession stream " + e.getMessage(), Project.MSG_ERR);
+            throw new BuildException(e.getMessage());
+        } // end of try-catch
+
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java
new file mode 100644
index 0000000..28f8064
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/CCMReconfigure.java
@@ -0,0 +1,159 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Task allows to reconfigure a project, recursively or not
+ */
+public class CCMReconfigure extends Continuus {
+
+    private String ccmProject = null;
+    private boolean recurse = false;
+    private boolean verbose = false;
+
+    /** Constructor for CCMReconfigure. */
+    public CCMReconfigure() {
+        super();
+        setCcmAction(COMMAND_RECONFIGURE);
+    }
+
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute ccm and then calls Exec's run method
+     * to execute the command line.
+     * </p>
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        int result = 0;
+
+        // build the command line from what we got the format
+        // as specified in the CCM.EXE help
+        commandLine.setExecutable(getCcmCommand());
+        commandLine.createArgument().setValue(getCcmAction());
+
+        checkOptions(commandLine);
+
+        result = run(commandLine);
+        if (Execute.isFailure(result)) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+
+        if (isRecurse()) {
+            cmd.createArgument().setValue(FLAG_RECURSE);
+        } // end of if ()
+
+        if (isVerbose()) {
+            cmd.createArgument().setValue(FLAG_VERBOSE);
+        } // end of if ()
+
+        if (getCcmProject() != null) {
+            cmd.createArgument().setValue(FLAG_PROJECT);
+            cmd.createArgument().setValue(getCcmProject());
+        }
+
+    }
+
+    /**
+     * Get the value of project.
+     * @return value of project.
+     */
+    public String getCcmProject() {
+        return ccmProject;
+    }
+
+    /**
+     * Sets the ccm project on which the operation is applied.
+     * @param v  Value to assign to project.
+     */
+    public void setCcmProject(String v) {
+        this.ccmProject = v;
+    }
+
+
+    /**
+     * Get the value of recurse.
+     * @return value of recurse.
+     */
+    public boolean isRecurse() {
+        return recurse;
+    }
+
+    /**
+     * If true, recurse on subproject (default false).
+     *
+     * @param v  Value to assign to recurse.
+     */
+    public void setRecurse(boolean v) {
+        this.recurse = v;
+    }
+
+
+    /**
+     * Get the value of verbose.
+     * @return value of verbose.
+     */
+    public boolean isVerbose() {
+        return verbose;
+    }
+
+    /**
+     * If true, do a verbose reconfigure operation (default false).
+     * @param v  Value to assign to verbose.
+     */
+    public void setVerbose(boolean v) {
+        this.verbose = v;
+    }
+
+
+    /**
+     * /recurse --
+     */
+    public static final String FLAG_RECURSE = "/recurse";
+
+    /**
+     * /recurse --
+     */
+    public static final String FLAG_VERBOSE = "/verbose";
+
+
+    /**
+     *  /project flag -- target project
+     */
+    public static final String FLAG_PROJECT = "/project";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java
new file mode 100644
index 0000000..5618dd6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ccm/Continuus.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ccm;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * A base class for creating tasks for executing commands on Continuus 5.1.
+ * <p>
+ * The class extends the  task as it operates by executing the ccm.exe program
+ * supplied with Continuus/Synergy. By default the task expects the ccm executable to be
+ * in the path,
+ * you can override this be specifying the ccmdir attribute.
+ * </p>
+ *
+ */
+public abstract class Continuus extends Task {
+
+    private String ccmDir = "";
+    private String ccmAction = "";
+
+    /**
+     * Get the value of ccmAction.
+     * @return value of ccmAction.
+     */
+    public String getCcmAction() {
+        return ccmAction;
+    }
+
+    /**
+     * Set the value of ccmAction.
+     * @param v  Value to assign to ccmAction.
+     * @ant.attribute ignore="true"
+     */
+    public void setCcmAction(String v) {
+        this.ccmAction = v;
+    }
+
+
+    /**
+     * Set the directory where the ccm executable is located.
+     *
+     * @param dir the directory containing the ccm executable
+     */
+    public final void setCcmDir(String dir) {
+        ccmDir = FileUtils.translatePath(dir);
+    }
+
+    /**
+     * Builds and returns the command string to execute ccm
+     * @return String containing path to the executable
+     */
+    protected final String getCcmCommand() {
+        String toReturn = ccmDir;
+        if (!toReturn.equals("") && !toReturn.endsWith("/")) {
+            toReturn += "/";
+        }
+
+        toReturn += CCM_EXE;
+
+        return toReturn;
+    }
+
+
+    /**
+     * Run the command.
+     * @param cmd the command line
+     * @param handler an execute stream handler
+     * @return the exit status of the command
+     */
+    protected int run(Commandline cmd, ExecuteStreamHandler handler) {
+        try {
+            Execute exe = new Execute(handler);
+            exe.setAntRun(getProject());
+            exe.setWorkingDirectory(getProject().getBaseDir());
+            exe.setCommandline(cmd.getCommandline());
+            return exe.execute();
+        } catch (java.io.IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+    /**
+     * Run the command.
+     * @param cmd the command line
+     * @return the exit status of the command
+     */
+    protected int run(Commandline cmd) {
+        return run(cmd, new LogStreamHandler(this, Project.MSG_VERBOSE, Project.MSG_WARN));
+    }
+
+    /**
+     * Constant for the thing to execute
+     */
+    private static final String CCM_EXE = "ccm";
+
+    /**
+     * The 'CreateTask' command
+     */
+    public static final String COMMAND_CREATE_TASK = "create_task";
+    /**
+     * The 'Checkout' command
+     */
+    public static final String COMMAND_CHECKOUT = "co";
+    /**
+     * The 'Checkin' command
+     */
+    public static final String COMMAND_CHECKIN = "ci";
+    /**
+     * The 'Reconfigure' command
+     */
+    public static final String COMMAND_RECONFIGURE = "reconfigure";
+
+    /**
+     * The 'Reconfigure' command
+     */
+    public static final String COMMAND_DEFAULT_TASK = "default_task";
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
new file mode 100644
index 0000000..88cfc01
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckin.java
@@ -0,0 +1,343 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase checkin.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nowarn</td>
+ *      <td>Suppress warning messages</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>preservetime</td>
+ *      <td>Preserve the modification time</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>keepcopy</td>
+ *      <td>Keeps a copy of the file with a .keep extension</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>identical</td>
+ *      <td>Allows the file to be checked in even if it is identical to the original</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCCheckin extends ClearCase {
+    private String mComment = null;
+    private String mCfile = null;
+    private boolean mNwarn = false;
+    private boolean mPtime = false;
+    private boolean mKeep = false;
+    private boolean mIdentical = true;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool checkin [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_CHECKIN);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        if (getNoWarn()) {
+            // -nwarn
+            cmd.createArgument().setValue(FLAG_NOWARN);
+        }
+
+        if (getPreserveTime()) {
+            // -ptime
+            cmd.createArgument().setValue(FLAG_PRESERVETIME);
+        }
+
+        if (getKeepCopy()) {
+            // -keep
+            cmd.createArgument().setValue(FLAG_KEEPCOPY);
+        }
+
+        if (getIdentical()) {
+            // -identical
+            cmd.createArgument().setValue(FLAG_IDENTICAL);
+        }
+
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+
+    /**
+     * Sets the comment string.
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Specifies a file containing a comment.
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * If true, suppress warning messages.
+     *
+     * @param nwarn the status to set the flag to
+     */
+    public void setNoWarn(boolean nwarn) {
+        mNwarn = nwarn;
+    }
+
+    /**
+     * Get nowarn flag status
+     *
+     * @return boolean containing status of nwarn flag
+     */
+    public boolean getNoWarn() {
+        return mNwarn;
+    }
+
+    /**
+     * If true, preserve the modification time.
+     *
+     * @param ptime the status to set the flag to
+     */
+    public void setPreserveTime(boolean ptime) {
+        mPtime = ptime;
+    }
+
+    /**
+     * Get preservetime flag status
+     *
+     * @return boolean containing status of preservetime flag
+     */
+    public boolean getPreserveTime() {
+        return mPtime;
+    }
+
+    /**
+     * If true, keeps a copy of the file with a .keep extension.
+     *
+     * @param keep the status to set the flag to
+     */
+    public void setKeepCopy(boolean keep) {
+        mKeep = keep;
+    }
+
+    /**
+     * Get keepcopy flag status
+     *
+     * @return boolean containing status of keepcopy flag
+     */
+    public boolean getKeepCopy() {
+        return mKeep;
+    }
+
+    /**
+     * If true, allows the file to be checked in even
+     * if it is identical to the original.
+     *
+     * @param identical the status to set the flag to
+     */
+    public void setIdentical(boolean identical) {
+        mIdentical = identical;
+    }
+
+    /**
+     * Get identical flag status
+     *
+     * @return boolean containing status of identical flag
+     */
+    public boolean getIdentical() {
+        return mIdentical;
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+
+        /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+        /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+        /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+        /**
+     * -nwarn flag -- suppresses warning messages
+     */
+    public static final String FLAG_NOWARN = "-nwarn";
+        /**
+     * -ptime flag -- preserves the modification time
+     */
+    public static final String FLAG_PRESERVETIME = "-ptime";
+        /**
+     * -keep flag -- keeps a copy of the file with a .keep extension
+     */
+    public static final String FLAG_KEEPCOPY = "-keep";
+        /**
+     * -identical flag -- allows the file to be checked in even if it is identical to the original
+     */
+    public static final String FLAG_IDENTICAL = "-identical";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
new file mode 100644
index 0000000..0eaf09a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCCheckout.java
@@ -0,0 +1,516 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * Performs ClearCase checkout.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>reserved</td>
+ *      <td>Specifies whether to check out the file as reserved or not</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>out</td>
+ *      <td>Creates a writable file under a different filename</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nodata</td>
+ *      <td>Checks out the file but does not create an editable file containing its data</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>branch</td>
+ *      <td>Specify a branch to check out the file to</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>version</td>
+ *      <td>Allows checkout of a version other than main latest</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nowarn</td>
+ *      <td>Suppress warning messages</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>notco</td>
+ *      <td>Fail if it's already checked out to the current view. Set to false to ignore it.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCCheckout extends ClearCase {
+    private boolean mReserved = true;
+    private String mOut = null;
+    private boolean mNdata = false;
+    private String mBranch = null;
+    private boolean mVersion = false;
+    private boolean mNwarn = false;
+    private String mComment = null;
+    private String mCfile = null;
+    private boolean mNotco = true;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got the format is
+        // cleartool checkout [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_CHECKOUT);
+
+        checkOptions(commandLine);
+        /*
+         * If configured to not care about whether the element is
+         * already checked out to the current view.
+         * Then check to see if it is checked out.
+         */
+        if (!getNotco() && lsCheckout()) {
+            getProject().log("Already checked out in this view: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+            return;
+        }
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Check to see if the element is checked out in the current view.
+     */
+    private boolean lsCheckout() {
+        Commandline cmdl = new Commandline();
+        String result;
+
+        // build the command line from what we got the format is
+        // cleartool lsco [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        cmdl.setExecutable(getClearToolCommand());
+        cmdl.createArgument().setValue(COMMAND_LSCO);
+        cmdl.createArgument().setValue("-cview");
+        cmdl.createArgument().setValue("-short");
+        cmdl.createArgument().setValue("-d");
+        // viewpath
+        cmdl.createArgument().setValue(getViewPath());
+
+        result = runS(cmdl);
+
+        // System.out.println( "lsCheckout: " + result );
+
+        return (result != null && result.length() > 0) ? true : false;
+    }
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        // ClearCase items
+        if (getReserved()) {
+            // -reserved
+            cmd.createArgument().setValue(FLAG_RESERVED);
+        } else {
+            // -unreserved
+            cmd.createArgument().setValue(FLAG_UNRESERVED);
+        }
+
+        if (getOut() != null) {
+            // -out
+            getOutCommand(cmd);
+        } else {
+            if (getNoData()) {
+                // -ndata
+                cmd.createArgument().setValue(FLAG_NODATA);
+            }
+
+        }
+
+        if (getBranch() != null) {
+            // -branch
+            getBranchCommand(cmd);
+        } else {
+            if (getVersion()) {
+                // -version
+                cmd.createArgument().setValue(FLAG_VERSION);
+            }
+
+        }
+
+        if (getNoWarn()) {
+            // -nwarn
+            cmd.createArgument().setValue(FLAG_NOWARN);
+        }
+
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+
+        // Print out info about the notco option
+        // System.out.println( "Notco: " + (getNotco() ? "yes" : "no") );
+    }
+
+    /**
+     * If true, checks out the file as reserved.
+     *
+     * @param reserved the status to set the flag to
+     */
+    public void setReserved(boolean reserved) {
+        mReserved = reserved;
+    }
+
+    /**
+     * Get reserved flag status
+     *
+     * @return boolean containing status of reserved flag
+     */
+    public boolean getReserved() {
+        return mReserved;
+    }
+
+    /**
+     * If true, checkout fails if the element is already checked out to the current view.
+     *
+     * @param notco the status to set the flag to
+     * @since ant 1.6.1
+     */
+    public void setNotco(boolean notco) {
+        mNotco = notco;
+    }
+
+    /**
+     * Get notco flag status
+     *
+     * @return boolean containing status of notco flag
+     * @since ant 1.6.1
+     */
+    public boolean getNotco() {
+        return mNotco;
+    }
+
+
+    /**
+     * Creates a writable file under a different filename.
+     *
+     * @param outf the path to the out file
+     */
+    public void setOut(String outf) {
+        mOut = outf;
+    }
+
+    /**
+     * Get out file
+     *
+     * @return String containing the path to the out file
+     */
+    public String getOut() {
+        return mOut;
+    }
+
+    /**
+     * If true, checks out the file but does not create an
+     * editable file containing its data.
+     *
+     * @param ndata the status to set the flag to
+     */
+    public void setNoData(boolean ndata) {
+        mNdata = ndata;
+    }
+
+    /**
+     * Get nodata flag status
+     *
+     * @return boolean containing status of ndata flag
+     */
+    public boolean getNoData() {
+        return mNdata;
+    }
+
+    /**
+     * Specify a branch to check out the file to.
+     *
+     * @param branch the name of the branch
+     */
+    public void setBranch(String branch) {
+        mBranch = branch;
+    }
+
+    /**
+     * Get branch name
+     *
+     * @return String containing the name of the branch
+     */
+    public String getBranch() {
+        return mBranch;
+    }
+
+    /**
+     * If true, allows checkout of a version other than main latest.
+     *
+     * @param version the status to set the flag to
+     */
+    public void setVersion(boolean version) {
+        mVersion = version;
+    }
+
+    /**
+     * Get version flag status
+     *
+     * @return boolean containing status of version flag
+     */
+    public boolean getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * If true, warning messages are suppressed.
+     *
+     * @param nwarn the status to set the flag to
+     */
+    public void setNoWarn(boolean nwarn) {
+        mNwarn = nwarn;
+    }
+
+    /**
+     * Get nowarn flag status
+     *
+     * @return boolean containing status of nwarn flag
+     */
+    public boolean getNoWarn() {
+        return mNwarn;
+    }
+
+    /**
+     * Sets the comment string.
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Specifies a file containing a comment.
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * Get the 'out' command
+     *
+     * @param cmd containing the command line string with or
+     *                    without the out flag and path appended
+     */
+    private void getOutCommand(Commandline cmd) {
+        if (getOut() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_OUT);
+            cmd.createArgument().setValue(getOut());
+        }
+    }
+
+    /**
+     * Get the 'branch' command
+     *
+     * @param cmd containing the command line string with or
+                          without the branch flag and name appended
+     */
+    private void getBranchCommand(Commandline cmd) {
+        if (getBranch() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_BRANCH);
+            cmd.createArgument().setValue(getBranch());
+        }
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *                    without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'cfile' command
+     *
+     * @param cmd containing the command line string with or
+     *                    without the cfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+        /**
+     *  -reserved flag -- check out the file as reserved
+     */
+    public static final String FLAG_RESERVED = "-reserved";
+        /**
+     *  -reserved flag -- check out the file as unreserved
+     */
+    public static final String FLAG_UNRESERVED = "-unreserved";
+        /**
+     * -out flag -- create a writable file under a different filename
+     */
+    public static final String FLAG_OUT = "-out";
+        /**
+     * -ndata flag -- checks out the file but does not create an editable file containing its data
+     */
+    public static final String FLAG_NODATA = "-ndata";
+        /**
+     * -branch flag -- checks out the file on a specified branch
+     */
+    public static final String FLAG_BRANCH = "-branch";
+        /**
+     * -version flag -- allows checkout of a version that is not main latest
+     */
+    public static final String FLAG_VERSION = "-version";
+        /**
+     * -nwarn flag -- suppresses warning messages
+     */
+    public static final String FLAG_NOWARN = "-nwarn";
+        /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+        /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+        /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java
new file mode 100644
index 0000000..c273554
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCLock.java
@@ -0,0 +1,378 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/**
+ * TODO:
+ * comment field doesn't include all options yet
+ */
+
+
+
+/**
+ * Performs a ClearCase Lock command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>replace</td>
+ *      <td>Specifies replacing an existing lock</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nusers</td>
+ *      <td>Specifies user(s) who can still modify the object/pname</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>obsolete</td>
+ *      <td>Specifies that the object/pname should be marked obsolete</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specifies how to populate comments fields</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>pname</td>
+ *      <td>Specifies the pathname to be locked.</td>
+ *      <td>No</td>
+ *   <tr>
+ *      <td>objselect</td>
+ *      <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>objsel</td>
+ *      <td>Specifies the object(s) to be unlocked.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCLock extends ClearCase {
+    private boolean mReplace = false;
+    private boolean mObsolete = false;
+    private String mComment = null;
+    private String mNusers = null;
+    private String mPname = null;
+    private String mObjselect = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got the format is
+        // cleartool lock [options...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_LOCK);
+
+        // Check the command line options
+        checkOptions(commandLine);
+
+        // For debugging
+        // System.out.println(commandLine.toString());
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getOpType(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Check the command line options.
+     */
+private void checkOptions(Commandline cmd) {
+        // ClearCase items
+        if (getReplace()) {
+            // -replace
+            cmd.createArgument().setValue(FLAG_REPLACE);
+        }
+        if (getObsolete()) {
+            // -obsolete
+            cmd.createArgument().setValue(FLAG_OBSOLETE);
+        } else {
+            getNusersCommand(cmd);
+        }
+        getCommentCommand(cmd);
+
+        if (getObjselect() == null && getPname() == null) {
+            throw new BuildException("Should select either an element "
+            + "(pname) or an object (objselect)");
+        }
+        getPnameCommand(cmd);
+        // object selector
+        if (getObjselect() != null) {
+            cmd.createArgument().setValue(getObjselect());
+        }
+}
+
+    /**
+     * If true, replace an existing lock.
+     *
+     * @param replace the status to set the flag to
+     */
+    public void setReplace(boolean replace) {
+        mReplace = replace;
+    }
+
+    /**
+     * Get replace flag status
+     *
+     * @return boolean containing status of replace flag
+     */
+    public boolean getReplace() {
+        return mReplace;
+    }
+
+    /**
+     * If true, mark object as obsolete.
+     *
+     * @param obsolete the status to set the flag to
+     */
+    public void setObsolete(boolean obsolete) {
+        mObsolete = obsolete;
+    }
+
+    /**
+     * Get obsolete flag status
+     *
+     * @return boolean containing status of obsolete flag
+     */
+    public boolean getObsolete() {
+        return mObsolete;
+    }
+
+    /**
+     * Sets the users who may continue to
+     * edit the object while it is locked.
+     *
+     * @param nusers users excluded from lock
+     */
+    public void setNusers(String nusers) {
+        mNusers = nusers;
+    }
+
+    /**
+     * Get nusers list
+     *
+     * @return String containing the list of users excluded from lock
+     */
+    public String getNusers() {
+        return mNusers;
+    }
+
+    /**
+     * Sets how comments should be written
+     * for the event record(s)
+     *
+     * @param comment comment method to use
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment method
+     *
+     * @return String containing the desired comment method
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Sets the pathname to be locked
+     *
+     * @param pname pathname to be locked
+     */
+    public void setPname(String pname) {
+        mPname = pname;
+    }
+
+    /**
+     * Get the pathname to be locked
+     *
+     * @return String containing the pathname to be locked
+     */
+    public String getPname() {
+        return mPname;
+    }
+
+    /**
+     * Sets the object(s) to be locked
+     *
+     * @param objsel objects to be locked
+     * @since ant 1.6.1
+     */
+    public void setObjSel(String objsel) {
+        mObjselect = objsel;
+    }
+
+    /**
+     * Sets the object(s) to be locked
+     *
+     * @param objselect objects to be locked
+     */
+    public void setObjselect(String objselect) {
+        mObjselect = objselect;
+    }
+
+    /**
+     * Get list of objects to be locked
+     *
+     * @return String containing the objects to be locked
+     */
+    public String getObjselect() {
+        return mObjselect;
+    }
+
+    /**
+     * Get the 'nusers' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the nusers flag and value appended
+     */
+    private void getNusersCommand(Commandline cmd) {
+        if (getNusers() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_NUSERS);
+            cmd.createArgument().setValue(getNusers());
+        }
+    }
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or without the
+     *            comment flag and value appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'pname' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the pname flag and value appended
+     */
+    private void getPnameCommand(Commandline cmd) {
+        if (getPname() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_PNAME);
+            cmd.createArgument().setValue(getPname());
+        }
+    }
+
+    /**
+     * Return which object/pname is being operated on
+     *
+     * @return String containing the object/pname being worked on
+     */
+    private String getOpType() {
+
+        if (getPname() != null) {
+            return getPname();
+        } else {
+            return getObjselect();
+        }
+    }
+
+    /**
+     *  -replace flag -- replace existing lock on object(s)
+     */
+    public static final String FLAG_REPLACE = "-replace";
+    /**
+     * -nusers flag -- list of users to exclude from lock
+     */
+    public static final String FLAG_NUSERS = "-nusers";
+    /**
+     * -obsolete flag -- mark locked object as obsolete
+     */
+    public static final String FLAG_OBSOLETE = "-obsolete";
+    /**
+     * -comment flag -- method to use for commenting events
+     */
+    public static final String FLAG_COMMENT = "-comment";
+    /**
+     * -pname flag -- pathname to lock
+     */
+    public static final String FLAG_PNAME = "-pname";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java
new file mode 100644
index 0000000..9bd1884
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkattr.java
@@ -0,0 +1,425 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * Task to perform mkattr command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>replace</td>
+ *      <td>Replace the value of the attribute if it already exists</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>recurse</td>
+ *      <td>Process each subdirectory under viewpath</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>version</td>
+ *      <td>Identify a specific version to attach the attribute to</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>typename</td>
+ *      <td>Name of the attribute type</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>typevalue</td>
+ *      <td>Value to attach to the attribute type</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMkattr extends ClearCase {
+    private boolean mReplace = false;
+    private boolean mRecurse = false;
+    private String mVersion = null;
+    private String mTypeName = null;
+    private String mTypeValue = null;
+    private String mComment = null;
+    private String mCfile = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Check for required attributes
+        if (getTypeName() == null) {
+            throw new BuildException("Required attribute TypeName not specified");
+        }
+        if (getTypeValue() == null) {
+            throw new BuildException("Required attribute TypeValue not specified");
+        }
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool mkattr [options...] [viewpath ...]
+        // as specified in the CLEARTOOL help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKATTR);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+
+        // For debugging
+        // System.out.println(commandLine.toString());
+
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getReplace()) {
+            // -replace
+            cmd.createArgument().setValue(FLAG_REPLACE);
+        }
+
+        if (getRecurse()) {
+            // -recurse
+            cmd.createArgument().setValue(FLAG_RECURSE);
+        }
+
+        if (getVersion() != null) {
+            // -version
+            getVersionCommand(cmd);
+        }
+
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        if (getTypeName() != null) {
+            // type
+            getTypeCommand(cmd);
+        }
+        if (getTypeValue() != null) {
+            // type value
+            getTypeValueCommand(cmd);
+        }
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+
+    /**
+     * Set the replace flag
+     *
+     * @param replace the status to set the flag to
+     */
+    public void setReplace(boolean replace) {
+        mReplace = replace;
+    }
+
+    /**
+     * Get replace flag status
+     *
+     * @return boolean containing status of replace flag
+     */
+    public boolean getReplace() {
+        return mReplace;
+    }
+
+    /**
+     * Set recurse flag
+     *
+     * @param recurse the status to set the flag to
+     */
+    public void setRecurse(boolean recurse) {
+        mRecurse = recurse;
+    }
+
+    /**
+     * Get recurse flag status
+     *
+     * @return boolean containing status of recurse flag
+     */
+    public boolean getRecurse() {
+        return mRecurse;
+    }
+
+    /**
+     * Set the version flag
+     *
+     * @param version the status to set the flag to
+     */
+    public void setVersion(String version) {
+        mVersion = version;
+    }
+
+    /**
+     * Get version flag status
+     *
+     * @return boolean containing status of version flag
+     */
+    public String getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Set comment string
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Set comment file
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * Set the attribute type-name
+     *
+     * @param tn the type name
+     */
+    public void setTypeName(String tn) {
+        mTypeName = tn;
+    }
+
+    /**
+     * Get attribute type-name
+     *
+     * @return String containing type name
+     */
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    /**
+     * Set the attribute type-value
+     *
+     * @param tv the type value
+     */
+    public void setTypeValue(String tv) {
+        mTypeValue = tv;
+    }
+
+    /**
+     * Get the attribute type-value
+     *
+     * @return String containing type value
+     */
+    public String getTypeValue() {
+        return mTypeValue;
+    }
+
+
+    /**
+     * Get the 'version' command
+     *
+     * @param cmd CommandLine containing the command line string with or
+     *                    without the version flag and string appended
+     */
+    private void getVersionCommand(Commandline cmd) {
+        if (getVersion() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_VERSION);
+            cmd.createArgument().setValue(getVersion());
+        }
+    }
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd         containing the command line string with or
+     *                    without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+    /**
+     * Get the attribute type-name
+     *
+     * @param cmd containing the command line string with or
+     *        without the type-name
+     */
+    private void getTypeCommand(Commandline cmd) {
+        String typenm = getTypeName();
+
+        if (typenm != null) {
+            cmd.createArgument().setValue(typenm);
+        }
+    }
+
+    /**
+     * Get the attribute type-value
+     *
+     * @param cmd containing the command line string with or
+     *        without the type-value
+     */
+    private void getTypeValueCommand(Commandline cmd) {
+        String typevl = getTypeValue();
+
+        if (typevl != null) {
+            if (Os.isFamily("windows")) {
+                typevl = "\\\"" + typevl + "\\\""; // Windows quoting of the value
+            } else {
+                typevl = "\"" + typevl + "\"";
+            }
+            cmd.createArgument().setValue(typevl);
+        }
+    }
+
+    /**
+     * -replace flag -- replace the existing value of the attribute
+     */
+    public static final String FLAG_REPLACE = "-replace";
+    /**
+     * -recurse flag -- process all subdirectories
+     */
+    public static final String FLAG_RECURSE = "-recurse";
+    /**
+     * -version flag -- attach attribute to specified version
+     */
+    public static final String FLAG_VERSION = "-version";
+    /**
+     * -c flag -- comment to attach to the element
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java
new file mode 100644
index 0000000..82c9600
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkbl.java
@@ -0,0 +1,365 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to CreateBaseline command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be
+used.</td>
+ *      <td>No</td>
+ *   </tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or
+cfile may be used.</td>
+ *      <td>No</td>
+ *   </tr>
+ *   <tr>
+ *      <td>baselinerootname</td>
+ *      <td>Specify the name to be associated with the baseline.</td>
+ *      <td>Yes</td>
+ *   </tr>
+ *   <tr>
+ *      <td>nowarn</td>
+ *      <td>Suppress warning messages</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>identical</td>
+ *      <td>Allows the baseline to be created even if it is identical to the
+previous baseline.</td>
+ *      <td>No</td>
+ *   </tr>
+ *   <tr>
+ *      <td>full</td>
+ *      <td>Creates a full baseline.</td>
+ *      <td>No</td>
+ *   </tr>
+ *   <tr>
+ *      <td>nlabel</td>
+ *      <td>Allows the baseline to be created without a label.</td>
+ *      <td>No</td>
+ *   </tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMkbl extends ClearCase {
+    private String mComment = null;
+    private String mCfile = null;
+    private String mBaselineRootName = null;
+    private boolean mNwarn = false;
+    private boolean mIdentical = true;
+    private boolean mFull = false;
+    private boolean mNlabel = false;
+
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool checkin [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKBL);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getBaselineRootName(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        if (getIdentical()) {
+            // -identical
+            cmd.createArgument().setValue(FLAG_IDENTICAL);
+        }
+
+       if (getFull()) {
+           // -full
+           cmd.createArgument().setValue(FLAG_FULL);
+       } else {
+           // -incremental
+           cmd.createArgument().setValue(FLAG_INCREMENTAL);
+       }
+
+       if (getNlabel()) {
+           // -nlabel
+           cmd.createArgument().setValue(FLAG_NLABEL);
+       }
+
+       // baseline_root_name
+        cmd.createArgument().setValue(getBaselineRootName());
+
+    }
+
+
+    /**
+     * Set comment string
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Set comment file
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * Set baseline_root_name
+     *
+     * @param baselineRootName the name of the baseline
+     */
+    public void setBaselineRootName(String baselineRootName) {
+        mBaselineRootName = baselineRootName;
+    }
+
+    /**
+     * Get baseline_root_name
+     *
+     * @return String containing the name of the baseline
+     */
+    public String getBaselineRootName() {
+        return mBaselineRootName;
+    }
+
+    /**
+
+    /**
+     * Set the nowarn flag
+     *
+     * @param nwarn the status to set the flag to
+     */
+    public void setNoWarn(boolean nwarn) {
+        mNwarn = nwarn;
+    }
+
+    /**
+     * Get nowarn flag status
+     *
+     * @return boolean containing status of nwarn flag
+     */
+    public boolean getNoWarn() {
+        return mNwarn;
+    }
+
+    /**
+     * Set the identical flag
+     *
+     * @param identical the status to set the flag to
+     */
+    public void setIdentical(boolean identical) {
+        mIdentical = identical;
+    }
+
+    /**
+     * Get identical flag status
+     *
+     * @return boolean containing status of identical flag
+     */
+    public boolean getIdentical() {
+        return mIdentical;
+    }
+
+    /**
+     * Set the full flag
+     *
+     * @param full the status to set the flag to
+     */
+    public void setFull(boolean full) {
+        mFull = full;
+    }
+
+    /**
+     * Get full flag status
+     *
+     * @return boolean containing status of full flag
+     */
+    public boolean getFull() {
+        return mFull;
+    }
+
+    /**
+     * Set the nlabel flag
+     *
+     * @param nlabel the status to set the flag to
+     */
+    public void setNlabel(boolean nlabel) {
+        mNlabel = nlabel;
+    }
+
+    /**
+     * Get nlabel status
+     *
+     * @return boolean containing status of nlabel flag
+     */
+    public boolean getNlabel() {
+        return mNlabel;
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *                    without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd CommandLine containing the command line string with or
+     *                    without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+
+        /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+        /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+        /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+        /**
+     * -identical flag -- allows the file to be checked in even if it is identical to the original
+     */
+    public static final String FLAG_IDENTICAL = "-identical";
+       /**
+     * -incremental flag -- baseline to be created is incremental
+     */
+    public static final String FLAG_INCREMENTAL = "-incremental";
+       /**
+     * -full flag -- baseline to be created is full
+     */
+    public static final String FLAG_FULL = "-full";
+       /**
+     * -nlabel -- baseline to be created without a label
+     */
+    public static final String FLAG_NLABEL = "-nlabel";
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java
new file mode 100644
index 0000000..4c89539
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkdir.java
@@ -0,0 +1,237 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase mkdir.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view directory that the command will operate on</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nocheckout</td>
+ *      <td>Do not checkout after element creation</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMkdir extends ClearCase {
+    private String  mComment = null;
+    private String  mCfile   = null;
+    private boolean mNoco    = false;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool mkelem [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKDIR);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+        if (getNoCheckout()) {
+            // -nco
+            cmd.createArgument().setValue(FLAG_NOCHECKOUT);
+        }
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+    /**
+     * Sets the comment string.
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Specifies a file containing a comment.
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * If true, do not checkout element after creation.
+     *
+     * @param co the status to set the flag to
+     */
+    public void setNoCheckout(boolean co) {
+        mNoco = co;
+    }
+
+    /**
+     * Get no checkout flag status
+     *
+     * @return boolean containing status of noco flag
+     */
+    public boolean getNoCheckout() {
+        return mNoco;
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+    /**
+     * -c flag -- comment to attach to the directory
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the directory
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+    /**
+     * -nco flag -- do not checkout element after creation
+     */
+    public static final String FLAG_NOCHECKOUT = "-nco";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
new file mode 100644
index 0000000..94faa5a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMkelem.java
@@ -0,0 +1,424 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase mkelem.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nowarn</td>
+ *      <td>Suppress warning messages</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>nocheckout</td>
+ *      <td>Do not checkout after element creation</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>checkin</td>
+ *      <td>Checkin element after creation</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>preservetime</td>
+ *      <td>Preserve the modification time (for checkin)</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>master</td>
+ *      <td>Assign mastership of the main branch to the current site</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>eltype</td>
+ *      <td>Element type to use during element creation</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMkelem extends ClearCase {
+    private String  mComment = null;
+    private String  mCfile   = null;
+    private boolean mNwarn   = false;
+    private boolean mPtime   = false;
+    private boolean mNoco    = false;
+    private boolean mCheckin = false;
+    private boolean mMaster  = false;
+    private String  mEltype  = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool mkelem [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKELEM);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        if (getNoWarn()) {
+            // -nwarn
+            cmd.createArgument().setValue(FLAG_NOWARN);
+        }
+        /*
+         * Should choose either -ci or -nco.
+         */
+        if (getNoCheckout() && getCheckin()) {
+            throw new BuildException("Should choose either [nocheckout | checkin]");
+        }
+        if (getNoCheckout()) {
+            // -nco
+            cmd.createArgument().setValue(FLAG_NOCHECKOUT);
+        }
+        if (getCheckin()) {
+            // -ci
+            cmd.createArgument().setValue(FLAG_CHECKIN);
+            if (getPreserveTime()) {
+                // -ptime
+                cmd.createArgument().setValue(FLAG_PRESERVETIME);
+            }
+        }
+        if (getMaster()) {
+            // -master
+            cmd.createArgument().setValue(FLAG_MASTER);
+        }
+        if (getEltype() != null) {
+            // -eltype
+            getEltypeCommand(cmd);
+        }
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+    /**
+     * Sets the comment string.
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Specifies a file containing a comment.
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * If true, suppress warning messages.
+     *
+     * @param nwarn the status to set the flag to
+     */
+    public void setNoWarn(boolean nwarn) {
+        mNwarn = nwarn;
+    }
+
+    /**
+     * Get nowarn flag status
+     *
+     * @return boolean containing status of nwarn flag
+     */
+    public boolean getNoWarn() {
+        return mNwarn;
+    }
+
+    /**
+     * If true, preserve the modification time.
+     *
+     * @param ptime the status to set the flag to
+     */
+    public void setPreserveTime(boolean ptime) {
+        mPtime = ptime;
+    }
+
+    /**
+     * Get preservetime flag status
+     *
+     * @return boolean containing status of preservetime flag
+     */
+    public boolean getPreserveTime() {
+        return mPtime;
+    }
+
+    /**
+     * If true, do not checkout element after creation.
+     *
+     * @param co the status to set the flag to
+     */
+    public void setNoCheckout(boolean co) {
+        mNoco = co;
+    }
+
+    /**
+     * Get no checkout flag status
+     *
+     * @return boolean containing status of noco flag
+     */
+    public boolean getNoCheckout() {
+        return mNoco;
+    }
+
+    /**
+     * If true, checkin the element after creation
+     *
+     * @param ci the status to set the flag to
+     */
+    public void setCheckin(boolean ci) {
+        mCheckin = ci;
+    }
+
+    /**
+     * Get ci flag status
+     *
+     * @return boolean containing status of ci flag
+     */
+    public boolean getCheckin() {
+        return mCheckin;
+    }
+
+    /**
+     * If true, changes mastership of the main branch
+     * to the current site
+     *
+     * @param master the status to set the flag to
+     */
+    public void setMaster(boolean master) {
+        mMaster = master;
+    }
+
+    /**
+     * Get master flag status
+     *
+     * @return boolean containing status of master flag
+     */
+    public boolean getMaster() {
+        return mMaster;
+    }
+
+    /**
+     * Specifies the element type to use.
+     *
+     * @param eltype to create element
+     */
+    public void setEltype(String eltype) {
+        mEltype = eltype;
+    }
+
+    /**
+     * Get element type
+     *
+     * @return String containing the element type
+     */
+    public String getEltype() {
+        return mEltype;
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+    /**
+     * Get the 'element type' command
+     *
+     * @param cmd containing the command line string with or
+     *            without the comment flag and string appended
+     */
+    private void getEltypeCommand(Commandline cmd) {
+        if (getEltype() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_ELTYPE);
+            cmd.createArgument().setValue(getEltype());
+        }
+    }
+
+    /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+    /**
+     * -nwarn flag -- suppresses warning messages
+     */
+    public static final String FLAG_NOWARN = "-nwarn";
+    /**
+     * -ptime flag -- preserves the modification time on checkin
+     */
+    public static final String FLAG_PRESERVETIME = "-ptime";
+    /**
+     * -nco flag -- do not checkout element after creation
+     */
+    public static final String FLAG_NOCHECKOUT = "-nco";
+    /**
+     * -ci flag -- checkin element after creation
+     */
+    public static final String FLAG_CHECKIN = "-ci";
+    /**
+     * -master flag -- change mastership of main branch to current site
+     */
+    public static final String FLAG_MASTER = "-master";
+    /**
+     * -eltype flag -- element type to use during creation
+     */
+    public static final String FLAG_ELTYPE = "-eltype";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
new file mode 100644
index 0000000..e3d288d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklabel.java
@@ -0,0 +1,402 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform mklabel command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>replace</td>
+ *      <td>Replace a label of the same type on the same branch</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>recurse</td>
+ *      <td>Process each subdirectory under viewpath</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>version</td>
+ *      <td>Identify a specific version to attach the label to</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>typename</td>
+ *      <td>Name of the label type</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>vob</td>
+ *      <td>Name of the VOB</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMklabel extends ClearCase {
+    private boolean mReplace = false;
+    private boolean mRecurse = false;
+    private String mVersion = null;
+    private String mTypeName = null;
+    private String mVOB = null;
+    private String mComment = null;
+    private String mCfile = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Check for required attributes
+        if (getTypeName() == null) {
+            throw new BuildException("Required attribute TypeName not specified");
+        }
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool mklabel [options...] [viewpath ...]
+        // as specified in the CLEARTOOL help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKLABEL);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getReplace()) {
+            // -replace
+            cmd.createArgument().setValue(FLAG_REPLACE);
+        }
+
+        if (getRecurse()) {
+            // -recurse
+            cmd.createArgument().setValue(FLAG_RECURSE);
+        }
+
+        if (getVersion() != null) {
+            // -version
+            getVersionCommand(cmd);
+        }
+
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        if (getTypeName() != null) {
+            // type
+            getTypeCommand(cmd);
+        }
+
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+
+    /**
+     * Set the replace flag
+     *
+     * @param replace the status to set the flag to
+     */
+    public void setReplace(boolean replace) {
+        mReplace = replace;
+    }
+
+    /**
+     * Get replace flag status
+     *
+     * @return boolean containing status of replace flag
+     */
+    public boolean getReplace() {
+        return mReplace;
+    }
+
+    /**
+     * Set recurse flag
+     *
+     * @param recurse the status to set the flag to
+     */
+    public void setRecurse(boolean recurse) {
+        mRecurse = recurse;
+    }
+
+    /**
+     * Get recurse flag status
+     *
+     * @return boolean containing status of recurse flag
+     */
+    public boolean getRecurse() {
+        return mRecurse;
+    }
+
+    /**
+     * Set the version flag
+     *
+     * @param version the status to set the flag to
+     */
+    public void setVersion(String version) {
+        mVersion = version;
+    }
+
+    /**
+     * Get version flag status
+     *
+     * @return boolean containing status of version flag
+     */
+    public String getVersion() {
+        return mVersion;
+    }
+
+    /**
+     * Set comment string
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Set comment file
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * Set the type-name
+     *
+     * @param tn the type name
+     */
+    public void setTypeName(String tn) {
+        mTypeName = tn;
+    }
+
+    /**
+     * Get type-name
+     *
+     * @return String containing type name
+     */
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    /**
+     * Set the VOB name
+     *
+     * @param vob the VOB name
+     */
+    public void setVOB(String vob) {
+        mVOB = vob;
+    }
+
+    /**
+     * Get VOB name
+     *
+     * @return String containing VOB name
+     */
+    public String getVOB() {
+        return mVOB;
+    }
+
+
+    /**
+     * Get the 'version' command
+     *
+     * @param cmd CommandLine containing the command line string with or
+     *                    without the version flag and string appended
+     */
+    private void getVersionCommand(Commandline cmd) {
+        if (getVersion() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_VERSION);
+            cmd.createArgument().setValue(getVersion());
+        }
+    }
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd         containing the command line string with or
+     *                    without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+    /**
+     * Get the type-name
+     *
+     * @param cmd containing the command line string with or
+     *        without the type-name
+     */
+    private void getTypeCommand(Commandline cmd) {
+        String typenm = null;
+
+        if (getTypeName() != null) {
+            typenm = getTypeName();
+            if (getVOB() != null) {
+                typenm += "@" + getVOB();
+            }
+            cmd.createArgument().setValue(typenm);
+        }
+    }
+
+
+    /**
+     * -replace flag -- replace another label of the same type
+     */
+    public static final String FLAG_REPLACE = "-replace";
+    /**
+     * -recurse flag -- process all subdirectories
+     */
+    public static final String FLAG_RECURSE = "-recurse";
+    /**
+     * -version flag -- attach label to specified version
+     */
+    public static final String FLAG_VERSION = "-version";
+    /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java
new file mode 100644
index 0000000..7bb7192
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCMklbtype.java
@@ -0,0 +1,440 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform mklbtype command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>typename</td>
+ *      <td>Name of the label type to create</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>vob</td>
+ *      <td>Name of the VOB</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>replace</td>
+ *      <td>Replace an existing label definition of the same type</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>global</td>
+ *      <td>Either global or ordinary can be specified, not both.
+ *          Creates a label type that is global to the VOB or to
+ *          VOBs that use this VOB</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>ordinary</td>
+ *      <td>Either global or ordinary can be specified, not both.
+ *          Creates a label type that can be used only in the current
+ *          VOB. <B>Default</B></td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>pbranch</td>
+ *      <td>Allows the label type to be used once per branch in a given
+ *          element's version tree</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>shared</td>
+ *      <td>Sets the way mastership is checked by ClearCase. See ClearCase
+ *          documentation for details</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or
+ *          cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCMklbtype extends ClearCase {
+    private String mTypeName = null;
+    private String mVOB = null;
+    private String mComment = null;
+    private String mCfile = null;
+    private boolean mReplace = false;
+    private boolean mGlobal = false;
+    private boolean mOrdinary = true;
+    private boolean mPbranch = false;
+    private boolean mShared = false;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        int result = 0;
+
+        // Check for required attributes
+        if (getTypeName() == null) {
+            throw new BuildException("Required attribute TypeName not specified");
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool mklbtype [options...] type-selector...
+        // as specified in the CLEARTOOL help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_MKLBTYPE);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getTypeSpecifier(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getReplace()) {
+            // -replace
+            cmd.createArgument().setValue(FLAG_REPLACE);
+        }
+
+        if (getOrdinary()) {
+            // -ordinary
+            cmd.createArgument().setValue(FLAG_ORDINARY);
+        } else {
+            if (getGlobal()) {
+                // -global
+                cmd.createArgument().setValue(FLAG_GLOBAL);
+            }
+        }
+
+        if (getPbranch()) {
+            // -pbranch
+            cmd.createArgument().setValue(FLAG_PBRANCH);
+        }
+
+        if (getShared()) {
+            // -shared
+            cmd.createArgument().setValue(FLAG_SHARED);
+        }
+
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        // type-name@vob
+        cmd.createArgument().setValue(getTypeSpecifier());
+    }
+
+
+    /**
+     * Set type-name string
+     *
+     * @param tn the type-name string
+     */
+    public void setTypeName(String tn) {
+        mTypeName = tn;
+    }
+
+    /**
+     * Get type-name string
+     *
+     * @return String containing the type-name
+     */
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    /**
+     * Set the VOB name
+     *
+     * @param vob the VOB name
+     */
+    public void setVOB(String vob) {
+        mVOB = vob;
+    }
+
+    /**
+     * Get VOB name
+     *
+     * @return String containing VOB name
+     */
+    public String getVOB() {
+        return mVOB;
+    }
+
+    /**
+     * Set the replace flag
+     *
+     * @param repl the status to set the flag to
+     */
+    public void setReplace(boolean repl) {
+        mReplace = repl;
+    }
+
+    /**
+     * Get replace flag status
+     *
+     * @return boolean containing status of replace flag
+     */
+    public boolean getReplace() {
+        return mReplace;
+    }
+
+    /**
+     * Set the global flag
+     *
+     * @param glob the status to set the flag to
+     */
+    public void setGlobal(boolean glob) {
+        mGlobal = glob;
+    }
+
+    /**
+     * Get global flag status
+     *
+     * @return boolean containing status of global flag
+     */
+    public boolean getGlobal() {
+        return mGlobal;
+    }
+
+    /**
+     * Set the ordinary flag
+     *
+     * @param ordinary the status to set the flag to
+     */
+    public void setOrdinary(boolean ordinary) {
+        mOrdinary = ordinary;
+    }
+
+    /**
+     * Get ordinary flag status
+     *
+     * @return boolean containing status of ordinary flag
+     */
+    public boolean getOrdinary() {
+        return mOrdinary;
+    }
+
+    /**
+     * Set the pbranch flag
+     *
+     * @param pbranch the status to set the flag to
+     */
+    public void setPbranch(boolean pbranch) {
+        mPbranch = pbranch;
+    }
+
+    /**
+     * Get pbranch flag status
+     *
+     * @return boolean containing status of pbranch flag
+     */
+    public boolean getPbranch() {
+        return mPbranch;
+    }
+
+    /**
+     * Set the shared flag
+     *
+     * @param shared the status to set the flag to
+     */
+    public void setShared(boolean shared) {
+        mShared = shared;
+    }
+
+    /**
+     * Get shared flag status
+     *
+     * @return boolean containing status of shared flag
+     */
+    public boolean getShared() {
+        return mShared;
+    }
+
+    /**
+     * Set comment string
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Set comment file
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+    /**
+     * Get the type-name specifier
+     *
+     * @return the 'type-name-specifier' command if the attribute was
+     *         specified, otherwise an empty string
+     */
+    private String getTypeSpecifier() {
+        String typenm = null;
+
+        typenm = getTypeName();
+        if (getVOB() != null) {
+            typenm += "@" + getVOB();
+        }
+
+        return typenm;
+    }
+
+
+    /**
+     * -replace flag -- replace existing label definition of the same type
+     */
+    public static final String FLAG_REPLACE = "-replace";
+    /**
+     * -global flag -- creates a label type that is global to the VOB or to VOBs that use this VOB
+     */
+    public static final String FLAG_GLOBAL = "-global";
+    /**
+     * -ordinary flag -- creates a label type that can be used only in the current VOB
+     */
+    public static final String FLAG_ORDINARY = "-ordinary";
+    /**
+     * -pbranch flag -- allows label type to be used once per branch
+     */
+    public static final String FLAG_PBRANCH = "-pbranch";
+    /**
+     * -shared flag -- sets the way mastership is checked by ClearCase
+     */
+    public static final String FLAG_SHARED = "-shared";
+    /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java
new file mode 100644
index 0000000..cef0c3a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCRmtype.java
@@ -0,0 +1,373 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Task to perform rmtype command to ClearCase.
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>typekind</td>
+ *      <td>The kind of type to create. Valid types are:<br>
+ *              attype                         attribute type<br>
+ *              brtype                         branch type<br>
+ *              eltype                         element type<br>
+ *              hltype                         hyperlink type<br>
+ *              lbtype                         label type<br>
+ *              trtype                         trigger type<br>
+ *      </td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>typename</td>
+ *      <td>The name of the type to remove</td>
+ *      <td>Yes</td>
+ *   <tr>
+ *   <tr>
+ *      <td>vob</td>
+ *      <td>Name of the VOB</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>ignore</td>
+ *      <td>Used with trigger types only. Forces removal of trigger type
+ *          even if a pre-operation trigger would prevent its removal</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>rmall</td>
+ *      <td>Removes all instances of a type and the type object itself</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specify a comment. Only one of comment or cfile may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>commentfile</td>
+ *      <td>Specify a file containing a comment. Only one of comment or cfile
+ *          may be used.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCRmtype extends ClearCase {
+    private String mTypeKind = null;
+    private String mTypeName = null;
+    private String mVOB = null;
+    private String mComment = null;
+    private String mCfile = null;
+    private boolean mRmall = false;
+    private boolean mIgnore = false;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        int result = 0;
+
+        // Check for required attributes
+        if (getTypeKind() == null) {
+            throw new BuildException("Required attribute TypeKind not specified");
+        }
+        if (getTypeName() == null) {
+            throw new BuildException("Required attribute TypeName not specified");
+        }
+
+        // build the command line from what we got. the format is
+        // cleartool rmtype [options...] type-selector...
+        // as specified in the CLEARTOOL help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_RMTYPE);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getTypeSpecifier(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        if (getIgnore()) {
+            // -ignore
+            cmd.createArgument().setValue(FLAG_IGNORE);
+        }
+        if (getRmAll()) {
+            // -rmall -force
+            cmd.createArgument().setValue(FLAG_RMALL);
+            cmd.createArgument().setValue(FLAG_FORCE);
+        }
+        if (getComment() != null) {
+            // -c
+            getCommentCommand(cmd);
+        } else {
+            if (getCommentFile() != null) {
+                // -cfile
+                getCommentFileCommand(cmd);
+            } else {
+                cmd.createArgument().setValue(FLAG_NOCOMMENT);
+            }
+        }
+
+        // type-kind:type-name
+        cmd.createArgument().setValue(getTypeSpecifier());
+    }
+
+    /**
+     * Set the ignore flag
+     *
+     * @param ignore the status to set the flag to
+     */
+    public void setIgnore(boolean ignore) {
+        mIgnore = ignore;
+    }
+
+    /**
+     * Get ignore flag status
+     *
+     * @return boolean containing status of ignore flag
+     */
+    public boolean getIgnore() {
+        return mIgnore;
+    }
+
+    /**
+     * Set rmall flag
+     *
+     * @param rmall the status to set the flag to
+     */
+    public void setRmAll(boolean rmall) {
+        mRmall = rmall;
+    }
+
+    /**
+     * Get rmall flag status
+     *
+     * @return boolean containing status of rmall flag
+     */
+    public boolean getRmAll() {
+        return mRmall;
+    }
+
+    /**
+     * Set comment string
+     *
+     * @param comment the comment string
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment string
+     *
+     * @return String containing the comment
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Set comment file
+     *
+     * @param cfile the path to the comment file
+     */
+    public void setCommentFile(String cfile) {
+        mCfile = cfile;
+    }
+
+    /**
+     * Get comment file
+     *
+     * @return String containing the path to the comment file
+     */
+    public String getCommentFile() {
+        return mCfile;
+    }
+
+    /**
+     * Set type-kind string
+     *
+     * @param tk the type-kind string
+     */
+    public void setTypeKind(String tk) {
+        mTypeKind = tk;
+    }
+
+    /**
+     * Get type-kind string
+     *
+     * @return String containing the type-kind
+     */
+    public String getTypeKind() {
+        return mTypeKind;
+    }
+
+    /**
+     * Set type-name string
+     *
+     * @param tn the type-name string
+     */
+    public void setTypeName(String tn) {
+        mTypeName = tn;
+    }
+
+    /**
+     * Get type-name string
+     *
+     * @return String containing the type-name
+     */
+    public String getTypeName() {
+        return mTypeName;
+    }
+
+    /**
+     * Set the VOB name
+     *
+     * @param vob the VOB name
+     */
+    public void setVOB(String vob) {
+        mVOB = vob;
+    }
+
+    /**
+     * Get VOB name
+     *
+     * @return String containing VOB name
+     */
+    public String getVOB() {
+        return mVOB;
+    }
+
+    /**
+     * Get the 'type-specifier' string
+     *
+     * @return the 'type-kind:type-name@vob' specifier
+     *
+     */
+    private String getTypeSpecifier() {
+        String tkind = getTypeKind();
+        String tname = getTypeName();
+        String typeSpec = null;
+
+        // Return the type-selector
+        typeSpec = tkind + ":" + tname;
+        if (getVOB() != null) {
+            typeSpec += "@" + getVOB();
+        }
+        return typeSpec;
+    }
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the comment flag and string appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'commentfile' command
+     *
+     * @param cmd containing the command line string with or
+     *        without the commentfile flag and file appended
+     */
+    private void getCommentFileCommand(Commandline cmd) {
+        if (getCommentFile() != null) {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENTFILE);
+            cmd.createArgument().setValue(getCommentFile());
+        }
+    }
+
+
+    /**
+     * -ignore flag -- ignore pre-trigger operations when removing a trigger type
+     */
+    public static final String FLAG_IGNORE = "-ignore";
+    /**
+     * -rmall flag -- removes all instances of a type and the type object itself
+     */
+    public static final String FLAG_RMALL = "-rmall";
+    /**
+     * -force flag -- suppresses confirmation prompts
+     */
+    public static final String FLAG_FORCE = "-force";
+    /**
+     * -c flag -- comment to attach to the file
+     */
+    public static final String FLAG_COMMENT = "-c";
+    /**
+     * -cfile flag -- file containing a comment to attach to the file
+     */
+    public static final String FLAG_COMMENTFILE = "-cfile";
+    /**
+     * -nc flag -- no comment is specified
+     */
+    public static final String FLAG_NOCOMMENT = "-nc";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java
new file mode 100644
index 0000000..3c00e1a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnCheckout.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs ClearCase UnCheckout command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>keepcopy</td>
+ *      <td>Specifies whether to keep a copy of the file with a .keep extension or not</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCUnCheckout extends ClearCase {
+    private boolean mKeep = false;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got the format is
+        // cleartool uncheckout [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_UNCHECKOUT);
+
+        checkOptions(commandLine);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        // ClearCase items
+        if (getKeepCopy()) {
+            // -keep
+            cmd.createArgument().setValue(FLAG_KEEPCOPY);
+        } else {
+            // -rm
+            cmd.createArgument().setValue(FLAG_RM);
+        }
+
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+    /**
+     * If true, keep a copy of the file with a .keep extension.
+     *
+     * @param keep the status to set the flag to
+     */
+    public void setKeepCopy(boolean keep) {
+        mKeep = keep;
+    }
+
+    /**
+     * Get keepcopy flag status
+     *
+     * @return boolean containing status of keep flag
+     */
+    public boolean getKeepCopy() {
+        return mKeep;
+    }
+
+
+    /**
+     *  -keep flag -- keep a copy of the file with .keep extension
+     */
+    public static final String FLAG_KEEPCOPY = "-keep";
+    /**
+     *  -rm flag -- remove the copy of the file
+     */
+    public static final String FLAG_RM = "-rm";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java
new file mode 100644
index 0000000..4ca3e89
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUnlock.java
@@ -0,0 +1,260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * TODO:
+ * comment field doesn't include all options yet
+ */
+
+/**
+ * Performs a ClearCase Unlock command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>comment</td>
+ *      <td>Specifies how to populate comments fields</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>pname</td>
+ *      <td>Specifies the object pathname to be unlocked.</td>
+ *      <td>No</td>
+ *   <tr>
+ *      <td>objselect</td>
+ *      <td>This variable is obsolete. Should use <i>objsel</i> instead.</td>
+ *      <td>no</td>
+ *   <tr>
+ *   <tr>
+ *      <td>objsel</td>
+ *      <td>Specifies the object(s) to be unlocked.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ *
+ * </table>
+ *
+ */
+public class CCUnlock extends ClearCase {
+    private String mComment = null;
+    private String mPname = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got the format is
+        // cleartool lock [options...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_UNLOCK);
+
+        // Check the command line options
+        checkOptions(commandLine);
+
+        // For debugging
+        // System.out.println(commandLine.toString());
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getOpType(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        // ClearCase items
+        getCommentCommand(cmd);
+
+        if (getObjSelect() == null && getPname() == null) {
+            throw new BuildException("Should select either an element "
+            + "(pname) or an object (objselect)");
+        }
+        getPnameCommand(cmd);
+        // object selector
+        if (getObjSelect() != null) {
+            cmd.createArgument().setValue(getObjSelect());
+        }
+    }
+
+    /**
+     * Sets how comments should be written
+     * for the event record(s)
+     *
+     * @param comment comment method to use
+     */
+    public void setComment(String comment) {
+        mComment = comment;
+    }
+
+    /**
+     * Get comment method
+     *
+     * @return String containing the desired comment method
+     */
+    public String getComment() {
+        return mComment;
+    }
+
+    /**
+     * Sets the pathname to be locked
+     *
+     * @param pname pathname to be locked
+     */
+    public void setPname(String pname) {
+        mPname = pname;
+    }
+
+    /**
+     * Get the pathname to be locked
+     *
+     * @return String containing the pathname to be locked
+     */
+    public String getPname() {
+        return mPname;
+    }
+
+    /**
+     * Sets the object(s) to be locked
+     *
+     * @param objselect objects to be locked
+     */
+    public void setObjselect(String objselect) {
+        setObjSelect(objselect);
+    }
+
+    /**
+     * Sets the object(s) to be locked
+     *
+     * @param objsel objects to be locked
+     * @since ant 1.6.1
+     */
+    public void setObjSel(String objsel) {
+        setObjSelect(objsel);
+    }
+
+    /**
+     * Get list of objects to be locked
+     *
+     * @return String containing the objects to be locked
+     */
+    public String getObjselect() {
+        return getObjSelect();
+    }
+
+    /**
+     * Get the 'comment' command
+     *
+     * @param cmd containing the command line string with or without the
+     *            comment flag and value appended
+     */
+    private void getCommentCommand(Commandline cmd) {
+        if (getComment() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_COMMENT);
+            cmd.createArgument().setValue(getComment());
+        }
+    }
+
+    /**
+     * Get the 'pname' command
+     *
+     * @param cmd containing the command line string with or without the
+     *            pname flag and value appended
+     */
+    private void getPnameCommand(Commandline cmd) {
+        if (getPname() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_PNAME);
+            cmd.createArgument().setValue(getPname());
+        }
+    }
+
+    /**
+     * Return which object/pname is being operated on
+     *
+     * @return String containing the object/pname being worked on
+     */
+    private String getOpType() {
+
+        if (getPname() != null) {
+            return getPname();
+        } else {
+            return getObjSelect();
+        }
+    }
+
+    /**
+     * -comment flag -- method to use for commenting events
+     */
+    public static final String FLAG_COMMENT = "-comment";
+    /**
+     * -pname flag -- pathname to lock
+     */
+    public static final String FLAG_PNAME = "-pname";
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java
new file mode 100644
index 0000000..712efdc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/CCUpdate.java
@@ -0,0 +1,331 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs a ClearCase Update command.
+ *
+ * <p>
+ * The following attributes are interpreted:
+ * <table border="1">
+ *   <tr>
+ *     <th>Attribute</th>
+ *     <th>Values</th>
+ *     <th>Required</th>
+ *   </tr>
+ *   <tr>
+ *      <td>viewpath</td>
+ *      <td>Path to the ClearCase view file or directory that the command will operate on</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>graphical</td>
+ *      <td>Displays a graphical dialog during the update</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>log</td>
+ *      <td>Specifies a log file for ClearCase to write to</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>overwrite</td>
+ *      <td>Specifies whether to overwrite hijacked files or not</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>rename</td>
+ *      <td>Specifies that hijacked files should be renamed with a .keep extension</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>currenttime</td>
+ *      <td>Specifies that modification time should be written as the current
+ *          time. Either currenttime or preservetime can be specified.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>preservetime</td>
+ *      <td>Specifies that modification time should preserved from the VOB
+ *          time. Either currenttime or preservetime can be specified.</td>
+ *      <td>No</td>
+ *   <tr>
+ *   <tr>
+ *      <td>failonerr</td>
+ *      <td>Throw an exception if the command fails. Default is true</td>
+ *      <td>No</td>
+ *   <tr>
+ * </table>
+ *
+ */
+public class CCUpdate extends ClearCase {
+    private boolean mGraphical = false;
+    private boolean mOverwrite = false;
+    private boolean mRename = false;
+    private boolean mCtime = false;
+    private boolean mPtime = false;
+    private String mLog = null;
+
+    /**
+     * Executes the task.
+     * <p>
+     * Builds a command line to execute cleartool and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command fails and failonerr is set to true
+     */
+    public void execute() throws BuildException {
+        Commandline commandLine = new Commandline();
+        Project aProj = getProject();
+        int result = 0;
+
+        // Default the viewpath to basedir if it is not specified
+        if (getViewPath() == null) {
+            setViewPath(aProj.getBaseDir().getPath());
+        }
+
+        // build the command line from what we got the format is
+        // cleartool update [options...] [viewpath ...]
+        // as specified in the CLEARTOOL.EXE help
+        commandLine.setExecutable(getClearToolCommand());
+        commandLine.createArgument().setValue(COMMAND_UPDATE);
+
+        // Check the command line options
+        checkOptions(commandLine);
+
+        // For debugging
+        getProject().log(commandLine.toString(), Project.MSG_DEBUG);
+
+        if (!getFailOnErr()) {
+            getProject().log("Ignoring any errors that occur for: "
+                    + getViewPathBasename(), Project.MSG_VERBOSE);
+        }
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnErr()) {
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Check the command line options.
+     */
+    private void checkOptions(Commandline cmd) {
+        // ClearCase items
+        if (getGraphical()) {
+            // -graphical
+            cmd.createArgument().setValue(FLAG_GRAPHICAL);
+        } else {
+            if (getOverwrite()) {
+                // -overwrite
+                cmd.createArgument().setValue(FLAG_OVERWRITE);
+            } else {
+                if (getRename()) {
+                    // -rename
+                    cmd.createArgument().setValue(FLAG_RENAME);
+                } else {
+                    // -noverwrite
+                    cmd.createArgument().setValue(FLAG_NOVERWRITE);
+                }
+            }
+
+            if (getCurrentTime()) {
+                // -ctime
+                cmd.createArgument().setValue(FLAG_CURRENTTIME);
+            } else {
+                if (getPreserveTime()) {
+                    // -ptime
+                    cmd.createArgument().setValue(FLAG_PRESERVETIME);
+                }
+            }
+
+            // -log logname
+            getLogCommand(cmd);
+        }
+
+        // viewpath
+        cmd.createArgument().setValue(getViewPath());
+    }
+
+    /**
+     * If true, displays a graphical dialog during the update.
+     *
+     * @param graphical the status to set the flag to
+     */
+    public void setGraphical(boolean graphical) {
+        mGraphical = graphical;
+    }
+
+    /**
+     * Get graphical flag status
+     *
+     * @return boolean containing status of graphical flag
+     */
+    public boolean getGraphical() {
+        return mGraphical;
+    }
+
+    /**
+     * If true, overwrite hijacked files.
+     *
+     * @param ow the status to set the flag to
+     */
+    public void setOverwrite(boolean ow) {
+        mOverwrite = ow;
+    }
+
+    /**
+     * Get overwrite hijacked files status
+     *
+     * @return boolean containing status of overwrite flag
+     */
+    public boolean getOverwrite() {
+        return mOverwrite;
+    }
+
+    /**
+     * If true, hijacked files are renamed with a .keep extension.
+     *
+     * @param ren the status to set the flag to
+     */
+    public void setRename(boolean ren) {
+        mRename = ren;
+    }
+
+    /**
+     * Get rename hijacked files status
+     *
+     * @return boolean containing status of rename flag
+     */
+    public boolean getRename() {
+        return mRename;
+    }
+
+    /**
+     * If true, modification time should be written as the current time.
+     * Either currenttime or preservetime can be specified.
+     *
+     * @param ct the status to set the flag to
+     */
+    public void setCurrentTime(boolean ct) {
+        mCtime = ct;
+    }
+
+    /**
+     * Get current time status
+     *
+     * @return boolean containing status of current time flag
+     */
+    public boolean getCurrentTime() {
+        return mCtime;
+    }
+
+    /**
+     * If true, modification time should be preserved from the VOB time.
+     * Either currenttime or preservetime can be specified.
+     *
+     * @param pt the status to set the flag to
+     */
+    public void setPreserveTime(boolean pt) {
+        mPtime = pt;
+    }
+
+    /**
+     * Get preserve time status
+     *
+     * @return boolean containing status of preserve time flag
+     */
+    public boolean getPreserveTime() {
+        return mPtime;
+    }
+
+    /**
+     * Sets the log file where cleartool records
+     * the status of the command.
+     *
+     * @param log the path to the log file
+     */
+    public void setLog(String log) {
+        mLog = log;
+    }
+
+    /**
+     * Get log file
+     *
+     * @return String containing the path to the log file
+     */
+    public String getLog() {
+        return mLog;
+    }
+
+
+    /**
+     * Get the 'log' command
+     *
+     * @param cmd containing the command line string with or without the log flag and path appended
+     */
+    private void getLogCommand(Commandline cmd) {
+        if (getLog() == null) {
+            return;
+        } else {
+            /* Had to make two separate commands here because if a space is
+               inserted between the flag and the value, it is treated as a
+               Windows filename with a space and it is enclosed in double
+               quotes ("). This breaks clearcase.
+            */
+            cmd.createArgument().setValue(FLAG_LOG);
+            cmd.createArgument().setValue(getLog());
+        }
+    }
+
+    /**
+     *  -graphical flag -- display graphical dialog during update operation
+     */
+    public static final String FLAG_GRAPHICAL = "-graphical";
+    /**
+     * -log flag -- file to log status to
+     */
+    public static final String FLAG_LOG = "-log";
+    /**
+     * -overwrite flag -- overwrite hijacked files
+     */
+    public static final String FLAG_OVERWRITE = "-overwrite";
+    /**
+     * -noverwrite flag -- do not overwrite hijacked files
+     */
+    public static final String FLAG_NOVERWRITE = "-noverwrite";
+    /**
+     * -rename flag -- rename hijacked files with .keep extension
+     */
+    public static final String FLAG_RENAME = "-rename";
+    /**
+     * -ctime flag -- modified time is written as the current time
+     */
+    public static final String FLAG_CURRENTTIME = "-ctime";
+    /**
+     * -ptime flag -- modified time is written as the VOB time
+     */
+    public static final String FLAG_PRESERVETIME = "-ptime";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java
new file mode 100644
index 0000000..d9bed57
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/clearcase/ClearCase.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.clearcase;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+
+
+/**
+ * A base class for creating tasks for executing commands on ClearCase.
+ * <p>
+ * The class extends the 'exec' task as it operates by executing the cleartool program
+ * supplied with ClearCase. By default the task expects the cleartool executable to be
+ * in the path, * you can override this be specifying the cleartooldir attribute.
+ * </p>
+ * <p>
+ * This class provides set and get methods for the 'viewpath' and 'objselect'
+ * attribute. It also contains constants for the flags that can be passed to
+ * cleartool.
+ * </p>
+ *
+ */
+public abstract class ClearCase extends Task {
+    private String mClearToolDir = "";
+    private String mviewPath = null;
+    private String mobjSelect = null;
+    private static int pcnt = 0;
+    private boolean mFailonerr = true;
+    /**
+     * Set the directory where the cleartool executable is located.
+     *
+     * @param dir the directory containing the cleartool executable
+     */
+    public final void setClearToolDir(String dir) {
+        mClearToolDir = FileUtils.translatePath(dir);
+    }
+
+    /**
+     * Builds and returns the command string to execute cleartool
+     *
+     * @return String containing path to the executable
+     */
+    protected final String getClearToolCommand() {
+        String toReturn = mClearToolDir;
+        if (!toReturn.equals("") && !toReturn.endsWith("/")) {
+            toReturn += "/";
+        }
+
+        toReturn += CLEARTOOL_EXE;
+
+        return toReturn;
+    }
+
+    /**
+     * Set the path to the item in a ClearCase view to operate on.
+     *
+     * @param viewPath Path to the view directory or file
+     */
+    public final void setViewPath(String viewPath) {
+        mviewPath = viewPath;
+    }
+
+    /**
+     * Get the path to the item in a clearcase view
+     *
+     * @return mviewPath
+     */
+    public String getViewPath() {
+        return mviewPath;
+    }
+
+    /**
+     * Get the basename path of the item in a clearcase view
+     *
+     * @return basename
+     */
+    public String getViewPathBasename() {
+        return (new File(mviewPath)).getName();
+    }
+
+    /**
+     * Set the object to operate on.
+     *
+     * @param objSelect object to operate on
+     */
+    public final void setObjSelect(String objSelect) {
+        mobjSelect = objSelect;
+    }
+
+    /**
+     * Get the object to operate on
+     *
+     * @return mobjSelect
+     */
+    public String getObjSelect() {
+        return mobjSelect;
+    }
+
+    /**
+     * Execute the given command are return success or failure
+     * @param cmd command line to execute
+     * @return the exit status of the subprocess or <code>INVALID</code>
+     */
+    protected int run(Commandline cmd) {
+        try {
+            Project aProj = getProject();
+            Execute exe
+                = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
+            exe.setAntRun(aProj);
+            exe.setWorkingDirectory(aProj.getBaseDir());
+            exe.setCommandline(cmd.getCommandline());
+            return exe.execute();
+        } catch (java.io.IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+    /**
+     * Execute the given command, and return it's output
+     * @param cmdline command line to execute
+     * @return output of the command line
+     */
+    protected String runS(Commandline cmdline) {
+        String   outV  = "opts.cc.runS.output" + pcnt++;
+        ExecTask exe   = new ExecTask(this);
+        Commandline.Argument arg = exe.createArg();
+
+        exe.setExecutable(cmdline.getExecutable());
+        arg.setLine(Commandline.toString(cmdline.getArguments()));
+        exe.setOutputproperty(outV);
+        exe.execute();
+
+        return getProject().getProperty(outV);
+    }
+    /**
+     * If true, command will throw an exception on failure.
+     *
+     * @param failonerr the status to set the flag to
+     * @since ant 1.6.1
+     */
+    public void setFailOnErr(boolean failonerr) {
+        mFailonerr = failonerr;
+    }
+
+    /**
+     * Get failonerr flag status
+     *
+     * @return boolean containing status of failonerr flag
+     * @since ant 1.6.1
+     */
+    public boolean getFailOnErr() {
+        return mFailonerr;
+    }
+
+    /**
+     * Constant for the thing to execute
+     */
+    private static final String CLEARTOOL_EXE = "cleartool";
+    /**
+     * The 'Update' command
+     */
+    public static final String COMMAND_UPDATE = "update";
+    /**
+     * The 'Checkout' command
+     */
+    public static final String COMMAND_CHECKOUT = "checkout";
+    /**
+     * The 'Checkin' command
+     */
+    public static final String COMMAND_CHECKIN = "checkin";
+    /**
+     * The 'UndoCheckout' command
+     */
+    public static final String COMMAND_UNCHECKOUT = "uncheckout";
+    /**
+     * The 'Lock' command
+     */
+    public static final String COMMAND_LOCK = "lock";
+    /**
+     * The 'Unlock' command
+     */
+    public static final String COMMAND_UNLOCK = "unlock";
+    /**
+     * The 'Mkbl' command
+     */
+    public static final String COMMAND_MKBL = "mkbl";
+    /**
+     * The 'Mklabel' command
+     */
+    public static final String COMMAND_MKLABEL = "mklabel";
+    /**
+     * The 'Mklbtype' command
+     */
+    public static final String COMMAND_MKLBTYPE = "mklbtype";
+    /**
+     * The 'Rmtype' command
+     */
+    public static final String COMMAND_RMTYPE = "rmtype";
+    /**
+     * The 'LsCheckout' command
+     */
+    public static final String COMMAND_LSCO = "lsco";
+    /**
+     * The 'Mkelem' command
+     */
+    public static final String COMMAND_MKELEM = "mkelem";
+    /**
+     * The 'Mkattr' command
+     */
+    public static final String COMMAND_MKATTR = "mkattr";
+    /**
+     * The 'Mkdir' command
+     */
+    public static final String COMMAND_MKDIR = "mkdir";
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java
new file mode 100644
index 0000000..1500e68
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/AntAnalyzer.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * An analyzer which uses the depend task's bytecode classes to analyze
+ * dependencies
+ *
+ */
+public class AntAnalyzer extends AbstractAnalyzer {
+    /**
+     * Default constructor
+     */
+    public AntAnalyzer() {
+    }
+
+    /**
+     * Determine the dependencies of the configured root classes.
+     *
+     * @param files a vector to be populated with the files which contain
+     *      the dependency classes
+     * @param classes a vector to be populated with the names of the
+     *      dependency classes.
+     */
+    protected void determineDependencies(Vector files, Vector classes) {
+        // we get the root classes and build up a set of
+        // classes upon which they depend
+        Hashtable dependencies = new Hashtable();
+        Hashtable containers = new Hashtable();
+        Hashtable toAnalyze = new Hashtable();
+        for (Enumeration e = getRootClasses(); e.hasMoreElements();) {
+            String classname = (String) e.nextElement();
+            toAnalyze.put(classname, classname);
+        }
+
+        int count = 0;
+        int maxCount = isClosureRequired() ? MAX_LOOPS : 1;
+        Hashtable analyzedDeps = null;
+        while (toAnalyze.size() != 0 && count++ < maxCount) {
+            analyzedDeps = new Hashtable();
+            for (Enumeration e = toAnalyze.keys(); e.hasMoreElements();) {
+                String classname = (String) e.nextElement();
+                dependencies.put(classname, classname);
+                try {
+                    File container = getClassContainer(classname);
+                    if (container == null) {
+                        continue;
+                    }
+                    containers.put(container, container);
+
+                    ZipFile zipFile = null;
+                    InputStream inStream = null;
+                    try {
+                        if (container.getName().endsWith(".class")) {
+                            inStream = new FileInputStream(container.getPath());
+                        } else {
+                            zipFile = new ZipFile(container.getPath());
+                            String entryName
+                                = classname.replace('.', '/') + ".class";
+                            ZipEntry entry = new ZipEntry(entryName);
+                            inStream
+                                = zipFile.getInputStream(entry);
+                        }
+                        ClassFile classFile = new ClassFile();
+                        classFile.read(inStream);
+                        Vector dependencyList = classFile.getClassRefs();
+                        Enumeration depEnum = dependencyList.elements();
+                        while (depEnum.hasMoreElements()) {
+                            String dependency = (String) depEnum.nextElement();
+                            analyzedDeps.put(dependency, dependency);
+                        }
+                    } finally {
+                        if (inStream != null) {
+                            inStream.close();
+                        }
+                        if (zipFile != null) {
+                            zipFile.close();
+                        }
+                    }
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+
+            toAnalyze.clear();
+
+            // now recover all the dependencies collected and add to the list.
+            Enumeration depsEnum = analyzedDeps.elements();
+            while (depsEnum.hasMoreElements()) {
+                String className = (String) depsEnum.nextElement();
+                if (!dependencies.containsKey(className)) {
+                    toAnalyze.put(className, className);
+                }
+            }
+        }
+
+        // pick up the last round of dependencies that were determined
+        Enumeration depsEnum = analyzedDeps.elements();
+        while (depsEnum.hasMoreElements()) {
+            String className = (String) depsEnum.nextElement();
+            dependencies.put(className, className);
+        }
+
+        files.removeAllElements();
+        for (Enumeration e = containers.keys(); e.hasMoreElements();) {
+            files.addElement((File) e.nextElement());
+        }
+
+        classes.removeAllElements();
+        for (Enumeration e = dependencies.keys(); e.hasMoreElements();) {
+            classes.addElement((String) e.nextElement());
+        }
+    }
+
+    /**
+     * Indicate if this analyzer can determine dependent files.
+     *
+     * @return true if the analyzer provides dependency file information.
+     */
+    protected boolean supportsFileDependencies() {
+        return true;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java
new file mode 100644
index 0000000..1f0c2d8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFile.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ClassCPInfo;
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPool;
+import org.apache.tools.ant.taskdefs.optional.depend.constantpool.ConstantPoolEntry;
+
+/**
+ * A ClassFile object stores information about a Java class. The class may
+ * be read from a DataInputStream.and written to a DataOutputStream. These
+ * are usually streams from a Java class file or a class file component of a
+ * Jar file.
+ *
+ */
+public class ClassFile {
+
+    /** The Magic Value that marks the start of a Java class file  */
+    private static final int CLASS_MAGIC = 0xCAFEBABE;
+
+    /** This class' constant pool.  */
+    private ConstantPool constantPool;
+
+    /** The class name for this class.  */
+    private String className;
+
+    /**
+     * Read the class from a data stream. This method takes an InputStream
+     * as input and parses the class from the stream. <p>
+     *
+     *
+     *
+     * @param stream an InputStream from which the class will be read
+     * @exception IOException if there is a problem reading from the given
+     *      stream.
+     * @exception ClassFormatError if the class cannot be parsed correctly
+     */
+    public void read(InputStream stream) throws IOException, ClassFormatError {
+        DataInputStream classStream = new DataInputStream(stream);
+
+        if (classStream.readInt() != CLASS_MAGIC) {
+            throw new ClassFormatError("No Magic Code Found "
+                + "- probably not a Java class file.");
+        }
+
+        // right we have a good looking class file.
+        /* int minorVersion = */ classStream.readUnsignedShort();
+        /* int majorVersion = */ classStream.readUnsignedShort();
+
+        // read the constant pool in and resolve it
+        constantPool = new ConstantPool();
+
+        constantPool.read(classStream);
+        constantPool.resolve();
+
+        /* int accessFlags = */ classStream.readUnsignedShort();
+        int thisClassIndex = classStream.readUnsignedShort();
+        /* int superClassIndex = */ classStream.readUnsignedShort();
+        ClassCPInfo classInfo
+            = (ClassCPInfo) constantPool.getEntry(thisClassIndex);
+        className  = classInfo.getClassName();
+    }
+
+
+    /**
+     * Get the classes which this class references.
+     *
+     * @return a vector of class names which this class references
+     */
+    public Vector getClassRefs() {
+
+        Vector classRefs = new Vector();
+
+        for (int i = 0; i < constantPool.size(); ++i) {
+            ConstantPoolEntry entry = constantPool.getEntry(i);
+
+            if (entry != null
+                && entry.getTag() == ConstantPoolEntry.CONSTANT_CLASS) {
+                ClassCPInfo classEntry = (ClassCPInfo) entry;
+
+                if (!classEntry.getClassName().equals(className)) {
+                    classRefs.addElement(
+                        ClassFileUtils.convertSlashName(classEntry.getClassName()));
+                }
+            }
+        }
+
+        return classRefs;
+    }
+
+    /**
+     * Get the class' fully qualified name in dot format.
+     *
+     * @return the class name in dot format (eg. java.lang.Object)
+     */
+    public String getFullClassName() {
+        return ClassFileUtils.convertSlashName(className);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java
new file mode 100644
index 0000000..92fc191
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileIterator.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+/**
+ * Iterator interface for iterating over a set of class files
+ *
+ */
+public interface ClassFileIterator {
+
+    /**
+     * Get the next class file in the iteration
+     *
+     * @return the next class file in the iteration
+     */
+    ClassFile getNextClassFile();
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java
new file mode 100644
index 0000000..c6eec6c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/ClassFileUtils.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+/**
+ * Utility class file routines. This class provides a number of static
+ * utility methods to convert between the formats used in the Java class
+ * file format and those commonly used in Java programming.
+ *
+ *
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class ClassFileUtils {
+
+    /**
+     * Convert a class name from class file slash notation to java source
+     * file dot notation.
+     *
+     * @param name the class name in slash notation org/apache/ant
+     * @return the class name in dot notation (eg. java.lang.Object).
+     */
+    public static String convertSlashName(String name) {
+        return name.replace('\\', '.').replace('/', '.');
+    }
+
+    /**
+     * Convert a class name from java source file dot notation to class file
+     * slash notation..
+     *
+     * @param dotName the class name in dot notation (eg. java.lang.Object).
+     * @return the class name in slash notation (eg. java/lang/Object).
+     */
+    public static String convertDotName(String dotName) {
+        return dotName.replace('.', '/');
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java
new file mode 100644
index 0000000..9bb8663
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java
@@ -0,0 +1,889 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.rmic.DefaultRmicAdapter;
+import org.apache.tools.ant.taskdefs.rmic.WLRmic;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
+
+/**
+ * Generates a dependency file for a given set of classes.
+ *
+ */
+public class Depend extends MatchingTask {
+    private static final int ONE_SECOND = 1000;
+
+    /**
+     * A class (struct) user to manage information about a class
+     *
+     */
+    private static class ClassFileInfo {
+        /** The file where the class file is stored in the file system */
+        private File absoluteFile;
+
+        /** The Java class name of this class */
+        private String className;
+
+        /** The source File containing this class */
+        private File sourceFile;
+
+        /** if user has been warned about this file not having a source file */
+        private boolean isUserWarned = false;
+    }
+
+    /** The path where source files exist */
+    private Path srcPath;
+
+    /** The path where compiled class files exist. */
+    private Path destPath;
+
+    /** The directory which contains the dependency cache. */
+    private File cache;
+
+    /** The list of source paths derived from the srcPath field. */
+    private String[] srcPathList;
+
+    /**
+     * A map which gives for every class a list of the class which it
+     * affects.
+     */
+    private Hashtable affectedClassMap;
+
+    /** A map which gives information about a class */
+    private Hashtable classFileInfoMap;
+
+    /**
+     * A map which gives the list of jars and classes from the classpath
+     * that a class depends upon
+     */
+    private Hashtable classpathDependencies;
+
+    /** The list of classes which are out of date. */
+    private Hashtable outOfDateClasses;
+
+    /**
+     * indicates that the dependency relationships should be extended beyond
+     * direct dependencies to include all classes. So if A directly affects
+     * B and B directly affects C, then A indirectly affects C.
+     */
+    private boolean closure = false;
+
+    /**
+     * flag to enable warning if we encounter RMI stubs
+     */
+    private boolean warnOnRmiStubs = true;
+
+    /**
+     * Flag which controls whether the reversed dependencies should be
+     * dumped to the log
+     */
+    private boolean dump = false;
+
+    /** The classpath to look for additional dependencies */
+    private Path dependClasspath;
+
+    /** constants used with the cache file */
+    private static final String CACHE_FILE_NAME = "dependencies.txt";
+    /** String Used to separate classnames in the dependency file */
+    private static final String CLASSNAME_PREPEND = "||:";
+
+    /**
+     * Set the classpath to be used for this dependency check.
+     *
+     * @param classpath the classpath to be used when checking for
+     *      dependencies on elements in the classpath
+     */
+    public void setClasspath(Path classpath) {
+        if (dependClasspath == null) {
+            dependClasspath = classpath;
+        } else {
+            dependClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Gets the classpath to be used for this dependency check.
+     *
+     * @return the current dependency classpath
+     */
+    public Path getClasspath() {
+        return dependClasspath;
+    }
+
+    /**
+     * Adds a classpath to be used for this dependency check.
+     *
+     * @return A path object to be configured by Ant
+     */
+    public Path createClasspath() {
+        if (dependClasspath == null) {
+            dependClasspath = new Path(getProject());
+        }
+        return dependClasspath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     *
+     * @param r a reference to a path object to be used as the depend
+     *      classpath
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Flag to set to true if you want dependency issues with RMI
+     * stubs to appear at warning level.
+     * @param warnOnRmiStubs if true set dependency issues to appear at warning level.
+     * @since Ant1.7
+     */
+    public void setWarnOnRmiStubs(boolean warnOnRmiStubs) {
+        this.warnOnRmiStubs = warnOnRmiStubs;
+    }
+
+    /**
+     * Read the dependencies from cache file
+     *
+     * @return a collection of class dependencies
+     * @exception IOException if the dependency file cannot be read
+     */
+    private Hashtable readCachedDependencies(File depFile) throws IOException {
+        Hashtable dependencyMap = new Hashtable();
+
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader(depFile));
+            String line = null;
+            Vector dependencyList = null;
+            String className = null;
+            int prependLength = CLASSNAME_PREPEND.length();
+            while ((line = in.readLine()) != null) {
+                if (line.startsWith(CLASSNAME_PREPEND)) {
+                    dependencyList = new Vector();
+                    className = line.substring(prependLength);
+                    dependencyMap.put(className, dependencyList);
+                } else {
+                    dependencyList.addElement(line);
+                }
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+
+        return dependencyMap;
+    }
+
+    /**
+     * Write the dependencies to cache file
+     *
+     * @param dependencyMap the map of dependencies to be written out.
+     * @exception IOException if the dependency file cannot be written out.
+     */
+    private void writeCachedDependencies(Hashtable dependencyMap)
+         throws IOException {
+        if (cache != null) {
+            PrintWriter pw = null;
+            try {
+                cache.mkdirs();
+                File depFile = new File(cache, CACHE_FILE_NAME);
+
+                pw = new PrintWriter(new FileWriter(depFile));
+                Enumeration e = dependencyMap.keys();
+                while (e.hasMoreElements()) {
+                    String className = (String) e.nextElement();
+
+                    pw.println(CLASSNAME_PREPEND + className);
+
+                    Vector dependencyList
+                         = (Vector) dependencyMap.get(className);
+                    int size = dependencyList.size();
+                    for (int x = 0; x < size; x++) {
+                        pw.println(dependencyList.elementAt(x));
+                    }
+                }
+            } finally {
+                if (pw != null) {
+                    pw.close();
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the classpath for dependency checking.
+     *
+     * This method removes the dest dirs if it is given from the dependency classpath
+     */
+    private Path getCheckClassPath() {
+        if (dependClasspath == null) {
+            return null;
+        }
+
+        String[] destPathElements = destPath.list();
+        String[] classpathElements = dependClasspath.list();
+        String checkPath = "";
+        for (int i = 0; i < classpathElements.length; ++i) {
+            String element = classpathElements[i];
+            boolean inDestPath = false;
+            for (int j = 0; j < destPathElements.length && !inDestPath; ++j) {
+                inDestPath = destPathElements[j].equals(element);
+            }
+            if (!inDestPath) {
+                if (checkPath.length() == 0) {
+                    checkPath = element;
+                } else {
+                    checkPath += ":" + element;
+                }
+            }
+        }
+
+        if (checkPath.length() == 0) {
+            return null;
+        }
+
+        return new Path(getProject(), checkPath);
+    }
+
+    /**
+     * Determine the dependencies between classes. Class dependencies are
+     * determined by examining the class references in a class file to other
+     * classes.
+     *
+     * This method sets up the following fields
+     * <ul>
+     *   <li>affectedClassMap - the list of classes each class affects</li>
+     *   <li>classFileInfoMap - information about each class</li>
+     *   <li>classpathDependencies - the list of jars and classes from the
+     *                             classpath that each class depends upon.</li>
+     * </ul>
+     *
+     * If required, the dependencies are written to the cache.
+     *
+     * @exception IOException if either the dependencies cache or the class
+     *      files cannot be read or written
+     */
+    private void determineDependencies() throws IOException {
+        affectedClassMap = new Hashtable();
+        classFileInfoMap = new Hashtable();
+        boolean cacheDirty = false;
+
+        Hashtable dependencyMap = new Hashtable();
+        File cacheFile = null;
+        boolean cacheFileExists = true;
+        long cacheLastModified = Long.MAX_VALUE;
+
+        // read the dependency cache from the disk
+        if (cache != null) {
+            cacheFile = new File(cache, CACHE_FILE_NAME);
+            cacheFileExists = cacheFile.exists();
+            cacheLastModified = cacheFile.lastModified();
+            if (cacheFileExists) {
+                dependencyMap = readCachedDependencies(cacheFile);
+            }
+        }
+        Enumeration classfileEnum = getClassFiles(destPath).elements();
+        while (classfileEnum.hasMoreElements()) {
+            ClassFileInfo info = (ClassFileInfo) classfileEnum.nextElement();
+            log("Adding class info for " + info.className, Project.MSG_DEBUG);
+            classFileInfoMap.put(info.className, info);
+
+            Vector dependencyList = null;
+
+            if (cache != null) {
+                // try to read the dependency info from the map if it is
+                // not out of date
+                if (cacheFileExists
+                    && cacheLastModified > info.absoluteFile.lastModified()) {
+                    // depFile exists and is newer than the class file
+                    // need to get dependency list from the map.
+                    dependencyList = (Vector) dependencyMap.get(info.className);
+                }
+            }
+
+            if (dependencyList == null) {
+                // not cached - so need to read directly from the class file
+                DependencyAnalyzer analyzer = new AntAnalyzer();
+                analyzer.addRootClass(info.className);
+                analyzer.addClassPath(destPath);
+                analyzer.setClosure(false);
+                dependencyList = new Vector();
+                Enumeration depEnum = analyzer.getClassDependencies();
+                while (depEnum.hasMoreElements()) {
+                    dependencyList.addElement(depEnum.nextElement());
+                }
+                cacheDirty = true;
+                dependencyMap.put(info.className, dependencyList);
+            }
+
+            // This class depends on each class in the dependency list. For each
+            // one of those, add this class into their affected classes list
+            Enumeration depEnum = dependencyList.elements();
+            while (depEnum.hasMoreElements()) {
+                String dependentClass = (String) depEnum.nextElement();
+
+                Hashtable affectedClasses
+                    = (Hashtable) affectedClassMap.get(dependentClass);
+                if (affectedClasses == null) {
+                    affectedClasses = new Hashtable();
+                    affectedClassMap.put(dependentClass, affectedClasses);
+                }
+
+                affectedClasses.put(info.className, info);
+            }
+        }
+
+        classpathDependencies = null;
+        Path checkPath = getCheckClassPath();
+        if (checkPath != null) {
+            // now determine which jars each class depends upon
+            classpathDependencies = new Hashtable();
+            AntClassLoader loader = getProject().createClassLoader(checkPath);
+
+            Hashtable classpathFileCache = new Hashtable();
+            Object nullFileMarker = new Object();
+            for (Enumeration e = dependencyMap.keys(); e.hasMoreElements();) {
+                String className = (String) e.nextElement();
+                Vector dependencyList = (Vector) dependencyMap.get(className);
+                Hashtable dependencies = new Hashtable();
+                classpathDependencies.put(className, dependencies);
+                Enumeration e2 = dependencyList.elements();
+                while (e2.hasMoreElements()) {
+                    String dependency = (String) e2.nextElement();
+                    Object classpathFileObject
+                        = classpathFileCache.get(dependency);
+                    if (classpathFileObject == null) {
+                        classpathFileObject = nullFileMarker;
+
+                        if (!dependency.startsWith("java.")
+                            && !dependency.startsWith("javax.")) {
+                            URL classURL
+                                = loader.getResource(dependency.replace('.', '/') + ".class");
+                            if (classURL != null) {
+                                if (classURL.getProtocol().equals("jar")) {
+                                    String jarFilePath = classURL.getFile();
+                                    int classMarker = jarFilePath.indexOf('!');
+                                    jarFilePath = jarFilePath.substring(0, classMarker);
+                                    if (jarFilePath.startsWith("file:")) {
+                                        classpathFileObject = new File(
+                                            FileUtils.getFileUtils().fromURI(jarFilePath));
+                                    } else {
+                                        throw new IOException(
+                                            "Bizarre nested path in jar: protocol: "
+                                            + jarFilePath);
+                                    }
+                                } else if (classURL.getProtocol().equals("file")) {
+                                    classpathFileObject = new File(
+                                        FileUtils.getFileUtils()
+                                        .fromURI(classURL.toExternalForm()));
+                                }
+                                log("Class " + className
+                                    + " depends on " + classpathFileObject
+                                    + " due to " + dependency, Project.MSG_DEBUG);
+                            }
+                        }
+                        classpathFileCache.put(dependency, classpathFileObject);
+                    }
+                    if (classpathFileObject != nullFileMarker) {
+                        // we need to add this jar to the list for this class.
+                        File jarFile = (File) classpathFileObject;
+                        dependencies.put(jarFile, jarFile);
+                    }
+                }
+            }
+        }
+
+        // write the dependency cache to the disk
+        if (cache != null && cacheDirty) {
+            writeCachedDependencies(dependencyMap);
+        }
+    }
+
+    /**
+     * Delete all the class files which are out of date, by way of their
+     * dependency on a class which is out of date
+     *
+     * @return the number of files deleted.
+     */
+    private int deleteAllAffectedFiles() {
+        int count = 0;
+        for (Enumeration e = outOfDateClasses.elements(); e.hasMoreElements();) {
+            String className = (String) e.nextElement();
+            count += deleteAffectedFiles(className);
+            ClassFileInfo classInfo
+                = (ClassFileInfo) classFileInfoMap.get(className);
+            if (classInfo != null && classInfo.absoluteFile.exists()) {
+                classInfo.absoluteFile.delete();
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Delete all the class files of classes which depend on the given class
+     *
+     * @param className the name of the class whose dependent classes will be
+     *      deleted
+     * @return the number of class files removed
+     */
+    private int deleteAffectedFiles(String className) {
+        int count = 0;
+
+        Hashtable affectedClasses = (Hashtable) affectedClassMap.get(className);
+        if (affectedClasses == null) {
+            return count;
+        }
+        for (Enumeration e = affectedClasses.keys(); e.hasMoreElements();) {
+            String affectedClass = (String) e.nextElement();
+            ClassFileInfo affectedClassInfo
+                = (ClassFileInfo) affectedClasses.get(affectedClass);
+
+            if (!affectedClassInfo.absoluteFile.exists()) {
+                continue;
+            }
+
+            if (affectedClassInfo.sourceFile == null) {
+                warnOutOfDateButNotDeleted(affectedClassInfo, affectedClass, className);
+                continue;
+            }
+
+            log("Deleting file " + affectedClassInfo.absoluteFile.getPath()
+                + " since " + className + " out of date", Project.MSG_VERBOSE);
+
+            affectedClassInfo.absoluteFile.delete();
+            count++;
+            if (closure) {
+                count += deleteAffectedFiles(affectedClass);
+            } else {
+                // without closure we may delete an inner class but not the
+                // top level class which would not trigger a recompile.
+
+                if (affectedClass.indexOf("$") == -1) {
+                    continue;
+                }
+                // need to delete the main class
+                String topLevelClassName
+                     = affectedClass.substring(0, affectedClass.indexOf("$"));
+                log("Top level class = " + topLevelClassName,
+                    Project.MSG_VERBOSE);
+                ClassFileInfo topLevelClassInfo
+                     = (ClassFileInfo) classFileInfoMap.get(topLevelClassName);
+                if (topLevelClassInfo != null
+                    && topLevelClassInfo.absoluteFile.exists()) {
+                    log("Deleting file "
+                        + topLevelClassInfo.absoluteFile.getPath()
+                        + " since one of its inner classes was removed",
+                        Project.MSG_VERBOSE);
+                    topLevelClassInfo.absoluteFile.delete();
+                    count++;
+                    if (closure) {
+                        count += deleteAffectedFiles(topLevelClassName);
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    /**
+     * warn when a class is out of date, but not deleted as its source is unknown.
+     * MSG_WARN is the normal level, but we downgrade to MSG_VERBOSE for RMI files
+     * if {@link #warnOnRmiStubs is false}
+     * @param affectedClassInfo info about the affectd class
+     * @param affectedClass the name of the affected .class file
+     * @param className the file that is triggering the out of dateness
+     */
+    private void warnOutOfDateButNotDeleted(
+            ClassFileInfo affectedClassInfo, String affectedClass,
+            String className) {
+        if (affectedClassInfo.isUserWarned) {
+            return;
+        }
+        int level = Project.MSG_WARN;
+        if (!warnOnRmiStubs) {
+            //downgrade warnings on RMI stublike classes, as they are generated
+            //by rmic, so there is no need to tell the user that their source is
+            //missing.
+            if (isRmiStub(affectedClass, className)) {
+                level = Project.MSG_VERBOSE;
+            }
+        }
+        log("The class " + affectedClass + " in file "
+            + affectedClassInfo.absoluteFile.getPath()
+            + " is out of date due to " + className
+            + " but has not been deleted because its source file"
+            + " could not be determined", level);
+        affectedClassInfo.isUserWarned = true;
+    }
+
+    /**
+     * test for being an RMI stub
+     * @param affectedClass  class being tested
+     * @param className      possible origin of the RMI stub
+     * @return whether the class affectedClass is a RMI stub
+     */
+    private boolean isRmiStub(String affectedClass, String className) {
+        return isStub(affectedClass, className, DefaultRmicAdapter.RMI_STUB_SUFFIX)
+                || isStub(affectedClass, className, DefaultRmicAdapter.RMI_SKEL_SUFFIX)
+                || isStub(affectedClass, className, WLRmic.RMI_STUB_SUFFIX)
+                || isStub(affectedClass, className, WLRmic.RMI_SKEL_SUFFIX);
+    }
+
+    private boolean isStub(String affectedClass, String baseClass, String suffix) {
+        return (baseClass + suffix).equals(affectedClass);
+    }
+
+    /**
+     * Dump the dependency information loaded from the classes to the Ant log
+     */
+    private void dumpDependencies() {
+        log("Reverse Dependency Dump for " + affectedClassMap.size()
+            + " classes:", Project.MSG_DEBUG);
+
+        Enumeration classEnum = affectedClassMap.keys();
+        while (classEnum.hasMoreElements()) {
+            String className = (String) classEnum.nextElement();
+            log(" Class " + className + " affects:", Project.MSG_DEBUG);
+            Hashtable affectedClasses
+                = (Hashtable) affectedClassMap.get(className);
+            Enumeration affectedClassEnum = affectedClasses.keys();
+            while (affectedClassEnum.hasMoreElements()) {
+                String affectedClass = (String) affectedClassEnum.nextElement();
+                ClassFileInfo info
+                    = (ClassFileInfo) affectedClasses.get(affectedClass);
+                log("    " + affectedClass + " in "
+                    + info.absoluteFile.getPath(), Project.MSG_DEBUG);
+            }
+        }
+
+        if (classpathDependencies != null) {
+            log("Classpath file dependencies (Forward):", Project.MSG_DEBUG);
+
+            Enumeration classpathEnum = classpathDependencies.keys();
+            while (classpathEnum.hasMoreElements()) {
+                String className = (String) classpathEnum.nextElement();
+                log(" Class " + className + " depends on:", Project.MSG_DEBUG);
+                Hashtable dependencies
+                    = (Hashtable) classpathDependencies.get(className);
+
+                Enumeration classpathFileEnum = dependencies.elements();
+                while (classpathFileEnum.hasMoreElements()) {
+                    File classpathFile = (File) classpathFileEnum.nextElement();
+                    log("    " + classpathFile.getPath(), Project.MSG_DEBUG);
+                }
+            }
+        }
+    }
+
+    private void determineOutOfDateClasses() {
+        outOfDateClasses = new Hashtable();
+        for (int i = 0; i < srcPathList.length; i++) {
+            File srcDir = getProject().resolveFile(srcPathList[i]);
+            if (srcDir.exists()) {
+                DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+                String[] files = ds.getIncludedFiles();
+                scanDir(srcDir, files);
+            }
+        }
+
+        // now check classpath file dependencies
+        if (classpathDependencies == null) {
+            return;
+        }
+
+        Enumeration classpathDepsEnum = classpathDependencies.keys();
+        while (classpathDepsEnum.hasMoreElements()) {
+            String className = (String) classpathDepsEnum.nextElement();
+            if (outOfDateClasses.containsKey(className)) {
+                continue;
+            }
+            ClassFileInfo info
+                = (ClassFileInfo) classFileInfoMap.get(className);
+
+            // if we have no info about the class - it may have been deleted already and we
+            // are using cached info.
+            if (info != null) {
+                Hashtable dependencies
+                    = (Hashtable) classpathDependencies.get(className);
+                for (Enumeration e2 = dependencies.elements(); e2.hasMoreElements();) {
+                    File classpathFile = (File) e2.nextElement();
+                    if (classpathFile.lastModified()
+                        > info.absoluteFile.lastModified()) {
+                        log("Class " + className
+                            + " is out of date with respect to "
+                            + classpathFile, Project.MSG_DEBUG);
+                        outOfDateClasses.put(className, className);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException Thrown in case of an unrecoverable error.
+     */
+    public void execute() throws BuildException {
+        try {
+            long start = System.currentTimeMillis();
+            if (srcPath == null) {
+                throw new BuildException("srcdir attribute must be set",
+                                         getLocation());
+            }
+
+            srcPathList = srcPath.list();
+            if (srcPathList.length == 0) {
+                throw new BuildException("srcdir attribute must be non-empty",
+                                         getLocation());
+            }
+
+            if (destPath == null) {
+                destPath = srcPath;
+            }
+
+            if (cache != null && cache.exists() && !cache.isDirectory()) {
+                throw new BuildException("The cache, if specified, must "
+                    + "point to a directory");
+            }
+
+            if (cache != null && !cache.exists()) {
+                cache.mkdirs();
+            }
+
+            determineDependencies();
+            if (dump) {
+                dumpDependencies();
+            }
+            determineOutOfDateClasses();
+            int count = deleteAllAffectedFiles();
+
+            long duration = (System.currentTimeMillis() - start) / ONE_SECOND;
+
+            final int summaryLogLevel;
+            if (count > 0) {
+                summaryLogLevel = Project.MSG_INFO;
+            }  else {
+                summaryLogLevel = Project.MSG_DEBUG;
+            }
+
+            log("Deleted " + count + " out of date files in "
+                + duration + " seconds", summaryLogLevel);
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Scans the directory looking for source files that are newer than
+     * their class files. The results are returned in the class variable
+     * compileList
+     *
+     * @param srcDir the source directory
+     * @param files the names of the files in the source dir which are to be
+     *      checked.
+     */
+    protected void scanDir(File srcDir, String[] files) {
+
+        for (int i = 0; i < files.length; i++) {
+            File srcFile = new File(srcDir, files[i]);
+            if (files[i].endsWith(".java")) {
+                String filePath = srcFile.getPath();
+                String className
+                    = filePath.substring(srcDir.getPath().length() + 1,
+                        filePath.length() - ".java".length());
+                className = ClassFileUtils.convertSlashName(className);
+                ClassFileInfo info
+                    = (ClassFileInfo) classFileInfoMap.get(className);
+                if (info == null) {
+                    // there was no class file. add this class to the list
+                    outOfDateClasses.put(className, className);
+                } else {
+                    if (srcFile.lastModified()
+                        > info.absoluteFile.lastModified()) {
+                        outOfDateClasses.put(className, className);
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Get the list of class files we are going to analyse.
+     *
+     * @param classLocations a path structure containing all the directories
+     *      where classes can be found.
+     * @return a vector containing the classes to analyse.
+     */
+    private Vector getClassFiles(Path classLocations) {
+        // break the classLocations into its components.
+        String[] classLocationsList = classLocations.list();
+
+        Vector classFileList = new Vector();
+
+        for (int i = 0; i < classLocationsList.length; ++i) {
+            File dir = new File(classLocationsList[i]);
+            if (dir.isDirectory()) {
+                addClassFiles(classFileList, dir, dir);
+            }
+        }
+
+        return classFileList;
+    }
+
+    /**
+     * Find the source file for a given class
+     *
+     * @param classname the classname in slash format.
+     * @param sourceFileKnownToExist if not null, a file already known to exist
+     *                               (saves call to .exists())
+     */
+    private File findSourceFile(String classname, File sourceFileKnownToExist) {
+        String sourceFilename;
+        int innerIndex = classname.indexOf("$");
+        if (innerIndex != -1) {
+            sourceFilename = classname.substring(0, innerIndex) + ".java";
+        } else {
+            sourceFilename = classname + ".java";
+        }
+
+        // search the various source path entries
+        for (int i = 0; i < srcPathList.length; ++i) {
+            File sourceFile = new File(srcPathList[i], sourceFilename);
+            if (sourceFile.equals(sourceFileKnownToExist) || sourceFile.exists()) {
+                return sourceFile;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Add the list of class files from the given directory to the class
+     * file vector, including any subdirectories.
+     *
+     * @param classFileList a list of ClassFileInfo objects for all the
+     *      files in the directory tree
+     * @param dir the directory tree to be searched, recursively, for class
+     *      files
+     * @param root the root of the source tree. This is used to determine
+     *      the absolute class name from the relative position in the
+     *      source tree
+     */
+    private void addClassFiles(Vector classFileList, File dir, File root) {
+        String[] filesInDir = dir.list();
+
+        if (filesInDir == null) {
+            return;
+        }
+        int length = filesInDir.length;
+
+        int rootLength = root.getPath().length();
+        File sourceFileKnownToExist = null; // speed optimization
+        for (int i = 0; i < length; ++i) {
+            File file = new File(dir, filesInDir[i]);
+            if (filesInDir[i].endsWith(".class")) {
+                ClassFileInfo info = new ClassFileInfo();
+                info.absoluteFile = file;
+                String relativeName = file.getPath().substring(
+                    rootLength + 1,
+                    file.getPath().length() - ".class".length());
+                info.className
+                    = ClassFileUtils.convertSlashName(relativeName);
+                info.sourceFile = sourceFileKnownToExist = findSourceFile(
+                    relativeName, sourceFileKnownToExist);
+                classFileList.addElement(info);
+            } else {
+                addClassFiles(classFileList, file, root);
+            }
+        }
+    }
+
+
+    /**
+     * Set the directories path to find the Java source files.
+     *
+     * @param srcPath the source path
+     */
+    public void setSrcdir(Path srcPath) {
+        this.srcPath = srcPath;
+    }
+
+    /**
+     * Set the destination directory where the compiled Java files exist.
+     *
+     * @param destPath the destination areas where build files are written
+     */
+    public void setDestDir(Path destPath) {
+        this.destPath = destPath;
+    }
+
+    /**
+     * Sets the dependency cache file.
+     *
+     * @param cache the dependency cache file
+     */
+    public void setCache(File cache) {
+        this.cache = cache;
+    }
+
+    /**
+     * If true, transitive dependencies are followed until the
+     * closure of the dependency set if reached.
+     * When not set, the depend task will only follow
+     * direct dependencies between classes.
+     *
+     * @param closure indicate if dependency closure is required.
+     */
+    public void setClosure(boolean closure) {
+        this.closure = closure;
+    }
+
+    /**
+     * If true, the dependency information will be written
+     * to the debug level log.
+     *
+     * @param dump set to true to dump dependency information to the log
+     */
+    public void setDump(boolean dump) {
+        this.dump = dump;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java
new file mode 100644
index 0000000..ebf244a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/DirectoryIterator.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * An iterator which iterates through the contents of a java directory. The
+ * iterator should be created with the directory at the root of the Java
+ * namespace.
+ *
+ */
+public class DirectoryIterator implements ClassFileIterator {
+
+    /**
+     * This is a stack of current iterators supporting the depth first
+     * traversal of the directory tree.
+     */
+    private Stack enumStack;
+
+    /**
+     * The current directory iterator. As directories encounter lower level
+     * directories, the current iterator is pushed onto the iterator stack
+     * and a new iterator over the sub directory becomes the current
+     * directory. This implements a depth first traversal of the directory
+     * namespace.
+     */
+    private Enumeration currentEnum;
+
+    /**
+     * Creates a directory iterator. The directory iterator is created to
+     * scan the root directory. If the changeInto flag is given, then the
+     * entries returned will be relative to this directory and not the
+     * current directory.
+     *
+     * @param rootDirectory the root if the directory namespace which is to
+     *      be iterated over
+     * @param changeInto if true then the returned entries will be relative
+     *      to the rootDirectory and not the current directory.
+     * @exception IOException if there is a problem reading the directory
+     *      information.
+     */
+    public DirectoryIterator(File rootDirectory, boolean changeInto)
+         throws IOException {
+        super();
+
+        enumStack = new Stack();
+
+        Vector filesInRoot = getDirectoryEntries(rootDirectory);
+
+        currentEnum = filesInRoot.elements();
+    }
+
+    /**
+     * Get a vector covering all the entries (files and subdirectories in a
+     * directory).
+     *
+     * @param directory the directory to be scanned.
+     * @return a vector containing File objects for each entry in the
+     *      directory.
+     */
+    private Vector getDirectoryEntries(File directory) {
+        Vector files = new Vector();
+
+        // File[] filesInDir = directory.listFiles();
+        String[] filesInDir = directory.list();
+
+        if (filesInDir != null) {
+            int length = filesInDir.length;
+
+            for (int i = 0; i < length; ++i) {
+                files.addElement(new File(directory, filesInDir[i]));
+            }
+        }
+
+        return files;
+    }
+
+    /**
+     * Template method to allow subclasses to supply elements for the
+     * iteration. The directory iterator maintains a stack of iterators
+     * covering each level in the directory hierarchy. The current iterator
+     * covers the current directory being scanned. If the next entry in that
+     * directory is a subdirectory, the current iterator is pushed onto the
+     * stack and a new iterator is created for the subdirectory. If the
+     * entry is a file, it is returned as the next element and the iterator
+     * remains valid. If there are no more entries in the current directory,
+     * the topmost iterator on the stack is popped off to become the
+     * current iterator.
+     *
+     * @return the next ClassFile in the iteration.
+     */
+    public ClassFile getNextClassFile() {
+        ClassFile nextElement = null;
+
+        try {
+            while (nextElement == null) {
+                if (currentEnum.hasMoreElements()) {
+                    File element = (File) currentEnum.nextElement();
+
+                    if (element.isDirectory()) {
+
+                        // push the current iterator onto the stack and then
+                        // iterate through this directory.
+                        enumStack.push(currentEnum);
+
+                        Vector files = getDirectoryEntries(element);
+
+                        currentEnum = files.elements();
+                    } else {
+
+                        // we have a file. create a stream for it
+                        FileInputStream inFileStream
+                            = new FileInputStream(element);
+
+                        if (element.getName().endsWith(".class")) {
+
+                            // create a data input stream from the jar
+                            // input stream
+                            ClassFile javaClass = new ClassFile();
+
+                            javaClass.read(inFileStream);
+
+                            nextElement = javaClass;
+                        }
+                    }
+                } else {
+                    // this iterator is exhausted. Can we pop one off the stack
+                    if (enumStack.empty()) {
+                        break;
+                    } else {
+                        currentEnum = (Enumeration) enumStack.pop();
+                    }
+                }
+            }
+        } catch (IOException e) {
+            nextElement = null;
+        }
+
+        return nextElement;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java
new file mode 100644
index 0000000..bc315d2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/JarFileIterator.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * A class file iterator which iterates through the contents of a Java jar
+ * file.
+ *
+ */
+public class JarFileIterator implements ClassFileIterator {
+    /** The jar stream from the jar file being iterated over*/
+    private ZipInputStream jarStream;
+
+    /**
+     * Construct an iterator over a jar stream
+     *
+     * @param stream the basic input stream from which the Jar is received
+     * @exception IOException if the jar stream cannot be created
+     */
+    public JarFileIterator(InputStream stream) throws IOException {
+        super();
+
+        jarStream = new ZipInputStream(stream);
+    }
+
+    /**
+     * Get the next ClassFile object from the jar
+     *
+     * @return a ClassFile object describing the class from the jar
+     */
+    public ClassFile getNextClassFile() {
+        ZipEntry jarEntry;
+        ClassFile nextElement = null;
+
+        try {
+            jarEntry = jarStream.getNextEntry();
+
+            while (nextElement == null && jarEntry != null) {
+                String entryName = jarEntry.getName();
+
+                if (!jarEntry.isDirectory() && entryName.endsWith(".class")) {
+
+                    // create a data input stream from the jar input stream
+                    ClassFile javaClass = new ClassFile();
+
+                    javaClass.read(jarStream);
+
+                    nextElement = javaClass;
+                } else {
+
+                    jarEntry = jarStream.getNextEntry();
+                }
+            }
+        } catch (IOException e) {
+            String message = e.getMessage();
+            String text = e.getClass().getName();
+
+            if (message != null) {
+                text += ": " + message;
+            }
+
+            throw new RuntimeException("Problem reading JAR file: " + text);
+        }
+
+        return nextElement;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java
new file mode 100644
index 0000000..8abbfc8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ClassCPInfo.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The constant pool entry which stores class information.
+ *
+ */
+public class ClassCPInfo extends ConstantPoolEntry {
+
+    /**
+     * The class' name. This will be only valid if the entry has been
+     * resolved against the constant pool.
+     */
+    private String className;
+
+    /**
+     * The index into the constant pool where this class' name is stored. If
+     * the class name is changed, this entry is invalid until this entry is
+     * connected to a constant pool.
+     */
+    private int index;
+
+    /**
+     * Constructor. Sets the tag value for this entry to type Class
+     */
+    public ClassCPInfo() {
+        super(CONSTANT_CLASS, 1);
+    }
+
+    /**
+     * Read the entry from a stream.
+     *
+     * @param cpStream the stream containing the constant pool entry to be
+     *      read.
+     * @exception IOException thrown if there is a problem reading the entry
+     *      from the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        index = cpStream.readUnsignedShort();
+        className = "unresolved";
+    }
+
+    /**
+     * Generate a string readable version of this entry
+     *
+     * @return string representation of this constant pool entry
+     */
+    public String toString() {
+        return "Class Constant Pool Entry for " + className + "[" + index + "]";
+    }
+
+    /**
+     * Resolve this class info against the given constant pool.
+     *
+     * @param constantPool the constant pool with which to resolve the
+     *      class.
+     */
+    public void resolve(ConstantPool constantPool) {
+        className = ((Utf8CPInfo) constantPool.getEntry(index)).getValue();
+
+        super.resolve(constantPool);
+    }
+
+    /**
+     * Get the class name of this entry.
+     *
+     * @return the class' name.
+     */
+    public String getClassName() {
+        return className;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java
new file mode 100644
index 0000000..6103422
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantCPInfo.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+/**
+ * A Constant Pool entry which represents a constant value.
+ *
+ */
+public abstract class ConstantCPInfo extends ConstantPoolEntry {
+
+    /**
+     * The entry's untyped value. Each subclass interprets the constant
+     * value based on the subclass's type. The value here must be
+     * compatible.
+     */
+    private Object value;
+
+    /**
+     * Initialise the constant entry.
+     *
+     * @param tagValue the constant pool entry type to be used.
+     * @param entries the number of constant pool entry slots occupied by
+     *      this entry.
+     */
+    protected ConstantCPInfo(int tagValue, int entries) {
+        super(tagValue, entries);
+    }
+
+    /**
+     * Get the value of the constant.
+     *
+     * @return the value of the constant (untyped).
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Set the constant value.
+     *
+     * @param newValue the new untyped value of this constant.
+     */
+    public void setValue(Object newValue) {
+        value = newValue;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java
new file mode 100644
index 0000000..2ce24db
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPool.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * The constant pool of a Java class. The constant pool is a collection of
+ * constants used in a Java class file. It stores strings, constant values,
+ * class names, method names, field names etc.
+ *
+ * @see <a href="http://java.sun.com/docs/books/vmspec/">The Java Virtual
+ *      Machine Specification</a>
+ */
+public class ConstantPool {
+
+    /** The entries in the constant pool. */
+    private Vector entries;
+
+    /**
+     * A Hashtable of UTF8 entries - used to get constant pool indexes of
+     * the UTF8 values quickly
+     */
+    private Hashtable utf8Indexes;
+
+    /** Initialise the constant pool. */
+    public ConstantPool() {
+        entries = new Vector();
+
+        // The zero index is never present in the constant pool itself so
+        // we add a null entry for it
+        entries.addElement(null);
+
+        utf8Indexes = new Hashtable();
+    }
+
+    /**
+     * Read the constant pool from a class input stream.
+     *
+     * @param classStream the DataInputStream of a class file.
+     * @exception IOException if there is a problem reading the constant pool
+     *      from the stream
+     */
+    public void read(DataInputStream classStream) throws IOException {
+        int numEntries = classStream.readUnsignedShort();
+
+        for (int i = 1; i < numEntries;) {
+            ConstantPoolEntry nextEntry
+                 = ConstantPoolEntry.readEntry(classStream);
+
+            i += nextEntry.getNumEntries();
+
+            addEntry(nextEntry);
+        }
+    }
+
+    /**
+     * Get the size of the constant pool.
+     *
+     * @return the size of the constant pool
+     */
+    public int size() {
+        return entries.size();
+    }
+
+    /**
+     * Add an entry to the constant pool.
+     *
+     * @param entry the new entry to be added to the constant pool.
+     * @return the index into the constant pool at which the entry is
+     *      stored.
+     */
+    public int addEntry(ConstantPoolEntry entry) {
+        int index = entries.size();
+
+        entries.addElement(entry);
+
+        int numSlots = entry.getNumEntries();
+
+        // add null entries for any additional slots required.
+        for (int j = 0; j < numSlots - 1; ++j) {
+            entries.addElement(null);
+        }
+
+        if (entry instanceof Utf8CPInfo) {
+            Utf8CPInfo utf8Info = (Utf8CPInfo) entry;
+
+            utf8Indexes.put(utf8Info.getValue(), new Integer(index));
+        }
+
+        return index;
+    }
+
+    /**
+     * Resolve the entries in the constant pool. Resolution of the constant
+     * pool involves transforming indexes to other constant pool entries
+     * into the actual data for that entry.
+     */
+    public void resolve() {
+        for (Enumeration i = entries.elements(); i.hasMoreElements();) {
+            ConstantPoolEntry poolInfo = (ConstantPoolEntry) i.nextElement();
+
+            if (poolInfo != null && !poolInfo.isResolved()) {
+                poolInfo.resolve(this);
+            }
+        }
+    }
+
+
+    /**
+     * Get an constant pool entry at a particular index.
+     *
+     * @param index the index into the constant pool.
+     * @return the constant pool entry at that index.
+     */
+    public ConstantPoolEntry getEntry(int index) {
+        return (ConstantPoolEntry) entries.elementAt(index);
+    }
+
+    /**
+     * Get the index of a given UTF8 constant pool entry.
+     *
+     * @param value the string value of the UTF8 entry.
+     * @return the index at which the given string occurs in the constant
+     *      pool or -1 if the value does not occur.
+     */
+    public int getUTF8Entry(String value) {
+        int index = -1;
+        Integer indexInteger = (Integer) utf8Indexes.get(value);
+
+        if (indexInteger != null) {
+            index = indexInteger.intValue();
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given CONSTANT_CLASS entry in the constant pool.
+     *
+     * @param className the name of the class for which the class entry
+     *      index is required.
+     * @return the index at which the given class entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getClassEntry(String className) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof ClassCPInfo) {
+                ClassCPInfo classinfo = (ClassCPInfo) element;
+
+                if (classinfo.getClassName().equals(className)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given constant value entry in the constant pool.
+     *
+     * @param constantValue the constant value for which the index is
+     *      required.
+     * @return the index at which the given value entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getConstantEntry(Object constantValue) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof ConstantCPInfo) {
+                ConstantCPInfo constantEntry = (ConstantCPInfo) element;
+
+                if (constantEntry.getValue().equals(constantValue)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given CONSTANT_METHODREF entry in the constant
+     * pool.
+     *
+     * @param methodClassName the name of the class which contains the
+     *      method being referenced.
+     * @param methodName the name of the method being referenced.
+     * @param methodType the type descriptor of the method being referenced.
+     * @return the index at which the given method ref entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getMethodRefEntry(String methodClassName, String methodName,
+                                 String methodType) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof MethodRefCPInfo) {
+                MethodRefCPInfo methodRefEntry = (MethodRefCPInfo) element;
+
+                if (methodRefEntry.getMethodClassName().equals(methodClassName)
+                     && methodRefEntry.getMethodName().equals(methodName)
+                     && methodRefEntry.getMethodType().equals(methodType)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given CONSTANT_INTERFACEMETHODREF entry in the
+     * constant pool.
+     *
+     * @param interfaceMethodClassName the name of the interface which
+     *      contains the method being referenced.
+     * @param interfaceMethodName the name of the method being referenced.
+     * @param interfaceMethodType the type descriptor of the method being
+     *      referenced.
+     * @return the index at which the given method ref entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getInterfaceMethodRefEntry(String interfaceMethodClassName,
+                                          String interfaceMethodName,
+                                          String interfaceMethodType) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof InterfaceMethodRefCPInfo) {
+                InterfaceMethodRefCPInfo interfaceMethodRefEntry
+                     = (InterfaceMethodRefCPInfo) element;
+
+                if (interfaceMethodRefEntry.getInterfaceMethodClassName().equals(
+                        interfaceMethodClassName)
+                     && interfaceMethodRefEntry.getInterfaceMethodName().equals(
+                         interfaceMethodName)
+                     && interfaceMethodRefEntry.getInterfaceMethodType().equals(
+                         interfaceMethodType)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given CONSTANT_FIELDREF entry in the constant
+     * pool.
+     *
+     * @param fieldClassName the name of the class which contains the field
+     *      being referenced.
+     * @param fieldName the name of the field being referenced.
+     * @param fieldType the type descriptor of the field being referenced.
+     * @return the index at which the given field ref entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getFieldRefEntry(String fieldClassName, String fieldName,
+                                String fieldType) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof FieldRefCPInfo) {
+                FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo) element;
+
+                if (fieldRefEntry.getFieldClassName().equals(fieldClassName)
+                     && fieldRefEntry.getFieldName().equals(fieldName)
+                     && fieldRefEntry.getFieldType().equals(fieldType)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Get the index of a given CONSTANT_NAMEANDTYPE entry in the constant
+     * pool.
+     *
+     * @param name the name
+     * @param type the type
+     * @return the index at which the given NameAndType entry occurs in the
+     *      constant pool or -1 if the value does not occur.
+     */
+    public int getNameAndTypeEntry(String name, String type) {
+        int index = -1;
+
+        for (int i = 0; i < entries.size() && index == -1; ++i) {
+            Object element = entries.elementAt(i);
+
+            if (element instanceof NameAndTypeCPInfo) {
+                NameAndTypeCPInfo nameAndTypeEntry
+                    = (NameAndTypeCPInfo) element;
+
+                if (nameAndTypeEntry.getName().equals(name)
+                     && nameAndTypeEntry.getType().equals(type)) {
+                    index = i;
+                }
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Dump the constant pool to a string.
+     *
+     * @return the constant pool entries as strings
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer("\n");
+        int size = entries.size();
+
+        for (int i = 0; i < size; ++i) {
+            sb.append("[" + i + "] = " + getEntry(i) + "\n");
+        }
+
+        return sb.toString();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java
new file mode 100644
index 0000000..63a40fb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/ConstantPoolEntry.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * An entry in the constant pool. This class contains a representation of the
+ * constant pool entries. It is an abstract base class for all the different
+ * forms of constant pool entry.
+ *
+ * @see ConstantPool
+ */
+public abstract class ConstantPoolEntry {
+
+    /** Tag value for UTF8 entries. */
+    public static final int CONSTANT_UTF8 = 1;
+
+    /** Tag value for Integer entries. */
+    public static final int CONSTANT_INTEGER = 3;
+
+    /** Tag value for Float entries. */
+    public static final int CONSTANT_FLOAT = 4;
+
+    /** Tag value for Long entries. */
+    public static final int CONSTANT_LONG = 5;
+
+    /** Tag value for Double entries. */
+    public static final int CONSTANT_DOUBLE = 6;
+
+    /** Tag value for Class entries. */
+    public static final int CONSTANT_CLASS = 7;
+
+    /** Tag value for String entries. */
+    public static final int CONSTANT_STRING = 8;
+
+    /** Tag value for Field Reference entries. */
+    public static final int CONSTANT_FIELDREF = 9;
+
+    /** Tag value for Method Reference entries. */
+    public static final int CONSTANT_METHODREF = 10;
+
+    /** Tag value for Interface Method Reference entries. */
+    public static final int CONSTANT_INTERFACEMETHODREF = 11;
+
+    /** Tag value for Name and Type entries. */
+    public static final int CONSTANT_NAMEANDTYPE = 12;
+
+    /**
+     * This entry's tag which identifies the type of this constant pool
+     * entry.
+     */
+    private int tag;
+
+    /**
+     * The number of slots in the constant pool, occupied by this entry.
+     */
+    private int numEntries;
+
+    /**
+     * A flag which indicates if this entry has been resolved or not.
+     */
+    private boolean resolved;
+
+    /**
+     * Initialise the constant pool entry.
+     *
+     * @param tagValue the tag value which identifies which type of constant
+     *      pool entry this is.
+     * @param entries the number of constant pool entry slots this entry
+     *      occupies.
+     */
+    public ConstantPoolEntry(int tagValue, int entries) {
+        tag = tagValue;
+        numEntries = entries;
+        resolved = false;
+    }
+
+    /**
+     * Read a constant pool entry from a stream. This is a factory method
+     * which reads a constant pool entry form a stream and returns the
+     * appropriate subclass for the entry.
+     *
+     * @param cpStream the stream from which the constant pool entry is to
+     *      be read.
+     * @return the appropriate ConstantPoolEntry subclass representing the
+     *      constant pool entry from the stream.
+     * @exception IOException if the constant pool entry cannot be read
+     *      from the stream
+     */
+    public static ConstantPoolEntry readEntry(DataInputStream cpStream)
+         throws IOException {
+        ConstantPoolEntry cpInfo = null;
+        int cpTag = cpStream.readUnsignedByte();
+
+        switch (cpTag) {
+
+            case CONSTANT_UTF8:
+                cpInfo = new Utf8CPInfo();
+
+                break;
+            case CONSTANT_INTEGER:
+                cpInfo = new IntegerCPInfo();
+
+                break;
+            case CONSTANT_FLOAT:
+                cpInfo = new FloatCPInfo();
+
+                break;
+            case CONSTANT_LONG:
+                cpInfo = new LongCPInfo();
+
+                break;
+            case CONSTANT_DOUBLE:
+                cpInfo = new DoubleCPInfo();
+
+                break;
+            case CONSTANT_CLASS:
+                cpInfo = new ClassCPInfo();
+
+                break;
+            case CONSTANT_STRING:
+                cpInfo = new StringCPInfo();
+
+                break;
+            case CONSTANT_FIELDREF:
+                cpInfo = new FieldRefCPInfo();
+
+                break;
+            case CONSTANT_METHODREF:
+                cpInfo = new MethodRefCPInfo();
+
+                break;
+            case CONSTANT_INTERFACEMETHODREF:
+                cpInfo = new InterfaceMethodRefCPInfo();
+
+                break;
+            case CONSTANT_NAMEANDTYPE:
+                cpInfo = new NameAndTypeCPInfo();
+
+                break;
+            default:
+                throw new ClassFormatError("Invalid Constant Pool entry Type "
+                     + cpTag);
+        }
+
+        cpInfo.read(cpStream);
+
+        return cpInfo;
+    }
+
+    /**
+     * Indicates whether this entry has been resolved. In general a constant
+     * pool entry can reference another constant pool entry by its index
+     * value. Resolution involves replacing this index value with the
+     * constant pool entry at that index.
+     *
+     * @return true if this entry has been resolved.
+     */
+    public boolean isResolved() {
+        return resolved;
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        resolved = true;
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public abstract void read(DataInputStream cpStream) throws IOException;
+
+    /**
+     * Get the Entry's type tag.
+     *
+     * @return The Tag value of this entry
+     */
+    public int getTag() {
+        return tag;
+    }
+
+    /**
+     * Get the number of Constant Pool Entry slots within the constant pool
+     * occupied by this entry.
+     *
+     * @return the number of slots used.
+     */
+    public final int getNumEntries() {
+        return numEntries;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java
new file mode 100644
index 0000000..a21c0d6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/DoubleCPInfo.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * The constant pool entry subclass used to represent double constant
+ * values.
+ *
+ */
+public class DoubleCPInfo extends ConstantCPInfo {
+    /**
+     * Constructor
+     */
+    public DoubleCPInfo() {
+        super(CONSTANT_DOUBLE, 2);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from the
+     *      stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        setValue(new Double(cpStream.readDouble()));
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "Double Constant Pool Entry: " + getValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java
new file mode 100644
index 0000000..06c0925
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FieldRefCPInfo.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A FieldRef CP Info
+ *
+ */
+public class FieldRefCPInfo extends ConstantPoolEntry {
+    /** Name of the field's class */
+    private String fieldClassName;
+    /** name of the field in that class */
+    private String fieldName;
+    /** The type of the field */
+    private String fieldType;
+    /** Index into the constant pool for the class */
+    private int classIndex;
+    /** Index into the constant pool for the name and type entry */
+    private int nameAndTypeIndex;
+
+    /** Constructor.  */
+    public FieldRefCPInfo() {
+        super(CONSTANT_FIELDREF, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        classIndex = cpStream.readUnsignedShort();
+        nameAndTypeIndex = cpStream.readUnsignedShort();
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        ClassCPInfo fieldClass
+            = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+        fieldClass.resolve(constantPool);
+
+        fieldClassName = fieldClass.getClassName();
+
+        NameAndTypeCPInfo nt
+            = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+        nt.resolve(constantPool);
+
+        fieldName = nt.getName();
+        fieldType = nt.getType();
+
+        super.resolve(constantPool);
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        String value;
+
+        if (isResolved()) {
+            value = "Field : Class = " + fieldClassName + ", name = "
+                + fieldName + ", type = " + fieldType;
+        } else {
+            value = "Field : Class index = " + classIndex
+                + ", name and type index = " + nameAndTypeIndex;
+        }
+
+        return value;
+    }
+
+    /**
+     * Gets the name of the class defining the field
+     *
+     * @return the name of the class defining the field
+     */
+    public String getFieldClassName() {
+        return fieldClassName;
+    }
+
+    /**
+     * Get the name of the field
+     *
+     * @return the field's name
+     */
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    /**
+     * Get the type of the field
+     *
+     * @return the field's type in string format
+     */
+    public String getFieldType() {
+        return fieldType;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java
new file mode 100644
index 0000000..532b672
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/FloatCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A Float CP Info
+ *
+ */
+public class FloatCPInfo extends ConstantCPInfo {
+
+    /** Constructor.  */
+    public FloatCPInfo() {
+        super(CONSTANT_FLOAT, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        setValue(new Float(cpStream.readFloat()));
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "Float Constant Pool Entry: " + getValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java
new file mode 100644
index 0000000..3beaa8c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/IntegerCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * An Integer CP Info
+ *
+ */
+public class IntegerCPInfo extends ConstantCPInfo {
+
+    /** Constructor.  */
+    public IntegerCPInfo() {
+        super(CONSTANT_INTEGER, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        setValue(new Integer(cpStream.readInt()));
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "Integer Constant Pool Entry: " + getValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java
new file mode 100644
index 0000000..fbc23c1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/InterfaceMethodRefCPInfo.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A InterfaceMethodRef CP Info
+ *
+ */
+public class InterfaceMethodRefCPInfo extends ConstantPoolEntry {
+    /** the class name of the class defining the interface method */
+    private String interfaceMethodClassName;
+    /** the name of the interface nmethod */
+    private String interfaceMethodName;
+    /** the method signature of the interface method */
+    private String interfaceMethodType;
+    /**
+     * the index into the constant pool of the class entry for the interface
+     * class
+     */
+    private int classIndex;
+    /**
+     * the index into the constant pool of the name and type entry
+     * describing the method
+     */
+    private int nameAndTypeIndex;
+
+    /** Constructor. */
+    public InterfaceMethodRefCPInfo() {
+        super(CONSTANT_INTERFACEMETHODREF, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        classIndex = cpStream.readUnsignedShort();
+        nameAndTypeIndex = cpStream.readUnsignedShort();
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        ClassCPInfo interfaceMethodClass
+             = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+        interfaceMethodClass.resolve(constantPool);
+
+        interfaceMethodClassName = interfaceMethodClass.getClassName();
+
+        NameAndTypeCPInfo nt
+             = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+        nt.resolve(constantPool);
+
+        interfaceMethodName = nt.getName();
+        interfaceMethodType = nt.getType();
+
+        super.resolve(constantPool);
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        String value;
+
+        if (isResolved()) {
+            value = "InterfaceMethod : Class = " + interfaceMethodClassName
+                 + ", name = " + interfaceMethodName + ", type = "
+                 + interfaceMethodType;
+        } else {
+            value = "InterfaceMethod : Class index = " + classIndex
+                 + ", name and type index = " + nameAndTypeIndex;
+        }
+
+        return value;
+    }
+
+    /**
+     * Gets the name of the class defining the interface method
+     *
+     * @return the name of the class defining the interface method
+     */
+    public String getInterfaceMethodClassName() {
+        return interfaceMethodClassName;
+    }
+
+    /**
+     * Get the name of the interface method
+     *
+     * @return the name of the interface method
+     */
+    public String getInterfaceMethodName() {
+        return interfaceMethodName;
+    }
+
+    /**
+     * Gets the type of the interface method
+     *
+     * @return the interface method's type signature
+     */
+    public String getInterfaceMethodType() {
+        return interfaceMethodType;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java
new file mode 100644
index 0000000..e854f04
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/LongCPInfo.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A Long CP Info
+ *
+ */
+public class LongCPInfo extends ConstantCPInfo {
+
+    /** Constructor.  */
+    public LongCPInfo() {
+        super(CONSTANT_LONG, 2);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        setValue(new Long(cpStream.readLong()));
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "Long Constant Pool Entry: " + getValue();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java
new file mode 100644
index 0000000..6b33521
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/MethodRefCPInfo.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A MethodRef CP Info
+ *
+ */
+public class MethodRefCPInfo extends ConstantPoolEntry {
+    /** the name of the class defining this method */
+    private String methodClassName;
+    /** the name of the method */
+    private String methodName;
+    /** the method's type descriptor */
+    private String methodType;
+    /** The index into the constant pool which defines the class of this method. */
+    private int classIndex;
+    /**
+     * the index into the constant pool which defined the name and type
+     * signature of the method
+     */
+    private int nameAndTypeIndex;
+
+    /** Constructor. */
+    public MethodRefCPInfo() {
+        super(CONSTANT_METHODREF, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        classIndex = cpStream.readUnsignedShort();
+        nameAndTypeIndex = cpStream.readUnsignedShort();
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        String value;
+
+        if (isResolved()) {
+            value = "Method : Class = " + methodClassName + ", name = "
+                 + methodName + ", type = " + methodType;
+        } else {
+            value = "Method : Class index = " + classIndex
+                 + ", name and type index = " + nameAndTypeIndex;
+        }
+
+        return value;
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        ClassCPInfo methodClass
+             = (ClassCPInfo) constantPool.getEntry(classIndex);
+
+        methodClass.resolve(constantPool);
+
+        methodClassName = methodClass.getClassName();
+
+        NameAndTypeCPInfo nt
+             = (NameAndTypeCPInfo) constantPool.getEntry(nameAndTypeIndex);
+
+        nt.resolve(constantPool);
+
+        methodName = nt.getName();
+        methodType = nt.getType();
+
+        super.resolve(constantPool);
+    }
+
+    /**
+     * Get the name of the class defining the method
+     *
+     * @return the name of the class defining this method
+     */
+    public String getMethodClassName() {
+        return methodClassName;
+    }
+
+    /**
+     * Get the name of the method.
+     *
+     * @return the name of the method.
+     */
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * Get the type signature of the method.
+     *
+     * @return the type signature of the method.
+     */
+    public String getMethodType() {
+        return methodType;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java
new file mode 100644
index 0000000..47f454d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/NameAndTypeCPInfo.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A NameAndType CP Info
+ *
+ */
+public class NameAndTypeCPInfo extends ConstantPoolEntry {
+
+    /** Constructor. */
+    public NameAndTypeCPInfo() {
+        super(CONSTANT_NAMEANDTYPE, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        nameIndex = cpStream.readUnsignedShort();
+        descriptorIndex = cpStream.readUnsignedShort();
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        String value;
+
+        if (isResolved()) {
+            value = "Name = " + name + ", type = " + type;
+        } else {
+            value = "Name index = " + nameIndex
+                 + ", descriptor index = " + descriptorIndex;
+        }
+
+        return value;
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        name = ((Utf8CPInfo) constantPool.getEntry(nameIndex)).getValue();
+        type = ((Utf8CPInfo) constantPool.getEntry(descriptorIndex)).getValue();
+
+        super.resolve(constantPool);
+    }
+
+    /**
+     * Get the name component of this entry
+     *
+     * @return the name of this name and type entry
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the type signature of this entry
+     *
+     * @return the type signature of this entry
+     */
+    public String getType() {
+        return type;
+    }
+
+    /** the name component of this entry */
+    private String name;
+    /** the type component of this entry */
+    private String type;
+    /**
+     * the index into the constant pool at which the name component's string
+     * value is stored
+     */
+    private int nameIndex;
+    /**
+     * the index into the constant pool where the type descriptor string is
+     * stored.
+     */
+    private int descriptorIndex;
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java
new file mode 100644
index 0000000..bc9ee24
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/StringCPInfo.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A String Constant Pool Entry. The String info contains an index into the
+ * constant pool where a UTF8 string is stored.
+ *
+ */
+public class StringCPInfo extends ConstantCPInfo {
+
+    /** Constructor.  */
+    public StringCPInfo() {
+        super(CONSTANT_STRING, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        index = cpStream.readUnsignedShort();
+
+        setValue("unresolved");
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "String Constant Pool Entry for "
+            + getValue() + "[" + index + "]";
+    }
+
+    /**
+     * Resolve this constant pool entry with respect to its dependents in
+     * the constant pool.
+     *
+     * @param constantPool the constant pool of which this entry is a member
+     *      and against which this entry is to be resolved.
+     */
+    public void resolve(ConstantPool constantPool) {
+        setValue(((Utf8CPInfo) constantPool.getEntry(index)).getValue());
+        super.resolve(constantPool);
+    }
+
+    /** the index into the constant pool containing the string's content */
+    private int index;
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java
new file mode 100644
index 0000000..5471ccd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/depend/constantpool/Utf8CPInfo.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * A UTF8 Constant Pool Entry.
+ *
+ */
+public class Utf8CPInfo extends ConstantPoolEntry {
+    /** The String value of the UTF-8 entry */
+    private String value;
+
+    /** Constructor.  */
+    public Utf8CPInfo() {
+        super(CONSTANT_UTF8, 1);
+    }
+
+    /**
+     * read a constant pool entry from a class stream.
+     *
+     * @param cpStream the DataInputStream which contains the constant pool
+     *      entry to be read.
+     * @exception IOException if there is a problem reading the entry from
+     *      the stream.
+     */
+    public void read(DataInputStream cpStream) throws IOException {
+        value = cpStream.readUTF();
+    }
+
+    /**
+     * Print a readable version of the constant pool entry.
+     *
+     * @return the string representation of this constant pool entry.
+     */
+    public String toString() {
+        return "UTF8 Value = " + value;
+    }
+
+    /**
+     * Get the string value of the UTF-8 entry
+     *
+     * @return the UTF-8 value as a Java string
+     */
+    public String getValue() {
+        return value;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/CSharp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/CSharp.java
new file mode 100644
index 0000000..66e3972
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/CSharp.java
@@ -0,0 +1,399 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ *  build notes
+ *  -The reference CD to listen to while editing this file is
+ *  nap: Underworld  - Everything, Everything
+ */
+// ====================================================================
+// place in the optional ant tasks package
+// but in its own dotnet group
+// ====================================================================
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+// ====================================================================
+// imports
+// ====================================================================
+
+import java.io.File;
+
+// ====================================================================
+
+/**
+ *  Compiles C# source into executables or modules.
+ *
+ * csc.exe on Windows or mcs on other platforms must be on the execute
+ * path, unless another executable or the full path to that executable
+ * is specified in the <tt>executable</tt> parameter
+ * <p>
+ * All parameters are optional: &lt;csc/&gt; should suffice to produce a debug
+ * build of all *.cs files. However, naming an <tt>destFile</tt>stops the
+ * csc compiler from choosing an output name from random, and
+ * allows the dependency checker to determine if the file is out of date.
+ * <p>
+ *  The task is a directory based task, so attributes like <b>includes="*.cs"
+ *  </b> and <b>excludes="broken.cs"</b> can be used to control the files pulled
+ *  in. By default, all *.cs files from the project folder down are included in
+ *  the command. When this happens the output file -if not specified- is taken
+ *  as the first file in the list, which may be somewhat hard to control.
+ *  Specifying the output file with <tt>destFile</tt> seems prudent. <p>
+ *
+ * <p>
+ * For more complex source trees, nested <tt>src</tt> elemements can be
+ * supplied. When such an element is present, the implicit fileset is ignored.
+ * This makes sense, when you think about it :)
+ *
+ * <p>For historical reasons the pattern
+ * <code>**</code><code>/*.cs</code> is preset as includes list and
+ * you can not override it with an explicit includes attribute.  Use
+ * nested <code>&lt;src&gt;</code> elements instead of the basedir
+ * attribute if you need more control.</p>
+ *
+ * <p>
+ * References to external files can be made through the references attribute,
+ * or (since Ant1.6), via nested &lt;reference&gt; filesets. With the latter,
+ * the timestamps of the references are also used in the dependency
+ * checking algorithm.
+ * <p>
+ *
+ * Example
+ *
+ * <pre>&lt;csc
+ *       optimize=&quot;true&quot;
+ *       debug=&quot;false&quot;
+ *       docFile=&quot;documentation.xml&quot;
+ *       warnLevel=&quot;4&quot;
+ *       unsafe=&quot;false&quot;
+ *       targetType=&quot;exe&quot;
+ *       incremental=&quot;false&quot;
+ *       mainClass = &quot;MainApp&quot;
+ *       destFile=&quot;NetApp.exe&quot;
+ *       &gt;
+ *           &lt;src dir="src" includes="*.cs" /&gt;
+ *       &lt;reference file="${testCSC.dll}" /&gt;
+ *       &lt;define name="RELEASE" /&gt;
+ *       &lt;define name="DEBUG" if="debug.property"/&gt;
+ *       &lt;define name="def3" unless="def3.property"/&gt;
+ *    &lt;/csc&gt;
+ * </pre>
+ *
+ *
+ * @ant.task    name="csc" category="dotnet"
+ * @since Ant 1.3
+ */
+
+public class CSharp extends DotnetCompile {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     *  defines list: RELEASE;WIN32;NO_SANITY_CHECKS;;SOMETHING_ELSE'
+     */
+    String definitions;
+
+
+    /**
+     *  output XML documentation flag
+     */
+    private File docFile;
+
+    /**
+     *  file alignment; 0 means let the compiler decide
+     */
+    private int fileAlign = 0;
+
+    /**
+     *  use full paths to things
+     */
+    private boolean fullpaths = false;
+
+    /**
+     *  incremental build flag
+     */
+    private boolean incremental;
+
+    /**
+     *  enable unsafe code flag. Clearly set to false by default
+     */
+    protected boolean unsafe;
+
+    /**
+     * A flag that tells the compiler not to read in the compiler
+     * settings files 'csc.rsp' in its bin directory and then the local directory
+     */
+    private boolean noconfig = false;
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     *  constructor inits everything and set up the search pattern
+     */
+
+    public CSharp() {
+        clear();
+    }
+
+    /**
+     * full cleanup
+     */
+    public void clear() {
+        super.clear();
+        docFile = null;
+        fileAlign = 0;
+        fullpaths = true;
+        incremental = false;
+        unsafe = false;
+        noconfig = false;
+        definitions = null;
+        setExecutable(isWindows ? "csc" : "mcs");
+    }
+
+
+
+    /**
+     *  file for generated XML documentation
+     *
+     *@param  f  output file
+     */
+    public void setDocFile(File f) {
+        docFile = f;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The DocFile Parameter to CSC
+     */
+    protected String getDocFileParameter() {
+        if (docFile != null) {
+            return "/doc:" + docFile.toString();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Set the file alignment.
+     * Valid values are 0,512, 1024, 2048, 4096, 8192,
+     * and 16384, 0 means 'leave to the compiler'
+     * @param fileAlign the value to use.
+     */
+    public void setFileAlign(int fileAlign) {
+        this.fileAlign = fileAlign;
+    }
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The OutputFile Parameter to CSC
+     */
+    protected String getFileAlignParameter() {
+        if (fileAlign != 0 && !"mcs".equals(getExecutable())) {
+            return "/filealign:" + fileAlign;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * If true, print the full path of files on errors.
+     *
+     *@param  enabled  The new fullPaths value
+     */
+    public void setFullPaths(boolean enabled) {
+        fullpaths = enabled;
+    }
+
+
+    /**
+     *  Gets the fullPathsParameter attribute of the CSharp object
+     *
+     *@return    The fullPathsParameter value or null if unset
+     */
+    protected String getFullPathsParameter() {
+        return fullpaths ? "/fullpaths" : null;
+    }
+
+
+    /**
+     *  set the incremental compilation flag on or off.
+     *
+     *@param  incremental  on/off flag
+     */
+    public void setIncremental(boolean incremental) {
+        this.incremental = incremental;
+    }
+
+
+    /**
+     *  query the incrementalflag
+     *
+     *@return    true if incremental compilation is turned on
+     */
+    public boolean getIncremental() {
+        return incremental;
+    }
+
+
+    /**
+     *  get the incremental build argument
+     *
+     *@return    The Incremental Parameter to CSC
+     */
+    protected String getIncrementalParameter() {
+        return "/incremental" + (incremental ? "+" : "-");
+    }
+
+    /**
+     *  The output file. This is identical to the destFile attribute.
+     *
+     *@param  params  The new outputFile value
+     */
+    public void setOutputFile(File params) {
+        setDestFile(params);
+    }
+
+
+    /**
+     * If true, enables the unsafe keyword.
+     *
+     *@param  unsafe  The new Unsafe value
+     */
+    public void setUnsafe(boolean unsafe) {
+        this.unsafe = unsafe;
+    }
+
+
+    /**
+     *  query the Unsafe attribute
+     *
+     *@return    The Unsafe value
+     */
+    public boolean getUnsafe() {
+        return this.unsafe;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The Unsafe Parameter to CSC
+     */
+    protected String getUnsafeParameter() {
+        return unsafe ? "/unsafe" : null;
+    }
+
+
+    /**
+     * A flag that tells the compiler not to read in the compiler
+     * settings files 'csc.rsp' in its bin directory and then the local directory
+     *
+     *@param  enabled  The new noConfig value
+     */
+    public void setNoConfig(boolean enabled) {
+        noconfig = enabled;
+    }
+
+
+    /**
+     *  Gets the noConfigParameter attribute of the CSharp object
+     *
+     *@return    The noConfigParameter value
+     */
+    protected String getNoConfigParameter() {
+        return noconfig ? "/noconfig" : null;
+    }
+
+
+    /**
+     *  Semicolon separated list of defined constants.
+     *
+     *@param  params  The new definitions value
+     */
+    public void setDefinitions(String params) {
+        definitions = params;
+    }
+
+    /**
+     * override the superclasses version of this method (which we call)
+     * with a check for a definitions attribute, the contents of which
+     * are appended to the list.
+     *@return    The Definitions Parameter to CSC
+     */
+    protected String getDefinitionsParameter() {
+        String predecessors = super.getDefinitionsParameter();
+        if (notEmpty(definitions)) {
+            if (predecessors == null) {
+                predecessors = "/define:";
+            }
+            return  predecessors + definitions;
+        } else {
+            return predecessors;
+        }
+    }
+
+
+    /**
+     * add Commands unique to C#.
+     * @param command ongoing command
+     */
+    public void addCompilerSpecificOptions(NetCommand command) {
+        command.addArgument(getIncludeDefaultReferencesParameter());
+        command.addArgument(getWarnLevelParameter());
+        command.addArgument(getDocFileParameter());
+        command.addArgument(getFullPathsParameter());
+        command.addArgument(getFileAlignParameter());
+        command.addArgument(getIncrementalParameter());
+        command.addArgument(getNoConfigParameter());
+        command.addArgument(getUnsafeParameter());
+    }
+
+    // end execute
+
+    /**
+     * Returns the delimiter which C# uses to separate references, i.e., a semi colon.
+     * @return the delimiter.
+     */
+    public String getReferenceDelimiter() {
+        return ";";
+    }
+
+
+    /**
+     * This method indicates the filename extension for C# files.
+     * @return the file extension for C#, i.e., "cs" (without the dot).
+     */
+    public String getFileExtension() {
+        return "cs";
+    }
+
+    /**
+     * Build a C# style parameter.
+     * @param command the command.
+     * @param resource the resource.
+     */
+    protected void createResourceParameter(
+        NetCommand command, DotnetResource resource) {
+        resource.getParameters(getProject(), command, true);
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetBaseMatchingTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetBaseMatchingTask.java
new file mode 100644
index 0000000..21a300f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetBaseMatchingTask.java
@@ -0,0 +1,194 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/**
+ * refactoring of some stuff so that different things (like ILASM)
+ * can use shared code.
+ */
+public class DotnetBaseMatchingTask extends MatchingTask {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     *  output file. If not supplied this is derived from the source file
+     */
+    protected File outputFile;
+    /**
+     * filesets of file to compile
+     */
+    protected Vector filesets = new Vector();
+
+    /**
+     *  source directory upon which the search pattern is applied
+     */
+    protected File srcDir;
+
+    /**
+     * Are we running on Windows?
+     *
+     * @since Ant 1.6.3
+     */
+    // CheckStyle:ConstantNameCheck OFF - bc
+    protected static final boolean isWindows = Os.isFamily("windows");
+
+    // CheckStyle:ConstantNameCheck ON
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+    * Overridden because we need to be able to set the srcDir.
+    * @return the source directory.
+    */
+    public File getSrcDir() {
+        return this.srcDir;
+    }
+
+    /**
+     *  Set the source directory of the files to be compiled.
+     *
+     *@param  srcDirName  The new SrcDir value
+     */
+    public void setSrcDir(File srcDirName) {
+        this.srcDir = srcDirName;
+    }
+
+    /**
+     *  Set the name of exe/library to create.
+     *
+     *@param  file  The new outputFile value
+     */
+    public void setDestFile(File file) {
+        outputFile = file;
+    }
+
+    /**
+     * add a new source directory to the compile
+     * @param src a fileset.
+     */
+    public void addSrc(FileSet src) {
+        filesets.add(src);
+    }
+
+    /**
+     * get the destination file
+     * @return the dest file or null for not assigned
+     */
+    public File getDestFile() {
+        return outputFile;
+    }
+
+    /**
+     * create the list of files
+     * @param command the command to create the files for.
+     * @param filesToBuild vector to add files to
+     * @param outputTimestamp timestamp to compare against
+     * @return number of files out of date
+     */
+    protected int buildFileList(NetCommand command, Hashtable filesToBuild, long outputTimestamp) {
+        int filesOutOfDate = 0;
+        boolean scanImplicitFileset
+            = getSrcDir() != null || filesets.size() == 0;
+        if (scanImplicitFileset) {
+            //scan for an implicit fileset if there was a srcdir set
+            //or there was no srcDir set but there was no contained classes
+            if (getSrcDir() == null) {
+                //if there is no src dir here, set it
+                setSrcDir(getProject().resolveFile("."));
+            }
+            log("working from source directory " + getSrcDir(),
+                    Project.MSG_VERBOSE);
+            //get dependencies list.
+            DirectoryScanner scanner = getDirectoryScanner(getSrcDir());
+            filesOutOfDate = command.scanOneFileset(scanner,
+                    filesToBuild, outputTimestamp);
+        }
+        //get any included source directories
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            filesOutOfDate += command.scanOneFileset(
+                    fs.getDirectoryScanner(getProject()),
+                    filesToBuild,
+                    outputTimestamp);
+        }
+
+        return filesOutOfDate;
+    }
+
+    /**
+     * add the list of files to a command
+     * @param filesToBuild vector of files
+     * @param command the command to append to
+     */
+    protected void addFilesToCommand(Hashtable filesToBuild, NetCommand command) {
+        int count = filesToBuild.size();
+        log("compiling " + count + " file" + ((count == 1) ? "" : "s"),
+                Project.MSG_VERBOSE);
+        Enumeration files = filesToBuild.elements();
+        while (files.hasMoreElements()) {
+            File file = (File) files.nextElement();
+            command.addArgument(file.toString());
+        }
+    }
+
+    /**
+     * determine the timestamp of the output file
+     * @return a timestamp or 0 for no output file known/exists
+     */
+    protected long getOutputFileTimestamp() {
+        long outputTimestamp;
+        if (getDestFile() != null && getDestFile().exists()) {
+            outputTimestamp = getDestFile().lastModified();
+        } else {
+            outputTimestamp = 0;
+        }
+        return outputTimestamp;
+    }
+
+    /**
+     * finish off the command by adding all dependent files, execute
+     * @param command the command to update.
+     * @param ignoreTimestamps not used.
+     */
+    protected void addFilesAndExecute(NetCommand command, boolean ignoreTimestamps) {
+        long outputTimestamp = getOutputFileTimestamp();
+        Hashtable filesToBuild = new Hashtable();
+        int filesOutOfDate = buildFileList(command, filesToBuild, outputTimestamp);
+
+        //now run the command of exe + settings + files
+        if (filesOutOfDate > 0) {
+            //add the files to the command
+            addFilesToCommand(filesToBuild, command);
+            command.runCommand();
+        } else {
+            log("output file is up to date", Project.MSG_VERBOSE);
+        }
+    }
+
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetCompile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetCompile.java
new file mode 100644
index 0000000..c67c731
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetCompile.java
@@ -0,0 +1,996 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ *  build notes
+ *  -The reference CD to listen to while editing this file is
+ *  nap:Cream+Live+2001+CD+2
+ */
+
+// place in the optional ant tasks package
+// but in its own dotnet group
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+// imports
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+
+/**
+ *  Abstract superclass for dotnet compiler tasks.
+ *
+ *  History
+ *  <table>
+ *    <tr>
+ *      <td>
+ *        0.1
+ *      </td>
+ *      <td>
+ *        First creation
+ *      </td>
+ *      <td>
+ *        Most of the code here was copied verbatim from v0.3 of
+ *        Steve Loughran's CSharp optional task. Abstracted functionality
+ *        to allow subclassing of other dotnet compiler types.
+ *      </td>
+ *    </tr>
+ *
+ *  </table>
+ *
+ *
+ * @version     0.1
+ */
+
+public abstract class DotnetCompile
+         extends DotnetBaseMatchingTask {
+
+    private static final int DEFAULT_WARN_LEVEL = 3;
+
+    /**
+     *  list of reference classes. (pretty much a classpath equivalent)
+     */
+    private String references;
+
+    /**
+     *  flag to enable automatic reference inclusion
+     */
+    private boolean includeDefaultReferences = true;
+
+    /**
+     *  icon for incorporation into apps
+     */
+    private File win32icon;
+
+    /**
+     *  icon for incorporation into apps
+     */
+    private File win32res;
+
+    /**
+     *  flag to control action on execution trouble
+     */
+    private boolean failOnError;
+
+    /**
+     *  using the path approach didn't work as it could not handle the implicit
+     *  execution path. Perhaps that could be extracted from the runtime and
+     *  then the path approach would be viable
+     */
+    private Path referenceFiles;
+
+    /**
+     *  optimise flag
+     */
+    private boolean optimize;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * a list of definitions to support;
+     */
+    protected Vector definitionList = new Vector();
+
+    /**
+     * our resources
+     */
+    protected Vector resources = new Vector();
+
+    /**
+     *  executable
+     */
+
+    protected String executable;
+
+    protected static final String REFERENCE_OPTION = "/reference:";
+
+    /**
+     *  debug flag. Controls generation of debug information.
+     */
+    protected boolean debug;
+
+    /**
+     *  warning level: 0-4, with 4 being most verbose
+     */
+    private int warnLevel;
+
+    /**
+     *  main class (or null for automatic choice)
+     */
+    protected String mainClass;
+
+    /**
+     *  any extra command options?
+     */
+    protected String extraOptions;
+
+    /**
+     *  type of target. Should be one of exe|library|module|winexe|(null)
+     *  default is exe; the actual value (if not null) is fed to the command
+     *  line. <br>
+     *  See /target
+     */
+    protected String targetType;
+
+    /**
+     *  utf out flag
+     */
+
+    protected boolean utf8output = false;
+
+    /**
+     *  list of extra modules to refer to
+     */
+    protected String additionalModules;
+    /**
+     * filesets of references
+     */
+    protected Vector referenceFilesets = new Vector();
+
+    /**
+     * flag to set to to use @file based command cache
+     */
+    private boolean useResponseFile = false;
+    private static final int AUTOMATIC_RESPONSE_FILE_THRESHOLD = 64;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     *  constructor inits everything and set up the search pattern
+     */
+
+    public DotnetCompile() {
+        clear();
+        setIncludes(getFilePattern());
+    }
+
+    /**
+     *  reset all contents.
+     */
+    public void clear() {
+        targetType = null;
+        win32icon = null;
+        srcDir = null;
+        mainClass = null;
+        warnLevel = DEFAULT_WARN_LEVEL;
+        optimize = false;
+        debug = true;
+        references = null;
+        failOnError = true;
+        additionalModules = null;
+        includeDefaultReferences = true;
+        extraOptions = null;
+    }
+
+
+    /**
+     * Semicolon separated list of DLLs to refer to.
+     *
+     *@param  s  The new References value
+     */
+    public void setReferences(String s) {
+        references = s;
+    }
+
+
+    /**
+     *  get the reference string or null for no argument needed
+     *
+     *@return    The References Parameter to CSC
+     */
+    protected String getReferencesParameter() {
+        //bail on no references
+        if (notEmpty(references)) {
+            if (isWindows) {
+                return '\"' + REFERENCE_OPTION + references + '\"';
+            } else {
+                return REFERENCE_OPTION + references;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Path of references to include.
+     * Wildcards should work.
+     *
+     *@param  path  another path to append
+     */
+    public void setReferenceFiles(Path path) {
+        //demand create pathlist
+        if (referenceFiles == null) {
+            referenceFiles = new Path(this.getProject());
+        }
+        referenceFiles.append(path);
+    }
+
+    /**
+     * add a new reference fileset to the compilation
+     * @param reference the files to use.
+     */
+    public void addReference(FileSet reference) {
+        referenceFilesets.add(reference);
+    }
+
+
+
+    /**
+     *  turn the path list into a list of files and a /references argument
+     *
+     *@return    null or a string of references.
+     */
+    protected String getReferenceFilesParameter() {
+        //bail on no references
+        if (references == null) {
+            return null;
+        }
+        //iterate through the ref list & generate an entry for each
+        //or just rely on the fact that the toString operator does this, but
+        //noting that the separator is ';' on windows, ':' on unix
+
+        //bail on no references listed
+        if (references.length() == 0) {
+            return null;
+        }
+
+        StringBuffer s = new StringBuffer(REFERENCE_OPTION);
+        if (isWindows) {
+            s.append('\"');
+        }
+        s.append(references);
+        if (isWindows) {
+            s.append('\"');
+        }
+        return s.toString();
+    }
+
+
+    /**
+     * If true, automatically includes the common assemblies
+     * in dotnet, and tells the compiler to link in mscore.dll.
+     *
+     *  set the automatic reference inclusion flag on or off this flag controls
+     *  the /nostdlib option in CSC
+     *
+     *@param  f  on/off flag
+     */
+    public void setIncludeDefaultReferences(boolean f) {
+        includeDefaultReferences = f;
+    }
+
+
+    /**
+     *  query automatic reference inclusion flag
+     *
+     *@return    true if flag is turned on
+     */
+    public boolean getIncludeDefaultReferences() {
+        return includeDefaultReferences;
+    }
+
+
+    /**
+     *  get the include default references flag or null for no argument needed
+     *
+     *@return    The Parameter to CSC
+     */
+    protected String getIncludeDefaultReferencesParameter() {
+        return "/nostdlib" + (includeDefaultReferences ? "-" : "+");
+    }
+
+
+
+    /**
+     * If true, enables optimization flag.
+     *
+     *@param  f  on/off flag
+     */
+    public void setOptimize(boolean f) {
+        optimize = f;
+    }
+
+
+    /**
+     *  query the optimise flag
+     *
+     *@return    true if optimise is turned on
+     */
+    public boolean getOptimize() {
+        return optimize;
+    }
+
+
+    /**
+     *  get the optimise flag or null for no argument needed
+     *
+     *@return    The Optimize Parameter to CSC
+     */
+    protected String getOptimizeParameter() {
+        return "/optimize" + (optimize ? "+" : "-");
+    }
+
+
+    /**
+     *  set the debug flag on or off.
+     *
+     *@param  f  on/off flag
+     */
+    public void setDebug(boolean f) {
+        debug = f;
+    }
+
+
+    /**
+     *  query the debug flag
+     *
+     *@return    true if debug is turned on
+     */
+    public boolean getDebug() {
+        return debug;
+    }
+
+
+    /**
+     *  get the debug switch argument
+     *
+     *@return    The Debug Parameter to CSC
+     */
+    protected String getDebugParameter() {
+        return "/debug" + (debug ? "+" : "-");
+    }
+
+
+    /**
+     * Level of warning currently between 1 and 4
+     * with 4 being the strictest.
+     *
+     *@param  warnLevel  warn level -see .net docs for valid range (probably
+     *      0-4)
+     */
+    public void setWarnLevel(int warnLevel) {
+        this.warnLevel = warnLevel;
+    }
+
+
+    /**
+     *  query warn level
+     *
+     *@return    current value
+     */
+    public int getWarnLevel() {
+        return warnLevel;
+    }
+
+
+    /**
+     *  get the warn level switch
+     *
+     *@return    The WarnLevel Parameter to CSC
+     */
+    protected String getWarnLevelParameter() {
+        return "/warn:" + warnLevel;
+    }
+
+
+    /**
+     *  Sets the name of main class for executables.
+     *
+     *@param  mainClass  The new MainClass value
+     */
+    public void setMainClass(String mainClass) {
+        this.mainClass = mainClass;
+    }
+
+
+    /**
+     *  Gets the MainClass attribute
+     *
+     *@return    The MainClass value
+     */
+    public String getMainClass() {
+        return this.mainClass;
+    }
+
+
+    /**
+     *  get the /main argument or null for no argument needed
+     *
+     *@return    The MainClass Parameter to CSC
+     */
+    protected String getMainClassParameter() {
+        if (mainClass != null && mainClass.length() != 0) {
+            return "/main:" + mainClass;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Any extra options which are not explicitly supported
+     * by this task.
+     *
+     *@param  extraOptions  The new ExtraOptions value
+     */
+    public void setExtraOptions(String extraOptions) {
+        this.extraOptions = extraOptions;
+    }
+
+
+    /**
+     *  Gets the ExtraOptions attribute
+     *
+     *@return    The ExtraOptions value
+     */
+    public String getExtraOptions() {
+        return this.extraOptions;
+    }
+
+
+    /**
+     *  get any extra options or null for no argument needed
+     *
+     *@return    The ExtraOptions Parameter to CSC
+     */
+    protected String getExtraOptionsParameter() {
+        if (extraOptions != null && extraOptions.length() != 0) {
+            return extraOptions;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     *  get any extra options or null for no argument needed, split
+     *  them if they represent multiple options.
+     *
+     * @return    The ExtraOptions Parameter to CSC
+     */
+    protected String[] getExtraOptionsParameters() {
+        String extra = getExtraOptionsParameter();
+        return extra == null ? null : Commandline.translateCommandline(extra);
+    }
+
+    /**
+     * Set the destination directory of files to be compiled.
+     *
+     *@param  dirName  The new DestDir value
+     */
+    public void setDestDir(File dirName) {
+        log("DestDir currently unused", Project.MSG_WARN);
+    }
+
+
+    /**
+     * set the target type to one of exe|library|module|winexe
+     * @param targetType the enumerated value.
+     */
+    public void setTargetType(TargetTypes targetType) {
+        this.targetType = targetType.getValue();
+    }
+    /**
+     * Set the type of target.
+     *
+     *@param  ttype          The new TargetType value
+     *@exception  BuildException  if target is not one of
+     *      exe|library|module|winexe
+     */
+    public void setTargetType(String ttype)
+             throws BuildException {
+        ttype = ttype.toLowerCase();
+        if (ttype.equals("exe") || ttype.equals("library")
+            || ttype.equals("module") || ttype.equals("winexe")) {
+            targetType = ttype;
+        } else {
+            throw new BuildException("targetType " + ttype
+                    + " is not one of 'exe', 'module', 'winexe' or 'library'");
+        }
+    }
+
+
+    /**
+     *  Gets the TargetType attribute
+     *
+     *@return    The TargetType value
+     */
+    public String getTargetType() {
+        return targetType;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The TargetType Parameter to CSC
+     */
+    protected String getTargetTypeParameter() {
+        if (notEmpty(targetType)) {
+            return "/target:" + targetType;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     *  Set the filename of icon to include.
+     *
+     *@param  fileName  path to the file. Can be relative, absolute, whatever.
+     */
+    public void setWin32Icon(File fileName) {
+        win32icon = fileName;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The Win32Icon Parameter to CSC
+     */
+    protected String getWin32IconParameter() {
+        if (win32icon != null) {
+            return "/win32icon:" + win32icon.toString();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Sets the filename of a win32 resource (.RES) file to include.
+     * This is not a .NET resource, but what Windows is used to.
+     *
+     *@param  fileName  path to the file. Can be relative, absolute, whatever.
+     */
+    public void setWin32Res(File fileName) {
+        win32res = fileName;
+    }
+
+    /**
+     * Gets the file of the win32 .res file to include.
+     * @return path to the file.
+     */
+    public File getWin32Res() {
+        return win32res;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The Win32Res Parameter to CSC
+     */
+    protected String getWin32ResParameter() {
+        if (win32res != null) {
+            return "/win32res:" + win32res.toString();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * If true, require all compiler output to be in UTF8 format.
+     *
+     *@param  enabled  The new utf8Output value
+     */
+    public void setUtf8Output(boolean enabled) {
+        utf8output = enabled;
+    }
+
+
+    /**
+     *  Gets the utf8OutpuParameter attribute of the CSharp object
+     *
+     *@return    The utf8OutpuParameter value
+     */
+    protected String getUtf8OutputParameter() {
+        return utf8output ? "/utf8output" : null;
+    }
+
+
+    /**
+     * add a define to the list of definitions
+     * @param define the define value.
+     */
+    public void addDefine(DotnetDefine define) {
+        definitionList.addElement(define);
+    }
+
+
+    /**
+     * get a list of definitions or null
+     * @return a string beginning /D: or null for no definitions
+     * @throws BuildException if there is an error.
+     */
+    protected String getDefinitionsParameter() throws BuildException {
+        StringBuffer defines = new StringBuffer();
+        Enumeration defEnum = definitionList.elements();
+        boolean firstDefinition = true;
+        while (defEnum.hasMoreElements()) {
+            //loop through all definitions
+            DotnetDefine define = (DotnetDefine) defEnum.nextElement();
+            if (define.isSet(this)) {
+                //add those that are set, and a delimiter
+                if (!firstDefinition) {
+                    defines.append(getDefinitionsDelimiter());
+                }
+                defines.append(define.getValue(this));
+                firstDefinition = false;
+            }
+        }
+        if (defines.length() == 0) {
+            return null;
+        } else {
+            return "/d:" + defines;
+        }
+    }
+
+
+    /**
+     * Semicolon separated list of modules to refer to.
+     *
+     *@param  params  The new additionalModules value
+     */
+    public void setAdditionalModules(String params) {
+        additionalModules = params;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The AdditionalModules Parameter to CSC
+     */
+    protected String getAdditionalModulesParameter() {
+        if (notEmpty(additionalModules)) {
+            return "/addmodule:" + additionalModules;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The OutputFile Parameter to CSC
+     */
+    protected String getDestFileParameter() {
+        if (outputFile != null) {
+            return "/out:" + outputFile.toString();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * If true, fail on compilation errors.
+     *
+     *@param  b  The new FailOnError value
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+
+    /**
+     *  query fail on error flag
+     *
+     *@return    The FailFailOnError value
+     */
+    public boolean getFailOnError() {
+        return failOnError;
+    }
+
+    /**
+     * link or embed a resource
+     * @param resource the resource to use.
+     */
+    public void addResource(DotnetResource resource) {
+        resources.add(resource);
+    }
+
+    /**
+     * This method gets the name of the executable.
+     * @return the name of the executable
+     */
+    protected String getExecutable() {
+        return executable;
+    }
+
+    /**
+     * set the name of the program, overriding the defaults.
+     * Can be used to set the full path to a program, or to switch
+     * to an alternate implementation of the command, such as the Mono or Rotor
+     * versions -provided they use the same command line arguments as the
+     * .NET framework edition
+     * @param executable the name of the program.
+     */
+    public void setExecutable(String executable) {
+        this.executable = executable;
+    }
+
+    /**
+     *  test for a string containing something useful
+     *
+     *@param  s  string in
+     *@return    true if the argument is not null or empty
+     */
+    protected boolean notEmpty(String s) {
+        return s != null && s.length() != 0;
+    }
+
+    /**
+     * validation code
+     * @throws  BuildException  if validation failed
+     */
+    protected void validate()
+            throws BuildException {
+        if (outputFile != null && outputFile.isDirectory()) {
+            throw new BuildException("destFile cannot be a directory");
+        }
+        if (getExecutable() == null) {
+            throw new BuildException("There is no executable defined for this task");
+        }
+    }
+
+    /**
+     * Get the pattern for files to compile.
+     * @return The compilation file pattern.
+     */
+    public String getFilePattern() {
+        return "**/*." + getFileExtension();
+    }
+
+    /**
+     * getter for flag
+     * @return The flag indicating whether the compilation is using a response file.
+     */
+    public boolean isUseResponseFile() {
+        return useResponseFile;
+    }
+
+    /**
+     * Flag to turn on response file use; default=false.
+     * When set the command params are saved to a file and
+     * this is passed in with @file. The task automatically switches
+     * to this mode with big commands; this option is here for
+     * testing and emergencies
+     * @param useResponseFile a <code>boolean</code> value.
+     */
+    public void setUseResponseFile(boolean useResponseFile) {
+        this.useResponseFile = useResponseFile;
+    }
+
+    /**
+     *  do the work by building the command line and then calling it
+     *
+     *@throws  BuildException  if validation or execution failed
+     */
+    public void execute()
+             throws BuildException {
+        log("This task is deprecated and will be removed in a future version\n"
+            + "of Ant.  It is now part of the .NET Antlib:\n"
+            + "http://ant.apache.org/antlibs/dotnet/index.html",
+            Project.MSG_WARN);
+
+        validate();
+        NetCommand command = createNetCommand();
+        //set up response file options
+        command.setAutomaticResponseFileThreshold(AUTOMATIC_RESPONSE_FILE_THRESHOLD);
+        command.setUseResponseFile(useResponseFile);
+        //fill in args
+        fillInSharedParameters(command);
+        addResources(command);
+        addCompilerSpecificOptions(command);
+        int referencesOutOfDate
+            = addReferenceFilesets(command, getOutputFileTimestamp());
+        //if the refs are out of date, force a build.
+        boolean forceBuild = referencesOutOfDate > 0;
+        addFilesAndExecute(command, forceBuild);
+
+    }
+
+    /**
+     * Get the delimiter that the compiler uses between references.
+     * For example, c# will return ";"; VB.NET will return ","
+     * @return The string delimiter for the reference string.
+     */
+    public abstract String getReferenceDelimiter();
+
+    /**
+     * Get the extension of filenames to compile.
+     * @return The string extension of files to compile.
+     */
+    public abstract String getFileExtension();
+
+
+    /**
+     * fill in the common information
+     * @param command the net command.
+     */
+    protected void fillInSharedParameters(NetCommand command) {
+        command.setFailOnError(getFailOnError());
+        //fill in args
+        command.addArgument("/nologo");
+        command.addArgument(getAdditionalModulesParameter());
+        command.addArgument(getDebugParameter());
+        command.addArgument(getDefinitionsParameter());
+        command.addArguments(getExtraOptionsParameters());
+        command.addArgument(getMainClassParameter());
+        command.addArgument(getOptimizeParameter());
+        command.addArgument(getDestFileParameter());
+        command.addArgument(getReferencesParameter());
+        command.addArgument(getTargetTypeParameter());
+        command.addArgument(getUtf8OutputParameter());
+        command.addArgument(getWin32IconParameter());
+        command.addArgument(getWin32ResParameter());
+    }
+
+    /**
+     * for every resource declared, we get the (language specific)
+     * resource setting
+     * @param command the net command.
+     */
+    protected void addResources(NetCommand command) {
+        Enumeration e = resources.elements();
+        while (e.hasMoreElements()) {
+            DotnetResource resource = (DotnetResource) e.nextElement();
+            createResourceParameter(command, resource);
+        }
+    }
+
+    /**
+     * Build a C# style parameter.
+     * @param command the command.
+     * @param resource the resource.
+     */
+    protected abstract void createResourceParameter(NetCommand command, DotnetResource resource);
+
+
+    /**
+     * run through the list of reference files and add them to the command
+     * @param command the command to use.
+     * @param outputTimestamp timestamp to compare against
+     * @return number of files out of date
+     */
+
+    protected int addReferenceFilesets(NetCommand command, long outputTimestamp) {
+        int filesOutOfDate = 0;
+        Hashtable filesToBuild = new Hashtable();
+        for (int i = 0; i < referenceFilesets.size(); i++) {
+            FileSet fs = (FileSet) referenceFilesets.elementAt(i);
+            filesOutOfDate += command.scanOneFileset(
+                    fs.getDirectoryScanner(getProject()),
+                    filesToBuild,
+                    outputTimestamp);
+        }
+        //bail out early if there were no files
+        if (filesToBuild.size() == 0) {
+            return 0;
+        }
+        //now scan the hashtable and add the files
+        Enumeration files = filesToBuild.elements();
+        while (files.hasMoreElements()) {
+            File file = (File) files.nextElement();
+            if (isFileManagedBinary(file)) {
+                if (isWindows) {
+                    command.addArgument(
+                    '"' + REFERENCE_OPTION + file.toString() + '"');
+                } else {
+                    command.addArgument(REFERENCE_OPTION + file.toString());
+                }
+            } else {
+                log("ignoring " + file + " as it is not a managed executable",
+                        Project.MSG_VERBOSE);
+            }
+
+        }
+
+        return filesOutOfDate;
+    }
+
+    /**
+     * create our helper command
+     * @return a command prefilled with the exe name and task name
+     */
+    protected NetCommand createNetCommand() {
+        NetCommand command = new NetCommand(this, getTaskName(), getExecutable());
+        return command;
+    }
+
+    /**
+     * add any compiler specifics
+     * @param command the command to use.
+     */
+    protected abstract void addCompilerSpecificOptions(NetCommand command);
+
+    /**
+     * override point for delimiting definitions.
+     * @return The definitions limiter, i.e., ";"
+     */
+    public String getDefinitionsDelimiter() {
+        return ";";
+    }
+
+
+    /**
+     * test for a file being managed or not
+     * @param file the file to test.
+     * @return true if we think this is a managed executable, and thus OK
+     * for linking
+     * @todo look at the PE header of the exe and see if it is managed or not.
+     */
+    protected static boolean isFileManagedBinary(File file) {
+        String filename = file.toString().toLowerCase();
+        return filename.endsWith(".exe") || filename.endsWith(".dll")
+                || filename.endsWith(".netmodule");
+    }
+
+    /**
+     * Target types to build.
+     * valid build types are exe|library|module|winexe
+     */
+    public static class TargetTypes extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {
+                "exe",
+                "library",
+                "module",
+                "winexe"
+            };
+        }
+    }
+
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetDefine.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetDefine.java
new file mode 100644
index 0000000..6de336f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetDefine.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+
+/**
+ * definitions can be conditional. What .NET conditions can not be
+ * is in any state other than defined and undefined; you cannot give
+ * a definition a value.
+ */
+public class DotnetDefine {
+    private String name;
+    private String ifCond;
+    private String unlessCond;
+
+
+    /**
+     * the name of a property which must be defined for
+     * the definition to be set. Optional.
+     * @param condition the name of the property
+     */
+    public void setIf(String condition) {
+        this.ifCond = condition;
+    }
+
+    /**
+     * the name of a property which must be undefined for
+     * the definition to be set. Optional.
+     * @param condition the name of the property
+     */
+    public void setUnless(String condition) {
+        this.unlessCond = condition;
+    }
+
+    /**
+     * Get the name of the definition.
+     * @return the name.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * the name of the definition. Required.
+     * @param name the name value.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * This method gets the value of this definition. Will be null if a condition
+     * was declared and not met
+     * @param owner owning task
+     * @return The value of the definition.
+     * @throws BuildException if there is an error.
+     */
+    public String getValue(Task owner) throws BuildException {
+        if (name == null) {
+            throw new BuildException("No name provided for the define element",
+                owner.getLocation());
+        }
+        if (!isSet(owner)) {
+            return null;
+        }
+        return name;
+    }
+
+
+    /**
+     * logic taken from patternset
+     * @param owner the owning task.
+     * @return true if the condition is valid
+     */
+    public boolean isSet(Task owner) {
+        Project p = owner.getProject();
+        if (ifCond != null && p.getProperty(ifCond) == null) {
+            return false;
+        } else if (unlessCond != null && p.getProperty(unlessCond) != null) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetResource.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetResource.java
new file mode 100644
index 0000000..0ca4f61
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/DotnetResource.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+
+import java.io.File;
+import java.util.ArrayList;
+import org.apache.tools.ant.types.FileSet;
+import java.util.Iterator;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+
+/**
+ * Used by {@link DotnetCompile} to name resources.
+ * Could be upgraded to a datatype in the distant future.
+ * A resource maps to /res:file,name
+ */
+public class DotnetResource {
+
+    /**
+     * name of resource
+     */
+    private File file;
+
+    /**
+     * embed (default) or link the resource
+     */
+    private boolean embed = true;
+
+    /**
+     * this is used in VBC and JSC
+     */
+    private Boolean isPublic = null;
+
+    /**
+     * name of the object
+     */
+    private String name = null;
+
+    /**
+     * A list of filesets with resources.
+     */
+    private ArrayList fileSets = new ArrayList();
+
+    /**
+     * a namespace to be used with <filesets>
+     */
+    private String namespace = null;
+
+    /**
+     * Return the embed attribute.
+     * @return the embed value.
+     */
+    public boolean isEmbed() {
+        return embed;
+    }
+
+    /**
+     * embed the resource in the assembly (default, true) or just link to it.
+     *
+     * @param embed a <code>boolean</code> value.
+     */
+    public void setEmbed(boolean embed) {
+        this.embed = embed;
+    }
+
+    /**
+     * The file resource.
+     * @return the file resource.
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * name the resource
+     *
+     * @param file the file.
+     */
+    public void setFile(File file) {
+        this.file = file;
+    }
+
+    /**
+     * Get the public attribute.
+     * @return the public attribute.
+     */
+    public Boolean getPublic() {
+        return isPublic;
+    }
+
+    /**
+     * VB and J# only: is a resource public or not?
+     *
+     * @param aPublic a <code>boolean</code> value.
+     */
+    public void setPublic(Boolean aPublic) {
+        isPublic = aPublic;
+    }
+
+    /**
+     * The name of the resource.
+     * @return the name of the resource.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * should the resource have a name?
+     *
+     * @param name the name of the resource.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Filesets root namespace. The value always ends with '.' .
+     *
+     * @return String namespace name
+     */
+    public String getNamespace() {
+        return namespace;
+    }
+
+    /**
+     * Sets filesets root namespace.
+     *
+     * @param namespace
+     *            String root namespace
+     */
+    public void setNamespace(String namespace) {
+        if (namespace == null) {
+            this.namespace = null;
+        } else {
+            this.namespace = (namespace.length() == 0 || namespace.endsWith(".") ? namespace
+                    : namespace + '.');
+        }
+    }
+
+    private void checkParameters() {
+        if (hasFilesets()) {
+            if (getName() != null) {
+                throw new BuildException(
+                        "Cannot use <resource name=\"...\"> attribute with filesets");
+            }
+            if (getFile() != null) {
+                throw new BuildException(
+                        "Cannot use <resource file=\"...\"> attribute with filesets");
+            }
+        } else {
+            if (getNamespace() != null) {
+                throw new BuildException(
+                        "Cannot use <resource namespace=\"...\"> attribute without filesets");
+            }
+        }
+    }
+
+    /**
+     * build the C# style parameter (which has no public/private option)
+     * @param p the current project.
+     * @param command the command.
+     * @param csharpStyle a <code>boolean</code> attribute.
+     */
+    public void getParameters(Project p, NetCommand command, boolean csharpStyle) {
+        checkParameters();
+        if (hasFilesets()) {
+            for (Iterator listIter = fileSets.iterator(); listIter.hasNext();) {
+                FileSet fs = (FileSet) listIter.next();
+                String baseDirectory = fs.getDir(p).toString();
+                String namespace = getNamespace(); // ends with '.' or null
+                DirectoryScanner ds = fs.getDirectoryScanner(p);
+                String[] files = ds.getIncludedFiles();
+                for (int i = 0; i < files.length; i++) {
+                    String file = files[i];
+                    command.addArgument(getParameter(baseDirectory + File.separatorChar + file,
+                            (namespace == null ? null : namespace
+                                    + file.replace(File.separatorChar, '.')), csharpStyle));
+                }
+            }
+        } else {
+            command.addArgument(getParameter(getFile().toString(), getName(), csharpStyle));
+        }
+    }
+
+    private String getParameter(String fileName, String name, boolean csharpStyle) {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(isEmbed() ? "/resource" : "/linkresource");
+        buffer.append(':');
+        buffer.append(fileName);
+        if (name != null) {
+            buffer.append(',');
+            buffer.append(name);
+            if (csharpStyle) {
+                if (getPublic() != null) {
+                    throw new BuildException("This compiler does not support the "
+                            + "public/private option.");
+                } else {
+                    if (getPublic() != null) {
+                        buffer.append(',');
+                        buffer.append(getPublic().booleanValue() ? "public" : "private");
+
+                    }
+                }
+            } else if (getPublic() != null) {
+                throw new BuildException("You cannot have a public or private "
+                        + "option without naming the resource");
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Adds a resource file set.
+     *
+     * @param fileset
+     *            FileSet
+     */
+    public void addFileset(FileSet fileset) {
+        fileSets.add(fileset);
+    }
+
+    /**
+     * Checks that <resource> node has embedded <filesets>
+     *
+     * @return boolean
+     */
+    public boolean hasFilesets() {
+        return fileSets.size() > 0;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ilasm.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ilasm.java
new file mode 100644
index 0000000..cc6a49d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ilasm.java
@@ -0,0 +1,540 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ *  build notes
+ *  -The reference CD to listen to while editing this file is
+ *  nap: Underworld  - Everything, Everything
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Assembles .NET Intermediate Language files.
+ * ilasm.exe must be on the execute path, unless another executable
+ * or the full path to that executable is specified in the <tt>executable</tt>
+ * parameter
+ *  <p>
+ *
+ *  <p>
+ *
+ *  All parameters are optional: &lt;il/&gt; should suffice to produce a debug
+ *  build of all *.il files. The option set is roughly compatible with the
+ *  CSharp class; even though the command line options are only vaguely
+ *  equivalent. [The low level commands take things like /OUT=file, csc wants
+ *  /out:file ... /verbose is used some places; /quiet here in ildasm... etc.]
+ *  It would be nice if someone made all the command line tools consistent (and
+ *  not as brittle as the java cmdline tools) <p>
+ *  <p>
+ *  The task is a directory based task, so attributes like <b>includes="*.il"
+ *  </b> and <b>excludes="broken.il"</b> can be used to control the files pulled
+ *  in. You can also use nested &lt;src&gt filesets to refer to source.
+ * <p>
+ *
+ * @ant.task    name="ilasm" category="dotnet"
+ */
+
+public class Ilasm
+         extends DotnetBaseMatchingTask {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    // CheckStyle:ConstantNameCheck OFF - bc
+    /**
+     *  Name of the executable. The .exe suffix is deliberately not included in
+     *  anticipation of the unix version
+     */
+    protected static final String exe_name = "ilasm";
+
+    /**
+     *  what is the file extension we search on?
+     */
+    protected static final String file_ext = "il";
+
+    /**
+     *  and now derive the search pattern from the extension
+     */
+    protected static final String file_pattern = "**/*." + file_ext;
+
+    /**
+     *  title of task for external presentation
+     */
+    protected static final String exe_title = "ilasm";
+
+    /**
+     *  type of target. Should be one of exe|library|module|winexe|(null)
+     *  default is exe; the actual value (if not null) is fed to the command
+     *  line. <br>
+     *  See /target
+     */
+    protected String targetType;
+
+    /**
+     *  verbose flag
+     */
+    protected boolean verbose;
+
+    /**
+     *  listing flag
+     */
+
+    protected boolean listing;
+
+    /**
+     *  resource file (.res format) to include in the app.
+     */
+    protected File resourceFile;
+
+    /**
+     *  flag to control action on execution trouble
+     */
+    protected boolean failOnError;
+
+    /**
+     *  debug flag. Controls generation of debug information.
+     */
+    protected boolean debug;
+
+    /**
+     *  file containing private key
+     */
+
+    private File keyfile;
+
+    /**
+     *  any extra command options?
+     */
+    protected String extraOptions;
+
+    /**
+     * filesets of references
+     */
+    protected Vector referenceFilesets = new Vector();
+
+    // CheckStyle:ConstantNameCheck ON
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * @since Ant 1.7
+     */
+    private boolean isMono = !Os.isFamily("windows");
+
+    /**
+     *  constructor inits everything and set up the search pattern
+     */
+    public Ilasm() {
+        Clear();
+        setIncludes(file_pattern);
+    }
+
+    // CheckStyle:MethodNameCheck OFF - bc
+    /**
+     *  reset all contents.
+     */
+    public void Clear() {
+        targetType = null;
+        srcDir = null;
+        listing = false;
+        verbose = false;
+        debug = true;
+        outputFile = null;
+        failOnError = true;
+        resourceFile = null;
+        extraOptions = null;
+    }
+    // CheckStyle:MethodNameCheck ON
+
+
+
+    /**
+     * Sets the type of target, either "exe" or "library".
+     *
+     *@param  targetType          one of exe|library|
+     *@exception  BuildException  if target is not one of
+     *      exe|library
+     */
+    public void setTargetType(String targetType)
+             throws BuildException {
+        this.targetType = targetType.toLowerCase();
+        if (!targetType.equals("exe") && !targetType.equals("library")) {
+            throw new BuildException("targetType " + targetType + " is not a valid type");
+        }
+    }
+
+
+    /**
+     *  accessor method for target type
+     *
+     *@return    the current target option
+     */
+    public String getTargetType() {
+        return targetType;
+    }
+
+
+    /**
+     *  g get the target type or null for no argument needed
+     *
+     *@return    The TargetTypeParameter value
+     */
+
+    protected String getTargetTypeParameter() {
+        if (!notEmpty(targetType)) {
+            return null;
+        }
+        if (targetType.equals("exe")) {
+            return "/exe";
+        } else if (targetType.equals("library")) {
+            return "/dll";
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Sets the Owner attribute.
+     *
+     * @param  s  The new Owner value
+     * @ant.attribute ignore="true"
+     */
+    public void setOwner(String s) {
+        log("This option is not supported by ILASM as of Beta-2, "
+            + "and will be ignored", Project.MSG_WARN);
+    }
+
+
+    /**
+     *  test for a string containing something useful
+     *
+     *@param  s       any string
+     *@return         true if the argument is not null or empty
+     */
+    protected boolean notEmpty(String s) {
+        return s != null && s.length() != 0;
+    }
+
+
+    /**
+     *  If true, enable verbose ILASM output.
+     *
+     *@param  b  flag set to true for verbose on
+     */
+    public void setVerbose(boolean b) {
+        verbose = b;
+    }
+
+
+    /**
+     *  turn the verbose flag into a parameter for ILASM
+     *
+     *@return    null or the appropriate command line string
+     */
+    protected String getVerboseParameter() {
+        return verbose ? null : "/quiet";
+    }
+
+
+    /**
+     * If true, produce a listing (off by default).
+     *
+     *@param  b  flag set to true for listing on
+     */
+    public void setListing(boolean b) {
+        listing = b;
+    }
+
+
+    /**
+     *  turn the listing flag into a parameter for ILASM
+     *
+     *@return    the appropriate string from the state of the listing flag
+     */
+    protected String getListingParameter() {
+        if (!isMono) {
+            return listing ? "/listing" : "/nolisting";
+        }
+        return null;
+    }
+
+
+    /**
+     * Set the output file; identical to setDestFile
+     * @see DotnetBaseMatchingTask#setDestFile
+     *@param  params  The new outputFile value
+     */
+    public void setOutputFile(File params) {
+        outputFile = params;
+    }
+
+
+    /**
+     *  get the output file
+     *
+     *@return    the argument string or null for no argument
+     */
+    protected String getOutputFileParameter() {
+        if (outputFile == null) {
+            return null;
+        }
+        return "/output=" + outputFile.toString();
+    }
+
+
+    /**
+     * name of resource file to include.
+     *
+     * @param  fileName  path to the file. Can be relative, absolute, whatever.
+     */
+    public void setResourceFile(File fileName) {
+        resourceFile = fileName;
+    }
+
+
+    /**
+     *  Gets the resourceFileParameter attribute of the Ilasm task
+     *
+     *@return    The resourceFileParameter value
+     */
+    protected String getResourceFileParameter() {
+        if (resourceFile != null) {
+            return "/resource=" + resourceFile.toString();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * If true, fails if ilasm tool fails.
+     *
+     *@param  b  The new failOnError value
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+
+    /**
+     *  query fail on error flag
+     *
+     *@return    The failFailOnError value
+     */
+    public boolean getFailOnError() {
+        return failOnError;
+    }
+
+
+    /**
+     *  set the debug flag on or off.
+     *
+     *@param  f  on/off flag
+     */
+    public void setDebug(boolean f) {
+        debug = f;
+    }
+
+
+    /**
+     *  query the debug flag
+     *
+     *@return    true if debug is turned on
+     */
+    public boolean getDebug() {
+        return debug;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The debugParameter value
+     */
+    protected String getDebugParameter() {
+        return debug ? "/debug" : null;
+    }
+
+
+    /**
+     * the name of a file containing a private key.
+     *
+     *@param  keyfile  The new keyfile value
+     */
+    public void setKeyfile(File keyfile) {
+        this.keyfile = keyfile;
+    }
+
+
+    /**
+     *  get the argument or null for no argument needed
+     *
+     *@return    The keyfileParameter value
+     */
+    protected String getKeyfileParameter() {
+        if (keyfile != null) {
+            return "/keyfile:" + keyfile.toString();
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Any extra options which are not explicitly
+     * supported by this task.
+     *
+     *@param  extraOptions  The new ExtraOptions value
+     */
+    public void setExtraOptions(String extraOptions) {
+        this.extraOptions = extraOptions;
+    }
+
+
+    /**
+     *  Gets the ExtraOptions attribute
+     *
+     *@return    The ExtraOptions value
+     */
+    public String getExtraOptions() {
+        return this.extraOptions;
+    }
+
+
+    /**
+     *  get any extra options or null for no argument needed
+     *
+     *@return    The ExtraOptions Parameter to CSC
+     */
+    protected String getExtraOptionsParameter() {
+        if (extraOptions != null && extraOptions.length() != 0) {
+            return extraOptions;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * set the target type to one of exe|library
+     * @param targetType the enumerated value.
+     */
+    public void setTargetType(TargetTypes targetType) {
+        this.targetType = targetType.getValue();
+    }
+
+    /**
+     * Explicitly override the Mono auto-detection.
+     *
+     * <p>Defaults to false on Windows and true on any other platform.</p>
+     * @param b a <code>boolean</code> value.
+     * @since Ant 1.7
+     */
+    public void setMono(boolean b) {
+        isMono = b;
+    }
+
+    /**
+     *  This is the execution entry point. Build a list of files and call ilasm
+     *  on each of them.
+     *
+     *@throws  BuildException  if the assembly failed and FailOnError is true
+     */
+    public void execute()
+             throws BuildException {
+        log("This task is deprecated and will be removed in a future version\n"
+            + "of Ant.  It is now part of the .NET Antlib:\n"
+            + "http://ant.apache.org/antlibs/dotnet/index.html",
+            Project.MSG_WARN);
+        NetCommand command = buildIlasmCommand();
+
+        addFilesAndExecute(command, false);
+
+    }
+    // end execute
+
+
+    /**
+     * build up our ilasm command
+     * @return
+     */
+    private NetCommand buildIlasmCommand() {
+        NetCommand command = new NetCommand(this, exe_title, exe_name);
+        command.setFailOnError(getFailOnError());
+        //fill in args
+        command.addArgument(getDebugParameter());
+        command.addArgument(getTargetTypeParameter());
+        command.addArgument(getListingParameter());
+        command.addArgument(getOutputFileParameter());
+        command.addArgument(getResourceFileParameter());
+        command.addArgument(getVerboseParameter());
+        command.addArgument(getKeyfileParameter());
+        command.addArgument(getExtraOptionsParameter());
+
+        /*
+         *  space for more argumentativeness
+         *  command.addArgument();
+         *  command.addArgument();
+         */
+        return command;
+    }
+
+    /**
+     * add a new reference fileset to the compilation
+     * @param reference the fileset to use.
+     */
+    public void addReference(FileSet reference) {
+        referenceFilesets.add(reference);
+    }
+
+    /**
+     * test for a file being managed or not
+     * @param file the file to test.
+     * @return true if we think this is a managed executable, and thus OK
+     * for linking
+     * @todo look at the PE header of the exe and see if it is managed or not.
+     */
+    protected static boolean isFileManagedBinary(File file) {
+        String filename = file.toString().toLowerCase();
+        return filename.endsWith(".exe") || filename.endsWith(".dll")
+                || filename.endsWith(".netmodule");
+    }
+
+
+    /**
+     * Target types to build.
+     * valid build types are exe|library|module|winexe
+     */
+    public static class TargetTypes extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{
+                "exe",
+                "library",
+            };
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ildasm.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ildasm.java
new file mode 100644
index 0000000..41b9a8a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/Ildasm.java
@@ -0,0 +1,474 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+
+/**
+ * Task to take a .NET or Mono -generated managed executable and turn it
+ * into ILASM assembly code. Useful when converting imported typelibs into
+ * assembler before patching and recompiling, as one has to do when doing
+ * advanced typelib work.
+ * <p>
+ * As well as generating the named output file, the ildasm program
+ * will also generate resource files <code>Icons.resources</code>
+ * <code>Message.resources</code> and a .res file whose filename stub is derived
+ * from the source in ways to obscure to determine.
+ * There is no way to control whether or not these files are created, or where they are created
+ * (they are created in the current directory; their names come from inside the
+ * executable and may be those used by the original developer). This task
+ * creates the resources in the directory specified by <code>resourceDir</code> if
+ * set, else in the same directory as the <code>destFile</code>.
+ *
+ * <p>
+ * This task requires the .NET SDK installed and ildasm on the path.
+ * To disassemble using alternate CLR systems, set the executable attribute
+ * to the name/path of the alternate implementation -one that must
+ * support all the classic ildasm commands.
+ *
+ * <p>
+ * Dependency logic: the task executes the command if the output file is missing
+ * or older than the source file. It does not take into account changes
+ * in the options of the task, or timestamp differences in resource files.
+ * When the underlying ildasm executable fails for some reason, it leaves the
+ * .il file in place with some error message. To prevent this from confusing
+ * the dependency logic, the file specified by the <code>dest</code>
+ * attribute is <i>always</i> deleted after an unsuccessful build.
+ * @ant.task category="dotnet"
+ */
+public class Ildasm extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * source file (mandatory)
+     */
+    private File sourceFile;
+
+    /**
+     * dest file (mandatory)
+     */
+    private File destFile;
+    /**
+     * progress bar switch
+     */
+    private boolean progressBar = false;
+
+    /**
+     * what is our encoding
+     */
+    private String encoding;
+
+    /**
+     * /bytes flag for byte markup
+     */
+
+    private boolean bytes = false;
+
+    /**
+     * line numbers? /linenum
+     */
+    private boolean linenumbers = false;
+
+    /**
+     * /raweh flag for raw exception handling
+     */
+    private boolean rawExceptionHandling = false;
+
+    /**
+     * show the source; /source
+     */
+    private boolean showSource = false;
+
+    /**
+     * /quoteallnames to quote all names
+     */
+    private boolean quoteallnames = false;
+
+    /**
+     * /header for header information
+     */
+    private boolean header = false;
+
+    /**
+     * when false, sets the /noil attribute
+     * to suppress assembly info
+     */
+    private boolean assembler = true;
+
+    /**
+     * include metadata
+     * /tokens
+     */
+
+    private boolean metadata = false;
+
+    /**
+     * what visibility do we want.
+     *
+     */
+    private String visibility;
+
+    /**
+     * specific item to disassemble
+     */
+
+    private String item;
+
+    /**
+     * override for the executable
+     */
+    private String executable = "ildasm";
+
+    /**
+     *  name of the directory for resources to be created. We cannot control
+     * their names, but we can say where they get created. If not set, the
+     * directory of the dest file is used
+     */
+    private File resourceDir;
+
+
+    /**
+     * Set the name of the directory for resources to be created. We cannot control
+     * their names, but we can say where they get created. If not set, the
+     * directory of the dest file is used
+     * @param resourceDir the directory in which to create resources.
+     */
+    public void setResourceDir(File resourceDir) {
+        this.resourceDir = resourceDir;
+    }
+
+    /**
+     * override the name of the executable (normally ildasm) or set
+     * its full path. Do not set a relative path, as the ugly hacks
+     * needed to create resource files in the dest directory
+     * force us to change to this directory before running the application.
+     * i.e use &lt;property location&gt to create an absolute path from a
+     * relative one before setting this value.
+     * @param executable the name of the executable to use.
+     */
+    public void setExecutable(String executable) {
+        this.executable = executable;
+    }
+
+    /**
+     * Select the output encoding: ascii, utf8 or unicode
+     * @param encoding the enumerated value.
+     */
+    public void setEncoding(EncodingTypes encoding) {
+        this.encoding = encoding.getValue();
+    }
+
+    /**
+     * enable (default) or disable assembly language in the output
+     * @param assembler a <code>boolean</code> value.
+     */
+    public void setAssembler(boolean assembler) {
+        this.assembler = assembler;
+    }
+
+    /**
+     * enable or disable (default) the original bytes as comments
+     * @param bytes a <code>boolean</code> value.
+     */
+    public void setBytes(boolean bytes) {
+        this.bytes = bytes;
+    }
+
+    /**
+     * the output file (required)
+     * @param destFile the destination file.
+     */
+    public void setDestFile(File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * include header information; default false.
+     * @param header a <code>boolean</code> value.
+     */
+    public void setHeader(boolean header) {
+        this.header = header;
+    }
+
+    /**
+     * name a single item to decode; a class or a method
+     * e.g item="Myclass::method" or item="namespace1::namespace2::Myclass:method(void(int32))
+     * @param item the item to decode.
+     */
+    public void setItem(String item) {
+        this.item = item;
+    }
+
+    /**
+     * include line number information; default=false
+     * @param linenumbers a <code>boolean</code> value.
+     */
+    public void setLinenumbers(boolean linenumbers) {
+        this.linenumbers = linenumbers;
+    }
+
+    /**
+     * include metadata information
+     * @param metadata a <code>boolean</code> value.
+     */
+    public void setMetadata(boolean metadata) {
+        this.metadata = metadata;
+    }
+
+    /**
+     * show a graphical progress bar in a window during the process; off by default
+     * @param progressBar a <code>boolean</code> value.
+     */
+    public void setProgressBar(boolean progressBar) {
+        this.progressBar = progressBar;
+    }
+
+    /**
+     * quote all names.
+     * @param quoteallnames a <code>boolean</code> value.
+     */
+    public void setQuoteallnames(boolean quoteallnames) {
+        this.quoteallnames = quoteallnames;
+    }
+
+    /**
+     * enable raw exception handling (default = false)
+     * @param rawExceptionHandling a <code>boolean</code> value.
+     */
+    public void setRawExceptionHandling(boolean rawExceptionHandling) {
+        this.rawExceptionHandling = rawExceptionHandling;
+    }
+
+    /**
+     * include the source as comments (default=false)
+     * @param showSource a <code>boolean</code> value.
+     */
+    public void setShowSource(boolean showSource) {
+        this.showSource = showSource;
+    }
+
+    /**
+     * the file to disassemble -required
+     * @param sourceFile the file to disassemble.
+     */
+    public void setSourceFile(File sourceFile) {
+        this.sourceFile = sourceFile;
+    }
+
+    /**
+     * alternate name for sourceFile
+     * @param sourceFile the source file.
+     */
+    public void setSrcFile(File sourceFile) {
+        setSourceFile(sourceFile);
+    }
+    /**
+     * This method sets the visibility options. It chooses one
+     * or more of the following, with + signs to concatenate them:
+     * <pre>
+     * pub : Public
+     * pri : Private
+     * fam : Family
+     * asm : Assembly
+     * faa : Family and Assembly
+     * foa : Family or Assembly
+     * psc : Private Scope
+     *</pre>
+     * e.g. visibility="pub+pri".
+     * Family means <code>protected</code> in C#;
+     * @param visibility the options to use.
+     */
+    public void setVisibility(String visibility) {
+        this.visibility = visibility;
+    }
+
+    /**
+     *  verify that source and dest are ok
+     */
+    private void validate() {
+        if (sourceFile == null || !sourceFile.exists() || !sourceFile.isFile()) {
+            throw new BuildException("invalid source");
+        }
+        if (destFile == null || destFile.isDirectory()) {
+            throw new BuildException("invalid dest");
+        }
+        if (resourceDir != null
+                && (!resourceDir.exists() || !resourceDir.isDirectory())) {
+            throw new BuildException("invalid resource directory");
+        }
+    }
+
+    /**
+     * Test for disassembly being needed; use existence and granularity
+     * correct date stamps
+     * @return true iff a rebuild is required.
+     */
+    private boolean isDisassemblyNeeded() {
+        if (!destFile.exists()) {
+            log("Destination file does not exist: a build is required",
+                    Project.MSG_VERBOSE);
+            return true;
+        }
+        long sourceTime = sourceFile.lastModified();
+        long destTime = destFile.lastModified();
+        if (sourceTime > (destTime + FILE_UTILS.getFileTimestampGranularity())) {
+            log("Source file is newer than the dest file: a rebuild is required",
+                    Project.MSG_VERBOSE);
+            return true;
+        } else {
+            log("The .il file is up to date", Project.MSG_VERBOSE);
+            return false;
+        }
+
+    }
+    /**
+     * do the work
+     * @throws BuildException if there is an error.
+     */
+    public void execute() throws BuildException {
+        log("This task is deprecated and will be removed in a future version\n"
+            + "of Ant.  It is now part of the .NET Antlib:\n"
+            + "http://ant.apache.org/antlibs/dotnet/index.html",
+            Project.MSG_WARN);
+        validate();
+        if (!isDisassemblyNeeded()) {
+            return;
+        }
+        NetCommand command = new NetCommand(this, "ildasm", executable);
+        command.setFailOnError(true);
+        //fill in args
+        command.addArgument("/text");
+        command.addArgument("/out=" + destFile.toString());
+        if (!progressBar) {
+            command.addArgument("/nobar");
+        }
+        if (linenumbers) {
+            command.addArgument("/linenum");
+        }
+        if (showSource) {
+            command.addArgument("/source");
+        }
+        if (quoteallnames) {
+            command.addArgument("/quoteallnames");
+        }
+        if (header) {
+            command.addArgument("/header");
+        }
+        if (!assembler) {
+            command.addArgument("/noil");
+        }
+        if (metadata) {
+            command.addArgument("/tokens");
+        }
+        command.addArgument("/item:", item);
+        if (rawExceptionHandling) {
+            command.addArgument("/raweh");
+        }
+        command.addArgument(EncodingTypes.getEncodingOption(encoding));
+        if (bytes) {
+            command.addArgument("/bytes");
+        }
+        command.addArgument("/vis:", visibility);
+
+        //add the source file
+        command.addArgument(sourceFile.getAbsolutePath());
+
+        //determine directory: resourceDir if set,
+        //the dir of the destFile if not
+        File execDir = resourceDir;
+        if (execDir == null) {
+            execDir = destFile.getParentFile();
+        }
+        command.setDirectory(execDir);
+
+        //now run
+        try {
+            command.runCommand();
+        } catch (BuildException e) {
+            //forcibly delete the output file in case of trouble
+            if (destFile.exists()) {
+                log("Deleting destination file as it may be corrupt");
+                destFile.delete();
+            }
+            //then rethrow the exception
+            throw e;
+        }
+
+    }
+
+    /**
+     * encoding options; the default is ascii
+     */
+    public static class EncodingTypes extends EnumeratedAttribute {
+        /** Unicode */
+        public static final String UNICODE = "unicode";
+        /** UTF8 */
+        public static final String UTF8 = "utf8";
+        /** ASCII */
+        public static final String ASCII = "ascii";
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{
+                ASCII,
+                UTF8,
+                UNICODE,
+            };
+        }
+
+        /**
+         * This method maps from an encoding enum to an encoding option.
+         * @param enumValue the value to use.
+         * @return The encoding option indicated by the enum value.
+         */
+        public static String getEncodingOption(String enumValue) {
+            if (UNICODE.equals(enumValue)) {
+                return "/unicode";
+            }
+            if (UTF8.equals(enumValue)) {
+                return "/utf8";
+            }
+            return null;
+        }
+    }
+
+    /**
+     * visibility options for decoding
+     */
+    public static class VisibilityOptions extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{
+                "pub", //Public
+                "pri", //Private
+                "fam", //Family
+                "asm", //Assembly
+                "faa", //Family and Assembly
+                "foa", //Family or Assembly
+                "psc", //Private Scope
+            };
+        }
+
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/ImportTypelib.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/ImportTypelib.java
new file mode 100644
index 0000000..f9e46c7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/ImportTypelib.java
@@ -0,0 +1,217 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+
+/**
+ * Import a COM type library into the .NET framework.
+ * <p>
+ *
+ * This task is a wrapper to .NET's tlbimport; it imports a tlb file to a NET assembly
+ * by generating a binary assembly (.dll) that contains all the binding
+ * metadata. It uses date timestamps to minimise rebuilds.
+ * <p>
+ * Example
+ * <pre>
+ *     &lt;importtypelib
+ *       srcfile="xerces.tlb"
+ *       destfile="xerces.dll"
+ *       namespace="Apache.Xerces"/&gt;
+ * </pre>
+ * @since Ant 1.6
+ * @ant.task category="dotnet"
+ */
+public class ImportTypelib extends Task {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * input file; precedes options
+     */
+    private File srcFile;
+
+    /**
+     * /out:file
+     */
+    private File destFile;
+
+    /**
+     *  /namespace:[string]
+     */
+    private String namespace;
+
+    /**
+     * /sysarray
+     */
+    private boolean useSysArray = false;
+
+    /**
+     * /unsafe
+     */
+    private boolean unsafe = false;
+
+    /**
+     * extra commands?
+     */
+    private String extraOptions = null;
+
+    /**
+     * This method names the output file.
+     *
+     * This is an operation which is required to have been performed.
+     * @param destFile the output file.
+     */
+    public void setDestFile(File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * This method sets what namespace the typelib is to be in.
+     * This is an operation which is required to have been performed.
+     * @param namespace the namespace to use.
+     */
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    /**
+     * This method sets which is the source .tlb file.
+     * This is an operation which is required to have been performed.
+     * @param srcFile the source file.
+     */
+    public void setSrcFile(File srcFile) {
+        this.srcFile = srcFile;
+    }
+
+    /**
+     * do you want unsafe code.
+     * @param unsafe a <code>boolean</code> value.
+     */
+    public void setUnsafe(boolean unsafe) {
+        this.unsafe = unsafe;
+    }
+
+    /**
+     * set this to map a COM SafeArray to the System.Array class
+     * @param useSysArray a <code>boolean</code> value.
+     */
+    public void setUseSysArray(boolean useSysArray) {
+        this.useSysArray = useSysArray;
+    }
+
+    /**
+     * set any extra options that are not yet supported by this task.
+     * @param extraOptions the options to use.
+     */
+    public void setExtraOptions(String extraOptions) {
+        this.extraOptions = extraOptions;
+    }
+
+    /**
+     * validation code
+     * @throws  BuildException  if validation failed
+     */
+    protected void validate()
+            throws BuildException {
+        if (destFile == null) {
+            throw new BuildException("destination file must be specified");
+        }
+        if (destFile.isDirectory()) {
+            throw new BuildException(
+                    "destination file is a directory");
+        }
+        if (srcFile == null || !srcFile.exists()) {
+            throw new BuildException(
+                    "source file does not exist");
+        }
+        if (srcFile.isDirectory()) {
+            throw new BuildException(
+                    "source file is a directory");
+        }
+        if (namespace == null) {
+            throw new BuildException("No namespace");
+        }
+    }
+
+    /**
+     * Test for disassembly being needed; use existence and granularity
+     * correct date stamps
+     * @return true iff a rebuild is required.
+     */
+    private boolean isExecuteNeeded() {
+        if (!destFile.exists()) {
+            log("Destination file does not exist: a build is required",
+                    Project.MSG_VERBOSE);
+            return true;
+        }
+        long sourceTime = srcFile.lastModified();
+        long destTime = destFile.lastModified();
+        if (sourceTime > (destTime + FILE_UTILS.getFileTimestampGranularity())) {
+            log("Source file is newer than the dest file: a rebuild is required",
+                    Project.MSG_VERBOSE);
+            return true;
+        } else {
+            log("The output file is up to date", Project.MSG_VERBOSE);
+            return false;
+        }
+
+    }
+
+
+    /**
+     * Create a typelib command
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        log("This task is deprecated and will be removed in a future version\n"
+            + "of Ant.  It is now part of the .NET Antlib:\n"
+            + "http://ant.apache.org/antlibs/dotnet/index.html",
+            Project.MSG_WARN);
+        validate();
+        log("Importing typelib " + srcFile
+            + " to assembly " + destFile
+            + " in namespace " + namespace, Project.MSG_VERBOSE);
+        //rebuild unless the dest file is newer than the source file
+        if (!isExecuteNeeded()) {
+            return;
+        }
+
+        NetCommand command = new NetCommand(this, "ImportTypelib", "tlbimp");
+        command.setFailOnError(true);
+        command.addArgument(srcFile.toString());
+        //fill in args
+        command.addArgument("/nologo");
+        command.addArgument("/out:" + destFile);
+        command.addArgument("/namespace:", namespace);
+        if (useSysArray) {
+            command.addArgument("/sysarray");
+        }
+        if (unsafe) {
+            command.addArgument("/unsafe");
+        }
+        command.addArgument(extraOptions);
+        command.runCommand();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/JSharp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/JSharp.java
new file mode 100644
index 0000000..6053a61
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/JSharp.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Compile J# source down to a managed .NET application.
+ * <p>
+ * J# is not Java. But it is the language closest to Java in the .NET framework.
+ * This task compiles jsharp source (.java files), and
+ * generates a .NET managed exe or dll.
+ * <p>
+ *
+ * <p>For historical reasons the pattern
+ * <code>**</code><code>/*.java</code> is preset as includes list and
+ * you can not override it with an explicit includes attribute.  Use
+ * nested <code>&lt;src&gt;</code> elements instead of the basedir
+ * attribute if you need more control.</p>
+ *
+ * @see <a ref=
+ * "http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vjsharp/html/vjoriMicrosoftVisualJ.asp"
+ * >Visual J++ online documentation</a>
+ *
+ * @since ant1.6
+ * @ant.task category="dotnet" name="jsharpc"
+ */
+public class JSharp extends DotnetCompile {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * hex base address
+     */
+    String baseAddress;
+
+    /** /x option to disable J++ and J# lang extensions
+     *
+     */
+    boolean pureJava = true;
+
+    /**
+     * whether to make package scoped stuff public or assembly scoped
+     */
+    boolean secureScoping = false;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /** No arg constructor. */
+    public JSharp() {
+        setExecutable("vjc");
+    }
+
+
+    /**
+     * Set the base address attribute.
+     * @param baseAddress the value to use.
+     */
+    public void setBaseAddress(String baseAddress) {
+        this.baseAddress = baseAddress;
+    }
+
+    /**
+     * do we want pure java (default, true) or corrupted J#?
+     * @param pureJava a <code>boolean</code> value.
+     */
+    public void setPureJava(boolean pureJava) {
+        this.pureJava = pureJava;
+    }
+
+    /**
+     * Make package scoped code visible to the current assembly only (default: false)
+     * .NET does not have package scoping. Instead it has assembly, private and public.
+     * By default, package content is public to all.
+     * @param secureScoping a <code>boolean</code> value.
+     */
+    public void setSecureScoping(boolean secureScoping) {
+        this.secureScoping = secureScoping;
+    }
+
+    /**
+     * Get the delimiter that the compiler uses between references.
+     * For example, c# will return ";"; VB.NET will return ","
+     * @return The string delimiter for the reference string.
+     */
+    public String getReferenceDelimiter() {
+        return ";";
+    }
+
+    /**
+     * Get the extension of filenames to compile.
+     * @return The string extension of files to compile.
+     */
+    public String getFileExtension() {
+        return ".java";
+    }
+
+    /**
+     * add jvc specific commands
+     * @param command the command to add to.
+     */
+    protected void addCompilerSpecificOptions(NetCommand command) {
+        if (pureJava) {
+            command.addArgument("/x:all");
+        }
+        if (secureScoping) {
+            command.addArgument("/securescoping");
+        }
+    }
+
+    /** {@inheritDoc} */
+    protected void createResourceParameter(NetCommand command, DotnetResource resource) {
+        resource.getParameters(getProject(), command, true);
+    }
+
+    /**
+     * validation code
+     * @throws  org.apache.tools.ant.BuildException  if validation failed
+     */
+    protected void validate()
+            throws BuildException {
+        super.validate();
+        if (getDestFile() == null) {
+            throw new BuildException("DestFile was not specified");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NetCommand.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NetCommand.java
new file mode 100644
index 0000000..6ff45e3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/NetCommand.java
@@ -0,0 +1,404 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ *  build notes
+ *  The reference CD to listen to while editing this file is
+ *  Underworld Everything, Everything
+ *  variable naming policy from Fowler's refactoring book.
+ */
+// place below the optional ant tasks package
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+// imports
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.io.BufferedOutputStream;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *  This is a helper class to spawn net commands out. In its initial form it
+ *  contains no .net specifics, just contains all the command line/exe
+ *  construction stuff. However, it may be handy in future to have a means of
+ *  setting the path to point to the dotnet bin directory; in which case the
+ *  shared code should go in here.
+ *
+ *@version    0.5
+ */
+
+public class NetCommand {
+    private static final int DEFAULT_RESPONSE_THRESHOLD = 64;
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     *  owner project
+     */
+    protected Task owner;
+
+    /**
+     *  executable
+     */
+    protected Execute executable;
+
+    /**
+     *  what is the command line
+     */
+    protected Commandline commandLine;
+
+    /**
+     *  title of the command
+     */
+    protected String title;
+
+    /**
+     *  actual program to invoke
+     */
+    protected String program;
+
+    /**
+     *  trace flag
+     */
+    protected boolean traceCommandLine = false;
+
+    /**
+     *  flag to control action on execution trouble
+     */
+    protected boolean failOnError;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * the directory to execute the command in. When null, the current
+     * directory is used.
+     */
+    private File directory;
+
+    /**
+     * flag to set to to use @file based command cache
+     */
+    private boolean useResponseFile = false;
+
+    /**
+     * name of a temp file; may be null
+     */
+    private File temporaryCommandFile;
+
+    /**
+     * internal threshold for auto-switch
+     */
+    private int automaticResponseFileThreshold = DEFAULT_RESPONSE_THRESHOLD;
+
+    /**
+     *  constructor
+     *
+     *@param  title        (for logging/errors)
+     *@param  owner        owner task
+     *@param  program      app we are to run
+     */
+
+    public NetCommand(Task owner, String title, String program) {
+        this.owner = owner;
+        this.title = title;
+        this.program = program;
+        commandLine = new Commandline();
+        commandLine.setExecutable(program);
+    }
+
+
+    /**
+     *  turn tracing on or off
+     *
+     *@param  b  trace flag
+     */
+    public void setTraceCommandLine(boolean b) {
+        traceCommandLine = b;
+    }
+
+
+    /**
+     *  set fail on error flag
+     *
+     *@param  b  fail flag -set to true to cause an exception to be raised if
+     *      the return value != 0
+     */
+    public void setFailOnError(boolean b) {
+        failOnError = b;
+    }
+
+
+    /**
+     *  query fail on error flag
+     *
+     *@return    The failFailOnError value
+     */
+    public boolean getFailFailOnError() {
+        return failOnError;
+    }
+
+
+    /**
+     * set the directory to run from, if the default is inadequate
+     * @param directory the directory to use.
+     */
+    public void setDirectory(File directory) {
+        this.directory = directory;
+    }
+
+    /**
+     *  verbose text log
+     *
+     *@param  msg  string to add to log if verbose is defined for the build
+     */
+    protected void logVerbose(String msg) {
+        owner.getProject().log(msg, Project.MSG_VERBOSE);
+    }
+
+
+    /**
+     *  error text log
+     *
+     *@param  msg  message to display as an error
+     */
+    protected void logError(String msg) {
+        owner.getProject().log(msg, Project.MSG_ERR);
+    }
+
+
+    /**
+     *  add an argument to a command line; do nothing if the arg is null or
+     *  empty string
+     *
+     *@param  argument  The feature to be added to the Argument attribute
+     */
+    public void addArgument(String argument) {
+        if (argument != null && argument.length() != 0) {
+            commandLine.createArgument().setValue(argument);
+        }
+    }
+
+    /**
+     *  add an argument to a command line; do nothing if the arg is null or
+     *  empty string
+     *
+     *@param  arguments  The features to be added to the Argument attribute
+     */
+    public void addArguments(String[] arguments) {
+        if (arguments != null && arguments.length != 0) {
+            for (int i = 0; i < arguments.length; i++) {
+                addArgument(arguments[i]);
+            }
+        }
+    }
+
+    /**
+     *  concatenate two strings together and add them as a single argument,
+     *  but only if argument2 is non-null and non-zero length
+     *
+     *@param  argument1  The first argument
+     *@param  argument2  The second argument
+     */
+    public void addArgument(String argument1, String argument2) {
+        if (argument2 != null && argument2.length() != 0) {
+            commandLine.createArgument().setValue(argument1 + argument2);
+        }
+    }
+
+    /**
+     * getter
+     * @return response file state
+     */
+    public boolean isUseResponseFile() {
+        return useResponseFile;
+    }
+
+    /**
+     * set this to true to always use the response file
+     * @param useResponseFile a <code>boolean</code> value.
+     */
+    public void setUseResponseFile(boolean useResponseFile) {
+        this.useResponseFile = useResponseFile;
+    }
+
+    /**
+     * getter for threshold
+     * @return 0 for disabled, or a threshold for enabling response files
+     */
+    public int getAutomaticResponseFileThreshold() {
+        return automaticResponseFileThreshold;
+    }
+
+    /**
+     * set threshold for automatically using response files -use 0 for off
+     * @param automaticResponseFileThreshold the threshold value to use.
+     */
+    public void setAutomaticResponseFileThreshold(int automaticResponseFileThreshold) {
+        this.automaticResponseFileThreshold = automaticResponseFileThreshold;
+    }
+
+    /**
+     *  set up the command sequence..
+     */
+    protected void prepareExecutor() {
+        // default directory to the project's base directory
+        if (owner == null) {
+            throw new RuntimeException("no owner");
+        }
+        if (owner.getProject() == null) {
+            throw new RuntimeException("Owner has no project");
+        }
+        File dir = owner.getProject().getBaseDir();
+        if (directory != null) {
+            dir = directory;
+        }
+
+        ExecuteStreamHandler handler = new LogStreamHandler(owner,
+                Project.MSG_INFO, Project.MSG_WARN);
+        executable = new Execute(handler, null);
+        executable.setAntRun(owner.getProject());
+        executable.setWorkingDirectory(dir);
+    }
+
+
+    /**
+     *  Run the command using the given Execute instance.
+     *
+     *@exception  BuildException  if something goes wrong and the
+     *      failOnError flag is true
+     */
+    public void runCommand()
+             throws BuildException {
+        prepareExecutor();
+        int err = -1;
+        // assume the worst
+        try {
+            if (traceCommandLine) {
+                owner.log("In directory " + executable.getWorkingDirectory());
+                owner.log(commandLine.describeCommand());
+            } else {
+                //in verbose mode we always log stuff
+                logVerbose("In directory " + executable.getWorkingDirectory());
+                logVerbose(commandLine.describeCommand());
+            }
+            setExecutableCommandLine();
+            err = executable.execute();
+            if (Execute.isFailure(err)) {
+                if (failOnError) {
+                    throw new BuildException(title + " returned: " + err, owner.getLocation());
+                } else {
+                    owner.log(title + "  Result: " + err, Project.MSG_ERR);
+                }
+            }
+        } catch (IOException e) {
+            throw new BuildException(title + " failed: " + e, e, owner.getLocation());
+        } finally {
+            if (temporaryCommandFile != null) {
+                temporaryCommandFile.delete();
+            }
+        }
+    }
+
+    /**
+     * set the executable command line
+     */
+    private void setExecutableCommandLine() {
+
+        String[] commands = commandLine.getCommandline();
+        //always trigger file mode if commands are big enough
+        if (automaticResponseFileThreshold > 0
+            && commands.length > automaticResponseFileThreshold) {
+            useResponseFile = true;
+        }
+        if (!useResponseFile || commands.length <= 1) {
+            //the simple action is to send the command line in as is
+            executable.setCommandline(commands);
+        } else {
+            //but for big operations, we save all the params to a temp file
+            //and set @tmpfile as the command -then we remember to delete the tempfile
+            //afterwards
+            FileOutputStream fos = null;
+
+            temporaryCommandFile = FILE_UTILS.createTempFile("cmd", ".txt", null, false, true);
+            owner.log("Using response file " + temporaryCommandFile, Project.MSG_VERBOSE);
+
+            try {
+                fos = new FileOutputStream(temporaryCommandFile);
+                PrintWriter out = new PrintWriter(new BufferedOutputStream(fos));
+                //start at 1 because element 0 is the executable name
+                for (int i = 1; i < commands.length; ++i) {
+                    out.println(commands[i]);
+                }
+                out.flush();
+                out.close();
+            } catch (IOException ex) {
+                throw new BuildException("saving command stream to " + temporaryCommandFile, ex);
+            }
+
+            String[] newCommandLine = new String[2];
+            newCommandLine[0] = commands[0];
+            newCommandLine[1] = "@" + temporaryCommandFile.getAbsolutePath();
+            logVerbose(Commandline.describeCommand(newCommandLine));
+            executable.setCommandline(newCommandLine);
+        }
+    }
+
+
+    /**
+     * scan through one fileset for files to include
+     * @param scanner the directory scanner to use.
+     * @param filesToBuild the map to place the files.
+     * @param outputTimestamp timestamp to compare against
+     * @return #of files out of date
+     * @todo should FAT granularity be included here?
+     */
+    public int scanOneFileset(DirectoryScanner scanner, Hashtable filesToBuild,
+                                        long outputTimestamp) {
+        int filesOutOfDate = 0;
+        String[] dependencies = scanner.getIncludedFiles();
+        File base = scanner.getBasedir();
+        //add to the list
+        for (int i = 0; i < dependencies.length; i++) {
+            File targetFile = new File(base, dependencies[i]);
+            if (filesToBuild.get(targetFile) == null) {
+                filesToBuild.put(targetFile, targetFile);
+                if (targetFile.lastModified() > outputTimestamp) {
+                    filesOutOfDate++;
+                    owner.log(targetFile.toString() + " is out of date",
+                              Project.MSG_VERBOSE);
+                } else {
+                    owner.log(targetFile.toString(),
+                              Project.MSG_VERBOSE);
+                }
+            }
+        }
+        return filesOutOfDate;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/VisualBasicCompile.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/VisualBasicCompile.java
new file mode 100644
index 0000000..fe22e37
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/VisualBasicCompile.java
@@ -0,0 +1,366 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * This task compiles Visual Basic.NET source into executables or modules.
+ * The task requires vbc.exe on the execute path, unless it or an equivalent
+ * program is specified in the <tt>executable</tt> parameter
+ *
+ * <p>
+ * All parameters are optional: &lt;vbc/&gt; should suffice to produce a debug
+ * build of all *.vb files.
+ *
+ * <p>
+
+ * The task is a directory based task, so attributes like
+ * <tt>includes=&quot;**\/*.vb&quot;</tt> and
+ * <tt>excludes=&quot;broken.vb&quot;</tt> can be used to control
+ * the files pulled in. By default,
+ * all *.vb files from the project folder down are included in the command.
+ * When this happens the destFile -if not specified-
+ * is taken as the first file in the list, which may be somewhat hard to control.
+   Specifying the output file with <tt>destfile</tt> is prudent.
+ </p>
+ <p>
+ * Also, dependency checking only works if destfile is set.
+ *
+ * <p>For historical reasons the pattern
+ * <code>**</code><code>/*.vb</code> is preset as includes list and
+ * you can not override it with an explicit includes attribute.  Use
+ * nested <code>&lt;src&gt;</code> elements instead of the basedir
+ * attribute if you need more control.</p>
+ *
+ * As with &lt;csc&gt; nested <tt>src</tt> filesets of source,
+ * reference filesets, definitions and resources can be provided.
+ *
+ * <p>
+ * Example
+ * </p>
+ * <pre>&lt;vbc
+ *   optimize=&quot;true&quot;
+ *   debug=&quot;false&quot;
+ *   warnLevel=&quot;4&quot;
+ *   targetType=&quot;exe&quot;
+ *   definitions=&quot;RELEASE&quot;
+ *   excludes=&quot;src/unicode_class.vb&quot;
+ *   mainClass = &quot;MainApp&quot;
+ *   destFile=&quot;NetApp.exe&quot;
+ *   optionExplicit=&quot;true&quot;
+ *   optionCompare=&quot;text&quot;
+ *   references="System.Xml,System.Web.Xml"
+ *   &gt;
+ *          &lt;reference file="${testCSC.dll}" /&gt;
+ *          &lt;define name="RELEASE" /&gt;
+ *          &lt;define name="DEBUG" if="debug.property"/&gt;
+ *          &lt;define name="def3" unless="def2.property"/&gt;
+ *   &lt;/vbc&gt;
+ </pre>
+ * @ant.task    name="vbc" category="dotnet"
+ */
+
+public class VisualBasicCompile extends DotnetCompile {
+
+    /**
+     * Compiler option to remove integer checks. Default: false.
+     */
+    private boolean removeIntChecks = false;
+
+    /**
+     * Require explicit declaration of variables? Default: false.
+     */
+    private boolean optionExplicit = false;
+
+    /**
+     * Enforce strict language semantics? Default: false.
+     */
+    private boolean optionStrict = false;
+
+    /**
+     * Whether to compare strings as "text" or "binary". Default: "binary".
+     */
+    private String optionCompare;
+
+    /**
+     * Root namespace for all type declarations.
+     */
+    private String rootNamespace;
+
+    /**
+     * Declare global imports fornamespaces in referenced metadata files.
+     */
+    private String imports;
+
+    /**
+     * Constructor for VisualBasicCompile.
+     */
+    public VisualBasicCompile() {
+        clear();
+    }
+
+    /**
+     *  reset all contents.
+     */
+    public void clear() {
+        super.clear();
+        imports = null;
+        rootNamespace = null;
+        optionCompare = null;
+        optionExplicit = false;
+        optionStrict = false;
+        removeIntChecks = false;
+        setExecutable("vbc");
+    }
+
+    /**
+     *  get the argument or null for no argument needed
+     *  This is overridden from DotnetCompile.java because VBC uses
+     *  "/win32resource:" rather than "/win32res:"
+     *
+     *@return    The Win32Res Parameter to CSC
+     */
+    protected String getWin32ResParameter() {
+        if (getWin32Res() != null) {
+            return "/win32resource:" + getWin32Res().toString();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Whether to remove integer checks. Default false.
+     * @param  flag  on/off flag
+     */
+    public void setRemoveIntChecks(boolean flag) {
+        removeIntChecks = flag;
+    }
+
+    /**
+     * Get the flag for removing integer checks.
+     * @return    true if flag is turned on
+     */
+    public boolean getRemoveIntChecks() {
+        return removeIntChecks;
+    }
+
+    /**
+     * Form the option string for removeIntChecks.
+     * @return The parameter string.
+     */
+    public String getRemoveIntChecksParameter() {
+        return "/removeintchecks" + (removeIntChecks ? "+" : "-");
+    }
+
+    /**
+     * Whether to require explicit declaration of variables.
+     * @param  flag  on/off flag
+     */
+    public void setOptionExplicit(boolean flag) {
+        optionExplicit = flag;
+    }
+
+    /**
+     * Get the flag for whether to require explicit declaration of variables.
+     *@return    true if flag is turned on
+     */
+    public boolean getOptionExplicit() {
+        return optionExplicit;
+    }
+
+    /**
+     * Form the option string for optionExplicit..
+     * @return The parameter string.
+     */
+    public String getOptionExplicitParameter() {
+        return "/optionexplicit" + (optionExplicit ? "+" : "-");
+    }
+
+    /**
+     * Enforce strict language semantics.
+     * @param  flag  on/off flag
+     */
+    public void setOptionStrict(boolean flag) {
+        optionStrict = flag;
+    }
+
+    /**
+     * Get the flag for whether to enforce strict language semantics.
+     * @return    true if flag is turned on
+     */
+    public boolean getOptionStrict() {
+        return optionStrict;
+    }
+
+    /**
+     * For the option string for optionStrict.
+     * @return The parameter string.
+     */
+    public String getOptionStrictParameter() {
+        return "/optionstrict" + (optionStrict ? "+" : "-");
+    }
+
+
+    /**
+     * Specifies the root namespace for all type declarations.
+     * @param rootNamespace a root namespace.
+     */
+    public void setRootNamespace(String rootNamespace) {
+        this.rootNamespace = rootNamespace;
+    }
+
+
+    /**
+     * Get the root namespace.
+     * @return  the root namespace.
+     */
+    public String getRootNamespace() {
+        return this.rootNamespace;
+    }
+
+
+    /**
+     * Form the option string for rootNamespace.
+     * @return  the root namespace option string.
+     */
+    protected String getRootNamespaceParameter() {
+        if (rootNamespace != null && rootNamespace.length() != 0) {
+            return "/rootnamespace:" + rootNamespace;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Declare global imports for namespaces in referenced metadata files.
+     * @param imports the imports string
+     */
+    public void setImports(String imports) {
+        this.imports = imports;
+    }
+
+
+    /**
+     * Get global imports for namespaces in referenced metadata files.
+     * @return  the imports string.
+     */
+    public String getImports() {
+        return this.imports;
+    }
+
+
+    /**
+     * Format the option for imports.
+     * @return  the formatted import option.
+     */
+    protected String getImportsParameter() {
+        if (imports != null && imports.length() != 0) {
+            return "/imports:" + imports;
+        } else {
+            return null;
+        }
+    }
+
+
+    /**
+     * Specify binary- or text-style string comparisons. Defaults
+     * to "binary"
+     * @param optionCompare the option compare style. "text" | "binary".
+     */
+    public void setOptionCompare(String optionCompare) {
+        if ("text".equalsIgnoreCase(optionCompare)) {
+            this.optionCompare = "text";
+        } else {
+            this.optionCompare = "binary";
+        }
+    }
+
+
+    /**
+     * "binary" or "text" for the string-comparison style.
+     * @return  the option compare style.
+     */
+    public String getOptionCompare() {
+        return this.optionCompare;
+    }
+
+    /**
+     * Format the option for string comparison style.
+     * @return  The formatted option.
+     */
+    protected String getOptionCompareParameter() {
+        if (optionCompare != null && "text".equalsIgnoreCase(optionCompare)) {
+            return "/optioncompare:text";
+        } else {
+            return "/optioncompare:binary";
+        }
+    }
+
+    /**
+     * implement VBC commands
+     * @param command the command to set arguements on.
+     */
+    protected void addCompilerSpecificOptions(NetCommand command) {
+        command.addArgument(getRemoveIntChecksParameter());
+        command.addArgument(getImportsParameter());
+        command.addArgument(getOptionExplicitParameter());
+        command.addArgument(getOptionStrictParameter());
+        command.addArgument(getRootNamespaceParameter());
+        command.addArgument(getOptionCompareParameter());
+    }
+
+    /**
+     * Get the delimiter that the compiler uses between references.
+     * For example, c# will return ";"; VB.NET will return ","
+     * @return The string delimiter for the reference string.
+     */
+    public String getReferenceDelimiter() {
+        return ",";
+    }
+
+
+
+    /**
+     * Get the extension of filenames to compile.
+     * @return The string extension of files to compile.
+     */
+    public String getFileExtension() {
+        return "vb";
+    }
+
+    /** {@inheritDoc} */
+    protected void createResourceParameter(NetCommand command, DotnetResource resource) {
+        resource.getParameters(getProject(), command, false);
+    }
+
+    /**
+     * validation code
+     * @throws  BuildException  if validation failed
+     */
+    protected void validate()
+            throws BuildException {
+        super.validate();
+        if (getDestFile() == null) {
+            throw new BuildException("DestFile was not specified");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WsdlToDotnet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WsdlToDotnet.java
new file mode 100644
index 0000000..fefe5e8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/dotnet/WsdlToDotnet.java
@@ -0,0 +1,595 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.dotnet;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Iterator;
+import java.net.MalformedURLException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Converts a WSDL file or URL resource into a .NET language.
+ *
+ * Why add a wrapper to the MS WSDL tool?
+ * So that you can verify that your web services, be they written with Axis or
+ *anyone else's SOAP toolkit, work with .NET clients.
+ *
+ *This task is dependency aware when using a file as a source and destination;
+ *so if you &lt;get&gt; the file (with <code>usetimestamp="true"</code>) then
+ *you only rebuild stuff when the WSDL file is changed. Of course,
+ *if the server generates a new timestamp every time you ask for the WSDL,
+ *this is not enough...use the &lt;filesmatch&gt; &lt;condition&gt; to
+ *to byte for byte comparison against a cached WSDL file then make
+ *the target conditional on that test failing.
+
+ * See "Creating an XML Web Service Proxy", "wsdl.exe" docs in
+ * the framework SDK documentation
+ * @version     0.5
+ * @ant.task    category="dotnet"
+ * @since       Ant 1.5
+ */
+
+public class WsdlToDotnet extends Task  {
+
+    /**
+     * used for timestamp checking
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * name of output file (required)
+     */
+    private File destFile = null;
+
+    /**
+     * language; defaults to C#
+     */
+    private String language = "CS";
+
+    /**
+     * flag set to true to generate server side skeleton
+     */
+    private boolean server = false;
+
+    /**
+     * namespace
+     */
+    private String namespace = null;
+
+    /**
+     *  flag to control action on execution trouble
+     */
+    private boolean failOnError = true;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     *  any extra command options?
+     */
+    protected String extraOptions = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     * protocol string. Exact value set depends on SOAP stack version.
+     * @since Ant 1.7
+     */
+    private String protocol = null;
+
+    /**
+     * should errors come in an IDE format. This
+     * is WSE only.
+     * @since Ant 1.7
+     */
+    private boolean ideErrors = false;
+
+    /**
+     * filesets of file to compile
+     * @since Ant 1.7
+     */
+    private Vector schemas = new Vector();
+
+    /**
+     * our WSDL file.
+     * @since ant1.7
+     */
+    private Schema wsdl = new Schema();
+
+    /**
+     * compiler
+     * @since ant1.7
+     */
+    private Compiler compiler = null;
+
+    /**
+     * error message: dest file is a directory
+     */
+    public static final String ERROR_DEST_FILE_IS_DIR = "destination file is a directory";
+
+    /**
+     * error message: no dest file
+     */
+    public static final String ERROR_NO_DEST_FILE = "destination file must be specified";
+
+    /**
+     * Name of the file to generate. Required
+     * @param destFile filename
+     */
+    public void setDestFile(File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * Sets the URL to fetch. Fetching is by wsdl.exe; Ant proxy settings
+     * are ignored; either url or srcFile is required.
+     * @param url url to save
+     */
+
+    public void setUrl(String url) {
+        wsdl.setUrl(url);
+    }
+
+    /**
+     * The local WSDL file to parse; either url or srcFile is required.
+     * @param srcFile WSDL file
+     */
+    public void setSrcFile(File srcFile) {
+        wsdl.setFile(srcFile);
+    }
+
+    /**
+     * set the language; one of "CS", "JS", or "VB"
+     * optional, default is CS for C# source
+     * @param language language to generate
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    /**
+     * flag to enable server side code generation;
+     * optional, default=false
+     * @param server server-side flag
+     */
+
+    public void setServer(boolean server) {
+        this.server = server;
+    }
+
+    /**
+     * namespace to place  the source in.
+     * optional; default ""
+     * @param namespace new namespace
+     */
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    /**
+     * Whether or not a failure should halt the build.
+     * Optional - default is <code>true</code>.
+     * @param failOnError new failure option
+     */
+    public void setFailOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     *  Any extra WSDL.EXE options which aren't explicitly
+     *  supported by the ant wrapper task; optional
+     *
+     *@param  extraOptions  The new ExtraOptions value
+     */
+    public void setExtraOptions(String extraOptions) {
+        this.extraOptions = extraOptions;
+    }
+
+    /**
+     * Defines wether errors are machine parseable.
+     * Optional, default=true
+     *
+     * @since Ant 1.7
+     * @param ideErrors a <code>boolean</code> value.
+     */
+    public void setIdeErrors(boolean ideErrors) {
+        this.ideErrors = ideErrors;
+    }
+
+    /**
+     * what protocol to use. SOAP, SOAP1.2, HttpPost and HttpGet
+     * are the base options. Different version and implementations may.
+     * offer different options.
+     * @since Ant 1.7
+     *
+     * @param protocol the protocol to use.
+     */
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    /**
+     * add a new source schema to the compilation
+     * @since Ant 1.7
+     *
+     * @param source a nested schema element.
+     */
+    public void addSchema(Schema source) {
+        schemas.add(source);
+    }
+
+    /**
+     * flag to trigger turning a filename into a file:url
+     * ignored for the mono compiler.
+     * @param b a <code>boolean</code> value.
+     */
+    public void setMakeURL(boolean b) {
+        wsdl.setMakeURL(b);
+    }
+
+    /**
+     * identify the compiler
+     * @since Ant 1.7
+     * @param compiler the enumerated value.
+     */
+    public void setCompiler(Compiler compiler) {
+        this.compiler = compiler;
+    }
+
+    /**
+     * validation code
+     * @throws  BuildException  if validation failed
+     */
+    protected void validate()
+            throws BuildException {
+        if (destFile == null) {
+            throw new BuildException(ERROR_NO_DEST_FILE);
+        }
+        if (destFile.isDirectory()) {
+            throw new BuildException(
+                    ERROR_DEST_FILE_IS_DIR);
+        }
+        wsdl.validate();
+    }
+
+    /**
+     *  do the work by building the command line and then calling it
+     *
+     *@throws  BuildException  if validation or execution failed
+     */
+    public void execute()
+             throws BuildException {
+        log("This task is deprecated and will be removed in a future version\n"
+            + "of Ant.  It is now part of the .NET Antlib:\n"
+            + "http://ant.apache.org/antlibs/dotnet/index.html",
+            Project.MSG_WARN);
+
+        if (compiler == null) {
+            compiler = Compiler.createDefaultCompiler();
+        }
+        validate();
+        NetCommand command = new NetCommand(this,
+                "WSDL",
+                compiler.getCommand());
+        command.setFailOnError(failOnError);
+        //fill in args
+        compiler.applyExtraArgs(command);
+        command.addArgument("/nologo");
+        command.addArgument("/out:" + destFile);
+        command.addArgument("/language:", language);
+        if (server) {
+            command.addArgument("/server");
+        }
+        command.addArgument("/namespace:", namespace);
+        if (protocol != null) {
+            command.addArgument("/protocol:" + protocol);
+        }
+        if (ideErrors) {
+            command.addArgument("/parsableErrors");
+        }
+        command.addArgument(extraOptions);
+
+        //set source and rebuild options
+        boolean rebuild = true;
+        long destLastModified = -1;
+
+        //rebuild unless the dest file is newer than the source file
+        if (destFile.exists()) {
+            destLastModified = destFile.lastModified();
+            rebuild = isRebuildNeeded(wsdl, destLastModified);
+        }
+        String path;
+        //mark for a rebuild if the dest file is newer
+        path = wsdl.evaluate();
+        if (!compiler.supportsAbsoluteFiles() && wsdl.getFile() != null) {
+            // Mono 1.0's wsdl doesn't deal with absolute paths
+            File f = wsdl.getFile();
+            command.setDirectory(f.getParentFile());
+            path = f.getName();
+        }
+        command.addArgument(path);
+        //add in any extra files.
+        //this is an error in mono, but we do not warn on it as they may fix that outside
+        //the ant build cycle.
+        Iterator it = schemas.iterator();
+        while (it.hasNext()) {
+            Schema schema = (Schema) it.next();
+            //mark for a rebuild if we are newer
+            rebuild |= isRebuildNeeded(schema, destLastModified);
+            command.addArgument(schema.evaluate());
+        }
+        //conditionally compile
+        if (rebuild) {
+            command.runCommand();
+        }
+    }
+
+    /**
+     * checks for a schema being out of data
+     * @param schema url/file
+     * @param destLastModified timestamp, -1 for no dest
+     * @return true if a rebuild is needed.
+     */
+    private boolean isRebuildNeeded(Schema schema, long destLastModified) {
+        if (destLastModified == -1) {
+            return true;
+        }
+        return !FILE_UTILS.isUpToDate(schema.getTimestamp(), destLastModified);
+    }
+
+
+    /**
+     * nested schema class
+     * Only supported on NET until mono add multi-URL handling on the command line
+     */
+    public static class Schema {
+        private File file;
+        private String url;
+        private boolean makeURL = false;
+
+        // Errors
+        /** One of file or url must be set */
+        public static final String ERROR_NONE_DECLARED = "One of file and url must be set";
+        /** Only one of file or url */
+        public static final String ERROR_BOTH_DECLARED = "Only one of file or url can be set";
+        /** Not found */
+        public static final String ERROR_FILE_NOT_FOUND = "Not found: ";
+        /** File is a directory */
+        public static final String ERROR_FILE_IS_DIR = "File is a directory: ";
+        /** Could not URL convert */
+        public static final String ERROR_NO_URL_CONVERT = "Could not URL convert ";
+
+        /**
+         * validate the schema
+         */
+        public  void validate() {
+
+            if (file != null) {
+                if (!file.exists()) {
+                    throw new BuildException(ERROR_FILE_NOT_FOUND + file.toString());
+                }
+                if (file.isDirectory()) {
+                    throw new BuildException(ERROR_FILE_IS_DIR + file.toString());
+                }
+            }
+            if (file != null && url != null) {
+                throw new BuildException(ERROR_BOTH_DECLARED);
+            }
+            if (file == null && url == null) {
+                throw new BuildException(ERROR_NONE_DECLARED);
+            }
+        }
+
+        /**
+         * Validate our settings.
+         * @return either the URL or the full file path
+         */
+        public String evaluate() {
+            validate();
+            if (url != null) {
+                return getUrl();
+            }
+            if (makeURL) {
+                try {
+                    return file.toURL().toExternalForm();
+                } catch (MalformedURLException e) {
+                    throw new BuildException(ERROR_NO_URL_CONVERT + file);
+                }
+            }
+            return file.toString();
+        }
+
+        /**
+         * Get the file.
+         * @return the file used.
+         */
+        public File getFile() {
+            return file;
+        }
+
+        /**
+         * name of a file to use as a source of WSDL or XSD data
+         * @param file the file to use.
+         */
+        public void setFile(File file) {
+            this.file = file;
+        }
+
+        /**
+         * Get the url.
+         * @return the URL of the resource.
+         */
+        public String getUrl() {
+            return url;
+        }
+
+        /**
+         * url of a resource.
+         * URLs have no timestamp checking, and are not validated
+         * @param url the URL string to use.
+         */
+        public void setUrl(String url) {
+            this.url = url;
+        }
+
+        /**
+         * Get the makeURL attribute.
+         * @return the attribute.
+         */
+        public boolean isMakeURL() {
+            return makeURL;
+        }
+
+        /**
+         * flag to request that a file is turned into an absolute file: URL
+         * before being passed to the WSDL compiler
+         * @param makeURL a <code>boolean</code> value.
+         */
+        public void setMakeURL(boolean makeURL) {
+            this.makeURL = makeURL;
+        }
+
+        /**
+         * Gets the file timestamp.
+         * @return the timestamp of a file, or -1 for a URL (meaning we do not know its age)
+         */
+        public long getTimestamp() {
+            if (file != null) {
+                return file.lastModified();
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    /**
+     * The enumerated values for our compiler
+     */
+    public static class Compiler extends EnumeratedAttribute {
+
+        /** microsoft */
+        public static final String COMPILER_MS = "microsoft";
+        /** mono */
+        public static final String COMPILER_MONO = "mono";
+        /** microsoft-on-mono */
+        public static final String COMPILER_MS_ON_MONO = "microsoft-on-mono";
+        // CheckStyle:VisibilityModifier OFF - bc
+        /** the index to string mappings */
+        String[] compilers = {
+            COMPILER_MS,
+            COMPILER_MONO,
+            COMPILER_MS_ON_MONO
+        };
+
+        /** WSDL */
+        public static final String EXE_WSDL = "wsdl";
+        /** MONO */
+        public static final String EXE_MONO = "mono";
+        /**
+         * programs to run
+         */
+        String[] compilerExecutables = {
+            EXE_WSDL,
+            EXE_WSDL,
+            EXE_MONO
+        };
+
+
+        /**
+         * extra things
+         */
+        String[][] extraCompilerArgs = {
+            {},
+            {},
+            {EXE_WSDL + ".exe"}
+        };
+
+        boolean[] absoluteFiles = {
+            true,
+            false,
+            true
+        };
+
+        // CheckStyle:VisibilityModifier ON
+        /**
+         * This is the only method a subclass needs to implement.
+         *
+         * @return an array holding all possible values of the enumeration.
+         *         The order of elements must be fixed so that <tt>indexOfValue(String)</tt>
+         *         always return the same index for the same value.
+         */
+        public String[] getValues() {
+            return compilers;
+        }
+
+        /**
+         * Create the default compiler for this platform.
+         * @return the default compiler
+         */
+        public static Compiler createDefaultCompiler() {
+            Compiler c = new Compiler();
+            String compilerName;
+            compilerName = Os.isFamily("windows") ? COMPILER_MS : COMPILER_MONO;
+            c.setValue(compilerName);
+            return c;
+        }
+
+        /**
+         * return the command to run
+         * @return the command
+         */
+        public String getCommand() {
+            return compilerExecutables[getIndex()];
+        }
+
+        /**
+         * return any extra arguments for the compiler
+         * @return extra compiler arguments
+         */
+        public String[] getExtraArgs() {
+            return extraCompilerArgs[getIndex()];
+        }
+
+        /**
+         * Get where the current value supports absolute files.
+         * @return true if the compiler does supports absolute files.
+         */
+        public boolean supportsAbsoluteFiles() {
+            return absoluteFiles[getIndex()];
+        }
+
+        /**
+         * apply any extra arguments of this class
+         * @param command the command to apply the arguments to.
+         */
+        public void applyExtraArgs(NetCommand command) {
+            String[] args = getExtraArgs();
+            for (int i = 0; i < args.length; i++) {
+               command.addArgument(args[i]);
+            }
+        }
+
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java
new file mode 100644
index 0000000..de68b6f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandDeploymentTool.java
@@ -0,0 +1,557 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+
+/**
+ * BorlandDeploymentTool is dedicated to the Borland Application Server 4.5 and 4.5.1
+ * This task generates and compiles the stubs and skeletons for all ejb described into the
+ * Deployment Descriptor, builds the jar file including the support files and verify
+ * whether the produced jar is valid or not.
+ * The supported options are:
+ * <ul>
+ * <li>debug  (boolean)    : turn on the debug mode for generation of
+ *                           stubs and skeletons (default:false)</li>
+ * <li>verify (boolean)    : turn on the verification at the end of the jar
+ *                           production  (default:true) </li>
+ * <li>verifyargs (String) : add optional argument to verify command
+ *                           (see vbj com.inprise.ejb.util.Verify)</li>
+ * <li>basdtd (String)     : location of the BAS DTD </li>
+ * <li>generateclient (boolean) : turn on the client jar file generation </li>
+ * <li>version (int)       : tell what is the Borland appserver version 4 or 5 </li>
+ * </ul>
+ *
+ *<PRE>
+ *
+ *      &lt;ejbjar srcdir=&quot;${build.classes}&quot;
+ *               basejarname=&quot;vsmp&quot;
+ *               descriptordir=&quot;${rsc.dir}/hrmanager&quot;&gt;
+ *        &lt;borland destdir=&quot;tstlib&quot;&gt;
+ *          &lt;classpath refid=&quot;classpath&quot; /&gt;
+ *        &lt;/borland&gt;
+ *        &lt;include name=&quot;**\ejb-jar.xml&quot;/&gt;
+ *        &lt;support dir=&quot;${build.classes}&quot;&gt;
+ *          &lt;include name=&quot;demo\smp\*.class&quot;/&gt;
+ *          &lt;include name=&quot;demo\helper\*.class&quot;/&gt;
+ *         &lt;/support&gt;
+ *     &lt;/ejbjar&gt;
+ *</PRE>
+ *
+ */
+public class BorlandDeploymentTool extends GenericDeploymentTool
+                                   implements ExecuteStreamHandler {
+    /** Borland 1.1 ejb id */
+    public static final String PUBLICID_BORLAND_EJB
+    = "-//Inprise Corporation//DTD Enterprise JavaBeans 1.1//EN";
+
+    protected static final String DEFAULT_BAS45_EJB11_DTD_LOCATION
+    = "/com/inprise/j2ee/xml/dtds/ejb-jar.dtd";
+
+    protected static final String DEFAULT_BAS_DTD_LOCATION
+    = "/com/inprise/j2ee/xml/dtds/ejb-inprise.dtd";
+
+    protected static final String BAS_DD = "ejb-inprise.xml";
+    protected static final String BES_DD = "ejb-borland.xml";
+
+
+    /** Java2iiop executable **/
+    protected static final String JAVA2IIOP = "java2iiop";
+
+    /** Verify class */
+    protected static final String VERIFY = "com.inprise.ejb.util.Verify";
+
+    /** Instance variable that stores the suffix for the borland jarfile. */
+    private String jarSuffix = "-ejb.jar";
+
+    /** Instance variable that stores the location of the borland DTD file. */
+    private String borlandDTD;
+
+    /** Instance variable that determines whether the debug mode is on */
+    private boolean java2iiopdebug = false;
+
+    /** store additional param for java2iiop command used to build EJB Stubs */
+    private String java2iioparams = null;
+
+    /** Instance variable that determines whether the client jar file is generated */
+    private boolean generateclient = false;
+
+    /** Borland Enterprise Server = version 5 */
+    static final int    BES       = 5;
+    /** Borland Application Server or Inprise Application Server  = version 4 */
+    static final int    BAS       = 4;
+
+    /** borland appserver version 4 or 5 */
+    private int version = BAS;
+
+
+    /**
+     * Instance variable that determines whether it is necessary to verify the
+     * produced jar
+     */
+    private boolean verify     = true;
+    private String  verifyArgs = "";
+
+    private Hashtable genfiles = new Hashtable();
+
+    /**
+     * set the debug mode for java2iiop (default false)
+     * @param debug the setting to use.
+     **/
+    public void setDebug(boolean debug) {
+        this.java2iiopdebug = debug;
+    }
+
+    /**
+     * set the verify  mode for the produced jar (default true)
+     * @param verify the setting to use.
+     **/
+    public void setVerify(boolean verify) {
+        this.verify = verify;
+    }
+
+
+    /**
+     * Setter used to store the suffix for the generated borland jar file.
+     * @param inString the string to use as the suffix.
+     */
+    public void setSuffix(String inString) {
+        this.jarSuffix = inString;
+    }
+
+
+    /**
+     * sets some additional args to send to verify command
+     * @param args additional command line parameters
+     */
+    public void setVerifyArgs(String args) {
+        this.verifyArgs = args;
+    }
+
+    /**
+     * Setter used to store the location of the borland DTD. This can be a file on the system
+     * or a resource on the classpath.
+     * @param inString the string to use as the DTD location.
+     */
+    public void setBASdtd(String inString) {
+        this.borlandDTD = inString;
+    }
+
+
+    /**
+     * setter used to store whether the task will include the generate client task.
+     * (see : BorlandGenerateClient task)
+     * @param b if true generate the client task.
+     */
+    public void setGenerateclient(boolean b) {
+        this.generateclient = b;
+    }
+
+    /**
+     * setter used to store the borland appserver version [4 or 5]
+     * @param version app server version 4 or 5
+     */
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    /**
+     * If filled, the params are added to the java2iiop command.
+     * (ex: -no_warn_missing_define)
+     * @param params additional params for java2iiop
+     */
+    public void setJava2iiopParams(String params) {
+        this.java2iioparams = params;
+    }
+
+
+    /**
+     * Get the borland descriptor handler.
+     * @param srcDir the source directory.
+     * @return the descriptor.
+     */
+    protected DescriptorHandler getBorlandDescriptorHandler(final File srcDir) {
+        DescriptorHandler handler =
+            new DescriptorHandler(getTask(), srcDir) {
+                    protected void processElement() {
+                        if (currentElement.equals("type-storage")) {
+                            // Get the filename of vendor specific descriptor
+                            String fileNameWithMETA = currentText;
+                            //trim the META_INF\ off of the file name
+                            String fileName
+                                = fileNameWithMETA.substring(META_DIR.length(),
+                                    fileNameWithMETA.length());
+                            File descriptorFile = new File(srcDir, fileName);
+
+                            ejbFiles.put(fileNameWithMETA, descriptorFile);
+                        }
+                    }
+                };
+        handler.registerDTD(PUBLICID_BORLAND_EJB,
+                            borlandDTD == null ? DEFAULT_BAS_DTD_LOCATION : borlandDTD);
+
+        for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+            EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+            handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+        }
+        return handler;
+    }
+
+    /**
+     * Add any vendor specific files which should be included in the
+     * EJB Jar.
+     * @param ejbFiles the map to add the files to.
+     * @param ddPrefix the prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+
+        //choose the right vendor DD
+        if (!(version == BES || version == BAS)) {
+            throw new BuildException("version " + version + " is not supported");
+        }
+
+        String dd = (version == BES ? BES_DD : BAS_DD);
+
+        log("vendor file : " + ddPrefix + dd, Project.MSG_DEBUG);
+
+        File borlandDD = new File(getConfig().descriptorDir, ddPrefix + dd);
+        if (borlandDD.exists()) {
+            log("Borland specific file found " + borlandDD,  Project.MSG_VERBOSE);
+            ejbFiles.put(META_DIR + dd ,  borlandDD);
+        } else {
+            log("Unable to locate borland deployment descriptor. "
+                + "It was expected to be in "
+                + borlandDD.getPath(), Project.MSG_WARN);
+            return;
+        }
+    }
+
+    /**
+     * Get the vendor specific name of the Jar that will be output. The modification date
+     * of this jar will be checked against the dependent bean classes.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        return new File(getDestDir(), baseName +  jarSuffix);
+    }
+
+    /**
+     * Verify the produced jar file by invoking the Borland verify tool
+     * @param sourceJar java.io.File representing the produced jar file
+     */
+    private void verifyBorlandJar(File sourceJar) {
+        if (version == BAS) {
+            verifyBorlandJarV4(sourceJar);
+            return;
+        }
+        if (version == BES) {
+            verifyBorlandJarV5(sourceJar);
+            return;
+        }
+        log("verify jar skipped because the version is invalid ["
+            + version + "]", Project.MSG_WARN);
+    }
+
+    /**
+     * Verify the produced jar file by invoking the Borland iastool tool
+     * @param sourceJar java.io.File representing the produced jar file
+     */
+    private void verifyBorlandJarV5(File sourceJar) {
+        log("verify BES " + sourceJar, Project.MSG_INFO);
+        try {
+            ExecTask execTask = null;
+            execTask = new ExecTask(getTask());
+            execTask.setDir(new File("."));
+            execTask.setExecutable("iastool");
+            //classpath
+            if (getCombinedClasspath() != null)  {
+                execTask.createArg().setValue("-VBJclasspath");
+                execTask.createArg().setValue(getCombinedClasspath().toString());
+            }
+
+            if (java2iiopdebug) {
+                execTask.createArg().setValue("-debug");
+            }
+            execTask.createArg().setValue("-verify");
+            execTask.createArg().setValue("-src");
+            // ejb jar file to verify
+            execTask.createArg().setValue(sourceJar.getPath());
+            log("Calling iastool", Project.MSG_VERBOSE);
+            execTask.execute();
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling generateclient Details: "
+                + e.toString();
+            throw new BuildException(msg, e);
+        }
+    }
+
+    /**
+     * Verify the produced jar file by invoking the Borland verify tool
+     * @param sourceJar java.io.File representing the produced jar file
+     */
+    private void verifyBorlandJarV4(File sourceJar) {
+        org.apache.tools.ant.taskdefs.Java javaTask = null;
+        log("verify BAS " + sourceJar, Project.MSG_INFO);
+        try  {
+            String args = verifyArgs;
+            args += " " + sourceJar.getPath();
+
+            javaTask = new Java(getTask());
+            javaTask.setTaskName("verify");
+            javaTask.setClassname(VERIFY);
+            Commandline.Argument arguments = javaTask.createArg();
+            arguments.setLine(args);
+            Path classpath = getCombinedClasspath();
+            if (classpath != null)  {
+                javaTask.setClasspath(classpath);
+                javaTask.setFork(true);
+            }
+
+            log("Calling " + VERIFY + " for " + sourceJar.toString(),
+                Project.MSG_VERBOSE);
+            javaTask.execute();
+        } catch (Exception e) {
+            //TO DO : delete the file if it is not a valid file.
+            String msg = "Exception while calling " + VERIFY + " Details: "
+                + e.toString();
+            throw new BuildException(msg, e);
+        }
+    }
+
+
+    /**
+     * Generate the client jar corresponding to the jar file passed as parameter
+     * the method uses the BorlandGenerateClient task.
+     * @param sourceJar java.io.File representing the produced jar file
+     */
+    private void generateClient(File sourceJar) {
+        getTask().getProject().addTaskDefinition("internal_bas_generateclient",
+            org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient.class);
+
+        org.apache.tools.ant.taskdefs.optional.ejb.BorlandGenerateClient gentask = null;
+        log("generate client for " + sourceJar, Project.MSG_INFO);
+        try {
+            Project project = getTask().getProject();
+            gentask
+                = (BorlandGenerateClient) project.createTask("internal_bas_generateclient");
+            gentask.setEjbjar(sourceJar);
+            gentask.setDebug(java2iiopdebug);
+            Path classpath = getCombinedClasspath();
+            if (classpath != null) {
+                gentask.setClasspath(classpath);
+            }
+            gentask.setVersion(version);
+            gentask.setTaskName("generate client");
+            gentask.execute();
+        } catch (Exception e) {
+            //TO DO : delete the file if it is not a valid file.
+            String msg = "Exception while calling " + VERIFY + " Details: "
+                + e.toString();
+            throw new BuildException(msg, e);
+        }
+    }
+
+    /**
+     * Generate stubs & skeleton for each home found into the DD
+     * Add all the generate class file into the ejb files
+     * @param ithomes : iterator on home class
+     */
+    private void buildBorlandStubs(Iterator ithomes) {
+        Execute execTask = null;
+
+        execTask = new Execute(this);
+        Project project = getTask().getProject();
+        execTask.setAntRun(project);
+        execTask.setWorkingDirectory(project.getBaseDir());
+
+        Commandline commandline = new Commandline();
+        commandline.setExecutable(JAVA2IIOP);
+        //debug ?
+        if (java2iiopdebug) {
+            commandline.createArgument().setValue("-VBJdebug");
+        }
+        //set the classpath
+        commandline.createArgument().setValue("-VBJclasspath");
+        commandline.createArgument().setPath(getCombinedClasspath());
+        //list file
+        commandline.createArgument().setValue("-list_files");
+        //no TIE classes
+        commandline.createArgument().setValue("-no_tie");
+
+        if (java2iioparams != null) {
+            log("additional  " + java2iioparams + " to java2iiop ", 0);
+            commandline.createArgument().setValue(java2iioparams);
+        }
+
+
+        //root dir
+        commandline.createArgument().setValue("-root_dir");
+        commandline.createArgument().setValue(getConfig().srcDir.getAbsolutePath());
+        //compiling order
+        commandline.createArgument().setValue("-compile");
+        //add the home class
+        while (ithomes.hasNext()) {
+            commandline.createArgument().setValue(ithomes.next().toString());
+        }
+
+        try {
+            log("Calling java2iiop", Project.MSG_VERBOSE);
+            log(commandline.describeCommand(), Project.MSG_DEBUG);
+            execTask.setCommandline(commandline.getCommandline());
+            int result = execTask.execute();
+            if (Execute.isFailure(result)) {
+                String msg = "Failed executing java2iiop (ret code is "
+                    + result + ")";
+                throw new BuildException(msg, getTask().getLocation());
+            }
+        } catch (java.io.IOException e) {
+            log("java2iiop exception :" + e.getMessage(), Project.MSG_ERR);
+            throw new BuildException(e, getTask().getLocation());
+        }
+    }
+
+    /**
+     * Method used to encapsulate the writing of the JAR file. Iterates over the
+     * filenames/java.io.Files in the Hashtable stored on the instance variable
+     * ejbFiles.
+     * @param baseName the base name.
+     * @param jarFile  the jar file to write to.
+     * @param files    the files to write to the jar.
+     * @param publicId the id to use.
+     * @throws BuildException if there is an error.
+     */
+    protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
+        throws BuildException {
+        //build the home classes list.
+        Vector homes = new Vector();
+        Iterator it = files.keySet().iterator();
+        while (it.hasNext()) {
+            String clazz = (String) it.next();
+            if (clazz.endsWith("Home.class")) {
+                //remove .class extension
+                String home = toClass(clazz);
+                homes.add(home);
+                log(" Home " + home, Project.MSG_VERBOSE);
+            }
+        }
+
+        buildBorlandStubs(homes.iterator());
+
+        //add the gen files to the collection
+        files.putAll(genfiles);
+
+        super.writeJar(baseName, jarFile, files, publicId);
+
+        if (verify) {
+            verifyBorlandJar(jarFile);
+        }
+
+        if (generateclient) {
+            generateClient(jarFile);
+        }
+    }
+
+    /**
+     * convert a class file name : A/B/C/toto.class
+     * into    a class name: A.B.C.toto
+     */
+    private String toClass(String filename) {
+        //remove the .class
+        String classname = filename.substring(0, filename.lastIndexOf(".class"));
+        classname = classname.replace('\\', '.');
+        return classname;
+    }
+
+    /**
+     * convert a file name : A/B/C/toto.java
+     * into    a class name: A/B/C/toto.class
+     */
+    private  String toClassFile(String filename) {
+        //remove the .class
+        String classfile = filename.substring(0, filename.lastIndexOf(".java"));
+        classfile = classfile + ".class";
+        return classfile;
+    }
+
+    // implementation of org.apache.tools.ant.taskdefs.ExecuteStreamHandler interface
+
+    /** {@inheritDoc}. */
+    public void start() throws IOException  { }
+    /** {@inheritDoc}. */
+    public void stop()  {  }
+    /** {@inheritDoc}. */
+    public void setProcessInputStream(OutputStream param1) throws IOException   { }
+
+    /**
+     * Set the output stream of the process.
+     * @param is the input stream.
+     * @throws IOException if there is an error.
+     */
+    public void setProcessOutputStream(InputStream is) throws IOException {
+        try {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+            String javafile;
+            while ((javafile = reader.readLine()) != null) {
+                if (javafile.endsWith(".java")) {
+                    String classfile = toClassFile(javafile);
+                    String key = classfile.substring(
+                        getConfig().srcDir.getAbsolutePath().length() + 1);
+                    genfiles.put(key, new File(classfile));
+                }
+            }
+            reader.close();
+        } catch (Exception e) {
+            String msg = "Exception while parsing  java2iiop output. Details: " + e.toString();
+            throw new BuildException(msg, e);
+        }
+    }
+
+    /**
+     * Set the error stream of the process.
+     * @param is the input stream.
+     * @throws IOException if there is an error.
+     */
+    public void setProcessErrorStream(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        String s = reader.readLine();
+        if (s != null) {
+            log("[java2iiop] " + s, Project.MSG_ERR);
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java
new file mode 100644
index 0000000..392f17a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/BorlandGenerateClient.java
@@ -0,0 +1,312 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.ExecTask;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Generates a Borland Application Server 4.5 client JAR using as
+ * input the EJB JAR file.
+ *
+ * Two mode are available: java mode (default) and fork mode. With the fork mode,
+ * it is impossible to add classpath to the command line.
+ *
+ * @ant.task name="blgenclient" category="ejb"
+ */
+public class BorlandGenerateClient extends Task {
+    static final String JAVA_MODE = "java";
+    static final String FORK_MODE = "fork";
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** debug the generateclient task */
+    boolean debug = false;
+
+    /** hold the ejbjar file name */
+    File ejbjarfile = null;
+
+    /** hold the client jar file name */
+    File clientjarfile = null;
+
+    /** hold the classpath */
+    Path classpath;
+
+    /** hold the mode (java|fork) */
+    String mode = FORK_MODE;
+
+    /** hold the version */
+    int version = BorlandDeploymentTool.BAS;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the version attribute.
+     * @param version the value to use.
+     */
+    public void setVersion(int version) {
+        this.version = version;
+    }
+
+    /**
+     * Command launching mode: java or fork.
+     * @param s the mode to use.
+     */
+    public void setMode(String s) {
+        mode = s;
+    }
+
+    /**
+     * If true, turn on the debug mode for each of the Borland tools launched.
+     * @param debug a <code>boolean</code> value.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * EJB JAR file.
+     * @param ejbfile the file to use.
+     */
+    public void setEjbjar(File ejbfile) {
+        ejbjarfile = ejbfile;
+    }
+
+    /**
+     * Client JAR file name.
+     * @param clientjar the file to use.
+     */
+    public void setClientjar(File clientjar) {
+        clientjarfile = clientjar;
+    }
+
+    /**
+     * Path to use for classpath.
+     * @param classpath the path to use.
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Adds path to the classpath.
+     * @return a path to be configured as a nested element.
+     */
+    public Path createClasspath() {
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Reference to existing path, to use as a classpath.
+     * @param r the reference to use.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+
+    /**
+     * Do the work.
+     *
+     * The work is actually done by creating a separate JVM to run a java task.
+     *
+     * @exception BuildException if something goes wrong with the build
+     */
+    public void execute() throws BuildException {
+        if (ejbjarfile == null || ejbjarfile.isDirectory()) {
+            throw new BuildException("invalid ejb jar file.");
+        }
+
+        if (clientjarfile == null || clientjarfile.isDirectory()) {
+            log("invalid or missing client jar file.", Project.MSG_VERBOSE);
+            String ejbjarname = ejbjarfile.getAbsolutePath();
+            //clientname = ejbjarfile+client.jar
+            String clientname = ejbjarname.substring(0, ejbjarname.lastIndexOf("."));
+            clientname = clientname + "client.jar";
+            clientjarfile = new File(clientname);
+        }
+
+        if (mode == null) {
+            log("mode is null default mode  is java");
+            setMode(JAVA_MODE);
+        }
+
+        if (!(version == BorlandDeploymentTool.BES
+            || version == BorlandDeploymentTool.BAS)) {
+            throw new BuildException("version " + version
+                                      + " is not supported");
+        }
+
+        log("client jar file is " + clientjarfile);
+
+        if (mode.equalsIgnoreCase(FORK_MODE)) {
+            executeFork();
+        } else {
+            executeJava();
+        } // end of else
+    }
+
+    /**
+     * launch the generate client using java api.
+     * @throws BuildException if there is an error.
+     */
+    protected void executeJava() throws BuildException {
+        try {
+            if (version == BorlandDeploymentTool.BES)  {
+                throw new BuildException("java mode is supported only for "
+                    + "previous version <=" + BorlandDeploymentTool.BAS);
+            }
+
+            log("mode : java");
+
+            Java execTask = null;
+            execTask = new Java(this);
+
+            execTask.setDir(new File("."));
+            execTask.setClassname("com.inprise.server.commandline.EJBUtilities");
+            //classpath
+            //add at the end of the classpath
+            //the system classpath in order to find the tools.jar file
+            execTask.setClasspath(classpath.concatSystemClasspath());
+
+            execTask.setFork(true);
+            execTask.createArg().setValue("generateclient");
+            if (debug) {
+                execTask.createArg().setValue("-trace");
+            }
+
+            execTask.createArg().setValue("-short");
+            execTask.createArg().setValue("-jarfile");
+            // ejb jar file
+            execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+            //client jar file
+            execTask.createArg().setValue("-single");
+            execTask.createArg().setValue("-clientjarfile");
+            execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+
+            log("Calling EJBUtilities", Project.MSG_VERBOSE);
+            execTask.execute();
+
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling generateclient Details: " + e.toString();
+            throw new BuildException(msg, e);
+        }
+    }
+
+    /**
+     * launch the generate client using system api.
+     * @throws BuildException if there is an error.
+     */
+    protected  void executeFork() throws BuildException {
+        if (version == BorlandDeploymentTool.BAS) {
+            executeForkV4();
+        }
+        if (version == BorlandDeploymentTool.BES) {
+            executeForkV5();
+        }
+    }
+
+    /**
+     * launch the generate client using system api.
+     * @throws BuildException if there is an error.
+     */
+    protected  void executeForkV4() throws BuildException {
+        try {
+
+            log("mode : fork " + BorlandDeploymentTool.BAS, Project.MSG_DEBUG);
+
+            ExecTask execTask = new ExecTask(this);
+
+            execTask.setDir(new File("."));
+            execTask.setExecutable("iastool");
+            execTask.createArg().setValue("generateclient");
+            if (debug) {
+                execTask.createArg().setValue("-trace");
+            }
+
+            execTask.createArg().setValue("-short");
+            execTask.createArg().setValue("-jarfile");
+            // ejb jar file
+            execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+            //client jar file
+            execTask.createArg().setValue("-single");
+            execTask.createArg().setValue("-clientjarfile");
+            execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+
+            log("Calling iastool", Project.MSG_VERBOSE);
+            execTask.execute();
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling generateclient Details: "
+                + e.toString();
+            throw new BuildException(msg, e);
+        }
+
+    }
+
+    /**
+     * launch the generate client using system api.
+     * @throws BuildException if there is an error.
+     */
+    protected  void executeForkV5() throws BuildException {
+        try {
+            log("mode : fork " + BorlandDeploymentTool.BES, Project.MSG_DEBUG);
+            ExecTask execTask = new ExecTask(this);
+
+            execTask.setDir(new File("."));
+
+            execTask.setExecutable("iastool");
+            if (debug) {
+                execTask.createArg().setValue("-debug");
+            }
+            execTask.createArg().setValue("-genclient");
+            execTask.createArg().setValue("-jars");
+            // ejb jar file
+            execTask.createArg().setValue(ejbjarfile.getAbsolutePath());
+            //client jar file
+            execTask.createArg().setValue("-target");
+            execTask.createArg().setValue(clientjarfile.getAbsolutePath());
+            //classpath
+            execTask.createArg().setValue("-cp");
+            execTask.createArg().setValue(classpath.toString());
+            log("Calling iastool", Project.MSG_VERBOSE);
+            execTask.execute();
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling generateclient Details: "
+                + e.toString();
+            throw new BuildException(msg, e);
+        }
+
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java
new file mode 100644
index 0000000..e8392605
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/DescriptorHandler.java
@@ -0,0 +1,389 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Hashtable;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.xml.sax.AttributeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Inner class used by EjbJar to facilitate the parsing of deployment
+ * descriptors and the capture of appropriate information. Extends
+ * HandlerBase so it only implements the methods needed. During parsing
+ * creates a hashtable consisting of entries mapping the name it should be
+ * inserted into an EJB jar as to a File representing the file on disk. This
+ * list can then be accessed through the getFiles() method.
+ */
+public class DescriptorHandler extends org.xml.sax.HandlerBase {
+    private static final int DEFAULT_HASH_TABLE_SIZE = 10;
+    private static final int STATE_LOOKING_EJBJAR = 1;
+    private static final int STATE_IN_EJBJAR = 2;
+    private static final int STATE_IN_BEANS = 3;
+    private static final int STATE_IN_SESSION = 4;
+    private static final int STATE_IN_ENTITY = 5;
+    private static final int STATE_IN_MESSAGE = 6;
+
+    private Task owningTask;
+
+    private String publicId = null;
+
+    /**
+     * Bunch of constants used for storing entries in a hashtable, and for
+     * constructing the filenames of various parts of the ejb jar.
+     */
+    private static final String EJB_REF               = "ejb-ref";
+    private static final String EJB_LOCAL_REF         = "ejb-local-ref";
+    private static final String HOME_INTERFACE        = "home";
+    private static final String REMOTE_INTERFACE      = "remote";
+    private static final String LOCAL_HOME_INTERFACE  = "local-home";
+    private static final String LOCAL_INTERFACE       = "local";
+    private static final String BEAN_CLASS            = "ejb-class";
+    private static final String PK_CLASS              = "prim-key-class";
+    private static final String EJB_NAME              = "ejb-name";
+    private static final String EJB_JAR               = "ejb-jar";
+    private static final String ENTERPRISE_BEANS      = "enterprise-beans";
+    private static final String ENTITY_BEAN           = "entity";
+    private static final String SESSION_BEAN          = "session";
+    private static final String MESSAGE_BEAN          = "message-driven";
+
+    /**
+     * The state of the parsing
+     */
+    private int parseState = STATE_LOOKING_EJBJAR;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Instance variable used to store the name of the current element being
+     * processed by the SAX parser.  Accessed by the SAX parser call-back methods
+     * startElement() and endElement().
+     */
+    protected String currentElement = null;
+
+    /**
+     * The text of the current element
+     */
+    protected String currentText = null;
+
+    /**
+     * Instance variable that stores the names of the files as they will be
+     * put into the jar file, mapped to File objects  Accessed by the SAX
+     * parser call-back method characters().
+     */
+    protected Hashtable ejbFiles = null;
+
+    /**
+     * Instance variable that stores the value found in the &lt;ejb-name&gt; element
+     */
+    protected String ejbName = null;
+
+    private Hashtable fileDTDs = new Hashtable();
+
+    private Hashtable resourceDTDs = new Hashtable();
+
+    private boolean inEJBRef = false;
+
+    private Hashtable urlDTDs = new Hashtable();
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * The directory containing the bean classes and interfaces. This is
+     * used for performing dependency file lookups.
+     */
+    private File srcDir;
+
+    /**
+     * Constructor for DescriptorHandler.
+     * @param task the task that owns this desciptor
+     * @param srcDir the source directory
+     */
+    public DescriptorHandler(Task task, File srcDir) {
+        this.owningTask = task;
+        this.srcDir = srcDir;
+    }
+
+    /**
+     * Register a dtd with a location.
+     * The location is one of a filename, a resource name in the classpath, or
+     * a URL.
+     * @param publicId the public identity of the dtd
+     * @param location the location of the dtd
+     */
+    public void registerDTD(String publicId, String location) {
+        if (location == null) {
+            return;
+        }
+
+        File fileDTD = new File(location);
+        if (!fileDTD.exists()) {
+            // resolve relative to project basedir
+            fileDTD = owningTask.getProject().resolveFile(location);
+        }
+
+        if (fileDTD.exists()) {
+            if (publicId != null) {
+                fileDTDs.put(publicId, fileDTD);
+                owningTask.log("Mapped publicId " + publicId + " to file "
+                    + fileDTD, Project.MSG_VERBOSE);
+            }
+            return;
+        }
+
+        if (getClass().getResource(location) != null) {
+            if (publicId != null) {
+                resourceDTDs.put(publicId, location);
+                owningTask.log("Mapped publicId " + publicId + " to resource "
+                    + location, Project.MSG_VERBOSE);
+            }
+        }
+
+        try {
+            if (publicId != null) {
+                URL urldtd = new URL(location);
+                urlDTDs.put(publicId, urldtd);
+            }
+        } catch (java.net.MalformedURLException e) {
+            //ignored
+        }
+
+    }
+
+    /**
+     * Resolve the entity.
+     * @see org.xml.sax.EntityResolver#resolveEntity(String, String).
+     * @param publicId The public identifier, or <code>null</code>
+     *                 if none is available.
+     * @param systemId The system identifier provided in the XML
+     *                 document. Will not be <code>null</code>.
+     * @return an inputsource for this identifier
+     * @throws SAXException if there is a problem.
+     */
+    public InputSource resolveEntity(String publicId, String systemId)
+        throws SAXException {
+        this.publicId = publicId;
+
+        File dtdFile = (File) fileDTDs.get(publicId);
+        if (dtdFile != null) {
+            try {
+                owningTask.log("Resolved " + publicId + " to local file "
+                    + dtdFile, Project.MSG_VERBOSE);
+                return new InputSource(new FileInputStream(dtdFile));
+            } catch (FileNotFoundException ex) {
+                // ignore
+            }
+        }
+
+        String dtdResourceName = (String) resourceDTDs.get(publicId);
+        if (dtdResourceName != null) {
+            InputStream is = this.getClass().getResourceAsStream(dtdResourceName);
+            if (is != null) {
+                owningTask.log("Resolved " + publicId + " to local resource "
+                    + dtdResourceName, Project.MSG_VERBOSE);
+                return new InputSource(is);
+            }
+        }
+
+        URL dtdUrl = (URL) urlDTDs.get(publicId);
+        if (dtdUrl != null) {
+            try {
+                InputStream is = dtdUrl.openStream();
+                owningTask.log("Resolved " + publicId + " to url "
+                    + dtdUrl, Project.MSG_VERBOSE);
+                return new InputSource(is);
+            } catch (IOException ioe) {
+                //ignore
+            }
+        }
+
+        owningTask.log("Could not resolve ( publicId: " + publicId
+            + ", systemId: " + systemId + ") to a local entity", Project.MSG_INFO);
+
+        return null;
+    }
+
+    /**
+     * Getter method that returns the set of files to include in the EJB jar.
+     * @return the map of files
+     */
+    public Hashtable getFiles() {
+        return (ejbFiles == null) ? new Hashtable() : ejbFiles;
+    }
+
+    /**
+     * Get the publicId of the DTD
+     * @return the public id
+     */
+    public String getPublicId() {
+        return publicId;
+    }
+
+     /**
+     * Getter method that returns the value of the &lt;ejb-name&gt; element.
+     * @return the ejb name
+     */
+    public String getEjbName() {
+        return ejbName;
+    }
+
+    /**
+     * SAX parser call-back method that is used to initialize the values of some
+     * instance variables to ensure safe operation.
+     * @throws SAXException on error
+     */
+    public void startDocument() throws SAXException {
+        this.ejbFiles = new Hashtable(DEFAULT_HASH_TABLE_SIZE, 1);
+        this.currentElement = null;
+        inEJBRef = false;
+    }
+
+
+    /**
+     * SAX parser call-back method that is invoked when a new element is entered
+     * into.  Used to store the context (attribute name) in the currentAttribute
+     * instance variable.
+     * @param name The name of the element being entered.
+     * @param attrs Attributes associated to the element.
+     * @throws SAXException on error
+     */
+    public void startElement(String name, AttributeList attrs)
+        throws SAXException {
+        this.currentElement = name;
+        currentText = "";
+        if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
+            inEJBRef = true;
+        } else if (parseState == STATE_LOOKING_EJBJAR && name.equals(EJB_JAR)) {
+            parseState = STATE_IN_EJBJAR;
+        } else if (parseState == STATE_IN_EJBJAR && name.equals(ENTERPRISE_BEANS)) {
+            parseState = STATE_IN_BEANS;
+        } else if (parseState == STATE_IN_BEANS && name.equals(SESSION_BEAN)) {
+            parseState = STATE_IN_SESSION;
+        } else if (parseState == STATE_IN_BEANS && name.equals(ENTITY_BEAN)) {
+            parseState = STATE_IN_ENTITY;
+        } else if (parseState == STATE_IN_BEANS && name.equals(MESSAGE_BEAN)) {
+            parseState = STATE_IN_MESSAGE;
+        }
+    }
+
+
+    /**
+     * SAX parser call-back method that is invoked when an element is exited.
+     * Used to blank out (set to the empty string, not nullify) the name of
+     * the currentAttribute.  A better method would be to use a stack as an
+     * instance variable, however since we are only interested in leaf-node
+     * data this is a simpler and workable solution.
+     * @param name The name of the attribute being exited. Ignored
+     *        in this implementation.
+     * @throws SAXException on error
+     */
+    public void endElement(String name) throws SAXException {
+        processElement();
+        currentText = "";
+        this.currentElement = "";
+        if (name.equals(EJB_REF) || name.equals(EJB_LOCAL_REF)) {
+            inEJBRef = false;
+        } else if (parseState == STATE_IN_ENTITY && name.equals(ENTITY_BEAN)) {
+            parseState = STATE_IN_BEANS;
+        } else if (parseState == STATE_IN_SESSION && name.equals(SESSION_BEAN)) {
+            parseState = STATE_IN_BEANS;
+        } else if (parseState == STATE_IN_MESSAGE && name.equals(MESSAGE_BEAN)) {
+            parseState = STATE_IN_BEANS;
+        } else if (parseState == STATE_IN_BEANS && name.equals(ENTERPRISE_BEANS)) {
+            parseState = STATE_IN_EJBJAR;
+        } else if (parseState == STATE_IN_EJBJAR && name.equals(EJB_JAR)) {
+            parseState = STATE_LOOKING_EJBJAR;
+        }
+    }
+
+    /**
+     * SAX parser call-back method invoked whenever characters are located within
+     * an element.  currentAttribute (modified by startElement and endElement)
+     * tells us whether we are in an interesting element (one of the up to four
+     * classes of an EJB).  If so then converts the classname from the format
+     * org.apache.tools.ant.Parser to the convention for storing such a class,
+     * org/apache/tools/ant/Parser.class.  This is then resolved into a file
+     * object under the srcdir which is stored in a Hashtable.
+     * @param ch A character array containing all the characters in
+     *        the element, and maybe others that should be ignored.
+     * @param start An integer marking the position in the char
+     *        array to start reading from.
+     * @param length An integer representing an offset into the
+     *        char array where the current data terminates.
+     * @throws SAXException on error
+     */
+    public void characters(char[] ch, int start, int length)
+        throws SAXException {
+
+        currentText += new String(ch, start, length);
+    }
+
+
+    /**
+     * Called when an endelement is seen.
+     * This may be overridden in derived classes.
+     * This updates the ejbfiles if the element is an interface or a bean class.
+     * This updates the ejbname if the element is an ejb name.
+     */
+    protected void processElement() {
+        if (inEJBRef
+            || (parseState != STATE_IN_ENTITY
+                && parseState != STATE_IN_SESSION
+                && parseState != STATE_IN_MESSAGE)) {
+            return;
+        }
+
+        if (currentElement.equals(HOME_INTERFACE)
+            || currentElement.equals(REMOTE_INTERFACE)
+            || currentElement.equals(LOCAL_INTERFACE)
+            || currentElement.equals(LOCAL_HOME_INTERFACE)
+            || currentElement.equals(BEAN_CLASS)
+            || currentElement.equals(PK_CLASS)) {
+
+            // Get the filename into a String object
+            File classFile = null;
+            String className = currentText.trim();
+
+            // If it's a primitive wrapper then we shouldn't try and put
+            // it into the jar, so ignore it.
+            if (!className.startsWith("java.")
+                && !className.startsWith("javax.")) {
+                // Translate periods into path separators, add .class to the
+                // name, create the File object and add it to the Hashtable.
+                className = className.replace('.', File.separatorChar);
+                className += ".class";
+                classFile = new File(srcDir, className);
+                ejbFiles.put(className, classFile);
+            }
+        }
+
+        // Get the value of the <ejb-name> tag.  Only the first occurrence.
+        if (currentElement.equals(EJB_NAME)) {
+            if (ejbName == null) {
+                ejbName = currentText.trim();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java
new file mode 100644
index 0000000..d6006d6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EJBDeploymentTool.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+
+
+import javax.xml.parsers.SAXParser;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+
+/**
+ * The interface to implement for deployment tools.
+ */
+public interface EJBDeploymentTool {
+    /**
+     * Process a deployment descriptor, generating the necessary vendor specific
+     * deployment files.
+     *
+     * @param descriptorFilename the name of the deployment descriptor
+     * @param saxParser a SAX parser which can be used to parse the deployment descriptor.
+     * @throws BuildException if there is an error.
+     */
+    void processDescriptor(String descriptorFilename, SAXParser saxParser)
+        throws BuildException;
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     * @throws BuildException if there is an error.
+     */
+    void validateConfigured() throws BuildException;
+
+    /**
+     * Set the task which owns this tool
+     * @param task the task.
+     */
+    void setTask(Task task);
+
+    /**
+     * Configure this tool for use in the ejbjar task.
+     * @param config contains configuration state.
+     */
+    void configure(EjbJar.Config config);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
new file mode 100644
index 0000000..f161ca0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/EjbJar.java
@@ -0,0 +1,628 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+// Standard java imports
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.xml.sax.SAXException;
+
+/**
+ * Provides automated EJB JAR file creation.
+ * <p>
+ * Extends the
+ * MatchingTask class provided in the default ant distribution to provide a
+ * directory scanning EJB jarfile generator.
+ * </p>
+ *
+ * <p>
+ * The task works by taking the deployment descriptors one at a time and
+ * parsing them to locate the names of the classes which should be placed in
+ * the jar. The classnames are translated to java.io.Files by replacing
+ * periods with File.separatorChar and resolving the generated filename as a
+ * relative path under the srcDir attribute. All necessary files are then
+ * assembled into a jarfile. One jarfile is constructed for each deployment
+ * descriptor found.
+ * </p>
+ *
+ * */
+public class EjbJar extends MatchingTask {
+
+    /**
+     * Inner class used to record information about the location of a local DTD
+     */
+    public static class DTDLocation
+        extends org.apache.tools.ant.types.DTDLocation {
+    }
+
+    /**
+     * A class which contains the configuration state of the ejbjar task.
+     * This state is passed to the deployment tools for configuration
+     */
+    static class Config {
+        // CheckStyle:VisibilityModifier OFF - bc
+        /**
+         * Stores a handle to the directory under which to search for class
+         * files
+         */
+        public File srcDir;
+
+        /**
+         * Stores a handle to the directory under which to search for
+         * deployment descriptors
+         */
+        public File descriptorDir;
+
+        /** Instance variable that marks the end of the 'basename' */
+        public String baseNameTerminator = "-";
+
+        /** Stores a handle to the destination EJB Jar file */
+        public String baseJarName;
+
+        /**
+         * Instance variable that determines whether to use a package structure
+         * of a flat directory as the destination for the jar files.
+         */
+        public boolean flatDestDir = false;
+
+        /**
+         * The classpath to use when loading classes
+         */
+        public Path classpath;
+
+        /**
+         * A Fileset of support classes
+         */
+        public List supportFileSets = new ArrayList();
+
+        /**
+         * The list of configured DTD locations
+         */
+        public ArrayList dtdLocations = new ArrayList();
+
+        /**
+         * The naming scheme used to determine the generated jar name
+         * from the descriptor information
+         */
+        public NamingScheme namingScheme;
+
+        /**
+         * The Manifest file
+         */
+        public File manifest;
+
+        /**
+         * The dependency analyzer to use to add additional classes to the jar
+         */
+        public String analyzer;
+        // CheckStyle:VisibilityModifier ON
+    }
+
+    /**
+     * An EnumeratedAttribute class for handling different EJB jar naming
+     * schemes
+     */
+    public static class NamingScheme extends EnumeratedAttribute {
+        /**
+         * Naming scheme where generated jar is determined from the ejb-name in
+         * the deployment descripor
+         */
+        public static final String EJB_NAME = "ejb-name";
+
+        /**
+         * Naming scheme where the generated jar name is based on the
+         * name of the directory containing the deployment descriptor
+         */
+        public static final String DIRECTORY = "directory";
+
+        /**
+         * Naming scheme where the generated jar name is based on the name of
+         * the deployment descriptor file
+         */
+        public static final String DESCRIPTOR = "descriptor";
+
+        /**
+         * Naming scheme where the generated jar is named by the basejarname
+         * attribute
+         */
+        public static final String BASEJARNAME = "basejarname";
+
+        /**
+         * Gets the values of the NamingScheme
+         *
+         * @return an array of the values of this attribute class.
+         */
+        public String[] getValues() {
+            return new String[] {EJB_NAME, DIRECTORY, DESCRIPTOR, BASEJARNAME};
+        }
+    }
+
+    /**
+     * CMP versions supported
+     * valid CMP versions are 1.0 and 2.0
+     * @since ant 1.6
+     */
+    public static class CMPVersion extends EnumeratedAttribute {
+        /** 1.0 value */
+        public static final String CMP1_0 = "1.0";
+        /** 2.0 value */
+        public static final String CMP2_0 = "2.0";
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[]{
+                CMP1_0,
+                CMP2_0,
+            };
+        }
+    }
+    /**
+     * The config which is built by this task and used by the various deployment
+     * tools to access the configuration of the ejbjar task
+     */
+    private Config config = new Config();
+
+
+    /**
+     * Stores a handle to the directory to put the Jar files in. This is
+     * only used by the generic deployment descriptor tool which is created
+     * if no other deployment descriptor tools are provided. Normally each
+     * deployment tool will specify the desitination dir itself.
+     */
+    private File destDir;
+
+    /** Instance variable that stores the suffix for the generated jarfile. */
+    private String genericJarSuffix = "-generic.jar";
+
+    /** Instance variable that stores the CMP version for the jboss jarfile. */
+    private String cmpVersion = CMPVersion.CMP1_0;
+
+    /** The list of deployment tools we are going to run. */
+    private ArrayList deploymentTools = new ArrayList();
+
+    /**
+     * Add a deployment tool to the list of deployment tools that will be
+     * processed
+     *
+     * @param deploymentTool a deployment tool instance to which descriptors
+     *        will be passed for processing.
+     */
+    protected void addDeploymentTool(EJBDeploymentTool deploymentTool) {
+        deploymentTool.setTask(this);
+        deploymentTools.add(deploymentTool);
+    }
+
+    /**
+     * Adds a deployment tool for Weblogic server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public WeblogicDeploymentTool createWeblogic() {
+        WeblogicDeploymentTool tool = new WeblogicDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for Websphere 4.0 server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public WebsphereDeploymentTool createWebsphere() {
+        WebsphereDeploymentTool tool = new WebsphereDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for Borland server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public BorlandDeploymentTool createBorland() {
+        log("Borland deployment tools",  Project.MSG_VERBOSE);
+
+        BorlandDeploymentTool tool = new BorlandDeploymentTool();
+        tool.setTask(this);
+        deploymentTools.add(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for iPlanet Application Server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public IPlanetDeploymentTool createIplanet() {
+        log("iPlanet Application Server deployment tools", Project.MSG_VERBOSE);
+
+        IPlanetDeploymentTool tool = new IPlanetDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for JBoss server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public JbossDeploymentTool createJboss() {
+        JbossDeploymentTool tool = new JbossDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for JOnAS server.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public JonasDeploymentTool createJonas() {
+        log("JOnAS deployment tools",  Project.MSG_VERBOSE);
+
+        JonasDeploymentTool tool = new JonasDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds a deployment tool for Weblogic when using the Toplink
+     * Object-Relational mapping.
+     *
+     * @return the deployment tool instance to be configured.
+     */
+    public WeblogicTOPLinkDeploymentTool createWeblogictoplink() {
+        log("The <weblogictoplink> element is no longer required. Please use "
+            + "the <weblogic> element and set newCMP=\"true\"",
+            Project.MSG_INFO);
+        WeblogicTOPLinkDeploymentTool tool
+            = new WeblogicTOPLinkDeploymentTool();
+        addDeploymentTool(tool);
+        return tool;
+    }
+
+    /**
+     * Adds to the classpath used to locate the super classes and
+     * interfaces of the classes that will make up the EJB JAR.
+     *
+     * @return the path to be configured.
+     */
+    public Path createClasspath() {
+        if (config.classpath == null) {
+            config.classpath = new Path(getProject());
+        }
+        return config.classpath.createPath();
+    }
+
+    /**
+     * Create a DTD location record. This stores the location of a DTD. The
+     * DTD is identified by its public Id. The location may either be a file
+     * location or a resource location.
+     *
+     * @return the DTD location object to be configured by Ant
+     */
+    public DTDLocation createDTD() {
+        DTDLocation dtdLocation = new DTDLocation();
+        config.dtdLocations.add(dtdLocation);
+
+        return dtdLocation;
+    }
+
+    /**
+     * Adds a fileset for support elements.
+     *
+     * @return a fileset which can be populated with support files.
+     */
+    public FileSet createSupport() {
+        FileSet supportFileSet = new FileSet();
+        config.supportFileSets.add(supportFileSet);
+        return supportFileSet;
+    }
+
+
+    /**
+     * Set the Manifest file to use when jarring. As of EJB 1.1, manifest
+     * files are no longer used to configure the EJB. However, they still
+     * have a vital importance if the EJB is intended to be packaged in an
+     * EAR file. By adding "Class-Path" settings to a Manifest file, the EJB
+     * can look for classes inside the EAR file itself, allowing for easier
+     * deployment. This is outlined in the J2EE specification, and all J2EE
+     * components are meant to support it.
+     *
+     * @param manifest the manifest to be used in the EJB jar
+     */
+     public void setManifest(File manifest) {
+         config.manifest = manifest;
+     }
+
+    /**
+     * Sets the source directory, which is the directory that
+     * contains the classes that will be added to the EJB jar. Typically
+     * this will include the home and remote interfaces and the bean class.
+     *
+     * @param inDir the source directory.
+     */
+    public void setSrcdir(File inDir) {
+        config.srcDir = inDir;
+    }
+
+    /**
+     * Set the descriptor directory. The descriptor directory contains the
+     * EJB deployment descriptors. These are XML files that declare the
+     * properties of a bean in a particular deployment scenario. Such
+     * properties include, for example, the transactional nature of the bean
+     * and the security access control to the bean's methods.
+     *
+     * @param inDir the directory containing the deployment descriptors.
+     */
+    public void setDescriptordir(File inDir) {
+        config.descriptorDir = inDir;
+    }
+
+    /**
+     * Set the analyzer to use when adding in dependencies to the JAR.
+     *
+     * @param analyzer the name of the dependency analyzer or a class.
+     */
+    public void setDependency(String analyzer) {
+        config.analyzer = analyzer;
+    }
+
+    /**
+     * Set the base name of the EJB JAR that is to be created if it is not
+     * to be determined from the name of the deployment descriptor files.
+     *
+     * @param inValue the basename that will be used when writing the jar
+     *      file containing the EJB
+     */
+    public void setBasejarname(String inValue) {
+        config.baseJarName = inValue;
+        if (config.namingScheme == null) {
+            config.namingScheme = new NamingScheme();
+            config.namingScheme.setValue(NamingScheme.BASEJARNAME);
+        } else if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)) {
+            throw new BuildException("The basejarname attribute is not "
+                + "compatible with the "
+                + config.namingScheme.getValue() + " naming scheme");
+        }
+    }
+
+    /**
+     * Set the naming scheme used to determine the name of the generated jars
+     * from the deployment descriptor
+     *
+     * @param namingScheme the naming scheme to be used
+     */
+    public void setNaming(NamingScheme namingScheme) {
+        config.namingScheme = namingScheme;
+        if (!config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
+            && config.baseJarName != null) {
+            throw new BuildException("The basejarname attribute is not "
+                + "compatible with the "
+                + config.namingScheme.getValue() + " naming scheme");
+        }
+    }
+
+    /**
+     * Gets the destination directory.
+     *
+     * @return destination directory
+     * @since ant 1.6
+     */
+    public File getDestdir() {
+        return this.destDir;
+    }
+
+    /**
+     * Set the destination directory. The EJB jar files will be written into
+     * this directory. The jar files that exist in this directory are also
+     * used when determining if the contents of the jar file have changed.
+     * Note that this parameter is only used if no deployment tools are
+     * specified. Typically each deployment tool will specify its own
+     * destination directory.
+     *
+     * @param inDir the destination directory in which to generate jars
+     */
+    public void setDestdir(File inDir) {
+        this.destDir = inDir;
+    }
+
+    /**
+     * Gets the CMP version.
+     *
+     * @return CMP version
+     * @since ant 1.6
+     */
+    public String getCmpversion() {
+        return this.cmpVersion;
+    }
+
+    /**
+     * Sets the CMP version.
+     *
+     * @param version CMP version.
+     * Must be either <code>1.0</code> or <code>2.0</code>.<br/>
+     * Default is <code>1.0</code>.<br/>
+     * Initially, only the JBoss implementation does something specific for CMP 2.0.<br/>
+     * @since ant 1.6
+     */
+    public void setCmpversion(CMPVersion version) {
+        this.cmpVersion = version.getValue();
+    }
+
+    /**
+     * Set the classpath to use when resolving classes for inclusion in the jar.
+     *
+     * @param classpath the classpath to use.
+     */
+    public void setClasspath(Path classpath) {
+        config.classpath = classpath;
+    }
+
+    /**
+     * Controls whether the
+     * destination JARs are written out in the destination directory with
+     * the same hierarchical structure from which the deployment descriptors
+     * have been read. If this is set to true the generated EJB jars are
+     * written into the root of the destination directory, otherwise they
+     * are written out in the same relative position as the deployment
+     * descriptors in the descriptor directory.
+     *
+     * @param inValue the new value of the flatdestdir flag.
+     */
+    public void setFlatdestdir(boolean inValue) {
+        config.flatDestDir = inValue;
+    }
+
+    /**
+     * Set the suffix for the generated jar file. When generic jars are
+     * generated, they have a suffix which is appended to the the bean name
+     * to create the name of the jar file. Note that this suffix includes
+     * the extension fo te jar file and should therefore end with an
+     * appropriate extension such as .jar or .ear
+     *
+     * @param inString the string to use as the suffix.
+     */
+    public void setGenericjarsuffix(String inString) {
+        this.genericJarSuffix = inString;
+    }
+
+    /**
+     * The string which terminates the bean name.
+     * The convention used by this task is
+     * that bean descriptors are named as the BeanName with some suffix. The
+     * baseNameTerminator string separates the bean name and the suffix and
+     * is used to determine the bean name.
+     *
+     * @param inValue a string which marks the end of the basename.
+     */
+    public void setBasenameterminator(String inValue) {
+        config.baseNameTerminator = inValue;
+    }
+
+    /**
+     * Validate the config that has been configured from the build file
+     *
+     * @throws BuildException if the config is not valid
+     */
+    private void validateConfig() throws BuildException {
+        if (config.srcDir == null) {
+            throw new BuildException("The srcDir attribute must be specified");
+        }
+
+        if (config.descriptorDir == null) {
+            config.descriptorDir = config.srcDir;
+        }
+
+        if (config.namingScheme == null) {
+            config.namingScheme = new NamingScheme();
+            config.namingScheme.setValue(NamingScheme.DESCRIPTOR);
+        } else if (config.namingScheme.getValue().equals(NamingScheme.BASEJARNAME)
+                    && config.baseJarName == null) {
+            throw new BuildException("The basejarname attribute must "
+                + "be specified with the basejarname naming scheme");
+        }
+    }
+
+    /**
+     * Invoked by Ant after the task is prepared, when it is ready to execute
+     * this task.
+     *
+     * This will configure all of the nested deployment tools to allow them to
+     * process the jar. If no deployment tools have been configured a generic
+     * tool is created to handle the jar.
+     *
+     * A parser is configured and then each descriptor found is passed to all
+     * the deployment tool elements for processing.
+     *
+     * @exception BuildException thrown whenever a problem is
+     *            encountered that cannot be recovered from, to signal to ant
+     *            that a major problem occurred within this task.
+     */
+    public void execute() throws BuildException {
+        validateConfig();
+
+        if (deploymentTools.size() == 0) {
+            GenericDeploymentTool genericTool = new GenericDeploymentTool();
+            genericTool.setTask(this);
+            genericTool.setDestdir(destDir);
+            genericTool.setGenericJarSuffix(genericJarSuffix);
+            deploymentTools.add(genericTool);
+        }
+
+        for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
+            EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
+            tool.configure(config);
+            tool.validateConfigured();
+        }
+
+        try {
+            // Create the parser using whatever parser the system dictates
+            SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+            saxParserFactory.setValidating(true);
+            SAXParser saxParser = saxParserFactory.newSAXParser();
+
+
+            DirectoryScanner ds = getDirectoryScanner(config.descriptorDir);
+            ds.scan();
+            String[] files = ds.getIncludedFiles();
+
+            log(files.length + " deployment descriptors located.",
+                Project.MSG_VERBOSE);
+
+            // Loop through the files. Each file represents one deployment
+            // descriptor, and hence one bean in our model.
+            for (int index = 0; index < files.length; ++index) {
+                // process the deployment descriptor in each tool
+                for (Iterator i = deploymentTools.iterator(); i.hasNext();) {
+                    EJBDeploymentTool tool = (EJBDeploymentTool) i.next();
+                    tool.processDescriptor(files[index], saxParser);
+                }
+            }
+        } catch (SAXException se) {
+            String msg = "SAXException while creating parser."
+                + "  Details: "
+                + se.getMessage();
+            throw new BuildException(msg, se);
+        } catch (ParserConfigurationException pce) {
+            String msg = "ParserConfigurationException while creating parser. "
+                       + "Details: " + pce.getMessage();
+            throw new BuildException(msg, pce);
+        }
+    } // end of execute()
+
+}
+
+
+
+
+
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
new file mode 100644
index 0000000..ec2006c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/GenericDeploymentTool.java
@@ -0,0 +1,952 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import javax.xml.parsers.SAXParser;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+
+/**
+ * A deployment tool which creates generic EJB jars. Generic jars contains
+ * only those classes and META-INF entries specified in the EJB 1.1 standard
+ *
+ * This class is also used as a framework for the creation of vendor specific
+ * deployment tools. A number of template methods are provided through which the
+ * vendor specific tool can hook into the EJB creation process.
+ *
+ */
+public class GenericDeploymentTool implements EJBDeploymentTool {
+    /** The default buffer byte size to use for IO */
+    public static final int DEFAULT_BUFFER_SIZE = 1024;
+    /** The level to use for compression */
+    public static final int JAR_COMPRESS_LEVEL  = 9;
+
+    /** The standard META-INF directory in jar files */
+    protected static final String META_DIR  = "META-INF/";
+
+    /** The standard MANIFEST file */
+    protected static final String MANIFEST  = META_DIR + "MANIFEST.MF";
+
+    /** Name for EJB Deployment descriptor within EJB jars */
+    protected static final String EJB_DD    = "ejb-jar.xml";
+
+    /** A dependency analyzer name to find ancestor classes */
+    public static final String ANALYZER_SUPER = "super";
+    /** A dependency analyzer name to find all related classes */
+    public static final String ANALYZER_FULL = "full";
+    /** A dependency analyzer name for no analyzer */
+    public static final String ANALYZER_NONE = "none";
+
+    /** The default analyzer */
+    public static final String DEFAULT_ANALYZER = ANALYZER_SUPER;
+
+    /** The analyzer class for the super analyzer */
+    public static final String ANALYZER_CLASS_SUPER
+        = "org.apache.tools.ant.util.depend.bcel.AncestorAnalyzer";
+    /** The analyzer class for the super analyzer */
+    public static final String ANALYZER_CLASS_FULL
+        = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
+
+    /**
+     * The configuration from the containing task. This config combined
+     * with the settings of the individual attributes here constitues the
+     * complete config for this deployment tool.
+     */
+    private EjbJar.Config config;
+
+    /** Stores a handle to the directory to put the Jar files in */
+    private File destDir;
+
+    /** The classpath to use with this deployment tool. This is appended to
+        any paths from the ejbjar task itself.*/
+    private Path classpath;
+
+    /** Instance variable that stores the suffix for the generated jarfile. */
+    private String genericJarSuffix = "-generic.jar";
+
+    /**
+     * The task to which this tool belongs. This is used to access services
+     * provided by the ant core, such as logging.
+     */
+    private Task task;
+
+    /**
+     * The classloader generated from the given classpath to load
+     * the super classes and super interfaces.
+     */
+    private ClassLoader classpathLoader = null;
+
+     /**
+     * Set of files have been loaded into the EJB jar
+     */
+    private Set addedfiles;
+
+    /**
+     * Handler used to parse the EJB XML descriptor
+     */
+    private DescriptorHandler handler;
+
+    /**
+     * Dependency analyzer used to collect class dependencies
+     */
+    private DependencyAnalyzer dependencyAnalyzer;
+
+    /** No arg constructor */
+    public GenericDeploymentTool() {
+    }
+
+
+    /**
+     * Set the destination directory; required.
+     * @param inDir the destination directory.
+     */
+    public void setDestdir(File inDir) {
+        this.destDir = inDir;
+    }
+
+    /**
+     * Get the destination directory.
+     *
+     * @return the destination directory into which EJB jars are to be written
+     */
+    protected File getDestDir() {
+        return destDir;
+    }
+
+
+    /**
+     * Set the task which owns this tool
+     *
+     * @param task the Task to which this deployment tool is associated.
+     */
+    public void setTask(Task task) {
+        this.task = task;
+    }
+
+    /**
+     * Get the task for this tool.
+     *
+     * @return the Task instance this tool is associated with.
+     */
+    protected Task getTask() {
+        return task;
+    }
+
+    /**
+     * Get the basename terminator.
+     *
+     * @return an ejbjar task configuration
+     */
+    protected EjbJar.Config getConfig() {
+        return config;
+    }
+
+    /**
+     * Indicate if this build is using the base jar name.
+     *
+     * @return true if the name of the generated jar is coming from the
+     *              basejarname attribute
+     */
+    protected boolean usingBaseJarName() {
+        return config.baseJarName != null;
+    }
+
+    /**
+     * Set the suffix for the generated jar file.
+     * @param inString the string to use as the suffix.
+     */
+    public void setGenericJarSuffix(String inString) {
+        this.genericJarSuffix = inString;
+    }
+
+    /**
+     * Add the classpath for the user classes
+     *
+     * @return a Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(task.getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     *
+     * @param classpath the classpath to be used for this build.
+     */
+    public void setClasspath(Path classpath) {
+        this.classpath = classpath;
+    }
+
+    /**
+     * Get the classpath by combining the one from the surrounding task, if any
+     * and the one from this tool.
+     *
+     * @return the combined classpath
+     */
+    protected Path getCombinedClasspath() {
+        Path combinedPath = classpath;
+        if (config.classpath != null) {
+            if (combinedPath == null) {
+                combinedPath = config.classpath;
+            } else {
+                combinedPath.append(config.classpath);
+            }
+        }
+
+        return combinedPath;
+    }
+
+    /**
+     * Log a message to the Ant output.
+     *
+     * @param message the message to be logged.
+     * @param level the severity of this message.
+     */
+    protected void log(String message, int level) {
+        getTask().log(message, level);
+    }
+
+    /**
+     * Get the build file location associated with this element's task.
+     *
+     * @return the task's location instance.
+     */
+    protected Location getLocation() {
+        return getTask().getLocation();
+    }
+
+    private void createAnalyzer() {
+        String analyzer = config.analyzer;
+        if (analyzer == null) {
+            analyzer = DEFAULT_ANALYZER;
+        }
+
+        if (analyzer.equals(ANALYZER_NONE)) {
+            return;
+        }
+
+        String analyzerClassName = null;
+        if (analyzer.equals(ANALYZER_SUPER)) {
+            analyzerClassName = ANALYZER_CLASS_SUPER;
+        } else if (analyzer.equals(ANALYZER_FULL)) {
+            analyzerClassName = ANALYZER_CLASS_FULL;
+        } else {
+            analyzerClassName = analyzer;
+        }
+
+        try {
+            Class analyzerClass = Class.forName(analyzerClassName);
+            dependencyAnalyzer
+                = (DependencyAnalyzer) analyzerClass.newInstance();
+            dependencyAnalyzer.addClassPath(new Path(task.getProject(),
+                config.srcDir.getPath()));
+            dependencyAnalyzer.addClassPath(config.classpath);
+        } catch (NoClassDefFoundError e) {
+            dependencyAnalyzer = null;
+            task.log("Unable to load dependency analyzer: " + analyzerClassName
+                + " - dependent class not found: " + e.getMessage(),
+                Project.MSG_WARN);
+        } catch (Exception e) {
+            dependencyAnalyzer = null;
+            task.log("Unable to load dependency analyzer: " + analyzerClassName
+                     + " - exception: " + e.getMessage(),
+                Project.MSG_WARN);
+        }
+    }
+
+
+    /**
+     * Configure this tool for use in the ejbjar task.
+     *
+     * @param config the configuration from the surrounding ejbjar task.
+     */
+    public void configure(EjbJar.Config config) {
+        this.config = config;
+
+        createAnalyzer();
+        classpathLoader = null;
+    }
+
+    /**
+     * Utility method that encapsulates the logic of adding a file entry to
+     * a .jar file.  Used by execute() to add entries to the jar file as it is
+     * constructed.
+     * @param jStream A JarOutputStream into which to write the
+     *        jar entry.
+     * @param inputFile A File from which to read the
+     *        contents the file being added.
+     * @param logicalFilename A String representing the name, including
+     *        all relevant path information, that should be stored for the entry
+     *        being added.
+     * @throws BuildException if there is a problem.
+     */
+    protected void addFileToJar(JarOutputStream jStream,
+                                File inputFile,
+                                String logicalFilename)
+        throws BuildException {
+        FileInputStream iStream = null;
+        try {
+            if (!addedfiles.contains(logicalFilename)) {
+                iStream = new FileInputStream(inputFile);
+                // Create the zip entry and add it to the jar file
+                ZipEntry zipEntry = new ZipEntry(logicalFilename.replace('\\', '/'));
+                jStream.putNextEntry(zipEntry);
+
+                // Create the file input stream, and buffer everything over
+                // to the jar output stream
+                byte[] byteBuffer = new byte[2 * DEFAULT_BUFFER_SIZE];
+                int count = 0;
+                do {
+                    jStream.write(byteBuffer, 0, count);
+                    count = iStream.read(byteBuffer, 0, byteBuffer.length);
+                } while (count != -1);
+
+                //add it to list of files in jar
+                addedfiles.add(logicalFilename);
+           }
+        } catch (IOException ioe) {
+            log("WARNING: IOException while adding entry "
+                + logicalFilename + " to jarfile from "
+                + inputFile.getPath() + " "  + ioe.getClass().getName()
+                + "-" + ioe.getMessage(), Project.MSG_WARN);
+        } finally {
+            // Close up the file input stream for the class file
+            if (iStream != null) {
+                try {
+                    iStream.close();
+                } catch (IOException closeException) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Get a descriptionHandler.
+     * @param srcDir the source directory.
+     * @return a handler.
+     */
+    protected DescriptorHandler getDescriptorHandler(File srcDir) {
+        DescriptorHandler h = new DescriptorHandler(getTask(), srcDir);
+
+        registerKnownDTDs(h);
+
+        // register any DTDs supplied by the user
+        for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+            EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+            h.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+        }
+        return h;
+    }
+
+    /**
+     * Register the locations of all known DTDs.
+     *
+     * vendor-specific subclasses should override this method to define
+     * the vendor-specific locations of the EJB DTDs
+     * @param handler no used in this class.
+     */
+    protected void registerKnownDTDs(DescriptorHandler handler) {
+        // none to register for generic
+    }
+
+    /** {@inheritDoc}. */
+    public void processDescriptor(String descriptorFileName, SAXParser saxParser) {
+
+        checkConfiguration(descriptorFileName, saxParser);
+
+        try {
+            handler = getDescriptorHandler(config.srcDir);
+
+            // Retrive the files to be added to JAR from EJB descriptor
+            Hashtable ejbFiles = parseEjbFiles(descriptorFileName, saxParser);
+
+            // Add any support classes specified in the build file
+            addSupportClasses(ejbFiles);
+
+            // Determine the JAR filename (without filename extension)
+            String baseName = getJarBaseName(descriptorFileName);
+
+            String ddPrefix = getVendorDDPrefix(baseName, descriptorFileName);
+
+            File manifestFile = getManifestFile(ddPrefix);
+            if (manifestFile != null) {
+                ejbFiles.put(MANIFEST, manifestFile);
+            }
+
+
+
+            // First the regular deployment descriptor
+            ejbFiles.put(META_DIR + EJB_DD,
+                         new File(config.descriptorDir, descriptorFileName));
+
+            // now the vendor specific files, if any
+            addVendorFiles(ejbFiles, ddPrefix);
+
+            // add any dependent files
+            checkAndAddDependants(ejbFiles);
+
+            // Lastly create File object for the Jar files. If we are using
+            // a flat destination dir, then we need to redefine baseName!
+            if (config.flatDestDir && baseName.length() != 0) {
+                int startName = baseName.lastIndexOf(File.separator);
+                if (startName == -1) {
+                    startName = 0;
+                }
+
+                int endName   = baseName.length();
+                baseName = baseName.substring(startName, endName);
+            }
+
+            File jarFile = getVendorOutputJarFile(baseName);
+
+
+            // Check to see if we need a build and start doing the work!
+            if (needToRebuild(ejbFiles, jarFile)) {
+                // Log that we are going to build...
+                log("building "
+                              + jarFile.getName()
+                              + " with "
+                              + String.valueOf(ejbFiles.size())
+                              + " files",
+                              Project.MSG_INFO);
+
+                // Use helper method to write the jarfile
+                String publicId = getPublicId();
+                writeJar(baseName, jarFile, ejbFiles, publicId);
+
+            } else {
+                // Log that the file is up to date...
+                log(jarFile.toString() + " is up to date.",
+                              Project.MSG_VERBOSE);
+            }
+
+        } catch (SAXException se) {
+            String msg = "SAXException while parsing '"
+                + descriptorFileName
+                + "'. This probably indicates badly-formed XML."
+                + "  Details: "
+                + se.getMessage();
+            throw new BuildException(msg, se);
+        } catch (IOException ioe) {
+            String msg = "IOException while parsing'"
+                + descriptorFileName
+                + "'.  This probably indicates that the descriptor"
+                + " doesn't exist. Details: "
+                + ioe.getMessage();
+            throw new BuildException(msg, ioe);
+        }
+    }
+
+    /**
+     * This method is called as the first step in the processDescriptor method
+     * to allow vendor-specific subclasses to validate the task configuration
+     * prior to processing the descriptor.  If the configuration is invalid,
+     * a BuildException should be thrown.
+     *
+     * @param descriptorFileName String representing the file name of an EJB
+     *                           descriptor to be processed
+     * @param saxParser          SAXParser which may be used to parse the XML
+     *                           descriptor
+     * @throws BuildException if there is a problem.
+     */
+    protected void checkConfiguration(String descriptorFileName,
+                                    SAXParser saxParser) throws BuildException {
+
+        /*
+         * For the GenericDeploymentTool, do nothing.  Vendor specific
+         * subclasses should throw a BuildException if the configuration is
+         * invalid for their server.
+         */
+    }
+
+    /**
+     * This method returns a list of EJB files found when the specified EJB
+     * descriptor is parsed and processed.
+     *
+     * @param descriptorFileName String representing the file name of an EJB
+     *                           descriptor to be processed
+     * @param saxParser          SAXParser which may be used to parse the XML
+     *                           descriptor
+     * @return                   Hashtable of EJB class (and other) files to be
+     *                           added to the completed JAR file
+     * @throws SAXException      Any SAX exception, possibly wrapping another
+     *                           exception
+     * @throws IOException       An IOException from the parser, possibly from a
+     *                           the byte stream or character stream
+     */
+    protected Hashtable parseEjbFiles(String descriptorFileName, SAXParser saxParser)
+                            throws IOException, SAXException {
+        FileInputStream descriptorStream = null;
+        Hashtable ejbFiles = null;
+
+        try {
+
+            /* Parse the ejb deployment descriptor.  While it may not
+             * look like much, we use a SAXParser and an inner class to
+             * get hold of all the classfile names for the descriptor.
+             */
+            descriptorStream
+                = new FileInputStream(new File(config.descriptorDir, descriptorFileName));
+            saxParser.parse(new InputSource(descriptorStream), handler);
+
+            ejbFiles = handler.getFiles();
+
+        } finally {
+            if (descriptorStream != null) {
+                try {
+                    descriptorStream.close();
+                } catch (IOException closeException) {
+                    // ignore
+                }
+            }
+        }
+
+        return ejbFiles;
+    }
+
+    /**
+     * Adds any classes the user specifies using <i>support</i> nested elements
+     * to the <code>ejbFiles</code> Hashtable.
+     *
+     * @param ejbFiles Hashtable of EJB classes (and other) files that will be
+     *                 added to the completed JAR file
+     */
+    protected void addSupportClasses(Hashtable ejbFiles) {
+        // add in support classes if any
+        Project project = task.getProject();
+        for (Iterator i = config.supportFileSets.iterator(); i.hasNext();) {
+            FileSet supportFileSet = (FileSet) i.next();
+            File supportBaseDir = supportFileSet.getDir(project);
+            DirectoryScanner supportScanner = supportFileSet.getDirectoryScanner(project);
+            supportScanner.scan();
+            String[] supportFiles = supportScanner.getIncludedFiles();
+            for (int j = 0; j < supportFiles.length; ++j) {
+                ejbFiles.put(supportFiles[j], new File(supportBaseDir, supportFiles[j]));
+            }
+        }
+    }
+
+
+    /**
+     * Using the EJB descriptor file name passed from the <code>ejbjar</code>
+     * task, this method returns the "basename" which will be used to name the
+     * completed JAR file.
+     *
+     * @param descriptorFileName String representing the file name of an EJB
+     *                           descriptor to be processed
+     * @return                   The "basename" which will be used to name the
+     *                           completed JAR file
+     */
+    protected String getJarBaseName(String descriptorFileName) {
+
+        String baseName = "";
+
+        // Work out what the base name is
+        if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)) {
+            String canonicalDescriptor = descriptorFileName.replace('\\', '/');
+            int index = canonicalDescriptor.lastIndexOf('/');
+            if (index != -1) {
+                baseName = descriptorFileName.substring(0, index + 1);
+            }
+            baseName += config.baseJarName;
+        } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+            int lastSeparatorIndex = descriptorFileName.lastIndexOf(File.separator);
+            int endBaseName = -1;
+            if (lastSeparatorIndex != -1) {
+                endBaseName = descriptorFileName.indexOf(config.baseNameTerminator,
+                                                            lastSeparatorIndex);
+            } else {
+                endBaseName = descriptorFileName.indexOf(config.baseNameTerminator);
+            }
+
+            if (endBaseName != -1) {
+                baseName = descriptorFileName.substring(0, endBaseName);
+            } else {
+                throw new BuildException("Unable to determine jar name "
+                    + "from descriptor \"" + descriptorFileName + "\"");
+            }
+        } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
+            File descriptorFile = new File(config.descriptorDir, descriptorFileName);
+            String path = descriptorFile.getAbsolutePath();
+            int lastSeparatorIndex
+                = path.lastIndexOf(File.separator);
+            if (lastSeparatorIndex == -1) {
+                throw new BuildException("Unable to determine directory name holding descriptor");
+            }
+            String dirName = path.substring(0, lastSeparatorIndex);
+            int dirSeparatorIndex = dirName.lastIndexOf(File.separator);
+            if (dirSeparatorIndex != -1) {
+                dirName = dirName.substring(dirSeparatorIndex + 1);
+            }
+
+            baseName = dirName;
+        } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)) {
+            baseName = handler.getEjbName();
+        }
+        return baseName;
+    }
+
+    /**
+     * Get the prefix for vendor deployment descriptors.
+     *
+     * This will contain the path and the start of the descriptor name,
+     * depending on the naming scheme
+     * @param baseName the base name to use.
+     * @param descriptorFileName the file name to use.
+     * @return the prefix.
+     */
+    public String getVendorDDPrefix(String baseName, String descriptorFileName) {
+        String ddPrefix = null;
+
+        if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+            ddPrefix = baseName + config.baseNameTerminator;
+        } else if (config.namingScheme.getValue().equals(EjbJar.NamingScheme.BASEJARNAME)
+            || config.namingScheme.getValue().equals(EjbJar.NamingScheme.EJB_NAME)
+            || config.namingScheme.getValue().equals(EjbJar.NamingScheme.DIRECTORY)) {
+            String canonicalDescriptor = descriptorFileName.replace('\\', '/');
+            int index = canonicalDescriptor.lastIndexOf('/');
+            if (index == -1) {
+                ddPrefix = "";
+            } else {
+                ddPrefix = descriptorFileName.substring(0, index + 1);
+            }
+        }
+        return ddPrefix;
+    }
+
+    /**
+     * Add any vendor specific files which should be included in the
+     * EJB Jar.
+     * @param ejbFiles a hashtable entryname -> file.
+     * @param ddPrefix a prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+        // nothing to add for generic tool.
+    }
+
+
+    /**
+     * Get the vendor specific name of the Jar that will be output. The modification date
+     * of this jar will be checked against the dependent bean classes.
+     * @param baseName the basename to use.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        return new File(destDir, baseName + genericJarSuffix);
+    }
+
+    /**
+     * This method checks the timestamp on each file listed in the <code>
+     * ejbFiles</code> and compares them to the timestamp on the <code>jarFile
+     * </code>.  If the <code>jarFile</code>'s timestamp is more recent than
+     * each EJB file, <code>true</code> is returned.  Otherwise, <code>false
+     * </code> is returned.
+     * TODO: find a way to check the manifest-file, that is found by naming convention
+     *
+     * @param ejbFiles Hashtable of EJB classes (and other) files that will be
+     *                 added to the completed JAR file
+     * @param jarFile  JAR file which will contain all of the EJB classes (and
+     *                 other) files
+     * @return         boolean indicating whether or not the <code>jarFile</code>
+     *                 is up to date
+     */
+    protected boolean needToRebuild(Hashtable ejbFiles, File jarFile) {
+        if (jarFile.exists()) {
+            long lastBuild = jarFile.lastModified();
+
+            Iterator fileIter = ejbFiles.values().iterator();
+
+            // Loop through the files seeing if any has been touched
+            // more recently than the destination jar.
+            while (fileIter.hasNext()) {
+                File currentFile = (File) fileIter.next();
+                if (lastBuild < currentFile.lastModified()) {
+                    log("Build needed because " + currentFile.getPath() + " is out of date",
+                        Project.MSG_VERBOSE);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the Public ID of the DTD specified in the EJB descriptor.  Not
+     * every vendor-specific <code>DeploymentTool</code> will need to reference
+     * this value or may want to determine this value in a vendor-specific way.
+     *
+     * @return Public ID of the DTD specified in the EJB descriptor.
+     */
+    protected String getPublicId() {
+        return handler.getPublicId();
+    }
+
+    /**
+     * Get the manifets file to use for building the generic jar.
+     *
+     * If the file does not exist the global manifest from the config is used
+     * otherwise the default Ant manifest will be used.
+     *
+     * @param prefix the prefix where to llook for the manifest file based on
+     *        the naming convention.
+     *
+     * @return the manifest file or null if the manifest file does not exist
+     */
+    protected File getManifestFile(String prefix) {
+        File manifestFile
+            = new File(getConfig().descriptorDir, prefix + "manifest.mf");
+        if (manifestFile.exists()) {
+            return manifestFile;
+        }
+
+        if (config.manifest != null) {
+            return config.manifest;
+        }
+        return null;
+    }
+
+    /**
+     * Method used to encapsulate the writing of the JAR file. Iterates over the
+     * filenames/java.io.Files in the Hashtable stored on the instance variable
+     * ejbFiles.
+     * @param baseName the base name to use.
+     * @param jarfile  the jar file to write to.
+     * @param files    the files to write to the jar.
+     * @param publicId the id to use.
+     * @throws BuildException if there is a problem.
+     */
+    protected void writeJar(String baseName, File jarfile, Hashtable files,
+                            String publicId) throws BuildException {
+
+        JarOutputStream jarStream = null;
+        try {
+            // clean the addedfiles set
+            if (addedfiles == null) {
+                addedfiles = new HashSet();
+            } else {
+                addedfiles.clear();
+            }
+
+            /* If the jarfile already exists then whack it and recreate it.
+             * Should probably think of a more elegant way to handle this
+             * so that in case of errors we don't leave people worse off
+             * than when we started =)
+             */
+            if (jarfile.exists()) {
+                jarfile.delete();
+            }
+            jarfile.getParentFile().mkdirs();
+            jarfile.createNewFile();
+
+            InputStream in = null;
+            Manifest manifest = null;
+            try {
+                File manifestFile = (File) files.get(MANIFEST);
+                if (manifestFile != null && manifestFile.exists()) {
+                    in = new FileInputStream(manifestFile);
+                } else {
+                    String defaultManifest = "/org/apache/tools/ant/defaultManifest.mf";
+                    in = this.getClass().getResourceAsStream(defaultManifest);
+                    if (in == null) {
+                        throw new BuildException("Could not find "
+                            + "default manifest: " + defaultManifest);
+                    }
+                }
+
+                manifest = new Manifest(in);
+            } catch (IOException e) {
+                throw new BuildException ("Unable to read manifest", e, getLocation());
+            } finally {
+                if (in != null) {
+                    in.close();
+                }
+            }
+
+            // Create the streams necessary to write the jarfile
+
+            jarStream = new JarOutputStream(new FileOutputStream(jarfile), manifest);
+            jarStream.setMethod(JarOutputStream.DEFLATED);
+
+            // Loop through all the class files found and add them to the jar
+            for (Iterator entryIterator = files.keySet().iterator(); entryIterator.hasNext();) {
+                String entryName = (String) entryIterator.next();
+                if (entryName.equals(MANIFEST)) {
+                    continue;
+                }
+
+                File entryFile = (File) files.get(entryName);
+
+                log("adding file '" + entryName + "'",
+                              Project.MSG_VERBOSE);
+
+                addFileToJar(jarStream, entryFile, entryName);
+
+                // See if there are any inner classes for this class and add them in if there are
+                InnerClassFilenameFilter flt = new InnerClassFilenameFilter(entryFile.getName());
+                File entryDir = entryFile.getParentFile();
+                String[] innerfiles = entryDir.list(flt);
+                if (innerfiles != null) {
+                    for (int i = 0, n = innerfiles.length; i < n; i++) {
+
+                        //get and clean up innerclass name
+                        int entryIndex = entryName.lastIndexOf(entryFile.getName()) - 1;
+                        if (entryIndex < 0) {
+                            entryName = innerfiles[i];
+                        } else {
+                            entryName = entryName.substring(0, entryIndex)
+                                + File.separatorChar + innerfiles[i];
+                        }
+                        // link the file
+                        entryFile = new File(config.srcDir, entryName);
+
+                        log("adding innerclass file '" + entryName + "'",
+                                Project.MSG_VERBOSE);
+
+                        addFileToJar(jarStream, entryFile, entryName);
+
+                    }
+                }
+            }
+        } catch (IOException ioe) {
+            String msg = "IOException while processing ejb-jar file '"
+                + jarfile.toString()
+                + "'. Details: "
+                + ioe.getMessage();
+            throw new BuildException(msg, ioe);
+        } finally {
+            if (jarStream != null) {
+                try {
+                    jarStream.close();
+                } catch (IOException closeException) {
+                    // ignore
+                }
+            }
+        }
+    } // end of writeJar
+
+
+    /**
+     * Add all available classes, that depend on Remote, Home, Bean, PK
+     * @param checkEntries files, that are extracted from the deployment descriptor
+     * @throws BuildException if there is a problem.
+     */
+    protected void checkAndAddDependants(Hashtable checkEntries)
+        throws BuildException {
+
+        if (dependencyAnalyzer == null) {
+            return;
+        }
+
+        dependencyAnalyzer.reset();
+
+        Iterator i = checkEntries.keySet().iterator();
+        while (i.hasNext()) {
+            String entryName = (String) i.next();
+            if (entryName.endsWith(".class")) {
+                String className = entryName.substring(0,
+                    entryName.length() - ".class".length());
+                className = className.replace(File.separatorChar, '/');
+                className = className.replace('/', '.');
+
+                dependencyAnalyzer.addRootClass(className);
+            }
+        }
+
+        Enumeration e = dependencyAnalyzer.getClassDependencies();
+
+        while (e.hasMoreElements()) {
+            String classname = (String) e.nextElement();
+            String location
+                = classname.replace('.', File.separatorChar) + ".class";
+            File classFile = new File(config.srcDir, location);
+            if (classFile.exists()) {
+                checkEntries.put(location, classFile);
+                log("dependent class: " + classname + " - " + classFile,
+                    Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+
+    /**
+     * Returns a Classloader object which parses the passed in generic EjbJar classpath.
+     * The loader is used to dynamically load classes from javax.ejb.* and the classes
+     * being added to the jar.
+     * @return a classloader.
+     */
+    protected ClassLoader getClassLoaderForBuild() {
+        if (classpathLoader != null) {
+            return classpathLoader;
+        }
+
+        Path combinedClasspath = getCombinedClasspath();
+
+        // only generate a new ClassLoader if we have a classpath
+        if (combinedClasspath == null) {
+            classpathLoader = getClass().getClassLoader();
+        } else {
+            classpathLoader
+                = getTask().getProject().createClassLoader(combinedClasspath);
+        }
+
+        return classpathLoader;
+    }
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     *
+     * @throws BuildException If the Deployment Tool's configuration isn't
+     *                        valid
+     */
+    public void validateConfigured() throws BuildException {
+        if ((destDir == null) || (!destDir.isDirectory())) {
+            String msg = "A valid destination directory must be specified "
+                            + "using the \"destdir\" attribute.";
+            throw new BuildException(msg, getLocation());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java
new file mode 100644
index 0000000..c64ca0e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetDeploymentTool.java
@@ -0,0 +1,384 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Hashtable;
+import javax.xml.parsers.SAXParser;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.xml.sax.SAXException;
+
+/**
+ * This class is used to generate iPlanet Application Server (iAS) 6.0 stubs and
+ * skeletons and build an EJB Jar file.  It is designed to be used with the Ant
+ * <code>ejbjar</code> task.  If only stubs and skeletons need to be generated
+ * (in other words, if no JAR file needs to be created), refer to the
+ * <code>iplanet-ejbc</code> task and the <code>IPlanetEjbcTask</code> class.
+ * <p>
+ * The following attributes may be specified by the user:
+ *   <ul>
+ *     <li><i>destdir</i> -- The base directory into which the generated JAR
+ *                           files will be written.  Each JAR file is written
+ *                           in directories which correspond to their location
+ *                           within the "descriptordir" namespace.  This is a
+ *                           required attribute.
+ *     <li><i>classpath</i> -- The classpath used when generating EJB stubs and
+ *                             skeletons.  This is an optional attribute (if
+ *                             omitted, the classpath specified in the "ejbjar"
+ *                             parent task will be used).  If specified, the
+ *                             classpath elements will be prepended to the
+ *                             classpath specified in the parent "ejbjar" task.
+ *                             Note that nested "classpath" elements may also be
+ *                             used.
+ *     <li><i>keepgenerated</i> -- Indicates whether or not the Java source
+ *                                 files which are generated by ejbc will be
+ *                                 saved or automatically deleted.  If "yes",
+ *                                 the source files will be retained.  This is
+ *                                 an optional attribute (if omitted, it
+ *                                 defaults to "no").
+ *     <li><i>debug</i> -- Indicates whether or not the ejbc utility should
+ *                         log additional debugging statements to the standard
+ *                         output.  If "yes", the additional debugging statements
+ *                         will be generated (if omitted, it defaults to "no").
+ *     <li><i>iashome</i> -- May be used to specify the "home" directory for
+ *                           this iPlanet Application server installation.  This
+ *                           is used to find the ejbc utility if it isn't
+ *                           included in the user's system path.  This is an
+ *                           optional attribute (if specified, it should refer
+ *                           to the <code>[install-location]/iplanet/ias6/ias
+ *                           </code> directory).  If omitted, the ejbc utility
+ *                           must be on the user's system path.
+ *     <li><i>suffix</i> -- String value appended to the JAR filename when
+ *                          creating each JAR.  This attribute is not required
+ *                          (if omitted, it defaults to ".jar").
+ *   </ul>
+ * <p>
+ * For each EJB descriptor found in the "ejbjar" parent task, this deployment
+ * tool will locate the three classes that comprise the EJB.  If these class
+ * files cannot be located in the specified <code>srcdir</code> directory, the
+ * task will fail.  The task will also attempt to locate the EJB stubs and
+ * skeletons in this directory.  If found, the timestamps on the stubs and
+ * skeletons will be checked to ensure they are up to date.  Only if these files
+ * cannot be found or if they are out of date will ejbc be called.
+ *
+ * @see    IPlanetEjbc
+ */
+public class IPlanetDeploymentTool extends GenericDeploymentTool {
+
+    /* Attributes set by the Ant build file */
+    private File    iashome;
+    private String  jarSuffix     = ".jar";
+    private boolean keepgenerated = false;
+    private boolean debug         = false;
+
+    /*
+     * Filenames of the standard EJB descriptor (which is passed to this class
+     * from the parent "ejbjar" task) and the iAS-specific EJB descriptor
+     * (whose name is determined by this class).  Both filenames are relative
+     * to the directory specified by the "srcdir" attribute in the ejbjar task.
+     */
+    private String  descriptorName;
+    private String  iasDescriptorName;
+
+    /*
+     * The displayName variable stores the value of the "display-name" element
+     * from the standard EJB descriptor.  As a future enhancement to this task,
+     * we may determine the name of the EJB JAR file using this display-name,
+     * but this has not be implemented yet.
+     */
+    private String  displayName;
+
+    /*
+     * Regardless of the name of the iAS-specific EJB descriptor file, it will
+     * written in the completed JAR file as "ias-ejb-jar.xml".  This is the
+     * naming convention implemented by iAS.
+     */
+    private static final String IAS_DD = "ias-ejb-jar.xml";
+
+    /**
+     * Setter method used to store the "home" directory of the user's iAS
+     * installation.  The directory specified should typically be
+     * <code>[install-location]/iplanet/ias6/ias</code>.
+     *
+     * @param iashome The home directory for the user's iAS installation.
+     */
+    public void setIashome(File iashome) {
+        this.iashome = iashome;
+    }
+
+    /**
+     * Setter method used to specify whether the Java source files generated by
+     * the ejbc utility should be saved or automatically deleted.
+     *
+     * @param keepgenerated boolean which, if <code>true</code>, indicates that
+     *                      Java source files generated by ejbc for the stubs
+     *                      and skeletons should be kept.
+     */
+    public void setKeepgenerated(boolean keepgenerated) {
+        this.keepgenerated = keepgenerated;
+    }
+
+    /**
+     * Sets whether or not debugging output will be generated when ejbc is
+     * executed.
+     *
+     * @param debug A boolean indicating if debugging output should be generated
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Setter method used to specify the filename suffix (for example, ".jar")
+     * for the JAR files to be created.
+     *
+     * @param jarSuffix The string to use as the JAR filename suffix.
+     */
+    public void setSuffix(String jarSuffix) {
+        this.jarSuffix = jarSuffix;
+    }
+
+    /**
+     * Since iAS doesn't generate a "generic" JAR as part of its processing,
+     * this attribute is ignored and a warning message is displayed to the user.
+     *
+     * @param inString the string to use as the suffix.  This parameter is
+     *                 ignored.
+     */
+    public void setGenericJarSuffix(String inString) {
+        log("Since a generic JAR file is not created during processing, the "
+                + "iPlanet Deployment Tool does not support the "
+                + "\"genericjarsuffix\" attribute.  It will be ignored.",
+            Project.MSG_WARN);
+    }
+
+    /** {@inheritDoc}. */
+    public void processDescriptor(String descriptorName, SAXParser saxParser) {
+        this.descriptorName = descriptorName;
+        this.iasDescriptorName = null;
+
+        log("iPlanet Deployment Tool processing: " + descriptorName + " (and "
+                + getIasDescriptorName() + ")", Project.MSG_VERBOSE);
+
+        super.processDescriptor(descriptorName, saxParser);
+    }
+
+    /**
+     * Verifies that the user selections are valid.
+     *
+     * @param descriptorFileName String representing the file name of an EJB
+     *                           descriptor to be processed
+     * @param saxParser          SAXParser which may be used to parse the XML
+     *                           descriptor
+     * @throws BuildException If the user selections are invalid.
+     */
+    protected void checkConfiguration(String descriptorFileName,
+                                    SAXParser saxParser) throws BuildException {
+
+        int startOfName = descriptorFileName.lastIndexOf(File.separatorChar) + 1;
+        String stdXml = descriptorFileName.substring(startOfName);
+        if (stdXml.equals(EJB_DD) && (getConfig().baseJarName == null)) {
+            String msg = "No name specified for the completed JAR file.  The EJB"
+                            + " descriptor should be prepended with the JAR "
+                            + "name or it should be specified using the "
+                            + "attribute \"basejarname\" in the \"ejbjar\" task.";
+            throw new BuildException(msg, getLocation());
+        }
+
+        File iasDescriptor = new File(getConfig().descriptorDir,
+                                        getIasDescriptorName());
+        if ((!iasDescriptor.exists()) || (!iasDescriptor.isFile())) {
+            String msg = "The iAS-specific EJB descriptor ("
+                            + iasDescriptor + ") was not found.";
+            throw new BuildException(msg, getLocation());
+        }
+
+        if ((iashome != null) && (!iashome.isDirectory())) {
+            String msg = "If \"iashome\" is specified, it must be a valid "
+                            + "directory (it was set to " + iashome + ").";
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * This method returns a list of EJB files found when the specified EJB
+     * descriptor is parsed and processed.
+     *
+     * @param descriptorFileName String representing the file name of an EJB
+     *                           descriptor to be processed
+     * @param saxParser          SAXParser which may be used to parse the XML
+     *                           descriptor
+     * @return                   Hashtable of EJB class (and other) files to be
+     *                           added to the completed JAR file
+     * @throws IOException       An IOException from the parser, possibly from
+     *                           the byte stream or character stream
+     * @throws SAXException      Any SAX exception, possibly wrapping another
+     *                           exception
+     */
+    protected Hashtable parseEjbFiles(String descriptorFileName,
+                         SAXParser saxParser) throws IOException, SAXException {
+
+        Hashtable files;
+
+        /* Build and populate an instance of the ejbc utility */
+        IPlanetEjbc ejbc = new IPlanetEjbc(
+                                    new File(getConfig().descriptorDir,
+                                                descriptorFileName),
+                                    new File(getConfig().descriptorDir,
+                                                getIasDescriptorName()),
+                                    getConfig().srcDir,
+                                    getCombinedClasspath().toString(),
+                                    saxParser);
+        ejbc.setRetainSource(keepgenerated);
+        ejbc.setDebugOutput(debug);
+        if (iashome != null) {
+            ejbc.setIasHomeDir(iashome);
+        }
+
+        /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
+        try {
+            ejbc.execute();
+        } catch (IPlanetEjbc.EjbcException e) {
+            throw new BuildException("An error has occurred while trying to "
+                        + "execute the iAS ejbc utility", e, getLocation());
+        }
+
+        displayName    = ejbc.getDisplayName();
+        files          = ejbc.getEjbFiles();
+
+        /* Add CMP descriptors to the list of EJB files */
+        String[] cmpDescriptors = ejbc.getCmpDescriptors();
+        if (cmpDescriptors.length > 0) {
+            File baseDir = getConfig().descriptorDir;
+
+            int endOfPath = descriptorFileName.lastIndexOf(File.separator);
+            String relativePath = descriptorFileName.substring(0, endOfPath + 1);
+
+            for (int i = 0; i < cmpDescriptors.length; i++) {
+                int endOfCmp = cmpDescriptors[i].lastIndexOf('/');
+                String cmpDescriptor = cmpDescriptors[i].substring(endOfCmp + 1);
+
+                File   cmpFile = new File(baseDir, relativePath + cmpDescriptor);
+                if (!cmpFile.exists()) {
+                    throw new BuildException("The CMP descriptor file ("
+                            + cmpFile + ") could not be found.", getLocation());
+                }
+                files.put(cmpDescriptors[i], cmpFile);
+            }
+        }
+
+        return files;
+    }
+
+    /**
+     * Add the iAS-specific EJB descriptor to the list of files which will be
+     * written to the JAR file.
+     *
+     * @param ejbFiles Hashtable of EJB class (and other) files to be added to
+     *                 the completed JAR file.
+     * @param ddPrefix not used
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+        ejbFiles.put(META_DIR + IAS_DD, new File(getConfig().descriptorDir,
+                     getIasDescriptorName()));
+    }
+
+    /**
+     * Get the name of the Jar that will be written. The modification date
+     * of this jar will be checked against the dependent bean classes.
+     *
+     * @param baseName String name of the EJB JAR file to be written (without
+     *                 a filename extension).
+     *
+     * @return File representing the JAR file which will be written.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        File jarFile = new File(getDestDir(), baseName + jarSuffix);
+        log("JAR file name: " + jarFile.toString(), Project.MSG_VERBOSE);
+        return jarFile;
+    }
+
+    /**
+     * The iAS ejbc utility doesn't require the Public ID of the descriptor's
+     * DTD for it to process correctly--this method always returns <code>null
+     * </code>.
+     *
+     * @return <code>null</code>.
+     */
+    protected String getPublicId() {
+        return null;
+    }
+
+    /**
+     * Determines the name of the iAS-specific EJB descriptor using the
+     * specified standard EJB descriptor name.  In general, the standard
+     * descriptor will be named "[basename]-ejb-jar.xml", and this method will
+     * return "[basename]-ias-ejb-jar.xml".
+     *
+     * @return The name of the iAS-specific EJB descriptor file.
+     */
+    private String getIasDescriptorName() {
+
+        /* Only calculate the descriptor name once */
+        if (iasDescriptorName != null) {
+            return iasDescriptorName;
+        }
+
+        String path = "";   // Directory path of the EJB descriptor
+        String basename;    // Filename appearing before name terminator
+        String remainder;   // Filename appearing after the name terminator
+
+        /* Find the end of the standard descriptor's relative path */
+        int startOfFileName = descriptorName.lastIndexOf(File.separatorChar);
+        if (startOfFileName != -1) {
+            path = descriptorName.substring(0, startOfFileName + 1);
+        }
+
+        /* Check to see if the standard name is used (there's no basename) */
+        if (descriptorName.substring(startOfFileName + 1).equals(EJB_DD)) {
+            basename = "";
+            remainder = EJB_DD;
+
+        } else {
+            int endOfBaseName = descriptorName.indexOf(
+                                                getConfig().baseNameTerminator,
+                                                startOfFileName);
+            /*
+             * Check for the odd case where the terminator and/or filename
+             * extension aren't found.  These will ensure "ias-" appears at the
+             * end of the name and before the '.' (if present).
+             */
+            if (endOfBaseName < 0) {
+                endOfBaseName = descriptorName.lastIndexOf('.') - 1;
+                if (endOfBaseName < 0) {
+                    endOfBaseName = descriptorName.length() - 1;
+                }
+            }
+
+            basename = descriptorName.substring(startOfFileName + 1,
+                                                endOfBaseName + 1);
+            remainder = descriptorName.substring(endOfBaseName + 1);
+        }
+
+        iasDescriptorName = path + basename + "ias-" + remainder;
+        return iasDescriptorName;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java
new file mode 100644
index 0000000..dba8006
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbc.java
@@ -0,0 +1,1493 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.AttributeList;
+import org.xml.sax.HandlerBase;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Compiles EJB stubs and skeletons for the iPlanet Application
+ * Server (iAS).  The class will read a standard EJB descriptor (as well as an
+ * EJB descriptor specific to iPlanet Application Server) to identify one or
+ * more EJBs to process.  It will search for EJB "source" classes (the remote
+; * interface, home interface, and EJB implementation class) and the EJB stubs
+ * and skeletons in the specified destination directory.  Only if the stubs and
+ * skeletons cannot be found or if they're out of date will the iPlanet
+ * Application Server ejbc utility be run.
+ * <p>
+ * Because this class (and it's assorted inner classes) may be bundled into the
+ * iPlanet Application Server distribution at some point (and removed from the
+ * Ant distribution), the class has been written to be independent of all
+ * Ant-specific classes.  It is also for this reason (and to avoid cluttering
+ * the Apache Ant source files) that this utility has been packaged into a
+ * single source file.
+ * <p>
+ * For more information on Ant Tasks for iPlanet Application Server, see the
+ * <code>IPlanetDeploymentTool</code> and <code>IPlanetEjbcTask</code> classes.
+ *
+ * @see    IPlanetDeploymentTool
+ * @see    IPlanetEjbcTask
+ * @ant.task ignore="true"
+ */
+public class IPlanetEjbc {
+
+    private static final int MIN_NUM_ARGS = 2;
+    private static final int MAX_NUM_ARGS = 8;
+    private static final int NUM_CLASSES_WITH_IIOP = 15;
+    private static final int NUM_CLASSES_WITHOUT_IIOP = 9;
+
+    /* Constants used for the "beantype" attribute */
+    private static final String ENTITY_BEAN       = "entity";
+    private static final String STATELESS_SESSION = "stateless";
+    private static final String STATEFUL_SESSION  = "stateful";
+
+    /* Filenames of the standard EJB descriptor and the iAS-specific descriptor */
+    private File        stdDescriptor;
+    private File        iasDescriptor;
+
+    /*
+     * Directory where "source" EJB files are stored and where stubs and
+     * skeletons will also be written.
+     */
+    private File        destDirectory;
+
+    /* Classpath used when the iAS ejbc is called */
+    private String      classpath;
+    private String[]    classpathElements;
+
+    /* Options passed to the iAS ejbc */
+    private boolean     retainSource = false;
+    private boolean     debugOutput  = false;
+
+    /* iAS installation directory (used if ejbc isn't on user's PATH) */
+    private File        iasHomeDir;
+
+    /* Parser and handler used to process both EJB descriptor files */
+    private SAXParser   parser;
+    private EjbcHandler handler = new EjbcHandler();
+
+    /*
+     * This Hashtable maintains a list of EJB class files processed by the ejbc
+     * utility (both "source" class files as well as stubs and skeletons). The
+     * key for the Hashtable is a String representing the path to the class file
+     * (relative to the destination directory).  The value for the Hashtable is
+     * a File object which reference the actual class file.
+     */
+    private Hashtable   ejbFiles     = new Hashtable();
+
+    /* Value of the display-name element read from the standard EJB descriptor */
+    private String      displayName;
+
+    /**
+     * Constructs an instance which may be used to process EJB descriptors and
+     * generate EJB stubs and skeletons, if needed.
+     *
+     * @param stdDescriptor File referencing a standard EJB descriptor.
+     * @param iasDescriptor File referencing an iAS-specific EJB descriptor.
+     * @param destDirectory File referencing the base directory where both
+     *                      EJB "source" files are found and where stubs and
+     *                      skeletons will be written.
+     * @param classpath     String representation of the classpath to be used
+     *                      by the iAS ejbc utility.
+     * @param parser        SAXParser to be used to process both of the EJB
+     *                      descriptors.
+     * @todo classpathElements is not needed here, its never used
+     *       (at least IDEA tells me so! :)
+     */
+    public IPlanetEjbc(File stdDescriptor,
+                       File iasDescriptor,
+                       File destDirectory,
+                       String classpath,
+                       SAXParser parser) {
+        this.stdDescriptor = stdDescriptor;
+        this.iasDescriptor      = iasDescriptor;
+        this.destDirectory      = destDirectory;
+        this.classpath          = classpath;
+        this.parser             = parser;
+
+        /*
+         * Parse the classpath into it's individual elements and store the
+         * results in the "classpathElements" instance variable.
+         */
+        List elements = new ArrayList();
+        if (classpath != null) {
+            StringTokenizer st = new StringTokenizer(classpath,
+                                                        File.pathSeparator);
+            while (st.hasMoreTokens()) {
+                elements.add(st.nextToken());
+            }
+            classpathElements
+                    = (String[]) elements.toArray(new String[elements.size()]);
+        }
+    }
+
+    /**
+     * If true, the Java source files which are generated by the
+     * ejbc process are retained.
+     *
+     * @param retainSource A boolean indicating if the Java source files for
+     *                     the stubs and skeletons should be retained.
+     * @todo This is not documented in the HTML. On purpose?
+     */
+    public void setRetainSource(boolean retainSource) {
+        this.retainSource = retainSource;
+    }
+
+    /**
+     * If true, enables debugging output when ejbc is executed.
+     *
+     * @param debugOutput A boolean indicating if debugging output should be
+     *                    generated
+     */
+    public void setDebugOutput(boolean debugOutput) {
+        this.debugOutput = debugOutput;
+    }
+
+    /**
+     * Registers the location of a local DTD file or resource.  By registering
+     * a local DTD, EJB descriptors can be parsed even when the remote servers
+     * which contain the "public" DTDs cannot be accessed.
+     *
+     * @param publicID The public DTD identifier found in an XML document.
+     * @param location The file or resource name for the appropriate DTD stored
+     *                 on the local machine.
+     */
+    public void registerDTD(String publicID, String location) {
+        handler.registerDTD(publicID, location);
+    }
+
+    /**
+     * May be used to specify the "home" directory for this iAS installation.
+     * The directory specified should typically be
+     * <code>[install-location]/iplanet/ias6/ias</code>.
+     *
+     * @param iasHomeDir The home directory for the user's iAS installation.
+     */
+    public void setIasHomeDir(File iasHomeDir) {
+        this.iasHomeDir = iasHomeDir;
+    }
+
+    /**
+     * Returns a Hashtable which contains a list of EJB class files processed by
+     * the ejbc utility (both "source" class files as well as stubs and
+     * skeletons). The key for the Hashtable is a String representing the path
+     * to the class file (relative to the destination directory).  The value for
+     * the Hashtable is a File object which reference the actual class file.
+     *
+     * @return The list of EJB files processed by the ejbc utility.
+     */
+    public Hashtable getEjbFiles() {
+        return ejbFiles;
+    }
+
+    /**
+     * Returns the display-name element read from the standard EJB descriptor.
+     *
+     * @return The EJB-JAR display name.
+     */
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    /**
+     * Returns the list of CMP descriptors referenced in the EJB descriptors.
+     *
+     * @return An array of CMP descriptors.
+     */
+    public String[] getCmpDescriptors() {
+        List returnList = new ArrayList();
+
+        EjbInfo[] ejbs = handler.getEjbs();
+
+        for (int i = 0; i < ejbs.length; i++) {
+            List descriptors = (List) ejbs[i].getCmpDescriptors();
+            returnList.addAll(descriptors);
+        }
+
+        return (String[]) returnList.toArray(new String[returnList.size()]);
+    }
+
+    /**
+     * Main application method for the iPlanet Application Server ejbc utility.
+     * If the application is run with no commandline arguments, a usage
+     * statement is printed for the user.
+     *
+     * @param args The commandline arguments passed to the application.
+     */
+    public static void main(String[] args) {
+        File        stdDescriptor;
+        File        iasDescriptor;
+        File        destDirectory = null;
+        String      classpath     = null;
+        SAXParser   parser        = null;
+        boolean     debug         = false;
+        boolean     retainSource  = false;
+        IPlanetEjbc ejbc;
+
+        if ((args.length < MIN_NUM_ARGS) || (args.length > MAX_NUM_ARGS)) {
+            usage();
+            return;
+        }
+
+        stdDescriptor = new File(args[args.length - 2]);
+        iasDescriptor = new File(args[args.length - 1]);
+
+        for (int i = 0; i < args.length - 2; i++) {
+            if (args[i].equals("-classpath")) {
+                classpath = args[++i];
+            } else if (args[i].equals("-d")) {
+                destDirectory = new File(args[++i]);
+            } else if (args[i].equals("-debug")) {
+                debug = true;
+            } else if (args[i].equals("-keepsource")) {
+                retainSource = true;
+            } else {
+                usage();
+                return;
+            }
+        }
+
+        /* If the -classpath flag isn't specified, use the system classpath */
+        if (classpath == null) {
+            Properties props = System.getProperties();
+            classpath = props.getProperty("java.class.path");
+        }
+
+        /*
+         * If the -d flag isn't specified, use the working directory as the
+         * destination directory
+         */
+        if (destDirectory == null) {
+            Properties props = System.getProperties();
+            destDirectory = new File(props.getProperty("user.dir"));
+        }
+
+        /* Construct a SAXParser used to process the descriptors */
+        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+        parserFactory.setValidating(true);
+        try {
+            parser = parserFactory.newSAXParser();
+        } catch (Exception e) {
+            // SAXException or ParserConfigurationException may be thrown
+            System.out.println("An exception was generated while trying to ");
+            System.out.println("create a new SAXParser.");
+            e.printStackTrace();
+            return;
+        }
+
+        /* Build and populate an instance of the ejbc utility */
+        ejbc = new IPlanetEjbc(stdDescriptor, iasDescriptor, destDirectory,
+                                classpath, parser);
+        ejbc.setDebugOutput(debug);
+        ejbc.setRetainSource(retainSource);
+
+        /* Execute the ejbc utility -- stubs/skeletons are rebuilt, if needed */
+        try {
+            ejbc.execute();
+        } catch (IOException e) {
+            System.out.println("An IOException has occurred while reading the "
+                    + "XML descriptors (" + e.getMessage() + ").");
+            return;
+        } catch (SAXException e) {
+            System.out.println("A SAXException has occurred while reading the "
+                    + "XML descriptors (" + e.getMessage() + ").");
+            return;
+        } catch (IPlanetEjbc.EjbcException e) {
+            System.out.println("An error has occurred while executing the ejbc "
+                    + "utility (" + e.getMessage() + ").");
+            return;
+        }
+    }
+
+    /**
+     * Print a usage statement.
+     */
+    private static void usage() {
+        System.out.println("java org.apache.tools.ant.taskdefs.optional.ejb.IPlanetEjbc \\");
+        System.out.println("  [OPTIONS] [EJB 1.1 descriptor] [iAS EJB descriptor]");
+        System.out.println("");
+        System.out.println("Where OPTIONS are:");
+        System.out.println("  -debug -- for additional debugging output");
+        System.out.println("  -keepsource -- to retain Java source files generated");
+        System.out.println("  -classpath [classpath] -- classpath used for compilation");
+        System.out.println("  -d [destination directory] -- directory for compiled classes");
+        System.out.println("");
+        System.out.println("If a classpath is not specified, the system classpath");
+        System.out.println("will be used.  If a destination directory is not specified,");
+        System.out.println("the current working directory will be used (classes will");
+        System.out.println("still be placed in subfolders which correspond to their");
+        System.out.println("package name).");
+        System.out.println("");
+        System.out.println("The EJB home interface, remote interface, and implementation");
+        System.out.println("class must be found in the destination directory.  In");
+        System.out.println("addition, the destination will look for the stubs and skeletons");
+        System.out.println("in the destination directory to ensure they are up to date.");
+    }
+
+    /**
+     * Compiles the stub and skeletons for the specified EJBs, if they need to
+     * be updated.
+     *
+     * @throws EjbcException If the ejbc utility cannot be correctly configured
+     *                       or if one or more of the EJB "source" classes
+     *                       cannot be found in the destination directory
+     * @throws IOException   If the parser encounters a problem reading the XML
+     *                       file
+     * @throws SAXException  If the parser encounters a problem processing the
+     *                       XML descriptor (it may wrap another exception)
+     */
+    public void execute() throws EjbcException, IOException, SAXException {
+
+        checkConfiguration();   // Throws EjbcException if unsuccessful
+
+        EjbInfo[] ejbs = getEjbs(); // Returns list of EJBs for processing
+
+        for (int i = 0; i < ejbs.length; i++) {
+            log("EJBInfo...");
+            log(ejbs[i].toString());
+        }
+
+        for (int i = 0; i < ejbs.length; i++) {
+            EjbInfo ejb = ejbs[i];
+
+            ejb.checkConfiguration(destDirectory);  // Throws EjbcException
+
+            if (ejb.mustBeRecompiled(destDirectory)) {
+                log(ejb.getName() + " must be recompiled using ejbc.");
+
+                String[] arguments = buildArgumentList(ejb);
+                callEjbc(arguments);
+
+            } else {
+                log(ejb.getName() + " is up to date.");
+            }
+        }
+    }
+
+    /**
+     * Executes the iPlanet Application Server ejbc command-line utility.
+     *
+     * @param arguments Command line arguments to be passed to the ejbc utility.
+     */
+    private void callEjbc(String[] arguments) {
+
+        /* Concatenate all of the command line arguments into a single String */
+        StringBuffer args = new StringBuffer();
+        for (int i = 0; i < arguments.length; i++) {
+            args.append(arguments[i]).append(" ");
+        }
+
+        /* If an iAS home directory is specified, prepend it to the commmand */
+        String command;
+        if (iasHomeDir == null) {
+            command = "";
+        } else {
+            command = iasHomeDir.toString() + File.separator + "bin"
+                                                        + File.separator;
+        }
+        command += "ejbc ";
+
+        log(command + args);
+
+        /*
+         * Use the Runtime object to execute an external command.  Use the
+         * RedirectOutput inner class to direct the standard and error output
+         * from the command to the JRE's standard output
+         */
+        try {
+            Process p = Runtime.getRuntime().exec(command + args);
+            RedirectOutput output = new RedirectOutput(p.getInputStream());
+            RedirectOutput error  = new RedirectOutput(p.getErrorStream());
+            output.start();
+            error.start();
+            p.waitFor();
+            p.destroy();
+        } catch (IOException e) {
+            log("An IOException has occurred while trying to execute ejbc.");
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            // Do nothing
+        }
+    }
+
+    /**
+     * Verifies that the user selections are valid.
+     *
+     * @throws EjbcException If the user selections are invalid.
+     */
+    protected void checkConfiguration() throws EjbcException {
+
+        String msg = "";
+
+        if (stdDescriptor == null) {
+            msg += "A standard XML descriptor file must be specified.  ";
+        }
+        if (iasDescriptor == null) {
+            msg += "An iAS-specific XML descriptor file must be specified.  ";
+        }
+        if (classpath == null) {
+            msg += "A classpath must be specified.    ";
+        }
+        if (parser == null) {
+            msg += "An XML parser must be specified.    ";
+        }
+
+        if (destDirectory == null) {
+            msg += "A destination directory must be specified.  ";
+        } else if (!destDirectory.exists()) {
+            msg += "The destination directory specified does not exist.  ";
+        } else if (!destDirectory.isDirectory()) {
+            msg += "The destination specified is not a directory.  ";
+        }
+
+        if (msg.length() > 0) {
+            throw new EjbcException(msg);
+        }
+    }
+
+    /**
+     * Parses the EJB descriptors and returns a list of EJBs which may need to
+     * be compiled.
+     *
+     * @return               An array of objects which describe the EJBs to be
+     *                       processed.
+     * @throws IOException   If the parser encounters a problem reading the XML
+     *                       files
+     * @throws SAXException  If the parser encounters a problem processing the
+     *                       XML descriptor (it may wrap another exception)
+     */
+    private EjbInfo[] getEjbs() throws IOException, SAXException {
+        EjbInfo[] ejbs = null;
+
+        /*
+         * The EJB information is gathered from the standard XML EJB descriptor
+         * and the iAS-specific XML EJB descriptor using a SAX parser.
+         */
+
+        parser.parse(stdDescriptor, handler);
+        parser.parse(iasDescriptor, handler);
+        ejbs = handler.getEjbs();
+
+        return ejbs;
+    }
+
+    /**
+     * Based on this object's instance variables as well as the EJB to be
+     * processed, the correct flags and parameters are set for the ejbc
+     * command-line utility.
+     * @param ejb The EJB for which stubs and skeletons will be compiled.
+     * @return    An array of Strings which are the command-line parameters for
+     *            for the ejbc utility.
+     */
+    private String[] buildArgumentList(EjbInfo ejb) {
+
+        List arguments = new ArrayList();
+
+        /* OPTIONAL COMMAND LINE PARAMETERS */
+
+        if (debugOutput) {
+            arguments.add("-debug");
+        }
+
+        /* No beantype flag is needed for an entity bean */
+        if (ejb.getBeantype().equals(STATELESS_SESSION)) {
+            arguments.add("-sl");
+        } else if (ejb.getBeantype().equals(STATEFUL_SESSION)) {
+            arguments.add("-sf");
+        }
+
+        if (ejb.getIiop()) {
+            arguments.add("-iiop");
+        }
+
+        if (ejb.getCmp()) {
+            arguments.add("-cmp");
+        }
+
+        if (retainSource) {
+            arguments.add("-gs");
+        }
+
+        if (ejb.getHasession()) {
+            arguments.add("-fo");
+        }
+
+        /* REQUIRED COMMAND LINE PARAMETERS */
+
+        arguments.add("-classpath");
+        arguments.add(classpath);
+
+        arguments.add("-d");
+        arguments.add(destDirectory.toString());
+
+        arguments.add(ejb.getHome().getQualifiedClassName());
+        arguments.add(ejb.getRemote().getQualifiedClassName());
+        arguments.add(ejb.getImplementation().getQualifiedClassName());
+
+        /* Convert the List into an Array and return it */
+        return (String[]) arguments.toArray(new String[arguments.size()]);
+    }
+
+    /**
+     * Convenience method used to print messages to the user if debugging
+     * messages are enabled.
+     *
+     * @param msg The String to print to standard output.
+     */
+    private void log(String msg) {
+        if (debugOutput) {
+            System.out.println(msg);
+        }
+    }
+
+
+    /* Inner classes follow */
+
+
+    /**
+     * This inner class is used to signal any problems during the execution of
+     * the ejbc compiler.
+     *
+     */
+    public class EjbcException extends Exception {
+
+        /**
+         * Constructs an exception with the given descriptive message.
+         *
+         * @param msg Description of the exception which has occurred.
+         */
+        public EjbcException(String msg) {
+            super(msg);
+        }
+    }  // End of EjbcException inner class
+
+
+    /**
+     * This inner class is an XML document handler that can be used to parse EJB
+     * descriptors (both the standard EJB descriptor as well as the iAS-specific
+     * descriptor that stores additional values for iAS).  Once the descriptors
+     * have been processed, the list of EJBs found can be obtained by calling
+     * the <code>getEjbs()</code> method.
+     *
+     * @see    IPlanetEjbc.EjbInfo
+     */
+    private class EjbcHandler extends HandlerBase {
+        /** EJB 1.1 ID */
+        private static final String PUBLICID_EJB11 =
+            "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+        /** IPlanet ID */
+        private static final String PUBLICID_IPLANET_EJB_60 =
+            "-//Sun Microsystems, Inc.//DTD iAS Enterprise JavaBeans 1.0//EN";
+        /** EJB 1.1 location */
+        private static final String DEFAULT_IAS60_EJB11_DTD_LOCATION =
+            "ejb-jar_1_1.dtd";
+        /** IAS60 location */
+        private static final String DEFAULT_IAS60_DTD_LOCATION =
+            "IASEjb_jar_1_0.dtd";
+
+        /*
+         * Two Maps are used to track local DTDs that will be used in case the
+         * remote copies of these DTDs cannot be accessed.  The key for the Map
+         * is the DTDs public ID and the value is the local location for the DTD
+         */
+        private Map       resourceDtds = new HashMap();
+        private Map       fileDtds = new HashMap();
+
+        private Map       ejbs = new HashMap();      // List of EJBs found in XML
+        private EjbInfo   currentEjb;             // One item within the Map
+        private boolean   iasDescriptor = false;  // Is doc iAS or EJB descriptor
+
+        private String    currentLoc = "";        // Tracks current element
+        private String    currentText;            // Tracks current text data
+        private String    ejbType;                // "session" or "entity"
+
+        /**
+         * Constructs a new instance of the handler and registers local copies
+         * of the standard EJB 1.1 descriptor DTD as well as iAS's EJB
+         * descriptor DTD.
+         */
+        public EjbcHandler() {
+            registerDTD(PUBLICID_EJB11, DEFAULT_IAS60_EJB11_DTD_LOCATION);
+            registerDTD(PUBLICID_IPLANET_EJB_60, DEFAULT_IAS60_DTD_LOCATION);
+        }
+
+        /**
+         * Returns the list of EJB objects found during the processing of the
+         * standard EJB 1.1 descriptor and iAS-specific EJB descriptor.
+         *
+         * @return An array of EJBs which were found during the descriptor
+         *         parsing.
+         */
+        public EjbInfo[] getEjbs() {
+            return (EjbInfo[]) ejbs.values().toArray(new EjbInfo[ejbs.size()]);
+        }
+
+        /**
+         * Returns the value of the display-name element found in the standard
+         * EJB 1.1 descriptor.
+         *
+         * @return String display-name value.
+         */
+        public String getDisplayName() {
+            return displayName;
+        }
+
+        /**
+         * Registers a local DTD that will be used when parsing an EJB
+         * descriptor.  When the DTD's public identifier is found in an XML
+         * document, the parser will reference the local DTD rather than the
+         * remote DTD.  This enables XML documents to be processed even when the
+         * public DTD isn't available.
+         *
+         * @param publicID The DTD's public identifier.
+         * @param location The location of the local DTD copy -- the location
+         *                 may either be a resource found on the classpath or a
+         *                 local file.
+         */
+        public void registerDTD(String publicID, String location) {
+            log("Registering: " + location);
+            if ((publicID == null) || (location == null)) {
+                return;
+            }
+
+            if (ClassLoader.getSystemResource(location) != null) {
+                log("Found resource: " + location);
+                resourceDtds.put(publicID, location);
+            } else {
+                File dtdFile = new File(location);
+                if (dtdFile.exists() && dtdFile.isFile()) {
+                    log("Found file: " + location);
+                    fileDtds.put(publicID, location);
+                }
+            }
+        }
+
+        /**
+         * Resolves an external entity found during XML processing.  If a public
+         * ID is found that has been registered with the handler, an <code>
+         * InputSource</code> will be returned which refers to the local copy.
+         * If the public ID hasn't been registered or if an error occurs, the
+         * superclass implementation is used.
+         *
+         * @param publicId The DTD's public identifier.
+         * @param systemId The location of the DTD, as found in the XML document.
+         */
+        public InputSource resolveEntity(String publicId, String systemId)
+                throws SAXException {
+            InputStream inputStream = null;
+
+
+            try {
+
+                /* Search the resource Map and (if not found) file Map */
+
+                String location = (String) resourceDtds.get(publicId);
+                if (location != null) {
+                    inputStream
+                        = ClassLoader.getSystemResource(location).openStream();
+                } else {
+                    location = (String) fileDtds.get(publicId);
+                    if (location != null) {
+                        inputStream = new FileInputStream(location);
+                    }
+                }
+            } catch (IOException e) {
+                return super.resolveEntity(publicId, systemId);
+            }
+
+            if (inputStream == null) {
+                return super.resolveEntity(publicId, systemId);
+            } else {
+                return new InputSource(inputStream);
+            }
+        }
+
+        /**
+         * Receive notification that the start of an XML element has been found.
+         *
+         * @param name String name of the element found.
+         * @param atts AttributeList of the attributes included with the element
+         *             (if any).
+         * @throws SAXException If the parser cannot process the document.
+         */
+        public void startElement(String name, AttributeList atts)
+                throws SAXException {
+
+            /*
+             * I need to "push" the element onto the String (currentLoc) which
+             * always represents the current location in the XML document.
+             */
+            currentLoc += "\\" + name;
+
+            /* A new element has started, so reset the text being captured */
+            currentText = "";
+
+            if (currentLoc.equals("\\ejb-jar")) {
+                iasDescriptor = false;
+            } else if (currentLoc.equals("\\ias-ejb-jar")) {
+                iasDescriptor = true;
+            }
+
+            if ((name.equals("session")) || (name.equals("entity"))) {
+                ejbType = name;
+            }
+        }
+
+        /**
+         * Receive notification that character data has been found in the XML
+         * document
+         *
+         * @param ch Array of characters which have been found in the document.
+         * @param start Starting index of the data found in the document.
+         * @param len The number of characters found in the document.
+         * @throws SAXException If the parser cannot process the document.
+         */
+        public void characters(char[] ch, int start, int len)
+                throws SAXException {
+
+            currentText += new String(ch).substring(start, start + len);
+        }
+
+        /**
+         * Receive notification that the end of an XML element has been found.
+         *
+         * @param name String name of the element.
+         * @throws SAXException If the parser cannot process the document.
+         */
+        public void endElement(String name) throws SAXException {
+
+            /*
+             * If this is a standard EJB 1.1 descriptor, we are looking for one
+             * set of data, while if this is an iAS-specific descriptor, we're
+             * looking for different set of data.  Hand the processing off to
+             * the appropriate method.
+             */
+            if (iasDescriptor) {
+                iasCharacters(currentText);
+            } else {
+                stdCharacters(currentText);
+            }
+
+            /*
+             * I need to "pop" the element off the String (currentLoc) which
+             * always represents my current location in the XML document.
+             */
+
+            int nameLength = name.length() + 1; // Add one for the "\"
+            int locLength  = currentLoc.length();
+
+            currentLoc = currentLoc.substring(0, locLength - nameLength);
+        }
+
+        /**
+         * Receive notification that character data has been found in a standard
+         * EJB 1.1 descriptor.  We're interested in retrieving the home
+         * interface, remote interface, implementation class, the type of bean,
+         * and if the bean uses CMP.
+         *
+         * @param value String data found in the XML document.
+         */
+        private void stdCharacters(String value) {
+
+            if (currentLoc.equals("\\ejb-jar\\display-name")) {
+                displayName = value;
+                return;
+            }
+
+            String base = "\\ejb-jar\\enterprise-beans\\" + ejbType;
+
+            if (currentLoc.equals(base + "\\ejb-name")) {
+                currentEjb = (EjbInfo) ejbs.get(value);
+                if (currentEjb == null) {
+                    currentEjb = new EjbInfo(value);
+                    ejbs.put(value, currentEjb);
+                }
+            } else if (currentLoc.equals(base + "\\home")) {
+                currentEjb.setHome(value);
+            } else if (currentLoc.equals(base + "\\remote")) {
+                currentEjb.setRemote(value);
+            } else if (currentLoc.equals(base + "\\ejb-class")) {
+                currentEjb.setImplementation(value);
+            } else if (currentLoc.equals(base + "\\prim-key-class")) {
+                currentEjb.setPrimaryKey(value);
+            } else if (currentLoc.equals(base + "\\session-type")) {
+                currentEjb.setBeantype(value);
+            } else if (currentLoc.equals(base + "\\persistence-type")) {
+                currentEjb.setCmp(value);
+            }
+        }
+
+        /**
+         * Receive notification that character data has been found in an
+         * iAS-specific descriptor.  We're interested in retrieving data
+         * indicating whether the bean must support RMI/IIOP access, whether
+         * the bean must provide highly available stubs and skeletons (in the
+         * case of stateful session beans), and if this bean uses additional
+         * CMP XML descriptors (in the case of entity beans with CMP).
+         *
+         * @param value String data found in the XML document.
+         */
+        private void iasCharacters(String value) {
+            String base = "\\ias-ejb-jar\\enterprise-beans\\" + ejbType;
+
+            if (currentLoc.equals(base + "\\ejb-name")) {
+                currentEjb = (EjbInfo) ejbs.get(value);
+                if (currentEjb == null) {
+                    currentEjb = new EjbInfo(value);
+                    ejbs.put(value, currentEjb);
+                }
+            } else if (currentLoc.equals(base + "\\iiop")) {
+                currentEjb.setIiop(value);
+            } else if (currentLoc.equals(base + "\\failover-required")) {
+                currentEjb.setHasession(value);
+            } else if (currentLoc.equals(base + "\\persistence-manager"
+                                              + "\\properties-file-location")) {
+                currentEjb.addCmpDescriptor(value);
+            }
+        }
+    }  // End of EjbcHandler inner class
+
+
+    /**
+     * This inner class represents an EJB that will be compiled using ejbc.
+     *
+     */
+    private class EjbInfo {
+        private String     name;              // EJB's display name
+        private Classname  home;              // EJB's home interface name
+        private Classname  remote;            // EJB's remote interface name
+        private Classname  implementation;      // EJB's implementation class
+        private Classname  primaryKey;        // EJB's primary key class
+        private String  beantype = "entity";  // or "stateful" or "stateless"
+        private boolean cmp       = false;      // Does this EJB support CMP?
+        private boolean iiop      = false;      // Does this EJB support IIOP?
+        private boolean hasession = false;      // Does this EJB require failover?
+        private List cmpDescriptors = new ArrayList();  // CMP descriptor list
+
+        /**
+         * Construct a new EJBInfo object with the given name.
+         *
+         * @param name The display name for the EJB.
+         */
+        public EjbInfo(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Returns the display name of the EJB.  If a display name has not been
+         * set, it returns the EJB implementation classname (if the
+         * implementation class is not set, it returns "[unnamed]").
+         *
+         * @return The display name for the EJB.
+         */
+        public String getName() {
+            if (name == null) {
+                if (implementation == null) {
+                    return "[unnamed]";
+                } else {
+                    return implementation.getClassName();
+                }
+            }
+            return name;
+        }
+
+        /*
+         * Below are getter's and setter's for each of the instance variables.
+         * Note that (in addition to supporting setters with the same type as
+         * the instance variable) a setter is provided with takes a String
+         * argument -- this are provided so the XML document handler can set
+         * the EJB values using the Strings it parses.
+         */
+
+        public void setHome(String home) {
+            setHome(new Classname(home));
+        }
+
+        public void setHome(Classname home) {
+            this.home = home;
+        }
+
+        public Classname getHome() {
+            return home;
+        }
+
+        public void setRemote(String remote) {
+            setRemote(new Classname(remote));
+        }
+
+        public void setRemote(Classname remote) {
+            this.remote = remote;
+        }
+
+        public Classname getRemote() {
+            return remote;
+        }
+
+        public void setImplementation(String implementation) {
+            setImplementation(new Classname(implementation));
+        }
+
+        public void setImplementation(Classname implementation) {
+            this.implementation = implementation;
+        }
+
+        public Classname getImplementation() {
+            return implementation;
+        }
+
+        public void setPrimaryKey(String primaryKey) {
+            setPrimaryKey(new Classname(primaryKey));
+        }
+
+        public void setPrimaryKey(Classname primaryKey) {
+            this.primaryKey = primaryKey;
+        }
+
+        public Classname getPrimaryKey() {
+            return primaryKey;
+        }
+
+        public void setBeantype(String beantype) {
+            this.beantype = beantype.toLowerCase();
+        }
+
+        public String getBeantype() {
+            return beantype;
+        }
+
+        public void setCmp(boolean cmp) {
+            this.cmp = cmp;
+        }
+
+        public void setCmp(String cmp) {
+            setCmp(cmp.equals("Container"));
+        }
+
+        public boolean getCmp() {
+            return cmp;
+        }
+
+        public void setIiop(boolean iiop) {
+            this.iiop = iiop;
+        }
+
+        public void setIiop(String iiop) {
+            setIiop(iiop.equals("true"));
+        }
+
+        public boolean getIiop() {
+            return iiop;
+        }
+
+        public void setHasession(boolean hasession) {
+            this.hasession = hasession;
+        }
+
+        public void setHasession(String hasession) {
+            setHasession(hasession.equals("true"));
+        }
+
+        public boolean getHasession() {
+            return hasession;
+        }
+
+        public void addCmpDescriptor(String descriptor) {
+            cmpDescriptors.add(descriptor);
+        }
+
+        public List getCmpDescriptors() {
+            return cmpDescriptors;
+        }
+
+        /**
+         * Verifies that the EJB is valid--if it is invalid, an exception is
+         * thrown
+         *
+         *
+         * @param buildDir The directory where the EJB remote interface, home
+         *                 interface, and implementation class must be found.
+         * @throws EjbcException If the EJB is invalid.
+         */
+        private void checkConfiguration(File buildDir) throws EjbcException  {
+
+            /* Check that the specified instance variables are valid */
+            if (home == null) {
+                throw new EjbcException("A home interface was not found "
+                            + "for the " + name + " EJB.");
+            }
+            if (remote == null) {
+                throw new EjbcException("A remote interface was not found "
+                            + "for the " + name + " EJB.");
+            }
+            if (implementation == null) {
+                throw new EjbcException("An EJB implementation class was not "
+                            + "found for the " + name + " EJB.");
+            }
+
+            if ((!beantype.equals(ENTITY_BEAN))
+                        && (!beantype.equals(STATELESS_SESSION))
+                        && (!beantype.equals(STATEFUL_SESSION))) {
+                throw new EjbcException("The beantype found (" + beantype + ") "
+                            + "isn't valid in the " + name + " EJB.");
+            }
+
+            if (cmp && (!beantype.equals(ENTITY_BEAN))) {
+                System.out.println("CMP stubs and skeletons may not be generated"
+                    + " for a Session Bean -- the \"cmp\" attribute will be"
+                    + " ignoredfor the " + name + " EJB.");
+            }
+
+            if (hasession && (!beantype.equals(STATEFUL_SESSION))) {
+                System.out.println("Highly available stubs and skeletons may "
+                    + "only be generated for a Stateful Session Bean -- the "
+                    + "\"hasession\" attribute will be ignored for the "
+                    + name + " EJB.");
+            }
+
+            /* Check that the EJB "source" classes all exist */
+            if (!remote.getClassFile(buildDir).exists()) {
+                throw new EjbcException("The remote interface "
+                            + remote.getQualifiedClassName() + " could not be "
+                            + "found.");
+            }
+            if (!home.getClassFile(buildDir).exists()) {
+                throw new EjbcException("The home interface "
+                            + home.getQualifiedClassName() + " could not be "
+                            + "found.");
+            }
+            if (!implementation.getClassFile(buildDir).exists()) {
+                throw new EjbcException("The EJB implementation class "
+                            + implementation.getQualifiedClassName() + " could "
+                            + "not be found.");
+            }
+        }
+
+        /**
+         * Determines if the ejbc utility needs to be run or not.  If the stubs
+         * and skeletons can all be found in the destination directory AND all
+         * of their timestamps are more recent than the EJB source classes
+         * (home, remote, and implementation classes), the method returns
+         * <code>false</code>.  Otherwise, the method returns <code>true</code>.
+         *
+         * @param destDir The directory where the EJB source classes, stubs and
+         *                skeletons are located.
+         * @return A boolean indicating whether or not the ejbc utility needs to
+         *         be run to bring the stubs and skeletons up to date.
+         */
+        public boolean mustBeRecompiled(File destDir) {
+
+            long sourceModified = sourceClassesModified(destDir);
+
+            long destModified = destClassesModified(destDir);
+
+            return (destModified < sourceModified);
+        }
+
+        /**
+         * Examines each of the EJB source classes (home, remote, and
+         * implementation) and returns the modification timestamp for the
+         * "oldest" class.
+         *
+         * @param classpath The classpath to be used to find the source EJB
+         *                  classes.  If <code>null</code>, the system classpath
+         *                  is used.
+         * @return The modification timestamp for the "oldest" EJB source class.
+         * @throws BuildException If one of the EJB source classes cannot be
+         *                        found on the classpath.
+         */
+        private long sourceClassesModified(File buildDir) {
+            long latestModified; // The timestamp of the "newest" class
+            long modified;       // Timestamp for a given class
+            File remoteFile;     // File for the remote interface class
+            File homeFile;       // File for the home interface class
+            File implFile;       // File for the EJB implementation class
+            File pkFile;         // File for the EJB primary key class
+
+            /* Check the timestamp on the remote interface */
+            remoteFile = remote.getClassFile(buildDir);
+            modified = remoteFile.lastModified();
+            if (modified == -1) {
+                System.out.println("The class "
+                                + remote.getQualifiedClassName() + " couldn't "
+                                + "be found on the classpath");
+                return -1;
+            }
+            latestModified = modified;
+
+            /* Check the timestamp on the home interface */
+            homeFile = home.getClassFile(buildDir);
+            modified = homeFile.lastModified();
+            if (modified == -1) {
+                System.out.println("The class "
+                                + home.getQualifiedClassName() + " couldn't be "
+                                + "found on the classpath");
+                return -1;
+            }
+            latestModified = Math.max(latestModified, modified);
+
+            /* Check the timestamp of the primary key class */
+            if (primaryKey != null) {
+                pkFile = primaryKey.getClassFile(buildDir);
+                modified = pkFile.lastModified();
+                if (modified == -1) {
+                    System.out.println("The class "
+                                    + primaryKey.getQualifiedClassName() + "couldn't be "
+                                    + "found on the classpath");
+                    return -1;
+                }
+                latestModified = Math.max(latestModified, modified);
+            } else {
+                pkFile = null;
+            }
+
+            /* Check the timestamp on the EJB implementation class.
+             *
+             * Note that if ONLY the implementation class has changed, it's not
+             * necessary to rebuild the EJB stubs and skeletons.  For this
+             * reason, we ensure the file exists (using lastModified above), but
+             * we DON'T compare it's timestamp with the timestamps of the home
+             * and remote interfaces (because it's irrelevant in determining if
+             * ejbc must be run)
+             */
+            implFile = implementation.getClassFile(buildDir);
+            modified = implFile.lastModified();
+            if (modified == -1) {
+                System.out.println("The class "
+                                + implementation.getQualifiedClassName()
+                                + " couldn't be found on the classpath");
+                return -1;
+            }
+
+            String pathToFile = remote.getQualifiedClassName();
+            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+            ejbFiles.put(pathToFile, remoteFile);
+
+            pathToFile = home.getQualifiedClassName();
+            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+            ejbFiles.put(pathToFile, homeFile);
+
+            pathToFile = implementation.getQualifiedClassName();
+            pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+            ejbFiles.put(pathToFile, implFile);
+
+            if (pkFile != null) {
+                pathToFile = primaryKey.getQualifiedClassName();
+                pathToFile = pathToFile.replace('.', File.separatorChar) + ".class";
+                ejbFiles.put(pathToFile, pkFile);
+            }
+
+            return latestModified;
+        }
+
+        /**
+         * Examines each of the EJB stubs and skeletons in the destination
+         * directory and returns the modification timestamp for the "oldest"
+         * class. If one of the stubs or skeletons cannot be found, <code>-1
+         * </code> is returned.
+         *
+         * @param dest The directory in which the EJB stubs and skeletons are
+         *             stored.
+         * @return The modification timestamp for the "oldest" EJB stub or
+         *         skeleton.  If one of the classes cannot be found, <code>-1
+         *         </code> is returned.
+         * @throws BuildException If the canonical path of the destination
+         *                        directory cannot be found.
+         */
+        private long destClassesModified(File destDir) {
+            String[] classnames = classesToGenerate(); // List of all stubs & skels
+            long destClassesModified = new Date().getTime(); // Earliest mod time
+            boolean allClassesFound  = true;           // Has each been found?
+
+            /*
+             * Loop through each stub/skeleton class that must be generated, and
+             * determine (if all exist) which file has the most recent timestamp
+             */
+            for (int i = 0; i < classnames.length; i++) {
+
+                String pathToClass =
+                        classnames[i].replace('.', File.separatorChar) + ".class";
+                File classFile = new File(destDir, pathToClass);
+
+                /*
+                 * Add each stub/skeleton class to the list of EJB files.  Note
+                 * that each class is added even if it doesn't exist now.
+                 */
+                ejbFiles.put(pathToClass, classFile);
+
+                allClassesFound = allClassesFound && classFile.exists();
+
+                if (allClassesFound) {
+                    long fileMod = classFile.lastModified();
+
+                    /* Keep track of the oldest modification timestamp */
+                    destClassesModified = Math.min(destClassesModified, fileMod);
+                }
+            }
+
+            return (allClassesFound) ? destClassesModified : -1;
+        }
+
+        /**
+         * Builds an array of class names which represent the stubs and
+         * skeletons which need to be generated for a given EJB.  The class
+         * names are fully qualified.  Nine classes are generated for all EJBs
+         * while an additional six classes are generated for beans requiring
+         * RMI/IIOP access.
+         *
+         * @return An array of Strings representing the fully-qualified class
+         *         names for the stubs and skeletons to be generated.
+         */
+        private String[] classesToGenerate() {
+            String[] classnames = (iiop)
+                ? new String[NUM_CLASSES_WITH_IIOP]
+                : new String[NUM_CLASSES_WITHOUT_IIOP];
+
+            final String remotePkg     = remote.getPackageName() + ".";
+            final String remoteClass   = remote.getClassName();
+            final String homePkg       = home.getPackageName() + ".";
+            final String homeClass     = home.getClassName();
+            final String implPkg       = implementation.getPackageName() + ".";
+            final String implFullClass = implementation.getQualifiedWithUnderscores();
+            int index = 0;
+
+            classnames[index++] = implPkg + "ejb_fac_" + implFullClass;
+            classnames[index++] = implPkg + "ejb_home_" + implFullClass;
+            classnames[index++] = implPkg + "ejb_skel_" + implFullClass;
+            classnames[index++] = remotePkg + "ejb_kcp_skel_" + remoteClass;
+            classnames[index++] = homePkg + "ejb_kcp_skel_" + homeClass;
+            classnames[index++] = remotePkg + "ejb_kcp_stub_" + remoteClass;
+            classnames[index++] = homePkg + "ejb_kcp_stub_" + homeClass;
+            classnames[index++] = remotePkg + "ejb_stub_" + remoteClass;
+            classnames[index++] = homePkg + "ejb_stub_" + homeClass;
+
+            if (!iiop) {
+                return classnames;
+            }
+
+            classnames[index++] = "org.omg.stub." + remotePkg + "_"
+                                    + remoteClass + "_Stub";
+            classnames[index++] = "org.omg.stub." + homePkg + "_"
+                                    + homeClass + "_Stub";
+            classnames[index++] = "org.omg.stub." + remotePkg
+                                    + "_ejb_RmiCorbaBridge_"
+                                    + remoteClass + "_Tie";
+            classnames[index++] = "org.omg.stub." + homePkg
+                                    + "_ejb_RmiCorbaBridge_"
+                                    + homeClass + "_Tie";
+
+            classnames[index++] = remotePkg + "ejb_RmiCorbaBridge_"
+                                                        + remoteClass;
+            classnames[index++] = homePkg + "ejb_RmiCorbaBridge_" + homeClass;
+
+            return classnames;
+        }
+
+        /**
+         * Convenience method which creates a String representation of all the
+         * instance variables of an EjbInfo object.
+         *
+         * @return A String representing the EjbInfo instance.
+         */
+        public String toString() {
+            String s = "EJB name: " + name
+                        + "\n\r              home:      " + home
+                        + "\n\r              remote:    " + remote
+                        + "\n\r              impl:      " + implementation
+                        + "\n\r              primaryKey: " + primaryKey
+                        + "\n\r              beantype:  " + beantype
+                        + "\n\r              cmp:       " + cmp
+                        + "\n\r              iiop:      " + iiop
+                        + "\n\r              hasession: " + hasession;
+
+            Iterator i = cmpDescriptors.iterator();
+            while (i.hasNext()) {
+                s += "\n\r              CMP Descriptor: " + i.next();
+            }
+
+            return s;
+        }
+
+    } // End of EjbInfo inner class
+
+    /**
+     * Convenience class used to represent the fully qualified name of a Java
+     * class.  It provides an easy way to retrieve components of the class name
+     * in a format that is convenient for building iAS stubs and skeletons.
+     *
+     */
+    private static class Classname {
+        private String qualifiedName;  // Fully qualified name of the Java class
+        private String packageName;    // Name of the package for this class
+        private String className;      // Name of the class without the package
+
+        /**
+         * This constructor builds an object which represents the name of a Java
+         * class.
+         *
+         * @param qualifiedName String representing the fully qualified class
+         *                      name of the Java class.
+         */
+        public Classname(String qualifiedName) {
+            if (qualifiedName == null) {
+                return;
+            }
+
+            this.qualifiedName = qualifiedName;
+
+            int index = qualifiedName.lastIndexOf('.');
+            if (index == -1) {
+                className = qualifiedName;
+                packageName = "";
+            } else {
+                packageName = qualifiedName.substring(0, index);
+                className   = qualifiedName.substring(index + 1);
+            }
+        }
+
+        /**
+         * Gets the fully qualified name of the Java class.
+         *
+         * @return String representing the fully qualified class name.
+         */
+        public String getQualifiedClassName() {
+            return qualifiedName;
+        }
+
+        /**
+         * Gets the package name for the Java class.
+         *
+         * @return String representing the package name for the class.
+         */
+        public String getPackageName() {
+            return packageName;
+        }
+
+        /**
+         * Gets the Java class name without the package structure.
+         *
+         * @return String representing the name for the class.
+         */
+        public String getClassName() {
+            return className;
+        }
+
+        /**
+         * Gets the fully qualified name of the Java class with underscores
+         * separating the components of the class name rather than periods.
+         * This format is used in naming some of the stub and skeleton classes
+         * for the iPlanet Application Server.
+         *
+         * @return String representing the fully qualified class name using
+         *         underscores instead of periods.
+         */
+        public String getQualifiedWithUnderscores() {
+            return qualifiedName.replace('.', '_');
+        }
+
+        /**
+         * Returns a File which references the class relative to the specified
+         * directory.  Note that the class file may or may not exist.
+         *
+         * @param  directory A File referencing the base directory containing
+         *                   class files.
+         * @return File referencing this class.
+         */
+        public File getClassFile(File directory) {
+            String pathToFile = qualifiedName.replace('.', File.separatorChar)
+                                            + ".class";
+            return new File(directory, pathToFile);
+        }
+
+        /**
+         * String representation of this class name.  It returns the fully
+         * qualified class name.
+         *
+         * @return String representing the fully qualified class name.
+         */
+        public String toString() {
+            return getQualifiedClassName();
+        }
+    }  // End of Classname inner class
+
+
+    /**
+     * Thread class used to redirect output from an <code>InputStream</code> to
+     * the JRE standard output.  This class may be used to redirect output from
+     * an external process to the standard output.
+     *
+     */
+    private static class RedirectOutput extends Thread {
+
+        private InputStream stream;  // Stream to read and redirect to standard output
+
+        /**
+         * Constructs a new instance that will redirect output from the
+         * specified stream to the standard output.
+         *
+         * @param stream InputStream which will be read and redirected to the
+         *               standard output.
+         */
+        public RedirectOutput(InputStream stream) {
+            this.stream = stream;
+        }
+
+        /**
+         * Reads text from the input stream and redirects it to standard output
+         * using a separate thread.
+         */
+        public void run() {
+            BufferedReader reader = new BufferedReader(
+                                            new InputStreamReader(stream));
+            String text;
+            try {
+                while ((text = reader.readLine()) != null) {
+                    System.out.println(text);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    // Do nothing
+                }
+            }
+        }
+    }  // End of RedirectOutput inner class
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java
new file mode 100644
index 0000000..88cbd43
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/IPlanetEjbcTask.java
@@ -0,0 +1,319 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.xml.sax.SAXException;
+
+/**
+ * Compiles EJB stubs and skeletons for the iPlanet Application Server.
+ * The EJBs to be processed are specified by the EJB 1.1 standard XML
+ * descriptor, and additional attributes are obtained from the iPlanet Application
+ * Server-specific XML descriptor.  Since the XML descriptors can include
+ * multiple EJBs, this is a convenient way of specifying many EJBs in a single
+ * Ant task.  The following attributes are allowed:
+ *   <ul>
+ *     <li><i>ejbdescriptor</i> -- Standard EJB 1.1 XML descriptor (typically
+ *                                 titled "ejb-jar.xml").  This attribute is
+ *                                 required.
+ *     <li><i>iasdescriptor</i> -- EJB XML descriptor for iPlanet Application
+ *                                 Server (typically titled "ias-ejb-jar.xml).
+ *                                 This attribute is required.
+ *     <li><i>dest</i> -- The is the base directory where the RMI stubs and
+ *                        skeletons are written.  In addition, the class files
+ *                        for each bean (home interface, remote interface, and
+ *                        EJB implementation) must be found in this directory.
+ *                        This attribute is required.
+ *     <li><i>classpath</i> -- The classpath used when generating EJB stubs and
+ *                             skeletons.  This is an optional attribute (if
+ *                             omitted, the classpath specified when Ant was
+ *                             started will be used).  Nested "classpath"
+ *                             elements may also be used.
+ *     <li><i>keepgenerated</i> -- Indicates whether or not the Java source
+ *                                 files which are generated by ejbc will be
+ *                                 saved or automatically deleted.  If "yes",
+ *                                 the source files will be retained.  This is
+ *                                 an optional attribute (if omitted, it
+ *                                 defaults to "no").
+ *     <li><i>debug</i> -- Indicates whether or not the ejbc utility should
+ *                         log additional debugging statements to the standard
+ *                         output.  If "yes", the additional debugging statements
+ *                         will be generated (if omitted, it defaults to "no").
+ *     <li><i>iashome</i> -- May be used to specify the "home" directory for
+ *                           this iPlanet Application Server installation.  This
+ *                           is used to find the ejbc utility if it isn't
+ *                           included in the user's system path.  This is an
+ *                           optional attribute (if specified, it should refer
+ *                           to the <code>[install-location]/iplanet/ias6/ias
+ *                           </code> directory).  If omitted, the ejbc utility
+ *                           must be on the user's system path.
+ *   </ul>
+ * <p>
+ * For each EJB specified, this task will locate the three classes that comprise
+ * the EJB.  If these class files cannot be located in the <code>dest</code>
+ * directory, the task will fail.  The task will also attempt to locate the EJB
+ * stubs and skeletons in this directory.  If found, the timestamps on the
+ * stubs and skeletons will be checked to ensure they are up to date.  Only if
+ * these files cannot be found or if they are out of date will ejbc be called
+ * to generate new stubs and skeletons.
+ *
+ * @see    IPlanetEjbc
+ *
+ * @ant.task name="iplanet-ejbc" category="ejb"
+ */
+public class IPlanetEjbcTask extends Task {
+
+    /* Attributes set by the Ant build file */
+    private File    ejbdescriptor;
+    private File    iasdescriptor;
+    private File    dest;
+    private Path    classpath;
+    private boolean keepgenerated = false;
+    private boolean debug         = false;
+    private File    iashome;
+
+    /**
+     * Sets the location of the standard XML EJB descriptor.  Typically, this
+     * file is named "ejb-jar.xml".
+     *
+     * @param ejbdescriptor The name and location of the EJB descriptor.
+     */
+    public void setEjbdescriptor(File ejbdescriptor) {
+        this.ejbdescriptor = ejbdescriptor;
+    }
+
+    /**
+     * Sets the location of the iAS-specific XML EJB descriptor.  Typically,
+     * this file is named "ias-ejb-jar.xml".
+     *
+     * @param iasdescriptor The name and location of the iAS-specific EJB
+     *                      descriptor.
+     */
+    public void setIasdescriptor (File iasdescriptor) {
+        this.iasdescriptor = iasdescriptor;
+    }
+
+    /**
+     * Sets the destination directory where the EJB source classes must exist
+     * and where the stubs and skeletons will be written.  The destination
+     * directory must exist before this task is executed.
+     *
+     * @param dest The directory where the compiled classes will be written.
+     */
+    public void setDest(File dest) {
+        this.dest = dest;
+    }
+
+    /**
+     * Sets the classpath to be used when compiling the EJB stubs and skeletons.
+     *
+     * @param classpath The classpath to be used.
+     */
+    public void setClasspath(Path classpath) {
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Adds to the classpath used when compiling the EJB stubs and skeletons.
+     * @return the class path.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * If true, the Java source files which are generated by ejbc will be saved .
+     *
+     * @param keepgenerated A boolean indicating if the Java source files for
+     *                      the stubs and skeletons should be retained.
+     */
+    public void setKeepgenerated(boolean keepgenerated) {
+        this.keepgenerated = keepgenerated;
+    }
+
+    /**
+     * If true, debugging output will be generated when ejbc is
+     * executed.
+     *
+     * @param debug A boolean indicating if debugging output should be generated
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * May be used to specify the "home" directory for this iAS installation.
+     * The directory specified should typically be
+     * <code>[install-location]/iplanet/ias6/ias</code>.
+     *
+     * @param iashome The home directory for the user's iAS installation.
+     */
+    public void setIashome(File iashome) {
+        this.iashome = iashome;
+    }
+
+    /**
+     * Does the work.
+     * @throws BuildException if there is a problem.
+     */
+    public void execute() throws BuildException {
+        checkConfiguration();
+
+        executeEjbc(getParser());
+    }
+
+    /**
+     * Verifies that the user selections are valid.
+     *
+     * @throws BuildException If the user selections are invalid.
+     */
+    private void checkConfiguration() throws BuildException {
+
+        if (ejbdescriptor == null) {
+            String msg = "The standard EJB descriptor must be specified using "
+                            + "the \"ejbdescriptor\" attribute.";
+            throw new BuildException(msg, getLocation());
+        }
+        if ((!ejbdescriptor.exists()) || (!ejbdescriptor.isFile())) {
+            String msg = "The standard EJB descriptor (" + ejbdescriptor
+                            + ") was not found or isn't a file.";
+            throw new BuildException(msg, getLocation());
+        }
+
+        if (iasdescriptor == null) {
+            String msg = "The iAS-speific XML descriptor must be specified using"
+                            + " the \"iasdescriptor\" attribute.";
+            throw new BuildException(msg, getLocation());
+        }
+        if ((!iasdescriptor.exists()) || (!iasdescriptor.isFile())) {
+            String msg = "The iAS-specific XML descriptor (" + iasdescriptor
+                            + ") was not found or isn't a file.";
+            throw new BuildException(msg, getLocation());
+        }
+
+        if (dest == null) {
+            String msg = "The destination directory must be specified using "
+                            + "the \"dest\" attribute.";
+            throw new BuildException(msg, getLocation());
+        }
+        if ((!dest.exists()) || (!dest.isDirectory())) {
+            String msg = "The destination directory (" + dest + ") was not "
+                            + "found or isn't a directory.";
+            throw new BuildException(msg, getLocation());
+        }
+
+        if ((iashome != null) && (!iashome.isDirectory())) {
+            String msg = "If \"iashome\" is specified, it must be a valid "
+                            + "directory (it was set to " + iashome + ").";
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Returns a SAXParser that may be used to process the XML descriptors.
+     *
+     * @return Parser which may be used to process the EJB descriptors.
+     * @throws BuildException If the parser cannot be created or configured.
+     */
+    private SAXParser getParser() throws BuildException {
+
+        SAXParser saxParser = null;
+        try {
+            SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+            saxParserFactory.setValidating(true);
+            saxParser = saxParserFactory.newSAXParser();
+        } catch (SAXException e) {
+            String msg = "Unable to create a SAXParser: " + e.getMessage();
+            throw new BuildException(msg, e, getLocation());
+        } catch (ParserConfigurationException e) {
+            String msg = "Unable to create a SAXParser: " + e.getMessage();
+            throw new BuildException(msg, e, getLocation());
+        }
+
+        return saxParser;
+    }
+
+    /**
+     * Executes the EJBc utility using the SAXParser provided.
+     *
+     * @param saxParser SAXParser that may be used to process the EJB
+     *                  descriptors
+     * @throws BuildException If there is an error reading or parsing the XML
+     *                        descriptors
+     */
+    private void executeEjbc(SAXParser saxParser) throws BuildException {
+        IPlanetEjbc ejbc = new IPlanetEjbc(ejbdescriptor,
+                                            iasdescriptor,
+                                            dest,
+                                            getClasspath().toString(),
+                                            saxParser);
+        ejbc.setRetainSource(keepgenerated);
+        ejbc.setDebugOutput(debug);
+        if (iashome != null) {
+            ejbc.setIasHomeDir(iashome);
+        }
+
+        try {
+            ejbc.execute();
+        } catch (IOException e) {
+            String msg = "An IOException occurred while trying to read the XML "
+                            + "descriptor file: " + e.getMessage();
+            throw new BuildException(msg, e, getLocation());
+        } catch (SAXException e) {
+            String msg = "A SAXException occurred while trying to read the XML "
+                            + "descriptor file: " + e.getMessage();
+            throw new BuildException(msg, e, getLocation());
+        } catch (IPlanetEjbc.EjbcException e) {
+            String msg = "An exception occurred while trying to run the ejbc "
+                            + "utility: " + e.getMessage();
+            throw new BuildException(msg, e, getLocation());
+        }
+    }
+
+    /**
+     * Returns the CLASSPATH to be used when calling EJBc.  If no user CLASSPATH
+     * is specified, the System classpath is returned instead.
+     *
+     * @return Path The classpath to be used for EJBc.
+     */
+    private Path getClasspath() {
+        Path cp = null;
+        if (classpath == null) {
+            cp = (new Path(getProject())).concatSystemClasspath("last");
+        } else {
+            cp = classpath.concatSystemClasspath("ignore");
+        }
+
+        return cp;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java
new file mode 100644
index 0000000..e92d9879
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/InnerClassFilenameFilter.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FilenameFilter;
+
+/**
+ * A filename filter for inner class files of a particular class.
+ */
+public class InnerClassFilenameFilter implements FilenameFilter {
+    private String baseClassName;
+
+    /**
+     * Constructor of filter.
+     * @param baseclass the class to filter inner classes on.
+     */
+    InnerClassFilenameFilter(String baseclass) {
+        int extidx = baseclass.lastIndexOf(".class");
+        if (extidx == -1) {
+            extidx = baseclass.length() - 1;
+        }
+        baseClassName = baseclass.substring(0, extidx);
+    }
+
+    /**
+     * Check if the file name passes the filter.
+     * @param dir not used.
+     * @param filename the filename to filter on.
+     * @return true if the filename is an inner class of the base class.
+     */
+    public boolean accept(File dir, String filename) {
+        if ((filename.lastIndexOf(".") != filename.lastIndexOf(".class"))
+            || (filename.indexOf(baseClassName + "$") != 0)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java
new file mode 100644
index 0000000..a0286b1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JbossDeploymentTool.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.util.Hashtable;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * The deployment tool to add the jboss specific deployment descriptor to the ejb jar file.
+ * Jboss only requires one additional file jboss.xml and does not require any additional
+ * compilation.
+ *
+ * @version 1.0
+ * @see EjbJar#createJboss
+ */
+public class JbossDeploymentTool extends GenericDeploymentTool {
+    protected static final String JBOSS_DD = "jboss.xml";
+    protected static final String JBOSS_CMP10D = "jaws.xml";
+    protected static final String JBOSS_CMP20D = "jbosscmp-jdbc.xml";
+
+    /** Instance variable that stores the suffix for the jboss jarfile. */
+    private String jarSuffix = ".jar";
+
+    /**
+     * Setter used to store the suffix for the generated JBoss jar file.
+     * @param inString the string to use as the suffix.
+     */
+    public void setSuffix(String inString) {
+        jarSuffix = inString;
+    }
+
+    /**
+     * Add any vendor specific files which should be included in the
+     * EJB Jar.
+     * @param ejbFiles the hashtable of files to populate.
+     * @param ddPrefix the prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+        File jbossDD = new File(getConfig().descriptorDir, ddPrefix + JBOSS_DD);
+        if (jbossDD.exists()) {
+            ejbFiles.put(META_DIR + JBOSS_DD, jbossDD);
+        } else {
+            log("Unable to locate jboss deployment descriptor. "
+                + "It was expected to be in " + jbossDD.getPath(),
+                Project.MSG_WARN);
+            return;
+        }
+        String descriptorFileName = JBOSS_CMP10D;
+        if (EjbJar.CMPVersion.CMP2_0.equals(getParent().getCmpversion())) {
+            descriptorFileName = JBOSS_CMP20D;
+        }
+        File jbossCMPD
+            = new File(getConfig().descriptorDir, ddPrefix + descriptorFileName);
+
+        if (jbossCMPD.exists()) {
+            ejbFiles.put(META_DIR + descriptorFileName, jbossCMPD);
+        } else {
+            log("Unable to locate jboss cmp descriptor. "
+                + "It was expected to be in "
+                + jbossCMPD.getPath(), Project.MSG_VERBOSE);
+            return;
+        }
+    }
+
+    /**
+     * Get the vendor specific name of the Jar that will be output. The modification date
+     * of this jar will be checked against the dependent bean classes.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        if (getDestDir() == null && getParent().getDestdir() == null) {
+            throw new BuildException("DestDir not specified");
+        }
+        if (getDestDir() == null) {
+            return new File(getParent().getDestdir(), baseName + jarSuffix);
+        } else {
+            return new File(getDestDir(), baseName + jarSuffix);
+        }
+    }
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     *
+     * @throws BuildException If the Deployment Tool's configuration isn't
+     *                        valid
+     * @since ant 1.6
+     */
+    public void validateConfigured() throws BuildException {
+    }
+
+    private EjbJar getParent() {
+        return (EjbJar) this.getTask();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java
new file mode 100644
index 0000000..c8c1f62
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/JonasDeploymentTool.java
@@ -0,0 +1,823 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import javax.xml.parsers.SAXParser;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The deployment tool to add the jonas specific deployment descriptors to the
+ * ejb JAR file. JONAS only requires one additional file jonas-ejb-jar.xml.
+ *
+ * @version 1.0
+ * @see EjbJar#createJonas
+ */
+public class JonasDeploymentTool extends GenericDeploymentTool {
+
+    /** Public Id of the standard deployment descriptor DTD. */
+    protected static final String EJB_JAR_1_1_PUBLIC_ID
+        = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+    protected static final String EJB_JAR_2_0_PUBLIC_ID
+        = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+
+    /** Public Id of the JOnAS-specific deployment descriptor DTD. */
+    protected static final String JONAS_EJB_JAR_2_4_PUBLIC_ID
+        = "-//ObjectWeb//DTD JOnAS 2.4//EN";
+    protected static final String JONAS_EJB_JAR_2_5_PUBLIC_ID
+        = "-//ObjectWeb//DTD JOnAS 2.5//EN";
+
+    /** RMI ORB. */
+    protected static final String RMI_ORB = "RMI";
+
+    /** JEREMIE ORB. */
+    protected static final String JEREMIE_ORB = "JEREMIE";
+
+    /** DAVID ORB. */
+    protected static final String DAVID_ORB = "DAVID";
+
+    /**
+     * Name of the standard deployment descriptor DTD (these files are stored in
+     * the ${JONAS_ROOT}/xml directory).
+     */
+    protected static final String EJB_JAR_1_1_DTD = "ejb-jar_1_1.dtd";
+    protected static final String EJB_JAR_2_0_DTD = "ejb-jar_2_0.dtd";
+
+    /**
+     * Name of the JOnAS-specific deployment descriptor DTD (these files are
+     * stored in the ${JONAS_ROOT}/xml directory).
+     */
+    protected static final String JONAS_EJB_JAR_2_4_DTD
+        = "jonas-ejb-jar_2_4.dtd";
+    protected static final String JONAS_EJB_JAR_2_5_DTD
+        = "jonas-ejb-jar_2_5.dtd";
+
+    /** Default JOnAS deployment descriptor name. */
+    protected static final String JONAS_DD = "jonas-ejb-jar.xml";
+
+    /** GenIC class name (JOnAS 2.5) */
+    protected static final String GENIC_CLASS =
+    "org.objectweb.jonas_ejb.genic.GenIC";
+
+    /** Old GenIC class name (JOnAS 2.4.x). */
+    protected static final String OLD_GENIC_CLASS_1 =
+        "org.objectweb.jonas_ejb.tools.GenWholeIC";
+
+    /** Old GenIC class name. */
+    protected static final String OLD_GENIC_CLASS_2 =
+        "org.objectweb.jonas_ejb.tools.GenIC";
+
+    /**
+     * Filename of the standard EJB descriptor (which is passed to this class
+     * from the parent "ejbjar" task). This file is relative to the directory
+     * specified by the "srcdir" attribute in the ejbjar task.
+     */
+    private String descriptorName;
+
+    /**
+     * Filename of the JOnAS-specific EJB descriptor (which is passed to this
+     * class from the parent "ejbjar" task). This file is relative to the
+     * directory specified by the "srcdir" attribute in the ejbjar task.
+     */
+    private String jonasDescriptorName;
+
+    /* ------------- */
+    /* GenIC options */
+    /* ------------- */
+
+    /**
+     * Temporary output directory used by GenIC.
+     */
+    private File outputdir;
+
+    /**
+     * <code>true</code> if the intermediate Java source files generated by
+     * GenIC must be deleted or not. The default is <code>false</code>
+     */
+    private boolean keepgenerated = false;
+
+    /**
+     * <code>true</code> if the generated source files must not be compiled via
+     * the java and rmi compilers. The default is <code>false</code>.
+     */
+    private boolean nocompil = false;
+
+    /**
+     * <code>true</code> if the XML deployment descriptors must be parsed
+     * without validation. The default is <code>false</code>.
+     */
+    private boolean novalidation = false;
+
+    /**
+     * Java compiler to use. The default is the value of
+     * <code>build.compiler</code> property.
+     */
+    private String javac;
+
+    /** Options to pass to the java compiler. */
+    private String javacopts;
+
+    /** Options to pass to the rmi compiler. */
+    private String rmicopts;
+
+    /**
+     * Whether or not the RMI skeleton and stub must be modified to
+     * implement the implicit propagation of the security context (the
+     * transactional context is always provided). The default is
+     * <code>false</code>.
+     */
+    private boolean secpropag = false;
+
+    /**
+     * <code>true</code> if the GenIC call must be verbose. The default
+     * is <code>false</code>.
+     */
+    private boolean verbose = false;
+
+    /** Additional args to send to GenIC. */
+    private String additionalargs;
+
+    /* ------------- */
+    /* other options */
+    /* ------------- */
+
+    /** JOnAS root directory. */
+    private File jonasroot;
+
+    /**
+     * <code>true</code> if the generic JAR file used as input to GenIC must be
+     * retained. The default is <code>false</code>.
+     */
+    private boolean keepgeneric = false;
+
+    /** Stores the suffix for the JOnAS JAR file. The default is '.jar'. */
+    private String suffix = ".jar";
+
+    /**
+     *  ORB to use (RMI, JEREMIE or DAVID). If omitted, it defaults to the one
+     *  present in classpath. If specified, the corresponding JOnAS JAR is
+     *  automatically added to the classpath.
+     */
+    private String orb;
+
+    /**
+     * <code>true</code> if GenIC must not be run on the EJB JAR.
+     * The default is <code>false</code>.
+     */
+    private boolean nogenic = false;
+
+    /* -------------------- */
+    /* GenIC options setter */
+    /* -------------------- */
+
+    /**
+     * Sets the <code>keepgenerated</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setKeepgenerated(boolean aBoolean) {
+        keepgenerated = aBoolean;
+    }
+
+    /**
+     * Sets the additional arguments.
+     *
+     * @param aString additional args.
+     */
+    public void setAdditionalargs(String aString) {
+        additionalargs = aString;
+    }
+
+    /**
+     * Sets the <code>nocompil</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setNocompil(boolean aBoolean) {
+        nocompil = aBoolean;
+    }
+
+    /**
+     * Sets the <code>novalidation</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setNovalidation(boolean aBoolean) {
+        novalidation = aBoolean;
+    }
+
+    /**
+     * Sets the java compiler to use.
+     *
+     * @param aString the java compiler.
+     */
+    public void setJavac(String aString) {
+        javac = aString;
+    }
+
+    /**
+     * Set the options to pass to the java compiler.
+     *
+     * @param aString the options.
+     */
+    public void setJavacopts(String aString) {
+        javacopts = aString;
+    }
+
+    /**
+     * Set the options to pass to the rmi compiler.
+     *
+     * @param aString the options.
+     */
+    public void setRmicopts(String aString) {
+        rmicopts = aString;
+    }
+
+    /**
+     * Sets the <code>secpropag</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setSecpropag(boolean aBoolean) {
+        secpropag = aBoolean;
+    }
+
+    /**
+     * Sets the <code>verbose</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setVerbose(boolean aBoolean) {
+        verbose = aBoolean;
+    }
+
+    /* -------------------- */
+    /* other options setter */
+    /* -------------------- */
+
+    /**
+     * Set the JOnAS root directory.
+     *
+     * @param aFile the JOnAS root directory.
+     */
+    public void setJonasroot(File aFile) {
+        jonasroot = aFile;
+    }
+
+    /**
+     * Sets the <code>keepgeneric</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setKeepgeneric(boolean aBoolean) {
+        keepgeneric = aBoolean;
+    }
+
+    /**
+     * Sets the jar suffix.
+     *
+     * @param aString the string to use as the suffix.
+     */
+    public void setJarsuffix(String aString) {
+        suffix = aString;
+    }
+
+    /**
+     * Sets the <code>orb</code> to construct classpath.
+     *
+     * @param aString 'RMI', 'JEREMIE', or 'DAVID'.
+     */
+    public void setOrb(String aString) {
+        orb = aString;
+    }
+
+    /**
+     * Sets the <code>nogenic</code> flag.
+     *
+     * @param aBoolean <code>true</code> if the flag must be set.
+     */
+    public void setNogenic(boolean aBoolean) {
+        nogenic = aBoolean;
+    }
+
+    /* ------------- */
+    /* other methods */
+    /* ------------- */
+
+    /** {@inheritDoc}. */
+    public void processDescriptor(String aDescriptorName, SAXParser saxParser) {
+
+        descriptorName = aDescriptorName;
+
+        log("JOnAS Deployment Tool processing: " + descriptorName,
+            Project.MSG_VERBOSE);
+
+        super.processDescriptor(descriptorName, saxParser);
+
+        if (outputdir != null) {
+            // the method deleteOnExit() do not work because the directory is not empty
+            log("Deleting temp output directory '" + outputdir + "'.", Project.MSG_VERBOSE);
+            deleteAllFiles(outputdir);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    protected void writeJar(String baseName, File jarfile, Hashtable ejbFiles, String publicId)
+    throws BuildException {
+
+        // create the generic jar first
+        File genericJarFile = super.getVendorOutputJarFile(baseName);
+        super.writeJar(baseName, genericJarFile, ejbFiles, publicId);
+
+        // GenIC call on generic jar
+        addGenICGeneratedFiles(genericJarFile, ejbFiles);
+
+        // create the real jar
+        super.writeJar(baseName, getVendorOutputJarFile(baseName), ejbFiles, publicId);
+
+        if (!keepgeneric) {
+            log("Deleting generic JAR " + genericJarFile.toString(), Project.MSG_VERBOSE);
+            genericJarFile.delete();
+        }
+    }
+
+    /** {@inheritDoc}. */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+
+    // JOnAS-specific descriptor deployment
+    jonasDescriptorName = getJonasDescriptorName();
+        File jonasDD = new File(getConfig().descriptorDir, jonasDescriptorName);
+
+        if (jonasDD.exists()) {
+            ejbFiles.put(META_DIR + JONAS_DD, jonasDD);
+        } else {
+            log("Unable to locate the JOnAS deployment descriptor. It was expected to be in: "
+                + jonasDD.getPath() + ".", Project.MSG_WARN);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    protected File getVendorOutputJarFile(String baseName) {
+        return new File(getDestDir(), baseName + suffix);
+    }
+
+    /**
+     * Determines the name of the JOnAS-specific EJB descriptor using the
+     * specified standard EJB descriptor name. In general, the standard
+     * descriptor will be named "[basename]-ejb-jar.xml", and this method will
+     * return "[basename]-jonas-ejb-jar.xml" or "jonas-[basename].xml"
+     *
+     * @return The name of the JOnAS-specific EJB descriptor file.
+     */
+    private String getJonasDescriptorName() {
+
+        // descriptorName = <path><basename><basenameterminator><remainder>
+        // examples = /org/objectweb/fooAppli/foo/Foo-ejb-jar.xml
+        // examples = /org/objectweb/fooAppli/foo/Foo.xml (JOnAS convention)
+
+        String jonasDN; // JOnAS-specific DD
+        boolean jonasConvention = false; // true if the JOnAS convention is used for the DD
+        String path;            // Directory path of the EJB descriptor
+        String fileName;        // EJB descriptor file name
+        String baseName;        // Filename appearing before name terminator
+        String remainder;       // Filename appearing after the name terminator
+
+        int startOfFileName = descriptorName.lastIndexOf(File.separatorChar);
+        if (startOfFileName != -1) {
+            // extract path info
+            path = descriptorName.substring(0, startOfFileName + 1);
+            fileName = descriptorName.substring(startOfFileName + 1);
+        } else {
+            // descriptorName is just a file without path
+            path = "";
+            fileName = descriptorName;
+        }
+
+        if (fileName.startsWith(EJB_DD)) {
+            return path + JONAS_DD;
+        }
+
+        int endOfBaseName = descriptorName.indexOf(getConfig().baseNameTerminator, startOfFileName);
+
+        /*
+         * Check for the odd case where the terminator and/or filename
+         * extension aren't found.  These will ensure "jonas-" appears at the
+         * end of the name and before the '.' (if present).
+         */
+        if (endOfBaseName < 0) {
+            // baseNameTerminator not found: the descriptor use the
+            // JOnAS naming convention, ie [Foo.xml,jonas-Foo.xml] and
+            // not [Foo<baseNameTerminator>-ejb-jar.xml,
+            // Foo<baseNameTerminator>-jonas-ejb-jar.xml].
+            endOfBaseName = descriptorName.lastIndexOf('.') - 1;
+            if (endOfBaseName < 0) {
+                // no . found
+                endOfBaseName = descriptorName.length() - 1;
+            }
+
+            jonasConvention = true;
+        }
+
+        baseName = descriptorName.substring(startOfFileName + 1, endOfBaseName + 1);
+        remainder = descriptorName.substring(endOfBaseName + 1);
+
+        if (jonasConvention) {
+            jonasDN = path + "jonas-" + baseName + ".xml";
+        } else {
+            jonasDN = path + baseName + "jonas-" + remainder;
+        }
+
+        log("Standard EJB descriptor name: " + descriptorName, Project.MSG_VERBOSE);
+        log("JOnAS-specific descriptor name: " + jonasDN, Project.MSG_VERBOSE);
+
+        return jonasDN;
+    }
+
+    /** {@inheritDoc}. */
+    protected String getJarBaseName(String descriptorFileName) {
+
+        String baseName = null;
+
+        if (getConfig().namingScheme.getValue().equals(EjbJar.NamingScheme.DESCRIPTOR)) {
+
+            // try to find JOnAS specific convention name
+            if (descriptorFileName.indexOf(getConfig().baseNameTerminator) == -1) {
+
+                // baseNameTerminator not found: the descriptor use the
+                // JOnAS naming convention, ie [Foo.xml,jonas-Foo.xml] and
+                // not [Foo<baseNameTerminator>-ejb-jar.xml,
+                // Foo<baseNameTerminator>-jonas-ejb-jar.xml].
+
+                String aCanonicalDescriptor = descriptorFileName.replace('\\', '/');
+                int lastSeparatorIndex = aCanonicalDescriptor.lastIndexOf('/');
+                int endOfBaseName;
+
+                if (lastSeparatorIndex != -1) {
+                    endOfBaseName = descriptorFileName.indexOf(".xml", lastSeparatorIndex);
+                } else {
+                    endOfBaseName = descriptorFileName.indexOf(".xml");
+                }
+
+                if (endOfBaseName != -1) {
+                    baseName = descriptorFileName.substring(0, endOfBaseName);
+                }
+            }
+        }
+
+        if (baseName == null) {
+            // else get standard baseName
+            baseName = super.getJarBaseName(descriptorFileName);
+        }
+
+        log("JAR base name: " + baseName, Project.MSG_VERBOSE);
+
+        return baseName;
+    }
+
+    /** {@inheritDoc}. */
+    protected void registerKnownDTDs(DescriptorHandler handler) {
+        handler.registerDTD(EJB_JAR_1_1_PUBLIC_ID,
+                    jonasroot + File.separator + "xml" + File.separator + EJB_JAR_1_1_DTD);
+        handler.registerDTD(EJB_JAR_2_0_PUBLIC_ID,
+                    jonasroot + File.separator + "xml" + File.separator + EJB_JAR_2_0_DTD);
+
+        handler.registerDTD(JONAS_EJB_JAR_2_4_PUBLIC_ID,
+                    jonasroot + File.separator + "xml" + File.separator + JONAS_EJB_JAR_2_4_DTD);
+        handler.registerDTD(JONAS_EJB_JAR_2_5_PUBLIC_ID,
+                    jonasroot + File.separator + "xml" + File.separator + JONAS_EJB_JAR_2_5_DTD);
+    }
+
+    /**
+     * Add to the given hashtable all the file generated by GenIC.
+     *
+     * @param genericJarFile jar file.
+     * @param ejbFiles the hashtable.
+     */
+    private void addGenICGeneratedFiles(
+        File genericJarFile, Hashtable ejbFiles) {
+        Java genicTask = null;    // GenIC task
+        String genicClass = null; // GenIC class (3 are supported for various
+                                  // versions
+        if (nogenic) {
+            return;
+        }
+
+        genicTask = new Java(getTask());
+        genicTask.setTaskName("genic");
+        genicTask.setFork(true);
+
+        // jonasroot
+        genicTask.createJvmarg().setValue("-Dinstall.root=" + jonasroot);
+
+        // java policy file
+        String jonasConfigDir = jonasroot + File.separator + "config";
+        File javaPolicyFile = new File(jonasConfigDir, "java.policy");
+        if (javaPolicyFile.exists()) {
+            genicTask.createJvmarg().setValue("-Djava.security.policy="
+                              + javaPolicyFile.toString());
+        }
+
+        // outputdir
+        try {
+            outputdir = createTempDir();
+        } catch (IOException aIOException) {
+            String msg = "Cannot create temp dir: " + aIOException.getMessage();
+            throw new BuildException(msg, aIOException);
+        }
+        log("Using temporary output directory: " + outputdir, Project.MSG_VERBOSE);
+
+        genicTask.createArg().setValue("-d");
+        genicTask.createArg().setFile(outputdir);
+
+        // work around a bug of GenIC 2.5
+        String key;
+        File f;
+        Enumeration keys = ejbFiles.keys();
+        while (keys.hasMoreElements()) {
+            key = (String) keys.nextElement();
+            f = new File(outputdir + File.separator + key);
+            f.getParentFile().mkdirs();
+        }
+        log("Worked around a bug of GenIC 2.5.", Project.MSG_VERBOSE);
+
+        // classpath
+        Path classpath = getCombinedClasspath();
+        if (classpath == null) {
+            classpath = new Path(getTask().getProject());
+        }
+        classpath.append(new Path(classpath.getProject(), jonasConfigDir));
+        classpath.append(new Path(classpath.getProject(), outputdir.toString()));
+
+        // try to create the classpath for the correct ORB
+        if (orb != null) {
+            String orbJar = jonasroot + File.separator + "lib"
+                + File.separator + orb + "_jonas.jar";
+            classpath.append(new Path(classpath.getProject(), orbJar));
+        }
+        log("Using classpath: " + classpath.toString(), Project.MSG_VERBOSE);
+        genicTask.setClasspath(classpath);
+
+        // class name (search in the classpath provided for the ejbjar element)
+        genicClass = getGenicClassName(classpath);
+        if (genicClass == null) {
+            log("Cannot find GenIC class in classpath.", Project.MSG_ERR);
+            throw new BuildException("GenIC class not found, please check the classpath.");
+        } else {
+            log("Using '" + genicClass + "' GenIC class." , Project.MSG_VERBOSE);
+            genicTask.setClassname(genicClass);
+        }
+
+        // keepgenerated
+        if (keepgenerated) {
+            genicTask.createArg().setValue("-keepgenerated");
+        }
+
+        // nocompil
+        if (nocompil) {
+            genicTask.createArg().setValue("-nocompil");
+        }
+
+        // novalidation
+        if (novalidation) {
+            genicTask.createArg().setValue("-novalidation");
+        }
+
+        // javac
+        if (javac != null) {
+            genicTask.createArg().setValue("-javac");
+            genicTask.createArg().setLine(javac);
+        }
+
+        // javacopts
+        if (javacopts != null && !javacopts.equals("")) {
+            genicTask.createArg().setValue("-javacopts");
+            genicTask.createArg().setLine(javacopts);
+        }
+
+        // rmicopts
+        if (rmicopts != null && !rmicopts.equals("")) {
+            genicTask.createArg().setValue("-rmicopts");
+            genicTask.createArg().setLine(rmicopts);
+        }
+
+        // secpropag
+        if (secpropag) {
+            genicTask.createArg().setValue("-secpropag");
+        }
+
+        // verbose
+        if (verbose) {
+            genicTask.createArg().setValue("-verbose");
+        }
+
+        // additionalargs
+        if (additionalargs != null) {
+            genicTask.createArg().setValue(additionalargs);
+        }
+
+        // the generated classes must not be added in the generic JAR!
+        // is that buggy on old JOnAS (2.4) ??
+        genicTask.createArg().setValue("-noaddinjar");
+
+        // input file to process by GenIC
+        genicTask.createArg().setValue(genericJarFile.getPath());
+
+        // calling GenIC task
+        log("Calling " + genicClass + " for " + getConfig().descriptorDir
+            + File.separator + descriptorName + ".", Project.MSG_VERBOSE);
+
+        if (genicTask.executeJava() != 0) {
+
+            // the method deleteOnExit() do not work because the directory is not empty
+            log("Deleting temp output directory '" + outputdir + "'.", Project.MSG_VERBOSE);
+            deleteAllFiles(outputdir);
+
+            if (!keepgeneric) {
+                log("Deleting generic JAR " + genericJarFile.toString(),
+                    Project.MSG_VERBOSE);
+                genericJarFile.delete();
+            }
+
+            throw new BuildException("GenIC reported an error.");
+        }
+
+        // add the generated files to the ejbFiles
+        addAllFiles(outputdir, "", ejbFiles);
+    }
+
+    /**
+     * Get the GenIC class name to use in the given classpath.
+     *
+     * @param classpath classpath where the GenIC class must be searched.
+     * @return the GenIC class name. Return <code>null</code> if the class name
+     * cannot be found.
+     */
+    String getGenicClassName(Path classpath) {
+
+        log("Looking for GenIC class in classpath: "
+            + classpath.toString(), Project.MSG_VERBOSE);
+
+        AntClassLoader cl = classpath.getProject().createClassLoader(classpath);
+
+        try {
+            cl.loadClass(JonasDeploymentTool.GENIC_CLASS);
+            log("Found GenIC class '" + JonasDeploymentTool.GENIC_CLASS
+                + "' in classpath.", Project.MSG_VERBOSE);
+            return JonasDeploymentTool.GENIC_CLASS;
+
+        } catch (ClassNotFoundException cnf1) {
+            log("GenIC class '" + JonasDeploymentTool.GENIC_CLASS
+                + "' not found in classpath.",
+            Project.MSG_VERBOSE);
+        }
+
+        try {
+            cl.loadClass(JonasDeploymentTool.OLD_GENIC_CLASS_1);
+            log("Found GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_1
+                + "' in classpath.", Project.MSG_VERBOSE);
+            return JonasDeploymentTool.OLD_GENIC_CLASS_1;
+
+        } catch (ClassNotFoundException cnf2) {
+            log("GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_1
+                + "' not found in classpath.",
+            Project.MSG_VERBOSE);
+        }
+
+        try {
+            cl.loadClass(JonasDeploymentTool.OLD_GENIC_CLASS_2);
+            log("Found GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_2
+                + "' in classpath.", Project.MSG_VERBOSE);
+            return JonasDeploymentTool.OLD_GENIC_CLASS_2;
+
+        } catch (ClassNotFoundException cnf3) {
+            log("GenIC class '" + JonasDeploymentTool.OLD_GENIC_CLASS_2
+                + "' not found in classpath.",
+            Project.MSG_VERBOSE);
+        }
+        return null;
+    }
+
+    /**
+     * Verify the configuration.
+     * @param descriptorFileName the name of the descriptor file.
+     * @param saxParser          not used.
+     * @throws BuildException if there is an error.
+     */
+    protected void checkConfiguration(String descriptorFileName,
+                      SAXParser saxParser) throws BuildException {
+
+        // jonasroot
+        if (jonasroot == null) {
+            throw new BuildException("The jonasroot attribut is not set.");
+        } else if (!jonasroot.isDirectory()) {
+            throw new BuildException("The jonasroot attribut '" + jonasroot
+                + "' is not a valid directory.");
+        }
+
+        // orb
+        if (orb != null && !orb.equals(RMI_ORB) && !orb.equals(JEREMIE_ORB)
+            && !orb.equals(DAVID_ORB)) {
+            throw new BuildException("The orb attribut '" + orb
+                + "' is not valid (must be either "
+                + RMI_ORB + ", " + JEREMIE_ORB + " or " + DAVID_ORB + ").");
+        }
+
+        // additionalargs
+        if (additionalargs != null && additionalargs.equals("")) {
+            throw new BuildException("Empty additionalargs attribut.");
+        }
+
+        // javac
+        if (javac != null && javac.equals("")) {
+            throw new BuildException("Empty javac attribut.");
+        }
+    }
+
+    /* ----------------------------------------------------------------------------------- */
+    /* utilitary methods */
+    /* ----------------------------------------------------------------------------------- */
+
+    /**
+     * Create a temporary directory for GenIC output.
+     *
+     * @return the temp directory.
+     * @throws BuildException if a temp directory cannot be created.
+     */
+    private File createTempDir() throws IOException {
+        File tmpDir = File.createTempFile("genic", null, null);
+        tmpDir.delete();
+        if (!tmpDir.mkdir()) {
+            throw new IOException("Cannot create the temporary directory '" + tmpDir + "'.");
+        }
+        return tmpDir;
+    }
+
+    /**
+     * Delete a file. If the file is a directory, delete recursivly all the
+     * files inside.
+     *
+     * @param aFile file to delete.
+     */
+    private void deleteAllFiles(File aFile) {
+        if (aFile.isDirectory()) {
+            File[] someFiles = aFile.listFiles();
+
+            for (int i = 0; i < someFiles.length; i++) {
+                deleteAllFiles(someFiles[i]);
+            }
+        }
+        aFile.delete();
+    }
+
+    /**
+     * Add a file to the a given hashtable. If the file is a directory, add
+     * recursivly all the files inside to the hashtable.
+     *
+     * @param file the file to add.
+     * @param rootDir the current sub-directory to scan.
+     * @param hashtable the hashtable where to add the files.
+     */
+    private void addAllFiles(File file, String rootDir, Hashtable hashtable) {
+
+        if (!file.exists()) {
+            throw new IllegalArgumentException();
+        }
+
+        String newRootDir;
+        if (file.isDirectory()) {
+            File[] files = file.listFiles();
+            for (int i = 0; i < files.length; i++) {
+                if (rootDir.length() > 0) {
+                    newRootDir = rootDir + File.separator + files[i].getName();
+                } else {
+                    newRootDir = files[i].getName();
+                }
+                addAllFiles(files[i], newRootDir, hashtable);
+            }
+        } else {
+            hashtable.put(rootDir, file);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java
new file mode 100644
index 0000000..1950664
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicDeploymentTool.java
@@ -0,0 +1,928 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+import org.xml.sax.InputSource;
+
+/**
+    The weblogic element is used to control the weblogic.ejbc compiler for
+    generating weblogic EJB jars. Prior to Ant 1.3, the method of locating CMP
+    descriptors was to use the ejbjar naming convention. So if your ejb-jar was
+    called, Customer-ejb-jar.xml, your weblogic descriptor was called Customer-
+    weblogic-ejb-jar.xml and your CMP descriptor had to be Customer-weblogic-cmp-
+    rdbms-jar.xml. In addition, the &lt;type-storage&gt; element in the weblogic
+    descriptor had to be set to the standard name META-INF/weblogic-cmp-rdbms-
+    jar.xml, as that is where the CMP descriptor was mapped to in the generated
+    jar.
+*/
+public class WeblogicDeploymentTool extends GenericDeploymentTool {
+    /** EJB11 id */
+    public static final String PUBLICID_EJB11
+         = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+    /** EJB20 id */
+    public static final String PUBLICID_EJB20
+         = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+    /** Weblogic 5.1.0 id */
+    public static final String PUBLICID_WEBLOGIC_EJB510
+         = "-//BEA Systems, Inc.//DTD WebLogic 5.1.0 EJB//EN";
+    /** Weblogic 6.0.0 id */
+    public static final String PUBLICID_WEBLOGIC_EJB600
+         = "-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN";
+    /** Weblogic 7.0.0 id */
+    public static final String PUBLICID_WEBLOGIC_EJB700
+         = "-//BEA Systems, Inc.//DTD WebLogic 7.0.0 EJB//EN";
+
+    /** Weblogic 5.1 dtd location */
+    protected static final String DEFAULT_WL51_EJB11_DTD_LOCATION
+         = "/weblogic/ejb/deployment/xml/ejb-jar.dtd";
+    /** Weblogic 6.0 ejb 1.1 dtd location */
+    protected static final String DEFAULT_WL60_EJB11_DTD_LOCATION
+         = "/weblogic/ejb20/dd/xml/ejb11-jar.dtd";
+    /** Weblogic 6.0 ejb 2.0 dtd location */
+    protected static final String DEFAULT_WL60_EJB20_DTD_LOCATION
+         = "/weblogic/ejb20/dd/xml/ejb20-jar.dtd";
+
+    protected static final String DEFAULT_WL51_DTD_LOCATION
+         = "/weblogic/ejb/deployment/xml/weblogic-ejb-jar.dtd";
+    protected static final String DEFAULT_WL60_51_DTD_LOCATION
+         = "/weblogic/ejb20/dd/xml/weblogic510-ejb-jar.dtd";
+    protected static final String DEFAULT_WL60_DTD_LOCATION
+         = "/weblogic/ejb20/dd/xml/weblogic600-ejb-jar.dtd";
+    protected static final String DEFAULT_WL70_DTD_LOCATION
+         = "/weblogic/ejb20/dd/xml/weblogic700-ejb-jar.dtd";
+
+    protected static final String DEFAULT_COMPILER = "default";
+
+    protected static final String WL_DD = "weblogic-ejb-jar.xml";
+    protected static final String WL_CMP_DD = "weblogic-cmp-rdbms-jar.xml";
+
+    protected static final String COMPILER_EJB11 = "weblogic.ejbc";
+    protected static final String COMPILER_EJB20 = "weblogic.ejbc20";
+
+    /** File utilities instance for copying jars */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Instance variable that stores the suffix for the weblogic jarfile. */
+    private String jarSuffix = ".jar";
+
+    /** Instance variable that stores the location of the weblogic DTD file. */
+    private String weblogicDTD;
+
+    /** Instance variable that stores the location of the ejb 1.1 DTD file. */
+    private String ejb11DTD;
+
+    /** Instance variable that determines whether generic ejb jars are kept. */
+    private boolean keepgenerated = false;
+
+    /**
+     * Instance variable that stores the fully qualified classname of the
+     * weblogic EJBC compiler
+     */
+    private String ejbcClass = null;
+
+    private String additionalArgs = "";
+
+    /**
+     * additional args to pass to the spawned jvm
+     */
+    private String additionalJvmArgs = "";
+
+    private boolean keepGeneric = false;
+
+    private String compiler = null;
+
+    private boolean alwaysRebuild = true;
+
+    /** controls whether ejbc is run on the generated jar */
+    private boolean noEJBC = false;
+
+    /** Indicates if the old CMP location convention is to be used.  */
+    private boolean newCMP = false;
+
+    /** The classpath to the weblogic classes. */
+    private Path wlClasspath = null;
+
+    /** System properties for the JVM. */
+    private Vector sysprops = new Vector();
+
+    /**
+     * The weblogic.StdoutSeverityLevel to use when running the JVM that
+     * executes ejbc. Set to 16 to avoid the warnings about EJB Home and
+     * Remotes being in the classpath
+     */
+    private Integer jvmDebugLevel = null;
+
+    private File outputDir;
+
+    /**
+     * Add a nested sysproperty element.
+     * @param sysp the element to add.
+     */
+    public void addSysproperty(Environment.Variable sysp) {
+        sysprops.add(sysp);
+    }
+
+
+    /**
+     * Get the classpath to the weblogic classpaths.
+     * @return the classpath to configure.
+     */
+    public Path createWLClasspath() {
+        if (wlClasspath == null) {
+            wlClasspath = new Path(getTask().getProject());
+        }
+        return wlClasspath.createPath();
+    }
+
+    /**
+     * If set ejbc will use this directory as the output
+     * destination rather than a jar file. This allows for the
+     * generation of &quot;exploded&quot; jars.
+     * @param outputDir the directory to be used.
+     */
+    public void setOutputDir(File outputDir) {
+        this.outputDir = outputDir;
+    }
+
+
+    /**
+     * Optional classpath to WL6.0.
+     * Weblogic 6.0 will give a warning if the home and remote interfaces
+     * of a bean are on the system classpath used to run weblogic.ejbc.
+     * In that case, the standard weblogic classes should be set with
+     * this attribute (or equivalent nested element) and the
+     * home and remote interfaces located with the standard classpath
+     * attribute.
+     * @param wlClasspath the path to be used.
+     */
+    public void setWLClasspath(Path wlClasspath) {
+        this.wlClasspath = wlClasspath;
+    }
+
+
+    /**
+     * The compiler (switch <code>-compiler</code>) to use; optional.
+     * This allows for the selection of a different compiler
+     * to be used for the compilation of the generated Java
+     * files. This could be set, for example, to Jikes to
+     * compile with the Jikes compiler. If this is not set
+     * and the <code>build.compiler</code> property is set
+     * to jikes, the Jikes compiler will be used. If this
+     * is not desired, the value &quot;<code>default</code>&quot;
+     * may be given to use the default compiler.
+     * @param compiler the compiler to be used.
+     */
+    public void setCompiler(String compiler) {
+        this.compiler = compiler;
+    }
+
+
+    /**
+     * Set the rebuild flag to false to only update changes in the jar rather
+     * than rerunning ejbc; optional, default true.
+     * This flag controls whether weblogic.ejbc is always
+     * invoked to build the jar file. In certain circumstances,
+     * such as when only a bean class has been changed, the jar
+     * can be generated by merely replacing the changed classes
+     * and not rerunning ejbc. Setting this to false will reduce
+     * the time to run ejbjar.
+     * @param rebuild a <code>boolean</code> value.
+     */
+    public void setRebuild(boolean rebuild) {
+        this.alwaysRebuild = rebuild;
+    }
+
+
+    /**
+     * Sets the weblogic.StdoutSeverityLevel to use when running the JVM that
+     * executes ejbc; optional. Set to 16 to avoid the warnings about EJB Home and
+     * Remotes being in the classpath
+     * @param jvmDebugLevel the value to use.
+     */
+    public void setJvmDebugLevel(Integer jvmDebugLevel) {
+        this.jvmDebugLevel = jvmDebugLevel;
+    }
+
+
+    /**
+     * Get the debug level.
+     * @return the jvm debug level (may be null).
+     */
+    public Integer getJvmDebugLevel() {
+        return jvmDebugLevel;
+    }
+
+
+
+    /**
+     * Setter used to store the suffix for the generated weblogic jar file.
+     *
+     * @param inString the string to use as the suffix.
+     */
+    public void setSuffix(String inString) {
+        this.jarSuffix = inString;
+    }
+
+
+    /**
+     * controls whether the generic file used as input to
+     * ejbc is retained; defaults to false
+     *
+     * @param inValue true for keep generic
+     */
+    public void setKeepgeneric(boolean inValue) {
+        this.keepGeneric = inValue;
+    }
+
+
+    /**
+     * Controls whether weblogic will keep the generated Java
+     * files used to build the class files added to the
+     * jar. This can be useful when debugging; default is false.
+     *
+     * @param inValue either 'true' or 'false'
+     */
+    public void setKeepgenerated(String inValue) {
+        this.keepgenerated = Boolean.valueOf(inValue).booleanValue();
+    }
+
+
+    /**
+     * Any optional extra arguments pass to the weblogic.ejbc
+     * tool.
+     * @param args extra arguments to pass to the ejbc tool.
+     */
+    public void setArgs(String args) {
+        this.additionalArgs = args;
+    }
+
+
+    /**
+     * Set any additional arguments to pass to the weblogic JVM; optional.
+     * @param args the arguments to be passed to the JVM
+     */
+    public void setJvmargs(String args) {
+        this.additionalJvmArgs = args;
+    }
+
+    /**
+     * Set the classname of the ejbc compiler;  optional
+     * Normally ejbjar determines
+     * the appropriate class based on the DTD used for the EJB. The EJB 2.0 compiler
+     * featured in weblogic 6 has, however, been deprecated in version 7. When
+     * using with version 7 this attribute should be set to
+     * &quot;weblogic.ejbc&quot; to avoid the deprecation warning.
+     * @param ejbcClass the name of the class to use.
+     */
+    public void setEjbcClass(String ejbcClass) {
+        this.ejbcClass = ejbcClass;
+    }
+
+
+    /**
+     * Get the ejbc compiler class.
+     * @return the name of the ejbc compiler class.
+     */
+    public String getEjbcClass() {
+        return ejbcClass;
+    }
+
+
+    /**
+     * <b>Deprecated</b>. Defines the location of the ejb-jar DTD in
+     *  the weblogic class hierarchy. Should not be needed, and the
+     * nested &lt;dtd&gt; element is recommended when it is.
+     *
+     * @param inString the string to use as the DTD location.
+     */
+    public void setWeblogicdtd(String inString) {
+        setEJBdtd(inString);
+    }
+
+
+    /**
+     * <b>Deprecated</b>. Defines the location of weblogic DTD in
+     *  the weblogic class hierarchy. Should not be needed, and the
+     * nested &lt;dtd&gt; element is recommended when it is.
+     *
+     * @param inString the string to use as the DTD location.
+     */
+    public void setWLdtd(String inString) {
+        this.weblogicDTD = inString;
+    }
+
+
+    /**
+     * <b>Deprecated</b>. Defines the location of Sun's EJB DTD in
+     *  the weblogic class hierarchy. Should not be needed, and the
+     * nested &lt;dtd&gt; element is recommended when it is.
+     *
+     * @param inString the string to use as the DTD location.
+     */
+    public void setEJBdtd(String inString) {
+        this.ejb11DTD = inString;
+    }
+
+
+    /**
+     * Set the value of the oldCMP scheme. This is an antonym for newCMP
+     * @ant.attribute ignore="true'
+     * @param oldCMP a <code>boolean</code> value.
+     */
+    public void setOldCMP(boolean oldCMP) {
+        this.newCMP = !oldCMP;
+    }
+
+
+    /**
+     * If this is set to true, the new method for locating
+     * CMP descriptors will be used; optional, default false.
+     * <P>
+     * The old CMP scheme locates the
+     * weblogic CMP descriptor based on the naming convention where the
+     * weblogic CMP file is expected to be named with the bean name as the
+     * prefix. Under this scheme the name of the CMP descriptor does not match
+     * the name actually used in the main weblogic EJB descriptor. Also,
+     * descriptors which contain multiple CMP references could not be used.
+     * @param newCMP a <code>boolean</code> value.
+     */
+    public void setNewCMP(boolean newCMP) {
+        this.newCMP = newCMP;
+    }
+
+
+    /**
+     * Do not EJBC the jar after it has been put together;
+     * optional, default false
+     * @param noEJBC a <code>boolean</code> value.
+     */
+    public void setNoEJBC(boolean noEJBC) {
+        this.noEJBC = noEJBC;
+    }
+
+
+    /**
+     * Register the DTDs.
+     * @param handler the handler to use.
+     */
+    protected void registerKnownDTDs(DescriptorHandler handler) {
+        // register all the known DTDs
+        handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL51_EJB11_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_EJB11, DEFAULT_WL60_EJB11_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
+        handler.registerDTD(PUBLICID_EJB20, DEFAULT_WL60_EJB20_DTD_LOCATION);
+    }
+
+
+    /**
+     * Get the weblogic descriptor handler.
+     * @param srcDir the source directory.
+     * @return the descriptor.
+     */
+    protected DescriptorHandler getWeblogicDescriptorHandler(final File srcDir) {
+        DescriptorHandler handler =
+            new DescriptorHandler(getTask(), srcDir) {
+                protected void processElement() {
+                    if (currentElement.equals("type-storage")) {
+                        // Get the filename of vendor specific descriptor
+                        String fileNameWithMETA = currentText;
+                        //trim the META_INF\ off of the file name
+                        String fileName
+                             = fileNameWithMETA.substring(META_DIR.length(),
+                            fileNameWithMETA.length());
+                        File descriptorFile = new File(srcDir, fileName);
+
+                        ejbFiles.put(fileNameWithMETA, descriptorFile);
+                    }
+                }
+            };
+
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL51_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, DEFAULT_WL60_51_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, DEFAULT_WL60_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB700, DEFAULT_WL70_DTD_LOCATION);
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB510, weblogicDTD);
+        handler.registerDTD(PUBLICID_WEBLOGIC_EJB600, weblogicDTD);
+
+        for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+            EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+            handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+        }
+        return handler;
+    }
+
+
+    /**
+     * Add any vendor specific files which should be included in the EJB Jar.
+     * @param ejbFiles the hash table to be populated.
+     * @param ddPrefix the prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+        File weblogicDD = new File(getConfig().descriptorDir, ddPrefix + WL_DD);
+
+        if (weblogicDD.exists()) {
+            ejbFiles.put(META_DIR + WL_DD,
+                weblogicDD);
+        } else {
+            log("Unable to locate weblogic deployment descriptor. "
+                + "It was expected to be in "
+                + weblogicDD.getPath(), Project.MSG_WARN);
+            return;
+        }
+
+        if (!newCMP) {
+            log("The old method for locating CMP files has been DEPRECATED.", Project.MSG_VERBOSE);
+            log("Please adjust your weblogic descriptor and set "
+                + "newCMP=\"true\" to use the new CMP descriptor "
+                + "inclusion mechanism. ", Project.MSG_VERBOSE);
+            // The the weblogic cmp deployment descriptor
+            File weblogicCMPDD = new File(getConfig().descriptorDir, ddPrefix + WL_CMP_DD);
+
+            if (weblogicCMPDD.exists()) {
+                ejbFiles.put(META_DIR + WL_CMP_DD,
+                    weblogicCMPDD);
+            }
+        } else {
+            // now that we have the weblogic descriptor, we parse the file
+            // to find other descriptors needed to deploy the bean.
+            // this could be the weblogic-cmp-rdbms.xml or any other O/R
+            // mapping tool descriptors.
+            try {
+                File ejbDescriptor = (File) ejbFiles.get(META_DIR + EJB_DD);
+                SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+
+                saxParserFactory.setValidating(true);
+
+                SAXParser saxParser = saxParserFactory.newSAXParser();
+                DescriptorHandler handler
+                    = getWeblogicDescriptorHandler(ejbDescriptor.getParentFile());
+
+                saxParser.parse(new InputSource
+                    (new FileInputStream(weblogicDD)),
+                        handler);
+
+                Hashtable ht = handler.getFiles();
+                Enumeration e = ht.keys();
+
+                while (e.hasMoreElements()) {
+                    String key = (String) e.nextElement();
+
+                    ejbFiles.put(key, ht.get(key));
+                }
+            } catch (Exception e) {
+                String msg = "Exception while adding Vendor specific files: " + e.toString();
+
+                throw new BuildException(msg, e);
+            }
+        }
+    }
+
+
+    /**
+     * Get the vendor specific name of the Jar that will be output. The
+     * modification date of this jar will be checked against the dependent
+     * bean classes.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        return new File(getDestDir(), baseName + jarSuffix);
+    }
+
+
+    /**
+     * Helper method invoked by execute() for each WebLogic jar to be built.
+     * Encapsulates the logic of constructing a java task for calling
+     * weblogic.ejbc and executing it.
+     *
+     * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
+     * @param destJar java.io.File representing the destination, WebLogic
+     *      jarfile.
+     */
+    private void buildWeblogicJar(File sourceJar, File destJar, String publicId) {
+        Java javaTask = null;
+
+        if (noEJBC) {
+            try {
+                FILE_UTILS.copyFile(sourceJar, destJar);
+                if (!keepgenerated) {
+                    sourceJar.delete();
+                }
+                return;
+            } catch (IOException e) {
+                throw new BuildException("Unable to write EJB jar", e);
+            }
+        }
+
+        String ejbcClassName = ejbcClass;
+
+        try {
+            javaTask = new Java(getTask());
+            javaTask.setTaskName("ejbc");
+
+            javaTask.createJvmarg().setLine(additionalJvmArgs);
+            if (!(sysprops.isEmpty())) {
+                for (Enumeration en = sysprops.elements(); en.hasMoreElements();) {
+                    Environment.Variable entry
+                        = (Environment.Variable) en.nextElement();
+                    javaTask.addSysproperty(entry);
+                }
+            }
+
+            if (getJvmDebugLevel() != null) {
+                javaTask.createJvmarg().setLine(" -Dweblogic.StdoutSeverityLevel=" + jvmDebugLevel);
+            }
+
+            if (ejbcClassName == null) {
+                // try to determine it from publicId
+                if (PUBLICID_EJB11.equals(publicId)) {
+                    ejbcClassName = COMPILER_EJB11;
+                } else if (PUBLICID_EJB20.equals(publicId)) {
+                    ejbcClassName = COMPILER_EJB20;
+                } else {
+                    log("Unrecognized publicId " + publicId
+                        + " - using EJB 1.1 compiler", Project.MSG_WARN);
+                    ejbcClassName = COMPILER_EJB11;
+                }
+            }
+
+            javaTask.setClassname(ejbcClassName);
+            javaTask.createArg().setLine(additionalArgs);
+            if (keepgenerated) {
+                javaTask.createArg().setValue("-keepgenerated");
+            }
+            if (compiler == null) {
+                // try to use the compiler specified by build.compiler.
+                // Right now we are just going to allow Jikes
+                String buildCompiler
+                    = getTask().getProject().getProperty("build.compiler");
+
+                if (buildCompiler != null && buildCompiler.equals("jikes")) {
+                    javaTask.createArg().setValue("-compiler");
+                    javaTask.createArg().setValue("jikes");
+                }
+            } else {
+                if (!compiler.equals(DEFAULT_COMPILER)) {
+                    javaTask.createArg().setValue("-compiler");
+                    javaTask.createArg().setLine(compiler);
+                }
+            }
+
+            Path combinedClasspath = getCombinedClasspath();
+            if (wlClasspath != null && combinedClasspath != null
+                 && combinedClasspath.toString().trim().length() > 0) {
+                javaTask.createArg().setValue("-classpath");
+                javaTask.createArg().setPath(combinedClasspath);
+            }
+
+            javaTask.createArg().setValue(sourceJar.getPath());
+            if (outputDir == null) {
+                javaTask.createArg().setValue(destJar.getPath());
+            } else {
+                javaTask.createArg().setValue(outputDir.getPath());
+            }
+
+            Path classpath = wlClasspath;
+
+            if (classpath == null) {
+                classpath = getCombinedClasspath();
+            }
+
+            javaTask.setFork(true);
+            if (classpath != null) {
+                javaTask.setClasspath(classpath);
+            }
+
+            log("Calling " + ejbcClassName + " for " + sourceJar.toString(),
+                Project.MSG_VERBOSE);
+
+            if (javaTask.executeJava() != 0) {
+                throw new BuildException("Ejbc reported an error");
+            }
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling " + ejbcClassName
+                + ". Details: " + e.toString();
+
+            throw new BuildException(msg, e);
+        }
+    }
+
+
+    /**
+     * Method used to encapsulate the writing of the JAR file. Iterates over
+     * the filenames/java.io.Files in the Hashtable stored on the instance
+     * variable ejbFiles.
+     * @param baseName the base name.
+     * @param jarFile the jar file to populate.
+     * @param files   the hash table of files to write.
+     * @param publicId the id to use.
+     * @throws BuildException if there is a problem.
+     */
+    protected void writeJar(String baseName, File jarFile, Hashtable files,
+                            String publicId) throws BuildException {
+        // need to create a generic jar first.
+        File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+        super.writeJar(baseName, genericJarFile, files, publicId);
+
+        if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+            buildWeblogicJar(genericJarFile, jarFile, publicId);
+        }
+        if (!keepGeneric) {
+            log("deleting generic jar " + genericJarFile.toString(),
+                Project.MSG_VERBOSE);
+            genericJarFile.delete();
+        }
+    }
+
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     * @throws BuildException if there is an error.
+     */
+    public void validateConfigured() throws BuildException {
+        super.validateConfigured();
+    }
+
+
+    /**
+     * Helper method to check to see if a weblogic EBJ1.1 jar needs to be
+     * rebuilt using ejbc. Called from writeJar it sees if the "Bean" classes
+     * are the only thing that needs to be updated and either updates the Jar
+     * with the Bean classfile or returns true, saying that the whole weblogic
+     * jar needs to be regened with ejbc. This allows faster build times for
+     * working developers. <p>
+     *
+     * The way weblogic ejbc works is it creates wrappers for the publicly
+     * defined methods as they are exposed in the remote interface. If the
+     * actual bean changes without changing the the method signatures then
+     * only the bean classfile needs to be updated and the rest of the
+     * weblogic jar file can remain the same. If the Interfaces, ie. the
+     * method signatures change or if the xml deployment descriptors changed,
+     * the whole jar needs to be rebuilt with ejbc. This is not strictly true
+     * for the xml files. If the JNDI name changes then the jar doesnt have to
+     * be rebuild, but if the resources references change then it does. At
+     * this point the weblogic jar gets rebuilt if the xml files change at
+     * all.
+     *
+     * @param genericJarFile java.io.File The generic jar file.
+     * @param weblogicJarFile java.io.File The weblogic jar file to check to
+     *      see if it needs to be rebuilt.
+     * @return true if the jar needs to be rebuilt.
+     */
+    // CheckStyle:MethodLength OFF - this will no be fixed
+    protected boolean isRebuildRequired(File genericJarFile, File weblogicJarFile) {
+        boolean rebuild = false;
+
+        JarFile genericJar = null;
+        JarFile wlJar = null;
+        File newWLJarFile = null;
+        JarOutputStream newJarStream = null;
+        ClassLoader genericLoader = null;
+
+        try {
+            log("Checking if weblogic Jar needs to be rebuilt for jar " + weblogicJarFile.getName(),
+                Project.MSG_VERBOSE);
+            // Only go forward if the generic and the weblogic file both exist
+            if (genericJarFile.exists() && genericJarFile.isFile()
+                 && weblogicJarFile.exists() && weblogicJarFile.isFile()) {
+                //open jar files
+                genericJar = new JarFile(genericJarFile);
+                wlJar = new JarFile(weblogicJarFile);
+
+                Hashtable genericEntries = new Hashtable();
+                Hashtable wlEntries = new Hashtable();
+                Hashtable replaceEntries = new Hashtable();
+
+                //get the list of generic jar entries
+                for (Enumeration e = genericJar.entries(); e.hasMoreElements();) {
+                    JarEntry je = (JarEntry) e.nextElement();
+
+                    genericEntries.put(je.getName().replace('\\', '/'), je);
+                }
+                //get the list of weblogic jar entries
+                for (Enumeration e = wlJar.entries(); e.hasMoreElements();) {
+                    JarEntry je = (JarEntry) e.nextElement();
+
+                    wlEntries.put(je.getName(), je);
+                }
+
+                //Cycle Through generic and make sure its in weblogic
+                genericLoader = getClassLoaderFromJar(genericJarFile);
+
+                for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) {
+                    String filepath = (String) e.nextElement();
+
+                    if (wlEntries.containsKey(filepath)) {
+                        // File name/path match
+
+                        // Check files see if same
+                        JarEntry genericEntry = (JarEntry) genericEntries.get(filepath);
+                        JarEntry wlEntry = (JarEntry) wlEntries.get(filepath);
+
+                        if ((genericEntry.getCrc() != wlEntry.getCrc())
+                            || (genericEntry.getSize() != wlEntry.getSize())) {
+
+                            if (genericEntry.getName().endsWith(".class")) {
+                                //File are different see if its an object or an interface
+                                String classname
+                                    = genericEntry.getName().replace(File.separatorChar, '.');
+
+                                classname = classname.substring(0, classname.lastIndexOf(".class"));
+
+                                Class genclass = genericLoader.loadClass(classname);
+
+                                if (genclass.isInterface()) {
+                                    //Interface changed   rebuild jar.
+                                    log("Interface " + genclass.getName()
+                                        + " has changed", Project.MSG_VERBOSE);
+                                    rebuild = true;
+                                    break;
+                                } else {
+                                    //Object class Changed   update it.
+                                    replaceEntries.put(filepath, genericEntry);
+                                }
+                            } else {
+                                // is it the manifest. If so ignore it
+                                if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) {
+                                    //File other then class changed   rebuild
+                                    log("Non class file " + genericEntry.getName()
+                                        + " has changed", Project.MSG_VERBOSE);
+                                    rebuild = true;
+                                    break;
+                                }
+                            }
+                        }
+                    } else {
+                        // a file doesnt exist rebuild
+
+                        log("File " + filepath + " not present in weblogic jar",
+                            Project.MSG_VERBOSE);
+                        rebuild = true;
+                        break;
+                    }
+                }
+
+                if (!rebuild) {
+                    log("No rebuild needed - updating jar", Project.MSG_VERBOSE);
+                    newWLJarFile = new File(weblogicJarFile.getAbsolutePath() + ".temp");
+                    if (newWLJarFile.exists()) {
+                        newWLJarFile.delete();
+                    }
+
+                    newJarStream = new JarOutputStream(new FileOutputStream(newWLJarFile));
+                    newJarStream.setLevel(0);
+
+                    //Copy files from old weblogic jar
+                    for (Enumeration e = wlEntries.elements(); e.hasMoreElements();) {
+                        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+                        int bytesRead;
+                        InputStream is;
+                        JarEntry je = (JarEntry) e.nextElement();
+
+                        if (je.getCompressedSize() == -1
+                            || je.getCompressedSize() == je.getSize()) {
+                            newJarStream.setLevel(0);
+                        } else {
+                            newJarStream.setLevel(JAR_COMPRESS_LEVEL);
+                        }
+
+                        // Update with changed Bean class
+                        if (replaceEntries.containsKey(je.getName())) {
+                            log("Updating Bean class from generic Jar "
+                                + je.getName(), Project.MSG_VERBOSE);
+                            // Use the entry from the generic jar
+                            je = (JarEntry) replaceEntries.get(je.getName());
+                            is = genericJar.getInputStream(je);
+                        } else {
+                            //use fle from original weblogic jar
+
+                            is = wlJar.getInputStream(je);
+                        }
+                        newJarStream.putNextEntry(new JarEntry(je.getName()));
+
+                        while ((bytesRead = is.read(buffer)) != -1) {
+                            newJarStream.write(buffer, 0, bytesRead);
+                        }
+                        is.close();
+                    }
+                } else {
+                    log("Weblogic Jar rebuild needed due to changed "
+                         + "interface or XML", Project.MSG_VERBOSE);
+                }
+            } else {
+                rebuild = true;
+            }
+        } catch (ClassNotFoundException cnfe) {
+            String cnfmsg = "ClassNotFoundException while processing ejb-jar file"
+                 + ". Details: "
+                 + cnfe.getMessage();
+
+            throw new BuildException(cnfmsg, cnfe);
+        } catch (IOException ioe) {
+            String msg = "IOException while processing ejb-jar file "
+                 + ". Details: "
+                 + ioe.getMessage();
+
+            throw new BuildException(msg, ioe);
+        } finally {
+            // need to close files and perhaps rename output
+            if (genericJar != null) {
+                try {
+                    genericJar.close();
+                } catch (IOException closeException) {
+                    // empty
+                }
+            }
+
+            if (wlJar != null) {
+                try {
+                    wlJar.close();
+                } catch (IOException closeException) {
+                    // empty
+                }
+            }
+
+            if (newJarStream != null) {
+                try {
+                    newJarStream.close();
+                } catch (IOException closeException) {
+                    // empty
+                }
+
+                try {
+                    FILE_UTILS.rename(newWLJarFile, weblogicJarFile);
+                } catch (IOException renameException) {
+                    log(renameException.getMessage(), Project.MSG_WARN);
+                    rebuild = true;
+                }
+            }
+            if (genericLoader != null
+                && genericLoader instanceof AntClassLoader) {
+                AntClassLoader loader = (AntClassLoader) genericLoader;
+                loader.cleanup();
+            }
+        }
+
+        return rebuild;
+    }
+
+
+    /**
+     * Helper method invoked by isRebuildRequired to get a ClassLoader for a
+     * Jar File passed to it.
+     *
+     * @param classjar java.io.File representing jar file to get classes from.
+     * @return the classloader for the jarfile.
+     * @throws IOException if there is a problem.
+     */
+    protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException {
+        Path lookupPath = new Path(getTask().getProject());
+
+        lookupPath.setLocation(classjar);
+
+        Path classpath = getCombinedClasspath();
+
+        if (classpath != null) {
+            lookupPath.append(classpath);
+        }
+
+        return getTask().getProject().createClassLoader(lookupPath);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java
new file mode 100644
index 0000000..2ee69d0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WeblogicTOPLinkDeploymentTool.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.util.Hashtable;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Deployment tool for Weblogic TOPLink.
+ */
+public class WeblogicTOPLinkDeploymentTool extends WeblogicDeploymentTool {
+
+    private static final String TL_DTD_LOC
+        = "http://www.objectpeople.com/tlwl/dtd/toplink-cmp_2_5_1.dtd";
+
+    private String toplinkDescriptor;
+    private String toplinkDTD;
+
+    /**
+     * Setter used to store the name of the toplink descriptor.
+     * @param inString the string to use as the descriptor name.
+     */
+    public void setToplinkdescriptor(String inString) {
+        this.toplinkDescriptor = inString;
+    }
+
+    /**
+     * Setter used to store the location of the toplink DTD file.
+     * This is expected to be an URL (file or otherwise). If running
+     * this on NT using a file URL, the safest thing would be to not use a
+     * drive spec in the URL and make sure the file resides on the drive that
+     * ANT is running from.  This will keep the setting in the build XML
+     * platform independent.
+     *
+     * @param inString the string to use as the DTD location.
+     */
+    public void setToplinkdtd(String inString) {
+        this.toplinkDTD = inString;
+    }
+
+    /**
+     * Get the descriptor handler.
+     * @param srcDir the source file.
+     * @return the descriptor handler.
+     */
+    protected DescriptorHandler getDescriptorHandler(File srcDir) {
+        DescriptorHandler handler = super.getDescriptorHandler(srcDir);
+        if (toplinkDTD != null) {
+            handler.registerDTD("-//The Object People, Inc.//"
+                + "DTD TOPLink for WebLogic CMP 2.5.1//EN", toplinkDTD);
+        } else {
+            handler.registerDTD("-//The Object People, Inc.//"
+                + "DTD TOPLink for WebLogic CMP 2.5.1//EN", TL_DTD_LOC);
+        }
+        return handler;
+    }
+
+    /**
+     * Add any vendor specific files which should be included in the
+     * EJB Jar.
+     * @param ejbFiles the hashtable to add files to.
+     * @param ddPrefix the prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String ddPrefix) {
+        super.addVendorFiles(ejbFiles, ddPrefix);
+        // Then the toplink deployment descriptor
+
+        // Setup a naming standard here?.
+
+
+        File toplinkDD = new File(getConfig().descriptorDir, ddPrefix + toplinkDescriptor);
+
+        if (toplinkDD.exists()) {
+            ejbFiles.put(META_DIR + toplinkDescriptor,
+                         toplinkDD);
+        } else {
+            log("Unable to locate toplink deployment descriptor. "
+                + "It was expected to be in "
+                + toplinkDD.getPath(), Project.MSG_WARN);
+        }
+    }
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     * @throws BuildException if there is an error.
+     */
+    public void validateConfigured() throws BuildException {
+        super.validateConfigured();
+        if (toplinkDescriptor == null) {
+            throw new BuildException("The toplinkdescriptor attribute must "
+                + "be specified");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
new file mode 100644
index 0000000..10f1712
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ejb/WebsphereDeploymentTool.java
@@ -0,0 +1,892 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.ejb;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Websphere deployment tool that augments the ejbjar task.
+ * Searches for the websphere specific deployment descriptors and
+ * adds them to the final ejb jar file. Websphere has two specific descriptors for session
+ * beans:
+ * <ul>
+ *    <li>ibm-ejb-jar-bnd.xmi</li>
+ *    <li>ibm-ejb-jar-ext.xmi</li>
+ * </ul>
+ * and another two for container managed entity beans:
+ * <ul>
+ *    <li>Map.mapxmi</li>
+ *    <li>Schema.dbxmi</li>
+ * </ul>
+ * In terms of WebSphere, the generation of container code and stubs is
+ * called <code>deployment</code>. This step can be performed by the websphere
+ * element as part of the jar generation process. If the switch
+ * <code>ejbdeploy</code> is on, the ejbdeploy tool from the websphere toolset
+ * is called for every ejb-jar. Unfortunately, this step only works, if you
+ * use the ibm jdk. Otherwise, the rmic (called by ejbdeploy) throws a
+ * ClassFormatError. Be sure to switch ejbdeploy off, if run ant with
+ * sun jdk.
+ *
+ */
+public class WebsphereDeploymentTool extends GenericDeploymentTool {
+
+    /** ID for ejb 1.1 */
+    public static final String PUBLICID_EJB11
+         = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN";
+    /** ID for ejb 2.0 */
+    public static final String PUBLICID_EJB20
+         = "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN";
+    /** Schema directory */
+    protected static final String SCHEMA_DIR = "Schema/";
+
+    protected static final String WAS_EXT = "ibm-ejb-jar-ext.xmi";
+    protected static final String WAS_BND = "ibm-ejb-jar-bnd.xmi";
+    protected static final String WAS_CMP_MAP = "Map.mapxmi";
+    protected static final String WAS_CMP_SCHEMA = "Schema.dbxmi";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Instance variable that stores the suffix for the websphere jarfile. */
+    private String jarSuffix = ".jar";
+
+    /** Instance variable that stores the location of the ejb 1.1 DTD file. */
+    private String ejb11DTD;
+
+    /** Instance variable that determines whether generic ejb jars are kept. */
+
+    private boolean keepGeneric = false;
+
+    private boolean alwaysRebuild = true;
+
+    private boolean ejbdeploy = true;
+
+    /** Indicates if the old CMP location convention is to be used. */
+    private boolean newCMP = false;
+
+    /** The classpath to the websphere classes. */
+    private Path wasClasspath = null;
+
+    /** The DB Vendor name, the EJB is persisted against */
+    private String dbVendor;
+
+    /** The name of the database to create. (For top-down mapping only) */
+    private String dbName;
+
+    /** The name of the schema to create. (For top-down mappings only) */
+    private String dbSchema;
+
+    /** true - Only generate the deployment code, do not run RMIC or Javac */
+    private boolean codegen;
+
+    /** true - Only output error messages, suppress informational messages */
+    private boolean quiet = true;
+
+    /** true - Disable the validation steps */
+    private boolean novalidate;
+
+    /** true - Disable warning and informational messages */
+    private boolean nowarn;
+
+    /** true - Disable informational messages */
+    private boolean noinform;
+
+    /** true - Enable internal tracing */
+    private boolean trace;
+
+    /** Additional options for RMIC */
+    private String rmicOptions;
+
+    /** true- Use the WebSphere 3.5 compatible mapping rules */
+    private boolean use35MappingRules;
+
+    /** the scratchdir for the ejbdeploy operation */
+    private String tempdir = "_ejbdeploy_temp";
+
+    /** the home directory for websphere */
+    private File websphereHome;
+
+    /**
+     * Get the classpath to the websphere classpaths.
+     * @return the websphere classpath.
+     */
+    public Path createWASClasspath() {
+        if (wasClasspath == null) {
+            wasClasspath = new Path(getTask().getProject());
+        }
+        return wasClasspath.createPath();
+    }
+
+
+    /**
+     * Set the websphere classpath.
+     * @param wasClasspath the websphere classpath.
+     */
+    public void setWASClasspath(Path wasClasspath) {
+        this.wasClasspath = wasClasspath;
+    }
+
+
+    /** Sets the DB Vendor for the Entity Bean mapping ; optional.
+     * <p>
+     * Valid options can be obtained by running the following command:
+     * <code>
+     * &lt;WAS_HOME&gt;/bin/EJBDeploy.[sh/bat] -help
+     * </code>
+     * </p>
+     * <p>
+     * This is also used to determine the name of the Map.mapxmi and
+     * Schema.dbxmi files, for example Account-DB2UDB_V81-Map.mapxmi
+     * and Account-DB2UDB_V81-Schema.dbxmi.
+     * </p>
+     *
+     * @param dbvendor database vendor type
+     */
+    public void setDbvendor(String dbvendor) {
+        this.dbVendor = dbvendor;
+    }
+
+
+    /**
+     * Sets the name of the Database to create; optional.
+     *
+     * @param dbName name of the database
+     */
+    public void setDbname(String dbName) {
+        this.dbName = dbName;
+    }
+
+
+    /**
+     * Sets the name of the schema to create; optional.
+     *
+     * @param dbSchema name of the schema
+     */
+    public void setDbschema(String dbSchema) {
+        this.dbSchema = dbSchema;
+    }
+
+
+    /**
+     * Flag, default false, to only generate the deployment
+     * code, do not run RMIC or Javac
+     *
+     * @param codegen option
+     */
+    public void setCodegen(boolean codegen) {
+        this.codegen = codegen;
+    }
+
+
+    /**
+     * Flag, default true, to only output error messages.
+     *
+     * @param quiet option
+     */
+    public void setQuiet(boolean quiet) {
+        this.quiet = quiet;
+    }
+
+
+    /**
+     * Flag to disable the validation steps; optional, default false.
+     *
+     * @param novalidate option
+     */
+    public void setNovalidate(boolean novalidate) {
+        this.novalidate = novalidate;
+    }
+
+
+    /**
+     * Flag to disable warning and informational messages; optional, default false.
+     *
+     * @param nowarn option
+     */
+    public void setNowarn(boolean nowarn) {
+        this.nowarn = nowarn;
+    }
+
+
+    /**
+     * Flag to disable informational messages; optional, default false.
+     *
+     * @param noinform if true disables informational messages
+     */
+    public void setNoinform(boolean noinform) {
+        this.noinform = noinform;
+    }
+
+
+    /**
+     * Flag to enable internal tracing when set, optional, default false.
+     *
+     * @param trace a <code>boolean</code> vaule.
+     */
+    public void setTrace(boolean trace) {
+        this.trace = trace;
+    }
+
+    /**
+     * Set the rmic options.
+     *
+     * @param options the options to use.
+     */
+    public void setRmicoptions(String options) {
+        this.rmicOptions = options;
+    }
+
+    /**
+     * Flag to use the WebSphere 3.5 compatible mapping rules ; optional, default false.
+     *
+     * @param attr a <code>boolean</code> value.
+     */
+    public void setUse35(boolean attr) {
+        use35MappingRules = attr;
+    }
+
+
+    /**
+     * Set the rebuild flag to false to only update changes in the jar rather
+     * than rerunning ejbdeploy; optional, default true.
+     * @param rebuild a <code>boolean</code> value.
+     */
+    public void setRebuild(boolean rebuild) {
+        this.alwaysRebuild = rebuild;
+    }
+
+
+    /**
+     * String value appended to the basename of the deployment
+     * descriptor to create the filename of the WebLogic EJB
+     * jar file. Optional, default '.jar'.
+     * @param inString the string to use as the suffix.
+     */
+    public void setSuffix(String inString) {
+        this.jarSuffix = inString;
+    }
+
+
+    /**
+     * This controls whether the generic file used as input to
+     * ejbdeploy is retained; optional, default false.
+     * @param inValue either 'true' or 'false'.
+     */
+    public void setKeepgeneric(boolean inValue) {
+        this.keepGeneric = inValue;
+    }
+
+
+    /**
+     * Decide, wether ejbdeploy should be called or not;
+     * optional, default true.
+     *
+     * @param ejbdeploy a <code>boolean</code> value.
+     */
+    public void setEjbdeploy(boolean ejbdeploy) {
+        this.ejbdeploy = ejbdeploy;
+    }
+
+
+    /**
+     * Setter used to store the location of the Sun's Generic EJB DTD. This
+     * can be a file on the system or a resource on the classpath.
+     *
+     * @param inString the string to use as the DTD location.
+     */
+    public void setEJBdtd(String inString) {
+        this.ejb11DTD = inString;
+    }
+
+
+    /**
+     * Set the value of the oldCMP scheme. This is an antonym for newCMP
+     * @ant.attribute ignore="true"
+     * @param oldCMP a <code>boolean</code> value.
+     */
+    public void setOldCMP(boolean oldCMP) {
+        this.newCMP = !oldCMP;
+    }
+
+
+    /**
+     * Set the value of the newCMP scheme. The old CMP scheme locates the
+     * websphere CMP descriptor based on the naming convention where the
+     * websphere CMP file is expected to be named with the bean name as the
+     * prefix. Under this scheme the name of the CMP descriptor does not match
+     * the name actually used in the main websphere EJB descriptor. Also,
+     * descriptors which contain multiple CMP references could not be used.
+     * @param newCMP a <code>boolean</code> value.
+     */
+    public void setNewCMP(boolean newCMP) {
+        this.newCMP = newCMP;
+    }
+
+
+    /**
+     * The directory, where ejbdeploy will write temporary files;
+     * optional, defaults to '_ejbdeploy_temp'.
+     * @param tempdir the directory name to use.
+     */
+    public void setTempdir(String tempdir) {
+        this.tempdir = tempdir;
+    }
+
+
+    /** {@inheritDoc}. */
+    protected DescriptorHandler getDescriptorHandler(File srcDir) {
+        DescriptorHandler handler = new DescriptorHandler(getTask(), srcDir);
+        // register all the DTDs, both the ones that are known and
+        // any supplied by the user
+        handler.registerDTD(PUBLICID_EJB11, ejb11DTD);
+
+        for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+            EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+            handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+        }
+
+        return handler;
+    }
+
+
+    /**
+     * Get a description handler.
+     * @param srcDir the source directory.
+     * @return the handler.
+     */
+    protected DescriptorHandler getWebsphereDescriptorHandler(final File srcDir) {
+        DescriptorHandler handler =
+            new DescriptorHandler(getTask(), srcDir) {
+                protected void processElement() {
+                }
+            };
+
+        for (Iterator i = getConfig().dtdLocations.iterator(); i.hasNext();) {
+            EjbJar.DTDLocation dtdLocation = (EjbJar.DTDLocation) i.next();
+
+            handler.registerDTD(dtdLocation.getPublicId(), dtdLocation.getLocation());
+        }
+        return handler;
+    }
+
+
+    /**
+     * Add any vendor specific files which should be included in the EJB Jar.
+     * @param ejbFiles a hashtable entryname -> file.
+     * @param baseName a prefix to use.
+     */
+    protected void addVendorFiles(Hashtable ejbFiles, String baseName) {
+
+        String ddPrefix = (usingBaseJarName() ? "" : baseName);
+        String dbPrefix = (dbVendor == null) ? "" : dbVendor + "-";
+
+        // Get the Extensions document
+        File websphereEXT = new File(getConfig().descriptorDir, ddPrefix + WAS_EXT);
+
+        if (websphereEXT.exists()) {
+            ejbFiles.put(META_DIR + WAS_EXT,
+                websphereEXT);
+        } else {
+            log("Unable to locate websphere extensions. "
+                + "It was expected to be in "
+                + websphereEXT.getPath(), Project.MSG_VERBOSE);
+        }
+
+        File websphereBND = new File(getConfig().descriptorDir, ddPrefix + WAS_BND);
+
+        if (websphereBND.exists()) {
+            ejbFiles.put(META_DIR + WAS_BND,
+                websphereBND);
+        } else {
+            log("Unable to locate websphere bindings. "
+                + "It was expected to be in "
+                + websphereBND.getPath(), Project.MSG_VERBOSE);
+        }
+
+        if (!newCMP) {
+            log("The old method for locating CMP files has been DEPRECATED.",
+                Project.MSG_VERBOSE);
+            log("Please adjust your websphere descriptor and set "
+                + "newCMP=\"true\" to use the new CMP descriptor "
+                + "inclusion mechanism. ", Project.MSG_VERBOSE);
+        } else {
+            // We attempt to put in the MAP and Schema files of CMP beans
+            try {
+                // Add the Map file
+                File websphereMAP = new File(getConfig().descriptorDir,
+                    ddPrefix + dbPrefix + WAS_CMP_MAP);
+
+                if (websphereMAP.exists()) {
+                    ejbFiles.put(META_DIR + WAS_CMP_MAP,
+                        websphereMAP);
+                } else {
+                    log("Unable to locate the websphere Map: "
+                        + websphereMAP.getPath(), Project.MSG_VERBOSE);
+                }
+
+                File websphereSchema = new File(getConfig().descriptorDir,
+                    ddPrefix + dbPrefix + WAS_CMP_SCHEMA);
+
+                if (websphereSchema.exists()) {
+                    ejbFiles.put(META_DIR + SCHEMA_DIR + WAS_CMP_SCHEMA,
+                        websphereSchema);
+                } else {
+                    log("Unable to locate the websphere Schema: "
+                        + websphereSchema.getPath(), Project.MSG_VERBOSE);
+                }
+                // Theres nothing else to see here...keep moving sonny
+            } catch (Exception e) {
+                String msg = "Exception while adding Vendor specific files: "
+                    + e.toString();
+
+                throw new BuildException(msg, e);
+            }
+        }
+    }
+
+
+    /**
+     * Get the vendor specific name of the Jar that will be output. The
+     * modification date of this jar will be checked against the dependent
+     * bean classes.
+     */
+    File getVendorOutputJarFile(String baseName) {
+        return new File(getDestDir(), baseName + jarSuffix);
+    }
+
+
+    /**
+     * Gets the options for the EJB Deploy operation
+     *
+     * @return String
+     */
+    protected String getOptions() {
+        // Set the options
+        StringBuffer options = new StringBuffer();
+
+        if (dbVendor != null) {
+            options.append(" -dbvendor ").append(dbVendor);
+        }
+        if (dbName != null) {
+            options.append(" -dbname \"").append(dbName).append("\"");
+        }
+
+        if (dbSchema != null) {
+            options.append(" -dbschema \"").append(dbSchema).append("\"");
+        }
+
+        if (codegen) {
+            options.append(" -codegen");
+        }
+
+        if (quiet) {
+            options.append(" -quiet");
+        }
+
+        if (novalidate) {
+            options.append(" -novalidate");
+        }
+
+        if (nowarn) {
+            options.append(" -nowarn");
+        }
+
+        if (noinform) {
+            options.append(" -noinform");
+        }
+
+        if (trace) {
+            options.append(" -trace");
+        }
+
+        if (use35MappingRules) {
+            options.append(" -35");
+        }
+
+        if (rmicOptions != null) {
+            options.append(" -rmic \"").append(rmicOptions).append("\"");
+        }
+
+        return options.toString();
+    }
+
+
+    /**
+     * Helper method invoked by execute() for each websphere jar to be built.
+     * Encapsulates the logic of constructing a java task for calling
+     * websphere.ejbdeploy and executing it.
+     *
+     * @param sourceJar java.io.File representing the source (EJB1.1) jarfile.
+     * @param destJar java.io.File representing the destination, websphere
+     *      jarfile.
+     */
+    private void buildWebsphereJar(File sourceJar, File destJar) {
+        try {
+            if (ejbdeploy) {
+                Java javaTask = new Java(getTask());
+                // Set the JvmArgs
+                javaTask.createJvmarg().setValue("-Xms64m");
+                javaTask.createJvmarg().setValue("-Xmx128m");
+
+                // Set the Environment variable
+                Environment.Variable var = new Environment.Variable();
+
+                var.setKey("websphere.lib.dir");
+                File libdir = new File(websphereHome, "lib");
+                var.setValue(libdir.getAbsolutePath());
+                javaTask.addSysproperty(var);
+
+                // Set the working directory
+                javaTask.setDir(websphereHome);
+
+                // Set the Java class name
+                javaTask.setTaskName("ejbdeploy");
+                javaTask.setClassname("com.ibm.etools.ejbdeploy.EJBDeploy");
+
+                javaTask.createArg().setValue(sourceJar.getPath());
+                javaTask.createArg().setValue(tempdir);
+                javaTask.createArg().setValue(destJar.getPath());
+                javaTask.createArg().setLine(getOptions());
+                if (getCombinedClasspath() != null
+                    && getCombinedClasspath().toString().length() > 0) {
+                    javaTask.createArg().setValue("-cp");
+                    javaTask.createArg().setValue(getCombinedClasspath().toString());
+                }
+
+                Path classpath = wasClasspath;
+
+                if (classpath == null) {
+                    classpath = getCombinedClasspath();
+                }
+
+                if (classpath != null) {
+                    javaTask.setClasspath(classpath);
+                    javaTask.setFork(true);
+                } else {
+                    javaTask.setFork(true);
+                }
+
+                log("Calling websphere.ejbdeploy for " + sourceJar.toString(),
+                    Project.MSG_VERBOSE);
+
+                javaTask.execute();
+            }
+        } catch (Exception e) {
+            // Have to catch this because of the semantics of calling main()
+            String msg = "Exception while calling ejbdeploy. Details: " + e.toString();
+
+            throw new BuildException(msg, e);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    protected void writeJar(String baseName, File jarFile, Hashtable files, String publicId)
+         throws BuildException {
+        if (ejbdeploy) {
+            // create the -generic.jar, if required
+            File genericJarFile = super.getVendorOutputJarFile(baseName);
+
+            super.writeJar(baseName, genericJarFile, files, publicId);
+
+            // create the output .jar, if required
+            if (alwaysRebuild || isRebuildRequired(genericJarFile, jarFile)) {
+                buildWebsphereJar(genericJarFile, jarFile);
+            }
+            if (!keepGeneric) {
+                log("deleting generic jar " + genericJarFile.toString(),
+                    Project.MSG_VERBOSE);
+                genericJarFile.delete();
+            }
+        } else {
+            // create the "undeployed" output .jar, if required
+            super.writeJar(baseName, jarFile, files, publicId);
+        }
+    }
+
+
+    /**
+     * Called to validate that the tool parameters have been configured.
+     * @throws BuildException if there is an error.
+     */
+    public void validateConfigured() throws BuildException {
+        super.validateConfigured();
+        if (ejbdeploy) {
+            String home = getTask().getProject().getProperty("websphere.home");
+            if (home == null) {
+                throw new BuildException("The 'websphere.home' property must "
+                    + "be set when 'ejbdeploy=true'");
+            }
+            websphereHome = getTask().getProject().resolveFile(home);
+        }
+    }
+
+
+    /**
+     * Helper method to check to see if a websphere EBJ1.1 jar needs to be
+     * rebuilt using ejbdeploy. Called from writeJar it sees if the "Bean"
+     * classes are the only thing that needs to be updated and either updates
+     * the Jar with the Bean classfile or returns true, saying that the whole
+     * websphere jar needs to be regened with ejbdeploy. This allows faster
+     * build times for working developers. <p>
+     *
+     * The way websphere ejbdeploy works is it creates wrappers for the
+     * publicly defined methods as they are exposed in the remote interface.
+     * If the actual bean changes without changing the the method signatures
+     * then only the bean classfile needs to be updated and the rest of the
+     * websphere jar file can remain the same. If the Interfaces, ie. the
+     * method signatures change or if the xml deployment descriptors changed,
+     * the whole jar needs to be rebuilt with ejbdeploy. This is not strictly
+     * true for the xml files. If the JNDI name changes then the jar doesnt
+     * have to be rebuild, but if the resources references change then it
+     * does. At this point the websphere jar gets rebuilt if the xml files
+     * change at all.
+     *
+     * @param genericJarFile java.io.File The generic jar file.
+     * @param websphereJarFile java.io.File The websphere jar file to check to
+     *      see if it needs to be rebuilt.
+     * @return true if a rebuild is required.
+     */
+    // CheckStyle:MethodLength OFF - this will no be fixed
+    protected boolean isRebuildRequired(File genericJarFile, File websphereJarFile) {
+        boolean rebuild = false;
+
+        JarFile genericJar = null;
+        JarFile wasJar = null;
+        File newwasJarFile = null;
+        JarOutputStream newJarStream = null;
+
+        try {
+            log("Checking if websphere Jar needs to be rebuilt for jar "
+                + websphereJarFile.getName(), Project.MSG_VERBOSE);
+            // Only go forward if the generic and the websphere file both exist
+            if (genericJarFile.exists() && genericJarFile.isFile()
+                 && websphereJarFile.exists() && websphereJarFile.isFile()) {
+                //open jar files
+                genericJar = new JarFile(genericJarFile);
+                wasJar = new JarFile(websphereJarFile);
+
+                Hashtable genericEntries = new Hashtable();
+                Hashtable wasEntries = new Hashtable();
+                Hashtable replaceEntries = new Hashtable();
+
+                //get the list of generic jar entries
+                for (Enumeration e = genericJar.entries(); e.hasMoreElements();) {
+                    JarEntry je = (JarEntry) e.nextElement();
+
+                    genericEntries.put(je.getName().replace('\\', '/'), je);
+                }
+                //get the list of websphere jar entries
+                for (Enumeration e = wasJar.entries(); e.hasMoreElements();) {
+                    JarEntry je = (JarEntry) e.nextElement();
+
+                    wasEntries.put(je.getName(), je);
+                }
+
+                //Cycle Through generic and make sure its in websphere
+                ClassLoader genericLoader = getClassLoaderFromJar(genericJarFile);
+
+                for (Enumeration e = genericEntries.keys(); e.hasMoreElements();) {
+                    String filepath = (String) e.nextElement();
+
+                    if (wasEntries.containsKey(filepath)) {
+                        // File name/path match
+                        // Check files see if same
+                        JarEntry genericEntry = (JarEntry) genericEntries.get(filepath);
+                        JarEntry wasEntry = (JarEntry) wasEntries.get(filepath);
+
+                        if ((genericEntry.getCrc() != wasEntry.getCrc())
+                            || (genericEntry.getSize() != wasEntry.getSize())) {
+
+                            if (genericEntry.getName().endsWith(".class")) {
+                                //File are different see if its an object or an interface
+                                String classname
+                                    = genericEntry.getName().replace(File.separatorChar, '.');
+
+                                classname = classname.substring(0, classname.lastIndexOf(".class"));
+
+                                Class genclass = genericLoader.loadClass(classname);
+
+                                if (genclass.isInterface()) {
+                                    //Interface changed   rebuild jar.
+                                    log("Interface " + genclass.getName()
+                                        + " has changed", Project.MSG_VERBOSE);
+                                    rebuild = true;
+                                    break;
+                                } else {
+                                    //Object class Changed   update it.
+                                    replaceEntries.put(filepath, genericEntry);
+                                }
+                            } else {
+                                // is it the manifest. If so ignore it
+                                if (!genericEntry.getName().equals("META-INF/MANIFEST.MF")) {
+                                    //File other then class changed   rebuild
+                                    log("Non class file " + genericEntry.getName()
+                                        + " has changed", Project.MSG_VERBOSE);
+                                    rebuild = true;
+                                }
+                                break;
+                            }
+                        }
+                    } else {
+                        // a file doesn't exist rebuild
+
+                        log("File " + filepath + " not present in websphere jar",
+                            Project.MSG_VERBOSE);
+                        rebuild = true;
+                        break;
+                    }
+                }
+
+                if (!rebuild) {
+                    log("No rebuild needed - updating jar", Project.MSG_VERBOSE);
+                    newwasJarFile = new File(websphereJarFile.getAbsolutePath() + ".temp");
+                    if (newwasJarFile.exists()) {
+                        newwasJarFile.delete();
+                    }
+
+                    newJarStream = new JarOutputStream(new FileOutputStream(newwasJarFile));
+                    newJarStream.setLevel(0);
+
+                    //Copy files from old websphere jar
+                    for (Enumeration e = wasEntries.elements(); e.hasMoreElements();) {
+                        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+                        int bytesRead;
+                        InputStream is;
+                        JarEntry je = (JarEntry) e.nextElement();
+
+                        if (je.getCompressedSize() == -1
+                            || je.getCompressedSize() == je.getSize()) {
+                            newJarStream.setLevel(0);
+                        } else {
+                            newJarStream.setLevel(JAR_COMPRESS_LEVEL);
+                        }
+
+                        // Update with changed Bean class
+                        if (replaceEntries.containsKey(je.getName())) {
+                            log("Updating Bean class from generic Jar " + je.getName(),
+                                Project.MSG_VERBOSE);
+                            // Use the entry from the generic jar
+                            je = (JarEntry) replaceEntries.get(je.getName());
+                            is = genericJar.getInputStream(je);
+                        } else {
+                            //use fle from original websphere jar
+
+                            is = wasJar.getInputStream(je);
+                        }
+                        newJarStream.putNextEntry(new JarEntry(je.getName()));
+
+                        while ((bytesRead = is.read(buffer)) != -1) {
+                            newJarStream.write(buffer, 0, bytesRead);
+                        }
+                        is.close();
+                    }
+                } else {
+                    log("websphere Jar rebuild needed due to changed "
+                        + "interface or XML", Project.MSG_VERBOSE);
+                }
+            } else {
+                rebuild = true;
+            }
+        } catch (ClassNotFoundException cnfe) {
+            String cnfmsg = "ClassNotFoundException while processing ejb-jar file"
+                 + ". Details: "
+                 + cnfe.getMessage();
+
+            throw new BuildException(cnfmsg, cnfe);
+        } catch (IOException ioe) {
+            String msg = "IOException while processing ejb-jar file "
+                 + ". Details: "
+                 + ioe.getMessage();
+
+            throw new BuildException(msg, ioe);
+        } finally {
+            // need to close files and perhaps rename output
+            if (genericJar != null) {
+                try {
+                    genericJar.close();
+                } catch (IOException closeException) {
+                    // Ignore
+                }
+            }
+
+            if (wasJar != null) {
+                try {
+                    wasJar.close();
+                } catch (IOException closeException) {
+                    // Ignore
+                }
+            }
+
+            if (newJarStream != null) {
+                try {
+                    newJarStream.close();
+                } catch (IOException closeException) {
+                    // Ignore
+                }
+
+                try {
+                    FILE_UTILS.rename(newwasJarFile, websphereJarFile);
+                } catch (IOException renameException) {
+                    log(renameException.getMessage(), Project.MSG_WARN);
+                    rebuild = true;
+                }
+            }
+        }
+
+        return rebuild;
+    }
+
+
+    /**
+     * Helper method invoked by isRebuildRequired to get a ClassLoader for a
+     * Jar File passed to it.
+     *
+     * @param classjar java.io.File representing jar file to get classes from.
+     * @return a classloader for the jar file.
+     * @throws IOException if there is an error.
+     */
+    protected ClassLoader getClassLoaderFromJar(File classjar) throws IOException {
+        Path lookupPath = new Path(getTask().getProject());
+
+        lookupPath.setLocation(classjar);
+
+        Path classpath = getCombinedClasspath();
+
+        if (classpath != null) {
+            lookupPath.append(classpath);
+        }
+
+        return getTask().getProject().createClassLoader(lookupPath);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java
new file mode 100644
index 0000000..fc2e256
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatability.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+/**
+ * Enum used in (@link Extension) to indicate the compatability
+ * of one extension to another. See (@link Extension) for instances
+ * of object.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  This file is from excalibur.extension package. Dont edit this file
+ * directly as there is no unit tests to make sure it is operational
+ * in ant. Edit file in excalibur and run tests there before changing
+ * ants file.
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * @see Extension
+ */
+public final class Compatability {
+    /**
+     * A string representaiton of compatability level.
+     */
+    private final String name;
+
+    /**
+     * Create a compatability enum with specified name.
+     *
+     * @param name the name of compatability level
+     */
+    Compatability(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Return name of compatability level.
+     *
+     * @return the name of compatability level
+     */
+    public String toString() {
+        return name;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java
new file mode 100644
index 0000000..0f91c66
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Compatibility.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+/**
+ * Enum used in (@link Extension) to indicate the compatibility
+ * of one extension to another. See (@link Extension) for instances
+ * of object.
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *  This file is from excalibur.extension package. Dont edit this file
+ * directly as there is no unit tests to make sure it is operational
+ * in ant. Edit file in excalibur and run tests there before changing
+ * ants file.
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * @see Extension
+ */
+public final class Compatibility {
+    /**
+     * A string representaiton of compatibility level.
+     */
+    private final String name;
+
+    /**
+     * Create a compatibility enum with specified name.
+     *
+     * @param name the name of compatibility level
+     */
+    Compatibility(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Return name of compatibility level.
+     *
+     * @return the name of compatibility level
+     */
+    public String toString() {
+        return name;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java
new file mode 100644
index 0000000..e5963f4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/DeweyDecimal.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+
+/**
+ * Utility class to contain version numbers in "Dewey Decimal"
+ * syntax.  Numbers in the "Dewey Decimal" syntax consist of positive
+ * decimal integers separated by periods ".".  For example, "2.0" or
+ * "1.2.3.4.5.6.7".  This allows an extensible number to be used to
+ * represent major, minor, micro, etc versions.  The version number
+ * must begin with a number.
+ *
+ * Original Implementation moved to org.apache.tools.ant.util.DeweyDecimal
+ */
+public final class DeweyDecimal extends org.apache.tools.ant.util.DeweyDecimal {
+
+    /**
+     * Construct a DeweyDecimal from an array of integer components.
+     *
+     * @param components an array of integer components.
+     */
+    public DeweyDecimal(final int[] components) {
+        super(components);
+    }
+
+    /**
+     * Construct a DeweyDecimal from string in DeweyDecimal format.
+     *
+     * @param string the string in dewey decimal format
+     * @exception NumberFormatException if string is malformed
+     */
+    public DeweyDecimal(final String string)
+        throws NumberFormatException {
+        super(string);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
new file mode 100644
index 0000000..419c3a5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java
@@ -0,0 +1,689 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * <p>Utility class that represents either an available "Optional Package"
+ * (formerly known as "Standard Extension") as described in the manifest
+ * of a JAR file, or the requirement for such an optional package.</p>
+ *
+ * <p>For more information about optional packages, see the document
+ * <em>Optional Package Versioning</em> in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * <code>guide/extensions/versioning.html</code>.</p>
+ *
+ */
+public final class Extension {
+    /**
+     * Manifest Attribute Name object for EXTENSION_LIST.
+     */
+    public static final Attributes.Name EXTENSION_LIST
+        = new Attributes.Name("Extension-List");
+
+    /**
+     * <code>Name</code> object for <code>Optional-Extension-List</code>
+     * manifest attribute used for declaring optional dependencies on
+     * installed extensions. Note that the dependencies declared by this method
+     * are not required for the library to operate but if present will be used.
+     * It is NOT part of the official "Optional Package" specification.
+     *
+     * @see <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/spec.html#dependnecy">
+     *      Installed extension dependency</a>
+     */
+    public static final Attributes.Name OPTIONAL_EXTENSION_LIST
+        = new Attributes.Name("Optional-Extension-List");
+
+    /**
+     * Manifest Attribute Name object for EXTENSION_NAME.
+     */
+    public static final Attributes.Name EXTENSION_NAME =
+        new Attributes.Name("Extension-Name");
+    /**
+     * Manifest Attribute Name object for SPECIFICATION_VERSION.
+     */
+    public static final Attributes.Name SPECIFICATION_VERSION
+        = Attributes.Name.SPECIFICATION_VERSION;
+
+    /**
+     * Manifest Attribute Name object for SPECIFICATION_VENDOR.
+     */
+    public static final Attributes.Name SPECIFICATION_VENDOR
+        = Attributes.Name.SPECIFICATION_VENDOR;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
+     */
+    public static final Attributes.Name IMPLEMENTATION_VERSION
+        = Attributes.Name.IMPLEMENTATION_VERSION;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
+     */
+    public static final Attributes.Name IMPLEMENTATION_VENDOR
+        = Attributes.Name.IMPLEMENTATION_VENDOR;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_URL.
+     */
+    public static final Attributes.Name IMPLEMENTATION_URL
+        = new Attributes.Name("Implementation-URL");
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_VENDOR_ID.
+     */
+    public static final Attributes.Name IMPLEMENTATION_VENDOR_ID
+        = new Attributes.Name("Implementation-Vendor-Id");
+
+    /**
+     * Enum indicating that extension is compatible with other extension.
+     */
+    public static final Compatibility COMPATIBLE
+        = new Compatibility("COMPATIBLE");
+
+    /**
+     * Enum indicating that extension requires an upgrade
+     * of specification to be compatible with other extension.
+     */
+    public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE
+        = new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
+
+    /**
+     * Enum indicating that extension requires a vendor
+     * switch to be compatible with other extension.
+     */
+    public static final Compatibility REQUIRE_VENDOR_SWITCH
+        = new Compatibility("REQUIRE_VENDOR_SWITCH");
+
+    /**
+     * Enum indicating that extension requires an upgrade
+     * of implementation to be compatible with other extension.
+     */
+    public static final Compatibility REQUIRE_IMPLEMENTATION_UPGRADE
+        = new Compatibility("REQUIRE_IMPLEMENTATION_UPGRADE");
+
+    /**
+     * Enum indicating that extension is incompatible with
+     * other extension in ways other than other enums
+     * indicate). For example the other extension may have
+     * a different ID.
+     */
+    public static final Compatibility INCOMPATIBLE
+        = new Compatibility("INCOMPATIBLE");
+
+    /**
+     * The name of the optional package being made available, or required.
+     */
+    private String extensionName;
+
+    /**
+     * The version number (dotted decimal notation) of the specification
+     * to which this optional package conforms.
+     */
+    private DeweyDecimal specificationVersion;
+
+    /**
+     * The name of the company or organization that originated the
+     * specification to which this optional package conforms.
+     */
+    private String specificationVendor;
+
+    /**
+     * The unique identifier of the company that produced the optional
+     * package contained in this JAR file.
+     */
+    private String implementationVendorID;
+
+    /**
+     * The name of the company or organization that produced this
+     * implementation of this optional package.
+     */
+    private String implementationVendor;
+
+    /**
+     * The version number (dotted decimal notation) for this implementation
+     * of the optional package.
+     */
+    private DeweyDecimal implementationVersion;
+
+    /**
+     * The URL from which the most recent version of this optional package
+     * can be obtained if it is not already installed.
+     */
+    private String implementationURL;
+
+    /**
+     * Return an array of <code>Extension</code> objects representing optional
+     * packages that are available in the JAR file associated with the
+     * specified <code>Manifest</code>.  If there are no such optional
+     * packages, a zero-length array is returned.
+     *
+     * @param manifest Manifest to be parsed
+     * @return the "available" extensions in specified manifest
+     */
+    public static Extension[] getAvailable(final Manifest manifest) {
+        if (null == manifest) {
+            return new Extension[ 0 ];
+        }
+
+        final ArrayList results = new ArrayList();
+
+        final Attributes mainAttributes = manifest.getMainAttributes();
+        if (null != mainAttributes) {
+            final Extension extension = getExtension("", mainAttributes);
+            if (null != extension) {
+                results.add(extension);
+            }
+        }
+
+        final Map entries = manifest.getEntries();
+        final Iterator keys = entries.keySet().iterator();
+        while (keys.hasNext()) {
+            final String key = (String) keys.next();
+            final Attributes attributes = (Attributes) entries.get(key);
+            final Extension extension = getExtension("", attributes);
+            if (null != extension) {
+                results.add(extension);
+            }
+        }
+
+        return (Extension[]) results.toArray(new Extension[results.size()]);
+    }
+
+    /**
+     * Return the set of <code>Extension</code> objects representing optional
+     * packages that are required by the application contained in the JAR
+     * file associated with the specified <code>Manifest</code>.  If there
+     * are no such optional packages, a zero-length list is returned.
+     *
+     * @param manifest Manifest to be parsed
+     * @return the dependencies that are specified in manifes
+     */
+    public static Extension[] getRequired(final Manifest manifest) {
+        return getListed(manifest, Attributes.Name.EXTENSION_LIST);
+    }
+
+    /**
+     * Return the set of <code>Extension</code> objects representing "Optional
+     * Packages" that the application declares they will use if present. If
+     * there are no such optional packages, a zero-length list is returned.
+     *
+     * @param manifest Manifest to be parsed
+     * @return the optional dependencies that are specified in manifest
+     */
+    public static Extension[] getOptions(final Manifest manifest) {
+        return getListed(manifest, OPTIONAL_EXTENSION_LIST);
+    }
+
+    /**
+     * Add Extension to the specified manifest Attributes.
+     *
+     * @param attributes the attributes of manifest to add to
+     * @param extension the extension
+     */
+    public static void addExtension(final Extension extension,
+                                     final Attributes attributes) {
+        addExtension(extension, "", attributes);
+    }
+
+    /**
+     * Add Extension to the specified manifest Attributes.
+     * Use the specified prefix so that dependencies can added
+     * with a prefix such as "java3d-" etc.
+     *
+     * @param attributes the attributes of manifest to add to
+     * @param extension the extension
+     * @param prefix the name to prefix to extension
+     */
+    public static void addExtension(final Extension extension,
+                                     final String prefix,
+                                     final Attributes attributes) {
+        attributes.putValue(prefix + EXTENSION_NAME,
+                             extension.getExtensionName());
+
+        final String specificationVendor = extension.getSpecificationVendor();
+        if (null != specificationVendor) {
+            attributes.putValue(prefix + SPECIFICATION_VENDOR,
+                                 specificationVendor);
+        }
+
+        final DeweyDecimal specificationVersion
+            = extension.getSpecificationVersion();
+        if (null != specificationVersion) {
+            attributes.putValue(prefix + SPECIFICATION_VERSION,
+                                 specificationVersion.toString());
+        }
+
+        final String implementationVendorID
+            = extension.getImplementationVendorID();
+        if (null != implementationVendorID) {
+            attributes.putValue(prefix + IMPLEMENTATION_VENDOR_ID,
+                                 implementationVendorID);
+        }
+
+        final String implementationVendor = extension.getImplementationVendor();
+        if (null != implementationVendor) {
+            attributes.putValue(prefix + IMPLEMENTATION_VENDOR,
+                                 implementationVendor);
+        }
+
+        final DeweyDecimal implementationVersion
+            = extension.getImplementationVersion();
+        if (null != implementationVersion) {
+            attributes.putValue(prefix + IMPLEMENTATION_VERSION,
+                                 implementationVersion.toString());
+        }
+
+        final String implementationURL = extension.getImplementationURL();
+        if (null != implementationURL) {
+            attributes.putValue(prefix + IMPLEMENTATION_URL,
+                                 implementationURL);
+        }
+    }
+
+    /**
+     * The constructor to create Extension object.
+     * Note that every component is allowed to be specified
+     * but only the extensionName is mandatory.
+     *
+     * @param extensionName the name of extension.
+     * @param specificationVersion the specification Version of extension.
+     * @param specificationVendor the specification Vendor of extension.
+     * @param implementationVersion the implementation Version of extension.
+     * @param implementationVendor the implementation Vendor of extension.
+     * @param implementationVendorId the implementation VendorId of extension.
+     * @param implementationURL the implementation URL of extension.
+     */
+    public Extension(final String extensionName,
+                      final String specificationVersion,
+                      final String specificationVendor,
+                      final String implementationVersion,
+                      final String implementationVendor,
+                      final String implementationVendorId,
+                      final String implementationURL) {
+        this.extensionName = extensionName;
+        this.specificationVendor = specificationVendor;
+
+        if (null != specificationVersion) {
+            try {
+                this.specificationVersion
+                    = new DeweyDecimal(specificationVersion);
+            } catch (final NumberFormatException nfe) {
+                final String error = "Bad specification version format '"
+                    + specificationVersion + "' in '" + extensionName
+                    + "'. (Reason: " + nfe + ")";
+                throw new IllegalArgumentException(error);
+            }
+        }
+
+        this.implementationURL = implementationURL;
+        this.implementationVendor = implementationVendor;
+        this.implementationVendorID = implementationVendorId;
+
+        if (null != implementationVersion) {
+            try {
+                this.implementationVersion
+                    = new DeweyDecimal(implementationVersion);
+            } catch (final NumberFormatException nfe) {
+                final String error = "Bad implementation version format '"
+                    + implementationVersion + "' in '" + extensionName
+                    + "'. (Reason: " + nfe + ")";
+                throw new IllegalArgumentException(error);
+            }
+        }
+
+        if (null == this.extensionName) {
+            throw new NullPointerException("extensionName property is null");
+        }
+    }
+
+    /**
+     * Get the name of the extension.
+     *
+     * @return the name of the extension
+     */
+    public String getExtensionName() {
+        return extensionName;
+    }
+
+    /**
+     * Get the vendor of the extensions specification.
+     *
+     * @return the vendor of the extensions specification.
+     */
+    public String getSpecificationVendor() {
+        return specificationVendor;
+    }
+
+    /**
+     * Get the version of the extensions specification.
+     *
+     * @return the version of the extensions specification.
+     */
+    public DeweyDecimal getSpecificationVersion() {
+        return specificationVersion;
+    }
+
+    /**
+     * Get the url of the extensions implementation.
+     *
+     * @return the url of the extensions implementation.
+     */
+    public String getImplementationURL() {
+        return implementationURL;
+    }
+
+    /**
+     * Get the vendor of the extensions implementation.
+     *
+     * @return the vendor of the extensions implementation.
+     */
+    public String getImplementationVendor() {
+        return implementationVendor;
+    }
+
+    /**
+     * Get the vendorID of the extensions implementation.
+     *
+     * @return the vendorID of the extensions implementation.
+     */
+    public String getImplementationVendorID() {
+        return implementationVendorID;
+    }
+
+    /**
+     * Get the version of the extensions implementation.
+     *
+     * @return the version of the extensions implementation.
+     */
+    public DeweyDecimal getImplementationVersion() {
+        return implementationVersion;
+    }
+
+    /**
+     * Return a Compatibility enum indicating the relationship of this
+     * <code>Extension</code> with the specified <code>Extension</code>.
+     *
+     * @param required Description of the required optional package
+     * @return the enum indicating the compatibility (or lack thereof)
+     *         of specifed extension
+     */
+    public Compatibility getCompatibilityWith(final Extension required) {
+        // Extension Name must match
+        if (!extensionName.equals(required.getExtensionName())) {
+            return INCOMPATIBLE;
+        }
+
+        // Available specification version must be >= required
+        final DeweyDecimal requiredSpecificationVersion
+            = required.getSpecificationVersion();
+        if (null != requiredSpecificationVersion) {
+            if (null == specificationVersion
+                || !isCompatible(specificationVersion, requiredSpecificationVersion)) {
+                return REQUIRE_SPECIFICATION_UPGRADE;
+            }
+        }
+
+        // Implementation Vendor ID must match
+        final String requiredImplementationVendorID
+            = required.getImplementationVendorID();
+        if (null != requiredImplementationVendorID) {
+            if (null == implementationVendorID
+                || !implementationVendorID.equals(requiredImplementationVendorID)) {
+                return REQUIRE_VENDOR_SWITCH;
+            }
+        }
+
+        // Implementation version must be >= required
+        final DeweyDecimal requiredImplementationVersion
+            = required.getImplementationVersion();
+        if (null != requiredImplementationVersion) {
+            if (null == implementationVersion
+                || !isCompatible(implementationVersion, requiredImplementationVersion)) {
+                return REQUIRE_IMPLEMENTATION_UPGRADE;
+            }
+        }
+
+        // This available optional package satisfies the requirements
+        return COMPATIBLE;
+    }
+
+    /**
+     * Return <code>true</code> if the specified <code>Extension</code>
+     * (which represents an optional package required by an application)
+     * is satisfied by this <code>Extension</code> (which represents an
+     * optional package that is already installed.  Otherwise, return
+     * <code>false</code>.
+     *
+     * @param required Description of the required optional package
+     * @return true if the specified extension is compatible with this extension
+     */
+    public boolean isCompatibleWith(final Extension required) {
+        return (COMPATIBLE == getCompatibilityWith(required));
+    }
+
+    /**
+     * Return a String representation of this object.
+     *
+     * @return string representation of object.
+     */
+    public String toString() {
+        final String brace = ": ";
+
+        final StringBuffer sb = new StringBuffer(EXTENSION_NAME.toString());
+        sb.append(brace);
+        sb.append(extensionName);
+        sb.append(StringUtils.LINE_SEP);
+
+        if (null != specificationVersion) {
+            sb.append(SPECIFICATION_VERSION);
+            sb.append(brace);
+            sb.append(specificationVersion);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != specificationVendor) {
+            sb.append(SPECIFICATION_VENDOR);
+            sb.append(brace);
+            sb.append(specificationVendor);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationVersion) {
+            sb.append(IMPLEMENTATION_VERSION);
+            sb.append(brace);
+            sb.append(implementationVersion);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationVendorID) {
+            sb.append(IMPLEMENTATION_VENDOR_ID);
+            sb.append(brace);
+            sb.append(implementationVendorID);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationVendor) {
+            sb.append(IMPLEMENTATION_VENDOR);
+            sb.append(brace);
+            sb.append(implementationVendor);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationURL) {
+            sb.append(IMPLEMENTATION_URL);
+            sb.append(brace);
+            sb.append(implementationURL);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Return <code>true</code> if the first version number is greater than
+     * or equal to the second; otherwise return <code>false</code>.
+     *
+     * @param first First version number (dotted decimal)
+     * @param second Second version number (dotted decimal)
+     */
+    private boolean isCompatible(final DeweyDecimal first,
+                                 final DeweyDecimal second) {
+        return first.isGreaterThanOrEqual(second);
+    }
+
+    /**
+     * Retrieve all the extensions listed under a particular key
+     * (Usually EXTENSION_LIST or OPTIONAL_EXTENSION_LIST).
+     *
+     * @param manifest the manifest to extract extensions from
+     * @param listKey the key used to get list (Usually
+     *        EXTENSION_LIST or OPTIONAL_EXTENSION_LIST)
+     * @return the list of listed extensions
+     */
+    private static Extension[] getListed(final Manifest manifest,
+                                          final Attributes.Name listKey) {
+        final ArrayList results = new ArrayList();
+        final Attributes mainAttributes = manifest.getMainAttributes();
+
+        if (null != mainAttributes) {
+            getExtension(mainAttributes, results, listKey);
+        }
+
+        final Map entries = manifest.getEntries();
+        final Iterator keys = entries.keySet().iterator();
+        while (keys.hasNext()) {
+            final String key = (String) keys.next();
+            final Attributes attributes = (Attributes) entries.get(key);
+            getExtension(attributes, results, listKey);
+        }
+
+        return (Extension[]) results.toArray(new Extension[results.size()]);
+    }
+
+    /**
+     * Add required optional packages defined in the specified
+     * attributes entry, if any.
+     *
+     * @param attributes Attributes to be parsed
+     * @param required list to add required optional packages to
+     * @param listKey the key to use to lookup list, usually EXTENSION_LIST
+     *    or OPTIONAL_EXTENSION_LIST
+     */
+    private static void getExtension(final Attributes attributes,
+                                     final ArrayList required,
+                                     final Attributes.Name listKey) {
+        final String names = attributes.getValue(listKey);
+        if (null == names) {
+            return;
+        }
+
+        final String[] extentions = split(names, " ");
+        for (int i = 0; i < extentions.length; i++) {
+            final String prefix = extentions[ i ] + "-";
+            final Extension extension = getExtension(prefix, attributes);
+
+            if (null != extension) {
+                required.add(extension);
+            }
+        }
+    }
+
+    /**
+     * Splits the string on every token into an array of strings.
+     *
+     * @param string the string
+     * @param onToken the token
+     * @return the resultant array
+     */
+    private static String[] split(final String string,
+                                        final String onToken) {
+        final StringTokenizer tokenizer = new StringTokenizer(string, onToken);
+        final String[] result = new String[ tokenizer.countTokens() ];
+
+        for (int i = 0; i < result.length; i++) {
+            result[ i ] = tokenizer.nextToken();
+        }
+
+        return result;
+    }
+
+    /**
+     * Extract an Extension from Attributes.
+     * Prefix indicates the prefix checked for each string.
+     * Usually the prefix is <em>"&lt;extension&gt;-"</em> if looking for a
+     * <b>Required</b> extension. If you are looking for an
+     * <b>Available</b> extension
+     * then the prefix is <em>""</em>.
+     *
+     * @param prefix the prefix for each attribute name
+     * @param attributes Attributes to searched
+     * @return the new Extension object, or null
+     */
+    private static Extension getExtension(final String prefix,
+                                          final Attributes attributes) {
+        //WARNING: We trim the values of all the attributes because
+        //Some extension declarations are badly defined (ie have spaces
+        //after version or vendorID)
+        final String nameKey = prefix + EXTENSION_NAME;
+        final String name = getTrimmedString(attributes.getValue(nameKey));
+        if (null == name) {
+            return null;
+        }
+
+        final String specVendorKey = prefix + SPECIFICATION_VENDOR;
+        final String specVendor
+            = getTrimmedString(attributes.getValue(specVendorKey));
+        final String specVersionKey = prefix + SPECIFICATION_VERSION;
+        final String specVersion
+            = getTrimmedString(attributes.getValue(specVersionKey));
+
+        final String impVersionKey = prefix + IMPLEMENTATION_VERSION;
+        final String impVersion
+            = getTrimmedString(attributes.getValue(impVersionKey));
+        final String impVendorKey = prefix + IMPLEMENTATION_VENDOR;
+        final String impVendor
+            = getTrimmedString(attributes.getValue(impVendorKey));
+        final String impVendorIDKey = prefix + IMPLEMENTATION_VENDOR_ID;
+        final String impVendorId
+            = getTrimmedString(attributes.getValue(impVendorIDKey));
+        final String impURLKey = prefix + IMPLEMENTATION_URL;
+        final String impURL = getTrimmedString(attributes.getValue(impURLKey));
+
+        return new Extension(name, specVersion, specVendor, impVersion,
+                              impVendor, impVendorId, impURL);
+    }
+
+    /**
+     * Trim the supplied string if the string is non-null
+     *
+     * @param value the string to trim or null
+     * @return the trimmed string or null
+     */
+    private static String getTrimmedString(final String value) {
+        return null == value ? null : value.trim();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java
new file mode 100644
index 0000000..0f00b55
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionAdapter.java
@@ -0,0 +1,227 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Simple class that represents an Extension and conforms to Ants
+ * patterns.
+ *
+ * @ant.datatype name="extension"
+ */
+public class ExtensionAdapter extends DataType {
+    /**
+     * The name of the optional package being made available, or required.
+     */
+    private String extensionName;
+
+    /**
+     * The version number (dotted decimal notation) of the specification
+     * to which this optional package conforms.
+     */
+    private DeweyDecimal specificationVersion;
+
+    /**
+     * The name of the company or organization that originated the
+     * specification to which this optional package conforms.
+     */
+    private String specificationVendor;
+
+    /**
+     * The unique identifier of the company that produced the optional
+     * package contained in this JAR file.
+     */
+    private String implementationVendorID;
+
+    /**
+     * The name of the company or organization that produced this
+     * implementation of this optional package.
+     */
+    private String implementationVendor;
+
+    /**
+     * The version number (dotted decimal notation) for this implementation
+     * of the optional package.
+     */
+    private DeweyDecimal implementationVersion;
+
+    /**
+     * The URL from which the most recent version of this optional package
+     * can be obtained if it is not already installed.
+     */
+    private String implementationURL;
+
+    /**
+     * Set the name of extension.
+     *
+     * @param extensionName the name of extension
+     */
+    public void setExtensionName(final String extensionName) {
+        verifyNotAReference();
+        this.extensionName = extensionName;
+    }
+
+    /**
+     * Set the specificationVersion of extension.
+     *
+     * @param specificationVersion the specificationVersion of extension
+     */
+    public void setSpecificationVersion(final String specificationVersion) {
+        verifyNotAReference();
+        this.specificationVersion = new DeweyDecimal(specificationVersion);
+    }
+
+    /**
+     * Set the specificationVendor of extension.
+     *
+     * @param specificationVendor the specificationVendor of extension
+     */
+    public void setSpecificationVendor(final String specificationVendor) {
+        verifyNotAReference();
+        this.specificationVendor = specificationVendor;
+    }
+
+    /**
+     * Set the implementationVendorID of extension.
+     *
+     * @param implementationVendorID the implementationVendorID of extension
+     */
+    public void setImplementationVendorId(final String implementationVendorID) {
+        verifyNotAReference();
+        this.implementationVendorID = implementationVendorID;
+    }
+
+    /**
+     * Set the implementationVendor of extension.
+     *
+     * @param implementationVendor the implementationVendor of extension
+     */
+    public void setImplementationVendor(final String implementationVendor) {
+        verifyNotAReference();
+        this.implementationVendor = implementationVendor;
+    }
+
+    /**
+     * Set the implementationVersion of extension.
+     *
+     * @param implementationVersion the implementationVersion of extension
+     */
+    public void setImplementationVersion(final String implementationVersion) {
+        verifyNotAReference();
+        this.implementationVersion = new DeweyDecimal(implementationVersion);
+    }
+
+    /**
+     * Set the implementationURL of extension.
+     *
+     * @param implementationURL the implementationURL of extension
+     */
+    public void setImplementationUrl(final String implementationURL) {
+        verifyNotAReference();
+        this.implementationURL = implementationURL;
+    }
+
+    /**
+     * Makes this instance in effect a reference to another ExtensionAdapter
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     *
+     * @param reference the reference to which this instance is associated
+     * @exception BuildException if this instance already has been configured.
+     */
+    public void setRefid(final Reference reference)
+        throws BuildException {
+        if (null != extensionName
+            || null != specificationVersion
+            || null != specificationVendor
+            || null != implementationVersion
+            || null != implementationVendorID
+            || null != implementationVendor
+            || null != implementationURL) {
+            throw tooManyAttributes();
+        }
+        // change this to get the objects from the other reference
+        Object o = reference.getReferencedObject(getProject());
+        if (o instanceof ExtensionAdapter) {
+            final ExtensionAdapter other = (ExtensionAdapter) o;
+            extensionName = other.extensionName;
+            specificationVersion = other.specificationVersion;
+            specificationVendor = other.specificationVendor;
+            implementationVersion = other.implementationVersion;
+            implementationVendorID = other.implementationVendorID;
+            implementationVendor = other.implementationVendor;
+            implementationURL = other.implementationURL;
+        } else {
+            final String message =
+                reference.getRefId() + " doesn\'t refer to a Extension";
+            throw new BuildException(message);
+        }
+
+        super.setRefid(reference);
+    }
+
+    private void verifyNotAReference()
+        throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+    }
+
+    /**
+     * Convert this adpater object into an extension object.
+     *
+     * @return the extension object
+     */
+    Extension toExtension()
+        throws BuildException {
+        if (null == extensionName) {
+            final String message = "Extension is missing name.";
+            throw new BuildException(message);
+        }
+
+        String specificationVersionString = null;
+        if (null != specificationVersion) {
+            specificationVersionString = specificationVersion.toString();
+        }
+        String implementationVersionString = null;
+        if (null != implementationVersion) {
+            implementationVersionString = implementationVersion.toString();
+        }
+        return new Extension(extensionName,
+                              specificationVersionString,
+                              specificationVendor,
+                              implementationVersionString,
+                              implementationVendor,
+                              implementationVendorID,
+                              implementationURL);
+    }
+
+    /**
+     * a debug toString method.
+     * @return the extension in a string.
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "{" + toExtension().toString() + "}";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java
new file mode 100644
index 0000000..0815065
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionResolver.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Interface to locate a File that satisfies extension.
+ *
+ */
+public interface ExtensionResolver {
+    /**
+     * Attempt to locate File that satisfies
+     * extension via resolver.
+     *
+     * @param extension the extension
+     * @param project the Ant project instance
+     * @return the File satisfying extension, null
+     *         if can not resolve extension
+     * @throws BuildException if error occurs attempting to
+     *         resolve extension
+     */
+    File resolve(Extension extension, Project project)
+        throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java
new file mode 100644
index 0000000..069f095
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionSet.java
@@ -0,0 +1,125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * The Extension set lists a set of "Optional Packages" /
+ * "Extensions".
+ *
+ * @ant.datatype name="extension-set"
+ */
+public class ExtensionSet
+    extends DataType {
+    /**
+     * ExtensionAdapter objects representing extensions.
+     */
+    private final ArrayList extensions = new ArrayList();
+
+    /**
+     * Filesets specifying all the extensions wanted.
+     */
+    private final ArrayList extensionsFilesets = new ArrayList();
+
+    /**
+     * Adds an extension that this library requires.
+     *
+     * @param extensionAdapter an extension that this library requires.
+     */
+    public void addExtension(final ExtensionAdapter extensionAdapter) {
+        extensions.add(extensionAdapter);
+    }
+
+    /**
+     * Adds a set of files about which extensions data will be extracted.
+     *
+     * @param fileSet a set of files about which extensions data will be extracted.
+     */
+    public void addLibfileset(final LibFileSet fileSet) {
+        extensionsFilesets.add(fileSet);
+    }
+
+    /**
+     * Adds a set of files about which extensions data will be extracted.
+     *
+     * @param fileSet a set of files about which extensions data will be extracted.
+     */
+    public void addFileset(final FileSet fileSet) {
+        extensionsFilesets.add(fileSet);
+    }
+
+    /**
+     * Extract a set of Extension objects from the ExtensionSet.
+     *
+     * @param proj the project instance.
+     * @return an array containing the Extensions from this set
+     * @throws BuildException if an error occurs
+     */
+    public Extension[] toExtensions(final Project proj)
+        throws BuildException {
+        final ArrayList extensionsList = ExtensionUtil.toExtensions(extensions);
+        ExtensionUtil.extractExtensions(proj, extensionsList, extensionsFilesets);
+        return (Extension[]) extensionsList.toArray(new Extension[extensionsList.size()]);
+    }
+
+    /**
+     * Makes this instance in effect a reference to another ExtensionSet
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     *
+     * @param reference the reference to which this instance is associated
+     * @exception BuildException if this instance already has been configured.
+     */
+    public void setRefid(final Reference reference)
+        throws BuildException {
+        if (!extensions.isEmpty() || !extensionsFilesets.isEmpty()) {
+            throw tooManyAttributes();
+        }
+        // change this to get the objects from the other reference
+        final Object object =
+            reference.getReferencedObject(getProject());
+        if (object instanceof ExtensionSet) {
+            final ExtensionSet other = (ExtensionSet) object;
+            extensions.addAll(other.extensions);
+            extensionsFilesets.addAll(other.extensionsFilesets);
+        } else {
+            final String message =
+                reference.getRefId() + " doesn\'t refer to a ExtensionSet";
+            throw new BuildException(message);
+        }
+
+        super.setRefid(reference);
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     * @return the extensions in a string.
+     */
+    public String toString() {
+        return "ExtensionSet" + Arrays.asList(toExtensions(getProject()));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java
new file mode 100644
index 0000000..089c789
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtensionUtil.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * A set of useful methods relating to extensions.
+ *
+ */
+public final class ExtensionUtil {
+    /**
+     * Class is not meant to be instantiated.
+     */
+    private ExtensionUtil() {
+        //all methods static
+    }
+
+    /**
+     * Convert a list of extensionAdapter objects to extensions.
+     *
+     * @param adapters the list of ExtensionAdapterss to add to convert
+     * @throws BuildException if an error occurs
+     */
+    static ArrayList toExtensions(final List adapters)
+        throws BuildException {
+        final ArrayList results = new ArrayList();
+
+        final int size = adapters.size();
+        for (int i = 0; i < size; i++) {
+            final ExtensionAdapter adapter =
+                (ExtensionAdapter) adapters.get(i);
+            final Extension extension = adapter.toExtension();
+            results.add(extension);
+        }
+
+        return results;
+    }
+
+    /**
+     * Generate a list of extensions from a specified fileset.
+     *
+     * @param libraries the list to add extensions to
+     * @param fileset the filesets containing librarys
+     * @throws BuildException if an error occurs
+     */
+    static void extractExtensions(final Project project,
+                                   final List libraries,
+                                   final List fileset)
+        throws BuildException {
+        if (!fileset.isEmpty()) {
+            final Extension[] extensions = getExtensions(project,
+                                                          fileset);
+            for (int i = 0; i < extensions.length; i++) {
+                libraries.add(extensions[ i ]);
+            }
+        }
+    }
+
+    /**
+     * Retrieve extensions from the specified libraries.
+     *
+     * @param libraries the filesets for libraries
+     * @return the extensions contained in libraries
+     * @throws BuildException if failing to scan libraries
+     */
+    private static Extension[] getExtensions(final Project project,
+                                              final List libraries)
+        throws BuildException {
+        final ArrayList extensions = new ArrayList();
+        final Iterator iterator = libraries.iterator();
+        while (iterator.hasNext()) {
+            final FileSet fileSet = (FileSet) iterator.next();
+
+            boolean includeImpl = true;
+            boolean includeURL = true;
+
+            if (fileSet instanceof LibFileSet) {
+                LibFileSet libFileSet = (LibFileSet) fileSet;
+                includeImpl = libFileSet.isIncludeImpl();
+                includeURL = libFileSet.isIncludeURL();
+            }
+
+            final DirectoryScanner scanner = fileSet.getDirectoryScanner(project);
+            final File basedir = scanner.getBasedir();
+            final String[] files = scanner.getIncludedFiles();
+            for (int i = 0; i < files.length; i++) {
+                final File file = new File(basedir, files[ i ]);
+                loadExtensions(file, extensions, includeImpl, includeURL);
+            }
+        }
+        return (Extension[]) extensions.toArray(new Extension[extensions.size()]);
+    }
+
+    /**
+     * Load list of available extensions from specified file.
+     *
+     * @param file the file
+     * @param extensionList the list to add available extensions to
+     * @throws BuildException if there is an error
+     */
+    private static void loadExtensions(final File file,
+                                        final List extensionList,
+                                        final boolean includeImpl,
+                                        final boolean includeURL)
+        throws BuildException {
+        try {
+            final JarFile jarFile = new JarFile(file);
+            final Extension[] extensions =
+                Extension.getAvailable(jarFile.getManifest());
+            for (int i = 0; i < extensions.length; i++) {
+                final Extension extension = extensions[ i ];
+                addExtension(extensionList, extension, includeImpl, includeURL);
+            }
+        } catch (final Exception e) {
+            throw new BuildException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Add extension to list.
+     * If extension should not have implementation details but
+     * does strip them. If extension should not have url but does
+     * then strip it.
+     *
+     * @param extensionList the list of extensions to add to
+     * @param originalExtension the extension
+     * @param includeImpl false to exclude implementation details
+     * @param includeURL false to exclude implementation URL
+     */
+    private static void addExtension(final List extensionList,
+                                      final Extension originalExtension,
+                                      final boolean includeImpl,
+                                      final boolean includeURL) {
+        Extension extension = originalExtension;
+        if (!includeURL
+            && null != extension.getImplementationURL()) {
+            extension =
+                new Extension(extension.getExtensionName(),
+                               extension.getSpecificationVersion().toString(),
+                               extension.getSpecificationVendor(),
+                               extension.getImplementationVersion().toString(),
+                               extension.getImplementationVendor(),
+                               extension.getImplementationVendorID(),
+                               null);
+        }
+
+        final boolean hasImplAttributes =
+            null != extension.getImplementationURL()
+            || null != extension.getImplementationVersion()
+            || null != extension.getImplementationVendorID()
+            || null != extension.getImplementationVendor();
+
+        if (!includeImpl && hasImplAttributes) {
+            extension =
+                new Extension(extension.getExtensionName(),
+                               extension.getSpecificationVersion().toString(),
+                               extension.getSpecificationVendor(),
+                               null,
+                               null,
+                               null,
+                               extension.getImplementationURL());
+        }
+
+        extensionList.add(extension);
+    }
+
+    /**
+     * Retrieve manifest for specified file.
+     *
+     * @param file the file
+     * @return the manifest
+     * @throws BuildException if errror occurs (file doesn't exist,
+     *         file not a jar, manifest doesn't exist in file)
+     */
+    static Manifest getManifest(final File file)
+        throws BuildException {
+        try {
+            final JarFile jarFile = new JarFile(file);
+            Manifest m = jarFile.getManifest();
+            if (m == null) {
+                throw new BuildException(file + " doesn't have a MANIFEST");
+            }
+            return m;
+        } catch (final IOException ioe) {
+            throw new BuildException(ioe.getMessage(), ioe);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java
new file mode 100644
index 0000000..d52bec4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/ExtraAttribute.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Simple holder for extra attributes in main section of manifest.
+ *
+ * @todo Refactor this and all the other parameter, sysproperty,
+ *   property etc into a single class in framework
+ */
+public class ExtraAttribute {
+    private String name;
+    private String value;
+
+    /**
+     * Set the name of the parameter.
+     *
+     * @param name the name of parameter
+     */
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Set the value of the parameter.
+     *
+     * @param value the parameter value
+     */
+    public void setValue(final String value) {
+        this.value = value;
+    }
+
+    /**
+     * Retrieve name of parameter.
+     *
+     * @return the name of parameter.
+     */
+    String getName() {
+        return name;
+    }
+
+    /**
+     * Retrieve the value of parameter.
+     *
+     * @return the value of parameter.
+     */
+    String getValue() {
+        return value;
+    }
+
+    /**
+     * Make sure that neither the name or the value
+     * is null.
+     *
+     * @throws BuildException if the attribute is invalid.
+     */
+    public void validate() throws BuildException {
+        if (null == name) {
+            final String message = "Missing name from parameter.";
+            throw new BuildException(message);
+        } else if (null == value) {
+            final String message = "Missing value from parameter " + name + ".";
+            throw new BuildException(message);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java
new file mode 100644
index 0000000..9787be3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibAvailableTask.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.jar.Manifest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Checks whether an extension is present in a fileset or an extensionSet.
+ *
+ * @ant.task name="jarlib-available"
+ */
+public class JarLibAvailableTask extends Task {
+    /**
+     * The library to display information about.
+     */
+    private File libraryFile;
+
+    /**
+     * Filesets specifying all the librarys
+     * to display information about.
+     */
+    private final Vector extensionFileSets = new Vector();
+
+    /**
+     * The name of the property to set if extension is available.
+     */
+    private String propertyName;
+
+    /**
+     * The extension that is required.
+     */
+    private ExtensionAdapter requiredExtension;
+
+    /**
+     * The name of property to set if extensions are available.
+     *
+     * @param property The name of property to set if extensions is available.
+     */
+    public void setProperty(final String property) {
+        this.propertyName = property;
+    }
+
+    /**
+     * The JAR library to check.
+     *
+     * @param file The jar library to check.
+     */
+    public void setFile(final File file) {
+        this.libraryFile = file;
+    }
+
+    /**
+     * Set the Extension looking for.
+     *
+     * @param extension Set the Extension looking for.
+     */
+    public void addConfiguredExtension(final ExtensionAdapter extension) {
+        if (null != requiredExtension) {
+            final String message = "Can not specify extension to "
+                + "search for multiple times.";
+            throw new BuildException(message);
+        }
+        requiredExtension = extension;
+    }
+
+    /**
+     * Adds a set of extensions to search in.
+     *
+     * @param extensionSet a set of extensions to search in.
+     */
+    public void addConfiguredExtensionSet(final ExtensionSet extensionSet) {
+        extensionFileSets.addElement(extensionSet);
+    }
+
+    /**
+     * Execute the task.
+     *
+     * @throws BuildException if somethign goes wrong.
+     */
+    public void execute() throws BuildException {
+        validate();
+
+        final Extension test = requiredExtension.toExtension();
+
+        // Check if list of files to check has been specified
+        if (!extensionFileSets.isEmpty()) {
+            final Iterator iterator = extensionFileSets.iterator();
+            while (iterator.hasNext()) {
+                final ExtensionSet extensionSet
+                    = (ExtensionSet) iterator.next();
+                final Extension[] extensions =
+                    extensionSet.toExtensions(getProject());
+                for (int i = 0; i < extensions.length; i++) {
+                    final Extension extension = extensions[ i ];
+                    if (extension.isCompatibleWith(test)) {
+                        getProject().setNewProperty(propertyName, "true");
+                    }
+                }
+            }
+        } else {
+            final Manifest manifest = ExtensionUtil.getManifest(libraryFile);
+            final Extension[] extensions = Extension.getAvailable(manifest);
+            for (int i = 0; i < extensions.length; i++) {
+                final Extension extension = extensions[ i ];
+                if (extension.isCompatibleWith(test)) {
+                    getProject().setNewProperty(propertyName, "true");
+                }
+            }
+        }
+    }
+
+    /**
+     * Validate the tasks parameters.
+     *
+     * @throws BuildException if invalid parameters found
+     */
+    private void validate() throws BuildException {
+        if (null == requiredExtension) {
+            final String message = "Extension element must be specified.";
+            throw new BuildException(message);
+        }
+
+        if (null == libraryFile && extensionFileSets.isEmpty()) {
+            final String message = "File attribute not specified.";
+            throw new BuildException(message);
+        }
+        if (null != libraryFile && !libraryFile.exists()) {
+            final String message = "File '" + libraryFile + "' does not exist.";
+            throw new BuildException(message);
+        }
+        if (null != libraryFile && !libraryFile.isFile()) {
+            final String message = "\'" + libraryFile + "\' is not a file.";
+            throw new BuildException(message);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java
new file mode 100644
index 0000000..945c3f4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibDisplayTask.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Displays the "Optional Package" and "Package Specification" information
+ * contained within the specified JARs.
+ *
+ * <p>Prior to JDK1.3, an "Optional Package" was known as an Extension.
+ * The specification for this mechanism is available in the JDK1.3
+ * documentation in the directory
+ * $JDK_HOME/docs/guide/extensions/versioning.html. Alternatively it is
+ * available online at <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+ * http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+ *
+ * @ant.task name="jarlib-display"
+ */
+public class JarLibDisplayTask extends Task {
+    /**
+     * The library to display information about.
+     */
+    private File libraryFile;
+
+    /**
+     * Filesets specifying all the librarys
+     * to display information about.
+     */
+    private final Vector libraryFileSets = new Vector();
+
+    /**
+     * The JAR library to display information for.
+     *
+     * @param file The jar library to display information for.
+     */
+    public void setFile(final File file) {
+        this.libraryFile = file;
+    }
+
+    /**
+     * Adds a set of files about which library data will be displayed.
+     *
+     * @param fileSet a set of files about which library data will be displayed.
+     */
+    public void addFileset(final FileSet fileSet) {
+        libraryFileSets.addElement(fileSet);
+    }
+
+    /**
+     * Execute the task.
+     *
+     * @throws BuildException if the task fails.
+     */
+    public void execute() throws BuildException {
+        validate();
+
+        final LibraryDisplayer displayer = new LibraryDisplayer();
+        // Check if list of files to check has been specified
+        if (!libraryFileSets.isEmpty()) {
+            final Iterator iterator = libraryFileSets.iterator();
+            while (iterator.hasNext()) {
+                final FileSet fileSet = (FileSet) iterator.next();
+                final DirectoryScanner scanner
+                    = fileSet.getDirectoryScanner(getProject());
+                final File basedir = scanner.getBasedir();
+                final String[] files = scanner.getIncludedFiles();
+                for (int i = 0; i < files.length; i++) {
+                    final File file = new File(basedir, files[ i ]);
+                    displayer.displayLibrary(file);
+                }
+            }
+        } else {
+            displayer.displayLibrary(libraryFile);
+        }
+    }
+
+    /**
+     * Validate the tasks parameters.
+     *
+     * @throws BuildException if invalid parameters found
+     */
+    private void validate() throws BuildException {
+        if (null == libraryFile && libraryFileSets.isEmpty()) {
+            final String message = "File attribute not specified.";
+            throw new BuildException(message);
+        }
+        if (null != libraryFile && !libraryFile.exists()) {
+            final String message = "File '" + libraryFile + "' does not exist.";
+            throw new BuildException(message);
+        }
+        if (null != libraryFile && !libraryFile.isFile()) {
+            final String message = "\'" + libraryFile + "\' is not a file.";
+            throw new BuildException(message);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java
new file mode 100644
index 0000000..37b24a3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibManifestTask.java
@@ -0,0 +1,295 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Generates a manifest that declares all the dependencies.
+ * The dependencies are determined by looking in the
+ * specified path and searching for Extension / "Optional Package"
+ * specifications in the manifests of the jars.
+ *
+ * <p>Prior to JDK1.3, an "Optional Package" was known as an Extension.
+ * The specification for this mechanism is available in the JDK1.3
+ * documentation in the directory
+ * $JDK_HOME/docs/guide/extensions/versioning.html. Alternatively it is
+ * available online at <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html">
+ * http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html</a>.</p>
+ *
+ * @ant.task name="jarlib-manifest"
+ */
+public final class JarLibManifestTask extends Task {
+    /**
+     * Version of manifest spec that task generates.
+     */
+    private static final String MANIFEST_VERSION = "1.0";
+
+    /**
+     * "Created-By" string used when creating manifest.
+     */
+    private static final String CREATED_BY = "Created-By";
+
+    /**
+     * The library to display information about.
+     */
+    private File destFile;
+
+    /**
+     * The extension supported by this library (if any).
+     */
+    private Extension extension;
+
+    /**
+     * ExtensionAdapter objects representing
+     * dependencies required by library.
+     */
+    private final ArrayList dependencies = new ArrayList();
+
+    /**
+     * ExtensionAdapter objects representing optional
+     * dependencies required by library.
+     */
+    private final ArrayList optionals = new ArrayList();
+
+    /**
+     * Extra attributes the user specifies for main section
+     * in manifest.
+     */
+    private final ArrayList extraAttributes = new ArrayList();
+
+    /**
+     * The location where generated manifest is placed.
+     *
+     * @param destFile The location where generated manifest is placed.
+     */
+    public void setDestfile(final File destFile) {
+        this.destFile = destFile;
+    }
+
+    /**
+     * Adds an extension that this library implements.
+     *
+     * @param extensionAdapter an extension that this library implements.
+     *
+     * @throws BuildException if there is multiple extensions detected
+     *         in the library.
+     */
+    public void addConfiguredExtension(final ExtensionAdapter extensionAdapter)
+            throws BuildException {
+        if (null != extension) {
+            throw new BuildException("Can not have multiple extensions defined in one library.");
+        }
+        extension = extensionAdapter.toExtension();
+    }
+
+    /**
+     * Adds a set of extensions that this library requires.
+     *
+     * @param extensionSet a set of extensions that this library requires.
+     */
+    public void addConfiguredDepends(final ExtensionSet extensionSet) {
+        dependencies.add(extensionSet);
+    }
+
+    /**
+     * Adds a set of extensions that this library optionally requires.
+     *
+     * @param extensionSet a set of extensions that this library optionally requires.
+     */
+    public void addConfiguredOptions(final ExtensionSet extensionSet) {
+        optionals.add(extensionSet);
+    }
+
+    /**
+     * Adds an attribute that is to be put in main section of manifest.
+     *
+     * @param attribute an attribute that is to be put in main section of manifest.
+     */
+    public void addConfiguredAttribute(final ExtraAttribute attribute) {
+        extraAttributes.add(attribute);
+    }
+
+    /**
+     * Execute the task.
+     *
+     * @throws BuildException if the task fails.
+     */
+    public void execute() throws BuildException {
+        validate();
+
+        final Manifest manifest = new Manifest();
+        final Attributes attributes = manifest.getMainAttributes();
+
+        attributes.put(Attributes.Name.MANIFEST_VERSION, MANIFEST_VERSION);
+        attributes.putValue(CREATED_BY, "Apache Ant "
+                + getProject().getProperty(MagicNames.ANT_VERSION));
+
+        appendExtraAttributes(attributes);
+
+        if (null != extension) {
+            Extension.addExtension(extension, attributes);
+        }
+
+        //Add all the dependency data to manifest for dependencies
+        final ArrayList depends = toExtensions(dependencies);
+        appendExtensionList(attributes, Extension.EXTENSION_LIST, "lib", depends.size());
+        appendLibraryList(attributes, "lib", depends);
+
+        // Add all the dependency data to manifest for "optional"
+        //dependencies
+        final ArrayList option = toExtensions(optionals);
+        appendExtensionList(attributes, Extension.OPTIONAL_EXTENSION_LIST, "opt", option.size());
+        appendLibraryList(attributes, "opt", option);
+
+        try {
+            log("Generating manifest " + destFile.getAbsoluteFile(), Project.MSG_INFO);
+            writeManifest(manifest);
+        } catch (final IOException ioe) {
+            throw new BuildException(ioe.getMessage(), ioe);
+        }
+    }
+
+    /**
+     * Validate the tasks parameters.
+     *
+     * @throws BuildException if invalid parameters found
+     */
+    private void validate() throws BuildException {
+        if (null == destFile) {
+            throw new BuildException("Destfile attribute not specified.");
+        }
+        if (destFile.exists() && !destFile.isFile()) {
+            throw new BuildException(destFile + " is not a file.");
+        }
+    }
+
+    /**
+     * Add any extra attributes to the manifest.
+     *
+     * @param attributes the manifest section to write
+     *        attributes to
+     */
+    private void appendExtraAttributes(final Attributes attributes) {
+        final Iterator iterator = extraAttributes.iterator();
+        while (iterator.hasNext()) {
+            final ExtraAttribute attribute =
+                (ExtraAttribute) iterator.next();
+            attributes.putValue(attribute.getName(),
+                                 attribute.getValue());
+        }
+    }
+
+    /**
+     * Write out manifest to destfile.
+     *
+     * @param manifest the manifest
+     * @throws IOException if error writing file
+     */
+    private void writeManifest(final Manifest manifest) throws IOException {
+        FileOutputStream output = null;
+        try {
+            output = new FileOutputStream(destFile);
+            manifest.write(output);
+            output.flush();
+        } finally {
+            if (null != output) {
+                try {
+                    output.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+    /**
+     * Append specified extensions to specified attributes.
+     * Use the extensionKey to list the extensions, usually "Extension-List:"
+     * for required dependencies and "Optional-Extension-List:" for optional
+     * dependencies. NOTE: "Optional" dependencies are not part of the
+     * specification.
+     *
+     * @param attributes the attributes to add extensions to
+     * @param extensions the list of extensions
+     * @throws BuildException if an error occurs
+     */
+    private void appendLibraryList(final Attributes attributes, final String listPrefix,
+            final ArrayList extensions) throws BuildException {
+        final int size = extensions.size();
+        for (int i = 0; i < size; i++) {
+            final Extension ext = (Extension) extensions.get(i);
+            final String prefix = listPrefix + i + "-";
+            Extension.addExtension(ext, prefix, attributes);
+        }
+    }
+
+    /**
+     * Append an attribute such as "Extension-List: lib0 lib1 lib2"
+     * using specified prefix and counting up to specified size.
+     * Also use specified extensionKey so that can generate list of
+     * optional dependencies aswell.
+     *
+     * @param size the number of librarys to list
+     * @param listPrefix the prefix for all librarys
+     * @param attributes the attributes to add key-value to
+     * @param extensionKey the key to use
+     */
+    private void appendExtensionList(final Attributes attributes,
+            final Attributes.Name extensionKey, final String listPrefix, final int size) {
+        final StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < size; i++) {
+            sb.append(listPrefix);
+            sb.append(i);
+            sb.append(' ');
+        }
+        //add in something like
+        //"Extension-List: javahelp java3d"
+        attributes.put(extensionKey, sb.toString());
+    }
+
+    /**
+     * Convert a list of ExtensionSet objects to extensions.
+     *
+     * @param extensionSets the list of ExtensionSets to add to list
+     * @throws BuildException if an error occurs
+     */
+    private ArrayList toExtensions(final ArrayList extensionSets) throws BuildException {
+        final ArrayList results = new ArrayList();
+
+        final int size = extensionSets.size();
+        for (int i = 0; i < size; i++) {
+            final ExtensionSet set = (ExtensionSet) extensionSets.get(i);
+            final Extension[] extensions = set.toExtensions(getProject());
+            for (int j = 0; j < extensions.length; j++) {
+                results.add(extensions[ j ]);
+            }
+        }
+        return results;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java
new file mode 100644
index 0000000..e6409cf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/JarLibResolveTask.java
@@ -0,0 +1,267 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.jar.Manifest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.AntResolver;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.LocationResolver;
+import org.apache.tools.ant.taskdefs.optional.extension.resolvers.URLResolver;
+
+/**
+ * Tries to locate a JAR to satisfy an extension and place
+ * location of JAR into property.
+ *
+ * @ant.task name="jarlib-resolve"
+ */
+public class JarLibResolveTask extends Task {
+    /**
+     * The name of the property in which the location of
+     * library is stored.
+     */
+    private String propertyName;
+
+    /**
+     * The extension that is required.
+     */
+    private Extension requiredExtension;
+
+    /**
+     * The set of resolvers to use to attempt to locate library.
+     */
+    private final ArrayList resolvers = new ArrayList();
+
+    /**
+     * Flag to indicate that you should check that
+     * the librarys resolved actually contain
+     * extension and if they don't then raise
+     * an exception.
+     */
+    private boolean checkExtension = true;
+
+    /**
+     * Flag indicating whether or not you should
+     * throw a BuildException if you cannot resolve
+     * library.
+     */
+    private boolean failOnError = true;
+
+    /**
+     * The name of the property in which the location of
+     * library is stored.
+     *
+     * @param property The name of the property in which the location of
+     *                 library is stored.
+     */
+    public void setProperty(final String property) {
+        this.propertyName = property;
+    }
+
+    /**
+     * Check nested libraries for extensions
+     *
+     * @param checkExtension if true, libraries returned by nested
+     * resolvers should be checked to see if they supply extension.
+     */
+    public void setCheckExtension(final boolean checkExtension) {
+        this.checkExtension = checkExtension;
+    }
+
+    /**
+     * Set whether to fail if error.
+     *
+     * @param failOnError if true, failure to locate library should fail build.
+     */
+    public void setFailOnError(final boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * Adds location resolver to look for a library in a location
+     * relative to project directory.
+     *
+     * @param loc the resolver location to search.
+     */
+    public void addConfiguredLocation(final LocationResolver loc) {
+        resolvers.add(loc);
+    }
+
+    /**
+     * Adds a URL resolver to download a library from a URL
+     * to a local file.
+     *
+     * @param url the URL resolver from which to download the library
+     */
+    public void addConfiguredUrl(final URLResolver url) {
+        resolvers.add(url);
+    }
+
+    /**
+     * Adds Ant resolver to run an Ant build file to generate a library.
+     *
+     * @param ant the AntResolver to generate the library.
+     */
+    public void addConfiguredAnt(final AntResolver ant) {
+        resolvers.add(ant);
+    }
+
+    /**
+     * Set the Extension looking for.
+     *
+     * @param extension Set the Extension looking for.
+     */
+    public void addConfiguredExtension(final ExtensionAdapter extension) {
+        if (null != requiredExtension) {
+            final String message = "Can not specify extension to "
+                + "resolve multiple times.";
+            throw new BuildException(message);
+        }
+        requiredExtension = extension.toExtension();
+    }
+
+    /**
+     * Execute the task.
+     *
+     * @throws BuildException if the task fails.
+     */
+    public void execute() throws BuildException {
+        validate();
+
+        getProject().log("Resolving extension: " + requiredExtension, Project.MSG_VERBOSE);
+
+        String candidate = getProject().getProperty(propertyName);
+
+        if (null != candidate) {
+            final String message = "Property Already set to: " + candidate;
+            if (failOnError) {
+                throw new BuildException(message);
+            }
+            getProject().log(message, Project.MSG_ERR);
+            return;
+        }
+
+        final int size = resolvers.size();
+        for (int i = 0; i < size; i++) {
+            final ExtensionResolver resolver =
+                (ExtensionResolver) resolvers.get(i);
+
+            getProject().log("Searching for extension using Resolver:" + resolver,
+                    Project.MSG_VERBOSE);
+
+            try {
+                final File file = resolver.resolve(requiredExtension, getProject());
+                try {
+                    checkExtension(file);
+                    return;
+                } catch (final BuildException be) {
+                    final String message = "File " + file + " returned by "
+                            + "resolver failed to satisfy extension due to: " + be.getMessage();
+                    getProject().log(message, Project.MSG_WARN);
+                }
+            } catch (final BuildException be) {
+                final String message = "Failed to resolve extension to file " + "using resolver "
+                        + resolver + " due to: " + be;
+                getProject().log(message, Project.MSG_WARN);
+            }
+        }
+        missingExtension();
+    }
+
+    /**
+     * Utility method that will throw a {@link BuildException}
+     * if {@link #failOnError} is true else it just displays
+     * a warning.
+     */
+    private void missingExtension() {
+        final String message = "Unable to resolve extension to a file";
+        if (failOnError) {
+            throw new BuildException(message);
+        }
+        getProject().log(message, Project.MSG_ERR);
+    }
+
+    /**
+     * Check if specified file satisfies extension.
+     * If it does then set the relevent property
+     * else throw a BuildException.
+     *
+     * @param file the candidate library
+     * @throws BuildException if library does not satisfy extension
+     */
+    private void checkExtension(final File file) {
+        if (!file.exists()) {
+            throw new BuildException("File " + file + " does not exist");
+        }
+        if (!file.isFile()) {
+            throw new BuildException("File " + file + " is not a file");
+        }
+        if (!checkExtension) {
+            getProject().log("Setting property to " + file
+                    + " without verifying library satisfies extension", Project.MSG_VERBOSE);
+            setLibraryProperty(file);
+        } else {
+            getProject().log("Checking file " + file + " to see if it satisfies extension",
+                    Project.MSG_VERBOSE);
+            final Manifest manifest = ExtensionUtil.getManifest(file);
+            final Extension[] extensions = Extension.getAvailable(manifest);
+            for (int i = 0; i < extensions.length; i++) {
+                final Extension extension = extensions[ i ];
+                if (extension.isCompatibleWith(requiredExtension)) {
+                    setLibraryProperty(file);
+                    return;
+                }
+            }
+            final String message = "File " + file + " skipped as it "
+                + "does not satisfy extension";
+            getProject().log(message, Project.MSG_VERBOSE);
+            throw new BuildException(message);
+        }
+    }
+
+    /**
+     * Utility method to set the appropriate property
+     * to indicate that specified file satisfies library
+     * requirements.
+     *
+     * @param file the library
+     */
+    private void setLibraryProperty(final File file) {
+        getProject().setNewProperty(propertyName, file.getAbsolutePath());
+    }
+
+    /**
+     * Validate the tasks parameters.
+     *
+     * @throws BuildException if invalid parameters found
+     */
+    private void validate() throws BuildException {
+        if (null == propertyName) {
+            final String message = "Property attribute must be specified.";
+            throw new BuildException(message);
+        }
+
+        if (null == requiredExtension) {
+            final String message = "Extension element must be specified.";
+            throw new BuildException(message);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java
new file mode 100644
index 0000000..591fda7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibFileSet.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * LibFileSet represents a fileset containing libraries.
+ * Asociated with the libraries is data pertaining to
+ * how they are to be handled when building manifests.
+ *
+ */
+public class LibFileSet
+    extends FileSet {
+    /**
+     * Flag indicating whether should include the
+     * "Implementation-URL" attribute in manifest.
+     * Defaults to false.
+     */
+    private boolean includeURL;
+
+    /**
+     * Flag indicating whether should include the
+     * "Implementation-*" attributes in manifest.
+     * Defaults to false.
+     */
+    private boolean includeImpl;
+
+    /**
+     * String that is the base URL for the librarys
+     * when constructing the "Implementation-URL"
+     * attribute. For instance setting the base to
+     * "http://jakarta.apache.org/avalon/libs/" and then
+     * including the library "excalibur-cli-1.0.jar" in the
+     * fileset will result in the "Implementation-URL" attribute
+     * being set to "http://jakarta.apache.org/avalon/libs/excalibur-cli-1.0.jar"
+     *
+     * Note this is only used if the library does not define
+     * "Implementation-URL" itself.
+     *
+     * Note that this also implies includeURL=true
+     */
+    private String urlBase;
+
+    /**
+     * Flag indicating whether should include the
+     * "Implementation-URL" attribute in manifest.
+     * Defaults to false.
+     *
+     * @param includeURL the flag
+     */
+    public void setIncludeUrl(boolean includeURL) {
+        this.includeURL = includeURL;
+    }
+
+    /**
+     * Flag indicating whether should include the
+     * "Implementation-*" attributes in manifest.
+     * Defaults to false.
+     *
+     * @param includeImpl the flag
+     */
+    public void setIncludeImpl(boolean includeImpl) {
+        this.includeImpl = includeImpl;
+    }
+
+    /**
+     * Set the url base for fileset.
+     *
+     * @param urlBase the base url
+     */
+    public void setUrlBase(String urlBase) {
+        this.urlBase = urlBase;
+    }
+
+    /**
+     * Get the includeURL flag.
+     *
+     * @return the includeURL flag.
+     */
+    boolean isIncludeURL() {
+        return includeURL;
+    }
+
+    /**
+     * Get the includeImpl flag.
+     *
+     * @return the includeImpl flag.
+     */
+    boolean isIncludeImpl() {
+        return includeImpl;
+    }
+
+    /**
+     * Get the urlbase.
+     *
+     * @return the urlbase.
+     */
+    String getUrlBase() {
+        return urlBase;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java
new file mode 100644
index 0000000..c8f9e86
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/LibraryDisplayer.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.io.File;
+import java.text.ParseException;
+import java.util.jar.Manifest;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Utility class to output the information in a jar relating
+ * to "Optional Packages" (formely known as "Extensions")
+ * and Package Specifications.
+ *
+ */
+class LibraryDisplayer {
+    /**
+     * Display the extensions and specifications contained
+     * within specified file.
+     *
+     * @param file the file
+     * @throws BuildException if fail to read file
+     */
+    void displayLibrary(final File file)
+        throws BuildException {
+        final Manifest manifest = ExtensionUtil.getManifest(file);
+        displayLibrary(file, manifest);
+    }
+
+    /**
+     * Display the extensions and specifications contained
+     * within specified file.
+     *
+     * @param file the file to use while reporting
+     * @param manifest the manifest of file
+     * @throws BuildException if fail to read file
+     */
+    void displayLibrary(final File file,
+                         final Manifest manifest)
+        throws BuildException {
+        final Extension[] available = Extension.getAvailable(manifest);
+        final Extension[] required = Extension.getRequired(manifest);
+        final Extension[] options = Extension.getOptions(manifest);
+        final Specification[] specifications = getSpecifications(manifest);
+
+        if (0 == available.length && 0 == required.length && 0 == options.length
+            && 0 == specifications.length) {
+            return;
+        }
+
+        final String message = "File: " + file;
+        final int size = message.length();
+        printLine(size);
+        System.out.println(message);
+        printLine(size);
+        if (0 != available.length) {
+            System.out.println("Extensions Supported By Library:");
+            for (int i = 0; i < available.length; i++) {
+                final Extension extension = available[ i ];
+                System.out.println(extension.toString());
+            }
+        }
+
+        if (0 != required.length) {
+            System.out.println("Extensions Required By Library:");
+            for (int i = 0; i < required.length; i++) {
+                final Extension extension = required[ i ];
+                System.out.println(extension.toString());
+            }
+        }
+
+        if (0 != options.length) {
+            System.out.println("Extensions that will be used by Library if present:");
+            for (int i = 0; i < options.length; i++) {
+                final Extension extension = options[ i ];
+                System.out.println(extension.toString());
+            }
+        }
+
+        if (0 != specifications.length) {
+            System.out.println("Specifications Supported By Library:");
+            for (int i = 0; i < specifications.length; i++) {
+                final Specification specification = specifications[ i ];
+                displaySpecification(specification);
+            }
+        }
+    }
+
+    /**
+     * Print out a line of '-'s equal to specified size.
+     *
+     * @param size the number of dashes to printout
+     */
+    private void printLine(final int size) {
+        for (int i = 0; i < size; i++) {
+            System.out.print("-");
+        }
+        System.out.println();
+    }
+
+    /**
+     * Get specifications from manifest.
+     *
+     * @param manifest the manifest
+     * @return the specifications or null if none
+     * @throws BuildException if malformed specification sections
+     */
+    private Specification[] getSpecifications(final Manifest manifest)
+        throws BuildException {
+        try {
+            return Specification.getSpecifications(manifest);
+        } catch (final ParseException pe) {
+            throw new BuildException(pe.getMessage(), pe);
+        }
+    }
+
+    /**
+     * Print out specification details.
+     *
+     * @param specification the specification
+     */
+    private void displaySpecification(final Specification specification) {
+        final String[] sections = specification.getSections();
+        if (null != sections) {
+            final StringBuffer sb = new StringBuffer("Sections: ");
+            for (int i = 0; i < sections.length; i++) {
+                sb.append(" ");
+                sb.append(sections[ i ]);
+            }
+            System.out.println(sb);
+        }
+        System.out.println(specification.toString());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java
new file mode 100644
index 0000000..a4dac26
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/Specification.java
@@ -0,0 +1,604 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * <p>Utility class that represents either an available "Optional Package"
+ * (formerly known as "Standard Extension") as described in the manifest
+ * of a JAR file, or the requirement for such an optional package.</p>
+ *
+ * <p>For more information about optional packages, see the document
+ * <em>Optional Package Versioning</em> in the documentation bundle for your
+ * Java2 Standard Edition package, in file
+ * <code>guide/extensions/versioning.html</code>.</p>
+ *
+ */
+public final class Specification {
+
+    private static final String MISSING = "Missing ";
+
+    /**
+     * Manifest Attribute Name object for SPECIFICATION_TITLE.
+     */
+    public static final Attributes.Name SPECIFICATION_TITLE
+        = Attributes.Name.SPECIFICATION_TITLE;
+
+    /**
+     * Manifest Attribute Name object for SPECIFICATION_VERSION.
+     */
+    public static final Attributes.Name SPECIFICATION_VERSION
+        = Attributes.Name.SPECIFICATION_VERSION;
+
+    /**
+     * Manifest Attribute Name object for SPECIFICATION_VENDOR.
+     */
+    public static final Attributes.Name SPECIFICATION_VENDOR
+        = Attributes.Name.SPECIFICATION_VENDOR;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_TITLE.
+     */
+    public static final Attributes.Name IMPLEMENTATION_TITLE
+        = Attributes.Name.IMPLEMENTATION_TITLE;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
+     */
+    public static final Attributes.Name IMPLEMENTATION_VERSION
+        = Attributes.Name.IMPLEMENTATION_VERSION;
+
+    /**
+     * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
+     */
+    public static final Attributes.Name IMPLEMENTATION_VENDOR
+        = Attributes.Name.IMPLEMENTATION_VENDOR;
+
+    /**
+     * Enum indicating that extension is compatible with other Package
+     * Specification.
+     */
+    public static final Compatibility COMPATIBLE =
+        new Compatibility("COMPATIBLE");
+
+    /**
+     * Enum indicating that extension requires an upgrade
+     * of specification to be compatible with other Package Specification.
+     */
+    public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE =
+        new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
+
+    /**
+     * Enum indicating that extension requires a vendor
+     * switch to be compatible with other Package Specification.
+     */
+    public static final Compatibility REQUIRE_VENDOR_SWITCH =
+        new Compatibility("REQUIRE_VENDOR_SWITCH");
+
+    /**
+     * Enum indicating that extension requires an upgrade
+     * of implementation to be compatible with other Package Specification.
+     */
+    public static final Compatibility REQUIRE_IMPLEMENTATION_CHANGE =
+        new Compatibility("REQUIRE_IMPLEMENTATION_CHANGE");
+
+    /**
+     * This enum indicates that an extension is incompatible with
+     * other Package Specification in ways other than other enums
+     * indicate. For example, the other Package Specification
+     * may have a different ID.
+     */
+    public static final Compatibility INCOMPATIBLE =
+        new Compatibility("INCOMPATIBLE");
+
+    /**
+     * The name of the Package Specification.
+     */
+    private String specificationTitle;
+
+    /**
+     * The version number (dotted decimal notation) of the specification
+     * to which this optional package conforms.
+     */
+    private DeweyDecimal specificationVersion;
+
+    /**
+     * The name of the company or organization that originated the
+     * specification to which this specification conforms.
+     */
+    private String specificationVendor;
+
+    /**
+     * The title of implementation.
+     */
+    private String implementationTitle;
+
+    /**
+     * The name of the company or organization that produced this
+     * implementation of this specification.
+     */
+    private String implementationVendor;
+
+    /**
+     * The version string for implementation. The version string is
+     * opaque.
+     */
+    private String implementationVersion;
+
+    /**
+     * The sections of jar that the specification applies to.
+     */
+    private String[] sections;
+
+    /**
+     * Return an array of <code>Package Specification</code> objects.
+     * If there are no such optional packages, a zero-length array is returned.
+     *
+     * @param manifest Manifest to be parsed
+     * @return the Package Specifications extensions in specified manifest
+     * @throws ParseException if the attributes of the specifications cannot
+     * be parsed according to their expected formats.
+     */
+    public static Specification[] getSpecifications(final Manifest manifest)
+        throws ParseException {
+        if (null == manifest) {
+            return new Specification[ 0 ];
+        }
+
+        final ArrayList results = new ArrayList();
+
+        final Map entries = manifest.getEntries();
+        final Iterator keys = entries.keySet().iterator();
+        while (keys.hasNext()) {
+            final String key = (String) keys.next();
+            final Attributes attributes = (Attributes) entries.get(key);
+            final Specification specification
+                = getSpecification(key, attributes);
+            if (null != specification) {
+                results.add(specification);
+            }
+        }
+
+        final ArrayList trimmedResults = removeDuplicates(results);
+        return (Specification[]) trimmedResults.toArray(new Specification[trimmedResults.size()]);
+    }
+
+    /**
+     * The constructor to create Package Specification object.
+     * Note that every component is allowed to be specified
+     * but only the specificationTitle is mandatory.
+     *
+     * @param specificationTitle the name of specification.
+     * @param specificationVersion the specification Version.
+     * @param specificationVendor the specification Vendor.
+     * @param implementationTitle the title of implementation.
+     * @param implementationVersion the implementation Version.
+     * @param implementationVendor the implementation Vendor.
+     */
+    public Specification(final String specificationTitle,
+                          final String specificationVersion,
+                          final String specificationVendor,
+                          final String implementationTitle,
+                          final String implementationVersion,
+                          final String implementationVendor) {
+        this(specificationTitle, specificationVersion, specificationVendor,
+              implementationTitle, implementationVersion, implementationVendor,
+              null);
+    }
+
+    /**
+     * The constructor to create Package Specification object.
+     * Note that every component is allowed to be specified
+     * but only the specificationTitle is mandatory.
+     *
+     * @param specificationTitle the name of specification.
+     * @param specificationVersion the specification Version.
+     * @param specificationVendor the specification Vendor.
+     * @param implementationTitle the title of implementation.
+     * @param implementationVersion the implementation Version.
+     * @param implementationVendor the implementation Vendor.
+     * @param sections the sections/packages that Specification applies to.
+     */
+    public Specification(final String specificationTitle,
+                          final String specificationVersion,
+                          final String specificationVendor,
+                          final String implementationTitle,
+                          final String implementationVersion,
+                          final String implementationVendor,
+                          final String[] sections) {
+        this.specificationTitle = specificationTitle;
+        this.specificationVendor = specificationVendor;
+
+        if (null != specificationVersion) {
+            try {
+                this.specificationVersion
+                    = new DeweyDecimal(specificationVersion);
+            } catch (final NumberFormatException nfe) {
+                final String error = "Bad specification version format '"
+                    + specificationVersion + "' in '" + specificationTitle
+                    + "'. (Reason: " + nfe + ")";
+                throw new IllegalArgumentException(error);
+            }
+        }
+
+        this.implementationTitle = implementationTitle;
+        this.implementationVendor = implementationVendor;
+        this.implementationVersion = implementationVersion;
+
+        if (null == this.specificationTitle) {
+            throw new NullPointerException("specificationTitle");
+        }
+
+        String[] copy = null;
+        if (null != sections) {
+            copy = new String[ sections.length ];
+            System.arraycopy(sections, 0, copy, 0, sections.length);
+        }
+        this.sections = copy;
+    }
+
+    /**
+     * Get the title of the specification.
+     *
+     * @return the title of speciication
+     */
+    public String getSpecificationTitle() {
+        return specificationTitle;
+    }
+
+    /**
+     * Get the vendor of the specification.
+     *
+     * @return the vendor of the specification.
+     */
+    public String getSpecificationVendor() {
+        return specificationVendor;
+    }
+
+    /**
+     * Get the title of the specification.
+     *
+     * @return the title of the specification.
+     */
+    public String getImplementationTitle() {
+        return implementationTitle;
+    }
+
+    /**
+     * Get the version of the specification.
+     *
+     * @return the version of the specification.
+     */
+    public DeweyDecimal getSpecificationVersion() {
+        return specificationVersion;
+    }
+
+    /**
+     * Get the vendor of the extensions implementation.
+     *
+     * @return the vendor of the extensions implementation.
+     */
+    public String getImplementationVendor() {
+        return implementationVendor;
+    }
+
+    /**
+     * Get the version of the implementation.
+     *
+     * @return the version of the implementation.
+     */
+    public String getImplementationVersion() {
+        return implementationVersion;
+    }
+
+    /**
+     * Return an array containing sections to which specification applies
+     * or null if relevent to no sections.
+     *
+     * @return an array containing sections to which specification applies
+     *         or null if relevent to no sections.
+     */
+    public String[] getSections() {
+        if (null == sections) {
+            return null;
+        }
+        final String[] newSections = new String[ sections.length ];
+        System.arraycopy(sections, 0, newSections, 0, sections.length);
+        return newSections;
+    }
+
+    /**
+     * Return a Compatibility enum indicating the relationship of this
+     * <code>Package Specification</code> with the specified
+     * <code>Extension</code>.
+     *
+     * @param other the other specification
+     * @return the enum indicating the compatibility (or lack thereof)
+     *         of specifed Package Specification
+     */
+    public Compatibility getCompatibilityWith(final Specification other) {
+        // Specification Name must match
+        if (!specificationTitle.equals(other.getSpecificationTitle())) {
+            return INCOMPATIBLE;
+        }
+
+        // Available specification version must be >= required
+        final DeweyDecimal otherSpecificationVersion
+            = other.getSpecificationVersion();
+        if (null != specificationVersion) {
+            if (null == otherSpecificationVersion
+                || !isCompatible(specificationVersion, otherSpecificationVersion)) {
+                return REQUIRE_SPECIFICATION_UPGRADE;
+            }
+        }
+
+        // Implementation Vendor ID must match
+        final String otherImplementationVendor
+            = other.getImplementationVendor();
+        if (null != implementationVendor) {
+            if (null == otherImplementationVendor
+                || !implementationVendor.equals(otherImplementationVendor)) {
+                return REQUIRE_VENDOR_SWITCH;
+            }
+        }
+
+        // Implementation version must be >= required
+        final String otherImplementationVersion
+            = other.getImplementationVersion();
+        if (null != implementationVersion) {
+            if (null == otherImplementationVersion
+                || !implementationVersion.equals(otherImplementationVersion)) {
+                return REQUIRE_IMPLEMENTATION_CHANGE;
+            }
+        }
+
+        // This available optional package satisfies the requirements
+        return COMPATIBLE;
+    }
+
+    /**
+     * Return <code>true</code> if the specified <code>package</code>
+     * is satisfied by this <code>Specification</code>. Otherwise, return
+     * <code>false</code>.
+     *
+     * @param other the specification
+     * @return true if the specification is compatible with this specification
+     */
+    public boolean isCompatibleWith(final Specification other) {
+        return (COMPATIBLE == getCompatibilityWith(other));
+    }
+
+    /**
+     * Return a String representation of this object.
+     *
+     * @return string representation of object.
+     */
+    public String toString() {
+        final String brace = ": ";
+
+        final StringBuffer sb
+            = new StringBuffer(SPECIFICATION_TITLE.toString());
+        sb.append(brace);
+        sb.append(specificationTitle);
+        sb.append(StringUtils.LINE_SEP);
+
+        if (null != specificationVersion) {
+            sb.append(SPECIFICATION_VERSION);
+            sb.append(brace);
+            sb.append(specificationVersion);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != specificationVendor) {
+            sb.append(SPECIFICATION_VENDOR);
+            sb.append(brace);
+            sb.append(specificationVendor);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationTitle) {
+            sb.append(IMPLEMENTATION_TITLE);
+            sb.append(brace);
+            sb.append(implementationTitle);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationVersion) {
+            sb.append(IMPLEMENTATION_VERSION);
+            sb.append(brace);
+            sb.append(implementationVersion);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        if (null != implementationVendor) {
+            sb.append(IMPLEMENTATION_VENDOR);
+            sb.append(brace);
+            sb.append(implementationVendor);
+            sb.append(StringUtils.LINE_SEP);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Return <code>true</code> if the first version number is greater than
+     * or equal to the second; otherwise return <code>false</code>.
+     *
+     * @param first First version number (dotted decimal)
+     * @param second Second version number (dotted decimal)
+     */
+    private boolean isCompatible(final DeweyDecimal first,
+                                 final DeweyDecimal second) {
+        return first.isGreaterThanOrEqual(second);
+    }
+
+    /**
+     * Combine all specifications objects that are identical except
+     * for the sections.
+     *
+     * <p>Note this is very inefficent and should probably be fixed
+     * in the future.</p>
+     *
+     * @param list the array of results to trim
+     * @return an array list with all duplicates removed
+     */
+    private static ArrayList removeDuplicates(final ArrayList list) {
+        final ArrayList results = new ArrayList();
+        final ArrayList sections = new ArrayList();
+        while (list.size() > 0) {
+            final Specification specification = (Specification) list.remove(0);
+            final Iterator iterator = list.iterator();
+            while (iterator.hasNext()) {
+                final Specification other = (Specification) iterator.next();
+                if (isEqual(specification, other)) {
+                    final String[] otherSections = other.getSections();
+                    if (null != otherSections) {
+                        sections.addAll(Arrays.asList(otherSections));
+                    }
+                    iterator.remove();
+                }
+            }
+
+            final Specification merged =
+                mergeInSections(specification, sections);
+            results.add(merged);
+            //Reset list of sections
+            sections.clear();
+        }
+
+        return results;
+    }
+
+    /**
+     * Test if two specifications are equal except for their sections.
+     *
+     * @param specification one specificaiton
+     * @param other the ohter specification
+     * @return true if two specifications are equal except for their
+     *         sections, else false
+     */
+    private static boolean isEqual(final Specification specification,
+                                    final Specification other) {
+        return
+            specification.getSpecificationTitle().equals(other.getSpecificationTitle())
+            && specification.getSpecificationVersion().isEqual(other.getSpecificationVersion())
+            && specification.getSpecificationVendor().equals(other.getSpecificationVendor())
+            && specification.getImplementationTitle().equals(other.getImplementationTitle())
+            && specification.getImplementationVersion().equals(other.getImplementationVersion())
+            && specification.getImplementationVendor().equals(other.getImplementationVendor());
+    }
+
+    /**
+     * Merge the specified sections into specified section and return result.
+     * If no sections to be added then just return original specification.
+     *
+     * @param specification the specification
+     * @param sectionsToAdd the list of sections to merge
+     * @return the merged specification
+     */
+    private static Specification mergeInSections(final Specification specification,
+                                              final ArrayList sectionsToAdd) {
+        if (0 == sectionsToAdd.size()) {
+            return specification;
+        }
+        sectionsToAdd.addAll(Arrays.asList(specification.getSections()));
+
+        final String[] sections =
+            (String[]) sectionsToAdd.toArray(new String[sectionsToAdd.size()]);
+
+        return new Specification(specification.getSpecificationTitle(),
+                specification.getSpecificationVersion().toString(),
+                specification.getSpecificationVendor(),
+                specification.getImplementationTitle(),
+                specification.getImplementationVersion(),
+                specification.getImplementationVendor(),
+                sections);
+    }
+
+    /**
+     * Trim the supplied string if the string is non-null
+     *
+     * @param value the string to trim or null
+     * @return the trimmed string or null
+     */
+    private static String getTrimmedString(final String value) {
+        return value == null ? null : value.trim();
+    }
+
+    /**
+     * Extract an Package Specification from Attributes.
+     *
+     * @param attributes Attributes to searched
+     * @return the new Specification object, or null
+     */
+    private static Specification getSpecification(final String section,
+                                                   final Attributes attributes)
+        throws ParseException {
+        //WARNING: We trim the values of all the attributes because
+        //Some extension declarations are badly defined (ie have spaces
+        //after version or vendor)
+        final String name
+            = getTrimmedString(attributes.getValue(SPECIFICATION_TITLE));
+        if (null == name) {
+            return null;
+        }
+
+        final String specVendor
+            = getTrimmedString(attributes.getValue(SPECIFICATION_VENDOR));
+        if (null == specVendor) {
+            throw new ParseException(MISSING + SPECIFICATION_VENDOR, 0);
+        }
+
+        final String specVersion
+            = getTrimmedString(attributes.getValue(SPECIFICATION_VERSION));
+        if (null == specVersion) {
+            throw new ParseException(MISSING + SPECIFICATION_VERSION, 0);
+        }
+
+        final String impTitle
+            = getTrimmedString(attributes.getValue(IMPLEMENTATION_TITLE));
+        if (null == impTitle) {
+            throw new ParseException(MISSING + IMPLEMENTATION_TITLE, 0);
+        }
+
+        final String impVersion
+            = getTrimmedString(attributes.getValue(IMPLEMENTATION_VERSION));
+        if (null == impVersion) {
+            throw new ParseException(MISSING + IMPLEMENTATION_VERSION, 0);
+        }
+
+        final String impVendor
+            = getTrimmedString(attributes.getValue(IMPLEMENTATION_VENDOR));
+        if (null == impVendor) {
+            throw new ParseException(MISSING + IMPLEMENTATION_VENDOR, 0);
+        }
+
+        return new Specification(name, specVersion, specVendor,
+                                  impTitle, impVersion, impVendor,
+                                  new String[]{section});
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java
new file mode 100644
index 0000000..e3c9070
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/AntResolver.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Ant;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class AntResolver implements ExtensionResolver {
+    private File antfile;
+    private File destfile;
+    private String target;
+
+    /**
+     * Sets the ant file
+     * @param antfile the ant file to set
+     */
+    public void setAntfile(final File antfile) {
+        this.antfile = antfile;
+    }
+
+    /**
+     * Sets the destination file
+     * @param destfile the destination file
+     */
+    public void setDestfile(final File destfile) {
+        this.destfile = destfile;
+    }
+
+    /**
+     * Sets the target
+     * @param target the target
+     */
+    public void setTarget(final String target) {
+        this.target = target;
+    }
+
+    /**
+     * Returns the resolved file
+     * @param extension the extension
+     * @param project the project
+     * @return the file resolved
+     * @throws BuildException if the file cannot be resolved
+     */
+    public File resolve(final Extension extension,
+                         final Project project) throws BuildException {
+        validate();
+
+        final Ant ant = new Ant();
+        ant.setProject(project);
+        ant.setInheritAll(false);
+        ant.setAntfile(antfile.getName());
+
+        try {
+            final File dir =
+                antfile.getParentFile().getCanonicalFile();
+            ant.setDir(dir);
+        } catch (final IOException ioe) {
+            throw new BuildException(ioe.getMessage(), ioe);
+        }
+
+        if (null != target) {
+            ant.setTarget(target);
+        }
+
+        ant.execute();
+
+        return destfile;
+    }
+
+    /*
+     * Validates URL
+     */
+    private void validate() {
+        if (null == antfile) {
+            final String message = "Must specify Buildfile";
+            throw new BuildException(message);
+        }
+
+        if (null == destfile) {
+            final String message = "Must specify destination file";
+            throw new BuildException(message);
+        }
+    }
+
+    /**
+     * Returns a string representation
+     * @return the string representation
+     */
+    public String toString() {
+        return "Ant[" + antfile + "==>" + destfile + "]";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java
new file mode 100644
index 0000000..ee6974b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/LocationResolver.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class LocationResolver implements ExtensionResolver {
+    private String location;
+
+    /**
+     * Sets the location for this resolver
+     * @param location the location
+     */
+    public void setLocation(final String location) {
+        this.location = location;
+    }
+
+    /**
+     * Returns the resolved file
+     * @param extension the extension
+     * @param project the project
+     * @return the file resolved
+     * @throws BuildException if no location is set
+     */
+    public File resolve(final Extension extension,
+                        final Project project) throws BuildException {
+        if (null == location) {
+            final String message = "No location specified for resolver";
+            throw new BuildException(message);
+        }
+
+        return project.resolveFile(location);
+    }
+    /**
+     * Returns a string representation of the Location
+     * @return the string representation
+     */
+    public String toString() {
+        return "Location[" + location + "]";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java
new file mode 100644
index 0000000..714f692
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/extension/resolvers/URLResolver.java
@@ -0,0 +1,132 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.extension.resolvers;
+
+import java.io.File;
+import java.net.URL;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Get;
+import org.apache.tools.ant.taskdefs.optional.extension.Extension;
+import org.apache.tools.ant.taskdefs.optional.extension.ExtensionResolver;
+
+/**
+ * Resolver that just returns s specified location.
+ *
+ */
+public class URLResolver implements ExtensionResolver {
+    private File destfile;
+    private File destdir;
+    private URL url;
+
+    /**
+     * Sets the URL
+     * @param url the url
+     */
+    public void setUrl(final URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Sets the destination file
+     * @param destfile the destination file
+     */
+    public void setDestfile(final File destfile) {
+        this.destfile = destfile;
+    }
+
+    /**
+     * Sets the destination directory
+     * @param destdir the destination directory
+     */
+    public void setDestdir(final File destdir) {
+        this.destdir = destdir;
+    }
+
+    /**
+     * Returns the file resolved from URL and directory
+     * @param extension the extention
+     * @param project the project
+     * @return file the file resolved
+     * @throws BuildException if the URL is invalid
+     */
+    public File resolve(final Extension extension,
+                         final Project project) throws BuildException {
+        validate();
+
+        final File file = getDest();
+
+        final Get get = new Get();
+        get.setProject(project);
+        get.setDest(file);
+        get.setSrc(url);
+        get.execute();
+
+        return file;
+    }
+
+    /*
+     * Gets the destination file
+     */
+    private File getDest() {
+        File result;
+        if (null != destfile) {
+            result = destfile;
+        } else {
+            final String file = url.getFile();
+            String filename;
+            if (null == file || file.length() <= 1) {
+                filename = "default.file";
+            } else {
+                int index = file.lastIndexOf('/');
+                if (-1 == index) {
+                    index = 0;
+                }
+                filename = file.substring(index);
+            }
+            result = new File(destdir, filename);
+        }
+        return result;
+    }
+
+    /*
+     * Validates URL
+     */
+    private void validate() {
+        if (null == url) {
+            final String message = "Must specify URL";
+            throw new BuildException(message);
+        }
+
+        if (null == destdir && null == destfile) {
+            final String message = "Must specify destination file or directory";
+            throw new BuildException(message);
+        } else if (null != destdir && null != destfile) {
+            final String message = "Must not specify both destination file or directory";
+            throw new BuildException(message);
+        }
+    }
+
+    /**
+     * Returns a string representation of the URL
+     * @return the string representation
+     */
+    public String toString() {
+        return "URL[" + url + "]";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java
new file mode 100644
index 0000000..3ca2266
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/i18n/Translate.java
@@ -0,0 +1,627 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.i18n;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LineTokenizer;
+
+/**
+ * Translates text embedded in files using Resource Bundle files.
+ * Since ant 1.6 preserves line endings
+ *
+ */
+public class Translate extends MatchingTask {
+    /**
+     * search a bundle matching the specified language, the country and the variant
+     */
+    private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT = 0;
+    /**
+     * search a bundle matching the specified language, and the country
+     */
+    private static final int BUNDLE_SPECIFIED_LANGUAGE_COUNTRY = 1;
+    /**
+     * search a bundle matching the specified language only
+     */
+    private static final int BUNDLE_SPECIFIED_LANGUAGE = 2;
+    /**
+     * search a bundle matching nothing special
+     */
+    private static final int BUNDLE_NOMATCH = 3;
+    /**
+     * search a bundle matching the language, the country and the variant
+     * of the current locale of the computer
+     */
+    private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT = 4;
+    /**
+     * search a bundle matching the language, and the country
+     * of the current locale of the computer
+     */
+    private static final int BUNDLE_DEFAULT_LANGUAGE_COUNTRY = 5;
+    /**
+     * search a bundle matching the language only
+     * of the current locale of the computer
+     */
+    private static final int BUNDLE_DEFAULT_LANGUAGE = 6;
+    /**
+     * number of possibilities for the search
+     */
+     private static final int BUNDLE_MAX_ALTERNATIVES = BUNDLE_DEFAULT_LANGUAGE + 1;
+    /**
+     * Family name of resource bundle
+     */
+    private String bundle;
+
+    /**
+     * Locale specific language of the resource bundle
+     */
+    private String bundleLanguage;
+
+    /**
+     * Locale specific country of the resource bundle
+     */
+    private String bundleCountry;
+
+    /**
+     * Locale specific variant of the resource bundle
+     */
+    private String bundleVariant;
+
+    /**
+     * Destination directory
+     */
+    private File toDir;
+
+    /**
+     * Source file encoding scheme
+     */
+    private String srcEncoding;
+
+    /**
+     * Destination file encoding scheme
+     */
+    private String destEncoding;
+
+    /**
+     * Resource Bundle file encoding scheme, defaults to srcEncoding
+     */
+    private String bundleEncoding;
+
+    /**
+     * Starting token to identify keys
+     */
+    private String startToken;
+
+    /**
+     * Ending token to identify keys
+     */
+    private String endToken;
+
+    /**
+     * Whether or not to create a new destination file.
+     * Defaults to <code>false</code>.
+     */
+    private boolean forceOverwrite;
+
+    /**
+     * Vector to hold source file sets.
+     */
+    private Vector filesets = new Vector();
+
+    /**
+     * Holds key value pairs loaded from resource bundle file
+     */
+    private Hashtable resourceMap = new Hashtable();
+    /**
+
+     * Used to resolve file names.
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Last Modified Timestamp of resource bundle file being used.
+     */
+    private long[] bundleLastModified = new long[BUNDLE_MAX_ALTERNATIVES];
+
+    /**
+     * Last Modified Timestamp of source file being used.
+     */
+    private long srcLastModified;
+
+    /**
+     * Last Modified Timestamp of destination file being used.
+     */
+    private long destLastModified;
+
+    /**
+     * Has at least one file from the bundle been loaded?
+     */
+    private boolean loaded = false;
+
+    /**
+     * Sets Family name of resource bundle; required.
+     * @param bundle family name of resource bundle
+     */
+    public void setBundle(String bundle) {
+        this.bundle = bundle;
+    }
+
+    /**
+     * Sets locale specific language of resource bundle; optional.
+     * @param bundleLanguage langage of the bundle
+     */
+    public void setBundleLanguage(String bundleLanguage) {
+        this.bundleLanguage = bundleLanguage;
+    }
+
+    /**
+     * Sets locale specific country of resource bundle; optional.
+     * @param bundleCountry country of the bundle
+     */
+    public void setBundleCountry(String bundleCountry) {
+        this.bundleCountry = bundleCountry;
+    }
+
+    /**
+     * Sets locale specific variant of resource bundle; optional.
+     * @param bundleVariant locale variant of resource bundle
+     */
+    public void setBundleVariant(String bundleVariant) {
+        this.bundleVariant = bundleVariant;
+    }
+
+    /**
+     * Sets Destination directory; required.
+     * @param toDir destination directory
+     */
+    public void setToDir(File toDir) {
+        this.toDir = toDir;
+    }
+
+    /**
+     * Sets starting token to identify keys; required.
+     * @param startToken starting token to identify keys
+     */
+    public void setStartToken(String startToken) {
+        this.startToken = startToken;
+    }
+
+    /**
+     * Sets ending token to identify keys; required.
+     * @param endToken ending token to identify keys
+     */
+    public void setEndToken(String endToken) {
+        this.endToken = endToken;
+    }
+
+    /**
+     * Sets source file encoding scheme; optional,
+     * defaults to encoding of local system.
+     * @param srcEncoding source file encoding
+     */
+    public void setSrcEncoding(String srcEncoding) {
+        this.srcEncoding = srcEncoding;
+    }
+
+    /**
+     * Sets destination file encoding scheme; optional.  Defaults to source file
+     * encoding
+     * @param destEncoding destination file encoding scheme
+     */
+    public void setDestEncoding(String destEncoding) {
+        this.destEncoding = destEncoding;
+    }
+
+    /**
+     * Sets Resource Bundle file encoding scheme; optional.  Defaults to source file
+     * encoding
+     * @param bundleEncoding bundle file encoding scheme
+     */
+    public void setBundleEncoding(String bundleEncoding) {
+        this.bundleEncoding = bundleEncoding;
+    }
+
+    /**
+     * Whether or not to overwrite existing file irrespective of
+     * whether it is newer than the source file as well as the
+     * resource bundle file.
+     * Defaults to false.
+     * @param forceOverwrite whether or not to overwrite existing files
+     */
+    public void setForceOverwrite(boolean forceOverwrite) {
+        this.forceOverwrite = forceOverwrite;
+    }
+
+    /**
+     * Adds a set of files to translate as a nested fileset element.
+     * @param set the fileset to be added
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Check attributes values, load resource map and translate
+     * @throws BuildException if the required attributes are not set
+     * Required : <ul>
+     *       <li>bundle</li>
+     *       <li>starttoken</li>
+     *       <li>endtoken</li>
+     *            </ul>
+     */
+    public void execute() throws BuildException {
+        if (bundle == null) {
+            throw new BuildException("The bundle attribute must be set.",
+                                     getLocation());
+        }
+
+        if (startToken == null) {
+            throw new BuildException("The starttoken attribute must be set.",
+                                     getLocation());
+        }
+
+        if (endToken == null) {
+            throw new BuildException("The endtoken attribute must be set.",
+                                     getLocation());
+        }
+
+        if (bundleLanguage == null) {
+            Locale l = Locale.getDefault();
+            bundleLanguage  = l.getLanguage();
+        }
+
+        if (bundleCountry == null) {
+            bundleCountry = Locale.getDefault().getCountry();
+        }
+
+        if (bundleVariant == null) {
+            Locale l = new Locale(bundleLanguage, bundleCountry);
+            bundleVariant = l.getVariant();
+        }
+
+        if (toDir == null) {
+            throw new BuildException("The todir attribute must be set.",
+                                     getLocation());
+        }
+
+        if (!toDir.exists()) {
+            toDir.mkdirs();
+        } else if (toDir.isFile()) {
+            throw new BuildException(toDir + " is not a directory");
+        }
+
+        if (srcEncoding == null) {
+            srcEncoding = System.getProperty("file.encoding");
+        }
+
+        if (destEncoding == null) {
+            destEncoding = srcEncoding;
+        }
+
+        if (bundleEncoding == null) {
+            bundleEncoding = srcEncoding;
+        }
+
+        loadResourceMaps();
+
+        translate();
+    }
+
+    /**
+     * Load resource maps based on resource bundle encoding scheme.
+     * The resource bundle lookup searches for resource files with various
+     * suffixes on the basis of (1) the desired locale and (2) the default
+     * locale (basebundlename), in the following order from lower-level
+     * (more specific) to parent-level (less specific):
+     *
+     * basebundlename + "_" + language1 + "_" + country1 + "_" + variant1
+     * basebundlename + "_" + language1 + "_" + country1
+     * basebundlename + "_" + language1
+     * basebundlename
+     * basebundlename + "_" + language2 + "_" + country2 + "_" + variant2
+     * basebundlename + "_" + language2 + "_" + country2
+     * basebundlename + "_" + language2
+     *
+     * To the generated name, a ".properties" string is appeneded and
+     * once this file is located, it is treated just like a properties file
+     * but with bundle encoding also considered while loading.
+     */
+    private void loadResourceMaps() throws BuildException {
+        Locale locale = new Locale(bundleLanguage,
+                                   bundleCountry,
+                                   bundleVariant);
+        String language = locale.getLanguage().length() > 0
+            ? "_" + locale.getLanguage() : "";
+        String country = locale.getCountry().length() > 0
+            ? "_" + locale.getCountry() : "";
+        String variant = locale.getVariant().length() > 0
+            ? "_" + locale.getVariant() : "";
+        String bundleFile = bundle + language + country + variant;
+        processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY_VARIANT, false);
+
+        bundleFile = bundle + language + country;
+        processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE_COUNTRY, false);
+
+        bundleFile = bundle + language;
+        processBundle(bundleFile, BUNDLE_SPECIFIED_LANGUAGE, false);
+
+        bundleFile = bundle;
+        processBundle(bundleFile, BUNDLE_NOMATCH, false);
+
+        //Load default locale bundle files
+        //using default file encoding scheme.
+        locale = Locale.getDefault();
+
+        language = locale.getLanguage().length() > 0
+            ? "_" + locale.getLanguage() : "";
+        country = locale.getCountry().length() > 0
+            ? "_" + locale.getCountry() : "";
+        variant = locale.getVariant().length() > 0
+            ? "_" + locale.getVariant() : "";
+        bundleEncoding = System.getProperty("file.encoding");
+
+        bundleFile = bundle + language + country + variant;
+        processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY_VARIANT, false);
+
+        bundleFile = bundle + language + country;
+        processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE_COUNTRY, false);
+
+        bundleFile = bundle + language;
+        processBundle(bundleFile, BUNDLE_DEFAULT_LANGUAGE, true);
+    }
+
+    /**
+     * Process each file that makes up this bundle.
+     */
+    private void processBundle(final String bundleFile, final int i,
+                               final boolean checkLoaded) throws BuildException {
+        final File propsFile = getProject().resolveFile(bundleFile + ".properties");
+        FileInputStream ins = null;
+        try {
+            ins = new FileInputStream(propsFile);
+            loaded = true;
+            bundleLastModified[i] = propsFile.lastModified();
+            log("Using " + propsFile, Project.MSG_DEBUG);
+            loadResourceMap(ins);
+        } catch (IOException ioe) {
+            log(propsFile + " not found.", Project.MSG_DEBUG);
+            //if all resource files associated with this bundle
+            //have been scanned for and still not able to
+            //find a single resrouce file, throw exception
+            if (!loaded && checkLoaded) {
+                throw new BuildException(ioe.getMessage(), getLocation());
+            }
+        }
+    }
+
+    /**
+     * Load resourceMap with key value pairs.  Values of existing keys
+     * are not overwritten.  Bundle's encoding scheme is used.
+     */
+    private void loadResourceMap(FileInputStream ins) throws BuildException {
+        try {
+            BufferedReader in = null;
+            InputStreamReader isr = new InputStreamReader(ins, bundleEncoding);
+            in = new BufferedReader(isr);
+            String line = null;
+            while ((line = in.readLine()) != null) {
+                //So long as the line isn't empty and isn't a comment...
+                if (line.trim().length() > 1 && '#' != line.charAt(0) && '!' != line.charAt(0)) {
+                    //Legal Key-Value separators are :, = and white space.
+                    int sepIndex = line.indexOf('=');
+                    if (-1 == sepIndex) {
+                        sepIndex = line.indexOf(':');
+                    }
+                    if (-1 == sepIndex) {
+                        for (int k = 0; k < line.length(); k++) {
+                            if (Character.isSpaceChar(line.charAt(k))) {
+                                sepIndex = k;
+                                break;
+                            }
+                        }
+                    }
+                    //Only if we do have a key is there going to be a value
+                    if (-1 != sepIndex) {
+                        String key = line.substring(0, sepIndex).trim();
+                        String value = line.substring(sepIndex + 1).trim();
+                        //Handle line continuations, if any
+                        while (value.endsWith("\\")) {
+                            value = value.substring(0, value.length() - 1);
+                            line = in.readLine();
+                            if (line != null) {
+                                value = value + line.trim();
+                            } else {
+                                break;
+                            }
+                        }
+                        if (key.length() > 0) {
+                            //Has key already been loaded into resourceMap?
+                            if (resourceMap.get(key) == null) {
+                                resourceMap.put(key, value);
+                            }
+                        }
+                    }
+                }
+            }
+            if (in != null) {
+                in.close();
+            }
+        } catch (IOException ioe) {
+            throw new BuildException(ioe.getMessage(), getLocation());
+        }
+    }
+
+    /**
+     * Reads source file line by line using the source encoding and
+     * searches for keys that are sandwiched between the startToken
+     * and endToken.  The values for these keys are looked up from
+     * the hashtable and substituted.  If the hashtable doesn't
+     * contain the key, they key itself is used as the value.
+     * Detination files and directories are created as needed.
+     * The destination file is overwritten only if
+     * the forceoverwritten attribute is set to true if
+     * the source file or any associated bundle resource file is
+     * newer than the destination file.
+     */
+    private void translate() throws BuildException {
+        int filesProcessed = 0;
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            String[] srcFiles = ds.getIncludedFiles();
+            for (int j = 0; j < srcFiles.length; j++) {
+                try {
+                    File dest = FILE_UTILS.resolveFile(toDir, srcFiles[j]);
+                    //Make sure parent dirs exist, else, create them.
+                    try {
+                        File destDir = new File(dest.getParent());
+                        if (!destDir.exists()) {
+                            destDir.mkdirs();
+                        }
+                    } catch (Exception e) {
+                        log("Exception occurred while trying to check/create "
+                            + " parent directory.  " + e.getMessage(),
+                            Project.MSG_DEBUG);
+                    }
+                    destLastModified = dest.lastModified();
+                    File src = FILE_UTILS.resolveFile(ds.getBasedir(), srcFiles[j]);
+                    srcLastModified = src.lastModified();
+                    //Check to see if dest file has to be recreated
+                    boolean needsWork = forceOverwrite
+                        || destLastModified < srcLastModified;
+                    if (!needsWork) {
+                        for (int icounter = 0; icounter < BUNDLE_MAX_ALTERNATIVES; icounter++) {
+                            needsWork = (destLastModified < bundleLastModified[icounter]);
+                            if (needsWork) {
+                                break;
+                            }
+                        }
+                    }
+                    if (needsWork) {
+                        log("Processing " + srcFiles[j],
+                            Project.MSG_DEBUG);
+                        FileOutputStream fos = new FileOutputStream(dest);
+                        BufferedWriter out
+                            = new BufferedWriter(new OutputStreamWriter(fos, destEncoding));
+                        FileInputStream fis = new FileInputStream(src);
+                        BufferedReader in
+                            = new BufferedReader(new InputStreamReader(fis, srcEncoding));
+                        String line;
+                        LineTokenizer lineTokenizer = new LineTokenizer();
+                        lineTokenizer.setIncludeDelims(true);
+                        line = lineTokenizer.getToken(in);
+                        while ((line) != null) {
+                            // 2003-02-21 new replace algorithm by tbee (tbee@tbee.org)
+                            // because it wasn't able to replace something like "@aaa;@bbb;"
+
+                            // is there a startToken
+                            // and there is still stuff following the startToken
+                            int startIndex = line.indexOf(startToken);
+                            while (startIndex >= 0
+                                && (startIndex + startToken.length()) <= line.length()) {
+                                // the new value, this needs to be here
+                                // because it is required to calculate the next position to
+                                // search from at the end of the loop
+                                String replace = null;
+
+                                // we found a starttoken, is there an endtoken following?
+                                // start at token+tokenlength because start and end
+                                // token may be indentical
+                                int endIndex = line.indexOf(
+                                    endToken, startIndex + startToken.length());
+                                if (endIndex < 0) {
+                                    startIndex += 1;
+                                } else {
+                                    // grab the token
+                                    String token = line.substring(
+                                        startIndex + startToken.length(), endIndex);
+
+                                    // If there is a white space or = or :, then
+                                    // it isn't to be treated as a valid key.
+                                    boolean validToken = true;
+                                    for (int k = 0; k < token.length() && validToken; k++) {
+                                        char c = token.charAt(k);
+                                        if (c == ':' || c == '='
+                                            || Character.isSpaceChar(c)) {
+                                            validToken = false;
+                                        }
+                                    }
+                                    if (!validToken) {
+                                        startIndex += 1;
+                                    } else {
+                                        // find the replace string
+                                        if (resourceMap.containsKey(token)) {
+                                            replace = (String) resourceMap.get(token);
+                                        } else {
+                                            log("Replacement string missing for: "
+                                                + token, Project.MSG_VERBOSE);
+                                            replace = startToken + token + endToken;
+                                        }
+
+
+                                        // generate the new line
+                                        line = line.substring(0, startIndex)
+                                             + replace
+                                             + line.substring(endIndex + endToken.length());
+
+                                        // set start position for next search
+                                        startIndex += replace.length();
+                                    }
+                                }
+
+                                // find next starttoken
+                                startIndex = line.indexOf(startToken, startIndex);
+                            }
+                            out.write(line);
+                            line = lineTokenizer.getToken(in);
+                        }
+                        if (in != null) {
+                            in.close();
+                        }
+                        if (out != null) {
+                            out.close();
+                        }
+                        ++filesProcessed;
+                    } else {
+                        log("Skipping " + srcFiles[j]
+                            + " as destination file is up to date",
+                            Project.MSG_VERBOSE);
+                    }
+                } catch (IOException ioe) {
+                    throw new BuildException(ioe.getMessage(), getLocation());
+                }
+            }
+        }
+        log("Translation performed on " + filesProcessed + " file(s).", Project.MSG_DEBUG);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java
new file mode 100644
index 0000000..7779c0c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/image/Image.java
@@ -0,0 +1,309 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.image;
+
+import com.sun.media.jai.codec.FileSeekableStream;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.optional.image.Draw;
+import org.apache.tools.ant.types.optional.image.ImageOperation;
+import org.apache.tools.ant.types.optional.image.Rotate;
+import org.apache.tools.ant.types.optional.image.Scale;
+import org.apache.tools.ant.types.optional.image.TransformOperation;
+
+import javax.media.jai.JAI;
+import javax.media.jai.PlanarImage;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Vector;
+
+/**
+ * A MatchingTask which relies on <a
+ * href="http://java.sun.com/products/java-media/jai">JAI (Java
+ * Advanced Imaging)</a> to perform image manipulation operations on
+ * existing images.  The operations are represented as ImageOperation
+ * DataType objects.  The operations are arranged to conform to the
+ * Chaining Model of JAI.  Check out the <a
+ * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/">
+ * JAI Programming Guide</a>.
+ *
+ * @see org.apache.tools.ant.types.optional.image.ImageOperation
+ * @see org.apache.tools.ant.types.DataType
+ */
+public class Image extends MatchingTask {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Vector instructions = new Vector();
+    protected boolean overwrite = false;
+    protected Vector filesets = new Vector();
+    protected File srcDir = null;
+    protected File destDir = null;
+
+    // CheckStyle:MemberNameCheck OFF - bc
+
+    //cannot remove underscores due to protected visibility >:(
+    protected String str_encoding = "JPEG";
+    protected boolean garbage_collect = false;
+
+    private boolean failonerror = true;
+
+    // CheckStyle:MemberNameCheck ON
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Add a set of files to be deleted.
+     * @param set the FileSet to add.
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Set whether to fail on error.
+     * If false, note errors to the output but keep going.
+     * @param failonerror true or false.
+     */
+    public void setFailOnError(boolean failonerror) {
+        this.failonerror = failonerror;
+    }
+
+    /**
+     * Set the source dir to find the image files.
+     * @param srcDir the directory in which the image files reside.
+     */
+    public void setSrcdir(File srcDir) {
+        this.srcDir = srcDir;
+    }
+
+    /**
+     * Set the image encoding type.  <a
+     * href="http://java.sun.com/products/java-media/jai/forDevelopers/jai1_0_1guide-unc/Encode.doc.html#56610">
+     * See this table in the JAI Programming Guide</a>.
+     * @param encoding the String image encoding.
+     */
+    public void setEncoding(String encoding) {
+        str_encoding = encoding;
+    }
+
+    /**
+     * Set whether to overwrite a file if there is a naming conflict.
+     * @param overwrite whether to overwrite.
+     */
+    public void setOverwrite(boolean overwrite) {
+        this.overwrite = overwrite;
+    }
+
+    /**
+     * Set whether to invoke Garbage Collection after each image processed.
+     * Defaults to false.
+     * @param gc whether to invoke the garbage collector.
+     */
+    public void setGc(boolean gc) {
+        garbage_collect = gc;
+    }
+
+    /**
+     * Set the destination directory for manipulated images.
+     * @param destDir The destination directory.
+     */
+    public void setDestDir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Add an ImageOperation to chain.
+     * @param instr The ImageOperation to append to the chain.
+     */
+    public void addImageOperation(ImageOperation instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a Rotate ImageOperation to the chain.
+     * @param instr The Rotate operation to add to the chain.
+     * @see org.apache.tools.ant.types.optional.image.Rotate
+     */
+    public void addRotate(Rotate instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a Scale ImageOperation to the chain.
+     * @param instr The Scale operation to add to the chain.
+     * @see org.apache.tools.ant.types.optional.image.Scale
+     */
+    public void addScale(Scale instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a Draw ImageOperation to the chain.  DrawOperation
+     * DataType objects can be nested inside the Draw object.
+     * @param instr The Draw operation to add to the chain.
+     * @see org.apache.tools.ant.types.optional.image.Draw
+     * @see org.apache.tools.ant.types.optional.image.DrawOperation
+     */
+    public void addDraw(Draw instr) {
+        instructions.add(instr);
+    }
+
+    /**
+    * Add an ImageOperation to chain.
+    * @param instr The ImageOperation to append to the chain.
+    * @since Ant 1.7
+    */
+    public void add(ImageOperation instr) {
+        addImageOperation(instr);
+    }
+
+    /**
+     * Executes all the chained ImageOperations on the file
+     * specified.
+     * @param file The file to be processed.
+     */
+    public void processFile(File file) {
+        try {
+            log("Processing File: " + file.getAbsolutePath());
+            FileSeekableStream input = new FileSeekableStream(file);
+            PlanarImage image = JAI.create("stream", input);
+            for (int i = 0; i < instructions.size(); i++) {
+                Object instr = instructions.elementAt(i);
+                if (instr instanceof TransformOperation) {
+                    image = ((TransformOperation) instr)
+                        .executeTransformOperation(image);
+                } else {
+                    log("Not a TransformOperation: " + instr);
+                }
+            }
+            input.close();
+
+            if (str_encoding.toLowerCase().equals("jpg")) {
+                str_encoding = "JPEG";
+            } else if (str_encoding.toLowerCase().equals("tif")) {
+                str_encoding = "TIFF";
+            }
+            if (destDir == null) {
+                destDir = srcDir;
+            }
+            File newFile = new File(destDir, file.getName());
+
+            if ((overwrite && newFile.exists()) && (!newFile.equals(file))) {
+                newFile.delete();
+            }
+            FileOutputStream stream = new FileOutputStream(newFile);
+
+            JAI.create("encode", image, stream, str_encoding.toUpperCase(),
+                       null);
+            stream.flush();
+            stream.close();
+        } catch (IOException err) {
+            if (!failonerror) {
+                log("Error processing file:  " + err);
+            } else {
+                throw new BuildException(err);
+            }
+        } catch (java.lang.RuntimeException rerr) {
+            if (!failonerror) {
+                log("Error processing file:  " + rerr);
+            } else {
+                throw new BuildException(rerr);
+            }
+        }
+    }
+
+    /**
+     * Executes the Task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+
+        validateAttributes();
+
+        try {
+            DirectoryScanner ds = null;
+            String[] files = null;
+            ArrayList filesList = new ArrayList();
+
+            // deal with specified srcDir
+            if (srcDir != null) {
+                ds = super.getDirectoryScanner(srcDir);
+
+                files = ds.getIncludedFiles();
+                for (int i = 0; i < files.length; i++) {
+                    filesList.add(new File(srcDir, files[i]));
+                }
+            }
+            // deal with the filesets
+            for (int i = 0; i < filesets.size(); i++) {
+                FileSet fs = (FileSet) filesets.elementAt(i);
+                ds = fs.getDirectoryScanner(getProject());
+                files = ds.getIncludedFiles();
+                File fromDir = fs.getDir(getProject());
+                for (int j = 0; j < files.length; j++) {
+                    filesList.add(new File(fromDir, files[j]));
+                }
+            }
+            if (!overwrite) {
+                // remove any files that shouldn't be overwritten.
+                ArrayList filesToRemove = new ArrayList();
+                for (Iterator i = filesList.iterator(); i.hasNext();) {
+                    File f = (File) i.next();
+                    File newFile = new File(destDir, f.getName());
+                    if (newFile.exists()) {
+                        filesToRemove.add(f);
+                    }
+                }
+                filesList.removeAll(filesToRemove);
+            }
+            // iterator through all the files and process them.
+            for (Iterator i = filesList.iterator(); i.hasNext();) {
+                File file = (File) i.next();
+
+                processFile(file);
+                if (garbage_collect) {
+                    System.gc();
+                }
+            }
+        } catch (Exception err) {
+            err.printStackTrace();
+            throw new BuildException(err.getMessage());
+        }
+    }
+
+    /**
+     * Ensure we have a consistent and legal set of attributes, and set
+     * any internal flags necessary based on different combinations
+     * of attributes.
+     * @throws BuildException on error.
+     */
+    protected void validateAttributes() throws BuildException {
+        if (srcDir == null && filesets.size() == 0) {
+            throw new BuildException("Specify at least one source"
+                                     + "--a srcDir or a fileset.");
+        }
+        if (srcDir == null && destDir == null) {
+            throw new BuildException("Specify the destDir, or the srcDir.");
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java
new file mode 100644
index 0000000..fdbde74
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/AbstractHotDeploymentTool.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Path;
+
+/**
+ *  Abstract class to support vendor-specific hot deployment tools.
+ *  This class will validate boilerplate attributes.
+ *
+ *  Subclassing this class for a vendor specific tool involves the
+ *  following.
+ *  <ol><li>Implement the <code>isActionValid()<code> method to insure the
+ *  action supplied as the "action" attribute of ServerDeploy is valid.
+ *  <li>Implement the <code>validateAttributes()</code> method to insure
+ *  all required attributes are supplied, and are in the correct format.
+ *  <li>Add a <code>add&lt;TOOL&gt;</code> method to the ServerDeploy
+ *  class.  This method will be called when Ant encounters a
+ *  <code>add&lt;TOOL&gt;</code> task nested in the
+ *  <code>serverdeploy</code> task.
+ *  <li>Define the <code>deploy</code> method.  This method should perform
+ *  whatever task it takes to hot-deploy the component.  IE: spawn a JVM and
+ *  run class, exec a native executable, run Java code...
+ *
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public abstract class AbstractHotDeploymentTool implements HotDeploymentTool {
+    /** The parent task **/
+    private ServerDeploy task;
+
+    /** The classpath passed to the JVM on execution. **/
+    private Path classpath;
+
+    /** The username for the deployment server. **/
+    private String userName;
+
+    /** The password for the deployment server. **/
+    private String password;
+
+    /** The address of the deployment server **/
+    private String server;
+
+    /**
+     *  Add a classpath as a nested element.
+     *  @return A Path object representing the classpath to be used.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(task.getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     *  Determines if the "action" attribute defines a valid action.
+     *  <p>Subclasses should determine if the action passed in is
+     *  supported by the vendor's deployment tool.
+     *  <p>Actions may by "deploy", "delete", etc... It all depends
+     *  on the tool.
+     *  @return true if the "action" attribute is valid, false if not.
+     */
+    protected abstract boolean isActionValid();
+
+    /**
+     *  Validates the passed in attributes.
+     *  Subclasses should chain to this super-method to insure
+     *  validation of boilerplate attributes.
+     *  <p>Only the "action" attribute is required in the
+     *  base class.  Subclasses should check attributes accordingly.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    public void validateAttributes() throws BuildException {
+        if (task.getAction() == null) {
+            throw new BuildException("The \"action\" attribute must be set");
+        }
+
+        if (!isActionValid()) {
+            throw new BuildException("Invalid action \"" + task.getAction() + "\" passed");
+        }
+
+        if (classpath == null) {
+            throw new BuildException("The classpath attribute must be set");
+        }
+    }
+
+    /**
+     *  Perform the actual deployment.
+     *  It's up to the subclasses to implement the actual behavior.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    public abstract void deploy() throws BuildException;
+
+    /**
+     *  Sets the parent task.
+     *  @param task a ServerDeploy object representing the parent task.
+     *  @ant.attribute ignore="true"
+     */
+    public void setTask(ServerDeploy task) {
+        this.task = task;
+    }
+
+    /**
+     *  Returns the task field, a ServerDeploy object.
+     *  @return An ServerDeploy representing the parent task.
+     */
+    protected ServerDeploy getTask() {
+        return task;
+    }
+
+    /**
+     *  gets the classpath field.
+     *  @return A Path representing the "classpath" attribute.
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     *  The classpath to be passed to the JVM running the tool;
+     *  optional depending upon the tool.
+     *  The classpath may also be supplied as a nested element.
+     *  @param classpath A Path object representing the "classpath" attribute.
+     */
+    public void setClasspath(Path classpath) {
+        this.classpath = classpath;
+    }
+
+    /**
+     *  Returns the userName field.
+     *  @return A String representing the "userName" attribute.
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     *  The user with privileges to deploy applications to the server; optional.
+     *  @param userName A String representing the "userName" attribute.
+     */
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    /**
+     *  Returns the password field.
+     *  @return A String representing the "password" attribute.
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     *  The password of the user; optional.
+     *  @param password A String representing the "password" attribute.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     *  Returns the server field.
+     *  @return A String representing the "server" attribute.
+     */
+    public String getServer() {
+        return server;
+    }
+
+    /**
+     *  The address or URL for the server where the component will be deployed.
+     *  @param server A String representing the "server" attribute.
+     */
+    public void setServer(String server) {
+        this.server = server;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java
new file mode 100644
index 0000000..3a25e61
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/GenericHotDeploymentTool.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *  A generic tool for J2EE server hot deployment.
+ *  <p>The simple implementation spawns a JVM with the supplied
+ *  class name, jvm args, and arguments.
+ *
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class GenericHotDeploymentTool extends AbstractHotDeploymentTool {
+    /** A Java task used to run the deployment tool **/
+    private Java java;
+
+    /** The fully qualified class name of the deployment tool **/
+    private String className;
+
+    /** List of valid actions **/
+    private static final String[] VALID_ACTIONS = {ACTION_DEPLOY};
+
+    /**
+     *  Add a nested argument element to hand to the deployment tool; optional.
+     *  @return A Commandline.Argument object representing the
+     *  command line argument being passed when the deployment
+     *  tool is run.  IE: "-user=mark", "-password=venture"...
+     */
+    public Commandline.Argument createArg() {
+        return java.createArg();
+    }
+
+    /**
+     *  Add a nested argment element to hand to the JVM running the
+     *  deployment tool.
+     *  Creates a nested arg element.
+     *  @return A Commandline.Argument object representing the
+     *  JVM command line argument being passed when the deployment
+     *  tool is run.  IE: "-ms64m", "-mx128m"...
+     */
+    public Commandline.Argument createJvmarg() {
+        return java.createJvmarg();
+    }
+
+    /**
+     *  Determines if the "action" attribute defines a valid action.
+     *  <p>Subclasses should determine if the action passed in is
+     *  supported by the vendor's deployment tool.
+     *  For this generic implementation, the only valid action is "deploy"
+     *  @return true if the "action" attribute is valid, false if not.
+     */
+    protected boolean isActionValid() {
+        return (getTask().getAction().equals(VALID_ACTIONS[0]));
+    }
+
+    /**
+     *  Sets the parent task.
+     *  @param task An ServerDeploy object representing the parent task.
+     *  @ant.attribute ignored="true"
+     */
+    public void setTask(ServerDeploy task) {
+        super.setTask(task);
+        java = new Java(task);
+    }
+
+    /**
+     *  Perform the actual deployment.
+     *  For this generic implementation, a JVM is spawned using the
+     *  supplied classpath, classname, JVM args, and command line arguments.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    public void deploy() throws BuildException {
+        java.setClassname(className);
+        java.setClasspath(getClasspath());
+        java.setFork(true);
+        java.setFailonerror(true);
+        java.execute();
+    }
+
+    /**
+     *  Validates the passed in attributes.
+     *  Ensures the className and arguments attribute have been set.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    public void validateAttributes() throws BuildException {
+        super.validateAttributes();
+
+        if (className == null) {
+            throw new BuildException("The classname attribute must be set");
+        }
+    }
+
+    /**
+     *  The name of the class to execute to perfom
+     *  deployment; required.
+     *  Example: "com.foobar.tools.deploy.DeployTool"
+     *  @param className The fully qualified class name of the class
+     *  to perform deployment.
+     */
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    /**
+     * get the java attribute.
+     * @return the java attribute.
+     */
+    public Java getJava() {
+        return java;
+    }
+
+    /**
+     * Get the classname attribute.
+     * @return the classname value.
+     */
+    public String getClassName() {
+        return className;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java
new file mode 100644
index 0000000..16c55d8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/HotDeploymentTool.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ *  An interface for vendor-specific "hot" deployment tools.
+ *
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public interface HotDeploymentTool {
+    /** The delete action String **/
+    String ACTION_DELETE = "delete";
+
+    /** The deploy action String **/
+    String ACTION_DEPLOY = "deploy";
+
+    /** The list action String **/
+    String ACTION_LIST = "list";
+
+    /** The undeploy action String **/
+    String ACTION_UNDEPLOY = "undeploy";
+
+    /** The update action String **/
+    String ACTION_UPDATE = "update";
+
+    /**
+     *  Validates the passed in attributes.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    void validateAttributes() throws BuildException;
+
+    /**
+     *  Perform the actual deployment.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    void deploy() throws BuildException;
+
+    /**
+     *  Sets the parent task.
+     *  @param task A ServerDeploy object representing the parent task.
+     */
+    void setTask(ServerDeploy task);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java
new file mode 100644
index 0000000..caed6a5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/JonasHotDeploymentTool.java
@@ -0,0 +1,251 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.Path;
+
+/**
+ *  An Ant wrapper task for the weblogic.deploy tool. This is used
+ *  to hot-deploy J2EE applications to a running WebLogic server.
+ *  This is <b>not</b> the same as creating the application
+ *  archive. This task assumes the archive (EAR, JAR, or WAR) file
+ *  has been assembled and is supplied as the "source" attribute.
+ *  <p>
+ *
+ *  In the end, this task assembles the commadline parameters and
+ *  runs the weblogic.deploy tool in a seperate JVM.
+ *
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *@see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class JonasHotDeploymentTool extends GenericHotDeploymentTool implements HotDeploymentTool {
+
+    /**
+     *  Description of the Field
+     */
+    protected static final String DEFAULT_ORB = "RMI";
+
+    /**
+     *  The classname of the tool to run *
+     */
+    private static final String JONAS_DEPLOY_CLASS_NAME = "org.objectweb.jonas.adm.JonasAdmin";
+
+    /**
+     *  All the valid actions that weblogic.deploy permits *
+     */
+    private static final String[] VALID_ACTIONS
+        = {ACTION_DELETE, ACTION_DEPLOY, ACTION_LIST, ACTION_UNDEPLOY, ACTION_UPDATE};
+
+    /**
+     *  Description of the Field
+     */
+    private File jonasroot;
+
+    /**
+     *  Description of the Field
+     */
+    private String orb = null;
+
+    /**
+     *  Description of the Field
+     */
+    private String davidHost;
+
+    /**
+     *  Description of the Field
+     */
+    private int davidPort;
+
+
+    /**
+     *  Set the host for the David ORB; required if
+     *  ORB==david.
+     *
+     *@param  inValue  The new davidhost value
+     */
+    public void setDavidhost(final String inValue) {
+        davidHost = inValue;
+    }
+
+
+    /**
+     *  Set the port for the David ORB; required if
+     *  ORB==david.
+     *
+     *@param  inValue  The new davidport value
+     */
+    public void setDavidport(final int inValue) {
+        davidPort = inValue;
+    }
+
+
+    /**
+     *  set the jonas root directory (-Dinstall.root=). This
+     *  element is required.
+     *
+     *@param  inValue  The new jonasroot value
+     */
+    public void setJonasroot(final File inValue) {
+        jonasroot = inValue;
+    }
+
+
+    /**
+     *
+     * Choose your ORB : RMI, JEREMIE, DAVID, ...; optional.
+     * If omitted, it defaults
+     * to the one present in classpath. The corresponding JOnAS JAR is
+     * automatically added to the classpath. If your orb is DAVID (RMI/IIOP) you must
+     * specify davidhost and davidport properties.
+     *
+     *@param  inValue  RMI, JEREMIE, DAVID,...
+     */
+    public void setOrb(final String inValue) {
+        orb = inValue;
+    }
+
+
+    /**
+     *  gets the classpath field.
+     *
+     *@return    A Path representing the "classpath" attribute.
+     */
+    public Path getClasspath() {
+
+        Path aClassPath = super.getClasspath();
+
+        if (aClassPath == null) {
+            aClassPath = new Path(getTask().getProject());
+        }
+        if (orb != null) {
+            String aOrbJar = new File(jonasroot, "lib/" + orb + "_jonas.jar").toString();
+            String aConfigDir = new File(jonasroot, "config/").toString();
+            Path aJOnASOrbPath = new Path(aClassPath.getProject(),
+                    aOrbJar + File.pathSeparator + aConfigDir);
+            aClassPath.append(aJOnASOrbPath);
+        }
+        return aClassPath;
+    }
+
+
+    /**
+     *  Validates the passed in attributes. <p>
+     *
+     *  The rules are:
+     *  <ol>
+     *    <li> If action is "deploy" or "update" the "application"
+     *    and "source" attributes must be supplied.
+     *    <li> If action is "delete" or "undeploy" the
+     *    "application" attribute must be supplied.
+     *
+     *@exception  BuildException                       Description
+     *      of Exception
+     */
+    public void validateAttributes() throws BuildException {
+        // super.validateAttributes(); // don't want to call this method
+
+        Java java = getJava();
+
+        String action = getTask().getAction();
+        if (action == null) {
+            throw new BuildException("The \"action\" attribute must be set");
+        }
+
+        if (!isActionValid()) {
+            throw new BuildException("Invalid action \"" + action + "\" passed");
+        }
+
+        if (getClassName() == null) {
+            setClassName(JONAS_DEPLOY_CLASS_NAME);
+        }
+
+        if (jonasroot == null || jonasroot.isDirectory()) {
+            java.createJvmarg().setValue("-Dinstall.root=" + jonasroot);
+            java.createJvmarg().setValue("-Djava.security.policy=" + jonasroot
+                + "/config/java.policy");
+
+            if ("DAVID".equals(orb)) {
+                java.createJvmarg().setValue("-Dorg.omg.CORBA.ORBClass"
+                    + "=org.objectweb.david.libs.binding.orbs.iiop.IIOPORB");
+                java.createJvmarg().setValue("-Dorg.omg.CORBA.ORBSingletonClass="
+                    + "org.objectweb.david.libs.binding.orbs.ORBSingletonClass");
+                java.createJvmarg().setValue("-Djavax.rmi.CORBA.StubClass="
+                    + "org.objectweb.david.libs.stub_factories.rmi.StubDelegate");
+                java.createJvmarg().setValue("-Djavax.rmi.CORBA.PortableRemoteObjectClass="
+                    + "org.objectweb.david.libs.binding.rmi.ORBPortableRemoteObjectDelegate");
+                java.createJvmarg().setValue("-Djavax.rmi.CORBA.UtilClass="
+                    + "org.objectweb.david.libs.helpers.RMIUtilDelegate");
+                java.createJvmarg().setValue("-Ddavid.CosNaming.default_method=0");
+                java.createJvmarg().setValue("-Ddavid.rmi.ValueHandlerClass="
+                    + "com.sun.corba.se.internal.io.ValueHandlerImpl");
+                if (davidHost != null) {
+                    java.createJvmarg().setValue("-Ddavid.CosNaming.default_host="
+                        + davidHost);
+                }
+                if (davidPort != 0) {
+                    java.createJvmarg().setValue("-Ddavid.CosNaming.default_port="
+                        + davidPort);
+                }
+            }
+        }
+
+        if (getServer() != null) {
+            java.createArg().setLine("-n " + getServer());
+        }
+
+        if (action.equals(ACTION_DEPLOY)
+            || action.equals(ACTION_UPDATE)
+            || action.equals("redeploy")) {
+            java.createArg().setLine("-a " + getTask().getSource());
+        } else if (action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY)) {
+            java.createArg().setLine("-r " + getTask().getSource());
+        } else if (action.equals(ACTION_LIST)) {
+            java.createArg().setValue("-l");
+        }
+    }
+
+
+    /**
+     *  Determines if the action supplied is valid. <p>
+     *
+     *  Valid actions are contained in the static array
+     *  VALID_ACTIONS
+     *
+     *@return    true if the action attribute is valid, false if
+     *      not.
+     */
+    protected boolean isActionValid() {
+        boolean valid = false;
+
+        String action = getTask().getAction();
+
+        for (int i = 0; i < VALID_ACTIONS.length; i++) {
+            if (action.equals(VALID_ACTIONS[i])) {
+                valid = true;
+                break;
+            }
+        }
+
+        return valid;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java
new file mode 100644
index 0000000..b2bb093
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/ServerDeploy.java
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ *  Controls hot deployment tools for J2EE servers.
+ *
+ *  This class is used as a framework for the creation of vendor specific
+ *  hot deployment tools.
+ *
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.GenericHotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.WebLogicHotDeploymentTool
+ */
+public class ServerDeploy extends Task {
+    /** The action to be performed.  IE: "deploy", "delete", etc... **/
+    private String action;
+
+    /** The source (fully-qualified path) to the component being deployed **/
+    private File source;
+
+    /** The vendor specific tool for deploying the component **/
+    private Vector vendorTools = new Vector();
+
+    ///////////////////////////////////////////////////////////////////////////
+    //
+    // Place vendor specific tool creations here.
+    //
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     *  Creates a generic deployment tool.
+     *  <p>Ant calls this method on creation to handle embedded "generic" elements
+     *  in the ServerDeploy task.
+     *  @param tool An instance of GenericHotDeployment tool, passed in by Ant.
+     */
+    public void addGeneric(GenericHotDeploymentTool tool) {
+        tool.setTask(this);
+        vendorTools.addElement(tool);
+    }
+
+    /**
+     *  Creates a WebLogic deployment tool, for deployment to WebLogic servers.
+     *  <p>Ant calls this method on creation to handle embedded "weblogic" elements
+     *  in the ServerDeploy task.
+     *  @param tool An instance of WebLogicHotDeployment tool, passed in by Ant.
+     */
+    public void addWeblogic(WebLogicHotDeploymentTool tool) {
+        tool.setTask(this);
+        vendorTools.addElement(tool);
+    }
+
+    /**
+     *  Creates a JOnAS deployment tool, for deployment to JOnAS servers.
+     *  <p>Ant calls this method on creation to handle embedded "jonas" elements
+     *  in the ServerDeploy task.
+     *  @param tool An instance of JonasHotDeployment tool, passed in by Ant.
+     */
+    public void addJonas(JonasHotDeploymentTool tool) {
+        tool.setTask(this);
+        vendorTools.addElement(tool);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    //
+    // Execute method
+    //
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     *  Execute the task.
+     *  <p>This method calls the deploy() method on each of the vendor-specific tools
+     *  in the <code>vendorTools</code> collection.  This performs the actual
+     *  process of deployment on each tool.
+     *  @exception org.apache.tools.ant.BuildException if the attributes
+     *  are invalid or incomplete, or a failure occurs in the deployment process.
+     */
+    public void execute() throws BuildException {
+        for (Enumeration e = vendorTools.elements();
+             e.hasMoreElements();) {
+            HotDeploymentTool tool = (HotDeploymentTool) e.nextElement();
+            tool.validateAttributes();
+            tool.deploy();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    //
+    // Set/get methods
+    //
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     *  Returns the action field.
+     *  @return A string representing the "action" attribute.
+     */
+    public String getAction() {
+        return action;
+    }
+
+    /**
+     *  The action to be performed, usually "deploy"; required.
+     *   Some tools support additional actions, such as "delete", "list", "undeploy", "update"...
+     *  @param action A String representing the "action" attribute.
+     */
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    /**
+     *  Returns the source field (the path/filename of the component to be
+     *  deployed.
+     *  @return A File object representing the "source" attribute.
+     */
+    public File getSource() {
+        return source;
+    }
+
+    /**
+     *  The filename of the component to be deployed; optional
+     *  depending upon the tool and the action.
+     *  @param source String representing the "source" attribute.
+     */
+    public void setSource(File source) {
+        this.source = source;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java
new file mode 100644
index 0000000..6fbbad2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/j2ee/WebLogicHotDeploymentTool.java
@@ -0,0 +1,247 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.j2ee;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+
+/**
+ *  An Ant wrapper task for the weblogic.deploy tool.  This is used to
+ *  hot-deploy J2EE applications to a running WebLogic server.
+ *  This is <b>not</b> the same as creating the application archive.
+ *  This task assumes the archive (EAR, JAR, or WAR) file has been
+ *  assembled and is supplied as the "source" attribute.
+ *  <p>In the end, this task assembles the commadline parameters
+ *  and runs the weblogic.deploy tool in a seperate JVM.
+ *
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.HotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.AbstractHotDeploymentTool
+ *  @see org.apache.tools.ant.taskdefs.optional.j2ee.ServerDeploy
+ */
+public class WebLogicHotDeploymentTool extends AbstractHotDeploymentTool
+                                       implements HotDeploymentTool {
+    private static final int STRING_BUFFER_SIZE = 1024;
+    /** The classname of the tool to run **/
+    private static final String WEBLOGIC_DEPLOY_CLASS_NAME = "weblogic.deploy";
+
+    /** All the valid actions that weblogic.deploy permits **/
+    private static final String[] VALID_ACTIONS
+        = {ACTION_DELETE, ACTION_DEPLOY, ACTION_LIST, ACTION_UNDEPLOY, ACTION_UPDATE};
+
+    /** Represents the "-debug" flag from weblogic.deploy **/
+    private boolean debug;
+
+    /** The application name that is being deployed **/
+    private String application;
+
+    /** The component name:target(s) for the "-component" argument of weblogic.deploy **/
+    private String component;
+
+    /**
+     *  Perform the actual deployment.
+     *  For this implementation, a JVM is spawned and the weblogic.deploy
+     *  tools is executed.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete.
+     */
+    public void deploy() {
+        Java java = new Java(getTask());
+        java.setFork(true);
+        java.setFailonerror(true);
+        java.setClasspath(getClasspath());
+
+        java.setClassname(WEBLOGIC_DEPLOY_CLASS_NAME);
+        java.createArg().setLine(getArguments());
+        java.execute();
+    }
+
+    /**
+     *  Validates the passed in attributes.
+     *  <p>The rules are:
+     *  <ol><li>If action is "deploy" or "update" the "application" and "source"
+     *  attributes must be supplied.
+     *  <li>If action is "delete" or "undeploy" the "application" attribute must
+     *  be supplied.
+     *  @exception org.apache.tools.ant.BuildException if the attributes are invalid or incomplete
+     */
+    public void validateAttributes() throws BuildException {
+        super.validateAttributes();
+
+        String action = getTask().getAction();
+
+        // check that the password has been set
+        if ((getPassword() == null)) {
+            throw new BuildException("The password attribute must be set.");
+        }
+
+        // check for missing application on deploy & update
+        if ((action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE))
+            && application == null) {
+            throw new BuildException("The application attribute must be set "
+                + "if action = " + action);
+        }
+
+        // check for missing source on deploy & update
+        if ((action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE))
+            && getTask().getSource() == null) {
+            throw new BuildException("The source attribute must be set if "
+                + "action = " + action);
+        }
+
+        // check for missing application on delete & undeploy
+        if ((action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY))
+            && application == null) {
+            throw new BuildException("The application attribute must be set if "
+                + "action = " + action);
+        }
+    }
+
+    /**
+     *  Builds the arguments to pass to weblogic.deploy according to the
+     *  supplied action.
+     *  @return A String containing the arguments for the weblogic.deploy tool.
+     * @throws BuildException if there is an error.
+     */
+    public String getArguments() throws BuildException {
+        String action = getTask().getAction();
+        String args = null;
+
+        if (action.equals(ACTION_DEPLOY) || action.equals(ACTION_UPDATE)) {
+            args = buildDeployArgs();
+        } else if (action.equals(ACTION_DELETE) || action.equals(ACTION_UNDEPLOY)) {
+            args = buildUndeployArgs();
+        } else if (action.equals(ACTION_LIST)) {
+            args = buildListArgs();
+        }
+
+        return args;
+    }
+
+    /**
+     *  Determines if the action supplied is valid.
+     *  <p>Valid actions are contained in the static array VALID_ACTIONS
+     *  @return true if the action attribute is valid, false if not.
+     */
+    protected boolean isActionValid() {
+        boolean valid = false;
+
+        String action = getTask().getAction();
+
+        for (int i = 0; i < VALID_ACTIONS.length; i++) {
+            if (action.equals(VALID_ACTIONS[i])) {
+                valid = true;
+                break;
+            }
+        }
+
+        return valid;
+    }
+
+    /**
+     *  Builds the prefix arguments to pass to weblogic.deploy.
+     *  These arguments are generic across all actions.
+     *  @return A StringBuffer containing the prefix arguments.
+     *  The action-specific build methods will append to this StringBuffer.
+     */
+    protected StringBuffer buildArgsPrefix() {
+        ServerDeploy task = getTask();
+        // constructs the "-url <url> -debug <action> <password>" portion
+        // of the commmand line
+        return new StringBuffer(STRING_BUFFER_SIZE)
+                .append((getServer() != null)
+                    ? "-url " + getServer()
+                    : "")
+                .append(" ")
+                .append(debug ? "-debug " : "")
+                .append((getUserName() != null)
+                    ? "-username " + getUserName()
+                    : "")
+                .append(" ")
+                .append(task.getAction()).append(" ")
+                .append(getPassword()).append(" ");
+    }
+
+    /**
+     *  Builds the arguments to pass to weblogic.deploy for deployment actions
+     *  ("deploy" and "update").
+     *  @return A String containing the full argument string for weblogic.deploy.
+     */
+    protected String buildDeployArgs() {
+        String args = buildArgsPrefix()
+                .append(application).append(" ")
+                .append(getTask().getSource())
+                .toString();
+
+        if (component != null) {
+            args = "-component " + component + " " + args;
+        }
+
+        return args;
+    }
+
+    /**
+     *  Builds the arguments to pass to weblogic.deploy for undeployment actions
+     *  ("undeploy" and "delete").
+     *  @return A String containing the full argument string for weblogic.deploy.
+     */
+    protected String buildUndeployArgs() {
+        return buildArgsPrefix()
+                .append(application).append(" ")
+                .toString();
+    }
+
+    /**
+     *  Builds the arguments to pass to weblogic.deploy for the list action
+     *  @return A String containing the full argument string for weblogic.deploy.
+     */
+    protected String buildListArgs() {
+        return buildArgsPrefix()
+                .toString();
+    }
+
+    /**
+     *  If set to true, additional information will be
+     *  printed during the deployment process; optional.
+     *  @param debug A boolean representing weblogic.deploy "-debug" flag.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     *  The name of the application being deployed; required.
+     *  @param application A String representing the application portion of the
+     *  weblogic.deploy command line.
+     */
+    public void setApplication(String application) {
+        this.application = application;
+    }
+
+    /**
+     * the component string for the deployment targets; optional.
+     * It is in the form <code>&lt;component&gt;:&lt;target1&gt;,&lt;target2&gt;...</code>
+     * Where component is the archive name (minus the .jar, .ear, .war
+     * extension).  Targets are the servers where the components will be deployed
+
+     *  @param component A String representing the value of the "-component"
+     *  argument of the weblogic.deploy command line argument.
+     */
+    public void setComponent(String component) {
+        this.component = component;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java
new file mode 100644
index 0000000..ea5ef23
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJDoc.java
@@ -0,0 +1,215 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Runs the JJDoc compiler compiler.
+ *
+ */
+public class JJDoc extends Task {
+
+    // keys to optional attributes
+    private static final String OUTPUT_FILE       = "OUTPUT_FILE";
+    private static final String TEXT              = "TEXT";
+    private static final String ONE_TABLE         = "ONE_TABLE";
+
+    private final Hashtable optionalAttrs = new Hashtable();
+
+    private String outputFile = null;
+    private boolean plainText = false;
+
+    private static final String DEFAULT_SUFFIX_HTML = ".html";
+    private static final String DEFAULT_SUFFIX_TEXT = ".txt";
+
+    // required attributes
+    private File targetFile      = null;
+    private File javaccHome      = null;
+
+    private CommandlineJava cmdl = new CommandlineJava();
+
+
+    /**
+     * Sets the TEXT BNF documentation option.
+     * @param plainText a <code>boolean</code> value.
+     */
+    public void setText(boolean plainText) {
+        optionalAttrs.put(TEXT, plainText ? Boolean.TRUE : Boolean.FALSE);
+        this.plainText = plainText;
+    }
+
+    /**
+     * Sets the ONE_TABLE documentation option.
+     * @param oneTable a <code>boolean</code> value.
+     */
+    public void setOnetable(boolean oneTable) {
+        optionalAttrs.put(ONE_TABLE, oneTable ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * The outputfile to write the generated BNF documentation file to.
+     * If not set, the file is written with the same name as
+     * the JavaCC grammar file with a suffix .html or .txt.
+     * @param outputFile the name of the output file.
+     */
+    public void setOutputfile(String outputFile) {
+        this.outputFile = outputFile;
+    }
+
+    /**
+     * The javacc grammar file to process.
+     * @param target the grammar file.
+     */
+    public void setTarget(File target) {
+        this.targetFile = target;
+    }
+
+    /**
+     * The directory containing the JavaCC distribution.
+     * @param javaccHome the home directory.
+     */
+    public void setJavacchome(File javaccHome) {
+        this.javaccHome = javaccHome;
+    }
+
+    /**
+     * Constructor
+     */
+    public JJDoc() {
+        cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+    }
+
+    /**
+     * Do the task.
+     * @throws BuildException if there is an error.
+     */
+    public void execute() throws BuildException {
+
+        // load command line with optional attributes
+        Enumeration iter = optionalAttrs.keys();
+        while (iter.hasMoreElements()) {
+            String name  = (String) iter.nextElement();
+            Object value = optionalAttrs.get(name);
+            cmdl.createArgument()
+                .setValue("-" + name + ":" + value.toString());
+        }
+
+        if (targetFile == null || !targetFile.isFile()) {
+            throw new BuildException("Invalid target: " + targetFile);
+        }
+
+        if (outputFile != null) {
+            cmdl.createArgument() .setValue("-" + OUTPUT_FILE + ":"
+                                            + outputFile.replace('\\', '/'));
+        }
+
+        // use the directory containing the target as the output directory
+        File javaFile = new File(createOutputFileName(targetFile, outputFile,
+                                                      plainText));
+
+        if (javaFile.exists()
+             && targetFile.lastModified() < javaFile.lastModified()) {
+            log("Target is already built - skipping (" + targetFile + ")",
+                Project.MSG_VERBOSE);
+            return;
+        }
+
+        cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+        final Path classpath = cmdl.createClasspath(getProject());
+        final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+        classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+        classpath.addJavaRuntime();
+
+        cmdl.setClassname(JavaCC.getMainClass(classpath,
+                                              JavaCC.TASKDEF_TYPE_JJDOC));
+
+        final Commandline.Argument arg = cmdl.createVmArgument();
+        arg.setValue("-mx140M");
+        arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+        final Execute process =
+            new Execute(new LogStreamHandler(this,
+                                             Project.MSG_INFO,
+                                             Project.MSG_INFO),
+                        null);
+        log(cmdl.describeCommand(), Project.MSG_VERBOSE);
+        process.setCommandline(cmdl.getCommandline());
+
+        try {
+            if (process.execute() != 0) {
+                throw new BuildException("JJDoc failed.");
+            }
+        } catch (IOException e) {
+            throw new BuildException("Failed to launch JJDoc", e);
+        }
+    }
+
+    private String createOutputFileName(File destFile, String optionalOutputFile,
+                                        boolean plain) {
+        String suffix = DEFAULT_SUFFIX_HTML;
+        String javaccFile = destFile.getAbsolutePath().replace('\\', '/');
+
+        if (plain) {
+            suffix = DEFAULT_SUFFIX_TEXT;
+        }
+
+        if ((optionalOutputFile == null) || optionalOutputFile.equals("")) {
+            int filePos = javaccFile.lastIndexOf("/");
+
+            if (filePos >= 0) {
+                javaccFile = javaccFile.substring(filePos + 1);
+            }
+
+            int suffixPos = javaccFile.lastIndexOf('.');
+
+            if (suffixPos == -1) {
+                optionalOutputFile = javaccFile + suffix;
+            } else {
+                String currentSuffix = javaccFile.substring(suffixPos);
+
+                if (currentSuffix.equals(suffix)) {
+                    optionalOutputFile = javaccFile + suffix;
+                } else {
+                    optionalOutputFile = javaccFile.substring(0, suffixPos)
+                        + suffix;
+                }
+            }
+        } else {
+            optionalOutputFile = optionalOutputFile.replace('\\', '/');
+        }
+
+        return (getProject().getBaseDir() + "/" + optionalOutputFile)
+            .replace('\\', '/');
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java
new file mode 100644
index 0000000..121c398
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JJTree.java
@@ -0,0 +1,405 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Runs the JJTree compiler compiler.
+ *
+ */
+public class JJTree extends Task {
+
+    // keys to optional attributes
+    private static final String OUTPUT_FILE       = "OUTPUT_FILE";
+    private static final String BUILD_NODE_FILES  = "BUILD_NODE_FILES";
+    private static final String MULTI             = "MULTI";
+    private static final String NODE_DEFAULT_VOID = "NODE_DEFAULT_VOID";
+    private static final String NODE_FACTORY      = "NODE_FACTORY";
+    private static final String NODE_SCOPE_HOOK   = "NODE_SCOPE_HOOK";
+    private static final String NODE_USES_PARSER  = "NODE_USES_PARSER";
+    private static final String STATIC            = "STATIC";
+    private static final String VISITOR           = "VISITOR";
+
+    private static final String NODE_PACKAGE      = "NODE_PACKAGE";
+    private static final String VISITOR_EXCEPTION = "VISITOR_EXCEPTION";
+    private static final String NODE_PREFIX       = "NODE_PREFIX";
+
+    private final Hashtable optionalAttrs = new Hashtable();
+
+    private String outputFile = null;
+
+    private static final String DEFAULT_SUFFIX = ".jj";
+
+    // required attributes
+    private File outputDirectory = null;
+    private File targetFile      = null;
+    private File javaccHome      = null;
+
+    private CommandlineJava cmdl = new CommandlineJava();
+
+
+    /**
+     * Sets the BUILD_NODE_FILES grammar option.
+     * @param buildNodeFiles a <code>boolean</code> value.
+     */
+    public void setBuildnodefiles(boolean buildNodeFiles) {
+        optionalAttrs.put(BUILD_NODE_FILES, buildNodeFiles ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the MULTI grammar option.
+     * @param multi a <code>boolean</code> value.
+     */
+    public void setMulti(boolean multi) {
+        optionalAttrs.put(MULTI, multi ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the NODE_DEFAULT_VOID grammar option.
+     * @param nodeDefaultVoid a <code>boolean</code> value.
+     */
+    public void setNodedefaultvoid(boolean nodeDefaultVoid) {
+        optionalAttrs.put(NODE_DEFAULT_VOID, nodeDefaultVoid ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the NODE_FACTORY grammar option.
+     * @param nodeFactory a <code>boolean</code> value.
+     */
+    public void setNodefactory(boolean nodeFactory) {
+        optionalAttrs.put(NODE_FACTORY, nodeFactory ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the NODE_SCOPE_HOOK grammar option.
+     * @param nodeScopeHook a <code>boolean</code> value.
+     */
+    public void setNodescopehook(boolean nodeScopeHook) {
+        optionalAttrs.put(NODE_SCOPE_HOOK, nodeScopeHook ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the NODE_USES_PARSER grammar option.
+     * @param nodeUsesParser a <code>boolean</code> value.
+     */
+    public void setNodeusesparser(boolean nodeUsesParser) {
+        optionalAttrs.put(NODE_USES_PARSER, nodeUsesParser ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the STATIC grammar option.
+     * @param staticParser a <code>boolean</code> value.
+     */
+    public void setStatic(boolean staticParser) {
+        optionalAttrs.put(STATIC, staticParser ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the VISITOR grammar option.
+     * @param visitor a <code>boolean</code> value.
+     */
+    public void setVisitor(boolean visitor) {
+        optionalAttrs.put(VISITOR, visitor ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the NODE_PACKAGE grammar option.
+     * @param nodePackage the option to use.
+     */
+    public void setNodepackage(String nodePackage) {
+        optionalAttrs.put(NODE_PACKAGE, nodePackage);
+    }
+
+    /**
+     * Sets the VISITOR_EXCEPTION grammar option.
+     * @param visitorException the option to use.
+     */
+    public void setVisitorException(String visitorException) {
+        optionalAttrs.put(VISITOR_EXCEPTION, visitorException);
+    }
+
+    /**
+     * Sets the NODE_PREFIX grammar option.
+     * @param nodePrefix the option to use.
+     */
+    public void setNodeprefix(String nodePrefix) {
+        optionalAttrs.put(NODE_PREFIX, nodePrefix);
+    }
+
+    /**
+     * The directory to write the generated JavaCC grammar and node files to.
+     * If not set, the files are written to the directory
+     * containing the grammar file.
+     * @param outputDirectory the output directory.
+     */
+    public void setOutputdirectory(File outputDirectory) {
+        this.outputDirectory = outputDirectory;
+    }
+
+    /**
+     * The outputfile to write the generated JavaCC grammar file to.
+     * If not set, the file is written with the same name as
+     * the JJTree grammar file with a suffix .jj.
+     * @param outputFile the output file name.
+     */
+    public void setOutputfile(String outputFile) {
+        this.outputFile = outputFile;
+    }
+
+    /**
+     * The jjtree grammar file to process.
+     * @param targetFile the grammar file.
+     */
+    public void setTarget(File targetFile) {
+        this.targetFile = targetFile;
+    }
+
+    /**
+     * The directory containing the JavaCC distribution.
+     * @param javaccHome the directory containing JavaCC.
+     */
+    public void setJavacchome(File javaccHome) {
+        this.javaccHome = javaccHome;
+    }
+
+    /**
+     * Constructor
+     */
+    public JJTree() {
+        cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+    }
+
+    /**
+     * Run the task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+
+        // load command line with optional attributes
+        Enumeration iter = optionalAttrs.keys();
+        while (iter.hasMoreElements()) {
+            String name  = (String) iter.nextElement();
+            Object value = optionalAttrs.get(name);
+            cmdl.createArgument().setValue("-" + name + ":" + value.toString());
+        }
+
+        if (targetFile == null || !targetFile.isFile()) {
+            throw new BuildException("Invalid target: " + targetFile);
+        }
+
+        File javaFile = null;
+
+        // use the directory containing the target as the output directory
+        if (outputDirectory == null) {
+            // convert backslashes to slashes, otherwise jjtree will
+            // put this as comments and this seems to confuse javacc
+            cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+                                           + getDefaultOutputDirectory());
+
+            javaFile = new File(createOutputFileName(targetFile, outputFile,
+                                                     null));
+        } else {
+            if (!outputDirectory.isDirectory()) {
+                throw new BuildException("'outputdirectory' " + outputDirectory
+                                         + " is not a directory.");
+            }
+
+            // convert backslashes to slashes, otherwise jjtree will
+            // put this as comments and this seems to confuse javacc
+            cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+                                           + outputDirectory.getAbsolutePath()
+                                             .replace('\\', '/'));
+
+            javaFile = new File(createOutputFileName(targetFile, outputFile,
+                                                     outputDirectory
+                                                     .getPath()));
+        }
+
+        if (javaFile.exists()
+            && targetFile.lastModified() < javaFile.lastModified()) {
+            log("Target is already built - skipping (" + targetFile + ")",
+                Project.MSG_VERBOSE);
+            return;
+        }
+
+        if (outputFile != null) {
+            cmdl.createArgument().setValue("-" + OUTPUT_FILE + ":"
+                                           + outputFile.replace('\\', '/'));
+        }
+
+        cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+        final Path classpath = cmdl.createClasspath(getProject());
+        final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+        classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+        classpath.addJavaRuntime();
+
+        cmdl.setClassname(JavaCC.getMainClass(classpath,
+                                              JavaCC.TASKDEF_TYPE_JJTREE));
+
+        final Commandline.Argument arg = cmdl.createVmArgument();
+        arg.setValue("-mx140M");
+        arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+        final Execute process =
+            new Execute(new LogStreamHandler(this,
+                                             Project.MSG_INFO,
+                                             Project.MSG_INFO),
+                        null);
+        log(cmdl.describeCommand(), Project.MSG_VERBOSE);
+        process.setCommandline(cmdl.getCommandline());
+
+        try {
+            if (process.execute() != 0) {
+                throw new BuildException("JJTree failed.");
+            }
+        } catch (IOException e) {
+            throw new BuildException("Failed to launch JJTree", e);
+        }
+    }
+
+    private String createOutputFileName(File destFile, String optionalOutputFile,
+                                        String outputDir) {
+        optionalOutputFile = validateOutputFile(optionalOutputFile,
+                                                outputDir);
+        String jjtreeFile = destFile.getAbsolutePath().replace('\\', '/');
+
+        if ((optionalOutputFile == null) || optionalOutputFile.equals("")) {
+            int filePos = jjtreeFile.lastIndexOf("/");
+
+            if (filePos >= 0) {
+                jjtreeFile = jjtreeFile.substring(filePos + 1);
+            }
+
+            int suffixPos = jjtreeFile.lastIndexOf('.');
+
+            if (suffixPos == -1) {
+                optionalOutputFile = jjtreeFile + DEFAULT_SUFFIX;
+            } else {
+                String currentSuffix = jjtreeFile.substring(suffixPos);
+
+                if (currentSuffix.equals(DEFAULT_SUFFIX)) {
+                    optionalOutputFile = jjtreeFile + DEFAULT_SUFFIX;
+                } else {
+                    optionalOutputFile = jjtreeFile.substring(0, suffixPos)
+                        + DEFAULT_SUFFIX;
+                }
+            }
+        }
+
+        if ((outputDir == null) || outputDir.equals("")) {
+            outputDir = getDefaultOutputDirectory();
+        }
+
+        return (outputDir + "/" + optionalOutputFile).replace('\\', '/');
+    }
+
+    /**
+     * When running JJTree from an Ant taskdesk the -OUTPUT_DIRECTORY must
+     * always be set. But when -OUTPUT_DIRECTORY is set, -OUTPUT_FILE is
+     * handled as if relative of this -OUTPUT_DIRECTORY. Thus when the
+     * -OUTPUT_FILE is absolute or contains a drive letter we have a problem.
+     *
+     * @param destFile
+     * @param outputDir
+     * @return
+     * @throws BuildException
+     */
+    private String validateOutputFile(String destFile,
+                                      String outputDir)
+        throws BuildException {
+        if (destFile == null) {
+            return null;
+        }
+
+        if ((outputDir == null)
+            && (destFile.startsWith("/") || destFile.startsWith("\\"))) {
+            String relativeOutputFile = makeOutputFileRelative(destFile);
+            setOutputfile(relativeOutputFile);
+
+            return relativeOutputFile;
+        }
+
+        String root = getRoot(new File(destFile)).getAbsolutePath();
+
+        if ((root.length() > 1)
+            && destFile.startsWith(root.substring(0, root.length() - 1))) {
+            throw new BuildException("Drive letter in 'outputfile' not "
+                                     + "supported: " + destFile);
+        }
+
+        return destFile;
+    }
+
+    private String makeOutputFileRelative(String destFile) {
+        StringBuffer relativePath = new StringBuffer();
+        String defaultOutputDirectory = getDefaultOutputDirectory();
+        int nextPos = defaultOutputDirectory.indexOf('/');
+        int startPos = nextPos + 1;
+
+        while (startPos > -1 && startPos < defaultOutputDirectory.length()) {
+            relativePath.append("/..");
+            nextPos = defaultOutputDirectory.indexOf('/', startPos);
+
+            if (nextPos == -1) {
+                startPos = nextPos;
+            } else {
+                startPos = nextPos + 1;
+            }
+        }
+
+        relativePath.append(destFile);
+
+        return relativePath.toString();
+    }
+
+    private String getDefaultOutputDirectory() {
+        return getProject().getBaseDir().getAbsolutePath().replace('\\', '/');
+    }
+
+    /**
+     * Determine root directory for a given file.
+     *
+     * @param file
+     * @return file's root directory
+     */
+    private File getRoot(File file) {
+        File root = file.getAbsoluteFile();
+
+        while (root.getParent() != null) {
+            root = root.getParentFile();
+        }
+
+        return root;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java
new file mode 100644
index 0000000..9df3d91
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javacc/JavaCC.java
@@ -0,0 +1,556 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javacc;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * JavaCC compiler compiler task.
+ *
+ */
+public class JavaCC extends Task {
+
+    // keys to optional attributes
+    private static final String LOOKAHEAD              = "LOOKAHEAD";
+    private static final String CHOICE_AMBIGUITY_CHECK = "CHOICE_AMBIGUITY_CHECK";
+    private static final String OTHER_AMBIGUITY_CHECK  = "OTHER_AMBIGUITY_CHECK";
+
+    private static final String STATIC                 = "STATIC";
+    private static final String DEBUG_PARSER           = "DEBUG_PARSER";
+    private static final String DEBUG_LOOKAHEAD        = "DEBUG_LOOKAHEAD";
+    private static final String DEBUG_TOKEN_MANAGER    = "DEBUG_TOKEN_MANAGER";
+    private static final String OPTIMIZE_TOKEN_MANAGER = "OPTIMIZE_TOKEN_MANAGER";
+    private static final String ERROR_REPORTING        = "ERROR_REPORTING";
+    private static final String JAVA_UNICODE_ESCAPE    = "JAVA_UNICODE_ESCAPE";
+    private static final String UNICODE_INPUT          = "UNICODE_INPUT";
+    private static final String IGNORE_CASE            = "IGNORE_CASE";
+    private static final String COMMON_TOKEN_ACTION    = "COMMON_TOKEN_ACTION";
+    private static final String USER_TOKEN_MANAGER     = "USER_TOKEN_MANAGER";
+    private static final String USER_CHAR_STREAM       = "USER_CHAR_STREAM";
+    private static final String BUILD_PARSER           = "BUILD_PARSER";
+    private static final String BUILD_TOKEN_MANAGER    = "BUILD_TOKEN_MANAGER";
+    private static final String SANITY_CHECK           = "SANITY_CHECK";
+    private static final String FORCE_LA_CHECK         = "FORCE_LA_CHECK";
+    private static final String CACHE_TOKENS           = "CACHE_TOKENS";
+    private static final String KEEP_LINE_COLUMN       = "KEEP_LINE_COLUMN";
+    private static final String JDK_VERSION            = "JDK_VERSION";
+
+    private final Hashtable optionalAttrs = new Hashtable();
+
+    // required attributes
+    private File outputDirectory = null;
+    private File targetFile      = null;
+    private File javaccHome      = null;
+
+    private CommandlineJava cmdl = new CommandlineJava();
+
+    protected static final int TASKDEF_TYPE_JAVACC = 1;
+    protected static final int TASKDEF_TYPE_JJTREE = 2;
+    protected static final int TASKDEF_TYPE_JJDOC = 3;
+
+    protected static final String[] ARCHIVE_LOCATIONS =
+        new String[] {
+            "JavaCC.zip",
+            "bin/lib/JavaCC.zip",
+            "bin/lib/javacc.jar",
+            "javacc.jar", // used by jpackage for JavaCC 3.x
+        };
+
+    protected static final int[] ARCHIVE_LOCATIONS_VS_MAJOR_VERSION =
+        new int[] {
+            1,
+            2,
+            3,
+            3,
+        };
+
+    protected static final String COM_PACKAGE = "COM.sun.labs.";
+    protected static final String COM_JAVACC_CLASS = "javacc.Main";
+    protected static final String COM_JJTREE_CLASS = "jjtree.Main";
+    protected static final String COM_JJDOC_CLASS = "jjdoc.JJDocMain";
+
+    protected static final String ORG_PACKAGE_3_0 = "org.netbeans.javacc.";
+    protected static final String ORG_PACKAGE_3_1 = "org.javacc.";
+    protected static final String ORG_JAVACC_CLASS = "parser.Main";
+    protected static final String ORG_JJTREE_CLASS = COM_JJTREE_CLASS;
+    protected static final String ORG_JJDOC_CLASS = COM_JJDOC_CLASS;
+
+    /**
+     * Sets the LOOKAHEAD grammar option.
+     * @param lookahead an <code>int</code> value.
+     */
+    public void setLookahead(int lookahead) {
+        optionalAttrs.put(LOOKAHEAD, new Integer(lookahead));
+    }
+
+    /**
+     * Sets the CHOICE_AMBIGUITY_CHECK grammar option.
+     * @param choiceAmbiguityCheck an <code>int</code> value.
+     */
+    public void setChoiceambiguitycheck(int choiceAmbiguityCheck) {
+        optionalAttrs.put(CHOICE_AMBIGUITY_CHECK, new Integer(choiceAmbiguityCheck));
+    }
+
+    /**
+     * Sets the OTHER_AMBIGUITY_CHECK grammar option.
+     * @param otherAmbiguityCheck an <code>int</code> value.
+     */
+    public void setOtherambiguityCheck(int otherAmbiguityCheck) {
+        optionalAttrs.put(OTHER_AMBIGUITY_CHECK, new Integer(otherAmbiguityCheck));
+    }
+
+    /**
+     * Sets the STATIC grammar option.
+     * @param staticParser a <code>boolean</code> value.
+     */
+    public void setStatic(boolean staticParser) {
+        optionalAttrs.put(STATIC, staticParser ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the DEBUG_PARSER grammar option.
+     * @param debugParser a <code>boolean</code> value.
+     */
+    public void setDebugparser(boolean debugParser) {
+        optionalAttrs.put(DEBUG_PARSER, debugParser ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the DEBUG_LOOKAHEAD grammar option.
+     * @param debugLookahead a <code>boolean</code> value.
+     */
+    public void setDebuglookahead(boolean debugLookahead) {
+        optionalAttrs.put(DEBUG_LOOKAHEAD, debugLookahead ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the DEBUG_TOKEN_MANAGER grammar option.
+     * @param debugTokenManager a <code>boolean</code> value.
+     */
+    public void setDebugtokenmanager(boolean debugTokenManager) {
+        optionalAttrs.put(DEBUG_TOKEN_MANAGER, debugTokenManager ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the OPTIMIZE_TOKEN_MANAGER grammar option.
+     * @param optimizeTokenManager a <code>boolean</code> value.
+     */
+    public void setOptimizetokenmanager(boolean optimizeTokenManager) {
+        optionalAttrs.put(OPTIMIZE_TOKEN_MANAGER,
+                          optimizeTokenManager ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the ERROR_REPORTING grammar option.
+     * @param errorReporting a <code>boolean</code> value.
+     */
+    public void setErrorreporting(boolean errorReporting) {
+        optionalAttrs.put(ERROR_REPORTING, errorReporting ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the JAVA_UNICODE_ESCAPE grammar option.
+     * @param javaUnicodeEscape a <code>boolean</code> value.
+     */
+    public void setJavaunicodeescape(boolean javaUnicodeEscape) {
+        optionalAttrs.put(JAVA_UNICODE_ESCAPE, javaUnicodeEscape ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the UNICODE_INPUT grammar option.
+     * @param unicodeInput a <code>boolean</code> value.
+     */
+    public void setUnicodeinput(boolean unicodeInput) {
+        optionalAttrs.put(UNICODE_INPUT, unicodeInput ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the IGNORE_CASE grammar option.
+     * @param ignoreCase a <code>boolean</code> value.
+     */
+    public void setIgnorecase(boolean ignoreCase) {
+        optionalAttrs.put(IGNORE_CASE, ignoreCase ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the COMMON_TOKEN_ACTION grammar option.
+     * @param commonTokenAction a <code>boolean</code> value.
+     */
+    public void setCommontokenaction(boolean commonTokenAction) {
+        optionalAttrs.put(COMMON_TOKEN_ACTION, commonTokenAction ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the USER_TOKEN_MANAGER grammar option.
+     * @param userTokenManager a <code>boolean</code> value.
+     */
+    public void setUsertokenmanager(boolean userTokenManager) {
+        optionalAttrs.put(USER_TOKEN_MANAGER, userTokenManager ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the USER_CHAR_STREAM grammar option.
+     * @param userCharStream a <code>boolean</code> value.
+     */
+    public void setUsercharstream(boolean userCharStream) {
+        optionalAttrs.put(USER_CHAR_STREAM, userCharStream ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the BUILD_PARSER grammar option.
+     * @param buildParser a <code>boolean</code> value.
+     */
+    public void setBuildparser(boolean buildParser) {
+        optionalAttrs.put(BUILD_PARSER, buildParser ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the BUILD_TOKEN_MANAGER grammar option.
+     * @param buildTokenManager a <code>boolean</code> value.
+     */
+    public void setBuildtokenmanager(boolean buildTokenManager) {
+        optionalAttrs.put(BUILD_TOKEN_MANAGER, buildTokenManager ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the SANITY_CHECK grammar option.
+     * @param sanityCheck a <code>boolean</code> value.
+     */
+    public void setSanitycheck(boolean sanityCheck) {
+        optionalAttrs.put(SANITY_CHECK, sanityCheck ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the FORCE_LA_CHECK grammar option.
+     * @param forceLACheck a <code>boolean</code> value.
+     */
+    public void setForcelacheck(boolean forceLACheck) {
+        optionalAttrs.put(FORCE_LA_CHECK, forceLACheck ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the CACHE_TOKENS grammar option.
+     * @param cacheTokens a <code>boolean</code> value.
+     */
+    public void setCachetokens(boolean cacheTokens) {
+        optionalAttrs.put(CACHE_TOKENS, cacheTokens ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the KEEP_LINE_COLUMN grammar option.
+     * @param keepLineColumn a <code>boolean</code> value.
+     */
+    public void setKeeplinecolumn(boolean keepLineColumn) {
+        optionalAttrs.put(KEEP_LINE_COLUMN, keepLineColumn ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Sets the JDK_VERSION option.
+     * @param jdkVersion the version to use.
+     * @since Ant1.7
+     */
+    public void setJDKversion(String jdkVersion) {
+        optionalAttrs.put(JDK_VERSION, jdkVersion);
+    }
+
+    /**
+     * The directory to write the generated files to.
+     * If not set, the files are written to the directory
+     * containing the grammar file.
+     * @param outputDirectory the output directory.
+     */
+    public void setOutputdirectory(File outputDirectory) {
+        this.outputDirectory = outputDirectory;
+    }
+
+    /**
+     * The grammar file to process.
+     * @param targetFile the grammar file.
+     */
+    public void setTarget(File targetFile) {
+        this.targetFile = targetFile;
+    }
+
+    /**
+     * The directory containing the JavaCC distribution.
+     * @param javaccHome the directory.
+     */
+    public void setJavacchome(File javaccHome) {
+        this.javaccHome = javaccHome;
+    }
+
+    /**
+     * Constructor
+     */
+    public JavaCC() {
+        cmdl.setVm(JavaEnvUtils.getJreExecutable("java"));
+    }
+
+    /**
+     * Run the task.
+     * @throws BuildException on error.
+     */
+    public void execute() throws BuildException {
+
+        // load command line with optional attributes
+        Enumeration iter = optionalAttrs.keys();
+        while (iter.hasMoreElements()) {
+            String name  = (String) iter.nextElement();
+            Object value = optionalAttrs.get(name);
+            cmdl.createArgument().setValue("-" + name + ":" + value.toString());
+        }
+
+        // check the target is a file
+        if (targetFile == null || !targetFile.isFile()) {
+            throw new BuildException("Invalid target: " + targetFile);
+        }
+
+        // use the directory containing the target as the output directory
+        if (outputDirectory == null) {
+            outputDirectory = new File(targetFile.getParent());
+        } else if (!outputDirectory.isDirectory()) {
+            throw new BuildException("Outputdir not a directory.");
+        }
+        cmdl.createArgument().setValue("-OUTPUT_DIRECTORY:"
+                                       + outputDirectory.getAbsolutePath());
+
+        // determine if the generated java file is up-to-date
+        final File javaFile = getOutputJavaFile(outputDirectory, targetFile);
+        if (javaFile.exists() && targetFile.lastModified() < javaFile.lastModified()) {
+            log("Target is already built - skipping (" + targetFile + ")", Project.MSG_VERBOSE);
+            return;
+        }
+        cmdl.createArgument().setValue(targetFile.getAbsolutePath());
+
+        final Path classpath = cmdl.createClasspath(getProject());
+        final File javaccJar = JavaCC.getArchiveFile(javaccHome);
+        classpath.createPathElement().setPath(javaccJar.getAbsolutePath());
+        classpath.addJavaRuntime();
+
+        cmdl.setClassname(JavaCC.getMainClass(classpath,
+                                              JavaCC.TASKDEF_TYPE_JAVACC));
+
+        final Commandline.Argument arg = cmdl.createVmArgument();
+        arg.setValue("-mx140M");
+        arg.setValue("-Dinstall.root=" + javaccHome.getAbsolutePath());
+
+        Execute.runCommand(this, cmdl.getCommandline());
+    }
+
+    /**
+     * Helper method to retrieve the path used to store the JavaCC.zip
+     * or javacc.jar which is different from versions.
+     *
+     * @param home the javacc home path directory.
+     * @throws BuildException thrown if the home directory is invalid
+     * or if the archive could not be found despite attempts to do so.
+     * @return the file object pointing to the JavaCC archive.
+     */
+    protected static File getArchiveFile(File home) throws BuildException {
+        return new File(home,
+                        ARCHIVE_LOCATIONS[getArchiveLocationIndex(home)]);
+    }
+
+    /**
+     * Helper method to retrieve main class which is different from versions.
+     * @param home the javacc home path directory.
+     * @param type the taskdef.
+     * @throws BuildException thrown if the home directory is invalid
+     * or if the archive could not be found despite attempts to do so.
+     * @return the main class for the taskdef.
+     */
+    protected static String getMainClass(File home, int type)
+        throws BuildException {
+
+        Path p = new Path(null);
+        p.createPathElement().setLocation(getArchiveFile(home));
+        p.addJavaRuntime();
+        return getMainClass(p, type);
+    }
+
+    /**
+     * Helper method to retrieve main class which is different from versions.
+     * @param path classpath to search in.
+     * @param type the taskdef.
+     * @throws BuildException thrown if the home directory is invalid
+     * or if the archive could not be found despite attempts to do so.
+     * @return the main class for the taskdef.
+     * @since Ant 1.7
+     */
+    protected static String getMainClass(Path path, int type)
+        throws BuildException {
+        String packagePrefix = null;
+        String mainClass = null;
+
+        AntClassLoader l = new AntClassLoader();
+        l.setClassPath(path.concatSystemClasspath("ignore"));
+        String javaccClass = COM_PACKAGE + COM_JAVACC_CLASS;
+        InputStream is = l.getResourceAsStream(javaccClass.replace('.', '/')
+                                               + ".class");
+        if (is != null) {
+            packagePrefix = COM_PACKAGE;
+            switch (type) {
+            case TASKDEF_TYPE_JAVACC:
+                mainClass = COM_JAVACC_CLASS;
+
+                break;
+
+            case TASKDEF_TYPE_JJTREE:
+                mainClass = COM_JJTREE_CLASS;
+
+                break;
+
+            case TASKDEF_TYPE_JJDOC:
+                mainClass = COM_JJDOC_CLASS;
+
+                break;
+            default:
+                // Fall Through
+            }
+        } else {
+            javaccClass = ORG_PACKAGE_3_1 + ORG_JAVACC_CLASS;
+            is = l.getResourceAsStream(javaccClass.replace('.', '/')
+                                       + ".class");
+            if (is != null) {
+                packagePrefix = ORG_PACKAGE_3_1;
+            } else {
+                javaccClass = ORG_PACKAGE_3_0 + ORG_JAVACC_CLASS;
+                is = l.getResourceAsStream(javaccClass.replace('.', '/')
+                                           + ".class");
+                if (is != null) {
+                    packagePrefix = ORG_PACKAGE_3_0;
+                }
+            }
+
+            if (is != null) {
+                switch (type) {
+                case TASKDEF_TYPE_JAVACC:
+                    mainClass = ORG_JAVACC_CLASS;
+
+                break;
+
+                case TASKDEF_TYPE_JJTREE:
+                    mainClass = ORG_JJTREE_CLASS;
+
+                    break;
+
+                case TASKDEF_TYPE_JJDOC:
+                    mainClass = ORG_JJDOC_CLASS;
+
+                    break;
+                default:
+                    // Fall Through
+                }
+            }
+        }
+
+        if (packagePrefix == null) {
+            throw new BuildException("failed to load JavaCC");
+        }
+        if (mainClass == null) {
+            throw new BuildException("unknown task type " + type);
+        }
+        return packagePrefix + mainClass;
+    }
+
+    /**
+     * Helper method to determine the archive location index.
+     *
+     * @param home the javacc home path directory.
+     * @throws BuildException thrown if the home directory is invalid
+     * or if the archive could not be found despite attempts to do so.
+     * @return the archive location index
+     */
+    private static int getArchiveLocationIndex(File home)
+        throws BuildException {
+
+        if (home == null || !home.isDirectory()) {
+            throw new BuildException("JavaCC home must be a valid directory.");
+        }
+
+        for (int i = 0; i < ARCHIVE_LOCATIONS.length; i++) {
+            File f = new File(home, ARCHIVE_LOCATIONS[i]);
+
+            if (f.exists()) {
+                return i;
+            }
+        }
+
+        throw new BuildException("Could not find a path to JavaCC.zip "
+                                 + "or javacc.jar from '" + home + "'.");
+    }
+
+    /**
+     * Helper method to determine the major version number of JavaCC.
+     *
+     * @param home the javacc home path directory.
+     * @throws BuildException thrown if the home directory is invalid
+     * or if the archive could not be found despite attempts to do so.
+     * @return a the major version number
+     */
+    protected static int getMajorVersionNumber(File home)
+        throws BuildException {
+
+        return
+            ARCHIVE_LOCATIONS_VS_MAJOR_VERSION[getArchiveLocationIndex(home)];
+    }
+
+    /**
+     * Determines the output Java file to be generated by the given grammar
+     * file.
+     *
+     */
+    private File getOutputJavaFile(File outputdir, File srcfile) {
+        String path = srcfile.getPath();
+
+        // Extract file's base-name
+        int startBasename = path.lastIndexOf(File.separator);
+        if (startBasename != -1) {
+            path = path.substring(startBasename + 1);
+        }
+
+        // Replace the file's extension with '.java'
+        int startExtn = path.lastIndexOf('.');
+        if (startExtn != -1) {
+            path = path.substring(0, startExtn) + ".java";
+        } else {
+            path += ".java";
+        }
+
+        // Change the directory
+        if (outputdir != null) {
+            path = outputdir + File.separator + path;
+        }
+
+        return new File(path);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java
new file mode 100644
index 0000000..121fa42
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapter.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+
+/**
+ * Interface for different backend implementations of the Javah task.
+ *
+ * @since Ant 1.6.3
+ */
+public interface JavahAdapter {
+    /**
+     * Performs the actual compilation.
+     * @param javah the calling javah task.
+     * @return true if the compilation was successful.
+     * @throws BuildException if there is an error.
+     * @since Ant 1.6.3
+     */
+    boolean compile(Javah javah) throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java
new file mode 100644
index 0000000..ad3aa87
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/JavahAdapterFactory.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Creates the JavahAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class JavahAdapterFactory {
+
+    /**
+     * Determines the default choice of adapter based on the VM
+     * vendor.
+     *
+     * @return the default choice of adapter based on the VM
+     * vendor
+     */
+    public static String getDefault() {
+        if (JavaEnvUtils.isKaffe()) {
+            return Kaffeh.IMPLEMENTATION_NAME;
+        }
+        return SunJavah.IMPLEMENTATION_NAME;
+    }
+
+    /**
+     * Creates the JavahAdapter based on the user choice and
+     * potentially the VM vendor.
+     *
+     * @param choice the user choice (if any).
+     * @param log a ProjectComponent instance used to access Ant's
+     * logging system.
+     * @return The adapter to use.
+     * @throws BuildException if there is an error.
+     */
+    public static JavahAdapter getAdapter(String choice,
+                                          ProjectComponent log)
+        throws BuildException {
+        if ((JavaEnvUtils.isKaffe() && choice == null)
+            || Kaffeh.IMPLEMENTATION_NAME.equals(choice)) {
+            return new Kaffeh();
+        } else if (SunJavah.IMPLEMENTATION_NAME.equals(choice)) {
+            return new SunJavah();
+        } else if (choice != null) {
+            return resolveClassName(choice);
+        }
+
+        // This default has been good enough until Ant 1.6.3, so stick
+        // with it
+        return new SunJavah();
+    }
+
+    /**
+     * Tries to resolve the given classname into a javah adapter.
+     * Throws a fit if it can't.
+     *
+     * @param className The fully qualified classname to be created.
+     * @throws BuildException This is the fit that is thrown if className
+     * isn't an instance of JavahAdapter.
+     */
+    private static JavahAdapter resolveClassName(String className)
+            throws BuildException {
+        return (JavahAdapter) ClasspathUtils.newInstance(className,
+                JavahAdapterFactory.class.getClassLoader(), JavahAdapter.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java
new file mode 100644
index 0000000..d37f771
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/Kaffeh.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Adapter to the native kaffeh compiler.
+ *
+ * @since Ant 1.6.3
+ */
+public class Kaffeh implements JavahAdapter {
+
+    /** the name of the javah adapter - kaffeh */
+    public static final String IMPLEMENTATION_NAME = "kaffeh";
+
+    /**
+     * Performs the actual compilation.
+     * @param javah the calling javah task.
+     * @return true if the compilation was successful.
+     * @throws BuildException if there is an error.
+     * @since Ant 1.6.3
+     */
+    public boolean compile(Javah javah) throws BuildException {
+        Commandline cmd = setupKaffehCommand(javah);
+        try {
+            Execute.runCommand(javah, cmd.getCommandline());
+            return true;
+        } catch (BuildException e) {
+            if (e.getMessage().indexOf("failed with return code") == -1) {
+                throw e;
+            }
+        }
+        return false;
+    }
+
+    private Commandline setupKaffehCommand(Javah javah) {
+        Commandline cmd = new Commandline();
+        cmd.setExecutable(JavaEnvUtils.getJdkExecutable("kaffeh"));
+
+        if (javah.getDestdir() != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(javah.getDestdir());
+        }
+
+        if (javah.getOutputfile() != null) {
+            cmd.createArgument().setValue("-o");
+            cmd.createArgument().setFile(javah.getOutputfile());
+        }
+
+        Path cp = new Path(javah.getProject());
+        if (javah.getBootclasspath() != null) {
+            cp.append(javah.getBootclasspath());
+        }
+        cp = cp.concatSystemBootClasspath("ignore");
+        if (javah.getClasspath() != null) {
+            cp.append(javah.getClasspath());
+        }
+        if (cp.size() > 0) {
+            cmd.createArgument().setValue("-classpath");
+            cmd.createArgument().setPath(cp);
+        }
+
+        if (!javah.getOld()) {
+            cmd.createArgument().setValue("-jni");
+        }
+
+        cmd.addArguments(javah.getCurrentArgs());
+
+        javah.logAndAddFiles(cmd);
+        return cmd;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java
new file mode 100644
index 0000000..0b1655a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/javah/SunJavah.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.javah;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.launch.Locator;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.taskdefs.optional.Javah;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+
+/**
+ * Adapter to com.sun.tools.javah.oldjavah.Main or com.sun.tools.javah.Main.
+ *
+ * @since Ant 1.6.3
+ */
+public class SunJavah implements JavahAdapter {
+
+    /** the name of the javah adapter - sun */
+    public static final String IMPLEMENTATION_NAME = "sun";
+
+    /**
+     * Performs the actual compilation.
+     * @param javah the calling javah task.
+     * @return true if the compilation was successful.
+     * @throws BuildException if there is an error.
+     * @since Ant 1.6.3
+     */
+    public boolean compile(Javah javah) throws BuildException {
+        Commandline cmd = setupJavahCommand(javah);
+        ExecuteJava ej = new ExecuteJava();
+        Class c = null;
+        try {
+            try {
+                // first search for the "old" javah class in 1.4.2 tools.jar
+                c = Class.forName("com.sun.tools.javah.oldjavah.Main");
+            } catch (ClassNotFoundException cnfe) {
+                // assume older than 1.4.2 tools.jar
+                c = Class.forName("com.sun.tools.javah.Main");
+            }
+        } catch (ClassNotFoundException ex) {
+            throw new BuildException(
+                "Can't load javah", ex, javah.getLocation());
+        }
+        cmd.setExecutable(c.getName());
+        ej.setJavaCommand(cmd);
+        File f = Locator.getClassSource(c);
+        if (f != null) {
+            ej.setClasspath(new Path(javah.getProject(), f.getPath()));
+        }
+        return ej.fork(javah) == 0;
+    }
+
+    private Commandline setupJavahCommand(Javah javah) {
+        Commandline cmd = new Commandline();
+
+        if (javah.getDestdir() != null) {
+            cmd.createArgument().setValue("-d");
+            cmd.createArgument().setFile(javah.getDestdir());
+        }
+
+        if (javah.getOutputfile() != null) {
+            cmd.createArgument().setValue("-o");
+            cmd.createArgument().setFile(javah.getOutputfile());
+        }
+
+        if (javah.getClasspath() != null) {
+            cmd.createArgument().setValue("-classpath");
+            cmd.createArgument().setPath(javah.getClasspath());
+        }
+
+        if (javah.getVerbose()) {
+            cmd.createArgument().setValue("-verbose");
+        }
+        if (javah.getOld()) {
+            cmd.createArgument().setValue("-old");
+        }
+        if (javah.getForce()) {
+            cmd.createArgument().setValue("-force");
+        }
+        if (javah.getStubs() && !javah.getOld()) {
+            throw new BuildException(
+                "stubs only available in old mode.", javah.getLocation());
+        }
+
+        if (javah.getStubs()) {
+            cmd.createArgument().setValue("-stubs");
+        }
+        Path bcp = new Path(javah.getProject());
+        if (javah.getBootclasspath() != null) {
+            bcp.append(javah.getBootclasspath());
+        }
+        bcp = bcp.concatSystemBootClasspath("ignore");
+        if (bcp.size() > 0) {
+            cmd.createArgument().setValue("-bootclasspath");
+            cmd.createArgument().setPath(bcp);
+        }
+
+        cmd.addArguments(javah.getCurrentArgs());
+
+        javah.logAndAddFiles(cmd);
+        return cmd;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java
new file mode 100644
index 0000000..8d65470
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTask.java
@@ -0,0 +1,679 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jdepend;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Vector;
+import java.util.Enumeration;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+
+/**
+ * Runs JDepend tests.
+ *
+ * <p>JDepend is a tool to generate design quality metrics for each Java package.
+ * It has been initially created by Mike Clark. JDepend can be found at <a
+ * href="http://www.clarkware.com/software/JDepend.html">http://www.clarkware.com/software/JDepend.html</a>.
+ *
+ * The current implementation spawn a new Java VM.
+ *
+ */
+public class JDependTask extends Task {
+    //private CommandlineJava commandline = new CommandlineJava();
+
+    // required attributes
+    private Path sourcesPath; // Deprecated!
+    private Path classesPath; // Use this going forward
+
+    // optional attributes
+    private File outputFile;
+    private File dir;
+    private Path compileClasspath;
+    private boolean haltonerror = false;
+    private boolean fork = false;
+    private Long timeout = null;
+
+    private String jvm = null;
+    private String format = "text";
+    private PatternSet defaultPatterns = new PatternSet();
+
+    private static Constructor packageFilterC;
+    private static Method setFilter;
+
+    private boolean includeRuntime = false;
+    private Path runtimeClasses = null;
+
+    static {
+        try {
+            Class packageFilter =
+                Class.forName("jdepend.framework.PackageFilter");
+            packageFilterC =
+                packageFilter.getConstructor(new Class[] {java.util.Collection.class});
+            setFilter =
+                jdepend.textui.JDepend.class.getDeclaredMethod("setFilter",
+                                                               new Class[] {packageFilter});
+        } catch (Throwable t) {
+            if (setFilter == null) {
+                packageFilterC = null;
+            }
+        }
+    }
+
+    /**
+     * If true,
+     *  include jdepend.jar in the forked VM.
+     *
+     * @param b include ant run time yes or no
+     * @since Ant 1.6
+     */
+    public void setIncluderuntime(boolean b) {
+        includeRuntime = b;
+    }
+
+    /**
+     * Set the timeout value (in milliseconds).
+     *
+     * <p>If the operation is running for more than this value, the jdepend
+     * will be canceled. (works only when in 'fork' mode).</p>
+     * @param value the maximum time (in milliseconds) allowed before
+     * declaring the test as 'timed-out'
+     * @see #setFork(boolean)
+     */
+    public void setTimeout(Long value) {
+        timeout = value;
+    }
+
+    /**
+     * @return the timeout value
+     */
+    public Long getTimeout() {
+        return timeout;
+    }
+
+    /**
+     * The output file name.
+     *
+     * @param outputFile the output file name
+     */
+    public void setOutputFile(File outputFile) {
+        this.outputFile = outputFile;
+    }
+
+    /**
+     * @return the output file name
+     */
+    public File getOutputFile() {
+        return outputFile;
+    }
+
+    /**
+     * Whether or not to halt on failure. Default: false.
+     * @param haltonerror the value to set
+     */
+    public void setHaltonerror(boolean haltonerror) {
+        this.haltonerror = haltonerror;
+    }
+
+    /**
+     * @return the value of the haltonerror attribute
+     */
+    public boolean getHaltonerror() {
+        return haltonerror;
+    }
+
+    /**
+     * If true, forks into a new JVM. Default: false.
+     *
+     * @param   value   <tt>true</tt> if a JVM should be forked,
+     *                  otherwise <tt>false<tt>
+     */
+    public void setFork(boolean value) {
+        fork = value;
+    }
+
+    /**
+     * @return the value of the fork attribute
+     */
+    public boolean getFork() {
+        return fork;
+    }
+
+    /**
+     * The command used to invoke a forked Java Virtual Machine.
+     *
+     * Default is <tt>java</tt>. Ignored if no JVM is forked.
+     * @param   value   the new VM to use instead of <tt>java</tt>
+     * @see #setFork(boolean)
+     */
+    public void setJvm(String value) {
+        jvm = value;
+
+    }
+
+    /**
+     * Adds a path to source code to analyze.
+     * @return a source path
+     * @deprecated since 1.6.x.
+     */
+    public Path createSourcespath() {
+        if (sourcesPath == null) {
+            sourcesPath = new Path(getProject());
+        }
+        return sourcesPath.createPath();
+    }
+
+    /**
+     * Gets the sourcepath.
+     * @return the sources path
+     * @deprecated since 1.6.x.
+     */
+    public Path getSourcespath() {
+        return sourcesPath;
+    }
+
+    /**
+     * Adds a path to class code to analyze.
+     * @return a classes path
+     */
+    public Path createClassespath() {
+        if (classesPath == null) {
+            classesPath = new Path(getProject());
+        }
+        return classesPath.createPath();
+    }
+
+    /**
+     * Gets the classespath.
+     * @return the classes path
+     */
+    public Path getClassespath() {
+        return classesPath;
+    }
+
+    /**
+     * The directory to invoke the VM in. Ignored if no JVM is forked.
+     * @param   dir     the directory to invoke the JVM from.
+     * @see #setFork(boolean)
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * @return the dir attribute
+     */
+    public File getDir() {
+        return dir;
+    }
+
+    /**
+     * Set the classpath to be used for this compilation.
+     * @param classpath a class path to be used
+     */
+    public void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        } else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Gets the classpath to be used for this compilation.
+     * @return the class path used for compilation
+     */
+    public Path getClasspath() {
+        return compileClasspath;
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a classpath
+     */
+    public Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath.createPath();
+    }
+
+    /**
+     * Create a new JVM argument. Ignored if no JVM is forked.
+     * @param commandline the commandline to create the argument on
+     * @return  create a new JVM argument so that any argument can
+     *          be passed to the JVM.
+     * @see #setFork(boolean)
+     */
+    public Commandline.Argument createJvmarg(CommandlineJava commandline) {
+        return commandline.createVmArgument();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere.
+     * @param r a classpath reference
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * add a name entry on the exclude list
+     * @return a pattern for the excludes
+     */
+    public PatternSet.NameEntry createExclude() {
+        return defaultPatterns.createExclude();
+    }
+
+    /**
+     * @return the excludes patterns
+     */
+    public PatternSet getExcludes() {
+        return defaultPatterns;
+    }
+
+    /**
+     * The format to write the output in, "xml" or "text".
+     *
+     * @param ea xml or text
+     */
+    public void setFormat(FormatAttribute ea) {
+        format = ea.getValue();
+    }
+
+    /**
+     * A class for the enumerated attribute format,
+     * values are xml and text.
+     * @see EnumeratedAttribute
+     */
+    public static class FormatAttribute extends EnumeratedAttribute {
+        private String [] formats = new String[]{"xml", "text"};
+
+        /**
+         * @return the enumerated values
+         */
+        public String[] getValues() {
+            return formats;
+        }
+    }
+
+    /**
+     * No problems with this test.
+     */
+    private static final int SUCCESS = 0;
+    /**
+     * An error occurred.
+     */
+    private static final int ERRORS = 1;
+
+    /**
+     * Search for the given resource and add the directory or archive
+     * that contains it to the classpath.
+     *
+     * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+     * getResource doesn't contain the name of the archive.</p>
+     *
+     * @param resource resource that one wants to lookup
+     * @since Ant 1.6
+     */
+    private void addClasspathEntry(String resource) {
+        /*
+         * pre Ant 1.6 this method used to call getClass().getResource
+         * while Ant 1.6 will call ClassLoader.getResource().
+         *
+         * The difference is that Class.getResource expects a leading
+         * slash for "absolute" resources and will strip it before
+         * delegating to ClassLoader.getResource - so we now have to
+         * emulate Class's behavior.
+         */
+        if (resource.startsWith("/")) {
+            resource = resource.substring(1);
+        } else {
+            resource = "org/apache/tools/ant/taskdefs/optional/jdepend/"
+                + resource;
+        }
+
+        File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
+                                               resource);
+        if (f != null) {
+            log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+            runtimeClasses.createPath().setLocation(f);
+        } else {
+            log("Couldn\'t find " + resource, Project.MSG_DEBUG);
+        }
+    }
+
+    /**
+     * execute the task
+     *
+     * @exception BuildException if an error occurs
+     */
+    public void execute() throws BuildException {
+
+        CommandlineJava commandline = new CommandlineJava();
+
+        if ("text".equals(format)) {
+            commandline.setClassname("jdepend.textui.JDepend");
+        } else
+            if ("xml".equals(format)) {
+                commandline.setClassname("jdepend.xmlui.JDepend");
+            }
+
+        if (jvm != null) {
+            commandline.setVm(jvm);
+        }
+        if (getSourcespath() == null && getClassespath() == null) {
+            throw new BuildException("Missing classespath required argument");
+        } else if (getClassespath() == null) {
+            String msg =
+                "sourcespath is deprecated in JDepend >= 2.5 "
+                + "- please convert to classespath";
+            log(msg);
+        }
+
+        // execute the test and get the return code
+        int exitValue = JDependTask.ERRORS;
+        boolean wasKilled = false;
+        if (!getFork()) {
+            exitValue = executeInVM(commandline);
+        } else {
+            ExecuteWatchdog watchdog = createWatchdog();
+            exitValue = executeAsForked(commandline, watchdog);
+            // null watchdog means no timeout, you'd better not check with null
+            if (watchdog != null) {
+                wasKilled = watchdog.killedProcess();
+            }
+        }
+
+        // if there is an error/failure and that it should halt, stop
+        // everything otherwise just log a statement
+        boolean errorOccurred = exitValue == JDependTask.ERRORS || wasKilled;
+
+        if (errorOccurred) {
+            String errorMessage = "JDepend FAILED"
+                + (wasKilled ? " - Timed out" : "");
+
+            if  (getHaltonerror()) {
+                throw new BuildException(errorMessage, getLocation());
+            } else {
+                log(errorMessage, Project.MSG_ERR);
+            }
+        }
+    }
+
+    // this comment extract from JUnit Task may also apply here
+    // "in VM is not very nice since it could probably hang the
+    // whole build. IMHO this method should be avoided and it would be best
+    // to remove it in future versions. TBD. (SBa)"
+
+    /**
+     * Execute inside VM.
+     *
+     * @param commandline the command line
+     * @return the return value of the mvm
+     * @exception BuildException if an error occurs
+     */
+    public int executeInVM(CommandlineJava commandline) throws BuildException {
+        jdepend.textui.JDepend jdepend;
+
+        if ("xml".equals(format)) {
+            jdepend = new jdepend.xmlui.JDepend();
+        } else {
+            jdepend = new jdepend.textui.JDepend();
+        }
+
+        FileWriter fw = null;
+        if (getOutputFile() != null) {
+            try {
+                fw = new FileWriter(getOutputFile().getPath());
+            } catch (IOException e) {
+                String msg = "JDepend Failed when creating the output file: "
+                    + e.getMessage();
+                log(msg);
+                throw new BuildException(msg);
+            }
+            jdepend.setWriter(new PrintWriter(fw));
+            log("Output to be stored in " + getOutputFile().getPath());
+        }
+
+
+        try {
+            if (getClassespath() != null) {
+                // This is the new, better way - use classespath instead
+                // of sourcespath.  The code is currently the same - you
+                // need class files in a directory to use this or jar files.
+                String[] cP = getClassespath().list();
+                for (int i = 0; i < cP.length; i++) {
+                    File f = new File(cP[i]);
+                    // not necessary as JDepend would fail, but why loose
+                    // some time?
+                    if (!f.exists()) {
+                        String msg = "\""
+                            + f.getPath()
+                            + "\" does not represent a valid"
+                            + " file or directory. JDepend would fail.";
+                        log(msg);
+                        throw new BuildException(msg);
+                    }
+                    try {
+                        jdepend.addDirectory(f.getPath());
+                    } catch (IOException e) {
+                        String msg =
+                            "JDepend Failed when adding a class directory: "
+                            + e.getMessage();
+                        log(msg);
+                        throw new BuildException(msg);
+                    }
+                }
+
+            } else if (getSourcespath() != null) {
+
+                // This is the old way and is deprecated - classespath is
+                // the right way to do this and is above
+                String[] sP = getSourcespath().list();
+                for (int i = 0; i < sP.length; i++) {
+                    File f = new File(sP[i]);
+
+                    // not necessary as JDepend would fail, but why loose
+                    // some time?
+                    if (!f.exists() || !f.isDirectory()) {
+                        String msg = "\""
+                            + f.getPath()
+                            + "\" does not represent a valid"
+                            + " directory. JDepend would fail.";
+                        log(msg);
+                        throw new BuildException(msg);
+                    }
+                    try {
+                        jdepend.addDirectory(f.getPath());
+                    } catch (IOException e) {
+                        String msg =
+                            "JDepend Failed when adding a source directory: "
+                            + e.getMessage();
+                        log(msg);
+                        throw new BuildException(msg);
+                    }
+                }
+            }
+
+            // This bit turns <exclude> child tags into patters to ignore
+            String[] patterns = defaultPatterns.getExcludePatterns(getProject());
+            if (patterns != null && patterns.length > 0) {
+                if (setFilter != null) {
+                    Vector v = new Vector();
+                    for (int i = 0; i < patterns.length; i++) {
+                        v.addElement(patterns[i]);
+                    }
+                    try {
+                        Object o = packageFilterC.newInstance(new Object[] {v});
+                        setFilter.invoke(jdepend, new Object[] {o});
+                    } catch (Throwable e) {
+                        log("excludes will be ignored as JDepend doesn't like me: "
+                            + e.getMessage(), Project.MSG_WARN);
+                    }
+                } else {
+                    log("Sorry, your version of JDepend doesn't support excludes",
+                        Project.MSG_WARN);
+                }
+            }
+
+            jdepend.analyze();
+        } finally {
+            FileUtils.close(fw);
+        }
+        return SUCCESS;
+    }
+
+
+    /**
+     * Execute the task by forking a new JVM. The command will block until
+     * it finishes. To know if the process was destroyed or not, use the
+     * <tt>killedProcess()</tt> method of the watchdog class.
+     * @param commandline the commandline for forked jvm
+     * @param  watchdog   the watchdog in charge of cancelling the test if it
+     * exceeds a certain amount of time. Can be <tt>null</tt>.
+     * @return the result of running the jdepend
+     * @throws BuildException in case of error
+     */
+    // JL: comment extracted from JUnitTask (and slightly modified)
+    public int executeAsForked(CommandlineJava commandline,
+                               ExecuteWatchdog watchdog) throws BuildException {
+        runtimeClasses = new Path(getProject());
+        addClasspathEntry("/jdepend/textui/JDepend.class");
+
+        // if not set, auto-create the ClassPath from the project
+        createClasspath();
+
+        // not sure whether this test is needed but cost nothing to put.
+        // hope it will be reviewed by anybody competent
+        if (getClasspath().toString().length() > 0) {
+            createJvmarg(commandline).setValue("-classpath");
+            createJvmarg(commandline).setValue(getClasspath().toString());
+        }
+
+        if (includeRuntime) {
+            Vector v = Execute.getProcEnvironment();
+            Enumeration e = v.elements();
+            while (e.hasMoreElements()) {
+                String s = (String) e.nextElement();
+                if (s.startsWith("CLASSPATH=")) {
+                    commandline.createClasspath(getProject()).createPath()
+                        .append(new Path(getProject(),
+                                         s.substring("CLASSPATH=".length()
+                                                     )));
+                }
+            }
+            log("Implicitly adding " + runtimeClasses + " to CLASSPATH",
+                Project.MSG_VERBOSE);
+            commandline.createClasspath(getProject()).createPath()
+                .append(runtimeClasses);
+        }
+
+        if (getOutputFile() != null) {
+            // having a space between the file and its path causes commandline
+            // to add quotes around the argument thus making JDepend not taking
+            // it into account. Thus we split it in two
+            commandline.createArgument().setValue("-file");
+            commandline.createArgument().setValue(outputFile.getPath());
+            // we have to find a cleaner way to put this output
+        }
+
+        if (getSourcespath() != null) {
+            // This is deprecated - use classespath in the future
+            String[] sP = getSourcespath().list();
+            for (int i = 0; i < sP.length; i++) {
+                File f = new File(sP[i]);
+
+                // not necessary as JDepend would fail, but why loose
+                // some time?
+                if (!f.exists() || !f.isDirectory()) {
+                    throw new BuildException("\"" + f.getPath()
+                                             + "\" does not represent a valid"
+                                             + " directory. JDepend would"
+                                             + " fail.");
+                }
+                commandline.createArgument().setValue(f.getPath());
+            }
+        }
+
+        if (getClassespath() != null) {
+            // This is the new way - use classespath - code is the
+            // same for now
+            String[] cP = getClassespath().list();
+            for (int i = 0; i < cP.length; i++) {
+                File f = new File(cP[i]);
+                // not necessary as JDepend would fail, but why loose
+                // some time?
+                if (!f.exists()) {
+                    throw new BuildException("\"" + f.getPath()
+                                             + "\" does not represent a valid"
+                                             + " file or directory. JDepend would"
+                                             + " fail.");
+                }
+                commandline.createArgument().setValue(f.getPath());
+            }
+        }
+
+        Execute execute = new Execute(new LogStreamHandler(this,
+            Project.MSG_INFO, Project.MSG_WARN), watchdog);
+        execute.setCommandline(commandline.getCommandline());
+        if (getDir() != null) {
+            execute.setWorkingDirectory(getDir());
+            execute.setAntRun(getProject());
+        }
+
+        if (getOutputFile() != null) {
+            log("Output to be stored in " + getOutputFile().getPath());
+        }
+        log(commandline.describeCommand(), Project.MSG_VERBOSE);
+        try {
+            return execute.execute();
+        } catch (IOException e) {
+            throw new BuildException("Process fork failed.", e, getLocation());
+        }
+    }
+
+    /**
+     * @return <tt>null</tt> if there is a timeout value, otherwise the
+     * watchdog instance.
+     * @throws BuildException in case of error
+     */
+    protected ExecuteWatchdog createWatchdog() throws BuildException {
+        if (getTimeout() == null) {
+            return null;
+        }
+        return new ExecuteWatchdog(getTimeout().longValue());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
new file mode 100644
index 0000000..20e9fc5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/ClassNameReader.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Reads just enough of a class file to determine the class' full name.
+ *
+ * <p>Extremely minimal constant pool implementation, mainly to support extracting
+ * strings from a class file.
+ */
+class ConstantPool {
+    // CheckStyle:VisibilityModifier OFF - bc
+    static final
+        byte UTF8 = 1, UNUSED = 2, INTEGER = 3, FLOAT = 4, LONG = 5, DOUBLE = 6,
+        CLASS = 7, STRING = 8, FIELDREF = 9, METHODREF = 10,
+        INTERFACEMETHODREF = 11, NAMEANDTYPE = 12;
+
+    byte[] types;
+
+    Object[] values;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Create a constant pool.
+     * @param data the data input containing the class.
+     * @throws IOException if there is an error.
+     */
+    ConstantPool(DataInput data) throws IOException {
+        super();
+
+        int count = data.readUnsignedShort();
+        types = new byte [ count ];
+        values = new Object [ count ];
+        // read in all constant pool entries.
+        for (int i = 1; i < count; i++) {
+            byte type = data.readByte();
+            types[i] = type;
+            switch (type) {
+            case UTF8 :
+                values[i] = data.readUTF();
+                break;
+
+            case UNUSED :
+                break;
+
+            case INTEGER :
+                values[i] = new Integer(data.readInt());
+                break;
+
+            case FLOAT :
+                values[i] = new Float(data.readFloat());
+                break;
+
+            case LONG :
+                values[i] = new Long(data.readLong());
+                ++i;
+                break;
+
+            case DOUBLE :
+                values[i] = new Double(data.readDouble());
+                ++i;
+                break;
+
+            case CLASS :
+            case STRING :
+                values[i] = new Integer(data.readUnsignedShort());
+                break;
+
+            case FIELDREF :
+            case METHODREF :
+            case INTERFACEMETHODREF :
+            case NAMEANDTYPE :
+                values[i] = new Integer(data.readInt());
+                break;
+            default:
+                // Do nothing
+            }
+        }
+    }
+}
+
+/**
+ * Provides a quick and dirty way to determine the true name of a class
+ * given just an InputStream. Reads in just enough to perform this
+ * minimal task only.
+ */
+public class ClassNameReader extends Object {
+    private static final int CLASS_MAGIC_NUMBER =  0xCAFEBABE;
+
+    /**
+     * Get the class name of a class in an input stream.
+     *
+     * @param input an <code>InputStream</code> value
+     * @return the name of the class
+     * @exception IOException if an error occurs
+     */
+    public static String getClassName(InputStream input) throws IOException {
+        DataInputStream data = new DataInputStream(input);
+        // verify this is a valid class file.
+        int cookie = data.readInt();
+        if (cookie != CLASS_MAGIC_NUMBER) {
+            return null;
+        }
+        /* int version = */ data.readInt();
+        // read the constant pool.
+        ConstantPool constants = new ConstantPool(data);
+        Object[] values = constants.values;
+        // read access flags and class index.
+        /* int accessFlags = */ data.readUnsignedShort();
+        int classIndex = data.readUnsignedShort();
+        Integer stringIndex = (Integer) values[classIndex];
+        String className = (String) values[stringIndex.intValue()];
+        return className;
+    }
+
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
new file mode 100644
index 0000000..7f9f400
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/JlinkTask.java
@@ -0,0 +1,182 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * This class defines objects that can link together various jar and
+ * zip files.
+ *
+ * <p>It is basically a wrapper for the jlink code written originally
+ * by <a href="mailto:beard@netscape.com">Patrick Beard</a>.  The
+ * classes org.apache.tools.ant.taskdefs.optional.jlink.Jlink and
+ * org.apache.tools.ant.taskdefs.optional.jlink.ClassNameReader
+ * support this class.</p>
+ *
+ * <p>For example:
+ * <code>
+ * <pre>
+ * &lt;jlink compress=&quot;false&quot; outfile=&quot;out.jar&quot;/&gt;
+ *   &lt;mergefiles&gt;
+ *     &lt;pathelement path=&quot;${build.dir}/mergefoo.jar&quot;/&gt;
+ *     &lt;pathelement path=&quot;${build.dir}/mergebar.jar&quot;/&gt;
+ *   &lt;/mergefiles&gt;
+ *   &lt;addfiles&gt;
+ *     &lt;pathelement path=&quot;${build.dir}/mac.jar&quot;/&gt;
+ *     &lt;pathelement path=&quot;${build.dir}/pc.zip&quot;/&gt;
+ *   &lt;/addfiles&gt;
+ * &lt;/jlink&gt;
+ * </pre>
+ * </code>
+ *
+ * @ant.task ignore="true"
+ */
+public class JlinkTask extends MatchingTask {
+
+    /**
+     * The output file for this run of jlink. Usually a jar or zip file.
+     * @param outfile the output file
+     */
+    public  void setOutfile(File outfile) {
+        this.outfile = outfile;
+    }
+
+    /**
+     * Establishes the object that contains the files to
+     * be merged into the output.
+     * @return a path to be configured
+     */
+    public  Path createMergefiles() {
+        if (this.mergefiles == null) {
+            this.mergefiles = new Path(getProject());
+        }
+        return this.mergefiles.createPath();
+    }
+
+    /**
+     * Sets the files to be merged into the output.
+     * @param mergefiles a path
+     */
+    public  void setMergefiles(Path mergefiles) {
+        if (this.mergefiles == null) {
+            this.mergefiles = mergefiles;
+        } else {
+            this.mergefiles.append(mergefiles);
+        }
+    }
+
+    /**
+     * Establishes the object that contains the files to
+     * be added to the output.
+     * @return a path to be configured
+     */
+    public  Path createAddfiles() {
+        if (this.addfiles == null) {
+            this.addfiles = new Path(getProject());
+        }
+        return this.addfiles.createPath();
+    }
+
+    /**
+     * Sets the files to be added into the output.
+     * @param addfiles a path
+     */
+    public  void setAddfiles(Path addfiles) {
+        if (this.addfiles == null) {
+            this.addfiles = addfiles;
+        } else {
+            this.addfiles.append(addfiles);
+        }
+    }
+
+    /**
+     * Defines whether or not the output should be compacted.
+     * @param compress a <code>boolean</code> value
+     */
+    public  void setCompress(boolean compress) {
+        this.compress = compress;
+    }
+
+    /**
+     * Does the adding and merging.
+     * @throws BuildException on error
+     */
+    public  void execute() throws BuildException {
+        //Be sure everything has been set.
+        if (outfile == null) {
+            throw new BuildException("outfile attribute is required! "
+                + "Please set.");
+        }
+        if (!haveAddFiles() && !haveMergeFiles()) {
+            throw new BuildException("addfiles or mergefiles required! "
+                + "Please set.");
+        }
+        log("linking:     " + outfile.getPath());
+        log("compression: " + compress, Project.MSG_VERBOSE);
+        jlink linker = new jlink();
+        linker.setOutfile(outfile.getPath());
+        linker.setCompression(compress);
+        if (haveMergeFiles()) {
+            log("merge files: " + mergefiles.toString(), Project.MSG_VERBOSE);
+            linker.addMergeFiles(mergefiles.list());
+        }
+        if (haveAddFiles()) {
+            log("add files: " + addfiles.toString(), Project.MSG_VERBOSE);
+            linker.addAddFiles(addfiles.list());
+        }
+        try  {
+            linker.link();
+        } catch (Exception ex) {
+            throw new BuildException(ex, getLocation());
+        }
+    }
+
+    private boolean haveAddFiles() {
+        return haveEntries(addfiles);
+    }
+
+    private boolean haveMergeFiles() {
+        return haveEntries(mergefiles);
+    }
+
+    private boolean haveEntries(Path p) {
+        if (p == null) {
+            return false;
+        }
+        if (p.size() > 0) {
+            return true;
+        }
+        return false;
+    }
+
+    private  File outfile = null;
+
+    private  Path mergefiles = null;
+
+    private  Path addfiles = null;
+
+    private  boolean compress = false;
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java
new file mode 100644
index 0000000..9945817
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jlink/jlink.java
@@ -0,0 +1,458 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/**
+ * jlink.java links together multiple .jar files Original code by Patrick
+ * Beard. Modifications to work with ANT by Matthew Kuperus Heun.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jlink;
+
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+// CheckStyle:TypeNameCheck OFF - bc
+/**
+ * jlink links together multiple .jar files.
+ */
+public class jlink {
+    private static final int BUFFER_SIZE = 8192;
+    private static final int VECTOR_INIT_SIZE = 10;
+
+    private String outfile = null;
+
+    private Vector mergefiles = new Vector(VECTOR_INIT_SIZE);
+
+    private Vector addfiles = new Vector(VECTOR_INIT_SIZE);
+
+    private boolean compression = false;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    byte[] buffer = new byte[BUFFER_SIZE];
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** The file that will be created by this instance of jlink.
+     * @param outfile the file to create.
+     */
+    public void setOutfile(String outfile) {
+        if (outfile == null) {
+            return;
+        }
+        this.outfile = outfile;
+    }
+
+
+    /**
+     * Adds a file to be merged into the output.
+     * @param fileToMerge the file to merge into the output.
+     */
+    public void addMergeFile(String fileToMerge) {
+        if (fileToMerge == null) {
+            return;
+        }
+        mergefiles.addElement(fileToMerge);
+    }
+
+
+    /** Adds a file to be added into the output.
+     * @param fileToAdd the file to add to the output.
+     */
+    public void addAddFile(String fileToAdd) {
+        if (fileToAdd == null) {
+            return;
+        }
+        addfiles.addElement(fileToAdd);
+    }
+
+
+    /**
+     * Adds several files to be merged into the output.
+     * @param filesToMerge an array of files to merge into the output.
+     */
+    public void addMergeFiles(String[] filesToMerge) {
+        if (filesToMerge == null) {
+            return;
+        }
+        for (int i = 0; i < filesToMerge.length; i++) {
+            addMergeFile(filesToMerge[i]);
+        }
+    }
+
+
+    /**
+     * Adds several file to be added into the output.
+     * @param filesToAdd an array of files to add to the output.
+     */
+    public void addAddFiles(String[] filesToAdd) {
+        if (filesToAdd == null) {
+            return;
+        }
+        for (int i = 0; i < filesToAdd.length; i++) {
+            addAddFile(filesToAdd[i]);
+        }
+    }
+
+
+    /**
+     * Determines whether output will be compressed.
+     * @param compress if true use compression.
+     */
+    public void setCompression(boolean compress) {
+        this.compression = compress;
+    }
+
+
+    /**
+     * Performs the linking of files. Addfiles are added to the output as-is.
+     * For example, a jar file is added to the output as a jar file. However,
+     * mergefiles are first examined for their type. If it is a jar or zip
+     * file, the contents will be extracted from the mergefile and entered
+     * into the output. If a zip or jar file is encountered in a subdirectory
+     * it will be added, not merged. If a directory is encountered, it becomes
+     * the root entry of all the files below it. Thus, you can provide
+     * multiple, disjoint directories, as addfiles: they will all be added in
+     * a rational manner to outfile.
+     * @throws Exception on error.
+     */
+    public void link() throws Exception {
+        ZipOutputStream output = new ZipOutputStream(new FileOutputStream(outfile));
+
+        if (compression) {
+            output.setMethod(ZipOutputStream.DEFLATED);
+            output.setLevel(Deflater.DEFAULT_COMPRESSION);
+        } else {
+            output.setMethod(ZipOutputStream.STORED);
+        }
+
+        Enumeration merges = mergefiles.elements();
+
+        while (merges.hasMoreElements()) {
+            String path = (String) merges.nextElement();
+            File f = new File(path);
+
+            if (f.getName().endsWith(".jar") || f.getName().endsWith(".zip")) {
+                //Do the merge
+                mergeZipJarContents(output, f);
+            } else {
+                //Add this file to the addfiles Vector and add it
+                //later at the top level of the output file.
+                addAddFile(path);
+            }
+        }
+
+        Enumeration adds = addfiles.elements();
+
+        while (adds.hasMoreElements()) {
+            String name = (String) adds.nextElement();
+            File f = new File(name);
+
+            if (f.isDirectory()) {
+                //System.out.println("in jlink: adding directory contents of " + f.getPath());
+                addDirContents(output, f, f.getName() + '/', compression);
+            } else {
+                addFile(output, f, "", compression);
+            }
+        }
+        FileUtils.close(output);
+    }
+
+
+    /**
+     * The command line entry point for jlink.
+     * @param args an array of arguments
+     */
+    public static void main(String[] args) {
+        // jlink output input1 ... inputN
+        if (args.length < 2) {
+            System.out.println("usage: jlink output input1 ... inputN");
+            System.exit(1);
+        }
+        jlink linker = new jlink();
+
+        linker.setOutfile(args[0]);
+        // To maintain compatibility with the command-line version,
+        // we will only add files to be merged.
+        for (int i = 1; i < args.length; i++) {
+            linker.addMergeFile(args[i]);
+        }
+        try {
+            linker.link();
+        } catch (Exception ex) {
+            System.err.print(ex.getMessage());
+        }
+    }
+
+
+    /*
+     * Actually performs the merging of f into the output.
+     * f should be a zip or jar file.
+     */
+    private void mergeZipJarContents(ZipOutputStream output, File f) throws IOException {
+        //Check to see that the file with name "name" exists.
+        if (!f.exists()) {
+            return;
+        }
+        ZipFile zipf = new ZipFile(f);
+        Enumeration entries = zipf.entries();
+
+        while (entries.hasMoreElements()) {
+            ZipEntry inputEntry = (ZipEntry) entries.nextElement();
+            //Ignore manifest entries.  They're bound to cause conflicts between
+            //files that are being merged.  User should supply their own
+            //manifest file when doing the merge.
+            String inputEntryName = inputEntry.getName();
+            int index = inputEntryName.indexOf("META-INF");
+
+            if (index < 0) {
+                //META-INF not found in the name of the entry. Go ahead and process it.
+                try {
+                    output.putNextEntry(processEntry(zipf, inputEntry));
+                } catch (ZipException ex) {
+                    //If we get here, it could be because we are trying to put a
+                    //directory entry that already exists.
+                    //For example, we're trying to write "com", but a previous
+                    //entry from another mergefile was called "com".
+                    //In that case, just ignore the error and go on to the
+                    //next entry.
+                    String mess = ex.getMessage();
+
+                    if (mess.indexOf("duplicate") >= 0) {
+                        //It was the duplicate entry.
+                        continue;
+                    } else {
+                        // I hate to admit it, but we don't know what happened
+                        // here.  Throw the Exception.
+                        throw ex;
+                    }
+                }
+
+                InputStream in = zipf.getInputStream(inputEntry);
+                int len = buffer.length;
+                int count = -1;
+
+                while ((count = in.read(buffer, 0, len)) > 0) {
+                    output.write(buffer, 0, count);
+                }
+                in.close();
+                output.closeEntry();
+            }
+        }
+        zipf.close();
+    }
+
+
+    /*
+     * Adds contents of a directory to the output.
+     */
+    private void addDirContents(ZipOutputStream output, File dir, String prefix,
+                                boolean compress) throws IOException {
+        String[] contents = dir.list();
+
+        for (int i = 0; i < contents.length; ++i) {
+            String name = contents[i];
+            File file = new File(dir, name);
+
+            if (file.isDirectory()) {
+                addDirContents(output, file, prefix + name + '/', compress);
+            } else {
+                addFile(output, file, prefix, compress);
+            }
+        }
+    }
+
+
+    /*
+     * Gets the name of an entry in the file.  This is the real name
+     * which for a class is the name of the package with the class
+     * name appended.
+     */
+    private String getEntryName(File file, String prefix) {
+        String name = file.getName();
+
+        if (!name.endsWith(".class")) {
+            // see if the file is in fact a .class file, and determine its actual name.
+            InputStream input = null;
+            try {
+                input = new FileInputStream(file);
+                String className = ClassNameReader.getClassName(input);
+
+                if (className != null) {
+                    return className.replace('.', '/') + ".class";
+                }
+            } catch (IOException ioe) {
+                //do nothing
+            } finally {
+                if (input != null) {
+                    try {
+                        input.close();
+                    } catch (IOException e) {
+                        //do nothing
+                    }
+                }
+            }
+        }
+        System.out.println("From " + file.getPath() + " and prefix " + prefix
+                           + ", creating entry " + prefix + name);
+        return (prefix + name);
+    }
+
+
+    /*
+     * Adds a file to the output stream.
+     */
+    private void addFile(ZipOutputStream output, File file, String prefix,
+                         boolean compress) throws IOException {
+        //Make sure file exists
+        if (!file.exists()) {
+            return;
+        }
+        ZipEntry entry = new ZipEntry(getEntryName(file, prefix));
+
+        entry.setTime(file.lastModified());
+        entry.setSize(file.length());
+        if (!compress) {
+            entry.setCrc(calcChecksum(file));
+        }
+        FileInputStream input = new FileInputStream(file);
+
+        addToOutputStream(output, input, entry);
+    }
+
+
+    /*
+     * A convenience method that several other methods might call.
+     */
+    private void addToOutputStream(ZipOutputStream output, InputStream input,
+                                   ZipEntry ze) throws IOException {
+        try {
+            output.putNextEntry(ze);
+        } catch (ZipException zipEx) {
+            //This entry already exists. So, go with the first one.
+            input.close();
+            return;
+        }
+
+        int numBytes = -1;
+
+        while ((numBytes = input.read(buffer)) > 0) {
+            output.write(buffer, 0, numBytes);
+        }
+        output.closeEntry();
+        input.close();
+    }
+
+
+    /*
+     * A method that does the work on a given entry in a mergefile.
+     * The big deal is to set the right parameters in the ZipEntry
+     * on the output stream.
+     */
+    private ZipEntry processEntry(ZipFile zip, ZipEntry inputEntry) {
+        /*
+          First, some notes.
+          On MRJ 2.2.2, getting the size, compressed size, and CRC32 from the
+          ZipInputStream does not work for compressed (deflated) files.  Those calls return -1.
+          For uncompressed (stored) files, those calls do work.
+          However, using ZipFile.getEntries() works for both compressed and
+          uncompressed files.
+
+          Now, from some simple testing I did, it seems that the value of CRC-32 is
+          independent of the compression setting. So, it should be easy to pass this
+          information on to the output entry.
+        */
+        String name = inputEntry.getName();
+
+        if (!(inputEntry.isDirectory() || name.endsWith(".class"))) {
+            try {
+                InputStream input = zip.getInputStream(zip.getEntry(name));
+                String className = ClassNameReader.getClassName(input);
+
+                input.close();
+                if (className != null) {
+                    name = className.replace('.', '/') + ".class";
+                }
+            } catch (IOException ioe) {
+                //do nothing
+            }
+        }
+        ZipEntry outputEntry = new ZipEntry(name);
+
+        outputEntry.setTime(inputEntry.getTime());
+        outputEntry.setExtra(inputEntry.getExtra());
+        outputEntry.setComment(inputEntry.getComment());
+        outputEntry.setTime(inputEntry.getTime());
+        if (compression) {
+            outputEntry.setMethod(ZipEntry.DEFLATED);
+            //Note, don't need to specify size or crc for compressed files.
+        } else {
+            outputEntry.setMethod(ZipEntry.STORED);
+            outputEntry.setCrc(inputEntry.getCrc());
+            outputEntry.setSize(inputEntry.getSize());
+        }
+        return outputEntry;
+    }
+
+
+    /*
+     * Necessary in the case where you add a entry that
+     * is not compressed.
+     */
+    private long calcChecksum(File f) throws IOException {
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(f));
+
+        return calcChecksum(in);
+    }
+
+
+    /*
+     * Necessary in the case where you add a entry that
+     * is not compressed.
+     */
+    private long calcChecksum(InputStream in) throws IOException {
+        CRC32 crc = new CRC32();
+        int len = buffer.length;
+        int count = -1;
+        int haveRead = 0;
+
+        while ((count = in.read(buffer, 0, len)) > 0) {
+            haveRead += count;
+            crc.update(buffer, 0, count);
+        }
+        in.close();
+        return crc.getValue();
+    }
+
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java
new file mode 100644
index 0000000..609938c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/Jasper41Mangler.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+
+/**
+ * this class implements the name mangling rules of the jasper in tomcat4.1.x
+ * which is likely to remain for some time
+ * @see "org.apache.jasper.JspCompilationContext"
+ */
+public class Jasper41Mangler implements JspMangler {
+
+
+    /**
+     * map from a jsp file to a java filename; does not do packages
+     *
+     * @param jspFile file
+     * @return java filename
+     */
+    public String mapJspToJavaName(File jspFile) {
+        String jspUri = jspFile.getAbsolutePath();
+        int start = jspUri.lastIndexOf(File.separatorChar) + 1;
+        int end = jspUri.length();
+        StringBuffer modifiedClassName;
+        modifiedClassName = new StringBuffer(jspUri.length() - start);
+        if (!Character.isJavaIdentifierStart(jspUri.charAt(start))
+            || jspUri.charAt(start) == '_') {
+            // If the first char is not a start of Java identifier or is _
+            // prepend a '_'.
+            modifiedClassName.append('_');
+        }
+        for (int i = start; i < end; i++) {
+            char ch = jspUri.charAt(i);
+            if (Character.isJavaIdentifierPart(ch)) {
+                modifiedClassName.append(ch);
+            } else if (ch == '.') {
+                modifiedClassName.append('_');
+            } else {
+                modifiedClassName.append(mangleChar(ch));
+            }
+        }
+        return modifiedClassName.toString();
+    }
+
+    /**
+     * Mangle the specified character to create a legal Java class name.
+     */
+    private static String mangleChar(char ch) {
+        // CheckStyle:MagicNumber OFF
+        String s = Integer.toHexString(ch);
+        int nzeros = 5 - s.length();
+        char[] result = new char[6];
+        result[0] = '_';
+        for (int i = 1; i <= nzeros; i++) {
+            result[i] = '0';
+        }
+        for (int i = nzeros + 1, j = 0; i < 6; i++, j++) {
+            result[i] = s.charAt(j);
+        }
+        return new String(result);
+        // CheckStyle:MagicNumber ON
+    }
+
+
+    /**
+     * taking in the substring representing the path relative to the source dir
+     * return a new string representing the destination path
+     * @param path not used.
+     * @return null as this is not implemented.
+     * @todo
+     */
+    public String mapPath(String path) {
+        return null;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java
new file mode 100644
index 0000000..e570ad8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspC.java
@@ -0,0 +1,692 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapter;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapterFactory;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Runs a JSP compiler.
+ *
+ * <p> This task takes the given jsp files and compiles them into java
+ * files. It is then up to the user to compile the java files into classes.
+ *
+ * <p> The task requires the srcdir and destdir attributes to be
+ * set. This Task is a MatchingTask, so the files to be compiled can be
+ * specified using includes/excludes attributes or nested include/exclude
+ * elements. Optional attributes are verbose (set the verbosity level passed
+ * to jasper), package (name of the destination package for generated java
+ * classes and classpath (the classpath to use when running the jsp
+ * compiler).
+ * <p> This task supports the nested elements classpath (A Path) and
+ * classpathref (A Reference) which can be used in preference to the
+ * attribute classpath, if the jsp compiler is not already in the ant
+ * classpath.
+ *
+ * <p><h4>Usage</h4>
+ * <pre>
+ * &lt;jspc srcdir="${basedir}/src/war"
+ *       destdir="${basedir}/gensrc"
+ *       package="com.i3sp.jsp"
+ *       verbose="9"&gt;
+ *   &lt;include name="**\/*.jsp" /&gt;
+ * &lt;/jspc&gt;
+ * </pre>
+ *
+ * <p> Large Amount of cutting and pasting from the Javac task...
+ * @since 1.5
+ */
+public class JspC extends MatchingTask {
+    private Path classpath;
+    private Path compilerClasspath;
+    private Path src;
+    private File destDir;
+    private String packageName;
+    /** name of the compiler to use */
+    private String compilerName = "jasper";
+
+    /**
+     *  -ieplugin &lt;clsid&gt; Java Plugin classid for Internet Explorer
+     */
+    private String iepluginid;
+    private boolean mapped;
+    private int verbose = 0;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Vector compileList = new Vector();
+    Vector javaFiles = new Vector();
+
+    /**
+     *  flag to control action on execution trouble
+     */
+    protected boolean failOnError = true;
+
+    /**
+     *  -uriroot &lt;dir&gt; The root directory that uri files should be resolved
+     *  against,
+     */
+    private File uriroot;
+
+    /**
+     *  -webinc &lt;file&gt; Creates partial servlet mappings for the -webapp option
+     */
+    private File webinc;
+
+    /**
+     *  -webxml &lt;file&gt; Creates a complete web.xml when using the -webapp option.
+     */
+
+    private File webxml;
+
+    /**
+     *  web apps
+     */
+    protected WebAppParameter webApp;
+
+
+
+    private static final String FAIL_MSG
+        = "Compile failed, messages should have been provided.";
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the path for source JSP files.
+     * @param srcDir the source path.
+     */
+    public void setSrcDir(Path srcDir) {
+        if (src == null) {
+            src = srcDir;
+        } else {
+            src.append(srcDir);
+        }
+    }
+
+    /**
+     * Get the source dir.
+     * @return the source path.
+     */
+    public Path getSrcDir() {
+        return src;
+    }
+
+    /**
+     * Set the destination directory into which the JSP source
+     * files should be compiled.
+     * @param destDir the destination directory.
+     */
+    public void setDestdir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Get the destination directory.
+     * @return the directory.
+     */
+    public File getDestdir() {
+        return destDir;
+    }
+
+    /**
+     * Set the name of the package the compiled jsp files should be in.
+     * @param pkg the name of the package.
+     */
+    public void setPackage(String pkg) {
+        this.packageName = pkg;
+    }
+
+    /**
+     * Get the name of the package.
+     * @return the package.
+     */
+    public String getPackage() {
+        return packageName;
+    }
+
+    /**
+     * Set the verbose level of the compiler
+     * @param i the verbose level to use.
+     */
+    public void setVerbose(int i) {
+        verbose = i;
+    }
+
+    /**
+     * Get the verbose level.
+     * @return the level.
+     */
+    public int getVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Whether or not the build should halt if compilation fails.
+     * Defaults to <code>true</code>.
+     * @param fail a <code>boolean</code> value.
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+    /**
+     * Gets the failonerror flag.
+     * @return the flag.
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Get the IE CLASSID value.
+     * @return the value.
+     */
+    public String getIeplugin() {
+        return iepluginid;
+    }
+    /**
+     * Java Plugin CLASSID for Internet Explorer
+     * @param iepluginid the id to use.
+     */
+    public void setIeplugin(String iepluginid) {
+        this.iepluginid = iepluginid;
+    }
+
+    /**
+     * If true, generate separate write() calls for each HTML line
+     * in the JSP.
+     * @return mapping status
+     */
+    public boolean isMapped() {
+        return mapped;
+    }
+
+    /**
+     * If true, generate separate write() calls for each HTML line
+     * in the JSP.
+     * @param mapped a <code>boolean</code> value.
+     */
+    public void setMapped(boolean mapped) {
+        this.mapped = mapped;
+    }
+
+    /**
+     * The URI context of relative URI references in the JSP pages.
+     * If it does not exist then it is derived from the location
+     * of the file relative to the declared or derived value of uriroot.
+     *
+     * @param  uribase  The new Uribase value
+     */
+    public void setUribase(File uribase) {
+        log("Uribase is currently an unused parameter", Project.MSG_WARN);
+    }
+
+    /**
+     * Get the uri base value.
+     * @return the value.
+     */
+    public File getUribase() {
+        return uriroot;
+    }
+
+    /**
+     *  The root directory that uri files should be resolved
+     *  against. (Default is the directory jspc is invoked from)
+     *
+     * @param  uriroot  The new Uribase value
+     */
+    public void setUriroot(File uriroot) {
+        this.uriroot = uriroot;
+    }
+
+    /**
+     * Get the uri root value.
+     * @return the value.
+     */
+    public File getUriroot() {
+        return uriroot;
+    }
+
+
+    /**
+     * Set the classpath to be used for this compilation.
+     * @param cp the path to be used.
+     */
+    public void setClasspath(Path cp) {
+        if (classpath == null) {
+            classpath = cp;
+        } else {
+            classpath.append(cp);
+        }
+    }
+
+    /**
+     * Adds a path to the classpath.
+     * @return a path to be configured.
+     */
+    public Path createClasspath() {
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Adds a reference to a classpath defined elsewhere
+     * @param r a reference to a classpath.
+     */
+    public void setClasspathRef(Reference r) {
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * Get the classpath.
+     * @return the classpath.
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Set the classpath to be used to find this compiler adapter
+     * @param cp the compiler classpath.
+     */
+    public void setCompilerclasspath(Path cp) {
+        if (compilerClasspath == null) {
+            compilerClasspath = cp;
+        } else {
+            compilerClasspath.append(cp);
+        }
+    }
+
+    /**
+     * get the classpath used to find the compiler adapter
+     * @return the compiler classpath.
+     */
+    public Path getCompilerclasspath() {
+        return compilerClasspath;
+    }
+
+    /**
+     * Support nested compiler classpath, used to locate compiler adapter
+     * @return a path to be configured.
+     */
+    public Path createCompilerclasspath() {
+        if (compilerClasspath == null) {
+            compilerClasspath = new Path(getProject());
+        }
+        return compilerClasspath.createPath();
+    }
+
+    /**
+     *  Filename for web.xml.
+     *
+     * @param  webxml  The new Webxml value
+     */
+    public void setWebxml(File webxml) {
+        this.webxml = webxml;
+    }
+
+    /**
+     * Filename for web.xml.
+     * @return The filename for web.xml.
+     */
+    public File getWebxml() {
+        return this.webxml;
+    }
+
+    /**
+     *  output filename for the fraction of web.xml that lists
+     *  servlets.
+     * @param  webinc  The new Webinc value
+     */
+    public void setWebinc(File webinc) {
+        this.webinc = webinc;
+    }
+
+    /**
+     * Get the webinc attribute.
+     * @return the webinc attribute.
+     */
+    public File getWebinc() {
+        return this.webinc;
+    }
+
+    /**
+     * Adds a single webapp.
+     *
+     * @param  webappParam  add a web app parameter
+     * @throws BuildException if more than one webapp is specified.
+     */
+    public void addWebApp(WebAppParameter webappParam)
+        throws BuildException {
+        //demand create vector of filesets
+        if (webApp == null) {
+            webApp = webappParam;
+        } else {
+            throw new BuildException("Only one webapp can be specified");
+        }
+    }
+
+    /**
+     * Get the web app.
+     * @return the web app attribute.
+     */
+    public WebAppParameter getWebApp() {
+        return webApp;
+    }
+
+    /**
+     * Class name of a JSP compiler adapter.
+     * @param compiler the compiler class name.
+     */
+    public void setCompiler(String compiler) {
+        this.compilerName = compiler;
+    }
+
+    /**
+    * get the list of files to compile
+    * @return the list of files.
+    */
+    public Vector getCompileList() {
+        return compileList;
+    }
+
+    /**
+     * execute by building up a list of files that
+     * have changed and hand them off to a jsp compiler
+     * @throws BuildException on error.
+     */
+    public void execute()
+        throws BuildException {
+
+        // make sure that we've got a destdir
+        if (destDir == null) {
+            throw new BuildException("destdir attribute must be set!",
+                                     getLocation());
+        }
+
+        if (!destDir.isDirectory()) {
+            throw new BuildException("destination directory \"" + destDir
+                    + "\" does not exist or is not a directory", getLocation());
+        }
+
+        File dest = getActualDestDir();
+
+        //bind to a compiler
+        JspCompilerAdapter compiler =
+            JspCompilerAdapterFactory.getCompiler(compilerName, this,
+                getProject().createClassLoader(compilerClasspath));
+
+        //if we are a webapp, hand off to the compiler, which had better handle it
+        if (webApp != null) {
+            doCompilation(compiler);
+            return;
+        }
+
+        // make sure that we've got a srcdir
+        if (src == null) {
+            throw new BuildException("srcdir attribute must be set!",
+                                     getLocation());
+        }
+        String [] list = src.list();
+        if (list.length == 0) {
+            throw new BuildException("srcdir attribute must be set!",
+                    getLocation());
+        }
+
+
+        // if the compiler does its own dependency stuff, we just call it right now
+        if (compiler.implementsOwnDependencyChecking()) {
+            doCompilation(compiler);
+            return;
+        }
+
+        //the remainder of this method is only for compilers that need their dependency work done
+        JspMangler mangler = compiler.createMangler();
+
+        // scan source directories and dest directory to build up both copy
+        // lists and compile lists
+        resetFileLists();
+        int filecount = 0;
+        for (int i = 0; i < list.length; i++) {
+            File srcDir = getProject().resolveFile(list[i]);
+            if (!srcDir.exists()) {
+                throw new BuildException("srcdir \"" + srcDir.getPath()
+                    + "\" does not exist!", getLocation());
+            }
+            DirectoryScanner ds = this.getDirectoryScanner(srcDir);
+            String[] files = ds.getIncludedFiles();
+            filecount = files.length;
+            scanDir(srcDir, dest, mangler, files);
+        }
+
+        // compile the source files
+
+        log("compiling " + compileList.size() + " files", Project.MSG_VERBOSE);
+
+        if (compileList.size() > 0) {
+
+            log("Compiling " + compileList.size() + " source file"
+                + (compileList.size() == 1 ? "" : "s")
+                + " to "
+                + dest);
+            doCompilation(compiler);
+
+        } else {
+            if (filecount == 0) {
+                log("there were no files to compile", Project.MSG_INFO);
+            } else {
+                log("all files are up to date", Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+    /**
+     * calculate where the files will end up:
+     * this is destDir or it id destDir + the package name
+     */
+    private File getActualDestDir() {
+        File dest = null;
+        if (packageName == null) {
+            dest = destDir;
+        } else {
+            String path = destDir.getPath() + File.separatorChar
+                + packageName.replace('.', File.separatorChar);
+            dest = new File(path);
+        }
+        return dest;
+    }
+
+    /**
+     * do the compile
+     */
+    private void doCompilation(JspCompilerAdapter compiler)
+            throws BuildException {
+        // now we need to populate the compiler adapter
+        compiler.setJspc(this);
+
+        // finally, lets execute the compiler!!
+        if (!compiler.execute()) {
+            if (failOnError) {
+                throw new BuildException(FAIL_MSG, getLocation());
+            } else {
+                log(FAIL_MSG, Project.MSG_ERR);
+            }
+        }
+    }
+
+    /**
+     * Clear the list of files to be compiled and copied..
+     */
+    protected void resetFileLists() {
+        compileList.removeAllElements();
+    }
+
+    /**
+     * Scans the directory looking for source files to be compiled.
+     * The results are returned in the class variable compileList
+     * @param srcDir the source directory.
+     * @param dest   the destination directory.
+     * @param mangler the jsp filename mangler.
+     * @param files   the file names to mangle.
+     */
+    protected void scanDir(
+        File srcDir, File dest, JspMangler mangler, String[] files) {
+
+        long now = (new Date()).getTime();
+
+        for (int i = 0; i < files.length; i++) {
+            String filename = files[i];
+            File srcFile = new File(srcDir, filename);
+            File javaFile = mapToJavaFile(mangler, srcFile, srcDir, dest);
+            if (javaFile == null) {
+                continue;
+            }
+
+            if (srcFile.lastModified() > now) {
+                log("Warning: file modified in the future: " + filename,
+                        Project.MSG_WARN);
+            }
+            boolean shouldCompile = false;
+            shouldCompile = isCompileNeeded(srcFile, javaFile);
+            if (shouldCompile) {
+               compileList.addElement(srcFile.getAbsolutePath());
+               javaFiles.addElement(javaFile);
+            }
+        }
+    }
+
+    /**
+     * Test whether or not compilation is needed. A return value of
+     * <code>true<code> means yes, <code>false</code> means
+     * our tests do not indicate this, but as the TLDs are
+     * not used for dependency checking this is not guaranteed.
+     * The current tests are
+     * <ol>
+     * <li>no dest file
+     * <li>dest file out of date w.r.t source
+     * <li>dest file zero bytes long
+     * </ol>
+     * @param srcFile JSP source file
+     * @param javaFile JSP dest file
+     * @return true if a compile is definately needed.
+     *
+     */
+    private boolean isCompileNeeded(File srcFile, File javaFile) {
+        boolean shouldCompile = false;
+        if (!javaFile.exists()) {
+            shouldCompile = true;
+            log("Compiling " + srcFile.getPath()
+                + " because java file " + javaFile.getPath()
+                + " does not exist", Project.MSG_VERBOSE);
+            } else {
+                if (srcFile.lastModified() > javaFile.lastModified()) {
+                    shouldCompile = true;
+                    log("Compiling " + srcFile.getPath()
+                        + " because it is out of date with respect to "
+                        + javaFile.getPath(),
+                        Project.MSG_VERBOSE);
+                } else {
+                    if (javaFile.length() == 0) {
+                        shouldCompile = true;
+                        log("Compiling " + srcFile.getPath()
+                            + " because java file " + javaFile.getPath()
+                            + " is empty", Project.MSG_VERBOSE);
+                    }
+                }
+        }
+        return shouldCompile;
+    }
+
+
+    /**
+     * get a filename from our jsp file.
+     * @param mangler the jsp filename managler.
+     * @param srcFile the source file.
+     * @param srcDir  the source directory.
+     * @param dest    the destination directory.
+     * @return the filename.
+     * @todo support packages and subdirs
+     */
+    protected File mapToJavaFile(JspMangler mangler, File srcFile, File srcDir, File dest) {
+        if (!srcFile.getName().endsWith(".jsp")) {
+            return null;
+        }
+        String javaFileName = mangler.mapJspToJavaName(srcFile);
+//        String srcFileDir=srcFile.getParent();
+        return new File(dest, javaFileName);
+    }
+
+    /**
+     * delete any java output files that are empty
+     * this is to get around a little defect in jasper: when it
+     * fails, it leaves incomplete files around.
+     */
+    public void deleteEmptyJavaFiles() {
+        if (javaFiles != null) {
+            Enumeration e = javaFiles.elements();
+            while (e.hasMoreElements()) {
+                File file = (File) e.nextElement();
+                if (file.exists() && file.length() == 0) {
+                    log("deleting empty output file " + file);
+                    file.delete();
+                }
+            }
+        }
+    }
+
+    /**
+     * static inner class used as a parameter element
+     */
+    public static class WebAppParameter {
+
+        /**
+         * the sole option
+         */
+        private File directory;
+
+        /**
+         * query current directory
+         * @return the directory.
+         */
+        public File getDirectory() {
+            return directory;
+        }
+
+        /**
+         * set directory; alternate syntax
+         * @param directory the base dir.
+         */
+        public void setBaseDir(File directory) {
+            this.directory = directory;
+        }
+    //end inner class
+    }
+
+
+//end class
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java
new file mode 100644
index 0000000..f62492c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspMangler.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+import java.io.File;
+
+/**
+ * This is an interface to the Mangler service that jspc needs to map
+ * JSP file names to java files.
+ * Note the complete lack of correlation
+ * with Jasper's mangler interface.
+ */
+public interface JspMangler {
+
+
+    /**
+     * map from a jsp file to a java filename; does not do packages
+     *
+     * @param jspFile file
+     * @return java filename
+     */
+    String mapJspToJavaName(File jspFile);
+
+    /**
+     * taking in the substring representing the path relative to the source dir
+     * return a new string representing the destination path
+     * @param path the path to map.
+     * @return the mapped path.
+     */
+    String mapPath(String path);
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java
new file mode 100644
index 0000000..6aaae5c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/JspNameMangler.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+import java.io.File;
+
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * This is a class derived from the Jasper code
+ * (org.apache.jasper.compiler.CommandLineCompiler) to map from a JSP filename
+ * to a valid Java classname.
+ *
+ */
+public class JspNameMangler implements JspMangler {
+
+    // CheckStyle:ConstantNameCheck OFF - bc
+
+    /**
+     * this is the list of keywords which can not be used as classnames
+     */
+    public static final String[] keywords = {
+            "assert",
+            "abstract", "boolean", "break", "byte",
+            "case", "catch", "char", "class",
+            "const", "continue", "default", "do",
+            "double", "else", "extends", "final",
+            "finally", "float", "for", "goto",
+            "if", "implements", "import",
+            "instanceof", "int", "interface",
+            "long", "native", "new", "package",
+            "private", "protected", "public",
+            "return", "short", "static", "super",
+            "switch", "synchronized", "this",
+            "throw", "throws", "transient",
+            "try", "void", "volatile", "while"
+            };
+
+    // CheckStyle:ConstantNameCheck ON
+
+    /**
+     * map from a jsp file to a java filename; does not do packages
+     *
+     * @param jspFile file
+     * @return java filename
+     */
+    public String mapJspToJavaName(File jspFile) {
+        return mapJspToBaseName(jspFile) + ".java";
+    }
+
+
+    /**
+     * map from a jsp file to a base name; does not deal with extensions
+     *
+     * @param jspFile jspFile file
+     * @return exensionless potentially remapped name
+     */
+    private String mapJspToBaseName(File jspFile) {
+        String className;
+        className = stripExtension(jspFile);
+
+        // since we don't mangle extensions like the servlet does,
+        // we need to check for keywords as class names
+        for (int i = 0; i < keywords.length; ++i) {
+            if (className.equals(keywords[i])) {
+                className += "%";
+                break;
+            }
+        }
+
+        // Fix for invalid characters. If you think of more add to the list.
+        StringBuffer modifiedClassName = new StringBuffer(className.length());
+        // first char is more restrictive than the rest
+        char firstChar = className.charAt(0);
+        if (Character.isJavaIdentifierStart(firstChar)) {
+            modifiedClassName.append(firstChar);
+        } else {
+            modifiedClassName.append(mangleChar(firstChar));
+        }
+        // this is the rest
+        for (int i = 1; i < className.length(); i++) {
+            char subChar = className.charAt(i);
+            if (Character.isJavaIdentifierPart(subChar)) {
+                modifiedClassName.append(subChar);
+            } else {
+                modifiedClassName.append(mangleChar(subChar));
+            }
+        }
+        return modifiedClassName.toString();
+    }
+
+
+    /**
+     * get short filename from file
+     *
+     * @param jspFile file in
+     * @return file without any jsp extension
+     */
+    private String stripExtension(File jspFile) {
+        return StringUtils.removeSuffix(jspFile.getName(), ".jsp");
+    }
+
+
+    /**
+     * definition of the char escaping algorithm
+     *
+     * @param ch char to mangle
+     * @return mangled string; 5 digit hex value
+     */
+    private static String mangleChar(char ch) {
+        // CheckStyle:MagicNumber OFF
+        if (ch == File.separatorChar) {
+            ch = '/';
+        }
+        String s = Integer.toHexString(ch);
+        int nzeros = 5 - s.length();
+        char[] result = new char[6];
+        result[0] = '_';
+        for (int i = 1; i <= nzeros; ++i) {
+            result[i] = '0';
+        }
+        int resultIndex = 0;
+        for (int i = nzeros + 1; i < 6; ++i) {
+            result[i] = s.charAt(resultIndex++);
+        }
+        return new String(result);
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * taking in the substring representing the path relative to the source dir
+     * return a new string representing the destination path
+     * not supported, as jasper in tomcat4.0 doesnt either
+     * @param path not used
+     * @return null always.
+     */
+    public String mapPath(String path) {
+        return null;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java
new file mode 100644
index 0000000..d4b6588
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/WLJspc.java
@@ -0,0 +1,332 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp;
+
+//apache/ant imports
+import java.io.File;
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.taskdefs.MatchingTask;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Precompiles JSP's using WebLogic's JSP compiler (weblogic.jspc).
+ *
+ * Tested only on Weblogic 4.5.1 - NT4.0 and Solaris 5.7
+ *
+ * required attributes
+ *      src : root of source tree for JSP, ie, the document root for your weblogic server
+ *      dest : root of destination directory, what you have set as
+ *             WorkingDir in the weblogic properties
+ *      package : start package name under which your JSP's would be compiled
+ *
+ * other attributes
+ *     classpath
+ *
+ * A classpath should be set which contains the weblogic classes as well as all
+ * application classes referenced by the JSP. The system classpath is also
+ * appended when the jspc is called, so you may choose to put everything in
+ * the classpath while calling Ant. However, since presumably the JSP's will
+ * reference classes being build by Ant, it would be better to explicitly add
+ * the classpath in the task
+ *
+ * The task checks timestamps on the JSP's and the generated classes, and compiles
+ * only those files that have changed.
+ *
+ * It follows the weblogic naming convention of putting classes in
+ *  <b> _dirName/_fileName.class for dirname/fileName.jsp   </b>
+ *
+ * Limitation: It compiles the files thru the Classic compiler only.
+ * Limitation: Since it is my experience that weblogic jspc throws out of
+ *             memory error on being given too many files at one go, it is
+ *             called multiple times with one jsp file each.
+ *
+ * <pre>
+ * example
+ * &lt;target name="jspcompile" depends="compile"&gt;
+ *   &lt;wljspc src="c:\\weblogic\\myserver\\public_html"
+ *           dest="c:\\weblogic\\myserver\\serverclasses" package="myapp.jsp"&gt;
+ *   &lt;classpath&gt;
+ *          &lt;pathelement location="${weblogic.classpath}" /&gt;
+ *           &lt;pathelement path="${compile.dest}" /&gt;
+ *      &lt;/classpath&gt;
+ *
+ *   &lt;/wljspc&gt;
+ * &lt;/target&gt;
+ * </pre>
+ *
+ */
+
+public class WLJspc extends MatchingTask {
+    //TODO Test on other versions of weblogic
+    //TODO add more attributes to the task, to take care of all jspc options
+    //TODO Test on Unix
+
+    /** root of compiled files tree */
+    private File destinationDirectory;
+
+    /** root of source files tree */
+    private File sourceDirectory;
+
+    /** package under which resultant classes will reside */
+    private String destinationPackage;
+
+    /** classpath used to compile the jsp files. */
+    private Path compileClasspath;
+
+    //private String compilerPath; //fully qualified name for the compiler executable
+
+    private String pathToPackage = "";
+    private Vector filesToDo = new Vector();
+
+    /**
+     * Run the task.
+     * @throws BuildException if there is an error.
+     */
+    public void execute() throws BuildException {
+        if (!destinationDirectory.isDirectory()) {
+            throw new BuildException("destination directory "
+                + destinationDirectory.getPath() + " is not valid");
+        }
+
+        if (!sourceDirectory.isDirectory()) {
+            throw new BuildException("src directory "
+                + sourceDirectory.getPath() + " is not valid");
+        }
+
+        if (destinationPackage == null) {
+            throw new BuildException("package attribute must be present.",
+                                     getLocation());
+        }
+
+
+        pathToPackage
+            = this.destinationPackage.replace('.', File.separatorChar);
+        // get all the files in the sourceDirectory
+        DirectoryScanner ds = super.getDirectoryScanner(sourceDirectory);
+
+        //use the systemclasspath as well, to include the ant jar
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+
+        compileClasspath = compileClasspath.concatSystemClasspath();
+        String[] files = ds.getIncludedFiles();
+
+        //Weblogic.jspc calls System.exit() ... have to fork
+        // Therefore, takes loads of time
+        // Can pass directories at a time (*.jsp) but easily runs out of
+        // memory on hefty dirs (even on  a Sun)
+        Java helperTask = new Java(this);
+        helperTask.setFork(true);
+        helperTask.setClassname("weblogic.jspc");
+        helperTask.setTaskName(getTaskName());
+        // CheckStyle:MagicNumber OFF
+        String[] args = new String[12];
+        // CheckStyle:MagicNumber ON
+
+        File jspFile = null;
+        String parents = "";
+        int j = 0;
+        //XXX  this array stuff is a remnant of prev trials.. gotta remove.
+        args[j++] = "-d";
+        args[j++] = destinationDirectory.getAbsolutePath().trim();
+        args[j++] = "-docroot";
+        args[j++] = sourceDirectory.getAbsolutePath().trim();
+        args[j++] = "-keepgenerated";
+        //Call compiler as class... dont want to fork again
+        //Use classic compiler -- can be parameterised?
+        args[j++] =  "-compilerclass";
+        args[j++] = "sun.tools.javac.Main";
+        //Weblogic jspc does not seem to work unless u explicitly set this...
+        // Does not take the classpath from the env....
+        // Am i missing something about the Java task??
+        args[j++] = "-classpath";
+        args[j++] = compileClasspath.toString();
+
+        this.scanDir(files);
+        log("Compiling " + filesToDo.size() + " JSP files");
+
+        for (int i = 0; i < filesToDo.size(); i++) {
+            //XXX
+            // All this to get package according to weblogic standards
+            // Can be written better... this is too hacky!
+            // Careful.. similar code in scanDir , but slightly different!!
+            String filename = (String) filesToDo.elementAt(i);
+            jspFile = new File(filename);
+            args[j] = "-package";
+            parents = jspFile.getParent();
+            if ((parents != null)  && (!("").equals(parents))) {
+                parents =  this.replaceString(parents, File.separator, "_.");
+                args[j + 1] = destinationPackage + "." + "_" + parents;
+            } else {
+                args[j + 1] = destinationPackage;
+            }
+
+
+            args[j + 2] =  sourceDirectory + File.separator + filename;
+            helperTask.clearArgs();
+
+            // CheckStyle:MagicNumber OFF
+            for (int x = 0; x < j + 3; x++) {
+                helperTask.createArg().setValue(args[x]);
+            }
+            // CheckStyle:MagicNumber ON
+
+            helperTask.setClasspath(compileClasspath);
+            if (helperTask.executeJava() != 0) {
+                log(filename + " failed to compile", Project.MSG_WARN);
+            }
+        }
+    }
+
+
+
+    /**
+     * Set the classpath to be used for this compilation.
+     * @param classpath the classpath to use.
+     */
+    public void setClasspath(Path classpath) {
+        if (compileClasspath == null) {
+            compileClasspath = classpath;
+        } else {
+            compileClasspath.append(classpath);
+        }
+    }
+
+    /**
+     * Maybe creates a nested classpath element.
+     * @return a path to be configured.
+     */
+    public Path createClasspath() {
+        if (compileClasspath == null) {
+            compileClasspath = new Path(getProject());
+        }
+        return compileClasspath;
+    }
+
+    /**
+     * Set the directory containing the source jsp's
+     *
+     *
+     * @param dirName the directory containg the source jsp's
+     */
+    public void setSrc(File dirName) {
+
+        sourceDirectory = dirName;
+    }
+
+     /**
+     * Set the directory containing the source jsp's
+     *
+     *
+     * @param dirName the directory containg the source jsp's
+     */
+    public void setDest(File dirName) {
+
+        destinationDirectory = dirName;
+    }
+
+    /**
+     * Set the package under which the compiled classes go
+     *
+     * @param packageName the package name for the clases
+     */
+    public void setPackage(String packageName) {
+
+        destinationPackage = packageName;
+    }
+
+    /**
+     * Scan the array of files and add the jsp
+     * files that need to be compiled to the filesToDo field.
+     * @param files the files to scan.
+     */
+    protected void scanDir(String[] files) {
+
+        long now = (new Date()).getTime();
+        File jspFile = null;
+        String parents = null;
+        String pack = "";
+        for (int i = 0; i < files.length; i++) {
+            File srcFile = new File(this.sourceDirectory, files[i]);
+            //XXX
+            // All this to convert source to destination directory according
+            // to weblogic standards Can be written better... this is too hacky!
+            jspFile = new File(files[i]);
+            parents = jspFile.getParent();
+
+            if ((parents != null)  && (!("").equals(parents))) {
+                parents =  this.replaceString(parents, File.separator, "_/");
+                pack = pathToPackage + File.separator + "_" + parents;
+            } else {
+                pack = pathToPackage;
+            }
+
+            String filePath = pack + File.separator + "_";
+            int startingIndex = files[i].lastIndexOf(File.separator) != -1
+                    ? files[i].lastIndexOf(File.separator) + 1 : 0;
+            int endingIndex = files[i].indexOf(".jsp");
+            if (endingIndex == -1) {
+                log("Skipping " + files[i] + ". Not a JSP",
+                    Project.MSG_VERBOSE);
+                continue;
+            }
+
+            filePath += files[i].substring(startingIndex, endingIndex);
+            filePath += ".class";
+            File classFile = new File(this.destinationDirectory, filePath);
+
+            if (srcFile.lastModified() > now) {
+                log("Warning: file modified in the future: "
+                    + files[i], Project.MSG_WARN);
+            }
+            if (srcFile.lastModified() > classFile.lastModified()) {
+                filesToDo.addElement(files[i]);
+                log("Recompiling File " + files[i], Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+
+    /**
+     * Replace occurances of a string with a replacement string.
+     * @param inpString the string to convert.
+     * @param escapeChars the string to replace.
+     * @param replaceChars the string to place.
+     * @return the converted string.
+     */
+    protected String replaceString(String inpString, String escapeChars,
+                                   String replaceChars) {
+        String localString = "";
+        int numTokens = 0;
+        StringTokenizer st = new StringTokenizer(inpString, escapeChars, true);
+        numTokens = st.countTokens();
+        for (int i = 0; i < numTokens; i++) {
+            String test = st.nextToken();
+            test = (test.equals(escapeChars) ? replaceChars : test);
+            localString += test;
+        }
+        return localString;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java
new file mode 100644
index 0000000..35f8c6c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/DefaultJspCompilerAdapter.java
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.types.CommandlineJava;
+
+/**
+ * This is the default implementation for the JspCompilerAdapter interface.
+ * This is currently very light on the ground since only one compiler type is
+ * supported.
+ *
+ */
+public abstract class DefaultJspCompilerAdapter
+    implements JspCompilerAdapter {
+
+    private static String lSep = System.getProperty("line.separator");
+
+    /**
+     * Logs the compilation parameters, adds the files to compile and logs the
+     * &quot;niceSourceList&quot;
+     * @param jspc the compiler task for logging
+     * @param compileList the list of files to compile
+     * @param cmd the command line used
+     */
+    protected void logAndAddFilesToCompile(JspC jspc,
+                                           Vector compileList,
+                                           CommandlineJava cmd) {
+        jspc.log("Compilation " + cmd.describeJavaCommand(),
+                 Project.MSG_VERBOSE);
+
+        StringBuffer niceSourceList = new StringBuffer("File");
+        if (compileList.size() != 1) {
+            niceSourceList.append("s");
+        }
+        niceSourceList.append(" to be compiled:");
+
+        niceSourceList.append(lSep);
+
+        Enumeration e = compileList.elements();
+        while (e.hasMoreElements()) {
+            String arg = (String) e.nextElement();
+            cmd.createArgument().setValue(arg);
+            niceSourceList.append("    ");
+            niceSourceList.append(arg);
+            niceSourceList.append(lSep);
+        }
+
+        jspc.log(niceSourceList.toString(), Project.MSG_VERBOSE);
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * our owner
+     */
+    protected JspC owner;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * set the owner
+     * @param owner the owner JspC compiler
+     */
+    public void setJspc(JspC owner) {
+        this.owner = owner;
+    }
+
+    /** get the owner
+     * @return the owner; should never be null
+     */
+    public JspC getJspc() {
+        return owner;
+    }
+
+
+    /**
+     *  add an argument oneple to the argument list, if the value aint null
+     * @param cmd the command line
+     * @param  argument  The argument
+     */
+    protected void addArg(CommandlineJava cmd, String argument) {
+        if (argument != null && argument.length() != 0) {
+           cmd.createArgument().setValue(argument);
+        }
+    }
+
+
+    /**
+     *  add an argument tuple to the argument list, if the value aint null
+     * @param cmd the command line
+     * @param  argument  The argument
+     * @param  value     the parameter
+     */
+    protected void addArg(CommandlineJava cmd, String argument, String value) {
+        if (value != null) {
+            cmd.createArgument().setValue(argument);
+            cmd.createArgument().setValue(value);
+        }
+    }
+
+    /**
+     *  add an argument tuple to the arg list, if the file parameter aint null
+     * @param cmd the command line
+     * @param  argument  The argument
+     * @param  file     the parameter
+     */
+    protected void addArg(CommandlineJava cmd, String argument, File file) {
+        if (file != null) {
+            cmd.createArgument().setValue(argument);
+            cmd.createArgument().setFile(file);
+        }
+    }
+
+    /**
+     * ask if compiler can sort out its own dependencies
+     * @return true if the compiler wants to do its own
+     * depends
+     */
+    public boolean implementsOwnDependencyChecking() {
+        return false;
+    }
+
+    /**
+     * get our project
+     * @return owner project data
+     */
+    public Project getProject() {
+        return getJspc().getProject();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java
new file mode 100644
index 0000000..b6f8c58
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JasperC.java
@@ -0,0 +1,181 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import java.io.File;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspMangler;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * The implementation of the jasper compiler.
+ * This is a cut-and-paste of the original Jspc task.
+ *
+ * @since ant1.5
+ */
+public class JasperC extends DefaultJspCompilerAdapter {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * what produces java classes from .jsp files
+     */
+    JspMangler mangler;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for JasperC.
+     * @param mangler a filename converter
+     */
+    public JasperC(JspMangler mangler) {
+        this.mangler = mangler;
+    }
+
+    /**
+     * Our execute method.
+     * @return true if successful
+     * @throws BuildException on error
+     */
+    public boolean execute()
+        throws BuildException {
+        getJspc().log("Using jasper compiler", Project.MSG_VERBOSE);
+        CommandlineJava cmd = setupJasperCommand();
+
+        try {
+            // Create an instance of the compiler, redirecting output to
+            // the project log
+            Java java = new Java(owner);
+            Path p = getClasspath();
+            if (getJspc().getClasspath() != null) {
+                getProject().log("using user supplied classpath: " + p,
+                                 Project.MSG_DEBUG);
+            } else {
+                getProject().log("using system classpath: " + p,
+                                 Project.MSG_DEBUG);
+            }
+            java.setClasspath(p);
+            java.setDir(getProject().getBaseDir());
+            java.setClassname("org.apache.jasper.JspC");
+            //this is really irritating; we need a way to set stuff
+            String []args = cmd.getJavaCommand().getArguments();
+            for (int i = 0; i < args.length; i++) {
+                java.createArg().setValue(args[i]);
+            }
+            java.setFailonerror(getJspc().getFailonerror());
+            //we are forking here to be sure that if JspC calls
+            //System.exit() it doesn't halt the build
+            java.setFork(true);
+            java.setTaskName("jasperc");
+            java.execute();
+            return true;
+        } catch (Exception ex) {
+            if (ex instanceof BuildException) {
+                throw (BuildException) ex;
+            } else {
+                throw new BuildException("Error running jsp compiler: ",
+                                         ex, getJspc().getLocation());
+            }
+        } finally {
+            getJspc().deleteEmptyJavaFiles();
+        }
+    }
+
+
+
+    /**
+     * build up a command line
+     * @return a command line for jasper
+     */
+    private CommandlineJava setupJasperCommand() {
+        CommandlineJava cmd = new CommandlineJava();
+        JspC jspc = getJspc();
+        addArg(cmd, "-d", jspc.getDestdir());
+        addArg(cmd, "-p", jspc.getPackage());
+
+        if (!isTomcat5x()) {
+            addArg(cmd, "-v" + jspc.getVerbose());
+        } else {
+            getProject().log("this task doesn't support Tomcat 5.x properly, "
+                             + "please use the Tomcat provided jspc task "
+                             + "instead");
+        }
+
+        addArg(cmd, "-uriroot", jspc.getUriroot());
+        addArg(cmd, "-uribase", jspc.getUribase());
+        addArg(cmd, "-ieplugin", jspc.getIeplugin());
+        addArg(cmd, "-webinc", jspc.getWebinc());
+        addArg(cmd, "-webxml", jspc.getWebxml());
+        addArg(cmd, "-die9");
+
+        if (jspc.isMapped()) {
+            addArg(cmd, "-mapped");
+        }
+        if (jspc.getWebApp() != null) {
+            File dir = jspc.getWebApp().getDirectory();
+            addArg(cmd, "-webapp", dir);
+        }
+        logAndAddFilesToCompile(getJspc(), getJspc().getCompileList(), cmd);
+        return cmd;
+    }
+
+    /**
+     * @return an instance of the mangler this compiler uses
+     */
+
+    public JspMangler createMangler() {
+        return mangler;
+    }
+
+    /**
+     * @since Ant 1.6.2
+     */
+    private Path getClasspath() {
+        Path p = getJspc().getClasspath();
+        if (p == null) {
+            p = new Path(getProject());
+            return p.concatSystemClasspath("only");
+        } else {
+            return p.concatSystemClasspath("ignore");
+        }
+    }
+
+    /**
+     * @since Ant 1.6.2
+     */
+    private boolean isTomcat5x() {
+        AntClassLoader l = null;
+        try {
+            l = getProject().createClassLoader(getClasspath());
+            l.loadClass("org.apache.jasper.tagplugins.jstl.If");
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        } finally {
+            if (l != null) {
+                l.cleanup();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java
new file mode 100644
index 0000000..56d2e06
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapter.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspC;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspMangler;
+
+/**
+ * The interface that all jsp compiler adapters must adher to.
+ *
+ * <p>A compiler adapter is an adapter that interprets the jspc's
+ * parameters in preperation to be passed off to the compier this
+ * adapter represents.  As all the necessary values are stored in the
+ * Jspc task itself, the only thing all adapters need is the jsp
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ */
+
+public interface JspCompilerAdapter {
+
+    /**
+     * Sets the compiler attributes, which are stored in the Jspc task.
+     * @param attributes the jsp compiler attributes
+     */
+    void setJspc(JspC attributes);
+
+    /**
+     * Executes the task.
+     *
+     * @return has the compilation been successful
+     * @throws BuildException on error
+     */
+    boolean execute() throws BuildException;
+
+    /**
+     * @return an instance of the mangler this compiler uses
+     */
+
+    JspMangler createMangler();
+
+    /**
+     * ask if compiler can sort out its own dependencies
+     * @return true if the compiler wants to do its own
+     * depends
+     */
+    boolean implementsOwnDependencyChecking();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java
new file mode 100644
index 0000000..819a3c1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/jsp/compilers/JspCompilerAdapterFactory.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.jsp.compilers;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspNameMangler;
+import org.apache.tools.ant.taskdefs.optional.jsp.Jasper41Mangler;
+
+
+/**
+ * Creates the necessary compiler adapter, given basic criteria.
+ *
+ */
+public final class JspCompilerAdapterFactory {
+
+    /** This is a singleton -- can't create instances!! */
+    private JspCompilerAdapterFactory() {
+    }
+
+    /**
+     * Based on the parameter passed in, this method creates the necessary
+     * factory desired.
+     *
+     * The current mapping for compiler names are as follows:
+     * <ul><li>jasper = jasper compiler (the default)
+     * <li><i>a fully quallified classname</i> = the name of a jsp compiler
+     * adapter
+     * </ul>
+     *
+     * @param compilerType either the name of the desired compiler, or the
+     * full classname of the compiler's adapter.
+     * @param task a task to log through.
+     * @return the compiler
+     * @throws BuildException if the compiler type could not be resolved into
+     * a compiler adapter.
+     */
+    public static JspCompilerAdapter getCompiler(String compilerType, Task task)
+        throws BuildException {
+        return getCompiler(compilerType, task,
+                           task.getProject().createClassLoader(null));
+    }
+
+    /**
+     * Based on the parameter passed in, this method creates the necessary
+     * factory desired.
+     *
+     * The current mapping for compiler names are as follows:
+     * <ul><li>jasper = jasper compiler (the default)
+     * <li><i>a fully quallified classname</i> = the name of a jsp compiler
+     * adapter
+     * </ul>
+     *
+     * @param compilerType either the name of the desired compiler, or the
+     * full classname of the compiler's adapter.
+     * @param task a task to log through.
+     * @param loader AntClassLoader with which the compiler should be loaded
+     * @return the compiler
+     * @throws BuildException if the compiler type could not be resolved into
+     * a compiler adapter.
+     */
+    public static JspCompilerAdapter getCompiler(String compilerType, Task task,
+                                                 AntClassLoader loader)
+        throws BuildException {
+
+        if (compilerType.equalsIgnoreCase("jasper")) {
+            //tomcat4.0 gets the old mangler
+            return new JasperC(new JspNameMangler());
+        }
+        if (compilerType.equalsIgnoreCase("jasper41")) {
+            //tomcat4.1 gets the new one
+            return new JasperC(new Jasper41Mangler());
+        }
+        return resolveClassName(compilerType, loader);
+    }
+
+    /**
+     * Tries to resolve the given classname into a compiler adapter.
+     * Throws a fit if it can't.
+     *
+     * @param className The fully qualified classname to be created.
+     * @param classloader Classloader with which to load the class
+     * @throws BuildException This is the fit that is thrown if className
+     * isn't an instance of JspCompilerAdapter.
+     */
+    private static JspCompilerAdapter resolveClassName(String className,
+                                                       AntClassLoader classloader)
+        throws BuildException {
+        try {
+            Class c = classloader.findClass(className);
+            Object o = c.newInstance();
+            return (JspCompilerAdapter) o;
+        } catch (ClassNotFoundException cnfe) {
+            throw new BuildException(className + " can\'t be found.", cnfe);
+        } catch (ClassCastException cce) {
+            throw new BuildException(className + " isn\'t the classname of "
+                                     + "a compiler adapter.", cce);
+        } catch (Throwable t) {
+            // for all other possibilities
+            throw new BuildException(className + " caused an interesting "
+                                     + "exception.", t);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
new file mode 100644
index 0000000..4869f97
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/AggregateTransformer.java
@@ -0,0 +1,345 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.URL;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Vector;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.XSLTProcess;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.taskdefs.TempFile;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.types.resources.FileResource;
+
+import org.w3c.dom.Document;
+
+/**
+ * Transform a JUnit xml report.
+ * The default transformation generates an html report in either framed or non-framed
+ * style. The non-framed style is convenient to have a concise report via mail, the
+ * framed report is much more convenient if you want to browse into different
+ * packages or testcases since it is a Javadoc like report.
+ *
+ */
+public class AggregateTransformer {
+    /**
+     * name of the frames format.
+     */
+    public static final String FRAMES = "frames";
+
+    /**
+     * name of the no frames format.
+     */
+    public static final String NOFRAMES = "noframes";
+
+    /**
+     * defines acceptable formats.
+     */
+    public static class Format extends EnumeratedAttribute {
+        /**
+         * list authorized values.
+         * @return authorized values.
+         */
+        public String[] getValues() {
+            return new String[]{FRAMES, NOFRAMES};
+        }
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** Task */
+    protected Task task;
+
+    /** the xml document to process */
+    protected Document document;
+
+    /** the style directory. XSLs should be read from here if necessary */
+    protected File styleDir;
+
+    /** the destination directory, this is the root from where html should be generated */
+    protected File toDir;
+
+    /**
+     * The params that will be sent to the XSL transformation
+     *
+     * @since Ant 1.7
+     */
+    private List params;
+
+    /**
+     * Instance of a utility class to use for file operations.
+     *
+     * @since Ant 1.7
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Used to ensure the uniqueness of a property
+     */
+    private static int counter = 0;
+
+    /** the format to use for the report. Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt> */
+    protected String format = FRAMES;
+
+    /** XML Parser factory */
+    private static DocumentBuilderFactory privateDBFactory;
+
+    /** XML Parser factory accessible to subclasses */
+    protected static DocumentBuilderFactory dbfactory;
+
+    static {
+       privateDBFactory = DocumentBuilderFactory.newInstance();
+       dbfactory = privateDBFactory;
+    }
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * constructor creating the transformer from the junitreport task.
+     * @param task  task delegating to this class
+     */
+    public AggregateTransformer(Task task) {
+        this.task = task;
+        params = new Vector();
+    }
+
+    /**
+     * Get the Document Builder Factory
+     *
+     * @return the DocumentBuilderFactory instance in use
+     */
+    protected static DocumentBuilderFactory getDocumentBuilderFactory() {
+        return privateDBFactory;
+    }
+
+    /**
+     * sets the format.
+     * @param format  Must be <tt>FRAMES</tt> or <tt>NOFRAMES</tt>
+     */
+    public void setFormat(Format format) {
+        this.format = format.getValue();
+    }
+
+    /**
+     * sets the input document.
+     * @param doc input dom tree
+     */
+    public void setXmlDocument(Document doc) {
+        this.document = doc;
+    }
+
+    /**
+     * Set the xml file to be processed. This is a helper if you want
+     * to set the file directly. Much more for testing purposes.
+     * @param xmlfile xml file to be processed
+     * @throws BuildException if the document cannot be parsed.
+     */
+    protected void setXmlfile(File xmlfile) throws BuildException {
+        try {
+            DocumentBuilder builder = privateDBFactory.newDocumentBuilder();
+            InputStream in = new FileInputStream(xmlfile);
+            try {
+                Document doc = builder.parse(in);
+                setXmlDocument(doc);
+            } finally {
+                in.close();
+            }
+        } catch (Exception e) {
+            throw new BuildException("Error while parsing document: " + xmlfile, e);
+        }
+    }
+
+    /**
+     * set the style directory. It is optional and will override the
+     * default xsl used.
+     * @param styledir  the directory containing the xsl files if the user
+     * would like to override with its own style.
+     */
+    public void setStyledir(File styledir) {
+        this.styleDir = styledir;
+    }
+
+    /** set the destination directory.
+     * @param todir the destination directory
+     */
+    public void setTodir(File todir) {
+        this.toDir = todir;
+    }
+
+    /** set the extension of the output files
+     * @param ext extension.
+     */
+    public void setExtension(String ext) {
+        task.log("extension is not used anymore", Project.MSG_WARN);
+    }
+
+    /**
+     * Create an instance of an XSL parameter for configuration by Ant.
+     *
+     * @return an instance of the Param class to be configured.
+     * @since Ant 1.7
+     */
+    public XSLTProcess.Param createParam() {
+        XSLTProcess.Param p = new XSLTProcess.Param();
+        params.add(p);
+        return p;
+    }
+
+    /**
+     * transformation
+     * @throws BuildException exception if something goes wrong with the transformation.
+     */
+    public void transform() throws BuildException {
+        checkOptions();
+        Project project = task.getProject();
+
+        TempFile tempFileTask = new TempFile();
+        tempFileTask.bindToOwner(task);
+
+        XSLTProcess xsltTask = new XSLTProcess();
+        xsltTask.bindToOwner(task);
+
+        xsltTask.setXslResource(getStylesheet());
+
+        // acrobatic cast.
+        xsltTask.setIn(((XMLResultAggregator) task).getDestinationFile());
+        File outputFile = null;
+        if (format.equals(FRAMES)) {
+            String tempFileProperty = getClass().getName() + String.valueOf(counter++);
+            File tmp = FILE_UTILS.resolveFile(project.getBaseDir(), project
+                    .getProperty("java.io.tmpdir"));
+            tempFileTask.setDestDir(tmp);
+            tempFileTask.setProperty(tempFileProperty);
+            tempFileTask.execute();
+            outputFile = new File(project.getProperty(tempFileProperty));
+        } else {
+            outputFile = new File(toDir, "junit-noframes.html");
+        }
+        xsltTask.setOut(outputFile);
+        for (Iterator i = params.iterator(); i.hasNext();) {
+            XSLTProcess.Param param = (XSLTProcess.Param) i.next();
+            XSLTProcess.Param newParam = xsltTask.createParam();
+            newParam.setProject(task.getProject());
+            newParam.setName(param.getName());
+            newParam.setExpression(param.getExpression());
+        }
+        XSLTProcess.Param paramx = xsltTask.createParam();
+        paramx.setProject(task.getProject());
+        paramx.setName("output.dir");
+        paramx.setExpression(toDir.getAbsolutePath());
+        final long t0 = System.currentTimeMillis();
+        try {
+            xsltTask.execute();
+        } catch (Exception e) {
+            throw new BuildException("Errors while applying transformations: " + e.getMessage(), e);
+        }
+        final long dt = System.currentTimeMillis() - t0;
+        task.log("Transform time: " + dt + "ms");
+        if (format.equals(FRAMES)) {
+            Delete delete = new Delete();
+            delete.bindToOwner(task);
+            delete.setFile(outputFile);
+            delete.execute();
+        }
+    }
+
+    /**
+     * access the stylesheet to be used as a resource.
+     * @return stylesheet as a resource
+     */
+    protected Resource getStylesheet() {
+        String xslname = "junit-frames.xsl";
+        if (NOFRAMES.equals(format)) {
+            xslname = "junit-noframes.xsl";
+        }
+        if (styleDir == null) {
+            // If style dir is not specified we have to retrieve
+            // the stylesheet from the classloader
+            URLResource stylesheet = new URLResource();
+            URL stylesheetURL = getClass().getClassLoader().getResource(
+                    "org/apache/tools/ant/taskdefs/optional/junit/xsl/" + xslname);
+            stylesheet.setURL(stylesheetURL);
+            return stylesheet;
+        }
+        // If we are here, then the style dir is here and we
+        // should read the stylesheet from the filesystem
+        FileResource stylesheet = new FileResource();
+        File stylesheetFile = new File(styleDir, xslname);
+        stylesheet.setFile(stylesheetFile);
+        return stylesheet;
+    }
+
+
+    /** check for invalid options
+     * @throws BuildException if something goes wrong.
+     */
+    protected void checkOptions() throws BuildException {
+        // set the destination directory relative from the project if needed.
+        if (toDir == null) {
+            toDir = task.getProject().resolveFile(".");
+        } else if (!toDir.isAbsolute()) {
+            toDir = task.getProject().resolveFile(toDir.getPath());
+        }
+    }
+
+    /**
+     * Get the systemid of the appropriate stylesheet based on its
+     * name and styledir. If no styledir is defined it will load
+     * it as a java resource in the xsl child package, otherwise it
+     * will get it from the given directory.
+     * @return system ID of the stylesheet.
+     * @throws IOException thrown if the requested stylesheet does
+     * not exist.
+     */
+    protected String getStylesheetSystemId() throws IOException {
+        String xslname = "junit-frames.xsl";
+        if (NOFRAMES.equals(format)) {
+            xslname = "junit-noframes.xsl";
+        }
+        if (styleDir == null) {
+            URL url = getClass().getResource("xsl/" + xslname);
+            if (url == null) {
+                throw new FileNotFoundException("Could not find jar resource " + xslname);
+            }
+            return url.toExternalForm();
+        }
+        File file = new File(styleDir, xslname);
+        if (!file.exists()) {
+            throw new FileNotFoundException("Could not find file '" + file + "'");
+        }
+        return JAXPUtils.getSystemId(file);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java
new file mode 100644
index 0000000..13c6c33
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BaseTest.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.util.Vector;
+
+/**
+ * Baseclass for BatchTest and JUnitTest.
+ *
+ */
+public abstract class BaseTest {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean haltOnError = false;
+    protected boolean haltOnFail = false;
+    protected boolean filtertrace = true;
+    protected boolean fork = false;
+    protected String ifProperty = null;
+    protected String unlessProperty = null;
+    protected Vector formatters = new Vector();
+    /** destination directory */
+    protected File destDir = null;
+
+    protected String failureProperty;
+    protected String errorProperty;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the filtertrace attribute.
+     * @param value a <code>boolean</code> value.
+     */
+    public void setFiltertrace(boolean value) {
+        filtertrace = value;
+    }
+
+    /**
+     * Get the filtertrace attribute.
+     * @return the attribute.
+     */
+    public boolean getFiltertrace() {
+        return filtertrace;
+    }
+
+    /**
+     * Set the fork attribute.
+     * @param value a <code>boolean</code> value.
+     */
+    public void setFork(boolean value) {
+        fork = value;
+    }
+
+    /**
+     * Get the fork attribute.
+     * @return the attribute.
+     */
+    public boolean getFork() {
+        return fork;
+    }
+
+    /**
+     * Set the haltonerror attribute.
+     * @param value a <code>boolean</code> value.
+     */
+    public void setHaltonerror(boolean value) {
+        haltOnError = value;
+    }
+
+    /**
+     * Set the haltonfailure attribute.
+     * @param value a <code>boolean</code> value.
+     */
+    public void setHaltonfailure(boolean value) {
+        haltOnFail = value;
+    }
+
+    /**
+     * Get the haltonerror attribute.
+     * @return the attribute.
+     */
+    public boolean getHaltonerror() {
+        return haltOnError;
+    }
+
+    /**
+     * Get the haltonfailure attribute.
+     * @return the attribute.
+     */
+    public boolean getHaltonfailure() {
+        return haltOnFail;
+    }
+
+    /**
+     * Set the if attribute.
+     * If this property is present in project,
+     * the test will be run.
+     * @param propertyName the name of the property to look for.
+     */
+    public void setIf(String propertyName) {
+        ifProperty = propertyName;
+    }
+
+    /**
+     * Set the unless attribute.
+     * If this property is present in project,
+     * the test will *not* be run.
+     * @param propertyName the name of the property to look for.
+     */
+    public void setUnless(String propertyName) {
+        unlessProperty = propertyName;
+    }
+
+    /**
+     * Allow a formatter nested element.
+     * @param elem a formatter nested element.
+     */
+    public void addFormatter(FormatterElement elem) {
+        formatters.addElement(elem);
+    }
+
+    /**
+     * Sets the destination directory.
+     * @param destDir the destination directory.
+     */
+    public void setTodir(File destDir) {
+        this.destDir = destDir;
+    }
+
+    /**
+     * Get the destination directory.
+     * @return the destination directory as an absolute path if it exists
+     *         otherwise return <tt>null</tt>
+     */
+    public String getTodir() {
+        if (destDir != null) {
+            return destDir.getAbsolutePath();
+        }
+        return null;
+    }
+
+    /**
+     * Get the failure property name.
+     * @return the name of the property to set on failure.
+     */
+    public String getFailureProperty() {
+        return failureProperty;
+    }
+
+    /**
+     * Set the name of the failure property.
+     * @param failureProperty the name of the property to set if
+     *                        the test fails.
+     */
+    public void setFailureProperty(String failureProperty) {
+        this.failureProperty = failureProperty;
+    }
+
+    /**
+     * Get the failure property name.
+     * @return the name of the property to set on failure.
+     */
+    public String getErrorProperty() {
+        return errorProperty;
+    }
+
+    /**
+     * Set the name of the error property.
+     * @param errorProperty the name of the property to set if
+     *                      the test has an error.
+     */
+    public void setErrorProperty(String errorProperty) {
+        this.errorProperty = errorProperty;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
new file mode 100644
index 0000000..9da0071
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BatchTest.java
@@ -0,0 +1,202 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Resources;
+
+/**
+ * <p> Create then run <code>JUnitTest</code>'s based on the list of files
+ *     given by the fileset attribute.
+ *
+ * <p> Every <code>.java</code> or <code>.class</code> file in the fileset is
+ * assumed to be a testcase.
+ * A <code>JUnitTest</code> is created for each of these named classes with
+ * basic setup inherited from the parent <code>BatchTest</code>.
+ *
+ * @see JUnitTest
+ */
+public final class BatchTest extends BaseTest {
+
+    /** the reference to the project */
+    private Project project;
+
+    /** the list of filesets containing the testcase filename rules */
+    private Resources resources = new Resources();
+
+    /**
+     * create a new batchtest instance
+     * @param project     the project it depends on.
+     */
+    public BatchTest(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Add a new fileset instance to this batchtest. Whatever the fileset is,
+     * only filename that are <tt>.java</tt> or <tt>.class</tt> will be
+     * considered as 'candidates'.
+     * @param     fs the new fileset containing the rules to get the testcases.
+     */
+    public void addFileSet(FileSet fs) {
+        add(fs);
+
+        // this one is here because the changes to support ResourceCollections
+        // have broken Magic's JUnitTestTask.
+        //
+        // The task adds a FileSet to a BatchTest instance using the
+        // Java API and without telling the FileSet about its project
+        // instance.  The original code would pass in project on the
+        // call to getDirectoryScanner - which is now hidden deep into
+        // Resources.iterator() and not reachable.
+        if (fs.getProject() == null) {
+            fs.setProject(project);
+        }
+    }
+
+
+    /**
+     * Add a new ResourceCollection instance to this
+     * batchtest. Whatever the collection is, only names that are
+     * <tt>.java</tt> or <tt>.class</tt> will be considered as
+     * 'candidates'.
+     * @param rc the new ResourceCollection containing the rules to
+     * get the testcases.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection rc) {
+        resources.add(rc);
+    }
+
+    /**
+     * Return all <tt>JUnitTest</tt> instances obtain by applying the fileset rules.
+     * @return  an enumeration of all elements of this batchtest that are
+     * a <tt>JUnitTest</tt> instance.
+     */
+    public Enumeration elements() {
+        JUnitTest[] tests = createAllJUnitTest();
+        return Enumerations.fromArray(tests);
+    }
+
+    /**
+     * Convenient method to merge the <tt>JUnitTest</tt>s of this batchtest
+     * to a <tt>Vector</tt>.
+     * @param v the vector to which should be added all individual tests of this
+     * batch test.
+     */
+    void addTestsTo(Vector v) {
+        JUnitTest[] tests = createAllJUnitTest();
+        v.ensureCapacity(v.size() + tests.length);
+        for (int i = 0; i < tests.length; i++) {
+            v.addElement(tests[i]);
+        }
+    }
+
+    /**
+     * Create all <tt>JUnitTest</tt>s based on the filesets. Each instance
+     * is configured to match this instance properties.
+     * @return the array of all <tt>JUnitTest</tt>s that belongs to this batch.
+     */
+    private JUnitTest[] createAllJUnitTest() {
+        String[] filenames = getFilenames();
+        JUnitTest[] tests = new JUnitTest[filenames.length];
+        for (int i = 0; i < tests.length; i++) {
+            String classname = javaToClass(filenames[i]);
+            tests[i] = createJUnitTest(classname);
+        }
+        return tests;
+    }
+
+    /**
+     * Iterate over all filesets and return the filename of all files
+     * that end with <tt>.java</tt> or <tt>.class</tt>. This is to avoid
+     * wrapping a <tt>JUnitTest</tt> over an xml file for example. A Testcase
+     * is obviously a java file (compiled or not).
+     * @return an array of filenames without their extension. As they should
+     * normally be taken from their root, filenames should match their fully
+     * qualified class name (If it is not the case it will fail when running the test).
+     * For the class <tt>org/apache/Whatever.class</tt> it will return <tt>org/apache/Whatever</tt>.
+     */
+    private String[] getFilenames() {
+        Vector v = new Vector();
+        Iterator iter = resources.iterator();
+        while (iter.hasNext()) {
+            Resource r = (Resource) iter.next();
+            if (r.isExists()) {
+                String pathname = r.getName();
+                if (pathname.endsWith(".java")) {
+                    v.addElement(pathname.substring(0, pathname.length() - ".java".length()));
+                } else if (pathname.endsWith(".class")) {
+                    v.addElement(pathname.substring(0, pathname.length() - ".class".length()));
+                }
+            }
+        }
+
+        String[] files = new String[v.size()];
+        v.copyInto(files);
+        return files;
+    }
+
+    /**
+     * Convenient method to convert a pathname without extension to a
+     * fully qualified classname. For example <tt>org/apache/Whatever</tt> will
+     * be converted to <tt>org.apache.Whatever</tt>
+     * @param filename the filename to "convert" to a classname.
+     * @return the classname matching the filename.
+     */
+    public static String javaToClass(String filename) {
+        return filename.replace(File.separatorChar, '.').replace('/', '.')
+            .replace('\\', '.');
+    }
+
+    /**
+     * Create a <tt>JUnitTest</tt> that has the same property as this
+     * <tt>BatchTest</tt> instance.
+     * @param classname the name of the class that should be run as a
+     * <tt>JUnitTest</tt>. It must be a fully qualified name.
+     * @return the <tt>JUnitTest</tt> over the given classname.
+     */
+    private JUnitTest createJUnitTest(String classname) {
+        JUnitTest test = new JUnitTest();
+        test.setName(classname);
+        test.setHaltonerror(this.haltOnError);
+        test.setHaltonfailure(this.haltOnFail);
+        test.setFiltertrace(this.filtertrace);
+        test.setFork(this.fork);
+        test.setIf(this.ifProperty);
+        test.setUnless(this.unlessProperty);
+        test.setTodir(this.destDir);
+        test.setFailureProperty(failureProperty);
+        test.setErrorProperty(errorProperty);
+        Enumeration list = this.formatters.elements();
+        while (list.hasMoreElements()) {
+            test.addFormatter((FormatterElement) list.nextElement());
+        }
+        return test;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java
new file mode 100644
index 0000000..3299227
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/BriefJUnitResultFormatter.java
@@ -0,0 +1,251 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ * Inspired by the PlainJUnitResultFormatter.
+ *
+ * @see FormatterElement
+ * @see PlainJUnitResultFormatter
+ */
+public class BriefJUnitResultFormatter implements JUnitResultFormatter {
+
+    private static final double ONE_SECOND = 1000.0;
+
+    /**
+     * Where to write the log to.
+     */
+    private OutputStream out;
+
+    /**
+     * Used for writing the results.
+     */
+    private PrintWriter output;
+
+    /**
+     * Used as part of formatting the results.
+     */
+    private StringWriter results;
+
+    /**
+     * Used for writing formatted results to.
+     */
+    private PrintWriter resultWriter;
+
+    /**
+     * Formatter for timings.
+     */
+    private NumberFormat numberFormat = NumberFormat.getInstance();
+
+    /**
+     * Output suite has written to System.out
+     */
+    private String systemOutput = null;
+
+    /**
+     * Output suite has written to System.err
+     */
+    private String systemError = null;
+
+    /**
+     * Constructor for BriefJUnitResultFormatter.
+     */
+    public BriefJUnitResultFormatter() {
+        results = new StringWriter();
+        resultWriter = new PrintWriter(results);
+    }
+
+    /**
+     * Sets the stream the formatter is supposed to write its results to.
+     * @param out the output stream to write to
+     */
+    public void setOutput(OutputStream out) {
+        this.out = out;
+        output = new PrintWriter(out);
+    }
+
+    /**
+     * @see JUnitResultFormatter#setSystemOutput(String)
+     */
+    /** {@inheritDoc}. */
+    public void setSystemOutput(String out) {
+        systemOutput = out;
+    }
+
+    /**
+     * @see JUnitResultFormatter#setSystemError(String)
+     */
+    /** {@inheritDoc}. */
+    public void setSystemError(String err) {
+        systemError = err;
+    }
+
+
+    /**
+     * The whole testsuite started.
+     * @param suite the test suite
+     */
+    public void startTestSuite(JUnitTest suite) {
+        if (output == null) {
+            return; // Quick return - no output do nothing.
+        }
+        StringBuffer sb = new StringBuffer("Testsuite: ");
+        sb.append(suite.getName());
+        sb.append(StringUtils.LINE_SEP);
+        output.write(sb.toString());
+        output.flush();
+    }
+
+    /**
+     * The whole testsuite ended.
+     * @param suite the test suite
+     */
+    public void endTestSuite(JUnitTest suite) {
+        StringBuffer sb = new StringBuffer("Tests run: ");
+        sb.append(suite.runCount());
+        sb.append(", Failures: ");
+        sb.append(suite.failureCount());
+        sb.append(", Errors: ");
+        sb.append(suite.errorCount());
+        sb.append(", Time elapsed: ");
+        sb.append(numberFormat.format(suite.getRunTime() / ONE_SECOND));
+        sb.append(" sec");
+        sb.append(StringUtils.LINE_SEP);
+        sb.append(StringUtils.LINE_SEP);
+
+        // append the err and output streams to the log
+        if (systemOutput != null && systemOutput.length() > 0) {
+            sb.append("------------- Standard Output ---------------")
+                    .append(StringUtils.LINE_SEP)
+                    .append(systemOutput)
+                    .append("------------- ---------------- ---------------")
+                    .append(StringUtils.LINE_SEP);
+        }
+
+        if (systemError != null && systemError.length() > 0) {
+            sb.append("------------- Standard Error -----------------")
+                    .append(StringUtils.LINE_SEP)
+                    .append(systemError)
+                    .append("------------- ---------------- ---------------")
+                    .append(StringUtils.LINE_SEP);
+        }
+
+        if (output != null) {
+            try {
+                output.write(sb.toString());
+                resultWriter.close();
+                output.write(results.toString());
+                output.flush();
+            } finally {
+                if (out != System.out && out != System.err) {
+                    FileUtils.close(out);
+                }
+            }
+        }
+    }
+
+    /**
+     * A test started.
+     * @param test a test
+     */
+    public void startTest(Test test) {
+    }
+
+    /**
+     * A test ended.
+     * @param test a test
+     */
+    public void endTest(Test test) {
+    }
+
+    /**
+     * Interface TestListener for JUnit &lt;= 3.4.
+     *
+     * <p>A Test failed.
+     * @param test a test
+     * @param t    the exception thrown by the test
+     */
+    public void addFailure(Test test, Throwable t) {
+        formatError("\tFAILED", test, t);
+    }
+
+    /**
+     * Interface TestListener for JUnit &gt; 3.4.
+     *
+     * <p>A Test failed.
+     * @param test a test
+     * @param t    the assertion failed by the test
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        addFailure(test, (Throwable) t);
+    }
+
+    /**
+     * A test caused an error.
+     * @param test  a test
+     * @param error the error thrown by the test
+     */
+    public void addError(Test test, Throwable error) {
+        formatError("\tCaused an ERROR", test, error);
+    }
+
+    /**
+     * Format the test for printing..
+     * @param test a test
+     * @return the formatted testname
+     */
+    protected String formatTest(Test test) {
+        if (test == null) {
+            return "Null Test: ";
+        } else {
+            return "Testcase: " + test.toString() + ":";
+        }
+    }
+
+    /**
+     * Format an error and print it.
+     * @param type the type of error
+     * @param test the test that failed
+     * @param error the exception that the test threw
+     */
+    protected synchronized void formatError(String type, Test test,
+                                            Throwable error) {
+        if (test != null) {
+            endTest(test);
+        }
+
+        resultWriter.println(formatTest(test) + type);
+        resultWriter.println(error.getMessage());
+        String strace = JUnitTestRunner.getFilteredTrace(error);
+        resultWriter.println(strace);
+        resultWriter.println();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
new file mode 100644
index 0000000..cee68e3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * Constants, like filenames shared between various classes in this package.
+ */
+public class Constants {
+
+    static final String HALT_ON_ERROR = "haltOnError=";
+    static final String HALT_ON_FAILURE = "haltOnFailure=";
+    static final String FILTERTRACE = "filtertrace=";
+    static final String CRASHFILE = "crashfile=";
+    static final String BEFORE_FIRST_TEST = "BeforeFirstTest";
+    static final String PROPSFILE = "propsfile=";
+    static final String SHOWOUTPUT = "showoutput=";
+    static final String OUTPUT_TO_FORMATTERS = "outputtoformatters=";
+    static final String FORMATTER = "formatter=";
+    static final String LOGTESTLISTENEREVENTS = "logtestlistenerevents=";
+    static final String TESTSFILE = "testsfile=";
+    static final String TERMINATED_SUCCESSFULLY = "terminated successfully";
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java
new file mode 100644
index 0000000..1b5b024
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/DOMUtil.java
@@ -0,0 +1,227 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Vector;
+import org.w3c.dom.Attr;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Comment;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+
+/**
+ * Some utilities that might be useful when manipulating DOM trees.
+ *
+ */
+public final class DOMUtil {
+
+    /** unused constructor */
+    private DOMUtil() {
+    }
+
+    /**
+     * Filter interface to be applied when iterating over a DOM tree.
+     * Just think of it like a <tt>FileFilter</tt> clone.
+     */
+    public interface NodeFilter {
+        /**
+         * @param       node    the node to check for acceptance.
+         * @return      <tt>true</tt> if the node is accepted by this filter,
+         *                      otherwise <tt>false</tt>
+         */
+        boolean accept(Node node);
+    }
+
+    /**
+     * list a set of node that match a specific filter. The list can be made
+     * recursively or not.
+     * @param   parent  the parent node to search from
+     * @param   filter  the filter that children should match.
+     * @param   recurse <tt>true</tt> if you want the list to be made recursively
+     *                  otherwise <tt>false</tt>.
+     * @return the node list that matches the filter.
+     */
+    public static NodeList listChildNodes(Node parent, NodeFilter filter, boolean recurse) {
+        NodeListImpl matches = new NodeListImpl();
+        NodeList children = parent.getChildNodes();
+        if (children != null) {
+            final int len = children.getLength();
+            for (int i = 0; i < len; i++) {
+                Node child = children.item(i);
+                if (filter.accept(child)) {
+                    matches.addElement(child);
+                }
+                if (recurse) {
+                    NodeList recmatches = listChildNodes(child, filter, recurse);
+                    final int reclength = recmatches.getLength();
+                    for (int j = 0; j < reclength; j++) {
+                        matches.addElement(recmatches.item(i));
+                    }
+                }
+            }
+        }
+        return matches;
+    }
+
+    /** custom implementation of a nodelist */
+    public static class NodeListImpl extends Vector implements NodeList {
+        private static final long serialVersionUID = 3175749150080946423L;
+
+        /**
+         * Get the number of nodes in the list.
+         * @return the length of the list.
+         */
+        public int getLength() {
+            return size();
+        }
+        /**
+         * Get a particular node.
+         * @param i the index of the node to get.
+         * @return the node if the index is in bounds, null otherwise.
+         */
+        public Node item(int i) {
+            try {
+                return (Node) elementAt(i);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                return null; // conforming to NodeList interface
+            }
+        }
+    }
+
+    /**
+     * return the attribute value of an element.
+     * @param node the node to get the attribute from.
+     * @param name the name of the attribute we are looking for the value.
+     * @return the value of the requested attribute or <tt>null</tt> if the
+     *         attribute was not found or if <tt>node</tt> is not an <tt>Element</tt>.
+     */
+    public static String getNodeAttribute(Node node, String name) {
+        if (node instanceof Element) {
+            Element element = (Element) node;
+            return element.getAttribute(name);
+        }
+        return null;
+    }
+
+
+    /**
+     * Iterate over the children of a given node and return the first node
+     * that has a specific name.
+     * @param   parent  the node to search child from. Can be <tt>null</tt>.
+     * @param   tagname the child name we are looking for. Cannot be <tt>null</tt>.
+     * @return  the first child that matches the given name or <tt>null</tt> if
+     *                  the parent is <tt>null</tt> or if a child does not match the
+     *                  given name.
+     */
+    public static Element getChildByTagName (Node parent, String tagname) {
+        if (parent == null) {
+            return null;
+        }
+        NodeList childList = parent.getChildNodes();
+        final int len = childList.getLength();
+        for (int i = 0; i < len; i++) {
+            Node child = childList.item(i);
+            if (child != null && child.getNodeType() == Node.ELEMENT_NODE
+                && child.getNodeName().equals(tagname)) {
+                return (Element) child;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Simple tree walker that will clone recursively a node. This is to
+     * avoid using parser-specific API such as Sun's <tt>changeNodeOwner</tt>
+     * when we are dealing with DOM L1 implementations since <tt>cloneNode(boolean)</tt>
+     * will not change the owner document.
+     * <tt>changeNodeOwner</tt> is much faster and avoid the costly cloning process.
+     * <tt>importNode</tt> is in the DOM L2 interface.
+     * @param   parent  the node parent to which we should do the import to.
+     * @param   child   the node to clone recursively. Its clone will be
+     *              appended to <tt>parent</tt>.
+     * @return  the cloned node that is appended to <tt>parent</tt>
+     */
+    public static Node importNode(Node parent, Node child) {
+        Node copy = null;
+        final Document doc = parent.getOwnerDocument();
+
+        switch (child.getNodeType()) {
+        case Node.CDATA_SECTION_NODE:
+            copy = doc.createCDATASection(((CDATASection) child).getData());
+            break;
+        case Node.COMMENT_NODE:
+            copy = doc.createComment(((Comment) child).getData());
+            break;
+        case Node.DOCUMENT_FRAGMENT_NODE:
+            copy = doc.createDocumentFragment();
+            break;
+        case Node.ELEMENT_NODE:
+            final Element elem = doc.createElement(((Element) child).getTagName());
+            copy = elem;
+            final NamedNodeMap attributes = child.getAttributes();
+            if (attributes != null) {
+                final int size = attributes.getLength();
+                for (int i = 0; i < size; i++) {
+                    final Attr attr = (Attr) attributes.item(i);
+                    elem.setAttribute(attr.getName(), attr.getValue());
+                }
+            }
+            break;
+        case Node.ENTITY_REFERENCE_NODE:
+            copy = doc.createEntityReference(child.getNodeName());
+            break;
+        case Node.PROCESSING_INSTRUCTION_NODE:
+            final ProcessingInstruction pi = (ProcessingInstruction) child;
+            copy = doc.createProcessingInstruction(pi.getTarget(), pi.getData());
+            break;
+        case Node.TEXT_NODE:
+            copy = doc.createTextNode(((Text) child).getData());
+            break;
+        default:
+            // this should never happen
+            throw new IllegalStateException("Invalid node type: " + child.getNodeType());
+        }
+
+        // okay we have a copy of the child, now the child becomes the parent
+        // and we are iterating recursively over its children.
+        try {
+            final NodeList children = child.getChildNodes();
+            if (children != null) {
+                final int size = children.getLength();
+                for (int i = 0; i < size; i++) {
+                    final Node newChild = children.item(i);
+                    if (newChild != null) {
+                        importNode(copy, newChild);
+                    }
+                }
+            }
+        } catch (DOMException ignored) {
+            // Ignore
+        }
+
+        // bingo append it. (this should normally not be done here)
+        parent.appendChild(copy);
+        return copy;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java
new file mode 100644
index 0000000..327547e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Enumerations.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * A couple of methods related to enumerations that might be useful.
+ * This class should probably disappear once the required JDK is set to 1.2
+ * instead of 1.1.
+ *
+ */
+public final class Enumerations {
+
+        private Enumerations() {
+        }
+
+        /**
+         * creates an enumeration from an array of objects.
+         * @param       array   the array of object to enumerate.
+         * @return the enumeration over the array of objects.
+         */
+        public static Enumeration fromArray(Object[] array) {
+                return new ArrayEnumeration(array);
+        }
+
+        /**
+        * creates an enumeration from an array of enumeration. The created enumeration
+        * will sequentially enumerate over all elements of each enumeration and skip
+        * <tt>null</tt> enumeration elements in the array.
+        * @param        enums   the array of enumerations.
+        * @return the enumeration over the array of enumerations.
+         */
+        public static Enumeration fromCompound(Enumeration[] enums) {
+                return new CompoundEnumeration(enums);
+        }
+
+}
+
+
+/**
+ * Convenient enumeration over an array of objects.
+ */
+class ArrayEnumeration implements Enumeration {
+
+        /** object array */
+        private Object[] array;
+
+        /** current index */
+        private int pos;
+
+        /**
+         * Initialize a new enumeration that wraps an array.
+         * @param       array   the array of object to enumerate.
+         */
+        public ArrayEnumeration(Object[] array) {
+                this.array = array;
+                this.pos = 0;
+        }
+        /**
+         * Tests if this enumeration contains more elements.
+         *
+         * @return  <code>true</code> if and only if this enumeration object
+         *           contains at least one more element to provide;
+         *          <code>false</code> otherwise.
+         */
+        public boolean hasMoreElements() {
+                return (pos < array.length);
+        }
+
+        /**
+         * Returns the next element of this enumeration if this enumeration
+         * object has at least one more element to provide.
+         *
+         * @return     the next element of this enumeration.
+         * @throws  NoSuchElementException  if no more elements exist.
+         */
+        public Object nextElement() throws NoSuchElementException {
+                if (hasMoreElements()) {
+                        Object o = array[pos];
+                        pos++;
+                        return o;
+                }
+                throw new NoSuchElementException();
+        }
+}
+/**
+ * Convenient enumeration over an array of enumeration. For example:
+ * <pre>
+ * Enumeration e1 = v1.elements();
+ * while (e1.hasMoreElements()) {
+ *    // do something
+ * }
+ * Enumeration e2 = v2.elements();
+ * while (e2.hasMoreElements()) {
+ *    // do the same thing
+ * }
+ * </pre>
+ * can be written as:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), v2.elements() };
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()) {
+ *    // do something
+ * }
+ * </pre>
+ * Note that the enumeration will skip null elements in the array. The following is
+ * thus possible:
+ * <pre>
+ * Enumeration[] enums = { v1.elements(), null, v2.elements() }; // a null enumeration in the array
+ * Enumeration e = Enumerations.fromCompound(enums);
+ * while (e.hasMoreElements()) {
+ *    // do something
+ * }
+ * </pre>
+ */
+ class CompoundEnumeration implements Enumeration {
+
+        /** enumeration array */
+        private Enumeration[] enumArray;
+
+        /** index in the enums array */
+        private int index = 0;
+
+    public CompoundEnumeration(Enumeration[] enumarray) {
+                this.enumArray = enumarray;
+    }
+
+        /**
+         * Tests if this enumeration contains more elements.
+         *
+         * @return  <code>true</code> if and only if this enumeration object
+         *           contains at least one more element to provide;
+         *          <code>false</code> otherwise.
+         */
+    public boolean hasMoreElements() {
+                while (index < enumArray.length) {
+                        if (enumArray[index] != null && enumArray[index].hasMoreElements()) {
+                                return true;
+                        }
+                        index++;
+                }
+                return false;
+    }
+
+        /**
+         * Returns the next element of this enumeration if this enumeration
+         * object has at least one more element to provide.
+         *
+         * @return     the next element of this enumeration.
+         * @throws  NoSuchElementException  if no more elements exist.
+         */
+    public Object nextElement() throws NoSuchElementException {
+                if (hasMoreElements()) {
+                        return enumArray[index].nextElement();
+                }
+                throw new NoSuchElementException();
+    }
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java
new file mode 100644
index 0000000..dc80abf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FailureRecorder.java
@@ -0,0 +1,421 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+package org.apache.tools.ant.taskdefs.optional.junit;

+

+import java.io.File;

+import java.io.FileNotFoundException;

+import java.io.FileOutputStream;

+import java.io.OutputStream;

+import java.io.PrintWriter;

+import java.text.SimpleDateFormat;

+import java.util.Date;

+import java.util.Iterator;

+import java.util.SortedSet;

+import java.util.TreeSet;

+import java.util.Vector;

+

+import junit.framework.AssertionFailedError;

+import junit.framework.Test;

+

+import org.apache.tools.ant.BuildEvent;

+import org.apache.tools.ant.BuildException;

+import org.apache.tools.ant.BuildListener;

+import org.apache.tools.ant.Project;

+import org.apache.tools.ant.types.DataType;

+import org.apache.tools.ant.util.FileUtils;

+

+/**

+ * <p>Collects all failing test <i>cases</i> and creates a new JUnit test class containing

+ * a suite() method which calls these failed tests.</p>

+ * <p>Having classes <i>A</i> ... <i>D</i> with each several testcases you could earn a new

+ * test class like

+ * <pre>

+ * // generated on: 2007.08.06 09:42:34,555

+ * import junit.framework.*;

+ * public class FailedTests extends TestCase {

+ *     public FailedTests(String testname) {

+ *         super(testname);

+ *     }

+ *     public static Test suite() {

+ *         TestSuite suite = new TestSuite();

+ *         suite.addTest( new B("test04") );

+ *         suite.addTest( new org.D("test10") );

+ *         return suite;

+ *     }

+ * }

+ * </pre>

+ *

+ * Because each running test case gets its own formatter, we collect

+ * the failing test cases in a static list. Because we dont have a finalizer

+ * method in the formatters "lifecycle", we register this formatter as

+ * BuildListener and generate the new java source on taskFinished event.

+ *

+ * @since Ant 1.8.0

+ */

+public class FailureRecorder extends DataType implements JUnitResultFormatter, BuildListener {

+

+    /**

+     * This is the name of a magic System property ({@value}). The value of this

+     * <b>System</b> property should point to the location where to store the

+     * generated class (without suffix).

+     * Default location and name is defined in DEFAULT_CLASS_LOCATION.

+     * @see #DEFAULT_CLASS_LOCATION

+     */

+    public static final String MAGIC_PROPERTY_CLASS_LOCATION

+        = "ant.junit.failureCollector";

+

+    /** Default location and name for the generated JUnit class file. {@value} */

+    public static final String DEFAULT_CLASS_LOCATION

+        = System.getProperty("java.io.tmpdir") + "FailedTests";

+

+    /** Prefix for logging. {@value} */

+    private static final String LOG_PREFIX = "    [junit]";

+

+    /** Class names of failed tests without duplicates. */

+    private static SortedSet/*<TestInfos>*/ failedTests = new TreeSet();

+

+    /** A writer for writing the generated source to. */

+    private PrintWriter writer;

+

+    /**

+     * Location and name of the generated JUnit class.

+     * Lazy instantiated via getLocationName().

+     */

+    private static String locationName;

+

+    /**

+     * Returns the (lazy evaluated) location for the collector class.

+     * Order for evaluation: System property > Ant property > default value

+     * @return location for the collector class

+     * @see #MAGIC_PROPERTY_CLASS_LOCATION

+     * @see #DEFAULT_CLASS_LOCATION

+     */

+    private String getLocationName() {

+        if (locationName == null) {

+            String syspropValue = System.getProperty(MAGIC_PROPERTY_CLASS_LOCATION);

+            String antpropValue = getProject().getProperty(MAGIC_PROPERTY_CLASS_LOCATION);

+

+            if (syspropValue != null) {

+                locationName = syspropValue;

+                verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use "

+                        + "its value '" + syspropValue + "' as location for collector class.");

+            } else if (antpropValue != null) {

+                locationName = antpropValue;

+                verbose("Ant property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' set, so use "

+                        + "its value '" + antpropValue + "' as location for collector class.");

+            } else {

+                locationName = DEFAULT_CLASS_LOCATION;

+                verbose("System property '" + MAGIC_PROPERTY_CLASS_LOCATION + "' not set, so use "

+                        + "value as location for collector class: '"

+                        + DEFAULT_CLASS_LOCATION + "'");

+            }

+

+            File locationFile = new File(locationName);

+            if (!locationFile.isAbsolute()) {

+                File f = new File(getProject().getBaseDir(), locationName);

+                locationName = f.getAbsolutePath();

+                verbose("Location file is relative (" + locationFile + ")"

+                        + " use absolute path instead (" + locationName + ")");

+            }

+        }

+

+        return locationName;

+    }

+

+    /**

+     * This method is called by the Ant runtime by reflection. We use the project reference for

+     * registration of this class as BuildListener.

+     *

+     * @param project

+     *            project reference

+     */

+    public void setProject(Project project) {

+        // store project reference for logging

+        super.setProject(project);

+        // check if already registered

+        boolean alreadyRegistered = false;

+        Vector allListeners = project.getBuildListeners();

+        for (int i = 0; i < allListeners.size(); i++) {

+            Object listener = allListeners.get(i);

+            if (listener instanceof FailureRecorder) {

+                alreadyRegistered = true;

+                continue;

+            }

+        }

+        // register if needed

+        if (!alreadyRegistered) {

+            verbose("Register FailureRecorder (@" + this.hashCode() + ") as BuildListener");

+            project.addBuildListener(this);

+        }

+    }

+

+    // ===== JUnitResultFormatter =====

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void endTestSuite(JUnitTest suite) throws BuildException {

+    }

+

+    /**

+     * Add the failed test to the list.

+     * @param test the test that errored.

+     * @param throwable the reason it errored.

+     * @see junit.framework.TestListener#addError(junit.framework.Test, java.lang.Throwable)

+     */

+    public void addError(Test test, Throwable throwable) {

+        failedTests.add(new TestInfos(test));

+    }

+

+    // CheckStyle:LineLengthCheck OFF - @see is long

+    /**

+     * Add the failed test to the list.

+     * @param test the test that failed.

+     * @param error the assertion that failed.

+     * @see junit.framework.TestListener#addFailure(junit.framework.Test, junit.framework.AssertionFailedError)

+     */

+    // CheckStyle:LineLengthCheck ON

+    public void addFailure(Test test, AssertionFailedError error) {

+        failedTests.add(new TestInfos(test));

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void setOutput(OutputStream out) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void setSystemError(String err) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void setSystemOutput(String out) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void startTestSuite(JUnitTest suite) throws BuildException {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void endTest(Test test) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void startTest(Test test) {

+    }

+

+    // ===== "Templates" for generating the JUnit class =====

+

+    private void writeJavaClass() {

+        try {

+            File sourceFile = new File((getLocationName() + ".java"));

+            verbose("Write collector class to '" + sourceFile.getAbsolutePath() + "'");

+

+            sourceFile.delete();

+            writer = new PrintWriter(new FileOutputStream(sourceFile));

+

+            createClassHeader();

+            createSuiteMethod();

+            createClassFooter();

+

+            FileUtils.close(writer);

+        } catch (FileNotFoundException e) {

+            e.printStackTrace();

+        }

+    }

+

+    private void createClassHeader() {

+        String className = getLocationName().replace('\\', '/');

+        if (className.indexOf('/') > -1) {

+            className = className.substring(className.lastIndexOf('/') + 1);

+        }

+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS");

+        writer.print("// generated on: ");

+        writer.println(sdf.format(new Date()));

+        writer.println("import junit.framework.*;");

+        writer.print("public class ");

+        writer.print(className);

+        // If this class does not extend TC, Ant doesnt run these

+        writer.println(" extends TestCase {");

+        // standard String-constructor

+        writer.print("    public ");

+        writer.print(className);

+        writer.println("(String testname) {");

+        writer.println("        super(testname);");

+        writer.println("    }");

+    }

+

+    private void createSuiteMethod() {

+        writer.println("    public static Test suite() {");

+        writer.println("        TestSuite suite = new TestSuite();");

+        for (Iterator iter = failedTests.iterator(); iter.hasNext();) {

+            TestInfos testInfos = (TestInfos) iter.next();

+            writer.print("        suite.addTest(");

+            writer.print(testInfos);

+            writer.println(");");

+        }

+        writer.println("        return suite;");

+        writer.println("    }");

+    }

+

+    private void createClassFooter() {

+        writer.println("}");

+    }

+

+    // ===== Helper classes and methods =====

+

+    /**

+     * Logging facade in INFO-mode.

+     * @param message Log-message

+     */

+    public void log(String message) {

+        getProject().log(LOG_PREFIX + " " + message, Project.MSG_INFO);

+    }

+

+    /**

+     * Logging facade in VERBOSE-mode.

+     * @param message Log-message

+     */

+    public void verbose(String message) {

+        getProject().log(LOG_PREFIX + " " + message, Project.MSG_VERBOSE);

+    }

+

+    /**

+     * TestInfos holds information about a given test for later use.

+     */

+    public class TestInfos implements Comparable {

+

+        /** The class name of the test. */

+        private String className;

+

+        /** The method name of the testcase. */

+        private String methodName;

+

+        /**

+         * This constructor extracts the needed information from the given test.

+         * @param test Test to analyze

+         */

+        public TestInfos(Test test) {

+            className = test.getClass().getName();

+            methodName = test.toString();

+            methodName = methodName.substring(0, methodName.indexOf('('));

+        }

+

+        /**

+         * This String-Representation can directly be used for instantiation of

+         * the JUnit testcase.

+         * @return the string representation.

+         * @see java.lang.Object#toString()

+         * @see FailureRecorder#createSuiteMethod()

+         */

+        public String toString() {

+            return "new " + className + "(\"" + methodName + "\")";

+        }

+

+        /**

+         * The SortedMap needs comparable elements.

+         * @param other the object to compare to.

+         * @return the result of the comparison.

+         * @see java.lang.Comparable#compareTo(T)

+         * @see SortedSet#comparator()

+         */

+        public int compareTo(Object other) {

+            if (other instanceof TestInfos) {

+                TestInfos otherInfos = (TestInfos) other;

+                return toString().compareTo(otherInfos.toString());

+            } else {

+                return -1;

+            }

+        }

+    }

+

+    // ===== BuildListener =====

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void buildFinished(BuildEvent event) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void buildStarted(BuildEvent event) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void messageLogged(BuildEvent event) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void targetFinished(BuildEvent event) {

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void targetStarted(BuildEvent event) {

+    }

+

+    /**

+     * The task outside of this JUnitResultFormatter is the <junit> task. So all tests passed

+     * and we could create the new java class.

+     * @param event  not used

+     * @see org.apache.tools.ant.BuildListener#taskFinished(org.apache.tools.ant.BuildEvent)

+     */

+    public void taskFinished(BuildEvent event) {

+        if (!failedTests.isEmpty()) {

+            writeJavaClass();

+        }

+    }

+

+    /**

+     * Not used

+     * {@inheritDoc}

+     */

+    public void taskStarted(BuildEvent event) {

+    }

+

+}

diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java
new file mode 100644
index 0000000..2a8a977
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/FormatterElement.java
@@ -0,0 +1,333 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.BufferedOutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * <p> A wrapper for the implementations of <code>JUnitResultFormatter</code>.
+ * In particular, used as a nested <code>&lt;formatter&gt;</code> element in
+ * a <code>&lt;junit&gt;</code> task.
+ * <p> For example,
+ * <code><pre>
+ *       &lt;junit printsummary="no" haltonfailure="yes" fork="false"&gt;
+ *           &lt;formatter type="plain" usefile="false" /&gt;
+ *           &lt;test name="org.apache.ecs.InternationalCharTest" /&gt;
+ *       &lt;/junit&gt;</pre></code>
+ * adds a <code>plain</code> type implementation
+ * (<code>PlainJUnitResultFormatter</code>) to display the results of the test.
+ *
+ * <p> Either the <code>type</code> or the <code>classname</code> attribute
+ * must be set.
+ *
+ * @see JUnitTask
+ * @see XMLJUnitResultFormatter
+ * @see BriefJUnitResultFormatter
+ * @see PlainJUnitResultFormatter
+ * @see FailureRecorder
+ * @see JUnitResultFormatter
+ */
+public class FormatterElement {
+
+    private String classname;
+    private String extension;
+    private OutputStream out = System.out;
+    private File outFile;
+    private boolean useFile = true;
+    private String ifProperty;
+    private String unlessProperty;
+
+    /**
+     * Store the project reference for passing it to nested components.
+     * @since Ant 1.8
+     */
+    private Project project;
+
+    /** xml formatter class */
+    public static final String XML_FORMATTER_CLASS_NAME =
+        "org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter";
+    /** brief formatter class */
+    public static final String BRIEF_FORMATTER_CLASS_NAME =
+        "org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter";
+    /** plain formatter class */
+    public static final String PLAIN_FORMATTER_CLASS_NAME =
+        "org.apache.tools.ant.taskdefs.optional.junit.PlainJUnitResultFormatter";
+    /** failure recorder class */
+    public static final String FAILURE_RECORDER_CLASS_NAME =
+        "org.apache.tools.ant.taskdefs.optional.junit.FailureRecorder";
+
+    /**
+     * <p> Quick way to use a standard formatter.
+     *
+     * <p> At the moment, there are three supported standard formatters.
+     * <ul>
+     * <li> The <code>xml</code> type uses a <code>XMLJUnitResultFormatter</code>.
+     * <li> The <code>brief</code> type uses a <code>BriefJUnitResultFormatter</code>.
+     * <li> The <code>plain</code> type (the default) uses a <code>PlainJUnitResultFormatter</code>.
+     * <li> The <code>failure</code> type uses a <code>FailureRecorder</code>.
+     * </ul>
+     *
+     * <p> Sets <code>classname</code> attribute - so you can't use that
+     * attribute if you use this one.
+     * @param type the enumerated value to use.
+     */
+    public void setType(TypeAttribute type) {
+        if ("xml".equals(type.getValue())) {
+            setClassname(XML_FORMATTER_CLASS_NAME);
+        } else {
+            if ("brief".equals(type.getValue())) {
+                setClassname(BRIEF_FORMATTER_CLASS_NAME);
+            } else {
+                if ("failure".equals(type.getValue())) {
+                    setClassname(FAILURE_RECORDER_CLASS_NAME);
+                } else { // must be plain, ensured by TypeAttribute
+                    setClassname(PLAIN_FORMATTER_CLASS_NAME);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p> Set name of class to be used as the formatter.
+     *
+     * <p> This class must implement <code>JUnitResultFormatter</code>
+     * @param classname the name of the formatter class.
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+        if (XML_FORMATTER_CLASS_NAME.equals(classname)) {
+           setExtension(".xml");
+        } else if (PLAIN_FORMATTER_CLASS_NAME.equals(classname)) {
+           setExtension(".txt");
+        } else if (BRIEF_FORMATTER_CLASS_NAME.equals(classname)) {
+           setExtension(".txt");
+        }
+    }
+
+    /**
+     * Get name of class to be used as the formatter.
+     * @return the name of the class.
+     */
+    public String getClassname() {
+        return classname;
+    }
+
+    /**
+     * Set the extension to use for the report file.
+     * @param ext the extension to use.
+     */
+    public void setExtension(String ext) {
+        this.extension = ext;
+    }
+
+    /**
+     * Get the extension used for the report file.
+     * @return the extension.
+     */
+    public String getExtension() {
+        return extension;
+    }
+
+    /**
+     * <p> Set the file which the formatte should log to.
+     *
+     * <p> Note that logging to file must be enabled .
+     */
+    void setOutfile(File out) {
+        this.outFile = out;
+    }
+
+    /**
+     * <p> Set output stream for formatter to use.
+     *
+     * <p> Defaults to standard out.
+     * @param out the output stream to use.
+     */
+    public void setOutput(OutputStream out) {
+        this.out = out;
+    }
+
+    /**
+     * Set whether the formatter should log to file.
+     * @param useFile if true use a file, if false send
+     *                to standard out.
+     */
+    public void setUseFile(boolean useFile) {
+        this.useFile = useFile;
+    }
+
+    /**
+     * Get whether the formatter should log to file.
+     */
+    boolean getUseFile() {
+        return useFile;
+    }
+
+    /**
+     * Set whether this formatter should be used.  It will be
+     * used if the property has been set, otherwise it won't.
+     * @param ifProperty name of property
+     */
+    public void setIf(String ifProperty) {
+        this.ifProperty = ifProperty;
+    }
+
+    /**
+     * Set whether this formatter should NOT be used. It
+     * will not be used if the property has been set, orthwise it
+     * will be used.
+     * @param unlessProperty name of property
+     */
+    public void setUnless(String unlessProperty) {
+        this.unlessProperty = unlessProperty;
+    }
+
+    /**
+     * Ensures that the selector passes the conditions placed
+     * on it with <code>if</code> and <code>unless</code> properties.
+     * @param t the task the this formatter is used in.
+     * @return true if the formatter should be used.
+     */
+    public boolean shouldUse(Task t) {
+        if (ifProperty != null && t.getProject().getProperty(ifProperty) == null) {
+            return false;
+        }
+        if (unlessProperty != null && t.getProject().getProperty(unlessProperty) != null) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * @since Ant 1.2
+     */
+    JUnitTaskMirror.JUnitResultFormatterMirror createFormatter() throws BuildException {
+        return createFormatter(null);
+    }
+
+    /**
+     * Store the project reference for passing it to nested components.
+     * @param project the reference
+     * @since Ant 1.8
+     */
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+
+    /**
+     * @since Ant 1.6
+     */
+    JUnitTaskMirror.JUnitResultFormatterMirror createFormatter(ClassLoader loader)
+            throws BuildException {
+
+        if (classname == null) {
+            throw new BuildException("you must specify type or classname");
+        }
+        //although this code appears to duplicate that of ClasspathUtils.newInstance,
+        //we cannot use that because this formatter may run in a forked process,
+        //without that class.
+        Class f = null;
+        try {
+            if (loader == null) {
+                f = Class.forName(classname);
+            } else {
+                f = Class.forName(classname, true, loader);
+            }
+        } catch (ClassNotFoundException e) {
+            throw new BuildException(
+                "Using loader " + loader + " on class " + classname
+                + ": " + e, e);
+        } catch (NoClassDefFoundError e) {
+            throw new BuildException(
+                "Using loader " + loader + " on class " + classname
+                + ": " + e, e);
+        }
+
+        Object o = null;
+        try {
+            o = f.newInstance();
+        } catch (InstantiationException e) {
+            throw new BuildException(e);
+        } catch (IllegalAccessException e) {
+            throw new BuildException(e);
+        }
+
+        if (!(o instanceof JUnitTaskMirror.JUnitResultFormatterMirror)) {
+            throw new BuildException(classname + " is not a JUnitResultFormatter");
+        }
+        JUnitTaskMirror.JUnitResultFormatterMirror r =
+            (JUnitTaskMirror.JUnitResultFormatterMirror) o;
+        if (useFile && outFile != null) {
+            try {
+                out = new BufferedOutputStream(new FileOutputStream(outFile));
+            } catch (java.io.IOException e) {
+                throw new BuildException("Unable to open file " + outFile, e);
+            }
+        }
+        r.setOutput(out);
+
+
+        boolean needToSetProjectReference = true;
+        try {
+            Field field = r.getClass().getField("project");
+            Object value = field.get(r);
+            if (value instanceof Project) {
+                // there is already a project reference so dont overwrite this
+                needToSetProjectReference = false;
+            }
+        } catch (Exception e) {
+            // no field present, so no previous reference exists
+        }
+
+        if (needToSetProjectReference) {
+            Method setter;
+            try {
+                setter = r.getClass().getMethod("setProject", new Class[] {Project.class});
+                setter.invoke(r, new Object[] {project});
+            } catch (Exception e) {
+                // no setProject to invoke; just ignore
+            }
+        }
+
+        return r;
+    }
+
+    /**
+     * <p> Enumerated attribute with the values "plain", "xml", "brief" and "failure".
+     *
+     * <p> Use to enumerate options for <code>type</code> attribute.
+     */
+    public static class TypeAttribute extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"plain", "xml", "brief", "failure"};
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java
new file mode 100644
index 0000000..ebfd455
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitResultFormatter.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+import junit.framework.TestListener;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This Interface describes classes that format the results of a JUnit
+ * testrun.
+ *
+ */
+public interface JUnitResultFormatter
+    extends TestListener, JUnitTaskMirror.JUnitResultFormatterMirror {
+    /**
+     * The whole testsuite started.
+     * @param suite the suite.
+     * @throws BuildException on error.
+     */
+    void startTestSuite(JUnitTest suite) throws BuildException;
+
+    /**
+     * The whole testsuite ended.
+     * @param suite the suite.
+     * @throws BuildException on error.
+     */
+    void endTestSuite(JUnitTest suite) throws BuildException;
+
+    /**
+     * Sets the stream the formatter is supposed to write its results to.
+     * @param out the output stream to use.
+     */
+    void setOutput(OutputStream out);
+
+    /**
+     * This is what the test has written to System.out
+     * @param out the string to write.
+     */
+    void setSystemOutput(String out);
+
+    /**
+     * This is what the test has written to System.err
+     * @param err the string to write.
+     */
+    void setSystemError(String err);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
new file mode 100644
index 0000000..507e87a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
@@ -0,0 +1,1920 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+import java.util.Locale;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteWatchdog;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.types.Assertions;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.CommandlineJava;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.types.PropertySet;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.LoaderUtils;
+
+/**
+ * Runs JUnit tests.
+ *
+ * <p> JUnit is a framework to create unit tests. It has been initially
+ * created by Erich Gamma and Kent Beck.  JUnit can be found at <a
+ * href="http://www.junit.org">http://www.junit.org</a>.
+ *
+ * <p> <code>JUnitTask</code> can run a single specific
+ * <code>JUnitTest</code> using the <code>test</code> element.</p>
+ * For example, the following target <code><pre>
+ *   &lt;target name="test-int-chars" depends="jar-test"&gt;
+ *       &lt;echo message="testing international characters"/&gt;
+ *       &lt;junit printsummary="no" haltonfailure="yes" fork="false"&gt;
+ *           &lt;classpath refid="classpath"/&gt;
+ *           &lt;formatter type="plain" usefile="false" /&gt;
+ *           &lt;test name="org.apache.ecs.InternationalCharTest" /&gt;
+ *       &lt;/junit&gt;
+ *   &lt;/target&gt;
+ * </pre></code>
+ * <p>runs a single junit test
+ * (<code>org.apache.ecs.InternationalCharTest</code>) in the current
+ * VM using the path with id <code>classpath</code> as classpath and
+ * presents the results formatted using the standard
+ * <code>plain</code> formatter on the command line.</p>
+ *
+ * <p> This task can also run batches of tests.  The
+ * <code>batchtest</code> element creates a <code>BatchTest</code>
+ * based on a fileset.  This allows, for example, all classes found in
+ * directory to be run as testcases.</p>
+ *
+ * <p>For example,</p><code><pre>
+ * &lt;target name="run-tests" depends="dump-info,compile-tests" if="junit.present"&gt;
+ *   &lt;junit printsummary="no" haltonfailure="yes" fork="${junit.fork}"&gt;
+ *     &lt;jvmarg value="-classic"/&gt;
+ *     &lt;classpath refid="tests-classpath"/&gt;
+ *     &lt;sysproperty key="build.tests" value="${build.tests}"/&gt;
+ *     &lt;formatter type="brief" usefile="false" /&gt;
+ *     &lt;batchtest&gt;
+ *       &lt;fileset dir="${tests.dir}"&gt;
+ *         &lt;include name="**&#047;*Test*" /&gt;
+ *       &lt;/fileset&gt;
+ *     &lt;/batchtest&gt;
+ *   &lt;/junit&gt;
+ * &lt;/target&gt;
+ * </pre></code>
+ * <p>this target finds any classes with a <code>test</code> directory
+ * anywhere in their path (under the top <code>${tests.dir}</code>, of
+ * course) and creates <code>JUnitTest</code>'s for each one.</p>
+ *
+ * <p> Of course, <code>&lt;junit&gt;</code> and
+ * <code>&lt;batch&gt;</code> elements can be combined for more
+ * complex tests. For an example, see the ant <code>build.xml</code>
+ * target <code>run-tests</code> (the second example is an edited
+ * version).</p>
+ *
+ * <p> To spawn a new Java VM to prevent interferences between
+ * different testcases, you need to enable <code>fork</code>.  A
+ * number of attributes and elements allow you to set up how this JVM
+ * runs.
+ *
+ *
+ * @since Ant 1.2
+ *
+ * @see JUnitTest
+ * @see BatchTest
+ */
+public class JUnitTask extends Task {
+
+    private static final String LINE_SEP
+        = System.getProperty("line.separator");
+    private static final String CLASSPATH = "CLASSPATH=";
+    private CommandlineJava commandline;
+    private Vector tests = new Vector();
+    private Vector batchTests = new Vector();
+    private Vector formatters = new Vector();
+    private File dir = null;
+
+    private Integer timeout = null;
+    private boolean summary = false;
+    private boolean reloading = true;
+    private String summaryValue = "";
+    private JUnitTaskMirror.JUnitTestRunnerMirror runner = null;
+
+    private boolean newEnvironment = false;
+    private Environment env = new Environment();
+
+    private boolean includeAntRuntime = true;
+    private Path antRuntimeClasses = null;
+
+    // Do we send output to System.out/.err in addition to the formatters?
+    private boolean showOutput = false;
+
+    // Do we send output to the formatters ?
+    private boolean outputToFormatters = true;
+
+    private File tmpDir;
+    private AntClassLoader classLoader = null;
+    private Permissions perm = null;
+    private ForkMode forkMode = new ForkMode("perTest");
+
+    private boolean splitJunit = false;
+    private JUnitTaskMirror delegate;
+    private ClassLoader mirrorLoader;
+
+    /** A boolean on whether to get the forked path for ant classes */
+    private boolean forkedPathChecked = false;
+
+    //   Attributes for basetest
+    private boolean haltOnError = false;
+    private boolean haltOnFail  = false;
+    private boolean filterTrace = true;
+    private boolean fork        = false;
+    private String  failureProperty;
+    private String  errorProperty;
+
+    private static final int STRING_BUFFER_SIZE = 128;
+    /**
+     * @since Ant 1.7
+     */
+    public static final String TESTLISTENER_PREFIX =
+        "junit.framework.TestListener: ";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * If true, force ant to re-classload all classes for each JUnit TestCase
+     *
+     * @param value force class reloading for each test case
+     */
+    public void setReloading(boolean value) {
+        reloading = value;
+    }
+
+    /**
+     * If true, smartly filter the stack frames of
+     * JUnit errors and failures before reporting them.
+     *
+     * <p>This property is applied on all BatchTest (batchtest) and
+     * JUnitTest (test) however it can possibly be overridden by their
+     * own properties.</p>
+     * @param value <tt>false</tt> if it should not filter, otherwise
+     * <tt>true<tt>
+     *
+     * @since Ant 1.5
+     */
+    public void setFiltertrace(boolean value) {
+        this.filterTrace = value;
+    }
+
+    /**
+     * If true, stop the build process when there is an error in a test.
+     * This property is applied on all BatchTest (batchtest) and JUnitTest
+     * (test) however it can possibly be overridden by their own
+     * properties.
+     * @param value <tt>true</tt> if it should halt, otherwise
+     * <tt>false</tt>
+     *
+     * @since Ant 1.2
+     */
+    public void setHaltonerror(boolean value) {
+        this.haltOnError = value;
+    }
+
+    /**
+     * Property to set to "true" if there is a error in a test.
+     *
+     * <p>This property is applied on all BatchTest (batchtest) and
+     * JUnitTest (test), however, it can possibly be overriden by
+     * their own properties.</p>
+     * @param propertyName the name of the property to set in the
+     * event of an error.
+     *
+     * @since Ant 1.4
+     */
+    public void setErrorProperty(String propertyName) {
+        this.errorProperty = propertyName;
+    }
+
+    /**
+     * If true, stop the build process if a test fails
+     * (errors are considered failures as well).
+     * This property is applied on all BatchTest (batchtest) and
+     * JUnitTest (test) however it can possibly be overridden by their
+     * own properties.
+     * @param value <tt>true</tt> if it should halt, otherwise
+     * <tt>false</tt>
+     *
+     * @since Ant 1.2
+     */
+    public void setHaltonfailure(boolean value) {
+        this.haltOnFail = value;
+    }
+
+    /**
+     * Property to set to "true" if there is a failure in a test.
+     *
+     * <p>This property is applied on all BatchTest (batchtest) and
+     * JUnitTest (test), however, it can possibly be overriden by
+     * their own properties.</p>
+     * @param propertyName the name of the property to set in the
+     * event of an failure.
+     *
+     * @since Ant 1.4
+     */
+    public void setFailureProperty(String propertyName) {
+        this.failureProperty = propertyName;
+    }
+
+    /**
+     * If true, JVM should be forked for each test.
+     *
+     * <p>It avoids interference between testcases and possibly avoids
+     * hanging the build.  this property is applied on all BatchTest
+     * (batchtest) and JUnitTest (test) however it can possibly be
+     * overridden by their own properties.</p>
+     * @param value <tt>true</tt> if a JVM should be forked, otherwise
+     * <tt>false</tt>
+     * @see #setTimeout
+     *
+     * @since Ant 1.2
+     */
+    public void setFork(boolean value) {
+        this.fork = value;
+    }
+
+    /**
+     * Set the behavior when {@link #setFork fork} fork has been enabled.
+     *
+     * <p>Possible values are "once", "perTest" and "perBatch".  If
+     * set to "once", only a single Java VM will be forked for all
+     * tests, with "perTest" (the default) each test will run in a
+     * fresh Java VM and "perBatch" will run all tests from the same
+     * &lt;batchtest&gt; in the same Java VM.</p>
+     *
+     * <p>This attribute will be ignored if tests run in the same VM
+     * as Ant.</p>
+     *
+     * <p>Only tests with the same configuration of haltonerror,
+     * haltonfailure, errorproperty, failureproperty and filtertrace
+     * can share a forked Java VM, so even if you set the value to
+     * "once", Ant may need to fork mutliple VMs.</p>
+     * @param mode the mode to use.
+     * @since Ant 1.6.2
+     */
+    public void setForkMode(ForkMode mode) {
+        this.forkMode = mode;
+    }
+
+    /**
+     * If true, print one-line statistics for each test, or "withOutAndErr"
+     * to also show standard output and error.
+     *
+     * Can take the values on, off, and withOutAndErr.
+     * @param value <tt>true</tt> to print a summary,
+     * <tt>withOutAndErr</tt> to include the test&apos;s output as
+     * well, <tt>false</tt> otherwise.
+     * @see SummaryJUnitResultFormatter
+     *
+     * @since Ant 1.2
+     */
+    public void setPrintsummary(SummaryAttribute value) {
+        summaryValue = value.getValue();
+        summary = value.asBoolean();
+    }
+
+    /**
+     * Print summary enumeration values.
+     */
+    public static class SummaryAttribute extends EnumeratedAttribute {
+        /**
+         * list the possible values
+         * @return  array of allowed values
+         */
+        public String[] getValues() {
+            return new String[] {"true", "yes", "false", "no",
+                                 "on", "off", "withOutAndErr"};
+        }
+
+        /**
+         * gives the boolean equivalent of the authorized values
+         * @return boolean equivalent of the value
+         */
+        public boolean asBoolean() {
+            String v = getValue();
+            return "true".equals(v)
+                || "on".equals(v)
+                || "yes".equals(v)
+                || "withOutAndErr".equals(v);
+        }
+    }
+
+    /**
+     * Set the timeout value (in milliseconds).
+     *
+     * <p>If the test is running for more than this value, the test
+     * will be canceled. (works only when in 'fork' mode).</p>
+     * @param value the maximum time (in milliseconds) allowed before
+     * declaring the test as 'timed-out'
+     * @see #setFork(boolean)
+     *
+     * @since Ant 1.2
+     */
+    public void setTimeout(Integer value) {
+        timeout = value;
+    }
+
+    /**
+     * Set the maximum memory to be used by all forked JVMs.
+     * @param   max     the value as defined by <tt>-mx</tt> or <tt>-Xmx</tt>
+     *                  in the java command line options.
+     *
+     * @since Ant 1.2
+     */
+    public void setMaxmemory(String max) {
+        getCommandline().setMaxmemory(max);
+    }
+
+    /**
+     * The command used to invoke the Java Virtual Machine,
+     * default is 'java'. The command is resolved by
+     * java.lang.Runtime.exec(). Ignored if fork is disabled.
+     *
+     * @param   value   the new VM to use instead of <tt>java</tt>
+     * @see #setFork(boolean)
+     *
+     * @since Ant 1.2
+     */
+    public void setJvm(String value) {
+        getCommandline().setVm(value);
+    }
+
+    /**
+     * Adds a JVM argument; ignored if not forking.
+     *
+     * @return create a new JVM argument so that any argument can be
+     * passed to the JVM.
+     * @see #setFork(boolean)
+     *
+     * @since Ant 1.2
+     */
+    public Commandline.Argument createJvmarg() {
+        return getCommandline().createVmArgument();
+    }
+
+    /**
+     * The directory to invoke the VM in. Ignored if no JVM is forked.
+     * @param   dir     the directory to invoke the JVM from.
+     * @see #setFork(boolean)
+     *
+     * @since Ant 1.2
+     */
+    public void setDir(File dir) {
+        this.dir = dir;
+    }
+
+    /**
+     * Adds a system property that tests can access.
+     * This might be useful to tranfer Ant properties to the
+     * testcases when JVM forking is not enabled.
+     *
+     * @since Ant 1.3
+     * @deprecated since ant 1.6
+     * @param sysp environment variable to add
+     */
+    public void addSysproperty(Environment.Variable sysp) {
+
+        getCommandline().addSysproperty(sysp);
+    }
+
+    /**
+     * Adds a system property that tests can access.
+     * This might be useful to tranfer Ant properties to the
+     * testcases when JVM forking is not enabled.
+     * @param sysp new environment variable to add
+     * @since Ant 1.6
+     */
+    public void addConfiguredSysproperty(Environment.Variable sysp) {
+        // get a build exception if there is a missing key or value
+        // see bugzilla report 21684
+        String testString = sysp.getContent();
+        getProject().log("sysproperty added : " + testString, Project.MSG_DEBUG);
+        getCommandline().addSysproperty(sysp);
+    }
+
+    /**
+     * Adds a set of properties that will be used as system properties
+     * that tests can access.
+     *
+     * This might be useful to tranfer Ant properties to the
+     * testcases when JVM forking is not enabled.
+     *
+     * @param sysp set of properties to be added
+     * @since Ant 1.6
+     */
+    public void addSyspropertyset(PropertySet sysp) {
+        getCommandline().addSyspropertyset(sysp);
+    }
+
+    /**
+     * Adds path to classpath used for tests.
+     *
+     * @return reference to the classpath in the embedded java command line
+     * @since Ant 1.2
+     */
+    public Path createClasspath() {
+        return getCommandline().createClasspath(getProject()).createPath();
+    }
+
+    /**
+     * Adds a path to the bootclasspath.
+     * @return reference to the bootclasspath in the embedded java command line
+     * @since Ant 1.6
+     */
+    public Path createBootclasspath() {
+        return getCommandline().createBootclasspath(getProject()).createPath();
+    }
+
+    /**
+     * Adds an environment variable; used when forking.
+     *
+     * <p>Will be ignored if we are not forking a new VM.</p>
+     * @param var environment variable to be added
+     * @since Ant 1.5
+     */
+    public void addEnv(Environment.Variable var) {
+        env.addVariable(var);
+    }
+
+    /**
+     * If true, use a new environment when forked.
+     *
+     * <p>Will be ignored if we are not forking a new VM.</p>
+     *
+     * @param newenv boolean indicating if setting a new environment is wished
+     * @since Ant 1.5
+     */
+    public void setNewenvironment(boolean newenv) {
+        newEnvironment = newenv;
+    }
+
+    /**
+     * Preset the attributes of the test
+     * before configuration in the build
+     * script.
+     * This allows attributes in the <junit> task
+     * be be defaults for the tests, but allows
+     * individual tests to override the defaults.
+     */
+    private void preConfigure(BaseTest test) {
+        test.setFiltertrace(filterTrace);
+        test.setHaltonerror(haltOnError);
+        if (errorProperty != null) {
+            test.setErrorProperty(errorProperty);
+        }
+        test.setHaltonfailure(haltOnFail);
+        if (failureProperty != null) {
+            test.setFailureProperty(failureProperty);
+        }
+        test.setFork(fork);
+    }
+
+    /**
+     * Add a new single testcase.
+     * @param   test    a new single testcase
+     * @see JUnitTest
+     *
+     * @since Ant 1.2
+     */
+    public void addTest(JUnitTest test) {
+        tests.addElement(test);
+        preConfigure(test);
+    }
+
+    /**
+     * Adds a set of tests based on pattern matching.
+     *
+     * @return  a new instance of a batch test.
+     * @see BatchTest
+     *
+     * @since Ant 1.2
+     */
+    public BatchTest createBatchTest() {
+        BatchTest test = new BatchTest(getProject());
+        batchTests.addElement(test);
+        preConfigure(test);
+        return test;
+    }
+
+    /**
+     * Add a new formatter to all tests of this task.
+     *
+     * @param fe formatter element
+     * @since Ant 1.2
+     */
+    public void addFormatter(FormatterElement fe) {
+        formatters.addElement(fe);
+    }
+
+    /**
+     * If true, include ant.jar, optional.jar and junit.jar in the forked VM.
+     *
+     * @param b include ant run time yes or no
+     * @since Ant 1.5
+     */
+    public void setIncludeantruntime(boolean b) {
+        includeAntRuntime = b;
+    }
+
+    /**
+     * If true, send any output generated by tests to Ant's logging system
+     * as well as to the formatters.
+     * By default only the formatters receive the output.
+     *
+     * <p>Output will always be passed to the formatters and not by
+     * shown by default.  This option should for example be set for
+     * tests that are interactive and prompt the user to do
+     * something.</p>
+     *
+     * @param showOutput if true, send output to Ant's logging system too
+     * @since Ant 1.5
+     */
+    public void setShowOutput(boolean showOutput) {
+        this.showOutput = showOutput;
+    }
+
+    /**
+     * If true, send any output generated by tests to the formatters.
+     *
+     * @param outputToFormatters if true, send output to formatters (Default
+     *                           is true).
+     * @since Ant 1.7.0
+     */
+    public void setOutputToFormatters(boolean outputToFormatters) {
+        this.outputToFormatters = outputToFormatters;
+    }
+
+    /**
+     * Assertions to enable in this program (if fork=true)
+     * @since Ant 1.6
+     * @param asserts assertion set
+     */
+    public void addAssertions(Assertions asserts) {
+        if (getCommandline().getAssertions() != null) {
+            throw new BuildException("Only one assertion declaration is allowed");
+        }
+        getCommandline().setAssertions(asserts);
+    }
+
+    /**
+     * Sets the permissions for the application run inside the same JVM.
+     * @since Ant 1.6
+     * @return .
+     */
+    public Permissions createPermissions() {
+        if (perm == null) {
+            perm = new Permissions();
+        }
+        return perm;
+    }
+
+    /**
+     * If set, system properties will be copied to the cloned VM - as
+     * well as the bootclasspath unless you have explicitly specified
+     * a bootclaspath.
+     *
+     * <p>Doesn't have any effect unless fork is true.</p>
+     * @param cloneVm a <code>boolean</code> value.
+     * @since Ant 1.7
+     */
+    public void setCloneVm(boolean cloneVm) {
+        getCommandline().setCloneVm(cloneVm);
+    }
+
+    /**
+     * Creates a new JUnitRunner and enables fork of a new Java VM.
+     *
+     * @throws Exception under ??? circumstances
+     * @since Ant 1.2
+     */
+    public JUnitTask() throws Exception {
+        getCommandline()
+            .setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
+    }
+
+    /**
+     * Where Ant should place temporary files.
+     *
+     * @param tmpDir location where temporary files should go to
+     * @since Ant 1.6
+     */
+    public void setTempdir(File tmpDir) {
+        if (tmpDir != null) {
+            if (!tmpDir.exists() || !tmpDir.isDirectory()) {
+                throw new BuildException(tmpDir.toString()
+                                         + " is not a valid temp directory");
+            }
+        }
+        this.tmpDir = tmpDir;
+    }
+
+    /**
+     * Adds the jars or directories containing Ant, this task and
+     * JUnit to the classpath - this should make the forked JVM work
+     * without having to specify them directly.
+     *
+     * @since Ant 1.4
+     */
+    public void init() {
+        antRuntimeClasses = new Path(getProject());
+        splitJunit = !addClasspathResource("/junit/framework/TestCase.class");
+        addClasspathEntry("/org/apache/tools/ant/launch/AntMain.class");
+        addClasspathEntry("/org/apache/tools/ant/Task.class");
+        addClasspathEntry("/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.class");
+    }
+
+    private static JUnitTaskMirror createMirror(JUnitTask task, ClassLoader loader) {
+        try {
+            loader.loadClass("junit.framework.Test"); // sanity check
+        } catch (ClassNotFoundException e) {
+            throw new BuildException(
+                    "The <classpath> for <junit> must include junit.jar "
+                    + "if not in Ant's own classpath",
+                    e, task.getLocation());
+        }
+        try {
+            Class c = loader.loadClass(JUnitTaskMirror.class.getName() + "Impl");
+            if (c.getClassLoader() != loader) {
+                throw new BuildException("Overdelegating loader", task.getLocation());
+            }
+            Constructor cons = c.getConstructor(new Class[] {JUnitTask.class});
+            return (JUnitTaskMirror) cons.newInstance(new Object[] {task});
+        } catch (Exception e) {
+            throw new BuildException(e, task.getLocation());
+        }
+    }
+
+    private final class SplitLoader extends AntClassLoader {
+
+        public SplitLoader(ClassLoader parent, Path path) {
+            super(parent, getProject(), path, true);
+        }
+
+        // forceLoadClass is not convenient here since it would not
+        // properly deal with inner classes of these classes.
+        protected synchronized Class loadClass(String classname, boolean resolve)
+        throws ClassNotFoundException {
+            Class theClass = findLoadedClass(classname);
+            if (theClass != null) {
+                return theClass;
+            }
+            if (isSplit(classname)) {
+                theClass = findClass(classname);
+                if (resolve) {
+                    resolveClass(theClass);
+                }
+                return theClass;
+            } else {
+                return super.loadClass(classname, resolve);
+            }
+        }
+
+        private final String[] splitClasses = {
+            "BriefJUnitResultFormatter",
+            "JUnitResultFormatter",
+            "JUnitTaskMirrorImpl",
+            "JUnitTestRunner",
+            "JUnitVersionHelper",
+            "OutErrSummaryJUnitResultFormatter",
+            "PlainJUnitResultFormatter",
+            "SummaryJUnitResultFormatter",
+            "XMLJUnitResultFormatter",
+        };
+
+        private boolean isSplit(String classname) {
+            String simplename = classname.substring(classname.lastIndexOf('.') + 1);
+            for (int i = 0; i < splitClasses.length; i++) {
+                if (simplename.equals(splitClasses[i])
+                        || simplename.startsWith(splitClasses[i] + '$')) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+    }
+
+    /**
+     * Sets up the delegate that will actually run the tests.
+     *
+     * <p>Will be invoked implicitly once the delegate is needed.</p>
+     *
+     * @since Ant 1.7.1
+     */
+    protected void setupJUnitDelegate() {
+        ClassLoader myLoader = JUnitTask.class.getClassLoader();
+        if (splitJunit) {
+            Path path = new Path(getProject());
+            path.add(antRuntimeClasses);
+            Path extra = getCommandline().getClasspath();
+            if (extra != null) {
+                path.add(extra);
+            }
+            mirrorLoader = new SplitLoader(myLoader, path);
+        } else {
+            mirrorLoader = myLoader;
+        }
+        delegate = createMirror(this, mirrorLoader);
+    }
+
+    /**
+     * Runs the testcase.
+     *
+     * @throws BuildException in case of test failures or errors
+     * @since Ant 1.2
+     */
+    public void execute() throws BuildException {
+        setupJUnitDelegate();
+
+        List testLists = new ArrayList();
+
+        boolean forkPerTest = forkMode.getValue().equals(ForkMode.PER_TEST);
+        if (forkPerTest || forkMode.getValue().equals(ForkMode.ONCE)) {
+            testLists.addAll(executeOrQueue(getIndividualTests(),
+                                            forkPerTest));
+        } else { /* forkMode.getValue().equals(ForkMode.PER_BATCH) */
+            final int count = batchTests.size();
+            for (int i = 0; i < count; i++) {
+                BatchTest batchtest = (BatchTest) batchTests.elementAt(i);
+                testLists.addAll(executeOrQueue(batchtest.elements(), false));
+            }
+            testLists.addAll(executeOrQueue(tests.elements(), forkPerTest));
+        }
+
+        try {
+            Iterator iter = testLists.iterator();
+            while (iter.hasNext()) {
+                List l = (List) iter.next();
+                if (l.size() == 1) {
+                    execute((JUnitTest) l.get(0));
+                } else {
+                    execute(l);
+                }
+            }
+        } finally {
+            cleanup();
+        }
+    }
+
+    /**
+     * Run the tests.
+     * @param arg one JunitTest
+     * @throws BuildException in case of test failures or errors
+     */
+    protected void execute(JUnitTest arg) throws BuildException {
+        JUnitTest test = (JUnitTest) arg.clone();
+        // set the default values if not specified
+        //@todo should be moved to the test class instead.
+        if (test.getTodir() == null) {
+            test.setTodir(getProject().resolveFile("."));
+        }
+
+        if (test.getOutfile() == null) {
+            test.setOutfile("TEST-" + test.getName());
+        }
+
+        // execute the test and get the return code
+        TestResultHolder result = null;
+        if (!test.getFork()) {
+            result = executeInVM(test);
+        } else {
+            ExecuteWatchdog watchdog = createWatchdog();
+            result = executeAsForked(test, watchdog, null);
+            // null watchdog means no timeout, you'd better not check with null
+        }
+        actOnTestResult(result, test, "Test " + test.getName());
+    }
+
+    /**
+     * Execute a list of tests in a single forked Java VM.
+     * @param testList the list of tests to execute.
+     * @throws BuildException on error.
+     */
+    protected void execute(List testList) throws BuildException {
+        JUnitTest test = null;
+        // Create a temporary file to pass the test cases to run to
+        // the runner (one test case per line)
+        File casesFile = createTempPropertiesFile("junittestcases");
+        PrintWriter writer = null;
+        try {
+            writer =
+                new PrintWriter(new BufferedWriter(new FileWriter(casesFile)));
+            Iterator iter = testList.iterator();
+            while (iter.hasNext()) {
+                test = (JUnitTest) iter.next();
+                writer.print(test.getName());
+                if (test.getTodir() == null) {
+                    writer.print("," + getProject().resolveFile("."));
+                } else {
+                    writer.print("," + test.getTodir());
+                }
+
+                if (test.getOutfile() == null) {
+                    writer.println("," + "TEST-" + test.getName());
+                } else {
+                    writer.println("," + test.getOutfile());
+                }
+            }
+            writer.flush();
+            writer.close();
+            writer = null;
+
+            // execute the test and get the return code
+            ExecuteWatchdog watchdog = createWatchdog();
+            TestResultHolder result =
+                executeAsForked(test, watchdog, casesFile);
+            actOnTestResult(result, test, "Tests");
+        } catch (IOException e) {
+            log(e.toString(), Project.MSG_ERR);
+            throw new BuildException(e);
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+
+            try {
+                casesFile.delete();
+            } catch (Exception e) {
+                log(e.toString(), Project.MSG_ERR);
+            }
+        }
+    }
+
+    /**
+     * Execute a testcase by forking a new JVM. The command will block
+     * until it finishes. To know if the process was destroyed or not
+     * or whether the forked Java VM exited abnormally, use the
+     * attributes of the returned holder object.
+     * @param  test       the testcase to execute.
+     * @param  watchdog   the watchdog in charge of cancelling the test if it
+     * exceeds a certain amount of time. Can be <tt>null</tt>, in this case
+     * the test could probably hang forever.
+     * @param casesFile list of test cases to execute. Can be <tt>null</tt>,
+     * in this case only one test is executed.
+     * @return the test results from the JVM itself.
+     * @throws BuildException in case of error creating a temporary property file,
+     * or if the junit process can not be forked
+     */
+    private TestResultHolder executeAsForked(JUnitTest test,
+                                             ExecuteWatchdog watchdog,
+                                             File casesFile)
+        throws BuildException {
+
+        if (perm != null) {
+            log("Permissions ignored when running in forked mode!",
+                Project.MSG_WARN);
+        }
+
+        CommandlineJava cmd;
+        try {
+            cmd = (CommandlineJava) (getCommandline().clone());
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException("This shouldn't happen", e, getLocation());
+        }
+        cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
+        if (casesFile == null) {
+            cmd.createArgument().setValue(test.getName());
+        } else {
+            log("Running multiple tests in the same VM", Project.MSG_VERBOSE);
+            cmd.createArgument().setValue(Constants.TESTSFILE + casesFile);
+        }
+
+        cmd.createArgument().setValue(Constants.FILTERTRACE + test.getFiltertrace());
+        cmd.createArgument().setValue(Constants.HALT_ON_ERROR + test.getHaltonerror());
+        cmd.createArgument().setValue(Constants.HALT_ON_FAILURE
+                                      + test.getHaltonfailure());
+        checkIncludeAntRuntime(cmd);
+
+        checkIncludeSummary(cmd);
+
+        cmd.createArgument().setValue(Constants.SHOWOUTPUT
+                                      + String.valueOf(showOutput));
+        cmd.createArgument().setValue(Constants.OUTPUT_TO_FORMATTERS
+                                      + String.valueOf(outputToFormatters));
+
+        cmd.createArgument().setValue(
+            Constants.LOGTESTLISTENEREVENTS + "true"); // #31885
+
+        StringBuffer formatterArg = new StringBuffer(STRING_BUFFER_SIZE);
+        final FormatterElement[] feArray = mergeFormatters(test);
+        for (int i = 0; i < feArray.length; i++) {
+            FormatterElement fe = feArray[i];
+            if (fe.shouldUse(this)) {
+                formatterArg.append(Constants.FORMATTER);
+                formatterArg.append(fe.getClassname());
+                File outFile = getOutput(fe, test);
+                if (outFile != null) {
+                    formatterArg.append(",");
+                    formatterArg.append(outFile);
+                }
+                cmd.createArgument().setValue(formatterArg.toString());
+                formatterArg = new StringBuffer();
+            }
+        }
+
+        File vmWatcher = createTempPropertiesFile("junitvmwatcher");
+        cmd.createArgument().setValue(Constants.CRASHFILE
+                                      + vmWatcher.getAbsolutePath());
+        File propsFile = createTempPropertiesFile("junit");
+        cmd.createArgument().setValue(Constants.PROPSFILE
+                                      + propsFile.getAbsolutePath());
+        Hashtable p = getProject().getProperties();
+        Properties props = new Properties();
+        for (Enumeration e = p.keys(); e.hasMoreElements();) {
+            Object key = e.nextElement();
+            props.put(key, p.get(key));
+        }
+        try {
+            FileOutputStream outstream = new FileOutputStream(propsFile);
+            props.store(outstream, "Ant JUnitTask generated properties file");
+            outstream.close();
+        } catch (java.io.IOException e) {
+            propsFile.delete();
+            throw new BuildException("Error creating temporary properties "
+                                     + "file.", e, getLocation());
+        }
+
+        Execute execute = new Execute(
+            new JUnitLogStreamHandler(
+                this,
+                Project.MSG_INFO,
+                Project.MSG_WARN),
+            watchdog);
+        execute.setCommandline(cmd.getCommandline());
+        execute.setAntRun(getProject());
+        if (dir != null) {
+            execute.setWorkingDirectory(dir);
+        }
+
+        String[] environment = env.getVariables();
+        if (environment != null) {
+            for (int i = 0; i < environment.length; i++) {
+                log("Setting environment variable: " + environment[i],
+                    Project.MSG_VERBOSE);
+            }
+        }
+        execute.setNewenvironment(newEnvironment);
+        execute.setEnvironment(environment);
+
+        log(cmd.describeCommand(), Project.MSG_VERBOSE);
+
+        checkForkedPath(cmd);
+
+        TestResultHolder result = new TestResultHolder();
+        try {
+            result.exitCode = execute.execute();
+        } catch (IOException e) {
+            throw new BuildException("Process fork failed.", e, getLocation());
+        } finally {
+            String vmCrashString = "unknown";
+            BufferedReader br = null;
+            try {
+                if (vmWatcher.exists()) {
+                    br = new BufferedReader(new FileReader(vmWatcher));
+                    vmCrashString = br.readLine();
+                } else {
+                    vmCrashString = "Monitor file ("
+                            + vmWatcher.getAbsolutePath()
+                            + ") missing, location not writable,"
+                            + " testcase not started or mixing ant versions?";
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                // ignored.
+            } finally {
+                FileUtils.close(br);
+                if (vmWatcher.exists()) {
+                    vmWatcher.delete();
+                }
+            }
+            if (watchdog != null && watchdog.killedProcess()) {
+                result.timedOut = true;
+                logTimeout(feArray, test, vmCrashString);
+            } else if (!Constants.TERMINATED_SUCCESSFULLY.equals(vmCrashString)) {
+                result.crashed = true;
+                logVmCrash(feArray, test, vmCrashString);
+            }
+
+            if (!propsFile.delete()) {
+                throw new BuildException("Could not delete temporary "
+                                         + "properties file.");
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Adding ant runtime.
+     * @param cmd command to run
+     */
+    private void checkIncludeAntRuntime(CommandlineJava cmd) {
+        if (includeAntRuntime) {
+            Vector v = Execute.getProcEnvironment();
+            Enumeration e = v.elements();
+            while (e.hasMoreElements()) {
+                String s = (String) e.nextElement();
+                if (s.startsWith(CLASSPATH)) {
+                    cmd.createClasspath(getProject()).createPath()
+                        .append(new Path(getProject(),
+                                         s.substring(CLASSPATH.length()
+                                                     )));
+                }
+            }
+            log("Implicitly adding " + antRuntimeClasses + " to CLASSPATH",
+                Project.MSG_VERBOSE);
+            cmd.createClasspath(getProject()).createPath()
+                .append(antRuntimeClasses);
+        }
+    }
+
+
+    /**
+     * check for the parameter being "withoutanderr" in a locale-independent way.
+     * @param summaryOption the summary option -can be null
+     * @return true if the run should be withoutput and error
+     */
+    private boolean equalsWithOutAndErr(String summaryOption) {
+        return summaryOption != null && "withoutanderr".equals(
+            summaryOption.toLowerCase(Locale.ENGLISH));
+    }
+
+    private void checkIncludeSummary(CommandlineJava cmd) {
+        if (summary) {
+            String prefix = "";
+            if (equalsWithOutAndErr(summaryValue)) {
+                prefix = "OutErr";
+            }
+            cmd.createArgument()
+                .setValue(Constants.FORMATTER
+                          + "org.apache.tools.ant.taskdefs.optional.junit."
+                          + prefix + "SummaryJUnitResultFormatter");
+        }
+    }
+
+    /**
+     * Check the path for multiple different versions of
+     * ant.
+     * @param cmd command to execute
+     */
+    private void checkForkedPath(CommandlineJava cmd) {
+        if (forkedPathChecked) {
+            return;
+        }
+        forkedPathChecked = true;
+        if (!cmd.haveClasspath()) {
+            return;
+        }
+        AntClassLoader loader = new AntClassLoader(
+            getProject(), cmd.createClasspath(getProject()));
+        String projectResourceName = LoaderUtils.classNameToResource(
+            Project.class.getName());
+        URL previous = null;
+        try {
+            for (Enumeration e = loader.getResources(projectResourceName);
+                 e.hasMoreElements();) {
+                URL current = (URL) e.nextElement();
+                if (previous != null && !current.equals(previous)) {
+                    log("WARNING: multiple versions of ant detected "
+                        + "in path for junit "
+                        + LINE_SEP + "         " + previous
+                        + LINE_SEP + "     and " + current,
+                        Project.MSG_WARN);
+                    return;
+                }
+                previous = current;
+            }
+        } catch (Exception ex) {
+            // Ignore exception
+        }
+    }
+
+    /**
+     * Create a temporary file to pass the properties to a new process.
+     * Will auto-delete on (graceful) exit.
+     * The file will be in the project basedir unless tmpDir declares
+     * something else.
+     * @param prefix
+     * @return created file
+     */
+    private File createTempPropertiesFile(String prefix) {
+        File propsFile =
+            FILE_UTILS.createTempFile(prefix, ".properties",
+                tmpDir != null ? tmpDir : getProject().getBaseDir(), true, true);
+        return propsFile;
+    }
+
+
+    /**
+     * Pass output sent to System.out to the TestRunner so it can
+     * collect ot for the formatters.
+     *
+     * @param output output coming from System.out
+     * @since Ant 1.5
+     */
+    protected void handleOutput(String output) {
+        if (output.startsWith(TESTLISTENER_PREFIX)) {
+            log(output, Project.MSG_VERBOSE);
+        } else if (runner != null) {
+            if (outputToFormatters) {
+                runner.handleOutput(output);
+            }
+            if (showOutput) {
+                super.handleOutput(output);
+            }
+        } else {
+            super.handleOutput(output);
+        }
+    }
+
+    /**
+     * Handle an input request by this task.
+     * @see Task#handleInput(byte[], int, int)
+     * This implementation delegates to a runner if it
+     * present.
+     * @param buffer the buffer into which data is to be read.
+     * @param offset the offset into the buffer at which data is stored.
+     * @param length the amount of data to read.
+     *
+     * @return the number of bytes read.
+     * @exception IOException if the data cannot be read.
+     *
+     * @since Ant 1.6
+     */
+    protected int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        if (runner != null) {
+            return runner.handleInput(buffer, offset, length);
+        } else {
+            return super.handleInput(buffer, offset, length);
+        }
+    }
+
+
+    /**
+     * Pass output sent to System.out to the TestRunner so it can
+     * collect ot for the formatters.
+     *
+     * @param output output coming from System.out
+     * @since Ant 1.5.2
+     */
+    protected void handleFlush(String output) {
+        if (runner != null) {
+            runner.handleFlush(output);
+            if (showOutput) {
+                super.handleFlush(output);
+            }
+        } else {
+            super.handleFlush(output);
+        }
+    }
+
+    /**
+     * Pass output sent to System.err to the TestRunner so it can
+     * collect it for the formatters.
+     *
+     * @param output output coming from System.err
+     * @since Ant 1.5
+     */
+    public void handleErrorOutput(String output) {
+        if (runner != null) {
+            runner.handleErrorOutput(output);
+            if (showOutput) {
+                super.handleErrorOutput(output);
+            }
+        } else {
+            super.handleErrorOutput(output);
+        }
+    }
+
+
+    /**
+     * Pass output sent to System.err to the TestRunner so it can
+     * collect it for the formatters.
+     *
+     * @param output coming from System.err
+     * @since Ant 1.5.2
+     */
+    public void handleErrorFlush(String output) {
+        if (runner != null) {
+            runner.handleErrorFlush(output);
+            if (showOutput) {
+                super.handleErrorFlush(output);
+            }
+        } else {
+            super.handleErrorFlush(output);
+        }
+    }
+
+    // in VM is not very nice since it could probably hang the
+    // whole build. IMHO this method should be avoided and it would be best
+    // to remove it in future versions. TBD. (SBa)
+
+    /**
+     * Execute inside VM.
+     * @param arg one JUnitTest
+     * @throws BuildException under unspecified circumstances
+     * @return the results
+     */
+    private TestResultHolder executeInVM(JUnitTest arg) throws BuildException {
+        if (delegate == null) {
+            setupJUnitDelegate();
+        }
+
+        JUnitTest test = (JUnitTest) arg.clone();
+        test.setProperties(getProject().getProperties());
+        if (dir != null) {
+            log("dir attribute ignored if running in the same VM",
+                Project.MSG_WARN);
+        }
+
+        if (newEnvironment || null != env.getVariables()) {
+            log("Changes to environment variables are ignored if running in "
+                + "the same VM.", Project.MSG_WARN);
+        }
+
+        if (getCommandline().getBootclasspath() != null) {
+            log("bootclasspath is ignored if running in the same VM.",
+                Project.MSG_WARN);
+        }
+
+        CommandlineJava.SysProperties sysProperties =
+                getCommandline().getSystemProperties();
+        if (sysProperties != null) {
+            sysProperties.setSystem();
+        }
+
+        try {
+            log("Using System properties " + System.getProperties(),
+                Project.MSG_VERBOSE);
+            if (splitJunit) {
+                classLoader = (AntClassLoader) delegate.getClass().getClassLoader();
+            } else {
+                createClassLoader();
+            }
+            if (classLoader != null) {
+                classLoader.setThreadContextLoader();
+            }
+            runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(),
+                                         test.getFiltertrace(),
+                                         test.getHaltonfailure(), false,
+                                         true, classLoader);
+            if (summary) {
+
+                JUnitTaskMirror.SummaryJUnitResultFormatterMirror f =
+                    delegate.newSummaryJUnitResultFormatter();
+                f.setWithOutAndErr(equalsWithOutAndErr(summaryValue));
+                f.setOutput(getDefaultOutput());
+                runner.addFormatter(f);
+            }
+
+            runner.setPermissions(perm);
+
+            final FormatterElement[] feArray = mergeFormatters(test);
+            for (int i = 0; i < feArray.length; i++) {
+                FormatterElement fe = feArray[i];
+                if (fe.shouldUse(this)) {
+                    File outFile = getOutput(fe, test);
+                    if (outFile != null) {
+                        fe.setOutfile(outFile);
+                    } else {
+                        fe.setOutput(getDefaultOutput());
+                    }
+                    runner.addFormatter(fe.createFormatter(classLoader));
+                }
+            }
+
+            runner.run();
+            TestResultHolder result = new TestResultHolder();
+            result.exitCode = runner.getRetCode();
+            return result;
+        } finally {
+            if (sysProperties != null) {
+                sysProperties.restoreSystem();
+            }
+            if (classLoader != null) {
+                classLoader.resetThreadContextLoader();
+            }
+        }
+    }
+
+    /**
+     * @return <tt>null</tt> if there is a timeout value, otherwise the
+     * watchdog instance.
+     *
+     * @throws BuildException under unspecified circumstances
+     * @since Ant 1.2
+     */
+    protected ExecuteWatchdog createWatchdog() throws BuildException {
+        if (timeout == null) {
+            return null;
+        }
+        return new ExecuteWatchdog((long) timeout.intValue());
+    }
+
+    /**
+     * Get the default output for a formatter.
+     *
+     * @return default output stream for a formatter
+     * @since Ant 1.3
+     */
+    protected OutputStream getDefaultOutput() {
+        return new LogOutputStream(this, Project.MSG_INFO);
+    }
+
+    /**
+     * Merge all individual tests from the batchtest with all individual tests
+     * and return an enumeration over all <tt>JUnitTest</tt>.
+     *
+     * @return enumeration over individual tests
+     * @since Ant 1.3
+     */
+    protected Enumeration getIndividualTests() {
+        final int count = batchTests.size();
+        final Enumeration[] enums = new Enumeration[ count + 1];
+        for (int i = 0; i < count; i++) {
+            BatchTest batchtest = (BatchTest) batchTests.elementAt(i);
+            enums[i] = batchtest.elements();
+        }
+        enums[enums.length - 1] = tests.elements();
+        return Enumerations.fromCompound(enums);
+    }
+
+    /**
+     * return an enumeration listing each test, then each batchtest
+     * @return enumeration
+     * @since Ant 1.3
+     */
+    protected Enumeration allTests() {
+        Enumeration[] enums = {tests.elements(), batchTests.elements()};
+        return Enumerations.fromCompound(enums);
+    }
+
+    /**
+     * @param test junit test
+     * @return array of FormatterElement
+     * @since Ant 1.3
+     */
+    private FormatterElement[] mergeFormatters(JUnitTest test) {
+        Vector feVector = (Vector) formatters.clone();
+        test.addFormattersTo(feVector);
+        FormatterElement[] feArray = new FormatterElement[feVector.size()];
+        feVector.copyInto(feArray);
+        return feArray;
+    }
+
+    /**
+     * If the formatter sends output to a file, return that file.
+     * null otherwise.
+     * @param fe  formatter element
+     * @param test one JUnit test
+     * @return file reference
+     * @since Ant 1.3
+     */
+    protected File getOutput(FormatterElement fe, JUnitTest test) {
+        if (fe.getUseFile()) {
+            String base = test.getOutfile();
+            if (base == null) {
+                base = JUnitTaskMirror.JUnitTestRunnerMirror.IGNORED_FILE_NAME;
+            }
+            String filename = base + fe.getExtension();
+            File destFile = new File(test.getTodir(), filename);
+            String absFilename = destFile.getAbsolutePath();
+            return getProject().resolveFile(absFilename);
+        }
+        return null;
+    }
+
+    /**
+     * Search for the given resource and add the directory or archive
+     * that contains it to the classpath.
+     *
+     * <p>Doesn't work for archives in JDK 1.1 as the URL returned by
+     * getResource doesn't contain the name of the archive.</p>
+     *
+     * @param resource resource that one wants to lookup
+     * @since Ant 1.4
+     */
+    protected void addClasspathEntry(String resource) {
+        addClasspathResource(resource);
+    }
+
+    /**
+     * Implementation of addClasspathEntry.
+     *
+     * @param resource resource that one wants to lookup
+     * @return true if something was in fact added
+     * @since Ant 1.7.1
+     */
+    private boolean addClasspathResource(String resource) {
+        /*
+         * pre Ant 1.6 this method used to call getClass().getResource
+         * while Ant 1.6 will call ClassLoader.getResource().
+         *
+         * The difference is that Class.getResource expects a leading
+         * slash for "absolute" resources and will strip it before
+         * delegating to ClassLoader.getResource - so we now have to
+         * emulate Class's behavior.
+         */
+        if (resource.startsWith("/")) {
+            resource = resource.substring(1);
+        } else {
+            resource = "org/apache/tools/ant/taskdefs/optional/junit/"
+                + resource;
+        }
+
+        File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
+                                               resource);
+        if (f != null) {
+            log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
+            antRuntimeClasses.createPath().setLocation(f);
+            return true;
+        } else {
+            log("Couldn\'t find " + resource, Project.MSG_DEBUG);
+            return false;
+        }
+    }
+
+    /**
+     * Take care that some output is produced in report files if the
+     * watchdog kills the test.
+     *
+     * @since Ant 1.5.2
+     */
+
+    private void logTimeout(FormatterElement[] feArray, JUnitTest test, String testCase) {
+        logVmExit(
+            feArray, test,
+            "Timeout occurred. Please note the time in the report does"
+            + " not reflect the time until the timeout.",
+            testCase);
+    }
+
+    /**
+     * Take care that some output is produced in report files if the
+     * forked machine exited before the test suite finished but the
+     * reason is not a timeout.
+     *
+     * @since Ant 1.7
+     */
+    private void logVmCrash(FormatterElement[] feArray, JUnitTest test, String testCase) {
+        logVmExit(
+            feArray, test,
+            "Forked Java VM exited abnormally. Please note the time in the report"
+            + " does not reflect the time until the VM exit.",
+            testCase);
+    }
+
+    /**
+     * Take care that some output is produced in report files if the
+     * forked machine terminated before the test suite finished
+     *
+     * @since Ant 1.7
+     */
+    private void logVmExit(FormatterElement[] feArray, JUnitTest test,
+                           String message, String testCase) {
+        if (delegate == null) {
+            setupJUnitDelegate();
+        }
+
+        try {
+            log("Using System properties " + System.getProperties(),
+                Project.MSG_VERBOSE);
+            if (splitJunit) {
+                classLoader = (AntClassLoader) delegate.getClass().getClassLoader();
+            } else {
+                createClassLoader();
+            }
+            if (classLoader != null) {
+                classLoader.setThreadContextLoader();
+            }
+
+            test.setCounts(1, 0, 1);
+            test.setProperties(getProject().getProperties());
+            for (int i = 0; i < feArray.length; i++) {
+                FormatterElement fe = feArray[i];
+                File outFile = getOutput(fe, test);
+                JUnitTaskMirror.JUnitResultFormatterMirror formatter =
+                    fe.createFormatter(classLoader);
+                if (outFile != null && formatter != null) {
+                    try {
+                        OutputStream out = new FileOutputStream(outFile);
+                        delegate.addVmExit(test, formatter, out, message, testCase);
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+            if (summary) {
+                JUnitTaskMirror.SummaryJUnitResultFormatterMirror f =
+                    delegate.newSummaryJUnitResultFormatter();
+                f.setWithOutAndErr("withoutanderr".equalsIgnoreCase(summaryValue));
+                delegate.addVmExit(test, f, getDefaultOutput(), message, testCase);
+            }
+        } finally {
+            if (classLoader != null) {
+                classLoader.resetThreadContextLoader();
+            }
+        }
+    }
+
+    /**
+     * Creates and configures an AntClassLoader instance from the
+     * nested classpath element.
+     *
+     * @since Ant 1.6
+     */
+    private void createClassLoader() {
+        Path userClasspath = getCommandline().getClasspath();
+        if (userClasspath != null) {
+            if (reloading || classLoader == null) {
+                deleteClassLoader();
+                Path classpath = (Path) userClasspath.clone();
+                if (includeAntRuntime) {
+                    log("Implicitly adding " + antRuntimeClasses
+                        + " to CLASSPATH", Project.MSG_VERBOSE);
+                    classpath.append(antRuntimeClasses);
+                }
+                classLoader = getProject().createClassLoader(classpath);
+                if (getClass().getClassLoader() != null
+                    && getClass().getClassLoader() != Project.class.getClassLoader()) {
+                    classLoader.setParent(getClass().getClassLoader());
+                }
+                classLoader.setParentFirst(false);
+                classLoader.addJavaLibraries();
+                log("Using CLASSPATH " + classLoader.getClasspath(),
+                    Project.MSG_VERBOSE);
+                // make sure the test will be accepted as a TestCase
+                classLoader.addSystemPackageRoot("junit");
+                // make sure the test annotation are accepted
+                classLoader.addSystemPackageRoot("org.junit");
+                // will cause trouble in JDK 1.1 if omitted
+                classLoader.addSystemPackageRoot("org.apache.tools.ant");
+            }
+        }
+    }
+
+    /**
+     * Removes resources.
+     *
+     * <p>Is invoked in {@link #execute execute}.  Subclasses that
+     * don't invoke execute should invoke this method in a finally
+     * block.</p>
+     *
+     * @since Ant 1.7.1
+     */
+    protected void cleanup() {
+        deleteClassLoader();
+        delegate = null;
+    }
+
+    /**
+     * Removes a classloader if needed.
+     * @since Ant 1.7
+     */
+    private void deleteClassLoader() {
+        if (classLoader != null) {
+            classLoader.cleanup();
+            classLoader = null;
+        }
+        if (mirrorLoader instanceof SplitLoader) {
+            ((SplitLoader) mirrorLoader).cleanup();
+        }
+        mirrorLoader = null;
+    }
+
+    /**
+     * Get the command line used to run the tests.
+     * @return the command line.
+     * @since Ant 1.6.2
+     */
+    protected CommandlineJava getCommandline() {
+        if (commandline == null) {
+            commandline = new CommandlineJava();
+        }
+        return commandline;
+    }
+
+    /**
+     * Forked test support
+     * @since Ant 1.6.2
+     */
+    private static final class ForkedTestConfiguration {
+        private boolean filterTrace;
+        private boolean haltOnError;
+        private boolean haltOnFailure;
+        private String errorProperty;
+        private String failureProperty;
+
+        /**
+         * constructor for forked test configuration
+         * @param filterTrace
+         * @param haltOnError
+         * @param haltOnFailure
+         * @param errorProperty
+         * @param failureProperty
+         */
+        ForkedTestConfiguration(boolean filterTrace, boolean haltOnError,
+                                boolean haltOnFailure, String errorProperty,
+                                String failureProperty) {
+            this.filterTrace = filterTrace;
+            this.haltOnError = haltOnError;
+            this.haltOnFailure = haltOnFailure;
+            this.errorProperty = errorProperty;
+            this.failureProperty = failureProperty;
+        }
+
+        /**
+         * configure from a test; sets member variables to attributes of the test
+         * @param test
+         */
+        ForkedTestConfiguration(JUnitTest test) {
+            this(test.getFiltertrace(),
+                    test.getHaltonerror(),
+                    test.getHaltonfailure(),
+                    test.getErrorProperty(),
+                    test.getFailureProperty());
+        }
+
+        /**
+         * equality test checks all the member variables
+         * @param other
+         * @return true if everything is equal
+         */
+        public boolean equals(Object other) {
+            if (other == null
+                || other.getClass() != ForkedTestConfiguration.class) {
+                return false;
+            }
+            ForkedTestConfiguration o = (ForkedTestConfiguration) other;
+            return filterTrace == o.filterTrace
+                && haltOnError == o.haltOnError
+                && haltOnFailure == o.haltOnFailure
+                && ((errorProperty == null && o.errorProperty == null)
+                    ||
+                    (errorProperty != null
+                     && errorProperty.equals(o.errorProperty)))
+                && ((failureProperty == null && o.failureProperty == null)
+                    ||
+                    (failureProperty != null
+                     && failureProperty.equals(o.failureProperty)));
+        }
+
+        /**
+         * hashcode is based only on the boolean members, and returns a value
+         * in the range 0-7.
+         * @return hash code value
+         */
+        public int hashCode() {
+            // CheckStyle:MagicNumber OFF
+            return (filterTrace ? 1 : 0)
+                + (haltOnError ? 2 : 0)
+                + (haltOnFailure ? 4 : 0);
+            // CheckStyle:MagicNumber ON
+        }
+    }
+
+    /**
+     * These are the different forking options
+     * @since 1.6.2
+     */
+    public static final class ForkMode extends EnumeratedAttribute {
+
+        /**
+         * fork once only
+         */
+        public static final String ONCE = "once";
+        /**
+         * fork once per test class
+         */
+        public static final String PER_TEST = "perTest";
+        /**
+         * fork once per batch of tests
+         */
+        public static final String PER_BATCH = "perBatch";
+
+        /** No arg constructor. */
+        public ForkMode() {
+            super();
+        }
+
+        /**
+         * Constructor using a value.
+         * @param value the value to use - once, perTest or perBatch.
+         */
+        public ForkMode(String value) {
+            super();
+            setValue(value);
+        }
+
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {ONCE, PER_TEST, PER_BATCH};
+        }
+    }
+
+    /**
+     * Executes all tests that don't need to be forked (or all tests
+     * if the runIndividual argument is true.  Returns a collection of
+     * lists of tests that share the same VM configuration and haven't
+     * been executed yet.
+     * @param testList the list of tests to be executed or queued.
+     * @param runIndividual if true execute each test individually.
+     * @return a list of tasks to be executed.
+     * @since 1.6.2
+     */
+    protected Collection executeOrQueue(Enumeration testList,
+                                        boolean runIndividual) {
+        Map testConfigurations = new HashMap();
+        while (testList.hasMoreElements()) {
+            JUnitTest test = (JUnitTest) testList.nextElement();
+            if (test.shouldRun(getProject())) {
+                if (runIndividual || !test.getFork()) {
+                    execute(test);
+                } else {
+                    ForkedTestConfiguration c =
+                        new ForkedTestConfiguration(test);
+                    List l = (List) testConfigurations.get(c);
+                    if (l == null) {
+                        l = new ArrayList();
+                        testConfigurations.put(c, l);
+                    }
+                    l.add(test);
+                }
+            }
+        }
+        return testConfigurations.values();
+    }
+
+    /**
+     * Logs information about failed tests, potentially stops
+     * processing (by throwing a BuildException) if a failure/error
+     * occurred or sets a property.
+     * @param exitValue the exitValue of the test.
+     * @param wasKilled if true, the test had been killed.
+     * @param test      the test in question.
+     * @param name      the name of the test.
+     * @since Ant 1.6.2
+     */
+    protected void actOnTestResult(int exitValue, boolean wasKilled,
+                                   JUnitTest test, String name) {
+        TestResultHolder t = new TestResultHolder();
+        t.exitCode = exitValue;
+        t.timedOut = wasKilled;
+        actOnTestResult(t, test, name);
+    }
+
+    /**
+     * Logs information about failed tests, potentially stops
+     * processing (by throwing a BuildException) if a failure/error
+     * occurred or sets a property.
+     * @param result    the result of the test.
+     * @param test      the test in question.
+     * @param name      the name of the test.
+     * @since Ant 1.7
+     */
+    protected void actOnTestResult(TestResultHolder result, JUnitTest test,
+                                   String name) {
+        // if there is an error/failure and that it should halt, stop
+        // everything otherwise just log a statement
+        boolean fatal = result.timedOut || result.crashed;
+        boolean errorOccurredHere =
+            result.exitCode == JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS || fatal;
+        boolean failureOccurredHere =
+            result.exitCode != JUnitTaskMirror.JUnitTestRunnerMirror.SUCCESS || fatal;
+        if (errorOccurredHere || failureOccurredHere) {
+            if ((errorOccurredHere && test.getHaltonerror())
+                || (failureOccurredHere && test.getHaltonfailure())) {
+                throw new BuildException(name + " failed"
+                    + (result.timedOut ? " (timeout)" : "")
+                    + (result.crashed ? " (crashed)" : ""), getLocation());
+            } else {
+                log(name + " FAILED"
+                    + (result.timedOut ? " (timeout)" : "")
+                    + (result.crashed ? " (crashed)" : ""), Project.MSG_ERR);
+                if (errorOccurredHere && test.getErrorProperty() != null) {
+                    getProject().setNewProperty(test.getErrorProperty(), "true");
+                }
+                if (failureOccurredHere && test.getFailureProperty() != null) {
+                    getProject().setNewProperty(test.getFailureProperty(), "true");
+                }
+            }
+        }
+    }
+
+    /**
+     * A value class that contains the result of a test.
+     */
+    protected class TestResultHolder {
+        // CheckStyle:VisibilityModifier OFF - bc
+        /** the exit code of the test. */
+        public int exitCode = JUnitTaskMirror.JUnitTestRunnerMirror.ERRORS;
+        /** true if the test timed out */
+        public boolean timedOut = false;
+        /** true if the test crashed */
+        public boolean crashed = false;
+        // CheckStyle:VisibilityModifier ON
+    }
+
+    /**
+     * A stream handler for handling the junit task.
+     * @since Ant 1.7
+     */
+    protected static class JUnitLogOutputStream extends LogOutputStream {
+        private Task task; // local copy since LogOutputStream.task is private
+
+        /**
+         * Constructor.
+         * @param task the task being logged.
+         * @param level the log level used to log data written to this stream.
+         */
+        public JUnitLogOutputStream(Task task, int level) {
+            super(task, level);
+            this.task = task;
+        }
+
+        /**
+         * Logs a line.
+         * If the line starts with junit.framework.TestListener: set the level
+         * to MSG_VERBOSE.
+         * @param line the line to log.
+         * @param level the logging level to use.
+         */
+        protected void processLine(String line, int level) {
+            if (line.startsWith(TESTLISTENER_PREFIX)) {
+                task.log(line, Project.MSG_VERBOSE);
+            } else {
+                super.processLine(line, level);
+            }
+        }
+    }
+
+    /**
+     * A log stream handler for junit.
+     * @since Ant 1.7
+     */
+    protected static class JUnitLogStreamHandler extends PumpStreamHandler {
+        /**
+         * Constructor.
+         * @param task the task to log.
+         * @param outlevel the level to use for standard output.
+         * @param errlevel the level to use for error output.
+         */
+        public JUnitLogStreamHandler(Task task, int outlevel, int errlevel) {
+            super(new JUnitLogOutputStream(task, outlevel),
+                  new LogOutputStream(task, errlevel));
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
new file mode 100644
index 0000000..defb09f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
@@ -0,0 +1,188 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.types.Permissions;
+
+/**
+ * Handles the portions of {@link JUnitTask} which need to directly access
+ * actual JUnit classes, so that junit.jar need not be on Ant's startup classpath.
+ * Neither JUnitTask.java nor JUnitTaskMirror.java nor their transitive static
+ * deps may import any junit.** classes!
+ * Specifically, need to not refer to
+ * - JUnitResultFormatter or its subclasses
+ * - JUnitVersionHelper
+ * - JUnitTestRunner
+ * Cf.  JUnitTask.SplitLoader#isSplit(String)
+ * Public only to permit access from classes in this package; do not use directly.
+ *
+ * @since 1.7
+ * @see "bug #38799"
+ */
+public interface JUnitTaskMirror {
+
+    /**
+     * Add the formatter to be called when the jvm exits before
+     * the test suite finishs.
+     * @param test the test.
+     * @param formatter the fomatter to use.
+     * @param out the output stream to use.
+     * @param message the message to write out.
+     * @param testCase the name of the test.
+     */
+    void addVmExit(JUnitTest test, JUnitResultFormatterMirror formatter,
+            OutputStream out, String message, String testCase);
+
+    /**
+     * Create a new test runner for a test.
+     * @param test the test to run.
+     * @param haltOnError if true halt the tests if an error occurs.
+     * @param filterTrace if true filter the stack traces.
+     * @param haltOnFailure if true halt the test if a failure occurs.
+     * @param showOutput    if true show output.
+     * @param logTestListenerEvents if true log test listener events.
+     * @param classLoader      the classloader to use to create the runner.
+     * @return the test runner.
+     */
+    JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, boolean haltOnError,
+            boolean filterTrace, boolean haltOnFailure, boolean showOutput,
+            boolean logTestListenerEvents, AntClassLoader classLoader);
+
+    /**
+     * Create a summary result formatter.
+     * @return the created formatter.
+     */
+    SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter();
+
+
+    /** The interface that JUnitResultFormatter extends. */
+    public interface JUnitResultFormatterMirror {
+        /**
+         * Set the output stream.
+         * @param outputStream the stream to use.
+         */
+        void setOutput(OutputStream outputStream);
+    }
+
+    /** The interface that SummaryJUnitResultFormatter extends. */
+    public interface SummaryJUnitResultFormatterMirror
+        extends JUnitResultFormatterMirror {
+
+        /**
+         * Set where standard out and standard error should be included.
+         * @param value if true include the outputs in the summary.
+         */
+        void setWithOutAndErr(boolean value);
+    }
+
+    /** Interface that test runners implement. */
+    public interface JUnitTestRunnerMirror {
+
+        /**
+         * Used in formatter arguments as a placeholder for the basename
+         * of the output file (which gets replaced by a test specific
+         * output file name later).
+         *
+         * @since Ant 1.6.3
+         */
+        String IGNORED_FILE_NAME = "IGNORETHIS";
+
+        /**
+         * No problems with this test.
+         */
+        int SUCCESS = 0;
+
+        /**
+         * Some tests failed.
+         */
+        int FAILURES = 1;
+
+        /**
+         * An error occurred.
+         */
+        int ERRORS = 2;
+
+        /**
+         * Permissions for the test run.
+         * @param perm the permissions to use.
+         */
+        void setPermissions(Permissions perm);
+
+        /** Run the test. */
+        void run();
+
+        /**
+         * Add a formatter to the test.
+         * @param formatter the formatter to use.
+         */
+        void addFormatter(JUnitResultFormatterMirror formatter);
+
+        /**
+         * Returns what System.exit() would return in the standalone version.
+         *
+         * @return 2 if errors occurred, 1 if tests failed else 0.
+         */
+        int getRetCode();
+
+        /**
+         * Handle output sent to System.err.
+         *
+         * @param output coming from System.err
+         */
+        void handleErrorFlush(String output);
+
+        /**
+         * Handle output sent to System.err.
+         *
+         * @param output output for System.err
+         */
+        void handleErrorOutput(String output);
+
+        /**
+         * Handle output sent to System.out.
+         *
+         * @param output output for System.out.
+         */
+        void handleOutput(String output);
+
+        /**
+         * Handle an input request.
+         *
+         * @param buffer the buffer into which data is to be read.
+         * @param offset the offset into the buffer at which data is stored.
+         * @param length the amount of data to read.
+         *
+         * @return the number of bytes read.
+         *
+         * @exception IOException if the data cannot be read.
+         */
+        int handleInput(byte[] buffer, int offset, int length) throws IOException;
+
+        /**
+         * Handle output sent to System.out.
+         *
+         * @param output output for System.out.
+         */
+       void handleFlush(String output);
+
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
new file mode 100644
index 0000000..815728b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import org.apache.tools.ant.AntClassLoader;
+
+/**
+ * Implementation of the part of the junit task which can directly refer to junit.* classes.
+ * Public only to permit use of reflection; do not use directly.
+ * @see JUnitTaskMirror
+ * @see "bug #38799"
+ * @since 1.7
+ */
+public final class JUnitTaskMirrorImpl implements JUnitTaskMirror {
+
+    private final JUnitTask task;
+
+    /**
+     * Constructor.
+     * @param task the junittask that uses this mirror.
+     */
+    public JUnitTaskMirrorImpl(JUnitTask task) {
+        this.task = task;
+    }
+
+    /** {@inheritDoc}. */
+    public void addVmExit(JUnitTest test, JUnitTaskMirror.JUnitResultFormatterMirror aFormatter,
+            OutputStream out, String message, String testCase) {
+        JUnitResultFormatter formatter = (JUnitResultFormatter) aFormatter;
+        formatter.setOutput(out);
+        formatter.startTestSuite(test);
+        //the trick to integrating test output to the formatter, is to
+        //create a special test class that asserts an error
+        //and tell the formatter that it raised.
+        TestCase t = new VmExitErrorTest(message, test, testCase);
+        formatter.startTest(t);
+        formatter.addError(t, new AssertionFailedError(message));
+        formatter.endTestSuite(test);
+    }
+
+    /** {@inheritDoc}. */
+    public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test,
+            boolean haltOnError, boolean filterTrace, boolean haltOnFailure,
+            boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) {
+        return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure,
+                showOutput, logTestListenerEvents, classLoader);
+    }
+
+    /** {@inheritDoc}. */
+    public JUnitTaskMirror.SummaryJUnitResultFormatterMirror newSummaryJUnitResultFormatter() {
+        return new SummaryJUnitResultFormatter();
+    }
+
+    static class VmExitErrorTest extends TestCase {
+
+        private String message;
+        private JUnitTest test;
+        private String testCase;
+
+        VmExitErrorTest(String aMessage, JUnitTest anOriginalTest, String aTestCase) {
+            message = aMessage;
+            test = anOriginalTest;
+            testCase = aTestCase;
+        }
+
+        public int countTestCases() {
+            return 1;
+        }
+
+        public void run(TestResult r) {
+            throw new AssertionFailedError(message);
+        }
+
+        public String getName() {
+            return testCase;
+        }
+
+        String getClassName() {
+            return test.getName();
+        }
+
+        public String toString() {
+            return test.getName() + ":" + testCase;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
new file mode 100644
index 0000000..e3cac56
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.tools.ant.Project;
+
+/**
+ * <p> Run a single JUnit test.
+ *
+ * <p> The JUnit test is actually run by {@link JUnitTestRunner}.
+ * So read the doc comments for that class :)
+ *
+ * @since Ant 1.2
+ *
+ * @see JUnitTask
+ * @see JUnitTestRunner
+ */
+public class JUnitTest extends BaseTest implements Cloneable {
+
+    /** the name of the test case */
+    private String name = null;
+
+    /** the name of the result file */
+    private String outfile = null;
+
+    // @todo this is duplicating TestResult information. Only the time is not
+    // part of the result. So we'd better derive a new class from TestResult
+    // and deal with it. (SB)
+    private long runs, failures, errors;
+    private long runTime;
+
+    // Snapshot of the system properties
+    private Properties props = null;
+
+    /** No arg constructor. */
+    public JUnitTest() {
+    }
+
+    /**
+     * Constructor with name.
+     * @param name the name of the test.
+     */
+    public JUnitTest(String name) {
+        this.name  = name;
+    }
+
+    /**
+     * Constructor with options.
+     * @param name the name of the test.
+     * @param haltOnError if true halt the tests if there is an error.
+     * @param haltOnFailure if true halt the tests if there is a failure.
+     * @param filtertrace if true filter stack traces.
+     */
+    public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
+                     boolean filtertrace) {
+        this.name  = name;
+        this.haltOnError = haltOnError;
+        this.haltOnFail = haltOnFailure;
+        this.filtertrace = filtertrace;
+    }
+
+    /**
+     * Set the name of the test class.
+     * @param value the name to use.
+     */
+    public void setName(String value) {
+        name = value;
+    }
+
+    /**
+     * Set the name of the output file.
+     * @param value the name of the output file to use.
+     */
+    public void setOutfile(String value) {
+        outfile = value;
+    }
+
+    /**
+     * Get the name of the test class.
+     * @return the name of the test.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the name of the output file
+     *
+     * @return the name of the output file.
+     */
+    public String getOutfile() {
+        return outfile;
+    }
+
+    /**
+     * Set the number of runs, failures and errors.
+     * @param runs     the number of runs.
+     * @param failures the number of failures.
+     * @param errors   the number of errors.
+     */
+    public void setCounts(long runs, long failures, long errors) {
+        this.runs = runs;
+        this.failures = failures;
+        this.errors = errors;
+    }
+
+    /**
+     * Set the runtime.
+     * @param runTime the time in milliseconds.
+     */
+    public void setRunTime(long runTime) {
+        this.runTime = runTime;
+    }
+
+    /**
+     * Get the number of runs.
+     * @return the number of runs.
+     */
+    public long runCount() {
+        return runs;
+    }
+
+    /**
+     * Get the number of failures.
+     * @return the number of failures.
+     */
+    public long failureCount() {
+        return failures;
+    }
+
+    /**
+     * Get the number of errors.
+     * @return the number of errors.
+     */
+    public long errorCount() {
+        return errors;
+    }
+
+    /**
+     * Get the run time.
+     * @return the run time in milliseconds.
+     */
+    public long getRunTime() {
+        return runTime;
+    }
+
+    /**
+     * Get the properties used in the test.
+     * @return the properties.
+     */
+    public Properties getProperties() {
+        return props;
+    }
+
+    /**
+     * Set the properties to be used in the test.
+     * @param p the properties.
+     *          This is a copy of the projects ant properties.
+     */
+    public void setProperties(Hashtable p) {
+        props = new Properties();
+        for (Enumeration e = p.keys(); e.hasMoreElements();) {
+            Object key = e.nextElement();
+            props.put(key, p.get(key));
+        }
+    }
+
+    /**
+     * Check if this test should run based on the if and unless
+     * attributes.
+     * @param p the project to use to check if the if and unless
+     *          properties exist in.
+     * @return true if this test or testsuite should be run.
+     */
+    public boolean shouldRun(Project p) {
+        if (ifProperty != null && p.getProperty(ifProperty) == null) {
+            return false;
+        } else if (unlessProperty != null
+                    && p.getProperty(unlessProperty) != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Get the formatters set for this test.
+     * @return the formatters as an array.
+     */
+    public FormatterElement[] getFormatters() {
+        FormatterElement[] fes = new FormatterElement[formatters.size()];
+        formatters.copyInto(fes);
+        return fes;
+    }
+
+    /**
+     * Convenient method to add formatters to a vector
+     */
+    void addFormattersTo(Vector v) {
+        final int count = formatters.size();
+        for (int i = 0; i < count; i++) {
+            v.addElement(formatters.elementAt(i));
+        }
+    }
+
+    /**
+     * @since Ant 1.5
+     * @return a clone of this test.
+     */
+    public Object clone() {
+        try {
+            JUnitTest t = (JUnitTest) super.clone();
+            t.props = props == null ? null : (Properties) props.clone();
+            t.formatters = (Vector) formatters.clone();
+            return t;
+        } catch (CloneNotSupportedException e) {
+            // plain impossible
+            return this;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
new file mode 100644
index 0000000..d59bb52
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
@@ -0,0 +1,1035 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.reflect.Method;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestFailure;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Permissions;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+/**
+ * Simple Testrunner for JUnit that runs all tests of a testsuite.
+ *
+ * <p>This TestRunner expects a name of a TestCase class as its
+ * argument. If this class provides a static suite() method it will be
+ * called and the resulting Test will be run. So, the signature should be
+ * <pre><code>
+ *     public static junit.framework.Test suite()
+ * </code></pre>
+ *
+ * <p> If no such method exists, all public methods starting with
+ * "test" and taking no argument will be run.
+ *
+ * <p> Summary output is generated at the end.
+ *
+ * @since Ant 1.2
+ */
+
+public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestRunnerMirror {
+
+    /**
+     * Holds the registered formatters.
+     */
+    private Vector formatters = new Vector();
+
+    /**
+     * Collects TestResults.
+     */
+    private TestResult res;
+
+    /**
+     * Do we filter junit.*.* stack frames out of failure and error exceptions.
+     */
+    private static boolean filtertrace = true;
+
+    /**
+     * Do we send output to System.out/.err in addition to the formatters?
+     */
+    private boolean showOutput = false;
+
+    private boolean outputToFormatters = true;
+
+    /**
+     * The permissions set for the test to run.
+     */
+    private Permissions perm = null;
+
+    private static final String[] DEFAULT_TRACE_FILTERS = new String[] {
+                "junit.framework.TestCase",
+                "junit.framework.TestResult",
+                "junit.framework.TestSuite",
+                "junit.framework.Assert.", // don't filter AssertionFailure
+                "junit.swingui.TestRunner",
+                "junit.awtui.TestRunner",
+                "junit.textui.TestRunner",
+                "java.lang.reflect.Method.invoke(",
+                "sun.reflect.",
+                "org.apache.tools.ant.",
+                // JUnit 4 support:
+                "org.junit.",
+                "junit.framework.JUnit4TestAdapter",
+                // See wrapListener for reason:
+                "Caused by: java.lang.AssertionError",
+                " more",
+        };
+
+
+    /**
+     * Do we stop on errors.
+     */
+    private boolean haltOnError = false;
+
+    /**
+     * Do we stop on test failures.
+     */
+    private boolean haltOnFailure = false;
+
+    /**
+     * Returncode
+     */
+    private int retCode = SUCCESS;
+
+    /**
+     * The TestSuite we are currently running.
+     */
+    private JUnitTest junitTest;
+
+    /** output written during the test */
+    private PrintStream systemError;
+
+    /** Error output during the test */
+    private PrintStream systemOut;
+
+    /** is this runner running in forked mode? */
+    private boolean forked = false;
+
+    /** Running more than one test suite? */
+    private static boolean multipleTests = false;
+
+    /** ClassLoader passed in in non-forked mode. */
+    private ClassLoader loader;
+
+    /** Do we print TestListener events? */
+    private boolean logTestListenerEvents = false;
+
+    /** Turned on if we are using JUnit 4 for this test suite. see #38811 */
+    private boolean junit4;
+
+    /**
+     * The file used to indicate that the build crashed.
+     * File will be empty in case the build did not crash.
+     */
+    private static String crashFile = null;
+
+    /**
+     * Constructor for fork=true or when the user hasn't specified a
+     * classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure) {
+        this(test, haltOnError, filtertrace, haltOnFailure, false);
+    }
+
+    /**
+     * Constructor for fork=true or when the user hasn't specified a
+     * classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     * @param showOutput    whether to send output to System.out/.err as well as formatters.
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure,
+                           boolean showOutput) {
+        this(test, haltOnError, filtertrace, haltOnFailure, showOutput, false);
+    }
+
+    /**
+     * Constructor for fork=true or when the user hasn't specified a
+     * classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     * @param showOutput    whether to send output to System.out/.err as well as formatters.
+     * @param logTestListenerEvents whether to print TestListener events.
+     * @since Ant 1.7
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure,
+                           boolean showOutput, boolean logTestListenerEvents) {
+        this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
+             logTestListenerEvents, null);
+    }
+
+    /**
+     * Constructor to use when the user has specified a classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     * @param loader the classloader to use running the test.
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure,
+                           ClassLoader loader) {
+        this(test, haltOnError, filtertrace, haltOnFailure, false, loader);
+    }
+
+    /**
+     * Constructor to use when the user has specified a classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     * @param showOutput    whether to send output to System.out/.err as well as formatters.
+     * @param loader the classloader to use running the test.
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure,
+                           boolean showOutput, ClassLoader loader) {
+        this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
+             false, loader);
+    }
+
+    /**
+     * Constructor to use when the user has specified a classpath.
+     * @param test the test to run.
+     * @param haltOnError whether to stop the run if an error is found.
+     * @param filtertrace whether to filter junit.*.* stack frames out of exceptions
+     * @param haltOnFailure whether to stop the run if failure is found.
+     * @param showOutput    whether to send output to System.out/.err as well as formatters.
+     * @param logTestListenerEvents whether to print TestListener events.
+     * @param loader the classloader to use running the test.
+     * @since Ant 1.7
+     */
+    public JUnitTestRunner(JUnitTest test, boolean haltOnError,
+                           boolean filtertrace, boolean haltOnFailure,
+                           boolean showOutput, boolean logTestListenerEvents,
+                           ClassLoader loader) {
+        JUnitTestRunner.filtertrace = filtertrace;
+        this.junitTest = test;
+        this.haltOnError = haltOnError;
+        this.haltOnFailure = haltOnFailure;
+        this.showOutput = showOutput;
+        this.logTestListenerEvents = logTestListenerEvents;
+        this.loader = loader;
+    }
+
+    private PrintStream savedOut = null;
+    private PrintStream savedErr = null;
+
+    private PrintStream createEmptyStream() {
+        return new PrintStream(
+            new OutputStream() {
+                public void write(int b) {
+                }
+            });
+    }
+
+    private PrintStream createTeePrint(PrintStream ps1, PrintStream ps2) {
+        return new PrintStream(new TeeOutputStream(ps1, ps2));
+    }
+
+    private void setupIOStreams(ByteArrayOutputStream o,
+                                ByteArrayOutputStream e) {
+        systemOut = new PrintStream(o);
+        systemError = new PrintStream(e);
+
+        if (forked) {
+            if (!outputToFormatters) {
+                if (!showOutput) {
+                    savedOut = System.out;
+                    savedErr = System.err;
+                    System.setOut(createEmptyStream());
+                    System.setErr(createEmptyStream());
+                }
+            } else {
+                savedOut = System.out;
+                savedErr = System.err;
+                if (!showOutput) {
+                    System.setOut(systemOut);
+                    System.setErr(systemError);
+                } else {
+                    System.setOut(createTeePrint(savedOut, systemOut));
+                    System.setErr(createTeePrint(savedErr, systemError));
+                }
+                perm = null;
+            }
+        } else {
+            if (perm != null) {
+                perm.setSecurityManager();
+            }
+        }
+    }
+
+    /**
+     * Run the test.
+     */
+    public void run() {
+        res = new TestResult();
+        res.addListener(wrapListener(this));
+        for (int i = 0; i < formatters.size(); i++) {
+            res.addListener(wrapListener((TestListener) formatters.elementAt(i)));
+        }
+
+        ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
+        ByteArrayOutputStream outStrm = new ByteArrayOutputStream();
+
+        setupIOStreams(outStrm, errStrm);
+
+        Test suite = null;
+        Throwable exception = null;
+        boolean startTestSuiteSuccess = false;
+
+        try {
+
+            try {
+                Class testClass = null;
+                if (loader == null) {
+                    testClass = Class.forName(junitTest.getName());
+                } else {
+                    testClass = Class.forName(junitTest.getName(), true,
+                                              loader);
+                }
+
+                // check for a static suite method first, even when using
+                // JUnit 4
+                Method suiteMethod = null;
+                try {
+                    // check if there is a suite method
+                    suiteMethod = testClass.getMethod("suite", new Class[0]);
+                } catch (NoSuchMethodException e) {
+                    // no appropriate suite method found. We don't report any
+                    // error here since it might be perfectly normal.
+                }
+
+                if (suiteMethod != null) {
+                    // if there is a suite method available, then try
+                    // to extract the suite from it. If there is an error
+                    // here it will be caught below and reported.
+                    suite = (Test) suiteMethod.invoke(null, new Class[0]);
+
+                } else {
+                    Class junit4TestAdapterClass = null;
+
+                    // Check for JDK 5 first. Will *not* help on JDK 1.4
+                    // if only junit-4.0.jar in CP because in that case
+                    // linkage of whole task will already have failed! But
+                    // will help if CP has junit-3.8.2.jar:junit-4.0.jar.
+
+                    // In that case first C.fN will fail with CNFE and we
+                    // will avoid UnsupportedClassVersionError.
+
+                    try {
+                        Class.forName("java.lang.annotation.Annotation");
+                        if (loader == null) {
+                            junit4TestAdapterClass =
+                                Class.forName("junit.framework.JUnit4TestAdapter");
+                        } else {
+                            junit4TestAdapterClass =
+                                Class.forName("junit.framework.JUnit4TestAdapter",
+                                              true, loader);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        // OK, fall back to JUnit 3.
+                    }
+                    junit4 = junit4TestAdapterClass != null;
+
+                    if (junit4) {
+                        // Let's use it!
+                        suite =
+                            (Test) junit4TestAdapterClass
+                            .getConstructor(new Class[] {Class.class}).
+                            newInstance(new Object[] {testClass});
+                    } else {
+                        // Use JUnit 3.
+
+                        // try to extract a test suite automatically this
+                        // will generate warnings if the class is no
+                        // suitable Test
+                        suite = new TestSuite(testClass);
+                    }
+
+                }
+
+            } catch (Throwable e) {
+                retCode = ERRORS;
+                exception = e;
+            }
+
+            long start = System.currentTimeMillis();
+
+            fireStartTestSuite();
+            startTestSuiteSuccess = true;
+            if (exception != null) { // had an exception constructing suite
+                for (int i = 0; i < formatters.size(); i++) {
+                    ((TestListener) formatters.elementAt(i))
+                        .addError(null, exception);
+                }
+                junitTest.setCounts(1, 0, 1);
+                junitTest.setRunTime(0);
+            } else {
+                try {
+                    logTestListenerEvent("tests to run: " + suite.countTestCases());
+                    suite.run(res);
+                } finally {
+                    if (junit4) {
+                        int[] cnts = findJUnit4FailureErrorCount(res);
+                        junitTest.setCounts(res.runCount(), cnts[0], cnts[1]);
+                    } else {
+                        junitTest.setCounts(res.runCount(), res.failureCount(),
+                                res.errorCount());
+                    }
+                    junitTest.setRunTime(System.currentTimeMillis() - start);
+                }
+            }
+        } finally {
+            if (perm != null) {
+                perm.restoreSecurityManager();
+            }
+            if (savedOut != null) {
+                System.setOut(savedOut);
+            }
+            if (savedErr != null) {
+                System.setErr(savedErr);
+            }
+
+            systemError.close();
+            systemError = null;
+            systemOut.close();
+            systemOut = null;
+            if (startTestSuiteSuccess) {
+                sendOutAndErr(new String(outStrm.toByteArray()),
+                              new String(errStrm.toByteArray()));
+            }
+        }
+        fireEndTestSuite();
+
+        if (retCode != SUCCESS || res.errorCount() != 0) {
+            retCode = ERRORS;
+        } else if (res.failureCount() != 0) {
+            retCode = FAILURES;
+        }
+    }
+
+    /**
+     * Returns what System.exit() would return in the standalone version.
+     *
+     * @return 2 if errors occurred, 1 if tests failed else 0.
+     */
+    public int getRetCode() {
+        return retCode;
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A new Test is started.
+     * @param t the test.
+     */
+    public void startTest(Test t) {
+        String testName = JUnitVersionHelper.getTestCaseName(t);
+        logTestListenerEvent("startTest(" + testName + ")");
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test is finished.
+     * @param test the test.
+     */
+    public void endTest(Test test) {
+        String testName = JUnitVersionHelper.getTestCaseName(test);
+        logTestListenerEvent("endTest(" + testName + ")");
+    }
+
+    private void logTestListenerEvent(String msg) {
+        PrintStream out = savedOut != null ? savedOut : System.out;
+        if (logTestListenerEvents) {
+            out.flush();
+            out.println(JUnitTask.TESTLISTENER_PREFIX + msg);
+            out.flush();
+        }
+    }
+
+    /**
+     * Interface TestListener for JUnit &lt;= 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t    the exception thrown by the test.
+     */
+    public void addFailure(Test test, Throwable t) {
+        String testName = JUnitVersionHelper.getTestCaseName(test);
+        logTestListenerEvent("addFailure(" + testName + ", " + t.getMessage() + ")");
+        if (haltOnFailure) {
+            res.stop();
+        }
+    }
+
+    /**
+     * Interface TestListener for JUnit &gt; 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t    the assertion thrown by the test.
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        addFailure(test, (Throwable) t);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>An error occurred while running the test.
+     * @param test the test.
+     * @param t    the error thrown by the test.
+     */
+    public void addError(Test test, Throwable t) {
+        String testName = JUnitVersionHelper.getTestCaseName(test);
+        logTestListenerEvent("addError(" + testName + ", " + t.getMessage() + ")");
+        if (haltOnError) {
+            res.stop();
+        }
+    }
+
+    /**
+     * Permissions for the test run.
+     * @since Ant 1.6
+     * @param permissions the permissions to use.
+     */
+    public void setPermissions(Permissions permissions) {
+        perm = permissions;
+    }
+
+    /**
+     * Handle a string destined for standard output.
+     * @param output the string to output
+     */
+    public void handleOutput(String output) {
+        if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) {
+            // ignore
+        } else if (systemOut != null) {
+            systemOut.print(output);
+        }
+    }
+
+    /**
+     * Handle input.
+     * @param buffer not used.
+     * @param offset not used.
+     * @param length not used.
+     * @return -1 always.
+     * @throws IOException never.
+     * @see org.apache.tools.ant.Task#handleInput(byte[], int, int)
+     *
+     * @since Ant 1.6
+     */
+    public int handleInput(byte[] buffer, int offset, int length)
+        throws IOException {
+        return -1;
+    }
+
+    /** {@inheritDoc}. */
+    public void handleErrorOutput(String output) {
+        if (systemError != null) {
+            systemError.print(output);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public void handleFlush(String output) {
+        if (systemOut != null) {
+            systemOut.print(output);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public void handleErrorFlush(String output) {
+        if (systemError != null) {
+            systemError.print(output);
+        }
+    }
+
+    private void sendOutAndErr(String out, String err) {
+        for (int i = 0; i < formatters.size(); i++) {
+            JUnitResultFormatter formatter =
+                ((JUnitResultFormatter) formatters.elementAt(i));
+
+            formatter.setSystemOutput(out);
+            formatter.setSystemError(err);
+        }
+    }
+
+    private void fireStartTestSuite() {
+        for (int i = 0; i < formatters.size(); i++) {
+            ((JUnitResultFormatter) formatters.elementAt(i))
+                .startTestSuite(junitTest);
+        }
+    }
+
+    private void fireEndTestSuite() {
+        for (int i = 0; i < formatters.size(); i++) {
+            ((JUnitResultFormatter) formatters.elementAt(i))
+                .endTestSuite(junitTest);
+        }
+    }
+
+    /**
+     * Add a formatter.
+     * @param f the formatter to add.
+     */
+    public void addFormatter(JUnitResultFormatter f) {
+        formatters.addElement(f);
+    }
+
+    /** {@inheritDoc}. */
+    public void addFormatter(JUnitTaskMirror.JUnitResultFormatterMirror f) {
+        formatters.addElement((JUnitResultFormatter) f);
+    }
+
+    /**
+     * Entry point for standalone (forked) mode.
+     *
+     * Parameters: testcaseclassname plus parameters in the format
+     * key=value, none of which is required.
+     *
+     * <table cols="4" border="1">
+     * <tr><th>key</th><th>description</th><th>default value</th></tr>
+     *
+     * <tr><td>haltOnError</td><td>halt test on
+     * errors?</td><td>false</td></tr>
+     *
+     * <tr><td>haltOnFailure</td><td>halt test on
+     * failures?</td><td>false</td></tr>
+     *
+     * <tr><td>formatter</td><td>A JUnitResultFormatter given as
+     * classname,filename. If filename is ommitted, System.out is
+     * assumed.</td><td>none</td></tr>
+     *
+     * <tr><td>showoutput</td><td>send output to System.err/.out as
+     * well as to the formatters?</td><td>false</td></tr>
+     *
+     * <tr><td>logtestlistenerevents</td><td>log TestListener events to
+     * System.out.</td><td>false</td></tr>
+     *
+     * </table>
+     * @param args the command line arguments.
+     * @throws IOException on error.
+     */
+    public static void main(String[] args) throws IOException {
+        boolean haltError = false;
+        boolean haltFail = false;
+        boolean stackfilter = true;
+        Properties props = new Properties();
+        boolean showOut = false;
+        boolean outputToFormat = true;
+        boolean logTestListenerEvents = false;
+
+
+        if (args.length == 0) {
+            System.err.println("required argument TestClassName missing");
+            System.exit(ERRORS);
+        }
+
+        if (args[0].startsWith(Constants.TESTSFILE)) {
+            multipleTests = true;
+            args[0] = args[0].substring(Constants.TESTSFILE.length());
+        }
+
+        for (int i = 1; i < args.length; i++) {
+            if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
+                haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length()));
+            } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) {
+                haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length()));
+            } else if (args[i].startsWith(Constants.FILTERTRACE)) {
+                stackfilter = Project.toBoolean(args[i].substring(Constants.FILTERTRACE.length()));
+            } else if (args[i].startsWith(Constants.CRASHFILE)) {
+                crashFile = args[i].substring(Constants.CRASHFILE.length());
+                registerTestCase(Constants.BEFORE_FIRST_TEST);
+            } else if (args[i].startsWith(Constants.FORMATTER)) {
+                try {
+                    createAndStoreFormatter(args[i].substring(Constants.FORMATTER.length()));
+                } catch (BuildException be) {
+                    System.err.println(be.getMessage());
+                    System.exit(ERRORS);
+                }
+            } else if (args[i].startsWith(Constants.PROPSFILE)) {
+                FileInputStream in = new FileInputStream(args[i]
+                                                         .substring(Constants.PROPSFILE.length()));
+                props.load(in);
+                in.close();
+            } else if (args[i].startsWith(Constants.SHOWOUTPUT)) {
+                showOut = Project.toBoolean(args[i].substring(Constants.SHOWOUTPUT.length()));
+            } else if (args[i].startsWith(Constants.LOGTESTLISTENEREVENTS)) {
+                logTestListenerEvents = Project.toBoolean(
+                    args[i].substring(Constants.LOGTESTLISTENEREVENTS.length()));
+            } else if (args[i].startsWith(Constants.OUTPUT_TO_FORMATTERS)) {
+                outputToFormat = Project.toBoolean(
+                    args[i].substring(Constants.OUTPUT_TO_FORMATTERS.length()));
+            }
+        }
+
+        // Add/overlay system properties on the properties from the Ant project
+        Hashtable p = System.getProperties();
+        for (Enumeration e = p.keys(); e.hasMoreElements();) {
+            Object key = e.nextElement();
+            props.put(key, p.get(key));
+        }
+
+        int returnCode = SUCCESS;
+        if (multipleTests) {
+            try {
+                java.io.BufferedReader reader =
+                    new java.io.BufferedReader(new java.io.FileReader(args[0]));
+                String testCaseName;
+                int code = 0;
+                boolean errorOccurred = false;
+                boolean failureOccurred = false;
+                String line = null;
+                while ((line = reader.readLine()) != null) {
+                    StringTokenizer st = new StringTokenizer(line, ",");
+                    testCaseName = st.nextToken();
+                    JUnitTest t = new JUnitTest(testCaseName);
+                    t.setTodir(new File(st.nextToken()));
+                    t.setOutfile(st.nextToken());
+                    t.setProperties(props);
+                    code = launch(t, haltError, stackfilter, haltFail,
+                                  showOut, outputToFormat,
+                                  logTestListenerEvents);
+                    errorOccurred = (code == ERRORS);
+                    failureOccurred = (code != SUCCESS);
+                    if (errorOccurred || failureOccurred) {
+                        if ((errorOccurred && haltError)
+                            || (failureOccurred && haltFail)) {
+                            registerNonCrash();
+                            System.exit(code);
+                        } else {
+                            if (code > returnCode) {
+                                returnCode = code;
+                            }
+                            System.out.println("TEST " + t.getName()
+                                               + " FAILED");
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        } else {
+            JUnitTest t = new JUnitTest(args[0]);
+            t.setProperties(props);
+            returnCode = launch(
+                t, haltError, stackfilter, haltFail,
+                showOut, outputToFormat, logTestListenerEvents);
+        }
+
+        registerNonCrash();
+        System.exit(returnCode);
+    }
+
+    private static Vector fromCmdLine = new Vector();
+
+    private static void transferFormatters(JUnitTestRunner runner,
+                                           JUnitTest test) {
+        runner.addFormatter(new JUnitResultFormatter() {
+
+            public void startTestSuite(JUnitTest suite) throws BuildException {
+            }
+
+            public void endTestSuite(JUnitTest suite) throws BuildException {
+            }
+
+            public void setOutput(OutputStream out) {
+            }
+
+            public void setSystemOutput(String out) {
+            }
+
+            public void setSystemError(String err) {
+            }
+
+            public void addError(Test arg0, Throwable arg1) {
+            }
+
+            public void addFailure(Test arg0, AssertionFailedError arg1) {
+            }
+
+            public void endTest(Test arg0) {
+            }
+
+            public void startTest(Test arg0) {
+                registerTestCase(JUnitVersionHelper.getTestCaseName(arg0));
+            }
+        });
+        for (int i = 0; i < fromCmdLine.size(); i++) {
+            FormatterElement fe = (FormatterElement) fromCmdLine.elementAt(i);
+            if (multipleTests && fe.getUseFile()) {
+                File destFile =
+                    new File(test.getTodir(),
+                             test.getOutfile() + fe.getExtension());
+                fe.setOutfile(destFile);
+            }
+            runner.addFormatter((JUnitResultFormatter) fe.createFormatter());
+        }
+    }
+
+    /**
+     * Line format is: formatter=<classname>(,<pathname>)?
+     */
+    private static void createAndStoreFormatter(String line)
+        throws BuildException {
+        FormatterElement fe = new FormatterElement();
+        int pos = line.indexOf(',');
+        if (pos == -1) {
+            fe.setClassname(line);
+            fe.setUseFile(false);
+        } else {
+            fe.setClassname(line.substring(0, pos));
+            fe.setUseFile(true);
+            if (!multipleTests) {
+                fe.setOutfile(new File(line.substring(pos + 1)));
+            } else {
+                int fName = line.indexOf(IGNORED_FILE_NAME);
+                if (fName > -1) {
+                    fe.setExtension(line
+                                    .substring(fName
+                                               + IGNORED_FILE_NAME.length()));
+                }
+            }
+        }
+        fromCmdLine.addElement(fe);
+    }
+
+    /**
+     * Returns a filtered stack trace.
+     * This is ripped out of junit.runner.BaseTestRunner.
+     * @param t the exception to filter.
+     * @return the filtered stack trace.
+     */
+    public static String getFilteredTrace(Throwable t) {
+        String trace = StringUtils.getStackTrace(t);
+        return JUnitTestRunner.filterStack(trace);
+    }
+
+    /**
+     * Filters stack frames from internal JUnit and Ant classes
+     * @param stack the stack trace to filter.
+     * @return the filtered stack.
+     */
+    public static String filterStack(String stack) {
+        if (!filtertrace) {
+            return stack;
+        }
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        StringReader sr = new StringReader(stack);
+        BufferedReader br = new BufferedReader(sr);
+
+        String line;
+        try {
+            while ((line = br.readLine()) != null) {
+                if (!filterLine(line)) {
+                    pw.println(line);
+                }
+            }
+        } catch (Exception e) {
+            return stack; // return the stack unfiltered
+        }
+        return sw.toString();
+    }
+
+    private static boolean filterLine(String line) {
+        for (int i = 0; i < DEFAULT_TRACE_FILTERS.length; i++) {
+            if (line.indexOf(DEFAULT_TRACE_FILTERS[i]) != -1) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @since Ant 1.6.2
+     */
+    private static int launch(JUnitTest t, boolean haltError,
+                              boolean stackfilter, boolean haltFail,
+                              boolean showOut, boolean outputToFormat,
+                              boolean logTestListenerEvents) {
+        JUnitTestRunner runner =
+            new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut,
+                                logTestListenerEvents, null);
+        runner.forked = true;
+        runner.outputToFormatters = outputToFormat;
+        transferFormatters(runner, t);
+
+        runner.run();
+        return runner.getRetCode();
+     }
+
+    /**
+     * @since Ant 1.7
+     */
+    private static void registerNonCrash()
+            throws IOException {
+        if (crashFile != null) {
+            FileWriter out = null;
+            try {
+                out = new FileWriter(crashFile);
+                out.write(Constants.TERMINATED_SUCCESSFULLY + "\n");
+                out.flush();
+            } finally {
+                if (out != null) {
+                    out.close();
+                }
+            }
+        }
+    }
+
+    private static void registerTestCase(String testCase) {
+        if (crashFile != null) {
+            try {
+                FileWriter out = null;
+                try {
+                    out = new FileWriter(crashFile);
+                    out.write(testCase + "\n");
+                    out.flush();
+                } finally {
+                    if (out != null) {
+                        out.close();
+                    }
+                }
+            } catch (IOException e) {
+                // ignored.
+            }
+        }
+    }
+
+    /**
+     * Modifies a TestListener when running JUnit 4: treats AssertionFailedError
+     * as a failure not an error.
+     *
+     * @since Ant 1.7
+     */
+    private TestListener wrapListener(final TestListener testListener) {
+        return new TestListener() {
+            public void addError(Test test, Throwable t) {
+                if (junit4 && t instanceof AssertionFailedError) {
+                    // JUnit 4 does not distinguish between errors and failures
+                    // even in the JUnit 3 adapter.
+                    // So we need to help it a bit to retain compatibility for JUnit 3 tests.
+                    testListener.addFailure(test, (AssertionFailedError) t);
+                } else if (junit4 && t.getClass().getName().equals("java.lang.AssertionError")) {
+                    // Not strictly necessary but probably desirable.
+                    // JUnit 4-specific test GUIs will show just "failures".
+                    // But Ant's output shows "failures" vs. "errors".
+                    // We would prefer to show "failure" for things that logically are.
+                    try {
+                        String msg = t.getMessage();
+                        AssertionFailedError failure = msg != null
+                            ? new AssertionFailedError(msg) : new AssertionFailedError();
+                        // To compile on pre-JDK 4 (even though this should always succeed):
+                        Method initCause = Throwable.class.getMethod(
+                            "initCause", new Class[] {Throwable.class});
+                        initCause.invoke(failure, new Object[] {t});
+                        testListener.addFailure(test, failure);
+                    } catch (Exception e) {
+                        // Rats.
+                        e.printStackTrace(); // should not happen
+                        testListener.addError(test, t);
+                    }
+                } else {
+                    testListener.addError(test, t);
+                }
+            }
+            public void addFailure(Test test, AssertionFailedError t) {
+                testListener.addFailure(test, t);
+            }
+            public void addFailure(Test test, Throwable t) { // pre-3.4
+                if (t instanceof AssertionFailedError) {
+                    testListener.addFailure(test, (AssertionFailedError) t);
+                } else {
+                    testListener.addError(test, t);
+                }
+            }
+            public void endTest(Test test) {
+                testListener.endTest(test);
+            }
+            public void startTest(Test test) {
+                testListener.startTest(test);
+            }
+        };
+    }
+
+    /**
+     * Use instead of TestResult.get{Failure,Error}Count on JUnit 4,
+     * since the adapter claims that all failures are errors.
+     * @since Ant 1.7
+     */
+    private int[] findJUnit4FailureErrorCount(TestResult res) {
+        int failures = 0;
+        int errors = 0;
+        Enumeration e = res.failures();
+        while (e.hasMoreElements()) {
+            e.nextElement();
+            failures++;
+        }
+        e = res.errors();
+        while (e.hasMoreElements()) {
+            Throwable t = ((TestFailure) e.nextElement()).thrownException();
+            if (t instanceof AssertionFailedError
+                || t.getClass().getName().equals("java.lang.AssertionError")) {
+                failures++;
+            } else {
+                errors++;
+            }
+        }
+        return new int[] {failures, errors};
+    }
+
+} // JUnitTestRunner
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
new file mode 100644
index 0000000..4ef80f6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelper.java
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.lang.reflect.Method;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * Work around for some changes to the public JUnit API between
+ * different JUnit releases.
+ * @since Ant 1.7
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class JUnitVersionHelper {
+
+    private static Method testCaseName = null;
+
+    /**
+     * Name of the JUnit4 class we look for.
+     * {@value}
+     * @since Ant 1.7.1
+     */
+    public static final String JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE
+        = "junit.framework.JUnit4TestCaseFacade";
+    private static final String UNKNOWN_TEST_CASE_NAME = "unknown";
+
+    static {
+        try {
+            testCaseName = TestCase.class.getMethod("getName", new Class[0]);
+        } catch (NoSuchMethodException e) {
+            // pre JUnit 3.7
+            try {
+                testCaseName = TestCase.class.getMethod("name", new Class[0]);
+            } catch (NoSuchMethodException ignored) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * JUnit 3.7 introduces TestCase.getName() and subsequent versions
+     * of JUnit remove the old name() method.  This method provides
+     * access to the name of a TestCase via reflection that is
+     * supposed to work with version before and after JUnit 3.7.
+     *
+     * <p>since Ant 1.5.1 this method will invoke &quot;<code>public
+     * String getName()</code>&quot; on any implementation of Test if
+     * it exists.</p>
+     *
+     * <p>Since Ant 1.7 also checks for JUnit4TestCaseFacade explicitly.
+     * This is used by junit.framework.JUnit4TestAdapter.</p>
+     * @param t the test.
+     * @return the name of the test.
+     */
+    public static String getTestCaseName(Test t) {
+        if (t == null) {
+            return UNKNOWN_TEST_CASE_NAME;
+        }
+        if (t.getClass().getName().equals(JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE)) {
+            // Self-describing as of JUnit 4 (#38811). But trim "(ClassName)".
+            String name = t.toString();
+            if (name.endsWith(")")) {
+                int paren = name.lastIndexOf('(');
+                return name.substring(0, paren);
+            } else {
+                return name;
+            }
+        }
+        if (t instanceof TestCase && testCaseName != null) {
+            try {
+                return (String) testCaseName.invoke(t, new Object[0]);
+            } catch (Throwable ignored) {
+                // ignore
+            }
+        } else {
+            try {
+                Method getNameMethod = null;
+                try {
+                    getNameMethod =
+                        t.getClass().getMethod("getName", new Class [0]);
+                } catch (NoSuchMethodException e) {
+                    getNameMethod = t.getClass().getMethod("name",
+                                                           new Class [0]);
+                }
+                if (getNameMethod != null
+                    && getNameMethod.getReturnType() == String.class) {
+                    return (String) getNameMethod.invoke(t, new Object[0]);
+                }
+            } catch (Throwable ignored) {
+                // ignore
+            }
+        }
+        return UNKNOWN_TEST_CASE_NAME;
+    }
+
+    /**
+     * Tries to find the name of the class which a test represents
+     * across JUnit 3 and 4. For Junit4 it parses the toString() value of the
+     * test, and extracts it from there.
+     * @since Ant 1.7.1 (it was private until then)
+     * @param test test case to look at
+     * @return the extracted class name.
+     */
+    public static String getTestCaseClassName(Test test) {
+        String className = test.getClass().getName();
+        if (test instanceof JUnitTaskMirrorImpl.VmExitErrorTest) {
+            className = ((JUnitTaskMirrorImpl.VmExitErrorTest) test).getClassName();
+        } else
+        if (className.equals(JUNIT_FRAMEWORK_JUNIT4_TEST_CASE_FACADE)) {
+            // JUnit 4 wraps solo tests this way. We can extract
+            // the original test name with a little hack.
+            String name = test.toString();
+            int paren = name.lastIndexOf('(');
+            if (paren != -1 && name.endsWith(")")) {
+                className = name.substring(paren + 1, name.length() - 1);
+            }
+        }
+        return className;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java
new file mode 100644
index 0000000..e0dc16c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/OutErrSummaryJUnitResultFormatter.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * Used instead of SummaryJUnitResultFormatter in forked tests if
+ * withOutAndErr is requested.
+ */
+
+public class OutErrSummaryJUnitResultFormatter
+    extends SummaryJUnitResultFormatter {
+
+    /**
+     * Empty
+     */
+    public OutErrSummaryJUnitResultFormatter() {
+        super();
+        setWithOutAndErr(true);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java
new file mode 100644
index 0000000..3ddb731
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/PlainJUnitResultFormatter.java
@@ -0,0 +1,250 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.text.NumberFormat;
+import java.util.Hashtable;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ *
+ */
+
+public class PlainJUnitResultFormatter implements JUnitResultFormatter {
+
+    private static final double ONE_SECOND = 1000.0;
+
+    /**
+     * Formatter for timings.
+     */
+    private NumberFormat nf = NumberFormat.getInstance();
+    /**
+     * Timing helper.
+     */
+    private Hashtable testStarts = new Hashtable();
+    /**
+     * Where to write the log to.
+     */
+    private OutputStream out;
+    /**
+     * Helper to store intermediate output.
+     */
+    private StringWriter inner;
+    /**
+     * Convenience layer on top of {@link #inner inner}.
+     */
+    private PrintWriter wri;
+    /**
+     * Suppress endTest if testcase failed.
+     */
+    private Hashtable failed = new Hashtable();
+
+    private String systemOutput = null;
+    private String systemError = null;
+
+    /** No arg constructor */
+    public PlainJUnitResultFormatter() {
+        inner = new StringWriter();
+        wri = new PrintWriter(inner);
+    }
+
+    /** {@inheritDoc}. */
+    public void setOutput(OutputStream out) {
+        this.out = out;
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemOutput(String out) {
+        systemOutput = out;
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemError(String err) {
+        systemError = err;
+    }
+
+    /**
+     * The whole testsuite started.
+     * @param suite the test suite
+     * @throws BuildException if unable to write the output
+     */
+    public void startTestSuite(JUnitTest suite) throws BuildException {
+        if (out == null) {
+            return; // Quick return - no output do nothing.
+        }
+        StringBuffer sb = new StringBuffer("Testsuite: ");
+        sb.append(suite.getName());
+        sb.append(StringUtils.LINE_SEP);
+        try {
+            out.write(sb.toString().getBytes());
+            out.flush();
+        } catch (IOException ex) {
+            throw new BuildException("Unable to write output", ex);
+        }
+    }
+
+    /**
+     * The whole testsuite ended.
+     * @param suite the test suite
+     * @throws BuildException if unable to write the output
+     */
+    public void endTestSuite(JUnitTest suite) throws BuildException {
+        StringBuffer sb = new StringBuffer("Tests run: ");
+        sb.append(suite.runCount());
+        sb.append(", Failures: ");
+        sb.append(suite.failureCount());
+        sb.append(", Errors: ");
+        sb.append(suite.errorCount());
+        sb.append(", Time elapsed: ");
+        sb.append(nf.format(suite.getRunTime() / ONE_SECOND));
+        sb.append(" sec");
+        sb.append(StringUtils.LINE_SEP);
+
+        // append the err and output streams to the log
+        if (systemOutput != null && systemOutput.length() > 0) {
+            sb.append("------------- Standard Output ---------------")
+                .append(StringUtils.LINE_SEP)
+                .append(systemOutput)
+                .append("------------- ---------------- ---------------")
+                .append(StringUtils.LINE_SEP);
+        }
+
+        if (systemError != null && systemError.length() > 0) {
+            sb.append("------------- Standard Error -----------------")
+                .append(StringUtils.LINE_SEP)
+                .append(systemError)
+                .append("------------- ---------------- ---------------")
+                .append(StringUtils.LINE_SEP);
+        }
+
+        sb.append(StringUtils.LINE_SEP);
+
+        if (out != null) {
+            try {
+                out.write(sb.toString().getBytes());
+                wri.close();
+                out.write(inner.toString().getBytes());
+                out.flush();
+            } catch (IOException ioex) {
+                throw new BuildException("Unable to write output", ioex);
+            } finally {
+                if (out != System.out && out != System.err) {
+                    FileUtils.close(out);
+                }
+            }
+        }
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A new Test is started.
+     * @param t the test.
+     */
+    public void startTest(Test t) {
+        testStarts.put(t, new Long(System.currentTimeMillis()));
+        failed.put(t, Boolean.FALSE);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test is finished.
+     * @param test the test.
+     */
+    public void endTest(Test test) {
+        if (Boolean.TRUE.equals(failed.get(test))) {
+            return;
+        }
+        synchronized (wri) {
+            wri.print("Testcase: "
+                      + JUnitVersionHelper.getTestCaseName(test));
+            Long l = (Long) testStarts.get(test);
+            double seconds = 0;
+            // can be null if an error occurred in setUp
+            if (l != null) {
+                seconds =
+                    (System.currentTimeMillis() - l.longValue()) / ONE_SECOND;
+            }
+
+            wri.println(" took " + nf.format(seconds) + " sec");
+        }
+    }
+
+    /**
+     * Interface TestListener for JUnit &lt;= 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t the exception.
+     */
+    public void addFailure(Test test, Throwable t) {
+        formatError("\tFAILED", test, t);
+    }
+
+    /**
+     * Interface TestListener for JUnit &gt; 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t  the assertion that failed.
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        addFailure(test, (Throwable) t);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>An error occurred while running the test.
+     * @param test the test.
+     * @param t    the exception.
+     */
+    public void addError(Test test, Throwable t) {
+        formatError("\tCaused an ERROR", test, t);
+    }
+
+    private void formatError(String type, Test test, Throwable t) {
+        synchronized (wri) {
+            if (test != null) {
+                endTest(test);
+                failed.put(test, Boolean.TRUE);
+            }
+
+            wri.println(type);
+            wri.println(t.getMessage());
+            String strace = JUnitTestRunner.getFilteredTrace(t);
+            wri.print(strace);
+            wri.println("");
+        }
+    }
+
+} // PlainJUnitResultFormatter
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java
new file mode 100644
index 0000000..6ee92c5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/SummaryJUnitResultFormatter.java
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Prints short summary output of the test to Ant's logging system.
+ *
+ */
+
+public class SummaryJUnitResultFormatter
+    implements JUnitResultFormatter, JUnitTaskMirror.SummaryJUnitResultFormatterMirror {
+
+    private static final double ONE_SECOND = 1000.0;
+
+    /**
+     * Formatter for timings.
+     */
+    private NumberFormat nf = NumberFormat.getInstance();
+    /**
+     * OutputStream to write to.
+     */
+    private OutputStream out;
+
+    private boolean withOutAndErr = false;
+    private String systemOutput = null;
+    private String systemError = null;
+
+    /**
+     * Empty
+     */
+    public SummaryJUnitResultFormatter() {
+    }
+    /**
+     * The testsuite started.
+     * @param suite the testsuite.
+     */
+    public void startTestSuite(JUnitTest suite) {
+        String newLine = System.getProperty("line.separator");
+        StringBuffer sb = new StringBuffer("Running ");
+        sb.append(suite.getName());
+        sb.append(newLine);
+
+        try {
+            out.write(sb.toString().getBytes());
+            out.flush();
+        } catch (IOException ioex) {
+            throw new BuildException("Unable to write summary output", ioex);
+        }
+    }
+    /**
+     * Empty
+     * @param t not used.
+     */
+    public void startTest(Test t) {
+    }
+    /**
+     * Empty
+     * @param test not used.
+     */
+    public void endTest(Test test) {
+    }
+    /**
+     * Empty
+     * @param test not used.
+     * @param t not used.
+     */
+    public void addFailure(Test test, Throwable t) {
+    }
+    /**
+     * Interface TestListener for JUnit &gt; 3.4.
+     *
+     * <p>A Test failed.
+     * @param test not used.
+     * @param t not used.
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        addFailure(test, (Throwable) t);
+    }
+    /**
+     * Empty
+     * @param test not used.
+     * @param t not used.
+     */
+    public void addError(Test test, Throwable t) {
+    }
+
+    /** {@inheritDoc}. */
+    public void setOutput(OutputStream out) {
+        this.out = out;
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemOutput(String out) {
+        systemOutput = out;
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemError(String err) {
+        systemError = err;
+    }
+
+    /**
+     * Should the output to System.out and System.err be written to
+     * the summary.
+     * @param value if true write System.out and System.err to the summary.
+     */
+    public void setWithOutAndErr(boolean value) {
+        withOutAndErr = value;
+    }
+
+    /**
+     * The whole testsuite ended.
+     * @param suite the testsuite.
+     * @throws BuildException if there is an error.
+     */
+    public void endTestSuite(JUnitTest suite) throws BuildException {
+        String newLine = System.getProperty("line.separator");
+        StringBuffer sb = new StringBuffer("Tests run: ");
+        sb.append(suite.runCount());
+        sb.append(", Failures: ");
+        sb.append(suite.failureCount());
+        sb.append(", Errors: ");
+        sb.append(suite.errorCount());
+        sb.append(", Time elapsed: ");
+        sb.append(nf.format(suite.getRunTime() / ONE_SECOND));
+        sb.append(" sec");
+        sb.append(newLine);
+
+        if (withOutAndErr) {
+            if (systemOutput != null && systemOutput.length() > 0) {
+                sb.append("Output:").append(newLine).append(systemOutput)
+                    .append(newLine);
+            }
+
+            if (systemError != null && systemError.length() > 0) {
+                sb.append("Error: ").append(newLine).append(systemError)
+                    .append(newLine);
+            }
+        }
+
+        try {
+            out.write(sb.toString().getBytes());
+            out.flush();
+        } catch (IOException ioex) {
+            throw new BuildException("Unable to write summary output", ioex);
+        } finally {
+            if (out != System.out && out != System.err) {
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java
new file mode 100644
index 0000000..8f56aa0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLConstants.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+/**
+ * <p> Interface groups XML constants.
+ * Interface that groups all constants used throughout the <tt>XML</tt>
+ * documents that are generated by the <tt>XMLJUnitResultFormatter</tt>.
+ * <p>
+ * As of now the DTD is:
+ * <code><pre>
+ * &lt;!ELEMENT testsuites (testsuite*)&gt;
+ *
+ * &lt;!ELEMENT testsuite (properties, testcase*,
+ *                    failure?, error?,
+ *                     system-out?, system-err?)&gt;
+ * &lt;!ATTLIST testsuite name      CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite tests     CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite failures  CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite errors    CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite time      CDATA #REQUIRED&gt;
+ * &lt;!ATTLIST testsuite package   CDATA #IMPLIED&gt;
+ * &lt;!ATTLIST testsuite id        CDATA #IMPLIED&gt;
+ *
+ *
+ * &lt;!ELEMENT properties (property*)&gt;
+ *
+ * &lt;!ELEMENT property EMPTY&gt;
+ *   &lt;!ATTLIST property name  CDATA #REQUIRED&gt;
+ *   &lt;!ATTLIST property value CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT testcase (failure?, error?)&gt;
+ *   &lt;!ATTLIST testcase name       CDATA #REQUIRED&gt;
+ *   &lt;!ATTLIST testcase classname  CDATA #IMPLIED&gt;
+ *   &lt;!ATTLIST testcase time       CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT failure (#PCDATA)&gt;
+ *  &lt;!ATTLIST failure message CDATA #IMPLIED&gt;
+ *  &lt;!ATTLIST failure type    CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT error (#PCDATA)&gt;
+ *   &lt;!ATTLIST error message CDATA #IMPLIED&gt;
+ *   &lt;!ATTLIST error type    CDATA #REQUIRED&gt;
+ *
+ * &lt;!ELEMENT system-err (#PCDATA)&gt;
+ *
+ * &lt;!ELEMENT system-out (#PCDATA)&gt;
+ *
+ * </pre></code>
+ * @see XMLJUnitResultFormatter
+ * @see XMLResultAggregator
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF (bc)
+public interface XMLConstants {
+    /** the testsuites element for the aggregate document */
+    String TESTSUITES = "testsuites";
+
+    /** the testsuite element */
+    String TESTSUITE = "testsuite";
+
+    /** the testcase element */
+    String TESTCASE = "testcase";
+
+    /** the error element */
+    String ERROR = "error";
+
+    /** the failure element */
+    String FAILURE = "failure";
+
+    /** the system-err element */
+    String SYSTEM_ERR = "system-err";
+
+    /** the system-out element */
+    String SYSTEM_OUT = "system-out";
+
+    /** package attribute for the aggregate document */
+    String ATTR_PACKAGE = "package";
+
+    /** name attribute for property, testcase and testsuite elements */
+    String ATTR_NAME = "name";
+
+    /** time attribute for testcase and testsuite elements */
+    String ATTR_TIME = "time";
+
+    /** errors attribute for testsuite elements */
+    String ATTR_ERRORS = "errors";
+
+    /** failures attribute for testsuite elements */
+    String ATTR_FAILURES = "failures";
+
+    /** tests attribute for testsuite elements */
+    String ATTR_TESTS = "tests";
+
+    /** type attribute for failure and error elements */
+    String ATTR_TYPE = "type";
+
+    /** message attribute for failure elements */
+    String ATTR_MESSAGE = "message";
+
+    /** the properties element */
+    String PROPERTIES = "properties";
+
+    /** the property element */
+    String PROPERTY = "property";
+
+    /** value attribute for property elements */
+    String ATTR_VALUE = "value";
+
+    /** classname attribute for testcase elements */
+    String ATTR_CLASSNAME = "classname";
+
+    /** id attribute */
+    String ATTR_ID = "id";
+
+    /**
+     * timestamp of test cases
+     */
+    String TIMESTAMP = "timestamp";
+
+    /**
+     * name of host running the tests
+     */
+    String HOSTNAME = "hostname";
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java
new file mode 100644
index 0000000..35621ce
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLJUnitResultFormatter.java
@@ -0,0 +1,295 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Date;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.DateUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+
+/**
+ * Prints XML output of the test to a specified Writer.
+ *
+ * @see FormatterElement
+ */
+
+public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants {
+
+    private static final double ONE_SECOND = 1000.0;
+
+    /** constant for unnnamed testsuites/cases */
+    private static final String UNKNOWN = "unknown";
+
+    private static DocumentBuilder getDocumentBuilder() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        } catch (Exception exc) {
+            throw new ExceptionInInitializerError(exc);
+        }
+    }
+
+    /**
+     * The XML document.
+     */
+    private Document doc;
+    /**
+     * The wrapper for the whole testsuite.
+     */
+    private Element rootElement;
+    /**
+     * Element for the current test.
+     */
+    private Hashtable testElements = new Hashtable();
+    /**
+     * tests that failed.
+     */
+    private Hashtable failedTests = new Hashtable();
+    /**
+     * Timing helper.
+     */
+    private Hashtable testStarts = new Hashtable();
+    /**
+     * Where to write the log to.
+     */
+    private OutputStream out;
+
+    /** No arg constructor. */
+    public XMLJUnitResultFormatter() {
+    }
+
+    /** {@inheritDoc}. */
+    public void setOutput(OutputStream out) {
+        this.out = out;
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemOutput(String out) {
+        formatOutput(SYSTEM_OUT, out);
+    }
+
+    /** {@inheritDoc}. */
+    public void setSystemError(String out) {
+        formatOutput(SYSTEM_ERR, out);
+    }
+
+    /**
+     * The whole testsuite started.
+     * @param suite the testsuite.
+     */
+    public void startTestSuite(JUnitTest suite) {
+        doc = getDocumentBuilder().newDocument();
+        rootElement = doc.createElement(TESTSUITE);
+        String n = suite.getName();
+        rootElement.setAttribute(ATTR_NAME, n == null ? UNKNOWN : n);
+
+        //add the timestamp
+        final String timestamp = DateUtils.format(new Date(),
+                DateUtils.ISO8601_DATETIME_PATTERN);
+        rootElement.setAttribute(TIMESTAMP, timestamp);
+        //and the hostname.
+        rootElement.setAttribute(HOSTNAME, getHostname());
+
+        // Output properties
+        Element propsElement = doc.createElement(PROPERTIES);
+        rootElement.appendChild(propsElement);
+        Properties props = suite.getProperties();
+        if (props != null) {
+            Enumeration e = props.propertyNames();
+            while (e.hasMoreElements()) {
+                String name = (String) e.nextElement();
+                Element propElement = doc.createElement(PROPERTY);
+                propElement.setAttribute(ATTR_NAME, name);
+                propElement.setAttribute(ATTR_VALUE, props.getProperty(name));
+                propsElement.appendChild(propElement);
+            }
+        }
+    }
+
+    /**
+     * get the local hostname
+     * @return the name of the local host, or "localhost" if we cannot work it out
+     */
+    private String getHostname()  {
+        try {
+            return InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+            return "localhost";
+        }
+    }
+
+    /**
+     * The whole testsuite ended.
+     * @param suite the testsuite.
+     * @throws BuildException on error.
+     */
+    public void endTestSuite(JUnitTest suite) throws BuildException {
+        rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount());
+        rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount());
+        rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount());
+        rootElement.setAttribute(
+            ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND));
+        if (out != null) {
+            Writer wri = null;
+            try {
+                wri = new BufferedWriter(new OutputStreamWriter(out, "UTF8"));
+                wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+                (new DOMElementWriter()).write(rootElement, wri, 0, "  ");
+                wri.flush();
+            } catch (IOException exc) {
+                throw new BuildException("Unable to write log file", exc);
+            } finally {
+                if (out != System.out && out != System.err) {
+                    FileUtils.close(wri);
+                }
+            }
+        }
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A new Test is started.
+     * @param t the test.
+     */
+    public void startTest(Test t) {
+        testStarts.put(t, new Long(System.currentTimeMillis()));
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>A Test is finished.
+     * @param test the test.
+     */
+    public void endTest(Test test) {
+        // Fix for bug #5637 - if a junit.extensions.TestSetup is
+        // used and throws an exception during setUp then startTest
+        // would never have been called
+        if (!testStarts.containsKey(test)) {
+            startTest(test);
+        }
+
+        Element currentTest = null;
+        if (!failedTests.containsKey(test)) {
+            currentTest = doc.createElement(TESTCASE);
+            String n = JUnitVersionHelper.getTestCaseName(test);
+            currentTest.setAttribute(ATTR_NAME,
+                                     n == null ? UNKNOWN : n);
+            // a TestSuite can contain Tests from multiple classes,
+            // even tests with the same name - disambiguate them.
+            currentTest.setAttribute(ATTR_CLASSNAME,
+                    JUnitVersionHelper.getTestCaseClassName(test));
+            rootElement.appendChild(currentTest);
+            testElements.put(test, currentTest);
+        } else {
+            currentTest = (Element) testElements.get(test);
+        }
+
+        Long l = (Long) testStarts.get(test);
+        currentTest.setAttribute(ATTR_TIME,
+            "" + ((System.currentTimeMillis()
+                   - l.longValue()) / ONE_SECOND));
+    }
+
+    /**
+     * Interface TestListener for JUnit &lt;= 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t the exception.
+     */
+    public void addFailure(Test test, Throwable t) {
+        formatError(FAILURE, test, t);
+    }
+
+    /**
+     * Interface TestListener for JUnit &gt; 3.4.
+     *
+     * <p>A Test failed.
+     * @param test the test.
+     * @param t the assertion.
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        addFailure(test, (Throwable) t);
+    }
+
+    /**
+     * Interface TestListener.
+     *
+     * <p>An error occurred while running the test.
+     * @param test the test.
+     * @param t the error.
+     */
+    public void addError(Test test, Throwable t) {
+        formatError(ERROR, test, t);
+    }
+
+    private void formatError(String type, Test test, Throwable t) {
+        if (test != null) {
+            endTest(test);
+            failedTests.put(test, test);
+        }
+
+        Element nested = doc.createElement(type);
+        Element currentTest = null;
+        if (test != null) {
+            currentTest = (Element) testElements.get(test);
+        } else {
+            currentTest = rootElement;
+        }
+
+        currentTest.appendChild(nested);
+
+        String message = t.getMessage();
+        if (message != null && message.length() > 0) {
+            nested.setAttribute(ATTR_MESSAGE, t.getMessage());
+        }
+        nested.setAttribute(ATTR_TYPE, t.getClass().getName());
+
+        String strace = JUnitTestRunner.getFilteredTrace(t);
+        Text trace = doc.createTextNode(strace);
+        nested.appendChild(trace);
+    }
+
+    private void formatOutput(String type, String output) {
+        Element nested = doc.createElement(type);
+        rootElement.appendChild(nested);
+        nested.appendChild(doc.createCDATASection(output));
+    }
+
+} // XMLJUnitResultFormatter
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java
new file mode 100644
index 0000000..55674cc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.DOMElementWriter;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Aggregates all &lt;junit&gt; XML formatter testsuite data under
+ * a specific directory and transforms the results via XSLT.
+ * It is not particulary clean but
+ * should be helpful while I am thinking about another technique.
+ *
+ * <p> The main problem is due to the fact that a JVM can be forked for a testcase
+ * thus making it impossible to aggregate all testcases since the listener is
+ * (obviously) in the forked JVM. A solution could be to write a
+ * TestListener that will receive events from the TestRunner via sockets. This
+ * is IMHO the simplest way to do it to avoid this file hacking thing.
+ *
+ * @ant.task name="junitreport" category="testing"
+ */
+public class XMLResultAggregator extends Task implements XMLConstants {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** the list of all filesets, that should contains the xml to aggregate */
+    protected Vector filesets = new Vector();
+
+    /** the name of the result file */
+    protected String toFile;
+
+    /** the directory to write the file to */
+    protected File toDir;
+
+    protected Vector transformers = new Vector();
+
+    /** The default directory: <tt>&#046;</tt>. It is resolved from the project directory */
+    public static final String DEFAULT_DIR = ".";
+
+    /** the default file name: <tt>TESTS-TestSuites.xml</tt> */
+    public static final String DEFAULT_FILENAME = "TESTS-TestSuites.xml";
+
+    /** the current generated id */
+    protected int generatedId = 0;
+
+    /**
+     * text checked for in tests, {@value}
+     */
+    static final String WARNING_IS_POSSIBLY_CORRUPTED
+        = " is not a valid XML document. It is possibly corrupted.";
+    /**
+     * text checked for in tests, {@value}
+     */
+    static final String WARNING_INVALID_ROOT_ELEMENT
+        = " is not a valid testsuite XML document";
+    /**
+     * text checked for in tests, {@value}
+     */
+    static final String WARNING_EMPTY_FILE
+        = " is empty.\nThis can be caused by the test JVM exiting unexpectedly";
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Generate a report based on the document created by the merge.
+     * @return the report
+     */
+    public AggregateTransformer createReport() {
+        AggregateTransformer transformer = new AggregateTransformer(this);
+        transformers.addElement(transformer);
+        return transformer;
+    }
+
+    /**
+     * Set the name of the aggregegated results file. It must be relative
+     * from the <tt>todir</tt> attribute. If not set it will use {@link #DEFAULT_FILENAME}
+     * @param  value   the name of the file.
+     * @see #setTodir(File)
+     */
+    public void setTofile(String value) {
+        toFile = value;
+    }
+
+    /**
+     * Set the destination directory where the results should be written. If not
+     * set if will use {@link #DEFAULT_DIR}. When given a relative directory
+     * it will resolve it from the project directory.
+     * @param value    the directory where to write the results, absolute or
+     * relative.
+     */
+    public void setTodir(File value) {
+        toDir = value;
+    }
+
+    /**
+     * Add a new fileset containing the XML results to aggregate
+     * @param    fs      the new fileset of xml results.
+     */
+    public void addFileSet(FileSet fs) {
+        filesets.addElement(fs);
+    }
+
+    /**
+     * Aggregate all testsuites into a single document and write it to the
+     * specified directory and file.
+     * @throws  BuildException  thrown if there is a serious error while writing
+     *          the document.
+     */
+    public void execute() throws BuildException {
+        Element rootElement = createDocument();
+        File destFile = getDestinationFile();
+        // write the document
+        try {
+            writeDOMTree(rootElement.getOwnerDocument(), destFile);
+        } catch (IOException e) {
+            throw new BuildException("Unable to write test aggregate to '" + destFile + "'", e);
+        }
+        // apply transformation
+        Enumeration e = transformers.elements();
+        while (e.hasMoreElements()) {
+            AggregateTransformer transformer =
+                (AggregateTransformer) e.nextElement();
+            transformer.setXmlDocument(rootElement.getOwnerDocument());
+            transformer.transform();
+        }
+    }
+
+    /**
+     * Get the full destination file where to write the result. It is made of
+     * the <tt>todir</tt> and <tt>tofile</tt> attributes.
+     * @return the destination file where should be written the result file.
+     */
+    public File getDestinationFile() {
+        if (toFile == null) {
+            toFile = DEFAULT_FILENAME;
+        }
+        if (toDir == null) {
+            toDir = getProject().resolveFile(DEFAULT_DIR);
+        }
+        return new File(toDir, toFile);
+    }
+
+    /**
+     * Get all <code>.xml</code> files in the fileset.
+     *
+     * @return all files in the fileset that end with a '.xml'.
+     */
+    protected File[] getFiles() {
+        Vector v = new Vector();
+        final int size = filesets.size();
+        for (int i = 0; i < size; i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            ds.scan();
+            String[] f = ds.getIncludedFiles();
+            for (int j = 0; j < f.length; j++) {
+                String pathname = f[j];
+                if (pathname.endsWith(".xml")) {
+                    File file = new File(ds.getBasedir(), pathname);
+                    file = getProject().resolveFile(file.getPath());
+                    v.addElement(file);
+                }
+            }
+        }
+
+        File[] files = new File[v.size()];
+        v.copyInto(files);
+        return files;
+    }
+
+    //----- from now, the methods are all related to DOM tree manipulation
+
+    /**
+     * Write the DOM tree to a file.
+     * @param doc the XML document to dump to disk.
+     * @param file the filename to write the document to. Should obviouslly be a .xml file.
+     * @throws IOException thrown if there is an error while writing the content.
+     */
+    protected void writeDOMTree(Document doc, File file) throws IOException {
+        OutputStream out = null;
+        PrintWriter wri = null;
+        try {
+            out = new BufferedOutputStream(new FileOutputStream(file));
+            wri = new PrintWriter(new OutputStreamWriter(out, "UTF8"));
+            wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+            (new DOMElementWriter()).write(doc.getDocumentElement(), wri, 0, "  ");
+            wri.flush();
+            // writers do not throw exceptions, so check for them.
+            if (wri.checkError()) {
+                throw new IOException("Error while writing DOM content");
+            }
+        } finally {
+            FileUtils.close(wri);
+            FileUtils.close(out);
+        }
+    }
+
+    /**
+     * <p> Create a DOM tree.
+     * Has 'testsuites' as firstchild and aggregates all
+     * testsuite results that exists in the base directory.
+     * @return  the root element of DOM tree that aggregates all testsuites.
+     */
+    protected Element createDocument() {
+        // create the dom tree
+        DocumentBuilder builder = getDocumentBuilder();
+        Document doc = builder.newDocument();
+        Element rootElement = doc.createElement(TESTSUITES);
+        doc.appendChild(rootElement);
+
+        generatedId = 0;
+
+        // get all files and add them to the document
+        File[] files = getFiles();
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            try {
+                log("Parsing file: '" + file + "'", Project.MSG_VERBOSE);
+                if (file.length() > 0) {
+                    Document testsuiteDoc
+                            = builder.parse(
+                                FileUtils.getFileUtils().toURI(files[i].getAbsolutePath()));
+                    Element elem = testsuiteDoc.getDocumentElement();
+                    // make sure that this is REALLY a testsuite.
+                    if (TESTSUITE.equals(elem.getNodeName())) {
+                        addTestSuite(rootElement, elem);
+                        generatedId++;
+                    } else {
+                        //wrong root element name
+                        // issue a warning.
+                        log("the file " + file
+                                + WARNING_INVALID_ROOT_ELEMENT,
+                                Project.MSG_WARN);
+                    }
+                } else {
+                    log("the file " + file
+                            + WARNING_EMPTY_FILE,
+                            Project.MSG_WARN);
+                }
+            } catch (SAXException e) {
+                // a testcase might have failed and write a zero-length document,
+                // It has already failed, but hey.... mm. just put a warning
+                log("The file " + file + WARNING_IS_POSSIBLY_CORRUPTED, Project.MSG_WARN);
+                log(StringUtils.getStackTrace(e), Project.MSG_DEBUG);
+            } catch (IOException e) {
+                log("Error while accessing file " + file + ": "
+                    + e.getMessage(), Project.MSG_ERR);
+            }
+        }
+        return rootElement;
+    }
+
+    /**
+     * <p> Add a new testsuite node to the document.
+     * The main difference is that it
+     * split the previous fully qualified name into a package and a name.
+     * <p> For example: <tt>org.apache.Whatever</tt> will be split into
+     * <tt>org.apache</tt> and <tt>Whatever</tt>.
+     * @param root the root element to which the <tt>testsuite</tt> node should
+     *        be appended.
+     * @param testsuite the element to append to the given root. It will slightly
+     *        modify the original node to change the name attribute and add
+     *        a package one.
+     */
+    protected void addTestSuite(Element root, Element testsuite) {
+        String fullclassname = testsuite.getAttribute(ATTR_NAME);
+        int pos = fullclassname.lastIndexOf('.');
+
+        // a missing . might imply no package at all. Don't get fooled.
+        String pkgName = (pos == -1) ? "" : fullclassname.substring(0, pos);
+        String classname = (pos == -1) ? fullclassname : fullclassname.substring(pos + 1);
+        Element copy = (Element) DOMUtil.importNode(root, testsuite);
+
+        // modify the name attribute and set the package
+        copy.setAttribute(ATTR_NAME, classname);
+        copy.setAttribute(ATTR_PACKAGE, pkgName);
+        copy.setAttribute(ATTR_ID, Integer.toString(generatedId));
+    }
+
+    /**
+     * Create a new document builder. Will issue an <tt>ExceptionInitializerError</tt>
+     * if something is going wrong. It is fatal anyway.
+     * @todo factorize this somewhere else. It is duplicated code.
+     * @return a new document builder to create a DOM
+     */
+    private static DocumentBuilder getDocumentBuilder() {
+        try {
+            return DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        } catch (Exception exc) {
+            throw new ExceptionInInitializerError(exc);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Xalan2Executor.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Xalan2Executor.java
new file mode 100644
index 0000000..de8a0e0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/Xalan2Executor.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.OutputStream;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This class is not used by the framework any more.
+ * We plan to remove it in Ant 1.8
+ * @deprecated since Ant 1.7
+ *
+ *
+ * @ant.task ignore="true"
+ */
+public class Xalan2Executor extends XalanExecutor {
+
+    private static final String APAC = "org.apache.xalan.";
+    private static final String SPAC = "com.sun.org.apache.xalan.";
+
+    private TransformerFactory tfactory = TransformerFactory.newInstance();
+
+    /** {@inheritDoc}. */
+    protected String getImplementation() throws BuildException {
+        return tfactory.getClass().getName();
+    }
+
+    /** {@inheritDoc}. */
+    protected String getProcVersion(String classNameImpl)
+        throws BuildException {
+        try {
+            // xalan 2
+            if (classNameImpl.equals(APAC + "processor.TransformerFactoryImpl")
+                ||
+                classNameImpl.equals(APAC + "xslt.XSLTProcessorFactory")) {
+                return getXalanVersion(APAC + "processor.XSLProcessorVersion");
+            }
+            // xalan xsltc
+            if (classNameImpl.equals(APAC
+                                     + "xsltc.trax.TransformerFactoryImpl")) {
+                return getXSLTCVersion(APAC + "xsltc.ProcessorVersion");
+            }
+            // jdk 1.5 xsltc
+            if (classNameImpl
+                .equals(SPAC + "internal.xsltc.trax.TransformerFactoryImpl")) {
+                return getXSLTCVersion(SPAC
+                                       + "internal.xsltc.ProcessorVersion");
+            }
+            throw new BuildException("Could not find a valid processor version"
+                                     + " implementation from "
+                                     + classNameImpl);
+        } catch (ClassNotFoundException e) {
+            throw new BuildException("Could not find processor version "
+                                     + "implementation", e);
+        }
+    }
+
+    /** {@inheritDoc}. */
+    void execute() throws Exception {
+        String systemId = caller.getStylesheetSystemId();
+        Source xslSrc = new StreamSource(systemId);
+        Transformer tformer = tfactory.newTransformer(xslSrc);
+        Source xmlSrc = new DOMSource(caller.document);
+        OutputStream os = getOutputStream();
+        try {
+            tformer.setParameter("output.dir", caller.toDir.getAbsolutePath());
+            Result result = new StreamResult(os);
+            tformer.transform(xmlSrc, result);
+        } finally {
+            os.close();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java
new file mode 100644
index 0000000..f4afe05
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/junit/XalanExecutor.java
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * This class is not used by the framework any more.
+ * We plan to remove it in Ant 1.8
+ * @deprecated since Ant 1.7
+ *
+ */
+abstract class XalanExecutor {
+    private static final String PACKAGE =
+        "org.apache.tools.ant.taskdefs.optional.junit.";
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** the transformer caller */
+    protected AggregateTransformer caller;
+    // CheckStyle:VisibilityModifier ON
+
+    /** set the caller for this object. */
+    private void setCaller(AggregateTransformer caller) {
+        this.caller = caller;
+    }
+
+    /** get the appropriate stream based on the format (frames/noframes) */
+    protected final OutputStream getOutputStream() throws IOException {
+        if (AggregateTransformer.FRAMES.equals(caller.format)) {
+            // dummy output for the framed report
+            // it's all done by extension...
+            return new ByteArrayOutputStream();
+        } else {
+            return new BufferedOutputStream(
+                new FileOutputStream(new File(caller.toDir, "junit-noframes.html")));
+        }
+    }
+
+    /** override to perform transformation */
+    abstract void execute() throws Exception;
+
+    /**
+     * Create a valid Xalan executor. It checks if Xalan2 is
+     * present. If none is available, it fails.
+     * @param caller object containing the transformation information.
+     * @throws BuildException thrown if it could not find a valid xalan
+     * executor.
+     */
+    static XalanExecutor newInstance(AggregateTransformer caller)
+        throws BuildException {
+        XalanExecutor executor = null;
+        try {
+            Class clazz = Class.forName(PACKAGE + "Xalan2Executor");
+            executor = (XalanExecutor) clazz.newInstance();
+        } catch (Exception xsltcApacheMissing) {
+            caller.task.log(xsltcApacheMissing.toString());
+                throw new BuildException("Could not find xstlc nor xalan2 "
+                                         + "in the classpath. Check "
+                                         + "http://xml.apache.org/xalan-j");
+        }
+        String classNameImpl = executor.getImplementation();
+        String version = executor.getProcVersion(classNameImpl);
+        caller.task.log("Using " + version, Project.MSG_VERBOSE);
+        executor.setCaller(caller);
+        return executor;
+    }
+
+    /**
+     * This methods should return the classname implementation of the
+     * underlying xslt processor
+     * @return the classname of the implementation, for example:
+     * org.apache.xalan.processor.TransformerFactoryImpl
+     * @see #getProcVersion(String)
+     */
+    protected abstract String getImplementation();
+
+    /**
+     * Try to discover the xslt processor version based on the
+     * className. There is nothing carved in stone and it can change
+     * anytime, so this is just for the sake of giving additional
+     * information if we can find it.
+     * @param classNameImpl the classname of the underlying xslt processor
+     * @return a string representing the implementation version.
+     * @throws BuildException
+     */
+    protected abstract String getProcVersion(String classNameImpl)
+        throws BuildException;
+
+    /** a bit simplistic but xsltc data are conveniently private non final */
+    protected final String getXSLTCVersion(String procVersionClassName)
+        throws ClassNotFoundException {
+        // there's a convenient xsltc class version but data are
+        // private so use package information
+        Class procVersion = Class.forName(procVersionClassName);
+        Package pkg = procVersion.getPackage();
+        return pkg.getName() + " " + pkg.getImplementationTitle()
+            + " " + pkg.getImplementationVersion();
+    }
+
+    /** pretty useful data (Xalan version information) to display. */
+    protected final String getXalanVersion(String procVersionClassName)
+        throws ClassNotFoundException {
+        Class procVersion = Class.forName(procVersionClassName);
+        String pkg = procVersion.getPackage().getName();
+        try {
+            Field f = procVersion.getField("S_VERSION");
+            return pkg + " " + f.get(null).toString();
+        } catch (Exception e) {
+            return pkg + " ?.?";
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java
new file mode 100644
index 0000000..ed9f8f3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/DefaultNative2Ascii.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * encapsulates the handling common to diffent Native2Asciiadapter
+ * implementations.
+ *
+ * @since Ant 1.6.3
+ */
+public abstract class DefaultNative2Ascii implements Native2AsciiAdapter {
+
+    /** No-arg constructor. */
+    public DefaultNative2Ascii() {
+    }
+
+    /**
+     * Splits the task into setting up the command line switches
+     * @param args the native 2 ascii arguments.
+     * @param srcFile the source file.
+     * @param destFile the destination file.
+     * @return run if the conversion was successful.
+     * @throws BuildException if there is a problem.
+     * (delegated to {@link #setup setup}), adding the file names
+     * (delegated to {@link #addFiles addFiles}) and running the tool
+     * (delegated to {@link #run run}).
+     */
+    public final boolean convert(Native2Ascii args, File srcFile,
+                                 File destFile) throws BuildException {
+        Commandline cmd = new Commandline();
+        setup(cmd, args);
+        addFiles(cmd, args, srcFile, destFile);
+        return run(cmd, args);
+    }
+
+    /**
+     * Sets up the initial command line.
+     *
+     * <p>only the -encoding argument and nested arg elements get
+     * handled here.</p>
+     *
+     * @param cmd Command line to add to
+     * @param args provides the user-setting and access to Ant's
+     * logging system.
+     * @throws BuildException if there was a problem.
+     */
+    protected void setup(Commandline cmd, Native2Ascii args)
+        throws BuildException {
+        if (args.getEncoding() != null) {
+            cmd.createArgument().setValue("-encoding");
+            cmd.createArgument().setValue(args.getEncoding());
+        }
+        cmd.addArguments(args.getCurrentArgs());
+    }
+
+    /**
+     * Adds source and dest files to the command line.
+     *
+     * <p>This implementation adds them without any leading
+     * qualifiers, source first.</p>
+     *
+     * @param cmd Command line to add to
+     * @param log provides access to Ant's logging system.
+     * @param src the source file
+     * @param dest the destination file
+     * @throws BuildException if there was a problem.
+     */
+    protected void addFiles(Commandline cmd, ProjectComponent log, File src,
+                            File dest) throws BuildException {
+        cmd.createArgument().setFile(src);
+        cmd.createArgument().setFile(dest);
+    }
+
+    /**
+     * Executes the command.
+     *
+     * @param cmd Command line to execute
+     * @param log provides access to Ant's logging system.
+     * @return whether execution was successful
+     * @throws BuildException if there was a problem.
+     */
+    protected abstract boolean run(Commandline cmd, ProjectComponent log)
+        throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java
new file mode 100644
index 0000000..cd4d36a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/KaffeNative2Ascii.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Adapter to kaffe.tools.native2ascii.Native2Ascii.
+ *
+ * @since Ant 1.6.3
+ */
+public final class KaffeNative2Ascii extends DefaultNative2Ascii {
+
+    // sorted by newest Kaffe version first
+    private static final String[] N2A_CLASSNAMES = new String[] {
+        "gnu.classpath.tools.native2ascii.Native2Ascii",
+        // pre Kaffe 1.1.5
+        "kaffe.tools.native2ascii.Native2Ascii",
+    };
+
+    /**
+     * Identifies this adapter.
+     */
+    public static final String IMPLEMENTATION_NAME = "kaffe";
+
+    /** {@inheritDoc} */
+    protected void setup(Commandline cmd, Native2Ascii args)
+        throws BuildException {
+        if (args.getReverse()) {
+            throw new BuildException("-reverse is not supported by Kaffe");
+        }
+        super.setup(cmd, args);
+    }
+
+    /** {@inheritDoc} */
+    protected boolean run(Commandline cmd, ProjectComponent log)
+        throws BuildException {
+        ExecuteJava ej = new ExecuteJava();
+        Class c = getN2aClass();
+        if (c == null) {
+            throw new BuildException("Couldn't load Kaffe's Native2Ascii"
+                                     + " class");
+        }
+
+        cmd.setExecutable(c.getName());
+        ej.setJavaCommand(cmd);
+        ej.execute(log.getProject());
+        // otherwise ExecuteJava has thrown an exception
+        return true;
+    }
+
+    /**
+     * tries to load Kaffe Native2Ascii and falls back to the older
+     * class name if necessary.
+     *
+     * @return null if neither class can get loaded.
+     */
+    private static Class getN2aClass() {
+        for (int i = 0; i < N2A_CLASSNAMES.length; i++) {
+            try {
+                return Class.forName(N2A_CLASSNAMES[i]);
+            } catch (ClassNotFoundException cnfe) {
+                // Ignore
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java
new file mode 100644
index 0000000..a4c8668
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapter.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+
+/**
+ * Interface for an adapter to a native2ascii implementation.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public interface Native2AsciiAdapter {
+    /**
+     * Convert the encoding of srcFile writing to destFile.
+     *
+     * @param args Task that holds command line arguments and allows
+     * the implementation to send messages to Ant's logging system
+     * @param srcFile the source to convert
+     * @param destFile where to send output to
+     * @return whether the conversion has been successful.
+     * @throws BuildException if there was a problem.
+     */
+    boolean convert(Native2Ascii args, File srcFile, File destFile)
+        throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java
new file mode 100644
index 0000000..abbaec6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/Native2AsciiAdapterFactory.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Creates the Native2AsciiAdapter based on the user choice and
+ * potentially the VM vendor.
+ *
+ * @since Ant 1.6.3
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class Native2AsciiAdapterFactory {
+
+    /**
+     * Determines the default choice of adapter based on the VM
+     * vendor.
+     *
+     * @return the default choice of adapter based on the VM
+     * vendor
+     */
+    public static String getDefault() {
+        if (JavaEnvUtils.isKaffe()) {
+            return KaffeNative2Ascii.IMPLEMENTATION_NAME;
+        }
+        return SunNative2Ascii.IMPLEMENTATION_NAME;
+    }
+
+    /**
+     * Creates the Native2AsciiAdapter based on the user choice and *
+     * potentially the VM vendor.
+     *
+     * @param choice the user choice (if any).
+     * @param log a ProjectComponent instance used to access Ant's
+     * logging system.
+     * @return The adapter to use.
+     * @throws BuildException if there was a problem.
+     */
+    public static Native2AsciiAdapter getAdapter(String choice,
+                                                 ProjectComponent log)
+        throws BuildException {
+        if ((JavaEnvUtils.isKaffe() && choice == null)
+            || KaffeNative2Ascii.IMPLEMENTATION_NAME.equals(choice)) {
+            return new KaffeNative2Ascii();
+        } else if (SunNative2Ascii.IMPLEMENTATION_NAME.equals(choice)) {
+            return new SunNative2Ascii();
+        } else if (choice != null) {
+            return resolveClassName(choice);
+        }
+
+        // This default has been good enough until Ant 1.6.3, so stick
+        // with it
+        return new SunNative2Ascii();
+    }
+
+    /**
+     * Tries to resolve the given classname into a native2ascii adapter.
+     * Throws a fit if it can't.
+     *
+     * @param className The fully qualified classname to be created.
+     * @throws BuildException This is the fit that is thrown if className
+     * isn't an instance of Native2AsciiAdapter.
+     */
+    private static Native2AsciiAdapter resolveClassName(String className)
+        throws BuildException {
+        return (Native2AsciiAdapter) ClasspathUtils.newInstance(className,
+            Native2AsciiAdapterFactory.class.getClassLoader(),
+            Native2AsciiAdapter.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java
new file mode 100644
index 0000000..101db7c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/SunNative2Ascii.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.native2ascii;
+
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.taskdefs.optional.Native2Ascii;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Adapter to sun.tools.native2ascii.Main.
+ *
+ * @since Ant 1.6.3
+ */
+public final class SunNative2Ascii extends DefaultNative2Ascii {
+
+    /**
+     * Identifies this adapter.
+     */
+    public static final String IMPLEMENTATION_NAME = "sun";
+
+    /** {@inheritDoc} */
+    protected void setup(Commandline cmd, Native2Ascii args)
+        throws BuildException {
+        if (args.getReverse()) {
+            cmd.createArgument().setValue("-reverse");
+        }
+        super.setup(cmd, args);
+    }
+
+    /** {@inheritDoc} */
+    protected boolean run(Commandline cmd, ProjectComponent log)
+        throws BuildException {
+        try {
+            Class n2aMain = Class.forName("sun.tools.native2ascii.Main");
+            Class[] param = new Class[] {String[].class};
+            Method convert = n2aMain.getMethod("convert", param);
+            if (convert == null) {
+                throw new BuildException("Could not find convert() method in "
+                                         + "sun.tools.native2ascii.Main");
+            }
+            Object o = n2aMain.newInstance();
+            return ((Boolean) convert.invoke(o,
+                                             new Object[] {cmd.getArguments()})
+                    ).booleanValue();
+        } catch (BuildException ex) {
+            //rethrow
+            throw ex;
+        } catch (Exception ex) {
+            //wrap
+           throw new BuildException("Error starting Sun's native2ascii: ", ex);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java
new file mode 100644
index 0000000..56693aa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTP.java
@@ -0,0 +1,2570 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPClientConfig;
+import org.apache.commons.net.ftp.FTPFile;
+import org.apache.commons.net.ftp.FTPReply;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Delete;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.RetryHandler;
+import org.apache.tools.ant.util.Retryable;
+
+/**
+ * Basic FTP client. Performs the following actions:
+ * <ul>
+ *   <li> <strong>send</strong> - send files to a remote server. This is the
+ *   default action.</li>
+ *   <li> <strong>get</strong> - retrieve files from a remote server.</li>
+ *   <li> <strong>del</strong> - delete files from a remote server.</li>
+ *   <li> <strong>list</strong> - create a file listing.</li>
+ *   <li> <strong>chmod</strong> - change unix file permissions.</li>
+ *   <li> <strong>rmdir</strong> - remove directories, if empty, from a
+ *   remote server.</li>
+ * </ul>
+ * <strong>Note:</strong> Some FTP servers - notably the Solaris server - seem
+ * to hold data ports open after a "retr" operation, allowing them to timeout
+ * instead of shutting them down cleanly. This happens in active or passive
+ * mode, and the ports will remain open even after ending the FTP session. FTP
+ * "send" operations seem to close ports immediately. This behavior may cause
+ * problems on some systems when downloading large sets of files.
+ *
+ * @since Ant 1.3
+ */
+public class FTP
+     extends Task {
+    protected static final int SEND_FILES = 0;
+    protected static final int GET_FILES = 1;
+    protected static final int DEL_FILES = 2;
+    protected static final int LIST_FILES = 3;
+    protected static final int MK_DIR = 4;
+    protected static final int CHMOD = 5;
+    protected static final int RM_DIR = 6;
+    protected static final int SITE_CMD = 7;
+    /** return code of ftp - not implemented in commons-net version 1.0 */
+    private static final int CODE_521 = 521;
+
+    /** adjust uptodate calculations where server timestamps are HH:mm and client's
+     * are HH:mm:ss */
+    private static final long GRANULARITY_MINUTE = 60000L;
+
+    /** Default port for FTP */
+    public static final int DEFAULT_FTP_PORT = 21;
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private String remotedir;
+    private String server;
+    private String userid;
+    private String password;
+    private String account;
+    private File listing;
+    private boolean binary = true;
+    private boolean passive = false;
+    private boolean verbose = false;
+    private boolean newerOnly = false;
+    private long timeDiffMillis = 0;
+    private long granularityMillis = 0L;
+    private boolean timeDiffAuto = false;
+    private int action = SEND_FILES;
+    private Vector filesets = new Vector();
+    private Vector dirCache = new Vector();
+    private int transferred = 0;
+    private String remoteFileSep = "/";
+    private int port = DEFAULT_FTP_PORT;
+    private boolean skipFailedTransfers = false;
+    private int skipped = 0;
+    private boolean ignoreNoncriticalErrors = false;
+    private boolean preserveLastModified = false;
+    private String chmod = null;
+    private String umask = null;
+    private FTPSystemType systemTypeKey = FTPSystemType.getDefault();
+    private String defaultDateFormatConfig = null;
+    private String recentDateFormatConfig = null;
+    private LanguageCode serverLanguageCodeConfig = LanguageCode.getDefault();
+    private String serverTimeZoneConfig = null;
+    private String shortMonthNamesConfig = null;
+    private Granularity timestampGranularity = Granularity.getDefault();
+    private boolean isConfigurationSet = false;
+    private int retriesAllowed = 0;
+    private String siteCommand = null;
+    private String initialSiteCommand = null;
+
+    protected static final String[] ACTION_STRS = {
+        "sending",
+        "getting",
+        "deleting",
+        "listing",
+        "making directory",
+        "chmod",
+        "removing",
+        "site"
+        };
+
+    protected static final String[] COMPLETED_ACTION_STRS = {
+        "sent",
+        "retrieved",
+        "deleted",
+        "listed",
+        "created directory",
+        "mode changed",
+        "removed",
+        "site command executed"
+        };
+
+    protected static final String[] ACTION_TARGET_STRS = {
+        "files",
+        "files",
+        "files",
+        "files",
+        "directory",
+        "files",
+        "directories",
+        "site command"
+        };
+
+
+    /**
+     * internal class allowing to read the contents of a remote file system
+     * using the FTP protocol
+     * used in particular for ftp get operations
+     * differences with DirectoryScanner
+     * "" (the root of the fileset) is never included in the included directories
+     * followSymlinks defaults to false
+     */
+    protected class FTPDirectoryScanner extends DirectoryScanner {
+        // CheckStyle:VisibilityModifier OFF - bc
+        protected FTPClient ftp = null;
+        // CheckStyle:VisibilityModifier ON
+
+        private String rootPath = null;
+
+        /**
+         * since ant 1.6
+         * this flag should be set to true on UNIX and can save scanning time
+         */
+        private boolean remoteSystemCaseSensitive = false;
+        private boolean remoteSensitivityChecked = false;
+
+        /**
+         * constructor
+         * @param ftp  ftpclient object
+         */
+        public FTPDirectoryScanner(FTPClient ftp) {
+            super();
+            this.ftp = ftp;
+            this.setFollowSymlinks(false);
+        }
+
+
+        /**
+         * scans the remote directory,
+         * storing internally the included files, directories, ...
+         */
+        public void scan() {
+            if (includes == null) {
+                // No includes supplied, so set it to 'matches all'
+                includes = new String[1];
+                includes[0] = "**";
+            }
+            if (excludes == null) {
+                excludes = new String[0];
+            }
+
+            filesIncluded = new Vector();
+            filesNotIncluded = new Vector();
+            filesExcluded = new Vector();
+            dirsIncluded = new Vector();
+            dirsNotIncluded = new Vector();
+            dirsExcluded = new Vector();
+
+            try {
+                String cwd = ftp.printWorkingDirectory();
+                // always start from the current ftp working dir
+                forceRemoteSensitivityCheck();
+
+                checkIncludePatterns();
+                clearCaches();
+                ftp.changeWorkingDirectory(cwd);
+            } catch (IOException e) {
+                throw new BuildException("Unable to scan FTP server: ", e);
+            }
+        }
+
+
+        /**
+         * this routine is actually checking all the include patterns in
+         * order to avoid scanning everything under base dir
+         * @since ant1.6
+         */
+        private void checkIncludePatterns() {
+
+            Hashtable newroots = new Hashtable();
+            // put in the newroots vector the include patterns without
+            // wildcard tokens
+            for (int icounter = 0; icounter < includes.length; icounter++) {
+                String newpattern =
+                    SelectorUtils.rtrimWildcardTokens(includes[icounter]);
+                newroots.put(newpattern, includes[icounter]);
+            }
+            if (remotedir == null) {
+                try {
+                    remotedir = ftp.printWorkingDirectory();
+                } catch (IOException e) {
+                    throw new BuildException("could not read current ftp directory",
+                        getLocation());
+                }
+            }
+            AntFTPFile baseFTPFile = new AntFTPRootFile(ftp, remotedir);
+            rootPath = baseFTPFile.getAbsolutePath();
+            // construct it
+            if (newroots.containsKey("")) {
+                // we are going to scan everything anyway
+                scandir(rootPath, "", true);
+            } else {
+                // only scan directories that can include matched files or
+                // directories
+                Enumeration enum2 = newroots.keys();
+
+                while (enum2.hasMoreElements()) {
+                    String currentelement = (String) enum2.nextElement();
+                    String originalpattern = (String) newroots.get(currentelement);
+                    AntFTPFile myfile = new AntFTPFile(baseFTPFile, currentelement);
+                    boolean isOK = true;
+                    boolean traversesSymlinks = false;
+                    String path = null;
+
+                    if (myfile.exists()) {
+                        forceRemoteSensitivityCheck();
+                        if (remoteSensitivityChecked
+                            && remoteSystemCaseSensitive && isFollowSymlinks()) {
+                            // cool case,
+                            //we do not need to scan all the subdirs in the relative path
+                            path = myfile.getFastRelativePath();
+                        } else {
+                            // may be on a case insensitive file system.  We want
+                            // the results to show what's really on the disk, so
+                            // we need to double check.
+                            try {
+                                path = myfile.getRelativePath();
+                                traversesSymlinks = myfile.isTraverseSymlinks();
+                            }  catch (IOException be) {
+                                throw new BuildException(be, getLocation());
+                            } catch (BuildException be) {
+                                isOK = false;
+                            }
+                        }
+                    } else {
+                        isOK = false;
+                    }
+                    if (isOK) {
+                        currentelement = path.replace(remoteFileSep.charAt(0), File.separatorChar);
+                        if (!isFollowSymlinks()
+                            && traversesSymlinks) {
+                            continue;
+                        }
+
+                        if (myfile.isDirectory()) {
+                            if (isIncluded(currentelement)
+                                && currentelement.length() > 0) {
+                                accountForIncludedDir(currentelement, myfile, true);
+                            }  else {
+                                if (currentelement.length() > 0) {
+                                    if (currentelement.charAt(currentelement
+                                                              .length() - 1)
+                                        != File.separatorChar) {
+                                        currentelement =
+                                            currentelement + File.separatorChar;
+                                    }
+                                }
+                                scandir(myfile.getAbsolutePath(), currentelement, true);
+                            }
+                        } else {
+                            if (isCaseSensitive
+                                && originalpattern.equals(currentelement)) {
+                                accountForIncludedFile(currentelement);
+                            } else if (!isCaseSensitive
+                                       && originalpattern
+                                       .equalsIgnoreCase(currentelement)) {
+                                accountForIncludedFile(currentelement);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        /**
+         * scans a particular directory
+         * @param dir directory to scan
+         * @param vpath  relative path to the base directory of the remote fileset
+         * always ended with a File.separator
+         * @param fast seems to be always true in practice
+         */
+        protected void scandir(String dir, String vpath, boolean fast) {
+            // avoid double scanning of directories, can only happen in fast mode
+            if (fast && hasBeenScanned(vpath)) {
+                return;
+            }
+            try {
+                if (!ftp.changeWorkingDirectory(dir)) {
+                    return;
+                }
+                String completePath = null;
+                if (!vpath.equals("")) {
+                    completePath = rootPath + remoteFileSep
+                        + vpath.replace(File.separatorChar, remoteFileSep.charAt(0));
+                } else {
+                    completePath = rootPath;
+                }
+                FTPFile[] newfiles = listFiles(completePath, false);
+
+                if (newfiles == null) {
+                    ftp.changeToParentDirectory();
+                    return;
+                }
+                for (int i = 0; i < newfiles.length; i++) {
+                    FTPFile file = newfiles[i];
+                    if (file != null
+                            && !file.getName().equals(".")
+                            && !file.getName().equals("..")) {
+                        if (isFunctioningAsDirectory(ftp, dir, file)) {
+                            String name = vpath + file.getName();
+                            boolean slowScanAllowed = true;
+                            if (!isFollowSymlinks() && file.isSymbolicLink()) {
+                                dirsExcluded.addElement(name);
+                                slowScanAllowed = false;
+                            } else if (isIncluded(name)) {
+                                accountForIncludedDir(name,
+                                    new AntFTPFile(ftp, file, completePath) , fast);
+                            } else {
+                                dirsNotIncluded.addElement(name);
+                                if (fast && couldHoldIncluded(name)) {
+                                    scandir(file.getName(),
+                                            name + File.separator, fast);
+                                }
+                            }
+                            if (!fast && slowScanAllowed) {
+                                scandir(file.getName(),
+                                        name + File.separator, fast);
+                            }
+                        } else {
+                            String name = vpath + file.getName();
+                            if (!isFollowSymlinks() && file.isSymbolicLink()) {
+                                filesExcluded.addElement(name);
+                            } else if (isFunctioningAsFile(ftp, dir, file)) {
+                                accountForIncludedFile(name);
+                            }
+                        }
+                    }
+                }
+                ftp.changeToParentDirectory();
+            } catch (IOException e) {
+                throw new BuildException("Error while communicating with FTP "
+                     + "server: ", e);
+            }
+        }
+        /**
+         * process included file
+         * @param name  path of the file relative to the directory of the fileset
+         */
+        private void accountForIncludedFile(String name) {
+            if (!filesIncluded.contains(name)
+                && !filesExcluded.contains(name)) {
+
+                if (isIncluded(name)) {
+                    if (!isExcluded(name)) {
+                        filesIncluded.addElement(name);
+                    } else {
+                        filesExcluded.addElement(name);
+                    }
+                } else {
+                    filesNotIncluded.addElement(name);
+                }
+            }
+        }
+
+        /**
+         *
+         * @param name path of the directory relative to the directory of
+         * the fileset
+         * @param file directory as file
+         * @param fast
+         */
+        private void accountForIncludedDir(String name, AntFTPFile file, boolean fast) {
+            if (!dirsIncluded.contains(name)
+                && !dirsExcluded.contains(name)) {
+
+                if (!isExcluded(name)) {
+                    if (fast) {
+                        if (file.isSymbolicLink()) {
+                            try {
+                                file.getClient().changeWorkingDirectory(file.curpwd);
+                            } catch (IOException ioe) {
+                                throw new BuildException("could not change directory to curpwd");
+                            }
+                            scandir(file.getLink(),
+                                name + File.separator, fast);
+                        } else {
+                            try {
+                                file.getClient().changeWorkingDirectory(file.curpwd);
+                            } catch (IOException ioe) {
+                                throw new BuildException("could not change directory to curpwd");
+                            }
+                            scandir(file.getName(),
+                                name + File.separator, fast);
+                        }
+                    }
+                    dirsIncluded.addElement(name);
+                } else {
+                    dirsExcluded.addElement(name);
+                    if (fast && couldHoldIncluded(name)) {
+                        try {
+                            file.getClient().changeWorkingDirectory(file.curpwd);
+                        } catch (IOException ioe) {
+                            throw new BuildException("could not change directory to curpwd");
+                        }
+                        scandir(file.getName(),
+                                name + File.separator, fast);
+                    }
+                }
+            }
+        }
+        /**
+         * temporary table to speed up the various scanning methods below
+         *
+         * @since Ant 1.6
+         */
+        private Map fileListMap = new HashMap();
+        /**
+         * List of all scanned directories.
+         *
+         * @since Ant 1.6
+         */
+        private Set scannedDirs = new HashSet();
+
+        /**
+         * Has the directory with the given path relative to the base
+         * directory already been scanned?
+         *
+         * <p>Registers the given directory as scanned as a side effect.</p>
+         *
+         * @since Ant 1.6
+         */
+        private boolean hasBeenScanned(String vpath) {
+            return !scannedDirs.add(vpath);
+        }
+
+        /**
+         * Clear internal caches.
+         *
+         * @since Ant 1.6
+         */
+        private void clearCaches() {
+            fileListMap.clear();
+            scannedDirs.clear();
+        }
+        /**
+         * list the files present in one directory.
+         * @param directory full path on the remote side
+         * @param changedir if true change to directory directory before listing
+         * @return array of FTPFile
+         */
+        public FTPFile[] listFiles(String directory, boolean changedir) {
+            //getProject().log("listing files in directory " + directory, Project.MSG_DEBUG);
+            String currentPath = directory;
+            if (changedir) {
+                try {
+                    boolean result = ftp.changeWorkingDirectory(directory);
+                    if (!result) {
+                        return null;
+                    }
+                    currentPath = ftp.printWorkingDirectory();
+                } catch (IOException ioe) {
+                    throw new BuildException(ioe, getLocation());
+                }
+            }
+            if (fileListMap.containsKey(currentPath)) {
+                getProject().log("filelist map used in listing files", Project.MSG_DEBUG);
+                return ((FTPFile[]) fileListMap.get(currentPath));
+            }
+            FTPFile[] result = null;
+            try {
+                result = ftp.listFiles();
+            } catch (IOException ioe) {
+                throw new BuildException(ioe, getLocation());
+            }
+            fileListMap.put(currentPath, result);
+            if (!remoteSensitivityChecked) {
+                checkRemoteSensitivity(result, directory);
+            }
+            return result;
+        }
+
+        private void forceRemoteSensitivityCheck() {
+            if (!remoteSensitivityChecked) {
+                try {
+                    checkRemoteSensitivity(ftp.listFiles(), ftp.printWorkingDirectory());
+                } catch (IOException ioe) {
+                    throw new BuildException(ioe, getLocation());
+                }
+            }
+        }
+        /**
+         * cd into one directory and
+         * list the files present in one directory.
+         * @param directory full path on the remote side
+         * @return array of FTPFile
+         */
+        public FTPFile[] listFiles(String directory) {
+            return listFiles(directory, true);
+        }
+        private void checkRemoteSensitivity(FTPFile[] array, String directory) {
+            if (array == null) {
+                return;
+            }
+            boolean candidateFound = false;
+            String target = null;
+            for (int icounter = 0; icounter < array.length; icounter++) {
+                if (array[icounter] != null && array[icounter].isDirectory()) {
+                    if (!array[icounter].getName().equals(".")
+                        && !array[icounter].getName().equals("..")) {
+                        candidateFound = true;
+                        target = fiddleName(array[icounter].getName());
+                        getProject().log("will try to cd to "
+                            + target + " where a directory called " + array[icounter].getName()
+                            + " exists", Project.MSG_DEBUG);
+                        for (int pcounter = 0; pcounter < array.length; pcounter++) {
+                            if (array[pcounter] != null
+                                && pcounter != icounter
+                                && target.equals(array[pcounter].getName())) {
+                                candidateFound = false;
+                            }
+                        }
+                        if (candidateFound) {
+                            break;
+                        }
+                    }
+                }
+            }
+            if (candidateFound) {
+                try {
+                    getProject().log("testing case sensitivity, attempting to cd to "
+                        + target, Project.MSG_DEBUG);
+                    remoteSystemCaseSensitive  = !ftp.changeWorkingDirectory(target);
+                } catch (IOException ioe) {
+                    remoteSystemCaseSensitive = true;
+                } finally {
+                    try {
+                        ftp.changeWorkingDirectory(directory);
+                    } catch (IOException ioe) {
+                        throw new BuildException(ioe, getLocation());
+                    }
+                }
+                getProject().log("remote system is case sensitive : " + remoteSystemCaseSensitive,
+                    Project.MSG_VERBOSE);
+                remoteSensitivityChecked = true;
+            }
+        }
+        private String fiddleName(String origin) {
+            StringBuffer result = new StringBuffer();
+            for (int icounter = 0; icounter < origin.length(); icounter++) {
+                if (Character.isLowerCase(origin.charAt(icounter))) {
+                    result.append(Character.toUpperCase(origin.charAt(icounter)));
+                } else if (Character.isUpperCase(origin.charAt(icounter))) {
+                    result.append(Character.toLowerCase(origin.charAt(icounter)));
+                } else {
+                    result.append(origin.charAt(icounter));
+                }
+            }
+            return result.toString();
+        }
+        /**
+         * an AntFTPFile is a representation of a remote file
+         * @since Ant 1.6
+         */
+        protected class AntFTPFile {
+            /**
+             * ftp client
+             */
+            private FTPClient client;
+            /**
+             * parent directory of the file
+             */
+            private String curpwd;
+            /**
+             * the file itself
+             */
+            private FTPFile ftpFile;
+            /**
+             *
+             */
+            private AntFTPFile parent = null;
+            private boolean relativePathCalculated = false;
+            private boolean traversesSymlinks = false;
+            private String relativePath = "";
+            /**
+             * constructor
+             * @param client ftp client variable
+             * @param ftpFile the file
+             * @param curpwd absolute remote path where the file is found
+             */
+            public AntFTPFile(FTPClient client, FTPFile ftpFile, String curpwd) {
+                this.client = client;
+                this.ftpFile = ftpFile;
+                this.curpwd = curpwd;
+            }
+            /**
+             * other constructor
+             * @param parent the parent file
+             * @param path  a relative path to the parent file
+             */
+            public AntFTPFile(AntFTPFile parent, String path) {
+                this.parent = parent;
+                this.client = parent.client;
+                Vector pathElements = SelectorUtils.tokenizePath(path);
+                try {
+                    boolean result = this.client.changeWorkingDirectory(parent.getAbsolutePath());
+                    //this should not happen, except if parent has been deleted by another process
+                    if (!result) {
+                        return;
+                    }
+                    this.curpwd = parent.getAbsolutePath();
+                } catch (IOException ioe) {
+                    throw new BuildException("could not change working dir to "
+                    + parent.curpwd);
+                }
+                for (int fcount = 0; fcount < pathElements.size() - 1; fcount++) {
+                    String currentPathElement = (String) pathElements.elementAt(fcount);
+                    try {
+                        boolean result = this.client.changeWorkingDirectory(currentPathElement);
+                        if (!result && !isCaseSensitive()
+                            && (remoteSystemCaseSensitive || !remoteSensitivityChecked)) {
+                           currentPathElement = findPathElementCaseUnsensitive(this.curpwd,
+                               currentPathElement);
+                            if (currentPathElement == null) {
+                                return;
+                            }
+                        } else if (!result) {
+                            return;
+                        }
+                        this.curpwd = this.curpwd + remoteFileSep
+                            + currentPathElement;
+                    } catch (IOException ioe) {
+                        throw new BuildException("could not change working dir to "
+                        + (String) pathElements.elementAt(fcount)
+                            + " from " + this.curpwd);
+                    }
+
+                }
+                String lastpathelement = (String) pathElements.elementAt(pathElements.size() - 1);
+                FTPFile [] theFiles = listFiles(this.curpwd);
+                this.ftpFile = getFile(theFiles, lastpathelement);
+            }
+            /**
+             * find a file in a directory in case unsensitive way
+             * @param parentPath        where we are
+             * @param soughtPathElement what is being sought
+             * @return                  the first file found or null if not found
+             */
+            private String findPathElementCaseUnsensitive(String parentPath,
+                               String soughtPathElement) {
+                // we are already in the right path, so the second parameter
+                // is false
+                FTPFile[] theFiles = listFiles(parentPath, false);
+                if (theFiles == null) {
+                    return null;
+                }
+                for (int icounter = 0; icounter < theFiles.length; icounter++) {
+                    if (theFiles[icounter] != null
+                        && theFiles[icounter].getName().equalsIgnoreCase(soughtPathElement)) {
+                        return theFiles[icounter].getName();
+                    }
+                }
+                return null;
+            }
+            /**
+             * find out if the file exists
+             * @return  true if the file exists
+             */
+            public boolean exists() {
+                return (ftpFile != null);
+            }
+            /**
+             * if the file is a symbolic link, find out to what it is pointing
+             * @return the target of the symbolic link
+             */
+            public String getLink() {
+                return ftpFile.getLink();
+            }
+            /**
+             * get the name of the file
+             * @return the name of the file
+             */
+            public String getName() {
+                return ftpFile.getName();
+            }
+            /**
+             * find out the absolute path of the file
+             * @return absolute path as string
+             */
+            public String getAbsolutePath() {
+                return curpwd + remoteFileSep + ftpFile.getName();
+            }
+            /**
+             * find out the relative path assuming that the path used to construct
+             * this AntFTPFile was spelled properly with regards to case.
+             * This is OK on a case sensitive system such as UNIX
+             * @return relative path
+             */
+            public String getFastRelativePath() {
+                String absPath = getAbsolutePath();
+                if (absPath.indexOf(rootPath + remoteFileSep) == 0) {
+                    return absPath.substring(rootPath.length() + remoteFileSep.length());
+                }
+                return null;
+            }
+            /**
+             * find out the relative path to the rootPath of the enclosing scanner.
+             * this relative path is spelled exactly like on disk,
+             * for instance if the AntFTPFile has been instantiated as ALPHA,
+             * but the file is really called alpha, this method will return alpha.
+             * If a symbolic link is encountered, it is followed, but the name of the link
+             * rather than the name of the target is returned.
+             * (ie does not behave like File.getCanonicalPath())
+             * @return                relative path, separated by remoteFileSep
+             * @throws IOException    if a change directory fails, ...
+             * @throws BuildException if one of the components of the relative path cannot
+             * be found.
+             */
+            public String getRelativePath() throws IOException, BuildException {
+                if (!relativePathCalculated) {
+                    if (parent != null) {
+                        traversesSymlinks = parent.isTraverseSymlinks();
+                        relativePath = getRelativePath(parent.getAbsolutePath(),
+                            parent.getRelativePath());
+                    } else {
+                        relativePath = getRelativePath(rootPath, "");
+                        relativePathCalculated = true;
+                    }
+                }
+                return relativePath;
+            }
+            /**
+             * get thge relative path of this file
+             * @param currentPath          base path
+             * @param currentRelativePath  relative path of the base path with regards to remote dir
+             * @return relative path
+             */
+            private String getRelativePath(String currentPath, String currentRelativePath) {
+                Vector pathElements = SelectorUtils.tokenizePath(getAbsolutePath(), remoteFileSep);
+                Vector pathElements2 = SelectorUtils.tokenizePath(currentPath, remoteFileSep);
+                String relPath = currentRelativePath;
+                for (int pcount = pathElements2.size(); pcount < pathElements.size(); pcount++) {
+                    String currentElement = (String) pathElements.elementAt(pcount);
+                    FTPFile[] theFiles = listFiles(currentPath);
+                    FTPFile theFile = null;
+                    if (theFiles != null) {
+                        theFile = getFile(theFiles, currentElement);
+                    }
+                    if (!relPath.equals("")) {
+                        relPath = relPath + remoteFileSep;
+                    }
+                    if (theFile == null) {
+                        // hit a hidden file assume not a symlink
+                        relPath = relPath + currentElement;
+                        currentPath = currentPath + remoteFileSep + currentElement;
+                        log("Hidden file " + relPath
+                            + " assumed to not be a symlink.",
+                            Project.MSG_VERBOSE);
+                    } else {
+                        traversesSymlinks = traversesSymlinks || theFile.isSymbolicLink();
+                        relPath = relPath + theFile.getName();
+                        currentPath = currentPath + remoteFileSep + theFile.getName();
+                    }
+                }
+                return relPath;
+            }
+            /**
+             * find a file matching a string in an array of FTPFile.
+             * This method will find "alpha" when requested for "ALPHA"
+             * if and only if the caseSensitive attribute is set to false.
+             * When caseSensitive is set to true, only the exact match is returned.
+             * @param theFiles  array of files
+             * @param lastpathelement  the file name being sought
+             * @return null if the file cannot be found, otherwise return the matching file.
+             */
+            public FTPFile getFile(FTPFile[] theFiles, String lastpathelement) {
+                if (theFiles == null) {
+                    return null;
+                }
+                for (int fcount = 0; fcount < theFiles.length; fcount++) {
+                    if (theFiles[fcount] != null) {
+                        if (theFiles[fcount].getName().equals(lastpathelement)) {
+                            return theFiles[fcount];
+                        } else if (!isCaseSensitive()
+                                && theFiles[fcount].getName().equalsIgnoreCase(
+                                        lastpathelement)) {
+                            return theFiles[fcount];
+                        }
+                    }
+                }
+                return null;
+            }
+            /**
+             * tell if a file is a directory.
+             * note that it will return false for symbolic links pointing to directories.
+             * @return <code>true</code> for directories
+             */
+            public boolean isDirectory() {
+                return ftpFile.isDirectory();
+            }
+            /**
+             * tell if a file is a symbolic link
+             * @return <code>true</code> for symbolic links
+             */
+            public boolean isSymbolicLink() {
+                return ftpFile.isSymbolicLink();
+            }
+            /**
+             * return the attached FTP client object.
+             * Warning : this instance is really shared with the enclosing class.
+             * @return  FTP client
+             */
+            protected FTPClient getClient() {
+                return client;
+            }
+
+            /**
+             * sets the current path of an AntFTPFile
+             * @param curpwd the current path one wants to set
+             */
+            protected void setCurpwd(String curpwd) {
+                this.curpwd = curpwd;
+            }
+            /**
+             * returns the path of the directory containing the AntFTPFile.
+             * of the full path of the file itself in case of AntFTPRootFile
+             * @return parent directory of the AntFTPFile
+             */
+            public String getCurpwd() {
+                return curpwd;
+            }
+            /**
+             * find out if a symbolic link is encountered in the relative path of this file
+             * from rootPath.
+             * @return <code>true</code> if a symbolic link is encountered in the relative path.
+             * @throws IOException if one of the change directory or directory listing operations
+             * fails
+             * @throws BuildException if a path component in the relative path cannot be found.
+             */
+            public boolean isTraverseSymlinks() throws IOException, BuildException {
+                if (!relativePathCalculated) {
+                    // getRelativePath also finds about symlinks
+                    getRelativePath();
+                }
+                return traversesSymlinks;
+            }
+
+            /**
+             * Get a string rep of this object.
+             * @return a string containing the pwd and the file.
+             */
+            public String toString() {
+                return "AntFtpFile: " + curpwd + "%" + ftpFile;
+            }
+        }
+        /**
+         * special class to represent the remote directory itself
+         * @since Ant 1.6
+         */
+        protected class AntFTPRootFile extends AntFTPFile {
+             private String remotedir;
+            /**
+             * constructor
+             * @param aclient FTP client
+             * @param remotedir remote directory
+             */
+             public AntFTPRootFile(FTPClient aclient, String remotedir) {
+                 super(aclient, null, remotedir);
+                 this.remotedir = remotedir;
+                 try {
+                     this.getClient().changeWorkingDirectory(this.remotedir);
+                     this.setCurpwd(this.getClient().printWorkingDirectory());
+                 } catch (IOException ioe) {
+                     throw new BuildException(ioe, getLocation());
+                 }
+             }
+            /**
+             * find the absolute path
+             * @return absolute path
+             */
+            public String getAbsolutePath() {
+                return this.getCurpwd();
+            }
+            /**
+             * find out the relative path to root
+             * @return empty string
+             * @throws BuildException actually never
+             * @throws IOException  actually never
+             */
+            public String getRelativePath() throws BuildException, IOException {
+                 return "";
+            }
+        }
+    }
+    /**
+     * check FTPFiles to check whether they function as directories too
+     * the FTPFile API seem to make directory and symbolic links incompatible
+     * we want to find out if we can cd to a symbolic link
+     * @param dir  the parent directory of the file to test
+     * @param file the file to test
+     * @return true if it is possible to cd to this directory
+     * @since ant 1.6
+     */
+    private boolean isFunctioningAsDirectory(FTPClient ftp, String dir, FTPFile file) {
+        boolean result = false;
+        String currentWorkingDir = null;
+        if (file.isDirectory()) {
+            return true;
+        } else if (file.isFile()) {
+            return false;
+        }
+        try {
+            currentWorkingDir = ftp.printWorkingDirectory();
+        } catch (IOException ioe) {
+            getProject().log("could not find current working directory " + dir
+                + " while checking a symlink",
+                Project.MSG_DEBUG);
+        }
+        if (currentWorkingDir != null) {
+            try {
+                result = ftp.changeWorkingDirectory(file.getLink());
+            } catch (IOException ioe) {
+                getProject().log("could not cd to " + file.getLink() + " while checking a symlink",
+                    Project.MSG_DEBUG);
+            }
+            if (result) {
+                boolean comeback = false;
+                try {
+                    comeback = ftp.changeWorkingDirectory(currentWorkingDir);
+                } catch (IOException ioe) {
+                    getProject().log("could not cd back to " + dir + " while checking a symlink",
+                        Project.MSG_ERR);
+                } finally {
+                    if (!comeback) {
+                        throw new BuildException("could not cd back to " + dir
+                            + " while checking a symlink");
+                    }
+                }
+            }
+        }
+        return result;
+    }
+    /**
+     * check FTPFiles to check whether they function as directories too
+     * the FTPFile API seem to make directory and symbolic links incompatible
+     * we want to find out if we can cd to a symbolic link
+     * @param dir  the parent directory of the file to test
+     * @param file the file to test
+     * @return true if it is possible to cd to this directory
+     * @since ant 1.6
+     */
+    private boolean isFunctioningAsFile(FTPClient ftp, String dir, FTPFile file) {
+        if (file.isDirectory()) {
+            return false;
+        } else if (file.isFile()) {
+            return true;
+        }
+        return !isFunctioningAsDirectory(ftp, dir, file);
+    }
+    /**
+     * Sets the remote directory where files will be placed. This may be a
+     * relative or absolute path, and must be in the path syntax expected by
+     * the remote server. No correction of path syntax will be performed.
+     *
+     * @param dir the remote directory name.
+     */
+    public void setRemotedir(String dir) {
+        this.remotedir = dir;
+    }
+
+
+    /**
+     * Sets the FTP server to send files to.
+     *
+     * @param server the remote server name.
+     */
+    public void setServer(String server) {
+        this.server = server;
+    }
+
+
+    /**
+     * Sets the FTP port used by the remote server.
+     *
+     * @param port the port on which the remote server is listening.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+
+    /**
+     * Sets the login user id to use on the specified server.
+     *
+     * @param userid remote system userid.
+     */
+    public void setUserid(String userid) {
+        this.userid = userid;
+    }
+
+
+    /**
+     * Sets the login password for the given user id.
+     *
+     * @param password the password on the remote system.
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Sets the login account to use on the specified server.
+     *
+     * @param pAccount the account name on remote system
+     * @since Ant 1.7
+     */
+    public void setAccount(String pAccount) {
+        this.account = pAccount;
+    }
+
+
+    /**
+     * If true, uses binary mode, otherwise text mode (default is binary).
+     *
+     * @param binary if true use binary mode in transfers.
+     */
+    public void setBinary(boolean binary) {
+        this.binary = binary;
+    }
+
+
+    /**
+     * Specifies whether to use passive mode. Set to true if you are behind a
+     * firewall and cannot connect without it. Passive mode is disabled by
+     * default.
+     *
+     * @param passive true is passive mode should be used.
+     */
+    public void setPassive(boolean passive) {
+        this.passive = passive;
+    }
+
+
+    /**
+     * Set to true to receive notification about each file as it is
+     * transferred.
+     *
+     * @param verbose true if verbose notifications are required.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+
+    /**
+     * A synonym for <tt>depends</tt>. Set to true to transmit only new
+     * or changed files.
+     *
+     * See the related attributes timediffmillis and timediffauto.
+     *
+     * @param newer if true only transfer newer files.
+     */
+    public void setNewer(boolean newer) {
+        this.newerOnly = newer;
+    }
+
+    /**
+     * number of milliseconds to add to the time on the remote machine
+     * to get the time on the local machine.
+     *
+     * use in conjunction with <code>newer</code>
+     *
+     * @param timeDiffMillis number of milliseconds
+     *
+     * @since ant 1.6
+     */
+    public void setTimeDiffMillis(long timeDiffMillis) {
+        this.timeDiffMillis = timeDiffMillis;
+    }
+
+    /**
+     * &quot;true&quot; to find out automatically the time difference
+     * between local and remote machine.
+     *
+     * This requires right to create
+     * and delete a temporary file in the remote directory.
+     *
+     * @param timeDiffAuto true = find automatically the time diff
+     *
+     * @since ant 1.6
+     */
+    public void setTimeDiffAuto(boolean timeDiffAuto) {
+        this.timeDiffAuto = timeDiffAuto;
+    }
+
+    /**
+     * Set to true to preserve modification times for "gotten" files.
+     *
+     * @param preserveLastModified if true preserver modification times.
+     */
+    public void setPreserveLastModified(boolean preserveLastModified) {
+        this.preserveLastModified = preserveLastModified;
+    }
+
+
+    /**
+     * Set to true to transmit only files that are new or changed from their
+     * remote counterparts. The default is to transmit all files.
+     *
+     * @param depends if true only transfer newer files.
+     */
+    public void setDepends(boolean depends) {
+        this.newerOnly = depends;
+    }
+
+
+    /**
+     * Sets the remote file separator character. This normally defaults to the
+     * Unix standard forward slash, but can be manually overridden using this
+     * call if the remote server requires some other separator. Only the first
+     * character of the string is used.
+     *
+     * @param separator the file separator on the remote system.
+     */
+    public void setSeparator(String separator) {
+        remoteFileSep = separator;
+    }
+
+
+    /**
+     * Sets the file permission mode (Unix only) for files sent to the
+     * server.
+     *
+     * @param theMode unix style file mode for the files sent to the remote
+     *        system.
+     */
+    public void setChmod(String theMode) {
+        this.chmod = theMode;
+    }
+
+
+    /**
+     * Sets the default mask for file creation on a unix server.
+     *
+     * @param theUmask unix style umask for files created on the remote server.
+     */
+    public void setUmask(String theUmask) {
+        this.umask = theUmask;
+    }
+
+
+    /**
+     *  A set of files to upload or download
+     *
+     * @param set the set of files to be added to the list of files to be
+     *        transferred.
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+
+    /**
+     * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+     * "mkdir", "chmod", "list", and "site".
+     *
+     * @deprecated since 1.5.x.
+     *             setAction(String) is deprecated and is replaced with
+     *      setAction(FTP.Action) to make Ant's Introspection mechanism do the
+     *      work and also to encapsulate operations on the type in its own
+     *      class.
+     * @ant.attribute ignore="true"
+     *
+     * @param action the FTP action to be performed.
+     *
+     * @throws BuildException if the action is not a valid action.
+     */
+    public void setAction(String action) throws BuildException {
+        log("DEPRECATED - The setAction(String) method has been deprecated."
+             + " Use setAction(FTP.Action) instead.");
+
+        Action a = new Action();
+
+        a.setValue(action);
+        this.action = a.getAction();
+    }
+
+
+    /**
+     * Sets the FTP action to be taken. Currently accepts "put", "get", "del",
+     * "mkdir", "chmod", "list", and "site".
+     *
+     * @param action the FTP action to be performed.
+     *
+     * @throws BuildException if the action is not a valid action.
+     */
+    public void setAction(Action action) throws BuildException {
+        this.action = action.getAction();
+    }
+
+
+    /**
+     * The output file for the "list" action. This attribute is ignored for
+     * any other actions.
+     *
+     * @param listing file in which to store the listing.
+     */
+    public void setListing(File listing) {
+        this.listing = listing;
+    }
+
+
+    /**
+     * If true, enables unsuccessful file put, delete and get
+     * operations to be skipped with a warning and the remainder
+     * of the files still transferred.
+     *
+     * @param skipFailedTransfers true if failures in transfers are ignored.
+     */
+    public void setSkipFailedTransfers(boolean skipFailedTransfers) {
+        this.skipFailedTransfers = skipFailedTransfers;
+    }
+
+
+    /**
+     * set the flag to skip errors on directory creation.
+     * (and maybe later other server specific errors)
+     *
+     * @param ignoreNoncriticalErrors true if non-critical errors should not
+     *        cause a failure.
+     */
+    public void setIgnoreNoncriticalErrors(boolean ignoreNoncriticalErrors) {
+        this.ignoreNoncriticalErrors = ignoreNoncriticalErrors;
+    }
+
+    private void configurationHasBeenSet() {
+        this.isConfigurationSet = true;
+    }
+
+    /**
+     * Sets the systemTypeKey attribute.
+     * Method for setting <code>FTPClientConfig</code> remote system key.
+     *
+     * @param systemKey the key to be set - BUT if blank
+     * the default value of null (which signifies "autodetect") will be kept.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setSystemTypeKey(FTPSystemType systemKey) {
+        if (systemKey != null && !systemKey.getValue().equals("")) {
+            this.systemTypeKey = systemKey;
+            configurationHasBeenSet();
+        }
+    }
+
+    /**
+     * Sets the defaultDateFormatConfig attribute.
+     * @param defaultDateFormat configuration to be set, unless it is
+     * null or empty string, in which case ignored.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setDefaultDateFormatConfig(String defaultDateFormat) {
+        if (defaultDateFormat != null && !defaultDateFormat.equals("")) {
+            this.defaultDateFormatConfig = defaultDateFormat;
+            configurationHasBeenSet();
+        }
+    }
+
+    /**
+     * Sets the recentDateFormatConfig attribute.
+     * @param recentDateFormat configuration to be set, unless it is
+     * null or empty string, in which case ignored.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setRecentDateFormatConfig(String recentDateFormat) {
+        if (recentDateFormat != null && !recentDateFormat.equals("")) {
+            this.recentDateFormatConfig = recentDateFormat;
+            configurationHasBeenSet();
+        }
+    }
+
+    /**
+     * Sets the serverLanguageCode attribute.
+     * @param serverLanguageCode configuration to be set, unless it is
+     * null or empty string, in which case ignored.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setServerLanguageCodeConfig(LanguageCode serverLanguageCode) {
+        if (serverLanguageCode != null && !serverLanguageCode.equals("")) {
+            this.serverLanguageCodeConfig = serverLanguageCode;
+            configurationHasBeenSet();
+        }
+    }
+
+    /**
+     * Sets the serverTimeZoneConfig attribute.
+     * @param serverTimeZoneId configuration to be set, unless it is
+     * null or empty string, in which case ignored.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setServerTimeZoneConfig(String serverTimeZoneId) {
+        if (serverTimeZoneId != null && !serverTimeZoneId.equals("")) {
+            this.serverTimeZoneConfig = serverTimeZoneId;
+            configurationHasBeenSet();
+        }
+    }
+
+    /**
+     * Sets the shortMonthNamesConfig attribute
+     *
+     * @param shortMonthNames configuration to be set, unless it is
+     * null or empty string, in which case ignored.
+     * @see org.apache.commons.net.ftp.FTPClientConfig
+     */
+    public void setShortMonthNamesConfig(String shortMonthNames) {
+        if (shortMonthNames != null && !shortMonthNames.equals("")) {
+            this.shortMonthNamesConfig = shortMonthNames;
+            configurationHasBeenSet();
+        }
+    }
+
+
+
+    /**
+     * Defines how many times to retry executing FTP command before giving up.
+     * Default is 0 - try once and if failure then give up.
+     *
+     * @param retriesAllowed number of retries to allow.  -1 means
+     * keep trying forever. "forever" may also be specified as a
+     * synonym for -1.
+     */
+    public void setRetriesAllowed(String retriesAllowed) {
+        if ("FOREVER".equalsIgnoreCase(retriesAllowed)) {
+            this.retriesAllowed = Retryable.RETRY_FOREVER;
+        } else {
+            try {
+                int retries = Integer.parseInt(retriesAllowed);
+                if (retries < Retryable.RETRY_FOREVER) {
+                    throw new BuildException(
+                            "Invalid value for retriesAllowed attribute: "
+                            + retriesAllowed);
+
+                }
+                this.retriesAllowed = retries;
+            } catch (NumberFormatException px) {
+                throw new BuildException(
+                        "Invalid value for retriesAllowed attribute: "
+                        + retriesAllowed);
+
+            }
+
+        }
+    }
+    /**
+     * @return Returns the systemTypeKey.
+     */
+    String getSystemTypeKey() {
+        return systemTypeKey.getValue();
+    }
+    /**
+     * @return Returns the defaultDateFormatConfig.
+     */
+    String getDefaultDateFormatConfig() {
+        return defaultDateFormatConfig;
+    }
+    /**
+     * @return Returns the recentDateFormatConfig.
+     */
+    String getRecentDateFormatConfig() {
+        return recentDateFormatConfig;
+    }
+    /**
+     * @return Returns the serverLanguageCodeConfig.
+     */
+    String getServerLanguageCodeConfig() {
+        return serverLanguageCodeConfig.getValue();
+    }
+    /**
+     * @return Returns the serverTimeZoneConfig.
+     */
+    String getServerTimeZoneConfig() {
+        return serverTimeZoneConfig;
+    }
+    /**
+     * @return Returns the shortMonthNamesConfig.
+     */
+    String getShortMonthNamesConfig() {
+        return shortMonthNamesConfig;
+    }
+    /**
+     * @return Returns the timestampGranularity.
+     */
+    Granularity getTimestampGranularity() {
+        return timestampGranularity;
+    }
+    /**
+     * Sets the timestampGranularity attribute
+     * @param timestampGranularity The timestampGranularity to set.
+     */
+    public void setTimestampGranularity(Granularity timestampGranularity) {
+        if (null == timestampGranularity || "".equals(timestampGranularity)) {
+            return;
+        }
+        this.timestampGranularity = timestampGranularity;
+     }
+    /**
+     * Sets the siteCommand attribute.  This attribute
+     * names the command that will be executed if the action
+     * is "site".
+     * @param siteCommand The siteCommand to set.
+     */
+    public void setSiteCommand(String siteCommand) {
+        this.siteCommand = siteCommand;
+    }
+    /**
+     * Sets the initialSiteCommand attribute.  This attribute
+     * names a site command that will be executed immediately
+     * after connection.
+     * @param initialCommand The initialSiteCommand to set.
+     */
+    public void setInitialSiteCommand(String initialCommand) {
+        this.initialSiteCommand = initialCommand;
+    }
+    /**
+     * Checks to see that all required parameters are set.
+     *
+     * @throws BuildException if the configuration is not valid.
+     */
+    protected void checkAttributes() throws BuildException {
+        if (server == null) {
+            throw new BuildException("server attribute must be set!");
+        }
+        if (userid == null) {
+            throw new BuildException("userid attribute must be set!");
+        }
+        if (password == null) {
+            throw new BuildException("password attribute must be set!");
+        }
+
+        if ((action == LIST_FILES) && (listing == null)) {
+            throw new BuildException("listing attribute must be set for list "
+                 + "action!");
+        }
+
+        if (action == MK_DIR && remotedir == null) {
+            throw new BuildException("remotedir attribute must be set for "
+                 + "mkdir action!");
+        }
+
+        if (action == CHMOD && chmod == null) {
+            throw new BuildException("chmod attribute must be set for chmod "
+                 + "action!");
+        }
+        if (action == SITE_CMD && siteCommand == null) {
+            throw new BuildException("sitecommand attribute must be set for site "
+                 + "action!");
+        }
+
+
+        if (this.isConfigurationSet) {
+            try {
+                Class.forName("org.apache.commons.net.ftp.FTPClientConfig");
+            } catch (ClassNotFoundException e) {
+                throw new BuildException(
+                 "commons-net.jar >= 1.4.0 is required for at least one"
+                 + " of the attributes specified.");
+            }
+        }
+    }
+
+    /**
+     * Executable a retryable object.
+     * @param h the retry hander.
+     * @param r the object that should be retried until it succeeds
+     *          or the number of retrys is reached.
+     * @param descr a description of the command that is being run.
+     * @throws IOException if there is a problem.
+     */
+    protected void executeRetryable(RetryHandler h, Retryable r, String descr)
+        throws IOException {
+        h.execute(r, descr);
+    }
+
+
+    /**
+     * For each file in the fileset, do the appropriate action: send, get,
+     * delete, or list.
+     *
+     * @param ftp the FTPClient instance used to perform FTP actions
+     * @param fs the fileset on which the actions are performed.
+     *
+     * @return the number of files to be transferred.
+     *
+     * @throws IOException if there is a problem reading a file
+     * @throws BuildException if there is a problem in the configuration.
+     */
+    protected int transferFiles(final FTPClient ftp, FileSet fs)
+         throws IOException, BuildException {
+        DirectoryScanner ds;
+        if (action == SEND_FILES) {
+            ds = fs.getDirectoryScanner(getProject());
+        } else {
+            // warn that selectors are not supported
+            if (fs.getSelectors(getProject()).length != 0) {
+                getProject().log("selectors are not supported in remote filesets",
+                    Project.MSG_WARN);
+            }
+            ds = new FTPDirectoryScanner(ftp);
+            fs.setupDirectoryScanner(ds, getProject());
+            ds.setFollowSymlinks(fs.isFollowSymlinks());
+            ds.scan();
+        }
+
+        String[] dsfiles = null;
+        if (action == RM_DIR) {
+            dsfiles = ds.getIncludedDirectories();
+        } else {
+            dsfiles = ds.getIncludedFiles();
+        }
+        String dir = null;
+
+        if ((ds.getBasedir() == null)
+             && ((action == SEND_FILES) || (action == GET_FILES))) {
+            throw new BuildException("the dir attribute must be set for send "
+                 + "and get actions");
+        } else {
+            if ((action == SEND_FILES) || (action == GET_FILES)) {
+                dir = ds.getBasedir().getAbsolutePath();
+            }
+        }
+
+        // If we are doing a listing, we need the output stream created now.
+        BufferedWriter bw = null;
+
+        try {
+            if (action == LIST_FILES) {
+                File pd = listing.getParentFile();
+
+                if (!pd.exists()) {
+                    pd.mkdirs();
+                }
+                bw = new BufferedWriter(new FileWriter(listing));
+            }
+            RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+            if (action == RM_DIR) {
+                // to remove directories, start by the end of the list
+                // the trunk does not let itself be removed before the leaves
+                for (int i = dsfiles.length - 1; i >= 0; i--) {
+                    final String dsfile = dsfiles[i];
+                    executeRetryable(h, new Retryable() {
+                        public void execute() throws IOException {
+                            rmDir(ftp, dsfile);
+                        }
+                    }, dsfile);
+                }
+            } else {
+                final BufferedWriter fbw = bw;
+                final String fdir = dir;
+                if (this.newerOnly) {
+                    this.granularityMillis =
+                        this.timestampGranularity.getMilliseconds(action);
+                }
+                for (int i = 0; i < dsfiles.length; i++) {
+                    final String dsfile = dsfiles[i];
+                    executeRetryable(h, new Retryable() {
+                        public void execute() throws IOException {
+                            switch (action) {
+                                case SEND_FILES:
+                                    sendFile(ftp, fdir, dsfile);
+                                    break;
+                                case GET_FILES:
+                                    getFile(ftp, fdir, dsfile);
+                                    break;
+                                case DEL_FILES:
+                                    delFile(ftp, dsfile);
+                                    break;
+                                case LIST_FILES:
+                                    listFile(ftp, fbw, dsfile);
+                                    break;
+                                case CHMOD:
+                                    doSiteCommand(ftp, "chmod " + chmod
+                                                  + " " + resolveFile(dsfile));
+                                    transferred++;
+                                    break;
+                                default:
+                                    throw new BuildException("unknown ftp action " + action);
+                            }
+                        }
+                    }, dsfile);
+                }
+            }
+        } finally {
+            if (bw != null) {
+                bw.close();
+            }
+        }
+
+        return dsfiles.length;
+    }
+
+
+    /**
+     * Sends all files specified by the configured filesets to the remote
+     * server.
+     *
+     * @param ftp the FTPClient instance used to perform FTP actions
+     *
+     * @throws IOException if there is a problem reading a file
+     * @throws BuildException if there is a problem in the configuration.
+     */
+    protected void transferFiles(FTPClient ftp)
+         throws IOException, BuildException {
+        transferred = 0;
+        skipped = 0;
+
+        if (filesets.size() == 0) {
+            throw new BuildException("at least one fileset must be specified.");
+        } else {
+            // get files from filesets
+            for (int i = 0; i < filesets.size(); i++) {
+                FileSet fs = (FileSet) filesets.elementAt(i);
+
+                if (fs != null) {
+                    transferFiles(ftp, fs);
+                }
+            }
+        }
+
+        log(transferred + " " + ACTION_TARGET_STRS[action] + " "
+            + COMPLETED_ACTION_STRS[action]);
+        if (skipped != 0) {
+            log(skipped + " " + ACTION_TARGET_STRS[action]
+                + " were not successfully " + COMPLETED_ACTION_STRS[action]);
+        }
+    }
+
+
+    /**
+     * Correct a file path to correspond to the remote host requirements. This
+     * implementation currently assumes that the remote end can handle
+     * Unix-style paths with forward-slash separators. This can be overridden
+     * with the <code>separator</code> task parameter. No attempt is made to
+     * determine what syntax is appropriate for the remote host.
+     *
+     * @param file the remote file name to be resolved
+     *
+     * @return the filename as it will appear on the server.
+     */
+    protected String resolveFile(String file) {
+        return file.replace(System.getProperty("file.separator").charAt(0),
+            remoteFileSep.charAt(0));
+    }
+
+
+    /**
+     * Creates all parent directories specified in a complete relative
+     * pathname. Attempts to create existing directories will not cause
+     * errors.
+     *
+     * @param ftp the FTP client instance to use to execute FTP actions on
+     *        the remote server.
+     * @param filename the name of the file whose parents should be created.
+     * @throws IOException under non documented circumstances
+     * @throws BuildException if it is impossible to cd to a remote directory
+     *
+     */
+    protected void createParents(FTPClient ftp, String filename)
+         throws IOException, BuildException {
+
+        File dir = new File(filename);
+        if (dirCache.contains(dir)) {
+            return;
+        }
+
+
+        Vector parents = new Vector();
+        String dirname;
+
+        while ((dirname = dir.getParent()) != null) {
+            File checkDir = new File(dirname);
+            if (dirCache.contains(checkDir)) {
+                break;
+            }
+            dir = checkDir;
+            parents.addElement(dir);
+        }
+
+        // find first non cached dir
+        int i = parents.size() - 1;
+
+        if (i >= 0) {
+            String cwd = ftp.printWorkingDirectory();
+            String parent = dir.getParent();
+            if (parent != null) {
+                if (!ftp.changeWorkingDirectory(resolveFile(parent))) {
+                    throw new BuildException("could not change to "
+                        + "directory: " + ftp.getReplyString());
+                }
+            }
+
+            while (i >= 0) {
+                dir = (File) parents.elementAt(i--);
+                // check if dir exists by trying to change into it.
+                if (!ftp.changeWorkingDirectory(dir.getName())) {
+                    // could not change to it - try to create it
+                    log("creating remote directory "
+                        + resolveFile(dir.getPath()), Project.MSG_VERBOSE);
+                    if (!ftp.makeDirectory(dir.getName())) {
+                        handleMkDirFailure(ftp);
+                    }
+                    if (!ftp.changeWorkingDirectory(dir.getName())) {
+                        throw new BuildException("could not change to "
+                            + "directory: " + ftp.getReplyString());
+                    }
+                }
+                dirCache.addElement(dir);
+            }
+            ftp.changeWorkingDirectory(cwd);
+        }
+    }
+    /**
+     * auto find the time difference between local and remote
+     * @param ftp handle to ftp client
+     * @return number of millis to add to remote time to make it comparable to local time
+     * @since ant 1.6
+     */
+    private long getTimeDiff(FTPClient ftp) {
+        long returnValue = 0;
+        File tempFile = findFileName(ftp);
+        try {
+            // create a local temporary file
+            FILE_UTILS.createNewFile(tempFile);
+            long localTimeStamp = tempFile.lastModified();
+            BufferedInputStream instream = new BufferedInputStream(new FileInputStream(tempFile));
+            ftp.storeFile(tempFile.getName(), instream);
+            instream.close();
+            boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+            if (success) {
+                FTPFile [] ftpFiles = ftp.listFiles(tempFile.getName());
+                if (ftpFiles.length == 1) {
+                    long remoteTimeStamp = ftpFiles[0].getTimestamp().getTime().getTime();
+                    returnValue = localTimeStamp - remoteTimeStamp;
+                }
+                ftp.deleteFile(ftpFiles[0].getName());
+            }
+            // delegate the deletion of the local temp file to the delete task
+            // because of race conditions occuring on Windows
+            Delete mydelete = new Delete();
+            mydelete.bindToOwner(this);
+            mydelete.setFile(tempFile.getCanonicalFile());
+            mydelete.execute();
+        } catch (Exception e) {
+            throw new BuildException(e, getLocation());
+        }
+        return returnValue;
+    }
+    /**
+     *  find a suitable name for local and remote temporary file
+     */
+    private File findFileName(FTPClient ftp) {
+        FTPFile [] theFiles = null;
+        final int maxIterations = 1000;
+        for (int counter = 1; counter < maxIterations; counter++) {
+            File localFile = FILE_UTILS.createTempFile(
+                "ant" + Integer.toString(counter), ".tmp",
+                null, false, false);
+            String fileName = localFile.getName();
+            boolean found = false;
+            try {
+                if (theFiles == null) {
+                    theFiles = ftp.listFiles();
+                }
+                for (int counter2 = 0; counter2 < theFiles.length; counter2++) {
+                    if (theFiles[counter2] != null
+                        && theFiles[counter2].getName().equals(fileName)) {
+                        found = true;
+                        break;
+                    }
+                }
+            } catch (IOException ioe) {
+                throw new BuildException(ioe, getLocation());
+            }
+            if (!found) {
+                localFile.deleteOnExit();
+                return localFile;
+            }
+        }
+        return null;
+    }
+
+    private static final SimpleDateFormat TIMESTAMP_LOGGING_SDF =
+        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     * Checks to see if the remote file is current as compared with the local
+     * file. Returns true if the target file is up to date.
+     * @param ftp ftpclient
+     * @param localFile local file
+     * @param remoteFile remote file
+     * @return true if the target file is up to date
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException if the date of the remote files cannot be found and the action is
+     * GET_FILES
+     */
+    protected boolean isUpToDate(FTPClient ftp, File localFile,
+                                 String remoteFile)
+         throws IOException, BuildException {
+        log("checking date for " + remoteFile, Project.MSG_VERBOSE);
+
+        FTPFile[] files = ftp.listFiles(remoteFile);
+
+        // For Microsoft's Ftp-Service an Array with length 0 is
+        // returned if configured to return listings in "MS-DOS"-Format
+        if (files == null || files.length == 0) {
+            // If we are sending files, then assume out of date.
+            // If we are getting files, then throw an error
+
+            if (action == SEND_FILES) {
+                log("Could not date test remote file: " + remoteFile
+                     + "assuming out of date.", Project.MSG_VERBOSE);
+                return false;
+            } else {
+                throw new BuildException("could not date test remote file: "
+                    + ftp.getReplyString());
+            }
+        }
+
+        long remoteTimestamp = files[0].getTimestamp().getTime().getTime();
+        long localTimestamp = localFile.lastModified();
+        long adjustedRemoteTimestamp =
+            remoteTimestamp + this.timeDiffMillis + this.granularityMillis;
+
+        StringBuffer msg = new StringBuffer("   [")
+                .append(TIMESTAMP_LOGGING_SDF.format(new Date(localTimestamp)))
+                .append("] local");
+        log(msg.toString(), Project.MSG_VERBOSE);
+
+        msg = new StringBuffer("   [")
+                  .append(TIMESTAMP_LOGGING_SDF.format(new Date(adjustedRemoteTimestamp)))
+                .append("] remote");
+        if (remoteTimestamp != adjustedRemoteTimestamp) {
+            msg.append(" - (raw: ")
+                .append(TIMESTAMP_LOGGING_SDF.format(new Date(remoteTimestamp)))
+            .append(")");
+        }
+        log(msg.toString(), Project.MSG_VERBOSE);
+
+
+
+        if (this.action == SEND_FILES) {
+            return adjustedRemoteTimestamp >= localTimestamp;
+        } else {
+            return localTimestamp >= adjustedRemoteTimestamp;
+        }
+    }
+
+
+    /**
+    * Sends a site command to the ftp server
+    * @param ftp ftp client
+    * @param theCMD command to execute
+    * @throws IOException  in unknown circumstances
+    * @throws BuildException in unknown circumstances
+    */
+    protected void doSiteCommand(FTPClient ftp, String theCMD)
+         throws IOException, BuildException {
+        boolean rc;
+        String[] myReply = null;
+
+        log("Doing Site Command: " + theCMD, Project.MSG_VERBOSE);
+
+        rc = ftp.sendSiteCommand(theCMD);
+
+        if (!rc) {
+            log("Failed to issue Site Command: " + theCMD, Project.MSG_WARN);
+        } else {
+
+            myReply = ftp.getReplyStrings();
+
+            for (int x = 0; x < myReply.length; x++) {
+                if (myReply[x].indexOf("200") == -1) {
+                    log(myReply[x], Project.MSG_WARN);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Sends a single file to the remote host. <code>filename</code> may
+     * contain a relative path specification. When this is the case, <code>sendFile</code>
+     * will attempt to create any necessary parent directories before sending
+     * the file. The file will then be sent using the entire relative path
+     * spec - no attempt is made to change directories. It is anticipated that
+     * this may eventually cause problems with some FTP servers, but it
+     * simplifies the coding.
+     * @param ftp ftp client
+     * @param dir base directory of the file to be sent (local)
+     * @param filename relative path of the file to be send
+     *        locally relative to dir
+     *        remotely relative to the remotedir attribute
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException in unknown circumstances
+     */
+    protected void sendFile(FTPClient ftp, String dir, String filename)
+         throws IOException, BuildException {
+        InputStream instream = null;
+
+        try {
+            // XXX - why not simply new File(dir, filename)?
+            File file = getProject().resolveFile(new File(dir, filename).getPath());
+
+            if (newerOnly && isUpToDate(ftp, file, resolveFile(filename))) {
+                return;
+            }
+
+            if (verbose) {
+                log("transferring " + file.getAbsolutePath());
+            }
+
+            instream = new BufferedInputStream(new FileInputStream(file));
+
+            createParents(ftp, filename);
+
+            ftp.storeFile(resolveFile(filename), instream);
+
+            boolean success = FTPReply.isPositiveCompletion(ftp.getReplyCode());
+
+            if (!success) {
+                String s = "could not put file: " + ftp.getReplyString();
+
+                if (skipFailedTransfers) {
+                    log(s, Project.MSG_WARN);
+                    skipped++;
+                } else {
+                    throw new BuildException(s);
+                }
+
+            } else {
+                // see if we should issue a chmod command
+                if (chmod != null) {
+                    doSiteCommand(ftp, "chmod " + chmod + " " + resolveFile(filename));
+                }
+                log("File " + file.getAbsolutePath() + " copied to " + server,
+                    Project.MSG_VERBOSE);
+                transferred++;
+            }
+        } finally {
+            if (instream != null) {
+                try {
+                    instream.close();
+                } catch (IOException ex) {
+                    // ignore it
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Delete a file from the remote host.
+     * @param ftp ftp client
+     * @param filename file to delete
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException if skipFailedTransfers is set to false
+     * and the deletion could not be done
+     */
+    protected void delFile(FTPClient ftp, String filename)
+         throws IOException, BuildException {
+        if (verbose) {
+            log("deleting " + filename);
+        }
+
+        if (!ftp.deleteFile(resolveFile(filename))) {
+            String s = "could not delete file: " + ftp.getReplyString();
+
+            if (skipFailedTransfers) {
+                log(s, Project.MSG_WARN);
+                skipped++;
+            } else {
+                throw new BuildException(s);
+            }
+        } else {
+            log("File " + filename + " deleted from " + server,
+                Project.MSG_VERBOSE);
+            transferred++;
+        }
+    }
+
+    /**
+     * Delete a directory, if empty, from the remote host.
+     * @param ftp ftp client
+     * @param dirname directory to delete
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException if skipFailedTransfers is set to false
+     * and the deletion could not be done
+     */
+    protected void rmDir(FTPClient ftp, String dirname)
+         throws IOException, BuildException {
+        if (verbose) {
+            log("removing " + dirname);
+        }
+
+        if (!ftp.removeDirectory(resolveFile(dirname))) {
+            String s = "could not remove directory: " + ftp.getReplyString();
+
+            if (skipFailedTransfers) {
+                log(s, Project.MSG_WARN);
+                skipped++;
+            } else {
+                throw new BuildException(s);
+            }
+        } else {
+            log("Directory " + dirname + " removed from " + server,
+                Project.MSG_VERBOSE);
+            transferred++;
+        }
+    }
+
+
+    /**
+     * Retrieve a single file from the remote host. <code>filename</code> may
+     * contain a relative path specification. <p>
+     *
+     * The file will then be retreived using the entire relative path spec -
+     * no attempt is made to change directories. It is anticipated that this
+     * may eventually cause problems with some FTP servers, but it simplifies
+     * the coding.</p>
+     * @param ftp the ftp client
+     * @param dir local base directory to which the file should go back
+     * @param filename relative path of the file based upon the ftp remote directory
+     *        and/or the local base directory (dir)
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException if skipFailedTransfers is false
+     * and the file cannot be retrieved.
+     */
+    protected void getFile(FTPClient ftp, String dir, String filename)
+         throws IOException, BuildException {
+        OutputStream outstream = null;
+        try {
+            File file = getProject().resolveFile(new File(dir, filename).getPath());
+
+            if (newerOnly && isUpToDate(ftp, file, resolveFile(filename))) {
+                return;
+            }
+
+            if (verbose) {
+                log("transferring " + filename + " to "
+                     + file.getAbsolutePath());
+            }
+
+            File pdir = file.getParentFile();
+
+            if (!pdir.exists()) {
+                pdir.mkdirs();
+            }
+            outstream = new BufferedOutputStream(new FileOutputStream(file));
+            ftp.retrieveFile(resolveFile(filename), outstream);
+
+            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                String s = "could not get file: " + ftp.getReplyString();
+
+                if (skipFailedTransfers) {
+                    log(s, Project.MSG_WARN);
+                    skipped++;
+                } else {
+                    throw new BuildException(s);
+                }
+
+            } else {
+                log("File " + file.getAbsolutePath() + " copied from "
+                     + server, Project.MSG_VERBOSE);
+                transferred++;
+                if (preserveLastModified) {
+                    outstream.close();
+                    outstream = null;
+                    FTPFile[] remote = ftp.listFiles(resolveFile(filename));
+                    if (remote.length > 0) {
+                        FILE_UTILS.setFileLastModified(file,
+                                                      remote[0].getTimestamp()
+                                                      .getTime().getTime());
+                    }
+                }
+            }
+        } finally {
+            if (outstream != null) {
+                try {
+                    outstream.close();
+                } catch (IOException ex) {
+                    // ignore it
+                }
+            }
+        }
+    }
+
+
+    /**
+     * List information about a single file from the remote host. <code>filename</code>
+     * may contain a relative path specification. <p>
+     *
+     * The file listing will then be retrieved using the entire relative path
+     * spec - no attempt is made to change directories. It is anticipated that
+     * this may eventually cause problems with some FTP servers, but it
+     * simplifies the coding.</p>
+     * @param ftp ftp client
+     * @param bw buffered writer
+     * @param filename the directory one wants to list
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException in unknown circumstances
+     */
+    protected void listFile(FTPClient ftp, BufferedWriter bw, String filename)
+            throws IOException, BuildException {
+        if (verbose) {
+            log("listing " + filename);
+        }
+        FTPFile[] ftpfiles = ftp.listFiles(resolveFile(filename));
+
+        if (ftpfiles != null && ftpfiles.length > 0) {
+            bw.write(ftpfiles[0].toString());
+            bw.newLine();
+            transferred++;
+        }
+    }
+
+
+    /**
+     * Create the specified directory on the remote host.
+     *
+     * @param ftp The FTP client connection
+     * @param dir The directory to create (format must be correct for host
+     *      type)
+     * @throws IOException  in unknown circumstances
+     * @throws BuildException if ignoreNoncriticalErrors has not been set to true
+     *         and a directory could not be created, for instance because it was
+     *         already existing. Precisely, the codes 521, 550 and 553 will trigger
+     *         a BuildException
+     */
+    protected void makeRemoteDir(FTPClient ftp, String dir)
+         throws IOException, BuildException {
+        String workingDirectory = ftp.printWorkingDirectory();
+        if (verbose) {
+            log("Creating directory: " + dir);
+        }
+        if (dir.indexOf("/") == 0) {
+            ftp.changeWorkingDirectory("/");
+        }
+        String subdir = "";
+        StringTokenizer st = new StringTokenizer(dir, "/");
+        while (st.hasMoreTokens()) {
+            subdir = st.nextToken();
+            log("Checking " + subdir, Project.MSG_DEBUG);
+            if (!ftp.changeWorkingDirectory(subdir)) {
+                if (!ftp.makeDirectory(subdir)) {
+                    // codes 521, 550 and 553 can be produced by FTP Servers
+                    //  to indicate that an attempt to create a directory has
+                    //  failed because the directory already exists.
+                    int rc = ftp.getReplyCode();
+                    if (!(ignoreNoncriticalErrors
+                        && (rc == FTPReply.CODE_550 || rc == FTPReply.CODE_553
+                        || rc == CODE_521))) {
+                        throw new BuildException("could not create directory: "
+                            + ftp.getReplyString());
+                    }
+                    if (verbose) {
+                        log("Directory already exists");
+                    }
+                } else {
+                    if (verbose) {
+                        log("Directory created OK");
+                    }
+                    ftp.changeWorkingDirectory(subdir);
+                }
+            }
+        }
+        if (workingDirectory != null) {
+            ftp.changeWorkingDirectory(workingDirectory);
+        }
+    }
+
+    /**
+     * look at the response for a failed mkdir action, decide whether
+     * it matters or not. If it does, we throw an exception
+     * @param ftp current ftp connection
+     * @throws BuildException if this is an error to signal
+     */
+    private void handleMkDirFailure(FTPClient ftp)
+            throws BuildException {
+        int rc = ftp.getReplyCode();
+        if (!(ignoreNoncriticalErrors
+             && (rc == FTPReply.CODE_550 || rc == FTPReply.CODE_553 || rc == CODE_521))) {
+            throw new BuildException("could not create directory: "
+                + ftp.getReplyString());
+        }
+    }
+
+    /**
+     * Runs the task.
+     *
+     * @throws BuildException if the task fails or is not configured
+     *         correctly.
+     */
+    public void execute() throws BuildException {
+        checkAttributes();
+
+        FTPClient ftp = null;
+
+        try {
+            log("Opening FTP connection to " + server, Project.MSG_VERBOSE);
+
+            ftp = new FTPClient();
+            if (this.isConfigurationSet) {
+                ftp = FTPConfigurator.configure(ftp, this);
+            }
+
+            ftp.connect(server, port);
+            if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                throw new BuildException("FTP connection failed: "
+                     + ftp.getReplyString());
+            }
+
+            log("connected", Project.MSG_VERBOSE);
+            log("logging in to FTP server", Project.MSG_VERBOSE);
+
+            if ((this.account != null && !ftp.login(userid, password, account))
+                    || (this.account == null && !ftp.login(userid, password))) {
+                throw new BuildException("Could not login to FTP server");
+            }
+
+            log("login succeeded", Project.MSG_VERBOSE);
+
+            if (binary) {
+                ftp.setFileType(org.apache.commons.net.ftp.FTP.IMAGE_FILE_TYPE);
+                if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                    throw new BuildException("could not set transfer type: "
+                        + ftp.getReplyString());
+                }
+            } else {
+                ftp.setFileType(org.apache.commons.net.ftp.FTP.ASCII_FILE_TYPE);
+                if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                    throw new BuildException("could not set transfer type: "
+                        + ftp.getReplyString());
+                }
+            }
+
+            if (passive) {
+                log("entering passive mode", Project.MSG_VERBOSE);
+                ftp.enterLocalPassiveMode();
+                if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                    throw new BuildException("could not enter into passive "
+                         + "mode: " + ftp.getReplyString());
+                }
+            }
+
+            // If an initial command was configured then send it.
+            // Some FTP servers offer different modes of operation,
+            // E.G. switching between a UNIX file system mode and
+            // a legacy file system.
+            if (this.initialSiteCommand != null) {
+                RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+                final FTPClient lftp = ftp;
+                executeRetryable(h, new Retryable() {
+                    public void execute() throws IOException {
+                        doSiteCommand(lftp, FTP.this.initialSiteCommand);
+                    }
+                }, "initial site command: " + this.initialSiteCommand);
+            }
+
+
+            // For a unix ftp server you can set the default mask for all files
+            // created.
+
+            if (umask != null) {
+                RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+                final FTPClient lftp = ftp;
+                executeRetryable(h, new Retryable() {
+                    public void execute() throws IOException {
+                        doSiteCommand(lftp, "umask " + umask);
+                    }
+                }, "umask " + umask);
+            }
+
+            // If the action is MK_DIR, then the specified remote
+            // directory is the directory to create.
+
+            if (action == MK_DIR) {
+                RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+                final FTPClient lftp = ftp;
+                executeRetryable(h, new Retryable() {
+                    public void execute() throws IOException {
+                        makeRemoteDir(lftp, remotedir);
+                    }
+                }, remotedir);
+            } else if (action == SITE_CMD) {
+                    RetryHandler h = new RetryHandler(this.retriesAllowed, this);
+                    final FTPClient lftp = ftp;
+                    executeRetryable(h, new Retryable() {
+                        public void execute() throws IOException {
+                            doSiteCommand(lftp, FTP.this.siteCommand);
+                        }
+                    }, "Site Command: " + this.siteCommand);
+            } else {
+                if (remotedir != null) {
+                    log("changing the remote directory", Project.MSG_VERBOSE);
+                    ftp.changeWorkingDirectory(remotedir);
+                    if (!FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
+                        throw new BuildException("could not change remote "
+                             + "directory: " + ftp.getReplyString());
+                    }
+                }
+                if (newerOnly && timeDiffAuto) {
+                // in this case we want to find how much time span there is between local
+                // and remote
+                    timeDiffMillis = getTimeDiff(ftp);
+                }
+                log(ACTION_STRS[action] + " " + ACTION_TARGET_STRS[action]);
+                transferFiles(ftp);
+            }
+
+        } catch (IOException ex) {
+            throw new BuildException("error during FTP transfer: " + ex, ex);
+        } finally {
+            if (ftp != null && ftp.isConnected()) {
+                try {
+                    log("disconnecting", Project.MSG_VERBOSE);
+                    ftp.logout();
+                    ftp.disconnect();
+                } catch (IOException ex) {
+                    // ignore it
+                }
+            }
+        }
+    }
+
+
+    /**
+     * an action to perform, one of
+     * "send", "put", "recv", "get", "del", "delete", "list", "mkdir", "chmod",
+     * "rmdir"
+     */
+    public static class Action extends EnumeratedAttribute {
+
+        private static final String[] VALID_ACTIONS = {
+            "send", "put", "recv", "get", "del", "delete", "list", "mkdir",
+            "chmod", "rmdir", "site"
+            };
+
+
+        /**
+         * Get the valid values
+         *
+         * @return an array of the valid FTP actions.
+         */
+        public String[] getValues() {
+            return VALID_ACTIONS;
+        }
+
+
+        /**
+         * Get the symbolic equivalent of the action value.
+         *
+         * @return the SYMBOL representing the given action.
+         */
+        public int getAction() {
+            String actionL = getValue().toLowerCase(Locale.US);
+
+            if (actionL.equals("send") || actionL.equals("put")) {
+                return SEND_FILES;
+            } else if (actionL.equals("recv") || actionL.equals("get")) {
+                return GET_FILES;
+            } else if (actionL.equals("del") || actionL.equals("delete")) {
+                return DEL_FILES;
+            } else if (actionL.equals("list")) {
+                return LIST_FILES;
+            } else if (actionL.equals("chmod")) {
+                return CHMOD;
+            } else if (actionL.equals("mkdir")) {
+                return MK_DIR;
+            } else if (actionL.equals("rmdir")) {
+                return RM_DIR;
+            } else if (actionL.equals("site")) {
+                return SITE_CMD;
+            }
+            return SEND_FILES;
+        }
+    }
+    /**
+     * represents one of the valid timestamp adjustment values
+     * recognized by the <code>timestampGranularity</code> attribute.<p>
+
+     * A timestamp adjustment may be used in file transfers for checking
+     * uptodateness. MINUTE means to add one minute to the server
+     * timestamp.  This is done because FTP servers typically list
+     * timestamps HH:mm and client FileSystems typically use HH:mm:ss.
+     *
+     * The default is to use MINUTE for PUT actions and NONE for GET
+     * actions, since GETs have the <code>preserveLastModified</code>
+     * option, which takes care of the problem in most use cases where
+     * this level of granularity is an issue.
+     *
+     */
+    public static class Granularity extends EnumeratedAttribute {
+
+        private static final String[] VALID_GRANULARITIES = {
+                "", "MINUTE", "NONE"
+        };
+
+        /**
+         * Get the valid values.
+         * @return the list of valid Granularity values
+         */
+        public String[] getValues() {
+            // TODO Auto-generated method stub
+            return VALID_GRANULARITIES;
+        }
+        /**
+         * returns the number of milliseconds associated with
+         * the attribute, which can vary in some cases depending
+         * on the value of the action parameter.
+         * @param action SEND_FILES or GET_FILES
+         * @return the number of milliseconds associated with
+         * the attribute, in the context of the supplied action
+         */
+        public long getMilliseconds(int action) {
+            String granularityU = getValue().toUpperCase(Locale.US);
+
+            if ("".equals(granularityU)) {
+                if (action == SEND_FILES) {
+                    return GRANULARITY_MINUTE;
+                }
+            } else if ("MINUTE".equals(granularityU)) {
+                return GRANULARITY_MINUTE;
+                }
+                return 0L;
+        }
+        static final Granularity getDefault() {
+            Granularity g = new Granularity();
+            g.setValue("");
+            return g;
+        }
+
+   }
+   /**
+         * one of the valid system type keys recognized by the systemTypeKey
+         * attribute.
+         */
+    public static class FTPSystemType extends EnumeratedAttribute {
+
+       private static final String[] VALID_SYSTEM_TYPES = {
+                   "", "UNIX", "VMS", "WINDOWS", "OS/2", "OS/400",
+                   "MVS"
+           };
+
+
+            /**
+             * Get the valid values.
+             * @return the list of valid system types.
+             */
+            public String[] getValues() {
+                return VALID_SYSTEM_TYPES;
+            }
+
+            static final FTPSystemType getDefault() {
+                FTPSystemType ftpst = new FTPSystemType();
+                ftpst.setValue("");
+                return ftpst;
+            }
+    }
+    /**
+     * Enumerated class for languages.
+     */
+    public static class LanguageCode extends EnumeratedAttribute {
+
+
+        private static final String[] VALID_LANGUAGE_CODES =
+            getValidLanguageCodes();
+
+        private static String[] getValidLanguageCodes() {
+            Collection c = FTPClientConfig.getSupportedLanguageCodes();
+            String[] ret = new String[c.size() + 1];
+            int i = 0;
+            ret[i++] = "";
+            for (Iterator it = c.iterator(); it.hasNext(); i++) {
+                ret[i] = (String) it.next();
+            }
+            return ret;
+        }
+
+
+             /**
+              * Return the value values.
+              * @return the list of valid language types.
+              */
+             public String[] getValues() {
+                 return VALID_LANGUAGE_CODES;
+             }
+
+             static final LanguageCode getDefault() {
+                 LanguageCode lc = new LanguageCode();
+                 lc.setValue("");
+                 return lc;
+             }
+     }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java
new file mode 100644
index 0000000..956ca42
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/FTPConfigurator.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPClientConfig;
+import org.apache.tools.ant.Project;
+
+/**
+ * The sole purpose of this class is (note that it is package-private
+ * is to serve as a separate, static compilation unit for importing
+ * FTPClientConfig, to enable users who wish to use the FTP task
+ * without using its new features to avoid  the need to
+ * upgrade to jakarta-commons-net 1.4.0, where FTPClientConfig was
+ * introduced.
+  */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+class FTPConfigurator {
+    /**
+     * configures the supplied FTPClient with the various
+     * attributes set in the supplied FTP task.
+     * @param client the FTPClient to be configured
+     * @param task the FTP task whose attributes are used to
+     * configure the client
+     * @return the client as configured.
+     */
+    static FTPClient configure(FTPClient client, FTP task) {
+        task.log("custom configuration", Project.MSG_VERBOSE);
+        FTPClientConfig config;
+        String systemTypeKey = task.getSystemTypeKey();
+        if (systemTypeKey != null && !"".equals(systemTypeKey)) {
+            config = new FTPClientConfig(systemTypeKey);
+            task.log("custom config: system key = "
+                    + systemTypeKey, Project.MSG_VERBOSE);
+        } else {
+            config = new FTPClientConfig();
+            task.log("custom config: system key = default (UNIX)",
+                    Project.MSG_VERBOSE);
+        }
+
+        String defaultDateFormatConfig = task.getDefaultDateFormatConfig();
+        if (defaultDateFormatConfig != null) {
+            config.setDefaultDateFormatStr(defaultDateFormatConfig);
+            task.log("custom config: default date format = "
+                    + defaultDateFormatConfig, Project.MSG_VERBOSE);
+        }
+
+        String recentDateFormatConfig = task.getRecentDateFormatConfig();
+        if (recentDateFormatConfig != null) {
+            config.setRecentDateFormatStr(recentDateFormatConfig);
+            task.log("custom config: recent date format = "
+                    + recentDateFormatConfig, Project.MSG_VERBOSE);
+        }
+
+        String serverLanguageCodeConfig = task.getServerLanguageCodeConfig();
+        if (serverLanguageCodeConfig != null) {
+            config.setServerLanguageCode(serverLanguageCodeConfig);
+            task.log("custom config: server language code = "
+                    + serverLanguageCodeConfig, Project.MSG_VERBOSE);
+        }
+
+        String serverTimeZoneConfig = task.getServerTimeZoneConfig();
+        if (serverTimeZoneConfig != null) {
+            config.setServerTimeZoneId(serverTimeZoneConfig);
+            task.log("custom config: server time zone ID = "
+                    + serverTimeZoneConfig, Project.MSG_VERBOSE);
+        }
+
+        String shortMonthNamesConfig = task.getShortMonthNamesConfig();
+        if (shortMonthNamesConfig != null) {
+            config.setShortMonthNames(shortMonthNamesConfig);
+            task.log("custom config: short month names = "
+                    + shortMonthNamesConfig, Project.MSG_VERBOSE);
+        }
+        client.configure(config);
+        return client;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java
new file mode 100644
index 0000000..fca4215
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/MimeMail.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.email.EmailTask;
+
+/**
+ * A task to send SMTP email; Use <tt>mail</tt> instead
+ *
+ * @deprecated since 1.6.x.
+ *             Use {@link EmailTask} instead.
+ *
+ * @since Ant1.4
+ */
+public class MimeMail extends EmailTask {
+    /**
+     * Executes this build task.
+     *
+     * @exception BuildException On error.
+     */
+    public void execute()
+        throws BuildException {
+        log("DEPRECATED - The " + getTaskName() + " task is deprecated. "
+            + "Use the mail task instead.");
+        super.execute();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java
new file mode 100644
index 0000000..0ca1123
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/RExecTask.java
@@ -0,0 +1,474 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import org.apache.commons.net.bsd.RExecClient;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Automates the rexec protocol.
+ *
+ * @since Ant 1.6
+ */
+
+public class RExecTask extends Task {
+
+    private static final int PAUSE_TIME = 250;
+
+    /**
+     *  The userid to login with, if automated login is used
+     */
+    private String userid  = null;
+
+    /**
+     *  The password to login with, if automated login is used
+     */
+    private String password = null;
+
+    /**
+     *  The command to execute
+     */
+    private String command = null;
+
+    /**
+     *  The server to connect to.
+     */
+    private String server  = null;
+
+    /**
+     *  The tcp port to connect to.
+     */
+    private int port = RExecClient.DEFAULT_PORT;
+
+    /**
+     *  The list of read/write commands for this session
+     */
+    private Vector rexecTasks = new Vector();
+
+    /**
+     *  If true, adds a CR to beginning of login script
+     */
+    private boolean addCarriageReturn = false;
+
+    /**
+     *  Default time allowed for waiting for a valid response
+     *  for all child reads.  A value of 0 means no limit.
+     */
+    private Integer defaultTimeout = null;
+
+    /**
+     *  This class is the parent of the Read and Write tasks.
+     *  It handles the common attributes for both.
+     */
+    public class RExecSubTask {
+        // CheckStyle:VisibilityModifier OFF - bc
+        protected String taskString = "";
+        // CheckStyle:VisibilityModifier ON
+
+        /**
+         * Execute the subtask.
+         * @param rexec the client
+         * @throws BuildException always as it is not allowed to instantiate this object
+         */
+        public void execute(AntRExecClient rexec)
+                throws BuildException {
+            throw new BuildException("Shouldn't be able instantiate a SubTask directly");
+        }
+
+        /**
+         *  the message as nested text
+         * @param s the nested text
+         */
+        public void addText(String s) {
+            setString(getProject().replaceProperties(s));
+        }
+
+        /**
+         * the message as an attribute
+         * @param s a <code>String</code> value
+         */
+        public void setString(String s) {
+           taskString += s;
+        }
+    }
+
+    /**
+     *  Sends text to the connected server
+     */
+    public class RExecWrite extends RExecSubTask {
+        private boolean echoString = true;
+        /**
+         * Execute the write exec task.
+         * @param rexec the task to use
+         * @throws BuildException on error
+         */
+        public void execute(AntRExecClient rexec)
+               throws BuildException {
+           rexec.sendString(taskString, echoString);
+        }
+
+        /**
+         * Whether or not the message should be echoed to the log.
+         * Defaults to <code>true</code>.
+         * @param b a <code>boolean</code> value
+         */
+        public void setEcho(boolean b) {
+           echoString = b;
+        }
+    }
+
+    /**
+     *  Reads the output from the connected server
+     *  until the required string is found or we time out.
+     */
+    public class RExecRead extends RExecSubTask {
+        private Integer timeout = null;
+        /**
+         * Execute the read exec task.
+         * @param rexec the task to use
+         * @throws BuildException on error
+         */
+        public void execute(AntRExecClient rexec)
+               throws BuildException {
+            rexec.waitForString(taskString, timeout);
+        }
+        /**
+         *  a timeout value that overrides any task wide timeout.
+         * @param i an <code>Integer</code> value
+         */
+        public void setTimeout(Integer i) {
+           this.timeout = i;
+        }
+
+        /**
+         * Sets the default timeout if none has been set already
+         * @param defaultTimeout an <code>Integer</code> value
+         * @ant.attribute ignore="true"
+         */
+        public void setDefaultTimeout(Integer defaultTimeout) {
+           if (timeout == null) {
+              timeout = defaultTimeout;
+           }
+        }
+    }
+
+    /**
+     *  This class handles the abstraction of the rexec protocol.
+     *  Currently it is a wrapper around <a
+     *  href="http://jakarta.apache.org/commons/net/index.html">Jakarta
+     *  Commons Net</a>.
+     */
+    public class AntRExecClient extends RExecClient {
+        /**
+         * Read from the rexec session until the string we are
+         * waiting for is found
+         * @param s The string to wait on
+         */
+        public void waitForString(String s) {
+            waitForString(s, null);
+        }
+
+        /**
+         * Read from the rexec session until the string we are
+         * waiting for is found or the timeout has been reached
+         * @param s The string to wait on
+         * @param timeout The maximum number of seconds to wait
+         */
+        public void waitForString(String s, Integer timeout) {
+            InputStream is = this.getInputStream();
+            try {
+                StringBuffer sb = new StringBuffer();
+                if (timeout == null || timeout.intValue() == 0) {
+                    while (sb.toString().indexOf(s) == -1) {
+                        sb.append((char) is.read());
+                    }
+                } else {
+                    Calendar endTime = Calendar.getInstance();
+                    endTime.add(Calendar.SECOND, timeout.intValue());
+                    while (sb.toString().indexOf(s) == -1) {
+                        while (Calendar.getInstance().before(endTime)
+                            && is.available() == 0) {
+                            Thread.sleep(PAUSE_TIME);
+                        }
+                        if (is.available() == 0) {
+                            throw new BuildException(
+                                "Response timed-out waiting for \"" + s + '\"',
+                                getLocation());
+                        }
+                        sb.append((char) is.read());
+                    }
+                }
+                log(sb.toString(), Project.MSG_INFO);
+            } catch (BuildException be) {
+                throw be;
+            } catch (Exception e) {
+                throw new BuildException(e, getLocation());
+            }
+        }
+
+        /**
+         * Write this string to the rexec session.
+         * @param s          the string to write
+         * @param echoString if true log the string sent
+         */
+        public void sendString(String s, boolean echoString) {
+            OutputStream os = this.getOutputStream();
+            try {
+                os.write((s + "\n").getBytes());
+                if (echoString) {
+                    log(s, Project.MSG_INFO);
+                }
+                os.flush();
+            } catch (Exception e) {
+                throw new BuildException(e, getLocation());
+            }
+        }
+        /**
+         * Read from the rexec session until the EOF is found or
+         * the timeout has been reached
+         * @param timeout The maximum number of seconds to wait
+         */
+        public void waitForEOF(Integer timeout) {
+            InputStream is = this.getInputStream();
+            try {
+                StringBuffer sb = new StringBuffer();
+                if (timeout == null || timeout.intValue() == 0) {
+                int read;
+                    while ((read = is.read()) != -1) {
+                        char c = (char) read;
+                        sb.append(c);
+                        if (c == '\n') {
+                        log(sb.toString(), Project.MSG_INFO);
+                        sb.delete(0, sb.length());
+                        }
+                    }
+                } else {
+                    Calendar endTime = Calendar.getInstance();
+                    endTime.add(Calendar.SECOND, timeout.intValue());
+                int read = 0;
+                    while (read != -1) {
+                        while (Calendar.getInstance().before(endTime) && is.available() == 0) {
+                            Thread.sleep(PAUSE_TIME);
+                        }
+                        if (is.available() == 0) {
+                        log(sb.toString(), Project.MSG_INFO);
+                            throw new BuildException(
+                                                     "Response timed-out waiting for EOF",
+                                                     getLocation());
+                        }
+                        read =  is.read();
+                        if (read != -1) {
+                        char c = (char) read;
+                        sb.append(c);
+                        if (c == '\n') {
+                                log(sb.toString(), Project.MSG_INFO);
+                                sb.delete(0, sb.length());
+                        }
+                        }
+                    }
+                }
+                if (sb.length() > 0) {
+                log(sb.toString(), Project.MSG_INFO);
+                }
+            } catch (BuildException be) {
+                throw be;
+            } catch (Exception e) {
+                throw new BuildException(e, getLocation());
+            }
+        }
+
+    }
+    /**
+     *  A string to wait for from the server.
+     *  A subTask &lt;read&gt; tag was found.  Create the object,
+     *  Save it in our list, and return it.
+     * @return a read sub task
+     */
+
+    public RExecSubTask createRead() {
+        RExecSubTask task = (RExecSubTask) new RExecRead();
+        rexecTasks.addElement(task);
+        return task;
+    }
+    /**
+     *  Add text to send to the server
+     *  A subTask &lt;write&gt; tag was found.  Create the object,
+     *  Save it in our list, and return it.
+     * @return a write sub task
+     */
+    public RExecSubTask createWrite() {
+        RExecSubTask task = (RExecSubTask) new RExecWrite();
+        rexecTasks.addElement(task);
+        return task;
+    }
+    /**
+     *  Verify that all parameters are included.
+     *  Connect and possibly login.
+     *  Iterate through the list of Reads and writes.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        /**  A server name is required to continue */
+        if (server == null) {
+            throw new BuildException("No Server Specified");
+        }
+        /**  A userid and password must appear together
+         *   if they appear.  They are not required.
+         */
+        if (userid == null && password != null) {
+            throw new BuildException("No Userid Specified");
+        }
+        if (password == null && userid != null) {
+            throw new BuildException("No Password Specified");
+        }
+
+        /**  Create the telnet client object */
+        AntRExecClient rexec = null;
+        try {
+            rexec = new AntRExecClient();
+            try {
+                rexec.connect(server, port);
+            } catch (IOException e) {
+                throw new BuildException("Can't connect to " + server);
+            }
+            if (userid != null && password != null && command != null
+                && rexecTasks.size() == 0) {
+                // simple one-shot execution
+                rexec.rexec(userid, password, command);
+            } else {
+                // need nested read/write elements
+                handleMultipleTasks(rexec);
+            }
+
+            /** Keep reading input stream until end of it or time-out */
+            rexec.waitForEOF(defaultTimeout);
+        } catch (IOException e) {
+            throw new BuildException("Error r-executing command", e);
+        } finally {
+            if (rexec != null && rexec.isConnected()) {
+                try {
+                    rexec.disconnect();
+                } catch (IOException e) {
+                    throw new BuildException("Error disconnecting from "
+                                             + server);
+                }
+            }
+        }
+    }
+    /**
+     *  Process a 'typical' login.  If it differs, use the read
+     *  and write tasks explicitely
+     */
+    private void login(AntRExecClient rexec) {
+        if (addCarriageReturn) {
+            rexec.sendString("\n", true);
+        }
+        rexec.waitForString("ogin:");
+        rexec.sendString(userid, true);
+        rexec.waitForString("assword:");
+        rexec.sendString(password, false);
+    }
+    /**
+     * Set the the comand to execute on the server;
+     * @param c a <code>String</code> value
+     */
+    public void setCommand(String c) {
+        this.command = c;
+    }
+
+    /**
+     *  send a carriage return after connecting; optional, defaults to false.
+     * @param b a <code>boolean</code> value
+     */
+    public void setInitialCR(boolean b) {
+        this.addCarriageReturn = b;
+    }
+    /**
+     *  Set the the login password to use
+     * required if <tt>userid</tt> is set.
+     * @param p a <code>String</code> value
+     */
+    public void setPassword(String p) {
+        this.password = p;
+    }
+
+    /**
+     *  Set the tcp port to connect to; default is 23.
+     * @param p an <code>int</code> value
+     */
+    public void setPort(int p) {
+        this.port = p;
+    }
+
+    /**
+     *  Set the hostname or address of the remote server.
+     * @param m a <code>String</code> value
+     */
+    public void setServer(String m) {
+        this.server = m;
+    }
+
+    /**
+     * set a default timeout in seconds to wait for a response,
+     * zero means forever (the default)
+     * @param i an <code>Integer</code> value
+     */
+    public void setTimeout(Integer i) {
+        this.defaultTimeout = i;
+    }
+    /**
+     * Set the the login id to use on the server;
+     * required if <tt>password</tt> is set.
+     * @param u a <code>String</code> value
+     */
+    public void setUserid(String u) {
+        this.userid = u;
+    }
+
+    /**
+     * Deals with multiple read/write calls.
+     *
+     * @since Ant 1.6.3
+     */
+    private void handleMultipleTasks(AntRExecClient rexec) {
+
+        /**  Login if userid and password were specified */
+        if (userid != null && password != null) {
+            login(rexec);
+        }
+        /**  Process each sub command */
+        Enumeration tasksToRun = rexecTasks.elements();
+        while (tasksToRun != null && tasksToRun.hasMoreElements()) {
+            RExecSubTask task = (RExecSubTask) tasksToRun.nextElement();
+            if (task instanceof RExecRead && defaultTimeout != null) {
+                ((RExecRead) task).setDefaultTimeout(defaultTimeout);
+            }
+            task.execute(rexec);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java
new file mode 100644
index 0000000..4a0eb53
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/SetProxy.java
@@ -0,0 +1,282 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
+import java.util.Properties;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.ProxySetup;
+
+/**
+ * Sets Java's web proxy properties, so that tasks and code run in
+ * the same JVM can have through-the-firewall access to remote web sites,
+ * and remote ftp sites.
+ * You can nominate an http and ftp proxy, or a socks server, reset the server
+ * settings, or do nothing at all.
+ * <p>
+ * Examples
+ * <pre>&lt;setproxy/&gt;</pre>
+ * do nothing
+ * <pre>&lt;setproxy proxyhost="firewall"/&gt;</pre>
+ * set the proxy to firewall:80
+ * <pre>&lt;setproxy proxyhost="firewall" proxyport="81"/&gt;</pre>
+ * set the proxy to firewall:81
+ * <pre>&lt;setproxy proxyhost=""/&gt;</pre>
+ * stop using the http proxy; don't change the socks settings
+ * <pre>&lt;setproxy socksproxyhost="socksy"/&gt;</pre>
+ * use socks via socksy:1080
+ * <pre>&lt;setproxy socksproxyhost=""/&gt;</pre>
+ * stop using the socks server.
+ * <p>
+ * You can set a username and password for http with the <tt>proxyHost</tt>
+ * and <tt>proxyPassword</tt> attributes. On Java1.4 and above these can also be
+ * used against SOCKS5 servers.
+ * </p>
+ * @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
+ *  java 1.5 network property list</a>
+  *@since       Ant 1.5
+ * @ant.task category="network"
+ */
+public class SetProxy extends Task {
+    private static final int HTTP_PORT = 80;
+    private static final int SOCKS_PORT = 1080;
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * proxy details
+     */
+    protected String proxyHost = null;
+
+    /**
+     * name of proxy port
+     */
+    protected int proxyPort = HTTP_PORT;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * socks host.
+     */
+    private String socksProxyHost = null;
+
+    /**
+     * Socks proxy port. Default is 1080.
+     */
+    private int socksProxyPort = SOCKS_PORT;
+
+
+    /**
+     * list of non proxy hosts
+     */
+    private String nonProxyHosts = null;
+
+    /**
+     * user for http only
+     */
+    private String proxyUser = null;
+
+    /**
+     * password for http only
+     */
+    private String proxyPassword = null;
+
+    /**
+     * the HTTP/ftp proxy host. Set this to "" for the http proxy
+     * option to be disabled
+     *
+     * @param hostname the new proxy hostname
+     */
+    public void setProxyHost(String hostname) {
+        proxyHost = hostname;
+    }
+
+
+    /**
+     * the HTTP/ftp proxy port number; default is 80
+     *
+     * @param port port number of the proxy
+     */
+    public void setProxyPort(int port) {
+        proxyPort = port;
+    }
+
+    /**
+     * The name of a Socks server. Set to "" to turn socks
+     * proxying off.
+     *
+     * @param host The new SocksProxyHost value
+     */
+    public void setSocksProxyHost(String host) {
+        this.socksProxyHost = host;
+    }
+
+
+    /**
+     * Set the ProxyPort for socks connections. The default value is 1080
+     *
+     * @param port The new SocksProxyPort value
+     */
+    public void setSocksProxyPort(int port) {
+        this.socksProxyPort = port;
+    }
+
+
+    /**
+     * A list of hosts to bypass the proxy on. These should be separated
+     * with the vertical bar character '|'. Only in Java 1.4 does ftp use
+     * this list.
+     * e.g. fozbot.corp.sun.com|*.eng.sun.com
+     * @param nonProxyHosts lists of hosts to talk direct to
+     */
+    public void setNonProxyHosts(String nonProxyHosts) {
+        this.nonProxyHosts = nonProxyHosts;
+    }
+
+    /**
+     * set the proxy user. Probably requires a password to accompany this
+     * setting. Default=""
+     * @param proxyUser username
+     * @since Ant1.6
+     */
+    public void setProxyUser(String proxyUser) {
+        this.proxyUser = proxyUser;
+    }
+
+    /**
+     * Set the password for the proxy. Used only if the proxyUser is set.
+     * @param proxyPassword password to go with the username
+     * @since Ant1.6
+     */
+    public void setProxyPassword(String proxyPassword) {
+        this.proxyPassword = proxyPassword;
+    }
+
+    /**
+     * if the proxy port and host settings are not null, then the settings
+     * get applied these settings last beyond the life of the object and
+     * apply to all network connections
+     * Relevant docs: buglist #4183340
+     */
+
+    public void applyWebProxySettings() {
+        boolean settingsChanged = false;
+        boolean enablingProxy = false;
+        Properties sysprops = System.getProperties();
+        if (proxyHost != null) {
+            settingsChanged = true;
+            if (proxyHost.length() != 0) {
+                traceSettingInfo();
+                enablingProxy = true;
+                sysprops.put(ProxySetup.HTTP_PROXY_HOST, proxyHost);
+                String portString = Integer.toString(proxyPort);
+                sysprops.put(ProxySetup.HTTP_PROXY_PORT, portString);
+                sysprops.put(ProxySetup.HTTPS_PROXY_HOST, proxyHost);
+                sysprops.put(ProxySetup.HTTPS_PROXY_PORT, portString);
+                sysprops.put(ProxySetup.FTP_PROXY_HOST, proxyHost);
+                sysprops.put(ProxySetup.FTP_PROXY_PORT, portString);
+                if (nonProxyHosts != null) {
+                    sysprops.put(ProxySetup.HTTP_NON_PROXY_HOSTS, nonProxyHosts);
+                    sysprops.put(ProxySetup.HTTPS_NON_PROXY_HOSTS, nonProxyHosts);
+                    sysprops.put(ProxySetup.FTP_NON_PROXY_HOSTS, nonProxyHosts);
+                }
+                if (proxyUser != null) {
+                    sysprops.put(ProxySetup.HTTP_PROXY_USERNAME, proxyUser);
+                    sysprops.put(ProxySetup.HTTP_PROXY_PASSWORD, proxyPassword);
+                }
+            } else {
+                log("resetting http proxy", Project.MSG_VERBOSE);
+                sysprops.remove(ProxySetup.HTTP_PROXY_HOST);
+                sysprops.remove(ProxySetup.HTTP_PROXY_PORT);
+                sysprops.remove(ProxySetup.HTTP_PROXY_USERNAME);
+                sysprops.remove(ProxySetup.HTTP_PROXY_PASSWORD);
+                sysprops.remove(ProxySetup.HTTPS_PROXY_HOST);
+                sysprops.remove(ProxySetup.HTTPS_PROXY_PORT);
+                sysprops.remove(ProxySetup.FTP_PROXY_HOST);
+                sysprops.remove(ProxySetup.FTP_PROXY_PORT);
+            }
+        }
+
+        //socks
+        if (socksProxyHost != null) {
+            settingsChanged = true;
+            if (socksProxyHost.length() != 0) {
+                enablingProxy = true;
+                sysprops.put(ProxySetup.SOCKS_PROXY_HOST, socksProxyHost);
+                sysprops.put(ProxySetup.SOCKS_PROXY_PORT, Integer.toString(socksProxyPort));
+                if (proxyUser != null) {
+                    //this may be a java1.4 thingy only
+                    sysprops.put(ProxySetup.SOCKS_PROXY_USERNAME, proxyUser);
+                    sysprops.put(ProxySetup.SOCKS_PROXY_PASSWORD, proxyPassword);
+                }
+
+            } else {
+                log("resetting socks proxy", Project.MSG_VERBOSE);
+                sysprops.remove(ProxySetup.SOCKS_PROXY_HOST);
+                sysprops.remove(ProxySetup.SOCKS_PROXY_PORT);
+                sysprops.remove(ProxySetup.SOCKS_PROXY_USERNAME);
+                sysprops.remove(ProxySetup.SOCKS_PROXY_PASSWORD);
+            }
+        }
+
+        if (proxyUser != null) {
+            if (enablingProxy) {
+                Authenticator.setDefault(new ProxyAuth(proxyUser,
+                                                       proxyPassword));
+            } else if (settingsChanged) {
+                Authenticator.setDefault(new ProxyAuth("", ""));
+            }
+        }
+    }
+
+    /**
+     * list out what is going on
+     */
+    private void traceSettingInfo() {
+        log("Setting proxy to "
+                + (proxyHost != null ? proxyHost : "''")
+                + ":" + proxyPort,
+                Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Does the work.
+     *
+     * @exception BuildException thrown in unrecoverable error.
+     */
+    public void execute() throws BuildException {
+        applyWebProxySettings();
+    }
+
+    /**
+     * @since 1.6.3
+     */
+    private static final class ProxyAuth extends Authenticator {
+        private PasswordAuthentication auth;
+
+        private ProxyAuth(String user, String pass) {
+            auth = new PasswordAuthentication(user, pass.toCharArray());
+        }
+
+        protected PasswordAuthentication getPasswordAuthentication() {
+            return auth;
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
new file mode 100644
index 0000000..3dea262
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/net/TelnetTask.java
@@ -0,0 +1,391 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import org.apache.commons.net.telnet.TelnetClient;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Automates the telnet protocol.
+ *
+ */
+
+public class TelnetTask extends Task {
+    private static final int WAIT_INTERVAL = 250;
+    private static final int TELNET_PORT = 23;
+
+    /**
+     *  The userid to login with, if automated login is used
+     */
+    private String userid  = null;
+
+    /**
+     *  The password to login with, if automated login is used
+     */
+    private String password = null;
+
+    /**
+     *  The server to connect to.
+     */
+    private String server  = null;
+
+    /**
+     *  The tcp port to connect to.
+     */
+    private int port = TELNET_PORT;
+
+    /**
+     *  The list of read/write commands for this session
+     */
+    private Vector telnetTasks = new Vector();
+
+    /**
+     *  If true, adds a CR to beginning of login script
+     */
+    private boolean addCarriageReturn = false;
+
+    /**
+     *  Default time allowed for waiting for a valid response
+     *  for all child reads.  A value of 0 means no limit.
+     */
+    private Integer defaultTimeout = null;
+
+    /**
+     *  Verify that all parameters are included.
+     *  Connect and possibly login
+     *  Iterate through the list of Reads and writes
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+       /**  A server name is required to continue */
+       if (server == null) {
+           throw new BuildException("No Server Specified");
+       }
+       /**  A userid and password must appear together
+        *   if they appear.  They are not required.
+        */
+       if (userid == null && password != null) {
+           throw new BuildException("No Userid Specified");
+       }
+       if (password == null && userid != null) {
+           throw new BuildException("No Password Specified");
+       }
+
+       /**  Create the telnet client object */
+       AntTelnetClient telnet = null;
+       try {
+           telnet = new AntTelnetClient();
+           try {
+               telnet.connect(server, port);
+           } catch (IOException e) {
+               throw new BuildException("Can't connect to " + server);
+           }
+           /**  Login if userid and password were specified */
+           if (userid != null && password != null) {
+               login(telnet);
+           }
+           /**  Process each sub command */
+           Enumeration tasksToRun = telnetTasks.elements();
+           while (tasksToRun != null && tasksToRun.hasMoreElements()) {
+               TelnetSubTask task = (TelnetSubTask) tasksToRun.nextElement();
+               if (task instanceof TelnetRead && defaultTimeout != null) {
+                   ((TelnetRead) task).setDefaultTimeout(defaultTimeout);
+               }
+               task.execute(telnet);
+           }
+       } finally {
+           if (telnet != null && telnet.isConnected()) {
+               try {
+                   telnet.disconnect();
+               } catch (IOException e) {
+                   throw new BuildException("Error disconnecting from "
+                                            + server);
+               }
+           }
+       }
+    }
+
+    /**
+     *  Process a 'typical' login.  If it differs, use the read
+     *  and write tasks explicitely
+     */
+    private void login(AntTelnetClient telnet) {
+       if (addCarriageReturn) {
+          telnet.sendString("\n", true);
+       }
+       telnet.waitForString("ogin:");
+       telnet.sendString(userid, true);
+       telnet.waitForString("assword:");
+       telnet.sendString(password, false);
+    }
+
+    /**
+     * Set the the login id to use on the server;
+     * required if <tt>password</tt> is set.
+     * @param u a <code>String</code> value
+     */
+    public void setUserid(String u) {
+        this.userid = u;
+    }
+
+    /**
+     *  Set the the login password to use
+     * required if <tt>userid</tt> is set.
+     * @param p a <code>String</code> value
+     */
+    public void setPassword(String p) {
+        this.password = p;
+    }
+
+    /**
+     *  Set the hostname or address of the remote server.
+     * @param m a <code>String</code> value
+     */
+    public void setServer(String m) {
+        this.server = m;
+    }
+
+    /**
+     *  Set the tcp port to connect to; default is 23.
+     * @param p an <code>int</code> value
+     */
+    public void setPort(int p) {
+        this.port = p;
+    }
+
+    /**
+     *  send a carriage return after connecting; optional, defaults to false.
+     * @param b a <code>boolean</code> value
+     */
+    public void setInitialCR(boolean b) {
+       this.addCarriageReturn = b;
+    }
+
+    /**
+     * set a default timeout in seconds to wait for a response,
+     * zero means forever (the default)
+     * @param i an <code>Integer</code> value
+     */
+    public void setTimeout(Integer i) {
+       this.defaultTimeout = i;
+    }
+
+    /**
+     *  A string to wait for from the server.
+     *  A subTask &lt;read&gt; tag was found.  Create the object,
+     *  Save it in our list, and return it.
+     * @return a read telnet sub task
+     */
+
+    public TelnetSubTask createRead() {
+        TelnetSubTask task = (TelnetSubTask) new TelnetRead();
+        telnetTasks.addElement(task);
+        return task;
+    }
+
+    /**
+     *  Add text to send to the server
+     *  A subTask &lt;write&gt; tag was found.  Create the object,
+     *  Save it in our list, and return it.
+     * @return a write telnet sub task
+     */
+    public TelnetSubTask createWrite() {
+        TelnetSubTask task = (TelnetSubTask) new TelnetWrite();
+        telnetTasks.addElement(task);
+        return task;
+    }
+
+    /**
+     *  This class is the parent of the Read and Write tasks.
+     *  It handles the common attributes for both.
+     */
+    public class TelnetSubTask {
+        // CheckStyle:VisibilityModifier OFF - bc
+        protected String taskString = "";
+        // CheckStyle:VisibilityModifier ON
+        /**
+         * Execute the subtask.
+         * @param telnet the client
+         * @throws BuildException always as it is not allowed to instantiate this object
+         */
+        public void execute(AntTelnetClient telnet)
+                throws BuildException {
+            throw new BuildException("Shouldn't be able instantiate a SubTask directly");
+        }
+
+        /**
+         *  the message as nested text
+         * @param s the nested text
+         */
+        public void addText(String s) {
+            setString(getProject().replaceProperties(s));
+        }
+
+        /**
+         * the message as an attribute
+         * @param s a <code>String</code> value
+         */
+        public void setString(String s) {
+           taskString += s;
+        }
+    }
+
+    /**
+     *  Sends text to the connected server
+     */
+    public class TelnetWrite extends TelnetSubTask {
+        private boolean echoString = true;
+        /**
+         * Execute the write task.
+         * @param telnet the task to use
+         * @throws BuildException on error
+         */
+        public void execute(AntTelnetClient telnet)
+               throws BuildException {
+           telnet.sendString(taskString, echoString);
+        }
+
+        /**
+         * Whether or not the message should be echoed to the log.
+         * Defaults to <code>true</code>.
+         * @param b a <code>boolean</code> value
+         */
+        public void setEcho(boolean b) {
+           echoString = b;
+        }
+    }
+
+    /**
+     *  Reads the output from the connected server
+     *  until the required string is found or we time out.
+     */
+    public class TelnetRead extends TelnetSubTask {
+        private Integer timeout = null;
+        /**
+         * Execute the read task.
+         * @param telnet the task to use
+         * @throws BuildException on error
+         */
+        public void execute(AntTelnetClient telnet)
+               throws BuildException {
+            telnet.waitForString(taskString, timeout);
+        }
+        /**
+         *  a timeout value that overrides any task wide timeout.
+         * @param i an <code>Integer</code> value
+         */
+        public void setTimeout(Integer i) {
+           this.timeout = i;
+        }
+
+        /**
+         * Sets the default timeout if none has been set already
+         * @param defaultTimeout an <code>Integer</code> value
+         * @ant.attribute ignore="true"
+         */
+        public void setDefaultTimeout(Integer defaultTimeout) {
+           if (timeout == null) {
+              timeout = defaultTimeout;
+           }
+        }
+    }
+
+    /**
+     *  This class handles the abstraction of the telnet protocol.
+     *  Currently it is a wrapper around <a
+     *  href="http://jakarta.apache.org/commons/net/index.html">Jakarta
+     *  Commons Net</a>.
+     */
+    public class AntTelnetClient extends TelnetClient {
+        /**
+         * Read from the telnet session until the string we are
+         * waiting for is found
+         * @param s The string to wait on
+         */
+        public void waitForString(String s) {
+            waitForString(s, null);
+        }
+
+        /**
+         * Read from the telnet session until the string we are
+         * waiting for is found or the timeout has been reached
+         * @param s The string to wait on
+         * @param timeout The maximum number of seconds to wait
+         */
+        public void waitForString(String s, Integer timeout) {
+            InputStream is = this.getInputStream();
+            try {
+                StringBuffer sb = new StringBuffer();
+                if (timeout == null || timeout.intValue() == 0) {
+                    while (sb.toString().indexOf(s) == -1) {
+                        sb.append((char) is.read());
+                    }
+                } else {
+                    Calendar endTime = Calendar.getInstance();
+                    endTime.add(Calendar.SECOND, timeout.intValue());
+                    while (sb.toString().indexOf(s) == -1) {
+                        while (Calendar.getInstance().before(endTime)
+                               && is.available() == 0) {
+                            Thread.sleep(WAIT_INTERVAL);
+                        }
+                        if (is.available() == 0) {
+                            log("Read before running into timeout: "
+                                + sb.toString(), Project.MSG_DEBUG);
+                            throw new BuildException(
+                                "Response timed-out waiting for \"" + s + '\"',
+                                getLocation());
+                        }
+                        sb.append((char) is.read());
+                    }
+                }
+                log(sb.toString(), Project.MSG_INFO);
+            } catch (BuildException be) {
+                throw be;
+            } catch (Exception e) {
+                throw new BuildException(e, getLocation());
+            }
+        }
+
+        /**
+         * Write this string to the telnet session.
+         * @param s          the string to write
+         * @param echoString if true log the string sent
+         */
+        public void sendString(String s, boolean echoString) {
+            OutputStream os = this.getOutputStream();
+            try {
+                os.write((s + "\n").getBytes());
+                if (echoString) {
+                    log(s, Project.MSG_INFO);
+                }
+                os.flush();
+            } catch (Exception e) {
+                throw new BuildException(e, getLocation());
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/FStatP4OutputHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/FStatP4OutputHandler.java
new file mode 100644
index 0000000..2d8c0a2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/FStatP4OutputHandler.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.perforce;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.oro.text.perl.Perl5Util;
+
+import java.util.ArrayList;
+
+/**
+ * FStatP4OutputHandler  - spezialied Perforce output handler
+ * able to sort files recognized as managed by Perforce and files not
+ * managed by Perforce in the output
+ *
+ */
+class FStatP4OutputHandler extends P4HandlerAdapter {
+    private P4Fstat parent;
+    private ArrayList existing = new ArrayList();
+    private ArrayList nonExisting = new ArrayList();
+    private static Perl5Util util = new Perl5Util();
+
+    public FStatP4OutputHandler(P4Fstat parent) {
+        this.parent = parent;
+    }
+
+    public void process(String line) throws BuildException {
+        if (util.match("/^... clientFile (.+)$/", line)) {
+            String f = util.group(1);
+            existing.add(f);
+        } else if (util.match("/^(.+) - no such file/", line)) {
+            String f = util.group(1);
+            nonExisting.add(f);
+        }
+        parent.log(parent.util.substitute("s/^.*: //", line),
+                   Project.MSG_VERBOSE);
+    }
+
+    public ArrayList getExisting() {
+        return existing;
+    }
+
+    public ArrayList getNonExisting() {
+        return nonExisting;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Add.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Add.java
new file mode 100644
index 0000000..3b2de82
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Add.java
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Adds specified files to Perforce.
+ *
+ * <b>Example Usage:</b>
+ * <table border="1">
+ * <th>Function</th><th>Command</th>
+ * <tr><td>Add files using P4USER, P4PORT and P4CLIENT settings specified</td>
+ * <td>&lt;P4add <br>P4view="//projects/foo/main/source/..." <br>P4User="fbloggs"
+ * <br>P4Port="km01:1666"
+ * <br>P4Client="fbloggsclient"&gt;<br>&lt;fileset basedir="dir" includes="**&#47;*.java"&gt;<br>
+ * &lt;/p4add&gt;</td></tr>
+ * <tr><td>Add files using P4USER, P4PORT and P4CLIENT settings defined in environment</td><td>
+ * &lt;P4add P4view="//projects/foo/main/source/..." /&gt;<br>&lt;fileset basedir="dir"
+ * includes="**&#47;*.java"&gt;<br>&lt;/p4add&gt;</td></tr>
+ * <tr><td>Specify the length of command line arguments to pass to each invocation of p4</td>
+ * <td>&lt;p4add Commandlength="450"&gt;</td></tr>
+ * </table>
+ *
+ * @ant.task category="scm"
+ */
+public class P4Add extends P4Base {
+    private static final int DEFAULT_CMD_LENGTH = 450;
+    private int changelist;
+    private String addCmd = "";
+    private Vector filesets = new Vector();
+    private int cmdLength = DEFAULT_CMD_LENGTH;
+
+    /**
+     *   Set the maximum length
+     *   of the commandline when calling Perforce to add the files.
+     *   Defaults to 450, higher values mean faster execution,
+     *   but also possible failures.
+     *   @param len maximum length of command line default is 450.
+     *   @throws BuildException if trying to set the command line length to 0 or less.
+     */
+
+    public void setCommandlength(int len) throws BuildException {
+        if (len <= 0) {
+            throw new BuildException("P4Add: Commandlength should be a positive number");
+        }
+        this.cmdLength = len;
+    }
+
+    /**
+     * If specified the open files are associated with the
+     * specified pending changelist number; otherwise the open files are
+     * associated with the default changelist.
+     *
+     * @param changelist the change list number.
+     *
+     * @throws BuildException if trying to set a change list number &lt;=0.
+     */
+    public void setChangelist(int changelist) throws BuildException {
+        if (changelist <= 0) {
+            throw new BuildException("P4Add: Changelist# should be a positive number");
+        }
+        this.changelist = changelist;
+    }
+
+    /**
+     * Add a fileset whose files will be added to Perforce.
+     *
+     * @param set the FileSet that one wants to add to Perforce Source Control.
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Run the task.
+     *
+     * @throws BuildException if the execution of the Perforce command fails.
+     */
+    public void execute() throws BuildException {
+        if (P4View != null) {
+            addCmd = P4View;
+        }
+        P4CmdOpts = (changelist > 0) ? ("-c " + changelist) : "";
+
+        StringBuffer filelist = new StringBuffer();
+
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+
+            String[] srcFiles = ds.getIncludedFiles();
+            if (srcFiles != null) {
+                for (int j = 0; j < srcFiles.length; j++) {
+                    File f = new File(ds.getBasedir(), srcFiles[j]);
+                    filelist.append(" ").append('"').append(f.getAbsolutePath()).append('"');
+                    if (filelist.length() > cmdLength) {
+                        execP4Add(filelist);
+                        filelist = new StringBuffer();
+                    }
+                }
+                if (filelist.length() > 0) {
+                    execP4Add(filelist);
+                }
+            } else {
+                log("No files specified to add!", Project.MSG_WARN);
+            }
+        }
+    }
+
+    private void execP4Add(StringBuffer list) {
+        log("Execing add " + P4CmdOpts + " " + addCmd + list, Project.MSG_INFO);
+        execP4Command("-s add " + P4CmdOpts + " " + addCmd + list, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Base.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Base.java
new file mode 100644
index 0000000..62a7512
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Base.java
@@ -0,0 +1,311 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import java.io.IOException;
+import org.apache.oro.text.perl.Perl5Util;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+
+
+/** Base class for Perforce (P4) ANT tasks. See individual task for example usage.
+ *
+ * @see P4Sync
+ * @see P4Have
+ * @see P4Change
+ * @see P4Edit
+ * @see P4Submit
+ * @see P4Label
+ * @see org.apache.tools.ant.taskdefs.Execute
+ */
+public abstract class P4Base extends org.apache.tools.ant.Task {
+    // CheckStyle:VisibilityModifier OFF - bc
+    // CheckStyle:MemberNameCheck OFF - bc
+    /**Perl5 regexp in Java - cool eh? */
+    protected Perl5Util util = null;
+    /** The OS shell to use (cmd.exe or /bin/sh) */
+    protected String shell;
+
+    //P4 runtime directives
+    /** Perforce Server Port (eg KM01:1666) */
+    protected String P4Port = "";
+    /** Perforce Client (eg myclientspec) */
+    protected String P4Client = "";
+    /** Perforce User (eg fbloggs) */
+    protected String P4User = "";
+    /** Perforce view for commands. (eg //projects/foobar/main/source/... )*/
+    protected String P4View = "";
+
+    // Perforce task directives
+    /** Keep going or fail on error - defaults to fail. */
+    protected boolean failOnError = true;
+
+    //P4 g-opts and cmd opts (rtfm)
+    /** Perforce 'global' opts.
+     * Forms half of low level API */
+    protected String P4Opts = "";
+    /** Perforce command opts.
+     * Forms half of low level API */
+    protected String P4CmdOpts = "";
+
+    /** Set by the task or a handler to indicate that the task has failed.  BuildExceptions
+     * can also be thrown to indicate failure. */
+    private boolean inError = false;
+
+    /** If inError is set, then errorMessage needs to contain the reason why. */
+    private String errorMessage = "";
+
+    // CheckStyle:MemberNameCheck ON
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * gets whether or not the task has encountered an error
+     * @return error flag
+     * @since ant 1.6
+     */
+    public boolean getInError() {
+        return inError;
+    }
+
+    /**
+     * sets the error flag on the task
+     * @param inError if true an error has been encountered by the handler
+     * @since ant 1.6
+     */
+    public void setInError(boolean inError) {
+        this.inError = inError;
+    }
+
+    /**
+     * gets the error message recorded by the Perforce handler
+     * @return error message
+     */
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    /**
+     * sets the error message
+     * @param errorMessage line of error output
+     */
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+    //Setters called by Ant
+
+    /**
+     * The p4d server and port to connect to;
+     * optional, default "perforce:1666"
+     *
+     * @param p4Port the port one wants to set such as localhost:1666
+     */
+    public void setPort(String p4Port) {
+        this.P4Port = "-p" + p4Port;
+    }
+
+    /**
+     * The p4 client spec to use;
+     * optional, defaults to the current user
+     *
+     * @param p4Client the name of the Perforce client spec
+     */
+    public void setClient(String p4Client) {
+        this.P4Client = "-c" + p4Client;
+    }
+
+    /**
+     * The p4 username;
+     * optional, defaults to the current user
+     *
+     * @param p4User the user name
+     */
+    public void setUser(String p4User) {
+        this.P4User = "-u" + p4User;
+    }
+    /**
+     * Set global P4 options; Used on all
+     * of the Perforce tasks.
+     *
+     * @param p4Opts global options, to use a specific P4Config file for instance
+     */
+    public void setGlobalopts(String p4Opts) {
+        this.P4Opts = p4Opts;
+    }
+    /**
+     * The client, branch or label view to operate upon;
+     * optional default "//...".
+     *
+     * the view is required for the following tasks :
+     * <ul>
+     * <li>p4delete</li>
+     * <li>p4edit</li>
+     * <li>p4reopen</li>
+     * <li>p4resolve</li>
+     * </ul>
+     *
+     * @param p4View the view one wants to use
+     */
+    public void setView(String p4View) {
+        this.P4View = p4View;
+    }
+
+    /**
+     * Set extra command options; only used on some
+     * of the Perforce tasks.
+     *
+     * @param p4CmdOpts  command line options going after the particular
+     * Perforce command
+     */
+    public void setCmdopts(String p4CmdOpts) {
+        this.P4CmdOpts = p4CmdOpts;
+    }
+
+    /**
+     * whether to stop the build (true, default)
+     * or keep going if an error is returned from the p4 command
+     * @param fail indicates whether one wants to fail the build if an error comes from the
+     * Perforce command
+     */
+    public void setFailonerror(boolean fail) {
+        failOnError = fail;
+    }
+    /**
+     *  sets attributes Port, Client, User from properties
+     *  if these properties are defined.
+     *  Called automatically by UnknownElement
+     *  @see org.apache.tools.ant.UnknownElement
+     *  <table>
+     *  <tr><th>Property</th><th>Attribute</th></tr>
+     *  <tr><td>p4.port</td><td>Port</td></tr>
+     *  <tr><td>p4.client</td><td>Client</td></tr>
+     *  <tr><td>p4.user</td><td>User</td></tr>
+     *  </table>
+     */
+    public void init() {
+
+        util = new Perl5Util();
+
+        //Get default P4 settings from environment - Mark would have done something cool with
+        //introspection here.....:-)
+        String tmpprop;
+        // CheckStyle:InnerAssignment OFF
+        if ((tmpprop = getProject().getProperty("p4.port")) != null) {
+            setPort(tmpprop);
+        }
+        if ((tmpprop = getProject().getProperty("p4.client")) != null) {
+            setClient(tmpprop);
+        }
+        if ((tmpprop = getProject().getProperty("p4.user")) != null) {
+            setUser(tmpprop);
+        }
+        // CheckStyle:InnerAssignment ON
+    }
+    /**
+    *  no usages found for this method
+    *  runs a Perforce command without a handler
+    * @param command the command that one wants to execute
+    * @throws BuildException if failonerror is set and the command fails
+    */
+    protected void execP4Command(String command) throws BuildException {
+        execP4Command(command, null);
+    }
+
+    /**
+     * Execute P4 command assembled by subclasses.
+     *
+     * @param command The command to run
+     * @param handler A P4Handler to process any input and output
+     *
+     * @throws BuildException if failonerror has been set to true
+     */
+    protected void execP4Command(String command, P4Handler handler) throws BuildException {
+        try {
+            // reset error flags before executing the command
+            inError = false;
+            errorMessage = "";
+            Commandline commandline = new Commandline();
+            commandline.setExecutable("p4");
+
+            //Check API for these - it's how CVS does it...
+            if (P4Port != null && P4Port.length() != 0) {
+                commandline.createArgument().setValue(P4Port);
+            }
+            if (P4User != null && P4User.length() != 0) {
+                commandline.createArgument().setValue(P4User);
+            }
+            if (P4Client != null && P4Client.length() != 0) {
+                commandline.createArgument().setValue(P4Client);
+            }
+            if (P4Opts != null && P4Opts.length() != 0) {
+                commandline.createArgument().setLine(P4Opts);
+            }
+            commandline.createArgument().setLine(command);
+
+            log(commandline.describeCommand(), Project.MSG_VERBOSE);
+
+            if (handler == null) {
+                handler = new SimpleP4OutputHandler(this);
+            }
+
+            Execute exe = new Execute(handler, null);
+
+            exe.setAntRun(getProject());
+
+            exe.setCommandline(commandline.getCommandline());
+
+            try {
+                exe.execute();
+
+                if (inError && failOnError) {
+                    throw new BuildException(errorMessage);
+                }
+            } catch (IOException e) {
+                throw new BuildException(e);
+            } finally {
+                try {
+                    handler.stop();
+                } catch (Exception e) {
+                    log("Error stopping execution framework: " + e.toString(),
+                        Project.MSG_ERR);
+                }
+            }
+
+
+        } catch (Exception e) {
+            String failMsg = "Problem exec'ing P4 command: " + e.getMessage();
+            if (failOnError) {
+                if (e instanceof BuildException) {
+                    throw (BuildException) e;
+                } else {
+                    throw new BuildException(failMsg, e);
+                }
+            } else {
+                log(failMsg, Project.MSG_ERR);
+            }
+
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Change.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Change.java
new file mode 100644
index 0000000..c9cf3ef
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Change.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Requests a new changelist from the Perforce server.
+ * P4Change creates a new changelist in perforce. P4Change sets the property
+ * ${p4.change} with the new changelist number. This should then be passed into
+ * p4edit and p4submit.
+ *
+ *
+ * @see P4Edit
+ * @see P4Submit
+ *
+ * @ant.task category="scm"
+ */
+public class P4Change extends P4Base {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    protected String emptyChangeList = null;
+    protected String description = "AutoSubmit By Ant";
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * creates a new Perforce change list
+     * sets the p4.change property to the number of the new change list
+     * @throws BuildException if the word error appears in the output coming from Perforce
+     */
+    public void execute() throws BuildException {
+
+        if (emptyChangeList == null) {
+            emptyChangeList = getEmptyChangeList();
+        }
+        final Project myProj = getProject();
+
+        P4Handler handler = new P4HandlerAdapter() {
+            public void process(String line) {
+                if (util.match("/Change/", line)) {
+
+                    //Remove any non-numerical chars - should leave the change number
+                    line = util.substitute("s/[^0-9]//g", line);
+
+                    int changenumber = Integer.parseInt(line);
+                    log("Change Number is " + changenumber, Project.MSG_INFO);
+                    myProj.setProperty("p4.change", "" + changenumber);
+
+                } else if (util.match("/error/", line)) {
+                    throw new BuildException("Perforce Error, check client settings and/or server");
+                }
+
+            }
+        };
+
+        handler.setOutput(emptyChangeList);
+
+        execP4Command("change -i", handler);
+    }
+
+    /**
+     * returns the text of an empty change list
+     * @return  the text of an empty change list
+     * @throws BuildException  if the text error is displayed
+     * in the Perforce output outside of a comment line
+     */
+    public String getEmptyChangeList() throws BuildException {
+        final StringBuffer stringbuf = new StringBuffer();
+
+        execP4Command("change -o", new P4HandlerAdapter() {
+            public void process(String line) {
+                if (!util.match("/^#/", line)) {
+                    if (util.match("/error/", line)) {
+                        log("Client Error", Project.MSG_VERBOSE);
+                        throw new BuildException("Perforce Error, "
+                        + "check client settings and/or server");
+                    } else if (util.match("/<enter description here>/", line)) {
+                        // we need to escape the description in case there are /
+                        description = backslash(description);
+                        line = util.substitute("s/<enter description here>/"
+                            + description + "/", line);
+                    } else if (util.match("/\\/\\//", line)) {
+                        //Match "//" for begining of depot filespec
+                        return;
+                    }
+                    stringbuf.append(line);
+                    stringbuf.append("\n");
+                }
+            }
+        });
+        return stringbuf.toString();
+    }
+
+    /**
+     * Ensure that a string is backslashing slashes so that  it does not
+     * confuse them with Perl substitution delimiter in Oro. Backslashes are
+     * always backslashes in a string unless they escape the delimiter.
+     * @param value the string to backslash for slashes
+     * @return the backslashed string
+     * @see <a href="http://jakarta.apache.org/oro/api/org/apache/oro/text/perl/Perl5Util.html
+     * #substitute(java.lang.String,%20java.lang.String)">Oro</a>
+     */
+    public static final String backslash(String value) {
+        final StringBuffer buf = new StringBuffer(value.length());
+        final int len = value.length();
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+            if (c == '/') {
+                buf.append('\\');
+            }
+            buf.append(c);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Description for ChangeList;optional.
+     * If none is specified, it will default to "AutoSubmit By Ant"
+     * @param desc description for the change list
+     */
+    public void setDescription(String desc) {
+        this.description = desc;
+    }
+
+} //EoF
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Counter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Counter.java
new file mode 100644
index 0000000..2fd13f5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Counter.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Obtains or sets the value of a counter.
+ *
+ * <p> When used in its base form
+ * (where only the counter name is provided), the counter value will be
+ * printed to the output stream. When the value is provided, the counter
+ * will be set to the value provided. When a property name is provided,
+ * the property will be filled with the value of the counter. You may
+ * not specify to both get and set the value of the counter in the same
+ * Task.
+ * </p>
+ * <P>
+ * The user performing this task must have Perforce &quot;review&quot; permissions
+ * as defined by Perforce protections in order for this task to succeed.
+</P>
+
+ * Example Usage:<br>
+ * &lt;p4counter name="${p4.counter}" property=${p4.change}"/&gt;
+ *
+ * @ant.task category="scm"
+ */
+
+public class P4Counter extends P4Base {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * name of the counter
+     */
+    public String counter = null;
+    /**
+     * name of an optional property
+     */
+    public String property = null;
+    /**
+     * flag telling whether the value of the counter should be set
+     */
+    public boolean shouldSetValue = false;
+    /**
+     * flag telling whether a property should be set
+     */
+    public boolean shouldSetProperty = false;
+    /**
+     * new value for the counter
+     */
+    public int value = 0;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * The name of the counter; required
+     * @param counter name of the counter
+     */
+    public void setName(String counter) {
+        this.counter = counter;
+    }
+
+    /**
+     * The new value for the counter; optional.
+     * @param value new value for the counter
+     */
+    public void setValue(int value) {
+        this.value = value;
+        shouldSetValue = true;
+    }
+
+    /**
+     * A property to be set with the value of the counter
+     * @param property the name of a property to set with the value
+     * of the counter
+     */
+    public void setProperty(String property) {
+        this.property = property;
+        shouldSetProperty = true;
+    }
+
+    /**
+     * again, properties are mutable in this tsk
+     * @throws BuildException if the required parameters are not supplied.
+     */
+    public void execute() throws BuildException {
+
+        if ((counter == null) || counter.length() == 0) {
+            throw new BuildException("No counter specified to retrieve");
+        }
+
+        if (shouldSetValue && shouldSetProperty) {
+            throw new BuildException("Cannot both set the value of the property and retrieve the "
+                + "value of the property.");
+        }
+
+        String command = "counter " + P4CmdOpts + " " + counter;
+        if (!shouldSetProperty) {
+            // NOTE kirk@radik.com 04-April-2001 -- If you put in the -s, you
+            // have to start running through regular expressions here. Much easier
+            // to just not include the scripting information than to try to add it
+            // and strip it later.
+            command = "-s " + command;
+        }
+        if (shouldSetValue) {
+            command += " " + value;
+        }
+
+        if (shouldSetProperty) {
+            final Project myProj = getProject();
+
+            P4Handler handler = new P4HandlerAdapter() {
+                public void process(String line) {
+                    log("P4Counter retrieved line \"" + line + "\"", Project.MSG_VERBOSE);
+                    try {
+                        value = Integer.parseInt(line);
+                        myProj.setProperty(property, "" + value);
+                    } catch (NumberFormatException nfe) {
+                        throw new BuildException("Perforce error. "
+                        + "Could not retrieve counter value.");
+                    }
+                }
+            };
+
+            execP4Command(command, handler);
+        } else {
+            execP4Command(command, new SimpleP4OutputHandler(this));
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Delete.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Delete.java
new file mode 100644
index 0000000..0631311
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Delete.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/** Checkout files for deletion.
+ *
+ * Example Usage:<br>
+ * &lt;p4delete change="${p4.change}" view="//depot/project/foo.txt" /&gt;<br>
+ *
+ * Simple re-write of P4Edit changing 'edit' to 'delete'.<br>
+ *
+ * @todo What to do if file is already open in one of our changelists perhaps
+ * (See also {@link P4Edit P4Edit})?<br>
+ *
+ * @ant.task category="scm"
+ */
+public class P4Delete extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * number of the change list to work on
+     */
+    public String change = null;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * An existing changelist number for the deletion; optional
+     * but strongly recommended.
+     * @param change the number of a change list
+     */
+    public void setChange(String change) {
+        this.change = change;
+    }
+
+    /**
+     * executes the p4 delete task
+     * @throws BuildException if there is no view specified
+     */
+    public void execute() throws BuildException {
+        if (change != null) {
+            P4CmdOpts = "-c " + change;
+        }
+        if (P4View == null) {
+            throw new BuildException("No view specified to delete");
+        }
+        execP4Command("-s delete " + P4CmdOpts + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Edit.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Edit.java
new file mode 100644
index 0000000..c313311
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Edit.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Open file(s) for edit.
+ * P4Change should be used to obtain a new changelist for P4Edit as,
+ * although P4Edit can open files to the default change,
+ * P4Submit cannot yet submit to it.
+ * Example Usage:<br>
+ * &lt;p4edit change="${p4.change}" view="//depot/project/foo.txt" /&gt;
+ *
+ * @todo Should call reopen if file is already open in one of our changelists perhaps?
+ *
+ * @ant.task category="scm"
+ */
+
+public class P4Edit extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * number of the change list to work on
+     */
+    public String change = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * An existing changelist number to assign files to; optional
+     * but strongly recommended.
+     * @param change the change list number
+     */
+    public void setChange(String change) {
+        this.change = change;
+    }
+
+    /**
+     * Run the p4 edit command
+     * @throws BuildException if there is no view specified
+     */
+    public void execute() throws BuildException {
+        if (change != null) {
+            P4CmdOpts = "-c " + change;
+        }
+        if (P4View == null) {
+            throw new BuildException("No view specified to edit");
+        }
+        execP4Command("-s edit " + P4CmdOpts + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Fstat.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Fstat.java
new file mode 100644
index 0000000..e7fd058
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Fstat.java
@@ -0,0 +1,198 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+
+import java.io.File;
+import java.util.Vector;
+import java.util.ArrayList;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * P4Fstat--find out which files are under Perforce control and which are not.
+ *
+ * <br><b>Example Usage:</b><br>
+ * <pre>
+ * &lt;project name=&quot;p4fstat&quot; default=&quot;p4fstat&quot;
+ * basedir=&quot;C:\dev\gnu&quot;&gt;
+ *     &lt;target name=&quot;p4fstat&quot; &gt;
+ *         &lt;p4fstat showfilter=&quot;all&quot;&gt;
+ *             &lt;fileset dir=&quot;depot&quot; includes=&quot;**\/*&quot;/&gt;
+ *         &lt;/p4fstat&gt;
+ *     &lt;/target&gt;
+ * &lt;/project&gt;
+ * </pre>
+ *
+ * @ant.task category="scm"
+ */
+public class P4Fstat extends P4Base {
+
+    private int changelist;
+    private String addCmd = "";
+    private Vector filesets = new Vector();
+    private static final int DEFAULT_CMD_LENGTH = 300;
+    private int cmdLength = DEFAULT_CMD_LENGTH;
+    private static final int SHOW_ALL = 0;
+    private static final int SHOW_EXISTING = 1;
+    private static final int SHOW_NON_EXISTING = 2;
+    private int show = SHOW_NON_EXISTING;
+    private FStatP4OutputHandler handler;
+    private StringBuffer filelist;
+    private int fileNum = 0;
+    private int doneFileNum = 0;
+    private boolean debug = false;
+
+    private static final String EXISTING_HEADER
+        = "Following files exist in perforce";
+    private static final String NONEXISTING_HEADER
+        = "Following files do not exist in perforce";
+
+    /**
+     * Sets the filter that one wants applied.
+     * <table>
+     * <tr><th>Option</th><th>Meaning</th></tr>
+     * <tr><td>all</td><td>all files under Perforce control or not</td></tr>
+     * <tr><td>existing</td><td>only files under Perforce control</td></tr>
+     * <tr><td>non-existing</td><td>only files not under Perforce control or not</td></tr>
+     * </table>
+     * @param filter should be one of all|existing|non-existing.
+     */
+    public void setShowFilter(String filter) {
+        if (filter.equalsIgnoreCase("all")) {
+            show = SHOW_ALL;
+        } else if (filter.equalsIgnoreCase("existing")) {
+            show = SHOW_EXISTING;
+        } else if (filter.equalsIgnoreCase("non-existing")) {
+            show = SHOW_NON_EXISTING;
+        } else {
+            throw new BuildException("P4Fstat: ShowFilter should be one of: "
+                + "all, existing, non-existing");
+        }
+    }
+
+    /**
+     * Sets optionally a change list number.
+     * @param changelist change list that one wants information about.
+     * @throws BuildException if the change list number is negative.
+     */
+    public void setChangelist(int changelist) throws BuildException {
+        if (changelist <= 0) {
+            throw new BuildException("P4FStat: Changelist# should be a "
+                + "positive number");
+        }
+        this.changelist = changelist;
+    }
+
+    /**
+     * Adds a fileset to be examined by p4fstat.
+     * @param set the fileset to add.
+     */
+    public void addFileset(FileSet set) {
+        filesets.addElement(set);
+    }
+
+    /**
+     * Executes the p4fstat task.
+     * @throws BuildException if no files are specified.
+     */
+    public void execute() throws BuildException {
+        handler = new FStatP4OutputHandler(this);
+        if (P4View != null) {
+            addCmd = P4View;
+        }
+        P4CmdOpts = (changelist > 0) ? ("-c " + changelist) : "";
+
+        filelist = new StringBuffer();
+
+        for (int i = 0; i < filesets.size(); i++) {
+            FileSet fs = (FileSet) filesets.elementAt(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+
+            String[] srcFiles = ds.getIncludedFiles();
+
+            if (srcFiles != null) {
+                fileNum = srcFiles.length;
+                for (int j = 0; j < srcFiles.length; j++) {
+                    File f = new File(ds.getBasedir(), srcFiles[j]);
+                    filelist.append(" ").append('"').append(f.getAbsolutePath()).append('"');
+                    doneFileNum++;
+                    if (filelist.length() > cmdLength) {
+
+                        execP4Fstat(filelist);
+                        filelist = new StringBuffer();
+                    }
+                }
+                if (filelist.length() > 0) {
+                    execP4Fstat(filelist);
+                }
+            } else {
+                log("No files specified to query status on!", Project.MSG_WARN);
+            }
+        }
+        if (show == SHOW_ALL || show == SHOW_EXISTING) {
+            printRes(handler.getExisting(), EXISTING_HEADER);
+        }
+        if (show == SHOW_ALL || show == SHOW_NON_EXISTING) {
+            printRes(handler.getNonExisting(), NONEXISTING_HEADER);
+        }
+    }
+
+    /**
+     * Return the number of files seen.
+     * @return the number of files seen.
+     */
+    public int getLengthOfTask() {
+        return fileNum;
+    }
+
+    /**
+     * Return the number of passes to make.
+     * IS THIS BEING USED?
+     * @return number of passes (how many filesets).
+     */
+    int getPasses() {
+        return filesets.size();
+    }
+
+    private void printRes(ArrayList ar, String header) {
+        log(header, Project.MSG_INFO);
+        for (int i = 0; i < ar.size(); i++) {
+            log((String) ar.get(i), Project.MSG_INFO);
+        }
+    }
+
+    private void execP4Fstat(StringBuffer list) {
+        String l = list.substring(0);
+        if (debug) {
+            log("Executing fstat " + P4CmdOpts + " " + addCmd + l + "\n",
+                Project.MSG_INFO);
+        }
+        execP4Command("fstat " + P4CmdOpts + " " + addCmd + l, handler);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Handler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Handler.java
new file mode 100644
index 0000000..53064a8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Handler.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+
+/** Interface for p4 job output stream handler. Classes implementing this interface
+ * can be called back by P4Base.execP4Command();
+ *
+ */
+public interface P4Handler extends ExecuteStreamHandler {
+
+    /**
+     * processing of one line of stdout or of stderr
+     * @param line a line of stdout or stderr that the implementation will process
+     * @throws BuildException at the discretion of the implementation.
+     */
+    void process(String line) throws BuildException;
+
+    /**
+     * set any data to be written to P4's stdin
+     * @param line the text to write to P4's stdin
+     * @throws BuildException if the line cannot be processed.
+     */
+    void setOutput(String line) throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4HandlerAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4HandlerAdapter.java
new file mode 100644
index 0000000..7ac13c8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4HandlerAdapter.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+/**
+ * base class to manage streams around the execution of the Perforce
+ * command line client
+ */
+public abstract class P4HandlerAdapter  implements P4Handler {
+    // CheckStyle:VisibilityModifier OFF - bc
+    String p4input = "";
+    private PumpStreamHandler myHandler = null;
+    // CheckStyle:VisibilityModifier ON
+    /**
+     *  set any data to be written to P4's stdin
+     *  @param p4Input the text to write to P4's stdin
+     */
+    public void setOutput(String p4Input) {
+        this.p4input = p4Input;
+    }
+    /**
+     * subclasses of P4HandlerAdapter must implement this routine
+     * processing of one line of stdout or of stderr
+     * @param line line of stdout or stderr to process
+     */
+    public abstract void process(String line);
+
+    /**
+     * this routine gets called by the execute routine of the Execute class
+     * it connects the PumpStreamHandler to the input/output/error streams of the process.
+     * @throws BuildException if there is a error.
+     * @see org.apache.tools.ant.taskdefs.Execute#execute
+     */
+    public void start() throws BuildException {
+        if (p4input != null && p4input.length() > 0) {
+            myHandler = new PumpStreamHandler(new P4OutputStream(this), new P4OutputStream(this),
+                new ByteArrayInputStream(p4input.getBytes()));
+        } else {
+            myHandler = new PumpStreamHandler(new P4OutputStream(this), new P4OutputStream(this));
+        }
+        myHandler.setProcessInputStream(os);
+        myHandler.setProcessErrorStream(es);
+        myHandler.setProcessOutputStream(is);
+        myHandler.start();
+    }
+
+    /**
+     * stops the processing of streams
+     * called from P4Base#execP4Command(String command, P4Handler handler)
+     * @see P4Base#execP4Command(String, P4Handler)
+     */
+    public void stop() {
+        if (myHandler != null) {
+            // might never have been started, forfor example ifif p4
+            // is not on the PATH
+            myHandler.stop();
+        }
+    }
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    OutputStream os;    //Input
+    InputStream is;     //Output
+    InputStream es;     //Error
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * connects the handler to the input stream into Perforce
+     * used indirectly by tasks requiring to send specific standard input
+     * such as p4label, p4change
+     * @param os the stream bringing input to the p4 executable
+     * @throws IOException under unknown circumstances
+     */
+    public void setProcessInputStream(OutputStream os) throws IOException {
+        this.os = os;
+    }
+
+    /**
+     * connects the handler to the stderr of the Perforce process
+     * @param is stderr coming from Perforce
+     * @throws IOException under unknown circumstances
+     */
+    public void setProcessErrorStream(InputStream is) throws IOException {
+        this.es = is;
+    }
+
+    /**
+     * connects the handler to the stdout of the Perforce process
+     * @param is stdout coming from Perforce
+     * @throws IOException under unknown circumstances
+     */
+    public void setProcessOutputStream(InputStream is) throws IOException {
+        this.is = is;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Have.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Have.java
new file mode 100644
index 0000000..4776f60
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Have.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+
+/** Lists Perforce files currently on client.
+ *
+ * P4Have simply dumps the current file version info into
+ * the Ant log (or stdout).
+ *
+ * @ant.task category="scm"
+ */
+public class P4Have extends P4Base {
+
+    /**
+     * Execute the Perforce <code>have</code> command.
+     *
+     * @throws BuildException if the command cannot be executed.
+     */
+    public void execute() throws BuildException {
+        execP4Command("have " + P4CmdOpts + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Integrate.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Integrate.java
new file mode 100644
index 0000000..294e839
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Integrate.java
@@ -0,0 +1,318 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Integrate file(s).
+ * P4Change should be used to obtain a new changelist for P4Integrate,
+ * although P4Integrate can open files to the default change,
+ * P4Submit cannot yet submit to it.
+ * Example Usage:<br>
+ * &lt;p4integrate change="${p4.change}"
+ * fromfile="//depot/project/dev/foo.txt" tofile="//depot/project/main/foo.txt" /&gt;
+ *
+ *
+ * @ant.task category="scm"
+ */
+
+public class P4Integrate extends P4Base {
+
+    private String change = null;
+    private String fromfile = null;
+    private String tofile = null;
+    private String branch = null;
+    private boolean restoredeletedrevisions = false;
+    private boolean forceintegrate = false;
+    private boolean leavetargetrevision = false;
+    private boolean enablebaselessmerges = false;
+    private boolean simulationmode = false;
+    private boolean reversebranchmappings = false;
+    private boolean propagatesourcefiletype = false;
+    private boolean nocopynewtargetfiles = false;
+
+    /**
+     * get the changelist number
+     *
+     * @return the changelist number set for this task
+     */
+    public String getChange() {
+        return change;
+    }
+
+    /**
+     * set the changelist number for the operation
+     *
+     * @param change An existing changelist number to assign files to; optional
+     * but strongly recommended.
+     */
+    public void setChange(String change) {
+        this.change = change;
+    }
+
+    /**
+     * get the from file specification
+     *
+     * @return the from file specification
+     */
+    public String getFromfile() {
+        return fromfile;
+    }
+
+    /**
+     * sets the from file specification
+     *
+     * @param fromf the from file specification
+     */
+    public void setFromfile(String fromf) {
+        this.fromfile = fromf;
+    }
+
+    /**
+     * get the to file specification
+     *
+     * @return the to file specification
+     */
+    public String getTofile() {
+        return tofile;
+    }
+
+    /**
+     * sets the to file specification
+     *
+     * @param tof the to file specification
+     */
+    public void setTofile(String tof) {
+        this.tofile = tof;
+    }
+
+    /**
+     * get the branch
+     *
+     * @return the name of the branch
+     */
+    public String getBranch() {
+        return branch;
+    }
+
+    /**
+     * sets the branch
+     *
+     * @param br the name of the branch to use
+     */
+    public void setBranch(String br) {
+        this.branch = br;
+    }
+
+    /**
+     * gets the restoredeletedrevisions flag
+     *
+     * @return restore deleted revisions
+     */
+    public boolean isRestoreDeletedRevisions() {
+        return restoredeletedrevisions;
+    }
+
+    /**
+     * sets the restoredeletedrevisions flag
+     *
+     * @param setrest value chosen for restoredeletedrevisions
+     */
+    public void setRestoreDeletedRevisions(boolean setrest) {
+        this.restoredeletedrevisions = setrest;
+    }
+
+    /**
+     * gets the forceintegrate flag
+     *
+     * @return restore deleted revisions
+     */
+    public boolean isForceIntegrate() {
+        return forceintegrate;
+    }
+
+    /**
+     * sets the forceintegrate flag
+     *
+     * @param setrest value chosen for forceintegrate
+     */
+    public void setForceIntegrate(boolean setrest) {
+        this.forceintegrate = setrest;
+    }
+
+    /**
+     * gets the leavetargetrevision flag
+     *
+     * @return flag indicating if the target revision should be preserved
+     */
+    public boolean isLeaveTargetRevision() {
+        return leavetargetrevision;
+    }
+
+    /**
+     * sets the leavetargetrevision flag
+     *
+     * @param setrest value chosen for leavetargetrevision
+     */
+    public void setLeaveTargetRevision(boolean setrest) {
+        this.leavetargetrevision = setrest;
+    }
+
+    /**
+     * gets the enablebaselessmerges flag
+     *
+     * @return boolean indicating if baseless merges are desired
+     */
+    public boolean isEnableBaselessMerges() {
+        return enablebaselessmerges;
+    }
+
+    /**
+     * sets the enablebaselessmerges flag
+     *
+     * @param setrest value chosen for enablebaselessmerges
+     */
+    public void setEnableBaselessMerges(boolean setrest) {
+        this.enablebaselessmerges = setrest;
+    }
+
+    /**
+     * gets the simulationmode flag
+     *
+     * @return simulation mode flag
+     */
+    public boolean isSimulationMode() {
+        return simulationmode;
+    }
+
+    /**
+     * sets the simulationmode flag
+     *
+     * @param setrest value chosen for simulationmode
+     */
+    public void setSimulationMode(boolean setrest) {
+        this.simulationmode = setrest;
+    }
+    /**
+     * returns the flag indicating if reverse branch mappings are sought
+     *
+     * @return reversebranchmappings flag
+     */
+    public boolean isReversebranchmappings() {
+        return reversebranchmappings;
+    }
+
+    /**
+     *  sets the reversebranchmappings flag
+     *
+     *  @param reversebranchmappings flag indicating if reverse branch mappings are sought
+     */
+    public void setReversebranchmappings(boolean reversebranchmappings) {
+        this.reversebranchmappings = reversebranchmappings;
+    }
+    /**
+     *  returns flag indicating if propagation of source file type is sought
+     *
+     *  @return flag set to true if you want to propagate source file type for existing target files
+     */
+    public boolean isPropagatesourcefiletype() {
+        return propagatesourcefiletype;
+    }
+    /**
+     *   sets flag indicating if one wants to propagate the source file type
+     *
+     *   @param propagatesourcefiletype
+     *   set it to true if you want to change the type of existing target files
+     *   according to type of source file.
+     */
+    public void setPropagatesourcefiletype(boolean propagatesourcefiletype) {
+        this.propagatesourcefiletype = propagatesourcefiletype;
+    }
+    /**
+     *   indicates intention to suppress the copying on the local hard disk of new target files.
+     *
+     *   @return indicates intention to suppress the copying
+     *   on the local hard disk of new target files.
+     */
+    public boolean isNocopynewtargetfiles() {
+        return nocopynewtargetfiles;
+    }
+
+    /**
+     *   sets nocopynewtargetfiles flag
+     *
+     *   @param nocopynewtargetfiles set it to true to gain speed in integration by not copying on
+     *   the local Perforce client new target files
+     */
+    public void setNocopynewtargetfiles(boolean nocopynewtargetfiles) {
+        this.nocopynewtargetfiles = nocopynewtargetfiles;
+    }
+
+    /**
+     *  execute the p4 integrate
+     *  @throws BuildException if there are missing parameters
+     */
+    public void execute() throws BuildException {
+        if (change != null) {
+            P4CmdOpts = "-c " + change;
+        }
+        if (this.forceintegrate) {
+            P4CmdOpts = P4CmdOpts + " -f";
+        }
+        if (this.restoredeletedrevisions) {
+                P4CmdOpts = P4CmdOpts + " -d";
+            }
+        if (this.leavetargetrevision) {
+            P4CmdOpts = P4CmdOpts + " -h";
+        }
+        if (this.enablebaselessmerges) {
+            P4CmdOpts = P4CmdOpts + " -i";
+        }
+        if (this.simulationmode) {
+            P4CmdOpts = P4CmdOpts + " -n";
+        }
+        if (this.reversebranchmappings) {
+            P4CmdOpts = P4CmdOpts + " -r";
+        }
+        if (this.propagatesourcefiletype) {
+            P4CmdOpts = P4CmdOpts + " -t";
+        }
+        if (this.nocopynewtargetfiles) {
+            P4CmdOpts = P4CmdOpts + "-v";
+        }
+        String command;
+        if (branch == null && fromfile != null && tofile != null) {
+           command = P4CmdOpts + " " + fromfile + " " + tofile;
+        } else if (branch != null && fromfile == null && tofile != null) {
+            command = P4CmdOpts + " -b " + branch + " " + tofile;
+        } else if (branch != null && fromfile != null) {
+            command = P4CmdOpts + " -b " + branch + " -s " + fromfile + " " + tofile;
+        } else {
+            throw new BuildException("you need to specify fromfile and tofile, "
+            + "or branch and tofile, or branch and fromfile, or branch and fromfile and tofile ");
+        }
+        execP4Command("-s integrate " + command, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Label.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Label.java
new file mode 100644
index 0000000..0c2edb7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Label.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ *  Creates a new Perforce label and set contents to reflect current
+ *  client file revisions.
+ *
+ *  Label name defaults to AntLabel if none set.
+ *
+ * Example Usage:
+ * <pre>
+ *   &lt;P4Label name="MyLabel-${TSTAMP}-${DSTAMP}" desc="Auto Build Label" /&gt;
+ * </pre>
+ *
+ * @ant.task category="scm"
+ */
+public class P4Label extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String name;
+    protected String desc;
+    protected String lock;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * The name of the label; optional, default "AntLabel"
+     * @param name the name of the label
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     *Label Description; optional
+     * @param desc description of the label
+     */
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+
+    /**
+     * when set to "locked", Perforce will lock the label once created; optional.
+     * @param lock only admissible value "locked"
+     */
+    public void setLock(String lock) {
+        this.lock = lock;
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if failonerror has been set to true and Perforce fails
+     */
+    public void execute() throws BuildException {
+        log("P4Label exec:", Project.MSG_INFO);
+
+        if (P4View == null || P4View.length() < 1) {
+            log("View not set, assuming //depot/...", Project.MSG_WARN);
+            P4View = "//depot/...";
+        } else {
+            P4View = StringUtils.replace(P4View, ":", "\n\t");
+            P4View = StringUtils.replace(P4View, ";", "\n\t");
+        }
+
+        if (desc == null || desc.length() < 1) {
+            log("Label Description not set, assuming 'AntLabel'",
+                Project.MSG_WARN);
+            desc = "AntLabel";
+        }
+
+        if (lock != null && !lock.equalsIgnoreCase("locked")) {
+            log("lock attribute invalid - ignoring", Project.MSG_WARN);
+        }
+
+        if (name == null || name.length() < 1) {
+            SimpleDateFormat formatter
+                = new SimpleDateFormat("yyyy.MM.dd-hh:mm");
+            Date now = new Date();
+            name = "AntLabel-" + formatter.format(now);
+            log("name not set, assuming '" + name + "'", Project.MSG_WARN);
+        }
+
+
+        //We have to create a unlocked label first
+        String newLabel =
+                "Label: " + name
+                + "\nDescription: " + desc
+                + "\nOptions: unlocked"
+                + "\nView: \n\t" + P4View;
+
+        P4Handler handler = new P4HandlerAdapter() {
+            public void process(String line) {
+                log(line, Project.MSG_VERBOSE);
+            }
+        };
+
+        handler.setOutput(newLabel);
+
+        execP4Command("label -i", handler);
+
+        execP4Command("labelsync -l " + name, new P4HandlerAdapter() {
+            public void process(String line) {
+                log(line, Project.MSG_VERBOSE);
+            }
+        });
+
+
+        log("Created Label " + name + " (" + desc + ") with view:\n" + P4View,
+            Project.MSG_INFO);
+
+        //Now lock if required
+        if (lock != null && lock.equalsIgnoreCase("locked")) {
+
+            log("Modifying lock status to 'locked'", Project.MSG_INFO);
+
+            final StringBuffer labelSpec = new StringBuffer();
+
+            //Read back the label spec from perforce,
+            //Replace Options
+            //Submit back to Perforce
+
+            handler = new P4HandlerAdapter() {
+                public void process(String line) {
+                    log(line, Project.MSG_VERBOSE);
+
+                    if (util.match("/^Options:/", line)) {
+                        line = "Options: " + lock;
+                    }
+
+                    labelSpec.append(line + "\n");
+                }
+            };
+
+
+            execP4Command("label -o " + name, handler);
+            log(labelSpec.toString(), Project.MSG_DEBUG);
+
+            log("Now locking label...", Project.MSG_VERBOSE);
+            handler = new P4HandlerAdapter() {
+                public void process(String line) {
+                    log(line, Project.MSG_VERBOSE);
+                }
+            };
+
+            handler.setOutput(labelSpec.toString());
+            execP4Command("label -i", handler);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Labelsync.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Labelsync.java
new file mode 100644
index 0000000..f27c50c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Labelsync.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ *  This method syncs an existing Perforce label against the Perforce client
+ *  or against a set of files/revisions.
+ *
+ *
+ * Example Usage:
+ * <pre>
+ *   &lt;p4labelsync name="MyLabel-${TSTAMP}-${DSTAMP}"
+ *   view="//depot/...#head;//depot2/file1#25" /&gt;
+ * </pre>
+ *
+ * @ant.task category="scm"
+ */
+public class P4Labelsync extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String name;
+    private boolean add; /* -a */
+    private boolean delete; /* -n */
+    private boolean simulationmode;  /* -n */
+    // CheckStyle:VisibilityModifier ON
+    /**
+     * -a flag of p4 labelsync - preserve files which exist in the label,
+     * but not in the current view
+     * @return  add attribute
+     * if set to true the task will not remove any files from the label
+     * only add files which were not there previously or update these where the revision has changed
+     * the add attribute is the -a flag of p4 labelsync
+     */
+    public boolean isAdd() {
+        return add;
+    }
+    /**
+     * -a flag of p4 labelsync - preserve files which exist in the label,
+     * but not in the current view
+     * @param add  if set to true the task will not remove any files from the label
+     * only add files which were not there previously or update these where the revision has changed
+     * the add attribute is the -a flag of p4 labelsync
+     */
+    public void setAdd(boolean add) {
+        this.add = add;
+    }
+    /**
+     * -d flag of p4 labelsync; indicates an intention of deleting from the label
+     * the files specified in the view
+     * @return  delete attribute
+     */
+    public boolean isDelete() {
+        return delete;
+    }
+
+    /**
+     * -d flag of p4 labelsync; indicates an intention of deleting from the label
+     *  the files specified in the view
+     * @param delete indicates intention of deleting from the label
+     * the files specified in the view
+     */
+    public void setDelete(boolean delete) {
+        this.delete = delete;
+    }
+
+
+    /**
+     * The name of the label; optional, default "AntLabel"
+     * @param name of the label
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+    /**
+     * -n flag of p4 labelsync - display changes without actually doing them
+     * @return -n flag of p4 labelsync
+     */
+    public boolean isSimulationmode() {
+        return simulationmode;
+    }
+    /**
+     * -n flag of p4 labelsync - display changes without actually doing them
+     * @param simulationmode display changes without actually doing them
+     */
+    public void setSimulationmode(boolean simulationmode) {
+        this.simulationmode = simulationmode;
+    }
+
+
+    /**
+     *  do the work
+     * @throws BuildException if the label name is not supplied
+     */
+    public void execute() throws BuildException {
+        log("P4Labelsync exec:", Project.MSG_INFO);
+
+        if (P4View != null && P4View.length() >= 1) {
+            P4View = StringUtils.replace(P4View, ":", "\n\t");
+            P4View = StringUtils.replace(P4View, ";", "\n\t");
+        }
+        if (P4View == null) {
+            P4View = "";
+        }
+
+        if (name == null || name.length() < 1) {
+            throw new BuildException("name attribute is compulsory for labelsync");
+        }
+
+        if (this.isSimulationmode()) {
+            P4CmdOpts = P4CmdOpts + " -n";
+        }
+        if (this.isDelete()) {
+            P4CmdOpts = P4CmdOpts + " -d";
+        }
+        if (this.isAdd()) {
+            P4CmdOpts = P4CmdOpts + " -a";
+        }
+
+        execP4Command("-s labelsync -l " + name + " " + P4CmdOpts + " " + P4View,
+            new SimpleP4OutputHandler(this));
+
+
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputHandler.java
new file mode 100644
index 0000000..f782f73
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputHandler.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/** Interface for p4 job output stream handler. Classes implementing this interface
+ * can be called back by P4Base.execP4Command();
+ *
+ */
+public interface P4OutputHandler {
+    /**
+     * implementations will be able to process lines of output from Perforce
+     * @param line a line of stdout or stderr coming from Perforce
+     * @throws BuildException implementations are allowed to throw BuildException
+     */
+    void process(String line) throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputStream.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputStream.java
new file mode 100644
index 0000000..93c22bd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4OutputStream.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * heavily inspired from LogOutputStream
+ * this stream class calls back the P4Handler on each line of stdout or stderr read
+ */
+public class P4OutputStream extends OutputStream {
+    private P4Handler handler;
+    private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+    private boolean skip = false;
+
+    /**
+     * creates a new P4OutputStream for a P4Handler
+     * @param handler   the handler which will process the streams
+     */
+    public P4OutputStream(P4Handler handler) {
+        this.handler = handler;
+    }
+
+    /**
+     * Write the data to the buffer and flush the buffer, if a line
+     * separator is detected.
+     *
+     * @param cc data to log (byte).
+     * @throws IOException IOException  if an I/O error occurs. In particular,
+     *             an <code>IOException</code> may be thrown if the
+     *             output stream has been closed.
+     */
+    public void write(int cc) throws IOException {
+        final byte c = (byte) cc;
+        if ((c == '\n') || (c == '\r')) {
+            if (!skip) {
+                processBuffer();
+            }
+        } else {
+            buffer.write(cc);
+        }
+        skip = (c == '\r');
+    }
+
+
+    /**
+     * Converts the buffer to a string and sends it to <code>processLine</code>
+     */
+    protected void processBuffer() {
+        handler.process(buffer.toString());
+        buffer.reset();
+    }
+
+    /**
+     * Writes all remaining
+     * @throws IOException if an I/O error occurs.
+     */
+    public void close() throws IOException {
+        if (buffer.size() > 0) {
+            processBuffer();
+        }
+        super.close();
+    }
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Reopen.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Reopen.java
new file mode 100644
index 0000000..642bf07
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Reopen.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Reopen Perforce checkout files between changelists.
+ *
+ * @ant.task category="scm"
+ */
+public class P4Reopen extends P4Base {
+
+    private String toChange = "";
+
+    /**
+     * The changelist to move files to; required.
+     * @param toChange new change list number
+     * @throws BuildException if the change parameter is null or empty
+     */
+    public void setToChange(String toChange) throws BuildException {
+        if (toChange == null || toChange.equals("")) {
+            throw new BuildException("P4Reopen: tochange cannot be null or empty");
+        }
+
+        this.toChange = toChange;
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if P4View is null
+     */
+    public void execute() throws BuildException {
+        if (P4View == null) {
+            throw new BuildException("No view specified to reopen");
+        }
+        execP4Command("-s reopen -c " + toChange + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Resolve.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Resolve.java
new file mode 100644
index 0000000..39cc81e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Resolve.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+* Portions of this software are based upon public domain software
+* originally written at the National Center for Supercomputing Applications,
+* University of Illinois, Urbana-Champaign.
+*/
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * @ant.task category="scm"
+ */
+public class P4Resolve extends P4Base {
+    private String resolvemode = null;
+
+
+    private boolean redoall; /* -f */
+    private boolean simulationmode;  /* -n */
+    private boolean forcetextmode;  /* -t */
+    private boolean markersforall; /* -v */
+    private static final String AUTOMATIC = "automatic";
+    private static final String FORCE = "force";
+    private static final String SAFE = "safe";
+    private static final String THEIRS = "theirs";
+    private static final String YOURS = "yours";
+    private static final String[] RESOLVE_MODES = {
+        AUTOMATIC,
+        FORCE,
+        SAFE,
+        THEIRS,
+        YOURS
+    };
+   /**
+    * returns the resolve mode
+    * @return  returns the resolve mode
+    */
+    public String getResolvemode() {
+        return resolvemode;
+    }
+    /**
+     * values for resolvemode
+     * <ul>
+     * <li> automatic -am</li>
+     * <li> force -af </li>
+     * <li> safe -as </li>
+     * <li> theirs -at </li>
+     * <li> yours -ay </li>
+     * </ul>
+     * @param resolvemode one of automatic, force, safe, theirs, yours
+     */
+    public void setResolvemode(String resolvemode) {
+        boolean found = false;
+        for (int counter = 0; counter < RESOLVE_MODES.length; counter++) {
+            if (resolvemode.equals(RESOLVE_MODES[counter])) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            throw new BuildException("Unacceptable value for resolve mode");
+        }
+        this.resolvemode = resolvemode;
+    }
+
+    /**
+     * allows previously resolved files to be resolved again
+     * @return flag indicating whether one wants to
+     * allow previously resolved files to be resolved again
+     */
+    public boolean isRedoall() {
+        return redoall;
+    }
+
+    /**
+     * set the redoall flag
+     * @param redoall flag indicating whether one want to
+     * allow previously resolved files to be resolved again
+     */
+    public void setRedoall(boolean redoall) {
+        this.redoall = redoall;
+    }
+
+    /**
+     * read the simulation mode flag
+     * @return flag indicating whether one wants just to simulate
+     * the p4 resolve operation whithout actually doing it
+     */
+    public boolean isSimulationmode() {
+        return simulationmode;
+    }
+
+    /**
+     * sets a flag
+     * @param simulationmode set to true, lists the integrations which would be performed,
+     * without actually doing them.
+     */
+    public void setSimulationmode(boolean simulationmode) {
+        this.simulationmode = simulationmode;
+    }
+
+    /**
+     * If set to true, attempts a textual merge, even for binary files
+     * @return flag value
+     */
+    public boolean isForcetextmode() {
+        return forcetextmode;
+    }
+
+    /**
+     * If set to true, attempts a textual merge, even for binary files
+     * @param forcetextmode set the flag value
+     */
+    public void setForcetextmode(boolean forcetextmode) {
+        this.forcetextmode = forcetextmode;
+    }
+
+    /**
+     * If set to true, puts in markers for all changes, conflicting or not
+     * @return  flag markersforall value
+     */
+    public boolean isMarkersforall() {
+        return markersforall;
+    }
+
+    /**
+      * If set to true, puts in markers for all changes, conflicting or not
+     * @param markersforall flag true or false
+     */
+    public void setMarkersforall(boolean markersforall) {
+        this.markersforall = markersforall;
+    }
+
+    /**
+     *  execute the p4 resolve
+     * @throws BuildException if there is a wrong resolve mode specified
+     *  or no view specified
+     */
+    public void execute() throws BuildException {
+        if (this.resolvemode.equals(AUTOMATIC)) {
+            P4CmdOpts = P4CmdOpts + " -am";
+        } else if (this.resolvemode.equals(FORCE)) {
+            P4CmdOpts = P4CmdOpts + " -af";
+        } else if (this.resolvemode.equals(SAFE)) {
+            P4CmdOpts = P4CmdOpts + " -as";
+        } else if (this.resolvemode.equals(THEIRS)) {
+            P4CmdOpts = P4CmdOpts + " -at";
+        } else if (this.resolvemode.equals(YOURS)) {
+            P4CmdOpts = P4CmdOpts + " -ay";
+        } else {
+            throw new BuildException("unsupported or absent resolve mode");
+        }
+        if (P4View == null) {
+            throw new BuildException("please specify a view");
+        }
+        if (this.isRedoall()) {
+            P4CmdOpts = P4CmdOpts + " -f";
+        }
+        if (this.isSimulationmode()) {
+            P4CmdOpts = P4CmdOpts + " -n";
+        }
+        if (this.isForcetextmode()) {
+            P4CmdOpts = P4CmdOpts + " -t";
+        }
+        if (this.isMarkersforall()) {
+            P4CmdOpts = P4CmdOpts + " -v";
+        }
+        execP4Command("-s resolve " + P4CmdOpts + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Revert.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Revert.java
new file mode 100644
index 0000000..2beb893
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Revert.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Revert Perforce open files or files in a changelist
+ *
+ * @ant.task category="scm"
+ */
+public class P4Revert extends P4Base {
+
+    private String revertChange = null;
+    private boolean onlyUnchanged = false;
+
+    /**
+     * The changelist to revert; optional.
+     * @param revertChange : the change list to revert
+     * @throws BuildException if the change list is null or empty string
+     */
+    public void setChange(String revertChange) throws BuildException {
+        if (revertChange == null || revertChange.equals("")) {
+            throw new BuildException("P4Revert: change cannot be null or empty");
+        }
+
+        this.revertChange = revertChange;
+
+    }
+
+    /**
+     * flag to revert only unchanged files (p4 revert -a); optional, default false.
+     * @param onlyUnchanged if set to true revert only unchanged files
+     */
+    public void setRevertOnlyUnchanged(boolean onlyUnchanged) {
+        this.onlyUnchanged = onlyUnchanged;
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if an error occurs during the execution of the Perforce command
+     * and failonError is set to true
+     */
+    public void execute() throws BuildException {
+
+        /* Here we can either revert any unchanged files in a changelist
+         * or
+         * any files regardless of whether they have been changed or not
+         *
+         *
+         * The whole process also accepts a p4 filespec
+         */
+        String p4cmd = "-s revert";
+        if (onlyUnchanged) {
+            p4cmd += " -a";
+        }
+
+        if (revertChange != null) {
+            p4cmd += " -c " + revertChange;
+        }
+
+        execP4Command(p4cmd + " " + P4View, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Submit.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Submit.java
new file mode 100644
index 0000000..763883c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Submit.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import java.util.Vector;
+
+/** Submits a numbered changelist to Perforce.
+ *
+ * <B>Note:</B> P4Submit cannot (yet) submit the default changelist.
+ * This shouldn't be a problem with the ANT task as the usual flow is
+ * P4Change to create a new numbered change followed by P4Edit then P4Submit.
+ *
+ * Example Usage:-<br>
+ * &lt;p4submit change="${p4.change}" /&gt;
+ *
+ * @ant.task category="scm"
+ */
+public class P4Submit extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    //ToDo: If dealing with default cl need to parse out <enter description here>
+    /**
+     * change list number
+     */
+    public String change;
+    // CheckStyle:VisibilityModifier ON
+    /**
+     * change property
+     */
+    private String changeProperty;
+    /**
+     * needsresolveproperty
+     */
+    private String needsResolveProperty;
+    /**
+     * set the change list number to submit
+     * @param change The changelist number to submit; required.
+     */
+    public void setChange(String change) {
+        this.change = change;
+    }
+    /**
+     * property defining the change number if the change number gets renumbered
+     * @param changeProperty name of a new property to which the change number
+     * will be assigned if it changes
+     * @since ant 1.6.1
+     */
+    public void setChangeProperty(String changeProperty) {
+        this.changeProperty = changeProperty;
+    }
+    /**
+     * property defining the need to resolve the change list
+     * @param needsResolveProperty a property which will be set if the change needs resolve
+     * @since ant 1.6.1
+     */
+    public void setNeedsResolveProperty(String needsResolveProperty) {
+        this.needsResolveProperty = needsResolveProperty;
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if no change list specified
+     */
+    public void execute() throws BuildException {
+        if (change != null) {
+            execP4Command("submit -c " + change, (P4HandlerAdapter) new P4SubmitAdapter(this));
+        } else {
+            //here we'd parse the output from change -o into submit -i
+            //in order to support default change.
+            throw new BuildException("No change specified (no support for default change yet....");
+        }
+    }
+
+    /**
+     * internal class used to process the output of p4 submit
+     */
+    public class P4SubmitAdapter extends SimpleP4OutputHandler {
+        /**
+         * Constructor.
+         * @param parent a P4Base instance.
+         */
+        public P4SubmitAdapter(P4Base parent) {
+            super(parent);
+        }
+        /**
+         * process a line of stdout/stderr coming from Perforce
+         * @param line line of stdout or stderr coming from Perforce
+         */
+        public void process(String line) {
+            super.process(line);
+            getProject().setProperty("p4.needsresolve", "0");
+            // this type of output might happen
+            // Change 18 renamed change 20 and submitted.
+            if (util.match("/renamed/", line)) {
+                try {
+                    Vector myarray = new Vector();
+                    util.split(myarray, line);
+                    boolean found = false;
+                    for (int counter = 0; counter < myarray.size(); counter++) {
+                        if (found) {
+                            String chnum = (String) myarray.elementAt(counter + 1);
+                            int changenumber = Integer.parseInt(chnum);
+                            log("Perforce change renamed " + changenumber, Project.MSG_INFO);
+                            getProject().setProperty("p4.change", "" + changenumber);
+                            if (changeProperty != null) {
+                                getProject().setNewProperty(changeProperty, chnum);
+                            }
+                            found = false;
+                        }
+                        if (((myarray.elementAt(counter))).equals("renamed")) {
+                            found = true;
+                        }
+                    }
+                // NumberFormatException or ArrayOutOfBondsException could happen here
+                } catch (Exception e) {
+                    String msg = "Failed to parse " + line  + "\n"
+                            + " due to " + e.getMessage();
+                    throw new BuildException(msg, e, getLocation());
+                }
+            }
+            if (util.match("/p4 submit -c/", line)) {
+                getProject().setProperty("p4.needsresolve", "1");
+                if (needsResolveProperty != null) {
+                    getProject().setNewProperty(needsResolveProperty, "true");
+                }
+            }
+
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Sync.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Sync.java
new file mode 100644
index 0000000..e32966c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/P4Sync.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/** Synchronize client space to a Perforce depot view.
+ *
+ *  The API allows additional functionality of the "p4 sync" command
+ * (such as "p4 sync -f //...#have" or other exotic invocations).</P>
+ *
+ * <b>Example Usage:</b>
+ * <table border="1">
+ * <th>Function</th><th>Command</th>
+ * <tr><td>Sync to head using P4USER, P4PORT and P4CLIENT settings specified</td>
+ * <td>&lt;P4Sync <br>P4view="//projects/foo/main/source/..." <br>
+ * P4User="fbloggs" <br>P4Port="km01:1666" <br>P4Client="fbloggsclient" /&gt;</td></tr>
+ * <tr><td>Sync to head using P4USER, P4PORT and P4CLIENT settings defined in environment</td>
+ * <td>&lt;P4Sync P4view="//projects/foo/main/source/..." /&gt;</td></tr>
+ * <tr><td>Force a re-sync to head, refreshing all files</td>
+ * <td>&lt;P4Sync force="yes" P4view="//projects/foo/main/source/..." /&gt;</td></tr>
+ * <tr><td>Sync to a label</td><td>&lt;P4Sync label="myPerforceLabel" /&gt;</td></tr>
+ * </table>
+ *
+ * @todo Add decent label error handling for non-exsitant labels
+ *
+ * @ant.task category="scm"
+ */
+public class P4Sync extends P4Base {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    String label;
+    private String syncCmd = "";
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Label to sync client to; optional.
+     * @param label name of a label against which one want to sync
+     * @throws BuildException if label is null or empty string
+     */
+    public void setLabel(String label) throws BuildException {
+        if (label == null || label.equals("")) {
+            throw new BuildException("P4Sync: Labels cannot be Null or Empty");
+        }
+
+        this.label = label;
+
+    }
+
+
+    /**
+     * force a refresh of files, if this attribute is set; false by default.
+     * @param force sync all files, whether they are supposed to be already uptodate or not.
+     * @throws BuildException if a label is set and force is null
+     */
+    public void setForce(String force) throws BuildException {
+        if (force == null && !label.equals("")) {
+            throw new BuildException("P4Sync: If you want to force, set force to non-null string!");
+        }
+        P4CmdOpts = "-f";
+    }
+
+    /**
+     * do the work
+     * @throws BuildException if an error occurs during the execution of the Perforce command
+     * and failOnError is set to true
+     */
+    public void execute() throws BuildException {
+
+
+        if (P4View != null) {
+            syncCmd = P4View;
+        }
+
+
+        if (label != null && !label.equals("")) {
+            syncCmd = syncCmd + "@" + label;
+        }
+
+
+        log("Execing sync " + P4CmdOpts + " " + syncCmd, Project.MSG_VERBOSE);
+
+        execP4Command("-s sync " + P4CmdOpts + " " + syncCmd, new SimpleP4OutputHandler(this));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/SimpleP4OutputHandler.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/SimpleP4OutputHandler.java
new file mode 100644
index 0000000..3e5a3cd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/SimpleP4OutputHandler.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/*
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * simple implementation of P4HandlerAdapter used by tasks which are not
+ * actually processing the output from Perforce
+ */
+public class SimpleP4OutputHandler extends P4HandlerAdapter {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    P4Base parent;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * simple constructor
+     * @param parent  a P4Base instance
+     */
+    public SimpleP4OutputHandler(P4Base parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * process one line of stderr/stdout
+     * if error conditions are detected, then setters are called on the
+     * parent
+     * @param line line of output
+     * @throws BuildException does not throw exceptions any more
+     */
+    public void process(String line) throws BuildException {
+        if (parent.util.match("/^exit/", line)) {
+            return;
+        }
+
+        //Throw exception on errors (except up-to-date)
+        //
+        //When a server is down, the code expects :
+        //Perforce client error:
+        //Connect to server failed; check $P4PORT.
+        //TCP connect to localhost:1666 failed.
+        //connect: localhost:1666: Connection refused
+        //Some forms producing commands (p4 -s change -o) do tag the output
+        //others don't.....
+        //Others mark errors as info, for example edit a file
+        //which is already open for edit.....
+        //Just look for error: - catches most things....
+
+        if (parent.util.match("/^error:/", line)
+            || parent.util.match("/^Perforce client error:/", line)) {
+            //when running labelsync, if view elements are in sync,
+            //Perforce produces a line of output
+            //looking like this one :
+            //error: //depot/file2 - label in sync.
+            if (!parent.util.match("/label in sync/", line)
+                && !parent.util.match("/up-to-date/", line)) {
+                parent.setInError(true);
+            } else {
+                //sync says "error:" when a file is up-to-date
+                line = parent.util.substitute("s/^[^:]*: //", line);
+            }
+        } else if (parent.util.match("/^info.*?:/", line)) {
+            //sometimes there's "info1:
+            line = parent.util.substitute("s/^[^:]*: //", line);
+        }
+        parent.log(line, parent.getInError() ? Project.MSG_ERR : Project.MSG_INFO);
+
+        if (parent.getInError()) {
+            parent.setErrorMessage(parent.getErrorMessage() + line + StringUtils.LINE_SEP);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/package.html b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/package.html
new file mode 100644
index 0000000..49dd917
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/perforce/package.html
@@ -0,0 +1,40 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<body>
+ANT Tasks for Perforce integration.
+
+These tasks provide basic P4 capabilities to automated ANT-based build systems. <b>Note:</b>
+the tasks in this package are linked against the Jakarta ORO 2.0 library which
+brings the power of Perl 5 regular expressions to Java.
+
+These tasks also require you to have the p4 (or p4.exe) client in your path.
+
+@see <A HREF="http://ant.apache.org/">Ant Project</A>
+@see <A HREF="http://www.perforce.com/">Perforce</A>
+
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Sync
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Label
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Have
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Change
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Edit
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Submit
+@see org.apache.tools.ant.taskdefs.optional.perforce.P4Counter
+
+
+
+@author <A HREF="mailto:leslie.hughes@rubus.com">Les Hughes</A>
+</body>
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java
new file mode 100644
index 0000000..e3cae4d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/Pvcs.java
@@ -0,0 +1,679 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.pvcs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.util.Enumeration;
+import java.util.Random;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.taskdefs.PumpStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ *
+ * Extracts the latest edition of the source code from a PVCS repository.
+ * PVCS is a version control system
+ * developed by <a href="http://www.merant.com/products/pvcs">Merant</a>.
+ * <br>
+ * Before using this tag, the user running ant must have access to the commands
+ * of PVCS (get and pcli) and must have access to the repository. Note that the way to specify
+ * the repository is platform dependent so use property to specify location of repository.
+ * <br>
+ * This version has been tested agains PVCS version 6.5 and 6.6 under Windows and Solaris.
+
+ *
+ * <b>19-04-2001</b> <p>The task now has a more robust
+ * parser. It allows for platform independant file paths
+ * and supports file names with <i>()</i>. Thanks to Erik Husby for
+ * bringing the bug to my attention.
+ *
+ * <b>27-04-2001</b> <p>UNC paths are now handled properly.
+ * Fix provided by Don Jeffery. He also added an <i>UpdateOnly</i> flag
+ * that, when true, conditions the PVCS get using the -U option to only
+ * update those files that have a modification time (in PVCS) that is newer
+ * than the existing workfile.
+ *
+ * <b>25-10-2002</b> <p>Added a revision attribute that currently is a
+ * synonym for label, but in a future release the behavior of the label
+ * attribute will change to use the -v option of GET.  See bug #13847 for
+ * discussion.
+ *
+ */
+public class Pvcs extends org.apache.tools.ant.Task {
+    // CheckStyle - magic numbers
+    // checking for "X:\ 0=dquote,1=letter,2=:,3=\
+    private static final int POS_1 = 1;
+    private static final int POS_2 = 2;
+    private static final int POS_3 = 3;
+
+    private String pvcsbin;
+    private String repository;
+    private String pvcsProject;
+    private Vector pvcsProjects;
+    private String workspace;
+    private String force;
+    private String promotiongroup;
+    private String label;
+    private String revision;
+    private boolean ignorerc;
+    private boolean updateOnly;
+    private String filenameFormat;
+    private String lineStart;
+    private String userId;
+    private String config;
+    /**
+     * Constant for the thing to execute
+     */
+    private static final String PCLI_EXE = "pcli";
+
+    /*
+     * Constant for the PCLI listversionedfiles recursive i a format "get" understands
+     */
+    // private static final String PCLI_LVF_ARGS = "lvf -z -aw";
+
+    /**
+     * Constant for the thing to execute
+     */
+    private static final String GET_EXE = "get";
+
+
+    /**
+     * Run the command.
+     * @param cmd the command line to use.
+     * @param out the output stream handler to use.
+     * @return the exit code of the command.
+     */
+    protected int runCmd(Commandline cmd, ExecuteStreamHandler out) {
+        try {
+            Project aProj = getProject();
+            Execute exe = new Execute(out);
+            exe.setAntRun(aProj);
+            exe.setWorkingDirectory(aProj.getBaseDir());
+            exe.setCommandline(cmd.getCommandline());
+            return exe.execute();
+        } catch (java.io.IOException e) {
+            String msg = "Failed executing: " + cmd.toString()
+                + ". Exception: " + e.getMessage();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    private String getExecutable(String exe) {
+        StringBuffer correctedExe = new StringBuffer();
+        if (getPvcsbin() != null) {
+            if (pvcsbin.endsWith(File.separator)) {
+                correctedExe.append(pvcsbin);
+            } else {
+                correctedExe.append(pvcsbin).append(File.separator);
+            }
+        }
+        return correctedExe.append(exe).toString();
+    }
+
+    /**
+     * @exception org.apache.tools.ant.BuildException Something is stopping the build...
+     */
+    public void execute() throws org.apache.tools.ant.BuildException {
+        int result = 0;
+
+        if (repository == null || repository.trim().equals("")) {
+            throw new BuildException("Required argument repository not specified");
+        }
+
+        // Check workspace exists
+        // Launch PCLI listversionedfiles -z -aw
+        // Capture output
+        // build the command line from what we got the format is
+        Commandline commandLine = new Commandline();
+        commandLine.setExecutable(getExecutable(PCLI_EXE));
+
+        commandLine.createArgument().setValue("lvf");
+        commandLine.createArgument().setValue("-z");
+        commandLine.createArgument().setValue("-aw");
+        if (getWorkspace() != null) {
+            commandLine.createArgument().setValue("-sp" + getWorkspace());
+        }
+        commandLine.createArgument().setValue("-pr" + getRepository());
+
+        String uid = getUserId();
+
+        if (uid != null) {
+            commandLine.createArgument().setValue("-id" + uid);
+        }
+
+        // default pvcs project is "/"
+        if (getPvcsproject() == null && getPvcsprojects().isEmpty()) {
+            pvcsProject = "/";
+        }
+
+        if (getPvcsproject() != null) {
+            commandLine.createArgument().setValue(getPvcsproject());
+        }
+        if (!getPvcsprojects().isEmpty()) {
+            Enumeration e = getPvcsprojects().elements();
+            while (e.hasMoreElements()) {
+                String projectName = ((PvcsProject) e.nextElement()).getName();
+                if (projectName == null || (projectName.trim()).equals("")) {
+                    throw new BuildException("name is a required attribute "
+                        + "of pvcsproject");
+                }
+                commandLine.createArgument().setValue(projectName);
+            }
+        }
+
+        File tmp = null;
+        File tmp2 = null;
+        try {
+            Random rand = new Random(System.currentTimeMillis());
+            tmp = new File("pvcs_ant_" + rand.nextLong() + ".log");
+            FileOutputStream fos = new FileOutputStream(tmp);
+            tmp2 = new File("pvcs_ant_" + rand.nextLong() + ".log");
+            log(commandLine.describeCommand(), Project.MSG_VERBOSE);
+            try {
+                result = runCmd(commandLine,
+                                new PumpStreamHandler(fos,
+                                    new LogOutputStream(this,
+                                                        Project.MSG_WARN)));
+            } finally {
+                fos.close();
+            }
+
+            if (Execute.isFailure(result) && !ignorerc) {
+                String msg = "Failed executing: " + commandLine.toString();
+                throw new BuildException(msg, getLocation());
+            }
+
+            if (!tmp.exists()) {
+                throw new BuildException("Communication between ant and pvcs "
+                    + "failed. No output generated from executing PVCS "
+                    + "commandline interface \"pcli\" and \"get\"");
+            }
+
+            // Create folders in workspace
+            log("Creating folders", Project.MSG_INFO);
+            createFolders(tmp);
+
+            // Massage PCLI lvf output transforming '\' to '/' so get command works appropriately
+            massagePCLI(tmp, tmp2);
+
+            // Launch get on output captured from PCLI lvf
+            commandLine.clearArgs();
+            commandLine.setExecutable(getExecutable(GET_EXE));
+
+            if (getConfig() != null && getConfig().length() > 0) {
+                commandLine.createArgument().setValue("-c" + getConfig());
+            }
+
+            if (getForce() != null && getForce().equals("yes")) {
+                commandLine.createArgument().setValue("-Y");
+            } else {
+                commandLine.createArgument().setValue("-N");
+            }
+
+            if (getPromotiongroup() != null) {
+                commandLine.createArgument().setValue("-G"
+                    + getPromotiongroup());
+            } else {
+                if (getLabel() != null) {
+                    commandLine.createArgument().setValue("-v" + getLabel());
+                } else {
+                    if (getRevision() != null) {
+                        commandLine.createArgument().setValue("-r"
+                            + getRevision());
+                    }
+                }
+            }
+
+            if (updateOnly) {
+                commandLine.createArgument().setValue("-U");
+            }
+
+            commandLine.createArgument().setValue("@" + tmp2.getAbsolutePath());
+            log("Getting files", Project.MSG_INFO);
+            log("Executing " + commandLine.toString(), Project.MSG_VERBOSE);
+            result = runCmd(commandLine,
+                new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN));
+            if (result != 0 && !ignorerc) {
+                String msg = "Failed executing: " + commandLine.toString()
+                    + ". Return code was " + result;
+                throw new BuildException(msg, getLocation());
+            }
+
+        } catch (FileNotFoundException e) {
+            String msg = "Failed executing: " + commandLine.toString()
+                + ". Exception: " + e.getMessage();
+            throw new BuildException(msg, getLocation());
+        } catch (IOException e) {
+            String msg = "Failed executing: " + commandLine.toString()
+                + ". Exception: " + e.getMessage();
+            throw new BuildException(msg, getLocation());
+        } catch (ParseException e) {
+            String msg = "Failed executing: " + commandLine.toString()
+                + ". Exception: " + e.getMessage();
+            throw new BuildException(msg, getLocation());
+        } finally {
+            if (tmp != null) {
+                tmp.delete();
+            }
+            if (tmp2 != null) {
+                tmp2.delete();
+            }
+        }
+    }
+
+    /**
+     * Parses the file and creates the folders specified in the output section
+     */
+    private void createFolders(File file) throws IOException, ParseException {
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader(file));
+            MessageFormat mf = new MessageFormat(getFilenameFormat());
+            String line = in.readLine();
+            while (line != null) {
+                log("Considering \"" + line + "\"", Project.MSG_VERBOSE);
+                if (line.startsWith("\"\\")    // Checking for "\
+                    || line.startsWith("\"/")  // or           "/
+                                               // or           "X:\...
+                   || (line.length() > POS_3 && line.startsWith("\"")
+                        && Character.isLetter(line.charAt(POS_1))
+                        && String.valueOf(line.charAt(POS_2)).equals(":")
+                        && String.valueOf(line.charAt(POS_3)).equals("\\"))) {
+                    Object[] objs = mf.parse(line);
+                    String f = (String) objs[1];
+                    // Extract the name of the directory from the filename
+                    int index = f.lastIndexOf(File.separator);
+                    if (index > -1) {
+                        File dir = new File(f.substring(0, index));
+                        if (!dir.exists()) {
+                            log("Creating " + dir.getAbsolutePath(),
+                                Project.MSG_VERBOSE);
+                            if (dir.mkdirs()) {
+                                log("Created " + dir.getAbsolutePath(),
+                                    Project.MSG_INFO);
+                            } else {
+                                log("Failed to create "
+                                    + dir.getAbsolutePath(),
+                                    Project.MSG_INFO);
+                            }
+                        } else {
+                            log(dir.getAbsolutePath() + " exists. Skipping",
+                                Project.MSG_VERBOSE);
+                        }
+                    } else {
+                        log("File separator problem with " + line,
+                            Project.MSG_WARN);
+                    }
+                } else {
+                    log("Skipped \"" + line + "\"", Project.MSG_VERBOSE);
+                }
+                line = in.readLine();
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+
+    /**
+     * Simple hack to handle the PVCS command-line tools botch when
+     * handling UNC notation.
+     * @throws IOException if there is an error.
+     */
+    private void massagePCLI(File in, File out)
+        throws IOException {
+        BufferedReader inReader = null;
+        BufferedWriter outWriter = null;
+        try {
+            inReader = new BufferedReader(new FileReader(in));
+            outWriter = new BufferedWriter(new FileWriter(out));
+            String s = null;
+            while ((s = inReader.readLine()) != null) {
+                String sNormal = s.replace('\\', '/');
+                outWriter.write(sNormal);
+                outWriter.newLine();
+            }
+        } finally {
+            if (inReader != null) {
+                inReader.close();
+            }
+            if (outWriter != null) {
+                outWriter.close();
+            }
+        }
+    }
+
+    /**
+     * Get network name of the PVCS repository
+     * @return String
+     */
+    public String getRepository() {
+        return repository;
+    }
+
+    /**
+     *  The filenameFormat attribute defines a MessageFormat string used
+     *  to parse the output of the pcli command.  It defaults to
+     *  <code>{0}-arc({1})</code>.  Repositories where the archive
+     *   extension is not  -arc should set this.
+     * @return the filename format attribute.
+     */
+    public String getFilenameFormat() {
+        return filenameFormat;
+    }
+
+    /**
+     * The format of the folder names; optional.
+     * This must be in a format suitable for
+     * <code>java.text.MessageFormat</code>.
+     *  Index 1 of the format will be used as the file name.
+     *  Defaults to <code>{0}-arc({1})</code>
+     * @param f the format to use.
+     */
+    public void setFilenameFormat(String f) {
+        filenameFormat = f;
+    }
+
+    /**
+
+     * The lineStart attribute is used to parse the output of the pcli
+     * command. It defaults to <code>&quot;P:</code>.  The parser already
+     * knows about / and \\, this property is useful in cases where the
+     * repository is accessed on a Windows platform via a drive letter
+     * mapping.
+     * @return the lineStart attribute.
+     */
+    public String getLineStart() {
+        return lineStart;
+    }
+
+    /**
+     * What a valid return value from PVCS looks like
+     *  when it describes a file.  Defaults to <code>&quot;P:</code>.
+     * If you are not using an UNC name for your repository and the
+     * drive letter <code>P</code> is incorrect for your setup, you may
+     * need to change this value, UNC names will always be
+     * accepted.
+     * @param l the value to use.
+     */
+    public void setLineStart(String l) {
+        lineStart = l;
+    }
+
+    /**
+     * The network name of the PVCS repository; required.
+     * @param repo String
+     */
+    public void setRepository(String repo) {
+        repository = repo;
+    }
+
+    /**
+     * Get name of the project in the PVCS repository
+     * @return String
+     */
+    public String getPvcsproject() {
+        return pvcsProject;
+    }
+
+    /**
+     * The project within the PVCS repository to extract files from;
+     * optional, default &quot;/&quot;
+     * @param prj String
+     */
+    public void setPvcsproject(String prj) {
+        pvcsProject = prj;
+    }
+
+    /**
+     * Get name of the project in the PVCS repository
+     * @return Vector
+     */
+    public Vector getPvcsprojects() {
+        return pvcsProjects;
+    }
+
+    /**
+     * Get name of the workspace to store the retrieved files
+     * @return String
+     */
+    public String getWorkspace() {
+        return workspace;
+    }
+
+    /**
+     * Workspace to use; optional.
+     * By specifying a workspace, the files are extracted to that location.
+     * A PVCS workspace is a name for a location of the workfiles and
+     * isn't as such the location itself.
+     * You define the location for a workspace using the PVCS GUI clients.
+     * If this isn't specified the default workspace for the current user is used.
+     * @param ws String
+     */
+    public void setWorkspace(String ws) {
+        workspace = ws;
+    }
+
+    /**
+     * Get name of the PVCS bin directory
+     * @return String
+     */
+    public String getPvcsbin() {
+        return pvcsbin;
+    }
+
+    /**
+     * Specifies the location of the PVCS bin directory; optional if on the PATH.
+     * On some systems the PVCS executables <i>pcli</i>
+     * and <i>get</i> are not found in the PATH. In such cases this attribute
+     * should be set to the bin directory of the PVCS installation containing
+     * the executables mentioned before. If this attribute isn't specified the
+     * tag expects the executables to be found using the PATH environment variable.
+     * @param bin PVCS bin directory
+     * @todo use a File setter and resolve paths.
+     */
+    public void setPvcsbin(String bin) {
+        pvcsbin = bin;
+    }
+
+    /**
+     * Get value of force
+     * @return String
+     */
+    public String getForce() {
+        return force;
+    }
+
+    /**
+     * Specifies the value of the force argument; optional.
+     * If set to <i>yes</i> all files that exists and are
+     * writable are overwritten. Default <i>no</i> causes the files
+     * that are writable to be ignored. This stops the PVCS command
+     * <i>get</i> to stop asking questions!
+     * @todo make a boolean setter
+     * @param f String (yes/no)
+     */
+    public void setForce(String f) {
+        if (f != null && f.equalsIgnoreCase("yes")) {
+            force = "yes";
+        } else {
+            force = "no";
+        }
+    }
+
+    /**
+     * Get value of promotiongroup
+     * @return String
+     */
+    public String getPromotiongroup() {
+        return promotiongroup;
+    }
+
+    /**
+     * Specifies the name of the promotiongroup argument
+     * @param w String
+     */
+    public void setPromotiongroup(String w) {
+        promotiongroup = w;
+    }
+
+    /**
+     * Get value of label
+     * @return String
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Only files marked with this label are extracted; optional.
+     * @param l String
+     */
+    public void setLabel(String l) {
+        label = l;
+    }
+
+    /**
+     * Get value of revision
+     * @return String
+     */
+    public String getRevision() {
+        return revision;
+    }
+
+    /**
+     * Only files with this revision are extract; optional.
+     * @param r String
+     */
+    public void setRevision(String r) {
+        revision = r;
+    }
+
+    /**
+     * Get value of ignorereturncode
+     * @return String
+     */
+    public boolean getIgnoreReturnCode() {
+        return ignorerc;
+    }
+
+    /**
+     * If set to true the return value from executing the pvcs
+     * commands are ignored; optional, default false.
+     * @param b a <code>boolean</code> value.
+     */
+    public void setIgnoreReturnCode(boolean b) {
+        ignorerc = b;
+    }
+
+    /**
+     * Specify a project within the PVCS repository to extract files from.
+     * @param p the pvcs project to use.
+     */
+    public void addPvcsproject(PvcsProject p) {
+        pvcsProjects.addElement(p);
+    }
+
+    /**
+     * get the updateOnly attribute.
+     * @return the updateOnly attribute.
+     */
+    public boolean getUpdateOnly() {
+        return updateOnly;
+    }
+
+    /**
+     * If set to <i>true</i> files are fetched only if
+     * newer than existing local files; optional, default false.
+     * @param l a <code>boolean</code> value.
+     */
+    public void setUpdateOnly(boolean l) {
+        updateOnly = l;
+    }
+
+    /**
+     * returns the path of the configuration file to be used
+     * @return the path of the config file
+     */
+    public String getConfig() {
+        return config;
+    }
+
+    /**
+     * Sets a configuration file other than the default to be used.
+     * These files have a .cfg extension and are often found in archive or pvcsprop folders.
+     * @param f config file - can be given absolute or relative to ant basedir
+     */
+    public void setConfig(File f) {
+        config = f.toString();
+    }
+
+
+    /**
+     * Get the userid.
+     * @return the userid.
+     */
+    public String getUserId() {
+        return userId;
+    }
+
+    /**
+     * User ID
+     * @param u the value to use.
+     */
+    public void setUserId(String u) {
+        userId = u;
+    }
+
+    /**
+     * Creates a Pvcs object
+     */
+    public Pvcs() {
+        super();
+        pvcsProject = null;
+        pvcsProjects = new Vector();
+        workspace = null;
+        repository = null;
+        pvcsbin = null;
+        force = null;
+        promotiongroup = null;
+        label = null;
+        ignorerc = false;
+        updateOnly = false;
+        lineStart = "\"P:";
+        filenameFormat = "{0}-arc({1})";
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java
new file mode 100644
index 0000000..a8c6a2a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/pvcs/PvcsProject.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.pvcs;
+
+
+
+/**
+ * represents a project within the PVCS repository to extract files from.
+ */
+public class PvcsProject {
+    private String name;
+
+    /** no arg constructor */
+    public PvcsProject() {
+        super();
+    }
+
+    /**
+     * Set the name of the project
+     * @param name the value to use.
+     */
+    public void setName(String name) {
+        PvcsProject.this.name = name;
+    }
+
+    /**
+     * Get the name of the project
+     * @return the name of the project.
+     */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java
new file mode 100644
index 0000000..db3f28d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java
@@ -0,0 +1,405 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.script;
+
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.taskdefs.DefBase;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.io.File;
+
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * Define a task using a script
+ *
+ * @since Ant 1.6
+ */
+public class ScriptDef extends DefBase {
+    /**
+     * script runner helper
+     */
+    private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+    /**
+     * script runner.
+     */
+    /** Used to run the script */
+    private ScriptRunnerBase   runner = null;
+
+    /** the name by which this script will be activated */
+    private String name;
+
+    /** Attributes definitions of this script */
+    private List attributes = new ArrayList();
+
+    /** Nested Element definitions of this script */
+    private List nestedElements = new ArrayList();
+
+    /** The attribute names as a set */
+    private Set attributeSet;
+
+    /** The nested element definitions indexed by their names */
+    private Map nestedElementMap;
+
+    /**
+     * Set the project.
+     * @param project the project that this def belows to.
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        helper.setProjectComponent(this);
+        helper.setSetBeans(false);
+    }
+
+    /**
+     * set the name under which this script will be activated in a build
+     * file
+     *
+     * @param name the name of the script
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Indicates whether the task supports a given attribute name
+     *
+     * @param attributeName the name of the attribute.
+     *
+     * @return true if the attribute is supported by the script.
+     */
+    public boolean isAttributeSupported(String attributeName) {
+        return attributeSet.contains(attributeName);
+    }
+
+    /**
+     * Class representing an attribute definition
+     */
+    public static class Attribute {
+        /** The attribute name */
+        private String name;
+
+        /**
+         * Set the attribute name
+         *
+         * @param name the attribute name
+         */
+        public void setName(String name) {
+            this.name = name.toLowerCase(Locale.US);
+        }
+    }
+
+    /**
+     * Add an attribute definition to this script.
+     *
+     * @param attribute the attribute definition.
+     */
+    public void addAttribute(Attribute attribute) {
+        attributes.add(attribute);
+    }
+
+    /**
+     * Class to represent a nested element definition
+     */
+    public static class NestedElement {
+        /** The name of the neseted element */
+        private String name;
+
+        /** The Ant type to which this nested element corresponds. */
+        private String type;
+
+        /** The class to be created for this nested element */
+        private String className;
+
+        /**
+         * set the tag name for this nested element
+         *
+         * @param name the name of this nested element
+         */
+        public void setName(String name) {
+            this.name = name.toLowerCase(Locale.US);
+        }
+
+        /**
+         * Set the type of this element. This is the name of an
+         * Ant task or type which is to be used when this element is to be
+         * created. This is an alternative to specifying the class name directly
+         *
+         * @param type the name of an Ant type, or task, to use for this nested
+         * element.
+         */
+        public void setType(String type) {
+            this.type = type;
+        }
+
+        /**
+         * Set the classname of the class to be used for the nested element.
+         * This specifies the class directly and is an alternative to specifying
+         * the Ant type name.
+         *
+         * @param className the name of the class to use for this nested
+         * element.
+         */
+        public void setClassName(String className) {
+            this.className = className;
+        }
+    }
+
+    /**
+     * Add a nested element definition.
+     *
+     * @param nestedElement the nested element definition.
+     */
+    public void addElement(NestedElement nestedElement) {
+        nestedElements.add(nestedElement);
+    }
+
+    /**
+     * Define the script.
+     */
+    public void execute() {
+        if (name == null) {
+            throw new BuildException("scriptdef requires a name attribute to "
+                + "name the script");
+        }
+
+        if (helper.getLanguage() == null) {
+            throw new BuildException("<scriptdef> requires a language attribute "
+                + "to specify the script language");
+        }
+
+        // Check if need to set the loader
+        if (getAntlibClassLoader() != null || hasCpDelegate()) {
+            helper.setClassLoader(createLoader());
+        }
+
+        // Now create the scriptRunner
+        runner = helper.getScriptRunner();
+
+        attributeSet = new HashSet();
+        for (Iterator i = attributes.iterator(); i.hasNext();) {
+            Attribute attribute = (Attribute) i.next();
+            if (attribute.name == null) {
+                throw new BuildException("scriptdef <attribute> elements "
+                    + "must specify an attribute name");
+            }
+
+            if (attributeSet.contains(attribute.name)) {
+                throw new BuildException("scriptdef <" + name + "> declares "
+                    + "the " + attribute.name + " attribute more than once");
+            }
+            attributeSet.add(attribute.name);
+        }
+
+        nestedElementMap = new HashMap();
+        for (Iterator i = nestedElements.iterator(); i.hasNext();) {
+            NestedElement nestedElement = (NestedElement) i.next();
+            if (nestedElement.name == null) {
+                throw new BuildException("scriptdef <element> elements "
+                    + "must specify an element name");
+            }
+            if (nestedElementMap.containsKey(nestedElement.name)) {
+                throw new BuildException("scriptdef <" + name + "> declares "
+                    + "the " + nestedElement.name + " nested element more "
+                    + "than once");
+            }
+
+            if (nestedElement.className == null
+                && nestedElement.type == null) {
+                throw new BuildException("scriptdef <element> elements "
+                    + "must specify either a classname or type attribute");
+            }
+            if (nestedElement.className != null
+                && nestedElement.type != null) {
+                throw new BuildException("scriptdef <element> elements "
+                    + "must specify only one of the classname and type "
+                    + "attributes");
+            }
+
+
+            nestedElementMap.put(nestedElement.name, nestedElement);
+        }
+
+        // find the script repository - it is stored in the project
+        Map scriptRepository = lookupScriptRepository();
+        name = ProjectHelper.genComponentName(getURI(), name);
+        scriptRepository.put(name, this);
+        AntTypeDefinition def = new AntTypeDefinition();
+        def.setName(name);
+        def.setClass(ScriptDefBase.class);
+        ComponentHelper.getComponentHelper(
+            getProject()).addDataTypeDefinition(def);
+    }
+
+    /**
+     * Find or create the script repository - it is stored in the project.
+     * This method is synchronized on the project under {@link MagicNames#SCRIPT_REPOSITORY}
+     * @return the current script repository registered as a refrence.
+     */
+    private Map lookupScriptRepository() {
+        Map scriptRepository = null;
+        Project p = getProject();
+        synchronized (p) {
+            scriptRepository =
+                    (Map) p.getReference(MagicNames.SCRIPT_REPOSITORY);
+            if (scriptRepository == null) {
+                scriptRepository = new HashMap();
+                p.addReference(MagicNames.SCRIPT_REPOSITORY,
+                        scriptRepository);
+            }
+        }
+        return scriptRepository;
+    }
+
+    /**
+     * Create a nested element to be configured.
+     *
+     * @param elementName the name of the nested element.
+     * @return object representing the element name.
+     */
+    public Object createNestedElement(String elementName) {
+        NestedElement definition
+            = (NestedElement) nestedElementMap.get(elementName);
+        if (definition == null) {
+            throw new BuildException("<" + name + "> does not support "
+                + "the <" + elementName + "> nested element");
+        }
+
+        Object instance = null;
+        String classname = definition.className;
+        if (classname == null) {
+            instance = getProject().createTask(definition.type);
+            if (instance == null) {
+                instance = getProject().createDataType(definition.type);
+            }
+        } else {
+            /*
+            // try the context classloader
+            ClassLoader loader
+                = Thread.currentThread().getContextClassLoader();
+            */
+            ClassLoader loader = createLoader();
+
+            try {
+                instance = ClasspathUtils.newInstance(classname, loader);
+            } catch (BuildException e) {
+                instance = ClasspathUtils.newInstance(classname, ScriptDef.class.getClassLoader());
+            }
+
+            getProject().setProjectReference(instance);
+        }
+
+        if (instance == null) {
+            throw new BuildException("<" + name + "> is unable to create "
+                + "the <" + elementName + "> nested element");
+        }
+        return instance;
+    }
+
+    /**
+     * Execute the script.
+     *
+     * @param attributes collection of attributes
+     * @param elements a list of nested element values.
+     * @deprecated since 1.7.
+     *             Use executeScript(attribute, elements, instance) instead.
+     */
+    public void executeScript(Map attributes, Map elements) {
+        executeScript(attributes, elements, null);
+    }
+
+    /**
+     * Execute the script.
+     * This is called by the script instance to execute the script for this
+     * definition.
+     *
+     * @param attributes collection of attributes
+     * @param elements   a list of nested element values.
+     * @param instance   the script instance; can be null
+     */
+    public void executeScript(Map attributes, Map elements, ScriptDefBase instance) {
+        runner.addBean("attributes", attributes);
+        runner.addBean("elements", elements);
+        runner.addBean("project", getProject());
+        if (instance != null) {
+            runner.addBean("self", instance);
+        }
+        runner.executeScript("scriptdef_" + name);
+    }
+
+    /**
+     * Defines the manager.
+     *
+     * @param manager the scripting manager.
+     */
+    public void setManager(String manager) {
+        helper.setManager(manager);
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        helper.setLanguage(language);
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        helper.setSrc(file);
+    }
+
+    /**
+     * Set the script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        helper.addText(text);
+    }
+
+    /**
+     * Add any source resource.
+     * @since Ant1.7.1
+     * @param resource source of script
+     */
+    public void add(ResourceCollection resource) {
+        helper.add(resource);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java
new file mode 100644
index 0000000..f98e10d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDefBase.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.script;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicConfigurator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * The script execution class. This class finds the defining script task
+ * and passes control to that task's executeScript method.
+ *
+ * @since Ant 1.6
+ */
+public class ScriptDefBase extends Task implements DynamicConfigurator {
+
+    /** Nested elements */
+    private Map nestedElementMap = new HashMap();
+
+    /** Attributes */
+    private Map attributes = new HashMap();
+
+    private String text;
+
+    /**
+     * Locate the script defining task and execute the script by passing
+     * control to it
+     */
+    public void execute() {
+        getScript().executeScript(attributes, nestedElementMap, this);
+    }
+
+    private ScriptDef getScript() {
+        String name = getTaskType();
+        Map scriptRepository
+            = (Map) getProject().getReference(MagicNames.SCRIPT_REPOSITORY);
+        if (scriptRepository == null) {
+            throw new BuildException("Script repository not found for " + name);
+        }
+
+        ScriptDef definition = (ScriptDef) scriptRepository.get(getTaskType());
+        if (definition == null) {
+            throw new BuildException("Script definition not found for " + name);
+        }
+        return definition;
+    }
+
+    /**
+     * Create a nested element
+     *
+     * @param name the nested element name
+     * @return the element to be configured
+     */
+    public Object createDynamicElement(String name)  {
+        List nestedElementList = (List) nestedElementMap.get(name);
+        if (nestedElementList == null) {
+            nestedElementList = new ArrayList();
+            nestedElementMap.put(name, nestedElementList);
+        }
+        Object element = getScript().createNestedElement(name);
+        nestedElementList.add(element);
+        return element;
+    }
+
+    /**
+     * Set a task attribute
+     *
+     * @param name the attribute name.
+     * @param value the attribute's string value
+     */
+    public void setDynamicAttribute(String name, String value) {
+        ScriptDef definition = getScript();
+        if (!definition.isAttributeSupported(name)) {
+                throw new BuildException("<" + getTaskType()
+                    + "> does not support the \"" + name + "\" attribute");
+        }
+
+        attributes.put(name, value);
+    }
+
+    /**
+     * Set the script text.
+     *
+     * @param text a component of the script text to be added.
+     * @since ant1.7
+     */
+    public void addText(String text) {
+        this.text = getProject().replaceProperties(text);
+    }
+
+    /**
+     * get the text of this element; may be null
+     * @return text or null for no nested text
+     * @since ant1.7
+     */
+    public String getText() {
+        return text;
+    }
+
+    /**
+     * Utility method for nested scripts; throws a BuildException
+     * with the given message.
+     * @param message text to pass to the BuildException
+     * @throws BuildException always.
+     * @since ant1.7
+     */
+    public void fail(String message) {
+        throw new BuildException(message);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java
new file mode 100644
index 0000000..d7805b0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOS.java
@@ -0,0 +1,478 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A base class for creating tasks for executing commands on SourceOffSite.
+ *
+ *  These tasks were inspired by the VSS tasks.
+ *
+ */
+
+public abstract class SOS extends Task implements SOSCmd {
+
+    private static final int ERROR_EXIT_STATUS = 255;
+
+    private String sosCmdDir = null;
+    private String sosUsername = null;
+    private String sosPassword = "";
+    private String projectPath = null;
+    private String vssServerPath = null;
+    private String sosServerPath = null;
+    private String sosHome = null;
+    private String localPath = null;
+    private String version = null;
+    private String label = null;
+    private String comment = null;
+    private String filename = null;
+
+    private boolean noCompress = false;
+    private boolean noCache = false;
+    private boolean recursive = false;
+    private boolean verbose = false;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /** Commandline to be executed. */
+    protected Commandline commandLine;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Flag to disable the cache when set.
+     * Required if SOSHOME is set as an environment variable.
+     * Defaults to false.
+     *
+     * @param  nocache  True to disable caching.
+     */
+    public final void setNoCache(boolean nocache) {
+        noCache = nocache;
+    }
+
+    /**
+     * Flag to disable compression when set. Defaults to false.
+     *
+     * @param  nocompress  True to disable compression.
+     */
+    public final void setNoCompress(boolean nocompress) {
+        noCompress = nocompress;
+    }
+
+    /**
+     * The directory where soscmd(.exe) is located.
+     * soscmd must be on the path if omitted.
+     *
+     * @param  dir  The new sosCmd value.
+     */
+    public final void setSosCmd(String dir) {
+        sosCmdDir = FileUtils.translatePath(dir);
+    }
+
+    /**
+     * The SourceSafe username.
+     *
+     * @param  username  The new username value.
+     *
+     * @ant.attribute group="required"
+     */
+    public final void setUsername(String username) {
+        sosUsername = username;
+    }
+
+    /**
+     * The SourceSafe password.
+     *
+     * @param  password  The new password value.
+     */
+    public final void setPassword(String password) {
+        sosPassword = password;
+    }
+
+    /**
+     * The SourceSafe project path.
+     *
+     * @param  projectpath  The new projectpath value.
+     *
+     * @ant.attribute group="required"
+     */
+    public final void setProjectPath(String projectpath) {
+        if (projectpath.startsWith(SOSCmd.PROJECT_PREFIX)) {
+            projectPath = projectpath;
+        } else {
+            projectPath = SOSCmd.PROJECT_PREFIX + projectpath;
+        }
+    }
+
+    /**
+     * The path to the location of the ss.ini file.
+     *
+     * @param  vssServerPath  The new vssServerPath value.
+     *
+     * @ant.attribute group="required"
+     */
+    public final void setVssServerPath(String vssServerPath) {
+        this.vssServerPath = vssServerPath;
+    }
+
+    /**
+     * Path to the SourceOffSite home directory.
+     *
+     * @param  sosHome  The new sosHome value.
+     */
+    public final void setSosHome(String sosHome) {
+        this.sosHome = sosHome;
+    }
+
+    /**
+     * The address and port of SourceOffSite Server,
+     * for example 192.168.0.1:8888.
+     *
+     * @param  sosServerPath  The new sosServerPath value.
+     *
+     * @ant.attribute group="required"
+     */
+    public final void setSosServerPath(String sosServerPath) {
+        this.sosServerPath = sosServerPath;
+    }
+
+    /**
+     * Override the working directory and get to the specified path.
+     *
+     * @param  path  The new localPath value.
+     */
+    public final void setLocalPath(Path path) {
+        localPath = path.toString();
+    }
+
+    /**
+     * Enable verbose output. Defaults to false.
+     *
+     * @param  verbose  True for verbose output.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    // Special setters for the sub-classes
+
+    /**
+     * Set the file name.
+     * @param file the filename to use.
+     */
+    protected void setInternalFilename(String file) {
+        filename = file;
+    }
+
+    /**
+     * Set the recursive flag.
+     * @param recurse if true use the recursive flag on the command line.
+     */
+    protected void setInternalRecursive(boolean recurse) {
+        recursive = recurse;
+    }
+
+    /**
+     * Set the comment text.
+     * @param text the comment text to use.
+     */
+    protected void setInternalComment(String text) {
+        comment = text;
+    }
+
+    /**
+     * Set the label.
+     * @param text the label to use.
+     */
+    protected void setInternalLabel(String text) {
+        label = text;
+    }
+
+    /**
+     * Set the version.
+     * @param text the version to use.
+     */
+    protected void setInternalVersion(String text) {
+        version = text;
+    }
+
+    /**
+     * Get the executable to run. Add the path if it was specifed in the build file
+     *
+     * @return the executable to run.
+     */
+    protected String getSosCommand() {
+        if (sosCmdDir == null) {
+            return COMMAND_SOS_EXE;
+        } else {
+            return sosCmdDir + File.separator + COMMAND_SOS_EXE;
+        }
+    }
+
+    /**
+     * Get the comment
+     * @return if it was set, null if not.
+     */
+    protected String getComment() {
+        return comment;
+    }
+
+    /**
+     * Get the version
+     * @return if it was set, null if not.
+     */
+    protected String getVersion() {
+        return version;
+    }
+
+    /**
+     * Get the label
+     * @return if it was set, null if not.
+     */
+    protected String getLabel() {
+        return label;
+    }
+
+    /**
+     * Get the username
+     * @return if it was set, null if not.
+     */
+    protected String getUsername() {
+        return sosUsername;
+    }
+
+    /**
+     * Get the password
+     * @return empty string if it wasn't set.
+     */
+    protected String getPassword() {
+        return sosPassword;
+    }
+
+    /**
+     * Get the project path
+     * @return if it was set, null if not.
+     */
+    protected String getProjectPath() {
+        return projectPath;
+    }
+
+    /**
+     * Get the VSS server path
+     * @return if it was set, null if not.
+     */
+    protected String getVssServerPath() {
+        return vssServerPath;
+    }
+
+    /**
+     * Get the SOS home directory.
+     * @return if it was set, null if not.
+     */
+    protected String getSosHome() {
+        return sosHome;
+    }
+
+    /**
+     * Get the SOS serve path.
+     * @return if it was set, null if not.
+     */
+    protected String getSosServerPath() {
+        return sosServerPath;
+    }
+
+    /**
+     * Get the filename to be acted upon.
+     * @return if it was set, null if not.
+     */
+    protected String getFilename() {
+        return filename;
+    }
+
+    /**
+     * Get the NoCompress flag.
+     *
+     * @return the 'nocompress' Flag if the attribute was 'true',
+     *         otherwise an empty string.
+     */
+    protected String getNoCompress() {
+        return noCompress ? FLAG_NO_COMPRESSION : "";
+    }
+
+    /**
+     * Get the NoCache flag.
+     *
+     * @return the 'nocache' Flag if the attribute was 'true', otherwise an empty string.
+     */
+    protected String getNoCache() {
+        return noCache ? FLAG_NO_CACHE : "";
+    }
+
+    /**
+     * Get the 'verbose' Flag.
+     *
+     * @return the 'verbose' Flag if the attribute was 'true', otherwise an empty string.
+     */
+    protected String getVerbose() {
+        return verbose ? FLAG_VERBOSE : "";
+    }
+
+    /**
+     * Get the 'recursive' Flag.
+     *
+     * @return the 'recursive' Flag if the attribute was 'true', otherwise an empty string.
+     */
+    protected String getRecursive() {
+        return recursive ? FLAG_RECURSION : "";
+    }
+
+    /**
+     * Builds and returns the working directory.
+     * <p>
+     * The localpath is created if it didn't exist.
+     *
+     * @return the absolute path of the working directory.
+     */
+    protected String getLocalPath() {
+        if (localPath == null) {
+            return getProject().getBaseDir().getAbsolutePath();
+        } else {
+            // make sure localDir exists, create it if it doesn't
+            File dir = getProject().resolveFile(localPath);
+            if (!dir.exists()) {
+                boolean done = dir.mkdirs();
+                if (!done) {
+                    String msg = "Directory " + localPath + " creation was not "
+                        + "successful for an unknown reason";
+                    throw new BuildException(msg, getLocation());
+                }
+                getProject().log("Created dir: " + dir.getAbsolutePath());
+            }
+            return dir.getAbsolutePath();
+        }
+    }
+
+    /**
+     * Subclasses implement the logic required to construct the command line.
+     *
+     * @return   The command line to execute.
+     */
+    abstract Commandline buildCmdLine();
+
+
+    /**
+     * Execute the created command line.
+     *
+     * @throws BuildException on error.
+     */
+    public void execute()
+        throws BuildException {
+        int result = 0;
+        buildCmdLine();
+        result = run(commandLine);
+        if (result == ERROR_EXIT_STATUS) {  // This is the exit status
+            String msg = "Failed executing: " + commandLine.toString();
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    /**
+     * Execute the created command line.
+     *
+     * @param  cmd              The command line to run.
+     * @return                  int the exit code.
+     * @throws  BuildException
+     */
+    protected int run(Commandline cmd) {
+        try {
+            Execute exe = new Execute(new LogStreamHandler(this,
+                    Project.MSG_INFO,
+                    Project.MSG_WARN));
+
+            exe.setAntRun(getProject());
+            exe.setWorkingDirectory(getProject().getBaseDir());
+            exe.setCommandline(cmd.getCommandline());
+            exe.setVMLauncher(false);  // Use the OS VM launcher so we get environment variables
+            return exe.execute();
+        } catch (java.io.IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+    /** Sets the executable and add the required attributes to the command line. */
+    protected void getRequiredAttributes() {
+        // Get the path to the soscmd(.exe)
+        commandLine.setExecutable(getSosCommand());
+        // SOS server address is required
+        if (getSosServerPath() == null) {
+            throw new BuildException("sosserverpath attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(FLAG_SOS_SERVER);
+        commandLine.createArgument().setValue(getSosServerPath());
+        // Login info is required
+        if (getUsername() == null) {
+            throw new BuildException("username attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(FLAG_USERNAME);
+        commandLine.createArgument().setValue(getUsername());
+        // The SOS class knows that the SOS server needs the password flag,
+        // even if there is no password ,so we send a " "
+        commandLine.createArgument().setValue(FLAG_PASSWORD);
+        commandLine.createArgument().setValue(getPassword());
+        // VSS Info is required
+        if (getVssServerPath() == null) {
+            throw new BuildException("vssserverpath attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(FLAG_VSS_SERVER);
+        commandLine.createArgument().setValue(getVssServerPath());
+        // VSS project is required
+        if (getProjectPath() == null) {
+            throw new BuildException("projectpath attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(FLAG_PROJECT);
+        commandLine.createArgument().setValue(getProjectPath());
+    }
+
+    /** Adds the optional attributes to the command line. */
+    protected void getOptionalAttributes() {
+        // -verbose
+        commandLine.createArgument().setValue(getVerbose());
+        // Disable Compression
+        commandLine.createArgument().setValue(getNoCompress());
+        // Path to the SourceOffSite home directory /home/user/.sos
+        if (getSosHome() == null) {
+            // If -soshome was not specified then we can look for nocache
+            commandLine.createArgument().setValue(getNoCache());
+        } else {
+            commandLine.createArgument().setValue(FLAG_SOS_HOME);
+            commandLine.createArgument().setValue(getSosHome());
+        }
+        //If a working directory was specified then add it to the command line
+        if (getLocalPath() != null) {
+            commandLine.createArgument().setValue(FLAG_WORKING_DIR);
+            commandLine.createArgument().setValue(getLocalPath());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java
new file mode 100644
index 0000000..9095f07
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckin.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Commits and unlocks files in Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="soscheckin" category="scm"
+ */
+public class SOSCheckin extends SOS {
+
+    /**
+     * The filename to act upon.
+     * If no file is specified then the task
+     * acts upon the project.
+     *
+     * @param  filename  The new file value
+     */
+    public final void setFile(String filename) {
+        super.setInternalFilename(filename);
+    }
+
+    /**
+     * Flag to recursively apply the action. Defaults to false.
+     *
+     * @param  recursive  True for recursive operation.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * The comment to apply to all files being labelled.
+     *
+     * @param  comment  The new comment value
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+
+    /**
+     * Build the command line. <p>
+     *
+     * CheckInFile required parameters: -server -name -password -database -project
+     *  -file<br>
+     * CheckInFile optional parameters: -workdir -log -verbose -nocache -nocompression
+     *  -soshome<br>
+     * CheckInProject required parameters: -server -name -password -database
+     *  -project<br>
+     * CheckInProject optional parameters: workdir -recursive -log -verbose
+     *  -nocache -nocompression -soshome<br>
+     *
+     * @return    Commandline the generated command to be executed
+     */
+    protected Commandline buildCmdLine() {
+        commandLine = new Commandline();
+
+        // If we find a "file" attribute then act on a file otherwise act on a project
+        if (getFilename() != null) {
+            // add -command CheckInFile to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKIN_FILE);
+            // add -file xxxxx to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+            commandLine.createArgument().setValue(getFilename());
+        } else {
+            // add -command CheckInProject to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKIN_PROJECT);
+            // look for a recursive option
+            commandLine.createArgument().setValue(getRecursive());
+        }
+
+        getRequiredAttributes();
+        getOptionalAttributes();
+
+        // Look for a comment
+        if (getComment() != null) {
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMENT);
+            commandLine.createArgument().setValue(getComment());
+        }
+        return commandLine;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java
new file mode 100644
index 0000000..fab6fb9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCheckout.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Retrieves and locks files in Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="soscheckout" category="scm"
+ */
+public class SOSCheckout extends SOS {
+
+    /**
+     * The filename to act upon.
+     * If no file is specified then the task
+     * acts upon the project.
+     *
+     * @param  filename  The new file value
+     */
+    public final void setFile(String filename) {
+        super.setInternalFilename(filename);
+    }
+
+    /**
+     * Flag to recursively apply the action. Defaults to false.
+     *
+     * @param  recursive  True for recursive operation.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Build the command line <br>
+     *
+     * CheckOutFile required parameters: -server -name -password -database -project -file<br>
+     * CheckOutFile optional parameters: -workdir -verbose -nocache -nocompression -soshome<br>
+     *
+     * CheckOutProject required parameters: -server -name -password -database -project<br>
+     * CheckOutProject optional parameters:-workdir -recursive -verbose -nocache
+     * -nocompression -soshome<br>
+     *
+     * @return    Commandline the generated command to be executed
+     */
+    protected Commandline buildCmdLine() {
+        commandLine = new Commandline();
+
+        // If we find a "file" attribute then act on a file otherwise act on a project
+        if (getFilename() != null) {
+            // add -command CheckOutFile to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKOUT_FILE);
+            // add -file xxxxx to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+            commandLine.createArgument().setValue(getFilename());
+        } else {
+            // add -command CheckOutProject to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_CHECKOUT_PROJECT);
+            // look for a recursive option
+            commandLine.createArgument().setValue(getRecursive());
+        }
+
+        getRequiredAttributes();
+        getOptionalAttributes();
+
+        return commandLine;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java
new file mode 100644
index 0000000..3543c41
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSCmd.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+/**
+ * Interface to hold constants used by the SOS tasks
+ *
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF (bc)
+public interface SOSCmd {
+    // soscmd Command options
+    /** The sos executable */
+    String COMMAND_SOS_EXE = "soscmd";
+    /** The get file command */
+    String COMMAND_GET_FILE = "GetFile";
+    /** The get project command */
+    String COMMAND_GET_PROJECT = "GetProject";
+    /** The checkout file command */
+    String COMMAND_CHECKOUT_FILE = "CheckOutFile";
+    /** The checkout project command */
+    String COMMAND_CHECKOUT_PROJECT = "CheckOutProject";
+    /** The checkin file command */
+    String COMMAND_CHECKIN_FILE = "CheckInFile";
+    /** The checkin project command */
+    String COMMAND_CHECKIN_PROJECT = "CheckInProject";
+    /** The get history command */
+    String COMMAND_HISTORY = "GetFileHistory";
+    /** The add label command */
+    String COMMAND_LABEL = "AddLabel";
+    /** The project prefix */
+    String PROJECT_PREFIX = "$";
+
+    // soscmd Option flags
+    /** The command option */
+    String FLAG_COMMAND = "-command";
+    /** The database (vss server) option */
+    String FLAG_VSS_SERVER = "-database";
+    /** The username option */
+    String FLAG_USERNAME = "-name";
+    /** The password option */
+    String FLAG_PASSWORD = "-password";
+    /** The log option */
+    String FLAG_COMMENT = "-log";
+    /** The workdir option */
+    String FLAG_WORKING_DIR = "-workdir";
+    /** The recursive option */
+    String FLAG_RECURSION = "-recursive";
+    /** The revision option */
+    String FLAG_VERSION = "-revision";
+    /** The label option */
+    String FLAG_LABEL = "-label";
+    /** The no compression option */
+    String FLAG_NO_COMPRESSION = "-nocompress";
+    /** The no cache option */
+    String FLAG_NO_CACHE = "-nocache";
+    /** The server option */
+    String FLAG_SOS_SERVER = "-server";
+    /** The sos home option */
+    String FLAG_SOS_HOME = "-soshome";
+    /** The project option */
+    String FLAG_PROJECT = "-project";
+    /** The file option */
+    String FLAG_FILE = "-file";
+    /** The verbose option */
+    String FLAG_VERBOSE = "-verbose";
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java
new file mode 100644
index 0000000..cdbf92b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSGet.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Retrieves a read-only copy of the specified project or file
+ * from Visual SourceSafe via a SourceOffSite server.
+ *
+ * @ant.task name="sosget" category="scm"
+ */
+public class SOSGet extends SOS {
+
+    /**
+     * The Filename to act upon.
+     * If no file is specified then the tasks
+     * act upon the project.
+     *
+     * @param  filename  The new file value
+     */
+    public final void setFile(String filename) {
+        super.setInternalFilename(filename);
+    }
+
+    /**
+     * Flag to recursively apply the action. Defaults to false
+     *
+     * @param  recursive  True for recursive operation.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Set the version number to get -
+     * only works with SOSGet on a file.
+     *
+     * @param  version  The new version value
+     */
+    public void setVersion(String version) {
+        super.setInternalVersion(version);
+    }
+
+    /**
+     * The labeled version to operate on in SourceSafe.
+     *
+     * @param  label  The new label value
+     */
+    public void setLabel(String label) {
+        super.setInternalLabel(label);
+    }
+
+    /**
+     * Build the command line <br>
+     *
+     * GetFile required parameters: -server -name -password -database -project -file<br>
+     * GetFile optional parameters: -workdir -revision -verbose -nocache -nocompression -soshome<br>
+     *
+     * GetProject required parameters: -server -name -password -database -project<br>
+     * GetProject optional parameters: -label -workdir -recursive -verbose -nocache
+     * -nocompression -soshome<br>
+     *
+     * @return    Commandline the generated command to be executed
+     */
+    protected Commandline buildCmdLine() {
+        commandLine = new Commandline();
+
+        // If we find a "file" attribute then act on a file otherwise act on a project
+        if (getFilename() != null) {
+            // add -command GetFile to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_GET_FILE);
+            // add -file xxxxx to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_FILE);
+            commandLine.createArgument().setValue(getFilename());
+            // look for a version attribute
+            if (getVersion() != null) {
+                //add -revision xxxxx to the commandline
+                commandLine.createArgument().setValue(SOSCmd.FLAG_VERSION);
+                commandLine.createArgument().setValue(getVersion());
+            }
+        } else {
+            // add -command GetProject to the commandline
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+            commandLine.createArgument().setValue(SOSCmd.COMMAND_GET_PROJECT);
+            // look for a recursive option
+            commandLine.createArgument().setValue(getRecursive());
+            // look for a label option
+            if (getLabel() != null) {
+                commandLine.createArgument().setValue(SOSCmd.FLAG_LABEL);
+                commandLine.createArgument().setValue(getLabel());
+            }
+        }
+
+        getRequiredAttributes();
+        getOptionalAttributes();
+
+        return commandLine;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java
new file mode 100644
index 0000000..dd6b13a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/SOSLabel.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Labels Visual SourceSafe files via a SourceOffSite server.
+ *
+ * @ant.task name="soslabel" category="scm"
+ */
+public class SOSLabel extends SOS {
+
+    /**
+     * The version number to label.
+     *
+     * @param  version  The new version value
+     */
+    public void setVersion(String version) {
+        super.setInternalVersion(version);
+    }
+
+    /**
+     * The label to apply the the files in SourceSafe.
+     *
+     * @param  label  The new label value
+     *
+     * @ant.attribute group="required"
+     */
+    public void setLabel(String label) {
+        super.setInternalLabel(label);
+    }
+
+    /**
+     * The comment to apply to all files being labelled.
+     *
+     * @param  comment  The new comment value
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+
+    /**
+     *  Build the command line <br>
+     *  AddLabel required parameters: -server -name -password -database -project -label<br>
+     *  AddLabel optional parameters: -verbose -comment<br>
+     *
+     * @return    Commandline the generated command to be executed
+     */
+    protected Commandline buildCmdLine() {
+        commandLine = new Commandline();
+
+        // add -command AddLabel to the commandline
+        commandLine.createArgument().setValue(SOSCmd.FLAG_COMMAND);
+        commandLine.createArgument().setValue(SOSCmd.COMMAND_LABEL);
+
+        getRequiredAttributes();
+
+        // a label is required
+        if (getLabel() == null) {
+            throw new BuildException("label attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(SOSCmd.FLAG_LABEL);
+        commandLine.createArgument().setValue(getLabel());
+
+        // -verbose
+        commandLine.createArgument().setValue(getVerbose());
+        // Look for a comment
+        if (getComment() != null) {
+            commandLine.createArgument().setValue(SOSCmd.FLAG_COMMENT);
+            commandLine.createArgument().setValue(getComment());
+        }
+        return commandLine;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html
new file mode 100644
index 0000000..a0538c2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sos/package.html
@@ -0,0 +1,29 @@
+<html>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<body>
+  <p>
+    Ant tasks for working with a SourceOffSite source control system.
+  </p>
+  <p>
+    The &lt;SOSGet&gt; Retreives file(s) from a SOS database<br>
+    The &lt;SOSCheckin&gt; Commits and unlocks file(s) in a SOS database<br>
+    The &lt;SOSCheckout&gt; Retreives and lock file(s) in a SOS database<br>
+    The &lt;SOSLabel&gt; Label a SOS database<br>
+  </p>
+</body>
+</html>
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java
new file mode 100644
index 0000000..6d1966c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/AntSoundPlayer.java
@@ -0,0 +1,241 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.sound;
+
+// ant includes
+import java.io.File;
+import java.io.IOException;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineEvent;
+import javax.sound.sampled.LineListener;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.Project;
+
+
+
+/**
+ * This class is designed to be used by any AntTask that requires audio output.
+ *
+ * It implements the BuildListener interface to listen for BuildEvents and could
+ * be easily extended to provide audio output upon any specific build events occuring.
+ *
+ * I have only tested this with .WAV and .AIFF sound file formats. Both seem to work fine.
+ *
+ */
+
+public class AntSoundPlayer implements LineListener, BuildListener {
+
+    private File fileSuccess = null;
+    private int loopsSuccess = 0;
+    private Long durationSuccess = null;
+
+    private File fileFail = null;
+    private int loopsFail = 0;
+    private Long durationFail = null;
+
+    /** Constructor for AntSoundPlayer. */
+    public AntSoundPlayer() {
+    }
+
+    /**
+     * @param file the location of the audio file to be played when the
+     *        build is successful
+     * @param loops the number of times the file should be played when
+     *        the build is successful
+     * @param duration the number of milliseconds the file should be
+     *        played when the build is successful
+     */
+    public void addBuildSuccessfulSound(File file, int loops, Long duration) {
+        this.fileSuccess = file;
+        this.loopsSuccess = loops;
+        this.durationSuccess = duration;
+    }
+
+
+    /**
+     * @param fileFail the location of the audio file to be played
+     *        when the build fails
+     * @param loopsFail the number of times the file should be played
+     *        when the build is fails
+     * @param durationFail the number of milliseconds the file should be
+     *        played when the build fails
+     */
+    public void addBuildFailedSound(File fileFail, int loopsFail, Long durationFail) {
+        this.fileFail = fileFail;
+        this.loopsFail = loopsFail;
+        this.durationFail = durationFail;
+    }
+
+    /**
+     * Plays the file for duration milliseconds or loops.
+     */
+    private void play(Project project, File file, int loops, Long duration) {
+
+        Clip audioClip = null;
+
+        AudioInputStream audioInputStream = null;
+
+
+        try {
+            audioInputStream = AudioSystem.getAudioInputStream(file);
+        } catch (UnsupportedAudioFileException uafe) {
+            project.log("Audio format is not yet supported: "
+                + uafe.getMessage());
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+
+        if (audioInputStream != null) {
+            AudioFormat format = audioInputStream.getFormat();
+            DataLine.Info   info = new DataLine.Info(Clip.class, format,
+                                             AudioSystem.NOT_SPECIFIED);
+            try {
+                audioClip = (Clip) AudioSystem.getLine(info);
+                audioClip.addLineListener(this);
+                audioClip.open(audioInputStream);
+            } catch (LineUnavailableException e) {
+                project.log("The sound device is currently unavailable");
+                return;
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+            if (duration != null) {
+                playClip(audioClip, duration.longValue());
+            } else {
+                playClip(audioClip, loops);
+            }
+            audioClip.drain();
+            audioClip.close();
+        } else {
+            project.log("Can't get data from file " + file.getName());
+        }
+    }
+
+    private void playClip(Clip clip, int loops) {
+
+        clip.loop(loops);
+        while (clip.isRunning()) {
+            // Empty block
+        }
+    }
+
+    private void playClip(Clip clip, long duration) {
+        clip.loop(Clip.LOOP_CONTINUOUSLY);
+        try {
+            Thread.sleep(duration);
+        } catch (InterruptedException e) {
+            // Ignore Exception
+        }
+    }
+
+    /**
+     * This is implemented to listen for any line events and closes the
+     * clip if required.
+     * @param event the line event to follow
+     */
+    public void update(LineEvent event) {
+        if (event.getType().equals(LineEvent.Type.STOP)) {
+            Line line = event.getLine();
+            line.close();
+        } else if (event.getType().equals(LineEvent.Type.CLOSE)) {
+            /*
+             *  There is a bug in JavaSound 0.90 (jdk1.3beta).
+             *  It prevents correct termination of the VM.
+             *  So we have to exit ourselves.
+             */
+            //System.exit(0);
+        }
+    }
+
+
+    /**
+     *  Fired before any targets are started.
+     * @param event ignored
+     */
+    public void buildStarted(BuildEvent event) {
+    }
+
+    /**
+     *  Fired after the last target has finished. This event
+     *  will still be thrown if an error occurred during the build.
+     * @param event the build finished event.
+     *  @see BuildEvent#getException()
+     */
+    public void buildFinished(BuildEvent event) {
+        if (event.getException() == null && fileSuccess != null) {
+            // build successfull!
+            play(event.getProject(), fileSuccess, loopsSuccess, durationSuccess);
+        } else if (event.getException() != null && fileFail != null) {
+            play(event.getProject(), fileFail, loopsFail, durationFail);
+        }
+    }
+
+    /**
+     *  Fired when a target is started.
+     * @param event ignored.
+     *  @see BuildEvent#getTarget()
+     */
+    public void targetStarted(BuildEvent event) {
+    }
+
+    /**
+     *  Fired when a target has finished. This event will
+     *  still be thrown if an error occurred during the build.
+     * @param event ignored.
+     *  @see BuildEvent#getException()
+     */
+    public void targetFinished(BuildEvent event) {
+    }
+
+    /**
+     *  Fired when a task is started.
+     * @param event ignored.
+     *  @see BuildEvent#getTask()
+     */
+    public void taskStarted(BuildEvent event) {
+    }
+
+    /**
+     *  Fired when a task has finished. This event will still
+     *  be throw if an error occurred during the build.
+     * @param event ignored.
+     *  @see BuildEvent#getException()
+     */
+    public void taskFinished(BuildEvent event) {
+    }
+
+    /**
+     *  Fired whenever a message is logged.
+     *  @param event the build event
+     *  @see BuildEvent#getMessage()
+     *  @see BuildEvent#getPriority()
+     */
+    public void messageLogged(BuildEvent event) {
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java
new file mode 100644
index 0000000..b55470a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/sound/SoundTask.java
@@ -0,0 +1,192 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.sound;
+
+import java.io.File;
+import java.util.Random;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * Plays a sound file at the end of the build, according to whether the build failed or succeeded.
+ *
+ * There are three attributes to be set:
+ *
+ * <code>source</code>: the location of the audio file to be played
+ * <code>duration</code>: play the sound file continuously until "duration" milliseconds has expired
+ * <code>loops</code>: the number of times the sound file should be played until stopped
+ *
+ * I have only tested this with .WAV and .AIFF sound file formats. Both seem
+ * to work fine.
+ *
+ * plans for the future:
+ * - use the midi api to define sounds (or drum beat etc) in xml and have
+ *   Ant play them back
+ *
+ */
+
+public class SoundTask extends Task {
+
+    private BuildAlert success = null;
+    private BuildAlert fail = null;
+
+    /**
+     * add a sound when the build succeeds
+     * @return a BuildAlert to be configured
+     */
+    public BuildAlert createSuccess() {
+        success = new BuildAlert();
+        return success;
+    }
+
+    /**
+     * add a sound when the build fails
+     * @return a BuildAlert to be configured
+     */
+    public BuildAlert createFail() {
+        fail = new BuildAlert();
+        return fail;
+     }
+
+    /** Constructor for SoundTask. */
+    public SoundTask() {
+    }
+
+    /**
+     * Initialize the task.
+     */
+    public void init() {
+    }
+
+    /**
+     * Execute the task.
+     */
+    public void execute() {
+
+        AntSoundPlayer soundPlayer = new AntSoundPlayer();
+
+        if (success == null) {
+            log("No nested success element found.", Project.MSG_WARN);
+        } else {
+            soundPlayer.addBuildSuccessfulSound(success.getSource(),
+              success.getLoops(), success.getDuration());
+        }
+
+        if (fail == null) {
+            log("No nested failure element found.", Project.MSG_WARN);
+        } else {
+            soundPlayer.addBuildFailedSound(fail.getSource(),
+              fail.getLoops(), fail.getDuration());
+        }
+
+        getProject().addBuildListener(soundPlayer);
+
+    }
+
+    /**
+     * A class to be extended by any BuildAlert's that require the output
+     * of sound.
+     */
+    public class BuildAlert {
+        private File source = null;
+        private int loops = 0;
+        private Long duration = null;
+
+        /**
+         * Sets the duration in milliseconds the file should be played; optional.
+         * @param duration the duration in millisconds
+         */
+        public void setDuration(Long duration) {
+            this.duration = duration;
+        }
+
+        /**
+         * Sets the location of the file to get the audio; required.
+         *
+         * @param source the name of a sound-file directory or of the audio file
+         */
+        public void setSource(File source) {
+            this.source = source;
+        }
+
+        /**
+         * Sets the number of times the source file should be played; optional.
+         *
+         * @param loops the number of loops to play the source file
+         */
+        public void setLoops(int loops) {
+            this.loops = loops;
+        }
+
+        /**
+         * Gets the location of the file to get the audio.
+         * @return the file location
+         */
+        public File getSource() {
+            File nofile = null;
+            // Check if source is a directory
+            if (source.exists()) {
+                if (source.isDirectory()) {
+                    // get the list of files in the dir
+                    String[] entries = source.list();
+                    Vector files = new Vector();
+                    for (int i = 0; i < entries.length; i++) {
+                        File f = new File(source, entries[i]);
+                        if (f.isFile()) {
+                            files.addElement(f);
+                        }
+                    }
+                    if (files.size() < 1) {
+                        throw new BuildException("No files found in directory " + source);
+                    }
+                    int numfiles = files.size();
+                    // get a random number between 0 and the number of files
+                    Random rn = new Random();
+                    int x = rn.nextInt(numfiles);
+                    // set the source to the file at that location
+                    this.source = (File) files.elementAt(x);
+                }
+            } else {
+                log(source + ": invalid path.", Project.MSG_WARN);
+                this.source = nofile;
+            }
+            return this.source;
+        }
+
+        /**
+         * Sets the number of times the source file should be played.
+         *
+         * @return the number of loops to play the source file
+         */
+        public int getLoops() {
+            return this.loops;
+        }
+
+        /**
+         * Gets the duration in milliseconds the file should be played.
+         * @return the duration in milliseconds
+         */
+        public Long getDuration() {
+            return this.duration;
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java
new file mode 100644
index 0000000..49863b2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashScreen.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.splash;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JWindow;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+
+class SplashScreen extends JWindow implements ActionListener, BuildListener {
+    private static final int FONT_SIZE = 12;
+    private JLabel text;
+    private JProgressBar pb;
+    private int total;
+    private static final int MIN = 0;
+    private static final int MAX = 200;
+
+    public SplashScreen(String msg) {
+        init(null);
+        setText(msg);
+    }
+
+    public SplashScreen(ImageIcon img) {
+        init(img);
+    }
+
+    protected void init(ImageIcon img) {
+
+        JPanel pan = (JPanel) getContentPane();
+        JLabel piccy;
+        if (img == null) {
+            piccy = new JLabel();
+        } else {
+            piccy = new JLabel(img);
+        }
+
+        piccy.setBorder(BorderFactory.createLineBorder(Color.black, 1));
+        text = new JLabel("Building....", JLabel.CENTER);
+        text.setFont(new Font("Sans-Serif", Font.BOLD, FONT_SIZE));
+        text.setBorder(BorderFactory.createEtchedBorder());
+
+        pb = new JProgressBar(MIN, MAX);
+        pb.setBorder(BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
+        JPanel pan2 = new JPanel();
+        pan2.setLayout(new BorderLayout());
+
+        pan2.add(text, BorderLayout.NORTH);
+        pan2.add(pb, BorderLayout.SOUTH);
+
+        pan.setLayout(new BorderLayout());
+        pan.add(piccy, BorderLayout.CENTER);
+        pan.add(pan2, BorderLayout.SOUTH);
+
+        pan.setBorder(BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
+
+        pack();
+
+        Dimension size = getSize();
+        Dimension scr = Toolkit.getDefaultToolkit().getScreenSize();
+        int x = (scr.width - size.width) / 2;
+        int y = (scr.height - size.height) / 2;
+        setBounds(x, y, size.width, size.height);
+    }
+
+    public void setText(String txt) {
+        text.setText(txt);
+    }
+
+    public void actionPerformed(ActionEvent a) {
+        if (total < MAX) {
+            total++;
+        } else {
+            total = MIN;
+        }
+        pb.setValue(total);
+    }
+
+    public void buildStarted(BuildEvent event) {
+        actionPerformed(null);
+    }
+
+    public void buildFinished(BuildEvent event) {
+        pb.setValue(MAX);
+        setVisible(false);
+        dispose();
+    }
+    public void targetStarted(BuildEvent event) {
+        actionPerformed(null);
+    }
+
+    public void targetFinished(BuildEvent event) {
+        actionPerformed(null);
+    }
+
+    public void taskStarted(BuildEvent event) {
+        actionPerformed(null);
+    }
+
+    public void taskFinished(BuildEvent event) {
+        actionPerformed(null);
+    }
+
+    public void messageLogged(BuildEvent event) {
+        actionPerformed(null);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java
new file mode 100644
index 0000000..768a49c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/splash/SplashTask.java
@@ -0,0 +1,248 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.splash;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import javax.swing.ImageIcon;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.Base64Converter;
+
+/**
+ * Creates a splash screen. The splash screen is displayed
+ * for the duration of the build and includes a handy progress bar as
+ * well. Use in conjunction with the sound task to provide interest
+ * whilst waiting for your builds to complete...
+ * @since Ant1.5
+ */
+public class SplashTask extends Task {
+    private static final int DEFAULT_SHOW_DURATION = 5000;
+
+    private String imgurl = null;
+    private String proxy = null;
+    private String user = null;
+    private String password = null;
+    private String port = "80";
+    private int showDuration = DEFAULT_SHOW_DURATION;
+    private boolean useProxy = false;
+
+    private static SplashScreen splash = null;
+
+    /**
+     * A URL pointing to an image to display; optional, default antlogo.gif
+     * from the classpath.
+     * @param imgurl the url string pointing to the image
+     */
+    public void setImageURL(String imgurl) {
+        this.imgurl = imgurl;
+    }
+
+    /**
+     * flag to enable proxy settings; optional, deprecated : consider
+     * using &lt;setproxy&gt; instead
+     * @param useProxy if ture, enable proxy settings
+     * @deprecated since 1.5.x.
+     *             Use org.apache.tools.ant.taskdefs.optional.SetProxy
+     */
+    public void setUseproxy(boolean useProxy) {
+        this.useProxy = useProxy;
+    }
+
+    /**
+     * name of proxy; optional.
+     * @param proxy the name of the proxy host
+     */
+    public void setProxy(String proxy) {
+        this.proxy = proxy;
+    }
+
+    /**
+     * Proxy port; optional, default 80.
+     * @param port the proxy port
+     */
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    /**
+     * Proxy user; optional, default =none.
+     * @param user the proxy user
+     */
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    /**
+     * Proxy password; required if <tt>user</tt> is set.
+     * @param password the proxy password
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * how long to show the splash screen in milliseconds,
+     * optional; default 5000 ms.
+     * @param duration the spash duration in milliseconds
+     */
+    public void setShowduration(int duration) {
+        this.showDuration = duration;
+    }
+
+
+    /**
+     * Execute the task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (splash != null) {
+            splash.setVisible(false);
+            getProject().removeBuildListener(splash);
+            splash.dispose();
+            splash = null;
+        }
+
+        log("Creating new SplashScreen", Project.MSG_VERBOSE);
+        InputStream in = null;
+
+        if (imgurl != null) {
+            try {
+                URLConnection conn = null;
+
+                if (useProxy && (proxy != null && proxy.length() > 0)
+                    && (port != null && port.length() > 0)) {
+
+                    log("Using proxied Connection",  Project.MSG_DEBUG);
+                    System.getProperties().put("http.proxySet", "true");
+                    System.getProperties().put("http.proxyHost", proxy);
+                    System.getProperties().put("http.proxyPort", port);
+
+                    URL url = new URL(imgurl);
+
+                    conn = url.openConnection();
+                    if (user != null && user.length() > 0) {
+                        // converted from sun internal classes to
+                        // new Base64Converter
+                        // utility class extracted from Get task
+                        String encodedcreds =
+                            new Base64Converter().encode(user + ":" + password);
+                        conn.setRequestProperty("Proxy-Authorization",
+                                                encodedcreds);
+                    }
+
+                } else {
+                    System.getProperties().put("http.proxySet", "false");
+                    System.getProperties().put("http.proxyHost", "");
+                    System.getProperties().put("http.proxyPort", "");
+                    log("Using Direction HTTP Connection", Project.MSG_DEBUG);
+                    URL url = new URL(imgurl);
+                    conn = url.openConnection();
+                }
+                conn.setDoInput(true);
+                conn.setDoOutput(false);
+
+                in = conn.getInputStream();
+
+                // Catch everything - some of the above return nulls,
+                // throw exceptions or generally misbehave
+                // in the event of a problem etc
+
+            } catch (Throwable ioe) {
+                log("Unable to download image, trying default Ant Logo",
+                    Project.MSG_DEBUG);
+                log("(Exception was \"" + ioe.getMessage() + "\"",
+                    Project.MSG_DEBUG);
+            }
+        }
+
+        if (in == null) {
+            ClassLoader cl = SplashTask.class.getClassLoader();
+            if (cl != null) {
+                in = cl.getResourceAsStream("images/ant_logo_large.gif");
+            } else {
+                in = ClassLoader
+                    .getSystemResourceAsStream("images/ant_logo_large.gif");
+            }
+        }
+
+        boolean success = false;
+        if (in != null) {
+            DataInputStream din = new DataInputStream(in);
+            try {
+                ByteArrayOutputStream bout = new ByteArrayOutputStream();
+                int data;
+                while ((data = din.read()) != -1) {
+                    bout.write((byte) data);
+                }
+
+                log("Got ByteArray, creating splash",  Project.MSG_DEBUG);
+
+                try {
+                    ImageIcon img = new ImageIcon(bout.toByteArray());
+                    splash = new SplashScreen(img);
+                    success = true;
+                } catch (Throwable e) {
+                    logHeadless(e);
+                }
+            } catch (Exception e) {
+                throw new BuildException(e);
+            } finally {
+                try {
+                    din.close();
+                } catch (IOException ioe) {
+                    // swallow if there was an error before so that
+                    // original error will be passed up
+                    if (success) {
+                        throw new BuildException(ioe);
+                    }
+                }
+            }
+        } else {
+            try {
+                splash = new SplashScreen("Image Unavailable.");
+                success = true;
+            } catch (Throwable e) {
+                logHeadless(e);
+            }
+        }
+
+        if (success) {
+            splash.setVisible(true);
+            splash.toFront();
+            getProject().addBuildListener(splash);
+            try {
+                Thread.sleep(showDuration);
+            } catch (InterruptedException e) {
+                // Ignore Exception
+            }
+        }
+    }
+
+    private void logHeadless(Throwable e) {
+        log("failed to display SplashScreen, caught "
+            + e.getClass().getName() + " with message: " + e.getMessage(),
+            Project.MSG_WARN);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java
new file mode 100644
index 0000000..04dbb88
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/AbstractSshMessage.java
@@ -0,0 +1,272 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.text.NumberFormat;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Abstract class for ssh upload and download
+ */
+public abstract class AbstractSshMessage {
+    private static final double ONE_SECOND = 1000.0;
+
+    private Session session;
+    private boolean verbose;
+    private LogListener listener = new LogListener() {
+        public void log(String message) {
+            // do nothing;
+        }
+    };
+
+    /**
+     * Constructor for AbstractSshMessage
+     * @param session the ssh session to use
+     */
+    public AbstractSshMessage(Session session) {
+        this(false, session);
+    }
+
+    /**
+     * Constructor for AbstractSshMessage
+     * @param verbose if true do verbose logging
+     * @param session the ssh session to use
+     * @since Ant 1.6.2
+     */
+    public AbstractSshMessage(boolean verbose, Session session) {
+        this.verbose = verbose;
+        this.session = session;
+    }
+
+    /**
+     * Open an ssh channel.
+     * @param command the command to use
+     * @return the channel
+     * @throws JSchException on error
+     */
+    protected Channel openExecChannel(String command) throws JSchException {
+        ChannelExec channel = (ChannelExec) session.openChannel("exec");
+        channel.setCommand(command);
+
+        return channel;
+    }
+
+    /**
+     * Open an ssh sftp channel.
+     * @return the channel
+     * @throws JSchException on error
+     */
+    protected ChannelSftp openSftpChannel() throws JSchException {
+        ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
+
+        return channel;
+    }
+
+    /**
+     * Send an ack.
+     * @param out the output stream to use
+     * @throws IOException on error
+     */
+    protected void sendAck(OutputStream out) throws IOException {
+        byte[] buf = new byte[1];
+        buf[0] = 0;
+        out.write(buf);
+        out.flush();
+    }
+
+    /**
+     * Reads the response, throws a BuildException if the response
+     * indicates an error.
+     * @param in the input stream to use
+     * @throws IOException on I/O error
+     * @throws BuildException on other errors
+     */
+    protected void waitForAck(InputStream in)
+        throws IOException, BuildException {
+        int b = in.read();
+
+        // b may be 0 for success,
+        //          1 for error,
+        //          2 for fatal error,
+
+        if (b == -1) {
+            // didn't receive any response
+            throw new BuildException("No response from server");
+        } else if (b != 0) {
+            StringBuffer sb = new StringBuffer();
+
+            int c = in.read();
+            while (c > 0 && c != '\n') {
+                sb.append((char) c);
+                c = in.read();
+            }
+
+            if (b == 1) {
+                throw new BuildException("server indicated an error: "
+                                         + sb.toString());
+            } else if (b == 2) {
+                throw new BuildException("server indicated a fatal error: "
+                                         + sb.toString());
+            } else {
+                throw new BuildException("unknown response, code " + b
+                                         + " message: " + sb.toString());
+            }
+        }
+    }
+
+    /**
+     * Carry out the transfer.
+     * @throws IOException on I/O errors
+     * @throws JSchException on ssh errors
+     */
+    public abstract void execute() throws IOException, JSchException;
+
+    /**
+     * Set a log listener.
+     * @param aListener the log listener
+     */
+    public void setLogListener(LogListener aListener) {
+        listener = aListener;
+    }
+
+    /**
+     * Log a message to the log listener.
+     * @param message the message to log
+     */
+    protected void log(String message) {
+        listener.log(message);
+    }
+
+    /**
+     * Log transfer stats to the log listener.
+     * @param timeStarted the time started
+     * @param timeEnded   the finishing time
+     * @param totalLength the total length
+     */
+    protected void logStats(long timeStarted,
+                             long timeEnded,
+                             long totalLength) {
+        double duration = (timeEnded - timeStarted) / ONE_SECOND;
+        NumberFormat format = NumberFormat.getNumberInstance();
+        format.setMaximumFractionDigits(2);
+        format.setMinimumFractionDigits(1);
+        listener.log("File transfer time: " + format.format(duration)
+            + " Average Rate: " + format.format(totalLength / duration)
+            + " B/s");
+    }
+
+    /**
+     * Is the verbose attribute set.
+     * @return true if the verbose attribute is set
+     * @since Ant 1.6.2
+     */
+    protected final boolean getVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Track progress every 10% if 100kb < filesize < 1mb. For larger
+     * files track progress for every percent transmitted.
+     * @param filesize the size of the file been transmitted
+     * @param totalLength the total transmission size
+     * @param percentTransmitted the current percent transmitted
+     * @return the percent that the file is of the total
+     */
+    protected final int trackProgress(long filesize, long totalLength,
+                                      int percentTransmitted) {
+
+        // CheckStyle:MagicNumber OFF
+        int percent = (int) Math.round(Math.floor((totalLength
+                                                   / (double) filesize) * 100));
+
+        if (percent > percentTransmitted) {
+            if (filesize < 1048576) {
+                if (percent % 10 == 0) {
+                    if (percent == 100) {
+                        System.out.println(" 100%");
+                    } else {
+                        System.out.print("*");
+                    }
+                }
+            } else {
+                if (percent == 50) {
+                    System.out.println(" 50%");
+                } else if (percent == 100) {
+                    System.out.println(" 100%");
+                } else {
+                    System.out.print(".");
+                }
+            }
+        }
+        // CheckStyle:MagicNumber ON
+
+        return percent;
+    }
+
+    private ProgressMonitor monitor = null;
+
+    /**
+     * Get the progress monitor.
+     * @return the progress monitor.
+     */
+    protected SftpProgressMonitor getProgressMonitor() {
+        if (monitor == null) {
+            monitor = new ProgressMonitor();
+        }
+        return monitor;
+    }
+
+    private class ProgressMonitor implements SftpProgressMonitor {
+        private long initFileSize = 0;
+        private long totalLength = 0;
+        private int percentTransmitted = 0;
+
+        public void init(int op, String src, String dest, long max) {
+            initFileSize = max;
+            totalLength = 0;
+            percentTransmitted = 0;
+        }
+
+        public boolean count(long len) {
+            totalLength += len;
+            percentTransmitted = trackProgress(initFileSize,
+                                               totalLength,
+                                               percentTransmitted);
+            return true;
+        }
+
+        public void end() {
+        }
+
+        public long getTotalLength() {
+            return totalLength;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java
new file mode 100644
index 0000000..ab2b5b2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Directory.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.StringTokenizer;
+import java.io.File;
+
+/**
+ * A helper object for Scp representing a directory in a file system.
+ */
+public class Directory {
+
+    private File directory;
+    private ArrayList childDirectories;
+    private ArrayList files;
+    private Directory parent;
+
+    /**
+     * Constructor for a Directory.
+     * @param directory a directory.
+     */
+    public Directory(File directory) {
+        this(directory,  null);
+    }
+
+    /**
+     * Constructor for a Directory.
+     * @param directory a directory
+     * @param parent    a parent Directory
+     */
+    public Directory(File directory , Directory parent) {
+        this.parent = parent;
+        this.childDirectories = new ArrayList();
+        this.files = new ArrayList();
+        this.directory = directory;
+    }
+
+    /**
+     * Add a directory to the child directories.
+     * @param directory a Directory
+     */
+    public void addDirectory(Directory directory) {
+        if (!childDirectories.contains(directory)) {
+            childDirectories.add(directory);
+        }
+    }
+
+    /**
+     * Add a file to the list of files.
+     * @param file a file to add
+     */
+    public void addFile(File file) {
+        files.add(file);
+    }
+
+    /**
+     * Get an iterator over the child Directories.
+     * @return an iterator
+     */
+    public Iterator directoryIterator() {
+        return childDirectories.iterator();
+    }
+
+    /**
+     * Get an iterator over the files.
+     * @return an iterator
+     */
+    public Iterator filesIterator() {
+        return files.iterator();
+    }
+
+    /**
+     * Get the parent Directory.
+     * @return the parent Directory.
+     */
+    public Directory getParent() {
+        return parent;
+    }
+
+    /**
+     * Is this a root Directory?
+     * @return true if there is no parent Directory
+     */
+    public boolean isRoot() {
+        return parent == null;
+    }
+
+    /**
+     * Get the directory file.
+     * @return the directory file
+     */
+    public File getDirectory() {
+        return directory;
+    }
+
+    /**
+     * Get a child directory of this directory.
+     * @param dir the directory to look for
+     * @return the child directory, or null if not found
+     */
+    public Directory getChild(File dir) {
+        for (int i = 0; i < childDirectories.size(); i++) {
+            Directory current = (Directory) childDirectories.get(i);
+            if (current.getDirectory().equals(dir)) {
+                return current;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * The equality method.
+     * This checks if the directory field is the same.
+     * @param obj the object to compare to
+     * @return true if this object has an equal directory field as the other object
+     */
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (!(obj instanceof Directory)) {
+            return false;
+        }
+
+        Directory d = (Directory) obj;
+
+        return this.directory.equals(d.directory);
+    }
+
+    /**
+     * The hashcode method.
+     * @return the hash code of the directory field
+     */
+    public int hashCode() {
+        return directory.hashCode();
+    }
+
+    /**
+     * Get the path components of this directory.
+     * @return the path components as an array of strings.
+     */
+    public String[] getPath() {
+        return getPath(directory.getAbsolutePath());
+    }
+
+    /**
+     * Convert a file path to an array of path components.
+     * This uses File.sepatator to split the file path string.
+     * @param thePath the file path string to convert
+     * @return an array of path components
+     */
+    public static String[] getPath(String thePath) {
+        StringTokenizer tokenizer = new StringTokenizer(thePath,
+                File.separator);
+        String[] path = new String[ tokenizer.countTokens() ];
+
+        int i = 0;
+        while (tokenizer.hasMoreTokens()) {
+            path[i] = tokenizer.nextToken();
+            i++;
+        }
+
+        return path;
+    }
+
+    /**
+     * Get the number of files in the files attribute.
+     * @return the number of files
+     */
+    public int fileSize() {
+        return files.size();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java
new file mode 100644
index 0000000..824e257
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/LogListener.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+/**
+ * Interface for ssh log listeners to implement.
+ */
+public interface LogListener {
+    /**
+     * Method for the loglistener to implement to recieve log messages.
+     * @param message the message to log
+     */
+    void log(String message);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
new file mode 100644
index 0000000..543998c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHBase.java
@@ -0,0 +1,223 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.JSch;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Base class for Ant tasks using jsch.
+ *
+ * @since Ant 1.6
+ */
+public abstract class SSHBase extends Task implements LogListener {
+
+    /** Default listen port for SSH daemon */
+    private static final int SSH_PORT = 22;
+
+    private String host;
+    private String knownHosts;
+    private int port = SSH_PORT;
+    private boolean failOnError = true;
+    private boolean verbose;
+    private SSHUserInfo userInfo;
+
+    /**
+     * Constructor for SSHBase.
+     */
+    public SSHBase() {
+        super();
+        userInfo = new SSHUserInfo();
+    }
+
+    /**
+     * Remote host, either DNS name or IP.
+     *
+     * @param host  The new host value
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * Get the host.
+     * @return the host
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Set the failonerror flag.
+     * Default is true
+     * @param failure if true throw a build exception when a failure occuries,
+     *                otherwise just log the failure and continue
+     */
+    public void setFailonerror(boolean failure) {
+        failOnError = failure;
+    }
+
+    /**
+     * Get the failonerror flag.
+     * @return the failonerror flag
+     */
+    public boolean getFailonerror() {
+        return failOnError;
+    }
+
+    /**
+     * Set the verbose flag.
+     * @param verbose if true output more verbose logging
+     * @since Ant 1.6.2
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Get the verbose flag.
+     * @return the verbose flag
+     * @since Ant 1.6.2
+     */
+    public boolean getVerbose() {
+        return verbose;
+    }
+
+    /**
+     * Username known to remote host.
+     *
+     * @param username  The new username value
+     */
+    public void setUsername(String username) {
+        userInfo.setName(username);
+    }
+
+
+    /**
+     * Sets the password for the user.
+     *
+     * @param password  The new password value
+     */
+    public void setPassword(String password) {
+        userInfo.setPassword(password);
+    }
+
+    /**
+     * Sets the keyfile for the user.
+     *
+     * @param keyfile  The new keyfile value
+     */
+    public void setKeyfile(String keyfile) {
+        userInfo.setKeyfile(keyfile);
+    }
+
+    /**
+     * Sets the passphrase for the users key.
+     *
+     * @param passphrase  The new passphrase value
+     */
+    public void setPassphrase(String passphrase) {
+        userInfo.setPassphrase(passphrase);
+    }
+
+    /**
+     * Sets the path to the file that has the identities of
+     * all known hosts.  This is used by SSH protocol to validate
+     * the identity of the host.  The default is
+     * <i>${user.home}/.ssh/known_hosts</i>.
+     *
+     * @param knownHosts a path to the known hosts file.
+     */
+    public void setKnownhosts(String knownHosts) {
+        this.knownHosts = knownHosts;
+    }
+
+    /**
+     * Setting this to true trusts hosts whose identity is unknown.
+     *
+     * @param yesOrNo if true trust the identity of unknown hosts.
+     */
+    public void setTrust(boolean yesOrNo) {
+        userInfo.setTrust(yesOrNo);
+    }
+
+    /**
+     * Changes the port used to connect to the remote host.
+     *
+     * @param port port number of remote host.
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Get the port attribute.
+     * @return the port
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Initialize the task.
+     * This initializizs the known hosts and sets the default port.
+     * @throws BuildException on error
+     */
+    public void init() throws BuildException {
+        super.init();
+        this.knownHosts = System.getProperty("user.home") + "/.ssh/known_hosts";
+        this.port = SSH_PORT;
+    }
+
+    /**
+     * Open an ssh seession.
+     * @return the opened session
+     * @throws JSchException on error
+     */
+    protected Session openSession() throws JSchException {
+        JSch jsch = new JSch();
+        if (null != userInfo.getKeyfile()) {
+            jsch.addIdentity(userInfo.getKeyfile());
+        }
+
+        if (!userInfo.getTrust() && knownHosts != null) {
+            log("Using known hosts: " + knownHosts, Project.MSG_DEBUG);
+            jsch.setKnownHosts(knownHosts);
+        }
+
+        Session session = jsch.getSession(userInfo.getName(), host, port);
+        session.setUserInfo(userInfo);
+        log("Connecting to " + host + ":" + port);
+        session.connect();
+        return session;
+    }
+
+    /**
+     * Get the user information.
+     * @return the user information
+     */
+    protected SSHUserInfo getUserInfo() {
+        return userInfo;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
new file mode 100644
index 0000000..1631539
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHExec.java
@@ -0,0 +1,313 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.KeepAliveOutputStream;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+/**
+ * Executes a command on a remote machine via ssh.
+ * @since     Ant 1.6 (created February 2, 2003)
+ */
+public class SSHExec extends SSHBase {
+
+    private static final int BUFFER_SIZE = 8192;
+    private static final int RETRY_INTERVAL = 500;
+
+    /** the command to execute via ssh */
+    private String command = null;
+
+    /** units are milliseconds, default is 0=infinite */
+    private long maxwait = 0;
+
+    /** for waiting for the command to finish */
+    private Thread thread = null;
+
+    private String outputProperty = null;   // like <exec>
+    private File outputFile = null;   // like <exec>
+    private boolean append = false;   // like <exec>
+
+    private Resource commandResource = null;
+
+    private static final String TIMEOUT_MESSAGE =
+        "Timeout period exceeded, connection dropped.";
+
+    /**
+     * Constructor for SSHExecTask.
+     */
+    public SSHExec() {
+        super();
+    }
+
+    /**
+     * Sets the command to execute on the remote host.
+     *
+     * @param command  The new command value
+     */
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    /**
+     * Sets a commandResource from a file
+     * @param f the value to use.
+     * @since Ant 1.7.1
+     */
+    public void setCommandResource(String f) {
+        this.commandResource = new FileResource(new File(f));
+    }
+
+    /**
+     * The connection can be dropped after a specified number of
+     * milliseconds. This is sometimes useful when a connection may be
+     * flaky. Default is 0, which means &quot;wait forever&quot;.
+     *
+     * @param timeout  The new timeout value in seconds
+     */
+    public void setTimeout(long timeout) {
+        maxwait = timeout;
+    }
+
+    /**
+     * If used, stores the output of the command to the given file.
+     *
+     * @param output  The file to write to.
+     */
+    public void setOutput(File output) {
+        outputFile = output;
+    }
+
+    /**
+     * Determines if the output is appended to the file given in
+     * <code>setOutput</code>. Default is false, that is, overwrite
+     * the file.
+     *
+     * @param append  True to append to an existing file, false to overwrite.
+     */
+    public void setAppend(boolean append) {
+        this.append = append;
+    }
+
+    /**
+     * If set, the output of the command will be stored in the given property.
+     *
+     * @param property  The name of the property in which the command output
+     *      will be stored.
+     */
+    public void setOutputproperty(String property) {
+        outputProperty = property;
+    }
+
+    /**
+     * Execute the command on the remote host.
+     *
+     * @exception BuildException  Most likely a network error or bad parameter.
+     */
+    public void execute() throws BuildException {
+        if (getHost() == null) {
+            throw new BuildException("Host is required.");
+        }
+        if (getUserInfo().getName() == null) {
+            throw new BuildException("Username is required.");
+        }
+        if (getUserInfo().getKeyfile() == null
+            && getUserInfo().getPassword() == null) {
+            throw new BuildException("Password or Keyfile is required.");
+        }
+        if (command == null && commandResource == null) {
+            throw new BuildException("Command or commandResource is required.");
+        }
+
+        Session session = null;
+
+        try {
+            session = openSession();
+            /* called once */
+            if (command != null) {
+                log("cmd : " + command, Project.MSG_INFO);
+                ByteArrayOutputStream out = executeCommand(session, command);
+                if (outputProperty != null) {
+                    //#bugzilla 43437
+                    getProject().setNewProperty(outputProperty, command + " : " + out);
+                }
+            } else { // read command resource and execute for each command
+                try {
+                    BufferedReader br = new BufferedReader(
+                            new InputStreamReader(commandResource.getInputStream()));
+                    String cmd;
+                    String output = "";
+                    while ((cmd = br.readLine()) != null) {
+                        log("cmd : " + cmd, Project.MSG_INFO);
+                        ByteArrayOutputStream out = executeCommand(session, cmd);
+                        output += cmd + " : " + out + "\n";
+                    }
+                    if (outputProperty != null) {
+                        //#bugzilla 43437
+                        getProject().setNewProperty(outputProperty, output);
+                    }
+                    FileUtils.close(br);
+                } catch (IOException e) {
+                    throw new BuildException(e);
+                }
+            }
+        } catch (JSchException e) {
+            throw new BuildException(e);
+        } finally {
+            if (session != null && session.isConnected()) {
+                session.disconnect();
+            }
+        }
+    }
+
+    private ByteArrayOutputStream executeCommand(Session session, String cmd)
+        throws BuildException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        TeeOutputStream tee = new TeeOutputStream(out, new KeepAliveOutputStream(System.out));
+
+        try {
+            final ChannelExec channel;
+            session.setTimeout((int) maxwait);
+            /* execute the command */
+            channel = (ChannelExec) session.openChannel("exec");
+            channel.setCommand(cmd);
+            channel.setOutputStream(tee);
+            channel.setExtOutputStream(tee);
+            channel.connect();
+            // wait for it to finish
+            thread =
+                new Thread() {
+                    public void run() {
+                        while (!channel.isClosed()) {
+                            if (thread == null) {
+                                return;
+                            }
+                            try {
+                                sleep(RETRY_INTERVAL);
+                            } catch (Exception e) {
+                                // ignored
+                            }
+                        }
+                    }
+                };
+
+            thread.start();
+            thread.join(maxwait);
+
+            if (thread.isAlive()) {
+                // ran out of time
+                thread = null;
+                if (getFailonerror()) {
+                    throw new BuildException(TIMEOUT_MESSAGE);
+                } else {
+                    log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+                }
+            } else {
+                //success
+                if (outputFile != null) {
+                    writeToFile(out.toString(), append, outputFile);
+                }
+
+                // this is the wrong test if the remote OS is OpenVMS,
+                // but there doesn't seem to be a way to detect it.
+                int ec = channel.getExitStatus();
+                if (ec != 0) {
+                    String msg = "Remote command failed with exit status " + ec;
+                    if (getFailonerror()) {
+                        throw new BuildException(msg);
+                    } else {
+                        log(msg, Project.MSG_ERR);
+                    }
+                }
+            }
+        } catch (BuildException e) {
+            throw e;
+        } catch (JSchException e) {
+            if (e.getMessage().indexOf("session is down") >= 0) {
+                if (getFailonerror()) {
+                    throw new BuildException(TIMEOUT_MESSAGE, e);
+                } else {
+                    log(TIMEOUT_MESSAGE, Project.MSG_ERR);
+                }
+            } else {
+                if (getFailonerror()) {
+                    throw new BuildException(e);
+                } else {
+                    log("Caught exception: " + e.getMessage(),
+                        Project.MSG_ERR);
+                }
+            }
+        } catch (Exception e) {
+            if (getFailonerror()) {
+                throw new BuildException(e);
+            } else {
+                log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+            }
+        }
+        return out;
+    }
+
+    /**
+     * Writes a string to a file. If destination file exists, it may be
+     * overwritten depending on the "append" value.
+     *
+     * @param from           string to write
+     * @param to             file to write to
+     * @param append         if true, append to existing file, else overwrite
+     * @exception Exception  most likely an IOException
+     */
+    private void writeToFile(String from, boolean append, File to)
+        throws IOException {
+        FileWriter out = null;
+        try {
+            out = new FileWriter(to.getAbsolutePath(), append);
+            StringReader in = new StringReader(from);
+            char[] buffer = new char[BUFFER_SIZE];
+            int bytesRead;
+            while (true) {
+                bytesRead = in.read(buffer);
+                if (bytesRead == -1) {
+                    break;
+                }
+                out.write(buffer, 0, bytesRead);
+            }
+            out.flush();
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java
new file mode 100644
index 0000000..ba69f18
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/SSHUserInfo.java
@@ -0,0 +1,216 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.UserInfo;
+import com.jcraft.jsch.UIKeyboardInteractive;
+
+/**
+ * Class containing information on an SSH user.
+ */
+public class SSHUserInfo implements UserInfo, UIKeyboardInteractive {
+
+    private String name;
+    private String password = null;
+    private String keyfile;
+    private String passphrase = null;
+    private boolean trustAllCertificates;
+
+    /** Constructor for SSHUserInfo. */
+    public SSHUserInfo() {
+        super();
+        this.trustAllCertificates = false;
+    }
+
+    /**
+     * Constructor for SSHUserInfo.
+     * @param password the user's password
+     * @param trustAllCertificates if true trust hosts whose identity is unknown
+     */
+    public SSHUserInfo(String password, boolean trustAllCertificates) {
+        super();
+        this.password = password;
+        this.trustAllCertificates = trustAllCertificates;
+    }
+
+    /**
+     * Gets the user name.
+     * @return the user name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Gets the pass phrase of the user.
+     * @param message a message
+     * @return the passphrase
+     */
+    public String getPassphrase(String message) {
+        return passphrase;
+    }
+
+    /**
+     * Gets the user's password.
+     * @return the user's password
+     */
+    public String getPassword() {
+        return password;
+    }
+
+    /**
+     * Prompts a string.
+     * @param str the string
+     * @return whether the string was prompted
+     */
+    public boolean prompt(String str) {
+        return false;
+    }
+
+    /**
+     * Indicates whether a retry was done.
+     * @return whether a retry was done
+     */
+    public boolean retry() {
+        return false;
+    }
+
+    /**
+     * Sets the name.
+     * @param name The name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Sets the passphrase.
+     * @param passphrase The passphrase to set
+     */
+    public void setPassphrase(String passphrase) {
+        this.passphrase = passphrase;
+    }
+
+    /**
+     * Sets the password.
+     * @param password The password to set
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    /**
+     * Sets the trust.
+     * @param trust whether to trust or not.
+     */
+    public void setTrust(boolean trust) {
+        this.trustAllCertificates = trust;
+    }
+
+    /**
+     * @return whether to trust or not.
+     */
+    public boolean getTrust() {
+        return this.trustAllCertificates;
+    }
+
+    /**
+     * Returns the passphrase.
+     * @return String
+     */
+    public String getPassphrase() {
+        return passphrase;
+    }
+
+    /**
+     * Returns the keyfile.
+     * @return String
+     */
+    public String getKeyfile() {
+        return keyfile;
+    }
+
+    /**
+     * Sets the keyfile.
+     * @param keyfile The keyfile to set
+     */
+    public void setKeyfile(String keyfile) {
+        this.keyfile = keyfile;
+    }
+
+    /**
+     * Implement the UserInfo interface.
+     * @param message ignored
+     * @return true always
+     */
+    public boolean promptPassphrase(String message) {
+        return true;
+    }
+
+    /**
+     * Implement the UserInfo interface.
+     * @param passwordPrompt ignored
+     * @return true the first time this is called, false otherwise
+     */
+    public boolean promptPassword(String passwordPrompt) {
+        return true;
+    }
+
+    /**
+     * Implement the UserInfo interface.
+     * @param message ignored
+     * @return the value of trustAllCertificates
+     */
+    public boolean promptYesNo(String message) {
+        return trustAllCertificates;
+    }
+
+//why do we do nothing?
+    /**
+     * Implement the UserInfo interface (noop).
+     * @param message ignored
+     */
+    public void showMessage(String message) {
+        //log(message, Project.MSG_DEBUG);
+    }
+
+    /**
+     * Implementation of UIKeyboardInteractive#promptKeyboardInteractive.
+     * @param destination not used.
+     * @param name        not used.
+     * @param instruction not used.
+     * @param prompt      the method checks if this is one in length.
+     * @param echo        the method checks if the first element is false.
+     * @return the password in an size one array if there is a password
+     *         and if the prompt and echo checks pass.
+     */
+    public String[] promptKeyboardInteractive(String destination,
+                                              String name,
+                                              String instruction,
+                                              String[] prompt,
+                                              boolean[] echo) {
+        if (prompt.length != 1 || echo[0] || this.password == null) {
+            return null;
+        }
+        String[] response = new String[1];
+        response[0] = this.password;
+        return response;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
new file mode 100644
index 0000000..878d428
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/Scp.java
@@ -0,0 +1,421 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+import java.io.IOException;
+import java.io.File;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Ant task for sending files to remote machine over ssh/scp.
+ *
+ * @since Ant 1.6
+ */
+public class Scp extends SSHBase {
+
+    private static final String[] FROM_ATTRS = {
+        "file", "localfile", "remotefile" };
+
+    private static final String[] TO_ATTRS = {
+        "todir", "localtodir", "remotetodir", "localtofile", "remotetofile" };
+
+    private String fromUri;
+    private String toUri;
+    private List fileSets = null;
+    private boolean isFromRemote, isToRemote;
+    private boolean isSftp = false;
+
+    /**
+     * Sets the file to be transferred.  This can either be a remote
+     * file or a local file.  Remote files take the form:<br>
+     * <i>user:password@host:/directory/path/file.example</i><br>
+     * Files to transfer can also include a wildcard to include all
+     * files in a remote directory.  For example:<br>
+     * <i>user:password@host:/directory/path/*</i><br>
+     * @param aFromUri a string representing the file to transfer.
+     */
+    public void setFile(String aFromUri) {
+        setFromUri(aFromUri);
+        this.isFromRemote = isRemoteUri(this.fromUri);
+    }
+
+    /**
+     * Sets the location where files will be transferred to.
+     * This can either be a remote directory or a local directory.
+     * Remote directories take the form of:<br>
+     * <i>user:password@host:/directory/path/</i><br>
+     * This parameter is required.
+
+     * @param aToUri a string representing the target of the copy.
+     */
+    public void setTodir(String aToUri) {
+        setToUri(aToUri);
+        this.isToRemote = isRemoteUri(this.toUri);
+    }
+
+    /**
+     * Similiar to {@link #setFile setFile} but explicitly states that
+     * the file is a local file.  This is the only way to specify a
+     * local file with a @ character.
+     * @param aFromUri a string representing the source of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setLocalFile(String aFromUri) {
+        setFromUri(aFromUri);
+        this.isFromRemote = false;
+    }
+
+    /**
+     * Similiar to {@link #setFile setFile} but explicitly states that
+     * the file is a remote file.
+     * @param aFromUri a string representing the source of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setRemoteFile(String aFromUri) {
+        setFromUri(aFromUri);
+        this.isFromRemote = true;
+     }
+
+    /**
+     * Similiar to {@link #setTodir setTodir} but explicitly states
+     * that the directory is a local.  This is the only way to specify
+     * a local directory with a @ character.
+     * @param aToUri a string representing the target of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setLocalTodir(String aToUri) {
+        setToUri(aToUri);
+        this.isToRemote = false;
+    }
+
+    /**
+     * Similiar to {@link #setTodir setTodir} but explicitly states
+     * that the directory is a remote.
+     * @param aToUri a string representing the target of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setRemoteTodir(String aToUri) {
+        setToUri(aToUri);
+        this.isToRemote = true;
+    }
+
+    /**
+     * Changes the file name to the given name while receiving it,
+     * only useful if receiving a single file.
+     * @param aToUri a string representing the target of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setLocalTofile(String aToUri) {
+        setToUri(aToUri);
+        this.isToRemote = false;
+    }
+
+    /**
+     * Changes the file name to the given name while sending it,
+     * only useful if sending a single file.
+     * @param aToUri a string representing the target of the copy.
+     * @since Ant 1.6.2
+     */
+    public void setRemoteTofile(String aToUri) {
+        setToUri(aToUri);
+        this.isToRemote = true;
+    }
+
+    /**
+     * Setting this to true to use sftp protocol.
+     *
+     * @param yesOrNo if true sftp protocol will be used.
+     */
+    public void setSftp(boolean yesOrNo) {
+        isSftp = yesOrNo;
+    }
+
+    /**
+     * Adds a FileSet tranfer to remote host.  NOTE: Either
+     * addFileSet() or setFile() are required.  But, not both.
+     *
+     * @param set FileSet to send to remote host.
+     */
+    public void addFileset(FileSet set) {
+        if (fileSets == null) {
+            fileSets = new LinkedList();
+        }
+        fileSets.add(set);
+    }
+
+    /**
+     * Initialize this task.
+     * @throws BuildException on error
+     */
+    public void init() throws BuildException {
+        super.init();
+        this.toUri = null;
+        this.fromUri = null;
+        this.fileSets = null;
+    }
+
+    /**
+     * Execute this task.
+     * @throws BuildException on error
+     */
+    public void execute() throws BuildException {
+        if (toUri == null) {
+            throw exactlyOne(TO_ATTRS);
+        }
+        if (fromUri == null && fileSets == null) {
+            throw exactlyOne(FROM_ATTRS, "one or more nested filesets");
+        }
+        try {
+            if (isFromRemote && !isToRemote) {
+                download(fromUri, toUri);
+            } else if (!isFromRemote && isToRemote) {
+                if (fileSets != null) {
+                    upload(fileSets, toUri);
+                } else {
+                    upload(fromUri, toUri);
+                }
+            } else if (isFromRemote && isToRemote) {
+                throw new BuildException(
+                    "Copying from a remote server to a remote server is not supported.");
+            } else {
+                throw new BuildException("'todir' and 'file' attributes "
+                    + "must have syntax like the following: "
+                    + "user:password@host:/path");
+            }
+        } catch (Exception e) {
+            if (getFailonerror()) {
+                throw new BuildException(e);
+            } else {
+                log("Caught exception: " + e.getMessage(), Project.MSG_ERR);
+            }
+        }
+    }
+
+    private void download(String fromSshUri, String toPath)
+        throws JSchException, IOException {
+        String file = parseUri(fromSshUri);
+
+        Session session = null;
+        try {
+            session = openSession();
+            ScpFromMessage message = null;
+            if (!isSftp) {
+                message =
+                    new ScpFromMessage(getVerbose(), session, file,
+                                       getProject().resolveFile(toPath),
+                                       fromSshUri.endsWith("*"));
+            } else {
+                message =
+                    new ScpFromMessageBySftp(getVerbose(), session, file,
+                                             getProject().resolveFile(toPath),
+                                             fromSshUri.endsWith("*"));
+            }
+            log("Receiving file: " + file);
+            message.setLogListener(this);
+            message.execute();
+        } finally {
+            if (session != null) {
+                session.disconnect();
+            }
+        }
+    }
+
+    private void upload(List fileSet, String toSshUri)
+        throws IOException, JSchException {
+        String file = parseUri(toSshUri);
+
+        Session session = null;
+        try {
+            List list = new ArrayList(fileSet.size());
+            for (Iterator i = fileSet.iterator(); i.hasNext();) {
+                FileSet set = (FileSet) i.next();
+                Directory d = createDirectory(set);
+                if (d != null) {
+                    list.add(d);
+                }
+            }
+            if (!list.isEmpty()) {
+                session = openSession();
+                ScpToMessage message = null;
+                if (!isSftp) {
+                    message = new ScpToMessage(getVerbose(), session,
+                                               list, file);
+                } else {
+                    message = new ScpToMessageBySftp(getVerbose(), session,
+                                                     list, file);
+                }
+                message.setLogListener(this);
+                message.execute();
+            }
+        } finally {
+            if (session != null) {
+                session.disconnect();
+            }
+        }
+    }
+
+    private void upload(String fromPath, String toSshUri)
+        throws IOException, JSchException {
+        String file = parseUri(toSshUri);
+
+        Session session = null;
+        try {
+            session = openSession();
+            ScpToMessage message = null;
+            if (!isSftp) {
+                message =
+                    new ScpToMessage(getVerbose(), session,
+                                     getProject().resolveFile(fromPath), file);
+            } else {
+                message =
+                    new ScpToMessageBySftp(getVerbose(), session,
+                                           getProject().resolveFile(fromPath),
+                                           file);
+            }
+            message.setLogListener(this);
+            message.execute();
+        } finally {
+            if (session != null) {
+                session.disconnect();
+            }
+        }
+    }
+
+    private String parseUri(String uri) {
+
+        int indexOfAt = uri.indexOf('@');
+        int indexOfColon = uri.indexOf(':');
+
+        if (indexOfColon > -1 && indexOfColon < indexOfAt) {
+            // user:password@host:/path notation
+            // everything upto the last @ before the last : is considered
+            // password. (so if the path contains an @ and a : it will not work)
+            int indexOfCurrentAt = indexOfAt;
+            int indexOfLastColon = uri.lastIndexOf(':');
+            while (indexOfCurrentAt > -1 && indexOfCurrentAt < indexOfLastColon)
+            {
+                indexOfAt = indexOfCurrentAt;
+                indexOfCurrentAt = uri.indexOf('@', indexOfCurrentAt + 1);
+            }
+            setUsername(uri.substring(0, indexOfColon));
+            setPassword(uri.substring(indexOfColon + 1, indexOfAt));
+        } else {
+            // no password, will require passphrase
+            setUsername(uri.substring(0, indexOfAt));
+        }
+
+        if (getUserInfo().getPassword() == null
+            && getUserInfo().getPassphrase() == null) {
+            throw new BuildException("neither password nor passphrase for user "
+                                     + getUserInfo().getName() + " has been "
+                                     + "given.  Can't authenticate.");
+        }
+
+        int indexOfPath = uri.indexOf(':', indexOfAt + 1);
+        if (indexOfPath == -1) {
+            throw new BuildException("no remote path in " + uri);
+        }
+
+        setHost(uri.substring(indexOfAt + 1, indexOfPath));
+        String remotePath = uri.substring(indexOfPath + 1);
+        if (remotePath.equals("")) {
+            remotePath = ".";
+        }
+        return remotePath;
+    }
+
+    private boolean isRemoteUri(String uri) {
+        boolean isRemote = true;
+        int indexOfAt = uri.indexOf('@');
+        if (indexOfAt < 0) {
+            isRemote = false;
+        }
+        return isRemote;
+    }
+
+    private Directory createDirectory(FileSet set) {
+        DirectoryScanner scanner = set.getDirectoryScanner(getProject());
+        Directory root = new Directory(scanner.getBasedir());
+        String[] files = scanner.getIncludedFiles();
+        if (files.length != 0) {
+            for (int j = 0; j < files.length; j++) {
+                String[] path = Directory.getPath(files[j]);
+                Directory current = root;
+                File currentParent = scanner.getBasedir();
+                for (int i = 0; i < path.length; i++) {
+                    File file = new File(currentParent, path[i]);
+                    if (file.isDirectory()) {
+                        current.addDirectory(new Directory(file));
+                        current = current.getChild(file);
+                        currentParent = current.getDirectory();
+                    } else if (file.isFile()) {
+                        current.addFile(file);
+                    }
+                }
+            }
+        } else {
+            // skip
+            root = null;
+        }
+        return root;
+    }
+
+    private void setFromUri(String fromUri) {
+        if (this.fromUri != null) {
+            throw exactlyOne(FROM_ATTRS);
+        }
+        this.fromUri = fromUri;
+    }
+
+    private void setToUri(String toUri) {
+        if (this.toUri != null) {
+            throw exactlyOne(TO_ATTRS);
+        }
+        this.toUri = toUri;
+    }
+
+    private BuildException exactlyOne(String[] attrs) {
+        return exactlyOne(attrs, null);
+    }
+
+    private BuildException exactlyOne(String[] attrs, String alt) {
+        StringBuffer buf = new StringBuffer("Exactly one of ").append(
+                '[').append(attrs[0]);
+        for (int i = 1; i < attrs.length; i++) {
+            buf.append('|').append(attrs[i]);
+        }
+        buf.append(']');
+        if (alt != null) {
+            buf.append(" or ").append(alt);
+        }
+        return new BuildException(buf.append(" is required.").toString());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
new file mode 100644
index 0000000..0050400
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
@@ -0,0 +1,246 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.ByteArrayOutputStream;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.Channel;
+
+/**
+ * A helper object representing an scp download.
+ */
+public class ScpFromMessage extends AbstractSshMessage {
+
+    private static final int HUNDRED_KILOBYTES = 102400;
+    private static final byte LINE_FEED = 0x0a;
+    private static final int BUFFER_SIZE = 1024;
+
+    private String remoteFile;
+    private File localFile;
+    private boolean isRecursive = false;
+
+    /**
+     * Constructor for ScpFromMessage
+     * @param session the ssh session to use
+     */
+    public ScpFromMessage(Session session) {
+        super(session);
+    }
+
+    /**
+     * Constructor for ScpFromMessage
+     * @param verbose if true do verbose logging
+     * @param session the ssh session to use
+     * @since Ant 1.7
+     */
+    public ScpFromMessage(boolean verbose, Session session) {
+        super(verbose, session);
+    }
+
+    /**
+     * Constructor for ScpFromMessage.
+     * @param verbose if true log extra information
+     * @param session the Scp session to use
+     * @param aRemoteFile the remote file name
+     * @param aLocalFile  the local file
+     * @param recursive   if true use recursion (-r option to scp)
+     * @since Ant 1.6.2
+     */
+    public ScpFromMessage(boolean verbose,
+                          Session session,
+                          String aRemoteFile,
+                          File aLocalFile,
+                          boolean recursive) {
+        super(verbose, session);
+        this.remoteFile = aRemoteFile;
+        this.localFile = aLocalFile;
+        this.isRecursive = recursive;
+    }
+
+    /**
+     * Constructor for ScpFromMessage.
+     * @param session the Scp session to use
+     * @param aRemoteFile the remote file name
+     * @param aLocalFile  the local file
+     * @param recursive   if true use recursion (-r option to scp)
+     */
+    public ScpFromMessage(Session session,
+                           String aRemoteFile,
+                           File aLocalFile,
+                           boolean recursive) {
+        this(false, session, aRemoteFile, aLocalFile, recursive);
+    }
+
+    /**
+     * Carry out the transfer.
+     * @throws IOException on i/o errors
+     * @throws JSchException on errors detected by scp
+     */
+    public void execute() throws IOException, JSchException {
+        String command = "scp -f ";
+        if (isRecursive) {
+            command += "-r ";
+        }
+        command += remoteFile;
+        Channel channel = openExecChannel(command);
+        try {
+            // get I/O streams for remote scp
+            OutputStream out = channel.getOutputStream();
+            InputStream in = channel.getInputStream();
+
+            channel.connect();
+
+            sendAck(out);
+            startRemoteCpProtocol(in, out, localFile);
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+        log("done\n");
+    }
+
+    private void startRemoteCpProtocol(InputStream in,
+                                       OutputStream out,
+                                       File localFile) throws IOException {
+        File startFile = localFile;
+        while (true) {
+            // C0644 filesize filename - header for a regular file
+            // T time 0 time 0\n - present if perserve time.
+            // D directory - this is the header for a directory.
+            ByteArrayOutputStream stream = new ByteArrayOutputStream();
+            while (true) {
+                int read = in.read();
+                if (read < 0) {
+                    return;
+                }
+                if ((byte) read == LINE_FEED) {
+                    break;
+                }
+                stream.write(read);
+            }
+            String serverResponse = stream.toString("UTF-8");
+            if (serverResponse.charAt(0) == 'C') {
+                parseAndFetchFile(serverResponse, startFile, out, in);
+            } else if (serverResponse.charAt(0) == 'D') {
+                startFile = parseAndCreateDirectory(serverResponse,
+                        startFile);
+                sendAck(out);
+            } else if (serverResponse.charAt(0) == 'E') {
+                startFile = startFile.getParentFile();
+                sendAck(out);
+            } else if (serverResponse.charAt(0) == '\01'
+                    || serverResponse.charAt(0) == '\02') {
+                // this indicates an error.
+                throw new IOException(serverResponse.substring(1));
+            }
+        }
+    }
+
+    private File parseAndCreateDirectory(String serverResponse,
+                                         File localFile) {
+        int start = serverResponse.indexOf(" ");
+        // appears that the next token is not used and it's zero.
+        start = serverResponse.indexOf(" ", start + 1);
+        String directoryName = serverResponse.substring(start + 1);
+        if (localFile.isDirectory()) {
+            File dir = new File(localFile, directoryName);
+            dir.mkdir();
+            log("Creating: " + dir);
+            return dir;
+        }
+        return null;
+    }
+
+    private void parseAndFetchFile(String serverResponse,
+                                   File localFile,
+                                   OutputStream out,
+                                   InputStream in) throws IOException {
+        int start = 0;
+        int end = serverResponse.indexOf(" ", start + 1);
+        start = end + 1;
+        end = serverResponse.indexOf(" ", start + 1);
+        long filesize = Long.parseLong(serverResponse.substring(start, end));
+        String filename = serverResponse.substring(end + 1);
+        log("Receiving: " + filename + " : " + filesize);
+        File transferFile = (localFile.isDirectory())
+                ? new File(localFile, filename)
+                : localFile;
+        fetchFile(transferFile, filesize, out, in);
+        waitForAck(in);
+        sendAck(out);
+    }
+
+    private void fetchFile(File localFile,
+                            long filesize,
+                            OutputStream out,
+                            InputStream in) throws IOException {
+        byte[] buf = new byte[BUFFER_SIZE];
+        sendAck(out);
+
+        // read a content of lfile
+        FileOutputStream fos = new FileOutputStream(localFile);
+        int length;
+        long totalLength = 0;
+        long startTime = System.currentTimeMillis();
+
+        // only track progress for files larger than 100kb in verbose mode
+        boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+        // since filesize keeps on decreasing we have to store the
+        // initial filesize
+        long initFilesize = filesize;
+        int percentTransmitted = 0;
+
+        try {
+            while (true) {
+                length = in.read(buf, 0,
+                                 (BUFFER_SIZE < filesize) ? BUFFER_SIZE
+                                                          : (int) filesize);
+                if (length < 0) {
+                    throw new EOFException("Unexpected end of stream.");
+                }
+                fos.write(buf, 0, length);
+                filesize -= length;
+                totalLength += length;
+                if (filesize == 0) {
+                    break;
+                }
+
+                if (trackProgress) {
+                    percentTransmitted = trackProgress(initFilesize,
+                                                       totalLength,
+                                                       percentTransmitted);
+                }
+            }
+        } finally {
+            long endTime = System.currentTimeMillis();
+            logStats(startTime, endTime, totalLength);
+            fos.flush();
+            fos.close();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java
new file mode 100644
index 0000000..9b54b08
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessageBySftp.java
@@ -0,0 +1,171 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.File;
+import java.io.IOException;
+
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.SftpATTRS;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+/**
+ * A helper object representing an scp download.
+ */
+public class ScpFromMessageBySftp extends ScpFromMessage {
+
+    private static final int HUNDRED_KILOBYTES = 102400;
+
+    private String remoteFile;
+    private File localFile;
+    private boolean isRecursive = false;
+    private boolean verbose = false;
+
+    /**
+     * Constructor for ScpFromMessageBySftp.
+     * @param verbose if true log extra information
+     * @param session the Scp session to use
+     * @param aRemoteFile the remote file name
+     * @param aLocalFile  the local file
+     * @param recursive   if true use recursion
+     * @since Ant 1.7
+     */
+    public ScpFromMessageBySftp(boolean verbose,
+                                Session session,
+                                String aRemoteFile,
+                                File aLocalFile,
+                                boolean recursive) {
+        super(verbose, session);
+        this.verbose = verbose;
+        this.remoteFile = aRemoteFile;
+        this.localFile = aLocalFile;
+        this.isRecursive = recursive;
+    }
+
+    /**
+     * Constructor for ScpFromMessageBySftp.
+     * @param session the Scp session to use
+     * @param aRemoteFile the remote file name
+     * @param aLocalFile  the local file
+     * @param recursive   if true use recursion
+     */
+    public ScpFromMessageBySftp(Session session,
+                                String aRemoteFile,
+                                File aLocalFile,
+                                boolean recursive) {
+        this(false, session, aRemoteFile, aLocalFile, recursive);
+    }
+
+    /**
+     * Carry out the transfer.
+     * @throws IOException on i/o errors
+     * @throws JSchException on errors detected by scp
+     */
+    public void execute() throws IOException, JSchException {
+        ChannelSftp channel = openSftpChannel();
+        try {
+            channel.connect();
+            try {
+                SftpATTRS attrs = channel.stat(remoteFile);
+                if (attrs.isDir() && !remoteFile.endsWith("/")) {
+                    remoteFile = remoteFile + "/";
+                }
+            } catch (SftpException ee) {
+                // Ignored
+            }
+            getDir(channel, remoteFile, localFile);
+        } catch (SftpException e) {
+            throw new JSchException(e.toString());
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+        log("done\n");
+    }
+
+    private void getDir(ChannelSftp channel,
+                        String remoteFile,
+                        File localFile) throws IOException, SftpException {
+        String pwd = remoteFile;
+        if (remoteFile.lastIndexOf('/') != -1) {
+            if (remoteFile.length() > 1) {
+                pwd = remoteFile.substring(0, remoteFile.lastIndexOf('/'));
+            }
+        }
+        channel.cd(pwd);
+        if (!localFile.exists()) {
+            localFile.mkdirs();
+        }
+        java.util.Vector files = channel.ls(remoteFile);
+        for (int i = 0; i < files.size(); i++) {
+            ChannelSftp.LsEntry le = (ChannelSftp.LsEntry) files.elementAt(i);
+            String name = le.getFilename();
+            if (le.getAttrs().isDir()) {
+                if (name.equals(".") || name.equals("..")) {
+                    continue;
+                }
+                getDir(channel,
+                       channel.pwd() + "/" + name + "/",
+                       new File(localFile, le.getFilename()));
+            } else {
+                getFile(channel, le, localFile);
+            }
+        }
+        channel.cd("..");
+    }
+
+    private void getFile(ChannelSftp channel,
+                         ChannelSftp.LsEntry le,
+                         File localFile) throws IOException, SftpException {
+        String remoteFile = le.getFilename();
+        if (!localFile.exists()) {
+            String path = localFile.getAbsolutePath();
+            int i = path.lastIndexOf(File.pathSeparator);
+            if (i != -1) {
+                if (path.length() > File.pathSeparator.length()) {
+                    new File(path.substring(0, i)).mkdirs();
+                }
+            }
+        }
+
+        if (localFile.isDirectory()) {
+            localFile = new File(localFile, remoteFile);
+        }
+
+        long startTime = System.currentTimeMillis();
+        long totalLength = le.getAttrs().getSize();
+
+        SftpProgressMonitor monitor = null;
+        boolean trackProgress = getVerbose() && totalLength > HUNDRED_KILOBYTES;
+        if (trackProgress) {
+            monitor = getProgressMonitor();
+        }
+        try {
+            log("Receiving: " + remoteFile + " : " + le.getAttrs().getSize());
+            channel.get(remoteFile, localFile.getAbsolutePath(), monitor);
+        } finally {
+            long endTime = System.currentTimeMillis();
+            logStats(startTime, endTime, (int) totalLength);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java
new file mode 100644
index 0000000..79ac843
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessage.java
@@ -0,0 +1,289 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.Channel;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.JSchException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * Utility class to carry out an upload scp transfer.
+ */
+public class ScpToMessage extends AbstractSshMessage {
+
+    private static final int HUNDRED_KILOBYTES = 102400;
+    private static final int BUFFER_SIZE = 1024;
+
+    private File localFile;
+    private String remotePath;
+    private List directoryList;
+
+    /**
+     * Constructor for ScpToMessage
+     * @param session the ssh session to use
+     */
+    public ScpToMessage(Session session) {
+        super(session);
+    }
+
+    /**
+     * Constructor for ScpToMessage
+     * @param verbose if true do verbose logging
+     * @param session the ssh session to use
+     * @since Ant 1.7
+     */
+    public ScpToMessage(boolean verbose, Session session) {
+        super(verbose, session);
+    }
+
+    /**
+     * Constructor for a local file to remote.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aLocalFile the local file
+     * @param aRemotePath the remote path
+     * @since Ant 1.6.2
+     */
+    public ScpToMessage(boolean verbose,
+                        Session session,
+                        File aLocalFile,
+                        String aRemotePath) {
+        this(verbose, session, aRemotePath);
+
+        this.localFile = aLocalFile;
+    }
+
+    /**
+     * Constructor for a local directories to remote.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aDirectoryList a list of directories
+     * @param aRemotePath the remote path
+     * @since Ant 1.6.2
+     */
+    public ScpToMessage(boolean verbose,
+                        Session session,
+                        List aDirectoryList,
+                        String aRemotePath) {
+        this(verbose, session, aRemotePath);
+
+        this.directoryList = aDirectoryList;
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aRemotePath the remote path
+     * @since Ant 1.6.2
+     */
+    private ScpToMessage(boolean verbose,
+                         Session session,
+                         String aRemotePath) {
+        super(verbose, session);
+        this.remotePath = aRemotePath;
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param session the scp session to use
+     * @param aLocalFile the local file
+     * @param aRemotePath the remote path
+     */
+    public ScpToMessage(Session session,
+                        File aLocalFile,
+                        String aRemotePath) {
+        this(false, session, aLocalFile, aRemotePath);
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param session the scp session to use
+     * @param aDirectoryList a list of directories
+     * @param aRemotePath the remote path
+     */
+    public ScpToMessage(Session session,
+                         List aDirectoryList,
+                         String aRemotePath) {
+        this(false, session, aDirectoryList, aRemotePath);
+    }
+
+    /**
+     * Carry out the transfer.
+     * @throws IOException on i/o errors
+     * @throws JSchException on errors detected by scp
+     */
+    public void execute() throws IOException, JSchException {
+        if (directoryList != null) {
+            doMultipleTransfer();
+        }
+        if (localFile != null) {
+            doSingleTransfer();
+        }
+        log("done.\n");
+    }
+
+    private void doSingleTransfer() throws IOException, JSchException {
+        String cmd = "scp -t " + remotePath;
+        Channel channel = openExecChannel(cmd);
+        try {
+
+            OutputStream out = channel.getOutputStream();
+            InputStream in = channel.getInputStream();
+
+            channel.connect();
+
+            waitForAck(in);
+            sendFileToRemote(localFile, in, out);
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+    }
+
+    private void doMultipleTransfer() throws IOException, JSchException {
+        Channel channel = openExecChannel("scp -r -d -t " + remotePath);
+        try {
+            OutputStream out = channel.getOutputStream();
+            InputStream in = channel.getInputStream();
+
+            channel.connect();
+
+            waitForAck(in);
+            for (Iterator i = directoryList.iterator(); i.hasNext();) {
+                Directory current = (Directory) i.next();
+                sendDirectory(current, in, out);
+            }
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+    }
+
+    private void sendDirectory(Directory current,
+                               InputStream in,
+                               OutputStream out) throws IOException {
+        for (Iterator fileIt = current.filesIterator(); fileIt.hasNext();) {
+            sendFileToRemote((File) fileIt.next(), in, out);
+        }
+        for (Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) {
+            Directory dir = (Directory) dirIt.next();
+            sendDirectoryToRemote(dir, in, out);
+        }
+    }
+
+    private void sendDirectoryToRemote(Directory directory,
+                                        InputStream in,
+                                        OutputStream out) throws IOException {
+        String command = "D0755 0 ";
+        command += directory.getDirectory().getName();
+        command += "\n";
+
+        out.write(command.getBytes());
+        out.flush();
+
+        waitForAck(in);
+        sendDirectory(directory, in, out);
+        out.write("E\n".getBytes());
+        out.flush();
+        waitForAck(in);
+    }
+
+    private void sendFileToRemote(File localFile,
+                                   InputStream in,
+                                   OutputStream out) throws IOException {
+        // send "C0644 filesize filename", where filename should not include '/'
+        long filesize = localFile.length();
+        String command = "C0644 " + filesize + " ";
+        command += localFile.getName();
+        command += "\n";
+
+        out.write(command.getBytes());
+        out.flush();
+
+        waitForAck(in);
+
+        // send a content of lfile
+        FileInputStream fis = new FileInputStream(localFile);
+        byte[] buf = new byte[BUFFER_SIZE];
+        long startTime = System.currentTimeMillis();
+        long totalLength = 0;
+
+        // only track progress for files larger than 100kb in verbose mode
+        boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+        // since filesize keeps on decreasing we have to store the
+        // initial filesize
+        long initFilesize = filesize;
+        int percentTransmitted = 0;
+
+        try {
+            if (this.getVerbose()) {
+                log("Sending: " + localFile.getName() + " : " + localFile.length());
+            }
+            while (true) {
+                int len = fis.read(buf, 0, buf.length);
+                if (len <= 0) {
+                    break;
+                }
+                out.write(buf, 0, len);
+                totalLength += len;
+
+                if (trackProgress) {
+                    percentTransmitted = trackProgress(initFilesize,
+                                                       totalLength,
+                                                       percentTransmitted);
+                }
+            }
+            out.flush();
+            sendAck(out);
+            waitForAck(in);
+        } finally {
+            if (this.getVerbose()) {
+                long endTime = System.currentTimeMillis();
+                logStats(startTime, endTime, totalLength);
+            }
+            fis.close();
+        }
+    }
+
+    /**
+     * Get the local file
+     * @return the local file
+     */
+    public File getLocalFile() {
+        return localFile;
+    }
+
+    /**
+     * Get the remote path
+     * @return the remote path
+     */
+    public String getRemotePath() {
+        return remotePath;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java
new file mode 100644
index 0000000..409f85b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpToMessageBySftp.java
@@ -0,0 +1,245 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.SftpProgressMonitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * Utility class to carry out an upload by sftp.
+ */
+public class ScpToMessageBySftp extends ScpToMessage/*AbstractSshMessage*/ {
+
+    private static final int HUNDRED_KILOBYTES = 102400;
+
+    private File localFile;
+    private String remotePath;
+    private List directoryList;
+
+    /**
+     * Constructor for a local file to remote.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aLocalFile the local file
+     * @param aRemotePath the remote path
+     * @since Ant 1.7
+     */
+    public ScpToMessageBySftp(boolean verbose,
+                              Session session,
+                              File aLocalFile,
+                              String aRemotePath) {
+        this(verbose, session, aRemotePath);
+
+        this.localFile = aLocalFile;
+    }
+
+    /**
+     * Constructor for a local directories to remote.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aDirectoryList a list of directories
+     * @param aRemotePath the remote path
+     * @since Ant 1.7
+     */
+    public ScpToMessageBySftp(boolean verbose,
+                              Session session,
+                              List aDirectoryList,
+                              String aRemotePath) {
+        this(verbose, session, aRemotePath);
+
+        this.directoryList = aDirectoryList;
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param verbose if true do verbose logging
+     * @param session the scp session to use
+     * @param aRemotePath the remote path
+     * @since Ant 1.6.2
+     */
+    private ScpToMessageBySftp(boolean verbose,
+                               Session session,
+                               String aRemotePath) {
+        super(verbose, session);
+        this.remotePath = aRemotePath;
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param session the scp session to use
+     * @param aLocalFile the local file
+     * @param aRemotePath the remote path
+     */
+    public ScpToMessageBySftp(Session session,
+                              File aLocalFile,
+                              String aRemotePath) {
+        this(false, session, aLocalFile, aRemotePath);
+    }
+
+    /**
+     * Constructor for ScpToMessage.
+     * @param session the scp session to use
+     * @param aDirectoryList a list of directories
+     * @param aRemotePath the remote path
+     */
+    public ScpToMessageBySftp(Session session,
+                              List aDirectoryList,
+                              String aRemotePath) {
+        this(false, session, aDirectoryList, aRemotePath);
+    }
+
+    /**
+     * Carry out the transfer.
+     * @throws IOException on i/o errors
+     * @throws JSchException on errors detected by scp
+     */
+    public void execute() throws IOException, JSchException {
+        if (directoryList != null) {
+            doMultipleTransfer();
+        }
+        if (localFile != null) {
+            doSingleTransfer();
+        }
+        log("done.\n");
+    }
+
+    private void doSingleTransfer() throws IOException, JSchException {
+        ChannelSftp channel = openSftpChannel();
+        try {
+            channel.connect();
+            try {
+                sendFileToRemote(channel, localFile, remotePath);
+            } catch (SftpException e) {
+                throw new JSchException(e.toString());
+            }
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+    }
+
+    private void doMultipleTransfer() throws IOException, JSchException {
+        ChannelSftp channel = openSftpChannel();
+        try {
+            channel.connect();
+
+            try {
+                channel.cd(remotePath);
+                for (Iterator i = directoryList.iterator(); i.hasNext();) {
+                    Directory current = (Directory) i.next();
+                    sendDirectory(channel, current);
+                }
+            } catch (SftpException e) {
+                throw new JSchException(e.toString());
+            }
+        } finally {
+            if (channel != null) {
+                channel.disconnect();
+            }
+        }
+    }
+
+    private void sendDirectory(ChannelSftp channel,
+                               Directory current)
+        throws IOException, SftpException {
+        for (Iterator fileIt = current.filesIterator(); fileIt.hasNext();) {
+            sendFileToRemote(channel, (File) fileIt.next(), null);
+        }
+        for (Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) {
+            Directory dir = (Directory) dirIt.next();
+            sendDirectoryToRemote(channel, dir);
+        }
+    }
+
+    private void sendDirectoryToRemote(ChannelSftp channel,
+                                       Directory directory)
+        throws IOException, SftpException {
+        String dir = directory.getDirectory().getName();
+        try {
+            channel.stat(dir);
+        } catch (SftpException e) {
+            // dir does not exist.
+            if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
+                channel.mkdir(dir);
+            }
+        }
+        channel.cd(dir);
+        sendDirectory(channel, directory);
+        channel.cd("..");
+    }
+
+    private void sendFileToRemote(ChannelSftp channel,
+                                  File localFile,
+                                  String remotePath)
+        throws IOException, SftpException {
+        long filesize = localFile.length();
+
+        if (remotePath == null) {
+            remotePath = localFile.getName();
+        }
+
+        long startTime = System.currentTimeMillis();
+        long totalLength = filesize;
+
+        // only track progress for files larger than 100kb in verbose mode
+        boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+
+        SftpProgressMonitor monitor = null;
+        if (trackProgress) {
+            monitor = getProgressMonitor();
+        }
+
+        try {
+            if (this.getVerbose()) {
+                log("Sending: " + localFile.getName() + " : " + filesize);
+            }
+            channel.put(localFile.getAbsolutePath(), remotePath, monitor);
+        } finally {
+            if (this.getVerbose()) {
+                long endTime = System.currentTimeMillis();
+                logStats(startTime, endTime, (int) totalLength);
+            }
+        }
+    }
+
+    /**
+     * Get the local file.
+     * @return the local file.
+     */
+    public File getLocalFile() {
+        return localFile;
+    }
+
+    /**
+     * Get the remote path.
+     * @return the remote path.
+     */
+    public String getRemotePath() {
+        return remotePath;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java
new file mode 100644
index 0000000..4b2978a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BlockFor.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.taskdefs.WaitFor;
+
+/**
+ * @since Ant 1.8
+ */
+
+public class BlockFor extends WaitFor {
+
+    /**
+     * Text to include in a message
+     */
+    private String text;
+
+
+    /**
+     * Constructor that takes the name of the task in the task name.
+     *
+     */
+    public BlockFor() {
+        super("blockfor");
+        text = getTaskName() + " timed out";
+    }
+
+    /**
+     * Constructor that takes the name of the task in the task name.
+     *
+     * @param taskName the name of the task.
+     */
+    public BlockFor(String taskName) {
+        super(taskName);
+    }
+
+    /**
+     * If the wait fails, a BuildException is thrown. All the superclasses actions are called first.
+     * @throws BuildTimeoutException on timeout, using the text in {@link #text}
+     *
+     */
+    protected void processTimeout() throws BuildTimeoutException {
+        super.processTimeout();
+        throw new BuildTimeoutException(text, getLocation());
+    }
+
+    /**
+     * Set the error text; all properties are expanded in the message.
+     *
+     * @param message the text to use in a failure message
+     */
+    public void addText(String message) {
+        text = getProject().replaceProperties(message);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java
new file mode 100644
index 0000000..143d08c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/BuildTimeoutException.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Location;
+
+/**
+ *
+ * This exception is used to indicate timeouts.
+ * @since Ant1.8
+ *
+ */
+
+public class BuildTimeoutException extends BuildException {
+
+    private static final long serialVersionUID = -8057644603246297562L;
+
+    /**
+     * Constructs a build exception with no descriptive information.
+     */
+    public BuildTimeoutException() {
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code>.
+     */
+    public BuildTimeoutException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code> unless a cause is specified.
+     * @param cause The exception that might have caused this one.
+     *              May be <code>null</code>.
+     */
+    public BuildTimeoutException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an exception with the given message and exception as
+     * a root cause and a location in a file.
+     *
+     * @param msg A description of or information about the exception.
+     *            Should not be <code>null</code> unless a cause is specified.
+     * @param cause The exception that might have caused this one.
+     *              May be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildTimeoutException(String msg, Throwable cause, Location location) {
+        super(msg, cause, location);
+    }
+
+    /**
+     * Constructs an exception with the given exception as a root cause.
+     *
+     * @param cause The exception that might have caused this one.
+     *              Should not be <code>null</code>.
+     */
+    public BuildTimeoutException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs an exception with the given descriptive message and a
+     * location in a file.
+     *
+     * @param message A description of or information about the exception.
+     *            Should not be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildTimeoutException(String message, Location location) {
+        super(message, location);
+    }
+
+    /**
+     * Constructs an exception with the given exception as
+     * a root cause and a location in a file.
+     *
+     * @param cause The exception that might have caused this one.
+     *              Should not be <code>null</code>.
+     * @param location The location in the project file where the error
+     *                 occurred. Must not be <code>null</code>.
+     */
+    public BuildTimeoutException(Throwable cause, Location location) {
+        super(cause, location);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java
new file mode 100644
index 0000000..c0fa135
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/testing/Funtest.java
@@ -0,0 +1,542 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.testing;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.TaskAdapter;
+import org.apache.tools.ant.util.WorkerAnt;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.Parallel;
+import org.apache.tools.ant.taskdefs.Sequential;
+import org.apache.tools.ant.taskdefs.WaitFor;
+
+/**
+ * Task to provide functional testing under Ant, with a fairly complex worflow of:
+ *
+ * <ul>
+ * <li>Conditional execution</li>
+ * <li>Application to start</li>
+ * <li>A probe to "waitfor" before running tests</li>
+ * <li>A tests sequence</li>
+ * <li>A reporting sequence that runs after the tests have finished</li>
+ * <li>A "teardown" clause that runs after the rest.</li>
+ * <li>Automated termination of the program it executes, if a timeout is not met</li>
+ * <li>Checking of a failure property and automatic raising of a fault
+ *     (with the text in failureText)
+ * if test shutdown and reporting succeeded</li>
+ *  </ul>
+ *
+ * The task is designed to be framework neutral; it will work with JUnit,
+ *  TestNG and other test frameworks That can be
+ * executed from Ant. It bears a resemblance to the FunctionalTest task from
+ * SmartFrog, as the attribute names were
+ * chosen to make migration easier. However, this task benefits from the
+ * ability to tweak Ant's internals, and so
+ * simplify the workflow, and from the experience of using the SmartFrog task.
+ * No code has been shared.
+ *
+ * @since Ant 1.8
+ */
+
+public class Funtest extends Task {
+
+    /**
+     * A condition that must be true before the tests are run. This makes it
+     * easier to define complex tests that only
+     * run if certain conditions are met, such as OS or network state.
+     */
+    private Condition condition;
+
+
+    /**
+     * Used internally to set the workflow up
+     */
+    private Parallel timedTests;
+
+    /**
+     * Setup runs if the condition is met. Once setup is complete, teardown
+     * will be run when the task finishes
+     */
+    private Sequential setup;
+
+    /**
+     * The application to run
+     */
+    private Sequential application;
+
+    /**
+     * A block that halts the tests until met.
+     */
+    private BlockFor block;
+
+    /**
+     * Tests to run
+     */
+    private Sequential tests;
+
+    /**
+     * Reporting only runs if the tests were executed. If the block stopped
+     * them, reporting is skipped.
+     */
+    private Sequential reporting;
+
+    /**
+     * Any teardown operations.
+     */
+    private Sequential teardown;
+
+    /**
+     * time for the tests to time out
+     */
+    private long timeout;
+
+    private long timeoutUnitMultiplier = WaitFor.ONE_MILLISECOND;
+
+    /**
+     * time for the execution to time out.
+     */
+    private long shutdownTime = 10 * WaitFor.ONE_SECOND;
+
+    private long shutdownUnitMultiplier = WaitFor.ONE_MILLISECOND;
+
+    /**
+     * Name of a property to look for
+     */
+    private String failureProperty;
+
+    /**
+     * Message to send when tests failed
+     */
+    private String failureMessage = "Tests failed";
+
+    /**
+     * Flag to set to true if you don't care about any shutdown errors.
+     * <p/>
+     * In that situation, errors raised during teardown are logged but not
+     * turned into BuildFault events. Similar to catching and ignoring
+     * <code>finally {}</code> clauses in Java/
+     */
+    private boolean failOnTeardownErrors = true;
+
+
+    /**
+     * What was thrown in the test run (including reporting)
+     */
+    private BuildException testException;
+    /**
+     * What got thrown during teardown
+     */
+    private BuildException teardownException;
+
+    /**
+     * Did the application throw an exception
+     */
+    private BuildException applicationException;
+
+    /**
+     * Did the task throw an exception
+     */
+    private BuildException taskException;
+
+    /** {@value} */
+    public static final String WARN_OVERRIDING = "Overriding previous definition of ";
+    /** {@value} */
+    public static final String APPLICATION_FORCIBLY_SHUT_DOWN = "Application forcibly shut down";
+    /** {@value} */
+    public static final String SHUTDOWN_INTERRUPTED = "Shutdown interrupted";
+    /** {@value} */
+    public static final String SKIPPING_TESTS
+        = "Condition failed -skipping tests";
+    /** Application exception */
+    public static final String APPLICATION_EXCEPTION = "Application Exception";
+    /** Teardown exception */
+    public static final String TEARDOWN_EXCEPTION = "Teardown Exception";
+
+    /**
+     * Log if the definition is overriding something
+     *
+     * @param name       what is being defined
+     * @param definition what should be null if you don't want a warning
+     */
+    private void logOverride(String name, Object definition) {
+        if (definition != null) {
+            log(WARN_OVERRIDING + '<' + name + '>', Project.MSG_WARN);
+        }
+    }
+
+    /**
+     * Add a condition.
+     * @param newCondition the condition to add.
+     */
+    public void addCondition(Condition newCondition) {
+        logOverride("condition", condition);
+        condition = newCondition;
+    }
+
+    /**
+     * Add an application.
+     * @param sequence the application to add.
+     */
+    public void addApplication(Sequential sequence) {
+        logOverride("application", application);
+        application = sequence;
+    }
+
+    /**
+     * Add a setup sequence.
+     * @param sequence the setup sequence to add.
+     */
+    public void addSetup(Sequential sequence) {
+        logOverride("setup", setup);
+        setup = sequence;
+    }
+
+    /**
+     * Add a block.
+     * @param sequence the block for to add.
+     */
+    public void addBlock(BlockFor sequence) {
+        logOverride("block", block);
+        block = sequence;
+    }
+
+    /**
+     * add tests.
+     * @param sequence a sequence to add.
+     */
+    public void addTests(Sequential sequence) {
+        logOverride("tests", tests);
+        tests = sequence;
+    }
+
+    /**
+     * set reporting sequence of tasks.
+     * @param sequence a reporting sequence to use.
+     */
+    public void addReporting(Sequential sequence) {
+        logOverride("reporting", reporting);
+        reporting = sequence;
+    }
+
+    /**
+     * set teardown sequence of tasks.
+     * @param sequence a teardown sequence to use.
+     */
+    public void addTeardown(Sequential sequence) {
+        logOverride("teardown", teardown);
+        teardown = sequence;
+    }
+
+    /**
+     * Set the failOnTeardownErrors attribute.
+     * @param failOnTeardownErrors the value to use.
+     */
+    public void setFailOnTeardownErrors(boolean failOnTeardownErrors) {
+        this.failOnTeardownErrors = failOnTeardownErrors;
+    }
+
+    /**
+     * Set the failureMessage attribute.
+     * @param failureMessage the value to use.
+     */
+    public void setFailureMessage(String failureMessage) {
+        this.failureMessage = failureMessage;
+    }
+
+    /**
+     * Set the failureProperty attribute.
+     * @param failureProperty the value to use.
+     */
+    public void setFailureProperty(String failureProperty) {
+        this.failureProperty = failureProperty;
+    }
+
+    /**
+     * Set the shutdownTime attribute.
+     * @param shutdownTime the value to use.
+     */
+    public void setShutdownTime(long shutdownTime) {
+        this.shutdownTime = shutdownTime;
+    }
+
+    /**
+     * Set the timeout attribute.
+     * @param timeout the value to use.
+     */
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * Set the timeoutunit attribute.
+     * @param unit the value to use.
+     */
+    public void setTimeoutUnit(WaitFor.Unit unit) {
+        timeoutUnitMultiplier = unit.getMultiplier();
+    }
+
+    /**
+     * Set the shutdownunit attribute.
+     * @param unit the value to use.
+     */
+    public void setShutdownUnit(WaitFor.Unit unit) {
+        shutdownUnitMultiplier = unit.getMultiplier();
+    }
+
+
+    /**
+     * Get the application exception.
+     * @return the application exception.
+     */
+    public BuildException getApplicationException() {
+        return applicationException;
+    }
+
+    /**
+     * Get the teardown exception.
+     * @return the teardown exception.
+     */
+    public BuildException getTeardownException() {
+        return teardownException;
+    }
+
+    /**
+     * Get the test exception.
+     * @return the test exception.
+     */
+    public BuildException getTestException() {
+        return testException;
+    }
+
+    /**
+     * Get the task exception.
+     * @return the task exception.
+     */
+    public BuildException getTaskException() {
+        return taskException;
+    }
+
+    /**
+     * Bind and initialise a task
+     * @param task task to bind
+     */
+    private void bind(Task task) {
+        task.bindToOwner(this);
+        task.init();
+    }
+
+    /**
+     * Create a newly bound parallel instance
+     * @param parallelTimeout timeout
+     * @return a bound and initialised parallel instance.
+     */
+    private Parallel newParallel(long parallelTimeout) {
+        Parallel par = new Parallel();
+        bind(par);
+        par.setFailOnAny(true);
+        par.setTimeout(parallelTimeout);
+        return par;
+    }
+
+    /**
+     * Create a newly bound parallel instance with one child
+     * @param parallelTimeout timeout
+     * @param child task
+     * @return a bound and initialised parallel instance.
+     */
+    private Parallel newParallel(long parallelTimeout, Task child) {
+        Parallel par = newParallel(parallelTimeout);
+        par.addTask(child);
+        return par;
+    }
+
+    /**
+     * Run the functional test sequence.
+     * <p/>
+     * This is a fairly complex workflow -what is going on is that we try to clean up
+     * no matter how the run ended, and to retain the innermost exception that got thrown
+     * during cleanup. That is, if teardown fails after the tests themselves failed, it is the
+     * test failing that is more important.
+     * @throws BuildException if something was caught during the run or teardown.
+     */
+    public void execute() throws BuildException {
+
+        //before anything else, check the condition
+        //and bail out if it is defined but not true
+        if (condition != null && !condition.eval()) {
+            //we are skipping the test
+            log(SKIPPING_TESTS);
+            return;
+        }
+
+        long timeoutMillis = timeout * timeoutUnitMultiplier;
+
+        //set up the application to run in a separate thread
+        Parallel applicationRun = newParallel(timeoutMillis);
+        //with a worker which we can use to manage it
+        WorkerAnt worker = new WorkerAnt(applicationRun, null);
+        if (application != null) {
+            applicationRun.addTask(application);
+        }
+
+        //The test run consists of the block followed by the tests.
+        long testRunTimeout = 0;
+        Sequential testRun = new Sequential();
+        bind(testRun);
+        if (block != null) {
+            //waitfor is not a task, it needs to be adapted
+            testRun.addTask(new TaskAdapter(block));
+            //add the block time to the total test run timeout
+            testRunTimeout = block.calculateMaxWaitMillis();
+        }
+
+        //add the tests and more delay
+        if (tests != null) {
+            testRun.addTask(tests);
+            testRunTimeout += timeoutMillis;
+        }
+        //add the reporting and more delay
+        if (reporting != null) {
+            testRun.addTask(reporting);
+            testRunTimeout += timeoutMillis;
+        }
+
+        //wrap this in a parallel purely to set up timeouts for the
+        //test run
+        timedTests = newParallel(testRunTimeout, testRun);
+
+        try {
+            //run any setup task
+            if (setup != null) {
+                Parallel setupRun = newParallel(timeoutMillis, setup);
+                setupRun.execute();
+            }
+            //start the worker thread and leave it running
+            worker.start();
+            //start the probe+test sequence
+            timedTests.execute();
+        } catch (BuildException e) {
+            //Record the exception and continue
+            testException = e;
+        } finally {
+            //teardown always runs; its faults are filed away
+            if (teardown != null) {
+                try {
+                    Parallel teardownRun = newParallel(timeoutMillis, teardown);
+                    teardownRun.execute();
+                } catch (BuildException e) {
+                    teardownException = e;
+                }
+            }
+        }
+
+        //we get here whether or not the tests/teardown have thrown a BuildException.
+        //do a forced shutdown of the running application, before processing the faults
+
+        try {
+            //wait for the worker to have finished
+            long shutdownTimeMillis = shutdownTime * shutdownUnitMultiplier;
+            worker.waitUntilFinished(shutdownTimeMillis);
+            if (worker.isAlive()) {
+                //then, if it is still running, interrupt it a second time.
+                log(APPLICATION_FORCIBLY_SHUT_DOWN, Project.MSG_WARN);
+                worker.interrupt();
+                worker.waitUntilFinished(shutdownTimeMillis);
+            }
+        } catch (InterruptedException e) {
+            //success, something interrupted the shutdown. There may be a leaked
+            //worker;
+            log(SHUTDOWN_INTERRUPTED, e, Project.MSG_VERBOSE);
+        }
+        applicationException = worker.getBuildException();
+
+        //Now faults are analysed
+
+        processExceptions();
+    }
+
+    /**
+     * Now faults are analysed.
+     * <p> The priority is
+     * <ol>
+     * <li>testexceptions, except those indicating a build timeout when the application itself
+     failed.<br>
+     (because often it is the application fault that is more interesting than the probe
+     failure, which is usually triggered by the application not starting
+     </li><li>
+     Application exceptions (above test timeout exceptions)
+     </li><li>
+     Teardown exceptions -except when they are being ignored
+     </li><li>
+     Test failures as indicated by the failure property
+     </li></ol>
+
+     */
+    protected void processExceptions() {
+        taskException = testException;
+
+        //look for an application fault
+        if (applicationException != null) {
+            if (taskException == null || taskException instanceof BuildTimeoutException) {
+                taskException = applicationException;
+            } else {
+                ignoringThrowable(APPLICATION_EXCEPTION, applicationException);
+            }
+        }
+
+        //now look for teardown faults, which may be ignored
+        if (teardownException != null) {
+            if (taskException == null && failOnTeardownErrors) {
+                taskException = teardownException;
+            } else {
+                //don't let the cleanup exception get in the way of any other failure
+                ignoringThrowable(TEARDOWN_EXCEPTION, teardownException);
+            }
+        }
+
+        //now, analyse the tests
+        if (failureProperty != null
+             && getProject().getProperty(failureProperty) != null) {
+            //we've failed
+            log(failureMessage);
+            if (taskException == null) {
+                taskException = new BuildException(failureMessage);
+            }
+        }
+
+        //at this point taskException is null or not.
+        //if not, throw the exception
+        if (taskException != null) {
+            throw taskException;
+        }
+    }
+
+    /**
+     * log that we are ignoring something rather than rethrowing it.
+     * @param type name of exception
+     * @param thrown what was thrown
+     */
+    protected void ignoringThrowable(String type, Throwable thrown) {
+        log(type + ": " + thrown.toString(),
+                thrown,
+                Project.MSG_WARN);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java
new file mode 100644
index 0000000..2293cf4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/AbstractAccessTask.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+
+public abstract class AbstractAccessTask
+    extends org.apache.tools.ant.taskdefs.ExecuteOn {
+
+    /**
+     * Chmod task for setting file and directory permissions.
+     */
+    public AbstractAccessTask() {
+        super.setParallel(true);
+        super.setSkipEmptyFilesets(true);
+    }
+
+    /**
+     * Set the file which should have its access attributes modified.
+     * @param src the file to modify
+     */
+    public void setFile(File src) {
+        FileSet fs = new FileSet();
+        fs.setFile(src);
+        addFileset(fs);
+    }
+
+    /**
+     * Prevent the user from specifying a different command.
+     *
+     * @ant.attribute ignore="true"
+     * @param cmdl A user supplied command line that we won't accept.
+     */
+    public void setCommand(Commandline cmdl) {
+        throw new BuildException(getTaskType()
+                                 + " doesn\'t support the command attribute",
+                                 getLocation());
+    }
+
+    /**
+     * Prevent the skipping of empty filesets
+     *
+     * @ant.attribute ignore="true"
+     * @param skip A user supplied boolean we won't accept.
+     */
+    public void setSkipEmptyFilesets(boolean skip) {
+        throw new BuildException(getTaskType() + " doesn\'t support the "
+                                 + "skipemptyfileset attribute",
+                                 getLocation());
+    }
+
+    /**
+     * Prevent the use of the addsourcefile atribute.
+     *
+     * @ant.attribute ignore="true"
+     * @param b A user supplied boolean we won't accept.
+     */
+    public void setAddsourcefile(boolean b) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the addsourcefile attribute", getLocation());
+    }
+
+    /**
+     * Automatically approve Unix OS's.
+     * @return true if a valid OS, for unix this is always true, otherwise
+     *              use the superclasses' test (user set).
+     */
+    protected boolean isValidOs() {
+        return Os.isFamily("unix") && super.isValidOs();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java
new file mode 100644
index 0000000..403fc2d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chgrp.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Chgrp equivalent for unix-like environments.
+ *
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+public class Chgrp extends AbstractAccessTask {
+
+    private boolean haveGroup = false;
+
+    /**
+     * Chgrp task for setting unix group of a file.
+     */
+    public Chgrp() {
+        super.setExecutable("chgrp");
+    }
+
+    /**
+     * Set the group atribute.
+     *
+     * @param group    The new group for the file(s) or directory(ies)
+     */
+    public void setGroup(String group) {
+        createArg().setValue(group);
+        haveGroup = true;
+    }
+
+    /**
+     * Ensure that all the required arguments and other conditions have
+     * been set.
+     */
+    protected void checkConfiguration() {
+        if (!haveGroup) {
+            throw new BuildException("Required attribute group not set in "
+                                     + "chgrp", getLocation());
+        }
+        super.checkConfiguration();
+    }
+
+    /**
+     * We don't want to expose the executable atribute, so overide it.
+     *
+     * @param e User supplied executable that we won't accept.
+     */
+    public void setExecutable(String e) {
+        throw new BuildException(getTaskType()
+                                 + " doesn\'t support the executable"
+                                 + " attribute", getLocation());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java
new file mode 100644
index 0000000..ba1028b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Chown.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Chown equivalent for unix-like environments.
+ *
+ * @since Ant 1.6
+ *
+ * @ant.task category="filesystem"
+ */
+public class Chown extends AbstractAccessTask {
+
+    private boolean haveOwner = false;
+
+    /**
+     * Chown task for setting file and directory permissions.
+     */
+    public Chown() {
+        super.setExecutable("chown");
+    }
+
+    /**
+     * Set the owner atribute.
+     *
+     * @param owner    The new owner for the file(s) or directory(ies)
+     */
+    public void setOwner(String owner) {
+        createArg().setValue(owner);
+        haveOwner = true;
+    }
+
+    /**
+     * Ensure that all the required arguments and other conditions have
+     * been set.
+     */
+    protected void checkConfiguration() {
+        if (!haveOwner) {
+            throw new BuildException("Required attribute owner not set in"
+                                     + " chown", getLocation());
+        }
+        super.checkConfiguration();
+    }
+
+    /**
+     * We don't want to expose the executable atribute, so overide it.
+     *
+     * @param e User supplied executable that we won't accept.
+     */
+    public void setExecutable(String e) {
+        throw new BuildException(getTaskType()
+                                 + " doesn\'t support the executable"
+                                 + " attribute", getLocation());
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
new file mode 100644
index 0000000..9cd2967
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/unix/Symlink.java
@@ -0,0 +1,605 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was developed on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileNotFoundException;
+
+import java.util.Vector;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.dispatch.DispatchTask;
+import org.apache.tools.ant.dispatch.DispatchUtils;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Creates, Deletes, Records and Restores Symlinks.
+ *
+ * <p> This task performs several related operations. In the most trivial
+ * and default usage, it creates a link specified in the link attribute to
+ * a resource specified in the resource attribute. The second usage of this
+ * task is to traverse a directory structure specified by a fileset,
+ * and write a properties file in each included directory describing the
+ * links found in that directory. The third usage is to traverse a
+ * directory structure specified by a fileset, looking for properties files
+ * (also specified as included in the fileset) and recreate the links
+ * that have been previously recorded for each directory. Finally, it can be
+ * used to remove a symlink without deleting the associated resource.
+ *
+ * <p> Usage examples:
+ *
+ * <p> Make a link named &quot;foo&quot; to a resource named
+ * &quot;bar.foo&quot; in subdir:
+ * <pre>
+ * &lt;symlink link=&quot;${dir.top}/foo&quot; resource=&quot;${dir.top}/subdir/bar.foo&quot;/&gt;
+ * </pre>
+ *
+ * <p> Record all links in subdir and its descendants in files named
+ * &quot;dir.links&quot;:
+ * <pre>
+ * &lt;symlink action=&quot;record&quot; linkfilename=&quot;dir.links&quot;&gt;
+ *    &lt;fileset dir=&quot;${dir.top}&quot; includes=&quot;subdir&#47;**&quot; /&gt;
+ * &lt;/symlink&gt;
+ * </pre>
+ *
+ * <p> Recreate the links recorded in the previous example:
+ * <pre>
+ * &lt;symlink action=&quot;recreate&quot;&gt;
+ *    &lt;fileset dir=&quot;${dir.top}&quot; includes=&quot;subdir&#47;**&#47;dir.links&quot; /&gt;
+ * &lt;/symlink&gt;
+ * </pre>
+ *
+ * <p> Delete a link named &quot;foo&quot; to a resource named
+ * &quot;bar.foo&quot; in subdir:
+ * <pre>
+ * &lt;symlink action=&quot;delete&quot; link=&quot;${dir.top}/foo&quot;/&gt;
+ * </pre>
+ *
+ * <p><strong>LIMITATIONS:</strong> Because Java has no direct support for
+ * handling symlinks this task divines them by comparing canonical and
+ * absolute paths. On non-unix systems this may cause false positives.
+ * Furthermore, any operating system on which the command
+ * <code>ln -s link resource</code> is not a valid command on the command line
+ * will not be able to use action=&quot;delete&quot;, action=&quot;single&quot;
+ * or action=&quot;recreate&quot;, but action=&quot;record&quot; should still
+ * work. Finally, the lack of support for symlinks in Java means that all links
+ * are recorded as links to the <strong>canonical</strong> resource name.
+ * Therefore the link: <code>link --> subdir/dir/../foo.bar</code> will be
+ * recorded as <code>link=subdir/foo.bar</code> and restored as
+ * <code>link --> subdir/foo.bar</code>.
+ *
+ */
+public class Symlink extends DispatchTask {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private String resource;
+    private String link;
+    private Vector fileSets = new Vector();
+    private String linkFileName;
+    private boolean overwrite;
+    private boolean failonerror;
+    private boolean executing = false;
+
+    /**
+     * Initialize the task.
+     * @throws BuildException on error.
+     */
+    public void init() throws BuildException {
+        super.init();
+        setDefaults();
+    }
+
+    /**
+     * The standard method for executing any task.
+     * @throws BuildException on error.
+     */
+    public synchronized void execute() throws BuildException {
+        if (executing) {
+            throw new BuildException(
+                "Infinite recursion detected in Symlink.execute()");
+        }
+        try {
+            executing = true;
+            DispatchUtils.execute(this);
+        } finally {
+            executing = false;
+        }
+    }
+
+    /**
+     * Create a symlink.
+     * @throws BuildException on error.
+     * @since Ant 1.7
+     */
+    public void single() throws BuildException {
+        try {
+            if (resource == null) {
+                handleError("Must define the resource to symlink to!");
+                return;
+            }
+            if (link == null) {
+                handleError("Must define the link name for symlink!");
+                return;
+            }
+            doLink(resource, link);
+        } finally {
+            setDefaults();
+        }
+    }
+
+    /**
+     * Delete a symlink.
+     * @throws BuildException on error.
+     * @since Ant 1.7
+     */
+    public void delete() throws BuildException {
+        try {
+            if (link == null) {
+                handleError("Must define the link name for symlink!");
+                return;
+            }
+            log("Removing symlink: " + link);
+            deleteSymlink(link);
+        } catch (FileNotFoundException fnfe) {
+            handleError(fnfe.toString());
+        } catch (IOException ioe) {
+            handleError(ioe.toString());
+        } finally {
+            setDefaults();
+        }
+    }
+
+    /**
+     * Restore symlinks.
+     * @throws BuildException on error.
+     * @since Ant 1.7
+     */
+    public void recreate() throws BuildException {
+        try {
+            if (fileSets.isEmpty()) {
+                handleError("File set identifying link file(s) "
+                            + "required for action recreate");
+                return;
+            }
+            Properties links = loadLinks(fileSets);
+
+            for (Iterator kitr = links.keySet().iterator(); kitr.hasNext();) {
+                String lnk = (String) kitr.next();
+                String res = links.getProperty(lnk);
+                // handle the case where lnk points to a directory (bug 25181)
+                try {
+                    File test = new File(lnk);
+                    if (!FILE_UTILS.isSymbolicLink(null, lnk)) {
+                        doLink(res, lnk);
+                    } else if (!test.getCanonicalPath().equals(
+                        new File(res).getCanonicalPath())) {
+                        deleteSymlink(lnk);
+                        doLink(res, lnk);
+                    } // else lnk exists, do nothing
+                } catch (IOException ioe) {
+                    handleError("IO exception while creating link");
+                }
+            }
+        } finally {
+            setDefaults();
+        }
+    }
+
+    /**
+     * Record symlinks.
+     * @throws BuildException on error.
+     * @since Ant 1.7
+     */
+    public void record() throws BuildException {
+        try {
+            if (fileSets.isEmpty()) {
+                handleError("Fileset identifying links to record required");
+                return;
+            }
+            if (linkFileName == null) {
+                handleError("Name of file to record links in required");
+                return;
+            }
+            // create a hashtable to group them by parent directory:
+            Hashtable byDir = new Hashtable();
+
+            // get an Iterator of file objects representing links (canonical):
+            for (Iterator litr = findLinks(fileSets).iterator();
+                litr.hasNext();) {
+                File thisLink = (File) litr.next();
+                File parent = thisLink.getParentFile();
+                Vector v = (Vector) byDir.get(parent);
+                if (v == null) {
+                    v = new Vector();
+                    byDir.put(parent, v);
+                }
+                v.addElement(thisLink);
+            }
+            // write a Properties file in each directory:
+            for (Iterator dirs = byDir.keySet().iterator(); dirs.hasNext();) {
+                File dir = (File) dirs.next();
+                Vector linksInDir = (Vector) byDir.get(dir);
+                Properties linksToStore = new Properties();
+
+                // fill up a Properties object with link and resource names:
+                for (Iterator dlnk = linksInDir.iterator(); dlnk.hasNext();) {
+                    File lnk = (File) dlnk.next();
+                    try {
+                        linksToStore.put(lnk.getName(), lnk.getCanonicalPath());
+                    } catch (IOException ioe) {
+                        handleError("Couldn't get canonical name of parent link");
+                    }
+                }
+                writePropertyFile(linksToStore, dir);
+            }
+        } finally {
+            setDefaults();
+        }
+    }
+
+    /**
+     * Return all variables to their default state for the next invocation.
+     * @since Ant 1.7
+     */
+    private void setDefaults() {
+        resource = null;
+        link = null;
+        linkFileName = null;
+        failonerror = true;   // default behavior is to fail on an error
+        overwrite = false;    // default behavior is to not overwrite
+        setAction("single");      // default behavior is make a single link
+        fileSets.clear();
+    }
+
+    /**
+     * Set overwrite mode. If set to false (default)
+     * the task will not overwrite existing links, and may stop the build
+     * if a link already exists depending on the setting of failonerror.
+     *
+     * @param owrite If true overwrite existing links.
+     */
+    public void setOverwrite(boolean owrite) {
+        this.overwrite = owrite;
+    }
+
+    /**
+     * Set failonerror mode. If set to true (default) the entire build fails
+     * upon error; otherwise the error is logged and the build will continue.
+     *
+     * @param foe    If true throw BuildException on error, else log it.
+     */
+    public void setFailOnError(boolean foe) {
+        this.failonerror = foe;
+    }
+
+    /**
+     * Set the action to be performed.  May be &quot;single&quot;,
+     * &quot;delete&quot;, &quot;recreate&quot; or &quot;record&quot;.
+     *
+     * @param action    The action to perform.
+     */
+    public void setAction(String action) {
+        super.setAction(action);
+    }
+
+    /**
+     * Set the name of the link. Used when action = &quot;single&quot;.
+     *
+     * @param lnk     The name for the link.
+     */
+    public void setLink(String lnk) {
+        this.link = lnk;
+    }
+
+    /**
+     * Set the name of the resource to which a link should be created.
+     * Used when action = &quot;single&quot;.
+     *
+     * @param src      The resource to be linked.
+     */
+    public void setResource(String src) {
+        this.resource = src;
+    }
+
+    /**
+     * Set the name of the file to which links will be written.
+     * Used when action = &quot;record&quot;.
+     *
+     * @param lf      The name of the file to write links to.
+     */
+    public void setLinkfilename(String lf) {
+        this.linkFileName = lf;
+    }
+
+    /**
+     * Add a fileset to this task.
+     *
+     * @param set      The fileset to add.
+     */
+    public void addFileset(FileSet set) {
+        fileSets.addElement(set);
+    }
+
+    /**
+     * Delete a symlink (without deleting the associated resource).
+     *
+     * <p>This is a convenience method that simply invokes
+     * <code>deleteSymlink(java.io.File)</code>.
+     *
+     * @param path    A string containing the path of the symlink to delete.
+     *
+     * @throws FileNotFoundException   When the path results in a
+     *                                   <code>File</code> that doesn't exist.
+     * @throws IOException             If calls to <code>File.rename</code>
+     *                                   or <code>File.delete</code> fail.
+     */
+    public static void deleteSymlink(String path)
+        throws IOException, FileNotFoundException {
+        deleteSymlink(new File(path));
+    }
+
+    /**
+     * Delete a symlink (without deleting the associated resource).
+     *
+     * <p>This is a utility method that removes a unix symlink without removing
+     * the resource that the symlink points to. If it is accidentally invoked
+     * on a real file, the real file will not be harmed, but an exception
+     * will be thrown when the deletion is attempted. This method works by
+     * getting the canonical path of the link, using the canonical path to
+     * rename the resource (breaking the link) and then deleting the link.
+     * The resource is then returned to its original name inside a finally
+     * block to ensure that the resource is unharmed even in the event of
+     * an exception.
+     *
+     * @param linkfil    A <code>File</code> object of the symlink to delete.
+     *
+     * @throws IOException             If calls to <code>File.rename</code>,
+     *                                   <code>File.delete</code> or
+     *                                   <code>File.getCanonicalPath</code>
+     *                                   fail.
+     */
+    public static void deleteSymlink(File linkfil)
+        throws IOException {
+        if (!linkfil.exists()) {
+            throw new FileNotFoundException("No such symlink: " + linkfil);
+        }
+        // find the resource of the existing link:
+        File canfil = linkfil.getCanonicalFile();
+
+        // rename the resource, thus breaking the link:
+        File temp = FILE_UTILS.createTempFile("symlink", ".tmp",
+                                              canfil.getParentFile(), false, false);
+        try {
+            try {
+                FILE_UTILS.rename(canfil, temp);
+            } catch (IOException e) {
+                throw new IOException(
+                    "Couldn't rename resource when attempting to delete "
+                    + linkfil);
+            }
+            // delete the (now) broken link:
+            if (!linkfil.delete()) {
+                throw new IOException("Couldn't delete symlink: " + linkfil
+                    + " (was it a real file? is this not a UNIX system?)");
+            }
+        } finally {
+            // return the resource to its original name:
+            try {
+                FILE_UTILS.rename(temp, canfil);
+            } catch (IOException e) {
+                throw new IOException("Couldn't return resource " + temp
+                    + " to its original name: " + canfil.getAbsolutePath()
+                    + "\n THE RESOURCE'S NAME ON DISK HAS "
+                    + "BEEN CHANGED BY THIS ERROR!\n");
+            }
+        }
+    }
+
+    /**
+     * Write a properties file. This method uses <code>Properties.store</code>
+     * and thus may throw exceptions that occur while writing the file.
+     *
+     * @param properties     The properties object to be written.
+     * @param dir            The directory for which we are writing the links.
+     * @throws BuildException if the property file could not be written
+     */
+    private void writePropertyFile(Properties properties, File dir)
+        throws BuildException {
+        BufferedOutputStream bos = null;
+        try {
+            bos = new BufferedOutputStream(
+                new FileOutputStream(new File(dir, linkFileName)));
+            properties.store(bos, "Symlinks from " + dir);
+        } catch (IOException ioe) {
+            throw new BuildException(ioe, getLocation());
+        } finally {
+            FileUtils.close(bos);
+        }
+    }
+
+    /**
+     * Handle errors based on the setting of failonerror.
+     *
+     * @param msg    The message to log, or include in the
+     *                  <code>BuildException</code>.
+     * @throws BuildException with the message if failonerror=true
+     */
+    private void handleError(String msg) {
+        if (failonerror) {
+            throw new BuildException(msg);
+        }
+        log(msg);
+    }
+
+    /**
+     * Conduct the actual construction of a link.
+     *
+     * <p> The link is constructed by calling <code>Execute.runCommand</code>.
+     *
+     * @param res   The path of the resource we are linking to.
+     * @param lnk       The name of the link we wish to make.
+     * @throws BuildException when things go wrong
+     */
+    private void doLink(String res, String lnk) throws BuildException {
+        File linkfil = new File(lnk);
+        String options = "-s";
+        if (overwrite) {
+            options += "f";
+            if (linkfil.exists()) {
+                try {
+                    deleteSymlink(linkfil);
+                } catch (FileNotFoundException fnfe) {
+                    log("Symlink disappeared before it was deleted: " + lnk);
+                } catch (IOException ioe) {
+                    log("Unable to overwrite preexisting link or file: " + lnk,
+                        ioe, Project.MSG_INFO);
+                }
+            }
+        }
+        String[] cmd = new String[] {"ln", options, res, lnk};
+        try {
+            Execute.runCommand(this, cmd);
+        } catch (BuildException failedToExecute) {
+            if (failonerror) {
+                throw failedToExecute;
+            } else {
+                //log at the info level, and keep going.
+                log(failedToExecute.getMessage(), failedToExecute, Project.MSG_INFO);
+            }
+        }
+    }
+
+    /**
+     * Find all the links in all supplied filesets.
+     *
+     * <p> This method is invoked when the action attribute is
+     * &quot;record&quot;. This means that filesets are interpreted
+     * as the directories in which links may be found.
+     *
+     * @param v   The filesets specified by the user.
+     * @return A HashSet of <code>File</code> objects containing the
+     *         links (with canonical parent directories).
+     */
+    private HashSet findLinks(Vector v) {
+        HashSet result = new HashSet();
+        for (int i = 0; i < v.size(); i++) {
+            FileSet fs = (FileSet) v.get(i);
+            DirectoryScanner ds = fs.getDirectoryScanner(getProject());
+            String[][] fnd = new String[][]
+                {ds.getIncludedFiles(), ds.getIncludedDirectories()};
+            File dir = fs.getDir(getProject());
+            for (int j = 0; j < fnd.length; j++) {
+                for (int k = 0; k < fnd[j].length; k++) {
+                    try {
+                        File f = new File(dir, fnd[j][k]);
+                        File pf = f.getParentFile();
+                        String name = f.getName();
+                        if (FILE_UTILS.isSymbolicLink(pf, name)) {
+                            result.add(new File(pf.getCanonicalFile(), name));
+                        }
+                    } catch (IOException e) {
+                        handleError("IOException: " + fnd[j][k] + " omitted");
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Load links from properties files included in one or more FileSets.
+     *
+     * <p> This method is only invoked when the action attribute is set to
+     * &quot;recreate&quot;. The filesets passed in are assumed to specify the
+     * names of the property files with the link information and the
+     * subdirectories in which to look for them.
+     *
+     * @param v    The <code>FileSet</code>s for this task.
+     * @return            The links to be made.
+     */
+    private Properties loadLinks(Vector v) {
+        Properties finalList = new Properties();
+        // loop through the supplied file sets:
+        for (int i = 0; i < v.size(); i++) {
+            FileSet fs = (FileSet) v.elementAt(i);
+            DirectoryScanner ds = new DirectoryScanner();
+            fs.setupDirectoryScanner(ds, getProject());
+            ds.setFollowSymlinks(false);
+            ds.scan();
+            String[] incs = ds.getIncludedFiles();
+            File dir = fs.getDir(getProject());
+
+            // load included files as properties files:
+            for (int j = 0; j < incs.length; j++) {
+                File inc = new File(dir, incs[j]);
+                File pf = inc.getParentFile();
+                Properties lnks = new Properties();
+                try {
+                    lnks.load(new BufferedInputStream(new FileInputStream(inc)));
+                    pf = pf.getCanonicalFile();
+                } catch (FileNotFoundException fnfe) {
+                    handleError("Unable to find " + incs[j] + "; skipping it.");
+                    continue;
+                } catch (IOException ioe) {
+                    handleError("Unable to open " + incs[j]
+                                + " or its parent dir; skipping it.");
+                    continue;
+                }
+                lnks.list(new PrintStream(
+                    new LogOutputStream(this, Project.MSG_INFO)));
+                // Write the contents to our master list of links
+                // This method assumes that all links are defined in
+                // terms of absolute paths, or paths relative to the
+                // working directory:
+                for (Iterator kitr = lnks.keySet().iterator(); kitr.hasNext();) {
+                    String key = (String) kitr.next();
+                    finalList.put(new File(pf, key).getAbsolutePath(),
+                        lnks.getProperty(key));
+                }
+            }
+        }
+        return finalList;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java
new file mode 100644
index 0000000..f00487c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSS.java
@@ -0,0 +1,783 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import java.io.File;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A base class for creating tasks for executing commands on Visual SourceSafe.
+ * <p>
+ * The class extends the 'exec' task as it operates by executing the ss.exe program
+ * supplied with SourceSafe. By default the task expects ss.exe to be in the path,
+ * you can override this be specifying the ssdir attribute.
+ * </p>
+ * <p>
+ * This class provides set and get methods for 'login' and 'vsspath' attributes. It
+ * also contains constants for the flags that can be passed to SS.
+ * </p>
+ *
+ */
+public abstract class MSVSS extends Task implements MSVSSConstants {
+
+    private String ssDir = null;
+    private String vssLogin = null;
+    private String vssPath = null;
+    private String serverPath = null;
+
+    /**  Version */
+    private String version = null;
+    /**  Date */
+    private String date = null;
+    /**  Label */
+    private String label = null;
+    /**  Auto response */
+    private String autoResponse = null;
+    /**  Local path */
+    private String localPath = null;
+    /**  Comment */
+    private String comment = null;
+    /**  From label */
+    private String fromLabel = null;
+    /**  To label */
+    private String toLabel = null;
+    /**  Output file name */
+    private String outputFileName = null;
+    /**  User */
+    private String user = null;
+    /**  From date */
+    private String fromDate = null;
+    /**  To date */
+    private String toDate = null;
+    /**  History style */
+    private String style = null;
+    /**  Quiet defaults to false */
+    private boolean quiet = false;
+    /**  Recursive defaults to false */
+    private boolean recursive = false;
+    /**  Writable defaults to false */
+    private boolean writable = false;
+    /**  Fail on error defaults to true */
+    private boolean failOnError = true;
+    /**  Get local copy for checkout defaults to true */
+    private boolean getLocalCopy = true;
+    /**  Number of days offset for History */
+    private int numDays = Integer.MIN_VALUE;
+    /**  Date format for History */
+    private DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
+    /**  Timestamp for retreived files */
+    private CurrentModUpdated timestamp = null;
+    /**  Behaviour for writable files */
+    private WritableFiles writableFiles = null;
+
+    /**
+     * Each sub-class must implemnt this method and return the constructed
+     * command line to be executed. It is up to the sub-task to determine the
+     * required attrubutes and their order.
+     * @return    The Constructed command line.
+     */
+    abstract Commandline buildCmdLine();
+
+    /**
+     * Directory where <code>ss.exe</code> resides.
+     * By default the task expects it to be in the PATH.
+     * @param  dir  The directory containing ss.exe.
+     */
+    public final void setSsdir(String dir) {
+        this.ssDir = FileUtils.translatePath(dir);
+    }
+
+    /**
+     * Login to use when accessing VSS, formatted as "username,password".
+     * <p>
+     * You can omit the password if your database is not password protected.
+     * If you have a password and omit it, Ant will hang.
+     * @param  vssLogin  The login string to use.
+     */
+    public final void setLogin(final String vssLogin) {
+        this.vssLogin = vssLogin;
+    }
+
+    /**
+     * SourceSafe path which specifies the project/file(s) you wish to perform
+     * the action on.
+     * <p>
+     * A prefix of 'vss://' will be removed if specified.
+     * @param  vssPath  The VSS project path.
+     * @ant.attribute group="required"
+     */
+    public final void setVsspath(final String vssPath) {
+        String projectPath;
+        // CheckStyle:MagicNumber OFF
+        if (vssPath.startsWith("vss://")) { //$NON-NLS-1$
+            projectPath = vssPath.substring(5);
+        } else {
+            projectPath = vssPath;
+        }
+        // CheckStyle:MagicNumber ON
+
+        if (projectPath.startsWith(PROJECT_PREFIX)) {
+            this.vssPath = projectPath;
+        } else {
+            this.vssPath = PROJECT_PREFIX + projectPath;
+        }
+    }
+
+    /**
+     * Directory where <code>srssafe.ini</code> resides.
+     * @param  serverPath  The path to the VSS server.
+     */
+    public final void setServerpath(final String serverPath) {
+        this.serverPath = serverPath;
+    }
+
+    /**
+     * Indicates if the build should fail if the Sourcesafe command does. Defaults to true.
+     * @param failOnError True if task should fail on any error.
+     */
+    public final void setFailOnError(final boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * Executes the task. <br>
+     * Builds a command line to execute ss.exe and then calls Exec's run method
+     * to execute the command line.
+     * @throws BuildException if the command cannot execute.
+     */
+    public void execute() throws BuildException {
+        int result = 0;
+        Commandline commandLine = buildCmdLine();
+        result = run(commandLine);
+        if (Execute.isFailure(result) && getFailOnError()) {
+            String msg = "Failed executing: " + formatCommandLine(commandLine)
+                     + " With a return code of " + result;
+            throw new BuildException(msg, getLocation());
+        }
+    }
+
+    // Special setters for the sub-classes
+
+    /**
+     * Set the internal comment attribute.
+     * @param comment the value to use.
+     */
+    protected void setInternalComment(final String comment) {
+        this.comment = comment;
+    }
+
+    /**
+     * Set the auto response attribute.
+     * @param autoResponse the value to use.
+     */
+    protected void setInternalAutoResponse(final String autoResponse) {
+        this.autoResponse = autoResponse;
+    }
+
+    /**
+     * Set the date attribute.
+     * @param date the value to use.
+     */
+    protected void setInternalDate(final String date) {
+        this.date = date;
+    }
+
+    /**
+     * Set the date format attribute.
+     * @param dateFormat the value to use.
+     */
+    protected void setInternalDateFormat(final DateFormat dateFormat) {
+        this.dateFormat = dateFormat;
+    }
+
+    /**
+     * Set the failOnError attribute.
+     * @param failOnError the value to use.
+     */
+    protected void setInternalFailOnError(final boolean failOnError) {
+        this.failOnError = failOnError;
+    }
+
+    /**
+     * Set the from date attribute.
+     * @param fromDate the value to use.
+     */
+    protected void setInternalFromDate(final String fromDate) {
+        this.fromDate = fromDate;
+    }
+
+    /**
+     * Set the from label attribute.
+     * @param fromLabel the value to use.
+     */
+    protected void setInternalFromLabel(final String fromLabel) {
+        this.fromLabel = fromLabel;
+    }
+
+    /**
+     * Set the label attribute.
+     * @param label the value to use.
+     */
+    protected void setInternalLabel(final String label) {
+        this.label = label;
+    }
+
+    /**
+     * Set the local path comment attribute.
+     * @param localPath the value to use.
+     */
+    protected void setInternalLocalPath(final String localPath) {
+        this.localPath = localPath;
+    }
+
+    /**
+     * Set the num days attribute.
+     * @param numDays the value to use.
+     */
+    protected void setInternalNumDays(final int numDays) {
+        this.numDays = numDays;
+    }
+
+    /**
+     * Set the outputFileName comment attribute.
+     * @param outputFileName the value to use.
+     */
+    protected void setInternalOutputFilename(final String outputFileName) {
+        this.outputFileName = outputFileName;
+    }
+
+    /**
+     * Set the quiet attribute.
+     * @param quiet the value to use.
+     */
+    protected void setInternalQuiet(final boolean quiet) {
+        this.quiet = quiet;
+    }
+
+    /**
+     * Set the recursive attribute.
+     * @param recursive the value to use.
+     */
+    protected void setInternalRecursive(final boolean recursive) {
+        this.recursive = recursive;
+    }
+
+    /**
+     * Set the style attribute.
+     * @param style the value to use.
+     */
+    protected void setInternalStyle(final String style) {
+        this.style = style;
+    }
+
+    /**
+     * Set the to date attribute.
+     * @param toDate the value to use.
+     */
+    protected void setInternalToDate(final String toDate) {
+        this.toDate = toDate;
+    }
+
+    /**
+     * Set the to label attribute.
+     * @param toLabel the value to use.
+     */
+    protected void setInternalToLabel(final String toLabel) {
+        this.toLabel = toLabel;
+    }
+
+    /**
+     * Set the user attribute.
+     * @param user the value to use.
+     */
+    protected void setInternalUser(final String user) {
+        this.user = user;
+    }
+
+    /**
+     * Set the version attribute.
+     * @param version the value to use.
+     */
+    protected void setInternalVersion(final String version) {
+        this.version = version;
+    }
+
+    /**
+     * Set the writable attribute.
+     * @param writable the value to use.
+     */
+    protected void setInternalWritable(final boolean writable) {
+        this.writable = writable;
+    }
+
+    /**
+     * Set the timestamp attribute.
+     * @param timestamp the value to use.
+     */
+    protected void setInternalFileTimeStamp(final CurrentModUpdated timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    /**
+     * Set the writableFiles attribute.
+     * @param writableFiles the value to use.
+     */
+    protected void setInternalWritableFiles(final WritableFiles writableFiles) {
+        this.writableFiles = writableFiles;
+    }
+
+    /**
+     * Set the getLocalCopy attribute.
+     * @param getLocalCopy the value to use.
+     */
+    protected void setInternalGetLocalCopy(final boolean getLocalCopy) {
+        this.getLocalCopy = getLocalCopy;
+    }
+
+    /**
+     * Gets the sscommand string. "ss" or "c:\path\to\ss"
+     * @return    The path to ss.exe or just ss if sscommand is not set.
+     */
+    protected String getSSCommand() {
+        if (ssDir == null) {
+            return SS_EXE;
+        }
+        return ssDir.endsWith(File.separator) ? ssDir + SS_EXE : ssDir
+                 + File.separator + SS_EXE;
+    }
+
+    /**
+     * Gets the vssserverpath string.
+     * @return    null if vssserverpath is not set.
+     */
+    protected String getVsspath() {
+        return vssPath;
+    }
+
+    /**
+     * Gets the quiet string. -O-
+     * @return An empty string if quiet is not set or is false.
+     */
+    protected String getQuiet() {
+        return quiet ? FLAG_QUIET : "";
+    }
+
+    /**
+     * Gets the recursive string. "-R"
+     * @return An empty string if recursive is not set or is false.
+     */
+    protected String getRecursive() {
+        return recursive ? FLAG_RECURSION : "";
+    }
+
+    /**
+     * Gets the writable string. "-W"
+     * @return An empty string if writable is not set or is false.
+     */
+    protected String getWritable() {
+        return writable ? FLAG_WRITABLE : "";
+    }
+
+    /**
+     * Gets the label string. "-Lbuild1"
+     * Max label length is 32 chars
+     * @return An empty string if label is not set.
+     */
+    protected String getLabel() {
+        String shortLabel = "";
+        if (label != null && label.length() > 0) {
+                shortLabel = FLAG_LABEL + getShortLabel();
+        }
+        return shortLabel;
+    }
+    /**
+     * Return at most the 30 first chars of the label,
+     * logging a warning message about the truncation
+     * @return at most the 30 first chars of the label
+     */
+    private String getShortLabel() {
+        String shortLabel;
+        // CheckStyle:MagicNumber OFF
+        if (label !=  null && label.length() > 31) {
+            shortLabel = this.label.substring(0, 30);
+            log("Label is longer than 31 characters, truncated to: " + shortLabel,
+                Project.MSG_WARN);
+        } else {
+            shortLabel = label;
+        }
+        // CheckStyle:MagicNumber ON
+        return shortLabel;
+    }
+    /**
+     * Gets the style string. "-Lbuild1"
+     * @return An empty string if label is not set.
+     */
+    protected String getStyle() {
+        return style != null ? style : "";
+    }
+
+    /**
+     * Gets the version string. Returns the first specified of version "-V1.0",
+     * date "-Vd01.01.01", label "-Vlbuild1".
+     * @return An empty string if a version, date and label are not set.
+     */
+    protected String getVersionDateLabel() {
+        String versionDateLabel = "";
+        if (version != null) {
+            versionDateLabel = FLAG_VERSION + version;
+        } else if (date != null) {
+            versionDateLabel = FLAG_VERSION_DATE + date;
+        } else {
+            // Use getShortLabel() so labels longer then 30 char are truncated
+            // and the user is warned
+            String shortLabel = getShortLabel();
+            if (shortLabel != null && !shortLabel.equals("")) {
+                versionDateLabel = FLAG_VERSION_LABEL + shortLabel;
+            }
+        }
+        return versionDateLabel;
+    }
+
+    /**
+     * Gets the version string.
+     * @return An empty string if a version is not set.
+     */
+    protected String getVersion() {
+        return version != null ? FLAG_VERSION + version : "";
+    }
+
+    /**
+     * Gets the localpath string. "-GLc:\source" <p>
+     * The localpath is created if it didn't exist.
+     * @return An empty string if localpath is not set.
+     */
+    protected String getLocalpath() {
+        String lclPath = ""; //set to empty str if no local path return
+        if (localPath != null) {
+            //make sure m_LocalDir exists, create it if it doesn't
+            File dir = getProject().resolveFile(localPath);
+            if (!dir.exists()) {
+                boolean done = dir.mkdirs();
+                if (!done) {
+                    String msg = "Directory " + localPath + " creation was not "
+                            + "successful for an unknown reason";
+                    throw new BuildException(msg, getLocation());
+                }
+                getProject().log("Created dir: " + dir.getAbsolutePath());
+            }
+            lclPath = FLAG_OVERRIDE_WORKING_DIR + localPath;
+        }
+        return lclPath;
+    }
+
+    /**
+     * Gets the comment string. "-Ccomment text"
+     * @return A comment of "-" if comment is not set.
+     */
+    protected String getComment() {
+        return comment != null ? FLAG_COMMENT + comment : FLAG_COMMENT + "-";
+    }
+
+    /**
+     * Gets the auto response string. This can be Y "-I-Y" or N "-I-N".
+     * @return The default value "-I-" if autoresponse is not set.
+     */
+    protected String getAutoresponse() {
+        if (autoResponse == null) {
+            return FLAG_AUTORESPONSE_DEF;
+        } else if (autoResponse.equalsIgnoreCase("Y")) {
+            return FLAG_AUTORESPONSE_YES;
+        } else if (autoResponse.equalsIgnoreCase("N")) {
+            return FLAG_AUTORESPONSE_NO;
+        } else {
+            return FLAG_AUTORESPONSE_DEF;
+        }
+    }
+
+    /**
+     * Gets the login string. This can be user and password, "-Yuser,password"
+     * or just user "-Yuser".
+     * @return An empty string if login is not set.
+     */
+    protected String getLogin() {
+        return vssLogin != null ? FLAG_LOGIN + vssLogin : "";
+    }
+
+    /**
+     * Gets the output file string. "-Ooutput.file"
+     * @return An empty string if user is not set.
+     */
+    protected String getOutput() {
+        return outputFileName != null ? FLAG_OUTPUT + outputFileName : "";
+    }
+
+    /**
+     * Gets the user string. "-Uusername"
+     * @return An empty string if user is not set.
+     */
+    protected String getUser() {
+        return user != null ? FLAG_USER + user : "";
+    }
+
+    /**
+     * Gets the version string. This can be to-from "-VLbuild2~Lbuild1", from
+     * "~Lbuild1" or to "-VLbuild2".
+     * @return An empty string if neither tolabel or fromlabel are set.
+     */
+    protected String getVersionLabel() {
+        if (fromLabel == null && toLabel == null) {
+            return "";
+        }
+        // CheckStyle:MagicNumber OFF
+        if (fromLabel != null && toLabel != null) {
+            if (fromLabel.length() > 31) {
+                fromLabel = fromLabel.substring(0, 30);
+                log("FromLabel is longer than 31 characters, truncated to: "
+                    + fromLabel, Project.MSG_WARN);
+            }
+            if (toLabel.length() > 31) {
+                toLabel = toLabel.substring(0, 30);
+                log("ToLabel is longer than 31 characters, truncated to: "
+                    + toLabel, Project.MSG_WARN);
+            }
+            return FLAG_VERSION_LABEL + toLabel + VALUE_FROMLABEL + fromLabel;
+        } else if (fromLabel != null) {
+            if (fromLabel.length() > 31) {
+                fromLabel = fromLabel.substring(0, 30);
+                log("FromLabel is longer than 31 characters, truncated to: "
+                    + fromLabel, Project.MSG_WARN);
+            }
+            return FLAG_VERSION + VALUE_FROMLABEL + fromLabel;
+        } else {
+            if (toLabel.length() > 31) {
+                toLabel = toLabel.substring(0, 30);
+                log("ToLabel is longer than 31 characters, truncated to: "
+                    + toLabel, Project.MSG_WARN);
+            }
+            return FLAG_VERSION_LABEL + toLabel;
+        }
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Gets the Version date string.
+     * @return An empty string if neither Todate or from date are set.
+     * @throws BuildException if there is an error.
+     */
+    protected String getVersionDate() throws BuildException {
+        if (fromDate == null && toDate == null
+            && numDays == Integer.MIN_VALUE) {
+            return "";
+        }
+        if (fromDate != null && toDate != null) {
+            return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE + fromDate;
+        } else if (toDate != null && numDays != Integer.MIN_VALUE) {
+            try {
+                return FLAG_VERSION_DATE + toDate + VALUE_FROMDATE
+                        + calcDate(toDate, numDays);
+            } catch (ParseException ex) {
+                String msg = "Error parsing date: " + toDate;
+                throw new BuildException(msg, getLocation());
+            }
+        } else if (fromDate != null && numDays != Integer.MIN_VALUE) {
+            try {
+                return FLAG_VERSION_DATE + calcDate(fromDate, numDays)
+                        + VALUE_FROMDATE + fromDate;
+            } catch (ParseException ex) {
+                String msg = "Error parsing date: " + fromDate;
+                throw new BuildException(msg, getLocation());
+            }
+        } else {
+            return fromDate != null ? FLAG_VERSION + VALUE_FROMDATE
+                    + fromDate : FLAG_VERSION_DATE + toDate;
+        }
+    }
+
+    /**
+     * Builds and returns the -G- flag if required.
+     * @return An empty string if get local copy is true.
+     */
+    protected String getGetLocalCopy() {
+        return (!getLocalCopy) ? FLAG_NO_GET : "";
+    }
+
+    /**
+     * Gets the value of the fail on error flag.
+     * @return    True if the FailOnError flag has been set or if 'writablefiles=skip'.
+     */
+    private boolean getFailOnError() {
+        return getWritableFiles().equals(WRITABLE_SKIP) ? false : failOnError;
+    }
+
+
+    /**
+     * Gets the value set for the FileTimeStamp.
+     * if it equals "current" then we return -GTC
+     * if it equals "modified" then we return -GTM
+     * if it equals "updated" then we return -GTU
+     * otherwise we return -GTC
+     *
+     * @return The default file time flag, if not set.
+     */
+    public String getFileTimeStamp() {
+        if (timestamp == null) {
+            return "";
+        } else if (timestamp.getValue().equals(TIME_MODIFIED)) {
+            return FLAG_FILETIME_MODIFIED;
+        } else if (timestamp.getValue().equals(TIME_UPDATED)) {
+            return FLAG_FILETIME_UPDATED;
+        } else {
+            return FLAG_FILETIME_DEF;
+        }
+    }
+
+
+    /**
+     * Gets the value to determine the behaviour when encountering writable files.
+     * @return An empty String, if not set.
+     */
+    public String getWritableFiles() {
+        if (writableFiles == null) {
+            return "";
+        } else if (writableFiles.getValue().equals(WRITABLE_REPLACE)) {
+            return FLAG_REPLACE_WRITABLE;
+        } else if (writableFiles.getValue().equals(WRITABLE_SKIP)) {
+            // ss.exe exits with '100', when files have been skipped
+            // so we have to ignore the failure
+            failOnError = false;
+            return FLAG_SKIP_WRITABLE;
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     *  Sets up the required environment and executes the command line.
+     *
+     * @param  cmd  The command line to execute.
+     * @return      The return code from the exec'd process.
+     */
+    private int run(Commandline cmd) {
+        try {
+            Execute exe = new Execute(new LogStreamHandler(this,
+                    Project.MSG_INFO,
+                    Project.MSG_WARN));
+
+            // If location of ss.ini is specified we need to set the
+            // environment-variable SSDIR to this value
+            if (serverPath != null) {
+                String[] env = exe.getEnvironment();
+                if (env == null) {
+                    env = new String[0];
+                }
+                String[] newEnv = new String[env.length + 1];
+                System.arraycopy(env, 0, newEnv, 0, env.length);
+                newEnv[env.length] = "SSDIR=" + serverPath;
+
+                exe.setEnvironment(newEnv);
+            }
+
+            exe.setAntRun(getProject());
+            exe.setWorkingDirectory(getProject().getBaseDir());
+            exe.setCommandline(cmd.getCommandline());
+            // Use the OS launcher so we get environment variables
+            exe.setVMLauncher(false);
+            return exe.execute();
+        } catch (IOException e) {
+            throw new BuildException(e, getLocation());
+        }
+    }
+
+     /**
+     * Calculates the start date for version comparison.
+     * <p>
+     * Calculates the date numDay days earlier than startdate.
+     * @param   startDate    The start date.
+     * @param   daysToAdd     The number of days to add.
+     * @return The calculated date.
+     * @throws ParseException
+     */
+    private String calcDate(String startDate, int daysToAdd) throws ParseException {
+        Calendar calendar = new GregorianCalendar();
+        Date currentDate = dateFormat.parse(startDate);
+        calendar.setTime(currentDate);
+        calendar.add(Calendar.DATE, daysToAdd);
+        return dateFormat.format(calendar.getTime());
+    }
+
+    /**
+     * Changes the password to '***' so it isn't displayed on screen if the build fails
+     *
+     * @param cmd   The command line to clean
+     * @return The command line as a string with out the password
+     */
+    private String formatCommandLine(Commandline cmd) {
+        StringBuffer sBuff = new StringBuffer(cmd.toString());
+        int indexUser = sBuff.substring(0).indexOf(FLAG_LOGIN);
+        if (indexUser > 0) {
+            int indexPass = sBuff.substring(0).indexOf(",", indexUser);
+            int indexAfterPass = sBuff.substring(0).indexOf(" ", indexPass);
+
+            for (int i = indexPass + 1; i < indexAfterPass; i++) {
+                sBuff.setCharAt(i, '*');
+            }
+        }
+        return sBuff.toString();
+    }
+
+    /**
+     * Extention of EnumeratedAttribute to hold the values for file time stamp.
+     */
+    public static class CurrentModUpdated extends EnumeratedAttribute {
+        /**
+         * Gets the list of allowable values.
+         * @return The values.
+         */
+        public String[] getValues() {
+            return new String[] {TIME_CURRENT, TIME_MODIFIED, TIME_UPDATED};
+        }
+    }
+
+    /**
+     * Extention of EnumeratedAttribute to hold the values for writable filess.
+     */
+    public static class WritableFiles extends EnumeratedAttribute {
+        /**
+         * Gets the list of allowable values.
+         * @return The values.
+         */
+        public String[] getValues() {
+            return new String[] {WRITABLE_REPLACE, WRITABLE_SKIP, WRITABLE_FAIL};
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java
new file mode 100644
index 0000000..0241ee3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSADD.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs Add commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vssadd" category="scm"
+ */
+public class MSVSSADD extends MSVSS {
+
+    private String localPath = null;
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    protected Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a localPath ...
+        if (getLocalpath() == null) {
+            String msg = "localPath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss Add VSS items [-B] [-C] [-D-] [-H] [-I-] [-K] [-N] [-O] [-R] [-W] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_ADD);
+
+        // VSS items
+        commandLine.createArgument().setValue(getLocalpath());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -R
+        commandLine.createArgument().setValue(getRecursive());
+        // -W
+        commandLine.createArgument().setValue(getWritable());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+        // -C
+        commandLine.createArgument().setValue(getComment());
+
+        return commandLine;
+    }
+
+    /**
+     * Returns the local path without the flag.; required
+     * @todo See why this returns the local path without the flag.
+     * @return The local path value.
+     */
+    protected String getLocalpath() {
+        return localPath;
+    }
+
+    /**
+     * Add files recursively. Defaults to false.
+     *
+     * @param recursive  The boolean value for recursive.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Unset the READ-ONLY flag on local copies of files added to VSS. Defaults to false.
+     *
+     * @param   writable The boolean value for writable.
+     */
+    public final void setWritable(boolean writable) {
+        super.setInternalWritable(writable);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+
+    /**
+     * Comment to apply to files added to SourceSafe.
+     *
+     * @param comment The comment to apply in SourceSafe
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+
+    /**
+     * Override the project working directory.
+     *
+     * @param   localPath   The path on disk.
+     */
+    public void setLocalpath(Path localPath) {
+        this.localPath = localPath.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java
new file mode 100644
index 0000000..f9521aa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKIN.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs CheckIn commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscheckin" category="scm"
+ */
+public class MSVSSCHECKIN extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    protected Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir ...
+        if (getVsspath() == null) {
+            String msg = "vsspath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss Checkin VSS items [-H] [-C] [-I-] [-N] [-O] [-R] [-W] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_CHECKIN);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -GL
+        commandLine.createArgument().setValue(getLocalpath());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -R
+        commandLine.createArgument().setValue(getRecursive());
+        // -W
+        commandLine.createArgument().setValue(getWritable());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+        // -C
+        commandLine.createArgument().setValue(getComment());
+
+        return commandLine;
+    }
+
+    /**
+     * Override the project working directory.
+     *
+     * @param   localPath   The path on disk.
+     */
+    public void setLocalpath(Path localPath) {
+        super.setInternalLocalPath(localPath.toString());
+    }
+
+    /**
+     * Check-in files recursively. Defaults to false.
+     *
+     * @param recursive  The boolean value for recursive.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Unset the READ-ONLY flag on local copies of files checked-in to VSS.
+     * Defaults to false.
+     *
+     * @param   writable The boolean value for writable.
+     */
+    public final void setWritable(boolean writable) {
+        super.setInternalWritable(writable);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+
+    /**
+     * Comment to apply to files checked-in to SourceSafe.
+     *
+     * @param comment The comment to apply in SourceSafe
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java
new file mode 100644
index 0000000..edbcde9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCHECKOUT.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Performs CheckOut commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscheckout" category="scm"
+ * @ant.attribute.group name="vdl" description="Only one of version, date or label"
+ */
+public class MSVSSCHECKOUT extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    protected Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir ...
+        if (getVsspath() == null) {
+            String msg = "vsspath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss Checkout VSS items [-G] [-C] [-H] [-I-] [-N] [-O] [-R] [-V] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_CHECKOUT);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -GL
+        commandLine.createArgument().setValue(getLocalpath());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -R
+        commandLine.createArgument().setValue(getRecursive());
+        // -V
+        commandLine.createArgument().setValue(getVersionDateLabel());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+        // -G
+        commandLine.createArgument().setValue(getFileTimeStamp());
+        // -GWS or -GWR
+        commandLine.createArgument().setValue(getWritableFiles());
+        // -G-
+        commandLine.createArgument().setValue(getGetLocalCopy());
+
+        return commandLine;
+    }
+
+    /**
+     * Override the project working directory.
+     *
+     * @param   localPath   The path on disk.
+     */
+    public void setLocalpath(Path localPath) {
+        super.setInternalLocalPath(localPath.toString());
+    }
+
+    /**
+     * Check-out files recursively. Defaults to false.
+     *
+     * @param recursive  The boolean value for recursive.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Version to check-out.
+     *
+     * @param  version The version to check-out.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setVersion(String version) {
+        super.setInternalVersion(version);
+    }
+
+    /**
+     * Date to check-out.
+     *
+     * @param  date The date to check-out.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setDate(String date) {
+        super.setInternalDate(date);
+    }
+
+    /**
+     * Label to check-out.
+     *
+     * @param  label The label to check-out.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setLabel(String label) {
+        super.setInternalLabel(label);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+
+    /**
+     * Date and time stamp given to the local copy. Defaults to <code>current</code>.
+     *
+     * @param timestamp     The file time stamping behaviour.
+     */
+    public void setFileTimeStamp(CurrentModUpdated timestamp) {
+        super.setInternalFileTimeStamp(timestamp);
+    }
+
+    /**
+     * Action taken when local files are writable. Defaults to <code>fail</code>.
+     * <p>
+     * Due to ss.exe returning with an exit code of '100' for both errors and when
+     * a file has been skipped, <code>failonerror</code> is set to false when using
+     * the <code>skip</code> option.
+     * </p>
+     *
+     * @param files     The writable files behaviour
+     */
+    public void setWritableFiles(WritableFiles files) {
+        super.setInternalWritableFiles(files);
+    }
+
+    /**
+     * Retrieve a local copy during a checkout. Defaults to true.
+     *
+     * @param get   The get local copy behaviour
+     */
+    public void setGetLocalCopy(boolean get) {
+        super.setInternalGetLocalCopy(get);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java
new file mode 100644
index 0000000..ae2fcb7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCP.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs CP (Change Project) commands to Microsoft Visual SourceSafe.
+ * <p>This task is typically used before a VssAdd in order to set the target project</p>
+ *
+ * @ant.task name="vsscp" category="scm"
+ */
+public class MSVSSCP extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    protected Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir ...
+        if (getVsspath() == null) {
+            String msg = "vsspath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss CP VSS items [-H] [-I-] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_CP);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+
+        return commandLine;
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java
new file mode 100644
index 0000000..4f298c0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSCREATE.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Creates a new project in Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsscreate" category="scm"
+ */
+public class MSVSSCREATE extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir...
+        if (getVsspath() == null) {
+            String msg = "vsspath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got
+        // the format is:
+        // ss Create VSS items [-C] [-H] [-I-] [-N] [-O] [-S] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_CREATE);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -C
+        commandLine.createArgument().setValue(getComment());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -O-
+        commandLine.createArgument().setValue(getQuiet());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+
+        return commandLine;
+    }
+
+    /**
+     * Comment to apply to the project created in SourceSafe.
+     *
+     * @param comment The comment to apply in SourceSafe
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+
+    /**
+     * Enable quiet mode. Defaults to false.
+     *
+     * @param   quiet The boolean value for quiet.
+     */
+    public final void setQuiet (boolean quiet) {
+        super.setInternalQuiet(quiet);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java
new file mode 100644
index 0000000..4144d44
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSConstants.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+/**
+ *  Holds all the constants for the VSS tasks.
+ *
+ */
+// CheckStyle:InterfaceIsType OFF (bc)
+public interface MSVSSConstants {
+    /**  Constant for the thing to execute  */
+    String SS_EXE = "ss";
+    /** Dollar Sigh to prefix the project path */
+    String PROJECT_PREFIX = "$";
+
+    /**  The 'CP' command  */
+    String COMMAND_CP = "CP";
+    /**  The 'Add' command  */
+    String COMMAND_ADD = "Add";
+    /**  The 'Get' command  */
+    String COMMAND_GET = "Get";
+    /**  The 'Checkout' command  */
+    String COMMAND_CHECKOUT = "Checkout";
+    /**  The 'Checkin' command  */
+    String COMMAND_CHECKIN = "Checkin";
+    /**  The 'Label' command  */
+    String COMMAND_LABEL = "Label";
+    /**  The 'History' command  */
+    String COMMAND_HISTORY = "History";
+    /**  The 'Create' command  */
+    String COMMAND_CREATE = "Create";
+
+    /**  The brief style flag  */
+    String STYLE_BRIEF = "brief";
+    /**  The codediff style flag  */
+    String STYLE_CODEDIFF = "codediff";
+    /**  The nofile style flag  */
+    String STYLE_NOFILE = "nofile";
+    /**  The default style flag  */
+    String STYLE_DEFAULT = "default";
+
+    /**  The text for  current (default) timestamp */
+    String TIME_CURRENT = "current";
+    /**  The text for  modified timestamp */
+    String TIME_MODIFIED = "modified";
+    /**  The text for  updated timestamp */
+    String TIME_UPDATED = "updated";
+
+    /**  The text for replacing writable files   */
+    String WRITABLE_REPLACE = "replace";
+    /**  The text for skiping writable files  */
+    String WRITABLE_SKIP = "skip";
+    /**  The text for failing on writable files  */
+    String WRITABLE_FAIL = "fail";
+
+    /** -Y flag */
+    String FLAG_LOGIN = "-Y";
+    /** -GL flag */
+    String FLAG_OVERRIDE_WORKING_DIR = "-GL";
+    /** -I- flag */
+    String FLAG_AUTORESPONSE_DEF = "-I-";
+    /** -I-Y flag */
+    String FLAG_AUTORESPONSE_YES = "-I-Y";
+    /** -I-N flag */
+    String FLAG_AUTORESPONSE_NO = "-I-N";
+    /** -R flag */
+    String FLAG_RECURSION = "-R";
+    /** -V flag */
+    String FLAG_VERSION = "-V";
+    /** -Vd flag */
+    String FLAG_VERSION_DATE = "-Vd";
+    /** -VL flag */
+    String FLAG_VERSION_LABEL = "-VL";
+    /** -W flag */
+    String FLAG_WRITABLE = "-W";
+    /** -N flag */
+    String VALUE_NO = "-N";
+    /** -Y flag */
+    String VALUE_YES = "-Y";
+    /** -O- flag */
+    String FLAG_QUIET = "-O-";
+    /** -C flag */
+    String FLAG_COMMENT = "-C";
+    /** -L flag */
+    String FLAG_LABEL = "-L";
+    /** ~d flag */
+    String VALUE_FROMDATE = "~d";
+    /** ~L flag */
+    String VALUE_FROMLABEL = "~L";
+    /** -O flag */
+    String FLAG_OUTPUT = "-O";
+    /** -U flag */
+    String FLAG_USER = "-U";
+    /** -F- flag */
+    String FLAG_NO_FILE = "-F-";
+    /** -B flag */
+    String FLAG_BRIEF = "-B";
+    /** -D flag */
+    String FLAG_CODEDIFF = "-D";
+    /** -GTC flag */
+    String FLAG_FILETIME_DEF = "-GTC";
+    /** -GTM flag */
+    String FLAG_FILETIME_MODIFIED = "-GTM";
+    /** -GTU flag */
+    String FLAG_FILETIME_UPDATED = "-GTU";
+    /** -GWR flag */
+    String FLAG_REPLACE_WRITABLE = "-GWR";
+    /** -GWS flag */
+    String FLAG_SKIP_WRITABLE = "-GWS";
+    /** -G- flag */
+    String FLAG_NO_GET = "-G-";
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java
new file mode 100644
index 0000000..fd5ed09
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSGET.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Perform Get commands from Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vssget" category="scm"
+ * @ant.attribute.group name="vdl" description="Only one of version, date or label"
+ */
+public class MSVSSGET extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // build the command line from what we got the format is
+        // ss Get VSS items [-G] [-H] [-I-] [-N] [-O] [-R] [-V] [-W] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_GET);
+
+        if (getVsspath() == null) {
+            throw new BuildException("vsspath attribute must be set!", getLocation());
+        }
+        commandLine.createArgument().setValue(getVsspath());
+
+        // -GL
+        commandLine.createArgument().setValue(getLocalpath());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -O-
+        commandLine.createArgument().setValue(getQuiet());
+        // -R
+        commandLine.createArgument().setValue(getRecursive());
+        // -V
+        commandLine.createArgument().setValue(getVersionDateLabel());
+        // -W
+        commandLine.createArgument().setValue(getWritable());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+        // -G
+        commandLine.createArgument().setValue(getFileTimeStamp());
+        // -GWS or -GWR
+        commandLine.createArgument().setValue(getWritableFiles());
+
+        return commandLine;
+    }
+
+    /**
+     * Override the project working directory.
+     *
+     * @param   localPath   The path on disk.
+     */
+    public void setLocalpath(Path localPath) {
+        super.setInternalLocalPath(localPath.toString());
+    }
+
+    /**
+     * Get files recursively. Defaults to false.
+     *
+     * @param recursive  The boolean value for recursive.
+     */
+    public final void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Enable quiet mode. Defaults to false.
+     *
+     * @param   quiet The boolean value for quiet.
+     */
+    public final void setQuiet (boolean quiet) {
+        super.setInternalQuiet(quiet);
+    }
+
+    /**
+     * Unset the READ-ONLY flag on files retrieved from VSS. Defaults to false.
+     *
+     * @param   writable The boolean value for writable.
+     */
+    public final void setWritable(boolean writable) {
+        super.setInternalWritable(writable);
+    }
+
+    /**
+     * Version to get.
+     *
+     * @param  version The version to get.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setVersion(String version) {
+        super.setInternalVersion(version);
+    }
+
+    /**
+     * Date to get.
+     *
+     * @param  date The date to get.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setDate(String date) {
+        super.setInternalDate(date);
+    }
+
+    /**
+     * Label to get.
+     *
+     * @param  label The label to get.
+     *
+     * @ant.attribute group="vdl"
+     */
+    public void setLabel(String label) {
+        super.setInternalLabel(label);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+
+    /**
+     * Date and time stamp given to the local copy. Defaults to <code>current</code>.
+     *
+     * @param timestamp     The file time stamping behaviour.
+     */
+    public void setFileTimeStamp(CurrentModUpdated timestamp) {
+        super.setInternalFileTimeStamp(timestamp);
+    }
+
+    /**
+     * Action taken when local files are writable. Defaults to <code>fail</code>.
+     * <p>
+     * Due to ss.exe returning with an exit code of '100' for both errors and when
+     * a file has been skipped, <code>failonerror</code> is set to false when using
+     * the <code>skip</code> option.
+     *
+     * @param files The action to take.
+     */
+    public void setWritableFiles(WritableFiles files) {
+        super.setInternalWritableFiles(files);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java
new file mode 100644
index 0000000..8f3b8ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSHISTORY.java
@@ -0,0 +1,199 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Performs History commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsshistory" category="scm"
+ */
+public class MSVSSHISTORY extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir and a label ...
+        if (getVsspath() == null) {
+            String msg = "vsspath attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss History elements [-H] [-L] [-N] [-O] [-V] [-Y] [-#] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_HISTORY);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -I-
+        commandLine.createArgument().setValue(FLAG_AUTORESPONSE_DEF);  // ignore all errors
+        // -Vd
+        commandLine.createArgument().setValue(getVersionDate());
+        // -VL
+        commandLine.createArgument().setValue(getVersionLabel());
+        // -R
+        commandLine.createArgument().setValue(getRecursive());
+        // -B / -D / -F-
+        commandLine.createArgument().setValue(getStyle());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+        // -O
+        commandLine.createArgument().setValue(getOutput());
+
+        return commandLine;
+    }
+
+    /**
+     * Retrieve history recursively. Defaults to false.
+     *
+     * @param recursive  The boolean value for recursive.
+     */
+    public void setRecursive(boolean recursive) {
+        super.setInternalRecursive(recursive);
+    }
+
+    /**
+     * Name of the user whose change history is generated.
+     *
+     * @param   user The username.
+     */
+    public void setUser(String user) {
+        super.setInternalUser(user);
+    }
+
+    /**
+     * Date representing the 'start' of the range.
+     *
+     * @param   fromDate    The start date.
+     */
+    public void setFromDate(String fromDate) {
+        super.setInternalFromDate(fromDate);
+    }
+
+    /**
+     * Date representing the 'end' of the range.
+     *
+     * @param   toDate    The end date.
+     */
+    public void setToDate(String toDate) {
+        super.setInternalToDate(toDate);
+    }
+
+    /**
+     * Label representing the 'start' of the range.
+     *
+     * @param   fromLabel    The start label.
+     */
+    public void setFromLabel(String fromLabel) {
+        super.setInternalFromLabel(fromLabel);
+    }
+
+    /**
+     * Label representing the 'end' of the range.
+     *
+     * @param   toLabel    The end label.
+     */
+    public void setToLabel(String toLabel) {
+        super.setInternalToLabel(toLabel);
+    }
+
+    /**
+     * Number of days for comparison.
+     * Defaults to 2 days.
+     *
+     * @param   numd    The number of days.
+     */
+    public void setNumdays(int numd) {
+        super.setInternalNumDays(numd);
+    }
+
+    /**
+     * Output file name for the history.
+     *
+     * @param   outfile The output file name.
+     */
+    public void setOutput(File outfile) {
+        if (outfile != null) {
+            super.setInternalOutputFilename(outfile.getAbsolutePath());
+        }
+    }
+
+    /**
+     * Format of dates in <code>fromDate</code and <code>toDate</code>.
+     * Used when calculating dates with the numdays attribute.
+     * This string uses the formatting rules of <code>SimpleDateFormat</code>.
+     * Defaults to <code>DateFormat.SHORT</code>.
+     *
+     * @param   dateFormat  The date format.
+     */
+    public void setDateFormat(String dateFormat) {
+        super.setInternalDateFormat(new SimpleDateFormat(dateFormat));
+    }
+
+   /**
+     * Output style. Valid options are:
+     * <ul>
+     * <li>brief:    -B Display a brief history.
+     * <li>codediff: -D Display line-by-line file changes.
+     * <li>nofile:   -F- Do not display individual file updates in the project history.
+     * <li>default:  No option specified. Display in Source Safe's default format.
+     * </ul>
+     *
+     * @param attr The history style:
+     */
+    public void setStyle(BriefCodediffNofile attr) {
+        String option = attr.getValue();
+        if (option.equals(STYLE_BRIEF)) {
+            super.setInternalStyle(FLAG_BRIEF);
+        } else if (option.equals(STYLE_CODEDIFF)) {
+            super.setInternalStyle(FLAG_CODEDIFF);
+        } else if (option.equals(STYLE_DEFAULT)) {
+            super.setInternalStyle("");
+        } else if (option.equals(STYLE_NOFILE)) {
+            super.setInternalStyle(FLAG_NO_FILE);
+        } else {
+            throw new BuildException("Style " + attr + " unknown.", getLocation());
+        }
+    }
+
+    /**
+     * Extention of EnumeratedAttribute to hold the values for style.
+     */
+    public static class BriefCodediffNofile extends EnumeratedAttribute {
+        /**
+         * Gets the list of allowable values.
+         * @return The values.
+         */
+        public String[] getValues() {
+            return new String[] {STYLE_BRIEF, STYLE_CODEDIFF, STYLE_NOFILE, STYLE_DEFAULT};
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java
new file mode 100644
index 0000000..4ba9d7b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/vss/MSVSSLABEL.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Performs Label commands to Microsoft Visual SourceSafe.
+ *
+ * @ant.task name="vsslabel" category="scm"
+ */
+public class MSVSSLABEL extends MSVSS {
+
+    /**
+     * Builds a command line to execute ss.
+     * @return     The constructed commandline.
+     */
+    Commandline buildCmdLine() {
+        Commandline commandLine = new Commandline();
+
+        // first off, make sure that we've got a command and a vssdir and a label ...
+        if (getVsspath() == null) {
+            throw new BuildException("vsspath attribute must be set!", getLocation());
+        }
+
+        String label = getLabel();
+        if (label.equals("")) {
+            String msg = "label attribute must be set!";
+            throw new BuildException(msg, getLocation());
+        }
+
+        // build the command line from what we got the format is
+        // ss Label VSS items [-C] [-H] [-I-] [-Llabel] [-N] [-O] [-V] [-Y] [-?]
+        // as specified in the SS.EXE help
+        commandLine.setExecutable(getSSCommand());
+        commandLine.createArgument().setValue(COMMAND_LABEL);
+
+        // VSS items
+        commandLine.createArgument().setValue(getVsspath());
+        // -C
+        commandLine.createArgument().setValue(getComment());
+        // -I- or -I-Y or -I-N
+        commandLine.createArgument().setValue(getAutoresponse());
+        // -L Specify the new label on the command line (instead of being prompted)
+        commandLine.createArgument().setValue(label);
+        // -V Label an existing file or project version
+        commandLine.createArgument().setValue(getVersion());
+        // -Y
+        commandLine.createArgument().setValue(getLogin());
+
+        return commandLine;
+    }
+
+    /**
+     * Label to apply in SourceSafe.
+     *
+     * @param  label The label to apply.
+     *
+     * @ant.attribute group="required"
+     */
+    public void setLabel(String label) {
+        super.setInternalLabel(label);
+    }
+
+    /**
+     * Version to label.
+     *
+     * @param  version The version to label.
+     */
+    public void setVersion(String version) {
+        super.setInternalVersion(version);
+    }
+
+    /**
+     * Comment to apply to files labeled in SourceSafe.
+     *
+     * @param comment The comment to apply in SourceSafe
+     */
+    public void setComment(String comment) {
+        super.setInternalComment(comment);
+    }
+
+    /**
+     * Autoresponce behaviour. Valid options are Y and N.
+     *
+     * @param response The auto response value.
+     */
+    public void setAutoresponse(String response) {
+        super.setInternalAutoResponse(response);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java
new file mode 100644
index 0000000..5dc338f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/optional/windows/Attrib.java
@@ -0,0 +1,195 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.windows;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.ExecuteOn;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+
+import java.io.File;
+
+/**
+ * Attrib equivalent for Win32 environments.
+ * Note: Attrib parameters /S and /D are not handled.
+ *
+ * @since Ant 1.6
+ */
+public class Attrib extends ExecuteOn {
+
+    private static final String ATTR_READONLY = "R";
+    private static final String ATTR_ARCHIVE  = "A";
+    private static final String ATTR_SYSTEM   = "S";
+    private static final String ATTR_HIDDEN   = "H";
+    private static final String SET    = "+";
+    private static final String UNSET  = "-";
+
+    private boolean haveAttr = false;
+
+    /** Constructor for Attrib. */
+    public Attrib() {
+        super.setExecutable("attrib");
+        super.setParallel(false);
+    }
+
+    /**
+     * A file to be attribed.
+     * @param src a file
+     */
+    public void setFile(File src) {
+        FileSet fs = new FileSet();
+        fs.setFile(src);
+        addFileset(fs);
+    }
+
+    /**
+     * Set the ReadOnly file attribute.
+     * @param value a <code>boolean</code> value
+     */
+    public void setReadonly(boolean value) {
+        addArg(value, ATTR_READONLY);
+    }
+
+    /**
+     * Set the Archive file attribute.
+     * @param value a <code>boolean</code> value
+     */
+    public void setArchive(boolean value) {
+        addArg(value, ATTR_ARCHIVE);
+    }
+
+    /**
+     * Set the System file attribute.
+     * @param value a <code>boolean</code> value
+     */
+    public void setSystem(boolean value) {
+        addArg(value, ATTR_SYSTEM);
+    }
+
+    /**
+     * Set the Hidden file attribute.
+     * @param value a <code>boolean</code> value
+     */
+    public void setHidden(boolean value) {
+        addArg(value, ATTR_HIDDEN);
+    }
+
+    /**
+     * Check the attributes.
+     */
+    protected void checkConfiguration() {
+        if (!haveAttr()) {
+            throw new BuildException("Missing attribute parameter",
+                                     getLocation());
+        }
+        super.checkConfiguration();
+    }
+
+    /**
+     * Set the executable.
+     * This is not allowed, and it always throws a BuildException.
+     * @param e ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setExecutable(String e) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the executable attribute", getLocation());
+    }
+
+    /**
+     * Set the executable.
+     * This is not allowed, and it always throws a BuildException.
+     * @param e ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setCommand(String e) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the command attribute", getLocation());
+    }
+
+    /**
+     * Add source file.
+     * This is not allowed, and it always throws a BuildException.
+     * @param b ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setAddsourcefile(boolean b) {
+        throw new BuildException(getTaskType()
+            + " doesn\'t support the addsourcefile attribute", getLocation());
+    }
+
+    /**
+     * Set skip empty file sets.
+     * This is not allowed, and it always throws a BuildException.
+     * @param skip ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setSkipEmptyFilesets(boolean skip) {
+        throw new BuildException(getTaskType() + " doesn\'t support the "
+                                 + "skipemptyfileset attribute",
+                                 getLocation());
+    }
+
+    /**
+     * Set parallel.
+     * This is not allowed, and it always throws a BuildException.
+     * @param parallel ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setParallel(boolean parallel) {
+        throw new BuildException(getTaskType()
+                                 + " doesn\'t support the parallel attribute",
+                                 getLocation());
+    }
+
+    /**
+     * Set max parallel.
+     * This is not allowed, and it always throws a BuildException.
+     * @param max ignored
+     * @ant.attribute ignore="true"
+     */
+    public void setMaxParallel(int max) {
+        throw new BuildException(getTaskType()
+                                 + " doesn\'t support the maxparallel attribute",
+                                 getLocation());
+    }
+
+    /**
+     * Check if the os is valid.
+     * Always include windows
+     * @return true if the os is valid.
+     */
+    protected boolean isValidOs() {
+        return Os.isFamily("windows") && super.isValidOs();
+    }
+
+    private static String getSignString(boolean attr) {
+        return (attr ? SET : UNSET);
+    }
+
+    private void addArg(boolean sign, String attribute) {
+        createArg().setValue(getSignString(sign) + attribute);
+        haveAttr = true;
+    }
+
+    private boolean haveAttr() {
+        return haveAttr;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/DefaultRmicAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/DefaultRmicAdapter.java
new file mode 100644
index 0000000..e62015b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/DefaultRmicAdapter.java
@@ -0,0 +1,493 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import java.io.File;
+import java.util.Random;
+import java.util.Vector;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Rmic;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * This is the default implementation for the RmicAdapter interface.
+ * Currently, this is a cut-and-paste of the original rmic task and
+ * DefaultCopmpilerAdapter.
+ *
+ * @since Ant 1.4
+ */
+public abstract class DefaultRmicAdapter implements RmicAdapter {
+
+    private Rmic attributes;
+    private FileNameMapper mapper;
+    private static final Random RAND = new Random();
+    /** suffix denoting a stub file: {@value} */
+    public static final String RMI_STUB_SUFFIX = "_Stub";
+    /** suffix denoting a skel file: {@value} */
+    public static final String RMI_SKEL_SUFFIX = "_Skel";
+    /** suffix denoting a tie file: {@value} */
+    public static final String RMI_TIE_SUFFIX = "_Tie";
+    /** arg for compat: {@value} */
+    public static final String STUB_COMPAT = "-vcompat";
+    /** arg for 1.1: {@value} */
+    public static final String STUB_1_1 = "-v1.1";
+    /** arg for 1.2: {@value} */
+    public static final String STUB_1_2 = "-v1.2";
+
+    /**
+     * option for stub 1.1 in the rmic task: {@value}
+     */
+    public static final String STUB_OPTION_1_1 = "1.1";
+    /**
+     * option for stub 1.2 in the rmic task: {@value}
+     */
+    public static final String STUB_OPTION_1_2 = "1.2";
+    /**
+     * option for stub compat in the rmic task: {@value}
+     */
+    public static final String STUB_OPTION_COMPAT = "compat";
+
+    /**
+     * Default constructor
+     */
+    public DefaultRmicAdapter() {
+    }
+
+    /**
+     * Sets Rmic attributes
+     * @param attributes the rmic attributes
+     */
+    public void setRmic(final Rmic attributes) {
+        this.attributes = attributes;
+        mapper = new RmicFileNameMapper();
+    }
+
+    /**
+     * Get the Rmic attributes
+     * @return the attributes as a Rmic taskdef
+     */
+    public Rmic getRmic() {
+        return attributes;
+    }
+
+    /**
+     * Gets the stub class suffix
+     * @return the stub suffix &quot;_Stub&quot;
+     */
+    protected String getStubClassSuffix() {
+        return RMI_STUB_SUFFIX;
+    }
+
+    /**
+     * Gets the skeleton class suffix
+     * @return the skeleton suffix &quot;_Skel&quot;
+     */
+    protected String getSkelClassSuffix() {
+        return RMI_SKEL_SUFFIX;
+    }
+
+    /**
+     * Gets the tie class suffix
+     * @return the tie suffix &quot;_Tie&quot;
+     */
+    protected String getTieClassSuffix() {
+        return RMI_TIE_SUFFIX;
+    }
+
+    /**
+     * This implementation returns a mapper that may return up to two
+     * file names.
+     *
+     * <ul>
+     *   <li>for JRMP it will return *_getStubClassSuffix (and
+     *   *_getSkelClassSuffix if JDK 1.1 is used)</li>
+     *
+     *   <li>for IDL it will return a random name, causing &lt;rmic&gt; to
+     *     always recompile.</li>
+     *
+     *   <li>for IIOP it will return _*_getStubClassSuffix for
+     *   interfaces and _*_getStubClassSuffix for non-interfaces (and
+     *   determine the interface and create _*_Stub from that).</li>
+     * </ul>
+     * @return a <code>FileNameMapper</code>
+     */
+    public FileNameMapper getMapper() {
+        return mapper;
+    }
+
+    /**
+     * Gets the CLASSPATH this rmic process will use.
+     * @return the classpath
+     */
+    public Path getClasspath() {
+        return getCompileClasspath();
+    }
+
+    /**
+     * Builds the compilation classpath.
+     * @return the classpath
+     */
+    protected Path getCompileClasspath() {
+        Path classpath = new Path(attributes.getProject());
+        // add dest dir to classpath so that previously compiled and
+        // untouched classes are on classpath
+        classpath.setLocation(attributes.getBase());
+
+        // Combine the build classpath with the system classpath, in an
+        // order determined by the value of build.sysclasspath
+
+        Path cp = attributes.getClasspath();
+        if (cp == null) {
+            cp = new Path(attributes.getProject());
+        }
+        if (attributes.getIncludeantruntime()) {
+            classpath.addExisting(cp.concatSystemClasspath("last"));
+        } else {
+            classpath.addExisting(cp.concatSystemClasspath("ignore"));
+        }
+
+        if (attributes.getIncludejavaruntime()) {
+            classpath.addJavaRuntime();
+        }
+        return classpath;
+    }
+
+    /**
+     * Setup rmic argument for rmic.
+     * @return the command line
+     */
+    protected Commandline setupRmicCommand() {
+        return setupRmicCommand(null);
+    }
+
+    /**
+     * Setup rmic argument for rmic.
+     * @param options additional parameters needed by a specific
+     *                implementation.
+     * @return the command line
+     */
+    protected Commandline setupRmicCommand(String[] options) {
+        Commandline cmd = new Commandline();
+
+        if (options != null) {
+            for (int i = 0; i < options.length; i++) {
+                cmd.createArgument().setValue(options[i]);
+            }
+        }
+
+        Path classpath = getCompileClasspath();
+
+        cmd.createArgument().setValue("-d");
+        cmd.createArgument().setFile(attributes.getBase());
+
+        if (attributes.getExtdirs() != null) {
+            cmd.createArgument().setValue("-extdirs");
+            cmd.createArgument().setPath(attributes.getExtdirs());
+        }
+
+        cmd.createArgument().setValue("-classpath");
+        cmd.createArgument().setPath(classpath);
+        String stubOption = addStubVersionOptions();
+        if (stubOption != null) {
+            //set the non-null stubOption
+            cmd.createArgument().setValue(stubOption);
+        }
+
+
+        if (null != attributes.getSourceBase()) {
+            cmd.createArgument().setValue("-keepgenerated");
+        }
+
+        if (attributes.getIiop()) {
+            attributes.log("IIOP has been turned on.", Project.MSG_INFO);
+            cmd.createArgument().setValue("-iiop");
+            if (attributes.getIiopopts() != null) {
+                attributes.log("IIOP Options: " + attributes.getIiopopts(),
+                               Project.MSG_INFO);
+                cmd.createArgument().setValue(attributes.getIiopopts());
+            }
+        }
+
+        if (attributes.getIdl())  {
+            cmd.createArgument().setValue("-idl");
+            attributes.log("IDL has been turned on.", Project.MSG_INFO);
+            if (attributes.getIdlopts() != null) {
+                cmd.createArgument().setValue(attributes.getIdlopts());
+                attributes.log("IDL Options: " + attributes.getIdlopts(),
+                               Project.MSG_INFO);
+            }
+        }
+
+        if (attributes.getDebug()) {
+            cmd.createArgument().setValue("-g");
+        }
+
+        String[] compilerArgs = attributes.getCurrentCompilerArgs();
+        compilerArgs = preprocessCompilerArgs(compilerArgs);
+        cmd.addArguments(compilerArgs);
+
+        logAndAddFilesToCompile(cmd);
+        return cmd;
+     }
+
+    /**
+     * This is an override point; get the stub version off the rmic command and
+     * translate that into a compiler-specific argument
+     * @return a string to use for the stub version; can be null
+     * @since Ant1.7.1
+     */
+    protected String addStubVersionOptions() {
+        //handle the many different stub options.
+        String stubVersion = attributes.getStubVersion();
+        //default is compatibility
+        String stubOption = null;
+        if (null != stubVersion) {
+            if (STUB_OPTION_1_1.equals(stubVersion)) {
+                stubOption = STUB_1_1;
+            } else if (STUB_OPTION_1_2.equals(stubVersion)) {
+                stubOption = STUB_1_2;
+            } else if (STUB_OPTION_COMPAT.equals(stubVersion)) {
+                stubOption = STUB_COMPAT;
+            } else {
+                //anything else
+                attributes.log("Unknown stub option " + stubVersion);
+                //do nothing with the value? or go -v+stubVersion??
+            }
+        }
+        //for java1.5+, we generate compatible stubs, that is, unless
+        //the caller asked for IDL or IIOP support.
+        if (stubOption == null
+            && !attributes.getIiop()
+            && !attributes.getIdl()) {
+            stubOption = STUB_COMPAT;
+        }
+        return stubOption;
+    }
+
+    /**
+     * Preprocess the compiler arguments in any way you see fit.
+     * This is to allow compiler adapters to validate or filter the arguments.
+     * The base implementation returns the original compiler arguments unchanged.
+     * @param compilerArgs the original compiler arguments
+     * @return the filtered set.
+     */
+    protected String[] preprocessCompilerArgs(String[] compilerArgs) {
+        return compilerArgs;
+    }
+
+
+    /**
+     * Strip out all -J args from the command list. Invoke this from
+     * {@link #preprocessCompilerArgs(String[])} if you have a non-forking
+     * compiler.
+     * @param compilerArgs the original compiler arguments
+     * @return the filtered set.
+     */
+    protected String[] filterJvmCompilerArgs(String[] compilerArgs) {
+        int len = compilerArgs.length;
+        List args = new ArrayList(len);
+        for (int i = 0; i < len; i++) {
+            String arg = compilerArgs[i];
+            if (!arg.startsWith("-J")) {
+                args.add(arg);
+            } else {
+                attributes.log("Dropping " + arg + " from compiler arguments");
+            }
+        }
+        int count = args.size();
+        return (String[]) args.toArray(new String[count]);
+    }
+
+
+    /**
+     * Logs the compilation parameters, adds the files to compile and logs the
+     * &quot;niceSourceList&quot;
+     * @param cmd the commandline args
+     */
+    protected void logAndAddFilesToCompile(Commandline cmd) {
+        Vector compileList = attributes.getCompileList();
+
+        attributes.log("Compilation " + cmd.describeArguments(),
+                       Project.MSG_VERBOSE);
+
+        StringBuffer niceSourceList = new StringBuffer("File");
+        int cListSize = compileList.size();
+        if (cListSize != 1) {
+            niceSourceList.append("s");
+        }
+        niceSourceList.append(" to be compiled:");
+
+        for (int i = 0; i < cListSize; i++) {
+            String arg = (String) compileList.elementAt(i);
+            cmd.createArgument().setValue(arg);
+            niceSourceList.append("    ");
+            niceSourceList.append(arg);
+        }
+
+        attributes.log(niceSourceList.toString(), Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Mapper that may return up to two file names.
+     *
+     * <ul>
+     *   <li>for JRMP it will return *_getStubClassSuffix (and
+     *   *_getSkelClassSuffix if JDK 1.1 is used)</li>
+     *
+     *   <li>for IDL it will return a random name, causing <rmic> to
+     *     always recompile.</li>
+     *
+     *   <li>for IIOP it will return _*_getStubClassSuffix for
+     *   interfaces and _*_getStubClassSuffix for non-interfaces (and
+     *   determine the interface and create _*_Stub from that).</li>
+     * </ul>
+     */
+    private class RmicFileNameMapper implements FileNameMapper {
+
+        RmicFileNameMapper() {
+        }
+
+        /**
+         * Empty implementation.
+         */
+        public void setFrom(String s) {
+        }
+        /**
+         * Empty implementation.
+         */
+        public void setTo(String s) {
+        }
+
+        public String[] mapFileName(String name) {
+            if (name == null
+                || !name.endsWith(".class")
+                || name.endsWith(getStubClassSuffix() + ".class")
+                || name.endsWith(getSkelClassSuffix() + ".class")
+                || name.endsWith(getTieClassSuffix() + ".class")) {
+                // Not a .class file or the one we'd generate
+                return null;
+            }
+
+            // we know that name.endsWith(".class")
+            String base = StringUtils.removeSuffix(name, ".class");
+
+            String classname = base.replace(File.separatorChar, '.');
+            if (attributes.getVerify()
+                && !attributes.isValidRmiRemote(classname)) {
+                return null;
+            }
+
+            /*
+             * fallback in case we have trouble loading the class or
+             * don't know how to handle it (there is no easy way to
+             * know what IDL mode would generate.
+             *
+             * This is supposed to make Ant always recompile the
+             * class, as a file of that name should not exist.
+             */
+            String[] target = new String[] {name + ".tmp." + RAND.nextLong()};
+
+            if (!attributes.getIiop() && !attributes.getIdl()) {
+                // JRMP with simple naming convention
+                if (STUB_OPTION_1_2.equals(attributes.getStubVersion())) {
+                    target = new String[] {
+                        base + getStubClassSuffix() + ".class"
+                    };
+                } else {
+                    target = new String[] {
+                        base + getStubClassSuffix() + ".class",
+                        base + getSkelClassSuffix() + ".class",
+                    };
+                }
+            } else if (!attributes.getIdl()) {
+                int lastSlash = base.lastIndexOf(File.separatorChar);
+
+                String dirname = "";
+                /*
+                 * I know, this is not necessary, but I prefer it explicit (SB)
+                 */
+                int index = -1;
+                if (lastSlash == -1) {
+                    // no package
+                    index = 0;
+                } else {
+                    index = lastSlash + 1;
+                    dirname = base.substring(0, index);
+                }
+
+                String filename = base.substring(index);
+
+                try {
+                    Class c = attributes.getLoader().loadClass(classname);
+
+                    if (c.isInterface()) {
+                        // only stub, no tie
+                        target = new String[] {
+                            dirname + "_" + filename + getStubClassSuffix()
+                            + ".class"
+                        };
+                    } else {
+                        /*
+                         * stub is derived from implementation,
+                         * tie from interface name.
+                         */
+                        Class interf = attributes.getRemoteInterface(c);
+                        String iName = interf.getName();
+                        String iDir = "";
+                        int iIndex = -1;
+                        int lastDot = iName.lastIndexOf(".");
+                        if (lastDot == -1) {
+                            // no package
+                            iIndex = 0;
+                        } else {
+                            iIndex = lastDot + 1;
+                            iDir = iName.substring(0, iIndex);
+                            iDir = iDir.replace('.', File.separatorChar);
+                        }
+
+                        target = new String[] {
+                            dirname + "_" + filename + getTieClassSuffix()
+                            + ".class",
+                            iDir + "_" + iName.substring(iIndex)
+                            + getStubClassSuffix() + ".class"
+                        };
+                    }
+                } catch (ClassNotFoundException e) {
+                    attributes.log("Unable to verify class " + classname
+                                   + ". It could not be found.",
+                                   Project.MSG_WARN);
+                } catch (NoClassDefFoundError e) {
+                    attributes.log("Unable to verify class " + classname
+                                   + ". It is not defined.", Project.MSG_WARN);
+                } catch (Throwable t) {
+                    attributes.log("Unable to verify class " + classname
+                                   + ". Loading caused Exception: "
+                                   + t.getMessage(), Project.MSG_WARN);
+                }
+            }
+            return target;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/ForkingSunRmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/ForkingSunRmic.java
new file mode 100644
index 0000000..7e187d1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/ForkingSunRmic.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.taskdefs.Rmic;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.LogStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+
+import java.io.IOException;
+
+/**
+ * This is an extension of the sun rmic compiler, which forks rather than
+ * executes it inline. Why so? Because rmic is dog slow, but if you fork the
+ * compiler you can have multiple copies compiling different bits of your project
+ * at the same time. Which, on a multi-cpu system results in significant speedups.
+ *
+ * Also, Java1.6 behaves oddly with -XNew, so we switch it on here if needed.
+ * @since ant1.7
+ */
+public class ForkingSunRmic extends DefaultRmicAdapter {
+
+    /**
+     * the name of this adapter for users to select
+     */
+    public static final String COMPILER_NAME = "forking";
+
+    /**
+     * exec by creating a new command
+     * @return true if the command ran successfully
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        Rmic owner = getRmic();
+        Commandline cmd = setupRmicCommand();
+        Project project = owner.getProject();
+        //rely on RMIC being on the path
+        cmd.setExecutable(JavaEnvUtils.getJdkExecutable(getExecutableName()));
+
+        //set up the args
+        String[] args = cmd.getCommandline();
+
+        try {
+            Execute exe = new Execute(new LogStreamHandler(owner,
+                    Project.MSG_INFO,
+                    Project.MSG_WARN));
+            exe.setAntRun(project);
+            exe.setWorkingDirectory(project.getBaseDir());
+            exe.setCommandline(args);
+            exe.execute();
+            return !exe.isFailure();
+        } catch (IOException exception) {
+            throw new BuildException("Error running " + getExecutableName()
+                    + " -maybe it is not on the path", exception);
+        }
+    }
+
+    /**
+     * Override point.
+     * @return the executable name.
+     */
+    protected String getExecutableName() {
+        return SunRmic.RMIC_EXECUTABLE;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/KaffeRmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/KaffeRmic.java
new file mode 100644
index 0000000..2108a68
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/KaffeRmic.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.ExecuteJava;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the rmic for Kaffe
+ *
+ * @since Ant 1.4
+ */
+public class KaffeRmic extends DefaultRmicAdapter {
+    // sorted by newest Kaffe version first
+    private static final String[] RMIC_CLASSNAMES = new String[] {
+        "gnu.classpath.tools.rmi.rmic.RMIC",
+        // pre Kaffe 1.1.5
+        "gnu.java.rmi.rmic.RMIC",
+        // pre Kaffe 1.1.2
+        "kaffe.rmi.rmic.RMIC",
+    };
+
+    /**
+     * the name of this adapter for users to select
+     */
+    public static final String COMPILER_NAME = "kaffe";
+
+    /** {@inheritDoc} */
+    public boolean execute() throws BuildException {
+        getRmic().log("Using Kaffe rmic", Project.MSG_VERBOSE);
+        Commandline cmd = setupRmicCommand();
+
+        Class c = getRmicClass();
+        if (c == null) {
+            StringBuffer buf = new StringBuffer("Cannot use Kaffe rmic, as it"
+                                                + " is not available.  None"
+                                                + " of ");
+            for (int i = 0; i < RMIC_CLASSNAMES.length; i++) {
+                if (i != 0) {
+                    buf.append(", ");
+                }
+
+                buf.append(RMIC_CLASSNAMES[i]);
+            }
+            buf.append(" have been found. A common solution is to set the"
+                       + " environment variable JAVA_HOME or CLASSPATH.");
+            throw new BuildException(buf.toString(),
+                                     getRmic().getLocation());
+        }
+
+        cmd.setExecutable(c.getName());
+        if (!c.getName().equals(RMIC_CLASSNAMES[RMIC_CLASSNAMES.length - 1])) {
+            // only supported since Kaffe 1.1.2
+            cmd.createArgument().setValue("-verbose");
+            getRmic().log(Commandline.describeCommand(cmd));
+        }
+        ExecuteJava ej = new ExecuteJava();
+        ej.setJavaCommand(cmd);
+        return ej.fork(getRmic()) == 0;
+    }
+
+    /**
+     * test for kaffe being on the system
+     * @return true if kaffe is on the current classpath
+     */
+    public static boolean isAvailable() {
+        return getRmicClass() != null;
+    }
+
+    /**
+     * tries to load Kaffe RMIC and falls back to the older class name
+     * if necessary.
+     *
+     * @return null if neither class can get loaded.
+     */
+    private static Class getRmicClass() {
+        for (int i = 0; i < RMIC_CLASSNAMES.length; i++) {
+            try {
+                return Class.forName(RMIC_CLASSNAMES[i]);
+            } catch (ClassNotFoundException cnfe) {
+                // Ignore
+            }
+        }
+        return null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapter.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapter.java
new file mode 100644
index 0000000..8493d4e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapter.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Rmic;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileNameMapper;
+
+/**
+ * The interface that all rmic adapters must adhere to.
+ *
+ * <p>A rmic adapter is an adapter that interprets the rmic's
+ * parameters in preperation to be passed off to the compiler this
+ * adapter represents.  As all the necessary values are stored in the
+ * Rmic task itself, the only thing all adapters need is the rmic
+ * task, the execute command and a parameterless constructor (for
+ * reflection).</p>
+ *
+ * @since Ant 1.4
+ */
+
+public interface RmicAdapter {
+
+    /**
+     * Sets the rmic attributes, which are stored in the Rmic task.
+     * @param attributes the rmic attributes to use
+     */
+    void setRmic(Rmic attributes);
+
+    /**
+     * Call the rmic compiler.
+     *
+     * @return true if has the compilation been successful
+     * @throws BuildException on error
+     */
+    boolean execute() throws BuildException;
+
+    /**
+     * Maps source class files to the files generated by this rmic
+     * implementation.
+     * @return the filename mapper used by this implementation
+     */
+    FileNameMapper getMapper();
+
+    /**
+     * The CLASSPATH this rmic process will use.
+     * @return the classpaht this rmic process will use
+     */
+    Path getClasspath();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapterFactory.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapterFactory.java
new file mode 100644
index 0000000..ee61309
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/RmicAdapterFactory.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+import java.util.Locale;
+
+
+/**
+ * Creates the necessary rmic adapter, given basic criteria.
+ *
+ * @since 1.4
+ */
+public final class RmicAdapterFactory {
+    /** The error message to be used when the compiler cannot be found. */
+    public static final String ERROR_UNKNOWN_COMPILER = "Class not found: ";
+
+    /** The error message to be used when the class is not an rmic adapter. */
+    public static final String ERROR_NOT_RMIC_ADAPTER = "Class of unexpected Type: ";
+
+    /** If the compiler has this name use a default compiler. */
+    public static final String DEFAULT_COMPILER = "default";
+
+    /** This is a singleton -- can't create instances!! */
+    private RmicAdapterFactory() {
+    }
+
+    /**
+     * Based on the parameter passed in, this method creates the necessary
+     * factory desired.
+     *
+     * <p>The current mapping for rmic names are as follows:</p>
+     * <ul><li>sun = SUN's rmic
+     * <li>kaffe = Kaffe's rmic
+     * <li><i>a fully quallified classname</i> = the name of a rmic
+     * adapter
+     * <li>weblogic = weblogic compiler
+     * <li>forking = Sun's RMIC by forking a new JVM
+     * </ul>
+     *
+     * @param rmicType either the name of the desired rmic, or the
+     * full classname of the rmic's adapter.
+     * @param task a task to log through.
+     * @return the compiler adapter
+     * @throws BuildException if the rmic type could not be resolved into
+     * a rmic adapter.
+     */
+    public static RmicAdapter getRmic(String rmicType, Task task)
+        throws BuildException {
+        //convert to lower case in the English locale,
+        String compiler = rmicType.toLowerCase(Locale.ENGLISH);
+
+        //handle default specially by choosing the sun or kaffe compiler
+        if (DEFAULT_COMPILER.equals(compiler) || compiler.length() == 0) {
+            compiler = KaffeRmic.isAvailable()
+                ? KaffeRmic.COMPILER_NAME
+                : SunRmic.COMPILER_NAME;
+        }
+        if (SunRmic.COMPILER_NAME.equals(compiler)) {
+            return new SunRmic();
+        } else if (KaffeRmic.COMPILER_NAME.equals(compiler)) {
+            return new KaffeRmic();
+        } else if (WLRmic.COMPILER_NAME.equals(compiler)) {
+            return new WLRmic();
+        } else if (ForkingSunRmic.COMPILER_NAME.equals(compiler)) {
+            return new ForkingSunRmic();
+        } else if (XNewRmic.COMPILER_NAME.equals(compiler)) {
+            return new XNewRmic();
+        }
+        //no match? ask for the non-lower-cased type
+        return resolveClassName(rmicType);
+    }
+
+    /**
+     * Tries to resolve the given classname into a rmic adapter.
+     * Throws a fit if it can't.
+     *
+     * @param className The fully qualified classname to be created.
+     * @throws BuildException This is the fit that is thrown if className
+     * isn't an instance of RmicAdapter.
+     */
+    private static RmicAdapter resolveClassName(String className)
+            throws BuildException {
+        return (RmicAdapter) ClasspathUtils.newInstance(className,
+                RmicAdapterFactory.class.getClassLoader(), RmicAdapter.class);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/SunRmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/SunRmic.java
new file mode 100644
index 0000000..5739438
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/SunRmic.java
@@ -0,0 +1,113 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.LogOutputStream;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the rmic for SUN's JDK.
+ *
+ * @since Ant 1.4
+ */
+public class SunRmic extends DefaultRmicAdapter {
+
+    /**
+     * name of the class
+     */
+    public static final String RMIC_CLASSNAME = "sun.rmi.rmic.Main";
+
+    /**
+     * the name of this adapter for users to select
+     */
+    public static final String COMPILER_NAME = "sun";
+
+    /**
+     * name of the executable
+     */
+    public static final String RMIC_EXECUTABLE = "rmic";
+    /** Error message to use with the sun rmic is not the classpath. */
+    public static final String ERROR_NO_RMIC_ON_CLASSPATH = "Cannot use SUN rmic, as it is not "
+                                         + "available.  A common solution is to "
+                                         + "set the environment variable "
+                                         + "JAVA_HOME";
+    /** Error message to use when there is an error starting the sun rmic compiler */
+    public static final String ERROR_RMIC_FAILED = "Error starting SUN rmic: ";
+
+    /**
+     * Run the rmic compiler.
+     * @return true if the compilation succeeded
+     * @throws BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        getRmic().log("Using SUN rmic compiler", Project.MSG_VERBOSE);
+        Commandline cmd = setupRmicCommand();
+
+        // Create an instance of the rmic, redirecting output to
+        // the project log
+        LogOutputStream logstr = new LogOutputStream(getRmic(),
+                                                     Project.MSG_WARN);
+
+        try {
+            Class c = Class.forName(RMIC_CLASSNAME);
+            Constructor cons
+                = c.getConstructor(new Class[]  {OutputStream.class, String.class});
+            Object rmic = cons.newInstance(new Object[] {logstr, "rmic"});
+
+            Method doRmic = c.getMethod("compile",
+                                        new Class [] {String[].class});
+            Boolean ok =
+                (Boolean) doRmic.invoke(rmic,
+                                       (new Object[] {cmd.getArguments()}));
+            return ok.booleanValue();
+        } catch (ClassNotFoundException ex) {
+            throw new BuildException(ERROR_NO_RMIC_ON_CLASSPATH,
+                                     getRmic().getLocation());
+        } catch (Exception ex) {
+            if (ex instanceof BuildException) {
+                throw (BuildException) ex;
+            } else {
+                throw new BuildException(ERROR_RMIC_FAILED,
+                                         ex, getRmic().getLocation());
+            }
+        } finally {
+            try {
+                logstr.close();
+            } catch (IOException e) {
+                throw new BuildException(e);
+            }
+        }
+    }
+
+
+    /**
+     * Strip out all -J args from the command list.
+     * @param compilerArgs the original compiler arguments
+     * @return the filtered set.
+     */
+    protected String[] preprocessCompilerArgs(String[] compilerArgs) {
+        return filterJvmCompilerArgs(compilerArgs);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/WLRmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/WLRmic.java
new file mode 100644
index 0000000..613de52
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/WLRmic.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.rmic;
+
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * The implementation of the rmic for WebLogic
+ *
+ * @since Ant 1.4
+ */
+public class WLRmic extends DefaultRmicAdapter {
+    /** The classname of the weblogic rmic */
+    public static final String WLRMIC_CLASSNAME = "weblogic.rmic";
+    /**
+     * the name of this adapter for users to select
+     */
+    public static final String COMPILER_NAME = "weblogic";
+
+    /** The error string to use if not able to find the weblogic rmic */
+    public static final String ERROR_NO_WLRMIC_ON_CLASSPATH =
+        "Cannot use WebLogic rmic, as it is not "
+        + "available. Add it to Ant's classpath with the -lib option";
+
+    /** The error string to use if not able to start the weblogic rmic */
+    public static final String ERROR_WLRMIC_FAILED = "Error starting WebLogic rmic: ";
+    /** The stub suffix */
+    public static final String WL_RMI_STUB_SUFFIX = "_WLStub";
+    /** The skeleton suffix */
+    public static final String WL_RMI_SKEL_SUFFIX = "_WLSkel";
+    /** upsupported error message */
+    public static final String UNSUPPORTED_STUB_OPTION = "Unsupported stub option: ";
+
+    /**
+     * Carry out the rmic compilation.
+     * @return true if the compilation succeeded
+     * @throws  BuildException on error
+     */
+    public boolean execute() throws BuildException {
+        getRmic().log("Using WebLogic rmic", Project.MSG_VERBOSE);
+        Commandline cmd = setupRmicCommand(new String[] {"-noexit"});
+
+        AntClassLoader loader = null;
+        try {
+            // Create an instance of the rmic
+            Class c = null;
+            if (getRmic().getClasspath() == null) {
+                c = Class.forName(WLRMIC_CLASSNAME);
+            } else {
+                loader
+                    = getRmic().getProject().createClassLoader(getRmic().getClasspath());
+                c = Class.forName(WLRMIC_CLASSNAME, true, loader);
+            }
+            Method doRmic = c.getMethod("main",
+                                        new Class [] {String[].class});
+            doRmic.invoke(null, new Object[] {cmd.getArguments()});
+            return true;
+        } catch (ClassNotFoundException ex) {
+            throw new BuildException(ERROR_NO_WLRMIC_ON_CLASSPATH, getRmic().getLocation());
+        } catch (Exception ex) {
+            if (ex instanceof BuildException) {
+                throw (BuildException) ex;
+            } else {
+                throw new BuildException(ERROR_WLRMIC_FAILED, ex,
+                                         getRmic().getLocation());
+            }
+        } finally {
+            if (loader != null) {
+                loader.cleanup();
+            }
+        }
+    }
+
+    /**
+     * Get the suffix for the rmic stub classes
+     * @return the stub suffix
+     */
+    public String getStubClassSuffix() {
+        return WL_RMI_STUB_SUFFIX;
+    }
+
+    /**
+     * Get the suffix for the rmic skeleton classes
+     * @return the skeleton suffix
+     */
+    public String getSkelClassSuffix() {
+        return WL_RMI_SKEL_SUFFIX;
+    }
+
+    /**
+     * Strip out all -J args from the command list.
+     *
+     * @param compilerArgs the original compiler arguments
+     * @return the filtered set.
+     */
+    protected String[] preprocessCompilerArgs(String[] compilerArgs) {
+        return filterJvmCompilerArgs(compilerArgs);
+    }
+
+    /**
+     * This is an override point; no stub version is returned. If any
+     * stub option is set, a warning is printed.
+     * @return null, for no stub version
+     */
+    protected String addStubVersionOptions() {
+        //handle the many different stub options.
+        String stubVersion = getRmic().getStubVersion();
+        if (null != stubVersion) {
+            getRmic().log(UNSUPPORTED_STUB_OPTION + stubVersion,
+                          Project.MSG_WARN);
+        }
+        return null;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/XNewRmic.java b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/XNewRmic.java
new file mode 100644
index 0000000..a5b9ad6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/taskdefs/rmic/XNewRmic.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.rmic;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Run rmic in a new process with -Xnew set.
+ * This switches rmic to use a new compiler, one that doesnt work in-process
+ * on ant on java1.6.
+ * see: <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=38732">
+ * http://issues.apache.org/bugzilla/show_bug.cgi?id=38732</a>
+ */
+public class XNewRmic extends ForkingSunRmic {
+
+    /**
+     * the name of this adapter for users to select
+     */
+    public static final String COMPILER_NAME = "xnew";
+
+    /** No-arg constructor. */
+    public XNewRmic() {
+    }
+
+    /**
+     * Create a normal command line, then with -Xnew at the front
+     * @return a command line that hands off to thw
+     */
+    protected Commandline setupRmicCommand() {
+        String[] options = new String[] {
+                "-Xnew"
+        };
+        Commandline commandline = super.setupRmicCommand(options);
+        return commandline;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/trunk/src/main/org/apache/tools/ant/types/AbstractFileSet.java
new file mode 100644
index 0000000..b800545
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/AbstractFileSet.java
@@ -0,0 +1,828 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.FileScanner;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.selectors.OrSelector;
+import org.apache.tools.ant.types.selectors.AndSelector;
+import org.apache.tools.ant.types.selectors.NotSelector;
+import org.apache.tools.ant.types.selectors.DateSelector;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.NoneSelector;
+import org.apache.tools.ant.types.selectors.SizeSelector;
+import org.apache.tools.ant.types.selectors.TypeSelector;
+import org.apache.tools.ant.types.selectors.DepthSelector;
+import org.apache.tools.ant.types.selectors.DependSelector;
+import org.apache.tools.ant.types.selectors.ExtendSelector;
+import org.apache.tools.ant.types.selectors.SelectSelector;
+import org.apache.tools.ant.types.selectors.PresentSelector;
+import org.apache.tools.ant.types.selectors.SelectorScanner;
+import org.apache.tools.ant.types.selectors.ContainsSelector;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+import org.apache.tools.ant.types.selectors.MajoritySelector;
+import org.apache.tools.ant.types.selectors.DifferentSelector;
+import org.apache.tools.ant.types.selectors.SelectorContainer;
+import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * Class that holds an implicit patternset and supports nested
+ * patternsets and creates a DirectoryScanner using these patterns.
+ *
+ * <p>Common base class for DirSet and FileSet.</p>
+ *
+ */
+public abstract class AbstractFileSet extends DataType
+    implements Cloneable, SelectorContainer {
+
+    private PatternSet defaultPatterns = new PatternSet();
+    private Vector additionalPatterns = new Vector();
+    private Vector selectors = new Vector();
+
+    private File dir;
+    private boolean useDefaultExcludes = true;
+    private boolean caseSensitive = true;
+    private boolean followSymlinks = true;
+    private boolean errorOnMissingDir = true;
+
+    /* cached DirectoryScanner instance for our own Project only */
+    private DirectoryScanner directoryScanner = null;
+
+    /**
+     * Construct a new <code>AbstractFileSet</code>.
+     */
+    public AbstractFileSet() {
+        super();
+    }
+
+    /**
+     * Construct a new <code>AbstractFileSet</code>, shallowly cloned
+     * from the specified <code>AbstractFileSet</code>.
+     * @param fileset the <code>AbstractFileSet</code> to use as a template.
+     */
+    protected AbstractFileSet(AbstractFileSet fileset) {
+        this.dir = fileset.dir;
+        this.defaultPatterns = fileset.defaultPatterns;
+        this.additionalPatterns = fileset.additionalPatterns;
+        this.selectors = fileset.selectors;
+        this.useDefaultExcludes = fileset.useDefaultExcludes;
+        this.caseSensitive = fileset.caseSensitive;
+        this.followSymlinks = fileset.followSymlinks;
+        this.errorOnMissingDir = fileset.errorOnMissingDir;
+        setProject(fileset.getProject());
+    }
+
+    /**
+     * Makes this instance in effect a reference to another instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the <code>Reference</code> to use.
+     * @throws BuildException on error
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (dir != null || defaultPatterns.hasPatterns(getProject())) {
+            throw tooManyAttributes();
+        }
+        if (!additionalPatterns.isEmpty()) {
+            throw noChildrenAllowed();
+        }
+        if (!selectors.isEmpty()) {
+            throw noChildrenAllowed();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Sets the base-directory for this instance.
+     * @param dir the directory's <code>File</code> instance.
+     * @throws BuildException on error
+     */
+    public synchronized void setDir(File dir) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.dir = dir;
+        directoryScanner = null;
+    }
+
+    /**
+     * Retrieves the base-directory for this instance.
+     * @return <code>File</code>.
+     */
+    public File getDir() {
+        return getDir(getProject());
+    }
+
+    /**
+     * Retrieves the base-directory for this instance.
+     * @param p the <code>Project</code> against which the
+     *          reference is resolved, if set.
+     * @return <code>File</code>.
+     */
+    public synchronized File getDir(Project p) {
+        return (isReference()) ? getRef(p).getDir(p) : dir;
+    }
+
+    /**
+     * Creates a nested patternset.
+     * @return <code>PatternSet</code>.
+     */
+    public synchronized PatternSet createPatternSet() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        PatternSet patterns = new PatternSet();
+        additionalPatterns.addElement(patterns);
+        directoryScanner = null;
+        return patterns;
+    }
+
+    /**
+     * Add a name entry to the include list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createInclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        directoryScanner = null;
+        return defaultPatterns.createInclude();
+    }
+
+    /**
+     * Add a name entry to the include files list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createIncludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        directoryScanner = null;
+        return defaultPatterns.createIncludesFile();
+    }
+
+    /**
+     * Add a name entry to the exclude list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createExclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        directoryScanner = null;
+        return defaultPatterns.createExclude();
+    }
+
+    /**
+     * Add a name entry to the excludes files list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createExcludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        directoryScanner = null;
+        return defaultPatterns.createExcludesFile();
+    }
+
+    /**
+     * Creates a single file fileset.
+     * @param file the single <code>File</code> included in this
+     *             <code>AbstractFileSet</code>.
+     */
+    public synchronized void setFile(File file) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        setDir(file.getParentFile());
+        createInclude().setName(file.getName());
+    }
+
+    /**
+     * Appends <code>includes</code> to the current list of include
+     * patterns.
+     *
+     * <p>Patterns may be separated by a comma or a space.</p>
+     *
+     * @param includes the <code>String</code> containing the include patterns.
+     */
+    public synchronized void setIncludes(String includes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        defaultPatterns.setIncludes(includes);
+        directoryScanner = null;
+    }
+
+    /**
+     * Appends <code>includes</code> to the current list of include
+     * patterns.
+     *
+     * @param includes array containing the include patterns.
+     * @since Ant 1.7
+     */
+    public synchronized void appendIncludes(String[] includes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (includes != null) {
+            for (int i = 0; i < includes.length; i++) {
+                defaultPatterns.createInclude().setName(includes[i]);
+            }
+            directoryScanner = null;
+        }
+    }
+
+    /**
+     * Appends <code>excludes</code> to the current list of exclude
+     * patterns.
+     *
+     * <p>Patterns may be separated by a comma or a space.</p>
+     *
+     * @param excludes the <code>String</code> containing the exclude patterns.
+     */
+    public synchronized void setExcludes(String excludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        defaultPatterns.setExcludes(excludes);
+        directoryScanner = null;
+    }
+
+    /**
+     * Appends <code>excludes</code> to the current list of include
+     * patterns.
+     *
+     * @param excludes array containing the exclude patterns.
+     * @since Ant 1.7
+     */
+    public synchronized void appendExcludes(String[] excludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (excludes != null) {
+            for (int i = 0; i < excludes.length; i++) {
+                defaultPatterns.createExclude().setName(excludes[i]);
+            }
+            directoryScanner = null;
+        }
+    }
+
+    /**
+     * Sets the <code>File</code> containing the includes patterns.
+     *
+     * @param incl <code>File</code> instance.
+     * @throws BuildException on error
+     */
+    public synchronized void setIncludesfile(File incl) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        defaultPatterns.setIncludesfile(incl);
+        directoryScanner = null;
+    }
+
+    /**
+     * Sets the <code>File</code> containing the excludes patterns.
+     *
+     * @param excl <code>File</code> instance.
+     * @throws BuildException on error
+     */
+    public synchronized void setExcludesfile(File excl) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        defaultPatterns.setExcludesfile(excl);
+        directoryScanner = null;
+    }
+
+    /**
+     * Sets whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes <code>boolean</code>.
+     */
+    public synchronized void setDefaultexcludes(boolean useDefaultExcludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.useDefaultExcludes = useDefaultExcludes;
+        directoryScanner = null;
+    }
+
+    /**
+     * Whether default exclusions should be used or not.
+     * @return the default exclusions value.
+     * @since Ant 1.6.3
+     */
+    public synchronized boolean getDefaultexcludes() {
+        return (isReference())
+            ? getRef(getProject()).getDefaultexcludes() : useDefaultExcludes;
+    }
+
+    /**
+     * Sets case sensitivity of the file system.
+     *
+     * @param caseSensitive <code>boolean</code>.
+     */
+    public synchronized void setCaseSensitive(boolean caseSensitive) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.caseSensitive = caseSensitive;
+        directoryScanner = null;
+    }
+
+    /**
+     * Find out if the fileset is case sensitive.
+     *
+     * @return <code>boolean</code> indicating whether the fileset is
+     * case sensitive.
+     *
+     * @since Ant 1.7
+     */
+    public synchronized boolean isCaseSensitive() {
+        return (isReference())
+            ? getRef(getProject()).isCaseSensitive() : caseSensitive;
+    }
+
+    /**
+     * Sets whether or not symbolic links should be followed.
+     *
+     * @param followSymlinks whether or not symbolic links should be followed.
+     */
+    public synchronized void setFollowSymlinks(boolean followSymlinks) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.followSymlinks = followSymlinks;
+        directoryScanner = null;
+    }
+
+    /**
+     * Find out if the fileset wants to follow symbolic links.
+     *
+     * @return <code>boolean</code> indicating whether symbolic links
+     *         should be followed.
+     *
+     * @since Ant 1.6
+     */
+    public synchronized boolean isFollowSymlinks() {
+        return (isReference())
+            ? getRef(getProject()).isFollowSymlinks() : followSymlinks;
+    }
+
+    /**
+     * Sets whether an error is thrown if a directory does not exist.
+     *
+     * @param errorOnMissingDir true if missing directories cause errors,
+     *                        false if not.
+     */
+     public void setErrorOnMissingDir(boolean errorOnMissingDir) {
+         this.errorOnMissingDir = errorOnMissingDir;
+     }
+
+    /**
+     * Returns the directory scanner needed to access the files to process.
+     * @return a <code>DirectoryScanner</code> instance.
+     */
+    public DirectoryScanner getDirectoryScanner() {
+        return getDirectoryScanner(getProject());
+    }
+
+    /**
+     * Returns the directory scanner needed to access the files to process.
+     * @param p the Project against which the DirectoryScanner should be configured.
+     * @return a <code>DirectoryScanner</code> instance.
+     */
+    public DirectoryScanner getDirectoryScanner(Project p) {
+        if (isReference()) {
+            return getRef(p).getDirectoryScanner(p);
+        }
+        DirectoryScanner ds = null;
+        synchronized (this) {
+            if (directoryScanner != null && p == getProject()) {
+                ds = directoryScanner;
+            } else {
+                if (dir == null) {
+                    throw new BuildException("No directory specified for "
+                                             + getDataTypeName() + ".");
+                }
+                if (!dir.exists() && errorOnMissingDir) {
+                    throw new BuildException(dir.getAbsolutePath()
+                                             + " not found.");
+                }
+                if (!dir.isDirectory() && dir.exists()) {
+                    throw new BuildException(dir.getAbsolutePath()
+                                             + " is not a directory.");
+                }
+                ds = new DirectoryScanner();
+                setupDirectoryScanner(ds, p);
+                ds.setFollowSymlinks(followSymlinks);
+                ds.setErrorOnMissingDir(errorOnMissingDir);
+                directoryScanner = (p == getProject()) ? ds : directoryScanner;
+            }
+        }
+        ds.scan();
+        return ds;
+    }
+
+    /**
+     * Set up the specified directory scanner against this
+     * AbstractFileSet's Project.
+     * @param ds a <code>FileScanner</code> instance.
+     */
+    public void setupDirectoryScanner(FileScanner ds) {
+        setupDirectoryScanner(ds, getProject());
+    }
+
+    /**
+     * Set up the specified directory scanner against the specified project.
+     * @param ds a <code>FileScanner</code> instance.
+     * @param p an Ant <code>Project</code> instance.
+     */
+    public synchronized void setupDirectoryScanner(FileScanner ds, Project p) {
+        if (isReference()) {
+            getRef(p).setupDirectoryScanner(ds, p);
+            return;
+        }
+        if (ds == null) {
+            throw new IllegalArgumentException("ds cannot be null");
+        }
+        ds.setBasedir(dir);
+
+        PatternSet ps = mergePatterns(p);
+        p.log(getDataTypeName() + ": Setup scanner in dir " + dir
+            + " with " + ps, Project.MSG_DEBUG);
+
+        ds.setIncludes(ps.getIncludePatterns(p));
+        ds.setExcludes(ps.getExcludePatterns(p));
+        if (ds instanceof SelectorScanner) {
+            SelectorScanner ss = (SelectorScanner) ds;
+            ss.setSelectors(getSelectors(p));
+        }
+        if (useDefaultExcludes) {
+            ds.addDefaultExcludes();
+        }
+        ds.setCaseSensitive(caseSensitive);
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced FileSet.
+     * @param p the current project
+     * @return the referenced FileSet
+     */
+    protected AbstractFileSet getRef(Project p) {
+        return (AbstractFileSet) getCheckedRef(p);
+    }
+
+    // SelectorContainer methods
+
+    /**
+     * Indicates whether there are any selectors here.
+     *
+     * @return whether any selectors are in this container.
+     */
+    public synchronized boolean hasSelectors() {
+        return (isReference() && getProject() != null)
+            ? getRef(getProject()).hasSelectors() : !(selectors.isEmpty());
+    }
+
+    /**
+     * Indicates whether there are any patterns here.
+     *
+     * @return whether any patterns are in this container.
+     */
+    public synchronized boolean hasPatterns() {
+        if (isReference() && getProject() != null) {
+            return getRef(getProject()).hasPatterns();
+        }
+        if (defaultPatterns.hasPatterns(getProject())) {
+            return true;
+        }
+        Enumeration e = additionalPatterns.elements();
+        while (e.hasMoreElements()) {
+            PatternSet ps = (PatternSet) e.nextElement();
+            if (ps.hasPatterns(getProject())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gives the count of the number of selectors in this container.
+     *
+     * @return the number of selectors in this container as an <code>int</code>.
+     */
+    public synchronized int selectorCount() {
+        return (isReference() && getProject() != null)
+            ? getRef(getProject()).selectorCount() : selectors.size();
+    }
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return a <code>FileSelector[]</code> of the selectors in this container.
+     */
+    public synchronized FileSelector[] getSelectors(Project p) {
+        return (isReference())
+            ? getRef(p).getSelectors(p) : (FileSelector[]) (selectors.toArray(
+            new FileSelector[selectors.size()]));
+    }
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     *
+     * @return an <code>Enumeration</code> of selectors.
+     */
+    public synchronized Enumeration selectorElements() {
+        return (isReference() && getProject() != null)
+            ? getRef(getProject()).selectorElements() : selectors.elements();
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new <code>FileSelector</code> to add.
+     */
+    public synchronized void appendSelector(FileSelector selector) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        selectors.addElement(selector);
+        directoryScanner = null;
+    }
+
+    /* Methods below all add specific selectors */
+
+    /**
+     * Add a "Select" selector entry on the selector list.
+     * @param selector the <code>SelectSelector</code> to add.
+     */
+    public void addSelector(SelectSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add an "And" selector entry on the selector list.
+     * @param selector the <code>AndSelector</code> to add.
+     */
+    public void addAnd(AndSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add an "Or" selector entry on the selector list.
+     * @param selector the <code>OrSelector</code> to add.
+     */
+    public void addOr(OrSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a "Not" selector entry on the selector list.
+     * @param selector the <code>NotSelector</code> to add.
+     */
+    public void addNot(NotSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a "None" selector entry on the selector list.
+     * @param selector the <code>NoneSelector</code> to add.
+     */
+    public void addNone(NoneSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a majority selector entry on the selector list.
+     * @param selector the <code>MajoritySelector</code> to add.
+     */
+    public void addMajority(MajoritySelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a selector date entry on the selector list.
+     * @param selector the <code>DateSelector</code> to add.
+     */
+    public void addDate(DateSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a selector size entry on the selector list.
+     * @param selector the <code>SizeSelector</code> to add.
+     */
+    public void addSize(SizeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a DifferentSelector entry on the selector list.
+     * @param selector the <code>DifferentSelector</code> to add.
+     */
+    public void addDifferent(DifferentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a selector filename entry on the selector list.
+     * @param selector the <code>FilenameSelector</code> to add.
+     */
+    public void addFilename(FilenameSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a selector type entry on the selector list.
+     * @param selector the <code>TypeSelector</code> to add.
+     */
+    public void addType(TypeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add an extended selector entry on the selector list.
+     * @param selector the <code>ExtendSelector</code> to add.
+     */
+    public void addCustom(ExtendSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a contains selector entry on the selector list.
+     * @param selector the <code>ContainsSelector</code> to add.
+     */
+    public void addContains(ContainsSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a present selector entry on the selector list.
+     * @param selector the <code>PresentSelector</code> to add.
+     */
+    public void addPresent(PresentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a depth selector entry on the selector list.
+     * @param selector the <code>DepthSelector</code> to add.
+     */
+    public void addDepth(DepthSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a depends selector entry on the selector list.
+     * @param selector the <code>DependSelector</code> to add.
+     */
+    public void addDepend(DependSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add a regular expression selector entry on the selector list.
+     * @param selector the <code>ContainsRegexpSelector</code> to add.
+     */
+    public void addContainsRegexp(ContainsRegexpSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add the modified selector.
+     * @param selector the <code>ModifiedSelector</code> to add.
+     * @since ant 1.6
+     */
+    public void addModified(ModifiedSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Add an arbitary selector.
+     * @param selector the <code>FileSelector</code> to add.
+     * @since Ant 1.6
+     */
+    public void add(FileSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * Returns included files as a list of semicolon-separated filenames.
+     *
+     * @return a <code>String</code> of included filenames.
+     */
+    public String toString() {
+        DirectoryScanner ds = getDirectoryScanner(getProject());
+        String[] files = ds.getIncludedFiles();
+        StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < files.length; i++) {
+            if (i > 0) {
+                sb.append(';');
+            }
+            sb.append(files[i]);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Creates a deep clone of this instance, except for the nested
+     * selectors (the list of selectors is a shallow clone of this
+     * instance's list).
+     * @return the cloned object
+     * @since Ant 1.6
+     */
+    public synchronized Object clone() {
+        if (isReference()) {
+            return (getRef(getProject())).clone();
+        } else {
+            try {
+                AbstractFileSet fs = (AbstractFileSet) super.clone();
+                fs.defaultPatterns = (PatternSet) defaultPatterns.clone();
+                fs.additionalPatterns = new Vector(additionalPatterns.size());
+                Enumeration e = additionalPatterns.elements();
+                while (e.hasMoreElements()) {
+                    fs.additionalPatterns
+                        .addElement(((PatternSet) e.nextElement()).clone());
+                }
+                fs.selectors = new Vector(selectors);
+                return fs;
+            } catch (CloneNotSupportedException e) {
+                throw new BuildException(e);
+            }
+        }
+    }
+
+    /**
+     * Get the merged include patterns for this AbstractFileSet.
+     * @param p the project to use.
+     * @return the include patterns of the default pattern set and all
+     * nested patternsets.
+     *
+     * @since Ant 1.7
+     */
+    public String[] mergeIncludes(Project p) {
+        return mergePatterns(p).getIncludePatterns(p);
+    }
+
+    /**
+     * Get the merged exclude patterns for this AbstractFileSet.
+     * @param p the project to use.
+     * @return the exclude patterns of the default pattern set and all
+     * nested patternsets.
+     *
+     * @since Ant 1.7
+     */
+    public String[] mergeExcludes(Project p) {
+        return mergePatterns(p).getExcludePatterns(p);
+    }
+
+    /**
+     * Get the merged patterns for this AbstractFileSet.
+     * @param p the project to use.
+     * @return the default patternset merged with the additional sets
+     * in a new PatternSet instance.
+     *
+     * @since Ant 1.7
+     */
+    public synchronized PatternSet mergePatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).mergePatterns(p);
+        }
+        PatternSet ps = (PatternSet) defaultPatterns.clone();
+        final int count = additionalPatterns.size();
+        for (int i = 0; i < count; i++) {
+            Object o = additionalPatterns.elementAt(i);
+            ps.append((PatternSet) o, p);
+        }
+        return ps;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/AntFilterReader.java b/trunk/src/main/org/apache/tools/ant/types/AntFilterReader.java
new file mode 100644
index 0000000..737bcec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/AntFilterReader.java
@@ -0,0 +1,157 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * An AntFilterReader is a wrapper class that encloses the classname
+ * and configuration of a Configurable FilterReader.
+ */
+public final class AntFilterReader
+    extends DataType implements Cloneable {
+
+    private String className;
+
+    private final Vector parameters = new Vector();
+
+    private Path classpath;
+
+    /**
+     * Set the className attribute.
+     *
+     * @param className a <code>String</code> value
+     */
+    public void setClassName(final String className) {
+        this.className = className;
+    }
+
+    /**
+     * Get the className attribute.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Add a Parameter.
+     *
+     * @param param a <code>Parameter</code> value
+     */
+    public void addParam(final Parameter param) {
+        parameters.addElement(param);
+    }
+
+    /**
+     * Set the classpath to load the FilterReader through (attribute).
+     * @param classpath a classpath
+     */
+    public void setClasspath(Path classpath) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Set the classpath to load the FilterReader through (nested element).
+     * @return a classpath to be configured
+     */
+    public Path createClasspath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Get the classpath.
+     * @return the classpath
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Set the classpath to load the FilterReader through via
+     * reference (attribute).
+     * @param r a reference to a classpath
+     */
+    public void setClasspathRef(Reference r) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * The parameters for this filter.
+     *
+     * @return a <code>Parameter[]</code> value
+     */
+    public Parameter[] getParams() {
+        Parameter[] params = new Parameter[parameters.size()];
+        parameters.copyInto(params);
+        return params;
+    }
+
+    /**
+     * Makes this instance in effect a reference to another AntFilterReader
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     *
+     * @param r the reference to which this instance is associated
+     * @exception BuildException if this instance already has been configured.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (!parameters.isEmpty() || className != null
+                || classpath != null) {
+            throw tooManyAttributes();
+        }
+        // change this to get the objects from the other reference
+        Object o = r.getReferencedObject(getProject());
+        if (o instanceof AntFilterReader) {
+            AntFilterReader afr = (AntFilterReader) o;
+            setClassName(afr.getClassName());
+            setClasspath(afr.getClasspath());
+            Parameter[] p = afr.getParams();
+            if (p != null) {
+                for (int i = 0; i < p.length; i++) {
+                    addParam(p[i]);
+                }
+            }
+        } else {
+            String msg = r.getRefId() + " doesn\'t refer to a FilterReader";
+            throw new BuildException(msg);
+        }
+
+        super.setRefid(r);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ArchiveFileSet.java b/trunk/src/main/org/apache/tools/ant/types/ArchiveFileSet.java
new file mode 100755
index 0000000..2780389
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ArchiveFileSet.java
@@ -0,0 +1,493 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.Iterator;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.zip.UnixStat;
+
+/**
+ * A ArchiveFileSet is a FileSet with extra attributes useful in the
+ * context of archiving tasks.
+ *
+ * It includes a prefix attribute which is prepended to each entry in
+ * the output archive file as well as a fullpath attribute.  It also
+ * supports Unix file permissions for files and directories.
+ *
+ * @since Ant 1.7
+ */
+public abstract class ArchiveFileSet extends FileSet {
+
+    private static final int BASE_OCTAL = 8;
+
+    /**
+     * Default value for the dirmode attribute.
+     *
+     * @since Ant 1.5.2
+     */
+    public static final int DEFAULT_DIR_MODE =
+        UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM;
+
+    /**
+     * Default value for the filemode attribute.
+     *
+     * @since Ant 1.5.2
+     */
+    public static final int DEFAULT_FILE_MODE =
+        UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM;
+
+    private Resource src          = null;
+    private String prefix         = "";
+    private String fullpath       = "";
+    private boolean hasDir        = false;
+    private int fileMode          = DEFAULT_FILE_MODE;
+    private int dirMode           = DEFAULT_DIR_MODE;
+
+    private boolean fileModeHasBeenSet = false;
+    private boolean dirModeHasBeenSet  = false;
+
+    /** Constructor for ArchiveFileSet */
+    public ArchiveFileSet() {
+        super();
+    }
+
+    /**
+     * Constructor using a fileset arguement.
+     * @param fileset the fileset to use
+     */
+    protected ArchiveFileSet(FileSet fileset) {
+        super(fileset);
+    }
+
+    /**
+     * Constructor using a archive fileset arguement.
+     * @param fileset the archivefileset to use
+     */
+    protected ArchiveFileSet(ArchiveFileSet fileset) {
+        super(fileset);
+        src = fileset.src;
+        prefix = fileset.prefix;
+        fullpath = fileset.fullpath;
+        hasDir = fileset.hasDir;
+        fileMode = fileset.fileMode;
+        dirMode = fileset.dirMode;
+        fileModeHasBeenSet = fileset.fileModeHasBeenSet;
+        dirModeHasBeenSet = fileset.dirModeHasBeenSet;
+    }
+
+    /**
+     * Set the directory for the fileset.
+     * @param dir the directory for the fileset
+     * @throws BuildException on error
+     */
+    public void setDir(File dir) throws BuildException {
+        checkAttributesAllowed();
+        if (src != null) {
+            throw new BuildException("Cannot set both dir and src attributes");
+        }
+        super.setDir(dir);
+        hasDir = true;
+    }
+
+    /**
+     * Set the source Archive file for the archivefileset.  Prevents both
+     * "dir" and "src" from being specified.
+     * @param a the archive as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        checkChildrenAllowed();
+        if (a.size() != 1) {
+            throw new BuildException("only single argument resource collections"
+                                     + " are supported as archives");
+        }
+        setSrcResource((Resource) a.iterator().next());
+    }
+
+    /**
+     * Set the source Archive file for the archivefileset.  Prevents both
+     * "dir" and "src" from being specified.
+     *
+     * @param srcFile The archive from which to extract entries.
+     */
+    public void setSrc(File srcFile) {
+        setSrcResource(new FileResource(srcFile));
+    }
+
+    /**
+     * Set the source Archive file for the archivefileset.  Prevents both
+     * "dir" and "src" from being specified.
+     *
+     * @param src The archive from which to extract entries.
+     */
+    public void setSrcResource(Resource src) {
+        checkArchiveAttributesAllowed();
+        if (hasDir) {
+            throw new BuildException("Cannot set both dir and src attributes");
+        }
+        this.src = src;
+    }
+
+    /**
+     * Get the archive from which entries will be extracted.
+     * @param p the project to use
+     * @return the source file
+     */
+    public File getSrc(Project p) {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(p)).getSrc(p);
+        }
+        return getSrc();
+    }
+
+    /**
+     * Get the archive file from which entries will be extracted.
+     * @return the archive in case the archive is a file, null otherwise.
+     */
+    public File getSrc() {
+        if (src instanceof FileResource) {
+            return ((FileResource) src).getFile();
+        }
+        return null;
+    }
+
+    /**
+     * Prepend this prefix to the path for each archive entry.
+     * Prevents both prefix and fullpath from being specified
+     *
+     * @param prefix The prefix to prepend to entries in the archive file.
+     */
+    public void setPrefix(String prefix) {
+        checkArchiveAttributesAllowed();
+        if (!"".equals(prefix) && !"".equals(fullpath)) {
+            throw new BuildException("Cannot set both fullpath and prefix attributes");
+        }
+        this.prefix = prefix;
+    }
+
+    /**
+     * Return the prefix prepended to entries in the archive file.
+     * @param p the project to use
+     * @return the prefix
+     */
+    public String getPrefix(Project p) {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(p)).getPrefix(p);
+        }
+        return prefix;
+    }
+
+    /**
+     * Set the full pathname of the single entry in this fileset.
+     * Prevents both prefix and fullpath from being specified
+     *
+     * @param fullpath the full pathname of the single entry in this fileset.
+     */
+    public void setFullpath(String fullpath) {
+        checkArchiveAttributesAllowed();
+        if (!"".equals(prefix) && !"".equals(fullpath)) {
+            throw new BuildException("Cannot set both fullpath and prefix attributes");
+        }
+        this.fullpath = fullpath;
+    }
+
+    /**
+     * Return the full pathname of the single entry in this fileset.
+     * @param p the project to use
+     * @return the full path
+     */
+    public String getFullpath(Project p) {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(p)).getFullpath(p);
+        }
+        return fullpath;
+    }
+
+    /**
+     * Creates a scanner for this type of archive.
+     * @return the scanner.
+     */
+    protected abstract ArchiveScanner newArchiveScanner();
+
+    /**
+     * Return the DirectoryScanner associated with this FileSet.
+     * If the ArchiveFileSet defines a source Archive file, then an ArchiveScanner
+     * is returned instead.
+     * @param p the project to use
+     * @return a directory scanner
+     */
+    public DirectoryScanner getDirectoryScanner(Project p) {
+        if (isReference()) {
+            return getRef(p).getDirectoryScanner(p);
+        }
+        if (src == null) {
+            return super.getDirectoryScanner(p);
+        }
+        if (!src.isExists()) {
+            throw new BuildException(
+                "the archive " + src.getName() + " doesn't exist");
+        }
+        if (src.isDirectory()) {
+            throw new BuildException("the archive " + src.getName()
+                                     + " can't be a directory");
+        }
+        ArchiveScanner as = newArchiveScanner();
+        as.setSrc(src);
+        super.setDir(p.getBaseDir());
+        setupDirectoryScanner(as, p);
+        as.init();
+        return as;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        if (isReference()) {
+            return ((ResourceCollection) (getRef(getProject()))).iterator();
+        }
+        if (src == null) {
+            return super.iterator();
+        }
+        ArchiveScanner as = (ArchiveScanner) getDirectoryScanner(getProject());
+        return as.getResourceFiles();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return size of the collection as int.
+     * @since Ant 1.7
+     */
+    public int size() {
+        if (isReference()) {
+            return ((ResourceCollection) (getRef(getProject()))).size();
+        }
+        if (src == null) {
+            return super.size();
+        }
+        ArchiveScanner as = (ArchiveScanner) getDirectoryScanner(getProject());
+        return as.getIncludedFilesCount();
+    }
+
+    /**
+     * Indicate whether this ResourceCollection is composed entirely of
+     * Resources accessible via local filesystem conventions.  If true,
+     * all Resources returned from this ResourceCollection should be
+     * instances of FileResource.
+     * @return whether this is a filesystem-only resource collection.
+     * @since Ant 1.7
+     */
+    public boolean isFilesystemOnly() {
+        return src == null;
+    }
+
+    /**
+     * A 3 digit octal string, specify the user, group and
+     * other modes in the standard Unix fashion;
+     * optional, default=0644
+     * @param octalString a <code>String</code> value
+     */
+    public void setFileMode(String octalString) {
+        checkArchiveAttributesAllowed();
+        integerSetFileMode(Integer.parseInt(octalString, BASE_OCTAL));
+    }
+
+    /**
+     * specify the user, group and
+     * other modes in the standard Unix fashion;
+     * optional, default=0644
+     *
+     * <p>We use the strange name so this method doesn't appear in
+     * IntrospectionHelpers list of attribute setters.</p>
+     * @param mode a <code>int</code> value
+     * @since Ant 1.7
+     */
+    public void integerSetFileMode(int mode) {
+        fileModeHasBeenSet = true;
+        this.fileMode = UnixStat.FILE_FLAG | mode;
+    }
+
+    /**
+     * Get the mode of the archive fileset
+     * @param p the project to use
+     * @return the mode
+     */
+    public int getFileMode(Project p) {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(p)).getFileMode(p);
+        }
+        return fileMode;
+    }
+
+    /**
+     * Whether the user has specified the mode explicitly.
+     * @return true if it has been set
+     */
+    public boolean hasFileModeBeenSet() {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(getProject())).hasFileModeBeenSet();
+        }
+        return fileModeHasBeenSet;
+    }
+
+    /**
+     * A 3 digit octal string, specify the user, group and
+     * other modes in the standard Unix fashion;
+     * optional, default=0755
+     * @param octalString a <code>String</code> value
+     */
+    public void setDirMode(String octalString) {
+        checkArchiveAttributesAllowed();
+        integerSetDirMode(Integer.parseInt(octalString, BASE_OCTAL));
+    }
+
+    /**
+     * specify the user, group and
+     * other modes in the standard Unix fashion;
+     * optional, default=0755
+     * <p>We use the strange name so this method doesn't appear in
+     * IntrospectionHelpers list of attribute setters.</p>
+     * @param mode a <code>int</code> value
+     * @since Ant 1.7
+     */
+    public void integerSetDirMode(int mode) {
+        dirModeHasBeenSet = true;
+        this.dirMode = UnixStat.DIR_FLAG | mode;
+    }
+
+    /**
+     * Get the dir mode of the archive fileset
+     * @param p the project to use
+     * @return the mode
+     */
+    public int getDirMode(Project p) {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(p)).getDirMode(p);
+        }
+        return dirMode;
+    }
+
+    /**
+     * Whether the user has specified the mode explicitly.
+     *
+     * @return true if it has been set
+     */
+    public boolean hasDirModeBeenSet() {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(getProject())).hasDirModeBeenSet();
+        }
+        return dirModeHasBeenSet;
+    }
+
+    /**
+     * A ArchiveFileset accepts another ArchiveFileSet or a FileSet as reference
+     * FileSets are often used by the war task for the lib attribute
+     * @param zfs the project to use
+     */
+    protected void configureFileSet(ArchiveFileSet zfs) {
+        zfs.setPrefix(prefix);
+        zfs.setFullpath(fullpath);
+        zfs.fileModeHasBeenSet = fileModeHasBeenSet;
+        zfs.fileMode = fileMode;
+        zfs.dirModeHasBeenSet = dirModeHasBeenSet;
+        zfs.dirMode = dirMode;
+    }
+
+    /**
+     * Return a ArchiveFileSet that has the same properties
+     * as this one.
+     * @return the cloned archiveFileSet
+     * @since Ant 1.6
+     */
+    public Object clone() {
+        if (isReference()) {
+            return ((ArchiveFileSet) getRef(getProject())).clone();
+        }
+        return super.clone();
+    }
+
+    /**
+     * For file-based archivefilesets, return the same as for normal filesets;
+     * else just return the path of the zip.
+     * @return for file based archivefilesets, included files as a list
+     * of semicolon-separated filenames. else just the name of the zip.
+     */
+    public String toString() {
+        if (hasDir && getProject() != null) {
+            return super.toString();
+        }
+        return src == null ? null : src.getName();
+    }
+
+    /**
+     * Return the prefix prepended to entries in the archive file.
+     * @return the prefix.
+     * @deprecated since 1.7.
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+    /**
+     * Return the full pathname of the single entryZ in this fileset.
+     * @return the full pathname.
+     * @deprecated since 1.7.
+     */
+    public String getFullpath() {
+        return fullpath;
+    }
+
+    /**
+     * @return the file mode.
+     * @deprecated since 1.7.
+     */
+    public int getFileMode() {
+        return fileMode;
+    }
+
+    /**
+     * @return the dir mode.
+     * @deprecated since 1.7.
+     */
+    public int getDirMode() {
+        return dirMode;
+    }
+
+    /**
+     * A check attributes for archiveFileSet.
+     * If there is a reference, and
+     * it is a ArchiveFileSet, the archive fileset attributes
+     * cannot be used.
+     * (Note, we can only see if the reference is an archive
+     * fileset if the project has been set).
+     */
+    private void checkArchiveAttributesAllowed() {
+        if (getProject() == null
+            || (isReference()
+                && (getRefid().getReferencedObject(
+                        getProject())
+                    instanceof ArchiveFileSet))) {
+            checkAttributesAllowed();
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ArchiveScanner.java b/trunk/src/main/org/apache/tools/ant/types/ArchiveScanner.java
new file mode 100755
index 0000000..59b8990
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ArchiveScanner.java
@@ -0,0 +1,335 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.Iterator;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+
+/**
+ * ArchiveScanner accesses the pattern matching algorithm in DirectoryScanner,
+ * which are protected methods that can only be accessed by subclassing.
+ *
+ * This implementation of FileScanner defines getIncludedFiles to return
+ * the matching archive entries.
+ *
+ * @since Ant 1.7
+ */
+public abstract class ArchiveScanner extends DirectoryScanner {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * The archive file which should be scanned.
+     */
+    protected File srcFile;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * The archive resource which should be scanned.
+     */
+    private Resource src;
+
+    /**
+     * to record the last scanned zip file with its modification date
+     */
+    private Resource lastScannedResource;
+
+    /**
+     * record list of all file zip entries
+     */
+    private TreeMap fileEntries = new TreeMap();
+
+    /**
+     * record list of all directory zip entries
+     */
+    private TreeMap dirEntries = new TreeMap();
+
+    /**
+     * record list of matching file zip entries
+     */
+    private TreeMap matchFileEntries = new TreeMap();
+
+    /**
+     * record list of matching directory zip entries
+     */
+    private TreeMap matchDirEntries = new TreeMap();
+
+    /**
+     * encoding of file names.
+     *
+     * @since Ant 1.6
+     */
+    private String encoding;
+
+    /**
+     * Don't scan when we have no zipfile.
+     * @since Ant 1.7
+     */
+    public void scan() {
+        if (src == null) {
+            return;
+        }
+        super.scan();
+    }
+
+    /**
+     * Sets the srcFile for scanning. This is the jar or zip file that
+     * is scanned for matching entries.
+     *
+     * @param srcFile the (non-null) archive file name for scanning
+     */
+    public void setSrc(File srcFile) {
+        setSrc(new FileResource(srcFile));
+    }
+
+    /**
+     * Sets the src for scanning. This is the jar or zip file that
+     * is scanned for matching entries.
+     *
+     * @param src the (non-null) archive resource
+     */
+    public void setSrc(Resource src) {
+        this.src = src;
+        if (src instanceof FileResource) {
+            srcFile = ((FileResource) src).getFile();
+        }
+    }
+
+    /**
+     * Sets encoding of file names.
+     * @param encoding the encoding format
+     * @since Ant 1.6
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Returns the names of the files which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the files which matched at least one of the
+     *         include patterns and none of the exclude patterns.
+     */
+    public String[] getIncludedFiles() {
+        if (src == null) {
+            return super.getIncludedFiles();
+        }
+        scanme();
+        Set s = matchFileEntries.keySet();
+        return (String[]) (s.toArray(new String[s.size()]));
+    }
+
+    /**
+     * Override parent implementation.
+     * @return count of included files.
+     * @since Ant 1.7
+     */
+    public int getIncludedFilesCount() {
+        if (src == null) {
+            return super.getIncludedFilesCount();
+        }
+        scanme();
+        return matchFileEntries.size();
+    }
+
+    /**
+     * Returns the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     * The names are relative to the base directory.
+     *
+     * @return the names of the directories which matched at least one of the
+     * include patterns and none of the exclude patterns.
+     */
+    public String[] getIncludedDirectories() {
+        if (src == null) {
+            return super.getIncludedDirectories();
+        }
+        scanme();
+        Set s = matchDirEntries.keySet();
+        return (String[]) (s.toArray(new String[s.size()]));
+    }
+
+    /**
+     * Override parent implementation.
+     * @return count of included directories.
+     * @since Ant 1.7
+     */
+    public int getIncludedDirsCount() {
+        if (src == null) {
+            return super.getIncludedDirsCount();
+        }
+        scanme();
+        return matchDirEntries.size();
+    }
+
+    /**
+     * Get the set of Resources that represent files.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    /* package-private for now */ Iterator getResourceFiles() {
+        if (src == null) {
+            return new FileResourceIterator(getBasedir(), getIncludedFiles());
+        }
+        scanme();
+        return matchFileEntries.values().iterator();
+    }
+
+    /**
+     * Get the set of Resources that represent directories.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    /* package-private for now */  Iterator getResourceDirectories() {
+        if (src == null) {
+            return new FileResourceIterator(getBasedir(), getIncludedDirectories());
+        }
+        scanme();
+        return matchDirEntries.values().iterator();
+    }
+
+    /**
+     * Initialize DirectoryScanner data structures.
+     */
+    public void init() {
+        if (includes == null) {
+            // No includes supplied, so set it to 'matches all'
+            includes = new String[1];
+            includes[0] = "**";
+        }
+        if (excludes == null) {
+            excludes = new String[0];
+        }
+    }
+
+    /**
+     * Matches a jar entry against the includes/excludes list,
+     * normalizing the path separator.
+     *
+     * @param path the (non-null) path name to test for inclusion
+     *
+     * @return <code>true</code> if the path should be included
+     *         <code>false</code> otherwise.
+     */
+    public boolean match(String path) {
+        String vpath = path.replace('/', File.separatorChar).
+            replace('\\', File.separatorChar);
+        return isIncluded(vpath) && !isExcluded(vpath);
+    }
+
+    /**
+     * Get the named Resource.
+     * @param name path name of the file sought in the archive
+     * @return the resource
+     * @since Ant 1.5.2
+     */
+    public Resource getResource(String name) {
+        if (src == null) {
+            return super.getResource(name);
+        }
+        if (name.equals("")) {
+            // special case in ZIPs, we do not want this thing included
+            return new Resource("", true, Long.MAX_VALUE, true);
+        }
+        // first check if the archive needs to be scanned again
+        scanme();
+        if (fileEntries.containsKey(name)) {
+            return (Resource) fileEntries.get(name);
+        }
+        name = trimSeparator(name);
+
+        if (dirEntries.containsKey(name)) {
+            return (Resource) dirEntries.get(name);
+        }
+        return new Resource(name);
+    }
+
+    /**
+     * Fills the file and directory maps with resources read from the archive.
+     *
+     * @param archive the archive to scan.
+     * @param encoding encoding used to encode file names inside the archive.
+     * @param fileEntries Map (name to resource) of non-directory
+     * resources found inside the archive.
+     * @param matchFileEntries Map (name to resource) of non-directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     * @param dirEntries Map (name to resource) of directory
+     * resources found inside the archive.
+     * @param matchDirEntries Map (name to resource) of directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     */
+    protected abstract void fillMapsFromArchive(Resource archive,
+                                                String encoding,
+                                                Map fileEntries,
+                                                Map matchFileEntries,
+                                                Map dirEntries,
+                                                Map matchDirEntries);
+
+    /**
+     * if the datetime of the archive did not change since
+     * lastScannedResource was initialized returns immediately else if
+     * the archive has not been scanned yet, then all the zip entries
+     * are put into the appropriate tables.
+     */
+    private void scanme() {
+        //do not use a FileResource b/c it pulls File info from the filesystem:
+        Resource thisresource = new Resource(src.getName(),
+                                             src.isExists(),
+                                             src.getLastModified());
+        // spare scanning again and again
+        if (lastScannedResource != null
+            && lastScannedResource.getName().equals(thisresource.getName())
+            && lastScannedResource.getLastModified()
+            == thisresource.getLastModified()) {
+            return;
+        }
+        init();
+
+        fileEntries.clear();
+        dirEntries.clear();
+        matchFileEntries.clear();
+        matchDirEntries.clear();
+        fillMapsFromArchive(src, encoding, fileEntries, matchFileEntries,
+                            dirEntries, matchDirEntries);
+
+        // record data about the last scanned resource
+        lastScannedResource = thisresource;
+    }
+
+    /**
+     * Remove trailing slash if present.
+     * @param s the file name to trim.
+     * @return the trimed file name.
+     */
+    protected static final String trimSeparator(String s) {
+        return s.endsWith("/") ? s.substring(0, s.length() - 1) : s;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Assertions.java b/trunk/src/main/org/apache/tools/ant/types/Assertions.java
new file mode 100644
index 0000000..af40d1e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Assertions.java
@@ -0,0 +1,366 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * The assertion datatype. This type describes
+ * assertion settings for the &lt;java&gt; task and others.
+ * One can set the system assertions, and enable/disable those in
+ * packages and classes.
+ * Assertions can only be enabled or disabled when forking Java.
+ *
+ * Example: set system assertions and all org.apache packages except
+ * for ant, and the class org.apache.tools.ant.Main.
+ * <pre>
+ * &lt;assertions enableSystemAssertions="true" &gt;
+ *   &lt;enable package="org.apache" /&gt;
+ *   &lt;disable package="org.apache.ant" /&gt;
+ *   &lt;enable class="org.apache.tools.ant.Main"/&gt;
+ * &lt;/assertions&gt;
+ *</pre>
+ * Disable system assertions; enable those in the anonymous package
+ * <pre>
+ * &lt;assertions enableSystemAssertions="false" &gt;
+ *   &lt;enable package="..." /&gt;
+ * &lt;/assertions&gt;
+ * </pre>
+ * enable assertions in a class called Test
+ * <pre>
+ * &lt;assertions &gt;
+ *   &lt;enable class="Test" /&gt;
+ * &lt;/assertions&gt;
+ * </pre>
+ * This type is a datatype, so you can declare assertions and use them later
+ *
+ * <pre>
+ * &lt;assertions id="project.assertions" &gt;
+ *   &lt;enable project="org.apache.test" /&gt;
+ * &lt;/assertions&gt;
+ *
+ * &lt;assertions refid="project.assertions" /&gt;
+ *
+ * </pre>
+ * @since Ant 1.6
+ */
+public class Assertions extends DataType implements Cloneable {
+
+    /**
+     * enable/disable sys assertions; null means undefined
+     */
+    private Boolean enableSystemAssertions;
+
+    /**
+     * list of type BaseAssertion
+     */
+    private ArrayList assertionList = new ArrayList();
+
+
+    /**
+     * enable assertions
+     * @param assertion an enable assertion nested element
+     */
+    public void addEnable(EnabledAssertion assertion) {
+        checkChildrenAllowed();
+        assertionList.add(assertion);
+    }
+
+    /**
+     * disable assertions
+     * @param assertion a disable assertion nested element
+     */
+    public void addDisable(DisabledAssertion assertion) {
+        checkChildrenAllowed();
+        assertionList.add(assertion);
+    }
+
+    /**
+     * enable or disable system assertions.
+     * Default is not set (neither -enablesystemassersions or -disablesytemassertions
+     * are used on the command line).
+     * @param enableSystemAssertions if true enable system assertions
+     */
+    public void setEnableSystemAssertions(Boolean enableSystemAssertions) {
+        checkAttributesAllowed();
+        this.enableSystemAssertions = enableSystemAssertions;
+    }
+
+    /**
+     * Set the value of the refid attribute.
+     *
+     * <p>Subclasses may need to check whether any other attributes
+     * have been set as well or child elements have been created and
+     * thus override this method. if they do the must call
+     * <code>super.setRefid</code>.</p>
+     * @param ref the reference to use
+     */
+    public void setRefid(Reference ref) {
+        if (assertionList.size() > 0 || enableSystemAssertions != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(ref);
+    }
+
+    /**
+     * get whatever we are referencing to. This could be ourself.
+     * @return the object that contains the assertion info
+     */
+    private Assertions getFinalReference() {
+        if (getRefid() == null) {
+            return this;
+        } else {
+            Object o = getRefid().getReferencedObject(getProject());
+            if (!(o instanceof Assertions)) {
+                throw new BuildException("reference is of wrong type");
+            }
+            return (Assertions) o;
+        }
+    }
+
+    /**
+     * how many assertions are made...will resolve references before returning
+     * @return total # of commands to make
+     */
+    public int size() {
+        Assertions clause = getFinalReference();
+        return clause.getFinalSize();
+    }
+
+
+    /**
+     * what is the final size of this object
+     * @return
+     */
+    private int getFinalSize() {
+        return assertionList.size() + (enableSystemAssertions != null ? 1 : 0);
+    }
+
+    /**
+     * add the assertions to a list in a format suitable
+     * for adding to a command line
+     * @param commandList the command line to format
+     */
+    public void applyAssertions(List commandList) {
+        getProject().log("Applying assertions", Project.MSG_DEBUG);
+        Assertions clause = getFinalReference();
+        //do the system assertions
+        if (Boolean.TRUE.equals(clause.enableSystemAssertions)) {
+            getProject().log("Enabling system assertions", Project.MSG_DEBUG);
+            commandList.add("-enablesystemassertions");
+        } else if (Boolean.FALSE.equals(clause.enableSystemAssertions)) {
+            getProject().log("disabling system assertions", Project.MSG_DEBUG);
+            commandList.add("-disablesystemassertions");
+        }
+
+        //now any inner assertions
+        Iterator it = clause.assertionList.iterator();
+        while (it.hasNext()) {
+            BaseAssertion assertion = (BaseAssertion) it.next();
+            String arg = assertion.toCommand();
+            getProject().log("adding assertion " + arg, Project.MSG_DEBUG);
+            commandList.add(arg);
+        }
+    }
+
+    /**
+     * apply all the assertions to the command.
+     * @param command the command line to format
+     */
+    public void applyAssertions(CommandlineJava command) {
+        Assertions clause = getFinalReference();
+        //do the system assertions
+        if (Boolean.TRUE.equals(clause.enableSystemAssertions)) {
+            addVmArgument(command, "-enablesystemassertions");
+        } else if (Boolean.FALSE.equals(clause.enableSystemAssertions)) {
+            addVmArgument(command, "-disablesystemassertions");
+        }
+
+        //now any inner assertions
+        Iterator it = clause.assertionList.iterator();
+        while (it.hasNext()) {
+            BaseAssertion assertion = (BaseAssertion) it.next();
+            String arg = assertion.toCommand();
+            addVmArgument(command, arg);
+        }
+    }
+
+    /**
+     * add the assertions to a list in a format suitable
+     * for adding to a command line
+     * @param commandIterator list of commands
+     */
+    public void applyAssertions(final ListIterator commandIterator) {
+        getProject().log("Applying assertions", Project.MSG_DEBUG);
+        Assertions clause = getFinalReference();
+        //do the system assertions
+        if (Boolean.TRUE.equals(clause.enableSystemAssertions)) {
+            getProject().log("Enabling system assertions", Project.MSG_DEBUG);
+            commandIterator.add("-enablesystemassertions");
+        } else if (Boolean.FALSE.equals(clause.enableSystemAssertions)) {
+            getProject().log("disabling system assertions", Project.MSG_DEBUG);
+            commandIterator.add("-disablesystemassertions");
+        }
+
+        //now any inner assertions
+        Iterator it = clause.assertionList.iterator();
+        while (it.hasNext()) {
+            BaseAssertion assertion = (BaseAssertion) it.next();
+            String arg = assertion.toCommand();
+            getProject().log("adding assertion " + arg, Project.MSG_DEBUG);
+            commandIterator.add(arg);
+        }
+    }
+
+    /**
+     * helper method to add a string JVM argument to a command
+     * @param command
+     * @param arg
+     */
+    private static void addVmArgument(CommandlineJava command, String arg) {
+        Commandline.Argument argument;
+        argument = command.createVmArgument();
+        argument.setValue(arg);
+    }
+
+    /**
+     * clone the objects.
+     * This is not a full depth clone; the list of assertions is cloned,
+     * but it does not clone the underlying assertions.
+     * @return a cli
+     * @throws CloneNotSupportedException if the super class does not support cloning
+     */
+    public Object clone() throws CloneNotSupportedException {
+        Assertions that = (Assertions) super.clone();
+        that.assertionList = (ArrayList) assertionList.clone();
+        return that;
+    }
+
+    /**
+     * base class for our assertion elements.
+     */
+
+    public abstract static class BaseAssertion {
+        private String packageName;
+        private String className;
+
+        /**
+         * name a class
+         * @param className a class name
+         */
+        public void setClass(String className) {
+            this.className = className;
+        }
+
+        /**
+         * name a package
+         * @param packageName a package name
+         */
+        public void setPackage(String packageName) {
+            this.packageName = packageName;
+        }
+
+        /**
+         * what is the class name?
+         * @return classname or null
+         * @see #setClass
+         */
+        protected String getClassName() {
+            return className;
+        }
+
+        /**
+         * what is the package name?
+         * @return package name or null
+         * @see #setPackage
+         */
+        protected String getPackageName() {
+            return packageName;
+        }
+
+        /**
+         * get the prefix used to begin the command; -ea or -da.
+         * @return prefix
+         */
+        public abstract String getCommandPrefix();
+
+        /**
+         * create a full command string from this class
+         * @throws BuildException in case of trouble
+         * @return The command string
+         */
+        public String toCommand() {
+            //catch invalidness
+            if (getPackageName() != null && getClassName() != null) {
+                throw new BuildException("Both package and class have been set");
+            }
+            StringBuffer command = new StringBuffer(getCommandPrefix());
+            //see if it is a package or a class
+            if (getPackageName() != null) {
+                //packages get a ... prefix
+                command.append(':');
+                command.append(getPackageName());
+                if (!command.toString().endsWith("...")) {
+                    //append the ... suffix if not there already
+                    command.append("...");
+                }
+            } else if (getClassName() != null) {
+                //classes just get the classname
+                command.append(':');
+                command.append(getClassName());
+            }
+            return command.toString();
+        }
+    }
+
+
+    /**
+     * an enabled assertion enables things
+     */
+    public static class EnabledAssertion extends BaseAssertion {
+        /**
+         * get the prefix used to begin the command; -ea or -da.
+         * @return prefix
+         */
+        public String getCommandPrefix() {
+            return "-ea";
+        }
+
+    }
+
+    /**
+     * A disabled assertion disables things
+     */
+    public static class DisabledAssertion extends BaseAssertion {
+        /**
+         * get the prefix used to begin the command; -ea or -da.
+         * @return prefix
+         */
+        public String getCommandPrefix() {
+            return "-da";
+        }
+
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Commandline.java b/trunk/src/main/org/apache/tools/ant/types/Commandline.java
new file mode 100644
index 0000000..a128117
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Commandline.java
@@ -0,0 +1,620 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.LinkedList;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.StringUtils;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * Commandline objects help handling command lines specifying processes to
+ * execute.
+ *
+ * The class can be used to define a command line as nested elements or as a
+ * helper to define a command line by an application.
+ * <p>
+ * <code>
+ * &lt;someelement&gt;<br>
+ * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 argument_3" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
+ * &lt;/someelement&gt;<br>
+ * </code>
+ * The element <code>someelement</code> must provide a method
+ * <code>createAcommandline</code> which returns an instance of this class.
+ *
+ */
+public class Commandline implements Cloneable {
+    /** win9x uses a (shudder) bat file (antRun.bat) for executing commands */
+    private static final boolean IS_WIN_9X = Os.isFamily("win9x");
+
+    /**
+     * The arguments of the command
+     */
+    private Vector arguments = new Vector();
+
+    /**
+     * the program to execute
+     */
+    private String executable = null;
+
+    protected static final String DISCLAIMER =
+        StringUtils.LINE_SEP
+        + "The \' characters around the executable and arguments are"
+        + StringUtils.LINE_SEP
+        + "not part of the command."
+        + StringUtils.LINE_SEP;
+
+    /**
+     * Create a command line from a string.
+     * @param toProcess the line: the first element becomes the executable, the rest
+     * the arguments.
+     */
+    public Commandline(String toProcess) {
+        super();
+        String[] tmp = translateCommandline(toProcess);
+        if (tmp != null && tmp.length > 0) {
+            setExecutable(tmp[0]);
+            for (int i = 1; i < tmp.length; i++) {
+                createArgument().setValue(tmp[i]);
+            }
+        }
+    }
+
+    /**
+     *  Create an empty command line.
+     */
+    public Commandline() {
+        super();
+    }
+
+    /**
+     * Used for nested xml command line definitions.
+     */
+    public static class Argument extends ProjectComponent {
+
+        private String[] parts;
+
+        /**
+         * Set a single commandline argument.
+         *
+         * @param value a single commandline argument.
+         */
+        public void setValue(String value) {
+            parts = new String[] {value};
+        }
+
+        /**
+         * Set the line to split into several commandline arguments.
+         *
+         * @param line line to split into several commandline arguments.
+         */
+        public void setLine(String line) {
+            if (line == null) {
+                return;
+            }
+            parts = translateCommandline(line);
+        }
+
+        /**
+         * Set a single commandline argument and treats it like a
+         * PATH--ensuring the right separator for the local platform
+         * is used.
+         *
+         * @param value a single commandline argument.
+         */
+        public void setPath(Path value) {
+            parts = new String[] {value.toString()};
+        }
+
+        /**
+         * Set a single commandline argument from a reference to a
+         * path--ensuring the right separator for the local platform
+         * is used.
+         *
+         * @param value a single commandline argument.
+         */
+        public void setPathref(Reference value) {
+            Path p = new Path(getProject());
+            p.setRefid(value);
+            parts = new String[] {p.toString()};
+        }
+
+        /**
+         * Set a single commandline argument to the absolute filename
+         * of the given file.
+         *
+         * @param value a single commandline argument.
+         */
+        public void setFile(File value) {
+            parts = new String[] {value.getAbsolutePath()};
+        }
+
+        /**
+         * Return the constituent parts of this Argument.
+         * @return an array of strings.
+         */
+        public String[] getParts() {
+            return parts;
+        }
+    }
+
+    /**
+     * Class to keep track of the position of an Argument.
+     <p>This class is there to support the srcfile and targetfile
+     elements of &lt;execon&gt; and &lt;transform&gt; - don't know
+     whether there might be additional use cases.</p> --SB
+     */
+    public class Marker {
+
+        private int position;
+        private int realPos = -1;
+
+        /**
+         * Construct a marker for the specified position.
+         * @param position the position to mark.
+         */
+        Marker(int position) {
+            this.position = position;
+        }
+
+        /**
+         * Return the number of arguments that preceded this marker.
+         *
+         * <p>The name of the executable -- if set -- is counted as the
+         * first argument.</p>
+         * @return the position of this marker.
+         */
+        public int getPosition() {
+            if (realPos == -1) {
+                realPos = (executable == null ? 0 : 1);
+                for (int i = 0; i < position; i++) {
+                    Argument arg = (Argument) arguments.elementAt(i);
+                    realPos += arg.getParts().length;
+                }
+            }
+            return realPos;
+        }
+    }
+
+    /**
+     * Create an argument object.
+     *
+     * <p>Each commandline object has at most one instance of the
+     * argument class.  This method calls
+     * <code>this.createArgument(false)</code>.</p>
+     *
+     * @see #createArgument(boolean)
+     * @return the argument object.
+     */
+    public Argument createArgument() {
+        return this.createArgument(false);
+    }
+
+    /**
+     * Create an argument object and add it to our list of args.
+     *
+     * <p>Each commandline object has at most one instance of the
+     * argument class.</p>
+     *
+     * @param insertAtStart if true, the argument is inserted at the
+     * beginning of the list of args, otherwise it is appended.
+     * @return an argument to be configured
+     */
+    public Argument createArgument(boolean insertAtStart) {
+        Argument argument = new Argument();
+        if (insertAtStart) {
+            arguments.insertElementAt(argument, 0);
+        } else {
+            arguments.addElement(argument);
+        }
+        return argument;
+    }
+
+    /**
+     * Set the executable to run. All file separators in the string
+     * are converted to the platform specific value.
+     * @param executable the String executable name.
+     */
+    public void setExecutable(String executable) {
+        if (executable == null || executable.length() == 0) {
+            return;
+        }
+        this.executable = executable.replace('/', File.separatorChar)
+            .replace('\\', File.separatorChar);
+    }
+
+    /**
+     * Get the executable.
+     * @return the program to run--null if not yet set.
+     */
+    public String getExecutable() {
+        return executable;
+    }
+
+    /**
+     * Append the arguments to the existing command.
+     * @param line an array of arguments to append.
+     */
+    public void addArguments(String[] line) {
+        for (int i = 0; i < line.length; i++) {
+            createArgument().setValue(line[i]);
+        }
+    }
+
+    /**
+     * Return the executable and all defined arguments.
+     * @return the commandline as an array of strings.
+     */
+    public String[] getCommandline() {
+        List commands = new LinkedList();
+        ListIterator list = commands.listIterator();
+        addCommandToList(list);
+        final String[] result = new String[commands.size()];
+        return (String[]) commands.toArray(result);
+    }
+
+    /**
+     * Add the entire command, including (optional) executable to a list.
+     * @param list the list to add to.
+     * @since Ant 1.6
+     */
+    public void addCommandToList(ListIterator list) {
+        if (executable != null) {
+            list.add(executable);
+        }
+        addArgumentsToList(list);
+    }
+
+    /**
+     * Returns all arguments defined by <code>addLine</code>,
+     * <code>addValue</code> or the argument object.
+     * @return the arguments as an array of strings.
+     */
+    public String[] getArguments() {
+        List result = new ArrayList(arguments.size() * 2);
+        addArgumentsToList(result.listIterator());
+        String [] res = new String[result.size()];
+        return (String[]) result.toArray(res);
+    }
+
+    /**
+     * Append all the arguments to the tail of a supplied list.
+     * @param list the list of arguments.
+     * @since Ant 1.6
+     */
+    public void addArgumentsToList(ListIterator list) {
+        for (int i = 0; i < arguments.size(); i++) {
+            Argument arg = (Argument) arguments.elementAt(i);
+            String[] s = arg.getParts();
+            if (s != null) {
+                for (int j = 0; j < s.length; j++) {
+                    list.add(s[j]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the command line as a string.
+     * @return the command line.
+     */
+    public String toString() {
+        return toString(getCommandline());
+    }
+
+    /**
+     * Put quotes around the given String if necessary.
+     *
+     * <p>If the argument doesn't include spaces or quotes, return it
+     * as is. If it contains double quotes, use single quotes - else
+     * surround the argument by double quotes.</p>
+     * @param argument the argument to quote if necessary.
+     * @return the quoted argument.
+     * @exception BuildException if the argument contains both, single
+     *                           and double quotes.
+     */
+    public static String quoteArgument(String argument) {
+        if (argument.indexOf("\"") > -1) {
+            if (argument.indexOf("\'") > -1) {
+                throw new BuildException("Can\'t handle single and double"
+                        + " quotes in same argument");
+            } else {
+                return '\'' + argument + '\'';
+            }
+        } else if (argument.indexOf("\'") > -1
+                   || argument.indexOf(" ") > -1
+                   // WIN9x uses a bat file for executing commands
+                   || (IS_WIN_9X && argument.indexOf(';') != -1)) {
+            return '\"' + argument + '\"';
+        } else {
+            return argument;
+        }
+    }
+
+    /**
+     * Quote the parts of the given array in way that makes them
+     * usable as command line arguments.
+     * @param line the list of arguments to quote.
+     * @return empty string for null or no command, else every argument split
+     * by spaces and quoted by quoting rules.
+     */
+    public static String toString(String[] line) {
+        // empty path return empty string
+        if (line == null || line.length == 0) {
+            return "";
+        }
+        // path containing one or more elements
+        final StringBuffer result = new StringBuffer();
+        for (int i = 0; i < line.length; i++) {
+            if (i > 0) {
+                result.append(' ');
+            }
+            result.append(quoteArgument(line[i]));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Crack a command line.
+     * @param toProcess the command line to process.
+     * @return the command line broken into strings.
+     * An empty or null toProcess parameter results in a zero sized array.
+     */
+    public static String[] translateCommandline(String toProcess) {
+        if (toProcess == null || toProcess.length() == 0) {
+            //no command? no string
+            return new String[0];
+        }
+        // parse with a simple finite state machine
+
+        final int normal = 0;
+        final int inQuote = 1;
+        final int inDoubleQuote = 2;
+        int state = normal;
+        StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
+        Vector v = new Vector();
+        StringBuffer current = new StringBuffer();
+        boolean lastTokenHasBeenQuoted = false;
+
+        while (tok.hasMoreTokens()) {
+            String nextTok = tok.nextToken();
+            switch (state) {
+            case inQuote:
+                if ("\'".equals(nextTok)) {
+                    lastTokenHasBeenQuoted = true;
+                    state = normal;
+                } else {
+                    current.append(nextTok);
+                }
+                break;
+            case inDoubleQuote:
+                if ("\"".equals(nextTok)) {
+                    lastTokenHasBeenQuoted = true;
+                    state = normal;
+                } else {
+                    current.append(nextTok);
+                }
+                break;
+            default:
+                if ("\'".equals(nextTok)) {
+                    state = inQuote;
+                } else if ("\"".equals(nextTok)) {
+                    state = inDoubleQuote;
+                } else if (" ".equals(nextTok)) {
+                    if (lastTokenHasBeenQuoted || current.length() != 0) {
+                        v.addElement(current.toString());
+                        current = new StringBuffer();
+                    }
+                } else {
+                    current.append(nextTok);
+                }
+                lastTokenHasBeenQuoted = false;
+                break;
+            }
+        }
+        if (lastTokenHasBeenQuoted || current.length() != 0) {
+            v.addElement(current.toString());
+        }
+        if (state == inQuote || state == inDoubleQuote) {
+            throw new BuildException("unbalanced quotes in " + toProcess);
+        }
+        String[] args = new String[v.size()];
+        v.copyInto(args);
+        return args;
+    }
+
+    /**
+     * Size operator. This actually creates the command line, so it is not
+     * a zero cost operation.
+     * @return number of elements in the command, including the executable.
+     */
+    public int size() {
+        return getCommandline().length;
+    }
+
+    /**
+     * Generate a deep clone of the contained object.
+     * @return a clone of the contained object
+     */
+    public Object clone() {
+        try {
+            Commandline c = (Commandline) super.clone();
+            c.arguments = (Vector) arguments.clone();
+            return c;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Clear out the whole command line.
+     */
+    public void clear() {
+        executable = null;
+        arguments.removeAllElements();
+    }
+
+    /**
+     * Clear out the arguments but leave the executable in place for
+     * another operation.
+     */
+    public void clearArgs() {
+        arguments.removeAllElements();
+    }
+
+    /**
+     * Return a marker.
+     *
+     * <p>This marker can be used to locate a position on the
+     * commandline--to insert something for example--when all
+     * parameters have been set.</p>
+     * @return a marker
+     */
+    public Marker createMarker() {
+        return new Marker(arguments.size());
+    }
+
+    /**
+     * Return a String that describes the command and arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @return a string that describes the command and arguments.
+     * @since Ant 1.5
+     */
+    public String describeCommand() {
+        return describeCommand(this);
+    }
+
+    /**
+     * Return a String that describes the arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @return a string that describes the arguments.
+     * @since Ant 1.5
+     */
+    public String describeArguments() {
+        return describeArguments(this);
+    }
+
+    /**
+     * Return a String that describes the command and arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @param line the Commandline to describe.
+     * @return a string that describes the command and arguments.
+     * @since Ant 1.5
+     */
+    public static String describeCommand(Commandline line) {
+        return describeCommand(line.getCommandline());
+    }
+
+    /**
+     * Return a String that describes the arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @param line the Commandline whose arguments to describe.
+     * @return a string that describes the arguments.
+     * @since Ant 1.5
+     */
+    public static String describeArguments(Commandline line) {
+        return describeArguments(line.getArguments());
+    }
+
+    /**
+     * Return a String that describes the command and arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     *
+     * <p>This method assumes that the first entry in the array is the
+     * executable to run.</p>
+     * @param args the command line to describe as an array of strings
+     * @return a string that describes the command and arguments.
+     * @since Ant 1.5
+     */
+    public static String describeCommand(String[] args) {
+        if (args == null || args.length == 0) {
+            return "";
+        }
+        StringBuffer buf = new StringBuffer("Executing \'");
+        buf.append(args[0]);
+        buf.append("\'");
+        if (args.length > 1) {
+            buf.append(" with ");
+            buf.append(describeArguments(args, 1));
+        } else {
+            buf.append(DISCLAIMER);
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Return a String that describes the arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @param args the command line to describe as an array of strings.
+     * @return a string that describes the arguments.
+     * @since Ant 1.5
+     */
+    public static String describeArguments(String[] args) {
+        return describeArguments(args, 0);
+    }
+
+    /**
+     * Return a String that describes the arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     *
+     * @param args the command line to describe as an array of strings.
+     * @param offset ignore entries before this index.
+     * @return a string that describes the arguments
+     *
+     * @since Ant 1.5
+     */
+    protected static String describeArguments(String[] args, int offset) {
+        if (args == null || args.length <= offset) {
+            return "";
+        }
+        StringBuffer buf = new StringBuffer("argument");
+        if (args.length > offset) {
+            buf.append("s");
+        }
+        buf.append(":").append(StringUtils.LINE_SEP);
+        for (int i = offset; i < args.length; i++) {
+            buf.append("\'").append(args[i]).append("\'")
+                .append(StringUtils.LINE_SEP);
+        }
+        buf.append(DISCLAIMER);
+        return buf.toString();
+    }
+
+    /**
+     * Get an iterator to the arguments list.
+     * @since Ant 1.7
+     * @return an Iterator.
+     */
+    public Iterator iterator() {
+        return arguments.iterator();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/CommandlineJava.java b/trunk/src/main/org/apache/tools/ant/types/CommandlineJava.java
new file mode 100644
index 0000000..efaa6f4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/CommandlineJava.java
@@ -0,0 +1,699 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+import java.util.Vector;
+
+/**
+ * A representation of a Java command line that is
+ * a composite of 2 <tt>Commandline</tt>s. One is used for the
+ * vm/options and one for the classname/arguments. It provides
+ * specific methods for a Java command line.
+ *
+ */
+public class CommandlineJava implements Cloneable {
+
+    /**
+     * commands to the JVM
+     */
+    private Commandline vmCommand = new Commandline();
+    /**
+     * actual java commands
+     */
+    private Commandline javaCommand = new Commandline();
+    /**
+     * properties to add using -D
+     */
+    private SysProperties sysProperties = new SysProperties();
+    private Path classpath = null;
+    private Path bootclasspath = null;
+    private String vmVersion;
+    private String maxMemory = null;
+    /**
+     *  any assertions to make? Currently only supported in forked JVMs
+     */
+    private Assertions assertions = null;
+
+    /**
+     * Indicate whether it will execute a jar file or not, in this case
+     * the first vm option must be a -jar and the 'executable' is a jar file.
+     */
+     private boolean executeJar = false;
+
+    /**
+     * Whether system properties and bootclasspath shall be cloned.
+     * @since Ant 1.7
+     */
+    private boolean cloneVm = false;
+
+    /**
+     * Specialized Environment class for System properties.
+     */
+    public static class SysProperties extends Environment implements Cloneable {
+        // CheckStyle:VisibilityModifier OFF - bc
+        /** the system properties. */
+        Properties sys = null;
+        // CheckStyle:VisibilityModifier ON
+        private Vector propertySets = new Vector();
+
+        /**
+         * Get the properties as an array; this is an override of the
+         * superclass, as it evaluates all the properties.
+         * @return the array of definitions; may be null.
+         * @throws BuildException on error.
+         */
+        public String[] getVariables() throws BuildException {
+
+            List definitions = new LinkedList();
+            ListIterator list = definitions.listIterator();
+            addDefinitionsToList(list);
+            if (definitions.size() == 0) {
+                return null;
+            } else {
+                return (String[]) definitions.toArray(new String[definitions.size()]);
+            }
+        }
+
+        /**
+         * Add all definitions (including property sets) to a list.
+         * @param listIt list iterator supporting add method.
+         */
+        public void addDefinitionsToList(ListIterator listIt) {
+            String[] props = super.getVariables();
+            if (props != null) {
+                for (int i = 0; i < props.length; i++) {
+                    listIt.add("-D" + props[i]);
+                }
+            }
+            Properties propertySetProperties = mergePropertySets();
+            for (Enumeration e = propertySetProperties.keys();
+                 e.hasMoreElements();) {
+                String key = (String) e.nextElement();
+                String value = propertySetProperties.getProperty(key);
+                listIt.add("-D" + key + "=" + value);
+            }
+        }
+
+        /**
+         * Get the size of the sysproperties instance. This merges all
+         * property sets, so is not an O(1) operation.
+         * @return the size of the sysproperties instance.
+         */
+        public int size() {
+            Properties p = mergePropertySets();
+            return variables.size() + p.size();
+        }
+
+        /**
+         * Cache the system properties and set the system properties to the
+         * new values.
+         * @throws BuildException if Security prevented this operation.
+         */
+        public void setSystem() throws BuildException {
+            try {
+                sys = System.getProperties();
+                Properties p = new Properties();
+                for (Enumeration e = sys.propertyNames(); e.hasMoreElements();) {
+                    String name = (String) e.nextElement();
+                    p.put(name, sys.getProperty(name));
+                }
+                p.putAll(mergePropertySets());
+                for (Enumeration e = variables.elements(); e.hasMoreElements();) {
+                    Environment.Variable v = (Environment.Variable) e.nextElement();
+                    v.validate();
+                    p.put(v.getKey(), v.getValue());
+                }
+                System.setProperties(p);
+            } catch (SecurityException e) {
+                throw new BuildException("Cannot modify system properties", e);
+            }
+        }
+
+        /**
+         * Restore the system properties to the cached value.
+         * @throws BuildException  if Security prevented this operation, or
+         * there were no system properties to restore.
+         */
+        public void restoreSystem() throws BuildException {
+            if (sys == null) {
+                throw new BuildException("Unbalanced nesting of SysProperties");
+            }
+
+            try {
+                System.setProperties(sys);
+                sys = null;
+            } catch (SecurityException e) {
+                throw new BuildException("Cannot modify system properties", e);
+            }
+        }
+
+        /**
+         * Create a deep clone.
+         * @return a cloned instance of SysProperties.
+         * @exception CloneNotSupportedException for signature.
+         */
+        public Object clone() throws CloneNotSupportedException {
+            try {
+                SysProperties c = (SysProperties) super.clone();
+                c.variables = (Vector) variables.clone();
+                c.propertySets = (Vector) propertySets.clone();
+                return c;
+            } catch (CloneNotSupportedException e) {
+                return null;
+            }
+        }
+
+        /**
+         * Add a propertyset to the total set.
+         * @param ps the new property set.
+         */
+        public void addSyspropertyset(PropertySet ps) {
+            propertySets.addElement(ps);
+        }
+
+        /**
+         * Add a propertyset to the total set.
+         * @param ps the new property set.
+         * @since Ant 1.6.3
+         */
+        public void addSysproperties(SysProperties ps) {
+            variables.addAll(ps.variables);
+            propertySets.addAll(ps.propertySets);
+        }
+
+        /**
+         * Merge all property sets into a single Properties object.
+         * @return the merged object.
+         */
+        private Properties mergePropertySets() {
+            Properties p = new Properties();
+            for (Enumeration e = propertySets.elements();
+                 e.hasMoreElements();) {
+                PropertySet ps = (PropertySet) e.nextElement();
+                p.putAll(ps.getProperties());
+            }
+            return p;
+        }
+
+    }
+
+    /**
+     * Constructor uses the VM we are running on now.
+     */
+    public CommandlineJava() {
+        setVm(JavaEnvUtils.getJreExecutable("java"));
+        setVmversion(JavaEnvUtils.getJavaVersion());
+    }
+
+    /**
+     * Create a new argument to the java program.
+     * @return an argument to be configured.
+     */
+    public Commandline.Argument createArgument() {
+        return javaCommand.createArgument();
+    }
+
+    /**
+     * Create a new JVM argument.
+     * @return an argument to be configured.
+     */
+    public Commandline.Argument createVmArgument() {
+        return vmCommand.createArgument();
+    }
+
+    /**
+     * Add a system property.
+     * @param sysp a property to be set in the JVM.
+     */
+    public void addSysproperty(Environment.Variable sysp) {
+        sysProperties.addVariable(sysp);
+    }
+
+    /**
+     * Add a set of system properties.
+     * @param sysp a set of properties.
+     */
+    public void addSyspropertyset(PropertySet sysp) {
+        sysProperties.addSyspropertyset(sysp);
+    }
+
+    /**
+     * Add a set of system properties.
+     * @param sysp a set of properties.
+     * @since Ant 1.6.3
+     */
+    public void addSysproperties(SysProperties sysp) {
+        sysProperties.addSysproperties(sysp);
+    }
+
+    /**
+     * Set the executable used to start the new JVM.
+     * @param vm the executable to use.
+     */
+    public void setVm(String vm) {
+        vmCommand.setExecutable(vm);
+    }
+
+    /**
+     * Set the JVM version required.
+     * @param value the version required.
+     */
+    public void setVmversion(String value) {
+        vmVersion = value;
+    }
+
+    /**
+     * Set whether system properties will be copied to the cloned VM--as
+     * well as the bootclasspath unless you have explicitly specified
+     * a bootclasspath.
+     * @param cloneVm if true copy the system properties.
+     * @since Ant 1.7
+     */
+    public void setCloneVm(boolean cloneVm) {
+        this.cloneVm = cloneVm;
+    }
+
+    /**
+     * Get the current assertions.
+     * @return assertions or null.
+     */
+    public Assertions getAssertions() {
+        return assertions;
+    }
+
+    /**
+     * Add an assertion set to the command.
+     * @param assertions assertions to make.
+     */
+    public void setAssertions(Assertions assertions) {
+        this.assertions = assertions;
+    }
+
+    /**
+     * Set a jar file to execute via the -jar option.
+     * @param jarpathname the pathname of the jar to execute.
+     */
+    public void setJar(String jarpathname) {
+        javaCommand.setExecutable(jarpathname);
+        executeJar = true;
+    }
+
+    /**
+     * Get the name of the jar to be run.
+     * @return the pathname of the jar file to run via -jar option
+     * or <tt>null</tt> if there is no jar to run.
+     * @see #getClassname()
+     */
+    public String getJar() {
+        if (executeJar) {
+            return javaCommand.getExecutable();
+        }
+        return null;
+    }
+
+    /**
+     * Set the classname to execute.
+     * @param classname the fully qualified classname.
+     */
+    public void setClassname(String classname) {
+        javaCommand.setExecutable(classname);
+        executeJar = false;
+    }
+
+    /**
+     * Get the name of the class to be run.
+     * @return the name of the class to run or <tt>null</tt> if there is no class.
+     * @see #getJar()
+     */
+    public String getClassname() {
+        if (!executeJar) {
+            return javaCommand.getExecutable();
+        }
+        return null;
+    }
+
+    /**
+     * Create a classpath.
+     * @param p the project to use to create the path.
+     * @return a path to be configured.
+     */
+    public Path createClasspath(Project p) {
+        if (classpath == null) {
+            classpath = new Path(p);
+        }
+        return classpath;
+    }
+
+    /**
+     * Create a boot classpath.
+     * @param p the project to use to create the path.
+     * @return a path to be configured.
+     * @since Ant 1.6
+     */
+    public Path createBootclasspath(Project p) {
+        if (bootclasspath == null) {
+            bootclasspath = new Path(p);
+        }
+        return bootclasspath;
+    }
+
+    /**
+     * Get the vm version.
+     * @return the vm version.
+     */
+    public String getVmversion() {
+        return vmVersion;
+    }
+
+    /**
+     * Get the command line to run a Java vm.
+     * @return the list of all arguments necessary to run the vm.
+     */
+    public String[] getCommandline() {
+        //create the list
+        List commands = new LinkedList();
+        final ListIterator listIterator = commands.listIterator();
+        //fill it
+        addCommandsToList(listIterator);
+        //convert to an array
+        return (String[]) commands.toArray(new String[commands.size()]);
+    }
+
+    /**
+     * Add all the commands to a list identified by the iterator passed in.
+     * @param listIterator an iterator that supports the add method.
+     * @since Ant 1.6
+     */
+    private void addCommandsToList(final ListIterator listIterator) {
+        //create the command to run Java, including user specified options
+        getActualVMCommand().addCommandToList(listIterator);
+        // properties are part of the vm options...
+        sysProperties.addDefinitionsToList(listIterator);
+
+        if (isCloneVm()) {
+            SysProperties clonedSysProperties = new SysProperties();
+            PropertySet ps = new PropertySet();
+            PropertySet.BuiltinPropertySetName sys =
+                new PropertySet.BuiltinPropertySetName();
+            sys.setValue("system");
+            ps.appendBuiltin(sys);
+            clonedSysProperties.addSyspropertyset(ps);
+            clonedSysProperties.addDefinitionsToList(listIterator);
+        }
+        //boot classpath
+        Path bcp = calculateBootclasspath(true);
+        if (bcp.size() > 0) {
+            listIterator.add("-Xbootclasspath:" + bcp.toString());
+        }
+        //main classpath
+        if (haveClasspath()) {
+            listIterator.add("-classpath");
+            listIterator.add(
+                    classpath.concatSystemClasspath("ignore").toString());
+        }
+        //now any assertions are added
+        if (getAssertions() != null) {
+            getAssertions().applyAssertions(listIterator);
+        }
+        // JDK usage command line says that -jar must be the first option, as there is
+        // a bug in JDK < 1.4 that forces the jvm type to be specified as the first
+        // option, it is appended here as specified in the docs even though there is
+        // in fact no order.
+        if (executeJar) {
+            listIterator.add("-jar");
+        }
+        // this is the classname to run as well as its arguments.
+        // in case of 'executeJar', the executable is a jar file.
+        javaCommand.addCommandToList(listIterator);
+    }
+
+    /**
+     * Specify max memory of the JVM.
+     * -mx or -Xmx depending on VM version.
+     * @param max the string to pass to the jvm to specifiy the max memory.
+     */
+    public void setMaxmemory(String max) {
+        this.maxMemory = max;
+    }
+
+    /**
+     * Get a string description.
+     * @return the command line as a string.
+     */
+    public String toString() {
+        return Commandline.toString(getCommandline());
+    }
+
+    /**
+     * Return a String that describes the command and arguments suitable for
+     * verbose output before a call to <code>Runtime.exec(String[])<code>.
+     * @return the description string.
+     * @since Ant 1.5
+     */
+    public String describeCommand() {
+        return Commandline.describeCommand(getCommandline());
+    }
+
+    /**
+     * Return a String that describes the java command and arguments
+     * for in-VM executions.
+     *
+     * <p>The class name is the executable in this context.</p>
+     * @return the description string.
+     * @since Ant 1.5
+     */
+    public String describeJavaCommand() {
+        return Commandline.describeCommand(getJavaCommand());
+    }
+
+    /**
+     * Get the VM command parameters, including memory settings.
+     * @return the VM command parameters.
+     */
+    protected Commandline getActualVMCommand() {
+        Commandline actualVMCommand = (Commandline) vmCommand.clone();
+        if (maxMemory != null) {
+            if (vmVersion.startsWith("1.1")) {
+                actualVMCommand.createArgument().setValue("-mx" + maxMemory);
+            } else {
+                actualVMCommand.createArgument().setValue("-Xmx" + maxMemory);
+            }
+        }
+        return actualVMCommand;
+    }
+
+    /**
+     * Get the size of the java command line. This is a fairly intensive
+     * operation, as it has to evaluate the size of many components.
+     * @return the total number of arguments in the java command line.
+     * @see #getCommandline()
+     * @deprecated since 1.7.
+     *             Please dont use this, it effectively creates the
+     *             entire command.
+     */
+    public int size() {
+        int size = getActualVMCommand().size() + javaCommand.size()
+            + sysProperties.size();
+        // cloned system properties
+        if (isCloneVm()) {
+            size += System.getProperties().size();
+        }
+        // classpath is "-classpath <classpath>" -> 2 args
+        if (haveClasspath()) {
+            size += 2;
+        }
+        // bootclasspath is "-Xbootclasspath:<classpath>" -> 1 arg
+        if (calculateBootclasspath(true).size() > 0) {
+            size++;
+        }
+        // jar execution requires an additional -jar option
+        if (executeJar) {
+            size++;
+        }
+        //assertions take up space too
+        if (getAssertions() != null) {
+            size += getAssertions().size();
+        }
+        return size;
+    }
+
+    /**
+     * Get the Java command to be used.
+     * @return the java command--not a clone.
+     */
+    public Commandline getJavaCommand() {
+        return javaCommand;
+    }
+
+    /**
+     * Get the VM command, including memory.
+     * @return A deep clone of the instance's VM command, with memory settings added.
+     */
+    public Commandline getVmCommand() {
+        return getActualVMCommand();
+    }
+
+    /**
+     * Get the classpath for the command.
+     * @return the classpath or null.
+     */
+    public Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Get the boot classpath.
+     * @return boot classpath or null.
+     */
+    public Path getBootclasspath() {
+        return bootclasspath;
+    }
+
+    /**
+     * Cache current system properties and set them to those in this
+     * Java command.
+     * @throws BuildException  if Security prevented this operation.
+     */
+    public void setSystemProperties() throws BuildException {
+        sysProperties.setSystem();
+    }
+
+    /**
+     * Restore the cached system properties.
+     * @throws BuildException  if Security prevented this operation, or
+     * there was no system properties to restore
+     */
+    public void restoreSystemProperties() throws BuildException {
+        sysProperties.restoreSystem();
+    }
+
+    /**
+     * Get the system properties object.
+     * @return The system properties object.
+     */
+    public SysProperties getSystemProperties() {
+        return sysProperties;
+    }
+
+    /**
+     * Deep clone the object.
+     * @return a CommandlineJava object.
+     * @throws BuildException if anything went wrong.
+     * @throws CloneNotSupportedException never.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        try {
+            CommandlineJava c = (CommandlineJava) super.clone();
+            c.vmCommand = (Commandline) vmCommand.clone();
+            c.javaCommand = (Commandline) javaCommand.clone();
+            c.sysProperties = (SysProperties) sysProperties.clone();
+            if (classpath != null) {
+                c.classpath = (Path) classpath.clone();
+            }
+            if (bootclasspath != null) {
+                c.bootclasspath = (Path) bootclasspath.clone();
+            }
+            if (assertions != null) {
+                c.assertions = (Assertions) assertions.clone();
+            }
+            return c;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Clear out the java arguments.
+     */
+    public void clearJavaArgs() {
+        javaCommand.clearArgs();
+    }
+
+    /**
+     * Determine whether the classpath has been specified, and whether it shall
+     * really be used or be nulled by build.sysclasspath.
+     * @return true if the classpath is to be used.
+     * @since Ant 1.6
+     */
+    public boolean haveClasspath() {
+        Path fullClasspath = classpath != null
+            ? classpath.concatSystemClasspath("ignore") : null;
+        return fullClasspath != null
+            && fullClasspath.toString().trim().length() > 0;
+    }
+
+    /**
+     * Determine whether the bootclasspath has been specified, and whether it
+     * shall really be used (build.sysclasspath could be set or the VM may not
+     * support it).
+     *
+     * @param log whether to log a warning if a bootclasspath has been
+     * specified but will be ignored.
+     * @return true if the bootclasspath is to be used.
+     * @since Ant 1.6
+     */
+    protected boolean haveBootclasspath(boolean log) {
+        return calculateBootclasspath(log).size() > 0;
+    }
+
+    /**
+     * Calculate the bootclasspath based on the bootclasspath
+     * specified, the build.sysclasspath and ant.build.clonevm magic
+     * properties as well as the cloneVm attribute.
+     * @param log whether to write messages to the log.
+     * @since Ant 1.7
+     */
+    private Path calculateBootclasspath(boolean log) {
+        if (vmVersion.startsWith("1.1")) {
+            if (bootclasspath != null && log) {
+                bootclasspath.log("Ignoring bootclasspath as "
+                                  + "the target VM doesn't support it.");
+            }
+        } else {
+            if (bootclasspath != null) {
+                return bootclasspath.concatSystemBootClasspath(isCloneVm()
+                                                               ? "last"
+                                                               : "ignore");
+            } else if (isCloneVm()) {
+                return Path.systemBootClasspath;
+            }
+        }
+        return new Path(null);
+    }
+
+    /**
+     * Find out whether either of the cloneVm attribute or the magic property
+     * ant.build.clonevm has been set.
+     * @return <code>boolean</code>.
+     * @since 1.7
+     */
+    private boolean isCloneVm() {
+        return cloneVm
+            || "true".equals(System.getProperty("ant.build.clonevm"));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Comparison.java b/trunk/src/main/org/apache/tools/ant/types/Comparison.java
new file mode 100755
index 0000000..a057d0d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Comparison.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.util.Arrays;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * EnumeratedAttribute for generic comparisons.  Accepts values
+ * "equal", "greater", "more", "less", "ne" (not equal),
+ * "ge" (greater or equal), "le" (less or equal), "eq" (equal),
+ * "gt" (greater), "lt" (less).
+ * @since Ant 1.7
+ */
+public class Comparison extends EnumeratedAttribute {
+    private static final String[] VALUES
+        = new String[] {"equal", "greater", "less",
+                        "ne", "ge", "le", "eq", "gt", "lt", "more"};
+
+    /** Equal Comparison. */
+    public static final Comparison EQUAL = new Comparison("equal");
+
+    /** Not-Equal Comparison. */
+    public static final Comparison NOT_EQUAL = new Comparison("ne");
+
+    /** Greater Comparison. */
+    public static final Comparison GREATER = new Comparison("greater");
+
+    /** Less Comparison. */
+    public static final Comparison LESS = new Comparison("less");
+
+    /** Greater-or-Equal Comparison. */
+    public static final Comparison GREATER_EQUAL = new Comparison("ge");
+
+    /** Less-or-Equal Comparison. */
+    public static final Comparison LESS_EQUAL = new Comparison("le");
+
+    private static final int[] EQUAL_INDEX = {0, 4, 5, 6};
+    private static final int[] LESS_INDEX = {2, 3, 5, 8};
+    private static final int[] GREATER_INDEX = {1, 3, 4, 7, 9};
+
+    /**
+     * Default constructor.
+     */
+    public Comparison() {
+    }
+
+    /**
+     * Construct a new Comparison with the specified value.
+     * @param value the EnumeratedAttribute value.
+     */
+    public Comparison(String value) {
+        setValue(value);
+    }
+
+    /**
+     * Return the possible values.
+     * @return String[] of EnumeratedAttribute values.
+     */
+    public String[] getValues() {
+        return VALUES;
+    }
+
+    /**
+     * Evaluate a comparison result as from Comparator.compare() or Comparable.compareTo().
+     * @param comparisonResult the result to evaluate.
+     * @return true if the comparison result fell within the parameters of this Comparison.
+     */
+    public boolean evaluate(int comparisonResult) {
+        if (getIndex() == -1) {
+            throw new BuildException("Comparison value not set.");
+        }
+        int[] i = comparisonResult < 0 ? LESS_INDEX
+            : comparisonResult > 0 ? GREATER_INDEX : EQUAL_INDEX;
+        return Arrays.binarySearch(i, getIndex()) >= 0;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/DTDLocation.java b/trunk/src/main/org/apache/tools/ant/types/DTDLocation.java
new file mode 100644
index 0000000..9fdeee2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/DTDLocation.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+/**
+ * <p>Helper class to handle the DTD nested element.  Instances of
+ * this class correspond to the <code>PUBLIC</code> catalog entry type
+ * of the <a
+ * href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
+ * OASIS "Open Catalog" standard</a>.</p>
+ *
+ * <p>Possible Future Enhancement: Bring the Ant element name into
+ * conformance with the OASIS standard.</p>
+ *
+ * @see org.apache.xml.resolver.Catalog
+ */
+public class DTDLocation extends ResourceLocation {
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/DataType.java b/trunk/src/main/org/apache/tools/ant/types/DataType.java
new file mode 100644
index 0000000..6e79590
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/DataType.java
@@ -0,0 +1,339 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Stack;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.util.IdentityStack;
+
+/**
+ * Base class for those classes that can appear inside the build file
+ * as stand alone data types.
+ *
+ * <p>This class handles the common description attribute and provides
+ * a default implementation for reference handling and checking for
+ * circular references that is appropriate for types that can not be
+ * nested inside elements of the same type (i.e. &lt;patternset&gt;
+ * but not &lt;path&gt;).</p>
+ *
+ */
+public abstract class DataType extends ProjectComponent implements Cloneable {
+    // CheckStyle:VisibilityModifier OFF
+
+    /**
+     * Value to the refid attribute.
+     *
+     * @deprecated since 1.7.
+     *             The user should not be directly referencing
+     *             variable. Please use {@link #getRefid} instead.
+     */
+    protected Reference ref;
+
+    /**
+     * Are we sure we don't hold circular references?
+     *
+     * <p>Subclasses are responsible for setting this value to false
+     * if we'd need to investigate this condition (usually because a
+     * child element has been added that is a subclass of
+     * DataType).</p>
+     *
+     * @deprecated since 1.7.
+     *             The user should not be directly referencing
+     *             variable. Please use {@link #setChecked} or
+     *             {@link #isChecked} instead.
+     */
+    protected boolean checked = true;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Has the refid attribute of this element been set?
+     * @return true if the refid attribute has been set
+     */
+    public boolean isReference() {
+        return ref != null;
+    }
+
+    /**
+     * Set the value of the refid attribute.
+     *
+     * <p>Subclasses may need to check whether any other attributes
+     * have been set as well or child elements have been created and
+     * thus override this method. if they do the must call
+     * <code>super.setRefid</code>.</p>
+     * @param ref the reference to use
+     */
+    public void setRefid(final Reference ref) {
+        this.ref = ref;
+        checked = false;
+    }
+
+    /**
+     * Gets as descriptive as possible a name used for this datatype instance.
+     * @return <code>String</code> name.
+     */
+    protected String getDataTypeName() {
+        return ComponentHelper.getElementName(getProject(), this, true);
+    }
+
+    /**
+     * Convenience method.
+     * @since Ant 1.7
+     */
+    protected void dieOnCircularReference() {
+        dieOnCircularReference(getProject());
+    }
+
+    /**
+     * Convenience method.
+     * @param p the Ant Project instance against which to resolve references.
+     * @since Ant 1.7
+     */
+    protected void dieOnCircularReference(Project p) {
+        if (checked || !isReference()) {
+            return;
+        }
+        dieOnCircularReference(new IdentityStack(this), p);
+    }
+
+    /**
+     * Check to see whether any DataType we hold references to is
+     * included in the Stack (which holds all DataType instances that
+     * directly or indirectly reference this instance, including this
+     * instance itself).
+     *
+     * <p>If one is included, throw a BuildException created by {@link
+     * #circularReference circularReference}.</p>
+     *
+     * <p>This implementation is appropriate only for a DataType that
+     * cannot hold other DataTypes as children.</p>
+     *
+     * <p>The general contract of this method is that it shouldn't do
+     * anything if {@link #checked <code>checked</code>} is true and
+     * set it to true on exit.</p>
+     * @param stack the stack of references to check.
+     * @param project the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected void dieOnCircularReference(final Stack stack,
+                                          final Project project)
+        throws BuildException {
+
+        if (checked || !isReference()) {
+            return;
+        }
+        Object o = ref.getReferencedObject(project);
+
+        if (o instanceof DataType) {
+            IdentityStack id = IdentityStack.getInstance(stack);
+
+            if (id.contains(o)) {
+                throw circularReference();
+            } else {
+                id.push(o);
+                ((DataType) o).dieOnCircularReference(id, project);
+                id.pop();
+            }
+        }
+        checked = true;
+    }
+
+    /**
+     * Allow DataTypes outside org.apache.tools.ant.types to indirectly call
+     * dieOnCircularReference on nested DataTypes.
+     * @param dt the DataType to check.
+     * @param stk the stack of references to check.
+     * @param p the project to use to dereference the references.
+     * @throws BuildException on error.
+     * @since Ant 1.7
+     */
+    public static void invokeCircularReferenceCheck(DataType dt, Stack stk,
+                                                    Project p) {
+        dt.dieOnCircularReference(stk, p);
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced object.
+     * @return the dereferenced object.
+     * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
+     * @since Ant 1.7
+     */
+    protected Object getCheckedRef() {
+        return getCheckedRef(getProject());
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced object.
+     * @param p the Ant Project instance against which to resolve references.
+     * @return the dereferenced object.
+     * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
+     * @since Ant 1.7
+     */
+    protected Object getCheckedRef(Project p) {
+        return getCheckedRef(getClass(), getDataTypeName(), p);
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced object.
+     * @param requiredClass the class that this reference should be a subclass of.
+     * @param dataTypeName  the name of the datatype that the reference should be
+     *                      (error message use only).
+     * @return the dereferenced object.
+     * @throws BuildException if the reference is invalid (circular ref, wrong class, etc).
+     */
+    protected Object getCheckedRef(final Class requiredClass,
+                                   final String dataTypeName) {
+        return getCheckedRef(requiredClass, dataTypeName, getProject());
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced object.  This version allows the fallback Project instance to be specified.
+     * @param requiredClass the class that this reference should be a subclass of.
+     * @param dataTypeName  the name of the datatype that the reference should be
+     *                      (error message use only).
+     * @param project       the fallback Project instance for dereferencing.
+     * @return the dereferenced object.
+     * @throws BuildException if the reference is invalid (circular ref, wrong class, etc),
+     *                        or if <code>project</code> is <code>null</code>.
+     * @since Ant 1.7
+     */
+    protected Object getCheckedRef(final Class requiredClass,
+                                   final String dataTypeName, final Project project) {
+        if (project == null) {
+            throw new BuildException("No Project specified");
+        }
+        dieOnCircularReference(project);
+        Object o = ref.getReferencedObject(project);
+        if (!(requiredClass.isAssignableFrom(o.getClass()))) {
+            log("Class " + o.getClass() + " is not a subclass of " + requiredClass,
+                    Project.MSG_VERBOSE);
+            String msg = ref.getRefId() + " doesn\'t denote a " + dataTypeName;
+            throw new BuildException(msg);
+        }
+        return o;
+    }
+
+    /**
+     * Creates an exception that indicates that refid has to be the
+     * only attribute if it is set.
+     * @return the exception to throw
+     */
+    protected BuildException tooManyAttributes() {
+        return new BuildException("You must not specify more than one "
+            + "attribute when using refid");
+    }
+
+    /**
+     * Creates an exception that indicates that this XML element must
+     * not have child elements if the refid attribute is set.
+     * @return the exception to throw
+     */
+    protected BuildException noChildrenAllowed() {
+        return new BuildException("You must not specify nested elements "
+            + "when using refid");
+    }
+
+    /**
+     * Creates an exception that indicates the user has generated a
+     * loop of data types referencing each other.
+     * @return the exception to throw
+     */
+    protected BuildException circularReference() {
+        return new BuildException("This data type contains a circular "
+            + "reference.");
+    }
+
+    /**
+     * The flag that is used to indicate that circular references have been checked.
+     * @return true if circular references have been checked
+     */
+    protected boolean isChecked() {
+        return checked;
+    }
+
+    /**
+     * Set the flag that is used to indicate that circular references have been checked.
+     * @param checked if true, if circular references have been checked
+     */
+    protected void setChecked(final boolean checked) {
+        this.checked = checked;
+    }
+
+    /**
+     * get the reference set on this object
+     * @return the reference or null
+     */
+    public Reference getRefid() {
+        return ref;
+    }
+
+    /**
+     * check that it is ok to set attributes, i.e that no reference is defined
+     * @since Ant 1.6
+     * @throws BuildException if not allowed
+     */
+    protected void checkAttributesAllowed() {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+    }
+
+    /**
+     * check that it is ok to add children, i.e that no reference is defined
+     * @since Ant 1.6
+     * @throws BuildException if not allowed
+     */
+    protected void checkChildrenAllowed() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+    }
+
+    /**
+     * Basic DataType toString().
+     * @return this DataType formatted as a String.
+     */
+    public String toString() {
+        String d = getDescription();
+        return d == null ? getDataTypeName() : getDataTypeName() + " " + d;
+    }
+
+    /**
+     * @since Ant 1.7
+     * @return a shallow copy of this DataType.
+     * @throws CloneNotSupportedException if there is a problem.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        DataType dt = (DataType) super.clone();
+        dt.setDescription(getDescription());
+        if (getRefid() != null) {
+            dt.setRefid(getRefid());
+        }
+        dt.setChecked(isChecked());
+        return dt;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/Description.java b/trunk/src/main/org/apache/tools/ant/types/Description.java
new file mode 100644
index 0000000..27f9cea
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Description.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.helper.ProjectHelper2;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.UnknownElement;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.helper.ProjectHelperImpl;
+
+import java.util.Vector;
+
+
+/**
+ * Description is used to provide a project-wide description element
+ * (that is, a description that applies to a buildfile as a whole).
+ * If present, the &lt;description&gt; element is printed out before the
+ * target descriptions.
+ *
+ * Description has no attributes, only text.  There can only be one
+ * project description per project.  A second description element will
+ * overwrite the first.
+ *
+ *
+ * @ant.datatype ignore="true"
+ */
+public class Description extends DataType {
+
+    /**
+     * Adds descriptive text to the project.
+     *
+     * @param text the descriptive text
+     */
+    public void addText(String text) {
+
+        ProjectHelper ph = ProjectHelper.getProjectHelper();
+        if (!(ph instanceof ProjectHelperImpl)) {
+            // New behavior for delayed task creation. Description
+            // will be evaluated in Project.getDescription()
+            return;
+        }
+        String currentDescription = getProject().getDescription();
+        if (currentDescription == null) {
+            getProject().setDescription(text);
+        } else {
+            getProject().setDescription(currentDescription + text);
+        }
+    }
+
+    /**
+     * Return the descriptions from all the targets of
+     * a project.
+     *
+     * @param project the project to get the descriptions for.
+     * @return a string containing the concatenated descriptions of
+     *         the targets.
+     */
+    public static String getDescription(Project project) {
+        Vector targets = (Vector) project.getReference(ProjectHelper2.REFID_TARGETS);
+        if (targets == null) {
+            return null;
+        }
+        StringBuffer description = new StringBuffer();
+        for (int i = 0; i < targets.size(); i++) {
+            Target t = (Target) targets.elementAt(i);
+            concatDescriptions(project, t, description);
+        }
+        return description.toString();
+    }
+
+    private static void concatDescriptions(Project project, Target t,
+                                           StringBuffer description) {
+        if (t == null) {
+            return;
+        }
+        Vector tasks = findElementInTarget(project, t, "description");
+        if (tasks == null) {
+            return;
+        }
+        for (int i = 0; i < tasks.size(); i++) {
+            Task task = (Task) tasks.elementAt(i);
+            if (!(task instanceof UnknownElement)) {
+                continue;
+            }
+            UnknownElement ue = ((UnknownElement) task);
+            String descComp = ue.getWrapper().getText().toString();
+            if (descComp != null) {
+                description.append(project.replaceProperties(descComp));
+            }
+        }
+    }
+
+    private static Vector findElementInTarget(Project project,
+                                              Target t, String name) {
+        Task[] tasks = t.getTasks();
+        Vector elems = new Vector();
+        for (int i = 0; i < tasks.length; i++) {
+            if (name.equals(tasks[i].getTaskName())) {
+                elems.addElement(tasks[i]);
+            }
+        }
+        return elems;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/DirSet.java b/trunk/src/main/org/apache/tools/ant/types/DirSet.java
new file mode 100644
index 0000000..447db98
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/DirSet.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Iterator;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+
+/**
+ * Subclass as hint for supporting tasks that the included directories
+ * instead of files should be used.
+ *
+ * @since Ant 1.5
+ */
+public class DirSet extends AbstractFileSet implements ResourceCollection {
+
+    /**
+     * Constructor for DirSet.
+     */
+    public DirSet() {
+        super();
+    }
+
+    /**
+     * Constructor for DirSet, with DirSet to shallowly clone.
+     * @param dirset the dirset to clone.
+     */
+    protected DirSet(DirSet dirset) {
+        super(dirset);
+    }
+
+    /**
+     * Return a DirSet that has the same basedir and same patternsets
+     * as this one.
+     * @return the cloned dirset.
+     */
+    public Object clone() {
+        if (isReference()) {
+            return ((DirSet) getRef(getProject())).clone();
+        } else {
+            return super.clone();
+        }
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        if (isReference()) {
+            return ((DirSet) getRef(getProject())).iterator();
+        }
+        return new FileResourceIterator(getDir(getProject()),
+            getDirectoryScanner(getProject()).getIncludedDirectories());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     * @since Ant 1.7
+     */
+    public int size() {
+        if (isReference()) {
+            return ((DirSet) getRef(getProject())).size();
+        }
+        return getDirectoryScanner(getProject()).getIncludedDirsCount();
+    }
+
+    /**
+     * Always returns true.
+     * @return true indicating that all elements will be FileResources.
+     * @since Ant 1.7
+     */
+    public boolean isFilesystemOnly() {
+        return true;
+    }
+
+    /**
+     * Returns included directories as a list of semicolon-separated paths.
+     *
+     * @return a <code>String</code> of included directories.
+     */
+    public String toString() {
+        DirectoryScanner ds = getDirectoryScanner(getProject());
+        String[] dirs = ds.getIncludedDirectories();
+        StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < dirs.length; i++) {
+            if (i > 0) {
+                sb.append(';');
+            }
+            sb.append(dirs[i]);
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/EnumeratedAttribute.java b/trunk/src/main/org/apache/tools/ant/types/EnumeratedAttribute.java
new file mode 100644
index 0000000..26e794a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/EnumeratedAttribute.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Helper class for attributes that can only take one of a fixed list
+ * of values.
+ *
+ * <p>See {@link org.apache.tools.ant.taskdefs.FixCRLF FixCRLF} for an
+ * example.
+ *
+ */
+public abstract class EnumeratedAttribute {
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * The selected value in this enumeration.
+     */
+    protected String value;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * the index of the selected value in the array.
+     */
+    private int index = -1;
+
+    /**
+     * This is the only method a subclass needs to implement.
+     *
+     * @return an array holding all possible values of the enumeration.
+     * The order of elements must be fixed so that <tt>indexOfValue(String)</tt>
+     * always return the same index for the same value.
+     */
+    public abstract String[] getValues();
+
+    /** bean constructor */
+    protected EnumeratedAttribute() {
+    }
+
+    /**
+     * Factory method for instantiating EAs via API in a more
+     * developer friendly way.
+     * @param clazz             Class, extending EA, which to instantiate
+     * @param value             The value to set on that EA
+     * @return                  Configured EA
+     * @throws BuildException   If the class could not be found or the value
+     *                          is not valid for the given EA-class.
+     * @see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=14831">
+     * http://issues.apache.org/bugzilla/show_bug.cgi?id=14831</a>
+     */
+    public static EnumeratedAttribute getInstance(
+        Class/*<? extends EnumeratedAttribute>*/ clazz,
+        String value) throws BuildException {
+        if (!EnumeratedAttribute.class.isAssignableFrom(clazz)) {
+            throw new BuildException(
+                "You have to provide a subclass from EnumeratedAttribut as clazz-parameter.");
+        }
+        EnumeratedAttribute ea = null;
+        try {
+            ea = (EnumeratedAttribute) clazz.newInstance();
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+        ea.setValue(value);
+        return ea;
+    }
+
+    /**
+     * Invoked by {@link org.apache.tools.ant.IntrospectionHelper IntrospectionHelper}.
+     * @param value the <code>String</code> value of the attribute
+     * @throws BuildException if the value is not valid for the attribute
+     */
+    public final void setValue(String value) throws BuildException {
+        int idx = indexOfValue(value);
+        if (idx == -1) {
+            throw new BuildException(value + " is not a legal value for this attribute");
+        }
+        this.index = idx;
+        this.value = value;
+    }
+
+    /**
+     * Is this value included in the enumeration?
+     * @param value the <code>String</code> value to look up
+     * @return true if the value is valid
+     */
+    public final boolean containsValue(String value) {
+        return (indexOfValue(value) != -1);
+    }
+
+    /**
+     * get the index of a value in this enumeration.
+     * @param value the string value to look for.
+     * @return the index of the value in the array of strings
+     * or -1 if it cannot be found.
+     * @see #getValues()
+     */
+    public final int indexOfValue(String value) {
+        String[] values = getValues();
+        if (values == null || value == null) {
+            return -1;
+        }
+        for (int i = 0; i < values.length; i++) {
+            if (value.equals(values[i])) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * @return the selected value.
+     */
+    public final String getValue() {
+        return value;
+    }
+
+    /**
+     * @return the index of the selected value in the array.
+     * @see #getValues()
+     */
+    public final int getIndex() {
+        return index;
+    }
+
+    /**
+     * Convert the value to its string form.
+     *
+     * @return the string form of the value.
+     */
+    public String toString() {
+        return getValue();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Environment.java b/trunk/src/main/org/apache/tools/ant/types/Environment.java
new file mode 100644
index 0000000..05695b9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Environment.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Wrapper for environment variables.
+ *
+ */
+public class Environment {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * a vector of type Enviromment.Variable
+     * @see Variable
+     */
+    protected Vector variables;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * representation of a single env value
+     */
+    public static class Variable {
+
+        /**
+         * env key and value pair; everything gets expanded to a string
+         * during assignment
+         */
+        private String key, value;
+
+        /**
+         * Constructor for variable
+         *
+         */
+        public Variable() {
+            super();
+        }
+
+        /**
+         * set the key
+         * @param key string
+         */
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        /**
+         * set the value
+         * @param value string value
+         */
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        /**
+         * key accessor
+         * @return key
+         */
+        public String getKey() {
+            return this.key;
+        }
+
+        /**
+         * value accessor
+         * @return value
+         */
+        public String getValue() {
+            return this.value;
+        }
+
+        /**
+         * stringify path and assign to the value.
+         * The value will contain all path elements separated by the appropriate
+         * separator
+         * @param path path
+         */
+        public void setPath(Path path) {
+            this.value = path.toString();
+        }
+
+        /**
+         * get the absolute path of a file and assign it to the value
+         * @param file file to use as the value
+         */
+        public void setFile(java.io.File file) {
+            this.value = file.getAbsolutePath();
+        }
+
+        /**
+         * get the assigment string
+         * This is not ready for insertion into a property file without following
+         * the escaping rules of the properties class.
+         * @return a string of the form key=value.
+         * @throws BuildException if key or value are unassigned
+         */
+        public String getContent() throws BuildException {
+            validate();
+            StringBuffer sb = new StringBuffer(key.trim());
+            sb.append("=").append(value.trim());
+            return sb.toString();
+        }
+
+        /**
+         * checks whether all required attributes have been specified.
+         * @throws BuildException if key or value are unassigned
+         */
+        public void validate() {
+            if (key == null || value == null) {
+                throw new BuildException("key and value must be specified "
+                    + "for environment variables.");
+            }
+        }
+    }
+
+    /**
+     * constructor
+     */
+    public Environment() {
+        variables = new Vector();
+    }
+
+    /**
+     * add a variable.
+     * Validity checking is <i>not</i> performed at this point. Duplicates
+     * are not caught either.
+     * @param var new variable.
+     */
+    public void addVariable(Variable var) {
+        variables.addElement(var);
+    }
+
+    /**
+     * get the variable list as an array
+     * @return array of key=value assignment strings
+     * @throws BuildException if any variable is misconfigured
+     */
+    public String[] getVariables() throws BuildException {
+        if (variables.size() == 0) {
+            return null;
+        }
+        String[] result = new String[variables.size()];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = ((Variable) variables.elementAt(i)).getContent();
+        }
+        return result;
+    }
+
+    /**
+     * Get the raw vector of variables. This is not a clone.
+     * @return a potentially empty (but never null) vector of elements of type
+     * Variable
+     * @since Ant 1.7
+     */
+    public Vector getVariablesVector() {
+        return variables;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/FileList.java b/trunk/src/main/org/apache/tools/ant/types/FileList.java
new file mode 100644
index 0000000..f01636e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FileList.java
@@ -0,0 +1,220 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+
+/**
+ * FileList represents an explicitly named list of files.  FileLists
+ * are useful when you want to capture a list of files regardless of
+ * whether they currently exist.  By contrast, FileSet operates as a
+ * filter, only returning the name of a matched file if it currently
+ * exists in the file system.
+ */
+public class FileList extends DataType implements ResourceCollection {
+
+    private Vector filenames = new Vector();
+    private File dir;
+
+    /**
+     * The default constructor.
+     *
+     */
+    public FileList() {
+        super();
+    }
+
+    /**
+     * A copy constructor.
+     *
+     * @param filelist a <code>FileList</code> value
+     */
+    protected FileList(FileList filelist) {
+        this.dir       = filelist.dir;
+        this.filenames = filelist.filenames;
+        setProject(filelist.getProject());
+    }
+
+    /**
+     * Makes this instance in effect a reference to another FileList
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the reference to another filelist.
+     * @exception BuildException if an error occurs.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if ((dir != null) || (filenames.size() != 0)) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Set the dir attribute.
+     *
+     * @param dir the directory this filelist is relative to.
+     * @exception BuildException if an error occurs
+     */
+    public void setDir(File dir) throws BuildException {
+        checkAttributesAllowed();
+        this.dir = dir;
+    }
+
+    /**
+     * @param p the current project
+     * @return the directory attribute
+     */
+    public File getDir(Project p) {
+        if (isReference()) {
+            return getRef(p).getDir(p);
+        }
+        return dir;
+    }
+
+    /**
+     * Set the filenames attribute.
+     *
+     * @param filenames a string contains filenames, separated by , or
+     *        by whitespace.
+     */
+    public void setFiles(String filenames) {
+        checkAttributesAllowed();
+        if (filenames != null && filenames.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(
+                filenames, ", \t\n\r\f", false);
+            while (tok.hasMoreTokens()) {
+               this.filenames.addElement(tok.nextToken());
+            }
+        }
+    }
+
+    /**
+     * Returns the list of files represented by this FileList.
+     * @param p the current project
+     * @return the list of files represented by this FileList.
+     */
+    public String[] getFiles(Project p) {
+        if (isReference()) {
+            return getRef(p).getFiles(p);
+        }
+
+        if (dir == null) {
+            throw new BuildException("No directory specified for filelist.");
+        }
+
+        if (filenames.size() == 0) {
+            throw new BuildException("No files specified for filelist.");
+        }
+
+        String[] result = new String[filenames.size()];
+        filenames.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced FileList.
+     * @param p the current project
+     * @return the FileList represented by a referenced filelist.
+     */
+    protected FileList getRef(Project p) {
+        return (FileList) getCheckedRef(p);
+    }
+
+    /**
+     * Inner class corresponding to the &lt;file&gt; nested element.
+     */
+    public static class FileName {
+        private String name;
+
+        /**
+         * The name attribute of the file element.
+         *
+         * @param name the name of a file to add to the file list.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * @return the name of the file for this element.
+         */
+        public String getName() {
+            return name;
+        }
+    }
+
+    /**
+     * Add a nested &lt;file&gt; nested element.
+     *
+     * @param name a configured file element with a name.
+     * @since Ant 1.6.2
+     */
+    public void addConfiguredFile(FileName name) {
+        if (name.getName() == null) {
+            throw new BuildException(
+                "No name specified in nested file element");
+        }
+        filenames.addElement(name.getName());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        if (isReference()) {
+            return ((FileList) getRef(getProject())).iterator();
+        }
+        return new FileResourceIterator(dir,
+            (String[]) (filenames.toArray(new String[filenames.size()])));
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     * @since Ant 1.7
+     */
+    public int size() {
+        if (isReference()) {
+            return ((FileList) getRef(getProject())).size();
+        }
+        return filenames.size();
+    }
+
+    /**
+     * Always returns true.
+     * @return true indicating that all elements will be FileResources.
+     * @since Ant 1.7
+     */
+    public boolean isFilesystemOnly() {
+        return true;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/FileSet.java b/trunk/src/main/org/apache/tools/ant/types/FileSet.java
new file mode 100644
index 0000000..443efe4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FileSet.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+
+/**
+ * Moved out of MatchingTask to make it a standalone object that could
+ * be referenced (by scripts for example).
+ *
+ */
+public class FileSet extends AbstractFileSet implements ResourceCollection {
+
+    /**
+     * Constructor for FileSet.
+     */
+    public FileSet() {
+        super();
+    }
+
+    /**
+     * Constructor for FileSet, with FileSet to shallowly clone.
+     * @param fileset the fileset to clone
+     */
+    protected FileSet(FileSet fileset) {
+        super(fileset);
+    }
+
+    /**
+     * Return a FileSet that has the same basedir and same patternsets
+     * as this one.
+     * @return the cloned fileset
+     */
+    public Object clone() {
+        if (isReference()) {
+            return ((FileSet) getRef(getProject())).clone();
+        } else {
+            return super.clone();
+        }
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        if (isReference()) {
+            return ((FileSet) getRef(getProject())).iterator();
+        }
+        return new FileResourceIterator(getDir(getProject()),
+            getDirectoryScanner(getProject()).getIncludedFiles());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     * @since Ant 1.7
+     */
+    public int size() {
+        if (isReference()) {
+            return ((FileSet) getRef(getProject())).size();
+        }
+        return getDirectoryScanner(getProject()).getIncludedFilesCount();
+    }
+
+    /**
+     * Always returns true.
+     * @return true indicating that all elements will be FileResources.
+     * @since Ant 1.7
+     */
+    public boolean isFilesystemOnly() {
+        return true;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/FilterChain.java b/trunk/src/main/org/apache/tools/ant/types/FilterChain.java
new file mode 100644
index 0000000..82999b6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FilterChain.java
@@ -0,0 +1,299 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.filters.ChainableReader;
+import org.apache.tools.ant.filters.ClassConstants;
+import org.apache.tools.ant.filters.EscapeUnicode;
+import org.apache.tools.ant.filters.ExpandProperties;
+import org.apache.tools.ant.filters.HeadFilter;
+import org.apache.tools.ant.filters.LineContains;
+import org.apache.tools.ant.filters.LineContainsRegExp;
+import org.apache.tools.ant.filters.PrefixLines;
+import org.apache.tools.ant.filters.ReplaceTokens;
+import org.apache.tools.ant.filters.StripJavaComments;
+import org.apache.tools.ant.filters.StripLineBreaks;
+import org.apache.tools.ant.filters.StripLineComments;
+import org.apache.tools.ant.filters.TabsToSpaces;
+import org.apache.tools.ant.filters.TailFilter;
+import org.apache.tools.ant.filters.TokenFilter;
+
+
+/**
+ * FilterChain may contain a chained set of filter readers.
+ *
+ */
+public class FilterChain extends DataType
+    implements Cloneable {
+
+    private Vector filterReaders = new Vector();
+
+    /**
+     * Add an AntFilterReader filter.
+     *
+     * @param filterReader an <code>AntFilterReader</code> value
+     */
+    public void addFilterReader(final AntFilterReader filterReader) {
+        filterReaders.addElement(filterReader);
+    }
+
+    /**
+     * Return the filters.
+     *
+     * @return a <code>Vector</code> value containing the filters
+     */
+    public Vector getFilterReaders() {
+        return filterReaders;
+    }
+
+    /**
+     * Add a ClassConstants filter.
+     *
+     * @param classConstants a <code>ClassConstants</code> value
+     */
+    public void addClassConstants(final ClassConstants classConstants) {
+        filterReaders.addElement(classConstants);
+    }
+
+    /**
+     * Add an ExpandProperties filter.
+     *
+     * @param expandProperties an <code>ExpandProperties</code> value
+     */
+    public void addExpandProperties(final ExpandProperties expandProperties) {
+        filterReaders.addElement(expandProperties);
+    }
+
+    /**
+     * Add a HeadFilter filter.
+     *
+     * @param headFilter a <code>HeadFilter</code> value
+     */
+    public void addHeadFilter(final HeadFilter headFilter) {
+        filterReaders.addElement(headFilter);
+    }
+
+    /**
+     * Add a LineContains filter.
+     *
+     * @param lineContains a <code>LineContains</code> value
+     */
+    public void addLineContains(final LineContains lineContains) {
+        filterReaders.addElement(lineContains);
+    }
+
+    /**
+     * Add a LineContainsRegExp filter.
+     *
+     * @param lineContainsRegExp a <code>LineContainsRegExp</code> value
+     */
+    public void addLineContainsRegExp(final LineContainsRegExp
+                                                lineContainsRegExp) {
+        filterReaders.addElement(lineContainsRegExp);
+    }
+
+    /**
+     * Add a PrefixLines filter.
+     *
+     * @param prefixLines a <code>PrefixLines</code> value
+     */
+    public void addPrefixLines(final PrefixLines prefixLines) {
+        filterReaders.addElement(prefixLines);
+    }
+
+    /**
+     * Add a ReplaceTokens filter.
+     *
+     * @param replaceTokens a <code>ReplaceTokens</code> value
+     */
+    public void addReplaceTokens(final ReplaceTokens replaceTokens) {
+        filterReaders.addElement(replaceTokens);
+    }
+
+    /**
+     * Add a StripJavaCommands filter.
+     *
+     * @param stripJavaComments a <code>StripJavaComments</code> value
+     */
+    public void addStripJavaComments(final StripJavaComments
+                                                stripJavaComments) {
+        filterReaders.addElement(stripJavaComments);
+    }
+
+    /**
+     * Add a StripLineBreaks filter.
+     *
+     * @param stripLineBreaks a <code>StripLineBreaks</code> value
+     */
+    public void addStripLineBreaks(final StripLineBreaks
+                                                stripLineBreaks) {
+        filterReaders.addElement(stripLineBreaks);
+    }
+
+    /**
+     * Add a StripLineComments filter.
+     *
+     * @param stripLineComments a <code>StripLineComments</code> value
+     */
+    public void addStripLineComments(final StripLineComments
+                                                stripLineComments) {
+        filterReaders.addElement(stripLineComments);
+    }
+
+    /**
+     * Add a TabsToSpaces filter.
+     *
+     * @param tabsToSpaces a <code>TabsToSpaces</code> value
+     */
+    public void addTabsToSpaces(final TabsToSpaces tabsToSpaces) {
+        filterReaders.addElement(tabsToSpaces);
+    }
+
+    /**
+     * Add a TailFilter filter.
+     *
+     * @param tailFilter a <code>TailFilter</code> value
+     */
+    public void addTailFilter(final TailFilter tailFilter) {
+        filterReaders.addElement(tailFilter);
+    }
+
+    /**
+     * Add an EscapeUnicode filter.
+     *
+     * @param escapeUnicode an <code>EscapeUnicode</code> value
+     * @since Ant 1.6
+     */
+    public void addEscapeUnicode(final EscapeUnicode escapeUnicode) {
+        filterReaders.addElement(escapeUnicode);
+    }
+
+    /**
+     * Add a TokenFilter filter.
+     *
+     * @param tokenFilter a <code>TokenFilter</code> value
+     * @since Ant 1.6
+     */
+    public void addTokenFilter(final TokenFilter tokenFilter) {
+        filterReaders.addElement(tokenFilter);
+    }
+
+    /**
+     * Add a delete characters filter.
+     *
+     * @param filter a <code>TokenFilter.DeleteCharacters</code> value
+     * @since Ant 1.6
+     */
+    public void addDeleteCharacters(TokenFilter.DeleteCharacters filter) {
+        filterReaders.addElement(filter);
+    }
+
+    /**
+     * Add a containsregex filter.
+     *
+     * @param filter a <code>TokenFilter.ContainsRegex</code> value
+     * @since Ant 1.6
+     */
+    public void addContainsRegex(TokenFilter.ContainsRegex filter) {
+        filterReaders.addElement(filter);
+    }
+
+    /**
+     * Add a replaceregex filter.
+     *
+     * @param filter a <code>TokenFilter.ReplaceRegex</code> value
+     */
+    public void addReplaceRegex(TokenFilter.ReplaceRegex filter) {
+        filterReaders.addElement(filter);
+    }
+
+    /**
+     * Add a trim filter.
+     *
+     * @param filter a <code>TokenFilter.Trim</code> value
+     * @since Ant 1.6
+     */
+    public void addTrim(TokenFilter.Trim filter) {
+        filterReaders.addElement(filter);
+    }
+
+    /**
+     * Add a replacestring filter.
+     *
+     * @param filter a <code>TokenFilter.ReplaceString</code> value
+     * @since Ant 1.6
+     */
+    public void addReplaceString(
+        TokenFilter.ReplaceString filter) {
+        filterReaders.addElement(filter);
+    }
+
+    /**
+     * Add an ignoreBlank filter.
+     *
+     * @param filter a <code>TokenFilter.IgnoreBlank</code> value
+     * @since Ant 1.6
+     */
+    public void addIgnoreBlank(
+        TokenFilter.IgnoreBlank filter) {
+        filterReaders.addElement(filter);
+    }
+
+
+    /**
+     * Makes this instance in effect a reference to another FilterChain
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     *
+     * @param r the reference to which this instance is associated
+     * @exception BuildException if this instance already has been configured.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (!filterReaders.isEmpty()) {
+            throw tooManyAttributes();
+        }
+        // change this to get the objects from the other reference
+        Object o = r.getReferencedObject(getProject());
+        if (o instanceof FilterChain) {
+            FilterChain fc = (FilterChain) o;
+            filterReaders = fc.getFilterReaders();
+        } else {
+            String msg = r.getRefId() + " doesn\'t refer to a FilterChain";
+            throw new BuildException(msg);
+        }
+
+        super.setRefid(r);
+    }
+
+    /**
+     * Add a chainfilter filter.
+     *
+     * @param filter a <code>ChainableReader</code> value
+     * @since Ant 1.6
+     */
+
+    public void add(ChainableReader filter) {
+        filterReaders.addElement(filter);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/FilterSet.java b/trunk/src/main/org/apache/tools/ant/types/FilterSet.java
new file mode 100644
index 0000000..592725b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FilterSet.java
@@ -0,0 +1,615 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A set of filters to be applied to something.
+ *
+ * A filter set may have begintoken and endtokens defined.
+ *
+ */
+public class FilterSet extends DataType implements Cloneable {
+
+    /**
+     * Individual filter component of filterset.
+     *
+     */
+    public static class Filter {
+        // CheckStyle:VisibilityModifier OFF - bc
+        /** Token which will be replaced in the filter operation. */
+        String token;
+
+        /** The value which will replace the token in the filtering operation. */
+        String value;
+        // CheckStyle:VisibilityModifier ON
+
+        /**
+         * Constructor for the Filter object.
+         *
+         * @param token  The token which will be replaced when filtering.
+         * @param value  The value which will replace the token when filtering.
+         */
+        public Filter(String token, String value) {
+           setToken(token);
+           setValue(value);
+        }
+
+        /**
+         * No-argument conmstructor.
+         */
+        public Filter() {
+        }
+
+        /**
+         * Sets the Token attribute of the Filter object.
+         *
+         * @param token  The new Token value.
+         */
+        public void setToken(String token) {
+           this.token = token;
+        }
+
+        /**
+         * Sets the Value attribute of the Filter object.
+         *
+         * @param value  The new Value value.
+         */
+        public void setValue(String value) {
+           this.value = value;
+        }
+
+        /**
+         * Gets the Token attribute of the Filter object.
+         *
+         * @return   The Token value.
+         */
+        public String getToken() {
+           return token;
+        }
+
+        /**
+         * Gets the Value attribute of the Filter object.
+         *
+         * @return   The Value value.
+         */
+        public String getValue() {
+           return value;
+        }
+     }
+
+    /**
+     * The filtersfile nested element.
+     *
+     */
+    public class FiltersFile {
+
+        /**
+         * Constructor for the FiltersFile object.
+         */
+        public FiltersFile() {
+        }
+
+        /**
+         * Sets the file from which filters will be read.
+         *
+         * @param file the file from which filters will be read.
+         */
+        public void setFile(File file) {
+           filtersFiles.add(file);
+        }
+    }
+
+    /**
+     * EnumeratedAttribute to set behavior WRT missing filtersfiles:
+     * "fail" (default), "warn", "ignore".
+     * @since Ant 1.7
+     */
+    public static class OnMissing extends EnumeratedAttribute {
+        private static final String[] VALUES
+            = new String[] {"fail", "warn", "ignore"};
+
+        /** Fail value */
+        public static final OnMissing FAIL = new OnMissing("fail");
+        /** Warn value */
+        public static final OnMissing WARN = new OnMissing("warn");
+        /** Ignore value */
+        public static final OnMissing IGNORE = new OnMissing("ignore");
+
+        private static final int FAIL_INDEX = 0;
+        private static final int WARN_INDEX = 1;
+        private static final int IGNORE_INDEX = 2;
+
+        /**
+         * Default constructor.
+         */
+        public OnMissing() {
+        }
+
+        /**
+         * Convenience constructor.
+         * @param value the value to set.
+         */
+        public OnMissing(String value) {
+            setValue(value);
+        }
+
+        //inherit doc
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return VALUES;
+        }
+    }
+
+    /** The default token start string */
+    public static final String DEFAULT_TOKEN_START = "@";
+
+    /** The default token end string */
+    public static final String DEFAULT_TOKEN_END = "@";
+
+    private String startOfToken = DEFAULT_TOKEN_START;
+    private String endOfToken = DEFAULT_TOKEN_END;
+
+    /** Contains a list of parsed tokens */
+    private Vector passedTokens;
+    /** if a duplicate token is found, this is set to true */
+    private boolean duplicateToken = false;
+
+    private boolean recurse = true;
+    private Hashtable filterHash = null;
+    private Vector filtersFiles = new Vector();
+    private OnMissing onMissingFiltersFile = OnMissing.FAIL;
+    private boolean readingFiles = false;
+
+    private int recurseDepth = 0;
+
+    /**
+     * List of ordered filters and filter files.
+     */
+    private Vector filters = new Vector();
+
+    /**
+     * Default constructor.
+     */
+    public FilterSet() {
+    }
+
+    /**
+     * Create a Filterset from another filterset.
+     *
+     * @param filterset the filterset upon which this filterset will be based.
+     */
+    protected FilterSet(FilterSet filterset) {
+        super();
+        this.filters = (Vector) filterset.getFilters().clone();
+    }
+
+    /**
+     * Get the filters in the filter set.
+     *
+     * @return a Vector of Filter instances.
+     */
+    protected synchronized Vector getFilters() {
+        if (isReference()) {
+            return getRef().getFilters();
+        }
+        //silly hack to avoid stack overflow...
+        if (!readingFiles) {
+            readingFiles = true;
+            for (int i = 0, sz = filtersFiles.size(); i < sz; i++) {
+                readFiltersFromFile((File) filtersFiles.get(i));
+            }
+            filtersFiles.clear();
+            readingFiles = false;
+        }
+        return filters;
+    }
+
+    /**
+     * Get the referenced filter set.
+     *
+     * @return the filterset from the reference.
+     */
+    protected FilterSet getRef() {
+        return (FilterSet) getCheckedRef(FilterSet.class, "filterset");
+    }
+
+    /**
+     * Gets the filter hash of the FilterSet.
+     *
+     * @return   The hash of the tokens and values for quick lookup.
+     */
+    public synchronized Hashtable getFilterHash() {
+        if (filterHash == null) {
+            filterHash = new Hashtable(getFilters().size());
+            for (Enumeration e = getFilters().elements(); e.hasMoreElements();) {
+               Filter filter = (Filter) e.nextElement();
+               filterHash.put(filter.getToken(), filter.getValue());
+            }
+        }
+        return filterHash;
+    }
+
+    /**
+     * Set the file containing the filters for this filterset.
+     *
+     * @param filtersFile sets the filter file from which to read filters
+     *        for this filter set.
+     * @throws BuildException if there is an error.
+     */
+    public void setFiltersfile(File filtersFile) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        filtersFiles.add(filtersFile);
+    }
+
+    /**
+     * Set the string used to id the beginning of a token.
+     *
+     * @param startOfToken  The new Begintoken value.
+     */
+    public void setBeginToken(String startOfToken) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (startOfToken == null || "".equals(startOfToken)) {
+            throw new BuildException("beginToken must not be empty");
+        }
+        this.startOfToken = startOfToken;
+    }
+
+    /**
+     * Get the begin token for this filterset.
+     *
+     * @return the filter set's begin token for filtering.
+     */
+    public String getBeginToken() {
+        if (isReference()) {
+            return getRef().getBeginToken();
+        }
+        return startOfToken;
+    }
+
+    /**
+     * Set the string used to id the end of a token.
+     *
+     * @param endOfToken  The new Endtoken value.
+     */
+    public void setEndToken(String endOfToken) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (endOfToken == null || "".equals(endOfToken)) {
+            throw new BuildException("endToken must not be empty");
+        }
+        this.endOfToken = endOfToken;
+    }
+
+    /**
+     * Get the end token for this filterset.
+     *
+     * @return the filter set's end token for replacement delimiting.
+     */
+    public String getEndToken() {
+        if (isReference()) {
+            return getRef().getEndToken();
+        }
+        return endOfToken;
+    }
+
+    /**
+     * Set whether recursive token expansion is enabled.
+     * @param recurse <code>boolean</code> whether to recurse.
+     */
+    public void setRecurse(boolean recurse) {
+        this.recurse = recurse;
+    }
+
+    /**
+     * Get whether recursive token expansion is enabled.
+     * @return <code>boolean</code> whether enabled.
+     */
+    public boolean isRecurse() {
+        return recurse;
+    }
+
+    /**
+     * Read the filters from the given file.
+     *
+     * @param filtersFile        the file from which filters are read.
+     * @exception BuildException when the file cannot be read.
+     */
+    public synchronized void readFiltersFromFile(File filtersFile) throws BuildException {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (!filtersFile.exists()) {
+           handleMissingFile("Could not read filters from file "
+                                     + filtersFile + " as it doesn't exist.");
+        }
+        if (filtersFile.isFile()) {
+           log("Reading filters from " + filtersFile, Project.MSG_VERBOSE);
+           FileInputStream in = null;
+           try {
+              Properties props = new Properties();
+              in = new FileInputStream(filtersFile);
+              props.load(in);
+
+              Enumeration e = props.propertyNames();
+              Vector filts = getFilters();
+              while (e.hasMoreElements()) {
+                 String strPropName = (String) e.nextElement();
+                 String strValue = props.getProperty(strPropName);
+                 filts.addElement(new Filter(strPropName, strValue));
+              }
+           } catch (Exception ex) {
+              throw new BuildException("Could not read filters from file: "
+                  + filtersFile, ex);
+           } finally {
+              FileUtils.close(in);
+           }
+        } else {
+           handleMissingFile(
+               "Must specify a file rather than a directory in "
+               + "the filtersfile attribute:" + filtersFile);
+        }
+        filterHash = null;
+    }
+
+    /**
+     * Does replacement on the given string with token matching.
+     * This uses the defined begintoken and endtoken values which default
+     * to @ for both.
+     * This resets the passedTokens and calls iReplaceTokens to
+     * do the actual replacements.
+     *
+     * @param line  The line in which to process embedded tokens.
+     * @return      The input string after token replacement.
+     */
+    public synchronized String replaceTokens(String line) {
+        return iReplaceTokens(line);
+    }
+
+    /**
+     * Add a new filter.
+     *
+     * @param filter the filter to be added.
+     */
+    public synchronized void addFilter(Filter filter) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        filters.addElement(filter);
+        filterHash = null;
+    }
+
+    /**
+     * Create a new FiltersFile.
+     *
+     * @return The filtersfile that was created.
+     */
+    public FiltersFile createFiltersfile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return new FiltersFile();
+    }
+
+    /**
+     * Add a new filter made from the given token and value.
+     *
+     * @param token The token for the new filter.
+     * @param value The value for the new filter.
+     */
+    public synchronized void addFilter(String token, String value) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        addFilter(new Filter(token, value));
+    }
+
+    /**
+     * Add a Filterset to this filter set.
+     *
+     * @param filterSet the filterset to be added to this filterset
+     */
+    public synchronized void addConfiguredFilterSet(FilterSet filterSet) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) {
+            addFilter((Filter) e.nextElement());
+        }
+    }
+
+    /**
+    * Test to see if this filter set has filters.
+    *
+    * @return Return true if there are filters in this set.
+    */
+    public synchronized boolean hasFilters() {
+        return getFilters().size() > 0;
+    }
+
+    /**
+     * Clone the filterset.
+     *
+     * @return a deep clone of this filterset.
+     *
+     * @throws BuildException if the clone cannot be performed.
+     */
+    public synchronized Object clone() throws BuildException {
+        if (isReference()) {
+            return ((FilterSet) getRef()).clone();
+        }
+        try {
+            FilterSet fs = (FilterSet) super.clone();
+            fs.filters = (Vector) getFilters().clone();
+            fs.setProject(getProject());
+            return fs;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Set the behavior WRT missing filtersfiles.
+     * @param onMissingFiltersFile the OnMissing describing the behavior.
+     */
+    public void setOnMissingFiltersFile(OnMissing onMissingFiltersFile) {
+        this.onMissingFiltersFile = onMissingFiltersFile;
+    }
+
+    /**
+     * Get the onMissingFiltersFile setting.
+     * @return the OnMissing instance.
+     */
+    public OnMissing getOnMissingFiltersFile() {
+        return onMissingFiltersFile;
+    }
+
+    /**
+     * Does replacement on the given string with token matching.
+     * This uses the defined begintoken and endtoken values which default
+     * to @ for both.
+     *
+     * @param line  The line to process the tokens in.
+     * @return      The string with the tokens replaced.
+     */
+    private synchronized String iReplaceTokens(String line) {
+        String beginToken = getBeginToken();
+        String endToken = getEndToken();
+        int index = line.indexOf(beginToken);
+
+        if (index > -1) {
+            Hashtable tokens = getFilterHash();
+            try {
+                StringBuffer b = new StringBuffer();
+                int i = 0;
+                String token = null;
+                String value = null;
+
+                while (index > -1) {
+                    //can't have zero-length token
+                    int endIndex = line.indexOf(endToken,
+                        index + beginToken.length() + 1);
+                    if (endIndex == -1) {
+                        break;
+                    }
+                    token
+                        = line.substring(index + beginToken.length(), endIndex);
+                    b.append(line.substring(i, index));
+                    if (tokens.containsKey(token)) {
+                        value = (String) tokens.get(token);
+                        if (recurse && !value.equals(token)) {
+                            // we have another token, let's parse it.
+                            value = replaceTokens(value, token);
+                        }
+                        log("Replacing: " + beginToken + token + endToken
+                            + " -> " + value, Project.MSG_VERBOSE);
+                        b.append(value);
+                        i = index + beginToken.length() + token.length()
+                            + endToken.length();
+                    } else {
+                        // just append beginToken and search further
+                        b.append(beginToken);
+                        i = index + beginToken.length();
+                    }
+                    index = line.indexOf(beginToken, i);
+                }
+
+                b.append(line.substring(i));
+                return b.toString();
+            } catch (StringIndexOutOfBoundsException e) {
+                return line;
+            }
+        } else {
+           return line;
+        }
+    }
+
+    /**
+     * This parses tokens which point to tokens.
+     * It also maintains a list of currently used tokens, so we cannot
+     * get into an infinite loop.
+     * @param line the value / token to parse.
+     * @param parent the parent token (= the token it was parsed from).
+     */
+    private synchronized String replaceTokens(String line, String parent)
+        throws BuildException {
+        String beginToken = getBeginToken();
+        String endToken = getEndToken();
+        if (recurseDepth == 0) {
+            passedTokens = new Vector();
+        }
+        recurseDepth++;
+        if (passedTokens.contains(parent) && !duplicateToken) {
+            duplicateToken = true;
+            System.out.println(
+                "Infinite loop in tokens. Currently known tokens : "
+                + passedTokens.toString() + "\nProblem token : " + beginToken
+                + parent + endToken + " called from " + beginToken
+                + passedTokens.lastElement().toString() + endToken);
+            recurseDepth--;
+            return parent;
+        }
+        passedTokens.addElement(parent);
+        String value = iReplaceTokens(line);
+        if (value.indexOf(beginToken) == -1 && !duplicateToken
+                && recurseDepth == 1) {
+            passedTokens = null;
+        } else if (duplicateToken) {
+            // should always be the case...
+            if (passedTokens.size() > 0) {
+                value = (String) passedTokens.remove(passedTokens.size() - 1);
+                if (passedTokens.size() == 0) {
+                    value = beginToken + value + endToken;
+                    duplicateToken = false;
+                }
+            }
+        }
+        recurseDepth--;
+        return value;
+    }
+
+    private void handleMissingFile(String message) {
+        switch (onMissingFiltersFile.getIndex()) {
+        case OnMissing.IGNORE_INDEX:
+            return;
+        case OnMissing.FAIL_INDEX:
+            throw new BuildException(message);
+        case OnMissing.WARN_INDEX:
+            log(message, Project.MSG_WARN);
+            return;
+        default:
+            throw new BuildException("Invalid value for onMissingFiltersFile");
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/FilterSetCollection.java b/trunk/src/main/org/apache/tools/ant/types/FilterSetCollection.java
new file mode 100644
index 0000000..1faba68
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FilterSetCollection.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+// java io classes
+
+
+
+
+// java util classes
+import java.util.Enumeration;
+import java.util.Vector;
+
+// ant classes
+
+
+
+
+/**
+ * A FilterSetCollection is a collection of filtersets each of which may have
+ * a different start/end token settings.
+ *
+ */
+public class FilterSetCollection {
+
+    private Vector filterSets = new Vector();
+
+    /**
+     * Constructor for a FilterSetCollection.
+     */
+    public FilterSetCollection() {
+    }
+
+    /**
+     * Constructor for a FilterSetCollection.
+     * @param filterSet a filterset to start the collection with
+     */
+    public FilterSetCollection(FilterSet filterSet) {
+        addFilterSet(filterSet);
+    }
+
+
+    /**
+     * Add a filterset to the collection.
+     *
+     * @param filterSet a <code>FilterSet</code> value
+     */
+    public void addFilterSet(FilterSet filterSet) {
+        filterSets.addElement(filterSet);
+    }
+
+    /**
+     * Does replacement on the given string with token matching.
+     * This uses the defined begintoken and endtoken values which default to @ for both.
+     *
+     * @param line  The line to process the tokens in.
+     * @return      The string with the tokens replaced.
+     */
+    public String replaceTokens(String line) {
+        String replacedLine = line;
+        for (Enumeration e = filterSets.elements(); e.hasMoreElements();) {
+            FilterSet filterSet = (FilterSet) e.nextElement();
+            replacedLine = filterSet.replaceTokens(replacedLine);
+        }
+        return replacedLine;
+    }
+
+    /**
+    * Test to see if this filter set it empty.
+    *
+    * @return   Return true if there are filter in this set otherwise false.
+    */
+    public boolean hasFilters() {
+        for (Enumeration e = filterSets.elements(); e.hasMoreElements();) {
+            FilterSet filterSet = (FilterSet) e.nextElement();
+            if (filterSet.hasFilters()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
+
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/FlexInteger.java b/trunk/src/main/org/apache/tools/ant/types/FlexInteger.java
new file mode 100644
index 0000000..d757429
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/FlexInteger.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+/**
+ * Helper class which can be used for Ant task attribute setter methods to allow
+ * the build file to specify an integer in either decimal, octal, or hexadecimal
+ * format.
+ *
+ * @see java.lang.Integer#decode(String)
+ */
+public class FlexInteger {
+    private Integer value;
+
+    /**
+     * Constructor used by Ant's introspection mechanism for attribute population
+     * @param value the value to decode
+     */
+    public FlexInteger(String value) {
+        this.value = Integer.decode(value);
+    }
+
+    /**
+     * Returns the decimal integer value
+     * @return the integer value
+     */
+    public int intValue() {
+        return value.intValue();
+    }
+
+    /**
+     * Overridden method to return the decimal value for display
+     * @return a string version of the integer
+     */
+    public String toString() {
+        return value.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/LogLevel.java b/trunk/src/main/org/apache/tools/ant/types/LogLevel.java
new file mode 100644
index 0000000..a02b948
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/LogLevel.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * The enumerated values for Ant's log level.
+ */
+public class LogLevel extends EnumeratedAttribute {
+
+    /** ERR loglevel constant. */
+    public static final LogLevel ERR = new LogLevel("error");
+
+    /** WARN loglevel constant. */
+    public static final LogLevel WARN = new LogLevel("warn");
+
+    /** INFO loglevel constant. */
+    public static final LogLevel INFO = new LogLevel("info");
+
+    /** VERBOSE loglevel constant. */
+    public static final LogLevel VERBOSE = new LogLevel("verbose");
+
+    /** DEBUG loglevel constant. */
+    public static final LogLevel DEBUG = new LogLevel("debug");
+
+    /**
+     * Public constructor.
+     */
+    public LogLevel() {
+    }
+
+    private LogLevel(String value) {
+        this();
+        setValue(value);
+    }
+
+    /**
+     * @see EnumeratedAttribute#getValues
+     * @return the strings allowed for the level attribute
+     */
+    public String[] getValues() {
+        return new String[] {
+            "error",
+            "warn",
+            "warning",
+            "info",
+            "verbose",
+            "debug"};
+    }
+
+    /**
+     * mapping of enumerated values to log levels
+     */
+    private static int[] levels = {
+        Project.MSG_ERR,
+        Project.MSG_WARN,
+        Project.MSG_WARN,
+        Project.MSG_INFO,
+        Project.MSG_VERBOSE,
+        Project.MSG_DEBUG
+    };
+
+    /**
+     * get the level of the echo of the current value
+     * @return the level
+     */
+    public int getLevel() {
+        return levels[getIndex()];
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Mapper.java b/trunk/src/main/org/apache/tools/ant/types/Mapper.java
new file mode 100644
index 0000000..8ab3a50
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Mapper.java
@@ -0,0 +1,319 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Properties;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.CompositeMapper;
+import org.apache.tools.ant.util.ContainerMapper;
+
+/**
+ * Element to define a FileNameMapper.
+ *
+ */
+public class Mapper extends DataType implements Cloneable {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    protected MapperType type = null;
+    protected String classname = null;
+    protected Path classpath = null;
+    protected String from = null;
+    protected String to = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+    private ContainerMapper container = null;
+
+    /**
+     * Construct a new <code>Mapper</code> element.
+     * @param p   the owning Ant <code>Project</code>.
+     */
+    public Mapper(Project p) {
+        setProject(p);
+    }
+
+    /**
+     * Set the type of <code>FileNameMapper</code> to use.
+     * @param type   the <code>MapperType</code> enumerated attribute.
+     */
+    public void setType(MapperType type) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.type = type;
+    }
+
+    /**
+     * Cannot mix add and addconfigured in same type, so
+     * provide this to override the add method.
+     * @param fileNameMapper   the <code>FileNameMapper</code> to add.
+     */
+    public void addConfigured(FileNameMapper fileNameMapper) {
+        add(fileNameMapper);
+    }
+
+    /**
+     * Add a nested <code>FileNameMapper</code>.
+     * @param fileNameMapper   the <code>FileNameMapper</code> to add.
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (container == null) {
+            if (type == null && classname == null) {
+                container = new CompositeMapper();
+            } else {
+                FileNameMapper m = getImplementation();
+                if (m instanceof ContainerMapper) {
+                    container = (ContainerMapper) m;
+                } else {
+                    throw new BuildException(String.valueOf(m)
+                        + " mapper implementation does not support nested mappers!");
+                }
+            }
+        }
+        container.add(fileNameMapper);
+    }
+
+    /**
+     * Add a Mapper
+     * @param mapper the mapper to add
+     */
+    public void addConfiguredMapper(Mapper mapper) {
+        add(mapper.getImplementation());
+    }
+
+    /**
+     * Set the class name of the FileNameMapper to use.
+     * @param classname the name of the class
+     */
+    public void setClassname(String classname) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.classname = classname;
+    }
+
+    /**
+     * Set the classpath to load the FileNameMapper through (attribute).
+     * @param classpath the classpath
+     */
+    public void setClasspath(Path classpath) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Set the classpath to load the FileNameMapper through (nested element).
+     * @return a path object to be configured
+     */
+    public Path createClasspath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Set the classpath to load the FileNameMapper through via
+     * reference (attribute).
+     * @param ref the reference to the FileNameMapper
+     */
+    public void setClasspathRef(Reference ref) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        createClasspath().setRefid(ref);
+    }
+
+    /**
+     * Set the argument to FileNameMapper.setFrom
+     * @param from the from attribute to pass to the FileNameMapper
+     */
+    public void setFrom(String from) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.from = from;
+    }
+
+    /**
+     * Set the argument to FileNameMapper.setTo
+     * @param to the to attribute to pass to the FileNameMapper
+     */
+    public void setTo(String to) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.to = to;
+    }
+
+    /**
+     * Make this Mapper instance a reference to another Mapper.
+     *
+     * <p>You must not set any other attribute if you make it a
+     * reference.</p>
+     * @param r the reference to another mapper
+     * @throws BuildException if other attributes are set
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (type != null || from != null || to != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Returns a fully configured FileNameMapper implementation.
+     * @return a FileNameMapper object to be configured
+     * @throws BuildException on error
+     */
+    public FileNameMapper getImplementation() throws BuildException {
+        if (isReference()) {
+            dieOnCircularReference();
+            Reference r = getRefid();
+            Object o = r.getReferencedObject(getProject());
+            if (o instanceof FileNameMapper) {
+                return (FileNameMapper) o;
+            }
+            if (o instanceof Mapper) {
+                return ((Mapper) o).getImplementation();
+            }
+            String od = o == null ? "null" : o.getClass().getName();
+            throw new BuildException(od + " at reference '"
+                + r.getRefId() + "' is not a valid mapper reference.");
+        }
+
+        if (type == null && classname == null && container == null) {
+            throw new BuildException(
+                "nested mapper or "
+                + "one of the attributes type or classname is required");
+        }
+
+        if (container != null) {
+            return container;
+        }
+
+        if (type != null && classname != null) {
+            throw new BuildException(
+                "must not specify both type and classname attribute");
+        }
+
+        try {
+            FileNameMapper m
+                = (FileNameMapper) (getImplementationClass().newInstance());
+            final Project p = getProject();
+            if (p != null) {
+                p.setProjectReference(m);
+            }
+            m.setFrom(from);
+            m.setTo(to);
+
+            return m;
+        } catch (BuildException be) {
+            throw be;
+        } catch (Throwable t) {
+            throw new BuildException(t);
+        }
+    }
+
+     /**
+     * Gets the Class object associated with the mapper implementation.
+     * @return <code>Class</code>.
+     * @throws ClassNotFoundException if the class cannot be found
+     */
+    protected Class getImplementationClass() throws ClassNotFoundException {
+
+        String cName = this.classname;
+        if (type != null) {
+            cName = type.getImplementation();
+        }
+
+        ClassLoader loader = (classpath == null)
+            ? getClass().getClassLoader()
+            : getProject().createClassLoader(classpath);
+
+        return Class.forName(cName, true, loader);
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced Mapper.
+     * @deprecated since Ant 1.7.1 because a mapper might ref a
+     *             FileNameMapper implementation directly.
+     * @return the referenced Mapper
+     */
+    protected Mapper getRef() {
+        return (Mapper) getCheckedRef();
+    }
+
+    /**
+     * Class as Argument to FileNameMapper.setType.
+     */
+    public static class MapperType extends EnumeratedAttribute {
+        private Properties implementations;
+
+        /** Constructor for the MapperType enumeration */
+        public MapperType() {
+            implementations = new Properties();
+            implementations.put("identity",
+                                "org.apache.tools.ant.util.IdentityMapper");
+            implementations.put("flatten",
+                                "org.apache.tools.ant.util.FlatFileNameMapper");
+            implementations.put("glob",
+                                "org.apache.tools.ant.util.GlobPatternMapper");
+            implementations.put("merge",
+                                "org.apache.tools.ant.util.MergingMapper");
+            implementations.put("regexp",
+                                "org.apache.tools.ant.util.RegexpPatternMapper");
+            implementations.put("package",
+                                "org.apache.tools.ant.util.PackageNameMapper");
+            implementations.put("unpackage",
+                                "org.apache.tools.ant.util.UnPackageNameMapper");
+        }
+
+        /**
+         * @return the filenamemapper names
+         */
+        public String[] getValues() {
+            return new String[] {"identity", "flatten", "glob",
+                                 "merge", "regexp", "package", "unpackage"};
+        }
+
+        /**
+         * @return the classname for the filenamemapper name
+         */
+        public String getImplementation() {
+            return implementations.getProperty(getValue());
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Parameter.java b/trunk/src/main/org/apache/tools/ant/types/Parameter.java
new file mode 100644
index 0000000..6c16d2d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Parameter.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+/**
+ * A parameter is composed of a name, type and value.
+ *
+ */
+public final class Parameter {
+    private String name = null;
+    private String type = null;
+    private String value = null;
+
+    /**
+     * Set the name attribute.
+     *
+     * @param name a <code>String</code> value
+     */
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Set the type attribute.
+     *
+     * @param type a <code>String</code> value
+     */
+    public void setType(final String type) {
+        this.type = type;
+    }
+
+    /**
+     * Set the value attribute.
+     *
+     * @param value a <code>String</code> value
+     */
+    public void setValue(final String value) {
+        this.value = value;
+    }
+
+    /**
+     * Get the name attribute.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the type attribute.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Get the value attribute.
+     *
+     * @return a <code>String</code> value
+     */
+    public String getValue() {
+        return value;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Parameterizable.java b/trunk/src/main/org/apache/tools/ant/types/Parameterizable.java
new file mode 100644
index 0000000..ed9ce1f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Parameterizable.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+/**
+ * Parameterizable objects take genric key value pairs.
+ *
+ */
+public interface Parameterizable {
+    /**
+     * Set the parameters
+     *
+     * @param parameters an array of name/type/value parameters.
+     */
+    void setParameters(Parameter[] parameters);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Path.java b/trunk/src/main/org/apache/tools/ant/types/Path.java
new file mode 100644
index 0000000..abf4dce
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Path.java
@@ -0,0 +1,751 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.PathTokenizer;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.FileResourceIterator;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * This object represents a path as used by CLASSPATH or PATH
+ * environment variable. A path might also be described as a collection
+ * of unique filesystem resources.
+ * <p>
+ * <code>
+ * &lt;sometask&gt;<br>
+ * &nbsp;&nbsp;&lt;somepath&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/path/to/file.jar" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement
+ *  path="/path/to/file2.jar:/path/to/class2;/path/to/class3" /&gt;
+ * <br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/path/to/file3.jar" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/path/to/file4.jar" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/somepath&gt;<br>
+ * &lt;/sometask&gt;<br>
+ * </code>
+ * <p>
+ * The object implemention <code>sometask</code> must provide a method called
+ * <code>createSomepath</code> which returns an instance of <code>Path</code>.
+ * Nested path definitions are handled by the Path object and must be labeled
+ * <code>pathelement</code>.<p>
+ *
+ * The path element takes a parameter <code>path</code> which will be parsed
+ * and split into single elements. It will usually be used
+ * to define a path from an environment variable.
+ */
+
+public class Path extends DataType implements Cloneable, ResourceCollection {
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** The system classpath as a Path object */
+    public static Path systemClasspath =
+        new Path(null, System.getProperty("java.class.path"));
+
+
+    /**
+     * The system bootclasspath as a Path object.
+     *
+     * @since Ant 1.6.2
+     */
+    public static Path systemBootClasspath =
+        new Path(null, System.getProperty("sun.boot.class.path"));
+
+    private static final Iterator EMPTY_ITERATOR
+        = Collections.EMPTY_SET.iterator();
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * Helper class, holds the nested <code>&lt;pathelement&gt;</code> values.
+     */
+    public class PathElement implements ResourceCollection {
+        private String[] parts;
+
+        /**
+         * Set the location.
+         *
+         * @param loc a <code>File</code> value
+         */
+        public void setLocation(File loc) {
+            parts = new String[] {translateFile(loc.getAbsolutePath())};
+        }
+
+        /**
+         * Set the path.
+         *
+         * @param path a <code>String</code> value
+         */
+        public void setPath(String path) {
+            parts = Path.translatePath(getProject(), path);
+        }
+
+        /**
+         * Return the converted pathelements.
+         *
+         * @return a <code>String[]</code> value
+         */
+        public String[] getParts() {
+            return parts;
+        }
+
+        /**
+         * Create an iterator.
+         * @return an iterator.
+         */
+        public Iterator iterator() {
+            return new FileResourceIterator(null, parts);
+        }
+
+        /**
+         * Check if this resource is only for filesystems.
+         * @return true.
+         */
+        public boolean isFilesystemOnly() {
+            return true;
+        }
+
+        /**
+         * Get the number of resources.
+         * @return the number of parts.
+         */
+        public int size() {
+            return parts == null ? 0 : parts.length;
+        }
+
+    }
+
+    private Boolean preserveBC;
+
+    private Union union = null;
+
+    /**
+     * Invoked by IntrospectionHelper for <code>setXXX(Path p)</code>
+     * attribute setters.
+     * @param p the <code>Project</code> for this path.
+     * @param path the <code>String</code> path definition.
+     */
+    public Path(Project p, String path) {
+        this(p);
+        createPathElement().setPath(path);
+    }
+
+    /**
+     * Construct an empty <code>Path</code>.
+     * @param project the <code>Project</code> for this path.
+     */
+    public Path(Project project) {
+        setProject(project);
+    }
+
+    /**
+     * Adds a element definition to the path.
+     * @param location the location of the element to add (must not be
+     * <code>null</code> nor empty.
+     * @throws BuildException on error
+     */
+    public void setLocation(File location) throws BuildException {
+        checkAttributesAllowed();
+        createPathElement().setLocation(location);
+    }
+
+    /**
+     * Parses a path definition and creates single PathElements.
+     * @param path the <code>String</code> path definition.
+     * @throws BuildException on error
+     */
+    public void setPath(String path) throws BuildException {
+        checkAttributesAllowed();
+        createPathElement().setPath(path);
+    }
+
+    /**
+     * Makes this instance in effect a reference to another Path instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the reference to another Path
+     * @throws BuildException on error
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (union != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Creates the nested <code>&lt;pathelement&gt;</code> element.
+     * @return the <code>PathElement</code> to be configured
+     * @throws BuildException on error
+     */
+    public PathElement createPathElement() throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        PathElement pe = new PathElement();
+        add(pe);
+        return pe;
+    }
+
+    /**
+     * Adds a nested <code>&lt;fileset&gt;</code> element.
+     * @param fs a <code>FileSet</code> to be added to the path
+     * @throws BuildException on error
+     */
+    public void addFileset(FileSet fs) throws BuildException {
+        if (fs.getProject() == null) {
+            fs.setProject(getProject());
+        }
+        add(fs);
+    }
+
+    /**
+     * Adds a nested <code>&lt;filelist&gt;</code> element.
+     * @param fl a <code>FileList</code> to be added to the path
+     * @throws BuildException on error
+     */
+    public void addFilelist(FileList fl) throws BuildException {
+        if (fl.getProject() == null) {
+            fl.setProject(getProject());
+        }
+        add(fl);
+    }
+
+    /**
+     * Adds a nested <code>&lt;dirset&gt;</code> element.
+     * @param dset a <code>DirSet</code> to be added to the path
+     * @throws BuildException on error
+     */
+    public void addDirset(DirSet dset) throws BuildException {
+        if (dset.getProject() == null) {
+            dset.setProject(getProject());
+        }
+        add(dset);
+    }
+
+    /**
+     * Adds a nested path
+     * @param path a <code>Path</code> to be added to the path
+     * @throws BuildException on error
+     * @since Ant 1.6
+     */
+    public void add(Path path) throws BuildException {
+        if (path == this) {
+            throw circularReference();
+        }
+        if (path.getProject() == null) {
+            path.setProject(getProject());
+        }
+        add((ResourceCollection) path);
+    }
+
+    /**
+     * Add a nested <code>ResourceCollection</code>.
+     * @param c the ResourceCollection to add.
+     * @since Ant 1.7
+     */
+    public void add(ResourceCollection c) {
+        checkChildrenAllowed();
+        if (c == null) {
+            return;
+        }
+        if (union == null) {
+            union = new Union();
+            union.setProject(getProject());
+            union.setCache(false);
+        }
+        union.add(c);
+        setChecked(false);
+    }
+
+    /**
+     * Creates a nested <code>&lt;path&gt;</code> element.
+     * @return a <code>Path</code> to be configured
+     * @throws BuildException on error
+     */
+    public Path createPath() throws BuildException {
+        Path p = new Path(getProject());
+        add(p);
+        return p;
+    }
+
+    /**
+     * Append the contents of the other Path instance to this.
+     * @param other a <code>Path</code> to be added to the path
+     */
+    public void append(Path other) {
+        if (other == null) {
+            return;
+        }
+        add(other);
+    }
+
+    /**
+     * Adds the components on the given path which exist to this
+     * Path. Components that don't exist aren't added.
+     *
+     * @param source - source path whose components are examined for existence
+     */
+     public void addExisting(Path source) {
+         addExisting(source, false);
+     }
+
+    /**
+     * Same as addExisting, but support classpath behavior if tryUserDir
+     * is true. Classpaths are relative to user dir, not the project base.
+     * That used to break jspc test
+     *
+     * @param source the source path
+     * @param tryUserDir  if true try the user directory if the file is not present
+     */
+    public void addExisting(Path source, boolean tryUserDir) {
+        String[] list = source.list();
+        File userDir = (tryUserDir) ? new File(System.getProperty("user.dir"))
+                : null;
+
+        for (int i = 0; i < list.length; i++) {
+            File f = resolveFile(getProject(), list[i]);
+
+            // probably not the best choice, but it solves the problem of
+            // relative paths in CLASSPATH
+            if (tryUserDir && !f.exists()) {
+                f = new File(userDir, list[i]);
+            }
+            if (f.exists()) {
+                setLocation(f);
+            } else {
+                log("dropping " + f + " from path as it doesn't exist",
+                    Project.MSG_VERBOSE);
+            }
+        }
+    }
+
+    /**
+     * Returns all path elements defined by this and nested path objects.
+     * @return list of path elements.
+     */
+    public String[] list() {
+        if (isReference()) {
+            return ((Path) getCheckedRef()).list();
+        }
+        return assertFilesystemOnly(union) == null
+            ? new String[0] : union.list();
+    }
+
+    /**
+     * Returns a textual representation of the path, which can be used as
+     * CLASSPATH or PATH environment variable definition.
+     * @return a textual representation of the path.
+     */
+    public String toString() {
+        return isReference() ? getCheckedRef().toString()
+            : union == null ? "" : union.toString();
+    }
+
+    /**
+     * Splits a PATH (with : or ; as separators) into its parts.
+     * @param project the project to use
+     * @param source a <code>String</code> value
+     * @return an array of strings, one for each path element
+     */
+    public static String[] translatePath(Project project, String source) {
+        final Vector result = new Vector();
+        if (source == null) {
+            return new String[0];
+        }
+        PathTokenizer tok = new PathTokenizer(source);
+        StringBuffer element = new StringBuffer();
+        while (tok.hasMoreTokens()) {
+            String pathElement = tok.nextToken();
+            try {
+                element.append(resolveFile(project, pathElement).getPath());
+            } catch (BuildException e) {
+                project.log("Dropping path element " + pathElement
+                    + " as it is not valid relative to the project",
+                    Project.MSG_VERBOSE);
+            }
+            for (int i = 0; i < element.length(); i++) {
+                translateFileSep(element, i);
+            }
+            result.addElement(element.toString());
+            element = new StringBuffer();
+        }
+        String[] res = new String[result.size()];
+        result.copyInto(res);
+        return res;
+    }
+
+    /**
+     * Returns its argument with all file separator characters
+     * replaced so that they match the local OS conventions.
+     * @param source the path to convert
+     * @return the converted path
+     */
+    public static String translateFile(String source) {
+        if (source == null) {
+          return "";
+        }
+        final StringBuffer result = new StringBuffer(source);
+        for (int i = 0; i < result.length(); i++) {
+            translateFileSep(result, i);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Translates occurrences at a position of / or \ to correct separator of the
+     * current platform and returns whether it had to do a
+     * replacement.
+     * @param buffer a buffer containing a string
+     * @param pos the position in the string buffer to convert
+     * @return true if the character was a / or \
+     */
+    protected static boolean translateFileSep(StringBuffer buffer, int pos) {
+        if (buffer.charAt(pos) == '/' || buffer.charAt(pos) == '\\') {
+            buffer.setCharAt(pos, File.separatorChar);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return ((Path) getCheckedRef()).size();
+        }
+        dieOnCircularReference();
+        return union == null ? 0 : assertFilesystemOnly(union).size();
+    }
+
+    /**
+     * Clone this Path.
+     * @return Path with shallowly cloned Resource children.
+     */
+    public Object clone() {
+        try {
+            Path result = (Path) super.clone();
+            result.union = union == null ? union : (Union) union.clone();
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Overrides the version of DataType to recurse on all DataType
+     * child elements that may have been added.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            if (union != null) {
+                stk.push(union);
+                invokeCircularReferenceCheck(union, stk, p);
+                stk.pop();
+            }
+            setChecked(true);
+        }
+    }
+
+    /**
+     * Resolve a filename with Project's help - if we know one that is.
+     */
+    private static File resolveFile(Project project, String relativeName) {
+        return FileUtils.getFileUtils().resolveFile(
+            (project == null) ? null : project.getBaseDir(), relativeName);
+    }
+
+    /**
+     * Concatenates the system class path in the order specified by
+     * the ${build.sysclasspath} property - using &quot;last&quot; as
+     * default value.
+     * @return the concatenated path
+     */
+    public Path concatSystemClasspath() {
+        return concatSystemClasspath("last");
+    }
+
+    /**
+     * Concatenates the system class path in the order specified by
+     * the ${build.sysclasspath} property - using the supplied value
+     * if ${build.sysclasspath} has not been set.
+     * @param defValue the order ("first", "last", "only")
+     * @return the concatenated path
+     */
+    public Path concatSystemClasspath(String defValue) {
+        return concatSpecialPath(defValue, Path.systemClasspath);
+    }
+
+    /**
+     * Concatenates the system boot class path in the order specified
+     * by the ${build.sysclasspath} property - using the supplied
+     * value if ${build.sysclasspath} has not been set.
+     * @param defValue the order ("first", "last", "only")
+     * @return the concatenated path
+     */
+    public Path concatSystemBootClasspath(String defValue) {
+        return concatSpecialPath(defValue, Path.systemBootClasspath);
+    }
+
+    /**
+     * Concatenates a class path in the order specified by the
+     * ${build.sysclasspath} property - using the supplied value if
+     * ${build.sysclasspath} has not been set.
+     */
+    private Path concatSpecialPath(String defValue, Path p) {
+        Path result = new Path(getProject());
+
+        String order = defValue;
+        if (getProject() != null) {
+            String o = getProject().getProperty("build.sysclasspath");
+            if (o != null) {
+                order = o;
+            }
+        }
+        if (order.equals("only")) {
+            // only: the developer knows what (s)he is doing
+            result.addExisting(p, true);
+
+        } else if (order.equals("first")) {
+            // first: developer could use a little help
+            result.addExisting(p, true);
+            result.addExisting(this);
+
+        } else if (order.equals("ignore")) {
+            // ignore: don't trust anyone
+            result.addExisting(this);
+
+        } else {
+            // last: don't trust the developer
+            if (!order.equals("last")) {
+                log("invalid value for build.sysclasspath: " + order,
+                    Project.MSG_WARN);
+            }
+            result.addExisting(this);
+            result.addExisting(p, true);
+        }
+        return result;
+    }
+
+    /**
+     * Add the Java Runtime classes to this Path instance.
+     */
+    public void addJavaRuntime() {
+        if (JavaEnvUtils.isKaffe()) {
+            // newer versions of Kaffe (1.1.1+) won't have this,
+            // but this will be sorted by FileSet anyway.
+            File kaffeShare = new File(System.getProperty("java.home")
+                                       + File.separator + "share"
+                                       + File.separator + "kaffe");
+            if (kaffeShare.isDirectory()) {
+                FileSet kaffeJarFiles = new FileSet();
+                kaffeJarFiles.setDir(kaffeShare);
+                kaffeJarFiles.setIncludes("*.jar");
+                addFileset(kaffeJarFiles);
+            }
+        } else if ("GNU libgcj".equals(System.getProperty("java.vm.name"))) {
+            addExisting(systemBootClasspath);
+        }
+
+        if (System.getProperty("java.vendor").toLowerCase(Locale.US).indexOf("microsoft") >= 0) {
+            // XXX is this code still necessary? is there any 1.2+ port?
+            // Pull in *.zip from packages directory
+            FileSet msZipFiles = new FileSet();
+            msZipFiles.setDir(new File(System.getProperty("java.home")
+                + File.separator + "Packages"));
+            msZipFiles.setIncludes("*.ZIP");
+            addFileset(msZipFiles);
+        } else {
+            // JDK 1.2+ seems to set java.home to the JRE directory.
+            addExisting(new Path(null,
+                                 System.getProperty("java.home")
+                                 + File.separator + "lib"
+                                 + File.separator + "rt.jar"));
+            // Just keep the old version as well and let addExisting
+            // sort it out.
+            addExisting(new Path(null,
+                                 System.getProperty("java.home")
+                                 + File.separator + "jre"
+                                 + File.separator + "lib"
+                                 + File.separator + "rt.jar"));
+
+            // Sun's and Apple's 1.4 have JCE and JSSE in separate jars.
+            String[] secJars = {"jce", "jsse"};
+            for (int i = 0; i < secJars.length; i++) {
+                addExisting(new Path(null,
+                                     System.getProperty("java.home")
+                                     + File.separator + "lib"
+                                     + File.separator + secJars[i] + ".jar"));
+                addExisting(new Path(null,
+                                     System.getProperty("java.home")
+                                     + File.separator + ".."
+                                     + File.separator + "Classes"
+                                     + File.separator + secJars[i] + ".jar"));
+            }
+
+            // IBM's 1.4 has rt.jar split into 4 smaller jars and a combined
+            // JCE/JSSE in security.jar.
+            String[] ibmJars
+                = {"core", "graphics", "security", "server", "xml"};
+            for (int i = 0; i < ibmJars.length; i++) {
+                addExisting(new Path(null,
+                                     System.getProperty("java.home")
+                                     + File.separator + "lib"
+                                     + File.separator + ibmJars[i] + ".jar"));
+            }
+
+            // Added for MacOS X
+            addExisting(new Path(null,
+                                 System.getProperty("java.home")
+                                 + File.separator + ".."
+                                 + File.separator + "Classes"
+                                 + File.separator + "classes.jar"));
+            addExisting(new Path(null,
+                                 System.getProperty("java.home")
+                                 + File.separator + ".."
+                                 + File.separator + "Classes"
+                                 + File.separator + "ui.jar"));
+        }
+    }
+
+    /**
+     * Emulation of extdirs feature in java >= 1.2.
+     * This method adds all files in the given
+     * directories (but not in sub-directories!) to the classpath,
+     * so that you don't have to specify them all one by one.
+     * @param extdirs - Path to append files to
+     */
+    public void addExtdirs(Path extdirs) {
+        if (extdirs == null) {
+            String extProp = System.getProperty("java.ext.dirs");
+            if (extProp != null) {
+                extdirs = new Path(getProject(), extProp);
+            } else {
+                return;
+            }
+        }
+
+        String[] dirs = extdirs.list();
+        for (int i = 0; i < dirs.length; i++) {
+            File dir = resolveFile(getProject(), dirs[i]);
+            if (dir.exists() && dir.isDirectory()) {
+                FileSet fs = new FileSet();
+                fs.setDir(dir);
+                fs.setIncludes("*");
+                addFileset(fs);
+            }
+        }
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract. The Iterator returned
+     * will throw ConcurrentModificationExceptions if ResourceCollections
+     * are added to this container while the Iterator is in use.
+     * @return a "fail-fast" Iterator.
+     */
+    public final synchronized Iterator iterator() {
+        if (isReference()) {
+            return ((Path) getCheckedRef()).iterator();
+        }
+        dieOnCircularReference();
+        if (getPreserveBC()) {
+            return new FileResourceIterator(null, list());
+        }
+        return union == null ? EMPTY_ITERATOR
+            : assertFilesystemOnly(union).iterator();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    public synchronized boolean isFilesystemOnly() {
+        if (isReference()) {
+            return ((Path) getCheckedRef()).isFilesystemOnly();
+        }
+        dieOnCircularReference();
+        assertFilesystemOnly(union);
+        return true;
+    }
+
+    /**
+     * Verify the specified ResourceCollection is filesystem-only.
+     * @param rc the ResourceCollection to check.
+     * @throws BuildException if <code>rc</code> is not filesystem-only.
+     * @return the passed in ResourceCollection.
+     */
+    protected ResourceCollection assertFilesystemOnly(ResourceCollection rc) {
+        if (rc != null && !(rc.isFilesystemOnly())) {
+            throw new BuildException(getDataTypeName()
+                + " allows only filesystem resources.");
+        }
+        return rc;
+    }
+
+    /**
+     * Helps determine whether to preserve BC by calling <code>list()</code> on subclasses.
+     * The default behavior of this method is to return <code>true</code> for any subclass
+     * that implements <code>list()</code>; this can, of course, be avoided by overriding
+     * this method to return <code>false</code>. It is not expected that the result of this
+     * method should change over time, thus it is called only once.
+     * @return <code>true</code> if <code>iterator()</code> should delegate to <code>list()</code>.
+     */
+    protected boolean delegateIteratorToList() {
+        if (getClass().equals(Path.class)) {
+            return false;
+        }
+        try {
+            Method listMethod = getClass().getMethod("list", (Class[]) null);
+            return !listMethod.getDeclaringClass().equals(Path.class);
+        } catch (Exception e) {
+            //shouldn't happen, but
+            return false;
+        }
+    }
+
+    private synchronized boolean getPreserveBC() {
+        if (preserveBC == null) {
+            preserveBC = delegateIteratorToList() ? Boolean.TRUE : Boolean.FALSE;
+        }
+        return preserveBC.booleanValue();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/PatternSet.java b/trunk/src/main/org/apache/tools/ant/types/PatternSet.java
new file mode 100644
index 0000000..dcf5d57
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/PatternSet.java
@@ -0,0 +1,511 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Named collection of include/exclude tags.
+ *
+ * <p>Moved out of MatchingTask to make it a standalone object that
+ * could be referenced (by scripts for example).
+ *
+ */
+public class PatternSet extends DataType implements Cloneable {
+    private Vector includeList = new Vector();
+    private Vector excludeList = new Vector();
+    private Vector includesFileList = new Vector();
+    private Vector excludesFileList = new Vector();
+
+    /**
+     * inner class to hold a name on list.  "If" and "Unless" attributes
+     * may be used to invalidate the entry based on the existence of a
+     * property (typically set thru the use of the Available task).
+     */
+    public class NameEntry {
+        private String name;
+        private String ifCond;
+        private String unlessCond;
+
+        /**
+         * Sets the name pattern.
+         *
+         * @param name The pattern string.
+         */
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Sets the if attribute. This attribute and the "unless"
+         * attribute are used to validate the name, based in the
+         * existence of the property.
+         *
+         * @param cond A property name. If this property is not
+         *             present, the name is invalid.
+         */
+        public void setIf(String cond) {
+            ifCond = cond;
+        }
+
+        /**
+         * Sets the unless attribute. This attribute and the "if"
+         * attribute are used to validate the name, based in the
+         * existence of the property.
+         *
+         * @param cond A property name. If this property is
+         *             present, the name is invalid.
+         */
+        public void setUnless(String cond) {
+            unlessCond = cond;
+        }
+
+        /**
+         * @return the name attribute.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * This validates the name - checks the if and unless
+         * properties.
+         *
+         * @param p the current project, used to check the presence or
+         *          absence of a property.
+         * @return  the name attribute or null if the "if" or "unless"
+         *          properties are not/are set.
+         */
+        public String evalName(Project p) {
+            return valid(p) ? name : null;
+        }
+
+        private boolean valid(Project p) {
+            if (ifCond != null && p.getProperty(ifCond) == null) {
+                return false;
+            }
+            if (unlessCond != null && p.getProperty(unlessCond) != null) {
+                return false;
+            }
+            return true;
+        }
+
+        /**
+         * @return a printable form of this object.
+         */
+        public String toString() {
+            StringBuffer buf = new StringBuffer();
+            if (name == null) {
+                buf.append("noname");
+            } else {
+                buf.append(name);
+            }
+            if ((ifCond != null) || (unlessCond != null)) {
+                buf.append(":");
+                String connector = "";
+
+                if (ifCond != null) {
+                    buf.append("if->");
+                    buf.append(ifCond);
+                    connector = ";";
+                }
+                if (unlessCond != null) {
+                    buf.append(connector);
+                    buf.append("unless->");
+                    buf.append(unlessCond);
+                }
+            }
+            return buf.toString();
+        }
+    }
+
+    private static final class InvertedPatternSet extends PatternSet {
+        private InvertedPatternSet(PatternSet p) {
+            setProject(p.getProject());
+            addConfiguredPatternset(p);
+        }
+        public String[] getIncludePatterns(Project p) {
+            return super.getExcludePatterns(p);
+        }
+        public String[] getExcludePatterns(Project p) {
+            return super.getIncludePatterns(p);
+        }
+    }
+
+    /**
+     * Creates a new <code>PatternSet</code> instance.
+     */
+    public PatternSet() {
+        super();
+    }
+
+    /**
+     * Makes this instance in effect a reference to another PatternSet
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the reference to another patternset.
+     * @throws BuildException on error.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (!includeList.isEmpty() || !excludeList.isEmpty()) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * This is a patternset nested element.
+     *
+     * @param p a configured patternset nested element.
+     */
+    public void addConfiguredPatternset(PatternSet p) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        String[] nestedIncludes = p.getIncludePatterns(getProject());
+        String[] nestedExcludes = p.getExcludePatterns(getProject());
+
+        if (nestedIncludes != null) {
+            for (int i = 0; i < nestedIncludes.length; i++) {
+                createInclude().setName(nestedIncludes[i]);
+            }
+        }
+        if (nestedExcludes != null) {
+            for (int i = 0; i < nestedExcludes.length; i++) {
+                createExclude().setName(nestedExcludes[i]);
+            }
+        }
+    }
+
+    /**
+     * add a name entry on the include list
+     * @return a nested include element to be configured.
+     */
+    public NameEntry createInclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(includeList);
+    }
+
+    /**
+     * add a name entry on the include files list
+     * @return a nested includesfile element to be configured.
+     */
+    public NameEntry createIncludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(includesFileList);
+    }
+
+    /**
+     * add a name entry on the exclude list
+     * @return a nested exclude element to be configured.
+     */
+    public NameEntry createExclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(excludeList);
+    }
+
+    /**
+     * add a name entry on the exclude files list
+     * @return a nested excludesfile element to be configured.
+     */
+    public NameEntry createExcludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        return addPatternToList(excludesFileList);
+    }
+
+    /**
+     * Appends <code>includes</code> to the current list of include patterns.
+     * Patterns may be separated by a comma or a space.
+     *
+     * @param includes the string containing the include patterns
+     */
+    public void setIncludes(String includes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (includes != null && includes.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(includes, ", ", false);
+            while (tok.hasMoreTokens()) {
+                createInclude().setName(tok.nextToken());
+            }
+        }
+    }
+
+    /**
+     * Appends <code>excludes</code> to the current list of exclude patterns.
+     * Patterns may be separated by a comma or a space.
+     *
+     * @param excludes the string containing the exclude patterns
+     */
+    public void setExcludes(String excludes) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (excludes != null && excludes.length() > 0) {
+            StringTokenizer tok = new StringTokenizer(excludes, ", ", false);
+            while (tok.hasMoreTokens()) {
+                createExclude().setName(tok.nextToken());
+            }
+        }
+    }
+
+    /**
+     * add a name entry to the given list
+     */
+    private NameEntry addPatternToList(Vector list) {
+        NameEntry result = new NameEntry();
+        list.addElement(result);
+        return result;
+    }
+
+    /**
+     * Sets the name of the file containing the includes patterns.
+     *
+     * @param includesFile The file to fetch the include patterns from.
+     * @throws BuildException on error.
+     */
+     public void setIncludesfile(File includesFile) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+         createIncludesFile().setName(includesFile.getAbsolutePath());
+     }
+
+    /**
+     * Sets the name of the file containing the excludes patterns.
+     *
+     * @param excludesFile The file to fetch the exclude patterns from.
+     * @throws BuildException on error.
+     */
+     public void setExcludesfile(File excludesFile) throws BuildException {
+         if (isReference()) {
+             throw tooManyAttributes();
+         }
+         createExcludesFile().setName(excludesFile.getAbsolutePath());
+     }
+
+    /**
+     *  Reads path matching patterns from a file and adds them to the
+     *  includes or excludes list (as appropriate).
+     */
+    private void readPatterns(File patternfile, Vector patternlist, Project p)
+            throws BuildException {
+
+        BufferedReader patternReader = null;
+        try {
+            // Get a FileReader
+            patternReader = new BufferedReader(new FileReader(patternfile));
+
+            // Create one NameEntry in the appropriate pattern list for each
+            // line in the file.
+            String line = patternReader.readLine();
+            while (line != null) {
+                if (line.length() > 0) {
+                    line = p.replaceProperties(line);
+                    addPatternToList(patternlist).setName(line);
+                }
+                line = patternReader.readLine();
+            }
+        } catch (IOException ioe)  {
+            throw new BuildException("An error occurred while reading from pattern file: "
+                    + patternfile, ioe);
+        } finally {
+            FileUtils.close(patternReader);
+        }
+    }
+
+    /**
+     * Adds the patterns of the other instance to this set.
+     * @param other the other PatternSet instance.
+     * @param p the current project.
+     */
+    public void append(PatternSet other, Project p) {
+        if (isReference()) {
+            throw new BuildException("Cannot append to a reference");
+        }
+        String[] incl = other.getIncludePatterns(p);
+        if (incl != null) {
+            for (int i = 0; i < incl.length; i++) {
+                createInclude().setName(incl[i]);
+            }
+        }
+        String[] excl = other.getExcludePatterns(p);
+        if (excl != null) {
+            for (int i = 0; i < excl.length; i++) {
+                createExclude().setName(excl[i]);
+            }
+        }
+    }
+
+    /**
+     * Returns the filtered include patterns.
+     * @param p the current project.
+     * @return the filtered included patterns.
+     */
+    public String[] getIncludePatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).getIncludePatterns(p);
+        }
+        readFiles(p);
+        return makeArray(includeList, p);
+    }
+
+    /**
+     * Returns the filtered include patterns.
+     * @param p the current project.
+     * @return the filtered excluded patterns.
+     */
+    public String[] getExcludePatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).getExcludePatterns(p);
+        }
+        readFiles(p);
+        return makeArray(excludeList, p);
+    }
+
+    /**
+     * Helper for FileSet classes.
+     * Check if there are patterns defined.
+     * @param p the current project.
+     * @return true if there are patterns.
+     */
+    public boolean hasPatterns(Project p) {
+        if (isReference()) {
+            return getRef(p).hasPatterns(p);
+        }
+        return includesFileList.size() > 0 || excludesFileList.size() > 0
+                || includeList.size() > 0 || excludeList.size() > 0;
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced PatternSet.
+     */
+    private PatternSet getRef(Project p) {
+        return (PatternSet) getCheckedRef(p);
+    }
+
+    /**
+     * Convert a vector of NameEntry elements into an array of Strings.
+     */
+    private String[] makeArray(Vector list, Project p) {
+        if (list.size() == 0) {
+            return null;
+        }
+        Vector tmpNames = new Vector();
+        for (Enumeration e = list.elements(); e.hasMoreElements();) {
+            NameEntry ne = (NameEntry) e.nextElement();
+            String pattern = ne.evalName(p);
+            if (pattern != null && pattern.length() > 0) {
+                tmpNames.addElement(pattern);
+            }
+        }
+        String[] result = new String[tmpNames.size()];
+        tmpNames.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Read includesfile ot excludesfile if not already done so.
+     */
+    private void readFiles(Project p) {
+        if (includesFileList.size() > 0) {
+            Enumeration e = includesFileList.elements();
+            while (e.hasMoreElements()) {
+                NameEntry ne = (NameEntry) e.nextElement();
+                String fileName = ne.evalName(p);
+                if (fileName != null) {
+                    File inclFile = p.resolveFile(fileName);
+                    if (!inclFile.exists()) {
+                        throw new BuildException("Includesfile " + inclFile.getAbsolutePath()
+                                + " not found.");
+                    }
+                    readPatterns(inclFile, includeList, p);
+                }
+            }
+            includesFileList.removeAllElements();
+        }
+        if (excludesFileList.size() > 0) {
+            Enumeration e = excludesFileList.elements();
+            while (e.hasMoreElements()) {
+                NameEntry ne = (NameEntry) e.nextElement();
+                String fileName = ne.evalName(p);
+                if (fileName != null) {
+                    File exclFile = p.resolveFile(fileName);
+                    if (!exclFile.exists()) {
+                        throw new BuildException("Excludesfile " + exclFile.getAbsolutePath()
+                                + " not found.");
+                    }
+                    readPatterns(exclFile, excludeList, p);
+                }
+            }
+            excludesFileList.removeAllElements();
+        }
+    }
+
+    /**
+     * @return a printable form of this object.
+     */
+    public String toString() {
+        return "patternSet{ includes: " + includeList + " excludes: " + excludeList + " }";
+    }
+
+    /**
+     * @since Ant 1.6
+     * @return a clone of this patternset.
+     */
+    public Object clone() {
+        try {
+            PatternSet ps = (PatternSet) super.clone();
+            ps.includeList = (Vector) includeList.clone();
+            ps.excludeList = (Vector) excludeList.clone();
+            ps.includesFileList = (Vector) includesFileList.clone();
+            ps.excludesFileList = (Vector) excludesFileList.clone();
+            return ps;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Add an inverted patternset.
+     * @param p the pattern to invert and add.
+     */
+    public void addConfiguredInvert(PatternSet p) {
+        addConfiguredPatternset(new InvertedPatternSet(p));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Permissions.java b/trunk/src/main/org/apache/tools/ant/types/Permissions.java
new file mode 100644
index 0000000..ca25b08
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Permissions.java
@@ -0,0 +1,357 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.lang.reflect.Constructor;
+import java.security.UnresolvedPermission;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ExitException;
+
+/**
+ * This class implements a security manager meant for usage by tasks that run inside the
+ * Ant VM. An examples are the Java Task and JUnitTask.
+ *
+ * The basic functionality is that nothing (except for a base set of permissions) is allowed, unless
+ * the permission is granted either explicitly or implicitly.
+ * If a permission is granted this can be overruled by explicitly revoking the permission.
+ *
+ * It is not permissible to add permissions (either granted or revoked) while the Security Manager
+ * is active (after calling setSecurityManager() but before calling restoreSecurityManager()).
+ *
+ * @since Ant 1.6
+ */
+public class Permissions {
+
+    private List grantedPermissions = new LinkedList();
+    private List revokedPermissions = new LinkedList();
+    private java.security.Permissions granted = null;
+    private SecurityManager origSm = null;
+    private boolean active = false;
+    private boolean delegateToOldSM;
+
+    // Mandatory constructor for permission object.
+    private static final Class[] PARAMS = {String.class, String.class};
+
+    /**
+     * Create a set of Permissions.  Equivalent to calling
+     * <code>new Permissions(false)</code>.
+     */
+    public Permissions() {
+        this(false);
+    }
+
+    /**
+     * Create a set of permissions.
+     * @param delegateToOldSM  if <code>true</code> the old security manager
+     * will be used if the permission has not been explicitly granted or revoked
+     * in this instance.
+     */
+    public Permissions(boolean delegateToOldSM) {
+        this.delegateToOldSM = delegateToOldSM;
+    }
+
+    /**
+     * Adds a permission to be granted.
+     * @param perm The Permissions.Permission to be granted.
+     */
+    public void addConfiguredGrant(Permissions.Permission perm) {
+        grantedPermissions.add(perm);
+    }
+
+    /**
+     * Adds a permission to be revoked.
+     * @param perm The Permissions.Permission to be revoked
+     */
+    public void addConfiguredRevoke(Permissions.Permission perm) {
+        revokedPermissions.add(perm);
+    }
+
+    /**
+     * To be used by tasks wishing to use this security model before executing the part to be
+     * subject to these Permissions. Note that setting the SecurityManager too early may
+     * prevent your part from starting, as for instance changing classloaders may be prohibited.
+     * The classloader for the new situation is supposed to be present.
+     * @throws BuildException on error
+     */
+    public synchronized void setSecurityManager() throws BuildException {
+        origSm = System.getSecurityManager();
+        init();
+        System.setSecurityManager(new MySM());
+        active = true;
+    }
+
+    /**
+     * Initializes the list of granted permissions, checks the list of revoked permissions.
+     */
+    private void init() throws BuildException {
+        granted = new java.security.Permissions();
+        for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) {
+            Permissions.Permission p = (Permissions.Permission) i.next();
+            if (p.getClassName() == null) {
+                throw new BuildException("Revoked permission " + p + " does not contain a class.");
+            }
+        }
+        for (Iterator i = grantedPermissions.listIterator(); i.hasNext();) {
+            Permissions.Permission p = (Permissions.Permission) i.next();
+            if (p.getClassName() == null) {
+                throw new BuildException("Granted permission " + p
+                        + " does not contain a class.");
+            } else {
+                java.security.Permission perm = createPermission(p);
+                granted.add(perm);
+            }
+        }
+        // Add base set of permissions
+        granted.add(new java.net.SocketPermission("localhost:1024-", "listen"));
+        granted.add(new java.util.PropertyPermission("java.version", "read"));
+        granted.add(new java.util.PropertyPermission("java.vendor", "read"));
+        granted.add(new java.util.PropertyPermission("java.vendor.url", "read"));
+        granted.add(new java.util.PropertyPermission("java.class.version", "read"));
+        granted.add(new java.util.PropertyPermission("os.name", "read"));
+        granted.add(new java.util.PropertyPermission("os.version", "read"));
+        granted.add(new java.util.PropertyPermission("os.arch", "read"));
+        granted.add(new java.util.PropertyPermission("file.encoding", "read"));
+        granted.add(new java.util.PropertyPermission("file.separator", "read"));
+        granted.add(new java.util.PropertyPermission("path.separator", "read"));
+        granted.add(new java.util.PropertyPermission("line.separator", "read"));
+        granted.add(new java.util.PropertyPermission("java.specification.version", "read"));
+        granted.add(new java.util.PropertyPermission("java.specification.vendor", "read"));
+        granted.add(new java.util.PropertyPermission("java.specification.name", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.specification.version", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.specification.vendor", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.specification.name", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.version", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.vendor", "read"));
+        granted.add(new java.util.PropertyPermission("java.vm.name", "read"));
+    }
+
+    private java.security.Permission createPermission(
+            Permissions.Permission permission) {
+        try {
+            // First add explicitly already resolved permissions will not be
+            // resolved when added as unresolved permission.
+            Class clazz = Class.forName(permission.getClassName());
+            String name = permission.getName();
+            String actions = permission.getActions();
+            Constructor ctr = clazz.getConstructor(PARAMS);
+            return (java.security.Permission) ctr.newInstance(new Object[] {
+                    name, actions });
+        } catch (Exception e) {
+            // Let the UnresolvedPermission handle it.
+            return new UnresolvedPermission(permission.getClassName(),
+                    permission.getName(), permission.getActions(), null);
+        }
+    }
+
+    /**
+     * To be used by tasks that just finished executing the parts subject to these permissions.
+     */
+    public synchronized void restoreSecurityManager() {
+        active = false;
+        System.setSecurityManager(origSm);
+    }
+
+    /**
+     * This inner class implements the actual SecurityManager that can be used by tasks
+     * supporting Permissions.
+     */
+    private class MySM extends SecurityManager {
+
+        /**
+         * Exit is treated in a special way in order to be able to return the exit code
+         * towards tasks.
+         * An ExitException is thrown instead of a simple SecurityException to indicate the exit
+         * code.
+         * Overridden from java.lang.SecurityManager
+         * @param status The exit status requested.
+         */
+        public void checkExit(int status) {
+            java.security.Permission perm = new java.lang.RuntimePermission("exitVM", null);
+            try {
+                checkPermission(perm);
+            } catch (SecurityException e) {
+                throw new ExitException(e.getMessage(), status);
+            }
+        }
+
+        /**
+         * The central point in checking permissions.
+         * Overridden from java.lang.SecurityManager
+         *
+         * @param perm The permission requested.
+         */
+        public void checkPermission(java.security.Permission perm) {
+            if (active) {
+                if (delegateToOldSM && !perm.getName().equals("exitVM")) {
+                    boolean permOK = false;
+                    if (granted.implies(perm)) {
+                        permOK = true;
+                    }
+                    checkRevoked(perm);
+                    /*
+                     if the permission was not explicitly granted or revoked
+                     the original security manager will do its work
+                    */
+                    if (!permOK && origSm != null) {
+                        origSm.checkPermission(perm);
+                    }
+                }  else {
+                    if (!granted.implies(perm)) {
+                        throw new SecurityException("Permission " + perm + " was not granted.");
+                    }
+                    checkRevoked(perm);
+                }
+            }
+        }
+
+        /**
+         * throws an exception if this permission is revoked
+         * @param perm the permission being checked
+         */
+        private void checkRevoked(java.security.Permission perm) {
+            for (Iterator i = revokedPermissions.listIterator(); i.hasNext();) {
+                if (((Permissions.Permission) i.next()).matches(perm)) {
+                    throw new SecurityException("Permission " + perm + " was revoked.");
+                }
+            }
+
+        }
+    }
+
+    /** Represents a permission. */
+    public static class Permission {
+        private String className;
+        private String name;
+        private String actionString;
+        private Set actions;
+
+        /**
+         * Set the class, mandatory.
+         * @param aClass The class name of the permission.
+         */
+        public void setClass(String aClass) {
+                className = aClass.trim();
+        }
+
+        /**
+         * Get the class of the permission.
+         * @return The class name of the permission.
+         */
+        public String getClassName() {
+            return className;
+        }
+
+        /**
+         * Set the name of the permission.
+         * @param aName The name of the permission.
+         */
+        public void setName(String aName) {
+            name = aName.trim();
+        }
+
+        /**
+         * Get the name of the permission.
+         * @return The name of the permission.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Set the actions.
+         * @param actions The actions of the permission.
+         */
+        public void setActions(String actions) {
+            actionString = actions;
+            if (actions.length() > 0) {
+                this.actions = parseActions(actions);
+            }
+        }
+
+        /**
+         * Get the actions.
+         * @return The actions of the permission.
+         */
+        public String getActions() {
+            return actionString;
+        }
+
+        /**
+         * Learn whether the permission matches in case of a revoked permission.
+         * @param perm The permission to check against.
+         */
+        boolean matches(java.security.Permission perm) {
+            if (!className.equals(perm.getClass().getName())) {
+                return false;
+            }
+            if (name != null) {
+                if (name.endsWith("*")) {
+                    if (!perm.getName().startsWith(name.substring(0, name.length() - 1))) {
+                        return false;
+                    }
+                } else {
+                    if (!name.equals(perm.getName())) {
+                        return false;
+                    }
+                }
+            }
+            if (actions != null) {
+                Set as = parseActions(perm.getActions());
+                int size = as.size();
+                as.removeAll(actions);
+                if (as.size() == size) {
+                    // None of the actions revoked, so all allowed.
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Parses the actions into a set of separate strings.
+         * @param actions The actions to be parsed.
+         */
+        private Set parseActions(String actions) {
+            Set result = new HashSet();
+            StringTokenizer tk = new StringTokenizer(actions, ",");
+            while (tk.hasMoreTokens()) {
+                String item = tk.nextToken().trim();
+                if (!item.equals("")) {
+                    result.add(item);
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Get a string description of the permissions.
+         * @return string description of the permissions.
+         */
+        public String toString() {
+            return ("Permission: " + className + " (\"" + name + "\", \"" + actions + "\")");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/PropertySet.java b/trunk/src/main/org/apache/tools/ant/types/PropertySet.java
new file mode 100644
index 0000000..c397760
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/PropertySet.java
@@ -0,0 +1,506 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.resources.PropertyResource;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+
+/**
+ * A set of properties.
+ *
+ * @since Ant 1.6
+ */
+public class PropertySet extends DataType implements ResourceCollection {
+
+    private boolean dynamic = true;
+    private boolean negate = false;
+    private Set cachedNames;
+    private Vector ptyRefs = new Vector();
+    private Vector setRefs = new Vector();
+    private Mapper mapper;
+
+    /**
+     * This is a nested class containing a reference to some properties
+     * and optionally a source of properties.
+     */
+    public static class PropertyRef {
+
+        private int count;
+        private String name;
+        private String regex;
+        private String prefix;
+        private String builtin;
+
+        /**
+         * Set the name.
+         * @param name a <code>String</code> value.
+         */
+        public void setName(String name) {
+            assertValid("name", name);
+            this.name = name;
+        }
+
+        /**
+         * Set the regular expression to use to filter the properties.
+         * @param regex a regular expression.
+         */
+        public void setRegex(String regex) {
+            assertValid("regex", regex);
+            this.regex = regex;
+        }
+
+        /**
+         * Set the prefix to use.
+         * @param prefix a <code>String</code> value.
+         */
+        public void setPrefix(String prefix) {
+            assertValid("prefix", prefix);
+            this.prefix = prefix;
+        }
+
+        /**
+         * Builtin property names - all, system or commandline.
+         * @param b an enumerated <code>BuildinPropertySetName</code> value.
+         */
+        public void setBuiltin(BuiltinPropertySetName b) {
+            String pBuiltIn = b.getValue();
+            assertValid("builtin", pBuiltIn);
+            this.builtin = pBuiltIn;
+        }
+
+        private void assertValid(String attr, String value) {
+            if (value == null || value.length() < 1) {
+                throw new BuildException("Invalid attribute: " + attr);
+            }
+
+            if (++count != 1) {
+                throw new BuildException("Attributes name, regex, and "
+                    + "prefix are mutually exclusive");
+            }
+        }
+
+        /**
+         * A debug toString().
+         * @return a string version of this object.
+         */
+        public String toString() {
+            return "name=" + name + ", regex=" + regex + ", prefix=" + prefix
+                + ", builtin=" + builtin;
+        }
+
+    } //end nested class
+
+    /**
+     * Allow properties of a particular name in the set.
+     * @param name the property name to allow.
+     */
+    public void appendName(String name) {
+        PropertyRef r = new PropertyRef();
+        r.setName(name);
+        addPropertyref(r);
+    }
+
+    /**
+     * Allow properties whose names match a regex in the set.
+     * @param regex the regular expression to use.
+     */
+    public void appendRegex(String regex) {
+        PropertyRef r = new PropertyRef();
+        r.setRegex(regex);
+        addPropertyref(r);
+    }
+
+    /**
+     * Allow properties whose names start with a prefix in the set.
+     * @param prefix the prefix to use.
+     */
+    public void appendPrefix(String prefix) {
+        PropertyRef r = new PropertyRef();
+        r.setPrefix(prefix);
+        addPropertyref(r);
+    }
+
+    /**
+     * Allow builtin (all, system or commandline) properties in the set.
+     * @param b the type of builtin properties.
+     */
+    public void appendBuiltin(BuiltinPropertySetName b) {
+        PropertyRef r = new PropertyRef();
+        r.setBuiltin(b);
+        addPropertyref(r);
+    }
+
+    /**
+     * Set a mapper to change property names.
+     * @param type mapper type.
+     * @param from source pattern.
+     * @param to output pattern.
+     */
+    public void setMapper(String type, String from, String to) {
+        Mapper m = createMapper();
+        Mapper.MapperType mapperType = new Mapper.MapperType();
+        mapperType.setValue(type);
+        m.setType(mapperType);
+        m.setFrom(from);
+        m.setTo(to);
+    }
+
+    /**
+     * Add a property reference (nested element) to the references to be used.
+     * @param ref a property reference.
+     */
+    public void addPropertyref(PropertyRef ref) {
+        assertNotReference();
+        ptyRefs.addElement(ref);
+    }
+
+    /**
+     * Add another property set to this set.
+     * @param ref another property set.
+     */
+    public void addPropertyset(PropertySet ref) {
+        assertNotReference();
+        setRefs.addElement(ref);
+    }
+
+    /**
+     * Create a mapper to map the property names.
+     * @return a mapper to be configured.
+     */
+    public Mapper createMapper() {
+        assertNotReference();
+        if (mapper != null) {
+            throw new BuildException("Too many <mapper>s!");
+        }
+        mapper = new Mapper(getProject());
+        return mapper;
+    }
+
+    /**
+     * Add a nested FileNameMapper.
+     * @param fileNameMapper the mapper to add.
+     * @since Ant 1.6.3
+     */
+    public void add(FileNameMapper fileNameMapper) {
+        createMapper().add(fileNameMapper);
+    }
+
+    /**
+     * Set whether to reevaluate the set everytime the set is used.
+     * Default is true.
+     *
+     * @param dynamic if true, reevaluate the property set each time
+     *                the set is used. if false cache the property set
+     *                the first time and use the cached set on subsequent
+     *                occasions.
+     */
+    public void setDynamic(boolean dynamic) {
+        assertNotReference();
+        this.dynamic = dynamic;
+    }
+
+    /**
+     * Set whether to negate results.
+     * If "true", all properties not selected by nested elements will be returned.
+     *  Default is "false".
+     * @param negate if true, negate the selection criteria.
+     */
+    public void setNegate(boolean negate) {
+        assertNotReference();
+        this.negate = negate;
+    }
+
+    /**
+     * Get the dynamic attribute.
+     * @return true if the property set is to be evalulated each time it is used.
+     */
+    public boolean getDynamic() {
+        return isReference() ? getRef().dynamic : dynamic;
+    }
+
+    /**
+     * Get the mapper attribute.
+     * @return the mapper attribute.
+     */
+    public Mapper getMapper() {
+        return isReference() ? getRef().mapper : mapper;
+    }
+
+    /**
+     * Convert the system properties to a hashtable.
+     * Use propertynames to get the list of properties (including
+     * default ones).
+     */
+    private Hashtable getAllSystemProperties() {
+        Hashtable ret = new Hashtable();
+        for (Enumeration e = System.getProperties().propertyNames();
+             e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            ret.put(name, System.getProperties().getProperty(name));
+        }
+        return ret;
+    }
+
+    /**
+     * This is the operation to get the existing or recalculated properties.
+     * @return the properties for this propertyset.
+     */
+    public Properties getProperties() {
+        if (isReference()) {
+            return getRef().getProperties();
+        }
+        Set names = null;
+        Project prj = getProject();
+        Hashtable props =
+            prj == null ? getAllSystemProperties() : prj.getProperties();
+
+        //quick & dirty, to make nested mapped p-sets work:
+        for (Enumeration e = setRefs.elements(); e.hasMoreElements();) {
+            PropertySet set = (PropertySet) e.nextElement();
+            props.putAll(set.getProperties());
+        }
+
+        if (getDynamic() || cachedNames == null) {
+            names = new HashSet();
+            addPropertyNames(names, props);
+            // Add this PropertySet's nested PropertySets' property names.
+            for (Enumeration e = setRefs.elements(); e.hasMoreElements();) {
+                PropertySet set = (PropertySet) e.nextElement();
+                names.addAll(set.getProperties().keySet());
+            }
+            if (negate) {
+                //make a copy...
+                HashSet complement = new HashSet(props.keySet());
+                complement.removeAll(names);
+                names = complement;
+            }
+            if (!getDynamic()) {
+                cachedNames = names;
+            }
+        } else {
+            names = cachedNames;
+        }
+        FileNameMapper m = null;
+        Mapper myMapper = getMapper();
+        if (myMapper != null) {
+            m = myMapper.getImplementation();
+        }
+        Properties properties = new Properties();
+        //iterate through the names, get the matching values
+        for (Iterator iter = names.iterator(); iter.hasNext();) {
+            String name = (String) iter.next();
+            String value = (String) props.get(name);
+            if (value != null) {
+                // may be null if a system property has been added
+                // after the project instance has been initialized
+                if (m != null) {
+                    //map the names
+                    String[] newname = m.mapFileName(name);
+                    if (newname != null) {
+                        name = newname[0];
+                    }
+                }
+                properties.setProperty(name, value);
+            }
+        }
+        return properties;
+    }
+
+    /**
+     * @param  names the output Set to fill with the property names
+     *         matching this PropertySet selection criteria.
+     * @param  properties the current Project properties, passed in to
+     *         avoid needless duplication of the Hashtable during recursion.
+     */
+    private void addPropertyNames(Set names, Hashtable properties) {
+        // Add this PropertySet's property names.
+        for (Enumeration e = ptyRefs.elements(); e.hasMoreElements();) {
+            PropertyRef r = (PropertyRef) e.nextElement();
+            if (r.name != null) {
+                if (properties.get(r.name) != null) {
+                    names.add(r.name);
+                }
+            } else if (r.prefix != null) {
+                for (Enumeration p = properties.keys(); p.hasMoreElements();) {
+                    String name = (String) p.nextElement();
+                    if (name.startsWith(r.prefix)) {
+                        names.add(name);
+                    }
+                }
+            } else if (r.regex != null) {
+                RegexpMatcherFactory matchMaker = new RegexpMatcherFactory();
+                RegexpMatcher matcher = matchMaker.newRegexpMatcher();
+                matcher.setPattern(r.regex);
+                for (Enumeration p = properties.keys(); p.hasMoreElements();) {
+                    String name = (String) p.nextElement();
+                    if (matcher.matches(name)) {
+                        names.add(name);
+                    }
+                }
+            } else if (r.builtin != null) {
+
+                if (r.builtin.equals(BuiltinPropertySetName.ALL)) {
+                    names.addAll(properties.keySet());
+                } else if (r.builtin.equals(BuiltinPropertySetName.SYSTEM)) {
+                    names.addAll(System.getProperties().keySet());
+                } else if (r.builtin.equals(BuiltinPropertySetName
+                                              .COMMANDLINE)) {
+                    names.addAll(getProject().getUserProperties().keySet());
+                } else {
+                    throw new BuildException("Impossible: Invalid builtin "
+                                             + "attribute!");
+                }
+            } else {
+                throw new BuildException("Impossible: Invalid PropertyRef!");
+            }
+        }
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced PropertySet.
+     * @return the referenced PropertySet.
+     */
+    protected PropertySet getRef() {
+        return (PropertySet) getCheckedRef(PropertySet.class, "propertyset");
+    }
+
+    /**
+     * Sets the value of the refid attribute.
+     *
+     * @param  r the reference this datatype should point to.
+     * @throws BuildException if another attribute was set, since
+     *         refid and all other attributes are mutually exclusive.
+     */
+    public final void setRefid(Reference r) {
+        if (!noAttributeSet) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Ensures this data type is not a reference.
+     *
+     * <p>Calling this method as the first line of every bean method of
+     * this data type (setXyz, addXyz, createXyz) ensure proper handling
+     * of the refid attribute.</p>
+     *
+     * @throws BuildException if the refid attribute was already set, since
+     *         refid and all other attributes are mutually exclusive.
+     */
+    protected final void assertNotReference() {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        noAttributeSet = false;
+    }
+
+    /**
+     * Flag which tracks whether any attribute has been set; used by
+     * {@link #assertNotReference()} and {@link #setRefid(Reference)}.
+     */
+    private boolean noAttributeSet = true;
+
+    /**
+     * Used for propertyref's builtin attribute.
+     */
+    public static class BuiltinPropertySetName extends EnumeratedAttribute {
+        static final String ALL = "all";
+        static final String SYSTEM = "system";
+        static final String COMMANDLINE = "commandline";
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {ALL, SYSTEM, COMMANDLINE};
+        }
+    }
+
+    /**
+     * A debug toString.
+     * This gets a comma separated list of key=value pairs for
+     * the properties in the set.
+     * The output order is sorted according to the keys' <i>natural order</i>.
+     * @return a string rep of this object.
+     */
+    public String toString() {
+        StringBuffer b = new StringBuffer();
+        TreeMap sorted = new TreeMap(getProperties());
+        for (Iterator i = sorted.entrySet().iterator(); i.hasNext();) {
+            Map.Entry e = (Map.Entry) i.next();
+            if (b.length() != 0) {
+                b.append(", ");
+            }
+            b.append(e.getKey().toString());
+            b.append("=");
+            b.append(e.getValue().toString());
+        }
+        return b.toString();
+    }
+
+    /**
+     * Fulfill the ResourceCollection interface.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        final Enumeration e = getProperties().propertyNames();
+        return new Iterator() {
+            public boolean hasNext() {
+                return e.hasMoreElements();
+            }
+            public Object next() {
+                return new PropertyResource(getProject(), (String) e.nextElement());
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return the size of this ResourceCollection.
+     */
+    public int size() {
+        return isReference() ? getRef().size() : getProperties().size();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    public boolean isFilesystemOnly() {
+        return isReference() && getRef().isFilesystemOnly();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Quantifier.java b/trunk/src/main/org/apache/tools/ant/types/Quantifier.java
new file mode 100755
index 0000000..ac1b84c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Quantifier.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * EnumeratedAttribute for quantifier comparisons. Evaluates a
+ * <code>boolean[]</code> or raw <code>true</code> and <code>false</code>
+ * counts. Accepts the following values:<ul>
+ * <li>"all"</li> - none <code>false</code>
+ * <li>"each"</li> - none <code>false</code>
+ * <li>"every"</li> - none <code>false</code>
+ * <li>"any"</li> - at least one <code>true</code>
+ * <li>"some"</li> - at least one <code>true</code>
+ * <li>"one"</li> - exactly one <code>true</code>
+ * <li>"majority"</li> - more <code>true</code> than <code>false</code>
+ * <li>"most"</li> - more <code>true</code> than <code>false</code>
+ * <li>"none"</li> - none <code>true</code>
+ * </ul>
+ * @since Ant 1.7
+ */
+public class Quantifier extends EnumeratedAttribute {
+    private static final String[] VALUES
+        = new String[] {"all", "each", "every", "any", "some", "one",
+                        "majority", "most", "none"};
+
+    /** ALL instance */
+    public static final Quantifier ALL = new Quantifier("all");
+    /** ANY instance */
+    public static final Quantifier ANY = new Quantifier("any");
+    /** ONE instance */
+    public static final Quantifier ONE = new Quantifier("one");
+    /** MAJORITY instance */
+    public static final Quantifier MAJORITY = new Quantifier("majority");
+    /** NONE instance */
+    public static final Quantifier NONE = new Quantifier("none");
+
+    private abstract static class Predicate {
+        abstract boolean eval(int t, int f);
+    }
+
+    private static final Predicate ALL_PRED = new Predicate() {
+        boolean eval(int t, int f) { return f == 0; }
+    };
+
+    private static final Predicate ANY_PRED = new Predicate() {
+        boolean eval(int t, int f) { return t > 0; }
+    };
+
+    private static final Predicate ONE_PRED = new Predicate() {
+        boolean eval(int t, int f) { return t == 1; }
+    };
+
+    private static final Predicate MAJORITY_PRED = new Predicate() {
+        boolean eval(int t, int f) { return t > f; }
+    };
+
+    private static final Predicate NONE_PRED = new Predicate() {
+        boolean eval(int t, int f) { return t == 0; }
+    };
+
+    private static final Predicate[] PREDS = new Predicate[VALUES.length];
+
+    static {
+        // CheckStyle:MagicNumber OFF
+        PREDS[0] = ALL_PRED;
+        PREDS[1] = ALL_PRED;
+        PREDS[2] = ALL_PRED;
+        PREDS[3] = ANY_PRED;
+        PREDS[4] = ANY_PRED;
+        PREDS[5] = ONE_PRED;
+        PREDS[6] = MAJORITY_PRED;
+        PREDS[7] = MAJORITY_PRED;
+        PREDS[8] = NONE_PRED;
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Default constructor.
+     */
+    public Quantifier() {
+    }
+
+    /**
+     * Construct a new Quantifier with the specified value.
+     * @param value the EnumeratedAttribute value.
+     */
+    public Quantifier(String value) {
+        setValue(value);
+    }
+
+    /**
+     * Return the possible values.
+     * @return String[] of EnumeratedAttribute values.
+     */
+    public String[] getValues() {
+        return VALUES;
+    }
+
+    /**
+     * Evaluate a <code>boolean<code> array.
+     * @param b the <code>boolean[]</code> to evaluate.
+     * @return true if the argument fell within the parameters of this Quantifier.
+     */
+    public boolean evaluate(boolean[] b) {
+        int t = 0;
+        for (int i = 0; i < b.length; i++) {
+            if (b[i]) {
+                t++;
+            }
+        }
+        return evaluate(t, b.length - t);
+    }
+
+    /**
+     * Evaluate integer <code>true</code> vs. <code>false</code> counts.
+     * @param t the number of <code>true</code> values.
+     * @param f the number of <code>false</code> values.
+     * @return true if the arguments fell within the parameters of this Quantifier.
+     */
+    public boolean evaluate(int t, int f) {
+        int index = getIndex();
+        if (index == -1) {
+            throw new BuildException("Quantifier value not set.");
+        }
+        return PREDS[index].eval(t, f);
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/RedirectorElement.java b/trunk/src/main/org/apache/tools/ant/types/RedirectorElement.java
new file mode 100755
index 0000000..0f37558
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/RedirectorElement.java
@@ -0,0 +1,607 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Redirector;
+
+/**
+ * Element representation of a <code>Redirector</code>.
+ * @since Ant 1.6.2
+ */
+public class RedirectorElement extends DataType {
+
+    /**
+     * Whether the input mapper was set via <code>setOutput</code>.
+     */
+    private boolean usingInput = false;
+
+    /**
+     * Whether the output mapper was set via <code>setOutput</code>.
+     */
+    private boolean usingOutput = false;
+
+    /**
+     * Whether the error mapper was set via <code>setError</code>.
+     */
+    private boolean usingError = false;
+
+    /**
+     * Indicates if standard error should be logged to Ant's log system
+     * rather than the output. This has no effect if standard error is
+     * redirected to a file or property.
+     */
+    private Boolean logError;
+
+    /** The name of the property into which output is to be stored */
+    private String outputProperty;
+
+    /** The name of the property into which error output is to be stored */
+    private String errorProperty;
+
+    /** String from which input is taken */
+    private String inputString;
+
+    /** Flag which indicates if error and output files are to be appended. */
+    private Boolean append;
+
+    /** Flag which indicates that output should be always sent to the log */
+    private Boolean alwaysLog;
+
+    /** Flag which indicates whether files should be created even if empty. */
+    private Boolean createEmptyFiles;
+
+    /** Input file mapper. */
+    private Mapper inputMapper;
+
+    /** Output file mapper. */
+    private Mapper outputMapper;
+
+    /** Error file mapper. */
+    private Mapper errorMapper;
+
+    /** input filter chains. */
+    private Vector inputFilterChains = new Vector();
+
+    /** output filter chains. */
+    private Vector outputFilterChains = new Vector();
+
+    /** error filter chains. */
+    private Vector errorFilterChains = new Vector();
+
+    /** The output encoding */
+    private String outputEncoding;
+
+    /** The error encoding */
+    private String errorEncoding;
+
+    /** The input encoding */
+    private String inputEncoding;
+
+    /** whether to log the inputstring */
+    private Boolean logInputString;
+
+    /**
+     * Add the input file mapper.
+     * @param inputMapper   <code>Mapper</code>.
+     */
+    public void addConfiguredInputMapper(Mapper inputMapper) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.inputMapper != null) {
+            if (usingInput) {
+                throw new BuildException("attribute \"input\""
+                    + " cannot coexist with a nested <inputmapper>");
+            } else {
+                throw new BuildException("Cannot have > 1 <inputmapper>");
+            }
+        }
+        this.inputMapper = inputMapper;
+    }
+
+    /**
+     * Add the output file mapper.
+     * @param outputMapper   <code>Mapper</code>.
+     */
+    public void addConfiguredOutputMapper(Mapper outputMapper) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.outputMapper != null) {
+            if (usingOutput) {
+                throw new BuildException("attribute \"output\""
+                    + " cannot coexist with a nested <outputmapper>");
+            } else {
+                throw new BuildException("Cannot have > 1 <outputmapper>");
+            }
+        }
+        this.outputMapper = outputMapper;
+    }
+
+    /**
+     * Add the error file mapper.
+     * @param errorMapper   <code>Mapper</code>.
+     */
+    public void addConfiguredErrorMapper(Mapper errorMapper) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.errorMapper != null) {
+            if (usingError) {
+                throw new BuildException("attribute \"error\""
+                    + " cannot coexist with a nested <errormapper>");
+            } else {
+                throw new BuildException("Cannot have > 1 <errormapper>");
+            }
+        }
+        this.errorMapper = errorMapper;
+    }
+
+    /**
+     * Make this instance in effect a reference to another instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the reference to use.
+     * @throws BuildException on error.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (usingInput
+            || usingOutput
+            || usingError
+            || inputString != null
+            || logError != null
+            || append != null
+            || createEmptyFiles != null
+            || inputEncoding != null
+            || outputEncoding != null
+            || errorEncoding != null
+            || outputProperty != null
+            || errorProperty != null
+            || logInputString != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Set the input to use for the task.
+     * @param input the file from which input is read.
+     */
+    public void setInput(File input) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (inputString != null) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        usingInput = true;
+        inputMapper = createMergeMapper(input);
+    }
+
+    /**
+     * Set the string to use as input
+     * @param inputString the string which is used as the input source
+     */
+    public void setInputString(String inputString) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (usingInput) {
+            throw new BuildException("The \"input\" and \"inputstring\" "
+                + "attributes cannot both be specified");
+        }
+        this.inputString = inputString;
+    }
+
+    /**
+     * Set whether to include the value of the input string in log messages.
+     * Defaults to true.
+     * @param logInputString true or false.
+     * @since Ant 1.7
+     */
+    public void setLogInputString(boolean logInputString) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.logInputString = logInputString ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * File the output of the process is redirected to. If error is not
+     * redirected, it too will appear in the output.
+     *
+     * @param out the file to which output stream is written.
+     */
+    public void setOutput(File out) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (out == null) {
+            throw new IllegalArgumentException("output file specified as null");
+        }
+        usingOutput = true;
+        outputMapper = createMergeMapper(out);
+    }
+
+    /**
+     * Set the output encoding.
+     * @param outputEncoding   <code>String</code>.
+     */
+    public void setOutputEncoding(String outputEncoding) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.outputEncoding = outputEncoding;
+    }
+
+    /**
+     * Set the error encoding.
+     *
+     * @param errorEncoding   <code>String</code>.
+     */
+    public void setErrorEncoding(String errorEncoding) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.errorEncoding = errorEncoding;
+    }
+
+    /**
+     * Set the input encoding.
+     * @param inputEncoding   <code>String</code>.
+     */
+    public void setInputEncoding(String inputEncoding) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.inputEncoding = inputEncoding;
+    }
+
+    /**
+     * Controls whether error output of exec is logged. This is only useful
+     * when output is being redirected and error output is desired in the
+     * Ant log.
+     * @param logError if true the standard error is sent to the Ant log system
+     *        and not sent to output.
+     */
+    public void setLogError(boolean logError) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.logError = ((logError) ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Set the file to which standard error is to be redirected.
+     * @param error the file to which error is to be written.
+     */
+    public void setError(File error) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (error == null) {
+            throw new IllegalArgumentException("error file specified as null");
+        }
+        usingError = true;
+        errorMapper = createMergeMapper(error);
+    }
+
+    /**
+     * Property name whose value should be set to the output of
+     * the process.
+     * @param outputProperty the name of the property to be set with the
+     *        task's output.
+     */
+    public void setOutputProperty(String outputProperty) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.outputProperty = outputProperty;
+    }
+
+    /**
+     * Whether output should be appended to or overwrite an existing file.
+     * Defaults to false.
+     * @param append if true output and error streams are appended to their
+     *        respective files, if specified.
+     */
+    public void setAppend(boolean append) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.append = ((append) ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * If true, (error and non-error) output will be "teed", redirected
+     * as specified while being sent to Ant's logging mechanism as if no
+     * redirection had taken place.  Defaults to false.
+     * @param alwaysLog <code>boolean</code>
+     * @since Ant 1.6.3
+     */
+    public void setAlwaysLog(boolean alwaysLog) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.alwaysLog = ((alwaysLog) ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Whether output and error files should be created even when empty.
+     * Defaults to true.
+     * @param createEmptyFiles <code>boolean</code>.
+     */
+    public void setCreateEmptyFiles(boolean createEmptyFiles) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.createEmptyFiles = ((createEmptyFiles)
+            ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
+     * Property name whose value should be set to the error of
+     * the process.
+     * @param errorProperty the name of the property to be set
+     *        with the error output.
+     */
+    public void setErrorProperty(String errorProperty) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.errorProperty = errorProperty;
+    }
+
+    /**
+     * Create a nested input <code>FilterChain</code>.
+     * @return <code>FilterChain</code>.
+     */
+    public FilterChain createInputFilterChain() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        FilterChain result = new FilterChain();
+        result.setProject(getProject());
+        inputFilterChains.add(result);
+        return result;
+    }
+
+    /**
+     * Create a nested output <code>FilterChain</code>.
+     * @return <code>FilterChain</code>.
+     */
+    public FilterChain createOutputFilterChain() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        FilterChain result = new FilterChain();
+        result.setProject(getProject());
+        outputFilterChains.add(result);
+        return result;
+    }
+
+    /**
+     * Create a nested error <code>FilterChain</code>.
+     * @return <code>FilterChain</code>.
+     */
+    public FilterChain createErrorFilterChain() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        FilterChain result = new FilterChain();
+        result.setProject(getProject());
+        errorFilterChains.add(result);
+        return result;
+    }
+
+    /**
+     * Configure the specified <code>Redirector</code>.
+     * @param redirector   <code>Redirector</code>.
+     */
+    public void configure(Redirector redirector) {
+        configure(redirector, null);
+    }
+
+    /**
+     * Configure the specified <code>Redirector</code>
+     * for the specified sourcefile.
+     * @param redirector   <code>Redirector</code>.
+     * @param sourcefile   <code>String</code>.
+     */
+    public void configure(Redirector redirector, String sourcefile) {
+        if (isReference()) {
+            getRef().configure(redirector, sourcefile);
+            return;
+        }
+        if (alwaysLog != null) {
+            redirector.setAlwaysLog(alwaysLog.booleanValue());
+        }
+        if (logError != null) {
+            redirector.setLogError(logError.booleanValue());
+        }
+        if (append != null) {
+            redirector.setAppend(append.booleanValue());
+        }
+        if (createEmptyFiles != null) {
+            redirector.setCreateEmptyFiles(createEmptyFiles.booleanValue());
+        }
+        if (outputProperty != null) {
+            redirector.setOutputProperty(outputProperty);
+        }
+        if (errorProperty != null) {
+            redirector.setErrorProperty(errorProperty);
+        }
+        if (inputString != null) {
+            redirector.setInputString(inputString);
+        }
+        if (logInputString != null) {
+            redirector.setLogInputString(logInputString.booleanValue());
+        }
+        if (inputMapper != null) {
+            String[] inputTargets = null;
+            try {
+                inputTargets =
+                    inputMapper.getImplementation().mapFileName(sourcefile);
+            } catch (NullPointerException enPeaEx) {
+                if (sourcefile != null) {
+                    throw enPeaEx;
+                }
+            }
+            if (inputTargets != null && inputTargets.length > 0) {
+                redirector.setInput(toFileArray(inputTargets));
+            }
+        }
+        if (outputMapper != null) {
+            String[] outputTargets = null;
+            try {
+                outputTargets =
+                    outputMapper.getImplementation().mapFileName(sourcefile);
+            } catch (NullPointerException enPeaEx) {
+                if (sourcefile != null) {
+                    throw enPeaEx;
+                }
+            }
+            if (outputTargets != null && outputTargets.length > 0) {
+                redirector.setOutput(toFileArray(outputTargets));
+            }
+        }
+        if (errorMapper != null) {
+            String[] errorTargets = null;
+            try {
+                errorTargets =
+                    errorMapper.getImplementation().mapFileName(sourcefile);
+            } catch (NullPointerException enPeaEx) {
+                if (sourcefile != null) {
+                    throw enPeaEx;
+                }
+            }
+            if (errorTargets != null && errorTargets.length > 0) {
+                redirector.setError(toFileArray(errorTargets));
+            }
+        }
+        if (inputFilterChains.size() > 0) {
+            redirector.setInputFilterChains(inputFilterChains);
+        }
+        if (outputFilterChains.size() > 0) {
+            redirector.setOutputFilterChains(outputFilterChains);
+        }
+        if (errorFilterChains.size() > 0) {
+            redirector.setErrorFilterChains(errorFilterChains);
+        }
+        if (inputEncoding != null) {
+            redirector.setInputEncoding(inputEncoding);
+        }
+        if (outputEncoding != null) {
+            redirector.setOutputEncoding(outputEncoding);
+        }
+        if (errorEncoding != null) {
+            redirector.setErrorEncoding(errorEncoding);
+        }
+    }
+
+    /**
+     * Create a merge mapper pointing to the specified destination file.
+     * @param destfile   <code>File</code>
+     * @return <code>Mapper</code>.
+     */
+    protected Mapper createMergeMapper(File destfile) {
+        Mapper result = new Mapper(getProject());
+        result.setClassname(
+            org.apache.tools.ant.util.MergingMapper.class.getName());
+        result.setTo(destfile.getAbsolutePath());
+        return result;
+    }
+
+    /**
+     * Return a <code>File[]</code> from the specified set of filenames.
+     * @param name   <code>String[]</code>
+     * @return <code>File[]</code>.
+     */
+    protected File[] toFileArray(String[] name) {
+        if (name == null) {
+            return null;
+        }
+        //remove any null elements
+        ArrayList list = new ArrayList(name.length);
+        for (int i = 0; i < name.length; i++) {
+            if (name[i] != null) {
+                list.add(getProject().resolveFile(name[i]));
+            }
+        }
+        return (File[]) (list.toArray(new File[list.size()]));
+    }
+
+    /**
+     * Overrides the version of DataType to recurse on all DataType
+     * child elements that may have been added.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            Mapper[] m = new Mapper[] {inputMapper, outputMapper, errorMapper};
+            for (int i = 0; i < m.length; i++) {
+                if (m[i] != null) {
+                    stk.push(m[i]);
+                    m[i].dieOnCircularReference(stk, p);
+                    stk.pop();
+                }
+            }
+            Vector[] v = new Vector[]
+                {inputFilterChains, outputFilterChains, errorFilterChains};
+            for (int i = 0; i < v.length; i++) {
+                if (v[i] != null) {
+                    for (Iterator fci = v[i].iterator(); fci.hasNext();) {
+                        FilterChain fc = (FilterChain) fci.next();
+                        stk.push(fc);
+                        fc.dieOnCircularReference(stk, p);
+                        stk.pop();
+                    }
+                }
+            }
+            setChecked(true);
+        }
+    }
+
+    /**
+     * Perform the check for circular references, returning the
+     * referenced RedirectorElement.
+     * @return the referenced RedirectorElement.
+     */
+    private RedirectorElement getRef() {
+        return (RedirectorElement) getCheckedRef();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Reference.java b/trunk/src/main/org/apache/tools/ant/types/Reference.java
new file mode 100644
index 0000000..e5e9b25
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Reference.java
@@ -0,0 +1,134 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Class to hold a reference to another object in the project.
+ *
+ */
+public class Reference {
+
+    private String refid;
+    private Project project;
+
+    /**
+     * Create a reference.
+     * @deprecated since 1.7.
+     *             Please use {@link Reference#Reference(Project,String)}
+     *             instead.
+     */
+    public Reference() {
+    }
+
+    /**
+     * Create a reference to a named ID.
+     * @param id the name of this reference
+     * @deprecated since 1.7.
+     *             Please use {@link Reference#Reference(Project,String)}
+     *             instead.
+     */
+    public Reference(String id) {
+        setRefId(id);
+    }
+
+    /**
+     * Create a reference to a named ID in a particular project.
+     * @param p the project this reference is associated with
+     * @param id the name of this reference
+     * @since Ant 1.6.3
+     */
+    public Reference(Project p, String id) {
+        setRefId(id);
+        setProject(p);
+    }
+
+    /**
+     * Set the reference id. Should not normally be necessary;
+     * use {@link Reference#Reference(Project, String)}.
+     * @param id the reference id to use
+     */
+    public void setRefId(String id) {
+        refid = id;
+    }
+
+    /**
+     * Get the reference id of this reference.
+     * @return the reference id
+     */
+    public String getRefId() {
+        return refid;
+    }
+
+    /**
+     * Set the associated project. Should not normally be necessary;
+     * use {@link Reference#Reference(Project,String)}.
+     * @param p the project to use
+     * @since Ant 1.6.3
+     */
+    public void setProject(Project p) {
+        this.project = p;
+    }
+
+    /**
+     * Get the associated project, if any; may be null.
+     * @return the associated project
+     * @since Ant 1.6.3
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Resolve the reference, using the associated project if
+     * it set, otherwise use the passed in project.
+     * @param fallback the fallback project to use if the project attribute of
+     *                 reference is not set.
+     * @return the dereferenced object.
+     * @throws BuildException if the reference cannot be dereferenced.
+     */
+    public Object getReferencedObject(Project fallback) throws BuildException {
+        if (refid == null) {
+            throw new BuildException("No reference specified");
+        }
+
+        Object o = project == null ? fallback.getReference(refid) : project.getReference(refid);
+        if (o == null) {
+            throw new BuildException("Reference " + refid + " not found.");
+        }
+        return o;
+    }
+
+    /**
+     * Resolve the reference, looking in the associated project.
+     * @see Project#getReference
+     * @return the dereferenced object.
+     * @throws BuildException if the project is null or the reference cannot be dereferenced
+     * @since Ant 1.6.3
+     */
+    public Object getReferencedObject() throws BuildException {
+        if (project == null) {
+            throw new BuildException("No project set on reference to " + refid);
+        }
+        return getReferencedObject(project);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/RegularExpression.java b/trunk/src/main/org/apache/tools/ant/types/RegularExpression.java
new file mode 100644
index 0000000..6a091de
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/RegularExpression.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.regexp.Regexp;
+import org.apache.tools.ant.util.regexp.RegexpFactory;
+
+/**
+ * A regular expression datatype.  Keeps an instance of the
+ * compiled expression for speed purposes.  This compiled
+ * expression is lazily evaluated (it is compiled the first
+ * time it is needed).  The syntax is the dependent on which
+ * regular expression type you are using.  The system property
+ * "ant.regexp.regexpimpl" will be the classname of the implementation
+ * that will be used.
+ *
+ * <pre>
+ * For jdk  &lt;= 1.3, there are two available implementations:
+ *   org.apache.tools.ant.util.regexp.JakartaOroRegexp (the default)
+ *        Based on the jakarta-oro package
+ *
+ *   org.apache.tools.ant.util.regexp.JakartaRegexpRegexp
+ *        Based on the jakarta-regexp package
+ *
+ * For jdk &gt;= 1.4 an additional implementation is available:
+ *   org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp
+ *        Based on the jdk 1.4 built in regular expression package.
+ * </pre>
+ *
+ * <pre>
+ *   &lt;regexp [ [id="id"] pattern="expression" | refid="id" ]
+ *   /&gt;
+ * </pre>
+ *
+ * @see org.apache.oro.text.regex.Perl5Compiler
+ * @see org.apache.regexp.RE
+ * @see java.util.regex.Pattern
+ *
+ * @see org.apache.tools.ant.util.regexp.Regexp
+ *
+ * @ant.datatype name="regexp"
+ */
+public class RegularExpression extends DataType {
+    /** Name of this data type */
+    public static final String DATA_TYPE_NAME = "regexp";
+    private boolean alreadyInit = false;
+
+    // The regular expression factory
+    private static final RegexpFactory FACTORY = new RegexpFactory();
+
+    private Regexp regexp = null;
+    // temporary variable
+    private String myPattern;
+    private boolean setPatternPending = false;
+
+    /**
+     * default constructor
+     */
+    public RegularExpression() {
+    }
+
+    private void init(Project p) {
+        if (!alreadyInit) {
+            this.regexp = FACTORY.newRegexp(p);
+            alreadyInit = true;
+        }
+    }
+    private void setPattern() {
+        if (setPatternPending) {
+            regexp.setPattern(myPattern);
+            setPatternPending = false;
+        }
+    }
+    /**
+     * sets the regular expression pattern
+     * @param pattern regular expression pattern
+     */
+    public void setPattern(String pattern) {
+        if (regexp == null) {
+            myPattern = pattern;
+            setPatternPending = true;
+        } else {
+            regexp.setPattern(pattern);
+        }
+    }
+
+    /***
+     * Gets the pattern string for this RegularExpression in the
+     * given project.
+     * @param p project
+     * @return pattern
+     */
+    public String getPattern(Project p) {
+        init(p);
+        if (isReference()) {
+            return getRef(p).getPattern(p);
+        }
+        setPattern();
+        return regexp.getPattern();
+    }
+
+    /**
+     * provides a reference to the Regexp contained in this
+     * @param p  project
+     * @return   Regexp instance associated with this RegularExpression instance
+     */
+    public Regexp getRegexp(Project p) {
+        init(p);
+        if (isReference()) {
+            return getRef(p).getRegexp(p);
+        }
+        setPattern();
+        return this.regexp;
+    }
+
+    /***
+     * Get the RegularExpression this reference refers to in
+     * the given project.  Check for circular references too
+     * @param p project
+     * @return resolved RegularExpression instance
+     */
+    public RegularExpression getRef(Project p) {
+        return (RegularExpression) getCheckedRef(p);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/Resource.java b/trunk/src/main/org/apache/tools/ant/types/Resource.java
new file mode 100644
index 0000000..05aa57b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Resource.java
@@ -0,0 +1,424 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Describes a "File-like" resource (File, ZipEntry, etc.).
+ *
+ * This class is meant to be used by classes needing to record path
+ * and date/time information about a file, a zip entry or some similar
+ * resource (URL, archive in a version control repository, ...).
+ *
+ * @since Ant 1.5.2
+ * @see org.apache.tools.ant.types.resources.Touchable
+ */
+public class Resource extends DataType implements Cloneable, Comparable, ResourceCollection {
+
+    /** Constant unknown size */
+    public static final long UNKNOWN_SIZE = -1;
+
+    /** Constant unknown datetime for getLastModified */
+    public static final long UNKNOWN_DATETIME = 0L;
+
+    /** Magic number */
+    protected static final int MAGIC = getMagicNumber("Resource".getBytes());
+
+    private static final int NULL_NAME = getMagicNumber("null name".getBytes());
+
+    /**
+     * Create a "magic number" for use in hashCode calculations.
+     * @param seed byte[] to seed with.
+     * @return a magic number as int.
+     */
+    protected static int getMagicNumber(byte[] seed) {
+        return new BigInteger(seed).intValue();
+    }
+
+    private String name = null;
+    private Boolean exists = null;
+    private Long lastmodified = null;
+    private Boolean directory = null;
+    private Long size = null;
+
+    /**
+     * Default constructor.
+     */
+    public Resource() {
+    }
+
+    /**
+     * Only sets the name.
+     *
+     * <p>This is a dummy, used for not existing resources.</p>
+     *
+     * @param name relative path of the resource.  Expects
+     * &quot;/&quot; to be used as the directory separator.
+     */
+    public Resource(String name) {
+        this(name, false, 0, false);
+    }
+
+    /**
+     * Sets the name, lastmodified flag, and exists flag.
+     *
+     * @param name relative path of the resource.  Expects
+     * &quot;/&quot; to be used as the directory separator.
+     * @param exists if true, this resource exists.
+     * @param lastmodified the last modification time of this resource.
+     */
+    public Resource(String name, boolean exists, long lastmodified) {
+        this(name, exists, lastmodified, false);
+    }
+
+    /**
+     * Sets the name, lastmodified flag, exists flag, and directory flag.
+     *
+     * @param name relative path of the resource.  Expects
+     * &quot;/&quot; to be used as the directory separator.
+     * @param exists if true the resource exists
+     * @param lastmodified the last modification time of the resource
+     * @param directory    if true, this resource is a directory
+     */
+    public Resource(String name, boolean exists, long lastmodified, boolean directory) {
+        this(name, exists, lastmodified, directory, UNKNOWN_SIZE);
+    }
+
+    /**
+     * Sets the name, lastmodified flag, exists flag, directory flag, and size.
+     *
+     * @param name relative path of the resource.  Expects
+     * &quot;/&quot; to be used as the directory separator.
+     * @param exists if true the resource exists
+     * @param lastmodified the last modification time of the resource
+     * @param directory    if true, this resource is a directory
+     * @param size the size of this resource.
+     */
+    public Resource(String name, boolean exists, long lastmodified, boolean directory, long size) {
+        this.name = name;
+        setName(name);
+        setExists(exists);
+        setLastModified(lastmodified);
+        setDirectory(directory);
+        setSize(size);
+    }
+
+    /**
+     * Name attribute will contain the path of a file relative to the
+     * root directory of its fileset or the recorded path of a zip
+     * entry.
+     *
+     * <p>example for a file with fullpath /var/opt/adm/resource.txt
+     * in a file set with root dir /var/opt it will be
+     * adm/resource.txt.</p>
+     *
+     * <p>&quot;/&quot; will be used as the directory separator.</p>
+     * @return the name of this resource.
+     */
+    public String getName() {
+        return isReference() ? ((Resource) getCheckedRef()).getName() : name;
+    }
+
+    /**
+     * Set the name of this Resource.
+     * @param name relative path of the resource.  Expects
+     * &quot;/&quot; to be used as the directory separator.
+     */
+    public void setName(String name) {
+        checkAttributesAllowed();
+        this.name = name;
+    }
+
+    /**
+     * The exists attribute tells whether a resource exists.
+     * @return true if this resource exists.
+     */
+    public boolean isExists() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).isExists();
+        }
+        //default true:
+        return exists == null || exists.booleanValue();
+    }
+
+    /**
+     * Set the exists attribute.
+     * @param exists if true, this resource exists.
+     */
+    public void setExists(boolean exists) {
+        checkAttributesAllowed();
+        this.exists = exists ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Tells the modification time in milliseconds since 01.01.1970 (the "epoch").
+     *
+     * @return the modification time, if that is meaningful
+     *            (e.g. for a file resource which exists);
+     *         0 if the resource does not exist, to mirror the behavior
+     *         of {@link java.io.File#lastModified};
+     *         or 0 if the notion of modification time is meaningless for this class
+     *           of resource (e.g. an inline string)
+     */
+    public long getLastModified() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getLastModified();
+        }
+        if (!isExists() || lastmodified == null) {
+            return UNKNOWN_DATETIME;
+        }
+        long result = lastmodified.longValue();
+        return result < UNKNOWN_DATETIME ? UNKNOWN_DATETIME : result;
+    }
+
+    /**
+     * Set the last modification attribute.
+     * @param lastmodified the modification time in milliseconds since 01.01.1970.
+     */
+    public void setLastModified(long lastmodified) {
+        checkAttributesAllowed();
+        this.lastmodified = new Long(lastmodified);
+    }
+
+    /**
+     * Tells if the resource is a directory.
+     * @return boolean flag indicating if the resource is a directory.
+     */
+    public boolean isDirectory() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).isDirectory();
+        }
+        //default false:
+        return directory != null && directory.booleanValue();
+    }
+
+    /**
+     * Set the directory attribute.
+     * @param directory if true, this resource is a directory.
+     */
+    public void setDirectory(boolean directory) {
+        checkAttributesAllowed();
+        this.directory = directory ? Boolean.TRUE : Boolean.FALSE;
+    }
+
+    /**
+     * Set the size of this Resource.
+     * @param size the size, as a long.
+     * @since Ant 1.6.3
+     */
+    public void setSize(long size) {
+        checkAttributesAllowed();
+        this.size = new Long(size > UNKNOWN_SIZE ? size : UNKNOWN_SIZE);
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist (for
+     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+     * @since Ant 1.6.3
+     */
+    public long getSize() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getSize();
+        }
+        return isExists()
+            ? (size != null ? size.longValue() : UNKNOWN_SIZE)
+            : 0L;
+    }
+
+    /**
+     * Clone this Resource.
+     * @return copy of this.
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(
+                    "CloneNotSupportedException for a Resource caught. "
+                    + "Derived classes must support cloning.");
+        }
+    }
+
+    /**
+     * Delegates to a comparison of names.
+     * @param other the object to compare to.
+     * @return a negative integer, zero, or a positive integer as this Resource
+     *         is less than, equal to, or greater than the specified Resource.
+     * @since Ant 1.6
+     */
+    public int compareTo(Object other) {
+        if (isReference()) {
+            return ((Comparable) getCheckedRef()).compareTo(other);
+        }
+        if (!(other instanceof Resource)) {
+            throw new IllegalArgumentException(
+                "Can only be compared with Resources");
+        }
+        return toString().compareTo(other.toString());
+    }
+
+    /**
+     * Implement basic Resource equality.
+     * @param other the object to check against.
+     * @return true if the specified Object is equal to this Resource.
+     * @since Ant 1.7
+     */
+    public boolean equals(Object other) {
+        if (isReference()) {
+            return getCheckedRef().equals(other);
+        }
+        return other.getClass().equals(getClass()) && compareTo(other) == 0;
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     * @since Ant 1.7
+     */
+    public int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        String name = getName();
+        return MAGIC * (name == null ? NULL_NAME : name.hashCode());
+    }
+
+    /**
+     * Get an InputStream for the Resource.
+     * @return an InputStream containing this Resource's content.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if InputStreams are not
+     *         supported for this Resource type.
+     * @since Ant 1.7
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     * @since Ant 1.7
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        return isReference() ? ((Resource) getCheckedRef()).iterator()
+            : new Iterator() {
+            private boolean done = false;
+            public boolean hasNext() {
+                return !done;
+            }
+            public Object next() {
+                if (done) {
+                    throw new NoSuchElementException();
+                }
+                done = true;
+                return Resource.this;
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return the size of this ResourceCollection.
+     * @since Ant 1.7
+     */
+    public int size() {
+        return isReference() ? ((Resource) getCheckedRef()).size() : 1;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this Resource is a FileResource.
+     * @since Ant 1.7
+     */
+    public boolean isFilesystemOnly() {
+        //default false:
+        return isReference() && ((Resource) getCheckedRef()).isFilesystemOnly();
+    }
+
+    /**
+     * Get the string representation of this Resource.
+     * @return this Resource formatted as a String.
+     * @since Ant 1.7
+     */
+    public String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        String n = getName();
+        return n == null ? "(anonymous)" : n;
+    }
+
+    /**
+     * Get a long String representation of this Resource.
+     * This typically should be the value of <code>toString()</code>
+     * prefixed by a type description.
+     * @return this Resource formatted as a long String.
+     * @since Ant 1.7
+     */
+    public final String toLongString() {
+        return isReference() ? ((Resource) getCheckedRef()).toLongString()
+            : getDataTypeName() + " \"" + toString() + '"';
+    }
+
+    /**
+     * Overrides the base version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (name != null
+            || exists != null
+            || lastmodified != null
+            || directory != null
+            || size != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ResourceCollection.java b/trunk/src/main/org/apache/tools/ant/types/ResourceCollection.java
new file mode 100755
index 0000000..efef88d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ResourceCollection.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.util.Iterator;
+
+/**
+ * Interface describing a collection of Resources.
+ * @since Ant 1.7
+ */
+public interface ResourceCollection {
+
+    /**
+     * Get an Iterator over the contents of this ResourceCollection, whose elements
+     * are <code>org.apache.tools.ant.types.Resource</code> instances.
+     * @return an Iterator of Resources.
+     */
+    Iterator iterator();
+
+    /**
+     * Learn the number of contained Resources.
+     * @return number of elements as int.
+     */
+    int size();
+
+    /**
+     * Indicate whether this ResourceCollection is composed entirely of
+     * Resources accessible via local filesystem conventions.  If true,
+     * all Resources returned from this ResourceCollection should be
+     * instances of FileResource.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    boolean isFilesystemOnly();
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ResourceFactory.java b/trunk/src/main/org/apache/tools/ant/types/ResourceFactory.java
new file mode 100644
index 0000000..515318e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ResourceFactory.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+/**
+ * this interface should be implemented by classes (Scanners) needing
+ * to deliver information about resources.
+ *
+ * @since Ant 1.5.2
+ */
+public interface ResourceFactory {
+
+    /**
+     * Query a resource (file, zipentry, ...) by name
+     *
+     * @param name relative path of the resource about which
+     * information is sought.  Expects &quot;/&quot; to be used as the
+     * directory separator.
+     * @return instance of Resource; the exists attribute of Resource
+     * will tell whether the sought resource exists
+     */
+    Resource getResource(String name);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ResourceLocation.java b/trunk/src/main/org/apache/tools/ant/types/ResourceLocation.java
new file mode 100644
index 0000000..c5a44ea
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ResourceLocation.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import java.net.URL;
+
+/**
+ * <p>Helper class to handle the <code>&lt;dtd&gt;</code> and
+ * <code>&lt;entity&gt;</code> nested elements.  These correspond to
+ * the <code>PUBLIC</code> and <code>URI</code> catalog entry types,
+ * respectively, as defined in the <a
+ * href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
+ * OASIS "Open Catalog" standard</a>.</p>
+ *
+ * <p>Possible Future Enhancements:
+ * <ul>
+ * <li>Bring the Ant element names into conformance with the OASIS standard</li>
+ * <li>Add support for additional OASIS catalog entry types</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.apache.xml.resolver.Catalog
+ * @since Ant 1.6
+ */
+public class ResourceLocation {
+
+    //-- Fields ----------------------------------------------------------------
+    /** publicId of the dtd/entity. */
+    private String publicId = null;
+
+    /** location of the dtd/entity - a file/resource/URL. */
+    private String location = null;
+
+    /**
+     * base URL of the dtd/entity, or null. If null, the Ant project
+     * basedir is assumed.  If the location specifies a relative
+     * URL/pathname, it is resolved using the base.  The default base
+     * for an external catalog file is the directory in which it is
+     * located.
+     */
+    private URL base = null;
+
+    //-- Methods ---------------------------------------------------------------
+
+    /**
+     * @param publicId uniquely identifies the resource.
+     */
+    public void setPublicId(String publicId) {
+        this.publicId = publicId;
+    }
+
+    /**
+     * @param location the location of the resource associated with the
+     *      publicId.
+     */
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    /**
+     * @param base the base URL of the resource associated with the
+     * publicId.  If the location specifies a relative URL/pathname,
+     * it is resolved using the base.  The default base for an
+     * external catalog file is the directory in which it is located.
+     */
+    public void setBase(URL base) {
+        this.base = base;
+    }
+
+    /**
+     * @return the publicId of the resource.
+     */
+    public String getPublicId() {
+        return publicId;
+    }
+
+    /**
+     * @return the location of the resource identified by the publicId.
+     */
+    public String getLocation() {
+        return location;
+    }
+
+    /**
+     * @return the base of the resource identified by the publicId.
+     */
+    public URL getBase() {
+        return base;
+    }
+
+} //-- ResourceLocation
diff --git a/trunk/src/main/org/apache/tools/ant/types/Substitution.java b/trunk/src/main/org/apache/tools/ant/types/Substitution.java
new file mode 100644
index 0000000..343f4c4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/Substitution.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+
+import org.apache.tools.ant.Project;
+
+/***
+ * A regular expression substitution datatype.  It is an expression
+ * that is meant to replace a regular expression.
+ *
+ * <pre>
+ *   &lt;substitution [ [id="id"] expression="expression" | refid="id" ]
+ *   /&gt;
+ * </pre>
+ *
+ * @see org.apache.oro.text.regex.Perl5Substitution
+ */
+public class Substitution extends DataType {
+    /** The name of this data type */
+    public static final String DATA_TYPE_NAME = "substitution";
+
+    private String expression;
+
+    /** Constructor for Substitution. */
+    public Substitution() {
+        this.expression = null;
+    }
+
+    /**
+     * Set the pattern string for this regular expression substitution.
+     * @param expression the regular expression to use
+     */
+    public void setExpression(String expression) {
+        this.expression = expression;
+    }
+
+    /***
+     * Gets the pattern string for this RegularExpression in the
+     * given project.
+     * @param p the project to look for the regular expression if this object is
+     *          a reference
+     * @return the pattern string
+     */
+    public String getExpression(Project p) {
+        if (isReference()) {
+            return getRef(p).getExpression(p);
+        }
+
+        return expression;
+    }
+
+    /***
+     * Get the RegularExpression this reference refers to in
+     * the given project.  Check for circular references too.
+     * @param p the project to look for the regular expression reference
+     * @return the resolved reference
+     */
+    public Substitution getRef(Project p) {
+        return (Substitution) getCheckedRef(p);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/TarFileSet.java b/trunk/src/main/org/apache/tools/ant/types/TarFileSet.java
new file mode 100755
index 0000000..7d61ae1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/TarFileSet.java
@@ -0,0 +1,268 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * A TarFileSet is a FileSet with extra attributes useful in the context of
+ * Tar/Jar tasks.
+ *
+ * A TarFileSet extends FileSets with the ability to extract a subset of the
+ * entries of a Tar file for inclusion in another Tar file.  It also includes
+ * a prefix attribute which is prepended to each entry in the output Tar file.
+ *
+ */
+public class TarFileSet extends ArchiveFileSet {
+
+    private boolean userNameSet;
+    private boolean groupNameSet;
+    private boolean userIdSet;
+    private boolean groupIdSet;
+
+    private String userName = "";
+    private String groupName = "";
+    private int    uid;
+    private int    gid;
+
+    /** Constructor for TarFileSet */
+    public TarFileSet() {
+        super();
+    }
+
+    /**
+     * Constructor using a fileset arguement.
+     * @param fileset the fileset to use
+     */
+    protected TarFileSet(FileSet fileset) {
+        super(fileset);
+    }
+
+    /**
+     * Constructor using a tarfileset arguement.
+     * @param fileset the tarfileset to use
+     */
+    protected TarFileSet(TarFileSet fileset) {
+        super(fileset);
+    }
+
+    /**
+     * The username for the tar entry
+     * This is not the same as the UID.
+     * @param userName the user name for the tar entry.
+     */
+    public void setUserName(String userName) {
+        checkTarFileSetAttributesAllowed();
+        userNameSet = true;
+        this.userName = userName;
+    }
+
+    /**
+     * @return the user name for the tar entry
+     */
+    public String getUserName() {
+        if (isReference()) {
+            return ((TarFileSet) getCheckedRef()).getUserName();
+        }
+        return userName;
+    }
+
+    /**
+     * @return whether the user name has been explicitly set.
+     */
+    public boolean hasUserNameBeenSet() {
+        return userNameSet;
+    }
+
+    /**
+     * The uid for the tar entry
+     * This is not the same as the User name.
+     * @param uid the id of the user for the tar entry.
+     */
+    public void setUid(int uid) {
+        checkTarFileSetAttributesAllowed();
+        userIdSet = true;
+        this.uid = uid;
+    }
+
+    /**
+     * @return the uid for the tar entry
+     */
+    public int getUid() {
+        if (isReference()) {
+            return ((TarFileSet) getCheckedRef()).getUid();
+        }
+        return uid;
+    }
+
+    /**
+     * @return whether the user id has been explicitly set.
+     */
+    public boolean hasUserIdBeenSet() {
+        return userIdSet;
+    }
+
+    /**
+     * The groupname for the tar entry; optional, default=""
+     * This is not the same as the GID.
+     * @param groupName the group name string.
+     */
+    public void setGroup(String groupName) {
+        checkTarFileSetAttributesAllowed();
+        groupNameSet = true;
+        this.groupName = groupName;
+    }
+
+    /**
+     * @return the group name string.
+     */
+    public String getGroup() {
+        if (isReference()) {
+            return ((TarFileSet) getCheckedRef()).getGroup();
+        }
+        return groupName;
+    }
+
+    /**
+     * @return whether the group name has been explicitly set.
+     */
+    public boolean hasGroupBeenSet() {
+        return groupNameSet;
+    }
+
+    /**
+     * The GID for the tar entry; optional, default="0"
+     * This is not the same as the group name.
+     * @param gid the group id.
+     */
+    public void setGid(int gid) {
+        checkTarFileSetAttributesAllowed();
+        groupIdSet = true;
+        this.gid = gid;
+    }
+
+    /**
+     * @return the group identifier.
+     */
+    public int getGid() {
+        if (isReference()) {
+            return ((TarFileSet) getCheckedRef()).getGid();
+        }
+        return gid;
+    }
+
+    /**
+     * @return whether the group id has been explicitly set.
+     */
+    public boolean hasGroupIdBeenSet() {
+        return groupIdSet;
+    }
+
+    /**
+     * Create a new scanner.
+     * @return the created scanner.
+     */
+    protected ArchiveScanner newArchiveScanner() {
+        TarScanner zs = new TarScanner();
+        return zs;
+    }
+
+    /**
+     * Makes this instance in effect a reference to another instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the <code>Reference</code> to use.
+     * @throws BuildException on error
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (userNameSet || userIdSet || groupNameSet || groupIdSet) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * A TarFileset accepts another TarFileSet or a FileSet as reference
+     * FileSets are often used by the war task for the lib attribute
+     * @param p the project to use
+     * @return the abstract fileset instance
+     */
+    protected AbstractFileSet getRef(Project p) {
+        dieOnCircularReference(p);
+        Object o = getRefid().getReferencedObject(p);
+        if (o instanceof TarFileSet) {
+            return (AbstractFileSet) o;
+        } else if (o instanceof FileSet) {
+            TarFileSet zfs = new TarFileSet((FileSet) o);
+            configureFileSet(zfs);
+            return zfs;
+        } else {
+            String msg = getRefid().getRefId() + " doesn\'t denote a tarfileset or a fileset";
+            throw new BuildException(msg);
+        }
+    }
+
+    /**
+     * Configure a fileset based on this fileset.
+     * If the fileset is a TarFileSet copy in the tarfileset
+     * specific attributes.
+     * @param zfs the archive fileset to configure.
+     */
+    protected void configureFileSet(ArchiveFileSet zfs) {
+        super.configureFileSet(zfs);
+        if (zfs instanceof TarFileSet) {
+            TarFileSet tfs = (TarFileSet) zfs;
+            tfs.setUserName(userName);
+            tfs.setGroup(groupName);
+            tfs.setUid(uid);
+            tfs.setGid(gid);
+        }
+    }
+
+    /**
+     * Return a TarFileSet that has the same properties
+     * as this one.
+     * @return the cloned tarFileSet
+     */
+    public Object clone() {
+        if (isReference()) {
+            return ((TarFileSet) getRef(getProject())).clone();
+        } else {
+            return super.clone();
+        }
+    }
+
+    /**
+     * A check attributes for TarFileSet.
+     * If there is a reference, and
+     * it is a TarFileSet, the tar fileset attributes
+     * cannot be used.
+     */
+    private void checkTarFileSetAttributesAllowed() {
+        if (getProject() == null
+            || (isReference()
+                && (getRefid().getReferencedObject(
+                        getProject())
+                    instanceof TarFileSet))) {
+            checkAttributesAllowed();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/TarScanner.java b/trunk/src/main/org/apache/tools/ant/types/TarScanner.java
new file mode 100755
index 0000000..5eb0d68
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/TarScanner.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.resources.TarResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
+
+/**
+ * Scans tar archives for resources.
+ */
+public class TarScanner extends ArchiveScanner {
+
+    /**
+     * Fills the file and directory maps with resources read from the
+     * archive.
+     *
+     * @param src the archive to scan.
+     * @param encoding encoding used to encode file names inside the archive.
+     * @param fileEntries Map (name to resource) of non-directory
+     * resources found inside the archive.
+     * @param matchFileEntries Map (name to resource) of non-directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     * @param dirEntries Map (name to resource) of directory
+     * resources found inside the archive.
+     * @param matchDirEntries Map (name to resource) of directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     */
+    protected void fillMapsFromArchive(Resource src, String encoding,
+                                       Map fileEntries, Map matchFileEntries,
+                                       Map dirEntries, Map matchDirEntries) {
+        TarEntry entry = null;
+        TarInputStream ti = null;
+
+        try {
+            try {
+                ti = new TarInputStream(src.getInputStream());
+            } catch (IOException ex) {
+                throw new BuildException("problem opening " + srcFile, ex);
+            }
+            while ((entry = ti.getNextEntry()) != null) {
+                Resource r = new TarResource(src, entry);
+                String name = entry.getName();
+                if (entry.isDirectory()) {
+                    name = trimSeparator(name);
+                    dirEntries.put(name, r);
+                    if (match(name)) {
+                        matchDirEntries.put(name, r);
+                    }
+                } else {
+                    fileEntries.put(name, r);
+                    if (match(name)) {
+                        matchFileEntries.put(name, r);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            throw new BuildException("problem reading " + srcFile, ex);
+        } finally {
+            FileUtils.close(ti);
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/types/TimeComparison.java b/trunk/src/main/org/apache/tools/ant/types/TimeComparison.java
new file mode 100755
index 0000000..15c136e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/TimeComparison.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * EnumeratedAttribute for time comparisons.  Accepts values
+ * "before", "after", "equal".
+ * @since Ant 1.7
+ */
+public class TimeComparison extends EnumeratedAttribute {
+    private static final String[] VALUES
+        = new String[] {"before", "after", "equal"};
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Before Comparison. */
+    public static final TimeComparison BEFORE = new TimeComparison("before");
+
+    /** After Comparison. */
+    public static final TimeComparison AFTER = new TimeComparison("after");
+
+    /** Equal Comparison. */
+    public static final TimeComparison EQUAL = new TimeComparison("equal");
+
+    /**
+     * Default constructor.
+     */
+    public TimeComparison() {
+    }
+
+    /**
+     * Construct a new TimeComparison with the specified value.
+     * @param value the EnumeratedAttribute value.
+     */
+    public TimeComparison(String value) {
+        setValue(value);
+    }
+
+    /**
+     * Return the possible values.
+     * @return String[] of EnumeratedAttribute values.
+     */
+    public String[] getValues() {
+        return VALUES;
+    }
+
+    /**
+     * Evaluate two times against this TimeComparison.
+     * @param t1 the first time to compare.
+     * @param t2 the second time to compare.
+     * @return true if the comparison result fell within the parameters of this TimeComparison.
+     */
+    public boolean evaluate(long t1, long t2) {
+        return evaluate(t1, t2, FILE_UTILS.getFileTimestampGranularity());
+    }
+
+    /**
+     * Evaluate two times against this TimeComparison.
+     * @param t1 the first time to compare.
+     * @param t2 the second time to compare.
+     * @param g the timestamp granularity.
+     * @return true if the comparison result fell within the parameters of this TimeComparison.
+     */
+    public boolean evaluate(long t1, long t2, long g) {
+        int cmp = getIndex();
+        if (cmp == -1) {
+            throw new BuildException("TimeComparison value not set.");
+        }
+        if (cmp == 0) {
+            return t1 - g < t2;
+        }
+        if (cmp == 1) {
+            return t1 + g > t2;
+        }
+        return Math.abs(t1 - t2) <= g;
+    }
+
+    /**
+     * Compare two times.
+     * @param t1 the first time to compare.
+     * @param t2 the second time to compare.
+     * @return a negative integer, a positive integer, or zero as t1 is
+     *         before, after, or equal to t2 accounting for the default granularity.
+     */
+    public static int compare(long t1, long t2) {
+        return compare(t1, t2, FILE_UTILS.getFileTimestampGranularity());
+    }
+
+    /**
+     * Compare two times.
+     * @param t1 the first time to compare.
+     * @param t2 the second time to compare.
+     * @param g the timestamp granularity.
+     * @return a negative integer, a positive integer, or zero as t1 is
+     *         before, after, or equal to t2 accounting for the specified granularity.
+     */
+    public static int compare(long t1, long t2, long g) {
+        long diff = t1 - t2;
+        long abs = Math.abs(diff);
+        return abs > Math.abs(g) ? (int) (diff / abs) : 0;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/XMLCatalog.java b/trunk/src/main/org/apache/tools/ant/types/XMLCatalog.java
new file mode 100644
index 0000000..66413e5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/XMLCatalog.java
@@ -0,0 +1,1107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.lang.reflect.Method;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Vector;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+
+
+/**
+ * <p>This data type provides a catalog of resource locations (such as
+ * DTDs and XML entities), based on the <a
+ * href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
+ * OASIS "Open Catalog" standard</a>.  The catalog entries are used
+ * both for Entity resolution and URI resolution, in accordance with
+ * the {@link org.xml.sax.EntityResolver EntityResolver} and {@link
+ * javax.xml.transform.URIResolver URIResolver} interfaces as defined
+ * in the <a href="http://java.sun.com/xml/jaxp">Java API for XML
+ * Processing Specification</a>.</p>
+ *
+ * <p>Resource locations can be specified either in-line or in
+ * external catalog file(s), or both.  In order to use an external
+ * catalog file, the xml-commons resolver library ("resolver.jar")
+ * must be in your classpath.  External catalog files may be either <a
+ * href="http://oasis-open.org/committees/entity/background/9401.html">
+ * plain text format</a> or <a
+ * href="http://www.oasis-open.org/committees/entity/spec-2001-08-06.html">
+ * XML format</a>.  If the xml-commons resolver library is not found
+ * in the classpath, external catalog files, specified in
+ * <code>&lt;catalogpath&gt;</code> paths, will be ignored and a warning will
+ * be logged.  In this case, however, processing of inline entries will proceed
+ * normally.</p>
+ *
+ * <p>Currently, only <code>&lt;dtd&gt;</code> and
+ * <code>&lt;entity&gt;</code> elements may be specified inline; these
+ * correspond to OASIS catalog entry types <code>PUBLIC</code> and
+ * <code>URI</code> respectively.</p>
+ *
+ * <p>The following is a usage example:</p>
+ *
+ * <code>
+ * &lt;xmlcatalog&gt;<br>
+ * &nbsp;&nbsp;&lt;dtd publicId="" location="/path/to/file.jar" /&gt;<br>
+ * &nbsp;&nbsp;&lt;dtd publicId="" location="/path/to/file2.jar" /&gt;<br>
+ * &nbsp;&nbsp;&lt;entity publicId="" location="/path/to/file3.jar" /&gt;<br>
+ * &nbsp;&nbsp;&lt;entity publicId="" location="/path/to/file4.jar" /&gt;<br>
+ * &nbsp;&nbsp;&lt;catalogpath&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/etc/sgml/catalog"/&gt;<br>
+ * &nbsp;&nbsp;&lt;/catalogpath&gt;<br>
+ * &nbsp;&nbsp;&lt;catalogfiles dir="/opt/catalogs/" includes="**\catalog.xml" /&gt;<br>
+ * &lt;/xmlcatalog&gt;<br>
+ * </code>
+ * <p>
+ * Tasks wishing to use <code>&lt;xmlcatalog&gt;</code> must provide a method called
+ * <code>createXMLCatalog</code> which returns an instance of
+ * <code>XMLCatalog</code>. Nested DTD and entity definitions are handled by
+ * the XMLCatalog object and must be labeled <code>dtd</code> and
+ * <code>entity</code> respectively.</p>
+ *
+ * <p>The following is a description of the resolution algorithm:
+ * entities/URIs/dtds are looked up in each of the following contexts,
+ * stopping when a valid and readable resource is found:
+ * <ol>
+ * <li>In the local filesystem</li>
+ * <li>In the classpath</li>
+ * <li>Using the Apache xml-commons resolver (if it is available)</li>
+ * <li>In URL-space</li>
+ * </ol>
+ * </p>
+ *
+ * <p>See {@link
+ * org.apache.tools.ant.taskdefs.optional.XMLValidateTask
+ * XMLValidateTask} for an example of a task that has integrated
+ * support for XMLCatalogs.</p>
+ *
+ * <p>Possible future extension could provide for additional OASIS
+ * entry types to be specified inline.</p>
+ *
+ */
+public class XMLCatalog extends DataType
+    implements Cloneable, EntityResolver, URIResolver {
+
+    /** helper for some File.toURL connversions */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    //-- Fields ----------------------------------------------------------------
+
+    /** Holds dtd/entity objects until needed. */
+    private Vector elements = new Vector();
+
+    /**
+     * Classpath in which to attempt to resolve resources.
+     */
+    private Path classpath;
+
+    /**
+     * Path listing external catalog files to search when resolving entities
+     */
+    private Path catalogPath;
+
+    /**
+     * The name of the bridge to the Apache xml-commons resolver
+     * class, used to determine whether resolver.jar is present in the
+     * classpath.
+     */
+    public static final String APACHE_RESOLVER
+        = "org.apache.tools.ant.types.resolver.ApacheCatalogResolver";
+
+    /**
+     * Resolver base class
+     */
+    public static final String CATALOG_RESOLVER
+        = "org.apache.xml.resolver.tools.CatalogResolver";
+
+        //-- Methods ---------------------------------------------------------------
+
+    /**
+     * Default constructor
+     */
+    public XMLCatalog() {
+        setChecked(false);
+    }
+
+    /**
+     * Returns the elements of the catalog - ResourceLocation objects.
+     *
+     * @return the elements of the catalog - ResourceLocation objects
+     */
+    private Vector getElements() {
+        return getRef().elements;
+    }
+
+    /**
+     * Returns the classpath in which to attempt to resolve resources.
+     *
+     * @return the classpath
+     */
+    private Path getClasspath() {
+        return getRef().classpath;
+    }
+
+    /**
+     * Allows nested classpath elements. Not allowed if this catalog
+     * is itself a reference to another catalog -- that is, a catalog
+     * cannot both refer to another <em>and</em> contain elements or
+     * other attributes.
+     *
+     * @return a Path instance to be configured.
+     */
+    public Path createClasspath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        setChecked(false);
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Allows simple classpath string.  Not allowed if this catalog is
+     * itself a reference to another catalog -- that is, a catalog
+     * cannot both refer to another <em>and</em> contain elements or
+     * other attributes.
+     *
+     * @param classpath the classpath to use to look up entities.
+     */
+    public void setClasspath(Path classpath) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+        setChecked(false);
+    }
+
+    /**
+     * Allows classpath reference.  Not allowed if this catalog is
+     * itself a reference to another catalog -- that is, a catalog
+     * cannot both refer to another <em>and</em> contain elements or
+     * other attributes.
+     *
+     * @param r an Ant reference containing a classpath.
+     */
+    public void setClasspathRef(Reference r) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        createClasspath().setRefid(r);
+        setChecked(false);
+    }
+
+    /** Creates a nested <code>&lt;catalogpath&gt;</code> element.
+     * Not allowed if this catalog is itself a reference to another
+     * catalog -- that is, a catalog cannot both refer to another
+     * <em>and</em> contain elements or other attributes.
+     *
+     * @return a path to be configured as the catalog path.
+     * @exception BuildException
+     * if this is a reference and no nested elements are allowed.
+     */
+    public Path createCatalogPath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.catalogPath == null) {
+            this.catalogPath = new Path(getProject());
+        }
+        setChecked(false);
+        return this.catalogPath.createPath();
+    }
+
+    /**
+     * Allows catalogpath reference.  Not allowed if this catalog is
+     * itself a reference to another catalog -- that is, a catalog
+     * cannot both refer to another <em>and</em> contain elements or
+     * other attributes.
+     *
+     * @param r an Ant reference containing a classpath to be used as
+     * the catalog path.
+     */
+    public void setCatalogPathRef(Reference r) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        createCatalogPath().setRefid(r);
+        setChecked(false);
+    }
+
+
+    /**
+     * Returns the catalog path in which to attempt to resolve DTDs.
+     *
+     * @return the catalog path
+     */
+    public Path getCatalogPath() {
+        return getRef().catalogPath;
+    }
+
+
+    /**
+     * Creates the nested <code>&lt;dtd&gt;</code> element.  Not
+     * allowed if this catalog is itself a reference to another
+     * catalog -- that is, a catalog cannot both refer to another
+     * <em>and</em> contain elements or other attributes.
+     *
+     * @param dtd the information about the PUBLIC resource mapping to
+     *            be added to the catalog
+     * @exception BuildException if this is a reference and no nested
+     *       elements are allowed.
+     */
+    public void addDTD(ResourceLocation dtd) throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+
+        getElements().addElement(dtd);
+        setChecked(false);
+    }
+
+    /**
+     * Creates the nested <code>&lt;entity&gt;</code> element.    Not
+     * allowed if this catalog is itself a reference to another
+     * catalog -- that is, a catalog cannot both refer to another
+     * <em>and</em> contain elements or other attributes.
+     *
+     * @param entity the information about the URI resource mapping to be
+     *       added to the catalog.
+     * @exception BuildException if this is a reference and no nested
+     *       elements are allowed.
+     */
+    public void addEntity(ResourceLocation entity) throws BuildException {
+        addDTD(entity);
+    }
+
+    /**
+     * Loads a nested <code>&lt;xmlcatalog&gt;</code> into our
+     * definition.  Not allowed if this catalog is itself a reference
+     * to another catalog -- that is, a catalog cannot both refer to
+     * another <em>and</em> contain elements or other attributes.
+     *
+     * @param catalog Nested XMLCatalog
+     */
+    public void addConfiguredXMLCatalog(XMLCatalog catalog) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+
+        // Add all nested elements to our catalog
+        Vector newElements = catalog.getElements();
+        Vector ourElements = getElements();
+        Enumeration e = newElements.elements();
+        while (e.hasMoreElements()) {
+            ourElements.addElement(e.nextElement());
+        }
+
+        // Append the classpath of the nested catalog
+        Path nestedClasspath = catalog.getClasspath();
+        createClasspath().append(nestedClasspath);
+
+        // Append the catalog path of the nested catalog
+        Path nestedCatalogPath = catalog.getCatalogPath();
+        createCatalogPath().append(nestedCatalogPath);
+        setChecked(false);
+    }
+
+    /**
+     * Makes this instance in effect a reference to another XMLCatalog
+     * instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.  That is, a catalog
+     * cannot both refer to another <em>and</em> contain elements or
+     * attributes.</p>
+     *
+     * @param r the reference to which this catalog instance is associated
+     * @exception BuildException if this instance already has been configured.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (!elements.isEmpty()) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Implements the EntityResolver.resolveEntity() interface method.
+     * @param publicId the public id to resolve.
+     * @param systemId the system id to resolve.
+     * @throws SAXException if there is a parsing problem.
+     * @throws IOException if there is an IO problem.
+     * @return the resolved entity.
+     * @see org.xml.sax.EntityResolver#resolveEntity
+     */
+    public InputSource resolveEntity(String publicId, String systemId)
+        throws SAXException, IOException {
+
+        if (isReference()) {
+            return getRef().resolveEntity(publicId, systemId);
+        }
+
+        dieOnCircularReference();
+
+        log("resolveEntity: '" + publicId + "': '" + systemId + "'",
+            Project.MSG_DEBUG);
+
+        InputSource inputSource =
+            getCatalogResolver().resolveEntity(publicId, systemId);
+
+        if (inputSource == null) {
+            log("No matching catalog entry found, parser will use: '"
+                + systemId + "'", Project.MSG_DEBUG);
+        }
+
+        return inputSource;
+    }
+
+    /**
+     * Implements the URIResolver.resolve() interface method.
+     * @param href an href attribute.
+     * @param base the base URI.
+     * @return a Source object, or null if href cannot be resolved.
+     * @throws TransformerException if an error occurs.
+     * @see javax.xml.transform.URIResolver#resolve
+     */
+    public Source resolve(String href, String base)
+        throws TransformerException {
+
+        if (isReference()) {
+            return getRef().resolve(href, base);
+        }
+
+        dieOnCircularReference();
+
+        SAXSource source = null;
+
+        String uri = removeFragment(href);
+
+        log("resolve: '" + uri + "' with base: '" + base + "'", Project.MSG_DEBUG);
+
+        source = (SAXSource) getCatalogResolver().resolve(uri, base);
+
+        if (source == null) {
+            log("No matching catalog entry found, parser will use: '"
+                + href + "'", Project.MSG_DEBUG);
+            //
+            // Cannot return a null source, because we have to call
+            // setEntityResolver (see setEntityResolver javadoc comment)
+            //
+            source = new SAXSource();
+            URL baseURL = null;
+            try {
+                if (base == null) {
+                    baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir());
+                } else {
+                    baseURL = new URL(base);
+                }
+                URL url = (uri.length() == 0 ? baseURL : new URL(baseURL, uri));
+                source.setInputSource(new InputSource(url.toString()));
+            } catch (MalformedURLException ex) {
+                // At this point we are probably in failure mode, but
+                // try to use the bare URI as a last gasp
+                source.setInputSource(new InputSource(uri));
+            }
+        }
+
+        setEntityResolver(source);
+        return source;
+    }
+
+    /**
+     * @since Ant 1.6
+     */
+    private XMLCatalog getRef() {
+        if (!isReference()) {
+            return this;
+        }
+        return (XMLCatalog) getCheckedRef(XMLCatalog.class, "xmlcatalog");
+    }
+
+    /**
+     * The instance of the CatalogResolver strategy to use.
+     */
+    private CatalogResolver catalogResolver = null;
+
+    /**
+     * Factory method for creating the appropriate CatalogResolver
+     * strategy implementation.
+     * <p> Until we query the classpath, we don't know whether the Apache
+     * resolver (Norm Walsh's library from xml-commons) is available or not.
+     * This method determines whether the library is available and creates the
+     * appropriate implementation of CatalogResolver based on the answer.</p>
+     * <p>This is an application of the Gang of Four Strategy Pattern
+     * combined with Template Method.</p>
+     */
+    private CatalogResolver getCatalogResolver() {
+
+        if (catalogResolver == null) {
+
+            AntClassLoader loader = null;
+
+            loader = getProject().createClassLoader(Path.systemClasspath);
+
+            try {
+                Class clazz = Class.forName(APACHE_RESOLVER, true, loader);
+
+                // The Apache resolver is present - Need to check if it can
+                // be seen by the catalog resolver class. Start by getting
+                // the actual loader
+                ClassLoader apacheResolverLoader = clazz.getClassLoader();
+
+                // load the base class through this loader.
+                Class baseResolverClass
+                    = Class.forName(CATALOG_RESOLVER, true, apacheResolverLoader);
+
+                // and find its actual loader
+                ClassLoader baseResolverLoader
+                    = baseResolverClass.getClassLoader();
+
+                // We have the loader which is being used to load the
+                // CatalogResolver. Can it see the ApacheResolver? The
+                // base resolver will only be able to create the ApacheResolver
+                // if it can see it - doesn't use the context loader.
+                clazz = Class.forName(APACHE_RESOLVER, true, baseResolverLoader);
+
+                Object obj  = clazz.newInstance();
+                //
+                // Success!  The xml-commons resolver library is
+                // available, so use it.
+                //
+                catalogResolver = new ExternalResolver(clazz, obj);
+            } catch (Throwable ex) {
+                //
+                // The xml-commons resolver library is not
+                // available, so we can't use it.
+                //
+                catalogResolver = new InternalResolver();
+                if (getCatalogPath() != null
+                    && getCatalogPath().list().length != 0) {
+                        log("Warning: XML resolver not found; external catalogs"
+                            + " will be ignored", Project.MSG_WARN);
+                    }
+                log("Failed to load Apache resolver: " + ex, Project.MSG_DEBUG);
+            }
+        }
+        return catalogResolver;
+    }
+
+    /**
+     * <p>This is called from the URIResolver to set an EntityResolver
+     * on the SAX parser to be used for new XML documents that are
+     * encountered as a result of the document() function, xsl:import,
+     * or xsl:include.  This is done because the XSLT processor calls
+     * out to the SAXParserFactory itself to create a new SAXParser to
+     * parse the new document.  The new parser does not automatically
+     * inherit the EntityResolver of the original (although arguably
+     * it should).  See below:</p>
+     *
+     * <tt>"If an application wants to set the ErrorHandler or
+     * EntityResolver for an XMLReader used during a transformation,
+     * it should use a URIResolver to return the SAXSource which
+     * provides (with getXMLReader) a reference to the XMLReader"</tt>
+     *
+     * <p>...quoted from page 118 of the Java API for XML
+     * Processing 1.1 specification</p>
+     *
+     */
+    private void setEntityResolver(SAXSource source) throws TransformerException {
+
+        XMLReader reader = source.getXMLReader();
+        if (reader == null) {
+            SAXParserFactory spFactory = SAXParserFactory.newInstance();
+            spFactory.setNamespaceAware(true);
+            try {
+                reader = spFactory.newSAXParser().getXMLReader();
+            } catch (ParserConfigurationException ex) {
+                throw new TransformerException(ex);
+            } catch (SAXException ex) {
+                throw new TransformerException(ex);
+            }
+        }
+        reader.setEntityResolver(this);
+        source.setXMLReader(reader);
+    }
+
+    /**
+     * Find a ResourceLocation instance for the given publicId.
+     *
+     * @param publicId the publicId of the Resource for which local information
+     *        is required.
+     * @return a ResourceLocation instance with information on the local location
+     *         of the Resource or null if no such information is available.
+     */
+    private ResourceLocation findMatchingEntry(String publicId) {
+        Enumeration e = getElements().elements();
+        ResourceLocation element = null;
+        while (e.hasMoreElements()) {
+            Object o = e.nextElement();
+            if (o instanceof ResourceLocation) {
+                element = (ResourceLocation) o;
+                if (element.getPublicId().equals(publicId)) {
+                    return element;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to remove trailing fragment from a URI.
+     * For example,
+     * <code>http://java.sun.com/index.html#chapter1</code>
+     * would return <code>http://java.sun.com/index.html</code>.
+     *
+     * @param uri The URI to process.  It may or may not contain a
+     *            fragment.
+     * @return The URI sans fragment.
+     */
+    private String removeFragment(String uri) {
+        String result = uri;
+        int hashPos = uri.indexOf("#");
+        if (hashPos >= 0) {
+            result = uri.substring(0, hashPos);
+        }
+        return result;
+    }
+
+    /**
+     * Utility method to lookup a ResourceLocation in the filesystem.
+     *
+     * @return An InputSource for reading the file, or <code>null</code>
+     *     if the file does not exist or is not readable.
+     */
+    private InputSource filesystemLookup(ResourceLocation matchingEntry) {
+
+        String uri = matchingEntry.getLocation();
+        // the following line seems to be necessary on Windows under JDK 1.2
+        uri = uri.replace(File.separatorChar, '/');
+        URL baseURL = null;
+
+        //
+        // The ResourceLocation may specify a relative path for its
+        // location attribute.  This is resolved using the appropriate
+        // base.
+        //
+        if (matchingEntry.getBase() != null) {
+            baseURL = matchingEntry.getBase();
+        } else {
+            try {
+                baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir());
+            } catch (MalformedURLException ex) {
+                throw new BuildException("Project basedir cannot be converted to a URL");
+            }
+        }
+
+        InputSource source = null;
+        URL url = null;
+        try {
+            url = new URL(baseURL, uri);
+        } catch (MalformedURLException ex) {
+            // this processing is useful under Windows when the location of the DTD
+            // has been given as an absolute path
+            // see Bugzilla Report 23913
+            File testFile = new File(uri);
+            if (testFile.exists() && testFile.canRead()) {
+                log("uri : '"
+                    + uri + "' matches a readable file", Project.MSG_DEBUG);
+                try {
+                    url = FILE_UTILS.getFileURL(testFile);
+                } catch (MalformedURLException ex1) {
+                    throw new BuildException(
+                        "could not find an URL for :" + testFile.getAbsolutePath());
+                }
+            } else {
+                log("uri : '"
+                    + uri + "' does not match a readable file", Project.MSG_DEBUG);
+
+            }
+        }
+
+        if (url != null && url.getProtocol().equals("file")) {
+            String fileName = FILE_UTILS.fromURI(url.toString());
+            if (fileName != null) {
+                log("fileName " + fileName, Project.MSG_DEBUG);
+                File resFile = new File(fileName);
+                if (resFile.exists() && resFile.canRead()) {
+                    try {
+                        source = new InputSource(new FileInputStream(resFile));
+                        String sysid = JAXPUtils.getSystemId(resFile);
+                        source.setSystemId(sysid);
+                        log("catalog entry matched a readable file: '"
+                            + sysid + "'", Project.MSG_DEBUG);
+                    } catch (IOException ex) {
+                        // ignore
+                    }
+                }
+            }
+        }
+        return source;
+    }
+
+    /**
+     * Utility method to lookup a ResourceLocation in the classpath.
+     *
+     * @return An InputSource for reading the resource, or <code>null</code>
+     *    if the resource does not exist in the classpath or is not readable.
+     */
+    private InputSource classpathLookup(ResourceLocation matchingEntry) {
+
+        InputSource source = null;
+
+        AntClassLoader loader = null;
+        Path cp = classpath;
+        if (cp != null) {
+            cp = classpath.concatSystemClasspath("ignore");
+        } else {
+            cp = (new Path(getProject())).concatSystemClasspath("last");
+        }
+        loader = getProject().createClassLoader(cp);
+
+        //
+        // for classpath lookup we ignore the base directory
+        //
+        InputStream is
+            = loader.getResourceAsStream(matchingEntry.getLocation());
+
+        if (is != null) {
+            source = new InputSource(is);
+            URL entryURL = loader.getResource(matchingEntry.getLocation());
+            String sysid = entryURL.toExternalForm();
+            source.setSystemId(sysid);
+            log("catalog entry matched a resource in the classpath: '"
+                + sysid + "'", Project.MSG_DEBUG);
+        }
+
+        return source;
+    }
+
+    /**
+     * Utility method to lookup a ResourceLocation in URL-space.
+     *
+     * @return An InputSource for reading the resource, or <code>null</code>
+     *    if the resource does not identify a valid URL or is not readable.
+     */
+    private InputSource urlLookup(ResourceLocation matchingEntry) {
+
+        String uri = matchingEntry.getLocation();
+        URL baseURL = null;
+
+        //
+        // The ResourceLocation may specify a relative url for its
+        // location attribute.  This is resolved using the appropriate
+        // base.
+        //
+        if (matchingEntry.getBase() != null) {
+            baseURL = matchingEntry.getBase();
+        } else {
+            try {
+                baseURL = FILE_UTILS.getFileURL(getProject().getBaseDir());
+            } catch (MalformedURLException ex) {
+                throw new BuildException("Project basedir cannot be converted to a URL");
+            }
+        }
+
+        InputSource source = null;
+        URL url = null;
+
+        try {
+            url = new URL(baseURL, uri);
+        } catch (MalformedURLException ex) {
+            // ignore
+        }
+
+        if (url != null) {
+            try {
+                InputStream is = url.openStream();
+                if (is != null) {
+                    source = new InputSource(is);
+                    String sysid = url.toExternalForm();
+                    source.setSystemId(sysid);
+                    log("catalog entry matched as a URL: '"
+                        + sysid + "'", Project.MSG_DEBUG);
+                }
+            } catch (IOException ex) {
+                // ignore
+            }
+        }
+
+        return source;
+
+    }
+
+    /**
+     * Interface implemented by both the InternalResolver strategy and
+     * the ExternalResolver strategy.
+     */
+    private interface CatalogResolver extends URIResolver, EntityResolver {
+
+        InputSource resolveEntity(String publicId, String systemId);
+
+        Source resolve(String href, String base) throws TransformerException;
+    }
+
+    /**
+     * The InternalResolver strategy is used if the Apache resolver
+     * library (Norm Walsh's library from xml-commons) is not
+     * available.  In this case, external catalog files will be
+     * ignored.
+     *
+     */
+    private class InternalResolver implements CatalogResolver {
+
+        public InternalResolver() {
+            log("Apache resolver library not found, internal resolver will be used",
+                Project.MSG_VERBOSE);
+        }
+
+        public InputSource resolveEntity(String publicId,
+                                         String systemId) {
+            InputSource result = null;
+            ResourceLocation matchingEntry = findMatchingEntry(publicId);
+
+            if (matchingEntry != null) {
+
+                log("Matching catalog entry found for publicId: '"
+                    + matchingEntry.getPublicId() + "' location: '"
+                    + matchingEntry.getLocation() + "'",
+                    Project.MSG_DEBUG);
+
+                result = filesystemLookup(matchingEntry);
+
+                if (result == null) {
+                    result = classpathLookup(matchingEntry);
+                }
+
+                if (result == null) {
+                    result = urlLookup(matchingEntry);
+                }
+            }
+            return result;
+        }
+
+        public Source resolve(String href, String base)
+            throws TransformerException {
+
+            SAXSource result = null;
+            InputSource source = null;
+
+            ResourceLocation matchingEntry = findMatchingEntry(href);
+
+            if (matchingEntry != null) {
+
+                log("Matching catalog entry found for uri: '"
+                    + matchingEntry.getPublicId() + "' location: '"
+                    + matchingEntry.getLocation() + "'",
+                    Project.MSG_DEBUG);
+
+                //
+                // Use the passed in base in preference to the base
+                // from matchingEntry, which is either null or the
+                // directory in which the external catalog file from
+                // which it was obtained is located.  We make a copy
+                // so matchingEntry's original base is untouched.
+                //
+                // This is the standard behavior as per my reading of
+                // the JAXP and XML Catalog specs.  CKS 11/7/2002
+                //
+                ResourceLocation entryCopy = matchingEntry;
+                if (base != null) {
+                    try {
+                        URL baseURL = new URL(base);
+                        entryCopy = new ResourceLocation();
+                        entryCopy.setBase(baseURL);
+                    } catch (MalformedURLException ex) {
+                        // ignore
+                    }
+                }
+                entryCopy.setPublicId(matchingEntry.getPublicId());
+                entryCopy.setLocation(matchingEntry.getLocation());
+
+                source = filesystemLookup(entryCopy);
+
+                if (source == null) {
+                    source = classpathLookup(entryCopy);
+                }
+
+                if (source == null) {
+                    source = urlLookup(entryCopy);
+                }
+
+                if (source != null) {
+                    result = new SAXSource(source);
+                }
+            }
+            return result;
+        }
+    }
+
+    /**
+     * The ExternalResolver strategy is used if the Apache resolver
+     * library (Norm Walsh's library from xml-commons) is available in
+     * the classpath.  The ExternalResolver is a essentially a superset
+     * of the InternalResolver.
+     *
+     */
+    private class ExternalResolver implements CatalogResolver {
+
+        private Method setXMLCatalog = null;
+        private Method parseCatalog = null;
+        private Method resolveEntity = null;
+        private Method resolve = null;
+
+        /** The instance of the ApacheCatalogResolver bridge class */
+        private Object resolverImpl = null;
+
+        private boolean externalCatalogsProcessed = false;
+
+        public ExternalResolver(Class resolverImplClass,
+                              Object resolverImpl) {
+
+            this.resolverImpl = resolverImpl;
+
+            //
+            // Get Method instances for each of the methods we need to
+            // call on the resolverImpl using reflection.  We can't
+            // call them directly, because they require on the
+            // xml-commons resolver library which may not be available
+            // in the classpath.
+            //
+            try {
+                setXMLCatalog =
+                    resolverImplClass.getMethod("setXMLCatalog",
+                                                new Class[] {XMLCatalog.class});
+
+                parseCatalog =
+                    resolverImplClass.getMethod("parseCatalog",
+                                                new Class[] {String.class});
+
+                resolveEntity =
+                    resolverImplClass.getMethod("resolveEntity",
+                                                new Class[] {String.class, String.class});
+
+                resolve =
+                    resolverImplClass.getMethod("resolve",
+                                                new Class[] {String.class, String.class});
+            } catch (NoSuchMethodException ex) {
+                throw new BuildException(ex);
+            }
+
+            log("Apache resolver library found, xml-commons resolver will be used",
+                Project.MSG_VERBOSE);
+        }
+
+        public InputSource resolveEntity(String publicId,
+                                         String systemId) {
+            InputSource result = null;
+
+            processExternalCatalogs();
+
+            ResourceLocation matchingEntry = findMatchingEntry(publicId);
+
+            if (matchingEntry != null) {
+
+                log("Matching catalog entry found for publicId: '"
+                    + matchingEntry.getPublicId() + "' location: '"
+                    + matchingEntry.getLocation() + "'",
+                    Project.MSG_DEBUG);
+
+                result = filesystemLookup(matchingEntry);
+
+                if (result == null) {
+                    result = classpathLookup(matchingEntry);
+                }
+
+                if (result == null) {
+                    try {
+                        result =
+                            (InputSource) resolveEntity.invoke(resolverImpl,
+                                                              new Object[] {publicId, systemId});
+                    } catch (Exception ex) {
+                        throw new BuildException(ex);
+                    }
+                }
+            } else {
+                //
+                // We didn't match a ResourceLocation, but since we
+                // only support PUBLIC and URI entry types internally,
+                // it is still possible that there is another entry in
+                // an external catalog that will match.  We call
+                // Apache resolver's resolveEntity method to cover
+                // this possibility.
+                //
+                try {
+                    result =
+                        (InputSource) resolveEntity.invoke(resolverImpl,
+                                                          new Object[] {publicId, systemId});
+                } catch (Exception ex) {
+                    throw new BuildException(ex);
+                }
+            }
+
+            return result;
+        }
+
+        public Source resolve(String href, String base)
+            throws TransformerException {
+
+            SAXSource result = null;
+            InputSource source = null;
+
+            processExternalCatalogs();
+
+            ResourceLocation matchingEntry = findMatchingEntry(href);
+
+            if (matchingEntry != null) {
+
+                log("Matching catalog entry found for uri: '"
+                    + matchingEntry.getPublicId() + "' location: '"
+                    + matchingEntry.getLocation() + "'",
+                    Project.MSG_DEBUG);
+
+                //
+                // Use the passed in base in preference to the base
+                // from matchingEntry, which is either null or the
+                // directory in which the external catalog file from
+                // which it was obtained is located.  We make a copy
+                // so matchingEntry's original base is untouched.  Of
+                // course, if there is no base, no need to make a
+                // copy...
+                //
+                // This is the standard behavior as per my reading of
+                // the JAXP and XML Catalog specs.  CKS 11/7/2002
+                //
+                ResourceLocation entryCopy = matchingEntry;
+                if (base != null) {
+                    try {
+                        URL baseURL = new URL(base);
+                        entryCopy = new ResourceLocation();
+                        entryCopy.setBase(baseURL);
+                    } catch (MalformedURLException ex) {
+                        // ignore
+                    }
+                }
+                entryCopy.setPublicId(matchingEntry.getPublicId());
+                entryCopy.setLocation(matchingEntry.getLocation());
+
+                source = filesystemLookup(entryCopy);
+
+                if (source == null) {
+                    source = classpathLookup(entryCopy);
+                }
+
+                if (source != null) {
+                    result = new SAXSource(source);
+                } else {
+                    try {
+                        result =
+                            (SAXSource) resolve.invoke(resolverImpl,
+                                                      new Object[] {href, base});
+                    } catch (Exception ex) {
+                        throw new BuildException(ex);
+                    }
+                }
+            } else {
+                //
+                // We didn't match a ResourceLocation, but since we
+                // only support PUBLIC and URI entry types internally,
+                // it is still possible that there is another entry in
+                // an external catalog that will match.  We call
+                // Apache resolver's resolveEntity method to cover
+                // this possibility.
+                //
+                try {
+                    result =
+                        (SAXSource) resolve.invoke(resolverImpl,
+                                                  new Object[] {href, base});
+                } catch (Exception ex) {
+                    throw new BuildException(ex);
+                }
+            }
+            return result;
+        }
+
+        /**
+         * Process each external catalog file specified in a
+         * <code>&lt;catalogpath&gt;</code>.  It will be
+         * parsed by the resolver library, and the individual elements
+         * will be added back to us (that is, the controlling
+         * XMLCatalog instance) via a callback mechanism.
+         */
+        private void processExternalCatalogs() {
+
+            if (!externalCatalogsProcessed) {
+
+                try {
+                    setXMLCatalog.invoke(resolverImpl,
+                                         new Object[] {XMLCatalog.this});
+                } catch (Exception ex) {
+                    throw new BuildException(ex);
+                }
+
+                // Parse each catalog listed in nested <catalogpath> elements
+                Path catPath = getCatalogPath();
+                if (catPath != null) {
+                    log("Using catalogpath '" + getCatalogPath() + "'",
+                        Project.MSG_DEBUG);
+                    String[] catPathList = getCatalogPath().list();
+
+                    for (int i = 0; i < catPathList.length; i++) {
+                        File catFile = new File(catPathList[i]);
+                        log("Parsing " + catFile, Project.MSG_DEBUG);
+                        try {
+                            parseCatalog.invoke(resolverImpl,
+                                    new Object[] {catFile.getPath()});
+                        } catch (Exception ex) {
+                            throw new BuildException(ex);
+                        }
+                    }
+                }
+            }
+            externalCatalogsProcessed = true;
+        }
+    }
+} //-- XMLCatalog
diff --git a/trunk/src/main/org/apache/tools/ant/types/ZipFileSet.java b/trunk/src/main/org/apache/tools/ant/types/ZipFileSet.java
new file mode 100644
index 0000000..6fcc665
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ZipFileSet.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * A ZipFileSet is a FileSet with extra attributes useful in the context of
+ * Zip/Jar tasks.
+ *
+ * A ZipFileSet extends FileSets with the ability to extract a subset of the
+ * entries of a Zip file for inclusion in another Zip file.  It also includes
+ * a prefix attribute which is prepended to each entry in the output Zip file.
+ *
+ * Since ant 1.6 ZipFileSet can be defined with an id and referenced in packaging tasks
+ *
+ */
+public class ZipFileSet extends ArchiveFileSet {
+
+    private String encoding = null;
+
+    /** Constructor for ZipFileSet */
+    public ZipFileSet() {
+        super();
+    }
+
+    /**
+     * Constructor using a fileset arguement.
+     * @param fileset the fileset to use
+     */
+    protected ZipFileSet(FileSet fileset) {
+        super(fileset);
+    }
+
+    /**
+     * Constructor using a zipfileset arguement.
+     * @param fileset the zipfileset to use
+     */
+    protected ZipFileSet(ZipFileSet fileset) {
+        super(fileset);
+        encoding = fileset.encoding;
+    }
+
+    /**
+     * Set the encoding used for this ZipFileSet.
+     * @param enc encoding as String.
+     * @since Ant 1.7
+     */
+    public void setEncoding(String enc) {
+        checkZipFileSetAttributesAllowed();
+        this.encoding = enc;
+    }
+
+    /**
+     * Get the encoding used for this ZipFileSet.
+     * @return String encoding.
+     * @since Ant 1.7
+     */
+    public String getEncoding() {
+        if (isReference()) {
+            AbstractFileSet ref = getRef(getProject());
+            if (ref instanceof ZipFileSet) {
+                return ((ZipFileSet) ref).getEncoding();
+            } else {
+                return null;
+            }
+        }
+        return encoding;
+    }
+
+    /**
+     * Return a new archive scanner based on this one.
+     * @return a new ZipScanner with the same encoding as this one.
+     */
+    protected ArchiveScanner newArchiveScanner() {
+        ZipScanner zs = new ZipScanner();
+        zs.setEncoding(encoding);
+        return zs;
+    }
+
+    /**
+     * A ZipFileset accepts another ZipFileSet or a FileSet as reference
+     * FileSets are often used by the war task for the lib attribute
+     * @param p the project to use
+     * @return the abstract fileset instance
+     */
+    protected AbstractFileSet getRef(Project p) {
+        dieOnCircularReference(p);
+        Object o = getRefid().getReferencedObject(p);
+        if (o instanceof ZipFileSet) {
+            return (AbstractFileSet) o;
+        } else if (o instanceof FileSet) {
+            ZipFileSet zfs = new ZipFileSet((FileSet) o);
+            configureFileSet(zfs);
+            return zfs;
+        } else {
+            String msg = getRefid().getRefId() + " doesn\'t denote a zipfileset or a fileset";
+            throw new BuildException(msg);
+        }
+    }
+
+    /**
+     * Return a ZipFileSet that has the same properties
+     * as this one.
+     * @return the cloned zipFileSet
+     */
+    public Object clone() {
+        if (isReference()) {
+            return ((ZipFileSet) getRef(getProject())).clone();
+        } else {
+            return super.clone();
+        }
+    }
+
+    /**
+     * A check attributes for zipFileSet.
+     * If there is a reference, and
+     * it is a ZipFileSet, the zip fileset attributes
+     * cannot be used.
+     */
+    private void checkZipFileSetAttributesAllowed() {
+        if (getProject() == null
+            || (isReference()
+                && (getRefid().getReferencedObject(
+                        getProject())
+                    instanceof ZipFileSet))) {
+            checkAttributesAllowed();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/ZipScanner.java b/trunk/src/main/org/apache/tools/ant/types/ZipScanner.java
new file mode 100644
index 0000000..9ea89bd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/ZipScanner.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.zip.ZipException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.ZipResource;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipFile;
+
+/**
+ * Scans zip archives for resources.
+ */
+public class ZipScanner extends ArchiveScanner {
+
+    /**
+     * Fills the file and directory maps with resources read from the
+     * archive.
+     *
+     * @param src the archive to scan.
+     * @param encoding encoding used to encode file names inside the archive.
+     * @param fileEntries Map (name to resource) of non-directory
+     * resources found inside the archive.
+     * @param matchFileEntries Map (name to resource) of non-directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     * @param dirEntries Map (name to resource) of directory
+     * resources found inside the archive.
+     * @param matchDirEntries Map (name to resource) of directory
+     * resources found inside the archive that matched all include
+     * patterns and didn't match any exclude patterns.
+     */
+    protected void fillMapsFromArchive(Resource src, String encoding,
+                                       Map fileEntries, Map matchFileEntries,
+                                       Map dirEntries, Map matchDirEntries) {
+        ZipEntry entry = null;
+        ZipFile zf = null;
+
+        File srcFile = null;
+        if (src instanceof FileResource) {
+            srcFile = ((FileResource) src).getFile();
+        } else {
+            throw new BuildException("only file resources are supported");
+        }
+
+        try {
+            try {
+                zf = new ZipFile(srcFile, encoding);
+            } catch (ZipException ex) {
+                throw new BuildException("problem reading " + srcFile, ex);
+            } catch (IOException ex) {
+                throw new BuildException("problem opening " + srcFile, ex);
+            }
+            Enumeration e = zf.getEntries();
+            while (e.hasMoreElements()) {
+                entry = (ZipEntry) e.nextElement();
+                Resource r = new ZipResource(srcFile, encoding, entry);
+                String name = entry.getName();
+                if (entry.isDirectory()) {
+                    name = trimSeparator(name);
+                    dirEntries.put(name, r);
+                    if (match(name)) {
+                        matchDirEntries.put(name, r);
+                    }
+                } else {
+                    fileEntries.put(name, r);
+                    if (match(name)) {
+                        matchFileEntries.put(name, r);
+                    }
+                }
+            }
+        } finally {
+            ZipFile.closeQuietly(zf);
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/types/conditions/antlib.xml b/trunk/src/main/org/apache/tools/ant/types/conditions/antlib.xml
new file mode 100644
index 0000000..7f9a1e7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/conditions/antlib.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<antlib>
+  <!--
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+  -->
+  <!-- Ant 1.6+ antlib declaration for conditions:
+  Use with the declaration xmlns:cond="antlib:org.apache.tools.ant.condition"
+  to
+  trigger Ant's autoload of this file into namespace 'cond' (or whatever name
+  suits).
+
+  Please keep this list in alphabetical order; it is easier to verify that way.
+
+  Additionally, ConditionBase uses this antlib to discover built-in conditions.
+  Prior to Ant 1.7, a new built-in condition required an addXXX method to be
+  added to ConditionBase.  Conditions added in or after version 1.7 need only
+  to be added to this antlib.
+  -->
+
+  <typedef name="and" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.And"/>
+  <typedef name="antversion" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.AntVersion"/>
+  <typedef name="contains" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Contains"/>
+  <typedef name="equals" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Equals"/>
+  <typedef name="filesmatch" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.FilesMatch"/>
+  <typedef name="hasfreespace" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.HasFreeSpace"/>
+  <typedef name="http" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Http"/>
+  <typedef name="isfailure" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsFailure"/>
+  <typedef name="isfalse" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsFalse"/>
+  <typedef name="isfileselected" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsFileSelected"/>
+  <typedef name="isreachable" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsReachable"/>
+  <typedef name="isreference" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsReference"/>
+  <typedef name="isset" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsSet"/>
+  <typedef name="issigned" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsSigned"/>
+  <typedef name="istrue"  onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.IsTrue"/>
+  <typedef name="not" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Not"/>
+  <typedef name="matches" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Matches"/>
+  <typedef name="or" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Or"/>
+  <typedef name="os" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Os"/>
+  <typedef name="parsersupports" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.ParserSupports"/>
+  <typedef name="resourcesmatch" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.ResourcesMatch"/>
+  <typedef name="resourcecontains" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.ResourceContains"/>
+  <typedef name="scriptcondition" onerror="ignore"
+           classname="org.apache.tools.ant.types.optional.ScriptCondition"/>
+  <typedef name="socket" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Socket"/>
+  <typedef name="typefound" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.TypeFound"/>
+  <typedef name="xor" onerror="ignore"
+           classname="org.apache.tools.ant.taskdefs.condition.Xor"/>
+</antlib>
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/types/defaults.properties b/trunk/src/main/org/apache/tools/ant/types/defaults.properties
new file mode 100644
index 0000000..dc4c696
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/defaults.properties
@@ -0,0 +1,92 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+description=org.apache.tools.ant.types.Description
+filterchain=org.apache.tools.ant.types.FilterChain
+filterreader=org.apache.tools.ant.types.AntFilterReader
+filterset=org.apache.tools.ant.types.FilterSet
+mapper=org.apache.tools.ant.types.Mapper
+redirector=org.apache.tools.ant.types.RedirectorElement
+patternset=org.apache.tools.ant.types.PatternSet
+regexp=org.apache.tools.ant.types.RegularExpression
+substitution=org.apache.tools.ant.types.Substitution
+xmlcatalog=org.apache.tools.ant.types.XMLCatalog
+extensionSet=org.apache.tools.ant.taskdefs.optional.extension.ExtensionSet
+extension=org.apache.tools.ant.taskdefs.optional.extension.ExtensionAdapter
+selector=org.apache.tools.ant.types.selectors.SelectSelector
+signedselector=org.apache.tools.ant.types.selectors.SignedSelector
+scriptfilter=org.apache.tools.ant.types.optional.ScriptFilter
+assertions=org.apache.tools.ant.types.Assertions
+concatfilter=org.apache.tools.ant.filters.ConcatFilter
+mavenrepository=org.apache.tools.ant.taskdefs.repository.MavenRepository
+scriptselector=org.apache.tools.ant.types.optional.ScriptSelector
+scriptmapper=org.apache.tools.ant.types.optional.ScriptMapper
+
+# different filename mappers
+identitymapper=org.apache.tools.ant.util.IdentityMapper
+flattenmapper=org.apache.tools.ant.util.FlatFileNameMapper
+globmapper=org.apache.tools.ant.util.GlobPatternMapper
+mergemapper=org.apache.tools.ant.util.MergingMapper
+regexpmapper=org.apache.tools.ant.util.RegexpPatternMapper
+packagemapper=org.apache.tools.ant.util.PackageNameMapper
+unpackagemapper=org.apache.tools.ant.util.UnPackageNameMapper
+compositemapper=org.apache.tools.ant.util.CompositeMapper
+chainedmapper=org.apache.tools.ant.util.ChainedMapper
+filtermapper=org.apache.tools.ant.types.mappers.FilterMapper
+
+#this condition is in here because it is the sole
+#condition defined in Ant1.6
+#please add new conditions to oata.types.conditions/antlib.xml instead of
+#here, to avoid namespace clash with things like selectors.
+isfileselected=org.apache.tools.ant.taskdefs.condition.IsFileSelected
+scriptcondition=org.apache.tools.ant.types.optional.ScriptCondition
+
+#ResourceCollections:
+dirset=org.apache.tools.ant.types.DirSet
+filelist=org.apache.tools.ant.types.FileList
+fileset=org.apache.tools.ant.types.FileSet
+path=org.apache.tools.ant.types.Path
+propertyset=org.apache.tools.ant.types.PropertySet
+zipfileset=org.apache.tools.ant.types.ZipFileSet
+classfileset=org.apache.tools.ant.types.optional.depend.ClassfileSet
+libfileset=org.apache.tools.ant.taskdefs.optional.extension.LibFileSet
+files=org.apache.tools.ant.types.resources.Files
+restrict=org.apache.tools.ant.types.resources.Restrict
+union=org.apache.tools.ant.types.resources.Union
+difference=org.apache.tools.ant.types.resources.Difference
+intersect=org.apache.tools.ant.types.resources.Intersect
+sort=org.apache.tools.ant.types.resources.Sort
+resources=org.apache.tools.ant.types.resources.Resources
+first=org.apache.tools.ant.types.resources.First
+last=org.apache.tools.ant.types.resources.Last
+tarfileset=org.apache.tools.ant.types.TarFileSet
+tokens=org.apache.tools.ant.types.resources.Tokens
+
+#Resources (single-element ResourceCollections):
+resource=org.apache.tools.ant.types.Resource
+file=org.apache.tools.ant.types.resources.FileResource
+url=org.apache.tools.ant.types.resources.URLResource
+string=org.apache.tools.ant.types.resources.StringResource
+zipentry=org.apache.tools.ant.types.resources.ZipResource
+propertyresource=org.apache.tools.ant.types.resources.PropertyResource
+tarentry=org.apache.tools.ant.types.resources.TarResource
+gzipresource=org.apache.tools.ant.types.resources.GZipResource
+bzip2resource=org.apache.tools.ant.types.resources.BZip2Resource
+javaresource=org.apache.tools.ant.types.resources.JavaResource
+
+#tokenizer implementations
+linetokenizer=org.apache.tools.ant.util.LineTokenizer
+stringtokenizer=org.apache.tools.ant.util.StringTokenizer
+filetokenizer=org.apache.tools.ant.util.FileTokenizer
diff --git a/trunk/src/main/org/apache/tools/ant/types/mappers/FilterMapper.java b/trunk/src/main/org/apache/tools/ant/types/mappers/FilterMapper.java
new file mode 100644
index 0000000..391a3f7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/mappers/FilterMapper.java
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.mappers;
+
+import java.io.StringReader;
+import java.io.Reader;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.UnsupportedAttributeException;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.FilterChain;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * This is a FileNameMapper based on a FilterChain.
+ */
+public class FilterMapper extends FilterChain implements FileNameMapper {
+
+    private static final int BUFFER_SIZE = 8192;
+
+    /**
+     * From attribute not supported.
+     * @param from a string
+     * @throws BuildException always
+     */
+    public void setFrom(String from) {
+        throw new UnsupportedAttributeException(
+            "filtermapper doesn't support the \"from\" attribute.", "from");
+    }
+
+    /**
+     * From attribute not supported.
+     * @param to a string
+     * @throws BuildException always
+     */
+    public void setTo(String to) {
+        throw new UnsupportedAttributeException(
+            "filtermapper doesn't support the \"to\" attribute.", "to");
+    }
+
+    /**
+     * Return the result of the filters on the sourcefilename.
+     * @param sourceFileName the filename to map
+     * @return  a one-element array of converted filenames, or null if
+     *          the filterchain returns an empty string.
+     */
+    public String[] mapFileName(String sourceFileName) {
+        try {
+            Reader stringReader = new StringReader(sourceFileName);
+            ChainReaderHelper helper = new ChainReaderHelper();
+            helper.setBufferSize(BUFFER_SIZE);
+            helper.setPrimaryReader(stringReader);
+            helper.setProject(getProject());
+            Vector filterChains = new Vector();
+            filterChains.add(this);
+            helper.setFilterChains(filterChains);
+            String result = FileUtils.safeReadFully(helper.getAssembledReader());
+            if (result.length() == 0) {
+                return null;
+            } else {
+                return new String[] {result};
+            }
+        } catch (BuildException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new BuildException(ex);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java b/trunk/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java
new file mode 100644
index 0000000..3c9bd44
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/AbstractScriptComponent.java
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * This is a {@link ProjectComponent} that has script support built in
+ * Use it as a foundation for scriptable things.
+ */
+public abstract class AbstractScriptComponent extends ProjectComponent {
+    /**
+     * script runner helper
+     */
+    private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+    /**
+     * script runner.
+     */
+    private ScriptRunnerBase   runner = null;
+
+    /**
+     * Set the project.
+     * @param project the owner of this component.
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        helper.setProjectComponent(this);
+    }
+
+    /**
+     * Get our script runner
+     * @return the runner
+     */
+    public ScriptRunnerBase getRunner() {
+        initScriptRunner();
+        return runner;
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        helper.setSrc(file);
+    }
+
+    /**
+     * The script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        helper.addText(text);
+    }
+
+    /**
+     * Defines the manager.
+     *
+     * @param manager the scripting manager.
+     */
+    public void setManager(String manager) {
+        helper.setManager(manager);
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        helper.setLanguage(language);
+    }
+
+    /**
+     * Initialize the script runner. Calls this before running the system
+     */
+    protected void initScriptRunner() {
+        if (runner != null) {
+            return;
+        }
+        helper.setProjectComponent(this);
+        runner = helper.getScriptRunner();
+    }
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        helper.setClasspath(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        return helper.createClasspath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        helper.setClasspathRef(r);
+    }
+
+    /**
+     * Run a script
+     * @param execName name of the script
+     */
+    protected void executeScript(String execName) {
+        getRunner().executeScript(execName);
+    }
+
+    /**
+     * Evaluate a script.
+     * @param execName name of the script.
+     * @return the result of the evaluation.
+     */
+    protected Object evaluateScript(String execName) {
+        return getRunner().evaluateScript(execName);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/ScriptCondition.java b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptCondition.java
new file mode 100644
index 0000000..d5d3ce7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptCondition.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+/**
+ * A condition that lets you include script.
+ * The condition component sets a bean "self", whose attribute "value"
+ * must be set to true for the condition to succeed, false to fail.
+ * The default is 'false'
+ */
+public class ScriptCondition extends AbstractScriptComponent implements Condition {
+
+    /**
+     * result field
+     */
+    private boolean value = false;
+
+    /**
+     * Is this condition true?
+     *
+     * @return true if the condition is true
+     *
+     * @throws org.apache.tools.ant.BuildException
+     *          if an error occurs
+     */
+    public boolean eval() throws BuildException {
+        initScriptRunner();
+        Object result = evaluateScript("ant_condition");
+        return result instanceof Boolean ? ((Boolean) result).booleanValue() : getValue();
+    }
+
+    /**
+     * get the current value of the conditon
+     * @return true if the condition
+     */
+    public boolean getValue() {
+        return value;
+    }
+
+    /**
+     * set the value of the condition.
+     * This is used by the script to pass the return value.
+     * It can be used by an attribute, in which case it sets the default
+     * value
+     * @param value the value to set the condition to
+     */
+    public void setValue(boolean value) {
+        this.value = value;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java
new file mode 100644
index 0000000..27f748c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptFilter.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.optional;
+
+import org.apache.tools.ant.filters.TokenFilter;
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * Most of this is CAP (Cut And Paste) from the Script task
+ * ScriptFilter class, implements TokenFilter.Filter
+ * for scripts to use.
+ * This provides the same beans as the Script Task
+ * to a script.
+ * The script is meant to use get self.token and
+ * set self.token in the reply.
+ *
+ * @since Ant 1.6
+ */
+public class ScriptFilter extends TokenFilter.ChainableReaderFilter {
+    /** script runner helper */
+    private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+    /** script runner. */
+    private ScriptRunnerBase   runner = null;
+
+    /** the token used by the script */
+    private String token;
+
+    /**
+     * Set the project.
+     * @param project the owner of this component.
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        helper.setProjectComponent(this);
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        helper.setLanguage(language);
+    }
+
+    /**
+     * Initialize.
+     *
+     * @exception BuildException if someting goes wrong
+     */
+    private void init() throws BuildException {
+        if (runner != null) {
+            return;
+        }
+        runner = helper.getScriptRunner();
+    }
+
+    /**
+     * The current token
+     *
+     * @param token the string filtered by the script
+     */
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    /**
+     * The current token
+     *
+     * @return the string filtered by the script
+     */
+    public String getToken() {
+        return token;
+    }
+
+    /**
+     * Called filter the token.
+     * This sets the token in this object, calls
+     * the script and returns the token.
+     *
+     * @param token the token to be filtered
+     * @return the filtered token
+     */
+    public String filter(String token) {
+        init();
+        setToken(token);
+        runner.executeScript("ant_filter");
+        return getToken();
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        helper.setSrc(file);
+    }
+
+    /**
+     * The script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        helper.addText(text);
+    }
+
+    /**
+     * Defines the manager.
+     *
+     * @param manager the scripting manager.
+     */
+    public void setManager(String manager) {
+        helper.setManager(manager);
+    }
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        helper.setClasspath(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        return helper.createClasspath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        helper.setClasspathRef(r);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/ScriptMapper.java b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptMapper.java
new file mode 100644
index 0000000..dff7115
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptMapper.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional;
+
+import org.apache.tools.ant.util.FileNameMapper;
+
+import java.util.ArrayList;
+
+/**
+ * Script support at map time.
+ * @since Ant1.7
+ */
+public class ScriptMapper extends AbstractScriptComponent implements FileNameMapper {
+
+
+    private ArrayList files;
+    static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+
+    /**
+     * Sets the from part of the transformation rule.
+     *
+     * @param from a string.
+     */
+    public void setFrom(String from) {
+
+    }
+
+    /**
+     * Sets the to part of the transformation rule.
+     *
+     * @param to a string.
+     */
+    public void setTo(String to) {
+
+    }
+
+    /**
+     * Reset the list of files
+     */
+    public void clear() {
+        files = new ArrayList(1);
+    }
+
+    /**
+     * Add a mapped name
+     * @param mapping the value to use.
+     */
+    public void addMappedName(String mapping) {
+        files.add(mapping);
+    }
+
+    /**
+     * Returns an array containing the target filename(s) for the given source
+     * file.
+     * <p/>
+     * <p>if the given rule doesn't apply to the source file, implementation
+     * must return null. SourceFileScanner will then omit the source file in
+     * question.</p>
+     *
+     * @param sourceFileName the name of the source file relative to some given
+     *                       basedirectory.
+     * @return an array of strings if the rule applies to the source file, or
+     *         null if it does not.
+     */
+
+    public String[] mapFileName(String sourceFileName) {
+        initScriptRunner();
+        getRunner().addBean("source", sourceFileName);
+        clear();
+        executeScript("ant_mapper");
+        if (files.size() == 0) {
+            return null;
+        } else {
+            return (String[]) files.toArray(EMPTY_STRING_ARRAY);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java
new file mode 100644
index 0000000..ca28f69
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/ScriptSelector.java
@@ -0,0 +1,223 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.selectors.BaseSelector;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ScriptRunnerHelper;
+
+/**
+ * Selector that lets you run a script with selection logic inline
+ * @since Ant1.7
+ */
+public class ScriptSelector extends BaseSelector {
+
+    /**
+     * script runner helper
+     */
+    private ScriptRunnerHelper helper = new ScriptRunnerHelper();
+
+    /**
+     * script runner
+     */
+    private ScriptRunnerBase runner;
+
+    /**
+     * fields updated for every selection
+     */
+    private File basedir;
+    private String filename;
+    private File file;
+
+    /**
+     * selected flag
+     */
+    private boolean selected;
+
+    /**
+     * Set the project.
+     * @param project the owner of this component.
+     */
+    public void setProject(Project project) {
+        super.setProject(project);
+        helper.setProjectComponent(this);
+    }
+
+    /**
+     * Defines the manager.
+     *
+     * @param manager the scripting manager.
+     */
+    public void setManager(String manager) {
+        helper.setManager(manager);
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        helper.setLanguage(language);
+    }
+
+    /**
+     * Initialize on demand.
+     *
+     * @throws org.apache.tools.ant.BuildException
+     *          if someting goes wrong
+     */
+    private void init() throws BuildException {
+        if (runner != null) {
+            return;
+        }
+        runner = helper.getScriptRunner();
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        helper.setSrc(file);
+    }
+
+    /**
+     * The script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        helper.addText(text);
+    }
+
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        helper.setClasspath(classpath);
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        return helper.createClasspath();
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        helper.setClasspathRef(r);
+    }
+
+    /**
+     * Set the setbeans attribute.
+     * If this is true, &lt;script&gt; will create variables in the
+     * script instance for all
+     * properties, targets and references of the current project.
+     * It this is false, only the project and self variables will
+     * be set.
+     * The default is true.
+     * @param setBeans the value to set.
+     */
+    public void setSetBeans(boolean setBeans) {
+        helper.setSetBeans(setBeans);
+    }
+
+    /**
+     * Method that each selector will implement to create their selection
+     * behaviour. If there is a problem with the setup of a selector, it can
+     * throw a BuildException to indicate the problem.
+     *
+     * @param basedir  A java.io.File object for the base directory
+     * @param filename The name of the file to check
+     * @param file     A File object for this filename
+     *
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        init();
+        setSelected(true);
+        this.file = file;
+        this.basedir = basedir;
+        this.filename = filename;
+        runner.addBean("basedir", basedir);
+        runner.addBean("filename", filename);
+        runner.addBean("file", file);
+        runner.executeScript("ant_selector");
+        return isSelected();
+    }
+
+    /**
+     * get the base directory
+     * @return the base directory
+     */
+    public File getBasedir() {
+        return basedir;
+    }
+
+    /**
+     * get the filename of the file
+     * @return the filename of the file that is currently been tested
+     */
+    public String getFilename() {
+        return filename;
+    }
+
+    /**
+     * get the file that is currently to be tested
+     * @return the file that is currently been tested
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * get state of selected flag
+     * @return the selected flag
+     */
+    public boolean isSelected() {
+        return selected;
+    }
+
+    /**
+     * set the selected state
+     * Intended for script use, not as an Ant attribute
+     * @param selected the selected state
+     */
+    public void setSelected(boolean selected) {
+        this.selected = selected;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java b/trunk/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java
new file mode 100644
index 0000000..6cc873b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/depend/ClassfileSet.java
@@ -0,0 +1,163 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.depend;
+
+import java.util.Vector;
+import java.util.Enumeration;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * A ClassfileSet is a FileSet that enlists all classes that depend on a
+ * certain set of root classes.
+ *
+ * ClassfileSet extends FileSet, its inherited properties
+ * defining the domain searched for dependent classes.
+ *
+ */
+public class ClassfileSet extends FileSet {
+    /**
+     * The list of root classes for this class file set. These are the
+     * classes which must be included in the fileset and which are the
+     * starting point for the dependency search.
+     */
+    private Vector rootClasses = new Vector();
+
+    /**
+     * The list of filesets which contain root classes.
+     */
+    private Vector rootFileSets = new Vector();
+
+    /**
+     * Inner class used to contain info about root classes.
+     */
+    public static class ClassRoot {
+        /** The name of the root class */
+        private String rootClass;
+
+        /**
+         * Set the root class name.
+         *
+         * @param name the name of the root class.
+         */
+        public void setClassname(String name) {
+            this.rootClass = name;
+        }
+
+        /**
+         * Get the name of the root class.
+         *
+         * @return the name of the root class.
+         */
+        public String getClassname() {
+            return rootClass;
+        }
+    }
+
+    /**
+     * Default constructor.
+     */
+    public ClassfileSet() {
+    }
+
+    /**
+     * Add a fileset to which contains a collection of root classes used to
+     * drive the search from classes.
+     *
+     * @param rootFileSet a root file set to be used to search for dependent
+     * classes.
+     */
+    public void addRootFileset(FileSet rootFileSet) {
+        rootFileSets.addElement(rootFileSet);
+    }
+
+    /**
+     * Create a ClassfileSet from another ClassfileSet.
+     *
+     * @param s the other classfileset.
+     */
+    protected ClassfileSet(ClassfileSet s) {
+        super(s);
+        rootClasses = (Vector) s.rootClasses.clone();
+    }
+
+    /**
+     * Set the root class attribute.
+     *
+     * @param rootClass the name of the root class.
+     */
+    public void setRootClass(String rootClass) {
+        rootClasses.addElement(rootClass);
+    }
+
+    /**
+     * Return the DirectoryScanner associated with this FileSet.
+     *
+     * @param p the project used to resolve dirs, etc.
+     *
+     * @return a dependency scanner.
+     */
+    public DirectoryScanner getDirectoryScanner(Project p) {
+        if (isReference()) {
+            return getRef(p).getDirectoryScanner(p);
+        }
+        Vector allRootClasses = (Vector) rootClasses.clone();
+        for (Enumeration e = rootFileSets.elements(); e.hasMoreElements();) {
+            FileSet additionalRootSet = (FileSet) e.nextElement();
+            DirectoryScanner additionalScanner
+                = additionalRootSet.getDirectoryScanner(p);
+            String[] files = additionalScanner.getIncludedFiles();
+            for (int i = 0; i < files.length; ++i) {
+                if (files[i].endsWith(".class")) {
+                    String classFilePath = StringUtils.removeSuffix(files[i], ".class");
+                    String className
+                        = classFilePath.replace('/', '.').replace('\\', '.');
+                    allRootClasses.addElement(className);
+                }
+            }
+        }
+        DirectoryScanner parentScanner = super.getDirectoryScanner(p);
+        DependScanner scanner = new DependScanner(parentScanner);
+        scanner.setBasedir(getDir(p));
+        scanner.setRootClasses(allRootClasses);
+        scanner.scan();
+        return scanner;
+    }
+
+    /**
+     * Add a nested root class definition to this class file set.
+     *
+     * @param root the configured class root.
+     */
+    public void addConfiguredRoot(ClassRoot root) {
+        rootClasses.addElement(root.getClassname());
+    }
+
+    /**
+     * Clone this data type.
+     *
+     * @return a clone of the class file set.
+     */
+    public Object clone() {
+        return new ClassfileSet(isReference()
+            ? (ClassfileSet) (getRef(getProject())) : this);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java b/trunk/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java
new file mode 100644
index 0000000..47a81f7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/depend/DependScanner.java
@@ -0,0 +1,213 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.depend;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.depend.DependencyAnalyzer;
+
+
+/**
+ * DirectoryScanner for finding class dependencies.
+ */
+public class DependScanner extends DirectoryScanner {
+    /**
+     * The name of the analyzer to use by default.
+     */
+    public static final String DEFAULT_ANALYZER_CLASS
+        = "org.apache.tools.ant.util.depend.bcel.FullAnalyzer";
+
+    /**
+     * The root classes to drive the search for dependent classes.
+     */
+    private Vector rootClasses;
+
+    /**
+     * The names of the classes to include in the fileset.
+     */
+    private Vector included;
+
+    /**
+     * The parent scanner which gives the basic set of files. Only files which
+     * are in this set and which can be reached from a root class will end
+     * up being included in the result set.
+     */
+    private DirectoryScanner parentScanner;
+
+    /**
+     * Create a DependScanner, using the given scanner to provide the basic
+     * set of files from which class files come.
+     *
+     * @param parentScanner the DirectoryScanner which returns the files from
+     *        which class files must come.
+     */
+    public DependScanner(DirectoryScanner parentScanner) {
+        this.parentScanner = parentScanner;
+    }
+
+    /**
+     * Sets the root classes to be used to drive the scan.
+     *
+     * @param rootClasses the rootClasses to be used for this scan.
+     */
+    public synchronized void setRootClasses(Vector rootClasses) {
+        this.rootClasses = rootClasses;
+    }
+
+    /**
+     * Get the names of the class files on which baseClass depends.
+     *
+     * @return the names of the files.
+     */
+    public String[] getIncludedFiles() {
+        String[] files = new String[getIncludedFilesCount()];
+        for (int i = 0; i < files.length; i++) {
+            files[i] = (String) included.elementAt(i);
+        }
+        return files;
+    }
+
+    /** {@inheritDoc}. */
+    public synchronized int getIncludedFilesCount() {
+        if (included == null) {
+            throw new IllegalStateException();
+        }
+        return included.size();
+    }
+
+    /**
+     * Scans the base directory for files on which baseClass depends.
+     *
+     * @exception IllegalStateException when basedir was set incorrectly.
+     */
+    public synchronized void scan() throws IllegalStateException {
+        included = new Vector();
+        String analyzerClassName = DEFAULT_ANALYZER_CLASS;
+        DependencyAnalyzer analyzer = null;
+        try {
+            Class analyzerClass = Class.forName(analyzerClassName);
+            analyzer = (DependencyAnalyzer) analyzerClass.newInstance();
+        } catch (Exception e) {
+            throw new BuildException("Unable to load dependency analyzer: "
+                + analyzerClassName, e);
+        }
+        analyzer.addClassPath(new Path(null, basedir.getPath()));
+
+        for (Enumeration e = rootClasses.elements(); e.hasMoreElements();) {
+            String rootClass = (String) e.nextElement();
+            analyzer.addRootClass(rootClass);
+        }
+        Enumeration e = analyzer.getClassDependencies();
+
+        String[] parentFiles = parentScanner.getIncludedFiles();
+        Hashtable parentSet = new Hashtable();
+        for (int i = 0; i < parentFiles.length; ++i) {
+            parentSet.put(parentFiles[i], parentFiles[i]);
+        }
+        while (e.hasMoreElements()) {
+            String classname = (String) e.nextElement();
+            String filename = classname.replace('.', File.separatorChar);
+            filename = filename + ".class";
+            File depFile = new File(basedir, filename);
+            if (depFile.exists() && parentSet.containsKey(filename)) {
+                // This is included
+                included.addElement(filename);
+            }
+        }
+    }
+
+    /**
+     * @see DirectoryScanner#addDefaultExcludes
+     */
+    public void addDefaultExcludes() {
+    }
+
+    /**
+     * @see DirectoryScanner#getExcludedDirectories
+     */
+    /** {@inheritDoc}. */
+    public String[] getExcludedDirectories() {
+        return null;
+    }
+
+    /**
+     * @see DirectoryScanner#getExcludedFiles
+     */
+    /** {@inheritDoc}. */
+    public String[] getExcludedFiles() {
+        return null;
+    }
+
+    /**
+     * @see DirectoryScanner#getIncludedDirectories
+     */
+    /** {@inheritDoc}. */
+    public String[] getIncludedDirectories() {
+        return new String[0];
+    }
+
+    /**
+     * @see DirectoryScanner#getIncludedDirsCount
+     */
+    /** {@inheritDoc}. */
+    public int getIncludedDirsCount() {
+        return 0;
+    }
+
+    /**
+     * @see DirectoryScanner#getNotIncludedDirectories
+     */
+    /** {@inheritDoc}. */
+    public String[] getNotIncludedDirectories() {
+        return null;
+    }
+
+    /**
+     * @see DirectoryScanner#getNotIncludedFiles
+     */
+    /** {@inheritDoc}. */
+    public String[] getNotIncludedFiles() {
+        return null;
+    }
+
+    /**
+     * @see DirectoryScanner#setExcludes
+     */
+    /** {@inheritDoc}. */
+    public void setExcludes(String[] excludes) {
+    }
+
+    /**
+     * @see DirectoryScanner#setIncludes
+     */
+    /** {@inheritDoc}. */
+    public void setIncludes(String[] includes) {
+    }
+
+    /**
+     * @see DirectoryScanner#setCaseSensitive
+     */
+    /** {@inheritDoc}. */
+    public void setCaseSensitive(boolean isCaseSensitive) {
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Arc.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Arc.java
new file mode 100644
index 0000000..6f64d1a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Arc.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.geom.Arc2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * Draw an arc.
+ */
+public class Arc extends BasicShape implements DrawOperation {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected int width = 0;
+    protected int height = 0;
+    protected int start = 0;
+    protected int stop = 0;
+    protected int type = Arc2D.OPEN;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the width.
+     * @param width the width of the arc.
+     */
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    /**
+     * Set the height.
+     * @param height the height of the arc.
+     */
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    /**
+     * Set the start of the arc.
+     * @param start the start of the arc.
+     */
+    public void setStart(int start) {
+        this.start = start;
+    }
+
+    /**
+     * Set the stop of the arc.
+     * @param stop the stop of the arc.
+     */
+    public void setStop(int stop) {
+        this.stop = stop;
+    }
+
+    /**
+     * Set the type of arc.
+     * @param strType the type to use - open, pie or chord.
+     * @todo refactor using an EnumeratedAttribute
+     */
+    public void setType(String strType) {
+        if (strType.toLowerCase().equals("open")) {
+            type = Arc2D.OPEN;
+        } else if (strType.toLowerCase().equals("pie")) {
+            type = Arc2D.PIE;
+        } else if (strType.toLowerCase().equals("chord")) {
+            type = Arc2D.CHORD;
+        }
+    }
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeDrawOperation() {
+        BufferedImage bi = new BufferedImage(width + (stroke_width * 2),
+            height + (stroke_width * 2), BufferedImage.TYPE_4BYTE_ABGR_PRE);
+
+        Graphics2D graphics = (Graphics2D) bi.getGraphics();
+
+        if (!stroke.equals("transparent")) {
+            BasicStroke bStroke = new BasicStroke(stroke_width);
+            graphics.setColor(ColorMapper.getColorByName(stroke));
+            graphics.setStroke(bStroke);
+            graphics.draw(new Arc2D.Double(stroke_width, stroke_width, width,
+                height, start, stop, type));
+        }
+
+        if (!fill.equals("transparent")) {
+            graphics.setColor(ColorMapper.getColorByName(fill));
+            graphics.fill(new Arc2D.Double(stroke_width, stroke_width,
+                width, height, start, stop, type));
+        }
+
+
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                PlanarImage img = ((DrawOperation) instr).executeDrawOperation();
+                graphics.drawImage(img.getAsBufferedImage(), null, 0, 0);
+            } else if (instr instanceof TransformOperation) {
+                graphics = (Graphics2D) bi.getGraphics();
+                PlanarImage image = ((TransformOperation) instr)
+                    .executeTransformOperation(PlanarImage.wrapRenderedImage(bi));
+                bi = image.getAsBufferedImage();
+            }
+        }
+        return PlanarImage.wrapRenderedImage(bi);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/BasicShape.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/BasicShape.java
new file mode 100644
index 0000000..ee2113a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/BasicShape.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+
+/** Draw a basic shape */
+public abstract class BasicShape extends ImageOperation implements DrawOperation {
+    // CheckStyle:VisibilityModifier OFF - bc
+    // CheckStyle:MemberNameCheck OFF - bc
+    protected int stroke_width = 0;
+    // CheckStyle:MemberNameCheck ON
+    protected String fill = "transparent";
+    protected String stroke = "black";
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     * Set the fill attribute.
+     * @param col the color value to use.
+     */
+    public void setFill(String col) {
+        fill = col;
+    }
+
+    /**
+     * Set the stroke attribute.
+     * @param col the color value to use.
+     */
+    public void setStroke(String col) {
+        stroke = col;
+    }
+
+    /**
+     * Set the stroke width attribute.
+     * @param width the value to use.
+     */
+    public void setStrokewidth(int width) {
+        stroke_width = width;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/ColorMapper.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/ColorMapper.java
new file mode 100644
index 0000000..ec01a8d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/ColorMapper.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import java.awt.Color;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public final class ColorMapper {
+    /** private constructor for Utility class */
+    private ColorMapper() {
+    }
+
+    /** black string */
+    public static final String COLOR_BLACK = "black";
+    /** blue string */
+    public static final String COLOR_BLUE = "blue";
+    /** cyan string */
+    public static final String COLOR_CYAN = "cyan";
+    /** black string */
+    public static final String COLOR_DARKGRAY = "darkgray";
+    /** gray string */
+    public static final String COLOR_GRAY = "gray";
+    /** lightgray string */
+    public static final String COLOR_LIGHTGRAY = "lightgray";
+    // Gotta atleast put in the proper spelling :-P
+    /** darkgrey string */
+    public static final String COLOR_DARKGREY = "darkgrey";
+    /** grey string */
+    public static final String COLOR_GREY = "grey";
+    /** lightgrey string */
+    public static final String COLOR_LIGHTGREY = "lightgrey";
+    /** green string */
+    public static final String COLOR_GREEN = "green";
+    /** magenta string */
+    public static final String COLOR_MAGENTA = "magenta";
+    /** orange string */
+    public static final String COLOR_ORANGE = "orange";
+    /** pink string */
+    public static final String COLOR_PINK = "pink";
+    /** reg string */
+    public static final String COLOR_RED = "red";
+    /** white string */
+    public static final String COLOR_WHITE = "white";
+    /** yellow string */
+    public static final String COLOR_YELLOW = "yellow";
+
+    /**
+     * Convert a color name to a color value.
+     * @param colorName a string repr of the color.
+     * @return the color value.
+     * @todo refactor to use an EnumeratedAttribute (maybe?)
+     */
+    public static Color getColorByName(String colorName) {
+        colorName = colorName.toLowerCase();
+
+        if (colorName.equals(COLOR_BLACK)) {
+            return Color.black;
+        } else if (colorName.equals(COLOR_BLUE)) {
+            return Color.blue;
+        } else if (colorName.equals(COLOR_CYAN)) {
+            return Color.cyan;
+        } else if (colorName.equals(COLOR_DARKGRAY) || colorName.equals(COLOR_DARKGREY)) {
+            return Color.darkGray;
+        } else if (colorName.equals(COLOR_GRAY) || colorName.equals(COLOR_GREY)) {
+            return Color.gray;
+        } else if (colorName.equals(COLOR_LIGHTGRAY) || colorName.equals(COLOR_LIGHTGREY)) {
+            return Color.lightGray;
+        } else if (colorName.equals(COLOR_GREEN)) {
+            return Color.green;
+        } else if (colorName.equals(COLOR_MAGENTA)) {
+            return Color.magenta;
+        } else if (colorName.equals(COLOR_ORANGE)) {
+            return Color.orange;
+        } else if (colorName.equals(COLOR_PINK)) {
+            return Color.pink;
+        } else if (colorName.equals(COLOR_RED)) {
+            return Color.red;
+        } else if (colorName.equals(COLOR_WHITE)) {
+            return Color.white;
+        } else if (colorName.equals(COLOR_YELLOW)) {
+            return Color.yellow;
+        }
+        return Color.black;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Draw.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Draw.java
new file mode 100644
index 0000000..b46ae41
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Draw.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Draw extends TransformOperation {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected int xloc = 0;
+    protected int yloc = 0;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the X location.
+     * @param x the value to use.
+     */
+    public void setXloc(int x) {
+        xloc = x;
+    }
+
+    /**
+     * Set the Y location.
+     * @param y the value to use.
+     */
+    public void setYloc(int y) {
+        yloc = y;
+    }
+
+    /** {@inheritDoc}. */
+    public void addRectangle(Rectangle rect) {
+        instructions.add(rect);
+    }
+
+    /** {@inheritDoc}. */
+    public void addText(Text text) {
+        instructions.add(text);
+    }
+
+    /**
+     * Add an ellipse.
+     * @param elip the ellipse to add.
+     */
+    public void addEllipse(Ellipse elip) {
+        instructions.add(elip);
+    }
+
+    /**
+     * Add an arc.
+     * @param arc the arc to add.
+     */
+    public void addArc(Arc arc) {
+        instructions.add(arc);
+    }
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeTransformOperation(PlanarImage image) {
+        BufferedImage bi = image.getAsBufferedImage();
+        Graphics2D graphics = (Graphics2D) bi.getGraphics();
+
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                PlanarImage op = ((DrawOperation) instr).executeDrawOperation();
+                log("\tDrawing to x=" + xloc + " y=" + yloc);
+                graphics.drawImage(op.getAsBufferedImage(), null, xloc, yloc);
+            } else if (instr instanceof TransformOperation) {
+                PlanarImage op
+                    = ((TransformOperation) instr).executeTransformOperation(null);
+                BufferedImage child = op.getAsBufferedImage();
+                log("\tDrawing to x=" + xloc + " y=" + yloc);
+                graphics.drawImage(child, null, xloc, yloc);
+                PlanarImage.wrapRenderedImage(bi);
+            }
+        }
+        image = PlanarImage.wrapRenderedImage(bi);
+
+        return image;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/DrawOperation.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/DrawOperation.java
new file mode 100644
index 0000000..7b6736a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/DrawOperation.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+
+/**
+ * Interface which represents an Operation which is "drawable", such
+ * as a Rectangle, Circle or Text.  The Operation is responsible for
+ * creating its own image buffer and drawing itself into it, then
+ * wrapping and returning it as a PlanarImage.  This allows multible
+ * "drawable" objects to be nested.
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public interface DrawOperation {
+    /**
+     * Abstract method which is intended to create an image buffer
+     * and return it so it can be drawn into another object.  Use
+     * an Alpha channel for a "transparent" background.
+     * @return a planar image
+     */
+    PlanarImage executeDrawOperation();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Ellipse.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Ellipse.java
new file mode 100644
index 0000000..f4701e1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Ellipse.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * Draw an ellipse.
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Ellipse extends BasicShape implements DrawOperation {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected int width = 0;
+    protected int height = 0;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the width.
+     * @param width the width of the elipse.
+     */
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    /**
+     * Set the height.
+     * @param height the height of the elipse.
+     */
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeDrawOperation() {
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+
+        Graphics2D graphics = (Graphics2D) bi.getGraphics();
+
+        if (!stroke.equals("transparent")) {
+            BasicStroke bStroke = new BasicStroke(stroke_width);
+            graphics.setColor(ColorMapper.getColorByName(stroke));
+            graphics.setStroke(bStroke);
+            graphics.draw(new Ellipse2D.Double(0, 0, width, height));
+        }
+
+        if (!fill.equals("transparent")) {
+            graphics.setColor(ColorMapper.getColorByName(fill));
+            graphics.fill(new Ellipse2D.Double(0, 0, width, height));
+        }
+
+
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                PlanarImage img = ((DrawOperation) instr).executeDrawOperation();
+                graphics.drawImage(img.getAsBufferedImage(), null, 0, 0);
+            } else if (instr instanceof TransformOperation) {
+                graphics = (Graphics2D) bi.getGraphics();
+                PlanarImage image = ((TransformOperation) instr)
+                    .executeTransformOperation(PlanarImage.wrapRenderedImage(bi));
+                bi = image.getAsBufferedImage();
+            }
+        }
+        return PlanarImage.wrapRenderedImage(bi);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/ImageOperation.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/ImageOperation.java
new file mode 100644
index 0000000..df6c848
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/ImageOperation.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import org.apache.tools.ant.types.DataType;
+import java.util.Vector;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public abstract class ImageOperation extends DataType {
+     // CheckStyle:VisibilityModifier OFF - bc
+    protected Vector instructions = new Vector();
+     // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Add a rotate to the operation.
+     * @param instr the rotate to add.
+     */
+    public void addRotate(Rotate instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a draw to the operation.
+     * @param instr the draw to add.
+     */
+    public void addDraw(Draw instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a rectangle to the operation.
+     * @param instr the rectangle to add.
+     */
+    public void addRectangle(Rectangle instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add text to the operation.
+     * @param instr the text to add.
+     */
+    public void addText(Text instr) {
+        instructions.add(instr);
+    }
+
+    /**
+     * Add a scale to the operation.
+     * @param instr the scale to add.
+     */
+    public void addScale(Scale instr) {
+        instructions.add(instr);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Rectangle.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Rectangle.java
new file mode 100644
index 0000000..f3204e7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Rectangle.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import java.awt.BasicStroke;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Rectangle extends BasicShape implements DrawOperation {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected int width = 0;
+    protected int height = 0;
+    protected int arcwidth = 0;
+    protected int archeight = 0;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Set the width.
+     * @param w the value to use.
+     */
+    public void setWidth(int w) {
+        width = w;
+    }
+
+    /**
+     * Set the height.
+     * @param h the value to use.
+     */
+    public void setHeight(int h) {
+        height = h;
+    }
+
+    /**
+     * Set the arc width.
+     * @param w the value to use.
+     */
+    public void setArcwidth(int w) {
+        arcwidth = w;
+    }
+
+    /**
+     * Set the arc height.
+     * @param h the value to use.
+     */
+    public void setArcheight(int h) {
+        archeight = h;
+    }
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeDrawOperation() {
+        log("\tCreating Rectangle w=" + width + " h=" + height + " arcw="
+            + arcwidth + " arch=" + archeight);
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+
+        Graphics2D graphics = (Graphics2D) bi.getGraphics();
+
+        if (!stroke.equals("transparent")) {
+            BasicStroke bStroke = new BasicStroke(stroke_width);
+            graphics.setColor(ColorMapper.getColorByName(stroke));
+            graphics.setStroke(bStroke);
+
+            if ((arcwidth != 0) || (archeight != 0)) {
+                graphics.drawRoundRect(0, 0, width, height, arcwidth, archeight);
+            } else {
+                graphics.drawRect(0, 0, width, height);
+            }
+        }
+
+        if (!fill.equals("transparent")) {
+            graphics.setColor(ColorMapper.getColorByName(fill));
+            if ((arcwidth != 0) || (archeight != 0)) {
+                graphics.fillRoundRect(stroke_width, stroke_width,
+                    width - (stroke_width * 2), height - (stroke_width * 2),
+                    arcwidth, archeight);
+            } else {
+                graphics.fillRect(stroke_width, stroke_width,
+                    width - (stroke_width * 2), height - (stroke_width * 2));
+            }
+        }
+
+
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                PlanarImage img = ((DrawOperation) instr).executeDrawOperation();
+                graphics.drawImage(img.getAsBufferedImage(), null, 0, 0);
+            } else if (instr instanceof TransformOperation) {
+                graphics = (Graphics2D) bi.getGraphics();
+                PlanarImage image
+                    = ((TransformOperation) instr)
+                    .executeTransformOperation(PlanarImage.wrapRenderedImage(bi));
+                bi = image.getAsBufferedImage();
+            }
+        }
+        return PlanarImage.wrapRenderedImage(bi);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Rotate.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Rotate.java
new file mode 100644
index 0000000..e20ded1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Rotate.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import javax.media.jai.InterpolationNearest;
+import javax.media.jai.JAI;
+import java.awt.image.renderable.ParameterBlock;
+import java.awt.image.BufferedImage;
+import java.awt.Graphics2D;
+
+/**
+ * ImageOperation to rotate an image by a certain degree
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Rotate extends TransformOperation implements DrawOperation {
+    private static final float HALF_CIRCLE = 180.0F;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected float angle = 0.0F;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Sets the angle of rotation in degrees.
+     * @param ang The angle at which to rotate the image
+     */
+    public void setAngle(String ang) {
+        angle = Float.parseFloat(ang);
+    }
+
+
+    /**
+     * Rotate an image.
+     * @param image the image to rotate.
+     * @return the rotated image.
+     */
+    public PlanarImage performRotate(PlanarImage image) {
+        float tAngle = (float) (angle * (Math.PI / HALF_CIRCLE));
+        ParameterBlock pb = new ParameterBlock();
+        pb.addSource(image);
+        pb.add(0.0F);
+        pb.add(0.0F);
+        pb.add(tAngle);
+        pb.add(new InterpolationNearest());
+        return JAI.create("Rotate", pb, null);
+    }
+
+
+    /**
+     * Performs the image rotation when being handled as a TransformOperation.
+     * @param image The image to perform the transformation on.
+     * @return the transformed image.
+     */
+    public PlanarImage executeTransformOperation(PlanarImage image) {
+        BufferedImage bi = null;
+        Graphics2D graphics = null;
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                System.out.println("Execing Draws");
+                PlanarImage op = ((DrawOperation) instr).executeDrawOperation();
+                image = performRotate(op);
+                return image;
+            } else if (instr instanceof TransformOperation) {
+                bi = image.getAsBufferedImage();
+                graphics = (Graphics2D) bi.getGraphics();
+                System.out.println("Execing Transforms");
+                image = ((TransformOperation) instr)
+                    .executeTransformOperation(PlanarImage.wrapRenderedImage(bi));
+                bi = image.getAsBufferedImage();
+            }
+        }
+        System.out.println("Execing as TransformOperation");
+        image = performRotate(image);
+        System.out.println(image);
+        return image;
+    }
+
+    /**
+     *  Performs the image rotation when being handled as a DrawOperation.
+     *  It absolutely requires that there be a DrawOperation nested beneath it,
+     *  but only the FIRST DrawOperation will be handled since it can only return
+     *  ONE image.
+     * @return the image.
+     */
+    public PlanarImage executeDrawOperation() {
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                PlanarImage op = ((DrawOperation) instr).executeDrawOperation();
+                op = performRotate(op);
+                return op;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Scale.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Scale.java
new file mode 100644
index 0000000..0b279e2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Scale.java
@@ -0,0 +1,178 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+import javax.media.jai.JAI;
+import javax.media.jai.PlanarImage;
+import java.awt.image.BufferedImage;
+import java.awt.image.renderable.ParameterBlock;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Scale extends TransformOperation implements DrawOperation {
+    private static final int HUNDRED = 100;
+
+    private String widthStr = "100%";
+    private String heightStr = "100%";
+    private boolean xPercent = true;
+    private boolean yPercent = true;
+    private String proportions = "ignore";
+
+    /** Enumerated class for proportions attribute. */
+    public static class ProportionsAttribute extends EnumeratedAttribute {
+        /** {@inheritDoc}. */
+        public String[] getValues() {
+            return new String[] {"ignore", "width", "height", "cover", "fit"};
+        }
+    }
+
+    /**
+     *  Sets the behaviour regarding the image proportions.
+     * @param pa the enumerated value.
+     */
+    public void setProportions(ProportionsAttribute pa) {
+        proportions = pa.getValue();
+    }
+
+    /**
+     * Sets the width of the image, either as an integer or a %.
+     * Defaults to 100%.
+     * @param width the value to use.
+     */
+    public void setWidth(String width) {
+        widthStr = width;
+    }
+
+    /**
+     *  Sets the height of the image, either as an integer or a %.  Defaults to 100%.
+     * @param height the value to use.
+     */
+    public void setHeight(String height) {
+        heightStr = height;
+    }
+
+    /**
+     * Get the width.
+     * @return the value converted from the width string.
+     */
+    public float getWidth() {
+        float width = 0.0F;
+        int percIndex = widthStr.indexOf('%');
+        if (percIndex > 0) {
+            width = Float.parseFloat(widthStr.substring(0, percIndex));
+            xPercent = true;
+            return width / HUNDRED;
+        } else {
+            xPercent = false;
+            return Float.parseFloat(widthStr);
+        }
+    }
+
+    /**
+     * Get the height.
+     * @return the value converted from the height string.
+     */
+    public float getHeight() {
+        int percIndex = heightStr.indexOf('%');
+        if (percIndex > 0) {
+            float height = Float.parseFloat(heightStr.substring(0, percIndex));
+            yPercent = true;
+            return height / HUNDRED;
+        } else {
+            yPercent = false;
+            return Float.parseFloat(heightStr);
+        }
+    }
+
+    /**
+     * Scale an image.
+     * @param image the image to scale.
+     * @return the scaled image.
+     */
+    public PlanarImage performScale(PlanarImage image) {
+        ParameterBlock pb = new ParameterBlock();
+        pb.addSource(image);
+        float xFl = getWidth();
+        float yFl = getHeight();
+
+        if (!xPercent) {
+            xFl = (xFl / image.getWidth());
+        }
+        if (!yPercent) {
+            yFl = (yFl / image.getHeight());
+        }
+
+        if ("width".equals(proportions)) {
+            yFl = xFl;
+        } else if ("height".equals(proportions)) {
+            xFl = yFl;
+        } else if ("fit".equals(proportions)) {
+            yFl = Math.min(xFl, yFl);
+            xFl = yFl;
+        } else if ("cover".equals(proportions)) {
+            yFl = Math.max(xFl, yFl);
+            xFl = yFl;
+        }
+
+        pb.add(new Float(xFl));
+        pb.add(new Float(yFl));
+
+        log("\tScaling to " + (xFl * HUNDRED) + "% x "
+            + (yFl * HUNDRED) + "%");
+
+        return JAI.create("scale", pb);
+    }
+
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeTransformOperation(PlanarImage image) {
+        BufferedImage bi = null;
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                return performScale(image);
+            } else if (instr instanceof TransformOperation) {
+                bi = image.getAsBufferedImage();
+                image = ((TransformOperation) instr)
+                    .executeTransformOperation(PlanarImage.wrapRenderedImage(bi));
+                bi = image.getAsBufferedImage();
+            }
+        }
+        return performScale(image);
+    }
+
+
+    /** {@inheritDoc}. */
+    public PlanarImage executeDrawOperation() {
+        for (int i = 0; i < instructions.size(); i++) {
+            ImageOperation instr = ((ImageOperation) instructions.elementAt(i));
+            if (instr instanceof DrawOperation) {
+                PlanarImage image = null;
+                // If this TransformOperation has DrawOperation children
+                // then Rotate the first child and return.
+                performScale(image);
+                return image;
+            }
+        }
+        return null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/Text.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/Text.java
new file mode 100644
index 0000000..27ec5f6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/Text.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+
+import javax.media.jai.PlanarImage;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public class Text extends ImageOperation implements DrawOperation {
+    private static final int DEFAULT_POINT = 10;
+
+    private String strText = "";
+    private String font = "Arial";
+    private int point = DEFAULT_POINT;
+    private boolean bold = false;
+    private boolean italic = false;
+    private String color = "black";
+
+    /**
+     * Set the string to be used as text.
+     * @param str the string to be used.
+     */
+    public void setString(String str) {
+        strText = str;
+    }
+
+    /**
+     * Set the font to be used to draw the text.
+     * @param f the font to be used.
+     */
+    public void setFont(String f) {
+        font = f;
+    }
+
+    /**
+     * Set the number of points to be used.
+     * @param p an integer value as a string.
+     */
+    public void setPoint(String p) {
+        point = Integer.parseInt(p);
+    }
+
+    /**
+     * Set the color of the text.
+     * @param c the color name.
+     */
+    public void setColor(String c) {
+        color = c;
+    }
+
+    /**
+     * @todo is this used?
+     * @param state not used at the moment.
+     */
+    public void setBold(boolean state) {
+        bold = state;
+    }
+
+    /**
+     * @todo is this used?
+     * @param state not used at the moment.
+     */
+    public void setItalic(boolean state) {
+        italic = state;
+    }
+
+    /**
+     * Draw the text.
+     * @return the resultant image.
+     */
+    public PlanarImage executeDrawOperation() {
+        log("\tCreating Text \"" + strText + "\"");
+
+        Color couloir = ColorMapper.getColorByName(color);
+        int width = 1;
+        int height = 1;
+
+        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+        Graphics2D graphics = (Graphics2D) bi.getGraphics();
+        graphics.setRenderingHint(
+            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(
+            RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+        Font f = new Font(font, Font.PLAIN, point);
+        FontMetrics fmetrics = graphics.getFontMetrics(f);
+        height = fmetrics.getMaxAscent() + fmetrics.getMaxDescent();
+        width = fmetrics.stringWidth(strText);
+
+
+        bi = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR_PRE);
+        graphics = (Graphics2D) bi.getGraphics();
+
+        graphics.setRenderingHint(
+            RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(
+            RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+
+        graphics.setFont(f);
+        graphics.setColor(couloir);
+        graphics.drawString(strText, 0, height - fmetrics.getMaxDescent());
+        PlanarImage image = PlanarImage.wrapRenderedImage(bi);
+        return image;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/optional/image/TransformOperation.java b/trunk/src/main/org/apache/tools/ant/types/optional/image/TransformOperation.java
new file mode 100644
index 0000000..fa50a23
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/optional/image/TransformOperation.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional.image;
+import javax.media.jai.PlanarImage;
+
+/**
+ *
+ * @see org.apache.tools.ant.taskdefs.optional.image.Image
+ */
+public abstract class TransformOperation extends ImageOperation {
+    /**
+     * Performs the transformations.
+     * @param img The image to perform the transformation on.
+     * @return the transformed image.
+     */
+    public abstract PlanarImage executeTransformOperation(PlanarImage img);
+
+     /** {@inheritDoc}. */
+    public void addRectangle(Rectangle instr) {
+        instructions.add(instr);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java b/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java
new file mode 100644
index 0000000..129924c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalog.java
@@ -0,0 +1,121 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resolver;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogEntry;
+
+import org.apache.xml.resolver.helpers.PublicId;
+
+/**
+ * This class extends the Catalog class provided by Norman Walsh's
+ * resolver library in xml-commons in order to add classpath entity
+ * and URI resolution.  Since XMLCatalog already does classpath
+ * resolution, we simply add all CatalogEntry instances back to the
+ * controlling XMLCatalog instance.  This is done via a callback
+ * mechanism.  ApacheCatalog is <em>only</em> used for external
+ * catalog files.  Inline entries (currently <code>&lt;dtd&gt;</code>
+ * and <code>&lt;entity&gt;</code>) are not added to ApacheCatalog.
+ * See XMLCatalog.java for the details of the entity and URI
+ * resolution algorithms.
+ *
+ * @see org.apache.tools.ant.types.XMLCatalog.CatalogResolver
+ * @since Ant 1.6
+ */
+public class ApacheCatalog extends Catalog {
+
+    /** The resolver object to callback. */
+    private ApacheCatalogResolver resolver = null;
+
+    /**
+     * <p>Create a new ApacheCatalog instance.</p>
+     *
+     * <p>This method overrides the superclass method of the same name
+     *  in order to set the resolver object for callbacks.  The reason
+     *  we have to do this is that internally Catalog creates a new
+     *  instance of itself for each external catalog file processed.
+     *  That is, if two external catalog files are processed, there
+     *  will be a total of two ApacheCatalog instances, and so on.</p>
+     * @return the catalog.
+     */
+    protected Catalog newCatalog() {
+        ApacheCatalog cat = (ApacheCatalog) super.newCatalog();
+        cat.setResolver(resolver);
+        return cat;
+    }
+
+    /**
+     * Set the resolver object to callback.
+     * @param resolver the apache catalog resolver.
+     */
+    public void setResolver(ApacheCatalogResolver resolver) {
+        this.resolver = resolver;
+    }
+
+    /**
+     * <p>This method overrides the superclass method of the same name
+     * in order to add catalog entries back to the controlling
+     * XMLCatalog instance.  In this way, we can add classpath lookup
+     * for these entries.</p>
+     *
+     * <p>When we add an external catalog file, the entries inside it
+     * get parsed by this method.  Therefore, we override it to add
+     * each of them back to the controlling XMLCatalog instance.  This
+     * is done by performing a callback to the ApacheCatalogResolver,
+     * which in turn calls the XMLCatalog.</p>
+     *
+     * <p>XMLCatalog currently only understands <code>PUBLIC</code>
+     * and <code>URI</code> entry types, so we ignore the other types.</p>
+     *
+     * @param entry The CatalogEntry to process.
+     */
+    public void addEntry(CatalogEntry entry) {
+
+        int type = entry.getEntryType();
+
+        if (type == PUBLIC) {
+
+            String publicid = PublicId.normalize(entry.getEntryArg(0));
+            String systemid = normalizeURI(entry.getEntryArg(1));
+
+            if (resolver == null) {
+                catalogManager.debug
+                    .message(1, "Internal Error: null ApacheCatalogResolver");
+            } else {
+                resolver.addPublicEntry(publicid, systemid, base);
+            }
+
+        } else if (type == URI) {
+
+            String uri = normalizeURI(entry.getEntryArg(0));
+            String altURI = normalizeURI(entry.getEntryArg(1));
+
+            if (resolver == null) {
+                catalogManager.debug
+                    .message(1, "Internal Error: null ApacheCatalogResolver");
+            } else {
+                resolver.addURIEntry(uri, altURI, base);
+            }
+
+        }
+
+        super.addEntry(entry);
+    }
+
+} //- ApacheCatalog
diff --git a/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java b/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java
new file mode 100644
index 0000000..79dae89
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resolver/ApacheCatalogResolver.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resolver;
+
+import java.io.IOException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.tools.ant.BuildException;
+
+import org.apache.tools.ant.types.XMLCatalog;
+import org.apache.tools.ant.types.ResourceLocation;
+
+import org.apache.xml.resolver.Catalog;
+import org.apache.xml.resolver.CatalogManager;
+
+import org.apache.xml.resolver.tools.CatalogResolver;
+
+/**
+ * <p>This class extends the CatalogResolver class provided by Norman
+ * Walsh's resolver library in xml-commons.  It provides the bridge
+ * between the Ant XMLCatalog datatype and the xml-commons Catalog
+ * class.  XMLCatalog calls methods in this class using Reflection in
+ * order to avoid requiring the xml-commons resolver library in the
+ * path.</p>
+ *
+ * <p>The {@link org.apache.tools.ant.types.resolver.ApacheCatalog
+ * ApacheCatalog} class is used to parse external catalog files, which
+ * can be in either <a
+ * href="http://oasis-open.org/committees/entity/background/9401.html">
+ * plain text format</a> or <a
+ * href="http://www.oasis-open.org/committees/entity/spec-2001-08-06.html">
+ * XML format</a>.</p>
+ *
+ * <p>For each entry found in an external catalog file, if any, an
+ * instance of {@link org.apache.tools.ant.types.ResourceLocation
+ * ResourceLocation} is created and added to the controlling
+ * XMLCatalog datatype.  In this way, these entries will be included
+ * in XMLCatalog's lookup algorithm.  See XMLCatalog.java for more
+ * details.</p>
+ *
+ * @see org.apache.tools.ant.types.XMLCatalog.CatalogResolver
+ * @see org.apache.xml.resolver.CatalogManager
+ * @since Ant 1.6
+ */
+
+public class ApacheCatalogResolver extends CatalogResolver {
+
+    /** The XMLCatalog object to callback. */
+    private XMLCatalog xmlCatalog = null;
+
+    static {
+        //
+        // If you don't do this, you get all sorts of annoying
+        // warnings about a missing properties file.  However, it
+        // seems to work just fine with default values.  Ultimately,
+        // we should probably include a "CatalogManager.properties"
+        // file in the ant jarfile with some default property
+        // settings.  See CatalogManager.java for more details.
+        //
+        CatalogManager.getStaticManager().setIgnoreMissingProperties(true);
+
+        //
+        // Make sure CatalogResolver instantiates ApacheCatalog,
+        // rather than a plain Catalog
+        //
+        System.getProperties().put("xml.catalog.className",
+                                   ApacheCatalog.class.getName());
+
+        CatalogManager.getStaticManager().setUseStaticCatalog(false);
+
+        // debug
+        // CatalogManager.getStaticManager().setVerbosity(4);
+    }
+
+    /**
+     * Set the XMLCatalog object to callback.
+     * @param xmlCatalog the XMLCatalog to use.
+     */
+    public void setXMLCatalog(XMLCatalog xmlCatalog) {
+        this.xmlCatalog = xmlCatalog;
+    }
+
+    /**
+     * XMLCatalog calls this to add an external catalog file for each
+     * file within a <code>&lt;catalogfiles&gt;</code> fileset.
+     * @param file the external catalog file.
+     */
+    public void parseCatalog(String file) {
+
+        Catalog catalog = getCatalog();
+        if (!(catalog instanceof ApacheCatalog)) {
+            throw new BuildException("Wrong catalog type found: " + catalog.getClass().getName());
+        }
+        ApacheCatalog apacheCatalog = (ApacheCatalog) catalog;
+
+        // Pass in reference to ourselves so we can be called back.
+        apacheCatalog.setResolver(this);
+
+        try {
+            apacheCatalog.parseCatalog(file);
+        } catch (MalformedURLException ex) {
+            throw new BuildException(ex);
+        } catch (IOException ex) {
+            throw new BuildException(ex);
+        }
+    }
+
+    /**
+     * <p>Add a PUBLIC catalog entry to the controlling XMLCatalog instance.
+     * ApacheCatalog calls this for each PUBLIC entry found in an external
+     * catalog file.</p>
+     *
+     * @param publicid The public ID of the resource
+     * @param systemid The system ID (aka location) of the resource
+     * @param base The base URL of the resource.  If the systemid
+     * specifies a relative URL/pathname, it is resolved using the
+     * base.  The default base for an external catalog file is the
+     * directory in which the catalog is located.
+     *
+     */
+    public void addPublicEntry(String publicid,
+                               String systemid,
+                               URL base) {
+
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setBase(base);
+        dtd.setPublicId(publicid);
+        dtd.setLocation(systemid);
+
+        xmlCatalog.addDTD(dtd);
+    }
+
+    /**
+     * <p>Add a URI catalog entry to the controlling XMLCatalog instance.
+     * ApacheCatalog calls this for each URI entry found in an external
+     * catalog file.</p>
+     *
+     * @param uri The URI of the resource
+     * @param altURI The URI to which the resource should be mapped
+     * (aka the location)
+     * @param base The base URL of the resource.  If the altURI
+     * specifies a relative URL/pathname, it is resolved using the
+     * base.  The default base for an external catalog file is the
+     * directory in which the catalog is located.
+     *
+     */
+    public void addURIEntry(String uri,
+                            String altURI,
+                            URL base) {
+
+        ResourceLocation entity = new ResourceLocation();
+        entity.setBase(base);
+        entity.setPublicId(uri);
+        entity.setLocation(altURI);
+
+        xmlCatalog.addEntity(entity);
+    }
+
+} //-- ApacheCatalogResolver
diff --git a/trunk/src/main/org/apache/tools/ant/types/resolver/package.html b/trunk/src/main/org/apache/tools/ant/types/resolver/package.html
new file mode 100644
index 0000000..11b3c77
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resolver/package.html
@@ -0,0 +1,35 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<body>
+Ant integration with xml-commons resolver.
+
+<p>These classes enhance the <code>&lt;xmlcatalog&gt;</code> datatype
+to support external catalog files using the xml-commons resolver, in
+accordance with the
+<a href="http://oasis-open.org/committees/entity/spec-2001-08-06.html">
+OASIS "Open Catalog" standard</a>.  They will be used if and only if
+the xml-commons resolver library is available on the classpath.</p>
+
+@see <A HREF="http://xml.apache.org/commons">Apache xml-commons Project</A>
+
+@see org.apache.tools.ant.types.XMLCatalog
+@see org.apache.tools.ant.types.resolver.ApacheCatalogResolver
+@see org.apache.tools.ant.types.resolver.ApacheCatalog
+
+@author <A HREF="mailto:cstrong@arielpartners.com">Craeg Strong</A>
+
+</body>
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/AbstractClasspathResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/AbstractClasspathResource.java
new file mode 100644
index 0000000..79f9eb4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/AbstractClasspathResource.java
@@ -0,0 +1,173 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ *
+ * A Resource representation of anything that is accessed via a Java classloader.
+ * The core methods to set/resolve the classpath are provided.
+ * @since Ant 1.8
+ *
+ */
+
+public abstract class AbstractClasspathResource extends Resource {
+    private Path classpath;
+    private Reference loader;
+
+    /**
+     * Set the classpath to use when looking up a resource.
+     * @param classpath to add to any existing classpath
+     */
+    public void setClasspath(Path classpath) {
+        checkAttributesAllowed();
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Add a classpath to use when looking up a resource.
+     * @return The classpath to be configured
+     */
+    public Path createClasspath() {
+        checkChildrenAllowed();
+        if (classpath == null) {
+            classpath = new Path(getProject());
+        }
+        return classpath.createPath();
+    }
+
+    /**
+     * Set the classpath to use when looking up a resource,
+     * given as reference to a &lt;path&gt; defined elsewhere
+     * @param r The reference value
+     */
+    public void setClasspathRef(Reference r) {
+        checkAttributesAllowed();
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * get the classpath used by this <code>LoadProperties</code>.
+     * @return The classpath
+     */
+    public Path getClasspath() {
+        return isReference()
+            ? ((JavaResource) getCheckedRef()).getClasspath() : classpath;
+    }
+
+    /**
+     * Get the loader.
+     * @return the loader.
+     */
+    public Reference getLoader() {
+        return loader;
+    }
+
+    /**
+     * Use the reference to locate the loader. If the loader is not
+     * found, taskdef will use the specified classpath and register it
+     * with the specified name.
+     *
+     * This allow multiple taskdef/typedef to use the same class loader,
+     * so they can be used together. It eliminate the need to
+     * put them in the CLASSPATH.
+     *
+     * @param r the reference to locate the loader.
+     */
+    public void setLoaderRef(Reference r) {
+        checkAttributesAllowed();
+        loader = r;
+    }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (loader != null || classpath != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Learn whether this resource exists. This implementation opens the input stream
+     * as the test.
+     * @return true if this resource exists.
+     */
+    public boolean isExists() {
+        if (isReference()) {
+            return  ((Resource) getCheckedRef()).isExists();
+        }
+        InputStream is = null;
+        try {
+            is = getInputStream();
+            return is != null;
+        } catch (IOException ex) {
+            return false;
+        } finally {
+            FileUtils.close(is);
+        }
+    }
+
+    /**
+     * Return an InputStream for reading the contents of this Resource.
+     * @return an InputStream object.
+     * @throws IOException if an error occurs.
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        ClassLoader cl = null;
+        if (loader != null) {
+            cl = (ClassLoader) loader.getReferencedObject();
+        }
+        if (cl == null) {
+            if (getClasspath() != null) {
+                cl = getProject().createClassLoader(classpath);
+            } else {
+                cl = JavaResource.class.getClassLoader();
+            }
+            if (loader != null && cl != null) {
+                getProject().addReference(loader.getRefId(), cl);
+            }
+        }
+
+        return openInputStream(cl);
+    }
+
+    /**
+     * open the inpout stream from a specific classloader
+     * @param cl the classloader to use. Will be null if the system classloader is used
+     * @return an open input stream for the resource
+     * @throws IOException if an error occurs.
+     */
+    protected abstract InputStream openInputStream(ClassLoader cl) throws IOException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/ArchiveResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/ArchiveResource.java
new file mode 100644
index 0000000..bc5d2a7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/ArchiveResource.java
@@ -0,0 +1,269 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * A Resource representation of an entry inside an archive.
+ * @since Ant 1.7
+ */
+public abstract class ArchiveResource extends Resource {
+    private static final int NULL_ARCHIVE
+        = Resource.getMagicNumber("null archive".getBytes());
+
+    private Resource archive;
+    private boolean haveEntry = false;
+    private boolean modeSet = false;
+    private int mode = 0;
+
+    /**
+     * Default constructor.
+     */
+    public ArchiveResource() {
+    }
+
+    /**
+     * Construct a ArchiveResource representing the specified
+     * entry in the specified archive.
+     * @param a the archive as File.
+     */
+    public ArchiveResource(File a) {
+        this(a, false);
+    }
+
+    /**
+     * Construct a ArchiveResource representing the specified
+     * entry in the specified archive.
+     * @param a the archive as File.
+     * @param withEntry if the entry has been specified.
+     */
+    public ArchiveResource(File a, boolean withEntry) {
+        setArchive(a);
+        haveEntry = withEntry;
+    }
+
+    /**
+     * Construct a ArchiveResource representing the specified
+     * entry in the specified archive.
+     * @param a the archive as Resource.
+     * @param withEntry if the entry has been specified.
+     */
+    public ArchiveResource(Resource a, boolean withEntry) {
+        addConfigured(a);
+        haveEntry = withEntry;
+    }
+
+    /**
+     * Set the archive that holds this Resource.
+     * @param a the archive as a File.
+     */
+    public void setArchive(File a) {
+        checkAttributesAllowed();
+        archive = new FileResource(a);
+    }
+
+    /**
+     * Sets the file or dir mode for this resource.
+     * @param mode integer representation of Unix permission mask.
+     */
+    public void setMode(int mode) {
+        checkAttributesAllowed();
+        this.mode = mode;
+        modeSet = true;
+    }
+
+    /**
+     * Sets the archive that holds this as a single element Resource
+     * collection.
+     * @param a the archive as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        checkChildrenAllowed();
+        if (archive != null) {
+            throw new BuildException("you must not specify more than one"
+                                     + " archive");
+        }
+        if (a.size() != 1) {
+            throw new BuildException("only single argument resource collections"
+                                     + " are supported as archives");
+        }
+        archive = (Resource) a.iterator().next();
+    }
+
+    /**
+     * Get the archive that holds this Resource.
+     * @return the archive as a Resource.
+     */
+    public Resource getArchive() {
+        return isReference()
+            ? ((ArchiveResource) getCheckedRef()).getArchive() : archive;
+    }
+
+    /**
+     * Get the last modified date of this Resource.
+     * @return the last modification date.
+     */
+    public long getLastModified() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getLastModified();
+        }
+        checkEntry();
+        return super.getLastModified();
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the long size of this Resource.
+     */
+    public long getSize() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getSize();
+        }
+        checkEntry();
+        return super.getSize();
+    }
+
+    /**
+     * Learn whether this Resource represents a directory.
+     * @return boolean flag indicating whether the entry is a directory.
+     */
+    public boolean isDirectory() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).isDirectory();
+        }
+        checkEntry();
+        return super.isDirectory();
+    }
+
+    /**
+     * Find out whether this Resource represents an existing Resource.
+     * @return boolean existence flag.
+     */
+    public boolean isExists() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).isExists();
+        }
+        checkEntry();
+        return super.isExists();
+    }
+
+    /**
+     * Get the file or dir mode for this Resource.
+     * @return integer representation of Unix permission mask.
+     */
+    public int getMode() {
+        if (isReference()) {
+            return ((ArchiveResource) getCheckedRef()).getMode();
+        }
+        checkEntry();
+        return mode;
+    }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (archive != null || modeSet) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Compare this ArchiveResource to another Resource.
+     * @param another the other Resource against which to compare.
+     * @return a negative integer, zero, or a positive integer as this Resource
+     *         is less than, equal to, or greater than the specified Resource.
+     */
+    public int compareTo(Object another) {
+        return this.equals(another) ? 0 : super.compareTo(another);
+    }
+
+    /**
+     * Compare another Object to this ArchiveResource for equality.
+     * @param another the other Object to compare.
+     * @return true if another is a Resource representing
+     *              the same entry in the same archive.
+     */
+    public boolean equals(Object another) {
+        if (this == another) {
+            return true;
+        }
+        if (isReference()) {
+            return getCheckedRef().equals(another);
+        }
+        if (!(another.getClass().equals(getClass()))) {
+            return false;
+        }
+        ArchiveResource r = (ArchiveResource) another;
+        return getArchive().equals(r.getArchive())
+            && getName().equals(r.getName());
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public int hashCode() {
+        return super.hashCode()
+            * (getArchive() == null ? NULL_ARCHIVE : getArchive().hashCode());
+    }
+
+    /**
+     * Format this Resource as a String.
+     * @return String representatation of this Resource.
+     */
+    public String toString() {
+        return isReference() ? getCheckedRef().toString()
+            : getArchive().toString() + ':' + getName();
+    }
+
+    private synchronized void checkEntry() throws BuildException {
+        if (haveEntry) {
+            return;
+        }
+        String name = getName();
+        if (name == null) {
+            throw new BuildException("entry name not set");
+        }
+        Resource r = getArchive();
+        if (r == null) {
+            throw new BuildException("archive attribute not set");
+        }
+        if (!r.isExists()) {
+            throw new BuildException(r.toString() + " does not exist.");
+        }
+        if (r.isDirectory()) {
+            throw new BuildException(r + " denotes a directory.");
+        }
+        fetchEntry();
+        haveEntry = true;
+    }
+
+    /**
+     * fetches information from the named entry inside the archive.
+     */
+    protected abstract void fetchEntry();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/BCFileSet.java b/trunk/src/main/org/apache/tools/ant/types/resources/BCFileSet.java
new file mode 100644
index 0000000..49e2e45
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/BCFileSet.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Utility FileSet that includes directories for backwards-compatibility
+ * with certain tasks e.g. Delete.
+ * @since Ant 1.7
+ */
+public class BCFileSet extends FileSet {
+    /**
+     * Default constructor.
+     */
+    public BCFileSet() {
+    }
+
+    /**
+     * Construct a new BCFileSet from the specified FileSet.
+     * @param fs the FileSet from which to inherit config.
+     */
+    public BCFileSet(FileSet fs) {
+        super(fs);
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     * @since Ant 1.7
+     */
+    public Iterator iterator() {
+        if (isReference()) {
+            return ((FileSet) getRef(getProject())).iterator();
+        }
+        FileResourceIterator result = new FileResourceIterator(getDir());
+        result.addFiles(getDirectoryScanner().getIncludedFiles());
+        result.addFiles(getDirectoryScanner().getIncludedDirectories());
+        return result;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     * @since Ant 1.7
+     */
+    public int size() {
+        if (isReference()) {
+            return ((FileSet) getRef(getProject())).size();
+        }
+        return getDirectoryScanner().getIncludedFilesCount()
+            + getDirectoryScanner().getIncludedDirsCount();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/BZip2Resource.java b/trunk/src/main/org/apache/tools/ant/types/resources/BZip2Resource.java
new file mode 100644
index 0000000..2b8cf7c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/BZip2Resource.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tools.bzip2.CBZip2InputStream;
+import org.apache.tools.bzip2.CBZip2OutputStream;
+
+/**
+ * A Bzip2 compressed resource.
+ *
+ * <p>Wraps around another resource, delegates all quries to that
+ * other resource but uncompresses/compresses streams on the fly.</p>
+ *
+ * @since Ant 1.7
+ */
+public class BZip2Resource extends CompressedResource {
+    private static final char[] MAGIC = new char[] {'B', 'Z'};
+
+    /** A no-arg constructor */
+    public BZip2Resource() {
+    }
+
+    /**
+     * Constructor with another resource to wrap.
+     * @param other the resource to wrap.
+     */
+    public BZip2Resource(org.apache.tools.ant.types.ResourceCollection other) {
+        super(other);
+    }
+
+    /**
+     * Decompress on the fly using {@link CBZip2InputStream}.
+     * @param in the stream to wrap.
+     * @return the wrapped stream.
+     * @throws IOException if there is a problem.
+     */
+    protected InputStream wrapStream(InputStream in) throws IOException {
+        for (int i = 0; i < MAGIC.length; i++) {
+            if (in.read() != MAGIC[i]) {
+                throw new IOException("Invalid bz2 stream.");
+            }
+        }
+        return new CBZip2InputStream(in);
+    }
+
+    /**
+     * Compress on the fly using {@link CBZip2OutputStream}.
+     * @param out the stream to wrap.
+     * @return the wrapped stream.
+     * @throws IOException if there is a problem.
+     */
+    protected OutputStream wrapStream(OutputStream out) throws IOException {
+        for (int i = 0; i < MAGIC.length; i++) {
+            out.write(MAGIC[i]);
+        }
+        return new CBZip2OutputStream(out);
+    }
+
+    /**
+     * Get the name of the compression method.
+     * @return the string "Bzip2".
+     */
+    protected String getCompressionName() {
+        return "Bzip2";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java b/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java
new file mode 100644
index 0000000..0722b3c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionContainer.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.util.List;
+import java.util.Stack;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Base class for ResourceCollections that nest multiple ResourceCollections.
+ * @since Ant 1.7
+ */
+public abstract class BaseResourceCollectionContainer
+    extends DataType implements ResourceCollection, Cloneable {
+    private List rc = new ArrayList();
+    private Collection coll = null;
+    private boolean cache = true;
+
+    /**
+     * Set whether to cache collections.
+     * @param b boolean cache flag.
+     */
+    public synchronized void setCache(boolean b) {
+        cache = b;
+    }
+
+    /**
+     * Learn whether to cache collections. Default is <code>true</code>.
+     * @return boolean cache flag.
+     */
+    public synchronized boolean isCache() {
+        return cache;
+    }
+
+    /**
+     * Clear the container.
+     * @throws BuildException on error.
+     */
+    public synchronized void clear() throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        rc.clear();
+        FailFast.invalidate(this);
+        coll = null;
+        setChecked(false);
+    }
+
+    /**
+     * Add a ResourceCollection to the container.
+     * @param c the ResourceCollection to add.
+     * @throws BuildException on error.
+     */
+    public synchronized void add(ResourceCollection c) throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (c == null) {
+            return;
+        }
+        if (Project.getProject(c) == null) {
+            Project p = getProject();
+            if (p != null) {
+                p.setProjectReference(c);
+            }
+        }
+        rc.add(c);
+        FailFast.invalidate(this);
+        coll = null;
+        setChecked(false);
+    }
+
+    /**
+     * Add the Collection of ResourceCollections to the container.
+     * @param c the Collection whose elements to add.
+     * @throws BuildException on error.
+     */
+    public synchronized void addAll(Collection c) throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        try {
+            for (Iterator i = c.iterator(); i.hasNext();) {
+                add((ResourceCollection) i.next());
+            }
+        } catch (ClassCastException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract. The Iterator returned
+     * will throw ConcurrentModificationExceptions if ResourceCollections
+     * are added to this container while the Iterator is in use.
+     * @return a "fail-fast" Iterator.
+     */
+    public final synchronized Iterator iterator() {
+        if (isReference()) {
+            return ((BaseResourceCollectionContainer) getCheckedRef()).iterator();
+        }
+        dieOnCircularReference();
+        return new FailFast(this, cacheCollection().iterator());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return ((BaseResourceCollectionContainer) getCheckedRef()).size();
+        }
+        dieOnCircularReference();
+        return cacheCollection().size();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    public synchronized boolean isFilesystemOnly() {
+        if (isReference()) {
+            return ((BaseResourceCollectionContainer) getCheckedRef()).isFilesystemOnly();
+        }
+        dieOnCircularReference();
+        //first the easy way, if all children are filesystem-only, return true:
+        boolean goEarly = true;
+        for (Iterator i = rc.iterator(); goEarly && i.hasNext();) {
+            goEarly = ((ResourceCollection) i.next()).isFilesystemOnly();
+        }
+        if (goEarly) {
+            return true;
+        }
+        /* now check each Resource in case the child only
+           lets through files from any children IT may have: */
+        for (Iterator i = cacheCollection().iterator(); i.hasNext();) {
+            if (!(i.next() instanceof FileResource)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Overrides the version of DataType to recurse on all DataType
+     * child elements that may have been added.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            for (Iterator i = rc.iterator(); i.hasNext();) {
+                Object o = i.next();
+                if (o instanceof DataType) {
+                    stk.push(o);
+                    invokeCircularReferenceCheck((DataType) o, stk, p);
+                    stk.pop();
+                }
+            }
+            setChecked(true);
+        }
+    }
+
+    /**
+     * Get the nested ResourceCollections.
+     * @return List.
+     */
+    protected final synchronized List getResourceCollections() {
+        dieOnCircularReference();
+        return Collections.unmodifiableList(rc);
+    }
+
+    /**
+     * Template method for subclasses to return a Collection object of Resources.
+     * @return Collection.
+     */
+    protected abstract Collection getCollection();
+
+    /**
+     * Implement clone.  The set of nested resource
+     * collections is shallowly cloned.
+     * @return a cloned instance.
+     */
+    public Object clone() {
+        try {
+            BaseResourceCollectionContainer c
+                = (BaseResourceCollectionContainer) super.clone();
+            c.rc = new ArrayList(rc);
+            c.coll = null;
+            return c;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+   }
+
+    /**
+     * Format this BaseResourceCollectionContainer as a String.
+     * @return a descriptive <code>String</code>.
+     */
+    public synchronized String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        if (cacheCollection().size() == 0) {
+            return "";
+        }
+        StringBuffer sb = new StringBuffer();
+        for (Iterator i = coll.iterator(); i.hasNext();) {
+            if (sb.length() > 0) {
+                sb.append(File.pathSeparatorChar);
+            }
+            sb.append(i.next());
+        }
+        return sb.toString();
+    }
+
+    private synchronized Collection cacheCollection() {
+        if (coll == null || !isCache()) {
+            coll = getCollection();
+        }
+        return coll;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionWrapper.java b/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionWrapper.java
new file mode 100644
index 0000000..2cf14cc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/BaseResourceCollectionWrapper.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.util.Stack;
+import java.util.Iterator;
+import java.util.Collection;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Base class for a ResourceCollection that wraps a single nested
+ * ResourceCollection.
+ * @since Ant 1.7
+ */
+public abstract class BaseResourceCollectionWrapper
+    extends DataType implements ResourceCollection, Cloneable {
+    private static final String ONE_NESTED_MESSAGE
+        = " expects exactly one nested resource collection.";
+
+    private ResourceCollection rc;
+    private Collection coll = null;
+    private boolean cache = true;
+
+    /**
+     * Set whether to cache collections.
+     * @param b boolean cache flag.
+     */
+    public synchronized void setCache(boolean b) {
+        cache = b;
+    }
+
+    /**
+     * Learn whether to cache collections. Default is <code>true</code>.
+     * @return boolean cache flag.
+     */
+    public synchronized boolean isCache() {
+        return cache;
+    }
+
+    /**
+     * Add a ResourceCollection to the container.
+     * @param c the ResourceCollection to add.
+     * @throws BuildException on error.
+     */
+    public synchronized void add(ResourceCollection c) throws BuildException {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (c == null) {
+            return;
+        }
+        if (rc != null) {
+            throw oneNested();
+        }
+        rc = c;
+        if (Project.getProject(rc) == null) {
+            Project p = getProject();
+            if (p != null) {
+                p.setProjectReference(rc);
+            }
+        }
+        setChecked(false);
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     */
+    public final synchronized Iterator iterator() {
+        if (isReference()) {
+            return ((BaseResourceCollectionWrapper) getCheckedRef()).iterator();
+        }
+        dieOnCircularReference();
+        return new FailFast(this, cacheCollection().iterator());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return ((BaseResourceCollectionWrapper) getCheckedRef()).size();
+        }
+        dieOnCircularReference();
+        return cacheCollection().size();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    public synchronized boolean isFilesystemOnly() {
+        if (isReference()) {
+            return ((BaseResourceCollectionContainer) getCheckedRef()).isFilesystemOnly();
+        }
+        dieOnCircularReference();
+
+        if (rc == null || rc.isFilesystemOnly()) {
+            return true;
+        }
+        /* now check each Resource in case the child only
+           lets through files from any children IT may have: */
+        for (Iterator i = cacheCollection().iterator(); i.hasNext();) {
+            if (!(i.next() instanceof FileResource)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Overrides the version of DataType to recurse on all DataType
+     * child elements that may have been added.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            if (rc instanceof DataType) {
+                stk.push(rc);
+                invokeCircularReferenceCheck((DataType) rc, stk, p);
+                stk.pop();
+            }
+            setChecked(true);
+        }
+    }
+
+    /**
+     * Get the nested ResourceCollection.
+     * @return a ResourceCollection.
+     * @throws BuildException if no nested ResourceCollection has been provided.
+     */
+    protected final synchronized ResourceCollection getResourceCollection() {
+        dieOnCircularReference();
+        if (rc == null) {
+            throw oneNested();
+        }
+        return rc;
+    }
+
+    /**
+     * Template method for subclasses to return a Collection of Resources.
+     * @return Collection.
+     */
+    protected abstract Collection getCollection();
+
+    /**
+     * Format this BaseResourceCollectionWrapper as a String.
+     * @return a descriptive <code>String</code>.
+     */
+    public synchronized String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        if (cacheCollection().size() == 0) {
+            return "";
+        }
+        StringBuffer sb = new StringBuffer();
+        for (Iterator i = coll.iterator(); i.hasNext();) {
+            if (sb.length() > 0) {
+                sb.append(File.pathSeparatorChar);
+            }
+            sb.append(i.next());
+        }
+        return sb.toString();
+    }
+
+    private synchronized Collection cacheCollection() {
+        if (coll == null || !isCache()) {
+            coll = getCollection();
+        }
+        return coll;
+    }
+
+    private BuildException oneNested() {
+        return new BuildException(super.toString() + ONE_NESTED_MESSAGE);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/CompressedResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/CompressedResource.java
new file mode 100644
index 0000000..759e6f3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/CompressedResource.java
@@ -0,0 +1,306 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * A compressed resource.
+ *
+ * <p>Wraps around another resource, delegates all queries (except
+ * getSize) to that other resource but uncompresses/compresses streams
+ * on the fly.</p>
+ *
+ * @since Ant 1.7
+ */
+public abstract class CompressedResource extends Resource {
+
+    private static final int BUFFER_SIZE = 8192;
+
+    private Resource resource;
+
+    /** no arg constructor */
+    public CompressedResource() {
+    }
+
+    /**
+     * Constructor with another resource to wrap.
+     * @param other the resource to wrap.
+     */
+    public CompressedResource(ResourceCollection other) {
+        addConfigured(other);
+    }
+
+    /**
+     * Sets the resource to wrap using a single-element collection.
+     * @param a the resource to wrap as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        checkChildrenAllowed();
+        if (resource != null) {
+            throw new BuildException("you must not specify more than one"
+                                     + " resource");
+        }
+        if (a.size() != 1) {
+            throw new BuildException("only single argument resource collections"
+                                     + " are supported");
+        }
+        resource = (Resource) a.iterator().next();
+    }
+
+    /**
+     * Get the name of the resource.
+     * @return the name of the wrapped resource.
+     */
+    public String getName() {
+        return getResource().getName();
+    }
+
+
+    /**
+     * Overridden, not allowed to set the name of the resource.
+     * @param name not used.
+     * @throws BuildException always.
+     */
+    public void setName(String name) throws BuildException {
+        throw new BuildException("you can't change the name of a compressed"
+                                 + " resource");
+    }
+
+    /**
+     * The exists attribute tells whether a file exists.
+     * @return true if this resource exists.
+     */
+    public boolean isExists() {
+        return getResource().isExists();
+    }
+
+    /**
+     * Set the exists attribute.
+     * @param exists if true, this resource exists.
+     */
+    public void setExists(boolean exists) {
+        throw new BuildException("you can't change the exists state of a "
+                                 + " compressed resource");
+    }
+
+    /**
+     * Tells the modification time in milliseconds since 01.01.1970 .
+     *
+     * @return 0 if the resource does not exist to mirror the behavior
+     * of {@link java.io.File File}.
+     */
+    public long getLastModified() {
+        return getResource().getLastModified();
+    }
+
+    /**
+     * Override setLastModified.
+     * @param lastmodified not used.
+     * @throws BuildException always.
+     */
+    public void setLastModified(long lastmodified) throws BuildException {
+        throw new BuildException("you can't change the timestamp of a "
+                                 + " compressed resource");
+    }
+
+    /**
+     * Tells if the resource is a directory.
+     * @return boolean flag indicating if the resource is a directory.
+     */
+    public boolean isDirectory() {
+        return getResource().isDirectory();
+    }
+
+    /**
+     * Override setDirectory.
+     * @param directory not used.
+     * @throws BuildException always.
+     */
+    public void setDirectory(boolean directory) throws BuildException {
+        throw new BuildException("you can't change the directory state of a "
+                                 + " compressed resource");
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist (for
+     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+     */
+    public long getSize() {
+        if (isExists()) {
+            InputStream in = null;
+            try {
+                in = getInputStream();
+                byte[] buf = new byte[BUFFER_SIZE];
+                int size = 0;
+                int readNow;
+                while ((readNow = in.read(buf, 0, buf.length)) > 0) {
+                    size += readNow;
+                }
+                return size;
+            } catch (IOException ex) {
+                throw new BuildException("caught exception while reading "
+                                         + getName(), ex);
+            } finally {
+                FileUtils.close(in);
+            }
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Override setSize.
+     * @param size not used.
+     * @throws BuildException always.
+     */
+    public void setSize(long size) throws BuildException {
+        throw new BuildException("you can't change the size of a "
+                                 + " compressed resource");
+    }
+
+    /**
+     * Delegates to a comparison of names.
+     * @param other the object to compare to.
+     * @return a negative integer, zero, or a positive integer as this Resource
+     *         is less than, equal to, or greater than the specified Resource.
+     */
+    public int compareTo(Object other) {
+        if (other == this) {
+            return 0;
+        }
+        if (other instanceof CompressedResource) {
+            return getResource().compareTo(
+                ((CompressedResource) other).getResource());
+        }
+        return getResource().compareTo(other);
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public int hashCode() {
+        return getResource().hashCode();
+    }
+
+    /**
+     * Get an InputStream for the Resource.
+     * @return an InputStream containing this Resource's content.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if InputStreams are not
+     *         supported for this Resource type.
+     */
+    public InputStream getInputStream() throws IOException {
+        InputStream in = getResource().getInputStream();
+        if (in != null) {
+            in = wrapStream(in);
+        }
+        return in;
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        OutputStream out = getResource().getOutputStream();
+        if (out != null) {
+            out = wrapStream(out);
+        }
+        return out;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this Resource is a FileResource.
+     */
+    public boolean isFilesystemOnly() {
+        return false;
+    }
+
+    /**
+     * Get the string representation of this Resource.
+     * @return this Resource formatted as a String.
+     * @since Ant 1.7
+     */
+    public String toString() {
+        return getCompressionName() + " compressed "
+            + getResource().toString();
+    }
+
+    /**
+     * Overrides the base version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (resource != null) {
+            throw noChildrenAllowed();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Is supposed to wrap the stream to allow decompression on the fly.
+     *
+     * @param in InputStream to wrap, will never be null.
+     * @return a compressed inputstream.
+     * @throws IOException if there is a problem.
+     */
+    protected abstract InputStream wrapStream(InputStream in)
+        throws IOException;
+
+    /**
+     * Is supposed to wrap the stream to allow compression on the fly.
+     *
+     * @param out OutputStream to wrap, will never be null.
+     * @return a compressed outputstream.
+     * @throws IOException if there is a problem.
+     */
+    protected abstract OutputStream wrapStream(OutputStream out)
+        throws IOException;
+
+    /**
+     * @return the name of the compression method.
+     */
+    protected abstract String getCompressionName();
+
+    private Resource getResource() {
+        if (isReference()) {
+            return (Resource) getCheckedRef();
+        } else if (resource == null) {
+            throw new BuildException("no resource specified");
+        }
+        return resource;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Difference.java b/trunk/src/main/org/apache/tools/ant/types/resources/Difference.java
new file mode 100644
index 0000000..28c5afb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Difference.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.List;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * ResourceCollection representing the difference between
+ * two or more nested ResourceCollections.
+ * @since Ant 1.7
+ */
+public class Difference extends BaseResourceCollectionContainer {
+
+    /**
+     * Calculate the difference of the nested ResourceCollections.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection() {
+        List rc = getResourceCollections();
+        int size = rc.size();
+        if (size < 2) {
+            throw new BuildException("The difference of " + size
+                + " resource collection" + ((size == 1) ? "" : "s")
+                + " is undefined.");
+        }
+        HashSet hs = new HashSet();
+        ArrayList al = new ArrayList();
+        for (Iterator rcIter = rc.iterator(); rcIter.hasNext();) {
+            for (Iterator r = nextRC(rcIter).iterator(); r.hasNext();) {
+                Object next = r.next();
+                if (hs.add(next)) {
+                    al.add(next);
+                } else {
+                    al.remove(next);
+                }
+            }
+        }
+        return al;
+    }
+
+    private static ResourceCollection nextRC(Iterator i) {
+        return (ResourceCollection) i.next();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/FailFast.java b/trunk/src/main/org/apache/tools/ant/types/resources/FailFast.java
new file mode 100644
index 0000000..7d24e71
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/FailFast.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.WeakHashMap;
+import java.util.NoSuchElementException;
+import java.util.ConcurrentModificationException;
+
+/**
+ * Helper class for ResourceCollections to return Iterators
+ * that fail on changes to the object.
+ * @since Ant 1.7
+ */
+/*package-private*/ class FailFast implements Iterator {
+    private static final WeakHashMap MAP = new WeakHashMap();
+
+    /**
+     * Invalidate any in-use Iterators from the specified Object.
+     * @param o the parent Object.
+     */
+    static synchronized void invalidate(Object o) {
+        Set s = (Set) (MAP.get(o));
+        if (s != null) {
+            s.clear();
+        }
+    }
+
+    private static synchronized void add(FailFast f) {
+        Set s = (Set) (MAP.get(f.parent));
+        if (s == null) {
+            s = new HashSet();
+            MAP.put(f.parent, s);
+        }
+        s.add(f);
+    }
+
+    private static synchronized void remove(FailFast f) {
+        Set s = (Set) (MAP.get(f.parent));
+        if (s != null) {
+            s.remove(f);
+        }
+    }
+
+    private static synchronized void failFast(FailFast f) {
+        Set s = (Set) (MAP.get(f.parent));
+        if (!s.contains(f)) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    private Object parent;
+    private Iterator wrapped;
+
+    /**
+     * Construct a new FailFast Iterator wrapping the specified Iterator
+     * and dependent upon the specified parent Object.
+     * @param o the parent Object.
+     * @param i the wrapped Iterator.
+     */
+    FailFast(Object o, Iterator i) {
+        if (o == null) {
+            throw new IllegalArgumentException("parent object is null");
+        }
+        if (i == null) {
+            throw new IllegalArgumentException("cannot wrap null iterator");
+        }
+        parent = o;
+        if (i.hasNext()) {
+            wrapped = i;
+            add(this);
+        }
+    }
+
+    /**
+     * Fulfill the Iterator contract.
+     * @return true if there are more elements.
+     */
+    public boolean hasNext() {
+        if (wrapped == null) {
+            return false;
+        }
+        failFast(this);
+        return wrapped.hasNext();
+    }
+
+    /**
+     * Fulfill the Iterator contract.
+     * @return the next element.
+     * @throws NoSuchElementException if no more elements.
+     */
+    public Object next() {
+        if (wrapped == null || !wrapped.hasNext()) {
+            throw new NoSuchElementException();
+        }
+        failFast(this);
+        try {
+            return wrapped.next();
+        } finally {
+            if (!wrapped.hasNext()) {
+                wrapped = null;
+                remove(this);
+            }
+        }
+    }
+
+    /**
+     * Fulfill the Iterator contract.
+     * @throws UnsupportedOperationException always.
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/FileProvider.java b/trunk/src/main/org/apache/tools/ant/types/resources/FileProvider.java
new file mode 100644
index 0000000..593f088
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/FileProvider.java
@@ -0,0 +1,36 @@
+/*

+ *  Licensed to the Apache Software Foundation (ASF) under one or more

+ *  contributor license agreements.  See the NOTICE file distributed with

+ *  this work for additional information regarding copyright ownership.

+ *  The ASF licenses this file to You under the Apache License, Version 2.0

+ *  (the "License"); you may not use this file except in compliance with

+ *  the License.  You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ *  Unless required by applicable law or agreed to in writing, software

+ *  distributed under the License is distributed on an "AS IS" BASIS,

+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ *  See the License for the specific language governing permissions and

+ *  limitations under the License.

+ *

+ */

+

+package org.apache.tools.ant.types.resources;

+

+import java.io.File;

+

+/**

+ * This is an interface that resources that can provide a file should implement.

+ * This is a refactoring of {@link FileResource}, to allow other resources

+ * to act as sources of files (and to make components that only support

+ * file-based resources from only support FileResource resources.

+ * @since Ant 1.8

+ */

+public interface FileProvider {

+    /**

+     * Get the file represented by this Resource.

+     * @return the file.

+     */

+    File getFile();

+}

diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/FileResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/FileResource.java
new file mode 100644
index 0000000..1e2a731
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/FileResource.java
@@ -0,0 +1,340 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceFactory;
+
+/**
+ * A Resource representation of a File.
+ * @since Ant 1.7
+ */
+public class FileResource extends Resource implements Touchable, FileProvider,
+        ResourceFactory {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private static final int NULL_FILE
+        = Resource.getMagicNumber("null file".getBytes());
+
+    private File file;
+    private File baseDir;
+
+    /**
+     * Default constructor.
+     */
+    public FileResource() {
+    }
+
+    /**
+     * Construct a new FileResource using the specified basedir and relative name.
+     * @param b      the basedir as File.
+     * @param name   the relative filename.
+     */
+    public FileResource(File b, String name) {
+        setFile(FILE_UTILS.resolveFile(b, name));
+        setBaseDir(b);
+    }
+
+    /**
+     * Construct a new FileResource from a File.
+     * @param f the File represented.
+     */
+    public FileResource(File f) {
+        setFile(f);
+    }
+
+    /**
+     * Constructor for Ant attribute introspection.
+     * @param p the Project against which to resolve <code>s</code>.
+     * @param s the absolute or Project-relative filename as a String.
+     * @see org.apache.tools.ant.IntrospectionHelper
+     */
+    public FileResource(Project p, String s) {
+        this(p.resolveFile(s));
+        setProject(p);
+    }
+
+    /**
+     * Set the File for this FileResource.
+     * @param f the File to be represented.
+     */
+    public void setFile(File f) {
+        checkAttributesAllowed();
+        file = f;
+    }
+
+    /**
+     * Get the file represented by this FileResource.
+     * @return the File.
+     */
+    public File getFile() {
+        return isReference() ? ((FileResource) getCheckedRef()).getFile() : file;
+    }
+
+    /**
+     * Set the basedir for this FileResource.
+     * @param b the basedir as File.
+     */
+    public void setBaseDir(File b) {
+        checkAttributesAllowed();
+        baseDir = b;
+    }
+
+    /**
+     * Return the basedir to which the name is relative.
+     * @return the basedir as File.
+     */
+    public File getBaseDir() {
+        return isReference()
+            ? ((FileResource) getCheckedRef()).getBaseDir() : baseDir;
+    }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (file != null || baseDir != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Get the name of this FileResource.  If the basedir is set,
+     * the name will be relative to that.  Otherwise the basename
+     * only will be returned.
+     * @return the name of this resource.
+     */
+    public String getName() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getName();
+        }
+        File b = getBaseDir();
+        return b == null ? getNotNullFile().getName()
+            : FILE_UTILS.removeLeadingPath(b, getNotNullFile());
+    }
+
+    /**
+     * Learn whether this file exists.
+     * @return true if this resource exists.
+     */
+    public boolean isExists() {
+        return isReference() ? ((Resource) getCheckedRef()).isExists()
+            : getNotNullFile().exists();
+    }
+
+    /**
+     * Get the modification time in milliseconds since 01.01.1970 .
+     * @return 0 if the resource does not exist.
+     */
+    public long getLastModified() {
+        return isReference()
+            ? ((Resource) getCheckedRef()).getLastModified()
+            : getNotNullFile().lastModified();
+    }
+
+    /**
+     * Learn whether the resource is a directory.
+     * @return boolean flag indicating if the resource is a directory.
+     */
+    public boolean isDirectory() {
+        return isReference() ? ((Resource) getCheckedRef()).isDirectory()
+            : getNotNullFile().isDirectory();
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist.
+     */
+    public long getSize() {
+        return isReference() ? ((Resource) getCheckedRef()).getSize()
+            : getNotNullFile().length();
+    }
+
+    /**
+     * Return an InputStream for reading the contents of this Resource.
+     * @return an InputStream object.
+     * @throws IOException if an error occurs.
+     */
+    public InputStream getInputStream() throws IOException {
+        return isReference()
+            ? ((Resource) getCheckedRef()).getInputStream()
+            : new FileInputStream(getNotNullFile());
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        File f = getNotNullFile();
+        if (f.exists()) {
+            if (f.isFile()) {
+                f.delete();
+            }
+        } else {
+            File p = f.getParentFile();
+            if (p != null && !(p.exists())) {
+                p.mkdirs();
+            }
+        }
+        return new FileOutputStream(f);
+    }
+
+    /**
+     * Compare this FileResource to another Resource.
+     * @param another the other Resource against which to compare.
+     * @return a negative integer, zero, or a positive integer as this FileResource
+     *         is less than, equal to, or greater than the specified Resource.
+     */
+    public int compareTo(Object another) {
+        if (isReference()) {
+            return ((Comparable) getCheckedRef()).compareTo(another);
+        }
+        if (this.equals(another)) {
+            return 0;
+        }
+        if (another.getClass().equals(getClass())) {
+            FileResource otherfr = (FileResource) another;
+            File f = getFile();
+            if (f == null) {
+                return -1;
+            }
+            File of = otherfr.getFile();
+            if (of == null) {
+                return 1;
+            }
+            return f.compareTo(of);
+        }
+        return super.compareTo(another);
+    }
+
+    /**
+     * Compare another Object to this FileResource for equality.
+     * @param another the other Object to compare.
+     * @return true if another is a FileResource representing the same file.
+     */
+    public boolean equals(Object another) {
+        if (this == another) {
+            return true;
+        }
+        if (isReference()) {
+            return getCheckedRef().equals(another);
+        }
+        if (!(another.getClass().equals(getClass()))) {
+            return false;
+        }
+        FileResource otherfr = (FileResource) another;
+        return getFile() == null
+            ? otherfr.getFile() == null
+            : getFile().equals(otherfr.getFile());
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return MAGIC * (getFile() == null ? NULL_FILE : getFile().hashCode());
+    }
+
+    /**
+     * Get the string representation of this Resource.
+     * @return this FileResource formatted as a String.
+     */
+    public String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        if (file == null) {
+            return "(unbound file resource)";
+        }
+        String absolutePath = file.getAbsolutePath();
+        return FILE_UTILS.normalize(absolutePath).getAbsolutePath();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this Resource is a FileResource.
+     */
+    public boolean isFilesystemOnly() {
+        return !isReference()
+            || ((FileResource) getCheckedRef()).isFilesystemOnly();
+    }
+
+    /**
+     * Implement the Touchable interface.
+     * @param modTime new last modification time.
+     */
+    public void touch(long modTime) {
+        if (isReference()) {
+            ((FileResource) getCheckedRef()).touch(modTime);
+            return;
+        }
+        getNotNullFile().setLastModified(modTime);
+    }
+
+    /**
+     * Get the file represented by this FileResource, ensuring it is not null.
+     * @return the not-null File.
+     * @throws BuildException if file is null.
+     */
+    protected File getNotNullFile() {
+        if (getFile() == null) {
+            throw new BuildException("file attribute is null!");
+        }
+        return getFile();
+    }
+
+    /**
+     * Create a new resource that matches a relative or absolute path.
+     * If the current instance has a baseDir attribute, it is copied.
+     * @param path relative/absolute path to a resource
+     * @return a new resource of type FileResource
+     * @throws BuildException if desired
+     * @since Ant1.8
+     */
+    public Resource getResource(String path) {
+        File newfile = FILE_UTILS.resolveFile(getFile(), path);
+        FileResource fileResource = new FileResource(newfile);
+        fileResource.setBaseDir(getBaseDir());
+        return fileResource;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java b/trunk/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java
new file mode 100644
index 0000000..a4bdbda
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/FileResourceIterator.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Iterator of FileResources from filenames.
+ * @since Ant 1.7
+ */
+public class FileResourceIterator implements Iterator {
+    private File basedir;
+    private String[] files;
+    private int pos = 0;
+
+    /**
+     * Construct a new FileResourceIterator.
+     */
+    public FileResourceIterator() {
+    }
+
+    /**
+     * Construct a new FileResourceIterator relative to the specified
+     * base directory.
+     * @param f the base directory of this instance.
+     */
+    public FileResourceIterator(File f) {
+        basedir = f;
+    }
+
+    /**
+     * Construct a new FileResourceIterator over the specified filenames,
+     * relative to the specified base directory.
+     * @param f the base directory of this instance.
+     * @param s the String[] of filenames.
+     */
+    public FileResourceIterator(File f, String[] s) {
+        this(f);
+        addFiles(s);
+    }
+
+    /**
+     * Add an array of filenames to this FileResourceIterator.
+     * @param s the filenames to add.
+     */
+    public void addFiles(String[] s) {
+        int start = (files == null) ? 0 : files.length;
+        String[] newfiles = new String[start + s.length];
+        if (start > 0) {
+            System.arraycopy(files, 0, newfiles, 0, start);
+        }
+        files = newfiles;
+        System.arraycopy(s, 0, files, start, s.length);
+    }
+
+    /**
+     * Find out whether this FileResourceIterator has more elements.
+     * @return whether there are more Resources to iterate over.
+     */
+    public boolean hasNext() {
+        return pos < files.length;
+    }
+
+    /**
+     * Get the next element from this FileResourceIterator.
+     * @return the next Object.
+     */
+    public Object next() {
+        return nextResource();
+    }
+
+    /**
+     * Not implemented.
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Convenience method to return the next resource.
+     * @return the next File.
+     */
+    public FileResource nextResource() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        return new FileResource(basedir, files[pos++]);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Files.java b/trunk/src/main/org/apache/tools/ant/types/resources/Files.java
new file mode 100644
index 0000000..394f5de
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Files.java
@@ -0,0 +1,506 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Collections;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.PatternSet;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.selectors.FileSelector;
+import org.apache.tools.ant.types.selectors.AbstractSelectorContainer;
+
+/**
+ * ResourceCollection implementation; like AbstractFileSet with absolute paths.
+ * @since Ant 1.7
+ */
+public class Files extends AbstractSelectorContainer
+    implements Cloneable, ResourceCollection {
+
+    private static final Iterator EMPTY_ITERATOR
+        = Collections.EMPTY_SET.iterator();
+
+    private PatternSet defaultPatterns = new PatternSet();
+    private Vector additionalPatterns = new Vector();
+    private Vector selectors = new Vector();
+
+    private boolean useDefaultExcludes = true;
+    private boolean caseSensitive = true;
+    private boolean followSymlinks = true;
+
+    /* cached DirectoryScanner instance */
+    private DirectoryScanner ds = null;
+
+    /**
+     * Construct a new <code>Files</code> collection.
+     */
+    public Files() {
+        super();
+    }
+
+    /**
+     * Construct a new <code>Files</code> collection, shallowly cloned
+     * from the specified <code>Files</code>.
+     * @param f the <code>Files</code> to use as a template.
+     */
+    protected Files(Files f) {
+        this.defaultPatterns = f.defaultPatterns;
+        this.additionalPatterns = f.additionalPatterns;
+        this.selectors = f.selectors;
+        this.useDefaultExcludes = f.useDefaultExcludes;
+        this.caseSensitive = f.caseSensitive;
+        this.followSymlinks = f.followSymlinks;
+        this.ds = f.ds;
+        setProject(f.getProject());
+    }
+
+    /**
+     * Make this instance in effect a reference to another instance.
+     *
+     * <p>You must not set another attribute or nest elements inside
+     * this element if you make it a reference.</p>
+     * @param r the <code>Reference</code> to use.
+     * @throws BuildException if there is a problem.
+     */
+    public void setRefid(Reference r) throws BuildException {
+        if (hasPatterns(defaultPatterns)) {
+            throw tooManyAttributes();
+        }
+        if (!additionalPatterns.isEmpty()) {
+            throw noChildrenAllowed();
+        }
+        if (!selectors.isEmpty()) {
+            throw noChildrenAllowed();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Create a nested patternset.
+     * @return <code>PatternSet</code>.
+     */
+    public synchronized PatternSet createPatternSet() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        PatternSet patterns = new PatternSet();
+        additionalPatterns.addElement(patterns);
+        ds = null;
+        return patterns;
+    }
+
+    /**
+     * Add a name entry to the include list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createInclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        ds = null;
+        return defaultPatterns.createInclude();
+    }
+
+    /**
+     * Add a name entry to the include files list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createIncludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        ds = null;
+        return defaultPatterns.createIncludesFile();
+    }
+
+    /**
+     * Add a name entry to the exclude list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createExclude() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        ds = null;
+        return defaultPatterns.createExclude();
+    }
+
+    /**
+     * Add a name entry to the excludes files list.
+     * @return <code>PatternSet.NameEntry</code>.
+     */
+    public synchronized PatternSet.NameEntry createExcludesFile() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        ds = null;
+        return defaultPatterns.createExcludesFile();
+    }
+
+    /**
+     * Append <code>includes</code> to the current list of include
+     * patterns.
+     *
+     * <p>Patterns may be separated by a comma or a space.</p>
+     *
+     * @param includes the <code>String</code> containing the include patterns.
+     */
+    public synchronized void setIncludes(String includes) {
+        checkAttributesAllowed();
+        defaultPatterns.setIncludes(includes);
+        ds = null;
+    }
+
+    /**
+     * Append <code>includes</code> to the current list of include
+     * patterns.
+     *
+     * @param includes array containing the include patterns.
+     */
+    public synchronized void appendIncludes(String[] includes) {
+        checkAttributesAllowed();
+        if (includes != null) {
+            for (int i = 0; i < includes.length; i++) {
+                defaultPatterns.createInclude().setName(includes[i]);
+            }
+            ds = null;
+        }
+    }
+
+    /**
+     * Append <code>excludes</code> to the current list of exclude
+     * patterns.
+     *
+     * <p>Patterns may be separated by a comma or a space.</p>
+     *
+     * @param excludes the <code>String</code> containing the exclude patterns.
+     */
+    public synchronized void setExcludes(String excludes) {
+        checkAttributesAllowed();
+        defaultPatterns.setExcludes(excludes);
+        ds = null;
+    }
+
+    /**
+     * Append <code>excludes</code> to the current list of include
+     * patterns.
+     *
+     * @param excludes array containing the exclude patterns.
+     */
+    public synchronized void appendExcludes(String[] excludes) {
+        checkAttributesAllowed();
+        if (excludes != null) {
+            for (int i = 0; i < excludes.length; i++) {
+                defaultPatterns.createExclude().setName(excludes[i]);
+            }
+            ds = null;
+        }
+    }
+
+    /**
+     * Set the <code>File</code> containing the includes patterns.
+     *
+     * @param incl <code>File</code> instance.
+     * @throws BuildException if there is a problem.
+     */
+    public synchronized void setIncludesfile(File incl) throws BuildException {
+        checkAttributesAllowed();
+        defaultPatterns.setIncludesfile(incl);
+        ds = null;
+    }
+
+    /**
+     * Set the <code>File</code> containing the excludes patterns.
+     *
+     * @param excl <code>File</code> instance.
+     * @throws BuildException if there is a problem.
+     */
+    public synchronized void setExcludesfile(File excl) throws BuildException {
+        checkAttributesAllowed();
+        defaultPatterns.setExcludesfile(excl);
+        ds = null;
+    }
+
+    /**
+     * Set whether default exclusions should be used or not.
+     *
+     * @param useDefaultExcludes <code>boolean</code>.
+     */
+    public synchronized void setDefaultexcludes(boolean useDefaultExcludes) {
+        checkAttributesAllowed();
+        this.useDefaultExcludes = useDefaultExcludes;
+        ds = null;
+    }
+
+    /**
+     * Get whether default exclusions should be used or not.
+     * @return the defaultexclusions value.
+     */
+    public synchronized boolean getDefaultexcludes() {
+        return (isReference())
+            ? getRef().getDefaultexcludes() : useDefaultExcludes;
+    }
+
+    /**
+     * Set case-sensitivity of the Files collection.
+     *
+     * @param caseSensitive <code>boolean</code>.
+     */
+    public synchronized void setCaseSensitive(boolean caseSensitive) {
+        checkAttributesAllowed();
+        this.caseSensitive = caseSensitive;
+        ds = null;
+    }
+
+    /**
+     * Find out if this Files collection is case-sensitive.
+     *
+     * @return <code>boolean</code> indicating whether the Files
+     * collection is case-sensitive.
+     */
+    public synchronized boolean isCaseSensitive() {
+        return (isReference())
+            ? getRef().isCaseSensitive() : caseSensitive;
+    }
+
+    /**
+     * Set whether or not symbolic links should be followed.
+     *
+     * @param followSymlinks whether or not symbolic links should be followed.
+     */
+    public synchronized void setFollowSymlinks(boolean followSymlinks) {
+        checkAttributesAllowed();
+        this.followSymlinks = followSymlinks;
+        ds = null;
+    }
+
+    /**
+     * Find out whether symbolic links should be followed.
+     *
+     * @return <code>boolean</code> indicating whether symbolic links
+     *         should be followed.
+     */
+    public synchronized boolean isFollowSymlinks() {
+        return (isReference())
+            ? getRef().isFollowSymlinks() : followSymlinks;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     */
+    public synchronized Iterator iterator() {
+        if (isReference()) {
+            return getRef().iterator();
+        }
+        ensureDirectoryScannerSetup();
+        ds.scan();
+        int fct = ds.getIncludedFilesCount();
+        int dct = ds.getIncludedDirsCount();
+        if (fct + dct == 0) {
+            return EMPTY_ITERATOR;
+        }
+        FileResourceIterator result = new FileResourceIterator();
+        if (fct > 0) {
+            result.addFiles(ds.getIncludedFiles());
+        }
+        if (dct > 0) {
+            result.addFiles(ds.getIncludedDirectories());
+        }
+        return result;
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return getRef().size();
+        }
+        ensureDirectoryScannerSetup();
+        ds.scan();
+        return ds.getIncludedFilesCount() + ds.getIncludedDirsCount();
+    }
+
+    /**
+     * Find out whether this Files collection has patterns.
+     *
+     * @return whether any patterns are in this container.
+     */
+    public synchronized boolean hasPatterns() {
+        if (isReference()) {
+            return getRef().hasPatterns();
+        }
+        if (hasPatterns(defaultPatterns)) {
+            return true;
+        }
+        for (Iterator i = additionalPatterns.iterator(); i.hasNext();) {
+            if (hasPatterns((PatternSet) i.next())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new <code>FileSelector</code> to add.
+     */
+    public synchronized void appendSelector(FileSelector selector) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        super.appendSelector(selector);
+        ds = null;
+    }
+
+    /**
+     * Format this Files collection as a String.
+     * @return a descriptive <code>String</code>.
+     */
+    public String toString() {
+        if (isReference()) {
+            return getRef().toString();
+        }
+        Iterator i = iterator();
+        if (!i.hasNext()) {
+            return "";
+        }
+        StringBuffer sb = new StringBuffer();
+        while (i.hasNext()) {
+            if (sb.length() > 0) {
+                sb.append(File.pathSeparatorChar);
+            }
+            sb.append(i.next());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Create a deep clone of this instance, except for the nested selectors
+     * (the list of selectors is a shallow clone of this instance's list).
+     * @return a cloned Object.
+     */
+    public synchronized Object clone() {
+        if (isReference()) {
+            return getRef().clone();
+        }
+        try {
+            Files f = (Files) super.clone();
+            f.defaultPatterns = (PatternSet) defaultPatterns.clone();
+            f.additionalPatterns = new Vector(additionalPatterns.size());
+            for (Iterator iter = additionalPatterns.iterator(); iter.hasNext();) {
+                PatternSet ps = (PatternSet) iter.next();
+                f.additionalPatterns.add(ps.clone());
+            }
+            f.selectors = new Vector(selectors);
+            return f;
+        } catch (CloneNotSupportedException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Get the merged include patterns for this Files collection.
+     * @param p Project instance.
+     * @return the include patterns of the default pattern set and all
+     * nested patternsets.
+     */
+    public String[] mergeIncludes(Project p) {
+        return mergePatterns(p).getIncludePatterns(p);
+    }
+
+    /**
+     * Get the merged exclude patterns for this Files collection.
+     * @param p Project instance.
+     * @return the exclude patterns of the default pattern set and all
+     * nested patternsets.
+     */
+    public String[] mergeExcludes(Project p) {
+        return mergePatterns(p).getExcludePatterns(p);
+    }
+
+    /**
+     * Get the merged patterns for this Files collection.
+     * @param p Project instance.
+     * @return the default patternset merged with the additional sets
+     * in a new PatternSet instance.
+     */
+    public synchronized PatternSet mergePatterns(Project p) {
+        if (isReference()) {
+            return getRef().mergePatterns(p);
+        }
+        PatternSet ps = new PatternSet();
+        ps.append(defaultPatterns, p);
+        final int count = additionalPatterns.size();
+        for (int i = 0; i < count; i++) {
+            Object o = additionalPatterns.elementAt(i);
+            ps.append((PatternSet) o, p);
+        }
+        return ps;
+    }
+
+    /**
+     * Always returns true.
+     * @return true indicating that all elements of a Files collection
+     *              will be FileResources.
+     */
+    public boolean isFilesystemOnly() {
+        return true;
+    }
+
+    /**
+     * Perform the check for circular references and return the
+     * referenced Files collection.
+     * @return <code>FileCollection</code>.
+     */
+    protected Files getRef() {
+        return (Files) getCheckedRef();
+    }
+
+    private synchronized void ensureDirectoryScannerSetup() {
+        if (ds == null) {
+            ds = new DirectoryScanner();
+            PatternSet ps = mergePatterns(getProject());
+            ds.setIncludes(ps.getIncludePatterns(getProject()));
+            ds.setExcludes(ps.getExcludePatterns(getProject()));
+            ds.setSelectors(getSelectors(getProject()));
+            if (useDefaultExcludes) {
+                ds.addDefaultExcludes();
+            }
+            ds.setCaseSensitive(caseSensitive);
+            ds.setFollowSymlinks(followSymlinks);
+        }
+    }
+
+    private boolean hasPatterns(PatternSet ps) {
+        String[] includePatterns = ps.getIncludePatterns(getProject());
+        String[] excludePatterns = ps.getExcludePatterns(getProject());
+        return (includePatterns != null && includePatterns.length > 0)
+            || (includePatterns != null && excludePatterns.length > 0);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/First.java b/trunk/src/main/org/apache/tools/ant/types/resources/First.java
new file mode 100644
index 0000000..96c2707
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/First.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * ResourceCollection that contains the first <code>count</code> elements of
+ * another ResourceCollection, a la the UNIX head command.
+ * @since Ant 1.7
+ */
+public class First extends SizeLimitCollection {
+
+    /**
+     * Take the first <code>count</code> elements.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection() {
+        int ct = getValidCount();
+        Iterator iter = getResourceCollection().iterator();
+        ArrayList al = new ArrayList(ct);
+        for (int i = 0; i < ct && iter.hasNext(); i++) {
+            al.add(iter.next());
+        }
+        return al;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/GZipResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/GZipResource.java
new file mode 100644
index 0000000..c1fe879
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/GZipResource.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * A GZip compressed resource.
+ *
+ * <p>Wraps around another resource, delegates all quries to that
+ * other resource but uncompresses/compresses streams on the fly.</p>
+ *
+ * @since Ant 1.7
+ */
+public class GZipResource extends CompressedResource {
+
+    /** A no-arg constructor */
+    public GZipResource() {
+    }
+
+    /**
+     * Constructor with another resource to wrap.
+     * @param other the resource to wrap.
+     */
+    public GZipResource(org.apache.tools.ant.types.ResourceCollection other) {
+        super(other);
+    }
+
+    /**
+     * Decompress on the fly using java.util.zip.GZIPInputStream.
+     * @param in the stream to wrap.
+     * @return the wrapped stream.
+     * @throws IOException if there is a problem.
+     */
+    protected InputStream wrapStream(InputStream in) throws IOException {
+        return new GZIPInputStream(in);
+    }
+
+    /**
+     * Compress on the fly using java.util.zip.GZIPOutStream.
+     * @param out the stream to wrap.
+     * @return the wrapped stream.
+     * @throws IOException if there is a problem.
+     */
+     protected OutputStream wrapStream(OutputStream out) throws IOException {
+        return new GZIPOutputStream(out);
+    }
+
+    /**
+     * Get the name of the compression method.
+     * @return the string "GZip".
+     */
+    protected String getCompressionName() {
+        return "GZip";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java b/trunk/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java
new file mode 100644
index 0000000..4b7ccf4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/ImmutableResourceException.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resources;
+
+import java.io.IOException;
+
+/**
+ * Exception thrown when an attempt is made to get an OutputStream
+ * from an immutable Resource.
+ * @since Ant 1.7
+ */
+public class ImmutableResourceException extends IOException {
+
+    /**
+     * Default constructor.
+     */
+    public ImmutableResourceException() {
+        super();
+    }
+
+    /**
+     * Construct a new ImmutableResourceException with the specified message.
+     * @param s the message String.
+     */
+    public ImmutableResourceException(String s) {
+        super(s);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Intersect.java b/trunk/src/main/org/apache/tools/ant/types/resources/Intersect.java
new file mode 100644
index 0000000..76b076d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Intersect.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * ResourceCollection representing the intersection
+ * of multiple nested ResourceCollections.
+ * @since Ant 1.7
+ */
+public class Intersect extends BaseResourceCollectionContainer {
+
+    /**
+     * Calculate the intersection of the nested ResourceCollections.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection() {
+        List rcs = getResourceCollections();
+        int size = rcs.size();
+        if (size < 2) {
+            throw new BuildException("The intersection of " + size
+                + " resource collection" + ((size == 1) ? "" : "s")
+                + " is undefined.");
+        }
+        ArrayList al = new ArrayList();
+        Iterator rc = rcs.iterator();
+        al.addAll(collect(rc.next()));
+        while (rc.hasNext()) {
+            al.retainAll(collect(rc.next()));
+        }
+        return al;
+    }
+
+    private ArrayList collect(Object o) {
+        ArrayList result = new ArrayList();
+        for (Iterator i = ((ResourceCollection) o).iterator(); i.hasNext();) {
+            result.add(i.next());
+        }
+        return result;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/JavaConstantResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/JavaConstantResource.java
new file mode 100644
index 0000000..6a22073
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/JavaConstantResource.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Field;
+
+/**
+ * A resource that is a java constant.
+ * This lets you extract values off the classpath and use them elsewhere
+ * @since Ant1.7
+ *
+ */
+
+public class JavaConstantResource extends AbstractClasspathResource {
+    /**
+     * open the inpout stream from a specific classloader
+     *
+     * @param cl the classloader to use. Will be null if the system classloader is used
+     * @return an open input stream for the resource
+     * @throws IOException if an error occurs.
+     */
+    protected InputStream openInputStream(ClassLoader cl) throws IOException {
+        Class clazz;
+        String constant = getName();
+        int index1 = constant.lastIndexOf('.');
+        if (index1 < 0) {
+            throw new IOException("No class name in " + constant);
+        }
+        int index = index1;
+        String classname = constant.substring(0, index);
+        String fieldname = constant.substring(index + 1, constant.length());
+        try {
+            clazz =
+                cl != null
+                ? Class.forName(classname, true, cl)
+                : Class.forName(classname);
+            Field field = clazz.getField(fieldname);
+            String value = field.get(null).toString();
+            return new ByteArrayInputStream(value.getBytes("UTF-8"));
+        } catch (ClassNotFoundException e) {
+            throw new IOException("Class not found:" + classname);
+        } catch (NoSuchFieldException e) {
+            throw new IOException(
+                "Field not found:" + fieldname + " in " + classname);
+        } catch (IllegalAccessException e) {
+            throw new IOException("Illegal access to :" + fieldname + " in " + classname);
+        } catch (NullPointerException npe) {
+            throw new IOException("Not a static field: " + fieldname + " in " + classname);
+        }
+    }
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/JavaResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/JavaResource.java
new file mode 100644
index 0000000..13fd88b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/JavaResource.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.tools.ant.types.Path;
+
+/**
+ * A Resource representation of something loadable via a Java classloader.
+ * @since Ant 1.7
+ */
+public class JavaResource extends AbstractClasspathResource {
+
+    /**
+     * Default constructor.
+     */
+    public JavaResource() {
+    }
+
+    /**
+     * Construct a new JavaResource using the specified name and
+     * classpath.
+     *
+     * @param name   the resource name.
+     * @param path   the classpath.
+     */
+    public JavaResource(String name, Path path) {
+        setName(name);
+        setClasspath(path);
+    }
+
+    /**
+     * open the inpout stream from a specific classloader
+     * @param cl the classloader to use. Will be null if the system classloader is used
+     * @return an open input stream for the resource
+     * @throws IOException if an error occurs.
+     */
+    protected InputStream openInputStream(ClassLoader cl) throws IOException {
+        return cl == null ? ClassLoader.getSystemResourceAsStream(getName())
+            : cl.getResourceAsStream(getName());
+    }
+
+    /**
+     * Compare this JavaResource to another Resource.
+     * @param another the other Resource against which to compare.
+     * @return a negative integer, zero, or a positive integer as this
+     * JavaResource is less than, equal to, or greater than the
+     * specified Resource.
+     */
+    public int compareTo(Object another) {
+        if (isReference()) {
+            return ((Comparable) getCheckedRef()).compareTo(another);
+        }
+        if (another.getClass().equals(getClass())) {
+            JavaResource otherjr = (JavaResource) another;
+            if (!getName().equals(otherjr.getName())) {
+                return getName().compareTo(otherjr.getName());
+            }
+            if (getLoader() != otherjr.getLoader()) {
+                if (getLoader() == null) {
+                    return -1;
+                }
+                if (otherjr.getLoader() == null) {
+                    return 1;
+                }
+                return getLoader().getRefId()
+                    .compareTo(otherjr.getLoader().getRefId());
+            }
+            Path p = getClasspath();
+            Path op = otherjr.getClasspath();
+            if (p != op) {
+                if (p == null) {
+                    return -1;
+                }
+                if (op == null) {
+                    return 1;
+                }
+                return p.toString().compareTo(op.toString());
+            }
+            return 0;
+        }
+        return super.compareTo(another);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Last.java b/trunk/src/main/org/apache/tools/ant/types/resources/Last.java
new file mode 100644
index 0000000..475a45e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Last.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * ResourceCollection that contains the last <code>count</code> elements of
+ * another ResourceCollection, a la the UNIX tail command.
+ * @since Ant 1.7.1
+ */
+public class Last extends SizeLimitCollection {
+
+    /**
+     * Take the last <code>count</code> elements.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection() {
+        int count = getValidCount();
+        ResourceCollection rc = getResourceCollection();
+        int i = count;
+        Iterator iter = rc.iterator();
+        int size = rc.size();
+        for (; i < size; i++) {
+            iter.next();
+        }
+
+        ArrayList al = new ArrayList(count);
+        for (; iter.hasNext(); i++) {
+            al.add(iter.next());
+        }
+        int found = al.size();
+        if (found == count || (size < count && found == size)) {
+            return al;
+        }
+
+        //mismatch:
+        String msg = "Resource collection " + rc + " reports size " + size
+            + " but returns " + i + " elements.";
+
+        //size was understated -> too many results; warn and continue:
+        if (found > count) {
+            log(msg, Project.MSG_WARN);
+            return al.subList(found - count, found);
+        }
+        //size was overstated; we missed some and are now in error-land:
+        throw new BuildException(msg);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/PropertyResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/PropertyResource.java
new file mode 100644
index 0000000..e263b5b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/PropertyResource.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.util.PropertyOutputStream;
+
+/**
+ * Exposes an Ant property as a Resource.
+ * @since Ant 1.7
+ */
+public class PropertyResource extends Resource {
+
+    /** Magic number */
+    private static final int PROPERTY_MAGIC
+        = Resource.getMagicNumber("PropertyResource".getBytes());
+
+    private static final InputStream UNSET = new InputStream() {
+        public int read() {
+            return -1;
+        }
+    };
+
+    /**
+     * Default constructor.
+     */
+    public PropertyResource() {
+    }
+
+    /**
+     * Construct a new PropertyResource with the specified name.
+     * @param p the project to use.
+     * @param n the String name of this PropertyResource (Ant property name/key).
+     */
+    public PropertyResource(Project p, String n) {
+        super(n);
+        setProject(p);
+    }
+
+    /**
+     * Get the value of this PropertyResource.
+     * @return the value of the specified Property.
+     */
+    public String getValue() {
+        Project p = getProject();
+        return p == null ? null : p.getProperty(getName());
+    }
+
+    /**
+     * Find out whether this Resource exists.
+     * @return true if the Property is set, false otherwise.
+     */
+    public boolean isExists() {
+        return getValue() != null;
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist (for
+     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+     */
+    public long getSize() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getSize();
+        }
+        return isExists() ? (long) getValue().length() : 0L;
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return super.hashCode() * PROPERTY_MAGIC;
+    }
+
+    /**
+     * Get the string.
+     *
+     * @return the string contents of the resource.
+     * @since Ant 1.7
+     */
+    public String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        return String.valueOf(getValue());
+    }
+
+    /**
+     * Get an InputStream for the Resource.
+     * @return an InputStream containing this Resource's content.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if InputStreams are not
+     *         supported for this Resource type.
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        return isExists() ? new ByteArrayInputStream(getValue().getBytes()) : UNSET;
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        if (isExists()) {
+            throw new ImmutableResourceException();
+        }
+        return new PropertyOutputStream(getProject(), getName());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Resources.java b/trunk/src/main/org/apache/tools/ant/types/resources/Resources.java
new file mode 100644
index 0000000..16719f8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Resources.java
@@ -0,0 +1,235 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.AbstractCollection;
+import java.util.NoSuchElementException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Generic ResourceCollection: Either stores nested ResourceCollections,
+ * making no attempt to remove duplicates, or references another ResourceCollection.
+ * @since Ant 1.7
+ */
+public class Resources extends DataType implements ResourceCollection {
+    /** static empty ResourceCollection */
+    public static final ResourceCollection NONE = new ResourceCollection() {
+        public boolean isFilesystemOnly() {
+            return true;
+        }
+        public Iterator iterator() {
+            return EMPTY_ITERATOR;
+        }
+        public int size() {
+            return 0;
+        }
+    };
+
+    /** static empty Iterator */
+    public static final Iterator EMPTY_ITERATOR = new Iterator() {
+        public Object next() {
+            throw new NoSuchElementException();
+        }
+        public boolean hasNext() {
+            return false;
+        }
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    };
+
+    private class MyCollection extends AbstractCollection {
+        private int size;
+
+        MyCollection() {
+            size = 0;
+            for (Iterator rci = getNested().iterator(); rci.hasNext();) {
+                size += ((ResourceCollection) rci.next()).size();
+            }
+        }
+        public int size() {
+            return size;
+        }
+        public Iterator iterator() {
+            return new MyIterator();
+        }
+        private class MyIterator implements Iterator {
+            private Iterator rci = getNested().iterator();
+            private Iterator ri = null;
+
+            public boolean hasNext() {
+                boolean result = ri != null && ri.hasNext();
+                while (!result && rci.hasNext()) {
+                    ri = ((ResourceCollection) rci.next()).iterator();
+                    result = ri.hasNext();
+                }
+                return result;
+            }
+            public Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                return ri.next();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+
+    private Vector rc;
+    private Collection coll;
+
+    /**
+     * Add a ResourceCollection.
+     * @param c the ResourceCollection to add.
+     */
+    public synchronized void add(ResourceCollection c) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (c == null) {
+            return;
+        }
+        if (rc == null) {
+            rc = new Vector();
+        }
+        rc.add(c);
+        FailFast.invalidate(this);
+        coll = null;
+        setChecked(false);
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     */
+    public synchronized Iterator iterator() {
+        if (isReference()) {
+            return getRef().iterator();
+        }
+        validate();
+        return new FailFast(this, coll.iterator());
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return getRef().size();
+        }
+        validate();
+        return coll.size();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return true if all Resources represent files.
+     */
+    public boolean isFilesystemOnly() {
+        if (isReference()) {
+            return getRef().isFilesystemOnly();
+        }
+        validate();
+
+        for (Iterator i = getNested().iterator(); i.hasNext();) {
+            if ((!((ResourceCollection) i.next()).isFilesystemOnly())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Format this <code>Resources</code> as a String.
+     * @return a descriptive <code>String</code>.
+     */
+    public synchronized String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        if (coll == null || coll.isEmpty()) {
+            return "";
+        }
+        StringBuffer sb = new StringBuffer();
+        for (Iterator i = coll.iterator(); i.hasNext();) {
+            if (sb.length() > 0) {
+                sb.append(File.pathSeparatorChar);
+            }
+            sb.append(i.next());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Overrides the version of DataType to recurse on all DataType
+     * child elements that may have been added.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            for (Iterator i = getNested().iterator(); i.hasNext();) {
+                Object o = i.next();
+                if (o instanceof DataType) {
+                    invokeCircularReferenceCheck((DataType) o, stk, p);
+                }
+            }
+            setChecked(true);
+        }
+    }
+
+    /**
+     * Resolves references, allowing any ResourceCollection.
+     * @return the referenced ResourceCollection.
+     */
+    private ResourceCollection getRef() {
+        return (ResourceCollection) getCheckedRef(
+            ResourceCollection.class, "ResourceCollection");
+    }
+
+    private synchronized void validate() {
+        dieOnCircularReference();
+        coll = (coll == null) ? new MyCollection() : coll;
+    }
+
+    private synchronized List getNested() {
+        return rc == null ? Collections.EMPTY_LIST : rc;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Restrict.java b/trunk/src/main/org/apache/tools/ant/types/resources/Restrict.java
new file mode 100644
index 0000000..aba581f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Restrict.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelectorContainer;
+
+/**
+ * ResourceCollection that allows a number of selectors to be
+ * applied to a single ResourceCollection for the purposes of
+ * restricting or narrowing results.
+ * @since Ant 1.7
+ */
+public class Restrict
+    extends ResourceSelectorContainer implements ResourceCollection {
+
+    private BaseResourceCollectionWrapper w = new BaseResourceCollectionWrapper() {
+        /**
+         * Restrict the nested ResourceCollection based on the nested selectors.
+         * @return a Collection of Resources.
+         */
+        protected Collection getCollection() {
+            ArrayList result = new ArrayList();
+outer:      for (Iterator ri = w.getResourceCollection().iterator(); ri.hasNext();) {
+                Resource r = (Resource) ri.next();
+                for (Iterator i = getSelectors(); i.hasNext();) {
+                    if (!((ResourceSelector) (i.next())).isSelected(r)) {
+                        continue outer;
+                    }
+                }
+                result.add(r);
+            }
+            return result;
+        }
+    };
+
+    /**
+     * Add the ResourceCollection.
+     * @param c the ResourceCollection to add.
+     */
+    public synchronized void add(ResourceCollection c) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (c == null) {
+            return;
+        }
+        w.add(c);
+    }
+
+    /**
+     * Set whether to cache collections.
+     * @param b boolean cache flag.
+     */
+    public synchronized void setCache(boolean b) {
+        w.setCache(b);
+    }
+
+    /**
+     * Learn whether to cache collections. Default is <code>true</code>.
+     * @return boolean cache flag.
+     */
+    public synchronized boolean isCache() {
+        return w.isCache();
+    }
+
+    /**
+     * Add a ResourceSelector.
+     * @param s the ResourceSelector to add.
+     */
+    public synchronized void add(ResourceSelector s) {
+        if (s == null) {
+            return;
+        }
+        super.add(s);
+        FailFast.invalidate(this);
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return an Iterator of Resources.
+     */
+    public final synchronized Iterator iterator() {
+        if (isReference()) {
+            return ((Restrict) getCheckedRef()).iterator();
+        }
+        dieOnCircularReference();
+        return w.iterator();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return number of elements as int.
+     */
+    public synchronized int size() {
+        if (isReference()) {
+            return ((Restrict) getCheckedRef()).size();
+        }
+        dieOnCircularReference();
+        return w.size();
+    }
+
+    /**
+     * Fulfill the ResourceCollection contract.
+     * @return whether this is a filesystem-only resource collection.
+     */
+    public synchronized boolean isFilesystemOnly() {
+        if (isReference()) {
+            return ((Restrict) getCheckedRef()).isFilesystemOnly();
+        }
+        dieOnCircularReference();
+        return w.isFilesystemOnly();
+    }
+
+    /**
+     * Format this Restrict collection as a String.
+     * @return the String value of this collection.
+     */
+    public synchronized String toString() {
+        if (isReference()) {
+            return getCheckedRef().toString();
+        }
+        dieOnCircularReference();
+        return w.toString();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/SizeLimitCollection.java b/trunk/src/main/org/apache/tools/ant/types/resources/SizeLimitCollection.java
new file mode 100644
index 0000000..aeb42dd
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/SizeLimitCollection.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * ResourceCollection that imposes a size limit on another ResourceCollection.
+ * @since Ant 1.7.1
+ */
+public abstract class SizeLimitCollection extends BaseResourceCollectionWrapper {
+    private static final String BAD_COUNT
+        = "size-limited collection count should be set to an int >= 0";
+
+    private int count = 1;
+
+    /**
+     * Set the number of resources to be included.
+     * @param i the count as <code>int</count>.
+     */
+    public synchronized void setCount(int i) {
+        count = i;
+    }
+
+    /**
+     * Get the number of resources to be included. Default is 1.
+     * @return the count as <code>int</count>.
+     */
+    public synchronized int getCount() {
+        return count;
+    }
+
+    /**
+     * Efficient size implementation.
+     * @return int size
+     */
+    public synchronized int size() {
+        int sz = getResourceCollection().size();
+        int ct = getValidCount();
+        return sz < ct ? sz : ct;
+    }
+
+    /**
+     * Get the count, verifying it is >= 0.
+     * @return int count
+     */
+    protected int getValidCount() {
+        int ct = getCount();
+        if (ct < 0) {
+            throw new BuildException(BAD_COUNT);
+        }
+        return ct;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Sort.java b/trunk/src/main/org/apache/tools/ant/types/resources/Sort.java
new file mode 100644
index 0000000..593f24f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Sort.java
@@ -0,0 +1,151 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Collections;
+import java.util.AbstractCollection;
+import java.util.NoSuchElementException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
+import org.apache.tools.ant.types.resources.comparators.DelegatedResourceComparator;
+
+/**
+ * ResourceCollection that sorts another ResourceCollection.
+ *
+ * Note that Sort must not be used in cases where the ordering of the objects
+ * being sorted might change during the sorting process.
+ *
+ * @since Ant 1.7
+ */
+public class Sort extends BaseResourceCollectionWrapper {
+
+    //sorted bag impl. borrowed from commons-collections TreeBag:
+    private static class SortedBag extends AbstractCollection {
+        private class MutableInt {
+            private int value = 0;
+        }
+        private class MyIterator implements Iterator {
+            private Iterator keyIter = t.keySet().iterator();
+            private Object current;
+            private int occurrence;
+            public synchronized boolean hasNext() {
+                return occurrence > 0 || keyIter.hasNext();
+            }
+            public synchronized Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                if (occurrence == 0) {
+                    current = keyIter.next();
+                    occurrence = ((MutableInt) t.get(current)).value;
+                }
+                --occurrence;
+                return current;
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        }
+        private TreeMap t;
+        private int size;
+
+        SortedBag(Comparator c) {
+            t = new TreeMap(c);
+        }
+        public synchronized Iterator iterator() {
+            return new MyIterator();
+        }
+        public synchronized boolean add(Object o) {
+            if (size < Integer.MAX_VALUE) {
+                ++size;
+            }
+            MutableInt m = (MutableInt) (t.get(o));
+            if (m == null) {
+                m = new MutableInt();
+                t.put(o, m);
+            }
+            m.value++;
+            return true;
+        }
+        public synchronized int size() {
+            return size;
+        }
+    }
+
+    private DelegatedResourceComparator comp = new DelegatedResourceComparator();
+
+    /**
+     * Sort the contained elements.
+     * @return a Collection of Resources.
+     */
+    protected synchronized Collection getCollection() {
+        ResourceCollection rc = getResourceCollection();
+        Iterator iter = rc.iterator();
+        if (!(iter.hasNext())) {
+            return Collections.EMPTY_SET;
+        }
+        SortedBag b = new SortedBag(comp);
+        while (iter.hasNext()) {
+            b.add(iter.next());
+        }
+        return b;
+    }
+
+    /**
+     * Add a ResourceComparator to this Sort ResourceCollection.
+     * If multiple ResourceComparators are added, they will be processed in LIFO order.
+     * @param c the ResourceComparator to add.
+     */
+    public synchronized void add(ResourceComparator c) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        comp.add(c);
+        FailFast.invalidate(this);
+    }
+
+    /**
+     * Overrides the BaseResourceCollectionContainer version
+     * to recurse on nested ResourceComparators.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            DataType.invokeCircularReferenceCheck(comp, stk, p);
+            setChecked(true);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/StringResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/StringResource.java
new file mode 100644
index 0000000..78b4f53
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/StringResource.java
@@ -0,0 +1,260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FilterOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Exposes a string as a Resource.
+ * @since Ant 1.7
+ */
+public class StringResource extends Resource {
+
+    /** Magic number */
+    private static final int STRING_MAGIC
+        = Resource.getMagicNumber("StringResource".getBytes());
+
+    private String encoding = null;
+
+    /**
+     * Default constructor.
+     */
+    public StringResource() {
+    }
+
+    /**
+     * Construct a StringResource with the supplied value.
+     * @param value the value of this StringResource.
+     */
+    public StringResource(String value) {
+        this(null, value);
+    }
+
+    /**
+     * Construct a StringResource with the supplied project and value,
+     * doing property replacement against the project if non-null.
+     * @param project the owning Project.
+     * @param value the value of this StringResource.
+     */
+    public StringResource(Project project, String value) {
+        setProject(project);
+        setValue(project == null ? value : project.replaceProperties(value));
+    }
+
+    /**
+     * Enforce String immutability.
+     * @param s the new name/value for this StringResource.
+     */
+    public synchronized void setName(String s) {
+        if (getName() != null) {
+            throw new BuildException(new ImmutableResourceException());
+        }
+        super.setName(s);
+    }
+
+    /**
+     * The value attribute is a semantically superior alias for the name attribute.
+     * @param s the String's value.
+     */
+    public synchronized void setValue(String s) {
+        setName(s);
+    }
+
+    /**
+     * Synchronize access.
+     * @return the name/value of this StringResource.
+     */
+    public synchronized String getName() {
+        return super.getName();
+    }
+
+    /**
+     * Get the value of this StringResource, resolving to the root reference if needed.
+     * @return the represented String.
+     */
+    public synchronized String getValue() {
+        return getName();
+    }
+
+    /**
+     * The exists attribute tells whether a resource exists.
+     *
+     * @return true if this resource exists.
+     */
+    public boolean isExists() {
+        return getValue() != null;
+    }
+
+    /**
+     * Add nested text to this resource.
+     * Properties will be expanded during this process.
+     * @since Ant 1.7.1
+     * @param text text to use as the string resource
+     */
+    public void addText(String text) {
+        checkChildrenAllowed();
+        setValue(getProject().replaceProperties(text));
+    }
+
+    /**
+     * Set the encoding to be used for this StringResource.
+     * @param s the encoding name.
+     */
+    public synchronized void setEncoding(String s) {
+        checkAttributesAllowed();
+        encoding = s;
+    }
+
+    /**
+     * Get the encoding used by this StringResource.
+     * @return the encoding name.
+     */
+    public synchronized String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist (for
+     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+     */
+    public synchronized long getSize() {
+        return isReference() ? ((Resource) getCheckedRef()).getSize()
+                : getContent().length();
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public synchronized int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return super.hashCode() * STRING_MAGIC;
+    }
+
+    /**
+     * Get the string. See {@link #getContent()}
+     *
+     * @return the string contents of the resource.
+     * @since Ant 1.7
+     */
+    public String toString() {
+        return String.valueOf(getContent());
+    }
+
+    /**
+     * Get an InputStream for the Resource.
+     * @return an InputStream containing this Resource's content.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if InputStreams are not
+     *         supported for this Resource type.
+     */
+    public synchronized InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        String content = getContent();
+        if (content == null) {
+            throw new IllegalStateException("unset string value");
+        }
+        return new ByteArrayInputStream(encoding == null
+                ? content.getBytes() : content.getBytes(encoding));
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public synchronized OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        if (getValue() != null) {
+            throw new ImmutableResourceException();
+        }
+        return new StringResourceFilterOutputStream();
+    }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (encoding != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Get the content of this StringResource. See {@link #getValue()}
+     * @return a String or null if there is no value.
+     */
+    protected synchronized String getContent() {
+        return getValue();
+    }
+
+    /**
+     * This method is only for use by our private helper output stream.
+     * It contains specific logic for expanding properties.
+     * @param output the output
+     */
+    private void setValueFromOutputStream(String output) {
+        String value;
+        if (getProject() != null) {
+            value = getProject().replaceProperties(output);
+        } else {
+            value = output;
+        }
+        setValue(value);
+    }
+
+    private class StringResourceFilterOutputStream extends FilterOutputStream {
+        private final ByteArrayOutputStream baos;
+
+        public StringResourceFilterOutputStream() {
+            super(new ByteArrayOutputStream());
+            baos = (ByteArrayOutputStream) out;
+        }
+
+        public void close() throws IOException {
+            super.close();
+            String result = encoding == null
+                    ? baos.toString() : baos.toString(encoding);
+
+            StringResource.this.setValueFromOutputStream(result);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/TarResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/TarResource.java
new file mode 100644
index 0000000..f840bf7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/TarResource.java
@@ -0,0 +1,194 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
+
+/**
+ * A Resource representation of an entry in a tar archive.
+ * @since Ant 1.7
+ */
+public class TarResource extends ArchiveResource {
+
+    private String userName = "";
+    private String groupName = "";
+    private int    uid;
+    private int    gid;
+
+    /**
+     * Default constructor.
+     */
+    public TarResource() {
+    }
+
+    /**
+     * Construct a TarResource representing the specified
+     * entry in the specified archive.
+     * @param a the archive as File.
+     * @param e the TarEntry.
+     */
+    public TarResource(File a, TarEntry e) {
+        super(a, true);
+        setEntry(e);
+    }
+
+    /**
+     * Construct a TarResource representing the specified
+     * entry in the specified archive.
+     * @param a the archive as Resource.
+     * @param e the TarEntry.
+     */
+    public TarResource(Resource a, TarEntry e) {
+        super(a, true);
+        setEntry(e);
+    }
+
+    /**
+     * Return an InputStream for reading the contents of this Resource.
+     * @return an InputStream object.
+     * @throws IOException if the tar file cannot be opened,
+     *         or the entry cannot be read.
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        Resource archive = getArchive();
+        final TarInputStream i = new TarInputStream(archive.getInputStream());
+        TarEntry te = null;
+        while ((te = i.getNextEntry()) != null) {
+            if (te.getName().equals(getName())) {
+                return i;
+            }
+        }
+
+        FileUtils.close(i);
+        throw new BuildException("no entry " + getName() + " in "
+                                 + getArchive());
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        throw new UnsupportedOperationException(
+            "Use the tar task for tar output.");
+    }
+
+    /**
+     * @return the user name for the tar entry
+     */
+    public String getUserName() {
+        if (isReference()) {
+            return ((TarResource) getCheckedRef()).getUserName();
+        }
+        return userName;
+    }
+
+    /**
+     * @return the group name for the tar entry
+     */
+    public String getGroup() {
+        if (isReference()) {
+            return ((TarResource) getCheckedRef()).getGroup();
+        }
+        return groupName;
+    }
+
+    /**
+     * @return the uid for the tar entry
+     */
+    public int getUid() {
+        if (isReference()) {
+            return ((TarResource) getCheckedRef()).getUid();
+        }
+        return uid;
+    }
+
+    /**
+     * @return the uid for the tar entry
+     */
+    public int getGid() {
+        if (isReference()) {
+            return ((TarResource) getCheckedRef()).getGid();
+        }
+        return uid;
+    }
+
+    /**
+     * fetches information from the named entry inside the archive.
+     */
+    protected void fetchEntry() {
+        Resource archive = getArchive();
+        TarInputStream i = null;
+        try {
+            i = new TarInputStream(archive.getInputStream());
+            TarEntry te = null;
+            while ((te = i.getNextEntry()) != null) {
+                if (te.getName().equals(getName())) {
+                    setEntry(te);
+                    return;
+                }
+            }
+        } catch (IOException e) {
+            log(e.getMessage(), Project.MSG_DEBUG);
+            throw new BuildException(e);
+        } finally {
+            if (i != null) {
+                FileUtils.close(i);
+            }
+        }
+        setEntry(null);
+    }
+
+    private void setEntry(TarEntry e) {
+        if (e == null) {
+            setExists(false);
+            return;
+        }
+        setName(e.getName());
+        setExists(true);
+        setLastModified(e.getModTime().getTime());
+        setDirectory(e.isDirectory());
+        setSize(e.getSize());
+        setMode(e.getMode());
+        userName = e.getUserName();
+        groupName = e.getGroupName();
+        uid = e.getUserId();
+        gid = e.getGroupId();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Tokens.java b/trunk/src/main/org/apache/tools/ant/types/resources/Tokens.java
new file mode 100644
index 0000000..a60d790
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Tokens.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Stack;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.util.ConcatResourceInputStream;
+import org.apache.tools.ant.util.LineTokenizer;
+import org.apache.tools.ant.util.Tokenizer;
+
+/**
+ * ResourceCollection consisting of StringResources gathered from tokenizing
+ * another ResourceCollection with a Tokenizer implementation.
+ * @since Ant 1.7
+ */
+public class Tokens extends BaseResourceCollectionWrapper {
+
+    private Tokenizer tokenizer;
+    private String encoding;
+
+    /**
+     * Sort the contained elements.
+     * @return a Collection of Resources.
+     */
+    protected synchronized Collection getCollection() {
+        ResourceCollection rc = getResourceCollection();
+        if (rc.size() == 0) {
+            return Collections.EMPTY_SET;
+        }
+        if (tokenizer == null) {
+            tokenizer = new LineTokenizer();
+        }
+        ConcatResourceInputStream cat = new ConcatResourceInputStream(rc);
+        cat.setManagingComponent(this);
+
+        InputStreamReader rdr = null;
+        if (encoding == null) {
+            rdr = new InputStreamReader(cat);
+        } else {
+            try {
+                rdr = new InputStreamReader(cat, encoding);
+            } catch (UnsupportedEncodingException e) {
+                throw new BuildException(e);
+            }
+        }
+        ArrayList result = new ArrayList();
+        try {
+            for (String s = tokenizer.getToken(rdr); s != null; s = tokenizer.getToken(rdr)) {
+                StringResource resource = new StringResource(s);
+                resource.setProject(getProject());
+                result.add(resource);
+            }
+        } catch (IOException e) {
+            throw new BuildException("Error reading tokens", e);
+        }
+        return result;
+    }
+
+    /**
+     * Set the encoding used to create the tokens.
+     * @param encoding the encoding to use.
+     */
+    public synchronized void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * Add the nested Tokenizer to this Tokens ResourceCollection.
+     * A LineTokenizer will be used by default.
+     * @param tokenizer the tokenizer to add.
+     */
+    public synchronized void add(Tokenizer tokenizer) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.tokenizer != null) {
+            throw new BuildException("Only one nested tokenizer allowed.");
+        }
+        this.tokenizer = tokenizer;
+    }
+
+    /**
+     * Overrides the BaseResourceCollectionContainer version
+     * to check the nested Tokenizer.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            if (tokenizer instanceof DataType) {
+                stk.push(tokenizer);
+                invokeCircularReferenceCheck((DataType) tokenizer, stk, p);
+            }
+            setChecked(true);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Touchable.java b/trunk/src/main/org/apache/tools/ant/types/resources/Touchable.java
new file mode 100644
index 0000000..3a54a69
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Touchable.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+/**
+ * Interface to be implemented by "touchable" resources;
+ * that is, those whose modification time can be altered.
+ * @since Ant 1.7
+ */
+public interface Touchable {
+    /**
+     * Method called to "touch" the resource.
+     * @param modTime the time to set the modified "field" of the resource,
+     *                measured in milliseconds since the epoch.
+     */
+    void touch(long modTime);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/URLResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/URLResource.java
new file mode 100644
index 0000000..a9fd4d3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/URLResource.java
@@ -0,0 +1,370 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.MalformedURLException;
+import java.net.JarURLConnection;
+import java.util.jar.JarFile;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Exposes a URL as a Resource.
+ * @since Ant 1.7
+ */
+public class URLResource extends Resource {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private static final int NULL_URL
+        = Resource.getMagicNumber("null URL".getBytes());
+
+    private URL url;
+    private URLConnection conn;
+
+    /**
+     * Default constructor.
+     */
+    public URLResource() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param u the URL to expose.
+     */
+    public URLResource(URL u) {
+        setURL(u);
+    }
+
+    /**
+     * Convenience constructor.
+     * @param f the File to set as a URL.
+     */
+    public URLResource(File f) {
+        setFile(f);
+    }
+
+    /**
+     * String constructor for Ant attribute introspection.
+     * @param u String representation of this URL.
+     * @see org.apache.tools.ant.IntrospectionHelper
+     */
+    public URLResource(String u) {
+        this(newURL(u));
+    }
+
+    /**
+     * Set the URL for this URLResource.
+     * @param u the URL to expose.
+     */
+    public synchronized void setURL(URL u) {
+        checkAttributesAllowed();
+        url = u;
+    }
+
+    /**
+     * Set the URL from a File.
+     * @param f the File to set as a URL.
+     */
+    public synchronized void setFile(File f) {
+        try {
+            setURL(FILE_UTILS.getFileURL(f));
+        } catch (MalformedURLException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Get the URL used by this URLResource.
+     * @return a URL object.
+     */
+    public synchronized URL getURL() {
+        if (isReference()) {
+            return ((URLResource) getCheckedRef()).getURL();
+        }
+        return url;
+     }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public synchronized void setRefid(Reference r) {
+        //not using the accessor in this case to avoid side effects
+        if (url != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Get the name of this URLResource
+     * (its file component minus the leading separator).
+     * @return the name of this resource.
+     */
+    public synchronized String getName() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getName();
+        }
+        String name = getURL().getFile();
+        return "".equals(name) ? name : name.substring(1);
+    }
+
+    /**
+     * Return this URLResource formatted as a String.
+     * @return a String representation of this URLResource.
+     */
+    public synchronized String toString() {
+        return isReference()
+            ? getCheckedRef().toString() : String.valueOf(getURL());
+    }
+
+    /**
+     * Find out whether the URL exists .
+     * @return true if this resource exists.
+     */
+    public synchronized boolean isExists() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).isExists();
+        }
+        return isExists(false);
+    }
+
+    /**
+     * Find out whether the URL exists, and close the connection
+     * opened to the URL if closeConnection is true.
+     *
+     * Note that this method does ensure that if:
+     * - the resource exists (if it returns true)
+     * - and if the current object is not a reference
+     * (isReference() returns false)
+     * - and if it was called with closeConnection to false,
+     *
+     * then the connection to the URL (stored in the conn
+     * private field) will be opened, and require to be closed
+     * by the caller.
+     *
+     * @param closeConnection true if the connection should be closed
+     * after the call, false if it should stay open.
+     * @return true if this resource exists.
+     */
+    private synchronized boolean isExists(boolean closeConnection) {
+        if (getURL() == null) {
+            return false;
+        }
+        try {
+            connect();
+            return true;
+        } catch (IOException e) {
+            return false;
+        } finally {
+            if (closeConnection) {
+                close();
+            }
+        }
+    }
+
+
+    /**
+     * Tells the modification time in milliseconds since 01.01.1970 .
+     *
+     * @return 0 if the resource does not exist to mirror the behavior
+     * of {@link java.io.File File}.
+     */
+    public synchronized long getLastModified() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getLastModified();
+        }
+        if (!isExists(false)) {
+            return 0L;
+        }
+        return conn.getLastModified();
+    }
+
+    /**
+     * Tells if the resource is a directory.
+     * @return boolean whether the resource is a directory.
+     */
+    public synchronized boolean isDirectory() {
+        return isReference()
+            ? ((Resource) getCheckedRef()).isDirectory()
+            : getName().endsWith("/");
+    }
+
+    /**
+     * Get the size of this Resource.
+     * @return the size, as a long, 0 if the Resource does not exist (for
+     *         compatibility with java.io.File), or UNKNOWN_SIZE if not known.
+     */
+    public synchronized long getSize() {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getSize();
+        }
+        if (!isExists(false)) {
+            return 0L;
+        }
+        try {
+            connect();
+            long contentlength = conn.getContentLength();
+            close();
+            return contentlength;
+        } catch (IOException e) {
+            return UNKNOWN_SIZE;
+        }
+    }
+
+    /**
+     * Test whether an Object equals this URLResource.
+     * @param another the other Object to compare.
+     * @return true if the specified Object is equal to this Resource.
+     */
+    public synchronized boolean equals(Object another) {
+        if (this == another) {
+            return true;
+        }
+        if (isReference()) {
+            return getCheckedRef().equals(another);
+        }
+        if (!(another.getClass().equals(getClass()))) {
+            return false;
+        }
+        URLResource otheru = (URLResource) another;
+        return getURL() == null
+            ? otheru.getURL() == null
+            : getURL().equals(otheru.getURL());
+    }
+
+    /**
+     * Get the hash code for this Resource.
+     * @return hash code as int.
+     */
+    public synchronized int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return MAGIC * ((getURL() == null) ? NULL_URL : getURL().hashCode());
+    }
+
+    /**
+     * Get an InputStream for the Resource.
+     * @return an InputStream containing this Resource's content.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if InputStreams are not
+     *         supported for this Resource type.
+     */
+    public synchronized InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        connect();
+        try {
+            return conn.getInputStream();
+        } finally {
+            conn = null;
+        }
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     * @throws IOException if the URL cannot be opened.
+     */
+    public synchronized OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        connect();
+        try {
+            return conn.getOutputStream();
+        } finally {
+            conn = null;
+        }
+    }
+
+    /**
+     * Ensure that we have a connection.
+     * @throws IOException if the connection cannot be established.
+     */
+    protected synchronized void connect() throws IOException {
+        URL u = getURL();
+        if (u == null) {
+            throw new BuildException("URL not set");
+        }
+        if (conn == null) {
+            try {
+                conn = u.openConnection();
+                conn.connect();
+            } catch (IOException e) {
+                log(e.toString(), Project.MSG_ERR);
+                conn = null;
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * Closes the URL connection if:
+     * - it is opened (i.e. the field conn is not null)
+     * - this type of URLConnection supports some sort of close mechanism
+     *
+     * This method ensures the field conn will be null after the call.
+     *
+     */
+    private synchronized void close() {
+        if (conn != null) {
+            try {
+                if (conn instanceof JarURLConnection) {
+                    JarURLConnection juc = (JarURLConnection) conn;
+                    JarFile jf = juc.getJarFile();
+                    jf.close();
+                    jf = null;
+                } else if (conn instanceof HttpURLConnection) {
+                    ((HttpURLConnection) conn).disconnect();
+                }
+            } catch (IOException exc) {
+                //ignore
+            } finally {
+                conn = null;
+            }
+        }
+    }
+
+    private static URL newURL(String u) {
+        try {
+            return new URL(u);
+        } catch (MalformedURLException e) {
+            throw new BuildException(e);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/Union.java b/trunk/src/main/org/apache/tools/ant/types/resources/Union.java
new file mode 100644
index 0000000..c0c72b2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/Union.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * ResourceCollection representing the union of multiple nested ResourceCollections.
+ * @since Ant 1.7
+ */
+public class Union extends BaseResourceCollectionContainer {
+
+    /**
+     * Static convenience method to union an arbitrary set of Resources.
+     * @param rc a ResourceCollection.
+     * @return a Union.
+     */
+    public static Union getInstance(ResourceCollection rc) {
+        return rc instanceof Union ? (Union) rc : new Union(rc);
+    }
+
+    /**
+     * Default constructor.
+     */
+    public Union() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param rc the ResourceCollection to add.
+     */
+    public Union(ResourceCollection rc) {
+        add(rc);
+    }
+
+    /**
+     * Returns all Resources in String format. Provided for
+     * convenience in implementing Path.
+     * @return String array of Resources.
+     */
+    public String[] list() {
+        if (isReference()) {
+            return ((Union) getCheckedRef()).list();
+        }
+        Collection result = getCollection(true);
+        return (String[]) (result.toArray(new String[result.size()]));
+    }
+
+    /**
+     * Convenience method.
+     * @return Resource[]
+     */
+    public Resource[] listResources() {
+        if (isReference()) {
+            return ((Union) getCheckedRef()).listResources();
+        }
+        Collection result = getCollection();
+        return (Resource[]) (result.toArray(new Resource[result.size()]));
+    }
+
+    /**
+     * Unify the contained Resources.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection() {
+        return getCollection(false);
+    }
+
+    /**
+     * Unify the contained Resources.
+     * @param asString indicates whether the resulting Collection
+     *        should contain Strings instead of Resources.
+     * @return a Collection of Resources.
+     */
+    protected Collection getCollection(boolean asString) {
+        List rc = getResourceCollections();
+        if (rc.isEmpty()) {
+            return Collections.EMPTY_LIST;
+        }
+        //preserve order-encountered using a list; enforce set logic manually:
+        // (LinkedHashSet better, but JDK 1.4+)
+        ArrayList union = new ArrayList(rc.size() * 2);
+        // Use a set as list.contains() can be expensive for lots of resources
+        Set set = new HashSet(rc.size() * 2);
+        for (Iterator rcIter = rc.iterator(); rcIter.hasNext();) {
+            for (Iterator r = nextRC(rcIter).iterator(); r.hasNext();) {
+                Object o = r.next();
+                if (asString) {
+                    o = o.toString();
+                }
+                if (set.add(o)) {
+                    union.add(o);
+                }
+            }
+        }
+        return union;
+    }
+
+    private static ResourceCollection nextRC(Iterator i) {
+        return (ResourceCollection) i.next();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java b/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
new file mode 100644
index 0000000..2aab102
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/ZipResource.java
@@ -0,0 +1,203 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.FilterInputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.zip.ZipFile;
+import org.apache.tools.zip.ZipEntry;
+
+/**
+ * A Resource representation of an entry in a zipfile.
+ * @since Ant 1.7
+ */
+public class ZipResource extends ArchiveResource {
+
+    private String encoding;
+
+    /**
+     * Default constructor.
+     */
+    public ZipResource() {
+    }
+
+    /**
+     * Construct a ZipResource representing the specified
+     * entry in the specified zipfile.
+     * @param z the zipfile as File.
+     * @param enc the encoding used for filenames.
+     * @param e the ZipEntry.
+     */
+    public ZipResource(File z, String enc, ZipEntry e) {
+        super(z, true);
+        setEncoding(enc);
+        setEntry(e);
+    }
+
+    /**
+     * Set the zipfile that holds this ZipResource.
+     * @param z the zipfile as a File.
+     */
+    public void setZipfile(File z) {
+        setArchive(z);
+    }
+
+    /**
+     * Get the zipfile that holds this ZipResource.
+     * @return the zipfile as a File.
+     */
+    public File getZipfile() {
+        FileResource r = (FileResource) getArchive();
+        return r.getFile();
+    }
+
+    /**
+     * Sets the archive that holds this as a single element Resource
+     * collection.
+     * @param a the archive as a single element Resource collection.
+     */
+    public void addConfigured(ResourceCollection a) {
+        super.addConfigured(a);
+        if (!a.isFilesystemOnly()) {
+            throw new BuildException("only filesystem resources are supported");
+        }
+    }
+
+    /**
+     * Set the encoding to use with the zipfile.
+     * @param enc the String encoding.
+     */
+    public void setEncoding(String enc) {
+        checkAttributesAllowed();
+        encoding = enc;
+    }
+
+    /**
+     * Get the encoding to use with the zipfile.
+     * @return String encoding.
+     */
+    public String getEncoding() {
+        return isReference()
+            ? ((ZipResource) getCheckedRef()).getEncoding() : encoding;
+    }
+
+    /**
+     * Overrides the super version.
+     * @param r the Reference to set.
+     */
+    public void setRefid(Reference r) {
+        if (encoding != null) {
+            throw tooManyAttributes();
+        }
+        super.setRefid(r);
+    }
+
+    /**
+     * Return an InputStream for reading the contents of this Resource.
+     * @return an InputStream object.
+     * @throws IOException if the zip file cannot be opened,
+     *         or the entry cannot be read.
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getInputStream();
+        }
+        final ZipFile z = new ZipFile(getZipfile(), getEncoding());
+        ZipEntry ze = z.getEntry(getName());
+        if (ze == null) {
+            z.close();
+            throw new BuildException("no entry " + getName() + " in "
+                                     + getArchive());
+        }
+        return new FilterInputStream(z.getInputStream(ze)) {
+            public void close() throws IOException {
+                FileUtils.close(in);
+                z.close();
+            }
+            protected void finalize() throws Throwable {
+                try {
+                    close();
+                } finally {
+                    super.finalize();
+                }
+            }
+        };
+    }
+
+    /**
+     * Get an OutputStream for the Resource.
+     * @return an OutputStream to which content can be written.
+     * @throws IOException if unable to provide the content of this
+     *         Resource as a stream.
+     * @throws UnsupportedOperationException if OutputStreams are not
+     *         supported for this Resource type.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isReference()) {
+            return ((Resource) getCheckedRef()).getOutputStream();
+        }
+        throw new UnsupportedOperationException(
+            "Use the zip task for zip output.");
+    }
+
+    /**
+     * fetches information from the named entry inside the archive.
+     */
+    protected void fetchEntry() {
+        ZipFile z = null;
+        try {
+            z = new ZipFile(getZipfile(), getEncoding());
+            setEntry(z.getEntry(getName()));
+        } catch (IOException e) {
+            log(e.getMessage(), Project.MSG_DEBUG);
+            throw new BuildException(e);
+        } finally {
+            if (z != null) {
+                try {
+                    z.close();
+                } catch (IOException e) {
+                    //?
+                }
+            }
+        }
+    }
+
+    private void setEntry(ZipEntry e) {
+        if (e == null) {
+            setExists(false);
+            return;
+        }
+        setName(e.getName());
+        setExists(true);
+        setLastModified(e.getTime());
+        setDirectory(e.isDirectory());
+        setSize(e.getSize());
+        setMode(e.getUnixMode());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Content.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Content.java
new file mode 100755
index 0000000..1810b64
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Content.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.util.ResourceUtils;
+
+/**
+ * Compares Resources by content.
+ * @since Ant 1.7
+ */
+public class Content extends ResourceComparator {
+
+    private boolean binary = true;
+
+    /**
+     * Set binary mode for this Content ResourceComparator. If this
+     * attribute is set to false, Resource content will be compared
+     * ignoring platform line-ending conventions.
+     * Default is <code>true</code>.
+     * @param b whether to compare content in binary mode.
+     */
+    public void setBinary(boolean b) {
+        binary = b;
+    }
+
+    /**
+     * Learn whether this Content ResourceComparator is operating in binary mode.
+     * @return boolean binary flag.
+     */
+    public boolean isBinary() {
+        return binary;
+    }
+
+    /**
+     * Compare two Resources by content.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws BuildException if I/O errors occur.
+     * @see org.apache.tools.ant.util.ResourceUtils#compareContent(Resource, Resource, boolean).
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        try {
+            return ResourceUtils.compareContent(foo, bar, !binary);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Date.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Date.java
new file mode 100755
index 0000000..b6be66b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Date.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Compares Resources by last modification date.
+ * @since Ant 1.7
+ */
+public class Date extends ResourceComparator {
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        long diff = foo.getLastModified() - bar.getLastModified();
+        if (diff > 0) {
+            return +1;
+        } else if (diff < 0) {
+            return -1;
+        } else {
+            return 0;
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/DelegatedResourceComparator.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/DelegatedResourceComparator.java
new file mode 100644
index 0000000..425c5b1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/DelegatedResourceComparator.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Delegates to other ResourceComparators or, if none specified,
+ * uses Resources' natural ordering.
+ * @since Ant 1.7
+ */
+public class DelegatedResourceComparator extends ResourceComparator {
+
+    private Vector v = null;
+
+    /**
+     * Add a delegate ResourceComparator.
+     * @param c the next delegate ResourceComparator.
+     */
+    public synchronized void add(ResourceComparator c) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (c == null) {
+            return;
+        }
+        v = (v == null) ? new Vector() : v;
+        v.add(c);
+    }
+
+    /**
+     * Equality method based on the vector of resources,
+     * or if a reference, the referredto object.
+     * @param o the object to check against.
+     * @return true if there is equality.
+     */
+    public synchronized boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (isReference()) {
+            return getCheckedRef().equals(o);
+        }
+        if (!(o instanceof DelegatedResourceComparator)) {
+            return false;
+        }
+        Vector ov = ((DelegatedResourceComparator) o).v;
+        return v == null ? ov == null : v.equals(ov);
+    }
+
+    /**
+     * Hashcode based on the rules for equality.
+     * @return a hashcode.
+     */
+    public synchronized int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return v == null ? 0 : v.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    protected synchronized int resourceCompare(Resource foo, Resource bar) {
+        //if no nested, natural order:
+        if (v == null || v.isEmpty()) {
+            return foo.compareTo(bar);
+        }
+        int result = 0;
+        for (Iterator i = v.iterator(); result == 0 && i.hasNext();) {
+            result = ((ResourceComparator) i.next()).resourceCompare(foo, bar);
+        }
+        return result;
+    }
+
+    /**
+     * Overrides the version from DataType to recurse on nested ResourceSelector
+s.
+     * @param stk the Stack of references.
+     * @param p   the Project to resolve against.
+     * @throws BuildException on error.
+     */
+    protected void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            if (!(v == null || v.isEmpty())) {
+                for (Iterator i = v.iterator(); i.hasNext();) {
+                    Object o = i.next();
+                    if (o instanceof DataType) {
+                        stk.push(o);
+                        invokeCircularReferenceCheck((DataType) o, stk, p);
+                    }
+                }
+            }
+            setChecked(true);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java
new file mode 100755
index 0000000..5832150
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Exists.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Compares Resources by existence.  Not existing is "less than" existing.
+ * @since Ant 1.7
+ */
+public class Exists extends ResourceComparator {
+
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        boolean f = foo.isExists();
+        if (f == bar.isExists()) {
+            return 0;
+        }
+        return f ? 1 : -1;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/FileSystem.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/FileSystem.java
new file mode 100644
index 0000000..c49c7b5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/FileSystem.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import java.io.File;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Compares filesystem Resources.
+ * @since Ant 1.7
+ */
+public class FileSystem extends ResourceComparator {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws ClassCastException if either resource is not an instance of FileResource.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        File foofile = ((FileResource) foo).getFile();
+        File barfile = ((FileResource) bar).getFile();
+        return foofile.equals(barfile) ? 0
+            : FILE_UTILS.isLeadingPath(foofile, barfile) ? -1
+            : FILE_UTILS.normalize(foofile.getAbsolutePath()).compareTo(
+                FILE_UTILS.normalize(barfile.getAbsolutePath()));
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Name.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Name.java
new file mode 100755
index 0000000..d048ac0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Name.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Compares Resources by name.
+ * @since Ant 1.7
+ */
+public class Name extends ResourceComparator {
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        return foo.getName().compareTo(bar.getName());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java
new file mode 100755
index 0000000..333c085
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/ResourceComparator.java
@@ -0,0 +1,81 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import java.util.Comparator;
+
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Abstract Resource Comparator.
+ * @since Ant 1.7
+ */
+public abstract class ResourceComparator extends DataType implements Comparator {
+
+    /**
+     * Compare two objects.
+     * @param foo the first Object.
+     * @param bar the second Object.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws ClassCastException if either argument is null.
+     */
+    public final int compare(Object foo, Object bar) {
+        dieOnCircularReference();
+        ResourceComparator c =
+            isReference() ? (ResourceComparator) getCheckedRef() : this;
+        return c.resourceCompare((Resource) foo, (Resource) bar);
+    }
+
+    /**
+     * Test for equality with this ResourceComparator.
+     * @param o the Object to compare against.
+     * @return true if the specified Object equals this one.
+     */
+    public boolean equals(Object o) {
+        if (isReference()) {
+            return getCheckedRef().equals(o);
+        }
+        if (o == null) {
+            return false;
+        }
+        return o == this || o.getClass().equals(getClass());
+    }
+
+    /**
+     * Hashcode based on the rules for equality.
+     * @return a hashcode.
+     */
+    public synchronized int hashCode() {
+        if (isReference()) {
+            return getCheckedRef().hashCode();
+        }
+        return getClass().hashCode();
+    }
+
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected abstract int resourceCompare(Resource foo, Resource bar);
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java
new file mode 100755
index 0000000..e7c1e95
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Reverse.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Reverses another ResourceComparator.  If no nested ResourceComparator
+ * is supplied, the compared Resources' natural order will be reversed.
+ * @since Ant 1.7
+ */
+public class Reverse extends ResourceComparator {
+    private static final String ONE_NESTED
+        = "You must not nest more than one ResourceComparator for reversal.";
+
+    private ResourceComparator nested;
+
+    /**
+     * Default constructor.
+     */
+    public Reverse() {
+    }
+
+    /**
+     * Construct a new Reverse, supplying the ResourceComparator to be reversed.
+     * @param c the ResourceComparator to reverse.
+     */
+    public Reverse(ResourceComparator c) {
+        add(c);
+    }
+
+    /**
+     * Add the ResourceComparator to reverse.
+     * @param c the ResourceComparator to add.
+     */
+    public void add(ResourceComparator c) {
+        if (nested != null) {
+            throw new BuildException(ONE_NESTED);
+        }
+        nested = c;
+    }
+
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is greater than, equal to, or less than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        return -1 * (nested == null
+            ? foo.compareTo(bar) : nested.compare(foo, bar));
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Size.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Size.java
new file mode 100755
index 0000000..d608a96
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Size.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Compares Resources by size.
+ * @since Ant 1.7
+ */
+public class Size extends ResourceComparator {
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        return (int) (foo.getSize() - bar.getSize());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Type.java b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Type.java
new file mode 100755
index 0000000..6c082ef
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/comparators/Type.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.comparators;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Compares Resources by is-directory status.  As a container
+ * of files, a directory is deemed "greater" than a file.
+ * @since Ant 1.7
+ */
+public class Type extends ResourceComparator {
+
+    /**
+     * Compare two Resources.
+     * @param foo the first Resource.
+     * @param bar the second Resource.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     */
+    protected int resourceCompare(Resource foo, Resource bar) {
+        boolean f = foo.isDirectory();
+        if (f == bar.isDirectory()) {
+            return 0;
+        }
+        return f ? 1 : -1;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/And.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/And.java
new file mode 100755
index 0000000..0dbb295
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/And.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * And ResourceSelector.
+ * @since Ant 1.7
+ */
+public class And extends ResourceSelectorContainer implements ResourceSelector {
+
+    /**
+     * Default constructor.
+     */
+    public And() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param r the ResourceSelector[] to add.
+     */
+    public And(ResourceSelector[] r) {
+        super(r);
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        for (Iterator i = getSelectors(); i.hasNext();) {
+            if (!((ResourceSelector) i.next()).isSelected(r)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Compare.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Compare.java
new file mode 100644
index 0000000..f1d7d0e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Compare.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Stack;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Comparison;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Quantifier;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.comparators.ResourceComparator;
+import org.apache.tools.ant.types.resources.comparators.DelegatedResourceComparator;
+
+/**
+ * ResourceSelector that compares against "control" Resource(s)
+ * using ResourceComparators.
+ * @since Ant 1.7
+ */
+public class Compare extends DataType implements ResourceSelector {
+
+    private static final String ONE_CONTROL_MESSAGE
+        = " the <control> element should be specified exactly once.";
+
+    private DelegatedResourceComparator comp = new DelegatedResourceComparator();
+    private Quantifier against = Quantifier.ALL;
+
+    private Comparison when = Comparison.EQUAL;
+
+    private Union control;
+
+    /**
+     * Add a ResourceComparator to this Compare selector.
+     * If multiple ResourceComparators are added, they will be processed in LIFO order.
+     * @param c the ResourceComparator to add.
+     */
+    public synchronized void add(ResourceComparator c) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        comp.add(c);
+    }
+
+    /**
+     * Set the quantifier to be used. Default "all".
+     * @param against the Quantifier EnumeratedAttribute to use.
+     */
+    public synchronized void setAgainst(Quantifier against) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.against = against;
+    }
+
+    /**
+     * Set the comparison to be used. Default "equal".
+     * @param when the Comparison EnumeratedAttribute to use.
+     */
+    public synchronized void setWhen(Comparison when) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        this.when = when;
+    }
+
+    /**
+     * Create the nested control element. These are the
+     * resources to compare against.
+     * @return ResourceCollection.
+     */
+    public synchronized ResourceCollection createControl() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (control != null) {
+            throw oneControl();
+        }
+        control = new Union();
+        return control;
+    }
+
+    //implement ResourceSelector; inherit doc
+    /** {@inheritDoc} */
+    public synchronized boolean isSelected(Resource r) {
+        if (isReference()) {
+            return ((ResourceSelector) getCheckedRef()).isSelected(r);
+        }
+        if (control == null) {
+            throw oneControl();
+        }
+        int t = 0, f = 0;
+        for (Iterator it = control.iterator(); it.hasNext();) {
+            if (when.evaluate(comp.compare(r, (Resource) it.next()))) {
+                t++;
+            } else {
+                f++;
+            }
+        }
+        return against.evaluate(t, f);
+    }
+
+    /**
+     * Overrides the version from DataType
+     * to recurse on nested ResourceComparators.
+     * @param stk the stack of data types to use (recursively).
+     * @param p   the project to use to dereference the references.
+     * @throws BuildException on error.
+     */
+    protected synchronized void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            if (control != null) {
+                DataType.invokeCircularReferenceCheck(control, stk, p);
+            }
+            DataType.invokeCircularReferenceCheck(comp, stk, p);
+            setChecked(true);
+        }
+    }
+
+    private BuildException oneControl() {
+        return new BuildException(super.toString() + ONE_CONTROL_MESSAGE);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Date.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Date.java
new file mode 100755
index 0000000..e128999
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Date.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.TimeComparison;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Date ResourceSelector.  Based on the date FileSelector, with the most
+ * notable difference being the lack of support for the includedirs attribute.
+ * It is recommended that the effect of includeDirs = "false" be achieved for
+ * resources by enclosing a "dir" Type ResourceSelector and a Date
+ * ResourceSelector in an Or ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Date implements ResourceSelector {
+    private static final String MILLIS_OR_DATETIME
+        = "Either the millis or the datetime attribute must be set.";
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private Long millis = null;
+    private String dateTime = null;
+    private String pattern = null;
+    private TimeComparison when = TimeComparison.EQUAL;
+    private long granularity = FILE_UTILS.getFileTimestampGranularity();
+
+    /**
+     * Set the date/time in milliseconds since 1970.
+     * @param m the number of millis.
+     */
+    public synchronized void setMillis(long m) {
+        millis = new Long(m);
+    }
+
+    /**
+     * Get the date/time in ms.
+     * @return long number of millis since 1970.
+     */
+    public synchronized long getMillis() {
+        return millis == null ? -1L : millis.longValue();
+    }
+
+    /**
+     * Set the date and time as a String.
+     * @param s the date & time to use.
+     */
+    public synchronized void setDateTime(String s) {
+        dateTime = s;
+        millis = null;
+    }
+
+    /**
+     * Get the date & time in String format.
+     * @return a String representing a date & time.
+     */
+    public synchronized String getDatetime() {
+        return dateTime;
+    }
+
+    /**
+     * Set the granularity to use for this ResourceSelector.
+     * @param g the timestamp granularity.
+     */
+    public synchronized void setGranularity(long g) {
+        granularity = g;
+    }
+
+    /**
+     * Get the timestamp granularity used by this ResourceSelector.
+     * @return the long granularity.
+     */
+    public synchronized long getGranularity() {
+        return granularity;
+    }
+
+    /**
+     * Set the optional pattern to use with the datetime attribute.
+     * @param p the SimpleDateFormat-compatible pattern string.
+     */
+    public synchronized void setPattern(String p) {
+        pattern = p;
+    }
+
+    /**
+     * Get the pattern for use with the datetime attribute.
+     * @return a SimpleDateFormat-compatible pattern string.
+     */
+    public synchronized String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Set the comparison mode.
+     * @param c a TimeComparison object.
+     */
+    public synchronized void setWhen(TimeComparison c) {
+        when = c;
+    }
+
+    /**
+     * Get the comparison mode.
+     * @return a TimeComparison object.
+     */
+    public synchronized TimeComparison getWhen() {
+        return when;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public synchronized boolean isSelected(Resource r) {
+        if (dateTime == null && millis == null) {
+            throw new BuildException(MILLIS_OR_DATETIME);
+        }
+        if (millis == null) {
+            DateFormat df = ((pattern == null)
+                ? DateFormat.getDateTimeInstance(
+                    DateFormat.SHORT, DateFormat.SHORT, Locale.US)
+                : new SimpleDateFormat(pattern));
+            try {
+                long m = df.parse(dateTime).getTime();
+                if (m < 0) {
+                    throw new BuildException("Date of " + dateTime
+                        + " results in negative milliseconds value"
+                        + " relative to epoch (January 1, 1970, 00:00:00 GMT).");
+                }
+                setMillis(m);
+            } catch (ParseException pe) {
+                throw new BuildException("Date of " + dateTime
+                        + " Cannot be parsed correctly. It should be in"
+                        + (pattern == null
+                        ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format.");
+            }
+        }
+        return when.evaluate(r.getLastModified(), millis.longValue(), granularity);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java
new file mode 100755
index 0000000..1b498bc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Exists.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Exists ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Exists implements ResourceSelector {
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        return r.isExists();
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java
new file mode 100755
index 0000000..1e7b16b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/InstanceOf.java
@@ -0,0 +1,130 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ComponentHelper;
+import org.apache.tools.ant.AntTypeDefinition;
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * InstanceOf ResourceSelector.
+ * @since Ant 1.7
+ */
+public class InstanceOf implements ResourceSelector {
+    private static final String ONE_ONLY = "Exactly one of class|type must be set.";
+
+    private Project project;
+    private Class clazz;
+    private String type;
+    private String uri;
+
+    /**
+     * Set the Project instance for this InstanceOf selector.
+     * @param p the Project instance used for type comparisons.
+     */
+    public void setProject(Project p) {
+        project = p;
+    }
+
+    /**
+     * Set the class to compare against.
+     * @param c the class.
+     */
+    public void setClass(Class c) {
+        if (clazz != null) {
+            throw new BuildException("The class attribute has already been set.");
+        }
+        clazz = c;
+    }
+
+    /**
+     * Set the Ant type to compare against.
+     * @param s the type name.
+     */
+    public void setType(String s) {
+        type = s;
+    }
+
+    /**
+     * Set the URI in which the Ant type, if specified, should be defined.
+     * @param u the URI.
+     */
+    public void setURI(String u) {
+        uri = u;
+    }
+
+    /**
+     * Get the comparison class.
+     * @return the Class object.
+     */
+    public Class getCheckClass() {
+        return clazz;
+    }
+
+    /**
+     * Get the comparison type.
+     * @return the String typename.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Get the type's URI.
+     * @return the String URI.
+     */
+    public String getURI() {
+        return uri;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     * @throws BuildException if an error occurs.
+     */
+    public boolean isSelected(Resource r) {
+        if ((clazz == null) == (type == null)) {
+            throw new BuildException(ONE_ONLY);
+        }
+        Class c = clazz;
+        if (type != null) {
+            if (project == null) {
+                throw new BuildException(
+                    "No project set for InstanceOf ResourceSelector; "
+                    + "the type attribute is invalid.");
+            }
+            AntTypeDefinition d = ComponentHelper.getComponentHelper(
+                project).getDefinition(ProjectHelper.genComponentName(uri, type));
+            if (d == null) {
+                throw new BuildException("type " + type + " not found.");
+            }
+            try {
+                c = d.innerGetTypeClass();
+            } catch (ClassNotFoundException e) {
+                throw new BuildException(e);
+            }
+        }
+        return c.isAssignableFrom(r.getClass());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java
new file mode 100755
index 0000000..92b0d26
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Majority.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Majority ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Majority
+    extends ResourceSelectorContainer implements ResourceSelector {
+
+    private boolean tie = true;
+
+    /**
+     * Default constructor.
+     */
+    public Majority() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param r the ResourceSelector[] to add.
+     */
+    public Majority(ResourceSelector[] r) {
+        super(r);
+    }
+
+    /**
+     * Set whether ties are allowed.
+     * @param b whether a tie is a pass.
+     */
+    public synchronized void setAllowtie(boolean b) {
+        tie = b;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public synchronized boolean isSelected(Resource r) {
+        int passed = 0;
+        int failed = 0;
+        int count = selectorCount();
+        boolean even = count % 2 == 0;
+        int threshold = count / 2;
+
+        for (Iterator i = getSelectors(); i.hasNext();) {
+            if (((ResourceSelector) i.next()).isSelected(r)) {
+                ++passed;
+                if (passed > threshold || (even && tie && passed == threshold)) {
+                    return true;
+                }
+            } else {
+                ++failed;
+                if (failed > threshold || (even && !tie && failed == threshold)) {
+                    return false;
+                }
+            }
+        }
+        //dummy
+        return false;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Name.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Name.java
new file mode 100755
index 0000000..30717cb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Name.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+
+/**
+ * Name ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Name implements ResourceSelector {
+    private String pattern;
+    private boolean cs = true;
+
+    /**
+     * Set the pattern to compare names against.
+     * @param n the pattern String to set.
+     */
+    public void setName(String n) {
+        pattern = n;
+    }
+
+    /**
+     * Get the pattern used by this Name ResourceSelector.
+     * @return the String selection pattern.
+     */
+    public String getName() {
+        return pattern;
+    }
+
+    /**
+     * Set whether the name comparisons are case-sensitive.
+     * @param b boolean case-sensitivity flag.
+     */
+    public void setCaseSensitive(boolean b) {
+        cs = b;
+    }
+
+    /**
+     * Learn whether this Name ResourceSelector is case-sensitive.
+     * @return boolean case-sensitivity flag.
+     */
+    public boolean isCaseSensitive() {
+        return cs;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        String n = r.getName();
+        if (SelectorUtils.match(pattern, n, cs)) {
+            return true;
+        }
+        String s = r.toString();
+        return s.equals(n) ? false : SelectorUtils.match(pattern, s, cs);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/None.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/None.java
new file mode 100755
index 0000000..16a1b62
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/None.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * None ResourceSelector.
+ * @since Ant 1.7
+ */
+public class None
+    extends ResourceSelectorContainer implements ResourceSelector {
+
+    /**
+     * Default constructor.
+     */
+    public None() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param r the ResourceSelector[] to add.
+     */
+    public None(ResourceSelector[] r) {
+        super(r);
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        boolean none = true;
+        for (Iterator i = getSelectors(); none && i.hasNext();) {
+            none = !((ResourceSelector) i.next()).isSelected(r);
+        }
+        return none;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Not.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Not.java
new file mode 100755
index 0000000..dc67da1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Not.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Not ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Not implements ResourceSelector {
+
+    private ResourceSelector sel;
+
+    /**
+     * Default constructor.
+     */
+    public Not() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param s the ResourceSelector to negate.
+     */
+    public Not(ResourceSelector s) {
+        add(s);
+    }
+
+    /**
+     * Set the ResourceSelector.
+     * @param s the ResourceSelector to negate.
+     * @throws IllegalStateException if already set.
+     */
+    public void add(ResourceSelector s) {
+        if (sel != null) {
+            throw new IllegalStateException(
+                "The Not ResourceSelector accepts a single nested ResourceSelector");
+        }
+        sel = s;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        return !(sel.isSelected(r));
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Or.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Or.java
new file mode 100755
index 0000000..d1438c9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Or.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Or ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Or extends ResourceSelectorContainer implements ResourceSelector {
+
+    /**
+     * Default constructor.
+     */
+    public Or() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param r the ResourceSelector[] to add.
+     */
+    public Or(ResourceSelector[] r) {
+        super(r);
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        for (Iterator i = getSelectors(); i.hasNext();) {
+            if (((ResourceSelector) i.next()).isSelected(r)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java
new file mode 100755
index 0000000..37151ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelector.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.types.Resource;
+
+/**
+ * Interface for a Resource selector.
+ * @since Ant 1.7
+ */
+public interface ResourceSelector {
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    boolean isSelected(Resource r);
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java
new file mode 100755
index 0000000..158fbc3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/ResourceSelectorContainer.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import java.util.Stack;
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Collections;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+
+/**
+ * ResourceSelector container.
+ * @since Ant 1.7
+ */
+public class ResourceSelectorContainer extends DataType {
+
+    private Vector v = new Vector();
+
+    /**
+     * Default constructor.
+     */
+    public ResourceSelectorContainer() {
+    }
+
+    /**
+     * Construct a new ResourceSelectorContainer with the specified array of selectors.
+     * @param r the ResourceSelector[] to add.
+     */
+    public ResourceSelectorContainer(ResourceSelector[] r) {
+        for (int i = 0; i < r.length; i++) {
+            add(r[i]);
+        }
+    }
+
+    /**
+     * Add a ResourceSelector to the container.
+     * @param s the ResourceSelector to add.
+     */
+    public void add(ResourceSelector s) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (s == null) {
+            return;
+        }
+        v.add(s);
+        setChecked(false);
+    }
+
+    /**
+     * Learn whether this ResourceSelectorContainer has selectors.
+     * @return boolean indicating whether selectors have been added to the container.
+     */
+    public boolean hasSelectors() {
+        if (isReference()) {
+            return ((ResourceSelectorContainer) getCheckedRef()).hasSelectors();
+        }
+        dieOnCircularReference();
+        return !v.isEmpty();
+    }
+
+    /**
+     * Get the count of nested selectors.
+     * @return the selector count as int.
+     */
+    public int selectorCount() {
+        if (isReference()) {
+            return ((ResourceSelectorContainer) getCheckedRef()).selectorCount();
+        }
+        dieOnCircularReference();
+        return v.size();
+    }
+
+    /**
+     * Return an Iterator over the nested selectors.
+     * @return Iterator of ResourceSelectors.
+     */
+    public Iterator getSelectors() {
+        if (isReference()) {
+            return ((ResourceSelectorContainer) getCheckedRef()).getSelectors();
+        }
+        dieOnCircularReference();
+        return Collections.unmodifiableList(v).iterator();
+    }
+
+    /**
+     * Overrides the version from DataType to recurse on nested ResourceSelectors.
+     * @param stk the Stack of references.
+     * @param p   the Project to resolve against.
+     * @throws BuildException on error.
+     */
+    protected void dieOnCircularReference(Stack stk, Project p)
+        throws BuildException {
+        if (isChecked()) {
+            return;
+        }
+        if (isReference()) {
+            super.dieOnCircularReference(stk, p);
+        } else {
+            for (Iterator i = v.iterator(); i.hasNext();) {
+                Object o = i.next();
+                if (o instanceof DataType) {
+                    stk.push(o);
+                    invokeCircularReferenceCheck((DataType) o, stk, p);
+                }
+            }
+            setChecked(true);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Size.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Size.java
new file mode 100755
index 0000000..1309d7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Size.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.Comparison;
+
+/**
+ * Size ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Size implements ResourceSelector {
+    private long size = -1;
+    private Comparison when = Comparison.EQUAL;
+
+    /**
+     * Set the size to compare against.
+     * @param l the long resource size.
+     */
+    public void setSize(long l) {
+        size = l;
+    }
+
+    /**
+     * Get the size compared to by this Size ResourceSelector.
+     * @return the long resource size.
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Set the comparison mode.
+     * @param c a Comparison object.
+     */
+    public void setWhen(Comparison c) {
+        when = c;
+    }
+
+    /**
+     * Get the comparison mode.
+     * @return a Comparison object.
+     */
+    public Comparison getWhen() {
+        return when;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        long diff = r.getSize() - size;
+        return when.evaluate(diff == 0 ? 0 : (int) (diff / Math.abs(diff)));
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Type.java b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Type.java
new file mode 100755
index 0000000..2fb6130
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/resources/selectors/Type.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+ * Type file/dir ResourceSelector.
+ * @since Ant 1.7
+ */
+public class Type implements ResourceSelector {
+
+    private static final String FILE_ATTR = "file";
+    private static final String DIR_ATTR = "dir";
+
+    /** Static file type selector. */
+    public static final Type FILE = new Type(new FileDir(FILE_ATTR));
+
+    /** Static dir type selector. */
+    public static final Type DIR = new Type(new FileDir(DIR_ATTR));
+
+    /**
+     * Implements the type attribute.
+     */
+    public static class FileDir extends EnumeratedAttribute {
+        private static final String[] VALUES = new String[] {FILE_ATTR, DIR_ATTR};
+
+        /**
+         * Default constructor.
+         */
+        public FileDir() {
+        }
+
+        /**
+         * Convenience constructor.
+         * @param value the String EnumeratedAttribute value.
+         */
+        public FileDir(String value) {
+            setValue(value);
+        }
+
+        /**
+         * Return the possible values.
+         * @return a String array.
+         */
+        public String[] getValues() {
+            return VALUES;
+        }
+    }
+
+    private FileDir type = null;
+
+    /**
+     * Default constructor.
+     */
+    public Type() {
+    }
+
+    /**
+     * Convenience constructor.
+     * @param fd the FileDir type.
+     */
+    public Type(FileDir fd) {
+        setType(fd);
+    }
+
+    /**
+     * Set type; file|dir.
+     * @param fd a FileDir object.
+     */
+    public void setType(FileDir fd) {
+        type = fd;
+    }
+
+    /**
+     * Return true if this Resource is selected.
+     * @param r the Resource to check.
+     * @return whether the Resource was selected.
+     */
+    public boolean isSelected(Resource r) {
+        if (type == null) {
+            throw new BuildException("The type attribute is required.");
+        }
+        int i = type.getIndex();
+        return r.isDirectory() ? i == 1 : i == 0;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java b/trunk/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java
new file mode 100644
index 0000000..c118068
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/AbstractSelectorContainer.java
@@ -0,0 +1,288 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * This is the a base class a container of selectors - it does
+ * not need do be a selector itself.
+ *
+ * @since 1.7
+ */
+public abstract class AbstractSelectorContainer extends DataType
+        implements SelectorContainer {
+
+    private Vector selectorsList = new Vector();
+
+    /**
+     * Indicates whether there are any selectors here.
+     * @return true if there are selectors
+     */
+    public boolean hasSelectors() {
+        return !(selectorsList.isEmpty());
+    }
+
+    /**
+     * Gives the count of the number of selectors in this container
+     * @return the number of selectors
+     */
+    public int selectorCount() {
+        return selectorsList.size();
+    }
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return an array of selectors
+     */
+    public FileSelector[] getSelectors(Project p) {
+        FileSelector[] result = new FileSelector[selectorsList.size()];
+        selectorsList.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     * @return an enumerator for the selectors
+     */
+    public Enumeration selectorElements() {
+        return selectorsList.elements();
+    }
+
+    /**
+     * Convert the Selectors within this container to a string. This will
+     * just be a helper class for the subclasses that put their own name
+     * around the contents listed here.
+     *
+     * @return comma separated list of Selectors contained in this one
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        Enumeration e = selectorElements();
+        if (e.hasMoreElements()) {
+            while (e.hasMoreElements()) {
+                buf.append(e.nextElement().toString());
+                if (e.hasMoreElements()) {
+                    buf.append(", ");
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new selector to add
+     */
+    public void appendSelector(FileSelector selector) {
+        selectorsList.addElement(selector);
+    }
+
+    /**
+     * <p>
+     * This validates each contained selector
+     * provided that the selector implements the validate interface.
+     * </p>
+     * <p>Ordinarily, this will validate all the elements of a selector
+     * container even if the isSelected() method of some elements is
+     * never called. This has two effects:</p>
+     * <ul>
+     * <li>Validation will often occur twice.
+     * <li>Since it is not required that selectors derive from
+     * BaseSelector, there could be selectors in the container whose
+     * error conditions are not detected if their isSelected() call
+     * is never made.
+     * </ul>
+     */
+    public void validate() {
+        Enumeration e = selectorElements();
+        while (e.hasMoreElements()) {
+            Object o = e.nextElement();
+            if (o instanceof BaseSelector) {
+                ((BaseSelector) o).validate();
+            }
+        }
+    }
+
+
+    /* Methods below all add specific selectors */
+
+    /**
+     * add a "Select" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSelector(SelectSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an "And" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addAnd(AndSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an "Or" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addOr(OrSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a "Not" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNot(NotSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a "None" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNone(NoneSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a majority selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addMajority(MajoritySelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector date entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDate(DateSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector size entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSize(SizeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector filename entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addFilename(FilenameSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an extended selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addCustom(ExtendSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a contains selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContains(ContainsSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a present selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addPresent(PresentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a depth selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepth(DepthSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a depends selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepend(DependSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * adds a different selector to the selector list
+     * @param selector the selector to add
+     */
+    public void addDifferent(DifferentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * adds a type selector to the selector list
+     * @param selector the selector to add
+     */
+    public void addType(TypeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a regular expression selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContainsRegexp(ContainsRegexpSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add the modified selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addModified(ModifiedSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an arbitary selector
+     * @param selector the selector to add
+     * @since Ant 1.6
+     */
+    public void add(FileSelector selector) {
+        appendSelector(selector);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/AndSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/AndSelector.java
new file mode 100644
index 0000000..48849e0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/AndSelector.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors, all of which have to
+ * select a file in order for this selector to select it.
+ *
+ * @since 1.5
+ */
+public class AndSelector extends BaseSelectorContainer {
+
+    /**
+     * Default constructor.
+     */
+    public AndSelector() {
+    }
+
+    /**
+     * @return a string representation of the selector
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{andselect: ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Returns true (the file is selected) only if all other selectors
+     * agree that the file should be selected.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename the name of the file to check
+     * @param file a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+        Enumeration e = selectorElements();
+        boolean result;
+
+        while (e.hasMoreElements()) {
+            result = ((FileSelector) e.nextElement()).isSelected(basedir,
+                    filename, file);
+            if (!result) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java
new file mode 100644
index 0000000..f17ca02
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Convenience base class for all selectors accessed through ExtendSelector.
+ * It provides support for gathering the parameters together as well as for
+ * assigning an error message and throwing a build exception if an error is
+ * detected.
+ *
+ * @since 1.5
+ */
+public abstract class BaseExtendSelector
+        extends BaseSelector
+        implements ExtendFileSelector {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** The passed in parameter array. */
+    protected Parameter[] parameters = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Default constructor.
+     */
+    public BaseExtendSelector() {
+    }
+
+    /**
+     * Set all the Parameters for this custom selector, collected by
+     * the ExtendSelector class.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Allows access to the parameters gathered and set within the
+     * &lt;custom&gt; tag.
+     *
+     * @return the set of parameters defined for this selector
+     */
+    protected Parameter[] getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Method that each selector will implement to create their
+     * selection behaviour. If there is a problem with the setup
+     * of a selector, it can throw a BuildException to indicate
+     * the problem.
+     *
+     * @param basedir A java.io.File object for the base directory
+     * @param filename The name of the file to check
+     * @param file A File object for this filename
+     * @return whether the file should be selected or not
+     * @exception BuildException if an error occurs
+     */
+    public abstract boolean isSelected(File basedir, String filename,
+                                       File file)
+            throws BuildException;
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java
new file mode 100644
index 0000000..9feeb7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java
@@ -0,0 +1,110 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.DataType;
+
+/**
+ * A convenience base class that you can subclass Selectors from. It
+ * provides some helpful common behaviour. Note that there is no need
+ * for Selectors to inherit from this class, it is only necessary that
+ * they implement FileSelector.
+ *
+ * @since 1.5
+ */
+public abstract class BaseSelector extends DataType implements FileSelector {
+
+    private String errmsg = null;
+
+
+    /**
+     * Do nothing constructor.
+     */
+    public BaseSelector() {
+    }
+
+    /**
+     * Allows all selectors to indicate a setup error. Note that only
+     * the first error message is recorded.
+     *
+     * @param msg The error message any BuildException should throw.
+     */
+    public void setError(String msg) {
+        if (errmsg == null) {
+            errmsg = msg;
+        }
+    }
+
+    /**
+     * Returns any error messages that have been set.
+     *
+     * @return the error condition
+     */
+    public String getError() {
+        return errmsg;
+    }
+
+
+    /**
+     * <p>Subclasses can override this method to provide checking of their
+     * state. So long as they call validate() from isSelected(), this will
+     * be called automatically (unless they override validate()).</p>
+     * <p>Implementations should check for incorrect settings and call
+     * setError() as necessary.</p>
+     */
+    public void verifySettings() {
+        if (isReference()) {
+            ((BaseSelector) getCheckedRef()).verifySettings();
+        }
+    }
+
+
+    /**
+     * Subclasses can use this to throw the requisite exception
+     * in isSelected() in the case of an error condition.
+     */
+    public void validate() {
+        if (getError() == null) {
+            verifySettings();
+        }
+        if (getError() != null) {
+            throw new BuildException(errmsg);
+        }
+    }
+
+    /**
+     * Method that each selector will implement to create their
+     * selection behaviour. If there is a problem with the setup
+     * of a selector, it can throw a BuildException to indicate
+     * the problem.
+     *
+     * @param basedir A java.io.File object for the base directory
+     * @param filename The name of the file to check
+     * @param file A File object for this filename
+     * @return whether the file should be selected or not
+     */
+    public abstract boolean isSelected(File basedir, String filename,
+                                       File file);
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java
new file mode 100644
index 0000000..10a44b9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java
@@ -0,0 +1,313 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * This is the base class for selectors that can contain other selectors.
+ *
+ * @since 1.5
+ */
+public abstract class BaseSelectorContainer extends BaseSelector
+        implements SelectorContainer {
+
+    private Vector selectorsList = new Vector();
+
+    /**
+     * Default constructor.
+     */
+    public BaseSelectorContainer() {
+    }
+
+    /**
+     * Indicates whether there are any selectors here.
+     * @return true if there are selectors
+     */
+    public boolean hasSelectors() {
+        return !(selectorsList.isEmpty());
+    }
+
+    /**
+     * Gives the count of the number of selectors in this container
+     * @return the number of selectors
+     */
+    public int selectorCount() {
+        return selectorsList.size();
+    }
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return an array of selectors
+     */
+    public FileSelector[] getSelectors(Project p) {
+        FileSelector[] result = new FileSelector[selectorsList.size()];
+        selectorsList.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     * @return an enumerator for the selectors
+     */
+    public Enumeration selectorElements() {
+        return selectorsList.elements();
+    }
+
+    /**
+     * Convert the Selectors within this container to a string. This will
+     * just be a helper class for the subclasses that put their own name
+     * around the contents listed here.
+     *
+     * @return comma separated list of Selectors contained in this one
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        Enumeration e = selectorElements();
+        if (e.hasMoreElements()) {
+            while (e.hasMoreElements()) {
+                buf.append(e.nextElement().toString());
+                if (e.hasMoreElements()) {
+                    buf.append(", ");
+                }
+            }
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new selector to add
+     */
+    public void appendSelector(FileSelector selector) {
+        selectorsList.addElement(selector);
+    }
+
+    /**
+     * <p>This implementation validates the container by calling
+     * verifySettings() and then validates each contained selector
+     * provided that the selector implements the validate interface.
+     * </p>
+     * <p>Ordinarily, this will validate all the elements of a selector
+     * container even if the isSelected() method of some elements is
+     * never called. This has two effects:</p>
+     * <ul>
+     * <li>Validation will often occur twice.
+     * <li>Since it is not required that selectors derive from
+     * BaseSelector, there could be selectors in the container whose
+     * error conditions are not detected if their isSelected() call
+     * is never made.
+     * </ul>
+     */
+    public void validate() {
+        verifySettings();
+        String errmsg = getError();
+        if (errmsg != null) {
+            throw new BuildException(errmsg);
+        }
+        Enumeration e = selectorElements();
+        while (e.hasMoreElements()) {
+            Object o = e.nextElement();
+            if (o instanceof BaseSelector) {
+                ((BaseSelector) o).validate();
+            }
+        }
+    }
+
+
+    /**
+     * Method that each selector will implement to create their selection
+     * behaviour. This is what makes SelectorContainer abstract.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename the name of the file to check
+     * @param file a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public abstract boolean isSelected(File basedir, String filename,
+                                       File file);
+
+
+    /* Methods below all add specific selectors */
+
+    /**
+     * add a "Select" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSelector(SelectSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an "And" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addAnd(AndSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an "Or" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addOr(OrSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a "Not" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNot(NotSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a "None" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addNone(NoneSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a majority selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addMajority(MajoritySelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector date entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDate(DateSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector size entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addSize(SizeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a selector filename entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addFilename(FilenameSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an extended selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addCustom(ExtendSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a contains selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContains(ContainsSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a present selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addPresent(PresentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a depth selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepth(DepthSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a depends selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addDepend(DependSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * adds a different selector to the selector list
+     * @param selector the selector to add
+     */
+    public void addDifferent(DifferentSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * adds a type selector to the selector list
+     * @param selector the selector to add
+     */
+    public void addType(TypeSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add a regular expression selector entry on the selector list
+     * @param selector the selector to add
+     */
+    public void addContainsRegexp(ContainsRegexpSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add the modified selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    public void addModified(ModifiedSelector selector) {
+        appendSelector(selector);
+    }
+
+    /**
+     * add an arbitary selector
+     * @param selector the selector to add
+     * @since Ant 1.6
+     */
+    public void add(FileSelector selector) {
+        appendSelector(selector);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsRegexpSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsRegexpSelector.java
new file mode 100644
index 0000000..4de2725
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsRegexpSelector.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.RegularExpression;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.util.regexp.Regexp;
+
+/**
+ * Selector that filters files based on a regular expression.
+ *
+ * @since Ant 1.6
+ */
+public class ContainsRegexpSelector extends BaseExtendSelector
+        implements ResourceSelector {
+
+    private String userProvidedExpression = null;
+    private RegularExpression myRegExp = null;
+    private Regexp myExpression = null;
+    /** Key to used for parameterized custom selector */
+    public static final String EXPRESSION_KEY = "expression";
+
+    /**
+     * Creates a new <code>ContainsRegexpSelector</code> instance.
+     */
+    public ContainsRegexpSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer(
+                "{containsregexpselector expression: ");
+        buf.append(userProvidedExpression);
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * The regular expression used to search the file.
+     *
+     * @param theexpression this must match a line in the file to be selected.
+     */
+    public void setExpression(String theexpression) {
+        this.userProvidedExpression = theexpression;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (EXPRESSION_KEY.equalsIgnoreCase(paramname)) {
+                    setExpression(parameters[i].getValue());
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks that an expression was specified.
+     *
+     */
+    public void verifySettings() {
+        if (userProvidedExpression == null) {
+            setError("The expression attribute is required");
+        }
+    }
+
+    /**
+     * Tests a regular expression against each line of text in the file.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        return isSelected(new FileResource(file));
+    }
+
+    /**
+     * Tests a regular expression against each line of text in a Resource.
+     *
+     * @param r the Resource to check.
+     * @return whether the Resource is selected or not
+     */
+    public boolean isSelected(Resource r) {
+        String teststr = null;
+        BufferedReader in = null;
+
+        // throw BuildException on error
+
+        validate();
+
+        if (r.isDirectory()) {
+            return true;
+        }
+
+        if (myRegExp == null) {
+            myRegExp = new RegularExpression();
+            myRegExp.setPattern(userProvidedExpression);
+            myExpression = myRegExp.getRegexp(getProject());
+        }
+
+        try {
+            in = new BufferedReader(new InputStreamReader(r.getInputStream()));
+        } catch (Exception e) {
+            throw new BuildException("Could not get InputStream from "
+                    + r.toLongString(), e);
+        }
+        try {
+            teststr = in.readLine();
+
+            while (teststr != null) {
+
+                if (myExpression.matches(teststr)) {
+                    return true;
+                }
+                teststr = in.readLine();
+            }
+
+            return false;
+        } catch (IOException ioe) {
+            throw new BuildException("Could not read " + r.toLongString());
+        } finally {
+            try {
+                in.close();
+            } catch (Exception e) {
+                throw new BuildException("Could not close "
+                                         + r.toLongString());
+            }
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java
new file mode 100644
index 0000000..31c5c5a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java
@@ -0,0 +1,207 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Selector that filters files/resources based on whether they contain a
+ * particular string.
+ *
+ * @since 1.5
+ */
+public class ContainsSelector extends BaseExtendSelector implements ResourceSelector {
+
+    private String contains = null;
+    private boolean casesensitive = true;
+    private boolean ignorewhitespace = false;
+    /** Key to used for parameterized custom selector */
+    public static final String EXPRESSION_KEY = "expression";
+    /** Used for parameterized custom selector */
+    public static final String CONTAINS_KEY = "text";
+    /** Used for parameterized custom selector */
+    public static final String CASE_KEY = "casesensitive";
+    /** Used for parameterized custom selector */
+    public static final String WHITESPACE_KEY = "ignorewhitespace";
+
+
+    /**
+     * Creates a new <code>ContainsSelector</code> instance.
+     *
+     */
+    public ContainsSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{containsselector text: ");
+        buf.append('"').append(contains).append('"');
+        buf.append(" casesensitive: ");
+        buf.append(casesensitive ? "true" : "false");
+        buf.append(" ignorewhitespace: ");
+        buf.append(ignorewhitespace ? "true" : "false");
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * The string to search for within a file.
+     *
+     * @param contains the string that a file must contain to be selected.
+     */
+    public void setText(String contains) {
+        this.contains = contains;
+    }
+
+    /**
+     * Whether to ignore case in the string being searched.
+     *
+     * @param casesensitive whether to pay attention to case sensitivity
+     */
+    public void setCasesensitive(boolean casesensitive) {
+        this.casesensitive = casesensitive;
+    }
+
+    /**
+     * Whether to ignore whitespace in the string being searched.
+     *
+     * @param ignorewhitespace whether to ignore any whitespace
+     *        (spaces, tabs, etc.) in the searchstring
+     */
+    public void setIgnorewhitespace(boolean ignorewhitespace) {
+        this.ignorewhitespace = ignorewhitespace;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (CONTAINS_KEY.equalsIgnoreCase(paramname)) {
+                    setText(parameters[i].getValue());
+                } else if (CASE_KEY.equalsIgnoreCase(paramname)) {
+                    setCasesensitive(Project.toBoolean(
+                            parameters[i].getValue()));
+                } else if (WHITESPACE_KEY.equalsIgnoreCase(paramname)) {
+                    setIgnorewhitespace(Project.toBoolean(
+                            parameters[i].getValue()));
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the pattern attribute has been set.
+     *
+     */
+    public void verifySettings() {
+        if (contains == null) {
+            setError("The text attribute is required");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        return isSelected(new FileResource(file));
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a Resource.
+     *
+     * @param r the Resource to check.
+     * @return whether the Resource is selected.
+     */
+    public boolean isSelected(Resource r) {
+
+        // throw BuildException on error
+        validate();
+
+        if (r.isDirectory() || contains.length() == 0) {
+            return true;
+        }
+
+        String userstr = contains;
+        if (!casesensitive) {
+            userstr = contains.toLowerCase();
+        }
+        if (ignorewhitespace) {
+            userstr = SelectorUtils.removeWhitespace(userstr);
+        }
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(r.getInputStream()));
+        } catch (Exception e) {
+            throw new BuildException("Could not get InputStream from "
+                    + r.toLongString(), e);
+        }
+        try {
+            String teststr = in.readLine();
+            while (teststr != null) {
+                if (!casesensitive) {
+                    teststr = teststr.toLowerCase();
+                }
+                if (ignorewhitespace) {
+                    teststr = SelectorUtils.removeWhitespace(teststr);
+                }
+                if (teststr.indexOf(userstr) > -1) {
+                    return true;
+                }
+                teststr = in.readLine();
+            }
+            return false;
+        } catch (IOException ioe) {
+            throw new BuildException("Could not read " + r.toLongString());
+        } finally {
+            FileUtils.close(in);
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/DateSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/DateSelector.java
new file mode 100644
index 0000000..76c1d16
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/DateSelector.java
@@ -0,0 +1,260 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
+import java.util.Locale;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.TimeComparison;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Selector that chooses files based on their last modified date.
+ *
+ * @since 1.5
+ */
+public class DateSelector extends BaseExtendSelector {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private long millis = -1;
+    private String dateTime = null;
+    private boolean includeDirs = false;
+    private long granularity = 0;
+    private String pattern;
+    private TimeComparison when = TimeComparison.EQUAL;
+
+    /** Key to used for parameterized custom selector */
+    public static final String MILLIS_KEY = "millis";
+    /** Key to used for parameterized custom selector */
+    public static final String DATETIME_KEY = "datetime";
+    /** Key to used for parameterized custom selector */
+    public static final String CHECKDIRS_KEY = "checkdirs";
+    /** Key to used for parameterized custom selector */
+    public static final String GRANULARITY_KEY = "granularity";
+    /** Key to used for parameterized custom selector */
+    public static final String WHEN_KEY = "when";
+    /** Key to used for parameterized custom selector */
+    public static final String PATTERN_KEY = "pattern";
+
+    /**
+     * Creates a new <code>DateSelector</code> instance.
+     *
+     */
+    public DateSelector() {
+        granularity = FILE_UTILS.getFileTimestampGranularity();
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{dateselector date: ");
+        buf.append(dateTime);
+        buf.append(" compare: ").append(when.getValue());
+        buf.append(" granularity: ");
+        buf.append(granularity);
+        if (pattern != null) {
+            buf.append(" pattern: ").append(pattern);
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * Set the time; for users who prefer to express time in ms since 1970.
+     *
+     * @param millis the time to compare file's last modified date to,
+     *        expressed in milliseconds.
+     */
+    public void setMillis(long millis) {
+        this.millis = millis;
+    }
+
+    /**
+     * Returns the millisecond value the selector is set for.
+     * @return the millisecond value.
+     */
+    public long getMillis() {
+        if (dateTime != null) {
+            validate();
+        }
+        return millis;
+    }
+
+    /**
+     * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM format,
+     * unless an alternate pattern is specified via the pattern attribute.
+     *
+     * @param dateTime a formatted date <code>String</code>.
+     */
+    public void setDatetime(String dateTime) {
+        this.dateTime = dateTime;
+        millis = -1;
+    }
+
+    /**
+     * Set whether to check dates on directories.
+     *
+     * @param includeDirs whether to check the timestamp on directories.
+     */
+    public void setCheckdirs(boolean includeDirs) {
+        this.includeDirs = includeDirs;
+    }
+
+    /**
+     * Sets the number of milliseconds leeway we will give before we consider
+     * a file not to have matched a date.
+     * @param granularity the number of milliseconds leeway.
+     */
+    public void setGranularity(int granularity) {
+        this.granularity = granularity;
+    }
+
+    /**
+     * Sets the type of comparison to be done on the file's last modified
+     * date.
+     *
+     * @param tcmp The comparison to perform, an EnumeratedAttribute.
+     */
+    public void setWhen(TimeComparisons tcmp) {
+        setWhen((TimeComparison) tcmp);
+    }
+
+    /**
+     * Set the comparison type.
+     * @param t TimeComparison object.
+     */
+    public void setWhen(TimeComparison t) {
+        when = t;
+    }
+
+    /**
+     * Sets the pattern to be used for the SimpleDateFormat.
+     *
+     * @param pattern the pattern that defines the date format.
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector.
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (MILLIS_KEY.equalsIgnoreCase(paramname)) {
+                    try {
+                        setMillis(Long.parseLong(parameters[i].getValue()));
+                    } catch (NumberFormatException nfe) {
+                        setError("Invalid millisecond setting "
+                                + parameters[i].getValue());
+                    }
+                } else if (DATETIME_KEY.equalsIgnoreCase(paramname)) {
+                    setDatetime(parameters[i].getValue());
+                } else if (CHECKDIRS_KEY.equalsIgnoreCase(paramname)) {
+                    setCheckdirs(Project.toBoolean(parameters[i].getValue()));
+                } else if (GRANULARITY_KEY.equalsIgnoreCase(paramname)) {
+                    try {
+                        setGranularity(Integer.parseInt(parameters[i].getValue()));
+                    } catch (NumberFormatException nfe) {
+                        setError("Invalid granularity setting "
+                            + parameters[i].getValue());
+                    }
+                } else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
+                    setWhen(new TimeComparison(parameters[i].getValue()));
+                } else if (PATTERN_KEY.equalsIgnoreCase(paramname)) {
+                    setPattern(parameters[i].getValue());
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * This is a consistency check to ensure the selector's required
+     * values have been set.
+     */
+    public void verifySettings() {
+        if (dateTime == null && millis < 0) {
+            setError("You must provide a datetime or the number of "
+                    + "milliseconds.");
+        } else if (millis < 0 && dateTime != null) {
+            // check millis and only set it once.
+            DateFormat df = ((pattern == null)
+                ? DateFormat.getDateTimeInstance(
+                    DateFormat.SHORT, DateFormat.SHORT, Locale.US)
+                : new SimpleDateFormat(pattern));
+
+            try {
+                setMillis(df.parse(dateTime).getTime());
+                if (millis < 0) {
+                    setError("Date of " + dateTime
+                        + " results in negative milliseconds value"
+                        + " relative to epoch (January 1, 1970, 00:00:00 GMT).");
+                }
+            } catch (ParseException pe) {
+                setError("Date of " + dateTime
+                        + " Cannot be parsed correctly. It should be in"
+                        + ((pattern == null)
+                        ? " MM/DD/YYYY HH:MM AM_PM" : pattern) + " format.");
+            }
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir the base directory from which the scan is being performed.
+     * @param filename is the name of the file to check.
+     * @param file is a java.io.File object the selector can use.
+     * @return whether the file is selected.
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        validate();
+
+        return (file.isDirectory() && !includeDirs)
+            || when.evaluate(file.lastModified(), millis, granularity);
+    }
+
+    /**
+     * Enumerated attribute with the values for time comparison.
+     * <p>
+     */
+    public static class TimeComparisons extends TimeComparison {
+    }
+
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/DependSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/DependSelector.java
new file mode 100644
index 0000000..f22ad29
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/DependSelector.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+/**
+ * Selector that filters files based on whether they are newer than
+ * a matching file in another directory tree. It can contain a mapper
+ * element, so isn't available as an ExtendSelector (since those
+ * parameters can't hold other elements).
+ *
+ * @since 1.5
+ */
+public class DependSelector extends MappingSelector {
+
+    /**
+     * Creates a new <code>DependSelector</code> instance.
+     *
+     */
+    public DependSelector() {
+
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{dependselector targetdir: ");
+        if (targetdir == null) {
+            buf.append("NOT YET SET");
+        } else {
+            buf.append(targetdir.getName());
+        }
+        buf.append(" granularity: ");
+        buf.append(granularity);
+        if (map != null) {
+            buf.append(" mapper: ");
+            buf.append(map.toString());
+        } else if (mapperElement != null) {
+            buf.append(" mapper: ");
+            buf.append(mapperElement.toString());
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+
+    /**
+     * this test is our selection test that compared the file with the destfile
+     * @param srcfile the source file
+     * @param destfile the destination file
+     * @return true if destination is out of date
+     */
+    public boolean selectionTest(File srcfile, File destfile) {
+        boolean selected = SelectorUtils.isOutOfDate(srcfile, destfile,
+                granularity);
+        return selected;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java
new file mode 100644
index 0000000..9d61650
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java
@@ -0,0 +1,185 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that filters files based on the how deep in the directory
+ * tree they are.
+ *
+ * @since 1.5
+ */
+public class DepthSelector extends BaseExtendSelector {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** min attribute */
+    public int min = -1;
+    /** max attribute */
+    public int max = -1;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /** Used for parameterized custom selector */
+    public static final String MIN_KEY = "min";
+    /** Used for parameterized custom selector */
+    public static final String MAX_KEY = "max";
+
+    /**
+     * Creates a new <code>DepthSelector</code> instance.
+     *
+     */
+    public DepthSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{depthselector min: ");
+        buf.append(min);
+        buf.append(" max: ");
+        buf.append(max);
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * The minimum depth below the basedir before a file is selected.
+     *
+     * @param min minimum directory levels below basedir to go
+     */
+    public void setMin(int min) {
+        this.min = min;
+    }
+
+    /**
+     * The minimum depth below the basedir before a file is selected.
+     *
+     * @param max maximum directory levels below basedir to go
+     */
+    public void setMax(int max) {
+        this.max = max;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (MIN_KEY.equalsIgnoreCase(paramname)) {
+                    try {
+                        setMin(Integer.parseInt(parameters[i].getValue()));
+                    } catch (NumberFormatException nfe1) {
+                        setError("Invalid minimum value "
+                                + parameters[i].getValue());
+                    }
+                } else if (MAX_KEY.equalsIgnoreCase(paramname)) {
+                    try {
+                        setMax(Integer.parseInt(parameters[i].getValue()));
+                    } catch (NumberFormatException nfe1) {
+                        setError("Invalid maximum value "
+                                + parameters[i].getValue());
+                    }
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the max depth is not lower than the min depth.
+     */
+    public void verifySettings() {
+        if (min < 0 && max < 0) {
+            setError("You must set at least one of the min or the "
+                    + "max levels.");
+        }
+        if (max < min && max > -1) {
+            setError("The maximum depth is lower than the minimum.");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset. Most of the work
+     * for this selector is offloaded into SelectorUtils, a static class
+     * that provides the same services for both FilenameSelector and
+     * DirectoryScanner.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        // throw BuildException on error
+        validate();
+
+        int depth = -1;
+        // If you felt daring, you could cache the basedir absolute path
+        String absBase = basedir.getAbsolutePath();
+        String absFile = file.getAbsolutePath();
+        StringTokenizer tokBase = new StringTokenizer(absBase,
+                File.separator);
+        StringTokenizer tokFile = new StringTokenizer(absFile,
+                File.separator);
+        while (tokFile.hasMoreTokens()) {
+            String filetoken = tokFile.nextToken();
+            if (tokBase.hasMoreTokens()) {
+                String basetoken = tokBase.nextToken();
+                // Sanity check. Ditch it if you want faster performance
+                if (!basetoken.equals(filetoken)) {
+                    throw new BuildException("File " + filename
+                            + " does not appear within " + absBase
+                            + "directory");
+                }
+            } else {
+                depth += 1;
+                if (max > -1 && depth > max) {
+                    return false;
+                }
+            }
+        }
+        if (tokBase.hasMoreTokens()) {
+            throw new BuildException("File " + filename
+                + " is outside of " + absBase + "directory tree");
+        }
+        if (min > -1 && depth < min) {
+            return false;
+        }
+        return true;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/DifferentSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/DifferentSelector.java
new file mode 100644
index 0000000..c11259d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/DifferentSelector.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.BuildException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * This selector selects files against a mapped set of target files, selecting
+ * all those files which are different.
+ * Files with different lengths are deemed different
+ * automatically
+ * Files with identical timestamps are viewed as matching by
+ * default, unless you specify otherwise.
+ * Contents are compared if the lengths are the same
+ * and the timestamps are ignored or the same,
+ * except if you decide to ignore contents to gain speed.
+ * <p>
+ * This is a useful selector to work with programs and tasks that don't handle
+ * dependency checking properly; Even if a predecessor task always creates its
+ * output files, followup tasks can be driven off copies made with a different
+ * selector, so their dependencies are driven on the absolute state of the
+ * files, not a timestamp.
+ * <p>
+ * Clearly, however, bulk file comparisons is inefficient; anything that can
+ * use timestamps is to be preferred. If this selector must be used, use it
+ * over as few files as possible, perhaps following it with an &lt;uptodate;&gt
+ * to keep the descendent routines conditional.
+ *
+ */
+public class DifferentSelector extends MappingSelector {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private boolean ignoreFileTimes = true;
+    private boolean ignoreContents = false;
+
+
+    /**
+     * This flag tells the selector to ignore file times in the comparison
+     * @param ignoreFileTimes if true ignore file times
+     */
+    public void setIgnoreFileTimes(boolean ignoreFileTimes) {
+        this.ignoreFileTimes = ignoreFileTimes;
+    }
+    /**
+     * This flag tells the selector to ignore contents
+     * @param ignoreContents if true ignore contents
+     * @since ant 1.6.3
+     */
+    public void setIgnoreContents(boolean ignoreContents) {
+        this.ignoreContents = ignoreContents;
+    }
+    /**
+     * this test is our selection test that compared the file with the destfile
+     * @param srcfile the source file
+     * @param destfile the destination file
+     * @return true if the files are different
+     */
+    protected boolean selectionTest(File srcfile, File destfile) {
+
+        //if either of them is missing, they are different
+        if (srcfile.exists() != destfile.exists()) {
+            return true;
+        }
+
+        if (srcfile.length() != destfile.length()) {
+            // different size =>different files
+            return true;
+        }
+
+        if (!ignoreFileTimes) {
+            //same date if dest timestamp is within granularity of the srcfile
+            boolean sameDate;
+            sameDate = destfile.lastModified() >= srcfile.lastModified() - granularity
+                    && destfile.lastModified() <= srcfile.lastModified() + granularity;
+
+            // different dates => different files
+            if (!sameDate) {
+                return true;
+            }
+        }
+        if (!ignoreContents) {
+            //here do a bulk comparison
+            try {
+                return !FILE_UTILS.contentEquals(srcfile, destfile);
+            } catch (IOException e) {
+                throw new BuildException("while comparing " + srcfile + " and "
+                        + destfile, e);
+            }
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java
new file mode 100644
index 0000000..4c64d11
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.types.Parameterizable;
+
+/**
+ * This is the interface to be used by all custom selectors, those that are
+ * called through the &lt;custom&gt; tag. It is the amalgamation of two
+ * interfaces, the FileSelector and the Paramterizable interface. Note that
+ * you will almost certainly want the default behaviour for handling
+ * Parameters, so you probably want to use the BaseExtendSelector class
+ * as the base class for your custom selector rather than implementing
+ * this interface from scratch.
+ *
+ * @since 1.5
+ */
+public interface ExtendFileSelector extends FileSelector, Parameterizable {
+
+    // No further methods necessary. This is just an amalgamation of two other
+    // interfaces.
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java
new file mode 100644
index 0000000..05bc265
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java
@@ -0,0 +1,200 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Selector that selects files by forwarding the request on to other classes.
+ *
+ * @since 1.5
+ */
+public class ExtendSelector extends BaseSelector {
+
+    private String classname = null;
+    private FileSelector dynselector = null;
+    private Vector paramVec = new Vector();
+    private Path classpath = null;
+
+    /**
+     * Default constructor.
+     */
+    public ExtendSelector() {
+    }
+
+    /**
+     * Sets the classname of the custom selector.
+     *
+     * @param classname is the class which implements this selector
+     */
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    /**
+     * Instantiates the identified custom selector class.
+     */
+    public void selectorCreate() {
+        if (classname != null && classname.length() > 0) {
+            try {
+                Class c = null;
+                if (classpath == null) {
+                    c = Class.forName(classname);
+                } else {
+                    AntClassLoader al
+                            = getProject().createClassLoader(classpath);
+                    c = Class.forName(classname, true, al);
+                }
+                dynselector = (FileSelector) c.newInstance();
+                final Project p = getProject();
+                if (p != null) {
+                    p.setProjectReference(dynselector);
+                }
+            } catch (ClassNotFoundException cnfexcept) {
+                setError("Selector " + classname
+                    + " not initialized, no such class");
+            } catch (InstantiationException iexcept) {
+                setError("Selector " + classname
+                    + " not initialized, could not create class");
+            } catch (IllegalAccessException iaexcept) {
+                setError("Selector " + classname
+                    + " not initialized, class not accessible");
+            }
+        } else {
+            setError("There is no classname specified");
+        }
+    }
+
+    /**
+     * Create new parameters to pass to custom selector.
+     *
+     * @param p The new Parameter object
+     */
+    public void addParam(Parameter p) {
+        paramVec.addElement(p);
+    }
+
+
+    /**
+     * Set the classpath to load the classname specified using an attribute.
+     * @param classpath the classpath to use
+     */
+    public final void setClasspath(Path classpath) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        if (this.classpath == null) {
+            this.classpath = classpath;
+        } else {
+            this.classpath.append(classpath);
+        }
+    }
+
+    /**
+     * Specify the classpath to use to load the Selector (nested element).
+     * @return a classpath to be configured
+     */
+    public final Path createClasspath() {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        if (this.classpath == null) {
+            this.classpath = new Path(getProject());
+        }
+        return this.classpath.createPath();
+    }
+
+    /**
+     * Get the classpath
+     * @return the classpath
+     */
+    public final Path getClasspath() {
+        return classpath;
+    }
+
+    /**
+     * Set the classpath to use for loading a custom selector by using
+     * a reference.
+     * @param r a reference to the classpath
+     */
+    public void setClasspathref(Reference r) {
+        if (isReference()) {
+            throw tooManyAttributes();
+        }
+        createClasspath().setRefid(r);
+    }
+
+    /**
+     * These are errors specific to ExtendSelector only. If there are
+     * errors in the custom selector, it should throw a BuildException
+     * when isSelected() is called.
+     */
+    public void verifySettings() {
+        // Creation is done here rather than in isSelected() because some
+        // containers may do a validation pass before running isSelected(),
+        // but we need to check for the existence of the created class.
+        if (dynselector == null) {
+            selectorCreate();
+        }
+        if (classname == null || classname.length() < 1) {
+            setError("The classname attribute is required");
+        } else if (dynselector == null) {
+            setError("Internal Error: The custom selector was not created");
+        } else if (!(dynselector instanceof ExtendFileSelector)
+                    && (paramVec.size() > 0)) {
+            setError("Cannot set parameters on custom selector that does not "
+                    + "implement ExtendFileSelector");
+        }
+    }
+
+
+    /**
+     * Allows the custom selector to choose whether to select a file. This
+     * is also where the Parameters are passed to the custom selector,
+     * since we know we must have them all by now. And since we must know
+     * both classpath and classname, creating the class is deferred to here
+     * as well.
+     * @param basedir The the base directory.
+     * @param filename The name of the file to check.
+     * @param file A File object for this filename.
+     * @return whether the file should be selected or not.
+     * @exception BuildException if an error occurs.
+     */
+    public boolean isSelected(File basedir, String filename, File file)
+            throws BuildException {
+        validate();
+        if (paramVec.size() > 0 && dynselector instanceof ExtendFileSelector) {
+            Parameter[] paramArray = new Parameter[paramVec.size()];
+            paramVec.copyInto(paramArray);
+            // We know that dynselector must be non-null if no error message
+            ((ExtendFileSelector) dynselector).setParameters(paramArray);
+        }
+        return dynselector.isSelected(basedir, filename, file);
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/FileSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/FileSelector.java
new file mode 100644
index 0000000..614a970
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/FileSelector.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This is the interface to be used by all selectors.
+ *
+ * @since 1.5
+ */
+public interface FileSelector {
+
+    /**
+     * Method that each selector will implement to create their
+     * selection behaviour. If there is a problem with the setup
+     * of a selector, it can throw a BuildException to indicate
+     * the problem.
+     *
+     * @param basedir A java.io.File object for the base directory
+     * @param filename The name of the file to check
+     * @param file A File object for this filename
+     * @return whether the file should be selected or not
+     * @exception BuildException if the selector was not configured correctly
+     */
+    boolean isSelected(File basedir, String filename, File file)
+            throws BuildException;
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java
new file mode 100644
index 0000000..dc5d4ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that filters files based on the filename.
+ *
+ * @since 1.5
+ */
+public class FilenameSelector extends BaseExtendSelector {
+
+    private String pattern = null;
+    private boolean casesensitive = true;
+
+    private boolean negated = false;
+    /** Used for parameterized custom selector */
+    public static final String NAME_KEY = "name";
+    /** Used for parameterized custom selector */
+    public static final String CASE_KEY = "casesensitive";
+    /** Used for parameterized custom selector */
+    public static final String NEGATE_KEY = "negate";
+
+    /**
+     * Creates a new <code>FilenameSelector</code> instance.
+     *
+     */
+    public FilenameSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{filenameselector name: ");
+        buf.append(pattern);
+        buf.append(" negate: ");
+        if (negated) {
+            buf.append("true");
+        } else {
+            buf.append("false");
+        }
+        buf.append(" casesensitive: ");
+        if (casesensitive) {
+            buf.append("true");
+        } else {
+            buf.append("false");
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * The name of the file, or the pattern for the name, that
+     * should be used for selection.
+     *
+     * @param pattern the file pattern that any filename must match
+     *                against in order to be selected.
+     */
+    public void setName(String pattern) {
+        pattern = pattern.replace('/', File.separatorChar).replace('\\',
+                File.separatorChar);
+        if (pattern.endsWith(File.separator)) {
+            pattern += "**";
+        }
+        this.pattern = pattern;
+    }
+
+    /**
+     * Whether to ignore case when checking filenames.
+     *
+     * @param casesensitive whether to pay attention to case sensitivity
+     */
+    public void setCasesensitive(boolean casesensitive) {
+        this.casesensitive = casesensitive;
+    }
+
+    /**
+     * You can optionally reverse the selection of this selector,
+     * thereby emulating an &lt;exclude&gt; tag, by setting the attribute
+     * negate to true. This is identical to surrounding the selector
+     * with &lt;not&gt;&lt;/not&gt;.
+     *
+     * @param negated whether to negate this selection
+     */
+    public void setNegate(boolean negated) {
+        this.negated = negated;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (NAME_KEY.equalsIgnoreCase(paramname)) {
+                    setName(parameters[i].getValue());
+                } else if (CASE_KEY.equalsIgnoreCase(paramname)) {
+                    setCasesensitive(Project.toBoolean(
+                            parameters[i].getValue()));
+                } else if (NEGATE_KEY.equalsIgnoreCase(paramname)) {
+                    setNegate(Project.toBoolean(parameters[i].getValue()));
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the name attribute has been set.
+     *
+     */
+    public void verifySettings() {
+        if (pattern == null) {
+            setError("The name attribute is required");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset. Most of the work
+     * for this selector is offloaded into SelectorUtils, a static class
+     * that provides the same services for both FilenameSelector and
+     * DirectoryScanner.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+
+        return (SelectorUtils.matchPath(pattern, filename,
+                casesensitive) == !(negated));
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java
new file mode 100644
index 0000000..137ee8e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector is here just to shake up your thinking a bit. Don't get
+ * too caught up in boolean, there are other ways you can evaluate a
+ * collection of selectors. This one takes a vote of the selectors it
+ * contains, and majority wins. You could also have an "all-but-one"
+ * selector, a "weighted-average" selector, and so on. These are left
+ * as exercises for the reader (as are the usecases where this would
+ * be necessary).
+ *
+ * @since 1.5
+ */
+public class MajoritySelector extends BaseSelectorContainer {
+
+    private boolean allowtie = true;
+
+    /**
+     * Default constructor.
+     */
+    public MajoritySelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{majorityselect: ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * A attribute to specify what will happen if number
+     * of yes votes is the same as the number of no votes
+     * defaults to true
+     *
+     * @param tiebreaker the value to give if there is a tie
+     */
+    public void setAllowtie(boolean tiebreaker) {
+        allowtie = tiebreaker;
+    }
+
+    /**
+     * Returns true (the file is selected) if most of the other selectors
+     * agree. In case of a tie, go by the allowtie setting. That defaults
+     * to true, meaning in case of a tie, the file is selected.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+        int yesvotes = 0;
+        int novotes = 0;
+        Enumeration e = selectorElements();
+        boolean result;
+
+        while (e.hasMoreElements()) {
+            result = ((FileSelector) e.nextElement()).isSelected(basedir,
+                    filename, file);
+            if (result) {
+                yesvotes = yesvotes + 1;
+            } else {
+                novotes = novotes + 1;
+            }
+        }
+        if (yesvotes > novotes) {
+            return true;
+        } else if (novotes > yesvotes) {
+            return false;
+        }
+        // At this point, we know we have a tie.
+        return allowtie;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/MappingSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/MappingSelector.java
new file mode 100644
index 0000000..5135605
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/MappingSelector.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.IdentityMapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+
+/**
+ * A mapping selector is an abstract class adding mapping support to the base
+ * selector
+ */
+public abstract class MappingSelector extends BaseSelector {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    protected File targetdir = null;
+    protected Mapper mapperElement = null;
+    protected FileNameMapper map = null;
+    protected int granularity = 0;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Creates a new <code>MappingSelector</code> instance.
+     *
+     */
+    public MappingSelector() {
+        granularity = (int) FILE_UTILS.getFileTimestampGranularity();
+    }
+
+
+    /**
+     * The name of the file or directory which is checked for out-of-date
+     * files.
+     *
+     * @param targetdir the directory to scan looking for files.
+     */
+    public void setTargetdir(File targetdir) {
+        this.targetdir = targetdir;
+    }
+
+    /**
+     * Defines the FileNameMapper to use (nested mapper element).
+     * @return a mapper to be configured
+     * @throws BuildException if more that one mapper defined
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper");
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the dest attribute has been set and we have a mapper.
+     */
+    public void verifySettings() {
+        if (targetdir == null) {
+            setError("The targetdir attribute is required.");
+        }
+        if (mapperElement == null) {
+            map = new IdentityMapper();
+        } else {
+            map = mapperElement.getImplementation();
+        }
+        if (map == null) {
+            setError("Could not set <mapper> element.");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        // throw BuildException on error
+        validate();
+
+        // Determine file whose out-of-dateness is to be checked
+        String[] destfiles = map.mapFileName(filename);
+        // If filename does not match the To attribute of the mapper
+        // then filter it out of the files we are considering
+        if (destfiles == null) {
+            return false;
+        }
+        // Sanity check
+        if (destfiles.length != 1 || destfiles[0] == null) {
+            throw new BuildException("Invalid destination file results for "
+                    + targetdir.getName() + " with filename " + filename);
+        }
+        String destname = destfiles[0];
+        File destfile = new File(targetdir, destname);
+
+        boolean selected = selectionTest(file, destfile);
+        return selected;
+    }
+
+    /**
+     * this test is our selection test that compared the file with the destfile
+     * @param srcfile file to test; may be null
+     * @param destfile destination file
+     * @return true if source file compares with destination file
+     */
+    protected abstract boolean selectionTest(File srcfile, File destfile);
+
+    /**
+     * Sets the number of milliseconds leeway we will give before we consider
+     * a file out of date. Defaults to 2000 on MS-DOS derivatives and 1000 on
+     * others.
+     * @param granularity the leeway in milliseconds
+     */
+    public void setGranularity(int granularity) {
+        this.granularity = granularity;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java
new file mode 100644
index 0000000..441f001
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors. All of those selectors
+ * must refuse to select a file before the file is considered selected by
+ * this selector.
+ *
+ * @since 1.5
+ */
+public class NoneSelector extends BaseSelectorContainer {
+
+    /**
+     * Default constructor.
+     */
+    public NoneSelector() {
+    }
+
+    /**
+     * @return a string representation of the selector
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{noneselect: ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Returns true (the file is selected) only if all other selectors
+     * agree that the file should not be selected.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+        Enumeration e = selectorElements();
+        boolean result;
+
+        while (e.hasMoreElements()) {
+            result = ((FileSelector) e.nextElement()).isSelected(basedir,
+                    filename, file);
+            if (result) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/NotSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/NotSelector.java
new file mode 100644
index 0000000..d5ff97b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/NotSelector.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+
+/**
+ * This selector has one other selectors whose meaning it inverts. It
+ * actually relies on NoneSelector for its implementation of the
+ * isSelected() method, but it adds a check to ensure there is only one
+ * other selector contained within.
+ *
+ * @since 1.5
+ */
+public class NotSelector extends NoneSelector {
+
+    /**
+     * Default constructor.
+     */
+    public NotSelector() {
+    }
+
+    /**
+     * Constructor that inverts the meaning of its argument.
+     * @param other the selector to invert
+     * @since Ant 1.7
+     */
+    public NotSelector(FileSelector other) {
+        this();
+        appendSelector(other);
+    }
+
+    /**
+     * @return a string representation of the selector
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{notselect: ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Makes sure that there is only one entry, sets an error message if
+     * not.
+     */
+    public void verifySettings() {
+        if (selectorCount() != 1) {
+            setError("One and only one selector is allowed within the "
+                + "<not> tag");
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/OrSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/OrSelector.java
new file mode 100644
index 0000000..71833ff
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/OrSelector.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.Enumeration;
+
+/**
+ * This selector has a collection of other selectors, any of which have to
+ * select a file in order for this selector to select it.
+ *
+ * @since 1.5
+ */
+public class OrSelector extends BaseSelectorContainer {
+
+    /**
+     * Default constructor.
+     */
+    public OrSelector() {
+    }
+
+    /**
+     * @return a string representation of the selector
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{orselect: ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Returns true (the file is selected) if any of the other selectors
+     * agree that the file should be selected.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename the name of the file to check
+     * @param file a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+        Enumeration e = selectorElements();
+        boolean result;
+
+        // First, check that all elements are correctly configured
+        while (e.hasMoreElements()) {
+            result = ((FileSelector) e.nextElement()).isSelected(basedir,
+                    filename, file);
+            if (result) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java
new file mode 100644
index 0000000..b32578a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java
@@ -0,0 +1,181 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+
+/**
+ * Selector that filters files based on whether they appear in another
+ * directory tree. It can contain a mapper element, so isn't available
+ * as an ExtendSelector (since those parameters can't hold other
+ * elements).
+ *
+ * @since 1.5
+ */
+public class PresentSelector extends BaseSelector {
+
+    private File targetdir = null;
+    private Mapper mapperElement = null;
+    private FileNameMapper map = null;
+    private boolean destmustexist = true;
+
+    /**
+     * Creates a new <code>PresentSelector</code> instance.
+     *
+     */
+    public PresentSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{presentselector targetdir: ");
+        if (targetdir == null) {
+            buf.append("NOT YET SET");
+        } else {
+            buf.append(targetdir.getName());
+        }
+        buf.append(" present: ");
+        if (destmustexist) {
+            buf.append("both");
+        } else {
+            buf.append("srconly");
+        }
+        if (map != null) {
+            buf.append(map.toString());
+        } else if (mapperElement != null) {
+            buf.append(mapperElement.toString());
+        }
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * The name of the file or directory which is checked for matching
+     * files.
+     *
+     * @param targetdir the directory to scan looking for matching files.
+     */
+    public void setTargetdir(File targetdir) {
+        this.targetdir = targetdir;
+    }
+
+    /**
+     * Defines the FileNameMapper to use (nested mapper element).
+     * @return a mapper to be configured
+     * @throws BuildException if more that one mapper defined
+     */
+    public Mapper createMapper() throws BuildException {
+        if (mapperElement != null) {
+            throw new BuildException("Cannot define more than one mapper");
+        }
+        mapperElement = new Mapper(getProject());
+        return mapperElement;
+    }
+
+
+    /**
+     * This sets whether to select a file if its dest file is present.
+     * It could be a <code>negate</code> boolean, but by doing things
+     * this way, we get some documentation on how the system works.
+     * A user looking at the documentation should clearly understand
+     * that the ONLY files whose presence is being tested are those
+     * that already exist in the source directory, hence the lack of
+     * a <code>destonly</code> option.
+     *
+     * @param fp An attribute set to either <code>srconly</code or
+     *           <code>both</code>.
+     */
+    public void setPresent(FilePresence fp) {
+        if (fp.getIndex() == 0) {
+            destmustexist = false;
+        }
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the targetdir attribute has been set and we have a mapper.
+     */
+    public void verifySettings() {
+        if (targetdir == null) {
+            setError("The targetdir attribute is required.");
+        }
+        if (mapperElement == null) {
+            map = new IdentityMapper();
+        } else {
+            map = mapperElement.getImplementation();
+        }
+        if (map == null) {
+            setError("Could not set <mapper> element.");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        // throw BuildException on error
+        validate();
+
+        // Determine file whose existence is to be checked
+        String[] destfiles = map.mapFileName(filename);
+        // If filename does not match the To attribute of the mapper
+        // then filter it out of the files we are considering
+        if (destfiles == null) {
+            return false;
+        }
+        // Sanity check
+        if (destfiles.length != 1 || destfiles[0] == null) {
+            throw new BuildException("Invalid destination file results for "
+                    + targetdir + " with filename " + filename);
+        }
+        String destname = destfiles[0];
+        File destfile = new File(targetdir, destname);
+        return destfile.exists() == destmustexist;
+    }
+
+    /**
+     * Enumerated attribute with the values for indicating where a file's
+     * presence is allowed and required.
+     */
+    public static class FilePresence extends EnumeratedAttribute {
+        /**
+         * @return the values as an array of strings
+         */
+        public String[] getValues() {
+            return new String[]{"srconly", "both"};
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SelectSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectSelector.java
new file mode 100644
index 0000000..159616e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectSelector.java
@@ -0,0 +1,211 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.util.Enumeration;
+import java.io.File;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * This selector just holds one other selector and forwards all
+ * requests to it. It exists so that there is a single selector
+ * type that can exist outside of any targets, as an element of
+ * project. It overrides all of the reference stuff so that it
+ * works as expected. Note that this is the only selector you
+ * can reference.
+ *
+ * @since 1.5
+ */
+public class SelectSelector extends BaseSelectorContainer {
+
+    private String ifProperty;
+    private String unlessProperty;
+
+    /**
+     * Default constructor.
+     */
+    public SelectSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        if (hasSelectors()) {
+            buf.append("{select");
+            if (ifProperty != null) {
+                buf.append(" if: ");
+                buf.append(ifProperty);
+            }
+            if (unlessProperty != null) {
+                buf.append(" unless: ");
+                buf.append(unlessProperty);
+            }
+            buf.append(" ");
+            buf.append(super.toString());
+            buf.append("}");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Performs the check for circular references and returns the
+     * referenced Selector.
+     */
+    private SelectSelector getRef() {
+        Object o = getCheckedRef(this.getClass(), "SelectSelector");
+        return (SelectSelector) o;
+    }
+
+    /**
+     * Indicates whether there are any selectors here.
+     * @return whether any selectors are in this container
+     */
+    public boolean hasSelectors() {
+        if (isReference()) {
+            return getRef().hasSelectors();
+        }
+        return super.hasSelectors();
+    }
+
+    /**
+     * Gives the count of the number of selectors in this container
+     * @return the number of selectors in this container
+     */
+    public int selectorCount() {
+        if (isReference()) {
+            return getRef().selectorCount();
+        }
+        return super.selectorCount();
+    }
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return an array of selectors in this container
+     */
+    public FileSelector[] getSelectors(Project p) {
+        if (isReference()) {
+            return getRef().getSelectors(p);
+        }
+        return super.getSelectors(p);
+    }
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     * @return an enumerator that goes through each of the selectors
+     */
+    public Enumeration selectorElements() {
+        if (isReference()) {
+            return getRef().selectorElements();
+        }
+        return super.selectorElements();
+    }
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new selector to add
+     */
+    public void appendSelector(FileSelector selector) {
+        if (isReference()) {
+            throw noChildrenAllowed();
+        }
+        super.appendSelector(selector);
+    }
+
+
+    /**
+     * Makes sure that there is only one entry, sets an error message if
+     * not.
+     */
+    public void verifySettings() {
+        int cnt = selectorCount();
+        if (cnt < 0 || cnt > 1) {
+            setError("Only one selector is allowed within the "
+                + "<selector> tag");
+        }
+    }
+
+    /**
+     * Ensures that the selector passes the conditions placed
+     * on it with <code>if</code> and <code>unless</code>.
+     * @return true if conditions are passed
+     */
+    public boolean passesConditions() {
+        if (ifProperty != null
+            && getProject().getProperty(ifProperty) == null) {
+            return false;
+        } else if (unlessProperty != null
+            && getProject().getProperty(unlessProperty) != null) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Sets the if attribute to a property which must exist for the
+     * selector to select any files.
+     * @param ifProperty the property to check
+     */
+    public void setIf(String ifProperty) {
+        this.ifProperty = ifProperty;
+    }
+
+    /**
+     * Sets the unless attribute to a property which cannot exist for the
+     * selector to select any files.
+     * @param unlessProperty the property to check
+     */
+    public void setUnless(String unlessProperty) {
+        this.unlessProperty = unlessProperty;
+    }
+
+    /**
+     * Returns true (the file is selected) only if the if property (if any)
+     * exists, the unless property (if any) doesn't exist, and the
+     * contained selector (if any) selects the file. If there is no contained
+     * selector, return true (because we assume that the point was to test
+     * the if and unless conditions).
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename the name of the file to check
+     * @param file a java.io.File object for the filename that the selector
+     * can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        validate();
+
+        // Deal with if and unless properties first
+        if (!(passesConditions())) {
+            return false;
+        }
+
+        Enumeration e = selectorElements();
+        if (!(e.hasMoreElements())) {
+            return true;
+        }
+        FileSelector f = (FileSelector) e.nextElement();
+        return f.isSelected(basedir, filename, file);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java
new file mode 100644
index 0000000..432a364
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.util.Enumeration;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+
+/**
+ * This is the interface for selectors that can contain other selectors.
+ *
+ * @since 1.5
+ */
+public interface SelectorContainer {
+
+    /**
+     * Indicates whether there are any selectors here.
+     *
+     * @return whether any selectors are in this container
+     */
+    boolean hasSelectors();
+
+    /**
+     * Gives the count of the number of selectors in this container
+     *
+     * @return the number of selectors in this container
+     */
+    int selectorCount();
+
+    /**
+     * Returns the set of selectors as an array.
+     * @param p the current project
+     * @return an array of selectors in this container
+     */
+    FileSelector[] getSelectors(Project p);
+
+    /**
+     * Returns an enumerator for accessing the set of selectors.
+     *
+     * @return an enumerator that goes through each of the selectors
+     */
+    Enumeration selectorElements();
+
+    /**
+     * Add a new selector into this container.
+     *
+     * @param selector the new selector to add
+     */
+    void appendSelector(FileSelector selector);
+
+    /* Methods below all add specific selectors */
+
+    /**
+     * add a "Select" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addSelector(SelectSelector selector);
+
+    /**
+     * add an "And" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addAnd(AndSelector selector);
+
+    /**
+     * add an "Or" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addOr(OrSelector selector);
+
+    /**
+     * add a "Not" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addNot(NotSelector selector);
+
+    /**
+     * add a "None" selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addNone(NoneSelector selector);
+
+    /**
+     * add a majority selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addMajority(MajoritySelector selector);
+
+    /**
+     * add a selector date entry on the selector list
+     * @param selector the selector to add
+     */
+    void addDate(DateSelector selector);
+
+    /**
+     * add a selector size entry on the selector list
+     * @param selector the selector to add
+     */
+    void addSize(SizeSelector selector);
+
+    /**
+     * add a selector filename entry on the selector list
+     * @param selector the selector to add
+     */
+    void addFilename(FilenameSelector selector);
+
+    /**
+     * add an extended selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addCustom(ExtendSelector selector);
+
+    /**
+     * add a contains selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addContains(ContainsSelector selector);
+
+    /**
+     * add a present selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addPresent(PresentSelector selector);
+
+    /**
+     * add a depth selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addDepth(DepthSelector selector);
+
+    /**
+     * add a depends selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addDepend(DependSelector selector);
+
+    /**
+     * add a regular expression selector entry on the selector list
+     * @param selector the selector to add
+     */
+    void addContainsRegexp(ContainsRegexpSelector selector);
+
+    /**
+     * add the type selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    void addType(TypeSelector selector);
+
+    /**
+     * add the different selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    void addDifferent(DifferentSelector selector);
+
+    /**
+     * add the modified selector
+     * @param selector the selector to add
+     * @since ant 1.6
+     */
+    void addModified(ModifiedSelector selector);
+
+    /**
+     * add an arbitary selector
+     * @param selector the selector to add
+     * @since Ant 1.6
+     */
+    void add(FileSelector selector);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java
new file mode 100644
index 0000000..718dbc2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.selectors;
+
+/**
+ * An interface used to describe the actions required by any type of
+ * directory scanner that supports Selecters.
+ *
+ * @since 1.5
+ */
+public interface SelectorScanner {
+    /**
+     * Sets the selectors the scanner should use.
+     *
+     * @param selectors the list of selectors
+     */
+    void setSelectors(FileSelector[] selectors);
+
+    /**
+     * Directories which were selected out of a scan.
+     *
+     * @return list of directories not selected
+     */
+    String[] getDeselectedDirectories();
+
+    /**
+     * Files which were selected out of a scan.
+     *
+     * @return list of files not selected
+     */
+    String[] getDeselectedFiles();
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
new file mode 100644
index 0000000..1fd7378
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java
@@ -0,0 +1,681 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * <p>This is a utility class used by selectors and DirectoryScanner. The
+ * functionality more properly belongs just to selectors, but unfortunately
+ * DirectoryScanner exposed these as protected methods. Thus we have to
+ * support any subclasses of DirectoryScanner that may access these methods.
+ * </p>
+ * <p>This is a Singleton.</p>
+ *
+ * @since 1.5
+ */
+public final class SelectorUtils {
+
+    private static SelectorUtils instance = new SelectorUtils();
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Private Constructor
+     */
+    private SelectorUtils() {
+    }
+
+    /**
+     * Retrieves the instance of the Singleton.
+     * @return singleton instance
+     */
+    public static SelectorUtils getInstance() {
+        return instance;
+    }
+
+    /**
+     * Tests whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     * <p>
+     * This is not a general purpose test and should only be used if you
+     * can live with false positives. For example, <code>pattern=**\a</code>
+     * and <code>str=b</code> will yield <code>true</code>.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     *
+     * @return whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     */
+    public static boolean matchPatternStart(String pattern, String str) {
+        return matchPatternStart(pattern, str, true);
+    }
+
+    /**
+     * Tests whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     * <p>
+     * This is not a general purpose test and should only be used if you
+     * can live with false positives. For example, <code>pattern=**\a</code>
+     * and <code>str=b</code> will yield <code>true</code>.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     * @return whether or not a given path matches the start of a given
+     * pattern up to the first "**".
+     */
+    public static boolean matchPatternStart(String pattern, String str,
+                                            boolean isCaseSensitive) {
+        // When str starts with a File.separator, pattern has to start with a
+        // File.separator.
+        // When pattern starts with a File.separator, str has to start with a
+        // File.separator.
+        if (str.startsWith(File.separator)
+                != pattern.startsWith(File.separator)) {
+            return false;
+        }
+
+        String[] patDirs = tokenizePathAsArray(pattern);
+        String[] strDirs = tokenizePathAsArray(str);
+
+        int patIdxStart = 0;
+        int patIdxEnd = patDirs.length - 1;
+        int strIdxStart = 0;
+        int strIdxEnd = strDirs.length - 1;
+
+        // up to first '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = patDirs[patIdxStart];
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
+                return false;
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+
+        // CheckStyle:SimplifyBooleanReturnCheck OFF
+        // Check turned off as the code needs the comments for the various
+        // code paths.
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            return true;
+        } else if (patIdxStart > patIdxEnd) {
+            // String not exhausted, but pattern is. Failure.
+            return false;
+        } else {
+            // pattern now holds ** while string is not exhausted
+            // this will generate false positives but we can live with that.
+            return true;
+        }
+    }
+
+    /**
+     * Tests whether or not a given path matches a given pattern.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     *
+     * @return <code>true</code> if the pattern matches against the string,
+     *         or <code>false</code> otherwise.
+     */
+    public static boolean matchPath(String pattern, String str) {
+        return matchPath(pattern, str, true);
+    }
+
+    /**
+     * Tests whether or not a given path matches a given pattern.
+     *
+     * @param pattern The pattern to match against. Must not be
+     *                <code>null</code>.
+     * @param str     The path to match, as a String. Must not be
+     *                <code>null</code>.
+     * @param isCaseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     * @return <code>true</code> if the pattern matches against the string,
+     *         or <code>false</code> otherwise.
+     */
+    public static boolean matchPath(String pattern, String str,
+                                    boolean isCaseSensitive) {
+        String[] patDirs = tokenizePathAsArray(pattern);
+        String[] strDirs = tokenizePathAsArray(str);
+
+        int patIdxStart = 0;
+        int patIdxEnd = patDirs.length - 1;
+        int strIdxStart = 0;
+        int strIdxEnd = strDirs.length - 1;
+
+        // up to first '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = patDirs[patIdxStart];
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
+                patDirs = null;
+                strDirs = null;
+                return false;
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (!patDirs[i].equals("**")) {
+                    patDirs = null;
+                    strDirs = null;
+                    return false;
+                }
+            }
+            return true;
+        } else {
+            if (patIdxStart > patIdxEnd) {
+                // String not exhausted, but pattern is. Failure.
+                patDirs = null;
+                strDirs = null;
+                return false;
+            }
+        }
+
+        // up to last '**'
+        while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+            String patDir = patDirs[patIdxEnd];
+            if (patDir.equals("**")) {
+                break;
+            }
+            if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
+                patDirs = null;
+                strDirs = null;
+                return false;
+            }
+            patIdxEnd--;
+            strIdxEnd--;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // String is exhausted
+            for (int i = patIdxStart; i <= patIdxEnd; i++) {
+                if (!patDirs[i].equals("**")) {
+                    patDirs = null;
+                    strDirs = null;
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+            int patIdxTmp = -1;
+            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+                if (patDirs[i].equals("**")) {
+                    patIdxTmp = i;
+                    break;
+                }
+            }
+            if (patIdxTmp == patIdxStart + 1) {
+                // '**/**' situation, so skip one
+                patIdxStart++;
+                continue;
+            }
+            // Find the pattern between padIdxStart & padIdxTmp in str between
+            // strIdxStart & strIdxEnd
+            int patLength = (patIdxTmp - patIdxStart - 1);
+            int strLength = (strIdxEnd - strIdxStart + 1);
+            int foundIdx = -1;
+            strLoop:
+                        for (int i = 0; i <= strLength - patLength; i++) {
+                            for (int j = 0; j < patLength; j++) {
+                                String subPat = patDirs[patIdxStart + j + 1];
+                                String subStr = strDirs[strIdxStart + i + j];
+                                if (!match(subPat, subStr, isCaseSensitive)) {
+                                    continue strLoop;
+                                }
+                            }
+
+                            foundIdx = strIdxStart + i;
+                            break;
+                        }
+
+            if (foundIdx == -1) {
+                patDirs = null;
+                strDirs = null;
+                return false;
+            }
+
+            patIdxStart = patIdxTmp;
+            strIdxStart = foundIdx + patLength;
+        }
+
+        for (int i = patIdxStart; i <= patIdxEnd; i++) {
+            if (!patDirs[i].equals("**")) {
+                patDirs = null;
+                strDirs = null;
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Tests whether or not a string matches against a pattern.
+     * The pattern may contain two special characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param pattern The pattern to match against.
+     *                Must not be <code>null</code>.
+     * @param str     The string which must be matched against the pattern.
+     *                Must not be <code>null</code>.
+     *
+     * @return <code>true</code> if the string matches against the pattern,
+     *         or <code>false</code> otherwise.
+     */
+    public static boolean match(String pattern, String str) {
+        return match(pattern, str, true);
+    }
+
+    /**
+     * Tests whether or not a string matches against a pattern.
+     * The pattern may contain two special characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param pattern The pattern to match against.
+     *                Must not be <code>null</code>.
+     * @param str     The string which must be matched against the pattern.
+     *                Must not be <code>null</code>.
+     * @param caseSensitive Whether or not matching should be performed
+     *                        case sensitively.
+     *
+     *
+     * @return <code>true</code> if the string matches against the pattern,
+     *         or <code>false</code> otherwise.
+     */
+    public static boolean match(String pattern, String str,
+                                boolean caseSensitive) {
+        char[] patArr = pattern.toCharArray();
+        char[] strArr = str.toCharArray();
+        int patIdxStart = 0;
+        int patIdxEnd = patArr.length - 1;
+        int strIdxStart = 0;
+        int strIdxEnd = strArr.length - 1;
+        char ch;
+
+        boolean containsStar = false;
+        for (int i = 0; i < patArr.length; i++) {
+            if (patArr[i] == '*') {
+                containsStar = true;
+                break;
+            }
+        }
+
+        if (!containsStar) {
+            // No '*'s, so we make a shortcut
+            if (patIdxEnd != strIdxEnd) {
+                return false; // Pattern and string do not have the same size
+            }
+            for (int i = 0; i <= patIdxEnd; i++) {
+                ch = patArr[i];
+                if (ch != '?') {
+                    if (different(caseSensitive, ch, strArr[i])) {
+                        return false; // Character mismatch
+                    }
+                }
+            }
+            return true; // String matches against pattern
+        }
+
+        if (patIdxEnd == 0) {
+            return true; // Pattern contains only '*', which matches anything
+        }
+
+        // Process characters before first star
+        while (true) {
+            ch = patArr[patIdxStart];
+            if (ch == '*' || strIdxStart > strIdxEnd) {
+                break;
+            }
+            if (ch != '?') {
+                if (different(caseSensitive, ch, strArr[strIdxStart])) {
+                    return false; // Character mismatch
+                }
+            }
+            patIdxStart++;
+            strIdxStart++;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // All characters in the string are used. Check if only '*'s are
+            // left in the pattern. If so, we succeeded. Otherwise failure.
+            return allStars(patArr, patIdxStart, patIdxEnd);
+        }
+
+        // Process characters after last star
+        while (true) {
+            ch = patArr[patIdxEnd];
+            if (ch == '*' || strIdxStart > strIdxEnd) {
+                break;
+            }
+            if (ch != '?') {
+                if (different(caseSensitive, ch, strArr[strIdxEnd])) {
+                    return false; // Character mismatch
+                }
+            }
+            patIdxEnd--;
+            strIdxEnd--;
+        }
+        if (strIdxStart > strIdxEnd) {
+            // All characters in the string are used. Check if only '*'s are
+            // left in the pattern. If so, we succeeded. Otherwise failure.
+            return allStars(patArr, patIdxStart, patIdxEnd);
+        }
+
+        // process pattern between stars. padIdxStart and patIdxEnd point
+        // always to a '*'.
+        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+            int patIdxTmp = -1;
+            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+                if (patArr[i] == '*') {
+                    patIdxTmp = i;
+                    break;
+                }
+            }
+            if (patIdxTmp == patIdxStart + 1) {
+                // Two stars next to each other, skip the first one.
+                patIdxStart++;
+                continue;
+            }
+            // Find the pattern between padIdxStart & padIdxTmp in str between
+            // strIdxStart & strIdxEnd
+            int patLength = (patIdxTmp - patIdxStart - 1);
+            int strLength = (strIdxEnd - strIdxStart + 1);
+            int foundIdx = -1;
+            strLoop:
+            for (int i = 0; i <= strLength - patLength; i++) {
+                for (int j = 0; j < patLength; j++) {
+                    ch = patArr[patIdxStart + j + 1];
+                    if (ch != '?') {
+                        if (different(caseSensitive, ch,
+                                      strArr[strIdxStart + i + j])) {
+                            continue strLoop;
+                        }
+                    }
+                }
+
+                foundIdx = strIdxStart + i;
+                break;
+            }
+
+            if (foundIdx == -1) {
+                return false;
+            }
+
+            patIdxStart = patIdxTmp;
+            strIdxStart = foundIdx + patLength;
+        }
+
+        // All characters in the string are used. Check if only '*'s are left
+        // in the pattern. If so, we succeeded. Otherwise failure.
+        return allStars(patArr, patIdxStart, patIdxEnd);
+    }
+
+    private static boolean allStars(char[] chars, int start, int end) {
+        for (int i = start; i <= end; ++i) {
+            if (chars[i] != '*') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean different(
+        boolean caseSensitive, char ch, char other) {
+        return caseSensitive
+            ? ch != other
+            : Character.toUpperCase(ch) != Character.toUpperCase(other);
+    }
+
+    /**
+     * Breaks a path up into a Vector of path elements, tokenizing on
+     * <code>File.separator</code>.
+     *
+     * @param path Path to tokenize. Must not be <code>null</code>.
+     *
+     * @return a Vector of path elements from the tokenized path
+     */
+    public static Vector tokenizePath (String path) {
+        return tokenizePath(path, File.separator);
+    }
+
+    /**
+     * Breaks a path up into a Vector of path elements, tokenizing on
+     *
+     * @param path Path to tokenize. Must not be <code>null</code>.
+     * @param separator the separator against which to tokenize.
+     *
+     * @return a Vector of path elements from the tokenized path
+     * @since Ant 1.6
+     */
+    public static Vector tokenizePath (String path, String separator) {
+        Vector ret = new Vector();
+        if (FileUtils.isAbsolutePath(path)) {
+            String[] s = FILE_UTILS.dissect(path);
+            ret.add(s[0]);
+            path = s[1];
+        }
+        StringTokenizer st = new StringTokenizer(path, separator);
+        while (st.hasMoreTokens()) {
+            ret.addElement(st.nextToken());
+        }
+        return ret;
+    }
+
+    /**
+     * Same as {@link #tokenizePath tokenizePath} but hopefully faster.
+     */
+    private static String[] tokenizePathAsArray(String path) {
+        String root = null;
+        if (FileUtils.isAbsolutePath(path)) {
+            String[] s = FILE_UTILS.dissect(path);
+            root = s[0];
+            path = s[1];
+        }
+        char sep = File.separatorChar;
+        int start = 0;
+        int len = path.length();
+        int count = 0;
+        for (int pos = 0; pos < len; pos++) {
+            if (path.charAt(pos) == sep) {
+                if (pos != start) {
+                    count++;
+                }
+                start = pos + 1;
+            }
+        }
+        if (len != start) {
+            count++;
+        }
+        String[] l = new String[count + ((root == null) ? 0 : 1)];
+
+        if (root != null) {
+            l[0] = root;
+            count = 1;
+        } else {
+            count = 0;
+        }
+        start = 0;
+        for (int pos = 0; pos < len; pos++) {
+            if (path.charAt(pos) == sep) {
+                if (pos != start) {
+                    String tok = path.substring(start, pos);
+                    l[count++] = tok;
+                }
+                start = pos + 1;
+            }
+        }
+        if (len != start) {
+            String tok = path.substring(start);
+            l[count/*++*/] = tok;
+        }
+        return l;
+    }
+
+    /**
+     * Returns dependency information on these two files. If src has been
+     * modified later than target, it returns true. If target doesn't exist,
+     * it likewise returns true. Otherwise, target is newer than src and
+     * is not out of date, thus the method returns false. It also returns
+     * false if the src file doesn't even exist, since how could the
+     * target then be out of date.
+     *
+     * @param src the original file
+     * @param target the file being compared against
+     * @param granularity the amount in seconds of slack we will give in
+     *        determining out of dateness
+     * @return whether the target is out of date
+     */
+    public static boolean isOutOfDate(File src, File target, int granularity) {
+        if (!src.exists()) {
+            return false;
+        }
+        if (!target.exists()) {
+            return true;
+        }
+        if ((src.lastModified() - granularity) > target.lastModified()) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns dependency information on these two resources. If src has been
+     * modified later than target, it returns true. If target doesn't exist,
+     * it likewise returns true. Otherwise, target is newer than src and
+     * is not out of date, thus the method returns false. It also returns
+     * false if the src file doesn't even exist, since how could the
+     * target then be out of date.
+     *
+     * @param src the original resource
+     * @param target the resource being compared against
+     * @param granularity the int amount in seconds of slack we will give in
+     *        determining out of dateness
+     * @return whether the target is out of date
+     */
+    public static boolean isOutOfDate(Resource src, Resource target,
+                                      int granularity) {
+        return isOutOfDate(src, target, (long) granularity);
+    }
+
+    /**
+     * Returns dependency information on these two resources. If src has been
+     * modified later than target, it returns true. If target doesn't exist,
+     * it likewise returns true. Otherwise, target is newer than src and
+     * is not out of date, thus the method returns false. It also returns
+     * false if the src file doesn't even exist, since how could the
+     * target then be out of date.
+     *
+     * @param src the original resource
+     * @param target the resource being compared against
+     * @param granularity the long amount in seconds of slack we will give in
+     *        determining out of dateness
+     * @return whether the target is out of date
+     */
+    public static boolean isOutOfDate(Resource src, Resource target,
+                                      long granularity) {
+        long sourceLastModified = src.getLastModified();
+        // Check if source exists - use sourceLastModified for file resources
+        // as it is quicker than checking exists() again, however string resources
+        // have a last modified time of 0
+        boolean sourceExists = (src instanceof FileResource)
+            ? sourceLastModified != 0L : src.isExists();
+
+        long targetLastModified = target.getLastModified();
+        if (targetLastModified == 0L) {
+            return true;
+        }
+        return (sourceLastModified - granularity) > targetLastModified;
+    }
+
+    /**
+     * "Flattens" a string by removing all whitespace (space, tab, linefeed,
+     * carriage return, and formfeed). This uses StringTokenizer and the
+     * default set of tokens as documented in the single arguement constructor.
+     *
+     * @param input a String to remove all whitespace.
+     * @return a String that has had all whitespace removed.
+     */
+    public static String removeWhitespace(String input) {
+        StringBuffer result = new StringBuffer();
+        if (input != null) {
+            StringTokenizer st = new StringTokenizer(input);
+            while (st.hasMoreTokens()) {
+                result.append(st.nextToken());
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Tests if a string contains stars or question marks
+     * @param input a String which one wants to test for containing wildcard
+     * @return true if the string contains at least a star or a question mark
+     */
+    public static boolean hasWildcards(String input) {
+        return (input.indexOf('*') != -1 || input.indexOf('?') != -1);
+    }
+
+    /**
+     * removes from a pattern all tokens to the right containing wildcards
+     * @param input the input string
+     * @return the leftmost part of the pattern without wildcards
+     */
+    public static String rtrimWildcardTokens(String input) {
+        String[] tokens = tokenizePathAsArray(input);
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < tokens.length; i++) {
+            if (hasWildcards(tokens[i])) {
+                break;
+            }
+            if (i > 0 && sb.charAt(sb.length() - 1) != File.separatorChar) {
+                sb.append(File.separator);
+            }
+            sb.append(tokens[i]);
+        }
+        return sb.toString();
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SignedSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SignedSelector.java
new file mode 100644
index 0000000..74f8bd5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SignedSelector.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+import java.io.File;
+import org.apache.tools.ant.types.DataType;
+import org.apache.tools.ant.taskdefs.condition.IsSigned;
+
+/**
+ * Selector that chooses files based on whether they are signed or not.
+ *
+ * @since 1.7
+ */
+public class SignedSelector extends DataType implements FileSelector {
+    private IsSigned isSigned = new IsSigned();
+
+    /**
+     * The signature name to check jarfile for.
+     *
+     * @param name signature to look for.
+     */
+    public void setName(String name) {
+        isSigned.setName(name);
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir not used by this selector
+     * @param filename not used by this selector
+     * @param file     path to file to be selected
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        if (file.isDirectory()) {
+            return false; // Quick return: directories cannot be signed
+        }
+        isSigned.setProject(getProject());
+        isSigned.setFile(file);
+        return isSigned.eval();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java
new file mode 100644
index 0000000..3248647
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java
@@ -0,0 +1,279 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.types.Comparison;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that filters files based on their size.
+ *
+ * @since 1.5
+ */
+public class SizeSelector extends BaseExtendSelector {
+
+    /** Constants for kilo, kibi etc */
+    private static final int  KILO = 1000;
+    private static final int  KIBI = 1024;
+    private static final int  KIBI_POS = 4;
+    private static final int  MEGA = 1000000;
+    private static final int  MEGA_POS = 9;
+    private static final int  MEBI = 1048576;
+    private static final int  MEBI_POS = 13;
+    private static final long GIGA = 1000000000L;
+    private static final int  GIGA_POS = 18;
+    private static final long GIBI = 1073741824L;
+    private static final int  GIBI_POS = 22;
+    private static final long TERA = 1000000000000L;
+    private static final int  TERA_POS = 27;
+    private static final long TEBI = 1099511627776L;
+    private static final int  TEBI_POS = 31;
+    private static final int  END_POS = 36;
+
+    /** Used for parameterized custom selector */
+    public static final String SIZE_KEY = "value";
+    /** Used for parameterized custom selector */
+    public static final String UNITS_KEY = "units";
+    /** Used for parameterized custom selector */
+    public static final String WHEN_KEY = "when";
+
+    private long size = -1;
+    private long multiplier = 1;
+    private long sizelimit = -1;
+    private Comparison when = Comparison.EQUAL;
+
+    /**
+     * Creates a new <code>SizeSelector</code> instance.
+     *
+     */
+    public SizeSelector() {
+    }
+
+    /**
+     * Returns a <code>String</code> object representing the specified
+     * SizeSelector. This is "{sizeselector value: " + <"compare",
+     * "less", "more", "equal"> + "}".
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{sizeselector value: ");
+        buf.append(sizelimit);
+        buf.append("compare: ").append(when.getValue());
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * A size selector needs to know what size to base its selecting on.
+     * This will be further modified by the multiplier to get an
+     * actual size limit.
+     *
+     * @param size the size to select against expressed in units.
+     */
+    public void setValue(long size) {
+        this.size = size;
+        if (multiplier != 0 && size > -1) {
+            sizelimit = size * multiplier;
+        }
+    }
+
+    /**
+     * Sets the units to use for the comparison. This is a little
+     * complicated because common usage has created standards that
+     * play havoc with capitalization rules. Thus, some people will
+     * use "K" for indicating 1000's, when the SI standard calls for
+     * "k". Others have tried to introduce "K" as a multiple of 1024,
+     * but that falls down when you reach "M", since "m" is already
+     * defined as 0.001.
+     * <p>
+     * To get around this complexity, a number of standards bodies
+     * have proposed the 2^10 standard, and at least one has adopted
+     * it. But we are still left with a populace that isn't clear on
+     * how capitalization should work.
+     * <p>
+     * We therefore ignore capitalization as much as possible.
+     * Completely mixed case is not possible, but all upper and lower
+     * forms are accepted for all long and short forms. Since we have
+     * no need to work with the 0.001 case, this practice works here.
+     * <p>
+     * This function translates all the long and short forms that a
+     * unit prefix can occur in and translates them into a single
+     * multiplier.
+     *
+     * @param units The units to compare the size to, using an
+     *        EnumeratedAttribute.
+     */
+    public void setUnits(ByteUnits units) {
+        int i = units.getIndex();
+        multiplier = 0;
+        if (i > -1 && i < KIBI_POS) {
+            multiplier = KILO;
+        } else if (i < MEGA_POS) {
+            multiplier = KIBI;
+        } else if (i < MEBI_POS) {
+            multiplier = MEGA;
+        } else if (i < GIGA_POS) {
+            multiplier = MEBI;
+        } else if (i < GIBI_POS) {
+            multiplier = GIGA;
+        } else if (i < TERA_POS) {
+            multiplier = GIBI;
+        } else if (i < TEBI_POS) {
+            multiplier = TERA;
+        } else if (i < END_POS) {
+            multiplier = TEBI;
+        }
+        if (multiplier > 0 && size > -1) {
+            sizelimit = size * multiplier;
+        }
+    }
+
+    /**
+     * This specifies when the file should be selected, whether it be
+     * when the file matches a particular size, when it is smaller,
+     * or whether it is larger.
+     *
+     * @param when The comparison to perform, an EnumeratedAttribute.
+     */
+    public void setWhen(SizeComparisons when) {
+        this.when = when;
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector.
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (SIZE_KEY.equalsIgnoreCase(paramname)) {
+                    try {
+                        setValue(Long.parseLong(parameters[i].getValue()));
+                    } catch (NumberFormatException nfe) {
+                        setError("Invalid size setting "
+                                + parameters[i].getValue());
+                    }
+                } else if (UNITS_KEY.equalsIgnoreCase(paramname)) {
+                    ByteUnits units = new ByteUnits();
+                    units.setValue(parameters[i].getValue());
+                    setUnits(units);
+                } else if (WHEN_KEY.equalsIgnoreCase(paramname)) {
+                    SizeComparisons scmp = new SizeComparisons();
+                    scmp.setValue(parameters[i].getValue());
+                    setWhen(scmp);
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p>Checks to make sure all settings are kosher. In this case, it
+     * means that the size attribute has been set (to a positive value),
+     * that the multiplier has a valid setting, and that the size limit
+     * is valid. Since the latter is a calculated value, this can only
+     * fail due to a programming error.
+     * </p>
+     * <p>If a problem is detected, the setError() method is called.
+     * </p>
+     */
+    public void verifySettings() {
+        if (size < 0) {
+            setError("The value attribute is required, and must be positive");
+        } else if (multiplier < 1) {
+            setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti");
+        } else if (sizelimit < 0) {
+            setError("Internal error: Code is not setting sizelimit correctly");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir A java.io.File object for the base directory.
+     * @param filename The name of the file to check.
+     * @param file A File object for this filename.
+     * @return whether the file should be selected or not.
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        // throw BuildException on error
+        validate();
+
+        // Directory size never selected for
+        if (file.isDirectory()) {
+            return true;
+        }
+        long diff = file.length() - sizelimit;
+        return when.evaluate(diff == 0 ? 0 : (int) (diff / Math.abs(diff)));
+    }
+
+
+    /**
+     * Enumerated attribute with the values for units.
+     * <p>
+     * This treats the standard SI units as representing powers of ten,
+     * as they should. If you want the powers of 2 that approximate
+     * the SI units, use the first two characters followed by a
+     * <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>,
+     * 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30)
+     * becomes <code>gibi</code>, and so on. The symbols are also
+     * accepted, and these are the first letter capitalized followed
+     * by an <code>i</code>. <code>Ki</code>, <code>Mi</code>,
+     * <code>Gi</code>, and so on. Capitalization variations on these
+     * are also accepted.
+     * <p>
+     * This binary prefix system is approved by the IEC and appears on
+     * its way for approval by other agencies, but it is not an SI
+     * standard. It disambiguates things for us, though.
+     */
+    public static class ByteUnits extends EnumeratedAttribute {
+        /**
+         * @return the values as an array of strings
+         */
+        public String[] getValues() {
+            return new String[]{"K", "k", "kilo", "KILO",
+                                "Ki", "KI", "ki", "kibi", "KIBI",
+                                "M", "m", "mega", "MEGA",
+                                "Mi", "MI", "mi", "mebi", "MEBI",
+                                "G", "g", "giga", "GIGA",
+                                "Gi", "GI", "gi", "gibi", "GIBI",
+                                "T", "t", "tera", "TERA",
+           /* You wish! */      "Ti", "TI", "ti", "tebi", "TEBI"
+            };
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values for size comparison.
+     */
+    public static class SizeComparisons extends Comparison {
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/TypeSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/TypeSelector.java
new file mode 100644
index 0000000..33ac443
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/TypeSelector.java
@@ -0,0 +1,135 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Selector that selects a certain kind of file: directory or regular.
+ *
+ * @since 1.6
+ */
+public class TypeSelector extends BaseExtendSelector {
+
+    private String type = null;
+
+    /** Key to used for parameterized custom selector */
+    public static final String TYPE_KEY = "type";
+
+    /**
+     * Creates a new <code>TypeSelector</code> instance.
+     *
+     */
+    public TypeSelector() {
+    }
+
+    /**
+     * @return a string describing this object
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{typeselector type: ");
+        buf.append(type);
+        buf.append("}");
+        return buf.toString();
+    }
+
+    /**
+     * Set the type of file to require.
+     * @param fileTypes the type of file - file or dir
+     */
+    public void setType(FileType fileTypes) {
+        this.type = fileTypes.getValue();
+    }
+
+    /**
+     * When using this as a custom selector, this method will be called.
+     * It translates each parameter into the appropriate setXXX() call.
+     *
+     * @param parameters the complete set of parameters for this selector
+     */
+    public void setParameters(Parameter[] parameters) {
+        super.setParameters(parameters);
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                String paramname = parameters[i].getName();
+                if (TYPE_KEY.equalsIgnoreCase(paramname)) {
+                    FileType t = new FileType();
+                    t.setValue(parameters[i].getValue());
+                    setType(t);
+                } else {
+                    setError("Invalid parameter " + paramname);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks to make sure all settings are kosher. In this case, it
+     * means that the pattern attribute has been set.
+     *
+     */
+    public void verifySettings() {
+        if (type == null) {
+            setError("The type attribute is required");
+        }
+    }
+
+    /**
+     * The heart of the matter. This is where the selector gets to decide
+     * on the inclusion of a file in a particular fileset.
+     *
+     * @param basedir the base directory the scan is being done from
+     * @param filename is the name of the file to check
+     * @param file is a java.io.File object the selector can use
+     * @return whether the file should be selected or not
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+
+        // throw BuildException on error
+        validate();
+
+        if (file.isDirectory()) {
+            return type.equals(FileType.DIR);
+        } else {
+            return type.equals(FileType.FILE);
+        }
+    }
+
+    /**
+     * Enumerated attribute with the values for types of file
+     */
+    public static class FileType extends EnumeratedAttribute {
+        /** the string value for file */
+        public static final String FILE = "file";
+        /** the string value for dir */
+        public static final String DIR = "dir";
+
+        /**
+         * @return the values as an array of strings
+         */
+        public String[] getValues() {
+            return new String[]{FILE, DIR};
+        }
+    }
+
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java
new file mode 100644
index 0000000..82e043b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Algorithm.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.io.File;
+
+
+/**
+ * The <i>Algorithm</i> defines how a value for a file is computed.
+ * It must be sure that multiple calls for the same file results in the
+ * same value.
+ * The implementing class should implement a useful toString() method.
+ *
+ * @version 2003-09-13
+ * @since  Ant 1.6
+ */
+public interface Algorithm {
+
+    /**
+     * Checks its prerequisites.
+     * @return <i>true</i> if all is ok, otherwise <i>false</i>.
+     */
+    boolean isValid();
+
+    /**
+     * Get the value for a file.
+     * @param file    File object for which the value should be evaluated.
+     * @return        The value for that file
+     */
+    String getValue(File file);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java
new file mode 100644
index 0000000..7aa61fa
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/Cache.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.util.Iterator;
+
+
+/**
+ * A Cache let the user store key-value-pairs in a permanent manner and access
+ * them.
+ * It is possible that a client uses get() before load() therefore the
+ * implementation must ensure that no error occurred because of the wrong
+ * <i>order</i>.
+ * The implementing class should implement a useful toString() method.
+ *
+ * @version 2003-09-13
+ * @since  Ant 1.6
+ */
+public interface Cache {
+
+    /**
+     * Checks its prerequisites.
+     * @return <i>true</i> if all is ok, otherwise <i>false</i>.
+     */
+    boolean isValid();
+
+    /** Deletes the cache. If file based the file has to be deleted also. */
+    void delete();
+
+    /** Loads the cache, must handle not existing cache. */
+    void load();
+
+    /** Saves modification of the cache. */
+    void save();
+
+    /**
+     * Returns a value for a given key from the cache.
+     * @param key the key
+     * @return the stored value
+     */
+    Object get(Object key);
+
+    /**
+     * Saves a key-value-pair in the cache.
+     * @param key the key
+     * @param value the value
+     */
+    void put(Object key, Object value);
+
+    /**
+     * Returns an iterator over the keys in the cache.
+     * @return An iterator over the keys.
+     */
+    Iterator iterator();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ChecksumAlgorithm.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ChecksumAlgorithm.java
new file mode 100644
index 0000000..10aee50
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ChecksumAlgorithm.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.util.zip.Checksum;
+import java.util.zip.CRC32;
+import java.util.zip.Adler32;
+import java.util.zip.CheckedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.security.NoSuchAlgorithmException;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Computes a 'checksum' for the content of file using
+ * java.util.zip.CRC32 and java.util.zip.Adler32.
+ * Use of this algorithm doesn't require any additional nested <param>s.
+ * Supported <param>s are:
+ * <table>
+ * <tr>
+ *   <th>name</th><th>values</th><th>description</th><th>required</th>
+ * </tr>
+ * <tr>
+ *   <td> algorithm.algorithm </td>
+ *   <td> ADLER | CRC ( default ) </td>
+ *   <td> name of the algorithm the checksum should use </td>
+ *   <td> no, defaults to CRC </td>
+ * </tr>
+ * </table>
+ *
+ * @version 2004-06-17
+ * @since  Ant 1.7
+ */
+public class ChecksumAlgorithm implements Algorithm {
+
+
+    // -----  member variables  -----
+
+
+    /**
+     * Checksum algorithm to be used.
+     */
+    private String algorithm = "CRC";
+
+    /**
+     * Checksum interface instance
+     */
+    private Checksum checksum = null;
+
+
+    // -----  Algorithm-Configuration  -----
+
+
+    /**
+     * Specifies the algorithm to be used to compute the checksum.
+     * Defaults to "CRC". Other popular algorithms like "ADLER" may be used as well.
+     * @param algorithm the digest algorithm to use
+     */
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+
+    /** Initialize the checksum interface. */
+    public void initChecksum() {
+        if (checksum != null) {
+            return;
+        }
+        if ("CRC".equalsIgnoreCase(algorithm)) {
+            checksum = new CRC32();
+        } else if ("ADLER".equalsIgnoreCase(algorithm)) {
+            checksum = new Adler32();
+        } else {
+            throw new BuildException(new NoSuchAlgorithmException());
+        }
+    }
+
+
+    // -----  Logic  -----
+
+
+    /**
+     * This algorithm supports only CRC and Adler.
+     * @return <i>true</i> if all is ok, otherwise <i>false</i>.
+     */
+    public boolean isValid() {
+        return "CRC".equalsIgnoreCase(algorithm) || "ADLER".equalsIgnoreCase(algorithm);
+    }
+
+
+    /**
+     * Computes a value for a file content with the specified checksum algorithm.
+     * @param file    File object for which the value should be evaluated.
+     * @return        The value for that file
+     */
+    public String getValue(File file) {
+        initChecksum();
+        String rval = null;
+
+        try {
+            if (file.canRead()) {
+                 checksum.reset();
+                 FileInputStream fis = new FileInputStream(file);
+                 CheckedInputStream check = new CheckedInputStream(fis, checksum);
+                 BufferedInputStream in = new BufferedInputStream(check);
+                 while (in.read() != -1) {
+                     // Read the file
+                 }
+                 rval = Long.toString(check.getChecksum().getValue());
+                 in.close();
+            }
+        } catch (Exception e) {
+            rval = null;
+        }
+        return rval;
+    }
+
+
+    /**
+     * Override Object.toString().
+     * @return some information about this algorithm.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("<ChecksumAlgorithm:");
+        buf.append("algorithm=").append(algorithm);
+        buf.append(">");
+        return buf.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java
new file mode 100644
index 0000000..1c97180
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/DigestAlgorithm.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Computes a 'hashvalue' for the content of file using
+ * java.security.MessageDigest.
+ * Use of this algorithm doesn't require any additional nested <param>s.
+ * Supported <param>s are:
+ * <table>
+ * <tr>
+ *   <th>name</th><th>values</th><th>description</th><th>required</th>
+ * </tr>
+ * <tr>
+ *   <td> algorithm.algorithm </td>
+ *   <td> MD5 | SHA (default provider) </td>
+ *   <td> name of the algorithm the provider should use </td>
+ *   <td> no, defaults to MD5 </td>
+ * </tr>
+ * <tr>
+ *   <td> algorithm.provider </td>
+ *   <td> </td>
+ *   <td> name of the provider to use </td>
+ *   <td> no, defaults to <i>null</i> </td>
+ * </tr>
+ * </table>
+ *
+ * @version 2004-07-08
+ * @since  Ant 1.6
+ */
+public class DigestAlgorithm implements Algorithm {
+
+    private static final int BYTE_MASK = 0xFF;
+    private static final int BUFFER_SIZE = 8192;
+
+    // -----  member variables  -----
+
+
+    /**
+     * MessageDigest algorithm to be used.
+     */
+    private String algorithm = "MD5";
+
+    /**
+     * MessageDigest Algorithm provider
+     */
+    private String provider = null;
+
+    /**
+     * Message Digest instance
+     */
+    private MessageDigest messageDigest = null;
+
+    /**
+     * Size of the read buffer to use.
+     */
+    private int readBufferSize = BUFFER_SIZE;
+
+
+    // -----  Algorithm-Configuration  -----
+
+
+    /**
+     * Specifies the algorithm to be used to compute the checksum.
+     * Defaults to "MD5". Other popular algorithms like "SHA" may be used as well.
+     * @param algorithm the digest algorithm to use
+     */
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+
+    /**
+     * Sets the MessageDigest algorithm provider to be used
+     * to calculate the checksum.
+     * @param provider provider to use
+     */
+    public void setProvider(String provider) {
+        this.provider = provider;
+    }
+
+
+    /** Initialize the security message digest. */
+    public void initMessageDigest() {
+        if (messageDigest != null) {
+            return;
+        }
+
+        if ((provider != null) && !"".equals(provider) && !"null".equals(provider)) {
+            try {
+                messageDigest = MessageDigest.getInstance(algorithm, provider);
+            } catch (NoSuchAlgorithmException noalgo) {
+                throw new BuildException(noalgo);
+            } catch (NoSuchProviderException noprovider) {
+                throw new BuildException(noprovider);
+            }
+        } else {
+            try {
+                messageDigest = MessageDigest.getInstance(algorithm);
+            } catch (NoSuchAlgorithmException noalgo) {
+                throw new BuildException(noalgo);
+            }
+        }
+    }
+
+
+    // -----  Logic  -----
+
+
+    /**
+     * This algorithm supports only MD5 and SHA.
+     * @return <i>true</i> if all is ok, otherwise <i>false</i>.
+     */
+    public boolean isValid() {
+        return "SHA".equalsIgnoreCase(algorithm) || "MD5".equalsIgnoreCase(algorithm);
+    }
+
+
+    /**
+     * Computes a value for a file content with the specified digest algorithm.
+     * @param file    File object for which the value should be evaluated.
+     * @return        The value for that file
+     */
+    // implementation adapted from ...taskdefs.Checksum, thanks to Magesh for hint
+    public String getValue(File file) {
+        initMessageDigest();
+        String checksum = null;
+        try {
+            if (!file.canRead()) {
+                return null;
+            }
+            FileInputStream fis = null;
+
+            byte[] buf = new byte[readBufferSize];
+            try {
+                messageDigest.reset();
+                fis = new FileInputStream(file);
+                DigestInputStream dis = new DigestInputStream(fis,
+                                                              messageDigest);
+                while (dis.read(buf, 0, readBufferSize) != -1) {
+                    // do nothing
+                }
+                dis.close();
+                fis.close();
+                fis = null;
+                byte[] fileDigest = messageDigest.digest();
+                StringBuffer checksumSb = new StringBuffer();
+                for (int i = 0; i < fileDigest.length; i++) {
+                    String hexStr
+                        = Integer.toHexString(BYTE_MASK & fileDigest[i]);
+                    if (hexStr.length() < 2) {
+                        checksumSb.append("0");
+                    }
+                    checksumSb.append(hexStr);
+                }
+                checksum = checksumSb.toString();
+            } catch (Exception e) {
+                return null;
+            }
+        } catch (Exception e) {
+            return null;
+        }
+        return checksum;
+    }
+
+
+    /**
+     * Override Object.toString().
+     * @return some information about this algorithm.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("<DigestAlgorithm:");
+        buf.append("algorithm=").append(algorithm);
+        buf.append(";provider=").append(provider);
+        buf.append(">");
+        return buf.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java
new file mode 100644
index 0000000..a0c22ae
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/EqualComparator.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.util.Comparator;
+
+
+/**
+ * Simple implementation of Comparator for use in CacheSelector.
+ * compare() returns '0' (should not be selected) if both parameter
+ * are equal otherwise '1' (should be selected).
+ *
+ * @version 2003-09-13
+ * @since  Ant 1.6
+ */
+public class EqualComparator implements Comparator {
+
+    /**
+     * Implements Comparator.compare().
+     * @param o1 the first object
+     * @param o2 the second object
+     * @return 0, if both are equal, otherwise 1
+     */
+    public int compare(Object o1, Object o2) {
+        if (o1 == null) {
+            if (o2 == null) {
+                return 1;
+            }
+            return 0;
+        }
+        return (o1.equals(o2)) ? 0 : 1;
+    }
+
+    /**
+     * Override Object.toString().
+     * @return information about this comparator
+     */
+    public String toString() {
+        return "EqualComparator";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java
new file mode 100644
index 0000000..10b7470
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/HashvalueAlgorithm.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.io.File;
+
+
+/**
+ * Computes a 'hashvalue' for the content of file using String.hashValue().
+ * Use of this algorithm doesn't require any additional nested <param>s and
+ * doesn't support any.
+ *
+ * @version 2003-09-13
+ * @since  Ant 1.6
+ */
+public class HashvalueAlgorithm implements Algorithm {
+
+    /**
+     * This algorithm doesn't need any configuration.
+     * Therefore it's always valid.
+     * @return always true
+     */
+    public boolean isValid() {
+        return true;
+    }
+
+    /**
+     * Computes a 'hashvalue' for a file content.
+     * It reads the content of a file, convert that to String and use the
+     * String.hashCode() method.
+     * @param file  The file for which the value should be computed
+     * @return the hashvalue or <i>null</i> if the file couldn't be read
+     */
+     // Because the content is only read the file will not be damaged. I tested
+     // with JPG, ZIP and PDF as binary files.
+    public String getValue(File file) {
+        try {
+            if (!file.canRead()) {
+                return null;
+            }
+            java.io.FileInputStream fis = new java.io.FileInputStream(file);
+            byte[] content = new byte[fis.available()];
+            fis.read(content);
+            fis.close();
+            String s = new String(content);
+            int hash = s.hashCode();
+            return Integer.toString(hash);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /**
+     * Override Object.toString().
+     * @return information about this comparator
+     */
+    public String toString() {
+        return "HashvalueAlgorithm";
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java
new file mode 100644
index 0000000..9fa8c68
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/ModifiedSelector.java
@@ -0,0 +1,974 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+// Java
+import java.util.Comparator;
+import java.util.Vector;
+import java.util.Iterator;
+import java.io.File;
+
+// Ant
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.IntrospectionHelper;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.types.EnumeratedAttribute;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.selectors.BaseExtendSelector;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ResourceUtils;
+
+
+/**
+ * <p>Selector class that uses <i>Algorithm</i>, <i>Cache</i> and <i>Comparator</i>
+ * for its work.
+ * The <i>Algorithm</i> is used for computing a hashvalue for a file.
+ * The <i>Comparator</i> decides whether to select or not.
+ * The <i>Cache</i> stores the other value for comparison by the <i>Comparator</i>
+ * in a persistent manner.</p>
+ *
+ * <p>The ModifiedSelector is implemented as a <b>CoreSelector</b> and uses default
+ * values for all its attributes therefore the simpliest example is <pre>
+ *   &lt;copy todir="dest"&gt;
+ *       &lt;filelist dir="src"&gt;
+ *           &lt;modified/&gt;
+ *       &lt;/filelist&gt;
+ *   &lt;/copy&gt;
+ * </pre></p>
+ *
+ * <p>The same example rewritten as CoreSelector with setting the all values
+ * (same as defaults are) would be <pre>
+ *   &lt;copy todir="dest"&gt;
+ *       &lt;filelist dir="src"&gt;
+ *           &lt;modified update="true"
+ *                     cache="propertyfile"
+ *                     algorithm="digest"
+ *                     comparator="equal"&gt;
+ *               &lt;param name="cache.cachefile"     value="cache.properties"/&gt;
+ *               &lt;param name="algorithm.algorithm" value="MD5"/&gt;
+ *           &lt;/modified&gt;
+ *       &lt;/filelist&gt;
+ *   &lt;/copy&gt;
+ * </pre></p>
+ *
+ * <p>And the same rewritten as CustomSelector would be<pre>
+ *   &lt;copy todir="dest"&gt;
+ *       &lt;filelist dir="src"&gt;
+ *           &lt;custom class="org.apache.tools.ant.type.selectors.ModifiedSelector"&gt;
+ *               &lt;param name="update"     value="true"/&gt;
+ *               &lt;param name="cache"      value="propertyfile"/&gt;
+ *               &lt;param name="algorithm"  value="digest"/&gt;
+ *               &lt;param name="comparator" value="equal"/&gt;
+ *               &lt;param name="cache.cachefile"     value="cache.properties"/&gt;
+ *               &lt;param name="algorithm.algorithm" value="MD5"/&gt;
+ *           &lt;/custom&gt;
+ *       &lt;/filelist&gt;
+ *   &lt;/copy&gt;
+ * </pre></p>
+ *
+ * <p>If you want to provide your own interface implementation you can do
+ * that via the *classname attributes. If the classes are not on Ant's core
+ * classpath, you will have to provide the path via nested &lt;classpath&gt;
+ * element, so that the selector can find the classes. <pre>
+ *   &lt;modified cacheclassname="com.mycompany.MyCache"&gt;
+ *       &lt;classpath&gt;
+ *           &lt;pathelement location="lib/mycompony-antutil.jar"/&gt;
+ *       &lt;/classpath&gt;
+ *   &lt;/modified&gt;
+ * </pre></p>
+ *
+ * <p>All these three examples copy the files from <i>src</i> to <i>dest</i>
+ * using the ModifiedSelector. The ModifiedSelector uses the <i>PropertyfileCache
+ * </i>, the <i>DigestAlgorithm</i> and the <i>EqualComparator</i> for its
+ * work. The PropertyfileCache stores key-value-pairs in a simple java
+ * properties file. The filename is <i>cache.properties</i>. The <i>update</i>
+ * flag lets the selector update the values in the cache (and on first call
+ * creates the cache). The <i>DigestAlgorithm</i> computes a hashvalue using the
+ * java.security.MessageDigest class with its MD5-Algorithm and its standard
+ * provider. The new computed hashvalue and the stored one are compared by
+ * the <i>EqualComparator</i> which returns 'true' (more correct a value not
+ * equals zero (1)) if the values are not the same using simple String
+ * comparison.</p>
+ *
+ * <p>A useful scenario for this selector is inside a build environment
+ * for homepage generation (e.g. with <a href="http://forrest.apache.org/">
+ * Apache Forrest</a>). <pre>
+ * &lt;target name="generate-and-upload-site"&gt;
+ *     &lt;echo&gt; generate the site using forrest &lt;/echo&gt;
+ *     &lt;antcall target="site"/&gt;
+ *
+ *     &lt;echo&gt; upload the changed files &lt;/echo&gt;
+ *     &lt;ftp server="${ftp.server}" userid="${ftp.user}" password="${ftp.pwd}"&gt;
+ *         &lt;fileset dir="htdocs/manual"&gt;
+ *             &lt;modified/&gt;
+ *         &lt;/fileset&gt;
+ *     &lt;/ftp&gt;
+ * &lt;/target&gt;
+ * </pre> Here all <b>changed</b> files are uploaded to the server. The
+ * ModifiedSelector saves therefore much upload time.</p>
+ *
+ *
+ * <p>This selector uses reflection for setting the values of its three interfaces
+ * (using org.apache.tools.ant.IntrospectionHelper) therefore no special
+ * 'configuration interfaces' has to be implemented by new caches, algorithms or
+ * comparators. All present <i>set</i>XX methods can be used. E.g. the DigestAlgorithm
+ * can use a specified provider for computing its value. For selecting this
+ * there is a <i>setProvider(String providername)</i> method. So you can use
+ * a nested <i>&lt;param name="algorithm.provider" value="MyProvider"/&gt;</i>.
+ *
+ *
+ * @since  Ant 1.6
+ */
+public class ModifiedSelector extends BaseExtendSelector
+                              implements BuildListener, ResourceSelector {
+
+    private static final String CACHE_PREFIX = "cache.";
+    private static final String ALGORITHM_PREFIX = "algorithm.";
+    private static final String COMPARATOR_PREFIX = "comparator.";
+
+
+    // -----  attributes  -----
+
+
+    /** Cache name for later instantiation. */
+    private CacheName cacheName = null;
+
+    /** User specified classname for Cache. */
+    private String cacheClass;
+
+    /** Algorithm name for later instantiation. */
+    private AlgorithmName algoName = null;
+
+    /** User specified classname for Algorithm. */
+    private String algorithmClass;
+
+    /** Comparator name for later instantiation. */
+    private ComparatorName compName = null;
+
+    /** User specified classname for Comparator. */
+    private String comparatorClass;
+
+    /** Should the cache be updated? */
+    private boolean update = true;
+
+    /** Are directories selected? */
+    private boolean selectDirectories = true;
+
+    /**
+     * Should Resources whithout an InputStream, and
+     * therefore without checking, be selected?
+     */
+    private boolean selectResourcesWithoutInputStream = true;
+
+    /** Delay the writing of the cache file */
+    private boolean delayUpdate = true;
+
+
+    // ----- internal member variables -----
+
+
+    /** How should the cached value and the new one compared? */
+    private Comparator comparator = null;
+
+    /** Algorithm for computing new values and updating the cache. */
+    private Algorithm algorithm = null;
+
+    /** The Cache containing the old values. */
+    private Cache cache = null;
+
+    /** Count of modified properties */
+    private int modified = 0;
+
+    /** Flag whether this object is configured. Configuration is only done once. */
+    private boolean isConfigured = false;
+
+    /**
+     * Parameter vector with parameters for later initialization.
+     * @see #configure
+     */
+    private Vector configParameter = new Vector();
+
+    /**
+     * Parameter vector with special parameters for later initialization.
+     * The names have the pattern '*.*', e.g. 'cache.cachefile'.
+     * These parameters are used <b>after</b> the parameters with the pattern '*'.
+     * @see #configure
+     */
+    private Vector specialParameter = new Vector();
+
+    /** The classloader of this class. */
+    private ClassLoader myClassLoader = null;
+
+    /** provided classpath for the classloader */
+    private Path classpath = null;
+
+
+    // -----  constructors  -----
+
+
+    /** Bean-Constructor. */
+    public ModifiedSelector() {
+    }
+
+
+    // ----- configuration  -----
+
+
+    /** Overrides BaseSelector.verifySettings(). */
+    public void verifySettings() {
+        configure();
+        if (cache == null) {
+            setError("Cache must be set.");
+        } else if (algorithm == null) {
+            setError("Algorithm must be set.");
+        } else if (!cache.isValid()) {
+            setError("Cache must be proper configured.");
+        } else if (!algorithm.isValid()) {
+            setError("Algorithm must be proper configured.");
+        }
+    }
+
+
+    /**
+     * Configures this Selector.
+     * Does this work only once per Selector object.
+     * <p>Because some problems while configuring from <custom>Selector
+     * the configuration is done in the following order:<ol>
+     * <li> collect the configuration data </li>
+     * <li> wait for the first isSelected() call </li>
+     * <li> set the default values </li>
+     * <li> set values for name pattern '*': update, cache, algorithm, comparator </li>
+     * <li> set values for name pattern '*.*: cache.cachefile, ... </li>
+     * </ol></p>
+     * <p>This configuration algorithm is needed because you don't know
+     * the order of arriving config-data. E.g. if you first set the
+     * <i>cache.cachefilename</i> and after that the <i>cache</i> itself,
+     * the default value for cachefilename is used, because setting the
+     * cache implies creating a new Cache instance - with its defaults.</p>
+     */
+    public void configure() {
+        //
+        // -----  The "Singleton"  -----
+        //
+        if (isConfigured) {
+            return;
+        }
+        isConfigured = true;
+
+        //
+        // -----  Set default values  -----
+        //
+        Project p = getProject();
+        String filename = "cache.properties";
+        File cachefile = null;
+        if (p != null) {
+            // normal use inside Ant
+            cachefile = new File(p.getBaseDir(), filename);
+
+            // set self as a BuildListener to delay cachefile saves
+            getProject().addBuildListener(this);
+        } else {
+            // no reference to project - e.g. during normal JUnit tests
+            cachefile = new File(filename);
+            setDelayUpdate(false);
+        }
+        Cache      defaultCache      = new PropertiesfileCache(cachefile);
+        Algorithm  defaultAlgorithm  = new DigestAlgorithm();
+        Comparator defaultComparator = new EqualComparator();
+        update = true;
+        selectDirectories = true;
+
+        //
+        // -----  Set the main attributes, pattern '*'  -----
+        //
+        for (Iterator itConfig = configParameter.iterator(); itConfig.hasNext();) {
+            Parameter par = (Parameter) itConfig.next();
+            if (par.getName().indexOf(".") > 0) {
+                // this is a *.* parameter for later use
+                specialParameter.add(par);
+            } else {
+                useParameter(par);
+            }
+        }
+        configParameter = new Vector();
+
+        // specify the algorithm classname
+        if (algoName != null) {
+            // use Algorithm defined via name
+            if ("hashvalue".equals(algoName.getValue())) {
+                algorithm = new HashvalueAlgorithm();
+            } else if ("digest".equals(algoName.getValue())) {
+                algorithm = new DigestAlgorithm();
+            } else if ("checksum".equals(algoName.getValue())) {
+                algorithm = new ChecksumAlgorithm();
+            }
+        } else {
+            if (algorithmClass != null) {
+                // use Algorithm specified by classname
+                algorithm = (Algorithm) loadClass(
+                    algorithmClass,
+                    "is not an Algorithm.",
+                    Algorithm.class);
+            } else {
+                // nothing specified - use default
+                algorithm = defaultAlgorithm;
+            }
+        }
+
+        // specify the cache classname
+        if (cacheName != null) {
+            // use Cache defined via name
+            if ("propertyfile".equals(cacheName.getValue())) {
+                cache = new PropertiesfileCache();
+            }
+        } else {
+            if (cacheClass != null) {
+                // use Cache specified by classname
+                cache = (Cache) loadClass(cacheClass, "is not a Cache.", Cache.class);
+            } else {
+                // nothing specified - use default
+                cache = defaultCache;
+            }
+        }
+
+        // specify the comparator classname
+        if (compName != null) {
+            // use Algorithm defined via name
+            if ("equal".equals(compName.getValue())) {
+                comparator = new EqualComparator();
+             } else if ("rule".equals(compName.getValue())) {
+                // TODO there is a problem with the constructor for the RBC.
+                // you have to provide the rules in the constructors - no setters
+                // available.
+                throw new BuildException("RuleBasedCollator not yet supported.");
+                // Have to think about lazy initialization here...  JHM
+                // comparator = new java.text.RuleBasedCollator();
+            }
+        } else {
+            if (comparatorClass != null) {
+                // use Algorithm specified by classname
+                comparator = (Comparator) loadClass(
+                    comparatorClass,
+                    "is not a Comparator.",
+                    Comparator.class);
+            } else {
+                // nothing specified - use default
+                comparator = defaultComparator;
+            }
+        }
+
+        //
+        // -----  Set the special attributes, pattern '*.*'  -----
+        //
+        for (Iterator itSpecial = specialParameter.iterator(); itSpecial.hasNext();) {
+            Parameter par = (Parameter) itSpecial.next();
+            useParameter(par);
+        }
+        specialParameter = new Vector();
+    }
+
+
+    /**
+     * Loads the specified class and initializes an object of that class.
+     * Throws a BuildException using the given message if an error occurs during
+     * loading/instantiation or if the object is not from the given type.
+     * @param classname the classname
+     * @param msg the message-part for the BuildException
+     * @param type the type to check against
+     * @return a castable object
+     */
+    protected Object loadClass(String classname, String msg, Class type) {
+        try {
+            // load the specified class
+            ClassLoader cl = getClassLoader();
+            Class clazz = null;
+            if (cl != null) {
+                clazz = cl.loadClass(classname);
+            } else {
+                clazz = Class.forName(classname);
+            }
+
+            Object rv = clazz.newInstance();
+
+            if (!type.isInstance(rv)) {
+                throw new BuildException("Specified class (" + classname + ") " + msg);
+            }
+            return rv;
+        } catch (ClassNotFoundException e) {
+            throw new BuildException("Specified class (" + classname + ") not found.");
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+
+    // -----  the selection work  -----
+
+
+    /**
+     * Implementation of ResourceSelector.isSelected().
+     *
+     * @param resource The resource to check
+     * @return whether the resource is selected
+     * @see ResourceSelector#isSelected(Resource)
+     */
+    public boolean isSelected(Resource resource) {
+        if (resource.isFilesystemOnly()) {
+            // We have a 'resourced' file, so reconvert it and use
+            // the 'old' implementation.
+            FileResource fileResource = (FileResource) resource;
+            File file = fileResource.getFile();
+            String filename = fileResource.getName();
+            File basedir = fileResource.getBaseDir();
+            return isSelected(basedir, filename, file);
+        } else {
+            try {
+                // How to handle non-file-Resources? I copy temporarily the
+                // resource to a file and use the file-implementation.
+                FileUtils fu = FileUtils.getFileUtils();
+                File tmpFile = fu.createTempFile("modified-", ".tmp", null, true, false);
+                Resource tmpResource = new FileResource(tmpFile);
+                ResourceUtils.copyResource(resource, tmpResource);
+                boolean isSelected = isSelected(tmpFile.getParentFile(),
+                                                tmpFile.getName(),
+                                                resource.toLongString());
+                tmpFile.delete();
+                return isSelected;
+            } catch (UnsupportedOperationException uoe) {
+                log("The resource '"
+                  + resource.getName()
+                  + "' does not provide an InputStream, so it is not checked. "
+                  + "Akkording to 'selres' attribute value it is "
+                  + ((selectResourcesWithoutInputStream) ? "" : " not")
+                  + "selected.", Project.MSG_INFO);
+                return selectResourcesWithoutInputStream;
+            } catch (Exception e) {
+                throw new BuildException(e);
+            }
+        }
+    }
+
+
+    /**
+     * Implementation of BaseExtendSelector.isSelected().
+     *
+     * @param basedir as described in BaseExtendSelector
+     * @param filename as described in BaseExtendSelector
+     * @param file as described in BaseExtendSelector
+     * @return as described in BaseExtendSelector
+     */
+    public boolean isSelected(File basedir, String filename, File file) {
+        return isSelected(basedir, filename, file.getAbsolutePath());
+    }
+
+
+    /**
+     * The business logic of this selector for use as ResourceSelector of
+     * FileSelector.
+     *
+     * @param basedir as described in BaseExtendSelector
+     * @param filename as described in BaseExtendSelector
+     * @param cacheKey the name for the key for storing the hashvalue
+     * @return
+     */
+    private boolean isSelected(File basedir, String filename, String cacheKey) {
+        validate();
+        File f = new File(basedir, filename);
+
+        // You can not compute a value for a directory
+        if (f.isDirectory()) {
+            return selectDirectories;
+        }
+
+        // Get the values and do the comparison
+        String cachedValue = String.valueOf(cache.get(f.getAbsolutePath()));
+        String newValue = algorithm.getValue(f);
+
+        boolean rv = (comparator.compare(cachedValue, newValue) != 0);
+
+        // Maybe update the cache
+        if (update && rv) {
+            cache.put(f.getAbsolutePath(), newValue);
+            setModified(getModified() + 1);
+            if (!getDelayUpdate()) {
+                saveCache();
+            }
+        }
+
+        return rv;
+    }
+
+
+   /**
+    * save the cache file
+    */
+    protected void saveCache() {
+        if (getModified() > 0) {
+            cache.save();
+            setModified(0);
+        }
+    }
+
+
+    // -----  attribute and nested element support  -----
+
+
+    /**
+     * Setter for algorithmClass.
+     * @param classname  new value
+     */
+    public void setAlgorithmClass(String classname) {
+        algorithmClass = classname;
+    }
+
+
+    /**
+     * Setter for comparatorClass.
+     * @param classname  new value
+     */
+    public void setComparatorClass(String classname) {
+        comparatorClass = classname;
+    }
+
+
+    /**
+     * Setter for cacheClass.
+     * @param classname  new value
+     */
+    public void setCacheClass(String classname) {
+        cacheClass = classname;
+    }
+
+
+    /**
+     * Support for <i>update</i> attribute.
+     * @param update new value
+     */
+    public void setUpdate(boolean update) {
+        this.update = update;
+    }
+
+
+    /**
+     * Support for <i>seldirs</i> attribute.
+     * @param seldirs new value
+     */
+    public void setSeldirs(boolean seldirs) {
+        selectDirectories = seldirs;
+    }
+
+
+    /**
+     * Support for <i>selres</i> attribute.
+     * @param newValue the new value
+     */
+    public void setSelres(boolean newValue) {
+        this.selectResourcesWithoutInputStream = newValue;
+    }
+
+
+    /**
+     * Getter for the modified count
+     * @return modified count
+     */
+    public int getModified() {
+        return modified;
+    }
+
+
+    /**
+     * Setter for the modified count
+     * @param modified count
+     */
+    public void setModified(int modified) {
+        this.modified = modified;
+    }
+
+
+    /**
+     * Getter for the delay update
+     * @return true if we should delay for performance
+     */
+    public boolean getDelayUpdate() {
+        return delayUpdate;
+    }
+
+
+    /**
+     * Setter for the delay update
+     * @param delayUpdate true if we should delay for performance
+     */
+    public void setDelayUpdate(boolean delayUpdate) {
+        this.delayUpdate = delayUpdate;
+    }
+
+
+    /**
+     * Add the classpath.
+     * @param path the classpath
+     */
+    public void addClasspath(Path path) {
+        if (classpath != null) {
+            throw new BuildException("<classpath> can be set only once.");
+        }
+        classpath = path;
+    }
+
+
+    /**
+     * Returns and initializes the classloader for this class.
+     * @return the classloader
+     */
+    public ClassLoader getClassLoader() {
+        if (myClassLoader == null) {
+            myClassLoader = (classpath == null)
+                // the usual classloader
+                ? getClass().getClassLoader()
+                // additional use the provided classpath
+                : getProject().createClassLoader(classpath);
+        }
+        return myClassLoader;
+    }
+
+
+    /**
+     * Set the used ClassLoader.
+     * If you invoke this selector by API (e.g. inside some testcases) the selector
+     * will use a different classloader for loading the interface implementations than
+     * the caller. Therefore you will get a ClassCastException if you get the
+     * implementations from the selector and cast them.
+     * @param loader the ClassLoader to use
+     */
+    public void setClassLoader(ClassLoader loader) {
+        myClassLoader = loader;
+    }
+
+
+    /**
+     * Support for nested &lt;param&gt; tags.
+     * @param key the key of the parameter
+     * @param value the value of the parameter
+     */
+    public void addParam(String key, Object value) {
+        Parameter par = new Parameter();
+        par.setName(key);
+        par.setValue(String.valueOf(value));
+        configParameter.add(par);
+    }
+
+
+    /**
+     * Support for nested &lt;param&gt; tags.
+     * @param parameter the parameter object
+     */
+    public void addParam(Parameter parameter) {
+        configParameter.add(parameter);
+    }
+
+
+    /**
+     * Defined in org.apache.tools.ant.types.Parameterizable.
+     * Overwrite implementation in superclass because only special
+     * parameters are valid.
+     * @see #addParam(String,Object).
+     * @param parameters the parameters to set.
+     */
+    public void setParameters(Parameter[] parameters) {
+        if (parameters != null) {
+            for (int i = 0; i < parameters.length; i++) {
+                configParameter.add(parameters[i]);
+            }
+        }
+    }
+
+
+    /**
+     * Support for nested <param name="" value=""/> tags.
+     * Parameter named <i>cache</i>, <i>algorithm</i>,
+     * <i>comparator</i> or <i>update</i> are mapped to
+     * the respective set-Method.
+     * Parameter which names starts with <i>cache.</i> or
+     * <i>algorithm.</i> or <i>comparator.</i> are tried
+     * to set on the appropriate object via its set-methods.
+     * Other parameters are invalid and an BuildException will
+     * be thrown.
+     *
+     * @param parameter  Key and value as parameter object
+     */
+    public void useParameter(Parameter parameter) {
+        String key = parameter.getName();
+        String value = parameter.getValue();
+        if ("cache".equals(key)) {
+            CacheName cn = new CacheName();
+            cn.setValue(value);
+            setCache(cn);
+        } else if ("algorithm".equals(key)) {
+            AlgorithmName an = new AlgorithmName();
+            an.setValue(value);
+            setAlgorithm(an);
+        } else if ("comparator".equals(key)) {
+            ComparatorName cn = new ComparatorName();
+            cn.setValue(value);
+            setComparator(cn);
+        } else if ("update".equals(key)) {
+            boolean updateValue =
+                ("true".equalsIgnoreCase(value))
+                ? true
+                : false;
+            setUpdate(updateValue);
+        } else if ("delayupdate".equals(key)) {
+            boolean updateValue =
+                ("true".equalsIgnoreCase(value))
+                ? true
+                : false;
+            setDelayUpdate(updateValue);
+        } else if ("seldirs".equals(key)) {
+            boolean sdValue =
+                ("true".equalsIgnoreCase(value))
+                ? true
+                : false;
+            setSeldirs(sdValue);
+        } else if (key.startsWith(CACHE_PREFIX)) {
+            String name = key.substring(CACHE_PREFIX.length());
+            tryToSetAParameter(cache, name, value);
+        } else if (key.startsWith(ALGORITHM_PREFIX)) {
+            String name = key.substring(ALGORITHM_PREFIX.length());
+            tryToSetAParameter(algorithm, name, value);
+        } else if (key.startsWith(COMPARATOR_PREFIX)) {
+            String name = key.substring(COMPARATOR_PREFIX.length());
+            tryToSetAParameter(comparator, name, value);
+        } else {
+            setError("Invalid parameter " + key);
+        }
+    }
+
+
+    /**
+     * Try to set a value on an object using reflection.
+     * Helper method for easier access to IntrospectionHelper.setAttribute().
+     * @param obj the object on which the attribute should be set
+     * @param name the attributename
+     * @param value the new value
+     */
+    protected void tryToSetAParameter(Object obj, String name, String value) {
+        Project prj = (getProject() != null) ? getProject() : new Project();
+        IntrospectionHelper iHelper
+            = IntrospectionHelper.getHelper(prj, obj.getClass());
+        try {
+            iHelper.setAttribute(prj, obj, name, value);
+        } catch (org.apache.tools.ant.BuildException e) {
+            // no-op
+        }
+    }
+
+
+    // ----- 'beautiful' output -----
+
+
+    /**
+     * Override Object.toString().
+     * @return information about this selector
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer("{modifiedselector");
+        buf.append(" update=").append(update);
+        buf.append(" seldirs=").append(selectDirectories);
+        buf.append(" cache=").append(cache);
+        buf.append(" algorithm=").append(algorithm);
+        buf.append(" comparator=").append(comparator);
+        buf.append("}");
+        return buf.toString();
+    }
+
+
+    // ----- BuildListener interface methods -----
+
+
+    /**
+     * Signals that the last target has finished.
+     * @param event recieved BuildEvent
+    */
+    public void buildFinished(BuildEvent event) {
+        if (getDelayUpdate()) {
+            saveCache();
+        }
+    }
+
+
+    /**
+     * Signals that a target has finished.
+     * @param event recieved BuildEvent
+    */
+    public void targetFinished(BuildEvent event) {
+        if (getDelayUpdate()) {
+            saveCache();
+        }
+    }
+
+
+    /**
+     * Signals that a task has finished.
+     * @param event recieved BuildEvent
+    */
+    public void taskFinished(BuildEvent event) {
+        if (getDelayUpdate()) {
+            saveCache();
+        }
+    }
+
+
+    /**
+     * Signals that a build has started.
+     * @param event recieved BuildEvent
+    */
+    public void buildStarted(BuildEvent event) {
+        // no-op
+    }
+
+
+    /**
+     * Signals that a target is starting.
+     * @param event received BuildEvent
+    */
+    public void targetStarted(BuildEvent event) {
+        // no-op
+    }
+
+
+
+    /**
+     * Signals that a task is starting.
+     * @param event recieved BuildEvent
+    */
+    public void taskStarted(BuildEvent event) {
+        // no-op
+    }
+
+
+    /**
+     * Signals a message logging event.
+     * @param event recieved BuildEvent
+    */
+    public void messageLogged(BuildEvent event) {
+        // no-op
+    }
+
+
+    // The EnumeratedAttributes for the three interface implementations.
+    // Name-Classname mapping is done in the configure() method.
+
+
+    /**
+     * Get the cache type to use.
+     * @return the enumerated cache type
+     */
+    public Cache getCache() {
+        return cache;
+    }
+
+    /**
+     * Set the cache type to use.
+     * @param name an enumerated cache type.
+     */
+    public void setCache(CacheName name) {
+        cacheName = name;
+    }
+
+    /**
+     * The enumerated type for cache.
+     * The values are "propertyfile".
+     */
+    public static class CacheName extends EnumeratedAttribute {
+        /**
+         * {@inheritDoc}
+         * @see EnumeratedAttribute#getValues()
+         */
+        public String[] getValues() {
+            return new String[] {"propertyfile" };
+        }
+    }
+
+    /**
+     * Get the algorithm type to use.
+     * @return the enumerated algorithm type
+     */
+    public Algorithm getAlgorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Set the algorithm type to use.
+     * @param name an enumerated algorithm type.
+     */
+    public void setAlgorithm(AlgorithmName name) {
+        algoName = name;
+    }
+
+    /**
+     * The enumerated type for algorithm.
+     * The values are "hashValue", "digest" and "checksum".
+     */
+    public static class AlgorithmName extends EnumeratedAttribute {
+        /**
+         * {@inheritDoc}
+         * @see EnumeratedAttribute#getValues()
+         */
+        public String[] getValues() {
+            return new String[] {"hashvalue", "digest", "checksum" };
+        }
+    }
+
+    /**
+     * Get the comparator type to use.
+     * @return the enumerated comparator type
+     */
+    public Comparator getComparator() {
+        return comparator;
+    }
+
+    /**
+     * Set the comparator type to use.
+     * @param name an enumerated comparator type.
+     */
+    public void setComparator(ComparatorName name) {
+        compName = name;
+    }
+
+    /**
+     * The enumerated type for algorithm.
+     * The values are "equal" and "rule".
+     */
+    public static class ComparatorName extends EnumeratedAttribute {
+        /**
+         * {@inheritDoc}
+         * @see EnumeratedAttribute#getValues()
+         */
+        public String[] getValues() {
+            return new String[] {"equal", "rule" };
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java
new file mode 100644
index 0000000..cbfcd97
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/selectors/modifiedselector/PropertiesfileCache.java
@@ -0,0 +1,236 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors.modifiedselector;
+
+
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+
+
+/**
+ * Use java.util.Properties for storing the values.
+ * The use of this Cache-implementation requires the use of the parameter
+ * <param name="cache.cachefile" .../> for defining, where to store the
+ * properties file.
+ *
+ * The ModifiedSelector sets the <i>cachefile</i> to the default value
+ * <i>cache.properties</i>.
+ *
+ * Supported <param>s are:
+ * <table>
+ * <tr>
+ *   <th>name</th><th>values</th><th>description</th><th>required</th>
+ * </tr>
+ * <tr>
+ *   <td> cache.cachefile </td>
+ *   <td> <i>path to file</i> </td>
+ *   <td> the name of the properties file </td>
+ *   <td> yes </td>
+ * </tr>
+ * </table>
+ *
+ * @version 2003-09-13
+ * @since  Ant 1.6
+ */
+public class PropertiesfileCache implements Cache {
+
+
+    // -----  member variables - configuration  -----
+
+
+    /** Where to store the properties? */
+    private File cachefile = null;
+
+    /** Object for storing the key-value-pairs. */
+    private Properties cache = new Properties();
+
+
+    // -----  member variables - internal use  -----
+
+
+    /** Is the cache already loaded? Prevents from multiple load operations. */
+    private boolean cacheLoaded = false;
+
+    /** Must the cache be saved? Prevents from multiple save operations. */
+    private boolean cacheDirty  = true;
+
+
+    // -----  Constructors  -----
+
+
+    /** Bean-Constructor. */
+    public PropertiesfileCache() {
+    }
+
+    /**
+     * Constructor.
+     * @param cachefile set the cachefile
+     */
+    public PropertiesfileCache(File cachefile) {
+        this.cachefile = cachefile;
+    }
+
+
+    // -----  Cache-Configuration  -----
+
+
+    /**
+     * Setter.
+     * @param file new value
+     */
+    public void setCachefile(File file) {
+        cachefile = file;
+    }
+
+
+    /**
+     * Getter.
+     * @return the cachefile
+     */
+    public File getCachefile() {
+        return cachefile;
+    }
+
+    /**
+     * This cache is valid if the cachefile is set.
+     * @return true if all is ok false otherwise
+     */
+    public boolean isValid() {
+        return (cachefile != null);
+    }
+
+
+    // -----  Data Access
+
+
+    /**
+     * Load the cache from underlying properties file.
+     */
+    public void load() {
+        if ((cachefile != null) && cachefile.isFile() && cachefile.canRead()) {
+            try {
+                BufferedInputStream bis = new BufferedInputStream(
+                    new FileInputStream(cachefile));
+                cache.load(bis);
+                bis.close();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        // after loading the cache is up to date with the file
+        cacheLoaded = true;
+        cacheDirty  = false;
+    }
+
+    /**
+     * Saves modification of the cache.
+     * Cache is only saved if there is one ore more entries.
+     * Because entries can not be deleted by this API, this Cache
+     * implementation checks the existence of entries before creating the file
+     * for performance optimisation.
+     */
+    public void save() {
+        if (!cacheDirty) {
+            return;
+        }
+        if ((cachefile != null) && cache.propertyNames().hasMoreElements()) {
+            try {
+                BufferedOutputStream bos = new BufferedOutputStream(
+                      new FileOutputStream(cachefile));
+                cache.store(bos, null);
+                bos.flush();
+                bos.close();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        cacheDirty = false;
+    }
+
+    /** Deletes the cache and its underlying file. */
+    public void delete() {
+        cache = new Properties();
+        cachefile.delete();
+        cacheLoaded = true;
+        cacheDirty = false;
+    }
+
+    /**
+     * Returns a value for a given key from the cache.
+     * @param key the key
+     * @return the stored value
+     */
+    public Object get(Object key) {
+        if (!cacheLoaded) {
+            load();
+        }
+        try {
+            return cache.getProperty(String.valueOf(key));
+        } catch (ClassCastException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Saves a key-value-pair in the cache.
+     * @param key the key
+     * @param value the value
+     */
+    public void put(Object key, Object value) {
+        cache.put(String.valueOf(key), String.valueOf(value));
+        cacheDirty = true;
+    }
+
+    /**
+     * Returns an iterator over the keys in the cache.
+     * @return An iterator over the keys.
+     */
+    public Iterator iterator() {
+        Vector v = new java.util.Vector();
+        Enumeration en = cache.propertyNames();
+        while (en.hasMoreElements()) {
+            v.add(en.nextElement());
+        }
+        return v.iterator();
+    }
+
+
+    // -----  additional  -----
+
+
+    /**
+     * Override Object.toString().
+     * @return information about this cache
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+        buf.append("<PropertiesfileCache:");
+        buf.append("cachefile=").append(cachefile);
+        buf.append(";noOfEntries=").append(cache.size());
+        buf.append(">");
+        return buf.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/spi/Provider.java b/trunk/src/main/org/apache/tools/ant/types/spi/Provider.java
new file mode 100644
index 0000000..2edfe78
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/spi/Provider.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.spi;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * ANT Jar-Task SPI extension
+ * This class corresponds to the nested element
+ * &lt;provider type="type"&gt; in the &lt;service type=""&gt;
+ * nested element of the jar task.
+ * @see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=31520">
+ * http://issues.apache.org/bugzilla/show_bug.cgi?id=31520</a>
+ */
+public class Provider extends ProjectComponent {
+    private String type;
+
+    /**
+     * @return the class name for
+     */
+    public String getClassName() {
+        return type;
+    }
+
+    /**
+     * Set the provider classname.
+     * @param type the value to set.
+     */
+    public void setClassName(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Check if the component has been configured correctly.
+     */
+    public void check() {
+        if (type == null) {
+            throw new BuildException(
+                "classname attribute must be set for provider element",
+                getLocation());
+        }
+        if (type.length() == 0) {
+            throw new BuildException(
+                "Invalid empty classname", getLocation());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/types/spi/Service.java b/trunk/src/main/org/apache/tools/ant/types/spi/Service.java
new file mode 100644
index 0000000..b983b5e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/types/spi/Service.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.spi;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * ANT Jar-Task SPI extension
+ *
+ * @see <a href="http://issues.apache.org/bugzilla/show_bug.cgi?id=31520">
+ * http://issues.apache.org/bugzilla/show_bug.cgi?id=31520</a>
+ */
+public class Service extends ProjectComponent {
+    private List providerList = new ArrayList();
+    private String type;
+
+    /**
+     * Set the provider classname.
+     * @param className the classname of a provider of this service.
+     */
+    public void setProvider(String className) {
+        Provider provider = new Provider();
+        provider.setClassName(className);
+        providerList.add(provider);
+    }
+
+    /**
+     * Add a nested provider element.
+     * @param provider a provider element.
+     */
+    public void addConfiguredProvider(Provider provider) {
+        provider.check();
+        providerList.add(provider);
+    }
+
+    /**
+     * @return the service type.
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Set the service type.
+     * @param type the service type, a classname of
+     *             an interface or a class (normally
+     *             abstract).
+     */
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Return the implementations of this
+     * services as an inputstream.
+     * @return an inputstream of the classname names
+     *         encoded as UTF-8.
+     * @throws IOException if there is an error.
+     */
+    public InputStream getAsStream() throws IOException {
+        ByteArrayOutputStream arrayOut;
+        Writer writer;
+        Iterator providerIterator;
+        Provider provider;
+
+        arrayOut = new ByteArrayOutputStream();
+        writer = new OutputStreamWriter(arrayOut, "UTF-8");
+        providerIterator = providerList.iterator();
+        while (providerIterator.hasNext()) {
+            provider = (Provider) providerIterator.next();
+            writer.write(provider.getClassName());
+            writer.write("\n");
+        }
+        writer.close();
+        return new ByteArrayInputStream(arrayOut.toByteArray());
+    }
+
+    /**
+     * Check if this object is configured correctly as a nested
+     * element.
+     */
+    public void check() {
+        if (type == null) {
+            throw new BuildException(
+                "type attribute must be set for service element",
+                getLocation());
+        }
+        if (type.length() == 0) {
+            throw new BuildException(
+                "Invalid empty type classname", getLocation());
+        }
+        if (providerList.size() == 0) {
+            throw new BuildException(
+                "provider attribute or nested provider element must be set!",
+                getLocation());
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/Base64Converter.java b/trunk/src/main/org/apache/tools/ant/util/Base64Converter.java
new file mode 100644
index 0000000..a5f7e5b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/Base64Converter.java
@@ -0,0 +1,124 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+/**
+ * BASE 64 encoding of a String or an array of bytes.
+ *
+ * Based on RFC 1421.
+ *
+ **/
+public class Base64Converter {
+
+    private static final int BYTE      = 8;
+    private static final int WORD      = 16;
+    private static final int BYTE_MASK = 0xFF;
+    private static final int POS_0_MASK = 0x0000003F;
+    private static final int POS_1_MASK = 0x00000FC0;
+    private static final int POS_1_SHIFT = 6;
+    private static final int POS_2_MASK = 0x0003F000;
+    private static final int POS_2_SHIFT = 12;
+    private static final int POS_3_MASK = 0x00FC0000;
+    private static final int POS_3_SHIFT = 18;
+
+
+    private static final char[] ALPHABET = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  //  0 to  7
+        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  //  8 to 15
+        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  // 16 to 23
+        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  // 24 to 31
+        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  // 32 to 39
+        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  // 40 to 47
+        'w', 'x', 'y', 'z', '0', '1', '2', '3',  // 48 to 55
+        '4', '5', '6', '7', '8', '9', '+', '/'}; // 56 to 63
+
+    // CheckStyle:ConstantNameCheck OFF - bc
+    /** Provided for BC purposes */
+    public static final char[] alphabet = ALPHABET;
+    // CheckStyle:ConstantNameCheck ON
+
+
+    /**
+     * Encode a string into base64 encoding.
+     * @param s the string to encode.
+     * @return the encoded string.
+     */
+    public String encode(String s) {
+        return encode(s.getBytes());
+    }
+
+    /**
+     * Encode a byte array into base64 encoding.
+     * @param octetString the byte array to encode.
+     * @return the encoded string.
+     */
+    public String encode(byte[] octetString) {
+        int bits24;
+        int bits6;
+
+        // CheckStyle:MagicNumber OFF
+        char[] out = new char[((octetString.length - 1) / 3 + 1) * 4];
+        // CheckStyle:MagicNumber ON
+        int outIndex = 0;
+        int i = 0;
+
+        // CheckStyle:MagicNumber OFF
+        while ((i + 3) <= octetString.length) {
+        // CheckStyle:MagicNumber ON
+            // store the octets
+            bits24 = (octetString[i++] & BYTE_MASK) << WORD;
+            bits24 |= (octetString[i++] & BYTE_MASK) << BYTE;
+            bits24 |= octetString[i++];
+
+            bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6  = (bits24 & POS_1_MASK) >> POS_1_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6 = (bits24 & POS_0_MASK);
+            out[outIndex++] = ALPHABET[bits6];
+        }
+        if (octetString.length - i == 2) {
+            // store the octets
+            bits24 = (octetString[i] & BYTE_MASK) << WORD;
+            bits24 |= (octetString[i + 1] & BYTE_MASK) << BYTE;
+            bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6 = (bits24 & POS_1_MASK) >> POS_1_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+
+            // padding
+            out[outIndex++] = '=';
+        } else if (octetString.length - i == 1) {
+            // store the octets
+            bits24 = (octetString[i] & BYTE_MASK) << WORD;
+            bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+            bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+            out[outIndex++] = ALPHABET[bits6];
+
+            // padding
+            out[outIndex++] = '=';
+            out[outIndex++] = '=';
+        }
+        return new String(out);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ChainedMapper.java b/trunk/src/main/org/apache/tools/ant/util/ChainedMapper.java
new file mode 100755
index 0000000..92054ec
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ChainedMapper.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+/**
+ * A <CODE>ContainerMapper</CODE> that chains the results of the first
+ * nested <CODE>FileNameMapper</CODE>s into sourcefiles for the second,
+ * the second to the third, and so on, returning the resulting mapped
+ * filenames from the last nested <CODE>FileNameMapper</CODE>.
+ */
+public class ChainedMapper extends ContainerMapper {
+
+    /** {@inheritDoc}. */
+    public String[] mapFileName(String sourceFileName) {
+        List inputs = new ArrayList();
+        List results = new ArrayList();
+        results.add(sourceFileName);
+        FileNameMapper mapper = null;
+
+        for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+            mapper = (FileNameMapper) (mIter.next());
+            if (mapper != null) {
+                inputs.clear();
+                inputs.addAll(results);
+                results.clear();
+
+                for (Iterator it = inputs.iterator(); it.hasNext();) {
+                    String[] mapped = mapper.mapFileName((String) (it.next()));
+                    if (mapped != null) {
+                        results.addAll(Arrays.asList(mapped));
+                    }
+                }
+            }
+        }
+        return (results.size() == 0) ? null
+            : (String[]) results.toArray(new String[results.size()]);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/ClasspathUtils.java b/trunk/src/main/org/apache/tools/ant/util/ClasspathUtils.java
new file mode 100644
index 0000000..38db0d5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ClasspathUtils.java
@@ -0,0 +1,463 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Offers some helper methods on the Path structure in ant.
+ *
+ * <p>The basic idea behind this utility class is to use it from inside the
+ * different Ant objects (and user defined objects) that need classLoading
+ * for their operation.
+ * Normally those would have a setClasspathRef() {for the @classpathref}
+ * and/or a createClasspath() {for the nested &lt;classpath&gt;}
+ * Typically one would have in your Ant Task or DataType</p>
+ *
+ * <pre><code>
+ * ClasspathUtils.Delegate cpDelegate;
+ *
+ * public void init() {
+ *     this.cpDelegate = ClasspathUtils.getDelegate(this);
+ *     super.init();
+ * }
+ *
+ * public void setClasspathRef(Reference r) {
+ *     this.cpDelegate.setClasspathRef(r);
+ * }
+ *
+ * public Path createClasspath() {
+ *     return this.cpDelegate.createClasspath();
+ * }
+ *
+ * public void setClassname(String fqcn) {
+ *     this.cpDelegate.setClassname(fqcn);
+ * }
+ * </code></pre>
+ *
+ * <p>At execution time, when you actually need the classloading
+ * you can just:</p>
+ *
+ * <pre><code>
+ *     Object o = this.cpDelegate.newInstance();
+ * </code></pre>
+ *
+ * @since Ant 1.6
+ */
+public class ClasspathUtils {
+
+    /**
+     * Name of the magic property that controls classloader reuse in Ant 1.4.
+     */
+    public static final String REUSE_LOADER_REF = MagicNames.REFID_CLASSPATH_REUSE_LOADER;
+
+    /**
+     * Convenience overloaded version of {@link
+     * #getClassLoaderForPath(Project, Reference, boolean)}.
+     *
+     * <p>Assumes the logical 'false' for the reverseLoader.</p>
+     *
+     * @param p the project
+     * @param ref the reference
+     * @return The class loader
+     */
+    public static ClassLoader getClassLoaderForPath(Project p, Reference ref) {
+        return getClassLoaderForPath(p, ref, false);
+    }
+
+    /**
+     * Convenience overloaded version of {@link #getClassLoaderForPath(Project, Path,
+     * String, boolean)}.
+     *
+     * <p>Delegates to the other one after extracting the referenced
+     * Path from the Project. This checks also that the passed
+     * Reference is pointing to a Path all right.</p>
+     * @param p current Ant project
+     * @param ref Reference to Path structure
+     * @param reverseLoader if set to true this new loader will take
+     * precedence over its parent (which is contra the regular
+     * classloader behaviour)
+     * @return The class loader
+     */
+    public static ClassLoader getClassLoaderForPath(
+        Project p, Reference ref, boolean reverseLoader) {
+        String pathId = ref.getRefId();
+        Object path = p.getReference(pathId);
+        if (!(path instanceof Path)) {
+            throw new BuildException("The specified classpathref " + pathId
+                    + " does not reference a Path.");
+        }
+        String loaderId = MagicNames.REFID_CLASSPATH_LOADER_PREFIX + pathId;
+        return getClassLoaderForPath(p, (Path) path, loaderId, reverseLoader);
+    }
+
+    /**
+     * Convenience overloaded version of {@link
+     * #getClassLoaderForPath(Project, Path, String, boolean)}.
+     *
+     * <p>Assumes the logical 'false' for the reverseLoader.</p>
+     *
+     * @param p current Ant project
+     * @param path the path
+     * @param loaderId the loader id string
+     * @return The class loader
+     */
+    public static ClassLoader getClassLoaderForPath(Project p, Path path, String loaderId) {
+        return getClassLoaderForPath(p, path, loaderId, false);
+    }
+
+    /**
+     * Convenience overloaded version of {@link
+     * #getClassLoaderForPath(Project, Path, String, boolean, boolean)}.
+     *
+     * <p>Sets value for 'reuseLoader' to true if the magic property
+     * has been set.</p>
+     *
+     * @param p the project
+     * @param path the path
+     * @param loaderId the loader id string
+     * @param reverseLoader if set to true this new loader will take
+     * precedence over its parent (which is contra the regular
+     * classloader behaviour)
+     * @return The class loader
+     */
+    public static ClassLoader getClassLoaderForPath(
+            Project p, Path path, String loaderId, boolean reverseLoader) {
+        return getClassLoaderForPath(p, path, loaderId, reverseLoader, isMagicPropertySet(p));
+    }
+
+    /**
+     * Gets a classloader that loads classes from the classpath
+     * defined in the path argument.
+     *
+     * <p>Based on the setting of the magic property
+     * 'ant.reuse.loader' this will try to reuse the previously
+     * created loader with that id, and of course store it there upon
+     * creation.</p>
+     * @param p             Ant Project where the handled components are living in.
+     * @param path          Path object to be used as classpath for this classloader
+     * @param loaderId      identification for this Loader,
+     * @param reverseLoader if set to true this new loader will take
+     *                      precedence over its parent (which is contra the regular
+     *                      classloader behaviour)
+     * @param reuseLoader   if true reuse the loader if it is found
+     * @return              ClassLoader that uses the Path as its classpath.
+     */
+    public static ClassLoader getClassLoaderForPath(
+            Project p, Path path, String loaderId, boolean reverseLoader, boolean reuseLoader) {
+        ClassLoader cl = null;
+
+        // magic property
+        if (loaderId != null && reuseLoader) {
+            Object reusedLoader = p.getReference(loaderId);
+            if (reusedLoader != null && !(reusedLoader instanceof ClassLoader)) {
+                throw new BuildException("The specified loader id " + loaderId
+                        + " does not reference a class loader");
+            }
+            cl = (ClassLoader) reusedLoader;
+        }
+        if (cl == null) {
+            cl = getUniqueClassLoaderForPath(p, path, reverseLoader);
+            if (loaderId != null && reuseLoader) {
+                p.addReference(loaderId, cl);
+            }
+        }
+        return cl;
+    }
+
+    /**
+     * Gets a fresh, different, previously unused classloader that uses the
+     * passed path as its classpath.
+     *
+     * <p>This method completely ignores the ant.reuse.loader magic
+     * property and should be used with caution.</p>
+     * @param p             Ant Project where the handled components are living in.
+     * @param path          the classpath for this loader
+     * @param reverseLoader if set to true this new loader will take
+     *                      precedence over its parent (which is contra the regular
+     *                      classloader behaviour)
+     * @return The fresh, different, previously unused class loader.
+     */
+    public static ClassLoader getUniqueClassLoaderForPath(Project p, Path path,
+            boolean reverseLoader) {
+        AntClassLoader acl = p.createClassLoader(path);
+        if (reverseLoader) {
+            acl.setParentFirst(false);
+            acl.addJavaLibraries();
+        }
+        return acl;
+    }
+
+    /**
+     * Creates a fresh object instance of the specified classname.
+     *
+     * <p> This uses the userDefinedLoader to load the specified class,
+     * and then makes an instance using the default no-argument constructor.
+     * </p>
+     *
+     * @param className the full qualified class name to load.
+     * @param userDefinedLoader the classloader to use.
+     * @return The fresh object instance
+     * @throws BuildException when loading or instantiation failed.
+     */
+    public static Object newInstance(String className, ClassLoader userDefinedLoader) {
+        return newInstance(className, userDefinedLoader, Object.class);
+    }
+
+    /**
+     * Creates a fresh object instance of the specified classname.
+     *
+     * <p> This uses the userDefinedLoader to load the specified class,
+     * and then makes an instance using the default no-argument constructor.
+     * </p>
+     *
+     * @param className the full qualified class name to load.
+     * @param userDefinedLoader the classloader to use.
+     * @param expectedType the Class that the result should be assignment
+     * compatible with. (No ClassCastException will be thrown in case
+     * the result of this method is casted to the expectedType)
+     * @return The fresh object instance
+     * @throws BuildException when loading or instantiation failed.
+     * @since Ant 1.7
+     */
+    public static Object newInstance(String className, ClassLoader userDefinedLoader,
+            Class expectedType) {
+        try {
+            Class clazz = Class.forName(className, true, userDefinedLoader);
+            Object o = clazz.newInstance();
+            if (!expectedType.isInstance(o)) {
+                throw new BuildException("Class of unexpected Type: " + className + " expected :"
+                        + expectedType);
+            }
+            return o;
+        } catch (ClassNotFoundException e) {
+            throw new BuildException("Class not found: " + className, e);
+        } catch (InstantiationException e) {
+            throw new BuildException("Could not instantiate " + className
+                    + ". Specified class should have a no " + "argument constructor.", e);
+        } catch (IllegalAccessException e) {
+            throw new BuildException("Could not instantiate " + className
+                    + ". Specified class should have a " + "public constructor.", e);
+        } catch (LinkageError e) {
+            throw new BuildException("Class " + className
+                    + " could not be loaded because of an invalid dependency.", e);
+        }
+    }
+
+    /**
+     * Obtains a delegate that helps out with classic classpath configuration.
+     *
+     * @param component your projectComponent that needs the assistence
+     * @return the helper, delegate.
+     * @see ClasspathUtils.Delegate
+     */
+    public static Delegate getDelegate(ProjectComponent component) {
+        return new Delegate(component);
+    }
+
+    /**
+     * Checks for the magic property that enables class loader reuse
+     * for <taskdef> and <typedef> in Ant 1.5 and earlier.
+     */
+    private static boolean isMagicPropertySet(Project p) {
+        return p.getProperty(REUSE_LOADER_REF) != null;
+    }
+
+    /**
+     * Delegate that helps out any specific ProjectComponent that needs
+     * dynamic classloading.
+     *
+     * <p>Ant ProjectComponents that need a to be able to dynamically load
+     * Classes and instantiate them often expose the following ant syntax
+     * sugar: </p>
+     *
+     * <ul><li> nested &lt;classpath&gt; </li>
+     * <li> attribute @classpathref </li>
+     * <li> attribute @classname </li></ul>
+     *
+     * <p> This class functions as a delegate handling the configuration
+     * issues for this recurring pattern.  Its usage pattern, as the name
+     * suggests, is delegation rather than inheritance. </p>
+     *
+     * @since Ant 1.6
+     */
+    public static class Delegate {
+        private final ProjectComponent component;
+        private Path classpath;
+        private String classpathId;
+        private String className;
+        private String loaderId;
+        private boolean reverseLoader = false;
+
+        /**
+         * Construct a Delegate
+         * @param component the ProjectComponent this delegate is for.
+         */
+        Delegate(ProjectComponent component) {
+            this.component = component;
+        }
+
+        /**
+         * This method is a Delegate method handling the @classpath attribute.
+         *
+         * <p>This attribute can set a path to add to the classpath.</p>
+         *
+         * @param classpath the path to use for the classpath.
+         */
+        public void setClasspath(Path classpath) {
+            if (this.classpath == null) {
+                this.classpath = classpath;
+            } else {
+                this.classpath.append(classpath);
+            }
+        }
+
+        /**
+         * Delegate method handling the &lt;classpath&gt; tag.
+         *
+         * <p>This nested path-like structure can set a path to add to the
+         * classpath.</p>
+         *
+         * @return the created path.
+         */
+        public Path createClasspath() {
+            if (this.classpath == null) {
+                this.classpath = new Path(component.getProject());
+            }
+            return this.classpath.createPath();
+        }
+
+        /**
+         * Delegate method handling the @classname attribute.
+         *
+         * <p>This attribute sets the full qualified class name of the class
+         * to load and instantiate.</p>
+         *
+         * @param fcqn the name of the class to load.
+         */
+        public void setClassname(String fcqn) {
+            this.className = fcqn;
+        }
+
+        /**
+         * Delegate method handling the @classpathref attribute.
+         *
+         * <p>This attribute can add a referenced path-like structure to the
+         * classpath.</p>
+         *
+         * @param r the reference to the classpath.
+         */
+        public void setClasspathref(Reference r) {
+            this.classpathId = r.getRefId();
+            createClasspath().setRefid(r);
+        }
+
+        /**
+         * Delegate method handling the @reverseLoader attribute.
+         *
+         * <p>This attribute can set a boolean indicating that the used
+         * classloader should NOT follow the classical parent-first scheme.
+         * </p>
+         *
+         * <p>By default this is supposed to be false.</p>
+         *
+         * <p>Caution: this behaviour is contradictory to the normal way
+         * classloaders work.  Do not let your ProjectComponent use it if
+         * you are not really sure.</p>
+         *
+         * @param reverseLoader if true reverse the order of looking up a class.
+         */
+        public void setReverseLoader(boolean reverseLoader) {
+            this.reverseLoader = reverseLoader;
+        }
+
+        /**
+         * Sets the loaderRef.
+         * @param r the reference to the loader.
+         */
+        public void setLoaderRef(Reference r) {
+            this.loaderId = r.getRefId();
+        }
+
+
+        /**
+         * Finds or creates the classloader for this object.
+         * @return The class loader.
+         */
+        public ClassLoader getClassLoader() {
+            return getClassLoaderForPath(getContextProject(), classpath, getClassLoadId(),
+                    reverseLoader, loaderId != null || isMagicPropertySet(getContextProject()));
+        }
+
+        /**
+         * The project of the ProjectComponent we are working for.
+         */
+        private Project getContextProject() {
+            return component.getProject();
+        }
+
+        /**
+         * Computes the loaderId based on the configuration of the component.
+         * @return a loader identifier.
+         */
+        public String getClassLoadId() {
+            if (loaderId == null && classpathId != null) {
+                return MagicNames.REFID_CLASSPATH_LOADER_PREFIX + classpathId;
+            } else {
+                return loaderId;
+            }
+        }
+
+        /**
+         * Helper method obtaining a fresh instance of the class specified
+         * in the @classname and using the specified classpath.
+         *
+         * @return the fresh instantiated object.
+         */
+        public Object newInstance() {
+            return ClasspathUtils.newInstance(this.className, getClassLoader());
+        }
+
+        /**
+         * The classpath.
+         * @return the classpath.
+         */
+        public Path getClasspath() {
+            return classpath;
+        }
+
+        /**
+         * Get the reverseLoader setting.
+         * @return true if looking up in reverse order.
+         */
+        public boolean isReverseLoader() {
+            return reverseLoader;
+        }
+
+        //TODO no methods yet for getClassname
+        //TODO no method for newInstance using a reverse-classloader
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/CollectionUtils.java b/trunk/src/main/org/apache/tools/ant/util/CollectionUtils.java
new file mode 100644
index 0000000..7a8cf1f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/CollectionUtils.java
@@ -0,0 +1,204 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Vector;
+import java.util.Iterator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * A set of helper methods related to collection manipulation.
+ *
+ * @since Ant 1.5
+ */
+public class CollectionUtils {
+
+    /**
+     * Please use Vector.equals() or List.equals().
+     * @param v1 the first vector.
+     * @param v2 the second vector.
+     * @return true if the vectors are equal.
+     * @since Ant 1.5
+     * @deprecated since 1.6.x.
+     */
+    public static boolean equals(Vector v1, Vector v2) {
+        if (v1 == v2) {
+            return true;
+        }
+
+        if (v1 == null || v2 == null) {
+            return false;
+        }
+
+        return v1.equals(v2);
+    }
+
+    /**
+     * Dictionary does not have an equals.
+     * Please use  Map.equals().
+     *
+     * <p>Follows the equals contract of Java 2's Map.</p>
+     * @param d1 the first directory.
+     * @param d2 the second directory.
+     * @return true if the directories are equal.
+     * @since Ant 1.5
+     * @deprecated since 1.6.x.
+     */
+    public static boolean equals(Dictionary d1, Dictionary d2) {
+        if (d1 == d2) {
+            return true;
+        }
+
+        if (d1 == null || d2 == null) {
+            return false;
+        }
+
+        if (d1.size() != d2.size()) {
+            return false;
+        }
+
+        Enumeration e1 = d1.keys();
+        while (e1.hasMoreElements()) {
+            Object key = e1.nextElement();
+            Object value1 = d1.get(key);
+            Object value2 = d2.get(key);
+            if (value2 == null || !value1.equals(value2)) {
+                return false;
+            }
+        }
+
+        // don't need the opposite check as the Dictionaries have the
+        // same size, so we've also covered all keys of d2 already.
+
+        return true;
+    }
+
+    /**
+     * Dictionary does not know the putAll method. Please use Map.putAll().
+     * @param m1 the to directory.
+     * @param m2 the from directory.
+     * @since Ant 1.6
+     * @deprecated since 1.6.x.
+     */
+    public static void putAll(Dictionary m1, Dictionary m2) {
+        for (Enumeration it = m2.keys(); it.hasMoreElements();) {
+            Object key = it.nextElement();
+            m1.put(key, m2.get(key));
+        }
+    }
+
+    /**
+     * An empty enumeration.
+     * @since Ant 1.6
+     */
+    public static final class EmptyEnumeration implements Enumeration {
+        /** Constructor for the EmptyEnumeration */
+        public EmptyEnumeration() {
+        }
+
+        /**
+         * @return false always.
+         */
+        public boolean hasMoreElements() {
+            return false;
+        }
+
+        /**
+         * @return nothing.
+         * @throws NoSuchElementException always.
+         */
+        public Object nextElement() throws NoSuchElementException {
+            throw new NoSuchElementException();
+        }
+    }
+
+    /**
+     * Append one enumeration to another.
+     * Elements are evaluated lazily.
+     * @param e1 the first enumeration.
+     * @param e2 the subsequent enumeration.
+     * @return an enumeration representing e1 followed by e2.
+     * @since Ant 1.6.3
+     */
+    public static Enumeration append(Enumeration e1, Enumeration e2) {
+        return new CompoundEnumeration(e1, e2);
+    }
+
+    /**
+     * Adapt the specified Iterator to the Enumeration interface.
+     * @param iter the Iterator to adapt.
+     * @return an Enumeration.
+     */
+    public static Enumeration asEnumeration(final Iterator iter) {
+        return new Enumeration() {
+            public boolean hasMoreElements() {
+                return iter.hasNext();
+            }
+            public Object nextElement() {
+                return iter.next();
+            }
+        };
+    }
+
+    /**
+     * Adapt the specified Enumeration to the Iterator interface.
+     * @param e the Enumeration to adapt.
+     * @return an Iterator.
+     */
+    public static Iterator asIterator(final Enumeration e) {
+        return new Iterator() {
+            public boolean hasNext() {
+                return e.hasMoreElements();
+            }
+            public Object next() {
+                return e.nextElement();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static final class CompoundEnumeration implements Enumeration {
+
+        private final Enumeration e1, e2;
+
+        public CompoundEnumeration(Enumeration e1, Enumeration e2) {
+            this.e1 = e1;
+            this.e2 = e2;
+        }
+
+        public boolean hasMoreElements() {
+            return e1.hasMoreElements() || e2.hasMoreElements();
+        }
+
+        public Object nextElement() throws NoSuchElementException {
+            if (e1.hasMoreElements()) {
+                return e1.nextElement();
+            } else {
+                return e2.nextElement();
+            }
+        }
+
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/CompositeMapper.java b/trunk/src/main/org/apache/tools/ant/util/CompositeMapper.java
new file mode 100755
index 0000000..78f72e7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/CompositeMapper.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * A <CODE>ContainerMapper</CODE> that unites the results of its constituent
+ * <CODE>FileNameMapper</CODE>s into a single set of result filenames.
+ */
+public class CompositeMapper extends ContainerMapper {
+
+    /** {@inheritDoc}. */
+    public String[] mapFileName(String sourceFileName) {
+        HashSet results = new HashSet();
+
+        FileNameMapper mapper = null;
+        for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+            mapper = (FileNameMapper) (mIter.next());
+            if (mapper != null) {
+                String[] mapped = mapper.mapFileName(sourceFileName);
+                if (mapped != null) {
+                    results.addAll(Arrays.asList(mapped));
+                }
+            }
+        }
+        return (results.size() == 0) ? null
+            : (String[]) results.toArray(new String[results.size()]);
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java b/trunk/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
new file mode 100755
index 0000000..7d50984
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.FileInputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+
+/**
+ * Special <code>InputStream</code> that will
+ * concatenate the contents of an array of files.
+ */
+public class ConcatFileInputStream extends InputStream {
+
+    private static final int EOF = -1;
+    private int currentIndex = -1;
+    private boolean eof = false;
+    private File[] file;
+    private InputStream currentStream;
+    private ProjectComponent managingPc;
+
+  /**
+   * Construct a new <code>ConcatFileInputStream</code>
+   * with the specified <code>File[]</code>.
+   * @param file   <code>File[]</code>.
+   * @throws IOException if I/O errors occur.
+   */
+    public ConcatFileInputStream(File[] file) throws IOException {
+        this.file = file;
+    }
+
+    /**
+     * Close the stream.
+     * @throws IOException if there is an error.
+     */
+    public void close() throws IOException {
+        closeCurrent();
+        eof = true;
+    }
+
+    /**
+     * Read a byte.
+     * @return the byte (0 - 255) or -1 if this is the end of the stream.
+     * @throws IOException if there is an error.
+     */
+    public int read() throws IOException {
+        int result = readCurrent();
+        if (result == EOF && !eof) {
+            openFile(++currentIndex);
+            result = readCurrent();
+        }
+        return result;
+    }
+
+    /**
+     * Set a managing <code>Task</code> for
+     * this <code>ConcatFileInputStream</code>.
+     * @param task   the managing <code>Task</code>.
+     */
+    public void setManagingTask(Task task) {
+        setManagingComponent(task);
+    }
+
+    /**
+     * Set a managing <code>Task</code> for
+     * this <code>ConcatFileInputStream</code>.
+     * @param pc the managing <code>Task</code>.
+     */
+    public void setManagingComponent(ProjectComponent pc) {
+        this.managingPc = pc;
+    }
+
+    /**
+     * Log a message with the specified logging level.
+     * @param message    the <code>String</code> message.
+     * @param loglevel   the <code>int</code> logging level.
+     */
+    public void log(String message, int loglevel) {
+        if (managingPc != null) {
+            managingPc.log(message, loglevel);
+        } else {
+            if (loglevel > Project.MSG_WARN) {
+                System.out.println(message);
+            } else {
+                System.err.println(message);
+            }
+        }
+    }
+
+    private int readCurrent() throws IOException {
+        return (eof || currentStream == null) ? EOF : currentStream.read();
+    }
+
+    private void openFile(int index) throws IOException {
+        closeCurrent();
+        if (file != null && index < file.length) {
+            log("Opening " + file[index], Project.MSG_VERBOSE);
+            try {
+                currentStream = new BufferedInputStream(
+                    new FileInputStream(file[index]));
+            } catch (IOException eyeOhEx) {
+                log("Failed to open " + file[index], Project.MSG_ERR);
+                throw eyeOhEx;
+            }
+        } else {
+            eof = true;
+        }
+    }
+
+    private void closeCurrent() {
+        FileUtils.close(currentStream);
+        currentStream = null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java b/trunk/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java
new file mode 100755
index 0000000..98b613c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java
@@ -0,0 +1,147 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Special <code>InputStream</code> that will
+ * concatenate the contents of Resources from a single ResourceCollection.
+ * @since Ant 1.7
+ */
+public class ConcatResourceInputStream extends InputStream {
+
+    private static final int EOF = -1;
+    private boolean eof = false;
+    private Iterator iter;
+    private InputStream currentStream;
+    private ProjectComponent managingPc;
+    private boolean ignoreErrors = false;
+
+  /**
+   * Construct a new ConcatResourceInputStream
+   * for the specified ResourceCollection.
+   * @param rc the ResourceCollection to combine.
+   */
+    public ConcatResourceInputStream(ResourceCollection rc) {
+        iter = rc.iterator();
+    }
+
+    /**
+     * Set whether this ConcatResourceInputStream ignores errors.
+     * @param b whether to ignore errors.
+     */
+    public void setIgnoreErrors(boolean b) {
+        ignoreErrors = b;
+    }
+
+    /**
+     * Find out whether this ConcatResourceInputStream ignores errors.
+     * @return boolean ignore-errors flag.
+     */
+    public boolean isIgnoreErrors() {
+        return ignoreErrors;
+    }
+
+    /**
+     * Close the stream.
+     * @throws IOException if there is an error.
+     */
+     public void close() throws IOException {
+        closeCurrent();
+        eof = true;
+    }
+
+    /**
+     * Read a byte.
+     * @return the byte (0 - 255) or -1 if this is the end of the stream.
+     * @throws IOException if there is an error.
+     */
+    public int read() throws IOException {
+        if (eof) {
+            return EOF;
+        }
+        int result = readCurrent();
+        if (result == EOF) {
+            nextResource();
+            result = readCurrent();
+        }
+        return result;
+    }
+
+    /**
+     * Set a managing <code>ProjectComponent</code> for
+     * this <code>ConcatResourceInputStream</code>.
+     * @param pc   the managing <code>ProjectComponent</code>.
+     */
+    public void setManagingComponent(ProjectComponent pc) {
+        this.managingPc = pc;
+    }
+
+    /**
+     * Log a message with the specified logging level.
+     * @param message    the <code>String</code> message.
+     * @param loglevel   the <code>int</code> logging level.
+     */
+    public void log(String message, int loglevel) {
+        if (managingPc != null) {
+            managingPc.log(message, loglevel);
+        } else {
+            (loglevel > Project.MSG_WARN ? System.out : System.err).println(message);
+        }
+    }
+
+    private int readCurrent() throws IOException {
+        return eof || currentStream == null ? EOF : currentStream.read();
+    }
+
+    private void nextResource() throws IOException {
+        closeCurrent();
+        while (iter.hasNext()) {
+            Resource r = (Resource) iter.next();
+            if (!r.isExists()) {
+                continue;
+            }
+            log("Concating " + r.toLongString(), Project.MSG_VERBOSE);
+            try {
+                currentStream = new BufferedInputStream(r.getInputStream());
+                return;
+            } catch (IOException eyeOhEx) {
+                if (!ignoreErrors) {
+                    log("Failed to get input stream for " + r, Project.MSG_ERR);
+                    throw eyeOhEx;
+                }
+            }
+        }
+        eof = true;
+    }
+
+    private void closeCurrent() {
+        FileUtils.close(currentStream);
+        currentStream = null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ContainerMapper.java b/trunk/src/main/org/apache/tools/ant/util/ContainerMapper.java
new file mode 100755
index 0000000..f47f427
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ContainerMapper.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collections;
+import org.apache.tools.ant.types.Mapper;
+
+/**
+ * A <code>FileNameMapper</code> that contains
+ * other <code>FileNameMapper</code>s.
+ * @see FileNameMapper
+ */
+public abstract class ContainerMapper implements FileNameMapper {
+
+    private List mappers = new ArrayList();
+
+    /**
+     * Add a <code>Mapper</code>.
+     * @param mapper the <code>Mapper</code> to add.
+     */
+    public void addConfiguredMapper(Mapper mapper) {
+        add(mapper.getImplementation());
+    }
+
+    /**
+     * An add configured version of the add method.
+     * This class used to contain an add method and an
+     * addConfiguredMapper method. Dur to ordering,
+     * the add method was always called first. This
+     * addConfigued method has been added to allow
+     * chaining to work correctly.
+     * @param fileNameMapper a <code>FileNameMapper</code>.
+     */
+    public void addConfigured(FileNameMapper fileNameMapper) {
+        add(fileNameMapper);
+    }
+
+    /**
+     * Add a <code>FileNameMapper</code>.
+     * @param fileNameMapper a <code>FileNameMapper</code>.
+     * @throws IllegalArgumentException if attempting to add this
+     *         <code>ContainerMapper</code> to itself, or if the specified
+     *         <code>FileNameMapper</code> is itself a <code>ContainerMapper</code>
+     *         that contains this <code>ContainerMapper</code>.
+     */
+    public synchronized void add(FileNameMapper fileNameMapper) {
+        if (this == fileNameMapper
+            || (fileNameMapper instanceof ContainerMapper
+            && ((ContainerMapper) fileNameMapper).contains(this))) {
+            throw new IllegalArgumentException(
+                "Circular mapper containment condition detected");
+        } else {
+            mappers.add(fileNameMapper);
+        }
+    }
+
+    /**
+     * Return <code>true</code> if this <code>ContainerMapper</code> or any of
+     * its sub-elements contains the specified <code>FileNameMapper</code>.
+     * @param fileNameMapper   the <code>FileNameMapper</code> to search for.
+     * @return <code>boolean</code>.
+     */
+    protected synchronized boolean contains(FileNameMapper fileNameMapper) {
+        boolean foundit = false;
+        for (Iterator iter = mappers.iterator(); iter.hasNext() && !foundit;) {
+            FileNameMapper next = (FileNameMapper) (iter.next());
+            foundit = (next == fileNameMapper
+                || (next instanceof ContainerMapper
+                && ((ContainerMapper) next).contains(fileNameMapper)));
+        }
+        return foundit;
+    }
+
+    /**
+     * Get the <code>List</code> of <code>FileNameMapper</code>s.
+     * @return <code>List</code>.
+     */
+    public synchronized List getMappers() {
+        return Collections.unmodifiableList(mappers);
+    }
+
+    /**
+     * Empty implementation.
+     * @param ignore ignored.
+     */
+    public void setFrom(String ignore) {
+        //Empty
+    }
+
+    /**
+     * Empty implementation.
+     * @param ignore ignored.
+     */
+    public void setTo(String ignore) {
+        //Empty
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/DOMElementWriter.java b/trunk/src/main/org/apache/tools/ant/util/DOMElementWriter.java
new file mode 100644
index 0000000..ad5fe37
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/DOMElementWriter.java
@@ -0,0 +1,585 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * Writes a DOM tree to a given Writer.
+ * warning: this utility currently does not declare XML Namespaces.
+ * <p>Utility class used by {@link org.apache.tools.ant.XmlLogger
+ * XmlLogger} and
+ * org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter
+ * XMLJUnitResultFormatter}.</p>
+ *
+ */
+public class DOMElementWriter {
+
+    private static final int HEX = 16;
+
+    /** prefix for generated prefixes */
+    private static final String NS = "ns";
+
+    /** xml declaration is on by default */
+    private boolean xmlDeclaration = true;
+
+    /**
+     * XML Namespaces are ignored by default.
+     */
+    private XmlNamespacePolicy namespacePolicy = XmlNamespacePolicy.IGNORE;
+
+    /**
+     * Map (URI to prefix) of known namespaces.
+     */
+    private HashMap nsPrefixMap = new HashMap();
+
+    /**
+     * Number of generated prefix to use next.
+     */
+    private int nextPrefix = 0;
+
+    /**
+     * Map (Element to URI) of namespaces defined on a given element.
+     */
+    private HashMap nsURIByElement = new HashMap();
+
+    /**
+     * Whether namespaces should be ignored for elements and attributes.
+     *
+     * @since Ant 1.7
+     */
+    public static class XmlNamespacePolicy {
+        private boolean qualifyElements;
+        private boolean qualifyAttributes;
+
+        /**
+         * Ignores namespaces for elements and attributes, the default.
+         */
+        public static final XmlNamespacePolicy IGNORE =
+            new XmlNamespacePolicy(false, false);
+
+        /**
+         * Ignores namespaces for attributes.
+         */
+        public static final XmlNamespacePolicy ONLY_QUALIFY_ELEMENTS =
+            new XmlNamespacePolicy(true, false);
+
+        /**
+         * Qualifies namespaces for elements and attributes.
+         */
+        public static final XmlNamespacePolicy QUALIFY_ALL =
+            new XmlNamespacePolicy(true, true);
+
+        /**
+         * @param qualifyElements whether to qualify elements
+         * @param qualifyAttributes whether to qualify elements
+         */
+        public XmlNamespacePolicy(boolean qualifyElements,
+                                  boolean qualifyAttributes) {
+            this.qualifyElements = qualifyElements;
+            this.qualifyAttributes = qualifyAttributes;
+        }
+    }
+
+    /**
+     * Create an element writer.
+     * The ?xml? declaration will be included, namespaces ignored.
+     */
+    public DOMElementWriter() {
+    }
+
+    /**
+     * Create an element writer
+     * XML namespaces will be ignored.
+     * @param xmlDeclaration flag to indicate whether the ?xml? declaration
+     * should be included.
+     * @since Ant1.7
+     */
+    public DOMElementWriter(boolean xmlDeclaration) {
+        this(xmlDeclaration, XmlNamespacePolicy.IGNORE);
+    }
+
+    /**
+     * Create an element writer
+     * XML namespaces will be ignored.
+     * @param xmlDeclaration flag to indicate whether the ?xml? declaration
+     * should be included.
+     * @param namespacePolicy the policy to use.
+     * @since Ant1.7
+     */
+    public DOMElementWriter(boolean xmlDeclaration,
+                            XmlNamespacePolicy namespacePolicy) {
+        this.xmlDeclaration = xmlDeclaration;
+        this.namespacePolicy = namespacePolicy;
+    }
+
+    private static String lSep = System.getProperty("line.separator");
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Don't try to be too smart but at least recognize the predefined
+     * entities.
+     */
+    protected String[] knownEntities = {"gt", "amp", "lt", "apos", "quot"};
+    // CheckStyle:VisibilityModifier ON
+
+
+    /**
+     * Writes a DOM tree to a stream in UTF8 encoding. Note that
+     * it prepends the &lt;?xml version='1.0' encoding='UTF-8'?&gt; if
+     * the xmlDeclaration field is true.
+     * The indent number is set to 0 and a 2-space indent.
+     * @param root the root element of the DOM tree.
+     * @param out the outputstream to write to.
+     * @throws IOException if an error happens while writing to the stream.
+     */
+    public void write(Element root, OutputStream out) throws IOException {
+        Writer wri = new OutputStreamWriter(out, "UTF8");
+        writeXMLDeclaration(wri);
+        write(root, wri, 0, "  ");
+        wri.flush();
+    }
+
+    /**
+     * Writes the XML declaration if xmlDeclaration is true.
+     * @param wri the writer to write to.
+     * @throws IOException if there is an error.
+     * @since Ant 1.7.0
+     */
+    public void writeXMLDeclaration(Writer wri) throws IOException {
+        if (xmlDeclaration) {
+            wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+        }
+    }
+
+    /**
+     * Writes a DOM tree to a stream.
+     *
+     * @param element the Root DOM element of the tree
+     * @param out where to send the output
+     * @param indent number of
+     * @param indentWith string that should be used to indent the
+     * corresponding tag.
+     * @throws IOException if an error happens while writing to the stream.
+     */
+    public void write(Element element, Writer out, int indent,
+                      String indentWith)
+        throws IOException {
+
+        // Write child elements and text
+        NodeList children = element.getChildNodes();
+        boolean hasChildren = (children.getLength() > 0);
+        boolean hasChildElements = false;
+        openElement(element, out, indent, indentWith, hasChildren);
+
+        if (hasChildren) {
+            for (int i = 0; i < children.getLength(); i++) {
+                Node child = children.item(i);
+
+                switch (child.getNodeType()) {
+
+                case Node.ELEMENT_NODE:
+                    hasChildElements = true;
+                    if (i == 0) {
+                        out.write(lSep);
+                    }
+                    write((Element) child, out, indent + 1, indentWith);
+                    break;
+
+                case Node.TEXT_NODE:
+                    out.write(encode(child.getNodeValue()));
+                    break;
+
+                case Node.COMMENT_NODE:
+                    out.write("<!--");
+                    out.write(encode(child.getNodeValue()));
+                    out.write("-->");
+                    break;
+
+                case Node.CDATA_SECTION_NODE:
+                    out.write("<![CDATA[");
+                    out.write(encodedata(((Text) child).getData()));
+                    out.write("]]>");
+                    break;
+
+                case Node.ENTITY_REFERENCE_NODE:
+                    out.write('&');
+                    out.write(child.getNodeName());
+                    out.write(';');
+                    break;
+
+                case Node.PROCESSING_INSTRUCTION_NODE:
+                    out.write("<?");
+                    out.write(child.getNodeName());
+                    String data = child.getNodeValue();
+                    if (data != null && data.length() > 0) {
+                        out.write(' ');
+                        out.write(data);
+                    }
+                    out.write("?>");
+                    break;
+                default:
+                    // Do nothing
+                }
+            }
+            closeElement(element, out, indent, indentWith, hasChildElements);
+        }
+    }
+
+    /**
+     * Writes the opening tag - including all attributes -
+     * corresponding to a DOM element.
+     *
+     * @param element the DOM element to write
+     * @param out where to send the output
+     * @param indent number of
+     * @param indentWith string that should be used to indent the
+     * corresponding tag.
+     * @throws IOException if an error happens while writing to the stream.
+     */
+    public void openElement(Element element, Writer out, int indent,
+                            String indentWith)
+        throws IOException {
+        openElement(element, out, indent, indentWith, true);
+    }
+
+    /**
+     * Writes the opening tag - including all attributes -
+     * corresponding to a DOM element.
+     *
+     * @param element the DOM element to write
+     * @param out where to send the output
+     * @param indent number of
+     * @param indentWith string that should be used to indent the
+     * corresponding tag.
+     * @param hasChildren whether this element has children.
+     * @throws IOException if an error happens while writing to the stream.
+     * @since Ant 1.7
+     */
+    public void openElement(Element element, Writer out, int indent,
+                            String indentWith, boolean hasChildren)
+        throws IOException {
+        // Write indent characters
+        for (int i = 0; i < indent; i++) {
+            out.write(indentWith);
+        }
+
+        // Write element
+        out.write("<");
+        if (namespacePolicy.qualifyElements) {
+            String uri = getNamespaceURI(element);
+            String prefix = (String) nsPrefixMap.get(uri);
+            if (prefix == null) {
+                if (nsPrefixMap.isEmpty()) {
+                    // steal default namespace
+                    prefix = "";
+                } else {
+                    prefix = NS + (nextPrefix++);
+                }
+                nsPrefixMap.put(uri, prefix);
+                addNSDefinition(element, uri);
+            }
+            if (!"".equals(prefix)) {
+                out.write(prefix);
+                out.write(":");
+            }
+        }
+        out.write(element.getTagName());
+
+        // Write attributes
+        NamedNodeMap attrs = element.getAttributes();
+        for (int i = 0; i < attrs.getLength(); i++) {
+            Attr attr = (Attr) attrs.item(i);
+            out.write(" ");
+            if (namespacePolicy.qualifyAttributes) {
+                String uri = getNamespaceURI(attr);
+                String prefix = (String) nsPrefixMap.get(uri);
+                if (prefix == null) {
+                    prefix = NS + (nextPrefix++);
+                    nsPrefixMap.put(uri, prefix);
+                    addNSDefinition(element, uri);
+                }
+                out.write(prefix);
+                out.write(":");
+            }
+            out.write(attr.getName());
+            out.write("=\"");
+            out.write(encode(attr.getValue()));
+            out.write("\"");
+        }
+
+        // write namespace declarations
+        ArrayList al = (ArrayList) nsURIByElement.get(element);
+        if (al != null) {
+            Iterator iter = al.iterator();
+            while (iter.hasNext()) {
+                String uri = (String) iter.next();
+                String prefix = (String) nsPrefixMap.get(uri);
+                out.write(" xmlns");
+                if (!"".equals(prefix)) {
+                    out.write(":");
+                    out.write(prefix);
+                }
+                out.write("=\"");
+                out.write(uri);
+                out.write("\"");
+            }
+        }
+
+        if (hasChildren) {
+            out.write(">");
+        } else {
+            removeNSDefinitions(element);
+            out.write(" />");
+            out.write(lSep);
+            out.flush();
+        }
+    }
+
+    /**
+     * Writes a DOM tree to a stream.
+     *
+     * @param element the Root DOM element of the tree
+     * @param out where to send the output
+     * @param indent number of
+     * @param indentWith string that should be used to indent the
+     * corresponding tag.
+     * @param hasChildren if true indent.
+     * @throws IOException if an error happens while writing to the stream.
+     */
+    public void closeElement(Element element, Writer out, int indent,
+                             String indentWith, boolean hasChildren)
+        throws IOException {
+        // If we had child elements, we need to indent before we close
+        // the element, otherwise we're on the same line and don't need
+        // to indent
+        if (hasChildren) {
+            for (int i = 0; i < indent; i++) {
+                out.write(indentWith);
+            }
+        }
+
+        // Write element close
+        out.write("</");
+        if (namespacePolicy.qualifyElements) {
+            String uri = getNamespaceURI(element);
+            String prefix = (String) nsPrefixMap.get(uri);
+            if (prefix != null && !"".equals(prefix)) {
+                out.write(prefix);
+                out.write(":");
+            }
+            removeNSDefinitions(element);
+        }
+        out.write(element.getTagName());
+        out.write(">");
+        out.write(lSep);
+        out.flush();
+    }
+
+    /**
+     * Escape &lt;, &gt; &amp; &apos;, &quot; as their entities and
+     * drop characters that are illegal in XML documents.
+     * @param value the string to encode.
+     * @return the encoded string.
+     */
+    public String encode(String value) {
+        StringBuffer sb = new StringBuffer();
+        int len = value.length();
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+            switch (c) {
+            case '<':
+                sb.append("&lt;");
+                break;
+            case '>':
+                sb.append("&gt;");
+                break;
+            case '\'':
+                sb.append("&apos;");
+                break;
+            case '\"':
+                sb.append("&quot;");
+                break;
+            case '&':
+                int nextSemi = value.indexOf(";", i);
+                if (nextSemi < 0
+                    || !isReference(value.substring(i, nextSemi + 1))) {
+                    sb.append("&amp;");
+                } else {
+                    sb.append('&');
+                }
+                break;
+            default:
+                if (isLegalCharacter(c)) {
+                    sb.append(c);
+                }
+                break;
+            }
+        }
+        return sb.substring(0);
+    }
+
+    /**
+     * Drop characters that are illegal in XML documents.
+     *
+     * <p>Also ensure that we are not including an <code>]]&gt;</code>
+     * marker by replacing that sequence with
+     * <code>&amp;#x5d;&amp;#x5d;&amp;gt;</code>.</p>
+     *
+     * <p>See XML 1.0 2.2 <a
+     * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">
+     * http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a> and
+     * 2.7 <a
+     * href="http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect">http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect</a>.</p>
+     * @param value the value to be encoded.
+     * @return the encoded value.
+
+     */
+    public String encodedata(final String value) {
+        StringBuffer sb = new StringBuffer();
+        int len = value.length();
+        for (int i = 0; i < len; ++i) {
+            char c = value.charAt(i);
+            if (isLegalCharacter(c)) {
+                sb.append(c);
+            }
+        }
+
+        String result = sb.substring(0);
+        int cdEnd = result.indexOf("]]>");
+        while (cdEnd != -1) {
+            sb.setLength(cdEnd);
+            // CheckStyle:MagicNumber OFF
+            sb.append("&#x5d;&#x5d;&gt;")
+                .append(result.substring(cdEnd + 3));
+            // CheckStyle:MagicNumber ON
+            result = sb.substring(0);
+            cdEnd = result.indexOf("]]>");
+        }
+
+        return result;
+    }
+
+    /**
+     * Is the given argument a character or entity reference?
+     * @param ent the value to be checked.
+     * @return true if it is an entity.
+     */
+    public boolean isReference(String ent) {
+        if (!(ent.charAt(0) == '&') || !ent.endsWith(";")) {
+            return false;
+        }
+
+        if (ent.charAt(1) == '#') {
+            if (ent.charAt(2) == 'x') {
+                try {
+                    // CheckStyle:MagicNumber OFF
+                    Integer.parseInt(ent.substring(3, ent.length() - 1), HEX);
+                    // CheckStyle:MagicNumber ON
+                    return true;
+                } catch (NumberFormatException nfe) {
+                    return false;
+                }
+            } else {
+                try {
+                    Integer.parseInt(ent.substring(2, ent.length() - 1));
+                    return true;
+                } catch (NumberFormatException nfe) {
+                    return false;
+                }
+            }
+        }
+
+        String name = ent.substring(1, ent.length() - 1);
+        for (int i = 0; i < knownEntities.length; i++) {
+            if (name.equals(knownEntities[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Is the given character allowed inside an XML document?
+     *
+     * <p>See XML 1.0 2.2 <a
+     * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">
+     * http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a>.</p>
+     * @param c the character to test.
+     * @return true if the character is allowed.
+     * @since 1.10, Ant 1.5
+     */
+    public boolean isLegalCharacter(char c) {
+        // CheckStyle:MagicNumber OFF
+        if (c == 0x9 || c == 0xA || c == 0xD) {
+            return true;
+        } else if (c < 0x20) {
+            return false;
+        } else if (c <= 0xD7FF) {
+            return true;
+        } else if (c < 0xE000) {
+            return false;
+        } else if (c <= 0xFFFD) {
+            return true;
+        }
+        // CheckStyle:MagicNumber ON
+        return false;
+    }
+
+    private void removeNSDefinitions(Element element) {
+        ArrayList al = (ArrayList) nsURIByElement.get(element);
+        if (al != null) {
+            Iterator iter = al.iterator();
+            while (iter.hasNext()) {
+                nsPrefixMap.remove(iter.next());
+            }
+            nsURIByElement.remove(element);
+        }
+    }
+
+    private void addNSDefinition(Element element, String uri) {
+        ArrayList al = (ArrayList) nsURIByElement.get(element);
+        if (al == null) {
+            al = new ArrayList();
+            nsURIByElement.put(element, al);
+        }
+        al.add(uri);
+    }
+
+    private static String getNamespaceURI(Node n) {
+        String uri = n.getNamespaceURI();
+        if (uri == null) {
+            // FIXME: Is "No Namespace is Empty Namespace" really OK?
+            uri = "";
+        }
+        return uri;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/DOMUtils.java b/trunk/src/main/org/apache/tools/ant/util/DOMUtils.java
new file mode 100644
index 0000000..4c3fabe
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/DOMUtils.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Some utility methods for common tasks when building DOM trees in memory.
+ *
+ * <p>In this documentation <code>&lt;a&gt;</code> means an {@link
+ * org.w3c.dom.Element Element} instance with name <code>a</code>.</p>
+ *
+ * @since Ant 1.6.3
+ */
+public class DOMUtils {
+
+    /**
+     * Get a new Document instance,
+     * @return the document.
+     * @since Ant 1.6.3
+     */
+    public static Document newDocument() {
+        return JAXPUtils.getDocumentBuilder().newDocument();
+    }
+
+    /**
+     * Creates a named Element and appends it to the given element,
+     * returns it.
+     *
+     * <p>This means
+     * <pre>createChildElement(&lt;a&gt;, "b")</pre>
+     * creates
+     * <pre>
+     * &lt;a&gt;
+     *   &lt;b/&gt;
+     * &lt;/a&gt;
+     * </pre>
+     * and returns <code>&lt;b&gt;</code>.</p>
+     *
+     * @param parent element that will receive the new element as child.
+     * @param name name of the new element.
+     * @return the new element.
+     *
+     * @since Ant 1.6.3
+     */
+    public static Element createChildElement(Element parent, String name) {
+        Document doc = parent.getOwnerDocument();
+        Element e = doc.createElement(name);
+        parent.appendChild(e);
+        return e;
+    }
+
+    /**
+     * Adds nested text.
+     *
+     * <p>This means
+     * <pre>appendText(&lt;a&gt;, "b")</pre>
+     * creates
+     * <pre>
+     * &lt;a&gt;b&lt;/a&gt;
+     * </pre>
+     * </p>
+     *
+     * @param parent element that will receive the new element as child.
+     * @param content text content.
+     *
+     * @since Ant 1.6.3
+     */
+    public static void appendText(Element parent, String content) {
+        Document doc = parent.getOwnerDocument();
+        Text t = doc.createTextNode(content);
+        parent.appendChild(t);
+    }
+
+    /**
+     * Adds a nested CDATA section.
+     *
+     * <p>This means
+     * <pre>appendCDATA(&lt;a&gt;, "b")</pre>
+     * creates
+     * <pre>
+     * &lt;a&gt;&lt;[!CDATA[b]]&gt;&lt;/a&gt;
+     * </pre>
+     * </p>
+     *
+     * @param parent element that will receive the new element as child.
+     * @param content text content.
+     *
+     * @since Ant 1.6.3
+     */
+    public static void appendCDATA(Element parent, String content) {
+        Document doc = parent.getOwnerDocument();
+        CDATASection c = doc.createCDATASection(content);
+        parent.appendChild(c);
+    }
+
+    /**
+     * Adds nested text in a new child element.
+     *
+     * <p>This means
+     * <pre>appendTextElement(&lt;a&gt;, "b", "c")</pre>
+     * creates
+     * <pre>
+     * &lt;a&gt;
+     *   &lt;b&gt;c&lt;/b&gt;
+     * &lt;/a&gt;
+     * </pre>
+     * </p>
+     *
+     * @param parent element that will receive the new element as child.
+     * @param name of the child element.
+     * @param content text content.
+     *
+     * @since Ant 1.6.3
+     */
+    public static void appendTextElement(Element parent, String name,
+                                         String content) {
+        Element e = createChildElement(parent, name);
+        appendText(e, content);
+    }
+
+    /**
+     * Adds a nested CDATA section in a new child element.
+     *
+     * <p>This means
+     * <pre>appendCDATAElement(&lt;a&gt;, "b", "c")</pre>
+     * creates
+     * <pre>
+     * &lt;a&gt;
+     *   &lt;b&gt;&lt;![CDATA[c]]>&lt;/b&gt;
+     * &lt;/a&gt;
+     * </pre>
+     * </pre>
+     * </p>
+     *
+     * @param parent element that will receive the new element as child.
+     * @param name of the child element.
+     * @param content text content.
+     *
+     * @since Ant 1.6.3
+     */
+    public static void appendCDATAElement(Element parent, String name,
+                                          String content) {
+        Element e = createChildElement(parent, name);
+        appendCDATA(e, content);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/DateUtils.java b/trunk/src/main/org/apache/tools/ant/util/DateUtils.java
new file mode 100644
index 0000000..30fd884
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/DateUtils.java
@@ -0,0 +1,277 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.text.ChoiceFormat;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Helper methods to deal with date/time formatting with a specific
+ * defined format (<a href="http://www.w3.org/TR/NOTE-datetime">ISO8601</a>)
+ * or a plurialization correct elapsed time in minutes and seconds.
+ *
+ * @since Ant 1.5
+ *
+ */
+public final class DateUtils {
+
+    private static final int ONE_SECOND = 1000;
+    private static final int ONE_MINUTE = 60;
+    private static final int ONE_HOUR = 60;
+    private static final int TEN = 10;
+    /**
+     * ISO8601-like pattern for date-time. It does not support timezone.
+     *  <tt>yyyy-MM-ddTHH:mm:ss</tt>
+     */
+    public static final String ISO8601_DATETIME_PATTERN
+            = "yyyy-MM-dd'T'HH:mm:ss";
+
+    /**
+     * ISO8601-like pattern for date. <tt>yyyy-MM-dd</tt>
+     */
+    public static final String ISO8601_DATE_PATTERN
+            = "yyyy-MM-dd";
+
+    /**
+     * ISO8601-like pattern for time.  <tt>HH:mm:ss</tt>
+     */
+    public static final String ISO8601_TIME_PATTERN
+            = "HH:mm:ss";
+
+    /**
+     * Format used for SMTP (and probably other) Date headers.
+     */
+    public static final DateFormat DATE_HEADER_FORMAT
+        = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
+
+
+// code from Magesh moved from DefaultLogger and slightly modified
+    private static final MessageFormat MINUTE_SECONDS
+            = new MessageFormat("{0}{1}");
+
+    private static final double[] LIMITS = {0, 1, 2};
+
+    private static final String[] MINUTES_PART = {"", "1 minute ", "{0,number} minutes "};
+
+    private static final String[] SECONDS_PART = {"0 seconds", "1 second", "{1,number} seconds"};
+
+    private static final ChoiceFormat MINUTES_FORMAT =
+            new ChoiceFormat(LIMITS, MINUTES_PART);
+
+    private static final ChoiceFormat SECONDS_FORMAT =
+            new ChoiceFormat(LIMITS, SECONDS_PART);
+
+    static {
+        MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
+        MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
+    }
+
+    /** private constructor */
+    private DateUtils() {
+    }
+
+
+    /**
+     * Format a date/time into a specific pattern.
+     * @param date the date to format expressed in milliseconds.
+     * @param pattern the pattern to use to format the date.
+     * @return the formatted date.
+     */
+    public static String format(long date, String pattern) {
+        return format(new Date(date), pattern);
+    }
+
+
+    /**
+     * Format a date/time into a specific pattern.
+     * @param date the date to format expressed in milliseconds.
+     * @param pattern the pattern to use to format the date.
+     * @return the formatted date.
+     */
+    public static String format(Date date, String pattern) {
+        DateFormat df = createDateFormat(pattern);
+        return df.format(date);
+    }
+
+
+    /**
+     * Format an elapsed time into a plurialization correct string.
+     * It is limited only to report elapsed time in minutes and
+     * seconds and has the following behavior.
+     * <ul>
+     * <li>minutes are not displayed when 0. (ie: "45 seconds")</li>
+     * <li>seconds are always displayed in plural form (ie "0 seconds" or
+     * "10 seconds") except for 1 (ie "1 second")</li>
+     * </ul>
+     * @param millis the elapsed time to report in milliseconds.
+     * @return the formatted text in minutes/seconds.
+     */
+    public static String formatElapsedTime(long millis) {
+        long seconds = millis / ONE_SECOND;
+        long minutes = seconds / ONE_MINUTE;
+        Object[] args = {new Long(minutes), new Long(seconds % ONE_MINUTE)};
+        return MINUTE_SECONDS.format(args);
+    }
+
+    /**
+     * return a lenient date format set to GMT time zone.
+     * @param pattern the pattern used for date/time formatting.
+     * @return the configured format for this pattern.
+     */
+    private static DateFormat createDateFormat(String pattern) {
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        TimeZone gmt = TimeZone.getTimeZone("GMT");
+        sdf.setTimeZone(gmt);
+        sdf.setLenient(true);
+        return sdf;
+    }
+
+    /**
+     * Calculate the phase of the moon for a given date.
+     *
+     * <p>Code heavily influenced by hacklib.c in <a
+     * href="http://www.nethack.org/">Nethack</a></p>
+     *
+     * <p>The Algorithm:
+     *
+     * <pre>
+     * moon period = 29.53058 days ~= 30, year = 365.2422 days
+     *
+     * days moon phase advances on first day of year compared to preceding year
+     *  = 365.2422 - 12*29.53058 ~= 11
+     *
+     * years in Metonic cycle (time until same phases fall on the same days of
+     *  the month) = 18.6 ~= 19
+     *
+     * moon phase on first day of year (epact) ~= (11*(year%19) + 18) % 30
+     *  (18 as initial condition for 1900)
+     *
+     * current phase in days = first day phase + days elapsed in year
+     *
+     * 6 moons ~= 177 days
+     * 177 ~= 8 reported phases * 22
+     * + 11/22 for rounding
+     * </pre>
+     *
+     * @param cal the calander.
+     *
+     * @return The phase of the moon as a number between 0 and 7 with
+     *         0 meaning new moon and 4 meaning full moon.
+     *
+     * @since 1.2, Ant 1.5
+     */
+    public static int getPhaseOfMoon(Calendar cal) {
+        // CheckStyle:MagicNumber OFF
+        int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
+        int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
+        int epact = (11 * yearInMetonicCycle + 18) % 30;
+        if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
+            epact++;
+        }
+        return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Returns the current Date in a format suitable for a SMTP date
+     * header.
+     * @return the current date.
+     * @since Ant 1.5.2
+     */
+    public static String getDateForHeader() {
+        Calendar cal = Calendar.getInstance();
+        TimeZone tz = cal.getTimeZone();
+        int offset = tz.getOffset(cal.get(Calendar.ERA),
+                                  cal.get(Calendar.YEAR),
+                                  cal.get(Calendar.MONTH),
+                                  cal.get(Calendar.DAY_OF_MONTH),
+                                  cal.get(Calendar.DAY_OF_WEEK),
+                                  cal.get(Calendar.MILLISECOND));
+        StringBuffer tzMarker = new StringBuffer(offset < 0 ? "-" : "+");
+        offset = Math.abs(offset);
+        int hours = offset / (ONE_HOUR * ONE_MINUTE * ONE_SECOND);
+        int minutes = offset / (ONE_MINUTE * ONE_SECOND) - ONE_HOUR * hours;
+        if (hours < TEN) {
+            tzMarker.append("0");
+        }
+        tzMarker.append(hours);
+        if (minutes < TEN) {
+            tzMarker.append("0");
+        }
+        tzMarker.append(minutes);
+        return DATE_HEADER_FORMAT.format(cal.getTime()) + tzMarker.toString();
+    }
+
+    /**
+     * Parse a string as a datetime using the ISO8601_DATETIME format which is
+     * <code>yyyy-MM-dd'T'HH:mm:ss</code>
+     *
+     * @param datestr string to be parsed
+     *
+     * @return a java.util.Date object as parsed by the format.
+     * @exception ParseException if the supplied string cannot be parsed by
+     * this pattern.
+     * @since Ant 1.6
+     */
+    public static Date parseIso8601DateTime(String datestr)
+        throws ParseException {
+        return new SimpleDateFormat(ISO8601_DATETIME_PATTERN).parse(datestr);
+    }
+
+    /**
+     * Parse a string as a date using the ISO8601_DATE format which is
+     * <code>yyyy-MM-dd</code>
+     *
+     * @param datestr string to be parsed
+     *
+     * @return a java.util.Date object as parsed by the format.
+     * @exception ParseException if the supplied string cannot be parsed by
+     * this pattern.
+     * @since Ant 1.6
+     */
+    public static Date parseIso8601Date(String datestr) throws ParseException {
+        return new SimpleDateFormat(ISO8601_DATE_PATTERN).parse(datestr);
+    }
+
+    /**
+     * Parse a string as a date using the either the ISO8601_DATETIME
+     * or ISO8601_DATE formats.
+     *
+     * @param datestr string to be parsed
+     *
+     * @return a java.util.Date object as parsed by the formats.
+     * @exception ParseException if the supplied string cannot be parsed by
+     * either of these patterns.
+     * @since Ant 1.6
+     */
+    public static Date parseIso8601DateTimeOrDate(String datestr)
+        throws ParseException {
+        try {
+            return parseIso8601DateTime(datestr);
+        } catch (ParseException px) {
+            return parseIso8601Date(datestr);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/DeweyDecimal.java b/trunk/src/main/org/apache/tools/ant/util/DeweyDecimal.java
new file mode 100644
index 0000000..72a3940
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/DeweyDecimal.java
@@ -0,0 +1,209 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.StringTokenizer;
+
+/**
+ * Utility class to contain version numbers in "Dewey Decimal"
+ * syntax.  Numbers in the "Dewey Decimal" syntax consist of positive
+ * decimal integers separated by periods ".".  For example, "2.0" or
+ * "1.2.3.4.5.6.7".  This allows an extensible number to be used to
+ * represent major, minor, micro, etc versions.  The version number
+ * must begin with a number.
+ *
+ */
+public class DeweyDecimal {
+
+    /** Array of components that make up DeweyDecimal */
+    private int[] components;
+
+    /**
+     * Construct a DeweyDecimal from an array of integer components.
+     *
+     * @param components an array of integer components.
+     */
+    public DeweyDecimal(final int[] components) {
+        this.components = new int[components.length];
+        System.arraycopy(components, 0, this.components, 0, components.length);
+    }
+
+    /**
+     * Construct a DeweyDecimal from string in DeweyDecimal format.
+     *
+     * @param string the string in dewey decimal format
+     * @exception NumberFormatException if string is malformed
+     */
+    public DeweyDecimal(final String string)
+        throws NumberFormatException {
+        final StringTokenizer tokenizer = new StringTokenizer(string, ".", true);
+        final int size = tokenizer.countTokens();
+
+        components = new int[ (size + 1) / 2 ];
+
+        for (int i = 0; i < components.length; i++) {
+            final String component = tokenizer.nextToken();
+            if (component.equals("")) {
+                throw new NumberFormatException("Empty component in string");
+            }
+
+            components[ i ] = Integer.parseInt(component);
+
+            //Strip '.' token
+            if (tokenizer.hasMoreTokens()) {
+                tokenizer.nextToken();
+
+                //If it ended in a dot, throw an exception
+                if (!tokenizer.hasMoreTokens()) {
+                    throw new NumberFormatException("DeweyDecimal ended in a '.'");
+                }
+            }
+        }
+    }
+
+    /**
+     * Return number of components in <code>DeweyDecimal</code>.
+     *
+     * @return the number of components in dewey decimal
+     */
+    public int getSize() {
+        return components.length;
+    }
+
+    /**
+     * Return the component at specified index.
+     *
+     * @param index the index of components
+     * @return the value of component at index
+     */
+    public int get(final int index) {
+        return components[ index ];
+    }
+
+    /**
+     * Return <code>true</code> if this <code>DeweyDecimal</code> is
+     * equal to the other <code>DeweyDecimal</code>.
+     *
+     * @param other the other DeweyDecimal
+     * @return true if equal to other DeweyDecimal, false otherwise
+     */
+    public boolean isEqual(final DeweyDecimal other) {
+        final int max = Math.max(other.components.length, components.length);
+
+        for (int i = 0; i < max; i++) {
+            final int component1 = (i < components.length) ? components[ i ] : 0;
+            final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+            if (component2 != component1) {
+                return false;
+            }
+        }
+
+        return true; // Exact match
+    }
+
+    /**
+     * Return <code>true</code> if this <code>DeweyDecimal</code> is
+     * less than the other <code>DeweyDecimal</code>.
+     *
+     * @param other the other DeweyDecimal
+     * @return true if less than other DeweyDecimal, false otherwise
+     */
+    public boolean isLessThan(final DeweyDecimal other) {
+        return !isGreaterThanOrEqual(other);
+    }
+
+    /**
+     * Return <code>true</code> if this <code>DeweyDecimal</code> is
+     * less than or equal to the other <code>DeweyDecimal</code>.
+     *
+     * @param other the other DeweyDecimal
+     * @return true if less than or equal to other DeweyDecimal, false otherwise
+     */
+    public boolean isLessThanOrEqual(final DeweyDecimal other) {
+        return !isGreaterThan(other);
+    }
+
+    /**
+     * Return <code>true</code> if this <code>DeweyDecimal</code> is
+     * greater than the other <code>DeweyDecimal</code>.
+     *
+     * @param other the other DeweyDecimal
+     * @return true if greater than other DeweyDecimal, false otherwise
+     */
+    public boolean isGreaterThan(final DeweyDecimal other) {
+        final int max = Math.max(other.components.length, components.length);
+
+        for (int i = 0; i < max; i++) {
+            final int component1 = (i < components.length) ? components[ i ] : 0;
+            final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+            if (component2 > component1) {
+                return false;
+            }
+            if (component2 < component1) {
+                return true;
+            }
+        }
+
+        return false; // Exact match
+    }
+
+    /**
+     * Return <code>true</code> if this <code>DeweyDecimal</code> is
+     * greater than or equal to the other <code>DeweyDecimal</code>.
+     *
+     * @param other the other DeweyDecimal
+     * @return true if greater than or equal to other DeweyDecimal, false otherwise
+     */
+    public boolean isGreaterThanOrEqual(final DeweyDecimal other) {
+        final int max = Math.max(other.components.length, components.length);
+
+        for (int i = 0; i < max; i++) {
+            final int component1 = (i < components.length) ? components[ i ] : 0;
+            final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+            if (component2 > component1) {
+                return false;
+            }
+            if (component2 < component1) {
+                return true;
+            }
+        }
+
+        return true; // Exact match
+    }
+
+    /**
+     * Return string representation of <code>DeweyDecimal</code>.
+     *
+     * @return the string representation of DeweyDecimal.
+     */
+    public String toString() {
+        final StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < components.length; i++) {
+            if (i != 0) {
+                sb.append('.');
+            }
+            sb.append(components[ i ]);
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/FileNameMapper.java b/trunk/src/main/org/apache/tools/ant/util/FileNameMapper.java
new file mode 100644
index 0000000..b0d32b3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/FileNameMapper.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Interface to be used by SourceFileScanner.
+ *
+ * <p>Used to find the name of the target file(s) corresponding to a
+ * source file.</p>
+ *
+ * <p>The rule by which the file names are transformed is specified
+ * via the setFrom and setTo methods. The exact meaning of these is
+ * implementation dependent.</p>
+ *
+ */
+public interface FileNameMapper {
+
+    /**
+     * Sets the from part of the transformation rule.
+     * @param from a string.
+     */
+    void setFrom(String from);
+
+    /**
+     * Sets the to part of the transformation rule.
+     * @param to a string.
+     */
+    void setTo(String to);
+
+    /**
+     * Returns an array containing the target filename(s) for the
+     * given source file.
+     *
+     * <p>if the given rule doesn't apply to the source file,
+     * implementation must return null. SourceFileScanner will then
+     * omit the source file in question.</p>
+     *
+     * @param sourceFileName the name of the source file relative to
+     *                       some given basedirectory.
+     * @return an array of strings if the ruld applies to the source file, or
+     *         null if it does not.
+     */
+    String[] mapFileName(String sourceFileName);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/FileTokenizer.java b/trunk/src/main/org/apache/tools/ant/util/FileTokenizer.java
new file mode 100644
index 0000000..01ee976
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/FileTokenizer.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Class to read the complete input into a string.
+ * @since Ant 1.7
+ */
+public class FileTokenizer extends ProjectComponent implements Tokenizer {
+
+    /**
+     * Get the complete input as a string
+     * @param in the reader object
+     * @return the complete input
+     * @throws IOException if error reading
+     */
+    public String getToken(Reader in) throws IOException {
+        return FileUtils.readFully(in);
+    }
+
+    /**
+     * Return the intra-token string
+     * @return an empty string always
+     */
+    public String getPostToken() {
+        return "";
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/FileUtils.java b/trunk/src/main/org/apache/tools/ant/util/FileUtils.java
new file mode 100644
index 0000000..a5f6969
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/FileUtils.java
@@ -0,0 +1,1579 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.PathTokenizer;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.launch.Locator;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * This class also encapsulates methods which allow Files to be
+ * referred to using abstract path names which are translated to native
+ * system file paths at runtime as well as copying files or setting
+ * their last modification time.
+ *
+ */
+public class FileUtils {
+    private static final int EXPAND_SPACE = 50;
+    private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
+
+    //get some non-crypto-grade randomness from various places.
+    private static Random rand = new Random(System.currentTimeMillis()
+            + Runtime.getRuntime().freeMemory());
+
+    private static final boolean ON_NETWARE = Os.isFamily("netware");
+    private static final boolean ON_DOS = Os.isFamily("dos");
+    private static final boolean ON_WIN9X = Os.isFamily("win9x");
+    private static final boolean ON_WINDOWS = Os.isFamily("windows");
+
+    static final int BUF_SIZE = 8192;
+
+
+    /**
+     * The granularity of timestamps under FAT.
+     */
+    public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
+
+    /**
+     * The granularity of timestamps under Unix.
+     */
+    public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
+
+    /**
+     * The granularity of timestamps under the NT File System.
+     * NTFS has a granularity of 100 nanoseconds, which is less
+     * than 1 millisecond, so we round this up to 1 millisecond.
+     */
+    public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1;
+
+    /**
+     * A one item cache for fromUri.
+     * fromUri is called for each element when parseing ant build
+     * files. It is a costly operation. This just caches the result
+     * of the last call.
+     */
+    private Object cacheFromUriLock = new Object();
+    private String cacheFromUriRequest = null;
+    private String cacheFromUriResponse = null;
+
+    /**
+     * Factory method.
+     *
+     * @return a new instance of FileUtils.
+     * @deprecated since 1.7.
+     *             Use getFileUtils instead,
+     * FileUtils do not have state.
+     */
+    public static FileUtils newFileUtils() {
+        return new FileUtils();
+    }
+
+    /**
+     * Method to retrieve The FileUtils, which is shared by all users of this
+     * method.
+     * @return an instance of FileUtils.
+     * @since Ant 1.6.3
+     */
+    public static FileUtils getFileUtils() {
+        return PRIMARY_INSTANCE;
+    }
+
+    /**
+     * Empty constructor.
+     */
+    protected FileUtils() {
+    }
+
+    /**
+     * Get the URL for a file taking into account # characters.
+     *
+     * @param file the file whose URL representation is required.
+     * @return The FileURL value.
+     * @throws MalformedURLException if the URL representation cannot be
+     *      formed.
+     */
+    public URL getFileURL(File file) throws MalformedURLException {
+        return new URL(toURI(file.getAbsolutePath()));
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination.
+     * No filtering is performed.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(String sourceFile, String destFile) throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), null, false, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination
+     * specifying if token filtering must be used.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(String sourceFile, String destFile, FilterSetCollection filters)
+            throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters, false, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination specifying if token
+     * filtering must be used and if source files may overwrite newer destination files.
+     *
+     * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+     * @param destFile Name of file to copy to. Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be overwritten if it already
+     *            exists.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
+                         boolean overwrite) throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters, overwrite, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination
+     * specifying if token
+     * filtering must be used, if source files may overwrite newer destination
+     * files and the last
+     * modified time of <code>destFile</code> file should be made equal to
+     * the last modified time
+     * of <code>sourceFile</code>.
+     *
+     * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+     * @param destFile Name of file to copy to. Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be
+     *            overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *            the resulting file
+     *            should be set to that of the source file.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(String sourceFile, String destFile,
+                         FilterSetCollection filters,
+                         boolean overwrite, boolean preserveLastModified)
+        throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters, overwrite,
+                 preserveLastModified);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination specifying if token
+     * filtering must be used, if source files may overwrite newer destination files and the last
+     * modified time of <code>destFile</code> file should be made equal to the last modified time
+     * of <code>sourceFile</code>.
+     *
+     * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+     * @param destFile Name of file to copy to. Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be overwritten if it already
+     *            exists.
+     * @param preserveLastModified Whether or not the last modified time of the resulting file
+     *            should be set to that of the source file.
+     * @param encoding the encoding used to read and write the files.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.5
+     */
+    public void copyFile(String sourceFile, String destFile,
+                         FilterSetCollection filters, boolean overwrite,
+                         boolean preserveLastModified, String encoding) throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters,
+                 overwrite, preserveLastModified, encoding);
+    }
+
+    // CheckStyle:ParameterNumberCheck OFF - bc
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering must be used, if
+     * filter chains must be used, if source files may overwrite
+     * newer destination files and the last modified time of
+     * <code>destFile</code> file should be made equal
+     * to the last modified time of <code>sourceFile</code>.
+     *
+     * @param sourceFile Name of file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile Name of file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param filterChains filterChains to apply during the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     * @param encoding the encoding used to read and write the files.
+     * @param project the project instance.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.5
+     */
+    public void copyFile(String sourceFile, String destFile,
+                         FilterSetCollection filters, Vector filterChains,
+                         boolean overwrite, boolean preserveLastModified,
+                         String encoding, Project project) throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
+                preserveLastModified, encoding, project);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination specifying if token
+     * filtering must be used, if filter chains must be used, if source files may overwrite newer
+     * destination files and the last modified time of <code>destFile</code> file should be made
+     * equal to the last modified time of <code>sourceFile</code>.
+     *
+     * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+     * @param destFile Name of file to copy to. Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param filterChains filterChains to apply during the copy.
+     * @param overwrite Whether or not the destination file should be overwritten if it already
+     *            exists.
+     * @param preserveLastModified Whether or not the last modified time of the resulting file
+     *            should be set to that of the source file.
+     * @param inputEncoding the encoding used to read the files.
+     * @param outputEncoding the encoding used to write the files.
+     * @param project the project instance.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.6
+     */
+    public void copyFile(String sourceFile, String destFile,
+                         FilterSetCollection filters, Vector filterChains,
+                         boolean overwrite, boolean preserveLastModified,
+                         String inputEncoding, String outputEncoding,
+                         Project project) throws IOException {
+        copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
+                preserveLastModified, inputEncoding, outputEncoding, project);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination. No filtering is performed.
+     *
+     * @param sourceFile the file to copy from. Must not be <code>null</code>.
+     * @param destFile the file to copy to. Must not be <code>null</code>.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(File sourceFile, File destFile) throws IOException {
+        copyFile(sourceFile, destFile, null, false, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination
+     * specifying if token filtering must be used.
+     *
+     * @param sourceFile the file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile the file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
+            throws IOException {
+        copyFile(sourceFile, destFile, filters, false, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering must be used and if
+     * source files may overwrite newer destination files.
+     *
+     * @param sourceFile the file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile the file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
+                         boolean overwrite) throws IOException {
+        copyFile(sourceFile, destFile, filters, overwrite, false);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering must be used, if
+     * source files may overwrite newer destination files and the
+     * last modified time of <code>destFile</code> file should be made equal
+     * to the last modified time of <code>sourceFile</code>.
+     *
+     * @param sourceFile the file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile the file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     *
+     * @throws IOException if the copying fails.
+     */
+    public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
+                         boolean overwrite, boolean preserveLastModified) throws IOException {
+        copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, null);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a destination specifying if token
+     * filtering must be used, if source files may overwrite newer destination files, the last
+     * modified time of <code>destFile</code> file should be made equal to the last modified time
+     * of <code>sourceFile</code> and which character encoding to assume.
+     *
+     * @param sourceFile the file to copy from. Must not be <code>null</code>.
+     * @param destFile the file to copy to. Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param overwrite Whether or not the destination file should be overwritten if it already
+     *            exists.
+     * @param preserveLastModified Whether or not the last modified time of the resulting file
+     *            should be set to that of the source file.
+     * @param encoding the encoding used to read and write the files.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.5
+     */
+    public void copyFile(File sourceFile, File destFile,
+                         FilterSetCollection filters, boolean overwrite,
+                         boolean preserveLastModified, String encoding) throws IOException {
+        copyFile(sourceFile, destFile, filters, null, overwrite,
+                 preserveLastModified, encoding, null);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering must be used, if
+     * filter chains must be used, if source files may overwrite
+     * newer destination files and the last modified time of
+     * <code>destFile</code> file should be made equal
+     * to the last modified time of <code>sourceFile</code>.
+     *
+     * @param sourceFile the file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile the file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param filterChains filterChains to apply during the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     * @param encoding the encoding used to read and write the files.
+     * @param project the project instance.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.5
+     */
+    public void copyFile(File sourceFile, File destFile,
+                         FilterSetCollection filters, Vector filterChains,
+                         boolean overwrite, boolean preserveLastModified,
+                         String encoding, Project project) throws IOException {
+        copyFile(sourceFile, destFile, filters, filterChains,
+                 overwrite, preserveLastModified, encoding, encoding, project);
+    }
+
+    /**
+     * Convenience method to copy a file from a source to a
+     * destination specifying if token filtering must be used, if
+     * filter chains must be used, if source files may overwrite
+     * newer destination files and the last modified time of
+     * <code>destFile</code> file should be made equal
+     * to the last modified time of <code>sourceFile</code>.
+     *
+     * @param sourceFile the file to copy from.
+     *                   Must not be <code>null</code>.
+     * @param destFile the file to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param filterChains filterChains to apply during the copy.
+     * @param overwrite Whether or not the destination file should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the resulting file should be set to that
+     *                             of the source file.
+     * @param inputEncoding the encoding used to read the files.
+     * @param outputEncoding the encoding used to write the files.
+     * @param project the project instance.
+     *
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.6
+     */
+    public void copyFile(File sourceFile, File destFile,
+                         FilterSetCollection filters, Vector filterChains,
+                         boolean overwrite, boolean preserveLastModified,
+                         String inputEncoding, String outputEncoding,
+                         Project project) throws IOException {
+        ResourceUtils.copyResource(
+            new FileResource(sourceFile), new FileResource(destFile),
+            filters, filterChains, overwrite, preserveLastModified,
+            inputEncoding, outputEncoding, project);
+    }
+
+    // CheckStyle:ParameterNumberCheck ON
+
+    /**
+     * Calls File.setLastModified(long time). Originally written to
+     * to dynamically bind to that call on Java1.2+.
+     *
+     * @param file the file whose modified time is to be set
+     * @param time the time to which the last modified time is to be set.
+     *             if this is -1, the current time is used.
+     */
+    public void setFileLastModified(File file, long time) {
+        ResourceUtils.setLastModified(new FileResource(file), time);
+    }
+
+    /**
+     * Interpret the filename as a file relative to the given file
+     * unless the filename already represents an absolute filename.
+     * Differs from <code>new File(file, filename)</code> in that
+     * the resulting File's path will always be a normalized,
+     * absolute pathname.  Also, if it is determined that
+     * <code>filename</code> is context-relative, <code>file</code>
+     * will be discarded and the reference will be resolved using
+     * available context/state information about the filesystem.
+     *
+     * @param file the "reference" file for relative paths. This
+     * instance must be an absolute file and must not contain
+     * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
+     * of /).  If it is null, this call is equivalent to
+     * <code>new java.io.File(filename).getAbsoluteFile()</code>.
+     *
+     * @param filename a file name.
+     *
+     * @return an absolute file.
+     * @throws java.lang.NullPointerException if filename is null.
+     */
+    public File resolveFile(File file, String filename) {
+        if (!isAbsolutePath(filename)) {
+            char sep = File.separatorChar;
+            filename = filename.replace('/', sep).replace('\\', sep);
+            if (isContextRelativePath(filename)) {
+                file = null;
+                // on cygwin, our current directory can be a UNC;
+                // assume user.dir is absolute or all hell breaks loose...
+                String udir = System.getProperty("user.dir");
+                if (filename.charAt(0) == sep && udir.charAt(0) == sep) {
+                    filename = dissect(udir)[0] + filename.substring(1);
+                }
+            }
+            filename = new File(file, filename).getAbsolutePath();
+        }
+        return normalize(filename);
+    }
+
+    /**
+     * On DOS and NetWare, the evaluation of certain file
+     * specifications is context-dependent.  These are filenames
+     * beginning with a single separator (relative to current root directory)
+     * and filenames with a drive specification and no intervening separator
+     * (relative to current directory of the specified root).
+     * @param filename the filename to evaluate.
+     * @return true if the filename is relative to system context.
+     * @throws java.lang.NullPointerException if filename is null.
+     * @since Ant 1.7
+     */
+    public static boolean isContextRelativePath(String filename) {
+        if (!(ON_DOS || ON_NETWARE) || filename.length() == 0) {
+            return false;
+        }
+        char sep = File.separatorChar;
+        filename = filename.replace('/', sep).replace('\\', sep);
+        char c = filename.charAt(0);
+        int len = filename.length();
+        return (c == sep && (len == 1 || filename.charAt(1) != sep))
+                || (Character.isLetter(c) && len > 1
+                && filename.indexOf(':') == 1
+                && (len == 2 || filename.charAt(2) != sep));
+    }
+
+    /**
+     * Verifies that the specified filename represents an absolute path.
+     * Differs from new java.io.File("filename").isAbsolute() in that a path
+     * beginning with a double file separator--signifying a Windows UNC--must
+     * at minimum match "\\a\b" to be considered an absolute path.
+     * @param filename the filename to be checked.
+     * @return true if the filename represents an absolute path.
+     * @throws java.lang.NullPointerException if filename is null.
+     * @since Ant 1.6.3
+     */
+    public static boolean isAbsolutePath(String filename) {
+        int len = filename.length();
+        if (len == 0) {
+            return false;
+        }
+        char sep = File.separatorChar;
+        filename = filename.replace('/', sep).replace('\\', sep);
+        char c = filename.charAt(0);
+        if (!(ON_DOS || ON_NETWARE)) {
+            return (c == sep);
+        }
+        if (c == sep) {
+            // CheckStyle:MagicNumber OFF
+            if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) {
+                return false;
+            }
+            // CheckStyle:MagicNumber ON
+            int nextsep = filename.indexOf(sep, 2);
+            return nextsep > 2 && nextsep + 1 < len;
+        }
+        int colon = filename.indexOf(':');
+        return (Character.isLetter(c) && colon == 1
+                && filename.length() > 2 && filename.charAt(2) == sep)
+                || (ON_NETWARE && colon > 0);
+    }
+
+    /**
+     * Translate a path into its native (platform specific) format.
+     * <p>
+     * This method uses PathTokenizer to separate the input path
+     * into its components. This handles DOS style paths in a relatively
+     * sensible way. The file separators are then converted to their platform
+     * specific versions.
+     *
+     * @param toProcess The path to be translated.
+     *                  May be <code>null</code>.
+     *
+     * @return the native version of the specified path or
+     *         an empty string if the path is <code>null</code> or empty.
+     *
+     * @since ant 1.7
+     * @see PathTokenizer
+     */
+    public static String translatePath(String toProcess) {
+        if (toProcess == null || toProcess.length() == 0) {
+            return "";
+        }
+        StringBuffer path = new StringBuffer(toProcess.length() + EXPAND_SPACE);
+        PathTokenizer tokenizer = new PathTokenizer(toProcess);
+        while (tokenizer.hasMoreTokens()) {
+            String pathComponent = tokenizer.nextToken();
+            pathComponent = pathComponent.replace('/', File.separatorChar);
+            pathComponent = pathComponent.replace('\\', File.separatorChar);
+            if (path.length() != 0) {
+                path.append(File.pathSeparatorChar);
+            }
+            path.append(pathComponent);
+        }
+        return path.toString();
+    }
+
+    /**
+     * &quot;Normalize&quot; the given absolute path.
+     *
+     * <p>This includes:
+     * <ul>
+     *   <li>Uppercase the drive letter if there is one.</li>
+     *   <li>Remove redundant slashes after the drive spec.</li>
+     *   <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
+     *   <li>DOS style paths that start with a drive letter will have
+     *     \ as the separator.</li>
+     * </ul>
+     * Unlike {@link File#getCanonicalPath()} this method
+     * specifically does not resolve symbolic links.
+     *
+     * @param path the path to be normalized.
+     * @return the normalized version of the path.
+     *
+     * @throws java.lang.NullPointerException if path is null.
+     */
+    public File normalize(final String path) {
+        Stack s = new Stack();
+        String[] dissect = dissect(path);
+        s.push(dissect[0]);
+
+        StringTokenizer tok = new StringTokenizer(dissect[1], File.separator);
+        while (tok.hasMoreTokens()) {
+            String thisToken = tok.nextToken();
+            if (".".equals(thisToken)) {
+                continue;
+            }
+            if ("..".equals(thisToken)) {
+                if (s.size() < 2) {
+                    // Cannot resolve it, so skip it.
+                    return new File(path);
+                }
+                s.pop();
+            } else { // plain component
+                s.push(thisToken);
+            }
+        }
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < s.size(); i++) {
+            if (i > 1) {
+                // not before the filesystem root and not after it, since root
+                // already contains one
+                sb.append(File.separatorChar);
+            }
+            sb.append(s.elementAt(i));
+        }
+        return new File(sb.toString());
+    }
+
+    /**
+     * Dissect the specified absolute path.
+     * @param path the path to dissect.
+     * @return String[] {root, remaining path}.
+     * @throws java.lang.NullPointerException if path is null.
+     * @since Ant 1.7
+     */
+    public String[] dissect(String path) {
+        char sep = File.separatorChar;
+        path = path.replace('/', sep).replace('\\', sep);
+
+        // make sure we are dealing with an absolute path
+        if (!isAbsolutePath(path)) {
+            throw new BuildException(path + " is not an absolute path");
+        }
+        String root = null;
+        int colon = path.indexOf(':');
+        if (colon > 0 && (ON_DOS || ON_NETWARE)) {
+
+            int next = colon + 1;
+            root = path.substring(0, next);
+            char[] ca = path.toCharArray();
+            root += sep;
+            //remove the initial separator; the root has it.
+            next = (ca[next] == sep) ? next + 1 : next;
+
+            StringBuffer sbPath = new StringBuffer();
+            // Eliminate consecutive slashes after the drive spec:
+            for (int i = next; i < ca.length; i++) {
+                if (ca[i] != sep || ca[i - 1] != sep) {
+                    sbPath.append(ca[i]);
+                }
+            }
+            path = sbPath.toString();
+        } else if (path.length() > 1 && path.charAt(1) == sep) {
+            // UNC drive
+            int nextsep = path.indexOf(sep, 2);
+            nextsep = path.indexOf(sep, nextsep + 1);
+            root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
+            path = path.substring(root.length());
+        } else {
+            root = File.separator;
+            path = path.substring(1);
+        }
+        return new String[] {root, path};
+    }
+
+    /**
+     * Returns a VMS String representation of a <code>File</code> object.
+     * This is useful since the JVM by default internally converts VMS paths
+     * to Unix style.
+     * The returned String is always an absolute path.
+     *
+     * @param f The <code>File</code> to get the VMS path for.
+     * @return The absolute VMS path to <code>f</code>.
+     */
+    public String toVMSPath(File f) {
+        // format: "DEVICE:[DIR.SUBDIR]FILE"
+        String osPath;
+        String path = normalize(f.getAbsolutePath()).getPath();
+        String name = f.getName();
+        boolean isAbsolute = path.charAt(0) == File.separatorChar;
+        // treat directories specified using .DIR syntax as files
+        // CheckStyle:MagicNumber OFF
+        boolean isDirectory = f.isDirectory()
+                && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
+        // CheckStyle:MagicNumber ON
+        String device = null;
+        StringBuffer directory = null;
+        String file = null;
+
+        int index = 0;
+
+        if (isAbsolute) {
+            index = path.indexOf(File.separatorChar, 1);
+            if (index == -1) {
+                return path.substring(1) + ":[000000]";
+            }
+            device = path.substring(1, index++);
+        }
+        if (isDirectory) {
+            directory = new StringBuffer(path.substring(index).replace(File.separatorChar, '.'));
+        } else {
+            int dirEnd = path.lastIndexOf(File.separatorChar, path.length());
+            if (dirEnd == -1 || dirEnd < index) {
+                file = path.substring(index);
+            } else {
+                directory = new StringBuffer(path.substring(index, dirEnd).
+                                             replace(File.separatorChar, '.'));
+                index = dirEnd + 1;
+                if (path.length() > index) {
+                    file = path.substring(index);
+                }
+            }
+        }
+        if (!isAbsolute && directory != null) {
+            directory.insert(0, '.');
+        }
+        osPath = ((device != null) ? device + ":" : "")
+                + ((directory != null) ? "[" + directory + "]" : "")
+                + ((file != null) ? file : "");
+        return osPath;
+    }
+
+    /**
+     * Create a File object for a temporary file in a given directory. Without
+     * actually creating the file.
+     *
+     * <p>
+     * The file denoted by the returned abstract pathname did not exist before
+     * this method was invoked, any subsequent invocation of this method will
+     * yield a different file name.
+     * </p>
+     * <p>
+     * The filename is prefixNNNNNsuffix where NNNN is a random number.
+     * </p>
+     *
+     * @param prefix
+     *            prefix before the random number.
+     * @param suffix
+     *            file extension; include the '.'.
+     * @param parentDir
+     *            Directory to create the temporary file in; java.io.tmpdir used
+     *            if not specified.
+     *
+     * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
+     * boolean, boolean) instead.
+     * @return a File reference to the new, nonexistent temporary file.
+     */
+    public File createTempFile(String prefix, String suffix, File parentDir) {
+        return createTempFile(prefix, suffix, parentDir, false, false);
+    }
+
+    /**
+     * Create a temporary file in a given directory.
+     *
+     * <p>The file denoted by the returned abstract pathname did not
+     * exist before this method was invoked, any subsequent invocation
+     * of this method will yield a different file name.</p>
+     *
+     * @param prefix prefix before the random number.
+     * @param suffix file extension; include the '.'.
+     * @param parentDir Directory to create the temporary file in;
+     * java.io.tmpdir used if not specified.
+     * @param deleteOnExit whether to set the tempfile for deletion on
+     *        normal VM exit.
+     * @param createFile true if the file must actually be created. If false
+     * chances exist that a file with the same name is created in the time
+     * between invoking this method and the moment the file is actually created.
+     * If possible set to true.
+     *
+     * @return a File reference to the new temporary file.
+     * @since Ant 1.7.1
+     */
+    public File createTempFile(String prefix, String suffix, File parentDir,
+            boolean deleteOnExit, boolean createFile) {
+        File result = null;
+        String parent = (parentDir == null)
+                ? System.getProperty("java.io.tmpdir")
+                : parentDir.getPath();
+
+        if (createFile) {
+            try {
+                result = File.createTempFile(prefix, suffix, new File(parent));
+            } catch (IOException e) {
+                throw new BuildException("Could not create tempfile in "
+                        + parent, e);
+            }
+        } else {
+            DecimalFormat fmt = new DecimalFormat("#####");
+            synchronized (rand) {
+                do {
+                    result = new File(parent, prefix
+                            + fmt.format(Math.abs(rand.nextInt())) + suffix);
+                } while (result.exists());
+            }
+        }
+
+        if (deleteOnExit) {
+            result.deleteOnExit();
+        }
+        return result;
+    }
+
+    /**
+     * Create a File object for a temporary file in a given directory. Without
+     * actually creating the file.
+     *
+     * <p>
+     * The file denoted by the returned abstract pathname did not exist before
+     * this method was invoked, any subsequent invocation of this method will
+     * yield a different file name.
+     * </p>
+     * <p>
+     * The filename is prefixNNNNNsuffix where NNNN is a random number.
+     * </p>
+     *
+     * @param prefix
+     *            prefix before the random number.
+     * @param suffix
+     *            file extension; include the '.'.
+     * @param parentDir
+     *            Directory to create the temporary file in; java.io.tmpdir used
+     *            if not specified.
+     * @param deleteOnExit
+     *            whether to set the tempfile for deletion on normal VM exit.
+     *
+     * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
+     * boolean, boolean) instead.
+     * @return a File reference to the new, nonexistent temporary file.
+     */
+    public File createTempFile(String prefix, String suffix,
+            File parentDir, boolean deleteOnExit) {
+        return createTempFile(prefix, suffix, parentDir, deleteOnExit, false);
+    }
+
+    /**
+     * Compares the contents of two files.
+     *
+     * @param f1 the file whose content is to be compared.
+     * @param f2 the other file whose content is to be compared.
+     *
+     * @return true if the content of the files is the same.
+     *
+     * @throws IOException if the files cannot be read.
+     */
+    public boolean contentEquals(File f1, File f2) throws IOException {
+        return contentEquals(f1, f2, false);
+    }
+
+    /**
+     * Compares the contents of two files.
+     *
+     * @param f1 the file whose content is to be compared.
+     * @param f2 the other file whose content is to be compared.
+     * @param textfile true if the file is to be treated as a text file and
+     *        differences in kind of line break are to be ignored.
+     *
+     * @return true if the content of the files is the same.
+     *
+     * @throws IOException if the files cannot be read.
+     * @since Ant 1.6.3
+     */
+    public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException {
+        return ResourceUtils.contentEquals(new FileResource(f1), new FileResource(f2), textfile);
+    }
+
+    /**
+     * This was originally an emulation of {@link File#getParentFile} for JDK 1.1, but it is now
+     * implemented using that method (Ant 1.6.3 onwards).
+     *
+     * @param f the file whose parent is required.
+     * @return the given file's parent, or null if the file does not have a parent.
+     * @since 1.10
+     * @deprecated since 1.7. Just use {@link File#getParentFile} directly.
+     */
+    public File getParentFile(File f) {
+        return (f == null) ? null : f.getParentFile();
+    }
+
+    /**
+     * Read from reader till EOF.
+     * @param rdr the reader from which to read.
+     * @return the contents read out of the given reader.
+     *
+     * @throws IOException if the contents could not be read out from the
+     *         reader.
+     */
+    public static String readFully(Reader rdr) throws IOException {
+        return readFully(rdr, BUF_SIZE);
+    }
+
+    /**
+     * Read from reader till EOF.
+     *
+     * @param rdr the reader from which to read.
+     * @param bufferSize the buffer size to use when reading.
+     *
+     * @return the contents read out of the given reader.
+     *
+     * @throws IOException if the contents could not be read out from the
+     *         reader.
+     */
+    public static String readFully(Reader rdr, int bufferSize)
+        throws IOException {
+        if (bufferSize <= 0) {
+            throw new IllegalArgumentException("Buffer size must be greater "
+                                               + "than 0");
+        }
+        final char[] buffer = new char[bufferSize];
+        int bufferLength = 0;
+        StringBuffer textBuffer = null;
+        while (bufferLength != -1) {
+            bufferLength = rdr.read(buffer);
+            if (bufferLength > 0) {
+                textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
+                textBuffer.append(new String(buffer, 0, bufferLength));
+            }
+        }
+        return (textBuffer == null) ? null : textBuffer.toString();
+    }
+
+    /**
+     * Safe read fully - do not return a null for an empty reader.
+     * @param reader the input to read from.
+     * @return the string.
+     * @throws IOException if unable to read from reader.
+     * @since Ant 1.7.1
+     */
+    public static String safeReadFully(Reader reader) throws IOException {
+        String ret = readFully(reader);
+        return ret == null ? "" : ret;
+    }
+
+    /**
+     * This was originally an emulation of File.createNewFile for JDK 1.1,
+     * but it is now implemented using that method (Ant 1.6.3 onwards).
+     *
+     * <p>This method has historically <strong>not</strong> guaranteed that the
+     * operation was atomic. In its current implementation it is.
+     *
+     * @param f the file to be created.
+     * @return true if the file did not exist already.
+     * @throws IOException on error.
+     * @since Ant 1.5
+     */
+    public boolean createNewFile(File f) throws IOException {
+        return f.createNewFile();
+    }
+
+    /**
+     * Create a new file, optionally creating parent directories.
+     *
+     * @param f the file to be created.
+     * @param mkdirs <code>boolean</code> whether to create parent directories.
+     * @return true if the file did not exist already.
+     * @throws IOException on error.
+     * @since Ant 1.6.3
+     */
+    public boolean createNewFile(File f, boolean mkdirs) throws IOException {
+        File parent = f.getParentFile();
+        if (mkdirs && !(parent.exists())) {
+            parent.mkdirs();
+        }
+        return f.createNewFile();
+    }
+
+    /**
+     * Checks whether a given file is a symbolic link.
+     *
+     * <p>It doesn't really test for symbolic links but whether the
+     * canonical and absolute paths of the file are identical--this
+     * may lead to false positives on some platforms.</p>
+     *
+     * @param parent the parent directory of the file to test
+     * @param name the name of the file to test.
+     *
+     * @return true if the file is a symbolic link.
+     * @throws IOException on error.
+     * @since Ant 1.5
+     */
+    public boolean isSymbolicLink(File parent, String name)
+        throws IOException {
+        if (parent == null) {
+            File f = new File(name);
+            parent = f.getParentFile();
+            name = f.getName();
+        }
+        File toTest = new File(parent.getCanonicalPath(), name);
+        return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
+    }
+
+    /**
+     * Removes a leading path from a second path.
+     *
+     * @param leading The leading path, must not be null, must be absolute.
+     * @param path The path to remove from, must not be null, must be absolute.
+     *
+     * @return path's normalized absolute if it doesn't start with
+     * leading; path's path with leading's path removed otherwise.
+     *
+     * @since Ant 1.5
+     */
+    public String removeLeadingPath(File leading, File path) {
+        String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
+        String p = normalize(path.getAbsolutePath()).getAbsolutePath();
+        if (l.equals(p)) {
+            return "";
+        }
+        // ensure that l ends with a /
+        // so we never think /foo was a parent directory of /foobar
+        if (!l.endsWith(File.separator)) {
+            l += File.separator;
+        }
+        return (p.startsWith(l)) ? p.substring(l.length()) : p;
+    }
+
+    /**
+     * Learn whether one path "leads" another.
+     * @param leading The leading path, must not be null, must be absolute.
+     * @param path The path to remove from, must not be null, must be absolute.
+     * @return true if path starts with leading; false otherwise.
+     * @since Ant 1.7
+     */
+    public boolean isLeadingPath(File leading, File path) {
+        String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
+        String p = normalize(path.getAbsolutePath()).getAbsolutePath();
+        if (l.equals(p)) {
+            return true;
+        }
+        // ensure that l ends with a /
+        // so we never think /foo was a parent directory of /foobar
+        if (!l.endsWith(File.separator)) {
+            l += File.separator;
+        }
+        return p.startsWith(l);
+    }
+
+    /**
+     * Constructs a <code>file:</code> URI that represents the
+     * external form of the given pathname.
+     *
+     * <p>Will be an absolute URI if the given path is absolute.</p>
+     *
+     * <p>This code encodes non ASCII characters too.</p>
+     *
+     * <p>The coding of the output is the same as what File.toURI().toASCIIString() produces</p>
+     *
+     * See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a>
+     * which makes some mention of how
+     * characters not supported by URI Reference syntax should be escaped.
+     *
+     * @param path the path in the local file system.
+     * @return the URI version of the local path.
+     * @since Ant 1.6
+     */
+    public String toURI(String path) {
+        // #8031: first try Java 1.4.
+        Class uriClazz = null;
+        try {
+            uriClazz = Class.forName("java.net.URI");
+        } catch (ClassNotFoundException e) {
+            // OK, Java 1.3.
+        }
+        if (uriClazz != null) {
+            try {
+                File f = new File(path).getAbsoluteFile();
+                java.lang.reflect.Method toURIMethod = File.class.getMethod("toURI", new Class[0]);
+                Object uriObj = toURIMethod.invoke(f, new Object[] {});
+                java.lang.reflect.Method toASCIIStringMethod
+                        = uriClazz.getMethod("toASCIIString", new Class[0]);
+                return (String) toASCIIStringMethod.invoke(uriObj, new Object[] {});
+            } catch (Exception e) {
+                // Reflection problems? Should not happen, debug.
+                e.printStackTrace();
+            }
+        }
+        boolean isDir = new File(path).isDirectory();
+
+        StringBuffer sb = new StringBuffer("file:");
+
+        path = resolveFile(null, path).getPath();
+        sb.append("//");
+        // add an extra slash for filesystems with drive-specifiers
+        if (!path.startsWith(File.separator)) {
+            sb.append("/");
+        }
+        path = path.replace('\\', '/');
+        try {
+            sb.append(Locator.encodeURI(path));
+        } catch (UnsupportedEncodingException exc) {
+            throw new BuildException(exc);
+        }
+        if (isDir && !path.endsWith("/")) {
+            sb.append('/');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Constructs a file path from a <code>file:</code> URI.
+     *
+     * <p>Will be an absolute path if the given URI is absolute.</p>
+     *
+     * <p>Swallows '%' that are not followed by two characters,
+     * doesn't deal with non-ASCII characters.</p>
+     *
+     * @param uri the URI designating a file in the local filesystem.
+     * @return the local file system path for the file.
+     * @since Ant 1.6
+     */
+    public String fromURI(String uri) {
+        synchronized (cacheFromUriLock) {
+            if (uri.equals(cacheFromUriRequest)) {
+                return cacheFromUriResponse;
+            }
+            String path = Locator.fromURI(uri);
+            String ret = isAbsolutePath(path) ? normalize(path).getAbsolutePath() : path;
+            cacheFromUriRequest = uri;
+            cacheFromUriResponse = ret;
+            return ret;
+        }
+    }
+
+    /**
+     * Compares two filenames.
+     *
+     * <p>Unlike java.io.File#equals this method will try to compare
+     * the absolute paths and &quot;normalize&quot; the filenames
+     * before comparing them.</p>
+     *
+     * @param f1 the file whose name is to be compared.
+     * @param f2 the other file whose name is to be compared.
+     *
+     * @return true if the file are for the same file.
+     *
+     * @since Ant 1.5.3
+     */
+    public boolean fileNameEquals(File f1, File f2) {
+        return normalize(f1.getAbsolutePath()).getAbsolutePath().equals(
+                normalize(f2.getAbsolutePath()).getAbsolutePath());
+    }
+
+    /**
+     * Renames a file, even if that involves crossing file system boundaries.
+     *
+     * <p>This will remove <code>to</code> (if it exists), ensure that
+     * <code>to</code>'s parent directory exists and move
+     * <code>from</code>, which involves deleting <code>from</code> as
+     * well.</p>
+     *
+     * @param from the file to move.
+     * @param to the new file name.
+     *
+     * @throws IOException if anything bad happens during this
+     * process.  Note that <code>to</code> may have been deleted
+     * already when this happens.
+     *
+     * @since Ant 1.6
+     */
+    public void rename(File from, File to) throws IOException {
+        from = normalize(from.getAbsolutePath()).getCanonicalFile();
+        to = normalize(to.getAbsolutePath());
+        if (!from.exists()) {
+            System.err.println("Cannot rename nonexistent file " + from);
+            return;
+        }
+        if (from.equals(to)) {
+            System.err.println("Rename of " + from + " to " + to + " is a no-op.");
+            return;
+        }
+        if (to.exists() && !(from.equals(to.getCanonicalFile()) || to.delete())) {
+            throw new IOException("Failed to delete " + to + " while trying to rename " + from);
+        }
+        File parent = to.getParentFile();
+        if (parent != null && !parent.exists() && !parent.mkdirs()) {
+            throw new IOException("Failed to create directory " + parent
+                                  + " while trying to rename " + from);
+        }
+        if (!from.renameTo(to)) {
+            copyFile(from, to);
+            if (!from.delete()) {
+                throw new IOException("Failed to delete " + from + " while trying to rename it.");
+            }
+        }
+    }
+
+    /**
+     * Get the granularity of file timestamps. The choice is made based on OS, which is
+     * incorrect--it should really be by filesystem. We do not have an easy way to probe for file
+     * systems, however, so this heuristic gives us a decent default.
+     *
+     * @return the difference, in milliseconds, which two file timestamps must have in order for the
+     *         two files to be considered to have different timestamps.
+     */
+    public long getFileTimestampGranularity() {
+        if (ON_WIN9X) {
+            return FAT_FILE_TIMESTAMP_GRANULARITY;
+        }
+        if (ON_WINDOWS) {
+            return NTFS_FILE_TIMESTAMP_GRANULARITY;
+        }
+        if (ON_DOS) {
+            return FAT_FILE_TIMESTAMP_GRANULARITY;
+        }
+        return UNIX_FILE_TIMESTAMP_GRANULARITY;
+    }
+
+    /**
+     * test whether a file or directory exists, with an error in the
+     * upper/lower case spelling of the name.
+     * Using this method is only interesting on case insensitive file systems
+     * (Windows).<br/>
+     * It will return true only if 3 conditions are met :
+     * <br/>
+     * <ul>
+     *   <li>operating system is case insensitive</li>
+     *   <li>file exists</li>
+     *   <li>actual name from directory reading is different from the
+     *       supplied argument</li>
+     * </ul>
+     *  <br/>
+     * the purpose is to identify files or directories on case-insensitive
+     * filesystems whose case is not what is expected.<br/>
+     * Possibly to rename them afterwards to the desired upper/lowercase
+     * combination.
+     * <br/>
+     * @param localFile file to test
+     * @return true if the file exists and the case of the actual file
+     *              is not the case of the parameter
+     * @since Ant 1.7.1
+     */
+    public boolean hasErrorInCase(File localFile) {
+        localFile = normalize(localFile.getAbsolutePath());
+        if (!localFile.exists()) {
+            return false;
+        }
+        final String localFileName = localFile.getName();
+        FilenameFilter ff = new FilenameFilter () {
+            public boolean accept(File dir, String name) {
+                return name.equalsIgnoreCase(localFileName) && (!name.equals(localFileName));
+            }
+        };
+        String[] names = localFile.getParentFile().list(ff);
+        return names != null && names.length == 1;
+    }
+
+    /**
+     * Returns true if the source is older than the dest.
+     * If the dest file does not exist, then the test returns false; it is
+     * implicitly not up do date.
+     * @param source source file (should be the older).
+     * @param dest dest file (should be the newer).
+     * @param granularity an offset added to the source time.
+     * @return true if the source is older than the dest after accounting
+     *              for granularity.
+     * @since Ant 1.6.3
+     */
+    public boolean isUpToDate(File source, File dest, long granularity) {
+        //do a check for the destination file existing
+        if (!dest.exists()) {
+            //if it does not, then the file is not up to date.
+            return false;
+        }
+        long sourceTime = source.lastModified();
+        long destTime = dest.lastModified();
+        return isUpToDate(sourceTime, destTime, granularity);
+    }
+
+    /**
+     * Returns true if the source is older than the dest.
+     * @param source source file (should be the older).
+     * @param dest dest file (should be the newer).
+     * @return true if the source is older than the dest, taking the granularity into account.
+     * @since Ant 1.6.3
+     */
+    public boolean isUpToDate(File source, File dest) {
+        return isUpToDate(source, dest, getFileTimestampGranularity());
+    }
+
+    /**
+     * Compare two timestamps for being up to date using
+     * the specified granularity.
+     *
+     * @param sourceTime timestamp of source file.
+     * @param destTime timestamp of dest file.
+     * @param granularity os/filesys granularity.
+     * @return true if the dest file is considered up to date.
+     */
+    public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
+        return destTime != -1 && destTime >= sourceTime + granularity;
+    }
+
+    /**
+     * Compare two timestamps for being up to date using the
+     * current granularity.
+     *
+     * @param sourceTime  timestamp of source file.
+     * @param destTime    timestamp of dest file.
+     * @return true if the dest file is considered up to date.
+     */
+    public boolean isUpToDate(long sourceTime, long destTime) {
+        return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
+    }
+
+    /**
+     * Close a Writer without throwing any exception if something went wrong.
+     * Do not attempt to close it if the argument is null.
+     * @param device output writer, can be null.
+     */
+    public static void close(Writer device) {
+        if (null != device) {
+            try {
+                device.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Close a Reader without throwing any exception if something went wrong.
+     * Do not attempt to close it if the argument is null.
+     *
+     * @param device Reader, can be null.
+     */
+    public static void close(Reader device) {
+        if (null != device) {
+            try {
+                device.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Close a stream without throwing any exception if something went wrong.
+     * Do not attempt to close it if the argument is null.
+     *
+     * @param device stream, can be null.
+     */
+    public static void close(OutputStream device) {
+        if (null != device) {
+            try {
+                device.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Close a stream without throwing any exception if something went wrong.
+     * Do not attempt to close it if the argument is null.
+     *
+     * @param device stream, can be null.
+     */
+    public static void close(InputStream device) {
+        if (null != device) {
+            try {
+                device.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Delete the file with {@link File#delete()} if the argument is not null.
+     * Do nothing on a null argument.
+     * @param file file to delete.
+     */
+    public static void delete(File file) {
+        if (file != null) {
+            file.delete();
+        }
+    }
+
+    /**
+     * Calculates the relative path between two files.
+     * <p>
+     * Implementation note:<br/> This function may throw an IOException if an I/O error occurs
+     * because its use of the canonical pathname may require filesystem queries.
+     * </p>
+     *
+     * @param fromFile the <code>File</code> to calculate the path from
+     * @param toFile the <code>File</code> to calculate the path to
+     * @return the relative path between the files
+     * @throws Exception for undocumented reasons
+     * @see File#getCanonicalPath()
+     *
+     * @since Ant 1.7
+     */
+    public static String getRelativePath(File fromFile, File toFile) throws Exception {
+        String fromPath = fromFile.getCanonicalPath();
+        String toPath = toFile.getCanonicalPath();
+
+        // build the path stack info to compare
+        String[] fromPathStack = getPathStack(fromPath);
+        String[] toPathStack = getPathStack(toPath);
+
+        if (0 < toPathStack.length && 0 < fromPathStack.length) {
+            if (!fromPathStack[0].equals(toPathStack[0])) {
+                // not the same device (would be "" on Linux/Unix)
+
+                return getPath(Arrays.asList(toPathStack));
+            }
+        } else {
+            // no comparison possible
+            return getPath(Arrays.asList(toPathStack));
+        }
+
+        int minLength = Math.min(fromPathStack.length, toPathStack.length);
+        int same = 1; // Used outside the for loop
+
+        // get index of parts which are equal
+        for (;
+             same < minLength && fromPathStack[same].equals(toPathStack[same]);
+             same++) {
+            // Do nothing
+        }
+
+        List relativePathStack = new ArrayList();
+
+        // if "from" part is longer, fill it up with ".."
+        // to reach path which is equal to both paths
+        for (int i = same; i < fromPathStack.length; i++) {
+            relativePathStack.add("..");
+        }
+
+        // fill it up path with parts which were not equal
+        for (int i = same; i < toPathStack.length; i++) {
+            relativePathStack.add(toPathStack[i]);
+        }
+
+        return getPath(relativePathStack);
+    }
+
+    /**
+     * Gets all names of the path as an array of <code>String</code>s.
+     *
+     * @param path to get names from
+     * @return <code>String</code>s, never <code>null</code>
+     *
+     * @since Ant 1.7
+     */
+    public static String[] getPathStack(String path) {
+        String normalizedPath = path.replace(File.separatorChar, '/');
+
+        // since Java 1.4
+        //return normalizedPath.split("/");
+        // workaround for Java 1.2-1.3
+        Object[] tokens = StringUtils.split(normalizedPath, '/').toArray();
+        String[] rv = new String[tokens.length];
+        System.arraycopy(tokens, 0, rv, 0, tokens.length);
+
+        return rv;
+    }
+
+    /**
+     * Gets path from a <code>List</code> of <code>String</code>s.
+     *
+     * @param pathStack <code>List</code> of <code>String</code>s to be concatenated as a path.
+     * @return <code>String</code>, never <code>null</code>
+     *
+     * @since Ant 1.7
+     */
+    public static String getPath(List pathStack) {
+        // can safely use '/' because Windows understands '/' as separator
+        return getPath(pathStack, '/');
+    }
+
+    /**
+     * Gets path from a <code>List</code> of <code>String</code>s.
+     *
+     * @param pathStack <code>List</code> of <code>String</code>s to be concated as a path.
+     * @param separatorChar <code>char</code> to be used as separator between names in path
+     * @return <code>String</code>, never <code>null</code>
+     *
+     * @since Ant 1.7
+     */
+    public static String getPath(final List pathStack, final char separatorChar) {
+        final StringBuffer buffer = new StringBuffer();
+
+        final Iterator iter = pathStack.iterator();
+        if (iter.hasNext()) {
+            buffer.append(iter.next());
+        }
+        while (iter.hasNext()) {
+            buffer.append(separatorChar);
+            buffer.append(iter.next());
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Get the default encoding.
+     * This is done by opening an InputStreamReader on
+     * a dummy InputStream and getting the encoding.
+     * Could use System.getProperty("file.encoding"), but cannot
+     * see where this is documented.
+     * @return the default file encoding.
+     */
+    public String getDefaultEncoding() {
+        InputStreamReader is = new InputStreamReader(
+            new InputStream() {
+                public int read() {
+                    return -1;
+                }
+            });
+        try {
+            return is.getEncoding();
+        } finally {
+            close(is);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java b/trunk/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java
new file mode 100644
index 0000000..420ccc6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the source
+ * file name without any leading directory information.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks if the flatten attribute has been set.</p>
+ *
+ */
+public class FlatFileNameMapper implements FileNameMapper {
+
+    /**
+     * Ignored.
+     * @param from ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Ignored.
+     * @param to ignored.
+     */
+    public void setTo(String to) {
+    }
+
+    /**
+     * Returns an one-element array containing the source file name
+     * without any leading directory information.
+     * @param sourceFileName the name to map.
+     * @return the file name in a one-element array.
+     */
+    public String[] mapFileName(String sourceFileName) {
+        return new String[] {new java.io.File(sourceFileName).getName()};
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/GlobPatternMapper.java b/trunk/src/main/org/apache/tools/ant/util/GlobPatternMapper.java
new file mode 100644
index 0000000..82f3972
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/GlobPatternMapper.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Implementation of FileNameMapper that does simple wildcard pattern
+ * replacements.
+ *
+ * <p>This does simple translations like *.foo -> *.bar where the
+ * prefix to .foo will be left unchanged. It only handles a single *
+ * character, use regular expressions for more complicated
+ * situations.</p>
+ *
+ * <p>This is one of the more useful Mappers, it is used by javac for
+ * example.</p>
+ *
+ */
+public class GlobPatternMapper implements FileNameMapper {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    /**
+     * Part of &quot;from&quot; pattern before the *.
+     */
+    protected String fromPrefix = null;
+
+    /**
+     * Part of &quot;from&quot; pattern after the *.
+     */
+    protected String fromPostfix = null;
+
+    /**
+     * Length of the prefix (&quot;from&quot; pattern).
+     */
+    protected int prefixLength;
+
+    /**
+     * Length of the postfix (&quot;from&quot; pattern).
+     */
+    protected int postfixLength;
+
+    /**
+     * Part of &quot;to&quot; pattern before the *.
+     */
+    protected String toPrefix = null;
+
+    /**
+     * Part of &quot;to&quot; pattern after the *.
+     */
+    protected String toPostfix = null;
+
+    // CheckStyle:VisibilityModifier ON
+
+    private boolean handleDirSep = false;
+    private boolean caseSensitive = true;
+
+    /**
+     * Attribute specifing whether to ignore the difference
+     * between / and \ (the two common directory characters).
+     * @param handleDirSep a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setHandleDirSep(boolean handleDirSep) {
+        this.handleDirSep = handleDirSep;
+    }
+
+    /**
+     * Attribute specifing whether to ignore the case difference
+     * in the names.
+     *
+     * @param caseSensitive a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    /**
+     * Sets the &quot;from&quot; pattern. Required.
+     * @param from a string
+     */
+    public void setFrom(String from) {
+        int index = from.lastIndexOf("*");
+        if (index == -1) {
+            fromPrefix = from;
+            fromPostfix = "";
+        } else {
+            fromPrefix = from.substring(0, index);
+            fromPostfix = from.substring(index + 1);
+        }
+        prefixLength = fromPrefix.length();
+        postfixLength = fromPostfix.length();
+    }
+
+    /**
+     * Sets the &quot;to&quot; pattern. Required.
+     * @param to a string
+     */
+    public void setTo(String to) {
+        int index = to.lastIndexOf("*");
+        if (index == -1) {
+            toPrefix = to;
+            toPostfix = "";
+        } else {
+            toPrefix = to.substring(0, index);
+            toPostfix = to.substring(index + 1);
+        }
+    }
+
+    /**
+     * Returns null if the source file name doesn't match the
+     * &quot;from&quot; pattern, an one-element array containing the
+     * translated file otherwise.
+     * @param sourceFileName the filename to map
+     * @return a list of converted filenames
+     */
+    public String[] mapFileName(String sourceFileName) {
+        if (fromPrefix == null
+            || !modifyName(sourceFileName).startsWith(modifyName(fromPrefix))
+            || !modifyName(sourceFileName).endsWith(modifyName(fromPostfix))) {
+            return null;
+        }
+        return new String[] {toPrefix
+                                 + extractVariablePart(sourceFileName)
+                                 + toPostfix};
+    }
+
+    /**
+     * Returns the part of the given string that matches the * in the
+     * &quot;from&quot; pattern.
+     * @param name the source file name
+     * @return the variable part of the name
+     */
+    protected String extractVariablePart(String name) {
+        return name.substring(prefixLength,
+                              name.length() - postfixLength);
+    }
+
+    /**
+     * modify string based on dir char mapping and case sensitivity
+     * @param name the name to convert
+     * @return the converted name
+     */
+    private String modifyName(String name) {
+        if (!caseSensitive) {
+            name = name.toLowerCase();
+        }
+        if (handleDirSep) {
+            if (name.indexOf('\\') != -1) {
+                name = name.replace('\\', '/');
+            }
+        }
+        return name;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/IdentityMapper.java b/trunk/src/main/org/apache/tools/ant/util/IdentityMapper.java
new file mode 100644
index 0000000..22c6c7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/IdentityMapper.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the source file name.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks.</p>
+ *
+ */
+public class IdentityMapper implements FileNameMapper {
+
+    /**
+     * Ignored.
+     * @param from ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Ignored.
+     * @param to ignored.
+     */
+    public void setTo(String to) {
+    }
+
+    /**
+     * Returns an one-element array containing the source file name.
+     * @param sourceFileName the name to map.
+     * @return the source filename in a one-element array.
+     */
+    public String[] mapFileName(String sourceFileName) {
+        return new String[] {sourceFileName};
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/IdentityStack.java b/trunk/src/main/org/apache/tools/ant/util/IdentityStack.java
new file mode 100755
index 0000000..2f95cf5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/IdentityStack.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Stack;
+
+/**
+ * Identity Stack.
+ * @since Ant 1.7
+ */
+public class IdentityStack extends Stack {
+
+    private static final long serialVersionUID = -5555522620060077046L;
+
+    /**
+     * Get an IdentityStack containing the contents of the specified Stack.
+     * @param s the Stack to copy; ignored if null.
+     * @return an IdentityStack instance.
+     */
+    public static IdentityStack getInstance(Stack s) {
+        if (s instanceof IdentityStack) {
+            return (IdentityStack) s;
+        }
+        IdentityStack result = new IdentityStack();
+        if (s != null) {
+            result.addAll(s);
+        }
+        return result;
+    }
+
+    /**
+     * Default constructor.
+     */
+    public IdentityStack() {
+    }
+
+    /**
+     * Construct a new IdentityStack with the specified Object
+     * as the bottom element.
+     * @param o the bottom element.
+     */
+    public IdentityStack(Object o) {
+        super();
+        push(o);
+    }
+
+    /**
+     * Override methods that use <code>.equals()</code> comparisons on elements.
+     * @param o the Object to search for.
+     * @return true if the stack contains the object.
+     * @see java.util.Vector#contains(Object)
+     */
+    public synchronized boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Override methods that use <code>.equals()</code> comparisons on elements.
+     * @param o   the Object to search for.
+     * @param pos the position from which to search.
+     * @return the position of the object, -1 if not found.
+     * @see java.util.Vector#indexOf(Object, int)
+     */
+    public synchronized int indexOf(Object o, int pos) {
+        for (int i = pos; i < size(); i++) {
+            if (get(i) == o) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Override methods that use <code>.equals()</code> comparisons on elements.
+     * @param o   the Object to search for.
+     * @param pos the position from which to search (backward).
+     * @return the position of the object, -1 if not found.
+     * @see java.util.Vector#indexOf(Object, int)
+     */
+    public synchronized int lastIndexOf(Object o, int pos) {
+        for (int i = pos; i >= 0; i--) {
+            if (get(i) == o) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/JAXPUtils.java b/trunk/src/main/org/apache/tools/ant/util/JAXPUtils.java
new file mode 100644
index 0000000..ca310fb
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/JAXPUtils.java
@@ -0,0 +1,258 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.apache.tools.ant.BuildException;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Collection of helper methods that retrieve a ParserFactory or
+ * Parsers and Readers.
+ *
+ * <p>This class will create only a single factory instance.</p>
+ *
+ * @since Ant 1.5
+ */
+public class JAXPUtils {
+
+    /**
+     * Helper for systemId.
+     *
+     * @since Ant 1.6
+     */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Parser factory to use to create parsers.
+     * @see #getParserFactory
+     *
+     * @since Ant 1.5
+     */
+    private static SAXParserFactory parserFactory = null;
+
+    /**
+     * Parser Factory to create Namespace aware parsers.
+     *
+     * @since Ant 1.6
+     */
+    private static SAXParserFactory nsParserFactory = null;
+
+    /**
+     * Parser factory to use to create document builders.
+     *
+     * @since Ant 1.6
+     */
+    private static DocumentBuilderFactory builderFactory = null;
+
+    /**
+     * Returns the parser factory to use. Only one parser factory is
+     * ever created by this method and is then cached for future use.
+     *
+     * @return a SAXParserFactory to use.
+     * @throws BuildException on error.
+     *
+     * @since Ant 1.5
+     */
+    public static synchronized SAXParserFactory getParserFactory()
+        throws BuildException {
+
+        if (parserFactory == null) {
+            parserFactory = newParserFactory();
+        }
+        return parserFactory;
+    }
+
+    /**
+     * Returns the parser factory to use to create namespace aware parsers.
+     *
+     * @return a SAXParserFactory to use which supports manufacture of
+     * namespace aware parsers.
+     * @throws BuildException on error.
+     *
+     * @since Ant 1.6
+     */
+    public static synchronized SAXParserFactory getNSParserFactory()
+        throws BuildException {
+
+        if (nsParserFactory == null) {
+            nsParserFactory = newParserFactory();
+            nsParserFactory.setNamespaceAware(true);
+        }
+        return nsParserFactory;
+    }
+
+    /**
+     * Returns a new  parser factory instance.
+     *
+     * @return the parser factory.
+     * @throws BuildException on error.
+     * @since Ant 1.5
+     */
+    public static SAXParserFactory newParserFactory() throws BuildException {
+
+        try {
+            return SAXParserFactory.newInstance();
+        } catch (FactoryConfigurationError e) {
+            throw new BuildException("XML parser factory has not been "
+                                     + "configured correctly: "
+                                     + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Returns a newly created SAX 1 Parser, using the default parser
+     * factory.
+     *
+     * @return a SAX 1 Parser.
+     * @throws BuildException on error.
+     * @see #getParserFactory
+     * @since Ant 1.5
+     */
+    public static Parser getParser() throws BuildException {
+        try {
+            return newSAXParser(getParserFactory()).getParser();
+        } catch (SAXException e) {
+            throw convertToBuildException(e);
+        }
+    }
+
+    /**
+     * Returns a newly created SAX 2 XMLReader, using the default parser
+     * factory.
+     *
+     * @return a SAX 2 XMLReader.
+     * @throws BuildException on error.
+     * @see #getParserFactory
+     * @since Ant 1.5
+     */
+    public static XMLReader getXMLReader() throws BuildException {
+        try {
+            return newSAXParser(getParserFactory()).getXMLReader();
+        } catch (SAXException e) {
+            throw convertToBuildException(e);
+        }
+    }
+
+    /**
+     * Returns a newly created SAX 2 XMLReader, which is namespace aware
+     *
+     * @return a SAX 2 XMLReader.
+     * @throws BuildException on error.
+     * @see #getParserFactory
+     * @since Ant 1.6
+     */
+    public static XMLReader getNamespaceXMLReader() throws BuildException {
+        try {
+            return newSAXParser(getNSParserFactory()).getXMLReader();
+        } catch (SAXException e) {
+            throw convertToBuildException(e);
+        }
+    }
+
+    /**
+     * This is a best attempt to provide a URL.toExternalForm() from
+     * a file URL. Some parsers like Crimson choke on uri that are made of
+     * backslashed paths (ie windows) as it is does not conform
+     * URI specifications.
+     * @param file the file to create the system id from.
+     * @return the systemid corresponding to the given file.
+     * @since Ant 1.5.2
+     */
+    public static String getSystemId(File file) {
+        return FILE_UTILS.toURI(file.getAbsolutePath());
+    }
+
+    /**
+     * Returns a newly created DocumentBuilder.
+     *
+     * @return a DocumentBuilder.
+     * @throws BuildException on error.
+     * @since Ant 1.6
+     */
+    public static DocumentBuilder getDocumentBuilder() throws BuildException {
+        try {
+            return getDocumentBuilderFactory().newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * @return a new SAXParser instance as helper for getParser and
+     * getXMLReader.
+     *
+     * @since Ant 1.5
+     */
+    private static SAXParser newSAXParser(SAXParserFactory factory)
+         throws BuildException {
+        try {
+            return factory.newSAXParser();
+        } catch (ParserConfigurationException e) {
+            throw new BuildException("Cannot create parser for the given "
+                                     + "configuration: " + e.getMessage(), e);
+        } catch (SAXException e) {
+            throw convertToBuildException(e);
+        }
+    }
+
+    /**
+     * Translate a SAXException into a BuildException
+     *
+     * @since Ant 1.5
+     */
+    private static BuildException convertToBuildException(SAXException e) {
+        Exception nested = e.getException();
+        if (nested != null) {
+            return new BuildException(nested);
+        } else {
+            return new BuildException(e);
+        }
+    }
+
+    /**
+     * Obtains the default builder factory if not already.
+     *
+     * @since Ant 1.6
+     */
+    private static synchronized
+        DocumentBuilderFactory getDocumentBuilderFactory()
+        throws BuildException {
+        if (builderFactory == null) {
+            try {
+                builderFactory = DocumentBuilderFactory.newInstance();
+            } catch (FactoryConfigurationError e) {
+                throw new BuildException("Document builder factory has not "
+                                         + "been configured correctly: "
+                                         + e.getMessage(), e);
+            }
+        }
+        return builderFactory;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/JavaEnvUtils.java b/trunk/src/main/org/apache/tools/ant/util/JavaEnvUtils.java
new file mode 100644
index 0000000..37ea257
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/JavaEnvUtils.java
@@ -0,0 +1,463 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+import java.util.Vector;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * A set of helper methods related to locating executables or checking
+ * conditons of a given Java installation.
+ *
+ * @since Ant 1.5
+ */
+public final class JavaEnvUtils {
+
+    private JavaEnvUtils() {
+    }
+
+    /** Are we on a DOS-based system */
+    private static final boolean IS_DOS = Os.isFamily("dos");
+    /** Are we on Novell NetWare */
+    private static final boolean IS_NETWARE = Os.isName("netware");
+    /** Are we on AIX */
+    private static final boolean IS_AIX = Os.isName("aix");
+
+    /** shortcut for System.getProperty("java.home") */
+    private static final String JAVA_HOME = System.getProperty("java.home");
+
+    /** FileUtils instance for path normalization */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /** Version of currently running VM. */
+    private static String javaVersion;
+
+    /** floating version of the JVM */
+    private static int javaVersionNumber;
+
+    /** Version constant for Java 1.0 */
+    public static final String JAVA_1_0 = "1.0";
+    /** Number Version constant for Java 1.0 */
+    public static final int VERSION_1_0 = 10;
+
+    /** Version constant for Java 1.1 */
+    public static final String JAVA_1_1 = "1.1";
+    /** Number Version constant for Java 1.1 */
+    public static final int VERSION_1_1 = 11;
+
+    /** Version constant for Java 1.2 */
+    public static final String JAVA_1_2 = "1.2";
+    /** Number Version constant for Java 1.2 */
+    public static final int VERSION_1_2 = 12;
+
+    /** Version constant for Java 1.3 */
+    public static final String JAVA_1_3 = "1.3";
+    /** Number Version constant for Java 1.3 */
+    public static final int VERSION_1_3 = 13;
+
+    /** Version constant for Java 1.4 */
+    public static final String JAVA_1_4 = "1.4";
+    /** Number Version constant for Java 1.4 */
+    public static final int VERSION_1_4 = 14;
+
+    /** Version constant for Java 1.5 */
+    public static final String JAVA_1_5 = "1.5";
+    /** Number Version constant for Java 1.5 */
+    public static final int VERSION_1_5 = 15;
+
+    /** Version constant for Java 1.6 */
+    public static final String JAVA_1_6 = "1.6";
+    /** Number Version constant for Java 1.6 */
+    public static final int VERSION_1_6 = 16;
+
+    /** Whether this is the Kaffe VM */
+    private static boolean kaffeDetected;
+
+    /** array of packages in the runtime */
+    private static Vector jrePackages;
+
+
+    static {
+
+        // Determine the Java version by looking at available classes
+        // java.net.Proxy was introduced in JDK 1.5
+        // java.lang.CharSequence was introduced in JDK 1.4
+        // java.lang.StrictMath was introduced in JDK 1.3
+        // java.lang.ThreadLocal was introduced in JDK 1.2
+        // java.lang.Void was introduced in JDK 1.1
+        // Count up version until a NoClassDefFoundError ends the try
+
+        try {
+            javaVersion = JAVA_1_0;
+            javaVersionNumber = VERSION_1_0;
+            Class.forName("java.lang.Void");
+            javaVersion = JAVA_1_1;
+            javaVersionNumber++;
+            Class.forName("java.lang.ThreadLocal");
+            javaVersion = JAVA_1_2;
+            javaVersionNumber++;
+            Class.forName("java.lang.StrictMath");
+            javaVersion = JAVA_1_3;
+            javaVersionNumber++;
+            Class.forName("java.lang.CharSequence");
+            javaVersion = JAVA_1_4;
+            javaVersionNumber++;
+            Class.forName("java.net.Proxy");
+            javaVersion = JAVA_1_5;
+            javaVersionNumber++;
+            Class.forName("java.util.ServiceLoader");
+            javaVersion = JAVA_1_6;
+            javaVersionNumber++;
+        } catch (Throwable t) {
+            // swallow as we've hit the max class version that
+            // we have
+        }
+        kaffeDetected = false;
+        try {
+            Class.forName("kaffe.util.NotImplemented");
+            kaffeDetected = true;
+        } catch (Throwable t) {
+            // swallow as this simply doesn't seem to be Kaffe
+        }
+    }
+
+    /**
+     * Returns the version of Java this class is running under.
+     * @return the version of Java as a String, e.g. "1.1"
+     */
+    public static String getJavaVersion() {
+        return javaVersion;
+    }
+
+
+    /**
+     * Returns the version of Java this class is running under.
+     * This number can be used for comparisions; it will always be
+     * @return the version of Java as a number 10x the major/minor,
+     * e.g Java1.5 has a value of 15
+     */
+    public static int getJavaVersionNumber() {
+        return javaVersionNumber;
+    }
+
+    /**
+     * Compares the current Java version to the passed in String -
+     * assumes the argument is one of the constants defined in this
+     * class.
+     * Note that Ant now requires JDK 1.2+ so {@link #JAVA_1_0} and
+     * {@link #JAVA_1_1} need no longer be tested for.
+     * @param version the version to check against the current version.
+     * @return true if the version of Java is the same as the given version.
+     * @since Ant 1.5
+     */
+    public static boolean isJavaVersion(String version) {
+        return javaVersion.equals(version);
+    }
+
+    /**
+     * Compares the current Java version to the passed in String -
+     * assumes the argument is one of the constants defined in this
+     * class.
+     * Note that Ant now requires JDK 1.2+ so {@link #JAVA_1_0} and
+     * {@link #JAVA_1_1} need no longer be tested for.
+     * @param version the version to check against the current version.
+     * @return true if the version of Java is the same or higher than the
+     * given version.
+     * @since Ant 1.7
+     */
+    public static boolean isAtLeastJavaVersion(String version) {
+        return javaVersion.compareTo(version) >= 0;
+    }
+
+    /**
+     * Checks whether the current Java VM is Kaffe.
+     * @return true if the current Java VM is Kaffe.
+     * @since Ant 1.6.3
+     * @see <a href="http://www.kaffe.org/">http://www.kaffe.org/</a>
+     */
+    public static boolean isKaffe() {
+        return kaffeDetected;
+    }
+
+    /**
+     * Finds an executable that is part of a JRE installation based on
+     * the java.home system property.
+     *
+     * <p><code>java</code>, <code>keytool</code>,
+     * <code>policytool</code>, <code>orbd</code>, <code>rmid</code>,
+     * <code>rmiregistry</code>, <code>servertool</code> and
+     * <code>tnameserv</code> are JRE executables on Sun based
+     * JRE's.</p>
+     *
+     * <p>You typically find them in <code>JAVA_HOME/jre/bin</code> if
+     * <code>JAVA_HOME</code> points to your JDK installation.  JDK
+     * &lt; 1.2 has them in the same directory as the JDK
+     * executables.</p>
+     * @param command the java executable to find.
+     * @return the path to the command.
+     * @since Ant 1.5
+     */
+    public static String getJreExecutable(String command) {
+        if (IS_NETWARE) {
+            // Extrapolating from:
+            // "NetWare may have a "java" in that directory, but 99% of
+            // the time, you don't want to execute it" -- Jeff Tulley
+            // <JTULLEY@novell.com>
+            return command;
+        }
+
+        File jExecutable = null;
+
+        if (IS_AIX) {
+            // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
+            // Sun's layout.
+            jExecutable = findInDir(JAVA_HOME + "/sh", command);
+        }
+
+        if (jExecutable == null) {
+            jExecutable = findInDir(JAVA_HOME + "/bin", command);
+        }
+
+        if (jExecutable != null) {
+            return jExecutable.getAbsolutePath();
+        } else {
+            // Unfortunately on Windows java.home doesn't always refer
+            // to the correct location, so we need to fall back to
+            // assuming java is somewhere on the PATH.
+            return addExtension(command);
+        }
+    }
+
+    /**
+     * Finds an executable that is part of a JDK installation based on
+     * the java.home system property.
+     *
+     * <p>You typically find them in <code>JAVA_HOME/bin</code> if
+     * <code>JAVA_HOME</code> points to your JDK installation.</p>
+     * @param command the java executable to find.
+     * @return the path to the command.
+     * @since Ant 1.5
+     */
+    public static String getJdkExecutable(String command) {
+        if (IS_NETWARE) {
+            // Extrapolating from:
+            // "NetWare may have a "java" in that directory, but 99% of
+            // the time, you don't want to execute it" -- Jeff Tulley
+            // <JTULLEY@novell.com>
+            return command;
+        }
+
+        File jExecutable = null;
+
+        if (IS_AIX) {
+            // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
+            // Sun's layout.
+            jExecutable = findInDir(JAVA_HOME + "/../sh", command);
+        }
+
+        if (jExecutable == null) {
+            jExecutable = findInDir(JAVA_HOME + "/../bin", command);
+        }
+
+        if (jExecutable != null) {
+            return jExecutable.getAbsolutePath();
+        } else {
+            // fall back to JRE bin directory, also catches JDK 1.0 and 1.1
+            // where java.home points to the root of the JDK and Mac OS X where
+            // the whole directory layout is different from Sun's
+            return getJreExecutable(command);
+        }
+    }
+
+    /**
+     * Adds a system specific extension to the name of an executable.
+     *
+     * @since Ant 1.5
+     */
+    private static String addExtension(String command) {
+        // This is the most common extension case - exe for windows and OS/2,
+        // nothing for *nix.
+        return command + (IS_DOS ? ".exe" : "");
+    }
+
+    /**
+     * Look for an executable in a given directory.
+     *
+     * @return null if the executable cannot be found.
+     */
+    private static File findInDir(String dirName, String commandName) {
+        File dir = FILE_UTILS.normalize(dirName);
+        File executable = null;
+        if (dir.exists()) {
+            executable = new File(dir, addExtension(commandName));
+            if (!executable.exists()) {
+                executable = null;
+            }
+        }
+        return executable;
+    }
+
+    /**
+     * demand creation of the package list.
+     * When you add a new package, add a new test below.
+     */
+
+    private static void buildJrePackages() {
+        jrePackages = new Vector();
+        switch(javaVersionNumber) {
+            case VERSION_1_6:
+            case VERSION_1_5:
+                //In Java1.5, the apache stuff moved.
+                jrePackages.addElement("com.sun.org.apache");
+                //fall through.
+            case VERSION_1_4:
+                if (javaVersionNumber == VERSION_1_4) {
+                    jrePackages.addElement("org.apache.crimson");
+                    jrePackages.addElement("org.apache.xalan");
+                    jrePackages.addElement("org.apache.xml");
+                    jrePackages.addElement("org.apache.xpath");
+                }
+                jrePackages.addElement("org.ietf.jgss");
+                jrePackages.addElement("org.w3c.dom");
+                jrePackages.addElement("org.xml.sax");
+                // fall through
+            case VERSION_1_3:
+                jrePackages.addElement("org.omg");
+                jrePackages.addElement("com.sun.corba");
+                jrePackages.addElement("com.sun.jndi");
+                jrePackages.addElement("com.sun.media");
+                jrePackages.addElement("com.sun.naming");
+                jrePackages.addElement("com.sun.org.omg");
+                jrePackages.addElement("com.sun.rmi");
+                jrePackages.addElement("sunw.io");
+                jrePackages.addElement("sunw.util");
+                // fall through
+            case VERSION_1_2:
+                jrePackages.addElement("com.sun.java");
+                jrePackages.addElement("com.sun.image");
+                // are there any here that we forgot?
+                // fall through
+            case VERSION_1_1:
+            default:
+                //things like sun.reflection, sun.misc, sun.net
+                jrePackages.addElement("sun");
+                jrePackages.addElement("java");
+                jrePackages.addElement("javax");
+                break;
+        }
+    }
+
+    /**
+     * Testing helper method; kept here for unification of changes.
+     * @return a list of test classes depending on the java version.
+     */
+    public static Vector getJrePackageTestCases() {
+        Vector tests = new Vector();
+        tests.addElement("java.lang.Object");
+        switch(javaVersionNumber) {
+            case VERSION_1_6:
+            case VERSION_1_5:
+                tests.addElement(
+                    "com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl ");
+                // Fall tru
+            case VERSION_1_4:
+                tests.addElement("sun.audio.AudioPlayer");
+                if (javaVersionNumber == VERSION_1_4) {
+                    tests.addElement("org.apache.crimson.parser.ContentModel");
+                    tests.addElement("org.apache.xalan.processor.ProcessorImport");
+                    tests.addElement("org.apache.xml.utils.URI");
+                    tests.addElement("org.apache.xpath.XPathFactory");
+                }
+                tests.addElement("org.ietf.jgss.Oid");
+                tests.addElement("org.w3c.dom.Attr");
+                tests.addElement("org.xml.sax.XMLReader");
+                // fall through
+            case VERSION_1_3:
+                tests.addElement("org.omg.CORBA.Any");
+                tests.addElement("com.sun.corba.se.internal.corba.AnyImpl");
+                tests.addElement("com.sun.jndi.ldap.LdapURL");
+                tests.addElement("com.sun.media.sound.Printer");
+                tests.addElement("com.sun.naming.internal.VersionHelper");
+                tests.addElement("com.sun.org.omg.CORBA.Initializer");
+                tests.addElement("sunw.io.Serializable");
+                tests.addElement("sunw.util.EventListener");
+                // fall through
+            case VERSION_1_2:
+                tests.addElement("javax.accessibility.Accessible");
+                tests.addElement("sun.misc.BASE64Encoder");
+                tests.addElement("com.sun.image.codec.jpeg.JPEGCodec");
+                // fall through
+            case VERSION_1_1:
+            default:
+                //things like sun.reflection, sun.misc, sun.net
+                tests.addElement("sun.reflect.SerializationConstructorAccessorImpl");
+                tests.addElement("sun.net.www.http.HttpClient");
+                tests.addElement("sun.audio.AudioPlayer");
+                break;
+        }
+        return tests;
+    }
+    /**
+     * get a vector of strings of packages built into
+     * that platforms runtime jar(s)
+     * @return list of packages.
+     */
+    public static Vector getJrePackages() {
+        if (jrePackages == null) {
+            buildJrePackages();
+        }
+        return jrePackages;
+    }
+
+    /**
+     *
+     * Writes the command into a temporary DCL script and returns the
+     * corresponding File object.
+     * It is the job of the caller to delete the file on exit.
+     * @param cmd the command.
+     * @return the file containing the command.
+     * @throws IOException if there is an error writing to the file.
+     */
+    public static File createVmsJavaOptionFile(String[] cmd)
+            throws IOException {
+        File script = FILE_UTILS.createTempFile("ANT", ".JAVA_OPTS", null, false, true);
+        PrintWriter out = null;
+        try {
+            out = new PrintWriter(new BufferedWriter(new FileWriter(script)));
+            for (int i = 0; i < cmd.length; i++) {
+                out.println(cmd[i]);
+            }
+        } finally {
+            FileUtils.close(out);
+        }
+        return script;
+    }
+
+    /**
+     * Return the value of ${java.home}
+     * @return the java home value.
+     */
+    public static String getJavaHome() {
+        return JAVA_HOME;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java b/trunk/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java
new file mode 100644
index 0000000..cc79d67
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class that can be used to wrap <tt>System.in</tt>
+ * without getting anxious about any client closing the stream.
+ *
+ * <p>
+ * In code-language it means that it is not necessary to do:
+ * <pre>
+ * if (out != System.in) {
+ *   in.close();
+ * }
+ * </pre>
+ * </p>
+ *
+ * @since Ant 1.6
+ */
+public class KeepAliveInputStream extends FilterInputStream {
+
+    /**
+     * Constructor of KeepAliveInputStream.
+     *
+     * @param in an InputStream value, it should be standard input.
+     */
+    public KeepAliveInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * This method does nothing.
+     * @throws IOException as we are overridding FilterInputStream.
+     */
+    public void close() throws IOException {
+        // do not close the stream
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java b/trunk/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java
new file mode 100644
index 0000000..0437a1f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Class that can be used to wrap <tt>System.out</tt> and <tt>System.err</tt>
+ * without getting anxious about any client closing the stream.
+ *
+ * <p>
+ * In code-language it means that it is not necessary to do:
+ * <pre>
+ * if (out != System.out && out!= System.err) {
+ *   out.close();
+ * }
+ * </pre>
+ * </p>
+ *
+ */
+public class KeepAliveOutputStream extends FilterOutputStream {
+
+    /**
+     * Constructor of KeepAliveOutputStream.
+     *
+     * @param out an OutputStream value, it shoudl be standard output.
+     */
+    public KeepAliveOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    /**
+     * This method does nothing.
+     * @throws IOException as we are overridding FilterOutputStream.
+     */
+    public void close() throws IOException {
+        // do not close the stream
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java b/trunk/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java
new file mode 100644
index 0000000..7d289b9
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java
@@ -0,0 +1,162 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Class that delays opening the output file until the first bytes
+ * shall be written or the method {@link #open open} has been invoked
+ * explicitly.
+ *
+ * @since Ant 1.6
+ */
+public class LazyFileOutputStream extends OutputStream {
+
+    private FileOutputStream fos;
+    private File file;
+    private boolean append;
+    private boolean alwaysCreate;
+    private boolean opened = false;
+    private boolean closed = false;
+
+    /**
+     * Creates a stream that will eventually write to the file with
+     * the given name and replace it.
+     * @param name the filename.
+     */
+    public LazyFileOutputStream(String name) {
+        this(name, false);
+    }
+
+    /**
+     * Creates a stream that will eventually write to the file with
+     * the given name and optionally append to instead of replacing
+     * it.
+     * @param name the filename.
+     * @param append if true append rather than replace.
+     */
+    public LazyFileOutputStream(String name, boolean append) {
+        this(new File(name), append);
+    }
+
+    /**
+     * Creates a stream that will eventually write to the file with
+     * the given name and replace it.
+     * @param f the file to create.
+     */
+    public LazyFileOutputStream(File f) {
+        this(f, false);
+    }
+
+    /**
+     * Creates a stream that will eventually write to the file with
+     * the given name and optionally append to instead of replacing
+     * it.
+     * @param file the file to create.
+     * @param append if true append rather than replace.
+     */
+    public LazyFileOutputStream(File file, boolean append) {
+        this(file, append, false);
+    }
+
+    /**
+     * Creates a stream that will eventually write to the file with
+     * the given name, optionally append to instead of replacing
+     * it, and optionally always create a file (even if zero length).
+     * @param file the file to create.
+     * @param append if true append rather than replace.
+     * @param alwaysCreate if true create the file even if nothing to write.
+     */
+    public LazyFileOutputStream(File file, boolean append,
+                                boolean alwaysCreate) {
+        this.file = file;
+        this.append = append;
+        this.alwaysCreate = alwaysCreate;
+    }
+
+    /**
+     * Explicitly open the file for writing.
+     *
+     * <p>Returns silently if the file has already been opened.</p>
+     * @throws IOException if there is an error.
+     */
+    public void open() throws IOException {
+        ensureOpened();
+    }
+
+    /**
+     * Close the file.
+     * @throws IOException if there is an error.
+     */
+    public synchronized void close() throws IOException {
+        if (alwaysCreate && !closed) {
+            ensureOpened();
+        }
+        if (opened) {
+            fos.close();
+        }
+        closed = true;
+    }
+
+    /**
+     * Delegates to the three-arg version.
+     * @param b the bytearray to write.
+     * @throws IOException if there is a problem.
+     */
+    public void write(byte[] b) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Write part of a byte array.
+     * @param b the byte array.
+     * @param offset write from this index.
+     * @param len    the number of bytes to write.
+     * @throws IOException if there is a probem.
+     */
+    public synchronized void write(byte[] b, int offset, int len)
+        throws IOException {
+        ensureOpened();
+        fos.write(b, offset, len);
+    }
+
+    /**
+     * Write a byte.
+     * @param b the byte to write.
+     * @throws IOException if there is a problem.
+     */
+    public synchronized void write(int b) throws IOException {
+        ensureOpened();
+        fos.write(b);
+    }
+
+    private synchronized void ensureOpened() throws IOException {
+        if (closed) {
+            throw new IOException(file + " has already been closed.");
+        }
+
+        if (!opened) {
+            fos = new FileOutputStream(file.getAbsolutePath(), append);
+            opened = true;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/LazyHashtable.java b/trunk/src/main/org/apache/tools/ant/util/LazyHashtable.java
new file mode 100644
index 0000000..98faf93
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LazyHashtable.java
@@ -0,0 +1,120 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Hashtable;
+import java.util.Enumeration;
+
+/** Hashtable implementation that allows delayed construction
+ * of expensive objects
+ *
+ * All operations that need access to the full list of objects
+ * will call initAll() first. Get and put are cheap.
+ *
+ * @since Ant 1.6
+ */
+public class LazyHashtable extends Hashtable {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean initAllDone = false;
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /** No arg constructor. */
+    public LazyHashtable() {
+        super();
+    }
+
+    /** Used to be part of init. It must be done once - but
+     * we delay it until we do need _all_ tasks. Otherwise we
+     * just get the tasks that we need, and avoid costly init.
+     */
+    protected void initAll() {
+        if (initAllDone) {
+            return;
+        }
+        initAllDone = true;
+    }
+
+
+    /**
+     * Get a enumeration over the elements.
+     * @return an enumeration.
+     */
+    public Enumeration elements() {
+        initAll();
+        return super.elements();
+    }
+
+    /**
+     * Check if the table is empty.
+     * @return true if it is.
+     */
+    public boolean isEmpty() {
+        initAll();
+        return super.isEmpty();
+    }
+
+    /**
+     * Get the size of the table.
+     * @return the size.
+     */
+    public int size() {
+        initAll();
+        return super.size();
+    }
+
+    /**
+     * Check if the table contains a particular value.
+     * @param value the value to look for.
+     * @return true if the table contains the value.
+     */
+    public boolean contains(Object value) {
+        initAll();
+        return super.contains(value);
+    }
+
+    /**
+     * Check if the table contains a particular key.
+     * @param value the key to look for.
+     * @return true if the table contains key.
+     */
+    public boolean containsKey(Object value) {
+        initAll();
+        return super.containsKey(value);
+    }
+
+    /**
+     * Delegates to {@link #contains contains}.
+     * @param value the value to look for.
+     * @return true if the table contains the value.
+     */
+    public boolean containsValue(Object value) {
+        return contains(value);
+    }
+
+    /**
+     * Get an enumeration over the keys.
+     * @return an enumeration.
+     */
+    public Enumeration keys() {
+        initAll();
+        return super.keys();
+    }
+
+    // XXX Unfortunately JDK1.2 adds entrySet(), keySet(), values() -
+    // implementing this requires a small hack, we can add it later.
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java b/trunk/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
new file mode 100755
index 0000000..7688e1a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
@@ -0,0 +1,159 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+
+/**
+ * Special <code>PipedInputStream</code> that will not die
+ * when the writing <code>Thread</code> is no longer alive.
+ * @since Ant 1.6.2
+ */
+public class LeadPipeInputStream extends PipedInputStream {
+    private static final int BYTE_MASK = 0xFF;
+    private ProjectComponent managingPc;
+
+    /**
+     * Construct a new <code>LeadPipeInputStream</code>.
+     */
+    public LeadPipeInputStream() {
+        super();
+    }
+
+    /**
+     * Construct a new <code>LeadPipeInputStream</code>
+     * with the specified buffer size.
+     * @param size   the size of the circular buffer.
+     */
+    public LeadPipeInputStream(int size) {
+        super();
+        setBufferSize(size);
+    }
+
+    /**
+     * Construct a new <code>LeadPipeInputStream</code> to pull
+     * from the specified <code>PipedOutputStream</code>.
+     * @param src   the <code>PipedOutputStream</code> source.
+     * @throws IOException if unable to construct the stream.
+     */
+    public LeadPipeInputStream(PipedOutputStream src) throws IOException {
+        super(src);
+    }
+
+    /**
+     * Construct a new <code>LeadPipeInputStream</code> to pull
+     * from the specified <code>PipedOutputStream</code>, using a
+     * circular buffer of the specified size.
+     * @param src    the <code>PipedOutputStream</code> source.
+     * @param size   the size of the circular buffer.
+     * @throws IOException if there is an error.
+     */
+    public LeadPipeInputStream(PipedOutputStream src, int size) throws IOException {
+        super(src);
+        setBufferSize(size);
+    }
+
+    //inherit doc
+    /**
+     * Read a byte from the stream.
+     * @return the byte (0 to 255) or -1 if there are no more.
+     * @throws IOException if there is an error.
+     */
+    public synchronized int read() throws IOException {
+        int result = -1;
+        try {
+            result = super.read();
+        } catch (IOException eyeOhEx) {
+            if ("write end dead".equalsIgnoreCase(eyeOhEx.getMessage())) {
+                if (super.in > 0 && super.out < super.buffer.length
+                    && super.out > super.in) {
+                    result = super.buffer[super.out++] & BYTE_MASK;
+                }
+            } else {
+                log("error at LeadPipeInputStream.read():  "
+                    + eyeOhEx.getMessage(), Project.MSG_INFO);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Set the size of the buffer.
+     * @param size   the new buffer size.  Ignored if <= current size.
+     */
+    public synchronized void setBufferSize(int size) {
+        if (size > buffer.length) {
+            byte[] newBuffer = new byte[size];
+            if (in >= 0) {
+                if (in > out) {
+                    System.arraycopy(buffer, out, newBuffer, out, in - out);
+                } else {
+                    int outlen = buffer.length - out;
+                    System.arraycopy(buffer, out, newBuffer, 0, outlen);
+                    System.arraycopy(buffer, 0, newBuffer, outlen, in);
+                    in += outlen;
+                    out = 0;
+                }
+            }
+            buffer = newBuffer;
+        }
+    }
+
+    /**
+     * Set a managing <code>Task</code> for
+     * this <code>LeadPipeInputStream</code>.
+     * @param task   the managing <code>Task</code>.
+     */
+    public void setManagingTask(Task task) {
+        setManagingComponent(task);
+    }
+
+    /**
+     * Set a managing <code>ProjectComponent</code> for
+     * this <code>LeadPipeInputStream</code>.
+     * @param pc   the managing <code>ProjectComponent</code>.
+     */
+    public void setManagingComponent(ProjectComponent pc) {
+        this.managingPc = pc;
+    }
+
+    /**
+     * Log a message with the specified logging level.
+     * @param message    the <code>String</code> message.
+     * @param loglevel   the <code>int</code> logging level.
+     */
+    public void log(String message, int loglevel) {
+        if (managingPc != null) {
+            managingPc.log(message, loglevel);
+        } else {
+            if (loglevel > Project.MSG_WARN) {
+                System.out.println(message);
+            } else {
+                System.err.println(message);
+            }
+        }
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java b/trunk/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java
new file mode 100644
index 0000000..30e5d88
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Invokes {@link #processLine processLine} whenever a full line has
+ * been written to this stream.
+ *
+ * <p>Tries to be smart about line separators.</p>
+ */
+public abstract class LineOrientedOutputStream extends OutputStream {
+
+    /** Initial buffer size. */
+    private static final int INTIAL_SIZE = 132;
+
+    /** Carriage return */
+    private static final int CR = 0x0d;
+
+    /** Linefeed */
+    private static final int LF = 0x0a;
+
+    private ByteArrayOutputStream buffer
+        = new ByteArrayOutputStream(INTIAL_SIZE);
+    private boolean skip = false;
+
+    /**
+     * Write the data to the buffer and flush the buffer, if a line
+     * separator is detected.
+     *
+     * @param cc data to log (byte).
+     * @throws IOException if there is an error.
+     */
+    public final void write(int cc) throws IOException {
+        final byte c = (byte) cc;
+        if ((c == LF) || (c == CR)) {
+            if (!skip) {
+              processBuffer();
+            }
+        } else {
+            buffer.write(cc);
+        }
+        skip = (c == CR);
+    }
+
+    /**
+     * Flush this log stream
+     * @throws IOException if there is an error.
+     */
+    public final void flush() throws IOException {
+        if (buffer.size() > 0) {
+            processBuffer();
+        }
+    }
+
+    /**
+     * Converts the buffer to a string and sends it to
+     * <code>processLine</code>
+     * @throws IOException if there is an error.
+     */
+    protected void processBuffer() throws IOException {
+        try {
+            processLine(buffer.toString());
+        } finally {
+            buffer.reset();
+        }
+    }
+
+    /**
+     * Processes a line.
+     *
+     * @param line the line to log.
+     * @throws IOException if there is an error.
+     */
+    protected abstract void processLine(String line) throws IOException;
+
+    /**
+     * Writes all remaining
+     * @throws IOException if there is an error.
+     */
+    public final void close() throws IOException {
+        if (buffer.size() > 0) {
+            processBuffer();
+        }
+        super.close();
+    }
+
+    /**
+     * Write a block of characters to the output stream
+     *
+     * @param b the array containing the data
+     * @param off the offset into the array where data starts
+     * @param len the length of block
+     *
+     * @throws IOException if the data cannot be written into the stream.
+     */
+    public final void write(byte[] b, int off, int len) throws IOException {
+        // find the line breaks and pass other chars through in blocks
+        int offset = off;
+        int blockStartOffset = offset;
+        int remaining = len;
+        while (remaining > 0) {
+            while (remaining > 0 && b[offset] != LF && b[offset] != CR) {
+                offset++;
+                remaining--;
+            }
+            // either end of buffer or a line separator char
+            int blockLength = offset - blockStartOffset;
+            if (blockLength > 0) {
+                buffer.write(b, blockStartOffset, blockLength);
+            }
+            while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) {
+                write(b[offset]);
+                offset++;
+                remaining--;
+            }
+            blockStartOffset = offset;
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/LineTokenizer.java b/trunk/src/main/org/apache/tools/ant/util/LineTokenizer.java
new file mode 100644
index 0000000..21bfb02
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LineTokenizer.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.Reader;
+import java.io.IOException;
+
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * class to tokenize the input as lines seperated
+ * by \r (mac style), \r\n (dos/windows style) or \n (unix style)
+ * @since Ant 1.6
+ */
+public class LineTokenizer extends ProjectComponent
+    implements Tokenizer {
+    private static final int NOT_A_CHAR = -2;
+    private String  lineEnd = "";
+    private int     pushed = NOT_A_CHAR;
+    private boolean includeDelims = false;
+
+    /**
+     * attribute includedelims - whether to include
+     * the line ending with the line, or to return
+     * it in the posttoken
+     * default false
+     * @param includeDelims if true include /r and /n in the line
+     */
+
+    public void setIncludeDelims(boolean includeDelims) {
+        this.includeDelims = includeDelims;
+    }
+
+    /**
+     * get the next line from the input
+     *
+     * @param in the input reader
+     * @return the line excluding /r or /n, unless includedelims is set
+     * @exception IOException if an error occurs reading
+     */
+    public String getToken(Reader in) throws IOException {
+        int ch = -1;
+        if (pushed != NOT_A_CHAR) {
+            ch = pushed;
+            pushed = NOT_A_CHAR;
+        } else {
+            ch = in.read();
+        }
+        if (ch == -1) {
+            return null;
+        }
+
+        lineEnd = "";
+        StringBuffer line = new StringBuffer();
+
+        int state = 0;
+        while (ch != -1) {
+            if (state == 0) {
+                if (ch == '\r') {
+                    state = 1;
+                } else if (ch == '\n') {
+                    lineEnd = "\n";
+                    break;
+                } else {
+                    line.append((char) ch);
+                }
+            } else {
+                state = 0;
+                if (ch == '\n') {
+                    lineEnd = "\r\n";
+                } else {
+                    pushed = ch;
+                    lineEnd = "\r";
+                }
+                break;
+            }
+            ch = in.read();
+        }
+        if (ch == -1 && state == 1) {
+            lineEnd = "\r";
+        }
+
+        if (includeDelims) {
+            line.append(lineEnd);
+        }
+        return line.toString();
+    }
+
+    /**
+     * @return the line ending character(s) for the current line
+     */
+    public String getPostToken() {
+        if (includeDelims) {
+            return "";
+        }
+        return lineEnd;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/LoaderUtils.java b/trunk/src/main/org/apache/tools/ant/util/LoaderUtils.java
new file mode 100644
index 0000000..6744cc7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/LoaderUtils.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.launch.Locator;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * ClassLoader utility methods
+ *
+ */
+public class LoaderUtils {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Set the context classloader
+     *
+     * @param loader the ClassLoader to be used as the context class loader
+     *      on the current thread.
+     */
+    public static void setContextClassLoader(ClassLoader loader) {
+        Thread currentThread = Thread.currentThread();
+        currentThread.setContextClassLoader(loader);
+    }
+
+
+    /**
+     * JDK1.1 compatible access to set the context class loader.
+     *
+     * @return the ClassLoader instance being used as the context
+     *      classloader on the current thread. Returns null on JDK 1.1
+     */
+    public static ClassLoader getContextClassLoader() {
+        Thread currentThread = Thread.currentThread();
+        return currentThread.getContextClassLoader();
+    }
+
+    /**
+     * Indicates if the context class loader methods are available
+     *
+     * @return true if the get and set methods dealing with the context
+     *      classloader are available.
+     */
+    public static boolean isContextLoaderAvailable() {
+        return true;
+    }
+
+    /**
+     * Normalize a source location
+     *
+     * @param source the source location to be normalized.
+     *
+     * @return the normalized source location.
+     */
+    private static File normalizeSource(File source) {
+        if (source != null) {
+            try {
+                source = FILE_UTILS.normalize(source.getAbsolutePath());
+            } catch (BuildException e) {
+                // relative path
+            }
+        }
+
+        return source;
+    }
+
+    /**
+     * Find the directory or jar file the class has been loaded from.
+     *
+     * @param c the class whose location is required.
+     * @return the file or jar with the class or null if we cannot
+     *         determine the location.
+     *
+     * @since Ant 1.6
+     */
+    public static File getClassSource(Class c) {
+        return normalizeSource(Locator.getClassSource(c));
+    }
+
+    /**
+     * Find the directory or a give resource has been loaded from.
+     *
+     * @param c the classloader to be consulted for the source
+     * @param resource the resource whose location is required.
+     *
+     * @return the file with the resource source or null if
+     *         we cannot determine the location.
+     *
+     * @since Ant 1.6
+     */
+    public static File getResourceSource(ClassLoader c, String resource) {
+        if (c == null) {
+            c = LoaderUtils.class.getClassLoader();
+        }
+        return normalizeSource(Locator.getResourceSource(c, resource));
+    }
+
+    /**
+     * Return the resource name of a class name.
+     * @param className the name of the class to convert.
+     * @return the corresponding resource name.
+     * @since Ant 1.7.0.
+     */
+    public static String classNameToResource(String className) {
+        return className.replace('.', '/') + ".class";
+    }
+
+    /**
+     * Check if a classloader has a classname resource.
+     * @param loader the classloader to look it.
+     * @param className the name of the class to look for.
+     * @return true if the classexists, false otherwise
+     * @since Ant 1.7.0.
+     */
+    public static boolean classExists(ClassLoader loader, String className) {
+        return loader.getResource(classNameToResource(className)) != null;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/MergingMapper.java b/trunk/src/main/org/apache/tools/ant/util/MergingMapper.java
new file mode 100644
index 0000000..7616526
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/MergingMapper.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the same
+ * target file name.
+ *
+ * <p>This is the default FileNameMapper for the archiving tasks and
+ * uptodate.</p>
+ *
+ */
+public class MergingMapper implements FileNameMapper {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected String[] mergedFile = null;
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Ignored.
+     * @param from ignored.
+     */
+    public void setFrom(String from) {
+    }
+
+    /**
+     * Sets the name of the merged file.
+     * @param to the name of the merged file.
+     */
+    public void setTo(String to) {
+        mergedFile = new String[] {to};
+    }
+
+    /**
+     * Returns an one-element array containing the file name set via setTo.
+     * @param sourceFileName ignored.
+     * @return a one-element array containing the merged filename.
+     */
+    public String[] mapFileName(String sourceFileName) {
+        return mergedFile;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java b/trunk/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java
new file mode 100755
index 0000000..6694c3f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Manages a set of <code>OutputStream</code>s to
+ * write to a single underlying stream, which is
+ * closed only when the last &quot;funnel&quot;
+ * has been closed.
+ */
+public class OutputStreamFunneler {
+
+    /**
+     * Default timeout.
+     * @see #setTimeout(long)
+     */
+    public static final long DEFAULT_TIMEOUT_MILLIS = 1000;
+
+    private final class Funnel extends OutputStream {
+        private boolean closed = false;
+
+        private Funnel() {
+            synchronized (OutputStreamFunneler.this) {
+                ++count;
+            }
+        }
+
+        public void flush() throws IOException {
+            synchronized (OutputStreamFunneler.this) {
+                dieIfClosed();
+                out.flush();
+            }
+        }
+
+        public void write(int b) throws IOException {
+            synchronized (OutputStreamFunneler.this) {
+                dieIfClosed();
+                out.write(b);
+            }
+        }
+
+        public void write(byte[] b) throws IOException {
+            synchronized (OutputStreamFunneler.this) {
+                dieIfClosed();
+                out.write(b);
+            }
+        }
+
+        public void write(byte[] b, int off, int len) throws IOException {
+            synchronized (OutputStreamFunneler.this) {
+                dieIfClosed();
+                out.write(b, off, len);
+            }
+        }
+
+        public void close() throws IOException {
+            release(this);
+        }
+    }
+
+    private OutputStream out;
+    private int count = 0;
+    private boolean closed;
+    private long timeoutMillis;
+
+    /**
+     * Create a new <code>OutputStreamFunneler</code> for
+     * the specified <code>OutputStream</code>.
+     * @param out   <code>OutputStream</code>.
+     */
+    public OutputStreamFunneler(OutputStream out) {
+        this(out, DEFAULT_TIMEOUT_MILLIS);
+    }
+
+    /**
+     * Create a new <code>OutputStreamFunneler</code> for
+     * the specified <code>OutputStream</code>, with the
+     * specified timeout value.
+     * @param out             <code>OutputStream</code>.
+     * @param timeoutMillis   <code>long</code>.
+     * @see #setTimeout(long)
+     */
+    public OutputStreamFunneler(OutputStream out, long timeoutMillis) {
+        if (out == null) {
+            throw new IllegalArgumentException(
+                "OutputStreamFunneler.<init>:  out == null");
+        }
+        this.out = out;
+        this.closed = false; //as far as we know
+        setTimeout(timeoutMillis);
+    }
+
+    /**
+     * Set the timeout for this <code>OutputStreamFunneler</code>.
+     * This is the maximum time that may elapse between the closure
+     * of the last &quot;funnel&quot; and the next call to
+     * <code>getOutputStream()</code> without closing the
+     * underlying stream.
+     * @param timeoutMillis   <code>long</code> timeout value.
+     */
+    public synchronized void setTimeout(long timeoutMillis) {
+        this.timeoutMillis = timeoutMillis;
+    }
+
+    /**
+     * Get a &quot;funnel&quot; <code>OutputStream</code> instance to
+     * write to this <code>OutputStreamFunneler</code>'s underlying
+     * <code>OutputStream</code>.
+     * @return <code>OutputStream</code>.
+     * @throws IOException if unable to create the funnel.
+     */
+    public synchronized OutputStream getFunnelInstance()
+        throws IOException {
+        dieIfClosed();
+        try {
+            return new Funnel();
+        } finally {
+            notifyAll();
+        }
+    }
+
+    private synchronized void release(Funnel funnel) throws IOException {
+        //ignore release of an already-closed funnel
+        if (!funnel.closed) {
+            try {
+                if (timeoutMillis > 0) {
+                    try {
+                        wait(timeoutMillis);
+                    } catch (InterruptedException eyeEx) {
+                        //ignore
+                    }
+                }
+                if (--count == 0) {
+                    close();
+                }
+            } finally {
+                funnel.closed = true;
+            }
+        }
+   }
+
+    private synchronized void close() throws IOException {
+        try {
+            dieIfClosed();
+            out.close();
+        } finally {
+            closed = true;
+        }
+    }
+
+    private synchronized void dieIfClosed() throws IOException {
+        if (closed) {
+            throw new IOException("The funneled OutputStream has been closed.");
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/PackageNameMapper.java b/trunk/src/main/org/apache/tools/ant/util/PackageNameMapper.java
new file mode 100644
index 0000000..bd33448
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/PackageNameMapper.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+
+/**
+ * Maps directory name matches into a dotted package name. This is
+ * useful for matching JUnit test cases againt their XML formatter
+ * results.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.PackageNameMapper"
+ *         from="*Test.java" to="${test.data.dir}/TEST-*Test.xml"/&gt;
+ * </pre>
+ *
+ */
+public class PackageNameMapper extends GlobPatternMapper {
+    /**
+     *  Returns the part of the given string that matches the * in the
+     *  &quot;from&quot; pattern replacing file separators with dots
+     *
+     *@param  name  Source filename
+     *@return       Replaced variable part
+     */
+    protected String extractVariablePart(String name) {
+        String var = name.substring(prefixLength,
+                name.length() - postfixLength);
+        return var.replace(File.separatorChar, '.');
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/PropertyOutputStream.java b/trunk/src/main/org/apache/tools/ant/util/PropertyOutputStream.java
new file mode 100755
index 0000000..59a1b7e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/PropertyOutputStream.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.ByteArrayOutputStream;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * Exception thrown when an attempt is made to get an OutputStream
+ * from an immutable Resource.
+ * @since Ant 1.7
+ */
+public class PropertyOutputStream extends ByteArrayOutputStream {
+    private Project project;
+    private String property;
+    private boolean trim;
+
+    /**
+     * Construct a new PropertyOutputStream for the specified Project
+     * and property name, trimming the property value.
+     * @param p the associated Ant Project.
+     * @param s the String property name.
+     */
+    public PropertyOutputStream(Project p, String s) {
+        this(p, s, true);
+    }
+
+    /**
+     * Construct a new PropertyOutputStream for
+     * the specified Project, property name, and trim mode.
+     * @param p the associated Ant Project.
+     * @param s the String property name.
+     * @param b the boolean trim mode.
+     */
+    public PropertyOutputStream(Project p, String s, boolean b) {
+        project = p;
+        property = s;
+        trim = b;
+    }
+
+    /**
+     * Close the PropertyOutputStream, storing the property.
+     */
+    public void close() {
+        if (project != null && property != null) {
+            String s = new String(toByteArray());
+            project.setNewProperty(property, trim ? s.trim() : s);
+        }
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/ProxySetup.java b/trunk/src/main/org/apache/tools/ant/util/ProxySetup.java
new file mode 100644
index 0000000..5be1e27
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ProxySetup.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * Code to do proxy setup. This is just factored out of the main system just to
+ * keep everything else less convoluted.
+ * @since Ant1.7
+ */
+
+public class ProxySetup {
+
+    /**
+     * owner project; used for logging and extracting properties
+     */
+    private Project owner;
+
+    /**
+     * Java1.5 property that enables use of system proxies.
+     * @value
+     */
+    public static final String USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
+    /** the http proxyhost property */
+    public static final String HTTP_PROXY_HOST = "http.proxyHost";
+    /** the http proxyport property */
+    public static final String HTTP_PROXY_PORT = "http.proxyPort";
+    /** the https proxyhost property */
+    public static final String HTTPS_PROXY_HOST = "https.proxyHost";
+    /** the https proxyport property */
+    public static final String HTTPS_PROXY_PORT = "https.proxyPort";
+    /** the ftp proxyhost property */
+    public static final String FTP_PROXY_HOST = "ftp.proxyHost";
+    /** the ftp proxyport property */
+    public static final String FTP_PROXY_PORT = "ftp.proxyPort";
+    /** the ftp proxyport property */
+    public static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";
+    /** the http hosts not to be proxied property */
+    public static final String HTTPS_NON_PROXY_HOSTS = "https.nonProxyHosts";
+    /** the ftp hosts not to be proxied property */
+    public static final String FTP_NON_PROXY_HOSTS = "ftp.nonProxyHosts";
+    /** the http proxy username property */
+    public static final String HTTP_PROXY_USERNAME = "http.proxyUser";
+    /** the http proxy password property */
+    public static final String HTTP_PROXY_PASSWORD = "http.proxyPassword";
+    /** the socks proxy host property */
+    public static final String SOCKS_PROXY_HOST = "socksProxyHost";
+    /** the socks proxy port property */
+    public static final String SOCKS_PROXY_PORT = "socksProxyPort";
+    /** the socks proxy username property */
+    public static final String SOCKS_PROXY_USERNAME = "java.net.socks.username";
+    /** the socks proxy password property */
+    public static final String SOCKS_PROXY_PASSWORD = "java.net.socks.password";
+
+    /**
+     * create a proxy setup class bound to this project
+     * @param owner the project that owns this setup.
+     */
+    public ProxySetup(Project owner) {
+        this.owner = owner;
+    }
+
+    /**
+     * Get the current system property settings
+     * @return current value; null for none or no access
+     */
+    public static String getSystemProxySetting() {
+        try {
+            return System.getProperty(USE_SYSTEM_PROXIES);
+        } catch (SecurityException e) {
+            //if you cannot read it, you won't be able to write it either
+            return null;
+        }
+    }
+
+    /**
+     * turn proxies on;
+     * if the proxy key is already set to some value: leave alone.
+     * if an ant property of the value {@link #USE_SYSTEM_PROXIES}
+     * is set, use that instead. Else set to "true".
+     */
+    public void enableProxies() {
+        if (!(getSystemProxySetting() != null)) {
+            String proxies = owner.getProperty(USE_SYSTEM_PROXIES);
+            if (proxies == null || Project.toBoolean(proxies)) {
+                proxies = "true";
+            }
+            String message = "setting " + USE_SYSTEM_PROXIES + " to " + proxies;
+            try {
+                owner.log(message, Project.MSG_DEBUG);
+                System.setProperty(USE_SYSTEM_PROXIES, proxies);
+            } catch (SecurityException e) {
+                //log security exceptions and continue; it aint that
+                //important and may be quite common running Ant embedded.
+                owner.log("Security Exception when " + message);
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ReaderInputStream.java b/trunk/src/main/org/apache/tools/ant/util/ReaderInputStream.java
new file mode 100755
index 0000000..620af8d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ReaderInputStream.java
@@ -0,0 +1,205 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * Adapts a <code>Reader</code> as an <code>InputStream</code>.
+ * Adapted from <code>StringInputStream</code>.
+ *
+ */
+public class ReaderInputStream extends InputStream {
+    private static final int BYTE_MASK = 0xFF;
+
+    /** Source Reader */
+    private Reader in;
+
+    private String encoding = System.getProperty("file.encoding");
+
+    private byte[] slack;
+
+    private int begin;
+
+    /**
+     * Construct a <code>ReaderInputStream</code>
+     * for the specified <code>Reader</code>.
+     *
+     * @param reader   <code>Reader</code>.  Must not be <code>null</code>.
+     */
+    public ReaderInputStream(Reader reader) {
+        in = reader;
+    }
+
+    /**
+     * Construct a <code>ReaderInputStream</code>
+     * for the specified <code>Reader</code>,
+     * with the specified encoding.
+     *
+     * @param reader     non-null <code>Reader</code>.
+     * @param encoding   non-null <code>String</code> encoding.
+     */
+    public ReaderInputStream(Reader reader, String encoding) {
+        this(reader);
+        if (encoding == null) {
+            throw new IllegalArgumentException("encoding must not be null");
+        } else {
+            this.encoding = encoding;
+        }
+    }
+
+    /**
+     * Reads from the <code>Reader</code>, returning the same value.
+     *
+     * @return the value of the next character in the <code>Reader</code>.
+     *
+     * @exception IOException if the original <code>Reader</code> fails to be read
+     */
+    public synchronized int read() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream Closed");
+        }
+
+        byte result;
+        if (slack != null && begin < slack.length) {
+            result = slack[begin];
+            if (++begin == slack.length) {
+                slack = null;
+            }
+        } else {
+            byte[] buf = new byte[1];
+            if (read(buf, 0, 1) <= 0) {
+                return -1;
+            } else {
+                result = buf[0];
+            }
+        }
+        return result & BYTE_MASK;
+    }
+
+    /**
+     * Reads from the <code>Reader</code> into a byte array
+     *
+     * @param b  the byte array to read into
+     * @param off the offset in the byte array
+     * @param len the length in the byte array to fill
+     * @return the actual number read into the byte array, -1 at
+     *         the end of the stream
+     * @exception IOException if an error occurs
+     */
+    public synchronized int read(byte[] b, int off, int len)
+        throws IOException {
+        if (in == null) {
+            throw new IOException("Stream Closed");
+        }
+        if (len == 0) {
+            return 0;
+        }
+        while (slack == null) {
+            char[] buf = new char[len]; // might read too much
+            int n = in.read(buf);
+            if (n == -1) {
+                return -1;
+            }
+            if (n > 0) {
+                slack = new String(buf, 0, n).getBytes(encoding);
+                begin = 0;
+            }
+        }
+
+        if (len > slack.length - begin) {
+            len = slack.length - begin;
+        }
+
+        System.arraycopy(slack, begin, b, off, len);
+
+        begin += len;
+        if (begin >= slack.length) {
+            slack = null;
+        }
+
+        return len;
+    }
+
+    /**
+     * Marks the read limit of the Reader.
+     *
+     * @param limit the maximum limit of bytes that can be read before the
+     *              mark position becomes invalid
+     */
+    public synchronized void mark(final int limit) {
+        try {
+            in.mark(limit);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe.getMessage());
+        }
+    }
+
+
+    /**
+     * @return   the current number of bytes ready for reading
+     * @exception IOException if an error occurs
+     */
+    public synchronized int available() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream Closed");
+        }
+        if (slack != null) {
+            return slack.length - begin;
+        }
+        if (in.ready()) {
+            return 1;
+        }
+        return 0;
+    }
+
+    /**
+     * @return false - mark is not supported
+     */
+    public boolean markSupported () {
+        return false;   // would be imprecise
+    }
+
+    /**
+     * Resets the Reader.
+     *
+     * @exception IOException if the Reader fails to be reset
+     */
+    public synchronized void reset() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream Closed");
+        }
+        slack = null;
+        in.reset();
+    }
+
+    /**
+     * Closes the Reader.
+     *
+     * @exception IOException if the original Reader fails to be closed
+     */
+    public synchronized void close() throws IOException {
+        if (in != null) {
+            in.close();
+            slack = null;
+            in = null;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ReflectUtil.java b/trunk/src/main/org/apache/tools/ant/util/ReflectUtil.java
new file mode 100644
index 0000000..74d3e65
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ReflectUtil.java
@@ -0,0 +1,193 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import org.apache.tools.ant.BuildException;
+import java.lang.reflect.Field;
+
+/**
+ * Utility class to handle reflection on java objects.
+ * The class contains static methods to call reflection
+ * methods, catch any exceptions, converting them
+ * to BuildExceptions.
+ */
+// CheckStyle:FinalClassCheck OFF - backward compatible
+public class ReflectUtil {
+
+    /**  private constructor */
+    private ReflectUtil() {
+    }
+
+    /**
+     * Call a method on the object with no parameters.
+     * @param obj  the object to invoke the method on.
+     * @param methodName the name of the method to call
+     * @return the object returned by the method
+     */
+    public static Object invoke(Object obj, String methodName) {
+        try {
+            Method method;
+            method = obj.getClass().getMethod(
+                        methodName, (Class[]) null);
+            return method.invoke(obj, (Object[]) null);
+        } catch (Exception t) {
+            throwBuildException(t);
+            return null; // NotReached
+        }
+    }
+
+    /**
+     * Call a method on the object with no parameters.
+     * Note: Unlike the invoke method above, this
+     * calls class or static methods, not instance methods.
+     * @param obj  the object to invoke the method on.
+     * @param methodName the name of the method to call
+     * @return the object returned by the method
+     */
+    public static Object invokeStatic(Object obj, String methodName) {
+        try {
+            Method method;
+            method = ((Class) obj).getMethod(
+                    methodName, (Class[]) null);
+            return method.invoke(obj, (Object[]) null);
+        }  catch (Exception t) {
+            throwBuildException(t);
+            return null; // NotReached
+        }
+    }
+
+    /**
+     * Call a method on the object with one argument.
+     * @param obj  the object to invoke the method on.
+     * @param methodName the name of the method to call
+     * @param argType    the type of argument.
+     * @param arg        the value of the argument.
+     * @return the object returned by the method
+     */
+    public static Object invoke(
+        Object obj, String methodName, Class argType, Object arg) {
+        try {
+            Method method;
+            method = obj.getClass().getMethod(
+                methodName, new Class[] {argType});
+            return method.invoke(obj, new Object[] {arg});
+        } catch (Exception t) {
+            throwBuildException(t);
+            return null; // NotReached
+        }
+    }
+
+    /**
+     * Call a method on the object with two argument.
+     * @param obj  the object to invoke the method on.
+     * @param methodName the name of the method to call
+     * @param argType1   the type of the first argument.
+     * @param arg1       the value of the first argument.
+     * @param argType2   the type of the second argument.
+     * @param arg2       the value of the second argument.
+     * @return the object returned by the method
+     */
+    public static Object invoke(
+        Object obj, String methodName, Class argType1, Object arg1,
+        Class argType2, Object arg2) {
+        try {
+            Method method;
+            method = obj.getClass().getMethod(
+                methodName, new Class[] {argType1, argType2});
+            return method.invoke(obj, new Object[] {arg1, arg2});
+        } catch (Exception t) {
+            throwBuildException(t);
+            return null; // NotReached
+        }
+    }
+
+    /**
+     * Get the value of a field in an object.
+     * @param obj the object to look at.
+     * @param fieldName the name of the field in the object.
+     * @return the value of the field.
+     * @throws BuildException if there is an error.
+     */
+    public static Object getField(Object obj, String fieldName)
+        throws BuildException {
+        try {
+            Field field = obj.getClass().getDeclaredField(fieldName);
+            field.setAccessible(true);
+            return field.get(obj);
+        } catch (Exception t) {
+            throwBuildException(t);
+            return null; // NotReached
+        }
+    }
+
+    /**
+     * A method to convert an invocationTargetException to
+     * a buildexception and throw it.
+     * @param t the invocation target exception.
+     * @throws BuildException the converted exception.
+     */
+    public static void throwBuildException(Exception t)
+        throws BuildException {
+        throw toBuildException(t);
+    }
+
+    /**
+     * A method to convert an invocationTargetException to
+     * a buildexception.
+     * @param t the invocation target exception.
+     * @return the converted exception.
+     * @since ant 1.7.1
+     */
+    public static BuildException toBuildException(Exception t) {
+        if (t instanceof InvocationTargetException) {
+            Throwable t2 = ((InvocationTargetException) t)
+                .getTargetException();
+            if (t2 instanceof BuildException) {
+                return (BuildException) t2;
+            }
+            return new BuildException(t2);
+        } else {
+            return new BuildException(t);
+        }
+    }
+
+    /**
+     * A method to test if an object responds to a given
+     * message (method call)
+     * @param o the object
+     * @param methodName the method to check for
+     * @return true if the object has the method.
+     * @throws BuildException if there is a problem.
+     */
+    public static boolean respondsTo(Object o, String methodName)
+        throws BuildException {
+        try {
+            Method[] methods = o.getClass().getMethods();
+            for (int i = 0; i < methods.length; i++) {
+                if (methods[i].getName().equals(methodName)) {
+                    return true;
+                }
+            }
+            return false;
+        } catch (Exception t) {
+            throw toBuildException(t);
+        }
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/util/ReflectWrapper.java b/trunk/src/main/org/apache/tools/ant/util/ReflectWrapper.java
new file mode 100644
index 0000000..e34363e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ReflectWrapper.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Utility class to handle reflection on java objects.
+ * The class is a holder class for an object and
+ * uses java reflection to call methods on the objects.
+ * If things go wrong, BuildExceptions are thrown.
+ */
+
+public class ReflectWrapper {
+    private Object obj;
+    /**
+     * Construct a wrapped object using the no arg constructor.
+     * @param loader the classloader to use to construct the class.
+     * @param name the classname of the object to construct.
+     */
+    public ReflectWrapper(ClassLoader loader, String name) {
+        try {
+            Class clazz;
+            clazz = Class.forName(name, true, loader);
+            Constructor constructor;
+            constructor = clazz.getConstructor((Class[]) null);
+            obj = constructor.newInstance((Object[]) null);
+        } catch (Exception t) {
+            ReflectUtil.throwBuildException(t);
+        }
+    }
+
+    /**
+     * Constructor using a passed in object.
+     * @param obj the object to wrap.
+     */
+    public ReflectWrapper(Object obj) {
+        this.obj = obj;
+    }
+
+    /**
+     * @return the wrapped object.
+     */
+    public Object getObject() {
+        return obj;
+    }
+
+    /**
+     * Call a method on the object with no parameters.
+     * @param methodName the name of the method to call
+     * @return the object returned by the method
+     */
+    public Object invoke(String methodName) {
+        return ReflectUtil.invoke(obj, methodName);
+    }
+
+    /**
+     * Call a method on the object with one argument.
+     * @param methodName the name of the method to call
+     * @param argType    the type of argument.
+     * @param arg        the value of the argument.
+     * @return the object returned by the method
+     */
+    public Object invoke(
+        String methodName, Class argType, Object arg) {
+        return ReflectUtil.invoke(obj, methodName, argType, arg);
+    }
+
+    /**
+     * Call a method on the object with one argument.
+     * @param methodName the name of the method to call
+     * @param argType1   the type of the first argument.
+     * @param arg1       the value of the first argument.
+     * @param argType2   the type of the second argument.
+     * @param arg2       the value of the second argument.
+     * @return the object returned by the method
+     */
+    public Object invoke(
+        String methodName, Class argType1, Object arg1,
+        Class argType2, Object arg2) {
+        return ReflectUtil.invoke(
+            obj, methodName, argType1, arg1, argType2, arg2);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java b/trunk/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java
new file mode 100644
index 0000000..51ad6e6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+
+/**
+ * Implementation of FileNameMapper that does regular expression
+ * replacements.
+ *
+ */
+public class RegexpPatternMapper implements FileNameMapper {
+
+    private static final int DECIMAL = 10;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected RegexpMatcher reg = null;
+    protected char[] to = null;
+    protected StringBuffer result = new StringBuffer();
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for RegexpPatternMapper.
+     * @throws BuildException on error.
+     */
+    public RegexpPatternMapper() throws BuildException {
+        reg = (new RegexpMatcherFactory()).newRegexpMatcher();
+    }
+
+    private boolean handleDirSep = false;
+    private int     regexpOptions = 0;
+
+    /**
+     * Attribute specifing whether to ignore the difference
+     * between / and \ (the two common directory characters).
+     * @param handleDirSep a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setHandleDirSep(boolean handleDirSep) {
+        this.handleDirSep = handleDirSep;
+    }
+
+    /**
+     * Attribute specifing whether to ignore the case difference
+     * in the names.
+     *
+     * @param caseSensitive a boolean, default is false.
+     * @since Ant 1.6.3
+     */
+    public void setCaseSensitive(boolean caseSensitive) {
+        if (!caseSensitive) {
+            regexpOptions = RegexpMatcher.MATCH_CASE_INSENSITIVE;
+        } else {
+            regexpOptions = 0;
+        }
+    }
+
+    /**
+     * Sets the &quot;from&quot; pattern. Required.
+     * @param from the from pattern.
+     * @throws BuildException on error.
+     */
+    public void setFrom(String from) throws BuildException {
+        try {
+            reg.setPattern(from);
+        } catch (NoClassDefFoundError e) {
+            // depending on the implementation the actual RE won't
+            // get instantiated in the constructor.
+            throw new BuildException("Cannot load regular expression matcher",
+                                     e);
+        }
+    }
+
+    /**
+     * Sets the &quot;to&quot; pattern. Required.
+     * @param to the to pattern.
+     * @throws BuildException on error.
+     */
+    public void setTo(String to) {
+        this.to = to.toCharArray();
+    }
+
+    /**
+     * Returns null if the source file name doesn't match the
+     * &quot;from&quot; pattern, an one-element array containing the
+     * translated file otherwise.
+     * @param sourceFileName the source file name
+     * @return a one-element array containing the translated file or
+     *         null if the to pattern did not match
+     */
+    public String[] mapFileName(String sourceFileName) {
+        if (handleDirSep) {
+            if (sourceFileName.indexOf("\\") != -1) {
+                sourceFileName = sourceFileName.replace('\\', '/');
+            }
+        }
+        if (reg == null  || to == null
+            || !reg.matches(sourceFileName, regexpOptions)) {
+            return null;
+        }
+        return new String[] {replaceReferences(sourceFileName)};
+    }
+
+    /**
+     * Replace all backreferences in the to pattern with the matched
+     * groups of the source.
+     * @param source the source file name.
+     * @return the translated file name.
+     */
+    protected String replaceReferences(String source) {
+        Vector v = reg.getGroups(source, regexpOptions);
+
+        result.setLength(0);
+        for (int i = 0; i < to.length; i++) {
+            if (to[i] == '\\') {
+                if (++i < to.length) {
+                    int value = Character.digit(to[i], DECIMAL);
+                    if (value > -1) {
+                        result.append((String) v.elementAt(value));
+                    } else {
+                        result.append(to[i]);
+                    }
+                } else {
+                    // XXX - should throw an exception instead?
+                    result.append('\\');
+                }
+            } else {
+                result.append(to[i]);
+            }
+        }
+        return result.substring(0);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ResourceUtils.java b/trunk/src/main/org/apache/tools/ant/util/ResourceUtils.java
new file mode 100644
index 0000000..a596da2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ResourceUtils.java
@@ -0,0 +1,571 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.Reader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.BufferedInputStream;
+import java.util.Arrays;
+import java.util.Vector;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.TimeComparison;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.Touchable;
+import org.apache.tools.ant.types.resources.selectors.Not;
+import org.apache.tools.ant.types.resources.selectors.Date;
+import org.apache.tools.ant.types.resources.selectors.Exists;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * This class provides utility methods to process Resources.
+ *
+ * @since Ant 1.5.2
+ */
+public class ResourceUtils {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private static final ResourceSelector NOT_EXISTS = new Not(new Exists());
+
+    /**
+     * Tells which source files should be reprocessed based on the
+     * last modification date of target files.
+     * @param logTo where to send (more or less) interesting output.
+     * @param source array of resources bearing relative path and last
+     * modification date.
+     * @param mapper filename mapper indicating how to find the target
+     * files.
+     * @param targets object able to map as a resource a relative path
+     * at <b>destination</b>.
+     * @return array containing the source files which need to be
+     * copied or processed, because the targets are out of date or do
+     * not exist.
+     */
+    public static Resource[] selectOutOfDateSources(ProjectComponent logTo,
+                                                    Resource[] source,
+                                                    FileNameMapper mapper,
+                                                    ResourceFactory targets) {
+        return selectOutOfDateSources(logTo, source, mapper, targets,
+                                      FILE_UTILS.getFileTimestampGranularity());
+    }
+
+    /**
+     * Tells which source files should be reprocessed based on the
+     * last modification date of target files.
+     * @param logTo where to send (more or less) interesting output.
+     * @param source array of resources bearing relative path and last
+     * modification date.
+     * @param mapper filename mapper indicating how to find the target
+     * files.
+     * @param targets object able to map as a resource a relative path
+     * at <b>destination</b>.
+     * @param granularity The number of milliseconds leeway to give
+     * before deciding a target is out of date.
+     * @return array containing the source files which need to be
+     * copied or processed, because the targets are out of date or do
+     * not exist.
+     * @since Ant 1.6.2
+     */
+    public static Resource[] selectOutOfDateSources(ProjectComponent logTo,
+                                                    Resource[] source,
+                                                    FileNameMapper mapper,
+                                                    ResourceFactory targets,
+                                                    long granularity) {
+        Union u = new Union();
+        u.addAll(Arrays.asList(source));
+        ResourceCollection rc
+            = selectOutOfDateSources(logTo, u, mapper, targets, granularity);
+        return rc.size() == 0 ? new Resource[0] : ((Union) rc).listResources();
+    }
+
+    /**
+     * Tells which sources should be reprocessed based on the
+     * last modification date of targets.
+     * @param logTo where to send (more or less) interesting output.
+     * @param source ResourceCollection.
+     * @param mapper filename mapper indicating how to find the target Resources.
+     * @param targets object able to map a relative path as a Resource.
+     * @param granularity The number of milliseconds leeway to give
+     * before deciding a target is out of date.
+     * @return ResourceCollection.
+     * @since Ant 1.7
+     */
+    public static ResourceCollection selectOutOfDateSources(ProjectComponent logTo,
+                                                            ResourceCollection source,
+                                                            FileNameMapper mapper,
+                                                            ResourceFactory targets,
+                                                            final long granularity) {
+        if (source.size() == 0) {
+            logTo.log("No sources found.", Project.MSG_VERBOSE);
+            return Resources.NONE;
+        }
+        source = Union.getInstance(source);
+        logFuture(logTo, source, granularity);
+
+        Union result = new Union();
+        for (Iterator iter = source.iterator(); iter.hasNext();) {
+            final Resource sr = (Resource) iter.next();
+            String srName = sr.getName();
+            srName = srName == null
+                ? srName : srName.replace('/', File.separatorChar);
+
+            String[] targetnames = null;
+            try {
+                targetnames = mapper.mapFileName(srName);
+            } catch (Exception e) {
+                logTo.log("Caught " + e + " mapping resource " + sr,
+                    Project.MSG_VERBOSE);
+            }
+            if (targetnames == null || targetnames.length == 0) {
+                logTo.log(sr + " skipped - don\'t know how to handle it",
+                      Project.MSG_VERBOSE);
+                continue;
+            }
+            Union targetColl = new Union();
+            for (int i = 0; i < targetnames.length; i++) {
+                targetColl.add(targets.getResource(
+                    targetnames[i].replace(File.separatorChar, '/')));
+            }
+            //find the out-of-date targets:
+            Restrict r = new Restrict();
+            r.add(new ResourceSelector() {
+                public boolean isSelected(Resource target) {
+                    /* Extra I/O, probably wasted:
+                    if (target.isDirectory()) {
+                        return false;
+                    }
+                     */
+                    return SelectorUtils.isOutOfDate(sr, target, granularity);
+                }
+            });
+            r.add(targetColl);
+            if (r.size() > 0) {
+                result.add(sr);
+                Resource t = (Resource) (r.iterator().next());
+                logTo.log(sr.getName() + " added as " + t.getName()
+                    + (t.isExists() ? " is outdated." : " doesn\'t exist."),
+                    Project.MSG_VERBOSE);
+                continue;
+            }
+            //log uptodateness of all targets:
+            logTo.log(sr.getName()
+                  + " omitted as " + targetColl.toString()
+                  + (targetColl.size() == 1 ? " is" : " are ")
+                  + " up to date.", Project.MSG_VERBOSE);
+        }
+        return result;
+    }
+
+    /**
+     * Convenience method to copy content from one Resource to another.
+     * No filtering is performed.
+     *
+     * @param source the Resource to copy from.
+     *                   Must not be <code>null</code>.
+     * @param dest   the Resource to copy to.
+     *                 Must not be <code>null</code>.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.7
+     */
+    public static void copyResource(Resource source, Resource dest) throws IOException {
+        copyResource(source, dest, null);
+    }
+
+    /**
+     * Convenience method to copy content from one Resource to another.
+     * No filtering is performed.
+     *
+     * @param source the Resource to copy from.
+     *                   Must not be <code>null</code>.
+     * @param dest   the Resource to copy to.
+     *                 Must not be <code>null</code>.
+     * @param project the project instance.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.7
+     */
+    public static void copyResource(Resource source, Resource dest, Project project)
+        throws IOException {
+        copyResource(source, dest, null, null, false,
+                     false, null, null, project);
+    }
+
+    // CheckStyle:ParameterNumberCheck OFF - bc
+    /**
+     * Convenience method to copy content from one Resource to another
+     * specifying whether token filtering must be used, whether filter chains
+     * must be used, whether newer destination files may be overwritten and
+     * whether the last modified time of <code>dest</code> file should be made
+     * equal to the last modified time of <code>source</code>.
+     *
+     * @param source the Resource to copy from.
+     *                   Must not be <code>null</code>.
+     * @param dest   the Resource to copy to.
+     *                 Must not be <code>null</code>.
+     * @param filters the collection of filters to apply to this copy.
+     * @param filterChains filterChains to apply during the copy.
+     * @param overwrite Whether or not the destination Resource should be
+     *                  overwritten if it already exists.
+     * @param preserveLastModified Whether or not the last modified time of
+     *                             the destination Resource should be set to that
+     *                             of the source.
+     * @param inputEncoding the encoding used to read the files.
+     * @param outputEncoding the encoding used to write the files.
+     * @param project the project instance.
+     *
+     * @throws IOException if the copying fails.
+     *
+     * @since Ant 1.7
+     */
+    public static void copyResource(Resource source, Resource dest,
+                             FilterSetCollection filters, Vector filterChains,
+                             boolean overwrite, boolean preserveLastModified,
+                             String inputEncoding, String outputEncoding,
+                             Project project)
+        throws IOException {
+        if (!overwrite) {
+            long slm = source.getLastModified();
+            if (dest.isExists() && slm != 0
+                && dest.getLastModified() > slm) {
+                return;
+            }
+        }
+        final boolean filterSetsAvailable = (filters != null
+                                             && filters.hasFilters());
+        final boolean filterChainsAvailable = (filterChains != null
+                                               && filterChains.size() > 0);
+        if (filterSetsAvailable) {
+            BufferedReader in = null;
+            BufferedWriter out = null;
+            try {
+                InputStreamReader isr = null;
+                if (inputEncoding == null) {
+                    isr = new InputStreamReader(source.getInputStream());
+                } else {
+                    isr = new InputStreamReader(source.getInputStream(),
+                                                inputEncoding);
+                }
+                in = new BufferedReader(isr);
+                OutputStreamWriter osw = null;
+                if (outputEncoding == null) {
+                    osw = new OutputStreamWriter(dest.getOutputStream());
+                } else {
+                    osw = new OutputStreamWriter(dest.getOutputStream(),
+                                                 outputEncoding);
+                }
+                out = new BufferedWriter(osw);
+                if (filterChainsAvailable) {
+                    ChainReaderHelper crh = new ChainReaderHelper();
+                    crh.setBufferSize(FileUtils.BUF_SIZE);
+                    crh.setPrimaryReader(in);
+                    crh.setFilterChains(filterChains);
+                    crh.setProject(project);
+                    Reader rdr = crh.getAssembledReader();
+                    in = new BufferedReader(rdr);
+                }
+                LineTokenizer lineTokenizer = new LineTokenizer();
+                lineTokenizer.setIncludeDelims(true);
+                String newline = null;
+                String line = lineTokenizer.getToken(in);
+                while (line != null) {
+                    if (line.length() == 0) {
+                        // this should not happen, because the lines are
+                        // returned with the end of line delimiter
+                        out.newLine();
+                    } else {
+                        newline = filters.replaceTokens(line);
+                        out.write(newline);
+                    }
+                    line = lineTokenizer.getToken(in);
+                }
+            } finally {
+                FileUtils.close(out);
+                FileUtils.close(in);
+            }
+        } else if (filterChainsAvailable
+                   || (inputEncoding != null
+                       && !inputEncoding.equals(outputEncoding))
+                   || (inputEncoding == null && outputEncoding != null)) {
+            BufferedReader in = null;
+            BufferedWriter out = null;
+            try {
+                InputStreamReader isr = null;
+                if (inputEncoding == null) {
+                    isr = new InputStreamReader(source.getInputStream());
+                } else {
+                    isr = new InputStreamReader(source.getInputStream(),
+                                                inputEncoding);
+                }
+                in = new BufferedReader(isr);
+                OutputStreamWriter osw = null;
+                if (outputEncoding == null) {
+                    osw = new OutputStreamWriter(dest.getOutputStream());
+                } else {
+                    osw = new OutputStreamWriter(dest.getOutputStream(),
+                                                 outputEncoding);
+                }
+                out = new BufferedWriter(osw);
+                if (filterChainsAvailable) {
+                    ChainReaderHelper crh = new ChainReaderHelper();
+                    crh.setBufferSize(FileUtils.BUF_SIZE);
+                    crh.setPrimaryReader(in);
+                    crh.setFilterChains(filterChains);
+                    crh.setProject(project);
+                    Reader rdr = crh.getAssembledReader();
+                    in = new BufferedReader(rdr);
+                }
+                char[] buffer = new char[FileUtils.BUF_SIZE];
+                while (true) {
+                    int nRead = in.read(buffer, 0, buffer.length);
+                    if (nRead == -1) {
+                        break;
+                    }
+                    out.write(buffer, 0, nRead);
+                }
+            } finally {
+                FileUtils.close(out);
+                FileUtils.close(in);
+            }
+        } else {
+            InputStream in = null;
+            OutputStream out = null;
+            try {
+                in = source.getInputStream();
+                out = dest.getOutputStream();
+
+                byte[] buffer = new byte[FileUtils.BUF_SIZE];
+                int count = 0;
+                do {
+                    out.write(buffer, 0, count);
+                    count = in.read(buffer, 0, buffer.length);
+                } while (count != -1);
+            } finally {
+                FileUtils.close(out);
+                FileUtils.close(in);
+            }
+        }
+        if (preserveLastModified && dest instanceof Touchable) {
+            setLastModified((Touchable) dest, source.getLastModified());
+        }
+    }
+    // CheckStyle:ParameterNumberCheck ON
+
+    /**
+     * Set the last modified time of an object implementing
+     * org.apache.tools.ant.types.resources.Touchable .
+     *
+     * @param t the Touchable whose modified time is to be set.
+     * @param time the time to which the last modified time is to be set.
+     *             if this is -1, the current time is used.
+     * @since Ant 1.7
+     */
+    public static void setLastModified(Touchable t, long time) {
+        t.touch((time < 0) ? System.currentTimeMillis() : time);
+    }
+
+    /**
+     * Compares the contents of two Resources.
+     *
+     * @param r1 the Resource whose content is to be compared.
+     * @param r2 the other Resource whose content is to be compared.
+     * @param text true if the content is to be treated as text and
+     *        differences in kind of line break are to be ignored.
+     *
+     * @return true if the content of the Resources is the same.
+     *
+     * @throws IOException if the Resources cannot be read.
+     * @since Ant 1.7
+     */
+    public static boolean contentEquals(Resource r1, Resource r2, boolean text) throws IOException {
+        if (r1.isExists() != r2.isExists()) {
+            return false;
+        }
+        if (!r1.isExists()) {
+            // two not existing files are equal
+            return true;
+        }
+        // should the following two be switched?  If r1 and r2 refer to the same file,
+        // isn't their content equal regardless of whether that file is a directory?
+        if (r1.isDirectory() || r2.isDirectory()) {
+            // don't want to compare directory contents for now
+            return false;
+        }
+        if (r1.equals(r2)) {
+            return true;
+        }
+        if (!text) {
+            long s1 = r1.getSize();
+            long s2 = r2.getSize();
+            if (s1 != Resource.UNKNOWN_SIZE && s2 != Resource.UNKNOWN_SIZE
+                    && s1 != s2) {
+                return false;
+            }
+        }
+        return compareContent(r1, r2, text) == 0;
+    }
+
+    /**
+     * Compare the content of two Resources. A nonexistent Resource's
+     * content is "less than" that of an existing Resource; a directory-type
+     * Resource's content is "less than" that of a file-type Resource.
+     * @param r1 the Resource whose content is to be compared.
+     * @param r2 the other Resource whose content is to be compared.
+     * @param text true if the content is to be treated as text and
+     *        differences in kind of line break are to be ignored.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws IOException if the Resources cannot be read.
+     * @since Ant 1.7
+     */
+    public static int compareContent(Resource r1, Resource r2, boolean text) throws IOException {
+        if (r1.equals(r2)) {
+            return 0;
+        }
+        boolean e1 = r1.isExists();
+        boolean e2 = r2.isExists();
+        if (!(e1 || e2)) {
+            return 0;
+        }
+        if (e1 != e2) {
+            return e1 ? 1 : -1;
+        }
+        boolean d1 = r1.isDirectory();
+        boolean d2 = r2.isDirectory();
+        if (d1 && d2) {
+            return 0;
+        }
+        if (d1 || d2) {
+            return d1 ? -1 : 1;
+        }
+        return text ? textCompare(r1, r2) : binaryCompare(r1, r2);
+    }
+
+    /**
+     * Binary compares the contents of two Resources.
+     * <p>
+     * simple but sub-optimal comparision algorithm. written for working
+     * rather than fast. Better would be a block read into buffers followed
+     * by long comparisions apart from the final 1-7 bytes.
+     * </p>
+     *
+     * @param r1 the Resource whose content is to be compared.
+     * @param r2 the other Resource whose content is to be compared.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws IOException if the Resources cannot be read.
+     * @since Ant 1.7
+     */
+    private static int binaryCompare(Resource r1, Resource r2) throws IOException {
+        InputStream in1 = null;
+        InputStream in2 = null;
+        try {
+            in1 = new BufferedInputStream(r1.getInputStream());
+            in2 = new BufferedInputStream(r2.getInputStream());
+
+            for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) {
+                int b2 = in2.read();
+                if (b1 != b2) {
+                    return b1 > b2 ? 1 : -1;
+                }
+            }
+            return in2.read() == -1 ? 0 : -1;
+        } finally {
+            FileUtils.close(in1);
+            FileUtils.close(in2);
+        }
+    }
+
+    /**
+     * Text compares the contents of two Resources.
+     * Ignores different kinds of line endings.
+     * @param r1 the Resource whose content is to be compared.
+     * @param r2 the other Resource whose content is to be compared.
+     * @return a negative integer, zero, or a positive integer as the first
+     *         argument is less than, equal to, or greater than the second.
+     * @throws IOException if the Resources cannot be read.
+     * @since Ant 1.7
+     */
+    private static int textCompare(Resource r1, Resource r2) throws IOException {
+        BufferedReader in1 = null;
+        BufferedReader in2 = null;
+        try {
+            in1 = new BufferedReader(new InputStreamReader(r1.getInputStream()));
+            in2 = new BufferedReader(new InputStreamReader(r2.getInputStream()));
+
+            String expected = in1.readLine();
+            while (expected != null) {
+                String actual = in2.readLine();
+                if (!expected.equals(actual)) {
+                    return expected.compareTo(actual);
+                }
+                expected = in1.readLine();
+            }
+            return in2.readLine() == null ? 0 : -1;
+        } finally {
+            FileUtils.close(in1);
+            FileUtils.close(in2);
+        }
+    }
+
+    /**
+     * Log which Resources (if any) have been modified in the future.
+     * @param logTo the ProjectComponent to do the logging.
+     * @param rc the collection of Resources to check.
+     * @param granularity the timestamp granularity to use.
+     * @since Ant 1.7
+     */
+    private static void logFuture(ProjectComponent logTo,
+                                  ResourceCollection rc, long granularity) {
+        long now = System.currentTimeMillis() + granularity;
+        Date sel = new Date();
+        sel.setMillis(now);
+        sel.setWhen(TimeComparison.AFTER);
+        Restrict future = new Restrict();
+        future.add(sel);
+        future.add(rc);
+        for (Iterator iter = future.iterator(); iter.hasNext();) {
+            logTo.log("Warning: " + ((Resource) iter.next()).getName()
+                     + " modified in the future.", Project.MSG_WARN);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/RetryHandler.java b/trunk/src/main/org/apache/tools/ant/util/RetryHandler.java
new file mode 100644
index 0000000..dd62bc2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/RetryHandler.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * A simple utility class to take a piece of code (that implements
+ * <code>Retryable</code> interface) and executes that with possibility to
+ * retry the execution in case of IOException.
+ */
+public class RetryHandler {
+
+    private int retriesAllowed = 0;
+    private Task task;
+
+    /**
+     * Create a new RetryingHandler.
+     *
+     * @param retriesAllowed how many times to retry
+     * @param task the Ant task that is is executed from, used for logging only
+     */
+    public RetryHandler(int retriesAllowed, Task task) {
+        this.retriesAllowed = retriesAllowed;
+        this.task = task;
+    }
+
+    /**
+     * Execute the <code>Retryable</code> code with specified number of retries.
+     *
+     * @param exe the code to execute
+     * @param desc some descriptive text for this piece of code, used for logging
+     * @throws IOException if the number of retries has exceeded the allowed limit
+     */
+    public void execute(Retryable exe, String desc) throws IOException {
+        int retries = 0;
+        while (true) {
+            try {
+                exe.execute();
+                break;
+            } catch (IOException e) {
+                retries++;
+                if (retries > this.retriesAllowed && this.retriesAllowed > -1) {
+                    task.log("try #" + retries + ": IO error ("
+                            + desc + "), number of maximum retries reached ("
+                            + this.retriesAllowed + "), giving up", Project.MSG_WARN);
+                    throw e;
+                } else {
+                    task.log("try #" + retries + ": IO error (" + desc
+                             + "), retrying", Project.MSG_WARN);
+                }
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/Retryable.java b/trunk/src/main/org/apache/tools/ant/util/Retryable.java
new file mode 100644
index 0000000..537244a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/Retryable.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+
+
+/**
+ * Simple interface for executing a piece of code. Used for writing anonymous inner
+ * classes in FTP task for retry-on-IOException behaviour.
+ *
+ * @see RetryHandler
+ */
+public interface Retryable {
+    /** The value to use to never give up. */
+    int RETRY_FOREVER = -1;
+    /**
+     * Called to execute the code.
+     * @throws IOException if there is a problem.
+     */
+    void execute() throws IOException;
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java b/trunk/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java
new file mode 100644
index 0000000..9bf9a60
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import java.io.File;
+import java.util.Map;
+import java.util.HashMap;
+
+
+/**
+ * A class to modify a classloader to
+ * support BSF language support.
+ */
+public class ScriptFixBSFPath {
+    private static final String UTIL_OPTIONAL_PACKAGE
+        = "org.apache.tools.ant.util.optional";
+
+    private static final String BSF_PACKAGE = "org.apache.bsf";
+    private static final String BSF_MANAGER = BSF_PACKAGE + ".BSFManager";
+    private static final String BSF_SCRIPT_RUNNER
+        = UTIL_OPTIONAL_PACKAGE + ".ScriptRunner";
+
+    /**
+     * The following are languages that have
+     * scripting engines embedded in bsf.jar.
+     * The array is converted to a map of
+     * languagename->classname.
+     */
+    private static final String[] BSF_LANGUAGES =
+        new String[] {
+            "js",         "org.mozilla.javascript.Scriptable",
+            "javascript", "org.mozilla.javascript.Scriptable",
+            "jacl",       "tcl.lang.Interp",
+            "netrexx",    "netrexx.lang.Rexx",
+            "nrx",        "netrexx.lang.Rexx",
+            "jython",     "org.python.core.Py",
+            "py",         "org.python.core.Py",
+            "xslt",       "org.apache.xpath.objects.XObject"};
+
+    /** A map of languages for which the engine in located in bsf */
+    private static final Map BSF_LANGUAGE_MAP = new HashMap();
+    static {
+        for (int i = 0; i < BSF_LANGUAGES.length; i = i + 2) {
+            BSF_LANGUAGE_MAP.put(BSF_LANGUAGES[i], BSF_LANGUAGES[i + 1]);
+        }
+    }
+
+    private File getClassSource(ClassLoader loader, String className) {
+        return LoaderUtils.getResourceSource(
+            loader,
+            LoaderUtils.classNameToResource(className));
+    }
+
+    private File getClassSource(String className) {
+        return getClassSource(getClass().getClassLoader(), className);
+    }
+
+    /**
+     * Check if need to mess about with the classloader.
+     * The class loader will need to be modified for two
+     * reasons:
+     * <ol>
+     *  <li>language is at a higher level than bsf for engines in bsf,
+     *      move bsf.
+     *  </li>
+     *  <li>bsf is at a higher level than oata.util.optional.ScriptRunner
+     *  </li>
+     * </ol>
+     *
+     * Assume a simple model for the loader:
+     *  thisloader<-customloader
+     *  or
+     *  thisloader
+     *
+     * @param loader the classloader to fix.
+     * @param language the language to use.
+     */
+    public void fixClassLoader(ClassLoader loader, String language) {
+        if (loader == getClass().getClassLoader()
+            || !(loader instanceof AntClassLoader)) {
+            return;
+        }
+        ClassLoader myLoader = getClass().getClassLoader();
+        AntClassLoader fixLoader = (AntClassLoader) loader;
+
+        // Check for location of bsf in this classloader
+        File bsfSource = getClassSource(BSF_MANAGER);
+
+        // If bsf is not in the classloader for this, need to move
+        // runner.
+        boolean needMoveRunner = (bsfSource == null);
+
+        // Check for location of language
+        String languageClassName = (String) BSF_LANGUAGE_MAP.get(language);
+
+        // Check if need to need to move bsf
+        boolean needMoveBsf =
+            bsfSource != null
+            && languageClassName != null
+            && !LoaderUtils.classExists(myLoader, languageClassName)
+            && LoaderUtils.classExists(loader, languageClassName);
+
+        // Update need to move runner
+        needMoveRunner = needMoveRunner || needMoveBsf;
+
+        // Check if bsf in place
+        if (bsfSource == null) {
+            bsfSource = getClassSource(loader, BSF_MANAGER);
+        }
+
+        if (bsfSource == null) {
+            throw new BuildException(
+                "Unable to find BSF classes for scripting");
+        }
+
+        if (needMoveBsf) {
+            fixLoader.addPathComponent(bsfSource);
+            fixLoader.addLoaderPackageRoot(BSF_PACKAGE);
+        }
+
+        if (needMoveRunner) {
+            fixLoader.addPathComponent(
+                LoaderUtils.getResourceSource(
+                    fixLoader,
+                    LoaderUtils.classNameToResource(BSF_SCRIPT_RUNNER)));
+            fixLoader.addLoaderPackageRoot(UTIL_OPTIONAL_PACKAGE);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ScriptRunner.java b/trunk/src/main/org/apache/tools/ant/util/ScriptRunner.java
new file mode 100644
index 0000000..1bc2adc
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ScriptRunner.java
@@ -0,0 +1,27 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+/**
+ * This class is here for backwards compatiblity.
+ * @deprecated Implementation moved to another location. Use
+ *             that org.apache.tools.ant.types.optional.ScriptRunner instead.
+ */
+public class ScriptRunner
+    extends org.apache.tools.ant.util.optional.ScriptRunner {
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
new file mode 100644
index 0000000..1bba545
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
@@ -0,0 +1,363 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * This is a common abstract base case for script runners.
+ * These classes need to implement executeScript, evaluateScript
+ * and supportsLanguage.
+ * @since Ant 1.7.0
+ */
+public abstract class ScriptRunnerBase {
+    /** Whether to keep the engine between calls to execute/eval */
+    private boolean keepEngine = false;
+
+    /** Script language */
+    private String language;
+
+    /** Script content */
+    private String script = "";
+
+    /** Project this runner is used in */
+    private Project project;
+
+    /** Classloader to be used when running the script. */
+    private ClassLoader scriptLoader;
+
+    /** Beans to be provided to the script */
+    private Map beans = new HashMap();
+
+    /**
+     * Add a list of named objects to the list to be exported to the script
+     *
+     * @param dictionary a map of objects to be placed into the script context
+     *        indexed by String names.
+     */
+    public void addBeans(Map dictionary) {
+        for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            try {
+                Object val = dictionary.get(key);
+                addBean(key, val);
+            } catch (BuildException ex) {
+                // The key is in the dictionary but cannot be retrieved
+                // This is usually due references that refer to tasks
+                // that have not been taskdefed in the current run.
+                // Ignore
+            }
+        }
+    }
+
+    /**
+     * Add a single object into the script context.
+     *
+     * @param key the name in the context this object is to stored under.
+     * @param bean the object to be stored in the script context.
+     */
+    public void addBean(String key, Object bean) {
+        boolean isValid = key.length() > 0
+            && Character.isJavaIdentifierStart(key.charAt(0));
+
+        for (int i = 1; isValid && i < key.length(); i++) {
+            isValid = Character.isJavaIdentifierPart(key.charAt(i));
+        }
+
+        if (isValid) {
+            beans.put(key, bean);
+        }
+    }
+
+    /**
+     * Get the beans used for the script.
+     * @return the map of beans.
+     */
+    protected Map getBeans() {
+        return beans;
+    }
+
+    /**
+     * Do the work.
+     * @param execName the name that will be passed to BSF for this script
+     *        execution.
+     */
+    public abstract void executeScript(String execName);
+
+    /**
+     * Evaluate the script.
+     * @param execName the name that will be passed to the
+     *                 scripting engine for this script execution.
+     * @return the result of evaluating the script.
+     */
+    public abstract Object evaluateScript(String execName);
+
+    /**
+     * Check if a script engine can be created for
+     * this language.
+     * @return true if a script engine can be created, false
+     *              otherwise.
+     */
+    public abstract boolean supportsLanguage();
+
+    /**
+     * Get the name of the manager prefix used for this
+     * scriptrunner.
+     * @return the prefix string.
+     */
+    public abstract String getManagerName();
+
+    /**
+     * Defines the language (required).
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    /**
+     * Get the script language
+     * @return the script language
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Set the script classloader.
+     * @param classLoader the classloader to use.
+     */
+    public void setScriptClassLoader(ClassLoader classLoader) {
+        this.scriptLoader = classLoader;
+    }
+
+    /**
+     * Get the classloader used to load the script engine.
+     * @return the classloader.
+     */
+    protected ClassLoader getScriptClassLoader() {
+        return scriptLoader;
+    }
+
+    /**
+     * Whether to keep the script engine between calls.
+     * @param keepEngine if true, keep the engine.
+     */
+    public void setKeepEngine(boolean keepEngine) {
+        this.keepEngine = keepEngine;
+    }
+
+    /**
+     * Get the keep engine attribute.
+     * @return the attribute.
+     */
+    public boolean getKeepEngine() {
+        return keepEngine;
+    }
+
+    /**
+     * Load the script from an external file; optional.
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        String filename = file.getPath();
+        if (!file.exists()) {
+            throw new BuildException("file " + filename + " not found.");
+        }
+        try {
+            readSource(new FileReader(file), filename);
+        } catch (FileNotFoundException e) {
+            //this can only happen if the file got deleted a short moment ago
+            throw new BuildException("file " + filename + " not found.");
+        }
+    }
+
+    /**
+     * Read some source in from the given reader
+     * @param reader the reader; this is closed afterwards.
+     * @param name the name to use in error messages
+     */
+    private void readSource(Reader reader, String name) {
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(reader);
+            script += FileUtils.safeReadFully(in);
+        } catch (IOException ex) {
+            throw new BuildException("Failed to read " + name, ex);
+        } finally {
+            FileUtils.close(in);
+        }
+    }
+
+
+    /**
+     * Add a resource to the source list.
+     * @since Ant 1.7.1
+     * @param sourceResource the resource to load
+     * @throws BuildException if the resource cannot be read
+     */
+    public void loadResource(Resource sourceResource) {
+        String name = sourceResource.toLongString();
+        InputStream in = null;
+        try {
+            in = sourceResource.getInputStream();
+        } catch (IOException e) {
+            throw new BuildException("Failed to open " + name, e);
+        } catch (UnsupportedOperationException e) {
+            throw new BuildException(
+                "Failed to open " + name + " -it is not readable", e);
+        }
+        readSource(new InputStreamReader(in), name);
+    }
+
+    /**
+     * Add all resources in a resource collection to the source list.
+     * @since Ant 1.7.1
+     * @param collection the resource to load
+     * @throws BuildException if a resource cannot be read
+     */
+    public void loadResources(ResourceCollection collection) {
+        Iterator resources = collection.iterator();
+        while (resources.hasNext()) {
+            Resource resource = (Resource) resources.next();
+            loadResource(resource);
+        }
+    }
+
+    /**
+     * Set the script text. Properties in the text are not expanded!
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        script += text;
+    }
+
+    /**
+     * Get the current script text content.
+     * @return the script text.
+     */
+    public String getScript() {
+        return script;
+    }
+
+    /**
+     * Clear the current script text content.
+     */
+    public void clearScript() {
+        this.script = "";
+    }
+
+    /**
+     * Set the project for this runner.
+     * @param project the project.
+     */
+    public void setProject(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Get the project for this runner.
+     * @return the project.
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Bind the runner to a project component.
+     * Properties, targets and references are all added as beans;
+     * project is bound to project, and self to the component.
+     * @param component to become <code>self</code>
+     */
+    public void bindToComponent(ProjectComponent component) {
+        project = component.getProject();
+        addBeans(project.getProperties());
+        addBeans(project.getUserProperties());
+        addBeans(project.getTargets());
+        addBeans(project.getReferences());
+        addBean("project", project);
+        addBean("self", component);
+    }
+
+    /**
+     * Bind the runner to a project component.
+     * The project and self are the only beans set.
+     * @param component to become <code>self</code>
+     */
+    public void bindToComponentMinimum(ProjectComponent component) {
+        project = component.getProject();
+        addBean("project", project);
+        addBean("self", component);
+    }
+
+    /**
+     * Check if the language attribute is set.
+     * @throws BuildException if it is not.
+     */
+    protected void checkLanguage() {
+        if (language == null) {
+            throw new BuildException(
+                "script language must be specified");
+        }
+    }
+
+    /**
+     * Replace the current context classloader with the
+     * script context classloader.
+     * @return the current context classloader.
+     */
+    protected ClassLoader replaceContextLoader() {
+        ClassLoader origContextClassLoader =
+            Thread.currentThread().getContextClassLoader();
+        if (getScriptClassLoader() == null) {
+            setScriptClassLoader(getClass().getClassLoader());
+        }
+        Thread.currentThread().setContextClassLoader(getScriptClassLoader());
+        return origContextClassLoader;
+    }
+
+    /**
+     * Restore the context loader with the original context classloader.
+     *
+     * script context loader.
+     * @param origLoader the original context classloader.
+     */
+    protected void restoreContextLoader(ClassLoader origLoader) {
+        Thread.currentThread().setContextClassLoader(
+                 origLoader);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java
new file mode 100644
index 0000000..77e9ee7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * This is a helper class used by ScriptRunnerHelper to
+ * create a ScriptRunner based on a classloader and on a language.
+ */
+public class ScriptRunnerCreator {
+    private static final String AUTO = "auto";
+    private static final String OATAU = "org.apache.tools.ant.util";
+    private static final String UTIL_OPT = OATAU + ".optional";
+
+    private static final String BSF = "bsf";
+    private static final String BSF_PACK = "org.apache.bsf";
+    private static final String BSF_MANAGER = BSF_PACK + ".BSFManager";
+    private static final String BSF_RUNNER = UTIL_OPT + ".ScriptRunner";
+
+    private static final String JAVAX = "javax";
+    private static final String JAVAX_MANAGER = "javax.script.ScriptEngineManager";
+    private static final String JAVAX_RUNNER = UTIL_OPT + ".JavaxScriptRunner";
+
+    private Project     project;
+    private String      manager;
+    private String      language;
+    private ClassLoader scriptLoader = null;
+
+    /**
+     * Constructor for creator.
+     * @param project the current project.
+     */
+    public ScriptRunnerCreator(Project project) {
+        this.project = project;
+    }
+
+    /**
+     * Create a ScriptRunner.
+     * @param manager      the script manager ("auto" | "bsf" | "javax")
+     * @param language     the language.
+     * @param classLoader  the classloader to use
+     * @return the created script runner.
+     * @throws BuildException if unable to create the ScriptRunner.
+     */
+    public synchronized ScriptRunnerBase createRunner(
+        String manager, String language, ClassLoader classLoader) {
+        this.manager      = manager;
+        this.language     = language;
+        this.scriptLoader = classLoader;
+
+        if (language == null) {
+            throw new BuildException("script language must be specified");
+        }
+        if (!manager.equals(AUTO) && !manager.equals(JAVAX) && !manager.equals(BSF)) {
+            throw new BuildException("Unsupported language prefix " + manager);
+        }
+
+        // Check for bsf first then javax
+        // This version does not check if the scriptManager
+        // supports the language.
+
+        ScriptRunnerBase ret = null;
+        ret = createRunner(BSF, BSF_MANAGER, BSF_RUNNER);
+        if (ret == null) {
+            ret = createRunner(JAVAX, JAVAX_MANAGER, JAVAX_RUNNER);
+        }
+        if (ret != null) {
+            return ret;
+        }
+        if (JAVAX.equals(manager)) {
+            throw new BuildException(
+                    "Unable to load the script engine manager " + "(" + JAVAX_MANAGER + ")");
+        }
+        if (BSF.equals(manager)) {
+            throw new BuildException(
+                    "Unable to load the BSF script engine manager " + "(" + BSF_MANAGER + ")");
+        }
+        throw new BuildException("Unable to load a script engine manager "
+                + "(" + BSF_MANAGER + " or " + JAVAX_MANAGER + ")");
+    }
+
+    /**
+     * Create a script runner if the scriptManager matches the passed
+     * in manager.
+     * This checks if the script manager exists in the scriptLoader
+     * classloader and if so it creates and returns the script runner.
+     * @param checkManager check if the manager matchs this value.
+     * @param managerClass the name of the script manager class.
+     * @param runnerClass   the name of ant's script runner for this manager.
+     * @return the script runner class.
+     * @throws BuildException if there is a problem creating the runner class.
+     */
+    private ScriptRunnerBase createRunner(
+        String checkManager, String managerClass, String runnerClass) {
+        ScriptRunnerBase runner = null;
+        if (!manager.equals(AUTO) && !manager.equals(checkManager)) {
+            return null;
+        }
+        if (scriptLoader.getResource(LoaderUtils.classNameToResource(managerClass)) == null) {
+            return null;
+        }
+        if (managerClass.equals(BSF_MANAGER)) {
+            new ScriptFixBSFPath().fixClassLoader(scriptLoader, language);
+        }
+        try {
+            runner = (ScriptRunnerBase) Class.forName(
+                    runnerClass, true, scriptLoader).newInstance();
+            runner.setProject(project);
+        } catch (Exception ex) {
+            throw ReflectUtil.toBuildException(ex);
+        }
+        runner.setLanguage(language);
+        runner.setScriptClassLoader(scriptLoader);
+        return runner;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java
new file mode 100644
index 0000000..c60ad6b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java
@@ -0,0 +1,203 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+
+/**
+ * A class to help in creating, setting and getting script runners.
+ */
+public class ScriptRunnerHelper {
+    private ClasspathUtils.Delegate cpDelegate = null;
+    private File    srcFile;
+    private String  manager = "auto";
+    private String  language;
+    private String  text;
+    private boolean setBeans = true;
+    private ProjectComponent projectComponent;
+    private ClassLoader scriptLoader = null;
+    private Union resources = new Union();
+
+    /**
+     * Set the project component associated with this helper.
+     * @param component the project component that owns this helper.
+     */
+    public void setProjectComponent(ProjectComponent component) {
+        this.projectComponent = component;
+    }
+
+    /**
+     * Create and set text on a script.
+     * @return the created or reused script runner.
+     */
+    public ScriptRunnerBase getScriptRunner() {
+        ScriptRunnerBase runner = getRunner();
+        if (srcFile != null) {
+            runner.setSrc(srcFile);
+        }
+        if (text != null) {
+            runner.addText(text);
+        }
+        if (resources != null) {
+            runner.loadResources(resources);
+        }
+        if (setBeans) {
+            runner.bindToComponent(projectComponent);
+        } else {
+            runner.bindToComponentMinimum(projectComponent);
+        }
+        return runner;
+    }
+
+    /**
+     * Classpath to be used when searching for classes and resources.
+     *
+     * @return an empty Path instance to be configured by Ant.
+     */
+    public Path createClasspath() {
+        return getClassPathDelegate().createClasspath();
+    }
+
+    /**
+     * Set the classpath to be used when searching for classes and resources.
+     *
+     * @param classpath an Ant Path object containing the search path.
+     */
+    public void setClasspath(Path classpath) {
+        getClassPathDelegate().setClasspath(classpath);
+    }
+
+    /**
+     * Set the classpath by reference.
+     *
+     * @param r a Reference to a Path instance to be used as the classpath
+     *          value.
+     */
+    public void setClasspathRef(Reference r) {
+        getClassPathDelegate().setClasspathref(r);
+    }
+
+    /**
+     * Load the script from an external file ; optional.
+     *
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        this.srcFile = file;
+    }
+
+    /**
+     * Add script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        this.text = text;
+    }
+
+    /**
+     * Defines the script manager - defaults to "auto".
+     *
+     * @param manager the scripting manager - "bsf" or "javax" or "auto"
+     */
+    public void setManager(String manager) {
+        this.manager = manager;
+    }
+
+    /**
+     * Defines the language (required).
+     *
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    /**
+     * Get the language.
+     * @return the scripting language.
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Set the setbeans attribute.
+     * If this is true, &lt;script&gt; will create variables in the
+     * script instance for all
+     * properties, targets and references of the current project.
+     * It this is false, only the project and self variables will
+     * be set.
+     * The default is true.
+     * @param setBeans the value to set.
+     */
+    public void setSetBeans(boolean setBeans) {
+        this.setBeans = setBeans;
+    }
+
+    /**
+     * Used when called by scriptdef.
+     * @param loader the loader used by scriptdef.
+     */
+    public void setClassLoader(ClassLoader loader) {
+        scriptLoader = loader;
+    }
+
+    private synchronized ClassLoader generateClassLoader() {
+        if (scriptLoader != null) {
+            return scriptLoader;
+        }
+        if (cpDelegate == null) {
+            scriptLoader = getClass().getClassLoader();
+            return scriptLoader;
+        }
+        scriptLoader = cpDelegate.getClassLoader();
+        return scriptLoader;
+    }
+
+    private ClasspathUtils.Delegate getClassPathDelegate() {
+        if (cpDelegate == null) {
+            cpDelegate = ClasspathUtils.getDelegate(projectComponent);
+        }
+        return cpDelegate;
+    }
+
+    /**
+     * Get a script runner.
+     */
+    private ScriptRunnerBase getRunner() {
+        return new ScriptRunnerCreator(projectComponent.getProject()).createRunner(
+                manager, language, generateClassLoader());
+    }
+
+    /**
+     * Add any source resource.
+     *
+     * @param resource source of script
+     * @since Ant 1.7.1
+     */
+    public void add(ResourceCollection resource) {
+        resources.add(resource);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/SourceFileScanner.java b/trunk/src/main/org/apache/tools/ant/util/SourceFileScanner.java
new file mode 100644
index 0000000..e986987
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/SourceFileScanner.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.util.Vector;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * Utility class that collects the functionality of the various
+ * scanDir methods that have been scattered in several tasks before.
+ *
+ * <p>The only method returns an array of source files. The array is a
+ * subset of the files given as a parameter and holds only those that
+ * are newer than their corresponding target files.</p>
+ *
+ */
+public class SourceFileScanner implements ResourceFactory {
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected Task task;
+    // CheckStyle:VisibilityModifier ON
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private File destDir;     // base directory of the fileset
+
+    /**
+     * Construct a new SourceFileScanner.
+     * @param task The task we should log messages through.
+     */
+    public SourceFileScanner(Task task) {
+        this.task = task;
+    }
+
+    /**
+     * Restrict the given set of files to those that are newer than
+     * their corresponding target files.
+     *
+     * @param files   the original set of files.
+     * @param srcDir  all files are relative to this directory.
+     * @param destDir target files live here. if null file names
+     *                returned by the mapper are assumed to be absolute.
+     * @param mapper  knows how to construct a target file names from
+     *                source file names.
+     * @return an array of filenames.
+     */
+    public String[] restrict(String[] files, File srcDir, File destDir,
+                             FileNameMapper mapper) {
+        return restrict(files, srcDir, destDir, mapper,
+                        FILE_UTILS.getFileTimestampGranularity());
+    }
+
+    /**
+     * Restrict the given set of files to those that are newer than
+     * their corresponding target files.
+     *
+     * @param files   the original set of files.
+     * @param srcDir  all files are relative to this directory.
+     * @param destDir target files live here. If null file names
+     *                returned by the mapper are assumed to be absolute.
+     * @param mapper  knows how to construct a target file names from
+     *                source file names.
+     * @param granularity The number of milliseconds leeway to give
+     *                    before deciding a target is out of date.
+     * @return an array of filenames.
+     *
+     * @since Ant 1.6.2
+     */
+    public String[] restrict(String[] files, File srcDir, File destDir,
+                             FileNameMapper mapper, long granularity) {
+        // record destdir for later use in getResource
+        this.destDir = destDir;
+        Vector v = new Vector();
+        for (int i = 0; i < files.length; i++) {
+            final String name = files[i];
+            v.addElement(new FileResource(srcDir, name) {
+                public String getName() {
+                    return name;
+                }
+            });
+        }
+        Resource[] sourceresources = new Resource[v.size()];
+        v.copyInto(sourceresources);
+
+        // build the list of sources which are out of date with
+        // respect to the target
+        Resource[] outofdate =
+            ResourceUtils.selectOutOfDateSources(task, sourceresources,
+                                                 mapper, this, granularity);
+        String[] result = new String[outofdate.length];
+        for (int counter = 0; counter < outofdate.length; counter++) {
+            result[counter] = outofdate[counter].getName();
+        }
+        return result;
+    }
+
+    /**
+     * Convenience layer on top of restrict that returns the source
+     * files as File objects (containing absolute paths if srcDir is
+     * absolute).
+     * @param files   the original set of files.
+     * @param srcDir  all files are relative to this directory.
+     * @param destDir target files live here. If null file names
+     *                returned by the mapper are assumed to be absolute.
+     * @param mapper  knows how to construct a target file names from
+     *                source file names.
+     * @return an array of files.
+     */
+    public File[] restrictAsFiles(String[] files, File srcDir, File destDir,
+                                  FileNameMapper mapper) {
+        return restrictAsFiles(files, srcDir, destDir, mapper,
+                               FILE_UTILS.getFileTimestampGranularity());
+    }
+
+    /**
+     * Convenience layer on top of restrict that returns the source
+     * files as File objects (containing absolute paths if srcDir is
+     * absolute).
+     *
+     * @param files   the original set of files.
+     * @param srcDir  all files are relative to this directory.
+     * @param destDir target files live here. If null file names
+     *                returned by the mapper are assumed to be absolute.
+     * @param mapper  knows how to construct a target file names from
+     *                source file names.
+     * @param granularity The number of milliseconds leeway to give
+     *                    before deciding a target is out of date.
+     * @return an array of files.
+     * @since Ant 1.6.2
+     */
+    public File[] restrictAsFiles(String[] files, File srcDir, File destDir,
+                                  FileNameMapper mapper, long granularity) {
+        String[] res = restrict(files, srcDir, destDir, mapper, granularity);
+        File[] result = new File[res.length];
+        for (int i = 0; i < res.length; i++) {
+            result[i] = new File(srcDir, res[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Returns resource information for a file at destination.
+     * @param name relative path of file at destination.
+     * @return data concerning a file whose relative path to destDir is name.
+     *
+     * @since Ant 1.5.2
+     */
+    public Resource getResource(String name) {
+        return new FileResource(destDir, name);
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/StringTokenizer.java b/trunk/src/main/org/apache/tools/ant/util/StringTokenizer.java
new file mode 100644
index 0000000..ef91ff6
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/StringTokenizer.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.Reader;
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Class to tokenize the input as areas separated
+ * by white space, or by a specified list of
+ * delim characters. Behaves like java.util.StringTokenizer.
+ * If the stream starts with delim characters, the first
+ * token will be an empty string (unless the treat delims
+ * as tokens flag is set).
+ * @since Ant 1.7
+ */
+public class StringTokenizer extends ProjectComponent implements Tokenizer {
+    private static final int NOT_A_CHAR = -2;
+    private String intraString = "";
+    private int    pushed = NOT_A_CHAR;
+    private char[] delims = null;
+    private boolean delimsAreTokens = false;
+    private boolean suppressDelims = false;
+    private boolean includeDelims = false;
+
+    /**
+     * attribute delims - the delimiter characters
+     * @param delims a string containing the delimiter characters
+     */
+    public void setDelims(String delims) {
+        this.delims = StringUtils.resolveBackSlash(delims).toCharArray();
+    }
+
+    /**
+     * attribute delimsaretokens - treat delimiters as
+     * separate tokens.
+     * @param delimsAreTokens true if delimiters are to be separate
+     */
+
+    public void setDelimsAreTokens(boolean delimsAreTokens) {
+        this.delimsAreTokens = delimsAreTokens;
+    }
+    /**
+     * attribute suppressdelims - suppress delimiters.
+     * default - false
+     * @param suppressDelims if true do not report delimiters
+     */
+    public void setSuppressDelims(boolean suppressDelims) {
+        this.suppressDelims = suppressDelims;
+    }
+
+    /**
+     * attribute includedelims - treat delimiters as part
+     * of the token.
+     * default - false
+     * @param includeDelims if true add delimiters to the token
+     */
+    public void setIncludeDelims(boolean includeDelims) {
+        this.includeDelims = includeDelims;
+    }
+
+    /**
+     * find and return the next token
+     *
+     * @param in the input stream
+     * @return the token
+     * @exception IOException if an error occurs reading
+     */
+    public String getToken(Reader in) throws IOException {
+        int ch = -1;
+        if (pushed != NOT_A_CHAR) {
+            ch = pushed;
+            pushed = NOT_A_CHAR;
+        } else {
+            ch = in.read();
+        }
+        if (ch == -1) {
+            return null;
+        }
+        boolean inToken = true;
+        intraString = "";
+        StringBuffer word = new StringBuffer();
+        StringBuffer padding = new StringBuffer();
+        while (ch != -1) {
+            char c = (char) ch;
+            boolean isDelim = isDelim(c);
+            if (inToken) {
+                if (isDelim) {
+                    if (delimsAreTokens) {
+                        if (word.length() == 0) {
+                            word.append(c);
+                        } else {
+                            pushed = ch;
+                        }
+                        break;
+                    }
+                    padding.append(c);
+                    inToken = false;
+                } else {
+                    word.append(c);
+                }
+            } else {
+                if (isDelim) {
+                    padding.append(c);
+                } else {
+                    pushed = ch;
+                    break;
+                }
+            }
+            ch = in.read();
+        }
+        intraString = padding.toString();
+        if (includeDelims) {
+            word.append(intraString);
+        }
+        return word.toString();
+    }
+
+    /**
+     * @return the intratoken string
+     */
+    public String getPostToken() {
+        return suppressDelims || includeDelims ? "" : intraString;
+    }
+
+    private boolean isDelim(char ch) {
+        if (delims == null) {
+            return Character.isWhitespace(ch);
+        }
+        for (int i = 0; i < delims.length; ++i) {
+            if (delims[i] == ch) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/StringUtils.java b/trunk/src/main/org/apache/tools/ant/util/StringUtils.java
new file mode 100644
index 0000000..6fd84b2
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/StringUtils.java
@@ -0,0 +1,274 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Vector;
+
+/**
+ * A set of helper methods related to string manipulation.
+ *
+ */
+public final class StringUtils {
+    private static final long KILOBYTE = 1024;
+    private static final long MEGABYTE = KILOBYTE * 1024;
+    private static final long GIGABYTE = MEGABYTE * 1024;
+    private static final long TERABYTE = GIGABYTE * 1024;
+    private static final long PETABYTE = TERABYTE * 1024;
+
+    /**
+     * constructor to stop anyone instantiating the class
+     */
+    private StringUtils() {
+    }
+
+    /** the line separator for this OS */
+    public static final String LINE_SEP = System.getProperty("line.separator");
+
+    /**
+     * Splits up a string into a list of lines. It is equivalent
+     * to <tt>split(data, '\n')</tt>.
+     * @param data the string to split up into lines.
+     * @return the list of lines available in the string.
+     */
+    public static Vector lineSplit(String data) {
+        return split(data, '\n');
+    }
+
+    /**
+     * Splits up a string where elements are separated by a specific
+     * character and return all elements.
+     * @param data the string to split up.
+     * @param ch the separator character.
+     * @return the list of elements.
+     */
+    public static Vector split(String data, int ch) {
+        Vector elems = new Vector();
+        int pos = -1;
+        int i = 0;
+        while ((pos = data.indexOf(ch, i)) != -1) {
+            String elem = data.substring(i, pos);
+            elems.addElement(elem);
+            i = pos + 1;
+        }
+        elems.addElement(data.substring(i));
+        return elems;
+    }
+
+    /**
+     * Replace occurrences into a string.
+     * @param data the string to replace occurrences into
+     * @param from the occurrence to replace.
+     * @param to the occurrence to be used as a replacement.
+     * @return the new string with replaced occurrences.
+     */
+    public static String replace(String data, String from, String to) {
+        StringBuffer buf = new StringBuffer(data.length());
+        int pos = -1;
+        int i = 0;
+        while ((pos = data.indexOf(from, i)) != -1) {
+            buf.append(data.substring(i, pos)).append(to);
+            i = pos + from.length();
+        }
+        buf.append(data.substring(i));
+        return buf.toString();
+    }
+
+    /**
+     * Convenient method to retrieve the full stacktrace from a given exception.
+     * @param t the exception to get the stacktrace from.
+     * @return the stacktrace from the given exception.
+     */
+    public static String getStackTrace(Throwable t) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw, true);
+        t.printStackTrace(pw);
+        pw.flush();
+        pw.close();
+        return sw.toString();
+    }
+
+    /**
+     * Checks that a string buffer ends up with a given string. It may sound
+     * trivial with the existing
+     * JDK API but the various implementation among JDKs can make those
+     * methods extremely resource intensive
+     * and perform poorly due to massive memory allocation and copying. See
+     * @param buffer the buffer to perform the check on
+     * @param suffix the suffix
+     * @return  <code>true</code> if the character sequence represented by the
+     *          argument is a suffix of the character sequence represented by
+     *          the StringBuffer object; <code>false</code> otherwise. Note that the
+     *          result will be <code>true</code> if the argument is the
+     *          empty string.
+     */
+    public static boolean endsWith(StringBuffer buffer, String suffix) {
+        if (suffix.length() > buffer.length()) {
+            return false;
+        }
+        // this loop is done on purpose to avoid memory allocation performance
+        // problems on various JDKs
+        // StringBuffer.lastIndexOf() was introduced in jdk 1.4 and
+        // implementation is ok though does allocation/copying
+        // StringBuffer.toString().endsWith() does massive memory
+        // allocation/copying on JDK 1.5
+        // See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169
+        int endIndex = suffix.length() - 1;
+        int bufferIndex = buffer.length() - 1;
+        while (endIndex >= 0) {
+            if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) {
+                return false;
+            }
+            bufferIndex--;
+            endIndex--;
+        }
+        return true;
+    }
+
+    /**
+     * xml does not do "c" like interpretation of strings.
+     * i.e. \n\r\t etc.
+     * this method processes \n, \r, \t, \f, \\
+     * also subs \s -> " \n\r\t\f"
+     * a trailing '\' will be ignored
+     *
+     * @param input raw string with possible embedded '\'s
+     * @return converted string
+     * @since Ant 1.7
+     */
+    public static String resolveBackSlash(String input) {
+        StringBuffer b = new StringBuffer();
+        boolean backSlashSeen = false;
+        for (int i = 0; i < input.length(); ++i) {
+            char c = input.charAt(i);
+            if (!backSlashSeen) {
+                if (c == '\\') {
+                    backSlashSeen = true;
+                } else {
+                    b.append(c);
+                }
+            } else {
+                switch (c) {
+                    case '\\':
+                        b.append((char) '\\');
+                        break;
+                    case 'n':
+                        b.append((char) '\n');
+                        break;
+                    case 'r':
+                        b.append((char) '\r');
+                        break;
+                    case 't':
+                        b.append((char) '\t');
+                        break;
+                    case 'f':
+                        b.append((char) '\f');
+                        break;
+                    case 's':
+                        b.append(" \t\n\r\f");
+                        break;
+                    default:
+                        b.append(c);
+                }
+                backSlashSeen = false;
+            }
+        }
+        return b.toString();
+    }
+
+    /**
+     * Takes a human readable size representation eg 10K
+     * a long value. Doesn't support 1.1K or other rational values.
+     * @param humanSize the amount as a human readable string.
+     * @return a long value representation
+     * @throws Exception if there is a problem.
+     * @since Ant 1.7
+     */
+    public static long parseHumanSizes(String humanSize) throws Exception {
+        long factor = 1L;
+        char s = humanSize.charAt(0);
+        switch (s) {
+            case '+':
+                humanSize = humanSize.substring(1);
+                break;
+            case '-':
+                factor = -1L;
+                humanSize = humanSize.substring(1);
+                break;
+            default:
+                break;
+        }
+        //last character isn't a digit
+        char c = humanSize.charAt(humanSize.length() - 1);
+        if (!Character.isDigit(c)) {
+            int trim = 1;
+            switch (c) {
+                case 'K':
+                    factor *= KILOBYTE;
+                    break;
+                case 'M':
+                    factor *= MEGABYTE;
+                    break;
+                case 'G':
+                    factor *= GIGABYTE;
+                    break;
+                case 'T':
+                    factor *= TERABYTE;
+                    break;
+                case 'P':
+                    factor *= PETABYTE;
+                    break;
+                default:
+                    trim = 0;
+            }
+            humanSize = humanSize.substring(0, humanSize.length() - trim);
+        }
+        return factor * Long.parseLong(humanSize);
+    }
+
+    /**
+     * Removes the suffix from a given string, if the string contains
+     * that suffix.
+     * @param string String for check
+     * @param suffix Suffix to remove
+     * @return the <i>string</i> with the <i>suffix</i>
+     */
+    public static String removeSuffix(String string, String suffix) {
+        if (string.endsWith(suffix)) {
+            return string.substring(0, string.length() - suffix.length());
+        } else {
+            return string;
+        }
+    }
+
+    /**
+     * Removes the prefix from a given string, if the string contains
+     * that prefix.
+     * @param string String for check
+     * @param prefix Prefix to remove
+     * @return the <i>string</i> with the <i>prefix</i>
+     */
+    public static String removePrefix(String string, String prefix) {
+        if (string.startsWith(prefix)) {
+            return string.substring(prefix.length());
+        } else {
+            return string;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/TaskLogger.java b/trunk/src/main/org/apache/tools/ant/util/TaskLogger.java
new file mode 100644
index 0000000..9ce5c51
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/TaskLogger.java
@@ -0,0 +1,79 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * A facade that makes logging nicer to use.
+ */
+public final class TaskLogger {
+    /**
+     * Task to use to do logging.
+     */
+    private Task task;
+
+    /**
+     * Constructor for the TaskLogger
+     * @param task the task
+     */
+    public TaskLogger(final Task task) {
+        this.task = task;
+    }
+
+    /**
+     * Log a message with <code>MSG_INFO</code> priority
+     * @param message the message to log
+     */
+    public void info(final String message) {
+        task.log(message, Project.MSG_INFO);
+    }
+
+    /**
+     * Log a message with <code>MSG_ERR</code> priority
+     * @param message the message to log
+     */
+    public void error(final String message) {
+        task.log(message, Project.MSG_ERR);
+    }
+
+    /**
+     * Log a message with <code>MSG_WARN</code> priority
+     * @param message the message to log
+     */
+    public void warning(final String message) {
+        task.log(message, Project.MSG_WARN);
+    }
+
+    /**
+     * Log a message with <code>MSG_VERBOSE</code> priority
+     * @param message the message to log
+     */
+    public void verbose(final String message) {
+        task.log(message, Project.MSG_VERBOSE);
+    }
+
+    /**
+     * Log a message with <code>MSG_DEBUG</code> priority
+     * @param message the message to log
+     */
+    public void debug(final String message) {
+        task.log(message, Project.MSG_DEBUG);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/TeeOutputStream.java b/trunk/src/main/org/apache/tools/ant/util/TeeOutputStream.java
new file mode 100644
index 0000000..7daf11f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/TeeOutputStream.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * A simple T-piece to replicate an output stream into two separate streams
+ *
+ */
+public class TeeOutputStream extends OutputStream {
+    private OutputStream left;
+    private OutputStream right;
+
+    /**
+     * Constructor for TeeOutputStream.
+     * @param left one of the output streams.
+     * @param right the other output stream.
+     */
+    public TeeOutputStream(OutputStream left, OutputStream right) {
+        this.left = left;
+        this.right = right;
+    }
+
+    /**
+     * Close both output streams.
+     * @throws IOException on error.
+     */
+    public void close() throws IOException {
+        try {
+            left.close();
+        } finally {
+            right.close();
+        }
+    }
+
+    /**
+     * Flush both output streams.
+     * @throws IOException on error
+     */
+    public void flush() throws IOException {
+        left.flush();
+        right.flush();
+    }
+
+    /**
+     * Write a byte array to both output streams.
+     * @param b an array of bytes.
+     * @throws IOException on error.
+     */
+    public void write(byte[] b) throws IOException {
+        left.write(b);
+        right.write(b);
+    }
+
+    /**
+     * Write a byte array to both output streams.
+     * @param b     the data.
+     * @param off   the start offset in the data.
+     * @param len   the number of bytes to write.
+     * @throws IOException on error.
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        left.write(b, off, len);
+        right.write(b, off, len);
+    }
+
+    /**
+     * Write a byte to both output streams.
+     * @param b the byte to write.
+     * @throws IOException on error.
+     */
+    public void write(int b) throws IOException {
+        left.write(b);
+        right.write(b);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/TimeoutObserver.java b/trunk/src/main/org/apache/tools/ant/util/TimeoutObserver.java
new file mode 100644
index 0000000..ba2e0c7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/TimeoutObserver.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+/**
+ * Interface for classes that want to be notified by Watchdog.
+ *
+ * @since Ant 1.5
+ *
+ * @see org.apache.tools.ant.util.Watchdog
+ *
+ */
+public interface TimeoutObserver {
+
+    /**
+     * Called when the watchdow times out.
+     *
+     * @param w the watchdog that timed out.
+     */
+    void timeoutOccured(Watchdog w);
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/Tokenizer.java b/trunk/src/main/org/apache/tools/ant/util/Tokenizer.java
new file mode 100644
index 0000000..dc9407c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/Tokenizer.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.Reader;
+import java.io.IOException;
+
+/**
+ * input stream tokenizers implement this interface
+ *
+ * @version Ant 1.6
+ */
+public interface Tokenizer {
+    /**
+     * get the next token from the input stream
+     * @param in the input stream
+     * @return the next token, or null for the end
+     *         of the stream
+     * @throws IOException if an error occurs
+     */
+    String getToken(Reader in) throws IOException;
+
+    /**
+     * return the string between tokens, after the
+     * previous token.
+     * @return the intra-token string
+     */
+    String getPostToken();
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/UUEncoder.java b/trunk/src/main/org/apache/tools/ant/util/UUEncoder.java
new file mode 100644
index 0000000..666b422
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/UUEncoder.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * UUEncoding of an input stream placed into an outputstream.
+ * This class is meant to be a drop in replacement for
+ * sun.misc.UUEncoder, which was previously used by Ant.
+ * The uuencode algorithm code has been copied from the
+ * geronimo project.
+ **/
+
+public class UUEncoder {
+    protected static final int DEFAULT_MODE = 644;
+    private static final int MAX_CHARS_PER_LINE = 45;
+    private static final int INPUT_BUFFER_SIZE = MAX_CHARS_PER_LINE * 100;
+    private OutputStream out;
+    private String name;
+
+    /**
+     * Constructor specifing a name for the encoded buffer, begin
+     * line will be:
+     * <pre>
+     *   begin 644 [NAME]
+     * </pre>
+     * @param name the name of the encoded buffer.
+     */
+    public UUEncoder(String name) {
+        this.name = name;
+    }
+
+    /**
+     * UUEncode bytes from the input stream, and write them as text characters
+     * to the output stream. This method will run until it exhausts the
+     * input stream.
+     * @param is the input stream.
+     * @param out the output stream.
+     * @throws IOException if there is an error.
+     */
+    public void encode(InputStream is, OutputStream out)
+        throws IOException {
+        this.out = out;
+        encodeBegin();
+        byte[] buffer = new byte[INPUT_BUFFER_SIZE];
+        int count;
+        while ((count = is.read(buffer, 0, buffer.length)) != -1) {
+            int pos = 0;
+            while (count > 0) {
+                int num = count > MAX_CHARS_PER_LINE
+                    ? MAX_CHARS_PER_LINE
+                    : count;
+                encodeLine(buffer, pos, num, out);
+                pos += num;
+                count -= num;
+            }
+        }
+        out.flush();
+        encodeEnd();
+    }
+
+    /**
+     * Encode a string to the output.
+     */
+    private void encodeString(String n) throws IOException {
+        PrintStream writer = new PrintStream(out);
+        writer.print(n);
+        writer.flush();
+    }
+
+    private void encodeBegin() throws IOException {
+        encodeString("begin " + DEFAULT_MODE + " " + name + "\n");
+    }
+
+    private void encodeEnd() throws IOException {
+        encodeString(" \nend\n");
+    }
+
+    /**
+     * Encode a single line of data (less than or equal to 45 characters).
+     *
+     * @param data   The array of byte data.
+     * @param off    The starting offset within the data.
+     * @param length Length of the data to encode.
+     * @param out    The output stream the encoded data is written to.
+     *
+     * @exception IOException
+     */
+    private void encodeLine(
+        byte[] data, int offset, int length, OutputStream out)
+        throws IOException {
+        // write out the number of characters encoded in this line.
+        // CheckStyle:MagicNumber OFF
+        out.write((byte) ((length & 0x3F) + ' '));
+        // CheckStyle:MagicNumber ON
+        byte a;
+        byte b;
+        byte c;
+
+        for (int i = 0; i < length;) {
+            // set the padding defaults
+            b = 1;
+            c = 1;
+            // get the next 3 bytes (if we have them)
+            a = data[offset + i++];
+            if (i < length) {
+                b = data[offset + i++];
+                if (i < length) {
+                    c = data[offset + i++];
+                }
+            }
+
+            // CheckStyle:MagicNumber OFF
+            byte d1 = (byte) (((a >>> 2) & 0x3F) + ' ');
+            byte d2 = (byte) ((((a << 4) & 0x30) | ((b >>> 4) & 0x0F)) + ' ');
+            byte d3 = (byte) ((((b << 2) & 0x3C) | ((c >>> 6) & 0x3)) + ' ');
+            byte d4 = (byte) ((c & 0x3F) + ' ');
+            // CheckStyle:MagicNumber ON
+
+            out.write(d1);
+            out.write(d2);
+            out.write(d3);
+            out.write(d4);
+        }
+
+        // terminate with a linefeed alone
+        out.write('\n');
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java b/trunk/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java
new file mode 100644
index 0000000..1777279
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+
+/**
+ * Maps dotted package name matches to a directory name.
+ * This is the inverse of the package mapper.
+ * This is useful for matching XML formatter results against their JUnit test
+ * cases.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.UnPackageNameMapper"
+ *         from="${test.data.dir}/TEST-*Test.xml" to="*Test.java"&gt;
+ * </pre>
+ *
+ *
+ */
+public class UnPackageNameMapper extends GlobPatternMapper {
+    /**
+     *  Returns the part of the given string that matches the * in the
+     *  &quot;from&quot; pattern replacing dots with file separators
+     *
+     *@param  name  Source filename
+     *@return       Replaced variable part
+     */
+    protected String extractVariablePart(String name) {
+        String var = name.substring(prefixLength,
+                name.length() - postfixLength);
+        return var.replace('.', File.separatorChar);
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/Watchdog.java b/trunk/src/main/org/apache/tools/ant/util/Watchdog.java
new file mode 100644
index 0000000..393bc7b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/Watchdog.java
@@ -0,0 +1,128 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Generalization of <code>ExecuteWatchdog</code>
+ *
+ * @since Ant 1.5
+ *
+ * @see org.apache.tools.ant.taskdefs.ExecuteWatchdog
+ *
+ */
+public class Watchdog implements Runnable {
+
+    private Vector observers = new Vector(1);
+    private long timeout = -1;
+    /**
+     * marked as volatile to stop the compiler caching values or (in java1.5+,
+     * reordering access)
+     */
+    private volatile boolean stopped = false;
+    /**
+     * Error string.
+     * {@value}
+     */
+    public static final String ERROR_INVALID_TIMEOUT = "timeout less than 1.";
+
+    /**
+     * Constructor for Watchdog.
+     * @param timeout the timeout to use in milliseconds (must be >= 1).
+     */
+    public Watchdog(long timeout) {
+        if (timeout < 1) {
+            throw new IllegalArgumentException(ERROR_INVALID_TIMEOUT);
+        }
+        this.timeout = timeout;
+    }
+
+    /**
+     * Add a timeout observer.
+     * @param to the timeout observer to add.
+     */
+    public void addTimeoutObserver(TimeoutObserver to) {
+        //no need to synchronize, as Vector is always synchronized
+        observers.addElement(to);
+    }
+
+    /**
+     * Remove a timeout observer.
+     * @param to the timeout observer to remove.
+     */
+    public void removeTimeoutObserver(TimeoutObserver to) {
+        //no need to synchronize, as Vector is always synchronized
+        observers.removeElement(to);
+    }
+
+    /**
+     * Inform the observers that a timeout has occurred.
+     * This happens in the watchdog thread.
+     */
+    protected final void fireTimeoutOccured() {
+        Enumeration e = observers.elements();
+        while (e.hasMoreElements()) {
+            ((TimeoutObserver) e.nextElement()).timeoutOccured(this);
+        }
+    }
+
+    /**
+     * Start the watch dog.
+     */
+    public synchronized void start() {
+        stopped = false;
+        Thread t = new Thread(this, "WATCHDOG");
+        t.setDaemon(true);
+        t.start();
+    }
+
+    /**
+     * Stop the watch dog.
+     */
+    public synchronized void stop() {
+        stopped = true;
+        notifyAll();
+    }
+
+    /**
+     * The run method of the watch dog thread.
+     * This simply does a wait for the timeout time, and
+     * if the stop flag has not been set when the wait has returned or
+     * has been interrupted, the watch dog listeners are informed.
+     */
+    public synchronized void run() {
+        long now = System.currentTimeMillis();
+        final long until = now + timeout;
+
+        try {
+            while (!stopped && until > now) {
+                wait(until - now);
+                now = System.currentTimeMillis();
+            }
+        } catch (InterruptedException e) {
+            // Ignore exception
+        }
+        if (!stopped) {
+            fireTimeoutOccured();
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/WeakishReference.java b/trunk/src/main/org/apache/tools/ant/util/WeakishReference.java
new file mode 100644
index 0000000..92f322f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/WeakishReference.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+
+import java.lang.ref.WeakReference;
+
+/**
+ * These classes are part of some code to reduce memory leaks by only
+ * retaining weak references to things
+ * on Java1.2+, and yet still work (with leaky hard references) on Java1.1.
+ * Now that Ant is 1.2+ only,
+ * life is simpler and none of the classes are needed any more.
+ *
+ * They are only retained in case a third-party task uses them
+ * @since ant1.6
+ * @see org.apache.tools.ant.util.optional.WeakishReference12
+ * @deprecated deprecated 1.7; will be removed in Ant1.8
+ *             Just use {@link java.lang.ref.WeakReference} directly.
+ */
+public class WeakishReference  {
+
+
+    private WeakReference weakref;
+
+    /**
+     * create a new soft reference, which is bound to a
+     * Weak reference inside
+     *
+     * @param reference
+     * @see java.lang.ref.WeakReference
+     */
+    WeakishReference(Object reference) {
+        this.weakref = new WeakReference(reference);
+    }
+
+    /**
+     * Returns this reference object's referent.  If this reference object has
+     * been cleared, then this method returns <code>null</code>.
+     *
+     * @return The object to which this reference refers, or
+     *         <code>null</code> if this reference object has been cleared.
+     */
+    public Object get() {
+        return weakref.get();
+    }
+
+    /**
+     * create the appropriate type of reference for the java version
+     * @param object the object that the reference will refer to.
+     * @return reference to the Object.
+     */
+    public static WeakishReference createReference(Object object) {
+            return new WeakishReference(object);
+    }
+
+
+    /**
+     * This was a hard reference for Java 1.1. Since Ant1.7,
+     * @deprecated since 1.7.
+     *             Hopefully nobody is using this.
+     */
+    public static class HardReference extends WeakishReference {
+
+        /**
+         * constructor.
+         * @param object the object that the reference will refer to.
+         */
+        public HardReference(Object object) {
+            super(object);
+        }
+
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/WorkerAnt.java b/trunk/src/main/org/apache/tools/ant/util/WorkerAnt.java
new file mode 100644
index 0000000..9a6b4d8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/WorkerAnt.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * A worker ant executes a single task in a background thread.
+ * After the run, any exception thrown is turned into a buildexception, which can be
+ * rethrown, the finished attribute is set, then notifyAll() is called,
+ * so that anyone waiting on the same notify object gets woken up.
+ * </p>
+ * This class is effectively a superset of
+ * {@link org.apache.tools.ant.taskdefs.Parallel.TaskRunnable}
+ *
+ * @since Ant 1.8
+ */
+
+public class WorkerAnt extends Thread {
+
+    private Task task;
+    private Object notify;
+    private volatile boolean finished = false;
+    private volatile BuildException buildException;
+    private volatile Throwable exception;
+
+    /**
+     * Error message if invoked with no task
+     */
+    public static final String ERROR_NO_TASK = "No task defined";
+
+
+    /**
+     * Create the worker.
+     * <p/>
+     * This does not start the thread, merely configures it.
+     * @param task the task
+     * @param notify what to notify
+     */
+    public WorkerAnt(Task task, Object notify) {
+        this.task = task;
+        this.notify = notify != null ? notify : this;
+    }
+
+    /**
+     * Create the worker, using the worker as the notification point.
+     * <p/>
+     * This does not start the thread, merely configures it.
+     * @param task the task
+     */
+    public WorkerAnt(Task task) {
+        this(task, null);
+    }
+
+    /**
+     * Get any build exception.
+     * This would seem to be oversynchronised, but know that Java pre-1.5 can
+     * reorder volatile access.
+     * The synchronized attribute is to force an ordering.
+     *
+     * @return the exception or null
+     */
+    public synchronized BuildException getBuildException() {
+        return buildException;
+    }
+
+    /**
+     * Get whatever was thrown, which may or may not be a buildException.
+     * Assertion: getException() instanceof BuildException <=> getBuildException()==getException()
+     * @return the exception.
+     */
+    public synchronized Throwable getException() {
+        return exception;
+    }
+
+
+    /**
+     * Get the task
+     * @return the task
+     */
+    public Task getTask() {
+        return task;
+    }
+
+
+    /**
+     * Query the task/thread for being finished.
+     * This would seem to be oversynchronised, but know that Java pre-1.5 can
+     * reorder volatile access.
+     * The synchronized attribute is to force an ordering.
+     * @return true if the task is finished.
+     */
+    public synchronized boolean isFinished() {
+        return finished;
+    }
+
+    /**
+     * Block on the notify object and so wait until the thread is finished.
+     * @param timeout timeout in milliseconds
+     * @throws InterruptedException if the execution was interrupted
+     */
+    public void waitUntilFinished(long timeout) throws InterruptedException {
+        synchronized (notify) {
+            if (!finished) {
+                notify.wait(timeout);
+            }
+        }
+    }
+
+    /**
+     * Raise an exception if one was caught
+     *
+     * @throws BuildException if one has been picked up
+     */
+    public void rethrowAnyBuildException() {
+        BuildException ex = getBuildException();
+        if (ex != null) {
+            throw ex;
+        }
+    }
+
+
+    /**
+     * Handle a caught exception, by recording it and possibly wrapping it
+     * in a BuildException for later rethrowing.
+     * @param thrown what was caught earlier
+     */
+    private synchronized void caught(Throwable thrown) {
+        exception = thrown;
+        buildException = (thrown instanceof BuildException)
+            ? (BuildException) thrown
+            : new BuildException(thrown);
+    }
+
+    /**
+     * Run the task, which is skipped if null.
+     * When invoked again, the task is re-run.
+     */
+    public void run() {
+        try {
+            if (task != null) {
+                task.execute();
+            }
+        } catch (Throwable thrown) {
+            caught(thrown);
+        } finally {
+            synchronized (notify) {
+                finished = true;
+                //reset the task.
+                //wake up our owner, if it is waiting
+                notify.notifyAll();
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/XMLFragment.java b/trunk/src/main/org/apache/tools/ant/util/XMLFragment.java
new file mode 100644
index 0000000..1f21a3a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/XMLFragment.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.apache.tools.ant.DynamicElementNS;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.DynamicConfiguratorNS;
+
+/**
+ * Use this class as a nested element if you want to get a literal DOM
+ * fragment of something nested into your task/type.
+ *
+ * <p>This is useful for tasks that want to deal with the "real" XML
+ * from the build file instead of objects.</p>
+ *
+ * <p>Code heavily influenced by code written by Dominique Devienne.</p>
+ *
+ * @since Ant 1.7
+ */
+public class XMLFragment extends ProjectComponent implements DynamicElementNS {
+
+    private Document doc;
+    private DocumentFragment fragment;
+
+    /**
+     * Constructor for XMLFragment object.
+     */
+    public XMLFragment() {
+        doc = JAXPUtils.getDocumentBuilder().newDocument();
+        fragment = doc.createDocumentFragment();
+    }
+
+    /**
+     * @return the DocumentFragment that corresponds to the nested
+     *          structure.
+     */
+    public DocumentFragment getFragment() {
+        return fragment;
+    }
+
+    /**
+     * Add nested text, expanding properties as we go
+     * @param s the text to add
+     */
+    public void addText(String s) {
+        addText(fragment, s);
+    }
+
+    /**
+     * Creates a nested element.
+     * @param uri the uri of the nested element
+     * @param name the localname of the nested element
+     * @param qName the qualified name of the nested element
+     * @return an object that the element is applied to
+     */
+    public Object createDynamicElement(String uri, String name, String qName) {
+        Element e = null;
+        if (uri.equals("")) {
+            e = doc.createElement(name);
+        } else {
+            e = doc.createElementNS(uri, qName);
+        }
+        fragment.appendChild(e);
+        return new Child(e);
+    }
+
+    /**
+     * Add text to a node.
+     * @param n node
+     * @param s value
+     */
+    private void addText(Node n, String s) {
+        s = getProject().replaceProperties(s);
+        //only text nodes that are non null after property expansion are added
+        if (s != null && !s.trim().equals("")) {
+            Text t = doc.createTextNode(s.trim());
+            n.appendChild(t);
+        }
+    }
+
+    /**
+     * An object to handle (recursively) nested elements.
+     */
+    public class Child implements DynamicConfiguratorNS {
+        private Element e;
+
+        Child(Element e) {
+            this.e = e;
+        }
+
+        /**
+         * Add nested text.
+         * @param s the text to add
+         */
+        public void addText(String s) {
+            XMLFragment.this.addText(e, s);
+        }
+
+        /**
+         * Sets the attribute
+         * @param uri the uri of the attribute
+         * @param name the localname of the attribute
+         * @param qName the qualified name of the attribute
+         * @param value the value of the attribute
+         */
+        public void setDynamicAttribute(
+            String uri, String name, String qName, String value) {
+            if (uri.equals("")) {
+                e.setAttribute(name, value);
+            } else {
+                e.setAttributeNS(uri, qName, value);
+            }
+        }
+
+        /**
+         * Creates a nested element.
+         * @param uri the uri of the nested element
+         * @param name the localname of the nested element
+         * @param qName the qualified name of the nested element
+         * @return an object that the element is applied to
+         */
+        public Object createDynamicElement(String uri, String name, String qName) {
+            Element e2 = null;
+            if (uri.equals("")) {
+                e2 = doc.createElement(name);
+            } else {
+                e2 = doc.createElementNS(uri, qName);
+            }
+            e.appendChild(e2);
+            return new Child(e2);
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/XmlConstants.java b/trunk/src/main/org/apache/tools/ant/util/XmlConstants.java
new file mode 100644
index 0000000..fdf0343
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/XmlConstants.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+/**
+ * XML Parser constants, all kept in one place for ease of reuse
+ * @see <a href="http://xml.apache.org/xerces-j/features.html">Xerces features</a>
+ * @see <a href="http://xml.apache.org/xerces-j/properties.html">Xerces properties</a>
+ * @see <a href=
+ * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+ * >SAX.</a>
+ */
+
+public class XmlConstants {
+    /** property for location of xml schema */
+    public static final String PROPERTY_SCHEMA_LOCATION =
+            "http://apache.org/xml/properties/schema/external-schemaLocation";
+    /** property for location of no-name schema */
+    public static final String PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION =
+            "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
+    /** property for full validation */
+    public static final String FEATURE_XSD_FULL_VALIDATION =
+            "http://apache.org/xml/features/validation/schema-full-checking";
+    /** property for xsd */
+    public static final String FEATURE_XSD = "http://apache.org/xml/features/validation/schema";
+
+    /** property for validation */
+    public static final String FEATURE_VALIDATION = "http://xml.org/sax/features/validation";
+    /** property for namespace support */
+    public static final String FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces";
+    /** property for schema language */
+    public static final String FEATURE_JAXP12_SCHEMA_LANGUAGE =
+            "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+    /** property for schema source */
+    public static final String FEATURE_JAXP12_SCHEMA_SOURCE =
+            "http://java.sun.com/xml/jaxp/properties/schemaSource";
+    /** the namespace for XML schema */
+    public static final String URI_XSD =
+            "http://www.w3.org/2001/XMLSchema";
+    /** the sax external entities feature */
+    public static final String FEATURE_EXTERNAL_ENTITIES =
+            "http://xml.org/sax/features/external-general-entities";
+    /** the apache.org/xml disalllow doctype decl feature */
+    public static final String FEATURE_DISALLOW_DTD =
+            "http://apache.org/xml/features/disallow-doctype-decl";
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java b/trunk/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
new file mode 100644
index 0000000..312a3ea
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
@@ -0,0 +1,284 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.ZipFile;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * An abstract implementation of the analyzer interface providing support
+ * for the bulk of interface methods.
+ *
+ */
+public abstract class AbstractAnalyzer implements DependencyAnalyzer {
+    /** Maximum number of loops for looking for indirect dependencies. */
+    public static final int MAX_LOOPS = 1000;
+
+    /** The source path for the source files */
+    private Path sourcePath = new Path(null);
+
+    /** The classpath containg dirs and jars of class files */
+    private Path classPath = new Path(null);
+
+    /** The list of root classes */
+    private Vector rootClasses = new Vector();
+
+    /** true if dependencies have been determined */
+    private boolean determined = false;
+
+    /** the list of File objects that the root classes depend upon */
+    private Vector fileDependencies;
+    /** the list of java classes the root classes depend upon */
+    private Vector classDependencies;
+
+    /** true if indirect dependencies should be gathered */
+    private boolean closure = true;
+
+    /** Setup the analyzer */
+    protected AbstractAnalyzer() {
+        reset();
+    }
+
+    /**
+     * Set the closure flag. If this flag is true the analyzer will traverse
+     * all class relationships until it has collected the entire set of
+     * direct and indirect dependencies
+     *
+     * @param closure true if dependencies should be traversed to determine
+     *      indirect dependencies.
+     */
+    public void setClosure(boolean closure) {
+        this.closure = closure;
+    }
+
+    /**
+     * Get the list of files in the file system upon which the root classes
+     * depend. The files will be either the classfiles or jar files upon
+     * which the root classes depend.
+     *
+     * @return an enumeration of File instances.
+     */
+    public Enumeration getFileDependencies() {
+        if (!supportsFileDependencies()) {
+            throw new RuntimeException("File dependencies are not supported "
+                + "by this analyzer");
+        }
+        if (!determined) {
+            determineDependencies(fileDependencies, classDependencies);
+        }
+        return fileDependencies.elements();
+    }
+
+    /**
+     * Get the list of classes upon which root classes depend. This is a
+     * list of Java classnames in dot notation.
+     *
+     * @return an enumeration of Strings, each being the name of a Java
+     *      class in dot notation.
+     */
+    public Enumeration getClassDependencies() {
+        if (!determined) {
+            determineDependencies(fileDependencies, classDependencies);
+        }
+        return classDependencies.elements();
+    }
+
+    /**
+     * Get the file that contains the class definition
+     *
+     * @param classname the name of the required class
+     * @return the file instance, zip or class, containing the
+     *         class or null if the class could not be found.
+     * @exception IOException if the files in the classpath cannot be read.
+     */
+    public File getClassContainer(String classname) throws IOException {
+        String classLocation = classname.replace('.', '/') + ".class";
+        // we look through the classpath elements. If the element is a dir
+        // we look for the file. IF it is a zip, we look for the zip entry
+        return getResourceContainer(classLocation, classPath.list());
+    }
+
+    /**
+     * Get the file that contains the class source.
+     *
+     * @param classname the name of the required class
+     * @return the file instance, zip or java, containing the
+     *         source or null if the source for the class could not be found.
+     * @exception IOException if the files in the sourcepath cannot be read.
+     */
+    public File getSourceContainer(String classname) throws IOException {
+        String sourceLocation = classname.replace('.', '/') + ".java";
+
+        // we look through the source path elements. If the element is a dir
+        // we look for the file. If it is a zip, we look for the zip entry.
+        // This isn't normal for source paths but we get it for free
+        return getResourceContainer(sourceLocation, sourcePath.list());
+    }
+
+    /**
+     * Add a source path to the source path used by this analyzer. The
+     * elements in the given path contain the source files for the classes
+     * being analyzed. Not all analyzers will use this information.
+     *
+     * @param sourcePath The Path instance specifying the source path
+     *      elements.
+     */
+    public void addSourcePath(Path sourcePath) {
+        if (sourcePath == null) {
+            return;
+        }
+        this.sourcePath.append(sourcePath);
+        this.sourcePath.setProject(sourcePath.getProject());
+    }
+
+    /**
+     * Add a classpath to the classpath being used by the analyzer. The
+     * classpath contains the binary classfiles for the classes being
+     * analyzed The elements may either be the directories or jar files.Not
+     * all analyzers will use this information.
+     *
+     * @param classPath the Path instance specifying the classpath elements
+     */
+    public void addClassPath(Path classPath) {
+        if (classPath == null) {
+            return;
+        }
+
+        this.classPath.append(classPath);
+        this.classPath.setProject(classPath.getProject());
+    }
+
+    /**
+     * Add a root class. The root classes are used to drive the
+     * determination of dependency information. The analyzer will start at
+     * the root classes and add dependencies from there.
+     *
+     * @param className the name of the class in Java dot notation.
+     */
+    public void addRootClass(String className) {
+        if (className == null) {
+            return;
+        }
+        if (!rootClasses.contains(className)) {
+            rootClasses.addElement(className);
+        }
+    }
+
+    /**
+     * Configure an aspect of the analyzer. The set of aspects that are
+     * supported is specific to each analyzer instance.
+     *
+     * @param name the name of the aspect being configured
+     * @param info the configuration info.
+     */
+    public void config(String name, Object info) {
+        // do nothing by default
+    }
+
+    /**
+     * Reset the dependency list. This will reset the determined
+     * dependencies and the also list of root classes.
+     */
+    public void reset() {
+        rootClasses.removeAllElements();
+        determined = false;
+        fileDependencies = new Vector();
+        classDependencies = new Vector();
+    }
+
+    /**
+     * Get an enumeration of the root classes
+     *
+     * @return an enumeration of Strings, each of which is a class name
+     *         for a root class.
+     */
+    protected Enumeration getRootClasses() {
+        return rootClasses.elements();
+    }
+
+    /**
+     * Indicate if the analyzer is required to follow
+     * indirect class relationships.
+     *
+     * @return true if indirect relationships should be followed.
+     */
+    protected boolean isClosureRequired() {
+        return closure;
+    }
+
+    /**
+     * Determine the dependencies of the current set of root classes
+     *
+     * @param files a vector into which Files upon which the root classes
+     *      depend should be placed.
+     * @param classes a vector of Strings into which the names of classes
+     *      upon which the root classes depend should be placed.
+     */
+    protected abstract void determineDependencies(Vector files, Vector classes);
+
+    /**
+     * Indicate if the particular subclass supports file dependency
+     * information.
+     *
+     * @return true if file dependencies are supported.
+     */
+    protected abstract boolean supportsFileDependencies();
+
+    /**
+     * Get the file that contains the resource
+     *
+     * @param resourceLocation the name of the required resource.
+     * @param paths the paths which will be searched for the resource.
+     * @return the file instance, zip or class, containing the
+     *         class or null if the class could not be found.
+     * @exception IOException if the files in the given paths cannot be read.
+     */
+    private File getResourceContainer(String resourceLocation, String[] paths)
+         throws IOException {
+        for (int i = 0; i < paths.length; ++i) {
+            File element = new File(paths[i]);
+            if (!element.exists()) {
+                continue;
+            }
+            if (element.isDirectory()) {
+                File resource = new File(element, resourceLocation);
+                if (resource.exists()) {
+                    return resource;
+                }
+            } else {
+                // must be a zip of some sort
+                ZipFile zipFile = null;
+                try {
+                    zipFile = new ZipFile(element);
+                    if (zipFile.getEntry(resourceLocation) != null) {
+                        return element;
+                    }
+                } finally {
+                    if (zipFile != null) {
+                        zipFile.close();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java b/trunk/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
new file mode 100644
index 0000000..f2d1933
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
@@ -0,0 +1,129 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * A dependency analyzer analyzes dependencies between Java classes to
+ * determine the minimal set of classes which are required by a set of
+ * &quot;root&quot; classes. Different implementations of this interface can
+ * use different strategies and libraries to determine the required set. For
+ * example, some analyzers will use class files while others might use
+ * source files. Analyzer specific configuration is catered for through a
+ * generic configure method
+ *
+ */
+public interface DependencyAnalyzer {
+    /**
+     * Add a source path to the source path used by this analyzer. The
+     * elements in the given path contain the source files for the classes
+     * being analyzed. Not all analyzers will use this information.
+     *
+     * @param sourcePath The Path instance specifying the source path
+     *      elements.
+     */
+    void addSourcePath(Path sourcePath);
+
+    /**
+     * Add a classpath to the classpath being used by the analyzer. The
+     * classpath contains the binary classfiles for the classes being
+     * analyzed The elements may either be the directories or jar files.Not
+     * all analyzers will use this information.
+     *
+     * @param classpath the Path instance specifying the classpath elements
+     */
+    void addClassPath(Path classpath);
+
+    /**
+     * Add a root class. The root classes are used to drive the
+     * determination of dependency information. The analyzer will start at
+     * the root classes and add dependencies from there.
+     *
+     * @param classname the name of the class in Java dot notation.
+     */
+    void addRootClass(String classname);
+
+    /**
+     * Get the list of files in the file system upon which the root classes
+     * depend. The files will be either the classfiles or jar files upon
+     * which the root classes depend.
+     *
+     * @return an enumeration of File instances.
+     */
+    Enumeration getFileDependencies();
+
+    /**
+     * Get the list of classes upon which root classes depend. This is a
+     * list of Java classnames in dot notation.
+     *
+     * @return an enumeration of Strings, each being the name of a Java
+     *      class in dot notation.
+     */
+    Enumeration getClassDependencies();
+
+
+    /**
+     * Reset the dependency list. This will reset the determined
+     * dependencies and the also list of root classes.
+     */
+    void reset();
+
+    /**
+     * Configure an aspect of the analyzer. The set of aspects that are
+     * supported is specific to each analyzer instance.
+     *
+     * @param name the name of the aspect being configured
+     * @param info the configuration information.
+     */
+    void config(String name, Object info);
+
+    /**
+     * Set the closure flag. If this flag is true the analyzer will traverse
+     * all class relationships until it has collected the entire set of
+     * direct and indirect dependencies
+     *
+     * @param closure true if dependencies should be traversed to determine
+     *      indirect dependencies.
+     */
+    void setClosure(boolean closure);
+
+
+    /**
+     * Get the file that contains the class definition
+     *
+     * @param classname the name of the required class
+     * @return the file instance, zip or class, containing the
+     *         class or null if the class could not be found.
+     * @exception IOException if the files in the classpath cannot be read.
+     */
+    File getClassContainer(String classname) throws IOException;
+
+    /**
+     * Get the file that contains the class source.
+     *
+     * @param classname the name of the required class
+     * @return the file instance, zip or java, containing the
+     *         source or null if the source for the class could not be found.
+     * @exception IOException if the files in the sourcepath cannot be read.
+     */
+    File getSourceContainer(String classname) throws IOException;
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
new file mode 100644
index 0000000..8adde6d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
@@ -0,0 +1,138 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * A dependency analyzer which returns superclass and superinterface
+ * dependencies.
+ *
+ */
+public class AncestorAnalyzer extends AbstractAnalyzer {
+
+    /**
+     * Default constructor
+     *
+     * Causes the BCEL classes to load to ensure BCEL dependencies can
+     * be satisfied
+     */
+    public AncestorAnalyzer() {
+        // force BCEL classes to load now
+        try {
+            new ClassParser("force");
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    /**
+     * Determine the dependencies of the configured root classes.
+     *
+     * @param files a vector to be populated with the files which contain
+     *      the dependency classes
+     * @param classes a vector to be populated with the names of the
+     *      depencency classes.
+     */
+    protected void determineDependencies(Vector files, Vector classes) {
+        // we get the root classes and build up a set of
+        // classes upon which they depend
+        Hashtable dependencies = new Hashtable();
+        Hashtable containers = new Hashtable();
+        Hashtable toAnalyze = new Hashtable();
+        Hashtable nextAnalyze = new Hashtable();
+        for (Enumeration e = getRootClasses(); e.hasMoreElements();) {
+            String classname = (String) e.nextElement();
+            toAnalyze.put(classname, classname);
+        }
+
+        int count = 0;
+        int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+        while (toAnalyze.size() != 0 && count++ < maxCount) {
+            nextAnalyze.clear();
+            for (Enumeration e = toAnalyze.keys(); e.hasMoreElements();) {
+                String classname = (String) e.nextElement();
+                dependencies.put(classname, classname);
+                try {
+                    File container = getClassContainer(classname);
+                    if (container == null) {
+                        continue;
+                    }
+                    containers.put(container, container);
+
+                    ClassParser parser = null;
+                    if (container.getName().endsWith(".class")) {
+                        parser = new ClassParser(container.getPath());
+                    } else {
+                        parser = new ClassParser(container.getPath(),
+                            classname.replace('.', '/') + ".class");
+                    }
+
+                    JavaClass javaClass = parser.parse();
+                    String[] interfaces = javaClass.getInterfaceNames();
+                    for (int i = 0; i < interfaces.length; ++i) {
+                        String interfaceName = interfaces[i];
+                        if (!dependencies.containsKey(interfaceName)) {
+                            nextAnalyze.put(interfaceName, interfaceName);
+                        }
+                    }
+
+                    if (javaClass.isClass()) {
+                        String superClass = javaClass.getSuperclassName();
+                        if (!dependencies.containsKey(superClass)) {
+                            nextAnalyze.put(superClass, superClass);
+                        }
+                    }
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+
+            Hashtable temp = toAnalyze;
+            toAnalyze = nextAnalyze;
+            nextAnalyze = temp;
+        }
+
+        files.removeAllElements();
+        for (Enumeration e = containers.keys(); e.hasMoreElements();) {
+            files.addElement((File) e.nextElement());
+        }
+
+        classes.removeAllElements();
+        for (Enumeration e = dependencies.keys(); e.hasMoreElements();) {
+            classes.addElement((String) e.nextElement());
+        }
+    }
+
+    /**
+     * Indicate if this analyzer can determine dependent files.
+     *
+     * @return true if the analyzer provides dependency file information.
+     */
+    protected boolean supportsFileDependencies() {
+        return true;
+    }
+
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
new file mode 100644
index 0000000..07bd388
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
@@ -0,0 +1,191 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.depend.bcel;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import org.apache.bcel.classfile.ConstantClass;
+import org.apache.bcel.classfile.ConstantPool;
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+import org.apache.bcel.classfile.ConstantNameAndType;
+
+/**
+ * A BCEL visitor implementation to collect class dependency information
+ *
+ */
+public class DependencyVisitor extends EmptyVisitor {
+    /** The collectd dependencies */
+    private Hashtable dependencies = new Hashtable();
+    /**
+     * The current class's constant pool - used to determine class names
+     * from class references.
+     */
+    private ConstantPool constantPool;
+
+    /**
+     * Get the dependencies collected by this visitor
+     *
+     * @return a Enumeration of classnames, being the classes upon which the
+     *      visited classes depend.
+     */
+    public Enumeration getDependencies() {
+        return dependencies.keys();
+    }
+
+    /** Clear the curretn set of collected dependencies. */
+    public void clearDependencies() {
+        dependencies.clear();
+    }
+
+    /**
+     * Visit the constant pool of a class
+     *
+     * @param constantPool the constant pool of the class being visited.
+     */
+    public void visitConstantPool(ConstantPool constantPool) {
+        this.constantPool = constantPool;
+    }
+
+    /**
+     * Visit a class reference
+     *
+     * @param constantClass the constantClass entry for the class reference
+     */
+    public void visitConstantClass(ConstantClass constantClass) {
+        String classname
+             = constantClass.getConstantValue(constantPool).toString();
+        addSlashClass(classname);
+    }
+
+    /**
+     * Visit a name and type ref
+     *
+     * Look for class references in this
+     *
+     * @param obj the name and type reference being visited.
+     */
+    public void visitConstantNameAndType(ConstantNameAndType obj) {
+        String name = obj.getName(constantPool);
+        if (obj.getSignature(constantPool).equals("Ljava/lang/Class;")
+                && name.startsWith("class$")) {
+            String classname
+                = name.substring("class$".length()).replace('$', '.');
+            // does the class have a package structure
+            int index = classname.lastIndexOf(".");
+            if (index > 0) {
+                char start;
+                // check if the package structure is more than 1 level deep
+                int index2 = classname.lastIndexOf(".", index - 1);
+                if (index2 != -1) {
+                    // class name has more than 1 package level 'com.company.Class'
+                    start = classname.charAt(index2 + 1);
+                } else {
+                    // class name has only 1 package level 'package.Class'
+                    start = classname.charAt(0);
+                }
+                // Check to see if it's an inner class 'com.company.Class$Inner'
+                // CheckStyle:MagicNumber OFF
+                if ((start > 0x40) && (start < 0x5B)) {
+                    // first letter of the previous segment of the class name 'Class'
+                    // is upper case ascii. so according to the spec it's an inner class
+                    classname = classname.substring(0, index) + "$"
+                        + classname.substring(index + 1);
+                    addClass(classname);
+                } else {
+                    // Add the class in dotted notation 'com.company.Class'
+                    addClass(classname);
+                }
+                // CheckStyle:MagicNumber ON
+            } else {
+                // Add a class with no package 'Class'
+                addClass(classname);
+            }
+        }
+    }
+
+    /**
+     * Visit a field of the class.
+     *
+     * @param field the field being visited
+     */
+    public void visitField(Field field) {
+        addClasses(field.getSignature());
+    }
+
+    /**
+     * Visit a Java class
+     *
+     * @param javaClass the class being visited.
+     */
+    public void visitJavaClass(JavaClass javaClass) {
+        addClass(javaClass.getClassName());
+    }
+
+    /**
+     * Visit a method of the current class
+     *
+     * @param method the method being visited.
+     */
+    public void visitMethod(Method method) {
+        String signature = method.getSignature();
+        int pos = signature.indexOf(")");
+        addClasses(signature.substring(1, pos));
+        addClasses(signature.substring(pos + 1));
+    }
+
+    /**
+     * Add a classname to the list of dependency classes
+     *
+     * @param classname the class to be added to the list of dependencies.
+     */
+    void addClass(String classname) {
+        dependencies.put(classname, classname);
+    }
+
+    /**
+     * Add all the classes from a descriptor string.
+     *
+     * @param string the descriptor string, being descriptors separated by
+     *      ';' characters.
+     */
+    private void addClasses(String string) {
+        StringTokenizer tokens = new StringTokenizer(string, ";");
+        while (tokens.hasMoreTokens()) {
+            String descriptor = tokens.nextToken();
+            int pos = descriptor.indexOf('L');
+            if (pos != -1) {
+                addSlashClass(descriptor.substring(pos + 1));
+            }
+        }
+    }
+
+    /**
+     * Adds a class name in slash format
+     * (for example org/apache/tools/ant/Main).
+     *
+     * @param classname the class name in slash format
+     */
+    private void addSlashClass(String classname) {
+        addClass(classname.replace('/', '.'));
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
new file mode 100644
index 0000000..324a85c
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.DescendingVisitor;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * An analyzer capable fo traversing all class - class relationships.
+ *
+ */
+public class FullAnalyzer extends AbstractAnalyzer {
+    /**
+     * Default constructor
+     *
+     * Causes the BCEL classes to load to ensure BCEL dependencies can
+     * be satisfied
+     */
+    public FullAnalyzer() {
+        // force BCEL classes to load now
+        try {
+            new ClassParser("force");
+        } catch (IOException e) {
+            // ignore
+        }
+    }
+
+    /**
+     * Determine the dependencies of the configured root classes.
+     *
+     * @param files a vector to be populated with the files which contain
+     *      the dependency classes
+     * @param classes a vector to be populated with the names of the
+     *      depencency classes.
+     */
+    protected void determineDependencies(Vector files, Vector classes) {
+        // we get the root classes and build up a set of
+        // classes upon which they depend
+        Hashtable dependencies = new Hashtable();
+        Hashtable containers = new Hashtable();
+        Hashtable toAnalyze = new Hashtable();
+        for (Enumeration e = getRootClasses(); e.hasMoreElements();) {
+            String classname = (String) e.nextElement();
+            toAnalyze.put(classname, classname);
+        }
+
+        int count = 0;
+        int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+        while (toAnalyze.size() != 0 && count++ < maxCount) {
+            DependencyVisitor dependencyVisitor = new DependencyVisitor();
+            for (Enumeration e = toAnalyze.keys(); e.hasMoreElements();) {
+                String classname = (String) e.nextElement();
+                dependencies.put(classname, classname);
+                try {
+                    File container = getClassContainer(classname);
+                    if (container == null) {
+                        continue;
+                    }
+                    containers.put(container, container);
+
+                    ClassParser parser = null;
+                    if (container.getName().endsWith(".class")) {
+                        parser = new ClassParser(container.getPath());
+                    } else {
+                        parser = new ClassParser(container.getPath(),
+                            classname.replace('.', '/') + ".class");
+                    }
+
+                    JavaClass javaClass = parser.parse();
+                    DescendingVisitor traverser
+                         = new DescendingVisitor(javaClass, dependencyVisitor);
+                    traverser.visit();
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+
+            toAnalyze.clear();
+
+            // now recover all the dependencies collected and add to the list.
+            Enumeration depsEnum = dependencyVisitor.getDependencies();
+            while (depsEnum.hasMoreElements()) {
+                String className = (String) depsEnum.nextElement();
+                if (!dependencies.containsKey(className)) {
+                    toAnalyze.put(className, className);
+                }
+            }
+        }
+
+        files.removeAllElements();
+        for (Enumeration e = containers.keys(); e.hasMoreElements();) {
+            files.addElement((File) e.nextElement());
+        }
+
+        classes.removeAllElements();
+        for (Enumeration e = dependencies.keys(); e.hasMoreElements();) {
+            classes.addElement((String) e.nextElement());
+        }
+    }
+
+    /**
+     * Indicate if this analyzer can determine dependent files.
+     *
+     * @return true if the analyzer provides dependency file information.
+     */
+    protected boolean supportsFileDependencies() {
+        return true;
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java b/trunk/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java
new file mode 100644
index 0000000..e8d35f3
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.facade;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Helper class for facade implementations - encapsulates treatment of
+ * explicit implementation choices, magic properties and
+ * implementation specific command line arguments.
+ *
+ *
+ * @since Ant 1.5
+ */
+public class FacadeTaskHelper {
+
+    /**
+     * Command line arguments.
+     */
+    private Vector args = new Vector();
+
+    /**
+     * The explicitly chosen implementation.
+     */
+    private String userChoice;
+
+    /**
+     * The magic property to consult.
+     */
+    private String magicValue;
+
+    /**
+     * The default value.
+     */
+    private String defaultValue;
+
+    /**
+     * @param defaultValue The default value for the implementation.
+     * Must not be null.
+     */
+    public FacadeTaskHelper(String defaultValue) {
+        this(defaultValue, null);
+    }
+
+    /**
+     * @param defaultValue The default value for the implementation.
+     * Must not be null.
+     * @param magicValue the value of a magic property that may hold a user.
+     * choice.  May be null.
+     */
+    public FacadeTaskHelper(String defaultValue, String magicValue) {
+        this.defaultValue = defaultValue;
+        this.magicValue = magicValue;
+    }
+
+    /**
+     * Used to set the value of the magic property.
+     * @param magicValue the value of a magic property that may hold a user.
+     */
+    public void setMagicValue(String magicValue) {
+        this.magicValue = magicValue;
+    }
+
+    /**
+     * Used for explicit user choices.
+     * @param userChoice the explicitly chosen implementation.
+     */
+    public void setImplementation(String userChoice) {
+        this.userChoice = userChoice;
+    }
+
+    /**
+     * Retrieves the implementation.
+     * @return the implementation.
+     */
+    public String getImplementation() {
+        return userChoice != null ? userChoice
+                                  : (magicValue != null ? magicValue
+                                                        : defaultValue);
+    }
+
+    /**
+     * Retrieves the explicit user choice.
+     * @return the explicit user choice.
+     */
+    public String getExplicitChoice() {
+        return userChoice;
+    }
+
+    /**
+     * Command line argument.
+     * @param arg an argument to add.
+     */
+    public void addImplementationArgument(ImplementationSpecificArgument arg) {
+        args.addElement(arg);
+    }
+
+    /**
+     * Retrieves the command line arguments enabled for the current
+     * facade implementation.
+     * @return an array of command line arguements.
+     */
+    public String[] getArgs() {
+        Vector tmp = new Vector(args.size());
+        for (Enumeration e = args.elements(); e.hasMoreElements();) {
+            ImplementationSpecificArgument arg =
+                ((ImplementationSpecificArgument) e.nextElement());
+            String[] curr = arg.getParts(getImplementation());
+            for (int i = 0; i < curr.length; i++) {
+                tmp.addElement(curr[i]);
+            }
+        }
+        String[] res = new String[tmp.size()];
+        tmp.copyInto(res);
+        return res;
+    }
+
+    /**
+     * Tests whether the implementation has been chosen by the user
+     * (either via a magic property or explicitly.
+     * @return true if magic or user choice has be set.
+     * @since Ant 1.5.2
+     */
+    public boolean hasBeenSet() {
+        return userChoice != null || magicValue != null;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java b/trunk/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java
new file mode 100644
index 0000000..2b2b838
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.facade;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Extension of Commandline.Argument with a new attribute that choses
+ * a specific implementation of the facade.
+ *
+ *
+ * @since Ant 1.5
+ */
+public class ImplementationSpecificArgument extends Commandline.Argument {
+    private String impl;
+
+    /** Constructor for ImplementationSpecificArgument. */
+    public ImplementationSpecificArgument() {
+        super();
+    }
+
+    /**
+     * Set the implementation this argument is for.
+     * @param impl the implementation this command line argument is for.
+     */
+    public void setImplementation(String impl) {
+        this.impl = impl;
+    }
+
+    /**
+     * Return the parts this Argument consists of, if the
+     * implementation matches the chosen implementation.
+     * @see org.apache.tools.ant.types.Commandline.Argument#getParts()
+     * @param chosenImpl the implementation to check against.
+     * @return the parts if the implemention matches or an zero length
+     *         array if not.
+     */
+    public final String[] getParts(String chosenImpl) {
+        if (impl == null || impl.equals(chosenImpl)) {
+            return super.getParts();
+        } else {
+            return new String[0];
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java b/trunk/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java
new file mode 100644
index 0000000..2de657d
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.java15;
+
+import org.apache.tools.ant.BuildException;
+
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * This class exists to create a string that tells diagnostics about the current
+ * state of proxy diagnostics.
+ * It does this in its toString operator.
+ * Java1.5+ is needed to compile this class; its interface is classic typeless
+ * Java.
+ * @since Ant 1.7
+ */
+public class ProxyDiagnostics {
+
+    private String destination;
+
+    private URI destURI;
+
+    /** {@value} */
+    public static final String DEFAULT_DESTINATION = "http://ant.apache.org/";
+
+    /**
+     * create a diagnostics binding for a specific URI
+     * @param destination dest to bind to
+     * @throws BuildException if the URI is malformed.
+     */
+    public ProxyDiagnostics(String destination) {
+        this.destination = destination;
+        try {
+            this.destURI = new URI(destination);
+        } catch (URISyntaxException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * create a proxy diagnostics tool bound to
+     * {@link #DEFAULT_DESTINATION}
+     */
+    public ProxyDiagnostics() {
+        this(DEFAULT_DESTINATION);
+    }
+
+    /**
+     * Get the diagnostics for proxy information.
+     * @return the information.
+     */
+    public String toString() {
+        ProxySelector selector = ProxySelector.getDefault();
+        List list = selector.select(destURI);
+        StringBuffer result = new StringBuffer();
+        Iterator proxies = list.listIterator();
+        while (proxies.hasNext()) {
+            Proxy proxy = (Proxy) proxies.next();
+            SocketAddress address = proxy.address();
+            if (address == null) {
+                result.append("Direct connection\n");
+            } else {
+                result.append(proxy.toString());
+                if (address instanceof InetSocketAddress) {
+                    InetSocketAddress ina = (InetSocketAddress) address;
+                    result.append(' ');
+                    result.append(ina.getHostName());
+                    result.append(':');
+                    result.append(ina.getPort());
+                    if (ina.isUnresolved()) {
+                        result.append(" [unresolved]");
+                    } else {
+                        InetAddress addr = ina.getAddress();
+                        result.append(" [");
+                        result.append(addr.getHostAddress());
+                        result.append(']');
+                    }
+                }
+                result.append('\n');
+            }
+        }
+        return result.toString();
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java b/trunk/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java
new file mode 100644
index 0000000..ad59534
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.optional;
+
+import org.apache.tools.ant.BuildException;
+
+
+import java.util.Iterator;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+import org.apache.tools.ant.util.ReflectUtil;
+import org.apache.tools.ant.util.ReflectWrapper;
+
+/**
+ * This class is used to run scripts using JSR 223.
+ * @since Ant 1.7.0
+ */
+public class JavaxScriptRunner extends ScriptRunnerBase {
+    private ReflectWrapper engine;
+
+    /**
+     * Get the name of the manager prefix.
+     * @return "javax"
+     */
+    public String getManagerName() {
+        return "javax";
+    }
+
+    /** {@inheritDoc}. */
+    public boolean supportsLanguage() {
+        if (engine != null) {
+            return true;
+        }
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
+        try {
+            return createEngine() != null;
+        } catch (Exception ex) {
+            return false;
+        } finally {
+            restoreContextLoader(origLoader);
+        }
+    }
+
+    /**
+     * Do the work to run the script.
+     *
+     * @param execName the name that will be passed to the
+     *                 scripting engine for this script execution.
+     *
+     * @exception BuildException if someting goes wrong exectuing the script.
+     */
+    public void executeScript(String execName) throws BuildException {
+        evaluateScript(execName);
+    }
+
+    /**
+     * Do the work to eval the script.
+     *
+     * @param execName the name that will be passed to the
+     *                 scripting engine for this script execution.
+     * @return the result of the evaluation
+     * @exception BuildException if something goes wrong executing the script.
+     */
+    public Object evaluateScript(String execName) throws BuildException {
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
+        try {
+            ReflectWrapper engine = createEngine();
+            if (engine == null) {
+                throw new BuildException(
+                    "Unable to create javax script engine for "
+                    + getLanguage());
+            }
+            for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
+                String key = (String) i.next();
+                Object value = getBeans().get(key);
+                if ("FX".equalsIgnoreCase(getLanguage())) {
+                    engine.invoke(
+                        "put", String.class, key
+                        + ":" + value.getClass().getName(),
+                        Object.class, value);
+                } else {
+                    engine.invoke(
+                        "put", String.class, key,
+                        Object.class, value);
+                }
+            }
+            // execute the script
+            return engine.invoke("eval", String.class, getScript());
+        } catch (BuildException be) {
+            //catch and rethrow build exceptions
+            throw be;
+        } catch (Exception be) {
+            //any other exception? Get its cause
+            Throwable t = be;
+            Throwable te = (Throwable) ReflectUtil.invoke(be, "getCause");
+            if (te != null) {
+                if  (te instanceof BuildException) {
+                    throw (BuildException) te;
+                } else {
+                    t = te;
+                }
+            }
+            throw new BuildException(t);
+        } finally {
+            restoreContextLoader(origLoader);
+        }
+    }
+
+    private ReflectWrapper createEngine() throws Exception {
+        if (engine != null) {
+            return engine;
+        }
+        ReflectWrapper manager = new ReflectWrapper(
+            getClass().getClassLoader(), "javax.script.ScriptEngineManager");
+        Object e = manager.invoke(
+            "getEngineByName", String.class, getLanguage());
+        if (e == null) {
+            return null;
+        }
+        ReflectWrapper ret = new ReflectWrapper(e);
+        if (getKeepEngine()) {
+            this.engine = ret;
+        }
+        return ret;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java b/trunk/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java
new file mode 100644
index 0000000..eed3ad1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.optional;
+
+import java.security.Permission;
+import org.apache.tools.ant.ExitException;
+
+/**
+ * This is intended as a replacement for the default system manager.
+ * The goal is to intercept System.exit calls and make it throw an
+ * exception instead so that a System.exit in a task does not
+ * fully terminate Ant.
+ *
+ * @see ExitException
+ */
+public class NoExitSecurityManager extends SecurityManager {
+
+    /**
+     * Override SecurityManager#checkExit.
+     * This throws an ExitException(status) exception.
+     * @param status the exit status
+     */
+    public void checkExit(int status) {
+        throw new ExitException(status);
+    }
+
+    /**
+     * Override SecurityManager#checkPermission.
+     * This does nothing.
+     * @param perm the requested permission.
+     */
+    public void checkPermission(Permission perm) {
+        // no permission here
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java b/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java
new file mode 100644
index 0000000..15f6e6f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java
@@ -0,0 +1,179 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.optional;
+
+import org.apache.bsf.BSFException;
+import org.apache.bsf.BSFManager;
+import org.apache.bsf.BSFEngine;
+
+import java.util.Iterator;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+import org.apache.tools.ant.util.ReflectUtil;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+
+/**
+ * This class is used to run BSF scripts
+ *
+ */
+public class ScriptRunner extends ScriptRunnerBase {
+    // Register Groovy ourselves, since BSF did not
+    // natively support it in versions previous to 1.2.4.
+    static {
+        BSFManager.registerScriptingEngine(
+            "groovy",
+            "org.codehaus.groovy.bsf.GroovyEngine",
+            new String[] {"groovy", "gy"});
+    }
+
+    private BSFEngine  engine;
+    private BSFManager manager;
+
+    /**
+     * Get the name of the manager prefix.
+     * @return "bsf"
+     */
+    public String getManagerName() {
+        return "bsf";
+    }
+
+    /**
+     * Check if bsf supports the language.
+     * @return true if bsf can create an engine for this language.
+     */
+    public boolean supportsLanguage() {
+        Hashtable table = (Hashtable) ReflectUtil.getField(
+            new BSFManager(), "registeredEngines");
+        String engineClassName = (String) table.get(getLanguage());
+        if (engineClassName == null) {
+            getProject().log(
+                "This is no BSF engine class for language '"
+                + getLanguage() + "'",
+                Project.MSG_VERBOSE);
+            return false;
+        }
+        try {
+            getScriptClassLoader().loadClass(engineClassName);
+            return true;
+        } catch (Throwable ex) {
+            getProject().log(
+                "unable to create BSF engine class for language '"
+                + getLanguage() + "'",
+                ex,
+                Project.MSG_VERBOSE);
+            return false;
+        }
+    }
+
+    /**
+     * Do the work.
+     *
+     * @param execName the name that will be passed to BSF for this script execution.
+     * @exception BuildException if something goes wrong executing the script.
+     */
+    public void executeScript(String execName) throws BuildException {
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
+        try {
+            BSFManager m = createManager();
+            declareBeans(m);
+            // execute the script
+            if (engine == null) {
+                m.exec(getLanguage(), execName, 0, 0, getScript());
+            } else {
+                engine.exec(execName, 0, 0, getScript());
+            }
+        } catch (BSFException be) {
+            throw getBuildException(be);
+        } finally {
+            restoreContextLoader(origLoader);
+        }
+    }
+
+    /**
+     * Evaluate the script.
+     *
+     * @param execName the name that will be passed to BSF for this script execution.
+     * @return the result of the evaluation
+     * @exception BuildException if something goes wrong executing the script.
+     */
+    public Object evaluateScript(String execName) throws BuildException {
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
+        try {
+            BSFManager m = createManager();
+            declareBeans(m);
+            // execute the script
+            if (engine == null) {
+                return m.eval(getLanguage(), execName, 0, 0, getScript());
+            }
+            return engine.eval(execName, 0, 0, getScript());
+        } catch (BSFException be) {
+            throw getBuildException(be);
+        } finally {
+            restoreContextLoader(origLoader);
+        }
+    }
+
+    /**
+     * Get/create a BuildException from a BSFException.
+     * @param be BSFException to convert.
+     * @return BuildException the converted exception.
+     */
+    private BuildException getBuildException(BSFException be) {
+        Throwable t = be;
+        Throwable te = be.getTargetException();
+        if (te instanceof BuildException) {
+            return (BuildException) te;
+        }
+        return new BuildException(te == null ? t : te);
+    }
+
+    private void declareBeans(BSFManager m) throws BSFException {
+        for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            Object value = getBeans().get(key);
+            if (value != null) {
+                m.declareBean(key, value, value.getClass());
+            } else {
+                // BSF uses a hashtable to store values
+                // so cannot declareBean with a null value
+                // So need to remove any bean of this name as
+                // that bean should not be visible
+                m.undeclareBean(key);
+            }
+        }
+    }
+
+    private BSFManager createManager() throws BSFException {
+        if (manager != null) {
+            return manager;
+        }
+        BSFManager m = new BSFManager();
+        m.setClassLoader(getScriptClassLoader());
+        if (getKeepEngine()) {
+            BSFEngine e = manager.loadScriptingEngine(getLanguage());
+            this.manager = m;
+            this.engine  = e;
+        }
+        return m;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java b/trunk/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java
new file mode 100644
index 0000000..4cd1278
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.optional;
+
+import org.apache.tools.ant.util.WeakishReference;
+
+/**
+ * This is a reference that really is is Weak, as it uses the
+ * appropriate java.lang.ref class.
+ * @deprecated since 1.7.
+ *             Just use {@link java.lang.ref.WeakReference} directly.
+ * Note that in ant1.7 is parent was changed to extend HardReference.
+ * This is because the latter has access to the (package scoped)
+ * WeakishReference(Object) constructor, and both that and this are thin
+ * facades on the underlying no-longer-abstract base class.
+ */
+public class WeakishReference12 extends WeakishReference.HardReference  {
+
+
+    /**
+     * create a new soft reference, which is bound to a
+     * Weak reference inside
+     * @param reference the object to reference.
+     * @see java.lang.ref.WeakReference
+     */
+    public WeakishReference12(Object reference) {
+        super(reference);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java
new file mode 100644
index 0000000..59d9e91
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java
@@ -0,0 +1,168 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.util.Vector;
+import org.apache.oro.text.regex.MatchResult;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.Perl5Compiler;
+import org.apache.oro.text.regex.Perl5Matcher;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of RegexpMatcher for Jakarta-ORO.
+ *
+ */
+public class JakartaOroMatcher implements RegexpMatcher {
+
+    private String pattern;
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected final Perl5Compiler compiler = new Perl5Compiler();
+    protected final Perl5Matcher matcher = new Perl5Matcher();
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for JakartaOroMatcher.
+     */
+    public JakartaOroMatcher() {
+    }
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     */
+    public String getPattern() {
+        return this.pattern;
+    }
+
+    /**
+     * Get a compiled representation of the regexp pattern
+     * @param options the options
+     * @return the compiled pattern
+     * @throws BuildException on error
+     */
+    protected Pattern getCompiledPattern(int options)
+        throws BuildException {
+        try {
+            // compute the compiler options based on the input options first
+            Pattern p = compiler.compile(pattern, getCompilerOptions(options));
+            return p;
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Does the given argument match the pattern using default options?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String argument) throws BuildException {
+        return matches(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Does the given argument match the pattern?
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String input, int options)
+        throws BuildException {
+        Pattern p = getCompiledPattern(options);
+        return matcher.contains(input, p);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String argument) throws BuildException {
+        return getGroups(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String input, int options)
+        throws BuildException {
+        if (!matches(input, options)) {
+            return null;
+        }
+        Vector v = new Vector();
+        MatchResult mr = matcher.getMatch();
+        int cnt = mr.groups();
+        for (int i = 0; i < cnt; i++) {
+            String match = mr.group(i);
+            // treat non-matching groups as empty matches
+            if (match == null) {
+                match = "";
+            }
+            v.addElement(match);
+        }
+        return v;
+    }
+
+    /**
+     * Convert the generic options to the regex compiler specific options.
+     * @param options the generic options
+     * @return the specific options
+     */
+    protected int getCompilerOptions(int options) {
+        int cOptions = Perl5Compiler.DEFAULT_MASK;
+
+        if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+            cOptions |= Perl5Compiler.CASE_INSENSITIVE_MASK;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+            cOptions |= Perl5Compiler.MULTILINE_MASK;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+            cOptions |= Perl5Compiler.SINGLELINE_MASK;
+        }
+
+        return cOptions;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java
new file mode 100644
index 0000000..45d00e4
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import org.apache.oro.text.regex.Perl5Substitution;
+import org.apache.oro.text.regex.Substitution;
+import org.apache.oro.text.regex.Util;
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the Jakarta Oro package
+ */
+public class JakartaOroRegexp extends JakartaOroMatcher implements Regexp {
+
+    private static final int DECIMAL = 10;
+
+    /** Constructor for JakartaOroRegexp */
+    public JakartaOroRegexp() {
+        super();
+    }
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    public String substitute(String input, String argument, int options)
+        throws BuildException {
+        // translate \1 to $1 so that the Perl5Substitution will work
+        StringBuffer subst = new StringBuffer();
+        for (int i = 0; i < argument.length(); i++) {
+            char c = argument.charAt(i);
+            if (c == '$') {
+                subst.append('\\');
+                subst.append('$');
+            } else if (c == '\\') {
+                if (++i < argument.length()) {
+                    c = argument.charAt(i);
+                    int value = Character.digit(c, DECIMAL);
+                    if (value > -1) {
+                        subst.append("$").append(value);
+                    } else {
+                        subst.append(c);
+                    }
+                } else {
+                    // XXX - should throw an exception instead?
+                    subst.append('\\');
+                }
+            } else {
+                subst.append(c);
+            }
+        }
+
+        // Do the substitution
+        Substitution s =
+            new Perl5Substitution(subst.toString(),
+                                  Perl5Substitution.INTERPOLATE_ALL);
+        return Util.substitute(matcher,
+                               getCompiledPattern(options),
+                               s,
+                               input,
+                               getSubsOptions(options));
+    }
+
+    /**
+     * Convert ant regexp substitution option to oro options.
+     *
+     * @param options the ant regexp options
+     * @return the oro substition options
+     */
+    protected int getSubsOptions(int options) {
+        boolean replaceAll = RegexpUtil.hasFlag(options, REPLACE_ALL);
+        int subsOptions = 1;
+        if (replaceAll) {
+            subsOptions = Util.SUBSTITUTE_ALL;
+        }
+        return subsOptions;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java
new file mode 100644
index 0000000..3e14415
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java
@@ -0,0 +1,161 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.util.Vector;
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of RegexpMatcher for Jakarta-Regexp.
+ *
+ */
+public class JakartaRegexpMatcher implements RegexpMatcher {
+
+    private String pattern;
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Compile the pattern.
+     *
+     * @param options the ant regexp options
+     * @return a compiled pattern
+     * @exception BuildException if an error occurs
+     */
+    protected RE getCompiledPattern(int options)
+        throws BuildException {
+        int cOptions = getCompilerOptions(options);
+        try {
+            RE reg = new RE(pattern);
+            reg.setMatchFlags(cOptions);
+            return reg;
+        } catch (RESyntaxException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Does the given argument match the pattern?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String argument) throws BuildException {
+        return matches(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Does the given argument match the pattern?
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String input, int options)
+        throws BuildException {
+        return matches(input, getCompiledPattern(options));
+    }
+
+    private boolean matches(String input, RE reg) {
+        return reg.match(input);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String argument) throws BuildException {
+        return getGroups(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String input, int options)
+        throws BuildException {
+        RE reg = getCompiledPattern(options);
+        if (!matches(input, reg)) {
+            return null;
+        }
+        Vector v = new Vector();
+        int cnt = reg.getParenCount();
+        for (int i = 0; i < cnt; i++) {
+            String match = reg.getParen(i);
+            // treat non-matching groups as empty matches
+            if (match == null) {
+                match = "";
+            }
+            v.addElement(match);
+        }
+        return v;
+    }
+
+    /**
+     * Convert the generic options to the regex compiler specific options.
+     * @param options the generic options
+     * @return the specific options
+     */
+    protected int getCompilerOptions(int options) {
+        int cOptions = RE.MATCH_NORMAL;
+
+        if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+            cOptions |= RE.MATCH_CASEINDEPENDENT;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+            cOptions |= RE.MATCH_MULTILINE;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+            cOptions |= RE.MATCH_SINGLELINE;
+        }
+
+        return cOptions;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java
new file mode 100644
index 0000000..5868fef
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import java.util.Vector;
+import org.apache.regexp.RE;
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the Jakarta Regexp package
+ */
+public class JakartaRegexpRegexp extends JakartaRegexpMatcher
+    implements Regexp {
+
+    private static final int DECIMAL = 10;
+
+    /** Constructor for JakartaRegexpRegexp */
+    public JakartaRegexpRegexp() {
+        super();
+    }
+
+    /**
+     * Convert ant regexp substitution option to apache regex options.
+     *
+     * @param options the ant regexp options
+     * @return the apache regex substition options
+     */
+    protected int getSubsOptions(int options) {
+        int subsOptions = RE.REPLACE_FIRSTONLY;
+        if (RegexpUtil.hasFlag(options, REPLACE_ALL)) {
+            subsOptions = RE.REPLACE_ALL;
+        }
+        return subsOptions;
+    }
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    public String substitute(String input, String argument, int options)
+        throws BuildException {
+        Vector v = getGroups(input, options);
+
+        // replace \1 with the corresponding group
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < argument.length(); i++) {
+            char c = argument.charAt(i);
+            if (c == '\\') {
+                if (++i < argument.length()) {
+                    c = argument.charAt(i);
+                    int value = Character.digit(c, DECIMAL);
+                    if (value > -1) {
+                        result.append((String) v.elementAt(value));
+                    } else {
+                        result.append(c);
+                    }
+                } else {
+                    // XXX - should throw an exception instead?
+                    result.append('\\');
+                }
+            } else {
+                result.append(c);
+            }
+        }
+        argument = result.toString();
+
+        RE reg = getCompiledPattern(options);
+        int sOptions = getSubsOptions(options);
+        return reg.subst(input, argument, sOptions);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java b/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java
new file mode 100644
index 0000000..07b2b17
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java
@@ -0,0 +1,169 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of RegexpMatcher for the built-in regexp matcher of
+ * JDK 1.4. UNIX_LINES option is enabled as a default.
+ *
+ */
+public class Jdk14RegexpMatcher implements RegexpMatcher {
+
+    private String pattern;
+
+    /** Constructor for JakartaOroRegexp */
+    public Jdk14RegexpMatcher() {
+    }
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     */
+    public void setPattern(String pattern) {
+        this.pattern = pattern;
+    }
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     * @throws BuildException on error
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    /**
+     * Get a compiled representation of the regexp pattern
+     * @param options the options
+     * @return the compiled pattern
+     * @throws BuildException on error
+     */
+    protected Pattern getCompiledPattern(int options)
+        throws BuildException {
+        int cOptions = getCompilerOptions(options);
+        try {
+            Pattern p = Pattern.compile(this.pattern, cOptions);
+            return p;
+        } catch (PatternSyntaxException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Does the given argument match the pattern using default options?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String argument) throws BuildException {
+        return matches(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Does the given argument match the pattern?
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    public boolean matches(String input, int options)
+        throws BuildException {
+        try {
+            Pattern p = getCompiledPattern(options);
+            return p.matcher(input).find();
+        } catch (Exception e) {
+            throw new BuildException(e);
+        }
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String argument) throws BuildException {
+        return getGroups(argument, MATCH_DEFAULT);
+    }
+
+    /**
+     * Returns a Vector of matched groups found in the argument.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param input the string to match against
+     * @param options the regex options to use
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    public Vector getGroups(String input, int options)
+        throws BuildException {
+        Pattern p = getCompiledPattern(options);
+        Matcher matcher = p.matcher(input);
+        if (!matcher.find()) {
+            return null;
+        }
+        Vector v = new Vector();
+        int cnt = matcher.groupCount();
+        for (int i = 0; i <= cnt; i++) {
+            String match = matcher.group(i);
+            // treat non-matching groups as empty matches
+            if (match == null) {
+                match = "";
+            }
+            v.addElement(match);
+        }
+        return v;
+    }
+
+    /**
+     * Convert the generic options to the regex compiler specific options.
+     * @param options the generic options
+     * @return the specific options
+     */
+    protected int getCompilerOptions(int options) {
+        // be strict about line separator
+        int cOptions = Pattern.UNIX_LINES;
+
+        if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+            cOptions |= Pattern.CASE_INSENSITIVE;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+            cOptions |= Pattern.MULTILINE;
+        }
+        if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+            cOptions |= Pattern.DOTALL;
+        }
+
+        return cOptions;
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java b/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java
new file mode 100644
index 0000000..bd0faa8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the JDK 1.4 regular expression package
+ */
+public class Jdk14RegexpRegexp extends Jdk14RegexpMatcher implements Regexp {
+
+    private static final int DECIMAL = 10;
+
+    /** Constructor for Jdk14RegexpRegexp */
+    public Jdk14RegexpRegexp() {
+        super();
+    }
+
+    /**
+     * Convert ant regexp substitution option to jdk1.4 options.
+     *
+     * @param options the ant regexp options
+     * @return the jdk14 substition options
+     */
+    protected int getSubsOptions(int options) {
+        int subsOptions = REPLACE_FIRST;
+        if (RegexpUtil.hasFlag(options, REPLACE_ALL)) {
+            subsOptions = REPLACE_ALL;
+        }
+        return subsOptions;
+    }
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    public String substitute(String input, String argument, int options)
+        throws BuildException {
+        // translate \1 to $(1) so that the Matcher will work
+        StringBuffer subst = new StringBuffer();
+        for (int i = 0; i < argument.length(); i++) {
+            char c = argument.charAt(i);
+            if (c == '$') {
+                subst.append('\\');
+                subst.append('$');
+            } else if (c == '\\') {
+                if (++i < argument.length()) {
+                    c = argument.charAt(i);
+                    int value = Character.digit(c, DECIMAL);
+                    if (value > -1) {
+                        subst.append("$").append(value);
+                    } else {
+                        subst.append(c);
+                    }
+                } else {
+                    // XXX - should throw an exception instead?
+                    subst.append('\\');
+                }
+            } else {
+                subst.append(c);
+            }
+        }
+        argument = subst.toString();
+
+        int sOptions = getSubsOptions(options);
+        Pattern p = getCompiledPattern(options);
+        StringBuffer sb = new StringBuffer();
+
+        Matcher m = p.matcher(input);
+        if (RegexpUtil.hasFlag(sOptions, REPLACE_ALL)) {
+            sb.append(m.replaceAll(argument));
+        } else {
+            boolean res = m.find();
+            if (res) {
+                m.appendReplacement(sb, argument);
+                m.appendTail(sb);
+            } else {
+                sb.append(input);
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/Regexp.java b/trunk/src/main/org/apache/tools/ant/util/regexp/Regexp.java
new file mode 100644
index 0000000..1c7816a
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/Regexp.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Interface which represents a regular expression, and the operations
+ * that can be performed on it.
+ *
+ */
+public interface Regexp extends RegexpMatcher {
+
+    /**
+     * Replace only the first occurrence of the regular expression
+     */
+    int REPLACE_FIRST          = 0x00000001;
+
+    /**
+     * Replace all occurrences of the regular expression
+     */
+    int REPLACE_ALL            = 0x00000010;
+
+    /**
+     * Perform a substitution on the regular expression.
+     * @param input The string to substitute on
+     * @param argument The string which defines the substitution
+     * @param options The list of options for the match and replace. See the
+     *                MATCH_ and REPLACE_ constants above.
+     * @return the result of the operation
+     * @throws BuildException on error
+     */
+    String substitute(String input, String argument, int options)
+        throws BuildException;
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java
new file mode 100644
index 0000000..504621f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/***
+ * Regular expression factory, which will create Regexp objects.  The
+ * actual implementation class depends on the System or Ant Property:
+ * <code>ant.regexp.regexpimpl</code>.
+ *
+ */
+public class RegexpFactory extends RegexpMatcherFactory {
+
+    /** Constructor for RegexpFactory */
+    public RegexpFactory() {
+    }
+
+    /***
+     * Create a new regular expression matcher instance.
+     * @return the matcher instance
+     * @throws BuildException on error
+     */
+    public Regexp newRegexp() throws BuildException {
+        return (Regexp) newRegexp(null);
+    }
+
+    /***
+     * Create a new regular expression matcher instance.
+     *
+     * @param p Project whose ant.regexp.regexpimpl property will be used.
+     * @return the matcher instance
+     * @throws BuildException on error
+     */
+    public Regexp newRegexp(Project p) throws BuildException {
+        String systemDefault = null;
+        if (p == null) {
+            systemDefault = System.getProperty(MagicNames.REGEXP_IMPL);
+        } else {
+            systemDefault = p.getProperty(MagicNames.REGEXP_IMPL);
+        }
+
+        if (systemDefault != null) {
+            return createRegexpInstance(systemDefault);
+            // XXX     should we silently catch possible exceptions and try to
+            //         load a different implementation?
+        }
+
+        Throwable cause = null;
+
+        try {
+            testAvailability("java.util.regex.Matcher");
+            return createRegexpInstance("org.apache.tools.ant.util.regexp.Jdk14RegexpRegexp");
+        } catch (BuildException be) {
+            cause = orCause(
+                cause, be,
+                JavaEnvUtils.getJavaVersionNumber() < JavaEnvUtils.VERSION_1_4);
+        }
+
+        try {
+            testAvailability("org.apache.oro.text.regex.Pattern");
+            return createRegexpInstance("org.apache.tools.ant.util.regexp.JakartaOroRegexp");
+        } catch (BuildException be) {
+            cause = orCause(cause, be, true);
+        }
+
+        try {
+            testAvailability("org.apache.regexp.RE");
+            return createRegexpInstance("org.apache.tools.ant.util.regexp.JakartaRegexpRegexp");
+        } catch (BuildException be) {
+            cause = orCause(cause, be, true);
+        }
+        throw new BuildException("No supported regular expression matcher found"
+                + (cause != null ? ": " + cause : ""), cause);
+    }
+
+    /**
+     * Wrapper over RegexpMatcherFactory.createInstance that ensures that
+     * we are dealing with a Regexp implementation.
+     * @param classname the name of the class to use.
+     * @return the instance.
+     * @throws BuildException if there is a problem.
+     * @since 1.3
+     *
+     * @see RegexpMatcherFactory#createInstance(String)
+     */
+    protected Regexp createRegexpInstance(String classname) throws BuildException {
+        return (Regexp) ClasspathUtils.newInstance(classname, RegexpFactory.class.getClassLoader(),
+                Regexp.class);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java
new file mode 100644
index 0000000..5c36d9b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.util.Vector;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Interface describing a regular expression matcher.
+ *
+ */
+public interface RegexpMatcher {
+
+    /***
+     * Default Mask (case insensitive, neither multiline nor
+     * singleline specified).
+     */
+    int MATCH_DEFAULT          = 0x00000000;
+
+    /***
+     * Perform a case insenstive match
+     */
+    int MATCH_CASE_INSENSITIVE = 0x00000100;
+
+    /***
+     * Treat the input as a multiline input
+     */
+    int MATCH_MULTILINE        = 0x00001000;
+
+    /***
+     * Treat the input as singleline input ('.' matches newline)
+     */
+    int MATCH_SINGLELINE       = 0x00010000;
+
+
+    /**
+     * Set the regexp pattern from the String description.
+     * @param pattern the pattern to match
+     * @throws BuildException on error
+     */
+    void setPattern(String pattern) throws BuildException;
+
+    /**
+     * Get a String representation of the regexp pattern
+     * @return the pattern
+     * @throws BuildException on error
+     */
+    String getPattern() throws BuildException;
+
+    /**
+     * Does the given argument match the pattern?
+     * @param argument the string to match against
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    boolean matches(String argument) throws BuildException;
+
+    /**
+     * Returns a Vector of matched groups found in the argument
+     * using default options.
+     *
+     * <p>Group 0 will be the full match, the rest are the
+     * parenthesized subexpressions</p>.
+     *
+     * @param argument the string to match against
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    Vector getGroups(String argument) throws BuildException;
+
+    /***
+     * Does this regular expression match the input, given
+     * certain options
+     * @param input The string to check for a match
+     * @param options The list of options for the match. See the
+     *                MATCH_ constants above.
+     * @return true if the pattern matches
+     * @throws BuildException on error
+     */
+    boolean matches(String input, int options) throws BuildException;
+
+    /***
+     * Get the match groups from this regular expression.  The return
+     * type of the elements is always String.
+     * @param input The string to check for a match
+     * @param options The list of options for the match. See the
+     *                MATCH_ constants above.
+     * @return the vector of groups
+     * @throws BuildException on error
+     */
+    Vector getGroups(String input, int options) throws BuildException;
+
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java
new file mode 100644
index 0000000..b78a27b
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java
@@ -0,0 +1,148 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.ClasspathUtils;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Simple Factory Class that produces an implementation of RegexpMatcher based on the system
+ * property <code>ant.regexp.regexpimpl</code> and the classes available.
+ *
+ * <p>
+ * In a more general framework this class would be abstract and have a static newInstance method.
+ * </p>
+ *
+ */
+public class RegexpMatcherFactory {
+
+    /** Constructor for RegexpMatcherFactory. */
+    public RegexpMatcherFactory() {
+    }
+
+    /***
+     * Create a new regular expression instance.
+     * @return the matcher
+     * @throws BuildException on error
+     */
+    public RegexpMatcher newRegexpMatcher() throws BuildException {
+        return newRegexpMatcher(null);
+    }
+
+    /***
+     * Create a new regular expression instance.
+     *
+     * @param p Project whose ant.regexp.regexpimpl property will be used.
+     * @return the matcher
+     * @throws BuildException on error
+     */
+    public RegexpMatcher newRegexpMatcher(Project p) throws BuildException {
+        String systemDefault = null;
+        if (p == null) {
+            systemDefault = System.getProperty(MagicNames.REGEXP_IMPL);
+        } else {
+            systemDefault = p.getProperty(MagicNames.REGEXP_IMPL);
+        }
+
+        if (systemDefault != null) {
+            return createInstance(systemDefault);
+            // XXX     should we silently catch possible exceptions and try to
+            //         load a different implementation?
+        }
+
+        Throwable cause = null;
+
+        try {
+            testAvailability("java.util.regex.Matcher");
+            return createInstance("org.apache.tools.ant.util.regexp.Jdk14RegexpMatcher");
+        } catch (BuildException be) {
+            cause = orCause(
+                cause, be,
+                JavaEnvUtils.getJavaVersionNumber() < JavaEnvUtils.VERSION_1_4);
+        }
+
+        try {
+            testAvailability("org.apache.oro.text.regex.Pattern");
+            return createInstance("org.apache.tools.ant.util.regexp.JakartaOroMatcher");
+        } catch (BuildException be) {
+            cause = orCause(cause, be, true);
+        }
+
+        try {
+            testAvailability("org.apache.regexp.RE");
+            return createInstance("org.apache.tools.ant.util.regexp.JakartaRegexpMatcher");
+        } catch (BuildException be) {
+            cause = orCause(cause, be, true);
+        }
+        throw new BuildException("No supported regular expression matcher found"
+                + (cause != null ? ": " + cause : ""), cause);
+    }
+
+    static Throwable orCause(Throwable deflt, BuildException be, boolean ignoreCnfe) {
+        if (deflt != null) {
+            return deflt;
+        }
+        Throwable t = be.getException();
+        return ignoreCnfe && t instanceof ClassNotFoundException ? null : t;
+    }
+
+    /**
+     * Create an instance of a matcher from a classname.
+     *
+     * @param className a <code>String</code> value
+     * @return a <code>RegexpMatcher</code> value
+     * @exception BuildException if an error occurs
+     */
+    protected RegexpMatcher createInstance(String className) throws BuildException {
+        return (RegexpMatcher) ClasspathUtils.newInstance(className, RegexpMatcherFactory.class
+                .getClassLoader(), RegexpMatcher.class);
+    }
+
+    /**
+     * Test if a particular class is available to be used.
+     *
+     * @param className a <code>String</code> value
+     * @exception BuildException if an error occurs
+     */
+    protected void testAvailability(String className) throws BuildException {
+        try {
+            Class.forName(className);
+        } catch (Throwable t) {
+            throw new BuildException(t);
+        }
+    }
+
+    /**
+     * Checks if a RegExp-Matcher is available.
+     * @param project  The project to check for (may be <code>null</code>)
+     * @return <code>true</code> if available otherwise <code>false</code>
+     */
+    public static boolean regexpMatcherPresent(Project project) {
+        try {
+            // The factory throws a BuildException if no usable matcher
+            // cant be instantiated. We dont need the matcher itself here.
+            new RegexpMatcherFactory().newRegexpMatcher(project);
+            return true;
+        } catch (Throwable ex) {
+            return false;
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java
new file mode 100644
index 0000000..544eac1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util.regexp;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/***
+ * Regular expression utilities class which handles flag operations.
+ *
+ */
+public class RegexpUtil {
+
+    /**
+     * Check the options has a particular flag set.
+     *
+     * @param options an <code>int</code> value
+     * @param flag an <code>int</code> value
+     * @return true if the flag is set
+     */
+    public static boolean hasFlag(int options, int flag) {
+        return ((options & flag) > 0);
+    }
+
+    /**
+     * Remove a particular flag from an int value contains the option flags.
+     *
+     * @param options an <code>int</code> value
+     * @param flag an <code>int</code> value
+     * @return the options with the flag unset
+     */
+    public static int removeFlag(int options, int flag) {
+        return (options & (0xFFFFFFFF - flag));
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/ant/version.txt b/trunk/src/main/org/apache/tools/ant/version.txt
new file mode 100644
index 0000000..0496e18
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/ant/version.txt
@@ -0,0 +1,2 @@
+VERSION=${project.version}
+DATE=${TODAY}
diff --git a/trunk/src/main/org/apache/tools/bzip2/BZip2Constants.java b/trunk/src/main/org/apache/tools/bzip2/BZip2Constants.java
new file mode 100644
index 0000000..3a511a7
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/bzip2/BZip2Constants.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+package org.apache.tools.bzip2;
+
+/**
+ * Base class for both the compress and decompress classes.
+ * Holds common arrays, and static data.
+ * <p>
+ * This interface is public for historical purposes.
+ * You should have no need to use it.
+ * </p>
+ */
+public interface BZip2Constants {
+
+    int baseBlockSize = 100000;
+    int MAX_ALPHA_SIZE = 258;
+    int MAX_CODE_LEN = 23;
+    int RUNA = 0;
+    int RUNB = 1;
+    int N_GROUPS = 6;
+    int G_SIZE = 50;
+    int N_ITERS = 4;
+    int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+    int NUM_OVERSHOOT_BYTES = 20;
+
+    /**
+     * This array really shouldn't be here.
+     * Again, for historical purposes it is.
+     *
+     * <p>FIXME: This array should be in a private or package private
+     * location, since it could be modified by malicious code.</p>
+     */
+    int[] rNums = {
+        619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+        985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+        733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+        419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+        878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+        862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+        150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+        170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+        73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+        909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+        641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+        161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+        382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+        98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+        227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+        469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+        184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+        715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+        951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+        652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+        645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+        609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+        653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+        411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+        170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+        857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+        669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+        944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+        344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+        897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+        433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+        686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+        946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+        978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+        680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+        707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+        297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+        134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+        343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+        140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+        170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+        369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+        804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+        896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+        661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+        768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+        61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+        372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+        780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+        920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+        645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+        936, 638
+    };
+}
diff --git a/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java b/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java
new file mode 100644
index 0000000..ebb5f60
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/bzip2/CBZip2InputStream.java
@@ -0,0 +1,976 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+package org.apache.tools.bzip2;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * An input stream that decompresses from the BZip2 format (without the file
+ * header chars) to be read as any other stream.
+ *
+ * <p>The decompression requires large amounts of memory. Thus you
+ * should call the {@link #close() close()} method as soon as
+ * possible, to force <tt>CBZip2InputStream</tt> to release the
+ * allocated memory.  See {@link CBZip2OutputStream
+ * CBZip2OutputStream} for information about memory usage.</p>
+ *
+ * <p><tt>CBZip2InputStream</tt> reads bytes from the compressed
+ * source stream via the single byte {@link java.io.InputStream#read()
+ * read()} method exclusively. Thus you should consider to use a
+ * buffered source stream.</p>
+ * 
+ * <p>Instances of this class are not threadsafe.</p>
+ */
+public class CBZip2InputStream extends InputStream implements BZip2Constants {
+
+    private static void reportCRCError() throws IOException {
+        // The clean way would be to throw an exception.
+        //throw new IOException("crc error");
+
+        // Just print a message, like the previous versions of this class did
+        System.err.println("BZip2 CRC error");
+    }
+
+    private void makeMaps() {
+        final boolean[] inUse   = this.data.inUse;
+        final byte[] seqToUnseq = this.data.seqToUnseq;
+
+        int nInUseShadow = 0;
+
+        for (int i = 0; i < 256; i++) {
+            if (inUse[i])
+                seqToUnseq[nInUseShadow++] = (byte) i;
+        }
+
+        this.nInUse = nInUseShadow;
+    }
+
+    /**
+     * Index of the last char in the block, so the block size == last + 1.
+     */
+    private int  last;
+
+    /**
+     * Index in zptr[] of original string after sorting.
+     */
+    private int  origPtr;
+
+    /**
+     * always: in the range 0 .. 9.
+     * The current block size is 100000 * this number.
+     */
+    private int blockSize100k;
+
+    private boolean blockRandomised;
+
+    private int bsBuff;
+    private int bsLive;
+    private final CRC crc = new CRC();
+
+    private int nInUse;
+
+    private InputStream in;
+
+    private int currentChar = -1;
+
+    private static final int EOF                  = 0;
+    private static final int START_BLOCK_STATE = 1;
+    private static final int RAND_PART_A_STATE = 2;
+    private static final int RAND_PART_B_STATE = 3;
+    private static final int RAND_PART_C_STATE = 4;
+    private static final int NO_RAND_PART_A_STATE = 5;
+    private static final int NO_RAND_PART_B_STATE = 6;
+    private static final int NO_RAND_PART_C_STATE = 7;
+
+    private int currentState = START_BLOCK_STATE;
+
+    private int storedBlockCRC, storedCombinedCRC;
+    private int computedBlockCRC, computedCombinedCRC;
+
+    // Variables used by setup* methods exclusively
+
+    private int su_count;
+    private int su_ch2;
+    private int su_chPrev;
+    private int su_i2;
+    private int su_j2;
+    private int su_rNToGo;
+    private int su_rTPos;
+    private int su_tPos;
+    private char su_z;
+
+    /**
+     * All memory intensive stuff.
+     * This field is initialized by initBlock().
+     */
+    private CBZip2InputStream.Data data;
+
+    /**
+     * Constructs a new CBZip2InputStream which decompresses bytes read from
+     * the specified stream.
+     *
+     * <p>Although BZip2 headers are marked with the magic
+     * <tt>"Bz"</tt> this constructor expects the next byte in the
+     * stream to be the first one after the magic.  Thus callers have
+     * to skip the first two bytes. Otherwise this constructor will
+     * throw an exception. </p>
+     *
+     * @throws IOException
+     *  if the stream content is malformed or an I/O error occurs.
+     * @throws NullPointerException
+     *  if <tt>in == null</tt>
+     */
+    public CBZip2InputStream(final InputStream in) throws IOException {
+        super();
+
+        this.in = in;
+        init();
+    }
+
+    public int read() throws IOException {
+        if (this.in != null) {
+            return read0();
+        } else {
+            throw new IOException("stream closed");
+        }
+    }
+
+    public int read(final byte[] dest, final int offs, final int len)
+        throws IOException {
+        if (offs < 0) {
+            throw new IndexOutOfBoundsException("offs(" + offs + ") < 0.");
+        }
+        if (len < 0) {
+            throw new IndexOutOfBoundsException("len(" + len + ") < 0.");
+        }
+        if (offs + len > dest.length) {
+            throw new IndexOutOfBoundsException("offs(" + offs + ") + len("
+                                                + len + ") > dest.length("
+                                                + dest.length + ").");
+        }
+        if (this.in == null) {
+            throw new IOException("stream closed");
+        }
+
+        final int hi = offs + len;
+        int destOffs = offs;
+        for (int b; (destOffs < hi) && ((b = read0()) >= 0);) {
+            dest[destOffs++] = (byte) b;
+        }
+
+        return (destOffs == offs) ? -1 : (destOffs - offs);
+    }
+
+    private int read0() throws IOException {
+        final int retChar = this.currentChar;
+
+        switch (this.currentState) {
+        case EOF:
+            return -1;
+
+        case START_BLOCK_STATE:
+            throw new IllegalStateException();
+
+        case RAND_PART_A_STATE:
+            throw new IllegalStateException();
+
+        case RAND_PART_B_STATE:
+            setupRandPartB();
+            break;
+
+        case RAND_PART_C_STATE:
+            setupRandPartC();
+            break;
+
+        case NO_RAND_PART_A_STATE:
+            throw new IllegalStateException();
+
+        case NO_RAND_PART_B_STATE:
+            setupNoRandPartB();
+            break;
+
+        case NO_RAND_PART_C_STATE:
+            setupNoRandPartC();
+            break;
+
+        default:
+            throw new IllegalStateException();
+        }
+
+        return retChar;
+    }
+
+    private void init() throws IOException {
+        int magic2 = this.in.read();
+        if (magic2 != 'h') {
+            throw new IOException("Stream is not BZip2 formatted: expected 'h'"
+                                  + " as first byte but got '" + (char) magic2
+                                  + "'");
+        }
+
+        int blockSize = this.in.read();
+        if ((blockSize < '1') || (blockSize > '9')) {
+            throw new IOException("Stream is not BZip2 formatted: illegal "
+                                  + "blocksize " + (char) blockSize);
+        }
+
+        this.blockSize100k = blockSize - '0';
+
+        initBlock();
+        setupBlock();
+    }
+
+    private void initBlock() throws IOException {
+        char magic0 = bsGetUByte();
+        char magic1 = bsGetUByte();
+        char magic2 = bsGetUByte();
+        char magic3 = bsGetUByte();
+        char magic4 = bsGetUByte();
+        char magic5 = bsGetUByte();
+
+        if (magic0 == 0x17 &&
+            magic1 == 0x72 &&
+            magic2 == 0x45 &&
+            magic3 == 0x38 &&
+            magic4 == 0x50 &&
+            magic5 == 0x90) {
+            complete(); // end of file
+        } else if (magic0 != 0x31 || // '1'
+                   magic1 != 0x41 || // ')'
+                   magic2 != 0x59 || // 'Y'
+                   magic3 != 0x26 || // '&'
+                   magic4 != 0x53 || // 'S'
+                   magic5 != 0x59   // 'Y'
+                   ) {
+            this.currentState = EOF;
+            throw new IOException("bad block header");
+        } else {
+            this.storedBlockCRC = bsGetInt();
+            this.blockRandomised = bsR(1) == 1;
+
+            /**
+             * Allocate data here instead in constructor, so we do not
+             * allocate it if the input file is empty.
+             */
+            if (this.data == null) {
+                this.data = new Data(this.blockSize100k);
+            }
+
+            // currBlockNo++;
+            getAndMoveToFrontDecode();
+
+            this.crc.initialiseCRC();
+            this.currentState = START_BLOCK_STATE;
+        }
+    }
+
+    private void endBlock() throws IOException {
+        this.computedBlockCRC = this.crc.getFinalCRC();
+
+        // A bad CRC is considered a fatal error.
+        if (this.storedBlockCRC != this.computedBlockCRC) {
+            // make next blocks readable without error
+            // (repair feature, not yet documented, not tested)
+            this.computedCombinedCRC
+                = (this.storedCombinedCRC << 1)
+                | (this.storedCombinedCRC >>> 31);
+            this.computedCombinedCRC ^= this.storedBlockCRC;
+
+            reportCRCError();
+        }
+
+        this.computedCombinedCRC
+            = (this.computedCombinedCRC << 1)
+            | (this.computedCombinedCRC >>> 31);
+        this.computedCombinedCRC ^= this.computedBlockCRC;
+    }
+
+    private void complete() throws IOException {
+        this.storedCombinedCRC = bsGetInt();
+        this.currentState = EOF;
+        this.data = null;
+
+        if (this.storedCombinedCRC != this.computedCombinedCRC) {
+            reportCRCError();
+        }
+    }
+
+    public void close() throws IOException {
+        InputStream inShadow = this.in;
+        if (inShadow != null) {
+            try {
+                if (inShadow != System.in) {
+                    inShadow.close();
+                }
+            } finally {
+                this.data = null;
+                this.in = null;
+            }
+        }
+    }
+
+    private int bsR(final int n) throws IOException {
+        int bsLiveShadow = this.bsLive;
+        int bsBuffShadow = this.bsBuff;
+
+        if (bsLiveShadow < n) {
+            final InputStream inShadow = this.in;
+            do {
+                int thech = inShadow.read();
+
+                if (thech < 0) {
+                    throw new IOException("unexpected end of stream");
+                }
+
+                bsBuffShadow = (bsBuffShadow << 8) | thech;
+                bsLiveShadow += 8;
+            } while (bsLiveShadow < n);
+
+            this.bsBuff = bsBuffShadow;
+        }
+
+        this.bsLive = bsLiveShadow - n;
+        return (bsBuffShadow >> (bsLiveShadow - n)) & ((1 << n) - 1);
+    }
+
+    private boolean bsGetBit() throws IOException {
+        int bsLiveShadow = this.bsLive;
+        int bsBuffShadow = this.bsBuff;
+
+        if (bsLiveShadow < 1) {
+            int thech = this.in.read();
+
+            if (thech < 0) {
+                throw new IOException("unexpected end of stream");
+            }
+
+            bsBuffShadow = (bsBuffShadow << 8) | thech;
+            bsLiveShadow += 8;
+            this.bsBuff = bsBuffShadow;
+        }
+
+        this.bsLive = bsLiveShadow - 1;
+        return ((bsBuffShadow >> (bsLiveShadow - 1)) & 1) != 0;
+    }
+
+    private char bsGetUByte() throws IOException {
+        return (char) bsR(8);
+    }
+
+    private int bsGetInt() throws IOException {
+        return (((((bsR(8) << 8) | bsR(8)) << 8) | bsR(8)) << 8) | bsR(8);
+    }
+
+    /**
+     * Called by createHuffmanDecodingTables() exclusively.
+     */
+    private static void hbCreateDecodeTables(final int[] limit,
+                                             final int[] base,
+                                             final int[] perm,
+                                             final char[] length,
+                                             final int minLen,
+                                             final int maxLen,
+                                             final int alphaSize) {
+        for (int i = minLen, pp = 0; i <= maxLen; i++) {
+            for (int j = 0; j < alphaSize; j++) {
+                if (length[j] == i) {
+                    perm[pp++] = j;
+                }
+            }
+        }
+
+        for (int i = MAX_CODE_LEN; --i > 0;) {
+            base[i] = 0;
+            limit[i] = 0;
+        }
+
+        for (int i = 0; i < alphaSize; i++) {
+            base[length[i] + 1]++;
+        }
+
+        for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {
+            b += base[i];
+            base[i] = b;
+        }
+
+        for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {
+            final int nb = base[i + 1];
+            vec += nb - b;
+            b = nb;
+            limit[i] = vec - 1;
+            vec <<= 1;
+        }
+
+        for (int i = minLen + 1; i <= maxLen; i++) {
+            base[i] = ((limit[i - 1] + 1) << 1) - base[i];
+        }
+    }
+
+    private void recvDecodingTables() throws IOException {
+        final Data dataShadow     = this.data;
+        final boolean[] inUse     = dataShadow.inUse;
+        final byte[] pos          = dataShadow.recvDecodingTables_pos;
+        final byte[] selector     = dataShadow.selector;
+        final byte[] selectorMtf  = dataShadow.selectorMtf;
+
+        int inUse16 = 0;
+
+        /* Receive the mapping table */
+        for (int i = 0; i < 16; i++) {
+            if (bsGetBit()) {
+                inUse16 |= 1 << i;
+            }
+        }
+
+        for (int i = 256; --i >= 0;) {
+            inUse[i] = false;
+        }
+
+        for (int i = 0; i < 16; i++) {
+            if ((inUse16 & (1 << i)) != 0) {
+                final int i16 = i << 4;
+                for (int j = 0; j < 16; j++) {
+                    if (bsGetBit()) {
+                        inUse[i16 + j] = true;
+                    }
+                }
+            }
+        }
+
+        makeMaps();
+        final int alphaSize = this.nInUse + 2;
+
+        /* Now the selectors */
+        final int nGroups = bsR(3);
+        final int nSelectors = bsR(15);
+
+        for (int i = 0; i < nSelectors; i++) {
+            int j = 0;
+            while (bsGetBit()) {
+                j++;
+            }
+            selectorMtf[i] = (byte) j;
+        }
+
+        /* Undo the MTF values for the selectors. */
+        for (int v = nGroups; --v >= 0;) {
+            pos[v] = (byte) v;
+        }
+
+        for (int i = 0; i < nSelectors; i++) {
+            int v = selectorMtf[i] & 0xff;
+            final byte tmp = pos[v];
+            while (v > 0) {
+                // nearly all times v is zero, 4 in most other cases
+                pos[v] = pos[v - 1];
+                v--;
+            }
+            pos[0] = tmp;
+            selector[i] = tmp;
+        }
+
+        final char[][] len  = dataShadow.temp_charArray2d;
+
+        /* Now the coding tables */
+        for (int t = 0; t < nGroups; t++) {
+            int curr = bsR(5);
+            final char[] len_t = len[t];
+            for (int i = 0; i < alphaSize; i++) {
+                while (bsGetBit()) {
+                    curr += bsGetBit() ? -1 : 1;
+                }
+                len_t[i] = (char) curr;
+            }
+        }
+
+        // finally create the Huffman tables
+        createHuffmanDecodingTables(alphaSize, nGroups);
+    }
+
+    /**
+     * Called by recvDecodingTables() exclusively.
+     */
+    private void createHuffmanDecodingTables(final int alphaSize,
+                                             final int nGroups) {
+        final Data dataShadow = this.data;
+        final char[][] len  = dataShadow.temp_charArray2d;
+        final int[] minLens = dataShadow.minLens;
+        final int[][] limit = dataShadow.limit;
+        final int[][] base  = dataShadow.base;
+        final int[][] perm  = dataShadow.perm;
+
+        for (int t = 0; t < nGroups; t++) {
+            int minLen = 32;
+            int maxLen = 0;
+            final char[] len_t = len[t];
+            for (int i = alphaSize; --i >= 0;) {
+                final char lent = len_t[i];
+                if (lent > maxLen) {
+                    maxLen = lent;
+                }
+                if (lent < minLen) {
+                    minLen = lent;
+                }
+            }
+            hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,
+                                 maxLen, alphaSize);
+            minLens[t] = minLen;
+        }
+    }
+
+    private void getAndMoveToFrontDecode() throws IOException {
+        this.origPtr = bsR(24);
+        recvDecodingTables();
+
+        final InputStream inShadow = this.in;
+        final Data dataShadow   = this.data;
+        final byte[] ll8        = dataShadow.ll8;
+        final int[] unzftab     = dataShadow.unzftab;
+        final byte[] selector   = dataShadow.selector;
+        final byte[] seqToUnseq = dataShadow.seqToUnseq;
+        final char[] yy         = dataShadow.getAndMoveToFrontDecode_yy;
+        final int[] minLens     = dataShadow.minLens;
+        final int[][] limit     = dataShadow.limit;
+        final int[][] base      = dataShadow.base;
+        final int[][] perm      = dataShadow.perm;
+        final int limitLast     = this.blockSize100k * 100000;
+
+        /*
+          Setting up the unzftab entries here is not strictly
+          necessary, but it does save having to do it later
+          in a separate pass, and so saves a block's worth of
+          cache misses.
+        */
+        for (int i = 256; --i >= 0;) {
+            yy[i] = (char) i;
+            unzftab[i] = 0;
+        }
+
+        int groupNo     = 0;
+        int groupPos    = G_SIZE - 1;
+        final int eob   = this.nInUse + 1;
+        int nextSym     = getAndMoveToFrontDecode0(0);
+        int bsBuffShadow      = this.bsBuff;
+        int bsLiveShadow      = this.bsLive;
+        int lastShadow        = -1;
+        int zt          = selector[groupNo] & 0xff;
+        int[] base_zt   = base[zt];
+        int[] limit_zt  = limit[zt];
+        int[] perm_zt   = perm[zt];
+        int minLens_zt  = minLens[zt];
+
+        while (nextSym != eob) {
+            if ((nextSym == RUNA) || (nextSym == RUNB)) {
+                int s = -1;
+
+                for (int n = 1; true; n <<= 1) {
+                    if (nextSym == RUNA) {
+                        s += n;
+                    } else if (nextSym == RUNB) {
+                        s += n << 1;
+                    } else {
+                        break;
+                    }
+
+                    if (groupPos == 0) {
+                        groupPos    = G_SIZE - 1;
+                        zt          = selector[++groupNo] & 0xff;
+                        base_zt     = base[zt];
+                        limit_zt    = limit[zt];
+                        perm_zt     = perm[zt];
+                        minLens_zt  = minLens[zt];
+                    } else {
+                        groupPos--;
+                    }
+
+                    int zn = minLens_zt;
+
+                    // Inlined:
+                    // int zvec = bsR(zn);
+                    while (bsLiveShadow < zn) {
+                        final int thech = inShadow.read();
+                        if (thech >= 0) {
+                            bsBuffShadow = (bsBuffShadow << 8) | thech;
+                            bsLiveShadow += 8;
+                            continue;
+                        } else {
+                            throw new IOException("unexpected end of stream");
+                        }
+                    }
+                    int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
+                    bsLiveShadow -= zn;
+
+                    while (zvec > limit_zt[zn]) {
+                        zn++;
+                        while (bsLiveShadow < 1) {
+                            final int thech = inShadow.read();
+                            if (thech >= 0) {
+                                bsBuffShadow = (bsBuffShadow << 8) | thech;
+                                bsLiveShadow += 8;
+                                continue;
+                            } else {
+                                throw new IOException("unexpected end of stream");
+                            }
+                        }
+                        bsLiveShadow--;
+                        zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
+                    }
+                    nextSym = perm_zt[zvec - base_zt[zn]];
+                }
+
+                final byte ch = seqToUnseq[yy[0]];
+                unzftab[ch & 0xff] += s + 1;
+
+                while (s-- >= 0) {
+                    ll8[++lastShadow] = ch;
+                }
+
+                if (lastShadow >= limitLast) {
+                    throw new IOException("block overrun");
+                }
+            } else {
+                if (++lastShadow >= limitLast) {
+                    throw new IOException("block overrun");
+                }
+
+                final char tmp = yy[nextSym - 1];
+                unzftab[seqToUnseq[tmp] & 0xff]++;
+                ll8[lastShadow] = seqToUnseq[tmp];
+
+                /*
+                  This loop is hammered during decompression,
+                  hence avoid native method call overhead of
+                  System.arraycopy for very small ranges to copy.
+                */
+                if (nextSym <= 16) {
+                    for (int j = nextSym - 1; j > 0;) {
+                        yy[j] = yy[--j];
+                    }
+                } else {
+                    System.arraycopy(yy, 0, yy, 1, nextSym - 1);
+                }
+
+                yy[0] = tmp;
+
+                if (groupPos == 0) {
+                    groupPos    = G_SIZE - 1;
+                    zt          = selector[++groupNo] & 0xff;
+                    base_zt     = base[zt];
+                    limit_zt    = limit[zt];
+                    perm_zt     = perm[zt];
+                    minLens_zt  = minLens[zt];
+                } else {
+                    groupPos--;
+                }
+
+                int zn = minLens_zt;
+
+                // Inlined:
+                // int zvec = bsR(zn);
+                while (bsLiveShadow < zn) {
+                    final int thech = inShadow.read();
+                    if (thech >= 0) {
+                        bsBuffShadow = (bsBuffShadow << 8) | thech;
+                        bsLiveShadow += 8;
+                        continue;
+                    } else {
+                        throw new IOException("unexpected end of stream");
+                    }
+                }
+                int zvec = (bsBuffShadow >> (bsLiveShadow - zn)) & ((1 << zn) - 1);
+                bsLiveShadow -= zn;
+
+                while (zvec > limit_zt[zn]) {
+                    zn++;
+                    while (bsLiveShadow < 1) {
+                        final int thech = inShadow.read();
+                        if (thech >= 0) {
+                            bsBuffShadow = (bsBuffShadow << 8) | thech;
+                            bsLiveShadow += 8;
+                            continue;
+                        } else {
+                            throw new IOException("unexpected end of stream");
+                        }
+                    }
+                    bsLiveShadow--;
+                    zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
+                }
+                nextSym = perm_zt[zvec - base_zt[zn]];
+            }
+        }
+
+        this.last = lastShadow;
+        this.bsLive = bsLiveShadow;
+        this.bsBuff = bsBuffShadow;
+    }
+
+    private int getAndMoveToFrontDecode0(final int groupNo)
+        throws IOException {
+        final InputStream inShadow  = this.in;
+        final Data dataShadow  = this.data;
+        final int zt          = dataShadow.selector[groupNo] & 0xff;
+        final int[] limit_zt  = dataShadow.limit[zt];
+        int zn = dataShadow.minLens[zt];
+        int zvec = bsR(zn);
+        int bsLiveShadow = this.bsLive;
+        int bsBuffShadow = this.bsBuff;
+
+        while (zvec > limit_zt[zn]) {
+            zn++;
+            while (bsLiveShadow < 1) {
+                final int thech = inShadow.read();
+
+                if (thech >= 0) {
+                    bsBuffShadow = (bsBuffShadow << 8) | thech;
+                    bsLiveShadow += 8;
+                    continue;
+                } else {
+                    throw new IOException("unexpected end of stream");
+                }
+            }
+            bsLiveShadow--;
+            zvec = (zvec << 1) | ((bsBuffShadow >> bsLiveShadow) & 1);
+        }
+
+        this.bsLive = bsLiveShadow;
+        this.bsBuff = bsBuffShadow;
+
+        return dataShadow.perm[zt][zvec - dataShadow.base[zt][zn]];
+    }
+
+    private void setupBlock() throws IOException {
+        if (this.data == null) {
+            return;
+        }
+
+        final int[] cftab = this.data.cftab;
+        final int[] tt    = this.data.initTT(this.last + 1);
+        final byte[] ll8  = this.data.ll8;
+        cftab[0] = 0;
+        System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);
+
+        for (int i = 1, c = cftab[0]; i <= 256; i++) {
+            c += cftab[i];
+            cftab[i] = c;
+        }
+
+        for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {
+            tt[cftab[ll8[i] & 0xff]++] = i;
+        }
+
+        if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {
+            throw new IOException("stream corrupted");
+        }
+
+        this.su_tPos = tt[this.origPtr];
+        this.su_count = 0;
+        this.su_i2 = 0;
+        this.su_ch2 = 256;   /* not a char and not EOF */
+
+        if (this.blockRandomised) {
+            this.su_rNToGo = 0;
+            this.su_rTPos = 0;
+            setupRandPartA();
+        } else {
+            setupNoRandPartA();
+        }
+    }
+
+    private void setupRandPartA() throws IOException {
+        if (this.su_i2 <= this.last) {
+            this.su_chPrev = this.su_ch2;
+            int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
+            this.su_tPos = this.data.tt[this.su_tPos];
+            if (this.su_rNToGo == 0) {
+                this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
+                if (++this.su_rTPos == 512) {
+                    this.su_rTPos = 0;
+                }
+            } else {
+                this.su_rNToGo--;
+            }
+            this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;
+            this.su_i2++;
+            this.currentChar = su_ch2Shadow;
+            this.currentState = RAND_PART_B_STATE;
+            this.crc.updateCRC(su_ch2Shadow);
+        } else {
+            endBlock();
+            initBlock();
+            setupBlock();
+        }
+    }
+
+    private void setupNoRandPartA() throws IOException {
+        if (this.su_i2 <= this.last) {
+            this.su_chPrev = this.su_ch2;
+            int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;
+            this.su_ch2 = su_ch2Shadow;
+            this.su_tPos = this.data.tt[this.su_tPos];
+            this.su_i2++;
+            this.currentChar = su_ch2Shadow;
+            this.currentState = NO_RAND_PART_B_STATE;
+            this.crc.updateCRC(su_ch2Shadow);
+        } else {
+            this.currentState = NO_RAND_PART_A_STATE;
+            endBlock();
+            initBlock();
+            setupBlock();
+        }
+    }
+
+    private void setupRandPartB() throws IOException {
+        if (this.su_ch2 != this.su_chPrev) {
+            this.currentState = RAND_PART_A_STATE;
+            this.su_count = 1;
+            setupRandPartA();
+        } else if (++this.su_count >= 4) {
+            this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
+            this.su_tPos = this.data.tt[this.su_tPos];
+            if (this.su_rNToGo == 0) {
+                this.su_rNToGo = BZip2Constants.rNums[this.su_rTPos] - 1;
+                if (++this.su_rTPos == 512) {
+                    this.su_rTPos = 0;
+                }
+            } else {
+                this.su_rNToGo--;
+            }
+            this.su_j2 = 0;
+            this.currentState = RAND_PART_C_STATE;
+            if (this.su_rNToGo == 1) {
+                this.su_z ^= 1;
+            }
+            setupRandPartC();
+        } else {
+            this.currentState = RAND_PART_A_STATE;
+            setupRandPartA();
+        }
+    }
+
+    private void setupRandPartC() throws IOException {
+        if (this.su_j2 < this.su_z) {
+            this.currentChar = this.su_ch2;
+            this.crc.updateCRC(this.su_ch2);
+            this.su_j2++;
+        } else {
+            this.currentState = RAND_PART_A_STATE;
+            this.su_i2++;
+            this.su_count = 0;
+            setupRandPartA();
+        }
+    }
+
+    private void setupNoRandPartB() throws IOException {
+        if (this.su_ch2 != this.su_chPrev) {
+            this.su_count = 1;
+            setupNoRandPartA();
+        } else if (++this.su_count >= 4) {
+            this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);
+            this.su_tPos = this.data.tt[this.su_tPos];
+            this.su_j2 = 0;
+            setupNoRandPartC();
+        } else {
+            setupNoRandPartA();
+        }
+    }
+
+    private void setupNoRandPartC() throws IOException {
+        if (this.su_j2 < this.su_z) {
+            int su_ch2Shadow = this.su_ch2;
+            this.currentChar = su_ch2Shadow;
+            this.crc.updateCRC(su_ch2Shadow);
+            this.su_j2++;
+            this.currentState = NO_RAND_PART_C_STATE;
+        } else {
+            this.su_i2++;
+            this.su_count = 0;
+            setupNoRandPartA();
+        }
+    }
+
+    private static final class Data extends Object {
+
+        // (with blockSize 900k)
+        final boolean[] inUse   = new boolean[256];                                   //      256 byte
+
+        final byte[] seqToUnseq   = new byte[256];                                    //      256 byte
+        final byte[] selector     = new byte[MAX_SELECTORS];                          //    18002 byte
+        final byte[] selectorMtf  = new byte[MAX_SELECTORS];                          //    18002 byte
+
+        /**
+         * Freq table collected to save a pass over the data during
+         * decompression.
+         */
+        final int[] unzftab = new int[256];                                           //     1024 byte
+
+        final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte
+        final int[][] base  = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte
+        final int[][] perm  = new int[N_GROUPS][MAX_ALPHA_SIZE];                      //     6192 byte
+        final int[] minLens = new int[N_GROUPS];                                      //       24 byte
+
+        final int[]     cftab     = new int[257];                                     //     1028 byte
+        final char[]    getAndMoveToFrontDecode_yy = new char[256];                   //      512 byte
+        final char[][]  temp_charArray2d  = new char[N_GROUPS][MAX_ALPHA_SIZE];       //     3096 byte
+        final byte[] recvDecodingTables_pos = new byte[N_GROUPS];                     //        6 byte
+        //---------------
+        //    60798 byte
+
+        int[] tt;                                                                     //  3600000 byte
+        byte[] ll8;                                                                   //   900000 byte
+        //---------------
+        //  4560782 byte
+        //===============
+
+        Data(int blockSize100k) {
+            super();
+
+            this.ll8 = new byte[blockSize100k * BZip2Constants.baseBlockSize];
+        }
+
+        /**
+         * Initializes the {@link #tt} array.
+         *
+         * This method is called when the required length of the array
+         * is known.  I don't initialize it at construction time to
+         * avoid unneccessary memory allocation when compressing small
+         * files.
+         */
+        final int[] initTT(int length) {
+            int[] ttShadow = this.tt;
+
+            // tt.length should always be >= length, but theoretically
+            // it can happen, if the compressor mixed small and large
+            // blocks.  Normally only the last block will be smaller
+            // than others.
+            if ((ttShadow == null) || (ttShadow.length < length)) {
+                this.tt = ttShadow = new int[length];
+            }
+
+            return ttShadow;
+        }
+
+    }
+}
+
diff --git a/trunk/src/main/org/apache/tools/bzip2/CBZip2OutputStream.java b/trunk/src/main/org/apache/tools/bzip2/CBZip2OutputStream.java
new file mode 100644
index 0000000..c99c915
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/bzip2/CBZip2OutputStream.java
@@ -0,0 +1,1632 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+package org.apache.tools.bzip2;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * An output stream that compresses into the BZip2 format (without the file
+ * header chars) into another stream.
+ *
+ * TODO:    Update to BZip2 1.0.1
+ */
+public class CBZip2OutputStream extends OutputStream implements BZip2Constants {
+    protected static final int SETMASK = (1 << 21);
+    protected static final int CLEARMASK = (~SETMASK);
+    protected static final int GREATER_ICOST = 15;
+    protected static final int LESSER_ICOST = 0;
+    protected static final int SMALL_THRESH = 20;
+    protected static final int DEPTH_THRESH = 10;
+
+    /*
+      If you are ever unlucky/improbable enough
+      to get a stack overflow whilst sorting,
+      increase the following constant and try
+      again.  In practice I have never seen the
+      stack go above 27 elems, so the following
+      limit seems very generous.
+    */
+    protected static final int QSORT_STACK_SIZE = 1000;
+
+    private static void panic() {
+        System.out.println("panic");
+        //throw new CError();
+    }
+
+    private void makeMaps() {
+        int i;
+        nInUse = 0;
+        for (i = 0; i < 256; i++) {
+            if (inUse[i]) {
+                seqToUnseq[nInUse] = (char) i;
+                unseqToSeq[i] = (char) nInUse;
+                nInUse++;
+            }
+        }
+    }
+
+    protected static void hbMakeCodeLengths(char[] len, int[] freq,
+                                            int alphaSize, int maxLen) {
+        /*
+          Nodes and heap entries run from 1.  Entry 0
+          for both the heap and nodes is a sentinel.
+        */
+        int nNodes, nHeap, n1, n2, i, j, k;
+        boolean  tooLong;
+
+        int[] heap = new int[MAX_ALPHA_SIZE + 2];
+        int[] weight = new int[MAX_ALPHA_SIZE * 2];
+        int[] parent = new int[MAX_ALPHA_SIZE * 2];
+
+        for (i = 0; i < alphaSize; i++) {
+            weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+        }
+
+        while (true) {
+            nNodes = alphaSize;
+            nHeap = 0;
+
+            heap[0] = 0;
+            weight[0] = 0;
+            parent[0] = -2;
+
+            for (i = 1; i <= alphaSize; i++) {
+                parent[i] = -1;
+                nHeap++;
+                heap[nHeap] = i;
+                {
+                    int zz, tmp;
+                    zz = nHeap;
+                    tmp = heap[zz];
+                    while (weight[tmp] < weight[heap[zz >> 1]]) {
+                        heap[zz] = heap[zz >> 1];
+                        zz >>= 1;
+                    }
+                    heap[zz] = tmp;
+                }
+            }
+            if (!(nHeap < (MAX_ALPHA_SIZE + 2))) {
+                panic();
+            }
+
+            while (nHeap > 1) {
+                n1 = heap[1];
+                heap[1] = heap[nHeap];
+                nHeap--;
+                {
+                    int zz = 0, yy = 0, tmp = 0;
+                    zz = 1;
+                    tmp = heap[zz];
+                    while (true) {
+                        yy = zz << 1;
+                        if (yy > nHeap) {
+                            break;
+                        }
+                        if (yy < nHeap
+                            && weight[heap[yy + 1]] < weight[heap[yy]]) {
+                            yy++;
+                        }
+                        if (weight[tmp] < weight[heap[yy]]) {
+                            break;
+                        }
+                        heap[zz] = heap[yy];
+                        zz = yy;
+                    }
+                    heap[zz] = tmp;
+                }
+                n2 = heap[1];
+                heap[1] = heap[nHeap];
+                nHeap--;
+                {
+                    int zz = 0, yy = 0, tmp = 0;
+                    zz = 1;
+                    tmp = heap[zz];
+                    while (true) {
+                        yy = zz << 1;
+                        if (yy > nHeap) {
+                            break;
+                        }
+                        if (yy < nHeap
+                            && weight[heap[yy + 1]] < weight[heap[yy]]) {
+                            yy++;
+                        }
+                        if (weight[tmp] < weight[heap[yy]]) {
+                            break;
+                        }
+                        heap[zz] = heap[yy];
+                        zz = yy;
+                    }
+                    heap[zz] = tmp;
+                }
+                nNodes++;
+                parent[n1] = parent[n2] = nNodes;
+
+                weight[nNodes] = ((weight[n1] & 0xffffff00)
+                                  + (weight[n2] & 0xffffff00))
+                    | (1 + (((weight[n1] & 0x000000ff)
+                            > (weight[n2] & 0x000000ff))
+                            ? (weight[n1] & 0x000000ff)
+                            : (weight[n2] & 0x000000ff)));
+
+                parent[nNodes] = -1;
+                nHeap++;
+                heap[nHeap] = nNodes;
+                {
+                    int zz = 0, tmp = 0;
+                    zz = nHeap;
+                    tmp = heap[zz];
+                    while (weight[tmp] < weight[heap[zz >> 1]]) {
+                        heap[zz] = heap[zz >> 1];
+                        zz >>= 1;
+                    }
+                    heap[zz] = tmp;
+                }
+            }
+            if (!(nNodes < (MAX_ALPHA_SIZE * 2))) {
+                panic();
+            }
+
+            tooLong = false;
+            for (i = 1; i <= alphaSize; i++) {
+                j = 0;
+                k = i;
+                while (parent[k] >= 0) {
+                    k = parent[k];
+                    j++;
+                }
+                len[i - 1] = (char) j;
+                if (j > maxLen) {
+                    tooLong = true;
+                }
+            }
+
+            if (!tooLong) {
+                break;
+            }
+
+            for (i = 1; i < alphaSize; i++) {
+                j = weight[i] >> 8;
+                j = 1 + (j / 2);
+                weight[i] = j << 8;
+            }
+        }
+    }
+
+    /*
+      index of the last char in the block, so
+      the block size == last + 1.
+    */
+    int last;
+
+    /*
+      index in zptr[] of original string after sorting.
+    */
+    int origPtr;
+
+    /*
+      always: in the range 0 .. 9.
+      The current block size is 100000 * this number.
+    */
+    int blockSize100k;
+
+    boolean blockRandomised;
+
+    int bytesOut;
+    int bsBuff;
+    int bsLive;
+    CRC mCrc = new CRC();
+
+    private boolean[] inUse = new boolean[256];
+    private int nInUse;
+
+    private char[] seqToUnseq = new char[256];
+    private char[] unseqToSeq = new char[256];
+
+    private char[] selector = new char[MAX_SELECTORS];
+    private char[] selectorMtf = new char[MAX_SELECTORS];
+
+    private char[] block;
+    private int[] quadrant;
+    private int[] zptr;
+    private short[] szptr;
+    private int[] ftab;
+
+    private int nMTF;
+
+    private int[] mtfFreq = new int[MAX_ALPHA_SIZE];
+
+    /*
+     * Used when sorting.  If too many long comparisons
+     * happen, we stop sorting, randomise the block
+     * slightly, and try again.
+     */
+    private int workFactor;
+    private int workDone;
+    private int workLimit;
+    private boolean firstAttempt;
+    private int nBlocksRandomised;
+
+    private int currentChar = -1;
+    private int runLength = 0;
+
+    public CBZip2OutputStream(OutputStream inStream) throws IOException {
+        this(inStream, 9);
+    }
+
+    public CBZip2OutputStream(OutputStream inStream, int inBlockSize)
+        throws IOException {
+        block = null;
+        quadrant = null;
+        zptr = null;
+        ftab = null;
+
+        bsSetStream(inStream);
+
+        workFactor = 50;
+        if (inBlockSize > 9) {
+            inBlockSize = 9;
+        }
+        if (inBlockSize < 1) {
+            inBlockSize = 1;
+        }
+        blockSize100k = inBlockSize;
+        allocateCompressStructures();
+        initialize();
+        initBlock();
+    }
+
+    /**
+     *
+     * modified by Oliver Merkel, 010128
+     *
+     */
+    public void write(int bv) throws IOException {
+        int b = (256 + bv) % 256;
+        if (currentChar != -1) {
+            if (currentChar == b) {
+                runLength++;
+                if (runLength > 254) {
+                    writeRun();
+                    currentChar = -1;
+                    runLength = 0;
+                }
+            } else {
+                writeRun();
+                runLength = 1;
+                currentChar = b;
+            }
+        } else {
+            currentChar = b;
+            runLength++;
+        }
+    }
+
+    private void writeRun() throws IOException {
+        if (last < allowableBlockSize) {
+            inUse[currentChar] = true;
+            for (int i = 0; i < runLength; i++) {
+                mCrc.updateCRC((char) currentChar);
+            }
+            switch (runLength) {
+            case 1:
+                last++;
+                block[last + 1] = (char) currentChar;
+                break;
+            case 2:
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                break;
+            case 3:
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                break;
+            default:
+                inUse[runLength - 4] = true;
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) currentChar;
+                last++;
+                block[last + 1] = (char) (runLength - 4);
+                break;
+            }
+        } else {
+            endBlock();
+            initBlock();
+            writeRun();
+        }
+    }
+
+    boolean closed = false;
+
+    protected void finalize() throws Throwable {
+        close();
+        super.finalize();
+    }
+
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+
+        if (runLength > 0) {
+            writeRun();
+        }
+        currentChar = -1;
+        endBlock();
+        endCompression();
+        closed = true;
+        super.close();
+        bsStream.close();
+    }
+
+    public void flush() throws IOException {
+        super.flush();
+        bsStream.flush();
+    }
+
+    private int blockCRC, combinedCRC;
+
+    private void initialize() throws IOException {
+        bytesOut = 0;
+        nBlocksRandomised = 0;
+
+        /* Write `magic' bytes h indicating file-format == huffmanised,
+           followed by a digit indicating blockSize100k.
+        */
+        bsPutUChar('h');
+        bsPutUChar('0' + blockSize100k);
+
+        combinedCRC = 0;
+    }
+
+    private int allowableBlockSize;
+
+    private void initBlock() {
+        //        blockNo++;
+        mCrc.initialiseCRC();
+        last = -1;
+        //        ch = 0;
+
+        for (int i = 0; i < 256; i++) {
+            inUse[i] = false;
+        }
+
+        /* 20 is just a paranoia constant */
+        allowableBlockSize = baseBlockSize * blockSize100k - 20;
+    }
+
+    private void endBlock() throws IOException {
+        blockCRC = mCrc.getFinalCRC();
+        combinedCRC = (combinedCRC << 1) | (combinedCRC >>> 31);
+        combinedCRC ^= blockCRC;
+
+        /* sort the block and establish posn of original string */
+        doReversibleTransformation();
+
+        /*
+          A 6-byte block header, the value chosen arbitrarily
+          as 0x314159265359 :-).  A 32 bit value does not really
+          give a strong enough guarantee that the value will not
+          appear by chance in the compressed datastream.  Worst-case
+          probability of this event, for a 900k block, is about
+          2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+          For a compressed file of size 100Gb -- about 100000 blocks --
+          only a 48-bit marker will do.  NB: normal compression/
+          decompression do *not* rely on these statistical properties.
+          They are only important when trying to recover blocks from
+          damaged files.
+        */
+        bsPutUChar(0x31);
+        bsPutUChar(0x41);
+        bsPutUChar(0x59);
+        bsPutUChar(0x26);
+        bsPutUChar(0x53);
+        bsPutUChar(0x59);
+
+        /* Now the block's CRC, so it is in a known place. */
+        bsPutint(blockCRC);
+
+        /* Now a single bit indicating randomisation. */
+        if (blockRandomised) {
+            bsW(1, 1);
+            nBlocksRandomised++;
+        } else {
+            bsW(1, 0);
+        }
+
+        /* Finally, block's contents proper. */
+        moveToFrontCodeAndSend();
+    }
+
+    private void endCompression() throws IOException {
+        /*
+          Now another magic 48-bit number, 0x177245385090, to
+          indicate the end of the last block.  (sqrt(pi), if
+          you want to know.  I did want to use e, but it contains
+          too much repetition -- 27 18 28 18 28 46 -- for me
+          to feel statistically comfortable.  Call me paranoid.)
+        */
+        bsPutUChar(0x17);
+        bsPutUChar(0x72);
+        bsPutUChar(0x45);
+        bsPutUChar(0x38);
+        bsPutUChar(0x50);
+        bsPutUChar(0x90);
+
+        bsPutint(combinedCRC);
+
+        bsFinishedWithStream();
+    }
+
+    private void hbAssignCodes (int[] code, char[] length, int minLen,
+                                int maxLen, int alphaSize) {
+        int n, vec, i;
+
+        vec = 0;
+        for (n = minLen; n <= maxLen; n++) {
+            for (i = 0; i < alphaSize; i++) {
+                if (length[i] == n) {
+                    code[i] = vec;
+                    vec++;
+                }
+            };
+            vec <<= 1;
+        }
+    }
+
+    private void bsSetStream(OutputStream f) {
+        bsStream = f;
+        bsLive = 0;
+        bsBuff = 0;
+        bytesOut = 0;
+    }
+
+    private void bsFinishedWithStream() throws IOException {
+        while (bsLive > 0) {
+            int ch = (bsBuff >> 24);
+            try {
+                bsStream.write(ch); // write 8-bit
+            } catch (IOException e) {
+                throw  e;
+            }
+            bsBuff <<= 8;
+            bsLive -= 8;
+            bytesOut++;
+        }
+    }
+
+    private void bsW(int n, int v) throws IOException {
+        while (bsLive >= 8) {
+            int ch = (bsBuff >> 24);
+            try {
+                bsStream.write(ch); // write 8-bit
+            } catch (IOException e) {
+                throw e;
+            }
+            bsBuff <<= 8;
+            bsLive -= 8;
+            bytesOut++;
+        }
+        bsBuff |= (v << (32 - bsLive - n));
+        bsLive += n;
+    }
+
+    private void bsPutUChar(int c) throws IOException {
+        bsW(8, c);
+    }
+
+    private void bsPutint(int u) throws IOException {
+        bsW(8, (u >> 24) & 0xff);
+        bsW(8, (u >> 16) & 0xff);
+        bsW(8, (u >>  8) & 0xff);
+        bsW(8,  u        & 0xff);
+    }
+
+    private void bsPutIntVS(int numBits, int c) throws IOException {
+        bsW(numBits, c);
+    }
+
+    private void sendMTFValues() throws IOException {
+        char len[][] = new char[N_GROUPS][MAX_ALPHA_SIZE];
+
+        int v, t, i, j, gs, ge, totc, bt, bc, iter;
+        int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+        int nGroups, nBytes;
+
+        alphaSize = nInUse + 2;
+        for (t = 0; t < N_GROUPS; t++) {
+            for (v = 0; v < alphaSize; v++) {
+                len[t][v] = (char) GREATER_ICOST;
+            }
+        }
+
+        /* Decide how many coding tables to use */
+        if (nMTF <= 0) {
+            panic();
+        }
+
+        if (nMTF < 200) {
+            nGroups = 2;
+        } else if (nMTF < 600) {
+            nGroups = 3;
+        } else if (nMTF < 1200) {
+            nGroups = 4;
+        } else if (nMTF < 2400) {
+            nGroups = 5;
+        } else {
+            nGroups = 6;
+        }
+
+        /* Generate an initial set of coding tables */ {
+            int nPart, remF, tFreq, aFreq;
+
+            nPart = nGroups;
+            remF  = nMTF;
+            gs = 0;
+            while (nPart > 0) {
+                tFreq = remF / nPart;
+                ge = gs - 1;
+                aFreq = 0;
+                while (aFreq < tFreq && ge < alphaSize - 1) {
+                    ge++;
+                    aFreq += mtfFreq[ge];
+                }
+
+                if (ge > gs && nPart != nGroups && nPart != 1
+                    && ((nGroups - nPart) % 2 == 1)) {
+                    aFreq -= mtfFreq[ge];
+                    ge--;
+                }
+
+                for (v = 0; v < alphaSize; v++) {
+                    if (v >= gs && v <= ge) {
+                        len[nPart - 1][v] = (char) LESSER_ICOST;
+                    } else {
+                        len[nPart - 1][v] = (char) GREATER_ICOST;
+                    }
+                }
+
+                nPart--;
+                gs = ge + 1;
+                remF -= aFreq;
+            }
+        }
+
+        int[][] rfreq = new int[N_GROUPS][MAX_ALPHA_SIZE];
+        int[] fave = new int[N_GROUPS];
+        short[] cost = new short[N_GROUPS];
+        /*
+          Iterate up to N_ITERS times to improve the tables.
+        */
+        for (iter = 0; iter < N_ITERS; iter++) {
+            for (t = 0; t < nGroups; t++) {
+                fave[t] = 0;
+            }
+
+            for (t = 0; t < nGroups; t++) {
+                for (v = 0; v < alphaSize; v++) {
+                    rfreq[t][v] = 0;
+                }
+            }
+
+            nSelectors = 0;
+            totc = 0;
+            gs = 0;
+            while (true) {
+
+                /* Set group start & end marks. */
+                if (gs >= nMTF) {
+                    break;
+                }
+                ge = gs + G_SIZE - 1;
+                if (ge >= nMTF) {
+                    ge = nMTF - 1;
+                }
+
+                /*
+                  Calculate the cost of this group as coded
+                  by each of the coding tables.
+                */
+                for (t = 0; t < nGroups; t++) {
+                    cost[t] = 0;
+                }
+
+                if (nGroups == 6) {
+                    short cost0, cost1, cost2, cost3, cost4, cost5;
+                    cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+                    for (i = gs; i <= ge; i++) {
+                        short icv = szptr[i];
+                        cost0 += len[0][icv];
+                        cost1 += len[1][icv];
+                        cost2 += len[2][icv];
+                        cost3 += len[3][icv];
+                        cost4 += len[4][icv];
+                        cost5 += len[5][icv];
+                    }
+                    cost[0] = cost0;
+                    cost[1] = cost1;
+                    cost[2] = cost2;
+                    cost[3] = cost3;
+                    cost[4] = cost4;
+                    cost[5] = cost5;
+                } else {
+                    for (i = gs; i <= ge; i++) {
+                        short icv = szptr[i];
+                        for (t = 0; t < nGroups; t++) {
+                            cost[t] += len[t][icv];
+                        }
+                    }
+                }
+
+                /*
+                  Find the coding table which is best for this group,
+                  and record its identity in the selector table.
+                */
+                bc = 999999999;
+                bt = -1;
+                for (t = 0; t < nGroups; t++) {
+                    if (cost[t] < bc) {
+                        bc = cost[t];
+                        bt = t;
+                    }
+                };
+                totc += bc;
+                fave[bt]++;
+                selector[nSelectors] = (char) bt;
+                nSelectors++;
+
+                /*
+                  Increment the symbol frequencies for the selected table.
+                */
+                for (i = gs; i <= ge; i++) {
+                    rfreq[bt][szptr[i]]++;
+                }
+
+                gs = ge + 1;
+            }
+
+            /*
+              Recompute the tables based on the accumulated frequencies.
+            */
+            for (t = 0; t < nGroups; t++) {
+                hbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+            }
+        }
+
+        rfreq = null;
+        fave = null;
+        cost = null;
+
+        if (!(nGroups < 8)) {
+            panic();
+        }
+        if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / G_SIZE)))) {
+            panic();
+        }
+
+
+        /* Compute MTF values for the selectors. */
+        {
+            char[] pos = new char[N_GROUPS];
+            char ll_i, tmp2, tmp;
+            for (i = 0; i < nGroups; i++) {
+                pos[i] = (char) i;
+            }
+            for (i = 0; i < nSelectors; i++) {
+                ll_i = selector[i];
+                j = 0;
+                tmp = pos[j];
+                while (ll_i != tmp) {
+                    j++;
+                    tmp2 = tmp;
+                    tmp = pos[j];
+                    pos[j] = tmp2;
+                }
+                pos[0] = tmp;
+                selectorMtf[i] = (char) j;
+            }
+        }
+
+        int[][] code = new int[N_GROUPS][MAX_ALPHA_SIZE];
+
+        /* Assign actual codes for the tables. */
+        for (t = 0; t < nGroups; t++) {
+            minLen = 32;
+            maxLen = 0;
+            for (i = 0; i < alphaSize; i++) {
+                if (len[t][i] > maxLen) {
+                    maxLen = len[t][i];
+                }
+                if (len[t][i] < minLen) {
+                    minLen = len[t][i];
+                }
+            }
+            if (maxLen > 20) {
+                panic();
+            }
+            if (minLen < 1) {
+                panic();
+            }
+            hbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+        }
+
+        /* Transmit the mapping table. */
+        {
+            boolean[] inUse16 = new boolean[16];
+            for (i = 0; i < 16; i++) {
+                inUse16[i] = false;
+                for (j = 0; j < 16; j++) {
+                    if (inUse[i * 16 + j]) {
+                        inUse16[i] = true;
+                    }
+                }
+            }
+
+            nBytes = bytesOut;
+            for (i = 0; i < 16; i++) {
+                if (inUse16[i]) {
+                    bsW(1, 1);
+                } else {
+                    bsW(1, 0);
+                }
+            }
+
+            for (i = 0; i < 16; i++) {
+                if (inUse16[i]) {
+                    for (j = 0; j < 16; j++) {
+                        if (inUse[i * 16 + j]) {
+                            bsW(1, 1);
+                        } else {
+                            bsW(1, 0);
+                        }
+                    }
+                }
+            }
+
+        }
+
+        /* Now the selectors. */
+        nBytes = bytesOut;
+        bsW (3, nGroups);
+        bsW (15, nSelectors);
+        for (i = 0; i < nSelectors; i++) {
+            for (j = 0; j < selectorMtf[i]; j++) {
+                bsW(1, 1);
+            }
+            bsW(1, 0);
+        }
+
+        /* Now the coding tables. */
+        nBytes = bytesOut;
+
+        for (t = 0; t < nGroups; t++) {
+            int curr = len[t][0];
+            bsW(5, curr);
+            for (i = 0; i < alphaSize; i++) {
+                while (curr < len[t][i]) {
+                    bsW(2, 2);
+                    curr++; /* 10 */
+                }
+                while (curr > len[t][i]) {
+                    bsW(2, 3);
+                    curr--; /* 11 */
+                }
+                bsW (1, 0);
+            }
+        }
+
+        /* And finally, the block data proper */
+        nBytes = bytesOut;
+        selCtr = 0;
+        gs = 0;
+        while (true) {
+            if (gs >= nMTF) {
+                break;
+            }
+            ge = gs + G_SIZE - 1;
+            if (ge >= nMTF) {
+                ge = nMTF - 1;
+            }
+            for (i = gs; i <= ge; i++) {
+                bsW(len[selector[selCtr]][szptr[i]],
+                    code[selector[selCtr]][szptr[i]]);
+            }
+
+            gs = ge + 1;
+            selCtr++;
+        }
+        if (!(selCtr == nSelectors)) {
+            panic();
+        }
+    }
+
+    private void moveToFrontCodeAndSend () throws IOException {
+        bsPutIntVS(24, origPtr);
+        generateMTFValues();
+        sendMTFValues();
+    }
+
+    private OutputStream bsStream;
+
+    private void simpleSort(int lo, int hi, int d) {
+        int i, j, h, bigN, hp;
+        int v;
+
+        bigN = hi - lo + 1;
+        if (bigN < 2) {
+            return;
+        }
+
+        hp = 0;
+        while (incs[hp] < bigN) {
+            hp++;
+        }
+        hp--;
+
+        for (; hp >= 0; hp--) {
+            h = incs[hp];
+
+            i = lo + h;
+            while (true) {
+                /* copy 1 */
+                if (i > hi) {
+                    break;
+                }
+                v = zptr[i];
+                j = i;
+                while (fullGtU(zptr[j - h] + d, v + d)) {
+                    zptr[j] = zptr[j - h];
+                    j = j - h;
+                    if (j <= (lo + h - 1)) {
+                        break;
+                    }
+                }
+                zptr[j] = v;
+                i++;
+
+                /* copy 2 */
+                if (i > hi) {
+                    break;
+                }
+                v = zptr[i];
+                j = i;
+                while (fullGtU(zptr[j - h] + d, v + d)) {
+                    zptr[j] = zptr[j - h];
+                    j = j - h;
+                    if (j <= (lo + h - 1)) {
+                        break;
+                    }
+                }
+                zptr[j] = v;
+                i++;
+
+                /* copy 3 */
+                if (i > hi) {
+                    break;
+                }
+                v = zptr[i];
+                j = i;
+                while (fullGtU(zptr[j - h] + d, v + d)) {
+                    zptr[j] = zptr[j - h];
+                    j = j - h;
+                    if (j <= (lo + h - 1)) {
+                        break;
+                    }
+                }
+                zptr[j] = v;
+                i++;
+
+                if (workDone > workLimit && firstAttempt) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private void vswap(int p1, int p2, int n) {
+        int temp = 0;
+        while (n > 0) {
+            temp = zptr[p1];
+            zptr[p1] = zptr[p2];
+            zptr[p2] = temp;
+            p1++;
+            p2++;
+            n--;
+        }
+    }
+
+    private char med3(char a, char b, char c) {
+        char t;
+        if (a > b) {
+            t = a;
+            a = b;
+            b = t;
+        }
+        if (b > c) {
+            t = b;
+            b = c;
+            c = t;
+        }
+        if (a > b) {
+            b = a;
+        }
+        return b;
+    }
+
+    private static class StackElem {
+        int ll;
+        int hh;
+        int dd;
+    }
+
+    private void qSort3(int loSt, int hiSt, int dSt) {
+        int unLo, unHi, ltLo, gtHi, med, n, m;
+        int sp, lo, hi, d;
+        StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+        for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+            stack[count] = new StackElem();
+        }
+
+        sp = 0;
+
+        stack[sp].ll = loSt;
+        stack[sp].hh = hiSt;
+        stack[sp].dd = dSt;
+        sp++;
+
+        while (sp > 0) {
+            if (sp >= QSORT_STACK_SIZE) {
+                panic();
+            }
+
+            sp--;
+            lo = stack[sp].ll;
+            hi = stack[sp].hh;
+            d = stack[sp].dd;
+
+            if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+                simpleSort(lo, hi, d);
+                if (workDone > workLimit && firstAttempt) {
+                    return;
+                }
+                continue;
+            }
+
+            med = med3(block[zptr[lo] + d + 1],
+                       block[zptr[hi            ] + d  + 1],
+                       block[zptr[(lo + hi) >> 1] + d + 1]);
+
+            unLo = ltLo = lo;
+            unHi = gtHi = hi;
+
+            while (true) {
+                while (true) {
+                    if (unLo > unHi) {
+                        break;
+                    }
+                    n = ((int) block[zptr[unLo] + d + 1]) - med;
+                    if (n == 0) {
+                        int temp = 0;
+                        temp = zptr[unLo];
+                        zptr[unLo] = zptr[ltLo];
+                        zptr[ltLo] = temp;
+                        ltLo++;
+                        unLo++;
+                        continue;
+                    };
+                    if (n >  0) {
+                        break;
+                    }
+                    unLo++;
+                }
+                while (true) {
+                    if (unLo > unHi) {
+                        break;
+                    }
+                    n = ((int) block[zptr[unHi] + d + 1]) - med;
+                    if (n == 0) {
+                        int temp = 0;
+                        temp = zptr[unHi];
+                        zptr[unHi] = zptr[gtHi];
+                        zptr[gtHi] = temp;
+                        gtHi--;
+                        unHi--;
+                        continue;
+                    };
+                    if (n <  0) {
+                        break;
+                    }
+                    unHi--;
+                }
+                if (unLo > unHi) {
+                    break;
+                }
+                int temp = 0;
+                temp = zptr[unLo];
+                zptr[unLo] = zptr[unHi];
+                zptr[unHi] = temp;
+                unLo++;
+                unHi--;
+            }
+
+            if (gtHi < ltLo) {
+                stack[sp].ll = lo;
+                stack[sp].hh = hi;
+                stack[sp].dd = d + 1;
+                sp++;
+                continue;
+            }
+
+            n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);
+            vswap(lo, unLo - n, n);
+            m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);
+            vswap(unLo, hi - m + 1, m);
+
+            n = lo + unLo - ltLo - 1;
+            m = hi - (gtHi - unHi) + 1;
+
+            stack[sp].ll = lo;
+            stack[sp].hh = n;
+            stack[sp].dd = d;
+            sp++;
+
+            stack[sp].ll = n + 1;
+            stack[sp].hh = m - 1;
+            stack[sp].dd = d + 1;
+            sp++;
+
+            stack[sp].ll = m;
+            stack[sp].hh = hi;
+            stack[sp].dd = d;
+            sp++;
+        }
+    }
+
+    private void mainSort() {
+        int i, j, ss, sb;
+        int[] runningOrder = new int[256];
+        int[] copy = new int[256];
+        boolean[] bigDone = new boolean[256];
+        int c1, c2;
+        int numQSorted;
+
+        /*
+          In the various block-sized structures, live data runs
+          from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,
+          set up the overshoot area for block.
+        */
+
+        //   if (verbosity >= 4) fprintf ( stderr, "   sort initialise ...\n" );
+        for (i = 0; i < NUM_OVERSHOOT_BYTES; i++) {
+            block[last + i + 2] = block[(i % (last + 1)) + 1];
+        }
+        for (i = 0; i <= last + NUM_OVERSHOOT_BYTES; i++) {
+            quadrant[i] = 0;
+        }
+
+        block[0] = (char) (block[last + 1]);
+
+        if (last < 4000) {
+            /*
+              Use simpleSort(), since the full sorting mechanism
+              has quite a large constant overhead.
+            */
+            for (i = 0; i <= last; i++) {
+                zptr[i] = i;
+            }
+            firstAttempt = false;
+            workDone = workLimit = 0;
+            simpleSort(0, last, 0);
+        } else {
+            numQSorted = 0;
+            for (i = 0; i <= 255; i++) {
+                bigDone[i] = false;
+            }
+
+            for (i = 0; i <= 65536; i++) {
+                ftab[i] = 0;
+            }
+
+            c1 = block[0];
+            for (i = 0; i <= last; i++) {
+                c2 = block[i + 1];
+                ftab[(c1 << 8) + c2]++;
+                c1 = c2;
+            }
+
+            for (i = 1; i <= 65536; i++) {
+                ftab[i] += ftab[i - 1];
+            }
+
+            c1 = block[1];
+            for (i = 0; i < last; i++) {
+                c2 = block[i + 2];
+                j = (c1 << 8) + c2;
+                c1 = c2;
+                ftab[j]--;
+                zptr[ftab[j]] = i;
+            }
+
+            j = ((block[last + 1]) << 8) + (block[1]);
+            ftab[j]--;
+            zptr[ftab[j]] = last;
+
+            /*
+              Now ftab contains the first loc of every small bucket.
+              Calculate the running order, from smallest to largest
+              big bucket.
+            */
+
+            for (i = 0; i <= 255; i++) {
+                runningOrder[i] = i;
+            }
+
+            {
+                int vv;
+                int h = 1;
+                do {
+                    h = 3 * h + 1;
+                }
+                while (h <= 256);
+                do {
+                    h = h / 3;
+                    for (i = h; i <= 255; i++) {
+                        vv = runningOrder[i];
+                        j = i;
+                        while ((ftab[((runningOrder[j - h]) + 1) << 8]
+                                - ftab[(runningOrder[j - h]) << 8])
+                                > (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
+                            runningOrder[j] = runningOrder[j - h];
+                            j = j - h;
+                            if (j <= (h - 1)) {
+                                break;
+                            }
+                        }
+                        runningOrder[j] = vv;
+                    }
+                } while (h != 1);
+            }
+
+            /*
+              The main sorting loop.
+            */
+            for (i = 0; i <= 255; i++) {
+
+                /*
+                  Process big buckets, starting with the least full.
+                */
+                ss = runningOrder[i];
+
+                /*
+                  Complete the big bucket [ss] by quicksorting
+                  any unsorted small buckets [ss, j].  Hopefully
+                  previous pointer-scanning phases have already
+                  completed many of the small buckets [ss, j], so
+                  we don't have to sort them at all.
+                */
+                for (j = 0; j <= 255; j++) {
+                    sb = (ss << 8) + j;
+                    if (!((ftab[sb] & SETMASK) == SETMASK)) {
+                        int lo = ftab[sb] & CLEARMASK;
+                        int hi = (ftab[sb + 1] & CLEARMASK) - 1;
+                        if (hi > lo) {
+                            qSort3(lo, hi, 2);
+                            numQSorted += (hi - lo + 1);
+                            if (workDone > workLimit && firstAttempt) {
+                                return;
+                            }
+                        }
+                        ftab[sb] |= SETMASK;
+                    }
+                }
+
+                /*
+                  The ss big bucket is now done.  Record this fact,
+                  and update the quadrant descriptors.  Remember to
+                  update quadrants in the overshoot area too, if
+                  necessary.  The "if (i < 255)" test merely skips
+                  this updating for the last bucket processed, since
+                  updating for the last bucket is pointless.
+                */
+                bigDone[ss] = true;
+
+                if (i < 255) {
+                    int bbStart  = ftab[ss << 8] & CLEARMASK;
+                    int bbSize   = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
+                    int shifts   = 0;
+
+                    while ((bbSize >> shifts) > 65534) {
+                        shifts++;
+                    }
+
+                    for (j = 0; j < bbSize; j++) {
+                        int a2update = zptr[bbStart + j];
+                        int qVal = (j >> shifts);
+                        quadrant[a2update] = qVal;
+                        if (a2update < NUM_OVERSHOOT_BYTES) {
+                            quadrant[a2update + last + 1] = qVal;
+                        }
+                    }
+
+                    if (!(((bbSize - 1) >> shifts) <= 65535)) {
+                        panic();
+                    }
+                }
+
+                /*
+                  Now scan this big bucket so as to synthesise the
+                  sorted order for small buckets [t, ss] for all t != ss.
+                */
+                for (j = 0; j <= 255; j++) {
+                    copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+                }
+
+                for (j = ftab[ss << 8] & CLEARMASK;
+                     j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) {
+                    c1 = block[zptr[j]];
+                    if (!bigDone[c1]) {
+                        zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+                        copy[c1]++;
+                    }
+                }
+
+                for (j = 0; j <= 255; j++) {
+                    ftab[(j << 8) + ss] |= SETMASK;
+                }
+            }
+        }
+    }
+
+    private void randomiseBlock() {
+        int i;
+        int rNToGo = 0;
+        int rTPos  = 0;
+        for (i = 0; i < 256; i++) {
+            inUse[i] = false;
+        }
+
+        for (i = 0; i <= last; i++) {
+            if (rNToGo == 0) {
+                rNToGo = (char) rNums[rTPos];
+                rTPos++;
+                if (rTPos == 512) {
+                    rTPos = 0;
+                }
+            }
+            rNToGo--;
+            block[i + 1] ^= ((rNToGo == 1) ? 1 : 0);
+            // handle 16 bit signed numbers
+            block[i + 1] &= 0xFF;
+
+            inUse[block[i + 1]] = true;
+        }
+    }
+
+    private void doReversibleTransformation() {
+        int i;
+
+        workLimit = workFactor * last;
+        workDone = 0;
+        blockRandomised = false;
+        firstAttempt = true;
+
+        mainSort();
+
+        if (workDone > workLimit && firstAttempt) {
+            randomiseBlock();
+            workLimit = workDone = 0;
+            blockRandomised = true;
+            firstAttempt = false;
+            mainSort();
+        }
+
+        origPtr = -1;
+        for (i = 0; i <= last; i++) {
+            if (zptr[i] == 0) {
+                origPtr = i;
+                break;
+            }
+        };
+
+        if (origPtr == -1) {
+            panic();
+        }
+    }
+
+    private boolean fullGtU(int i1, int i2) {
+        int k;
+        char c1, c2;
+        int s1, s2;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        c1 = block[i1 + 1];
+        c2 = block[i2 + 1];
+        if (c1 != c2) {
+            return (c1 > c2);
+        }
+        i1++;
+        i2++;
+
+        k = last + 1;
+
+        do {
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            s1 = quadrant[i1];
+            s2 = quadrant[i2];
+            if (s1 != s2) {
+                return (s1 > s2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            s1 = quadrant[i1];
+            s2 = quadrant[i2];
+            if (s1 != s2) {
+                return (s1 > s2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            s1 = quadrant[i1];
+            s2 = quadrant[i2];
+            if (s1 != s2) {
+                return (s1 > s2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            s1 = quadrant[i1];
+            s2 = quadrant[i2];
+            if (s1 != s2) {
+                return (s1 > s2);
+            }
+            i1++;
+            i2++;
+
+            if (i1 > last) {
+                i1 -= last;
+                i1--;
+            };
+            if (i2 > last) {
+                i2 -= last;
+                i2--;
+            };
+
+            k -= 4;
+            workDone++;
+        } while (k >= 0);
+
+        return false;
+    }
+
+    /*
+      Knuth's increments seem to work better
+      than Incerpi-Sedgewick here.  Possibly
+      because the number of elems to sort is
+      usually small, typically <= 20.
+    */
+    private int[] incs = {1, 4, 13, 40, 121, 364, 1093, 3280,
+                           9841, 29524, 88573, 265720,
+                           797161, 2391484};
+
+    private void allocateCompressStructures () {
+        int n = baseBlockSize * blockSize100k;
+        block = new char[(n + 1 + NUM_OVERSHOOT_BYTES)];
+        quadrant = new int[(n + NUM_OVERSHOOT_BYTES)];
+        zptr = new int[n];
+        ftab = new int[65537];
+
+        if (block == null || quadrant == null || zptr == null
+            || ftab == null) {
+            //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+            //compressOutOfMemory ( totalDraw, n );
+        }
+
+        /*
+          The back end needs a place to store the MTF values
+          whilst it calculates the coding tables.  We could
+          put them in the zptr array.  However, these values
+          will fit in a short, so we overlay szptr at the
+          start of zptr, in the hope of reducing the number
+          of cache misses induced by the multiple traversals
+          of the MTF values when calculating coding tables.
+          Seems to improve compression speed by about 1%.
+        */
+        //    szptr = zptr;
+
+
+        szptr = new short[2 * n];
+    }
+
+    private void generateMTFValues() {
+        char[] yy = new char[256];
+        int  i, j;
+        char tmp;
+        char tmp2;
+        int zPend;
+        int wr;
+        int EOB;
+
+        makeMaps();
+        EOB = nInUse + 1;
+
+        for (i = 0; i <= EOB; i++) {
+            mtfFreq[i] = 0;
+        }
+
+        wr = 0;
+        zPend = 0;
+        for (i = 0; i < nInUse; i++) {
+            yy[i] = (char) i;
+        }
+
+
+        for (i = 0; i <= last; i++) {
+            char ll_i;
+
+            ll_i = unseqToSeq[block[zptr[i]]];
+
+            j = 0;
+            tmp = yy[j];
+            while (ll_i != tmp) {
+                j++;
+                tmp2 = tmp;
+                tmp = yy[j];
+                yy[j] = tmp2;
+            };
+            yy[0] = tmp;
+
+            if (j == 0) {
+                zPend++;
+            } else {
+                if (zPend > 0) {
+                    zPend--;
+                    while (true) {
+                        switch (zPend % 2) {
+                        case 0:
+                            szptr[wr] = (short) RUNA;
+                            wr++;
+                            mtfFreq[RUNA]++;
+                            break;
+                        case 1:
+                            szptr[wr] = (short) RUNB;
+                            wr++;
+                            mtfFreq[RUNB]++;
+                            break;
+                        };
+                        if (zPend < 2) {
+                            break;
+                        }
+                        zPend = (zPend - 2) / 2;
+                    };
+                    zPend = 0;
+                }
+                szptr[wr] = (short) (j + 1);
+                wr++;
+                mtfFreq[j + 1]++;
+            }
+        }
+
+        if (zPend > 0) {
+            zPend--;
+            while (true) {
+                switch (zPend % 2) {
+                case 0:
+                    szptr[wr] = (short) RUNA;
+                    wr++;
+                    mtfFreq[RUNA]++;
+                    break;
+                case 1:
+                    szptr[wr] = (short) RUNB;
+                    wr++;
+                    mtfFreq[RUNB]++;
+                    break;
+                }
+                if (zPend < 2) {
+                    break;
+                }
+                zPend = (zPend - 2) / 2;
+            }
+        }
+
+        szptr[wr] = (short) EOB;
+        wr++;
+        mtfFreq[EOB]++;
+
+        nMTF = wr;
+    }
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/bzip2/CRC.java b/trunk/src/main/org/apache/tools/bzip2/CRC.java
new file mode 100644
index 0000000..0102c8e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/bzip2/CRC.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+package org.apache.tools.bzip2;
+
+/**
+ * A simple class the hold and calculate the CRC for sanity checking
+ * of the data.
+ *
+ */
+final class CRC {
+    static final int crc32Table[] = {
+        0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
+        0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
+        0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+        0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+        0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
+        0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+        0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
+        0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
+        0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+        0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
+        0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
+        0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+        0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
+        0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+        0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+        0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
+        0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
+        0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+        0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+        0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
+        0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+        0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
+        0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
+        0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+        0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
+        0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
+        0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+        0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
+        0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+        0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+        0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
+        0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
+        0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+        0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+        0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
+        0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+        0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
+        0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
+        0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+        0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
+        0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
+        0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+        0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
+        0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+        0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+        0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
+        0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
+        0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+        0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+        0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
+        0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+        0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
+        0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
+        0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+        0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
+        0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
+        0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+        0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
+        0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+        0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+        0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
+        0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
+        0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+    };
+
+    CRC() {
+        initialiseCRC();
+    }
+
+    void initialiseCRC() {
+        globalCrc = 0xffffffff;
+    }
+
+    int getFinalCRC() {
+        return ~globalCrc;
+    }
+
+    int getGlobalCRC() {
+        return globalCrc;
+    }
+
+    void setGlobalCRC(int newCrc) {
+        globalCrc = newCrc;
+    }
+
+    void updateCRC(int inCh) {
+        int temp = (globalCrc >> 24) ^ inCh;
+        if (temp < 0) {
+            temp = 256 + temp;
+        }
+        globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
+    }
+
+    void updateCRC(int inCh, int repeat) {
+        int globalCrcShadow = this.globalCrc;
+        while (repeat-- > 0) {
+            int temp = (globalCrcShadow >> 24) ^ inCh;
+            globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0)
+                                                      ? temp
+                                                      : (temp + 256)];
+        }
+        this.globalCrc = globalCrcShadow;
+    }
+
+    int globalCrc;
+}
+
diff --git a/trunk/src/main/org/apache/tools/mail/ErrorInQuitException.java b/trunk/src/main/org/apache/tools/mail/ErrorInQuitException.java
new file mode 100644
index 0000000..2c9b85f
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/mail/ErrorInQuitException.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.mail;
+
+import java.io.IOException;
+
+/**
+ * Specialized IOException that get thrown if SMPT's QUIT command fails.
+ *
+ * <p>This seems to happen with some version of MS Exchange that
+ * doesn't respond with a 221 code immediately.  See <a
+ * href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5273">Bug
+ * report 5273</a>.</p>
+ *
+ */
+public class ErrorInQuitException extends IOException {
+
+    /**
+     * Initialise from an IOException
+     *
+     * @param e the IO Exception.
+     */
+    public ErrorInQuitException(IOException e) {
+        super(e.getMessage());
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/mail/MailMessage.java b/trunk/src/main/org/apache/tools/mail/MailMessage.java
new file mode 100644
index 0000000..ea64f36
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/mail/MailMessage.java
@@ -0,0 +1,525 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * The original version of this class was donated by Jason Hunter,
+ * who wrote the class as part of the com.oreilly.servlet
+ * package for his book "Java Servlet Programming" (O'Reilly).
+ * See http://www.servlets.com.
+ *
+ */
+
+package org.apache.tools.mail;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.BufferedOutputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.InetAddress;
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * A class to help send SMTP email.
+ * This class is an improvement on the sun.net.smtp.SmtpClient class
+ * found in the JDK.  This version has extra functionality, and can be used
+ * with JVMs that did not extend from the JDK.  It's not as robust as
+ * the JavaMail Standard Extension classes, but it's easier to use and
+ * easier to install, and has an Open Source license.
+ * <p>
+ * It can be used like this:
+ * <blockquote><pre>
+ * String mailhost = "localhost";  // or another mail host
+ * String from = "Mail Message Servlet &lt;MailMessage@server.com&gt;";
+ * String to = "to@you.com";
+ * String cc1 = "cc1@you.com";
+ * String cc2 = "cc2@you.com";
+ * String bcc = "bcc@you.com";
+ * &nbsp;
+ * MailMessage msg = new MailMessage(mailhost);
+ * msg.setPort(25);
+ * msg.from(from);
+ * msg.to(to);
+ * msg.cc(cc1);
+ * msg.cc(cc2);
+ * msg.bcc(bcc);
+ * msg.setSubject("Test subject");
+ * PrintStream out = msg.getPrintStream();
+ * &nbsp;
+ * Enumeration enum = req.getParameterNames();
+ * while (enum.hasMoreElements()) {
+ *   String name = (String)enum.nextElement();
+ *   String value = req.getParameter(name);
+ *   out.println(name + " = " + value);
+ * }
+ * &nbsp;
+ * msg.sendAndClose();
+ * </pre></blockquote>
+ * <p>
+ * Be sure to set the from address, then set the recepient
+ * addresses, then set the subject and other headers, then get the
+ * PrintStream, then write the message, and finally send and close.
+ * The class does minimal error checking internally; it counts on the mail
+ * host to complain if there's any malformatted input or out of order
+ * execution.
+ * <p>
+ * An attachment mechanism based on RFC 1521 could be implemented on top of
+ * this class.  In the meanwhile, JavaMail is the best solution for sending
+ * email with attachments.
+ * <p>
+ * Still to do:
+ * <ul>
+ * <li>Figure out how to close the connection in case of error
+ * </ul>
+ *
+ * @version 1.1, 2000/03/19, added angle brackets to address, helps some servers
+ * version 1.0, 1999/12/29
+ */
+public class MailMessage {
+
+    /** default mailhost */
+    public static final String DEFAULT_HOST = "localhost";
+
+    /** default port for SMTP: 25 */
+    public static final int DEFAULT_PORT = 25;
+
+    /** host name for the mail server */
+    private String host;
+
+    /** host port for the mail server */
+    private int port = DEFAULT_PORT;
+
+    /** sender email address */
+    private String from;
+
+    /** list of email addresses to reply to */
+    private Vector replyto;
+
+    /** list of email addresses to send to */
+    private Vector to;
+
+    /** list of email addresses to cc to */
+    private Vector cc;
+
+    /** headers to send in the mail */
+    private Vector headersKeys;
+    private Vector headersValues;
+
+    private MailPrintStream out;
+
+    private SmtpResponseReader in;
+
+    private Socket socket;
+    private static final int OK_READY = 220;
+    private static final int OK_HELO = 250;
+    private static final int OK_FROM = 250;
+    private static final int OK_RCPT_1 = 250;
+    private static final int OK_RCPT_2 = 251;
+    private static final int OK_DATA = 354;
+    private static final int OK_DOT = 250;
+    private static final int OK_QUIT = 221;
+
+  /**
+   * Constructs a new MailMessage to send an email.
+   * Use localhost as the mail server with port 25.
+   *
+   * @exception IOException if there's any problem contacting the mail server
+   */
+  public MailMessage() throws IOException {
+    this(DEFAULT_HOST, DEFAULT_PORT);
+  }
+
+  /**
+   * Constructs a new MailMessage to send an email.
+   * Use the given host as the mail server with port 25.
+   *
+   * @param host the mail server to use
+   * @exception IOException if there's any problem contacting the mail server
+   */
+  public MailMessage(String host) throws IOException {
+    this(host, DEFAULT_PORT);
+  }
+
+  /**
+   * Constructs a new MailMessage to send an email.
+   * Use the given host and port as the mail server.
+   *
+   * @param host the mail server to use
+   * @param port the port to connect to
+   * @exception IOException if there's any problem contacting the mail server
+   */
+  public MailMessage(String host, int port) throws IOException {
+    this.port = port;
+    this.host = host;
+    replyto = new Vector();
+    to = new Vector();
+    cc = new Vector();
+    headersKeys = new Vector();
+    headersValues = new Vector();
+    connect();
+    sendHelo();
+  }
+
+    /**
+     * Set the port to connect to the SMTP host.
+     * @param port the port to use for connection.
+     * @see #DEFAULT_PORT
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * Sets the from address.  Also sets the "From" header.  This method should
+     * be called only once.
+     * @param from the from address
+     * @exception IOException if there's any problem reported by the mail server
+     */
+    public void from(String from) throws IOException {
+        sendFrom(from);
+        this.from = from;
+    }
+
+    /**
+     * Sets the replyto address
+     * This method may be
+     * called multiple times.
+     * @param rto the replyto address
+     *
+     */
+    public void replyto(String rto) {
+      this.replyto.addElement(rto);
+    }
+
+  /**
+   * Sets the to address.  Also sets the "To" header.  This method may be
+   * called multiple times.
+   *
+   * @param to the to address
+   * @exception IOException if there's any problem reported by the mail server
+   */
+  public void to(String to) throws IOException {
+    sendRcpt(to);
+    this.to.addElement(to);
+  }
+
+  /**
+   * Sets the cc address.  Also sets the "Cc" header.  This method may be
+   * called multiple times.
+   *
+   * @param cc the cc address
+   * @exception IOException if there's any problem reported by the mail server
+   */
+  public void cc(String cc) throws IOException {
+    sendRcpt(cc);
+    this.cc.addElement(cc);
+  }
+
+  /**
+   * Sets the bcc address.  Does NOT set any header since it's a *blind* copy.
+   * This method may be called multiple times.
+   *
+   * @param bcc the bcc address
+   * @exception IOException if there's any problem reported by the mail server
+   */
+  public void bcc(String bcc) throws IOException {
+    sendRcpt(bcc);
+    // No need to keep track of Bcc'd addresses
+  }
+
+  /**
+   * Sets the subject of the mail message.  Actually sets the "Subject"
+   * header.
+   * @param subj the subject of the mail message
+   */
+  public void setSubject(String subj) {
+    setHeader("Subject", subj);
+  }
+
+  /**
+   * Sets the named header to the given value.  RFC 822 provides the rules for
+   * what text may constitute a header name and value.
+   * @param name name of the header
+   * @param value contents of the header
+   */
+  public void setHeader(String name, String value) {
+    // Blindly trust the user doesn't set any invalid headers
+    headersKeys.add(name);
+    headersValues.add(value);
+  }
+
+  /**
+   * Returns a PrintStream that can be used to write the body of the message.
+   * A stream is used since email bodies are byte-oriented.  A writer can
+   * be wrapped on top if necessary for internationalization.
+   * This is actually done in Message.java
+   *
+   * @return a printstream containing the data and the headers of the email
+   * @exception IOException if there's any problem reported by the mail server
+   * @see org.apache.tools.ant.taskdefs.email.Message
+   */
+  public PrintStream getPrintStream() throws IOException {
+    setFromHeader();
+    setReplyToHeader();
+    setToHeader();
+    setCcHeader();
+    setHeader("X-Mailer", "org.apache.tools.mail.MailMessage (ant.apache.org)");
+    sendData();
+    flushHeaders();
+    return out;
+  }
+
+
+  // RFC 822 s4.1: "From:" header must be sent
+  // We rely on error checking by the MTA
+  void setFromHeader() {
+    setHeader("From", from);
+  }
+
+  // RFC 822 s4.1: "Reply-To:" header is optional
+  void setReplyToHeader() {
+    if (!replyto.isEmpty()) {
+      setHeader("Reply-To", vectorToList(replyto));
+    }
+  }
+
+  void setToHeader() {
+    if (!to.isEmpty()) {
+      setHeader("To", vectorToList(to));
+    }
+  }
+
+  void setCcHeader() {
+    if (!cc.isEmpty()) {
+      setHeader("Cc", vectorToList(cc));
+    }
+  }
+
+  String vectorToList(Vector v) {
+    StringBuffer buf = new StringBuffer();
+    Enumeration e = v.elements();
+    while (e.hasMoreElements()) {
+      buf.append(e.nextElement());
+      if (e.hasMoreElements()) {
+        buf.append(", ");
+      }
+    }
+    return buf.toString();
+  }
+
+  void flushHeaders() throws IOException {
+    // RFC 822 s4.1:
+    //   "Header fields are NOT required to occur in any particular order,
+    //    except that the message body MUST occur AFTER the headers"
+    // (the same section specifies a reccommended order, which we ignore)
+   for (int i = 0; i < headersKeys.size(); i++) {
+      String name = (String) headersKeys.elementAt(i);
+      String value = (String) headersValues.elementAt(i);
+      out.println(name + ": " + value);
+    }
+    out.println();
+    out.flush();
+  }
+
+  /**
+   * Sends the message and closes the connection to the server.
+   * The MailMessage object cannot be reused.
+   *
+   * @exception IOException if there's any problem reported by the mail server
+   */
+  public void sendAndClose() throws IOException {
+      try {
+          sendDot();
+          sendQuit();
+      } finally {
+          disconnect();
+      }
+  }
+
+  // Make a limited attempt to extract a sanitized email address
+  // Prefer text in <brackets>, ignore anything in (parentheses)
+  static String sanitizeAddress(String s) {
+    int paramDepth = 0;
+    int start = 0;
+    int end = 0;
+    int len = s.length();
+
+    for (int i = 0; i < len; i++) {
+      char c = s.charAt(i);
+      if (c == '(') {
+        paramDepth++;
+        if (start == 0) {
+          end = i;  // support "address (name)"
+        }
+      } else if (c == ')') {
+        paramDepth--;
+        if (end == 0) {
+          start = i + 1;  // support "(name) address"
+        }
+      } else if (paramDepth == 0 && c == '<') {
+        start = i + 1;
+      } else if (paramDepth == 0 && c == '>') {
+        end = i;
+      }
+    }
+
+    if (end == 0) {
+      end = len;
+    }
+
+    return s.substring(start, end);
+  }
+
+  // * * * * * Raw protocol methods below here * * * * *
+
+  void connect() throws IOException {
+    socket = new Socket(host, port);
+    out = new MailPrintStream(
+          new BufferedOutputStream(
+          socket.getOutputStream()));
+    in = new SmtpResponseReader(socket.getInputStream());
+    getReady();
+  }
+
+  void getReady() throws IOException {
+    String response = in.getResponse();
+    int[] ok = {OK_READY};
+    if (!isResponseOK(response, ok)) {
+      throw new IOException(
+        "Didn't get introduction from server: " + response);
+    }
+  }
+  void sendHelo() throws IOException {
+    String local = InetAddress.getLocalHost().getHostName();
+    int[] ok = {OK_HELO};
+    send("HELO " + local, ok);
+  }
+  void sendFrom(String from) throws IOException {
+    int[] ok = {OK_FROM};
+    send("MAIL FROM: " + "<" + sanitizeAddress(from) + ">", ok);
+  }
+  void sendRcpt(String rcpt) throws IOException {
+    int[] ok = {OK_RCPT_1, OK_RCPT_2};
+    send("RCPT TO: " + "<" + sanitizeAddress(rcpt) + ">", ok);
+  }
+
+  void sendData() throws IOException {
+    int[] ok = {OK_DATA};
+    send("DATA", ok);
+  }
+
+  void sendDot() throws IOException {
+    int[] ok = {OK_DOT};
+    send("\r\n.", ok);  // make sure dot is on new line
+  }
+
+    void sendQuit() throws IOException {
+        int[] ok = {OK_QUIT};
+        try {
+            send("QUIT", ok);
+        } catch (IOException e) {
+            throw new ErrorInQuitException(e);
+        }
+    }
+
+    void send(String msg, int[] ok) throws IOException {
+        out.rawPrint(msg + "\r\n");  // raw supports <CRLF>.<CRLF>
+        String response = in.getResponse();
+        if (!isResponseOK(response, ok)) {
+            throw new IOException("Unexpected reply to command: "
+                                  + msg + ": " + response);
+        }
+    }
+
+  boolean isResponseOK(String response, int[] ok) {
+    // Check that the response is one of the valid codes
+    for (int i = 0; i < ok.length; i++) {
+      if (response.startsWith("" + ok[i])) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+    void disconnect() throws IOException {
+        if (out != null) {
+            out.close();
+        }
+        if (in != null) {
+            try {
+                in.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+        if (socket != null) {
+            try {
+                socket.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+    }
+}
+
+/**
+ * This PrintStream subclass makes sure that <CRLF>. becomes <CRLF>..
+ *  per RFC 821.  It also ensures that new lines are always \r\n.
+*/
+class MailPrintStream extends PrintStream {
+
+  private int lastChar;
+
+  public MailPrintStream(OutputStream out) {
+    super(out, true);  // deprecated, but email is byte-oriented
+  }
+
+  // Mac does \n\r, but that's tough to distinguish from Windows \r\n\r\n.
+  // Don't tackle that problem right now.
+  public void write(int b) {
+    if (b == '\n' && lastChar != '\r') {
+      rawWrite('\r');  // ensure always \r\n
+      rawWrite(b);
+    } else if (b == '.' && lastChar == '\n') {
+      rawWrite('.');  // add extra dot
+      rawWrite(b);
+    } else {
+      rawWrite(b);
+    }
+    lastChar = b;
+  }
+
+  public void write(byte[] buf, int off, int len) {
+    for (int i = 0; i < len; i++) {
+      write(buf[off + i]);
+    }
+  }
+
+  void rawWrite(int b) {
+    super.write(b);
+  }
+
+  void rawPrint(String s) {
+    int len = s.length();
+    for (int i = 0; i < len; i++) {
+      rawWrite(s.charAt(i));
+    }
+  }
+}
+
diff --git a/trunk/src/main/org/apache/tools/mail/SmtpResponseReader.java b/trunk/src/main/org/apache/tools/mail/SmtpResponseReader.java
new file mode 100644
index 0000000..8d52ec8
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/mail/SmtpResponseReader.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.mail;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * A wrapper around the raw input from the SMTP server that assembles
+ * multi line responses into a single String.
+ *
+ * <p>The same rules used here would apply to FTP and other Telnet
+ * based protocols as well.</p>
+ *
+ */
+public class SmtpResponseReader {
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected BufferedReader reader = null;
+    // CheckStyle:VisibilityModifier ON
+    private StringBuffer result = new StringBuffer();
+
+    /**
+     * Wrap this input stream.
+     * @param in the stream to wrap.
+     */
+    public SmtpResponseReader(InputStream in) {
+        reader = new BufferedReader(new InputStreamReader(in));
+    }
+
+    /**
+     * Read until the server indicates that the response is complete.
+     *
+     * @return Responsecode (3 digits) + Blank + Text from all
+     *         response line concatenated (with blanks replacing the \r\n
+     *         sequences).
+     * @throws IOException on error.
+     */
+    public String getResponse() throws IOException {
+        result.setLength(0);
+        String line = reader.readLine();
+        // CheckStyle:MagicNumber OFF
+        if (line != null && line.length() >= 3) {
+            result.append(line.substring(0, 3));
+            result.append(" ");
+        }
+        // CheckStyle:MagicNumber ON
+
+        while (line != null) {
+            append(line);
+            if (!hasMoreLines(line)) {
+                break;
+            }
+            line = reader.readLine();
+        }
+        return result.toString().trim();
+    }
+
+    /**
+     * Closes the underlying stream.
+     * @throws IOException on error.
+     */
+    public void close() throws IOException {
+        reader.close();
+    }
+
+    /**
+     * Should we expect more input?
+     * @param line the line to check.
+     * @return true if there are more lines to check.
+     */
+    protected boolean hasMoreLines(String line) {
+        // CheckStyle:MagicNumber OFF
+        return line.length() > 3 && line.charAt(3) == '-';
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Append the text from this line of the resonse.
+     */
+    private void append(String line) {
+        // CheckStyle:MagicNumber OFF
+        if (line.length() > 4) {
+            result.append(line.substring(4));
+            result.append(" ");
+        }
+        // CheckStyle:MagicNumber ON
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/tar/TarBuffer.java b/trunk/src/main/org/apache/tools/tar/TarBuffer.java
new file mode 100644
index 0000000..528bc33
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarBuffer.java
@@ -0,0 +1,461 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * The TarBuffer class implements the tar archive concept
+ * of a buffered input stream. This concept goes back to the
+ * days of blocked tape drives and special io devices. In the
+ * Java universe, the only real function that this class
+ * performs is to ensure that files have the correct "block"
+ * size, or other tars will complain.
+ * <p>
+ * You should never have a need to access this class directly.
+ * TarBuffers are created by Tar IO Streams.
+ *
+ */
+
+public class TarBuffer {
+
+    /** Default record size */
+    public static final int DEFAULT_RCDSIZE = (512);
+
+    /** Default block size */
+    public static final int DEFAULT_BLKSIZE = (DEFAULT_RCDSIZE * 20);
+
+    private InputStream     inStream;
+    private OutputStream    outStream;
+    private byte[]          blockBuffer;
+    private int             currBlkIdx;
+    private int             currRecIdx;
+    private int             blockSize;
+    private int             recordSize;
+    private int             recsPerBlock;
+    private boolean         debug;
+
+    /**
+     * Constructor for a TarBuffer on an input stream.
+     * @param inStream the input stream to use
+     */
+    public TarBuffer(InputStream inStream) {
+        this(inStream, TarBuffer.DEFAULT_BLKSIZE);
+    }
+
+    /**
+     * Constructor for a TarBuffer on an input stream.
+     * @param inStream the input stream to use
+     * @param blockSize the block size to use
+     */
+    public TarBuffer(InputStream inStream, int blockSize) {
+        this(inStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for a TarBuffer on an input stream.
+     * @param inStream the input stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarBuffer(InputStream inStream, int blockSize, int recordSize) {
+        this.inStream = inStream;
+        this.outStream = null;
+
+        this.initialize(blockSize, recordSize);
+    }
+
+    /**
+     * Constructor for a TarBuffer on an output stream.
+     * @param outStream the output stream to use
+     */
+    public TarBuffer(OutputStream outStream) {
+        this(outStream, TarBuffer.DEFAULT_BLKSIZE);
+    }
+
+    /**
+     * Constructor for a TarBuffer on an output stream.
+     * @param outStream the output stream to use
+     * @param blockSize the block size to use
+     */
+    public TarBuffer(OutputStream outStream, int blockSize) {
+        this(outStream, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for a TarBuffer on an output stream.
+     * @param outStream the output stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarBuffer(OutputStream outStream, int blockSize, int recordSize) {
+        this.inStream = null;
+        this.outStream = outStream;
+
+        this.initialize(blockSize, recordSize);
+    }
+
+    /**
+     * Initialization common to all constructors.
+     */
+    private void initialize(int blockSize, int recordSize) {
+        this.debug = false;
+        this.blockSize = blockSize;
+        this.recordSize = recordSize;
+        this.recsPerBlock = (this.blockSize / this.recordSize);
+        this.blockBuffer = new byte[this.blockSize];
+
+        if (this.inStream != null) {
+            this.currBlkIdx = -1;
+            this.currRecIdx = this.recsPerBlock;
+        } else {
+            this.currBlkIdx = 0;
+            this.currRecIdx = 0;
+        }
+    }
+
+    /**
+     * Get the TAR Buffer's block size. Blocks consist of multiple records.
+     * @return the block size
+     */
+    public int getBlockSize() {
+        return this.blockSize;
+    }
+
+    /**
+     * Get the TAR Buffer's record size.
+     * @return the record size
+     */
+    public int getRecordSize() {
+        return this.recordSize;
+    }
+
+    /**
+     * Set the debugging flag for the buffer.
+     *
+     * @param debug If true, print debugging output.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Determine if an archive record indicate End of Archive. End of
+     * archive is indicated by a record that consists entirely of null bytes.
+     *
+     * @param record The record data to check.
+     * @return true if the record data is an End of Archive
+     */
+    public boolean isEOFRecord(byte[] record) {
+        for (int i = 0, sz = getRecordSize(); i < sz; ++i) {
+            if (record[i] != 0) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Skip over a record on the input stream.
+     * @throws IOException on error
+     */
+    public void skipRecord() throws IOException {
+        if (debug) {
+            System.err.println("SkipRecord: recIdx = " + currRecIdx
+                               + " blkIdx = " + currBlkIdx);
+        }
+
+        if (inStream == null) {
+            throw new IOException("reading (via skip) from an output buffer");
+        }
+
+        if (currRecIdx >= recsPerBlock) {
+            if (!readBlock()) {
+                return;    // UNDONE
+            }
+        }
+
+        currRecIdx++;
+    }
+
+    /**
+     * Read a record from the input stream and return the data.
+     *
+     * @return The record data.
+     * @throws IOException on error
+     */
+    public byte[] readRecord() throws IOException {
+        if (debug) {
+            System.err.println("ReadRecord: recIdx = " + currRecIdx
+                               + " blkIdx = " + currBlkIdx);
+        }
+
+        if (inStream == null) {
+            throw new IOException("reading from an output buffer");
+        }
+
+        if (currRecIdx >= recsPerBlock) {
+            if (!readBlock()) {
+                return null;
+            }
+        }
+
+        byte[] result = new byte[recordSize];
+
+        System.arraycopy(blockBuffer,
+                         (currRecIdx * recordSize), result, 0,
+                         recordSize);
+
+        currRecIdx++;
+
+        return result;
+    }
+
+    /**
+     * @return false if End-Of-File, else true
+     */
+    private boolean readBlock() throws IOException {
+        if (debug) {
+            System.err.println("ReadBlock: blkIdx = " + currBlkIdx);
+        }
+
+        if (inStream == null) {
+            throw new IOException("reading from an output buffer");
+        }
+
+        currRecIdx = 0;
+
+        int offset = 0;
+        int bytesNeeded = blockSize;
+
+        while (bytesNeeded > 0) {
+            long numBytes = inStream.read(blockBuffer, offset,
+                                               bytesNeeded);
+
+            //
+            // NOTE
+            // We have fit EOF, and the block is not full!
+            //
+            // This is a broken archive. It does not follow the standard
+            // blocking algorithm. However, because we are generous, and
+            // it requires little effort, we will simply ignore the error
+            // and continue as if the entire block were read. This does
+            // not appear to break anything upstream. We used to return
+            // false in this case.
+            //
+            // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
+            //
+            if (numBytes == -1) {
+                if (offset == 0) {
+                    // Ensure that we do not read gigabytes of zeros
+                    // for a corrupt tar file.
+                    // See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924
+                    return false;
+                }
+                // However, just leaving the unread portion of the buffer dirty does
+                // cause problems in some cases.  This problem is described in
+                // http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
+                //
+                // The solution is to fill the unused portion of the buffer with zeros.
+
+                Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0);
+
+                break;
+            }
+
+            offset += numBytes;
+            bytesNeeded -= numBytes;
+
+            if (numBytes != blockSize) {
+                if (debug) {
+                    System.err.println("ReadBlock: INCOMPLETE READ "
+                                       + numBytes + " of " + blockSize
+                                       + " bytes read.");
+                }
+            }
+        }
+
+        currBlkIdx++;
+
+        return true;
+    }
+
+    /**
+     * Get the current block number, zero based.
+     *
+     * @return The current zero based block number.
+     */
+    public int getCurrentBlockNum() {
+        return currBlkIdx;
+    }
+
+    /**
+     * Get the current record number, within the current block, zero based.
+     * Thus, current offset = (currentBlockNum * recsPerBlk) + currentRecNum.
+     *
+     * @return The current zero based record number.
+     */
+    public int getCurrentRecordNum() {
+        return currRecIdx - 1;
+    }
+
+    /**
+     * Write an archive record to the archive.
+     *
+     * @param record The record data to write to the archive.
+     * @throws IOException on error
+     */
+    public void writeRecord(byte[] record) throws IOException {
+        if (debug) {
+            System.err.println("WriteRecord: recIdx = " + currRecIdx
+                               + " blkIdx = " + currBlkIdx);
+        }
+
+        if (outStream == null) {
+            throw new IOException("writing to an input buffer");
+        }
+
+        if (record.length != recordSize) {
+            throw new IOException("record to write has length '"
+                                  + record.length
+                                  + "' which is not the record size of '"
+                                  + recordSize + "'");
+        }
+
+        if (currRecIdx >= recsPerBlock) {
+            writeBlock();
+        }
+
+        System.arraycopy(record, 0, blockBuffer,
+                         (currRecIdx * recordSize),
+                         recordSize);
+
+        currRecIdx++;
+    }
+
+    /**
+     * Write an archive record to the archive, where the record may be
+     * inside of a larger array buffer. The buffer must be "offset plus
+     * record size" long.
+     *
+     * @param buf The buffer containing the record data to write.
+     * @param offset The offset of the record data within buf.
+     * @throws IOException on error
+     */
+    public void writeRecord(byte[] buf, int offset) throws IOException {
+        if (debug) {
+            System.err.println("WriteRecord: recIdx = " + currRecIdx
+                               + " blkIdx = " + currBlkIdx);
+        }
+
+        if (outStream == null) {
+            throw new IOException("writing to an input buffer");
+        }
+
+        if ((offset + recordSize) > buf.length) {
+            throw new IOException("record has length '" + buf.length
+                                  + "' with offset '" + offset
+                                  + "' which is less than the record size of '"
+                                  + recordSize + "'");
+        }
+
+        if (currRecIdx >= recsPerBlock) {
+            writeBlock();
+        }
+
+        System.arraycopy(buf, offset, blockBuffer,
+                         (currRecIdx * recordSize),
+                         recordSize);
+
+        currRecIdx++;
+    }
+
+    /**
+     * Write a TarBuffer block to the archive.
+     */
+    private void writeBlock() throws IOException {
+        if (debug) {
+            System.err.println("WriteBlock: blkIdx = " + currBlkIdx);
+        }
+
+        if (outStream == null) {
+            throw new IOException("writing to an input buffer");
+        }
+
+        outStream.write(blockBuffer, 0, blockSize);
+        outStream.flush();
+
+        currRecIdx = 0;
+        currBlkIdx++;
+    }
+
+    /**
+     * Flush the current data block if it has any data in it.
+     */
+    private void flushBlock() throws IOException {
+        if (debug) {
+            System.err.println("TarBuffer.flushBlock() called.");
+        }
+
+        if (outStream == null) {
+            throw new IOException("writing to an input buffer");
+        }
+
+        if (currRecIdx > 0) {
+            writeBlock();
+        }
+    }
+
+    /**
+     * Close the TarBuffer. If this is an output buffer, also flush the
+     * current block before closing.
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        if (debug) {
+            System.err.println("TarBuffer.closeBuffer().");
+        }
+
+        if (outStream != null) {
+            flushBlock();
+
+            if (outStream != System.out
+                    && outStream != System.err) {
+                outStream.close();
+
+                outStream = null;
+            }
+        } else if (inStream != null) {
+            if (inStream != System.in) {
+                inStream.close();
+
+                inStream = null;
+            }
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/tar/TarConstants.java b/trunk/src/main/org/apache/tools/tar/TarConstants.java
new file mode 100644
index 0000000..2ba5d66
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarConstants.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+/**
+ * This interface contains all the definitions used in the package.
+ *
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF (bc)
+public interface TarConstants {
+
+    /**
+     * The length of the name field in a header buffer.
+     */
+    int    NAMELEN = 100;
+
+    /**
+     * The length of the mode field in a header buffer.
+     */
+    int    MODELEN = 8;
+
+    /**
+     * The length of the user id field in a header buffer.
+     */
+    int    UIDLEN = 8;
+
+    /**
+     * The length of the group id field in a header buffer.
+     */
+    int    GIDLEN = 8;
+
+    /**
+     * The length of the checksum field in a header buffer.
+     */
+    int    CHKSUMLEN = 8;
+
+    /**
+     * The length of the size field in a header buffer.
+     */
+    int    SIZELEN = 12;
+
+    /**
+     * The maximum size of a file in a tar archive (That's 11 sevens, octal).
+     */
+    long   MAXSIZE = 077777777777L;
+
+    /**
+     * The length of the magic field in a header buffer.
+     */
+    int    MAGICLEN = 8;
+
+    /**
+     * The length of the modification time field in a header buffer.
+     */
+    int    MODTIMELEN = 12;
+
+    /**
+     * The length of the user name field in a header buffer.
+     */
+    int    UNAMELEN = 32;
+
+    /**
+     * The length of the group name field in a header buffer.
+     */
+    int    GNAMELEN = 32;
+
+    /**
+     * The length of the devices field in a header buffer.
+     */
+    int    DEVLEN = 8;
+
+    /**
+     * LF_ constants represent the "link flag" of an entry, or more commonly,
+     * the "entry type". This is the "old way" of indicating a normal file.
+     */
+    byte   LF_OLDNORM = 0;
+
+    /**
+     * Normal file type.
+     */
+    byte   LF_NORMAL = (byte) '0';
+
+    /**
+     * Link file type.
+     */
+    byte   LF_LINK = (byte) '1';
+
+    /**
+     * Symbolic link file type.
+     */
+    byte   LF_SYMLINK = (byte) '2';
+
+    /**
+     * Character device file type.
+     */
+    byte   LF_CHR = (byte) '3';
+
+    /**
+     * Block device file type.
+     */
+    byte   LF_BLK = (byte) '4';
+
+    /**
+     * Directory file type.
+     */
+    byte   LF_DIR = (byte) '5';
+
+    /**
+     * FIFO (pipe) file type.
+     */
+    byte   LF_FIFO = (byte) '6';
+
+    /**
+     * Contiguous file type.
+     */
+    byte   LF_CONTIG = (byte) '7';
+
+    /**
+     * The magic tag representing a POSIX tar archive.
+     */
+    String TMAGIC = "ustar";
+
+    /**
+     * The magic tag representing a GNU tar archive.
+     */
+    String GNU_TMAGIC = "ustar  ";
+
+    /**
+     * The namr of the GNU tar entry which contains a long name.
+     */
+    String GNU_LONGLINK = "././@LongLink";
+
+    /**
+     * Identifies the *next* file on the tape as having a long name.
+     */
+    byte LF_GNUTYPE_LONGNAME = (byte) 'L';
+}
diff --git a/trunk/src/main/org/apache/tools/tar/TarEntry.java b/trunk/src/main/org/apache/tools/tar/TarEntry.java
new file mode 100644
index 0000000..4fb5b66
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarEntry.java
@@ -0,0 +1,638 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+import java.io.File;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * This class represents an entry in a Tar archive. It consists
+ * of the entry's header, as well as the entry's File. Entries
+ * can be instantiated in one of three ways, depending on how
+ * they are to be used.
+ * <p>
+ * TarEntries that are created from the header bytes read from
+ * an archive are instantiated with the TarEntry( byte[] )
+ * constructor. These entries will be used when extracting from
+ * or listing the contents of an archive. These entries have their
+ * header filled in using the header bytes. They also set the File
+ * to null, since they reference an archive entry not a file.
+ * <p>
+ * TarEntries that are created from Files that are to be written
+ * into an archive are instantiated with the TarEntry( File )
+ * constructor. These entries have their header filled in using
+ * the File's information. They also keep a reference to the File
+ * for convenience when writing entries.
+ * <p>
+ * Finally, TarEntries can be constructed from nothing but a name.
+ * This allows the programmer to construct the entry by hand, for
+ * instance when only an InputStream is available for writing to
+ * the archive, and the header information is constructed from
+ * other information. In this case the header fields are set to
+ * defaults and the File is set to null.
+ *
+ * <p>
+ * The C structure for a Tar Entry's header is:
+ * <pre>
+ * struct header {
+ * char name[NAMSIZ];
+ * char mode[8];
+ * char uid[8];
+ * char gid[8];
+ * char size[12];
+ * char mtime[12];
+ * char chksum[8];
+ * char linkflag;
+ * char linkname[NAMSIZ];
+ * char magic[8];
+ * char uname[TUNMLEN];
+ * char gname[TGNMLEN];
+ * char devmajor[8];
+ * char devminor[8];
+ * } header;
+ * </pre>
+ *
+ */
+
+public class TarEntry implements TarConstants {
+    /** The entry's name. */
+    private StringBuffer name;
+
+    /** The entry's permission mode. */
+    private int mode;
+
+    /** The entry's user id. */
+    private int userId;
+
+    /** The entry's group id. */
+    private int groupId;
+
+    /** The entry's size. */
+    private long size;
+
+    /** The entry's modification time. */
+    private long modTime;
+
+    /** The entry's link flag. */
+    private byte linkFlag;
+
+    /** The entry's link name. */
+    private StringBuffer linkName;
+
+    /** The entry's magic tag. */
+    private StringBuffer magic;
+
+    /** The entry's user name. */
+    private StringBuffer userName;
+
+    /** The entry's group name. */
+    private StringBuffer groupName;
+
+    /** The entry's major device number. */
+    private int devMajor;
+
+    /** The entry's minor device number. */
+    private int devMinor;
+
+    /** The entry's file reference */
+    private File file;
+
+    /** Maximum length of a user's name in the tar file */
+    public static final int MAX_NAMELEN = 31;
+
+    /** Default permissions bits for directories */
+    public static final int DEFAULT_DIR_MODE = 040755;
+
+    /** Default permissions bits for files */
+    public static final int DEFAULT_FILE_MODE = 0100644;
+
+    /** Convert millis to seconds */
+    public static final int MILLIS_PER_SECOND = 1000;
+
+    /**
+     * Construct an empty entry and prepares the header values.
+     */
+    private TarEntry () {
+        this.magic = new StringBuffer(TMAGIC);
+        this.name = new StringBuffer();
+        this.linkName = new StringBuffer();
+
+        String user = System.getProperty("user.name", "");
+
+        if (user.length() > MAX_NAMELEN) {
+            user = user.substring(0, MAX_NAMELEN);
+        }
+
+        this.userId = 0;
+        this.groupId = 0;
+        this.userName = new StringBuffer(user);
+        this.groupName = new StringBuffer("");
+        this.file = null;
+    }
+
+    /**
+     * Construct an entry with only a name. This allows the programmer
+     * to construct the entry's header "by hand". File is set to null.
+     *
+     * @param name the entry name
+     */
+    public TarEntry(String name) {
+        this();
+
+        boolean isDir = name.endsWith("/");
+
+        this.devMajor = 0;
+        this.devMinor = 0;
+        this.name = new StringBuffer(name);
+        this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;
+        this.linkFlag = isDir ? LF_DIR : LF_NORMAL;
+        this.userId = 0;
+        this.groupId = 0;
+        this.size = 0;
+        this.modTime = (new Date()).getTime() / MILLIS_PER_SECOND;
+        this.linkName = new StringBuffer("");
+        this.userName = new StringBuffer("");
+        this.groupName = new StringBuffer("");
+        this.devMajor = 0;
+        this.devMinor = 0;
+
+    }
+
+    /**
+     * Construct an entry with a name and a link flag.
+     *
+     * @param name the entry name
+     * @param linkFlag the entry link flag.
+     */
+    public TarEntry(String name, byte linkFlag) {
+        this(name);
+        this.linkFlag = linkFlag;
+    }
+
+    /**
+     * Construct an entry for a file. File is set to file, and the
+     * header is constructed from information from the file.
+     *
+     * @param file The file that the entry represents.
+     */
+    public TarEntry(File file) {
+        this();
+
+        this.file = file;
+
+        String fileName = file.getPath();
+        String osname = System.getProperty("os.name").toLowerCase(Locale.US);
+
+        if (osname != null) {
+
+            // Strip off drive letters!
+            // REVIEW Would a better check be "(File.separator == '\')"?
+
+            if (osname.startsWith("windows")) {
+                if (fileName.length() > 2) {
+                    char ch1 = fileName.charAt(0);
+                    char ch2 = fileName.charAt(1);
+
+                    if (ch2 == ':'
+                            && ((ch1 >= 'a' && ch1 <= 'z')
+                                || (ch1 >= 'A' && ch1 <= 'Z'))) {
+                        fileName = fileName.substring(2);
+                    }
+                }
+            } else if (osname.indexOf("netware") > -1) {
+                int colon = fileName.indexOf(':');
+                if (colon != -1) {
+                    fileName = fileName.substring(colon + 1);
+                }
+            }
+        }
+
+        fileName = fileName.replace(File.separatorChar, '/');
+
+        // No absolute pathnames
+        // Windows (and Posix?) paths can start with "\\NetworkDrive\",
+        // so we loop on starting /'s.
+        while (fileName.startsWith("/")) {
+            fileName = fileName.substring(1);
+        }
+
+        this.linkName = new StringBuffer("");
+        this.name = new StringBuffer(fileName);
+
+        if (file.isDirectory()) {
+            this.mode = DEFAULT_DIR_MODE;
+            this.linkFlag = LF_DIR;
+
+            if (this.name.charAt(this.name.length() - 1) != '/') {
+                this.name.append("/");
+            }
+        } else {
+            this.mode = DEFAULT_FILE_MODE;
+            this.linkFlag = LF_NORMAL;
+        }
+
+        this.size = file.length();
+        this.modTime = file.lastModified() / MILLIS_PER_SECOND;
+        this.devMajor = 0;
+        this.devMinor = 0;
+    }
+
+    /**
+     * Construct an entry from an archive's header bytes. File is set
+     * to null.
+     *
+     * @param headerBuf The header bytes from a tar archive entry.
+     */
+    public TarEntry(byte[] headerBuf) {
+        this();
+        parseTarHeader(headerBuf);
+    }
+
+    /**
+     * Determine if the two entries are equal. Equality is determined
+     * by the header names being equal.
+     *
+     * @param it Entry to be checked for equality.
+     * @return True if the entries are equal.
+     */
+    public boolean equals(TarEntry it) {
+        return getName().equals(it.getName());
+    }
+
+    /**
+     * Determine if the two entries are equal. Equality is determined
+     * by the header names being equal.
+     *
+     * @param it Entry to be checked for equality.
+     * @return True if the entries are equal.
+     */
+    public boolean equals(Object it) {
+        if (it == null || getClass() != it.getClass()) {
+            return false;
+        }
+        return equals((TarEntry) it);
+    }
+
+    /**
+     * Hashcodes are based on entry names.
+     *
+     * @return the entry hashcode
+     */
+    public int hashCode() {
+        return getName().hashCode();
+    }
+
+    /**
+     * Determine if the given entry is a descendant of this entry.
+     * Descendancy is determined by the name of the descendant
+     * starting with this entry's name.
+     *
+     * @param desc Entry to be checked as a descendent of this.
+     * @return True if entry is a descendant of this.
+     */
+    public boolean isDescendent(TarEntry desc) {
+        return desc.getName().startsWith(getName());
+    }
+
+    /**
+     * Get this entry's name.
+     *
+     * @return This entry's name.
+     */
+    public String getName() {
+        return name.toString();
+    }
+
+    /**
+     * Set this entry's name.
+     *
+     * @param name This entry's new name.
+     */
+    public void setName(String name) {
+        this.name = new StringBuffer(name);
+    }
+
+    /**
+     * Set the mode for this entry
+     *
+     * @param mode the mode for this entry
+     */
+    public void setMode(int mode) {
+        this.mode = mode;
+    }
+
+    /**
+     * Get this entry's link name.
+     *
+     * @return This entry's link name.
+     */
+    public String getLinkName() {
+        return linkName.toString();
+    }
+
+    /**
+     * Get this entry's user id.
+     *
+     * @return This entry's user id.
+     */
+    public int getUserId() {
+        return userId;
+    }
+
+    /**
+     * Set this entry's user id.
+     *
+     * @param userId This entry's new user id.
+     */
+    public void setUserId(int userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * Get this entry's group id.
+     *
+     * @return This entry's group id.
+     */
+    public int getGroupId() {
+        return groupId;
+    }
+
+    /**
+     * Set this entry's group id.
+     *
+     * @param groupId This entry's new group id.
+     */
+    public void setGroupId(int groupId) {
+        this.groupId = groupId;
+    }
+
+    /**
+     * Get this entry's user name.
+     *
+     * @return This entry's user name.
+     */
+    public String getUserName() {
+        return userName.toString();
+    }
+
+    /**
+     * Set this entry's user name.
+     *
+     * @param userName This entry's new user name.
+     */
+    public void setUserName(String userName) {
+        this.userName = new StringBuffer(userName);
+    }
+
+    /**
+     * Get this entry's group name.
+     *
+     * @return This entry's group name.
+     */
+    public String getGroupName() {
+        return groupName.toString();
+    }
+
+    /**
+     * Set this entry's group name.
+     *
+     * @param groupName This entry's new group name.
+     */
+    public void setGroupName(String groupName) {
+        this.groupName = new StringBuffer(groupName);
+    }
+
+    /**
+     * Convenience method to set this entry's group and user ids.
+     *
+     * @param userId This entry's new user id.
+     * @param groupId This entry's new group id.
+     */
+    public void setIds(int userId, int groupId) {
+        setUserId(userId);
+        setGroupId(groupId);
+    }
+
+    /**
+     * Convenience method to set this entry's group and user names.
+     *
+     * @param userName This entry's new user name.
+     * @param groupName This entry's new group name.
+     */
+    public void setNames(String userName, String groupName) {
+        setUserName(userName);
+        setGroupName(groupName);
+    }
+
+    /**
+     * Set this entry's modification time. The parameter passed
+     * to this method is in "Java time".
+     *
+     * @param time This entry's new modification time.
+     */
+    public void setModTime(long time) {
+        modTime = time / MILLIS_PER_SECOND;
+    }
+
+    /**
+     * Set this entry's modification time.
+     *
+     * @param time This entry's new modification time.
+     */
+    public void setModTime(Date time) {
+        modTime = time.getTime() / MILLIS_PER_SECOND;
+    }
+
+    /**
+     * Set this entry's modification time.
+     *
+     * @return time This entry's new modification time.
+     */
+    public Date getModTime() {
+        return new Date(modTime * MILLIS_PER_SECOND);
+    }
+
+    /**
+     * Get this entry's file.
+     *
+     * @return This entry's file.
+     */
+    public File getFile() {
+        return file;
+    }
+
+    /**
+     * Get this entry's mode.
+     *
+     * @return This entry's mode.
+     */
+    public int getMode() {
+        return mode;
+    }
+
+    /**
+     * Get this entry's file size.
+     *
+     * @return This entry's file size.
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Set this entry's file size.
+     *
+     * @param size This entry's new file size.
+     */
+    public void setSize(long size) {
+        this.size = size;
+    }
+
+
+    /**
+     * Indicate if this entry is a GNU long name block
+     *
+     * @return true if this is a long name extension provided by GNU tar
+     */
+    public boolean isGNULongNameEntry() {
+        return linkFlag == LF_GNUTYPE_LONGNAME
+                           && name.toString().equals(GNU_LONGLINK);
+    }
+
+    /**
+     * Return whether or not this entry represents a directory.
+     *
+     * @return True if this entry is a directory.
+     */
+    public boolean isDirectory() {
+        if (file != null) {
+            return file.isDirectory();
+        }
+
+        if (linkFlag == LF_DIR) {
+            return true;
+        }
+
+        if (getName().endsWith("/")) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * If this entry represents a file, and the file is a directory, return
+     * an array of TarEntries for this entry's children.
+     *
+     * @return An array of TarEntry's for this entry's children.
+     */
+    public TarEntry[] getDirectoryEntries() {
+        if (file == null || !file.isDirectory()) {
+            return new TarEntry[0];
+        }
+
+        String[]   list = file.list();
+        TarEntry[] result = new TarEntry[list.length];
+
+        for (int i = 0; i < list.length; ++i) {
+            result[i] = new TarEntry(new File(file, list[i]));
+        }
+
+        return result;
+    }
+
+    /**
+     * Write an entry's header information to a header buffer.
+     *
+     * @param outbuf The tar entry header buffer to fill in.
+     */
+    public void writeEntryHeader(byte[] outbuf) {
+        int offset = 0;
+
+        offset = TarUtils.getNameBytes(name, outbuf, offset, NAMELEN);
+        offset = TarUtils.getOctalBytes(mode, outbuf, offset, MODELEN);
+        offset = TarUtils.getOctalBytes(userId, outbuf, offset, UIDLEN);
+        offset = TarUtils.getOctalBytes(groupId, outbuf, offset, GIDLEN);
+        offset = TarUtils.getLongOctalBytes(size, outbuf, offset, SIZELEN);
+        offset = TarUtils.getLongOctalBytes(modTime, outbuf, offset, MODTIMELEN);
+
+        int csOffset = offset;
+
+        for (int c = 0; c < CHKSUMLEN; ++c) {
+            outbuf[offset++] = (byte) ' ';
+        }
+
+        outbuf[offset++] = linkFlag;
+        offset = TarUtils.getNameBytes(linkName, outbuf, offset, NAMELEN);
+        offset = TarUtils.getNameBytes(magic, outbuf, offset, MAGICLEN);
+        offset = TarUtils.getNameBytes(userName, outbuf, offset, UNAMELEN);
+        offset = TarUtils.getNameBytes(groupName, outbuf, offset, GNAMELEN);
+        offset = TarUtils.getOctalBytes(devMajor, outbuf, offset, DEVLEN);
+        offset = TarUtils.getOctalBytes(devMinor, outbuf, offset, DEVLEN);
+
+        while (offset < outbuf.length) {
+            outbuf[offset++] = 0;
+        }
+
+        long chk = TarUtils.computeCheckSum(outbuf);
+
+        TarUtils.getCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);
+    }
+
+    /**
+     * Parse an entry's header information from a header buffer.
+     *
+     * @param header The tar entry header buffer to get information from.
+     */
+    public void parseTarHeader(byte[] header) {
+        int offset = 0;
+
+        name = TarUtils.parseName(header, offset, NAMELEN);
+        offset += NAMELEN;
+        mode = (int) TarUtils.parseOctal(header, offset, MODELEN);
+        offset += MODELEN;
+        userId = (int) TarUtils.parseOctal(header, offset, UIDLEN);
+        offset += UIDLEN;
+        groupId = (int) TarUtils.parseOctal(header, offset, GIDLEN);
+        offset += GIDLEN;
+        size = TarUtils.parseOctal(header, offset, SIZELEN);
+        offset += SIZELEN;
+        modTime = TarUtils.parseOctal(header, offset, MODTIMELEN);
+        offset += MODTIMELEN;
+        offset += CHKSUMLEN;
+        linkFlag = header[offset++];
+        linkName = TarUtils.parseName(header, offset, NAMELEN);
+        offset += NAMELEN;
+        magic = TarUtils.parseName(header, offset, MAGICLEN);
+        offset += MAGICLEN;
+        userName = TarUtils.parseName(header, offset, UNAMELEN);
+        offset += UNAMELEN;
+        groupName = TarUtils.parseName(header, offset, GNAMELEN);
+        offset += GNAMELEN;
+        devMajor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
+        offset += DEVLEN;
+        devMinor = (int) TarUtils.parseOctal(header, offset, DEVLEN);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/tar/TarInputStream.java b/trunk/src/main/org/apache/tools/tar/TarInputStream.java
new file mode 100644
index 0000000..c17d6d0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarInputStream.java
@@ -0,0 +1,397 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * The TarInputStream reads a UNIX tar archive as an InputStream.
+ * methods are provided to position at each successive entry in
+ * the archive, and the read each entry as a normal input stream
+ * using read().
+ *
+ */
+public class TarInputStream extends FilterInputStream {
+    private static final int SMALL_BUFFER_SIZE = 256;
+    private static final int BUFFER_SIZE = 8 * 1024;
+    private static final int LARGE_BUFFER_SIZE = 32 * 1024;
+    private static final int BYTE_MASK = 0xFF;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean debug;
+    protected boolean hasHitEOF;
+    protected long entrySize;
+    protected long entryOffset;
+    protected byte[] readBuf;
+    protected TarBuffer buffer;
+    protected TarEntry currEntry;
+
+    /**
+     * This contents of this array is not used at all in this class,
+     * it is only here to avoid repreated object creation during calls
+     * to the no-arg read method.
+     */
+    protected byte[] oneBuf;
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     */
+    public TarInputStream(InputStream is) {
+        this(is, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     */
+    public TarInputStream(InputStream is, int blockSize) {
+        this(is, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param is the input stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarInputStream(InputStream is, int blockSize, int recordSize) {
+        super(is);
+
+        this.buffer = new TarBuffer(is, blockSize, recordSize);
+        this.readBuf = null;
+        this.oneBuf = new byte[1];
+        this.debug = false;
+        this.hasHitEOF = false;
+    }
+
+    /**
+     * Sets the debugging flag.
+     *
+     * @param debug True to turn on debugging.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+        buffer.setDebug(debug);
+    }
+
+    /**
+     * Closes this stream. Calls the TarBuffer's close() method.
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        buffer.close();
+    }
+
+    /**
+     * Get the record size being used by this stream's TarBuffer.
+     *
+     * @return The TarBuffer record size.
+     */
+    public int getRecordSize() {
+        return buffer.getRecordSize();
+    }
+
+    /**
+     * Get the available data that can be read from the current
+     * entry in the archive. This does not indicate how much data
+     * is left in the entire archive, only in the current entry.
+     * This value is determined from the entry's size header field
+     * and the amount of data already read from the current entry.
+     * Integer.MAX_VALUE is returen in case more than Integer.MAX_VALUE
+     * bytes are left in the current entry in the archive.
+     *
+     * @return The number of available bytes for the current entry.
+     * @throws IOException for signature
+     */
+    public int available() throws IOException {
+        if (entrySize - entryOffset > Integer.MAX_VALUE) {
+            return Integer.MAX_VALUE;
+        }
+        return (int) (entrySize - entryOffset);
+    }
+
+    /**
+     * Skip bytes in the input buffer. This skips bytes in the
+     * current entry's data, not the entire archive, and will
+     * stop at the end of the current entry's data if the number
+     * to skip extends beyond that point.
+     *
+     * @param numToSkip The number of bytes to skip.
+     * @return the number actually skipped
+     * @throws IOException on error
+     */
+    public long skip(long numToSkip) throws IOException {
+        // REVIEW
+        // This is horribly inefficient, but it ensures that we
+        // properly skip over bytes via the TarBuffer...
+        //
+        byte[] skipBuf = new byte[BUFFER_SIZE];
+        long skip = numToSkip;
+        while (skip > 0) {
+            int realSkip = (int) (skip > skipBuf.length ? skipBuf.length : skip);
+            int numRead = read(skipBuf, 0, realSkip);
+            if (numRead == -1) {
+                break;
+            }
+            skip -= numRead;
+        }
+        return (numToSkip - skip);
+    }
+
+    /**
+     * Since we do not support marking just yet, we return false.
+     *
+     * @return False.
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Since we do not support marking just yet, we do nothing.
+     *
+     * @param markLimit The limit to mark.
+     */
+    public void mark(int markLimit) {
+    }
+
+    /**
+     * Since we do not support marking just yet, we do nothing.
+     */
+    public void reset() {
+    }
+
+    /**
+     * Get the next entry in this tar archive. This will skip
+     * over any remaining data in the current entry, if there
+     * is one, and place the input stream at the header of the
+     * next entry, and read the header and instantiate a new
+     * TarEntry from the header bytes and return that entry.
+     * If there are no more entries in the archive, null will
+     * be returned to indicate that the end of the archive has
+     * been reached.
+     *
+     * @return The next TarEntry in the archive, or null.
+     * @throws IOException on error
+     */
+    public TarEntry getNextEntry() throws IOException {
+        if (hasHitEOF) {
+            return null;
+        }
+
+        if (currEntry != null) {
+            long numToSkip = entrySize - entryOffset;
+
+            if (debug) {
+                System.err.println("TarInputStream: SKIP currENTRY '"
+                        + currEntry.getName() + "' SZ "
+                        + entrySize + " OFF "
+                        + entryOffset + "  skipping "
+                        + numToSkip + " bytes");
+            }
+
+            if (numToSkip > 0) {
+                skip(numToSkip);
+            }
+
+            readBuf = null;
+        }
+
+        byte[] headerBuf = buffer.readRecord();
+
+        if (headerBuf == null) {
+            if (debug) {
+                System.err.println("READ NULL RECORD");
+            }
+            hasHitEOF = true;
+        } else if (buffer.isEOFRecord(headerBuf)) {
+            if (debug) {
+                System.err.println("READ EOF RECORD");
+            }
+            hasHitEOF = true;
+        }
+
+        if (hasHitEOF) {
+            currEntry = null;
+        } else {
+            currEntry = new TarEntry(headerBuf);
+
+            if (debug) {
+                System.err.println("TarInputStream: SET CURRENTRY '"
+                        + currEntry.getName()
+                        + "' size = "
+                        + currEntry.getSize());
+            }
+
+            entryOffset = 0;
+
+            entrySize = currEntry.getSize();
+        }
+
+        if (currEntry != null && currEntry.isGNULongNameEntry()) {
+            // read in the name
+            StringBuffer longName = new StringBuffer();
+            byte[] buf = new byte[SMALL_BUFFER_SIZE];
+            int length = 0;
+            while ((length = read(buf)) >= 0) {
+                longName.append(new String(buf, 0, length));
+            }
+            getNextEntry();
+            if (currEntry == null) {
+                // Bugzilla: 40334
+                // Malformed tar file - long entry name not followed by entry
+                return null;
+            }
+            // remove trailing null terminator
+            if (longName.length() > 0
+                && longName.charAt(longName.length() - 1) == 0) {
+                longName.deleteCharAt(longName.length() - 1);
+            }
+            currEntry.setName(longName.toString());
+        }
+
+        return currEntry;
+    }
+
+    /**
+     * Reads a byte from the current tar archive entry.
+     *
+     * This method simply calls read( byte[], int, int ).
+     *
+     * @return The byte read, or -1 at EOF.
+     * @throws IOException on error
+     */
+    public int read() throws IOException {
+        int num = read(oneBuf, 0, 1);
+        return num == -1 ? -1 : ((int) oneBuf[0]) & BYTE_MASK;
+    }
+
+    /**
+     * Reads bytes from the current tar archive entry.
+     *
+     * This method is aware of the boundaries of the current
+     * entry in the archive and will deal with them as if they
+     * were this stream's start and EOF.
+     *
+     * @param buf The buffer into which to place bytes read.
+     * @param offset The offset at which to place bytes read.
+     * @param numToRead The number of bytes to read.
+     * @return The number of bytes read, or -1 at EOF.
+     * @throws IOException on error
+     */
+    public int read(byte[] buf, int offset, int numToRead) throws IOException {
+        int totalRead = 0;
+
+        if (entryOffset >= entrySize) {
+            return -1;
+        }
+
+        if ((numToRead + entryOffset) > entrySize) {
+            numToRead = (int) (entrySize - entryOffset);
+        }
+
+        if (readBuf != null) {
+            int sz = (numToRead > readBuf.length) ? readBuf.length
+                    : numToRead;
+
+            System.arraycopy(readBuf, 0, buf, offset, sz);
+
+            if (sz >= readBuf.length) {
+                readBuf = null;
+            } else {
+                int newLen = readBuf.length - sz;
+                byte[] newBuf = new byte[newLen];
+
+                System.arraycopy(readBuf, sz, newBuf, 0, newLen);
+
+                readBuf = newBuf;
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        while (numToRead > 0) {
+            byte[] rec = buffer.readRecord();
+
+            if (rec == null) {
+                // Unexpected EOF!
+                throw new IOException("unexpected EOF with " + numToRead
+                        + " bytes unread");
+            }
+
+            int sz = numToRead;
+            int recLen = rec.length;
+
+            if (recLen > sz) {
+                System.arraycopy(rec, 0, buf, offset, sz);
+
+                readBuf = new byte[recLen - sz];
+
+                System.arraycopy(rec, sz, readBuf, 0, recLen - sz);
+            } else {
+                sz = recLen;
+
+                System.arraycopy(rec, 0, buf, offset, recLen);
+            }
+
+            totalRead += sz;
+            numToRead -= sz;
+            offset += sz;
+        }
+
+        entryOffset += totalRead;
+
+        return totalRead;
+    }
+
+    /**
+     * Copies the contents of the current tar archive entry directly into
+     * an output stream.
+     *
+     * @param out The OutputStream into which to write the entry's data.
+     * @throws IOException on error
+     */
+    public void copyEntryContents(OutputStream out) throws IOException {
+        byte[] buf = new byte[LARGE_BUFFER_SIZE];
+
+        while (true) {
+            int numRead = read(buf, 0, buf.length);
+
+            if (numRead == -1) {
+                break;
+            }
+
+            out.write(buf, 0, numRead);
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/tar/TarOutputStream.java b/trunk/src/main/org/apache/tools/tar/TarOutputStream.java
new file mode 100644
index 0000000..50fa2c1
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarOutputStream.java
@@ -0,0 +1,355 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * The TarOutputStream writes a UNIX tar archive as an OutputStream.
+ * Methods are provided to put entries, and then write their contents
+ * by writing to this stream using write().
+ *
+ */
+public class TarOutputStream extends FilterOutputStream {
+    /** Fail if a long file name is required in the archive. */
+    public static final int LONGFILE_ERROR = 0;
+
+    /** Long paths will be truncated in the archive. */
+    public static final int LONGFILE_TRUNCATE = 1;
+
+    /** GNU tar extensions are used to store long file names in the archive. */
+    public static final int LONGFILE_GNU = 2;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+    protected boolean   debug;
+    protected long      currSize;
+    protected String    currName;
+    protected long      currBytes;
+    protected byte[]    oneBuf;
+    protected byte[]    recordBuf;
+    protected int       assemLen;
+    protected byte[]    assemBuf;
+    protected TarBuffer buffer;
+    protected int       longFileMode = LONGFILE_ERROR;
+    // CheckStyle:VisibilityModifier ON
+
+    private boolean closed = false;
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     */
+    public TarOutputStream(OutputStream os) {
+        this(os, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     * @param blockSize the block size to use
+     */
+    public TarOutputStream(OutputStream os, int blockSize) {
+        this(os, blockSize, TarBuffer.DEFAULT_RCDSIZE);
+    }
+
+    /**
+     * Constructor for TarInputStream.
+     * @param os the output stream to use
+     * @param blockSize the block size to use
+     * @param recordSize the record size to use
+     */
+    public TarOutputStream(OutputStream os, int blockSize, int recordSize) {
+        super(os);
+
+        this.buffer = new TarBuffer(os, blockSize, recordSize);
+        this.debug = false;
+        this.assemLen = 0;
+        this.assemBuf = new byte[recordSize];
+        this.recordBuf = new byte[recordSize];
+        this.oneBuf = new byte[1];
+    }
+
+    /**
+     * Set the long file mode.
+     * This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or LONGFILE_GNU(2).
+     * This specifies the treatment of long file names (names >= TarConstants.NAMELEN).
+     * Default is LONGFILE_ERROR.
+     * @param longFileMode the mode to use
+     */
+    public void setLongFileMode(int longFileMode) {
+        this.longFileMode = longFileMode;
+    }
+
+
+    /**
+     * Sets the debugging flag.
+     *
+     * @param debugF True to turn on debugging.
+     */
+    public void setDebug(boolean debugF) {
+        this.debug = debugF;
+    }
+
+    /**
+     * Sets the debugging flag in this stream's TarBuffer.
+     *
+     * @param debug True to turn on debugging.
+     */
+    public void setBufferDebug(boolean debug) {
+        buffer.setDebug(debug);
+    }
+
+    /**
+     * Ends the TAR archive without closing the underlying OutputStream.
+     * The result is that the two EOF records of nulls are written.
+     * @throws IOException on error
+     */
+    public void finish() throws IOException {
+        // See Bugzilla 28776 for a discussion on this
+        // http://issues.apache.org/bugzilla/show_bug.cgi?id=28776
+        writeEOFRecord();
+        writeEOFRecord();
+    }
+
+    /**
+     * Ends the TAR archive and closes the underlying OutputStream.
+     * This means that finish() is called followed by calling the
+     * TarBuffer's close().
+     * @throws IOException on error
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            finish();
+            buffer.close();
+            out.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Get the record size being used by this stream's TarBuffer.
+     *
+     * @return The TarBuffer record size.
+     */
+    public int getRecordSize() {
+        return buffer.getRecordSize();
+    }
+
+    /**
+     * Put an entry on the output stream. This writes the entry's
+     * header record and positions the output stream for writing
+     * the contents of the entry. Once this method is called, the
+     * stream is ready for calls to write() to write the entry's
+     * contents. Once the contents are written, closeEntry()
+     * <B>MUST</B> be called to ensure that all buffered data
+     * is completely written to the output stream.
+     *
+     * @param entry The TarEntry to be written to the archive.
+     * @throws IOException on error
+     */
+    public void putNextEntry(TarEntry entry) throws IOException {
+        if (entry.getName().length() >= TarConstants.NAMELEN) {
+
+            if (longFileMode == LONGFILE_GNU) {
+                // create a TarEntry for the LongLink, the contents
+                // of which are the entry's name
+                TarEntry longLinkEntry = new TarEntry(TarConstants.GNU_LONGLINK,
+                                                      TarConstants.LF_GNUTYPE_LONGNAME);
+
+                longLinkEntry.setSize(entry.getName().length() + 1);
+                putNextEntry(longLinkEntry);
+                write(entry.getName().getBytes());
+                write(0);
+                closeEntry();
+            } else if (longFileMode != LONGFILE_TRUNCATE) {
+                throw new RuntimeException("file name '" + entry.getName()
+                                             + "' is too long ( > "
+                                             + TarConstants.NAMELEN + " bytes)");
+            }
+        }
+
+        entry.writeEntryHeader(recordBuf);
+        buffer.writeRecord(recordBuf);
+
+        currBytes = 0;
+
+        if (entry.isDirectory()) {
+            currSize = 0;
+        } else {
+            currSize = entry.getSize();
+        }
+        currName = entry.getName();
+    }
+
+    /**
+     * Close an entry. This method MUST be called for all file
+     * entries that contain data. The reason is that we must
+     * buffer data written to the stream in order to satisfy
+     * the buffer's record based writes. Thus, there may be
+     * data fragments still being assembled that must be written
+     * to the output stream before this entry is closed and the
+     * next entry written.
+     * @throws IOException on error
+     */
+    public void closeEntry() throws IOException {
+        if (assemLen > 0) {
+            for (int i = assemLen; i < assemBuf.length; ++i) {
+                assemBuf[i] = 0;
+            }
+
+            buffer.writeRecord(assemBuf);
+
+            currBytes += assemLen;
+            assemLen = 0;
+        }
+
+        if (currBytes < currSize) {
+            throw new IOException("entry '" + currName + "' closed at '"
+                                  + currBytes
+                                  + "' before the '" + currSize
+                                  + "' bytes specified in the header were written");
+        }
+    }
+
+    /**
+     * Writes a byte to the current tar archive entry.
+     *
+     * This method simply calls read( byte[], int, int ).
+     *
+     * @param b The byte written.
+     * @throws IOException on error
+     */
+    public void write(int b) throws IOException {
+        oneBuf[0] = (byte) b;
+
+        write(oneBuf, 0, 1);
+    }
+
+    /**
+     * Writes bytes to the current tar archive entry.
+     *
+     * This method simply calls write( byte[], int, int ).
+     *
+     * @param wBuf The buffer to write to the archive.
+     * @throws IOException on error
+     */
+    public void write(byte[] wBuf) throws IOException {
+        write(wBuf, 0, wBuf.length);
+    }
+
+    /**
+     * Writes bytes to the current tar archive entry. This method
+     * is aware of the current entry and will throw an exception if
+     * you attempt to write bytes past the length specified for the
+     * current entry. The method is also (painfully) aware of the
+     * record buffering required by TarBuffer, and manages buffers
+     * that are not a multiple of recordsize in length, including
+     * assembling records from small buffers.
+     *
+     * @param wBuf The buffer to write to the archive.
+     * @param wOffset The offset in the buffer from which to get bytes.
+     * @param numToWrite The number of bytes to write.
+     * @throws IOException on error
+     */
+    public void write(byte[] wBuf, int wOffset, int numToWrite) throws IOException {
+        if ((currBytes + numToWrite) > currSize) {
+            throw new IOException("request to write '" + numToWrite
+                                  + "' bytes exceeds size in header of '"
+                                  + currSize + "' bytes for entry '"
+                                  + currName + "'");
+
+            //
+            // We have to deal with assembly!!!
+            // The programmer can be writing little 32 byte chunks for all
+            // we know, and we must assemble complete records for writing.
+            // REVIEW Maybe this should be in TarBuffer? Could that help to
+            // eliminate some of the buffer copying.
+            //
+        }
+
+        if (assemLen > 0) {
+            if ((assemLen + numToWrite) >= recordBuf.length) {
+                int aLen = recordBuf.length - assemLen;
+
+                System.arraycopy(assemBuf, 0, recordBuf, 0,
+                                 assemLen);
+                System.arraycopy(wBuf, wOffset, recordBuf,
+                                 assemLen, aLen);
+                buffer.writeRecord(recordBuf);
+
+                currBytes += recordBuf.length;
+                wOffset += aLen;
+                numToWrite -= aLen;
+                assemLen = 0;
+            } else {
+                System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
+                                 numToWrite);
+
+                wOffset += numToWrite;
+                assemLen += numToWrite;
+                numToWrite -= numToWrite;
+            }
+        }
+
+        //
+        // When we get here we have EITHER:
+        // o An empty "assemble" buffer.
+        // o No bytes to write (numToWrite == 0)
+        //
+        while (numToWrite > 0) {
+            if (numToWrite < recordBuf.length) {
+                System.arraycopy(wBuf, wOffset, assemBuf, assemLen,
+                                 numToWrite);
+
+                assemLen += numToWrite;
+
+                break;
+            }
+
+            buffer.writeRecord(wBuf, wOffset);
+
+            int num = recordBuf.length;
+
+            currBytes += num;
+            numToWrite -= num;
+            wOffset += num;
+        }
+    }
+
+    /**
+     * Write an EOF (end of archive) record to the tar archive.
+     * An EOF record consists of a record of all zeros.
+     */
+    private void writeEOFRecord() throws IOException {
+        for (int i = 0; i < recordBuf.length; ++i) {
+            recordBuf[i] = 0;
+        }
+
+        buffer.writeRecord(recordBuf);
+    }
+}
+
+
diff --git a/trunk/src/main/org/apache/tools/tar/TarUtils.java b/trunk/src/main/org/apache/tools/tar/TarUtils.java
new file mode 100644
index 0000000..1c4d960
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/tar/TarUtils.java
@@ -0,0 +1,206 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * This package is based on the work done by Timothy Gerard Endres
+ * (time@ice.com) to whom the Ant project is very grateful for his great code.
+ */
+
+package org.apache.tools.tar;
+
+/**
+ * This class provides static utility methods to work with byte streams.
+ *
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class TarUtils {
+
+    private static final int BYTE_MASK = 255;
+
+    /**
+     * Parse an octal string from a header buffer. This is used for the
+     * file permission mode value.
+     *
+     * @param header The header buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The long value of the octal string.
+     */
+    public static long parseOctal(byte[] header, int offset, int length) {
+        long    result = 0;
+        boolean stillPadding = true;
+        int     end = offset + length;
+
+        for (int i = offset; i < end; ++i) {
+            if (header[i] == 0) {
+                break;
+            }
+
+            if (header[i] == (byte) ' ' || header[i] == '0') {
+                if (stillPadding) {
+                    continue;
+                }
+
+                if (header[i] == (byte) ' ') {
+                    break;
+                }
+            }
+
+            stillPadding = false;
+            // CheckStyle:MagicNumber OFF
+            result = (result << 3) + (header[i] - '0');
+            // CheckStyle:MagicNumber ON
+        }
+
+        return result;
+    }
+
+    /**
+     * Parse an entry name from a header buffer.
+     *
+     * @param header The header buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The header's entry name.
+     */
+    public static StringBuffer parseName(byte[] header, int offset, int length) {
+        StringBuffer result = new StringBuffer(length);
+        int          end = offset + length;
+
+        for (int i = offset; i < end; ++i) {
+            if (header[i] == 0) {
+                break;
+            }
+
+            result.append((char) header[i]);
+        }
+
+        return result;
+    }
+
+    /**
+     * Determine the number of bytes in an entry name.
+     *
+     * @param name The header name from which to parse.
+     * @param buf The buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The number of bytes in a header's entry name.
+     */
+    public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) {
+        int i;
+
+        for (i = 0; i < length && i < name.length(); ++i) {
+            buf[offset + i] = (byte) name.charAt(i);
+        }
+
+        for (; i < length; ++i) {
+            buf[offset + i] = 0;
+        }
+
+        return offset + length;
+    }
+
+    /**
+     * Parse an octal integer from a header buffer.
+     *
+     * @param value The header value
+     * @param buf The buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The integer value of the octal bytes.
+     */
+    public static int getOctalBytes(long value, byte[] buf, int offset, int length) {
+        int    idx = length - 1;
+
+        buf[offset + idx] = 0;
+        --idx;
+        buf[offset + idx] = (byte) ' ';
+        --idx;
+
+        if (value == 0) {
+            buf[offset + idx] = (byte) '0';
+            --idx;
+        } else {
+            for (long val = value; idx >= 0 && val > 0; --idx) {
+                // CheckStyle:MagicNumber OFF
+                buf[offset + idx] = (byte) ((byte) '0' + (byte) (val & 7));
+                val = val >> 3;
+                // CheckStyle:MagicNumber ON
+            }
+        }
+
+        for (; idx >= 0; --idx) {
+            buf[offset + idx] = (byte) ' ';
+        }
+
+        return offset + length;
+    }
+
+    /**
+     * Parse an octal long integer from a header buffer.
+     *
+     * @param value The header value
+     * @param buf The buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The long value of the octal bytes.
+     */
+    public static int getLongOctalBytes(long value, byte[] buf, int offset, int length) {
+        byte[] temp = new byte[length + 1];
+
+        getOctalBytes(value, temp, 0, length + 1);
+        System.arraycopy(temp, 0, buf, offset, length);
+
+        return offset + length;
+    }
+
+    /**
+     * Parse the checksum octal integer from a header buffer.
+     *
+     * @param value The header value
+     * @param buf The buffer from which to parse.
+     * @param offset The offset into the buffer from which to parse.
+     * @param length The number of header bytes to parse.
+     * @return The integer value of the entry's checksum.
+     */
+    public static int getCheckSumOctalBytes(long value, byte[] buf, int offset, int length) {
+        getOctalBytes(value, buf, offset, length);
+
+        buf[offset + length - 1] = (byte) ' ';
+        buf[offset + length - 2] = 0;
+
+        return offset + length;
+    }
+
+    /**
+     * Compute the checksum of a tar entry header.
+     *
+     * @param buf The tar entry's header buffer.
+     * @return The computed checksum.
+     */
+    public static long computeCheckSum(byte[] buf) {
+        long sum = 0;
+
+        for (int i = 0; i < buf.length; ++i) {
+            sum += BYTE_MASK & buf[i];
+        }
+
+        return sum;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/zip/AsiExtraField.java b/trunk/src/main/org/apache/tools/zip/AsiExtraField.java
new file mode 100644
index 0000000..a5ce0a5
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/AsiExtraField.java
@@ -0,0 +1,337 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.zip.CRC32;
+import java.util.zip.ZipException;
+
+/**
+ * Adds Unix file permission and UID/GID fields as well as symbolic
+ * link handling.
+ *
+ * <p>This class uses the ASi extra field in the format:
+ * <pre>
+ *         Value         Size            Description
+ *         -----         ----            -----------
+ * (Unix3) 0x756e        Short           tag for this extra block type
+ *         TSize         Short           total data size for this block
+ *         CRC           Long            CRC-32 of the remaining data
+ *         Mode          Short           file permissions
+ *         SizDev        Long            symlink'd size OR major/minor dev num
+ *         UID           Short           user ID
+ *         GID           Short           group ID
+ *         (var.)        variable        symbolic link filename
+ * </pre>
+ * taken from appnote.iz (Info-ZIP note, 981119) found at <a
+ * href="ftp://ftp.uu.net/pub/archiving/zip/doc/">ftp://ftp.uu.net/pub/archiving/zip/doc/</a></p>
+
+ *
+ * <p>Short is two bytes and Long is four bytes in big endian byte and
+ * word order, device numbers are currently not supported.</p>
+ *
+ */
+public class AsiExtraField implements ZipExtraField, UnixStat, Cloneable {
+
+    private static final ZipShort HEADER_ID = new ZipShort(0x756E);
+    private static final int      WORD = 4;
+    /**
+     * Standard Unix stat(2) file mode.
+     *
+     * @since 1.1
+     */
+    private int mode = 0;
+    /**
+     * User ID.
+     *
+     * @since 1.1
+     */
+    private int uid = 0;
+    /**
+     * Group ID.
+     *
+     * @since 1.1
+     */
+    private int gid = 0;
+    /**
+     * File this entry points to, if it is a symbolic link.
+     *
+     * <p>empty string - if entry is not a symbolic link.</p>
+     *
+     * @since 1.1
+     */
+    private String link = "";
+    /**
+     * Is this an entry for a directory?
+     *
+     * @since 1.1
+     */
+    private boolean dirFlag = false;
+
+    /**
+     * Instance used to calculate checksums.
+     *
+     * @since 1.1
+     */
+    private CRC32 crc = new CRC32();
+
+    /** Constructor for AsiExtraField. */
+    public AsiExtraField() {
+    }
+
+    /**
+     * The Header-ID.
+     * @return the value for the header id for this extrafield
+     * @since 1.1
+     */
+    public ZipShort getHeaderId() {
+        return HEADER_ID;
+    }
+
+    /**
+     * Length of the extra field in the local file data - without
+     * Header-ID or length specifier.
+     * @return a <code>ZipShort</code> for the length of the data of this extra field
+     * @since 1.1
+     */
+    public ZipShort getLocalFileDataLength() {
+        return new ZipShort(WORD         // CRC
+                          + 2         // Mode
+                          + WORD         // SizDev
+                          + 2         // UID
+                          + 2         // GID
+                          + getLinkedFile().getBytes().length);
+    }
+
+    /**
+     * Delegate to local file data.
+     * @return the centralDirectory length
+     * @since 1.1
+     */
+    public ZipShort getCentralDirectoryLength() {
+        return getLocalFileDataLength();
+    }
+
+    /**
+     * The actual data to put into local file data - without Header-ID
+     * or length specifier.
+     * @return get the data
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataData() {
+        // CRC will be added later
+        byte[] data = new byte[getLocalFileDataLength().getValue() - WORD];
+        System.arraycopy(ZipShort.getBytes(getMode()), 0, data, 0, 2);
+
+        byte[] linkArray = getLinkedFile().getBytes();
+        // CheckStyle:MagicNumber OFF
+        System.arraycopy(ZipLong.getBytes(linkArray.length),
+                         0, data, 2, WORD);
+
+        System.arraycopy(ZipShort.getBytes(getUserId()),
+                         0, data, 6, 2);
+        System.arraycopy(ZipShort.getBytes(getGroupId()),
+                         0, data, 8, 2);
+
+        System.arraycopy(linkArray, 0, data, 10, linkArray.length);
+        // CheckStyle:MagicNumber ON
+
+        crc.reset();
+        crc.update(data);
+        long checksum = crc.getValue();
+
+        byte[] result = new byte[data.length + WORD];
+        System.arraycopy(ZipLong.getBytes(checksum), 0, result, 0, WORD);
+        System.arraycopy(data, 0, result, WORD, data.length);
+        return result;
+    }
+
+    /**
+     * Delegate to local file data.
+     * @return the local file data
+     * @since 1.1
+     */
+    public byte[] getCentralDirectoryData() {
+        return getLocalFileDataData();
+    }
+
+    /**
+     * Set the user id.
+     * @param uid the user id
+     * @since 1.1
+     */
+    public void setUserId(int uid) {
+        this.uid = uid;
+    }
+
+    /**
+     * Get the user id.
+     * @return the user id
+     * @since 1.1
+     */
+    public int getUserId() {
+        return uid;
+    }
+
+    /**
+     * Set the group id.
+     * @param gid the group id
+     * @since 1.1
+     */
+    public void setGroupId(int gid) {
+        this.gid = gid;
+    }
+
+    /**
+     * Get the group id.
+     * @return the group id
+     * @since 1.1
+     */
+    public int getGroupId() {
+        return gid;
+    }
+
+    /**
+     * Indicate that this entry is a symbolic link to the given filename.
+     *
+     * @param name Name of the file this entry links to, empty String
+     *             if it is not a symbolic link.
+     *
+     * @since 1.1
+     */
+    public void setLinkedFile(String name) {
+        link = name;
+        mode = getMode(mode);
+    }
+
+    /**
+     * Name of linked file
+     *
+     * @return name of the file this entry links to if it is a
+     *         symbolic link, the empty string otherwise.
+     *
+     * @since 1.1
+     */
+    public String getLinkedFile() {
+        return link;
+    }
+
+    /**
+     * Is this entry a symbolic link?
+     * @return true if this is a symbolic link
+     * @since 1.1
+     */
+    public boolean isLink() {
+        return getLinkedFile().length() != 0;
+    }
+
+    /**
+     * File mode of this file.
+     * @param mode the file mode
+     * @since 1.1
+     */
+    public void setMode(int mode) {
+        this.mode = getMode(mode);
+    }
+
+    /**
+     * File mode of this file.
+     * @return the file mode
+     * @since 1.1
+     */
+    public int getMode() {
+        return mode;
+    }
+
+    /**
+     * Indicate whether this entry is a directory.
+     * @param dirFlag if true, this entry is a directory
+     * @since 1.1
+     */
+    public void setDirectory(boolean dirFlag) {
+        this.dirFlag = dirFlag;
+        mode = getMode(mode);
+    }
+
+    /**
+     * Is this entry a directory?
+     * @return true if this entry is a directory
+     * @since 1.1
+     */
+    public boolean isDirectory() {
+        return dirFlag && !isLink();
+    }
+
+    /**
+     * Populate data from this array as if it was in local file data.
+     * @param data an array of bytes
+     * @param offset the start offset
+     * @param length the number of bytes in the array from offset
+     * @since 1.1
+     * @throws ZipException on error
+     */
+    public void parseFromLocalFileData(byte[] data, int offset, int length)
+        throws ZipException {
+
+        long givenChecksum = ZipLong.getValue(data, offset);
+        byte[] tmp = new byte[length - WORD];
+        System.arraycopy(data, offset + WORD, tmp, 0, length - WORD);
+        crc.reset();
+        crc.update(tmp);
+        long realChecksum = crc.getValue();
+        if (givenChecksum != realChecksum) {
+            throw new ZipException("bad CRC checksum "
+                                   + Long.toHexString(givenChecksum)
+                                   + " instead of "
+                                   + Long.toHexString(realChecksum));
+        }
+
+        int newMode = ZipShort.getValue(tmp, 0);
+        // CheckStyle:MagicNumber OFF
+        byte[] linkArray = new byte[(int) ZipLong.getValue(tmp, 2)];
+        uid = ZipShort.getValue(tmp, 6);
+        gid = ZipShort.getValue(tmp, 8);
+
+        if (linkArray.length == 0) {
+            link = "";
+        } else {
+            System.arraycopy(tmp, 10, linkArray, 0, linkArray.length);
+            link = new String(linkArray);
+        }
+        // CheckStyle:MagicNumber ON
+        setDirectory((newMode & DIR_FLAG) != 0);
+        setMode(newMode);
+    }
+
+    /**
+     * Get the file mode for given permissions with the correct file type.
+     * @param mode the mode
+     * @return the type with the mode
+     * @since 1.1
+     */
+    protected int getMode(int mode) {
+        int type = FILE_FLAG;
+        if (isLink()) {
+            type = LINK_FLAG;
+        } else if (isDirectory()) {
+            type = DIR_FLAG;
+        }
+        return type | (mode & PERM_MASK);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java b/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java
new file mode 100644
index 0000000..237f5be
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ExtraFieldUtils.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.zip.ZipException;
+
+/**
+ * ZipExtraField related methods
+ *
+ */
+// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
+public class ExtraFieldUtils {
+
+    private static final int WORD = 4;
+
+    /**
+     * Static registry of known extra fields.
+     *
+     * @since 1.1
+     */
+    private static Hashtable implementations;
+
+    static {
+        implementations = new Hashtable();
+        register(AsiExtraField.class);
+        register(JarMarker.class);
+    }
+
+    /**
+     * Register a ZipExtraField implementation.
+     *
+     * <p>The given class must have a no-arg constructor and implement
+     * the {@link ZipExtraField ZipExtraField interface}.</p>
+     * @param c the class to register
+     *
+     * @since 1.1
+     */
+    public static void register(Class c) {
+        try {
+            ZipExtraField ze = (ZipExtraField) c.newInstance();
+            implementations.put(ze.getHeaderId(), c);
+        } catch (ClassCastException cc) {
+            throw new RuntimeException(c + " doesn\'t implement ZipExtraField");
+        } catch (InstantiationException ie) {
+            throw new RuntimeException(c + " is not a concrete class");
+        } catch (IllegalAccessException ie) {
+            throw new RuntimeException(c + "\'s no-arg constructor is not public");
+        }
+    }
+
+    /**
+     * Create an instance of the approriate ExtraField, falls back to
+     * {@link UnrecognizedExtraField UnrecognizedExtraField}.
+     * @param headerId the header identifier
+     * @return an instance of the appropiate ExtraField
+     * @exception InstantiationException if unable to instantiate the class
+     * @exception IllegalAccessException if not allowed to instatiate the class
+     * @since 1.1
+     */
+    public static ZipExtraField createExtraField(ZipShort headerId)
+        throws InstantiationException, IllegalAccessException {
+        Class c = (Class) implementations.get(headerId);
+        if (c != null) {
+            return (ZipExtraField) c.newInstance();
+        }
+        UnrecognizedExtraField u = new UnrecognizedExtraField();
+        u.setHeaderId(headerId);
+        return u;
+    }
+
+    /**
+     * Split the array into ExtraFields and populate them with the
+     * give data.
+     * @param data an array of bytes
+     * @return an array of ExtraFields
+     * @since 1.1
+     * @throws ZipException on error
+     */
+    public static ZipExtraField[] parse(byte[] data) throws ZipException {
+        Vector v = new Vector();
+        int start = 0;
+        while (start <= data.length - WORD) {
+            ZipShort headerId = new ZipShort(data, start);
+            int length = (new ZipShort(data, start + 2)).getValue();
+            if (start + WORD + length > data.length) {
+                throw new ZipException("data starting at " + start
+                    + " is in unknown format");
+            }
+            try {
+                ZipExtraField ze = createExtraField(headerId);
+                ze.parseFromLocalFileData(data, start + WORD, length);
+                v.addElement(ze);
+            } catch (InstantiationException ie) {
+                throw new ZipException(ie.getMessage());
+            } catch (IllegalAccessException iae) {
+                throw new ZipException(iae.getMessage());
+            }
+            start += (length + WORD);
+        }
+        if (start != data.length) { // array not exhausted
+            throw new ZipException("data starting at " + start
+                + " is in unknown format");
+        }
+
+        ZipExtraField[] result = new ZipExtraField[v.size()];
+        v.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Merges the local file data fields of the given ZipExtraFields.
+     * @param data an array of ExtraFiles
+     * @return an array of bytes
+     * @since 1.1
+     */
+    public static byte[] mergeLocalFileDataData(ZipExtraField[] data) {
+        int sum = WORD * data.length;
+        for (int i = 0; i < data.length; i++) {
+            sum += data[i].getLocalFileDataLength().getValue();
+        }
+        byte[] result = new byte[sum];
+        int start = 0;
+        for (int i = 0; i < data.length; i++) {
+            System.arraycopy(data[i].getHeaderId().getBytes(),
+                             0, result, start, 2);
+            System.arraycopy(data[i].getLocalFileDataLength().getBytes(),
+                             0, result, start + 2, 2);
+            byte[] local = data[i].getLocalFileDataData();
+            System.arraycopy(local, 0, result, start + WORD, local.length);
+            start += (local.length + WORD);
+        }
+        return result;
+    }
+
+    /**
+     * Merges the central directory fields of the given ZipExtraFields.
+     * @param data an array of ExtraFields
+     * @return an array of bytes
+     * @since 1.1
+     */
+    public static byte[] mergeCentralDirectoryData(ZipExtraField[] data) {
+        int sum = WORD * data.length;
+        for (int i = 0; i < data.length; i++) {
+            sum += data[i].getCentralDirectoryLength().getValue();
+        }
+        byte[] result = new byte[sum];
+        int start = 0;
+        for (int i = 0; i < data.length; i++) {
+            System.arraycopy(data[i].getHeaderId().getBytes(),
+                             0, result, start, 2);
+            System.arraycopy(data[i].getCentralDirectoryLength().getBytes(),
+                             0, result, start + 2, 2);
+            byte[] local = data[i].getCentralDirectoryData();
+            System.arraycopy(local, 0, result, start + WORD, local.length);
+            start += (local.length + WORD);
+        }
+        return result;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/zip/JarMarker.java b/trunk/src/main/org/apache/tools/zip/JarMarker.java
new file mode 100644
index 0000000..c063353
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/JarMarker.java
@@ -0,0 +1,108 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.zip.ZipException;
+
+/**
+ * If this extra field is added as the very first extra field of the
+ * archive, Solaris will consider it an executable jar file.
+ *
+ * @since Ant 1.6.3
+ */
+public final class JarMarker implements ZipExtraField {
+
+    private static final ZipShort ID = new ZipShort(0xCAFE);
+    private static final ZipShort NULL = new ZipShort(0);
+    private static final byte[] NO_BYTES = new byte[0];
+    private static final JarMarker DEFAULT = new JarMarker();
+
+    /** No-arg constructor */
+    public JarMarker() {
+        // empty
+    }
+
+    /**
+     * Since JarMarker is stateless we can always use the same instance.
+     * @return the DEFAULT jarmaker.
+     */
+    public static JarMarker getInstance() {
+        return DEFAULT;
+    }
+
+    /**
+     * The Header-ID.
+     * @return the header id
+     */
+    public ZipShort getHeaderId() {
+        return ID;
+    }
+
+    /**
+     * Length of the extra field in the local file data - without
+     * Header-ID or length specifier.
+     * @return 0
+     */
+    public ZipShort getLocalFileDataLength() {
+        return NULL;
+    }
+
+    /**
+     * Length of the extra field in the central directory - without
+     * Header-ID or length specifier.
+     * @return 0
+     */
+    public ZipShort getCentralDirectoryLength() {
+        return NULL;
+    }
+
+    /**
+     * The actual data to put into local file data - without Header-ID
+     * or length specifier.
+     * @return the data
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataData() {
+        return NO_BYTES;
+    }
+
+    /**
+     * The actual data to put central directory - without Header-ID or
+     * length specifier.
+     * @return the data
+     */
+    public byte[] getCentralDirectoryData() {
+        return NO_BYTES;
+    }
+
+    /**
+     * Populate data from this array as if it was in local file data.
+     * @param data an array of bytes
+     * @param offset the start offset
+     * @param length the number of bytes in the array from offset
+     *
+     * @throws ZipException on error
+     */
+    public void parseFromLocalFileData(byte[] data, int offset, int length)
+        throws ZipException {
+        if (length != 0) {
+            throw new ZipException("JarMarker doesn't expect any data");
+        }
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/zip/UnixStat.java b/trunk/src/main/org/apache/tools/zip/UnixStat.java
new file mode 100644
index 0000000..2ca0674
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/UnixStat.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+/**
+ * Constants from stat.h on Unix systems.
+ *
+ */
+// CheckStyle:InterfaceIsTypeCheck OFF - backward compatible
+public interface UnixStat {
+
+    /**
+     * Bits used for permissions (and sticky bit)
+     *
+     * @since 1.1
+     */
+    int PERM_MASK =           07777;
+    /**
+     * Indicates symbolic links.
+     *
+     * @since 1.1
+     */
+    int LINK_FLAG =         0120000;
+    /**
+     * Indicates plain files.
+     *
+     * @since 1.1
+     */
+    int FILE_FLAG =         0100000;
+    /**
+     * Indicates directories.
+     *
+     * @since 1.1
+     */
+    int DIR_FLAG =           040000;
+
+    // ----------------------------------------------------------
+    // somewhat arbitrary choices that are quite common for shared
+    // installations
+    // -----------------------------------------------------------
+
+    /**
+     * Default permissions for symbolic links.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_LINK_PERM =    0777;
+    /**
+     * Default permissions for directories.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_DIR_PERM =     0755;
+    /**
+     * Default permissions for plain files.
+     *
+     * @since 1.1
+     */
+    int DEFAULT_FILE_PERM =    0644;
+}
diff --git a/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java b/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
new file mode 100644
index 0000000..79f2e6e
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/UnrecognizedExtraField.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+/**
+ * Simple placeholder for all those extra fields we don't want to deal
+ * with.
+ *
+ * <p>Assumes local file data and central directory entries are
+ * identical - unless told the opposite.</p>
+ *
+ */
+public class UnrecognizedExtraField implements ZipExtraField {
+
+    /**
+     * The Header-ID.
+     *
+     * @since 1.1
+     */
+    private ZipShort headerId;
+
+    /**
+     * Set the header id.
+     * @param headerId the header id to use
+     */
+    public void setHeaderId(ZipShort headerId) {
+        this.headerId = headerId;
+    }
+
+    /**
+     * Get the header id.
+     * @return the header id
+     */
+    public ZipShort getHeaderId() {
+        return headerId;
+    }
+
+    /**
+     * Extra field data in local file data - without
+     * Header-ID or length specifier.
+     *
+     * @since 1.1
+     */
+    private byte[] localData;
+
+    /**
+     * Set the extra field data in the local file data -
+     * without Header-ID or length specifier.
+     * @param data the field data to use
+     */
+    public void setLocalFileDataData(byte[] data) {
+        localData = data;
+    }
+
+    /**
+     * Get the length of the local data.
+     * @return the length of the local data
+     */
+    public ZipShort getLocalFileDataLength() {
+        return new ZipShort(localData.length);
+    }
+
+    /**
+     * Get the local data.
+     * @return the local data
+     */
+    public byte[] getLocalFileDataData() {
+        return localData;
+    }
+
+    /**
+     * Extra field data in central directory - without
+     * Header-ID or length specifier.
+     *
+     * @since 1.1
+     */
+    private byte[] centralData;
+
+    /**
+     * Set the extra field data in central directory.
+     * @param data the data to use
+     */
+    public void setCentralDirectoryData(byte[] data) {
+        centralData = data;
+    }
+
+    /**
+     * Get the central data length.
+     * If there is no central data, get the local file data length.
+     * @return the central data length
+     */
+    public ZipShort getCentralDirectoryLength() {
+        if (centralData != null) {
+            return new ZipShort(centralData.length);
+        }
+        return getLocalFileDataLength();
+    }
+
+    /**
+     * Get the central data.
+     * @return the central data if present, else return the local file data
+     */
+    public byte[] getCentralDirectoryData() {
+        if (centralData != null) {
+            return centralData;
+        }
+        return getLocalFileDataData();
+    }
+
+    /**
+     * @param data the array of bytes.
+     * @param offset the source location in the data array.
+     * @param length the number of bytes to use in the data array.
+     * @see ZipExtraField#parseFromLocalFileData(byte[], int, int)
+     */
+    public void parseFromLocalFileData(byte[] data, int offset, int length) {
+        byte[] tmp = new byte[length];
+        System.arraycopy(data, offset, tmp, 0, length);
+        setLocalFileDataData(tmp);
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipEntry.java b/trunk/src/main/org/apache/tools/zip/ZipEntry.java
new file mode 100644
index 0000000..5bceee0
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipEntry.java
@@ -0,0 +1,372 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.Vector;
+import java.util.zip.ZipException;
+
+/**
+ * Extension that adds better handling of extra fields and provides
+ * access to the internal and external file attributes.
+ *
+ */
+public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable {
+
+    private static final int PLATFORM_UNIX = 3;
+    private static final int PLATFORM_FAT  = 0;
+    private static final int SHORT_MASK = 0xFFFF;
+    private static final int SHORT_SHIFT = 16;
+
+    private int internalAttributes = 0;
+    private int platform = PLATFORM_FAT;
+    private long externalAttributes = 0;
+    private Vector/*<ZipExtraField>*/ extraFields = null;
+    private String name = null;
+
+    /**
+     * Creates a new zip entry with the specified name.
+     * @param name the name of the entry
+     * @since 1.1
+     */
+    public ZipEntry(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     * @param entry the entry to get fields from
+     * @since 1.1
+     * @throws ZipException on error
+     */
+    public ZipEntry(java.util.zip.ZipEntry entry) throws ZipException {
+        super(entry);
+        byte[] extra = entry.getExtra();
+        if (extra != null) {
+            setExtraFields(ExtraFieldUtils.parse(extra));
+        } else {
+            // initializes extra data to an empty byte array
+            setExtra();
+        }
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified zip entry.
+     * @param entry the entry to get fields from
+     * @throws ZipException on error
+     * @since 1.1
+     */
+    public ZipEntry(ZipEntry entry) throws ZipException {
+        this((java.util.zip.ZipEntry) entry);
+        setInternalAttributes(entry.getInternalAttributes());
+        setExternalAttributes(entry.getExternalAttributes());
+        setExtraFields(entry.getExtraFields());
+    }
+
+    /**
+     * @since 1.9
+     */
+    protected ZipEntry() {
+        super("");
+    }
+
+    /**
+     * Overwrite clone.
+     * @return a cloned copy of this ZipEntry
+     * @since 1.1
+     */
+    public Object clone() {
+        ZipEntry e = (ZipEntry) super.clone();
+
+        e.extraFields = extraFields != null ? (Vector) extraFields.clone() : null;
+        e.setInternalAttributes(getInternalAttributes());
+        e.setExternalAttributes(getExternalAttributes());
+        e.setExtraFields(getExtraFields());
+        return e;
+    }
+
+    /**
+     * Retrieves the internal file attributes.
+     *
+     * @return the internal file attributes
+     * @since 1.1
+     */
+    public int getInternalAttributes() {
+        return internalAttributes;
+    }
+
+    /**
+     * Sets the internal file attributes.
+     * @param value an <code>int</code> value
+     * @since 1.1
+     */
+    public void setInternalAttributes(int value) {
+        internalAttributes = value;
+    }
+
+    /**
+     * Retrieves the external file attributes.
+     * @return the external file attributes
+     * @since 1.1
+     */
+    public long getExternalAttributes() {
+        return externalAttributes;
+    }
+
+    /**
+     * Sets the external file attributes.
+     * @param value an <code>long</code> value
+     * @since 1.1
+     */
+    public void setExternalAttributes(long value) {
+        externalAttributes = value;
+    }
+
+    /**
+     * Sets Unix permissions in a way that is understood by Info-Zip's
+     * unzip command.
+     * @param mode an <code>int</code> value
+     * @since Ant 1.5.2
+     */
+    public void setUnixMode(int mode) {
+        // CheckStyle:MagicNumberCheck OFF - no point
+        setExternalAttributes((mode << 16)
+                              // MS-DOS read-only attribute
+                              | ((mode & 0200) == 0 ? 1 : 0)
+                              // MS-DOS directory flag
+                              | (isDirectory() ? 0x10 : 0));
+        // CheckStyle:MagicNumberCheck ON
+        platform = PLATFORM_UNIX;
+    }
+
+    /**
+     * Unix permission.
+     * @return the unix permissions
+     * @since Ant 1.6
+     */
+    public int getUnixMode() {
+        return (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK);
+    }
+
+    /**
+     * Platform specification to put into the &quot;version made
+     * by&quot; part of the central file header.
+     *
+     * @return 0 (MS-DOS FAT) unless {@link #setUnixMode setUnixMode}
+     * has been called, in which case 3 (Unix) will be returned.
+     *
+     * @since Ant 1.5.2
+     */
+    public int getPlatform() {
+        return platform;
+    }
+
+    /**
+     * Set the platform (UNIX or FAT).
+     * @param platform an <code>int</code> value - 0 is FAT, 3 is UNIX
+     * @since 1.9
+     */
+    protected void setPlatform(int platform) {
+        this.platform = platform;
+    }
+
+    /**
+     * Replaces all currently attached extra fields with the new array.
+     * @param fields an array of extra fields
+     * @since 1.1
+     */
+    public void setExtraFields(ZipExtraField[] fields) {
+        extraFields = new Vector();
+        for (int i = 0; i < fields.length; i++) {
+            extraFields.addElement(fields[i]);
+        }
+        setExtra();
+    }
+
+    /**
+     * Retrieves extra fields.
+     * @return an array of the extra fields
+     * @since 1.1
+     */
+    public ZipExtraField[] getExtraFields() {
+        if (extraFields == null) {
+            return new ZipExtraField[0];
+        }
+        ZipExtraField[] result = new ZipExtraField[extraFields.size()];
+        extraFields.copyInto(result);
+        return result;
+    }
+
+    /**
+     * Adds an extra fields - replacing an already present extra field
+     * of the same type.
+     * @param ze an extra field
+     * @since 1.1
+     */
+    public void addExtraField(ZipExtraField ze) {
+        if (extraFields == null) {
+            extraFields = new Vector();
+        }
+        ZipShort type = ze.getHeaderId();
+        boolean done = false;
+        for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
+            if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
+                extraFields.setElementAt(ze, i);
+                done = true;
+            }
+        }
+        if (!done) {
+            extraFields.addElement(ze);
+        }
+        setExtra();
+    }
+
+    /**
+     * Remove an extra fields.
+     * @param type the type of extra field to remove
+     * @since 1.1
+     */
+    public void removeExtraField(ZipShort type) {
+        if (extraFields == null) {
+            extraFields = new Vector();
+        }
+        boolean done = false;
+        for (int i = 0, fieldsSize = extraFields.size(); !done && i < fieldsSize; i++) {
+            if (((ZipExtraField) extraFields.elementAt(i)).getHeaderId().equals(type)) {
+                extraFields.removeElementAt(i);
+                done = true;
+            }
+        }
+        if (!done) {
+            throw new java.util.NoSuchElementException();
+        }
+        setExtra();
+    }
+
+    /**
+     * Throws an Exception if extra data cannot be parsed into extra fields.
+     * @param extra an array of bytes to be parsed into extra fields
+     * @throws RuntimeException if the bytes cannot be parsed
+     * @since 1.1
+     * @throws RuntimeException on error
+     */
+    public void setExtra(byte[] extra) throws RuntimeException {
+        try {
+            setExtraFields(ExtraFieldUtils.parse(extra));
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * Unfortunately {@link java.util.zip.ZipOutputStream
+     * java.util.zip.ZipOutputStream} seems to access the extra data
+     * directly, so overriding getExtra doesn't help - we need to
+     * modify super's data directly.
+     *
+     * @since 1.1
+     */
+    protected void setExtra() {
+        super.setExtra(ExtraFieldUtils.mergeLocalFileDataData(getExtraFields()));
+    }
+
+    /**
+     * Retrieves the extra data for the local file data.
+     * @return the extra data for local file
+     * @since 1.1
+     */
+    public byte[] getLocalFileDataExtra() {
+        byte[] extra = getExtra();
+        return extra != null ? extra : new byte[0];
+    }
+
+    /**
+     * Retrieves the extra data for the central directory.
+     * @return the central directory extra data
+     * @since 1.1
+     */
+    public byte[] getCentralDirectoryExtra() {
+        return ExtraFieldUtils.mergeCentralDirectoryData(getExtraFields());
+    }
+
+    /**
+     * Make this class work in JDK 1.1 like a 1.2 class.
+     *
+     * <p>This either stores the size for later usage or invokes
+     * setCompressedSize via reflection.</p>
+     * @param size the size to use
+     * @deprecated since 1.7.
+     *             Use setCompressedSize directly.
+     * @since 1.2
+     */
+    public void setComprSize(long size) {
+        setCompressedSize(size);
+    }
+
+    /**
+     * Get the name of the entry.
+     * @return the entry name
+     * @since 1.9
+     */
+    public String getName() {
+        return name == null ? super.getName() : name;
+    }
+
+    /**
+     * Is this entry a directory?
+     * @return true if the entry is a directory
+     * @since 1.10
+     */
+    public boolean isDirectory() {
+        return getName().endsWith("/");
+    }
+
+    /**
+     * Set the name of the entry.
+     * @param name the name to use
+     */
+    protected void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get the hashCode of the entry.
+     * This uses the name as the hashcode.
+     * @return a hashcode.
+     * @since Ant 1.7
+     */
+    public int hashCode() {
+        // this method has severe consequences on performance. We cannot rely
+        // on the super.hashCode() method since super.getName() always return
+        // the empty string in the current implemention (there's no setter)
+        // so it is basically draining the performance of a hashmap lookup
+        return getName().hashCode();
+    }
+
+    /**
+     * The equality method. In this case, the implementation returns 'this == o'
+     * which is basically the equals method of the Object class.
+     * @param o the object to compare to
+     * @return true if this object is the same as <code>o</code>
+     * @since Ant 1.7
+     */
+    public boolean equals(Object o) {
+        return (this == o);
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipExtraField.java b/trunk/src/main/org/apache/tools/zip/ZipExtraField.java
new file mode 100644
index 0000000..622ff17
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipExtraField.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.zip.ZipException;
+
+/**
+ * General format of extra field data.
+ *
+ * <p>Extra fields usually appear twice per file, once in the local
+ * file data and once in the central directory.  Usually they are the
+ * same, but they don't have to be.  {@link
+ * java.util.zip.ZipOutputStream java.util.zip.ZipOutputStream} will
+ * only use the local file data in both places.</p>
+ *
+ */
+public interface ZipExtraField {
+
+    /**
+     * The Header-ID.
+     * @return the header id
+     * @since 1.1
+     */
+    ZipShort getHeaderId();
+
+    /**
+     * Length of the extra field in the local file data - without
+     * Header-ID or length specifier.
+     * @return the length of the field in the local file data
+     * @since 1.1
+     */
+    ZipShort getLocalFileDataLength();
+
+    /**
+     * Length of the extra field in the central directory - without
+     * Header-ID or length specifier.
+     * @return the length of the field in the central directory
+     * @since 1.1
+     */
+    ZipShort getCentralDirectoryLength();
+
+    /**
+     * The actual data to put into local file data - without Header-ID
+     * or length specifier.
+     * @return the data
+     * @since 1.1
+     */
+    byte[] getLocalFileDataData();
+
+    /**
+     * The actual data to put central directory - without Header-ID or
+     * length specifier.
+     * @return the data
+     * @since 1.1
+     */
+    byte[] getCentralDirectoryData();
+
+    /**
+     * Populate data from this array as if it was in local file data.
+     * @param data an array of bytes
+     * @param offset the start offset
+     * @param length the number of bytes in the array from offset
+     *
+     * @since 1.1
+     * @throws ZipException on error
+     */
+    void parseFromLocalFileData(byte[] data, int offset, int length)
+        throws ZipException;
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipFile.java b/trunk/src/main/org/apache/tools/zip/ZipFile.java
new file mode 100644
index 0000000..4e7edcf
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipFile.java
@@ -0,0 +1,579 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+import java.util.zip.ZipException;
+
+/**
+ * Replacement for <code>java.util.ZipFile</code>.
+ *
+ * <p>This class adds support for file name encodings other than UTF-8
+ * (which is required to work on ZIP files created by native zip tools
+ * and is able to skip a preamble like the one found in self
+ * extracting archives.  Furthermore it returns instances of
+ * <code>org.apache.tools.zip.ZipEntry</code> instead of
+ * <code>java.util.zip.ZipEntry</code>.</p>
+ *
+ * <p>It doesn't extend <code>java.util.zip.ZipFile</code> as it would
+ * have to reimplement all methods anyway.  Like
+ * <code>java.util.ZipFile</code>, it uses RandomAccessFile under the
+ * covers and supports compressed and uncompressed entries.</p>
+ *
+ * <p>The method signatures mimic the ones of
+ * <code>java.util.zip.ZipFile</code>, with a couple of exceptions:
+ *
+ * <ul>
+ *   <li>There is no getName method.</li>
+ *   <li>entries has been renamed to getEntries.</li>
+ *   <li>getEntries and getEntry return
+ *   <code>org.apache.tools.zip.ZipEntry</code> instances.</li>
+ *   <li>close is allowed to throw IOException.</li>
+ * </ul>
+ *
+ */
+public class ZipFile {
+    private static final int HASH_SIZE = 509;
+    private static final int SHORT     =   2;
+    private static final int WORD      =   4;
+    private static final int NIBLET_MASK = 0x0f;
+    private static final int BYTE_SHIFT = 8;
+    private static final int POS_0 = 0;
+    private static final int POS_1 = 1;
+    private static final int POS_2 = 2;
+    private static final int POS_3 = 3;
+
+    /**
+     * Maps ZipEntrys to Longs, recording the offsets of the local
+     * file headers.
+     */
+    private Hashtable entries = new Hashtable(HASH_SIZE);
+
+    /**
+     * Maps String to ZipEntrys, name -> actual entry.
+     */
+    private Hashtable nameMap = new Hashtable(HASH_SIZE);
+
+    private static final class OffsetEntry {
+        private long headerOffset = -1;
+        private long dataOffset = -1;
+    }
+
+    /**
+     * The encoding to use for filenames and the file comment.
+     *
+     * <p>For a list of possible values see <a
+     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+     * Defaults to the platform's default character encoding.</p>
+     */
+    private String encoding = null;
+
+    /**
+     * The actual data source.
+     */
+    private RandomAccessFile archive;
+
+    /**
+     * Opens the given file for reading, assuming the platform's
+     * native encoding for file names.
+     *
+     * @param f the archive.
+     *
+     * @throws IOException if an error occurs while reading the file.
+     */
+    public ZipFile(File f) throws IOException {
+        this(f, null);
+    }
+
+    /**
+     * Opens the given file for reading, assuming the platform's
+     * native encoding for file names.
+     *
+     * @param name name of the archive.
+     *
+     * @throws IOException if an error occurs while reading the file.
+     */
+    public ZipFile(String name) throws IOException {
+        this(new File(name), null);
+    }
+
+    /**
+     * Opens the given file for reading, assuming the specified
+     * encoding for file names.
+     *
+     * @param name name of the archive.
+     * @param encoding the encoding to use for file names
+     *
+     * @throws IOException if an error occurs while reading the file.
+     */
+    public ZipFile(String name, String encoding) throws IOException {
+        this(new File(name), encoding);
+    }
+
+    /**
+     * Opens the given file for reading, assuming the specified
+     * encoding for file names.
+     *
+     * @param f the archive.
+     * @param encoding the encoding to use for file names
+     *
+     * @throws IOException if an error occurs while reading the file.
+     */
+    public ZipFile(File f, String encoding) throws IOException {
+        this.encoding = encoding;
+        archive = new RandomAccessFile(f, "r");
+        try {
+            populateFromCentralDirectory();
+            resolveLocalFileHeaderData();
+        } catch (IOException e) {
+            try {
+                archive.close();
+            } catch (IOException e2) {
+                // swallow, throw the original exception instead
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * The encoding to use for filenames and the file comment.
+     *
+     * @return null if using the platform's default character encoding.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Closes the archive.
+     * @throws IOException if an error occurs closing the archive.
+     */
+    public void close() throws IOException {
+        archive.close();
+    }
+
+    /**
+     * close a zipfile quietly; throw no io fault, do nothing
+     * on a null parameter
+     * @param zipfile file to close, can be null
+     */
+    public static void closeQuietly(ZipFile zipfile) {
+        if (zipfile != null) {
+            try {
+                zipfile.close();
+            } catch (IOException e) {
+                //ignore
+            }
+        }
+    }
+
+    /**
+     * Returns all entries.
+     * @return all entries as {@link ZipEntry} instances
+     */
+    public Enumeration getEntries() {
+        return entries.keys();
+    }
+
+    /**
+     * Returns a named entry - or <code>null</code> if no entry by
+     * that name exists.
+     * @param name name of the entry.
+     * @return the ZipEntry corresponding to the given name - or
+     * <code>null</code> if not present.
+     */
+    public ZipEntry getEntry(String name) {
+        return (ZipEntry) nameMap.get(name);
+    }
+
+    /**
+     * Returns an InputStream for reading the contents of the given entry.
+     * @param ze the entry to get the stream for.
+     * @return a stream to read the entry from.
+     * @throws IOException if unable to create an input stream from the zipenty
+     * @throws ZipException if the zipentry has an unsupported compression method
+     */
+    public InputStream getInputStream(ZipEntry ze)
+        throws IOException, ZipException {
+        OffsetEntry offsetEntry = (OffsetEntry) entries.get(ze);
+        if (offsetEntry == null) {
+            return null;
+        }
+        long start = offsetEntry.dataOffset;
+        BoundedInputStream bis =
+            new BoundedInputStream(start, ze.getCompressedSize());
+        switch (ze.getMethod()) {
+            case ZipEntry.STORED:
+                return bis;
+            case ZipEntry.DEFLATED:
+                bis.addDummy();
+                return new InflaterInputStream(bis, new Inflater(true));
+            default:
+                throw new ZipException("Found unsupported compression method "
+                                       + ze.getMethod());
+        }
+    }
+
+    private static final int CFH_LEN =
+        /* version made by                 */ SHORT
+        /* version needed to extract       */ + SHORT
+        /* general purpose bit flag        */ + SHORT
+        /* compression method              */ + SHORT
+        /* last mod file time              */ + SHORT
+        /* last mod file date              */ + SHORT
+        /* crc-32                          */ + WORD
+        /* compressed size                 */ + WORD
+        /* uncompressed size               */ + WORD
+        /* filename length                 */ + SHORT
+        /* extra field length              */ + SHORT
+        /* file comment length             */ + SHORT
+        /* disk number start               */ + SHORT
+        /* internal file attributes        */ + SHORT
+        /* external file attributes        */ + WORD
+        /* relative offset of local header */ + WORD;
+
+    /**
+     * Reads the central directory of the given archive and populates
+     * the internal tables with ZipEntry instances.
+     *
+     * <p>The ZipEntrys will know all data that can be obtained from
+     * the central directory alone, but not the data that requires the
+     * local file header or additional data to be read.</p>
+     */
+    private void populateFromCentralDirectory()
+        throws IOException {
+        positionAtCentralDirectory();
+
+        byte[] cfh = new byte[CFH_LEN];
+
+        byte[] signatureBytes = new byte[WORD];
+        archive.readFully(signatureBytes);
+        long sig = ZipLong.getValue(signatureBytes);
+        final long cfhSig = ZipLong.getValue(ZipOutputStream.CFH_SIG);
+        while (sig == cfhSig) {
+            archive.readFully(cfh);
+            int off = 0;
+            ZipEntry ze = new ZipEntry();
+
+            int versionMadeBy = ZipShort.getValue(cfh, off);
+            off += SHORT;
+            ze.setPlatform((versionMadeBy >> BYTE_SHIFT) & NIBLET_MASK);
+
+            off += WORD; // skip version info and general purpose byte
+
+            ze.setMethod(ZipShort.getValue(cfh, off));
+            off += SHORT;
+
+            // FIXME this is actually not very cpu cycles friendly as we are converting from
+            // dos to java while the underlying Sun implementation will convert
+            // from java to dos time for internal storage...
+            long time = dosToJavaTime(ZipLong.getValue(cfh, off));
+            ze.setTime(time);
+            off += WORD;
+
+            ze.setCrc(ZipLong.getValue(cfh, off));
+            off += WORD;
+
+            ze.setCompressedSize(ZipLong.getValue(cfh, off));
+            off += WORD;
+
+            ze.setSize(ZipLong.getValue(cfh, off));
+            off += WORD;
+
+            int fileNameLen = ZipShort.getValue(cfh, off);
+            off += SHORT;
+
+            int extraLen = ZipShort.getValue(cfh, off);
+            off += SHORT;
+
+            int commentLen = ZipShort.getValue(cfh, off);
+            off += SHORT;
+
+            off += SHORT; // disk number
+
+            ze.setInternalAttributes(ZipShort.getValue(cfh, off));
+            off += SHORT;
+
+            ze.setExternalAttributes(ZipLong.getValue(cfh, off));
+            off += WORD;
+
+            byte[] fileName = new byte[fileNameLen];
+            archive.readFully(fileName);
+            ze.setName(getString(fileName));
+
+
+            // LFH offset,
+            OffsetEntry offset = new OffsetEntry();
+            offset.headerOffset = ZipLong.getValue(cfh, off);
+            // data offset will be filled later
+            entries.put(ze, offset);
+
+            nameMap.put(ze.getName(), ze);
+
+            archive.skipBytes(extraLen);
+
+            byte[] comment = new byte[commentLen];
+            archive.readFully(comment);
+            ze.setComment(getString(comment));
+
+            archive.readFully(signatureBytes);
+            sig = ZipLong.getValue(signatureBytes);
+        }
+    }
+
+    private static final int MIN_EOCD_SIZE =
+        /* end of central dir signature    */ WORD
+        /* number of this disk             */ + SHORT
+        /* number of the disk with the     */
+        /* start of the central directory  */ + SHORT
+        /* total number of entries in      */
+        /* the central dir on this disk    */ + SHORT
+        /* total number of entries in      */
+        /* the central dir                 */ + SHORT
+        /* size of the central directory   */ + WORD
+        /* offset of start of central      */
+        /* directory with respect to       */
+        /* the starting disk number        */ + WORD
+        /* zipfile comment length          */ + SHORT;
+
+    private static final int CFD_LOCATOR_OFFSET =
+        /* end of central dir signature    */ WORD
+        /* number of this disk             */ + SHORT
+        /* number of the disk with the     */
+        /* start of the central directory  */ + SHORT
+        /* total number of entries in      */
+        /* the central dir on this disk    */ + SHORT
+        /* total number of entries in      */
+        /* the central dir                 */ + SHORT
+        /* size of the central directory   */ + WORD;
+
+    /**
+     * Searches for the &quot;End of central dir record&quot;, parses
+     * it and positions the stream at the first central directory
+     * record.
+     */
+    private void positionAtCentralDirectory()
+        throws IOException {
+        boolean found = false;
+        long off = archive.length() - MIN_EOCD_SIZE;
+        if (off >= 0) {
+            archive.seek(off);
+            byte[] sig = ZipOutputStream.EOCD_SIG;
+            int curr = archive.read();
+            while (curr != -1) {
+                if (curr == sig[POS_0]) {
+                    curr = archive.read();
+                    if (curr == sig[POS_1]) {
+                        curr = archive.read();
+                        if (curr == sig[POS_2]) {
+                            curr = archive.read();
+                            if (curr == sig[POS_3]) {
+                                found = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+                archive.seek(--off);
+                curr = archive.read();
+            }
+        }
+        if (!found) {
+            throw new ZipException("archive is not a ZIP archive");
+        }
+        archive.seek(off + CFD_LOCATOR_OFFSET);
+        byte[] cfdOffset = new byte[WORD];
+        archive.readFully(cfdOffset);
+        archive.seek(ZipLong.getValue(cfdOffset));
+    }
+
+    /**
+     * Number of bytes in local file header up to the &quot;length of
+     * filename&quot; entry.
+     */
+    private static final long LFH_OFFSET_FOR_FILENAME_LENGTH =
+        /* local file header signature     */ WORD
+        /* version needed to extract       */ + SHORT
+        /* general purpose bit flag        */ + SHORT
+        /* compression method              */ + SHORT
+        /* last mod file time              */ + SHORT
+        /* last mod file date              */ + SHORT
+        /* crc-32                          */ + WORD
+        /* compressed size                 */ + WORD
+        /* uncompressed size               */ + WORD;
+
+    /**
+     * Walks through all recorded entries and adds the data available
+     * from the local file header.
+     *
+     * <p>Also records the offsets for the data to read from the
+     * entries.</p>
+     */
+    private void resolveLocalFileHeaderData()
+        throws IOException {
+        Enumeration e = getEntries();
+        while (e.hasMoreElements()) {
+            ZipEntry ze = (ZipEntry) e.nextElement();
+            OffsetEntry offsetEntry = (OffsetEntry) entries.get(ze);
+            long offset = offsetEntry.headerOffset;
+            archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH);
+            byte[] b = new byte[SHORT];
+            archive.readFully(b);
+            int fileNameLen = ZipShort.getValue(b);
+            archive.readFully(b);
+            int extraFieldLen = ZipShort.getValue(b);
+            archive.skipBytes(fileNameLen);
+            byte[] localExtraData = new byte[extraFieldLen];
+            archive.readFully(localExtraData);
+            ze.setExtra(localExtraData);
+            /*dataOffsets.put(ze,
+                            new Long(offset + LFH_OFFSET_FOR_FILENAME_LENGTH
+                                     + SHORT + SHORT + fileNameLen + extraFieldLen));
+            */
+            offsetEntry.dataOffset = offset + LFH_OFFSET_FOR_FILENAME_LENGTH
+                                     + SHORT + SHORT + fileNameLen + extraFieldLen;
+        }
+    }
+
+    /**
+     * Convert a DOS date/time field to a Date object.
+     *
+     * @param zipDosTime contains the stored DOS time.
+     * @return a Date instance corresponding to the given time.
+     */
+    protected static Date fromDosTime(ZipLong zipDosTime) {
+        long dosTime = zipDosTime.getValue();
+        return new Date(dosToJavaTime(dosTime));
+    }
+
+    /*
+     * Converts DOS time to Java time (number of milliseconds since epoch).
+     */
+    private static long dosToJavaTime(long dosTime) {
+        Calendar cal = Calendar.getInstance();
+        // CheckStyle:MagicNumberCheck OFF - no point
+        cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980);
+        cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1);
+        cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f);
+        cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f);
+        cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f);
+        cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e);
+        // CheckStyle:MagicNumberCheck ON
+        return cal.getTime().getTime();
+    }
+
+
+    /**
+     * Retrieve a String from the given bytes using the encoding set
+     * for this ZipFile.
+     *
+     * @param bytes the byte array to transform
+     * @return String obtained by using the given encoding
+     * @throws ZipException if the encoding cannot be recognized.
+     */
+    protected String getString(byte[] bytes) throws ZipException {
+        if (encoding == null) {
+            return new String(bytes);
+        } else {
+            try {
+                return new String(bytes, encoding);
+            } catch (UnsupportedEncodingException uee) {
+                throw new ZipException(uee.getMessage());
+            }
+        }
+    }
+
+    /**
+     * InputStream that delegates requests to the underlying
+     * RandomAccessFile, making sure that only bytes from a certain
+     * range can be read.
+     */
+    private class BoundedInputStream extends InputStream {
+        private long remaining;
+        private long loc;
+        private boolean addDummyByte = false;
+
+        BoundedInputStream(long start, long remaining) {
+            this.remaining = remaining;
+            loc = start;
+        }
+
+        public int read() throws IOException {
+            if (remaining-- <= 0) {
+                if (addDummyByte) {
+                    addDummyByte = false;
+                    return 0;
+                }
+                return -1;
+            }
+            synchronized (archive) {
+                archive.seek(loc++);
+                return archive.read();
+            }
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (remaining <= 0) {
+                if (addDummyByte) {
+                    addDummyByte = false;
+                    b[off] = 0;
+                    return 1;
+                }
+                return -1;
+            }
+
+            if (len <= 0) {
+                return 0;
+            }
+
+            if (len > remaining) {
+                len = (int) remaining;
+            }
+            int ret = -1;
+            synchronized (archive) {
+                archive.seek(loc);
+                ret = archive.read(b, off, len);
+            }
+            if (ret > 0) {
+                loc += ret;
+                remaining -= ret;
+            }
+            return ret;
+        }
+
+        /**
+         * Inflater needs an extra dummy byte for nowrap - see
+         * Inflater's javadocs.
+         */
+        void addDummy() {
+            addDummyByte = true;
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipLong.java b/trunk/src/main/org/apache/tools/zip/ZipLong.java
new file mode 100644
index 0000000..677f954
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipLong.java
@@ -0,0 +1,150 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+/**
+ * Utility class that represents a four byte integer with conversion
+ * rules for the big endian byte order of ZIP files.
+ *
+ */
+public final class ZipLong implements Cloneable {
+
+    private static final int WORD = 4;
+    private static final int BYTE_BIT_SIZE = 8;
+    private static final int BYTE_MASK = 0xFF;
+
+    private static final int BYTE_1 = 1;
+    private static final int BYTE_1_MASK = 0xFF00;
+    private static final int BYTE_1_SHIFT = 8;
+
+    private static final int BYTE_2 = 2;
+    private static final int BYTE_2_MASK = 0xFF0000;
+    private static final int BYTE_2_SHIFT = 16;
+
+    private static final int BYTE_3 = 3;
+    private static final long BYTE_3_MASK = 0xFF000000L;
+    private static final int BYTE_3_SHIFT = 24;
+
+    private long value;
+
+    /**
+     * Create instance from a number.
+     * @param value the long to store as a ZipLong
+     * @since 1.1
+     */
+    public ZipLong(long value) {
+        this.value = value;
+    }
+
+    /**
+     * Create instance from bytes.
+     * @param bytes the bytes to store as a ZipLong
+     * @since 1.1
+     */
+    public ZipLong (byte[] bytes) {
+        this(bytes, 0);
+    }
+
+    /**
+     * Create instance from the four bytes starting at offset.
+     * @param bytes the bytes to store as a ZipLong
+     * @param offset the offset to start
+     * @since 1.1
+     */
+    public ZipLong (byte[] bytes, int offset) {
+        value = ZipLong.getValue(bytes, offset);
+    }
+
+    /**
+     * Get value as four bytes in big endian byte order.
+     * @since 1.1
+     * @return value as four bytes in big endian order
+     */
+    public byte[] getBytes() {
+        return ZipLong.getBytes(value);
+    }
+
+    /**
+     * Get value as Java long.
+     * @since 1.1
+     * @return value as a long
+     */
+    public long getValue() {
+        return value;
+    }
+
+    /**
+     * Get value as four bytes in big endian byte order.
+     * @param value the value to convert
+     * @return value as four bytes in big endian byte order
+     */
+    public static byte[] getBytes(long value) {
+        byte[] result = new byte[WORD];
+        result[0] = (byte) ((value & BYTE_MASK));
+        result[BYTE_1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
+        result[BYTE_2] = (byte) ((value & BYTE_2_MASK) >> BYTE_2_SHIFT);
+        result[BYTE_3] = (byte) ((value & BYTE_3_MASK) >> BYTE_3_SHIFT);
+        return result;
+    }
+
+    /**
+     * Helper method to get the value as a Java long from four bytes starting at given array offset
+     * @param bytes the array of bytes
+     * @param offset the offset to start
+     * @return the correspondanding Java long value
+     */
+    public static long getValue(byte[] bytes, int offset) {
+        long value = (bytes[offset + BYTE_3] << BYTE_3_SHIFT) & BYTE_3_MASK;
+        value += (bytes[offset + BYTE_2] << BYTE_2_SHIFT) & BYTE_2_MASK;
+        value += (bytes[offset + BYTE_1] << BYTE_1_SHIFT) & BYTE_1_MASK;
+        value += (bytes[offset] & BYTE_MASK);
+        return value;
+    }
+
+    /**
+     * Helper method to get the value as a Java long from a four-byte array
+     * @param bytes the array of bytes
+     * @return the correspondanding Java long value
+     */
+    public static long getValue(byte[] bytes) {
+        return getValue(bytes, 0);
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     * @param o an object to compare
+     * @return true if the objects are equal
+     * @since 1.1
+     */
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof ZipLong)) {
+            return false;
+        }
+        return value == ((ZipLong) o).getValue();
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     * @return the value stored in the ZipLong
+     * @since 1.1
+     */
+    public int hashCode() {
+        return (int) value;
+    }
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipOutputStream.java b/trunk/src/main/org/apache/tools/zip/ZipOutputStream.java
new file mode 100644
index 0000000..7657285
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipOutputStream.java
@@ -0,0 +1,918 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.ZipException;
+
+/**
+ * Reimplementation of {@link java.util.zip.ZipOutputStream
+ * java.util.zip.ZipOutputStream} that does handle the extended
+ * functionality of this package, especially internal/external file
+ * attributes and extra fields with different layouts for local file
+ * data and central directory entries.
+ *
+ * <p>This class will try to use {@link java.io.RandomAccessFile
+ * RandomAccessFile} when you know that the output is going to go to a
+ * file.</p>
+ *
+ * <p>If RandomAccessFile cannot be used, this implementation will use
+ * a Data Descriptor to store size and CRC information for {@link
+ * #DEFLATED DEFLATED} entries, this means, you don't need to
+ * calculate them yourself.  Unfortunately this is not possible for
+ * the {@link #STORED STORED} method, here setting the CRC and
+ * uncompressed size information is required before {@link
+ * #putNextEntry putNextEntry} can be called.</p>
+ *
+ */
+public class ZipOutputStream extends FilterOutputStream {
+
+    private static final int BYTE_MASK = 0xFF;
+    private static final int SHORT = 2;
+    private static final int WORD = 4;
+    private static final int BUFFER_SIZE = 512;
+
+    /**
+     * Compression method for deflated entries.
+     *
+     * @since 1.1
+     */
+    public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED;
+
+    /**
+     * Default compression level for deflated entries.
+     *
+     * @since Ant 1.7
+     */
+    public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION;
+
+    /**
+     * Compression method for stored entries.
+     *
+     * @since 1.1
+     */
+    public static final int STORED = java.util.zip.ZipEntry.STORED;
+
+    /**
+     * Current entry.
+     *
+     * @since 1.1
+     */
+    private ZipEntry entry;
+
+    /**
+     * The file comment.
+     *
+     * @since 1.1
+     */
+    private String comment = "";
+
+    /**
+     * Compression level for next entry.
+     *
+     * @since 1.1
+     */
+    private int level = DEFAULT_COMPRESSION;
+
+    /**
+     * Has the compression level changed when compared to the last
+     * entry?
+     *
+     * @since 1.5
+     */
+    private boolean hasCompressionLevelChanged = false;
+
+    /**
+     * Default compression method for next entry.
+     *
+     * @since 1.1
+     */
+    private int method = java.util.zip.ZipEntry.DEFLATED;
+
+    /**
+     * List of ZipEntries written so far.
+     *
+     * @since 1.1
+     */
+    private Vector entries = new Vector();
+
+    /**
+     * CRC instance to avoid parsing DEFLATED data twice.
+     *
+     * @since 1.1
+     */
+    private CRC32 crc = new CRC32();
+
+    /**
+     * Count the bytes written to out.
+     *
+     * @since 1.1
+     */
+    private long written = 0;
+
+    /**
+     * Data for local header data
+     *
+     * @since 1.1
+     */
+    private long dataStart = 0;
+
+    /**
+     * Offset for CRC entry in the local file header data for the
+     * current entry starts here.
+     *
+     * @since 1.15
+     */
+    private long localDataStart = 0;
+
+    /**
+     * Start of central directory.
+     *
+     * @since 1.1
+     */
+    private long cdOffset = 0;
+
+    /**
+     * Length of central directory.
+     *
+     * @since 1.1
+     */
+    private long cdLength = 0;
+
+    /**
+     * Helper, a 0 as ZipShort.
+     *
+     * @since 1.1
+     */
+    private static final byte[] ZERO = {0, 0};
+
+    /**
+     * Helper, a 0 as ZipLong.
+     *
+     * @since 1.1
+     */
+    private static final byte[] LZERO = {0, 0, 0, 0};
+
+    /**
+     * Holds the offsets of the LFH starts for each entry.
+     *
+     * @since 1.1
+     */
+    private Hashtable offsets = new Hashtable();
+
+    /**
+     * The encoding to use for filenames and the file comment.
+     *
+     * <p>For a list of possible values see <a
+     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+     * Defaults to the platform's default character encoding.</p>
+     *
+     * @since 1.3
+     */
+    private String encoding = null;
+
+    // CheckStyle:VisibilityModifier OFF - bc
+
+    /**
+     * This Deflater object is used for output.
+     *
+     * <p>This attribute is only protected to provide a level of API
+     * backwards compatibility.  This class used to extend {@link
+     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
+     * Revision 1.13.</p>
+     *
+     * @since 1.14
+     */
+    protected Deflater def = new Deflater(level, true);
+
+    /**
+     * This buffer servers as a Deflater.
+     *
+     * <p>This attribute is only protected to provide a level of API
+     * backwards compatibility.  This class used to extend {@link
+     * java.util.zip.DeflaterOutputStream DeflaterOutputStream} up to
+     * Revision 1.13.</p>
+     *
+     * @since 1.14
+     */
+    protected byte[] buf = new byte[BUFFER_SIZE];
+
+    // CheckStyle:VisibilityModifier ON
+
+    /**
+     * Optional random access output.
+     *
+     * @since 1.14
+     */
+    private RandomAccessFile raf = null;
+
+    /**
+     * Creates a new ZIP OutputStream filtering the underlying stream.
+     * @param out the outputstream to zip
+     * @since 1.1
+     */
+    public ZipOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    /**
+     * Creates a new ZIP OutputStream writing to a File.  Will use
+     * random access if possible.
+     * @param file the file to zip to
+     * @since 1.14
+     * @throws IOException on error
+     */
+    public ZipOutputStream(File file) throws IOException {
+        super(null);
+
+        try {
+            raf = new RandomAccessFile(file, "rw");
+            raf.setLength(0);
+        } catch (IOException e) {
+            if (raf != null) {
+                try {
+                    raf.close();
+                } catch (IOException inner) {
+                    // ignore
+                }
+                raf = null;
+            }
+            out = new FileOutputStream(file);
+        }
+    }
+
+    /**
+     * This method indicates whether this archive is writing to a seekable stream (i.e., to a random
+     * access file).
+     *
+     * <p>For seekable streams, you don't need to calculate the CRC or
+     * uncompressed size for {@link #STORED} entries before
+     * invoking {@link #putNextEntry}.
+     * @return true if seekable
+     * @since 1.17
+     */
+    public boolean isSeekable() {
+        return raf != null;
+    }
+
+    /**
+     * The encoding to use for filenames and the file comment.
+     *
+     * <p>For a list of possible values see <a
+     * href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html</a>.
+     * Defaults to the platform's default character encoding.</p>
+     * @param encoding the encoding value
+     * @since 1.3
+     */
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    /**
+     * The encoding to use for filenames and the file comment.
+     *
+     * @return null if using the platform's default character encoding.
+     *
+     * @since 1.3
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Finishs writing the contents and closes this as well as the
+     * underlying stream.
+     *
+     * @since 1.1
+     * @throws IOException on error
+     */
+    public void finish() throws IOException {
+        closeEntry();
+        cdOffset = written;
+        for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) {
+            writeCentralFileHeader((ZipEntry) entries.elementAt(i));
+        }
+        cdLength = written - cdOffset;
+        writeCentralDirectoryEnd();
+        offsets.clear();
+        entries.removeAllElements();
+    }
+
+    /**
+     * Writes all necessary data for this entry.
+     *
+     * @since 1.1
+     * @throws IOException on error
+     */
+    public void closeEntry() throws IOException {
+        if (entry == null) {
+            return;
+        }
+
+        long realCrc = crc.getValue();
+        crc.reset();
+
+        if (entry.getMethod() == DEFLATED) {
+            def.finish();
+            while (!def.finished()) {
+                deflate();
+            }
+
+            entry.setSize(adjustToLong(def.getTotalIn()));
+            entry.setCompressedSize(adjustToLong(def.getTotalOut()));
+            entry.setCrc(realCrc);
+
+            def.reset();
+
+            written += entry.getCompressedSize();
+        } else if (raf == null) {
+            if (entry.getCrc() != realCrc) {
+                throw new ZipException("bad CRC checksum for entry "
+                                       + entry.getName() + ": "
+                                       + Long.toHexString(entry.getCrc())
+                                       + " instead of "
+                                       + Long.toHexString(realCrc));
+            }
+
+            if (entry.getSize() != written - dataStart) {
+                throw new ZipException("bad size for entry "
+                                       + entry.getName() + ": "
+                                       + entry.getSize()
+                                       + " instead of "
+                                       + (written - dataStart));
+            }
+        } else { /* method is STORED and we used RandomAccessFile */
+            long size = written - dataStart;
+
+            entry.setSize(size);
+            entry.setCompressedSize(size);
+            entry.setCrc(realCrc);
+        }
+
+        // If random access output, write the local file header containing
+        // the correct CRC and compressed/uncompressed sizes
+        if (raf != null) {
+            long save = raf.getFilePointer();
+
+            raf.seek(localDataStart);
+            writeOut(ZipLong.getBytes(entry.getCrc()));
+            writeOut(ZipLong.getBytes(entry.getCompressedSize()));
+            writeOut(ZipLong.getBytes(entry.getSize()));
+            raf.seek(save);
+        }
+
+        writeDataDescriptor(entry);
+        entry = null;
+    }
+
+    /**
+     * Begin writing next entry.
+     * @param ze the entry to write
+     * @since 1.1
+     * @throws IOException on error
+     */
+    public void putNextEntry(ZipEntry ze) throws IOException {
+        closeEntry();
+
+        entry = ze;
+        entries.addElement(entry);
+
+        if (entry.getMethod() == -1) { // not specified
+            entry.setMethod(method);
+        }
+
+        if (entry.getTime() == -1) { // not specified
+            entry.setTime(System.currentTimeMillis());
+        }
+
+        // Size/CRC not required if RandomAccessFile is used
+        if (entry.getMethod() == STORED && raf == null) {
+            if (entry.getSize() == -1) {
+                throw new ZipException("uncompressed size is required for"
+                                       + " STORED method when not writing to a"
+                                       + " file");
+            }
+            if (entry.getCrc() == -1) {
+                throw new ZipException("crc checksum is required for STORED"
+                                       + " method when not writing to a file");
+            }
+            entry.setCompressedSize(entry.getSize());
+        }
+
+        if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
+            def.setLevel(level);
+            hasCompressionLevelChanged = false;
+        }
+        writeLocalFileHeader(entry);
+    }
+
+    /**
+     * Set the file comment.
+     * @param comment the comment
+     * @since 1.1
+     */
+    public void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    /**
+     * Sets the compression level for subsequent entries.
+     *
+     * <p>Default is Deflater.DEFAULT_COMPRESSION.</p>
+     * @param level the compression level.
+     * @throws IllegalArgumentException if an invalid compression level is specified.
+     * @since 1.1
+     */
+    public void setLevel(int level) {
+        if (level < Deflater.DEFAULT_COMPRESSION
+            || level > Deflater.BEST_COMPRESSION) {
+            throw new IllegalArgumentException(
+                "Invalid compression level: " + level);
+        }
+        hasCompressionLevelChanged = (this.level != level);
+        this.level = level;
+    }
+
+    /**
+     * Sets the default compression method for subsequent entries.
+     *
+     * <p>Default is DEFLATED.</p>
+     * @param method an <code>int</code> from java.util.zip.ZipEntry
+     * @since 1.1
+     */
+    public void setMethod(int method) {
+        this.method = method;
+    }
+
+    /**
+     * Writes bytes to ZIP entry.
+     * @param b the byte array to write
+     * @param offset the start position to write from
+     * @param length the number of bytes to write
+     * @throws IOException on error
+     */
+    public void write(byte[] b, int offset, int length) throws IOException {
+        if (entry.getMethod() == DEFLATED) {
+            if (length > 0) {
+                if (!def.finished()) {
+                    def.setInput(b, offset, length);
+                    while (!def.needsInput()) {
+                        deflate();
+                    }
+                }
+            }
+        } else {
+            writeOut(b, offset, length);
+            written += length;
+        }
+        crc.update(b, offset, length);
+    }
+
+    /**
+     * Writes a single byte to ZIP entry.
+     *
+     * <p>Delegates to the three arg method.</p>
+     * @param b the byte to write
+     * @since 1.14
+     * @throws IOException on error
+     */
+    public void write(int b) throws IOException {
+        byte[] buff = new byte[1];
+        buff[0] = (byte) (b & BYTE_MASK);
+        write(buff, 0, 1);
+    }
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since 1.14
+     */
+    public void close() throws IOException {
+        finish();
+
+        if (raf != null) {
+            raf.close();
+        }
+        if (out != null) {
+            out.close();
+        }
+    }
+
+    /**
+     * Flushes this output stream and forces any buffered output bytes
+     * to be written out to the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since 1.14
+     */
+    public void flush() throws IOException {
+        if (out != null) {
+            out.flush();
+        }
+    }
+
+    /*
+     * Various ZIP constants
+     */
+    /**
+     * local file header signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] LFH_SIG = ZipLong.getBytes(0X04034B50L);
+    /**
+     * data descriptor signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] DD_SIG = ZipLong.getBytes(0X08074B50L);
+    /**
+     * central file header signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] CFH_SIG = ZipLong.getBytes(0X02014B50L);
+    /**
+     * end of central dir signature
+     *
+     * @since 1.1
+     */
+    protected static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L);
+
+    /**
+     * Writes next block of compressed data to the output stream.
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void deflate() throws IOException {
+        int len = def.deflate(buf, 0, buf.length);
+        if (len > 0) {
+            writeOut(buf, 0, len);
+        }
+    }
+
+    /**
+     * Writes the local file header entry
+     * @param ze the entry to write
+     * @throws IOException on error
+     *
+     * @since 1.1
+     */
+    protected void writeLocalFileHeader(ZipEntry ze) throws IOException {
+        offsets.put(ze, ZipLong.getBytes(written));
+
+        writeOut(LFH_SIG);
+        written += WORD;
+
+        //store method in local variable to prevent multiple method calls
+        final int zipMethod = ze.getMethod();
+
+        // version needed to extract
+        // general purpose bit flag
+        // CheckStyle:MagicNumber OFF
+        if (zipMethod == DEFLATED && raf == null) {
+            // requires version 2 as we are going to store length info
+            // in the data descriptor
+            writeOut(ZipShort.getBytes(20));
+
+            // bit3 set to signal, we use a data descriptor
+            writeOut(ZipShort.getBytes(8));
+        } else {
+            writeOut(ZipShort.getBytes(10));
+            writeOut(ZERO);
+        }
+        // CheckStyle:MagicNumber ON
+        written += WORD;
+
+        // compression method
+        writeOut(ZipShort.getBytes(zipMethod));
+        written += SHORT;
+
+        // last mod. time and date
+        writeOut(toDosTime(ze.getTime()));
+        written += WORD;
+
+        // CRC
+        // compressed length
+        // uncompressed length
+        localDataStart = written;
+        if (zipMethod == DEFLATED || raf != null) {
+            writeOut(LZERO);
+            writeOut(LZERO);
+            writeOut(LZERO);
+        } else {
+            writeOut(ZipLong.getBytes(ze.getCrc()));
+            writeOut(ZipLong.getBytes(ze.getSize()));
+            writeOut(ZipLong.getBytes(ze.getSize()));
+        }
+        // CheckStyle:MagicNumber OFF
+        written += 12;
+        // CheckStyle:MagicNumber ON
+
+        // file name length
+        byte[] name = getBytes(ze.getName());
+        writeOut(ZipShort.getBytes(name.length));
+        written += SHORT;
+
+        // extra field length
+        byte[] extra = ze.getLocalFileDataExtra();
+        writeOut(ZipShort.getBytes(extra.length));
+        written += SHORT;
+
+        // file name
+        writeOut(name);
+        written += name.length;
+
+        // extra field
+        writeOut(extra);
+        written += extra.length;
+
+        dataStart = written;
+    }
+
+    /**
+     * Writes the data descriptor entry.
+     * @param ze the entry to write
+     * @throws IOException on error
+     *
+     * @since 1.1
+     */
+    protected void writeDataDescriptor(ZipEntry ze) throws IOException {
+        if (ze.getMethod() != DEFLATED || raf != null) {
+            return;
+        }
+        writeOut(DD_SIG);
+        writeOut(ZipLong.getBytes(entry.getCrc()));
+        writeOut(ZipLong.getBytes(entry.getCompressedSize()));
+        writeOut(ZipLong.getBytes(entry.getSize()));
+        // CheckStyle:MagicNumber OFF
+        written += 16;
+        // CheckStyle:MagicNumber ON
+    }
+
+    /**
+     * Writes the central file header entry.
+     * @param ze the entry to write
+     * @throws IOException on error
+     *
+     * @since 1.1
+     */
+    protected void writeCentralFileHeader(ZipEntry ze) throws IOException {
+        writeOut(CFH_SIG);
+        written += WORD;
+
+        // version made by
+        // CheckStyle:MagicNumber OFF
+        writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20));
+        written += SHORT;
+
+        // version needed to extract
+        // general purpose bit flag
+        if (ze.getMethod() == DEFLATED && raf == null) {
+            // requires version 2 as we are going to store length info
+            // in the data descriptor
+            writeOut(ZipShort.getBytes(20));
+
+            // bit3 set to signal, we use a data descriptor
+            writeOut(ZipShort.getBytes(8));
+        } else {
+            writeOut(ZipShort.getBytes(10));
+            writeOut(ZERO);
+        }
+        // CheckStyle:MagicNumber ON
+        written += WORD;
+
+        // compression method
+        writeOut(ZipShort.getBytes(ze.getMethod()));
+        written += SHORT;
+
+        // last mod. time and date
+        writeOut(toDosTime(ze.getTime()));
+        written += WORD;
+
+        // CRC
+        // compressed length
+        // uncompressed length
+        writeOut(ZipLong.getBytes(ze.getCrc()));
+        writeOut(ZipLong.getBytes(ze.getCompressedSize()));
+        writeOut(ZipLong.getBytes(ze.getSize()));
+        // CheckStyle:MagicNumber OFF
+        written += 12;
+        // CheckStyle:MagicNumber ON
+
+        // file name length
+        byte[] name = getBytes(ze.getName());
+        writeOut(ZipShort.getBytes(name.length));
+        written += SHORT;
+
+        // extra field length
+        byte[] extra = ze.getCentralDirectoryExtra();
+        writeOut(ZipShort.getBytes(extra.length));
+        written += SHORT;
+
+        // file comment length
+        String comm = ze.getComment();
+        if (comm == null) {
+            comm = "";
+        }
+        byte[] commentB = getBytes(comm);
+        writeOut(ZipShort.getBytes(commentB.length));
+        written += SHORT;
+
+        // disk number start
+        writeOut(ZERO);
+        written += SHORT;
+
+        // internal file attributes
+        writeOut(ZipShort.getBytes(ze.getInternalAttributes()));
+        written += SHORT;
+
+        // external file attributes
+        writeOut(ZipLong.getBytes(ze.getExternalAttributes()));
+        written += WORD;
+
+        // relative offset of LFH
+        writeOut((byte[]) offsets.get(ze));
+        written += WORD;
+
+        // file name
+        writeOut(name);
+        written += name.length;
+
+        // extra field
+        writeOut(extra);
+        written += extra.length;
+
+        // file comment
+        writeOut(commentB);
+        written += commentB.length;
+    }
+
+    /**
+     * Writes the &quot;End of central dir record&quot;.
+     * @throws IOException on error
+     *
+     * @since 1.1
+     */
+    protected void writeCentralDirectoryEnd() throws IOException {
+        writeOut(EOCD_SIG);
+
+        // disk numbers
+        writeOut(ZERO);
+        writeOut(ZERO);
+
+        // number of entries
+        byte[] num = ZipShort.getBytes(entries.size());
+        writeOut(num);
+        writeOut(num);
+
+        // length and location of CD
+        writeOut(ZipLong.getBytes(cdLength));
+        writeOut(ZipLong.getBytes(cdOffset));
+
+        // ZIP file comment
+        byte[] data = getBytes(comment);
+        writeOut(ZipShort.getBytes(data.length));
+        writeOut(data);
+    }
+
+    /**
+     * Smallest date/time ZIP can handle.
+     *
+     * @since 1.1
+     */
+    private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L);
+
+    /**
+     * Convert a Date object to a DOS date/time field.
+     * @param time the <code>Date</code> to convert
+     * @return the date as a <code>ZipLong</code>
+     * @since 1.1
+     */
+    protected static ZipLong toDosTime(Date time) {
+        return new ZipLong(toDosTime(time.getTime()));
+    }
+
+    /**
+     * Convert a Date object to a DOS date/time field.
+     *
+     * <p>Stolen from InfoZip's <code>fileio.c</code></p>
+     * @param t number of milliseconds since the epoch
+     * @return the date as a byte array
+     * @since 1.26
+     */
+    protected static byte[] toDosTime(long t) {
+        Date time = new Date(t);
+        // CheckStyle:MagicNumberCheck OFF - I do not think that using constants
+        //                                   here will improve the readablity
+        int year = time.getYear() + 1900;
+        if (year < 1980) {
+            return DOS_TIME_MIN;
+        }
+        int month = time.getMonth() + 1;
+        long value =  ((year - 1980) << 25)
+            |         (month << 21)
+            |         (time.getDate() << 16)
+            |         (time.getHours() << 11)
+            |         (time.getMinutes() << 5)
+            |         (time.getSeconds() >> 1);
+        return ZipLong.getBytes(value);
+        // CheckStyle:MagicNumberCheck ON
+    }
+
+    /**
+     * Retrieve the bytes for the given String in the encoding set for
+     * this Stream.
+     * @param name the string to get bytes from
+     * @return the bytes as a byte array
+     * @throws ZipException on error
+     *
+     * @since 1.3
+     */
+    protected byte[] getBytes(String name) throws ZipException {
+        if (encoding == null) {
+            return name.getBytes();
+        } else {
+            try {
+                return name.getBytes(encoding);
+            } catch (UnsupportedEncodingException uee) {
+                throw new ZipException(uee.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Write bytes to output or random access file.
+     * @param data the byte array to write
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void writeOut(byte[] data) throws IOException {
+        writeOut(data, 0, data.length);
+    }
+
+    /**
+     * Write bytes to output or random access file.
+     * @param data the byte array to write
+     * @param offset the start position to write from
+     * @param length the number of bytes to write
+     * @throws IOException on error
+     *
+     * @since 1.14
+     */
+    protected final void writeOut(byte[] data, int offset, int length)
+        throws IOException {
+        if (raf != null) {
+            raf.write(data, offset, length);
+        } else {
+            out.write(data, offset, length);
+        }
+    }
+
+    /**
+     * Assumes a negative integer really is a positive integer that
+     * has wrapped around and re-creates the original value.
+     * @param i the value to treat as unsigned int.
+     * @return the unsigned int as a long.
+     * @since 1.34
+     */
+    protected static long adjustToLong(int i) {
+        if (i < 0) {
+            return 2 * ((long) Integer.MAX_VALUE) + 2 + i;
+        } else {
+            return i;
+        }
+    }
+
+}
diff --git a/trunk/src/main/org/apache/tools/zip/ZipShort.java b/trunk/src/main/org/apache/tools/zip/ZipShort.java
new file mode 100644
index 0000000..d756349
--- /dev/null
+++ b/trunk/src/main/org/apache/tools/zip/ZipShort.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+/**
+ * Utility class that represents a two byte integer with conversion
+ * rules for the big endian byte order of ZIP files.
+ *
+ */
+public final class ZipShort implements Cloneable {
+    private static final int BYTE_MASK = 0xFF;
+    private static final int BYTE_1_MASK = 0xFF00;
+    private static final int BYTE_1_SHIFT = 8;
+
+    private int value;
+
+    /**
+     * Create instance from a number.
+     * @param value the int to store as a ZipShort
+     * @since 1.1
+     */
+    public ZipShort (int value) {
+        this.value = value;
+    }
+
+    /**
+     * Create instance from bytes.
+     * @param bytes the bytes to store as a ZipShort
+     * @since 1.1
+     */
+    public ZipShort (byte[] bytes) {
+        this(bytes, 0);
+    }
+
+    /**
+     * Create instance from the two bytes starting at offset.
+     * @param bytes the bytes to store as a ZipShort
+     * @param offset the offset to start
+     * @since 1.1
+     */
+    public ZipShort (byte[] bytes, int offset) {
+        value = ZipShort.getValue(bytes, offset);
+    }
+
+    /**
+     * Get value as two bytes in big endian byte order.
+     * @return the value as a a two byte array in big endian byte order
+     * @since 1.1
+     */
+    public byte[] getBytes() {
+        byte[] result = new byte[2];
+        result[0] = (byte) (value & BYTE_MASK);
+        result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
+        return result;
+    }
+
+    /**
+     * Get value as Java int.
+     * @return value as a Java int
+     * @since 1.1
+     */
+    public int getValue() {
+        return value;
+    }
+
+    /**
+     * Get value as two bytes in big endian byte order.
+     * @param value the Java int to convert to bytes
+     * @return the converted int as a byte array in big endian byte order
+     */
+    public static byte[] getBytes(int value) {
+        byte[] result = new byte[2];
+        result[0] = (byte) (value & BYTE_MASK);
+        result[1] = (byte) ((value & BYTE_1_MASK) >> BYTE_1_SHIFT);
+        return result;
+    }
+
+    /**
+     * Helper method to get the value as a java int from two bytes starting at given array offset
+     * @param bytes the array of bytes
+     * @param offset the offset to start
+     * @return the correspondanding java int value
+     */
+    public static int getValue(byte[] bytes, int offset) {
+        int value = (bytes[offset + 1] << BYTE_1_SHIFT) & BYTE_1_MASK;
+        value += (bytes[offset] & BYTE_MASK);
+        return value;
+    }
+
+    /**
+     * Helper method to get the value as a java int from a two-byte array
+     * @param bytes the array of bytes
+     * @return the correspondanding java int value
+     */
+    public static int getValue(byte[] bytes) {
+        return getValue(bytes, 0);
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     * @param o an object to compare
+     * @return true if the objects are equal
+     * @since 1.1
+     */
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof ZipShort)) {
+            return false;
+        }
+        return value == ((ZipShort) o).getValue();
+    }
+
+    /**
+     * Override to make two instances with same value equal.
+     * @return the value stored in the ZipShort
+     * @since 1.1
+     */
+    public int hashCode() {
+        return value;
+    }
+}
diff --git a/trunk/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml b/trunk/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml
new file mode 100755
index 0000000..ae61b9d
--- /dev/null
+++ b/trunk/src/resources/org/apache/tools/ant/types/resources/comparators/antlib.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<antlib>
+  <typedef name="name"
+    classname="org.apache.tools.ant.types.resources.comparators.Name" />
+  <typedef name="size"
+    classname="org.apache.tools.ant.types.resources.comparators.Size" />
+  <typedef name="date"
+    classname="org.apache.tools.ant.types.resources.comparators.Date" />
+  <typedef name="exists"
+    classname="org.apache.tools.ant.types.resources.comparators.Exists" />
+  <typedef name="type"
+    classname="org.apache.tools.ant.types.resources.comparators.Type" />
+  <typedef name="content"
+    classname="org.apache.tools.ant.types.resources.comparators.Content" />
+  <typedef name="reverse"
+    classname="org.apache.tools.ant.types.resources.comparators.Reverse" />
+</antlib>
diff --git a/trunk/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml b/trunk/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml
new file mode 100755
index 0000000..115e2fb
--- /dev/null
+++ b/trunk/src/resources/org/apache/tools/ant/types/resources/selectors/antlib.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<antlib>
+  <typedef name="and"
+    classname="org.apache.tools.ant.types.resources.selectors.And" />
+  <typedef name="compare"
+    classname="org.apache.tools.ant.types.resources.selectors.Compare" />
+  <typedef name="contains"
+    classname="org.apache.tools.ant.types.selectors.ContainsSelector" />
+  <typedef name="containsregexp"
+    classname="org.apache.tools.ant.types.selectors.ContainsRegexpSelector" />
+  <typedef name="date"
+    classname="org.apache.tools.ant.types.resources.selectors.Date" />
+  <typedef name="exists"
+    classname="org.apache.tools.ant.types.resources.selectors.Exists" />
+  <typedef name="instanceof"
+    classname="org.apache.tools.ant.types.resources.selectors.InstanceOf" />
+  <typedef name="majority"
+    classname="org.apache.tools.ant.types.resources.selectors.Majority" />
+  <typedef name="modified"
+    classname="org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector" />
+  <typedef name="name"
+    classname="org.apache.tools.ant.types.resources.selectors.Name" />
+  <typedef name="none"
+    classname="org.apache.tools.ant.types.resources.selectors.None" />
+  <typedef name="not"
+    classname="org.apache.tools.ant.types.resources.selectors.Not" />
+  <typedef name="or"
+    classname="org.apache.tools.ant.types.resources.selectors.Or" />
+  <typedef name="size"
+    classname="org.apache.tools.ant.types.resources.selectors.Size" />
+  <typedef name="type"
+    classname="org.apache.tools.ant.types.resources.selectors.Type" />
+</antlib>
diff --git a/trunk/src/script/ant b/trunk/src/script/ant
new file mode 100644
index 0000000..2e60839
--- /dev/null
+++ b/trunk/src/script/ant
@@ -0,0 +1,326 @@
+#! /bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Extract launch and ant arguments, (see details below).
+ant_exec_args=
+no_config=false
+use_jikes_default=false
+ant_exec_debug=false
+show_help=false
+for arg in "$@" ; do
+  if [ "$arg" = "--noconfig" ] ; then
+    no_config=true
+  elif [ "$arg" = "--usejikes" ] ; then
+    use_jikes_default=true
+  elif [ "$arg" = "--execdebug" ] ; then
+    ant_exec_debug=true
+  elif [ my"$arg" = my"--h"  -o my"$arg" = my"--help"  ] ; then
+    show_help=true
+    ant_exec_args="$ant_exec_args -h"
+  else
+    if [  my"$arg" = my"-h"  -o  my"$arg" = my"-help" ] ; then
+      show_help=true
+    fi
+    ant_exec_args="$ant_exec_args \"$arg\""
+  fi
+done
+
+# Source/default ant configuration
+if $no_config ; then
+  rpm_mode=false
+  usejikes=$use_jikes_default
+else
+  # load system-wide ant configuration (ONLY if ANT_HOME has NOT been set)
+  if [ -z "$ANT_HOME" -o "$ANT_HOME" = "/usr/share/ant" ]; then
+      if [ -f "/etc/ant.conf" ] ; then
+          . /etc/ant.conf
+      fi
+  fi
+
+  # load user ant configuration
+  if [ -f "$HOME/.ant/ant.conf" ] ; then
+    . $HOME/.ant/ant.conf
+  fi
+  if [ -f "$HOME/.antrc" ] ; then
+    . "$HOME/.antrc"
+  fi
+
+  # provide default configuration values
+  if [ -z "$rpm_mode" ] ; then
+    rpm_mode=false
+  fi
+  if [ -z "$usejikes" ] ; then
+    usejikes=$use_jikes_default
+  fi
+fi
+
+# Setup Java environment in rpm mode
+if $rpm_mode ; then
+  if [ -f /usr/share/java-utils/java-functions ] ; then
+    . /usr/share/java-utils/java-functions
+    set_jvm
+    set_javacmd
+  fi
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  Darwin*) darwin=true
+           if [ -z "$JAVA_HOME" ] ; then
+             JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
+           fi
+           ;;
+esac
+
+if [ -z "$ANT_HOME" -o ! -d "$ANT_HOME" ] ; then
+  ## resolve links - $0 may be a link to ant's home
+  PRG="$0"
+  progname=`basename "$0"`
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+    PRG="$link"
+    else
+    PRG=`dirname "$PRG"`"/$link"
+    fi
+  done
+
+  ANT_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  ANT_HOME=`cd "$ANT_HOME" > /dev/null && pwd`
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$ANT_HOME" ] &&
+    ANT_HOME=`cygpath --unix "$ANT_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# set ANT_LIB location
+ANT_LIB="${ANT_HOME}/lib"
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    # IBM's JDK on AIX uses strange locations for the executables
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    elif [ -x "$JAVA_HOME/jre/bin/java" ] ; then
+      JAVACMD="$JAVA_HOME/jre/bin/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD=`which java 2> /dev/null `
+    if [ -z "$JAVACMD" ] ; then
+        JAVACMD=java
+    fi
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly."
+  echo "  We cannot execute $JAVACMD"
+  exit 1
+fi
+
+# Build local classpath using just the launcher in non-rpm mode or
+# use the Jpackage helper in rpm mode with basic and default jars
+# specified in the ant.conf configuration. Because the launcher is
+# used, libraries linked in ANT_HOME/lib will also be included, but this
+# is discouraged as it is not java-version safe. A user should
+# request optional jars and their dependencies via the OPT_JAR_LIST
+# variable
+if $rpm_mode && [ -x /usr/bin/build-classpath ] ; then
+  LOCALCLASSPATH="$(/usr/bin/build-classpath ant ant-launcher jaxp_parser_impl xml-commons-apis)"
+
+  # If no optional jars have been specified then build the default list
+  if [ -z "$OPT_JAR_LIST" ] ; then
+    for file in /etc/ant.d/*; do
+      if [ -f "$file" ]; then
+        case "$file" in
+        *~) ;;
+        *#*) ;;
+        *.rpmsave) ;;
+        *.rpmnew) ;;
+        *)
+          for dep in `cat "$file"`; do
+            case "$OPT_JAR_LIST" in
+            *"$dep"*) ;;
+            *) OPT_JAR_LIST="$OPT_JAR_LIST${OPT_JAR_LIST:+ }$dep"
+            esac
+          done
+        esac
+      fi
+    done
+  fi
+
+  # If the user requested to try to add some other jars to the classpath
+  if [ -n "$OPT_JAR_LIST" ] ; then
+    _OPTCLASSPATH="$(/usr/bin/build-classpath $OPT_JAR_LIST 2> /dev/null)"
+    if [ -n "$_OPTCLASSPATH" ] ; then 
+      LOCALCLASSPATH="$LOCALCLASSPATH:$_OPTCLASSPATH"
+    fi
+  fi
+
+  # Explicitly add javac path to classpath, assume JAVA_HOME set
+  # properly in rpm mode
+  if [ -f "$JAVA_HOME/lib/tools.jar" ] ; then
+    LOCALCLASSPATH="$LOCALCLASSPATH:$JAVA_HOME/lib/tools.jar"
+  fi
+  if [ -f "$JAVA_HOME/lib/classes.zip" ] ; then
+    LOCALCLASSPATH="$LOCALCLASSPATH:$JAVA_HOME/lib/classes.zip"
+  fi
+
+  # if CLASSPATH_OVERRIDE env var is set, LOCALCLASSPATH will be
+  # user CLASSPATH first and ant-found jars after.
+  # In that case, the user CLASSPATH will override ant-found jars
+  #
+  # if CLASSPATH_OVERRIDE is not set, we'll have the normal behaviour
+  # with ant-found jars first and user CLASSPATH after
+  if [ -n "$CLASSPATH" ] ; then
+    # merge local and specified classpath 
+    if [ -z "$LOCALCLASSPATH" ] ; then 
+      LOCALCLASSPATH="$CLASSPATH"
+    elif [ -n "$CLASSPATH_OVERRIDE" ] ; then
+      LOCALCLASSPATH="$CLASSPATH:$LOCALCLASSPATH"
+    else
+      LOCALCLASSPATH="$LOCALCLASSPATH:$CLASSPATH"
+    fi
+
+    # remove class path from launcher -cp option
+    CLASSPATH=""
+  fi
+else
+  # not using rpm_mode; use launcher to determine classpaths
+  if [ -z "$LOCALCLASSPATH" ] ; then
+      LOCALCLASSPATH=$ANT_LIB/ant-launcher.jar
+  else
+      LOCALCLASSPATH=$ANT_LIB/ant-launcher.jar:$LOCALCLASSPATH
+  fi
+fi
+
+if [ -n "$JAVA_HOME" ] ; then
+  # OSX hack to make Ant work with jikes
+  if $darwin ; then
+    OSXHACK="${JAVA_HOME}/../Classes"
+    if [ -d "${OSXHACK}" ] ; then
+      for i in "${OSXHACK}"/*.jar
+      do
+        JIKESPATH="$JIKESPATH:$i"
+      done
+    fi
+  fi
+fi
+
+# Allow Jikes support (off by default)
+if $usejikes; then
+  ANT_OPTS="$ANT_OPTS -Dbuild.compiler=jikes"
+fi
+
+# For Cygwin, switch paths to appropriate format before running java
+# For PATHs convert to unix format first, then to windows format to ensure
+# both formats are supported. Probably this will fail on directories with ;
+# in the name in the path. Let's assume that paths containing ; are more
+# rare than windows style paths on cygwin.
+if $cygwin; then
+  if [ "$OS" = "Windows_NT" ] && cygpath -m .>/dev/null 2>/dev/null ; then
+    format=mixed
+  else
+    format=windows
+  fi
+  ANT_HOME=`cygpath --$format "$ANT_HOME"`
+  ANT_LIB=`cygpath --$format "$ANT_LIB"`
+  JAVA_HOME=`cygpath --$format "$JAVA_HOME"`
+  LCP_TEMP=`cygpath --path --unix "$LOCALCLASSPATH"`
+  LOCALCLASSPATH=`cygpath --path --$format "$LCP_TEMP"`
+  if [ -n "$CLASSPATH" ] ; then
+    CP_TEMP=`cygpath --path --unix "$CLASSPATH"`
+    CLASSPATH=`cygpath --path --$format "$CP_TEMP"`
+  fi
+  CYGHOME=`cygpath --$format "$HOME"`
+fi
+
+# Show script help if requested
+if $show_help ; then
+  echo $0 '[script options] [options] [target [target2 [target3] ..]]'
+  echo 'Script Options:'
+  echo '  --help, --h            print this message and ant help'
+  echo '  --noconfig             suppress sourcing of /etc/ant.conf,'
+  echo '                         $HOME/.ant/ant.conf, and $HOME/.antrc'
+  echo '                         configuration files'
+  echo '  --usejikes             enable use of jikes by default, unless'
+  echo '                         set explicitly in configuration files'
+  echo '  --execdebug            print ant exec line generated by this'
+  echo '                         launch script'
+  echo '  '
+fi
+# add a second backslash to variables terminated by a backslash under cygwin
+if $cygwin; then
+  case "$ANT_HOME" in
+    *\\ )
+    ANT_HOME="$ANT_HOME\\"
+    ;;
+  esac
+  case "$CYGHOME" in
+    *\\ )
+    CYGHOME="$CYGHOME\\"
+    ;;
+  esac
+  case "$JIKESPATH" in
+    *\\ )
+    JIKESPATH="$JIKESPATH\\"
+    ;;
+  esac
+  case "$LOCALCLASSPATH" in
+    *\\ )
+    LOCALCLASSPATH="$LOCALCLASSPATH\\"
+    ;;
+  esac
+  case "$CLASSPATH" in
+    *\\ )
+    CLASSPATH="$CLASSPATH\\"
+    ;;
+  esac
+fi
+# Execute ant using eval/exec to preserve spaces in paths,
+# java options, and ant args
+ant_sys_opts=
+if [ -n "$CYGHOME" ]; then
+  if [ -n "$JIKESPATH" ]; then
+    ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\" -Dcygwin.user.home=\"$CYGHOME\""
+  else
+    ant_sys_opts="-Dcygwin.user.home=\"$CYGHOME\""
+  fi
+else
+  if [ -n "$JIKESPATH" ]; then
+    ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\""
+  fi
+fi
+ant_exec_command="exec \"$JAVACMD\" $ANT_OPTS -classpath \"$LOCALCLASSPATH\" -Dant.home=\"$ANT_HOME\" -Dant.library.dir=\"$ANT_LIB\" $ant_sys_opts org.apache.tools.ant.launch.Launcher $ANT_ARGS -cp \"$CLASSPATH\" $ant_exec_args"
+if $ant_exec_debug ; then
+    echo $ant_exec_command
+fi
+eval $ant_exec_command
diff --git a/trunk/src/script/ant.bat b/trunk/src/script/ant.bat
new file mode 100755
index 0000000..6d57c81
--- /dev/null
+++ b/trunk/src/script/ant.bat
@@ -0,0 +1,226 @@
+@echo off
+
+REM  Licensed to the Apache Software Foundation (ASF) under one or more
+REM  contributor license agreements.  See the NOTICE file distributed with
+REM  this work for additional information regarding copyright ownership.
+REM  The ASF licenses this file to You under the Apache License, Version 2.0
+REM  (the "License"); you may not use this file except in compliance with
+REM  the License.  You may obtain a copy of the License at
+REM 
+REM      http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM  Unless required by applicable law or agreed to in writing, software
+REM  distributed under the License is distributed on an "AS IS" BASIS,
+REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM  See the License for the specific language governing permissions and
+REM  limitations under the License.
+
+REM This is an inordinately troublesome piece of code, particularly because it
+REM tries to work on both Win9x and WinNT-based systems. If we could abandon '9x
+REM support, things would be much easier, but sadly, it is not yet time.
+REM Be cautious about editing this, and only add WinNT specific stuff in code that
+REM only runs on WinNT.
+
+if "%HOME%"=="" goto homeDrivePathPre
+if exist "%HOME%\antrc_pre.bat" call "%HOME%\antrc_pre.bat"
+
+:homeDrivePathPre
+if "%HOMEDRIVE%%HOMEPATH%"=="" goto userProfilePre
+if "%HOMEDRIVE%%HOMEPATH%"=="%HOME%" goto userProfilePre
+if exist "%HOMEDRIVE%%HOMEPATH%\antrc_pre.bat" call "%HOMEDRIVE%%HOMEPATH%\antrc_pre.bat"
+
+:userProfilePre
+if "%USERPROFILE%"=="" goto alpha
+if "%USERPROFILE%"=="%HOME%" goto alpha
+if "%USERPROFILE%"=="%HOMEDRIVE%%HOMEPATH%" goto alpha
+if exist "%USERPROFILE%\antrc_pre.bat" call "%USERPROFILE%\antrc_pre.bat"
+
+:alpha
+
+if "%OS%"=="Windows_NT" @setlocal
+if "%OS%"=="WINNT" @setlocal
+
+if "%ANT_HOME%"=="" goto setDefaultAntHome
+
+:stripAntHome
+if not _%ANT_HOME:~-1%==_\ goto checkClasspath
+set ANT_HOME=%ANT_HOME:~0,-1%
+goto stripAntHome
+
+:setDefaultAntHome
+rem %~dp0 is expanded pathname of the current script under NT
+set ANT_HOME=%~dp0..
+
+:checkClasspath
+set _USE_CLASSPATH=yes
+rem CLASSPATH must not be used if it is equal to ""
+if "%CLASSPATH%"=="""" set _USE_CLASSPATH=no
+if "%CLASSPATH%"=="" set _USE_CLASSPATH=no
+
+rem Slurp the command line arguments. This loop allows for an unlimited number
+rem of arguments (up to the command line limit, anyway).
+set ANT_CMD_LINE_ARGS=%1
+if ""%1""=="""" goto doneStart
+shift
+:setupArgs
+if ""%1""=="""" goto doneStart
+if ""%1""==""-noclasspath"" goto clearclasspath
+set ANT_CMD_LINE_ARGS=%ANT_CMD_LINE_ARGS% %1
+shift
+goto setupArgs
+
+rem here is there is a -noclasspath in the options
+:clearclasspath
+set _USE_CLASSPATH=no
+shift
+goto setupArgs
+
+rem This label provides a place for the argument list loop to break out
+rem and for NT handling to skip to.
+
+:doneStart
+
+if _USE_CLASSPATH==no goto findAntHome
+
+:stripClasspath
+if not _%CLASSPATH:~-1%==_\ goto findAntHome
+set CLASSPATH=%CLASSPATH:~0,-1%
+goto stripClasspath
+
+:findAntHome
+rem find ANT_HOME if it does not exist due to either an invalid value passed
+rem by the user or the %0 problem on Windows 9x
+if exist "%ANT_HOME%\lib\ant.jar" goto checkJava
+
+rem check for ant in Program Files
+if not exist "%ProgramFiles%\ant" goto checkSystemDrive
+set ANT_HOME=%ProgramFiles%\ant
+goto checkJava
+
+:checkSystemDrive
+rem check for ant in root directory of system drive
+if not exist %SystemDrive%\ant\lib\ant.jar goto checkCDrive
+set ANT_HOME=%SystemDrive%\ant
+goto checkJava
+
+:checkCDrive
+rem check for ant in C:\ant for Win9X users
+if not exist C:\ant\lib\ant.jar goto noAntHome
+set ANT_HOME=C:\ant
+goto checkJava
+
+:noAntHome
+echo ANT_HOME is set incorrectly or ant could not be located. Please set ANT_HOME.
+goto end
+
+:checkJava
+set _JAVACMD=%JAVACMD%
+
+if "%JAVA_HOME%" == "" goto noJavaHome
+if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
+if "%_JAVACMD%" == "" set _JAVACMD=%JAVA_HOME%\bin\java.exe
+goto checkJikes
+
+:noJavaHome
+if "%_JAVACMD%" == "" set _JAVACMD=java.exe
+
+:checkJikes
+if not "%JIKESPATH%"=="" goto runAntWithJikes
+
+:runAnt
+if "%_USE_CLASSPATH%"=="no" goto runAntNoClasspath
+:runAntWithClasspath
+"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% -cp "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
+rem Check the error code of the Ant build
+if not "%OS%"=="Windows_NT" goto onError
+set ANT_ERROR=%ERRORLEVEL%
+goto end
+
+:runAntNoClasspath
+"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%
+rem Check the error code of the Ant build
+if not "%OS%"=="Windows_NT" goto onError
+set ANT_ERROR=%ERRORLEVEL%
+goto end
+
+:runAntWithJikes
+
+if not _%JIKESPATH:~-1%==_\ goto checkJikesAndClasspath
+set JIKESPATH=%JIKESPATH:~0,-1%
+goto runAntWithJikes
+
+:checkJikesAndClasspath
+
+if "%_USE_CLASSPATH%"=="no" goto runAntWithJikesNoClasspath
+
+:runAntWithJikesAndClasspath
+"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" "-Djikes.class.path=%JIKESPATH%" org.apache.tools.ant.launch.Launcher %ANT_ARGS%  -cp "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
+rem Check the error code of the Ant build
+if not "%OS%"=="Windows_NT" goto onError
+set ANT_ERROR=%ERRORLEVEL%
+goto end
+
+:runAntWithJikesNoClasspath
+"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" "-Djikes.class.path=%JIKESPATH%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%
+rem Check the error code of the Ant build
+if not "%OS%"=="Windows_NT" goto onError
+set ANT_ERROR=%ERRORLEVEL%
+goto end
+
+:onError
+rem Windows 9x way of checking the error code.  It matches via brute force.
+for %%i in (1 10 100) do set err%%i=
+for %%i in (0 1 2) do if errorlevel %%i00 set err100=%%i
+if %err100%==2 goto onError200
+if %err100%==0 set err100=
+for %%i in (0 1 2 3 4 5 6 7 8 9) do if errorlevel %err100%%%i0 set err10=%%i
+if "%err100%"=="" if %err10%==0 set err10=
+:onError1
+for %%i in (0 1 2 3 4 5 6 7 8 9) do if errorlevel %err100%%err10%%%i set err1=%%i
+goto onErrorEnd
+:onError200
+for %%i in (0 1 2 3 4 5) do if errorlevel 2%%i0 set err10=%%i
+if err10==5 for %%i in (0 1 2 3 4 5) do if errorlevel 25%%i set err1=%%i
+if not err10==5 goto onError1
+:onErrorEnd
+set ANT_ERROR=%err100%%err10%%err1%
+for %%i in (1 10 100) do set err%%i=
+
+:end
+rem bug ID 32069: resetting an undefined env variable changes the errorlevel.
+if not "%_JAVACMD%"=="" set _JAVACMD=
+if not "%_ANT_CMD_LINE_ARGS%"=="" set ANT_CMD_LINE_ARGS=
+
+if "%ANT_ERROR%"=="0" goto mainEnd
+
+rem Set the return code if we are not in NT.  We can only set
+rem a value of 1, but it's better than nothing.
+if not "%OS%"=="Windows_NT" echo 1 > nul | choice /n /c:1
+
+rem Set the ERRORLEVEL if we are running NT.
+if "%OS%"=="Windows_NT" color 00
+
+goto omega
+
+:mainEnd
+
+rem If there were no errors, we run the post script.
+if "%OS%"=="Windows_NT" @endlocal
+if "%OS%"=="WINNT" @endlocal
+
+if "%HOME%"=="" goto homeDrivePathPost
+if exist "%HOME%\antrc_post.bat" call "%HOME%\antrc_post.bat"
+
+:homeDrivePathPost
+if "%HOMEDRIVE%%HOMEPATH%"=="" goto userProfilePost
+if "%HOMEDRIVE%%HOMEPATH%"=="%HOME%" goto userProfilePost
+if exist "%HOMEDRIVE%%HOMEPATH%\antrc_post.bat" call "%HOMEDRIVE%%HOMEPATH%\antrc_post.bat"
+
+:userProfilePost
+if "%USERPROFILE%"=="" goto omega
+if "%USERPROFILE%"=="%HOME%" goto omega
+if "%USERPROFILE%"=="%HOMEDRIVE%%HOMEPATH%" goto omega
+if exist "%USERPROFILE%\antrc_post.bat" call "%USERPROFILE%\antrc_post.bat"
+
+:omega
+
diff --git a/trunk/src/script/ant.cmd b/trunk/src/script/ant.cmd
new file mode 100644
index 0000000..d221a40
--- /dev/null
+++ b/trunk/src/script/ant.cmd
@@ -0,0 +1,93 @@
+/* 
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+ 
+    Run ant
+*/
+
+'@echo off'
+parse arg mode envarg '::' antarg
+
+if mode\='.' & mode\='..' & mode\='/' then do
+  envarg = mode envarg
+  mode = ''
+end
+
+if antarg = '' then do
+  antarg = envarg
+  envarg = ''
+end
+
+x = setlocal()
+
+env="OS2ENVIRONMENT"
+antenv = _getenv_('antenv')
+if _testenv_() = 0 then interpret 'call "' || antenv || '"' '"' || envarg || '"'
+
+if mode = '' then mode = _getenv_('ANT_MODE' '..')
+if mode \= '/' then do
+  runrc = _getenv_('runrc')
+  antrc = _getenv_('antrc' 'antrc.cmd')
+  if mode = '..' then mode = '-r'
+  else mode = ''
+  interpret 'call "' || runrc || '"' antrc '"' || mode || '"'
+end
+
+if _testenv_() = 0 then do
+  say 'Ant environment is not set properly'
+  x = endlocal()
+  exit 16
+end
+
+settings = '-Dant.home=' || ANT_HOME '-Djava.home=' || JAVA_HOME
+
+java = _getenv_('javacmd' 'java')
+opts = value('ANT_OPTS',,env)
+args = value('ANT_ARGS',,env)
+lcp = value('LOCALCLASSPATH',,env)
+cp = value('CLASSPATH',,env)
+if value('ANT_USE_CP',,env) \= '' then do
+  if lcp \= '' & right(lcp, 1) \= ';' then lcp = lcp || ';'
+  lcp = lcp || cp
+  'SET CLASSPATH='
+end
+if lcp\='' then lcp = '-classpath' lcp
+
+cmd = java opts lcp '-jar' ANT_HOME ||'\lib\ant-launcher.jar' settings args antarg
+launcher = stream(ANT_HOME ||'\lib\ant-launcher.jar', 'C', 'query exists')
+if launcher = '' then entry = 'org.apache.tools.ant.Main'
+else entry = 'org.apache.tools.ant.launch.Launcher'
+java opts lcp entry settings args antarg
+
+x = endlocal()
+
+return rc
+
+_testenv_: procedure expose env ANT_HOME JAVA_HOME
+ANT_HOME = value('ANT_HOME',,env)
+if ANT_HOME = '' then return 0
+JAVA_HOME = value('JAVA_HOME',,env)
+if JAVA_HOME = '' then return 0
+cp = translate(value('CLASSPATH',,env))
+if pos(translate(ANT_HOME), cp) = 0 then return 0
+if pos(translate(JAVA_HOME), cp) = 0 then return 0
+return 1
+
+_getenv_: procedure expose env
+parse arg envar default
+if default = '' then default = envar
+var = value(translate(envar),,env)
+if var = '' then var = default
+return var
diff --git a/trunk/src/script/antRun b/trunk/src/script/antRun
new file mode 100644
index 0000000..8110f86
--- /dev/null
+++ b/trunk/src/script/antRun
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Args: DIR command
+cd "$1"
+CMD="$2"
+shift
+shift
+
+exec "$CMD" "$@"
diff --git a/trunk/src/script/antRun.bat b/trunk/src/script/antRun.bat
new file mode 100755
index 0000000..10d2bbc
--- /dev/null
+++ b/trunk/src/script/antRun.bat
@@ -0,0 +1,50 @@
+@echo off
+
+REM  Licensed to the Apache Software Foundation (ASF) under one or more
+REM  contributor license agreements.  See the NOTICE file distributed with
+REM  this work for additional information regarding copyright ownership.
+REM  The ASF licenses this file to You under the Apache License, Version 2.0
+REM  (the "License"); you may not use this file except in compliance with
+REM  the License.  You may obtain a copy of the License at
+REM 
+REM      http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM  Unless required by applicable law or agreed to in writing, software
+REM  distributed under the License is distributed on an "AS IS" BASIS,
+REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM  See the License for the specific language governing permissions and
+REM  limitations under the License.
+
+if "%OS%"=="Windows_NT" @setlocal
+if "%OS%"=="WINNT" @setlocal
+
+if ""%1""=="""" goto runCommand
+
+rem Change drive and directory to %1
+if "%OS%"=="Windows_NT" goto nt_cd
+if "%OS%"=="WINNT" goto nt_cd
+cd ""%1""
+goto end_cd
+:nt_cd
+cd /d ""%1""
+:end_cd
+shift
+
+rem Slurp the command line arguments. This loop allows for an unlimited number
+rem of arguments (up to the command line limit, anyway).
+set ANT_RUN_CMD=%1
+if ""%1""=="""" goto runCommand
+shift
+:loop
+if ""%1""=="""" goto runCommand
+set ANT_RUN_CMD=%ANT_RUN_CMD% %1
+shift
+goto loop
+
+:runCommand
+rem echo %ANT_RUN_CMD%
+%ANT_RUN_CMD%
+
+if "%OS%"=="Windows_NT" @endlocal
+if "%OS%"=="WINNT" @endlocal
+
diff --git a/trunk/src/script/antRun.pl b/trunk/src/script/antRun.pl
new file mode 100644
index 0000000..dbea10f
--- /dev/null
+++ b/trunk/src/script/antRun.pl
@@ -0,0 +1,66 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#######################################################################
+#
+# antRun.pl
+#
+# wrapper script for invoking commands on a platform with Perl installed
+# this is akin to antRun.bat, and antRun the SH script 
+#
+# created:         2001-10-18
+# author:          Jeff Tulley jtulley@novell.com 
+#######################################################################
+#be fussy about variables
+use strict;
+
+#turn warnings on during dev; generates a few spurious uninitialised var access warnings
+#use warnings;
+
+#and set $debug to 1 to turn on trace info (currently unused)
+my $debug=1;
+
+#######################################################################
+# change drive and directory to "%1"
+my $ANT_RUN_CMD = @ARGV[0];
+
+# assign current run command to "%2"
+chdir (@ARGV[0]) || die "Can't cd to $ARGV[0]: $!\n";
+if ($^O eq "NetWare") {
+    # There is a bug in Perl 5 on NetWare, where chdir does not
+    # do anything.  On NetWare, the following path-prefixed form should 
+    # always work. (afaict)
+    $ANT_RUN_CMD .= "/".@ARGV[1];
+}
+else {
+    $ANT_RUN_CMD = @ARGV[1];
+}
+
+# dispose of the first two arguments, leaving only the command's args.
+shift;
+shift;
+
+# run the command
+my $returnValue = system $ANT_RUN_CMD, @ARGV;
+if ($returnValue eq 0) {
+    exit 0;
+}
+else {
+    # only 0 and 1 are widely recognized as exit values
+    # so change the exit value to 1
+    exit 1;
+}
diff --git a/trunk/src/script/antenv.cmd b/trunk/src/script/antenv.cmd
new file mode 100644
index 0000000..170d89f
--- /dev/null
+++ b/trunk/src/script/antenv.cmd
@@ -0,0 +1,98 @@
+/* 
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+'@echo off'
+call RxFuncAdd "SysLoadFuncs", "RexxUtil", "SysLoadFuncs"
+call SysLoadFuncs
+
+/* Prepare the parameters for later use */
+parse arg argv
+mode = ''
+args = ''
+opts = ''
+cp = ''
+lcp = ''
+
+do i = 1 to words(argv)
+  param = word(argv, i)
+  select
+    when param='-lcp' then mode = 'l'
+    when param='-cp' | param='-classpath' then mode = 'c'
+    when abbrev('-opts', param, 4) then mode = 'o'
+    when abbrev('-args', param, 4) then mode = 'a'
+  otherwise
+    select
+      when mode = 'a' then args = space(args param, 1)
+      when mode = 'c' then cp = space(cp param, 1)
+      when mode = 'l' then lcp = space(lcp param, 1)
+      when mode = 'o' then opts = space(opts param, 1)
+    otherwise
+      say 'Option' param 'ignored'
+    end
+  end
+end
+
+env="OS2ENVIRONMENT"
+antconf = _getenv_('antconf' 'antconf.cmd')
+runrc = _getenv_('runrc')
+interpret 'call "' || runrc || '"' '"' || antconf || '"' 'ETC'
+ANT_HOME = value('ANT_HOME',,env)
+JAVA_HOME = value('JAVA_HOME',,env)
+classpath = value('CLASSPATH',,env)
+classes = stream(JAVA_HOME || "\lib\classes.zip", "C", "QUERY EXISTS")
+if classes \= '' then classpath = prepend(classpath classes)
+classes = stream(JAVA_HOME || "\lib\tools.jar", "C", "QUERY EXISTS")
+if classes \= '' then classpath = prepend(classpath classes)
+
+classpath = prepend(classpath ANT_HOME || '\lib\ant-launcher.jar')
+'SET CLASSPATH=' || classpath
+
+/* Setting classpathes, options and arguments */
+envset = _getenv_('envset')
+if cp\=''   then interpret 'call "' || envset || '"' '"; CLASSPATH"' '"' || cp || '"'
+if lcp\=''  then interpret 'call "' || envset || '"' '"; LOCALCLASSPATH"' '"' || lcp || '"'
+if opts\='' then interpret 'call "' || envset || '"' '"-D ANT_OPTS"' '"' || opts || '"'
+if args\='' then interpret 'call "' || envset || '"' '"ANT_ARGS"' '"' || args || '"'
+
+exit 0
+
+addpath: procedure
+parse arg path elem
+if elem = '' then do
+  if path\='' & right(path, 1)\=';' then path = path || ';'
+  return path
+end
+if substr(path, length(path)) = ';' then glue = ''
+else glue = ';'
+if pos(translate(elem), translate(path)) = 0 then path = path || glue || elem || ';'
+return path
+
+prepend: procedure
+parse arg path elem
+if elem = '' then do
+  if path\='' & right(path, 1)\=';' then path = path || ';'
+  return path
+end
+if pos(translate(elem), translate(path)) = 0 then path = elem || ';' || path
+return path
+
+_getenv_: procedure expose env
+parse arg envar default
+if default = '' then default = envar
+var = value(translate(envar),,env)
+if var = '' then var = default
+return var
diff --git a/trunk/src/script/complete-ant-cmd.pl b/trunk/src/script/complete-ant-cmd.pl
new file mode 100644
index 0000000..b58c26e
--- /dev/null
+++ b/trunk/src/script/complete-ant-cmd.pl
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+# A script to allow Bash or Z-Shell to complete an Ant command-line.  
+#
+# To install for Bash 2.0 or better, add the following to ~/.bashrc:
+# 
+#     $ complete -C complete-ant-cmd ant build.sh
+#
+# To install for Z-Shell 2.5 or better, add the following to ~/.zshrc:
+#
+#     function ant_complete () {
+#         local args_line args
+#         read -l args_line
+#         set -A args $args_line
+#         set -A reply $(COMP_LINE=$args_line complete-ant-cmd ${args[1]} $1)
+#     }
+#     compctl -K ant_complete ant build.sh
+#     
+# @author Mike Williams <mikew@cortexebusiness.com.au>
+
+my $cmdLine = $ENV{'COMP_LINE'};
+my $antCmd = $ARGV[0];
+my $word = $ARGV[1];
+
+my @completions;
+if ($word =~ /^-/) {
+    list( restrict( $word, getArguments() ));
+} elsif ($cmdLine =~ /-(f|buildfile)\s+\S*$/) {
+    list( getBuildFiles($word) );
+} else {
+    list( restrict( $word, getTargets() ));
+}
+
+exit(0);
+
+sub list {
+    for (@_) {
+        print "$_\n";
+    }
+}
+
+sub restrict {
+    my ($word, @completions) = @_;
+    grep( /^\Q$word\E/, @completions );
+}
+
+sub getArguments {
+    qw(-buildfile -debug -emacs -f -find -help -listener -logfile 
+       -logger -projecthelp -quiet -verbose -version); 
+}
+
+
+sub getBuildFiles {
+    my ($word) = @_;
+    grep( /\.xml$/, glob( "$word*" ));
+}
+
+sub getTargets {
+
+    # Look for build-file
+    my $buildFile = 'build.xml';
+    if ($cmdLine =~ /-(f|buildfile)\s+(\S+)/) {
+        $buildFile = $2;
+    }
+    return () unless (-f $buildFile);
+
+    # Run "ant -projecthelp" to list targets.  Keep a cache of results in a
+    # cache-file.
+    my $cacheFile = $buildFile;
+    $cacheFile =~ s|(.*/)?(.*)|${1}.ant-targets-${2}|;
+    if ((!-e $cacheFile) || (-M $buildFile) < (-M $cacheFile)) {
+        open( CACHE, '>'.$cacheFile ) || die "can\'t write $cacheFile: $!\n";
+        open( HELP, "$antCmd -projecthelp -f '$buildFile'|" ) || return(); 
+        my %targets;
+        while( <HELP> ) {
+            if (/^\s+(\S+)/) {
+                $targets{$1}++;
+            }
+        }
+        my @targets = sort keys %targets;
+        for (@targets) { print CACHE "$_\n"; }
+        return @targets;
+    }
+    
+    # Read the target-cache
+    open( CACHE, $cacheFile ) || die "can\'t read $cacheFile: $!\n";
+    my @targets;
+    while (<CACHE>) {
+        chop;
+        s/\r$//;  # for Cygwin
+        push( @targets, $_ );
+    }
+    close( CACHE );
+    @targets;
+
+}
+
+
+
diff --git a/trunk/src/script/envset.cmd b/trunk/src/script/envset.cmd
new file mode 100644
index 0000000..3b07419
--- /dev/null
+++ b/trunk/src/script/envset.cmd
@@ -0,0 +1,131 @@
+/*
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+SET environment variables
+First optional parameter:
+   ;     parameters are considered parts of a path variable, semicolons are
+         appended to each element if not already present
+   -D    parameters are properties for Java or Makefile etc., -D will be
+         prepended and the parameters will be separated by a space
+   =D    the same as above but equal sign is not required
+   ,     parameters should be comma separated in the environment variable
+   -     parameters should be separated by the next parameter
+   Other values mean that the first parameter is missing and the environment
+   variable will be set to the space separated parameters
+
+Second parameter: name of the environment variable
+
+Next parameters: values
+; implies that the equal sign is considered a part of the parameter and is
+not interpreted
+
+-D requires parameters in the form name=value. If the equal sign is not found,
+the parameters are changed to name=expanded_name
+
+Other options have optional equal sign. If it is found, only the part after
+the equal sign will be oprionally expanded.
+
+If the parameter is the minus sign, the next parameter will not be expanded.
+If the parameter is a single dot, it will be replaced with the value of the
+environment variable as it existed before envset was invoked.
+
+For other parameters the batch looks for the environment variable with the
+same name (in uppercase). If it is found, it forms the expanded_name. If
+the environment variable with such a name does not exist, the expanded_name
+will hold the parameter name without case conversion.
+*/
+
+parse arg mode envar args
+
+equal = 0
+sep = ' '
+
+/* Parse command line parameters */
+select
+  when mode='-' then do
+    sep = envar
+    parse var args envar args
+  end
+  when mode=';' then do
+    sep = ''
+    equal = -1
+  end
+  when mode='-D' then equal = 1
+  when mode='=D' then mode = '-D'
+  when mode=',' then sep = ','
+otherwise
+  args = envar args
+  envar = mode
+  mode = ''
+end
+
+env = 'OS2ENVIRONMENT'
+envar = translate(envar)
+orig = value(envar,,env)
+newval = ''
+expand = 1
+
+/* for each parameter... */
+do i = 1 to words(args)
+  if expand > 0 & word(args, i) = '-' then expand = 0
+  else call addval word(args, i)
+end
+
+/* Optionally enclose path variable by quotes */
+if mode = ';' & pos(' ', newval) > 0 then newval = '"' || newval || '"'
+
+/* Set the new value, 'SET' cannot be used since it does not allow '=' */
+x = value(envar, newval, env)
+exit 0
+
+addval: procedure expose sep equal orig expand newval mode env
+parse arg var
+
+if var = '.' then expvar = orig
+else do
+  if equal >= 0 then do
+    parse var var name '=' val
+    if val = '' then var = name
+    else var = val
+  end
+  if expand = 0 then expvar = var
+  else expvar = value(translate(var),,env)
+  if expvar = '' then expvar = var
+  if equal >= 0 then do
+    if val = '' then do
+      parse var expvar key '=' val
+      if val <> '' then name = key
+      else do
+        if equal > 0 then val = key
+        else name = key
+      end
+    end
+    else val = expvar
+    if pos(' ', val) > 0 | pos('=', val) > 0 then val = '"' || val || '"'
+    if val = '' then expvar = name
+    else expvar = name || '=' || val
+  end
+  if mode = '-D' then expvar = '-D' || expvar
+  if mode = ';' then do
+    if right(expvar, 1) <> ';' then expvar = expvar || ';'
+  end
+end
+
+if newval = '' then newval = expvar
+else newval = newval || sep || expvar
+expand = 1
+return
diff --git a/trunk/src/script/lcp.bat b/trunk/src/script/lcp.bat
new file mode 100755
index 0000000..4bf2e7c
--- /dev/null
+++ b/trunk/src/script/lcp.bat
@@ -0,0 +1,31 @@
+REM
+REM  Licensed to the Apache Software Foundation (ASF) under one or more
+REM  contributor license agreements.  See the NOTICE file distributed with
+REM  this work for additional information regarding copyright ownership.
+REM  The ASF licenses this file to You under the Apache License, Version 2.0
+REM  (the "License"); you may not use this file except in compliance with
+REM  the License.  You may obtain a copy of the License at
+REM 
+REM      http://www.apache.org/licenses/LICENSE-2.0
+REM 
+REM  Unless required by applicable law or agreed to in writing, software
+REM  distributed under the License is distributed on an "AS IS" BASIS,
+REM  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM  See the License for the specific language governing permissions and
+REM  limitations under the License.
+REM
+REM
+
+set _CLASSPATHCOMPONENT=%1
+if ""%1""=="""" goto gotAllArgs
+shift
+
+:argCheck
+if ""%1""=="""" goto gotAllArgs
+set _CLASSPATHCOMPONENT=%_CLASSPATHCOMPONENT% %1
+shift
+goto argCheck
+
+:gotAllArgs
+set LOCALCLASSPATH=%LOCALCLASSPATH%;%_CLASSPATHCOMPONENT%
+
diff --git a/trunk/src/script/runant.pl b/trunk/src/script/runant.pl
new file mode 100644
index 0000000..5f8307a
--- /dev/null
+++ b/trunk/src/script/runant.pl
@@ -0,0 +1,153 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#######################################################################
+#
+# runant.pl
+#
+# wrapper script for invoking ant in a platform with Perl installed
+# this may include cgi-bin invocation, which is considered somewhat daft.
+# (slo: that should be a separate file which can be derived from this
+# and returns the XML formatted output)
+#
+# the code is not totally portable due to classpath and directory splitting
+# issues. oops. (NB, use File::Spec::Functions  will help and the code is
+# structured for the catfile() call, but because of perl version funnies
+# the code is not included. 
+#
+# created:         2000-8-24
+# author:          Steve Loughran steve_l@sourceforge.net
+#######################################################################
+#
+# Assumptions:
+#
+# - the "java" executable/script is on the command path
+# - ANT_HOME has been set
+# - target platform uses ":" as classpath separator or perl indicates it is dos/win32
+# - target platform uses "/" as directory separator.
+
+#be fussy about variables
+use strict;
+
+#platform specifics (disabled)
+#use File::Spec::Functions;
+
+#turn warnings on during dev; generates a few spurious uninitialised var access warnings
+#use warnings;
+
+#and set $debug to 1 to turn on trace info
+my $debug=1;
+
+#######################################################################
+#
+# check to make sure environment is setup
+#
+
+my $HOME = $ENV{ANT_HOME};
+if ($HOME eq "")
+        {
+    die "\n\nANT_HOME *MUST* be set!\n\n";
+        }
+
+my $JAVACMD = $ENV{JAVACMD};
+$JAVACMD = "java" if $JAVACMD eq "";
+
+my $onnetware = 0;
+if ($^O eq "NetWare")
+{
+  $onnetware = 1;
+}
+
+my $oncygwin = ($^O eq "cygwin");
+
+#ISSUE: what java wants to split up classpath varies from platform to platform 
+#and perl is not too hot at hinting which box it is on.
+#here I assume ":" 'cept on win32, dos, and netware. Add extra tests here as needed.
+my $s=":";
+if(($^O eq "MSWin32") || ($^O eq "dos") || ($^O eq "cygwin") ||
+   ($onnetware == 1))
+        {
+        $s=";";
+        }
+
+#build up standard classpath
+my $localpath = "$HOME/lib/ant-launcher.jar";
+#set JVM options and Ant arguments, if any
+my @ANT_OPTS=split(" ", $ENV{ANT_OPTS});
+my @ANT_ARGS=split(" ", $ENV{ANT_ARGS});
+
+#jikes
+if($ENV{JIKESPATH} ne "")
+        {
+        push @ANT_OPTS, "-Djikes.class.path=$ENV{JIKESPATH}";
+        }
+
+#construct arguments to java
+my @ARGS;
+push @ARGS, @ANT_OPTS;
+
+my $CYGHOME = "";
+
+my $classpath=$ENV{CLASSPATH};
+if ($oncygwin == 1) {
+  $localpath = `cygpath --path --windows $localpath`;
+  chomp ($localpath);
+  if (! $classpath eq "")
+  {
+    $classpath = `cygpath --path --windows "$classpath"`;
+    chomp ($classpath);
+  }
+  $HOME = `cygpath --path --windows $HOME`;
+  chomp ($HOME);
+  $CYGHOME = `cygpath --path --windows $ENV{HOME}`;
+  chomp ($CYGHOME);
+}
+push @ARGS, "-classpath", "$localpath";
+push @ARGS, "-Dant.home=$HOME";
+if ( ! $CYGHOME eq "" )
+{
+  push @ARGS, "-Dcygwin.user.home=\"$CYGHOME\""
+}
+push @ARGS, "org.apache.tools.ant.launch.Launcher", @ANT_ARGS;
+push @ARGS, @ARGV;
+if (! $classpath eq "")
+{
+  if ($onnetware == 1)
+  {
+    # make classpath literally $CLASSPATH
+    # this is to avoid pushing us over the 512 character limit
+    # even skip the ; - that is already in $localpath
+    push @ARGS, "-lib", "\$CLASSPATH";
+  }
+  else
+  {
+    push @ARGS, "-lib", "$classpath";
+  }
+}
+print "\n $JAVACMD @ARGS\n\n" if ($debug);
+
+my $returnValue = system $JAVACMD, @ARGS;
+if ($returnValue eq 0)
+        {
+        exit 0;
+        }
+else
+        {
+        # only 0 and 1 are widely recognized as exit values
+        # so change the exit value to 1
+        exit 1;
+        }
diff --git a/trunk/src/script/runant.py b/trunk/src/script/runant.py
new file mode 100644
index 0000000..eec549e
--- /dev/null
+++ b/trunk/src/script/runant.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+# Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+"""
+
+ runant.py
+
+    This script is a translation of the runant.pl written by Steve Loughran.
+    It runs ant with/out arguments, it should be quite portable (thanks to
+    the python os library)
+    This script has been tested with Python2.0/Win2K
+
+ created:         2001-04-11
+ author:          Pierre Dittgen pierre.dittgen@criltelecom.com
+
+ Assumptions:
+
+ - the "java" executable/script is on the command path
+"""
+import os, os.path, string, sys
+
+# Change it to 1 to get extra debug information
+debug = 0
+
+#######################################################################
+
+# If ANT_HOME is not set default to script's parent directory
+if os.environ.has_key('ANT_HOME'):
+    ANT_HOME = os.environ['ANT_HOME']
+else:
+    ANT_HOME = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
+
+# set ANT_LIB location
+ANT_LIB = os.path.join(ANT_HOME, 'lib')
+
+# set JAVACMD (check variables JAVACMD and JAVA_HOME)
+JAVACMD = None
+if not os.environ.has_key('JAVACMD'):
+    if os.environ.has_key('JAVA_HOME'):
+        if not os.path.exists(os.environ['JAVA_HOME']):
+            print "Warning: JAVA_HOME is not defined correctly."
+        else:
+            JAVACMD = os.path.join(os.environ['JAVA_HOME'], 'bin', 'java')
+    else:
+        print "Warning: JAVA_HOME not set."
+else:
+    JAVACMD = os.environ['JAVACMD']
+if not JAVACMD:
+    JAVACMD = 'java'
+
+launcher_jar = os.path.join(ANT_LIB, 'ant-launcher.jar')
+if not os.path.exists(launcher_jar):
+    print 'Unable to locate ant-launcher.jar. Expected to find it in %s' % \
+        ANT_LIB
+
+# Build up standard classpath (LOCALCLASSPATH)
+LOCALCLASSPATH = launcher_jar
+if os.environ.has_key('LOCALCLASSPATH'):
+    LOCALCLASSPATH += os.pathsep + os.environ['LOCALCLASSPATH']
+
+ANT_OPTS = ""
+if os.environ.has_key('ANT_OPTS'):
+    ANT_OPTS = os.environ['ANT_OPTS']
+
+OPTS = ""
+if os.environ.has_key('JIKESPATH'):
+    OPTS = '-Djikes.class.path=\"%s\"' % os.environ['JIKESPATH']
+
+ANT_ARGS = ""
+if os.environ.has_key('ANT_ARGS'):
+    ANT_ARGS = os.environ['ANT_ARGS']
+
+CLASSPATH = ""
+if os.environ.has_key('CLASSPATH'):
+    CLASSPATH = os.environ['CLASSPATH']
+
+# Builds the commandline
+cmdline = ('%s %s -classpath %s -Dant.home=%s %s ' + \
+    'org.apache.tools.ant.launch.Launcher %s -lib %s %s') \
+     % (JAVACMD, ANT_OPTS, LOCALCLASSPATH, ANT_HOME, OPTS, ANT_ARGS, \
+        CLASSPATH, string.join(sys.argv[1:], ' '))
+
+if debug:
+    print '\n%s\n\n' % (cmdline)
+sys.stdout.flush()
+
+# Run the biniou!
+os.system(cmdline)
diff --git a/trunk/src/script/runrc.cmd b/trunk/src/script/runrc.cmd
new file mode 100644
index 0000000..c68f04d
--- /dev/null
+++ b/trunk/src/script/runrc.cmd
@@ -0,0 +1,60 @@
+/* 
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+   Run RC file, name is in the first arg, second arg is either PATH
+   ENV  or -r or nothing 
+*/
+
+parse arg name path rest
+
+if name = '' then do
+  say 'RC file name is missing'
+  exit 1
+end
+
+if rest \= '' then do
+  say 'Too many parameters'
+  exit 1
+end
+
+call runit name path
+exit 0
+
+runit: procedure
+parse arg name path dir
+
+if path \= '' & path \= '-r' then do
+  dir = value(translate(path),,'OS2ENVIRONMENT')
+  if dir = '' then return
+  dir = translate(dir, '\', '/') /* change UNIX-like path to OS/2 */
+end
+
+if dir = '' then dir = directory()
+
+if path = '-r' then do /* recursive call */
+  subdir = filespec('path', dir)
+  if subdir \= '\' then do
+    subdir = left(subdir, length(subdir)-1)
+    call runit name path filespec('drive', dir) || subdir
+  end
+end
+
+/* Look for the file and run it */
+if right(dir, 1) \= '\' then dir = dir || '\'
+rcfile = stream(dir || name, 'c', 'query exists')
+if rcfile \= '' then interpret 'call "' || rcfile || '"'
+
+return
diff --git a/trunk/src/tests/antunit/antunit-base.xml b/trunk/src/tests/antunit/antunit-base.xml
new file mode 100644
index 0000000..4600892
--- /dev/null
+++ b/trunk/src/tests/antunit/antunit-base.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="antunit-base">
+
+  <target name="antunit">
+    <antunit xmlns="antlib:org.apache.ant.antunit">
+      <plainlistener />
+      <file file="${ant.file}" xmlns="antlib:org.apache.tools.ant" />
+    </antunit>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/bugfixes/README.txt b/trunk/src/tests/antunit/bugfixes/README.txt
new file mode 100644
index 0000000..c2b5e5d
--- /dev/null
+++ b/trunk/src/tests/antunit/bugfixes/README.txt
@@ -0,0 +1,2 @@
+This directory contains tests for the bugs
+that have been fixed.
diff --git a/trunk/src/tests/antunit/bugfixes/bugzilla-43324-stackoverflow-test.xml b/trunk/src/tests/antunit/bugfixes/bugzilla-43324-stackoverflow-test.xml
new file mode 100644
index 0000000..d706b8f
--- /dev/null
+++ b/trunk/src/tests/antunit/bugfixes/bugzilla-43324-stackoverflow-test.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="length-test" default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../antunit-base.xml" />
+
+  <target name="testnested">
+    <macrodef name="root-macro">
+      <element name="sub-tasks" optional="false" />
+
+      <sequential>
+        <!-- do stuff -->
+        <sub-tasks />
+      </sequential>
+    </macrodef>
+
+    <macrodef name="used-macro-a">
+      <element name="a-sub-tasks" optional="false" implicit="true" />
+
+      <sequential>
+        <root-macro>
+          <sub-tasks>
+            <!-- do stuff -->
+            <a-sub-tasks />
+          </sub-tasks>
+        </root-macro>
+      </sequential>
+    </macrodef>
+
+    <macrodef name="used-macro-b">
+      <element name="b-sub-tasks" optional="false" implicit="true" />
+
+      <sequential>
+        <used-macro-a>
+          <root-macro>
+            <sub-tasks>
+              <!-- do stuff -->
+              <b-sub-tasks />
+            </sub-tasks>
+          </root-macro>
+        </used-macro-a>
+      </sequential>
+    </macrodef>
+
+    <used-macro-b>
+      <echo message="Test B" />
+    </used-macro-b>
+
+    <au:assertLogContains text="Test B"/>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/core/location/location.xml b/trunk/src/tests/antunit/core/location/location.xml
new file mode 100644
index 0000000..74c9ff0
--- /dev/null
+++ b/trunk/src/tests/antunit/core/location/location.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="location-test" basedir="." default="all"

+       xmlns:au="antlib:org.apache.ant.antunit">

+       

+  <property name="ant.build.dir" location="../../../../../build"/>

+  <property name="working.dir"

+            location="${ant.build.dir}/ant-unit/location-dir"/>

+  <property name="classes.dir" location="${working.dir}/classes"/>

+  

+  <target name="all">

+    <au:antunit>

+      <fileset file="${ant.file}"/>

+      <au:plainlistener/>

+    </au:antunit>

+  </target>

+  

+  <target name="setUp">

+    <mkdir dir="${classes.dir}"/>

+    <javac srcdir="src" destdir="${classes.dir}" debug="yes"/>

+    <taskdef name="echo-location" classname="task.EchoLocation"

+             classpath="${classes.dir}"/>

+  </target>

+  

+  <target name="define">

+    <taskdef name="echoloc"

+      classname="task.EchoLocation">

+      <classpath>

+        <pathelement location="${classes.dir}" />

+        <pathelement path="${java.class.path}"/>

+      </classpath>

+    </taskdef>

+  </target>

+  

+  <target name="macrodef" depends="define">

+    <macrodef name="echoloc2" backtrace="false">

+      <sequential>

+        <echoloc/>

+      </sequential>

+    </macrodef>

+  </target>

+  

+  <target name="presetdef" depends="define">

+    <presetdef name="echoloc3">

+      <echoloc/>

+    </presetdef>

+  </target>

+  

+  <target name="tearDown">

+    <delete dir="${working.dir}"/>

+  </target>

+  

+  <target name="test-plain-task">

+    <echo id="echo">Hello</echo>

+    <au:assertLogContains text="Hello"/>

+  </target>

+  

+  <target name="test-standalone-type">

+    <!-- TODO -->

+  </target>

+  

+  <target name="test-condition-task">

+    <!-- TODO -->

+  </target>

+  

+  <target name="test-macrodef-wrapped-task" depends="macrodef">

+    <echo id="echo3">Hello</echo>

+    <echoloc2/>

+    <au:assertLogContains text="Line: "/>

+  </target>

+  

+  <target name="test-presetdef-wrapped-task" depends="presetdef">

+    <echo id="echo4">Hello</echo>

+    <echoloc3/>

+    <au:assertLogContains text="Line: "/>

+  </target>

+  

+</project>

diff --git a/trunk/src/tests/antunit/core/location/src/task/EchoLocation.java b/trunk/src/tests/antunit/core/location/src/task/EchoLocation.java
new file mode 100644
index 0000000..9743c52
--- /dev/null
+++ b/trunk/src/tests/antunit/core/location/src/task/EchoLocation.java
@@ -0,0 +1,26 @@
+/*

+Licensed to the Apache Software Foundation (ASF) under one or more

+contributor license agreements.  See the NOTICE file distributed with

+this work for additional information regarding copyright ownership.

+The ASF licenses this file to You under the Apache License, Version 2.0

+(the "License"); you may not use this file except in compliance with

+the License.  You may obtain a copy of the License at

+

+    http://www.apache.org/licenses/LICENSE-2.0

+

+Unless required by applicable law or agreed to in writing, software

+distributed under the License is distributed on an "AS IS" BASIS,

+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+See the License for the specific language governing permissions and

+limitations under the License.

+*/

+package task;

+

+import org.apache.tools.ant.Project;

+import org.apache.tools.ant.Task;

+

+public class EchoLocation extends Task {

+	public void execute() {

+        log("Line: " + getLocation().getLineNumber(), Project.MSG_INFO);

+    }

+}
\ No newline at end of file
diff --git a/trunk/src/tests/antunit/core/nested-text-test.xml b/trunk/src/tests/antunit/core/nested-text-test.xml
new file mode 100644
index 0000000..0a93b5b
--- /dev/null
+++ b/trunk/src/tests/antunit/core/nested-text-test.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+
+  <target name="testAcceptNested">
+    <echo>foo</echo>
+  </target>
+
+  <target name="testRejectNested">
+    <typedef name="object" classname="java.lang.Object" />
+    <au:expectfailure expectedMessage="The &lt;object&gt; type doesn't support nested text data (&quot;foo&quot;).">
+      <object>foo</object>
+    </au:expectfailure>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/core/ref-psyntax-hint.xml b/trunk/src/tests/antunit/core/ref-psyntax-hint.xml
new file mode 100644
index 0000000..055217c
--- /dev/null
+++ b/trunk/src/tests/antunit/core/ref-psyntax-hint.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <target name="testIt">
+    <au:expectfailure>
+      <pathconvert refid="${foo}" />
+    </au:expectfailure>
+    <au:assertLogContains level="warning"
+      text="Unresolvable reference $${foo} might be a misuse of property expansion syntax." />
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/core/uuencode/src/task/BaseTask.java b/trunk/src/tests/antunit/core/uuencode/src/task/BaseTask.java
new file mode 100644
index 0000000..22fb70e
--- /dev/null
+++ b/trunk/src/tests/antunit/core/uuencode/src/task/BaseTask.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package task;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Base class for the uuencode/decode test tasks.
+ */
+abstract public class BaseTask extends Task {
+    private final static FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private File inFile;
+    private File outFile;
+
+    public void setInFile(File inFile) {
+        this.inFile = inFile;
+    }
+    protected File getInFile() {
+        return inFile;
+    }
+    public void setOutFile(File outFile) {
+        this.outFile = outFile;
+    }
+    protected File getOutFile() {
+        return outFile;
+    }
+    public void execute() {
+        assertAttribute(inFile, "inFile");
+        assertAttribute(outFile, "outFile");
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+            inputStream = new BufferedInputStream(
+                new FileInputStream(getInFile()));
+            outputStream = new FileOutputStream(getOutFile());
+            doit(inputStream, outputStream);
+        } catch (Exception ex) {
+            throw new BuildException(ex);
+        } finally {
+            FILE_UTILS.close(inputStream);
+            FILE_UTILS.close(outputStream);
+        }
+    }
+    
+    abstract protected void doit(
+        InputStream is, OutputStream os) throws Exception;
+    
+    private void assertAttribute(File file, String attributeName) {
+        if (file == null) {
+            throw new BuildException("Required attribute " + attributeName
+                                     + " not set");
+        }
+    }
+}
+
+    
diff --git a/trunk/src/tests/antunit/core/uuencode/src/task/UUDecodeTask.java b/trunk/src/tests/antunit/core/uuencode/src/task/UUDecodeTask.java
new file mode 100644
index 0000000..8423f8c
--- /dev/null
+++ b/trunk/src/tests/antunit/core/uuencode/src/task/UUDecodeTask.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package task;
+import java.io.InputStream;
+import java.io.OutputStream;
+import sun.misc.UUDecoder;
+
+/**
+ * Decodes a uuencoded file using sun.misc.UUDecoder.
+ */
+public class UUDecodeTask extends BaseTask {
+    protected void doit(InputStream is, OutputStream os) throws Exception {
+        new UUDecoder().decodeBuffer(is, os);
+    }
+}
+    
diff --git a/trunk/src/tests/antunit/core/uuencode/src/task/UUEncodeTask.java b/trunk/src/tests/antunit/core/uuencode/src/task/UUEncodeTask.java
new file mode 100644
index 0000000..2b878f8
--- /dev/null
+++ b/trunk/src/tests/antunit/core/uuencode/src/task/UUEncodeTask.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package task;
+import org.apache.tools.ant.util.UUEncoder;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * UUEncodes a file using org.apache.tools.ant.util.UUEncoder.
+ */
+public class UUEncodeTask extends BaseTask {
+    protected void doit(InputStream is, OutputStream os) throws Exception {
+        new UUEncoder(getInFile().getName()).encode(is, os);
+    }
+}
diff --git a/trunk/src/tests/antunit/core/uuencode/uuencode-test.xml b/trunk/src/tests/antunit/core/uuencode/uuencode-test.xml
new file mode 100644
index 0000000..e42e227
--- /dev/null
+++ b/trunk/src/tests/antunit/core/uuencode/uuencode-test.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit">
+  <property name="ant.build.dir" location="../../../../../build"/>
+  <property name="my.build.dir"
+            location="${ant.build.dir}/ant-unit/uuencode-dir"/>
+  <property name="classes.dir" location="${my.build.dir}/classes"/>
+
+  <available property="sun.uudecode.avail" classname="sun.misc.UUDecoder"/>
+
+  <target name="define" if="sun.uudecode.avail">
+    <mkdir dir="${classes.dir}"/>
+    <javac srcdir="src" destdir="${classes.dir}" debug="yes"/>
+    <taskdef name="uuencode" classname="task.UUEncodeTask"
+             classpath="${classes.dir}"/>
+    <taskdef name="uudecode" classname="task.UUDecodeTask"
+             classpath="${classes.dir}"/>
+  </target>
+
+  <target name="test-simple" depends="define" if="sun.uudecode.avail">
+    <uuencode infile="${ant.file}"
+              outfile="${my.build.dir}/uuencoded"/>
+    <uudecode infile="${my.build.dir}/uuencoded"
+              outfile="${my.build.dir}/decoded"/>
+    <au:assertTrue>
+      <filesmatch file1="${ant.file}" file2="${my.build.dir}/decoded"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset file="${ant.file}"/>
+      <au:plainlistener/>
+    </au:antunit>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/filters/striplinecomments-test.xml b/trunk/src/tests/antunit/filters/striplinecomments-test.xml
new file mode 100644
index 0000000..2af0f01
--- /dev/null
+++ b/trunk/src/tests/antunit/filters/striplinecomments-test.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <property name="br" value="${line.separator}" />
+
+  <string id="input">foo
+#pound
+bar
+//java sl
+baz
+REMark
+</string>
+
+  <macrodef name="test">
+    <attribute name="lines" />
+    <element name="comments" implicit="true" />
+    <sequential>
+      <au:assertTrue>
+        <resourcecount count="@{lines}">
+          <tokens>
+            <concat>
+              <resource refid="input" />
+              <filterchain>
+                <striplinecomments>
+                  <comments />
+                </striplinecomments>
+                <ignoreblank />
+              </filterchain>
+            </concat>
+          </tokens>
+        </resourcecount>
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <target name="testBasic">
+    <test lines="5">
+      <comment value="#" />
+    </test>
+  </target>
+
+  <target name="testMultiple">
+    <test lines="3">
+      <comment value="#" />
+      <comment value="//" />
+      <comment value="REM" />
+    </test>
+  </target>
+
+  <target name="testNestedText">
+    <test lines="3">
+      <comment>#</comment>
+      <comment>//</comment>
+      <comment>REM</comment>
+    </test>
+  </target>
+
+  <target name="testExclusivity">
+    <au:expectfailure>
+      <filterchain>
+        <striplinecomments>
+          <comment value="#">#"</comment>
+        </striplinecomments>
+      </filterchain>
+    </au:expectfailure>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/junit-frames.xsl b/trunk/src/tests/antunit/junit-frames.xsl
new file mode 100644
index 0000000..9fab285
--- /dev/null
+++ b/trunk/src/tests/antunit/junit-frames.xsl
@@ -0,0 +1,889 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+    xmlns:lxslt="http://xml.apache.org/xslt"
+    xmlns:redirect="http://xml.apache.org/xalan/redirect"
+    xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils"
+    extension-element-prefixes="redirect">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"/>
+<xsl:decimal-format decimal-separator="." grouping-separator=","/>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a set of HTML files a la javadoc where you can browse easily
+ through all directories and projects.
+
+-->
+<xsl:param name="output.dir" select="'.'"/>
+
+
+<xsl:template match="testsuites">
+    <!-- create the index.html -->
+    <redirect:write file="{$output.dir}/index.html">
+        <xsl:call-template name="index.html"/>
+    </redirect:write>
+
+    <!-- create the stylesheet.css -->
+    <redirect:write file="{$output.dir}/stylesheet.css">
+        <xsl:call-template name="stylesheet.css"/>
+    </redirect:write>
+
+    <!-- create the overview-directories.html at the root -->
+    <redirect:write file="{$output.dir}/overview-summary.html">
+        <xsl:apply-templates select="." mode="overview.directories"/>
+    </redirect:write>
+
+    <!-- create the all-directories.html at the root -->
+    <redirect:write file="{$output.dir}/overview-frame.html">
+        <xsl:apply-templates select="." mode="all.directories"/>
+    </redirect:write>
+
+    <!-- create the all-projects.html at the root -->
+    <redirect:write file="{$output.dir}/allprojects-frame.html">
+        <xsl:apply-templates select="." mode="all.projects"/>
+    </redirect:write>
+
+    <!-- create the all-tests.html at the root -->
+    <redirect:write file="{$output.dir}/all-tests.html">
+        <xsl:apply-templates select="." mode="all.tests"/>
+    </redirect:write>
+
+    <!-- create the alltests-fails.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-fails.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'fails'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- create the alltests-errors.html at the root -->
+    <redirect:write file="{$output.dir}/alltests-errors.html">
+      <xsl:apply-templates select="." mode="all.tests">
+        <xsl:with-param name="type" select="'errors'"/>
+      </xsl:apply-templates>
+    </redirect:write>
+
+  <!-- process all directories -->
+    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+        <xsl:call-template name="directory">
+            <xsl:with-param name="name" select="@package"/>
+        </xsl:call-template>
+    </xsl:for-each>
+</xsl:template>
+
+
+<xsl:template name="directory">
+    <xsl:param name="name"/>
+    <xsl:variable name="directory.dir">
+        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if>
+        <xsl:if test="$name = ''">.</xsl:if>
+    </xsl:variable>
+    <!--Processing directory <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> -->
+    <!-- create a projects-list.html in the directory directory -->
+    <redirect:write file="{$output.dir}/{$directory.dir}/directory-frame.html">
+        <xsl:call-template name="projects.list">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- create a directory-summary.html in the directory directory -->
+    <redirect:write file="{$output.dir}/{$directory.dir}/directory-summary.html">
+        <xsl:call-template name="directory.summary">
+            <xsl:with-param name="name" select="$name"/>
+        </xsl:call-template>
+    </redirect:write>
+
+    <!-- for each project, creates a @name.html -->
+    <!-- @bug there will be a problem with inner projects having the same name, it will be overwritten -->
+  <xsl:for-each select="/testsuites/testsuite[@package = $name]">
+    <redirect:write file="{$output.dir}/{$directory.dir}/{@id}_{@name}.html">
+      <xsl:apply-templates select="." mode="project.details"/>
+    </redirect:write>
+    <xsl:if test="string-length(./system-out)!=0">
+      <redirect:write file="{$output.dir}/{$directory.dir}/{@id}_{@name}-out.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-out"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="string-length(./system-err)!=0">
+      <redirect:write file="{$output.dir}/{$directory.dir}/{@id}_{@name}-err.txt">
+        <xsl:value-of disable-output-escaping="yes" select="./system-err"/>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="failures/text() != 0">
+      <redirect:write file="{$output.dir}/{$directory.dir}/{@id}_{@name}-fails.html">
+        <xsl:apply-templates select="." mode="project.details">
+          <xsl:with-param name="type" select="'fails'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+    <xsl:if test="errors/text() != 0">
+      <redirect:write file="{$output.dir}/{$directory.dir}/{@id}_{@name}-errors.html">
+        <xsl:apply-templates select="." mode="project.details">
+          <xsl:with-param name="type" select="'errors'"/>
+        </xsl:apply-templates>
+      </redirect:write>
+    </xsl:if>
+  </xsl:for-each>
+</xsl:template>
+
+<xsl:template name="index.html">
+<html>
+    <head>
+        <title>AntUnit Test Results.</title>
+    </head>
+    <frameset cols="20%,80%">
+        <frameset rows="30%,70%">
+            <frame src="overview-frame.html" name="directoryListFrame"/>
+            <frame src="allprojects-frame.html" name="projectListFrame"/>
+        </frameset>
+        <frame src="overview-summary.html" name="projectFrame"/>
+        <noframes>
+            <h2>Frame Alert</h2>
+            <p>
+                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
+            </p>
+        </noframes>
+    </frameset>
+</html>
+</xsl:template>
+
+<!-- this is the stylesheet css to use for nearly everything -->
+<xsl:template name="stylesheet.css">
+body {
+    font:normal 68% verdana,arial,helvetica;
+    color:#000000;
+}
+table tr td, table tr th {
+    font-size: 68%;
+}
+table.details tr th{
+    font-weight: bold;
+    text-align:left;
+    background:#a6caf0;
+}
+table.details tr td{
+    background:#eeeee0;
+}
+
+p {
+    line-height:1.5em;
+    margin-top:0.5em; margin-bottom:1.0em;
+}
+h1 {
+    margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+}
+h2 {
+    margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+}
+h3 {
+    margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+}
+h4 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h5 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+h6 {
+    margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+}
+.Error {
+    font-weight:bold; color:red;
+}
+.Failure {
+    font-weight:bold; color:purple;
+}
+.Properties {
+  text-align:right;
+}
+</xsl:template>
+
+<!-- Create list of all/failed/errored tests -->
+<xsl:template match="testsuites" mode="all.tests">
+    <xsl:param name="type" select="'all'"/>
+    <html>
+	<xsl:variable name="title">
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <xsl:text>All Failures</xsl:text>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <xsl:text>All Errors</xsl:text>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:text>All Tests</xsl:text>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</xsl:variable>
+	<head>
+	    <title>AntUnit Test Results: <xsl:value-of select="$title"/></title>
+	    <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name"/>
+            </xsl:call-template>
+	</head>
+	<body>
+	    <xsl:attribute name="onload">open('allprojects-frame.html','projectListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h2><xsl:value-of select="$title"/></h2>
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header">
+		    <xsl:with-param name="show.project" select="'yes'"/>
+		</xsl:call-template>
+		<!--
+                test can even not be started at all (failure to load the project)
+		so report the error directly
+		-->
+              <xsl:if test="./error">
+                <tr class="Error">
+                  <td colspan="4">
+                    <xsl:apply-templates select="./error"/>
+                  </td>
+                </tr>
+              </xsl:if>
+              <xsl:choose>
+                <xsl:when test="$type = 'fails'">
+                  <xsl:apply-templates select=".//testcase[failure]" mode="print.test">
+                    <xsl:with-param name="show.project" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:when test="$type = 'errors'">
+                  <xsl:apply-templates select=".//testcase[error]" mode="print.test">
+                    <xsl:with-param name="show.project" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:when>
+                <xsl:otherwise>
+                  <xsl:apply-templates select=".//testcase" mode="print.test">
+                    <xsl:with-param name="show.project" select="'yes'"/>
+                  </xsl:apply-templates>
+                </xsl:otherwise>
+              </xsl:choose>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every testsuite project.
+    It prints a summary of the testsuite and detailed information about
+    testcase methods.
+     ====================================================================== -->
+<xsl:template match="testsuite" mode="project.details">
+    <xsl:param name="type" select="'all'"/>
+    <xsl:variable name="directory.name" select="@package"/>
+    <xsl:variable name="project.name"><xsl:if test="not($directory.name = '')"><xsl:value-of select="$directory.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable>
+    <html>
+        <head>
+          <title>AntUnit Test Results: <xsl:value-of select="$project.name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name" select="$directory.name"/>
+            </xsl:call-template>
+       <script type="text/javascript" language="JavaScript">
+        var TestCases = new Array();
+        var cur;
+        <xsl:apply-templates select="properties"/>
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style type=\"text/css\">");
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in TestCases[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + TestCases[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+        </head>
+        <body>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Project <xsl:value-of select="$project.name"/></h3>
+
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="testsuite.test.header"/>
+                <xsl:apply-templates select="." mode="print.test"/>
+            </table>
+
+	    <xsl:choose>
+		<xsl:when test="$type = 'fails'">
+		    <h2>Failures</h2>
+		</xsl:when>
+		<xsl:when test="$type = 'errors'">
+		    <h2>Errors</h2>
+		</xsl:when>
+		<xsl:otherwise>
+		    <h2>Tests</h2>
+		</xsl:otherwise>
+	    </xsl:choose>
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+		<xsl:call-template name="testcase.test.header"/>
+		<!--
+                test can even not be started at all (failure to load the project)
+		so report the error directly
+		-->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+		<xsl:choose>
+		    <xsl:when test="$type = 'fails'">
+			<xsl:apply-templates select="./testcase[failure]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:when test="$type = 'errors'">
+			<xsl:apply-templates select="./testcase[error]" mode="print.test"/>
+		    </xsl:when>
+		    <xsl:otherwise>
+			<xsl:apply-templates select="./testcase" mode="print.test"/>
+		    </xsl:otherwise>
+		</xsl:choose>
+            </table>
+            <!--div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            <xsl:if test="string-length(./system-out)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-out.txt</xsl:attribute>
+                        System.out &#187;
+                    </a>
+                </div>
+            </xsl:if>
+            <xsl:if test="string-length(./system-err)!=0">
+                <div class="Properties">
+                    <a>
+                        <xsl:attribute name="href">./<xsl:value-of select="@id"/>_<xsl:value-of select="@name"/>-err.txt</xsl:attribute>
+                        System.err &#187;
+                    </a>
+                </div>
+            </xsl:if-->
+        </body>
+    </html>
+</xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <xsl:template match="properties">
+    cur = TestCases['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+
+
+<!-- ======================================================================
+    This page is created for every directory.
+    It prints the name of all projects that belongs to this directory.
+    @param name the directory name to print projects.
+     ====================================================================== -->
+<!-- list of projects in a directory -->
+<xsl:template name="projects.list">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <title>AntUnit Test Projects: <xsl:value-of select="$name"/></title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <table width="100%">
+                <tr>
+                    <td nowrap="nowrap">
+                        <h2><a href="directory-summary.html" target="projectFrame">
+                            <xsl:value-of select="$name"/>
+                            <xsl:if test="$name = ''">&lt;none&gt;</xsl:if>
+                        </a></h2>
+                    </td>
+                </tr>
+            </table>
+
+            <h2>Projects</h2>
+            <table width="100%">
+                <xsl:for-each select="/testsuites/testsuite[./@package = $name]">
+                    <xsl:sort select="@name"/>
+                    <tr>
+                        <td nowrap="nowrap">
+                            <a href="{@id}_{@name}.html" target="projectFrame"><xsl:value-of select="@name"/></a>
+                        </td>
+                    </tr>
+                </xsl:for-each>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    Creates an all-projects.html file that contains a link to all directory-summary.html
+    on each project.
+-->
+<xsl:template match="testsuites" mode="all.projects">
+    <html>
+        <head>
+            <title>All AntUnit Test Projects</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2>Projects</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite" mode="all.projects">
+                    <xsl:sort select="@name"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.projects">
+    <xsl:variable name="directory.name" select="@package"/>
+    <tr>
+        <td nowrap="nowrap">
+            <a target="projectFrame">
+                <xsl:attribute name="href">
+                    <xsl:if test="not($directory.name='')">
+                        <xsl:value-of select="translate($directory.name,'.','/')"/><xsl:text>/</xsl:text>
+                    </xsl:if><xsl:value-of select="@id"/>_<xsl:value-of select="@name"/><xsl:text>.html</xsl:text>
+                </xsl:attribute>
+                <xsl:value-of select="@name"/>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!--
+    Creates an html file that contains a link to all directory-summary.html files on
+    each directory existing on testsuites.
+    @bug there will be a problem here, I don't know yet how to handle unnamed directory :(
+-->
+<xsl:template match="testsuites" mode="all.directories">
+    <html>
+        <head>
+            <title>All AntUnit Test Directories</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <h2><a href="overview-summary.html" target="projectFrame">Home</a></h2>
+            <h2>Directories</h2>
+            <table width="100%">
+                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.directories">
+                    <xsl:sort select="@package"/>
+                </xsl:apply-templates>
+            </table>
+        </body>
+    </html>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="all.directories">
+    <tr>
+        <td nowrap="nowrap">
+            <a href="./{translate(@package,'.','/')}/directory-summary.html" target="projectFrame">
+                <xsl:value-of select="@package"/>
+                <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+            </a>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.directories">
+    <html>
+        <head>
+            <title>AntUnit Test Results: Summary</title>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+        <xsl:attribute name="onload">open('allprojects-frame.html','projectListFrame')</xsl:attribute>
+        <xsl:call-template name="pageHeader"/>
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/tests/text())"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/errors/text())"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/failures/text())"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/time/text())"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:otherwise>Pass</xsl:otherwise>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><a title="Display all tests" href="all-tests.html"><xsl:value-of select="$testCount"/></a></td>
+            <td><a title="Display all failures" href="alltests-fails.html"><xsl:value-of select="$failureCount"/></a></td>
+            <td><a title="Display all errors" href="alltests-errors.html"><xsl:value-of select="$errorCount"/></a></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated.
+        </td>
+        </tr>
+        </table>
+
+        <h2>Directories</h2>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package" order="ascending"/>
+                <!-- get the node set containing all testsuites that have the same directory -->
+                <xsl:variable name="insamedirectory" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <tr valign="top">
+                    <!-- display a failure if there is any failure/error in the directory -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="sum($insamedirectory/errors/text()) &gt; 0">Error</xsl:when>
+                            <xsl:when test="sum($insamedirectory/failures/text()) &gt; 0">Failure</xsl:when>
+                            <xsl:otherwise>Pass</xsl:otherwise>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="./{translate(@package,'.','/')}/directory-summary.html">
+                        <xsl:value-of select="@package"/>
+                        <xsl:if test="@package = ''">&lt;none&gt;</xsl:if>
+                    </a></td>
+                    <td><xsl:value-of select="sum($insamedirectory/tests/text())"/></td>
+                    <td><xsl:value-of select="sum($insamedirectory/errors/text())"/></td>
+                    <td><xsl:value-of select="sum($insamedirectory/failures/text())"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="sum($insamedirectory/time/text())"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$insamedirectory/@timestamp"/></td>
+                    <td><xsl:value-of select="$insamedirectory/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+        </body>
+        </html>
+</xsl:template>
+
+
+<xsl:template name="directory.summary">
+    <xsl:param name="name"/>
+    <html>
+        <head>
+            <xsl:call-template name="create.stylesheet.link">
+                <xsl:with-param name="directory.name" select="$name"/>
+            </xsl:call-template>
+        </head>
+        <body>
+            <xsl:attribute name="onload">open('directory-frame.html','projectListFrame')</xsl:attribute>
+            <xsl:call-template name="pageHeader"/>
+            <h3>Directory <xsl:value-of select="$name"/></h3>
+
+            <!--table border="0" cellpadding="5" cellspacing="2" width="95%">
+                <xsl:call-template name="project.metrics.header"/>
+                <xsl:apply-templates select="." mode="print.metrics"/>
+            </table-->
+
+            <xsl:variable name="insamedirectory" select="/testsuites/testsuite[./@package = $name]"/>
+            <xsl:if test="count($insamedirectory) &gt; 0">
+                <h2>Projects</h2>
+                <p>
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+                    <xsl:apply-templates select="$insamedirectory" mode="print.test">
+                        <xsl:sort select="@name"/>
+                    </xsl:apply-templates>
+                </table>
+                </p>
+            </xsl:if>
+        </body>
+    </html>
+</xsl:template>
+
+
+<!--
+    transform string like a.b.c to ../../../
+    @param path the path to transform into a descending directory path
+-->
+<xsl:template name="path">
+    <xsl:param name="path"/>
+    <xsl:if test="contains($path,'.')">
+        <xsl:text>../</xsl:text>
+        <xsl:call-template name="path">
+            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param>
+        </xsl:call-template>
+    </xsl:if>
+    <xsl:if test="not(contains($path,'.')) and not($path = '')">
+        <xsl:text>../</xsl:text>
+    </xsl:if>
+</xsl:template>
+
+
+<!-- create the link to the stylesheet based on the directory name -->
+<xsl:template name="create.stylesheet.link">
+    <xsl:param name="directory.name"/>
+    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($directory.name = 'unnamed directory')"><xsl:call-template name="path"><xsl:with-param name="path" select="$directory.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link>
+</xsl:template>
+
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1>AntUnit Test Results</h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href="http://ant.apache.org/antlibs/antunit/">AntUnit</a> and <a href="http://ant.apache.org/">Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<!-- project header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <xsl:param name="show.project" select="''"/>
+    <tr valign="top">
+	<xsl:if test="boolean($show.project)">
+	    <th>Project</th>
+	</xsl:if>
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- project information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="errors/text()[.&gt; 0]">Error</xsl:when>
+                <xsl:when test="failures/text()[.&gt; 0]">Failure</xsl:when>
+                <xsl:otherwise>Pass</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:value-of select="@name"/></a></td>
+        <td><a title="Display all tests" href="{@id}_{@name}.html"><xsl:apply-templates select="tests/text()"/></a></td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="errors/text() != 0">
+		    <a title="Display only errors" href="{@id}_{@name}-errors.html"><xsl:apply-templates select="errors/text()"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="errors/text()"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td>
+	    <xsl:choose>
+		<xsl:when test="failures/text() != 0">
+		    <a title="Display only failures" href="{@id}_{@name}-fails.html"><xsl:apply-templates select="failures/text()"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:apply-templates select="failures/text()"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <td><xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="time/text()"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <xsl:param name="show.project" select="''"/>
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+	<xsl:variable name="project.href">
+	    <xsl:value-of select="concat(translate(../@package,'.','/'), '/', ../@id, '_', ../@name, '.html')"/>
+	</xsl:variable>
+	<xsl:if test="boolean($show.project)">
+	    <td><a href="{$project.href}"><xsl:value-of select="../@name"/></a></td>
+	</xsl:if>
+        <td>
+	    <a name="{@name}"/>
+	    <xsl:choose>
+		<xsl:when test="boolean($show.project)">
+		    <a href="{concat($project.href, '#', @name)}"><xsl:value-of select="@name"/></a>
+		</xsl:when>
+		<xsl:otherwise>
+		    <xsl:value-of select="@name"/>
+		</xsl:otherwise>
+	    </xsl:choose>
+	</td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="time/text()"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<!-- Note : the below template error and failure are the same style
+            so just call the same style store in the toolkit template -->
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<!-- Style for the error and failure in the testcase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <xsl:choose>
+        <xsl:when test="@linenumber">
+            <br></br>
+            at line <xsl:value-of select="@linenumber"/>
+            <xsl:choose>
+                <xsl:when test="@columnnumber">
+                    , column <xsl:value-of select="@columnnumber"/>
+                </xsl:when>
+            </xsl:choose>
+        </xsl:when>
+    </xsl:choose>
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/trunk/src/tests/antunit/junit-noframes.xsl b/trunk/src/tests/antunit/junit-noframes.xsl
new file mode 100644
index 0000000..255046a
--- /dev/null
+++ b/trunk/src/tests/antunit/junit-noframes.xsl
@@ -0,0 +1,485 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+        xmlns:lxslt="http://xml.apache.org/xslt"
+        xmlns:stringutils="xalan://org.apache.tools.ant.util.StringUtils">
+<xsl:output method="html" indent="yes" encoding="US-ASCII"
+  doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" />
+<xsl:decimal-format decimal-separator="." grouping-separator="," />
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<!--
+
+ Sample stylesheet to be used with Ant JUnitReport output.
+
+ It creates a non-framed report that can be useful to send via
+ e-mail or such.
+
+-->
+<xsl:template match="testsuites">
+    <html>
+        <head>
+            <title>AntUnit Test Results</title>
+    <style type="text/css">
+      body {
+        font:normal 68% verdana,arial,helvetica;
+        color:#000000;
+      }
+      table tr td, table tr th {
+          font-size: 68%;
+      }
+      table.details tr th{
+        font-weight: bold;
+        text-align:left;
+        background:#a6caf0;
+      }
+      table.details tr td{
+        background:#eeeee0;
+      }
+
+      p {
+        line-height:1.5em;
+        margin-top:0.5em; margin-bottom:1.0em;
+      }
+      h1 {
+        margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
+      }
+      h2 {
+        margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
+      }
+      h3 {
+        margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
+      }
+      h4 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h5 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      h6 {
+        margin-bottom: 0.5em; font: bold 100% verdana,arial,helvetica
+      }
+      .Error {
+        font-weight:bold; color:red;
+      }
+      .Failure {
+        font-weight:bold; color:purple;
+      }
+      .Properties {
+        text-align:right;
+      }
+      </style>
+       <!--
+      <script type="text/javascript" language="JavaScript">
+        var Projects = new Array();
+        var cur;
+        <xsl:for-each select="./testsuite">
+            <xsl:apply-templates select="properties"/>
+        </xsl:for-each>
+
+       </script>
+       <script type="text/javascript" language="JavaScript"><![CDATA[
+        function displayProperties (name) {
+          var win = window.open('','JUnitSystemProperties','scrollbars=1,resizable=1');
+          var doc = win.document;
+          doc.open();
+          doc.write("<html><head><title>Properties of " + name + "</title>");
+          doc.write("<style>")
+          doc.write("body {font:normal 68% verdana,arial,helvetica; color:#000000; }");
+          doc.write("table tr td, table tr th { font-size: 68%; }");
+          doc.write("table.properties { border-collapse:collapse; border-left:solid 1 #cccccc; border-top:solid 1 #cccccc; padding:5px; }");
+          doc.write("table.properties th { text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#eeeeee; }");
+          doc.write("table.properties td { font:normal; text-align:left; border-right:solid 1 #cccccc; border-bottom:solid 1 #cccccc; background-color:#fffffff; }");
+          doc.write("h3 { margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica }");
+          doc.write("</style>");
+          doc.write("</head><body>");
+          doc.write("<h3>Properties of " + name + "</h3>");
+          doc.write("<div align=\"right\"><a href=\"javascript:window.close();\">Close</a></div>");
+          doc.write("<table class='properties'>");
+          doc.write("<tr><th>Name</th><th>Value</th></tr>");
+          for (prop in Projects[name]) {
+            doc.write("<tr><th>" + prop + "</th><td>" + Projects[name][prop] + "</td></tr>");
+          }
+          doc.write("</table>");
+          doc.write("</body></html>");
+          doc.close();
+          win.focus();
+        }
+      ]]>
+      </script>
+      -->
+        </head>
+        <body>
+            <a name="top"></a>
+            <xsl:call-template name="pageHeader"/>
+
+            <!-- Summary part -->
+            <xsl:call-template name="summary"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- Directory List part -->
+            <xsl:call-template name="directorylist"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- For each directory create its part -->
+            <xsl:call-template name="directories"/>
+            <hr size="1" width="95%" align="left"/>
+
+            <!-- For each class create the  part -->
+            <xsl:call-template name="classes"/>
+
+        </body>
+    </html>
+</xsl:template>
+
+
+
+    <!-- ================================================================== -->
+    <!-- Write a list of all directories with an hyperlink to the anchor of    -->
+    <!-- of the directory name.                                               -->
+    <!-- ================================================================== -->
+    <xsl:template name="directorylist">
+        <h2>Directories</h2>
+        Note: directory statistics are not computed recursively, they only sum up all of its testsuites numbers.
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+            <xsl:call-template name="testsuite.test.header"/>
+            <!-- list all directories recursively -->
+            <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+                <xsl:sort select="@package"/>
+                <xsl:variable name="testsuites-in-directory" select="/testsuites/testsuite[./@package = current()/@package]"/>
+                <xsl:variable name="testCount" select="sum($testsuites-in-directory/tests/text())"/>
+                <xsl:variable name="errorCount" select="sum($testsuites-in-directory/errors/text())"/>
+                <xsl:variable name="failureCount" select="sum($testsuites-in-directory/failures/text())"/>
+                <xsl:variable name="timeCount" select="sum($testsuites-in-directory/time/text())"/>
+
+                <!-- write a summary for the directory -->
+                <tr valign="top">
+                    <!-- set a nice color depending if there is an error/failure -->
+                    <xsl:attribute name="class">
+                        <xsl:choose>
+                            <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                            <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                        </xsl:choose>
+                    </xsl:attribute>
+                    <td><a href="#{@package}"><xsl:value-of select="@package"/></a></td>
+                    <td><xsl:value-of select="$testCount"/></td>
+                    <td><xsl:value-of select="$errorCount"/></td>
+                    <td><xsl:value-of select="$failureCount"/></td>
+                    <td>
+                    <xsl:call-template name="display-time">
+                        <xsl:with-param name="value" select="$timeCount"/>
+                    </xsl:call-template>
+                    </td>
+                    <td><xsl:value-of select="$testsuites-in-directory/@timestamp"/></td>
+                    <td><xsl:value-of select="$testsuites-in-directory/@hostname"/></td>
+                </tr>
+            </xsl:for-each>
+        </table>
+    </xsl:template>
+
+
+    <!-- ================================================================== -->
+    <!-- Write a directory level report                                       -->
+    <!-- It creates a table with values from the document:                  -->
+    <!-- Name | Tests | Errors | Failures | Time                            -->
+    <!-- ================================================================== -->
+    <xsl:template name="directories">
+        <!-- create an anchor to this directory name -->
+        <xsl:for-each select="/testsuites/testsuite[not(./@package = preceding-sibling::testsuite/@package)]">
+            <xsl:sort select="@package"/>
+                <a name="{@package}"></a>
+                <h3>Directory <xsl:value-of select="@package"/></h3>
+
+                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+                    <xsl:call-template name="testsuite.test.header"/>
+
+                    <!-- match the testsuites of this directory -->
+                    <xsl:apply-templates select="/testsuites/testsuite[./@package = current()/@package]" mode="print.test"/>
+                </table>
+                <a href="#top">Back to top</a>
+                <p/>
+                <p/>
+        </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template name="classes">
+        <xsl:for-each select="testsuite">
+            <xsl:sort select="@name"/>
+            <!-- create an anchor to this class name -->
+            <a name="{@name}"></a>
+            <h3>Project <xsl:value-of select="@name"/></h3>
+
+            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+              <xsl:call-template name="testcase.test.header"/>
+              <!--
+              test can even not be started at all (failure to load the class)
+              so report the error directly
+              -->
+                <xsl:if test="./error">
+                    <tr class="Error">
+                        <td colspan="4"><xsl:apply-templates select="./error"/></td>
+                    </tr>
+                </xsl:if>
+                <xsl:apply-templates select="./testcase" mode="print.test"/>
+            </table>
+            <!--
+            <div class="Properties">
+                <a>
+                    <xsl:attribute name="href">javascript:displayProperties('<xsl:value-of select="@package"/>.<xsl:value-of select="@name"/>');</xsl:attribute>
+                    Properties &#187;
+                </a>
+            </div>
+            -->
+            <p/>
+
+            <a href="#top">Back to top</a>
+        </xsl:for-each>
+    </xsl:template>
+
+    <xsl:template name="summary">
+        <h2>Summary</h2>
+        <xsl:variable name="testCount" select="sum(testsuite/tests/text())"/>
+        <xsl:variable name="errorCount" select="sum(testsuite/errors/text())"/>
+        <xsl:variable name="failureCount" select="sum(testsuite/failures/text())"/>
+        <xsl:variable name="timeCount" select="sum(testsuite/time/text())"/>
+        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
+        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%">
+        <tr valign="top">
+            <th>Tests</th>
+            <th>Failures</th>
+            <th>Errors</th>
+            <th>Success rate</th>
+            <th>Time</th>
+        </tr>
+        <tr valign="top">
+            <xsl:attribute name="class">
+                <xsl:choose>
+                    <xsl:when test="$failureCount &gt; 0">Failure</xsl:when>
+                    <xsl:when test="$errorCount &gt; 0">Error</xsl:when>
+                </xsl:choose>
+            </xsl:attribute>
+            <td><xsl:value-of select="$testCount"/></td>
+            <td><xsl:value-of select="$failureCount"/></td>
+            <td><xsl:value-of select="$errorCount"/></td>
+            <td>
+                <xsl:call-template name="display-percent">
+                    <xsl:with-param name="value" select="$successRate"/>
+                </xsl:call-template>
+            </td>
+            <td>
+                <xsl:call-template name="display-time">
+                    <xsl:with-param name="value" select="$timeCount"/>
+                </xsl:call-template>
+            </td>
+
+        </tr>
+        </table>
+        <table border="0" width="95%">
+        <tr>
+        <td style="text-align: justify;">
+        Note: <i>failures</i> are anticipated and checked for with assertions while <i>errors</i> are unanticipated.
+        </td>
+        </tr>
+        </table>
+    </xsl:template>
+
+  <!--
+   Write properties into a JavaScript data structure.
+   This is based on the original idea by Erik Hatcher (ehatcher@apache.org)
+   -->
+  <!--
+  <xsl:template match="properties">
+    cur = Projects['<xsl:value-of select="../@package"/>.<xsl:value-of select="../@name"/>'] = new Array();
+    <xsl:for-each select="property">
+    <xsl:sort select="@name"/>
+        cur['<xsl:value-of select="@name"/>'] = '<xsl:call-template name="JS-escape"><xsl:with-param name="string" select="@value"/></xsl:call-template>';
+    </xsl:for-each>
+  </xsl:template>
+  -->
+
+<!-- Page HEADER -->
+<xsl:template name="pageHeader">
+    <h1>Unit Test Results</h1>
+    <table width="100%">
+    <tr>
+        <td align="left"></td>
+        <td align="right">Designed for use with <a href='http://ant.apache.org/antlibs/antunit/'>AntUnit</a> and <a href='http://ant.apache.org/'>Ant</a>.</td>
+    </tr>
+    </table>
+    <hr size="1"/>
+</xsl:template>
+
+<xsl:template match="testsuite" mode="header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+<!-- class header -->
+<xsl:template name="testsuite.test.header">
+    <tr valign="top">
+        <th width="80%">Name</th>
+        <th>Tests</th>
+        <th>Errors</th>
+        <th>Failures</th>
+        <th nowrap="nowrap">Time(s)</th>
+        <th nowrap="nowrap">Time Stamp</th>
+        <th>Host</th>
+    </tr>
+</xsl:template>
+
+<!-- method header -->
+<xsl:template name="testcase.test.header">
+    <tr valign="top">
+        <th>Name</th>
+        <th>Status</th>
+        <th width="80%">Type</th>
+        <th nowrap="nowrap">Time(s)</th>
+    </tr>
+</xsl:template>
+
+
+<!-- class information -->
+<xsl:template match="testsuite" mode="print.test">
+    <tr valign="top">
+        <!-- set a nice color depending if there is an error/failure -->
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="failures/text()[.&gt; 0]">Failure</xsl:when>
+                <xsl:when test="errors/text()[.&gt; 0]">Error</xsl:when>
+            </xsl:choose>
+        </xsl:attribute>
+
+        <!-- print testsuite information -->
+        <td><a href="#{@name}"><xsl:value-of select="@name"/></a></td>
+        <td><xsl:value-of select="tests/text()"/></td>
+        <td><xsl:value-of select="errors/text()"/></td>
+        <td><xsl:value-of select="failures/text()"/></td>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="time/text()"/>
+            </xsl:call-template>
+        </td>
+        <td><xsl:apply-templates select="@timestamp"/></td>
+        <td><xsl:apply-templates select="@hostname"/></td>
+    </tr>
+</xsl:template>
+
+<xsl:template match="testcase" mode="print.test">
+    <tr valign="top">
+        <xsl:attribute name="class">
+            <xsl:choose>
+                <xsl:when test="error">Error</xsl:when>
+                <xsl:when test="failure">Failure</xsl:when>
+                <xsl:otherwise>TableRowColor</xsl:otherwise>
+            </xsl:choose>
+        </xsl:attribute>
+        <td><xsl:value-of select="@name"/></td>
+        <xsl:choose>
+            <xsl:when test="failure">
+                <td>Failure</td>
+                <td><xsl:apply-templates select="failure"/></td>
+            </xsl:when>
+            <xsl:when test="error">
+                <td>Error</td>
+                <td><xsl:apply-templates select="error"/></td>
+            </xsl:when>
+            <xsl:otherwise>
+                <td>Success</td>
+                <td></td>
+            </xsl:otherwise>
+        </xsl:choose>
+        <td>
+            <xsl:call-template name="display-time">
+                <xsl:with-param name="value" select="time/text()"/>
+            </xsl:call-template>
+        </td>
+    </tr>
+</xsl:template>
+
+
+<xsl:template match="failure">
+    <xsl:call-template name="display-failures"/>
+</xsl:template>
+
+<xsl:template match="error">
+    <xsl:call-template name="display-failures"/>
+    <!-- display the stacktrace -->
+    <br/><br/>
+    <code>
+        <xsl:call-template name="br-replace">
+            <xsl:with-param name="word" select="."/>
+        </xsl:call-template>
+    </code>
+    <!-- the latter is better but might be problematic for non-21" monitors... -->
+    <!--pre><xsl:value-of select="."/></pre-->
+</xsl:template>
+
+<!-- Style for the error and failure in the tescase template -->
+<xsl:template name="display-failures">
+    <xsl:choose>
+        <xsl:when test="not(@message)">N/A</xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@message"/>
+        </xsl:otherwise>
+    </xsl:choose>
+    <xsl:choose>
+        <xsl:when test="@linenumber">
+            <br></br>
+            at line <xsl:value-of select="@linenumber"/>
+            <xsl:choose>
+                <xsl:when test="@columnnumber">
+                    , column <xsl:value-of select="@columnnumber"/>
+                </xsl:when>
+            </xsl:choose>
+        </xsl:when>
+    </xsl:choose>
+</xsl:template>
+
+<xsl:template name="JS-escape">
+    <xsl:param name="string"/>
+    <xsl:param name="tmp1" select="stringutils:replace(string($string),'\','\\')"/>
+    <xsl:param name="tmp2" select="stringutils:replace(string($tmp1),&quot;'&quot;,&quot;\&apos;&quot;)"/>
+    <xsl:value-of select="$tmp2"/>
+</xsl:template>
+
+
+<!--
+    template that will convert a carriage return into a br tag
+    @param word the text from which to convert CR to BR tag
+-->
+<xsl:template name="br-replace">
+    <xsl:param name="word"/>
+    <xsl:value-of disable-output-escaping="yes" select='stringutils:replace(string($word),"&#xA;","&lt;br/>")'/>
+</xsl:template>
+
+<xsl:template name="display-time">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.000')"/>
+</xsl:template>
+
+<xsl:template name="display-percent">
+    <xsl:param name="value"/>
+    <xsl:value-of select="format-number($value,'0.00%')"/>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/trunk/src/tests/antunit/taskdefs/concat-test.xml b/trunk/src/tests/antunit/taskdefs/concat-test.xml
new file mode 100644
index 0000000..379bc2e
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/concat-test.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <target name="tearDown">
+    <delete file="binaryAppendDest" />
+    <delete file="encodeStringDest" />
+  </target>
+
+  <target name="testBinaryAppend">
+    <au:assertTrue message="prerequisite conditions unmet">
+      <length length="0">
+        <!-- allow for nonexistent OR zero-length: -->
+        <fileset file="binaryAppendDest" />
+      </length>
+    </au:assertTrue>
+    <echo file="binaryAppendDest">x</echo>
+    <au:assertTrue message="destfile setup failed">
+      <length length="1" file="binaryAppendDest" />
+    </au:assertTrue>
+    <concat append="true" destfile="binaryAppendDest" binary="true">
+      <string value="x" />
+    </concat>
+    <au:assertTrue message="expected length 2">
+      <length file="binaryAppendDest" length="2" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testStringEncoding" if="os.unix">
+    <property name="br" value="${line.separator}" />
+    <concat destfile="encodeStringDest"
+            outputEncoding="utf-16">foo${br}bar${br}baz${br}</concat>
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <file file="utf-16.expected" />
+        <file file="encodeStringDest" />
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+	
+  <target name="testStringEncodingWindows" if="os.windows">
+    <property name="br" value="${line.separator}" />
+	<concat destfile="encodeStringDest"
+	        outputEncoding="utf-16">foo${br}bar${br}baz${br}</concat>
+	<au:assertTrue>
+	  <resourcesmatch astext="true">
+	    <file file="utf-16.expected.windows" />
+	    <file file="encodeStringDest" />
+	  </resourcesmatch>
+	</au:assertTrue>
+  </target>
+
+  <target name="testDoNotFixNestedText" description="Bugzilla 42369">
+    <au:assertTrue>
+      <resourcesmatch>
+        <string>foo</string>
+        <concat fixlastline="true">foo</concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/condition/antversion-test.xml b/trunk/src/tests/antunit/taskdefs/condition/antversion-test.xml
new file mode 100644
index 0000000..01ebe1d
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/condition/antversion-test.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="antversion-test" default="all" basedir="." xmlns:au="antlib:org.apache.ant.antunit">

+

+  <target name="test-atleast">

+    <au:assertTrue message="Expected antversion of ${ant.version} to be at least 1.7.0">

+        <!-- AntVersion was introduced like AntUnit in 1.7 - so this must be true -->

+    	<antversion atleast="1.7.0"/>

+    </au:assertTrue>	

+  </target>

+

+  <target name="test-exactly">

+    <antversion property="ant.actual.version"/>

+    <au:assertTrue message="Expected antversion of ${ant.actual.version}">

+    	<antversion exactly="${ant.actual.version}"/>

+    </au:assertTrue>	

+  </target>

+

+  <target name="test-atleast-fail">

+  	<property name="version" value="1.8.9"/>

+    <au:assertFalse>

+   	  <antversion atleast="1.9.0"/>

+    </au:assertFalse>

+  </target>

+    

+  <target name="test-task">

+    <antversion property="antversion"/>

+    <au:assertPropertySet name="antversion" message="Property 'antversion' should be set."/>

+    <echo>AntVersion=${antversion}</echo>  

+  </target>    

+    

+  <target name="test-property-conditional1">

+    <antversion property="antversion" atleast="2.0.0"/>

+    <au:assertTrue message="Property 'antversion' should not be set because this is not Ant 2.0.0+.">

+      <not>

+        <isset property="antversion"/>  

+      </not>  

+    </au:assertTrue>  

+  </target>

+    

+  <target name="test-property-conditional2">

+    <antversion property="antversion" atleast="1.7.0"/>

+    <au:assertTrue message="Property 'antversion' should be set because we should have Ant 1.7.0+ (${ant.version}).">

+      <isset property="antversion"/>  

+    </au:assertTrue>  

+  </target>

+

+  <target name="all">

+    <au:antunit>

+      <fileset file="${ant.file}"/>

+      <au:plainlistener/>

+    </au:antunit>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/condition/hasfreespace-test.xml b/trunk/src/tests/antunit/taskdefs/condition/hasfreespace-test.xml
new file mode 100644
index 0000000..94b184f
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/condition/hasfreespace-test.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="hasfreespace-test" default="all" basedir="." xmlns:au="antlib:org.apache.ant.antunit">

+

+  <available property="jdk6.available" classname="java.util.ServiceLoader"/>

+

+  <property name="partition" value="${user.home}" />

+

+

+  <target name="test-not-enough-space-human" if="jdk6.available">

+    <au:assertFalse>

+      <hasfreespace partition="${partition}" needed="1P"/>

+    </au:assertFalse>	

+  </target>

+

+  <target name="test-enough-space-human" if="jdk6.available">

+    <au:assertTrue>

+      <hasfreespace partition="${partition}" needed="1K"/>

+    </au:assertTrue>	

+  </target>

+

+  <target name="test-not-enough-space" if="jdk6.available">

+  	<property name="long.max-value" value="9223372036854775807"/>

+    <au:assertFalse>

+   	  <hasfreespace partition="${partition}" needed="${long.max-value}"/>

+    </au:assertFalse>

+  </target>

+		

+  <target name="test-enough-space" if="jdk6.available">

+    <au:assertTrue>

+      <hasfreespace partition="${partition}" needed="1"/>			

+    </au:assertTrue>	

+  </target>

+

+  <target name="all">

+    <au:antunit>

+      <fileset file="${ant.file}"/>

+      <au:plainlistener/>

+    </au:antunit>

+  </target>

+

+</project>
\ No newline at end of file
diff --git a/trunk/src/tests/antunit/taskdefs/condition/resourcecontains-test.xml b/trunk/src/tests/antunit/taskdefs/condition/resourcecontains-test.xml
new file mode 100644
index 0000000..cd92202
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/condition/resourcecontains-test.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="resourcecontains-test" default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+

+  <import file="../../antunit-base.xml"/>

+

+  <target name="setUp">

+    <property name="file" location="${java.io.tmpdir}/test-resource.txt"/>

+    <echo file="${file}" message="loads of text!"/>

+  </target>

+

+  <target name="tearDown">

+    <delete file="${file}"/>

+  </target>

+

+  <target name="testcontains">

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains resource="${file}" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testContainsLowerNonCS">

+    <echo file="${file}" message="LOADS OF TEXT!"/>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains resource="${file}" substring="text"

+                        casesensitive="false"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testContainsUpperNonCS">

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains resource="${file}" substring="TEXT"

+                        casesensitive="false"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testContainsEmptyString">

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains resource="${file}" substring="" />

+    </au:assertTrue>

+  </target>

+

+  <target name="testContainsEmptyProperty">

+    <property name="testContainsEmptyProperty" value="" />

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains resource="${file}"

+                        substring="${testContainsEmptyProperty}" />

+    </au:assertTrue>

+  </target>

+

+  <target name="testwithemptyfile">

+    <truncate file="${file}"/>

+    <au:assertFalse message="Should have found nothing as file is empty">

+      <resourcecontains resource="${file}" substring="text"/>

+    </au:assertFalse>

+  </target>

+

+  <target name="testWithEmptyFileAndSubstring">

+    <truncate file="${file}"/>

+    <au:assertTrue message="Empty resource should contain empty string">

+      <resourcecontains resource="${file}" substring=""/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testdoesntcontain">

+    <au:assertFalse message="Should have found nothing as file is empty">

+      <resourcecontains resource="${file}" substring="futurama"/>

+    </au:assertFalse>

+  </target>

+

+  <target name="testFileRefContains">

+    <file id="file" file="${file}" />

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="file" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testStringRefContains">

+    <string id="string">loads of text!</string>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="string" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testTextConcatRefContains">

+    <resources id="concat">

+      <concat>loads of text!</concat>

+    </resources>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="concat" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testFileConcatRefContains">

+    <resources id="concat">

+      <concat><file file="${file}" /></concat>

+    </resources>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="concat" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testMultiConcatRefContains">

+    <resources id="concat">

+      <concat>

+        <header>HEADER</header>

+        <footer>FOOTER</footer>

+        <string>foo</string>

+        <file file="${file}" />

+        <string>bar</string>

+      </concat>

+    </resources>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="concat" substring="text"/>

+    </au:assertTrue>

+  </target>

+

+  <target name="testFirstRefContains">

+    <first id="first">

+      <fileset dir="${basedir}" includes="*-test.xml" />

+    </first>

+    <au:assertTrue message="Should have found the text in the resource">

+      <resourcecontains refid="first" substring="project"/>

+    </au:assertTrue>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/delete-test.xml b/trunk/src/tests/antunit/taskdefs/delete-test.xml
new file mode 100644
index 0000000..7746b2d
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/delete-test.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="delete-test" basedir="." default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+  <property name="working.dir" value="working"/>
+  <property name="existing.dir" value="working/exists"/>
+  <property name="nonexistent.dir" value="working/nonexists"/>
+  
+  <import file="../antunit-base.xml" />
+
+  <target name="init">
+    <delete dir="${working.dir}"/>
+    <mkdir dir="${working.dir}"/>
+    <mkdir dir="${existing.dir}"/>
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${working.dir}"/>
+  </target>
+
+  <!--test that you can delete a fileset with a nonexistent dir without failure-->
+  <target name="testdelfileset" depends="init">
+    <delete quiet="true" includeEmptyDirs="true">
+       <fileset dir="${nonexistent.dir}"/>
+    </delete>
+
+    <au:assertFileExists file="${existing.dir}" />
+      
+    <delete quiet="true" includeEmptyDirs="true">
+       <fileset dir="${existing.dir}"/>
+    </delete>
+
+    <au:assertFileDoesntExist file="${existing.dir}" />
+
+
+    <mkdir dir="${existing.dir}"/>
+
+    <delete quiet="true" includeEmptyDirs="true">
+       <fileset dir="${nonexistent.dir}"/>
+       <fileset dir="${existing.dir}"/>
+    </delete>
+
+
+    <au:assertFileDoesntExist file="${existing.dir}" />
+
+    <mkdir dir="${existing.dir}"/>
+
+    <delete quiet="true" includeEmptyDirs="true">
+       <fileset dir="${existing.dir}"/>
+       <fileset dir="${nonexistent.dir}"/>
+    </delete>
+
+
+    <au:assertFileDoesntExist file="${existing.dir}" />
+
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/dependset/test.xml b/trunk/src/tests/antunit/taskdefs/dependset/test.xml
new file mode 100644
index 0000000..ec340b4
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/dependset/test.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="dependset-test" xmlns:au="antlib:org.apache.ant.antunit">
+
+  <target name="test1">
+    <au:expectfailure expectedMessage="At least one set of source resources must be specified">
+      <dependset />
+    </au:expectfailure>
+  </target>
+
+  <target name="test2">
+    <au:expectfailure expectedMessage="At least one set of target files must be specified">
+      <dependset>
+        <srcfilelist dir="." files="test2.tmp" />
+      </dependset>
+    </au:expectfailure>
+  </target>
+
+  <target name="test3">
+    <au:expectfailure expectedMessage="At least one set of source resources must be specified">
+      <dependset>
+        <targetfileset dir="." includes="test3.tmp" />
+      </dependset>
+    </au:expectfailure>
+  </target>
+
+  <target name="test4">
+    <touch file="test4.tmp" />
+    <dependset>
+      <srcfilelist dir="." files="test4.tmp" />
+      <targetfileset id="targetfs" dir="." includes="i-do-not-exist" />
+    </dependset>
+  </target>
+
+  <target name="test5">
+    <touch file="older.tmp" />
+    <sleep seconds="3" />
+    <touch file="newer.tmp" />
+    <dependset>
+      <srcfilelist dir="." files="newer.tmp" />
+      <targetfilelist dir="." files="older.tmp" />
+    </dependset>
+    <au:assertFalse>
+      <available file="older.tmp" />
+    </au:assertFalse>
+  </target>
+
+  <target name="test6">
+    <touch file="sourceset_1.tmp" />
+  	<touch file="targetset_1.tmp" />
+    <sleep seconds="3" />
+  	<touch file="sourceset_2.tmp" />
+  	<touch file="targetset_2.tmp" />
+  	<sleep seconds="2" />	
+    <dependset>
+      <sources>
+        <filelist dir="." files="sourceset_1.tmp,sourceset_2.tmp" />
+      </sources>
+      <targets>
+        <filelist dir="." files="targetset_1.tmp,targetset_2.tmp" />
+      </targets>
+    </dependset>
+    <au:assertFalse>
+      <available file="targetset_1.tmp" />
+    </au:assertFalse>
+    <au:assertFalse>
+      <available file="targetset_2.tmp" />
+    </au:assertFalse>
+  </target>
+
+  <target name="test7">
+    <touch file="older.tmp" />
+    <dependset>
+      <sources>
+        <propertyresource name="thereisnosuchproperty" />
+      </sources>
+      <targets>
+        <filelist dir="." files="older.tmp" />
+      </targets>
+    </dependset>
+    <au:assertFalse>
+      <available file="older.tmp" />
+    </au:assertFalse>
+  </target>
+
+  <target name="test8">
+    <touch file="older.tmp" />
+    <property name="foo" value="bar" />
+    <dependset>
+      <sources>
+        <propertyresource name="foo" />
+      </sources>
+      <targets>
+        <filelist dir="." files="older.tmp" />
+      </targets>
+    </dependset>
+    <au:assertTrue>
+      <available file="older.tmp" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test9">
+    <au:assertFalse>
+      <available file="test9dir" type="dir" />
+    </au:assertFalse>
+    <touch file="test9.tmp" />
+    <dependset>
+      <srcfileset dir="." includes="test9.tmp" />
+      <targetfileset dir="test9dir" />
+    </dependset>
+  </target>
+
+  <target name="tearDown"> 
+    <delete file="test4.tmp" />
+    <delete file="test9.tmp" />
+    <delete file="older.tmp" />
+    <delete file="newer.tmp" />
+  	<delete file="sourceset_1.tmp" />
+   	<delete file="sourceset_2.tmp" />
+  	<delete file="targetset_1.tmp" />
+  	<delete file="targetset_2.tmp" />
+  	
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/dirname-test.xml b/trunk/src/tests/antunit/taskdefs/dirname-test.xml
new file mode 100644
index 0000000..c138850
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/dirname-test.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="dirname-test" basedir="." default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+

+  <import file="../antunit-base.xml"/>

+

+  <target name="test1">

+    <au:expectfailure expectedmessage="property attribute required">

+      <dirname/>

+    </au:expectfailure>

+  </target>

+

+  <target name="test2">

+    <au:expectfailure expectedmessage="file attribute required">

+      <dirname property="propname"/>

+    </au:expectfailure>

+  </target>

+

+  <target name="test3">

+    <au:expectfailure expectedmessage="property attribute required">

+      <dirname file="filename"/>

+    </au:expectfailure>

+  </target>

+

+  <target name="init-test4">

+    <condition property="valid.os">

+      <and>

+        <not><os family="dos"/></not><not><os family="netware"/></not>

+      </and>

+    </condition>

+  </target>

+

+  <target name="test4" depends="init-test4" if="valid.os">

+    <dirname property="local.dir" file="/usr/local/foo.txt"/>

+    <au:assertPropertyEquals name="local.dir" 

+      value="${file.separator}usr${file.separator}local"/>

+  </target>

+  

+  <target name="test5">

+    <dirname property="base.dir" file="foo.txt"/>

+    <au:assertPropertyEquals name="base.dir" value="${basedir}"/>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/echoxml-test.xml b/trunk/src/tests/antunit/taskdefs/echoxml-test.xml
new file mode 100644
index 0000000..c62f4cb
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/echoxml-test.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+

+  <!-- note relies on antunit built from svn trunk (1.1-alpha) -->

+  <import file="../antunit-base.xml"/>

+

+  <target name="setUp">

+  <property name="file" location="${java.io.tmpdir}/echoed.xml"/>

+    <echoxml file="${file}">

+      <project>

+        <property name="foo" value="bar" />

+        <fail message="$$$${foo}=$${foo}">

+          <condition>

+            <istrue value="${mustfail}" />

+          </condition>

+        </fail>

+      </project>

+    </echoxml>

+  </target>

+  

+  <target name="tearDown">

+    <delete file="${file}"/>

+  </target>  

+

+  <target name="testPass">

+  <ant antfile="${file}"/>

+  </target>

+  

+  <target name="testFail">

+    <au:expectfailure expectedmessage="${foo}=bar" message="Should have thrown an exception">

+      <ant antfile="${file}">

+        <property name="mustfail" value="true" />

+      </ant>

+    </au:expectfailure>

+  </target>

+  

+  <target name="testEmpty">

+    <au:expectfailure expectedmessage="No nested XML specified" message="Should have thrown an exception">

+      <echoxml />

+    </au:expectfailure>

+  </target>

+  

+  <target name="test-ns"> <!-- comment this if you don't have the svn trunk of antunit -->

+    <echoxml file="${file}" xmlns:a="antlib:a">

+      <a:something />

+    </echoxml>

+    <au:assertResourceContains resource="${file}" value="a:something"/>

+  </target>

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/exec/apply-test.xml b/trunk/src/tests/antunit/taskdefs/exec/apply-test.xml
new file mode 100755
index 0000000..95216ba
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/exec/apply-test.xml
@@ -0,0 +1,741 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="apply-test" xmlns:au="antlib:org.apache.ant.antunit">
+  <property environment="env" />
+  <!-- UNIX -->
+  <available file="sh" filepath="${env.PATH}" property="sh.executable" />
+  <!-- CYGWIN -->
+  <available file="sh.exe" filepath="${env.PATH}" property="sh.exe.executable" />
+  <condition property="test.can.run">
+    <or>
+      <isset property="sh.executable" />
+      <isset property="sh.exe.executable" />
+    </or>
+  </condition>
+  <!-- UNIX -->
+  <available file="sed" filepath="${env.PATH}" property="sed.executable" />
+  <!-- CYGWIN -->
+  <available file="sed.exe" filepath="${env.PATH}" property="sed.exe.executable" />
+  <condition property="sed.can.run">
+    <or>
+      <isset property="sed.executable" />
+      <isset property="sed.exe.executable" />
+    </or>
+  </condition>
+  <!-- UNIX -->
+  <available file="echo" filepath="${env.PATH}" property="echo.executable" />
+  <!-- CYGWIN -->
+  <available file="echo.exe" filepath="${env.PATH}" property="echo.exe.executable" />
+  <condition property="echo.can.run">
+    <or>
+      <isset property="echo.executable" />
+      <isset property="echo.exe.executable" />
+    </or>
+  </condition>
+
+  <!-- UNIX -->
+  <available file="ls" filepath="${env.PATH}" property="ls.executable" />
+  <!-- CYGWIN -->
+  <available file="ls.exe" filepath="${env.PATH}" property="ls.exe.executable" />
+  <!-- piggyback the name of the executable here -->
+  <condition property="ls.can.run" value="ls">
+    <isset property="ls.executable" />
+  </condition>
+  <condition property="ls.can.run" value="ls.exe">
+    <isset property="ls.exe.executable" />
+  </condition>
+
+  <property name="eol" value="${line.separator}" />
+
+  <macrodef name="rcat">
+    <attribute name="refid" />
+    <sequential>
+      <echo>@@{refid}=@{refid}</echo>
+      <concat><resources refid="@{refid}" /></concat>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assertEmptyFile">
+    <attribute name="file" />
+    <sequential>
+      <au:assertTrue>
+        <and>
+          <available file="@{file}" type="file" />
+          <length length="0" file="@{file}" />
+        </and>
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <target name="xyz">
+    <echo file="x">s/x/blah/g${eol}</echo>
+    <echo file="y">s/y/blah/g${eol}</echo>
+    <echo file="z">s/z/blah/g${eol}</echo>
+    <fileset id="xyz" dir="${basedir}" includes="x,y,z" />
+    <filelist id="xyzlist" dir="${basedir}" files="x,y,z" />
+    <property name="x" location="x" />
+    <property name="y" location="y" />
+    <property name="z" location="z" />
+  </target>
+
+  <target name="testNoRedirect" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertLogContains text="${x} out" />
+    <au:assertLogContains text="${y} out" />
+    <au:assertLogContains text="${z} out" />
+    <au:assertLogContains text="${x} err" />
+    <au:assertLogContains text="${y} err" />
+    <au:assertLogContains text="${z} err" />
+
+    <!--
+
+    The original junit test also verified that x out happened before
+    y out, and y out happened before z out; likewise with err output.
+    I added the antunit:logcontent resource hoping that would help,
+    but I think we need a way to filter (copy) resources first.
+    THAT necessitates the string-to-resource coding we are currently
+    discussing on the dev list IMO.  MJB, 9/22/2006
+
+    -->
+
+  </target>
+
+  <target name="testRedirect1" depends="xyz" if="test.can.run">
+    <apply executable="sh" output="redirect.out" append="true">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <resourcecount count="1">
+        <restrict id="results">
+          <file file="redirect.out" />
+          <and xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <contains text="${x} out" />
+            <contains text="${y} out" />
+            <contains text="${z} out" />
+            <contains text="${x} err" />
+            <contains text="${y} err" />
+            <contains text="${z} err" />
+          </and>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+
+  </target>
+
+  <target name="testRedirect2" depends="xyz" if="test.can.run">
+    <apply executable="sh" output="redirect.out"
+           error="redirect.err" append="true">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirect.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} err${eol}${y} err${eol}${z} err" />
+          <file file="redirect.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirect3" depends="xyz" if="test.can.run">
+    <apply executable="sh" logerror="true" append="true"
+           output="redirect.out" outputproperty="redirect3.out">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <string value="${x} out${eol}${y} out${eol}${z} out" />
+        <file file="redirect.out" />
+        <propertyresource name="redirect3.out" />
+      </resourcesmatch>
+    </au:assertTrue>
+
+    <au:assertLogContains text="${x} err" />
+    <au:assertLogContains text="${y} err" />
+    <au:assertLogContains text="${z} err" />
+  </target>
+
+  <target name="testRedirect4" depends="xyz" if="test.can.run">
+    <apply executable="sh" append="true"
+           error="redirect.err" errorproperty="redirect4.err"
+           output="redirect.out" outputproperty="redirect4.out">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirect.out" />
+          <propertyresource name="redirect4.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} err${eol}${y} err${eol}${z} err" />
+          <file file="redirect.err" />
+          <propertyresource name="redirect4.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirect5" depends="xyz" if="sed.can.run">
+    <apply executable="sed" inputstring="x y z${eol}" append="true"
+           error="redirect.err" errorproperty="redirect5.err"
+           output="redirect.out" outputproperty="redirect5.out">
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <propertyresource name="redirect5.out" />
+          <string value="blah y z${eol}x blah z${eol}x y blah" />
+          <file file="redirect.out" />
+        </resourcesmatch>
+        <equals arg1="${redirect5.err}" arg2="" />
+      </and>
+    </au:assertTrue>
+    <assertEmptyFile file="redirect.err" />
+  </target>
+
+  <target name="testRedirect6" depends="xyz" if="sed.can.run">
+    <echo file="redirect.in">x y z${eol}</echo>
+    <apply executable="sed" input="redirect.in" append="true"
+           error="redirect.err" errorproperty="redirect6.err"
+           output="redirect.out" outputproperty="redirect6.out">
+      <arg value="-f" />
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <propertyresource name="redirect6.out" />
+          <string value="blah y z${eol}x blah z${eol}x y blah" />
+          <file file="redirect.out" />
+        </resourcesmatch>
+        <equals arg1="${redirect6.err}" arg2="" />
+        <length length="0"><file file="redirect.err" /></length>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirect7" depends="xyz" if="sed.can.run">
+    <apply executable="sed" inputstring="x y z${eol}"
+           error="redirect.err" output="redirect.out"
+           outputproperty="redirect7.out">
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <equals arg1="${redirect7.out}" arg2="blah y z" />
+        <resourcesmatch astext="true">
+          <file file="redirect.out" />
+          <string value="x y blah" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+    <assertEmptyFile file="redirect.err" />
+  </target>
+
+  <target name="testRedirector1" description="fail"
+          depends="xyz" if="test.can.run">
+    <au:expectfailure
+            expectedmessage="cannot have &gt; 1 nested &lt;redirector&gt;s">
+      <apply executable="sh">
+        <arg value="parrot.sh" />
+        <fileset refid="xyz" />
+        <redirector output="redirector.out" />
+        <redirector output="whocares" />
+      </apply>
+    </au:expectfailure>
+  </target>
+
+  <target name="testRedirector2" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+      <redirector output="redirector.out" append="true" />
+    </apply>
+    <au:assertTrue>
+      <resourcecount count="1">
+        <restrict id="results">
+          <file file="redirector.out" />
+          <and xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <contains text="${x} out" />
+            <contains text="${y} out" />
+            <contains text="${z} out" />
+            <contains text="${x} err" />
+            <contains text="${y} err" />
+            <contains text="${z} err" />
+          </and>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirector3" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+      <redirector append="true"
+                  output="redirector.out" error="redirector.err" />
+    </apply>
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirector.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} err${eol}${y} err${eol}${z} err" />
+          <file file="redirector.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirector4" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+      <redirector output="redirector.out" logerror="true"
+                  append="true" outputproperty="redirector4.out" />
+    </apply>
+
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <string value="${x} out${eol}${y} out${eol}${z} out" />
+        <file file="redirector.out" />
+        <propertyresource name="redirector4.out" />
+      </resourcesmatch>
+    </au:assertTrue>
+
+    <au:assertLogContains text="${x} err" />
+    <au:assertLogContains text="${y} err" />
+    <au:assertLogContains text="${z} err" />
+  </target>
+
+  <target name="testRedirector5" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <redirector error="redirector.err" errorproperty="redirector5.err"
+                  output="redirector.out" outputproperty="redirector5.out"
+                  append="true" />
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirector.out" />
+          <propertyresource name="redirector5.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} err${eol}${y} err${eol}${z} err" />
+          <file file="redirector.err" />
+          <propertyresource name="redirector5.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirector6" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <redirector append="true" outputproperty="redirector6.out"
+                  errorproperty="redirector6.err">
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+      </redirector>
+      <arg value="parrot.sh" />
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirector.out" />
+          <propertyresource name="redirector6.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} err${eol}${y} err${eol}${z} err" />
+          <file file="redirector.err" />
+          <propertyresource name="redirector6.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirector7" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <redirector append="true" outputproperty="redirector7.out"
+                  errorproperty="redirector7.err">
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+        <errorfilterchain>
+          <replacestring from="err" to="ERROR!!!" />
+        </errorfilterchain>
+      </redirector>
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="${x} out${eol}${y} out${eol}${z} out" />
+          <file file="redirector.out" />
+          <propertyresource name="redirector7.out" />
+        </resourcesmatch>
+        <resourcesmatch astext="true">
+          <string value="${x} ERROR!!!${eol}${y} ERROR!!!${eol}${z} ERROR!!!" />
+          <file file="redirector.err" />
+          <propertyresource name="redirector7.err" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testRedirector8" depends="xyz" if="sed.can.run">
+    <echo file="redirector.in">x y z${eol}</echo>
+    <apply executable="sed">
+      <redirector append="true" outputproperty="redirector8.out"
+                  errorproperty="redirector8.err">
+        <inputmapper type="merge" to="redirector.in" />
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+      </redirector>
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <propertyresource name="redirector8.out" />
+          <string value="blah y z${eol}x blah z${eol}x y blah" />
+          <file file="redirector.out" />
+        </resourcesmatch>
+        <equals arg1="${redirector8.err}" arg2="" />
+      </and>
+    </au:assertTrue>
+    <assertEmptyFile file="redirector.err" />
+  </target>
+
+  <macrodef name="valRor9-12">
+    <attribute name="n" />
+    <sequential>
+      <au:assertTrue>
+        <and>
+          <equals arg1="" arg2="${redirector@{n}.err}" />
+          <resourcesmatch astext="true">
+           <string value="blah after y after z${eol}x after blah after z${eol}x after y after blah" />
+           <propertyresource name="redirector@{n}.out" />
+           <file file="redirector.out" />
+          </resourcesmatch>
+        </and>
+      </au:assertTrue>
+      <assertEmptyFile file="redirector.err" />
+    </sequential>
+  </macrodef>
+
+  <target name="testRedirector9" depends="xyz" if="sed.can.run">
+    <echo file="redirector.in">x before y before z${eol}</echo>
+    <apply executable="sed">
+      <redirector outputproperty="redirector9.out"
+                  errorproperty="redirector9.err" append="true">
+        <inputfilterchain>
+          <replacestring from="before" to="after" />
+        </inputfilterchain>
+        <inputmapper type="merge" to="redirector.in" />
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+      </redirector>
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <valRor9-12 n="9" />
+  </target>
+
+  <target name="testRedirector10" depends="xyz" if="sed.can.run">
+    <echo file="redirector.in">x before y before z${eol}</echo>
+    <apply executable="sed">
+      <redirector outputproperty="redirector10.out"
+                  errorproperty="redirector10.err" append="true">
+        <outputfilterchain>
+          <replacestring from="before" to="after" />
+        </outputfilterchain>
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+      </redirector>
+      <arg value="-f" />
+      <srcfile />
+      <arg value="redirector.in" />
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <valRor9-12 n="10" />
+  </target>
+
+  <target name="testRedirector11" depends="xyz" if="sed.can.run">
+    <apply executable="sed">
+      <redirector outputproperty="redirector11.out"
+                  errorproperty="redirector11.err"
+                  inputstring="x before y before z${eol}"
+                  append="true">
+        <inputfilterchain>
+          <replacestring from="before" to="after" />
+        </inputfilterchain>
+        <outputmapper type="merge" to="redirector.out" />
+        <errormapper type="merge" to="redirector.err" />
+      </redirector>
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <valRor9-12 n="11" />
+  </target>
+
+  <target name="testRedirector12" depends="xyz" if="sed.can.run">
+    <echo file="redirector.in">x before y before z${eol}</echo>
+    <apply executable="sed" output="redirector.out" error="redirector.err">
+      <redirector outputproperty="redirector12.out"
+                  errorproperty="redirector12.err" append="true">
+        <outputfilterchain>
+          <replacestring from="before" to="after" />
+        </outputfilterchain>
+        <outputmapper type="glob" from="nomatch" to="nomatchout" />
+        <errormapper type="glob" from="nomatch" to="nomatcherr" />
+      </redirector>
+      <arg value="-f" />
+      <srcfile />
+      <arg value="redirector.in" />
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <valRor9-12 n="12" />
+  </target>
+
+  <target name="testRedirector13" depends="xyz" if="test.can.run">
+    <apply executable="sh">
+      <redirector>
+        <outputfilterchain>
+          <replacestring from="out" to="OUTPUT???" />
+        </outputfilterchain>
+        <errorfilterchain>
+          <replacestring from="err" to="ERROR!!!" />
+        </errorfilterchain>
+      </redirector>
+      <arg value="parrot.sh" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <au:assertLogContains text="${x} OUTPUT???" />
+    <au:assertLogContains text="${y} OUTPUT???" />
+    <au:assertLogContains text="${z} OUTPUT???" />
+    <au:assertLogContains text="${x} ERROR!!!" />
+    <au:assertLogContains text="${y} ERROR!!!" />
+    <au:assertLogContains text="${z} ERROR!!!" />
+  </target>
+
+  <target name="testRedirector14" depends="xyz" if="sed.can.run">
+    <echo file="redirector.in">z before y before x${eol}</echo>
+    <apply executable="sed">
+      <redirector append="true"
+                  inputstring="x before y before z${eol}">
+        <outputfilterchain>
+          <replacestring from="before" to="after" />
+        </outputfilterchain>
+        <inputmapper type="glob" from="x" to="redirector.in" />
+        <outputmapper type="glob" from="y" to="redirector.out" />
+        <errormapper type="glob" from="z" to="redirector.err" />
+      </redirector>
+      <arg value="-f" />
+      <fileset refid="xyz" />
+    </apply>
+
+    <assertEmptyFile file="redirector.err" />
+
+    <au:assertTrue>
+      <and>
+        <resourcesmatch astext="true">
+          <string value="z after y after blahx after y after blah" />
+          <au:logcontent />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+    <au:assertTrue message="${logcontent}">
+      <and>
+        <resourcesmatch astext="true">
+          <string value="x after blah after z" />
+          <file file="redirector.out" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="pad">
+    <condition property="pad" value="">
+      <or>
+        <not>
+          <os family="dos" />
+        </not>
+        <not>
+          <or>
+            <equals arg1="${ant.java.version}" arg2="1.1" />
+            <equals arg1="${ant.java.version}" arg2="1.2" />
+          </or>
+        </not>
+      </or>
+    </condition>
+
+    <condition property="pad" value=" ">
+      <and>
+        <os family="dos" />
+        <or>
+          <equals arg1="${ant.java.version}" arg2="1.2" />
+        </or>
+      </and>
+    </condition>
+
+  </target>
+
+  <target name="testIgnoreMissing" depends="xyz,pad" if="echo.can.run">
+    <filelist id="xylist" dir="${basedir}" files="x,y" />
+    <delete file="z" />
+
+    <pathconvert property="xy" pathsep="${pad}${eol}" refid="xylist" />
+
+    <pathconvert property="xyz" pathsep="${pad}${eol}" refid="xyzlist" />
+
+    <apply executable="echo" ignoremissing="true"
+           outputproperty="ignoretrue" append="true">
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <apply executable="echo" ignoremissing="false"
+           outputproperty="ignorefalse" append="true">
+      <filelist refid="xyzlist" />
+    </apply>
+
+    <au:assertTrue>
+      <and>
+        <equals arg1="${xy}${pad}" arg2="${ignoretrue}" />
+        <equals arg1="${xyz}${pad}" arg2="${ignorefalse}" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testForce" depends="xyz,pad" if="echo.can.run">
+    <presetdef name="ekko">
+      <apply executable="echo" append="true" dest="${basedir}">
+        <filelist refid="xyzlist" />
+        <mapper type="identity" />
+      </apply>
+    </presetdef>
+
+    <pathconvert property="xyz" pathsep="${pad}${eol}" refid="xyzlist" />
+
+    <ekko outputproperty="foo" />
+    <ekko outputproperty="bar" force="true" />
+
+    <au:assertTrue>
+      <and>
+        <equals arg1="${foo}" arg2="" />
+        <equals arg1="${bar}" arg2="${xyz}" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testNoDest" depends="xyz" if="echo.can.run">
+    <presetdef name="ekko">
+      <apply executable="echo" addsourcefile="false" force="true">
+        <filelist dir="${basedir}" files="x" />
+        <globmapper from="*" to="${basedir}/*" />
+        <targetfile />
+      </apply>
+    </presetdef>
+    <ekko outputproperty="dest" dest="${basedir}" />
+    <ekko outputproperty="nodest" />
+
+    <au:assertFileDoesntExist file="${dest}" />
+    <au:assertFileExists file="${nodest}" />
+  </target>
+
+  <target name="testLsPath" if="ls.can.run">
+    <apply executable="ls" parallel="false" outputproperty="lsPathOut"
+           force="true" dest="${basedir}" append="true" type="both">
+      <path path="${env.PATH}" />
+      <identitymapper/>
+    </apply>
+    <au:assertTrue>
+      <resourcecount count="1">
+        <restrict>
+          <propertyresource name="lsPathOut" />
+          <containsregexp expression="^${ls.can.run}$"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testLsPathParallel" if="ls.can.run">
+    <apply executable="ls" parallel="true" outputproperty="lsPathParallelOut"
+           force="true" dest="${basedir}" append="true" type="both">
+      <path path="${env.PATH}" />
+      <identitymapper/>
+    </apply>
+    <au:assertTrue>
+      <resourcecount count="1">
+        <restrict>
+          <propertyresource name="lsPathParallelOut" />
+          <containsregexp expression="^${ls.can.run}$"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="tearDown">
+    <delete>
+      <fileset refid="xyz" />
+      <fileset dir="${basedir}" includes="redirect.*" />
+      <fileset dir="${basedir}" includes="redirector.*" />
+    </delete>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/exec/parrot.sh b/trunk/src/tests/antunit/taskdefs/exec/parrot.sh
new file mode 100755
index 0000000..2467f23
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/exec/parrot.sh
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+for arg in "$@" ; do
+	echo $arg out
+	sleep 1
+	echo $arg err>&2
+done
diff --git a/trunk/src/tests/antunit/taskdefs/gzip-test.xml b/trunk/src/tests/antunit/taskdefs/gzip-test.xml
new file mode 100644
index 0000000..ead4efd
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/gzip-test.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+

+    <!-- note relies on antunit built from svn trunk (1.1-alpha) -->

+    <import file="../antunit-base.xml" />

+

+    <target name="setUp">

+        <mkdir dir="${java.io.tmpdir}/gzip-test" />

+        <mkdir dir="${java.io.tmpdir}/gzip-test/empty" />

+        <touch file="${java.io.tmpdir}/gzip-test/fileone" />

+        <touch file="${java.io.tmpdir}/gzip-test/filetwo" />

+    </target>

+

+    <target name="tearDown">

+        <delete includeemptydirs="true">

+            <fileset dir="${java.io.tmpdir}/gzip-test" />

+        </delete>

+    </target>

+

+    <target name="testFailNone">

+        <au:expectfailure expectedmessage="No resource selected, gzip needs exactly one resource." message="Should have thrown an exception">

+            <gzip destfile="${java.io.tmpdir}/gzip-test/file.gz">

+                <fileset dir="${java.io.tmpdir}/gzip-test/empty" />

+            </gzip>

+        </au:expectfailure>

+    </target>

+

+    <target name="testFailTwo">

+        <au:expectfailure expectedmessage="gzip cannot handle multiple resources at once. (2 resources were selected.)" message="Should have thrown an exception">

+            <gzip destfile="${java.io.tmpdir}/gzip-test/file.gz">

+                <fileset dir="${java.io.tmpdir}/gzip-test" />

+            </gzip>

+        </au:expectfailure>

+    </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/input-test.xml b/trunk/src/tests/antunit/taskdefs/input-test.xml
new file mode 100644
index 0000000..30586ff
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/input-test.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test-input" default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+	

+	<import file="../antunit-base.xml"/>

+	

+	<target name="setUp">

+		<available property="jdk1.6+" classname="java.util.ServiceLoader"/>

+	</target>

+		

+	<target name="test-secure-input" if="jdk1.6+">

+		<input message="secure-input:>" addproperty="the.password">

+			<handler classname="org.apache.tools.ant.input.SecureInputHandler"/>

+		</input>

+		<au:assertPropertySet name="the.password"/>

+	</target>

+	

+</project>
\ No newline at end of file
diff --git a/trunk/src/tests/antunit/taskdefs/jar-spi-test.xml b/trunk/src/tests/antunit/taskdefs/jar-spi-test.xml
new file mode 100644
index 0000000..c05311a
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/jar-spi-test.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <property name="jar.dir" location="jar_spi_dir"/>
+  <property name="jar.src.dir" location="jar_spi_dir/src"/>
+  <property name="jar.src.file" location="jar_spi_dir/src/a_file"/>
+    
+  <available property="jdk1.4+" classname="java.lang.CharSequence"/>  
+  <condition property="some.regexp.support">
+    <or>
+      <isset property="jdk1.4+"/>
+      <isset property="apache.regexp.present"/>
+      <isset property="apache.oro.present"/>
+    </or>
+  </condition>
+
+  <target name="init">
+    <mkdir dir="${jar.src.dir}"/>
+    <delete quiet="yes" file="${jar.src.file}"/>
+    <touch file="${jar.src.file}"/>
+    <delete quiet="yes" file="${jar.dir}/file.jar"/>
+    <delete quiet="yes" dir="${jar.dir}/output"/>
+  </target>
+
+  <target name="test-simple" depends="init" if="some.regexp.support">
+
+    <jar jarfile="${jar.dir}/file.jar">
+      <fileset dir="${jar.src.dir}"/>
+      <service type="a.b.c" provider="a.b.c.d"/>
+    </jar>
+
+    <unjar src="${jar.dir}/file.jar"
+           dest="${jar.dir}/output"/>
+
+    <loadfile property="simple"
+              srcfile="${jar.dir}/output/META-INF/services/a.b.c"
+              encoding="UTF-8"/>
+
+    <au:assertTrue>
+      <matches string="${simple}" pattern="^a\.b\.c\.d$"/>
+    </au:assertTrue>
+
+  </target>
+
+  <target name="test-providers" depends="init" if="some.regexp.support">
+
+    <jar jarfile="${jar.dir}/file.jar">
+      <fileset dir="${jar.src.dir}"/>
+      <service type="a.b.c">
+        <provider classname="a.X"/>
+        <provider classname="a.D"/>
+      </service>
+    </jar>
+
+    <unjar src="${jar.dir}/file.jar"
+           dest="${jar.dir}/output"/>
+
+    <loadfile property="providers"
+              srcfile="${jar.dir}/output/META-INF/services/a.b.c"
+              encoding="UTF-8"/>
+    <au:assertTrue>
+      <matches string="${providers}" pattern="^a\.X\na\.D$"/>
+    </au:assertTrue>
+
+  </target>
+
+  <target name="test-multi" depends="init" if="some.regexp.support">
+
+    <jar jarfile="${jar.dir}/file.jar">
+      <fileset dir="${jar.src.dir}"/>
+      <service type="a.b.c">
+        <provider classname="a.X"/>
+        <provider classname="a.D"/>
+      </service>
+      <service type="javax.a.service">
+        <provider classname="a.O.T"/>
+        <provider classname="a.B"/>
+      </service>
+    </jar>
+
+    <unjar src="${jar.dir}/file.jar"
+           dest="${jar.dir}/output"/>
+
+    <loadfile property="multi-a"
+              srcfile="${jar.dir}/output/META-INF/services/a.b.c"
+              encoding="UTF-8"/>
+
+    <au:assertTrue>
+      <matches string="${multi-a}" pattern="^a\.X\na\.D$"/>
+    </au:assertTrue>
+
+    <loadfile property="multi-b"
+              srcfile="${jar.dir}/output/META-INF/services/javax.a.service"
+              encoding="UTF-8"/>
+
+    <au:assertTrue>
+      <matches string="${multi-b}" pattern="^a\.O\.T\na\.B$"/>
+    </au:assertTrue>
+
+  </target>
+
+  <target name="test-reject-no-type" depends="init">
+    <au:expectfailure>
+      <jar jarfile="${jar.dir}/file.jar">
+        <fileset dir="${jar.src.dir}"/>
+        <service provider="a.X"/>
+      </jar>
+    </au:expectfailure>
+  </target>
+
+  <target name="test-reject-no-provider" depends="init">
+    <au:expectfailure>
+      <jar jarfile="${jar.dir}/file.jar">
+        <fileset dir="${jar.src.dir}"/>
+        <service type="a.X"/>
+      </jar>
+    </au:expectfailure>
+  </target>
+
+  <target name="test-reject-no-classname" depends="init">
+    <au:expectfailure>
+      <jar jarfile="${jar.dir}/file.jar">
+        <fileset dir="${jar.src.dir}"/>
+        <service type="a.X">
+          <provider/>
+        </service>
+      </jar>
+    </au:expectfailure>
+  </target>
+
+  <target name="tearDown">
+    <delete quiet="yes" dir="${jar.dir}"/>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/javac-dir/bad-src/Bad.java b/trunk/src/tests/antunit/taskdefs/javac-dir/bad-src/Bad.java
new file mode 100644
index 0000000..3b749f8
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/javac-dir/bad-src/Bad.java
@@ -0,0 +1,22 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/** a simple class with a bug */
+public class Simple {
+    // should get a not-terminated error
+    String s = ";
+}
diff --git a/trunk/src/tests/antunit/taskdefs/javac-dir/good-src/Simple.java b/trunk/src/tests/antunit/taskdefs/javac-dir/good-src/Simple.java
new file mode 100644
index 0000000..9c08f56
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/javac-dir/good-src/Simple.java
@@ -0,0 +1,20 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+/** a simple do nothing class */
+public class Simple {
+}
diff --git a/trunk/src/tests/antunit/taskdefs/javac-test.xml b/trunk/src/tests/antunit/taskdefs/javac-test.xml
new file mode 100644
index 0000000..8d4aafe
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/javac-test.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <property name="ant-build" location="../../../../build"/>
+  <property name="javac-dir" location="${ant-build}/ant-unit/javac-dir"/>
+  <property name="build-dir" location="${javac-dir}/build"/>
+  
+  <target name="test-includeDestClasses">
+    <property name="DATE" value="09/10/1999 4:30 pm"/>
+    <delete dir="${javac-dir}/src"/>
+    <mkdir dir="${javac-dir}/src"/>
+    <echo file="${javac-dir}/src/A.java">
+      public class A { B b;}
+    </echo>
+    <echo file="${javac-dir}/src/B.java">
+      public class B { }
+    </echo>
+    <delete dir="${javac-dir}/classes" quiet="yes"/>
+    <mkdir dir="${javac-dir}/classes"/>
+    <javac srcdir="${javac-dir}/src" destdir="${javac-dir}/classes"/>
+    <touch file="${javac-dir}/src/B.java" datetime="${DATE}"/>
+    <touch file="${javac-dir}/classes/B.class" datetime="${DATE}"/>
+    <!-- following should not update B.class -->
+    <delete quiet="yes" file="${javac-dir}/classes/A.class"/>
+    <javac srcdir="${javac-dir}/src" destdir="${javac-dir}/classes"/>
+    <au:assertTrue>
+      <isfileselected file="${javac-dir}/classes/B.class">
+        <date datetime="${DATE}" when="equal"/>
+      </isfileselected>
+    </au:assertTrue>
+    <!-- following should update B.class -->
+    <delete quiet="yes" file="${javac-dir}/classes/A.class"/>
+    <javac srcdir="${javac-dir}/src"
+           destdir="${javac-dir}/classes" includeDestClasses="no"/>
+    <au:assertFalse>
+      <isfileselected file="${javac-dir}/classes/B.class">
+        <date datetime="${DATE}" when="equal"/>
+      </isfileselected>
+    </au:assertFalse>
+  </target>
+
+  <target name="test-updated-property">
+    <delete quiet="yes" dir="${build-dir}"/>
+    <mkdir dir="${build-dir}"/>
+    <javac srcdir="javac-dir/good-src" destdir="${build-dir}"
+           updatedProperty="classes-updated"/>
+    <au:assertTrue>
+      <equals arg1="${classes-updated}" arg2="true"/>
+    </au:assertTrue>
+    <javac srcdir="javac-dir/good-src" destdir="${build-dir}"
+           updatedProperty="classes-updated-2"/>
+    <au:assertFalse>
+      <isset property="classes-updated-2"/>
+    </au:assertFalse>
+  </target>
+
+  <target name="test-error-property">
+    <delete quiet="yes" dir="${build-dir}"/>
+    <mkdir dir="${build-dir}"/>
+    <javac srcdir="javac-dir/good-src" destdir="${build-dir}"
+           failOnError="false"
+           errorProperty="compile-failed"/>
+    <au:assertTrue>
+      <equals arg1="${compile-failed}" arg2="${compile-failed}"/>
+    </au:assertTrue>
+    <javac srcdir="javac-dir/bad-src" destdir="${build-dir}"
+           failOnError="false"
+           errorProperty="compile-failed"/>
+    <au:assertTrue>
+      <equals arg1="${compile-failed}" arg2="true"/>
+    </au:assertTrue>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/length-test.xml b/trunk/src/tests/antunit/taskdefs/length-test.xml
new file mode 100644
index 0000000..8f5fd6b
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/length-test.xml
@@ -0,0 +1,238 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="length-test" default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../antunit-base.xml" />
+
+  <property name="dir" location="lengthtestdir" />
+  <property name="dir.a" location="${dir}/a" />
+  <property name="dir.b" location="${dir}/b" />
+  <property name="zipfile" location="lengthtest.zip" />
+
+  <target name="setUp">
+    <mkdir dir="${dir.a}" />
+    <mkdir dir="${dir.b}" />
+    <property name="foo" location="${dir.a}/foo" />
+    <property name="bar" location="${dir.b}/bar" />
+    <echo file="${foo}" message="foo" />
+    <echo file="${bar}" message="bar" />
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${dir}" />
+    <delete file="${zipfile}" />
+  </target>
+
+  <target name="testEach" depends="setUp">
+    <length mode="each" property="length.each">
+      <fileset id="fs" dir="${dir}" />
+    </length>
+    <length string="${length.each}" property="length.length.each" />
+    <length string="${foo}${bar}........${line.separator}"
+            property="length.expected" />
+
+    <au:assertTrue>
+      <!-- test that both files are represented, and that the
+           output is the expected length; do not assume order. -->
+      <and>
+        <contains string="${length.each}" substring="${foo} : 3" />
+        <contains string="${length.each}" substring="${bar} : 3" />
+        <equals arg1="${length.length.each}" arg2="${length.expected}" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testEachCondition" depends="setUp">
+    <length mode="each" property="length.each">
+      <fileset id="fs" dir="${dir}" />
+    </length>
+    <length string="${foo}${bar}........${line.separator}"
+            property="length.expected" />
+    <au:assertTrue>
+      <!-- test that both files are represented, and that the
+           output is the expected length; do not assume order. -->
+      <and>
+        <contains string="${length.each}" substring="${foo} : 3" />
+        <contains string="${length.each}" substring="${bar} : 3" />
+        <length string="${length.each}" length="${length.expected}" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testAll" depends="setUp">
+    <length property="length.all">
+      <fileset id="foo" file="${dir.a}/foo" />
+      <fileset id="bar" file="${dir.b}/bar" />
+    </length>
+    <au:assertTrue>
+      <equals arg1="6" arg2="${length.all}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testAllCondition" depends="setUp">
+    <au:assertTrue>
+      <length length="6">
+        <fileset id="foo" file="${dir.a}/foo" />
+        <fileset id="bar" file="${dir.b}/bar" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testFile" depends="setUp">
+    <length property="length.foo" file="${dir.a}/foo" />
+    <au:assertTrue>
+      <equals arg1="3" arg2="${length.foo}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testFileCondition" depends="setUp">
+    <au:assertTrue>
+      <length length="3" file="${dir.a}/foo" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testBoth" depends="setUp">
+    <length property="length.foo" file="${dir.a}/foo">
+      <fileset file="${dir.b}/bar" />
+    </length>
+    <au:assertTrue>
+      <equals arg1="6" arg2="${length.foo}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testBothCondition" depends="setUp">
+    <au:assertTrue>
+      <length length="6" file="${dir.a}/foo">
+        <fileset file="${dir.b}/bar" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testDupes" depends="setUp">
+    <length property="length.foo" file="${dir.a}/foo">
+      <fileset dir="${dir}" />
+    </length>
+    <au:assertTrue>
+      <equals arg1="9" arg2="${length.foo}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testDupesCondition" depends="setUp">
+    <au:assertTrue>
+      <length length="9" file="${dir.a}/foo">
+        <fileset dir="${dir}" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testString">
+    <length string="foo" property="length.string" />
+    <au:assertTrue>
+      <equals arg1="3" arg2="${length.string}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testStringCondition">
+    <au:assertTrue>
+      <length string="foo" length="3" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testTrimString">
+    <length string=" foo " trim="true" property="length.string" />
+    <au:assertTrue>
+      <equals arg1="3" arg2="${length.string}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testTrimStringCondition">
+    <au:assertTrue>
+      <length string=" foo " trim="true" length="3" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testNoTrimString">
+    <length string=" foo " property="length.string" />
+    <au:assertTrue>
+      <equals arg1="5" arg2="${length.string}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testNoTrimStringCondition">
+    <au:assertTrue>
+      <length string=" foo " length="5" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testTrimFile" description="should fail">
+    <au:expectfailure>
+      <length file="${ant.file}" trim="false" />
+    </au:expectfailure>
+  </target>
+
+  <target name="testStringFile" description="should fail">
+    <au:expectfailure>
+      <length string="foo" file="${ant.file}" />
+    </au:expectfailure>
+  </target>
+
+  <target name="testImmutable">
+    <length string="foo" property="length.string" />
+    <length string="foobar" property="length.string" />
+    <au:assertTrue>
+      <equals arg1="3" arg2="${length.string}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="zip" depends="setUp">
+    <zip destfile="${zipfile}">
+      <fileset file="${foo}" />
+      <fileset file="${bar}" />
+    </zip>
+  </target>
+
+  <target name="testZipFileSet" depends="zip">
+    <length property="length.zipfile1">
+      <zipfileset src="${zipfile}" />
+    </length>
+    <length property="length.zipfile2">
+      <zipfileset src="${zipfile}" includes="bar" />
+    </length>
+    <au:assertTrue>
+      <and>
+        <equals arg1="6" arg2="${length.zipfile1}" />
+        <equals arg1="3" arg2="${length.zipfile2}" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testZipFileSetCondition" depends="zip">
+    <au:assertTrue>
+      <and>
+        <length length="6">
+          <zipfileset src="${zipfile}" />
+        </length>
+        <length length="3">
+          <zipfileset src="${zipfile}" includes="bar" />
+        </length>
+      </and>
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/loadresource-test.xml b/trunk/src/tests/antunit/taskdefs/loadresource-test.xml
new file mode 100644
index 0000000..7836e63
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/loadresource-test.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+

+  <import file="../antunit-base.xml" />

+

+  <target name="test-resourceString">

+    <loadresource property="p">

+      <string value="one"/>

+    </loadresource >

+    <au:assertPropertyEquals name="p" value="one"/>

+  </target>

+

+  <target name="test-resourceSizeZero" description="Bug 42319">

+    <loadresource property="p">

+      <string value=""/>

+    </loadresource >

+    <au:assertTrue>

+      <not>

+        <isset property="p"/>

+      </not>

+    </au:assertTrue>

+    <au:assertLogContains text="Do not set property p as its length is 0."/>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/macrodef-test.xml b/trunk/src/tests/antunit/taskdefs/macrodef-test.xml
new file mode 100644
index 0000000..460bdf9
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/macrodef-test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="length-test" default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../antunit-base.xml" />
+
+  <target name="testDefaultTest">
+    <macrodef name="test-log">
+      <text name="log" default="DEFAULT-LOG-VALUE"/>
+      <sequential>
+        <concat>@{log}</concat>
+      </sequential>
+    </macrodef>
+    <test-log/>
+    <au:assertLogContains text="DEFAULT-LOG-VALUE"/>
+    <test-log>THIS IS NOT DEFAULT LOG</test-log>
+    <au:assertLogContains text="THIS IS NOT DEFAULT LOG"/>
+  </target>
+
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/move-test.xml b/trunk/src/tests/antunit/taskdefs/move-test.xml
new file mode 100644
index 0000000..6c950a3
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/move-test.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+  <import file="../antunit-base.xml" />

+

+  <target name="test-move-caseonly">

+    <!-- this test is inspired by bugzilla 41948 -->

+    <!-- Especially interesting if executed on case-insensitive file systems -->

+    <touch file="${java.io.tmpdir}/abc"/>

+    <move file="${java.io.tmpdir}/abc" tofile="${java.io.tmpdir}/aBc"/>

+    <fileset dir="${java.io.tmpdir}" id="myfs">

+      <include name="aBc"/>

+    </fileset>

+    <pathconvert refid="myfs" property="myproperty" setonempty="false"/>

+    <au:assertPropertySet name="myproperty" message="abc was not renamed aBc"/>

+  </target>

+

+  <target name="tearDown">

+    <delete file="${java.io.tmpdir}/aBc"/>

+  </target>

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/optional/junit/junit-outputtoformatters-test.xml b/trunk/src/tests/antunit/taskdefs/optional/junit/junit-outputtoformatters-test.xml
new file mode 100644
index 0000000..6a1ab76
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/optional/junit/junit-outputtoformatters-test.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit">
+  <property name="ant-build" location="../../../../../../build"/>
+  <property name="build-junit-dir" location="${ant-build}/ant-unit/junit-dir"/>
+  <property name="classes.dir" location="${build-junit-dir}/classes"/>
+  <property name="reports.dir" location="${build-junit-dir}/report"/>
+
+  <macrodef name="assert-file-not-contains" backtrace="no">
+    <sequential>
+      <au:assertFalse>
+        <isfileselected file="${reports.dir}/TEST-ExampleTest.txt">
+          <contains text="Hello From Test"/>
+        </isfileselected>
+      </au:assertFalse>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assert-file-contains" backtrace="no">
+    <sequential>
+      <au:assertTrue>
+        <isfileselected file="${reports.dir}/TEST-ExampleTest.txt">
+          <contains text="Hello From Test"/>
+        </isfileselected>
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assert-log-not-contains" backtrace="no">
+    <sequential>
+      <au:assertLogDoesntContain text="Hello From Test" />
+    </sequential>
+  </macrodef>
+
+  <macrodef name="assert-log-contains" backtrace="no">
+    <sequential>
+      <au:assertLogContains text="Hello From Test" />
+    </sequential>
+  </macrodef>
+
+  <macrodef name="run-junit">
+    <attribute name="fork"/>
+    <attribute name="showoutput"/>
+    <attribute name="outputtoformatters"/>
+    <sequential>
+      <junit fork="@{fork}" haltonfailure="no" showoutput="@{showoutput}"
+           outputtoformatters="@{outputtoformatters}">
+        <test name="ExampleTest" todir="${reports.dir}"/> 
+        <classpath path="${classes.dir}"/>
+        <formatter type="plain" usefile="yes"/>
+      </junit>
+    </sequential>
+  </macrodef>
+
+  <target name="init">
+    <delete quiet="yes" dir="${build-junit-dir}"/>
+    <mkdir  dir="${classes.dir}"/>
+    <mkdir  dir="${reports.dir}"/>
+  </target>
+    
+  <target name="compile" depends="init">
+    <javac srcdir="src" destdir="${classes.dir}" debug="yes"/>
+  </target>
+
+  <target name="test-show-yes-formatters-yes" depends="compile">
+    <run-junit fork="yes" showoutput="yes"
+               outputtoformatters="yes"/>
+    <assert-log-contains/>
+    <assert-file-contains/>
+  </target>
+
+  <target name="test-show-yes-formatters-no" depends="compile">
+    <run-junit fork="yes" showoutput="yes"
+               outputtoformatters="no"/>
+    <assert-log-contains/>
+    <assert-file-not-contains/>
+  </target>
+
+  <target name="test-show-yes-formatters-no-forkno" depends="compile">
+    <run-junit fork="no" showoutput="yes"
+               outputtoformatters="no"/>
+    <assert-log-contains/>
+    <assert-file-not-contains/>
+  </target>
+
+  <target name="test-show-no-formatters-no" depends="compile">
+    <run-junit fork="yes" showoutput="no"
+               outputtoformatters="no"/>
+    <assert-log-not-contains/>
+    <assert-file-not-contains/>
+  </target>
+
+  <target name="test-show-no-formatters-no-fork-no" depends="compile">
+    <run-junit fork="no" showoutput="no"
+               outputtoformatters="no"/>
+    <assert-log-not-contains/>
+    <assert-file-not-contains/>
+  </target>
+
+  <target name="test-show-no-formatters-yes" depends="compile">
+    <run-junit fork="yes" showoutput="no"
+               outputtoformatters="yes"/>
+    <assert-log-not-contains/>
+    <assert-file-contains/>
+  </target>
+
+  <target name="test-show-no-formatters-yes-fork-no" depends="compile">
+    <run-junit fork="no" showoutput="no"
+               outputtoformatters="yes"/>
+    <assert-log-not-contains/>
+    <assert-file-contains/>
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset file="${ant.file}"/>
+      <au:plainlistener/>
+    </au:antunit>
+  </target>
+
+</project>
+
diff --git a/trunk/src/tests/antunit/taskdefs/optional/junit/src/ExampleTest.java b/trunk/src/tests/antunit/taskdefs/optional/junit/src/ExampleTest.java
new file mode 100644
index 0000000..f1e5ca2
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/optional/junit/src/ExampleTest.java
@@ -0,0 +1,23 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+import junit.framework.TestCase;
+
+public class ExampleTest extends TestCase {
+    public void testHello() {
+        System.out.println("Hello From Test");
+    }
+}
diff --git a/trunk/src/tests/antunit/taskdefs/optional/script/scriptdef-test.xml b/trunk/src/tests/antunit/taskdefs/optional/script/scriptdef-test.xml
new file mode 100644
index 0000000..e1b0c07
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/optional/script/scriptdef-test.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../../../antunit-base.xml"/>	
+	
+  <description>
+    In which we test interesting aspects of scripting.
+    The targeted language is javascript; this lets us run without
+    additions on Java6+.
+  </description>
+  
+  <target name="tearDown">
+  </target>
+
+  <condition property="prereqs-ok">
+    <or>
+      <available classname="org.apache.bsf.BSFManager"/>
+      <available classname="javax.script.ScriptEngineManager"/>
+    </or>
+  </condition>
+
+  <property name="script.manager" value="auto" />
+
+  <string id="script.code">
+    self.log("Ant version =${ant.version}");
+    project.setNewProperty("property","live");
+  </string>
+
+  <presetdef name="js">
+    <scriptdef language="javascript" name="scripttest"
+        manager="${script.manager}">
+      <!-- optional property attribute-->
+      <attribute name="property" />
+    </scriptdef>
+  </presetdef>
+
+  <property name="prop"
+      value='self.log("Ant version =${ant.version}");project.setNewProperty("property","live");' />
+
+  <presetdef name="assertPropSet">
+    <au:assertPropertyEquals name="property" value="live" />
+  </presetdef>
+
+
+  <!--purely to test that everything works -->
+  <target name="testInline" if="prereqs-ok">
+    <js>self.log("Hello");</js>
+    <scripttest/>
+  </target>
+
+  <target name="testStringResource" if="prereqs-ok">
+    <js>
+      <string value='self.log("Ant version =${ant.version}");' />
+    </js>
+    <scripttest/>
+  </target>
+
+  <target name="testStringResourceRef" if="prereqs-ok">
+    <js>
+      <string refid="script.code" />
+    </js>
+    <scripttest/>
+    <assertPropSet />
+  </target>
+
+  <target name="testStringResourceInline" if="prereqs-ok">
+    <js>
+      <string>
+        self.log("Ant version =${ant.version}");
+        project.setNewProperty("property","live");
+      </string>
+    </js>
+    <scripttest/>
+    <assertPropSet/>
+  </target>
+
+  <target name="testPropertyResource" if="prereqs-ok">
+    <js>
+      <propertyresource name="prop" />
+    </js>
+    <scripttest/>
+    <assertPropSet/>
+  </target>
+
+  <target name="testMixedResources" if="prereqs-ok">
+    <js>
+      <string refid="script.code" />
+      <propertyresource name="prop" />
+      <string >
+        project.setNewProperty("property2","live");
+      </string>
+    </js>
+    <scripttest/>
+    <assertPropSet name="property2" />
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml b/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml
new file mode 100644
index 0000000..fe5ba33
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/optional/unix/symlink-test.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="symlink-test"
+    default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../../../antunit-base.xml"/>
+
+  <property name="build.dir" location="build" />
+
+  <target name="setUp">
+    <condition property="isUnix">
+      <os family="unix" />
+    </condition>
+  </target>
+
+  <target name="os">
+
+    <mkdir dir="${build.dir}" />
+    <condition property="unix">
+      <os family="unix" />
+    </condition>
+    <property name="file_ref"
+      location="${build.dir}/file"/>
+    <property name="hanging_ref"
+        location="${build.dir}/hanging_ref"/>
+  </target>
+
+  <target name="init" depends="os" if="unix">
+    <touch file="${file_ref}" />
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${build.dir}" />
+  </target>
+
+  <target name="testCreateDouble" depends="init" if="unix">
+    <symlink overwrite="true" link="${build.dir}/link"
+        resource="${file_ref}"/>
+    <symlink overwrite="true" link="${build.dir}/link"
+        resource="${file_ref}"/>
+  </target>
+
+
+  <target name="testCreateDoubleHanging" depends="init" if="unix">
+    <symlink overwrite="true" link="${build.dir}/link2"
+        resource="${hanging_ref}"/>
+    <symlink overwrite="true" link="${build.dir}/link2"
+        resource="${hanging_ref}"/>
+  </target>
+
+  <target name="testCreateOverFile" depends="init" if="unix">
+    <touch file="${build.dir}/link3" />
+    <symlink overwrite="true" link="${build.dir}/link3"
+        resource="${file_ref}"/>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/pathconvert-test.xml b/trunk/src/tests/antunit/taskdefs/pathconvert-test.xml
new file mode 100644
index 0000000..3683aff
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/pathconvert-test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <target name="test-dir-char">
+    <pathconvert property="def|ghi" dirsep="|">
+      <map from="${basedir}/abc/" to=''/>
+      <path location="abc/def/ghi"/>
+    </pathconvert>
+    <au:assertTrue>
+      <equals arg1="${def|ghi}" arg2="def|ghi"/>
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/propertyhelper-test.xml b/trunk/src/tests/antunit/taskdefs/propertyhelper-test.xml
new file mode 100644
index 0000000..56ba64e
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/propertyhelper-test.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <!-- each test verifies that the PropertyEvaluator delegate works -->
+  <import file="../antunit-base.xml" />
+
+  <available property="prereqs-ok" classname="org.apache.bsf.BSFManager"/>
+
+  <target name="setUp" unless="setup.complete" if="prereqs-ok">
+    <script language="beanshell" manager="bsf">
+      import org.apache.tools.ant.PropertyHelper;
+      public class MapEvaluator implements PropertyHelper.PropertyEvaluator {
+        HashMap map = new HashMap();
+        public MapEvaluator() {
+          map.put("string", "string");
+          map.put("object", new Object());
+          map.put("int", new Integer(1));
+          map.put("null", null);
+        }
+        public Object evaluate(String property, PropertyHelper propertyHelper) {
+          return map.get(property.toLowerCase());
+        }
+      }
+      project.addReference("mapEvaluator", new MapEvaluator());
+    </script>
+    <propertyhelper>
+      <delegate refid="mapEvaluator" />
+    </propertyhelper>
+    <property name="setup.complete" value="true" />
+  </target>
+
+  <target name="testValueTypes" depends="setUp" if="prereqs-ok">
+    <!-- verify BC, strings -->
+    <au:assertPropertyEquals name="string" value="${STRING}" />
+
+    <!-- verify non-string properties -->
+    <au:assertPropertyEquals name="object" value="${OBJECT}" />
+    <au:assertPropertyEquals name="int" value="${INT}" />
+
+    <!-- verify that a string containing nothing but a property reference is a valid value -->
+    <property name="string2" value="${string}" />
+    <au:assertPropertyEquals name="string2" value="${string}" />
+
+    <property name="object2" value="${object}" />
+    <!-- demonstrate that equals args can be non-string -->
+    <au:assertPropertyEquals name="object2" value="${object}" />
+
+    <property name="int2" value="${int}" />
+    <au:assertPropertyEquals name="int2" value="${int}" />
+  </target>
+
+  <target name="testNull" depends="setUp" if="prereqs-ok">
+    <!-- demonstrate that a null value always implies a nonexistent property -->
+    <au:assertFalse>
+      <isset property="null" />
+    </au:assertFalse>
+  </target>
+
+  <target name="testAvailable" depends="setUp" if="prereqs-ok">
+    <!-- verify the available task can set a non-string property -->
+    <available file="${ant.file}" type="file" property="available.string" value="bc" />
+    <au:assertPropertyEquals name="available.string" value="bc" />
+    <available file="${ant.file}" type="file" property="available.object" value="${object}" />
+    <au:assertPropertyEquals name="available.object" value="${OBJECT}" />
+  </target>
+
+  <target name="testCondition" depends="setUp" if="prereqs-ok">
+    <!-- verify the condition task can set a non-string property -->
+    <echo>$${ant.file}=${ant.file}</echo>
+    <condition property="condition.true.string">
+      <available file="${ant.file}" type="file" />
+    </condition>
+    <au:assertPropertyEquals name="condition.true.string" value="true" />
+    <condition property="condition.else.string" value="true" else="false">
+      <not><available file="${ant.file}" type="file" /></not>
+    </condition>
+    <au:assertPropertyEquals name="condition.else.string" value="false" />
+    <condition property="condition.true.object" value="${object}">
+      <available file="${ant.file}" type="file" />
+    </condition>
+    <au:assertPropertyEquals name="condition.true.object" value="${OBJECT}" />
+    <condition property="condition.else.int" value="${object}" else="${int}">
+      <not><available file="${ant.file}" type="file" /></not>
+    </condition>
+    <au:assertPropertyEquals name="condition.else.int" value="${INT}" />
+  </target>
+
+  <target name="testEmbeddedNonString" if="prereqs-ok">
+    <!-- verify that a property embedded in a string is a substring -->
+    <au:assertTrue>
+      <equals arg1="@${int}@" arg2="@1@" />
+    </au:assertTrue>
+  </target>
+
+  <target name="testLoadProperties" if="prereqs-ok">
+    <au:assertFalse>
+      <isset property="object2" />
+    </au:assertFalse>
+    <string id="props" value="object2=$${object}" />
+    <!-- verify the property is not yet expanded -->
+    <au:assertTrue>
+      <length length="17">
+        <resource refid="props" />
+      </length>
+    </au:assertTrue>
+    <loadproperties>
+      <resource refid="props" />
+    </loadproperties>
+    <au:assertPropertyEquals name="object2" value="${object}" />
+    <au:assertPropertyEquals name="object2" value="${OBJECT}" />
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/retry-test.xml b/trunk/src/tests/antunit/taskdefs/retry-test.xml
new file mode 100644
index 0000000..74ae060
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/retry-test.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="retry-test" default="antunit" xmlns:au="antlib:org.apache.ant.antunit">

+  <import file="../antunit-base.xml"/>

+

+  <target name="test-fail-and-retry">

+    <property name="i" value="3"/>

+    <property name="dest" value="${java.io.tmpdir}/dest"/>

+    <!-- just in case this ever becomes a legit url... -->

+    <property name="src" value="http://iojasodjojaosdj"/>

+    <au:expectfailure expectedmessage="Task [get] failed after [${i}] attempts; giving up">

+      <retry retrycount="${i}">

+        <get src="${src}" dest="${dest}"/>

+      </retry>

+    </au:expectfailure>

+    <au:assertLogContains text="Attempt [1]: error occurred; retrying..."/>

+  </target>

+

+  <target name="test-success">

+    <property name="i" value="3"/>

+    <property name="dest" value="${java.io.tmpdir}/dest"/>

+    <retry retrycount="${i}">

+      <touch file="${dest}"/>

+    </retry>

+    <au:assertLogDoesntContain text="Attempt [1]: error occurred; retrying..."/>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/taskdefs/subant-test.xml b/trunk/src/tests/antunit/taskdefs/subant-test.xml
new file mode 100644
index 0000000..7fc925b
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/subant-test.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+
+  <description>
+    Test that subant properly sets various properties
+  </description>
+  <import file="../antunit-base.xml" />
+
+  <target name="tearDown">
+    <delete file="binaryAppendDest" />
+    <delete file="encodeStringDest" />
+  </target>
+
+  <target name="assertProperties">
+    <au:assertPropertySet name="ant.version" />
+    <au:assertPropertySet name="java.home" />
+    <au:assertPropertySet name="java.class.path" />
+  </target>
+
+  <target name="testAntVersion">
+    <subant inheritall="false" target="assertProperties">
+      <fileset file="${ant.file}" />
+    </subant>
+  </target>
+
+</project>
\ No newline at end of file
diff --git a/trunk/src/tests/antunit/taskdefs/touch-test.xml b/trunk/src/tests/antunit/taskdefs/touch-test.xml
new file mode 100644
index 0000000..a9327ed
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/touch-test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="touch-test" default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml"/>
+
+  <target name="test-no-child">
+    <au:expectfailure>
+      <touch />
+    </au:expectfailure>
+  </target>
+
+  <target name="test-no-match">
+    <touch>
+      <fileset file="${ant.file}">
+        <filename name="IDONOTMATCH" />
+      </fileset>
+    </touch>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/truncate/truncate-test.xml b/trunk/src/tests/antunit/taskdefs/truncate/truncate-test.xml
new file mode 100644
index 0000000..86f896c
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/truncate/truncate-test.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="truncate-test" default="default"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <target name="default">
+    <au:antunit>
+      <file file="${ant.file}" />
+    </au:antunit>
+  </target>
+
+  <target name="tearDown">
+    <delete file="foo" />
+    <delete file="bar" />
+    <delete dir="baz" />
+  </target>
+
+  <target name="test-basic">
+    <truncate file="foo" />
+    <au:assertTrue>
+      <length file="foo" length="0" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-explicit">
+    <truncate file="foo" length="1034" />
+    <au:assertTrue>
+      <length file="foo" length="1034" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-extend">
+    <truncate file="foo" length="5" />
+    <au:assertTrue>
+      <length file="foo" length="5" />
+    </au:assertTrue>
+    <truncate file="foo" adjust="5" />
+    <au:assertTrue>
+      <length file="foo" length="10" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-truncate">
+    <truncate file="foo" length="5" />
+    <au:assertTrue>
+      <length file="foo" length="5" />
+    </au:assertTrue>
+    <truncate file="foo" adjust="-5" />
+    <au:assertTrue>
+      <length file="foo" length="0" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-bigger">
+    <truncate file="foo" length="1K" />
+    <au:assertTrue>
+      <and>
+        <length file="foo" length="1K" />
+        <length file="foo" length="1024" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="truncate-bigger">
+    <truncate file="foo" length="3K" />
+    <au:assertTrue>
+      <length file="foo" length="3K" />
+    </au:assertTrue>
+    <truncate file="foo" adjust="-2K" />
+    <au:assertTrue>
+      <length file="foo" length="1K" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-no-create">
+    <au:assertFileDoesntExist file="foo" />
+    <truncate file="foo" create="false" length="0" />
+    <au:assertFileDoesntExist file="foo" />
+  </target>
+
+  <target name="test-mkdirs">
+    <au:assertFileDoesntExist file="baz" />
+    <truncate file="baz/foo" mkdirs="true" length="0" />
+    <au:assertTrue>
+      <length file="baz/foo" length="0" />
+    </au:assertTrue>
+  </target>
+
+  <target name="test-rc">
+    <truncate length="10">
+      <resources>
+        <file file="foo" />
+        <file file="bar" />
+      </resources>
+    </truncate>
+    <au:assertTrue>
+      <and>
+        <length file="foo" length="10" />
+        <length file="bar" length="10" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-bad-resource">
+    <au:expectfailure>
+      <truncate length="1P">
+        <string value="blah" />
+      </truncate>
+    </au:expectfailure>
+  </target>
+
+  <target name="test-invalid-attrs">
+    <au:expectfailure>
+      <truncate file="foo" length="0" adjust="0" />
+    </au:expectfailure>
+  </target>
+
+  <target name="test-bad-length">
+    <au:expectfailure>
+      <truncate file="foo" length="-1P" />
+    </au:expectfailure>
+  </target>
+
+  <target name="test-no-files">
+    <au:expectfailure>
+      <truncate length="0" />
+    </au:expectfailure>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/utf-16.expected b/trunk/src/tests/antunit/taskdefs/utf-16.expected
new file mode 100755
index 0000000..7c7c2a7
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/utf-16.expected
Binary files differ
diff --git a/trunk/src/tests/antunit/taskdefs/utf-16.expected.windows b/trunk/src/tests/antunit/taskdefs/utf-16.expected.windows
new file mode 100644
index 0000000..1e138e8
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/utf-16.expected.windows
Binary files differ
diff --git a/trunk/src/tests/antunit/taskdefs/war-test.xml b/trunk/src/tests/antunit/taskdefs/war-test.xml
new file mode 100644
index 0000000..1d07315
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/war-test.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="war-test" basedir="." default="antunit"
+       xmlns:au="antlib:org.apache.ant.antunit">
+  <property name="working.dir" value="working"/>
+
+  <import file="../antunit-base.xml" />
+
+  <target name="init">
+    <delete dir="${working.dir}"/>
+    <mkdir dir="${working.dir}"/>
+    <property name="warfile" location="${working.dir}/test.war"/>
+    <property name="web.xml" location="web.xml"/>
+    <property name="webxml.generated" location="${working.dir}/WEB-INF/web.xml"/>
+
+    <!--failing on duplicates is half our testing-->
+    <presetdef name="mkwar">
+      <war destfile="${warfile}" duplicate="fail"/>
+    </presetdef>
+    <presetdef name="expandwar">
+      <unzip src="${working.dir}/test.war" dest="${working.dir}"/>
+    </presetdef>
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${working.dir}"/>
+  </target>
+
+  <!--test that you can patch a fileset reference into a lib element-->
+  <target name="testlibrefs" depends="init">
+    <mkwar webxml="${web.xml}">
+      <fileset id="test" dir="." includes="web.xml"/>
+      <lib refid="test"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+  <!-- 
+  This checks that as of Java EE 5, the web.xml attr is optional.
+  Here there is a web.xml, in the webinf fileset, rather than a fileset
+  -->
+  <target name="testWebXmlInWebinf" depends="init">
+    <mkwar>
+      <webinf dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+  <target name="testWebXmlMissingFromUpdate" depends="init">
+    <mkwar webxml="${web.xml}" />
+    <!-- there is no web.xml file, but that is ok, as
+      we are updating -->
+    <mkwar update="true">
+      <classes dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+  <target name="testWebXmlInImplicitUpdate" depends="init">
+    <mkwar webxml="${web.xml}" />
+    <!-- when we are implicitly updating, the web.xml file does not get
+     pulled in, but the command still succeeds.-->
+    <mkwar webxml="${web.xml}" >
+      <classes dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+  <target name="NotestWebXmlFilesetInImplicitUpdate" depends="init">
+    <mkwar webxml="${web.xml}" />
+    <!-- when we are implicitly updating, the web.xml file does not get
+     pulled in, but the command still succeeds.-->
+    <mkwar >
+      <webinf dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+
+  <target name="testDuplicateWebXml" depends="init">
+    <mkwar webxml="${web.xml}" >
+      <webinf dir="." includes="web.xml"/>
+      <webinf file="${web.xml}"/>
+      <zipfileset file="${web.xml}" prefix="WEB-INF"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+  </target>
+
+  <target name="testDifferentDuplicateWebXml" depends="init">
+    <copy file="${web.xml}" todir="${working.dir}" />
+    <mkwar webxml="${web.xml}" >
+      <webinf dir="${working.dir}" includes="web.xml"/>
+      <webinf file="${web.xml}"/>
+      <zipfileset file="${web.xml}" prefix="WEB-INF"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${webxml.generated}" />
+    <au:assertLogContains text="The duplicate entry is"/>
+  </target>
+
+
+  <!--
+    this target does not have a web.xml file.
+    Instead it pulls in
+  -->
+  <target name="testWebXmlOptional" depends="init">
+    <mkwar needxmlfile="false">
+      <classes dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${working.dir}/WEB-INF/classes/web.xml" />
+    <au:assertFalse>
+      <available file="${webxml.generated}" />
+    </au:assertFalse>
+  </target>
+
+  <target name="testWebXmlOptionalFailure" depends="init">
+    <au:expectfailure>
+      <mkwar >
+        <classes dir="." includes="web.xml"/>
+      </mkwar>
+    </au:expectfailure>
+  </target>
+
+  <target name="testWebXmlOptionalFailure2" depends="init">
+    <au:expectfailure>
+      <mkwar  needxmlfile="true">
+        <classes dir="." includes="web.xml"/>
+      </mkwar>
+    </au:expectfailure>
+  </target>
+
+  <target name="testClassesElement" depends="init">
+    <mkwar needxmlfile="false">
+      <classes dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${working.dir}/WEB-INF/classes/web.xml" />
+  </target>
+
+  <target name="testLibElement" depends="init">
+    <mkwar needxmlfile="false">
+      <lib dir="." includes="web.xml"/>
+    </mkwar>
+    <expandwar/>
+    <au:assertFileExists file="${working.dir}/WEB-INF/lib/web.xml" />
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/web.xml b/trunk/src/tests/antunit/taskdefs/web.xml
new file mode 100644
index 0000000..414625a
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/web.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         version="2.5" metadata-complete="true">
+
+</web-app>
diff --git a/trunk/src/tests/antunit/taskdefs/whichresource-test.xml b/trunk/src/tests/antunit/taskdefs/whichresource-test.xml
new file mode 100644
index 0000000..a69fbfe
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/whichresource-test.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <property name="ant-build" location="../../../../build"/>
+  <property name="build-dir" 
+            location="${ant-build}/ant-unit/whichresource/build"/>
+
+  <target name="init">
+    <delete quiet="yes" dir="${build-dir}"/>
+    <mkdir dir="${build-dir}"/>
+    <javac srcdir="javac-dir/good-src" destdir="${build-dir}"/>
+    <path id="whichresource-build" path="${build-dir}"/>
+  </target>
+  
+  <target name="test-reference" depends="init">
+    <whichresource
+      property="whichresource.prop"
+      class="Simple"
+      classpathref="whichresource-build"/>
+
+    <au:assertTrue>
+      <contains string="${whichresource.prop}"
+                substring="Simple.class"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-not-present" depends="init">
+    <whichresource
+      property="whichresource2.prop"
+      class="ClassNotPresent"
+      classpathref="whichresource-build"/>
+
+    <au:assertFalse>
+      <isset property="whichresource.prop2"/>
+    </au:assertFalse>
+  </target>
+    
+</project>
diff --git a/trunk/src/tests/antunit/taskdefs/xmlproperty-test.xml b/trunk/src/tests/antunit/taskdefs/xmlproperty-test.xml
new file mode 100644
index 0000000..ac3c9c8
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/xmlproperty-test.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <description/>
+  <target name="test-empty">
+    <xmlproperty file="xmlproperty-test.xml"/>
+    <au:assertTrue>
+      <equals arg1="" arg2="${project.description}"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-multi">
+    <property name="root.element.value" value="original"/>
+    <xmlproperty file="xmlproperty.multi.xml" collapseAttributes="yes"/>
+    <au:assertTrue>
+      <equals arg1="original" arg2="${root.element.value}"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="load">
+    <xmlproperty
+        file="xmlproperty.inline-expansion.xml"
+        collapseAttributes="true"
+        keepRoot="false"
+        semanticAttributes="true"/>
+    <echo>
+ element      expected    actual
+    p         $${app.n}    ${app.p}
+    n            n        ${app.n}
+    o            n        ${app.o}
+    m            n        ${app.m}
+    </echo>
+  </target>
+
+  <target name="NotestInlineExpansion" depends="load">
+    <au:assertPropertyEquals name="app.m" value="n"/>
+    <au:assertPropertyEquals name="app.n" value="n"/>
+    <au:assertPropertyEquals name="app.o" value="n"/>
+    <au:assertPropertyEquals name="app.p" value="$${app.n}"/>
+    <property name="sequence" value="${app.m}${app.n}${app.o}${app.p}"/>
+    <fail>
+      xml attributes are not expanding correctly
+      expected: mnop=nnn$${app.n}
+      actual    mnop=${sequence}
+      <condition>
+        <not>
+          <equals arg1="${sequence}" arg2="nnn${app.n}"/>
+        </not>
+      </condition>
+    </fail>
+  </target>
+</project>
+
diff --git a/trunk/src/tests/antunit/taskdefs/xmlproperty.inline-expansion.xml b/trunk/src/tests/antunit/taskdefs/xmlproperty.inline-expansion.xml
new file mode 100644
index 0000000..a915179
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/xmlproperty.inline-expansion.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root-tag>
+  <!--used to check that the ordering of attribute expansion/eval is the order of
+  declaration in the build file, not alphabetical
+
+    expectations are
+      p : ${app.n}
+      n : n
+      o : n
+      m : n
+  -->
+  <app
+      p="${app.n}"
+      n="n"
+      o="${app.n}"
+      m="${app.n}"/>
+</root-tag>
\ No newline at end of file
diff --git a/trunk/src/tests/antunit/taskdefs/xmlproperty.multi.xml b/trunk/src/tests/antunit/taskdefs/xmlproperty.multi.xml
new file mode 100644
index 0000000..9899c58
--- /dev/null
+++ b/trunk/src/tests/antunit/taskdefs/xmlproperty.multi.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<root>
+   <element value="a" />
+   <element value="b" />
+</root>
diff --git a/trunk/src/tests/antunit/types/build-embedded-ref.xml b/trunk/src/tests/antunit/types/build-embedded-ref.xml
new file mode 100644
index 0000000..f2cbd2a
--- /dev/null
+++ b/trunk/src/tests/antunit/types/build-embedded-ref.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all">
+  <target name="all"/>
+</project>
diff --git a/trunk/src/tests/antunit/types/conditions/isreference-test.xml b/trunk/src/tests/antunit/types/conditions/isreference-test.xml
new file mode 100644
index 0000000..8929e90
--- /dev/null
+++ b/trunk/src/tests/antunit/types/conditions/isreference-test.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="isreference-test" default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../../antunit-base.xml" />
+
+  <target name="out-of-band">
+    <path id="out-of-band" path="."/>
+  </target>
+
+  <target name="testOutOfBand">
+    <au:assertFalse>
+      <isreference refid="out-of-band"/>
+    </au:assertFalse>
+  </target>
+
+  <target name="testInBand">
+    <path id="in-band" path="."/>
+    <au:assertTrue>
+      <isreference refid="in-band"/>
+    </au:assertTrue>
+  </target>
+</project>
+
diff --git a/trunk/src/tests/antunit/types/conditions/matches-test.xml b/trunk/src/tests/antunit/types/conditions/matches-test.xml
new file mode 100644
index 0000000..5d17461
--- /dev/null
+++ b/trunk/src/tests/antunit/types/conditions/matches-test.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <!-- NB: ant's interface to JDK14 regex enables UNIX_LINES -->
+  <property name="NL" value="&#10;"/>
+  <regexp id="myid" pattern="^[a-z]{3,4}$"/>
+
+  <available property="jdk1.4+" classname="java.lang.CharSequence"/>  
+  <condition property="some.regexp.support">
+    <or>
+      <isset property="jdk1.4+"/>
+      <isset property="apache.regexp.present"/>
+      <isset property="apache.oro.present"/>
+    </or>
+  </condition>
+    
+  <target name="test-refid" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="abc">
+        <regexp refid="myid"/>
+      </matches>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-simple" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="abc" pattern="^[a-z]{3,4}$"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-nomatch" if="some.regexp.support">
+    <au:assertFalse>
+      <matches string="abc" pattern="^b.*" />
+    </au:assertFalse>
+  </target>
+
+  <target name="test-date" if="some.regexp.support">
+    <tstamp>
+      <format property="today" pattern="dd-MM-yyyy" locale="en"/>
+    </tstamp>
+    <au:assertTrue>
+      <matches string="${today}">
+        <regexp pattern="^[0123]\d-[01]\d-[12]\d\d\d$" />
+      </matches>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-abc" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="abc" pattern="ab?"/>
+    </au:assertTrue>
+    <au:assertTrue>
+      <matches string="abc" pattern="ab."/>
+    </au:assertTrue>
+    <au:assertTrue>
+      <matches string="ab" pattern="ab?"/>
+    </au:assertTrue>
+    <au:assertTrue>
+      <matches string="ab" pattern="ab"/>
+    </au:assertTrue>
+    <au:assertTrue>
+      <matches string="acb" pattern="ab?"/>
+    </au:assertTrue>
+    <au:assertFalse>
+      <matches string="acb" pattern="ab."/>
+    </au:assertFalse>
+  </target>
+
+  <target name="test-caseinsensitive" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="ABC" pattern="ab?" casesensitive="false"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-singleline" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="AB${line.separator}C" pattern="^ab.*C$"
+               casesensitive="false"
+               singleline="true"/>
+    </au:assertTrue>
+    <au:assertFalse>
+      <matches string="AB${line.separator}C" pattern="^ab.*C$"
+               casesensitive="false"
+               singleline="false"/>
+    </au:assertFalse>
+  </target>
+
+  <target name="test-multiline" if="some.regexp.support">
+    <au:assertTrue>
+      <matches string="AB${NL}C" pattern="^C$"
+               multiline="true"/>
+    </au:assertTrue>
+    <au:assertTrue>
+      <matches string="AB${NL}C" pattern="^AB$"
+               multiline="true"/>
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/defer-reference-test.xml b/trunk/src/tests/antunit/types/defer-reference-test.xml
new file mode 100644
index 0000000..a67ad3b
--- /dev/null
+++ b/trunk/src/tests/antunit/types/defer-reference-test.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit">
+  <target name="notcalled">
+    <filelist id="ref1" dir="${basedir}" files="xxx" />
+  </target>
+  
+  <target name="test-macrodef-embedded-ref">
+    <!-- bug 34458 -->
+    <macrodef name="foo">
+      <element name="nested" implicit="yes" optional="yes"/>
+      <sequential>
+        <fileset id="abc" dir=".">
+          <nested/>
+        </fileset>
+      </sequential>
+    </macrodef>
+
+    <ant antfile="build-embedded-ref.xml" inheritRefs="true"/>
+  </target>
+
+  <condition property="allow.script">
+    <and>
+      <available classname="org.apache.bsf.BSFManager" />
+      <available classname="bsh.StringUtil" />
+    </and>
+  </condition>
+
+  <target name="test-script" if="allow.script">
+    <!-- bugzilla: 37688 -->
+    <macrodef name="compileMapper" >
+      <attribute name="objDir" />
+      <attribute name="id" default="compileMapperID" />
+      <sequential>
+        <mkdir dir="@{objDir}"/>
+        <mapper id="@{id}">
+          <chainedmapper  >
+            <flattenmapper/>
+            <globmapper from="*" to="@{objDir}/*.o"/>
+          </chainedmapper>
+        </mapper>
+      </sequential>
+    </macrodef>
+    <script language="beanshell"/>
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset file="${ant.file}"/>
+      <au:plainlistener/>
+    </au:antunit>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/fileset-test.xml b/trunk/src/tests/antunit/types/fileset-test.xml
new file mode 100644
index 0000000..fcae0c8
--- /dev/null
+++ b/trunk/src/tests/antunit/types/fileset-test.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit" default="all">
+
+  <target name="test-fileset-missing-dir">
+    <path id="missing.path.id">
+      <fileset id="missing.dir.fs" dir="not present"
+               erroronmissingdir="false"/>
+    </path>
+    <au:assertTrue>
+      <and>
+        <equals arg1="" arg2="${toString:missing.path.id}"/>
+        <resourcecount count="0" refid="missing.dir.fs" />
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-fileset-with-if">
+    <fileset id="this.xml" dir=".">
+      <include if="trigger.include" name="fileset-test.xml"/>
+    </fileset>
+    <pathconvert refid="this.xml" property="this.xml.prop" pathsep="${line.separator}" setonempty="false"/>
+    <au:assertTrue message="fileset this.xml should not contain anything but contains ${this.xml.prop}">
+        <not>
+          <isset property="this.xml.prop"/>
+        </not>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-fileset-with-if-property-set">
+    <property name="trigger.include" value="true"/>
+    <fileset id="this.xml" dir=".">
+      <include if="trigger.include" name="fileset-test.xml"/>
+    </fileset>
+    <pathconvert refid="this.xml" property="this.xml.prop" pathsep="${line.separator}" setonempty="false"/>
+    <au:assertPropertySet name="this.xml.prop" message="fileset should contain one file"/>
+    <echo>${this.xml.prop}</echo>
+    <au:assertLogContains text="fileset-test.xml"/>
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset dir="${basedir}" includes="fileset-test.xml"/>
+      <au:plainlistener/>
+    </au:antunit>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/types/filterset-test.xml b/trunk/src/tests/antunit/types/filterset-test.xml
new file mode 100644
index 0000000..7287aab
--- /dev/null
+++ b/trunk/src/tests/antunit/types/filterset-test.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+
+  <property name="br" value="${line.separator}" />
+
+  <target name="testRecursionRegression">
+    <copy todir="${basedir}">
+      <string value="@a@${br}@b@${br}@c@${br}" />
+      <mergemapper to="filterset-output.txt" />
+      <filterset>
+        <filter token="a" value="aaa" />
+        <filter token="b" value="bbb" />
+        <filter token="c" value="@a@:@b@" />
+      </filterset>
+    </copy>
+
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <file file="filterset-output.txt" />
+        <string value="aaa${br}bbb${br}aaa:bbb${br}" />
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="tearDown">
+    <delete file="filterset-output.txt" />
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/mapper-ref.xml b/trunk/src/tests/antunit/types/mapper-ref.xml
new file mode 100644
index 0000000..3ada7f3
--- /dev/null
+++ b/trunk/src/tests/antunit/types/mapper-ref.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- does not address/replace the circular reference checks, etc.
+     in MapperTest.java (yet).
+ -->
+
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <macrodef name="test">
+    <sequential>
+      <pathconvert property="dest">
+        <string value="foo" />
+        <mapper refid="mapper" />
+      </pathconvert>
+      <au:assertTrue>
+        <equals arg1="${dest}" arg2="bar" />
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <target name="testBasic" description="success">
+    <mapper id="mapper" type="merge" to="bar" />
+    <test />
+  </target>
+
+  <target name="testFileNameMapper" description="success">
+    <mergemapper id="mapper" to="bar" />
+    <test />
+  </target>
+
+  <target name="testWrongType" description="failure">
+    <path id="mapper" path="whocares" />
+    <au:expectfailure 
+      expectedMessage="org.apache.tools.ant.types.Path at reference 'mapper' is not a valid mapper reference.">
+      <test />
+    </au:expectfailure>
+  </target>
+
+  <target name="all" depends="testBasic,testFileNameMapper,testWrongType" />
+
+</project>
diff --git a/trunk/src/tests/antunit/types/modified-selector-test.xml b/trunk/src/tests/antunit/types/modified-selector-test.xml
new file mode 100644
index 0000000..fc9b697
--- /dev/null
+++ b/trunk/src/tests/antunit/types/modified-selector-test.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit" default="antunit">
+
+  <import file="../antunit-base.xml"/>
+  <property name="test-build-dir"
+            location="../../../../build/ant-unit/modified-selector"/>
+
+  <target name="test-one-file">
+    <delete dir="${test-build-dir}"/>
+    <mkdir dir="${test-build-dir}"/>
+    <copy todir="${test-build-dir}" overwrite="yes">
+      <fileset dir="." includes="modified-selector-test.xml">
+        <modified update="true">
+          <param name="cache.cachefile" value="${test-build-dir}/cc.properties"/>
+        </modified>
+      </fileset>
+    </copy>
+
+    <au:assertTrue>
+      <available file="${test-build-dir}/cc.properties"/>
+    </au:assertTrue>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/types/path-test.xml b/trunk/src/tests/antunit/types/path-test.xml
new file mode 100644
index 0000000..d0796a4
--- /dev/null
+++ b/trunk/src/tests/antunit/types/path-test.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit" default="antunit">

+

+  <import file="../antunit-base.xml" />

+

+  <property name="existingFile" value="${basedir}/build.xml" />

+

+  <files id="files">

+    <include name="${existingFile}" />

+  </files>

+    

+  <target name="test-directUse" description="Bug 42397 - works fine">

+    <path id="path">

+      <files>

+        <include name="${existingFile}" />

+      </files>

+    </path>

+  </target>

+

+  <target name="test-refid" description="Bug 42397">

+    <path id="path">

+      <files refid="files" />

+    </path>

+  </target>

+

+</project>

diff --git a/trunk/src/tests/antunit/types/patternset-invert-test.xml b/trunk/src/tests/antunit/types/patternset-invert-test.xml
new file mode 100644
index 0000000..7c0912e
--- /dev/null
+++ b/trunk/src/tests/antunit/types/patternset-invert-test.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit">
+
+  <macrodef name="test">
+    <sequential>
+      <au:assertTrue>
+        <resourcecount count="0">
+          <intersect>
+            <fileset dir="${basedir}">
+              <patternset refid="plus" />
+            </fileset>
+            <fileset dir="${basedir}">
+              <patternset refid="minus" />
+            </fileset>
+          </intersect>
+        </resourcecount>
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <target name="testInvertNested">
+    <basename property="basename" file="${ant.file}" />
+    <echo>$${basename}=${basename}</echo>
+    <patternset id="plus" includes="${basename}" />
+    <patternset id="minus">
+      <invert>
+        <patternset refid="plus" />
+      </invert>
+    </patternset>
+    <test />
+  </target>
+
+  <target name="testInvertRefid">
+    <basename property="basename" file="${ant.file}" />
+    <echo>$${basename}=${basename}</echo>
+    <patternset id="plus" includes="${basename}" />
+    <patternset id="minus">
+      <invert refid="plus" />
+    </patternset>
+    <test />
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset file="${ant.file}"/>
+      <au:plainlistener />
+    </au:antunit>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/concat-resource-test.xml b/trunk/src/tests/antunit/types/resources/concat-resource-test.xml
new file mode 100644
index 0000000..a27a733
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/concat-resource-test.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project name="test-concat" basedir="." default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <import file="../../antunit-base.xml" />
+
+  <property name="br" value="${line.separator}" />
+  <property name="world" value="World" />
+
+  <property name="out.dir" location="tempdir"/>
+
+  <target name="tearDown">
+    <delete dir="${out.dir}" quiet="true"/>
+  </target>
+
+  <target name="testCountEquals1">
+    <au:assertTrue>
+      <resourcecount count="1">
+        <concat>Hello, ${world}!</concat>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testReplacement">
+    <au:assertTrue>
+      <resourcesmatch>
+        <string>Hello, ${world}!</string>
+        <concat>Hello, ${world}!</concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="testResources">
+    <au:assertTrue>
+      <resourcesmatch>
+        <string>foobarbaz</string>
+        <concat>
+          <string value="foo" />
+          <string value="bar" />
+          <string value="baz" />
+        </concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="testFixLastLineResources">
+    <au:assertTrue>
+      <resourcesmatch>
+        <string>foo${line.separator}bar${line.separator}baz${line.separator}</string>
+        <concat fixlastline="true">
+          <string value="foo" />
+          <string value="bar" />
+          <string value="baz" />
+        </concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="testEncoding">
+    <mkdir dir="${out.dir}"/>
+    <copy file="utf-16.in" toDir="${out.dir}" encoding="utf-16">
+      <filterchain>
+        <fixcrlf/>
+      </filterchain>
+    </copy>
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <file file="${out.dir}/utf-16.in" />
+        <concat outputEncoding="utf-16">foo${br}bar${br}baz${br}</concat>
+        <concat outputEncoding="utf-16" fixlastline="true">
+          <string value="foo" />
+          <string value="bar" />
+          <string value="baz" />
+        </concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="testFiltering">
+    <au:assertTrue>
+      <resourcesmatch astext="true">
+        <concat>foo${br}bar${br}baz${br}</concat>
+        <concat>
+foo
+#comment 1
+bar
+#comment 2
+baz
+#comment 3
+          <filterchain>
+            <striplinecomments>
+              <comment value="#" />
+            </striplinecomments>
+            <ignoreblank />
+          </filterchain>
+        </concat>
+      </resourcesmatch>
+    </au:assertTrue>
+  </target>
+
+  <target name="testReference">
+    <resources id="concat">
+      <concat>foo</concat>
+    </resources>
+    <au:assertTrue>
+      <and>
+        <resourcecount count="1" refid="concat" />
+        <resourcesmatch>
+          <string>foo</string>
+          <resources refid="concat" />
+          <!-- purposely hit it twice to see what happens -->
+          <resources refid="concat" />
+        </resourcesmatch>
+      </and>
+    </au:assertTrue>
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/files-test.xml b/trunk/src/tests/antunit/types/resources/files-test.xml
new file mode 100644
index 0000000..c33ed6c
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/files-test.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<project name="files-test" default="antunit"

+         xmlns:au="antlib:org.apache.ant.antunit">

+

+  <target name="antunit">

+    <au:antunit>

+      <au:plainlistener />

+      <file file="${ant.file}" />

+    </au:antunit>

+  </target>

+  

+  <target name="setUp">

+    <property name="out" value="out"/>

+  </target>

+  

+  <target name="tearDown">

+    <delete dir="${out}"/>

+  </target>

+

+  <target name="testEmptyReference" description="Bug43048">

+    <files id="foo"/>

+    <mkdir dir="${out}"/>

+    <copy todir="${out}">

+      <!-- threw a java.lang.NullPointerException -->

+	  <files refid="foo"/>

+    </copy>

+  </target>

+

+  <target name="testEmptyFiles" description="Bug43048">

+    <mkdir dir="${out}"/>

+    <copy todir="${out}">

+      <files/>

+    </copy>

+  </target>

+

+

+</project>

diff --git a/trunk/src/tests/antunit/types/resources/first-last-test.xml b/trunk/src/tests/antunit/types/resources/first-last-test.xml
new file mode 100644
index 0000000..dc3304b
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/first-last-test.xml
@@ -0,0 +1,157 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+
+  <tokens id="testrc">
+    <string value="1,2,3,4,5" />
+    <stringtokenizer delims="," />
+  </tokens>
+
+  <target name="testfirst0">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <first count="0"><resources refid="testrc" /></first>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst1">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <first><resources refid="testrc" /></first>
+          <string value="1" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst2">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <first count="2"><resources refid="testrc" /></first>
+          <resources>
+            <string value="1" />
+            <string value="2" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst5">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <first count="5"><resources refid="testrc" /></first>
+          <resources refid="testrc" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst6">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <first count="6"><resources refid="testrc" /></first>
+          <resources refid="testrc" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst-1">
+    <au:expectfailure expectedmessage="size-limited collection count should be set to an int &gt;= 0">
+      <resourcecount>
+        <first count="-1"><resources refid="testrc" /></first>
+      </resourcecount>
+    </au:expectfailure>
+  </target>
+
+  <target name="testlast0">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <last count="0"><resources refid="testrc" /></last>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testlast1">
+    <pathconvert>
+      <last count="1"><resources refid="testrc" /></last>
+    </pathconvert>
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <last><resources refid="testrc" /></last>
+          <string value="5" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testlast2">
+    <pathconvert>
+      <last count="2"><resources refid="testrc" /></last>
+    </pathconvert>
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <last count="2"><resources refid="testrc" /></last>
+          <resources>
+            <string value="4" />
+            <string value="5" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testlast5">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <last count="5"><resources refid="testrc" /></last>
+          <resources refid="testrc" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testlast6">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <last count="6"><resources refid="testrc" /></last>
+          <resources refid="testrc" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testlast-1">
+    <au:expectfailure expectedmessage="size-limited collection count should be set to an int &gt;= 0">
+      <resourcecount>
+        <last count="-1"><resources refid="testrc" /></last>
+      </resourcecount>
+    </au:expectfailure>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/latepath-test.xml b/trunk/src/tests/antunit/types/resources/latepath-test.xml
new file mode 100644
index 0000000..5cafffd
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/latepath-test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit">
+
+  <target name="testLatePath" depends="tearDown">
+    <path id="p">
+      <fileset file="testLatePath" />
+    </path>
+    <pathconvert refid="p" />
+    <touch file="testLatePath" />
+    <au:assertTrue>
+      <resourcecount when="eq" count="1" refid="p" />
+    </au:assertTrue>
+  </target>
+
+  <target name="tearDown">
+    <delete file="testLatePath" />
+  </target>
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/selectors/test-componentdef.xml b/trunk/src/tests/antunit/types/resources/selectors/test-componentdef.xml
new file mode 100644
index 0000000..187412e
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/selectors/test-componentdef.xml
@@ -0,0 +1,458 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit">
+
+  <available property="jdk1.4+" classname="java.lang.CharSequence"/>  
+  <condition property="some.regexp.support">
+    <or>
+      <isset property="jdk1.4+"/>
+      <isset property="apache.regexp.present"/>
+      <isset property="apache.oro.present"/>
+    </or>
+  </condition>    
+    
+  <target name="testname1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <resource name="foo" />
+            <resource name="bar" />
+            <resource name="baz" />
+            <resource name="boo" />
+            <resource name="bang" />
+          </resources>
+          <name name="ba?" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testname2">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <file file="foo" />
+            <resource name="foo" />
+            <file file="foo" basedir="${basedir}" />
+          </resources>
+          <name name="foo" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="name" depends="testname1,testname2" />
+
+  <target name="testexists">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <file file="idonotexist" />
+            <resource name="foo" />
+            <resource name="foo" exists="false" />
+          </resources>
+          <exists />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <file file="foo" />
+            <url url="http://ant.apache.org/index.html" />
+            <resource name="foo" />
+            <string value="foo" />
+            <file file="bar" />
+          </resources>
+          <instanceof type="file" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype2">
+    <typedef name="file" uri="test"
+             classname="org.apache.tools.ant.types.resources.FileResource" />
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <url file="foo" />
+            <file file="bar" xmlns="test" />
+          </resources>
+          <instanceof type="test:file" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype3">
+    <typedef name="file" uri="test"
+             classname="org.apache.tools.ant.types.resources.FileResource" />
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <url file="foo" />
+            <file file="bar" xmlns="test" />
+          </resources>
+          <instanceof type="file" uri="test" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="instanceoftype"
+    depends="testinstanceoftype1,testinstanceoftype2,testinstanceoftype3" />
+
+  <target name="testinstanceofclass">
+    <au:assertTrue>
+      <resourcecount when="equal" count="7">
+        <restrict>
+          <resources>
+            <filelist dir="${basedir}" files="a,b,c,d,e,f,g" />
+          </resources>
+          <instanceof class="org.apache.tools.ant.types.Resource" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="instanceof" depends="instanceoftype,testinstanceofclass" />
+
+  <target name="testtype">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+             <file file="${basedir}" />
+             <file file="${ant.file}" />
+             <resource directory="true" />
+             <resource directory="false" />
+          </resources>
+          <type type="dir" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testdate">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+             <resource lastmodified="4" />
+             <resource lastmodified="5" />
+             <resource lastmodified="6" />
+             <resource lastmodified="7" />
+             <resource lastmodified="8" />
+          </resources>
+          <date when="after" millis="5" granularity="0" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testsize">
+    <au:assertTrue>
+      <resourcecount when="equal" count="4">
+        <restrict>
+          <resources>
+             <resource size="4" />
+             <resource size="5" />
+             <resource size="6" />
+             <resource size="7" />
+             <resource size="8" />
+          </resources>
+          <size when="le" size="7" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testand">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <and xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </and>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testor">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <or xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </or>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testnot">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <not xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <size size="3" />
+          </not>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testnone">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <none xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </none>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority2">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority>
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="resource" />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority3">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority allowtie="true">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+            <exists />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority4">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority allowtie="false">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+            <exists />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcontains">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+          <contains text="b"/>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcontainsregexp" if="some.regexp.support">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+          <containsregexp expression="^b..$"/>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcompare">
+    <au:assertTrue>
+      <and>
+        <!-- basic test, natural ordering -->
+        <resourcecount count="3">
+          <restrict>
+            <compare when="greater" against="each">
+              <control><string value="b" /></control>
+            </compare>
+            <resources>
+              <string value="a" />
+              <string value="b" />
+              <string value="c" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+        <!-- one comparator, default when/against -->
+        <resourcecount count="5">
+          <restrict>
+            <compare>
+              <control><string value="." /></control>
+              <size />
+            </compare>
+            <resources>
+              <string value="a" />
+              <string value="b" />
+              <string value="c" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+        <!-- multiple controls, comparators -->
+        <resourcecount count="3">
+          <restrict>
+            <compare when="greater" against="each">
+              <control>
+                <string value="a" />
+                <string value="b" />
+                <string value="bb" />
+                <string value="c" />
+                <string value="ccc" />
+              </control>
+              <name />
+              <size />
+            </compare>
+            <resources>
+              <string value="a" />
+              <string value="bbbb" />
+              <string value="ccc" />
+              <string value="cccc" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="majority"
+          depends="testmajority1,testmajority2,testmajority3,testmajority4" />
+
+  <target name="logical"
+          depends="testand,testor,testnone,testnot,majority" />
+
+  <target name="all"
+    depends="name,testexists,instanceof,testtype,testdate,testsize,testcontains,testcontainsregexp,logical,testcompare" />
+
+  <!-- 
+    The tests for oata.types.selectors.ModifiedSelectorTest as 
+    ResourceSelector are in its test-buildfile src\etc\testcases\types\selectors.xml. 
+  -->
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/selectors/test.xml b/trunk/src/tests/antunit/types/resources/selectors/test.xml
new file mode 100755
index 0000000..1584ecd
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/selectors/test.xml
@@ -0,0 +1,464 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit"
+         xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors"
+         xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
+
+  <available property="jdk1.4+" classname="java.lang.CharSequence"/>  
+  <condition property="some.regexp.support">
+    <or>
+      <isset property="jdk1.4+"/>
+      <isset property="apache.regexp.present"/>
+      <isset property="apache.oro.present"/>
+    </or>
+  </condition>    
+    
+  <target name="testname1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <resource name="foo" />
+            <resource name="bar" />
+            <resource name="baz" />
+            <resource name="boo" />
+            <resource name="bang" />
+          </resources>
+          <rsel:name name="ba?" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testname2">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <file file="foo" />
+            <resource name="foo" />
+            <file file="foo" basedir="${basedir}" />
+          </resources>
+          <rsel:name name="foo" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="name" depends="testname1,testname2" />
+
+  <target name="testexists">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <file file="idonotexist" />
+            <resource name="foo" />
+            <resource name="foo" exists="false" />
+          </resources>
+          <rsel:exists />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <file file="foo" />
+            <url url="http://ant.apache.org/index.html" />
+            <resource name="foo" />
+            <string value="foo" />
+            <file file="bar" />
+          </resources>
+          <rsel:instanceof type="file" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype2">
+    <typedef name="file" uri="test"
+             classname="org.apache.tools.ant.types.resources.FileResource" />
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <url file="foo" />
+            <file file="bar" xmlns="test" />
+          </resources>
+          <rsel:instanceof type="test:file" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testinstanceoftype3">
+    <typedef name="file" uri="test"
+             classname="org.apache.tools.ant.types.resources.FileResource" />
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <url file="foo" />
+            <file file="bar" xmlns="test" />
+          </resources>
+          <rsel:instanceof type="file" uri="test" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="instanceoftype"
+    depends="testinstanceoftype1,testinstanceoftype2,testinstanceoftype3" />
+
+  <target name="testinstanceofclass">
+    <au:assertTrue>
+      <resourcecount when="equal" count="7">
+        <restrict>
+          <resources>
+            <filelist dir="${basedir}" files="a,b,c,d,e,f,g" />
+          </resources>
+          <rsel:instanceof class="org.apache.tools.ant.types.Resource" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="instanceof" depends="instanceoftype,testinstanceofclass" />
+
+  <target name="testtype">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+             <file file="${basedir}" />
+             <file file="${ant.file}" />
+             <resource directory="true" />
+             <resource directory="false" />
+          </resources>
+          <rsel:type type="dir" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testdate">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+             <resource lastmodified="4" />
+             <resource lastmodified="5" />
+             <resource lastmodified="6" />
+             <resource lastmodified="7" />
+             <resource lastmodified="8" />
+          </resources>
+          <rsel:date when="after" millis="5" granularity="0" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testsize">
+    <au:assertTrue>
+      <resourcecount when="equal" count="4">
+        <restrict>
+          <resources>
+             <resource size="4" />
+             <resource size="5" />
+             <resource size="6" />
+             <resource size="7" />
+             <resource size="8" />
+          </resources>
+          <rsel:size when="le" size="7" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testand">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <and xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </and>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testor">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <or xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </or>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testnot">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <not xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <size size="3" />
+          </not>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testnone">
+    <au:assertTrue>
+      <resourcecount when="equal" count="1">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <none xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+          </none>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority1">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority2">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="resource" />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority3">
+    <au:assertTrue>
+      <resourcecount when="equal" count="3">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority allowtie="true"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+            <exists />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testmajority4">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="fee" />
+            <resource name="fi" size="3" />
+            <resource name="fo" />
+            <resource name="fum" />
+          </resources>
+          <majority allowtie="false"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors">
+            <name name="f?" />
+            <size size="3" />
+            <instanceof type="string" />
+            <exists />
+          </majority>
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcontains">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+          <contains text="b"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcontainsregexp" if="some.regexp.support">
+    <au:assertTrue>
+      <resourcecount when="equal" count="2">
+        <restrict>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+          <containsregexp expression="^b..$"
+              xmlns="antlib:org.apache.tools.ant.types.resources.selectors" />
+        </restrict>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testcompare">
+    <au:assertTrue>
+      <and>
+        <!-- basic test, natural ordering -->
+        <resourcecount count="3">
+          <restrict>
+            <rsel:compare when="greater" against="each">
+              <control><string value="b" /></control>
+            </rsel:compare>
+            <resources>
+              <string value="a" />
+              <string value="b" />
+              <string value="c" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+        <!-- one comparator, default when/against -->
+        <resourcecount count="5">
+          <restrict>
+            <rsel:compare>
+              <control><string value="." /></control>
+              <rcmp:size />
+            </rsel:compare>
+            <resources>
+              <string value="a" />
+              <string value="b" />
+              <string value="c" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+        <!-- multiple controls, comparators -->
+        <resourcecount count="3">
+          <restrict>
+            <rsel:compare when="greater" against="each">
+              <control>
+                <string value="a" />
+                <string value="b" />
+                <string value="bb" />
+                <string value="c" />
+                <string value="ccc" />
+              </control>
+              <rcmp:name />
+              <rcmp:size />
+            </rsel:compare>
+            <resources>
+              <string value="a" />
+              <string value="bbbb" />
+              <string value="ccc" />
+              <string value="cccc" />
+              <string value="d" />
+              <string value="e" />
+            </resources>
+          </restrict>
+        </resourcecount>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="majority"
+          depends="testmajority1,testmajority2,testmajority3,testmajority4" />
+
+  <target name="logical"
+          depends="testand,testor,testnone,testnot,majority" />
+
+  <target name="all"
+    depends="name,testexists,instanceof,testtype,testdate,testsize,testcontains,testcontainsregexp,logical,testcompare" />
+
+  <!-- 
+    The tests for oata.types.selectors.ModifiedSelectorTest as 
+    ResourceSelector are in its test-buildfile src\etc\testcases\types\selectors.xml. 
+  -->
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/test.xml b/trunk/src/tests/antunit/types/resources/test.xml
new file mode 100644
index 0000000..999d43e
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/test.xml
@@ -0,0 +1,384 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project default="all" xmlns:au="antlib:org.apache.ant.antunit"
+         xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
+
+  <property name="dirname" value="work" />
+  <property name="dir" location="${dirname}" />
+  <property name="zip" location="${dirname}.zip" />
+  <property name="jar" location="${dirname}.jar" />
+  <property name="file" location="${dirname}/file.txt" />
+    
+  <condition property="offline">
+    <not>
+      <or>
+        <http url="http://www.apache.org"/>
+        <http url="http://www.google.com"/>
+      </or>
+    </not>
+  </condition>
+
+  <target name="setUp">
+
+    <touch mkdirs="true">
+      <filelist dir="${dir}/foo/a" files="x,y,z" />
+    </touch>
+
+    <copy todir="${dir}/foo" enablemultiplemappings="true">
+      <fileset dir="${dir}/foo" />
+      <mapper>
+        <globmapper handledirsep="true" from="a/*" to="b/*" />
+        <globmapper handledirsep="true" from="a/*" to="c/*" />
+      </mapper>
+    </copy>
+
+    <copy todir="${dir}/bar">
+      <fileset dir="${dir}/foo" />
+    </copy>
+
+    <property name="foo" location="${dir}/foo" />
+    <property name="foo.a" location="${dir}/foo/a" />
+    <property name="foo.b" location="${dir}/foo/b" />
+    <property name="foo.c" location="${dir}/foo/c" />
+
+    <property name="bar" location="${dir}/bar" />
+    <property name="bar.a" location="${dir}/bar/a" />
+    <property name="bar.b" location="${dir}/bar/b" />
+    <property name="bar.c" location="${dir}/bar/c" />
+  </target>
+
+  <target name="tearDown">
+    <delete dir="${dir}" />
+    <delete file="${zip}" />
+    <delete file="${jar}" deleteonexit="true" />
+    <delete file="${file}" />
+  </target>
+
+  <target name="testfiles1" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="26">
+        <files>
+          <include name="${dir}/foo/" />
+          <include name="${dir}/bar/" />
+        </files>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfiles2" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="8">
+        <files>
+          <include name="${dir}/foo/" />
+          <include name="${dir}/bar/" />
+          <type type="dir" />
+        </files>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfiles3" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="18">
+        <files>
+          <include name="${dir}/foo/" />
+          <include name="${dir}/bar/" />
+          <type type="file" />
+        </files>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testnestedresources" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="27"><!-- include duplicates! -->
+        <resources>
+          <files>
+            <include name="${dir}/foo/" />
+            <include name="${dir}/bar/" />
+            <type type="file" />
+          </files>
+          <files>
+            <include name="${dir}/foo/" />
+            <type type="file" />
+          </files>
+        </resources>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testresourcesref" depends="setUp">
+    <files id="files">
+      <include name="${dir}/foo/" />
+      <include name="${dir}/bar/" />
+      <type type="file" />
+    </files>
+    <au:assertTrue>
+      <resourcecount count="18">
+        <resources refid="files" />
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfileset" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="9">
+        <fileset dir="${dir}/foo" />
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testdirset" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="4">
+        <dirset dir="${dir}/foo" />
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfilelist">
+    <au:assertTrue>
+      <resourcecount count="5">
+        <filelist dir="${dir}/foo" files="1,2,3,4,5" />
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testpath" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="24">
+        <path>
+          <path id="p">
+            <fileset id="fs" dir="${foo.a}" /> <!-- 3 -->
+            <dirset id="ds" dir="${foo}" /> <!-- 4 -->
+          </path>
+          <pathelement id="pe" location="${dir}" /> <!-- 1 -->
+          <filelist id="fl" dir="${bar}" files="1,2,3,a,b,c" /> <!-- 6 -->
+          <files id="f" includes="${bar}/" /> <!-- 13; 3 overlap fl -->
+        </path>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="createzip" depends="setUp">
+    <zip destfile="${zip}" basedir="${dir}" />
+  </target>
+
+  <target name="testzipfileset" depends="createzip">
+    <au:assertTrue>
+      <resourcecount count="9">
+        <zipfileset src="${zip}" includes="foo/" />
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testpropertyset">
+    <property name="testpropertyset.a" value="a" />
+    <property name="testpropertyset.aa" value="aa" />
+    <property name="testpropertyset.aaa" value="aaa" />
+    <propertyset id="testpropertyset">
+      <propertyref prefix="testpropertyset." />
+    </propertyset>
+    <au:assertTrue>
+      <and>
+        <resourcecount refid="testpropertyset" count="3" />
+        <length length="12">
+          <resources>
+            <resources refid="testpropertyset" />
+            <propertyset refid="testpropertyset" />
+          </resources>
+        </length>
+      </and>
+    </au:assertTrue>
+  </target>
+
+  <target name="testunion" depends="setUp">
+    <au:assertTrue>
+      <resourcecount count="4">
+        <union>
+          <files includes="${foo.a}/w,${foo.a}/x" /> <!-- 1 -->
+          <fileset dir="${foo.a}" includes="x,y" /> <!-- 2; net 1 -->
+          <filelist dir="${foo.a}" files="v" /> <!-- 1 -->
+          <files includes="${foo.a}/y,${foo.a}/z" /> <!-- 2; net 1 -->
+        </union>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testintersect">
+    <au:assertTrue>
+      <resourcecount count="3">
+        <intersect>
+          <filelist dir="${dir}" files="1,2,3,4,5" />
+          <filelist dir="${dir}" files="2,3,4,5,6" />
+          <filelist dir="${dir}" files="3,4,5,6,7" />
+        </intersect>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testdifference">
+    <au:assertTrue>
+      <resourcecount count="2">
+        <difference id="diff">
+          <filelist dir="${dir}" files="1,2,3,4,5" />
+          <filelist dir="${dir}" files="2,3,4,5,6" />
+          <filelist dir="${dir}" files="3,4,5,6,7" />
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfileurl">
+    <au:assertTrue>
+      <length when="greater" length="0">
+        <url file="${ant.file}" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfileurlref">
+    <url id="fileurl" file="${ant.file}" />
+    <au:assertTrue>
+      <length when="greater" length="0">
+        <url refid="fileurl" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testhttpurl1" unless="offline">
+    <au:assertTrue>
+      <length when="greater" length="0">
+        <url url="http://www.w3.org/MarkUp" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testhttpurl2" unless="offline">
+    <concat destfile="${file}" force="true" append="false">
+      <url id="httpurl" url="http://ant.apache.org/index.html" />
+      <url refid="httpurl" />
+    </concat>
+    <length property="httpurl.length">
+      <url refid="httpurl" />
+    </length>
+    <length property="file.length">
+      <file file="${file}"/>
+    </length>
+    <au:assertTrue message="length of url ${httpurl.length} length of file ${file.length} file should be twice as big">
+      <length file="${file}" when="greater" length="${httpurl.length}" />
+    </au:assertTrue>
+  </target>
+
+  <target name="createjar" depends="setUp">
+    <jar destfile="${jar}" basedir="${dir}" />
+  </target>
+
+  <target name="testjarurl" depends="createjar">
+    <pathconvert property="jarurl">
+      <url file="${jar}" />
+    </pathconvert>
+    <au:assertTrue>
+      <length when="greater" length="0">
+        <url url="jar:${jarurl}!/META-INF/MANIFEST.MF" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfile" depends="setUp">
+    <echo file="${file}">This is a test.</echo>
+    <au:assertTrue>
+      <length length="15">
+        <file file="${file}" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testzipentry" depends="createjar">
+    <au:assertTrue>
+      <length when="greater" length="0">
+        <zipentry zipfile="${jar}" name="META-INF/MANIFEST.MF" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="teststring1">
+    <au:assertTrue>
+      <length length="15">
+        <string value="This is a test." />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="teststring2">
+    <property name="test" value="foo" />
+    <au:assertTrue>
+      <length length="14">
+        <string value="This is a ${test}." />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testresource">
+    <au:assertTrue>
+      <length length="4096">
+        <resource size="4096" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testproperty">
+    <property name="testproperty" value="abcdefghij" />
+    <au:assertTrue>
+      <length length="10">
+        <propertyresource name="testproperty" />
+      </length>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst0">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <first count="0">
+          <filelist dir="${dir}" files="1,2,3,4,5" />
+        </first>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst1">
+    <au:assertTrue>
+      <resourcecount count="1">
+        <first>
+          <filelist dir="${dir}" files="1,2,3,4,5" />
+        </first>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testfirst2">
+    <au:assertTrue>
+      <resourcecount count="2">
+        <first count="2">
+          <filelist dir="${dir}" files="1,2,3,4,5" />
+        </first>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/tokens-test.xml b/trunk/src/tests/antunit/types/resources/tokens-test.xml
new file mode 100644
index 0000000..c09d604
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/tokens-test.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="test-tokens" default="antunit"
+         xmlns:au="antlib:org.apache.ant.antunit">
+
+  <property name="eol" value="${line.separator}" />
+
+  <target name="antunit">
+    <au:antunit>
+      <au:plainlistener />
+      <file file="${ant.file}" />
+    </au:antunit>
+  </target>
+
+  <target name="testLines">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <tokens>
+            <string value="foo${eol}bar${eol}baz" />
+          </tokens>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testExplicitLines">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <tokens>
+            <string value="foo${eol}bar${eol}baz" />
+            <linetokenizer />
+          </tokens>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testFileTokenizer">
+    <au:assertTrue>
+      <resourcecount count="1">
+        <tokens>
+          <resources>
+            <string value="foo${eol}bar${eol}baz" />
+            <file file="${ant.file}" />
+          </resources>
+          <filetokenizer />
+        </tokens>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testStringTokenizer">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <tokens>
+            <string value="foo bar baz " />
+            <stringtokenizer />
+          </tokens>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testEncoding">
+    <au:assertTrue>
+      <resourcecount count="0">
+        <difference>
+          <tokens encoding="utf-16">
+            <file file="utf-16.in" />
+          </tokens>
+          <resources>
+            <string value="foo" />
+            <string value="bar" />
+            <string value="baz" />
+          </resources>
+        </difference>
+      </resourcecount>
+    </au:assertTrue>
+  </target>
+
+  <target name="testSort">
+    <pathconvert property="sorted" pathsep="${eol}">
+      <sort>
+        <tokens>
+          <string value="foo bar etc baz" />
+          <stringtokenizer />
+        </tokens>
+    </sort>
+    </pathconvert>
+    <au:assertTrue>
+      <equals arg1="bar${eol}baz${eol}etc${eol}foo" arg2="${sorted}" />
+    </au:assertTrue>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/resources/utf-16.in b/trunk/src/tests/antunit/types/resources/utf-16.in
new file mode 100644
index 0000000..7c7c2a7
--- /dev/null
+++ b/trunk/src/tests/antunit/types/resources/utf-16.in
Binary files differ
diff --git a/trunk/src/tests/antunit/types/scriptcondition-test.xml b/trunk/src/tests/antunit/types/scriptcondition-test.xml
new file mode 100644
index 0000000..04578b5
--- /dev/null
+++ b/trunk/src/tests/antunit/types/scriptcondition-test.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project name="scriptcondition-test" default="antunit" xmlns:au="antlib:org.apache.ant.antunit">
+  <import file="../antunit-base.xml" />
+
+  <macrodef name="t">
+    <element name="test" implicit="yes" />
+    <attribute name="message"/>
+    <sequential>
+      <au:assertTrue message="query @{message} failed; result was false">
+        <test />
+      </au:assertTrue>
+    </sequential>
+  </macrodef>
+
+  <macrodef name="f">
+    <element name="test" implicit="yes" />
+    <attribute name="message"/>
+    <sequential>
+      <au:assertFalse message="test @{message} failed; result was true">
+        <test />
+      </au:assertFalse>
+    </sequential>
+  </macrodef>
+
+  <condition property="js.avail">
+    <available classname="org.mozilla.javascript.EvaluatorException"/>
+  </condition>
+
+  <condition property="beanshell.avail">
+    <available classname="bsh.BshMethod"/>
+  </condition>
+
+  <!-- this is here to test the macro is well coded -->
+  <target name="testMacro">
+    <t message="testMacro">
+      <istrue value="true"/>
+    </t>
+    <f message="testMacro2">
+      <istrue value="false"/>
+    </f>
+  </target>
+
+ <target name="testNolanguage">
+    <au:expectfailure message="Absence of language attribute not detected"
+                      expectedMessage="script language must be specified">
+      <t message="testNolanguage">
+        <scriptcondition>
+          self.setValue(true);
+        </scriptcondition>
+      </t>
+    </au:expectfailure>
+  </target>
+
+  <target name="testClearByDefault" if="js.avail">
+    <f message="testClearByDefault">
+      <scriptcondition language="javascript">
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testValueWorks" if="js.avail">
+    <t message="testValueWorks">
+      <scriptcondition language="javascript" value="true" />
+    </t>
+  </target>
+
+  <target name="testSetWorks" if="js.avail">
+    <t message="testSetWorks">
+      <scriptcondition language="javascript" value="false">
+        self.setValue(true);
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testClearWorks" if="js.avail">
+    <f message="testClearWorks">
+      <scriptcondition language="javascript" value="true">
+        self.setValue(false);
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testBeanshellReturnTrue" if="beanshell.avail">
+    <t message="testBeanshellReturnTrue">
+      <scriptcondition language="beanshell" value="false">
+        return true;
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testBeanshellReturnFalse" if="beanshell.avail">
+    <f message="testBeanshellReturnFalse">
+      <scriptcondition language="beanshell" value="true">
+        return false;
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testBeanshellReturnOverridesValue" if="beanshell.avail">
+    <f message="testBeanshellReturnOverridesValue">
+      <scriptcondition language="beanshell" value="false">
+        self.setValue(true);
+        return false;
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testBeanshellReturnNullIgnored" if="beanshell.avail">
+    <t message="testBeanshellReturnNullIgnored">
+      <scriptcondition language="beanshell" value="true">
+        return null;
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testBeanshellReturnNonBooleanIgnored" if="beanshell.avail">
+    <t message="testBeanshellReturnNonBooleanIgnored">
+      <scriptcondition language="beanshell" value="true">
+        return 20;
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testJsReturnTrue" if="js.avail">
+    <t message="testJsReturnTrue">
+      <scriptcondition language="javascript" value="false">
+        java.lang.Boolean.TRUE
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testJsReturnFalse" if="js.avail">
+    <f message="testJsReturnFalse">
+      <scriptcondition language="javascript" value="true">
+        java.lang.Boolean.FALSE
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testJsReturnOverridesValue" if="js.avail">
+    <f message="testJsReturnOverridesValue">
+      <scriptcondition language="javascript" value="false">
+        self.setValue(true);
+        false
+      </scriptcondition>
+    </f>
+  </target>
+
+  <target name="testJsReturnNullIgnored" if="js.avail">
+    <t message="testJsReturnNullIgnored">
+      <scriptcondition language="javascript" value="true">
+        null
+      </scriptcondition>
+    </t>
+  </target>
+
+  <target name="testJsReturnNonBooleanIgnored" if="js.avail">
+    <t message="testJsReturnNonBooleanIgnored">
+      <scriptcondition language="javascript" value="true">
+        new java.lang.Integer(20)
+      </scriptcondition>
+    </t>
+  </target>
+
+</project>
diff --git a/trunk/src/tests/antunit/types/zipfileset-test.xml b/trunk/src/tests/antunit/types/zipfileset-test.xml
new file mode 100644
index 0000000..838d9d3
--- /dev/null
+++ b/trunk/src/tests/antunit/types/zipfileset-test.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns:au="antlib:org.apache.ant.antunit" default="all">
+  <property name="top.build.dir" location="../../../../build"/>
+  <property name="build.dir"
+            location="${top.build.dir}/ant-unit/zipfileset-dir"/>
+
+  <target name="test-refid-modify">
+    <fileset id="modify-refid-1"
+             dir="${basedir}"
+             includes="*.xml"
+             />
+    <zipfileset id="modify-refid-2"
+                refid="modify-refid-1"
+                prefix="WEB-INF/lib/"/>
+    <delete quiet="yes" dir="${build.dir}"/>
+    <mkdir dir="${build.dir}"/>
+    <jar jarfile="${build.dir}/jar.jar">
+      <zipfileset refid="modify-refid-2"/>
+    </jar>
+    <unjar src="${build.dir}/jar.jar"
+           dest="${build.dir}"/>
+    <au:assertTrue>
+      <available file="${build.dir}/WEB-INF/lib/zipfileset-test.xml"/>
+    </au:assertTrue>
+  </target>
+
+  <target name="test-refid-check-prefix">
+    <zipfileset id="test-refid"
+                dir="${basedir}"/>
+    <au:expectfailure>
+      <zipfileset id="ref2"
+                  refid="test-refid"
+                  prefix="WEB-INF/lib/"/>
+    </au:expectfailure>
+    <au:expectfailure>
+      <zipfileset id="ref3"
+                  prefix="WEB-INF/lib/"
+                  ReFiD="test-refid"/>
+    </au:expectfailure>
+  </target>
+
+  <target name="test-refid-check-encoding">
+    <zipfileset id="test-refid2"
+                encoding="utf-8"
+                dir="${basedir}"/>
+    <au:expectfailure>
+      <zipfileset id="ref4"
+                  encoding="utf-8"
+                  refid="test-refid2"/>
+    </au:expectfailure>
+  </target>
+
+  <target name="all">
+    <au:antunit>
+      <fileset dir="${basedir}" includes="zipfileset-test.xml"/>
+      <au:plainlistener/>
+    </au:antunit>
+  </target>
+</project>
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderDelegationTest.java b/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderDelegationTest.java
new file mode 100644
index 0000000..4ee6794
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderDelegationTest.java
@@ -0,0 +1,127 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import junit.framework.TestCase;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Test case for ant class loader
+ *
+ */
+public class AntClassLoaderDelegationTest extends TestCase {
+
+    /** Instance of a utility class to use for file operations. */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private Project p;
+
+    public AntClassLoaderDelegationTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        p = new Project();
+        p.init();
+    }
+
+    /** Sample resource present in build/testcases/ */
+    private static final String TEST_RESOURCE
+        = "apache/tools/ant/IncludeTest.class";
+    
+    public void testFindResources() throws Exception {
+        // This path should contain the class files for these testcases:
+        String buildTestcases = System.getProperty("build.tests");
+        assertNotNull("defined ${build.tests}", buildTestcases);
+        assertTrue("have a dir " + buildTestcases,
+                   new File(buildTestcases).isDirectory());
+        Path path = new Path(p, buildTestcases + "/org");
+        // A special parent loader which is not the system class loader:
+        ClassLoader parent = new ParentLoader();
+        // An AntClassLoader which is supposed to delegate to
+        // the parent and then to the disk path:
+        ClassLoader acl = new AntClassLoader(parent, p, path, true);
+        // The intended result URLs:
+        URL urlFromPath = new URL(
+            FILE_UTILS.toURI(buildTestcases) + "org/" + TEST_RESOURCE);
+        URL urlFromParent = new URL("http://ant.apache.org/" + TEST_RESOURCE);
+        assertEquals("correct resources (regular delegation order)",
+            Arrays.asList(new URL[] {urlFromParent, urlFromPath}),
+            enum2List(acl.getResources(TEST_RESOURCE)));
+        acl = new AntClassLoader(parent, p, path, false);
+        assertEquals("correct resources (reverse delegation order)",
+            Arrays.asList(new URL[] {urlFromPath, urlFromParent}),
+            enum2List(acl.getResources(TEST_RESOURCE)));
+    }
+
+    public void testFindIsolateResources() throws Exception {
+        String buildTestcases = System.getProperty("build.tests");
+        assertNotNull("defined ${build.tests}", buildTestcases);
+        assertTrue("have a dir " + buildTestcases,
+                   new File(buildTestcases).isDirectory());
+        Path path = new Path(p, buildTestcases + "/org");
+        // A special parent loader which is not the system class loader:
+        ClassLoader parent = new ParentLoader();
+
+        URL urlFromPath = new URL(
+            FILE_UTILS.toURI(buildTestcases) + "org/" + TEST_RESOURCE);
+        AntClassLoader acl = new AntClassLoader(parent, p, path, false);
+        acl.setIsolated(true);
+        assertEquals("correct resources (reverse delegation order)",
+            Arrays.asList(new URL[] {urlFromPath}),
+            enum2List(acl.getResources(TEST_RESOURCE)));
+    }
+    
+    private static List enum2List(Enumeration e) {
+        // JDK 1.4: return Collections.list(e);
+        List l = new ArrayList();
+        while (e.hasMoreElements()) {
+            l.add(e.nextElement());
+        }
+        return l;
+    }
+    
+    /** Special loader that just knows how to find TEST_RESOURCE. */
+    private static final class ParentLoader extends ClassLoader {
+        
+        public ParentLoader() {}
+        
+        protected Enumeration findResources(String name) throws IOException {
+            if (name.equals(TEST_RESOURCE)) {
+                return Collections.enumeration(
+                    Collections.singleton(
+                        new URL("http://ant.apache.org/" + name)));
+            } else {
+                return Collections.enumeration(Collections.EMPTY_SET);
+            }
+        }
+        
+    }
+    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java b/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
new file mode 100644
index 0000000..10649da
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/AntClassLoaderTest.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Test case for ant class loader
+ *
+ */
+public class AntClassLoaderTest extends BuildFileTest {
+
+    private Project p;
+
+    public AntClassLoaderTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        p = new Project();
+        p.init();
+        configureProject("src/etc/testcases/core/antclassloader.xml");
+        getProject().executeTarget("setup");
+    }
+
+    public void tearDown() {
+        getProject().executeTarget("cleanup");
+    }
+    //test inspired by bug report 37085
+    public void testJarWithManifestInDirWithSpace() {
+        String mainjarstring = getProject().getProperty("main.jar");
+        String extjarstring = getProject().getProperty("ext.jar");
+        Path myPath = new Path(getProject());
+        myPath.setLocation(new File(mainjarstring));
+        getProject().setUserProperty("build.sysclasspath","ignore");
+        AntClassLoader myLoader = getProject().createClassLoader(myPath);
+        String path = myLoader.getClasspath();
+        assertEquals(mainjarstring + File.pathSeparator + extjarstring, path);
+    }
+    public void testJarWithManifestInNonAsciiDir() {
+        String mainjarstring = getProject().getProperty("main.jar.nonascii");
+        String extjarstring = getProject().getProperty("ext.jar.nonascii");
+        Path myPath = new Path(getProject());
+        myPath.setLocation(new File(mainjarstring));
+        getProject().setUserProperty("build.sysclasspath","ignore");
+        AntClassLoader myLoader = getProject().createClassLoader(myPath);
+        String path = myLoader.getClasspath();
+        assertEquals(mainjarstring + File.pathSeparator + extjarstring, path);
+    }
+    public void testCleanup() throws BuildException {
+        Path path = new Path(p, ".");
+        AntClassLoader loader = p.createClassLoader(path);
+        try {
+            // we don't expect to find this
+            loader.findClass("fubar");
+            fail("Did not expect to find fubar class");
+        } catch (ClassNotFoundException e) {
+            // ignore expected
+        }
+
+        loader.cleanup();
+        try {
+            // we don't expect to find this
+            loader.findClass("fubar");
+            fail("Did not expect to find fubar class");
+        } catch (ClassNotFoundException e) {
+            // ignore expected
+        } catch (NullPointerException e) {
+            fail("loader should not fail even if cleaned up");
+        }
+
+        // tell the build it is finished
+        p.fireBuildFinished(null);
+        try {
+            // we don't expect to find this
+            loader.findClass("fubar");
+            fail("Did not expect to find fubar class");
+        } catch (ClassNotFoundException e) {
+            // ignore expected
+        } catch (NullPointerException e) {
+            fail("loader should not fail even if project finished");
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java b/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java
new file mode 100644
index 0000000..18ae9bd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/BuildFileTest.java
@@ -0,0 +1,561 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+/**
+ * A BuildFileTest is a TestCase which executes targets from an Ant buildfile
+ * for testing.
+ *
+ * This class provides a number of utility methods for particular build file
+ * tests which extend this class.
+ *
+ */
+public abstract class BuildFileTest extends TestCase {
+
+    protected Project project;
+
+    private StringBuffer logBuffer;
+    private StringBuffer fullLogBuffer;
+    private StringBuffer outBuffer;
+    private StringBuffer errBuffer;
+    private BuildException buildException;
+
+    /**
+     * Default constructor for the BuildFileTest object.
+     */
+    public BuildFileTest() {
+        super();
+    }
+
+    /**
+     * Constructor for the BuildFileTest object.
+     *
+     * @param  name string to pass up to TestCase constructor
+     */
+    public BuildFileTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Automatically calls the target called "tearDown"
+     * from the build file tested if it exits.
+     *
+     * This allows to use Ant tasks directly in the build file
+     * to clean up after each test. Note that no "setUp" target
+     * is automatically called, since it's trivial to have a
+     * test target depend on it.
+     */
+    protected void tearDown() throws Exception {
+        if (project == null) {
+            /*
+             * Maybe the BuildFileTest was subclassed and there is
+             * no initialized project. So we could avoid getting a
+             * NPE.
+             * If there is an initialized project getTargets() does
+             * not return null as it is initialized by an empty
+             * HashSet.
+             */
+            return;
+        }
+        final String tearDown = "tearDown";
+        if (project.getTargets().containsKey(tearDown)) {
+            project.executeTarget(tearDown);
+        }
+    }
+
+    /**
+     * run a target, expect for any build exception
+     *
+     * @param  target target to run
+     * @param  cause  information string to reader of report
+     */
+    public void expectBuildException(String target, String cause) {
+        expectSpecificBuildException(target, cause, null);
+    }
+
+    /**
+     * Assert that only the given message has been logged with a
+     * priority &lt;= INFO when running the given target.
+     */
+    public void expectLog(String target, String log) {
+        executeTarget(target);
+        String realLog = getLog();
+        assertEquals(log, realLog);
+    }
+
+    /**
+     * Assert that the given substring is in the log messages.
+     */
+    public void assertLogContaining(String substring) {
+        String realLog = getLog();
+        assertTrue("expecting log to contain \"" + substring + "\" log was \""
+                   + realLog + "\"",
+                   realLog.indexOf(substring) >= 0);
+    }
+
+    /**
+     * Assert that the given substring is in the output messages.
+     * @since Ant1.7
+     */
+    public void assertOutputContaining(String substring) {
+        assertOutputContaining(null, substring);
+    }
+
+    /**
+     * Assert that the given substring is in the output messages.
+     * @param message Print this message if the test fails. Defaults to 
+     *                a meaningful text if <tt>null</tt> is passed.  
+     * @since Ant1.7
+     */
+    public void assertOutputContaining(String message, String substring) {
+        String realOutput = getOutput();
+        String realMessage = (message != null) 
+            ? message 
+            : "expecting output to contain \"" + substring + "\" output was \"" + realOutput + "\"";
+        assertTrue(realMessage, realOutput.indexOf(substring) >= 0);
+    }
+
+    /**
+     * Assert that the given substring is not in the output messages.
+     * @param message Print this message if the test fails. Defaults to 
+     *                a meaningful text if <tt>null</tt> is passed.  
+     * @since Ant1.7
+     */
+    public void assertOutputNotContaining(String message, String substring) {
+        String realOutput = getOutput();
+        String realMessage = (message != null) 
+            ? message 
+            : "expecting output to not contain \"" + substring + "\" output was \"" + realOutput + "\"";
+        assertFalse(realMessage, realOutput.indexOf(substring) >= 0);
+    }
+
+    /**
+     * Assert that the given message has been logged with a priority &lt;= INFO when running the
+     * given target.
+     */
+    public void expectLogContaining(String target, String log) {
+        executeTarget(target);
+        assertLogContaining(log);
+    }
+
+    /**
+     * Gets the log the BuildFileTest object.
+     * Only valid if configureProject() has been called.
+     *
+     * @pre logBuffer!=null
+     * @return    The log value
+     */
+    public String getLog() {
+        return logBuffer.toString();
+    }
+
+    /**
+     * Assert that the given message has been logged with a priority
+     * &gt;= VERBOSE when running the given target.
+     */
+    public void expectDebuglog(String target, String log) {
+        executeTarget(target);
+        String realLog = getFullLog();
+        assertEquals(log, realLog);
+    }
+
+    /**
+     * Assert that the given substring is in the log messages.
+     */
+    public void assertDebuglogContaining(String substring) {
+        String realLog = getFullLog();
+        assertTrue("expecting debug log to contain \"" + substring 
+                   + "\" log was \""
+                   + realLog + "\"",
+                   realLog.indexOf(substring) >= 0);
+    }
+
+    /**
+     * Gets the log the BuildFileTest object.
+     *
+     * Only valid if configureProject() has been called.
+     *
+     * @pre fullLogBuffer!=null
+     * @return    The log value
+     */
+    public String getFullLog() {
+        return fullLogBuffer.toString();
+    }
+
+    /**
+     * execute the target, verify output matches expectations
+     *
+     * @param  target  target to execute
+     * @param  output  output to look for
+     */
+    public void expectOutput(String target, String output) {
+        executeTarget(target);
+        String realOutput = getOutput();
+        assertEquals(output, realOutput.trim());
+    }
+
+    /**
+     * Executes the target, verify output matches expectations
+     * and that we got the named error at the end
+     *
+     * @param  target  target to execute
+     * @param  output  output to look for
+     * @param  error   Description of Parameter
+     */
+    public void expectOutputAndError(String target, String output, String error) {
+        executeTarget(target);
+        String realOutput = getOutput();
+        assertEquals(output, realOutput);
+        String realError = getError();
+        assertEquals(error, realError);
+    }
+
+    public String getOutput() {
+        return cleanBuffer(outBuffer);
+    }
+
+    public String getError() {
+        return cleanBuffer(errBuffer);
+    }
+
+    public BuildException getBuildException() {
+        return buildException;
+    }
+
+    private String cleanBuffer(StringBuffer buffer) {
+        StringBuffer cleanedBuffer = new StringBuffer();
+        boolean cr = false;
+        for (int i = 0; i < buffer.length(); i++) {
+            char ch = buffer.charAt(i);
+            if (ch == '\r') {
+                cr = true;
+                continue;
+            }
+
+            if (!cr) {
+                cleanedBuffer.append(ch);
+            } else {
+                cleanedBuffer.append(ch);
+            }
+        }
+        return cleanedBuffer.toString();
+    }
+
+    /**
+     * Sets up to run the named project
+     *
+     * @param  filename name of project file to run
+     */
+    public void configureProject(String filename) throws BuildException {
+        configureProject(filename, Project.MSG_DEBUG);
+    }
+
+    /**
+     * Sets up to run the named project
+     *
+     * @param  filename name of project file to run
+     */
+    public void configureProject(String filename, int logLevel)
+        throws BuildException {
+        logBuffer = new StringBuffer();
+        fullLogBuffer = new StringBuffer();
+        project = new Project();
+        project.init();
+        File antFile = new File(System.getProperty("root"), filename);
+        project.setUserProperty("ant.file" , antFile.getAbsolutePath());
+        project.addBuildListener(new AntTestListener(logLevel));
+        ProjectHelper.configureProject(project, antFile);
+    }
+
+    /**
+     * Executes a target we have set up
+     *
+     * @pre configureProject has been called
+     * @param  targetName  target to run
+     */
+    public void executeTarget(String targetName) {
+        PrintStream sysOut = System.out;
+        PrintStream sysErr = System.err;
+        try {
+            sysOut.flush();
+            sysErr.flush();
+            outBuffer = new StringBuffer();
+            PrintStream out = new PrintStream(new AntOutputStream(outBuffer));
+            System.setOut(out);
+            errBuffer = new StringBuffer();
+            PrintStream err = new PrintStream(new AntOutputStream(errBuffer));
+            System.setErr(err);
+            logBuffer = new StringBuffer();
+            fullLogBuffer = new StringBuffer();
+            buildException = null;
+            project.executeTarget(targetName);
+        } finally {
+            System.setOut(sysOut);
+            System.setErr(sysErr);
+        }
+
+    }
+
+    /**
+     * Get the project which has been configured for a test.
+     *
+     * @return the Project instance for this test.
+     */
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * Gets the directory of the project.
+     *
+     * @return the base dir of the project
+     */
+    public File getProjectDir() {
+        return project.getBaseDir();
+    }
+
+    /**
+     * Runs a target, wait for a build exception.
+     *
+     * @param  target target to run
+     * @param  cause  information string to reader of report
+     * @param  msg    the message value of the build exception we are waiting
+     *         for set to null for any build exception to be valid
+     */
+    public void expectSpecificBuildException(String target, String cause, String msg) {
+        try {
+            executeTarget(target);
+        } catch (org.apache.tools.ant.BuildException ex) {
+            buildException = ex;
+            if ((null != msg) && (!ex.getMessage().equals(msg))) {
+                fail("Should throw BuildException because '" + cause
+                        + "' with message '" + msg
+                        + "' (actual message '" + ex.getMessage() + "' instead)");
+            }
+            return;
+        }
+        fail("Should throw BuildException because: " + cause);
+    }
+
+    /**
+     * run a target, expect an exception string
+     * containing the substring we look for (case sensitive match)
+     *
+     * @param  target target to run
+     * @param  cause  information string to reader of report
+     * @param  contains  substring of the build exception to look for
+     */
+    public void expectBuildExceptionContaining(String target, String cause, String contains) {
+        try {
+            executeTarget(target);
+        } catch (org.apache.tools.ant.BuildException ex) {
+            buildException = ex;
+            if ((null != contains) && (ex.getMessage().indexOf(contains) == -1)) {
+                fail("Should throw BuildException because '" + cause + "' with message containing '" + contains + "' (actual message '" + ex.getMessage() + "' instead)");
+            }
+            return;
+        }
+        fail("Should throw BuildException because: " + cause);
+    }
+
+    /**
+     * call a target, verify property is as expected
+     *
+     * @param target build file target
+     * @param property property name
+     * @param value expected value
+     */
+    public void expectPropertySet(String target, String property, String value) {
+        executeTarget(target);
+        assertPropertyEquals(property, value);
+    }
+
+    /**
+     * assert that a property equals a value; comparison is case sensitive.
+     *
+     * @param property property name
+     * @param value expected value
+     */
+    public void assertPropertyEquals(String property, String value) {
+        String result = project.getProperty(property);
+        assertEquals("property " + property,value,result);
+    }
+
+    /**
+     * assert that a property equals "true".
+     *
+     * @param property property name
+     */
+    public  void assertPropertySet(String property) {
+        assertPropertyEquals(property, "true");
+    }
+
+    /**
+     * assert that a property is null.
+     *
+     * @param property property name
+     */
+    public  void assertPropertyUnset(String property) {
+        assertPropertyEquals(property, null);
+    }
+
+    /**
+     * call a target, verify named property is "true".
+     *
+     * @param target build file target
+     * @param property property name
+     */
+    public  void expectPropertySet(String target, String property) {
+        expectPropertySet(target, property, "true");
+    }
+
+    /**
+     * Call a target, verify property is null.
+     *
+     * @param target build file target
+     * @param property property name
+     */
+    public  void expectPropertyUnset(String target, String property) {
+        expectPropertySet(target, property, null);
+    }
+
+    /**
+     * Retrieve a resource from the caller classloader to avoid
+     * assuming a vm working directory. The resource path must be
+     * relative to the package name or absolute from the root path.
+     *
+     * @param resource the resource to retrieve its url.
+     * @throws junit.framework.AssertionFailedError if the resource is not found.
+     */
+    public  URL getResource(String resource){
+        URL url = getClass().getResource(resource);
+        assertNotNull("Could not find resource :" + resource, url);
+        return url;
+    }
+
+    /**
+     * an output stream which saves stuff to our buffer.
+     */
+    private static class AntOutputStream extends java.io.OutputStream {
+        private StringBuffer buffer;
+
+        public AntOutputStream( StringBuffer buffer ) {
+            this.buffer = buffer;
+        }
+
+        public void write(int b) {
+            buffer.append((char)b);
+        }
+    }
+
+    /**
+     * Our own personal build listener.
+     */
+    private class AntTestListener implements BuildListener {
+        private int logLevel;
+
+        /**
+         * Constructs a test listener which will ignore log events
+         * above the given level.
+         */
+        public AntTestListener(int logLevel) {
+            this.logLevel = logLevel;
+        }
+
+        /**
+         * Fired before any targets are started.
+         */
+        public void buildStarted(BuildEvent event) {
+        }
+
+        /**
+         * Fired after the last target has finished. This event
+         * will still be thrown if an error occurred during the build.
+         *
+         * @see BuildEvent#getException()
+         */
+        public void buildFinished(BuildEvent event) {
+        }
+
+        /**
+         * Fired when a target is started.
+         *
+         * @see BuildEvent#getTarget()
+         */
+        public void targetStarted(BuildEvent event) {
+            //System.out.println("targetStarted " + event.getTarget().getName());
+        }
+
+        /**
+         * Fired when a target has finished. This event will
+         * still be thrown if an error occurred during the build.
+         *
+         * @see BuildEvent#getException()
+         */
+        public void targetFinished(BuildEvent event) {
+            //System.out.println("targetFinished " + event.getTarget().getName());
+        }
+
+        /**
+         * Fired when a task is started.
+         *
+         * @see BuildEvent#getTask()
+         */
+        public void taskStarted(BuildEvent event) {
+            //System.out.println("taskStarted " + event.getTask().getTaskName());
+        }
+
+        /**
+         * Fired when a task has finished. This event will still
+         * be throw if an error occurred during the build.
+         *
+         * @see BuildEvent#getException()
+         */
+        public void taskFinished(BuildEvent event) {
+            //System.out.println("taskFinished " + event.getTask().getTaskName());
+        }
+
+        /**
+         * Fired whenever a message is logged.
+         *
+         * @see BuildEvent#getMessage()
+         * @see BuildEvent#getPriority()
+         */
+        public void messageLogged(BuildEvent event) {
+            if (event.getPriority() > logLevel) {
+                // ignore event
+                return;
+            }
+
+            if (event.getPriority() == Project.MSG_INFO ||
+                event.getPriority() == Project.MSG_WARN ||
+                event.getPriority() == Project.MSG_ERR) {
+                logBuffer.append(event.getMessage());
+            }
+            fullLogBuffer.append(event.getMessage());
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/CaseTest.java b/trunk/src/tests/junit/org/apache/tools/ant/CaseTest.java
new file mode 100644
index 0000000..fcb56d7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/CaseTest.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Simple tests of build file processing
+ */
+public class CaseTest extends BuildFileTest {
+
+    public CaseTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/case.xml");
+    }
+
+    /**
+     * Test whether the build file treats nested elements without
+     * regard to case. This should not cause an exception.
+     */
+    public void testCaseSensitivity() {
+        executeTarget("case-sensitivity");
+    }
+
+    /**
+     * Test whether the build file uses case when determining
+     * task names.
+     */
+    public void testTaskCase() {
+        expectBuildExceptionContaining("taskcase",
+            "Task names are case sensitive",
+            "Problem: failed to create task or type ecHO");
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DirectoryScannerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/DirectoryScannerTest.java
new file mode 100644
index 0000000..293434a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DirectoryScannerTest.java
@@ -0,0 +1,534 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.FileUtils;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Iterator;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.DirectoryScanner
+ *
+ */
+public class DirectoryScannerTest extends BuildFileTest {
+
+    public DirectoryScannerTest(String name) {super(name);}
+
+    // keep track of what operating systems are supported here.
+    private boolean supportsSymlinks = Os.isFamily("unix");
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/directoryscanner.xml");
+        getProject().executeTarget("setup");
+    }
+
+    public void tearDown() {
+        getProject().executeTarget("cleanup");
+    }
+
+    public void test1() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha"});
+        ds.scan();
+        compareFiles(ds, new String[] {} ,new String[] {"alpha"});
+    }
+
+    public void test2() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void test3() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"", "alpha", "alpha/beta",
+                                   "alpha/beta/gamma"});
+    }
+
+    public void testFullPathMatchesCaseSensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/GAMMA.XML"});
+        ds.scan();
+        compareFiles(ds, new String[] {}, new String[] {});
+    }
+
+    public void testFullPathMatchesCaseInsensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setCaseSensitive(false);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/GAMMA.XML"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+            new String[] {});
+    }
+
+    public void test2ButCaseInsensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"ALPHA/"});
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testAllowSymlinks() {
+        if (!supportsSymlinks) {
+            return;
+        }
+
+        getProject().executeTarget("symlink-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha/beta/gamma"});
+    }
+
+    public void testProhibitSymlinks() {
+        if (!supportsSymlinks) {
+            return;
+        }
+
+        getProject().executeTarget("symlink-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/"});
+        ds.setFollowSymlinks(false);
+        ds.scan();
+        compareFiles(ds, new String[] {}, new String[] {});
+    }
+
+    // father and child pattern test
+    public void testOrderOfIncludePatternsIrrelevant() {
+        String [] expectedFiles = {"alpha/beta/beta.xml",
+                                   "alpha/beta/gamma/gamma.xml"};
+        String [] expectedDirectories = {"alpha/beta", "alpha/beta/gamma" };
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/be?a/**", "alpha/beta/gamma/"});
+        ds.scan();
+        compareFiles(ds, expectedFiles, expectedDirectories);
+        // redo the test, but the 2 include patterns are inverted
+        ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/", "alpha/be?a/**"});
+        ds.scan();
+        compareFiles(ds, expectedFiles, expectedDirectories);
+    }
+
+    public void testPatternsDifferInCaseScanningSensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testPatternsDifferInCaseScanningInsensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/"});
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testFullpathDiffersInCaseScanningSensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/beta/gamma/gamma.xml",
+            "alpha/beta/gamma/GAMMA.XML"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+
+    public void testFullpathDiffersInCaseScanningInsensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/beta/gamma/gamma.xml",
+            "alpha/beta/gamma/GAMMA.XML"
+        });
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+
+    public void testParentDiffersInCaseScanningSensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/beta/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testParentDiffersInCaseScanningInsensitive() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/beta/"});
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    /**
+     * Test case for setFollowLinks() and associated functionality.
+     * Only supports test on Linux at the moment because Java has
+     * no real notion of symlinks built in, so an os-specfic call
+     * to Runtime.exec() must be made to create a link to test against.
+     */
+    public void testSetFollowLinks() throws IOException {
+        if (supportsSymlinks) {
+            File linkFile = new File(System.getProperty("root"), "src/main/org/apache/tools/ThisIsALink");
+            System.err.println("link exists pre-test? " + linkFile.exists());
+            
+            try {
+                // add conditions and more commands as soon as the need arises
+                String[] command = new String[] {
+                    "ln", "-s", "ant", linkFile.getAbsolutePath()
+                };
+                try {
+                    Runtime.getRuntime().exec(command);
+                    // give ourselves some time for the system call
+                    // to execute... tweak if you have a really over
+                    // loaded system.
+                    Thread.sleep(1000);
+                } catch (IOException ioe) {
+                    fail("IOException making link "+ioe);
+                } catch (InterruptedException ie) {
+                }
+
+                File dir = new File(System.getProperty("root"), "src/main/org/apache/tools");
+                System.err.println("link exists after exec? " + linkFile.exists());
+                System.err.println("Ant knows it is a link? " + FileUtils.getFileUtils().isSymbolicLink(dir, "ThisIsALink"));
+
+                DirectoryScanner ds = new DirectoryScanner();
+
+                // followLinks should be true by default, but if this ever
+                // changes we will need this line.
+                ds.setFollowSymlinks(true);
+
+                ds.setBasedir(dir);
+                ds.setExcludes(new String[] {"ant/**"});
+                ds.scan();
+
+                boolean haveZipPackage = false;
+                boolean haveTaskdefsPackage = false;
+
+                String[] included = ds.getIncludedDirectories();
+                for (int i=0; i<included.length; i++) {
+                    if (included[i].equals("zip")) {
+                        haveZipPackage = true;
+                    } else if (included[i].equals("ThisIsALink"
+                                                  + File.separator
+                                                  + "taskdefs")) {
+                        haveTaskdefsPackage = true;
+                    }
+                }
+
+                // if we followed the symlink we just made we should
+                // bypass the excludes.
+
+                assertTrue("(1) zip package included", haveZipPackage);
+                assertTrue("(1) taskdefs package included",
+                           haveTaskdefsPackage);
+
+
+                ds = new DirectoryScanner();
+                ds.setFollowSymlinks(false);
+
+                ds.setBasedir(dir);
+                ds.setExcludes(new String[] {"ant/**"});
+                ds.scan();
+
+                haveZipPackage = false;
+                haveTaskdefsPackage = false;
+                included = ds.getIncludedDirectories();
+                for (int i=0; i<included.length; i++) {
+                    if (included[i].equals("zip")) {
+                        haveZipPackage = true;
+                    } else if (included[i].equals("ThisIsALink"
+                                                  + File.separator
+                                                  + "taskdefs")) {
+                        haveTaskdefsPackage = true;
+                    }
+                }
+                assertTrue("(2) zip package included", haveZipPackage);
+                assertTrue("(2) taskdefs package not included",
+                           !haveTaskdefsPackage);
+
+            } finally {
+                System.err.println("link exists pre-delete? " + linkFile.exists());
+                if (!linkFile.delete()) {
+                    throw new RuntimeException("Failed to delete " + linkFile);
+                }
+                System.err.println("link exists post-delete? " + linkFile.exists());
+            }
+        }
+    }
+
+    public void testExcludeOneFile() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "**/*.xml"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/beta/b*xml"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+
+    public void testExcludeHasPrecedence() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/**"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {});
+
+    }
+
+    public void testAlternateIncludeExclude() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/**",
+            "alpha/beta/gamma/**"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/beta/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {"alpha"});
+
+    }
+
+    public void testAlternateExcludeInclude() {
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {
+            "alpha/**",
+            "alpha/beta/gamma/**"
+        });
+        ds.setIncludes(new String[] {
+            "alpha/beta/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {});
+
+    }
+
+    /**
+     * Test inspired by Bug#1415.
+     */
+    public void testChildrenOfExcludedDirectory() {
+        getProject().executeTarget("children-of-excluded-dir-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {"alpha/**"});
+        ds.setFollowSymlinks(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"delta/delta.xml"},
+                    new String[] {"", "delta"});
+
+        ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {"alpha"});
+        ds.setFollowSymlinks(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml",
+                                        "delta/delta.xml"},
+                     new String[] {"", "alpha/beta", "alpha/beta/gamma", "delta"});
+
+    }
+
+    public void testIsExcludedDirectoryScanned() {
+        String shareclassloader = getProject().getProperty("tests.and.ant.share.classloader");
+        // when the test is started by the build.xml of ant
+        // if the property tests.and.ant.share.classloader is not set in the build.xml
+        // a sysproperty with name tests.and.ant.share.classloader and value
+        // ${tests.and.ant.share.classloader} will be set
+        // we are trying to catch this here.
+        if (shareclassloader == null
+                || (shareclassloader != null && shareclassloader.indexOf("${") == 0)) {
+            System.out.println("cannot execute testIsExcludedDirectoryScanned when tests are forked, " +
+                    "package private method called");
+            return;
+        }
+        getProject().executeTarget("children-of-excluded-dir-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {"**/gamma/**"});
+        ds.setFollowSymlinks(false);
+        ds.scan();
+        Set set = ds.getScannedDirs();
+        assertFalse("empty set", set.isEmpty());
+        String s = "alpha/beta/gamma/".replace('/', File.separatorChar);
+        assertFalse("scanned " + s, set.contains(s));
+    }
+
+    public void testAbsolute1() {
+        getProject().executeTarget("extended-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        String tmpdir = getProject().getBaseDir().getAbsolutePath().replace(
+            File.separatorChar, '/') + "/tmp";
+        ds.setIncludes(new String[] {tmpdir + "/**/*"});
+        ds.scan();
+        compareFiles(ds, new String[] {tmpdir + "/alpha/beta/beta.xml",
+                                       tmpdir + "/alpha/beta/gamma/gamma.xml",
+                                       tmpdir + "/delta/delta.xml"},
+                     new String[] {tmpdir + "/alpha",
+                                   tmpdir + "/alpha/beta",
+                                   tmpdir + "/alpha/beta/gamma",
+                                   tmpdir + "/delta"});
+    }
+
+    public void testAbsolute2() {
+        getProject().executeTarget("setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        ds.setIncludes(new String[] {"alpha/**", "alpha/beta/gamma/**"});
+        ds.scan();
+        String[] mt = new String[0];
+        compareFiles(ds, mt, mt);
+    }
+
+    public void testAbsolute3() {
+        getProject().executeTarget("extended-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        String tmpdir = getProject().getBaseDir().getAbsolutePath().replace(
+            File.separatorChar, '/') + "/tmp";
+        ds.setIncludes(new String[] {tmpdir + "/**/*"});
+        ds.setExcludes(new String[] {"**/alpha",
+                                     "**/delta/*"});
+        ds.scan();
+        compareFiles(ds, new String[] {tmpdir + "/alpha/beta/beta.xml",
+                                       tmpdir + "/alpha/beta/gamma/gamma.xml"},
+                     new String[] {tmpdir + "/alpha/beta",
+                                   tmpdir + "/alpha/beta/gamma",
+                                   tmpdir + "/delta"});
+    }
+
+    public void testAbsolute4() {
+        getProject().executeTarget("extended-setup");
+        DirectoryScanner ds = new DirectoryScanner();
+        String tmpdir = getProject().getBaseDir().getAbsolutePath().replace(
+            File.separatorChar, '/') + "/tmp";
+        ds.setIncludes(new String[] {tmpdir + "/alpha/beta/**/*",
+                                     tmpdir + "/delta/*"});
+        ds.setExcludes(new String[] {"**/beta.xml"});
+        ds.scan();
+        compareFiles(ds, new String[] {tmpdir + "/alpha/beta/gamma/gamma.xml",
+                                       tmpdir + "/delta/delta.xml"},
+                     new String[] {tmpdir + "/alpha/beta/gamma"});
+    }
+
+    public void testAbsolute5() {
+        //testing drive letter search from root:
+        if (!(Os.isFamily("dos") || Os.isFamily("netware"))) {
+            return;
+        }
+        DirectoryScanner ds = new DirectoryScanner();
+        String pattern = new File(File.separator).getAbsolutePath().toUpperCase() + "*";
+        ds.setIncludes(new String[] {pattern});
+        ds.scan();
+        //if this is our context we assume there must be something here:
+        assertTrue("should have at least one resident file",
+            ds.getIncludedFilesCount() + ds.getIncludedDirsCount() > 0);
+    }
+
+    private void compareFiles(DirectoryScanner ds, String[] expectedFiles,
+                              String[] expectedDirectories) {
+        String includedFiles[] = ds.getIncludedFiles();
+        String includedDirectories[] = ds.getIncludedDirectories();
+        assertEquals("file present: ", expectedFiles.length,
+                     includedFiles.length);
+        assertEquals("directories present: ", expectedDirectories.length,
+                     includedDirectories.length);
+
+        TreeSet files = new TreeSet();
+        for (int counter = 0; counter < includedFiles.length; counter++) {
+            files.add(includedFiles[counter].replace(File.separatorChar, '/'));
+        }
+        TreeSet directories = new TreeSet();
+        for (int counter = 0; counter < includedDirectories.length; counter++) {
+            directories.add(includedDirectories[counter]
+                            .replace(File.separatorChar, '/'));
+        }
+
+        String currentfile;
+        Iterator i = files.iterator();
+        int counter = 0;
+        while (i.hasNext()) {
+            currentfile = (String) i.next();
+            assertEquals(expectedFiles[counter], currentfile);
+            counter++;
+        }
+        String currentdirectory;
+        Iterator dirit = directories.iterator();
+        counter = 0;
+        while (dirit.hasNext()) {
+            currentdirectory = (String) dirit.next();
+            assertEquals(expectedDirectories[counter], currentdirectory);
+            counter++;
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DispatchTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/DispatchTaskTest.java
new file mode 100644
index 0000000..2184a97
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DispatchTaskTest.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class DispatchTaskTest extends BuildFileTest {
+
+    public DispatchTaskTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/dispatch/dispatch.xml");
+    }
+
+    public void testDisp() {
+        expectBuildException("disp", "list");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskAbstract.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskAbstract.java
new file mode 100644
index 0000000..18fe09d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskAbstract.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.Task;
+
+public abstract class DummyTaskAbstract extends Task {
+
+    public DummyTaskAbstract() {
+    }
+
+    public void execute() {
+    }
+
+    public abstract void abstractDummy();
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskInterface.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskInterface.java
new file mode 100644
index 0000000..8ae5f5b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskInterface.java
@@ -0,0 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public interface DummyTaskInterface {
+
+    void execute();
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOk.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOk.java
new file mode 100644
index 0000000..ff8fdab
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOk.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.Task;
+
+public class DummyTaskOk extends Task {
+
+    public DummyTaskOk() {
+    }
+
+    public void execute() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOkNonTask.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOkNonTask.java
new file mode 100644
index 0000000..234abd6
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskOkNonTask.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public class DummyTaskOkNonTask {
+
+    public DummyTaskOkNonTask() {
+    }
+
+    public void execute() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonPublicExecute.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonPublicExecute.java
new file mode 100644
index 0000000..766283d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonPublicExecute.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public class DummyTaskWithNonPublicExecute {
+
+    public DummyTaskWithNonPublicExecute() {
+    }
+
+    void execute() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonVoidExecute.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonVoidExecute.java
new file mode 100644
index 0000000..876b9b7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithNonVoidExecute.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public class DummyTaskWithNonVoidExecute {
+
+    public DummyTaskWithNonVoidExecute() {
+    }
+
+    public int execute() {
+        return 0;
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutDefaultConstructor.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutDefaultConstructor.java
new file mode 100644
index 0000000..40661f5
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutDefaultConstructor.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.Task;
+
+public class DummyTaskWithoutDefaultConstructor extends Task {
+
+    public DummyTaskWithoutDefaultConstructor(int dummy) {
+    }
+
+    public void execute() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutExecute.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutExecute.java
new file mode 100644
index 0000000..6d5ea00
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutExecute.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public class DummyTaskWithoutExecute {
+
+    public DummyTaskWithoutExecute() {
+    }
+
+    public void execute(String dummy) {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutPublicConstructor.java b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutPublicConstructor.java
new file mode 100644
index 0000000..0ec4ff8
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/DummyTaskWithoutPublicConstructor.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.Task;
+
+public class DummyTaskWithoutPublicConstructor extends Task {
+
+    DummyTaskWithoutPublicConstructor() {
+    }
+
+    public void execute() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/ExecutorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/ExecutorTest.java
new file mode 100755
index 0000000..bf8c9bd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/ExecutorTest.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.util.Vector;
+
+/**
+ * Executor tests
+ */
+public class ExecutorTest extends BuildFileTest implements BuildListener {
+    private static final String SINGLE_CHECK
+        = "org.apache.tools.ant.helper.SingleCheckExecutor";
+    private static final String IGNORE_DEPS
+        = "org.apache.tools.ant.helper.IgnoreDependenciesExecutor";
+    private static final Vector TARGET_NAMES;
+    static {
+        TARGET_NAMES = new Vector();
+        TARGET_NAMES.add("a");
+        TARGET_NAMES.add("b");
+    }
+
+    private int targetCount;
+
+    /* BuildListener stuff */
+    public void targetStarted(BuildEvent event) {
+        targetCount++;
+    }
+    public void buildStarted(BuildEvent event) {}
+    public void buildFinished(BuildEvent event) {}
+    public void targetFinished(BuildEvent event) {}
+    public void taskStarted(BuildEvent event) {}
+    public void taskFinished(BuildEvent event) {}
+    public void messageLogged(BuildEvent event) {}
+
+    public ExecutorTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/executor.xml");
+        targetCount = 0;
+        getProject().addBuildListener(this);
+    }
+
+    private Project getProject(String e) {
+        return getProject(e, false);
+    }
+
+    private Project getProject(String e, boolean f) {
+        return getProject(e, f, false);
+    }
+
+    private Project getProject(String e, boolean f, boolean k) {
+        Project p = getProject();
+        p.setNewProperty("ant.executor.class", e);
+        p.setKeepGoingMode(k);
+        if (f) {
+            p.setNewProperty("failfoo", "foo");
+        }
+        return p;
+    }
+
+    public void testDefaultExecutor() {
+        getProject().executeTargets(TARGET_NAMES);
+        assertEquals(4, targetCount);
+    }
+
+    public void testSingleCheckExecutor() {
+        getProject(SINGLE_CHECK).executeTargets(TARGET_NAMES);
+        assertEquals(3, targetCount);
+    }
+
+    public void testIgnoreDependenciesExecutor() {
+        getProject(IGNORE_DEPS).executeTargets(TARGET_NAMES);
+        assertEquals(2, targetCount);
+    }
+
+    public void testDefaultFailure() {
+        try {
+            getProject(null, true).executeTargets(TARGET_NAMES);
+            fail("should fail");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage().equals("failfoo"));
+            assertEquals(1, targetCount);
+        }
+    }
+
+    public void testSingleCheckFailure() {
+        try {
+            getProject(SINGLE_CHECK, true).executeTargets(TARGET_NAMES);
+            fail("should fail");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage().equals("failfoo"));
+            assertEquals(1, targetCount);
+        }
+    }
+
+    public void testIgnoreDependenciesFailure() {
+        //no foo failure; foo is never executed as dependencies are ignored!
+        getProject(IGNORE_DEPS, true).executeTargets(TARGET_NAMES);
+    }
+
+    public void testKeepGoingDefault() {
+        try {
+            getProject(null, true, true).executeTargets(TARGET_NAMES);
+            fail("should fail");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage().equals("failfoo"));
+            assertEquals(2, targetCount);
+        }
+    }
+
+    public void testKeepGoingSingleCheck() {
+        try {
+            getProject(SINGLE_CHECK, true, true).executeTargets(TARGET_NAMES);
+            fail("should fail");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage().equals("failfoo"));
+            assertEquals(1, targetCount);
+        }
+    }
+
+    public void testKeepGoingIgnoreDependencies() {
+        try {
+            //explicitly add foo for failure
+            Vector targetNames = new Vector(TARGET_NAMES);
+            targetNames.add(0, "foo");
+            getProject(IGNORE_DEPS, true, true).executeTargets(targetNames);
+            fail("should fail");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage().equals("failfoo"));
+            assertEquals(3, targetCount);
+        }
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/ExtendedTaskdefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/ExtendedTaskdefTest.java
new file mode 100644
index 0000000..08a8029
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/ExtendedTaskdefTest.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant;
+
+/**
+ * created 16-Mar-2006 12:25:12
+ */
+
+public class ExtendedTaskdefTest extends BuildFileTest {
+
+    /**
+     * Constructor for the BuildFileTest object.
+     *
+     * @param name string to pass up to TestCase constructor
+     */
+    public ExtendedTaskdefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/extended-taskdef.xml");
+    }
+
+    /**
+     * Automatically calls the target called "tearDown"
+     * from the build file tested if it exits.
+     * <p/>
+     * This allows to use Ant tasks directly in the build file
+     * to clean up after each test. Note that no "setUp" target
+     * is automatically called, since it's trivial to have a
+     * test target depend on it.
+     */
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        executeTarget("teardown");
+    }
+
+    public void testRun() throws Exception {
+        expectBuildExceptionContaining("testRun",
+                "exception thrown by the subclass",
+                "executing the Foo task");
+    }
+
+    public void testRun2() throws Exception {
+        expectBuildExceptionContaining("testRun2",
+                "exception thrown by the subclass",
+                "executing the Foo task");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/ImmutableTest.java b/trunk/src/tests/junit/org/apache/tools/ant/ImmutableTest.java
new file mode 100644
index 0000000..fef59cd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/ImmutableTest.java
@@ -0,0 +1,78 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class ImmutableTest extends BuildFileTest {
+
+    public ImmutableTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/immutable.xml");
+    }
+
+    // override allowed on <available>
+    public void test1() {
+        executeTarget("test1");
+        assertEquals("override", project.getProperty("test"));
+    }
+
+    // ensure <tstamp>'s new prefix attribute is working
+    public void test2() {
+        executeTarget("test2");
+        assertNotNull(project.getProperty("DSTAMP"));
+        assertNotNull(project.getProperty("start.DSTAMP"));
+    }
+
+    // ensure <tstamp> follows the immutability rule
+    public void test3() {
+        executeTarget("test3");
+        assertEquals("original", project.getProperty("DSTAMP"));
+    }
+
+    // ensure <condition> follows the immutability rule
+    public void test4() {
+        executeTarget("test4");
+        assertEquals("original", project.getProperty("test"));
+    }
+    // ensure <checksum> follows the immutability rule
+    public void test5() {
+        executeTarget("test5");
+        assertEquals("original", project.getProperty("test"));
+    }
+
+    // ensure <exec> follows the immutability rule
+    public void test6() {
+        executeTarget("test6");
+        assertEquals("original", project.getProperty("test1"));
+        assertEquals("original", project.getProperty("test2"));
+    }
+
+    // ensure <pathconvert> follows the immutability rule
+    public void test7() {
+        executeTarget("test7");
+        assertEquals("original", project.getProperty("test"));
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/IncludeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/IncludeTest.java
new file mode 100644
index 0000000..56cb5d5
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/IncludeTest.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test the build file inclusion using XML entities.
+ *
+ */
+public class IncludeTest extends BuildFileTest {
+
+    public IncludeTest(String name) {
+        super(name);
+    }
+
+    public void test1() {
+        configureProject("src/etc/testcases/core/include/basic/include.xml");
+        expectLog("test1", "from included entity");
+    }
+
+    public void test2() {
+        configureProject("src/etc/testcases/core/include/frag#ment/include.xml");
+        expectLog("test1", "from included entity");
+    }
+
+    public void test3() {
+        configureProject("src/etc/testcases/core/include/frag#ment/simple.xml");
+        expectLog("test1", "from simple buildfile");
+    }
+
+    public void test4() {
+        configureProject("src/etc/testcases/core/include/basic/relative.xml");
+        expectLog("test1", "from included entity");
+    }
+
+    public void test5() {
+        configureProject("src/etc/testcases/core/include/frag#ment/relative.xml");
+        expectLog("test1", "from included entity");
+    }
+
+    public void testParseErrorInIncluding() {
+        try {
+            configureProject("src/etc/testcases/core/include/including_file_parse_error/build.xml");
+            fail("should have caused a parser exception");
+        } catch (BuildException e) {
+            assertTrue(e.getLocation().toString()
+                       + " should refer to build.xml",
+                       e.getLocation().toString().indexOf("build.xml:") > -1);
+        }
+    }
+
+    public void testTaskErrorInIncluding() {
+        configureProject("src/etc/testcases/core/include/including_file_task_error/build.xml");
+        try {
+            executeTarget("test");
+            fail("should have cause a build failure");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage()
+                       + " should start with \'Warning: Could not find",
+                         e.getMessage().startsWith("Warning: Could not find file "));
+            assertTrue(e.getLocation().toString()
+                       + " should end with build.xml:14: ",
+                       e.getLocation().toString().endsWith("build.xml:14: "));
+        }
+    }
+
+    public void testParseErrorInIncluded() {
+        try {
+            configureProject("src/etc/testcases/core/include/included_file_parse_error/build.xml");
+            fail("should have caused a parser exception");
+        } catch (BuildException e) {
+            assertTrue(e.getLocation().toString()
+                       + " should refer to included_file.xml",
+                       e.getLocation().toString()
+                       .indexOf("included_file.xml:") > -1);
+        }
+    }
+
+    public void testTaskErrorInIncluded() {
+        configureProject("src/etc/testcases/core/include/included_file_task_error/build.xml");
+        try {
+            executeTarget("test");
+            fail("should have cause a build failure");
+        } catch (BuildException e) {
+            assertTrue(e.getMessage()
+                       + " should start with \'Warning: Could not find",
+                         e.getMessage().startsWith("Warning: Could not find file "));
+            assertTrue(e.getLocation().toString()
+                       + " should end with included_file.xml:2: ",
+                       e.getLocation().toString().endsWith("included_file.xml:2: "));
+        }
+    }
+
+    public void testWithSpaceInclude() {
+        configureProject("src/etc/testcases/core/include/with space/include.xml");
+        try {
+            expectLog("test1", "from included entity in 'with space'");
+        } catch (Throwable t) {
+            throw new AssertionFailedError(
+                t.toString() + "; log=\n" + getFullLog());
+        }
+    }
+
+    public void testWithSpaceSimple() {
+        configureProject("src/etc/testcases/core/include/with space/simple.xml");
+        expectLog("test1", "from simple buildfile in 'with space'");
+    }
+
+    public void testWithSpaceRelative() {
+        configureProject("src/etc/testcases/core/include/with space/relative.xml");
+        expectLog("test1", "from included entity in 'with space'");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/IntrospectionHelperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/IntrospectionHelperTest.java
new file mode 100644
index 0000000..26a0156
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/IntrospectionHelperTest.java
@@ -0,0 +1,684 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import junit.framework.TestCase;
+import junit.framework.AssertionFailedError;
+import java.io.File;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.IntrospectionHelper.
+ *
+ */
+
+public class IntrospectionHelperTest extends TestCase {
+
+    private Project p;
+    private IntrospectionHelper ih;
+    private static final String projectBasedir = File.separator;
+
+    public IntrospectionHelperTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        p = new Project();
+        p.setBasedir(projectBasedir);
+        ih = IntrospectionHelper.getHelper(getClass());
+    }
+
+    public void testIsDynamic() {
+        assertTrue("Not dynamic", false == ih.isDynamic());
+    }
+
+    public void testIsContainer() {
+        assertTrue("Not a container", false == ih.isContainer());
+    }
+
+    public void testAddText() throws BuildException {
+        ih.addText(p, this, "test");
+        try {
+            ih.addText(p, this, "test2");
+            fail("test2 shouldn\'t be equal to test");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+
+        ih = IntrospectionHelper.getHelper(String.class);
+        try {
+            ih.addText(p, "", "test");
+            fail("String doesn\'t support addText");
+        } catch (BuildException be) {
+        }
+    }
+
+    public void testGetAddTextMethod() {
+        Method m = ih.getAddTextMethod();
+        assertMethod(m, "addText", String.class, "test", "bing!");
+
+        ih = IntrospectionHelper.getHelper(String.class);
+        try {
+            m = ih.getAddTextMethod();
+        } catch (BuildException e) {}
+    }
+
+    public void testSupportsCharacters() {
+        assertTrue("IntrospectionHelperTest supports addText",
+                   ih.supportsCharacters());
+
+        ih = IntrospectionHelper.getHelper(String.class);
+        assertTrue("String doesn\'t support addText", !ih.supportsCharacters());
+    }
+
+    public void addText(String text) {
+        assertEquals("test", text);
+    }
+
+    public void testElementCreators() throws BuildException {
+        try {
+            ih.getElementType("one");
+            fail("don't have element type one");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("two");
+            fail("createTwo takes arguments");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("three");
+            fail("createThree returns void");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("four");
+            fail("createFour returns array");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("five");
+            fail("createFive returns primitive type");
+        } catch (BuildException be) {
+        }
+        assertEquals(String.class, ih.getElementType("six"));
+        assertEquals("test", ih.createElement(p, this, "six"));
+
+        try {
+            ih.getElementType("seven");
+            fail("addSeven takes two arguments");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("eight");
+            fail("addEight takes no arguments");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("nine");
+            fail("nine return non void");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("ten");
+            fail("addTen takes array argument");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("eleven");
+            fail("addEleven takes primitive argument");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.getElementType("twelve");
+            fail("no primitive constructor for java.lang.Class");
+        } catch (BuildException be) {
+        }
+        assertEquals(StringBuffer.class, ih.getElementType("thirteen"));
+        assertEquals("test", ih.createElement(p, this, "thirteen").toString());
+
+        try {
+            ih.createElement(p, this, "fourteen");
+            fail("fourteen throws NullPointerException");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof NullPointerException);
+        }
+
+        try {
+            ih.createElement(p, this, "fourteen");
+            fail("fifteen throws NullPointerException");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof NullPointerException);
+        }
+    }
+
+    private Map getExpectedNestedElements() {
+        Map elemMap = new Hashtable();
+        elemMap.put("six", String.class);
+        elemMap.put("thirteen", StringBuffer.class);
+        elemMap.put("fourteen", StringBuffer.class);
+        elemMap.put("fifteen", StringBuffer.class);
+        return elemMap;
+    }
+
+    public void testGetNestedElements() {
+        Map elemMap = getExpectedNestedElements();
+        Enumeration e = ih.getNestedElements();
+        while (e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            Class expect = (Class) elemMap.get(name);
+            assertNotNull("Support for "+name+" in IntrospectioNHelperTest?",
+                          expect);
+            assertEquals("Return type of "+name, expect, ih.getElementType(name));
+            elemMap.remove(name);
+        }
+        assertTrue("Found all", elemMap.isEmpty());
+    }
+
+    public void testGetNestedElementMap() {
+        Map elemMap = getExpectedNestedElements();
+        Map actualMap = ih.getNestedElementMap();
+        for (Iterator i = actualMap.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            String elemName = (String) entry.getKey();
+            Class elemClass = (Class) elemMap.get(elemName);
+            assertNotNull("Support for " + elemName +
+                          " in IntrospectionHelperTest?", elemClass);
+            assertEquals("Type of " + elemName, elemClass, entry.getValue());
+            elemMap.remove(elemName);
+        }
+        assertTrue("Found all", elemMap.isEmpty());
+
+        // Check it's a read-only map.
+        try {
+            actualMap.clear();
+        } catch (UnsupportedOperationException e) {}
+    }
+
+    public void testGetElementMethod() {
+        assertElemMethod("six", "createSix", String.class, null);
+        assertElemMethod("thirteen", "addThirteen", null, StringBuffer.class);
+        assertElemMethod("fourteen", "addFourteen", null, StringBuffer.class);
+        assertElemMethod("fifteen", "createFifteen", StringBuffer.class, null);
+    }
+
+    private void assertElemMethod(String elemName, String methodName,
+                                  Class returnType, Class methodArg) {
+        Method m = ih.getElementMethod(elemName);
+        assertEquals("Method name", methodName, m.getName());
+        Class expectedReturnType = (returnType == null)? Void.TYPE: returnType;
+        assertEquals("Return type", expectedReturnType, m.getReturnType());
+        Class[] args = m.getParameterTypes();
+        if (methodArg != null) {
+            assertEquals("Arg Count", 1, args.length);
+            assertEquals("Arg Type", methodArg, args[0]);
+        } else {
+            assertEquals("Arg Count", 0, args.length);
+        }
+    }
+
+    public Object createTwo(String s) {
+        return null;
+    }
+
+    public void createThree() {}
+
+    public Object[] createFour() {
+        return null;
+    }
+
+    public int createFive() {
+        return 0;
+    }
+
+    public String createSix() {
+        return "test";
+    }
+
+    public StringBuffer createFifteen() {
+        throw new NullPointerException();
+    }
+
+    public void addSeven(String s, String s2) {}
+
+    public void addEight() {}
+
+    public String addNine(String s) {
+        return null;
+    }
+
+    public void addTen(String[] s) {}
+
+    public void addEleven(int i) {}
+
+    public void addTwelve(Class c) {}
+
+    public void addThirteen(StringBuffer sb) {
+        sb.append("test");
+    }
+
+    public void addFourteen(StringBuffer s) {
+        throw new NullPointerException();
+    }
+
+    public void testAttributeSetters() throws BuildException {
+        try {
+            ih.setAttribute(p, this, "one", "test");
+            fail("setOne doesn't exist");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.setAttribute(p, this, "two", "test");
+            fail("setTwo returns non void");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.setAttribute(p, this, "three", "test");
+            fail("setThree takes no args");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.setAttribute(p, this, "four", "test");
+            fail("setFour takes two args");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.setAttribute(p, this, "five", "test");
+            fail("setFive takes array arg");
+        } catch (BuildException be) {
+        }
+        try {
+            ih.setAttribute(p, this, "six", "test");
+            fail("Project doesn't have a String constructor");
+        } catch (BuildException be) {
+        }
+        ih.setAttribute(p, this, "seven", "2");
+        try {
+            ih.setAttribute(p, this, "seven", "3");
+            fail("2 shouldn't be equals to three");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "eight", "2");
+        try {
+            ih.setAttribute(p, this, "eight", "3");
+            fail("2 shouldn't be equals to three - as int");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "nine", "2");
+        try {
+            ih.setAttribute(p, this, "nine", "3");
+            fail("2 shouldn't be equals to three - as Integer");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "ten", "2");
+        try {
+            ih.setAttribute(p, this, "ten", "3");
+            fail(projectBasedir+"2 shouldn't be equals to "+projectBasedir+"3");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "eleven", "2");
+        try {
+            ih.setAttribute(p, this, "eleven", "on");
+            fail("on shouldn't be false");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "twelve", "2");
+        try {
+            ih.setAttribute(p, this, "twelve", "on");
+            fail("on shouldn't be false");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "thirteen", "org.apache.tools.ant.Project");
+        try {
+            ih.setAttribute(p, this, "thirteen", "org.apache.tools.ant.ProjectHelper");
+            fail("org.apache.tools.ant.Project shouldn't be equal to org.apache.tools.ant.ProjectHelper");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        try {
+            ih.setAttribute(p, this, "thirteen", "org.apache.tools.ant.Project2");
+            fail("org.apache.tools.ant.Project2 doesn't exist");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof ClassNotFoundException);
+        }
+        ih.setAttribute(p, this, "fourteen", "2");
+        try {
+            ih.setAttribute(p, this, "fourteen", "on");
+            fail("2 shouldn't be equals to three - as StringBuffer");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "fifteen", "abcd");
+        try {
+            ih.setAttribute(p, this, "fifteen", "on");
+            fail("o shouldn't be equal to a");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "sixteen", "abcd");
+        try {
+            ih.setAttribute(p, this, "sixteen", "on");
+            fail("o shouldn't be equal to a");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "seventeen", "17");
+        try {
+            ih.setAttribute(p, this, "seventeen", "3");
+            fail("17 shouldn't be equals to three");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "eightteen", "18");
+        try {
+            ih.setAttribute(p, this, "eightteen", "3");
+            fail("18 shouldn't be equals to three");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+        ih.setAttribute(p, this, "nineteen", "19");
+        try {
+            ih.setAttribute(p, this, "nineteen", "3");
+            fail("19 shouldn't be equals to three");
+        } catch (BuildException be) {
+            assertTrue(be.getException() instanceof AssertionFailedError);
+        }
+    }
+
+    private Map getExpectedAttributes() {
+        Map attrMap = new Hashtable();
+        attrMap.put("seven", String.class);
+        attrMap.put("eight", Integer.TYPE);
+        attrMap.put("nine", Integer.class);
+        attrMap.put("ten", File.class);
+        attrMap.put("eleven", Boolean.TYPE);
+        attrMap.put("twelve", Boolean.class);
+        attrMap.put("thirteen", Class.class);
+        attrMap.put("fourteen", StringBuffer.class);
+        attrMap.put("fifteen", Character.TYPE);
+        attrMap.put("sixteen", Character.class);
+        attrMap.put("seventeen", Byte.TYPE);
+        attrMap.put("eightteen", Short.TYPE);
+        attrMap.put("nineteen", Double.TYPE);
+
+        /*
+         * JUnit 3.7 adds a getName method to TestCase - so we now
+         * have a name attribute in IntrospectionHelperTest if we run
+         * under JUnit 3.7 but not in earlier versions.
+         *
+         * Simply add it here and remove it after the tests.
+         */
+        attrMap.put("name", String.class);
+
+        return attrMap;
+    }
+
+    public void testGetAttributes() {
+        Map attrMap = getExpectedAttributes();
+        Enumeration e = ih.getAttributes();
+        while (e.hasMoreElements()) {
+            String name = (String) e.nextElement();
+            Class expect = (Class) attrMap.get(name);
+            assertNotNull("Support for "+name+" in IntrospectionHelperTest?",
+                          expect);
+            assertEquals("Type of "+name, expect, ih.getAttributeType(name));
+            attrMap.remove(name);
+        }
+        attrMap.remove("name");
+        assertTrue("Found all", attrMap.isEmpty());
+    }
+
+    public void testGetAttributeMap() {
+        Map attrMap = getExpectedAttributes();
+        Map actualMap = ih.getAttributeMap();
+        for (Iterator i = actualMap.entrySet().iterator(); i.hasNext();) {
+            Map.Entry entry = (Map.Entry) i.next();
+            String attrName = (String) entry.getKey();
+            Class attrClass = (Class) attrMap.get(attrName);
+            assertNotNull("Support for " + attrName +
+                          " in IntrospectionHelperTest?", attrClass);
+            assertEquals("Type of " + attrName, attrClass, entry.getValue());
+            attrMap.remove(attrName);
+        }
+        attrMap.remove("name");
+        assertTrue("Found all", attrMap.isEmpty());
+
+        // Check it's a read-only map.
+        try {
+            actualMap.clear();
+        } catch (UnsupportedOperationException e) {}
+    }
+
+    public void testGetAttributeMethod() {
+        assertAttrMethod("seven", "setSeven", String.class,
+                         "2", "3");
+        assertAttrMethod("eight", "setEight", Integer.TYPE,
+                         new Integer(2), new Integer(3));
+        assertAttrMethod("nine", "setNine", Integer.class,
+                         new Integer(2), new Integer(3));
+        assertAttrMethod("ten", "setTen", File.class,
+                         new File(projectBasedir + 2), new File("toto"));
+        assertAttrMethod("eleven", "setEleven", Boolean.TYPE,
+                         Boolean.FALSE, Boolean.TRUE);
+        assertAttrMethod("twelve", "setTwelve", Boolean.class,
+                         Boolean.FALSE, Boolean.TRUE);
+        assertAttrMethod("thirteen", "setThirteen", Class.class,
+                         Project.class, Map.class);
+        assertAttrMethod("fourteen", "setFourteen", StringBuffer.class,
+                         new StringBuffer("2"), new StringBuffer("3"));
+        assertAttrMethod("fifteen", "setFifteen", Character.TYPE,
+                         new Character('a'), new Character('b'));
+        assertAttrMethod("sixteen", "setSixteen", Character.class,
+                         new Character('a'), new Character('b'));
+        assertAttrMethod("seventeen", "setSeventeen", Byte.TYPE,
+                         new Byte((byte)17), new Byte((byte)10));
+        assertAttrMethod("eightteen", "setEightteen", Short.TYPE,
+                         new Short((short)18), new Short((short)10));
+        assertAttrMethod("nineteen", "setNineteen", Double.TYPE,
+                         new Double(19), new Double((short)10));
+
+        try {
+            assertAttrMethod("onehundred", null, null, null, null);
+            fail("Should have raised a BuildException!");
+        } catch (BuildException e) {}
+    }
+
+    private void assertAttrMethod(String attrName, String methodName,
+                                  Class methodArg, Object arg, Object badArg) {
+        Method m = ih.getAttributeMethod(attrName);
+        assertMethod(m, methodName, methodArg, arg, badArg);
+    }
+
+    public int setTwo(String s) {
+        return 0;
+    }
+
+    public void setThree() {}
+
+    public void setFour(String s1, String s2) {}
+
+    public void setFive(String[] s) {}
+
+    public void setSix(Project p) {}
+
+    public void setSeven(String s) {
+        assertEquals("2", s);
+    }
+
+    public void setEight(int i) {
+        assertEquals(2, i);
+    }
+
+    public void setNine(Integer i) {
+        assertEquals(2, i.intValue());
+    }
+
+    public void setTen(File f) {
+        String path = f.getAbsolutePath();
+        if (Os.isFamily("unix") || Os.isFamily("openvms")) {
+            assertEquals(projectBasedir+"2", path);
+        } else if (Os.isFamily("netware")) {
+            assertEquals(projectBasedir+"2", path.toLowerCase(Locale.US));
+        } else {
+            assertEquals(":"+projectBasedir+"2",
+                         path.toLowerCase(Locale.US).substring(1));
+        }
+    }
+
+    public void setEleven(boolean b) {
+        assertTrue(!b);
+    }
+
+    public void setTwelve(Boolean b) {
+        assertTrue(!b.booleanValue());
+    }
+
+    public void setThirteen(Class c) {
+        assertEquals(Project.class, c);
+    }
+
+    public void setFourteen(StringBuffer sb) {
+        assertEquals("2", sb.toString());
+    }
+
+    public void setFifteen(char c) {
+        assertEquals(c, 'a');
+    }
+
+    public void setSixteen(Character c) {
+        assertEquals(c.charValue(), 'a');
+    }
+
+    public void setSeventeen(byte b) {
+        assertEquals(17, b);
+    }
+
+    public void setEightteen(short s) {
+        assertEquals(18, s);
+    }
+
+    public void setNineteen(double d) {
+        double diff = d - 19;
+        assertTrue("Expected 19, received " + d, diff > -1e-6 && diff < 1e-6);
+    }
+
+    public void testGetExtensionPoints() {
+        List extensions = ih.getExtensionPoints();
+        final int adders = 2;
+        assertEquals("extension count", adders, extensions.size());
+
+        // this original test assumed something about the order of
+        // add(Number) and addConfigured(Map) returned by reflection.
+        // Unfortunately the assumption doesn't hold for all VMs
+        // (failed on MacOS X using JDK 1.4.2_05) and the possible
+        // combinatorics are too hard to check.  We really only want
+        // to ensure that the more derived Hashtable can be found
+        // before Map.
+//        assertExtMethod(extensions.get(0), "add", Number.class,
+//                        new Integer(2), new Integer(3));
+
+        // addConfigured(Hashtable) should come before addConfigured(Map)
+        assertExtMethod(extensions.get(adders - 2),
+                        "addConfigured", Hashtable.class,
+                        makeTable("key", "value"), makeTable("1", "2"));
+
+        assertExtMethod(extensions.get(adders - 1), "addConfigured", Map.class,
+                        new HashMap(), makeTable("1", "2"));
+    }
+
+    private void assertExtMethod(Object mo, String methodName, Class methodArg,
+                                 Object arg, Object badArg) {
+        assertMethod((Method) mo, methodName, methodArg, arg, badArg);
+    }
+
+    private void assertMethod(Method m, String methodName, Class methodArg,
+                              Object arg, Object badArg) {
+        assertEquals("Method name", methodName, m.getName());
+        assertEquals("Return type", Void.TYPE, m.getReturnType());
+        Class[] args = m.getParameterTypes();
+        assertEquals("Arg Count", 1, args.length);
+        assertEquals("Arg Type", methodArg, args[0]);
+
+        try {
+            m.invoke(this, new Object[] { arg });
+        } catch (IllegalAccessException e) {
+            throw new BuildException(e);
+        } catch (InvocationTargetException e) {
+            throw new BuildException(e);
+        }
+
+        try {
+            m.invoke(this, new Object[] { badArg });
+            fail("Should have raised an assertion exception");
+        } catch (IllegalAccessException e) {
+            throw new BuildException(e);
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            assertTrue(t instanceof junit.framework.AssertionFailedError);
+        }
+    }
+
+    public List add(List l) {
+        // INVALID extension point
+        return null;
+    }
+
+    // see comments in testGetExtensionPoints
+//    public void add(Number n) {
+//        // Valid extension point
+//        assertEquals(2, n.intValue());
+//    }
+
+    public void add(List l, int i) {
+        // INVALID extension point
+    }
+
+    public void addConfigured(Map m) {
+        // Valid extension point
+        assertTrue(m.size() == 0);
+    }
+
+    public void addConfigured(Hashtable h) {
+        // Valid extension point, more derived than Map above, but *after* it!
+        assertEquals(makeTable("key", "value"), h);
+    }
+
+    private Hashtable makeTable(Object key, Object value) {
+        Hashtable table = new Hashtable();
+        table.put(key, value);
+        return table;
+    }
+
+} // IntrospectionHelperTest
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/LoaderRefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/LoaderRefTest.java
new file mode 100644
index 0000000..946c59c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/LoaderRefTest.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class LoaderRefTest extends BuildFileTest {
+
+    public LoaderRefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/loaderref/loaderref.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    // override allowed on <available>
+    public void testBadRef() {
+        expectBuildExceptionContaining("testbadref", "Should fail due to ref "
+            + "not being a class loader", "does not reference a class loader");
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/LocationTest.java b/trunk/src/tests/junit/org/apache/tools/ant/LocationTest.java
new file mode 100644
index 0000000..b8c9af0
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/LocationTest.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.taskdefs.ConditionTask;
+import org.apache.tools.ant.taskdefs.Echo;
+import org.apache.tools.ant.types.FileSet;
+
+public class LocationTest extends BuildFileTest {
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/location.xml");
+    }
+
+    public void testPlainTask() {
+        executeTarget("testPlainTask");
+        Echo e = (Echo) getProject().getReference("echo");
+        assertFalse(e.getLocation() == Location.UNKNOWN_LOCATION);
+        assertFalse(e.getLocation().getLineNumber() == 0);
+    }
+
+    public void testStandaloneType() {
+        executeTarget("testStandaloneType");
+        Echo e = (Echo) getProject().getReference("echo2");
+        FileSet f = (FileSet) getProject().getReference("fs");
+        assertFalse(f.getLocation() == Location.UNKNOWN_LOCATION);
+        assertEquals(e.getLocation().getLineNumber() + 1,
+                     f.getLocation().getLineNumber());
+    }
+
+    public void testConditionTask() {
+        executeTarget("testConditionTask");
+        TaskAdapter ta = (TaskAdapter) getProject().getReference("cond");
+        ConditionTask c = (ConditionTask) ta.getProxy();
+        assertFalse(c.getLocation() == Location.UNKNOWN_LOCATION);
+        assertFalse(c.getLocation().getLineNumber() == 0);
+    }
+
+    public void testMacrodefWrappedTask() {
+        executeTarget("testMacrodefWrappedTask");
+        Echo e = (Echo) getProject().getReference("echo3");
+        assertTrue(getLog().indexOf("Line: " 
+                                    + (e.getLocation().getLineNumber() + 1))
+                   > -1);
+    }
+
+    public void testPresetdefWrappedTask() {
+        executeTarget("testPresetdefWrappedTask");
+        Echo e = (Echo) getProject().getReference("echo4");
+        assertTrue(getLog().indexOf("Line: " 
+                                    + (e.getLocation().getLineNumber() + 1))
+                   > -1);
+    }
+
+    public static class EchoLocation extends Task {
+        public void execute() {
+            log("Line: " + getLocation().getLineNumber(), Project.MSG_INFO);
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/MockBuildListener.java b/trunk/src/tests/junit/org/apache/tools/ant/MockBuildListener.java
new file mode 100644
index 0000000..f68a828
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/MockBuildListener.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.util.Vector;
+
+import junit.framework.Assert;
+
+public class MockBuildListener extends Assert implements BuildListener {
+
+    private final Vector buffer = new Vector();
+    private final Project project;
+
+    public MockBuildListener(final Project project) {
+        this.project = project;
+    }
+
+    public void buildStarted(BuildEvent event) {}
+    public void buildFinished(BuildEvent event) {}
+    public void targetStarted(BuildEvent event) {}
+    public void targetFinished(BuildEvent event) {}
+    public void taskStarted(BuildEvent event) {}
+    public void taskFinished(BuildEvent event) {}
+
+    public void messageLogged(final BuildEvent actual) {
+        if(actual.getPriority()==Project.MSG_DEBUG)
+            return;
+        assertTrue("unexpected messageLogged: "+actual.getMessage(), !buffer.isEmpty());
+        assertEquals("unexpected project ", project, actual.getProject());
+
+        BuildEvent expected = (BuildEvent) buffer.elementAt(0);
+        buffer.removeElementAt(0);
+        assertEquals("unexpected messageLogged ", expected.getMessage(), actual.getMessage());
+        assertEquals("unexpected priority ", expected.getPriority(), actual.getPriority());
+    }
+
+    public void assertEmpty() {
+        assertTrue("MockBuildListener is not empty", buffer.isEmpty());
+    }
+
+    public void addBuildEvent(final String message, final int priority) {
+        final BuildEvent be = new BuildEvent(project);
+        be.setMessage(message, priority);
+        buffer.addElement(be);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/PickOneTask.java b/trunk/src/tests/junit/org/apache/tools/ant/PickOneTask.java
new file mode 100644
index 0000000..560194b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/PickOneTask.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.dispatch.DispatchTask;
+
+public class PickOneTask extends DispatchTask {
+    public void list() {
+        throw new BuildException("list");
+    }
+
+    public void show() {
+        throw new BuildException("show");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/ProjectComponentTest.java b/trunk/src/tests/junit/org/apache/tools/ant/ProjectComponentTest.java
new file mode 100644
index 0000000..e195b4e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/ProjectComponentTest.java
@@ -0,0 +1,47 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import junit.framework.TestCase;
+
+public class ProjectComponentTest extends TestCase {
+
+    public ProjectComponentTest(String name) {
+        super(name);
+    }
+
+    public void testClone() throws CloneNotSupportedException {
+        Project expectedProject = new Project();
+        Location expectedLocation = new Location("foo");
+        String expectedDescription = "bar";
+
+        // use an anonymous subclass since ProjectComponent is abstract
+        ProjectComponent pc = new ProjectComponent() {
+            };
+        pc.setProject(expectedProject);
+        pc.setLocation(expectedLocation);
+        pc.setDescription(expectedDescription);
+
+        ProjectComponent cloned = (ProjectComponent) pc.clone();
+        assertNotSame(pc, cloned);
+        assertSame(cloned.getProject(), expectedProject);
+        assertSame(cloned.getLocation(), expectedLocation);
+        assertSame(cloned.getDescription(), expectedDescription);
+    }
+}
\ No newline at end of file
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/ProjectTest.java b/trunk/src/tests/junit/org/apache/tools/ant/ProjectTest.java
new file mode 100644
index 0000000..eaf8c50
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/ProjectTest.java
@@ -0,0 +1,297 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import org.apache.tools.ant.input.DefaultInputHandler;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.input.PropertyFileInputHandler;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.*;
+
+import java.io.File;
+import junit.framework.TestCase;
+
+
+/**
+ * Very limited test class for Project. Waiting to be extended.
+ *
+ */
+public class ProjectTest extends TestCase {
+
+    private Project p;
+    private String root;
+    private MockBuildListener mbl;
+
+    public ProjectTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        p = new Project();
+        p.init();
+        root = new File(File.separator).getAbsolutePath().toUpperCase();
+        mbl = new MockBuildListener(p);
+    }
+
+    public void testDataTypes() throws BuildException {
+        assertNull("dummy is not a known data type",
+                   p.createDataType("dummy"));
+        Object o = p.createDataType("fileset");
+        assertNotNull("fileset is a known type", o);
+        assertTrue("fileset creates FileSet", o instanceof FileSet);
+        assertTrue("PatternSet",
+               p.createDataType("patternset") instanceof PatternSet);
+        assertTrue("Path", p.createDataType("path") instanceof Path);
+    }
+
+    /**
+     * This test has been a starting point for moving the code to FileUtils.
+     */
+    public void testResolveFile() {
+        if (Os.isFamily("netware") || Os.isFamily("dos")) {
+            assertEqualsIgnoreDriveCase(localize(File.separator),
+                p.resolveFile("/", null).getPath());
+            assertEqualsIgnoreDriveCase(localize(File.separator),
+                p.resolveFile("\\", null).getPath());
+            /*
+             * throw in drive letters
+             */
+            String driveSpec = "C:";
+            String driveSpecLower = "c:";
+            
+            assertEqualsIgnoreDriveCase(driveSpecLower + "\\",
+                         p.resolveFile(driveSpec + "/", null).getPath());
+            assertEqualsIgnoreDriveCase(driveSpecLower + "\\",
+                         p.resolveFile(driveSpec + "\\", null).getPath());
+            assertEqualsIgnoreDriveCase(driveSpecLower + "\\",
+                         p.resolveFile(driveSpecLower + "/", null).getPath());
+            assertEqualsIgnoreDriveCase(driveSpecLower + "\\",
+                         p.resolveFile(driveSpecLower + "\\", null).getPath());
+            /*
+             * promised to eliminate consecutive slashes after drive letter.
+             */
+            assertEqualsIgnoreDriveCase(driveSpec + "\\",
+                         p.resolveFile(driveSpec + "/////", null).getPath());
+            assertEqualsIgnoreDriveCase(driveSpec + "\\",
+                         p.resolveFile(driveSpec + "\\\\\\\\\\\\", null).getPath());
+        } else {
+            /*
+             * Start with simple absolute file names.
+             */
+            assertEquals(File.separator,
+                         p.resolveFile("/", null).getPath());
+            assertEquals(File.separator,
+                         p.resolveFile("\\", null).getPath());
+            /*
+             * drive letters are not used, just to be considered as normal
+             * part of a name
+             */
+            String driveSpec = "C:";
+            String udir = System.getProperty("user.dir") + File.separatorChar;
+            assertEquals(udir + driveSpec,
+                         p.resolveFile(driveSpec + "/", null).getPath());
+            assertEquals(udir + driveSpec,
+                         p.resolveFile(driveSpec + "\\", null).getPath());
+            String driveSpecLower = "c:";
+            assertEquals(udir + driveSpecLower,
+                         p.resolveFile(driveSpecLower + "/", null).getPath());
+            assertEquals(udir + driveSpecLower,
+                         p.resolveFile(driveSpecLower + "\\", null).getPath());
+        }
+        /*
+         * Now test some relative file name magic.
+         */
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("./4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile(".\\4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("./.\\4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("../3/4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("..\\3\\4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("../../5/.././2/./3/6/../4", new File(localize("/1/2/3"))).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     p.resolveFile("..\\../5/..\\./2/./3/6\\../4", new File(localize("/1/2/3"))).getPath());
+
+    }
+
+    /**
+     * adapt file separators to local conventions
+     */
+    private String localize(String path) {
+        path = root + path.substring(1);
+        return path.replace('\\', File.separatorChar).replace('/', File.separatorChar);
+    }
+
+    /**
+     * convenience method
+     * the drive letter is in lower case under cygwin
+     * calling this method allows tests where FileUtils.normalize
+     * is called via resolveFile to pass under cygwin
+     */
+    private void assertEqualsIgnoreDriveCase(String s1, String s2) {
+        if ((Os.isFamily("dos") || Os.isFamily("netware"))
+            && s1.length() >= 1 && s2.length() >= 1) {
+            StringBuffer sb1 = new StringBuffer(s1);
+            StringBuffer sb2 = new StringBuffer(s2);
+            sb1.setCharAt(0, Character.toUpperCase(s1.charAt(0)));
+            sb2.setCharAt(0, Character.toUpperCase(s2.charAt(0)));
+            assertEquals(sb1.toString(), sb2.toString());
+        } else {
+            assertEquals(s1, s2);
+        }
+    }
+
+    private void assertTaskDefFails(final Class taskClass,
+                                       final String message) {
+        final String dummyName = "testTaskDefinitionDummy";
+        try {
+            mbl.addBuildEvent(message, Project.MSG_ERR);
+            p.addTaskDefinition(dummyName, taskClass);
+            fail("expected BuildException(\""+message+"\", Project.MSG_ERR) when adding task " + taskClass);
+        }
+        catch(BuildException e) {
+            assertEquals(message, e.getMessage());
+            mbl.assertEmpty();
+            assertTrue(!p.getTaskDefinitions().containsKey(dummyName));
+        }
+    }
+
+    public void testAddTaskDefinition() {
+        p.addBuildListener(mbl);
+
+        p.addTaskDefinition("Ok", DummyTaskOk.class);
+        assertEquals(DummyTaskOk.class, p.getTaskDefinitions().get("Ok"));
+        p.addTaskDefinition("OkNonTask", DummyTaskOkNonTask.class);
+        assertEquals(DummyTaskOkNonTask.class, p.getTaskDefinitions().get("OkNonTask"));
+        mbl.assertEmpty();
+
+        assertTaskDefFails(DummyTaskPrivate.class,   DummyTaskPrivate.class   + " is not public");
+
+        assertTaskDefFails(DummyTaskProtected.class,
+                           DummyTaskProtected.class + " is not public");
+
+        assertTaskDefFails(DummyTaskPackage.class,   DummyTaskPackage.class   + " is not public");
+
+        assertTaskDefFails(DummyTaskAbstract.class,  DummyTaskAbstract.class  + " is abstract");
+        assertTaskDefFails(DummyTaskInterface.class, DummyTaskInterface.class + " is abstract");
+
+        assertTaskDefFails(DummyTaskWithoutDefaultConstructor.class, "No public no-arg constructor in " + DummyTaskWithoutDefaultConstructor.class);
+        assertTaskDefFails(DummyTaskWithoutPublicConstructor.class,  "No public no-arg constructor in " + DummyTaskWithoutPublicConstructor.class);
+
+        assertTaskDefFails(DummyTaskWithoutExecute.class,       "No public execute() in " + DummyTaskWithoutExecute.class);
+        assertTaskDefFails(DummyTaskWithNonPublicExecute.class, "No public execute() in " + DummyTaskWithNonPublicExecute.class);
+
+        mbl.addBuildEvent("return type of execute() should be void but was \"int\" in " + DummyTaskWithNonVoidExecute.class, Project.MSG_WARN);
+        p.addTaskDefinition("NonVoidExecute", DummyTaskWithNonVoidExecute.class);
+        mbl.assertEmpty();
+        assertEquals(DummyTaskWithNonVoidExecute.class, p.getTaskDefinitions().get("NonVoidExecute"));
+    }
+
+    public void testInputHandler() {
+        InputHandler ih = p.getInputHandler();
+        assertNotNull(ih);
+        assertTrue(ih instanceof DefaultInputHandler);
+        InputHandler pfih = new PropertyFileInputHandler();
+        p.setInputHandler(pfih);
+        assertSame(pfih, p.getInputHandler());
+    }
+
+    public void testTaskDefinitionContainsKey() {
+        assertTrue(p.getTaskDefinitions().containsKey("echo"));
+    }
+
+    public void testTaskDefinitionContains() {
+        assertTrue(p.getTaskDefinitions().contains(org.apache.tools.ant.taskdefs.Echo.class));
+    }
+
+    public void testDuplicateTargets() {
+        // fail, because buildfile contains two targets with the same name
+        try {
+            BFT bft = new BFT("", "core/duplicate-target.xml");
+        } catch (BuildException ex) {
+            assertEquals("specific message",
+                         "Duplicate target 'twice'",
+                         ex.getMessage());
+            return;
+        }
+        fail("Should throw BuildException about duplicate target");
+    }
+
+    public void testDuplicateTargetsImport() {
+        // overriding target from imported buildfile is allowed
+        BFT bft = new BFT("", "core/duplicate-target2.xml");
+        bft.expectLog("once", "once from buildfile");
+    }
+
+
+    private class DummyTaskPrivate extends Task {
+        public DummyTaskPrivate() {}
+        public void execute() {}
+    }
+
+    protected class DummyTaskProtected extends Task {
+        public DummyTaskProtected() {}
+        public void execute() {}
+    }
+
+    private class BFT extends org.apache.tools.ant.BuildFileTest {
+        BFT(String name, String buildfile) {
+            super(name);
+            this.buildfile = buildfile;
+            setUp();
+        }
+
+        // avoid multiple configurations
+        boolean isConfigured = false;
+
+        // the buildfile to use
+        String buildfile = "";
+
+        public void setUp() {
+            if (!isConfigured) {
+                configureProject("src/etc/testcases/"+buildfile);
+                isConfigured = true;
+            }
+        }
+
+        public void tearDown() { }
+
+        // call a target
+        public void doTarget(String target) {
+            if (!isConfigured) setUp();
+            executeTarget(target);
+        }
+
+        public org.apache.tools.ant.Project getProject() {
+            return super.getProject();
+        }
+    }//class-BFT
+
+}
+
+class DummyTaskPackage extends Task {
+    public DummyTaskPackage() {}
+    public void execute() {}
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/PropertyExpansionTest.java b/trunk/src/tests/junit/org/apache/tools/ant/PropertyExpansionTest.java
new file mode 100644
index 0000000..718d843
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/PropertyExpansionTest.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant;
+
+/**
+ * class to look at how we expand properties
+ */
+public class PropertyExpansionTest extends BuildFileTest {
+
+
+    public PropertyExpansionTest(String name) {
+        super(name);
+    }
+
+    /**
+     * we bind to an existing test file because we are too lazy to write our
+     * own, and we don't really care what it is
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/core/immutable.xml");
+    }
+
+    /**
+     * run through the test cases of expansion
+     */
+    public void testPropertyExpansion() {
+        assertExpandsTo("","");
+        assertExpandsTo("$","$");
+        assertExpandsTo("$$-","$-");
+        assertExpandsTo("$$","$");
+        project.setProperty("expanded","EXPANDED");
+        assertExpandsTo("a${expanded}b","aEXPANDEDb");
+        assertExpandsTo("${expanded}${expanded}","EXPANDEDEXPANDED");
+        assertExpandsTo("$$$","$$");
+        assertExpandsTo("$$$$-","$$-");
+        assertExpandsTo("","");
+        assertExpandsTo("Class$$subclass","Class$subclass");
+    }
+
+    /**
+     * new things we want
+     */
+    public void testDollarPassthru() {
+        assertExpandsTo("$-","$-");
+        assertExpandsTo("Class$subclass","Class$subclass");
+        assertExpandsTo("$$$-","$$-");
+        assertExpandsTo("$$$$$","$$$");
+        assertExpandsTo("${unassigned.property}","${unassigned.property}");
+        assertExpandsTo("a$b","a$b");
+        assertExpandsTo("$}}","$}}");
+    }
+
+
+    /**
+     * old things we dont want; not a test no more
+     */
+    public void oldtestQuirkyLegacyBehavior() {
+        assertExpandsTo("Class$subclass","Classsubclass");
+        assertExpandsTo("$$$-","$-");
+        assertExpandsTo("a$b","ab");
+        assertExpandsTo("$}}","}}");
+    }
+
+    /**
+     * little helper method to validate stuff
+     */
+    private void assertExpandsTo(String source,String expected) {
+        String actual=project.replaceProperties(source);
+        assertEquals(source,expected,actual);
+    }
+
+//end class
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/TaskContainerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/TaskContainerTest.java
new file mode 100644
index 0000000..e582f13
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/TaskContainerTest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+public class TaskContainerTest extends BuildFileTest {
+
+    public TaskContainerTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/core/taskcontainer.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testPropertyExpansion() {
+        executeTarget("testPropertyExpansion");
+        assertTrue("attribute worked",
+                   getLog().indexOf("As attribute: it worked") > -1);
+        assertTrue("nested text worked",
+                   getLog().indexOf("As nested text: it worked") > -1);
+    }
+
+    public void testTaskdef() {
+        executeTarget("testTaskdef");
+        assertTrue("attribute worked",
+                   getLog().indexOf("As attribute: it worked") > -1);
+        assertTrue("nested text worked",
+                   getLog().indexOf("As nested text: it worked") > -1);
+        assertTrue("nested text worked",
+                   getLog().indexOf("As nested task: it worked") > -1);
+    }
+
+    public void testCaseInsensitive() {
+        executeTarget("testCaseInsensitive");
+        assertTrue("works outside of container",
+                   getLog().indexOf("hello ") > -1);
+        assertTrue("works inside of container",
+                   getLog().indexOf("world") > -1);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/TopLevelTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/TopLevelTaskTest.java
new file mode 100644
index 0000000..1aceaa2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/TopLevelTaskTest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+// This test will fail with embed, or if top-level is moved out of
+// dependency - as 'echo' happens as part of configureProject stage.
+
+/**
+ * Tests for builds with tasks at the top level
+ *
+ * @since Ant 1.6
+ */
+public class TopLevelTaskTest extends BuildFileTest {
+
+    public TopLevelTaskTest(String name) {
+        super(name);
+    }
+
+    public void testNoTarget() {
+        configureProject("src/etc/testcases/core/topleveltasks/notarget.xml");
+        expectLog("", "Called");
+    }
+
+    public void testCalledFromTopLevelAnt() {
+        configureProject("src/etc/testcases/core/topleveltasks/toplevelant.xml");
+        expectLog("", "Called");
+    }
+
+    public void testCalledFromTargetLevelAnt() {
+        configureProject("src/etc/testcases/core/topleveltasks/targetlevelant.xml");
+        expectLog("foo", "Called");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/UnknownElementTest.java b/trunk/src/tests/junit/org/apache/tools/ant/UnknownElementTest.java
new file mode 100644
index 0000000..43caea0
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/UnknownElementTest.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+public class UnknownElementTest extends BuildFileTest {
+    public void setUp() {
+        configureProject("src/etc/testcases/core/unknownelement.xml");
+    }
+    public void testMaybeConfigure() {
+        // make sure we do not get a NPE
+        executeTarget("testMaybeConfigure");
+    }
+
+    public static class Child extends Task {
+        Parent parent;
+        public void injectParent(Parent parent) {
+            this.parent = parent;
+        }
+        public void execute() {
+            parent.fromChild();
+        }
+    }
+
+    public static class Parent extends Task implements TaskContainer {
+        List children = new ArrayList();
+        public void addTask(Task t) {
+            children.add(t);
+        }
+
+        public void fromChild() {
+            log("fromchild");
+        }
+        
+        public void execute() {
+            for (Iterator i = children.iterator(); i.hasNext();) {
+                UnknownElement el = (UnknownElement) i.next();
+                el.maybeConfigure();
+                Child child = (Child) el.getRealThing();
+                child.injectParent(this);
+                child.perform();
+            }
+        }
+    }
+}
+
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/ConcatFilterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/ConcatFilterTest.java
new file mode 100644
index 0000000..46060bb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/ConcatFilterTest.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * JUnit Testcases for ConcatReader
+ */
+public class ConcatFilterTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private static final String lSep = StringUtils.LINE_SEP;
+
+    private static final String FILE_PREPEND_WITH =
+          "this-should-be-the-first-line" + lSep
+        + "Line  1" + lSep
+        + "Line  2" + lSep
+        + "Line  3" + lSep
+        + "Line  4" + lSep
+    ;
+
+    private static final String FILE_PREPEND =
+          "Line  1" + lSep
+        + "Line  2" + lSep
+        + "Line  3" + lSep
+        + "Line  4" + lSep
+        + "Line  5" + lSep
+    ;
+
+    private static final String FILE_APPEND_WITH =
+          "Line 57" + lSep
+        + "Line 58" + lSep
+        + "Line 59" + lSep
+        + "Line 60" + lSep
+        + "this-should-be-the-last-line" + lSep
+    ;
+
+    private static final String FILE_APPEND =
+          "Line 56" + lSep
+        + "Line 57" + lSep
+        + "Line 58" + lSep
+        + "Line 59" + lSep
+        + "Line 60" + lSep
+    ;
+
+
+    public ConcatFilterTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/concat.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testFilterReaderNoArgs() throws IOException {
+        executeTarget("testFilterReaderNoArgs");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"input/concatfilter.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(), "result/concat.FilterReaderNoArgs.test");
+        assertTrue("testFilterReaderNoArgs: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testFilterReaderBefore() {
+        doTest("testFilterReaderPrepend", FILE_PREPEND_WITH, FILE_APPEND);
+    }
+
+    public void testFilterReaderAfter() {
+        doTest("testFilterReaderAppend", FILE_PREPEND, FILE_APPEND_WITH);
+    }
+
+    public void testFilterReaderBeforeAfter() {
+        doTest("testFilterReaderPrependAppend", FILE_PREPEND_WITH, FILE_APPEND_WITH);
+    }
+
+    public void testConcatFilter() {
+        doTest("testConcatFilter", FILE_PREPEND, FILE_APPEND);
+    }
+
+    public void testConcatFilterBefore() {
+        doTest("testConcatFilterPrepend", FILE_PREPEND_WITH, FILE_APPEND);
+    }
+
+    public void testConcatFilterAfter() {
+        doTest("testConcatFilterAppend", FILE_PREPEND, FILE_APPEND_WITH);
+    }
+
+    public void testConcatFilterBeforeAfter() {
+        doTest("testConcatFilterPrependAppend", FILE_PREPEND_WITH, FILE_APPEND_WITH);
+    }
+
+
+    /**
+     * Executes a target and checks the beginning and the ending of a file.
+     * The filename depends on the target name: target name <i>testHelloWorld</i>
+     * will search for a file <i>result/concat.HelloWorld.test</i>.
+     * @param target The target to invoke
+     * @param expectedStart The string which should be at the beginning of the file
+     * @param expectedEnd The string which should be at the end of the file
+     */
+    protected void doTest(String target, String expectedStart, String expectedEnd) {
+        executeTarget(target);
+        String resultContent = read("result/concat." + target.substring(4) + ".test");
+        assertTrue("First 5 lines differs.", resultContent.startsWith(expectedStart));
+        assertTrue("Last 5 lines differs.", resultContent.endsWith(expectedEnd));
+    }
+
+
+    /**
+     * Wrapper for FileUtils.readFully().
+     * Additionally it resolves the filename according the the projects basedir
+     * and closes the used reader.
+     * @param filename The name of the file to read
+     * @return the content of the file or <i>null</i> if something goes wrong
+     */
+    protected String read(String filename) {
+        String content = null;
+        try {
+            File file = FILE_UTILS.resolveFile(getProject().getBaseDir(), filename);
+            java.io.FileReader rdr = new java.io.FileReader(file);
+            content = FileUtils.readFully(rdr);
+            rdr.close();
+            rdr = null;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return content;
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/DynamicFilterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/DynamicFilterTest.java
new file mode 100644
index 0000000..6de81c6
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/DynamicFilterTest.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.Reader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class DynamicFilterTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    public DynamicFilterTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/dynamicfilter.xml");
+        executeTarget("init");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+    public void testCustomFilter() throws IOException {
+        expectFileContains("dynamicfilter", "result/dynamicfilter",
+                           "hellO wOrld");
+    }
+
+    // ------------------------------------------------------
+    //   Helper methods
+    // -----------------------------------------------------
+
+    private String getFileString(String filename)
+        throws IOException
+    {
+        Reader r = null;
+        try {
+            r = new FileReader(FILE_UTILS.resolveFile(getProject().getBaseDir(), filename));
+            return  FileUtils.readFully(r);
+        }
+        finally {
+            FileUtils.close(r);
+        }
+
+    }
+
+    private void expectFileContains(String name, String contains)
+        throws IOException
+    {
+        String content = getFileString(name);
+        assertTrue(
+            "expecting file " + name + " to contain " + contains +
+            " but got " + content, content.indexOf(contains) > -1);
+    }
+
+    private void expectFileContains(
+        String target, String name, String contains)
+        throws IOException
+    {
+        executeTarget(target);
+        expectFileContains(name, contains);
+    }
+
+    public static class CustomFilter implements ChainableReader {
+        char replace = 'x';
+        char with    = 'y';
+
+        public void setReplace(char replace) {
+            this.replace = replace;
+        }
+
+        public void setWith(char with) {
+            this.with = with;
+        }
+
+        public Reader chain(final Reader rdr) {
+            return new BaseFilterReader(rdr) {
+                public int read()
+                    throws IOException
+                {
+                    int c = in.read();
+                    if (c == replace)
+                        return with;
+                    else
+                        return c;
+                }
+            };
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/EscapeUnicodeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/EscapeUnicodeTest.java
new file mode 100644
index 0000000..b054699
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/EscapeUnicodeTest.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class EscapeUnicodeTest extends BuildFileTest {
+    
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public EscapeUnicodeTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testEscapeUnicode() throws IOException {
+        executeTarget("testEscapeUnicode");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(), "expected/escapeunicode.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(), "result/escapeunicode.test");
+        assertTrue(FILE_UTILS.contentEquals(expected, result));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/HeadTailTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/HeadTailTest.java
new file mode 100644
index 0000000..4bff517
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/HeadTailTest.java
@@ -0,0 +1,131 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/** JUnit Testcases for TailFilter and HeadFilter
+ */
+/* I wrote the testcases in one java file because I want also to test the
+ * combined behaviour (see end of the class).
+*/
+public class HeadTailTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    public HeadTailTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/head-tail.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testHead() throws IOException {
+        executeTarget("testHead");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(), "expected/head-tail.head.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(), "result/head-tail.head.test");
+        assertTrue("testHead: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testHeadLines() throws IOException {
+        executeTarget("testHeadLines");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(), "expected/head-tail.headLines.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(), "result/head-tail.headLines.test");
+        assertTrue("testHeadLines: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testHeadSkip() throws IOException {
+        executeTarget("testHeadSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.headSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.headSkip.test");
+        assertTrue("testHeadSkip: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testHeadLinesSkip() throws IOException {
+        executeTarget("testHeadLinesSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.headLinesSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.headLinesSkip.test");
+        assertTrue("testHeadLinesSkip: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testFilterReaderHeadLinesSkip() throws IOException {
+        executeTarget("testFilterReaderHeadLinesSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),
+            "expected/head-tail.headLinesSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),
+            "result/head-tail.filterReaderHeadLinesSkip.test");
+        assertTrue("testFilterReaderHeadLinesSkip: Result not like expected",
+                   FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testTail() throws IOException {
+        executeTarget("testTail");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.tail.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.tail.test");
+        assertTrue("testTail: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testTailLines() throws IOException {
+        executeTarget("testTailLines");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.tailLines.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.tailLines.test");
+        assertTrue("testTailLines: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testTailSkip() throws IOException {
+        executeTarget("testTailSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.tailSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.tailSkip.test");
+        assertTrue("testTailSkip: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testTailLinesSkip() throws IOException {
+        executeTarget("testTailLinesSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.tailLinesSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.tailLinesSkip.test");
+        assertTrue("testTailLinesSkip: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testFilterReaderTailLinesSkip() throws IOException {
+        executeTarget("testFilterReaderTailLinesSkip");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),
+            "expected/head-tail.tailLinesSkip.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),
+            "result/head-tail.filterReaderTailLinesSkip.test");
+        assertTrue("testFilterReaderTailLinesSkip: Result not like expected",
+                   FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testHeadTail() throws IOException {
+        executeTarget("testHeadTail");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/head-tail.headtail.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/head-tail.headtail.test");
+        assertTrue("testHeadTail: Result not like expected", FILE_UTILS.contentEquals(expected, result));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/LineContainsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/LineContainsTest.java
new file mode 100644
index 0000000..fb33364
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/LineContainsTest.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class LineContainsTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    public LineContainsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testLineContains() throws IOException {
+        executeTarget("testLineContains");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/linecontains.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/linecontains.test");
+        assertTrue(FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testNegateLineContains() throws IOException {
+        executeTarget("testNegateLineContains");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/NoNewLineTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/NoNewLineTest.java
new file mode 100644
index 0000000..00df34e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/NoNewLineTest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/** JUnit Testcases for No new line when filterchain used
+ */
+
+
+public class NoNewLineTest extends BuildFileTest {
+
+    public NoNewLineTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testNoAddNewLine() throws IOException {
+        executeTarget("testNoAddNewLine");
+    }
+
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/ReplaceTokensTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/ReplaceTokensTest.java
new file mode 100644
index 0000000..7a42948
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/ReplaceTokensTest.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class ReplaceTokensTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public ReplaceTokensTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testReplaceTokens() throws IOException {
+        executeTarget("testReplaceTokens");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/replacetokens.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/replacetokens.test");
+        assertTrue(FILE_UTILS.contentEquals(expected, result));
+    }
+
+    public void testReplaceTokensPropertyFile() throws IOException {
+        executeTarget("testReplaceTokensPropertyFile");
+        File expected = FILE_UTILS.resolveFile(getProjectDir(), "expected/replacetokens.test");
+        File result = FILE_UTILS.resolveFile(getProjectDir(), "result/replacetokensPropertyFile.test");
+        assertTrue(FILE_UTILS.contentEquals(expected, result));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/StripJavaCommentsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/StripJavaCommentsTest.java
new file mode 100644
index 0000000..c3311c0
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/StripJavaCommentsTest.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class StripJavaCommentsTest extends BuildFileTest {
+    
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public StripJavaCommentsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testStripJavaComments() throws IOException {
+        executeTarget("testStripJavaComments");
+        File expected = FILE_UTILS.resolveFile(getProject().getBaseDir(),"expected/stripjavacomments.test");
+        File result = FILE_UTILS.resolveFile(getProject().getBaseDir(),"result/stripjavacomments.test");
+        assertTrue(FILE_UTILS.contentEquals(expected, result));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/filters/TokenFilterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/filters/TokenFilterTest.java
new file mode 100644
index 0000000..acd944a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/filters/TokenFilterTest.java
@@ -0,0 +1,296 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.Reader;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class TokenFilterTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    public TokenFilterTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/filters/tokenfilter.xml");
+        executeTarget("init");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    /** make sure tokenfilter exists */
+    public void testTokenfilter() throws IOException {
+        executeTarget("tokenfilter");
+    }
+
+    public void testTrimignore() throws IOException {
+        expectLogContaining("trimignore", "Hello-World");
+    }
+
+    public void testStringTokenizer() throws IOException {
+        expectLogContaining(
+            "stringtokenizer", "#This#is#a#number#of#words#");
+    }
+
+    public void testUnixLineOutput() throws IOException {
+        expectFileContains(
+            "unixlineoutput", "result/unixlineoutput",
+            "\nThis\nis\na\nnumber\nof\nwords\n");
+    }
+
+    public void testDosLineOutput() throws IOException {
+        expectFileContains(
+            "doslineoutput", "result/doslineoutput",
+            "\r\nThis\r\nis\r\na\r\nnumber\r\nof\r\nwords\r\n");
+    }
+
+    public void testFileTokenizer() throws IOException {
+        String contents = getFileString(
+            "filetokenizer", "result/filetokenizer");
+        assertStringContains(contents, "   of words");
+        assertStringNotContains(contents, " This is");
+    }
+
+    public void testReplaceString() throws IOException {
+        expectFileContains(
+            "replacestring", "result/replacestring",
+            "this is the moon");
+    }
+
+    public void testReplaceStrings() throws IOException {
+        expectLogContaining("replacestrings", "bar bar bar");
+    }
+
+    public void testContainsString() throws IOException {
+        String contents = getFileString(
+            "containsstring", "result/containsstring");
+        assertStringContains(contents, "this is a line contains foo");
+        assertStringNotContains(contents, "this line does not");
+    }
+
+    public void testReplaceRegex() throws IOException {
+        if (! hasRegex("testReplaceRegex"))
+            return;
+        String contents = getFileString(
+            "replaceregex", "result/replaceregex");
+        assertStringContains(contents, "world world world world");
+        assertStringContains(contents, "dog Cat dog");
+        assertStringContains(contents, "moon Sun Sun");
+        assertStringContains(contents, "found WhiteSpace");
+        assertStringContains(contents, "Found digits [1234]");
+        assertStringNotContains(contents, "This is a line with digits");
+    }
+
+    public void testFilterReplaceRegex() throws IOException {
+        if (! hasRegex("testFilterReplaceRegex"))
+            return;
+        String contents = getFileString(
+            "filterreplaceregex", "result/filterreplaceregex");
+        assertStringContains(contents, "world world world world");
+    }
+
+    public void testHandleDollerMatch() throws IOException {
+        if (! hasRegex("testFilterReplaceRegex"))
+            return;
+        executeTarget("dollermatch");
+    }
+
+    public void testTrimFile() throws IOException {
+        String contents = getFileString(
+            "trimfile", "result/trimfile");
+        assertTrue("no ws at start", contents.startsWith("This is th"));
+        assertTrue("no ws at end", contents.endsWith("second line."));
+        assertStringContains(contents, "  This is the second");
+    }
+
+    public void testTrimFileByLine() throws IOException {
+        String contents = getFileString(
+            "trimfilebyline", "result/trimfilebyline");
+        assertFalse("no ws at start", contents.startsWith("This is th"));
+        assertFalse("no ws at end", contents.endsWith("second line."));
+        assertStringNotContains(contents, "  This is the second");
+        assertStringContains(contents, "file.\nThis is the second");
+    }
+
+    public void testFilterReplaceString() throws IOException {
+        String contents = getFileString(
+            "filterreplacestring", "result/filterreplacestring");
+        assertStringContains(contents, "This is the moon");
+    }
+
+    public void testFilterReplaceStrings() throws IOException {
+        expectLogContaining("filterreplacestrings", "bar bar bar");
+    }
+
+    public void testContainsRegex() throws IOException {
+        if (! hasRegex("testContainsRegex"))
+            return;
+        String contents = getFileString(
+            "containsregex", "result/containsregex");
+        assertStringContains(contents, "hello world");
+        assertStringNotContains(contents, "this is the moon");
+        assertStringContains(contents, "World here");
+    }
+
+    public void testFilterContainsRegex() throws IOException {
+        if (! hasRegex("testFilterContainsRegex"))
+            return;
+        String contents = getFileString(
+            "filtercontainsregex", "result/filtercontainsregex");
+        assertStringContains(contents, "hello world");
+        assertStringNotContains(contents, "this is the moon");
+        assertStringContains(contents, "World here");
+    }
+
+    public void testContainsRegex2() throws IOException {
+        if (! hasRegex("testContainsRegex2"))
+            return;
+        String contents = getFileString(
+            "containsregex2", "result/containsregex2");
+        assertStringContains(contents, "void register_bits();");
+    }
+
+    public void testDeleteCharacters() throws IOException {
+        String contents = getFileString(
+            "deletecharacters", "result/deletechars");
+        assertStringNotContains(contents, "#");
+        assertStringNotContains(contents, "*");
+        assertStringContains(contents, "This is some ");
+    }
+
+    public void testScriptFilter() throws IOException {
+        if (! hasScript("testScriptFilter"))
+            return;
+
+        expectFileContains("scriptfilter", "result/scriptfilter",
+                           "HELLO WORLD");
+    }
+
+
+    public void testScriptFilter2() throws IOException {
+        if (! hasScript("testScriptFilter"))
+            return;
+
+        expectFileContains("scriptfilter2", "result/scriptfilter2",
+                           "HELLO MOON");
+    }
+
+    public void testCustomTokenFilter() throws IOException {
+        expectFileContains("customtokenfilter", "result/custom",
+                           "Hello World");
+    }
+
+    // ------------------------------------------------------
+    //   Helper methods
+    // -----------------------------------------------------
+    private boolean hasScript(String test) {
+        try {
+            executeTarget("hasscript");
+        }
+        catch (Throwable ex) {
+            System.out.println(
+                test + ": skipped - script not present ");
+            return false;
+        }
+        return true;
+    }
+
+    private boolean hasRegex(String test) {
+        try {
+            executeTarget("hasregex");
+            expectFileContains("result/replaceregexp", "bye world");
+        }
+        catch (Throwable ex) {
+            System.out.println(test + ": skipped - regex not present "
+                               + ex);
+            return false;
+        }
+        return true;
+    }
+
+    private void assertStringContains(String string, String contains) {
+        assertTrue("[" + string + "] does not contain [" + contains +"]",
+                   string.indexOf(contains) > -1);
+    }
+
+    private void assertStringNotContains(String string, String contains) {
+        assertTrue("[" + string + "] does contain [" + contains +"]",
+                   string.indexOf(contains) == -1);
+    }
+
+    private String getFileString(String filename)
+        throws IOException
+    {
+        Reader r = null;
+        try {
+            r = new FileReader(FILE_UTILS.resolveFile(getProject().getBaseDir(),filename));
+            return  FileUtils.readFully(r);
+        }
+        finally {
+            FileUtils.close(r);
+        }
+
+    }
+
+    private String getFileString(String target, String filename)
+        throws IOException
+    {
+        executeTarget(target);
+        return getFileString(filename);
+    }
+
+    private void expectFileContains(String name, String contains)
+        throws IOException
+    {
+        String content = getFileString(name);
+        assertTrue(
+            "expecting file " + name + " to contain " + contains +
+            " but got " + content, content.indexOf(contains) > -1);
+    }
+
+    private void expectFileContains(
+        String target, String name, String contains)
+        throws IOException
+    {
+        executeTarget(target);
+        expectFileContains(name, contains);
+    }
+
+    public static class Capitalize
+        implements TokenFilter.Filter
+    {
+        public String filter(String token) {
+            if (token.length() == 0)
+                return token;
+            return token.substring(0, 1).toUpperCase() +
+                token.substring(1);
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/launch/LocatorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/launch/LocatorTest.java
new file mode 100644
index 0000000..dc093a7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/launch/LocatorTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.launch;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/** Test the locator in the ant-launch JAR */
+public class LocatorTest extends TestCase {
+    private boolean windows;
+    private boolean unix;
+    private static final String LAUNCHER_JAR = "//morzine/slo/Java/Apache/ant/lib/ant-launcher.jar";
+    private static final String SHARED_JAR_URI = "jar:file:"+ LAUNCHER_JAR +"!/org/apache/tools/ant/launch/Launcher.class";
+
+    /**
+     * No-arg constructor to enable serialization. This method is not intended to be used by mere mortals without calling
+     * setName().
+     */
+    public LocatorTest() {
+    }
+
+    /** Constructs a test case with the given name.
+     * @param name
+     */
+    public LocatorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Sets up the fixture, for example, open a network connection.
+     * This method is called before a test is executed.
+     */
+    protected void setUp() throws Exception {
+        super.setUp();
+        windows = Os.isFamily(Os.FAMILY_DOS);
+        unix = Os.isFamily(Os.FAMILY_UNIX);
+    }
+
+    private String resolve(String uri) {
+        String j14 = Locator.fromURI(uri);
+        String j13 = Locator.fromURIJava13(uri);
+        assertEquals("Different fromURI conversion.\nJava1.4=" + j14 + "\nJava1.3=" + j13 + "\n",
+                j14, j13);
+        return j14;
+    }
+
+    /**
+     * expect a uri to resolve to strings on different platforms
+     * @param uri uri to parse
+     * @param expectedUnix unix string (or null to skip that test)
+     * @param expectedDos DOS string (or null to skip that test)
+     * @return the resolved string
+     */
+    private String resolveTo(String uri, String expectedUnix, String expectedDos) {
+        String result = resolve(uri);
+        assertResolved(uri, expectedUnix, result, unix);
+        assertResolved(uri, expectedDos, result, windows);
+        return result;
+    }
+
+    /**
+     * Assert something resolved
+     * @param uri original URI
+     * @param expectedResult what we expected
+     * @param result what we got
+     * @param enabled is the test enabled?
+     */
+    private void assertResolved(String uri, String expectedResult, String result, boolean enabled) {
+        if (enabled && expectedResult != null && expectedResult.length() > 0) {
+            assertEquals("Expected " + uri + " to resolve to \n" + expectedResult + "\n but got\n"
+                    + result + "\n", expectedResult, result);
+        }
+    }
+
+    /**
+     * This asserts that we can round trip the path to a URI and back again
+     * @param path filename with no directory separators
+     * @return the trailing filename
+     */
+    private String assertResolves(String path) {
+        String asuri = new File(path).toURI().toASCIIString();
+        String fullpath = System.getProperty("user.dir") + File.separator + path;
+        String result = resolveTo(asuri, fullpath, fullpath);
+        return result.substring(result.lastIndexOf(File.separatorChar) + 1);
+    }
+
+
+    /**
+     * this isnt really a valid URI, except maybe in IE
+     * @throws Exception
+     */
+    public void testNetworkURI() throws Exception {
+        resolveTo("file:\\\\PC03\\jclasses\\lib\\ant-1.7.0.jar", ""
+                + "\\\\PC03\\jclasses\\lib\\ant-1.7.0.jar",
+                "\\\\PC03\\jclasses\\lib\\ant-1.7.0.jar");
+    }
+
+    /**
+     * This is not being tested as we don't appear to generate paths like this in the launcher
+     * @throws Exception
+     */
+    public void NotestTripleForwardSlashNetworkURI() throws Exception {
+        resolveTo("file:///PC03/jclasses/lib/ant-1.7.0.jar",
+                "///PC03/jclasses/lib/ant-1.7.0.jar",
+                "\\\\PC03\\jclasses\\lib\\ant-1.7.0.jar");
+    }
+
+    public void testUnixNetworkPath() throws Exception {
+        resolveTo("file://cluster/home/ant/lib",
+                "//cluster/home/ant/lib",
+                "\\\\cluster\\home\\ant\\lib");
+    }
+
+    public void testUnixPath() throws Exception {
+        resolveTo("file:/home/ant/lib", "/home/ant/lib", null);
+    }
+
+    public void testSpacedURI() throws Exception {
+        resolveTo("file:C:\\Program Files\\Ant\\lib",
+                "C:\\Program Files\\Ant\\lib",
+                "C:\\Program Files\\Ant\\lib");
+    }
+
+    /**
+     * Bug 42275; Ant failing to run off a remote share
+     * @throws Throwable if desired
+     */
+    public void testAntOnRemoteShare() throws Throwable {
+        String resolved=Locator.fromJarURI(SHARED_JAR_URI);
+        assertResolved(SHARED_JAR_URI, LAUNCHER_JAR,resolved,true);
+    }
+
+    /**
+     * Bug 42275; Ant failing to run off a remote share
+     *
+     * @throws Throwable if desired
+     */
+    public void testFileFromRemoteShare() throws Throwable {
+        String resolved = Locator.fromJarURI(SHARED_JAR_URI);
+        assertResolved(SHARED_JAR_URI, LAUNCHER_JAR, resolved, true);
+        File f=new File(resolved);
+        String path = f.getAbsolutePath();
+        assertTrue(path.indexOf("\\\\")==0);
+    }
+
+    public void testHttpURI() throws Exception {
+        String url = "http://ant.apache.org";
+        try {
+            Locator.fromURI(url);
+        } catch (IllegalArgumentException e) {
+            String message = e.getMessage();
+            assertTrue(message, message.indexOf(Locator.ERROR_NOT_FILE_URI) >= 0);
+            assertTrue(message, message.indexOf(url) >= 0);
+        }
+    }
+
+    public void testInternationalURI() throws Exception {
+        String result = assertResolves("L\u00f6wenbrau.aus.M\u00fcnchen");
+        char umlauted = result.charAt(1);
+        assertEquals("expected 0xf6 (\u00f6), but got " + Integer.toHexString(umlauted) + " '"
+                + umlauted + "'", 0xf6, umlauted);
+    }
+
+    public void testOddLowAsciiURI() throws Exception {
+        assertResolves("hash# and percent%");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AbstractCvsTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AbstractCvsTaskTest.java
new file mode 100644
index 0000000..50e3f61
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AbstractCvsTaskTest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class AbstractCvsTaskTest extends BuildFileTest {
+
+    public AbstractCvsTaskTest() {
+        this( "AbstractCvsTaskTest" );
+    }
+
+    public AbstractCvsTaskTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/abstractcvstask.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testAbstractCvsTask() {
+        executeTarget( "all" );
+    }
+
+    public void testPackageAttribute() {
+        File f = getProject().resolveFile("tmpdir/ant/build.xml");
+        assertTrue("starting empty", !f.exists());
+        expectLogContaining("package-attribute", "U ant/build.xml");
+        assertTrue("now it is there", f.exists());
+    }
+
+    public void testTagAttribute() {
+        File f = getProject().resolveFile("tmpdir/ant/build.xml");
+        assertTrue("starting empty", !f.exists());
+        expectLogContaining("tag-attribute", "ANT_141 (revision: 1.175.2.13)");
+        assertTrue("now it is there", f.exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntLikeTasksAtTopLevelTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntLikeTasksAtTopLevelTest.java
new file mode 100644
index 0000000..e8c1349
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntLikeTasksAtTopLevelTest.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * @since Ant 1.6
+ */
+public class AntLikeTasksAtTopLevelTest extends BuildFileTest {
+    public AntLikeTasksAtTopLevelTest(String name) {
+        super(name);
+    }
+
+    public void testAnt() {
+        try {
+            configureProject("src/etc/testcases/taskdefs/toplevelant.xml");
+            fail("no exception thrown");
+        } catch (BuildException e) {
+            assertEquals("ant task at the top level must not invoke its own"
+                         + " build file.", e.getMessage());
+        }
+    }
+
+    public void testSubant() {
+        try {
+            configureProject("src/etc/testcases/taskdefs/toplevelsubant.xml");
+            fail("no exception thrown");
+        } catch (BuildException e) {
+            assertEquals("subant task at the top level must not invoke its own"
+                         + " build file.", e.getMessage());
+        }
+    }
+
+    public void testAntcall() {
+        try {
+            configureProject("src/etc/testcases/taskdefs/toplevelantcall.xml");
+            fail("no exception thrown");
+        } catch (BuildException e) {
+            assertEquals("antcall must not be used at the top level.",
+                         e.getMessage());
+        }
+    }
+
+}// AntLikeTasksAtTopLevelTest
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntStructureTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntStructureTest.java
new file mode 100644
index 0000000..af09c97
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntStructureTest.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.PrintWriter;
+import java.util.Hashtable;
+import junit.framework.Assert;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
+/**
+ */
+public class AntStructureTest extends BuildFileTest {
+
+    public AntStructureTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/antstructure.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void testCustomPrinter() {
+        executeTarget("testCustomPrinter");
+        // can't access the booleans in MyPrinter here (even if they
+        // were static) since the MyPrinter instance that was used in
+        // the test has likely been loaded via a different classloader
+        // than this class.  Therefore we make the printer assert its
+        // state and only check for the tail invocation.
+        assertLogContaining(MyPrinter.TAIL_CALLED);
+    }
+
+    public static class MyPrinter implements AntStructure.StructurePrinter {
+        private static final String TAIL_CALLED = "tail has been called";
+        private boolean headCalled = false;
+        private boolean targetCalled = false;
+        private boolean tailCalled = false;
+        private int elementCalled = 0;
+        private Project p;
+
+        public void printHead(PrintWriter out, Project p, Hashtable tasks,
+                              Hashtable types) {
+            Assert.assertTrue(!headCalled);
+            Assert.assertTrue(!targetCalled);
+            Assert.assertTrue(!tailCalled);
+            Assert.assertEquals(0, elementCalled);
+            headCalled = true;
+        }
+        public void printTargetDecl(PrintWriter out) {
+            Assert.assertTrue(headCalled);
+            Assert.assertTrue(!targetCalled);
+            Assert.assertTrue(!tailCalled);
+            Assert.assertEquals(0, elementCalled);
+            targetCalled = true;
+        }
+        public void printElementDecl(PrintWriter out, Project p, String name,
+                                     Class element) {
+            Assert.assertTrue(headCalled);
+            Assert.assertTrue(targetCalled);
+            Assert.assertTrue(!tailCalled);
+            elementCalled++;
+            this.p = p;
+        }
+        public void printTail(PrintWriter out) {
+            Assert.assertTrue(headCalled);
+            Assert.assertTrue(targetCalled);
+            Assert.assertTrue(!tailCalled);
+            Assert.assertTrue(elementCalled > 0);
+            tailCalled = true;
+            p.log(TAIL_CALLED);
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntTest.java
new file mode 100644
index 0000000..32a55b5
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntTest.java
@@ -0,0 +1,512 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildListener;
+import org.apache.tools.ant.input.InputHandler;
+import org.apache.tools.ant.input.PropertyFileInputHandler;
+import org.apache.tools.ant.types.Path;
+
+/**
+ */
+public class AntTest extends BuildFileTest {
+
+    public AntTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/ant.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "recursive call");
+    }
+
+    // target must be specified
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    // Should fail since a recursion will occur...
+    public void test3() {
+        expectBuildException("test1", "recursive call");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "target attribute must not be empty");
+    }
+
+    public void test4b() {
+        expectBuildException("test4b", "target doesn't exist");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+    }
+
+    public void test6() {
+        executeTarget("test6");
+    }
+
+    public void testExplicitBasedir1() {
+        File dir1 = getProjectDir();
+        File dir2 = project.resolveFile("..");
+        testBaseDirs("explicitBasedir1",
+                     new String[] {dir1.getAbsolutePath(),
+                                   dir2.getAbsolutePath()
+                     });
+    }
+
+    public void testExplicitBasedir2() {
+        File dir1 = getProjectDir();
+        File dir2 = project.resolveFile("..");
+        testBaseDirs("explicitBasedir2",
+                     new String[] {dir1.getAbsolutePath(),
+                                   dir2.getAbsolutePath()
+                     });
+    }
+
+    public void testInheritBasedir() {
+        String basedir = getProjectDir().getAbsolutePath();
+        testBaseDirs("inheritBasedir", new String[] {basedir, basedir});
+    }
+
+    public void testDoNotInheritBasedir() {
+        File dir1 = getProjectDir();
+        File dir2 = project.resolveFile("ant");
+        String basedir = getProjectDir().getAbsolutePath();
+        testBaseDirs("doNotInheritBasedir",
+                     new String[] {dir1.getAbsolutePath(),
+                                   dir2.getAbsolutePath()
+                     });
+    }
+
+    public void testBasedirTripleCall() {
+        File dir1 = getProjectDir();
+        File dir2 = project.resolveFile("ant");
+        testBaseDirs("tripleCall",
+                     new String[] {dir1.getAbsolutePath(),
+                                   dir2.getAbsolutePath(),
+                                   dir1.getAbsolutePath()
+                     });
+    }
+
+    protected void testBaseDirs(String target, String[] dirs) {
+        BasedirChecker bc = new BasedirChecker(dirs);
+        project.addBuildListener(bc);
+        executeTarget(target);
+        AssertionFailedError ae = bc.getError();
+        if (ae != null) {
+            throw ae;
+        }
+        project.removeBuildListener(bc);
+    }
+
+    public void testReferenceInheritance() {
+        Path p = Path.systemClasspath;
+        p.setProject(project);
+        project.addReference("path", p);
+        project.addReference("no-override", p);
+        testReference("testInherit", new String[] {"path", "path"},
+                      new boolean[] {true, true}, p);
+        testReference("testInherit",
+                      new String[] {"no-override", "no-override"},
+                      new boolean[] {true, false}, p);
+        testReference("testInherit",
+                      new String[] {"no-override", "no-override"},
+                      new boolean[] {false, false}, null);
+    }
+
+    public void testReferenceNoInheritance() {
+        Path p = Path.systemClasspath;
+        p.setProject(project);
+        project.addReference("path", p);
+        project.addReference("no-override", p);
+        testReference("testNoInherit", new String[] {"path", "path"},
+                      new boolean[] {true, false}, p);
+        testReference("testNoInherit", new String[] {"path", "path"},
+                      new boolean[] {false, true}, null);
+        testReference("testInherit",
+                      new String[] {"no-override", "no-override"},
+                      new boolean[] {true, false}, p);
+        testReference("testInherit",
+                      new String[] {"no-override", "no-override"},
+                      new boolean[] {false, false}, null);
+    }
+
+    public void testReferenceRename() {
+        Path p = Path.systemClasspath;
+        p.setProject(project);
+        project.addReference("path", p);
+        testReference("testRename", new String[] {"path", "path"},
+                      new boolean[] {true, false}, p);
+        testReference("testRename", new String[] {"path", "path"},
+                      new boolean[] {false, true}, null);
+        testReference("testRename", new String[] {"newpath", "newpath"},
+                      new boolean[] {false, true}, p);
+    }
+
+    public void testInheritPath() {
+        executeTarget("testInheritPath");
+    }
+
+    protected void testReference(String target, String[] keys,
+                                 boolean[] expect, Object value) {
+        ReferenceChecker rc = new ReferenceChecker(keys, expect, value);
+        project.addBuildListener(rc);
+        executeTarget(target);
+        AssertionFailedError ae = rc.getError();
+        if (ae != null) {
+            throw ae;
+        }
+        project.removeBuildListener(rc);
+    }
+
+    public void testLogfilePlacement() {
+        File[] logFiles = new File[] {
+            getProject().resolveFile("test1.log"),
+            getProject().resolveFile("test2.log"),
+            getProject().resolveFile("ant/test3.log"),
+            getProject().resolveFile("ant/test4.log")
+        };
+        for (int i=0; i<logFiles.length; i++) {
+            assertTrue(logFiles[i].getName()+" doesn\'t exist",
+                       !logFiles[i].exists());
+        }
+
+        executeTarget("testLogfilePlacement");
+
+        for (int i=0; i<logFiles.length; i++) {
+            assertTrue(logFiles[i].getName()+" exists",
+                       logFiles[i].exists());
+        }
+    }
+
+    public void testInputHandlerInheritance() {
+        InputHandler ih = new PropertyFileInputHandler();
+        getProject().setInputHandler(ih);
+        InputHandlerChecker ic = new InputHandlerChecker(ih);
+        getProject().addBuildListener(ic);
+        executeTarget("tripleCall");
+        AssertionFailedError ae = ic.getError();
+        if (ae != null) {
+            throw ae;
+        }
+        getProject().removeBuildListener(ic);
+    }
+
+    public void testRefId() {
+        Path testPath = new Path(project);
+        testPath.createPath().setPath(System.getProperty("java.class.path"));
+        PropertyChecker pc =
+            new PropertyChecker("testprop",
+                                new String[] {null,
+                                              testPath.toString()});
+        project.addBuildListener(pc);
+        executeTarget("testRefid");
+        AssertionFailedError ae = pc.getError();
+        if (ae != null) {
+            throw ae;
+        }
+        project.removeBuildListener(pc);
+    }
+
+    public void testUserPropertyWinsInheritAll() {
+        getProject().setUserProperty("test", "7");
+        expectLogContaining("test-property-override-inheritall-start",
+                            "The value of test is 7");
+    }
+
+    public void testUserPropertyWinsNoInheritAll() {
+        getProject().setUserProperty("test", "7");
+        expectLogContaining("test-property-override-no-inheritall-start",
+                            "The value of test is 7");
+    }
+
+    public void testOverrideWinsInheritAll() {
+        expectLogContaining("test-property-override-inheritall-start",
+                            "The value of test is 4");
+    }
+
+    public void testOverrideWinsNoInheritAll() {
+        expectLogContaining("test-property-override-no-inheritall-start",
+                            "The value of test is 4");
+    }
+
+    public void testPropertySet() {
+        executeTarget("test-propertyset");
+        assertTrue(getLog().indexOf("test1 is ${test1}") > -1);
+        assertTrue(getLog().indexOf("test2 is ${test2}") > -1);
+        assertTrue(getLog().indexOf("test1.x is 1") > -1);
+    }
+
+    public void testInfiniteLoopViaDepends() {
+        expectBuildException("infinite-loop-via-depends", "recursive call");
+    }
+
+    public void testMultiSameProperty() {
+        expectLog("multi-same-property", "prop is two");
+    }
+
+    public void testTopLevelTarget() {
+        expectLog("topleveltarget", "Hello world");
+    }
+
+    public void testMultiplePropertyFileChildren() {
+        PropertyChecker pcBar = new PropertyChecker("bar",
+                                                    new String[] {null, "Bar"});
+        PropertyChecker pcFoo = new PropertyChecker("foo",
+                                                    new String[] {null, "Foo"});
+        project.addBuildListener(pcBar);
+        project.addBuildListener(pcFoo);
+        executeTarget("multiple-property-file-children");
+        AssertionFailedError aeBar = pcBar.getError();
+        if (aeBar != null) {
+            throw aeBar;
+        }
+        AssertionFailedError aeFoo = pcFoo.getError();
+        if (aeFoo != null) {
+            throw aeFoo;
+        }
+        project.removeBuildListener(pcBar);
+        project.removeBuildListener(pcFoo);
+    }
+
+    public void testBlankTarget() {
+        expectBuildException("blank-target", "target name must not be empty");
+    }
+
+    public void testMultipleTargets() {
+        expectLog("multiple-targets", "tadadctbdbtc");
+    }
+
+    public void testMultipleTargets2() {
+        expectLog("multiple-targets-2", "dadctb");
+    }
+
+    private class BasedirChecker implements BuildListener {
+        private String[] expectedBasedirs;
+        private int calls = 0;
+        private AssertionFailedError error;
+
+        BasedirChecker(String[] dirs) {
+            expectedBasedirs = dirs;
+        }
+
+        public void buildStarted(BuildEvent event) {}
+        public void buildFinished(BuildEvent event) {}
+        public void targetFinished(BuildEvent event){}
+        public void taskStarted(BuildEvent event) {}
+        public void taskFinished(BuildEvent event) {}
+        public void messageLogged(BuildEvent event) {}
+
+        public void targetStarted(BuildEvent event) {
+            if (event.getTarget().getName().equals("")) {
+                return;
+            }
+            if (error == null) {
+                try {
+                    assertEquals(expectedBasedirs[calls++],
+                                 event.getProject().getBaseDir().getAbsolutePath());
+                } catch (AssertionFailedError e) {
+                    error = e;
+                }
+            }
+        }
+
+        AssertionFailedError getError() {
+            return error;
+        }
+
+    }
+
+    private class ReferenceChecker implements BuildListener {
+        private String[] keys;
+        private boolean[] expectSame;
+        private Object value;
+        private int calls = 0;
+        private AssertionFailedError error;
+
+        ReferenceChecker(String[] keys, boolean[] expectSame, Object value) {
+            this.keys = keys;
+            this.expectSame = expectSame;
+            this.value = value;
+        }
+
+        public void buildStarted(BuildEvent event) {}
+        public void buildFinished(BuildEvent event) {}
+        public void targetFinished(BuildEvent event){}
+        public void taskStarted(BuildEvent event) {}
+        public void taskFinished(BuildEvent event) {}
+        public void messageLogged(BuildEvent event) {}
+
+        public void targetStarted(BuildEvent event) {
+            if (event.getTarget().getName().equals("")) {
+                return;
+            }
+            if (error == null) {
+                try {
+                    String msg =
+                        "Call " + calls + " refid=\'" + keys[calls] + "\'";
+                    if (value == null) {
+                        Object o = event.getProject().getReference(keys[calls]);
+                        if (expectSame[calls++]) {
+                            assertNull(msg, o);
+                        } else {
+                            assertNotNull(msg, o);
+                        }
+                    } else {
+                        // a rather convoluted equals() test
+                        Path expect = (Path) value;
+                        Path received = (Path) event.getProject().getReference(keys[calls]);
+                        boolean shouldBeEqual = expectSame[calls++];
+                        if (received == null) {
+                            assertTrue(msg, !shouldBeEqual);
+                        } else {
+                            String[] l1 = expect.list();
+                            String[] l2 = received.list();
+                            if (l1.length == l2.length) {
+                                for (int i=0; i<l1.length; i++) {
+                                    if (!l1[i].equals(l2[i])) {
+                                        assertTrue(msg, !shouldBeEqual);
+                                    }
+                                }
+                                assertTrue(msg, shouldBeEqual);
+                            } else {
+                                assertTrue(msg, !shouldBeEqual);
+                            }
+                        }
+                    }
+                } catch (AssertionFailedError e) {
+                    error = e;
+                }
+            }
+        }
+
+        AssertionFailedError getError() {
+            return error;
+        }
+
+    }
+
+    private class InputHandlerChecker implements BuildListener {
+        private InputHandler ih;
+        private AssertionFailedError error;
+
+        InputHandlerChecker(InputHandler value) {
+            ih = value;
+        }
+
+        public void buildStarted(BuildEvent event) {
+            check(event);
+        }
+        public void buildFinished(BuildEvent event) {
+            check(event);
+        }
+        public void targetFinished(BuildEvent event) {
+            check(event);
+        }
+        public void taskStarted(BuildEvent event) {
+            check(event);
+        }
+        public void taskFinished(BuildEvent event) {
+            check(event);
+        }
+        public void messageLogged(BuildEvent event) {
+            check(event);
+        }
+
+        public void targetStarted(BuildEvent event) {
+            check(event);
+        }
+
+        private void check(BuildEvent event) {
+            if (error == null) {
+                try {
+                    assertNotNull(event.getProject().getInputHandler());
+                    assertSame(ih, event.getProject().getInputHandler());
+                } catch (AssertionFailedError e) {
+                    error = e;
+                }
+            }
+        }
+
+        AssertionFailedError getError() {
+            return error;
+        }
+
+    }
+
+    private class PropertyChecker implements BuildListener {
+        private String[] expectedValues;
+        private String key;
+        private int calls = 0;
+        private AssertionFailedError error;
+
+        PropertyChecker(String key, String[] values) {
+            this.key = key;
+            this.expectedValues = values;
+        }
+
+        public void buildStarted(BuildEvent event) {}
+        public void buildFinished(BuildEvent event) {}
+        public void targetFinished(BuildEvent event){}
+        public void taskStarted(BuildEvent event) {}
+        public void taskFinished(BuildEvent event) {}
+        public void messageLogged(BuildEvent event) {}
+
+        public void targetStarted(BuildEvent event) {
+            if (event.getTarget().getName().equals("")) {
+                return;
+            }
+            if (calls >= expectedValues.length) {
+                error = new AssertionFailedError("Unexpected invocation of"
+                                                 + " target "
+                                                 + event.getTarget().getName());
+            }
+
+            if (error == null) {
+                try {
+                    assertEquals(expectedValues[calls++],
+                                 event.getProject().getProperty(key));
+                } catch (AssertionFailedError e) {
+                    error = e;
+                }
+            }
+        }
+
+        AssertionFailedError getError() {
+            return error;
+        }
+
+    }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntlibTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntlibTest.java
new file mode 100644
index 0000000..ea9db5c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AntlibTest.java
@@ -0,0 +1,94 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.Project;
+
+/**
+ */
+public class AntlibTest extends BuildFileTest {
+    public AntlibTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/antlib.xml");
+    }
+
+    /**
+     * only do the antlib tests if we are in the same JVM as ant.
+     * @return
+     */
+    private boolean isSharedJVM() {
+        String property = System.getProperty("tests.and.ant.share.classloader");
+        return property!=null && Project.toBoolean(property);
+    }
+
+    public void testAntlibFile() {
+        expectLog("antlib.file", "MyTask called");
+    }
+
+    /**
+     * Confirms that all matching resources will be used, so that you
+     * can collect several antlibs in one Definer call.
+     * @see "http://issues.apache.org/bugzilla/show_bug.cgi?id=24024"
+     */
+    public void testAntlibResource() {
+        expectLog("antlib.resource", "MyTask called-and-then-MyTask2 called");
+    }
+
+    public void testNsCurrent() {
+        expectLog("ns.current", "Echo2 inside a macroHello from x:p");
+    }
+
+
+    public void testAntlib_uri() {
+        if (isSharedJVM()) {
+            executeTarget("antlib_uri");
+        }
+    }
+
+    public void testAntlib_uri_auto() {
+        if (isSharedJVM()) {
+            executeTarget("antlib_uri_auto");
+        }
+    }
+
+    public void testAntlib_uri_auto2() {
+        if (isSharedJVM()) {
+            executeTarget("antlib_uri_auto2");
+        }
+    }
+    
+    public static class MyTask extends Task {
+        public void execute() {
+            log("MyTask called");
+        }
+    }
+
+    public static class MyTask2 extends Task {
+        public void execute() {
+            log("MyTask2 called");
+        }
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AptTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AptTest.java
new file mode 100644
index 0000000..e7a65db
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AptTest.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+ package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class AptTest extends BuildFileTest {
+    public AptTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/apt.xml");
+    }
+
+    /**
+     * Tears down the fixture, for example, close a network connection. This
+     * method is called after a test is executed.
+     */
+    protected void tearDown() throws Exception {
+        executeTarget("clean");
+    }
+
+    public void testApt() {
+        executeTarget("testApt");
+    }
+
+    public void testAptFork() {
+        executeTarget("testAptFork");
+    }
+ 
+    public void testAptForkFalse() {
+        executeTarget("testAptForkFalse");
+        assertLogContaining(Apt.WARNING_IGNORING_FORK);
+    }
+
+    public void testListAnnotationTypes() {
+        executeTarget("testListAnnotationTypes");
+        assertLogContaining("Set of annotations found:");
+        assertLogContaining("Distributed");
+    }
+
+    public void testAptNewFactory() {
+        executeTarget("testAptNewFactory");
+        assertProcessed();
+    }
+
+    public void testAptNewFactoryFork() {
+        executeTarget("testAptNewFactoryFork");
+        assertProcessed();
+    }
+    
+    private void assertProcessed() {
+        assertLogContaining("DistributedAnnotationProcessor-is-go");
+        assertLogContaining("[-Abuild.dir=");
+        assertLogContaining("visiting DistributedAnnotationFactory");
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AvailableTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AvailableTest.java
new file mode 100644
index 0000000..57b9ff0
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/AvailableTest.java
@@ -0,0 +1,213 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * JUnit test for the Available task/condition.
+ */
+public class AvailableTest extends BuildFileTest {
+
+    public AvailableTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/available.xml");
+    }
+
+    // Nothing specified -> Fail
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    // Only property specified -> Fail
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    // Only file specified -> Fail
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    // file doesn't exist -> property 'test' == null
+    public void test4() {
+        executeTarget("test4");
+        assertTrue(project.getProperty("test") == null);
+    }
+
+    // file does exist -> property 'test' == 'true'
+    public void test5() {
+        executeTarget("test5");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // resource doesn't exist -> property 'test' == null
+    public void test6() {
+        executeTarget("test6");
+        assertTrue(project.getProperty("test") == null);
+    }
+
+    // resource does exist -> property 'test' == 'true'
+    public void test7() {
+        executeTarget("test7");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // class doesn't exist -> property 'test' == null
+    public void test8() {
+        executeTarget("test8");
+        assertTrue(project.getProperty("test") == null);
+    }
+
+    // class does exist -> property 'test' == 'true'
+    public void test9() {
+        executeTarget("test9");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // All three specified and all three exist -> true
+    public void test10() {
+        executeTarget("test10");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // All three specified but class missing -> null
+    public void test11() {
+        executeTarget("test11");
+        assertNull(project.getProperty("test"));
+    }
+
+    // Specified property-name is "" -> true
+    public void test12() {
+        executeTarget("test12");
+        assertNull(project.getProperty("test"));
+        assertEquals("true", project.getProperty(""));
+    }
+
+    // Specified file is "" -> invalid files do not exist
+    public void test13() {
+        executeTarget("test13");
+        assertNull(project.getProperty("test"));
+    }
+
+    // Specified file is "" actually a directory, so it should pass
+    public void test13b() {
+        executeTarget("test13b");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Specified resource is "" -> can such a thing exist?
+    /*
+     * returns non null IBM JDK 1.3 Linux
+     */
+//    public void test14() {
+//        executeTarget("test14");
+//        assertEquals(project.getProperty("test"), null);
+//    }
+
+    // Specified class is "" -> can not exist
+    public void test15() {
+        executeTarget("test15");
+        assertNull(project.getProperty("test"));
+    }
+
+    // Specified dir is "" -> this is the current directory and should
+    // always exist
+    public void test16() {
+        executeTarget("test16");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Specified dir is "../taskdefs" -> should exist since it's the
+    // location of the buildfile used...
+    public void test17() {
+        executeTarget("test17");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Specified dir is "../this_dir_should_never_exist" -> null
+    public void test18() {
+        executeTarget("test18");
+        assertNull(project.getProperty("test"));
+    }
+
+    // Invalid type specified
+    public void test19() {
+        expectBuildException("test19", "Invalid value for type attribute.");
+    }
+
+    // Core class that exists in system classpath is ignored
+    public void test20() {
+        executeTarget("test20");
+        assertNull(project.getProperty("test"));
+    }
+
+    // Core class that exists in system classpath is ignored, but found in specified classpath
+    public void test21() {
+        executeTarget("test21");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Core class that exists in system classpath is not ignored with ignoresystemclass="false"
+    public void test22() {
+        executeTarget("test22");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Core class that exists in system classpath is not ignored with default ignoresystemclasses value
+    public void test23() {
+        executeTarget("test23");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // Class is found in specified classpath
+    public void test24() {
+        executeTarget("test24");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // File is not found in specified filepath
+    public void testSearchInPathNotThere() {
+        executeTarget("searchInPathNotThere");
+        assertNull(project.getProperty("test"));
+    }
+
+    // File is not found in specified filepath
+    public void testSearchInPathIsThere() {
+        executeTarget("searchInPathIsThere");
+        assertEquals("true", project.getProperty("test"));
+    }
+
+    // test when file begins with basedir twice
+    public void testDoubleBasedir() {
+        executeTarget("testDoubleBasedir");
+    }
+
+    // test for searching parents
+    public void testSearchParents() {
+        executeTarget("search-parents");
+    }
+    // test for not searching parents
+    public void testSearchParentsNot() {
+        executeTarget("search-parents-not");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BUnzip2Test.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BUnzip2Test.java
new file mode 100644
index 0000000..b2bf71c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BUnzip2Test.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ */
+public class BUnzip2Test extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public BUnzip2Test(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/bunzip2.xml");
+        executeTarget("prepare");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testRealTest() throws java.io.IOException {
+        testRealTest("realTest");
+    }
+
+    public void testRealTestWithResource() throws java.io.IOException {
+        testRealTest("realTestWithResource");
+    }
+
+    private void testRealTest(String target) throws java.io.IOException {
+        executeTarget(target);
+        assertTrue("File content mismatch after bunzip2",
+            FILE_UTILS.contentEquals(project.resolveFile("expected/asf-logo-huge.tar"),
+                                    project.resolveFile("asf-logo-huge.tar")));
+    }
+
+    public void testDocumentationClaimsOnCopy() throws java.io.IOException {
+        testRealTest("testDocumentationClaimsOnCopy");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BZip2Test.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BZip2Test.java
new file mode 100644
index 0000000..d5f7de4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BZip2Test.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.bzip2.CBZip2InputStream;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ */
+public class BZip2Test extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public BZip2Test(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/bzip2.xml");
+        executeTarget("prepare");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testRealTest() throws IOException {
+        executeTarget("realTest");
+
+        // doesn't work: Depending on the compression engine used,
+        // compressed bytes may differ. False errors would be
+        // reported.
+        // assertTrue("File content mismatch",
+        // FILE_UTILS.contentEquals(project.resolveFile("expected/asf-logo-huge.tar.bz2"),
+        // project.resolveFile("asf-logo-huge.tar.bz2")));
+
+        // We have to compare the decompressed content instead:
+
+        File originalFile =
+            project.resolveFile("expected/asf-logo-huge.tar.bz2");
+        File actualFile   = project.resolveFile("asf-logo-huge.tar.bz2");
+
+        InputStream originalIn =
+            new BufferedInputStream(new FileInputStream(originalFile));
+        assertEquals((byte) 'B', originalIn.read());
+        assertEquals((byte) 'Z', originalIn.read());
+
+        InputStream actualIn =
+            new BufferedInputStream(new FileInputStream(actualFile));
+        assertEquals((byte) 'B', actualIn.read());
+        assertEquals((byte) 'Z', actualIn.read());
+
+        originalIn = new CBZip2InputStream(originalIn);
+        actualIn   = new CBZip2InputStream(actualIn);
+
+        while (true) {
+            int expected = originalIn.read();
+            int actual   = actualIn.read();
+            if (expected >= 0) {
+                if (expected != actual) {
+                    fail("File content mismatch");
+                }
+            } else {
+                if (actual >= 0) {
+                    fail("File content mismatch");
+                }
+                break;
+            }
+        }
+
+        originalIn.close();
+        actualIn.close();
+    }
+
+    public void testResource(){
+        executeTarget("realTestWithResource");
+    }
+
+    public void testDateCheck(){
+        executeTarget("testDateCheck");
+        String log = getLog();
+        assertTrue(
+            "Expecting message ending with 'asf-logo.gif.bz2 is up to date.' but got '" + log + "'",
+            log.endsWith("asf-logo.gif.bz2 is up to date."));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BasenameTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BasenameTest.java
new file mode 100644
index 0000000..07d1281
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/BasenameTest.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class BasenameTest extends BuildFileTest {
+
+    public BasenameTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/basename.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required attribute missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required attribute missing");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required attribute missing");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+        String checkprop = project.getProperty("file.w.suf");
+        assertEquals("foo.txt", checkprop);
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        String checkprop = project.getProperty("file.wo.suf");
+        assertEquals("foo", checkprop);
+    }
+
+    public void testMultipleDots() {
+        executeTarget("testMultipleDots");
+        String checkprop = project.getProperty("file.wo.suf");
+        assertEquals("foo.bar", checkprop);
+    }
+
+    public void testNoDots() {
+        executeTarget("testNoDots");
+        String checkprop = project.getProperty("file.wo.suf");
+        assertEquals("foo.bar", checkprop);
+    }
+
+    public void testValueEqualsSuffixWithDot() {
+        executeTarget("testValueEqualsSuffixWithDot");
+        String checkprop = project.getProperty("file.wo.suf");
+        assertEquals("", checkprop);
+    }
+
+    public void testValueEqualsSuffixWithoutDot() {
+        executeTarget("testValueEqualsSuffixWithoutDot");
+        String checkprop = project.getProperty("file.wo.suf");
+        assertEquals("", checkprop);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CVSPassTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CVSPassTest.java
new file mode 100644
index 0000000..57884f6
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CVSPassTest.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.*;
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests CVSLogin task.
+ *
+ */
+public class CVSPassTest extends BuildFileTest {
+    private final String EOL = System.getProperty("line.separator");
+    private static final String JAKARTA_URL =
+        ":pserver:anoncvs@jakarta.apache.org:/home/cvspublic Ay=0=h<Z";
+    private static final String XML_URL =
+        ":pserver:anoncvs@xml.apache.org:/home/cvspublic Ay=0=h<Z";
+    private static final String TIGRIS_URL =
+        ":pserver:guest@cvs.tigris.org:/cvs AIbdZ,";
+
+
+    public CVSPassTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/cvspass.xml");
+    }
+
+    public void testNoCVSRoot() {
+        try{
+            executeTarget("test1");
+            fail("BuildException not thrown");
+        }catch(BuildException e){
+            assertEquals("cvsroot is required", e.getMessage());
+        }
+    }
+
+    public void testNoPassword() {
+        try{
+            executeTarget("test2");
+            fail("BuildException not thrown");
+        }catch(BuildException e){
+            assertEquals("password is required", e.getMessage());
+        }
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testPassFile() throws Exception {
+        executeTarget("test3");
+        File f = new File(getProjectDir(), "testpassfile.tmp");
+
+        assertTrue( "Passfile "+f+" not created", f.exists());
+
+        assertEquals(JAKARTA_URL+EOL, readFile(f));
+
+    }
+
+    public void testPassFileDuplicateEntry() throws Exception {
+        executeTarget("test4");
+        File f = new File(getProjectDir(), "testpassfile.tmp");
+
+        assertTrue( "Passfile "+f+" not created", f.exists());
+
+        assertEquals(
+            JAKARTA_URL+ EOL+
+            TIGRIS_URL+ EOL,
+            readFile(f));
+    }
+
+    public void testPassFileMultipleEntry() throws Exception {
+        executeTarget("test5");
+        File f = new File(getProjectDir(), "testpassfile.tmp");
+
+        assertTrue( "Passfile "+f+" not created", f.exists());
+
+        assertEquals(
+            JAKARTA_URL+ EOL+
+            XML_URL+ EOL+
+            TIGRIS_URL+ EOL,
+            readFile(f));
+    }
+
+    private String readFile(File f) throws Exception {
+        BufferedReader reader = null;
+
+        try {
+            reader = new BufferedReader(new FileReader(f));
+
+            StringBuffer buf = new StringBuffer();
+            String line=null;
+            while((line=reader.readLine())!=null){
+                buf.append(line + EOL);
+            }
+            return buf.toString();
+        } finally {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CallTargetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CallTargetTest.java
new file mode 100644
index 0000000..5ef9111
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CallTargetTest.java
@@ -0,0 +1,72 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class CallTargetTest extends BuildFileTest {
+
+    public CallTargetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/calltarget.xml");
+    }
+
+    // see bugrep 21724 (references not passing through with antcall)
+    public void testInheritRefFileSet() {
+        expectLogContaining("testinheritreffileset", "calltarget.xml");
+    }
+
+    // see bugrep 21724 (references not passing through with antcall)
+    public void testInheritFilterset() {
+        project.executeTarget("testinheritreffilterset");
+    }
+
+    // see bugrep 11418 (In repeated calls to the same target,
+    // params will not be passed in)
+    public void testMultiCall() {
+        Vector v = new Vector();
+        v.add("call-multi");
+        v.add("call-multi");
+        project.executeTargets(v);
+        assertLogContaining("multi is SETmulti is SET");
+    }
+
+    public void testBlankTarget() {
+        expectBuildException("blank-target", "target name must not be empty");
+    }
+
+    public void testMultipleTargets() {
+        expectLog("multiple-targets", "tadadctbdbtc");
+    }
+
+    public void testMultipleTargets2() {
+        expectLog("multiple-targets-2", "dadctb");
+    }
+
+    public void tearDown() {
+        project.executeTarget("cleanup");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ChecksumTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ChecksumTest.java
new file mode 100644
index 0000000..346752c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ChecksumTest.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+import java.io.IOException;
+
+/**
+ */
+public class ChecksumTest extends BuildFileTest {
+
+    public ChecksumTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/checksum.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testCreateMd5() throws IOException {
+        executeTarget("createMd5");
+    }
+
+    public void testCreateMD5SUMformat() throws IOException {
+        executeTarget("createMD5SUMformat");
+    }
+    
+    public void testCreateSVFformat() throws IOException {
+        executeTarget("createSVFformat");
+    }
+    
+    public void testCreatePattern() throws IOException {
+        executeTarget("createPattern");
+    }
+
+    public void testSetProperty() {
+        executeTarget("setProperty");
+    }
+
+    public void testVerifyTotal() {
+        executeTarget("verifyTotal");
+    }
+
+    public void testVerifyTotalRC() {
+        executeTarget("verifyTotalRC");
+    }
+
+    public void testVerifyChecksumdir() {
+        executeTarget("verifyChecksumdir");
+    }
+
+    public void testVerifyAsTask() {
+        executeTarget("verifyAsTask");
+    }
+
+    public void testVerifyMD5SUMAsTask() {
+        executeTarget("verifyMD5SUMAsTask");
+    }
+
+    public void testVerifyAsCondition() {
+        executeTarget("verifyAsCondition");
+    }
+
+    public void testVerifyFromProperty() {
+        executeTarget("verifyFromProperty");
+    }
+
+    public void testVerifyChecksumdirNoTotal() {
+        executeTarget("verifyChecksumdirNoTotal");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConcatTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConcatTest.java
new file mode 100644
index 0000000..b5f9173
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConcatTest.java
@@ -0,0 +1,285 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A test class for the 'concat' task, used to concatenate a series of
+ * files into a single stream.
+ *
+ */
+public class ConcatTest
+    extends BuildFileTest {
+
+    /**
+     * The name of the temporary file.
+     */
+    private static final String tempFile = "concat.tmp";
+
+    /**
+     * The name of the temporary file.
+     */
+    private static final String tempFile2 = "concat.tmp.2";
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    /**
+     * Required constructor.
+     */
+    public ConcatTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test set up, called by the unit test framework prior to each
+     * test.
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/concat.xml");
+    }
+
+    /**
+     * Test tear down, called by the unit test framework prior to each
+     * test.
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    /**
+     * Expect an exception when insufficient information is provided.
+     */
+    public void test1() {
+        expectBuildException("test1", "Insufficient information.");
+    }
+
+    /**
+     * Expect an exception when the destination file is invalid.
+     */
+    public void test2() {
+        expectBuildException("test2", "Invalid destination file.");
+    }
+
+    /**
+     * Cats the string 'Hello, World!' to a temporary file.
+     */
+    public void test3() {
+
+        File file = new File(getProjectDir(), tempFile);
+        if (file.exists()) {
+            file.delete();
+        }
+
+        executeTarget("test3");
+
+        assertTrue(file.exists());
+    }
+
+    /**
+     * Cats the file created in test3 three times.
+     */
+    public void test4() {
+        test3();
+
+        File file = new File(getProjectDir(), tempFile);
+        final long origSize = file.length();
+
+        executeTarget("test4");
+
+        File file2 = new File(getProjectDir(), tempFile2);
+        final long newSize = file2.length();
+
+        assertEquals(origSize * 3, newSize);
+    }
+
+    /**
+     * Cats the string 'Hello, World!' to the console.
+     */
+    public void test5() {
+        expectLog("test5", "Hello, World!");
+    }
+
+    public void test6() {
+        String filename = "src/etc/testcases/taskdefs/thisfiledoesnotexist"
+            .replace('/', File.separatorChar);
+        expectLogContaining("test6", filename +" does not exist.");
+    }
+
+    public void testConcatNoNewline() {
+        expectLog("testConcatNoNewline", "ab");
+    }
+
+    public void testConcatNoNewlineEncoding() {
+        expectLog("testConcatNoNewlineEncoding", "ab");
+    }
+
+    public void testPath() {
+        test3();
+
+        File file = new File(getProjectDir(), tempFile);
+        final long origSize = file.length();
+
+        executeTarget("testPath");
+
+        File file2 = new File(getProjectDir(), tempFile2);
+        final long newSize = file2.length();
+
+        assertEquals(origSize, newSize);
+
+    }
+    public void testAppend() {
+        test3();
+
+        File file = new File(getProjectDir(), tempFile);
+        final long origSize = file.length();
+
+        executeTarget("testAppend");
+
+        File file2 = new File(getProjectDir(), tempFile2);
+        final long newSize = file2.length();
+
+        assertEquals(origSize*2, newSize);
+
+    }
+
+    public void testFilter() {
+        executeTarget("testfilter");
+        assertTrue(getLog().indexOf("REPLACED") > -1);
+    }
+
+    public void testNoOverwrite() {
+        executeTarget("testnooverwrite");
+        File file2 = new File(getProjectDir(), tempFile2);
+        long size = file2.length();
+        assertEquals(size, 0);
+    }
+
+    public void testheaderfooter() {
+        test3();
+        expectLog("testheaderfooter", "headerHello, World!footer");
+    }
+
+    public void testfileheader() {
+        test3();
+        expectLog("testfileheader", "Hello, World!Hello, World!");
+    }
+
+    /**
+     * Expect an exception when attempting to cat an file to itself
+     */
+    public void testsame() {
+        expectBuildException("samefile", "output file same as input");
+    }
+
+    /**
+     * Check if filter inline works
+     */
+    public void testfilterinline() {
+        executeTarget("testfilterinline");
+        assertTrue(getLog().indexOf("REPLACED") > -1);
+    }
+
+    /**
+     * Check if multireader works
+     */
+    public void testmultireader() {
+        executeTarget("testmultireader");
+        assertTrue(getLog().indexOf("Bye") > -1);
+        assertTrue(getLog().indexOf("Hello") == -1);
+    }
+    /**
+     * Check if fixlastline works
+     */
+    public void testfixlastline()
+        throws IOException
+    {
+        expectFileContains(
+            "testfixlastline", "concat.line4",
+            "end of line" + System.getProperty("line.separator")
+            + "This has");
+    }
+
+    /**
+     * Check if fixlastline works with eol
+     */
+    public void testfixlastlineeol()
+        throws IOException
+    {
+        expectFileContains(
+            "testfixlastlineeol", "concat.linecr",
+            "end of line\rThis has");
+    }
+
+    // ------------------------------------------------------
+    //   Helper methods - should be in BuildFileTest
+    // -----------------------------------------------------
+
+    private String getFileString(String filename)
+        throws IOException
+    {
+        Reader r = null;
+        try {
+            r = new FileReader(getProject().resolveFile(filename));
+            return  FileUtils.readFully(r);
+        }
+        finally {
+            FileUtils.close(r);
+        }
+
+    }
+
+    private String getFileString(String target, String filename)
+        throws IOException
+    {
+        executeTarget(target);
+        return getFileString(filename);
+    }
+
+    private void expectFileContains(
+        String target, String filename, String contains)
+        throws IOException
+    {
+        String content = getFileString(target, filename);
+        assertTrue(
+            "expecting file " + filename + " to contain " +
+            contains +
+            " but got " + content, content.indexOf(contains) > -1);
+    }
+
+    public void testTranscoding() throws IOException {
+        executeTarget("testTranscoding");
+        File f1 = getProject().resolveFile("copy/expected/utf-8");
+        File f2 = getProject().resolveFile("concat.utf8");
+        assertTrue(f1.toString() + " differs from " + f2.toString(),
+                FILE_UTILS.contentEquals(f1, f2));
+    }
+
+    public void testResources() {
+        executeTarget("testResources");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConditionTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConditionTest.java
new file mode 100644
index 0000000..7cf71cc
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ConditionTest.java
@@ -0,0 +1,275 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * @created 13 January 2002
+ */
+public class ConditionTest extends BuildFileTest {
+
+    /**
+     * Constructor for the ConditionTest object
+     *
+     * @param name we dont know
+     */
+    public ConditionTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/condition.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testBasic() {
+       expectPropertySet("basic","basic");
+    }
+
+    public void testConditionIncomplete() {
+        expectSpecificBuildException("condition-incomplete",
+                                     "property attribute has been omitted",
+                                     "The property attribute is required.");
+    }
+
+    public void testConditionEmpty() {
+        expectSpecificBuildException("condition-empty",
+                                     "no conditions",
+                                     "You must nest a condition into <condition>");
+    }
+
+    public void testShortcut() {
+        expectPropertySet("shortcut","shortcut","set");
+    }
+
+    public void testUnset() {
+        expectPropertyUnset("dontset","dontset");
+    }
+
+    public void testSetValue() {
+        expectPropertySet("setvalue","setvalue","woowoo");
+    }
+
+    public void testNegation() {
+        expectPropertySet("negation","negation");
+    }
+
+    public void testNegationFalse() {
+        expectPropertyUnset("negationfalse","negationfalse");
+    }
+
+    public void testNegationIncomplete() {
+        expectSpecificBuildException("negationincomplete",
+                                     "no conditions in <not>",
+                                     "You must nest a condition into <not>");
+    }
+
+    public void testAnd() {
+        expectPropertySet("and","and");
+    }
+
+    public void testAndFails() {
+        expectPropertyUnset("andfails","andfails");
+    }
+
+    public void testAndIncomplete() {
+        expectPropertyUnset("andincomplete","andincomplete");
+    }
+
+    public void testAndempty() {
+        expectPropertySet("andempty","andempty");
+    }
+
+    public void testOr() {
+        expectPropertySet("or","or");
+    }
+
+    public void testOrincomplete() {
+        expectPropertySet("or","or");
+    }
+
+    public void testOrFails() {
+        expectPropertyUnset("orfails","orfails");
+    }
+
+    public void testOrboth() {
+        expectPropertySet("orboth","orboth");
+    }
+
+    public void testFilesmatchIdentical() {
+        expectPropertySet("filesmatch-identical","filesmatch-identical");
+    }
+
+
+    public void testFilesmatchIncomplete() {
+        expectSpecificBuildException("filesmatch-incomplete",
+                                     "Missing file2 attribute",
+                                     "both file1 and file2 are required in filesmatch");
+    }
+
+    public void testFilesmatchOddsizes() {
+        expectPropertyUnset("filesmatch-oddsizes","filesmatch-oddsizes");
+    }
+
+    public void testFilesmatchExistence() {
+        expectPropertyUnset("filesmatch-existence", "filesmatch-existence");
+    }
+
+    public void testFilesmatchDifferent() {
+        expectPropertyUnset("filesmatch-different","filesmatch-different");
+    }
+
+    public void testFilesmatchMatch() {
+        expectPropertySet("filesmatch-match","filesmatch-match");
+    }
+
+    public void testFilesmatchDifferentSizes() {
+        expectPropertyUnset("filesmatch-different-sizes",
+            "filesmatch-different-sizes");
+    }
+
+    public void testFilesmatchDifferentOnemissing() {
+        expectPropertyUnset("filesmatch-different-onemissing",
+            "filesmatch-different-onemissing");
+    }
+
+    public void testFilesmatchDifferentEol() {
+        executeTarget("filesmatch-different-eol");
+    }
+
+    public void testFilesmatchSameEol() {
+        executeTarget("filesmatch-same-eol");
+    }
+
+    public void testFilesmatchNeitherExist() {
+        executeTarget("filesmatch-neitherexist");
+    }
+
+    public void testContains() {
+        expectPropertySet("contains","contains");
+    }
+
+
+    public void testContainsDoesnt() {
+        expectPropertyUnset("contains-doesnt","contains-doesnt");
+    }
+
+    public void testContainsAnycase() {
+        expectPropertySet("contains-anycase","contains-anycase");
+    }
+
+
+    public void testContainsIncomplete1() {
+        expectSpecificBuildException("contains-incomplete1",
+                    "Missing contains attribute",
+                    "both string and substring are required in contains");
+    }
+
+    public void testContainsIncomplete2() {
+        expectSpecificBuildException("contains-incomplete2",
+                    "Missing contains attribute",
+                    "both string and substring are required in contains");
+    }
+
+    public void testIstrue() {
+        expectPropertySet("istrue","istrue");
+    }
+
+    public void testIstrueNot() {
+        expectPropertyUnset("istrue-not","istrue-not");
+    }
+
+    public void testIstrueFalse() {
+        expectPropertyUnset("istrue-false","istrue-false");
+    }
+
+
+    public void testIstrueIncomplete1() {
+        expectSpecificBuildException("istrue-incomplete",
+                    "Missing attribute",
+                    "Nothing to test for truth");
+    }
+
+    public void testIsfalseTrue() {
+        expectPropertyUnset("isfalse-true","isfalse-true");
+    }
+
+    public void testIsfalseNot() {
+        expectPropertySet("isfalse-not","isfalse-not");
+    }
+
+    public void testIsfalseFalse() {
+        expectPropertySet("isfalse-false","isfalse-false");
+    }
+
+
+    public void testIsfalseIncomplete1() {
+        expectSpecificBuildException("isfalse-incomplete",
+                    "Missing attribute",
+                    "Nothing to test for falsehood");
+    }
+
+    public void testElse() {
+        executeTarget("testElse");
+    }
+
+    public void testResourcesmatchError() {
+        expectBuildException("resourcesmatch-error",
+            "should fail because no resources specified");
+    }
+
+    public void testResourcesmatchEmpty() {
+        executeTarget("resourcesmatch-match-empty");
+    }
+
+    public void testResourcesmatchOne() {
+        executeTarget("resourcesmatch-match-one");
+    }
+
+    public void testResourcesmatchBinary() {
+        executeTarget("resourcesmatch-match-binary");
+    }
+
+    public void testResourcesmatchMultipleBinary() {
+        executeTarget("resourcesmatch-match-multiple-binary");
+    }
+
+    public void testResourcesmatchDiffer() {
+        executeTarget("resourcesmatch-differ");
+    }
+
+    public void testResourcesmatchText() {
+        executeTarget("resourcesmatch-match-text");
+    }
+
+    public void testResourcesmatchNoneExist() {
+        executeTarget("resourcesmatch-noneexist");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyTest.java
new file mode 100644
index 0000000..f205b26
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyTest.java
@@ -0,0 +1,231 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Tests FileSet using the Copy task.
+ *
+ */
+public class CopyTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public CopyTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/copy.xml");
+    }
+
+    public void test1() {
+        executeTarget("test1");
+        File f = new File(getProjectDir(), "copytest1.tmp");
+        if ( !f.exists()) {
+            fail("Copy failed");
+        }
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test2() {
+        executeTarget("test2");
+        File f = new File(getProjectDir(), "copytest1dir/copy.xml");
+        if ( !f.exists()) {
+            fail("Copy failed");
+        }
+    }
+
+    public void test3() {
+        executeTarget("test3");
+        File file3  = new File(getProjectDir(), "copytest3.tmp");
+        assertTrue(file3.exists());
+        File file3a = new File(getProjectDir(), "copytest3a.tmp");
+        assertTrue(file3a.exists());
+        File file3b = new File(getProjectDir(), "copytest3b.tmp");
+        assertTrue(file3b.exists());
+        File file3c = new File(getProjectDir(), "copytest3c.tmp");
+        assertTrue(file3c.exists());
+
+        //file length checks rely on touch generating a zero byte file
+        if(file3.length()==0) {
+            fail("could not overwrite an existing, older file");
+        }
+        if(file3c.length()!=0) {
+            fail("could not force overwrite an existing, newer file");
+        }
+        if(file3b.length()==0) {
+            fail("unexpectedly overwrote an existing, newer file");
+        }
+
+        //file time checks for java1.2+
+        assertTrue(file3a.lastModified()==file3.lastModified());
+        assertTrue(file3c.lastModified()<file3a.lastModified());
+
+    }
+
+    public void testFilterTest() {
+        executeTarget("filtertest");
+        assertTrue(getOutput().indexOf("loop in tokens") == -1);
+    }
+
+    public void testInfiniteFilter() {
+        executeTarget("infinitetest");
+        assertTrue(getOutput().indexOf("loop in tokens") != -1);
+    }
+
+    public void testFilterSet() throws IOException {
+        executeTarget("testFilterSet");
+        File tmp  = new File(getProjectDir(), "copy.filterset.tmp");
+        File check  = new File(getProjectDir(), "expected/copy.filterset.filtered");
+        assertTrue(tmp.exists());
+        assertTrue(FILE_UTILS.contentEquals(tmp, check));
+    }
+
+    public void testFilterChain() throws IOException {
+        executeTarget("testFilterChain");
+        File tmp  = new File(getProjectDir(), "copy.filterchain.tmp");
+        File check  = new File(getProjectDir(), "expected/copy.filterset.filtered");
+        assertTrue(tmp.exists());
+        assertTrue(FILE_UTILS.contentEquals(tmp, check));
+    }
+
+    public void testSingleFileFileset() {
+        executeTarget("test_single_file_fileset");
+        File file  = new File(getProjectDir(),
+                                        "copytest_single_file_fileset.tmp");
+        assertTrue(file.exists());
+    }
+
+    public void testSingleFilePath() {
+        executeTarget("test_single_file_path");
+        File file  = new File(getProjectDir(),
+                                        "copytest_single_file_path.tmp");
+        assertTrue(file.exists());
+    }
+
+    public void testTranscoding() throws IOException {
+        executeTarget("testTranscoding");
+        File f1 = getProject().resolveFile("copy/expected/utf-8");
+        File f2 = getProject().resolveFile("copytest1.tmp");
+        assertTrue(FILE_UTILS.contentEquals(f1, f2));
+    }
+
+    public void testMissingFileIgnore() {
+        expectLogContaining("testMissingFileIgnore",
+                            "Warning: Could not find file ");
+    }
+
+    public void testMissingFileBail() {
+        expectBuildException("testMissingFileBail", "not-there doesn't exist");
+        assertTrue(getBuildException().getMessage()
+                   .startsWith("Warning: Could not find file "));
+    }
+
+    public void testMissingDirIgnore() {
+        expectLogContaining("testMissingDirIgnore", "Warning: ");
+    }
+
+    public void testMissingDirBail() {
+        expectBuildException("testMissingDirBail", "not-there doesn't exist");
+        assertTrue(getBuildException().getMessage().endsWith(" not found."));
+    }
+    
+    public void testFileResourcePlain() {
+        executeTarget("testFileResourcePlain");
+        File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt");
+        File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt");
+        File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt");
+        assertTrue(file1.exists());
+        assertTrue(file2.exists());
+        assertTrue(file3.exists());
+    }
+    
+    public void _testFileResourceWithMapper() {
+        executeTarget("testFileResourceWithMapper");
+        File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt.bak");
+        File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt.bak");
+        File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt.bak");
+        assertTrue(file1.exists());
+        assertTrue(file2.exists());
+        assertTrue(file3.exists());
+    }
+    
+    public void testFileResourceWithFilter() {
+        executeTarget("testFileResourceWithFilter");
+        File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/fileNR.txt");
+        assertTrue(file1.exists());
+        try {
+            String file1Content = FileUtils.readFully(new FileReader(file1));
+            assertEquals("This is file 42", file1Content);
+        } catch (IOException e) {
+            // no-op: not a real business error
+        }
+    }
+    
+    public void testPathAsResource() {
+        executeTarget("testPathAsResource");
+        File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt");
+        File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt");
+        File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt");
+        assertTrue(file1.exists());
+        assertTrue(file2.exists());
+        assertTrue(file3.exists());
+    }
+    
+    public void testZipfileset() {
+        executeTarget("testZipfileset");
+        File file1 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file1.txt");
+        File file2 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file2.txt");
+        File file3 = new File(getProjectDir(), getProject().getProperty("to.dir")+"/file3.txt");
+        assertTrue(file1.exists());
+        assertTrue(file2.exists());
+        assertTrue(file3.exists());
+    }
+
+    public void testDirset() {
+        executeTarget("testDirset");
+    }
+    
+    public void _testResourcePlain() {
+        executeTarget("testResourcePlain");
+    }
+    
+    public void _testResourcePlainWithMapper() {
+        executeTarget("testResourcePlainWithMapper");
+    }
+    
+    public void _testResourcePlainWithFilter() {
+        executeTarget("testResourcePlainWithFilter");
+    }
+    
+    public void _testOnlineResources() {
+        executeTarget("testOnlineResources");
+    }
+    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopydirTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopydirTest.java
new file mode 100644
index 0000000..eecac59
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopydirTest.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class CopydirTest extends BuildFileTest {
+
+    public CopydirTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/copydir.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    public void test4() {
+        expectLog("test4", "DEPRECATED - The copydir task is deprecated.  Use copy instead.Warning: src == dest");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        java.io.File f = new java.io.File(getProjectDir(), "../taskdefs.tmp");
+        if (!f.exists() || !f.isDirectory()) {
+            fail("Copy failed");
+        }
+        // We keep this, so we have something to delete in later tests :-)
+    }
+
+    public void test6() {
+        expectBuildException("test6", "target is file");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyfileTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyfileTest.java
new file mode 100644
index 0000000..e32c498
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/CopyfileTest.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class CopyfileTest extends BuildFileTest {
+
+    public void test6() {
+        expectBuildException("test6", "target is directory");
+    }
+
+    public CopyfileTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/copyfile.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    public void test4() {
+        expectLog("test4", "DEPRECATED - The copyfile task is deprecated.  Use copy instead.Warning: src == dest");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        java.io.File f = new java.io.File(getProjectDir(), "copyfile.tmp");
+        if (f.exists()) {
+            f.delete();
+        } else {
+            fail("Copy failed");
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DefaultExcludesTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DefaultExcludesTest.java
new file mode 100644
index 0000000..b26584d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DefaultExcludesTest.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DirectoryScanner;
+
+/**
+ */
+public class DefaultExcludesTest extends BuildFileTest {
+
+    public DefaultExcludesTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/defaultexcludes.xml");
+    }
+
+    public void tearDown() {
+        project.executeTarget("cleanup");
+    }
+
+    // Output the default excludes
+    public void test1() {
+        String[] expected = {
+                          "**/*~",
+                          "**/#*#",
+                          "**/.#*",
+                          "**/%*%",
+                          "**/._*",
+                          "**/CVS",
+                          "**/CVS/**",
+                          "**/.cvsignore",
+                          "**/SCCS",
+                          "**/SCCS/**",
+                          "**/vssver.scc",
+                          "**/.svn",
+                          "**/.svn/**",
+                          "**/.DS_Store"};
+        project.executeTarget("test1");
+        assertEquals("current default excludes", expected, DirectoryScanner.getDefaultExcludes());
+    }
+
+    // adding something to the excludes'
+    public void test2() {
+        String[] expected = {
+                          "**/*~",
+                          "**/#*#",
+                          "**/.#*",
+                          "**/%*%",
+                          "**/._*",
+                          "**/CVS",
+                          "**/CVS/**",
+                          "**/.cvsignore",
+                          "**/SCCS",
+                          "**/SCCS/**",
+                          "**/vssver.scc",
+                          "**/.svn",
+                          "**/.svn/**",
+                          "**/.DS_Store",
+                          "foo"};
+        project.executeTarget("test2");
+        assertEquals("current default excludes", expected, DirectoryScanner.getDefaultExcludes());
+    }
+
+    // removing something from the defaults
+    public void test3() {
+        String[] expected = {
+                          "**/*~",
+                          "**/#*#",
+                          "**/.#*",
+                          "**/%*%",
+                          "**/._*",
+                          //CVS missing
+                          "**/CVS/**",
+                          "**/.cvsignore",
+                          "**/SCCS",
+                          "**/SCCS/**",
+                          "**/vssver.scc",
+                          "**/.svn",
+                          "**/.svn/**",
+                          "**/.DS_Store"};
+        project.executeTarget("test3");
+        assertEquals("current default excludes", expected, DirectoryScanner.getDefaultExcludes());
+    }
+    private void assertEquals(String message, String[] expected, String[] actual) {
+        // check that both arrays have the same size
+        assertEquals(message + " : string array length match", expected.length, actual.length);
+        for (int counter=0; counter <expected.length; counter++) {
+            assertEquals(message + " : " + counter + "th element in array match", expected[counter], actual[counter]);
+        }
+
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeleteTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeleteTest.java
new file mode 100644
index 0000000..2ddc798
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeleteTest.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class DeleteTest extends BuildFileTest {
+
+    public DeleteTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/delete.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        executeTarget("test2");
+    }
+//where oh where has my test case 3 gone?
+    public void test4() {
+        executeTarget("test4");
+    }
+    public void test5() {
+        executeTarget("test5");
+    }
+    public void test6() {
+        executeTarget("test6");
+    }
+    public void test7() {
+        executeTarget("test7");
+    }
+    public void test8() {
+        executeTarget("test8");
+    }
+    public void test9() {
+        executeTarget("test9");
+    }
+    public void test10() {
+        executeTarget("test10");
+    }
+    public void test11() {
+        executeTarget("test11");
+    }
+    public void test12() {
+        executeTarget("test12");
+    }
+    public void test13() {
+        executeTarget("test13");
+    }
+    public void test14() {
+        executeTarget("test14");
+    }
+    public void test15() {
+        executeTarget("test15");
+    }
+    public void test16() {
+        executeTarget("test16");
+    }
+    public void test17() {
+        executeTarget("test17");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeltreeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeltreeTest.java
new file mode 100644
index 0000000..62040a9
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DeltreeTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class DeltreeTest extends BuildFileTest {
+
+    public DeltreeTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/deltree.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        // We try to delete the directory created in CopydirTest
+        executeTarget("test2");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DemuxOutputTask.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DemuxOutputTask.java
new file mode 100644
index 0000000..e5e3b2f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DemuxOutputTask.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Random;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * A simple task that prints to System.out and System.err and then catches
+ * the output which it then checks. If the output does not match, an
+ * exception is thrown
+ *
+ * @since 1.5
+ * @created 21 February 2002
+ */
+public class DemuxOutputTask extends Task {
+    private String randomOutValue;
+    private String randomErrValue;
+    private boolean outputReceived = false;
+    private boolean errorReceived = false;
+
+    public void execute() {
+        Random generator = new Random();
+        randomOutValue = "Output Value is " + generator.nextInt();
+        randomErrValue = "Error Value is " + generator.nextInt();
+
+        System.out.println(randomOutValue);
+        System.err.println(randomErrValue);
+        if (!outputReceived) {
+            throw new BuildException("Did not receive output");
+        }
+
+        if (!errorReceived) {
+            throw new BuildException("Did not receive error");
+        }
+    }
+
+    protected void handleOutput(String line) {
+        line = line.trim();
+        if (line.length() != 0 && !line.equals(randomOutValue)) {
+            String message = "Received = [" + line + "], expected = ["
+                + randomOutValue + "]";
+            throw new BuildException(message);
+        }
+        outputReceived = true;
+    }
+
+    protected void handleErrorOutput(String line) {
+        line = line.trim();
+        if (line.length() != 0 && !line.equals(randomErrValue)) {
+            String message = "Received = [" + line + "], expected = ["
+                + randomErrValue + "]";
+            throw new BuildException(message);
+        }
+        errorReceived = true;
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DirnameTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DirnameTest.java
new file mode 100644
index 0000000..7a5b929
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DirnameTest.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ */
+public class DirnameTest extends BuildFileTest {
+
+    public DirnameTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/dirname.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "property attribute required");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "file attribute required");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "property attribute required");
+    }
+
+    public void test4() {
+        if (Os.isFamily("netware") || Os.isFamily("dos")) {
+            return;
+        }
+        executeTarget("test4");
+        String filesep = System.getProperty("file.separator");
+        String expected = filesep + "usr" + filesep + "local";
+        String checkprop = project.getProperty("local.dir");
+        if (!checkprop.equals(expected)) {
+            fail("dirname failed");
+        }
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        String expected = project.getProperty("basedir");
+        String checkprop = project.getProperty("base.dir");
+        if (!checkprop.equals(expected)) {
+            fail("dirname failed");
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTask.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTask.java
new file mode 100644
index 0000000..0d4b6cd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTask.java
@@ -0,0 +1,46 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.DynamicConfigurator;
+import org.apache.tools.ant.Task;
+
+public class DynamicTask extends Task implements DynamicConfigurator {
+
+    public void execute() {
+    }
+
+    public void setDynamicAttribute(String name, String value) {
+        getProject().setNewProperty(name, value);
+    }
+
+    public Object createDynamicElement(String name) {
+        return new Sub();
+    }
+
+    public class Sub implements DynamicConfigurator {
+        public void setDynamicAttribute(String name, String value) {
+            getProject().setNewProperty(name, value);
+        }
+
+        public Object createDynamicElement(String name) {
+            return null;
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTest.java
new file mode 100644
index 0000000..de44261
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/DynamicTest.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class DynamicTest extends BuildFileTest {
+
+    public DynamicTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/dynamictask.xml");
+    }
+
+    public void testSimple() {
+        executeTarget("simple");
+        assertEquals("1", project.getProperty("prop1"));
+        assertEquals("2", project.getProperty("prop2"));
+        assertEquals("3", project.getProperty("prop3"));
+        assertEquals("4", project.getProperty("prop4"));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java
new file mode 100644
index 0000000..1cd9263
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoTest.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.Project;
+
+/**
+ */
+public class EchoTest extends BuildFileTest {
+
+    public EchoTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/echo.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    // Output an empty String
+    public void test1() {
+        expectLog("test1", "");
+    }
+    
+    public void testLogBlankEcho() {
+        EchoTestLogger logger = new EchoTestLogger();
+        getProject().addBuildListener(logger);
+        getProject().executeTarget("test1");
+        assertEquals("     [echo] ", logger.lastLoggedMessage );
+    }
+ 
+    // Output 'OUTPUT OF ECHO'
+    public void test2() {
+        expectLog("test2", "OUTPUT OF ECHO");
+    }
+
+    public void test3() {
+        expectLog("test3", "\n"+
+                              "    This \n"+
+                              "    is\n"+
+                              "    a \n"+
+                              "    multiline\n"+
+                              "    message\n"+
+                              "    ");
+    }
+
+    public void testFile() throws Exception {
+        executeTarget("testFile");
+    }
+
+    public void testAppend() throws Exception {
+        executeTarget("testAppend");
+    }
+
+    public void testEmptyEncoding() throws Exception {
+        executeTarget("testEmptyEncoding");
+    }
+
+    public void testUTF16Encoding() throws Exception {
+        executeTarget("testUTF16Encoding");
+    }
+    public void testUTF8Encoding() throws Exception {
+        executeTarget("testUTF8Encoding");
+    }
+    
+    private class EchoTestLogger extends DefaultLogger {
+        String lastLoggedMessage;
+    
+        
+        /**
+         * 
+         */
+        public EchoTestLogger() {
+            super();
+            this.setMessageOutputLevel(Project.MSG_DEBUG);
+            this.setOutputPrintStream(new PrintStream(new ByteArrayOutputStream(256)));
+            this.setErrorPrintStream(new PrintStream(new ByteArrayOutputStream(256)));
+        }
+        /* 
+         * @param message
+         */
+        protected void log(String message) {
+            this.lastLoggedMessage = message;
+        }
+        
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoXMLTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoXMLTest.java
new file mode 100755
index 0000000..2cf2817
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/EchoXMLTest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class EchoXMLTest extends BuildFileTest {
+
+    public EchoXMLTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/echoxml.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void testPass() {
+        executeTarget("testPass");
+    }
+
+    public void testFail() {
+        expectBuildExceptionContaining("testFail", "must fail", "${foo}=bar");
+    }
+
+    public void testEmpty() {
+        expectBuildExceptionContaining("testEmpty", "must fail", "No nested XML specified");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecTaskTest.java
new file mode 100644
index 0000000..d3a143f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecTaskTest.java
@@ -0,0 +1,491 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.*;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.GregorianCalendar;
+
+import junit.framework.ComparisonFailure;
+
+/**
+ * Unit test for the &lt;exec&gt; task.
+ */
+public class ExecTaskTest extends BuildFileTest {
+    private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/";
+    private static final String BUILD_FILE = BUILD_PATH + "exec.xml";
+    private static final int TIME_TO_WAIT = 1;
+    /** maximum time allowed for the build in milliseconds */
+    private static final int MAX_BUILD_TIME = 4000;
+    private static final int SECURITY_MARGIN = 2000; // wait 2 second extras
+    // the test failed with 100 ms of margin on cvs.apache.org on August 1st, 2003
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File logFile;
+    private MonitoredBuild myBuild = null;
+    volatile private boolean buildFinished = false;
+    public ExecTaskTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(BUILD_FILE);
+    }
+
+    public void tearDown() {
+        if (logFile != null && logFile.exists()) {
+            getProject().setProperty("logFile", logFile.getAbsolutePath());
+        }
+        executeTarget("cleanup");
+    }
+
+    public void testNoRedirect() {
+        executeTarget("no-redirect");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        assertEquals("unexpected log content",
+            getProject().getProperty("ant.file") + " out"
+            + getProject().getProperty("ant.file") + " err", getLog());
+    }
+
+    public void testRedirect1() throws IOException {
+        executeTarget("redirect1");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String expectedOut = getProject().getProperty("ant.file") + " out\n"
+            + getProject().getProperty("ant.file") + " err\n";
+
+        assertEquals("unexpected output",
+            expectedOut, getFileString("redirect.out"));
+    }
+
+    public void testRedirect2() throws IOException {
+        executeTarget("redirect2");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output",
+            getProject().getProperty("ant.file") + " out\n",
+            getFileString("redirect.out"));
+        assertEquals("unexpected error output",
+            getProject().getProperty("ant.file") + " err\n",
+            getFileString("redirect.err"));
+    }
+
+    public void testRedirect3() throws IOException {
+        executeTarget("redirect3");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        assertEquals("unexpected log content",
+            getProject().getProperty("ant.file") + " err", getLog());
+        String expectedOut = getProject().getProperty("ant.file") + " out\n";
+
+        assertEquals("unexpected output",
+            expectedOut, getFileString("redirect.out"));
+        assertPropertyEquals("redirect.out", expectedOut.trim());
+    }
+
+    public void testRedirect4() throws IOException {
+        executeTarget("redirect4");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String expectedOut = getProject().getProperty("ant.file") + " out\n";
+        String expectedErr = getProject().getProperty("ant.file") + " err\n";
+
+        assertEquals("unexpected output",
+            expectedOut, getFileString("redirect.out"));
+        assertPropertyEquals("redirect.out", expectedOut.trim());
+        assertEquals("unexpected error output",
+            expectedErr, getFileString("redirect.err"));
+        assertPropertyEquals("redirect.err", expectedErr.trim());
+    }
+
+    public void testRedirect5() throws IOException {
+        testRedirect5or6("redirect5");
+    }
+
+    public void testRedirect6() throws IOException {
+        testRedirect5or6("redirect6");
+    }
+
+    public void testRedirect5or6(String target) throws IOException {
+        executeTarget(target);
+        if (getProject().getProperty("wc.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output", "3", getFileString("redirect.out").trim());
+        assertEquals("property redirect.out", "3",
+            getProject().getProperty("redirect.out").trim());
+        assertNull("unexpected error output", getFileString("redirect.err"));
+        assertPropertyEquals("redirect.err", "");
+    }
+
+    public void testRedirect7() throws IOException {
+        executeTarget("redirect7");
+        if (getProject().getProperty("wc.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output", "3", getFileString("redirect.out").trim());
+        assertEquals("property redirect.out", "3",
+            getProject().getProperty("redirect.out").trim());
+        assertNull("unexpected error output", getFileString("redirect.err"));
+    }
+
+    public void testRedirector1() {
+        executeTarget("init");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        expectBuildException("redirector1", "cannot have > 1 nested <redirector>s");
+    }
+
+    public void testRedirector2() throws IOException {
+        executeTarget("redirector2");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output",
+            getProject().getProperty("ant.file") + " out\n"
+            + getProject().getProperty("ant.file") + " err\n",
+            getFileString("redirector.out"));
+    }
+
+    public void testRedirector3() throws IOException {
+        executeTarget("redirector3");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output",
+            getProject().getProperty("ant.file") + " out\n",
+            getFileString("redirector.out"));
+        assertEquals("unexpected error output",
+            getProject().getProperty("ant.file") + " err\n",
+            getFileString("redirector.err"));
+    }
+
+    public void testRedirector4() throws IOException {
+        executeTarget("redirector4");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String expectedOut = getProject().getProperty("ant.file") + " out\n";
+
+        assertEquals("unexpected log content",
+            getProject().getProperty("ant.file") + " err", getLog());
+        assertEquals("unexpected output", expectedOut,
+            getFileString("redirector.out"));
+        assertPropertyEquals("redirector.out", expectedOut.trim());
+    }
+
+    public void testRedirector5() throws IOException {
+        testRedirector5or6("redirector5");
+    }
+
+    public void testRedirector6() throws IOException {
+        testRedirector5or6("redirector6");
+    }
+
+    private void testRedirector5or6(String target) throws IOException {
+        executeTarget(target);
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String expectedOut = getProject().getProperty("ant.file") + " out\n";
+        String expectedErr = getProject().getProperty("ant.file") + " err\n";
+
+        assertEquals("unexpected output", expectedOut,
+            getFileString("redirector.out"));
+        assertPropertyEquals("redirector.out", expectedOut.trim());
+        assertEquals("unexpected error output", expectedErr,
+            getFileString("redirector.err"));
+        assertPropertyEquals("redirector.err", expectedErr.trim());
+    }
+
+    public void testRedirector7() throws IOException {
+        executeTarget("redirector7");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String expectedOut = getProject().getProperty("ant.file") + " out\n";
+        String expectedErr = getProject().getProperty("ant.file") + " ERROR!!!\n";
+
+        assertEquals("unexpected output", expectedOut,
+            getFileString("redirector.out"));
+        assertPropertyEquals("redirector.out", expectedOut.trim());
+        assertEquals("unexpected error output", expectedErr,
+            getFileString("redirector.err"));
+        assertPropertyEquals("redirector.err", expectedErr.trim());
+    }
+
+    public void testRedirector8() throws IOException {
+        executeTarget("redirector8");
+        if (getProject().getProperty("wc.can.run") == null) {
+            return;
+        }
+
+        assertEquals("unexpected output", "3", getFileString("redirector.out").trim());
+        assertEquals("property redirector.out", "3",
+            getProject().getProperty("redirector.out").trim());
+        assertNull("unexpected error output", getFileString("redirector.err"));
+        assertPropertyEquals("redirector.err", "");
+    }
+
+    public void testRedirector9() throws IOException {
+        testRedirector9Thru12("redirector9");
+    }
+
+    public void testRedirector10() throws IOException {
+        testRedirector9Thru12("redirector10");
+    }
+
+    public void testRedirector11() throws IOException {
+        testRedirector9Thru12("redirector11");
+    }
+
+    public void testRedirector12() throws IOException {
+        testRedirector9Thru12("redirector12");
+    }
+
+    private void testRedirector9Thru12(String target) throws IOException {
+        executeTarget(target);
+        if (getProject().getProperty("cat.can.run") == null) {
+            return;
+        }
+        String expectedOut = "blah after blah";
+
+        assertEquals("unexpected output",
+            expectedOut, getFileString("redirector.out").trim());
+        assertPropertyEquals("redirector.out", expectedOut.trim());
+        assertNull("unexpected error output", getFileString("redirector.err"));
+        assertPropertyEquals("redirector.err", "");
+    }
+
+    public void testRedirector13() {
+        executeTarget("redirector13");
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        String antfile = getProject().getProperty("ant.file");
+        try {
+            //no point in setting a message
+            assertEquals(antfile + " OUTPUT???" + antfile + " ERROR!!!", getLog());
+        } catch (ComparisonFailure cf) {
+            assertEquals("unexpected log content",
+                antfile + " ERROR!!!" + antfile + " OUTPUT???", getLog());
+        }
+    }
+
+    public void testRedirector14() {
+        executeTarget("redirector14");
+        if (getProject().getProperty("cat.can.run") == null) {
+            return;
+        }
+        assertEquals("unexpected log output", "blah after blah", getLog());
+    }
+
+    public void testRedirector15() throws IOException {
+        executeTarget("redirector15");
+        if (getProject().getProperty("cat.can.run") == null) {
+            return;
+        }
+        assertTrue("error with transcoding",
+            FILE_UTILS.contentEquals(
+            getProject().resolveFile("expected/utf-8"),
+            getProject().resolveFile("redirector.out")));
+    }
+
+    public void testRedirector16() {
+        executeTarget("redirector16");
+    }
+
+    public void testRedirector17() {
+        executeTarget("redirector17");
+    }
+
+    public void testRedirector18() {
+        if (getProject().getProperty("test.can.run") == null) {
+            return;
+        }
+        expectLog("redirector18", getProject().getProperty("ant.file")
+            + " out" + getProject().getProperty("ant.file") + " err");
+    }
+
+    public void testspawn() {
+        project.executeTarget("init");
+        if (project.getProperty("test.can.run") == null) {
+            return;
+        }
+        myBuild = new MonitoredBuild(new File(System.getProperty("root"), BUILD_FILE), "spawn");
+        logFile = FILE_UTILS.createTempFile("spawn","log", project.getBaseDir(), false, false);
+        // this is guaranteed by FileUtils#createTempFile
+        assertTrue("log file not existing", !logFile.exists());
+        // make the spawned process run 4 seconds
+        myBuild.setTimeToWait(TIME_TO_WAIT);
+        myBuild.setLogFile(logFile.getAbsolutePath());
+        myBuild.addBuildListener(new MonitoredBuildListener());
+        myBuild.start();
+        GregorianCalendar startwait = new GregorianCalendar();
+        // this loop runs parallel to the build
+        while (!buildFinished) {
+            try {
+                Thread.sleep(10);
+            } catch (InterruptedException e) {
+                System.out.println("my sleep was interrupted");
+            }
+            GregorianCalendar now = new GregorianCalendar();
+            // security
+            if (now.getTime().getTime() - startwait.getTime().getTime() > MAX_BUILD_TIME) {
+                System.out.println("aborting wait, too long " + (now.getTime().getTime() - startwait.getTime().getTime()) + "milliseconds");
+                break;
+            }
+        }
+        // now wait until the spawned process is finished
+        try {
+            Thread.sleep((TIME_TO_WAIT) * 1000 + SECURITY_MARGIN);
+        } catch (InterruptedException e) {
+            System.out.println("my sleep was interrupted");
+        }
+        // time of the build in milli seconds
+        long elapsed = myBuild.getTimeElapsed();
+        assertTrue("we waited more than the process lasted", TIME_TO_WAIT * 1000
+                + SECURITY_MARGIN > elapsed);
+        logFile = new File(logFile.getAbsolutePath());
+        assertTrue("log file found after spawn", logFile.exists());
+    }
+
+    public void testExecUnknownOS() {
+        executeTarget("testExecUnknownOS");
+    }
+
+    public void testExecOSFamily() {
+        executeTarget("testExecOSFamily");
+    }
+
+    public void testExecInconsistentSettings() {
+        executeTarget("testExecInconsistentSettings");
+    }
+    
+    private static class MonitoredBuild implements Runnable {
+        private Thread worker;
+        private File myBuildFile = null;
+        private String target = null;
+        private Project project = null;
+        private int timeToWait = 0;
+        private String logFile = null;
+        private GregorianCalendar timeStarted = null;
+        private GregorianCalendar timeFinished = null;
+
+        public void setLogFile(String logFile) {
+            this.logFile = logFile;
+            project.setProperty("logFile", logFile);
+        }
+
+        public void setTimeToWait(int timeToWait) {
+            this.timeToWait = timeToWait;
+            project.setProperty("timeToWait", Long.toString(timeToWait));
+        }
+
+        public void addBuildListener(BuildListener bl) {
+            project.addBuildListener(bl);
+        }
+        public MonitoredBuild(File buildFile, String target) {
+            myBuildFile = buildFile;
+            this.target = target;
+            project=new Project();
+            project = new Project();
+            project.init();
+            project.setUserProperty( "ant.file" , myBuildFile.getAbsolutePath() );
+            ProjectHelper.configureProject(project, myBuildFile);
+        }
+        /**
+         *
+         * @return time in millis of the build
+         */
+        public long getTimeElapsed() {
+            return timeFinished.getTime().getTime() - timeStarted.getTime().getTime();
+        }
+        public void start() {
+            worker = new Thread(this, myBuildFile.toString() + "/" + target);
+            worker.start();
+        }
+        public void run() {
+            startProject();
+        }
+        private void startProject() {
+            timeStarted = new GregorianCalendar();
+            project.executeTarget(target);
+            timeFinished = new GregorianCalendar();
+        }
+    }
+    private class MonitoredBuildListener implements BuildListener {
+        public void buildStarted(BuildEvent event) {
+        }
+
+        public void buildFinished(BuildEvent event) {
+        }
+
+        public void targetStarted(BuildEvent event) {
+        }
+
+        public void targetFinished(BuildEvent event) {
+            if (event.getTarget().getName().equals("spawn")) {
+                buildFinished = true;
+            }
+        }
+
+        public void taskStarted(BuildEvent event) {
+        }
+
+        public void taskFinished(BuildEvent event) {
+        }
+
+        public void messageLogged(BuildEvent event) {
+        }
+    }
+
+    //borrowed from TokenFilterTest
+    private String getFileString(String filename) throws IOException {
+        String result = null;
+        FileReader reader = null;
+        try {
+            reader = new FileReader(getProject().resolveFile(filename));
+            result = FileUtils.readFully(reader);
+        } catch (IOException eyeOhEx) {
+        } finally {
+            FileUtils.close(reader);
+        }
+        return result;
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java
new file mode 100644
index 0000000..09e23bb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Simple testcase for the ExecuteJava class - mostly stolen from
+ * ExecuteWatchdogTest.
+ *
+ */
+public class ExecuteJavaTest extends TestCase {
+
+    private final static int TIME_OUT = 5000;
+
+    private final static int CLOCK_ERROR=200;
+    private final static int TIME_OUT_TEST=TIME_OUT-CLOCK_ERROR;
+
+    private ExecuteJava ej;
+    private Project project;
+    private Path cp;
+
+    public ExecuteJavaTest(String name) {
+        super(name);
+    }
+
+    protected void setUp(){
+        ej = new ExecuteJava();
+        ej.setTimeout(new Long(TIME_OUT));
+        project = new Project();
+        project.setBasedir(".");
+        project.setProperty(MagicNames.ANT_HOME, System.getProperty(MagicNames.ANT_HOME));
+        cp = new Path(project, getTestClassPath());
+        ej.setClasspath(cp);
+    }
+
+    private Commandline getCommandline(int timetorun) throws Exception {
+        Commandline cmd = new Commandline();
+        cmd.setExecutable(TimeProcess.class.getName());
+        cmd.createArgument().setValue(String.valueOf(timetorun));
+        return cmd;
+    }
+
+    public void testNoTimeOut() throws Exception {
+        Commandline cmd = getCommandline(TIME_OUT/2);
+        ej.setJavaCommand(cmd);
+        ej.execute(project);
+        assertTrue("process should not have been killed", !ej.killedProcess());
+    }
+
+    // test that the watchdog ends the process
+    public void testTimeOut() throws Exception {
+        Commandline cmd = getCommandline(TIME_OUT*2);
+        ej.setJavaCommand(cmd);
+        long now = System.currentTimeMillis();
+        ej.execute(project);
+        long elapsed = System.currentTimeMillis() - now;
+        assertTrue("process should have been killed", ej.killedProcess());
+
+        assertTrue("elapse time of "+elapsed
+                   +" ms is less than timeout value of "+TIME_OUT_TEST+" ms",
+                   elapsed >= TIME_OUT_TEST);
+        assertTrue("elapse time of "+elapsed
+                   +" ms is greater than run value of "+(TIME_OUT*2)+" ms",
+                   elapsed < TIME_OUT*2);
+    }
+
+
+    public void testNoTimeOutForked() throws Exception {
+        Commandline cmd = getCommandline(TIME_OUT/2);
+        ej.setJavaCommand(cmd);
+        ej.fork(cp);
+        assertTrue("process should not have been killed", !ej.killedProcess());
+    }
+
+    // test that the watchdog ends the process
+    public void testTimeOutForked() throws Exception {
+        //process doesn't die properly under this combination,
+        //thus test fails.  No workaround?
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+            && Os.isFamily("dos")) {
+            return;
+        }
+        Commandline cmd = getCommandline(TIME_OUT*2);
+        ej.setJavaCommand(cmd);
+        long now = System.currentTimeMillis();
+        ej.fork(cp);
+        long elapsed = System.currentTimeMillis() - now;
+        assertTrue("process should have been killed", ej.killedProcess());
+
+        assertTrue("elapse time of "+elapsed
+                   +" ms is less than timeout value of "+TIME_OUT_TEST+" ms",
+                   elapsed >= TIME_OUT_TEST);
+        assertTrue("elapse time of "+elapsed
+                   +" ms is greater than run value of "+(TIME_OUT*2)+" ms",
+                   elapsed < TIME_OUT*2);
+    }
+
+    /**
+     * Dangerous method to obtain the classpath for the test. This is
+     * severely tighted to the build.xml properties.
+     */
+    private static String getTestClassPath(){
+        String classpath = System.getProperty("build.tests");
+        if (classpath == null) {
+            System.err.println("WARNING: 'build.tests' property is not available !");
+            classpath = System.getProperty("java.class.path");
+        }
+
+        return classpath;
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteWatchdogTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteWatchdogTest.java
new file mode 100644
index 0000000..92c4a10
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ExecuteWatchdogTest.java
@@ -0,0 +1,153 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.util.JavaEnvUtils;
+import junit.framework.*;
+import java.io.*;
+
+/**
+ * Simple testcase for the ExecuteWatchdog class.
+ *
+ */
+public class ExecuteWatchdogTest extends TestCase {
+
+    private final static long TIME_OUT = 5000;
+
+    private final static String TEST_CLASSPATH = getTestClassPath();
+
+    private final static int CLOCK_ERROR=200;
+    private final static long TIME_OUT_TEST=TIME_OUT-CLOCK_ERROR;
+
+    private ExecuteWatchdog watchdog;
+
+    public ExecuteWatchdogTest(String name) {
+        super(name);
+    }
+
+    protected void setUp(){
+        watchdog = new ExecuteWatchdog(TIME_OUT);
+    }
+
+    /**
+     * Dangerous method to obtain the classpath for the test. This is
+     * severely tighted to the build.xml properties.
+     */
+    private static String getTestClassPath(){
+        String classpath = System.getProperty("build.tests");
+        if (classpath == null) {
+            System.err.println("WARNING: 'build.tests' property is not available !");
+            classpath = System.getProperty("java.class.path");
+        }
+
+        return classpath;
+    }
+
+    private Process getProcess(long timetorun) throws Exception {
+        String[] cmdArray = {
+            JavaEnvUtils.getJreExecutable("java"), "-classpath", TEST_CLASSPATH,
+            TimeProcess.class.getName(), String.valueOf(timetorun)
+        };
+        //System.out.println("Testing with classpath: " + System.getProperty("java.class.path"));
+        return Runtime.getRuntime().exec(cmdArray);
+    }
+
+    private String getErrorOutput(Process p) throws Exception {
+        BufferedReader err = new BufferedReader( new InputStreamReader(p.getErrorStream()) );
+        StringBuffer buf = new StringBuffer();
+        String line;
+        while ( (line = err.readLine()) != null){
+            buf.append(line);
+        }
+        return buf.toString();
+    }
+
+    private int waitForEnd(Process p) throws Exception {
+        int retcode = p.waitFor();
+        if (retcode != 0){
+            String err = getErrorOutput(p);
+            if (err.length() > 0){
+                System.err.println("ERROR:");
+                System.err.println(err);
+            }
+        }
+        return retcode;
+    }
+
+    public void testNoTimeOut() throws Exception {
+        Process process = getProcess(TIME_OUT/2);
+        watchdog.start(process);
+        int retCode = waitForEnd(process);
+        assertTrue("process should not have been killed", !watchdog.killedProcess());
+        assertFalse(Execute.isFailure(retCode));
+    }
+
+    // test that the watchdog ends the process
+    public void testTimeOut() throws Exception {
+        Process process = getProcess(TIME_OUT*2);
+        long now = System.currentTimeMillis();
+        watchdog.start(process);
+        int retCode = process.waitFor();
+        long elapsed = System.currentTimeMillis() - now;
+        assertTrue("process should have been killed", watchdog.killedProcess());
+                //      assertTrue("return code is invalid: " + retCode, retCode!=0);
+        assertTrue("elapse time of "+elapsed+" ms is less than timeout value of "+TIME_OUT_TEST+" ms", elapsed >= TIME_OUT_TEST);
+        assertTrue("elapse time of "+elapsed+" ms is greater than run value of "+(TIME_OUT*2)+" ms", elapsed < TIME_OUT*2);
+    }
+
+    // test a process that runs and failed
+    public void testFailed() throws Exception {
+        Process process = getProcess(-1); // process should abort
+        watchdog.start(process);
+        int retCode = process.waitFor();
+        assertTrue("process should not have been killed", !watchdog.killedProcess());
+        assertTrue("return code is invalid: " + retCode, retCode!=0);
+    }
+
+    public void testManualStop() throws Exception {
+        final Process process = getProcess(TIME_OUT*2);
+        watchdog.start(process);
+
+        // I assume that starting this takes less than TIME_OUT/2 ms...
+        Thread thread = new Thread(){
+                public void run(){
+                    try {
+                        process.waitFor();
+                    } catch(InterruptedException e){
+                        // not very nice but will do the job
+                        fail("process interrupted in thread");
+                    }
+                }
+        };
+        thread.start();
+
+        // wait for TIME_OUT/2, there should be about TIME_OUT/2 ms remaining before timeout
+        thread.join(TIME_OUT/2);
+
+         // now stop the watchdog.
+        watchdog.stop();
+
+        // wait for the thread to die, should be the end of the process
+        thread.join();
+
+        // process should be dead and well finished
+        assertEquals(0, process.exitValue());
+        assertTrue("process should not have been killed", !watchdog.killedProcess());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FailTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FailTest.java
new file mode 100644
index 0000000..5628fbb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FailTest.java
@@ -0,0 +1,164 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class FailTest extends BuildFileTest {
+
+    public FailTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/fail.xml");
+    }
+
+    public void test1() {
+        expectBuildExceptionContaining("test1",
+                "it is required to fail :-)",
+                "No message");
+    }
+
+    public void test2() {
+        expectSpecificBuildException("test2",
+            "it is required to fail :-)",
+            "test2");
+    }
+
+    public void testText() {
+        expectSpecificBuildException("testText",
+            "it is required to fail :-)",
+            "testText");
+    }
+
+    public void testIf() {
+        try {
+            executeTarget("testIf");
+        } catch (BuildException be) {
+            fail("foo has not been defined, testIf must not fail");
+        }
+        project.setProperty("foo", "");
+        expectBuildException("testIf", "testIf must fail if foo has been set");
+    }
+
+    public void testUnless() {
+        expectBuildException("testUnless",
+                             "testUnless must fail unless foo has been set");
+        project.setProperty("foo", "");
+        try {
+            executeTarget("testUnless");
+        } catch (BuildException be) {
+            fail("foo has been defined, testUnless must not fail");
+        }
+    }
+
+    /**
+     * see that the different combinations work, and
+     * that the autogenerated text contains information
+     * about which condition was not met
+     */
+    public void testIfAndUnless() {
+        //neither
+        executeTarget("testIfAndUnless");
+        project.setProperty("if", "");
+        expectBuildExceptionContaining("testIfAndUnless",
+                "expect fail on defined(if)",
+                "if=if and unless=unless");
+        project.setProperty("unless", "");
+        //this call should succeed as unless overrides if
+        executeTarget("testIfAndUnless");
+    }
+    /**
+     * see that the different combinations work, and
+     * that the autogenerated text contains information
+     * about which condition was not met
+     */
+    public void testIfAndUnless2() {
+        project.setProperty("unless", "");
+        try {
+            executeTarget("testIfAndUnless");
+        } catch (BuildException be) {
+            fail("defined(if) && !defined(unless); testIfAndUnless must not fail");
+        }
+    }
+
+    public void testNested1() {
+        expectSpecificBuildException("testNested1",
+            "it is required to fail :-)",
+            "condition satisfied");
+    }
+
+    public void testNested2() {
+        try {
+            executeTarget("testNested2");
+        } catch (BuildException be) {
+            fail("condition not satisfied; testNested2 must not fail");
+        }
+    }
+
+    public void testNested3() {
+        expectSpecificBuildException("testNested3",
+            "it is required to fail :-)",
+            "testNested3");
+    }
+
+    public void testNested4() {
+        String specificMessage = "Nested conditions "
+          + "not permitted in conjunction with if/unless attributes";
+
+        char[] c = {'a', 'b', 'c'};
+        StringBuffer target = new StringBuffer("testNested4x");
+
+        for (int i = 0; i < c.length; i++) {
+            target.setCharAt(target.length() - 1, c[i]);
+            expectSpecificBuildException(target.toString(),
+                "it is required to fail :-)", specificMessage);
+        }
+    }
+
+    public void testNested5() {
+        expectSpecificBuildException("testNested5",
+            "it is required to fail :-)",
+            "Only one nested condition is allowed.");
+    }
+
+    public void testNested6() {
+        expectSpecificBuildException("testNested6",
+            "it is required to fail :-)",
+            "testNested6\ntestNested6\ntestNested6");
+    }
+
+    public void testNested7() {
+        String specificMessage = "A single nested condition is required.";
+
+        char[] c = {'a', 'b'};
+        StringBuffer target = new StringBuffer("testNested7x");
+
+        for (int i = 0; i < c.length; i++) {
+            target.setCharAt(target.length() - 1, c[i]);
+            expectSpecificBuildException(target.toString(),
+                "it is required to fail :-)", specificMessage);
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FilterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FilterTest.java
new file mode 100644
index 0000000..c4e9efb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FilterTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class FilterTest extends BuildFileTest {
+
+    public FilterTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/filter.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument missing");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument missing");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        assertEquals("2000",
+                     getFilteredFile("5", "filtered.tmp"));
+    }
+
+
+    public void test6() {
+        executeTarget("test6");
+        assertEquals("2000",
+                     getFilteredFile("6", "taskdefs.tmp/filter1.txt"));
+    }
+
+    public void test7() {
+        executeTarget("test7");
+        assertEquals("<%@ include file=\"root/some/include.jsp\"%>",
+                     getFilteredFile("7", "filtered.tmp"));
+    }
+
+    public void test8() {
+        executeTarget("test8");
+        assertEquals("<%@ include file=\"root/some/include.jsp\"%>",
+                     getFilteredFile("8", "taskdefs.tmp/filter2.txt"));
+    }
+
+    public void test9() {
+        executeTarget("test9");
+        assertEquals("included",
+                    getFilteredFile("9", "taskdefs.tmp/filter3.txt"));
+    }
+
+    private String getFilteredFile(String testNumber, String filteredFile) {
+
+        String line = null;
+        File f = new File(getProjectDir(), filteredFile);
+        if (!f.exists()) {
+            fail("filter test"+testNumber+" failed");
+        } else {
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new FileReader(f));
+            } catch (FileNotFoundException fnfe) {
+                fail("filter test"+testNumber+" failed, filtered file: " + f.toString() + " not found");
+            }
+            try {
+                line = in.readLine();
+                in.close();
+            } catch (IOException ioe) {
+                fail("filter test"+testNumber+" failed.  IOException while reading filtered file: " + ioe);
+            }
+        }
+        f.delete();
+        return line;
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FixCrLfTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FixCrLfTest.java
new file mode 100644
index 0000000..98b2cb2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/FixCrLfTest.java
@@ -0,0 +1,219 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class FixCrLfTest extends BuildFileTest {
+
+    public FixCrLfTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/fixcrlf/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() throws IOException {
+        executeTarget("test1");
+    }
+
+    public void test2() throws IOException {
+        executeTarget("test2");
+    }
+
+    public void test3() throws IOException {
+        executeTarget("test3");
+    }
+
+    public void test4() throws IOException {
+        executeTarget("test4");
+    }
+
+    public void test5() throws IOException {
+        executeTarget("test5");
+    }
+
+    public void test6() throws IOException {
+        executeTarget("test6");
+    }
+
+    public void test7() throws IOException {
+        executeTarget("test7");
+    }
+
+    public void test8() throws IOException {
+        executeTarget("test8");
+    }
+
+    public void test9() throws IOException {
+        executeTarget("test9");
+    }
+
+    public void testMacLines() throws IOException {
+        executeTarget("testMacLines");
+    }
+
+    public void testNoOverwrite() throws IOException {
+        executeTarget("testNoOverwrite");
+    }
+
+    public void testEncoding() throws IOException {
+        executeTarget("testEncoding");
+    }
+
+    public void testOutputEncoding() throws IOException {
+        executeTarget("testOutputEncoding");
+    }
+
+    public void testLongLines() throws IOException {
+        executeTarget("testLongLines");
+    }
+
+    public void testCrCrLfSequenceUnix() throws IOException {
+        executeTarget("testCrCrLfSequence-unix");
+    }
+
+    public void testCrCrLfSequenceDos() throws IOException {
+        executeTarget("testCrCrLfSequence-dos");
+    }
+
+    public void testCrCrLfSequenceMac() throws IOException {
+        executeTarget("testCrCrLfSequence-mac");
+    }
+
+    public void testFixlastDos() throws IOException {
+        executeTarget("testFixlastDos");
+    }
+
+    public void testFixlastFalseMac() throws IOException {
+        executeTarget("testFixlastFalseMac");
+    }
+
+    public void testFixFile() throws Exception {
+        executeTarget("testFixFile");
+    }
+
+    public void testFixFileExclusive() throws Exception {
+        expectBuildExceptionContaining("testFixFileExclusive",
+                FixCRLF.ERROR_FILE_AND_SRCDIR, FixCRLF.ERROR_FILE_AND_SRCDIR);
+    }
+
+    /**
+     * Bugzilla Report 20840
+     *
+     * Will fail with an exception if the parent directories do not
+     * get created.
+     */
+    public void testCreateParentDirs() {
+        executeTarget("createParentDirs");
+    }
+
+    public void testPreserveLastModified() {
+        executeTarget("testPreserveLastModified");
+    }
+
+    public void testFilter1() {
+        executeTarget("testFilter1");
+    }
+
+    public void testFilter2() {
+        executeTarget("testFilter2");
+    }
+
+    public void testFilter3() {
+        executeTarget("testFilter3");
+    }
+
+    public void testFilter4() {
+        executeTarget("testFilter4");
+    }
+
+    public void testFilter5() {
+        executeTarget("testFilter5");
+    }
+
+    public void testFilter6() {
+        executeTarget("testFilter6");
+    }
+
+    public void testFilter7() {
+        executeTarget("testFilter7");
+    }
+
+    public void testFilter8() {
+        executeTarget("testFilter8");
+    }
+
+    public void testFilter9() {
+        executeTarget("testFilter9");
+    }
+
+    public void testCannotDoubleEof() {
+        executeTarget("testCannotDoubleEof");
+    }
+
+    public void testTabInLiteralInComment() {
+        executeTarget("testTabInLiteralInComment");
+    }
+
+    // not used, but public so theoretically must remain for BC?
+    public void assertEqualContent(File expect, File result)
+        throws AssertionFailedError, IOException {
+        if (!result.exists()) {
+            fail("Expected file "+result+" doesn\'t exist");
+        }
+
+        InputStream inExpect = null;
+        InputStream inResult = null;
+        try {
+            inExpect = new BufferedInputStream(new FileInputStream(expect));
+            inResult = new BufferedInputStream(new FileInputStream(result));
+
+            int expectedByte = inExpect.read();
+            while (expectedByte != -1) {
+                assertEquals(expectedByte, inResult.read());
+                expectedByte = inExpect.read();
+            }
+            assertEquals("End of file", -1, inResult.read());
+        } finally {
+            if (inResult != null) {
+                inResult.close();
+            }
+            if (inExpect != null) {
+                inExpect.close();
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GUnzipTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GUnzipTest.java
new file mode 100644
index 0000000..57a8196
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GUnzipTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class GUnzipTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public GUnzipTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/gunzip.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "attribute src invalid");
+    }
+
+    public void testRealTest() throws java.io.IOException {
+        testRealTest("realTest");
+    }
+
+    public void testRealTestWithResource() throws java.io.IOException {
+        testRealTest("realTestWithResource");
+    }
+
+    private void testRealTest(String target) throws java.io.IOException {
+        executeTarget(target);
+        assertTrue(FILE_UTILS.contentEquals(project.resolveFile("../asf-logo.gif"),
+                                           project.resolveFile("asf-logo.gif")));
+    }
+
+    public void testTestGzipTask() throws java.io.IOException {
+        testRealTest("testGzipTask");
+    }
+
+    public void testDocumentationClaimsOnCopy() throws java.io.IOException {
+        testRealTest("testDocumentationClaimsOnCopy");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GetTest.java
new file mode 100644
index 0000000..dd01d0e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GetTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class GetTest extends BuildFileTest {
+
+    public GetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/get.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument missing");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument missing");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "src invalid");
+    }
+
+    public void test5() {
+        expectBuildException("test5", "dest invalid (or no http-server on local machine)");
+    }
+
+    public void test6() {
+        executeTarget("test6");
+    }
+
+    public void testUseTimestamp() {
+        executeTarget("testUseTimestamp");
+    }
+
+    public void testUseTomorrow() {
+        executeTarget("testUseTomorrow");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GzipTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GzipTest.java
new file mode 100644
index 0000000..c2426fa
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/GzipTest.java
@@ -0,0 +1,76 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class GzipTest extends BuildFileTest {
+
+    public GzipTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/gzip.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument missing");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument missing");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "zipfile must not point to a directory");
+    }
+
+    public void testGZip(){
+        executeTarget("realTest");
+        String log = getLog();
+        assertTrue("Expecting message starting with 'Building:' but got '"
+            + log + "'", log.startsWith("Building:"));
+        assertTrue("Expecting message ending with 'asf-logo.gif.gz' but got '"
+            + log + "'", log.endsWith("asf-logo.gif.gz"));
+    }
+
+    public void testResource(){
+        executeTarget("realTestWithResource");
+    }
+
+    public void testDateCheck(){
+        executeTarget("testDateCheck");
+        String log = getLog();
+        assertTrue(
+            "Expecting message ending with 'asf-logo.gif.gz is up to date.' but got '" + log + "'",
+            log.endsWith("asf-logo.gif.gz is up to date."));
+    }
+
+    public void tearDown(){
+        executeTarget("cleanup");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ImportTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ImportTest.java
new file mode 100644
index 0000000..ad4d05b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ImportTest.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+
+/**
+ */
+public class ImportTest extends BuildFileTest {
+
+    public ImportTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+    }
+
+    public void tearDown() {
+    }
+
+    public void testSimpleImport() {
+        configureProject("src/etc/testcases/taskdefs/import/import.xml");
+        assertLogContaining("Before importIn imported topAfter import");
+    }
+
+    public void testUnnamedNesting() {
+        configureProject("src/etc/testcases/taskdefs/import/unnamedImport.xml",
+                         Project.MSG_WARN);
+        String log = getLog();
+        assertTrue("Warnings logged when not expected: " + log,
+                    log.length() == 0);
+    }
+
+    public void testSerial() {
+        configureProject("src/etc/testcases/taskdefs/import/subdir/serial.xml");
+        assertLogContaining("Unnamed2.xmlUnnamed1.xml");
+        String fullLog = getFullLog();
+        String substring = "Skipped already imported file";
+        assertTrue("expecting full log to contain \"" + substring
+            + "\" full log was \"" + fullLog + "\"",
+            fullLog.indexOf(substring) >= 0);
+    }
+
+    // allow this as imported in targets are only tested when a target is run
+    public void testImportInTargetNoEffect() {
+        configureProject("src/etc/testcases/taskdefs/import/subdir/importintarget.xml");
+        expectPropertyUnset("no-import", "foo");
+        assertTrue(null == getProject().getReference("baz"));
+    }
+
+    // deactivate this test as imports within targets are not allowed
+    public void notTestImportInTargetWithEffect() {
+        configureProject("src/etc/testcases/taskdefs/import/subdir/importintarget.xml");
+        expectPropertySet("do-import", "foo", "bar");
+        assertNotNull(getProject().getReference("baz"));
+    }
+
+    public void testImportInTargetNotAllowed() {
+        configureProject(
+            "src/etc/testcases/taskdefs/import/subdir/importintarget.xml");
+        expectBuildExceptionContaining(
+            "do-import", "not a top level task",
+            "import only allowed as a top-level task");
+    }
+
+    public void testImportInSequential() {
+        configureProject(
+            "src/etc/testcases/taskdefs/import/subdir/importinsequential.xml");
+        expectPropertySet("within-imported", "foo", "bar");
+        assertNotNull(getProject().getReference("baz"));
+    }
+
+    public void testImportSameTargets() {
+        try {
+            configureProject(
+                "src/etc/testcases/taskdefs/import/same_target.xml");
+        } catch (BuildException ex) {
+            String message = ex.getMessage();
+            if (message.indexOf("Duplicate target") == -1) {
+                assertTrue("Did not see 'Duplicate target' in '" + message +"'", false);
+            }
+            return;
+        }
+        assertTrue(
+            "Did not see build exception",
+            false);
+    }
+
+    public void testImportError() {
+        try {
+            configureProject(
+                "src/etc/testcases/taskdefs/import/import_bad_import.xml");
+        } catch (BuildException ex) {
+            Location lo = ex.getLocation();
+            assertTrue(
+                "expected location of build exception to be set",
+                (lo != null));
+            assertTrue(
+                "expected location to contain calling file",
+                lo.getFileName().indexOf("import_bad_import.xml") != -1);
+            assertTrue(
+                "expected message of ex to contain called file",
+                ex.getMessage().indexOf("bad.xml") != -1);
+            return;
+        }
+        assertTrue(
+            "Did not see build exception",
+            false);
+    }
+
+    public void testSymlinkedImports() throws Exception {
+        String ln = "/usr/bin/ln";
+        if (!new File(ln).exists()) {
+            ln = "/bin/ln";
+        }
+        if (!new File(ln).exists()) {
+            // Running on Windows or something, so skip it.
+            return;
+        }
+        String symlink = "src/etc/testcases/taskdefs/import/symlinks/d3b";
+        File symlinkFile = new File(System.getProperty("root"), symlink);
+        if (Runtime.getRuntime().exec(new String[] {ln, "-s", "d3a", symlinkFile.getAbsolutePath()}).waitFor() != 0) {
+            throw new IOException("'" + ln + " -s d3a " + symlink + "' failed");
+        }
+        try {
+            configureProject(
+                "src/etc/testcases/taskdefs/import/symlinks/d1/p1.xml");
+            assertPropertyEquals(
+                "ant.file.p2",
+                new File(System.getProperty("root"), "src/etc/testcases/taskdefs/import/symlinks/d2/p2.xml")
+                .getAbsolutePath());
+            assertPropertyEquals(
+                "ant.file.p3",
+                new File(System.getProperty("root"), "src/etc/testcases/taskdefs/import/symlinks/d3b/p3.xml")
+                .getAbsolutePath());
+        } finally {
+            symlinkFile.delete();
+        }
+    }
+
+    public void testTargetFirst() {
+        configureProject("src/etc/testcases/taskdefs/import/importtargetfirst.xml");
+        assertLogContaining("Importing targetfirstAfter target firstAfter importing");
+    }
+
+    public void testTargetName() {
+        configureProject("src/etc/testcases/taskdefs/import/c.xml");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InitializeClassTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InitializeClassTest.java
new file mode 100644
index 0000000..0994e17
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InitializeClassTest.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Test to see if static initializers are invoked the same way
+ * when <java> is invoked in forked and unforked modes.
+ *
+ */
+public class InitializeClassTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private File f1 = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/forkedout");
+    private File f2 = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/unforkedout");
+
+    public InitializeClassTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/initializeclass.xml");
+    }
+
+    public void testAll() throws IOException {
+        executeTarget("forked");
+        PrintStream ps = System.out;
+        PrintStream newps = new PrintStream(new FileOutputStream(f2));
+        System.setOut(newps);
+        project.executeTarget("unforked");
+        System.setOut(ps);
+        newps.close();
+        assertTrue("Forked - non-forked mismatch", FILE_UTILS.contentEquals(f1, f2));
+    }
+
+    public void tearDown() {
+        f1.delete();
+        f2.delete();
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InputTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InputTest.java
new file mode 100644
index 0000000..debdc0c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/InputTest.java
@@ -0,0 +1,106 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.FileInputStream;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.input.PropertyFileInputHandler;
+
+
+public class InputTest extends BuildFileTest {
+
+    public InputTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/input.xml");
+        System.getProperties()
+            .put(PropertyFileInputHandler.FILE_NAME_KEY,
+                 getProject().resolveFile("input.properties")
+                 .getAbsolutePath());
+        getProject().setInputHandler(new PropertyFileInputHandler());
+    }
+
+    public void test1() {
+        executeTarget("test1");
+    }
+
+    public void test2() {
+        executeTarget("test2");
+    }
+
+    public void test3() {
+        expectSpecificBuildException("test3", "invalid input",
+                                     "Found invalid input test for \'"
+                                     + getKey("All data is"
+                                              + " going to be deleted from DB"
+                                              + " continue?")
+                                     + "\'");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+    }
+
+    public void test6() {
+        executeTarget("test6");
+        assertEquals("scott", project.getProperty("db.user"));
+    }
+
+    public void testPropertyFileInlineHandler() {
+        executeTarget("testPropertyFileInlineHandler");
+    }
+
+    public void testDefaultInlineHandler() {
+        stdin();
+        executeTarget("testDefaultInlineHandler");
+    }
+
+    public void testGreedyInlineHandler() {
+        stdin();
+        executeTarget("testGreedyInlineHandler");
+    }
+
+    public void testGreedyInlineHandlerClassname() {
+        stdin();
+        executeTarget("testGreedyInlineHandlerClassname");
+    }
+
+    public void testGreedyInlineHandlerRefid() {
+        stdin();
+        executeTarget("testGreedyInlineHandlerRefid");
+    }
+
+    private void stdin() {
+        try {
+            System.setIn(new FileInputStream(
+                getProject().resolveFile("input.stdin")));
+        } catch (Exception e) {
+            throw e instanceof RuntimeException
+                ? (RuntimeException) e : new RuntimeException(e.getMessage());
+        }
+    }
+
+    private String getKey(String key) {
+        return key; // XXX what is this for?
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java
new file mode 100644
index 0000000..1fb1f5b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java
@@ -0,0 +1,303 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class JarTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private static String tempJar = "tmp.jar";
+    private static String tempDir = "jartmp/";
+    private Reader r1, r2;
+
+    public JarTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/jar.xml");
+    }
+
+    public void tearDown() {
+        if (r1 != null) {
+            try {
+                r1.close();
+            } catch (IOException e) {
+            }
+        }
+        if (r2 != null) {
+            try {
+                r2.close();
+            } catch (IOException e) {
+            }
+        }
+
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "manifest file does not exist");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "Unrecognized whenempty attribute: format C: /y");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+        File jarFile = new File(getProjectDir(), tempJar);
+        assertTrue(jarFile.exists());
+    }
+
+    public void testNoRecreateWithoutUpdate() {
+        testNoRecreate("test4");
+    }
+
+    public void testNoRecreateWithUpdate() {
+        testNoRecreate("testNoRecreateWithUpdate");
+    }
+
+    private void testNoRecreate(String secondTarget) {
+        executeTarget("test4");
+        File jarFile = new File(getProjectDir(), tempJar);
+        long jarModifiedDate = jarFile.lastModified();
+        try {
+            Thread.sleep(2500);
+        } catch (InterruptedException e) {
+        } // end of try-catch
+        executeTarget(secondTarget);
+        assertEquals("jar has not been recreated in " + secondTarget,
+                     jarModifiedDate, jarFile.lastModified());
+    }
+
+    public void testRecreateWithoutUpdateAdditionalFiles() {
+        testRecreate("test4", "testRecreateWithoutUpdateAdditionalFiles");
+    }
+
+    public void testRecreateWithUpdateAdditionalFiles() {
+        testRecreate("test4", "testRecreateWithUpdateAdditionalFiles");
+    }
+
+    public void testRecreateWithoutUpdateNewerFile() {
+        testRecreate("testRecreateNewerFileSetup",
+                     "testRecreateWithoutUpdateNewerFile");
+    }
+
+    public void testRecreateWithUpdateNewerFile() {
+        testRecreate("testRecreateNewerFileSetup",
+                     "testRecreateWithUpdateNewerFile");
+    }
+
+    private void testRecreate(String firstTarget, String secondTarget) {
+        executeTarget(firstTarget);
+        long sleeptime = 3000
+            + FILE_UTILS.getFileTimestampGranularity();
+        try {
+            Thread.sleep(sleeptime);
+        } catch (InterruptedException e) {
+        } // end of try-catch
+        File jarFile = new File(getProjectDir(), tempJar);
+        long jarModifiedDate = jarFile.lastModified();
+        executeTarget(secondTarget);
+        jarFile = new File(getProjectDir(), tempJar);
+        assertTrue("jar has been recreated in " + secondTarget,
+                   jarModifiedDate < jarFile.lastModified());
+    }
+
+    public void testManifestStaysIntact()
+        throws IOException, ManifestException {
+        executeTarget("testManifestStaysIntact");
+
+        r1 = new FileReader(getProject()
+                            .resolveFile(tempDir + "manifest"));
+        r2 = new FileReader(getProject()
+                            .resolveFile(tempDir + "META-INF/MANIFEST.MF"));
+        Manifest mf1 = new Manifest(r1);
+        Manifest mf2 = new Manifest(r2);
+        assertEquals(mf1, mf2);
+    }
+
+    public void testNoRecreateBasedirExcludesWithUpdate() {
+        testNoRecreate("testNoRecreateBasedirExcludesWithUpdate");
+    }
+
+    public void testNoRecreateBasedirExcludesWithoutUpdate() {
+        testNoRecreate("testNoRecreateBasedirExcludesWithoutUpdate");
+    }
+
+    public void testNoRecreateZipfilesetExcludesWithUpdate() {
+        testNoRecreate("testNoRecreateZipfilesetExcludesWithUpdate");
+    }
+
+    public void testNoRecreateZipfilesetExcludesWithoutUpdate() {
+        testNoRecreate("testNoRecreateZipfilesetExcludesWithoutUpdate");
+    }
+
+    public void testRecreateZipfilesetWithoutUpdateAdditionalFiles() {
+        testRecreate("test4",
+                     "testRecreateZipfilesetWithoutUpdateAdditionalFiles");
+    }
+
+    public void testRecreateZipfilesetWithUpdateAdditionalFiles() {
+        testRecreate("test4",
+                     "testRecreateZipfilesetWithUpdateAdditionalFiles");
+    }
+
+    public void testRecreateZipfilesetWithoutUpdateNewerFile() {
+        testRecreate("testRecreateNewerFileSetup",
+                     "testRecreateZipfilesetWithoutUpdateNewerFile");
+    }
+
+    public void testRecreateZipfilesetWithUpdateNewerFile() {
+        testRecreate("testRecreateNewerFileSetup",
+                     "testRecreateZipfilesetWithUpdateNewerFile");
+    }
+
+    public void testCreateWithEmptyFileset() {
+        executeTarget("testCreateWithEmptyFilesetSetUp");
+        executeTarget("testCreateWithEmptyFileset");
+        executeTarget("testCreateWithEmptyFileset");
+    }
+
+    public void testUpdateIfOnlyManifestHasChanged() {
+        executeTarget("testUpdateIfOnlyManifestHasChanged");
+        File jarXml = getProject().resolveFile(tempDir + "jar.xml");
+        assertTrue(jarXml.exists());
+    }
+
+    // bugzilla report 10262
+    public void testNoDuplicateIndex() throws IOException {
+        ZipFile archive = null;
+        try {
+            executeTarget("testIndexTests");
+            archive = new ZipFile(getProject().resolveFile(tempJar));
+            Enumeration e = archive.entries();
+            int numberOfIndexLists = 0;
+            while (e.hasMoreElements()) {
+                ZipEntry ze = (ZipEntry) e.nextElement();
+                if (ze.getName().equals("META-INF/INDEX.LIST")) {
+                    numberOfIndexLists++;
+                }
+            }
+            assertEquals(1, numberOfIndexLists);
+        } finally {
+            if (archive != null) {
+                archive.close();
+            }
+        }
+    }
+
+    // bugzilla report 16972
+    public void testRootFilesInIndex() throws IOException {
+        ZipFile archive = null;
+        try {
+            executeTarget("testIndexTests");
+            archive = new ZipFile(getProject().resolveFile(tempJar));
+            ZipEntry ze = archive.getEntry("META-INF/INDEX.LIST");
+            InputStream is = archive.getInputStream(ze);
+            BufferedReader r = new BufferedReader(new InputStreamReader(is,
+                                                                        "UTF8"));
+            boolean foundSub = false;
+            boolean foundSubFoo = false;
+            boolean foundFoo = false;
+
+            String line = r.readLine();
+            while (line != null) {
+                if (line.equals("foo")) {
+                    foundFoo = true;
+                } else if (line.equals("sub")) {
+                    foundSub = true;
+                } else if (line.equals("sub/foo")) {
+                    foundSubFoo = true;
+                }
+                line = r.readLine();
+            }
+
+            assertTrue(foundSub);
+            assertTrue(!foundSubFoo);
+            assertTrue(foundFoo);
+        } finally {
+            if (archive != null) {
+                archive.close();
+            }
+        }
+    }
+    public void testManifestOnlyJar() {
+        expectLogContaining("testManifestOnlyJar", "Building MANIFEST-only jar: ");
+        File manifestFile = getProject().resolveFile(tempDir + "META-INF" + File.separator + "MANIFEST.MF");
+        assertTrue(manifestFile.exists());
+    }
+
+    public void testIndexJarsPlusJarMarker() {
+        executeTarget("testIndexJarsPlusJarMarker");
+    }
+    
+    public void testNoVersionInfoFail() {
+        expectBuildExceptionContaining("testNoVersionInfoFail", "Manifest Implemention information missing.", "No Implementation-Title set.");
+    }
+    
+    public void testNoVersionInfoIgnore() {
+        executeTarget("testNoVersionInfoIgnore");
+        assertTrue( getFullLog().indexOf("No Implementation-Title set.") > -1 );
+        assertTrue( getFullLog().indexOf("No Implementation-Version set.") > -1 );
+        assertTrue( getFullLog().indexOf("No Implementation-Vendor set.") > -1 );
+    }
+
+    public void testNoVersionInfoWarn() {
+        executeTarget("testNoVersionInfoWarn");
+        assertTrue( getLog().indexOf("No Implementation-Title set.") > -1 );
+        assertTrue( getLog().indexOf("No Implementation-Version set.") > -1 );
+        assertTrue( getLog().indexOf("No Implementation-Vendor set.") > -1 );
+    }
+
+    public void testNoVersionInfoNoStrict() {
+        executeTarget("testNoVersionInfoNoStrict");
+        assertFalse( getLog().indexOf("No Implementation-Title set.") > -1 );
+        assertFalse( getLog().indexOf("No Implementation-Version set.") > -1 );
+        assertFalse( getLog().indexOf("No Implementation-Vendor set.") > -1 );
+    }
+    
+    public void testHasVersionInfo() {
+        executeTarget("testHasVersionInfo");
+        assertFalse( getLog().indexOf("No Implementation-Title set.") > -1 );
+        assertFalse( getLog().indexOf("No Implementation-Version set.") > -1 );
+        assertFalse( getLog().indexOf("No Implementation-Vendor set.") > -1 );
+    }
+    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java
new file mode 100644
index 0000000..a5ae686
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavaTest.java
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.TeeOutputStream;
+
+/**
+ * stress out java task
+ * */
+public class JavaTest extends BuildFileTest {
+
+    private static final int TIME_TO_WAIT = 1;
+    // wait 1 second extra to allow for java to start ...
+    // this time was OK on a Win NT machine and on nagoya
+    private static final int SECURITY_MARGIN = 2000;
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    private boolean runFatalTests=false;
+
+    public JavaTest(String name) {
+        super(name);
+    }
+
+    /**
+     * configure the project.
+     * if the property junit.run.fatal.tests is set we run
+     * the fatal tests
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/java.xml");
+
+        //final String propname="tests-classpath.value";
+        //String testClasspath=System.getProperty(propname);
+        //System.out.println("Test cp="+testClasspath);
+        String propname="tests-classpath.value";
+        String runFatal=System.getProperty("junit.run.fatal.tests");
+        if(runFatal!=null)
+            runFatalTests=true;
+    }
+
+    public void tearDown() {
+        // remove log file from testSpawn
+        project.executeTarget("cleanup");
+    }
+
+    public void testNoJarNoClassname(){
+        expectBuildExceptionContaining("testNoJarNoClassname",
+            "parameter validation",
+            "Classname must not be null.");
+    }
+
+    public void testJarNoFork() {
+        expectBuildExceptionContaining("testJarNoFork",
+            "parameter validation",
+            "Cannot execute a jar in non-forked mode. "
+                + "Please set fork='true'. ");
+    }
+
+    public void testJarAndClassName() {
+        expectBuildException("testJarAndClassName",
+            "Should not be able to set both classname AND jar");
+    }
+
+
+    public void testClassnameAndJar() {
+        expectBuildException("testClassnameAndJar",
+            "Should not be able to set both classname AND jar");
+    }
+
+    public void testRun() {
+        executeTarget("testRun");
+    }
+
+
+
+    /** this test fails but we ignore the return value;
+     *  we verify that failure only matters when failonerror is set
+     */
+    public void testRunFail() {
+        if(runFatalTests) {
+            executeTarget("testRunFail");
+        }
+    }
+
+    public void testRunFailFoe() {
+        if(runFatalTests) {
+            expectBuildExceptionContaining("testRunFailFoe",
+                "java failures being propagated",
+                "Java returned:");
+        }
+}
+
+    public void testRunFailFoeFork() {
+        expectBuildExceptionContaining("testRunFailFoeFork",
+            "java failures being propagated",
+            "Java returned:");
+    }
+
+    public void testExcepting() {
+        expectLogContaining("testExcepting",
+                            "Exception raised inside called program");
+    }
+
+    public void testExceptingFork() {
+        expectLogContaining("testExceptingFork",
+                            "Java Result:");
+    }
+
+    public void testExceptingFoe() {
+        expectBuildExceptionContaining("testExceptingFoe",
+            "passes exception through",
+            "Exception raised inside called program");
+    }
+
+    public void testExceptingFoeFork() {
+        expectBuildExceptionContaining("testExceptingFoeFork",
+            "exceptions turned into error codes",
+            "Java returned:");
+    }
+
+    public void testResultPropertyZero() {
+        executeTarget("testResultPropertyZero");
+        assertEquals("0",project.getProperty("exitcode"));
+    }
+
+    public void testResultPropertyNonZero() {
+        executeTarget("testResultPropertyNonZero");
+        assertEquals("2",project.getProperty("exitcode"));
+    }
+
+    public void testResultPropertyZeroNoFork() {
+        executeTarget("testResultPropertyZeroNoFork");
+        assertEquals("0",project.getProperty("exitcode"));
+    }
+
+    public void testResultPropertyNonZeroNoFork() {
+        executeTarget("testResultPropertyNonZeroNoFork");
+         assertEquals("-1",project.getProperty("exitcode"));
+     }
+
+    public void testRunFailWithFailOnError() {
+        expectBuildExceptionContaining("testRunFailWithFailOnError",
+            "non zero return code",
+            "Java returned:");
+    }
+
+    public void testRunSuccessWithFailOnError() {
+        executeTarget("testRunSuccessWithFailOnError");
+    }
+
+    public void testSpawn() {
+        File logFile = FILE_UTILS.createTempFile("spawn","log", project.getBaseDir(), false, false);
+        // this is guaranteed by FileUtils#createTempFile
+        assertTrue("log file not existing", !logFile.exists());
+        project.setProperty("logFile", logFile.getAbsolutePath());
+        project.setProperty("timeToWait", Long.toString(TIME_TO_WAIT));
+        project.executeTarget("testSpawn");
+        try {
+            Thread.sleep(TIME_TO_WAIT * 1000 + SECURITY_MARGIN);
+        } catch (Exception ex) {
+            System.out.println("my sleep was interrupted");
+        }
+        // let's be nice with the next generation of developers
+        if (!logFile.exists()) {
+            System.out.println("suggestion: increase the constant"
+            + " SECURITY_MARGIN to give more time for java to start.");
+        }
+        assertTrue("log file exists", logFile.exists());
+    }
+
+    public void testRedirect1() {
+        executeTarget("redirect1");
+    }
+
+    public void testRedirect2() {
+        executeTarget("redirect2");
+    }
+
+    public void testRedirect3() {
+        executeTarget("redirect3");
+    }
+
+    public void testRedirector1() {
+        executeTarget("redirector1");
+    }
+
+    public void testRedirector2() {
+        executeTarget("redirector2");
+    }
+
+    /**
+     * entry point class with no dependencies other
+     * than normal JRE runtime
+     */
+    public static class EntryPoint {
+
+    /**
+     * this entry point is used by the java.xml tests to
+     * generate failure strings to handle
+     * argv[0] = exit code (optional)
+     * argv[1] = string to print to System.out (optional)
+     * argv[1] = string to print to System.err (optional)
+     */
+        public static void main(String[] argv) {
+            int exitCode=0;
+            if(argv.length>0) {
+                try {
+                    exitCode=Integer.parseInt(argv[0]);
+                } catch(NumberFormatException nfe) {
+                    exitCode=-1;
+                }
+            }
+            if(argv.length>1) {
+                System.out.println(argv[1]);
+            }
+            if(argv.length>2) {
+                System.err.println(argv[2]);
+            }
+            if(exitCode!=0) {
+                System.exit(exitCode);
+            }
+        }
+    }
+
+    /**
+     * entry point class with no dependencies other
+     * than normal JRE runtime
+     */
+    public static class ExceptingEntryPoint {
+
+        /**
+         * throw a run time exception which does not need
+         * to be in the signature of the entry point
+         */
+        public static void main(String[] argv) {
+            throw new NullPointerException("Exception raised inside called program");
+        }
+    }
+    /**
+     * test class for spawn
+     */
+    public static class SpawnEntryPoint {
+        public static void main(String [] argv) {
+            int sleepTime = 10;
+            String logFile = "spawn.log";
+            if (argv.length >= 1) {
+                sleepTime = Integer.parseInt(argv[0]);
+            }
+            if (argv.length >= 2)
+            {
+                logFile = argv[1];
+            }
+            OutputStreamWriter out = null;
+            try {
+                Thread.sleep(sleepTime * 1000);
+            } catch (InterruptedException ex) {
+                System.out.println("my sleep was interrupted");
+            }
+
+            try {
+                File dest = new File(logFile);
+                FileOutputStream fos = new FileOutputStream(dest);
+                out = new OutputStreamWriter(fos);
+                out.write("bye bye\n");
+            } catch (Exception ex) {}
+            finally {
+                try {out.close();} catch (IOException ioe) {}}
+
+        }
+    }
+
+    /**
+     * entry point class to pipe System.in to the specified stream:
+     * "out", "err", or "both".  If none specified, swallow the input.
+     */
+    public static class PipeEntryPoint {
+
+        /**
+         * pipe input to specified output
+         */
+        public static void main(String[] args) {
+            OutputStream os = null;
+            if (args.length > 0) {
+                if ("out".equalsIgnoreCase(args[0])) {
+                    os = System.out;
+                } else if ("err".equalsIgnoreCase(args[0])) {
+                    os = System.err;
+                } else if ("both".equalsIgnoreCase(args[0])) {
+                    os = new TeeOutputStream(System.out, System.err);
+                }
+            }
+            if (os != null) {
+                Thread t = new Thread(new StreamPumper(System.in, os, true));
+                t.start();
+                try {
+                    t.join();
+                } catch (InterruptedException eyeEx) {
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavacTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavacTest.java
new file mode 100644
index 0000000..9b234cf
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavacTest.java
@@ -0,0 +1,245 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.compilers.CompilerAdapter;
+import org.apache.tools.ant.taskdefs.compilers.CompilerAdapterFactory;
+import org.apache.tools.ant.taskdefs.compilers.Javac12;
+import org.apache.tools.ant.taskdefs.compilers.Javac13;
+import org.apache.tools.ant.taskdefs.compilers.JavacExternal;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import junit.framework.TestCase;
+
+/**
+ * Testcase for <javac>.
+ *
+ */
+public class JavacTest extends TestCase {
+
+    private Project project;
+    private Javac javac;
+
+    public JavacTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.init();
+        javac = new Javac();
+        javac.setProject(project);
+    }
+
+    /**
+     * Test setting the name of the javac executable.
+     */
+    public void testForkedExecutableName() {
+        assertNull("no fork means no executable", javac.getJavacExecutable());
+
+        project.setProperty("build.compiler", "modern");
+        assertNull("no fork means no executable", javac.getJavacExecutable());
+
+        javac.setFork(true);
+        assertNotNull("normal fork", javac.getJavacExecutable());
+        assertTrue("name should contain \"javac\"",
+                   javac.getJavacExecutable().indexOf("javac") > -1);
+
+        project.setProperty("build.compiler", "extJavac");
+        javac.setFork(false);
+        assertNotNull("fork via property", javac.getJavacExecutable());
+        assertTrue("name should contain \"javac\"",
+                   javac.getJavacExecutable().indexOf("javac") > -1);
+
+        project.setProperty("build.compiler", "whatever");
+        assertNull("no fork and not extJavac means no executable",
+                   javac.getJavacExecutable());
+
+        String myJavac = "Slartibartfast";
+        javac.setFork(true);
+        javac.setExecutable(myJavac);
+        assertEquals(myJavac, javac.getJavacExecutable());
+    }
+
+    /**
+     * Test nested compiler args.
+     */
+    public void testCompilerArg() {
+        String[] args = javac.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("no args", 0, args.length);
+
+        Javac.ImplementationSpecificArgument arg = javac.createCompilerArg();
+        String ford = "Ford";
+        String prefect = "Prefect";
+        String testArg = ford + " " + prefect;
+        arg.setValue(testArg);
+        args = javac.getCurrentCompilerArgs();
+        assertEquals("unconditional single arg", 1, args.length);
+        assertEquals(testArg, args[0]);
+
+        arg.setCompiler("jikes");
+        args = javac.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("implementation is jikes but build.compiler is null",
+                     0, args.length);
+
+        project.setProperty("build.compiler", "jvc");
+        args = javac.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("implementation is jikes but build.compiler is jvc",
+                     0, args.length);
+
+        project.setProperty("build.compiler", "jikes");
+        args = javac.getCurrentCompilerArgs();
+        assertEquals("both are jikes", 1, args.length);
+        assertEquals(testArg, args[0]);
+
+        arg.setLine(testArg);
+        args = javac.getCurrentCompilerArgs();
+        assertEquals("split at space", 2, args.length);
+        assertEquals(ford, args[0]);
+        assertEquals(prefect, args[1]);
+    }
+
+    /**
+     * Test nested compiler args in the fork="true" and
+     * implementation="extJavac" case.
+     */
+    public void testCompilerArgForForkAndExtJavac() {
+        Javac.ImplementationSpecificArgument arg = javac.createCompilerArg();
+        String ford = "Ford";
+        String prefect = "Prefect";
+        String testArg = ford + " " + prefect;
+        arg.setValue(testArg);
+        arg.setCompiler("extJavac");
+        javac.setFork(true);
+        String[] args = javac.getCurrentCompilerArgs();
+        assertEquals("both are forked javac", 1, args.length);
+        assertEquals(testArg, args[0]);
+    }
+
+    /**
+     * Test compiler attribute.
+     */
+    public void testCompilerAttribute() {
+        // check defaults
+        String compiler = javac.getCompiler();
+        assertNotNull(compiler);
+        if (System.getProperty("build.compiler") != null) {
+            assertEquals(System.getProperty("build.compiler"),
+                         compiler);
+        } else {
+            assertTrue("default value",
+                       "javac1.1".equals(compiler)
+                       || "javac1.2".equals(compiler)
+                       || "javac1.3".equals(compiler)
+                       || "javac1.4".equals(compiler)
+                       || "javac1.5".equals(compiler)
+                       || "classic".equals(compiler));
+        }
+
+        javac.setFork(true);
+        assertNotNull(javac.getCompiler());
+        assertEquals("extJavac", javac.getCompiler());
+        assertEquals(compiler, javac.getCompilerVersion());
+
+        // check build.compiler provides defaults
+        javac = new Javac();
+        javac.setProject(project);
+        // setUserProperty to override system properties
+        project.setUserProperty("build.compiler", "jikes");
+        compiler = javac.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("jikes", compiler);
+
+        javac.setFork(true);
+        compiler = javac.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("jikes", compiler);
+
+        // check attribute overrides build.compiler
+        javac.setFork(false);
+        javac.setCompiler("jvc");
+        compiler = javac.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("jvc", compiler);
+
+        javac.setFork(true);
+        compiler = javac.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("jvc", compiler);
+    }
+
+    public void testCompilerAdapter() {
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+            || JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
+            javac.setCompiler("javac1.1");
+        } else {
+            javac.setCompiler("javac1.4");
+        }
+
+        javac.setDepend(true);
+        CompilerAdapter adapter =
+            CompilerAdapterFactory.getCompiler(javac.getCompiler(), javac);
+
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+            || JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
+            assertTrue(adapter instanceof Javac12);
+        } else {
+            assertTrue(adapter instanceof Javac13);
+        }
+
+        javac.setFork(true);
+        adapter =
+            CompilerAdapterFactory.getCompiler(javac.getCompiler(), javac);
+        assertTrue(adapter instanceof JavacExternal);
+    }
+
+    public void testSourceNoDefault() {
+        assertNull(javac.getSource());
+    }
+
+    public void testSourceWithDefault() {
+        project.setNewProperty("ant.build.javac.source", "1.4");
+        assertEquals("1.4", javac.getSource());
+    }
+
+    public void testSourceOverridesDefault() {
+        project.setNewProperty("ant.build.javac.source", "1.4");
+        javac.setSource("1.5");
+        assertEquals("1.5", javac.getSource());
+    }
+
+    public void testTargetNoDefault() {
+        assertNull(javac.getTarget());
+    }
+
+    public void testTargetWithDefault() {
+        project.setNewProperty("ant.build.javac.target", "1.4");
+        assertEquals("1.4", javac.getTarget());
+    }
+
+    public void testTargetOverridesDefault() {
+        project.setNewProperty("ant.build.javac.target", "1.4");
+        javac.setTarget("1.5");
+        assertEquals("1.5", javac.getTarget());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavadocTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavadocTest.java
new file mode 100755
index 0000000..e233860
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/JavadocTest.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+public class JavadocTest extends BuildFileTest {
+
+    public JavadocTest(String name) {
+        super(name);
+    }
+
+    private static final String BUILD_PATH = "src/etc/testcases/taskdefs/javadoc/";
+    private static final String BUILD_FILENAME = "javadoc.xml";
+    private static final String BUILD_FILE = BUILD_PATH + BUILD_FILENAME;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        configureProject(BUILD_FILE);
+    }
+
+    // PR 38370
+    public void testDirsetPath() throws Exception {
+        executeTarget("dirsetPath");
+    }
+
+    // PR 38370
+    public void testDirsetPathWithoutPackagenames() throws Exception {
+        try {
+            executeTarget("dirsetPathWithoutPackagenames");
+        } catch (BuildException e) {
+            fail("Contents of path should be picked up without specifying package names: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testNestedDirsetPath() throws Exception {
+        executeTarget("nestedDirsetPath");
+    }
+
+    // PR 38370
+    public void testFilesetPath() throws Exception {
+        try {
+            executeTarget("filesetPath");
+        } catch (BuildException e) {
+            fail("A path can contain filesets: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testNestedFilesetPath() throws Exception {
+        try {
+            executeTarget("nestedFilesetPath");
+        } catch (BuildException e) {
+            fail("A path can contain nested filesets: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testFilelistPath() throws Exception {
+        try {
+            executeTarget("filelistPath");
+        } catch (BuildException e) {
+            fail("A path can contain filelists: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testNestedFilelistPath() throws Exception {
+        try {
+            executeTarget("nestedFilelistPath");
+        } catch (BuildException e) {
+            fail("A path can contain nested filelists: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testPathelementPath() throws Exception {
+        executeTarget("pathelementPath");
+    }
+
+    // PR 38370
+    public void testPathelementLocationPath() throws Exception {
+        try {
+            executeTarget("pathelementLocationPath");
+        } catch (BuildException e) {
+            fail("A path can contain pathelements pointing to a file: " + e);
+        }
+    }
+
+    // PR 38370
+    public void testNestedSource() throws Exception {
+        executeTarget("nestedSource");
+    }
+
+    // PR 38370
+    public void testNestedFilesetRef() throws Exception {
+        executeTarget("nestedFilesetRef");
+    }
+
+    // PR 38370
+    public void testNestedFilesetRefInPath() throws Exception {
+        executeTarget("nestedFilesetRefInPath");
+    }
+
+    public void testNestedFilesetNoPatterns() throws Exception {
+        executeTarget("nestedFilesetNoPatterns");
+    }
+
+    public void testDoublyNestedFileset() throws Exception {
+        executeTarget("doublyNestedFileset");
+    }
+
+    public void testDoublyNestedFilesetNoPatterns() throws Exception {
+        executeTarget("doublyNestedFilesetNoPatterns");
+    }
+
+    public void testNonJavaIncludes() throws Exception { // #41264
+        executeTarget("nonJavaIncludes");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadFileTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadFileTest.java
new file mode 100644
index 0000000..479a6c3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadFileTest.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test the load file task
+ *
+ * @created 10 December 2001
+ */
+public class LoadFileTest extends BuildFileTest {
+
+    /**
+     * Constructor for the LoadFileTest object
+     *
+     * @param name Description of Parameter
+     */
+    public LoadFileTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/loadfile.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoSourcefileDefined() {
+        expectBuildException("testNoSourcefileDefined",
+                "source file not defined");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoPropertyDefined() {
+        expectBuildException("testNoPropertyDefined",
+                "output property not defined");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoSourcefilefound() {
+        expectBuildExceptionContaining("testNoSourcefilefound",
+                "File not found", " doesn't exist");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testFailOnError()
+            throws BuildException {
+        expectPropertyUnset("testFailOnError","testFailOnError");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testLoadAFile()
+            throws BuildException {
+        executeTarget("testLoadAFile");
+        if(project.getProperty("testLoadAFile").indexOf("eh?")<0) {
+            fail("property is not all in the file");
+        }
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testLoadAFileEnc()
+            throws BuildException {
+        executeTarget("testLoadAFileEnc");
+        if(project.getProperty("testLoadAFileEnc")==null) {
+            fail("file load failed");
+        }
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testEvalProps()
+            throws BuildException {
+        executeTarget("testEvalProps");
+        if(project.getProperty("testEvalProps").indexOf("rain")<0) {
+            fail("property eval broken");
+        }
+    }
+
+    /**
+     * Test FilterChain and FilterReaders
+     */
+    public void testFilterChain()
+            throws BuildException {
+        executeTarget("testFilterChain");
+        if(project.getProperty("testFilterChain").indexOf("World!")<0) {
+            fail("Filter Chain broken");
+        }
+    }
+
+    /**
+     * Test StripJavaComments filterreader functionality.
+     */
+    public final void testStripJavaComments()
+            throws BuildException {
+        executeTarget("testStripJavaComments");
+        final String expected = project.getProperty("expected");
+        final String generated = project.getProperty("testStripJavaComments");
+        assertEquals(expected, generated);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testOneLine()
+            throws BuildException {
+            expectPropertySet("testOneLine","testOneLine","1,2,3,4");
+
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadPropertiesTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadPropertiesTest.java
new file mode 100644
index 0000000..24b7413
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/LoadPropertiesTest.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class LoadPropertiesTest extends BuildFileTest {
+
+    public LoadPropertiesTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/loadproperties.xml");
+    }
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testPrefixedProperties() {
+        executeTarget("testPrefixedProperties");
+        String url = project.getProperty("server1.http.url");
+        assertEquals("http://localhost:80", url);
+    }
+
+    public void testPropertiesFromResource() {
+        executeTarget("testPropertiesFromResource");
+        executeTarget("loadPropertiesCheck");
+    }
+
+    public void testPropertiesFromFileSet() {
+        executeTarget("testPropertiesFromFileSet");
+        executeTarget("loadPropertiesCheck");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MacroDefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MacroDefTest.java
new file mode 100644
index 0000000..d24096c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MacroDefTest.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class MacroDefTest extends BuildFileTest {
+    public MacroDefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/macrodef.xml");
+    }
+
+    public void testSimple() {
+        expectLog("simple", "Hello World");
+    }
+
+    public void testText() {
+        expectLog("text", "Inner Text");
+    }
+
+    public void testDuplicateAttribute() {
+        expectBuildException(
+            "duplicate.attribute",
+            "the attribute text has already been specified");
+    }
+
+    public void testDuplicateElement() {
+        expectBuildException(
+            "duplicate.element",
+            "the element text has already been specified");
+    }
+
+    public void testUri() {
+        expectLog("uri", "Hello World");
+    }
+
+    public void testNested() {
+        expectLog("nested", "A nested element");
+    }
+
+    public void testDouble() {
+        expectLog(
+            "double",
+            "@{prop} is 'property', value of ${property} is 'A property value'");
+    }
+
+    public void testIgnoreCase() {
+        expectLog(
+            "ignorecase",
+            "a is ab is b");
+    }
+
+    public void testIgnoreElementCase() {
+        expectLog(
+            "ignore-element-case",
+            "nested elementnested element");
+    }
+
+    public void testTextElement() {
+        expectLogContaining(
+            "textelement", "Hello world");
+    }
+
+    public void testTextTrim() {
+        expectLogContaining(
+            "text.trim", "[Hello world]");
+    }
+
+    public void testDuplicateTextName() {
+        expectBuildException(
+            "duplicatetextname",
+            "the name \"text\" is already used as an attribute");
+    }
+    public void testDuplicateTextName2() {
+        expectBuildException(
+            "duplicatetextname2",
+            "the attribute name \"text\" has already been used by the text element");
+    }
+    public void testEscape() {
+        expectLog(
+            "escape",
+            "a@b or a@b is avalue@bvalue");
+    }
+    public void testAttributeDescription() {
+        expectLog(
+            "attribute.description",
+            "description is hello world");
+    }
+    public void testOverrideDefault() {
+        expectLog(
+            "override.default",
+            "value is new");
+    }
+    public void testImplicit() {
+        expectLog(
+            "implicit", "Before implicitIn implicitAfter implicit");
+    }
+    public void testImplicitNotOptional() {
+        expectSpecificBuildException(
+            "implicit.notoptional",
+            "Missing nested elements for implicit element implicit",
+            "Missing nested elements for implicit element implicit");
+    }
+    public void testImplicitOptional() {
+        expectLog(
+            "implicit.optional", "Before implicitAfter implicit");
+    }
+    public void testImplicitExplicit() {
+        expectSpecificBuildException(
+            "implicit.explicit",
+            "Only one element allowed when using implicit elements",
+            "Only one element allowed when using implicit elements");
+    }
+
+    public void testBackTraceOff() {
+        try {
+            executeTarget("backtraceoff");
+        } catch (BuildException ex) {
+            if (ex.getMessage().indexOf("following error occurred") != -1) {
+                fail("error message contained backtrace - " + ex.getMessage());
+            }
+        }
+    }
+
+    public void testBackTrace() {
+        expectBuildExceptionContaining(
+            "backtraceon",
+            "Checking if a back trace is created",
+            "following error occurred");
+    }
+
+    public void testTopLevelText() {
+        expectLogContaining("top-level-text", "Hello World");
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MakeUrlTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MakeUrlTest.java
new file mode 100644
index 0000000..7f9885f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MakeUrlTest.java
@@ -0,0 +1,137 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URL;
+
+
+public class MakeUrlTest extends BuildFileTest {
+
+    public MakeUrlTest(String s) {
+        super(s);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/makeurl.xml");
+    }
+
+    public void testEmpty() {
+        expectBuildExceptionContaining("testEmpty", "missing property", "property");
+    }
+
+    public void testNoProperty() {
+        expectBuildExceptionContaining("testNoProperty", "missing property", "property");
+    }
+
+    public void testNoFile() {
+        expectBuildExceptionContaining("testNoFile", "missing file", "file");
+    }
+
+    public void testValidation() {
+        expectBuildExceptionContaining("testValidation", MakeUrl.ERROR_MISSING_FILE, "file");
+    }
+
+    public void testWorks() {
+        executeTarget("testWorks");
+        assertPropertyContains("testWorks", "file:");
+        assertPropertyContains("testWorks", "/foo");
+    }
+
+    public void testIllegalChars() {
+        executeTarget("testIllegalChars");
+        assertPropertyContains("testIllegalChars", "file:");
+        assertPropertyContains("testIllegalChars", "fo%20o%25");
+    }
+
+    /**
+     * test that we can round trip by opening a url that exists
+     *
+     * @throws IOException
+     */
+    public void testRoundTrip() throws IOException {
+        executeTarget("testRoundTrip");
+        assertPropertyContains("testRoundTrip", "file:");
+        String property = getProperty("testRoundTrip");
+        URL url = new URL(property);
+        InputStream instream = url.openStream();
+        instream.close();
+    }
+
+    public void testIllegalCombinations() {
+        executeTarget("testIllegalCombinations");
+        assertPropertyContains("testIllegalCombinations", "/foo");
+        assertPropertyContains("testIllegalCombinations", ".xml");
+    }
+
+    public void testFileset() {
+        executeTarget("testFileset");
+        assertPropertyContains("testFileset", ".xml ");
+        String result = getProperty("testFileset");
+        assertPropertyEndsWith("testFileset", ".xml");
+    }
+
+    public void testFilesetSeparator() {
+        executeTarget("testFilesetSeparator");
+        assertPropertyContains("testFilesetSeparator", ".xml\",\"");
+        assertPropertyEndsWith("testFilesetSeparator", ".xml");
+    }
+
+    public void testPath() {
+        executeTarget("testPath");
+        assertPropertyContains("testPath", "makeurl.xml");
+    }
+
+    /**
+     * assert that a property ends with
+     *
+     * @param property
+     * @param ending
+     */
+    private void assertPropertyEndsWith(String property, String ending) {
+        String result = getProperty(property);
+        String substring = result.substring(result.length() - ending.length());
+        assertEquals(ending, substring);
+    }
+
+    /**
+     * assert that a property contains a string
+     *
+     * @param property name of property to look for
+     * @param contains what to search for in the string
+     */
+    protected void assertPropertyContains(String property, String contains) {
+        String result = getProperty(property);
+
+        assertTrue("expected " + contains + " in " + result,
+                result != null && result.indexOf(contains) >= 0);
+    }
+
+    /**
+     * get a property from the project
+     *
+     * @param property
+     * @return
+     */
+    protected String getProperty(String property) {
+        return project.getProperty(property);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestClassPathTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestClassPathTest.java
new file mode 100644
index 0000000..08ecb08
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestClassPathTest.java
@@ -0,0 +1,167 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.util.JavaEnvUtils;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+
+/**
+ * Tests &lt;bm:manifestclasspath&gt;.
+ */
+public class ManifestClassPathTest
+             extends BuildFileTest {
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/manifestclasspath.xml");
+    }
+
+    public void testBadDirectory() {
+        expectBuildExceptionContaining("test-bad-directory", "bad-jar-dir",
+                                       "Jar's directory not found:");
+        assertPropertyUnset("jar.classpath");
+    }
+
+    public void testBadNoProperty() {
+        expectBuildExceptionContaining("test-bad-no-property", "no-property",
+                                       "Missing 'property' attribute!");
+        assertPropertyUnset("jar.classpath");
+    }
+
+    public void testBadPropertyExists() {
+        expectBuildExceptionContaining("test-bad-property-exists",
+            "property-exits", "Property 'jar.classpath' already set!");
+        assertPropertyEquals("jar.classpath", "exists");
+    }
+
+    public void testBadNoJarfile() {
+        expectBuildExceptionContaining("test-bad-no-jarfile", "no-jarfile",
+                                       "Missing 'jarfile' attribute!");
+        assertPropertyUnset("jar.classpath");
+    }
+
+    public void testBadNoClassPath() {
+        expectBuildExceptionContaining("test-bad-no-classpath", "no-classpath",
+                                       "Missing nested <classpath>!");
+        assertPropertyUnset("jar.classpath");
+    }
+
+    public void testParentLevel1() {
+        executeTarget("test-parent-level1");
+
+        assertPropertyEquals("jar.classpath", "dsp-core/ " +
+                                              "dsp-pres/ " +
+                                              "dsp-void/ " +
+                                              "../generated/dsp-core/ " +
+                                              "../generated/dsp-pres/ " +
+                                              "../generated/dsp-void/ " +
+                                              "../resources/dsp-core/ " +
+                                              "../resources/dsp-pres/ " +
+                                              "../resources/dsp-void/");
+    }
+
+    public void testParentLevel2() {
+        executeTarget("test-parent-level2");
+
+        assertPropertyEquals("jar.classpath", "../dsp-core/ " +
+                                              "../dsp-pres/ " +
+                                              "../dsp-void/ " +
+                                              "../../generated/dsp-core/ " +
+                                              "../../generated/dsp-pres/ " +
+                                              "../../generated/dsp-void/ " +
+                                              "../../resources/dsp-core/ " +
+                                              "../../resources/dsp-pres/ " +
+                                              "../../resources/dsp-void/");
+    }
+
+    public void testParentLevel2TooDeep() {
+        expectBuildExceptionContaining("test-parent-level2-too-deep", "nopath",
+                                       "No suitable relative path from ");
+        assertPropertyUnset("jar.classpath");
+    }
+
+    public void testPseudoTahoeRefid() {
+        if (!RegexpMatcherFactory.regexpMatcherPresent(project)) {
+            System.out.println("Test 'testPseudoTahoeRefid' skipped because no regexp matcher is present.");
+            return;
+        }
+        executeTarget("test-pseudo-tahoe-refid");
+        assertPropertyEquals("jar.classpath", "classes/dsp-core/ " +
+                                              "classes/dsp-pres/ " +
+                                              "classes/dsp-void/ " +
+                                              "generated/dsp-core/ " +
+                                              "resources/dsp-core/ " +
+                                              "resources/dsp-pres/");
+    }
+
+    public void testPseudoTahoeNested() {
+        if (!RegexpMatcherFactory.regexpMatcherPresent(project)) {
+            System.out.println("Test 'testPseudoTahoeNested' skipped because no regexp matcher is present.");
+            return;
+        }
+        executeTarget("test-pseudo-tahoe-nested");
+        assertPropertyEquals("jar.classpath", "classes/dsp-core/ " +
+                                              "classes/dsp-pres/ " +
+                                              "classes/dsp-void/ " +
+                                              "generated/dsp-core/ " +
+                                              "resources/dsp-core/ " +
+                                              "resources/dsp-pres/");
+    }
+
+    public void testParentLevel2WithJars() {
+        executeTarget("test-parent-level2-with-jars");
+
+        assertPropertyEquals("jar.classpath", "../../lib/acme-core.jar " +
+                                              "../../lib/acme-pres.jar " +
+                                              "../dsp-core/ " +
+                                              "../dsp-pres/ " +
+                                              "../dsp-void/ " +
+                                              "../../generated/dsp-core/ " +
+                                              "../../generated/dsp-pres/ " +
+                                              "../../generated/dsp-void/ " +
+                                              "../../resources/dsp-core/ " +
+                                              "../../resources/dsp-pres/ " +
+                                              "../../resources/dsp-void/");
+    }
+    public void testInternationalGerman() {
+        if (!JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_4)) {
+            System.out.println("Test with international characters skipped under pre 1.4 jvm.");
+            return;
+        }
+        executeTarget("international-german");
+        expectLogContaining("run-two-jars", "beta alpha");
+            
+    }
+    public void testInternationalHebrew() {
+        if (!JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_4)) {
+            System.out.println("Test with international characters skipped under pre 1.4 jvm.");
+            return;
+        }
+        if (!Os.isFamily("windows")) {
+            executeTarget("international-hebrew");
+            expectLogContaining("run-two-jars", "beta alpha");
+        } else {
+            System.out.println("Test with hebrew path not attempted under Windows");
+        }
+
+    }
+
+} // END class ManifestClassPathTest
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestTest.java
new file mode 100644
index 0000000..225473c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ManifestTest.java
@@ -0,0 +1,366 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
+/**
+ * Testcase for the Manifest class used in the jar task.
+ *
+ */
+public class ManifestTest extends BuildFileTest {
+
+    public static final String EXPANDED_MANIFEST
+        = "src/etc/testcases/taskdefs/manifests/META-INF/MANIFEST.MF";
+
+    public static final String LONG_LINE
+        = "AReallyLongLineToTestLineBreakingInManifests-ACapabilityWhich" +
+          "IsSureToLeadToHundredsOfQuestionsAboutWhyAntMungesManifests" +
+          "OfCourseTheAnswerIsThatIsWhatTheSpecRequiresAndIfAnythingHas" +
+          "AProblemWithThatItIsNotABugInAnt";
+
+    public static final String LONG_70_NAME 
+        = "ThisNameIsJustSeventyCharactersWhichIsAllowedAccordingToTheSpecsFiller";
+    public static final String LONG_68_NAME 
+        = "ThisNameIsJustSixtyEightCharactersWhichIsAllowedAccordingToTheSpecsX";
+    public static final String NOT_LONG_NAME 
+        = "NameIsJustUnderSeventyCharactersWhichIsAllowedAccordingTheSpec";
+
+    public static final String VALUE = "NOT_LONG";
+
+    public ManifestTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/manifest.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * Empty manifest - is OK
+     */
+    public void test1() throws ManifestException, IOException {
+        executeTarget("test1");
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        String version = manifest.getManifestVersion();
+        assertEquals("Manifest was not created with correct version - ", "1.0", version);
+    }
+
+    /**
+     * Simple Manifest with version 2.0
+     */
+    public void test2() throws ManifestException, IOException {
+        executeTarget("test2");
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        String version = manifest.getManifestVersion();
+        assertEquals("Manifest was not created with correct version - ", "2.0", version);
+    }
+
+    /**
+     * Malformed manifest - no : on the line
+     */
+    public void test3() {
+        expectBuildExceptionContaining("test3", "Manifest is invalid - no colon on header line",
+                                       "Invalid Manifest");
+    }
+
+    /**
+     * Malformed manifest - starts with continuation line
+     */
+    public void test4() {
+        expectBuildExceptionContaining("test4", "Manifest is invalid - section starts with continuation line",
+                                       "Invalid Manifest");
+   }
+
+    /**
+     * Malformed manifest - Name attribute in main section
+     */
+    public void test5() {
+        executeTarget("test5");
+        String output = getLog();
+        boolean hasWarning = output.indexOf("Manifest warning: \"Name\" attributes should not occur in the main section") != -1;
+        assertTrue("Expected warning about Name in main section", hasWarning);
+    }
+
+    /**
+     * New Section not starting with Name attribute.
+     */
+    public void test6() {
+        expectBuildExceptionContaining("test6", "Manifest is invalid - section starts with incorrect attribute",
+                                       "Invalid Manifest");
+        String output = getLog();
+        boolean hasWarning = output.indexOf("Manifest sections should start with a \"Name\" attribute") != -1;
+        assertTrue("Expected warning about section not starting with Name: attribute", hasWarning);
+    }
+
+    /**
+     * From attribute is illegal
+     */
+    public void test7() {
+        executeTarget("test7");
+
+        boolean hasWarning = getLog().indexOf(Manifest.ERROR_FROM_FORBIDDEN) != -1;
+        assertTrue("Expected warning about From: attribute", hasWarning);
+    }
+
+    /**
+     * Inline manifest - OK
+     */
+    public void test8() throws IOException, ManifestException {
+        executeTarget("test8");
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        Manifest.Section mainSection = manifest.getMainSection();
+        String classpath = mainSection.getAttributeValue("class-path");
+        assertEquals("Class-Path attribute was not set correctly - ", "fubar", classpath);
+
+        Manifest.Section testSection = manifest.getSection("Test");
+        String testAttr = testSection.getAttributeValue("TestAttr");
+        assertEquals("TestAttr attribute was not set correctly - ", "Test", testAttr);
+    }
+
+    /**
+     * Inline manifest - Invalid since has a Name attribute in the section element
+     */
+    public void test9() {
+        expectBuildExceptionContaining("test9", "Construction is invalid - Name attribute should not be used",
+                                       "Specify the section name using the \"name\" attribute of the <section> element");
+    }
+
+    /**
+     * Inline manifest - Invalid attribute without name
+     */
+    public void test10() {
+        expectBuildExceptionContaining("test10", "Attribute has no name",
+                                       "Attributes must have name and value");
+    }
+
+    /**
+     * Inline manifest - Invalid attribute without value
+     */
+    public void test11() {
+        expectBuildExceptionContaining("test11", "Attribute has no value",
+                                       "Attributes must have name and value");
+    }
+
+    /**
+     * Inline manifest - Invalid attribute without value
+     */
+    public void test12() {
+        expectBuildExceptionContaining("test12", "Section with no name",
+                                       "Sections must have a name");
+    }
+
+    /**
+     * Inline manifest - Duplicate attribute
+     */
+    public void test13() {
+        expectBuildExceptionContaining("test13", "Duplicate Attribute",
+                                       "The attribute \"Test\" may not occur more than once in the same section");
+    }
+
+    /**
+     * Inline manifest - OK since classpath entries can be duplicated.
+     */
+    public void test14() throws IOException, ManifestException {
+        executeTarget("test14");
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        Manifest.Section mainSection = manifest.getMainSection();
+        String classpath = mainSection.getAttributeValue("class-path");
+        assertEquals("Class-Path attribute was not set correctly - ",
+            "Test1 Test2 Test3 Test4", classpath);
+    }
+
+    /**
+     * Tets long line wrapping
+     */
+    public void testLongLine() throws IOException, ManifestException {
+        Project p = getProject();
+        p.setUserProperty("test.longline", LONG_LINE);
+        p.setUserProperty("test.long68name" , LONG_68_NAME);
+        p.setUserProperty("test.long70name" , LONG_70_NAME);
+        p.setUserProperty("test.notlongname" , NOT_LONG_NAME);
+        p.setUserProperty("test.value", VALUE);
+        executeTarget("testLongLine");
+
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        Manifest.Section mainSection = manifest.getMainSection();
+        String classpath = mainSection.getAttributeValue("class-path");
+        assertEquals("Class-Path attribute was not set correctly - ",
+            LONG_LINE, classpath);
+        
+        String value = mainSection.getAttributeValue(LONG_68_NAME);
+        assertEquals("LONG_68_NAME_VALUE_MISMATCH", VALUE, value);
+        value = mainSection.getAttributeValue(LONG_70_NAME);
+        assertEquals("LONG_70_NAME_VALUE_MISMATCH", VALUE, value);
+        value = mainSection.getAttributeValue(NOT_LONG_NAME);
+        assertEquals("NOT_LONG_NAME_VALUE_MISMATCH", VALUE, value);
+        
+        BufferedReader in = new BufferedReader(new FileReader(EXPANDED_MANIFEST));
+        
+        Set set = new HashSet();
+        String read = in.readLine();
+        while (read != null)
+        {
+            set.add(read);
+            read = in.readLine();
+        }
+        
+        assertTrue("Manifest file should have contained string ", set
+                .remove(" NOT_LONG"));
+        assertTrue("Manifest file should have contained string ", set
+                .remove(" NG"));
+        assertTrue("Manifest file should have contained string ", set
+                .remove(LONG_70_NAME + ": "));
+        assertTrue("Manifest file should have contained string ", set
+                .remove(NOT_LONG_NAME + ": NOT_LO"));
+    }
+
+    /**
+     * Tests ordering of sections
+     */
+    public void testOrder1() throws IOException, ManifestException {
+        executeTarget("testOrder1");
+
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        Enumeration e = manifest.getSectionNames();
+        String section1 = (String)e.nextElement();
+        String section2 = (String)e.nextElement();
+        assertEquals("First section name unexpected", "Test1", section1);
+        assertEquals("Second section name unexpected", "Test2", section2);
+
+        Manifest.Section section = manifest.getSection("Test1");
+        e = section.getAttributeKeys();
+        String attr1Key = (String)e.nextElement();
+        String attr2Key = (String)e.nextElement();
+        String attr1 = section.getAttribute(attr1Key).getName();
+        String attr2 = section.getAttribute(attr2Key).getName();
+        assertEquals("First attribute name unexpected", "TestAttr1", attr1);
+        assertEquals("Second attribute name unexpected", "TestAttr2", attr2);
+    }
+
+    /**
+     * Tests ordering of sections
+     */
+    public void testOrder2() throws IOException, ManifestException {
+        executeTarget("testOrder2");
+
+        Manifest manifest = getManifest(EXPANDED_MANIFEST);
+        Enumeration e = manifest.getSectionNames();
+        String section1 = (String)e.nextElement();
+        String section2 = (String)e.nextElement();
+        assertEquals("First section name unexpected", "Test2", section1);
+        assertEquals("Second section name unexpected", "Test1", section2);
+
+        Manifest.Section section = manifest.getSection("Test1");
+        e = section.getAttributeKeys();
+        String attr1Key = (String)e.nextElement();
+        String attr2Key = (String)e.nextElement();
+        String attr1 = section.getAttribute(attr1Key).getName();
+        String attr2 = section.getAttribute(attr2Key).getName();
+        assertEquals("First attribute name unexpected", "TestAttr2", attr1);
+        assertEquals("Second attribute name unexpected", "TestAttr1", attr2);
+    }
+
+    /**
+     * file attribute for manifest task is required.
+     */
+    public void testNoFile() {
+        expectBuildException("testNoFile", "file is required");
+    }
+
+    /**
+     * replace changes Manifest-Version from 2.0 to 1.0
+     */
+    public void testReplace() throws IOException, ManifestException {
+        executeTarget("testReplace");
+        Manifest mf = getManifest("src/etc/testcases/taskdefs/mftest.mf");
+        assertNotNull(mf);
+        assertEquals(Manifest.getDefaultManifest(), mf);
+    }
+
+    /**
+     * update keeps the Manifest-Version and adds a new attribute Foo
+     */
+    public void testUpdate() throws IOException, ManifestException {
+        executeTarget("testUpdate");
+        Manifest mf = getManifest("src/etc/testcases/taskdefs/mftest.mf");
+        assertNotNull(mf);
+        assertTrue(!Manifest.getDefaultManifest().equals(mf));
+        String mfAsString = mf.toString();
+        assertNotNull(mfAsString);
+        assertTrue(mfAsString.startsWith("Manifest-Version: 2.0"));
+        assertTrue(mfAsString.indexOf("Foo: Bar") > -1);
+
+        mf = getManifest("src/etc/testcases/taskdefs/mftest2.mf");
+        assertNotNull(mf);
+        mfAsString = mf.toString();
+        assertNotNull(mfAsString);
+        assertEquals(-1, mfAsString.indexOf("Foo: Bar"));
+        assertTrue(mfAsString.indexOf("Foo: Baz") > -1);
+    }
+
+    public void testFrom() {
+        expectLogContaining("testFrom", Manifest.ERROR_FROM_FORBIDDEN);
+    }
+
+    public void testIllegalName() {
+        expectBuildException("testIllegalName", "Manifest attribute names must not contain ' '");
+    }
+
+    public void testIllegalNameInSection() {
+        expectBuildException("testIllegalNameInSection", "Manifest attribute names must not contain ' '");
+    }
+
+    public void testIllegalNameBegin() {
+        expectBuildException("testIllegalNameInSection", "Manifest attribute names must not start with '-' at the begin.");
+    }
+
+    public void testIllegalName2() {
+        expectBuildException("testIllegalName", "Manifest attribute names must not contain '.'");
+    }
+
+    public void testIllegalName3() {
+        expectBuildException("testIllegalName", "Manifest attribute names must not contain '*'");
+    }
+
+    /**
+     * Reads mftest.mf.
+     */
+    private Manifest getManifest(String filename) throws IOException, ManifestException {
+        FileReader r = new FileReader(new File(System.getProperty("root"), filename));
+        try {
+            return new Manifest(r);
+        } finally {
+            r.close();
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MkdirTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MkdirTest.java
new file mode 100644
index 0000000..d9a1078
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MkdirTest.java
@@ -0,0 +1,51 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class MkdirTest extends BuildFileTest {
+
+    public MkdirTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/mkdir.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "directory already exists as a file");
+    }
+
+    public void test3() {
+        executeTarget("test3");
+        java.io.File f = new java.io.File(getProjectDir(), "testdir.tmp");
+        if (!f.exists() || !f.isDirectory()) {
+            fail("mkdir failed");
+        } else {
+            f.delete();
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MoveTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MoveTest.java
new file mode 100644
index 0000000..ce5dc71
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MoveTest.java
@@ -0,0 +1,146 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Tests the Move task.
+ *
+ */
+public class MoveTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public MoveTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/move.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testFilterSet() throws IOException {
+        executeTarget("testFilterSet");
+        File tmp  = new File(getProjectDir(), "move.filterset.tmp");
+        File check  = new File(getProjectDir(), "expected/copy.filterset.filtered");
+        assertTrue(tmp.exists());
+        assertTrue(FILE_UTILS.contentEquals(tmp, check));
+    }
+
+    public void testFilterChain() throws IOException {
+        executeTarget("testFilterChain");
+        File tmp  = new File(getProjectDir(), "move.filterchain.tmp");
+        File check  = new File(getProjectDir(), "expected/copy.filterset.filtered");
+        assertTrue(tmp.exists());
+        assertTrue(FILE_UTILS.contentEquals(tmp, check));
+    }
+
+    /** Bugzilla Report 11732 */
+    public void testDirectoryRemoval() throws IOException {
+        executeTarget("testDirectoryRemoval");
+        assertTrue(!getProject().resolveFile("E/B/1").exists());
+        assertTrue(getProject().resolveFile("E/C/2").exists());
+        assertTrue(getProject().resolveFile("E/D/3").exists());
+        assertTrue(getProject().resolveFile("A/B/1").exists());
+        assertTrue(!getProject().resolveFile("A/C/2").exists());
+        assertTrue(!getProject().resolveFile("A/D/3").exists());
+        assertTrue(!getProject().resolveFile("A/C").exists());
+        assertTrue(!getProject().resolveFile("A/D").exists());
+    }
+
+    /** Bugzilla Report 18886 */
+    public void testDirectoryRetaining() throws IOException {
+        executeTarget("testDirectoryRetaining");
+        assertTrue(getProject().resolveFile("E").exists());
+        assertTrue(getProject().resolveFile("E/1").exists());
+        assertTrue(!getProject().resolveFile("A/1").exists());
+        assertTrue(getProject().resolveFile("A").exists());
+    }
+
+    public void testCompleteDirectoryMove() throws IOException {
+        testCompleteDirectoryMove("testCompleteDirectoryMove");
+    }
+
+    public void testCompleteDirectoryMove2() throws IOException {
+        testCompleteDirectoryMove("testCompleteDirectoryMove2");
+    }
+
+    private void testCompleteDirectoryMove(String target) throws IOException {
+        executeTarget(target);
+        assertTrue(getProject().resolveFile("E").exists());
+        assertTrue(getProject().resolveFile("E/1").exists());
+        assertTrue(!getProject().resolveFile("A/1").exists());
+        // <path> swallows the basedir, it seems
+        //assertTrue(!getProject().resolveFile("A").exists());
+    }
+
+    public void testPathElementMove() throws IOException {
+        executeTarget("testPathElementMove");
+        assertTrue(getProject().resolveFile("E").exists());
+        assertTrue(getProject().resolveFile("E/1").exists());
+        assertTrue(!getProject().resolveFile("A/1").exists());
+        assertTrue(getProject().resolveFile("A").exists());
+    }
+
+    public void testMoveFileAndFileset() {
+        executeTarget("testMoveFileAndFileset");
+    }
+
+    public void testCompleteDirectoryMoveToExistingDir() {
+        executeTarget("testCompleteDirectoryMoveToExistingDir");
+    }
+
+    public void testCompleteDirectoryMoveFileToFile() {
+        executeTarget("testCompleteDirectoryMoveFileToFile");
+    }
+
+    public void testCompleteDirectoryMoveFileToDir() {
+        executeTarget("testCompleteDirectoryMoveFileToDir");
+    }
+
+    public void testCompleteDirectoryMoveFileAndFileset() {
+        executeTarget("testCompleteDirectoryMoveFileAndFileset");
+    }
+
+    public void testCompleteDirectoryMoveFileToExistingFile() {
+        executeTarget("testCompleteDirectoryMoveFileToExistingFile");
+    }
+
+    public void testCompleteDirectoryMoveFileToExistingDir() {
+        executeTarget("testCompleteDirectoryMoveFileToExistingDir");
+    }
+
+    public void testCompleteDirectoryMoveFileToDirWithExistingFile() {
+        executeTarget("testCompleteDirectoryMoveFileToDirWithExistingFile");
+    }
+
+    public void testCompleteDirectoryMoveFileToDirWithExistingDir() {
+        executeTarget("testCompleteDirectoryMoveFileToDirWithExistingDir");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MultiMapTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MultiMapTest.java
new file mode 100644
index 0000000..680a8eb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/MultiMapTest.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileNameMapper;
+
+
+/**
+ */
+public class MultiMapTest extends BuildFileTest {
+
+    public MultiMapTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/multimap.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testMultiCopy() {
+        executeTarget("multicopy");
+    }
+
+    public void testMultiMove() {
+        executeTarget("multimove");
+    }
+
+    public void testSingleCopy() {
+        executeTarget("singlecopy");
+    }
+
+    public void testSingleMove() {
+        executeTarget("singlemove");
+    }
+
+    public void testCopyWithEmpty() {
+        executeTarget("copywithempty");
+    }
+
+    public void testMoveWithEmpty() {
+        executeTarget("movewithempty");
+    }
+
+    public static class TestMapper implements FileNameMapper {
+        public TestMapper() {}
+        public void setFrom(String from) {}
+        public void setTo(String to) {}
+        public String[] mapFileName(final String source_file_name) {
+            return new String[] {
+                source_file_name, source_file_name+".copy2" };
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/NiceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/NiceTest.java
new file mode 100644
index 0000000..26d483a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/NiceTest.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * test nice
+ */
+public class NiceTest extends BuildFileTest {
+
+    public NiceTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/nice.xml");
+    }
+
+    public void testNoop() {
+        executeTarget("noop");
+    }
+
+    public void testCurrent() {
+        executeTarget("current");
+    }
+
+    public void testFaster() {
+        executeTarget("faster");
+    }
+
+    public void testSlower() {
+        executeTarget("slower");
+    }
+
+    public void testTooSlow() {
+        expectBuildExceptionContaining(
+                "too_slow","out of range","out of the range 1-10");
+    }
+
+    public void testTooFast() {
+        expectBuildExceptionContaining(
+                "too_fast", "out of range", "out of the range 1-10");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ParallelTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ParallelTest.java
new file mode 100644
index 0000000..b3b3cb7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ParallelTest.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+import java.io.PrintStream;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DemuxOutputStream;
+import org.apache.tools.ant.Project;
+
+/**
+ * Test of the parallel TaskContainer
+ *
+ * @created 21 February 2002
+ */
+public class ParallelTest extends BuildFileTest {
+    /** Standard property value for the basic test */
+    public final static String DIRECT_MESSAGE = "direct";
+    /** Standard property value for the basic and fail test */
+    public final static String DELAYED_MESSAGE = "delayed";
+    /** Standard property value for the fail test */
+    public final static String FAILURE_MESSAGE = "failure";
+
+    /** the build fiel associated with this test */
+    public final static String TEST_BUILD_FILE
+         = "src/etc/testcases/taskdefs/parallel.xml";
+
+    /**
+     * Constructor for the ParallelTest object
+     *
+     * @param name name of the test
+     */
+    public ParallelTest(String name) {
+        super(name);
+    }
+
+    /** The JUnit setup method */
+    public void setUp() {
+        configureProject(TEST_BUILD_FILE);
+    }
+
+    /** tests basic operation of the parallel task */
+    public void testBasic() {
+        // should get no output at all
+        Project p = getProject();
+        p.setUserProperty("test.direct", DIRECT_MESSAGE);
+        p.setUserProperty("test.delayed", DELAYED_MESSAGE);
+        expectOutputAndError("testBasic", "", "");
+        String log = getLog();
+        assertEquals("parallel tasks didn't output correct data", log,
+            DIRECT_MESSAGE + DELAYED_MESSAGE);
+
+    }
+
+    /** tests basic operation of the parallel task */
+    public void testThreadCount() {
+        // should get no output at all
+        Project p = getProject();
+        p.setUserProperty("test.direct", DIRECT_MESSAGE);
+        p.setUserProperty("test.delayed", DELAYED_MESSAGE);
+        expectOutputAndError("testThreadCount", "", "");
+        String log = getLog();
+        int pos = 0;
+        while (pos > -1) {
+            pos = countThreads(log, pos);
+        }
+    }
+
+    /**
+     * the test result string should match the regex
+     * <code>^(\|\d+\/(+-)*)+\|$</code> for someting like
+     * <code>|3/++--+-|5/+++++-----|</code>
+     *
+     *@returns -1 no more tests
+     *          # start pos of next test
+     *@throws AssertionFailedException when a constraint is invalid
+     */
+    static int countThreads(String s, int start) {
+        int firstPipe = s.indexOf('|', start);
+        int beginSlash = s.indexOf('/', firstPipe);
+        int lastPipe = s.indexOf('|', beginSlash);
+        if ((firstPipe == -1) || (beginSlash == -1) || (lastPipe == -1)) {
+            return -1;
+        }
+
+        int max = Integer.parseInt(s.substring(firstPipe + 1, beginSlash));
+        int current = 0;
+        int pos = beginSlash + 1;
+        while (pos < lastPipe) {
+            switch (s.charAt(pos++)) {
+                case '+':
+                    current++;
+                    break;
+                case '-':
+                    current--;
+                    break;
+                default:
+                    throw new AssertionFailedError("Only expect '+-' in result count, found "
+                        + s.charAt(--pos) + " at position " + pos);
+            }
+            if (current > max) {
+                throw new AssertionFailedError("Number of executing threads exceeded number allowed: "
+                    + current + " > " + max);
+            }
+        }
+        return lastPipe;
+    }
+
+
+    /** tests the failure of a task within a parallel construction */
+    public void testFail() {
+        // should get no output at all
+        Project p = getProject();
+        p.setUserProperty("test.failure", FAILURE_MESSAGE);
+        p.setUserProperty("test.delayed", DELAYED_MESSAGE);
+        expectBuildExceptionContaining("testFail",
+            "fail task in one parallel branch", FAILURE_MESSAGE);
+    }
+
+    /** tests the demuxing of output streams in a multithreaded situation */
+    public void testDemux() {
+        Project p = getProject();
+        p.addTaskDefinition("demuxtest", DemuxOutputTask.class);
+        PrintStream out = System.out;
+        PrintStream err = System.err;
+        System.setOut(new PrintStream(new DemuxOutputStream(p, false)));
+        System.setErr(new PrintStream(new DemuxOutputStream(p, true)));
+
+        try {
+            p.executeTarget("testDemux");
+        } finally {
+            System.setOut(out);
+            System.setErr(err);
+        }
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PathConvertTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PathConvertTest.java
new file mode 100755
index 0000000..2f8428c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PathConvertTest.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Unit test for the &lt;pathconvert&gt; task.
+ */
+public class PathConvertTest extends BuildFileTest {
+    private static final String BUILD_PATH = "src/etc/testcases/taskdefs/";
+    private static final String BUILD_FILENAME = "pathconvert.xml";
+    private static final String BUILD_FILE = BUILD_PATH + BUILD_FILENAME;
+    
+    public PathConvertTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(BUILD_FILE);
+    }
+
+    public void testMap() {
+        test("testmap");
+    }
+
+    public void testMapper() {
+        test("testmapper");
+    }
+
+    public void testNoTargetOs() {
+        executeTarget("testnotargetos");
+    }
+
+    private void test(String target) {
+        executeTarget(target);
+        assertPropertyEquals("result", "test#" + BUILD_FILENAME);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PreSetDefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PreSetDefTest.java
new file mode 100644
index 0000000..f0a25ba
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PreSetDefTest.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ */
+public class PreSetDefTest extends BuildFileTest {
+    public PreSetDefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/presetdef.xml");
+    }
+
+    public void testSimple() {
+        expectLog("simple", "Hello world");
+    }
+
+    public void testText() {
+        expectLog("text", "Inner Text");
+    }
+
+    public void testUri() {
+        expectLog("uri", "Hello world");
+    }
+
+    public void testDefaultTest() {
+        expectLog("defaulttest", "attribute is false");
+    }
+
+    public void testDoubleDefault() {
+        expectLog("doubledefault", "attribute is falseattribute is true");
+    }
+
+    public void testTextOptional() {
+        expectLog("text.optional", "MyTextoverride text");
+    }
+
+    public void testElementOrder() {
+        expectLog("element.order", "Line 1Line 2");
+    }
+
+    public void testElementOrder2() {
+        expectLog("element.order2", "Line 1Line 2Line 3");
+    }
+
+    public void testAntTypeTest() {
+        expectLog("antTypeTest", "");
+    }
+
+    public void testCorrectTaskNameBadAttr() {
+        expectBuildExceptionContaining(
+            "correct_taskname_badattr", "attribute message", "javac doesn't support the");
+    }
+
+    public void testCorrectTaskNameBadEl() {
+        expectBuildExceptionContaining(
+            "correct_taskname_badel", "element message", "javac doesn't support the");
+    }
+    
+    public void testPresetdefWithNestedElementTwice() { // #38056
+        executeTarget("presetdef-with-nested-element-twice");
+        executeTarget("presetdef-with-nested-element-twice");
+    }
+    
+    /**
+     * A test class to check default properties
+     */
+    public static class DefaultTest extends Task {
+        boolean isSet = false;
+        boolean attribute = false;
+        public void setAttribute(boolean b) {
+            if (isSet) {
+                throw new BuildException("Attribute Already set");
+            }
+            attribute = b;
+            isSet = true;
+        }
+
+        public void execute() {
+            getProject().log("attribute is " + attribute);
+        }
+    }
+
+    /**
+     * A test class to check presetdef with add and addConfigured and ant-type
+     */
+    public static class AntTypeTest extends Task {
+        public void addFileSet(FileSet fileset) {
+        }
+        public void addConfiguredConfigured(FileSet fileset) {
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProcessDestroyerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProcessDestroyerTest.java
new file mode 100644
index 0000000..110e04a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProcessDestroyerTest.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Created on Feb 19, 2003
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class ProcessDestroyerTest extends TestCase {
+
+    /**
+     * Constructor for ProcessDestroyerTest.
+     * @param arg0
+     */
+    public ProcessDestroyerTest(String arg0) {
+        super(arg0);
+    }
+
+    public void testProcessDestroyer(){
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)) {
+            return;
+        }
+
+        try {
+            ProcessDestroyer processDestroyer = new ProcessDestroyer();
+            Process process =
+                Runtime.getRuntime().exec(
+                    "java -cp "
+                        + System.getProperty("java.class.path")
+                        + " "
+                        + getClass().getName());
+
+            assertFalse("Not registered as shutdown hook",
+                        processDestroyer.isAddedAsShutdownHook());
+
+            processDestroyer.add(process);
+
+            assertTrue("Registered as shutdown hook",
+                       processDestroyer.isAddedAsShutdownHook());
+            try {
+                process.destroy();
+            } finally {
+                processDestroyer.remove(process);
+            }
+
+            assertFalse("Not registered as shutdown hook",
+                        processDestroyer.isAddedAsShutdownHook());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void main(String[] args){
+        new ProcessDestroyerTest("testProcessDestroyer").testProcessDestroyer();
+        try{
+            Thread.sleep(60000);
+        }catch(InterruptedException ie){
+            ie.printStackTrace();
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PropertyTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PropertyTest.java
new file mode 100644
index 0000000..b830f53
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/PropertyTest.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class PropertyTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public PropertyTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/property.xml");
+    }
+
+    public void test1() {
+        // should get no output at all
+        expectOutputAndError("test1", "", "");
+    }
+
+    public void test2() {
+        expectLog("test2", "testprop1=aa, testprop3=xxyy, testprop4=aazz");
+    }
+
+    public void test3() {
+        try {
+            executeTarget("test3");
+        }
+        catch (BuildException e) {
+            assertTrue("Circular definition not detected - ",
+                     e.getMessage().indexOf("was circularly defined") != -1);
+            return;
+        }
+        fail("Did not throw exception on circular exception");
+    }
+
+    public void test4() {
+        expectLog("test4", "http.url is http://localhost:999");
+    }
+
+    public void test5() {
+        String baseDir = getProject().getProperty("basedir");
+        try {
+            String uri = FILE_UTILS.toURI(
+                baseDir + "/property3.properties");
+            getProject().setNewProperty(
+                "test5.url", uri);
+        } catch (Exception ex) {
+            throw new BuildException(ex);
+        }
+        expectLog("test5", "http.url is http://localhost:999");
+    }
+
+    public void testPrefixSuccess() {
+        executeTarget("prefix.success");
+        assertEquals("80", project.getProperty("server1.http.port"));
+    }
+
+    public void testPrefixFailure() {
+       try {
+            executeTarget("prefix.fail");
+        }
+        catch (BuildException e) {
+            assertTrue("Prefix allowed on non-resource/file load - ", 
+                     e.getMessage().indexOf("Prefix is only valid") != -1);
+            return;
+        }
+        fail("Did not throw exception on invalid use of prefix");
+    }
+
+    public void testCircularReference() {
+        try {
+            executeTarget("testCircularReference");
+        } catch (BuildException e) {
+            assertTrue("Circular definition not detected - ",
+                         e.getMessage().indexOf("was circularly defined")
+                         != -1);
+            return;
+        }
+        fail("Did not throw exception on circular exception");
+    }
+
+    public void testThisIsNotACircularReference() {
+        expectLog("thisIsNotACircularReference", "b is A/A/A");
+    }
+    
+    public void testXmlProperty() {
+        try {
+            Class.forName("java.lang.Iterable");
+            executeTarget("testXmlProperty");
+            assertEquals("ONE", project.getProperty("xml.one"));
+            assertEquals("TWO", project.getProperty("xml.two"));
+        } catch (ClassNotFoundException e) {
+            // Xml-Loading only on Java5+
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProtectedJarMethodsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProtectedJarMethodsTest.java
new file mode 100644
index 0000000..379df9c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ProtectedJarMethodsTest.java
@@ -0,0 +1,95 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class ProtectedJarMethodsTest extends BuildFileTest {
+
+    private static String tempJar = "tmp.jar";
+
+    public ProtectedJarMethodsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/jar.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testGrabFilesAndDirs() throws IOException {
+        executeTarget("testIndexTests");
+        String archive = getProject().resolveFile(tempJar).getAbsolutePath();
+        ArrayList dirs = new ArrayList();
+        ArrayList files = new ArrayList();
+        String[] expectedDirs = new String[] {
+            "sub/",
+        };
+        String[] expectedFiles = new String[] {
+            "foo",
+        };
+        Jar.grabFilesAndDirs(archive, dirs, files);
+        assertEquals(expectedDirs.length, dirs.size());
+        for (int i = 0; i < expectedDirs.length; i++) {
+            assertTrue("Found " + expectedDirs[i],
+                       dirs.contains(expectedDirs[i]));
+        }
+        assertEquals(expectedFiles.length, files.size());
+        for (int i = 0; i < expectedFiles.length; i++) {
+            assertTrue("Found " + expectedFiles[i],
+                       files.contains(expectedFiles[i]));
+        }
+    }
+
+    public void testFindJarNameNoClasspath() {
+        assertEquals("foo", Jar.findJarName("foo", null));
+        assertEquals("foo", Jar.findJarName("lib" + File.separatorChar + "foo",
+                                            null));
+    }
+
+    public void testFindJarNameNoMatch() {
+        assertNull(Jar.findJarName("foo", new String[] {"bar"}));
+    }
+
+    public void testFindJarNameSimpleMatches() {
+        assertEquals("foo", Jar.findJarName("foo", new String[] {"foo"}));
+        assertEquals("lib/foo", Jar.findJarName("foo",
+                                                new String[] {"lib/foo"}));
+        assertEquals("foo", Jar.findJarName("bar" + File.separatorChar + "foo",
+                                            new String[] {"foo"}));
+        assertEquals("lib/foo",
+                     Jar.findJarName("bar" + File.separatorChar + "foo",
+                                     new String[] {"lib/foo"}));
+    }
+
+    public void testFindJarNameLongestMatchWins() {
+        assertEquals("lib/foo",
+                     Jar.findJarName("lib/foo", 
+                                     new String[] {"foo", "lib/foo", 
+                                                   "lib/bar/foo"}));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RecorderTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RecorderTest.java
new file mode 100644
index 0000000..3750007
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RecorderTest.java
@@ -0,0 +1,85 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.IOException;
+
+/**
+ */
+public class RecorderTest extends BuildFileTest {
+
+    private static final String REC_IN = "recorder/";
+    private static final String REC_DIR = "recorder-out/";
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public RecorderTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/recorder.xml");
+        executeTarget("prepare");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testNoAppend() throws IOException {
+        executeTarget("noappend");
+        assertTrue(FILE_UTILS
+                   .contentEquals(project.resolveFile(REC_IN
+                                                      + "rectest1.result"),
+                                  project.resolveFile(REC_DIR
+                                                      + "rectest1.log"), true));
+    }
+
+    public void testAppend() throws IOException {
+        executeTarget("append");
+        assertTrue(FILE_UTILS
+                   .contentEquals(project.resolveFile(REC_IN
+                                                      + "rectest2.result"),
+                                  project.resolveFile(REC_DIR
+                                                      + "rectest2.log"), true));
+    }
+
+    public void testRestart() throws IOException {
+        executeTarget("restart");
+        assertTrue(FILE_UTILS
+                   .contentEquals(project.resolveFile(REC_IN
+                                                      + "rectest3.result"),
+                                  project.resolveFile(REC_DIR
+                                                      + "rectest3.log"), true));
+    }
+
+    public void testDeleteRestart() throws IOException {
+        executeTarget("deleterestart");
+        assertTrue(FILE_UTILS
+                   .contentEquals(project.resolveFile(REC_IN
+                                                      + "rectest4.result"),
+                                  project.resolveFile(REC_DIR
+                                                      + "rectest4.log"), true));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RenameTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RenameTest.java
new file mode 100644
index 0000000..8460fc1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RenameTest.java
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class RenameTest extends BuildFileTest {
+
+    public RenameTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/rename.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument missing");
+    }
+    public void test2() {
+        expectBuildException("test2", "required argument missing");
+    }
+    public void test3() {
+        expectBuildException("test3", "required argument missing");
+    }
+/*
+    public void test4() {
+        expectBuildException("test4", "source and destination the same");
+    }
+    public void test5() {
+        executeTarget("test5");
+    }
+    */
+    public void test6() {
+        executeTarget("test6");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ReplaceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ReplaceTest.java
new file mode 100644
index 0000000..22ee92a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ReplaceTest.java
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+import java.io.*;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ */
+public class ReplaceTest extends BuildFileTest {
+
+    public ReplaceTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/replace.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "empty token not allowed");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+    }
+
+    public void test6() {
+        expectBuildException("test6", "required argument not specified");
+    }
+
+    public void test7() {
+        expectBuildException("test7", "empty token not allowed");
+    }
+
+    public void test8() {
+        executeTarget("test8");
+    }
+
+    public void test9() throws IOException{
+        executeTarget("test9");
+        String tmpdir = project.getProperty("tmp.dir");
+        assertEqualContent(new File(tmpdir, "result.txt"),
+                    new File(tmpdir, "output.txt"));
+    }
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+    public void assertEqualContent(File expect, File result)
+        throws AssertionFailedError, IOException {
+        if (!result.exists()) {
+            fail("Expected file "+result+" doesn\'t exist");
+        }
+
+        InputStream inExpect = null;
+        InputStream inResult = null;
+        try {
+            inExpect = new BufferedInputStream(new FileInputStream(expect));
+            inResult = new BufferedInputStream(new FileInputStream(result));
+
+            int expectedByte = inExpect.read();
+            while (expectedByte != -1) {
+                assertEquals(expectedByte, inResult.read());
+                expectedByte = inExpect.read();
+            }
+            assertEquals("End of file", -1, inResult.read());
+        } finally {
+            if (inResult != null) {
+                inResult.close();
+            }
+            if (inExpect != null) {
+                inExpect.close();
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicAdvancedTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicAdvancedTest.java
new file mode 100644
index 0000000..d9630a8
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicAdvancedTest.java
@@ -0,0 +1,285 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.rmic.RmicAdapterFactory;
+import org.apache.tools.ant.taskdefs.rmic.DefaultRmicAdapter;
+
+/**
+ * Date: 04-Aug-2004
+ * Time: 22:15:46
+ */
+public class RmicAdvancedTest extends BuildFileTest {
+
+    public RmicAdvancedTest(String name) {
+        super(name);
+    }
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/rmic/";
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() throws Exception {
+        super.setUp();
+        configureProject(TASKDEFS_DIR + "rmic.xml");
+    }
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+    /**
+     * verify that "default" binds us to the default compiler
+     */
+    public void testDefault() throws Exception {
+        executeTarget("testDefault");
+    }
+
+    /**
+     * verify that "" binds us to the default compiler
+     */
+    public void testEmpty() throws Exception {
+        executeTarget("testEmpty");
+    }
+    /**
+     * test sun's rmic compiler
+     */
+    public void testRmic() throws Exception {
+        executeTarget("testRmic");
+    }
+
+    /**
+     * test sun's rmic compiler strips
+     * out -J arguments when not forking
+     */
+    public void testRmicJArg() throws Exception {
+        executeTarget("testRmicJArg");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testKaffe() throws Exception {
+        executeTarget("testKaffe");
+    }
+    // WLrmic tests don't work
+    /**
+     * test weblogic
+     */
+    public void XtestWlrmic() throws Exception {
+        executeTarget("testWlrmic");
+    }
+
+    /**
+     *  test weblogic's stripping of -J args
+     */
+    public void XtestWlrmicJArg() throws Exception {
+        executeTarget("testWlrmicJArg");
+    }
+
+    /**
+     * test the forking compiler
+     */
+    public void NotestForking() throws Exception {
+        executeTarget("testForking");
+    }
+
+    /**
+     * test the forking compiler
+     */
+    public void testForkingAntClasspath() throws Exception {
+        executeTarget("testForkingAntClasspath");
+    }
+
+    /**
+     * test the forking compiler
+     */
+    public void testAntClasspath() throws Exception {
+        executeTarget("testAntClasspath");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testBadName() throws Exception {
+        expectBuildExceptionContaining("testBadName",
+                "compiler not known",
+                RmicAdapterFactory.ERROR_UNKNOWN_COMPILER);
+    }
+
+    /**
+     * load an adapter by name
+     */
+    public void testExplicitClass() throws Exception {
+        executeTarget("testExplicitClass");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testWrongClass() throws Exception {
+        expectBuildExceptionContaining("testWrongClass",
+                "class not an RMIC adapter",
+                RmicAdapterFactory.ERROR_NOT_RMIC_ADAPTER);
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testDefaultBadClass() throws Exception {
+        expectBuildExceptionContaining("testDefaultBadClass",
+                "expected the class to fail",
+                Rmic.ERROR_RMIC_FAILED);
+        //dont look for much text here as it is vendor and version dependent
+        assertLogContaining("unimplemented.class");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testMagicProperty() throws Exception {
+        expectBuildExceptionContaining("testMagicProperty",
+                "magic property not working",
+                RmicAdapterFactory.ERROR_UNKNOWN_COMPILER);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testMagicPropertyOverridesEmptyString() throws Exception {
+        expectBuildExceptionContaining("testMagicPropertyOverridesEmptyString",
+                "magic property not working",
+                RmicAdapterFactory.ERROR_UNKNOWN_COMPILER);
+    }
+
+
+    /**
+     *
+     */
+    public void testMagicPropertyIsEmptyString() throws Exception {
+        executeTarget("testMagicPropertyIsEmptyString");
+    }
+
+
+    public void NotestFailingAdapter() throws Exception {
+        expectBuildExceptionContaining("testFailingAdapter",
+                "expected failures to propagate",
+                Rmic.ERROR_RMIC_FAILED);
+    }
+
+
+    /**
+     * test that version 1.1 stubs are good
+     * @throws Exception
+     */
+    public void testVersion11() throws Exception {
+        executeTarget("testVersion11");
+    }
+
+    /**
+     * test that version 1.2 stubs are good
+     *
+     * @throws Exception
+     */
+    public void testVersion12() throws Exception {
+        executeTarget("testVersion12");
+    }
+
+    /**
+     * test that version compat stubs are good
+     *
+     * @throws Exception
+     */
+    public void testVersionCompat() throws Exception {
+        executeTarget("testVersionCompat");
+    }
+
+    /**
+     * test that passes -Xnew to sun's rmic.
+     *
+     * @throws Exception
+     */
+    public void testXnew() throws Exception {
+        executeTarget("testXnew");
+    }
+
+    /**
+     * test that passes -Xnew to sun's rmic running in a different VM.
+     *
+     * @throws Exception
+     */
+    public void testXnewForked() throws Exception {
+        executeTarget("testXnewForked");
+    }
+
+    /**
+     * test that runs the new xnew compiler adapter.
+     *
+     * @throws Exception
+     */
+    public void testXnewCompiler() throws Exception {
+        executeTarget("testXnewCompiler");
+    }
+
+    /**
+     * test that verifies that IDL compiles.
+     *
+     * @throws Exception
+     */
+    public void testIDL() throws Exception {
+        executeTarget("testIDL");
+    }
+
+    /**
+     * test that verifies that IIOP compiles.
+     *
+     * @throws Exception
+     */
+    public void testIIOP() throws Exception {
+        executeTarget("testIIOP");
+    }
+
+    /**
+     * this little bunny verifies that we can load stuff, and that
+     * a failure to execute is turned into a fault
+     */
+    public static class FailingRmicAdapter extends DefaultRmicAdapter {
+        public static final String LOG_MESSAGE = "hello from FailingRmicAdapter";
+
+        /**
+         * Executes the task.
+         *
+         * @return false -always
+         */
+        public boolean execute() throws BuildException {
+            getRmic().log(LOG_MESSAGE);
+            return false;
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicTest.java
new file mode 100644
index 0000000..78f07d1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/RmicTest.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import junit.framework.TestCase;
+
+
+/**
+ * Testcase for <rmic>.
+ *
+ * @since Ant 1.5
+ */
+public class RmicTest extends TestCase {
+
+    private Project project;
+    private Rmic rmic;
+
+    public RmicTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.init();
+        rmic = new Rmic();
+        rmic.setProject(project);
+    }
+
+    /**
+     * Test nested compiler args.
+     */
+    public void testCompilerArg() {
+        String[] args = rmic.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("no args", 0, args.length);
+
+        Rmic.ImplementationSpecificArgument arg = rmic.createCompilerArg();
+        String ford = "Ford";
+        String prefect = "Prefect";
+        String testArg = ford + " " + prefect;
+        arg.setValue(testArg);
+        args = rmic.getCurrentCompilerArgs();
+        assertEquals("unconditional single arg", 1, args.length);
+        assertEquals(testArg, args[0]);
+
+        arg.setCompiler("weblogic");
+        args = rmic.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("implementation is weblogic but build.rmic is null",
+                     0, args.length);
+
+        project.setProperty("build.rmic", "sun");
+        args = rmic.getCurrentCompilerArgs();
+        assertNotNull(args);
+        assertEquals("implementation is weblogic but build.rmic is sun",
+                     0, args.length);
+
+        project.setProperty("build.rmic", "weblogic");
+        args = rmic.getCurrentCompilerArgs();
+        assertEquals("both are weblogic", 1, args.length);
+        assertEquals(testArg, args[0]);
+    }
+
+    /**
+     * Test compiler attribute.
+     */
+    public void testCompilerAttribute() {
+        // check defaults
+        String compiler = rmic.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("expected sun or kaffe, but found "+compiler,compiler,"default");
+
+        project.setNewProperty("build.rmic", "weblogic");
+        compiler = rmic.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("weblogic", compiler);
+
+        // check attribute overrides build.compiler
+        rmic.setCompiler("kaffe");
+        compiler = rmic.getCompiler();
+        assertNotNull(compiler);
+        assertEquals("kaffe", compiler);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SQLExecTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SQLExecTest.java
new file mode 100644
index 0000000..6854b8b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SQLExecTest.java
@@ -0,0 +1,237 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.sql.Driver;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.DriverPropertyInfo;
+import java.util.Properties;
+import java.io.File;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Simple testcase to test for driver caching.
+ * To test for your own database, you may need to tweak getProperties(int)
+ * and add a couple of keys. see testOracle and testMySQL for an example.
+ *
+ * It would be much better to extend this testcase by using HSQL
+ * as the test db, so that a db is really used.
+ *
+ */
+public class SQLExecTest extends TestCase {
+
+    // some database keys, see #getProperties(int)
+    public final static int NULL = 0;
+    public final static int ORACLE = 1;
+    public final static int MYSQL = 2;
+
+    // keys used in properties.
+    public final static String DRIVER = "driver";
+    public final static String USER = "user";
+    public final static String PASSWORD = "password";
+    public final static String URL = "url";
+    public final static String PATH = "path";
+    public final static String SQL = "sql";
+
+    public SQLExecTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() throws Exception {
+        // make sure the cache is cleared.
+        JDBCTask.getLoaderMap().clear();
+    }
+
+   // simple test to ensure that the caching does work...
+    public void testDriverCaching(){
+        SQLExec sql = createTask(getProperties(NULL));
+        assertTrue(!SQLExec.getLoaderMap().containsKey(NULL_DRIVER));
+        try {
+            sql.execute();
+        } catch (BuildException e){
+            assertTrue(e.getException().getMessage().indexOf("No suitable Driver") != -1);
+        }
+        assertTrue(SQLExec.getLoaderMap().containsKey(NULL_DRIVER));
+        assertSame(sql.getLoader(), JDBCTask.getLoaderMap().get(NULL_DRIVER));
+        ClassLoader loader1 = sql.getLoader();
+
+        // 2nd run..
+        sql = createTask(getProperties(NULL));
+        // the driver must still be cached.
+        assertTrue(JDBCTask.getLoaderMap().containsKey(NULL_DRIVER));
+        try {
+            sql.execute();
+        } catch (BuildException e){
+            assertTrue(e.getException().getMessage().indexOf("No suitable Driver") != -1);
+        }
+        assertTrue(JDBCTask.getLoaderMap().containsKey(NULL_DRIVER));
+        assertSame(sql.getLoader(), JDBCTask.getLoaderMap().get(NULL_DRIVER));
+        assertSame(loader1, sql.getLoader());
+    }
+
+    public void testNull() throws Exception {
+        doMultipleCalls(1000, NULL, true, true);
+    }
+
+    /*
+    public void testOracle(){
+        doMultipleCalls(1000, ORACLE, true, false);
+    }*/
+
+    /*
+    public void testMySQL(){
+        doMultipleCalls(1000, MYSQL, true, false);
+    }*/
+
+
+    /**
+     * run a sql tasks multiple times.
+     * @param calls number of times to execute the task
+     * @param database the database to execute on.
+     * @param caching should caching be enabled ?
+     * @param catchexception true to catch exception for each call, false if not.
+     */
+    protected void doMultipleCalls(int calls, int database, boolean caching, boolean catchexception){
+        Properties props = getProperties(database);
+        for (int i = 0; i < calls; i++){
+            SQLExec sql = createTask(props);
+            sql.setCaching(caching);
+            try  {
+                sql.execute();
+            } catch (BuildException e){
+                if (!catchexception){
+                    throw e;
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a task from a set of properties
+     * @see #getProperties(int)
+     */
+    protected SQLExec createTask(Properties props){
+        SQLExec sql = new SQLExec();
+        sql.setProject( new Project() );
+        sql.setDriver( props.getProperty(DRIVER) );
+        sql.setUserid( props.getProperty(USER) );
+        sql.setPassword( props.getProperty(PASSWORD) );
+        sql.setUrl( props.getProperty(URL) );
+        sql.createClasspath().setLocation( new File(props.getProperty(PATH)) );
+        sql.addText( props.getProperty(SQL) );
+        return sql;
+    }
+
+    /**
+     * try to find the path from a resource (jar file or directory name)
+     * so that it can be used as a classpath to load the resource.
+     */
+    protected String findResourcePath(String resource){
+        resource = resource.replace('.', '/') + ".class";
+        URL url = getClass().getClassLoader().getResource(resource);
+        if (url == null) {
+            return null;
+        }
+        String u = url.toString();
+        if (u.startsWith("jar:file:")) {
+            int pling = u.indexOf("!");
+            return u.substring("jar:file:".length(), pling);
+        } else if (u.startsWith("file:")) {
+            int tail = u.indexOf(resource);
+            return u.substring("file:".length(), tail);
+        }
+        return null;
+    }
+
+    /**
+     * returns a configuration associated to a specific database.
+     * If you want to test on your specific base, you'd better
+     * tweak this to make it run or add your own database.
+     * The driver lib should be dropped into the system classloader.
+     */
+    protected Properties getProperties(int database){
+        Properties props = null;
+        switch (database){
+            case ORACLE:
+                props = getProperties("oracle.jdbc.driver.OracleDriver", "test", "test", "jdbc:oracle:thin:@127.0.0.1:1521:orcl");
+                break;
+            case MYSQL:
+                props = getProperties("org.gjt.mm.mysql.Driver", "test", "test", "jdbc:mysql://127.0.0.1:3306/test");
+                break;
+            case NULL:
+            default:
+                props = getProperties(NULL_DRIVER, "test", "test", "jdbc:database://hostname:port/name");
+        }
+        // look for the driver path...
+        String path = findResourcePath(props.getProperty(DRIVER));
+        props.put(PATH, path);
+        props.put(SQL, "create table OOME_TEST(X INTEGER NOT NULL);\ndrop table if exists OOME_TEST;");
+        return props;
+    }
+
+    /** helper method to build properties */
+    protected Properties getProperties(String driver, String user, String pwd, String url){
+        Properties props = new Properties();
+        props.put(DRIVER, driver);
+        props.put(USER, user);
+        props.put(PASSWORD, pwd);
+        props.put(URL, url);
+        return props;
+    }
+
+
+//--- NULL JDBC driver just for simple test since there are no db driver
+// available as a default in Ant :)
+
+    public final static String NULL_DRIVER = NullDriver.class.getName();
+
+    public static class NullDriver implements Driver {
+        public Connection connect(String url, Properties info)
+                throws SQLException {
+            return null;
+        }
+
+        public boolean acceptsURL(String url) throws SQLException {
+            return false;
+        }
+
+        public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)
+                throws SQLException {
+            return new DriverPropertyInfo[0];
+        }
+
+        public int getMajorVersion() {
+            return 0;
+        }
+
+        public int getMinorVersion() {
+            return 0;
+        }
+
+        public boolean jdbcCompliant() {
+            return false;
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SignJarTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SignJarTest.java
new file mode 100644
index 0000000..a232d6aa
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SignJarTest.java
@@ -0,0 +1,216 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * Testcase for the Signjar task
+ *
+ */
+public class SignJarTest extends BuildFileTest {
+
+    public static final String EXPANDED_MANIFEST
+        = "src/etc/testcases/taskdefs/manifests/META-INF/MANIFEST.MF";
+
+
+    public SignJarTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/signjar.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * check for being offline
+     * @return true iff the system property "offline" is "true"
+     */
+    private boolean isOffline() {
+        return Boolean.getBoolean("offline");
+    }
+    public void testBasicSigning() {
+        executeTarget("basic");
+    }
+
+    public void testSigFile() {
+        executeTarget("sigfile");
+    }
+
+    public void testMaxMemory() {
+        executeTarget("maxmemory");
+    }
+
+    public void testURLKeystoreFile() {
+        executeTarget("urlKeystoreFile");
+    }
+
+    public void testURLKeystoreHTTP() {
+        if(!isOffline()) {
+            executeTarget("urlKeystoreHTTP");
+        }
+    }
+
+    public void testPreserveLastModified() {
+        executeTarget("preserveLastModified");
+    }
+
+    public void testFileset() {
+        executeTarget("testFileset");
+    }
+
+    public void testFilesetAndJar() {
+        executeTarget("testFilesetAndJar");
+    }
+
+    public void testFilesetAndSignedJar() {
+        expectBuildExceptionContaining("testFilesetAndSignedJar",
+                "incompatible attributes",
+                SignJar.ERROR_SIGNEDJAR_AND_PATHS);
+    }
+
+    public void testPath() {
+        executeTarget("testPath");
+    }
+
+    public void testPathAndJar() {
+        executeTarget("testPathAndJar");
+    }
+
+    public void testPathAndSignedJar() {
+        expectBuildExceptionContaining("testPathAndSignedJar",
+                "incompatible attributes",
+                SignJar.ERROR_SIGNEDJAR_AND_PATHS);
+    }
+
+    public void testSignedJar() {
+        executeTarget("testSignedJar");
+    }
+
+    public void testDestDir() {
+        executeTarget("testDestDir");
+    }
+
+    public void testDestDirAndSignedJar() {
+        expectBuildExceptionContaining("testFilesetAndSignedJar",
+                "incompatible attributes",
+                SignJar.ERROR_SIGNEDJAR_AND_PATHS);
+    }
+
+    public void testDestDirAndSignedJar2() {
+        expectBuildExceptionContaining("testPathAndSignedJar",
+                "incompatible attributes",
+                SignJar.ERROR_SIGNEDJAR_AND_PATHS);
+    }
+
+    public void testDestDirFileset() {
+        executeTarget("testDestDirFileset");
+    }
+
+    public void testMapperFileset() {
+        executeTarget("testMapperFileset");
+    }
+
+    public void testDestDirPath() {
+        executeTarget("testDestDirPath");
+    }
+
+    public void testMapperPath() {
+        executeTarget("testMapperPath");
+    }
+
+    public void testMapperNoDest() {
+        expectBuildExceptionContaining("testMapperNoDest",
+                "two mappers",
+                SignJar.ERROR_MAPPER_WITHOUT_DEST);
+    }
+
+    public void testTwoMappers() {
+        expectBuildExceptionContaining("testTwoMappers",
+                "two mappers",
+                SignJar.ERROR_TOO_MANY_MAPPERS);
+    }
+
+    public void testNoAlias() {
+        expectBuildExceptionContaining("testNoAlias",
+                "no alias",
+                SignJar.ERROR_NO_ALIAS);
+    }
+
+    public void testNoFiles() {
+        expectBuildExceptionContaining("testNoFiles",
+                "no files",
+                SignJar.ERROR_NO_SOURCE);
+    }
+
+    public void testNoStorePass() {
+        expectBuildExceptionContaining("testNoStorePass",
+                "no password",
+                SignJar.ERROR_NO_STOREPASS);
+    }
+
+    public void testTsaLocalhost() {
+        //only test on java1.5+
+        if(JavaEnvUtils.getJavaVersionNumber()>=15) {
+            expectBuildException("testTsaLocalhost",
+                "no TSA at localhost:0");
+            assertLogContaining("java.net.ConnectException");
+        }
+    }
+
+    public void testSysProperty() {
+        executeTarget("testSysProperty");
+    }
+
+    public void testVerifyJar() {
+        executeTarget("testVerifyJar");
+    }
+
+    public void testVerifyNoArgs() {
+        expectBuildExceptionContaining("testVerifyNoArgs",
+                "no args",
+                AbstractJarSignerTask.ERROR_NO_SOURCE);
+    }
+
+    public void testVerifyJarUnsigned() {
+        expectBuildExceptionContaining("testVerifyJarUnsigned",
+                "unsigned JAR file",
+                VerifyJar.ERROR_NO_VERIFY);
+    }
+
+    public void NotestVerifyJarNotInKeystore() {
+        expectBuildExceptionContaining("testVerifyJarNotInKeystore",
+                "signature not in keystore",
+                VerifyJar.ERROR_NO_VERIFY);
+    }
+
+    public void testVerifyFileset() {
+        executeTarget("testVerifyFileset");
+    }
+
+    public void testVerifyPath() {
+        executeTarget("testVerifyPath");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SleepTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SleepTest.java
new file mode 100644
index 0000000..63b61af
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SleepTest.java
@@ -0,0 +1,111 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+/**
+ * @created 01 May 2001
+ */
+public class SleepTest extends BuildFileTest {
+
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/";
+    private final static boolean TRACE=false;
+	private final static int ERROR_RANGE=1000;
+	
+    public SleepTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "sleep.xml");
+    }
+
+    public void test1() {
+       Timer timer=new Timer();
+        executeTarget("test1");
+        timer.stop();
+        if(TRACE) System.out.println(" test1 elapsed time="+timer.time());
+        assertTrue(timer.time()>=0);
+    }
+
+    public void test2() {
+        Timer timer=new Timer();
+        executeTarget("test2");
+        timer.stop();
+        if(TRACE) System.out.println(" test2 elapsed time="+timer.time());
+        assertTrue(timer.time()>=0);
+    }
+
+    public void test3() {
+        Timer timer=new Timer();
+        executeTarget("test3");
+        timer.stop();
+        if(TRACE) System.out.println(" test3 elapsed time="+timer.time());
+        assertTrue(timer.time()>=(2000-ERROR_RANGE));
+    }
+
+    public void test4() {
+        Timer timer=new Timer();
+        executeTarget("test3");
+        timer.stop();
+        if(TRACE) System.out.println(" test4 elapsed time="+timer.time());
+        assertTrue(timer.time()>=(2000-ERROR_RANGE) && timer.time()<60000);
+    }
+
+    public void test5() {
+        expectBuildException("test5",
+            "Negative sleep periods are not supported");
+    }
+
+    public void test6() {
+        Timer timer=new Timer();
+        executeTarget("test6");
+        timer.stop();
+        if(TRACE) System.out.println(" test6 elapsed time="+timer.time());
+        assertTrue(timer.time()<2000);
+    }
+
+
+    /**
+    * inner timer class
+    */
+    private static class Timer {
+        long start=0;
+        long stop=0;
+
+        public Timer() {
+            start();
+        }
+
+        public void start() {
+            start=System.currentTimeMillis();
+        }
+
+        public void stop() {
+            stop=System.currentTimeMillis();
+        }
+
+        public long time() {
+            return stop-start;
+        }
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/StyleTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/StyleTest.java
new file mode 100644
index 0000000..2c1778e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/StyleTest.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.taskdefs.optional.XsltTest;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * TestCases for {@link XSLTProcess} task.
+ * XXX merge with {@link XsltTest}?
+ * @version 2003-08-05
+ */
+public class StyleTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public StyleTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() throws Exception {
+        configureProject("src/etc/testcases/taskdefs/style/build.xml");
+        //executeTarget("setup");
+        //commented out for performance while target is empty
+    }
+
+    protected void tearDown() throws Exception {
+        executeTarget("teardown");
+    }
+
+    public void testStyleIsSet() throws Exception {
+        expectSpecificBuildException("testStyleIsSet",
+                "no stylesheet specified", "specify the " +
+                "stylesheet either as a filename in style " +
+                "attribute or as a nested resource");
+    }
+
+    public void testTransferParameterSet() throws Exception {
+        expectFileContains("testTransferParameterSet",  // target
+                           "out/out.xml",               // file
+                           "set='myvalue'");            // exptected string
+    }
+
+    public void testTransferParameterEmpty() throws Exception {
+        expectFileContains("testTransferParameterEmpty",
+                           "out/out.xml",
+                           "empty=''");
+    }
+
+    public void testTransferParameterUnset() throws Exception {
+        expectFileContains("testTransferParameterUnset",
+                           "out/out.xml",
+                           "undefined='${value}'");
+    }
+
+    public void testTransferParameterUnsetWithIf() throws Exception {
+        expectFileContains("testTransferParameterUnsetWithIf",
+                           "out/out.xml",
+                           "undefined='undefined default value'");
+    }
+
+    public void testNewerStylesheet() throws Exception {
+        expectFileContains("testNewerStylesheet",
+                           "out/out.xml",
+                           "new-value");
+    }
+
+    public void testDefaultMapper() throws Exception {
+        testDefaultMapper("testDefaultMapper");
+    }
+
+    public void testExplicitFileset() throws Exception {
+        testDefaultMapper("testExplicitFileset");
+    }
+
+    public void testDefaultMapper(String target) throws Exception {
+        assertTrue(!(FileUtils.getFileUtils().resolveFile(
+                getProject().getBaseDir(),"out/data.html")).exists());
+        expectFileContains(target,
+                           "out/data.html",
+                           "set='myvalue'");
+    }
+
+    public void testCustomMapper() throws Exception {
+        assertTrue(!FILE_UTILS.resolveFile(
+                getProject().getBaseDir(), "out/out.xml").exists());
+        expectFileContains("testCustomMapper",
+                           "out/out.xml",
+                           "set='myvalue'");
+    }
+
+    public void testTypedMapper() throws Exception {
+        assertTrue(!FILE_UTILS.resolveFile(
+                getProject().getBaseDir(), "out/out.xml").exists());
+        expectFileContains("testTypedMapper",
+                           "out/out.xml",
+                           "set='myvalue'");
+    }
+
+    public void testDirectoryHierarchyWithDirMatching() throws Exception {
+        executeTarget("testDirectoryHierarchyWithDirMatching");
+        assertTrue(FILE_UTILS.resolveFile(
+                getProject().getBaseDir(), "out/dest/level1/data.html")
+                   .exists());
+    }
+
+    public void testDirsWithSpaces() throws Exception {
+        executeTarget("testDirsWithSpaces");
+        assertTrue(FILE_UTILS.resolveFile(
+                getProject().getBaseDir(), "out/d est/data.html")
+                   .exists());
+    }
+
+    public void testWithStyleAttrAndResource() throws Exception {
+        expectSpecificBuildException("testWithStyleAttrAndResource",
+                "Must throws a BuildException", "specify the " +
+                "stylesheet either as a filename in style " +
+                "attribute or as a nested resource but not " +
+                "as both");
+    }
+
+    public void testWithFileResource() throws Exception {
+        expectFileContains("testWithFileResource", "out/out.xml", "set='value'");
+    }
+
+    public void testWithUrlResource() throws Exception {
+        expectFileContains("testWithUrlResource", "out/out.xml", "set='value'");
+    }
+
+    public void testFilenameAsParam() throws Exception {
+        executeTarget("testFilenameAsParam");
+        assertFileContains("out/out/one.txt",      "filename='one.xml'");
+        assertFileContains("out/out/two.txt",      "filename='two.xml'");
+        assertFileContains("out/out/three.txt",    "filename='three.xml'");
+        assertFileContains("out/out/dir/four.txt", "filename='four.xml'");
+        assertFileContains("out/out/dir/four.txt", "filedir ='-not-set-'");
+    }
+
+    public void testFilenameAsParamNoSetting() throws Exception {
+        executeTarget("testFilenameAsParamNoSetting");
+        assertFileContains("out/out/one.txt",      "filename='-not-set-'");
+        assertFileContains("out/out/two.txt",      "filename='-not-set-'");
+        assertFileContains("out/out/three.txt",    "filename='-not-set-'");
+        assertFileContains("out/out/dir/four.txt", "filename='-not-set-'");
+    }
+
+    public void testFilenameAndFiledirAsParam() throws Exception {
+        executeTarget("testFilenameAndFiledirAsParam");
+        assertFileContains("out/out/one.txt",      "filename='one.xml'");
+        assertFileContains("out/out/one.txt",      "filedir ='.'");
+        assertFileContains("out/out/dir/four.txt", "filename='four.xml'");
+        assertFileContains("out/out/dir/four.txt", "filedir ='dir'");
+    }
+
+
+    // *************  copied from ConcatTest  *************
+
+    // ------------------------------------------------------
+    //   Helper methods - should be in BuildFileTest
+    // -----------------------------------------------------
+
+    private String getFileString(String filename)
+        throws IOException
+    {
+        Reader r = null;
+        try {
+            r = new FileReader(getProject().resolveFile(filename));
+            return  FileUtils.readFully(r);
+        }
+        finally {
+            FileUtils.close(r);
+        }
+    }
+
+    private void expectFileContains(
+        String target, String filename, String contains)
+        throws IOException
+    {
+        executeTarget(target);
+        assertFileContains(filename, contains);
+    }
+
+    private void assertFileContains(String filename, String contains) throws IOException {
+        String content = getFileString(filename);
+        assertTrue(
+              "expecting file " + filename
+            + " to contain " + contains
+            + " but got " + content,
+            content.indexOf(contains) > -1);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SubAntTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SubAntTest.java
new file mode 100644
index 0000000..ede8b0e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SubAntTest.java
@@ -0,0 +1,144 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import junit.framework.AssertionFailedError;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildListener;
+
+
+public class SubAntTest extends BuildFileTest {
+
+    public SubAntTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/subant.xml");
+    }
+
+    public void testnodirs() {
+        project.executeTarget("testnodirs");
+        expectLog("testnodirs", "No sub-builds to iterate on");
+    }
+
+    // target must be specified
+    public void testgenericantfile() {
+        File dir1 = project.resolveFile(".");
+        File dir2 = project.resolveFile("subant/subant-test1");
+        File dir3 = project.resolveFile("subant/subant-test2");
+
+        testBaseDirs("testgenericantfile",
+                     new String[] { dir1.getAbsolutePath(),
+                         dir2.getAbsolutePath(),
+                         dir3.getAbsolutePath()
+
+                     });
+    }
+
+    public void testantfile() {
+        File dir1 = project.resolveFile(".");
+        // basedir of subant/subant-test1/subant.xml is ..
+        // therefore we expect here the subant/subant-test1 subdirectory
+        File dir2 = project.resolveFile("subant/subant-test1");
+        // basedir of subant/subant-test2/subant.xml is ..
+        // therefore we expect here the subant subdirectory
+        File dir3 = project.resolveFile("subant");
+
+        testBaseDirs("testantfile",
+                     new String[] { dir1.getAbsolutePath(),
+                         dir2.getAbsolutePath(),
+                         dir3.getAbsolutePath()
+
+                     });
+
+    }
+    
+    public void testMultipleTargets() {
+        executeTarget("multipleTargets");
+        assertLogContaining("test1-one");
+        assertLogContaining("test1-two");
+        assertLogContaining("test2-one");
+        assertLogContaining("test2-two");
+    }
+    
+    public void testMultipleTargetsOneDoesntExist_FOEfalse() {
+        executeTarget("multipleTargetsOneDoesntExist_FOEfalse");
+        assertLogContaining("Target \"three\" does not exist in the project \"subant\"");
+    }
+    
+    public void testMultipleTargetsOneDoesntExist_FOEtrue() {
+        expectBuildExceptionContaining("multipleTargetsOneDoesntExist_FOEtrue", 
+                                       "Calling not existent target", 
+                                       "Target \"three\" does not exist in the project \"subant\"");
+    }
+
+    protected void testBaseDirs(String target, String[] dirs) {
+        SubAntTest.BasedirChecker bc = new SubAntTest.BasedirChecker(dirs);
+        project.addBuildListener(bc);
+        executeTarget(target);
+        AssertionFailedError ae = bc.getError();
+        if (ae != null) {
+            throw ae;
+        }
+        project.removeBuildListener(bc);
+    }
+
+    private class BasedirChecker implements BuildListener {
+        private String[] expectedBasedirs;
+        private int calls = 0;
+        private AssertionFailedError error;
+
+        BasedirChecker(String[] dirs) {
+            expectedBasedirs = dirs;
+        }
+
+        public void buildStarted(BuildEvent event) {}
+        public void buildFinished(BuildEvent event) {}
+        public void targetFinished(BuildEvent event){}
+        public void taskStarted(BuildEvent event) {}
+        public void taskFinished(BuildEvent event) {}
+        public void messageLogged(BuildEvent event) {}
+
+        public void targetStarted(BuildEvent event) {
+            if (event.getTarget().getName().equals("")) {
+                return;
+            }
+            if (error == null) {
+                try {
+                    assertEquals(expectedBasedirs[calls++],
+                            event.getProject().getBaseDir().getAbsolutePath());
+                } catch (AssertionFailedError e) {
+                    error = e;
+                }
+            }
+        }
+
+        AssertionFailedError getError() {
+            return error;
+        }
+
+    }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SyncTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SyncTest.java
new file mode 100644
index 0000000..62302d3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/SyncTest.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class SyncTest extends BuildFileTest {
+
+    public SyncTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/sync.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testSimpleCopy() {
+        executeTarget("simplecopy");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsPresent(d);
+        assertTrue(getFullLog().indexOf("dangling") == -1);
+    }
+
+    public void testEmptyCopy() {
+        executeTarget("emptycopy");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsNotPresent(d);
+        String c = getProject().getProperty("dest") + "/a/b/c";
+        assertFileIsNotPresent(c);
+        assertTrue(getFullLog().indexOf("dangling") == -1);
+    }
+
+    public void testEmptyDirCopy() {
+        executeTarget("emptydircopy");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsNotPresent(d);
+        String c = getProject().getProperty("dest") + "/a/b/c";
+        assertFileIsPresent(c);
+        assertTrue(getFullLog().indexOf("dangling") == -1);
+    }
+
+    public void testCopyAndRemove() {
+        testCopyAndRemove("copyandremove");
+    }
+
+    public void testCopyAndRemoveWithFileList() {
+        testCopyAndRemove("copyandremove-with-filelist");
+    }
+
+    public void testCopyAndRemoveWithZipfileset() {
+        testCopyAndRemove("copyandremove-with-zipfileset");
+    }
+
+    private void testCopyAndRemove(String target) {
+        executeTarget(target);
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsPresent(d);
+        String f = getProject().getProperty("dest") + "/e/f";
+        assertFileIsNotPresent(f);
+        assertTrue(getFullLog().indexOf("Removing orphan file:") > -1);
+        assertDebuglogContaining("Removed 1 dangling file from");
+        assertDebuglogContaining("Removed 1 dangling directory from");
+    }
+
+    public void testCopyAndRemoveEmptyPreserve() {
+        executeTarget("copyandremove-emptypreserve");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsPresent(d);
+        String f = getProject().getProperty("dest") + "/e/f";
+        assertFileIsNotPresent(f);
+        assertTrue(getFullLog().indexOf("Removing orphan file:") > -1);
+        assertDebuglogContaining("Removed 1 dangling file from");
+        assertDebuglogContaining("Removed 1 dangling directory from");
+    }
+
+    public void testEmptyDirCopyAndRemove() {
+        executeTarget("emptydircopyandremove");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsNotPresent(d);
+        String c = getProject().getProperty("dest") + "/a/b/c";
+        assertFileIsPresent(c);
+        String f = getProject().getProperty("dest") + "/e/f";
+        assertFileIsNotPresent(f);
+        assertTrue(getFullLog().indexOf("Removing orphan directory:") > -1);
+        assertDebuglogContaining("NO dangling file to remove from");
+        assertDebuglogContaining("Removed 2 dangling directories from");
+    }
+
+    public void testCopyNoRemove() {
+        executeTarget("copynoremove");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsPresent(d);
+        String f = getProject().getProperty("dest") + "/e/f";
+        assertFileIsPresent(f);
+        assertTrue(getFullLog().indexOf("Removing orphan file:") == -1);
+    }
+
+    public void testCopyNoRemoveSelectors() {
+        executeTarget("copynoremove-selectors");
+        String d = getProject().getProperty("dest") + "/a/b/c/d";
+        assertFileIsPresent(d);
+        String f = getProject().getProperty("dest") + "/e/f";
+        assertFileIsPresent(f);
+        assertTrue(getFullLog().indexOf("Removing orphan file:") == -1);
+    }
+
+    public void assertFileIsPresent(String f) {
+        assertTrue("Expected file " + f,
+                   getProject().resolveFile(f).exists());
+    }
+
+    public void assertFileIsNotPresent(String f) {
+        assertTrue("Didn't expect file " + f,
+                   !getProject().resolveFile(f).exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TStampTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TStampTest.java
new file mode 100644
index 0000000..8f91546
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TStampTest.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+import junit.framework.TestCase;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Location;
+
+/**
+ *
+ */
+public class TStampTest extends TestCase {
+
+    protected Tstamp tstamp;
+    protected Project project;
+    protected Location location;
+
+    public TStampTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() throws Exception {
+        location = new Location("test.xml");
+        project = new Project();
+        tstamp = new Tstamp();
+        tstamp.setLocation(location);
+        tstamp.setProject(project);
+    }
+
+    public void testTimeZone() throws Exception {
+        Tstamp.CustomFormat format = tstamp.createFormat();
+        format.setProperty("today");
+        format.setPattern("HH:mm:ss z");
+        format.setTimezone("GMT");
+        Date date = Calendar.getInstance().getTime();
+        format.execute(project, date, location);
+        String today = project.getProperty("today");
+
+        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss z");
+        sdf.setTimeZone( TimeZone.getTimeZone("GMT") );
+        String expected = sdf.format(date);
+
+        assertEquals(expected, today);
+    }
+
+    /**
+     * verifies that custom props have priority over the
+     * originals
+     * @throws Exception
+     */
+    public void testWriteOrder() throws Exception {
+        Tstamp.CustomFormat format = tstamp.createFormat();
+        format.setProperty("TODAY");
+        format.setPattern("HH:mm:ss z");
+        format.setTimezone("GMT");
+        Date date = Calendar.getInstance().getTime();
+        format.execute(project, date, location);
+        String today = project.getProperty("TODAY");
+
+        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss z");
+        sdf.setTimeZone( TimeZone.getTimeZone("GMT") );
+        String expected = sdf.format(date);
+
+        assertEquals(expected, today);
+
+    }
+
+    /**
+     * verifies that custom props have priority over the
+     * originals
+     * @throws Exception
+     */
+    public void testPrefix() throws Exception {
+        tstamp.setPrefix("prefix");
+        tstamp.execute();
+        String prop= project.getProperty("prefix.DSTAMP");
+        assertNotNull(prop);
+    }
+
+    public void testFormatPrefix() throws Exception {
+	Tstamp.CustomFormat format = tstamp.createFormat();
+        format.setProperty("format");
+        format.setPattern("HH:mm:ss z");
+        format.setTimezone("GMT");
+
+        tstamp.setPrefix("prefix");
+        tstamp.execute();
+        String prop= project.getProperty("prefix.format");
+        assertNotNull(prop);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java
new file mode 100644
index 0000000..55bed19
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TarTest.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.IOException;
+import java.io.File;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class TarTest extends BuildFileTest {
+
+    public TarTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/tar.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "tar cannot include itself");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+        File f
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test5.tar");
+
+        if (!f.exists()) {
+            fail("Tarring a directory failed");
+        }
+    }
+
+    public void test6() {
+        expectBuildException("test6", "Invalid value specified for longfile attribute.");
+    }
+
+    public void test7() {
+        test7("test7");
+    }
+
+    public void test7UsingPlainFileSet() {
+        test7("test7UsingPlainFileSet");
+    }
+
+    public void test7UsingFileList() {
+        test7("test7UsingFileList");
+    }
+
+    private void test7(String target) {
+        executeTarget(target);
+        File f1
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test7-prefix");
+
+        if (!(f1.exists() && f1.isDirectory())) {
+            fail("The prefix attribute is not working properly.");
+        }
+
+        File f2
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test7dir");
+
+        if (!(f2.exists() && f2.isDirectory())) {
+            fail("The prefix attribute is not working properly.");
+        }
+    }
+
+    public void test8() {
+        test8("test8");
+    }
+
+    public void test8UsingZipFileset() {
+        test8("test8UsingZipFileset");
+    }
+
+    public void test8UsingZipFilesetSrc() {
+        test8("test8UsingZipFilesetSrc");
+    }
+
+    public void test8UsingTarFilesetSrc() {
+        test8("test8UsingTarFilesetSrc");
+    }
+
+    public void test8UsingZipEntry() {
+        test8("test8UsingZipEntry");
+    }
+
+    private void test8(String target) {
+        executeTarget(target);
+        File f1
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test8.xml");
+        if (! f1.exists()) {
+            fail("The fullpath attribute or the preserveLeadingSlashes attribute does not work propertly");
+        }
+    }
+
+    public void test9() {
+        expectBuildException("test9", "Invalid value specified for compression attribute.");
+    }
+
+    public void test10() {
+        executeTarget("test10");
+        File f1
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test10.xml");
+        if (! f1.exists()) {
+            fail("The fullpath attribute or the preserveLeadingSlashes attribute does not work propertly");
+        }
+    }
+
+    public void test11() {
+        executeTarget("test11");
+        File f1
+            = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/test11.xml");
+        if (! f1.exists()) {
+            fail("The fullpath attribute or the preserveLeadingSlashes attribute does not work propertly");
+        }
+    }
+
+    public void testGZipResource() throws IOException {
+        executeTarget("testGZipResource");
+        assertTrue(FileUtils.getFileUtils()
+                   .contentEquals(getProject().resolveFile("../asf-logo.gif"),
+                                  getProject().resolveFile("testout/asf-logo.gif.gz")));
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefTest.java
new file mode 100644
index 0000000..091a393
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class TaskdefTest extends BuildFileTest {
+
+    public TaskdefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/taskdef.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+    public void test4() {
+        expectBuildException("test4", "classname specified doesn't exist");
+    }
+
+    public void test5() {
+        expectBuildException("test5", "No public execute() in " + Project.class);
+    }
+
+    public void test5a() {
+        executeTarget("test5a");
+    }
+
+    public void test6() {
+        expectLog("test6", "simpletask: worked");
+    }
+
+    public void test7() {
+        expectLog("test7", "worked");
+    }
+
+    public void testGlobal() {
+        expectLog("testGlobal", "worked");
+    }
+
+    public void testOverride() {
+        executeTarget("testOverride");
+        String log = getLog();
+        assertTrue("override warning sent",
+                   log.indexOf("Trying to override old definition of task copy") > -1);
+        assertTrue("task inside target worked",
+                   log.indexOf("In target") > -1);
+        assertTrue("task inside target worked",
+                   log.indexOf("In TaskContainer") > -1);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefsTest.java
new file mode 100644
index 0000000..5de5ef4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TaskdefsTest.java
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * @deprecated use BuildFileTest instead.
+ */
+public abstract class TaskdefsTest extends BuildFileTest {
+
+    public TaskdefsTest(String name) {
+        super(name);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TestProcess.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TestProcess.java
new file mode 100644
index 0000000..00ebe4b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TestProcess.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Interactive Testcase for Processdestroyer.
+ *
+ */
+public class TestProcess
+    implements Runnable
+{
+    private boolean run = true;
+    private boolean done = false;
+
+    public void shutdown()
+    {
+        if (!done)
+        {
+            System.out.println("shutting down TestProcess");
+            run = false;
+
+            synchronized(this)
+            {
+                while (!done)
+                {
+                    try { wait(); } catch (InterruptedException ie) {}
+                }
+            }
+
+            System.out.println("TestProcess shut down");
+        }
+    }
+
+    public void run()
+    {
+        for (int i = 0; i < 5 && run; i++)
+        {
+            System.out.println(Thread.currentThread().getName());
+
+            try { Thread.sleep(2000); } catch (InterruptedException ie) {}
+        }
+
+        synchronized(this)
+        {
+            done = true;
+            notifyAll();
+        }
+    }
+
+    public Thread getShutdownHook()
+    {
+        return new TestProcessShutdownHook();
+    }
+
+    private class TestProcessShutdownHook
+        extends Thread
+    {
+        public void run()
+        {
+            shutdown();
+        }
+    }
+
+    public static void main(String[] args)
+    {
+        TestProcess tp = new TestProcess();
+        new Thread(tp, "TestProcess thread").start();
+        Runtime.getRuntime().addShutdownHook(tp.getShutdownHook());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TimeProcess.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TimeProcess.java
new file mode 100644
index 0000000..eee15d1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TimeProcess.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+/**
+ * Helper class for ExecuteWatchdogTest and ExecuteJavaTest.
+ *
+ * <p>Used to be an inner class of ExecuteWatchdogTest.
+ *
+ */
+public class TimeProcess {
+    public static void main(String[] args) throws Exception {
+        int time = Integer.parseInt(args[0]);
+        if (time < 1) {
+            throw new IllegalArgumentException("Invalid time: " + time);
+        }
+        Thread.sleep(time);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TouchTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TouchTest.java
new file mode 100644
index 0000000..ea7d499
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TouchTest.java
@@ -0,0 +1,183 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+
+public class TouchTest extends BuildFileTest {
+
+    private static String TOUCH_FILE = "src/etc/testcases/taskdefs/touchtest";
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public TouchTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/touch.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public long getTargetTime() {
+
+        File file = new File(System.getProperty("root"), TOUCH_FILE);
+        if(!file.exists()) {
+            throw new BuildException("failed to touch file " + file);
+        }
+        return file.lastModified();
+    }
+
+    /**
+     * No real test, simply checks whether the dateformat without
+     * seconds is accepted - by erroring out otherwise.
+     */
+    public void testNoSeconds() {
+        executeTarget("noSeconds");
+        long time = getTargetTime();
+    }
+
+    /**
+     * No real test, simply checks whether the dateformat with
+     * seconds is accepted - by erroring out otherwise.
+     */
+    public void testSeconds() {
+        executeTarget("seconds");
+        long time=getTargetTime();
+    }
+    /**
+     * verify that the millis test sets things up
+     */
+    public void testMillis() {
+        touchFile("testMillis", 662256000000L);
+    }
+
+    /**
+     * verify that the default value defaults to now
+     */
+    public void testNow() {
+        long now=System.currentTimeMillis();
+        executeTarget("testNow");
+        long time = getTargetTime();
+        assertTimesNearlyMatch(time,now,5000);
+    }
+    /**
+     * verify that the millis test sets things up
+     */
+    public void test2000() {
+        touchFile("test2000", 946080000000L);
+    }
+
+    /**
+     * test the file list
+     */
+    public void testFilelist() {
+        touchFile("testFilelist", 662256000000L);
+    }
+
+    /**
+     * test the file set
+     */
+    public void testFileset() {
+        touchFile("testFileset", 946080000000L);
+    }
+
+    /**
+     * test the resource collection
+     */
+    public void testResourceCollection() {
+        touchFile("testResourceCollection", 1662256000000L);
+    }
+
+    /**
+     * test the mapped file set
+     */
+    public void testMappedFileset() {
+        executeTarget("testMappedFileset");
+    }
+
+    /**
+     * test the explicit mapped file set
+     */
+    public void testExplicitMappedFileset() {
+        executeTarget("testExplicitMappedFileset");
+    }
+
+    /**
+     * test the mapped file list
+     */
+    public void testMappedFilelist() {
+        executeTarget("testMappedFilelist");
+    }
+
+    /**
+     * test the pattern attribute
+     */
+    public void testGoodPattern() {
+        executeTarget("testGoodPattern");
+    }
+
+    /**
+     * test the pattern attribute again
+     */
+    public void testBadPattern() {
+        expectBuildExceptionContaining("testBadPattern",
+            "No parsing exception thrown", "Unparseable");
+    }
+
+    /**
+     * run a target to touch the test file; verify the timestamp is as expected
+     * @param targetName
+     * @param timestamp
+     */
+    private void touchFile(String targetName, long timestamp) {
+        executeTarget(targetName);
+        long time = getTargetTime();
+        assertTimesNearlyMatch(timestamp, time);
+    }
+
+    /**
+     * assert that two times are within the current FS granularity;
+     * @param timestamp
+     * @param time
+     */
+    public void assertTimesNearlyMatch(long timestamp,long time) {
+        long granularity= FILE_UTILS.getFileTimestampGranularity();
+        assertTimesNearlyMatch(timestamp, time, granularity);
+    }
+
+    /**
+     * assert that two times are within a specified range
+     * @param timestamp
+     * @param time
+     * @param range
+     */
+    private void assertTimesNearlyMatch(long timestamp, long time, long range) {
+        assertTrue("Time " + timestamp + " is not within " + range + " ms of "
+            + time, (Math.abs(time - timestamp) <= range));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypeAdapterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypeAdapterTest.java
new file mode 100644
index 0000000..d85e156
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypeAdapterTest.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TypeAdapter;
+
+
+/**
+ */
+public class TypeAdapterTest extends BuildFileTest {
+
+    public TypeAdapterTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/typeadapter.xml");
+    }
+
+    public void testTaskAdapter() {
+        expectLogContaining("taskadapter", "MyExec called");
+    }
+
+    public void testRunAdapter() {
+        expectLogContaining("runadapter", "MyRunnable called");
+    }
+
+    public void testRunAdapterError() {
+        expectBuildExceptionContaining(
+            "runadaptererror", "xx", "No public run() method in");
+    }
+
+    public void testDelay() {
+        expectLogContaining("delay", "MyTask called");
+    }
+
+    public void testOnErrorReport() {
+        expectLogContaining("onerror.report",
+                            "MyTaskNotPresent cannot be found");
+    }
+
+    public void testOnErrorIgnore() {
+        expectLog("onerror.ignore","");
+    }
+
+    public static class MyTask extends Task {
+        public void execute() {
+            log("MyTask called");
+        }
+    }
+
+    public static class MyExec {
+        private Project project;
+        public void setProject(Project project) {
+            this.project = project;
+        }
+
+        public void execute() {
+            project.log("MyExec called");
+        }
+    }
+
+    public static class MyRunnable {
+        private Project project;
+        public void setProject(Project project) {
+            this.project = project;
+        }
+
+        public void run() {
+            project.log("MyRunnable called");
+        }
+    }
+
+    public static class RunnableAdapter
+        extends Task implements TypeAdapter
+    {
+        private String execMethodName = "run";
+        private Object proxy;
+
+        public Method getExecuteMethod(Class proxyClass) {
+            try {
+                Method execMethod = proxyClass.getMethod(
+                    execMethodName, null);
+                if (!Void.TYPE.equals(execMethod.getReturnType())) {
+                    String message =
+                        "return type of " + execMethodName + "() should be "
+                        + "void but was \"" + execMethod.getReturnType() +
+                        "\" in "
+                        + proxyClass;
+                    log(message, Project.MSG_WARN);
+                }
+                return execMethod;
+            } catch (NoSuchMethodException e) {
+                String message = "No public "+ execMethodName +
+                    "() method in "
+                    + proxyClass;
+                log(message, Project.MSG_ERR);
+                throw new BuildException(message);
+            }
+        }
+        public void checkProxyClass(Class proxyClass) {
+            getExecuteMethod(proxyClass);
+        }
+
+        public void setProxy(Object o) {
+            getExecuteMethod(o.getClass());
+            this.proxy = o;
+        }
+
+        public Object getProxy() {
+            return proxy;
+        }
+
+        public void execute() {
+            getProject().setProjectReference(proxy);
+            Method executeMethod = getExecuteMethod(proxy.getClass());
+            try {
+                executeMethod.invoke(proxy, null);
+            } catch (java.lang.reflect.InvocationTargetException ie) {
+                log("Error in " + proxy.getClass(), Project.MSG_ERR);
+                Throwable t = ie.getTargetException();
+                if (t instanceof BuildException) {
+                    throw ((BuildException) t);
+                } else {
+                    throw new BuildException(t);
+                }
+            } catch (Exception ex) {
+                log("Error in " + proxy.getClass(), Project.MSG_ERR);
+                throw new BuildException(ex);
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypedefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypedefTest.java
new file mode 100644
index 0000000..5c2c041
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/TypedefTest.java
@@ -0,0 +1,87 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class TypedefTest extends BuildFileTest {
+
+    public TypedefTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/typedef.xml");
+    }
+
+    public void testEmpty() {
+        expectBuildException("empty", "required argument not specified");
+    }
+
+    public void testNoName() {
+        expectBuildException("noName", "required argument not specified");
+    }
+
+    public void testNoClassname() {
+        expectBuildException("noClassname", "required argument not specified");
+    }
+
+    public void testClassNotFound() {
+        expectBuildException("classNotFound",
+                             "classname specified doesn't exist");
+    }
+
+    public void testGlobal() {
+        expectLog("testGlobal", "");
+        Object ref = project.getReferences().get("global");
+        assertNotNull("ref is not null", ref);
+        assertEquals("org.example.types.TypedefTestType",
+                     ref.getClass().getName());
+    }
+
+    public void testLocal() {
+        expectLog("testLocal", "");
+        Object ref = project.getReferences().get("local");
+        assertNotNull("ref is not null", ref);
+        assertEquals("org.example.types.TypedefTestType",
+                     ref.getClass().getName());
+    }
+
+    /**
+     * test to make sure that one can define a not present
+     * optional type twice and then have a valid definition.
+     */
+    public void testDoubleNotPresent() {
+        expectLogContaining("double-notpresent", "hi");
+    }
+    
+    public void testNoResourceOnErrorFailAll(){
+    		this.expectBuildExceptionContaining("noresourcefailall","the requested resource does not exist","Could not load definitions from resource ");
+    }
+    
+    public void testNoResourceOnErrorFail(){
+		expectLogContaining("noresourcefail","Could not load definitions from resource ");
+    }
+    
+    public void testNoResourceOnErrorNotFail(){
+    		expectLogContaining("noresourcenotfail","Could not load definitions from resource ");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UntarTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UntarTest.java
new file mode 100644
index 0000000..5ec3b9f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UntarTest.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class UntarTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public UntarTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/untar.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testRealTest() throws java.io.IOException {
+        testLogoExtraction("realTest");
+    }
+
+    public void testRealGzipTest() throws java.io.IOException {
+        testLogoExtraction("realGzipTest");
+    }
+
+    public void testRealBzip2Test() throws java.io.IOException {
+        testLogoExtraction("realBzip2Test");
+    }
+
+    public void testTestTarTask() throws java.io.IOException {
+        testLogoExtraction("testTarTask");
+    }
+
+    public void testTestGzipTarTask() throws java.io.IOException {
+        testLogoExtraction("testGzipTarTask");
+    }
+
+    public void testTestBzip2TarTask() throws java.io.IOException {
+        testLogoExtraction("testBzip2TarTask");
+    }
+
+    public void testSrcDirTest() {
+        expectBuildException("srcDirTest", "Src cannot be a directory.");
+    }
+
+    public void testEncoding() {
+        expectSpecificBuildException("encoding",
+                                     "<untar> overrides setEncoding.",
+                                     "The untar task doesn't support the "
+                                     + "encoding attribute");
+    }
+
+    public void testResourceCollection() throws java.io.IOException {
+        testLogoExtraction("resourceCollection");
+    }
+
+    private void testLogoExtraction(String target) throws java.io.IOException {
+        executeTarget(target);
+        assertTrue(FILE_UTILS.contentEquals(project.resolveFile("../asf-logo.gif"),
+                                           project.resolveFile("asf-logo.gif")));
+    }
+
+    public void testDocumentationClaimsOnCopy() {
+        executeTarget("testDocumentationClaimsOnCopy");
+        assertFalse(getProject().resolveFile("untartestout/1/foo").exists());
+        assertTrue(getProject().resolveFile("untartestout/2/bar").exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UnzipTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UnzipTest.java
new file mode 100644
index 0000000..14a769b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UnzipTest.java
@@ -0,0 +1,206 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.IOException;
+
+/**
+ */
+public class UnzipTest extends BuildFileTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public UnzipTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/unzip.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "required argument not specified");
+    }
+
+
+    public void testRealTest() throws java.io.IOException {
+        executeTarget("realTest");
+        assertLogoUncorrupted();
+    }
+
+    /**
+     * test that the logo gif file has not been corrupted
+     * @throws IOException
+     */
+    private void assertLogoUncorrupted() throws IOException {
+        assertTrue(FILE_UTILS.contentEquals(project.resolveFile("../asf-logo.gif"),
+                                           project.resolveFile("asf-logo.gif")));
+    }
+
+    public void testTestZipTask() throws java.io.IOException {
+        executeTarget("testZipTask");
+        assertLogoUncorrupted();
+    }
+
+    public void testTestUncompressedZipTask() throws java.io.IOException {
+        executeTarget("testUncompressedZipTask");
+        assertLogoUncorrupted();
+    }
+
+    /*
+     * PR 11100
+     */
+    public void testPatternSetExcludeOnly() {
+        executeTarget("testPatternSetExcludeOnly");
+        assertFileMissing("1/foo is excluded", "unziptestout/1/foo");
+        assertFileExists("2/bar is not excluded", "unziptestout/2/bar");
+    }
+
+    /*
+     * PR 11100
+     */
+    public void testPatternSetIncludeOnly() {
+        executeTarget("testPatternSetIncludeOnly");
+        assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+        assertFileExists("2/bar is included", "unziptestout/2/bar");
+    }
+
+    /*
+     * PR 11100
+     */
+    public void testPatternSetIncludeAndExclude() {
+        executeTarget("testPatternSetIncludeAndExclude");
+        assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+        assertFileMissing("2/bar is excluded", "unziptestout/2/bar");
+    }
+
+    /*
+     * PR 38973
+     */
+    public void testTwoPatternSets() {
+        executeTarget("testTwoPatternSets");
+        assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+        assertFileExists("2/bar is included", "unziptestout/2/bar");
+    }
+
+    /*
+     * PR 38973
+     */
+    public void testTwoPatternSetsWithExcludes() {
+        executeTarget("testTwoPatternSetsWithExcludes");
+        assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+        assertFileMissing("2/bar is excluded", "unziptestout/2/bar");
+    }
+
+    /*
+     * PR 16213
+     */
+    public void testSelfExtractingArchive() {
+        executeTarget("selfExtractingArchive");
+    }
+
+
+    /*
+     * PR 20969
+     */
+    public void testPatternSetSlashOnly() {
+        executeTarget("testPatternSetSlashOnly");
+        assertFileMissing("1/foo is not included", "unziptestout/1/foo");
+        assertFileExists("\"2/bar is included", "unziptestout/2/bar");
+    }
+
+
+    /*
+     * PR 10504
+     */
+    public void testEncoding() {
+        executeTarget("encodingTest");
+        assertFileExists("foo has been properly named", "unziptestout/foo");
+    }
+
+    /*
+     * PR 21996
+     */
+    public void testFlattenMapper() {
+        executeTarget("testFlattenMapper");
+        assertFileMissing("1/foo is not flattened", "unziptestout/1/foo");
+        assertFileExists("foo is flattened", "unziptestout/foo");
+    }
+
+    /**
+     * assert that a file exists, relative to the project
+     * @param message message if there is no mpatch
+     * @param filename filename to resolve against the project
+     */
+    private void assertFileExists(String message, String filename) {
+        assertTrue(message,
+                   getProject().resolveFile(filename).exists());
+    }
+
+    /**
+     * assert that a file doesnt exist, relative to the project
+     *
+     * @param message  message if there is no mpatch
+     * @param filename filename to resolve against the project
+     */
+    private void assertFileMissing(String message, String filename) {
+        assertTrue(message,
+                !getProject().resolveFile(filename).exists());
+    }
+
+    /**
+     * PR 21996
+     */
+    public void testGlobMapper() {
+        executeTarget("testGlobMapper");
+        assertFileMissing("1/foo is not mapped", "unziptestout/1/foo");
+        assertFileExists("1/foo is mapped", "unziptestout/1/foo.txt");
+    }
+
+    public void testTwoMappers() {
+        expectBuildException("testTwoMappers",Expand.ERROR_MULTIPLE_MAPPERS);
+    }
+
+    public void testResourceCollections() {
+        executeTarget("testResourceCollection");
+        assertFileExists("junit.jar has been extracted",
+                         "unziptestout/junit/framework/Assert.class");
+    }
+
+    public void testDocumentationClaimsOnCopy() {
+        executeTarget("testDocumentationClaimsOnCopy");
+        assertFileMissing("1/foo is excluded", "unziptestout/1/foo");
+        assertFileExists("2/bar is not excluded", "unziptestout/2/bar");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UpToDateTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UpToDateTest.java
new file mode 100755
index 0000000..2e8ffa4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/UpToDateTest.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class UpToDateTest extends BuildFileTest {
+
+    public UpToDateTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/uptodate.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void testFilesetUpToDate() {
+        expectPropertySet("testFilesetUpToDate", "foo");
+    }
+
+    public void testFilesetOutOfDate() {
+        expectPropertyUnset("testFilesetOutOfDate", "foo");
+    }
+
+    public void testRCUpToDate() {
+        expectPropertySet("testRCUpToDate", "foo");
+    }
+
+    public void testRCOutOfDate() {
+        expectPropertyUnset("testRCOutOfDate", "foo");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WarTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WarTest.java
new file mode 100644
index 0000000..fea9865
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WarTest.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the war task
+ *
+ */
+public class WarTest extends BuildFileTest {
+    public static final String TEST_BUILD_FILE
+        = "src/etc/testcases/taskdefs/war.xml";
+
+    public WarTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TEST_BUILD_FILE);
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * Test direct dependency removal
+     */
+    public void testLibRefs() {
+        executeTarget("testlibrefs");
+        File f = getProject().resolveFile("working/WEB-INF/lib/war.xml");
+        assertTrue("File has been put into lib", f.exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WhichResourceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WhichResourceTest.java
new file mode 100644
index 0000000..61854e5
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/WhichResourceTest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class WhichResourceTest extends BuildFileTest {
+    public static final String TEST_BUILD_FILE
+        = "src/etc/testcases/taskdefs/whichresource.xml";
+
+    public WhichResourceTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TEST_BUILD_FILE);
+    }
+
+    public void testClassname() {
+        executeTarget("testClassname");
+        assertNotNull(getProject().getProperty("antmain"));
+    }
+
+    public void testResourcename() {
+        executeTarget("testResourcename");
+        assertNotNull(getProject().getProperty("defaults"));
+    }
+
+    public void testResourcenameWithLeadingSlash() {
+        executeTarget("testResourcenameWithLeadingSlash");
+        assertNotNull(getProject().getProperty("defaults"));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlPropertyTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlPropertyTest.java
new file mode 100644
index 0000000..c8a46ea
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlPropertyTest.java
@@ -0,0 +1,359 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ */
+public class XmlPropertyTest extends BuildFileTest {
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public XmlPropertyTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/xmlproperty.xml");
+    }
+
+    public void testFile() {
+        testProperties("test");
+    }
+
+    public void testResource() {
+        testProperties("testResource");
+    }
+
+    private void testProperties(String target) {
+        executeTarget(target);
+        assertEquals("true", getProject().getProperty("root-tag(myattr)"));
+        assertEquals("Text", getProject().getProperty("root-tag.inner-tag"));
+        assertEquals("val",
+                     getProject().getProperty("root-tag.inner-tag(someattr)"));
+        assertEquals("false", getProject().getProperty("root-tag.a2.a3.a4"));
+        assertEquals("CDATA failed",
+            "<test>", getProject().getProperty("root-tag.cdatatag"));
+    }
+
+    public void testDTD() {
+        executeTarget("testdtd");
+        assertEquals("Text", getProject().getProperty("root-tag.inner-tag"));
+    }
+
+    public void testNone () {
+        doTest("testNone", false, false, false, false, false);
+    }
+
+    public void testKeeproot() {
+        doTest("testKeeproot", true, false, false, false, false);
+    }
+
+    public void testCollapse () {
+        doTest("testCollapse", false, true, false, false, false);
+    }
+
+    public void testSemantic () {
+        doTest("testSemantic", false, false, true, false, false);
+    }
+
+    public void testKeeprootCollapse () {
+        doTest("testKeeprootCollapse", true, true, false, false, false);
+    }
+
+    public void testKeeprootSemantic () {
+        doTest("testKeeprootSemantic", true, false, true, false, false);
+    }
+
+    public void testCollapseSemantic () {
+        doTest("testCollapseSemantic", false, true, true, false, false);
+    }
+
+    public void testKeeprootCollapseSemantic () {
+        doTest("testKeeprootCollapseSemantic", true, true, true, false, false);
+    }
+
+    public void testInclude () {
+        doTest("testInclude", false, false, false, true, false);
+    }
+
+    public void testSemanticInclude () {
+        doTest("testSemanticInclude", false, false, true, true, false);
+    }
+
+    public void testSemanticLocal () {
+        doTest("testSemanticInclude", false, false, true, false, true);
+    }
+
+    public void testNeedsCatalog() {
+        executeTarget("testneedscat");
+        assertEquals("true", getProject().getProperty("skinconfig.foo"));
+    }
+
+    /**
+     * Actually run a test, finding all input files (and corresponding
+     * goldfile)
+     */
+    private void doTest(String msg, boolean keepRoot, boolean collapse,
+                        boolean semantic, boolean include, boolean localRoot) {
+        Enumeration iter =
+            getFiles(new File(System.getProperty("root"), "src/etc/testcases/taskdefs/xmlproperty/inputs"));
+        while (iter.hasMoreElements()) {
+            File inputFile = (File) iter.nextElement();
+            // What's the working directory?  If local, then its the
+            // folder of the input file.  Otherwise, its the "current" dir..
+            File workingDir;
+            if ( localRoot ) {
+                workingDir = inputFile.getParentFile();
+            } else {
+                workingDir = FILE_UTILS.resolveFile(new File("."), ".");
+            }
+
+            try {
+
+                File propertyFile = getGoldfile(inputFile, keepRoot, collapse,
+                                                semantic, include, localRoot);
+                if (!propertyFile.exists()) {
+//                    System.out.println("Skipping as "
+//                                       + propertyFile.getAbsolutePath()
+//                                       + ") doesn't exist.");
+                    continue;
+                }
+
+                //                System.out.println(msg + " (" + propertyFile.getName() + ") in (" + workingDir + ")");
+
+                Project p = new Project();
+
+                XmlProperty xmlproperty = new XmlProperty();
+                xmlproperty.setProject(p);
+                xmlproperty.setFile(inputFile);
+
+                xmlproperty.setKeeproot(keepRoot);
+                xmlproperty.setCollapseAttributes(collapse);
+                xmlproperty.setSemanticAttributes(semantic);
+                xmlproperty.setIncludeSemanticAttribute(include);
+                xmlproperty.setRootDirectory(workingDir);
+
+                // Set a property on the project to make sure that loading
+                // a property with the same name from an xml file will
+                // *not* change it.
+                p.setNewProperty("override.property.test", "foo");
+
+                xmlproperty.execute();
+
+                Properties props = new Properties();
+                props.load(new FileInputStream(propertyFile));
+
+                //printProperties(p.getProperties());
+
+                ensureProperties(msg, inputFile, workingDir, p, props);
+                ensureReferences(msg, inputFile, p.getReferences());
+
+            } catch (IOException ex) {
+                fail(ex.toString());
+            }
+        }
+    }
+
+    /**
+     * Make sure every property loaded from the goldfile was also
+     * read from the XmlProperty.  We could try and test the other way,
+     * but some other properties may get set in the XmlProperty due
+     * to generic Project/Task configuration.
+     */
+    private static void ensureProperties (String msg, File inputFile,
+                                          File workingDir, Project p,
+                                          Properties properties) {
+        Hashtable xmlproperties = p.getProperties();
+        // Every key identified by the Properties must have been loaded.
+        Enumeration propertyKeyEnum = properties.propertyNames();
+        while(propertyKeyEnum.hasMoreElements()){
+            String currentKey = propertyKeyEnum.nextElement().toString();
+            String assertMsg = msg + "-" + inputFile.getName()
+                + " Key=" + currentKey;
+
+            String propertyValue = properties.getProperty(currentKey);
+
+            String xmlValue = (String)xmlproperties.get(currentKey);
+
+            if ( propertyValue.indexOf("ID.") == 0 ) {
+                // The property is an id's thing -- either a property
+                // or a path.  We need to make sure
+                // that the object was created with the given id.
+                // We don't have an adequate way of testing the actual
+                // *value* of the Path object, though...
+                String id = currentKey;
+                Object obj = p.getReferences().get(id);
+
+                if ( obj == null ) {
+                    fail(assertMsg + " Object ID does not exist.");
+                }
+
+                // What is the property supposed to be?
+                propertyValue =
+                    propertyValue.substring(3, propertyValue.length());
+                if (propertyValue.equals("path")) {
+                    if (!(obj instanceof Path)) {
+                        fail(assertMsg + " Path ID is a "
+                             + obj.getClass().getName());
+                    }
+                } else {
+                    assertEquals(assertMsg, propertyValue, obj.toString());
+                }
+
+            } else {
+
+                if (propertyValue.indexOf("FILE.") == 0) {
+                    // The property is the name of a file.  We are testing
+                    // a location attribute, so we need to resolve the given
+                    // file name in the provided folder.
+                    String fileName =
+                        propertyValue.substring(5, propertyValue.length());
+                    File f = new File(workingDir, fileName);
+                    propertyValue = f.getAbsolutePath();
+                }
+
+                assertEquals(assertMsg, propertyValue, xmlValue);
+            }
+
+        }
+    }
+
+    /**
+     * Debugging method to print the properties in the given hashtable
+     */
+    private static void printProperties(Hashtable xmlproperties) {
+        Enumeration keyEnum = xmlproperties.keys();
+        while (keyEnum.hasMoreElements()) {
+            String currentKey = keyEnum.nextElement().toString();
+            System.out.println(currentKey + " = "
+                               + xmlproperties.get(currentKey));
+        }
+    }
+
+    /**
+     * Ensure all references loaded by the project are valid.
+     */
+    private static void ensureReferences (String msg, File inputFile,
+                                          Hashtable references) {
+        Enumeration referenceKeyEnum = references.keys();
+        while(referenceKeyEnum.hasMoreElements()){
+            String currentKey = referenceKeyEnum.nextElement().toString();
+            Object currentValue = references.get(currentKey);
+
+            if (currentValue instanceof Path) {
+            } else if (currentValue instanceof String) {
+            } else {
+                if( ! currentKey.startsWith("ant.") ) {
+                    fail(msg + "-" + inputFile.getName() + " Key="
+                         + currentKey + " is not a recognized type.");
+                }
+            }
+        }
+    }
+
+    /**
+     * Munge the name of the input file to find an appropriate goldfile,
+     * based on hardwired naming conventions.
+     */
+    private static File getGoldfile (File input, boolean keepRoot,
+                                     boolean collapse, boolean semantic,
+                                     boolean include, boolean localRoot) {
+        // Substitute .xml with .properties
+        String baseName = input.getName().toLowerCase();
+        if (baseName.endsWith(".xml")) {
+            baseName = baseName.substring(0, baseName.length() - 4)
+                + ".properties";
+        }
+
+        File dir = input.getParentFile().getParentFile();
+
+        String goldFileFolder = "goldfiles/";
+
+        if (keepRoot) {
+            goldFileFolder += "keeproot-";
+        } else {
+            goldFileFolder += "nokeeproot-";
+        }
+
+        if (semantic) {
+            goldFileFolder += "semantic-";
+            if (include) {
+                goldFileFolder += "include-";
+            }
+        } else {
+            if (collapse) {
+                goldFileFolder += "collapse-";
+            } else {
+                goldFileFolder += "nocollapse-";
+            }
+        }
+
+        return new File(dir, goldFileFolder + baseName);
+    }
+
+    /**
+     * Retrieve a list of xml files in the specified folder
+     * and below.
+     */
+    private static Enumeration getFiles (final File startingDir) {
+        Vector result = new Vector();
+        getFiles(startingDir, result);
+        return result.elements();
+    }
+
+    /**
+     * Collect a list of xml files in the specified folder
+     * and below.
+     */
+    private static void getFiles (final File startingDir, Vector collect) {
+        FileFilter filter = new FileFilter() {
+            public boolean accept (File file) {
+                if (file.isDirectory()) {
+                    return true;
+                } else {
+                    return (file.getPath().indexOf("taskdefs") > 0 &&
+                            file.getPath().toLowerCase().endsWith(".xml") );
+                }
+            }
+        };
+
+        File[] files = startingDir.listFiles(filter);
+        for (int i=0;i<files.length;i++) {
+            File f = files[i];
+            if (!f.isDirectory()) {
+                collect.addElement(f);
+            } else {
+                getFiles(f, collect);
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlnsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlnsTest.java
new file mode 100644
index 0000000..7ba1050
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/XmlnsTest.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Task;
+
+/**
+ */
+public class XmlnsTest extends BuildFileTest {
+    public XmlnsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/xmlns.xml");
+    }
+
+    public void testXmlns() {
+        expectLog("xmlns", "MyTask called");
+    }
+
+    public void testXmlnsFile() {
+        expectLog("xmlns.file", "MyTask called");
+    }
+
+    public void testCore() {
+        expectLog("core", "MyTask called");
+    }
+
+    public void testExcluded() {
+        expectBuildExceptionContaining(
+            "excluded", "excluded uri",
+            "Attempt to use a reserved URI ant:notallowed");
+    }
+
+    public void testOther() {
+        expectLog("other", "a message");
+    }
+
+    public void testNsAttributes() {
+        expectLog("ns.attributes", "hello world");
+    }
+
+    public static class MyTask extends Task {
+        public void execute() {
+            log("MyTask called");
+        }
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ZipTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ZipTest.java
new file mode 100644
index 0000000..e44ce90
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/ZipTest.java
@@ -0,0 +1,191 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.zip.UnixStat;
+
+/**
+ */
+public class ZipTest extends BuildFileTest {
+    //instance variable to allow cleanup
+    ZipFile zfPrefixAddsDir = null;
+    public ZipTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/zip.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument not specified");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "required argument not specified");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "zip cannot include itself");
+    }
+
+    //    public void test4() {
+    //        expectBuildException("test4", "zip cannot include itself");
+    //    }
+
+    public void tearDown() {
+        try {
+            if ( zfPrefixAddsDir != null) {
+                zfPrefixAddsDir.close();
+            }
+
+        } catch (IOException e) {
+            //ignored
+        }
+        executeTarget("cleanup");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+    }
+
+
+    public void test6() {
+        executeTarget("test6");
+    }
+
+
+    public void test7() {
+        executeTarget("test7");
+    }
+
+    public void test8() {
+        executeTarget("test8");
+    }
+
+    public void testZipgroupfileset() throws IOException {
+        executeTarget("testZipgroupfileset");
+
+        ZipFile zipFile = new ZipFile(new File(getProjectDir(), "zipgroupfileset.zip"));
+
+        assertTrue(zipFile.getEntry("ant.xml") != null);
+        assertTrue(zipFile.getEntry("optional/jspc.xml") != null);
+        assertTrue(zipFile.getEntry("zip/zipgroupfileset3.zip") != null);
+
+        assertTrue(zipFile.getEntry("test6.mf") == null);
+        assertTrue(zipFile.getEntry("test7.mf") == null);
+
+        zipFile.close();
+    }
+
+    public void testUpdateNotNecessary() {
+        executeTarget("testUpdateNotNecessary");
+        assertEquals(-1, getLog().indexOf("Updating"));
+    }
+
+    public void testUpdateIsNecessary() {
+        expectLogContaining("testUpdateIsNecessary", "Updating");
+    }
+
+    // Bugzilla Report 18403
+    public void testPrefixAddsDir() throws IOException {
+        executeTarget("testPrefixAddsDir");
+        File archive = getProject().resolveFile("test3.zip");
+        zfPrefixAddsDir = new ZipFile(archive);
+        ZipEntry ze = zfPrefixAddsDir.getEntry("test/");
+        assertNotNull("test/ has been added", ze);
+
+    }
+
+    // Bugzilla Report 19449
+    public void testFilesOnlyDoesntCauseRecreate()
+        throws InterruptedException {
+        executeTarget("testFilesOnlyDoesntCauseRecreateSetup");
+        long l = getProject().resolveFile("test3.zip").lastModified();
+        Thread.sleep(3000);
+        executeTarget("testFilesOnlyDoesntCauseRecreate");
+        assertEquals(l, getProject().resolveFile("test3.zip").lastModified());
+    }
+
+    // Bugzilla Report 22865
+    public void testEmptySkip() {
+        executeTarget("testEmptySkip");
+    }
+    // Bugzilla Report 30365
+    public void testZipEmptyDir() {
+        executeTarget("zipEmptyDir");
+    }
+    // Bugzilla Report 40258
+    public void testZipEmptyDirFilesOnly() {
+        executeTarget("zipEmptyDirFilesOnly");
+    }
+    public void testZipEmptyCreate() {
+        expectLogContaining("zipEmptyCreate", "Note: creating empty");
+    }
+    // Bugzilla Report 25513
+    public void testCompressionLevel() {
+        executeTarget("testCompressionLevel");
+    }
+
+    // Bugzilla Report 33412
+    public void testDefaultExcludesAndUpdate() 
+        throws ZipException, IOException {
+        executeTarget("testDefaultExcludesAndUpdate");
+        ZipFile f = null;
+        try {
+            f = new ZipFile(getProject().resolveFile("test3.zip"));
+            assertNotNull("ziptest~ should be included",
+                          f.getEntry("ziptest~"));
+        } finally {
+            if (f != null) {
+                f.close();
+            }
+        }
+    }
+
+    public void testFileResource() {
+        executeTarget("testFileResource");
+    }
+
+    public void testNonFileResource() {
+        executeTarget("testNonFileResource");
+    }
+
+    public void testTarFileSet() throws IOException {
+        executeTarget("testTarFileSet");
+        org.apache.tools.zip.ZipFile zf = null;
+        try {
+            zf = new org.apache.tools.zip.ZipFile(getProject()
+                                                  .resolveFile("test3.zip"));
+            org.apache.tools.zip.ZipEntry ze = zf.getEntry("asf-logo.gif");
+            assertEquals(UnixStat.FILE_FLAG | 0446, ze.getUnixMode());
+        } finally {
+            if (zf != null) {
+                zf.close();
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/AntVersionTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/AntVersionTest.java
new file mode 100644
index 0000000..a2c5e44
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/AntVersionTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcases for the &lt;antversion&gt; condition.
+ *
+ */
+public class AntVersionTest extends BuildFileTest {
+    
+    public AntVersionTest(String name) {
+        super(name);
+    }
+    
+    public void setUp() throws Exception {
+        configureProject("src/etc/testcases/taskdefs/conditions/antversion.xml");
+    }
+    
+    public void testAtLeast() {
+        executeTarget("testatleast");
+    }
+    
+    public void testExactly() {
+        executeTarget("testexactly");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ContainsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ContainsTest.java
new file mode 100644
index 0000000..0cbe1fa
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ContainsTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import junit.framework.TestCase;
+
+/**
+ * Testcase for the &lt;contains&gt; condition.
+ *
+ */
+public class ContainsTest extends TestCase {
+
+    public ContainsTest(String name) {
+        super(name);
+    }
+
+    public void testCaseSensitive() {
+        Contains con = new Contains();
+        con.setString("abc");
+        con.setSubstring("A");
+        assertTrue(!con.eval());
+
+        con.setCasesensitive(false);
+        assertTrue(con.eval());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/EqualsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/EqualsTest.java
new file mode 100644
index 0000000..9980a80
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/EqualsTest.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import junit.framework.TestCase;
+
+/**
+ * Testcase for the &lt;equals&gt; condition.
+ *
+ */
+public class EqualsTest extends TestCase {
+
+    public EqualsTest(String name) {
+        super(name);
+    }
+
+    public void testTrim() {
+        Equals eq = new Equals();
+        eq.setArg1("a");
+        eq.setArg2(" a");
+        assertTrue(!eq.eval());
+
+        eq.setTrim(true);
+        assertTrue(eq.eval());
+
+        eq.setArg2("a\t");
+        assertTrue(eq.eval());
+    }
+
+    public void testCaseSensitive() {
+        Equals eq = new Equals();
+        eq.setArg1("a");
+        eq.setArg2("A");
+        assertTrue(!eq.eval());
+
+        eq.setCasesensitive(false);
+        assertTrue(eq.eval());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFailureTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFailureTest.java
new file mode 100755
index 0000000..1d0e222
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFailureTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcases for the &lt;isfailure&gt; condition.
+ *
+ */
+public class IsFailureTest extends BuildFileTest {
+
+    public IsFailureTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/isfailure.xml");
+    }
+
+    public void testIsFailure() {
+       executeTarget("testisfailure");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFileSelectedTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFileSelectedTest.java
new file mode 100644
index 0000000..66aba80
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsFileSelectedTest.java
@@ -0,0 +1,53 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the &lt;isfileselected&gt; condition.
+ *
+ */
+public class IsFileSelectedTest extends BuildFileTest {
+
+    public IsFileSelectedTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/isfileselected.xml");
+    }
+
+    public void testSimple() {
+        executeTarget("simple");
+    }
+    public void testName() {
+        executeTarget("name");
+    }
+    public void testBaseDir() {
+        executeTarget("basedir");
+    }
+    public void testType() {
+        executeTarget("type");
+    }
+    public void testNotSelector() {
+        expectBuildExceptionContaining(
+            "not.selector", "checking for use as a selector (not allowed)",
+            "fileset doesn't support the nested \"isfile");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReachableTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReachableTest.java
new file mode 100644
index 0000000..3078c0e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReachableTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * test for reachable things
+ */
+public class IsReachableTest extends BuildFileTest {
+
+    public IsReachableTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(
+                "src/etc/testcases/taskdefs/conditions/isreachable.xml");
+    }
+
+
+    public void testLocalhost() throws Exception {
+        executeTarget("testLocalhost");
+    }
+
+    public void testLocalhostURL() throws Exception {
+        executeTarget("testLocalhostURL");
+    }
+
+    public void testIpv4localhost() throws Exception {
+        executeTarget("testIpv4localhost");
+    }
+
+    public void testFTPURL() throws Exception {
+        executeTarget("testFTPURL");
+    }
+
+    public void testBoth() throws Exception {
+        expectBuildExceptionContaining("testBoth",
+                "error on two targets",
+                IsReachable.ERROR_BOTH_TARGETS);
+    }
+
+    public void testNoTargets() throws Exception {
+        expectBuildExceptionContaining("testNoTargets",
+                "no params",
+                IsReachable.ERROR_NO_HOSTNAME);
+    }
+
+    public void testBadTimeout() throws Exception {
+        expectBuildExceptionContaining("testBadTimeout",
+                "error on -ve timeout",
+                IsReachable.ERROR_BAD_TIMEOUT);
+    }
+
+    public void NotestFile() throws Exception {
+        expectBuildExceptionContaining("testFile",
+                "error on file URL",
+                IsReachable.ERROR_NO_HOST_IN_URL);
+    }
+
+    public void testBadURL() throws Exception {
+        expectBuildExceptionContaining("testBadURL",
+                "error in URL",
+                IsReachable.ERROR_BAD_URL);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReferenceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReferenceTest.java
new file mode 100644
index 0000000..ba775c4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsReferenceTest.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcases for the &lt;isreference&gt; condition.
+ *
+ */
+public class IsReferenceTest extends BuildFileTest {
+
+    public IsReferenceTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/isreference.xml");
+    }
+
+    public void testBasic() {
+       expectPropertySet("basic", "global-path");
+       assertPropertySet("target-path");
+       assertPropertyUnset("undefined");
+    }
+
+    public void testNotEnoughArgs() {
+        expectSpecificBuildException("isreference-incomplete",
+                                     "refid attribute has been omitted",
+                                     "No reference specified for isreference "
+                                     + "condition");
+    }
+
+    public void testType() {
+       expectPropertySet("type", "global-path");
+       assertPropertyUnset("global-path-as-fileset");
+       assertPropertyUnset("global-path-as-foo");
+       assertPropertySet("global-echo");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsSignedTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsSignedTest.java
new file mode 100644
index 0000000..f2f9486
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/IsSignedTest.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the &lt;issigned&gt; condition.
+ *
+ */
+public class IsSignedTest extends BuildFileTest {
+
+    public IsSignedTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/issigned.xml");
+    }
+
+    public void testPass() {
+        executeTarget("pass");
+    }
+    public void testPassword() {
+        executeTarget("password");
+    }
+    public void testAPassword() {
+        executeTarget("apassword");
+    }
+    public void testAllSigned() {
+        executeTarget("allsigned");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ParserSupportsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ParserSupportsTest.java
new file mode 100644
index 0000000..fc4f131
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/ParserSupportsTest.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ 
+ */
+public class ParserSupportsTest extends BuildFileTest {
+
+    public ParserSupportsTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/parsersupports.xml");
+    }
+
+    public void testEmpty() throws Exception {
+        expectBuildExceptionContaining("testEmpty",
+                ParserSupports.ERROR_NO_ATTRIBUTES,
+                ParserSupports.ERROR_NO_ATTRIBUTES);
+    }
+
+    public void testBoth() throws Exception {
+        expectBuildExceptionContaining("testBoth",
+                ParserSupports.ERROR_BOTH_ATTRIBUTES,
+                ParserSupports.ERROR_BOTH_ATTRIBUTES);
+    }
+
+    public void testNamespaces() throws Exception {
+        executeTarget("testNamespaces");
+    }
+
+    public void testPropertyNoValue() throws Exception {
+        expectBuildExceptionContaining("testPropertyNoValue",
+                ParserSupports.ERROR_NO_VALUE,
+                ParserSupports.ERROR_NO_VALUE);
+    }
+
+    public void testUnknownProperty() throws Exception {
+        executeTarget("testUnknownProperty");
+    }
+    public void NotestPropertyInvalid() throws Exception {
+        executeTarget("testPropertyInvalid");
+    }
+    public void NotestXercesProperty() throws Exception {
+        executeTarget("testXercesProperty");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/TypeFoundTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/TypeFoundTest.java
new file mode 100644
index 0000000..a0d4971
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/TypeFoundTest.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * test the typeexists condition
+ */
+public class TypeFoundTest extends BuildFileTest {
+
+    public TypeFoundTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/typefound.xml");
+    }
+
+    public void testTask() {
+        expectPropertySet("testTask", "testTask");
+    }
+
+    public void testUndefined() {
+        expectBuildExceptionContaining("testUndefined","left out the name attribute", "No type specified");
+    }
+
+    public void testTaskThatIsntDefined() {
+        expectPropertyUnset("testTaskThatIsntDefined", "testTaskThatIsntDefined");
+    }
+
+    public void testTaskThatDoesntReallyExist() {
+        expectPropertyUnset("testTaskThatDoesntReallyExist", "testTaskThatDoesntReallyExist");
+    }
+
+    public void testType() {
+        expectPropertySet("testType", "testType");
+    }
+
+    public void testPreset() {
+        expectPropertySet("testPreset", "testPreset");
+    }
+
+    public void testMacro() {
+        expectPropertySet("testMacro", "testMacro");
+    }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/XorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/XorTest.java
new file mode 100644
index 0000000..0003c85
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/condition/XorTest.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.condition;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test that Xor follows the conventional boolean logic semantics
+ * (a ^ b) === (a||b)&!(a&&b)
+ */
+public class XorTest extends BuildFileTest {
+
+    public XorTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/conditions/xor.xml");
+    }
+
+    public void testEmpty() {
+        executeTarget("testEmpty");
+    }
+
+    public void test0() {
+        executeTarget("test0");
+    }
+
+    public void test1() {
+        executeTarget("test1");
+    }
+
+    public void test00() {
+        executeTarget("test00");
+    }
+
+    public void test10() {
+        executeTarget("test10");
+    }
+
+    public void test01() {
+        executeTarget("test01");
+    }
+
+    public void test11() {
+        executeTarget("test11");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java
new file mode 100644
index 0000000..b9add9b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogParserTest.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import junit.framework.TestCase;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Date;
+
+/**
+ * Minimal test of the parser implementation
+ */
+public class ChangeLogParserTest extends TestCase {
+
+    protected ChangeLogParser parser = new ChangeLogParser();
+
+    public void testOldCvsFormat() throws Exception {
+        parser.stdout("Working file: build.xml");
+        parser.stdout("revision 1.475");
+        parser.stdout("date: 2004/06/05 16:10:32;  author: somebody;  state: Exp;  lines: +2 -2");
+        parser.stdout("I have done something. I swear.");
+        parser.stdout("=============================================================================");
+        CVSEntry[] entries = parser.getEntrySetAsArray();
+        assertEquals("somebody", entries[0].getAuthor());
+        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.set(2004, Calendar.JUNE, 5, 16, 10, 32);
+        Date date = cal.getTime();
+        assertEquals(date, entries[0].getDate());
+    }
+
+    public void testCvs112Format() throws Exception {
+        parser.stdout("Working file: build.xml");
+        parser.stdout("revision 1.475");
+        parser.stdout("date: 2004-06-05 16:10:32 +0000; author: somebody; state: Exp;  lines: +2 -2");
+        parser.stdout("I have done something. I swear.");
+        parser.stdout("=============================================================================");
+        CVSEntry[] entries = parser.getEntrySetAsArray();
+        assertEquals("somebody", entries[0].getAuthor());
+        Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+        cal.set(Calendar.MILLISECOND, 0);
+        cal.set(2004, Calendar.JUNE, 5, 16, 10, 32);
+        Date date = cal.getTime();
+        assertEquals(date, entries[0].getDate());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriterTest.java
new file mode 100644
index 0000000..9b2f5a7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/cvslib/ChangeLogWriterTest.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.cvslib;
+
+import junit.framework.TestCase;
+
+import java.util.Date;
+import java.io.PrintWriter;
+import java.io.OutputStreamWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.XMLReader;
+import org.xml.sax.InputSource;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+/**
+ *  Test for the cvslib ChangeLogWriter
+ */
+public class ChangeLogWriterTest extends TestCase {
+
+    private ChangeLogWriter writer = new ChangeLogWriter();
+
+    public void testNonUTF8Characters() throws Exception {
+        CVSEntry entry = new CVSEntry(new Date(), "Se\u00f1orita", "2003 < 2004 && 3 > 5");
+        entry.addFile("Medicare & review.doc", "1.1");
+        entry.addFile("El\u00e8ments de style", "1.2");
+        CVSEntry[] entries = { entry };
+
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        PrintWriter pwriter = new PrintWriter(new OutputStreamWriter(output, "UTF-8"));
+        writer.printChangeLog(pwriter, entries);
+
+        // make sure that the parsing does not break
+        XMLReader xmlReader = JAXPUtils.getXMLReader();
+        InputStream input = new ByteArrayInputStream(output.toByteArray());
+        xmlReader.setContentHandler(new NullContentHandler());
+        xmlReader.parse(new InputSource(input));
+    }
+
+    public static class NullContentHandler implements ContentHandler {
+        public void endDocument() throws SAXException {
+        }
+
+        public void startDocument() throws SAXException {
+        }
+
+        public void characters(char ch[], int start, int length) throws SAXException {
+            String debug = new String(ch, start, length);
+        }
+
+        public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
+        }
+
+        public void endPrefixMapping(String prefix) throws SAXException {
+        }
+
+        public void skippedEntity(String name) throws SAXException {
+        }
+
+        public void setDocumentLocator(Locator locator) {
+        }
+
+        public void processingInstruction(String target, String data) throws SAXException {
+        }
+
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+        }
+
+        public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
+        }
+
+        public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir1/B.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir1/B.java
new file mode 100644
index 0000000..9057fa0
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir1/B.java
@@ -0,0 +1,30 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.dir1;
+
+public class B extends org.apache.tools.ant.taskdefs.dir2.A {
+    static {
+        System.out.println("B CLASS INITIALIZATION");
+        setA(new B());
+    }
+
+    public String toString() {
+        return "I am a B.";
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir2/A.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir2/A.java
new file mode 100644
index 0000000..5186ac4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/dir2/A.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.dir2;
+
+public class A {
+    public static void main(String [] args) {
+        System.out.println("MAIN");
+        System.out.println(a);
+    }
+
+    static A a=new A();
+
+    static {
+        System.out.println("A CLASS INITIALIZATION");
+    }
+
+    protected static void setA(A oa) {
+        a=oa;
+    }
+
+    public String toString() {
+        return "I am a A.";
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java
new file mode 100644
index 0000000..72c87a3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailAddressTest.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.email;
+
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.6
+ */
+public class EmailAddressTest extends TestCase {
+
+    public EmailAddressTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+    }
+
+    public void test1() {
+        expectNameAddress( new EmailAddress("address (name)") );
+    }
+
+    public void test2() {
+        expectNameAddress( new EmailAddress("(name) address") );
+    }
+
+    public void test3() {
+        expectNameAddress( new EmailAddress("name <address>") );
+    }
+
+    public void test4() {
+        expectNameAddress( new EmailAddress("<address> name") );
+    }
+
+    public void test5() {
+        expectNameAddress( new EmailAddress("<address> (name)") );
+    }
+
+    public void test6() {
+        expectNameAddress( new EmailAddress("(name) <address>") );
+    }
+
+    public void test7() {
+        expectNameAddress2( new EmailAddress("address (<name>)") );
+    }
+
+    public void test8() {
+        expectNameAddress2( new EmailAddress("(<name>) address") );
+    }
+
+    public void test9() {
+        expectNameAddress3( new EmailAddress("address") );
+    }
+
+    public void testA() {
+        expectNameAddress3( new EmailAddress("<address>") );
+    }
+
+    public void testB() {
+        expectNameAddress3( new EmailAddress(" <address> ") );
+    }
+
+    public void testC() {
+        expectNameAddress3( new EmailAddress("< address >") );
+    }
+
+    public void testD() {
+        expectNameAddress3( new EmailAddress(" < address > ") );
+    }
+
+    private void expectNameAddress(EmailAddress e) {
+        assertEquals( "name", e.getName() );
+        assertEquals( "address", e.getAddress() );
+    }
+
+    // where the name contains <>
+    private void expectNameAddress2(EmailAddress e) {
+        assertEquals( "<name>", e.getName() );
+        assertEquals( "address", e.getAddress() );
+    }
+
+    // where only an address is supplied
+    private void expectNameAddress3(EmailAddress e) {
+        assertTrue( "Expected null, found <" + e.getName() + ">",
+            e.getName() == null );
+        assertEquals( "address", e.getAddress() );
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java
new file mode 100644
index 0000000..66b89cd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/email/EmailTaskTest.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.email;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * TODO : develop these testcases - the email task needs to have attributes allowing
+ * to simulate sending mail and to catch the output in text files or streams
+ */
+public class EmailTaskTest extends BuildFileTest {
+
+    public EmailTaskTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/email/mail.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "SMTP auth only possible with MIME mail");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "SSL only possible with MIME mail");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ANTLRTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ANTLRTest.java
new file mode 100644
index 0000000..d886d82
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ANTLRTest.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.*;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * If you want to run tests, it is highly recommended
+ * to download ANTLR (www.antlr.org), build the 'antlrall.jar' jar
+ * with  <code>make antlr-all.jar</code> and drop the jar (about 300KB) into
+ * Ant lib.
+ * - Running w/ the default antlr.jar (70KB) does not work (missing class)
+ *
+ * Unless of course you specify the ANTLR classpath in your
+ * system classpath. (see ANTLR install.html)
+ *
+ */
+public class ANTLRTest extends BuildFileTest {
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/antlr/";
+
+    public ANTLRTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "antlr.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "required argument, target, missing");
+    }
+
+    public void test2() {
+        expectBuildException("test2", "Invalid output directory");
+    }
+
+    public void test3() {
+        executeTarget("test3");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+    }
+
+    public void test5() {
+        // should print "panic: Cannot find importVocab file 'JavaTokenTypes.txt'"
+        // since it needs to run java.g first before java.tree.g
+        expectBuildException("test5", "ANTLR returned: 1");
+    }
+
+    public void test6() {
+        executeTarget("test6");
+    }
+
+    public void test7() {
+        expectBuildException("test7", "Unable to determine generated class");
+    }
+
+    /**
+     * This is a negative test for the super grammar (glib) option.
+     */
+    public void test8() {
+        expectBuildException("test8", "Invalid super grammar file");
+    }
+
+    /**
+     * This is a positive test for the super grammar (glib) option.  ANTLR
+     * will throw an error if everything is not correct.
+     */
+    public void test9() {
+        executeTarget("test9");
+    }
+
+    /**
+     * This test creates an html-ized version of the calculator grammar.
+     * The sanity check is simply whether or not an html file was generated.
+     */
+    public void test10() {
+        executeTarget("test10");
+        File outputDirectory = new File(System.getProperty("root"), TASKDEFS_DIR + "antlr.tmp");
+        String[] calcFiles = outputDirectory.list(new HTMLFilter());
+        assertTrue(calcFiles.length > 0);
+    }
+
+    /**
+     * This is just a quick sanity check to run the diagnostic option and
+     * make sure that it doesn't throw any funny exceptions.
+     */
+    public void test11() {
+        executeTarget("test11");
+    }
+
+    /**
+     * This is just a quick sanity check to run the trace option and
+     * make sure that it doesn't throw any funny exceptions.
+     */
+    public void test12() {
+        executeTarget("test12");
+    }
+
+    /**
+     * This is just a quick sanity check to run all the rest of the
+     * trace options (traceLexer, traceParser, and traceTreeWalker) to
+     * make sure that they don't throw any funny exceptions.
+     */
+    public void test13() {
+        executeTarget("test13");
+    }
+
+    public void testNoRecompile() {
+        executeTarget("test9");
+        assertEquals(-1, getFullLog().indexOf("Skipped grammar file."));
+        executeTarget("noRecompile");
+        assertTrue(-1 != getFullLog().indexOf("Skipped grammar file."));
+    }
+
+    public void testNormalRecompile() {
+        executeTarget("test9");
+        assertEquals(-1, getFullLog().indexOf("Skipped grammar file."));
+        executeTarget("normalRecompile");
+        assertEquals(-1, getFullLog().indexOf("Skipped grammar file."));
+    }
+
+    // Bugzilla Report 12961
+    public void testSupergrammarChangeRecompile() {
+        executeTarget("test9");
+        assertEquals(-1, getFullLog().indexOf("Skipped grammar file."));
+        executeTarget("supergrammarChangeRecompile");
+        assertEquals(-1, getFullLog().indexOf("Skipped grammar file."));
+    }
+}
+
+class CalcFileFilter implements FilenameFilter {
+    public boolean accept(File dir, String name) {
+        return name.startsWith("Calc");
+    }
+}
+
+class HTMLFilter implements FilenameFilter {
+    public boolean accept(File dir, String name) {
+        return name.endsWith("html");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/AbstractXSLTLiaisonTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/AbstractXSLTLiaisonTest.java
new file mode 100644
index 0000000..72139e1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/AbstractXSLTLiaisonTest.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.net.URL;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import junit.framework.TestCase;
+import org.apache.tools.ant.taskdefs.XSLTLiaison;
+import org.apache.tools.ant.util.FileUtils;
+import org.w3c.dom.Document;
+
+/**
+ * Abtract testcase for XSLTLiaison.
+ * Override createLiaison for each XSLTLiaison.
+ *
+ * <a href="sbailliez@apache.org">Stephane Bailliez</a>
+ */
+public abstract class AbstractXSLTLiaisonTest extends TestCase {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    protected XSLTLiaison liaison;
+
+    protected  AbstractXSLTLiaisonTest(String name){
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        liaison = createLiaison();
+    }
+
+    // to override
+    protected abstract XSLTLiaison createLiaison() throws Exception ;
+
+    /** load the file from the caller classloader that loaded this class */
+    protected File getFile(String name) throws FileNotFoundException {
+        URL url = getClass().getResource(name);
+        if (url == null){
+          throw new FileNotFoundException("Unable to load '" + name + "' from classpath");
+        }
+        return new File(FILE_UTILS.fromURI(url.toExternalForm()));
+    }
+
+    /** keep it simple stupid */
+    public void testTransform() throws Exception {
+        File xsl = getFile("/taskdefs/optional/xsltliaison-in.xsl");
+        liaison.setStylesheet(xsl);
+        liaison.addParam("param", "value");
+        File in = getFile("/taskdefs/optional/xsltliaison-in.xml");
+        File out = new File("xsltliaison.tmp");
+        out.deleteOnExit(); // just to be sure
+        try {
+            liaison.transform(in, out);
+        } finally {
+            out.delete();
+        }
+    }
+
+    public void testEncoding() throws Exception {
+        File xsl = getFile("/taskdefs/optional/xsltliaison-encoding-in.xsl");
+        liaison.setStylesheet(xsl);
+        File in = getFile("/taskdefs/optional/xsltliaison-encoding-in.xml");
+        File out = new File("xsltliaison-encoding.tmp");
+        out.deleteOnExit(); // just to be sure
+        try {
+            liaison.transform(in, out);
+            Document doc = parseXML(out);
+            assertEquals("root",doc.getDocumentElement().getNodeName());
+            assertEquals("message",doc.getDocumentElement().getFirstChild().getNodeName());
+            assertEquals("\u00E9\u00E0\u00E8\u00EF\u00F9",doc.getDocumentElement().getFirstChild().getFirstChild().getNodeValue());
+        } finally {
+            out.delete();
+        }
+    }
+
+    public Document parseXML(File file) throws Exception {
+        DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder dbuilder = dbfactory.newDocumentBuilder();
+        return dbuilder.parse(file);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/BeanShellScriptTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/BeanShellScriptTest.java
new file mode 100644
index 0000000..77358cd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/BeanShellScriptTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the examples of the &lt;script&gt; task docs.
+ *
+ * @since Ant 1.5.2
+ */
+public class BeanShellScriptTest extends BuildFileTest {
+
+    public BeanShellScriptTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/script.xml");
+    }
+
+    public void testCanLoad() {
+        expectLog("useBeanshell", "I'm here");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/DotnetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/DotnetTest.java
new file mode 100644
index 0000000..79cd72f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/DotnetTest.java
@@ -0,0 +1,136 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the Dotnet tasks, based off WsdlToDotnetTest
+ *
+ * @since Ant 1.6
+ */
+public class DotnetTest extends BuildFileTest {
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public DotnetTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "dotnet.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCSC() throws Exception {
+        executeTarget("testCSC");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCSCintrinsicFileset() throws Exception {
+        executeTarget("testCSCintrinsicFileset");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCSCdll() throws Exception {
+        executeTarget("testCSCdll");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCscReferences() throws Exception {
+        executeTarget("testCscReferences");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCscResources() throws Exception {
+        executeTarget("testCSCResources");
+    }
+
+    /**
+     * test we can assemble
+     */
+    public void testILASM() throws Exception {
+        executeTarget("testILASM");
+    }
+
+    /**
+     * test we can disassemble
+     */
+    public void testILDASM() throws Exception {
+        executeTarget("testILDASM");
+    }
+
+    /**
+     * test we can disassemble
+     */
+    public void testILDASM_empty() throws Exception {
+        expectBuildExceptionContaining("testILDASM_empty",
+                "parameter validation",
+                "invalid");
+    }
+
+    /**
+     * test we can handle jsharp (if found)
+     */
+    public void testJsharp() throws Exception {
+        executeTarget("jsharp");
+    }
+
+    /**
+     * test we can handle jsharp (if found)
+     */
+    public void testResponseFile() throws Exception {
+        executeTarget("testCSCresponseFile");
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/EchoPropertiesTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/EchoPropertiesTest.java
new file mode 100644
index 0000000..8e51c61
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/EchoPropertiesTest.java
@@ -0,0 +1,253 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.BufferedReader;
+import java.util.Properties;
+
+/**
+ * Tests the EchoProperties task.
+ *
+ * @created   17-Jan-2002
+ * @since     Ant 1.5
+ */
+public class EchoPropertiesTest extends BuildFileTest {
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+    private static final String GOOD_OUTFILE = "test.properties";
+    private static final String GOOD_OUTFILE_XML = "test.xml";
+    private static final String PREFIX_OUTFILE = "test-prefix.properties";
+    private static final String TEST_VALUE = "isSet";
+    private static final String BAD_OUTFILE = ".";
+
+    public EchoPropertiesTest(String name) {
+        super(name);
+    }
+
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "echoproperties.xml");
+        project.setProperty( "test.property", TEST_VALUE );
+    }
+
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+
+    public void testEchoToLog() {
+        expectLogContaining("testEchoToLog", "test.property="+TEST_VALUE);
+    }
+
+    public void testEchoWithEmptyPrefixToLog() {
+        expectLogContaining("testEchoWithEmptyPrefixToLog", "test.property="+TEST_VALUE);
+    }
+
+
+    public void testReadBadFile() {
+        expectBuildExceptionContaining( "testReadBadFile",
+            "srcfile is a directory", "srcfile is a directory!" );
+    }
+
+
+    public void testReadBadFileFail() {
+        expectBuildExceptionContaining( "testReadBadFile",
+            "srcfile is a directory", "srcfile is a directory!" );
+    }
+
+
+    public void testReadBadFileNoFail() {
+        expectLog( "testReadBadFileNoFail", "srcfile is a directory!" );
+    }
+
+
+    public void testEchoToBadFile() {
+        expectBuildExceptionContaining( "testEchoToBadFile",
+            "destfile is a directory", "destfile is a directory!" );
+    }
+
+
+    public void testEchoToBadFileFail() {
+        expectBuildExceptionContaining( "testEchoToBadFileFail",
+            "destfile is a directory", "destfile is a directory!" );
+    }
+
+
+    public void testEchoToBadFileNoFail() {
+        expectLog( "testEchoToBadFileNoFail", "destfile is a directory!");
+    }
+
+
+    public void testEchoToGoodFile() throws Exception {
+        executeTarget( "testEchoToGoodFile" );
+        assertGoodFile();
+    }
+
+
+    public void testEchoToGoodFileXml() throws Exception {
+        executeTarget( "testEchoToGoodFileXml" );
+
+        // read in the file
+        File f = createRelativeFile( GOOD_OUTFILE_XML );
+        FileReader fr = new FileReader( f );
+        try {
+            BufferedReader br = new BufferedReader( fr );
+            String read = null;
+            while ( (read = br.readLine()) != null) {
+                if (read.indexOf("<property name=\"test.property\" value=\""+TEST_VALUE+"\" />") >= 0) {
+                    // found the property we set - it's good.
+                    return;
+                }
+            }
+            fail( "did not encounter set property in generated file." );
+        } finally {
+            try {
+                fr.close();
+            } catch(IOException e) {}
+        }
+    }
+
+
+    public void testEchoToGoodFileFail() throws Exception {
+        executeTarget( "testEchoToGoodFileFail" );
+        assertGoodFile();
+    }
+
+
+    public void testEchoToGoodFileNoFail() throws Exception {
+        executeTarget( "testEchoToGoodFileNoFail" );
+        assertGoodFile();
+    }
+
+
+    public void testEchoPrefix() throws Exception {
+        testEchoPrefixVarious("testEchoPrefix");
+    }
+
+    public void testEchoPrefixAsPropertyset() throws Exception {
+        testEchoPrefixVarious("testEchoPrefixAsPropertyset");
+    }
+
+    public void testEchoPrefixAsNegatedPropertyset() throws Exception {
+        testEchoPrefixVarious("testEchoPrefixAsNegatedPropertyset");
+    }
+
+    public void testEchoPrefixAsDoublyNegatedPropertyset() throws Exception {
+        testEchoPrefixVarious("testEchoPrefixAsDoublyNegatedPropertyset");
+    }
+
+    public void testWithPrefixAndRegex() throws Exception {
+        expectSpecificBuildException("testWithPrefixAndRegex",
+                "The target must fail with prefix and regex attributes set",
+                "Please specify either prefix or regex, but not both");
+    }
+
+    public void testWithEmptyPrefixAndRegex() throws Exception {
+        expectLogContaining("testEchoWithEmptyPrefixToLog", "test.property="+TEST_VALUE);
+    }
+
+    public void testWithRegex() throws Exception {
+        if (!RegexpMatcherFactory.regexpMatcherPresent(project)) {
+            System.out.println("Test 'testWithRegex' skipped because no regexp matcher is present.");
+            return;
+        }
+        executeTarget("testWithRegex");
+        assertDebuglogContaining("ant.home=");
+    }
+
+    private void testEchoPrefixVarious(String target) throws Exception {
+        executeTarget(target);
+        Properties props = loadPropFile(PREFIX_OUTFILE);
+        assertEquals("prefix didn't include 'a.set' property",
+            "true", props.getProperty("a.set"));
+        assertNull("prefix failed to filter out property 'b.set'",
+            props.getProperty("b.set"));
+    }
+
+    protected Properties loadPropFile(String relativeFilename)
+            throws IOException {
+        File f = createRelativeFile( relativeFilename );
+        Properties props=new Properties();
+        InputStream in=null;
+        try  {
+            in=new BufferedInputStream(new FileInputStream(f));
+            props.load(in);
+        } finally {
+            if(in!=null) {
+                try { in.close(); } catch(IOException e) {}
+            }
+        }
+        return props;
+    }
+
+    protected void assertGoodFile() throws Exception {
+        File f = createRelativeFile( GOOD_OUTFILE );
+        assertTrue(
+            "Did not create "+f.getAbsolutePath(),
+            f.exists() );
+        Properties props=loadPropFile(GOOD_OUTFILE);
+        props.list(System.out);
+        assertEquals("test property not found ",
+                     TEST_VALUE, props.getProperty("test.property"));
+/*
+        // read in the file
+        FileReader fr = new FileReader( f );
+        try {
+            BufferedReader br = new BufferedReader( fr );
+            String read = null;
+            while ( (read = br.readLine()) != null)
+            {
+                if (read.indexOf("test.property" + TEST_VALUE) >= 0)
+                {
+                    // found the property we set - it's good.
+                    return;
+                }
+            }
+            fail( "did not encounter set property in generated file." );
+        } finally {
+            try { fr.close(); } catch(IOException e) {}
+        }
+*/
+    }
+
+
+    protected String toAbsolute( String filename ) {
+        return createRelativeFile( filename ).getAbsolutePath();
+    }
+
+
+    protected File createRelativeFile( String filename ) {
+        if (filename.equals( "." )) {
+            return getProjectDir();
+        }
+        // else
+        return new File( getProjectDir(), filename );
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JavahTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JavahTest.java
new file mode 100644
index 0000000..8caa42c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JavahTest.java
@@ -0,0 +1,50 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class JavahTest extends BuildFileTest {
+
+    private final static String BUILD_XML = 
+        "src/etc/testcases/taskdefs/optional/javah/build.xml";
+
+    public JavahTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(BUILD_XML);
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void testSimpleCompile() {
+        executeTarget("simple-compile");
+        assertTrue(getProject().resolveFile("output/org_example_Foo.h")
+                   .exists());
+    }
+
+    public void testCompileFileset() {
+        executeTarget("test-fileset");
+        assertTrue(getProject().resolveFile("output/org_example_Foo.h")
+                   .exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JspcTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JspcTest.java
new file mode 100644
index 0000000..7e810b1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/JspcTest.java
@@ -0,0 +1,229 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.taskdefs.optional.jsp.Jasper41Mangler;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspMangler;
+import org.apache.tools.ant.taskdefs.optional.jsp.JspNameMangler;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapter;
+import org.apache.tools.ant.taskdefs.optional.jsp.compilers.JspCompilerAdapterFactory;
+
+/**
+ * Tests the Jspc task.
+ *
+ * @created 07 March 2002
+ * @since Ant 1.5
+ */
+public class JspcTest extends BuildFileTest {
+    /**
+     * Description of the Field
+     */
+    private File baseDir;
+    /**
+     * Description of the Field
+     */
+    private File outDir;
+
+    /**
+     * Description of the Field
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+
+
+    /**
+     * Constructor for the JspcTest object
+     *
+     * @param name Description of Parameter
+     */
+    public JspcTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "jspc.xml");
+        baseDir = new File(System.getProperty("root"), TASKDEFS_DIR);
+        outDir = new File(baseDir, "jsp/java");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testSimple() throws Exception {
+        executeJspCompile("testSimple", "simple_jsp.java");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testUriroot() throws Exception {
+        executeJspCompile("testUriroot", "uriroot_jsp.java");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testXml() throws Exception {
+        executeJspCompile("testXml", "xml_jsp.java");
+    }
+
+
+    /**
+     * try a keyword in a file
+     */
+    public void testKeyword() throws Exception {
+        executeJspCompile("testKeyword", "default_jsp.java");
+    }
+
+
+    /**
+     * what happens to 1nvalid-classname
+     */
+    public void testInvalidClassname() throws Exception {
+        executeJspCompile("testInvalidClassname",
+                "_1nvalid_0002dclassname_jsp.java");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoTld() throws Exception {
+//         expectBuildExceptionContaining("testNoTld",
+//                 "Jasper found an error in a file",
+//                 "Java returned: 9");
+         expectBuildExceptionContaining("testNoTld",
+                 "not found",
+                 "Java returned: 9");
+    }
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNotAJspFile()  throws Exception {
+        executeTarget("testNotAJspFile");
+    }
+
+    /**
+     * webapp test is currently broken, because it picks up
+     * on the missing_tld file, and bails.
+     */
+/*
+    public void testWebapp()  throws Exception {
+        executeTarget("testWebapp");
+    }
+*/
+    /**
+     * run a target then verify the named file gets created
+     *
+     * @param target Description of Parameter
+     * @param javafile Description of Parameter
+     * @exception Exception trouble
+     */
+    protected void executeJspCompile(String target, String javafile)
+        throws Exception {
+        executeTarget(target);
+        assertJavaFileCreated(javafile);
+    }
+
+
+    /**
+     * verify that a named file was created
+     *
+     * @param filename Description of Parameter
+     * @exception Exception trouble
+     */
+    protected void assertJavaFileCreated(String filename)
+        throws Exception {
+        File file = getOutputFile(filename);
+        assertTrue("file " + filename + " not found", file.exists());
+        assertTrue("file " + filename + " is empty", file.length() > 0);
+    }
+
+    /**
+     * Gets the OutputFile attribute of the JspcTest object
+     *
+     * @param subpath Description of Parameter
+     * @return The OutputFile value
+     */
+    protected File getOutputFile(String subpath) {
+        return new File(outDir, subpath);
+    }
+
+    /**
+     * verify that we select the appropriate mangler
+     */
+    public void testJasperNameManglerSelection() {
+        JspCompilerAdapter adapter=
+                JspCompilerAdapterFactory.getCompiler("jasper", null,null);
+        JspMangler mangler=adapter.createMangler();
+        assertTrue(mangler instanceof JspNameMangler);
+        adapter= JspCompilerAdapterFactory.getCompiler("jasper41", null, null);
+        mangler = adapter.createMangler();
+        assertTrue(mangler instanceof Jasper41Mangler);
+    }
+
+    public void testJasper41() {
+        JspMangler mangler = new Jasper41Mangler();
+        //java keywords are not special
+        assertMapped(mangler, "for.jsp", "for_jsp");
+        //underscores go in front of invalid start chars
+        assertMapped(mangler, "0.jsp", "_0_jsp");
+        //underscores at the front get an underscore too
+        assertMapped(mangler, "_.jsp", "___jsp");
+        //non java char at start => underscore then the the _hex value
+        assertMapped(mangler, "-.jsp", "__0002d_jsp");
+        //and paths are stripped
+        char s = File.separatorChar;
+        assertMapped(mangler, "" + s + s + "somewhere" + s + "file" + s + "index.jsp", "index_jsp");
+    }
+
+    /**
+     * assert our mapping rules
+     * @param mangler
+     * @param filename
+     * @param classname
+     */
+    protected void assertMapped(JspMangler mangler, String filename, String classname) {
+        String mappedname = mangler.mapJspToJavaName(new File(filename));
+        assertTrue(filename+" should have mapped to "+classname
+                    +" but instead mapped to "+mappedname,
+                    classname.equals(mappedname));
+    }
+
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/Native2AsciiTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/Native2AsciiTest.java
new file mode 100644
index 0000000..d18c82a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/Native2AsciiTest.java
@@ -0,0 +1,48 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+public class Native2AsciiTest extends BuildFileTest {
+
+    private final static String BUILD_XML = 
+        "src/etc/testcases/taskdefs/optional/native2ascii/build.xml";
+
+    public Native2AsciiTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(BUILD_XML);
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void testIso8859_1() throws java.io.IOException {
+        executeTarget("testIso8859-1");
+        File in = getProject().resolveFile("expected/iso8859-1.test");
+        File out = getProject().resolveFile("output/iso8859-1.test");
+        assertTrue(FileUtils.getFileUtils().contentEquals(in, out, true));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PropertyFileTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PropertyFileTest.java
new file mode 100644
index 0000000..795d52c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PropertyFileTest.java
@@ -0,0 +1,227 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ *  JUnit testcase that excercises the optional PropertyFile task in ant.
+ *  (this is really more of a functional test so far.., but it's enough to let
+ *   me start refactoring...)
+ *
+ *@created    October 2, 2001
+ */
+
+public class PropertyFileTest extends BuildFileTest {
+
+    public PropertyFileTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     *  The JUnit setup method
+     */
+    public void setUp() throws Exception {
+        destroyTempFiles();
+        initTestPropFile();
+        initBuildPropFile();
+        configureProject(projectFilePath);
+        project.setProperty(valueDoesNotGetOverwrittenPropertyFileKey,valueDoesNotGetOverwrittenPropertyFile);
+    }
+
+
+    /**
+     *  The JUnit tearDown method
+     */
+    public void tearDown() {
+        destroyTempFiles();
+    }
+
+    public void testNonExistingFile() {
+        PropertyFile props = new PropertyFile();
+        props.setProject( getProject() );
+        File file = new File("this-file-does-not-exist.properties");
+        props.setFile(file);
+        assertFalse("Properties file exists before test.", file.exists());
+        props.execute();
+        assertTrue("Properties file does not exist after test.", file.exists());
+        file.delete();
+    }
+
+    /**
+     *  A unit test for JUnit- Excercises the propertyfile tasks ability to
+     *  update properties that are already defined-
+     */
+    public void testUpdatesExistingProperties() throws Exception {
+        Properties beforeUpdate = getTestProperties();
+        assertEquals(FNAME, beforeUpdate.getProperty(FNAME_KEY));
+        assertEquals(LNAME, beforeUpdate.getProperty(LNAME_KEY));
+        assertEquals(EMAIL, beforeUpdate.getProperty(EMAIL_KEY));
+        assertEquals(null, beforeUpdate.getProperty(PHONE_KEY));
+        assertEquals(null, beforeUpdate.getProperty(AGE_KEY));
+        assertEquals(null, beforeUpdate.getProperty(DATE_KEY));
+
+        // ask ant to update the properties...
+        executeTarget("update-existing-properties");
+
+        Properties afterUpdate = getTestProperties();
+        assertEquals(NEW_FNAME, afterUpdate.getProperty(FNAME_KEY));
+        assertEquals(NEW_LNAME, afterUpdate.getProperty(LNAME_KEY));
+        assertEquals(NEW_EMAIL, afterUpdate.getProperty(EMAIL_KEY));
+        assertEquals(NEW_PHONE, afterUpdate.getProperty(PHONE_KEY));
+        assertEquals(NEW_AGE, afterUpdate.getProperty(AGE_KEY));
+        assertEquals(NEW_DATE, afterUpdate.getProperty(DATE_KEY));
+    }
+
+    public void testExerciseDefaultAndIncrement() throws Exception {
+        executeTarget("exercise");
+        assertEquals("3",project.getProperty("int.with.default"));
+        assertEquals("1",project.getProperty("int.without.default"));
+        assertEquals("-->",project.getProperty("string.with.default"));
+        assertEquals(".",project.getProperty("string.without.default"));
+        assertEquals("2002/01/21 12:18", project.getProperty("ethans.birth"));
+        assertEquals("2003/01/21", project.getProperty("first.birthday"));
+        assertEquals("0124", project.getProperty("olderThanAWeek"));
+        assertEquals("37", project.getProperty("existing.prop"));
+        assertEquals("6",project.getProperty("int.without.value"));
+    }
+
+    public void testValueDoesNotGetOverwritten() {
+        // this test shows that the bug report 21505 is fixed
+        executeTarget("bugDemo1");
+        executeTarget("bugDemo2");
+        assertEquals("5", project.getProperty("foo"));
+    }
+/*
+    public void testDirect() throws Exception {
+        PropertyFile pf = new PropertyFile();
+        pf.setProject(project);
+        pf.setFile(new File(System.getProperty("root"), testPropsFilePath));
+        PropertyFile.Entry entry = pf.createEntry();
+
+        entry.setKey("date");
+        entry.setValue("123");
+        PropertyFile.Entry.Type type = new PropertyFile.Entry.Type();
+        type.setValue("date");
+        entry.setType(type);
+
+        entry.setPattern("yyyy/MM/dd");
+
+        PropertyFile.Entry.Operation operation = new PropertyFile.Entry.Operation();
+        operation.setValue("+");
+        pf.execute();
+
+        Properties props = getTestProperties();
+        assertEquals("yeehaw", props.getProperty("date"));
+    }
+*/
+
+    private Properties getTestProperties() throws Exception {
+        Properties testProps = new Properties();
+        FileInputStream propsFile = new FileInputStream(new File(System.getProperty("root"), testPropsFilePath));
+        testProps.load(propsFile);
+        propsFile.close();
+        return testProps;
+    }
+
+
+    private void initTestPropFile() throws Exception {
+        Properties testProps = new Properties();
+        testProps.put(FNAME_KEY, FNAME);
+        testProps.put(LNAME_KEY, LNAME);
+        testProps.put(EMAIL_KEY, EMAIL);
+        testProps.put("existing.prop", "37");
+
+        FileOutputStream fos = new FileOutputStream(new File(System.getProperty("root"), testPropsFilePath));
+        testProps.store(fos, "defaults");
+        fos.close();
+    }
+
+
+    private void initBuildPropFile() throws Exception {
+        Properties buildProps = new Properties();
+        buildProps.put(testPropertyFileKey, testPropertyFile);
+        buildProps.put(FNAME_KEY, NEW_FNAME);
+        buildProps.put(LNAME_KEY, NEW_LNAME);
+        buildProps.put(EMAIL_KEY, NEW_EMAIL);
+        buildProps.put(PHONE_KEY, NEW_PHONE);
+        buildProps.put(AGE_KEY, NEW_AGE);
+        buildProps.put(DATE_KEY, NEW_DATE);
+
+        FileOutputStream fos = new FileOutputStream(new File(System.getProperty("root"), buildPropsFilePath));
+        buildProps.store(fos, null);
+        fos.close();
+    }
+
+
+    private void destroyTempFiles() {
+        File tempFile = new File(System.getProperty("root"), testPropsFilePath);
+        tempFile.delete();
+        tempFile = null;
+
+        tempFile = new File(System.getProperty("root"), buildPropsFilePath);
+        tempFile.delete();
+        tempFile = null;
+
+        tempFile = new File(System.getProperty("root"), valueDoesNotGetOverwrittenPropsFilePath);
+        tempFile.delete();
+        tempFile = null;
+    }
+
+
+
+    private static final String
+        projectFilePath     = "src/etc/testcases/taskdefs/optional/propertyfile.xml",
+
+        testPropertyFile    = "propertyfile.test.properties",
+        testPropertyFileKey = "test.propertyfile",
+        testPropsFilePath   = "src/etc/testcases/taskdefs/optional/" + testPropertyFile,
+
+        valueDoesNotGetOverwrittenPropertyFile    = "overwrite.test.properties",
+        valueDoesNotGetOverwrittenPropertyFileKey = "overwrite.test.propertyfile",
+        valueDoesNotGetOverwrittenPropsFilePath   = "src/etc/testcases/taskdefs/optional/" + valueDoesNotGetOverwrittenPropertyFile,
+
+        buildPropsFilePath  = "src/etc/testcases/taskdefs/optional/propertyfile.build.properties",
+
+        FNAME     = "Bruce",
+        NEW_FNAME = "Clark",
+        FNAME_KEY = "firstname",
+
+        LNAME     = "Banner",
+        NEW_LNAME = "Kent",
+        LNAME_KEY = "lastname",
+
+        EMAIL     = "incredible@hulk.com",
+        NEW_EMAIL = "kc@superman.com",
+        EMAIL_KEY = "email",
+
+        NEW_PHONE = "(520) 555-1212",
+        PHONE_KEY = "phone",
+
+        NEW_AGE = "30",
+        AGE_KEY = "age",
+
+        NEW_DATE = "2001/01/01 12:45",
+        DATE_KEY = "date";
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PvcsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PvcsTest.java
new file mode 100644
index 0000000..0dc1d70
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/PvcsTest.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ */
+public class PvcsTest extends BuildFileTest {
+
+    public PvcsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/pvcs.xml");
+    }
+
+    public void test1() {
+        expectBuildException("test1", "Required argument repository not specified");
+    }
+
+    public void test2() {
+        executeTarget("test2");
+    }
+
+    public void test3() {
+        executeTarget("test3");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+    }
+
+    public void test5() {
+        executeTarget("test5");
+    }
+
+    public void test6() {
+        expectBuildException("test6", "Failed executing: /never/heard/of/a/directory/structure/like/this/pcli lvf -z -aw -pr//ct4serv2/pvcs/monitor /. Exception: /never/heard/of/a/directory/structure/like/this/pcli: not found");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ReplaceRegExpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ReplaceRegExpTest.java
new file mode 100644
index 0000000..bc18d05
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ReplaceRegExpTest.java
@@ -0,0 +1,105 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.util.Properties;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * JUnit Testcase for the optional replaceregexp task.
+ *
+ */
+public class ReplaceRegExpTest extends BuildFileTest {
+    private static final String PROJECT_PATH = "src/etc/testcases/taskdefs/optional";
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    
+    public ReplaceRegExpTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(PROJECT_PATH + "/replaceregexp.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testReplace() throws IOException {
+        Properties original = new Properties();
+        FileInputStream propsFile = null;
+        try {
+            propsFile = new FileInputStream(new File(System.getProperty("root"), PROJECT_PATH + "/replaceregexp.properties"));
+            original.load(propsFile);
+        } finally {
+            if (propsFile != null) {
+                propsFile.close();
+                propsFile = null;
+            }
+        }
+
+        assertEquals("Def", original.get("OldAbc"));
+
+        executeTarget("testReplace");
+
+        Properties after = new Properties();
+        try {
+            propsFile = new FileInputStream(new File(System.getProperty("root"), PROJECT_PATH + "/test.properties"));
+            after.load(propsFile);
+        } finally {
+            if (propsFile != null) {
+                propsFile.close();
+                propsFile = null;
+            }
+        }
+
+        assertNull(after.get("OldAbc"));
+        assertEquals("AbcDef", after.get("NewProp"));
+    }
+    // inspired by bug 22541
+    public void testDirectoryDateDoesNotChange() {
+        executeTarget("touchDirectory");
+        File myFile = new File(System.getProperty("root"), PROJECT_PATH + "/" + getProject().getProperty("tmpregexp"));
+        long timeStampBefore = myFile.lastModified();
+        executeTarget("testDirectoryDateDoesNotChange");
+        long timeStampAfter = myFile.lastModified();
+        assertEquals("directory date should not change",
+            timeStampBefore, timeStampAfter);
+    }
+    public void testDontAddNewline1() throws IOException {
+        executeTarget("testDontAddNewline1");
+        assertTrue("Files match",
+                   FILE_UTILS
+                   .contentEquals(new File(System.getProperty("root"), PROJECT_PATH + "/test.properties"),
+                                  new File(System.getProperty("root"), PROJECT_PATH + "/replaceregexp2.result.properties")));
+    }
+
+    public void testDontAddNewline2() throws IOException {
+        executeTarget("testDontAddNewline2");
+        assertTrue("Files match",
+                   FILE_UTILS
+                   .contentEquals(new File(System.getProperty("root"), PROJECT_PATH + "/test.properties"),
+                                  new File(System.getProperty("root"), PROJECT_PATH + "/replaceregexp2.result.properties")));
+    }
+
+}// ReplaceRegExpTest
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoReferenceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoReferenceTest.java
new file mode 100644
index 0000000..64ae4f4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoReferenceTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests using an undefined reference.
+ *
+ * @since Ant 1.6
+ */
+public class RhinoReferenceTest extends BuildFileTest {
+
+    public RhinoReferenceTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(
+            "src/etc/testcases/taskdefs/optional/script_reference.xml");
+    }
+
+    public void testScript() {
+        executeTarget("script");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoScriptTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoScriptTest.java
new file mode 100644
index 0000000..f3f3a49
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RhinoScriptTest.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the examples of the &lt;script&gt; task docs.
+ *
+ * @since Ant 1.5.2
+ */
+public class RhinoScriptTest extends BuildFileTest {
+
+    public RhinoScriptTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/script.xml");
+    }
+
+    public void testExample1() {
+        executeTarget("example1");
+        int index = getLog().indexOf("1");
+        assertTrue(index > -1);
+        index = getLog().indexOf("4", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("9", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("16", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("25", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("36", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("49", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("64", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("81", index);
+        assertTrue(index > -1);
+        index = getLog().indexOf("100", index);
+        assertTrue(index > -1);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RpmTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RpmTest.java
new file mode 100644
index 0000000..17cf953
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/RpmTest.java
@@ -0,0 +1,66 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
+import org.apache.tools.ant.types.Commandline;
+import junit.framework.TestCase;
+
+public class RpmTest extends TestCase {
+
+    public void testShouldThrowExceptionWhenRpmFails() throws Exception {
+        Rpm rpm = new MyRpm();
+        rpm.setProject(new org.apache.tools.ant.Project());
+        rpm.setFailOnError(true);
+        // execute
+        try {
+            rpm.execute();
+            fail("should have thrown a build exception");
+        } catch (BuildException ex) {
+            assertTrue(ex.getMessage()
+                       .indexOf("' failed with exit code 2") != -1);
+        }
+    }
+
+    public void testShouldNotThrowExceptionWhenRpmFails() throws Exception {
+        Rpm rpm = new MyRpm();
+        rpm.execute();
+    }
+
+    // override some of the code so we can test the handling of the
+    // return code only.
+    public static class MyRpm extends Rpm {
+        protected Execute getExecute(Commandline toExecute,
+                                     ExecuteStreamHandler streamhandler) {
+            return new Execute() {
+                    public int execute() {
+                        // 2 is != 0 and even, so it is considered
+                        // failure on any platform currently supported
+                        // by Execute#isFailure.
+                        return 2;
+                    }
+                };
+        }
+
+        public void log(String msg, int msgLevel) {
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/SchemaValidateTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/SchemaValidateTest.java
new file mode 100644
index 0000000..3793e2f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/SchemaValidateTest.java
@@ -0,0 +1,99 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test schema validation
+ */
+
+public class SchemaValidateTest extends BuildFileTest {
+
+    /**
+     * where tasks run
+     */
+    private final static String TASKDEFS_DIR =
+            "src/etc/testcases/taskdefs/optional/";
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public SchemaValidateTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "schemavalidate.xml");
+    }
+
+    /**
+     * test with no namespace
+     */
+    public void testNoNamespace() throws Exception {
+        executeTarget("testNoNamespace");
+    }
+
+    /**
+     * add namespace awareness.
+     */
+    public void testNSMapping() throws Exception {
+        executeTarget("testNSMapping");
+    }
+
+    public void testNoEmptySchemaNamespace() throws Exception {
+        expectBuildExceptionContaining("testNoEmptySchemaNamespace",
+                "empty namespace URI",SchemaValidate.SchemaLocation.ERROR_NO_URI);
+    }
+
+    public void testNoEmptySchemaLocation() throws Exception {
+        expectBuildExceptionContaining("testNoEmptySchemaLocation",
+                "empty schema location",
+                SchemaValidate.SchemaLocation.ERROR_NO_LOCATION);
+    }
+
+    public void testNoFile() throws Exception {
+        expectBuildExceptionContaining("testNoFile",
+                "no file at file attribute",
+                SchemaValidate.SchemaLocation.ERROR_NO_FILE);
+    }
+
+    public void testNoDoubleSchemaLocation() throws Exception {
+        expectBuildExceptionContaining("testNoDoubleSchemaLocation",
+                "two locations for schemas",
+                SchemaValidate.SchemaLocation.ERROR_TWO_LOCATIONS);
+    }
+    public void testNoDuplicateSchema() throws Exception {
+        expectBuildExceptionContaining("testNoDuplicateSchema",
+                "duplicate schemas with different values",
+                SchemaValidate.ERROR_DUPLICATE_SCHEMA);
+    }
+
+    public void testEqualsSchemasOK() throws Exception {
+        executeTarget("testEqualsSchemasOK");
+    }
+
+    public void testFileset() throws Exception {
+        executeTarget("testFileset");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java
new file mode 100644
index 0000000..55427ab
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/TraXLiaisonTest.java
@@ -0,0 +1,100 @@
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.taskdefs.XSLTLiaison;
+import org.apache.tools.ant.taskdefs.XSLTLogger;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.JAXPUtils;
+
+import java.io.File;
+
+import junit.framework.AssertionFailedError;
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/**
+ * TraX XSLTLiaison testcase
+ */
+public class TraXLiaisonTest extends AbstractXSLTLiaisonTest
+    implements XSLTLogger {
+
+    public TraXLiaisonTest(String name){
+        super(name);
+    }
+
+    public void tearDown() {
+        File f = new File("xalan2-redirect-out.tmp");
+        if (f.exists()) {
+            f.delete();
+        }
+    }
+
+    public XSLTLiaison createLiaison() throws Exception {
+        TraXLiaison l = new TraXLiaison();
+        l.setLogger(this);
+        return l;
+    }
+
+    public void testXalan2Redirect() throws Exception {
+        File xsl = getFile("/taskdefs/optional/xalan-redirect-in.xsl");
+        liaison.setStylesheet(xsl);
+        File out = new File("xalan2-redirect-out-dummy.tmp");
+        File in = getFile("/taskdefs/optional/xsltliaison-in.xsl");
+        try {
+            liaison.addParam("xalan-version", "2");
+            liaison.transform(in, out);
+        } finally {
+            out.delete();
+        }
+    }
+
+    public void testMultipleTransform() throws Exception {
+        File xsl = getFile("/taskdefs/optional/xsltliaison-in.xsl");
+        liaison.setStylesheet(xsl);
+        liaison.addParam("param", "value");
+        File in = getFile("/taskdefs/optional/xsltliaison-in.xml");
+        // test for 10 consecutives transform
+        for (int i = 0; i < 50; i++){
+            File out = new File("xsltliaison" + i + ".tmp");
+            try {
+                liaison.transform(in, out);
+            } catch (Exception e){
+                throw new BuildException("failed in transform " + i, e);
+            } finally {
+                out.delete();
+            }
+        }
+    }
+
+    public void testSystemId(){
+        File file = null;
+        if ( File.separatorChar == '\\' ){
+            file = new File("d:\\jdk");
+        } else {
+            file = new File("/user/local/bin");
+        }
+        String systemid = JAXPUtils.getSystemId(file);
+        assertTrue("SystemIDs should start by file:/", systemid.startsWith("file:/"));
+        assertTrue("SystemIDs should not start with file:////", !systemid.startsWith("file:////"));
+    }
+
+    public void log(String message) {
+        throw new AssertionFailedError("Liaison sent message: "+message);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/WsdlToDotnetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/WsdlToDotnetTest.java
new file mode 100644
index 0000000..9d3d4ea
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/WsdlToDotnetTest.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.taskdefs.optional.dotnet.WsdlToDotnet;
+
+/**
+ * Tests the WsdlToDotnet task.
+ *
+ * @since Ant 1.5
+ */
+public class WsdlToDotnetTest extends BuildFileTest {
+
+    /**
+     * dir for taskdefs
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+
+    /**
+     * message from exec
+     */
+    private static final String WSDL_FAILED = "WSDL returned:";
+
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public WsdlToDotnetTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "WsdlToDotnet.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoParams() throws Exception {
+        expectBuildExceptionContaining("testNoParams",
+                "expected failure",
+                WsdlToDotnet.ERROR_NO_DEST_FILE);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testNoSrc() throws Exception {
+        expectBuildExceptionContaining("testNoSrc",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_NONE_DECLARED);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testDestIsDir() throws Exception {
+        expectBuildExceptionContaining("testDestIsDir",
+                "expected failure",
+                WsdlToDotnet.ERROR_DEST_FILE_IS_DIR);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testBothSrc() throws Exception {
+        expectBuildExceptionContaining("testBothSrc",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_BOTH_DECLARED);
+    }
+     /**
+     * A unit test for JUnit
+     */
+    public void testSrcIsDir() throws Exception {
+        expectBuildExceptionContaining("testSrcIsDir",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_FILE_IS_DIR);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testSrcIsMissing() throws Exception {
+        expectBuildExceptionContaining("testSrcIsMissing",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_FILE_NOT_FOUND);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testLocalWsdl() throws Exception {
+        executeTarget("testLocalWsdl");
+    }
+    /**
+     * A unit test for JUnit
+     */
+    public void testLocalWsdlServer() throws Exception {
+        executeTarget("testLocalWsdlServer");
+    }
+     /**
+     * A unit test for JUnit
+     */
+    public void testInvalidExtraOps() throws Exception {
+        expectBuildExceptionContaining("testInvalidExtraOps",
+                "expected failure",
+                WSDL_FAILED);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testLocalWsdlVB() throws Exception {
+        executeTarget("testLocalWsdlVB");
+    }
+    /**
+     * A unit test for JUnit
+     */
+    public void testLocalWsdlServerVB() throws Exception {
+        executeTarget("testLocalWsdlServerVB");
+    }
+     /**
+     * A unit test for JUnit
+     */
+    public void testInvalidExtraOpsVB() throws Exception {
+        expectBuildExceptionContaining("testInvalidExtraOpsVB",
+                "expected failure",
+                WSDL_FAILED);
+    }
+
+    /**
+     * as if parseable errors were not ignored, mono and WSE1.0 would
+     * crash and burn. So here we verify the property exists,
+     * and that it is not passed to the app when false
+     */
+    public void testParseableErrorsIgnoredWhenFalse() throws Exception {
+        executeTarget("testLocalWsdl");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testSchemaFileMustExist() throws Exception {
+        expectBuildExceptionContaining("testSchemaFileMustExist",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_FILE_NOT_FOUND);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testSchemaFileMustHaveOneOptionOnly() throws Exception {
+        expectBuildExceptionContaining("testSchemaFileMustHaveOneOptionOnly",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_BOTH_DECLARED);
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testSchemaMustBeSet() throws Exception {
+        expectBuildExceptionContaining("testSchemaMustBeSet",
+                "expected failure",
+                WsdlToDotnet.Schema.ERROR_NONE_DECLARED);
+    }
+
+
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateCatalogTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateCatalogTest.java
new file mode 100644
index 0000000..64db8e7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateCatalogTest.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the XMLValidate optional task with nested external catalogs.
+ *
+ * @see XmlValidateTest
+ * @since Ant 1.6
+ */
+public class XmlValidateCatalogTest extends BuildFileTest {
+
+    /**
+     * where tasks run
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public XmlValidateCatalogTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "xmlvalidate.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+
+    }
+
+    /**
+     * catalogfiles fileset should be ignored
+     * if resolver.jar is not present, but will
+     * be used if it is.  either way, test should
+     * work b/c we have a nested dtd with the same
+     * entity
+     */
+    public void testXmlCatalogFiles() {
+        executeTarget("xmlcatalogfiles");
+    }
+
+    /**
+     * Test nested catalogpath.
+     * It should be ignored if resolver.jar is not
+     * present, but will be used if it is.  either
+     * way, test should work b/c we have a nested
+     * dtd with the same entity
+     */
+    public void testXmlCatalogPath() {
+        executeTarget("xmlcatalogpath");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java
new file mode 100644
index 0000000..27be8a4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XmlValidateTest.java
@@ -0,0 +1,189 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the XMLValidate optional task, by running targets in the test script
+ * <code>src/etc/testcases/taskdefs/optional/xmlvalidate.xml</code>
+ * <p>
+ *
+ * @see XmlValidateCatalogTest
+ * @since Ant 1.5
+ */
+public class XmlValidateTest extends BuildFileTest {
+
+    /**
+     * where tasks run
+     */
+    private final static String TASKDEFS_DIR =
+        "src/etc/testcases/taskdefs/optional/";
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public XmlValidateTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "xmlvalidate.xml");
+    }
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {}
+
+    /**
+     * Basic inline 'dtd' element test.
+     */
+    public void testValidate() throws Exception {
+        executeTarget("testValidate");
+    }
+
+    /**
+     * Test indirect validation.
+     */
+    public void testDeepValidate() throws Exception {
+        executeTarget("testDeepValidate");
+    }
+
+    /**
+     *
+     */
+    public void testXmlCatalog() {
+        executeTarget("xmlcatalog");
+    }
+
+    /**
+     *
+     */
+    public void testXmlCatalogViaRefid() {
+        executeTarget("xmlcatalogViaRefid");
+    }
+
+    /**
+     * Test that the nested dtd element is used when resolver.jar is not
+     * present.  This test should pass either way.
+     */
+    public void testXmlCatalogFiles() {
+        executeTarget("xmlcatalogfiles-override");
+    }
+
+    /**
+     * Test nested catalogpath.
+     * Test that the nested dtd element is used when resolver.jar is not
+     * present.  This test should pass either way.
+     */
+    public void testXmlCatalogPath() {
+        executeTarget("xmlcatalogpath-override");
+    }
+
+    /**
+     * Test nested xmlcatalog definitions
+     */
+    public void testXmlCatalogNested() {
+        executeTarget("xmlcatalognested");
+    }
+
+    /**
+     * Test xml schema validation
+     */
+    public void testXmlSchemaGood() throws BuildException {
+        try {
+            executeTarget("testSchemaGood");
+        } catch (BuildException e) {
+            if (e
+                .getMessage()
+                .endsWith(" doesn't recognize feature http://apache.org/xml/features/validation/schema")
+                || e.getMessage().endsWith(
+                    " doesn't support feature http://apache.org/xml/features/validation/schema")) {
+                System.err.println(" skipped, parser doesn't support schema");
+            } else {
+                throw e;
+            }
+        }
+    }
+    /**
+     * Test xml schema validation
+     */
+    public void testXmlSchemaBad() {
+        try {
+            executeTarget("testSchemaBad");
+            fail("Should throw BuildException because 'Bad Schema Validation'");
+
+            expectBuildExceptionContaining(
+                "testSchemaBad",
+                "Bad Schema Validation",
+                "not a valid XML document");
+        } catch (BuildException e) {
+            if (e
+                .getMessage()
+                .endsWith(" doesn't recognize feature http://apache.org/xml/features/validation/schema")
+                || e.getMessage().endsWith(
+                    " doesn't support feature http://apache.org/xml/features/validation/schema")) {
+                System.err.println(" skipped, parser doesn't support schema");
+            } else {
+                assertTrue(
+                    e.getMessage().indexOf("not a valid XML document") > -1);
+            }
+        }
+    }
+
+    /**
+     * iso-2022-jp.xml is valid but wouldn't get recognized on systems
+     * with a different native encoding.
+     *
+     * Bug 11279
+     */
+    public void testIso2022Jp() {
+        executeTarget("testIso2022Jp");
+    }
+
+    /**
+     * utf-8.xml is invalid as it contains non-UTF-8 characters, but
+     * would pass on systems with a native iso-8859-1 (or similar)
+     * encoding.
+     *
+     * Bug 11279
+     */
+    public void testUtf8() {
+        expectBuildException("testUtf8", "invalid characters in file");
+    }
+
+    // Tests property element, using XML schema properties as an example.
+
+    public void testPropertySchemaForValidXML() {
+        executeTarget("testProperty.validXML");
+    }
+
+    public void testPropertySchemaForInvalidXML() {
+        expectBuildException(
+            "testProperty.invalidXML",
+            "XML file does not satisfy schema.");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XsltTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XsltTest.java
new file mode 100644
index 0000000..c28551d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/XsltTest.java
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Tests the {@link XSLTProcess} task.
+ * XXX merge with {@link StyleTest}?
+ * @since Ant 1.5
+ */
+public class XsltTest extends BuildFileTest {
+
+    /**
+     * where tasks run
+     */
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/";
+
+
+    /**
+     * Constructor
+     *
+     * @param name testname
+     */
+    public XsltTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "xslt.xml");
+    }
+
+
+    /**
+     * The teardown method for JUnit
+     */
+    public void tearDown() {
+        executeTarget("teardown");
+    }
+
+
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCatchNoDtd() throws Exception {
+        expectBuildExceptionContaining("testCatchNoDtd",
+                                       "expected failure",
+                                       "Fatal error during transformation");
+    }
+
+    /**
+     * A unit test for JUnit
+     */
+    public void testCatalog() throws Exception {
+         executeTarget("testCatalog");
+    }
+
+    public void testOutputProperty() throws Exception {
+      executeTarget("testOutputProperty");
+    }
+
+    public void testFactory() throws Exception {
+        executeTarget("testFactory");
+    }
+
+    public void testAttribute() throws Exception {
+        executeTarget("testAttribute");
+    }
+    public void testXMLWithEntitiesInNonAsciiPath() throws Exception {
+        executeTarget("testXMLWithEntitiesInNonAsciiPath");
+    }
+
+    /**
+     * check that the system id gets set properly on stylesheets.
+     * @throws Exception if something goes wrong.
+     */
+    public void testStyleSheetWithInclude() throws Exception {
+        executeTarget("testStyleSheetWithInclude");
+        if (getLog().indexOf("java.io.FileNotFoundException") != -1) {
+            fail("xsl:include was not found");
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/depend/DependTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/depend/DependTest.java
new file mode 100644
index 0000000..82f301e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/depend/DependTest.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.depend;
+
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Testcase for the Depend optional task.
+ *
+ */
+public class DependTest extends BuildFileTest {
+    public static final String RESULT_FILESET = "result";
+
+    public static final String TEST_BUILD_FILE
+        = "src/etc/testcases/taskdefs/optional/depend/depend.xml";
+
+    public DependTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TEST_BUILD_FILE);
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * Test direct dependency removal
+     */
+    public void testDirect() {
+        executeTarget("testdirect");
+        Hashtable files = getResultFiles();
+        assertEquals("Depend did not leave correct number of files", 3,
+            files.size());
+        assertTrue("Result did not contain A.class",
+            files.containsKey("A.class"));
+        assertTrue("Result did not contain D.class",
+            files.containsKey("D.class"));
+    }
+
+    /**
+     * Test dependency traversal (closure)
+     */
+    public void testClosure() {
+        executeTarget("testclosure");
+        Hashtable files = getResultFiles();
+        assertTrue("Depend did not leave correct number of files", 
+            files.size() <= 2);
+        assertTrue("Result did not contain D.class",
+            files.containsKey("D.class"));
+    }
+
+    /**
+     * Test that inner class dependencies trigger deletion of the outer class
+     */
+    public void testInner() {
+        executeTarget("testinner");
+        assertEquals("Depend did not leave correct number of files", 0,
+            getResultFiles().size());
+    }
+
+    /**
+     * Test that multi-leve inner class dependencies trigger deletion of
+     * the outer class
+     */
+    public void testInnerInner() {
+        executeTarget("testinnerinner");
+        assertEquals("Depend did not leave correct number of files", 0,
+            getResultFiles().size());
+    }
+
+    /**
+     * Test that an exception is thrown when there is no source
+     */
+    public void testNoSource() {
+        expectBuildExceptionContaining("testnosource",
+            "No source specified", "srcdir attribute must be set");
+    }
+
+    /**
+     * Test that an exception is thrown when the source attribute is empty
+     */
+    public void testEmptySource() {
+        expectBuildExceptionContaining("testemptysource",
+            "No source specified", "srcdir attribute must be non-empty");
+    }
+
+    /**
+     * Read the result fileset into a Hashtable
+     *
+     * @return a Hashtable containing the names of the files in the result
+     * fileset
+     */
+    private Hashtable getResultFiles() {
+        FileSet resultFileSet = (FileSet) project.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(project);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        return files;
+    }
+
+
+    /**
+     * Test mutual dependency between inner and outer do not cause both to be
+     * deleted
+     */
+    public void testInnerClosure() {
+        executeTarget("testinnerclosure");
+        assertEquals("Depend did not leave correct number of files", 4,
+            getResultFiles().size());
+    }
+
+    /**
+     * Test the operation of the cache
+     */
+    public void testCache() {
+        executeTarget("testcache");
+    }
+
+    /**
+     * Test the detection and warning of non public classes
+     */
+    public void testNonPublic() {
+        executeTarget("testnonpublic");
+        String log = getLog();
+        assertTrue("Expected warning about APrivate",
+            log.indexOf("The class APrivate in file") != -1);
+        assertTrue("but has not been deleted because its source file "
+            + "could not be determined",
+            log.indexOf("The class APrivate in file") != -1);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/i18n/TranslateTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/i18n/TranslateTest.java
new file mode 100644
index 0000000..64b5885
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/i18n/TranslateTest.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.i18n;
+
+import org.apache.tools.ant.BuildFileTest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Tests the Translate task.
+ *
+ * @since     Ant 1.6
+ */
+public class TranslateTest extends BuildFileTest {
+    static private final int BUF_SIZE = 32768;
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/i18n/translate";
+
+    public TranslateTest(String name) {
+        super(name);
+    }
+
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "/translate.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        executeTarget("test1");
+        assertTrue("translation of "+ TASKDEFS_DIR + "/input/template.txt",compareFiles(TASKDEFS_DIR+"/expected/de/template.txt",TASKDEFS_DIR+"/output/de/template.txt"));
+    }
+    private boolean compareFiles(String name1, String name2) {
+        File file1 = new File(System.getProperty("root"), name1);
+        File file2 = new File(System.getProperty("root"), name2);
+
+        try {
+            if (!file1.exists() || !file2.exists()) {
+                System.out.println("One or both files do not exist:" + name1 + ", " + name2);
+                return false;
+            }
+
+            if (file1.length() != file2.length()) {
+                System.out.println("File size mismatch:" + name1 + "(" + file1.length() + "), " +
+                                   name2  + "(" + file2.length() + ")");
+                return false;
+            }
+
+            // byte - byte compare
+            byte[] buffer1 = new byte[BUF_SIZE];
+            byte[] buffer2 = new byte[BUF_SIZE];
+
+            FileInputStream fis1 = new FileInputStream(file1);
+            FileInputStream fis2 = new FileInputStream(file2);
+            int index = 0;
+            int read = 0;
+            while ((read = fis1.read(buffer1)) != -1) {
+                fis2.read(buffer2);
+                for (int i = 0; i < read; ++i, ++index) {
+                    if (buffer1[i] != buffer2[i]) {
+                        System.out.println("Bytes mismatch:" + name1 + ", " + name2 +
+                                           " at byte " + index);
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+        catch (IOException e) {
+            System.out.println("IOException comparing files: " + name1 + ", " + name2);
+            return false;
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java
new file mode 100644
index 0000000..25b4245
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/image/ImageTest.java
@@ -0,0 +1,119 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.image;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+import java.io.File;
+
+
+/**
+ * Tests the Image task.
+ *
+ * @since     Ant 1.5
+ */
+public class ImageTest extends BuildFileTest {
+
+    private final static String TASKDEFS_DIR = 
+        "src/etc/testcases/taskdefs/optional/image/";
+    private final static String LARGEIMAGE = "largeimage.jpg";
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public ImageTest(String name) {
+        super(name);
+    }
+
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "image.xml");
+    }
+
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testEchoToLog() {
+        expectLogContaining("testEchoToLog", "Processing File");
+    }
+
+    public void testSimpleScale(){
+        expectLogContaining("testSimpleScale", "Processing File");
+        File f = createRelativeFile("/dest/" + LARGEIMAGE);
+        assertTrue(
+                   "Did not create "+f.getAbsolutePath(),
+                   f.exists());
+
+    }
+
+    public void testOverwriteTrue() {
+        expectLogContaining("testSimpleScale", "Processing File");
+        File f = createRelativeFile("/dest/" + LARGEIMAGE);
+        long lastModified = f.lastModified();
+        try {
+            Thread.sleep(FILE_UTILS
+                         .getFileTimestampGranularity());
+        }
+        catch (InterruptedException e) {}
+        expectLogContaining("testOverwriteTrue", "Processing File");
+        f = createRelativeFile("/dest/" + LARGEIMAGE);
+        long overwrittenLastModified = f.lastModified();
+        assertTrue("File was not overwritten.",
+                   lastModified < overwrittenLastModified);
+    }
+
+    public void testOverwriteFalse() {
+        expectLogContaining("testSimpleScale", "Processing File");
+        File f = createRelativeFile("/dest/" + LARGEIMAGE);
+        long lastModified = f.lastModified();
+        expectLogContaining("testOverwriteFalse", "Processing File");
+        f = createRelativeFile("/dest/" + LARGEIMAGE);
+        long overwrittenLastModified = f.lastModified();
+        assertTrue("File was overwritten.",
+                   lastModified == overwrittenLastModified);
+    }
+
+
+    public void off_testFailOnError() {
+        try {
+            expectLogContaining("testFailOnError", 
+                                "Unable to process image stream");
+        }
+        catch (RuntimeException re){
+            assertTrue("Run time exception should say "
+                       + "'Unable to process image stream'. :" 
+                       + re.toString(),
+                       re.toString()
+                       .indexOf("Unable to process image stream") > -1);
+        }
+    }
+
+
+
+    protected File createRelativeFile(String filename) {
+        if (filename.equals(".")) {
+            return getProjectDir();
+        }
+        // else
+        return new File(getProjectDir(), filename);
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTest.java
new file mode 100644
index 0000000..4e91d9c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/jdepend/JDependTest.java
@@ -0,0 +1,97 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.jdepend;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the JDepend optional task.
+ *
+ */
+public class JDependTest extends BuildFileTest {
+    public static final String RESULT_FILESET = "result";
+
+    public JDependTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(
+            "src/etc/testcases/taskdefs/optional/jdepend/jdepend.xml");
+    }
+
+    /**
+     * Test simple
+     */
+    public void testSimple() {
+        expectOutputContaining(
+            "simple", "Package: org.apache.tools.ant.util.facade");
+    }
+
+    /**
+     * Test xml
+     */
+    public void testXml() {
+        expectOutputContaining(
+            "xml", "<DependsUpon>");
+    }
+
+    /**
+     * Test fork
+     * - forked output goes to log
+     */
+    public void testFork() {
+        expectLogContaining(
+            "fork", "Package: org.apache.tools.ant.util.facade");
+    }
+
+    /**
+     * Test fork xml
+     */
+    public void testForkXml() {
+        expectLogContaining(
+            "fork-xml", "<DependsUpon>");
+    }
+
+    /**
+     * Test timeout
+     */
+    public void testTimeout() {
+        expectLogContaining(
+            "fork-timeout", "JDepend FAILED - Timed out");
+    }
+
+
+    /**
+     * Test timeout without timing out
+     */
+    public void testTimeoutNot() {
+        expectLogContaining(
+            "fork-timeout-not", "Package: org.apache.tools.ant.util.facade");
+    }
+
+    /**
+     * Assert that the given message has been outputted
+     */
+    protected void expectOutputContaining(String target, String substring) {
+        executeTarget(target);
+        assertOutputContaining(substring);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/DOMUtilTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/DOMUtilTest.java
new file mode 100644
index 0000000..8adde6a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/DOMUtilTest.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+import javax.xml.parsers.DocumentBuilder;
+
+import org.apache.tools.ant.util.JAXPUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public class DOMUtilTest extends TestCase {
+    public void testListChildNodes() throws SAXException, IOException {
+        DocumentBuilder db = JAXPUtils.getDocumentBuilder();
+        InputStream is = this.getClass().getClassLoader().getResourceAsStream("taskdefs/optional/junit/matches.xml");
+        Document doc = db.parse(is);
+        NodeList nl = DOMUtil.listChildNodes(doc.getFirstChild(), new FooNodeFilter(), true);
+        assertEquals(nl.getLength(), 3);
+    }
+    public class FooNodeFilter implements DOMUtil.NodeFilter {
+        public boolean accept(Node node) {
+            if (node.getNodeName().equals("foo")) {
+                return true;
+            }
+            return false;  //To change body of implemented methods use File | Settings | File Templates.
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitClassLoaderTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitClassLoaderTest.java
new file mode 100644
index 0000000..36f5d6e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitClassLoaderTest.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+/**
+ * Test to ensure that the classloader loading JUnit testcase
+ * is also the context classloader.
+ *
+ */
+public class JUnitClassLoaderTest extends TestCase {
+
+    public JUnitClassLoaderTest(String s) {
+        super(s);
+    }
+
+    public void testContextClassLoader(){
+        ClassLoader context = Thread.currentThread().getContextClassLoader();
+        ClassLoader caller = getClass().getClassLoader();
+        assertSame(context, caller);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java
new file mode 100644
index 0000000..d195293
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitReportTest.java
@@ -0,0 +1,206 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.net.URL;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Small testcase for the junitreporttask.
+ * First test added to reproduce an fault, still a lot to improve
+ *
+ */
+public class JUnitReportTest extends BuildFileTest {
+
+    public JUnitReportTest(String name){
+        super(name);
+    }
+
+    protected void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/junitreport.xml");
+    }
+
+    protected void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * Verifies that no empty junit-noframes.html is generated when frames
+     * output is selected via the default.
+     * Needs reports1 task from junitreport.xml.
+     */
+    public void testNoFileJUnitNoFrames() {
+        executeTarget("reports1");
+        if (new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/junit-noframes.html").exists())
+        {
+            fail("No file junit-noframes.html expected");
+        }
+    }
+
+    public void assertIndexCreated() {
+        if (!new File(System.getProperty("root"),
+                "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html").exists()) {
+            fail("No file index file found");
+        }
+
+    }
+
+    /**
+     * run a target, assert the index file is there, look for text in the log
+     * @param targetName target
+     * @param text optional text to look for
+     */
+    private void expectReportWithText(String targetName, String text) {
+        executeTarget(targetName);
+        assertIndexCreated();
+        if(text!=null) {
+            assertLogContaining(text);
+        }
+    }
+
+
+    public void testEmptyFile() throws Exception {
+        expectReportWithText("testEmptyFile",
+                XMLResultAggregator.WARNING_EMPTY_FILE);
+    }
+
+    public void testIncompleteFile() throws Exception {
+        expectReportWithText("testIncompleteFile",
+                XMLResultAggregator.WARNING_IS_POSSIBLY_CORRUPTED);
+    }
+    public void testWrongElement() throws Exception {
+        expectReportWithText("testWrongElement",
+                XMLResultAggregator.WARNING_INVALID_ROOT_ELEMENT);
+    }
+
+    // Bugzilla Report 34963
+    public void testStackTraceLineBreaks() throws Exception {
+        expectReportWithText("testStackTraceLineBreaks", null);
+        FileReader r = null;
+        try {
+            r = new FileReader(new File(System.getProperty("root"),
+                                        "src/etc/testcases/taskdefs/optional/junitreport/test/html/sampleproject/coins/0_CoinTest.html"));
+            String report = FileUtils.readFully(r);
+            assertTrue("output must contain <br>",
+                       report.indexOf("junit.framework.AssertionFailedError: DOEG<br/>")
+                   > -1);
+        } finally {
+            FileUtils.close(r);
+        }
+    }
+
+
+    // Bugzilla Report 38477
+    public void testSpecialSignsInSrcPath() throws Exception {
+        executeTarget("testSpecialSignsInSrcPath");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+
+    public void testSpecialSignsInHtmlPath() throws Exception {
+        executeTarget("testSpecialSignsInHtmlPath");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html# $%\u00A7&-!report/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+
+    //Bugzilla Report 39708
+    public void testWithStyleFromDir() throws Exception {
+        executeTarget("testWithStyleFromDir");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+
+    //Bugzilla Report 40021
+    public void testNoFrames() throws Exception {
+        executeTarget("testNoFrames");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/junit-noframes.html");
+        // tests one the file object
+        assertTrue("No junit-noframes.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+    //Bugzilla Report 39708
+    public void testWithStyleFromDirAndXslImport() throws Exception {
+        executeTarget("testWithStyleFromDirAndXslImport");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+
+    public void testWithStyleFromClasspath() throws Exception {
+        executeTarget("testWithStyleFromClasspath");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+
+    public void testWithParams() throws Exception {
+        expectLogContaining("testWithParams", "key1=value1,key2=value2");
+        File reportFile = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/optional/junitreport/test/html/index.html");
+        // tests one the file object
+        assertTrue("No index.html present. Not generated?", reportFile.exists() );
+        assertTrue("Cant read the report file.", reportFile.canRead() );
+        assertTrue("File shouldnt be empty.", reportFile.length() > 0 );
+        // conversion to URL via FileUtils like in XMLResultAggregator, not as suggested in the bug report
+        URL reportUrl = new URL( FileUtils.getFileUtils().toURI(reportFile.getAbsolutePath()) );
+        InputStream reportStream = reportUrl.openStream();
+        assertTrue("This shouldnt be an empty stream.", reportStream.available() > 0);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
new file mode 100644
index 0000000..7ec0dbb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskTest.java
@@ -0,0 +1,249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class JUnitTaskTest extends BuildFileTest {
+
+    /**
+     * Constructor for the JUnitTaskTest object.
+     */
+    public JUnitTaskTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method.
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/junit.xml");
+    }
+
+    /**
+     * The teardown method for JUnit.
+     */
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void testCrash() {
+       expectPropertySet("crash", "crashed");
+    }
+
+    public void testNoCrash() {
+       expectPropertyUnset("nocrash", "crashed");
+    }
+
+    public void testTimeout() {
+       expectPropertySet("timeout", "timeout");
+    }
+
+    public void testNoTimeout() {
+       expectPropertyUnset("notimeout", "timeout");
+    }
+
+    public void testNonForkedCapture() throws IOException {
+        executeTarget("capture");
+        assertNoPrint(getLog(), "log");
+        assertNoPrint(getFullLog(), "debug log");
+    }
+
+    public void testForkedCapture() throws IOException {
+        getProject().setProperty("fork", "true");
+        testNonForkedCapture();
+        // those would fail because of the way BuildFileTest captures output
+        assertNoPrint(getOutput(), "output");
+        assertNoPrint(getError(), "error output");
+        assertOutput();
+    }
+
+    public void testBatchTestForkOnceToDir() {
+        assertResultFilesExist("testBatchTestForkOnceToDir", ".xml");
+    }
+
+    /** Bugzilla Report 32973 */
+    public void testBatchTestForkOnceExtension() {
+        assertResultFilesExist("testBatchTestForkOnceExtension", ".foo");
+    }
+
+
+    /* Bugzilla Report 42984 */
+    //TODO This scenario works from command line, but not from JUnit ...
+    //     Running these steps from the junit.xml-directory work
+    //     $ ant -f junit.xml failureRecorder.prepare
+    //     $ ant -f junit.xml failureRecorder.runtest
+    //     $ ant -f junit.xml failureRecorder.runtest
+    //     $ ant -f junit.xml failureRecorder.fixing
+    //     $ ant -f junit.xml failureRecorder.runtest
+    //     $ ant -f junit.xml failureRecorder.runtest
+    //     But running the JUnit testcase fails in 4th run.
+    public void testFailureRecorder() {
+        File testDir = new File(getProjectDir(), "out");
+        File collectorFile = new File(getProjectDir(), "out/FailedTests.java");
+        
+        // ensure that there is a clean test environment
+        assertFalse("Test directory '" + testDir.getAbsolutePath() + "' must not exist before the test preparation.", 
+                testDir.exists());
+        assertFalse("The collector file '" + collectorFile.getAbsolutePath() + "'must not exist before the test preparation.", 
+                collectorFile.exists());
+
+        
+        // prepare the test environment
+        executeTarget("failureRecorder.prepare");
+        assertTrue("Test directory '" + testDir.getAbsolutePath() + "' was not created.", testDir.exists());
+        assertTrue("There should be one class.", (new File(testDir, "A.class")).exists());
+        assertFalse("The collector file '" + collectorFile.getAbsolutePath() 
+                + "' should not exist before the 1st run.", collectorFile.exists());
+        
+        
+        // 1st junit run: should do all tests - failing and not failing tests
+        executeTarget("failureRecorder.runtest");
+        assertTrue("The collector file '" + collectorFile.getAbsolutePath() 
+                + "' should exist after the 1st run.", collectorFile.exists());
+        // the passing test cases
+        assertOutputContaining("1st run: should run A.test01", "A.test01");
+        assertOutputContaining("1st run: should run B.test05", "B.test05");
+        assertOutputContaining("1st run: should run B.test06", "B.test06");
+        assertOutputContaining("1st run: should run C.test07", "C.test07");
+        assertOutputContaining("1st run: should run C.test08", "C.test08");
+        assertOutputContaining("1st run: should run C.test09", "C.test09");
+        // the failing test cases
+        assertOutputContaining("1st run: should run A.test02", "A.test02");
+        assertOutputContaining("1st run: should run A.test03", "A.test03");
+        assertOutputContaining("1st run: should run B.test04", "B.test04");
+        assertOutputContaining("1st run: should run D.test10", "D.test10");
+
+        
+        // 2nd junit run: should do only failing tests
+        executeTarget("failureRecorder.runtest");
+        assertTrue("The collector file '" + collectorFile.getAbsolutePath() 
+                + "' should exist after the 2nd run.", collectorFile.exists());
+        // the passing test cases
+        assertOutputNotContaining("2nd run: should not run A.test01", "A.test01");
+        assertOutputNotContaining("2nd run: should not run A.test05", "B.test05");
+        assertOutputNotContaining("2nd run: should not run B.test06", "B.test06");
+        assertOutputNotContaining("2nd run: should not run C.test07", "C.test07");
+        assertOutputNotContaining("2nd run: should not run C.test08", "C.test08");
+        assertOutputNotContaining("2nd run: should not run C.test09", "C.test09");
+        // the failing test cases
+        assertOutputContaining("2nd run: should run A.test02", "A.test02");
+        assertOutputContaining("2nd run: should run A.test03", "A.test03");
+        assertOutputContaining("2nd run: should run B.test04", "B.test04");
+        assertOutputContaining("2nd run: should run D.test10", "D.test10");
+        
+        
+        // "fix" errors in class A
+        executeTarget("failureRecorder.fixing");
+        
+        // 3rd run: four running tests with two errors
+        executeTarget("failureRecorder.runtest");
+        assertTrue("The collector file '" + collectorFile.getAbsolutePath() 
+                + "' should exist after the 3rd run.", collectorFile.exists());
+        assertOutputContaining("3rd run: should run A.test02", "A.test02");
+        assertOutputContaining("3rd run: should run A.test03", "A.test03");
+        assertOutputContaining("3rd run: should run B.test04", "B.test04");
+        assertOutputContaining("3rd run: should run D.test10", "D.test10");
+        
+        
+        // 4rd run: two running tests with errors
+        executeTarget("failureRecorder.runtest");
+        assertTrue("The collector file '" + collectorFile.getAbsolutePath() 
+                + "' should exist after the 4th run.", collectorFile.exists());
+        //TODO: these two statements fail
+        //assertOutputNotContaining("4th run: should not run A.test02", "A.test02");
+        //assertOutputNotContaining("4th run: should not run A.test03", "A.test03");
+        assertOutputContaining("4th run: should run B.test04", "B.test04");
+        assertOutputContaining("4th run: should run D.test10", "D.test10");
+    }
+
+
+    public void testBatchTestForkOnceCustomFormatter() {
+        assertResultFilesExist("testBatchTestForkOnceCustomFormatter", "foo");
+    }
+
+    private void assertResultFilesExist(String target, String extension) {
+        executeTarget(target);
+        assertResultFileExists("JUnitClassLoader", extension);
+        assertResultFileExists("JUnitTestRunner", extension);
+        assertResultFileExists("JUnitVersionHelper", extension);
+    }
+
+    private void assertResultFileExists(String classNameFragment, String ext) {
+        assertTrue("result for " + classNameFragment + "Test" + ext + " exists",
+                   getProject().resolveFile("out/TEST-org.apache.tools.ant."
+                                            + "taskdefs.optional.junit."
+                                            + classNameFragment + "Test" + ext)
+                   .exists());
+    }
+
+    private void assertNoPrint(String result, String where) {
+        assertTrue(where + " '" + result + "' must not contain print statement",
+                   result.indexOf("print to System.") == -1);
+    }
+
+    private void assertOutput() throws IOException {
+        FileReader inner = new FileReader(getProject()
+                                          .resolveFile("testlog.txt"));
+        BufferedReader reader = new BufferedReader(inner);
+        try {
+            String line = reader.readLine();
+            assertEquals("Testsuite: org.apache.tools.ant.taskdefs.optional.junit.Printer",
+                         line);
+            line = reader.readLine();
+            assertNotNull(line);
+            assertTrue(line.startsWith("Tests run: 1, Failures: 0, Errors: 0, Time elapsed:"));
+            line = reader.readLine();
+            assertEquals("------------- Standard Output ---------------",
+                         line);
+            assertPrint(reader.readLine(), "static", "out");
+            assertPrint(reader.readLine(), "constructor", "out");
+            assertPrint(reader.readLine(), "method", "out");
+            line = reader.readLine();
+            assertEquals("------------- ---------------- ---------------",
+                         line);
+            line = reader.readLine();
+            assertEquals("------------- Standard Error -----------------",
+                         line);
+            assertPrint(reader.readLine(), "static", "err");
+            assertPrint(reader.readLine(), "constructor", "err");
+            assertPrint(reader.readLine(), "method", "err");
+            line = reader.readLine();
+            assertEquals("------------- ---------------- ---------------",
+                         line);
+            line = reader.readLine();
+            assertEquals("", line);
+            line = reader.readLine();
+            assertNotNull(line);
+            assertTrue(line.startsWith("Testcase: testNoCrash took "));
+        } finally {
+            inner.close();
+        }
+    }
+
+    private void assertPrint(String line, String from, String to) {
+        String search = from + " print to System." + to;
+        assertEquals(search, line);
+    }
+
+}
\ No newline at end of file
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java
new file mode 100644
index 0000000..ac36af2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestListenerTest.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class JUnitTestListenerTest extends BuildFileTest {
+
+    // The captureToSummary test writes to stdout and stderr, good for
+    // verifying that the TestListener support doesn't break anything.
+    private static final String PASS_TEST_TARGET = "captureToSummary";
+
+    // testNoCrash is the test invoked by the captureToSummary's junit task
+    private static final String PASS_TEST = "testNoCrash";
+
+    public JUnitTestListenerTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/junit.xml");
+    }
+
+    public void testFullLogOutput() {
+        executeTarget(PASS_TEST_TARGET);
+        assertTrue("expecting full log to have BuildListener events", 
+                   hasBuildListenerEvents(getFullLog()));
+    }
+    
+    public void testNoLogOutput() {
+        executeTarget(PASS_TEST_TARGET);
+        assertFalse("expecting log to not have BuildListener events", 
+                    hasBuildListenerEvents(getLog()));
+    }
+
+    public void testTestCountFired() {
+        executeTarget(PASS_TEST_TARGET);
+	assertTrue("expecting test count message",
+		   hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + 
+				   "tests to run: "));
+    }
+    
+    public void testStartTestFired() {
+        executeTarget(PASS_TEST_TARGET);
+	assertTrue("expecting test started message",
+		   hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + 
+				   "startTest(" + PASS_TEST + ")"));
+    }
+    
+    public void testEndTestFired() {
+        executeTarget(PASS_TEST_TARGET);
+	assertTrue("expecting test ended message",
+		   hasEventMessage(JUnitTask.TESTLISTENER_PREFIX + 
+				   "endTest(" + PASS_TEST + ")"));
+    }
+    
+    private boolean hasBuildListenerEvents(String log) {
+        return log.indexOf(JUnitTask.TESTLISTENER_PREFIX) >= 0;
+    }
+
+    private boolean hasEventMessage(String eventPrefix) {
+	return getFullLog().indexOf(eventPrefix) >= 0;
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java
new file mode 100644
index 0000000..d44ebdf
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java
@@ -0,0 +1,165 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.*;
+import junit.framework.*;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Small testcase for the runner, tests are very very very basics.
+ * They must be enhanced with time.
+ *
+ */
+public class JUnitTestRunnerTest extends TestCase {
+
+    // mandatory constructor
+    public JUnitTestRunnerTest(String name){
+        super(name);
+    }
+
+    // check that having no suite generates no errors
+    public void testNoSuite(){
+        TestRunner runner = createRunner(NoSuiteTestCase.class);
+        runner.run();
+        assertEquals(runner.getFormatter().getError(), JUnitTestRunner.SUCCESS, runner.getRetCode());
+    }
+
+    // check that a suite generates no errors
+    public void testSuite(){
+        TestRunner runner = createRunner(SuiteTestCase.class);
+        runner.run();
+        assertEquals(runner.getFormatter().getError(), JUnitTestRunner.SUCCESS, runner.getRetCode());
+    }
+
+    // check that an invalid suite generates an error.
+    public void testInvalidSuite(){
+        TestRunner runner = createRunner(InvalidSuiteTestCase.class);
+        runner.run();
+        String error = runner.getFormatter().getError();
+        assertEquals(error, JUnitTestRunner.ERRORS, runner.getRetCode());
+        assertTrue(error, error.indexOf("thrown on purpose") != -1);
+    }
+
+    // check that something which is not a testcase generates no errors
+    // at first even though this is incorrect.
+    public void testNoTestCase(){
+        TestRunner runner = createRunner(NoTestCase.class);
+        runner.run();
+        // On junit3 this is a FAILURE, on junit4 this is an ERROR
+        int ret = runner.getRetCode();
+        
+        if (ret != JUnitTestRunner.FAILURES && ret != JUnitTestRunner.ERRORS) {
+            fail("Unexpected result " + ret + " from junit runner");
+        }
+        // JUnit3 test
+        //assertEquals(runner.getFormatter().getError(), JUnitTestRunner.FAILURES, runner.getRetCode());
+    }
+
+    // check that an exception in the constructor is noticed
+    public void testInvalidTestCase(){
+        TestRunner runner = createRunner(InvalidTestCase.class);
+        runner.run();
+        // On junit3 this is a FAILURE, on junit4 this is an ERROR
+        int ret = runner.getRetCode();
+        if (ret != JUnitTestRunner.FAILURES && ret != JUnitTestRunner.ERRORS) {
+            fail("Unexpected result " + ret + " from junit runner");
+        }
+        // JUNIT3 test
+        //assertEquals(error, JUnitTestRunner.FAILURES, runner.getRetCode());
+        //@fixme as of now does not report the original stacktrace.
+        //assertTrue(error, error.indexOf("thrown on purpose") != -1);
+    }
+
+    protected TestRunner createRunner(Class clazz){
+        return new TestRunner(new JUnitTest(clazz.getName()), true, true, true);
+    }
+
+    // the test runner that wrap the dummy formatter that interests us
+    private final static class TestRunner extends JUnitTestRunner {
+        private ResultFormatter formatter = new ResultFormatter();
+        TestRunner(JUnitTest test, boolean haltonerror, boolean filtertrace, boolean haltonfailure){
+            super(test, haltonerror, filtertrace,  haltonfailure, TestRunner.class.getClassLoader());
+            // use the classloader that loaded this class otherwise
+            // it will not be able to run inner classes if this test
+            // is ran in non-forked mode.
+            addFormatter(formatter);
+        }
+        ResultFormatter getFormatter(){
+            return formatter;
+        }
+    }
+
+    // dummy formatter just to catch the error
+    private final static class ResultFormatter implements JUnitResultFormatter {
+        private Throwable error;
+        public void setSystemOutput(String output){}
+        public void setSystemError(String output){}
+        public void startTestSuite(JUnitTest suite) throws BuildException{}
+        public void endTestSuite(JUnitTest suite) throws BuildException{}
+        public void setOutput(java.io.OutputStream out){}
+        public void startTest(Test t) {}
+        public void endTest(Test test) {}
+        public void addFailure(Test test, Throwable t) { }
+        public void addFailure(Test test, AssertionFailedError t) { }
+        public void addError(Test test, Throwable t) {
+            error = t;
+        }
+        String getError(){
+            if (error == null){
+                return "";
+            }
+            StringWriter sw = new StringWriter();
+            error.printStackTrace(new PrintWriter(sw));
+            return sw.toString();
+        }
+    }
+
+    public static class NoTestCase {
+    }
+
+    public static class InvalidTestCase extends TestCase {
+        public InvalidTestCase(String name){
+            super(name);
+            throw new NullPointerException("thrown on purpose");
+        }
+    }
+
+    public static class NoSuiteTestCase extends TestCase {
+        public NoSuiteTestCase(String name){ super(name); }
+        public void testA(){}
+    }
+
+    public static class SuiteTestCase extends NoSuiteTestCase {
+        public SuiteTestCase(String name){ super(name); }
+        public static Test suite(){
+            return new TestSuite(SuiteTestCase.class);
+        }
+    }
+
+    public static class InvalidSuiteTestCase extends NoSuiteTestCase {
+        public InvalidSuiteTestCase(String name){ super(name); }
+        public static Test suite(){
+            throw new NullPointerException("thrown on purpose");
+        }
+    }
+    public static void main(String[] args){
+        junit.textui.TestRunner.run(JUnitTestRunnerTest.class);
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelperTest.java
new file mode 100644
index 0000000..a23b840
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitVersionHelperTest.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+/**
+ */
+public class JUnitVersionHelperTest extends TestCase {
+
+    public JUnitVersionHelperTest(String name) {
+        super(name);
+    }
+
+    public void testMyOwnName() {
+        assertEquals("testMyOwnName",
+                     JUnitVersionHelper.getTestCaseName(this));
+    }
+
+    public void testNonTestCaseName() {
+        assertEquals("I'm a foo",
+                     JUnitVersionHelper.getTestCaseName(new Foo1()));
+    }
+
+    public void testNoStringReturn() {
+        assertEquals("unknown",
+                     JUnitVersionHelper.getTestCaseName(new Foo2()));
+    }
+
+    public void testNoGetName() {
+        assertEquals("unknown",
+                     JUnitVersionHelper.getTestCaseName(new Foo3()));
+    }
+
+    public void testNameNotGetName() {
+        assertEquals("I'm a foo, too",
+                     JUnitVersionHelper.getTestCaseName(new Foo4()));
+    }
+
+    public void testNull() {
+        assertEquals("unknown", JUnitVersionHelper.getTestCaseName(null));
+    }
+
+    public void testTestCaseSubClass() {
+        assertEquals("overridden getName",
+                     JUnitVersionHelper.getTestCaseName(new Foo5()));
+    }
+
+    public static class Foo implements Test {
+        public int countTestCases() {return 0;}
+        public void run(TestResult result) {}
+    }
+
+    public static class Foo1 extends Foo {
+        public String getName() {return "I'm a foo";}
+    }
+
+    public static class Foo2 extends Foo {
+        public int getName() {return 1;}
+    }
+
+    public static class Foo3 extends Foo {
+    }
+
+    public static class Foo4 extends Foo {
+        public String name() {return "I'm a foo, too";}
+    }
+
+    public static class Foo5 extends TestCase {
+        public String getName() {return "overridden getName";}
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/NoVmCrash.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/NoVmCrash.java
new file mode 100644
index 0000000..601eab2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/NoVmCrash.java
@@ -0,0 +1,33 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class NoVmCrash extends TestCase {
+
+    public NoVmCrash(String name) {
+        super(name);
+    }
+
+    public void testNoCrash() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Printer.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Printer.java
new file mode 100644
index 0000000..c0acc1c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Printer.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class Printer extends TestCase {
+
+    public Printer(String name) {
+        super(name);
+        System.err.println("constructor print to System.err");
+        System.out.println("constructor print to System.out");
+    }
+
+    static {
+        System.err.println("static print to System.err");
+        System.out.println("static print to System.out");
+    }
+
+    public void testNoCrash() {
+        System.err.println("method print to System.err");
+        System.out.println("method print to System.out");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Sleeper.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Sleeper.java
new file mode 100644
index 0000000..cabc763
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/Sleeper.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class Sleeper extends TestCase {
+
+    public Sleeper(String name) {
+        super(name);
+    }
+
+    public void testSleep() {
+        try {
+            Thread.sleep(5 * 1000);
+        } catch (InterruptedException e) {
+        } // end of try-catch
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/SuiteMethodTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/SuiteMethodTest.java
new file mode 100644
index 0000000..14a0966
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/SuiteMethodTest.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+/**
+ * validates that the suite() method works in classes that don't
+ * implement Test.
+ */
+public class SuiteMethodTest {
+
+    public static Test suite() {
+        return new Nested("testMethod");
+    }
+
+    public static class Nested extends TestCase {
+        public Nested(String name) {
+            super(name);
+        }
+
+        public void testMethod() {
+            assertTrue(true);
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/TestFormatter.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/TestFormatter.java
new file mode 100644
index 0000000..27420d6
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/TestFormatter.java
@@ -0,0 +1,112 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+
+public class TestFormatter implements JUnitResultFormatter {
+
+    private static final byte[] grafitto = new byte[] {
+        (byte) 'T', (byte) 'e', (byte) 's', (byte) 't', (byte) 'F', (byte) 'o',
+        (byte) 'r', (byte) 'm', (byte) 'a', (byte) 't', (byte) 't', (byte) 'e',
+        (byte) 'r', (byte) ' ', (byte) 'w', (byte) 'a', (byte) 's', (byte) ' ',
+        (byte) 'h', (byte) 'e', (byte) 'r', (byte) 'e', 10
+    };
+
+    /**
+     * Where to write the log to.
+     */
+    private OutputStream out;
+
+    /**
+     * Empty
+     */
+    public TestFormatter() {
+    }
+
+    /**
+     * Empty
+     */
+    public void startTestSuite(JUnitTest suite) {
+    }
+    /**
+     * Empty
+     */
+    public void startTest(Test t) {
+    }
+    /**
+     * Empty
+     */
+    public void endTest(Test test) {
+    }
+    /**
+     * Empty
+     */
+    public void addFailure(Test test, Throwable t) {
+    }
+    /**
+     * Empty
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+    }
+    /**
+     * Empty
+     */
+    public void addError(Test test, Throwable t) {
+    }
+    /**
+     * Empty
+     */
+    public void setSystemOutput(String out) {
+    }
+    /**
+     * Empty
+     */
+    public void setSystemError(String err) {
+    }
+
+    public void setOutput(OutputStream out) {
+        this.out = out;
+    }
+
+    public void endTestSuite(JUnitTest suite) throws BuildException {
+        if (out != null) {
+            try {
+                out.write(grafitto);
+                out.flush();
+            } catch (IOException ioex) {
+                throw new BuildException("Unable to write output", ioex);
+            } finally {
+                if (out != System.out && out != System.err) {
+                    try {
+                        out.close();
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/VmCrash.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/VmCrash.java
new file mode 100644
index 0000000..8ccf17a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/VmCrash.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class VmCrash extends TestCase {
+
+    public VmCrash(String name) {
+        super(name);
+    }
+
+    public void testCrash() {
+        System.exit(0);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/XMLFormatterWithCDATAOnSystemOut.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/XMLFormatterWithCDATAOnSystemOut.java
new file mode 100644
index 0000000..f93fb88
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/XMLFormatterWithCDATAOnSystemOut.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.junit;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+public class XMLFormatterWithCDATAOnSystemOut extends BuildFileTest {
+
+    private static String DIR = "src/etc/testcases/taskdefs/optional/junit";
+    private static String REPORT =
+        "TEST-" + XMLFormatterWithCDATAOnSystemOut.class.getName() + ".xml";
+
+    private static String TESTDATA =
+        "<ERROR>" +
+        "<![CDATA[<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+        "  <RESPONSE>" +
+        "    <GDS/>" +
+        "    <ERROR>" +
+        "      <ID/>" +
+        "      <MESSAGE/>" +
+        "      <REQUEST_TYPE/>" +
+        "      <RESEND/>" +
+        "      <RAW_RESPONSE/>" +
+        "    </ERROR>" +
+        "  </RESPONSE>" +
+        "]]>" +
+        "</ERROR>";
+
+    public XMLFormatterWithCDATAOnSystemOut(String name) {
+        super(name);
+    }
+
+    public void testOutput() {
+        System.out.println(TESTDATA);
+    }
+
+    public void testBuildfile() throws IOException {
+        configureProject(DIR + "/cdataoutput.xml");
+        if (getProject().getProperty("cdata.inner") == null) {
+            // avoid endless loop
+            executeTarget("run-junit");
+            File f = getProject().resolveFile(REPORT);
+            FileReader reader = null;
+            try {
+                reader = new FileReader(f);
+                String content = FileUtils.readFully(reader);
+                assertTrue(content.indexOf("</RESPONSE>&#x5d;&#x5d;&gt;"
+                                           + "</ERROR>") > 0);
+            } finally {
+                if (reader != null) {
+                    reader.close();
+                }
+                f.delete();
+            }
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java
new file mode 100644
index 0000000..ffe7228
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java
@@ -0,0 +1,895 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.net;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.Vector;
+
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DefaultLogger;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.RetryHandler;
+import org.apache.tools.ant.util.Retryable;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+
+public class FTPTest extends BuildFileTest{
+    // keep track of what operating systems are supported here.
+    private boolean supportsSymlinks = Os.isFamily("unix");
+
+    private FTPClient ftp;
+    private boolean connectionSucceeded = true;
+    private boolean loginSuceeded = true;
+    private String tmpDir = null;
+    private String remoteTmpDir = null;
+    private String ftpFileSep = null;
+    private myFTP myFTPTask = new myFTP();
+
+    public FTPTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/net/ftp.xml");
+        getProject().executeTarget("setup");
+        tmpDir = getProject().getProperty("tmp.dir");
+        ftp = new FTPClient();
+        ftpFileSep = getProject().getProperty("ftp.filesep");
+        myFTPTask.setSeparator(ftpFileSep);
+        myFTPTask.setProject(getProject());
+        remoteTmpDir = myFTPTask.resolveFile(tmpDir);
+        String remoteHost = getProject().getProperty("ftp.host");
+        int port = Integer.parseInt(getProject().getProperty("ftp.port"));
+        String remoteUser = getProject().getProperty("ftp.user");
+        String password = getProject().getProperty("ftp.password");
+        try {
+            ftp.connect(remoteHost, port);
+        } catch (Exception ex) {
+            connectionSucceeded = false;
+            loginSuceeded = false;
+            System.out.println("could not connect to host " + remoteHost + " on port " + port);
+        }
+        if (connectionSucceeded) {
+            try {
+                ftp.login(remoteUser, password);
+            } catch (IOException ioe) {
+                loginSuceeded = false;
+                System.out.println("could not log on to " + remoteHost + " as user " + remoteUser);
+            }
+        }
+    }
+
+    public void tearDown() {
+        try {
+            ftp.disconnect();
+        } catch (IOException ioe) {
+            // do nothing
+        }
+        getProject().executeTarget("cleanup");
+    }
+    private boolean changeRemoteDir(String remoteDir) {
+        boolean result = true;
+        try {
+            ftp.cwd(remoteDir);
+        }
+        catch (Exception ex) {
+            System.out.println("could not change directory to " + remoteTmpDir);
+            result = false;
+        }
+        return result;
+    }
+    public void test1() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir))  {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"alpha"});
+                ds.scan();
+                compareFiles(ds, new String[] {} ,new String[] {"alpha"});
+            }
+        }
+    }
+
+    public void test2() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"alpha/"});
+                ds.scan();
+                compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                               "alpha/beta/gamma/gamma.xml"},
+                    new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+            }
+        }
+    }
+
+    public void test3() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.scan();
+                compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                               "alpha/beta/gamma/gamma.xml"},
+                    new String[] {"alpha", "alpha/beta",
+                                  "alpha/beta/gamma"});
+            }
+        }
+    }
+
+    public void testFullPathMatchesCaseSensitive() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"alpha/beta/gamma/GAMMA.XML"});
+                ds.scan();
+                compareFiles(ds, new String[] {}, new String[] {});
+            }
+        }
+    }
+
+    public void testFullPathMatchesCaseInsensitive() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setCaseSensitive(false);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"alpha/beta/gamma/GAMMA.XML"});
+                ds.scan();
+                compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                    new String[] {});
+            }
+        }
+    }
+
+    public void test2ButCaseInsensitive() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"ALPHA/"});
+                ds.setCaseSensitive(false);
+                ds.scan();
+                compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                               "alpha/beta/gamma/gamma.xml"},
+                    new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+            }
+        }
+    }
+    public void test2bisButCaseInsensitive() {
+        if (loginSuceeded) {
+            if (changeRemoteDir(remoteTmpDir)) {
+                FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+                ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+                ds.setIncludes(new String[] {"alpha/BETA/gamma/"});
+                ds.setCaseSensitive(false);
+                ds.scan();
+                compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                    new String[] {"alpha/beta/gamma"});
+            }
+        }
+    }
+    public void testGetWithSelector() {
+        expectLogContaining("ftp-get-with-selector",
+            "selectors are not supported in remote filesets");
+        FileSet fsDestination = (FileSet) getProject().getReference("fileset-destination-without-selector");
+        DirectoryScanner dsDestination = fsDestination.getDirectoryScanner(getProject());
+        dsDestination.scan();
+        String [] sortedDestinationDirectories = dsDestination.getIncludedDirectories();
+        String [] sortedDestinationFiles = dsDestination.getIncludedFiles();
+        for (int counter = 0; counter < sortedDestinationDirectories.length; counter++) {
+            sortedDestinationDirectories[counter] =
+                sortedDestinationDirectories[counter].replace(File.separatorChar, '/');
+        }
+        for (int counter = 0; counter < sortedDestinationFiles.length; counter++) {
+            sortedDestinationFiles[counter] =
+                sortedDestinationFiles[counter].replace(File.separatorChar, '/');
+        }
+        FileSet fsSource =  (FileSet) getProject().getReference("fileset-source-without-selector");
+        DirectoryScanner dsSource = fsSource.getDirectoryScanner(getProject());
+        dsSource.scan();
+        compareFiles(dsSource, sortedDestinationFiles, sortedDestinationDirectories);
+    }
+    public void testGetFollowSymlinksTrue() {
+        if (!supportsSymlinks) {
+            return;
+        }
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("ftp-get-directory-symbolic-link");
+        FileSet fsDestination = (FileSet) getProject().getReference("fileset-destination-without-selector");
+        DirectoryScanner dsDestination = fsDestination.getDirectoryScanner(getProject());
+        dsDestination.scan();
+        compareFiles(dsDestination, new String[] {"alpha/beta/gamma/gamma.xml"},
+            new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+    public void testGetFollowSymlinksFalse() {
+        if (!supportsSymlinks) {
+            return;
+        }
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("ftp-get-directory-no-symbolic-link");
+        FileSet fsDestination = (FileSet) getProject().getReference("fileset-destination-without-selector");
+        DirectoryScanner dsDestination = fsDestination.getDirectoryScanner(getProject());
+        dsDestination.scan();
+        compareFiles(dsDestination, new String[] {},
+            new String[] {});
+    }
+    public void testAllowSymlinks() {
+        if (!supportsSymlinks) {
+            return;
+        }
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("symlink-setup");
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/"});
+        ds.setFollowSymlinks(true);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha/beta/gamma"});
+    }
+
+    public void testProhibitSymlinks() {
+        if (!supportsSymlinks) {
+            return;
+        }
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("symlink-setup");
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/"});
+        ds.setFollowSymlinks(false);
+        ds.scan();
+        compareFiles(ds, new String[] {}, new String[] {});
+    }
+    public void testFileSymlink() {
+        if (!supportsSymlinks) {
+            return;
+        }
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("symlink-file-setup");
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/"});
+        ds.setFollowSymlinks(true);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha/beta/gamma"});
+    }
+    // father and child pattern test
+    public void testOrderOfIncludePatternsIrrelevant() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        String [] expectedFiles = {"alpha/beta/beta.xml",
+                                   "alpha/beta/gamma/gamma.xml"};
+        String [] expectedDirectories = {"alpha/beta", "alpha/beta/gamma" };
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/be?a/**", "alpha/beta/gamma/"});
+        ds.scan();
+        compareFiles(ds, expectedFiles, expectedDirectories);
+        // redo the test, but the 2 include patterns are inverted
+        ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/beta/gamma/", "alpha/be?a/**"});
+        ds.scan();
+        compareFiles(ds, expectedFiles, expectedDirectories);
+    }
+
+    public void testPatternsDifferInCaseScanningSensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testPatternsDifferInCaseScanningInsensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/"});
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testFullpathDiffersInCaseScanningSensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/beta/gamma/gamma.xml",
+            "alpha/beta/gamma/GAMMA.XML"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+
+    public void testFullpathDiffersInCaseScanningInsensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/beta/gamma/gamma.xml",
+            "alpha/beta/gamma/GAMMA.XML"
+        });
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+
+    public void testParentDiffersInCaseScanningSensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/beta/"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testParentDiffersInCaseScanningInsensitive() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {"alpha/", "ALPHA/beta/"});
+        ds.setCaseSensitive(false);
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml"},
+                     new String[] {"alpha", "alpha/beta", "alpha/beta/gamma"});
+    }
+
+    public void testExcludeOneFile() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "**/*.xml"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/beta/b*xml"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/gamma/gamma.xml"},
+                     new String[] {});
+    }
+    public void testExcludeHasPrecedence() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/**"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {});
+
+    }
+    public void testAlternateIncludeExclude() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setIncludes(new String[] {
+            "alpha/**",
+            "alpha/beta/gamma/**"
+        });
+        ds.setExcludes(new String[] {
+            "alpha/beta/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {"alpha"});
+
+    }
+    public void testAlternateExcludeInclude() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {
+            "alpha/**",
+            "alpha/beta/gamma/**"
+        });
+        ds.setIncludes(new String[] {
+            "alpha/beta/**"
+        });
+        ds.scan();
+        compareFiles(ds, new String[] {},
+                     new String[] {});
+
+    }
+    /**
+     * Test inspired by Bug#1415.
+     */
+    public void testChildrenOfExcludedDirectory() {
+        if (!loginSuceeded) {
+            return;
+        }
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        getProject().executeTarget("children-of-excluded-dir-setup");
+        FTP.FTPDirectoryScanner ds = myFTPTask.newScanner(ftp);
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {"alpha/**"});
+        ds.scan();
+        compareFiles(ds, new String[] {"delta/delta.xml"},
+                    new String[] {"delta"});
+
+        ds = myFTPTask.newScanner(ftp);
+        if (!changeRemoteDir(remoteTmpDir)) {
+            return;
+        }
+        ds.setBasedir(new File(getProject().getBaseDir(), "tmp"));
+        ds.setExcludes(new String[] {"alpha"});
+        ds.scan();
+        compareFiles(ds, new String[] {"alpha/beta/beta.xml",
+                                       "alpha/beta/gamma/gamma.xml",
+                                        "delta/delta.xml"},
+                     new String[] {"alpha/beta", "alpha/beta/gamma", "delta"});
+
+    }
+    
+    /**
+     * This class enables the use of the log messages as a way of testing 
+     * the number of files actually transferred.
+     * It uses the ant regular expression mechanism to get a regex parser
+     * to parse the log output.
+     */
+    private class CountLogListener extends DefaultLogger {
+        private Vector lastMatchGroups = null;
+        private RegexpMatcher matcher = new RegexpMatcherFactory().newRegexpMatcher();
+
+        /**
+         * The only constructor for a CountLogListener
+         * @param pattern a regular expression pattern.  It should have 
+         * one parenthesized group and that group should contain the
+         * number desired.
+         */
+        public CountLogListener(String pattern) {
+            super();
+            this.matcher.setPattern(pattern);
+        }
+        
+        
+        /* 
+         * @param event the build event that is being logged.
+         */
+        public void messageLogged(BuildEvent event) {
+            String message = event.getMessage();
+            if (this.matcher.matches(message)) {
+                lastMatchGroups = this.matcher.getGroups(message);
+            }
+            super.messageLogged(event);
+        }
+        
+        /**
+         * returns the desired number that results from parsing the log
+         * message
+         * @return the number of files indicated in the desired message or -1
+         * if a matching log message was never found.
+         */
+        public int getCount() {
+            if (this.lastMatchGroups == null) {
+                return -1;
+            }
+            return Integer.parseInt((String) this.lastMatchGroups.get(1));
+        }
+    }
+    
+    /**
+     * This class enables the use of the log to count the number
+     * of times a message has been emitted.
+     */
+    private class LogCounter extends DefaultLogger {
+        private Map searchMap = new HashMap();
+        private int matchCount;
+
+        public void addLogMessageToSearch(String message) {
+            searchMap.put(message, new Integer(0));
+        }
+        
+        /* 
+         * @param event the build event that is being logged.
+         */
+        public void messageLogged(BuildEvent event) {
+            String message = event.getMessage();
+            Integer mcnt = (Integer) searchMap.get(message);
+            if (null != mcnt) {
+                searchMap.put(message, new Integer(mcnt.intValue() + 1));
+            }
+            super.messageLogged(event);
+        }
+        
+        /**
+         * @return the number of times that the looked for message was sent 
+         * to the log
+         */
+        public int getMatchCount(String message) {
+            Integer mcnt = (Integer) searchMap.get(message);
+            if (null != mcnt) {
+                return mcnt.intValue();
+            }
+            return 0;
+        }
+    }
+    /**
+     * Tests the combination of the newer parameter and the 
+     * serverTimezoneConfig  parameter in the PUT action.  The default 
+     * configuration is an ftp server on localhost which formats 
+     * timestamps as GMT.
+     */
+    public void testTimezonePut() {
+        CountLogListener log = new CountLogListener("(\\d+) files? sent");
+        getProject().executeTarget("timed.test.setup");
+        getProject().addBuildListener(log);
+        getProject().executeTarget("timed.test.put.older");
+        assertEquals(1, log.getCount());
+    }
+
+    /**
+     * Tests the combination of the newer parameter and the 
+     * serverTimezoneConfig  parameter in the GET action.  The default 
+     * configuration is an ftp server on localhost which formats 
+     * timestamps as GMT.
+     */
+    public void testTimezoneGet() {
+        CountLogListener log = new CountLogListener("(\\d+) files? retrieved");
+        getProject().executeTarget("timed.test.setup");
+        getProject().addBuildListener(log);
+        getProject().executeTarget("timed.test.get.older");
+        assertEquals(3, log.getCount());
+    }
+   
+    
+    /**
+     * Tests that the presence of one of the server config params forces
+     * the system type to Unix if not specified.
+     */
+    public void testConfiguration1() {
+        int[] expectedCounts = {
+                1,1,0,1,0,0,0
+        };
+        performConfigTest("configuration.1", expectedCounts);
+        
+    }
+
+    /**
+     * Tests the systemTypeKey attribute.
+     */
+    public void testConfiguration2() {
+        int[] expectedCounts = {
+                1,0,0,1,1,0,0
+        };
+        performConfigTest("configuration.2", expectedCounts);
+        
+    }
+
+    /**
+     * Tests the systemTypeKey attribute with UNIX specified.
+     */
+    public void testConfiguration3() {
+        int[] expectedCounts = {
+                1,0,1,0,0,1,0
+        };
+        performConfigTest("configuration.3", expectedCounts);
+        
+    }
+    
+    public void testConfigurationLang() {
+        int[] expectedCounts = {
+                1,1,0,0,0,0,1
+        };
+        performConfigTest("configuration.lang.good", expectedCounts);
+        
+        try {
+            performConfigTest("configuration.lang.bad", expectedCounts);
+            fail("BuildException Expected");
+        } catch (Exception bx) {
+            assertTrue(bx instanceof BuildException); 
+        }
+    }
+    /**
+     * Tests the systemTypeKey attribute.
+     */
+    public void testConfigurationNone() {
+        int[] expectedCounts = {
+                0,0,0,0,0,0,0
+        };
+        performConfigTest("configuration.none", expectedCounts);
+ 
+    }
+    
+    private void performConfigTest(String target, int[] expectedCounts) {
+        String[] messages = new String[]{
+                "custom configuration",
+                "custom config: system key = default (UNIX)",
+                "custom config: system key = UNIX",
+                "custom config: server time zone ID = " + getProject().getProperty("ftp.server.timezone"),
+                "custom config: system key = WINDOWS",
+                "custom config: default date format = yyyy/MM/dd HH:mm",
+                "custom config: server language code = de" 
+
+        };
+        LogCounter counter = new LogCounter();
+        for (int i=0; i < messages.length; i++) {
+            counter.addLogMessageToSearch(messages[i]);
+        }
+            
+        getProject().addBuildListener(counter);
+        getProject().executeTarget(target);
+        for (int i=0; i < messages.length; i++) {
+            assertEquals("target "+target+":message "+ i, expectedCounts[i], counter.getMatchCount(messages[i]));
+        }
+        
+    }
+
+    
+    /**
+     *  this test is inspired by a user reporting that deletions of directories with the ftp task do not work
+     */
+    public void testFTPDelete() {
+        getProject().executeTarget("ftp-delete");
+    }
+    private void compareFiles(DirectoryScanner ds, String[] expectedFiles,
+                              String[] expectedDirectories) {
+        String includedFiles[] = ds.getIncludedFiles();
+        String includedDirectories[] = ds.getIncludedDirectories();
+        assertEquals("file present: ", expectedFiles.length,
+                     includedFiles.length);
+        assertEquals("directories present: ", expectedDirectories.length,
+                     includedDirectories.length);
+
+        for (int counter=0; counter < includedFiles.length; counter++) {
+            includedFiles[counter] = includedFiles[counter].replace(File.separatorChar, '/');
+        }
+        Arrays.sort(includedFiles);
+        for (int counter=0; counter < includedDirectories.length; counter++) {
+            includedDirectories[counter] = includedDirectories[counter]
+                            .replace(File.separatorChar, '/');
+        }
+        Arrays.sort(includedDirectories);
+        for (int counter=0; counter < includedFiles.length; counter++) {
+            assertEquals(expectedFiles[counter], includedFiles[counter]);
+        }
+        for (int counter=0; counter < includedDirectories.length; counter++) {
+            assertEquals(expectedDirectories[counter], includedDirectories[counter]);
+            counter++;
+        }
+    }
+    private static class myFTP extends FTP {
+        public FTP.FTPDirectoryScanner newScanner(FTPClient client) {
+            return new FTP.FTPDirectoryScanner(client);
+        }
+        // provide public visibility
+        public String resolveFile(String file) {
+            return super.resolveFile(file);
+        }
+    }
+
+
+    public abstract static class myRetryableFTP extends FTP {
+        private final int numberOfFailuresToSimulate;
+        private int simulatedFailuresLeft;
+        
+        protected myRetryableFTP(int numberOfFailuresToSimulate) {
+            this.numberOfFailuresToSimulate = numberOfFailuresToSimulate;
+            this.simulatedFailuresLeft = numberOfFailuresToSimulate;
+        }
+
+        protected void getFile(FTPClient ftp, String dir, String filename)
+                throws IOException, BuildException 
+        {
+            if (this.simulatedFailuresLeft > 0) {
+                this.simulatedFailuresLeft--;
+                throw new IOException("Simulated failure for testing");
+            }
+           super.getFile(ftp, dir, filename);
+        }
+        protected void executeRetryable(RetryHandler h, Retryable r,
+                String filename) throws IOException 
+        {
+            this.simulatedFailuresLeft = this.numberOfFailuresToSimulate;    
+            super.executeRetryable(h, r, filename);
+        }
+    }
+    public static class oneFailureFTP extends myRetryableFTP {
+        public oneFailureFTP() {
+            super(1);
+        }
+    }
+    public static class twoFailureFTP extends myRetryableFTP {
+        public twoFailureFTP() {
+            super(2);
+        }
+    }
+    public static class threeFailureFTP extends myRetryableFTP {
+        public threeFailureFTP() {
+            super(3);
+        }
+    }
+    
+    public static class randomFailureFTP extends myRetryableFTP {
+        public randomFailureFTP() {
+            super(new Random().nextInt(Short.MAX_VALUE));
+        }
+    }
+    public void testGetWithSelectorRetryable1() {
+        getProject().addTaskDefinition("ftp", oneFailureFTP.class);
+        try {
+            getProject().executeTarget("ftp-get-with-selector-retryable");
+        } catch (BuildException bx) {
+            fail("Two retries expected, failed after one.");
+        }
+    }
+    public void testGetWithSelectorRetryable2() {
+        getProject().addTaskDefinition("ftp", twoFailureFTP.class);
+        try {
+            getProject().executeTarget("ftp-get-with-selector-retryable");
+        } catch (BuildException bx) {
+            fail("Two retries expected, failed after two.");
+        }
+    }
+    
+    public void testGetWithSelectorRetryable3() {
+        getProject().addTaskDefinition("ftp", threeFailureFTP.class);
+        try {
+            getProject().executeTarget("ftp-get-with-selector-retryable");
+            fail("Two retries expected, continued after two.");
+        } catch (BuildException bx) {
+        }
+    }
+    public void testGetWithSelectorRetryableRandom() {
+        getProject().addTaskDefinition("ftp", randomFailureFTP.class);
+        try {
+            getProject().setProperty("ftp.retries", "forever");
+            getProject().executeTarget("ftp-get-with-selector-retryable");
+        } catch (BuildException bx) {
+            fail("Retry forever specified, but failed.");
+        }
+    }
+    
+    public void testInitialCommand() {
+        performCommandTest("test-initial-command", new int[] { 1,0 });
+    }
+    public void testSiteAction() {
+        performCommandTest("test-site-action", new int[] { 1,0 });
+    }
+    
+    private void performCommandTest(String target, int[] expectedCounts) {
+        String[] messages = new String[]{
+                "Doing Site Command: umask 222",
+                "Failed to issue Site Command: umask 222",
+
+        };
+        LogCounter counter = new LogCounter();
+        for (int i=0; i < messages.length; i++) {
+            counter.addLogMessageToSearch(messages[i]);
+        }
+            
+        getProject().addBuildListener(counter);
+        getProject().executeTarget(target);
+        for (int i=0; i < messages.length; i++) {
+            assertEquals("target "+target+":message "+ i, expectedCounts[i], counter.getMatchCount(messages[i]));
+        }
+
+    }
+    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/P4ChangeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/P4ChangeTest.java
new file mode 100644
index 0000000..0a44ae8
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/P4ChangeTest.java
@@ -0,0 +1,52 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.perforce;
+
+import junit.framework.TestCase;
+import org.apache.oro.text.perl.Perl5Util;
+
+/**
+ * Basic testcase to ensure that backslashing is OK.
+ */
+public class P4ChangeTest extends TestCase {
+
+    protected P4Change p4change;
+
+    public P4ChangeTest(String s) {
+        super(s);
+    }
+
+    protected void setUp() throws Exception {
+        p4change = new P4Change();
+    }
+
+    public void testBackslash(){
+        String input = "comment with a / inside";
+        String output = P4Change.backslash(input);
+        assertEquals("comment with a \\/ inside", output);
+    }
+
+    public void testSubstitute(){
+        Perl5Util util = new Perl5Util();
+        String tosubstitute = "xx<here>xx";
+        String input = P4Change.backslash("/a/b/c/");
+        String output = util.substitute("s/<here>/" + input + "/", tosubstitute);
+        assertEquals("xx/a/b/c/xx", output);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/p4integrate.xml b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/p4integrate.xml
new file mode 100644
index 0000000..40e0d96
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/perforce/p4integrate.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- author Antoine Levy-Lambert levylambert@tiscali-dsl.de -->
+<!-- this test demonstrates p4integrate -->
+<project name="integrate" default= "testintegrate">
+  <property name="second_client" value="levyant_cygwin_test"/>
+  <property name="second_client_root" value="C:\dev\test"/>
+  <property name="depot_file_spec" value="//depot/foobar"/>
+  <property name="depot_file_spec_2" value="//depot/hello"/>
+  <target name="testintegrate">
+    <p4change client="${second_client}"/>
+    <property name="change1" value="${p4.change}" />
+    <p4integrate client="${second_client}" change="${p4.change}" fromfile="${depot_file_spec}" tofile="${depot_file_spec_2}" forceintegrate="true" />
+    <p4resolve  client="${second_client}" view="${depot_file_spec_2}" resolvemode="theirs"/>
+    <p4submit client="${second_client}" change="${p4.change}"/>
+  </target>
+</project>
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/script/ScriptDefTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/script/ScriptDefTest.java
new file mode 100644
index 0000000..07cb1eb
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/script/ScriptDefTest.java
@@ -0,0 +1,117 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.script;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import java.io.File;
+
+/**
+ * Tests the examples of the &lt;scriptdef&gt; task.
+ *
+ * @since Ant 1.6
+ */
+public class ScriptDefTest extends BuildFileTest {
+
+    public ScriptDefTest(String name) {
+        super(name);
+    }
+
+    /**
+     * The JUnit setup method
+     */
+    public void setUp() {
+        configureProject("src/etc/testcases/taskdefs/optional/script/scriptdef.xml");
+    }
+
+    public void testSimple() {
+        executeTarget("simple");
+        // get the fileset and its basedir
+        Project p = getProject();
+        FileSet fileset = (FileSet) p.getReference("testfileset");
+        File baseDir = fileset.getDir(p);
+        String log = getLog();
+        assertTrue("Expecting attribute value printed",
+            log.indexOf("Attribute attr1 = test") != -1);
+
+        assertTrue("Expecting nested element value printed",
+            log.indexOf("Fileset basedir = " + baseDir.getAbsolutePath()) != -1);
+    }
+
+    public void testNoLang() {
+        expectBuildExceptionContaining("nolang",
+            "Absence of language attribute not detected",
+            "requires a language attribute");
+    }
+
+    public void testNoName() {
+        expectBuildExceptionContaining("noname",
+            "Absence of name attribute not detected",
+            "scriptdef requires a name attribute");
+    }
+
+    public void testNestedByClassName() {
+        executeTarget("nestedbyclassname");
+        // get the fileset and its basedir
+        Project p = getProject();
+        FileSet fileset = (FileSet) p.getReference("testfileset");
+        File baseDir = fileset.getDir(p);
+        String log = getLog();
+        assertTrue("Expecting attribute value to be printed",
+            log.indexOf("Attribute attr1 = test") != -1);
+
+        assertTrue("Expecting nested element value to be printed",
+            log.indexOf("Fileset basedir = " + baseDir.getAbsolutePath()) != -1);
+    }
+
+    public void testNoElement() {
+        expectOutput("noelement", "Attribute attr1 = test");
+    }
+
+    public void testException() {
+        expectBuildExceptionContaining("exception",
+            "Should have thrown an exception in the script",
+            "TypeError");
+    }
+
+    public void testDoubleDef() {
+        executeTarget("doubledef");
+        String log = getLog();
+        assertTrue("Task1 did not execute",
+            log.indexOf("Task1") != -1);
+        assertTrue("Task2 did not execute",
+            log.indexOf("Task2") != -1);
+    }
+
+    public void testDoubleAttribute() {
+        expectBuildExceptionContaining("doubleAttributeDef",
+            "Should have detected duplicate attribute definition",
+            "attr1 attribute more than once");
+    }
+
+    public void testProperty() {
+        executeTarget("property");
+        // get the fileset and its basedir
+        String log = getLog();
+        assertTrue("Expecting property in attribute value replaced",
+            log.indexOf("Attribute value = test") != -1);
+    }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/sos/SOSTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/sos/SOSTest.java
new file mode 100644
index 0000000..d36de00
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/sos/SOSTest.java
@@ -0,0 +1,336 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.sos;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ *  Testcase to ensure that command line generation and required attributes are
+ *  correct.
+ *
+ */
+public class SOSTest extends BuildFileTest {
+
+    private Commandline commandline;
+
+    private static final String VSS_SERVER_PATH = "\\\\server\\vss\\srcsafe.ini";
+    private static final String VSS_PROJECT_PATH = "/SourceRoot/Project";
+    private static final String DS_VSS_PROJECT_PATH = "$/SourceRoot/Project";
+    private static final String SOS_SERVER_PATH = "192.168.0.1:8888";
+    private static final String SOS_USERNAME = "ant";
+    private static final String SOS_PASSWORD = "rocks";
+    private static final String LOCAL_PATH = "testdir";
+    private static final String SRC_FILE = "Class1.java";
+    private static final String SRC_LABEL = "label1";
+    private static final String SRC_COMMENT = "I fixed a bug";
+    private static final String SOS_HOME = "/home/user/.sos";
+    private static final String VERSION = "007";
+
+    /**
+     *  Constructor for the SOSTest object
+     *
+     * @param  s  Test name
+     */
+    public SOSTest(String s) {
+        super(s);
+    }
+
+    /**
+     *  The JUnit setup method
+     *
+     * @throws  Exception
+     */
+    protected void setUp()
+        throws Exception {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    /**
+     *  The teardown method for JUnit
+     *
+     * @throws  Exception
+     */
+    protected void tearDown()
+        throws Exception {
+        File file = new File(project.getBaseDir(), LOCAL_PATH);
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    /**  Test SOSGetFile flags & commandline generation  */
+    public void testGetFileFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "GetFile", "-file",
+                SRC_FILE, "-revision", "007", "-server", SOS_SERVER_PATH, "-name",
+                SOS_USERNAME, "-password", SOS_PASSWORD, "-database", VSS_SERVER_PATH,
+                "-project", DS_VSS_PROJECT_PATH, "-verbose", "-nocompress",
+                "-nocache", "-workdir", project.getBaseDir().getAbsolutePath()
+                 + File.separator + LOCAL_PATH};
+
+        // Set up a SOSGet task
+        SOSGet sosGet = new SOSGet();
+        sosGet.setProject(project);
+        sosGet.setVssServerPath(VSS_SERVER_PATH);
+        sosGet.setSosServerPath(SOS_SERVER_PATH);
+        sosGet.setProjectPath(VSS_PROJECT_PATH);
+        sosGet.setFile(SRC_FILE);
+        sosGet.setUsername(SOS_USERNAME);
+        sosGet.setPassword(SOS_PASSWORD);
+        sosGet.setVersion(VERSION);
+        sosGet.setLocalPath(new Path(project, LOCAL_PATH));
+        sosGet.setNoCache(true);
+        sosGet.setNoCompress(true);
+        sosGet.setVerbose(true);
+        sosGet.setRecursive(true);
+
+        commandline = sosGet.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test SOSGetProject flags & commandline generation  */
+    public void testGetProjectFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "GetProject", "-recursive",
+                "-label", SRC_LABEL, "-server", SOS_SERVER_PATH, "-name", SOS_USERNAME,
+                "-password", "", "-database", VSS_SERVER_PATH, "-project",
+                DS_VSS_PROJECT_PATH, "", "", "-soshome", SOS_HOME, "-workdir",
+                project.getBaseDir().getAbsolutePath()};
+
+        // Set up a SOSGet task
+        SOSGet sosGet = new SOSGet();
+        sosGet.setProject(project);
+        sosGet.setVssServerPath(VSS_SERVER_PATH);
+        sosGet.setSosServerPath(SOS_SERVER_PATH);
+        sosGet.setProjectPath(DS_VSS_PROJECT_PATH);
+        sosGet.setLabel(SRC_LABEL);
+        sosGet.setUsername(SOS_USERNAME);
+        sosGet.setSosHome(SOS_HOME);
+        sosGet.setNoCache(true);
+        sosGet.setNoCompress(false);
+        sosGet.setVerbose(false);
+        sosGet.setRecursive(true);
+
+        commandline = sosGet.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Tests SOSGet required attributes.  */
+    public void testGetExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/sos/sos.xml");
+        expectSpecificBuildException("sosget.1", "some cause", "sosserverpath attribute must be set!");
+        expectSpecificBuildException("sosget.2", "some cause", "username attribute must be set!");
+        expectSpecificBuildException("sosget.3", "some cause", "vssserverpath attribute must be set!");
+        expectSpecificBuildException("sosget.4", "some cause", "projectpath attribute must be set!");
+    }
+
+    /**  Test CheckInFile option flags  */
+    public void testCheckinFileFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "CheckInFile", "-file",
+                SRC_FILE, "-server", SOS_SERVER_PATH, "-name", SOS_USERNAME,
+                "-password", SOS_PASSWORD, "-database", VSS_SERVER_PATH, "-project",
+                DS_VSS_PROJECT_PATH, "-verbose", "-nocompress", "-nocache",
+                "-workdir", project.getBaseDir().getAbsolutePath() + File.separator
+                 + LOCAL_PATH, "-log", SRC_COMMENT};
+
+        // Set up a SOSCheckin task
+        SOSCheckin sosCheckin = new SOSCheckin();
+        sosCheckin.setProject(project);
+        sosCheckin.setVssServerPath(VSS_SERVER_PATH);
+        sosCheckin.setSosServerPath(SOS_SERVER_PATH);
+        sosCheckin.setProjectPath(VSS_PROJECT_PATH);
+        sosCheckin.setFile(SRC_FILE);
+        sosCheckin.setComment(SRC_COMMENT);
+        sosCheckin.setUsername(SOS_USERNAME);
+        sosCheckin.setPassword(SOS_PASSWORD);
+        sosCheckin.setLocalPath(new Path(project, LOCAL_PATH));
+        sosCheckin.setNoCache(true);
+        sosCheckin.setNoCompress(true);
+        sosCheckin.setVerbose(true);
+        sosCheckin.setRecursive(true);
+
+        commandline = sosCheckin.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test CheckInProject option flags  */
+    public void testCheckinProjectFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "CheckInProject",
+                "-recursive", "-server", SOS_SERVER_PATH, "-name", SOS_USERNAME,
+                "-password", "", "-database", VSS_SERVER_PATH, "-project",
+                DS_VSS_PROJECT_PATH, "", "", "-soshome", SOS_HOME, "-workdir",
+                project.getBaseDir().getAbsolutePath(), "-log", SRC_COMMENT,};
+
+        // Set up a SOSCheckin task
+        SOSCheckin sosCheckin = new SOSCheckin();
+        sosCheckin.setProject(project);
+        sosCheckin.setVssServerPath(VSS_SERVER_PATH);
+        sosCheckin.setSosServerPath(SOS_SERVER_PATH);
+        sosCheckin.setProjectPath(DS_VSS_PROJECT_PATH);
+        sosCheckin.setComment(SRC_COMMENT);
+        sosCheckin.setUsername(SOS_USERNAME);
+        sosCheckin.setSosHome(SOS_HOME);
+        sosCheckin.setNoCache(true);
+        sosCheckin.setNoCompress(false);
+        sosCheckin.setVerbose(false);
+        sosCheckin.setRecursive(true);
+
+        commandline = sosCheckin.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test SOSCheckIn required attributes.  */
+    public void testCheckinExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/sos/sos.xml");
+        expectSpecificBuildException("soscheckin.1", "some cause", "sosserverpath attribute must be set!");
+        expectSpecificBuildException("soscheckin.2", "some cause", "username attribute must be set!");
+        expectSpecificBuildException("soscheckin.3", "some cause", "vssserverpath attribute must be set!");
+        expectSpecificBuildException("soscheckin.4", "some cause", "projectpath attribute must be set!");
+    }
+
+    /**  Test CheckOutFile option flags  */
+    public void testCheckoutFileFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "CheckOutFile", "-file",
+                SRC_FILE, "-server", SOS_SERVER_PATH, "-name", SOS_USERNAME,
+                "-password", SOS_PASSWORD, "-database", VSS_SERVER_PATH, "-project",
+                DS_VSS_PROJECT_PATH, "-verbose", "-nocompress", "-nocache",
+                "-workdir", project.getBaseDir().getAbsolutePath()
+                 + File.separator + LOCAL_PATH};
+
+        // Set up a SOSCheckout task
+        SOSCheckout sosCheckout = new SOSCheckout();
+        sosCheckout.setProject(project);
+        sosCheckout.setVssServerPath(VSS_SERVER_PATH);
+        sosCheckout.setSosServerPath(SOS_SERVER_PATH);
+        sosCheckout.setProjectPath(DS_VSS_PROJECT_PATH);
+        sosCheckout.setFile(SRC_FILE);
+        sosCheckout.setUsername(SOS_USERNAME);
+        sosCheckout.setPassword(SOS_PASSWORD);
+        sosCheckout.setLocalPath(new Path(project, LOCAL_PATH));
+        sosCheckout.setNoCache(true);
+        sosCheckout.setNoCompress(true);
+        sosCheckout.setVerbose(true);
+        sosCheckout.setRecursive(true);
+
+        commandline = sosCheckout.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test CheckOutProject option flags  */
+    public void testCheckoutProjectFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "CheckOutProject",
+                "-recursive", "-server", SOS_SERVER_PATH, "-name", SOS_USERNAME,
+                "-password", "", "-database", VSS_SERVER_PATH, "-project",
+                DS_VSS_PROJECT_PATH, "", "", "-soshome", SOS_HOME, "-workdir",
+                project.getBaseDir().getAbsolutePath()};
+
+        // Set up a sosCheckout task
+        SOSCheckout sosCheckout = new SOSCheckout();
+        sosCheckout.setProject(project);
+        sosCheckout.setVssServerPath(VSS_SERVER_PATH);
+        sosCheckout.setSosServerPath(SOS_SERVER_PATH);
+        sosCheckout.setProjectPath(VSS_PROJECT_PATH);
+        sosCheckout.setUsername(SOS_USERNAME);
+        sosCheckout.setSosHome(SOS_HOME);
+        sosCheckout.setNoCache(true);
+        sosCheckout.setNoCompress(false);
+        sosCheckout.setVerbose(false);
+        sosCheckout.setRecursive(true);
+
+        commandline = sosCheckout.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test SOSCheckout required attributes.  */
+    public void testCheckoutExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/sos/sos.xml");
+        expectSpecificBuildException("soscheckout.1", "some cause", "sosserverpath attribute must be set!");
+        expectSpecificBuildException("soscheckout.2", "some cause", "username attribute must be set!");
+        expectSpecificBuildException("soscheckout.3", "some cause", "vssserverpath attribute must be set!");
+        expectSpecificBuildException("soscheckout.4", "some cause", "projectpath attribute must be set!");
+    }
+
+    /**  Test Label option flags  */
+    public void testLabelFlags() {
+        String[] sTestCmdLine = {"soscmd", "-command", "AddLabel", "-server",
+                SOS_SERVER_PATH, "-name", SOS_USERNAME, "-password", "", "-database",
+                VSS_SERVER_PATH, "-project", DS_VSS_PROJECT_PATH, "-label",
+                SRC_LABEL, "-verbose", "-log", SRC_COMMENT};
+
+        // Set up a sosCheckout task
+        SOSLabel sosLabel = new SOSLabel();
+        sosLabel.setVssServerPath(VSS_SERVER_PATH);
+        sosLabel.setSosServerPath(SOS_SERVER_PATH);
+        sosLabel.setProjectPath(DS_VSS_PROJECT_PATH);
+        sosLabel.setUsername(SOS_USERNAME);
+        sosLabel.setSosHome(SOS_HOME);
+        sosLabel.setComment(SRC_COMMENT);
+        sosLabel.setLabel(SRC_LABEL);
+        sosLabel.setNoCache(true);
+        sosLabel.setNoCompress(false);
+        sosLabel.setVerbose(true);
+
+        commandline = sosLabel.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Test SOSLabel required attributes.  */
+    public void testLabelExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/sos/sos.xml");
+        expectSpecificBuildException("soslabel.1", "some cause", "sosserverpath attribute must be set!");
+        expectSpecificBuildException("soslabel.2", "some cause", "username attribute must be set!");
+        expectSpecificBuildException("soslabel.3", "some cause", "vssserverpath attribute must be set!");
+        expectSpecificBuildException("soslabel.4", "some cause", "projectpath attribute must be set!");
+        expectSpecificBuildException("soslabel.5", "some cause", "label attribute must be set!");
+    }
+
+    /**
+     *  Iterate through the generated command line comparing it to reference
+     *  one.
+     *
+     * @param  sTestCmdLine       The reference command line;
+     * @param  sGeneratedCmdLine  The generated command line;
+     */
+    private void checkCommandLines(String[] sTestCmdLine, String[] sGeneratedCmdLine) {
+        int length = sTestCmdLine.length;
+        for (int i = 0; i < length; i++) {
+            try {
+                assertEquals("arg # " + String.valueOf(i),
+                        sTestCmdLine[i],
+                        sGeneratedCmdLine[i]);
+            } catch (ArrayIndexOutOfBoundsException aioob) {
+                fail("missing arg " + sTestCmdLine[i]);
+            }
+        }
+        if (sGeneratedCmdLine.length > sTestCmdLine.length) {
+            // We have extra elements
+            fail("extra args");
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/splash/SplashScreenTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/splash/SplashScreenTest.java
new file mode 100644
index 0000000..81da893
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/splash/SplashScreenTest.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.splash;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * This is an "interactive" test, it passes if the splash screen
+ * disappears after the "finished" but before the "exiting" message.
+ *
+ * This even isn't a JUnit test case.
+ *
+ * @since Ant 1.5.2
+ */
+public class SplashScreenTest {
+
+    public static void main(String[] args) {
+        Project p = new Project();
+        SplashTask t = new SplashTask();
+        t.setProject(p);
+        t.execute();
+
+        // give it some time to display
+        try {
+            Thread.currentThread().sleep(2000);
+        } catch (InterruptedException e) {
+        } // end of try-catch
+
+        p.fireBuildFinished(null);
+        System.err.println("finished");
+
+        try {
+            Thread.currentThread().sleep(2000);
+        } catch (InterruptedException e) {
+        } // end of try-catch
+        System.err.println("exiting");
+        System.exit(0);
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ssh/ScpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ssh/ScpTest.java
new file mode 100644
index 0000000..8c21c8d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/ssh/ScpTest.java
@@ -0,0 +1,166 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs.optional.ssh;
+
+import junit.framework.TestCase;
+
+import java.io.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.FilesMatch;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.selectors.FilenameSelector;
+
+/**
+ * This is a unit test for the Scp task in Ant.  It must be
+ * configured with command line options in order for it to work.
+ * Here are the options:
+ *
+ * scp.tmp              This is a local path to a temporary
+ *                      directory for this task to use.
+ * scp.host             This is the remote location of the form:
+ *                      "user:password@host:/path/to/directory"
+ * scp.port             The port of the listening SSH service.
+ *                      Defaults to 22.  (optional)
+ * scp.known.hosts      The file containing the public keys of known
+ *                      hosts.  Must be a SSH2 version file, but
+ *                      supports RSA and DSA keys. If it is not present
+ *                      this task setTrust() to true.  (optional)
+ */
+public class ScpTest extends TestCase {
+
+    private File tempDir = new File( System.getProperty("scp.tmp") );
+    private String sshHostUri = System.getProperty("scp.host");
+    private int port = Integer.parseInt( System.getProperty( "scp.port", "22" ) );
+    private String knownHosts = System.getProperty("scp.known.hosts");
+
+    private List cleanUpList = new ArrayList();
+
+    public ScpTest(String testname) {
+        super(testname);
+    }
+
+    protected void setUp() {
+        cleanUpList.clear();
+    }
+
+    protected void tearDown() {
+        for( Iterator i = cleanUpList.iterator(); i.hasNext(); ) {
+            File file = (File) i.next();
+            file.delete();
+        }
+    }
+
+    public void testSingleFileUploadAndDownload() throws IOException {
+        File uploadFile = createTemporaryFile();
+
+        Scp scpTask = createTask();
+        scpTask.setFile( uploadFile.getPath() );
+        scpTask.setTodir( sshHostUri );
+        scpTask.execute();
+
+        File testFile = new File( tempDir.getPath() + File.separator +
+                "download-testSingleFileUploadAndDownload.test" );
+        addCleanup( testFile );
+        assertTrue( "Assert that the testFile does not exist.",
+                !testFile.exists() );
+
+        scpTask.setFile( sshHostUri + "/" + uploadFile.getName() );
+        scpTask.setTodir( testFile.getPath() );
+        scpTask.execute();
+
+        assertTrue( "Assert that the testFile exists.", testFile.exists() );
+        compareFiles( uploadFile, testFile );
+    }
+
+    public void testMultiUploadAndDownload() throws IOException {
+        List uploadList = new ArrayList();
+        for( int i = 0; i < 5; i++ ) {
+            uploadList.add( createTemporaryFile() );
+        }
+
+        Scp scp = createTask();
+        FilenameSelector selector = new FilenameSelector();
+        selector.setName( "scp*" );
+        FileSet fileset = new FileSet();
+        fileset.setDir( tempDir );
+        fileset.addFilename( selector );
+        scp.addFileset( fileset );
+        scp.setTodir( sshHostUri );
+        scp.execute();
+
+        File multi = new File( tempDir, "multi" );
+        multi.mkdir();
+        addCleanup( multi );
+
+        Scp scp2 = createTask();
+        scp2.setFile( sshHostUri + "/scp*" );
+        scp2.setTodir( multi.getPath() );
+        scp2.execute();
+
+        FilesMatch match = new FilesMatch();
+        for( Iterator i = uploadList.iterator(); i.hasNext(); ) {
+            File f = (File)i.next();
+            match.setFile1( f );
+            File f2 = new File( multi, f.getName() );
+            match.setFile2( f2 );
+            assertTrue("Assert file '" + f.getPath() + "' and file '" +
+                    f2.getPath() + "'", match.eval() );
+        }
+    }
+
+    public void addCleanup( File file ) {
+        cleanUpList.add( file );
+    }
+
+    private void compareFiles(File src, File dest) {
+        FilesMatch match = new FilesMatch();
+        match.setFile1( src );
+        match.setFile2( dest );
+
+        assertTrue( "Assert files are equal.", match.eval() );
+    }
+
+    private File createTemporaryFile() throws IOException {
+        File uploadFile;
+        uploadFile = File.createTempFile( "scp", "test", tempDir );
+        FileWriter writer = new FileWriter( uploadFile );
+        writer.write("Can you hear me now?\n");
+        writer.close();
+        addCleanup( uploadFile );
+        return uploadFile;
+    }
+
+    private Scp createTask() {
+        Scp scp = new Scp();
+        Project p = new Project();
+        p.init();
+        scp.setProject( p );
+        if( knownHosts != null ) {
+            scp.setKnownhosts( knownHosts );
+        } else {
+            scp.setTrust( true );
+        }
+        scp.setPort( port );
+        return scp;
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
new file mode 100644
index 0000000..83f65a3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/unix/SymlinkTest.java
@@ -0,0 +1,190 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ * Since the initial version of this file was deveolped on the clock on
+ * an NSF grant I should say the following boilerplate:
+ *
+ * This material is based upon work supported by the National Science
+ * Foundaton under Grant No. EIA-0196404. Any opinions, findings, and
+ * conclusions or recommendations expressed in this material are those
+ * of the author and do not necessarily reflect the views of the
+ * National Science Foundation.
+ */
+
+package org.apache.tools.ant.taskdefs.optional.unix;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
+/**
+ * Test cases for the Symlink task. Link creation, link deletion, recording
+ * of links in multiple directories, and restoration of links recorded are
+ * all tested. A separate test for the utility method Symlink.deleteSymlink
+ * is not included because action="delete" only prints a message and calls
+ * Symlink.deleteSymlink, making a separate test redundant.
+ *
+ */
+
+public class SymlinkTest extends BuildFileTest {
+
+    private Project p;
+    private boolean supportsSymlinks = Os.isFamily("unix");
+
+    public SymlinkTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        if (supportsSymlinks) {
+            configureProject("src/etc/testcases/taskdefs/optional/unix/symlink.xml");
+            executeTarget("setup");
+        }
+    }
+
+
+    public void testSingle() {
+        if (supportsSymlinks) {
+            executeTarget("test-single");
+            p = getProject();
+            assertNotNull("Failed to create file",
+                          p.getProperty("test.single.file.created"));
+            assertNotNull("Failed to create link",
+                          p.getProperty("test.single.link.created"));
+        }
+    }
+
+    public void testDelete() {
+        if (supportsSymlinks) {
+            executeTarget("test-delete");
+            p = getProject();
+            String linkDeleted = p.getProperty("test.delete.link.still.there");
+            assertNotNull("Actual file deleted by symlink",
+                          p.getProperty("test.delete.file.still.there"));
+            if (linkDeleted != null) {
+                fail(linkDeleted);
+            }
+        }
+    }
+
+    public void testRecord() {
+        if (supportsSymlinks) {
+            executeTarget("test-record");
+            p = getProject();
+
+            assertNotNull("Failed to create dir1",
+                          p.getProperty("test.record.dir1.created"));
+
+            assertNotNull("Failed to create dir2",
+                          p.getProperty("test.record.dir2.created"));
+
+            assertNotNull("Failed to create file1",
+                          p.getProperty("test.record.file1.created"));
+
+            assertNotNull("Failed to create file2",
+                          p.getProperty("test.record.file2.created"));
+
+            assertNotNull("Failed to create fileA",
+                          p.getProperty("test.record.fileA.created"));
+
+            assertNotNull("Failed to create fileB",
+                          p.getProperty("test.record.fileB.created"));
+
+            assertNotNull("Failed to create fileC",
+                          p.getProperty("test.record.fileC.created"));
+
+            assertNotNull("Failed to create link1",
+                          p.getProperty("test.record.link1.created"));
+
+            assertNotNull("Failed to create link2",
+                          p.getProperty("test.record.link2.created"));
+
+            assertNotNull("Failed to create link3",
+                          p.getProperty("test.record.link3.created"));
+
+            assertNotNull("Failed to create dirlink",
+                          p.getProperty("test.record.dirlink.created"));
+
+            assertNotNull("Failed to create dirlink2",
+                          p.getProperty("test.record.dirlink2.created"));
+
+            assertNotNull("Couldn't record links in dir1",
+                          p.getProperty("test.record.dir1.recorded"));
+
+            assertNotNull("Couldn't record links in dir2",
+                          p.getProperty("test.record.dir2.recorded"));
+
+            String dir3rec = p.getProperty("test.record.dir3.recorded");
+
+            if (dir3rec != null) {
+                fail(dir3rec);
+            }
+
+        }
+    }
+
+    public void testRecreate() {
+        if (supportsSymlinks) {
+            executeTarget("test-recreate");
+            p = getProject();
+            String link1Rem = p.getProperty("test.recreate.link1.not.removed");
+            String link2Rem = p.getProperty("test.recreate.link2.not.removed");
+            String link3Rem = p.getProperty("test.recreate.link3.not.removed");
+            String dirlinkRem = p.getProperty("test.recreate.dirlink.not.removed");
+            if (link1Rem != null) {
+                fail(link1Rem);
+            }
+            if (link2Rem != null) {
+                fail(link2Rem);
+            }
+            if (link3Rem != null) {
+                fail(link3Rem);
+            }
+            if (dirlinkRem != null) {
+                fail(dirlinkRem);
+            }
+            assertNotNull("Failed to recreate link1",
+                          p.getProperty("test.recreate.link1.recreated"));
+            assertNotNull("Failed to recreate link2",
+                          p.getProperty("test.recreate.link2.recreated"));
+            assertNotNull("Failed to recreate link3",
+                          p.getProperty("test.recreate.link3.recreated"));
+            assertNotNull("Failed to recreate dirlink",
+                          p.getProperty("test.recreate.dirlink.recreated"));
+            
+            String doubleRecreate = p.getProperty("test.recreate.dirlink2.recreated.twice");
+
+            if (doubleRecreate != null) {
+                fail(doubleRecreate);
+            }
+
+            assertNotNull("Failed to alter dirlink3",
+                          p.getProperty("test.recreate.dirlink3.was.altered"));
+
+        }
+    }
+
+    public void tearDown() {
+        if (supportsSymlinks) {
+            executeTarget("teardown");
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/vss/MSVSSTest.java b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/vss/MSVSSTest.java
new file mode 100644
index 0000000..7891d0b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/taskdefs/optional/vss/MSVSSTest.java
@@ -0,0 +1,453 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.taskdefs.optional.vss;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Location;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Tstamp;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.types.Path;
+
+/**
+ *  Testcase to ensure that command line generation and required attributes are correct.
+ *
+ */
+public class MSVSSTest extends BuildFileTest implements MSVSSConstants {
+
+    private Commandline commandline;
+
+    private static final String VSS_SERVER_PATH = "\\\\server\\vss\\srcsafe.ini";
+    private static final String VSS_PROJECT_PATH = "/SourceRoot/Project";
+    private static final String DS_VSS_PROJECT_PATH = "$/SourceRoot/Project";
+    private static final String VSS_USERNAME = "ant";
+    private static final String VSS_PASSWORD = "rocks";
+    private static final String LOCAL_PATH = "testdir";
+    private static final String SRC_FILE = "Class1.java";
+    private static final String SRC_LABEL = "label1";
+    private static final String LONG_LABEL = "123456789012345678901234567890";
+    private static final String SRC_COMMENT = "I fixed a bug";
+    private static final String VERSION = "007";
+    private static final String DATE = "00-00-00";
+    private static final String DATE2 = "01-01-01";
+    private static final String OUTPUT = "output.log";
+    private static final String SS_DIR = "c:/winnt".replace('/', File.separatorChar);
+
+    /**
+     *  Constructor for the MSVSSTest object
+     *
+     * @param  s  Test name
+     */
+    public MSVSSTest(String s) {
+        super(s);
+    }
+
+    /**
+     *  The JUnit setup method
+     *
+     * @throws  Exception
+     */
+    protected void setUp()
+        throws Exception {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    /**
+     *  The teardown method for JUnit
+     *
+     * @throws  Exception
+     */
+    protected void tearDown()
+        throws Exception {
+        File file = new File(project.getBaseDir(), LOCAL_PATH);
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    /**  Tests VSSGet commandline generation.  */
+    public void testGetCommandLine() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_GET, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_OVERRIDE_WORKING_DIR + project.getBaseDir().getAbsolutePath()
+                 + File.separator + LOCAL_PATH, MSVSS.FLAG_AUTORESPONSE_DEF,
+                MSVSS.FLAG_RECURSION, MSVSS.FLAG_VERSION + VERSION, MSVSS.FLAG_LOGIN
+                 + VSS_USERNAME + "," + VSS_PASSWORD, FLAG_FILETIME_UPDATED, FLAG_SKIP_WRITABLE};
+
+        // Set up a VSSGet task
+        MSVSSGET vssGet = new MSVSSGET();
+        vssGet.setProject(project);
+        vssGet.setRecursive(true);
+        vssGet.setLocalpath(new Path(project, LOCAL_PATH));
+        vssGet.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+        vssGet.setVersion(VERSION);
+        vssGet.setQuiet(false);
+        vssGet.setDate(DATE);
+        vssGet.setLabel(SRC_LABEL);
+        vssGet.setVsspath(VSS_PROJECT_PATH);
+        MSVSS.CurrentModUpdated cmu = new MSVSS.CurrentModUpdated();
+        cmu.setValue(TIME_UPDATED);
+        vssGet.setFileTimeStamp(cmu);
+        MSVSS.WritableFiles wf = new MSVSS.WritableFiles();
+        wf.setValue(WRITABLE_SKIP);
+        vssGet.setWritableFiles(wf);
+
+        commandline = vssGet.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Tests VSSGet required attributes.  */
+    public void testGetExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vssget.1", "some cause", "vsspath attribute must be set!");
+    }
+
+    /**  Tests Label commandline generation.  */
+    public void testLabelCommandLine1() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_LABEL, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_COMMENT + SRC_COMMENT, MSVSS.FLAG_AUTORESPONSE_YES,
+                MSVSS.FLAG_LABEL + SRC_LABEL, MSVSS.FLAG_VERSION + VERSION, MSVSS.FLAG_LOGIN
+                 + VSS_USERNAME + "," + VSS_PASSWORD};
+
+        // Set up a VSSLabel task
+        MSVSSLABEL vssLabel = new MSVSSLABEL();
+        vssLabel.setProject(project);
+        vssLabel.setComment(SRC_COMMENT);
+        vssLabel.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+        vssLabel.setVersion(VERSION);
+        vssLabel.setAutoresponse("Y");
+        vssLabel.setLabel(SRC_LABEL);
+        vssLabel.setVsspath(VSS_PROJECT_PATH);
+
+        commandline = vssLabel.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Tests Label commandline generation with a label of more than 31 chars.  */
+    public void testLabelCommandLine2() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_LABEL, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_COMMENT + SRC_COMMENT, MSVSS.FLAG_AUTORESPONSE_DEF,
+                MSVSS.FLAG_LABEL + LONG_LABEL,
+                MSVSS.FLAG_LOGIN + VSS_USERNAME + "," + VSS_PASSWORD};
+
+        // Set up a VSSLabel task
+        MSVSSLABEL vssLabel = new MSVSSLABEL();
+        vssLabel.setProject(project);
+        vssLabel.setComment(SRC_COMMENT);
+        vssLabel.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+        vssLabel.setLabel(LONG_LABEL + "blahblah");
+        vssLabel.setVsspath(VSS_PROJECT_PATH);
+
+        commandline = vssLabel.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSLabel required attributes.
+     */
+    public void testLabelExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsslabel.1", "some cause", "vsspath attribute must be set!");
+        expectSpecificBuildException("vsslabel.2", "some cause", "label attribute must be set!");
+    }
+
+    /**  Tests VSSHistory commandline generation with from label.  */
+    public void testHistoryCommandLine1() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_HISTORY, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_VERSION_LABEL + LONG_LABEL
+                 + MSVSS.VALUE_FROMLABEL + SRC_LABEL, MSVSS.FLAG_LOGIN + VSS_USERNAME
+                 + "," + VSS_PASSWORD, MSVSS.FLAG_OUTPUT + project.getBaseDir().getAbsolutePath()
+                 + File.separator + OUTPUT};
+
+        // Set up a VSSHistory task
+        MSVSSHISTORY vssHistory = new MSVSSHISTORY();
+        vssHistory.setProject(project);
+
+        vssHistory.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+
+        vssHistory.setFromLabel(SRC_LABEL);
+        vssHistory.setToLabel(LONG_LABEL + "blahblah");
+        vssHistory.setVsspath(VSS_PROJECT_PATH);
+        vssHistory.setRecursive(false);
+        vssHistory.setOutput(new File(project.getBaseDir().getAbsolutePath(), OUTPUT));
+
+        commandline = vssHistory.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Tests VSSHistory commandline generation with from date.  */
+    public void testHistoryCommandLine2() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_HISTORY, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_VERSION_DATE + DATE + MSVSS.VALUE_FROMDATE
+                + DATE2, MSVSS.FLAG_RECURSION,  MSVSS.FLAG_LOGIN + VSS_USERNAME + "," + VSS_PASSWORD};
+
+        // Set up a VSSHistory task
+        MSVSSHISTORY vssHistory = new MSVSSHISTORY();
+        vssHistory.setProject(project);
+        vssHistory.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+        vssHistory.setFromDate(DATE2);
+        vssHistory.setToDate(DATE);
+        vssHistory.setVsspath(VSS_PROJECT_PATH);
+        vssHistory.setRecursive(true);
+
+        commandline = vssHistory.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**  Tests VSSHistory commandline generation with date calculation.  */
+    public void testHistoryCommandLine3() {
+        // Set up a Timestamp
+        Tstamp tstamp = new Tstamp();
+        Location location = new Location("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        tstamp.setLocation(location);
+        tstamp.setProject(project);
+        Tstamp.CustomFormat format = tstamp.createFormat();
+        format.setProperty("today");
+        format.setPattern("HH:mm:ss z");
+        format.setTimezone("GMT");
+        Date date = Calendar.getInstance().getTime();
+        format.execute(project, date, location);
+        String today = project.getProperty("today");
+
+        // Get today's date
+        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss z");
+        sdf.setTimeZone( TimeZone.getTimeZone("GMT") );
+        String expected = sdf.format(date);
+
+        // Set up a VSSHistory task
+        MSVSSHISTORY vssHistory = new MSVSSHISTORY();
+        vssHistory.setProject(project);
+        vssHistory.setLogin(VSS_USERNAME);
+        vssHistory.setToDate(today);
+        vssHistory.setVsspath(VSS_PROJECT_PATH);
+
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_HISTORY, DS_VSS_PROJECT_PATH,
+        MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_VERSION_DATE + expected, MSVSS.FLAG_LOGIN + VSS_USERNAME};
+
+        commandline = vssHistory.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Tests VSSHistory required attributes.
+     */
+    public void testHistoryExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsshistory.1", "some cause", "vsspath attribute must be set!");
+    }
+
+    /**  Tests CheckIn commandline generation.  */
+    public void testCheckinCommandLine() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_CHECKIN, DS_VSS_PROJECT_PATH,
+                MSVSS.FLAG_AUTORESPONSE_NO, MSVSS.FLAG_WRITABLE, MSVSS.FLAG_LOGIN + VSS_USERNAME,
+                MSVSS.FLAG_COMMENT + SRC_COMMENT};
+
+        // Set up a VSSCheckIn task
+        MSVSSCHECKIN vssCheckin = new MSVSSCHECKIN();
+        vssCheckin.setProject(project);
+        vssCheckin.setComment(SRC_COMMENT);
+        vssCheckin.setLogin(VSS_USERNAME);
+        vssCheckin.setAutoresponse("N");
+        vssCheckin.setVsspath(VSS_PROJECT_PATH);
+        vssCheckin.setWritable(true);
+
+        commandline = vssCheckin.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSCheckIn required attributes.
+     */
+    public void testCheckinExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsscheckin.1", "some cause", "vsspath attribute must be set!");
+    }
+
+    /**  Tests CheckOut commandline generation.  */
+    public void testCheckoutCommandLine() {
+        String[] sTestCmdLine = {SS_DIR + File.separator + MSVSS.SS_EXE, MSVSS.COMMAND_CHECKOUT,
+                DS_VSS_PROJECT_PATH, MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_RECURSION,
+                MSVSS.FLAG_VERSION_DATE + DATE, MSVSS.FLAG_LOGIN + VSS_USERNAME,
+                FLAG_FILETIME_MODIFIED, FLAG_NO_GET};
+
+        // Set up a VSSCheckOut task
+        MSVSSCHECKOUT vssCheckout = new MSVSSCHECKOUT();
+        vssCheckout.setProject(project);
+        vssCheckout.setLogin(VSS_USERNAME);
+        vssCheckout.setVsspath(DS_VSS_PROJECT_PATH);
+        vssCheckout.setRecursive(true);
+        vssCheckout.setDate(DATE);
+        vssCheckout.setLabel(SRC_LABEL);
+        vssCheckout.setSsdir(SS_DIR);
+        MSVSS.CurrentModUpdated cmu = new MSVSS.CurrentModUpdated();
+        cmu.setValue(TIME_MODIFIED);
+        vssCheckout.setFileTimeStamp(cmu);
+        vssCheckout.setGetLocalCopy(false);
+
+        commandline = vssCheckout.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSCheckout required attributes.
+     */
+    public void testCheckoutExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsscheckout.1", "some cause", "vsspath attribute must be set!");
+        expectSpecificBuildException("vsscheckout.2", "some cause", "blah is not a legal value for this attribute");
+    }
+
+    /**  Tests Add commandline generation.  */
+    public void testAddCommandLine() {
+        String[] sTestCmdLine = {SS_DIR + File.separator + MSVSS.SS_EXE, MSVSS.COMMAND_ADD,
+                project.getBaseDir().getAbsolutePath() + File.separator + LOCAL_PATH,
+                MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_RECURSION,
+                MSVSS.FLAG_LOGIN + VSS_USERNAME + "," + VSS_PASSWORD, MSVSS.FLAG_COMMENT + "-"};
+
+        // Set up a VSSAdd task
+        MSVSSADD vssAdd = new MSVSSADD();
+        vssAdd.setProject(project);
+        vssAdd.setLogin(VSS_USERNAME + "," + VSS_PASSWORD);
+        vssAdd.setVsspath(DS_VSS_PROJECT_PATH);
+        vssAdd.setRecursive(true);
+        vssAdd.setSsdir(SS_DIR);
+        vssAdd.setWritable(false);
+        vssAdd.setLocalpath(new Path(project, LOCAL_PATH));
+
+        commandline = vssAdd.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSAdd required attributes.
+     */
+    public void testAddExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vssadd.1", "some cause", "localPath attribute must be set!");
+    }
+
+    /**  Tests CP commandline generation.  */
+    public void testCpCommandLine() {
+        String[] sTestCmdLine = {MSVSS.SS_EXE, MSVSS.COMMAND_CP,
+                DS_VSS_PROJECT_PATH, MSVSS.FLAG_AUTORESPONSE_DEF, MSVSS.FLAG_LOGIN +
+                VSS_USERNAME};
+
+        // Set up a VSSCp task
+        MSVSSCP vssCp = new MSVSSCP();
+        vssCp.setProject(project);
+        vssCp.setLogin(VSS_USERNAME);
+        vssCp.setVsspath(DS_VSS_PROJECT_PATH);
+
+        commandline = vssCp.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSCP required attributes.
+     */
+    public void testCpExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsscp.1", "some cause", "vsspath attribute must be set!");
+    }
+
+    /**  Tests Create commandline generation.  */
+    public void testCreateCommandLine() {
+        String[] sTestCmdLine = { MSVSS.SS_EXE, MSVSS.COMMAND_CREATE,
+                DS_VSS_PROJECT_PATH, MSVSS.FLAG_COMMENT + SRC_COMMENT, MSVSS.FLAG_AUTORESPONSE_NO,
+                MSVSS.FLAG_QUIET, MSVSS.FLAG_LOGIN + VSS_USERNAME};
+
+        // Set up a VSSCreate task
+        MSVSSCREATE vssCreate = new MSVSSCREATE();
+        vssCreate.setProject(project);
+        vssCreate.setComment(SRC_COMMENT);
+        vssCreate.setLogin(VSS_USERNAME);
+        vssCreate.setVsspath(DS_VSS_PROJECT_PATH);
+        vssCreate.setFailOnError(true);
+        vssCreate.setAutoresponse("N");
+        vssCreate.setQuiet(true);
+
+        commandline = vssCreate.buildCmdLine();
+
+        checkCommandLines(sTestCmdLine, commandline.getCommandline());
+    }
+
+    /**
+     * Test VSSCreate required attributes.
+     */
+    public void testCreateExceptions() {
+        configureProject("src/etc/testcases/taskdefs/optional/vss/vss.xml");
+        expectSpecificBuildException("vsscreate.1", "some cause", "vsspath attribute must be set!");
+    }
+
+    /**
+     * Iterate through the generated command line comparing it to reference one.
+     * @param sTestCmdLine          The reference command line;
+     * @param sGeneratedCmdLine     The generated command line;
+     */
+    private void checkCommandLines(String[] sTestCmdLine, String[] sGeneratedCmdLine) {
+        int testLength = sTestCmdLine.length;
+        int genLength = sGeneratedCmdLine.length;
+
+        int genIndex = 0;
+        int testIndex = 0;
+
+        while (testIndex < testLength) {
+            try {
+                if (sGeneratedCmdLine[genIndex] == "") {
+                    genIndex++;
+                    continue;
+                }
+                assertEquals("arg # " + testIndex,
+                        sTestCmdLine[testIndex],
+                        sGeneratedCmdLine[genIndex]);
+                testIndex++;
+                genIndex++;
+            } catch (ArrayIndexOutOfBoundsException aioob) {
+                fail("missing arg " + sTestCmdLine[testIndex]);
+            }
+        }
+
+        // Count the number of empty strings
+        int cnt = 0;
+        for (int i = 0; i < genLength; i++) {
+            if (sGeneratedCmdLine[i] == "") {
+                cnt++;
+            }
+        }
+        if (genLength - cnt > sTestCmdLine.length) {
+            // We have extra elements
+            fail("extra args");
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/AbstractFileSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/AbstractFileSetTest.java
new file mode 100644
index 0000000..a2aae12
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/AbstractFileSetTest.java
@@ -0,0 +1,245 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * Base class for FileSetTest and DirSetTest.
+ *
+ * <p>This doesn't actually test much, mainly reference handling.
+ *
+ */
+
+public abstract class AbstractFileSetTest extends TestCase {
+
+    private Project project;
+
+    public AbstractFileSetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    protected abstract AbstractFileSet getInstance();
+
+    protected final Project getProject() {
+        return project;
+    }
+
+    public final void testEmptyElementIfIsReference() {
+        AbstractFileSet f = getInstance();
+        f.setIncludes("**/*.java");
+        try {
+            f.setRefid(new Reference(getProject(), "dummyref"));
+            fail("Can add reference to "
+                 + f.getDataTypeName()
+                 + " with elements from setIncludes");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+
+        f = getInstance();
+        f.createPatternSet();
+        try {
+            f.setRefid(new Reference(getProject(), "dummyref"));
+            fail("Can add reference to "
+                 + f.getDataTypeName()
+                 + " with nested patternset element.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when "
+                         + "using refid", be.getMessage());
+        }
+
+        f = getInstance();
+        f.createInclude();
+        try {
+            f.setRefid(new Reference(getProject(), "dummyref"));
+            fail("Can add reference to "
+                 + f.getDataTypeName()
+                 + " with nested include element.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+
+        f = getInstance();
+        f.setRefid(new Reference(getProject(), "dummyref"));
+        try {
+            f.setIncludes("**/*.java");
+            fail("Can set includes in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+        try {
+            f.setIncludesfile(new File("/a"));
+            fail("Can set includesfile in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+        try {
+            f.setExcludes("**/*.java");
+            fail("Can set excludes in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+        try {
+            f.setExcludesfile(new File("/a"));
+            fail("Can set excludesfile in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+        try {
+            f.setDir(project.resolveFile("."));
+            fail("Can set dir in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute "
+                         + "when using refid", be.getMessage());
+        }
+        try {
+            f.createInclude();
+            fail("Can add nested include in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using "
+                         + "refid", be.getMessage());
+        }
+        try {
+            f.createExclude();
+            fail("Can add nested exclude in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using "
+                         + "refid", be.getMessage());
+        }
+        try {
+            f.createIncludesFile();
+            fail("Can add nested includesfile in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using "
+                         + "refid", be.getMessage());
+        }
+        try {
+            f.createExcludesFile();
+            fail("Can add nested excludesfile in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using "
+                         + "refid", be.getMessage());
+        }
+        try {
+            f.createPatternSet();
+            fail("Can add nested patternset in "
+                 + f.getDataTypeName()
+                 + " that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using "
+                         + "refid", be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+        AbstractFileSet f = getInstance();
+        project.addReference("dummy", f);
+        f.setRefid(new Reference(getProject(), "dummy"));
+        try {
+            f.getDir(project);
+            fail("Can make " + f.getDataTypeName()
+                 + " a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            f.getDirectoryScanner(project);
+            fail("Can make " + f.getDataTypeName()
+                 + " a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 --> dummy1
+        AbstractFileSet f1 = getInstance();
+        project.addReference("dummy1", f1);
+        f1.setRefid(new Reference(getProject(), "dummy2"));
+        AbstractFileSet f2 = getInstance();
+        project.addReference("dummy2", f2);
+        f2.setRefid(new Reference(getProject(), "dummy3"));
+        AbstractFileSet f3 = getInstance();
+        project.addReference("dummy3", f3);
+        f3.setRefid(new Reference(getProject(), "dummy1"));
+        try {
+            f1.getDir(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            f1.getDirectoryScanner(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3
+        // (which has the Project's basedir as root).
+        f1 = getInstance();
+        project.addReference("dummy1", f1);
+        f1.setRefid(new Reference(getProject(), "dummy2"));
+        f2 = getInstance();
+        project.addReference("dummy2", f2);
+        f2.setRefid(new Reference(getProject(), "dummy3"));
+        f3 = getInstance();
+        project.addReference("dummy3", f3);
+        f3.setDir(project.resolveFile("."));
+        File dir = f1.getDir(project);
+        assertEquals("Dir is basedir", dir, project.getBaseDir());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/AddTypeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/AddTypeTest.java
new file mode 100644
index 0000000..715cbc1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/AddTypeTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+
+public class AddTypeTest extends BuildFileTest {
+
+    public AddTypeTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/addtype.xml");
+    }
+
+    public void testAddPath() {
+        executeTarget("addpath");
+    }
+
+    public void testAddCondition() {
+        executeTarget("addcondition");
+    }
+
+    public void testAddFilter() {
+        executeTarget("addfilter");
+    }
+
+    public void testAddSelector() {
+        executeTarget("addselector");
+    }
+
+    public void testNestedA() {
+        expectLogContaining("nested.a", "add A called");
+    }
+
+    public void testNestedB() {
+        expectLogContaining("nested.b", "add B called");
+    }
+
+    public void testNestedC() {
+        expectLogContaining("nested.c", "add C called");
+    }
+
+    public void testNestedAB() {
+        expectBuildExceptionContaining(
+            "nested.ab", "Should have got ambiguous", "ambiguous");
+    }
+
+    public void testConditionType() {
+        expectLogContaining("condition.type", "beforeafter");
+    }
+
+    public void testConditionTask() {
+        expectLogContaining("condition.task", "My Condition execution");
+    }
+    public void testConditionConditionType() {
+        expectLogContaining("condition.condition.type", "My Condition eval");
+    }
+    public void testConditionConditionTask() {
+        expectBuildExceptionContaining(
+            "condition.condition.task", "task masking condition",
+            "doesn't support the nested");
+    }
+
+    public void testAddConfigured() {
+        expectLogContaining(
+            "myaddconfigured", "value is Value Setexecute: value is Value Set");
+    }
+
+    public void testAddConfiguredValue() {
+        expectLogContaining(
+            "myaddconfiguredvalue",
+            "value is Value Setexecute: value is Value Set");
+    }
+
+    public void testNamespace() {
+        executeTarget("namespacetest");
+    }
+
+    // The following will be used as types and tasks
+
+    public static interface A {}
+    public static interface B {}
+    public static interface C extends A {}
+    public static interface AB extends A, B {}
+
+    public static class AImpl implements A{}
+    public static class BImpl implements B{}
+    public static class CImpl implements C{}
+    public static class ABImpl implements AB{}
+
+    public static class NestedContainer
+        extends Task
+    {
+        public void add(A el) {
+            log("add A called");
+        }
+        public void add(B el) {
+            log("add B called");
+        }
+        public void add(C el) {
+            log("add C called");
+        }
+    }
+
+    public static class MyCondition
+        implements Condition
+    {
+        Project project;
+        public void setProject(Project project) {
+            this.project = project;
+        }
+        public boolean eval() {
+            project.log("My Condition eval");
+            return true;
+        }
+        public void execute() {
+            project.log("My Condition execution");
+        }
+    }
+
+    public static class MyValue
+    {
+        private String text = "NOT SET YET";
+        public void addText(String text) {
+            this.text = text;
+        }
+        public String toString() {
+            return text;
+        }
+    }
+
+    public static class MyAddConfigured
+        extends Task
+    {
+        MyValue value;
+        public void addConfigured(MyValue value) {
+            log("value is " + value);
+            this.value = value;
+        }
+        public void add(MyValue value) {
+            throw new BuildException("Should not be called");
+        }
+        public void execute() {
+            log("execute: value is " + value);
+        }
+    }
+
+    public static class MyAddConfiguredValue
+        extends Task
+    {
+        MyValue value;
+        public void addConfiguredValue(MyValue value) {
+            log("value is " + value);
+            this.value = value;
+        }
+        public void addValue(MyValue value) {
+            throw new BuildException("Should not be called");
+        }
+        public void execute() {
+            log("execute: value is " + value);
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/AssertionsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/AssertionsTest.java
new file mode 100644
index 0000000..ffe3ec5
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/AssertionsTest.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * test assertion handling
+ */
+public class AssertionsTest extends BuildFileTest {
+
+    public AssertionsTest(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        configureProject("src/etc/testcases/types/assertions.xml");
+    }
+
+    protected void tearDown() throws Exception {
+        executeTarget("teardown");
+    }
+
+    /**
+     * runs a test and expects an assertion thrown in forked code
+     * @param target
+     */
+    protected void expectAssertion(String target) {
+        expectBuildExceptionContaining(target,
+                "assertion not thrown in "+target,
+                "Java returned: 1");
+    }
+
+    public void testClassname() {
+        expectAssertion("test-classname");
+    }
+
+    public void testPackage() {
+        expectAssertion("test-package");
+    }
+
+    public void testEmptyAssertions() {
+        executeTarget("test-empty-assertions");
+    }
+
+    public void testDisable() {
+        executeTarget("test-disable");
+    }
+
+    public void testOverride() {
+        expectAssertion("test-override");
+    }
+
+    public void testOverride2() {
+        executeTarget("test-override2");
+    }
+    public void testReferences() {
+        expectAssertion("test-references");
+    }
+
+    public void testMultipleAssertions() {
+        expectBuildExceptionContaining("test-multiple-assertions",
+                "multiple assertions rejected",
+                "Only one assertion declaration is allowed");
+    }
+
+    public void testReferenceAbuse() {
+        expectBuildExceptionContaining("test-reference-abuse",
+                "reference abuse rejected",
+                "You must not specify");
+    }
+
+    public void testNofork() {
+        if (AssertionsTest.class.desiredAssertionStatus()) {
+            return; // ran Ant tests with -ea and this would fail spuriously
+        }
+        expectLogContaining("test-nofork",
+                "Assertion statements are currently ignored in non-forked mode");
+    }
+
+
+    public void testJunit() {
+        executeTarget("test-junit");
+    }
+}
+
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineJavaTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineJavaTest.java
new file mode 100644
index 0000000..8f2ebfc
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineJavaTest.java
@@ -0,0 +1,186 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.JavaEnvUtils;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.CommandlineJava
+ *
+ */
+public class CommandlineJavaTest extends TestCase {
+
+    private String cloneVm;
+
+    public CommandlineJavaTest(String name) {
+        super(name);
+    }
+
+    private Project project;
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(System.getProperty("root"));
+        project.setProperty("build.sysclasspath", "ignore");
+        cloneVm = System.getProperty("ant.build.clonevm");
+        if (cloneVm != null) {
+            System.setProperty("ant.build.clonevm", "false");
+        }
+    }
+
+    public void tearDown() {
+        if (cloneVm != null) {
+            System.setProperty("ant.build.clonevm", cloneVm);
+        }
+    }
+
+    public void testGetCommandline() throws Exception {
+        CommandlineJava c = new CommandlineJava();
+        c.createArgument().setValue("org.apache.tools.ant.CommandlineJavaTest");
+        c.setClassname("junit.textui.TestRunner");
+        c.createVmArgument().setValue("-Djava.compiler=NONE");
+        String[] s = c.getCommandline();
+        assertEquals("no classpath", 4, s.length);
+        /*
+         * After changing CommandlineJava to search for the java
+         * executable, I don't know, how to tests the value returned
+         * here without using the same logic as applied in the class
+         * itself.
+         *
+         * assertTrue("no classpath", "java", s[0]);
+         */
+        assertEquals("no classpath", "-Djava.compiler=NONE", s[1]);
+        assertEquals("no classpath", "junit.textui.TestRunner", s[2]);
+        assertEquals("no classpath",
+                     "org.apache.tools.ant.CommandlineJavaTest", s[3]);
+        try {
+            CommandlineJava c2 = (CommandlineJava) c.clone();
+        } catch (NullPointerException ex) {
+            fail("cloning should work without classpath specified");
+        }
+
+        c.createClasspath(project).setLocation(project.resolveFile("build.xml"));
+        c.createClasspath(project).setLocation(project.resolveFile(
+            System.getProperty(MagicNames.ANT_HOME)+"/lib/ant.jar"));
+        s = c.getCommandline();
+        assertEquals("with classpath", 6, s.length);
+        //        assertEquals("with classpath", "java", s[0]);
+        assertEquals("with classpath", "-Djava.compiler=NONE", s[1]);
+        assertEquals("with classpath", "-classpath", s[2]);
+        assertTrue("build.xml contained",
+               s[3].indexOf("build.xml"+java.io.File.pathSeparator) >= 0);
+        assertTrue("ant.jar contained", s[3].endsWith("ant.jar"));
+        assertEquals("with classpath", "junit.textui.TestRunner", s[4]);
+        assertEquals("with classpath",
+                     "org.apache.tools.ant.CommandlineJavaTest", s[5]);
+    }
+
+    public void testJarOption() throws Exception {
+        CommandlineJava c = new CommandlineJava();
+        c.createArgument().setValue("arg1");
+        c.setJar("myfile.jar");
+        c.createVmArgument().setValue("-classic");
+        c.createVmArgument().setValue("-Dx=y");
+        String[] s = c.getCommandline();
+        assertEquals("-classic", s[1]);
+        assertEquals("-Dx=y", s[2]);
+        assertEquals("-jar", s[3]);
+        assertEquals("myfile.jar", s[4]);
+        assertEquals("arg1", s[5]);
+    }
+
+    public void testSysproperties() {
+        String currentClasspath = System.getProperty("java.class.path");
+        assertNotNull(currentClasspath);
+        assertNull(System.getProperty("key"));
+        CommandlineJava c = new CommandlineJava();
+        Environment.Variable v = new Environment.Variable();
+        v.setKey("key");
+        v.setValue("value");
+        c.addSysproperty(v);
+
+        project.setProperty("key2", "value2");
+        PropertySet ps = new PropertySet();
+        ps.setProject(project);
+        ps.appendName("key2");
+        c.addSyspropertyset(ps);
+
+        try {
+            c.setSystemProperties();
+            String newClasspath = System.getProperty("java.class.path");
+            assertNotNull(newClasspath);
+            assertEquals(currentClasspath, newClasspath);
+            assertNotNull(System.getProperty("key"));
+            assertEquals("value", System.getProperty("key"));
+            assertTrue(System.getProperties().containsKey("java.class.path"));
+            assertNotNull(System.getProperty("key2"));
+            assertEquals("value2", System.getProperty("key2"));
+        } finally {
+            c.restoreSystemProperties();
+        }
+        assertNull(System.getProperty("key"));
+        assertNull(System.getProperty("key2"));
+    }
+
+    public void testAssertions() throws Exception {
+        if (JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_2)
+            || JavaEnvUtils.isJavaVersion(JavaEnvUtils.JAVA_1_3)) {
+            return;
+        }
+
+        CommandlineJava c = new CommandlineJava();
+        c.createArgument().setValue("org.apache.tools.ant.CommandlineJavaTest");
+        c.setClassname("junit.textui.TestRunner");
+        c.createVmArgument().setValue("-Djava.compiler=NONE");
+        Assertions a = new Assertions();
+        a.setProject(project);
+        Assertions.EnabledAssertion ea = new Assertions.EnabledAssertion();
+        ea.setClass("junit.textui.TestRunner");
+        a.addEnable(ea);
+        c.setAssertions(a);
+
+        String[] expected = new String[] {
+            null,
+            "-Djava.compiler=NONE",
+            "-ea:junit.textui.TestRunner",
+            "junit.textui.TestRunner",
+            "org.apache.tools.ant.CommandlineJavaTest",
+        };
+            
+        // only the second iteration would pass because of PR 27218
+        for (int i = 0; i < 3; i++) {
+            String[] s = c.getCommandline();
+            assertEquals(expected.length, s.length);
+            for (int j = 1; j < expected.length; j++) {
+                assertEquals(expected[j], s[j]);
+            }
+        }
+        CommandlineJava c2 = (CommandlineJava) c.clone();
+        String[] s = c2.getCommandline();
+        assertEquals(expected.length, s.length);
+        for (int j = 1; j < expected.length; j++) {
+            assertEquals(expected[j], s[j]);
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineTest.java
new file mode 100644
index 0000000..559c5f7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/CommandlineTest.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.CommandLine
+ *
+ */
+public class CommandlineTest extends TestCase {
+
+    public CommandlineTest(String name) {
+        super(name);
+    }
+
+    public void testTokenizer() {
+        String[] s = Commandline.translateCommandline("1 2 3");
+        assertEquals("Simple case", 3, s.length);
+        for (int i=0; i<3; i++) {
+            assertEquals(""+(i+1), s[i]);
+        }
+
+        s = Commandline.translateCommandline("");
+        assertEquals("empty string", 0, s.length);
+
+        s = Commandline.translateCommandline(null);
+        assertEquals("null", 0, s.length);
+
+        s = Commandline.translateCommandline("1 \'2\' 3");
+        assertEquals("Simple case with single quotes", 3, s.length);
+        assertEquals("Single quotes have been stripped", "2", s[1]);
+
+        s = Commandline.translateCommandline("1 \"2\" 3");
+        assertEquals("Simple case with double quotes", 3, s.length);
+        assertEquals("Double quotes have been stripped", "2", s[1]);
+
+        s = Commandline.translateCommandline("1 \"2 3\" 4");
+        assertEquals("Case with double quotes and whitespace", 3, s.length);
+        assertEquals("Double quotes stripped, space included", "2 3", s[1]);
+
+        s = Commandline.translateCommandline("1 \"2\'3\" 4");
+        assertEquals("Case with double quotes around single quote", 3, s.length);
+        assertEquals("Double quotes stripped, single quote included", "2\'3",
+                     s[1]);
+
+        s = Commandline.translateCommandline("1 \'2 3\' 4");
+        assertEquals("Case with single quotes and whitespace", 3, s.length);
+        assertEquals("Single quotes stripped, space included", "2 3", s[1]);
+
+        s = Commandline.translateCommandline("1 \'2\"3\' 4");
+        assertEquals("Case with single quotes around double quote", 3, s.length);
+        assertEquals("Single quotes stripped, double quote included", "2\"3",
+                     s[1]);
+
+        // \ doesn't have a special meaning anymore - this is different from
+        // what the Unix sh does but causes a lot of problems on DOS
+        // based platforms otherwise
+        s = Commandline.translateCommandline("1 2\\ 3 4");
+        assertEquals("case with quoted whitespace", 4, s.length);
+        assertEquals("backslash included", "2\\", s[1]);
+
+        // "" should become a single empty argument, same for ''
+        // PR 5906
+        s = Commandline.translateCommandline("\"\" a");
+        assertEquals("Doublequoted null arg prepend", 2, s.length);
+        assertEquals("Doublequoted null arg prepend", "", s[0]);
+        assertEquals("Doublequoted null arg prepend", "a", s[1]);
+        s = Commandline.translateCommandline("a \"\"");
+        assertEquals("Doublequoted null arg append", 2, s.length);
+        assertEquals("Doublequoted null arg append", "a", s[0]);
+        assertEquals("Doublequoted null arg append", "", s[1]);
+        s = Commandline.translateCommandline("\"\"");
+        assertEquals("Doublequoted null arg", 1, s.length);
+        assertEquals("Doublequoted null arg", "", s[0]);
+
+        s = Commandline.translateCommandline("\'\' a");
+        assertEquals("Singlequoted null arg prepend", 2, s.length);
+        assertEquals("Singlequoted null arg prepend", "", s[0]);
+        assertEquals("Singlequoted null arg prepend", "a", s[1]);
+        s = Commandline.translateCommandline("a \'\'");
+        assertEquals("Singlequoted null arg append", 2, s.length);
+        assertEquals("Singlequoted null arg append", "a", s[0]);
+        assertEquals("Singlequoted null arg append", "", s[1]);
+        s = Commandline.translateCommandline("\'\'");
+        assertEquals("Singlequoted null arg", 1, s.length);
+        assertEquals("Singlequoted null arg", "", s[0]);
+
+        // now to the expected failures
+
+        try {
+            s = Commandline.translateCommandline("a \'b c");
+            fail("unbalanced single quotes undetected");
+        } catch (BuildException be) {
+            assertEquals("unbalanced quotes in a \'b c", be.getMessage());
+        }
+
+        try {
+            s = Commandline.translateCommandline("a \"b c");
+            fail("unbalanced double quotes undetected");
+        } catch (BuildException be) {
+            assertEquals("unbalanced quotes in a \"b c", be.getMessage());
+        }
+    }
+
+    public void testToString() {
+        assertEquals("", Commandline.toString(new String[0]));
+        assertEquals("", Commandline.toString(null));
+        assertEquals("1 2 3", Commandline.toString(new String[] {"1", "2", "3"}));
+        assertEquals("1 \"2 3\"", Commandline.toString(new String[] {"1", "2 3"}));
+        assertEquals("1 \"2\'3\"", Commandline.toString(new String[] {"1", "2\'3"}));
+        assertEquals("1 \'2\"3\'", Commandline.toString(new String[] {"1", "2\"3"}));
+    }
+
+    public void testAwkCommand(){
+        Commandline c = new Commandline();
+        c.setExecutable("awk");
+        c.createArgument().setValue("'NR == 2 { print $NF }'");
+        String[] s = c.getCommandline();
+        assertNotNull(s);
+        assertEquals(2, s.length);
+        assertEquals("awk", s[0]);
+        assertEquals("'NR == 2 { print $NF }'", s[1]);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/DescriptionTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/DescriptionTest.java
new file mode 100644
index 0000000..966465d
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/DescriptionTest.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * FilterSet testing
+ *
+ */
+public class DescriptionTest extends BuildFileTest {
+
+    public DescriptionTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+    }
+
+    public void tearDown() {
+    }
+
+    public void test1() {
+        configureProject("src/etc/testcases/types/description1.xml");
+        assertEquals("Single description failed", "Test Project Description", project.getDescription());
+    }
+
+    public void test2() {
+        configureProject("src/etc/testcases/types/description2.xml");
+        assertEquals("Multi line description failed", "Multi Line\nProject Description", project.getDescription());
+    }
+
+    public void test3() {
+        configureProject("src/etc/testcases/types/description3.xml");
+        assertEquals("Multi instance description failed", "Multi Instance Project Description", project.getDescription());
+    }
+
+    public void test4() {
+        configureProject("src/etc/testcases/types/description4.xml");
+        assertEquals("Multi instance nested description failed", "Multi Instance Nested Project Description", project.getDescription());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/DirSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/DirSetTest.java
new file mode 100644
index 0000000..c17ef55
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/DirSetTest.java
@@ -0,0 +1,83 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.DirSet.
+ *
+ */
+public class DirSetTest extends AbstractFileSetTest {
+
+    public DirSetTest(String name) {
+        super(name);
+    }
+
+    protected AbstractFileSet getInstance() {
+        return new DirSet();
+    }
+
+    public void testFileSetIsNoDirSet() {
+        DirSet ds = (DirSet) getInstance();
+        ds.setProject(getProject());
+        FileSet fs = new FileSet();
+        fs.setProject(getProject());
+        getProject().addReference("dummy", fs);
+        ds.setRefid(new Reference(getProject(), "dummy"));
+        try {
+            ds.getDir(getProject());
+            fail("DirSet created from FileSet reference");
+        } catch (BuildException e) {
+            assertEquals("dummy doesn\'t denote a DirSet", e.getMessage());
+        }
+
+        ds = (DirSet) getInstance();
+        ds.setProject(getProject());
+        getProject().addReference("dummy2", ds);
+        fs.setRefid(new Reference(getProject(), "dummy2"));
+        try {
+            fs.getDir(getProject());
+            fail("FileSet created from DirSet reference");
+        } catch (BuildException e) {
+            assertEquals("dummy2 doesn\'t denote a FileSet", e.getMessage());
+        }
+    }
+
+    public void testToString() throws Exception {
+        File tmp = File.createTempFile("DirSetTest", "");
+        tmp.delete();
+        File a = new File(tmp, "a");
+        a.mkdirs();
+        File b = new File(tmp, "b");
+        File bc = new File(b, "c");
+        bc.mkdirs();
+        new FileOutputStream(new File(a, "x")).close();
+        new FileOutputStream(new File(b, "x")).close();
+        new FileOutputStream(new File(bc, "x")).close();
+        DirSet ds = new DirSet();
+        ds.setProject(getProject());
+        ds.setDir(tmp);
+        ds.setIncludes("b/");
+        assertEquals("b;b" + File.separator + "c", ds.toString());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/EnumeratedAttributeTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/EnumeratedAttributeTest.java
new file mode 100644
index 0000000..e0751b4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/EnumeratedAttributeTest.java
@@ -0,0 +1,102 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.EnumeratedAttribute.
+ */
+public class EnumeratedAttributeTest extends TestCase {
+
+    private static String[] expected = {"a", "b", "c"};
+
+    public EnumeratedAttributeTest(String name) {
+        super(name);
+    }
+
+    public void testContains() {
+        EnumeratedAttribute t1 = new TestNormal();
+        for (int i=0; i<expected.length; i++) {
+            assertTrue(expected[i]+" is in TestNormal",
+                   t1.containsValue(expected[i]));
+            assertTrue(expected[i].toUpperCase()+" is in TestNormal",
+                   !t1.containsValue(expected[i].toUpperCase()));
+        }
+        assertTrue("TestNormal doesn\'t have \"d\" attribute",
+               !t1.containsValue("d"));
+        assertTrue("TestNull doesn\'t have \"d\" attribute and doesn\'t die",
+               !(new TestNull()).containsValue("d"));
+    }
+
+    public void testFactory() {
+		Factory ea = (Factory)EnumeratedAttribute.getInstance(Factory.class, "one");
+		assertEquals("Factory did not set the right value.", ea.getValue(), "one");
+		try {
+	    	EnumeratedAttribute.getInstance(Factory.class, "illegal");
+	    	fail("Factory should fail when trying to set an illegal value.");
+		} catch (BuildException be) {
+			// was expected
+		}
+	}
+
+	public void testExceptions() {
+        EnumeratedAttribute t1 = new TestNormal();
+        for (int i=0; i<expected.length; i++) {
+            try {
+                t1.setValue(expected[i]);
+            } catch (BuildException be) {
+                fail("unexpected exception for value "+expected[i]);
+            }
+        }
+        try {
+            t1.setValue("d");
+            fail("expected exception for value \"d\"");
+        } catch (BuildException be) {
+        }
+        try {
+            (new TestNull()).setValue("d");
+            fail("expected exception for value \"d\" in TestNull");
+        } catch (BuildException be) {
+        } catch (Throwable other) {
+            fail("unexpected death of TestNull: "+other.getMessage());
+        }
+    }
+
+    public static class TestNormal extends EnumeratedAttribute {
+        public String[] getValues() {
+            return expected;
+        }
+    }
+
+    public static class TestNull extends EnumeratedAttribute {
+        public String[] getValues() {
+            return null;
+        }
+    }
+
+    public static class Factory extends EnumeratedAttribute {
+    	public String[] getValues() {
+    		return new String[] { "one", "two", "three" };
+    	}
+    }
+    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/FileListTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/FileListTest.java
new file mode 100644
index 0000000..87f4f11
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/FileListTest.java
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Some tests for filelist.
+ */
+
+public class FileListTest extends BuildFileTest {
+
+    public FileListTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/filelist.xml");
+    }
+    
+    public void testEmptyElementIfIsReference() {
+        FileList f = new FileList();
+        f.setDir(project.resolveFile("."));
+        try {
+            f.setRefid(new Reference(getProject(), "dummyref"));
+            fail("Can add reference to FileList with directory attribute set.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        f = new FileList();
+        f.setFiles("foo.xml,c/d/bar.xml");
+        try {
+            f.setRefid(new Reference(getProject(), "dummyref"));
+            fail("Can add reference to FileList with file attribute set.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        f = new FileList();
+        f.setRefid(new Reference(getProject(), "dummyref"));
+        try {
+            f.setFiles("a/b/foo.java");
+            fail("Can set files in FileList that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+        try {
+            f.setDir(project.resolveFile("."));
+            fail("Can set dir in FileList that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+        FileList f = new FileList();
+        project.addReference("dummy", f);
+        f.setRefid(new Reference(getProject(), "dummy"));
+        try {
+            f.getDir(project);
+            fail("Can make FileList a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            f.getFiles(project);
+            fail("Can make FileList a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 --> dummy1
+        FileList f1 = new FileList();
+        project.addReference("dummy1", f1);
+        f1.setRefid(new Reference(getProject(), "dummy2"));
+        FileList f2 = new FileList();
+        project.addReference("dummy2", f2);
+        f2.setRefid(new Reference(getProject(), "dummy3"));
+        FileList f3 = new FileList();
+        project.addReference("dummy3", f3);
+        f3.setRefid(new Reference(getProject(), "dummy1"));
+        try {
+            f1.getDir(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            f1.getFiles(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3
+        // (which has the Project's basedir as root).
+        f1 = new FileList();
+        project.addReference("dummy1", f1);
+        f1.setRefid(new Reference(getProject(), "dummy2"));
+        f2 = new FileList();
+        project.addReference("dummy2", f2);
+        f2.setRefid(new Reference(getProject(), "dummy3"));
+        f3 = new FileList();
+        project.addReference("dummy3", f3);
+        f3.setDir(project.resolveFile("."));
+        File dir = f1.getDir(project);
+        assertEquals("Dir is basedir", dir, project.getBaseDir());
+    }
+    
+    public void testSimple() {
+        expectLog("simple", "/abc/a");
+    }
+
+    public void testDouble() {
+        expectLog("double", "/abc/a:/abc/b");
+    }
+
+    public void testNested() {
+        expectLog("nested", "/abc/a:/abc/b");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/FileSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/FileSetTest.java
new file mode 100644
index 0000000..3595986
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/FileSetTest.java
@@ -0,0 +1,39 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.FileSet.
+ *
+ * <p>This doesn't actually test much, mainly reference handling.
+ *
+ */
+
+public class FileSetTest extends AbstractFileSetTest {
+
+    public FileSetTest(String name) {
+        super(name);
+    }
+
+    protected AbstractFileSet getInstance() {
+        return new FileSet();
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/FilterSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/FilterSetTest.java
new file mode 100644
index 0000000..4f01428
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/FilterSetTest.java
@@ -0,0 +1,221 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * FilterSet testing
+ *
+ */
+public class FilterSetTest extends BuildFileTest {
+
+    static private final int BUF_SIZE = 32768;
+
+    public FilterSetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/filterset.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test1() {
+        executeTarget("test1");
+        assertTrue("Filterset 1 failed", compareFiles("src/etc/testcases/types/gold/filterset1.txt",
+                                                      "src/etc/testcases/types/dest1.txt"));
+    }
+
+    public void test2() {
+        executeTarget("test2");
+        assertTrue("Filterset 2 failed", compareFiles("src/etc/testcases/types/gold/filterset2.txt",
+                                                      "src/etc/testcases/types/dest2.txt"));
+    }
+
+    public void test3() {
+        executeTarget("test3");
+        assertTrue("Filterset 3 failed", compareFiles("src/etc/testcases/types/gold/filterset3.txt",
+                                                      "src/etc/testcases/types/dest3.txt"));
+    }
+
+    /**
+     * This will test the recursive FilterSet.  Which means that if
+     * the filter value @test@ contains another filter value, it will
+     * actually resolve.
+     */
+    public void testRecursive() {
+        String result = "it works line";
+        String line="@test@ line";
+        FilterSet fs = new FilterSet();
+        fs.addFilter("test", "@test1@");
+        fs.addFilter("test1","@test2@");
+        fs.addFilter("test2", "it works");
+        fs.setBeginToken("@");
+        fs.setEndToken("@");
+        assertEquals(result, fs.replaceTokens(line));
+    }
+
+    /**
+     * Test to see what happens when the resolving occurs in an
+     * infinite loop.
+     */
+    public void testInfinite() {
+        String result = "@test@ line testvalue";
+        String line = "@test@ line @test3@";
+        FilterSet fs = new FilterSet();
+        fs.addFilter("test", "@test1@");
+        fs.addFilter("test1","@test2@");
+        fs.addFilter("test2", "@test@");
+        fs.addFilter("test3", "testvalue");
+        fs.setBeginToken("@");
+        fs.setEndToken("@");
+        assertEquals(result, fs.replaceTokens(line));
+    }
+
+    /**
+     * Test to see what happens when the resolving occurs in
+     * what would be an infinite loop, but with recursion disabled.
+     */
+    public void testRecursionDisabled() {
+        String result = "@test1@ line testvalue";
+        String line = "@test@ line @test2@";
+        FilterSet fs = new FilterSet();
+        fs.addFilter("test", "@test1@");
+        fs.addFilter("test1","@test@");
+        fs.addFilter("test2", "testvalue");
+        fs.setBeginToken("@");
+        fs.setEndToken("@");
+        fs.setRecurse(false);
+        assertEquals(result, fs.replaceTokens(line));
+    }
+
+    public void testNonInfiniteRecursiveMultipleOnSingleLine() {
+        FilterSet filters = new FilterSet();
+
+        filters.setBeginToken("<");
+        filters.setEndToken(">");
+
+        filters.addFilter("ul", "<itemizedlist>");
+        filters.addFilter("/ul", "</itemizedList>");
+        filters.addFilter("li", "<listitem>");
+        filters.addFilter("/li", "</listitem>");
+
+        String result = "<itemizedlist><listitem>Item 1</listitem> <listitem>Item 2</listitem></itemizedList>";
+        String line = "<ul><li>Item 1</li> <li>Item 2</li></ul>";
+
+        assertEquals(result, filters.replaceTokens(line));
+    }
+    
+    public void testNestedFilterSets() {
+        executeTarget("test-nested-filtersets");
+
+        FilterSet fs = (FilterSet) getProject().getReference("1");
+        Hashtable filters = fs.getFilterHash();
+        assertEquals(1, filters.size());
+        assertEquals("value1", filters.get("token1"));
+
+        fs = (FilterSet) getProject().getReference("2");
+        filters = fs.getFilterHash();
+        assertEquals(2, filters.size());
+        assertEquals("1111", filters.get("aaaa"));
+        assertEquals("2222", filters.get("bbbb"));
+
+        fs = (FilterSet) getProject().getReference("3");
+        filters = fs.getFilterHash();
+        assertEquals(1, filters.size());
+        assertEquals("value4", filters.get("token4"));
+
+        fs = (FilterSet) getProject().getReference("5");
+        filters = fs.getFilterHash();
+        assertEquals(1, filters.size());
+        assertEquals("value1", filters.get("token1"));
+    }
+
+    public void testFiltersFileElement() {
+        executeTarget("testFiltersFileElement");
+    }
+
+    public void testFiltersFileAttribute() {
+        executeTarget("testFiltersFileAttribute");
+    }
+
+    public void testMultipleFiltersFiles() {
+        executeTarget("testMultipleFiltersFiles");
+    }
+
+    public void testMissingFiltersFile() {
+        expectBuildException("testMissingFiltersFile",
+            "should fail due to missing filtersfile");
+    }
+
+    public void testAllowMissingFiltersFile() {
+        executeTarget("testAllowMissingFiltersFile");
+    }
+
+    private boolean compareFiles(String name1, String name2) {
+        File file1 = new File(System.getProperty("root"), name1);
+        File file2 = new File(System.getProperty("root"), name2);
+
+        try {
+            if (!file1.exists() || !file2.exists()) {
+                System.out.println("One or both files do not exist:" + name1 + ", " + name2);
+                return false;
+            }
+
+            if (file1.length() != file2.length()) {
+                System.out.println("File size mismatch:" + name1 + "(" + file1.length() + "), " +
+                                   name2  + "(" + file2.length() + ")");
+                return false;
+            }
+
+            // byte - byte compare
+            byte[] buffer1 = new byte[BUF_SIZE];
+            byte[] buffer2 = new byte[BUF_SIZE];
+
+            FileInputStream fis1 = new FileInputStream(file1);
+            FileInputStream fis2 = new FileInputStream(file2);
+            int index = 0;
+            int read = 0;
+            while ((read = fis1.read(buffer1)) != -1) {
+                fis2.read(buffer2);
+                for (int i = 0; i < read; ++i, ++index) {
+                    if (buffer1[i] != buffer2[i]) {
+                        System.out.println("Bytes mismatch:" + name1 + ", " + name2 +
+                                           " at byte " + index);
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+        catch (IOException e) {
+            System.out.println("IOException comparing files: " + name1 + ", " + name2);
+            return false;
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/FlexIntegerTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/FlexIntegerTest.java
new file mode 100644
index 0000000..d618b76
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/FlexIntegerTest.java
@@ -0,0 +1,73 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildException;
+
+public class FlexIntegerTest extends BuildFileTest {
+
+    public FlexIntegerTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/flexinteger.xml");
+    }
+
+    public void testFlexInteger() {
+        executeTarget("test");
+        assertEquals(project.getProperty("flexint.value1"), "10");
+        assertEquals(project.getProperty("flexint.value2"), "8");
+    }
+
+    // This class acts as a custom Ant task also
+    // and uses these variables/methods in that mode
+    private Project taskProject;
+    String propName;
+    private FlexInteger value;
+
+    /**
+     * To make taskdef happy
+     */
+    public FlexIntegerTest() {
+        super("FlexIntegerTest");
+    }
+
+    public void setPropName(String propName) {
+        this.propName = propName;
+    }
+
+    public void setValue(FlexInteger value) {
+        this.value = value;
+    }
+
+    public void setProject(Project project) {
+        taskProject = project;
+    }
+
+    public void execute() {
+        if (propName == null || value == null) {
+            throw new BuildException("name and value required");
+        }
+
+        taskProject.setNewProperty(propName, value.toString());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/MapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/MapperTest.java
new file mode 100644
index 0000000..a5f6037
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/MapperTest.java
@@ -0,0 +1,246 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.ChainedMapper;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FlatFileNameMapper;
+import org.apache.tools.ant.util.GlobPatternMapper;
+import org.apache.tools.ant.util.MergingMapper;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.Mapper.
+ *
+ */
+
+public class MapperTest extends TestCase {
+
+    private Project project;
+
+    public MapperTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    public void testEmptyElementIfIsReference() {
+        Mapper m = new Mapper(project);
+        m.setFrom("*.java");
+        try {
+            m.setRefid(new Reference(project, "dummyref"));
+            fail("Can add reference to Mapper with from attribute set");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        m = new Mapper(project);
+        m.setRefid(new Reference(project, "dummyref"));
+        try {
+            m.setFrom("*.java");
+            fail("Can set from in Mapper that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        m = new Mapper(project);
+        m.setRefid(new Reference(project, "dummyref"));
+        try {
+            m.setTo("*.java");
+            fail("Can set to in Mapper that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+        try {
+            Mapper.MapperType mt = new Mapper.MapperType();
+            mt.setValue("glob");
+            m.setType(mt);
+            fail("Can set type in Mapper that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+        Mapper m = new Mapper(project);
+        project.addReference("dummy", m);
+        m.setRefid(new Reference(project, "dummy"));
+        try {
+            m.getImplementation();
+            fail("Can make Mapper a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 --> dummy1
+        Mapper m1 = new Mapper(project);
+        project.addReference("dummy1", m1);
+        m1.setRefid(new Reference(project, "dummy2"));
+        Mapper m2 = new Mapper(project);
+        project.addReference("dummy2", m2);
+        m2.setRefid(new Reference(project, "dummy3"));
+        Mapper m3 = new Mapper(project);
+        project.addReference("dummy3", m3);
+        m3.setRefid(new Reference(project, "dummy1"));
+        try {
+            m1.getImplementation();
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3
+        // (which holds a glob mapper from "*.java" to "*.class"
+        m1 = new Mapper(project);
+        project.addReference("dummy1", m1);
+        m1.setRefid(new Reference(project, "dummy2"));
+        m2 = new Mapper(project);
+        project.addReference("dummy2", m2);
+        m2.setRefid(new Reference(project, "dummy3"));
+        m3 = new Mapper(project);
+        project.addReference("dummy3", m3);
+        Mapper.MapperType mt = new Mapper.MapperType();
+        mt.setValue("glob");
+        m3.setType(mt);
+        m3.setFrom("*.java");
+        m3.setTo("*.class");
+        FileNameMapper fmm = m1.getImplementation();
+        assertTrue("should be glob", fmm instanceof GlobPatternMapper);
+        String[] result = fmm.mapFileName("a.java");
+        assertEquals("a.java should match", 1, result.length);
+        assertEquals("a.class", result[0]);
+    }
+
+    public void testNested() {
+        Mapper mapper1 = new Mapper(project);
+        Mapper.MapperType mt = new Mapper.MapperType();
+        mt.setValue("glob");
+        mapper1.setType(mt);
+        mapper1.setFrom("from*");
+        mapper1.setTo("to*");
+
+        //mix element types
+        FileNameMapper mapper2 = new FlatFileNameMapper();
+        FileNameMapper mapper3 = new MergingMapper();
+        mapper3.setTo("mergefile");
+
+        Mapper container = new Mapper(project);
+        container.addConfiguredMapper(mapper1);
+        container.add(mapper2);
+        container.add(mapper3);
+
+        FileNameMapper fileNameMapper = container.getImplementation();
+        String[] targets = fileNameMapper.mapFileName("fromfilename");
+        assertNotNull("no filenames mapped", targets);
+        assertEquals("wrong number of filenames mapped", 3, targets.length);
+        List list = Arrays.asList(targets);
+        assertTrue("cannot find expected target \"tofilename\"",
+            list.contains("tofilename"));
+        assertTrue("cannot find expected target \"fromfilename\"",
+            list.contains("fromfilename"));
+        assertTrue("cannot find expected target \"mergefile\"",
+            list.contains("mergefile"));
+    }
+
+    public void testChained() {
+
+        // a --> b --> c --- def
+        //               \-- ghi
+
+        FileNameMapper mapperAB = new GlobPatternMapper();
+        mapperAB.setFrom("a");
+        mapperAB.setTo("b");
+
+        FileNameMapper mapperBC = new GlobPatternMapper();
+        mapperBC.setFrom("b");
+        mapperBC.setTo("c");
+
+        //implicit composite
+        Mapper mapperCX = new Mapper(project);
+
+        FileNameMapper mapperDEF = new GlobPatternMapper();
+        mapperDEF.setFrom("c");
+        mapperDEF.setTo("def");
+
+        FileNameMapper mapperGHI = new GlobPatternMapper();
+        mapperGHI.setFrom("c");
+        mapperGHI.setTo("ghi");
+
+        mapperCX.add(mapperDEF);
+        mapperCX.add(mapperGHI);
+
+        Mapper chained = new Mapper(project);
+        chained.setClassname(ChainedMapper.class.getName());
+        chained.add(mapperAB);
+        chained.add(mapperBC);
+        chained.addConfiguredMapper(mapperCX);
+
+        FileNameMapper fileNameMapper = chained.getImplementation();
+        String[] targets = fileNameMapper.mapFileName("a");
+        assertNotNull("no filenames mapped", targets);
+        assertEquals("wrong number of filenames mapped", 2, targets.length);
+        List list = Arrays.asList(targets);
+        assertTrue("cannot find expected target \"def\"", list.contains("def"));
+        assertTrue("cannot find expected target \"ghi\"", list.contains("ghi"));
+    }
+
+    public void testCopyTaskWithTwoFilesets() {
+        TaskdefForCopyTest t = new TaskdefForCopyTest("test1");
+        try {
+            t.setUp();
+            t.test1();
+        } finally {
+            t.tearDown();
+        }
+    }
+
+    private class TaskdefForCopyTest extends BuildFileTest {
+        TaskdefForCopyTest(String name) {
+            super(name);
+        }
+
+        public void setUp() {
+            configureProject("src/etc/testcases/types/mapper.xml");
+        }
+
+        public void tearDown() {
+            executeTarget("cleanup");
+        }
+
+        public void test1() {
+            executeTarget("test1");
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/PathTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/PathTest.java
new file mode 100644
index 0000000..ca944a9
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/PathTest.java
@@ -0,0 +1,563 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.Path
+ *
+ */
+
+public class PathTest extends TestCase {
+
+    public static boolean isUnixStyle = File.pathSeparatorChar == ':';
+    public static boolean isNetWare = Os.isFamily("netware");
+
+    private Project project;
+
+    public PathTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(System.getProperty("root"));
+    }
+
+    // actually tests constructor as well as setPath
+    public void testConstructorUnixStyle() {
+        Path p = new Path(project, "/a:/b");
+        String[] l = p.list();
+        assertEquals("two items, Unix style", 2, l.length);
+        if (isUnixStyle) {
+            assertEquals("/a", l[0]);
+            assertEquals("/b", l[1]);
+        } else if (isNetWare) {
+            assertEquals("\\a", l[0]);
+            assertEquals("\\b", l[1]);
+        } else {
+            String base = new File(File.separator).getAbsolutePath();
+            assertEquals(base + "a", l[0]);
+            assertEquals(base + "b", l[1]);
+        }
+    }
+
+    public void testRelativePathUnixStyle() {
+        project.setBasedir(new File(System.getProperty("root"), "src/etc").getAbsolutePath());
+        Path p = new Path(project, "..:testcases");
+        String[] l = p.list();
+        assertEquals("two items, Unix style", 2, l.length);
+        if (isUnixStyle) {
+           assertTrue("test resolved relative to src/etc",
+                 l[0].endsWith("/src"));
+           assertTrue("test resolved relative to src/etc",
+                 l[1].endsWith("/src/etc/testcases"));
+        } else if (isNetWare) {
+           assertTrue("test resolved relative to src/etc",
+                 l[0].endsWith("\\src"));
+           assertTrue("test resolved relative to src/etc",
+                 l[1].endsWith("\\src\\etc\\testcases"));
+        } else {
+           assertTrue("test resolved relative to src/etc",
+                 l[0].endsWith("\\src"));
+           assertTrue("test resolved relative to src/etc",
+                 l[1].endsWith("\\src\\etc\\testcases"));
+        }
+    }
+
+    public void testConstructorWindowsStyle() {
+        Path p = new Path(project, "\\a;\\b");
+        String[] l = p.list();
+        assertEquals("two items, DOS style", 2, l.length);
+        if (isUnixStyle) {
+            assertEquals("/a", l[0]);
+            assertEquals("/b", l[1]);
+        } else if (isNetWare) {
+            assertEquals("\\a", l[0]);
+            assertEquals("\\b", l[1]);
+        } else {
+            String base = new File(File.separator).getAbsolutePath();
+            assertEquals(base + "a", l[0]);
+            assertEquals(base + "b", l[1]);
+        }
+
+        p = new Path(project, "c:\\test");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 2, l.length);
+            assertTrue("c resolved relative to project\'s basedir",
+                   l[0].endsWith("/c"));
+            assertEquals("/test", l[1]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 1, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+        } else {
+            assertEquals("drives on DOS", 1, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+        }
+
+        p = new Path(project, "c:\\test;d:\\programs");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 4, l.length);
+            assertTrue("c resolved relative to project\'s basedir",
+                   l[0].endsWith("/c"));
+            assertEquals("/test", l[1]);
+            assertTrue("d resolved relative to project\'s basedir",
+                   l[2].endsWith("/d"));
+            assertEquals("/programs", l[3]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 2, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("d:\\programs", l[1].toLowerCase(Locale.US));
+        } else {
+            assertEquals("drives on DOS", 2, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("d:\\programs", l[1].toLowerCase(Locale.US));
+        }
+
+        p = new Path(project, "c:/test");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 2, l.length);
+            assertTrue("c resolved relative to project\'s basedir",
+                   l[0].endsWith("/c"));
+            assertEquals("/test", l[1]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 1, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+        } else {
+            assertEquals("drives on DOS", 1, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+        }
+
+        p = new Path(project, "c:/test;d:/programs");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 4, l.length);
+            assertTrue("c resolved relative to project\'s basedir",
+                   l[0].endsWith("/c"));
+            assertEquals("/test", l[1]);
+            assertTrue("d resolved relative to project\'s basedir",
+                   l[2].endsWith("/d"));
+            assertEquals("/programs", l[3]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 2, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("d:\\programs", l[1].toLowerCase(Locale.US));
+        } else {
+            assertEquals("drives on DOS", 2, l.length);
+            assertEquals("c:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("d:\\programs", l[1].toLowerCase(Locale.US));
+        }
+    }
+
+    public void testConstructorNetWareStyle() {
+        // try a netware-volume length path, see how it is handled
+        Path p = new Path(project, "sys:\\test");
+        String[] l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 2, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("/sys"));
+            assertEquals("/test", l[1]);
+        } else if (isNetWare) {
+            assertEquals("sys:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("volumes on NetWare", 1, l.length);
+        } else {
+            assertEquals("no multiple character-length volumes on Windows", 2, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("\\sys"));
+            assertTrue("test resolved relative to project\'s basedir",
+                   l[1].endsWith("\\test"));
+        }
+
+        // try a multi-part netware-volume length path, see how it is handled
+        p = new Path(project, "sys:\\test;dev:\\temp");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 4, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("/sys"));
+            assertEquals("/test", l[1]);
+            assertTrue("dev resolved relative to project\'s basedir",
+                   l[2].endsWith("/dev"));
+            assertEquals("/temp", l[3]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 2, l.length);
+            assertEquals("sys:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("dev:\\temp", l[1].toLowerCase(Locale.US));
+        } else {
+            assertEquals("no multiple character-length volumes on Windows", 4, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("\\sys"));
+            assertTrue("test resolved relative to project\'s basedir",
+                   l[1].endsWith("\\test"));
+            assertTrue("dev resolved relative to project\'s basedir",
+                   l[2].endsWith("\\dev"));
+            assertTrue("temp resolved relative to project\'s basedir",
+                   l[3].endsWith("\\temp"));
+        }
+
+        // try a netware-volume length path w/forward slash, see how it is handled
+        p = new Path(project, "sys:/test");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 2, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("/sys"));
+            assertEquals("/test", l[1]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 1, l.length);
+            assertEquals("sys:\\test", l[0].toLowerCase(Locale.US));
+        } else {
+            assertEquals("no multiple character-length volumes on Windows", 2, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("\\sys"));
+            assertTrue("test resolved relative to project\'s basedir",
+                   l[1].endsWith("\\test"));
+        }
+
+        // try a multi-part netware-volume length path w/forward slash, see how it is handled
+        p = new Path(project, "sys:/test;dev:/temp");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 4, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("/sys"));
+            assertEquals("/test", l[1]);
+            assertTrue("dev resolved relative to project\'s basedir",
+                   l[2].endsWith("/dev"));
+            assertEquals("/temp", l[3]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 2, l.length);
+            assertEquals("sys:\\test", l[0].toLowerCase(Locale.US));
+            assertEquals("dev:\\temp", l[1].toLowerCase(Locale.US));
+        } else {
+            assertEquals("no multiple character-length volumes on Windows", 4, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("\\sys"));
+            assertTrue("test resolved relative to project\'s basedir",
+                   l[1].endsWith("\\test"));
+            assertTrue("dev resolved relative to project\'s basedir",
+                   l[2].endsWith("\\dev"));
+            assertTrue("temp resolved relative to project\'s basedir",
+                   l[3].endsWith("\\temp"));
+         }
+
+        // try a multi-part netware-volume length path with UNIX
+        // separator (this testcase if from an actual bug that was
+        // found, in AvailableTest, which uses PathTokenizer)
+        p = new Path(project,
+                     "SYS:\\JAVA/lib/rt.jar:SYS:\\JAVA/lib/classes.zip");
+        l = p.list();
+        if (isUnixStyle) {
+            assertEquals("no drives on Unix", 3, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("/SYS"));
+            assertEquals("/JAVA/lib/rt.jar", l[1]);
+            assertEquals("/JAVA/lib/classes.zip", l[2]);
+        } else if (isNetWare) {
+            assertEquals("volumes on NetWare", 2, l.length);
+            assertEquals("sys:\\java\\lib\\rt.jar", l[0].toLowerCase(Locale.US));
+            assertEquals("sys:\\java\\lib\\classes.zip", l[1].toLowerCase(Locale.US));
+        } else {
+            assertEquals("no multiple character-length volumes on Windows", 3, l.length);
+            assertTrue("sys resolved relative to project\'s basedir",
+                   l[0].endsWith("\\SYS"));
+            assertTrue("java/lib/rt.jar resolved relative to project\'s basedir",
+                   l[1].endsWith("\\JAVA\\lib\\rt.jar"));
+            assertTrue("java/lib/classes.zip resolved relative to project\'s basedir",
+                   l[2].endsWith("\\JAVA\\lib\\classes.zip"));
+        }
+    }
+
+    public void testConstructorMixedStyle() {
+        Path p = new Path(project, "\\a;\\b:/c");
+        String[] l = p.list();
+        assertEquals("three items, mixed style", 3, l.length);
+        if (isUnixStyle) {
+            assertEquals("/a", l[0]);
+            assertEquals("/b", l[1]);
+            assertEquals("/c", l[2]);
+        } else if (isNetWare) {
+            assertEquals("\\a", l[0]);
+            assertEquals("\\b", l[1]);
+            assertEquals("\\c", l[2]);
+        } else {
+            String base = new File(File.separator).getAbsolutePath();
+            assertEquals(base + "a", l[0]);
+            assertEquals(base + "b", l[1]);
+            assertEquals(base + "c", l[2]);
+        }
+    }
+
+    public void testSetLocation() {
+        Path p = new Path(project);
+        p.setLocation(new File(File.separatorChar+"a"));
+        String[] l = p.list();
+        if (isUnixStyle) {
+            assertEquals(1, l.length);
+            assertEquals("/a", l[0]);
+        } else if (isNetWare) {
+            assertEquals(1, l.length);
+            assertEquals("\\a", l[0]);
+        } else {
+            assertEquals(1, l.length);
+            assertEquals(":\\a", l[0].substring(1));
+        }
+    }
+
+    public void testAppending() {
+        Path p = new Path(project, "/a:/b");
+        String[] l = p.list();
+        assertEquals("2 after construction", 2, l.length);
+        p.setLocation(new File("/c"));
+        l = p.list();
+        assertEquals("3 after setLocation", 3, l.length);
+        p.setPath("\\d;\\e");
+        l = p.list();
+        assertEquals("5 after setPath", 5, l.length);
+        p.append(new Path(project, "\\f"));
+        l = p.list();
+        assertEquals("6 after append", 6, l.length);
+        p.createPath().setLocation(new File("/g"));
+        l = p.list();
+        assertEquals("7 after append", 7, l.length);
+    }
+
+    public void testEmpyPath() {
+        Path p = new Path(project, "");
+        String[] l = p.list();
+        assertEquals("0 after construction", 0, l.length);
+        p.setPath("");
+        l = p.list();
+        assertEquals("0 after setPath", 0, l.length);
+        p.append(new Path(project));
+        l = p.list();
+        assertEquals("0 after append", 0, l.length);
+        p.createPath();
+        l = p.list();
+        assertEquals("0 after append", 0, l.length);
+    }
+
+    public void testUnique() {
+        Path p = new Path(project, "/a:/a");
+        String[] l = p.list();
+        assertEquals("1 after construction", 1, l.length);
+        String base = new File(File.separator).getAbsolutePath();
+        p.setLocation(new File(base, "a"));
+        l = p.list();
+        assertEquals("1 after setLocation", 1, l.length);
+        p.setPath("\\a;/a");
+        l = p.list();
+        assertEquals("1 after setPath", 1, l.length);
+        p.append(new Path(project, "/a;\\a:\\a"));
+        l = p.list();
+        assertEquals("1 after append", 1, l.length);
+        p.createPath().setPath("\\a:/a");
+        l = p.list();
+        assertEquals("1 after append", 1, l.length);
+    }
+
+    public void testEmptyElementIfIsReference() {
+        Path p = new Path(project, "/a:/a");
+        try {
+            p.setRefid(new Reference(project, "dummyref"));
+            fail("Can add reference to Path with elements from constructor");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        p = new Path(project);
+        p.setLocation(new File("/a"));
+        try {
+            p.setRefid(new Reference(project, "dummyref"));
+            fail("Can add reference to Path with elements from setLocation");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        Path another = new Path(project, "/a:/a");
+        project.addReference("dummyref", another);
+        p = new Path(project);
+        p.setRefid(new Reference(project, "dummyref"));
+        try {
+            p.setLocation(new File("/a"));
+            fail("Can set location in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.setPath("/a;\\a");
+            fail("Can set path in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.createPath();
+            fail("Can create nested Path in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.createPathElement();
+            fail("Can create nested PathElement in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.addFileset(new FileSet());
+            fail("Can add nested FileSet in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.addFilelist(new FileList());
+            fail("Can add nested FileList in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+
+        try {
+            p.addDirset(new DirSet());
+            fail("Can add nested Dirset in Path that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+        Path p = new Path(project);
+        project.addReference("dummy", p);
+        p.setRefid(new Reference(project, "dummy"));
+        try {
+            p.list();
+            fail("Can make Path a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 --> dummy1
+        Path p1 = new Path(project);
+        project.addReference("dummy1", p1);
+        Path p2 = p1.createPath();
+        project.addReference("dummy2", p2);
+        Path p3 = p2.createPath();
+        project.addReference("dummy3", p3);
+        p3.setRefid(new Reference(project, "dummy1"));
+        try {
+            p1.list();
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 (with Path "/a")
+        p1 = new Path(project);
+        project.addReference("dummy1", p1);
+        p2 = p1.createPath();
+        project.addReference("dummy2", p2);
+        p3 = p2.createPath();
+        project.addReference("dummy3", p3);
+        p3.setLocation(new File("/a"));
+        String[] l = p1.list();
+        assertEquals("One element buried deep inside a nested path structure",
+                     1, l.length);
+        if (isUnixStyle) {
+            assertEquals("/a", l[0]);
+        } else if (isNetWare) {
+            assertEquals("\\a", l[0]);
+        } else {
+            assertEquals(":\\a", l[0].substring(1));
+        }
+    }
+
+    public void testFileList() {
+        Path p = new Path(project);
+        FileList f = new FileList();
+        f.setProject(project);
+        f.setDir(project.resolveFile("."));
+        f.setFiles("build.xml");
+        p.addFilelist(f);
+        String[] l = p.list();
+        assertEquals(1, l.length);
+        assertEquals(project.resolveFile("build.xml").getAbsolutePath(), l[0]);
+    }
+
+    public void testFileSet() {
+        Path p = new Path(project);
+        FileSet f = new FileSet();
+        f.setProject(project);
+        f.setDir(project.resolveFile("."));
+        f.setIncludes("build.xml");
+        p.addFileset(f);
+        String[] l = p.list();
+        assertEquals(1, l.length);
+        assertEquals(project.resolveFile("build.xml").getAbsolutePath(), l[0]);
+    }
+
+    public void testDirSet() {
+        Path p = new Path(project);
+        DirSet d = new DirSet();
+        d.setProject(project);
+        d.setDir(project.resolveFile("."));
+        d.setIncludes("build");
+        p.addDirset(d);
+        String[] l = p.list();
+        assertEquals(1, l.length);
+        assertEquals(project.resolveFile("build").getAbsolutePath(), l[0]);
+    }
+
+    public void testRecursion() {
+        Path p = new Path(project);
+        try {
+            p.append(p);
+            assertEquals(0, p.list().length);
+        } catch (BuildException x) {
+            String m = x.toString();
+            assertTrue(m, m.indexOf("circular") != -1);
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java
new file mode 100644
index 0000000..5f30ed7
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/PatternSetTest.java
@@ -0,0 +1,203 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.PatternSet.
+ *
+ * <p>This doesn't actually test much, mainly reference handling.</p>
+ *
+ */
+
+public class PatternSetTest extends TestCase {
+
+    private Project project;
+
+    public PatternSetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    public void testEmptyElementIfIsReference() {
+        PatternSet p = new PatternSet();
+        p.setIncludes("**/*.java");
+        try {
+            p.setRefid(new Reference(project, "dummyref"));
+            fail("Can add reference to PatternSet with elements from setIncludes");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        p = new PatternSet();
+        p.setRefid(new Reference(project, "dummyref"));
+        try {
+            p.setIncludes("**/*.java");
+            fail("Can set includes in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+
+        p = new PatternSet();
+        p.setRefid(new Reference(project, "dummyref"));
+        try {
+            p.setIncludesfile(new File("/a"));
+            fail("Can set includesfile in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.setExcludes("**/*.java");
+            fail("Can set excludes in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.setExcludesfile(new File("/a"));
+            fail("Can set excludesfile in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one attribute when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.createInclude();
+            fail("Can add nested include in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.createExclude();
+            fail("Can add nested exclude in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.createIncludesFile();
+            fail("Can add nested includesfile in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+        try {
+            p.createExcludesFile();
+            fail("Can add nested excludesfile in PatternSet that is a reference.");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+        PatternSet p = new PatternSet();
+        project.addReference("dummy", p);
+        p.setRefid(new Reference(project, "dummy"));
+        try {
+            p.getIncludePatterns(project);
+            fail("Can make PatternSet a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            p.getExcludePatterns(project);
+            fail("Can make PatternSet a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3 --> dummy1
+        PatternSet p1 = new PatternSet();
+        project.addReference("dummy1", p1);
+        p1.setRefid(new Reference(project, "dummy2"));
+        PatternSet p2 = new PatternSet();
+        project.addReference("dummy2", p2);
+        p2.setRefid(new Reference(project, "dummy3"));
+        PatternSet p3 = new PatternSet();
+        project.addReference("dummy3", p3);
+        p3.setRefid(new Reference(project, "dummy1"));
+        try {
+            p1.getIncludePatterns(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+        try {
+            p1.getExcludePatterns(project);
+            fail("Can make circular reference.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        }
+
+        // dummy1 --> dummy2 --> dummy3
+        // (which holds patterns "include" and "exclude")
+        p1 = new PatternSet();
+        project.addReference("dummy1", p1);
+        p1.setRefid(new Reference(project, "dummy2"));
+        p2 = new PatternSet();
+        project.addReference("dummy2", p2);
+        p2.setRefid(new Reference(project, "dummy3"));
+        p3 = new PatternSet();
+        project.addReference("dummy3", p3);
+        p3.setIncludes("include");
+        p3.createExclude().setName("exclude");
+        String[] i = p1.getIncludePatterns(project);
+        assertEquals("One include pattern buried deep inside a nested patternset structure",
+                     1, i.length);
+        assertEquals("include", i[0]);
+        i = p3.getExcludePatterns(project);
+        assertEquals("One exclude pattern buried deep inside a nested patternset structure",
+                     1, i.length);
+        assertEquals("exclude", i[0]);
+    }
+
+    public void testNestedPatternset() {
+        PatternSet p = new PatternSet();
+        p.setIncludes("**/*.java");
+
+        PatternSet nested = new PatternSet();
+        nested.setExcludes("**/*.class");
+
+        p.addConfiguredPatternset(nested);
+
+        String[] excludes = p.getExcludePatterns(project);
+        String[] includes = p.getIncludePatterns(project);
+
+        assertEquals("Includes","**/*.java", includes[0]);
+        assertEquals("Excludes","**/*.class", excludes[0]);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/PermissionsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/PermissionsTest.java
new file mode 100644
index 0000000..7c6e062
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/PermissionsTest.java
@@ -0,0 +1,156 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.ExitException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.Permissions.
+ *
+ */
+public class PermissionsTest extends TestCase {
+
+    Permissions perms;
+
+    public PermissionsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        perms = new Permissions();
+        Permissions.Permission perm = new Permissions.Permission();
+        // Grant extra permissions to read and write the user.* properties and read to the
+        // java.home property
+        perm.setActions("read, write");
+        perm.setName("user.*");
+        perm.setClass("java.util.PropertyPermission");
+        perms.addConfiguredGrant(perm);
+
+        perm = new Permissions.Permission();
+        perm.setActions("read");
+        perm.setName("java.home");
+        perm.setClass("java.util.PropertyPermission");
+        perms.addConfiguredGrant(perm);
+
+        perm = new Permissions.Permission();
+        perm.setActions("read");
+        perm.setName("file.encoding");
+        perm.setClass("java.util.PropertyPermission");
+        perms.addConfiguredGrant(perm);
+
+        // Revoke permission to write user.home (granted above via user.*), still able to read though.
+        // and the default granted permission to read os.name.
+        perm = new Permissions.Permission();
+        perm.setActions("write");
+        perm.setName("user.home");
+        perm.setClass("java.util.PropertyPermission");
+        perms.addConfiguredRevoke(perm);
+
+        perm = new Permissions.Permission();
+        perm.setActions("read");
+        perm.setName("os.*");
+        perm.setClass("java.util.PropertyPermission");
+        perms.addConfiguredRevoke(perm);
+    }
+
+    /** Tests a permission that is granted per default. */
+    public void testDefaultGranted() {
+        perms.setSecurityManager();
+        try {
+            String s = System.getProperty("line.separator");
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+
+    /** Tests a permission that has been granted later via wildcard. */
+    public void testGranted() {
+        perms.setSecurityManager();
+        try {
+            String s = System.getProperty("user.name");
+            System.setProperty("user.name", s);
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+
+    /** Tests a permission that has been granted and revoked later. */
+    public void testGrantedAndRevoked() {
+        perms.setSecurityManager();
+        try {
+            String s = System.getProperty("user.home");
+            System.setProperty("user.home", s);
+            fail("Could perform an action that should have been forbidden.");
+        } catch (SecurityException e){
+            // Was expected, test passes
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+
+    /** Tests a permission that is granted as per default but revoked later via wildcard. */
+    public void testDefaultRevoked() {
+        perms.setSecurityManager();
+        try {
+            System.getProperty("os.name");
+            fail("Could perform an action that should have been forbidden.");
+        } catch (SecurityException e){
+            // Was expected, test passes
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+    /** Tests a permission that has not been granted or revoked. */
+    public void testOther() {
+        String ls = System.getProperty("line.separator");
+        perms.setSecurityManager();
+        try {
+            String s = System.setProperty("line.separator",ls);
+            fail("Could perform an action that should have been forbidden.");
+        } catch (SecurityException e){
+            // Was expected, test passes
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+
+    /** Tests an exit condition. */
+    public void testExit() {
+        perms.setSecurityManager();
+        try {
+            System.out.println("If this is the last line on standard out the testExit f.a.i.l.e.d");
+            System.exit(3);
+            fail("Totaly impossible that this fail is ever executed. Please let me know if it is!");
+        } catch (ExitException e) {
+            if (e.getStatus() != 3) {
+                fail("Received wrong exit status in Exit Exception.");
+            }
+            System.out.println("testExit successful.");
+        } finally {
+            perms.restoreSecurityManager();
+        }
+    }
+
+
+    public void tearDown() {
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/PolyTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/PolyTest.java
new file mode 100644
index 0000000..fe6d286
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/PolyTest.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+public class PolyTest extends BuildFileTest {
+
+    public PolyTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/poly.xml");
+    }
+
+    public void testFileSet() {
+        expectLogContaining("fileset", "types.FileSet");
+    }
+
+    public void testFileSetAntType() {
+        expectLogContaining("fileset-ant-type", "types.PolyTest$MyFileSet");
+    }
+
+    public void testPath() {
+        expectLogContaining("path", "types.Path");
+    }
+
+    public void testPathAntType() {
+        expectLogContaining("path-ant-type", "types.PolyTest$MyPath");
+    }
+
+    public static class MyFileSet extends FileSet {}
+
+    public static class MyPath extends Path {
+        public MyPath(Project project) {
+            super(project);
+        }
+    }
+
+    public static class MyTask extends Task {
+        public void addPath(Path path) {
+            log("class of path is " + path.getClass());
+        }
+        public void addFileset(FileSet fileset) {
+            log("class of fileset is " + fileset.getClass());
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/PropertySetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/PropertySetTest.java
new file mode 100644
index 0000000..aea7f92
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/PropertySetTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class PropertySetTest extends BuildFileTest {
+
+    public PropertySetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/propertyset.xml");
+    }
+
+    public void testReferenceToTwoReferences() {
+        executeTarget("reference-to-two-references");
+    }
+
+    public void testNestedMapped() {
+        executeTarget("nested-mapped");
+    }
+
+    public void testNestedMappedMapped() {
+        executeTarget("nested-mapped-mapped");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/RedirectorElementTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/RedirectorElementTest.java
new file mode 100755
index 0000000..678b7b2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/RedirectorElementTest.java
@@ -0,0 +1,64 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.BuildFileTest;
+
+public class RedirectorElementTest extends BuildFileTest {
+
+    public RedirectorElementTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/redirector.xml", Project.MSG_VERBOSE);
+    }
+
+    public void test1() {
+        executeTarget("test1");
+        assertTrue((getProject().getReference("test1")
+            instanceof RedirectorElement));
+    }
+
+    public void test2() {
+        expectBuildException("test2", "You must not specify more than one "
+            + "attribute when using refid");
+    }
+
+    public void test3() {
+        expectBuildException("test3", "You must not specify nested elements "
+            + "when using refid");
+    }
+
+    public void test4() {
+        executeTarget("test4");
+    }
+
+    public void testLogInputString() {
+        executeTarget("testLogInputString");
+        if (super.getLog().indexOf("testLogInputString can-cat") >=0 ) {
+            assertDebuglogContaining("Using input string");
+        }
+    }
+
+    public void testRefid() {
+        executeTarget("testRefid");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceComparatorsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceComparatorsTest.java
new file mode 100755
index 0000000..0b39a60
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceComparatorsTest.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class ResourceComparatorsTest extends BuildFileTest {
+
+    public ResourceComparatorsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/resources/comparators/build.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("tearDown");
+    }
+
+    public void testcompoundsort1() {
+        executeTarget("testcompoundsort1");
+    }
+
+    public void testcompoundsort2() {
+        executeTarget("testcompoundsort2");
+    }
+
+    public void testcontent() {
+        executeTarget("testcontent");
+    }
+
+    public void testexists() {
+        executeTarget("testexists");
+    }
+
+    public void testdate() {
+        executeTarget("testdate");
+    }
+
+    public void testname() {
+        executeTarget("testname");
+    }
+
+    public void testrvcontent() {
+        executeTarget("testrvcontent");
+    }
+
+    public void testrvdefault() {
+        executeTarget("testrvdefault");
+    }
+
+    public void testrvexists() {
+        executeTarget("testrvexists");
+    }
+
+    public void testrvdate() {
+        executeTarget("testrvdate");
+    }
+
+    public void testrvname() {
+        executeTarget("testrvname");
+    }
+
+    public void testrvsize() {
+        executeTarget("testrvsize");
+    }
+
+    public void testrvtype() {
+        executeTarget("testrvtype");
+    }
+
+    public void testsize() {
+        executeTarget("testsize");
+    }
+
+    public void testsortdefault() {
+        executeTarget("testsortdefault");
+    }
+
+    public void testtype() {
+        executeTarget("testtype");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceOutputTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceOutputTest.java
new file mode 100755
index 0000000..f0ec5e4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/ResourceOutputTest.java
@@ -0,0 +1,152 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.UnknownServiceException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Zip;
+import org.apache.tools.ant.types.resources.ImmutableResourceException;
+import org.apache.tools.ant.types.resources.PropertyResource;
+import org.apache.tools.ant.types.resources.StringResource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.types.resources.ZipResource;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.ResourceUtils;
+
+public class ResourceOutputTest extends BuildFileTest {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private static final File basedir = new File(System.getProperty("root"),
+        "src/etc/testcases/types/resources");
+
+    public ResourceOutputTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.init();
+        project.setUserProperty("basedir" , basedir.getAbsolutePath());
+    }
+
+    public void testresourceoutput() {
+        try {
+            testoutputbe(new Resource("foo"));
+            fail("should have caught UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+        }
+    }
+
+    public void teststringoutput1() {
+        StringResource r = new StringResource();
+        testoutputbe(r);
+        assertEquals("foo", r.getValue());
+    }
+
+    public void teststringoutput2() {
+        StringResource r = new StringResource("bar");
+        try {
+            testoutput(r);
+            fail("should have caught ImmutableResourceException");
+        } catch (ImmutableResourceException e) {
+        } catch (IOException e) {
+            fail("caught some other IOException: " + e);
+        }
+        assertEquals("bar", r.getValue());
+    }
+
+    public void testpropertyoutput1() {
+        PropertyResource r = new PropertyResource(getProject(), "bar");
+        testoutputbe(r);
+        assertPropertyEquals("bar", "foo");
+    }
+
+    public void testpropertyoutput2() {
+        getProject().setNewProperty("bar", "bar");
+        PropertyResource r = new PropertyResource(getProject(), "bar");
+        try {
+            testoutput(r);
+            fail("should have caught ImmutableResourceException");
+        } catch (ImmutableResourceException e) {
+        } catch (IOException e) {
+            fail("caught some other IOException: " + e);
+        }
+        assertPropertyEquals("bar", "bar");
+    }
+
+    public void testurloutput() {
+        File f = getProject().resolveFile("testurloutput");
+        try {
+            FILE_UTILS.createNewFile(f);
+            testoutput(new URLResource(f));
+            fail("should have caught UnknownServiceException");
+        } catch (UnknownServiceException e) {
+        } catch (IOException e) {
+            e.printStackTrace(System.err);
+            fail("caught some other IOException: " + e);
+        } finally {
+            if (!f.delete()) {
+                f.deleteOnExit();
+            }
+        }
+    }
+
+    public void testzipentryoutput() {
+        Zip z = new Zip();
+        z.setProject(getProject());
+        Zip.WhenEmpty create = new Zip.WhenEmpty();
+        create.setValue("create");
+        z.setWhenempty(create);
+        z.setBasedir(basedir);
+        z.setExcludes("**/*");
+        File f = getProject().resolveFile("foo");
+        z.setDestFile(f);
+        z.execute();
+        ZipResource r = new ZipResource();
+        r.setZipfile(f);
+        r.setName("foo");
+        try {
+            testoutputbe(r);
+            fail("should have caught UnsupportedOperationException");
+        } catch (UnsupportedOperationException e) {
+        } finally {
+            if (!f.delete()) {
+                f.deleteOnExit();
+            }
+        }
+    }
+
+    private void testoutputbe(Resource dest) {
+        try {
+            testoutput(dest);
+        } catch (IOException e) {
+            throw new BuildException(e);
+        }
+    }
+
+    private void testoutput(Resource dest) throws IOException {
+        ResourceUtils.copyResource(new StringResource("foo"), dest, null);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/TarFileSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/TarFileSetTest.java
new file mode 100755
index 0000000..d0d570b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/TarFileSetTest.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.TarFileSet.
+ *
+ * <p>This doesn't actually test much, mainly reference handling.
+ *
+ */
+
+public class TarFileSetTest extends AbstractFileSetTest {
+
+    public TarFileSetTest(String name) {
+        super(name);
+    }
+
+    protected AbstractFileSet getInstance() {
+        return new TarFileSet();
+    }
+    public final void testAttributes() {
+        TarFileSet f = (TarFileSet)getInstance();
+        //check that dir and src are incompatible
+        f.setSrc(new File("example.tar"));
+        try {
+            f.setDir(new File("examples"));
+            fail("can add dir to "
+                    + f.getDataTypeName()
+                    + " when a src is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both dir and src attributes",be.getMessage());
+        }
+        f = (TarFileSet)getInstance();
+        //check that dir and src are incompatible
+        f.setDir(new File("examples"));
+        try {
+            f.setSrc(new File("example.tar"));
+            fail("can add src to "
+                    + f.getDataTypeName()
+                    + " when a dir is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both dir and src attributes",be.getMessage());
+        }
+        //check that fullpath and prefix are incompatible
+        f = (TarFileSet)getInstance();
+        f.setSrc(new File("example.tar"));
+        f.setPrefix("/examples");
+        try {
+            f.setFullpath("/doc/manual/index.html");
+            fail("Can add fullpath to "
+                    + f.getDataTypeName()
+                    + " when a prefix is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both fullpath and prefix attributes", be.getMessage());
+        }
+        f = (TarFileSet)getInstance();
+        f.setSrc(new File("example.tar"));
+        f.setFullpath("/doc/manual/index.html");
+        try {
+            f.setPrefix("/examples");
+            fail("Can add prefix to "
+                    + f.getDataTypeName()
+                    + " when a fullpath is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both fullpath and prefix attributes", be.getMessage());
+        }
+        // check that reference tarfilesets cannot have specific attributes
+        f = (TarFileSet)getInstance();
+        f.setRefid(new Reference(getProject(), "test"));
+        try {
+            f.setSrc(new File("example.tar"));
+            fail("Can add src to "
+                    + f.getDataTypeName()
+                    + " when a refid is already present");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one "
+            + "attribute when using refid", be.getMessage());
+        }
+        // check that a reference tarfileset gets the same attributes as the original
+        f = (TarFileSet)getInstance();
+        f.setSrc(new File("example.tar"));
+        f.setPrefix("/examples");
+        f.setFileMode("600");
+        f.setDirMode("530");
+        getProject().addReference("test",f);
+        TarFileSet zid=(TarFileSet)getInstance();
+        zid.setRefid(new Reference(getProject(), "test"));
+        assertTrue("src attribute copied by copy constructor",zid.getSrc(getProject()).equals(f.getSrc(getProject())));
+        assertTrue("prefix attribute copied by copy constructor",f.getPrefix(getProject()).equals(zid.getPrefix(getProject())));
+        assertTrue("file mode attribute copied by copy constructor",f.getFileMode(getProject())==zid.getFileMode(getProject()));
+        assertTrue("dir mode attribute copied by copy constructor",f.getDirMode(getProject())==zid.getDirMode(getProject()));
+      }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogBuildFileTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogBuildFileTest.java
new file mode 100644
index 0000000..6d487af
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogBuildFileTest.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * BuildFileTest testcases for org.apache.tools.ant.types.XMLCatalog
+ *
+ * @see org.apache.tools.ant.types.XMLCatalogTest
+ *
+ */
+public class XMLCatalogBuildFileTest extends BuildFileTest {
+
+    public XMLCatalogBuildFileTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+    }
+
+    public void tearDown() {
+    }
+
+    //
+    // Ensure that an external entity resolves as expected with NO
+    // XMLCatalog involvement:
+    //
+    // Transform an XML file that refers to the entity into a text
+    // file, stuff result into property: val1
+    //
+    public void testEntityNoCatalog() {
+        configureProject("src/etc/testcases/types/xmlcatalog.xml");
+        expectPropertySet("testentitynocatalog", "val1",
+                          "A stitch in time saves nine");
+    }
+
+    //
+    // Ensure that an external entity resolves as expected Using an
+    // XMLCatalog:
+    //
+    // Transform an XML file that refers to the entity into a text
+    // file, entity is listed in the XMLCatalog pointing to a
+    // different file.  Stuff result into property: val2
+    //
+    public void testEntityWithCatalog() {
+        configureProject("src/etc/testcases/types/xmlcatalog.xml");
+        expectPropertySet("testentitywithcatalog", "val2",
+                          "No news is good news");
+    }
+
+    //
+    // Ensure that an external entity resolves as expected with NO
+    // XMLCatalog involvement:
+    //
+    // Transform an XML file that contains a reference to a _second_ XML file
+    // via the document() function.  The _second_ XML file refers to an entity.
+    // Stuff result into the property: val3
+    //
+    public void testDocumentNoCatalog() {
+        configureProject("src/etc/testcases/types/xmlcatalog.xml");
+        expectPropertySet("testdocumentnocatalog", "val3",
+                          "A stitch in time saves nine");
+    }
+
+    //
+    // Ensure that an external entity resolves as expected Using an
+    // XMLCatalog:
+    //
+    // Transform an XML file that contains a reference to a _second_ XML file
+    // via the document() function.  The _second_ XML file refers to an entity.
+    // The entity is listed in the XMLCatalog pointing to a different file.
+    // Stuff result into the property: val4
+    //
+    public void testDocumentWithCatalog() {
+        configureProject("src/etc/testcases/types/xmlcatalog.xml");
+        expectPropertySet("testdocumentwithcatalog", "val4",
+                          "No news is good news");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogTest.java
new file mode 100644
index 0000000..2671648
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/XMLCatalogTest.java
@@ -0,0 +1,411 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.sax.SAXSource;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.JAXPUtils;
+import org.xml.sax.InputSource;
+
+/**
+ * JUnit testcases for org.apache.tools.ant.types.XMLCatalog
+ *
+ */
+public class XMLCatalogTest extends TestCase {
+
+    private Project project;
+    private XMLCatalog catalog;
+
+    private XMLCatalog newCatalog() {
+        XMLCatalog cat = new XMLCatalog();
+        cat.setProject(project);
+        return cat;
+    }
+
+    private String toURLString(File file) throws MalformedURLException {
+        return JAXPUtils.getSystemId(file);
+    }
+
+    public XMLCatalogTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(System.getProperty("root"));
+
+        // This causes XMLCatalog to print out detailed logging
+        // messages for debugging
+        //
+        // DefaultLogger logger = new DefaultLogger();
+        // logger.setMessageOutputLevel(Project.MSG_DEBUG);
+        // logger.setOutputPrintStream(System.out);
+        // logger.setErrorPrintStream(System.err);
+        // project.addBuildListener(logger);
+
+        catalog = newCatalog();
+    }
+
+   public void tearDown() {
+      project = null;
+      catalog = null;
+   }
+
+   public void testEmptyCatalog() {
+       try {
+           InputSource result = catalog.resolveEntity("PUBLIC ID ONE",
+                                                      "i/dont/exist.dtd");
+           assertNull("Empty catalog should return null", result);
+       } catch (Exception e) {
+           fail("resolveEntity() failed!" + e.toString());
+       }
+
+       try {
+           Source result = catalog.resolve("i/dont/exist.dtd", null);
+           String expected = toURLString(new File(project.getBaseDir() +
+                                                  "/i/dont/exist.dtd"));
+           //
+           // These shenanigans are necessary b/c Norm Walsh's resolver
+           // has a different idea of how file URLs are created on windoze
+           // ie file://c:/foo instead of file:///c:/foo
+           //
+           String resultStr = new URL(((SAXSource)result).getInputSource().getSystemId()).getFile();
+           assertTrue("Empty catalog should return input",
+                      expected.endsWith(resultStr));
+       } catch (Exception e) {
+           fail("resolve() failed!" + e.toString());
+       }
+   }
+
+    public void testNonExistentEntry() {
+
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId("PUBLIC ID ONE");
+        dtd.setLocation("i/dont/exist.dtd");
+
+        try {
+            InputSource result = catalog.resolveEntity("PUBLIC ID ONE",
+                                                       "i/dont/exist.dtd");
+            assertNull("Nonexistent Catalog entry should not be returned", result);
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+        try {
+            Source result = catalog.resolve("i/dont/exist.dtd", null);
+            String expected = toURLString(new File(project.getBaseDir().toURL() +
+                                                   "/i/dont/exist.dtd"));
+            String resultStr = new URL(((SAXSource)result).getInputSource().getSystemId()).getFile();
+            assertTrue("Nonexistent Catalog entry return input",
+                       expected.endsWith(resultStr));
+        } catch (Exception e) {
+            fail("resolve() failed!" + e.toString());
+        }
+    }
+
+    public void testEmptyElementIfIsReference() {
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId("PUBLIC ID ONE");
+        dtd.setLocation("i/dont/exist.dtd");
+        catalog.addDTD(dtd);
+        project.addReference("catalog", catalog);
+
+        try {
+            catalog.setRefid(new Reference(project, "dummyref"));
+            fail("Can add reference to nonexistent XMLCatalog");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one "
+                         + "attribute when using refid", be.getMessage());
+        }
+
+        XMLCatalog catalog2 = newCatalog();
+        catalog2.setRefid(new Reference(project, "catalog"));
+
+        try {
+            catalog2.addConfiguredXMLCatalog(catalog);
+            fail("Can add nested XMLCatalog to XMLCatalog that is a reference");
+        } catch (BuildException be) {
+            assertEquals("You must not specify nested elements when using refid",
+                         be.getMessage());
+        }
+    }
+
+    public void testCircularReferenceCheck() {
+
+        // catalog <--> catalog
+        project.addReference("catalog", catalog);
+        catalog.setRefid(new Reference(project, "catalog"));
+
+        try {
+            InputSource result = catalog.resolveEntity("PUBLIC ID ONE",
+                                                       "i/dont/exist.dtd");
+            fail("Can make XMLCatalog a Reference to itself.");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+        // catalog1 --> catalog2 --> catalog3 --> catalog1
+        XMLCatalog catalog1 = newCatalog();
+        project.addReference("catalog1", catalog1);
+        XMLCatalog catalog2 = newCatalog();
+        project.addReference("catalog2", catalog2);
+        XMLCatalog catalog3 = newCatalog();
+        project.addReference("catalog3", catalog3);
+
+        catalog3.setRefid(new Reference(project, "catalog1"));
+        catalog2.setRefid(new Reference(project, "catalog3"));
+        catalog1.setRefid(new Reference(project, "catalog2"));
+
+        try {
+            InputSource result = catalog1.resolveEntity("PUBLIC ID ONE",
+                                                        "i/dont/exist.dtd");
+            fail("Can make circular reference");
+        } catch (BuildException be) {
+            assertEquals("This data type contains a circular reference.",
+                         be.getMessage());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+    }
+    // inspired by Bugzilla Report 23913
+    // a problem used to happen under Windows when the location of the DTD was given as an absolute path
+    // possibly with a mixture of file separators
+    public void testAbsolutePath() {
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId("-//stevo//DTD doc 1.0//EN");
+
+        String sysid = System.getProperty("root") + File.separator + "src/etc/testcases/taskdefs/optional/xml/doc.dtd";
+        dtd.setLocation(sysid);
+        catalog.addDTD(dtd);
+        File dtdFile = project.resolveFile(sysid);
+
+        try {
+            InputSource result = catalog.resolveEntity("-//stevo//DTD doc 1.0//EN",
+                                                       "nap:chemical+brothers");
+            assertNotNull(result);
+            assertEquals(toURLString(dtdFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+    }
+
+    public void testSimpleEntry() {
+
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId("-//stevo//DTD doc 1.0//EN");
+        String sysid = "src/etc/testcases/taskdefs/optional/xml/doc.dtd";
+        dtd.setLocation(sysid);
+        catalog.addDTD(dtd);
+        File dtdFile = project.resolveFile(sysid);
+
+        try {
+            InputSource result = catalog.resolveEntity("-//stevo//DTD doc 1.0//EN",
+                                                       "nap:chemical+brothers");
+            assertNotNull(result);
+            assertEquals(toURLString(dtdFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+    }
+
+    public void testEntryReference() {
+
+        String publicId = "-//stevo//DTD doc 1.0//EN";
+        String sysid = "src/etc/testcases/taskdefs/optional/xml/doc.dtd";
+
+        // catalog2 --> catalog1 --> catalog
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId(publicId);
+        dtd.setLocation(sysid);
+        catalog.addDTD(dtd);
+        File dtdFile = project.resolveFile(sysid);
+
+        String uri = "http://foo.com/bar/blah.xml";
+        String uriLoc = "src/etc/testcases/taskdefs/optional/xml/about.xml";
+
+        ResourceLocation entity = new ResourceLocation();
+        entity.setPublicId(uri);
+        entity.setLocation(uriLoc);
+        catalog.addEntity(entity);
+        File xmlFile = project.resolveFile(uriLoc);
+
+        project.addReference("catalog", catalog);
+
+        XMLCatalog catalog1 = newCatalog();
+        project.addReference("catalog1", catalog1);
+        XMLCatalog catalog2 = newCatalog();
+        project.addReference("catalog2", catalog1);
+
+        catalog1.setRefid(new Reference(project, "catalog"));
+        catalog2.setRefid(new Reference(project, "catalog1"));
+
+        try {
+            InputSource result = catalog2.resolveEntity(publicId,
+                                                        "nap:chemical+brothers");
+
+            assertNotNull(result);
+            assertEquals(toURLString(dtdFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+        try {
+            Source result = catalog.resolve(uri, null);
+            assertNotNull(result);
+            assertEquals(toURLString(xmlFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolve() failed!" + e.toString());
+        }
+    }
+
+    public void testNestedCatalog() {
+
+        String publicId = "-//stevo//DTD doc 1.0//EN";
+        String dtdLoc = "src/etc/testcases/taskdefs/optional/xml/doc.dtd";
+
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId(publicId);
+        dtd.setLocation(dtdLoc);
+        catalog.addDTD(dtd);
+        File dtdFile = project.resolveFile(dtdLoc);
+
+        String uri = "http://foo.com/bar/blah.xml";
+        String uriLoc = "src/etc/testcases/taskdefs/optional/xml/about.xml";
+
+        ResourceLocation entity = new ResourceLocation();
+        entity.setPublicId(uri);
+        entity.setLocation(uriLoc);
+        catalog.addEntity(entity);
+        File xmlFile = project.resolveFile(uriLoc);
+
+        XMLCatalog catalog1 = newCatalog();
+        catalog1.addConfiguredXMLCatalog(catalog);
+
+        try {
+            InputSource result = catalog1.resolveEntity(publicId,
+                                                        "nap:chemical+brothers");
+            assertNotNull(result);
+            assertEquals(toURLString(dtdFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+        try {
+            Source result = catalog.resolve(uri, null);
+            assertNotNull(result);
+            assertEquals(toURLString(xmlFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolve() failed!" + e.toString());
+        }
+
+    }
+
+    public void testResolverBase() {
+
+        String uri = "http://foo.com/bar/blah.xml";
+        String uriLoc = "etc/testcases/taskdefs/optional/xml/about.xml";
+        String base = null;
+        try {
+            base = toURLString(project.getBaseDir()) + "/src/";
+        } catch (MalformedURLException ex) {
+            fail (ex.toString());
+        }
+
+        ResourceLocation entity = new ResourceLocation();
+        entity.setPublicId(uri);
+        entity.setLocation(uriLoc);
+        catalog.addEntity(entity);
+        File xmlFile = project.resolveFile("src/" + uriLoc);
+
+        try {
+            Source result = catalog.resolve(uri, base);
+            assertNotNull(result);
+            assertEquals(toURLString(xmlFile),
+                         result.getSystemId());
+        } catch (Exception e) {
+            fail("resolve() failed!" + e.toString());
+        }
+    }
+
+    public void testClasspath() {
+
+
+        String publicId = "-//stevo//DTD doc 1.0//EN";
+        String dtdLoc = "testcases/taskdefs/optional/xml/doc.dtd";
+        String path1 = project.getBaseDir().toString() + "/src/etc";
+
+        ResourceLocation dtd = new ResourceLocation();
+        dtd.setPublicId(publicId);
+        dtd.setLocation(dtdLoc);
+        catalog.addDTD(dtd);
+        File dtdFile = project.resolveFile("src/etc/" + dtdLoc);
+
+        String uri = "http://foo.com/bar/blah.xml";
+        String uriLoc = "etc/testcases/taskdefs/optional/xml/about.xml";
+        String path2 = project.getBaseDir().toString() + "/src";
+
+        ResourceLocation entity = new ResourceLocation();
+        entity.setPublicId(uri);
+        entity.setLocation(uriLoc);
+        catalog.addEntity(entity);
+        File xmlFile = project.resolveFile("src/" + uriLoc);
+
+        Path aPath = new Path(project, path1);
+        aPath.append(new Path(project, path2));
+        catalog.setClasspath(aPath);
+
+        try {
+            InputSource result = catalog.resolveEntity(publicId,
+                                                       "nap:chemical+brothers");
+            assertNotNull(result);
+            String resultStr = new URL(result.getSystemId()).getFile();
+            assertTrue(toURLString(dtdFile).endsWith(resultStr));
+        } catch (Exception e) {
+            fail("resolveEntity() failed!" + e.toString());
+        }
+
+        try {
+            Source result = catalog.resolve(uri, null);
+            assertNotNull(result);
+            String resultStr = new URL(result.getSystemId()).getFile();
+            assertTrue(toURLString(xmlFile).endsWith(resultStr));
+        } catch (Exception e) {
+            fail("resolve() failed!" + e.toString());
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/ZipFileSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/ZipFileSetTest.java
new file mode 100644
index 0000000..19b2582
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/ZipFileSetTest.java
@@ -0,0 +1,115 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.ant.types.ZipFileSet.
+ *
+ * <p>This doesn't actually test much, mainly reference handling.
+ *
+ */
+
+public class ZipFileSetTest extends AbstractFileSetTest {
+
+    public ZipFileSetTest(String name) {
+        super(name);
+    }
+
+    protected AbstractFileSet getInstance() {
+        return new ZipFileSet();
+    }
+    public final void testAttributes() {
+        ZipFileSet f = (ZipFileSet)getInstance();
+        //check that dir and src are incompatible
+        f.setSrc(new File("example.zip"));
+        try {
+            f.setDir(new File("examples"));
+            fail("can add dir to "
+                    + f.getDataTypeName()
+                    + " when a src is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both dir and src attributes",be.getMessage());
+        }
+        f = (ZipFileSet)getInstance();
+        //check that dir and src are incompatible
+        f.setDir(new File("examples"));
+        try {
+            f.setSrc(new File("example.zip"));
+            fail("can add src to "
+                    + f.getDataTypeName()
+                    + " when a dir is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both dir and src attributes",be.getMessage());
+        }
+        //check that fullpath and prefix are incompatible
+        f = (ZipFileSet)getInstance();
+        f.setSrc(new File("example.zip"));
+        f.setPrefix("/examples");
+        try {
+            f.setFullpath("/doc/manual/index.html");
+            fail("Can add fullpath to "
+                    + f.getDataTypeName()
+                    + " when a prefix is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both fullpath and prefix attributes", be.getMessage());
+        }
+        f = (ZipFileSet)getInstance();
+        f.setSrc(new File("example.zip"));
+        f.setFullpath("/doc/manual/index.html");
+        try {
+            f.setPrefix("/examples");
+            fail("Can add prefix to "
+                    + f.getDataTypeName()
+                    + " when a fullpath is already present");
+        } catch (BuildException be) {
+            assertEquals("Cannot set both fullpath and prefix attributes", be.getMessage());
+        }
+        // check that reference zipfilesets cannot have specific attributes
+        f = (ZipFileSet)getInstance();
+        f.setRefid(new Reference(getProject(), "test"));
+        try {
+            f.setSrc(new File("example.zip"));
+            fail("Can add src to "
+                    + f.getDataTypeName()
+                    + " when a refid is already present");
+        } catch (BuildException be) {
+            assertEquals("You must not specify more than one "
+            + "attribute when using refid", be.getMessage());
+        }
+        // check that a reference zipfileset gets the same attributes as the original
+        f = (ZipFileSet)getInstance();
+        f.setSrc(new File("example.zip"));
+        f.setPrefix("/examples");
+        f.setFileMode("600");
+        f.setDirMode("530");
+        getProject().addReference("test",f);
+        ZipFileSet zid=(ZipFileSet)getInstance();
+        zid.setRefid(new Reference(getProject(), "test"));
+        assertTrue("src attribute copied by copy constructor",zid.getSrc(getProject()).equals(f.getSrc(getProject())));
+        assertTrue("prefix attribute copied by copy constructor",f.getPrefix(getProject()).equals(zid.getPrefix(getProject())));
+        assertTrue("file mode attribute copied by copy constructor",f.getFileMode(getProject())==zid.getFileMode(getProject()));
+        assertTrue("dir mode attribute copied by copy constructor",f.getDirMode(getProject())==zid.getDirMode(getProject()));
+      }
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/GlobMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/GlobMapperTest.java
new file mode 100644
index 0000000..71a79d3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/GlobMapperTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.mappers;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the &lt;globmapper&gt; mapper.
+ *
+ */
+public class GlobMapperTest extends BuildFileTest {
+    public GlobMapperTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/types/mappers/globmapper.xml");
+    }
+
+    public void testIgnoreCase() {
+        executeTarget("ignore.case");
+    }
+    public void testHandleDirSep() {
+        executeTarget("handle.dirsep");
+    }
+}
+
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/MapperResult.java b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/MapperResult.java
new file mode 100644
index 0000000..43a7b29
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/MapperResult.java
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.mappers;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.util.FileNameMapper;
+
+/**
+ * This is a test task to show the result of a mapper
+ * on a specific input.
+ * (Test is not in the name of the class, to make sure that
+ * it is not treated as a unit test.
+ */
+
+public class MapperResult extends Task {
+
+    private String failMessage = "";
+    private String input;
+    private String output;
+    private FileNameMapper fileNameMapper;
+
+    /**
+     * The output on an empty string array
+     */
+    private static final String NULL_MAPPER_RESULT = "<NULL>";
+
+    public void setFailMessage(String failMessage) {
+        this.failMessage = failMessage;
+    }
+    
+    public void setInput(String input) {
+        this.input = input;
+    }
+
+    public void setOutput(String output) {
+        this.output = output;
+    }
+
+    public void addConfiguredMapper(Mapper mapper) {
+        add(mapper.getImplementation());
+    }
+
+    public void add(FileNameMapper fileNameMapper) {
+        if (this.fileNameMapper != null) {
+            throw new BuildException("Only one mapper type nested element allowed");
+        }
+        this.fileNameMapper = fileNameMapper;
+    }
+        
+    public void execute() {
+        if (input == null) {
+            throw new BuildException("Missing attribute 'input'");
+        }
+        if (output == null) {
+            throw new BuildException("Missing attribute 'output'");
+        }
+        if (fileNameMapper == null) {
+            throw new BuildException("Missing a nested file name mapper type element");
+        }
+        String[] result = fileNameMapper.mapFileName(input);
+        String flattened;
+        if (result == null) {
+            flattened = NULL_MAPPER_RESULT;
+        } else {
+            StringBuffer b = new StringBuffer();
+            for (int i = 0; i < result.length; ++i) {
+                if (i != 0) {
+                    b.append("|");
+                }
+                b.append(result[i]);
+            }
+            flattened = b.toString();
+        }
+        if (!flattened.equals(output)) {
+            throw new BuildException(
+                failMessage
+                + " "
+                + "got "
+                + flattened
+                + " "
+                + "expected "
+                + output);
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/RegexpPatternMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/RegexpPatternMapperTest.java
new file mode 100644
index 0000000..a3c1c3a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/mappers/RegexpPatternMapperTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.mappers;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the &lt;regexpmapper&gt; mapper.
+ *
+ */
+public class RegexpPatternMapperTest extends BuildFileTest {
+    public RegexpPatternMapperTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/types/mappers/regexpmapper.xml");
+    }
+
+    public void testIgnoreCase() {
+        executeTarget("ignore.case");
+    }
+    public void testHandleDirSep() {
+        executeTarget("handle.dirsep");
+    }
+}
+
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptMapperTest.java
new file mode 100644
index 0000000..208e7a1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptMapperTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test our script mapping
+ */
+public class ScriptMapperTest extends BuildFileTest {
+    public ScriptMapperTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/mappers/scriptmapper.xml");
+    }
+
+    public void testClear() {
+        executeTarget("testClear");
+    }
+    public void testSetMultiple() {
+        executeTarget("testSetMultiple");
+    }
+    public void testPassthrough() {
+        executeTarget("testPassthrough");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptSelectorTest.java
new file mode 100644
index 0000000..1052669
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/ScriptSelectorTest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.optional;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Test that scripting selection works. Needs scripting support to work
+ */
+public class ScriptSelectorTest extends BuildFileTest {
+
+
+    public ScriptSelectorTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/selectors/scriptselector.xml");
+    }
+
+    public void testNolanguage() {
+        expectBuildExceptionContaining("testNolanguage",
+                "Absence of language attribute not detected",
+                "script language must be specified");
+    }
+
+    public void testSelectionSetByDefault() {
+        executeTarget("testSelectionSetByDefault");
+    }
+    public void testSelectionSetWorks() {
+        executeTarget("testSelectionSetWorks");
+    }
+    public void testSelectionClearWorks() {
+        executeTarget("testSelectionClearWorks");
+    }
+    public void testFilenameAttribute() {
+        executeTarget("testFilenameAttribute");
+    }
+    public void testFileAttribute() {
+        executeTarget("testFileAttribute");
+    }
+    public void testBasedirAttribute() {
+        executeTarget("testBasedirAttribute");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java
new file mode 100644
index 0000000..0f97b88
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/optional/depend/ClassFileSetTest.java
@@ -0,0 +1,177 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.optional.depend;
+
+import java.io.File;
+import java.util.Hashtable;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+
+/**
+ * Testcase for the Classfileset optional type.
+ *
+ */
+public class ClassFileSetTest extends BuildFileTest {
+    public static final String RESULT_FILESET = "result";
+
+    public ClassFileSetTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        // share the setup for testing the depend task
+        configureProject("src/etc/testcases/taskdefs/optional/depend/depend.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("clean");
+    }
+
+    /**
+     * Test basic classfileset
+     */
+    public void testBasicSet() {
+        Project p = getProject();
+        executeTarget("testbasicset");
+        FileSet resultFileSet = (FileSet)p.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(p);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        assertEquals("Classfileset did not pick up expected number of "
+            + "class files", 4, files.size());
+        assertTrue("Result did not contain A.class",
+            files.containsKey("A.class"));
+        assertTrue("Result did not contain B.class",
+            files.containsKey("B.class"));
+        assertTrue("Result did not contain C.class",
+            files.containsKey("C.class"));
+        assertTrue("Result did not contain D.class",
+            files.containsKey("D.class"));
+    }
+
+    /**
+     * Test small classfileset
+     */
+    public void testSmallSet() {
+        Project p = getProject();
+        executeTarget("testsmallset");
+        FileSet resultFileSet = (FileSet)p.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(p);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        assertEquals("Classfileset did not pick up expected number of "
+            + "class files", 2, files.size());
+        assertTrue("Result did not contain B.class",
+            files.containsKey("B.class"));
+        assertTrue("Result did not contain C.class",
+            files.containsKey("C.class"));
+    }
+
+    /**
+     * Test combo classfileset
+     */
+    public void testComboSet() {
+        Project p = getProject();
+        executeTarget("testcomboset");
+        FileSet resultFileSet = (FileSet)p.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(p);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        assertEquals("Classfileset did not pick up expected number of "
+            + "class files", 1, files.size());
+        assertTrue("Result did not contain C.class",
+            files.containsKey("C.class"));
+    }
+
+    /**
+     * Test that you can pass a classfileset by reference to a fileset.
+     */
+    public void testByReference() {
+        executeTarget("testbyreference");
+    }
+
+    /**
+     * Test that classes included in a method "System.out.println(MyClass.class)" are included.
+     */
+    public void testMethodParam() {
+        Project p = getProject();
+        executeTarget("testmethodparam");
+        FileSet resultFileSet = (FileSet)p.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(p);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        assertEquals("Classfileset did not pick up expected number of "
+            + "class files", 5, files.size());
+        assertTrue("Result did not contain A.class",
+            files.containsKey("A.class"));
+        assertTrue("Result did not contain B.class",
+            files.containsKey("B.class"));
+        assertTrue("Result did not contain C.class",
+            files.containsKey("C.class"));
+        assertTrue("Result did not contain D.class",
+            files.containsKey("D.class"));
+        assertTrue("Result did not contain E.class",
+            files.containsKey("E.class"));
+    }
+
+    /**
+     * Test that classes included in a method "System.out.println(Outer.Inner.class)" are included.
+     */
+    public void testMethodParamInner() {
+        Project p = getProject();
+        executeTarget("testmethodparaminner");
+        FileSet resultFileSet = (FileSet)p.getReference(RESULT_FILESET);
+        DirectoryScanner scanner = resultFileSet.getDirectoryScanner(p);
+        String[] scannedFiles = scanner.getIncludedFiles();
+        Hashtable files = new Hashtable();
+        for (int i = 0; i < scannedFiles.length; ++i) {
+            files.put(scannedFiles[i], scannedFiles[i]);
+        }
+        assertEquals("Classfileset did not pick up expected number of "
+            + "class files", 4, files.size());
+        assertTrue("Result did not contain test" + File.separator + "Outer$Inner.class",
+            files.containsKey("test" + File.separator + "Outer$Inner.class"));
+        assertTrue("Result did not contain test" + File.separator + "Outer.class",
+            files.containsKey("test" + File.separator + "Outer.class"));
+        assertTrue("Result did not contain test" + File.separator + "ContainsOnlyInner.class",
+            files.containsKey("test" + File.separator + "ContainsOnlyInner.class"));
+        assertTrue("Result did not contain test" + File.separator + "ContainsOnlyInner.class",
+            files.containsKey("test" + File.separator + "MethodParam.class"));
+    }
+
+    public void testResourceCollection() {
+        executeTarget("testresourcecollection");
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/resources/JavaResourceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/resources/JavaResourceTest.java
new file mode 100755
index 0000000..697fee6
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/resources/JavaResourceTest.java
@@ -0,0 +1,41 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import org.apache.tools.ant.BuildFileTest;
+
+public class JavaResourceTest extends BuildFileTest {
+
+    public JavaResourceTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/resources/javaresource.xml");
+    }
+
+    public void testLoadManifest() {
+        executeTarget("loadManifest");
+        assertNotNull(getProject().getProperty("manifest"));
+
+        // this actually relies on the first manifest being found on
+        // the classpath (probably rt.jar's) being valid
+        assertTrue(getProject().getProperty("manifest")
+                   .startsWith("Manifest-Version:"));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/resources/TarResourceTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/resources/TarResourceTest.java
new file mode 100755
index 0000000..c2157dc
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/resources/TarResourceTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.types.resources;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+public class TarResourceTest extends BuildFileTest {
+
+    private static final FileUtils FU = FileUtils.getFileUtils();
+
+    public TarResourceTest(String name) {
+        super(name);
+    }
+
+    protected void setUp() throws Exception {
+        configureProject("src/etc/testcases/types/resources/tarentry.xml");
+    }
+
+    protected void tearDown() throws Exception {
+        executeTarget("tearDown");
+    }
+
+    public void testUncompressSource() throws java.io.IOException {
+        executeTarget("uncompressSource");
+        assertTrue(FU.contentEquals(project.resolveFile("../../asf-logo.gif"),
+                                    project.resolveFile("testout/asf-logo.gif")));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/BaseSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/BaseSelectorTest.java
new file mode 100644
index 0000000..ca0ae51
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/BaseSelectorTest.java
@@ -0,0 +1,289 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
+/**
+ * Base test case for Selectors. Provides a shared test as well as
+ * a test bed for selecting on, and a helper method for determining
+ * whether selections are correct.
+ *
+ */
+public abstract class BaseSelectorTest extends TestCase {
+
+    private Project project;
+    private TaskdefForMakingBed tbed = null;
+    protected String basedirname = "src/etc/testcases/types";
+    protected String beddirname = basedirname + "/selectortest";
+    protected String mirrordirname = basedirname + "/selectortest2";
+    protected File basedir = new File(System.getProperty("root"), basedirname);
+    protected File beddir = new File(System.getProperty("root"), beddirname);
+    protected File mirrordir = new File(System.getProperty("root"), mirrordirname);
+    protected String[] filenames = {".","asf-logo.gif.md5","asf-logo.gif.bz2",
+            "asf-logo.gif.gz","copy.filterset.filtered","zip/asf-logo.gif.zip",
+            "tar/asf-logo.gif.tar","tar/asf-logo-huge.tar.gz",
+            "tar/gz/asf-logo.gif.tar.gz","tar/bz2/asf-logo.gif.tar.bz2",
+            "tar/bz2/asf-logo-huge.tar.bz2","tar/bz2"};
+    protected File[] files = new File[filenames.length];
+    protected File[] mirrorfiles = new File[filenames.length];
+
+    public BaseSelectorTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.init();
+        project.setBaseDir(basedir);
+        for (int x = 0; x < files.length; x++) {
+            files[x] = new File(beddir,filenames[x]);
+            mirrorfiles[x] = new File(mirrordir,filenames[x]);
+        }
+    }
+
+    /**
+     * Override this in child classes to return a specific Selector
+     */
+    public abstract BaseSelector getInstance();
+
+
+    /**
+     * Return a preconfigured selector (with a set reference to
+     * project instance).
+     * @return the selector
+     */
+    public BaseSelector getSelector() {
+        BaseSelector selector = getInstance();
+        selector.setProject( getProject() );
+        return selector;
+    }
+
+
+    public Project getProject() {
+        return project;
+    }
+
+    /**
+     * This is a test that all Selectors derived from BaseSelector can
+     * use. It calls the setError() method and checks to ensure that a
+     * BuildException is thrown as a result.
+     */
+    public void testRespondsToError() {
+        BaseSelector s = getInstance();
+        if (s == null) {
+            return;
+        }
+        s.setError("test error");
+        try {
+            s.isSelected(beddir,filenames[0],files[0]);
+            fail("Cannot cause BuildException when setError() is called");
+        } catch (BuildException be) {
+            assertEquals("test error",
+                         be.getMessage());
+        }
+    }
+
+
+    /**
+     * This is a helper method that takes a selector and calls its
+     * isSelected() method on each file in the testbed. It returns
+     * a string of "T"s amd "F"s
+     */
+    public String selectionString(FileSelector selector) {
+        return selectionString(beddir,files,selector);
+    }
+
+    /**
+     * This is a helper method that takes a selector and calls its
+     * isSelected() method on each file in the mirror testbed. This
+     * variation is used for dependency checks and to get around the
+     * limitations in the touch task when running JDK 1.1. It returns
+     * a string of "T"s amd "F"s.
+     */
+    public String mirrorSelectionString(FileSelector selector) {
+        return selectionString(mirrordir,mirrorfiles,selector);
+    }
+
+    /**
+     * Worker method for the two convenience methods above. Applies a
+     * selector on a set of files passed in and returns a string of
+     * "T"s amd "F"s from applying the selector to each file.
+     */
+    public String selectionString(File basedir, File[] files, FileSelector selector) {
+        StringBuffer buf = new StringBuffer();
+        for (int x = 0; x < files.length; x++) {
+            if (selector.isSelected(basedir,filenames[x],files[x])) {
+                buf.append('T');
+            }
+            else {
+                buf.append('F');
+            }
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Does the selection test for a given selector and prints the
+     * filenames of the differing files (selected but shouldn't,
+     * not selected but should).
+     * @param selector  The selector to test
+     * @param expected  The expected result
+     */
+    public void performTests(FileSelector selector, String expected) {
+        String result = selectionString(selector);
+        String diff = diff(expected, result);
+        String resolved = resolve(diff);
+        assertEquals("Differing files: " + resolved, result, expected);
+    }
+
+    /**
+     *  Checks which files are selected and shouldn't be or which
+     *  are not selected but should.
+     *  @param expected    String containing 'F's and 'T's
+     *  @param result      String containing 'F's and 'T's
+     *  @return Difference as String containing '-' (equal) and
+     *          'X' (difference).
+     */
+    public String diff(String expected, String result) {
+        int length1 = expected.length();
+        int length2 = result.length();
+        int min = (length1 > length2) ? length2 : length1;
+        StringBuffer sb = new StringBuffer();
+        for (int i=0; i<min; i++) {
+            sb.append(
+                  (expected.charAt(i) == result.charAt(i))
+                ? "-"
+                : "X"
+            );
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Resolves a diff-String (@see diff()) against the (inherited) filenames-
+     * and files arrays.
+     * @param filelist    Diff-String
+     * @return String containing the filenames for all differing files,
+     *         separated with semicolons ';'
+     */
+    public String resolve(String filelist) {
+        StringBuffer sb = new StringBuffer();
+        int min = (filenames.length > filelist.length())
+                ? filelist.length()
+                : filenames.length;
+        for (int i=0; i<min; i++) {
+            if ('X'==filelist.charAt(i)) {
+                sb.append(filenames[i]);
+                sb.append(";");
+            }
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * <p>Creates a testbed. We avoid the dreaded "test" word so that we
+     * don't falsely identify this as a test to be run. The actual
+     * setting up of the testbed is done in the
+     * <code>src/etc/testcases/types/selectors.xml</code> build file.</p>
+     *
+     * <p>Note that the right way to call this is within a try block,
+     * with a finally clause that calls cleanupBed(). You place tests of
+     * the isSelected() method within the try block.</p>
+     */
+    protected void makeBed() {
+        tbed = new TaskdefForMakingBed("setupfiles");
+        tbed.setUp();
+        tbed.makeTestbed();
+    }
+
+    /**
+     * Cleans up the testbed by calling a target in the
+     * <code>src/etc/testcases/types/selectors.xml</code> file.
+     */
+    protected void cleanupBed() {
+        if (tbed != null) {
+            tbed.tearDown();
+            tbed = null;
+        }
+    }
+
+
+    /**
+     * <p>Creates a mirror of the testbed for use in dependency checks.</p>
+     *
+     * <p>Note that the right way to call this is within a try block,
+     * with a finally clause that calls cleanupMirror(). You place tests of
+     * the isSelected() method within the try block.</p>
+     */
+    protected void makeMirror() {
+        tbed = new TaskdefForMakingBed("mirrorfiles");
+        tbed.setUp();
+        tbed.makeMirror();
+    }
+
+    /**
+     * Cleans up the mirror testbed by calling a target in the
+     * <code>src/etc/testcases/types/selectors.xml</code> file.
+     */
+    protected void cleanupMirror() {
+        if (tbed != null) {
+            tbed.deleteMirror();
+            tbed = null;
+        }
+    }
+
+    private class TaskdefForMakingBed extends BuildFileTest {
+
+        TaskdefForMakingBed(String name) {
+            super(name);
+        }
+
+        public void setUp() {
+            configureProject("src/etc/testcases/types/selectors.xml");
+        }
+
+        public void tearDown() {
+            executeTarget("cleanup");
+        }
+
+        public void makeTestbed() {
+            executeTarget("setupfiles");
+        }
+
+        public void makeMirror() {
+            executeTarget("mirrorfiles");
+        }
+
+        public void deleteMirror() {
+            executeTarget("cleanup.mirrorfiles");
+        }
+    }
+
+
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsRegexpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsRegexpTest.java
new file mode 100644
index 0000000..b3ba47c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsRegexpTest.java
@@ -0,0 +1,84 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.Project;
+
+
+public class ContainsRegexpTest extends TestCase {
+
+    private Project project;
+
+    public ContainsRegexpTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        project = new Project();
+        project.setBasedir(".");
+    }
+
+    public void testContainsRegexp() {
+        TaskdefForRegexpTest MyTask =
+            new TaskdefForRegexpTest("containsregexp");
+        try {
+            MyTask.setUp();
+            MyTask.test();
+        } finally {
+            MyTask.tearDown();
+        }
+    }
+
+    private class TaskdefForRegexpTest extends BuildFileTest {
+        TaskdefForRegexpTest(String name) {
+            super(name);
+        }
+
+        public void setUp() {
+            configureProject("src/etc/testcases/types/selectors.xml");
+        }
+
+        public void tearDown() {
+            executeTarget("cleanupregexp");
+        }
+
+        public void test() {
+            File dir = null;
+            File[] files = null;
+            int filecount;
+
+            executeTarget("containsregexp");
+	
+            dir = new File(getProjectDir() + "/regexpseltestdest/");
+            files = dir.listFiles();
+            filecount = files.length;
+	
+            if (filecount != 1)
+                assertEquals("ContainsRegexp test should have copied 1 file",
+                             1, files.length);
+	
+        }
+    }
+}
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsSelectorTest.java
new file mode 100644
index 0000000..bde5ece
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ContainsSelectorTest.java
@@ -0,0 +1,123 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Tests Contains Selectors.
+ *
+ */
+public class ContainsSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public ContainsSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new ContainsSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        ContainsSelector s = (ContainsSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("ContainsSelector did not check for required field 'text'");
+        } catch (BuildException be1) {
+            assertEquals("The text attribute is required", be1.getMessage());
+        }
+
+        s = (ContainsSelector)getInstance();
+        Parameter param = new Parameter();
+        param.setName("garbage in");
+        param.setValue("garbage out");
+        Parameter[] params = {param};
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("ContainsSelector did not check for valid parameter element");
+        } catch (BuildException be2) {
+            assertEquals("Invalid parameter garbage in", be2.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        ContainsSelector s;
+        String results;
+
+        try {
+            makeBed();
+
+            s = (ContainsSelector)getInstance();
+            s.setText("no such string in test files");
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (ContainsSelector)getInstance();
+            s.setText("Apache Ant");
+            results = selectionString(s);
+            assertEquals("TFFFTFFFFFFT", results);
+
+            s = (ContainsSelector)getInstance();
+            s.setText("apache ant");
+            s.setCasesensitive(true);
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (ContainsSelector)getInstance();
+            s.setText("apache ant");
+            s.setCasesensitive(false);
+            results = selectionString(s);
+            assertEquals("TFFFTFFFFFFT", results);
+
+            s = (ContainsSelector)getInstance();
+            s.setText("ApacheAnt");
+            s.setIgnorewhitespace(true);
+            results = selectionString(s);
+            assertEquals("TFFFTFFFFFFT", results);
+
+            s = (ContainsSelector)getInstance();
+            s.setText("A p a c h e    A n t");
+            s.setIgnorewhitespace(true);
+            results = selectionString(s);
+            assertEquals("TFFFTFFFFFFT", results);
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DateSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DateSelectorTest.java
new file mode 100644
index 0000000..2126d43
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DateSelectorTest.java
@@ -0,0 +1,239 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+import java.text.SimpleDateFormat;
+import java.text.ParsePosition;
+import java.util.Date;
+
+
+/**
+ * Tests Date Selectors.
+ *
+ */
+public class DateSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public DateSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new DateSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        DateSelector s = (DateSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for required fields");
+        } catch (BuildException be1) {
+            assertEquals("You must provide a datetime or the number of "
+                    + "milliseconds.", be1.getMessage());
+        }
+
+        s = (DateSelector)getInstance();
+        s.setDatetime("01/01/1969 01:01 AM");
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for Datetime being in the "
+                    + "allowable range");
+        } catch (BuildException be2) {
+            assertEquals("Date of 01/01/1969 01:01 AM results in negative "
+                    + "milliseconds value relative to epoch (January 1, "
+                    + "1970, 00:00:00 GMT).", be2.getMessage());
+        }
+
+        s = (DateSelector)getInstance();
+        s.setDatetime("this is not a date");
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for Datetime being in a "
+                    + "valid format");
+        } catch (BuildException be3) {
+            assertEquals("Date of this is not a date"
+                        + " Cannot be parsed correctly. It should be in"
+                        + " MM/DD/YYYY HH:MM AM_PM format.", be3.getMessage());
+        }
+
+        s = (DateSelector)getInstance();
+        Parameter param = new Parameter();
+        param.setName("garbage in");
+        param.setValue("garbage out");
+        Parameter[] params = new Parameter[1];
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for valid parameter element");
+        } catch (BuildException be4) {
+            assertEquals("Invalid parameter garbage in", be4.getMessage());
+        }
+
+        s = (DateSelector)getInstance();
+        param = new Parameter();
+        param.setName("millis");
+        param.setValue("garbage out");
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for valid millis parameter");
+        } catch (BuildException be5) {
+            assertEquals("Invalid millisecond setting garbage out",
+                    be5.getMessage());
+        }
+
+        s = (DateSelector)getInstance();
+        param = new Parameter();
+        param.setName("granularity");
+        param.setValue("garbage out");
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DateSelector did not check for valid granularity parameter");
+        } catch (BuildException be6) {
+            assertEquals("Invalid granularity setting garbage out",
+                    be6.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        DateSelector s;
+        String results;
+
+        DateSelector.TimeComparisons before = new
+                DateSelector.TimeComparisons();
+        before.setValue("before");
+        DateSelector.TimeComparisons equal = new
+                DateSelector.TimeComparisons();
+        equal.setValue("equal");
+        DateSelector.TimeComparisons after = new
+                DateSelector.TimeComparisons();
+        after.setValue("after");
+
+        try {
+            makeBed();
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("10/10/1999 1:45 PM");
+            s.setWhen(before);
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("10/10/1999 1:45 PM");
+            s.setWhen(before);
+            s.setCheckdirs(true);
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("10/10/1999 1:45 PM");
+            s.setWhen(after);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("11/21/2001 4:54 AM");
+            s.setWhen(before);
+            results = selectionString(s);
+            assertEquals("TFTFFFFFFFFT", results);
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("11/21/2001 4:55 AM");
+            SimpleDateFormat formatter = new SimpleDateFormat();
+            Date d = formatter.parse("11/21/2001 4:55 AM",new ParsePosition(0));
+
+            long milliseconds = s.getMillis();
+            s.setWhen(equal);
+            results = selectionString(s);
+            assertEquals("TTFFTFFFTTTT", results);
+
+            s = (DateSelector)getInstance();
+            s.setMillis(milliseconds);
+            s.setWhen(equal);
+            results = selectionString(s);
+            assertEquals("TTFFTFFFTTTT", results);
+
+            s = (DateSelector)getInstance();
+            s.setDatetime("11/21/2001 4:56 AM");
+            s.setWhen(after);
+            results = selectionString(s);
+            assertEquals("TFFTFTTTFFFT", results);
+
+            s = (DateSelector)getInstance();
+            Parameter param1 = new Parameter();
+            Parameter param2 = new Parameter();
+            param1.setName("datetime");
+            param1.setValue("11/21/2001 4:56 AM");
+            param2.setName("when");
+            param2.setValue("after");
+            Parameter[] params = {param1,param2};
+            s.setParameters(params);
+            results = selectionString(s);
+            assertEquals("TFFTFTTTFFFT", results);
+            try {
+                makeMirror();
+
+                s = (DateSelector)getInstance();
+                long testtime = mirrorfiles[5].lastModified();
+                s.setMillis(testtime);
+                s.setWhen(after);
+                s.setGranularity(2);
+                results = mirrorSelectionString(s);
+                assertEquals("TFFFFTTTTTTT", results);
+
+                s = (DateSelector)getInstance();
+                testtime = mirrorfiles[6].lastModified();
+                s.setMillis(testtime);
+                s.setWhen(before);
+                s.setGranularity(2);
+                results = mirrorSelectionString(s);
+                assertEquals("TTTTTTTFFFFT", results);
+            }
+            finally {
+                cleanupMirror();
+            }
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DependSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DependSelectorTest.java
new file mode 100644
index 0000000..6dc9e89
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DependSelectorTest.java
@@ -0,0 +1,172 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Mapper;
+
+import java.io.File;
+
+
+/**
+ * Tests Depend Selectors
+ *
+ */
+public class DependSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public DependSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new DependSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        DependSelector s = (DependSelector)getInstance();
+        try {
+            s.createMapper();
+            s.createMapper();
+            fail("DependSelector allowed more than one nested mapper.");
+        } catch (BuildException be1) {
+            assertEquals("Cannot define more than one mapper",
+                    be1.getMessage());
+        }
+
+        s = (DependSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DependSelector did not check for required fields");
+        } catch (BuildException be2) {
+            assertEquals("The targetdir attribute is required.",
+                    be2.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        DependSelector s;
+        String results;
+        File subdir;
+        Mapper m;
+        Mapper.MapperType identity = new Mapper.MapperType();
+        identity.setValue("identity");
+        Mapper.MapperType glob = new Mapper.MapperType();
+        glob.setValue("glob");
+        Mapper.MapperType merge = new Mapper.MapperType();
+        merge.setValue("merge");
+
+        try {
+            makeBed();
+
+            s = (DependSelector)getInstance();
+            s.setTargetdir(beddir);
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+            s = (DependSelector)getInstance();
+            s.setTargetdir(beddir);
+            m = s.createMapper();
+            m.setType(identity);
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+            s = (DependSelector)getInstance();
+            s.setTargetdir(beddir);
+            m = s.createMapper();
+            m.setType(merge);
+            m.setTo("asf-logo.gif.gz");
+            results = selectionString(s);
+            assertEquals("TFFFFTTTFFF", results.substring(0,11));
+
+            s = (DependSelector)getInstance();
+            s.setTargetdir(beddir);
+            m = s.createMapper();
+            m.setType(merge);
+            m.setTo("asf-logo.gif.bz2");
+            results = selectionString(s);
+            assertEquals("TTFTTTTTTTTT", results);
+
+            // Test for path relative to project base directory
+            s = (DependSelector)getInstance();
+            subdir = new File("selectortest/tar/bz2");
+            s.setTargetdir(subdir);
+            m = s.createMapper();
+            m.setType(glob);
+            m.setFrom("*.bz2");
+            m.setTo("*.tar.bz2");
+            results = selectionString(s);
+            assertEquals("FFTFFFFFFTTF", results);
+
+            s = (DependSelector)getInstance();
+            subdir = new File(beddir,"tar/bz2");
+            s.setTargetdir(subdir);
+            m = s.createMapper();
+            m.setType(glob);
+            m.setFrom("*.bz2");
+            m.setTo("*.tar.bz2");
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFTTF", results);
+
+            try {
+                makeMirror();
+
+                s = (DependSelector)getInstance();
+                File testdir = getProject().resolveFile("selectortest2");
+                s.setTargetdir(testdir);
+                results = selectionString(s);
+                assertEquals("FFFTTFFFFFFF", results);
+
+                s = (DependSelector)getInstance();
+                testdir = getProject().resolveFile("selectortest2/tar/bz2");
+                s.setTargetdir(testdir);
+                m = s.createMapper();
+                m.setType(glob);
+                m.setFrom("*.bz2");
+                m.setTo("*.tar.bz2");
+                results = mirrorSelectionString(s);
+                assertEquals("FFFFFFFFFTTF", results);
+                results = selectionString(s);
+                assertEquals("FFFFFFFFFTTF", results);
+            }
+            finally {
+                cleanupMirror();
+            }
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DepthSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DepthSelectorTest.java
new file mode 100644
index 0000000..64c260f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/DepthSelectorTest.java
@@ -0,0 +1,158 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Tests Depth Selectors
+ *
+ */
+public class DepthSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public DepthSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new DepthSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        DepthSelector s = (DepthSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DepthSelector did not check for required fields");
+        } catch (BuildException be1) {
+            assertEquals("You must set at least one of the min or the " +
+                    "max levels.", be1.getMessage());
+        }
+
+        s = (DepthSelector)getInstance();
+        s.setMin(5);
+        s.setMax(2);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DepthSelector did not check for maximum being higher "
+                    + "than minimum");
+        } catch (BuildException be2) {
+            assertEquals("The maximum depth is lower than the minimum.",
+                    be2.getMessage());
+        }
+
+        s = (DepthSelector)getInstance();
+        Parameter param = new Parameter();
+        param.setName("garbage in");
+        param.setValue("garbage out");
+        Parameter[] params = new Parameter[1];
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DepthSelector did not check for valid parameter element");
+        } catch (BuildException be3) {
+            assertEquals("Invalid parameter garbage in", be3.getMessage());
+        }
+
+        s = (DepthSelector)getInstance();
+        param = new Parameter();
+        param.setName("min");
+        param.setValue("garbage out");
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DepthSelector accepted bad minimum as parameter");
+        } catch (BuildException be4) {
+            assertEquals("Invalid minimum value garbage out",
+                    be4.getMessage());
+        }
+
+        s = (DepthSelector)getInstance();
+        param = new Parameter();
+        param.setName("max");
+        param.setValue("garbage out");
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("DepthSelector accepted bad maximum as parameter");
+        } catch (BuildException be5) {
+            assertEquals("Invalid maximum value garbage out",
+                    be5.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        DepthSelector s;
+        String results;
+
+        try {
+            makeBed();
+
+            s = (DepthSelector)getInstance();
+            s.setMin(20);
+            s.setMax(25);
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+            s = (DepthSelector)getInstance();
+            s.setMin(0);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (DepthSelector)getInstance();
+            s.setMin(1);
+            results = selectionString(s);
+            assertEquals("FFFFFTTTTTTT", results);
+
+            s = (DepthSelector)getInstance();
+            s.setMax(0);
+            results = selectionString(s);
+            assertEquals("TTTTTFFFFFFF", results);
+
+            s = (DepthSelector)getInstance();
+            s.setMin(1);
+            s.setMax(1);
+            results = selectionString(s);
+            assertEquals("FFFFFTTTFFFT", results);
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/FilenameSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/FilenameSelectorTest.java
new file mode 100644
index 0000000..2083d63
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/FilenameSelectorTest.java
@@ -0,0 +1,125 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Tests Filename Selectors
+ *
+ */
+public class FilenameSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public FilenameSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new FilenameSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        FilenameSelector s = (FilenameSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("FilenameSelector did not check for required fields");
+        } catch (BuildException be1) {
+            assertEquals("The name attribute is required", be1.getMessage());
+        }
+
+        s = (FilenameSelector)getInstance();
+        Parameter param = new Parameter();
+        param.setName("garbage in");
+        param.setValue("garbage out");
+        Parameter[] params = {param};
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("FilenameSelector did not check for valid parameter element");
+        } catch (BuildException be2) {
+            assertEquals("Invalid parameter garbage in", be2.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        FilenameSelector s;
+        String results;
+
+        try {
+            makeBed();
+
+            s = (FilenameSelector)getInstance();
+            s.setName("no match possible");
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+            s = (FilenameSelector)getInstance();
+            s.setName("*.gz");
+            results = selectionString(s);
+            // This is turned off temporarily. There appears to be a bug
+            // in SelectorUtils.matchPattern() where it is recursive on
+            // Windows even if no ** is in pattern.
+            //assertEquals("FFFTFFFFFFFF", results); // Unix
+            // vs
+            //assertEquals("FFFTFFFFTFFF", results); // Windows
+
+            s = (FilenameSelector)getInstance();
+            s.setName("**/*.gz");
+            s.setNegate(true);
+            results = selectionString(s);
+            assertEquals("TTTFTTTFFTTT", results);
+
+            s = (FilenameSelector)getInstance();
+            s.setName("**/*.GZ");
+            s.setCasesensitive(false);
+            results = selectionString(s);
+            assertEquals("FFFTFFFTTFFF", results);
+
+            s = (FilenameSelector)getInstance();
+            Parameter param1 = new Parameter();
+            param1.setName("name");
+            param1.setValue("**/*.bz2");
+            Parameter[] params = {param1};
+            s.setParameters(params);
+            results = selectionString(s);
+            assertEquals("FFTFFFFFFTTF", results);
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockAlgorithm.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockAlgorithm.java
new file mode 100644
index 0000000..458c83f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockAlgorithm.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+
+import java.io.File;
+import org.apache.tools.ant.types.selectors.modifiedselector.Algorithm;
+
+public class MockAlgorithm implements Algorithm {
+    public boolean isValid() {
+        return true;
+    }
+
+    public String getValue(File file) {
+        return "TEST";
+    }
+
+    public String toString() {
+        return "MockAlgorithm@" + hashCode();
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockCache.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockCache.java
new file mode 100644
index 0000000..bcea69e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockCache.java
@@ -0,0 +1,68 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+
+import java.util.Iterator;
+import org.apache.tools.ant.types.selectors.modifiedselector.Cache;
+
+public class MockCache implements Cache {
+
+    public boolean debug = false;
+    public boolean saved = false;
+
+
+    public MockCache() {
+        log("()");
+    }
+
+    public boolean isValid() {
+        log(".isValid()");
+        return true;
+    }
+    public void delete() {
+        log(".delete()");
+    }
+    public void load() {
+        log(".load()");
+    }
+    public void save() {
+        log(".save()");
+        saved = true;
+    }
+    public Object get(Object key) {
+        log(".get("+key+")");
+        return key;
+    }
+    public void put(Object key, Object value) {
+        log(".put("+key+", "+value+")");
+        saved = false;
+    }
+    public Iterator iterator() {
+        log("iterator()");
+        return null;
+    }
+    public String toString() {
+        return "MockCache@" + hashCode();
+    }
+
+    private void log(String msg) {
+        if (debug) System.out.println(this+msg);
+    }
+}//class-MockCache
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockComparator.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockComparator.java
new file mode 100644
index 0000000..a7c1553
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/MockComparator.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import java.util.Comparator;
+
+public class MockComparator implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        return 0;
+    }
+
+    public String toString() {
+        return "MockComparator";
+    }
+}//class-MockCache
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java
new file mode 100644
index 0000000..e3265ec
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/ModifiedSelectorTest.java
@@ -0,0 +1,1015 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+
+// Java
+import java.io.File;
+import java.text.RuleBasedCollator;
+import java.util.Comparator;
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Target;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Parameter;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.selectors.modifiedselector.Algorithm;
+import org.apache.tools.ant.types.selectors.modifiedselector.Cache;
+import org.apache.tools.ant.types.selectors.modifiedselector.ChecksumAlgorithm;
+import org.apache.tools.ant.types.selectors.modifiedselector.DigestAlgorithm;
+import org.apache.tools.ant.types.selectors.modifiedselector.EqualComparator;
+import org.apache.tools.ant.types.selectors.modifiedselector.HashvalueAlgorithm;
+import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
+import org.apache.tools.ant.types.selectors.modifiedselector.PropertiesfileCache;
+import org.apache.tools.ant.util.FileUtils;
+
+
+/**
+ * Unit tests for ModifiedSelector.
+ *
+ * @since  Ant 1.6
+ */
+public class ModifiedSelectorTest extends BaseSelectorTest {
+
+    /** Utilities used for file operations */
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    //  =====================  attributes  =====================
+
+
+    /** Package of the CacheSelector classes. */
+    private static String pkg = "org.apache.tools.ant.types.selectors.modifiedselector";
+
+    /** Path where the testclasses are. */
+    private Path testclasses = null;
+
+
+    //  =====================  constructors, factories  =====================
+
+
+    public ModifiedSelectorTest(String name) {
+        super(name);
+    }
+
+
+    /**
+     * Factory method from base class. This should be overriden in child
+     * classes to return a specific Selector class (like here).
+     */
+    public BaseSelector getInstance() {
+        return new ModifiedSelector();
+    }
+
+
+    //  =====================  JUnit stuff  =====================
+
+
+    public void setUp() {
+        // project reference is set in super.setUp()
+        super.setUp();
+        // init the testclasses path object
+        Project prj = getProject();
+        if (prj != null) {
+            testclasses = new Path(prj, prj.getProperty("build.tests.value"));
+        }
+    }
+
+
+    /* * /
+    // for test only - ignore tests where we arent work at the moment
+    public static junit.framework.Test suite() {
+        junit.framework.TestSuite suite= new junit.framework.TestSuite();
+        suite.addTest(new ModifiedSelectorTest("testValidateWrongCache"));
+        return suite;
+    }
+    /* */
+
+
+    // =======  testcases for the attributes and nested elements of the selector  =====
+
+
+    /** Test right use of cache names. */
+    public void testValidateWrongCache() {
+        String name = "this-is-not-a-valid-cache-name";
+        try {
+            ModifiedSelector.CacheName cacheName = new ModifiedSelector.CacheName();
+            cacheName.setValue(name);
+            fail("CacheSelector.CacheName accepted invalid value.");
+        } catch (BuildException be) {
+            assertEquals(name + " is not a legal value for this attribute",
+                         be.getMessage());
+        }
+    }
+
+
+    /** Test right use of cache names. */
+    public void testValidateWrongAlgorithm() {
+        String name = "this-is-not-a-valid-algorithm-name";
+        try {
+            ModifiedSelector.AlgorithmName algoName
+                = new ModifiedSelector.AlgorithmName();
+            algoName.setValue(name);
+            fail("CacheSelector.AlgorithmName accepted invalid value.");
+        } catch (BuildException be) {
+            assertEquals(name + " is not a legal value for this attribute",
+                         be.getMessage());
+        }
+    }
+
+
+    /** Test right use of comparator names. */
+    public void testValidateWrongComparator() {
+        String name = "this-is-not-a-valid-comparator-name";
+        try {
+            ModifiedSelector.ComparatorName compName
+                = new ModifiedSelector.ComparatorName();
+            compName.setValue(name);
+            fail("ModifiedSelector.ComparatorName accepted invalid value.");
+        } catch (BuildException be) {
+            assertEquals(name + " is not a legal value for this attribute",
+                         be.getMessage());
+        }
+    }
+
+
+    public void testIllegalCustomAlgorithm() {
+        try {
+            getAlgoName("java.lang.Object");
+            fail("Illegal classname used.");
+        } catch (Exception e) {
+            assertTrue("Wrong exception type: " + e.getClass().getName(), e instanceof BuildException);
+            assertEquals("Wrong exception message.",
+                         "Specified class (java.lang.Object) is not an Algorithm.",
+                         e.getMessage());
+
+        }
+    }
+
+
+    public void testNonExistentCustomAlgorithm() {
+        boolean noExcThrown = false;
+        try {
+            getAlgoName("non.existent.custom.Algorithm");
+            noExcThrown = true;
+        } catch (Exception e) {
+            if (noExcThrown) {
+                fail("does 'non.existent.custom.Algorithm' really exist?");
+            }
+            assertTrue("Wrong exception type: " + e.getClass().getName(), e instanceof BuildException);
+            assertEquals("Wrong exception message.",
+                         "Specified class (non.existent.custom.Algorithm) not found.",
+                         e.getMessage());
+
+        }
+    }
+
+
+    public void testCustomAlgorithm() {
+        String algo = getAlgoName("org.apache.tools.ant.types.selectors.modifiedselector.HashvalueAlgorithm");
+        assertTrue("Wrong algorithm used: "+algo, algo.startsWith("HashvalueAlgorithm"));
+    }
+
+
+    public void testCustomAlgorithm2() {
+        String algo = getAlgoName("org.apache.tools.ant.types.selectors.MockAlgorithm");
+        assertTrue("Wrong algorithm used: "+algo, algo.startsWith("MockAlgorithm"));
+    }
+
+
+    public void testCustomClasses() {
+        BFT bft = new BFT();
+        bft.setUp();
+        try {
+            // do the actions
+            bft.doTarget("modifiedselectortest-customClasses");
+            // do the checks - the buildfile stores the fileset as property
+            String fsFullValue = bft.getProperty("fs.full.value");
+            String fsModValue  = bft.getProperty("fs.mod.value");
+
+            assertNotNull("'fs.full.value' must be set.", fsFullValue);
+            assertTrue("'fs.full.value' must not be null.", !"".equals(fsFullValue));
+            assertTrue("'fs.full.value' must contain ant.bat.", fsFullValue.indexOf("ant.bat")>-1);
+
+            assertNotNull("'fs.mod.value' must be set.", fsModValue);
+            // must be empty according to the Mock* implementations
+            assertTrue("'fs.mod.value' must be empty.", "".equals(fsModValue));
+        // don't catch the JUnit exceptions
+        } finally {
+            bft.doTarget("modifiedselectortest-scenario-clean");
+            bft.deletePropertiesfile();
+            bft.tearDown();
+        }
+    }
+
+
+    public void testDelayUpdateTaskFinished() {
+        doDelayUpdateTest(1);
+    }
+
+
+    public void testDelayUpdateTargetFinished() {
+        doDelayUpdateTest(2);
+    }
+
+
+    public void testDelayUpdateBuildFinished() {
+        doDelayUpdateTest(3);
+    }
+
+
+    public void doDelayUpdateTest(int kind) {
+        // no check for 1<=kind<=3 - only internal use therefore check it
+        // while development
+
+        // readable form of parameter kind
+        String[] kinds = {"task", "target", "build"};
+
+        // setup the "Ant project"
+        MockProject project = new MockProject();
+        File base  = new File("base");
+        File file1 = new File("file1");
+        File file2 = new File("file2");
+
+        // setup the selector
+        ModifiedSelector sel = new ModifiedSelector();
+        sel.setProject(project);
+        sel.setUpdate(true);
+        sel.setDelayUpdate(true);
+        // sorry - otherwise we will get a ClassCastException because the MockCache
+        // is loaded by two different classloader ...
+        sel.setClassLoader(this.getClass().getClassLoader());
+        sel.addClasspath(testclasses);
+
+        sel.setAlgorithmClass("org.apache.tools.ant.types.selectors.MockAlgorithm");
+        sel.setCacheClass("org.apache.tools.ant.types.selectors.MockCache");
+        sel.configure();
+
+        // get the cache, so we can check our things
+        MockCache cache = (MockCache)sel.getCache();
+
+        // the test
+        assertFalse("Cache must not be saved before 1st selection.", cache.saved);
+        sel.isSelected(base, "file1", file1);
+        assertFalse("Cache must not be saved after 1st selection.", cache.saved);
+        sel.isSelected(base, "file2", file2);
+        assertFalse("Cache must not be saved after 2nd selection.", cache.saved);
+        switch (kind) {
+            case 1 : project.fireTaskFinished();   break;
+            case 2 : project.fireTargetFinished(); break;
+            case 3 : project.fireBuildFinished();  break;
+        }
+        assertTrue("Cache must be saved after " + kinds[kind-1] + "Finished-Event.", cache.saved);
+
+        // MockCache doesnt create a file - therefore no cleanup needed
+    }
+
+
+    /**
+     * Extracts the real used algorithm name from the ModifiedSelector using
+     * its toString() method.
+     * @param classname  the classname from the algorithm to use
+     * @return  the algorithm part from the toString() (without brackets)
+     */
+    private String getAlgoName(String classname) {
+        ModifiedSelector sel = new ModifiedSelector();
+        // add the test classes to its classpath
+        sel.addClasspath(testclasses);
+        sel.setAlgorithmClass(classname);
+        // let the selector do its checks
+        sel.validate();
+        // extract the algorithm name (and config) from the selectors output
+        String s1 = sel.toString();
+        int posStart = s1.indexOf("algorithm=") + 10;
+        int posEnd   = s1.indexOf(" comparator=");
+        String algo  = s1.substring(posStart, posEnd);
+        // '<' and '>' are only used if the algorithm has properties
+        if (algo.startsWith("<")) algo = algo.substring(1);
+        if (algo.endsWith(">"))   algo = algo.substring(0, algo.length()-1);
+        // return the clean value
+        return algo;
+    }
+
+
+    // ================  testcases for the cache implementations  ================
+
+
+    /**
+     * Propertycache must have a set 'cachefile' attribute.
+     * The default in ModifiedSelector "cache.properties" is set by the selector.
+     */
+    public void testPropcacheInvalid() {
+        Cache cache = new PropertiesfileCache();
+        if (cache.isValid())
+            fail("PropertyfilesCache does not check its configuration.");
+    }
+
+
+    public void testPropertyfileCache() {
+        PropertiesfileCache cache = new PropertiesfileCache();
+        File cachefile = new File("cache.properties");
+        cache.setCachefile(cachefile);
+        doTest(cache);
+        assertFalse("Cache file not deleted.", cachefile.exists());
+    }
+
+
+    /** Checks whether a cache file is created. */
+    public void testCreatePropertiesCacheDirect() {
+        File cachefile = new File(basedir, "cachefile.properties");
+
+        PropertiesfileCache cache = new PropertiesfileCache();
+        cache.setCachefile(cachefile);
+
+        cache.put("key", "value");
+        cache.save();
+
+        assertTrue("Cachefile not created.", cachefile.exists());
+
+        cache.delete();
+        assertFalse("Cachefile not deleted.", cachefile.exists());
+    }
+
+
+    /** Checks whether a cache file is created. */
+    public void testCreatePropertiesCacheViaModifiedSelector() {
+        File cachefile = new File(basedir, "cachefile.properties");
+        try {
+
+            // initialize test environment (called "bed")
+            makeBed();
+
+            // Configure the selector
+            ModifiedSelector s = (ModifiedSelector)getSelector();
+            s.setDelayUpdate(false);
+            s.addParam("cache.cachefile", cachefile);
+
+            ModifiedSelector.CacheName cacheName = new ModifiedSelector.CacheName();
+            cacheName.setValue("propertyfile");
+            s.setCache(cacheName);
+
+            s.setUpdate(true);
+
+            selectionString(s);
+
+            // evaluate correctness
+            assertTrue("Cache file is not created.", cachefile.exists());
+        } finally {
+            cleanupBed();
+            if (cachefile!=null) cachefile.delete();
+        }
+    }
+
+
+    /**
+     * In earlier implementations there were problems with the <i>order</i>
+     * of the <param>s. The scenario was <pre>
+     *   <custom class="ModifiedSelector">
+     *       <param name="cache.cachefile" value="mycache.properties" />
+     *       <param name="cache" value="propertyfiles" />
+     *   </custom>
+     * </pre> It was important first to set the cache and then to set
+     * the cache's configuration parameters. That results in the reorganized
+     * configure() method of ModifiedSelector. This testcase tests that.
+     */
+    public void testCreatePropertiesCacheViaCustomSelector() {
+        File cachefile = FILE_UTILS.createTempFile("tmp-cache-", ".properties", null, false, false);
+        try {
+            // initialize test environment (called "bed")
+            makeBed();
+
+            // Configure the selector
+
+            ExtendSelector s = new ExtendSelector();
+            s.setClassname("org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector");
+            s.addParam(createParam("update", "true"));
+            s.addParam(createParam("cache.cachefile", cachefile.getAbsolutePath()));
+            s.addParam(createParam("cache", "propertyfile"));
+
+            selectionString(s);
+
+            // evaluate correctness
+            assertTrue("Cache file is not created.", cachefile.exists());
+        } finally {
+            cleanupBed();
+            if (cachefile!=null) cachefile.delete();
+        }
+    }
+
+
+    public void _testCustomCache() {
+        // same logic as on algorithm, no testcases created
+    }
+
+
+    /**
+     * Test the interface semantic of Caches.
+     * This method does some common test for cache implementations.
+     * A cache must return a stored value and a valid iterator.
+     * After calling the delete() the cache must be empty.
+     *
+     * @param algo   configured test object
+     */
+    protected void doTest(Cache cache) {
+        assertTrue("Cache not proper configured.", cache.isValid());
+
+        String key1   = "key1";
+        String value1 = "value1";
+        String key2   = "key2";
+        String value2 = "value2";
+
+        // given cache must be empty
+        Iterator it1 = cache.iterator();
+        assertFalse("Cache is not empty", it1.hasNext());
+
+        // cache must return a stored value
+        cache.put(key1, value1);
+        cache.put(key2, value2);
+        assertEquals("cache returned wrong value", value1, cache.get(key1));
+        assertEquals("cache returned wrong value", value2, cache.get(key2));
+
+        // test the iterator
+        Iterator it2 = cache.iterator();
+        Object   returned = it2.next();
+        boolean ok = (key1.equals(returned) || key2.equals(returned));
+        String msg = "Iterator returned unexpected value."
+                   + "  key1.equals(returned)="+key1.equals(returned)
+                   + "  key2.equals(returned)="+key2.equals(returned)
+                   + "  returned="+returned
+                   + "  ok="+ok;
+        assertTrue(msg, ok);
+
+        // clear the cache
+        cache.delete();
+        Iterator it3 = cache.iterator();
+        assertFalse("Cache is not empty", it1.hasNext());
+    }
+
+
+    // ==============  testcases for the algorithm implementations  ==============
+
+
+    public void testHashvalueAlgorithm() {
+        HashvalueAlgorithm algo = new HashvalueAlgorithm();
+        doTest(algo);
+    }
+
+
+    public void testDigestAlgorithmMD5() {
+        DigestAlgorithm algo = new DigestAlgorithm();
+        algo.setAlgorithm("MD5");
+        doTest(algo);
+    }
+
+
+    public void testDigestAlgorithmSHA() {
+        DigestAlgorithm algo = new DigestAlgorithm();
+        algo.setAlgorithm("SHA");
+        doTest(algo);
+    }
+
+
+    public void testChecksumAlgorithm() {
+        ChecksumAlgorithm algo = new ChecksumAlgorithm();
+        doTest(algo);
+    }
+
+
+    public void testChecksumAlgorithmCRC() {
+        ChecksumAlgorithm algo = new ChecksumAlgorithm();
+        algo.setAlgorithm("CRC");
+        doTest(algo);
+    }
+
+
+    public void testChecksumAlgorithmAdler() {
+        ChecksumAlgorithm algo = new ChecksumAlgorithm();
+        algo.setAlgorithm("Adler");
+        doTest(algo);
+    }
+
+
+    /**
+     * Test the interface semantic of Algorithms.
+     * This method does some common test for algorithm implementations.
+     * An algorithm must return always the same value for the same file and
+     * it must not return <i>null</i>.
+     *
+     * @param algo   configured test object
+     */
+    protected void doTest(Algorithm algo) {
+        assertTrue("Algorithm not proper configured.", algo.isValid());
+        try {
+            makeBed();
+
+            for (int i=0; i<files.length; i++) {
+                File file = files[i];  // must not be a directory
+                if (file.isFile()) {
+                    // get the Hashvalues
+                    String hash1 = algo.getValue(file);
+                    String hash2 = algo.getValue(file);
+                    String hash3 = algo.getValue(file);
+                    String hash4 = algo.getValue(file);
+                    String hash5 = algo.getValue(new File(file.getAbsolutePath()));
+
+                    // Assert !=null and equality
+                    assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash1);
+                    assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash2);
+                    assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash3);
+                    assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash4);
+                    assertNotNull("Hashvalue was null for "+file.getAbsolutePath(), hash5);
+                    assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash2);
+                    assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash3);
+                    assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash4);
+                    assertEquals("getHashvalue() returned different value for "+file.getAbsolutePath(), hash1, hash5);
+                }//if-isFile
+            }//for
+        } finally {
+            cleanupBed();
+        }
+    }
+
+
+
+    // ==============  testcases for the comparator implementations  ==============
+
+
+    public void testEqualComparator() {
+        EqualComparator comp = new EqualComparator();
+        doTest(comp);
+    }
+
+
+    public void testRuleComparator() {
+        RuleBasedCollator comp = (RuleBasedCollator)RuleBasedCollator.getInstance();
+        doTest(comp);
+    }
+
+
+    public void testEqualComparatorViaSelector() {
+        ModifiedSelector s = (ModifiedSelector)getSelector();
+        ModifiedSelector.ComparatorName compName = new ModifiedSelector.ComparatorName();
+        compName.setValue("equal");
+        s.setComparator(compName);
+        try {
+            performTests(s, "TTTTTTTTTTTT");
+        } finally {
+            s.getCache().delete();
+        }
+    }
+
+
+    public void _testRuleComparatorViaSelector() { //not yet supported see note in selector
+        ModifiedSelector s = (ModifiedSelector)getSelector();
+        ModifiedSelector.ComparatorName compName = new ModifiedSelector.ComparatorName();
+        compName.setValue("rule");
+        s.setComparator(compName);
+        try {
+            performTests(s, "TTTTTTTTTTTT");
+        } finally {
+            s.getCache().delete();
+        }
+    }
+
+
+    public void _testCustomComparator() {
+        // same logic as on algorithm, no testcases created
+    }
+
+
+    public void testResourceSelectorSimple() {
+        BFT bft = new BFT("modifiedselector");
+        bft.doTarget("modifiedselectortest-ResourceSimple");
+        bft.deleteCachefile();
+        //new File("src/etc/testcases/types/resources/selectors/cache.properties").delete();
+    }
+    public void testResourceSelectorSelresTrue() {
+        BFT bft = new BFT("modifiedselector");
+        bft.doTarget("modifiedselectortest-ResourceSelresTrue");
+        bft.assertLogContaining("does not provide an InputStream");
+        bft.deleteCachefile();
+    }
+    public void testResourceSelectorSelresFalse() {
+        BFT bft = new BFT("modifiedselector");
+        bft.doTarget("modifiedselectortest-ResourceSelresFalse");
+        bft.deleteCachefile();
+    }
+    public void testResourceSelectorScenarioSimple() {
+        BFT bft = new BFT("modifiedselector");
+        bft.doTarget("modifiedselectortest-scenario-resourceSimple");
+        bft.doTarget("modifiedselectortest-scenario-clean");
+        bft.deleteCachefile();
+    }
+    /**
+     * Test the interface semantic of Comparators.
+     * This method does some common test for comparator implementations.
+     *
+     * @param algo   configured test object
+     */
+    protected void doTest(Comparator comp) {
+        Object o1 = new String("string1");
+        Object o2 = new String("string2");
+        Object o3 = new String("string2"); // really "2"
+
+        assertTrue("Comparator gave wrong value.", comp.compare(o1, o2) != 0);
+        assertTrue("Comparator gave wrong value.", comp.compare(o1, o3) != 0);
+        assertTrue("Comparator gave wrong value.", comp.compare(o2, o3) == 0);
+    }
+
+
+    // =====================  scenario tests  =====================
+
+
+    /**
+     * Tests whether the seldirs attribute is used.
+     */
+    public void testSeldirs() {
+        ModifiedSelector s = (ModifiedSelector)getSelector();
+        try {
+            makeBed();
+
+            StringBuffer sbTrue  = new StringBuffer();
+            StringBuffer sbFalse = new StringBuffer();
+            for (int i=0; i<filenames.length; i++) {
+                if (files[i].isDirectory()) {
+                    sbTrue.append("T");
+                    sbFalse.append("F");
+                } else {
+                    sbTrue.append("T");
+                    sbFalse.append("T");
+                }
+            }
+
+            s.setSeldirs(true);
+            performTests(s, sbTrue.toString());
+            s.getCache().delete();
+
+            s.setSeldirs(false);
+            performTests(s, sbFalse.toString());
+            s.getCache().delete();
+
+        } finally {
+            cleanupBed();
+            if (s!=null) s.getCache().delete();
+        }
+    }
+
+
+    /**
+     * Complex test scenario using default values (DigestAlgorithm with MD5,
+     * PropertiesfileCache with file=cache.properties, EqualComparator
+     * and update=true). <ol>
+     * <li> try fist time --> should select all </li>
+     * <li> try second time --> should select no files (only directories) </li>
+     * <li> modify timestamp of one file and content of a nother one </li>
+     * <li> try third time --> should select only the file with modified
+     *      content </li>
+     */
+    public void testScenario1() {
+        BFT bft = null;
+        ModifiedSelector s = null;
+        try {
+            //
+            // *****  initialize test environment (called "bed")  *****
+            //
+            makeBed();
+            String results = null;
+
+            // Configure the selector - only defaults are used
+            s = (ModifiedSelector)getSelector();
+
+            //
+            // *****  First Run  *****
+            // the first call should get all files, because nothing is in
+            // the cache
+            //
+            performTests(s, "TTTTTTTTTTTT");
+
+            //
+            // *****  Second Run  *****
+            // the second call should get no files, because no content
+            // has changed
+            //
+            performTests(s, "TFFFFFFFFFFT");
+
+            //
+            // *****  make some files dirty  *****
+            //
+
+            // these files are made dirty --> 3+4 with different content
+            String f2name = "tar/bz2/asf-logo-huge.tar.bz2";
+            String f3name = "asf-logo.gif.md5";
+            String f4name = "copy.filterset.filtered";
+
+            // AccessObject to the test-Ant-environment
+            bft = new BFT();
+            // give some values (via property file) to that environment
+            bft.writeProperties("f2name="+f2name);
+            bft.writeProperties("f3name="+f3name);
+            bft.writeProperties("f4name="+f4name);
+            // call the target for making the files dirty
+            bft.doTarget("modifiedselectortest-makeDirty");
+
+            //
+            // *****  Third Run  *****
+            // third call should get only those files, which CONTENT changed
+            // (no timestamp changes required!)
+            results = selectionString(s);
+
+            //
+            // *****  Check the result  *****
+            //
+
+            // Mark all files which should be selected as (T)rue and all others
+            // as (F)alse. Directories are always selected so they always are
+            // (T)rue.
+            StringBuffer expected = new StringBuffer();
+            for (int i=0; i<filenames.length; i++) {
+                String ch = "F";
+                if (files[i].isDirectory()) ch = "T";
+                // f2name shouldn't be selected: only timestamp has changed!
+                if (filenames[i].equalsIgnoreCase(f3name)) ch = "T";
+                if (filenames[i].equalsIgnoreCase(f4name)) ch = "T";
+                expected.append(ch);
+            }
+
+            assertEquals(
+                "Wrong files selected. Differing files: "       // info text
+                + resolve(diff(expected.toString(), results)),  // list of files
+                expected.toString(),                            // expected result
+                results                                         // result
+            );
+
+        } finally {
+            // cleanup the environment
+            cleanupBed();
+            if (s!=null) s.getCache().delete();
+            if (bft!=null) bft.deletePropertiesfile();
+        }
+    }
+
+
+    /**
+     * This scenario is based on scenario 1, but does not use any
+     * default value and its based on <custom> selector. Used values are:<ul>
+     * <li><b>Cache: </b> Propertyfile,
+     *                    cachefile={java.io.tmpdir}/mycache.txt </li>
+     * <li><b>Algorithm: </b> Digest
+     *                    algorithm=SHA, Provider=null </li>
+     * <li><b>Comparator: </b> java.text.RuleBasedCollator
+     * <li><b>Update: </b> true </li>
+     */
+    public void _testScenario2() { // RuleBasedCollator not yet supported - see Selector:375 note
+        ExtendSelector s = new ExtendSelector();
+        BFT bft = new BFT();
+        String cachefile = System.getProperty("java.io.tmpdir")+"/mycache.txt";
+        try {
+            makeBed();
+
+            s.setClassname("org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector");
+
+            s.addParam(createParam("cache.cachefile", cachefile));
+            //s.addParam(createParam("algorithm.provider","---")); // i don't know any valid
+            s.addParam(createParam("cache","propertyfile"));
+            s.addParam(createParam("update","true"));
+            s.addParam(createParam("comparator","rule"));
+            s.addParam(createParam("algorithm.name","sha"));
+            s.addParam(createParam("algorithm","digest"));
+
+            // first and second run
+            performTests(s, "TTTTTTTTTTTT");
+            performTests(s, "TFFFFFFFFFFT");
+            // make dirty
+            String f2name = "tar/bz2/asf-logo-huge.tar.bz2";
+            String f3name = "asf-logo.gif.md5";
+            String f4name = "copy.filterset.filtered";
+            bft.writeProperties("f2name="+f2name);
+            bft.writeProperties("f3name="+f3name);
+            bft.writeProperties("f4name="+f4name);
+            bft.doTarget("modifiedselectortest-makeDirty");
+            // third run
+            String results = selectionString(s);
+            StringBuffer expected = new StringBuffer();
+            for (int i=0; i<filenames.length; i++) {
+                String ch = "F";
+                if (files[i].isDirectory()) ch = "T";
+                if (filenames[i].equalsIgnoreCase(f3name)) ch = "T";
+                if (filenames[i].equalsIgnoreCase(f4name)) ch = "T";
+                expected.append(ch);
+            }
+            assertEquals(
+                "Wrong files selected. Differing files: "       // info text
+                + resolve(diff(expected.toString(), results)),  // list of files
+                expected.toString(),                            // expected result
+                results                                         // result
+            );
+        } finally {
+            // cleanup the environment
+            cleanupBed();
+            (new java.io.File(cachefile)).delete();
+            if (bft!=null) bft.deletePropertiesfile();
+        }
+    }
+
+
+    public void testScenarioCoreSelectorDefaults() {
+        doScenarioTest("modifiedselectortest-scenario-coreselector-defaults", "cache.properties");
+    }
+
+
+    public void testScenarioCoreSelectorSettings() {
+        doScenarioTest("modifiedselectortest-scenario-coreselector-settings", "core.cache.properties");
+    }
+
+
+    public void testScenarioCustomSelectorSettings() {
+        doScenarioTest("modifiedselectortest-scenario-customselector-settings", "core.cache.properties");
+    }
+
+
+    public void doScenarioTest(String target, String cachefilename) {
+        BFT bft = new BFT();
+        bft.setUp();
+        File cachefile = new File(basedir, cachefilename);
+        try {
+            // do the actions
+            bft.doTarget("modifiedselectortest-scenario-clean");
+            bft.doTarget(target);
+
+            // the directories to check
+            File to1 = new File(basedir, "selectortest/to-1");
+            File to2 = new File(basedir, "selectortest/to-2");
+            File to3 = new File(basedir, "selectortest/to-3");
+
+            // do the checks
+            assertTrue("Cache file not created.", cachefile.exists());
+            assertTrue("Not enough files copied on first time.", to1.list().length>5);
+            assertTrue("Too much files copied on second time.", to2.list().length==0);
+            assertTrue("Too much files copied on third time.", to3.list().length==2);
+        // don't catch the JUnit exceptions
+        } finally {
+            bft.doTarget("modifiedselectortest-scenario-clean");
+            bft.deletePropertiesfile();
+            bft.tearDown();
+            cachefile.delete();
+        }
+    }
+
+
+    //  =====================  helper methods and classes  ====================
+
+
+    /**
+     * Creates a configured parameter object.
+     * @param name   name of the parameter
+     * @param value  value of the parameter
+     * @return the parameter object
+     */
+    private Parameter createParam(String name, String value) {
+        Parameter p = new Parameter();
+        p.setName(name);
+        p.setValue(value);
+        return p;
+    }
+
+
+    /**
+     * The BFT class wrapps the selector test-builfile inside an
+     * ant project (BuildFileTest). It supports target execution
+     * and property transfer to that project.
+     */
+    private class BFT extends org.apache.tools.ant.BuildFileTest {
+        String buildfile = "src/etc/testcases/types/selectors.xml";
+
+        BFT() { super("nothing"); }
+        BFT(String name) {
+            super(name);
+        }
+
+        String propfile = "ModifiedSelectorTest.properties";
+
+        boolean isConfigured = false;
+
+        public void setUp() {
+            configureProject(buildfile);
+            isConfigured = true;
+        }
+
+
+        /**
+         * This stub teardown is here because the outer class needs to call the
+         * tearDown method, and in the superclass it is protected.
+         */
+        public void tearDown() {
+            try {
+                super.tearDown();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+
+        public void doTarget(String target) {
+            if (!isConfigured) setUp();
+            executeTarget(target);
+        }
+
+        public String getProperty(String property) {
+            return project.getProperty(property);
+        }
+
+        public void writeProperties(String line) {
+            if (!isConfigured) setUp();
+            File dir = getProject().getBaseDir();
+            File file = new File(dir, propfile);
+            try {
+                java.io.FileWriter out =
+                    new java.io.FileWriter(file.getAbsolutePath(), true);
+                out.write(line);
+                out.write(System.getProperty("line.separator"));
+                out.flush();
+                out.close();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        public void deletePropertiesfile() {
+            if (!isConfigured) setUp();
+            new File(getProject().getBaseDir(), propfile).delete();
+        }
+
+        public void deleteCachefile() {
+            File basedir = new File(buildfile).getParentFile();
+            File cacheFile = new File(basedir, "cache.properties");
+            cacheFile.delete();
+        }
+
+        public String getBuildfile() {
+            return buildfile;
+        }
+        public void setBuildfile(String buildfile) {
+            this.buildfile = buildfile;
+        }
+    }//class-BFT
+
+
+    /**
+     * MockProject wrappes a very small ant project (one target, one task)
+     * but provides public methods to fire the build events.
+     */
+    private class MockProject extends Project {
+        private Task   task;
+        private Target target;
+
+        public MockProject() {
+            task = new Task(){
+                public void execute() {
+                }
+            };
+            task.setTaskName("testTask");
+            target = new Target();
+            target.setName("testTarget");
+            target.setProject(this);
+            target.addTask(task);
+            task.setOwningTarget(target);
+        }
+
+        public void fireBuildFinished() {
+            super.fireBuildFinished(null);
+        }
+        public void fireSubBuildFinished() {
+            super.fireSubBuildFinished(null);
+        }
+        public void fireTargetStarted() {
+            super.fireTargetStarted(target);
+        }
+        public void fireTargetFinished() {
+            super.fireTargetFinished(target, null);
+        }
+        public void fireTaskStarted() {
+            super.fireTaskStarted(task);
+        }
+        public void fireTaskFinished() {
+            super.fireTaskFinished(task, null);
+        }
+    }//class-MockProject
+
+
+}//class-ModifiedSelectorTest
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/PresentSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/PresentSelectorTest.java
new file mode 100644
index 0000000..180faf3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/PresentSelectorTest.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Mapper;
+
+import java.io.File;
+
+
+/**
+ * Tests Present Selectors
+ *
+ */
+public class PresentSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public PresentSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new PresentSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        PresentSelector s = (PresentSelector)getInstance();
+        try {
+            s.createMapper();
+            s.createMapper();
+            fail("PresentSelector allowed more than one nested mapper.");
+        } catch (BuildException be1) {
+            assertEquals("Cannot define more than one mapper",
+                    be1.getMessage());
+        }
+
+        s = (PresentSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("PresentSelector did not check for required fields");
+        } catch (BuildException be2) {
+            assertEquals("The targetdir attribute is required.",
+                    be2.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        PresentSelector s;
+        String results;
+        Mapper m;
+        Mapper.MapperType identity = new Mapper.MapperType();
+        identity.setValue("identity");
+        Mapper.MapperType glob = new Mapper.MapperType();
+        glob.setValue("glob");
+        Mapper.MapperType merge = new Mapper.MapperType();
+        merge.setValue("merge");
+        Mapper.MapperType flatten = new Mapper.MapperType();
+        flatten.setValue("flatten");
+
+        try {
+            makeBed();
+
+            s = (PresentSelector)getInstance();
+            s.setTargetdir(beddir);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (PresentSelector)getInstance();
+            s.setTargetdir(beddir);
+            m = s.createMapper();
+            m.setType(identity);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (PresentSelector)getInstance();
+            File subdir = new File(System.getProperty("root"), "src/etc/testcases/taskdefs/expected");
+            s.setTargetdir(subdir);
+            m = s.createMapper();
+            m.setType(flatten);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTF", results);
+
+            s = (PresentSelector)getInstance();
+            s.setTargetdir(beddir);
+            m = s.createMapper();
+            m.setType(merge);
+            m.setTo("asf-logo.gif.gz");
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (PresentSelector)getInstance();
+            subdir = new File(beddir, "tar/bz2");
+            s.setTargetdir(subdir);
+            m = s.createMapper();
+            m.setType(glob);
+            m.setFrom("*.bz2");
+            m.setTo("*.tar.bz2");
+            results = selectionString(s);
+            assertEquals("FFTFFFFFFFFF", results);
+
+            try {
+                makeMirror();
+
+                s = (PresentSelector)getInstance();
+                subdir = getProject().resolveFile("selectortest2");
+                s.setTargetdir(subdir);
+                results = mirrorSelectionString(s);
+                assertEquals("TTTFFTTTTTTT", results);
+                results = selectionString(s);
+                assertEquals("TTTFFTTTTTTT", results);
+
+
+            }
+            finally {
+                cleanupMirror();
+            }
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/README b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/README
new file mode 100755
index 0000000..eb48f6b
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/README
@@ -0,0 +1,96 @@
+A DESCRIPTION OF THE SELECTOR TEST FRAMEWORK
+
+When writing tests for selectors, I found that I wanted to have some
+standard way of working with a set of files and testing whether one or
+another of them was selected. To that end, I created a base class called
+BaseSelectorTest that does most of the heavy lifting. Of course, you can
+test your selectors any way you want, but if you want to reuse this code,
+read on.
+
+What BaseSelectorTest does is use an ant build file
+"src/etc/testcases/types/selector.xml" to copy a tree of files out of
+"src/etc/testcases/taskdefs/expected" into a "selectortest" directories.
+Then it takes a list of 12 of the files and directories in this tree, and
+applies whatever selector you pass in to each one. It passes back to your
+test a 12 character long string indicating which of the 12 files and
+directories was selected, using 'T' for selected and 'F' for not selected.
+In the Test class for your selector, you override the getInstance() method
+to create your own type of selector, and set the elements of your selector
+a variety of ways to ensure that the string of T's and F's returned when
+the selector is applied to those 12 files is correct.
+
+So, for example, DepthSelectorTest.java extends BaseSelectorTest and has
+the following code:
+
+
+    public BaseSelector getInstance() {
+        return new DepthSelector();
+    }
+
+
+    public void testSelectionBehaviour() {
+        DepthSelector s;
+        String results;
+
+
+        try {
+            makeBed();
+
+
+            s = (DepthSelector)getInstance();
+            s.setMin(20);
+            s.setMax(25);
+            results = selectionString(s);
+            assertEquals("FFFFFFFFFFFF", results);
+
+
+            s = (DepthSelector)getInstance();
+            s.setMin(0);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+
+            s = (DepthSelector)getInstance();
+            s.setMin(1);
+            results = selectionString(s);
+            assertEquals("FFFFFTTTTTTT", results);
+
+
+The first test says that none of the 12 files or directories will match if
+the depth range for the selector is between 20 and 25 (that would be one
+deep directory tree!). The second says that all files and directories
+match if the minimum depth is set to 0 and the maximum isn't specified. The
+third test says that if the minumum depth is 1, the first 5 entries in the
+list of 12 will not be selected and the rest will.
+
+
+You can find the 12 files and directories that are tested for selection in
+the BaseSelectorTest class. I used a fixed list so that if someone added
+new files to the src/etc/testcases/types directory it wouldn't break my
+tests:
+
+
+    protected String[] filenames = {".","asf-logo.gif.md5","asf-
+    logo.gif.bz2",
+            "asf-logo.gif.gz","copy.filterset.filtered","zip/asf-
+            logo.gif.zip",
+            "tar/asf-logo.gif.tar","tar/asf-logo-huge.tar.gz",
+            "tar/gz/asf-logo.gif.tar.gz","tar/bz2/asf-logo.gif.tar.bz2",
+            "tar/bz2/asf-logo-huge.tar.bz2","tar/bz2"};
+
+
+If you wish to use this set of files and directories to test your selector,
+you can reuse the BaseSelectorTest with no change to it.
+
+You may find you need to alter the build file so that you get some
+variation in the files that your selector can work with. Most of the core
+selectors have required that kind of modification. If you do that, make
+sure that it doesn't alter the output strings on the other selector test,
+or if it does that you update their expected return results.
+
+You may also want to alter the set of files you look at in a particular
+selector test. Since the filelist in BaseSelectorTest is protected, you
+should be able to override it as you need to. Or you can alter the fileset
+in BaseSelectorTest itself, provided you update the test strings in all the
+other unit tests.
+
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SignedSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SignedSelectorTest.java
new file mode 100644
index 0000000..8b938b9
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SignedSelectorTest.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildFileTest;
+
+/**
+ * Testcase for the &lt;signedselector&gt; selector.
+ *
+ */
+public class SignedSelectorTest extends BuildFileTest {
+
+    public SignedSelectorTest(String name) {
+        super(name);
+    }
+    public void setUp() {
+        configureProject("src/etc/testcases/types/selectors/signedselector.xml");
+    }
+
+    public void testSelectSigned() {
+        executeTarget("selectsigned");
+    }
+    public void testNotSelected() {
+        executeTarget("notselected");
+    }
+    public void testName() {
+        executeTarget("name");
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SizeSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SizeSelectorTest.java
new file mode 100644
index 0000000..52fcf4c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/SizeSelectorTest.java
@@ -0,0 +1,201 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Tests Size Selectors
+ *
+ */
+public class SizeSelectorTest extends BaseSelectorTest {
+
+    private Project project;
+
+    public SizeSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new SizeSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        SizeSelector s = (SizeSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("SizeSelector did not check for required fields");
+        } catch (BuildException be1) {
+            assertEquals("The value attribute is required, and must "
+                    + "be positive", be1.getMessage());
+        }
+
+        s = (SizeSelector)getInstance();
+        s.setValue(-10);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("SizeSelector did not check for value being in the "
+                    + "allowable range");
+        } catch (BuildException be2) {
+            assertEquals("The value attribute is required, and must "
+                    + "be positive", be2.getMessage());
+        }
+
+        s = (SizeSelector)getInstance();
+        Parameter param = new Parameter();
+        param.setName("garbage in");
+        param.setValue("garbage out");
+        Parameter[] params = {param};
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("SizeSelector did not check for valid parameter element");
+        } catch (BuildException be3) {
+            assertEquals("Invalid parameter garbage in", be3.getMessage());
+        }
+
+        s = (SizeSelector)getInstance();
+        param = new Parameter();
+        param.setName("value");
+        param.setValue("garbage out");
+        params[0] = param;
+        s.setParameters(params);
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("SizeSelector accepted bad value as parameter");
+        } catch (BuildException be4) {
+            assertEquals("Invalid size setting garbage out",
+                    be4.getMessage());
+        }
+
+        s = (SizeSelector)getInstance();
+        Parameter param1 = new Parameter();
+        Parameter param2 = new Parameter();
+        param1.setName("value");
+        param1.setValue("5");
+        param2.setName("units");
+        param2.setValue("garbage out");
+        params = new Parameter[2];
+        params[0] = param1;
+        params[1] = param2;
+        try {
+            s.setParameters(params);
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("SizeSelector accepted bad units as parameter");
+        } catch (BuildException be5) {
+            assertEquals("garbage out is not a legal value for this attribute",
+                    be5.getMessage());
+        }
+
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        SizeSelector s;
+        String results;
+
+        SizeSelector.ByteUnits kilo = new SizeSelector.ByteUnits();
+        kilo.setValue("K");
+        SizeSelector.ByteUnits kibi = new SizeSelector.ByteUnits();
+        kibi.setValue("Ki");
+        SizeSelector.ByteUnits tibi = new SizeSelector.ByteUnits();
+        tibi.setValue("Ti");
+        SizeSelector.SizeComparisons less = new SizeSelector.SizeComparisons();
+        less.setValue("less");
+        SizeSelector.SizeComparisons equal = new SizeSelector.SizeComparisons();
+        equal.setValue("equal");
+        SizeSelector.SizeComparisons more = new SizeSelector.SizeComparisons();
+        more.setValue("more");
+
+
+        try {
+            makeBed();
+
+            s = (SizeSelector)getInstance();
+            s.setValue(10);
+            s.setWhen(less);
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (SizeSelector)getInstance();
+            s.setValue(10);
+            s.setWhen(more);
+            results = selectionString(s);
+            assertEquals("TTTTTTTTTTTT", results);
+
+            s = (SizeSelector)getInstance();
+            s.setValue(32);
+            s.setWhen(equal);
+            results = selectionString(s);
+            assertEquals("TFFFTFFFFFFT", results);
+
+            s = (SizeSelector)getInstance();
+            s.setValue(7);
+            s.setWhen(more);
+            s.setUnits(kilo);
+            results = selectionString(s);
+            assertEquals("TFTFFTTTTTTT", results);
+
+            s = (SizeSelector)getInstance();
+            s.setValue(7);
+            s.setWhen(more);
+            s.setUnits(kibi);
+            results = selectionString(s);
+            assertEquals("TFTFFFTTFTTT", results);
+
+            s = (SizeSelector)getInstance();
+            s.setValue(99999);
+            s.setWhen(more);
+            s.setUnits(tibi);
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (SizeSelector)getInstance();
+            Parameter param1 = new Parameter();
+            Parameter param2 = new Parameter();
+            Parameter param3 = new Parameter();
+            param1.setName("value");
+            param1.setValue("20");
+            param2.setName("units");
+            param2.setValue("Ki");
+            param3.setName("when");
+            param3.setValue("more");
+            Parameter[] params = {param1,param2,param3};
+            s.setParameters(params);
+            results = selectionString(s);
+            assertEquals("TFFFFFFTFFTT", results);
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/TypeSelectorTest.java b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/TypeSelectorTest.java
new file mode 100644
index 0000000..1158177
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/types/selectors/TypeSelectorTest.java
@@ -0,0 +1,90 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.types.selectors;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Tests Type Selectors.
+ *
+ */
+public class TypeSelectorTest extends BaseSelectorTest {
+
+    public TypeSelectorTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Factory method from base class. This is overriden in child
+     * classes to return a specific Selector class.
+     */
+    public BaseSelector getInstance() {
+        return new TypeSelector();
+    }
+
+    /**
+     * Test the code that validates the selector.
+     */
+    public void testValidate() {
+        TypeSelector s = (TypeSelector)getInstance();
+        try {
+            s.isSelected(basedir,filenames[0],files[0]);
+            fail("TypeSelector did not check for required fields");
+        } catch (BuildException be1) {
+            assertEquals("The type attribute is required"
+                    , be1.getMessage());
+        }
+    }
+
+    /**
+     * Tests to make sure that the selector is selecting files correctly.
+     */
+    public void testSelectionBehaviour() {
+        TypeSelector s;
+        String results;
+
+        TypeSelector.FileType directory = new
+                TypeSelector.FileType();
+        directory.setValue("dir");
+        TypeSelector.FileType file = new
+                TypeSelector.FileType();
+        file.setValue("file");
+
+        try {
+            makeBed();
+
+            s = (TypeSelector)getInstance();
+            s.setType(directory);
+            results = selectionString(s);
+            assertEquals("TFFFFFFFFFFT", results);
+
+            s = (TypeSelector)getInstance();
+            s.setType(file);
+            results = selectionString(s);
+            assertEquals("FTTTTTTTTTTF", results);
+
+
+        }
+        finally {
+            cleanupBed();
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/ClasspathUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/ClasspathUtilsTest.java
new file mode 100644
index 0000000..b975f65
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/ClasspathUtilsTest.java
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+
+
+/**
+ * Test case for ClasspathUtils
+ *
+ */
+public class ClasspathUtilsTest extends TestCase {
+
+    private Project p;
+
+    public ClasspathUtilsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        p = new Project();
+        p.init();
+    }
+
+
+    public void testOnlyOneInstance() {
+        Enumeration enumeration;
+        String list = "";
+        ClassLoader c = ClasspathUtils.getUniqueClassLoaderForPath(p, (Path) null, false);
+        try {
+            enumeration = c.getResources(
+                "org/apache/tools/ant/taskdefs/defaults.properties");
+        } catch (IOException e) {
+            throw new BuildException(
+                "Could not get the defaults.properties resource");
+        }
+        int count = 0;
+        while (enumeration.hasMoreElements()) {
+            list = list + " " + enumeration.nextElement();
+            count++;
+        }
+        assertTrue("Should be only one and not " + count + " " + list, count == 1);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/CollectionUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/CollectionUtilsTest.java
new file mode 100644
index 0000000..340c357
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/CollectionUtilsTest.java
@@ -0,0 +1,101 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for org.apache.tools.ant.util.CollectionUtils.
+ *
+ */
+public class CollectionUtilsTest extends TestCase {
+
+    public CollectionUtilsTest(String name) {
+        super(name);
+    }
+
+    public void testVectorEquals() {
+        assertTrue(!CollectionUtils.equals(null, new Vector()));
+        assertTrue(!CollectionUtils.equals(new Vector(), null));
+        assertTrue(CollectionUtils.equals(new Vector(), new Vector()));
+        Vector v1 = new Vector();
+        Stack s2 = new Stack();
+        v1.addElement("foo");
+        s2.push("foo");
+        assertTrue(CollectionUtils.equals(v1, s2));
+        assertTrue(CollectionUtils.equals(s2, v1));
+        v1.addElement("bar");
+        assertTrue(!CollectionUtils.equals(v1, s2));
+        assertTrue(!CollectionUtils.equals(s2, v1));
+        s2.push("bar");
+        assertTrue(CollectionUtils.equals(v1, s2));
+        assertTrue(CollectionUtils.equals(s2, v1));
+        s2.push("baz");
+        assertTrue(!CollectionUtils.equals(v1, s2));
+        assertTrue(!CollectionUtils.equals(s2, v1));
+        v1.addElement("baz");
+        assertTrue(CollectionUtils.equals(v1, s2));
+        assertTrue(CollectionUtils.equals(s2, v1));
+        v1.addElement("zyzzy");
+        s2.push("zyzzy2");
+        assertTrue(!CollectionUtils.equals(v1, s2));
+        assertTrue(!CollectionUtils.equals(s2, v1));
+    }
+
+    public void testDictionaryEquals() {
+        assertTrue(!CollectionUtils.equals(null, new Hashtable()));
+        assertTrue(!CollectionUtils.equals(new Hashtable(), null));
+        assertTrue(CollectionUtils.equals(new Hashtable(), new Properties()));
+        Hashtable h1 = new Hashtable();
+        Properties p2 = new Properties();
+        h1.put("foo", "");
+        p2.put("foo", "");
+        assertTrue(CollectionUtils.equals(h1, p2));
+        assertTrue(CollectionUtils.equals(p2, h1));
+        h1.put("bar", "");
+        assertTrue(!CollectionUtils.equals(h1, p2));
+        assertTrue(!CollectionUtils.equals(p2, h1));
+        p2.put("bar", "");
+        assertTrue(CollectionUtils.equals(h1, p2));
+        assertTrue(CollectionUtils.equals(p2, h1));
+        p2.put("baz", "");
+        assertTrue(!CollectionUtils.equals(h1, p2));
+        assertTrue(!CollectionUtils.equals(p2, h1));
+        h1.put("baz", "");
+        assertTrue(CollectionUtils.equals(h1, p2));
+        assertTrue(CollectionUtils.equals(p2, h1));
+        h1.put("zyzzy", "");
+        p2.put("zyzzy2", "");
+        assertTrue(!CollectionUtils.equals(h1, p2));
+        assertTrue(!CollectionUtils.equals(p2, h1));
+        p2.put("zyzzy", "");
+        h1.put("zyzzy2", "");
+        assertTrue(CollectionUtils.equals(h1, p2));
+        assertTrue(CollectionUtils.equals(p2, h1));
+        h1.put("dada", "1");
+        p2.put("dada", "2");
+        assertTrue(!CollectionUtils.equals(h1, p2));
+        assertTrue(!CollectionUtils.equals(p2, h1));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/DOMElementWriterTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/DOMElementWriterTest.java
new file mode 100644
index 0000000..0e6d629
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/DOMElementWriterTest.java
@@ -0,0 +1,257 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Tests for org.apache.tools.ant.util.DOMElementWriter.
+ *
+ */
+public class DOMElementWriterTest extends TestCase {
+
+    private DOMElementWriter w = new DOMElementWriter();
+
+    public DOMElementWriterTest(String name) {
+        super(name);
+    }
+
+    public void testIsReference() {
+        assertTrue("&#20;", w.isReference("&#20;"));
+        assertTrue("&#x20;", w.isReference("&#x20;"));
+        assertTrue("&#xA0;", w.isReference("&#xA0;"));
+        assertTrue("&#A0;", !w.isReference("&#A0;"));
+        assertTrue("20;", !w.isReference("20;"));
+        assertTrue("&#20", !w.isReference("&#20"));
+        assertTrue("&quot;", w.isReference("&quot;"));
+        assertTrue("&apos;", w.isReference("&apos;"));
+        assertTrue("&gt;", w.isReference("&gt;"));
+        assertTrue("&lt;", w.isReference("&lt;"));
+        assertTrue("&amp;", w.isReference("&amp;"));
+    }
+
+    public void testEncode() {
+        assertEquals("&#20;", w.encode("&#20;"));
+        assertEquals("&#x20;", w.encode("&#x20;"));
+        assertEquals("&#xA0;", w.encode("&#xA0;"));
+        assertEquals("&amp;#A0;", w.encode("&#A0;"));
+        assertEquals("20;", w.encode("20;"));
+        assertEquals("&amp;#20", w.encode("&#20"));
+        assertEquals("&quot;", w.encode("&quot;"));
+        assertEquals("&apos;", w.encode("&apos;"));
+        assertEquals("&gt;", w.encode("&gt;"));
+        assertEquals("&lt;", w.encode("&lt;"));
+        assertEquals("&amp;", w.encode("&amp;"));
+        assertEquals("&quot;", w.encode("\""));
+        assertEquals("&lt;", w.encode("<"));
+        assertEquals("&amp;", w.encode("&"));
+        assertEquals("", w.encode("\u0017"));
+        assertEquals("&#20;\"20;&", w.encodedata("&#20;\"20;&"));
+        assertEquals("", w.encodedata("\u0017"));
+    }
+
+    public void testIsLegalCharacter() {
+        assertTrue("0x00", !w.isLegalCharacter('\u0000'));
+        assertTrue("0x09", w.isLegalCharacter('\t'));
+        assertTrue("0x0A", w.isLegalCharacter('\n'));
+        assertTrue("0x0C", w.isLegalCharacter('\r'));
+        assertTrue("0x1F", !w.isLegalCharacter('\u001F'));
+        assertTrue("0x20", w.isLegalCharacter('\u0020'));
+        assertTrue("0xD7FF", w.isLegalCharacter('\uD7FF'));
+        assertTrue("0xD800", !w.isLegalCharacter('\uD800'));
+        assertTrue("0xDFFF", !w.isLegalCharacter('\uDFFF'));
+        assertTrue("0xE000", w.isLegalCharacter('\uE000'));
+        assertTrue("0xFFFD", w.isLegalCharacter('\uFFFD'));
+        assertTrue("0xFFFE", !w.isLegalCharacter('\uFFFE'));
+    }
+
+    public void testCDATAEndEncoding() {
+        assertEquals("]>", w.encodedata("]>"));
+        assertEquals("]]", w.encodedata("]]"));
+        assertEquals("&#x5d;&#x5d;&gt;", w.encodedata("]]>"));
+        assertEquals("&#x5d;&#x5d;&gt;A", w.encodedata("]]>A"));
+        assertEquals("A&#x5d;&#x5d;&gt;", w.encodedata("A]]>"));
+        assertEquals("A&#x5d;&#x5d;&gt;A", w.encodedata("A]]>A"));
+        assertEquals("A&#x5d;&#x5d;&gt;B&#x5d;&#x5d;&gt;C",
+                     w.encodedata("A]]>B]]>C"));
+    }
+
+    public void testNoAdditionalWhiteSpaceForText() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElement("root");
+        DOMUtils.appendTextElement(root, "textElement", "content");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w = new DOMElementWriter();
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root>" + StringUtils.LINE_SEP
+                     + "  <textElement>content</textElement>"
+                     + StringUtils.LINE_SEP
+                     + "</root>" + StringUtils.LINE_SEP,
+                     sw.toString());
+    }
+
+    public void testNoAdditionalWhiteSpaceForCDATA() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElement("root");
+        DOMUtils.appendCDATAElement(root, "cdataElement", "content");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w = new DOMElementWriter();
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root>" + StringUtils.LINE_SEP
+                     + "  <cdataElement><![CDATA[content]]></cdataElement>"
+                     + StringUtils.LINE_SEP
+                     + "</root>" + StringUtils.LINE_SEP,
+                     sw.toString());
+    }
+
+    public void testNoAdditionalWhiteSpaceForEmptyElement() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElement("root");
+        DOMUtils.createChildElement(root, "emptyElement");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w = new DOMElementWriter();
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root>" + StringUtils.LINE_SEP
+                     //                     + "  <emptyElement></emptyElement>"
+                     + "  <emptyElement />"
+                     + StringUtils.LINE_SEP
+                     + "</root>" + StringUtils.LINE_SEP,
+                     sw.toString());
+    }
+
+    public void testNoNSPrefixByDefault() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        root.setAttributeNS("urn:foo2", "bar", "baz");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w = new DOMElementWriter();
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root bar=\"baz\" />"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+
+    public void testNSOnElement() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        root.setAttributeNS("urn:foo2", "bar", "baz");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w =
+            new DOMElementWriter(false,
+                                 DOMElementWriter.XmlNamespacePolicy
+                                 .ONLY_QUALIFY_ELEMENTS);
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root bar=\"baz\" xmlns=\"urn:foo\" />"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+
+    public void testNSPrefixOnAttribute() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        root.setAttributeNS("urn:foo2", "bar", "baz");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w =
+            new DOMElementWriter(false,
+                                 DOMElementWriter.XmlNamespacePolicy
+                                 .QUALIFY_ALL);
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root ns0:bar=\"baz\" xmlns=\"urn:foo\""
+                     + " xmlns:ns0=\"urn:foo2\" />"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+
+    public void testNSPrefixOnAttributeEvenWithoutElement() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        root.setAttributeNS("urn:foo2", "bar", "baz");
+
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w =
+            new DOMElementWriter(false,
+                                 new DOMElementWriter.XmlNamespacePolicy(false,
+                                                                         true)
+                                 );
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root ns0:bar=\"baz\" xmlns:ns0=\"urn:foo2\" />"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+
+    public void testNSGetsReused() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        Element child = d.createElementNS("urn:foo", "child");
+        root.appendChild(child);
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w =
+            new DOMElementWriter(false,
+                                 DOMElementWriter.XmlNamespacePolicy
+                                 .ONLY_QUALIFY_ELEMENTS);
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root xmlns=\"urn:foo\">"
+                     + StringUtils.LINE_SEP
+                     + "  <child />"
+                     + StringUtils.LINE_SEP
+                     + "</root>"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+
+    public void testNSGoesOutOfScope() throws IOException {
+        Document d = DOMUtils.newDocument();
+        Element root = d.createElementNS("urn:foo", "root");
+        Element child = d.createElementNS("urn:foo2", "child");
+        root.appendChild(child);
+        Element child2 = d.createElementNS("urn:foo2", "child");
+        root.appendChild(child2);
+        Element grandChild = d.createElementNS("urn:foo2", "grandchild");
+        child2.appendChild(grandChild);
+        Element child3 = d.createElementNS("urn:foo2", "child");
+        root.appendChild(child3);
+        StringWriter sw = new StringWriter();
+        DOMElementWriter w =
+            new DOMElementWriter(false,
+                                 DOMElementWriter.XmlNamespacePolicy
+                                 .ONLY_QUALIFY_ELEMENTS);
+        w.write(root, sw, 0, "  ");
+        assertEquals("<root xmlns=\"urn:foo\">"
+                     + StringUtils.LINE_SEP
+                     + "  <ns0:child xmlns:ns0=\"urn:foo2\" />"
+                     + StringUtils.LINE_SEP
+                     + "  <ns1:child xmlns:ns1=\"urn:foo2\">"
+                     + StringUtils.LINE_SEP
+                     + "    <ns1:grandchild />"
+                     + StringUtils.LINE_SEP
+                     + "  </ns1:child>"
+                     + StringUtils.LINE_SEP
+                     + "  <ns2:child xmlns:ns2=\"urn:foo2\" />"
+                     + StringUtils.LINE_SEP
+                      + "</root>"
+                     + StringUtils.LINE_SEP, sw.toString());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/DateUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/DateUtilsTest.java
new file mode 100644
index 0000000..ede0b43
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/DateUtilsTest.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+/**
+ * TestCase for DateUtils.
+ *
+ */
+public class DateUtilsTest extends TestCase {
+    public DateUtilsTest(String s) {
+        super(s);
+    }
+
+    public void testElapsedTime(){
+        String text = DateUtils.formatElapsedTime(50*1000);
+        assertEquals("50 seconds", text);
+        text = DateUtils.formatElapsedTime(65*1000);
+        assertEquals("1 minute 5 seconds", text);
+        text = DateUtils.formatElapsedTime(120*1000);
+        assertEquals("2 minutes 0 seconds", text);
+        text = DateUtils.formatElapsedTime(121*1000);
+        assertEquals("2 minutes 1 second", text);
+    }
+
+    public void testDateTimeISO(){
+        TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
+        Calendar cal = Calendar.getInstance(timeZone);
+        cal.set(2002,1,23,10,11,12);
+        String text = DateUtils.format(cal.getTime(),
+                DateUtils.ISO8601_DATETIME_PATTERN);
+        assertEquals("2002-02-23T09:11:12", text);
+    }
+
+    public void testDateISO(){
+        TimeZone timeZone = TimeZone.getTimeZone("GMT");
+        Calendar cal = Calendar.getInstance(timeZone);
+        cal.set(2002,1,23);
+        String text = DateUtils.format(cal.getTime(),
+                DateUtils.ISO8601_DATE_PATTERN);
+        assertEquals("2002-02-23", text);
+    }
+
+    public void testTimeISODate(){
+        // make sure that elapsed time in set via date works
+        TimeZone timeZone = TimeZone.getTimeZone("GMT+1");
+        Calendar cal = Calendar.getInstance(timeZone);
+        cal.set(2002,1,23, 21, 11, 12);
+        String text = DateUtils.format(cal.getTime(),
+                DateUtils.ISO8601_TIME_PATTERN);
+        assertEquals("20:11:12", text);
+    }
+
+    public void testTimeISO(){
+        // make sure that elapsed time in ms works
+        long ms = (20*3600 + 11*60 + 12)*1000;
+        String text = DateUtils.format(ms,
+                DateUtils.ISO8601_TIME_PATTERN);
+        assertEquals("20:11:12", text);
+    }
+
+    public void testPhaseOfMoon() {
+        TimeZone timeZone = TimeZone.getTimeZone("GMT");
+        Calendar cal = Calendar.getInstance(timeZone);
+        // should be full moon
+        cal.set(2002, 2, 27);
+        assertEquals(4, DateUtils.getPhaseOfMoon(cal));
+        // should be new moon
+        cal.set(2002, 2, 12);
+        assertEquals(0, DateUtils.getPhaseOfMoon(cal));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java
new file mode 100644
index 0000000..835d6dd
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/FileUtilsTest.java
@@ -0,0 +1,622 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * Tests for org.apache.tools.ant.util.FileUtils.
+ *
+ */
+public class FileUtilsTest extends TestCase {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+    private File removeThis;
+    private String root;
+
+    public FileUtilsTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        // Windows adds the drive letter in uppercase, unless you run Cygwin
+        root = new File(File.separator).getAbsolutePath().toUpperCase();
+    }
+
+    public void tearDown() {
+        if (removeThis != null && removeThis.exists()) {
+            if (!removeThis.delete())
+            {
+                removeThis.deleteOnExit();
+            }
+        }
+    }
+
+    /**
+     * test modification.
+     * Since Ant1.7, the method being tested no longer uses
+     * reflection to provide backwards support to Java1.1, so this
+     * test is not so critical. But it does explore file system
+     * behaviour and will help catch any regression in Java itself,
+     * so is worth retaining.
+     * @see FileUtils#setFileLastModified(java.io.File, long)
+     * @throws IOException
+     */
+    public void testSetLastModified() throws IOException {
+        removeThis = new File("dummy");
+        FileOutputStream fos = new FileOutputStream(removeThis);
+        fos.write(new byte[0]);
+        fos.close();
+        long modTime = removeThis.lastModified();
+        assertTrue(modTime != 0);
+
+        /*
+         * Sleep for some time to make sure a touched file would get a
+         * more recent timestamp according to the file system's
+         * granularity (should be > 2s to account for Windows FAT).
+         */
+        try {
+            Thread.sleep(5000);
+        } catch (InterruptedException ie) {
+            fail(ie.getMessage());
+        }
+
+        FILE_UTILS.setFileLastModified(removeThis, -1);
+        long secondModTime = removeThis.lastModified();
+        assertTrue(secondModTime > modTime);
+
+        // number of milliseconds in a day
+        final int millisperday=24 * 3600 * 1000;
+        // in a previous version, the date of the file was set to 123456
+        // milliseconds since 01.01.1970
+        // it did not work on a computer running JDK 1.4.1_02 + Windows 2000
+        FILE_UTILS.setFileLastModified(removeThis, secondModTime + millisperday);
+        long thirdModTime = removeThis.lastModified();
+        /*
+         * I would love to compare this with 123456, but depending on
+         * the filesystems granularity it can take an arbitrary value.
+         *
+         * Just assert the time has changed.
+         */
+        assertTrue(thirdModTime != secondModTime);
+    }
+
+    public void testResolveFile() {
+        if (!(Os.isFamily("dos") || Os.isFamily("netware"))) {
+            /*
+             * Start with simple absolute file names.
+             */
+            assertEquals(File.separator,
+                         FILE_UTILS.resolveFile(null, "/").getPath());
+            assertEquals(File.separator,
+                         FILE_UTILS.resolveFile(null, "\\").getPath());
+        } else {
+            assertEqualsIgnoreDriveCase(localize(File.separator),
+                FILE_UTILS.resolveFile(null, "/").getPath());
+            assertEqualsIgnoreDriveCase(localize(File.separator),
+                FILE_UTILS.resolveFile(null, "\\").getPath());
+            /*
+             * throw in drive letters
+             */
+            String driveSpec = "C:";
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpec + "/").getPath());
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpec + "\\").getPath());
+            String driveSpecLower = "c:";
+            assertEquals(driveSpecLower + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "/").getPath());
+            assertEquals(driveSpecLower + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "\\").getPath());
+            /*
+             * promised to eliminate consecutive slashes after drive letter.
+             */
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpec + "/////").getPath());
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.resolveFile(null, driveSpec + "\\\\\\\\\\\\").getPath());
+        }
+        if (Os.isFamily("netware")) {
+            /*
+             * throw in NetWare volume names
+             */
+            String driveSpec = "SYS:";
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "/").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "\\").getPath());
+            String driveSpecLower = "sys:";
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "/").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "\\").getPath());
+            /*
+             * promised to eliminate consecutive slashes after drive letter.
+             */
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "/////").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "\\\\\\\\\\\\").getPath());
+        } else if (!(Os.isFamily("dos"))) {
+            /*
+             * drive letters must be considered just normal filenames.
+             */
+            String driveSpec = "C:";
+            String udir = System.getProperty("user.dir");
+            assertEquals(udir + File.separator + driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "/").getPath());
+            assertEquals(udir + File.separator + driveSpec,
+                         FILE_UTILS.resolveFile(null, driveSpec + "\\").getPath());
+            String driveSpecLower = "c:";
+            assertEquals(udir + File.separator + driveSpecLower,
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "/").getPath());
+            assertEquals(udir + File.separator + driveSpecLower,
+                         FILE_UTILS.resolveFile(null, driveSpecLower + "\\").getPath());
+        }
+
+        /*
+         * Now test some relative file name magic.
+         */
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "./4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), ".\\4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "./.\\4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "../3/4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "..\\3\\4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "../../5/.././2/./3/6/../4").getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.resolveFile(new File(localize("/1/2/3")), "..\\../5/..\\./2/./3/6\\../4").getPath());
+
+        assertEquals("meaningless result but no exception",
+                new File(localize("/1/../../b")),
+                FILE_UTILS.resolveFile(new File(localize("/1")), "../../b"));
+
+    }
+
+    public void testNormalize() {
+        if (!(Os.isFamily("dos") || Os.isFamily("netware"))) {
+            /*
+             * Start with simple absolute file names.
+             */
+            assertEquals(File.separator,
+                         FILE_UTILS.normalize("/").getPath());
+            assertEquals(File.separator,
+                         FILE_UTILS.normalize("\\").getPath());
+        } else {
+            try {
+                 FILE_UTILS.normalize("/").getPath();
+                 fail("normalized \"/\" on dos or netware");
+            } catch (Exception e) {
+            }
+            try {
+                 FILE_UTILS.normalize("\\").getPath();
+                 fail("normalized \"\\\" on dos or netware");
+            } catch (Exception e) {
+            }
+        }
+
+        if (Os.isFamily("dos")) {
+            /*
+             * throw in drive letters
+             */
+            String driveSpec = "C:";
+            try {
+                 FILE_UTILS.normalize(driveSpec).getPath();
+                 fail(driveSpec + " is not an absolute path");
+            } catch (Exception e) {
+            }
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.normalize(driveSpec + "/").getPath());
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.normalize(driveSpec + "\\").getPath());
+            String driveSpecLower = "c:";
+            assertEquals(driveSpecLower + "\\",
+                         FILE_UTILS.normalize(driveSpecLower + "/").getPath());
+            assertEquals(driveSpecLower + "\\",
+                         FILE_UTILS.normalize(driveSpecLower + "\\").getPath());
+            /*
+             * promised to eliminate consecutive slashes after drive letter.
+             */
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.normalize(driveSpec + "/////").getPath());
+            assertEquals(driveSpec + "\\",
+                         FILE_UTILS.normalize(driveSpec + "\\\\\\\\\\\\").getPath());
+        } else if (Os.isFamily("netware")) {
+            /*
+             * throw in NetWare volume names
+             */
+            String driveSpec = "SYS:";
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpec).getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpec + "/").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpec + "\\").getPath());
+            String driveSpecLower = "sys:";
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpecLower).getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpecLower + "/").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpecLower + "\\").getPath());
+            assertEquals(driveSpec + "\\junk",
+                         FILE_UTILS.normalize(driveSpecLower + "\\junk").getPath());
+            /*
+             * promised to eliminate consecutive slashes after drive letter.
+             */
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpec + "/////").getPath());
+            assertEquals(driveSpec,
+                         FILE_UTILS.normalize(driveSpec + "\\\\\\\\\\\\").getPath());
+        } else {
+            try {
+                String driveSpec = "C:";
+                assertEquals(driveSpec,
+                             FILE_UTILS.normalize(driveSpec).getPath());
+                fail("Expected failure, C: isn't an absolute path on other os's");
+            } catch (BuildException e) {
+                // Passed test 
+            }
+        }
+
+        /*
+         * Now test some relative file name magic.
+         */
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/./4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/.\\4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/./.\\4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/../3/4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/..\\3\\4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/../../5/.././2/./3/6/../4")).getPath());
+        assertEquals(localize("/1/2/3/4"),
+                     FILE_UTILS.normalize(localize("/1/2/3/..\\../5/..\\./2/./3/6\\../4")).getPath());
+
+        try {
+            FILE_UTILS.normalize("foo");
+            fail("foo is not an absolute path");
+        } catch (BuildException e) {
+            // Expected exception caught
+        }
+
+        assertEquals("will not go outside FS root (but will not throw an exception either)",
+                new File(localize("/1/../../b")),
+                FILE_UTILS.normalize(localize("/1/../../b")));
+    }
+
+    /**
+     * Test handling of null arguments.
+     */
+    public void testNullArgs() {
+        try {
+            FILE_UTILS.normalize(null);
+            fail("successfully normalized a null-file");
+        } catch (NullPointerException npe) {
+            // Expected exception caught
+        }
+
+        File f = FILE_UTILS.resolveFile(null, "a");
+        assertEquals(f, new File("a").getAbsoluteFile());
+    }
+
+    
+    /**
+     * Test createTempFile
+     */
+    public void testCreateTempFile()
+    {
+        // null parent dir
+        File tmp1 = FILE_UTILS.createTempFile("pre", ".suf", null, false, true);
+        String tmploc = System.getProperty("java.io.tmpdir");
+        String name = tmp1.getName();
+        assertTrue("starts with pre", name.startsWith("pre"));
+        assertTrue("ends with .suf", name.endsWith(".suf"));
+        assertTrue("File was created", tmp1.exists());
+        assertEquals((new File(tmploc, tmp1.getName())).getAbsolutePath(), tmp1
+                .getAbsolutePath());
+        tmp1.delete();
+
+        File dir2 = new File(tmploc + "/ant-test");
+        dir2.mkdir();
+        removeThis = dir2;
+
+        File tmp2 = FILE_UTILS.createTempFile("pre", ".suf", dir2, true, true);
+        String name2 = tmp2.getName();
+        assertTrue("starts with pre", name2.startsWith("pre"));
+        assertTrue("ends with .suf", name2.endsWith(".suf"));
+        assertTrue("File was created", tmp2.exists());
+        assertEquals((new File(dir2, tmp2.getName())).getAbsolutePath(), tmp2
+                .getAbsolutePath());
+        tmp2.delete();
+        dir2.delete();
+
+        File parent = new File((new File("/tmp")).getAbsolutePath());
+        tmp1 = FILE_UTILS.createTempFile("pre", ".suf", parent, false);
+        assertTrue("new file", !tmp1.exists());
+
+        name = tmp1.getName();
+        assertTrue("starts with pre", name.startsWith("pre"));
+        assertTrue("ends with .suf", name.endsWith(".suf"));
+        assertEquals("is inside parent dir", parent.getAbsolutePath(), tmp1
+                .getParent());
+
+        tmp2 = FILE_UTILS.createTempFile("pre", ".suf", parent, false);
+        assertTrue("files are different", !tmp1.getAbsolutePath().equals(
+                tmp2.getAbsolutePath()));
+
+        // null parent dir
+        File tmp3 = FILE_UTILS.createTempFile("pre", ".suf", null, false);
+        tmploc = System.getProperty("java.io.tmpdir");
+        assertEquals((new File(tmploc, tmp3.getName())).getAbsolutePath(), tmp3
+                .getAbsolutePath());
+    }
+
+    /**
+     * Test contentEquals
+     */
+    public void testContentEquals() throws IOException {
+        assertTrue("Non existing files", FILE_UTILS.contentEquals(new File(System.getProperty("root"), "foo"),
+                                                          new File(System.getProperty("root"), "bar")));
+        assertTrue("One exists, the other one doesn\'t",
+                   !FILE_UTILS.contentEquals(new File(System.getProperty("root"), "foo"), new File(System.getProperty("root"), "build.xml")));
+        assertTrue("Don\'t compare directories",
+                   !FILE_UTILS.contentEquals(new File(System.getProperty("root"), "src"), new File(System.getProperty("root"), "src")));
+        assertTrue("File equals itself",
+                   FILE_UTILS.contentEquals(new File(System.getProperty("root"), "build.xml"),
+                                    new File(System.getProperty("root"), "build.xml")));
+        assertTrue("Files are different",
+                   !FILE_UTILS.contentEquals(new File(System.getProperty("root"), "build.xml"),
+                                     new File(System.getProperty("root"), "docs.xml")));
+    }
+
+    /**
+     * Test createNewFile
+     */
+    public void testCreateNewFile() throws IOException {
+        removeThis = new File("dummy");
+        assertTrue(!removeThis.exists());
+        FILE_UTILS.createNewFile(removeThis);
+        assertTrue(removeThis.exists());
+    }
+
+    /**
+     * Test removeLeadingPath.
+     */
+    public void testRemoveLeadingPath() {
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("/foo"),
+                                                 new File("/foo/bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("/foo/"),
+                                                 new File("/foo/bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("\\foo"),
+                                                 new File("\\foo\\bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("\\foo\\"),
+                                                 new File("\\foo\\bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("c:/foo"),
+                                                 new File("c:/foo/bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("c:/foo/"),
+                                                 new File("c:/foo/bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("c:\\foo"),
+                                                 new File("c:\\foo\\bar")));
+        assertEquals("bar", FILE_UTILS.removeLeadingPath(new File("c:\\foo\\"),
+                                                 new File("c:\\foo\\bar")));
+        if (!(Os.isFamily("dos") || Os.isFamily("netware"))) {
+            assertEquals(FILE_UTILS.normalize("/bar").getAbsolutePath(),
+                         FILE_UTILS.removeLeadingPath(new File("/foo"), new File("/bar")));
+            assertEquals(FILE_UTILS.normalize("/foobar").getAbsolutePath(),
+                         FILE_UTILS.removeLeadingPath(new File("/foo"), new File("/foobar")));
+        }
+        // bugzilla report 19979
+        assertEquals("", FILE_UTILS.removeLeadingPath(new File("/foo/bar"),
+                                              new File("/foo/bar")));
+        assertEquals("", FILE_UTILS.removeLeadingPath(new File("/foo/bar"),
+                                              new File("/foo/bar/")));
+        assertEquals("", FILE_UTILS.removeLeadingPath(new File("/foo/bar/"),
+                                              new File("/foo/bar/")));
+        assertEquals("", FILE_UTILS.removeLeadingPath(new File("/foo/bar/"),
+                                              new File("/foo/bar")));
+
+        String expected = "foo/bar".replace('\\', File.separatorChar)
+            .replace('/', File.separatorChar);
+        assertEquals(expected, FILE_UTILS.removeLeadingPath(new File("/"),
+                                                    new File("/foo/bar")));
+        assertEquals(expected, FILE_UTILS.removeLeadingPath(new File("c:/"),
+                                                    new File("c:/foo/bar")));
+        assertEquals(expected, FILE_UTILS.removeLeadingPath(new File("c:\\"),
+                                                    new File("c:\\foo\\bar")));
+    }
+
+    /**
+     * test toUri
+     */
+    public void testToURI() {
+        String dosRoot = null;
+        if (Os.isFamily("dos") || Os.isFamily("netware")) {
+            dosRoot = System.getProperty("user.dir")
+                .substring(0, 3).replace(File.separatorChar, '/');
+
+            //preserve case on Cygwin when using 1.4 toURI:
+            Class uriClazz = null;
+            try {
+                uriClazz = Class.forName("java.net.URI");
+            } catch (ClassNotFoundException e) {
+                // OK, Java 1.3.
+                dosRoot = dosRoot.toUpperCase();
+            }
+        }
+        else
+        {
+            dosRoot = "";
+        }
+        if (Os.isFamily("dos")) {
+            assertEquals("file:/c:/foo", removeExtraneousAuthority(FILE_UTILS.toURI("c:\\foo")));
+        }
+        if (Os.isFamily("netware")) {
+            assertEquals("file:/SYS:/foo", removeExtraneousAuthority(FILE_UTILS.toURI("sys:\\foo")));
+        }
+        if (File.pathSeparatorChar == '/') {
+            assertEquals("file:/foo", removeExtraneousAuthority(FILE_UTILS.toURI("/foo")));
+            assertTrue("file: URIs must name absolute paths", FILE_UTILS.toURI("./foo").startsWith("file:/"));
+            assertTrue(FILE_UTILS.toURI("./foo").endsWith("/foo"));
+            assertEquals("file:/" + dosRoot + "foo%20bar", removeExtraneousAuthority(FILE_UTILS.toURI("/foo bar")));
+            assertEquals("file:/" + dosRoot + "foo%23bar", removeExtraneousAuthority(FILE_UTILS.toURI("/foo#bar")));
+        } else if (File.pathSeparatorChar == '\\') {
+            assertEquals("file:/" + dosRoot + "foo", removeExtraneousAuthority(FILE_UTILS.toURI("\\foo")));
+            assertTrue("file: URIs must name absolute paths", FILE_UTILS.toURI(".\\foo").startsWith("file:/"));
+            assertTrue(FILE_UTILS.toURI(".\\foo").endsWith("/foo"));
+            assertEquals("file:/" + dosRoot + "foo%20bar", removeExtraneousAuthority(FILE_UTILS.toURI("\\foo bar")));
+            assertEquals("file:/" + dosRoot + "foo%23bar", removeExtraneousAuthority(FILE_UTILS.toURI("\\foo#bar")));
+        }
+        // a test with ant for germans
+        // the escaped character used for the test is the "a umlaut"
+        // this is the fix for the bug 37348
+        assertEquals("file:/" + dosRoot + "%C3%A4nt", removeExtraneousAuthority(FILE_UTILS.toURI("/\u00E4nt")));
+    }
+
+    /**
+     * Authority field is unnecessary, but harmless, in file: URIs.
+     * Java 1.4 does not produce it when using File.toURI.
+     */
+    private static String removeExtraneousAuthority(String uri) {
+        String prefix = "file:///";
+        if (uri.startsWith(prefix)) {
+            return "file:/" + uri.substring(prefix.length());
+        } else {
+            return uri;
+        }
+    }
+
+    public void testIsContextRelativePath() {
+        if (Os.isFamily("dos")) {
+            assertTrue(FileUtils.isContextRelativePath("/\u00E4nt"));
+            assertTrue(FileUtils.isContextRelativePath("\\foo"));
+        }
+    }
+    /**
+     * test fromUri
+     */
+    public void testFromURI() {
+        String dosRoot = null;
+        if (Os.isFamily("dos") || Os.isFamily("netware")) {
+            dosRoot = System.getProperty("user.dir").substring(0, 2);
+        } else {
+            dosRoot = "";
+        }
+        if (Os.isFamily("netware")) {
+            assertEqualsIgnoreDriveCase("SYS:\\foo", FILE_UTILS.fromURI("file:///sys:/foo"));
+        }
+        if (Os.isFamily("dos")) {
+            assertEqualsIgnoreDriveCase("C:\\foo", FILE_UTILS.fromURI("file:///c:/foo"));
+        }
+        assertEqualsIgnoreDriveCase(dosRoot + File.separator + "foo", FILE_UTILS.fromURI("file:///foo"));
+        assertEquals("." + File.separator + "foo",
+                     FILE_UTILS.fromURI("file:./foo"));
+        assertEquals(dosRoot + File.separator + "foo bar", FILE_UTILS.fromURI("file:///foo%20bar"));
+        assertEquals(dosRoot + File.separator + "foo#bar", FILE_UTILS.fromURI("file:///foo%23bar"));
+    }
+
+    public void testModificationTests() {
+
+        //get a time
+        long firstTime=System.currentTimeMillis();
+        //add some time. We assume no OS has a granularity this bad
+        long secondTime=firstTime+60000;
+/*
+        assertTrue("same timestamp is up to date",
+                fu.isUpToDate(firstTime, firstTime));
+                */
+
+        //check that older is up to date with a newer dest
+        assertTrue("older source files are up to date",
+                FILE_UTILS.isUpToDate(firstTime,secondTime));
+        //check that older is up to date with a newer dest
+        assertFalse("newer source files are no up to date",
+                FILE_UTILS.isUpToDate(secondTime, firstTime));
+
+        assertTrue("-1 dest timestamp implies nonexistence",
+                !FILE_UTILS.isUpToDate(firstTime,-1L));
+    }
+
+    public void testHasErrorInCase() {
+        File tempFolder = new File(System.getProperty("java.io.tmpdir"));
+        File wellcased = FILE_UTILS.createTempFile("alpha", "beta", tempFolder,
+                                                   true, true);
+        String s = wellcased.getName().toUpperCase();
+        File wrongcased = new File(tempFolder, s);
+        if (Os.isFamily("dos")) {
+            assertTrue(FILE_UTILS.hasErrorInCase(wrongcased));
+            assertFalse(FILE_UTILS.hasErrorInCase(wellcased));
+        } else {
+            assertFalse(FILE_UTILS.hasErrorInCase(wrongcased));
+            assertFalse(FILE_UTILS.hasErrorInCase(wellcased));
+        }
+        
+    }
+    public void testGetDefaultEncoding() {
+        // This just tests that the function does not blow up
+        FILE_UTILS.getDefaultEncoding();
+    }
+
+    /**
+     * adapt file separators to local conventions
+     */
+    private String localize(String path) {
+        path = root + path.substring(1);
+        return path.replace('\\', File.separatorChar).replace('/', File.separatorChar);
+    }
+
+    /**
+     * convenience method
+     * normalize brings the drive in uppercase
+     * the drive letter is in lower case under cygwin
+     * calling this method allows tests where normalize is called to pass under cygwin
+     */
+    private void assertEqualsIgnoreDriveCase(String s1, String s2) {
+        if ((Os.isFamily("dos") || Os.isFamily("netware"))
+            && s1.length() > 0 && s2.length() > 0) {
+            StringBuffer sb1 = new StringBuffer(s1);
+            StringBuffer sb2 = new StringBuffer(s2);
+            sb1.setCharAt(0, Character.toUpperCase(s1.charAt(0)));
+            sb2.setCharAt(0, Character.toUpperCase(s2.charAt(0)));
+            assertEquals(sb1.toString(), sb2.toString());
+        } else {
+            assertEquals(s1, s2);
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/GlobPatternMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/GlobPatternMapperTest.java
new file mode 100644
index 0000000..bca05b2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/GlobPatternMapperTest.java
@@ -0,0 +1,98 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for org.apache.tools.ant.util;GlobPatternMapper.
+ *
+ */
+public class GlobPatternMapperTest extends TestCase {
+
+    public GlobPatternMapperTest(String name) {
+        super(name);
+    }
+
+    public void testNoPatternAtAll() {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("foobar");
+        m.setTo("baz");
+        assertNull("Shouldn\'t match foobar", m.mapFileName("plonk"));
+        String[] result = m.mapFileName("foobar");
+        assertNotNull("Should match foobar", result);
+        assertEquals("only one result for foobar", 1, result.length);
+        assertEquals("baz", result[0]);
+    }
+
+    public void testPostfixOnly() {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("*foo");
+        m.setTo("*plonk");
+        assertNull("Shouldn\'t match *foo", m.mapFileName("bar.baz"));
+        String[] result = m.mapFileName("bar.foo");
+        assertNotNull("Should match *.foo", result);
+        assertEquals("only one result for bar.foo", 1, result.length);
+        assertEquals("bar.plonk", result[0]);
+
+        // Try a silly case
+        m.setTo("foo*");
+        result = m.mapFileName("bar.foo");
+        assertEquals("foobar.", result[0]);
+    }
+
+    public void testPrefixOnly() {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("foo*");
+        m.setTo("plonk*");
+        assertNull("Shouldn\'t match foo*", m.mapFileName("bar.baz"));
+        String[] result = m.mapFileName("foo.bar");
+        assertNotNull("Should match foo*", result);
+        assertEquals("only one result for foo.bar", 1, result.length);
+        assertEquals("plonk.bar", result[0]);
+
+        // Try a silly case
+        m.setTo("*foo");
+        result = m.mapFileName("foo.bar");
+        assertEquals(".barfoo", result[0]);
+    }
+
+    public void testPreAndPostfix() {
+        GlobPatternMapper m = new GlobPatternMapper();
+        m.setFrom("foo*bar");
+        m.setTo("plonk*pling");
+        assertNull("Shouldn\'t match foo*bar", m.mapFileName("bar.baz"));
+        String[] result = m.mapFileName("foo.bar");
+        assertNotNull("Should match foo*bar", result);
+        assertEquals("only one result for foo.bar", 1, result.length);
+        assertEquals("plonk.pling", result[0]);
+
+        // and a little longer
+        result = m.mapFileName("foo.baz.bar");
+        assertNotNull("Should match foo*bar", result);
+        assertEquals("only one result for foo.baz.bar", 1, result.length);
+        assertEquals("plonk.baz.pling", result[0]);
+
+        // and a little shorter
+        result = m.mapFileName("foobar");
+        assertNotNull("Should match foo*bar", result);
+        assertEquals("only one result for foobar", 1, result.length);
+        assertEquals("plonkpling", result[0]);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/JAXPUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/JAXPUtilsTest.java
new file mode 100644
index 0000000..e5a3b7f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/JAXPUtilsTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+/**
+ * JAXPUtils test case
+ */
+public class JAXPUtilsTest extends TestCase {
+    public JAXPUtilsTest(String name){
+        super(name);
+    }
+
+    public void testGetSystemId(){
+        File file = null;
+        if ( File.separatorChar == '\\' ){
+            file = new File("d:\\jdk");
+        } else {
+            file = new File("/user/local/bin");
+        }
+        String systemid = JAXPUtils.getSystemId(file);
+        assertTrue("SystemIDs should start by file:/", systemid.startsWith("file:/"));
+        assertTrue("SystemIDs should not start with file:////", !systemid.startsWith("file:////"));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/JavaEnvUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/JavaEnvUtilsTest.java
new file mode 100644
index 0000000..2c25fc2
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/JavaEnvUtilsTest.java
@@ -0,0 +1,140 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * TestCase for JavaEnvUtils.
+ *
+ */
+public class JavaEnvUtilsTest extends TestCase {
+
+    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+    public JavaEnvUtilsTest(String s) {
+        super(s);
+    }
+
+    public void testGetExecutableNetware() {
+        if (Os.isName("netware")) {
+            assertEquals("java", JavaEnvUtils.getJreExecutable("java"));
+            assertEquals("javac", JavaEnvUtils.getJdkExecutable("javac"));
+            assertEquals("foo", JavaEnvUtils.getJreExecutable("foo"));
+            assertEquals("foo", JavaEnvUtils.getJdkExecutable("foo"));
+        }
+    }
+
+    public void testGetExecutableWindows() {
+        if (Os.isFamily("windows")) {
+            String javaHome =
+                FILE_UTILS.normalize(System.getProperty("java.home"))
+                .getAbsolutePath();
+
+            String j = JavaEnvUtils.getJreExecutable("java");
+            assertTrue(j.endsWith(".exe"));
+            assertTrue(j+" is absolute", (new File(j)).isAbsolute());
+            try {
+                assertTrue(j+" is normalized and in the JRE dir",
+                           j.startsWith(javaHome));
+            } catch (AssertionFailedError e) {
+                // java.home is bogus
+                assertEquals("java.exe", j);
+            }
+
+            j = JavaEnvUtils.getJdkExecutable("javac");
+            assertTrue(j.endsWith(".exe"));
+            try {
+                assertTrue(j+" is absolute", (new File(j)).isAbsolute());
+                String javaHomeParent =
+                    FILE_UTILS.normalize(javaHome+"/..").getAbsolutePath();
+                assertTrue(j+" is normalized and in the JDK dir",
+                           j.startsWith(javaHomeParent));
+                assertTrue(j+" is normalized and not in the JRE dir",
+                           !j.startsWith(javaHome));
+
+            } catch (AssertionFailedError e) {
+                // java.home is bogus
+                assertEquals("javac.exe", j);
+            }
+
+            assertEquals("foo.exe", JavaEnvUtils.getJreExecutable("foo"));
+            assertEquals("foo.exe", JavaEnvUtils.getJdkExecutable("foo"));
+        }
+    }
+
+    public void testGetExecutableMostPlatforms() {
+        if (!Os.isName("netware") && !Os.isFamily("windows")) {
+            String javaHome =
+                FILE_UTILS.normalize(System.getProperty("java.home"))
+                .getAbsolutePath();
+
+            // could still be OS/2
+            String extension = Os.isFamily("dos") ? ".exe" : "";
+
+            String j = JavaEnvUtils.getJreExecutable("java");
+            if (!extension.equals("")) {
+                assertTrue(j.endsWith(extension));
+            }
+            assertTrue(j+" is absolute", (new File(j)).isAbsolute());
+            assertTrue(j+" is normalized and in the JRE dir",
+                       j.startsWith(javaHome));
+
+            j = JavaEnvUtils.getJdkExecutable("javac");
+            if (!extension.equals("")) {
+                assertTrue(j.endsWith(extension));
+            }
+            assertTrue(j+" is absolute", (new File(j)).isAbsolute());
+
+            String javaHomeParent =
+                FILE_UTILS.normalize(javaHome+"/..").getAbsolutePath();
+            assertTrue(j+" is normalized and in the JDK dir",
+                       j.startsWith(javaHomeParent));
+
+            if (Os.isFamily("mac")) {
+                assertTrue(j+" is normalized and in the JRE dir",
+                           j.startsWith(javaHome));
+            } else {
+                assertTrue(j+" is normalized and not in the JRE dir",
+                           !j.startsWith(javaHome));
+            }
+
+            assertEquals("foo"+extension,
+                         JavaEnvUtils.getJreExecutable("foo"));
+            assertEquals("foo"+extension,
+                         JavaEnvUtils.getJdkExecutable("foo"));
+        }
+
+    }
+
+    public void testIsAtLeastJavaVersion()
+    {
+        assertTrue(
+                "Current java version is not at least the current java version...",
+                JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.getJavaVersion()));
+        assertFalse(
+                "In case the current java version is higher than 9.0 definitely a new algorithem will be needed",
+                JavaEnvUtils.isAtLeastJavaVersion("9.0"));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/LazyFileOutputStreamTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/LazyFileOutputStreamTest.java
new file mode 100644
index 0000000..394669e
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/LazyFileOutputStreamTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.6
+ */
+public class LazyFileOutputStreamTest extends TestCase {
+    private LazyFileOutputStream los;
+    private final static File f = new File("test.txt");
+
+    public LazyFileOutputStreamTest(String s) {
+        super(s);
+    }
+
+    public void setUp() {
+        los = new LazyFileOutputStream(f);
+    }
+
+    public void tearDown() throws IOException {
+        try {
+            los.close();
+        } finally {
+            f.delete();
+        }
+    }
+
+    public void testNoFileWithoutWrite() throws IOException {
+        los.close();
+        assertTrue(f + " has not been written.", !f.exists());
+    }
+
+    public void testOpen() throws IOException {
+        los.open();
+        los.close();
+        assertTrue(f + " has been written.", f.exists());
+    }
+
+    public void testSingleByte() throws IOException {
+        los.write(0);
+        los.close();
+        assertTrue(f + " has been written.", f.exists());
+    }
+
+    public void testByteArray() throws IOException {
+        los.write(new byte[] {0});
+        los.close();
+        assertTrue(f + " has been written.", f.exists());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/LineOrientedOutputStreamTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/LineOrientedOutputStreamTest.java
new file mode 100644
index 0000000..7bcb4dc
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/LineOrientedOutputStreamTest.java
@@ -0,0 +1,139 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import java.io.IOException;
+import junit.framework.TestCase;
+
+/**
+ */
+
+public class LineOrientedOutputStreamTest extends TestCase {
+
+    private static String LINE = "This is a line";
+    private DummyStream stream;
+
+    public LineOrientedOutputStreamTest(String name) {
+        super(name);
+    }
+    
+    public void setUp() {
+        stream = new DummyStream();
+    }
+
+    public void tearDown() throws IOException {
+        if (stream != null) {
+            stream.close();
+        }
+    }
+
+    public void testLineWithLinefeedArray() throws IOException {
+        writeByteArray();
+        writeAsArray('\n');
+        stream.assertInvoked();
+    }
+
+    public void testLineWithLinefeedSingleBytes() throws IOException {
+        writeSingleBytes();
+        stream.write('\n');
+        stream.assertInvoked();
+    }
+
+    public void testLineWithCariagereturnArray() throws IOException {
+        writeByteArray();
+        writeAsArray('\r');
+        stream.assertInvoked();
+    }
+
+    public void testLineWithCariagereturnSingleBytes() throws IOException {
+        writeSingleBytes();
+        stream.write('\r');
+        stream.assertInvoked();
+    }
+
+    public void testLineWithCariagereturnLinefeedArray() throws IOException {
+        writeByteArray();
+        writeAsArray('\r');
+        writeAsArray('\n');
+        stream.assertInvoked();
+    }
+
+    public void testLineWithCariagereturnLinefeedSingleBytes() throws IOException {
+        writeSingleBytes();
+        stream.write('\r');
+        stream.write('\n');
+        stream.assertInvoked();
+    }
+
+    public void testFlushArray() throws IOException {
+        writeByteArray();
+        stream.flush();
+        stream.assertInvoked();
+    }
+
+    public void testFlushSingleBytes() throws IOException {
+        writeSingleBytes();
+        stream.flush();
+        stream.assertInvoked();
+    }
+
+    public void testCloseArray() throws IOException {
+        writeByteArray();
+        stream.close();
+        stream.assertInvoked();
+        stream = null;
+    }
+
+    public void testCloseSingleBytes() throws IOException {
+        writeSingleBytes();
+        stream.close();
+        stream.assertInvoked();
+        stream = null;
+    }
+
+    private void writeByteArray() throws IOException {
+        stream.write(LINE.getBytes(), 0, LINE.length());
+    }
+
+    private void writeSingleBytes() throws IOException {
+        byte[] b = LINE.getBytes();
+        for (int i = 0; i < b.length; i++) {
+            stream.write(b[i]);
+        }
+    }
+
+    private void writeAsArray(char c) throws IOException {
+        stream.write(new byte[] {(byte) c}, 0, 1);
+    }
+
+    private class DummyStream extends LineOrientedOutputStream {
+        private boolean invoked;
+        protected void processLine(String line) {
+            LineOrientedOutputStreamTest.this.assertFalse("Only one line",
+                                                          invoked);
+            LineOrientedOutputStreamTest.this.assertEquals(LINE, line);
+            invoked = true;
+        }
+
+        private void assertInvoked() {
+            LineOrientedOutputStreamTest.this.assertTrue("At least one line",
+                                                          invoked);
+        }
+    }
+}// LineOrientedOutputStreamTest
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/LoaderUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/LoaderUtilsTest.java
new file mode 100644
index 0000000..49518ea
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/LoaderUtilsTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.6
+ */
+public class LoaderUtilsTest extends TestCase {
+
+    public LoaderUtilsTest(String name) {
+        super(name);
+    }
+
+    public void testGetXyzSource() {
+        File f1 = LoaderUtils.getClassSource(LoaderUtils.class);
+        assertNotNull(f1);
+
+        File f2 = LoaderUtils.getResourceSource(null,
+                                                "org/apache/tools/ant/taskdefs/defaults.properties");
+        assertNotNull(f2);
+
+        assertEquals(f1.getAbsolutePath(), f2.getAbsolutePath());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/PackageNameMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/PackageNameMapperTest.java
new file mode 100644
index 0000000..f6c859f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/PackageNameMapperTest.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ package org.apache.tools.ant.util;
+
+import java.io.File;
+import junit.framework.TestCase;
+
+public class PackageNameMapperTest extends TestCase {
+    public PackageNameMapperTest(String name) { super(name); }
+
+    public void testMapping() {
+        PackageNameMapper mapper = new PackageNameMapper();
+        mapper.setFrom("*.java");
+        mapper.setTo("TEST-*.xml");
+        String file = fixupPath("org/apache/tools/ant/util/PackageNameMapperTest.java");
+        String result = mapper.mapFileName(file)[0];
+
+        assertEquals("TEST-org.apache.tools.ant.util.PackageNameMapperTest.xml",
+          result);
+    }
+
+    private String fixupPath(String file) {
+        return file.replace('/', File.separatorChar);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/ReaderInputStreamTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/ReaderInputStreamTest.java
new file mode 100644
index 0000000..5e421ce
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/ReaderInputStreamTest.java
@@ -0,0 +1,96 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.*;
+
+import junit.framework.TestCase;
+
+/**
+ * Test for ReaderInputStream
+ */
+public class ReaderInputStreamTest extends TestCase {
+    public ReaderInputStreamTest(String s) {
+        super(s);
+    }
+
+    public void testSimple() throws Exception {
+        compareBytes("abc", "utf-8");
+    }
+
+    public void testSimple16() throws Exception {
+        compareBytes("a", "utf-16");
+    }
+
+    public void testSimpleAbc16() throws Exception {
+        // THIS WILL FAIL.
+        //compareBytes("abc", "utf-16");
+        byte[] bytes = new byte[40];
+        int pos = 0;
+        ReaderInputStream r = new ReaderInputStream(
+            new StringReader("abc"), "utf-16");
+        for (int i = 0; true; ++i) {
+            int res = r.read();
+            if (res == -1) {
+                break;
+            }
+            bytes[pos++] = (byte) res;
+        }
+        bytes = "abc".getBytes("utf-16");
+        //        String n = new String(bytes, 0, pos, "utf-16");
+        String n = new String(bytes, 0, bytes.length, "utf-16");
+        System.out.println(n);
+    }
+
+    public void testReadZero() throws Exception {
+        ReaderInputStream r = new ReaderInputStream(
+            new StringReader("abc"));
+        byte[] bytes = new byte[30];
+        // First read in zero bytes
+        r.read(bytes, 0, 0);
+        // Now read in the string
+        int readin = r.read(bytes, 0, 10);
+        // Make sure that the counts are the same
+        assertEquals("abc".getBytes().length, readin);
+    }
+
+    public void testPreample() throws Exception {
+        byte[] bytes = "".getBytes("utf-16");
+        System.out.println("Preample len is " + bytes.length);
+    }
+    
+    private void compareBytes(String s, String encoding) throws Exception {
+        byte[] expected = s.getBytes(encoding);
+        
+        ReaderInputStream r = new ReaderInputStream(
+            new StringReader(s), encoding);
+        for (int i = 0; i < expected.length; ++i) {
+            int expect = expected[i] & 0xFF;
+            int read = r.read();
+            if (expect != read) {
+                fail("Mismatch in ReaderInputStream at index " + i
+                     + " expecting " + expect + " got " + read + " for string "
+                     + s + " with encoding " + encoding);
+            }
+        }
+        if (r.read() != -1) {
+            fail("Mismatch in ReaderInputStream - EOF not seen for string "
+                 + s + " with encoding " + encoding);
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/ResourceUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/ResourceUtilsTest.java
new file mode 100644
index 0000000..072718c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/ResourceUtilsTest.java
@@ -0,0 +1,61 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import junit.framework.TestCase;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Echo;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+
+/**
+ * Tests for org.apache.tools.ant.util.ResourceUtils.
+ */
+public class ResourceUtilsTest extends TestCase
+    implements ResourceFactory, FileNameMapper {
+
+    private Echo taskINeedForLogging = new Echo();
+
+    public ResourceUtilsTest(String name) {
+        super(name);
+        taskINeedForLogging.setProject(new Project());
+    }
+
+    public void testNoDuplicates() {
+        Resource r = new Resource("samual vimes", true, 1, false);
+        Resource[] toNew =
+            ResourceUtils.selectOutOfDateSources(taskINeedForLogging,
+                                                 new Resource[] {r},
+                                                 this, this);
+        assertEquals(1, toNew.length);
+    }
+
+    /* ============ ResourceFactory interface ====================== */
+    public Resource getResource(String name) {
+        return new Resource(name); // implies lastModified == 0
+    }
+
+    /* ============ FileNameMapper interface ======================= */
+    public void setFrom(String s) {}
+    public void setTo(String s) {}
+    public String[] mapFileName(String s) {
+        return new String[] {"fred colon", "carrot ironfoundersson"};
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/StringUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/StringUtilsTest.java
new file mode 100644
index 0000000..52e0898
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/StringUtilsTest.java
@@ -0,0 +1,154 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+/**
+ * Test for StringUtils
+ */
+public class StringUtilsTest extends TestCase {
+    public StringUtilsTest(String s) {
+        super(s);
+    }
+
+    public void testSplit(){
+        final String data = "a,b,,";
+        Vector res = StringUtils.split(data, ',');
+        assertEquals(4, res.size());
+        assertEquals("a", res.elementAt(0));
+        assertEquals("b", res.elementAt(1));
+        assertEquals("", res.elementAt(2));
+        assertEquals("", res.elementAt(3));
+    }
+
+    public void testSplitLines(){
+        final String data = "a\r\nb\nc\nd\ne";
+        Vector res = StringUtils.lineSplit(data);
+        assertEquals(5, res.size());
+        assertEquals("a\r", res.elementAt(0));
+        assertEquals("b", res.elementAt(1));
+        assertEquals("c", res.elementAt(2));
+        assertEquals("d", res.elementAt(3));
+        assertEquals("e", res.elementAt(4));
+    }
+
+    public void testReplace() {
+        final String data = "abcabcabca";
+        String res = StringUtils.replace(data, "a", "");
+        assertEquals("bcbcbc", res);
+    }
+
+    public void testEndsWithBothEmpty() {
+        assertTrue( StringUtils.endsWith( new StringBuffer(), "") );
+    }
+
+    public void testEndsWithEmptyString() {
+        assertTrue( StringUtils.endsWith( new StringBuffer("12234545"), "") );
+    }
+
+    public void testEndsWithShorterString() {
+        assertTrue( StringUtils.endsWith( new StringBuffer("12345678"), "78"));
+    }
+
+    public void testEndsWithSameString() {
+        assertTrue( StringUtils.endsWith( new StringBuffer("123"), "123"));
+    }
+
+    public void testEndsWithLongerString() {
+        assertFalse( StringUtils.endsWith( new StringBuffer("12"), "1245"));
+    }
+
+    public void testEndsWithNoMatch() {
+        assertFalse( StringUtils.endsWith( new StringBuffer("12345678"), "789"));
+    }
+
+    public void testEndsWithEmptyBuffer() {
+        assertFalse( StringUtils.endsWith( new StringBuffer(""), "12345667") );
+    }
+
+    public void testEndsWithJDKPerf() {
+        StringBuffer buf = getFilledBuffer(1024*300, 'a');
+        for (int i = 0; i < 1000; i++) {
+            assertTrue(buf.toString().endsWith("aa"));
+        }
+    }
+
+    public void testEndsWithPerf() {
+        StringBuffer buf = getFilledBuffer(1024*300, 'a');
+        for (int i = 0; i < 1000; i++) {
+            assertTrue(StringUtils.endsWith(buf, "aa"));
+        }
+    }
+
+    private StringBuffer getFilledBuffer(int size, char ch) {
+        StringBuffer buf = new StringBuffer(size);
+        for (int i = 0; i < size; i++) { buf.append(ch); };
+        return buf;
+    }
+    
+    public void testParseHumanSizes() throws Exception {
+    	final long KILOBYTE = 1024;
+    	final long MEGABYTE = KILOBYTE * 1024;
+    	final long GIGABYTE = MEGABYTE * 1024;
+    	final long TERABYTE = GIGABYTE * 1024;
+    	final long PETABYTE = TERABYTE * 1024;
+    	assertEquals(StringUtils.parseHumanSizes("1K"), KILOBYTE);
+    	assertEquals(StringUtils.parseHumanSizes("1M"), MEGABYTE);
+    	assertEquals(StringUtils.parseHumanSizes("1G"), GIGABYTE);
+    	assertEquals(StringUtils.parseHumanSizes("1T"), TERABYTE);
+    	assertEquals(StringUtils.parseHumanSizes("1P"), PETABYTE);
+    	assertEquals(StringUtils.parseHumanSizes("1"), 1L);
+    }
+    
+    public void testRemoveSuffix() {
+        String prefix = "Prefix";
+        String name = "Name";
+        String suffix = "Suffix";
+        String input = prefix + name + suffix;
+        assertEquals(
+            "Does not remove the suffix right.",    
+            prefix + name, 
+            StringUtils.removeSuffix(input, suffix)
+        );
+        assertEquals(
+            "Should leave the string unattended.",    
+            prefix + name + suffix, 
+            StringUtils.removeSuffix(input, "bla")
+        );
+    }
+    
+    public void testRemovePrefix() {
+        String prefix = "Prefix";
+        String name = "Name";
+        String suffix = "Suffix";
+        String input = prefix + name + suffix;
+        assertEquals(
+            "Does not remove the prefix right.",    
+            name + suffix, 
+            StringUtils.removePrefix(input, prefix)
+        );
+        assertEquals(
+            "Should leave the string unattended.",    
+            prefix + name + suffix, 
+            StringUtils.removePrefix(input, "bla")
+        );
+    }    
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/UnPackageNameMapperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/UnPackageNameMapperTest.java
new file mode 100644
index 0000000..c78e1d3
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/UnPackageNameMapperTest.java
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.ant.util;
+
+import java.io.File;
+import junit.framework.TestCase;
+
+public class UnPackageNameMapperTest extends TestCase {
+    public UnPackageNameMapperTest(String name) { super(name); }
+
+    public void testMapping() {
+        UnPackageNameMapper mapper = new UnPackageNameMapper();
+        mapper.setFrom("TEST-*.xml");
+        mapper.setTo("*.java");
+        String file ="TEST-org.apache.tools.ant.util.UnPackageNameMapperTest.xml";
+        String result = mapper.mapFileName(file)[0];
+        String expected = fixupPath("org/apache/tools/ant/util/UnPackageNameMapperTest.java");
+
+        assertEquals(expected, result);
+    }
+
+    private String fixupPath(String file) {
+        return file.replace('/', File.separatorChar);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/XMLFragmentTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/XMLFragmentTest.java
new file mode 100644
index 0000000..f139d60
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/XMLFragmentTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class XMLFragmentTest extends BuildFileTest {
+
+    public XMLFragmentTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject("src/etc/testcases/types/xmlfragment.xml");
+    }
+
+    public void testNestedText() {
+        XMLFragment x = (XMLFragment) getProject().getReference("nested-text");
+        assertNotNull(x);
+        Node n = x.getFragment();
+        assertTrue("No attributes", !n.hasAttributes());
+        NodeList nl = n.getChildNodes();
+        assertEquals(1, nl.getLength());
+        assertEquals(Node.TEXT_NODE, nl.item(0).getNodeType());
+        assertEquals("foo", nl.item(0).getNodeValue());
+    }
+
+    public void testNestedChildren() {
+        XMLFragment x =
+            (XMLFragment) getProject().getReference("with-children");
+        assertNotNull(x);
+        Node n = x.getFragment();
+        assertTrue("No attributes", !n.hasAttributes());
+        NodeList nl = n.getChildNodes();
+        assertEquals(3, nl.getLength());
+
+        assertEquals(Node.ELEMENT_NODE, nl.item(0).getNodeType());
+        Element child1 = (Element) nl.item(0);
+        assertEquals("child1", child1.getTagName());
+        assertTrue(!child1.hasAttributes());
+        NodeList nl2 = child1.getChildNodes();
+        assertEquals(1, nl2.getLength());
+        assertEquals(Node.TEXT_NODE, nl2.item(0).getNodeType());
+        assertEquals("foo", nl2.item(0).getNodeValue());
+
+        assertEquals(Node.ELEMENT_NODE, nl.item(1).getNodeType());
+        Element child2 = (Element) nl.item(1);
+        assertEquals("child2", child2.getTagName());
+        assertTrue(child2.hasAttributes());
+        nl2 = child2.getChildNodes();
+        assertEquals(0, nl2.getLength());
+        assertEquals("bar", child2.getAttribute("foo"));
+
+        assertEquals(Node.ELEMENT_NODE, nl.item(2).getNodeType());
+        Element child3 = (Element) nl.item(2);
+        assertEquals("child3", child3.getTagName());
+        assertTrue(!child3.hasAttributes());
+        nl2 = child3.getChildNodes();
+        assertEquals(1, nl2.getLength());
+        assertEquals(Node.ELEMENT_NODE, nl2.item(0).getNodeType());
+        assertEquals("child4", ((Element) nl2.item(0)).getTagName());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/facade/FacadeTaskHelperTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/facade/FacadeTaskHelperTest.java
new file mode 100644
index 0000000..f80b4d9
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/facade/FacadeTaskHelperTest.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.facade;
+
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.5
+ */
+public class FacadeTaskHelperTest extends TestCase {
+
+    public FacadeTaskHelperTest(String name) {
+        super(name);
+    }
+
+    public void testPrecedenceRules() {
+        FacadeTaskHelper fth = new FacadeTaskHelper("foo");
+        assertEquals("foo", fth.getImplementation());
+
+        fth.setMagicValue("bar");
+        assertEquals("bar", fth.getImplementation());
+
+        fth = new FacadeTaskHelper("foo", "bar");
+        assertEquals("bar", fth.getImplementation());
+
+        fth = new FacadeTaskHelper("foo", null);
+        assertEquals("foo", fth.getImplementation());
+
+        fth = new FacadeTaskHelper("foo");
+        fth.setMagicValue("bar");
+        fth.setImplementation("baz");
+        assertEquals("baz", fth.getImplementation());
+    }
+
+    public void testHasBeenSet() {
+        FacadeTaskHelper fth = new FacadeTaskHelper("foo");
+        assertTrue("nothing set", !fth.hasBeenSet());
+        fth.setMagicValue(null);
+        assertTrue("magic has not been set", !fth.hasBeenSet());
+        fth.setMagicValue("foo");
+        assertTrue("magic has been set", fth.hasBeenSet());
+        fth.setMagicValue(null);
+        assertTrue(!fth.hasBeenSet());
+        fth.setImplementation("baz");
+        assertTrue("set explicitly", fth.hasBeenSet());
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/facade/ImplementationSpecificArgumentTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/facade/ImplementationSpecificArgumentTest.java
new file mode 100644
index 0000000..e4e7a2a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/facade/ImplementationSpecificArgumentTest.java
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.facade;
+
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.5
+ */
+public class ImplementationSpecificArgumentTest extends TestCase {
+
+    public ImplementationSpecificArgumentTest(String name) {
+        super(name);
+    }
+
+    public void testDependsOnImplementation() {
+        ImplementationSpecificArgument ia =
+            new ImplementationSpecificArgument();
+        ia.setLine("A B");
+        String[] parts = ia.getParts();
+        assertNotNull(parts);
+        assertEquals(2, parts.length);
+        assertEquals("A", parts[0]);
+        assertEquals("B", parts[1]);
+
+        parts = ia.getParts(null);
+        assertNotNull(parts);
+        assertEquals(2, parts.length);
+        assertEquals("A", parts[0]);
+        assertEquals("B", parts[1]);
+
+        ia.setImplementation("foo");
+        parts = ia.getParts(null);
+        assertNotNull(parts);
+        assertEquals(0, parts.length);
+
+        parts = ia.getParts("foo");
+        assertNotNull(parts);
+        assertEquals(2, parts.length);
+        assertEquals("A", parts[0]);
+        assertEquals("B", parts[1]);
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroMatcherTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroMatcherTest.java
new file mode 100644
index 0000000..d1405f4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroMatcherTest.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+/**
+ * Tests for the jakarta-oro implementation of the RegexpMatcher interface.
+ *
+ */
+public class JakartaOroMatcherTest extends RegexpMatcherTest {
+
+    public RegexpMatcher getImplementation() {
+        return new JakartaOroMatcher();
+    }
+
+    public JakartaOroMatcherTest(String name) {
+        super(name);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroRegexpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroRegexpTest.java
new file mode 100644
index 0000000..e869c62
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaOroRegexpTest.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+/**
+ * Tests for the jakarta-oro implementation of the Regexp interface.
+ *
+ */
+public class JakartaOroRegexpTest extends RegexpTest {
+
+    public Regexp getRegexpImplementation() {
+        return new JakartaOroRegexp();
+    }
+
+    public JakartaOroRegexpTest(String name) {
+        super(name);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpMatcherTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpMatcherTest.java
new file mode 100644
index 0000000..3340b59
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpMatcherTest.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.io.IOException;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests for the jakarta-regexp implementation of the RegexpMatcher interface.
+ *
+ */
+public class JakartaRegexpMatcherTest extends RegexpMatcherTest {
+
+    public RegexpMatcher getImplementation() {
+        return new JakartaRegexpMatcher();
+    }
+
+    public JakartaRegexpMatcherTest(String name) {
+        super(name);
+    }
+
+    public void testWindowsLineSeparator2() throws IOException {
+        try {
+            super.testWindowsLineSeparator2();
+            fail("Should trigger when this bug is fixed. {@since 1.2}");
+        } catch (AssertionFailedError e) {
+        }
+    }
+
+    /**
+     * Fails for the same reason as "default" mode in doEndTest2.
+     */
+    public void testUnixLineSeparator() throws IOException {
+        try {
+            super.testUnixLineSeparator();
+            fail("Should trigger once this bug is fixed. {@since 1.2}");
+        } catch (AssertionFailedError e) {
+        }
+    }
+
+
+    /**
+     * Fails for "default" mode.
+     */
+    protected void doEndTest2(String text) {}
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpRegexpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpRegexpTest.java
new file mode 100644
index 0000000..078fbb1
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/JakartaRegexpRegexpTest.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.io.IOException;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests for the jakarta-regexp implementation of the Regexp interface.
+ *
+ */
+public class JakartaRegexpRegexpTest extends RegexpTest {
+
+    public Regexp getRegexpImplementation() {
+        return new JakartaRegexpRegexp();
+    }
+
+    public JakartaRegexpRegexpTest(String name) {
+        super(name);
+    }
+
+    public void testWindowsLineSeparator2() throws IOException {
+        try {
+            super.testWindowsLineSeparator2();
+            fail("Should trigger when this bug is fixed. {@since 1.2}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    /**
+     * Fails for the same reason as "default" mode in doEndTest2.
+     */
+    public void testUnixLineSeparator() throws IOException {
+        try {
+            super.testUnixLineSeparator();
+            fail("Should trigger once this bug is fixed. {@since 1.2}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    /**
+     * Fails for "default" mode.
+     */
+    protected void doEndTest2(String text) {}
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcherTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcherTest.java
new file mode 100644
index 0000000..c042e71
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcherTest.java
@@ -0,0 +1,70 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.io.IOException;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests for the JDK 1.4 implementation of the RegexpMatcher interface.
+ *
+ */
+public class Jdk14RegexpMatcherTest extends RegexpMatcherTest {
+
+    public RegexpMatcher getImplementation() {
+        return new Jdk14RegexpMatcher();
+    }
+
+    public Jdk14RegexpMatcherTest(String name) {
+        super(name);
+    }
+
+    public void testParagraphCharacter() throws IOException {
+        try {
+            super.testParagraphCharacter();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testLineSeparatorCharacter() throws IOException {
+        try {
+            super.testLineSeparatorCharacter();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testStandaloneCR() throws IOException {
+        try {
+            super.testStandaloneCR();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testWindowsLineSeparator() throws IOException {
+        try {
+            super.testWindowsLineSeparator();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexpTest.java
new file mode 100644
index 0000000..2b60406
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexpTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.io.IOException;
+
+import junit.framework.AssertionFailedError;
+
+/**
+ * Tests for the JDK 1.4 implementation of the Regexp interface.
+ *
+ */
+public class Jdk14RegexpRegexpTest extends RegexpTest {
+
+    public Regexp getRegexpImplementation() {
+        return new Jdk14RegexpRegexp();
+    }
+
+    public Jdk14RegexpRegexpTest(String name) {
+        super(name);
+    }
+
+    public void testParagraphCharacter() throws IOException {
+        try {
+            super.testParagraphCharacter();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testLineSeparatorCharacter() throws IOException {
+        try {
+            super.testLineSeparatorCharacter();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testStandaloneCR() throws IOException {
+        try {
+            super.testStandaloneCR();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+    public void testWindowsLineSeparator() throws IOException {
+        try {
+            super.testWindowsLineSeparator();
+            fail("Should trigger once fixed. {@since JDK 1.4RC1}");
+        } catch (AssertionFailedError e){
+        }
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpMatcherTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpMatcherTest.java
new file mode 100644
index 0000000..0950827
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpMatcherTest.java
@@ -0,0 +1,204 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for all implementations of the RegexpMatcher interface.
+ *
+ */
+public abstract class RegexpMatcherTest extends TestCase {
+
+    public final static String UNIX_LINE = "\n";
+
+    private RegexpMatcher reg;
+
+    public abstract RegexpMatcher getImplementation();
+
+    protected final RegexpMatcher getReg() {return reg;}
+
+    public RegexpMatcherTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        reg = getImplementation();
+    }
+
+    public void testMatches() {
+        reg.setPattern("aaaa");
+        assertTrue("aaaa should match itself", reg.matches("aaaa"));
+        assertTrue("aaaa should match xaaaa", reg.matches("xaaaa"));
+        assertTrue("aaaa shouldn\'t match xaaa", !reg.matches("xaaa"));
+        reg.setPattern("^aaaa");
+        assertTrue("^aaaa shouldn\'t match xaaaa", !reg.matches("xaaaa"));
+        assertTrue("^aaaa should match aaaax", reg.matches("aaaax"));
+        reg.setPattern("aaaa$");
+        assertTrue("aaaa$ shouldn\'t match aaaax", !reg.matches("aaaax"));
+        assertTrue("aaaa$ should match xaaaa", reg.matches("xaaaa"));
+        reg.setPattern("[0-9]+");
+        assertTrue("[0-9]+ should match 123", reg.matches("123"));
+        assertTrue("[0-9]+ should match 1", reg.matches("1"));
+        assertTrue("[0-9]+ shouldn\'t match \'\'", !reg.matches(""));
+        assertTrue("[0-9]+ shouldn\'t match a", !reg.matches("a"));
+        reg.setPattern("[0-9]*");
+        assertTrue("[0-9]* should match 123", reg.matches("123"));
+        assertTrue("[0-9]* should match 1", reg.matches("1"));
+        assertTrue("[0-9]* should match \'\'", reg.matches(""));
+        assertTrue("[0-9]* should match a", reg.matches("a"));
+        reg.setPattern("([0-9]+)=\\1");
+        assertTrue("([0-9]+)=\\1 should match 1=1", reg.matches("1=1"));
+        assertTrue("([0-9]+)=\\1 shouldn\'t match 1=2", !reg.matches("1=2"));
+    }
+
+    public void testGroups() {
+        reg.setPattern("aaaa");
+        Vector v = reg.getGroups("xaaaa");
+        assertEquals("No parens -> no extra groups", 1, v.size());
+        assertEquals("Trivial match with no parens", "aaaa",
+                     (String) v.elementAt(0));
+
+        reg.setPattern("(aaaa)");
+        v = reg.getGroups("xaaaa");
+        assertEquals("Trivial match with single paren", 2, v.size());
+        assertEquals("Trivial match with single paren, full match", "aaaa",
+                     (String) v.elementAt(0));
+        assertEquals("Trivial match with single paren, matched paren", "aaaa",
+                     (String) v.elementAt(0));
+
+        reg.setPattern("(a+)b(b+)");
+        v = reg.getGroups("xaabb");
+        assertEquals(3, v.size());
+        assertEquals("aabb", (String) v.elementAt(0));
+        assertEquals("aa", (String) v.elementAt(1));
+        assertEquals("b", (String) v.elementAt(2));
+    }
+
+    public void testBugzillaReport14619() {
+        reg.setPattern("^(.*)/src/((.*/)*)([a-zA-Z0-9_\\.]+)\\.java$");
+        Vector v = reg.getGroups("de/tom/src/Google.java");
+        assertEquals(5, v.size());
+        assertEquals("de/tom", v.elementAt(1));
+        assertEquals("", v.elementAt(2));
+        assertEquals("", v.elementAt(3));
+        assertEquals("Google", v.elementAt(4));
+    }
+
+    public void testCaseInsensitiveMatch() {
+        reg.setPattern("aaaa");
+        assertTrue("aaaa doesn't match AAaa", !reg.matches("AAaa"));
+        assertTrue("aaaa matches AAaa ignoring case",
+                   reg.matches("AAaa", RegexpMatcher.MATCH_CASE_INSENSITIVE));
+    }
+
+
+// make sure there are no issues concerning line separator interpretation
+// a line separator for regex (perl) is always a unix line (ie \n)
+
+    public void testParagraphCharacter() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("paragraph character", !reg.matches("end of text\u2029"));
+    }
+
+    public void testLineSeparatorCharacter() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("line-separator character", !reg.matches("end of text\u2028"));
+    }
+
+    public void testNextLineCharacter() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("next-line character", !reg.matches("end of text\u0085"));
+    }
+
+    public void testStandaloneCR() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("standalone CR", !reg.matches("end of text\r"));
+    }
+
+    public void testWindowsLineSeparator() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("Windows line separator", !reg.matches("end of text\r\n"));
+    }
+
+    public void testWindowsLineSeparator2() throws IOException {
+        reg.setPattern("end of text\r$");
+        assertTrue("Windows line separator", reg.matches("end of text\r\n"));
+    }
+
+    public void testUnixLineSeparator() throws IOException {
+        reg.setPattern("end of text$");
+        assertTrue("Unix line separator", reg.matches("end of text\n"));
+    }
+
+
+    public void testMultiVersusSingleLine() throws IOException {
+        StringBuffer buf = new StringBuffer();
+        buf.append("Line1").append(UNIX_LINE);
+        buf.append("starttest Line2").append(UNIX_LINE);
+        buf.append("Line3 endtest").append(UNIX_LINE);
+        buf.append("Line4").append(UNIX_LINE);
+        String text = buf.toString();
+
+        doStartTest1(text);
+        doStartTest2(text);
+        doEndTest1(text);
+        doEndTest2(text);
+    }
+
+    protected void doStartTest1(String text) {
+        reg.setPattern("^starttest");
+        assertTrue("^starttest in default mode", !reg.matches(text));
+        assertTrue("^starttest in single line mode",
+               !reg.matches(text, RegexpMatcher.MATCH_SINGLELINE));
+        assertTrue("^starttest in multi line mode",
+               reg.matches(text, RegexpMatcher.MATCH_MULTILINE));
+    }
+
+    protected void doStartTest2(String text) {
+        reg.setPattern("^Line1");
+        assertTrue("^Line1 in default mode", reg.matches(text));
+        assertTrue("^Line1 in single line mode",
+               reg.matches(text, RegexpMatcher.MATCH_SINGLELINE));
+        assertTrue("^Line1 in multi line mode",
+               reg.matches(text, RegexpMatcher.MATCH_MULTILINE));
+    }
+
+    protected void doEndTest1(String text) {
+        reg.setPattern("endtest$");
+        assertTrue("endtest$ in default mode", !reg.matches(text));
+        assertTrue("endtest$ in single line mode",
+               !reg.matches(text, RegexpMatcher.MATCH_SINGLELINE));
+        assertTrue("endtest$ in multi line mode",
+               reg.matches(text, RegexpMatcher.MATCH_MULTILINE));
+    }
+
+    protected void doEndTest2(String text) {
+        reg.setPattern("Line4$");
+        assertTrue("Line4$ in default mode", reg.matches(text));
+        assertTrue("Line4$ in single line mode",
+               reg.matches(text, RegexpMatcher.MATCH_SINGLELINE));
+        assertTrue("Line4$ in multi line mode",
+               reg.matches(text, RegexpMatcher.MATCH_MULTILINE));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpTest.java b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpTest.java
new file mode 100644
index 0000000..5cfe8c9
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/ant/util/regexp/RegexpTest.java
@@ -0,0 +1,63 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.util.regexp;
+
+/**
+ * Tests for all implementations of the Regexp interface.
+ *
+ */
+public abstract class RegexpTest extends RegexpMatcherTest {
+
+    private static final String test = "abcdefg-abcdefg";
+    private static final String pattern = "ab([^d]*)d([^f]*)f";
+
+    public RegexpTest(String name) {
+        super(name);
+    }
+
+    public final RegexpMatcher getImplementation() {
+        return getRegexpImplementation();
+    }
+
+    public abstract Regexp getRegexpImplementation();
+
+    public void testSubstitution() {
+        Regexp reg = (Regexp) getReg();
+        reg.setPattern(pattern);
+        assertTrue(reg.matches(test));
+        assertEquals("abedcfg-abcdefg", reg.substitute(test, "ab\\2d\\1f",
+                                                       Regexp.MATCH_DEFAULT));
+    }
+
+    public void testReplaceFirstSubstitution() {
+        Regexp reg = (Regexp) getReg();
+        reg.setPattern(pattern);
+        assertTrue(reg.matches(test));
+        assertEquals("abedcfg-abcdefg", reg.substitute(test, "ab\\2d\\1f",
+                                                       Regexp.REPLACE_FIRST));
+    }
+
+    public void testReplaceAllSubstitution() {
+        Regexp reg = (Regexp) getReg();
+        reg.setPattern(pattern);
+        assertTrue(reg.matches(test));
+        assertEquals("abedcfg-abedcfg", reg.substitute(test, "ab\\2d\\1f",
+                                                       Regexp.REPLACE_ALL));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/mail/MailMessageTest.java b/trunk/src/tests/junit/org/apache/tools/mail/MailMessageTest.java
new file mode 100644
index 0000000..a8e7530
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/mail/MailMessageTest.java
@@ -0,0 +1,734 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.mail;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.mail.MailMessage;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.mail.MailMessage.
+ *
+ * @since Ant 1.6
+ */
+public class MailMessageTest extends TestCase {
+
+    // 27224 = magic (a random port which is unlikely to be in use)
+    private static int TEST_PORT = 27224;
+
+    private String local = null;
+
+    public MailMessageTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        try {
+            local = InetAddress.getLocalHost().getHostName();
+        } catch (java.net.UnknownHostException uhe) {
+            // ignore
+        }
+    }
+
+    /**
+     *  Test an example that is similar to the one given in the API
+     *  If this testcase takes >90s to complete, it is very likely that
+     *  the two threads are blocked waiting for each other and Thread.join()
+     *  timed out.
+     */
+    public void testAPIExample() {
+
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.to("to@you.com");
+        testMailClient.cc("cc1@you.com");
+        testMailClient.cc("cc2@you.com");
+        testMailClient.bcc("bcc@you.com");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage( "test line 1\n" +
+            "test line 2" );
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail( "InterruptedException: " + ie );
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <to@you.com>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <cc1@you.com>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <cc2@you.com>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <bcc@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+        "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+        "To: to@you.com\r\n" +
+        "Cc: cc1@you.com, cc2@you.com\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "test line 1\r\n" +
+        "test line 2\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        for (int icounter = 0; icounter<expectedResult.length(); icounter++) {
+            if (icounter < result.length()) {
+                if (expectedResult.charAt(icounter) != result.charAt(icounter)) {
+                    System.out.println("posit " + icounter + " expected "
+                        + expectedResult.charAt(icounter)
+                    + " result " + result.charAt(icounter));
+                }
+            }
+        }
+        if (expectedResult.length()>result.length()) {
+            System.out.println("excedent of expected result "
+                + expectedResult.substring(result.length()));
+        }
+        if (expectedResult.length()<result.length()) {
+            System.out.println("excedent of result "
+                + result.substring(expectedResult.length()));
+        }
+        assertEquals(expectedResult.length(), result.length());
+        assertEquals(expectedResult, result); // order of headers cannot be guaranteed
+        if (testMailClient.isFailed()) {
+            fail(testMailClient.getFailMessage());
+        }
+    }
+
+    /**
+     *  Test a MailMessage with no cc or bcc lines
+     */
+    public void testToOnly() {
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.to("to@you.com");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage( "test line 1\n" +
+            "test line 2" );
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail("InterruptedException: " + ie);
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <to@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+            "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+            "To: to@you.com\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "test line 1\r\n" +
+        "test line 2\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        assertEquals(expectedResult.length(), result.length());
+        assertEquals(expectedResult, result); // order of headers cannot be guaranteed
+        if (testMailClient.isFailed()) {
+            fail(testMailClient.getFailMessage());
+        }
+    }
+
+
+    /**
+     *  Test a MailMessage with no to or bcc lines
+     */
+    public void testCcOnly() {
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.cc("cc@you.com");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage( "test line 1\n" +
+            "test line 2" );
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail( "InterruptedException: " + ie );
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <cc@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+            "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+            "Cc: cc@you.com\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "test line 1\r\n" +
+        "test line 2\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        assertEquals(expectedResult.length(), result.length());
+        assertEquals(expectedResult, result);
+        if (testMailClient.isFailed()) {
+            fail(testMailClient.getFailMessage());
+        }
+    }
+
+
+    /**
+     *  Test a MailMessage with no to or cc lines
+     */
+    public void testBccOnly() {
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.bcc("bcc@you.com");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage( "test line 1\n" +
+            "test line 2" );
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail( "InterruptedException: " + ie );
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <bcc@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+        "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "test line 1\r\n" +
+        "test line 2\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        assertEquals( expectedResult.length(), result.length() );
+        assertEquals( expectedResult, result );
+        if ( testMailClient.isFailed() ) {
+            fail( testMailClient.getFailMessage() );
+        }
+    }
+
+
+    /**
+     *  Test a MailMessage with no subject line
+     *  Subject is an optional field (RFC 822 s4.1)
+     */
+    public void testNoSubject() {
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.to("to@you.com");
+        testMailClient.setMessage( "test line 1\n" +
+            "test line 2" );
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail( "InterruptedException: " + ie );
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <to@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+            "To: to@you.com\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "test line 1\r\n" +
+        "test line 2\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        assertEquals( expectedResult.length(), result.length() );
+        assertEquals( expectedResult, result );
+        if ( testMailClient.isFailed() ) {
+            fail( testMailClient.getFailMessage() );
+        }
+    }
+
+
+    /**
+     *  Test a MailMessage with empty body message
+     */
+    public void testEmptyBody() {
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.to("to@you.com");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage("");
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail( "InterruptedException: " + ie );
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <to@you.com>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+            "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+            "To: to@you.com\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        assertEquals(expectedResult.length(), result.length());
+        assertEquals(expectedResult, result);
+        if (testMailClient.isFailed()) {
+            fail(testMailClient.getFailMessage());
+        }
+    }
+
+
+    /**
+     *  Test a MailMessage with US-ASCII character set
+     *  The next four testcase can be kinda hard to debug as Ant will often
+     *  print the junit failure in US-ASCII.
+     */
+    public void testAsciiCharset() {
+
+        ServerThread testMailServer = new ServerThread();
+        Thread server = new Thread(testMailServer);
+        server.start();
+
+        ClientThread testMailClient = new ClientThread();
+
+        testMailClient.from("Mail Message <EmailTaskTest@ant.apache.org>");
+        testMailClient.to("Ceki G\u00fclc\u00fc <abuse@mail-abuse.org>");
+        testMailClient.setSubject("Test subject");
+        testMailClient.setMessage("");
+
+        Thread client = new Thread(testMailClient);
+        client.start();
+
+        try {
+            server.join(60 * 1000); // 60s
+            client.join(30 * 1000); // a further 30s
+        } catch (InterruptedException ie ) {
+            fail("InterruptedException: " + ie);
+        }
+
+        String result = testMailServer.getResult();
+        String expectedResult = "220 test SMTP EmailTaskTest\r\n" +
+        "HELO " + local + "\r\n" +
+        "250 " + local + " Hello " + local + " [127.0.0.1], pleased to meet you\r\n" +
+        "MAIL FROM: <EmailTaskTest@ant.apache.org>\r\n" +
+        "250\r\n" +
+        "RCPT TO: <abuse@mail-abuse.org>\r\n" +
+        "250\r\n" +
+        "DATA\r\n" +
+        "354\r\n" +
+        "Subject: Test subject\r\n" +
+            "From: Mail Message <EmailTaskTest@ant.apache.org>\r\n" +
+            "To: Ceki G\u00fclc\u00fc <abuse@mail-abuse.org>\r\n" +
+        "X-Mailer: org.apache.tools.mail.MailMessage (ant.apache.org)\r\n" +
+        "\r\n" +
+        "\r\n" +
+        "\r\n" +
+        ".\r\n" +
+        "250\r\n" +
+        "QUIT\r\n" +
+        "221\r\n";
+        ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
+        ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
+        PrintStream bos1 = new PrintStream(baos1, true);
+        PrintStream bos2 = new PrintStream(baos2, true);
+
+        bos1.print(expectedResult);
+        bos2.print(result);
+
+        assertEquals( "expected message length != actual message length "
+            + "in testAsciiCharset()", expectedResult.length(), result.length() );
+        assertEquals( "baos1 and baos2 should be the same in testAsciiCharset()",
+            baos1.toString(), baos2.toString() ); // order of headers cannot be guaranteed
+        if (testMailClient.isFailed()) {
+            fail(testMailClient.getFailMessage());
+        }
+    }
+
+
+
+
+    /**
+     * A private test class that pretends to be a mail transfer agent
+     */
+    private class ServerThread implements Runnable {
+
+        private StringBuffer sb = null;
+        private boolean loop = false;
+        ServerSocket ssock = null;
+        Socket sock = null;
+        BufferedWriter out = null;
+        BufferedReader in = null;
+        private boolean data = false;  // state engine: false=envelope, true=message
+
+        public void run() {
+
+            try {
+                ssock = new ServerSocket(TEST_PORT);
+                sock = ssock.accept(); // wait for connection
+                in = new BufferedReader( new InputStreamReader(
+                    sock.getInputStream()) );
+                out = new BufferedWriter( new OutputStreamWriter(
+                    sock.getOutputStream() ) );
+                sb = new StringBuffer();
+                send( "220 test SMTP EmailTaskTest\r\n" );
+                loop = true;
+                while ( loop ) {
+                    String response = in.readLine();
+                    if ( response == null ) {
+                        loop = false;
+                        break;
+                    }
+                    sb.append( response + "\r\n" );
+
+                    if ( !data && response.startsWith( "HELO" ) ) {
+                        send( "250 " + local + " Hello " + local + " " +
+                        "[127.0.0.1], pleased to meet you\r\n" );
+                    } else if ( !data && response.startsWith("MAIL") ) {
+                        send( "250\r\n" );
+                    } else if ( !data && response.startsWith("RCPT")) {
+                        send( "250\r\n" );
+                    } else if (!data && response.startsWith("DATA")) {
+                        send( "354\r\n" );
+                        data = true;
+                    } else if (data && response.equals(".") ) {
+                        send( "250\r\n" );
+                        data = false;
+                    } else if (!data && response.startsWith("QUIT")) {
+                        send( "221\r\n" );
+                        loop = false;
+                    } else if (!data) {
+                        //throw new IllegalStateException("Command unrecognized: "
+                        //    + response);
+                        send( "500 5.5.1 Command unrecognized: \"" +
+                            response + "\"\r\n" );
+                        loop = false;
+                    } else {
+                        // sb.append( response + "\r\n" );
+                    }
+
+                } // while
+            } catch (IOException ioe) {
+                fail();
+            } finally {
+                disconnect();
+            }
+        }
+
+        private void send(String retmsg) throws IOException {
+            out.write( retmsg );
+            out.flush();
+            sb.append( retmsg );
+        }
+
+        private void disconnect() {
+            if (out != null) {
+                try {
+                    out.flush();
+                    out.close();
+                    out = null;
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            if (in != null) {
+                try {
+                    in.close();
+                    in = null;
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            if (sock != null) {
+                try {
+                    sock.close();
+                    sock = null;
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+            if (ssock != null) {
+                try {
+                    ssock.close();
+                    ssock = null;
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+
+        public synchronized String getResult() {
+            loop = false;
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     *  A private test class that wraps MailMessage
+     */
+    private class ClientThread implements Runnable {
+
+        private MailMessage msg;
+        private boolean fail = false;
+        private String failMessage = null;
+
+        protected String from = null;
+        protected String subject = null;
+        protected String message = null;
+
+        protected Vector replyToList = new Vector();
+        protected Vector toList = new Vector();
+        protected Vector ccList = new Vector();
+        protected Vector bccList = new Vector();
+
+
+        public void run() {
+            for (int i = 9; i > 0; i--) {
+                try {
+                    msg = new MailMessage("localhost", TEST_PORT);
+                } catch (java.net.ConnectException ce) {
+                    try {
+                        Thread.sleep(10 * 1000);
+                    } catch (InterruptedException ie) {
+                        // ignore
+                    }
+                } catch (IOException ioe) {
+                    fail = true;
+                    failMessage = "IOException: " + ioe;
+                    return;
+                }
+                if (msg != null) {
+                    break;
+                }
+            }
+
+            if (msg == null) {
+                fail = true;
+                failMessage = "java.net.ConnectException: Connection refused";
+                return;
+            }
+
+            try {
+                msg.from(from);
+
+                Enumeration e;
+
+                e = replyToList.elements();
+                while (e.hasMoreElements()) {
+                    msg.replyto(e.nextElement().toString());
+                }
+
+                e = toList.elements();
+                while (e.hasMoreElements()) {
+                    msg.to(e.nextElement().toString());
+                }
+
+                e = ccList.elements();
+                while (e.hasMoreElements()) {
+                    msg.cc(e.nextElement().toString());
+                }
+
+                e = bccList.elements();
+                while (e.hasMoreElements()) {
+                    msg.bcc(e.nextElement().toString());
+                }
+
+                if (subject != null) {
+                    msg.setSubject(subject);
+                }
+
+                if (message != null ) {
+                    PrintStream out = msg.getPrintStream();
+                    out.println( message );
+                }
+
+                msg.sendAndClose();
+            } catch (IOException ioe) {
+                fail = true;
+                failMessage = "IOException: " + ioe;
+                return;
+            }
+        }
+
+        public boolean isFailed() {
+            return fail;
+        }
+
+        public String getFailMessage() {
+            return failMessage;
+        }
+
+        public void replyTo(String replyTo) {
+            replyToList.add(replyTo);
+        }
+
+        public void to(String to) {
+            toList.add(to);
+        }
+
+        public void cc(String cc) {
+            ccList.add(cc);
+        }
+
+        public void bcc(String bcc) {
+            bccList.add(bcc);
+        }
+
+        public void setSubject(String subject) {
+            this.subject = subject;
+        }
+
+        public void from(String from) {
+            this.from = from;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/tar/TarEntryTest.java b/trunk/src/tests/junit/org/apache/tools/tar/TarEntryTest.java
new file mode 100644
index 0000000..23f4185
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/tar/TarEntryTest.java
@@ -0,0 +1,38 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.tar;
+
+import junit.framework.TestCase;
+
+/**
+ * @since Ant 1.6
+ */
+public class TarEntryTest extends TestCase {
+
+    public TarEntryTest(String name) {
+        super(name);
+    }
+
+    /**
+     * demonstrates bug 18105 on OSes with os.name shorter than 7.
+     */
+    public void testFileConstructor() {
+        new TarEntry(new java.io.File("/foo"));
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/tar/TarOutputStreamTest.java b/trunk/src/tests/junit/org/apache/tools/tar/TarOutputStreamTest.java
new file mode 100644
index 0000000..be5311a
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/tar/TarOutputStreamTest.java
@@ -0,0 +1,34 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.tar;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class TarOutputStreamTest extends TestCase {
+
+    public void testClose() throws IOException {
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+        TarOutputStream stream = new TarOutputStream(byteStream);
+        stream.close();
+        stream.close();
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/tar/TarRoundTripTest.java b/trunk/src/tests/junit/org/apache/tools/tar/TarRoundTripTest.java
new file mode 100644
index 0000000..a86fd25
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/tar/TarRoundTripTest.java
@@ -0,0 +1,60 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.tools.tar;
+
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import junit.framework.TestCase;
+
+public class TarRoundTripTest extends TestCase {
+
+    private static final String LONG_NAME
+        = "this/path/name/contains/more/than/one/hundred/characters/in/order/"
+            + "to/test/the/GNU/long/file/name/capability/round/tripped";
+
+    public TarRoundTripTest(String name) {
+        super(name);
+    }
+
+    /**
+     * test round-tripping long (GNU) entries
+     */
+    public void testLongRoundTripping() throws IOException {
+        TarEntry original = new TarEntry(LONG_NAME);
+        assertTrue("over 100 chars", LONG_NAME.length() > 100);
+        assertEquals("original name", LONG_NAME, original.getName());
+
+
+        ByteArrayOutputStream buff = new ByteArrayOutputStream();
+        TarOutputStream tos = new TarOutputStream(buff);
+        tos.setLongFileMode(TarOutputStream.LONGFILE_GNU);
+        tos.putNextEntry(original);
+        tos.closeEntry();
+        tos.close();
+
+        TarInputStream tis
+            = new TarInputStream(new ByteArrayInputStream(buff.toByteArray()));
+        TarEntry tripped = tis.getNextEntry();
+        assertEquals("round-tripped name", LONG_NAME, tripped.getName());
+        assertNull("no more entries", tis.getNextEntry());
+        tis.close();
+    }
+}
+
+
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/AsiExtraFieldTest.java b/trunk/src/tests/junit/org/apache/tools/zip/AsiExtraFieldTest.java
new file mode 100644
index 0000000..c8e4fe4
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/AsiExtraFieldTest.java
@@ -0,0 +1,141 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.AsiExtraField.
+ *
+ */
+public class AsiExtraFieldTest extends TestCase implements UnixStat {
+    public AsiExtraFieldTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test file mode magic.
+     */
+    public void testModes() {
+        AsiExtraField a = new AsiExtraField();
+        a.setMode(0123);
+        assertEquals("plain file", 0100123, a.getMode());
+        a.setDirectory(true);
+        assertEquals("directory", 040123, a.getMode());
+        a.setLinkedFile("test");
+        assertEquals("symbolic link", 0120123, a.getMode());
+    }
+
+    /**
+     * Test content.
+     */
+    public void testContent() {
+        AsiExtraField a = new AsiExtraField();
+        a.setMode(0123);
+        a.setUserId(5);
+        a.setGroupId(6);
+        byte[] b = a.getLocalFileDataData();
+
+        // CRC manually calculated, sorry
+        byte[] expect = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC
+                         0123, (byte)0x80,                   // mode
+                         0, 0, 0, 0,                         // link length
+                         5, 0, 6, 0};                        // uid, gid
+        assertEquals("no link", expect.length, b.length);
+        for (int i=0; i<expect.length; i++) {
+            assertEquals("no link, byte "+i, expect[i], b[i]);
+        }
+
+        a.setLinkedFile("test");
+        expect = new byte[] {0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC
+                             0123, (byte)0xA0,                   // mode
+                             4, 0, 0, 0,                         // link length
+                             5, 0, 6, 0,                         // uid, gid
+                             (byte)'t', (byte)'e', (byte)'s', (byte)'t'};
+        b = a.getLocalFileDataData();
+        assertEquals("no link", expect.length, b.length);
+        for (int i=0; i<expect.length; i++) {
+            assertEquals("no link, byte "+i, expect[i], b[i]);
+        }
+
+    }
+
+    /**
+     * Test reparse
+     */
+    public void testReparse() throws Exception {
+        // CRC manually calculated, sorry
+        byte[] data = {(byte)0xC6, 0x02, 0x78, (byte)0xB6, // CRC
+                       0123, (byte)0x80,                   // mode
+                       0, 0, 0, 0,                         // link length
+                       5, 0, 6, 0};                        // uid, gid
+        AsiExtraField a = new AsiExtraField();
+        a.parseFromLocalFileData(data, 0, data.length);
+        assertEquals("length plain file", data.length,
+                     a.getLocalFileDataLength().getValue());
+        assertTrue("plain file, no link", !a.isLink());
+        assertTrue("plain file, no dir", !a.isDirectory());
+        assertEquals("mode plain file", FILE_FLAG | 0123, a.getMode());
+        assertEquals("uid plain file", 5, a.getUserId());
+        assertEquals("gid plain file", 6, a.getGroupId());
+
+        data = new byte[] {0x75, (byte)0x8E, 0x41, (byte)0xFD, // CRC
+                           0123, (byte)0xA0,                   // mode
+                           4, 0, 0, 0,                         // link length
+                           5, 0, 6, 0,                         // uid, gid
+                           (byte)'t', (byte)'e', (byte)'s', (byte)'t'};
+        a = new AsiExtraField();
+        a.parseFromLocalFileData(data, 0, data.length);
+        assertEquals("length link", data.length,
+                     a.getLocalFileDataLength().getValue());
+        assertTrue("link, is link", a.isLink());
+        assertTrue("link, no dir", !a.isDirectory());
+        assertEquals("mode link", LINK_FLAG | 0123, a.getMode());
+        assertEquals("uid link", 5, a.getUserId());
+        assertEquals("gid link", 6, a.getGroupId());
+        assertEquals("test", a.getLinkedFile());
+
+        data = new byte[] {(byte)0x8E, 0x01, (byte)0xBF, (byte)0x0E, // CRC
+                           0123, (byte)0x40,                         // mode
+                           0, 0, 0, 0,                               // link
+                           5, 0, 6, 0};                          // uid, gid
+        a = new AsiExtraField();
+        a.parseFromLocalFileData(data, 0, data.length);
+        assertEquals("length dir", data.length,
+                     a.getLocalFileDataLength().getValue());
+        assertTrue("dir, no link", !a.isLink());
+        assertTrue("dir, is dir", a.isDirectory());
+        assertEquals("mode dir", DIR_FLAG | 0123, a.getMode());
+        assertEquals("uid dir", 5, a.getUserId());
+        assertEquals("gid dir", 6, a.getGroupId());
+
+        data = new byte[] {0, 0, 0, 0,                           // bad CRC
+                           0123, (byte)0x40,                     // mode
+                           0, 0, 0, 0,                           // link
+                           5, 0, 6, 0};                          // uid, gid
+        a = new AsiExtraField();
+        try {
+            a.parseFromLocalFileData(data, 0, data.length);
+            fail("should raise bad CRC exception");
+        } catch (Exception e) {
+            assertEquals("bad CRC checksum 0 instead of ebf018e",
+                         e.getMessage());
+        }
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java b/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
new file mode 100644
index 0000000..c405138
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/ExtraFieldUtilsTest.java
@@ -0,0 +1,114 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ExtraFieldUtils.
+ *
+ */
+public class ExtraFieldUtilsTest extends TestCase implements UnixStat {
+    public ExtraFieldUtilsTest(String name) {
+        super(name);
+    }
+
+    private AsiExtraField a;
+    private UnrecognizedExtraField dummy;
+    private byte[] data;
+    private byte[] aLocal;
+
+    public void setUp() {
+        a = new AsiExtraField();
+        a.setMode(0755);
+        a.setDirectory(true);
+        dummy = new UnrecognizedExtraField();
+        dummy.setHeaderId(new ZipShort(1));
+        dummy.setLocalFileDataData(new byte[0]);
+        dummy.setCentralDirectoryData(new byte[] {0});
+
+        aLocal = a.getLocalFileDataData();
+        byte[] dummyLocal = dummy.getLocalFileDataData();
+        data = new byte[4 + aLocal.length + 4 + dummyLocal.length];
+        System.arraycopy(a.getHeaderId().getBytes(), 0, data, 0, 2);
+        System.arraycopy(a.getLocalFileDataLength().getBytes(), 0, data, 2, 2);
+        System.arraycopy(aLocal, 0, data, 4, aLocal.length);
+        System.arraycopy(dummy.getHeaderId().getBytes(), 0, data,
+                         4+aLocal.length, 2);
+        System.arraycopy(dummy.getLocalFileDataLength().getBytes(), 0, data,
+                         4+aLocal.length+2, 2);
+        System.arraycopy(dummyLocal, 0, data,
+                         4+aLocal.length+4, dummyLocal.length);
+
+    }
+
+    /**
+     * test parser.
+     */
+    public void testParse() throws Exception {
+        ZipExtraField[] ze = ExtraFieldUtils.parse(data);
+        assertEquals("number of fields", 2, ze.length);
+        assertTrue("type field 1", ze[0] instanceof AsiExtraField);
+        assertEquals("mode field 1", 040755,
+                     ((AsiExtraField) ze[0]).getMode());
+        assertTrue("type field 2", ze[1] instanceof UnrecognizedExtraField);
+        assertEquals("data length field 2", 0,
+                     ze[1].getLocalFileDataLength().getValue());
+
+        byte[] data2 = new byte[data.length-1];
+        System.arraycopy(data, 0, data2, 0, data2.length);
+        try {
+            ExtraFieldUtils.parse(data2);
+            fail("data should be invalid");
+        } catch (Exception e) {
+            assertEquals("message",
+                         "data starting at "+(4+aLocal.length)+" is in unknown format",
+                         e.getMessage());
+        }
+    }
+
+    /**
+     * Test merge methods
+     */
+    public void testMerge() {
+        byte[] local =
+            ExtraFieldUtils.mergeLocalFileDataData(new ZipExtraField[] {a, dummy});
+        assertEquals("local length", data.length, local.length);
+        for (int i=0; i<local.length; i++) {
+            assertEquals("local byte "+i, data[i], local[i]);
+        }
+
+        byte[] dummyCentral = dummy.getCentralDirectoryData();
+        byte[] data2 = new byte[4 + aLocal.length + 4 + dummyCentral.length];
+        System.arraycopy(data, 0, data2, 0, 4 + aLocal.length + 2);
+        System.arraycopy(dummy.getCentralDirectoryLength().getBytes(), 0,
+                         data2, 4+aLocal.length+2, 2);
+        System.arraycopy(dummyCentral, 0, data2,
+                         4+aLocal.length+4, dummyCentral.length);
+
+
+        byte[] central =
+            ExtraFieldUtils.mergeCentralDirectoryData(new ZipExtraField[] {a, dummy});
+        assertEquals("central length", data2.length, central.length);
+        for (int i=0; i<central.length; i++) {
+            assertEquals("central byte "+i, data2[i], central[i]);
+        }
+
+    }
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/ZipEntryTest.java b/trunk/src/tests/junit/org/apache/tools/zip/ZipEntryTest.java
new file mode 100644
index 0000000..b8e2f6c
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/ZipEntryTest.java
@@ -0,0 +1,118 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ZipEntry.
+ *
+ */
+public class ZipEntryTest extends TestCase {
+
+    public ZipEntryTest(String name) {
+        super(name);
+    }
+
+    /**
+     * test handling of extra fields
+     *
+     * @since 1.1
+     */
+    public void testExtraFields() {
+        AsiExtraField a = new AsiExtraField();
+        a.setDirectory(true);
+        a.setMode(0755);
+        UnrecognizedExtraField u = new UnrecognizedExtraField();
+        u.setHeaderId(new ZipShort(1));
+        u.setLocalFileDataData(new byte[0]);
+
+        ZipEntry ze = new ZipEntry("test/");
+        ze.setExtraFields(new ZipExtraField[] {a, u});
+        byte[] data1 = ze.getExtra();
+        ZipExtraField[] result = ze.getExtraFields();
+        assertEquals("first pass", 2, result.length);
+        assertSame(a, result[0]);
+        assertSame(u, result[1]);
+
+        UnrecognizedExtraField u2 = new UnrecognizedExtraField();
+        u2.setHeaderId(new ZipShort(1));
+        u2.setLocalFileDataData(new byte[] {1});
+
+        ze.addExtraField(u2);
+        byte[] data2 = ze.getExtra();
+        result = ze.getExtraFields();
+        assertEquals("second pass", 2, result.length);
+        assertSame(a, result[0]);
+        assertSame(u2, result[1]);
+        assertEquals("length second pass", data1.length+1, data2.length);
+
+        UnrecognizedExtraField u3 = new UnrecognizedExtraField();
+        u3.setHeaderId(new ZipShort(2));
+        u3.setLocalFileDataData(new byte[] {1});
+        ze.addExtraField(u3);
+        result = ze.getExtraFields();
+        assertEquals("third pass", 3, result.length);
+
+        ze.removeExtraField(new ZipShort(1));
+        byte[] data3 = ze.getExtra();
+        result = ze.getExtraFields();
+        assertEquals("fourth pass", 2, result.length);
+        assertSame(a, result[0]);
+        assertSame(u3, result[1]);
+        assertEquals("length fourth pass", data2.length, data3.length);
+
+        try {
+            ze.removeExtraField(new ZipShort(1));
+            fail("should be no such element");
+        } catch (java.util.NoSuchElementException nse) {
+        }
+    }
+
+    public void testUnixMode() {
+        ZipEntry ze = new ZipEntry("foo");
+        assertEquals(0, ze.getPlatform());
+        ze.setUnixMode(0755);
+        assertEquals(3, ze.getPlatform());
+        assertEquals(0755,
+                     (ze.getExternalAttributes() >> 16) & 0xFFFF);
+        assertEquals(0, ze.getExternalAttributes()  & 0xFFFF);
+
+        ze.setUnixMode(0444);
+        assertEquals(3, ze.getPlatform());
+        assertEquals(0444,
+                     (ze.getExternalAttributes() >> 16) & 0xFFFF);
+        assertEquals(1, ze.getExternalAttributes()  & 0xFFFF);
+
+        ze = new ZipEntry("foo/");
+        assertEquals(0, ze.getPlatform());
+        ze.setUnixMode(0777);
+        assertEquals(3, ze.getPlatform());
+        assertEquals(0777,
+                     (ze.getExternalAttributes() >> 16) & 0xFFFF);
+        assertEquals(0x10, ze.getExternalAttributes()  & 0xFFFF);
+
+        ze.setUnixMode(0577);
+        assertEquals(3, ze.getPlatform());
+        assertEquals(0577,
+                     (ze.getExternalAttributes() >> 16) & 0xFFFF);
+        assertEquals(0x11, ze.getExternalAttributes()  & 0xFFFF);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/ZipLongTest.java b/trunk/src/tests/junit/org/apache/tools/zip/ZipLongTest.java
new file mode 100644
index 0000000..e72aaaa
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/ZipLongTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ZipLong.
+ *
+ */
+public class ZipLongTest extends TestCase {
+
+    public ZipLongTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test conversion to bytes.
+     */
+    public void testToBytes() {
+        ZipLong zl = new ZipLong(0x12345678);
+        byte[] result = zl.getBytes();
+        assertEquals("length getBytes", 4, result.length);
+        assertEquals("first byte getBytes", 0x78, result[0]);
+        assertEquals("second byte getBytes", 0x56, result[1]);
+        assertEquals("third byte getBytes", 0x34, result[2]);
+        assertEquals("fourth byte getBytes", 0x12, result[3]);
+    }
+
+    /**
+     * Test conversion from bytes.
+     */
+    public void testFromBytes() {
+        byte[] val = new byte[] {0x78, 0x56, 0x34, 0x12};
+        ZipLong zl = new ZipLong(val);
+        assertEquals("value from bytes", 0x12345678, zl.getValue());
+    }
+
+    /**
+     * Test the contract of the equals method.
+     */
+    public void testEquals() {
+        ZipLong zl = new ZipLong(0x12345678);
+        ZipLong zl2 = new ZipLong(0x12345678);
+        ZipLong zl3 = new ZipLong(0x87654321);
+
+        assertTrue("reflexive", zl.equals(zl));
+
+        assertTrue("works", zl.equals(zl2));
+        assertTrue("works, part two", !zl.equals(zl3));
+
+        assertTrue("symmetric", zl2.equals(zl));
+
+        assertTrue("null handling", !zl.equals(null));
+        assertTrue("non ZipLong handling", !zl.equals(new Integer(0x1234)));
+    }
+
+    /**
+     * Test sign handling.
+     */
+    public void testSign() {
+        ZipLong zl = new ZipLong(new byte[] {(byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF});
+        assertEquals(0x00000000FFFFFFFFl, zl.getValue());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/ZipOutputStreamTest.java b/trunk/src/tests/junit/org/apache/tools/zip/ZipOutputStreamTest.java
new file mode 100644
index 0000000..19b7c05
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/ZipOutputStreamTest.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import junit.framework.TestCase;
+
+public class ZipOutputStreamTest extends TestCase {
+    
+    private Date time;
+    private ZipLong zl;
+    
+    /**
+     * Constructor
+     */	
+    public ZipOutputStreamTest(String name) {
+        super(name);
+    }
+	
+    protected void setUp() throws Exception {
+        time = new Date();
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(time);
+        int year = cal.get(Calendar.YEAR);
+        int month = cal.get(Calendar.MONTH) + 1;
+        long value =  ((year - 1980) << 25)
+            |         (month << 21)
+            |	      (cal.get(Calendar.DAY_OF_MONTH) << 16)
+            |         (cal.get(Calendar.HOUR_OF_DAY) << 11)
+            |         (cal.get(Calendar.MINUTE) << 5)
+            |         (cal.get(Calendar.SECOND) >> 1);
+
+        byte[] result = new byte[4];
+        result[0] = (byte) ((value & 0xFF));
+        result[1] = (byte) ((value & 0xFF00) >> 8);
+        result[2] = (byte) ((value & 0xFF0000) >> 16);
+        result[3] = (byte) ((value & 0xFF000000L) >> 24);
+        zl = new ZipLong(result);
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    public void testZipLong() throws Exception {
+        ZipLong test = ZipOutputStream.toDosTime(time);
+        assertEquals(test.getValue(), zl.getValue());
+    }
+
+    public void testAdjustToLong() {
+        assertEquals((long) Integer.MAX_VALUE,
+                     ZipOutputStream.adjustToLong(Integer.MAX_VALUE));
+        assertEquals(((long) Integer.MAX_VALUE) + 1,
+                     ZipOutputStream.adjustToLong(Integer.MAX_VALUE + 1));
+        assertEquals(2 * ((long) Integer.MAX_VALUE),
+                     ZipOutputStream.adjustToLong(2 * Integer.MAX_VALUE));
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/apache/tools/zip/ZipShortTest.java b/trunk/src/tests/junit/org/apache/tools/zip/ZipShortTest.java
new file mode 100644
index 0000000..3fb604f
--- /dev/null
+++ b/trunk/src/tests/junit/org/apache/tools/zip/ZipShortTest.java
@@ -0,0 +1,80 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.tools.zip;
+
+import junit.framework.TestCase;
+
+/**
+ * JUnit 3 testcases for org.apache.tools.zip.ZipShort.
+ *
+ */
+public class ZipShortTest extends TestCase {
+
+    public ZipShortTest(String name) {
+        super(name);
+    }
+
+    /**
+     * Test conversion to bytes.
+     */
+    public void testToBytes() {
+        ZipShort zs = new ZipShort(0x1234);
+        byte[] result = zs.getBytes();
+        assertEquals("length getBytes", 2, result.length);
+        assertEquals("first byte getBytes", 0x34, result[0]);
+        assertEquals("second byte getBytes", 0x12, result[1]);
+    }
+
+    /**
+     * Test conversion from bytes.
+     */
+    public void testFromBytes() {
+        byte[] val = new byte[] {0x34, 0x12};
+        ZipShort zs = new ZipShort(val);
+        assertEquals("value from bytes", 0x1234, zs.getValue());
+    }
+
+    /**
+     * Test the contract of the equals method.
+     */
+    public void testEquals() {
+        ZipShort zs = new ZipShort(0x1234);
+        ZipShort zs2 = new ZipShort(0x1234);
+        ZipShort zs3 = new ZipShort(0x5678);
+
+        assertTrue("reflexive", zs.equals(zs));
+
+        assertTrue("works", zs.equals(zs2));
+        assertTrue("works, part two", !zs.equals(zs3));
+
+        assertTrue("symmetric", zs2.equals(zs));
+
+        assertTrue("null handling", !zs.equals(null));
+        assertTrue("non ZipShort handling", !zs.equals(new Integer(0x1234)));
+    }
+
+    /**
+     * Test sign handling.
+     */
+    public void testSign() {
+        ZipShort zs = new ZipShort(new byte[] {(byte)0xFF, (byte)0xFF});
+        assertEquals(0x0000FFFF, zs.getValue());
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/example/junit/Output.java b/trunk/src/tests/junit/org/example/junit/Output.java
new file mode 100644
index 0000000..a7135f7
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/junit/Output.java
@@ -0,0 +1,37 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.example.junit;
+
+import junit.framework.TestCase;
+
+/**
+ * Not really a test of Ant but a test that is run by the test of the
+ * junit task.  Confused?
+ *
+ * @since Ant 1.5
+ */
+public class Output extends TestCase {
+
+    public Output(String s) {
+        super(s);
+    }
+
+    public void testOutput() {
+        System.out.println("foo");
+    }
+}
diff --git a/trunk/src/tests/junit/org/example/junit/ThreadedOutput.java b/trunk/src/tests/junit/org/example/junit/ThreadedOutput.java
new file mode 100644
index 0000000..91f462a
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/junit/ThreadedOutput.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.example.junit;
+
+import junit.framework.TestCase;
+
+/**
+ * Not really a test of Ant but a test that is run by the test of the
+ * junit task.  Confused?
+ *
+ * @since Ant 1.5
+ */
+public class ThreadedOutput extends TestCase {
+
+    public ThreadedOutput(String s) {
+        super(s);
+    }
+
+    public void testOutput() throws InterruptedException {
+        Thread t = new Thread(new Runnable() {
+                public void run() {
+                    System.out.println("foo");
+                }
+            });
+        t.start();
+        t.join();
+    }
+}
diff --git a/trunk/src/tests/junit/org/example/junit/XmlParserTest.java b/trunk/src/tests/junit/org/example/junit/XmlParserTest.java
new file mode 100644
index 0000000..ddc766d
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/junit/XmlParserTest.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.example.junit;
+
+import junit.framework.TestCase;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * created Aug 12, 2004 1:39:59 PM
+ */
+
+public class XmlParserTest extends TestCase {
+
+    public XmlParserTest(String s) {
+        super(s);
+    }
+
+    public void testXercesIsPresent() throws SAXException {
+        XMLReader xerces;
+        xerces = XMLReaderFactory.createXMLReader(
+                        "org.apache.xerces.parsers.SAXParser");
+        assertNotNull(xerces);
+    }
+
+    public void testXercesHandlesSchema() throws SAXException {
+        XMLReader xerces;
+        xerces = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
+        xerces.setFeature("http://apache.org/xml/features/validation/schema",
+                true);
+    }
+
+    public void testParserHandlesSchema() throws SAXException {
+        XMLReader xerces;
+        xerces = XMLReaderFactory.createXMLReader();
+        xerces.setFeature("http://apache.org/xml/features/validation/schema",
+                true);
+    }
+
+}
diff --git a/trunk/src/tests/junit/org/example/tasks/TaskdefTestContainerTask.java b/trunk/src/tests/junit/org/example/tasks/TaskdefTestContainerTask.java
new file mode 100644
index 0000000..a566d5c
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/tasks/TaskdefTestContainerTask.java
@@ -0,0 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.example.tasks;
+
+import org.apache.tools.ant.taskdefs.Sequential;
+
+public class TaskdefTestContainerTask extends Sequential {
+    public TaskdefTestContainerTask() {}
+}
diff --git a/trunk/src/tests/junit/org/example/tasks/TaskdefTestSimpleTask.java b/trunk/src/tests/junit/org/example/tasks/TaskdefTestSimpleTask.java
new file mode 100644
index 0000000..bce8cd5
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/tasks/TaskdefTestSimpleTask.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.example.tasks;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+public class TaskdefTestSimpleTask extends Task {
+
+    public class Echo {
+        Echo() {}
+        private String message = null;
+        public void setMessage(String s) {message = s;}
+    }
+
+    public TaskdefTestSimpleTask() {}
+
+    private Echo echo;
+    public Echo createEcho() {
+        echo = new Echo();
+        return echo;
+    }
+
+    public void execute() {
+        log("simpletask: "+echo.message, Project.MSG_INFO);
+    }
+
+}
+
diff --git a/trunk/src/tests/junit/org/example/tasks/antlib.xml b/trunk/src/tests/junit/org/example/tasks/antlib.xml
new file mode 100644
index 0000000..b920da7
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/tasks/antlib.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib>
+<macrodef name="simple">
+   <element name="some-tasks" optional="yes" implicit="yes"/>
+   <sequential>
+      <some-tasks/>
+   </sequential>
+</macrodef>
+</antlib>
+      
diff --git a/trunk/src/tests/junit/org/example/tasks/antlib2.xml b/trunk/src/tests/junit/org/example/tasks/antlib2.xml
new file mode 100644
index 0000000..b920da7
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/tasks/antlib2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<antlib>
+<macrodef name="simple">
+   <element name="some-tasks" optional="yes" implicit="yes"/>
+   <sequential>
+      <some-tasks/>
+   </sequential>
+</macrodef>
+</antlib>
+      
diff --git a/trunk/src/tests/junit/org/example/types/TypedefTestType.java b/trunk/src/tests/junit/org/example/types/TypedefTestType.java
new file mode 100644
index 0000000..235b76f
--- /dev/null
+++ b/trunk/src/tests/junit/org/example/types/TypedefTestType.java
@@ -0,0 +1,25 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.example.types;
+
+import org.apache.tools.ant.ProjectComponent;
+
+public class TypedefTestType extends ProjectComponent {
+}
+
diff --git a/trunk/xdocs/antlibs/antunit/index.xml b/trunk/xdocs/antlibs/antunit/index.xml
new file mode 100755
index 0000000..342d1f4
--- /dev/null
+++ b/trunk/xdocs/antlibs/antunit/index.xml
@@ -0,0 +1,239 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>AntUnit</title>
+  </properties>
+
+  <body>
+
+    <section name="AntUnit 1.0">
+      <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+
+      <p>Apache AntUnit 1.0 is now available for download as <a
+      href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
+      or <a
+      href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
+      release.</p>
+    </section>
+
+    <section name="Idea">
+      <p>Initially all tests for Ant tasks were written as individual
+      <a href="http://www.junit.org/">JUnit</a> test cases.  Pretty
+      soon it was clear that most tests needed to perform common tasks
+      like reading a build file, initializing a project instance with
+      it and executing a target.  At this point <a
+      href="http://svn.apache.org/viewcvs.cgi/ant/core/trunk/src/testcases/org/apache/tools/ant/BuildFileTest.java">BuildFileTest</a>
+      was invented, a base class for almost all task test cases.</p>
+
+      <p>BuildFileTest works fine and in fact has been picked up by <a
+      href="http://ant-contrib.sf.net/">the Ant-Contrib Project</a>
+      and others as well.</p>
+
+      <p>Over time a new pattern evolved, more and more tests only
+      executed a target and didn't check any effects.  Instead that
+      target contained the assertions as a <code>&lt;fail&gt;</code>
+      task.  This is an example taken from the build file for the
+      ANTLR task (using Ant 1.7 features):</p>
+
+      <source><![CDATA[
+  <target name="test3" depends="setup">
+    <antlr target="antlr.g" outputdirectory="${tmp.dir}"/>
+    <fail>
+      <condition>
+        <!-- to prove each of these files exists;
+             ANTLR >= 2.7.6 leaves behind new (.smap) files as well. -->
+        <resourcecount when="ne" count="5">
+          <fileset dir="${tmp.dir}">
+            <include name="CalcParserTokenTypes.txt" />
+            <include name="CalcParserTokenTypes.java" />
+            <include name="CalcLexer.java" />
+            <include name="CalcParser.java" />
+            <include name="CalcTreeWalker.java" />
+          </fileset>
+        </resourcecount>
+      </condition>
+    </fail>
+  </target>
+]]></source>
+
+      <p>where the corresponding JUnit testcase has been reduced
+      to</p>
+
+      <source><![CDATA[
+...
+public class ANTLRTest extends BuildFileTest {
+
+    private final static String TASKDEFS_DIR = "src/etc/testcases/taskdefs/optional/antlr/";
+
+    public ANTLRTest(String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        configureProject(TASKDEFS_DIR + "antlr.xml");
+    }
+
+    public void tearDown() {
+        executeTarget("cleanup");
+    }
+
+    public void test3() {
+        executeTarget("test3");
+    }
+...
+}
+]]></source>
+
+      <p>This approach has a couple of advantages, one of them is that
+      it is very easy to translate an example build file from a bug
+      report into a test case.  If you ask a user for a testcase for a
+      given bug in Ant, he now doesn't need to understand JUnit or how
+      to fit a test into Ant's existing tests any more.</p>
+
+      <p>AntUnit takes this approach to testing even further, it
+      removes JUnit completely and it comes with a set of predefined
+      <code>&lt;assert&gt;</code> tasks in order to reuse common kind
+      of checks.</p>
+
+      <p>It turns out that AntUnit lends itself as a solution to other
+      problems as well.  The assertions are an easy way to validate a
+      setup before even starting the build process, for example.
+      AntUnit could also be used for functional and integration tests
+      outside of the scope of Ant tasks (assert contents of databases
+      after running an application, assert contents of HTTP responses
+      ...).  This is an area that will need more research.</p>
+    </section>
+
+    <section name="Concepts">
+      <subsection name="antunit Task">
+        <p>The &lt;antunit&gt; task drives the tests much like
+        &lt;junit&gt; does for JUnit tests.</p>
+
+        <p>When called on a build file, the task will start a new Ant
+        project for that build file and scan for targets with names
+        that start with "test".  For each such target it then will</p>
+        <ol>
+          <li>Execute the target named setUp, if there is one.</li>
+          <li>Execute the target itself - if this target depends on
+          other targets the normal Ant rules apply and the dependent
+          targets are executed first.</li>
+          <li>Execute the target names tearDown, if there is one.</li>
+        </ol>
+
+      </subsection>
+      <subsection name="Assertions">
+
+        <p>The base task is <code>&lt;assertTrue&gt;</code>.  It
+        accepts a single nested condition and throws a subclass of
+        BuildException named AssertionFailedException if that
+        condition evaluates to false.</p>
+
+        <p>This task could have been implemented using
+        <code>&lt;macrodef&gt;</code> and <code>&lt;fail&gt;</code>,
+        but in fact it is a "real" task so that it is possible to
+        throw a subclass of BuildException.  The
+        <code>&lt;antunit&gt;</code> task catches this exception and
+        marks the target as failed, any other type of Exception
+        (including other BuildException) are test errors.</p>
+
+        <p>Together with <code>&lt;assertTrue&gt;</code> there are
+        many predefined assertions for common conditions, most of
+        these are only macros.</p>
+
+      </subsection>
+
+      <subsection name="Other Tasks">
+
+        <p>The <code>&lt;logcapturer&gt;</code> captures all messages
+        that pass Ant's logging system and provides them via a
+        reference inside of the project.  If you want to assert
+        certain log messages, you need to start this task (prior to
+        your target under test) and use the
+        <code>&lt;assertLogContains&gt;</code> assertion.</p>
+
+        <p><code>&lt;expectFailure&gt;</code> is a task container that
+        catches any BuildException thrown by tasks nested into it.  If
+        no exception has been thrown it will cause a test failure (by
+        throwing an AssertionFailedException).</p>
+      </subsection>
+
+      <subsection name="AntUnitListener">
+        <p>Part of the library is the <code>AntUnitListener</code>
+        interface that can be used to record test results.  The
+        &lt;antunit&gt; task accepts arbitrary many listeners and
+        relays test results to them.</p>
+
+        <p>Currently two implementations -
+        <code>&lt;plainlistener&gt;</code> and <code>xmllistener</code> 
+        modelled after the "plain" and "xml"
+        JUnit listeners - are bundled with the library.</p>
+      </subsection>
+    </section>
+
+    <section name="Examples">
+
+      <p>This is a way to test that <code>&lt;touch&gt;</code>
+      actually creates a file if it doesn't exist:</p>
+
+      <source><![CDATA[
+<project xmlns:au="antlib:org.apache.ant.antunit">
+  <!-- is called prior to the test -->
+  <target name="setUp">
+    <property name="foo" value="foo"/>
+  </target>
+
+  <!-- is called after the test, even if that caused an error -->
+  <target name="tearDown">
+    <delete file="${foo}" quiet="true"/>
+  </target>
+
+  <!-- the actual test case -->
+  <target name="testTouchCreatesFile">
+    <au:assertFileDoesntExist file="${foo}"/>
+    <touch file="${foo}"/>
+    <au:assertFileExists file="${foo}"/>
+  </target>
+</project>
+]]></source>
+
+      <p>When running a task like</p>
+
+      <source><![CDATA[
+    <au:antunit>
+      <fileset dir="." includes="touch.xml"/>
+      <au:plainlistener/>
+    </au:antunit>
+]]></source>
+
+      <p>from a buildfile of its own you'll get a result that looks like</p>
+
+      <source><![CDATA[
+[au:antunit] Build File: /tmp/touch.xml
+[au:antunit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.249 sec
+[au:antunit] Target: testTouchCreatesFile took 0.183 sec
+
+BUILD SUCCESSFUL
+Total time: 1 second
+]]></source>
+
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/antlibs/bindownload.xml b/trunk/xdocs/antlibs/bindownload.xml
new file mode 100644
index 0000000..e85be76
--- /dev/null
+++ b/trunk/xdocs/antlibs/bindownload.xml
@@ -0,0 +1,208 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Binary Distributions</title>
+    <index value="1"/>
+  </properties>
+
+<body>
+
+<section name="Downloading Antlibs">
+
+<p>Use the links below to download a binary distribution of Antlibs from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>.</p>
+
+<p>Antlibs are distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+
+<p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/antlibs/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/antlibs/">mirror</a>.</p>
+
+</section>
+
+<!--section name="Downloading Betas">
+
+<p>Beta releases are not mirrored, you can find our latest beta
+releases at <a
+href="http://people.apache.org/dist/ant/antlibs/">http://people.apache.org/dist/ant/antlibs/</a>.</p>
+
+<p>Currently available:</p>
+
+<ul>
+
+  <li><a
+  href="http://people.apache.org/dist/ant/antlibs/antunit/binaries/">AntUnit
+  1.0Beta2</a></li>
+
+</ul>
+
+</section-->
+
+<section name="Mirror">
+
+<p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+
+<form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+</section>
+
+<section name="Current Antlib Releases">
+
+<div class="warning">
+<div class="label">Note</div>
+<div class="content">Very recent releases may not be available on all
+mirrors for a few days.</div>
+</div>
+<br></br>
+<div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+
+<ul>
+<li>Apache .NET Ant Library 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip">apache-ant-dotnet-1.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz">apache-ant-dotnet-1.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2">apache-ant-dotnet-1.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/binaries/apache-ant-dotnet-1.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+
+<li>Apache AntUnit 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip">apache-ant-antunit-1.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz">apache-ant-antunit-1.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2">apache-ant-antunit-1.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/binaries/apache-ant-antunit-1.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+</ul>
+</section>
+
+<!--section name="Old Ant Releases">
+
+<p>Older releases of Ant can be found <a
+href="http://archive.apache.org/dist/ant/binaries/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a
+href="[location]#Current Release of Ant">latest</a> release.</p>
+
+</section-->
+
+<section name="Verify Releases">
+
+<p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+
+<p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a
+href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+
+<p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-dotnet-1.0-bin.tar.gz.asc
+</code></p>
+
+<p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a
+href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a
+href="http://www.fourmilab.ch/md5/">here</a>, <a
+href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a
+href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+
+<p>We highly recommend to verify the PGP signature, though.</p>
+
+</section>
+
+</body>
+</document>
diff --git a/trunk/xdocs/antlibs/charter.xml b/trunk/xdocs/antlibs/charter.xml
new file mode 100644
index 0000000..03fa691
--- /dev/null
+++ b/trunk/xdocs/antlibs/charter.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>Ant Libraries - Charter</title>
+  </properties>
+
+  <body>
+    <section name="Charter">
+    
+      <p>Below is the text of the proposal that has been accepted by
+      the Ant PMC.  Further amendments are expected.</p>
+
+      <source>
+Proposal to Create a Ant-Libraries Sub-Project in Apache Ant
+============================================================
+
+(0) rationale
+
+Ant itself has accumulated lots and lots of tasks over time. So many,
+that Ant developers have become reluctant to adding new
+task. Furthermore any new task in Ant would be tied to Ant's release
+schedule which is too slow for a thriving, fresh piece of code.
+
+The proposal allows Ant tasks and types to be developed under the Ant
+umbrella by Ant developers but have much shorter release cycles than
+Ant itself. In addition it would new committers who would have commit
+access to a single Ant library instead of the whole of Ant.
+
+(1) scope of the subproject
+
+The subproject shall create and maintain libraries of Ant tasks and
+types. Each library will be managed in the same manner as the Ant
+project itself, the PMC is ultimately responsible for it.
+
+Common Java libraries that only happen to provide Ant tasks as well
+are out of scope of the subproject. Providing the tasks or types has
+to be the primary goal of the library.
+
+To further this goal, the subproject shall also host a workplace for
+Ant committers.
+
+(1.5) interaction with other subprojects
+
+(1.5.1) the sandbox
+
+The subproject will host a SVN repository available to all Ant
+committers as a workplace for new Ant libraries.
+
+Before a library can have a public release it has to get promoted to
+the "proper" Ant libraries subproject. This also means it has to match
+the requirements of an Ant library as defined in section (4) under
+Guidelines below.
+
+The status of any library developed in the sandbox shall be reviewed
+after six months and the library gets either promoted or removed - or
+it has to be re-evaluated after another six months.
+
+(2) identify the initial source from which the subproject is to be populated
+
+Some Ant committers have developed tasks or libraries inside of the
+Ant CVS module under the proposal/sandbox directory. Committers are
+free to move them over to the new sandbox subproject or remove them
+completely.
+
+Libraries expected to move to the sandbox subproject initially are
+
+* the .NET tasks under proposal/sandbox/dotnet
+
+* the Subversion support tasks under proposal/sandbox/svn
+
+(3) identify the initial Apache resources to be created
+
+(3.1) mailing list(s)
+
+None. At least at the beginning we don't expect too much traffic and
+the existing mailing lists of the Ant projects will be used.
+
+(3.2) SVN repositories
+
+Create &lt;http://svn.apache.org/repos/asf/ant/>
+
+Expected are sub-directories
+
+antlibs/
+   |
+   -----> proper/
+   |        |
+   |        -----> library1
+   |        |        |
+   |        |        -----------> trunk
+   |        |        -----------> tags
+   |        |        -----------> branches
+   |        -----> library2
+   |                 |
+   |                 -----------> trunk
+   |                 -----------> tags
+   |                 -----------> branches
+   |
+   -----> sandbox/
+            |
+            -----> library1
+            |        |
+            |        -----------> trunk
+            |        -----------> tags
+            |        -----------> branches
+            -----> library2
+                     |
+                     -----------> trunk
+                     -----------> tags
+                     -----------> branches
+
+And potentially collections of all-trunks using svn:external as shown
+by the current Jakarta Commons structure.
+
+(3.3) Bugzilla
+
+New components under product "Ant" for each new library.
+
+(4) identify the initial set of committers
+
+All current Ant PMC members plus the active Ant committers who are not
+PMC members yet.
+
+Guidelines
+----------
+
+Note:
+
+* is, has, will, shall, must - required.
+
+* may, should, are encouraged - optional but recommended.
+
+(1) The primary unit of reuse and release is the Ant library.
+
+(2) The library is not a framework or a general library but a
+    collection of Ant tasks and types.
+
+(3) Each library must have a clearly defined purpose, scope, and API.
+
+(4) Each library is treated as a product in its own right.
+
+(4.1) Each library has its own status file, release schedule, version
+      number, QA tests, documentation, bug category, and individual
+      JAR.
+
+(4.2) Each library must clearly specify any external dependencies,
+      including any other libraries, and the earliest JDK version
+      required.
+
+(4.3) Each library must maintain a list of its active committers in
+      its status file.
+
+(4.4) The libraries should use a standard scheme for versioning, QA
+      tests, and directory layouts, and a common format for
+      documentation and Ant build files.
+
+(4.4) Each library will be hosted on its own page on the subproject
+      Web site, and will also be indexed in a master directory.
+
+(4.5) Volunteers become committers to this subproject in the same way
+      they are entered to any Apache subproject.
+
+      Once the required infrastructure is in place, volunteers may
+      become committers for a single Ant library only.
+
+(4.6) New libraries may be proposed to the Ant dev mailing list. To be
+      accepted, a library proposal must receive majority approval of
+      the Ant PMC. Proposals are to identify the rationale for the
+      library, its scope, the initial source from which the library is
+      to be created, and the initial set of committers.
+
+(4.7) As stated in the Ant guidelines, an action requiring majority
+      approval must receive at least 3 binding +1 votes and more +1
+      votes than -1 votes.
+
+(4.8) Each Ant library needs at least three committers, at least one
+      of them has to be an Ant PMC member.
+      </source>
+
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/antlibs/dotnet/index.xml b/trunk/xdocs/antlibs/dotnet/index.xml
new file mode 100755
index 0000000..bce794b
--- /dev/null
+++ b/trunk/xdocs/antlibs/dotnet/index.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>.NET Ant Library</title>
+  </properties>
+
+  <body>
+
+    <section name=".NET Ant Library 1.0">
+      <h3>November 6, 2006 - Apache .NET Ant Library 1.0
+      Available</h3>
+
+      <p>Apache .NET Ant Library 1.0 is now available for
+      download as <a
+      href="http://ant.apache.org/antlibs/bindownload.cgi">binary</a>
+      or <a
+      href="http://ant.apache.org/antlibs/srcdownload.cgi">source</a>
+      release.</p>
+    </section>
+
+    <section name="Idea">
+
+      <p>This library doesn't strive to replace NAnt or MSBuild, its
+      main purpose is to help those of us who work on projects
+      crossing platform boundaries.  With this library you can use Ant
+      to build and test the Java as well as the .NET parts of your
+      project.</p>
+
+      <p>This library provides a special version of the
+      <code>&lt;exec&gt;</code> task tailored to run .NET executables.
+      On Windows it will assume the Microsoft framework is around and
+      run the executable directly, while it will invoke Mono on any
+      other platform.  Of course you can override these
+      assumptions.</p>
+
+      <p>Based on this a few tasks to run well known .NET utilities
+      from within Ant are provided, namely tasks to run <a
+      href="http://www.nunit.org/">NUnit</a>, <a
+      href="http://nant.sf.net/">NAnt</a>, <a
+      href="http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=27&amp;SiteID=1">MSBuild</a>
+      and the <a href="http://wix.sf.net/">Wix</a> toolkit.</p>
+
+      <p>The initial .NET tasks of Ant (compiler tasks for C#, J# and VB.NET
+      for example) have also been moved to this Antlib and will see further
+      development here.</p>
+    </section>
+
+    <section name="Tasks">
+      <subsection name="dotnetexec">
+        <p>Runs a .NET executable.</p>
+      </subsection>
+
+      <subsection name="nunit">
+        <p>Runs NUnit tests.</p>
+      </subsection>
+
+      <subsection name="nant">
+        <p>Invokes NAnt, either on an external file or a build file
+        snippet contained inside your Ant build file.</p>
+      </subsection>
+
+      <subsection name="msbuild">
+        <p>Invokes MSBuild, either on an external file or a build file
+        snippet contained inside your Ant build file.</p>
+      </subsection>
+
+      <subsection name="wix">
+        <p>Invokes the candle and light executables of the WiX toolkit
+          in order to create MSI installers from within Ant.</p>
+      </subsection>
+    </section>
+
+    <section name="Examples">
+      <subsection name="nant">
+        <source><![CDATA[
+<project xmlns:dn="antlib:org.apache.ant.dotnet">
+  <dn:nant>
+    <build>
+      <echo message="Hello world"/>
+    </build>
+  </dn:nant>
+</project>
+]]></source>
+
+        <p>runs NAnt on the embedded <code>&lt;echo&gt;</code>
+        task, output looks like</p>
+
+        <source><![CDATA[
+Buildfile: test.xml
+[dn:nant] NAnt 0.85 (Build 0.85.1932.0; rc3; 16.04.2005)
+[dn:nant] Copyright (C) 2001-2005 Gerry Shaw
+[dn:nant] http://nant.sourceforge.net
+[dn:nant] 
+[dn:nant] Buildfile: file:///c:/DOKUME~1/STEFAN~1.BOD/LOKALE~1/Temp/build1058451555.xml
+[dn:nant] Target framework: Microsoft .NET Framework 1.1
+[dn:nant] 
+[dn:nant]      [echo] Hello world
+[dn:nant] 
+[dn:nant] BUILD SUCCEEDED
+[dn:nant] 
+[dn:nant] Total time: 0.2 seconds.
+
+BUILD SUCCESSFUL
+Total time: 2 seconds]]></source>
+      </subsection>
+
+      <subsection name="msbuild">
+        <source><![CDATA[
+<project xmlns:dn="antlib:org.apache.ant.dotnet">
+  <dn:msbuild>
+    <build>
+      <Message Text="Hello world"
+        xmlns="http://schemas.microsoft.com/developer/msbuild/2003"/>
+    </build>
+  </dn:msbuild>
+</project>]]></source>
+
+        <p>runs MSBuild on the embedded <code>&lt;Message&gt;</code>
+        task, output looks like</p>
+
+        <source><![CDATA[
+Buildfile: test.xml
+[dn:msbuild] Microsoft (R) Build Engine Version 2.0.50727.42
+[dn:msbuild] [Microsoft .NET Framework, Version 2.0.50727.42]
+[dn:msbuild] Copyright (C) Microsoft Corporation 2005. All rights reserved.
+
+[dn:msbuild] Build started 15.12.2005 20:21:56.
+[dn:msbuild] __________________________________________________
+[dn:msbuild] Project "c:\Dokumente und Einstellungen\stefan.bodewig\Lokale Einstellungen\Temp\build1543310185.xml" (default targets):
+
+[dn:msbuild] Target generated-by-ant:
+[dn:msbuild]     Hello world
+
+[dn:msbuild] Build succeeded.
+[dn:msbuild]     0 Warning(s)
+[dn:msbuild]     0 Error(s)
+
+[dn:msbuild] Time Elapsed 00:00:00.10
+
+BUILD SUCCESSFUL
+Total time: 0 seconds
+]]></source>
+
+      </subsection>
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/antlibs/index.xml b/trunk/xdocs/antlibs/index.xml
new file mode 100644
index 0000000..cceb9fe
--- /dev/null
+++ b/trunk/xdocs/antlibs/index.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>The Ant Libraries Subproject</title>
+  </properties>
+
+  <body>
+
+    <section name="The Ant Libraries Subproject">
+      <h3>Ant Libraries - or Antlibs for short</h3>
+
+      <p>With Ant 1.6.0 and the ant libraries concept creating
+      libraries of Ant tasks that are easy to get dropped into an
+      existing Ant installation has become far easier.</p>
+
+      <p>The Ant Libraries subproject was started as a place to
+      develop small libraries of tasks that can get released
+      independent of Ant's release schedule - which is necessary for
+      nascent Ant tasks since Ant's own release schedule has become
+      rather slow over time.</p>
+
+      <p>The subproject also offers a sandbox as playground for Ant
+      committers to try new ideas for tasks.</p>
+
+    </section>
+
+  </body>
+</document>
+
diff --git a/trunk/xdocs/antlibs/proper.xml b/trunk/xdocs/antlibs/proper.xml
new file mode 100644
index 0000000..e7ceac7
--- /dev/null
+++ b/trunk/xdocs/antlibs/proper.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>Ant Libraries</title>
+  </properties>
+
+  <body>
+
+    <section name="Ant Libraries">
+
+      <a name="antunit"/>
+      <subsection name="AntUnit - Unit Test Framework for Ant Tasks">
+
+        <p>AntUnit borrows ideas from JUnit 3.x and the &lt;junit&gt;
+        task.  It provides a task that runs build files as unit tests
+        as well as a number of assertion tasks to support the
+        idea.</p>
+
+        <table>
+          <tr>
+            <th>Homepage:</th>
+            <td><a href="./antunit/index.html">http://ant.apache.org/antlibs/antunit/</a></td>
+          </tr>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2005-04-15</td>
+          </tr>
+          <tr>
+            <th>Promoted from sandbox:</th>
+            <td>2005-11-22</td>
+          </tr>
+          <tr>
+            <th>Latest Release:</th>
+            <td>1.0 released on January 8, 2007</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <a name="dotnet"/>
+      <subsection name="DotNet - Improved Support for .NET projects">
+
+        <p>Provides a simple infrastructure to execute .NET
+        applications from within Ant for different VMs so that the
+        user doesn't have to change the build file when she wants to
+        run Mono on Linux and Microsoft's VM on Windows.</p>
+
+        <p>Also contains &lt;nant&gt;, &lt;nunit&gt; and
+        &lt;msbuild&gt; tasks and an untested &lt;wix&gt; tasks.</p>
+
+        <table>
+          <tr>
+            <th>Homepage:</th>
+            <td><a href="./dotnet/index.html">http://ant.apache.org/antlibs/dotnet/</a></td>
+          </tr>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2005-04-15</td>
+          </tr>
+          <tr>
+            <th>Promoted from sandbox:</th>
+            <td>2005-11-22</td>
+          </tr>
+          <tr>
+            <th>Latest Release:</th>
+            <td>1.0 released on November 6, 2006</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <a name="svn"/>
+      <subsection name="SVN - Subversion Support">
+
+        <p>Contains tasks that correspond to Ant's &lt;cvs&gt;,
+        &lt;cvschangelog&gt; and &lt;cvstagdiff&gt; tasks.  Requires
+        Subversion's command line client.</p>
+
+        <table>
+          <tr>
+            <th>Homepage:</th>
+            <td><a href="./svn/index.html">http://ant.apache.org/antlibs/svn/</a></td>
+          </tr>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/">https://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/">http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2005-04-15</td>
+          </tr>
+          <tr>
+            <th>Promoted from sandbox:</th>
+            <td>2005-11-22</td>
+          </tr>
+          <tr>
+            <th>Latest Release:</th>
+            <td>None</td>
+          </tr>
+        </table>
+      </subsection>
+
+    </section>
+
+  </body>
+</document>
+
diff --git a/trunk/xdocs/antlibs/sandbox.xml b/trunk/xdocs/antlibs/sandbox.xml
new file mode 100644
index 0000000..b4d24bb
--- /dev/null
+++ b/trunk/xdocs/antlibs/sandbox.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>Ant Libraries - The Sandbox</title>
+  </properties>
+
+  <body>
+
+    <section name="Ant Libraries - The Sandbox">
+
+      <p>The sandbox is the place where new Ant Libraries start their
+      life, it is a playground for Ant committers and other
+      contributors who find committers to sponsor their ideas.</p>
+
+      <p>The sandbox is no dumping ground.  If a Sandbox Ant Library
+      fails to attract interest within a reasonable amount of time, it
+      gets removed from the sandbox.</p>
+
+    </section>
+
+    <section name="Current Sandbox Ant Libraries">
+
+      <subsection name="Debian - Debian related tasks">
+
+        <p>Debian provides tasks for generating Debian packages.</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/sandbox/antlibs/debian/trunk/">https://svn.apache.org/repos/asf/ant/sandbox/antlibs/debian/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/debian/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/debian/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2007-05-18</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td>Kevin Jackson</td>
+          </tr>
+        </table>
+      </subsection>
+
+
+      <subsection name="GenDoc - Generate the manual for Ant Tasks from their sources">
+
+        <p>Most of the information needed for writing the manual is inside the sources: attributes, nested elements (especially
+        inherited one). GenDoc collects these information and generates the manual as xml page. Following steps transform this
+        xml into the final format (HTML in the first step, PDF may follow).</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/gendoc/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/gendoc/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/gendoc/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/gendoc/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2005-04-15</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td> </td>
+          </tr>
+        </table>
+      </subsection>
+
+
+      <subsection name="HTTP - tasks for handling HTTP requests">
+
+        <p>This antlib contains tasks to make the basic HTTP requests: get, post, head, put, with Basicauthentication.</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/http/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/http/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/http/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2006-06-27</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td>  </td>
+          </tr>
+        </table>
+      </subsection>
+      
+
+      <subsection name="Manual4Eclipse - Generate an Eclipse Help PlugIn from Ant's manual">
+        <p>This AntLib provides tasks for generating an Eclipse Help PlugIn from Ant's manual.</p>
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/manual4eclipse/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/manual4eclipse/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/manual4eclipse/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/manual4eclipse/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Java compatibility:</th>
+            <td>Java 1.5+</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2007-03-01</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td> </td>
+          </tr>
+        </table>
+      </subsection>
+      
+      
+      <subsection name="Props - additional Property Resolver">
+
+        <p>This is a library of supplementary handlers for Ant properties resolution.</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/sandbox/antlibs/props/trunk/">https://svn.apache.org/repos/asf/ant/sandbox/antlibs/props/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/props/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/props/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.8.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2007-07-25</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td>Matt Benson</td>
+          </tr>
+        </table>
+      </subsection>      
+      
+      
+      <subsection name="VSS - Microsoft Visual SourceSafe Tasks">
+
+        <p>This antlib provides an interface to the Microsoft Visual SourceSafe SCM. The original tasks 
+        (org.apache.tools.ant.taskdefs.optional.vss) have been expanded upon in this antlib. 
+        Some fixes to issues in the original tasks have also been incorporated.</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="http://svn.apache.org/repos/asf/ant/sandbox/antlibs/vss/">http://svn.apache.org/repos/asf/ant/sandbox/antlibs/vss/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewvc/ant/sandbox/antlibs/vss/">http://svn.apache.org/viewvc/ant/sandbox/antlibs/vss/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2006-04-26  </td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td>  </td>
+          </tr>
+        </table>
+      </subsection>
+
+
+
+
+      <!-- example for copy/paste reuse ;-)
+      <subsection name="AntUnit - Unit Test Framework for Ant Tasks">
+
+        <p>AntUnit borrows ideas from JUnit 3.x and the &lt;junit&gt;
+        task.  It provides a task that runs build files as unit tests
+        as well as a number of assertion tasks to support the
+        idea.</p>
+
+        <table>
+          <tr>
+            <th>SVN URL:</th>
+            <td><a href="https://svn.apache.org/repos/asf/ant/sandbox/antlibs/antunit/trunk/">https://svn.apache.org/repos/asf/ant/sandbox/antlibs/antunit/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>ViewSVN:</th>
+            <td><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/antunit/trunk/">http://svn.apache.org/viewcvs.cgi/ant/sandbox/antlibs/antunit/trunk/</a></td>
+          </tr>
+          <tr>
+            <th>Ant compatibility:</th>
+            <td>Ant 1.7.x</td>
+          </tr>
+          <tr>
+            <th>Added to sandbox:</th>
+            <td>2005-04-15</td>
+          </tr>
+          <tr>
+            <th>Sponsoring Committers</th>
+            <td>Stefan Bodewig</td>
+          </tr>
+        </table>
+      </subsection>
+      -->
+    </section>
+
+  </body>
+</document>
diff --git a/trunk/xdocs/antlibs/srcdownload.xml b/trunk/xdocs/antlibs/srcdownload.xml
new file mode 100644
index 0000000..18f4a48
--- /dev/null
+++ b/trunk/xdocs/antlibs/srcdownload.xml
@@ -0,0 +1,208 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Source Distributions</title>
+    <index value="1"/>
+  </properties>
+
+<body>
+
+<section name="Downloading Antlibs">
+
+<p>Use the links below to download a source distribution of Antlibs from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>.</p>
+
+<p>Antlibs are distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+
+<p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/antlibs/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/antlibs/">mirror</a>.</p>
+
+</section>
+
+<!--section name="Downloading Betas">
+
+<p>Beta releases are not mirrored, you can find our latest beta
+releases at <a
+href="http://people.apache.org/dist/ant/antlibs/">http://people.apache.org/dist/ant/antlibs/</a>.</p>
+
+<p>Currently available:</p>
+
+<ul>
+
+  <li><a
+  href="http://people.apache.org/dist/ant/antlibs/antunit/source/">AntUnit
+  1.0Beta2</a></li>
+
+</ul>
+
+</section-->
+
+<section name="Mirror">
+
+<p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+
+<form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+</section>
+
+<section name="Current Antlib Releases">
+
+<div class="warning">
+<div class="label">Note</div>
+<div class="content">Very recent releases may not be available on all
+mirrors for a few days.</div>
+</div>
+<br></br>
+<div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+
+<ul>
+<li>Apache .NET Ant Library 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip">apache-ant-dotnet-1.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz">apache-ant-dotnet-1.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2">apache-ant-dotnet-1.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/dotnet/source/apache-ant-dotnet-1.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+
+<li>Apache AntUnit 1.0
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip">apache-ant-antunit-1.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz">apache-ant-antunit-1.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2">apache-ant-antunit-1.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/antlibs/antunit/source/apache-ant-antunit-1.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</li>
+</ul>
+</section>
+
+<!--section name="Old Ant Releases">
+
+<p>Older releases of Ant can be found <a
+href="http://archive.apache.org/dist/ant/source/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a
+href="[location]#Current Release of Ant">latest</a> release.</p>
+
+</section-->
+
+<section name="Verify Releases">
+
+<p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+
+<p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a
+href="http://www.apache.org/dist/ant/antlibs/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+
+<p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-dotnet-1.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-dotnet-1.0-bin.tar.gz.asc
+</code></p>
+
+<p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a
+href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a
+href="http://www.fourmilab.ch/md5/">here</a>, <a
+href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a
+href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+
+<p>We highly recommend to verify the PGP signature, though.</p>
+
+</section>
+
+</body>
+</document>
diff --git a/trunk/xdocs/antlibs/svn/index.xml b/trunk/xdocs/antlibs/svn/index.xml
new file mode 100755
index 0000000..86dda6a
--- /dev/null
+++ b/trunk/xdocs/antlibs/svn/index.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <title>Subversion Ant Library</title>
+  </properties>
+
+  <body>
+
+    <section name="Idea">
+      <p>The main purpose of this Ant library is to provide the same
+      level of support that Ant provides for CVS.  This means the
+      tasks are wrappers on top of the command line client (read: you
+      still need to install an svn client) and there is not much more
+      than running the executable and creating some reports.</p>
+
+      <p>If you are looking for projects that aim at more, there are
+      better alternatives, for example <a
+      href="http://subclipse.tigris.org/svnant.html">Subclipse's Ant
+      task</a> or <a
+      href="http://tmate.org/svn/ant.html">JavaSVN</a>.</p>
+    </section>
+
+    <section name="Tasks">
+      <subsection name="svn">
+        <p>A very thin layer on top of the command line executable,
+        comparable to <a
+        href="http://ant.apache.org/manual/CoreTasks/cvs.html">the CVS
+        task</a>.</p>
+      </subsection>
+
+      <subsection name="changelog">
+        <p>Creates a log of change comments between two revisions,
+        comparable to <a
+        href="http://ant.apache.org/manual/CoreTasks/changelog.html">CvsChangeLog</a>.</p>
+      </subsection>
+
+      <subsection name="*diff">
+        <p><code>&lt;tagdiff&gt;</code> creates a differences report
+        for the changes between two tags or branches.</p>
+
+        <p><code>&lt;revisiondiff&gt;</code> creates a differences report
+        for the changes between two revisions.</p>
+
+        <p>Together comparable to <a
+        href="http://ant.apache.org/manual/CoreTasks/cvstagdiff.html">CvsTagDiff</a>.</p>
+      </subsection>
+    </section>
+
+    <section name="Examples">
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/antnews.xml b/trunk/xdocs/antnews.xml
new file mode 100644
index 0000000..c34feec
--- /dev/null
+++ b/trunk/xdocs/antnews.xml
@@ -0,0 +1,405 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="">Conor MacNeill</author>
+    <author email="">Stefan Bodewig</author>
+    <author email="">Magesh Umasankar</author>
+    <author email="">Antoine Levy-Lambert</author>
+    <title>News</title>
+  </properties>
+
+<body>
+  <section name="Apache Ivy is an Ant Sub-Project Now!">
+    <h3>October 11, 2007 - Apache Ivy is an Ant Sub-Project Now!</h3>
+
+    <p>Apache Ivy, "A Java based tool for tracking, resolving and
+    managing project dependencies.", just finished <a
+    href="http://incubator.apache.org/">Incubation</a> and has joined
+    the Ant project.  More information will be available from the Ant
+    site soon.</p>
+
+    <p>Until we've finished the migration, you can learn more about
+    Ivy from its <a href="http://incubator.apache.org/ivy/">Incubator
+    website</a>.</p>
+  </section>
+
+  <section name="AntUnit 1.0">
+    <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+    <p>Apache AntUnit 1.0 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a
+    href="antlibs/antunit/">AntUnit home page</a>.</p>
+  </section>
+
+  <section name="Ant 1.7.0">
+    <h3>December 19, 2006 - Ant 1.7.0 Available</h3>
+    <p>Apache Ant 1.7.0 is now available for <a
+    href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+
+    <p> Ant 1.7 introduces a resource framework. Some of the core ant 
+    tasks such as &lt;copy/&gt; are now able to process not only file 
+    system resources but also zip entries, tar entries, paths, ... 
+    Resource collections group resources, and can be further 
+    combined with operators such as union and intersection. This 
+    can be extended by custom resources and custom tasks using resources.</p>
+
+    <p>
+    Ant 1.7 starts outsourcing of optional tasks to Antlibs. 
+    The .NET antlib in preparation will replace the .NET optional tasks which ship in Ant.
+    Support for the version control system Subversion will be only provided as an antlib to
+    be released shortly. 
+    </p>
+
+    <p>Ant 1.7 fixes also a large number of bugs.</p>
+
+    <p>Ant 1.7 has some initial support for Java6 features.</p>
+  </section>
+
+  <section name=".NET Ant Library 1.0Beta1">
+    <h3>November 6, 2006 - Apache .NET Ant Library 1.0 Available</h3>
+    <p>Apache .NET Ant Library 1.0 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+
+    <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+  </section>
+
+  <section name="AntUnit 1.0Beta2">
+    <h3>October 29, 2006 - Apache AntUnit 1.0Beta2 Available</h3>
+    <p>Apache AntUnit 1.0Beta1 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a
+    href="antlibs/antunit/">AntUnit home page</a>.</p>
+  </section>
+
+  <section name="AntUnit 1.0Beta1">
+    <h3>September 22, 2006 - Apache AntUnit 1.0Beta1 Available</h3>
+    <p>Apache AntUnit 1.0Beta1 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a
+    href="antlibs/antunit/">AntUnit home page</a>.</p>
+  </section>
+
+  <section name=".NET Ant Library 1.0Beta1">
+    <h3>September 13, 2006 - Apache .NET Ant Library 1.0Beta1 Available</h3>
+    <p>Apache .NET Ant Library 1.0Beta1 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+
+    <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+  </section>
+
+  <section name="Ant 1.6.5">
+    <h3>June 2, 2005 - Ant 1.6.5 Available</h3>
+    <p>Apache Ant 1.6.5 is now available for <a
+    href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+    <p>This is a bug fix release.</p>
+  </section>
+
+  <section name="Ant 1.6.4">
+    <h3>May 19, 2005 - Ant 1.6.4 Available</h3>
+    <p>Apache Ant 1.6.4 is now available for <a
+    href="http://archive.apache.org/dist/ant/">download</a>.</p>
+    <p>This is a bug fix release.</p>
+  </section>
+
+  <section name="Ant 1.6.3">
+    <h3>April 28, 2005 - Ant 1.6.3 Available</h3>
+    <p>Apache Ant 1.6.3 is now available for <a
+    href="http://archive.apache.org/dist/ant/">download</a>.</p>
+    <p>There is a large list of fixed bugs and enhancements.</p>
+    <p>Some of the bugs affecting the embedded use of Ant are fixed.</p>
+  </section>
+
+  <section name="Antidote Retired">
+    <h3>April 4th, 2005 - The Apache Ant Project Retires Antidote, the
+    Ant GUI</h3>
+
+    <p>The Antidote subproject was once started to provide a GUI for
+    Ant at a time where IDE support for Ant was far from usable.
+    Unfortunately it never attracted a developer community of its
+    own.</p>
+
+    <p>At the same time IDE support for Ant has become ubiquitous by
+    now and there is little reason to have a GUI just for Ant.  This
+    makes it even less likely that volunteers will start to spend time
+    working on it.</p>
+
+    <p>Antidote's development has been stalled for years now, despite
+    some efforts to rejuvenate it by single developers.  Therefore the
+    Ant developers have chosen to retire Antidote.</p>
+
+    <p>Antidote will no longer be developed by the Ant project; its
+    CVS module will be shut down.</p>
+
+    <p>If you are interested in Antidote's sources to learn from or
+    build on it, you can find snapshots at <a
+    href="http://archive.apache.org/ant/antidote/">http://archive.apache.org/ant/antidote/</a>.</p>
+  </section>
+
+  <section name="Ant 1.6.2">
+    <h3>July 16, 2004 - Ant 1.6.2 Available</h3>
+    <p>Apache Ant 1.6.2 available for <a
+    href="http://archive.apache.org/dist/ant/">download</a>.</p>
+    <p>Nested elements for namespaced tasks and types may belong to the
+Ant default namespace as well as the task's or type's namespace.</p>
+    <p>All exceptions thrown by tasks are now wrapped in a
+buildexception giving the location in the buildfile of the task.</p>
+    <p>Ant 1.6.2 fixes a large number of bugs and adds a number of
+features which were asked for by users on Bugzilla.</p>
+  </section>
+
+  <section name="Wiki Migration">
+    <h3>February 29, 2004</h3>
+    <p>The Ant Wiki pages have been migrated to their 
+      <a href="http://wiki.apache.org/ant/">new home</a> on the Apache
+      Wiki farm.
+    </p>
+  </section>
+
+  <section name="Ant 1.6.1">
+    <h3>February 12, 2004 - Ant 1.6.1 Available</h3>
+     <p>Apache Ant 1.6.1 is still available for
+      <a href="http://archive.apache.org/dist/ant/">download</a>.
+     </p>
+    <p>The ASF Board has approved the new Apache License 2.0.
+    For a copy of that license, please see
+    <a href="http://www.apache.org/licenses/">
+    http://www.apache.org/licenses/</a>.</p>
+    <p>The Ant 1.6.1 release is delivered with the
+    Apache License 2.0.</p>
+    <p>Ant 1.6.1 fixes several bugs, most notably the handling
+    of the default namespace for nested elements.</p>
+    <p>Ant 1.6.1 also introduces initial support for compiling with
+    Java 1.5.</p>
+  </section>
+   <section name="Ant 1.6.0">
+    <h3>December 18, 2003 - Ant 1.6.0 Available</h3>
+     <p>Apache Ant 1.6.0 is still available for
+      <a href="http://archive.apache.org/dist/ant/">download</a>.
+     </p>
+     <p>As
+    we've already said in the announcements of Ant 1.5.4, this release
+    requires JDK 1.2 or later to run.</p>
+
+    <p>Ant 1.6.0 adds a lot of new features, most prominently support
+    for XML namespaces as well as a new concept of Ant libraries that
+    makes use of namespaces to avoid name clashes of custom tasks.
+    For a longer list of fixed bugs and new features see the release
+    notes.</p>
+    
+    <p>If you find anything that hasn't been covered in the manual (I bet you
+did) or could be explained better, feel free to help us out in the
+<a href="http://wiki.apache.org/ant/NewAntFeaturesInDetail">Wiki</a>.</p>
+
+   </section>
+
+  <section name="Ant 1.5.4">
+    <h3>August 12, 2003 - Ant 1.5.4 Available</h3>
+    <p>Apache Ant 1.5.4 is still available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+    </p>
+    
+    <p>This is a minor bugfix release that fixes a problem with the
+    <code>javah</code> task on JDK 1.4.2 and a couple of bugs in the
+    Visual Age for Java intergration tasks.  If you don't use javah or
+    VAJ, there is no reason to upgrade.</p>
+
+    <div class="warning">
+    <div class="label">Note</div>
+    <div class="content">Ant 1.5.4 is the last release that supports
+      JDK 1.1. Ant 1.6.0 requires JDK 1.2 or
+      later.
+    </div>
+    </div>
+  </section>
+
+  <section name="Java Pro 2003 Readers Choice Award">
+    <a href="http://www.ftponline.com/javapro/">
+      <img style="padding: 5px" src="images/jp_rcwinner_2003.gif" alt="" border="0" height="80" width="139" align="right"/></a>
+    <h3>June 11th, 2003: Ant wins a Java Pro readers' choice award</h3>
+    <p>
+      Ant has won the Java Pro 2003 Readers' Choice Award for 
+    </p>
+    <p>
+      <strong>Most Valuable Java Deployment Technology</strong>.
+    </p>
+    
+    <p>
+      Thanks to Java Pro and all its readers. You can read about
+      these 
+      <a href="http://www.ftponline.com/reports/javaone/2003/awards/">awards</a>
+      at the Java Pro website.
+    </p>
+  </section>
+
+  <section name="JDJ Editors Choice Award">
+    <a href="http://sys-con.com/java/article2a.cfm?id=2059&amp;count=1734&amp;tot=6&amp;page=2"><img src="images/JDJEditorsChoiceAward.jpg" alt="" border="0" align="right"/></a>
+    <h3>June 2003: Ant wins JDJ Editors&apos; Choice Award</h3>
+
+    <p>
+&quot;Ant is the hammer of the Java world: without it, civilization might have progressed, but much more slowly than it has. Ant is one of the most useful build tools I have ever had the pleasure to use.&quot; - Joe Ottinger
+    </p>
+    
+  </section>
+
+  <section name="Ant keeps on winning!">
+    <a href="http://www.javaworld.com/"><img src="images/jw_ec_logo_winner2003.gif" alt="" border="0" height="108" width="252" align="right"/></a>
+    <h3>June 9th, 2003: Ant wins the JavaWorld Editors&apos; Choice Award</h3>
+
+    <p>
+    Ant has won the JavaWorld Editors&apos; Choice Award for
+    </p>
+    <p>
+    <strong>Most Useful Java Community-Developed Technology</strong>
+    </p>
+    
+    <p>
+    for the second time in a row! Read the
+    <a href="http://www.javaworld.com/javaworld/jw-06-2003/jw-0609-eca.html"> full article</a> -- or jump directly to the bit about
+    <a href="http://www.javaworld.com/javaworld/jw-06-2003/jw-0609-eca-p4.html"> our award</a> <code>:)</code></p>
+  </section>
+  
+  <section name="Ant 1.5.3">
+    <h3>April 9, 2003 - Ant 1.5.3 Available</h3>
+    <p>Apache Ant 1.5.3 is still available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+    </p>
+  </section>
+
+
+  <section name="Ant 1.5.2">
+    <h3>March 3, 2003 - Ant 1.5.2 Available!</h3>
+    <p>The final version of Ant 1.5.2 is available for
+     <a href="http://archive.apache.org/dist/ant/">download</a>.
+     If you have any feedback on this release, feel free to join the 
+     discussion on the dev and user mailing lists.
+     </p>
+  </section>
+
+  <section name="Ant Top Level Project">
+    <h3>November 18, 2002</h3>
+    <p>The Apache board <a href="mission.html">created</a>
+       the Apache Ant top level project. Ant has now migrated from the Jakarta
+       project into an Apache project of its own. This is primarily an
+       organizational change and will not affect the technical aspects of
+       the project. Ant retains a strong association with the Apache
+       Jakarta project. One effect of this change is that the Ant webpage
+       is now located at <a href="http://ant.apache.org/">http://ant.apache.org/</a>
+     </p>
+  </section>
+    
+  <section name="Ant 1.5.1">
+    <h3>October 3, 2002 - Ant 1.5.1 Available !</h3>
+    <p>The final version of Ant 1.5.1 is still available for
+     <a href="http://archive.apache.org/dist/ant/">
+     download</a>. If you have any feedback on this release, feel free to join the 
+     discussion on the ant-dev and ant-user mailing lists.
+     </p>
+  </section>
+
+  <section name="Ant 1.5">
+    <h3>July 15, 2002 - Fix for Cygwin problem in wrapper script available</h3>
+      <p>The wrapper script of Ant 1.5 needs to be replaced with a new
+      version for Cygwin users.  See the <a
+      href="faq.html#1.5-cygwin-sh">FAQ</a> for details.</p>
+
+    <h3>July 10, 2002 - Ant 1.5 Released!</h3>
+    <p>The final version of Ant 1.5 is now available for 
+     <a href="http://archive.apache.org/dist/ant/">
+     download</a>. If you have any feedback on this release, feel free to join the 
+     discussion on the ant-dev and ant-user mailing lists.
+     </p>
+  </section>
+
+  <section name="Ant wins again!">
+    <a href="http://www.sdmagazine.com/"><img src="images/sdm_productivity_award.gif" alt="" border="0" height="108" width="181" align="right"/></a>
+    <h3>Apr 29, 2002: Ant wins <em>Software Development</em> magazine&apos;s
+    2002 Productivity Award.</h3>
+    <p>
+    Ant has been awarded a <strong>2002 Productivity Award</strong> by
+    <a href="http://www.sdmagazine.com/"><em>Software Development</em></a>
+    magazine.  Read the
+    <a href="http://www.sdmagazine.com/jolts/press_release_4-26-02.htm">
+    press release</a> for more information and the full list of winners.
+    </p>
+  </section>
+
+  <section name="Ant has won!">
+    <a href="http://www.javaworld.com/"><img src="images/jw_ec_logo_winner2002.gif" alt="" border="0" height="108" width="252" align="right"/></a>
+    <h3>Mar 26, 2002: Ant wins the JavaWorld Editors&apos; Choice
+    Award</h3>
+
+    <p>
+    Ant has won the JavaWorld Editors&apos; Choice Award for
+    <strong>Most Useful Java Community-Developed Technology</strong>.
+    Read the
+    <a href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards.html
+"> full article</a> -- or jump directly to the bit about
+    <a href="http://www.javaworld.com/javaworld/jw-03-2002/jw-0326-awards-p3.html"> our award</a> <code>:)</code></p>
+  </section>
+  
+  <section name="Java 1.4 Support">
+    <h3>Feb 15, 2002: Java 1.4 Support</h3>
+    <p>
+      Java 1.4 has now been released by Sun. The latest Ant source supports 
+      the new <tt>assert</tt> statement in the compiler task via the <tt>source</tt> 
+      attribute. It also contains a compatibility fix needed for some ant tasks
+      on Java 1.4 over Windows XP. If you have problems running Ant 1.4.1 on WinXP/Java 1.4,
+      please use a recent build or compile your own version from the source tree. 
+    </p>
+  </section>
+  
+  <section name="See our new logo!">
+    <h3>Have a look at our new cool logo!</h3>
+  </section>
+  
+  <section name="Ant 1.4.1">
+  <h3>11 October 2001 Ant 1.4.1 released !</h3>
+  <p>Please visit the 
+     <a href="http://archive.apache.org/dist/ant/">
+     download area</a>. 
+     </p>
+  </section>
+
+  <section name="Best-Practices Profile of Ant at Sun&apos;s Dot-Com Builder">
+      <p>Sun has released an introductory article on Ant on their
+      Dot-Com Builder site on May&#160;30&#160;2001. See <a
+      href="http://dcb.sun.com/practices/profiles/ant.jsp">http://dcb.sun.com/practices/profiles/ant.jsp</a></p>
+  </section>
+
+
+</body>
+</document>
+
diff --git a/trunk/xdocs/bindownload.xml b/trunk/xdocs/bindownload.xml
new file mode 100644
index 0000000..bcaa921
--- /dev/null
+++ b/trunk/xdocs/bindownload.xml
@@ -0,0 +1,176 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Binary Distributions</title>
+    <base/>
+  </properties>
+
+<body>
+
+<section name="Downloading Ant">
+
+<p>Use the links below to download a binary distribution of Ant from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>.</p>
+
+<p>Ant is distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+
+<p>In addition the <a href="http://www.jpackage.org">JPackage
+project</a> provides RPMs at their own distribution site.</p>
+
+<p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/">mirror</a>.</p>
+
+</section>
+
+<section name="Mirror">
+
+<p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+
+<form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+</section>
+
+<section name="Current Release of Ant">
+
+<p>Currently, Apache Ant 1.7.0 is the best available version, see the
+<a href="[preferred]/ant/README.html">release notes</a>.</p>
+
+<div class="warning">
+<div class="label">Note</div>
+<div class="content">Ant 1.7.0 has been released on 19-Dec-2006 and
+may not be available on all mirrors for a few days.</div>
+</div>
+<br></br>
+<div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.zip">apache-ant-1.7.0-bin.zip</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.tar.gz">apache-ant-1.7.0-bin.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/binaries/apache-ant-1.7.0-bin.tar.bz2">apache-ant-1.7.0-bin.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/binaries/apache-ant-1.7.0-bin.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</section>
+
+
+<section name="Old Ant Releases">
+
+<p>Older releases of Ant can be found <a
+href="http://archive.apache.org/dist/ant/binaries/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a
+href="[location]#Current Release of Ant">latest</a> release.</p>
+
+</section>
+
+<section name="Verify Releases">
+
+<p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+
+<p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a
+href="http://www.apache.org/dist/ant/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+
+<p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-1.7.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-1.7.0-bin.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-1.7.0-bin.tar.gz.asc
+</code></p>
+
+<p>A command line version of <a href="http://www.gnupg.org/download/">GnuPG</a> 
+is also available for Windows users.  Follow the 
+<a href="http://www.gnupg.org/(en)/documentation/faqs.html#q4.19">instructions</a> 
+to verify the package.</p>
+
+<p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a
+href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a
+href="http://www.fourmilab.ch/md5/">here</a>, <a
+href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a
+href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+
+<p>We highly recommend to verify the PGP signature, though.</p>
+
+</section>
+
+</body>
+</document>
diff --git a/trunk/xdocs/bugs.xml b/trunk/xdocs/bugs.xml
new file mode 100644
index 0000000..15b72a7
--- /dev/null
+++ b/trunk/xdocs/bugs.xml
@@ -0,0 +1,171 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="">Antoine Levy-Lambert</author>
+    <title>Bug database</title>
+  </properties>
+
+  <body>
+    <section name="Bug Database">
+         <p>
+           This page gives you some bookmarks to use the Bugzilla <a href="http://issues.apache.org/bugzilla/">
+            Apache Bug Database</a>.
+         </p>
+         <p>
+           This link <a href="http://issues.apache.org/">issues.apache.org</a> connects you
+           to the complete list of Apache Bug Database systems.
+         </p>
+      <subsection name="Has It Been Reported?">
+         <p>
+            If the current nightly build doesn't resolve your problem, it is
+            possible that someone else has reported the issue. It is time to
+            look at the bug database. This system is easy to use, and it will
+            let you search the <a href="http://issues.apache.org/bugzilla/buglist.cgi?bug_status=UNCONFIRMED&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;email1=&amp;emailtype1=substring&amp;emailassigned_to1=1&amp;email2=&amp;emailtype2=substring&amp;emailreporter2=1&amp;bugidtype=include&amp;bug_id=&amp;changedin=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;product=Ant&amp;short_desc=&amp;short_desc_type=substring&amp;long_desc=&amp;long_desc_type=substring&amp;bug_file_loc=&amp;bug_file_loc_type=substring&amp;keywords=&amp;keywords_type=anywords&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;order=bugs.bug_id">
+            currently open</a> and resolved bugs to see if your problem has
+            already been reported. If your problem has been reported, you can
+            see whether any of the developers have commented, suggesting
+            workarounds, or the reason for the bug, etc. Or you may have
+            information to add (see about creating and modifying bug reports
+            below), in which case, go right ahead and add the information.
+            If you don't have any additional information, you may just want
+            to vote for this bug, and perhaps
+            add yourself to the <code>CC</code> list to follow the progress
+            of this bug.
+         </p>
+         <p><a href="http://issues.apache.org/bugzilla/buglist.cgi?query_format=advanced&amp;short_desc_type=allwordssubstr&amp;short_desc=&amp;product=Ant&amp;long_desc_type=substring&amp;long_desc=&amp;bug_file_loc_type=allwordssubstr&amp;bug_file_loc=&amp;keywords_type=allwords&amp;keywords=&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailtype1=substring&amp;email1=&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailtype2=substring&amp;email2=&amp;bugidtype=include&amp;bug_id=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=">Open Ant bugs by order of priority</a>.</p>
+         <p><a href="http://issues.apache.org/bugzilla/buglist.cgi?query_format=advanced&amp;short_desc_type=allwordssubstr&amp;short_desc=&amp;product=Ant&amp;long_desc_type=substring&amp;long_desc=&amp;bug_file_loc_type=allwordssubstr&amp;bug_file_loc=&amp;keywords_type=allwords&amp;keywords=&amp;bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailtype1=substring&amp;email1=&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailtype2=substring&amp;email2=&amp;bugidtype=include&amp;bug_id=&amp;votes=&amp;chfieldfrom=&amp;chfieldto=Now&amp;chfieldvalue=&amp;field0-0-0=noop&amp;type0-0-0=noop&amp;value0-0-0=&amp;order=bugs.votes,bugs.priority%2Cbugs.bug_severity&amp;query_based_on=">Open Ant bugs by number of votes</a>.</p>
+      </subsection>
+
+      <subsection name="Filing a Bug Report">
+         <p>
+            Please read our document about <a href="problems.html">problems</a>
+            before deciding that there is an unreported
+            bug in Ant.
+        </p>
+        <p>
+            You have a few choices at this point. You can send
+            an email to the <code>user</code> mailing list
+            to see if
+            others have encountered your issue and find out how they may
+            have worked around it. If after some discussion, you feel it
+            is time to create
+            a bug report, this is a simple operation in the bug database.
+            Please try to provide as much information as possible in order
+            to assist the developers in resolving the bug. Please try to enter
+            correct values for the various inputs when creating the bug, such
+            as which version of Ant you are running, and on which platform,
+            etc. Once the bug is created, you can also add attachments to
+            the bug report.
+         </p>
+         <p>
+            What information should you include in your bug report? The
+            easiest bugs to fix are those that are most easily reproducible,
+            so it is really helpful if you can produce a small test case that
+            exhibits the problem. In this case, you would attach the build file
+            and any other files necessary to reproduce the problem, probably
+            packed together in an archive. If you can't produce a test case,
+            you should try to include a snippet from your build file and the
+            relevant sections from the verbose or debug output from Ant. Try
+            to include the header information where Ant states the version,
+            the OS and VM information, etc. As debug output is likely to be
+            very large, it's best to remove any output that is not
+            relevant. Once the bug is entered into the bug database, you
+            will be kept informed by email about progress on the bug. If
+            you receive email asking for further information, please try to
+            respond, as it will aid in the resolution of your bug.
+         </p>
+         <p>
+            To create the bug report hit this
+            <a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Ant">
+            link</a>.
+         </p>
+      </subsection>
+
+      <subsection name="Asking for an Enhancement">
+         <p>
+            Sometimes, you may find that Ant just doesn't do what you need it
+            to. It isn't a bug, as such, since Ant is working the way it is
+            supposed to work. Perhaps it is some additional functionality for
+            a task that hasn't been thought of yet, or maybe a completely new
+            task. For these situations, you will
+            want to raise an <i>enhancement request</i>. Enhancement requests
+            are managed using the same Apache Bug Database described above.
+            These are just a different type of bug report. If you look in the
+            bug database, you will see that one of the severity settings for
+            a bug is &quot;Enhancement&quot;. Just fill the bug report in,
+            set the severity of the bug to &quot;Enhancement&quot;, and
+            state in the description how you would like to have Ant enhanced.
+            Again, you should first check whether there are any existing
+            enhancment requests that cover your needs. If so, just add your
+            vote to these.
+         </p>
+        <p>
+          <a href="http://issues.apache.org/bugzilla/enter_bug.cgi?product=Ant&amp;bug_severity=enhancement">
+          Create an enhancement report</a>
+
+        </p>
+      </subsection>
+
+      <subsection name="Fixing the Bug">
+         <p>
+            If you aren't satisfied with just filing a bug report, you can
+            try to find the cause of the problem and provide a fix yourself.
+            The best way to do that is by working with the latest code from Subversion.
+            Alternatively, you can work with the source code available from the
+            <a href="http://ant.apache.org/srcdownload.cgi">
+            source distributions</a>. If you
+            are going to tackle the problem at this level, you may want to
+            discuss some details first on the <code>dev</code>
+            mailing list. Once you have a fix for the problem, you may submit
+            the fix as a <i>patch</i> to either the
+            <code>dev</code> mailing
+            list, or enter the bug database as described above and attach the
+            patch to the bug report. Using the bug database has the advantage
+            of being able to track the progress of your patch.
+         </p>
+         <p>
+            If you have a patch to submit and are sending it to the
+            <code>dev</code> mailing list,
+            prefix &quot;[PATCH]&quot;
+            to your message subject (this is also a good idea for
+            a subject line in the bug database).
+            Please include any relevant bug numbers.
+            Patch files should be created with the <code>-u</code>
+            option of the
+            <code>diff</code> or <code>svn diff</code> command. For
+            example:<br></br><br></br>
+            <font face="verdana" size="-1">
+            diff -u Javac.java.orig Javac.java &gt; javac.diffs<br></br><br></br>
+            </font>
+            or, if you have source from Subversion:<br></br><br></br>
+            <font face="verdana" size="-1">
+            svn diff Javac.java &gt; javac.diffs<br></br><br></br>
+            </font>
+
+           Note: You should give your patch files meaningful names.
+           This makes it easier for developers who need to apply a number
+           of different patch files.
+        </p>
+      </subsection>
+
+
+   </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/bylaws.xml b/trunk/xdocs/bylaws.xml
new file mode 100644
index 0000000..f1a87a6
--- /dev/null
+++ b/trunk/xdocs/bylaws.xml
@@ -0,0 +1,477 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Project Bylaws</title>
+    <author email="">Apache Ant PMC</author>
+  </properties>
+
+<body>
+  <section name="Apache Ant Project Bylaws">
+    <p>
+      This document defines the bylaws under which the Apache Ant project
+      operates. It defines the roles and responsibilities of the
+      project, who may vote, how voting works, how conflicts are resolved,
+      etc.
+    </p>
+
+    <p>
+      Ant is a project of the
+      <a href="http://www.apache.org/foundation/">Apache Software
+      Foundation</a>.  The foundation holds the copyright on Apache
+      code including the code in the  Ant codebase. The
+      <a href="http://www.apache.org/foundation/faq.html">foundation FAQ</a>
+      explains the operation and background of the foundation.
+    </p>
+
+    <p>
+      Ant is typical of Apache projects in that it operates under a set of
+      principles, known collectively as the &quot;Apache Way&quot;. If you are
+      new to Apache development, please refer to the
+      <a href="http://incubator.apache.org">Incubator project</a>
+      for more information on how Apache projects operate. <b>Note:</b> the
+      incubator project has only been recently set up and does not yet explain
+      the Apache Way in great detail.
+    </p>
+
+    <ul>
+        <li><a href="#Roles and Responsibilities">Roles and Responsibilities</a></li>
+        <li><a href="#Decision Making">How decisions are made</a></li>
+    </ul>
+
+  </section>
+
+  <section name="Roles and Responsibilities">
+    <p>
+      Apache projects define a set of roles with associated rights and
+      responsibilities. These roles govern what tasks an individual may perform
+      within the project. The roles are defined in the following sections
+    </p>
+
+    <ul>
+      <li><a href="#Users">Users</a></li>
+      <li><a href="#Developers">Developers</a></li>
+      <li><a href="#Committers">Committers</a></li>
+      <li><a href="#Project Management Committee">
+        Project Management Committee (PMC)</a>
+      </li>
+    </ul>
+
+    <subsection name="Users">
+      <p>
+        The most important participants in the project are people who use our
+        software. The majority of our developers start out as users and guide
+        their development efforts from the user's perspective.
+      </p>
+
+      <p>
+        Users contribute to the Apache projects by providing feedback to
+        developers in the form of bug reports and feature suggestions. As
+        well, users participate in the Apache community by helping other users
+        on mailing lists and user support forums.
+      </p>
+
+    </subsection>
+
+    <subsection name="Developers">
+      <p>
+        All of the volunteers who are contributing time, code, documentation,
+        or resources to the Ant Project. A developer that makes sustained,
+        welcome contributions to the project may be invited to become a
+        Committer, though the exact timing of such invitations depends on many
+        factors.
+      </p>
+    </subsection>
+
+    <subsection name="Committers">
+      <p>
+        The project's Committers are responsible for the project's technical
+        management. All committers have write access to the project's source
+        repositories. Committers may cast binding votes on any technical
+        discussion regarding the project.
+      </p>
+
+      <p>
+        Committer access is by invitation only and must be approved by lazy
+        consensus of the active PMC members. A Committer is considered emeritus
+        by their own declaration or by not contributing in any form to the
+        project for over six months. An emeritus committer may request
+        reinstatement of commit access from the PMC. Such reinstatement is
+        subject to lazy consensus of active PMC members.
+      </p>
+
+      <p>
+        Commit access can be revoked by a unanimous vote of all the active
+        PMC members (except the committer in question if they are also a PMC member).
+      </p>
+
+      <p>
+        All Apache committers are required to have a signed Contributor License
+        Agreement (CLA) on file with the Apache Software Foundation. There is a
+        <a href="http://www.apache.org/dev/committers.html">Committer FAQ</a>
+        which provides more details on the requirements for Committers
+      </p>
+
+      <p>
+        A committer who makes a sustained contribution to the project may be
+        invited to become a member of the PMC. The form of contribution is
+        not limited to code. It can also include code review, helping out
+        users on the mailing lists, documentation, etc.
+      </p>
+    </subsection>
+    <subsection name="Project Management Committee">
+      <p>
+        The Project Management Committee (PMC) for Apache Ant was created by a
+        <a href="mission.html">resolution</a> of the board of the Apache
+        Software Foundation on 18<sup>th</sup> November 2002. The PMC is
+        responsible to the board and the ASF for the management and oversight
+        of the Apache Ant codebase. The responsibilities of the PMC include
+      </p>
+
+      <ul>
+        <li>Deciding what is distributed as products of the Apache Ant project.
+            In particular all releases must be approved by the PMC
+        </li>
+        <li>Maintaining the project's shared resources, including the codebase
+            repository, mailing lists, websites.
+        </li>
+        <li>Speaking on behalf of the project.
+        </li>
+        <li>Resolving license disputes regarding products of the project
+        </li>
+        <li>Nominating new PMC members and committers
+        </li>
+        <li>Maintaining these bylaws and other guidelines of the project
+        </li>
+      </ul>
+
+      <p>
+        Membership of the PMC is by invitation only and must be approved by a
+        lazy consensus of active PMC members. A PMC member is considered
+        &quot;emeritus&quot; by their own declaration or by not contributing in
+        any form to the project for over six months. An emeritus member may
+        request reinstatement to the PMC. Such reinstatement is subject to lazy
+        consensus of the active PMC members. Membership of the PMC can be
+        revoked by an unanimous vote of all the active PMC members other than
+        the member in question.
+      </p>
+
+      <p>
+        The chair of the PMC is appointed by the ASF board. The chair is an
+        office holder of the Apache Software Foundation (Vice President,
+        Apache Ant) and has primary responsibility to the board for the
+        management of the projects within the scope of the Ant PMC. The chair
+        reports to the board quarterly on developments within the Ant project.
+        The PMC may consider the position of PMC chair annually and if
+        supported by 2/3 Majority may recommend a new chair to the board.
+        Ultimately, however, it is the board's responsibility who it chooses
+        to appoint as the PMC chair.
+      </p>
+    </subsection>
+  </section>
+
+  <section name="Decision Making">
+    <p>
+      Within the Ant project, different types of decisions require different
+      forms of approval. For example, the
+      <a href="#Roles and Responsibilities">previous section</a> describes
+      several decisions which require &quot;lazy consensus&quot; approval. This
+      section defines how voting is performed, the types of approvals, and which
+      types of decision require which type of approval.
+    </p>
+
+    <subsection name="Voting">
+      <p>
+        Decisions regarding the project are made by votes on the primary project
+        development mailing list (dev@ant.apache.org). Where necessary,
+        PMC voting may take place on the private Ant PMC mailing list.
+        Votes are clearly indicated by subject line starting with [VOTE] or
+        [PMC-VOTE]. Votes may contain multiple items for approval and these
+        should be clearly separated. Voting is carried out by replying to the
+        vote mail. Voting may take four flavours
+      </p>
+
+      <table>
+        <tr>
+          <td><strong>+1</strong></td>
+          <td>
+            &quot;Yes,&quot; &quot;Agree,&quot; or &quot;the action should be
+            performed.&quot; In general, this vote also indicates a willingness
+            on the behalf of the voter in &quot;making it happen&quot;
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>+0</strong></td>
+          <td>
+            This vote indicates a willingness for the action under
+            consideration to go ahead. The voter, however will not be able
+            to help.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>-0</strong></td>
+          <td>
+            This vote indicates that the voter does not, in general, agree with
+            the proposed action but is not concerned enough to prevent the
+            action going ahead.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>-1</strong></td>
+          <td>
+            This is a negative vote. On issues where consensus is required,
+            this vote counts as a <strong>veto</strong>. All vetoes must
+            contain an explanation of why the veto is appropriate. Vetoes with
+            no explanation are void. It may also be appropriate for a -1 vote
+            to include an alternative course of action.
+          </td>
+        </tr>
+      </table>
+
+      <p>
+        All participants in the Ant project are encouraged to show their
+        agreement with or against a particular action by voting. For technical
+        decisions, only the votes of active committers are binding. Non binding
+        votes are still useful for those with binding votes to understand the
+        perception of an action in the wider Ant community. For PMC decisions,
+        only the votes of PMC members are binding.
+      </p>
+
+      <p>
+        Voting can also be applied to changes made to the Ant codebase. These
+        typically take the form of a veto (-1) in reply to the commit message
+        sent when the commit is made.
+      </p>
+    </subsection>
+
+    <subsection name="Approvals">
+      <p>
+        These are the types of approvals that can be sought. Different actions
+        require different types of approvals
+      </p>
+
+      <table>
+        <tr>
+          <td><strong>Consensus</strong></td>
+          <td>
+            For this to pass, all voters with binding votes must vote and there
+            can be no binding vetoes (-1). Consensus votes are rarely required
+            due to the impracticality of getting all eligible voters to cast a
+            vote.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>Lazy Consensus</strong></td>
+          <td>
+            Lazy consensus requires 3 binding +1 votes and no binding vetoes.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>Lazy Majority</strong></td>
+          <td>
+            A lazy majority vote requires 3 binding +1 votes and more binding +1
+            votes that -1 votes.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>Lazy Approval</strong></td>
+          <td>
+            An action with lazy approval is implicitly allowed unless a -1 vote
+            is received, at which time, depending on the type of action, either
+            lazy majority or lazy consensus approval must be obtained.
+          </td>
+        </tr>
+
+        <tr>
+          <td><strong>2/3 Majority</strong></td>
+          <td>
+            Some actions require a 2/3 majority of active committers or PMC
+            members to pass. Such actions typically affect the foundation
+            of the project (e.g. adopting a new codebase to replace an existing
+            product). The higher threshold is designed to ensure such changes
+            are strongly supported. To pass this vote requires at least 2/3 of
+            binding vote holders to vote +1
+          </td>
+        </tr>
+      </table>
+    </subsection>
+
+    <subsection name="Vetoes">
+      <p>
+        A valid, binding veto cannot be overruled. If a veto is cast, it must be
+        accompanied by a valid reason explaining the reasons for the veto. The
+        validity of a veto, if challenged, can be confirmed by anyone who has
+        a binding vote. This does not necessarily  signify agreement with the
+        veto - merely that the veto is valid.
+      </p>
+
+      <p>
+        If you disagree with a valid veto, you must lobby the person casting
+        the veto to withdraw their veto. If a veto is not withdrawn, the action
+        that has been vetoed must be reversed in a timely manner.
+      </p>
+    </subsection>
+
+    <subsection name="Actions">
+      <p>
+        This section describes the various actions which are undertaken within
+        the project, the corresponding approval required for that action and
+        those who have binding votes over the action.
+      </p>
+
+      <table>
+        <tr>
+          <th>Action</th>
+          <th>Description</th>
+          <th>Approval</th>
+          <th>Binding Votes</th>
+        </tr>
+        <tr>
+          <td><strong>Code Change</strong></td>
+          <td>
+            A change made to a codebase of the project and committed
+            by a committer. This includes source code, documentation, website
+            content, etc.
+          </td>
+          <td>
+            Lazy approval and then lazy consensus.
+          </td>
+          <td>
+            Active committers.
+          </td>
+        </tr>
+        <tr>
+          <td><strong>Release Plan</strong></td>
+          <td>
+            Defines the timetable and actions for a release. The plan also
+            nominates a Release Manager.
+          </td>
+          <td>
+            Lazy majority
+          </td>
+          <td>
+            Active committers
+          </td>
+        </tr>
+        <tr>
+          <td><strong>Product Release</strong></td>
+          <td>
+            When a release of one of the project's products is ready, a vote is
+            required to accept the release as an official release of the
+            project.
+          </td>
+          <td>
+            Lazy Majority
+          </td>
+          <td>
+            Active PMC members
+          </td>
+        </tr>
+        <tr>
+          <td><strong>Adoption of New Codebase</strong></td>
+          <td>
+            <p>
+            When the codebase for an existing, released product is to be
+            replaced with an alternative codebase. If such a vote fails to
+            gain approval, the existing code base will continue.
+            </p>
+
+            <p>
+            This also covers the creation of new sub-projects
+            within the project
+            </p>
+          </td>
+          <td>
+            2/3 majority
+          </td>
+          <td>
+            Active committers
+          </td>
+        </tr>
+        <tr>
+          <td><strong>New Committer</strong></td>
+          <td>
+            When a new committer is proposed for the project
+          </td>
+          <td>
+            Lazy consensus
+          </td>
+          <td>
+            Active PMC members
+          </td>
+        </tr>
+        <tr>
+          <td><strong>New PMC Member</strong></td>
+          <td>
+            When a committer is proposed for the PMC
+          </td>
+          <td>
+            Lazy consensus
+          </td>
+          <td>
+            Active PMC members
+          </td>
+        </tr>
+        <tr>
+          <td><strong>Committer Removal</strong></td>
+          <td>
+            <p>When removal of commit privileges is sought.</p>
+            <p><b>Note: </b> Such actions will also be referred to the ASF
+            board by the PMC chair</p>
+          </td>
+          <td>
+            Consensus
+          </td>
+          <td>
+            Active PMC members (excluding the committer in question if a
+            member of the PMC).
+          </td>
+        </tr>
+        <tr>
+          <td><strong>PMC Member Removal</strong></td>
+          <td>
+            <p>When removal of a PMC member is sought.</p>
+            <p><b>Note: </b> Such actions will also be referred to the
+            ASF board by the PMC chair</p>
+          </td>
+          <td>
+            Consensus
+          </td>
+          <td>
+            Active PMC members (excluding the member in question).
+          </td>
+        </tr>
+      </table>
+    </subsection>
+    <subsection name="Voting Timeframes">
+      <p>
+        Votes are open for a period of 1 week to allow all active voters
+        time to consider the vote. Votes relating to code changes are not
+        subject to a strict timetable but should be made as timely as possible.
+      </p>
+    </subsection>
+  </section>
+</body>
+</document>
diff --git a/trunk/xdocs/contributors.xml b/trunk/xdocs/contributors.xml
new file mode 100644
index 0000000..6ca7f91
--- /dev/null
+++ b/trunk/xdocs/contributors.xml
@@ -0,0 +1,382 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+  <properties>
+    <title>Contributors</title>
+    <author email="">Apache Ant PMC</author>
+  </properties>
+
+  <body>
+    <section name="Project Management Committee">
+
+      <subsection name="Active Members">
+
+            <p>
+                <b>Bruce Atherton</b> (bruce at callenish.com - <a href="http://www.callenish.com/~bruce">http://www.callenish.com/~bruce</a>)
+<br/>
+Currently a Systems Architect with Avue Technologies, Bruce has been
+working with Java since version 1.0a2. He also claims to be one of the first
+people to mark up a FAQ with HTML, for a web browser of the distant past
+called Cello.
+            </p>
+
+            <p>
+                <b>Stephane Bailliez</b><br/>
+            </p>
+
+            <p>
+                <b>Matt Benson</b><br/>
+            </p>
+
+            <p>
+                <b>Stefan Bodewig</b> (stefan.bodewig at freenet.de -
+          <a href="http://stefan.samaflost.de/">http://stefan.samaflost.de/</a>)
+<br/>
+</p>
+
+            <p>
+                <b>Dominique Devienne</b> (ddevienne at apache.org)
+<br/>
+Dominique has been involved non-stop with the Ant user community since
+the 1.4 days, trying without success to answer posts as well or as often
+as Diane Holt after she left the user list. He is opinionated, always
+striving for the best possible design. While at Landmark Graphics, he
+designed and implemented large Ant/CppTasks builds for mixed Java/C++ projects.
+            </p>
+
+            <p>
+                <b>Erik Hatcher</b> (ehatcher at apache.org)
+<br/>
+Erik is the co-author of <a href="http://www.manning.com/hatcher">
+Java Development with Ant</a> and speaks on Ant and other topics at
+<a href="http://www.nofluffjuststuff.com">No Fluff, Just Stuff
+symposiums</a> as well as other venues.  Erik is the President of
+<a href="http://www.ehatchersolutions.com">eHatcher Solutions, Inc</a>.
+</p>
+            <p>
+                <b>Martijn (J.M.) Kruithof</b> (ant at kruithof xs4all nl)
+<br/>
+Martijn Kruithof is a system engineer working with and on Java products
+in a telecommunication network setting.
+</p>
+            <p>
+                <b>Antoine Levy-Lambert</b> (antoine at apache.org)
+<br/>
+Antoine is working as a software engineer for 
+<a href="http://www.arielpartners.com">Ariel Partners</a>.
+He is specialized in builds and automation of deployment processes.
+
+            </p>
+
+             <p>
+                <b>Steve Loughran</b><br/>
+            </p>
+
+            <p>
+                <b>Conor MacNeill</b> (conor at cortexebusiness.com.au)
+<br/>
+Conor is a senior developer at Cortex eBusiness, where he develops
+J2EE based systems. In his spare time he helps with the development of
+the Ant build tool.  He is also serving as the Chairman of this PMC.
+</p>
+
+            <p>
+				<b>Jan Matèrne</b> (jhm at apache.org)
+<br/>
+Jan is consultant for OOA/D in the computer centre of the government
+of Northrhine Westfalia / Germany.
+            </p>
+
+            <p>
+                <b>Peter Reilly</b><br/>
+            </p>
+
+            <p>
+                <b>
+                    <a href="http://www.intertwingly.net/">Sam Ruby</a>
+                </b>
+                (rubys at us.ibm.com)
+<br/>
+Sam takes a perverse pleasure in integrating disparate things.  He is
+a member of the <a href="http://www.php.net/credits.php">PHP group</a>, Apache
+<a href="http://xml.apache.org/whoweare.html">XML PMC</a>, Apache
+sponsor for the <a href="http://xml.apache.org/soap">xml-soap</a> subproject
+and convener of <a href="http://www.ecma.ch">ECMA</a> TC39 TG3.
+</p>
+            <p>
+                <b>Magesh Umasankar</b> (umagesh at apache.org)
+<br/>
+Magesh, President of <a href='http://www.metamachsolutions.com'>Metamach Solutions</a>, 
+an Atlanta-based technology-management consultancy, has recently launched 
+<a href='http://www.winedin.com'>WinedIn.com</a> for wine-lovers to pair food and wine. 
+</p>
+
+            <p>
+                <b>Christoph Wilhelms</b> (christoph.wilhelms at t-online.de)
+<br/>
+Christoph works as software engineer at the world's biggest travel company
+<a href="http://www.tui.com">TUI</a>. His passion are all UI related things so
+at the Ant-Project he takes care of Antidote - the Ant GUI.
+            </p>
+<p>
+  <b>Kevin Jackson</b> (foamdino at gmail.com)<br/>
+</p>
+
+      </subsection>
+      <subsection name="Emeritus Members">
+
+            <p>
+                <b>James Duncan Davidson</b> (duncan at x180.net - <a href="http://x180.net/">http://x180.net/</a>)
+<br/>
+
+By day, Duncan works in the Open Source Program Office at Sun
+Microsystems where he helps various Open Source efforts within Sun
+&quot;do the right thing&quot;. Previously at Sun he was responsible
+for the Servlet API Specifications 2.1 and 2.2 as well as the Java API
+for XML Parsing 1.0 and was the original author of Tomcat and Ant. He
+was one of the rabble-rousers within Sun that helped make the Jakarta
+Project a reality and served as the first Chairman of the Jakarta PMC.
+</p>
+
+            <p>
+                <b>Diane Holt</b><br/>
+            </p>
+
+            <p>
+                <b>Donald Leslie</b><br/>
+            </p>
+
+            <p>
+                <b>Costin Monolache</b><br/>
+            </p>
+
+            <p>
+                <b>Jon Skeet</b><br/>
+            </p>
+
+      </subsection>
+
+    </section>
+    <section name="Committers">
+
+      <subsection name="Active Committers">
+
+            <p>
+                <b>Steve Cohen</b>
+            </p>
+
+            <p>
+                <b>Jose Alberto Fernandez</b>
+            </p>
+
+            <p>
+                <b>Jesse Glick</b> (jesse dot glick at sun dot com)
+<br/>
+Jesse has been using Java since 1998 and joined Sun Microsystems as
+part of the company that produced the NetBeans IDE. After discovering
+Ant in the 1.2 days, he wrote most of NetBeans' Ant integration.
+Recently he has worked on the NetBeans 4.0 project system, based heavily
+on Ant as a build tool.
+</p>
+<p>
+   <b>Alexey Solofnenko</b> (trelony at gmail.com)<br />
+</p>
+
+      </subsection>
+      <subsection name="Emeritus Committers">
+            <p>
+                <b>Preston Bannister</b><br/>
+            </p>
+
+            <p>
+                <b>Nick Davis</b><br/>
+            </p>
+
+            <p>
+                <b>Darrell DeBoer</b><br/>
+            </p>
+
+            <p>
+                <b>Peter Donald</b> (peter at apache.org)
+<br/>
+
+Peter is an avid java developer who is active in the
+<a href="http://jakarta.apache.org/avalon/">Avalon</a> and
+<a href="http://ant.apache.org/">Ant</a> projects.
+In his spare time he develops a distributed virtual environment
+(ie military simulator or 3D game) using java technologies.
+</p>
+
+            <p>
+                <b>Danno Ferrin</b> (shemnon at yahoo.com)
+<br/>
+Danno has been programming in Java since Summer 96. Danno wrote a JSP
+engine on his own and released it the very same day Jakarta was
+announced at JavaOne. Since then, he decided to join the Jakarta
+project in a spirit of co-operation over competition.
+</p>
+
+            <p>
+                <b>Simeon H.K. Fitch</b> (simeon.fitch at mseedsoft.com)
+<br/>
+Simeon is owner of Mustard Seed Software, which specializes in developing
+distributed applications and user interfaces for the science, engineering,
+and research oriented clients. He is the lead architect and developer for
+Antidote, the GUI for Ant.
+</p>
+
+            <p>
+                <b>Thomas Haas</b> (tha at whitestein.com)
+<br/>
+Tom is interested in distributed systems, Java middleware and worked on an
+implementation of the JMS specification. At Whitestein Technologies he is
+working on bringing software agent technology and J2EE together.
+</p>
+
+      <p>
+
+                <b>Jason Hunter</b> (jh at servlets.com)
+<br/>
+Jason is author of "Java Servlet Programming" (O'Reilly) and publisher
+of <a href="http://www.servlets.com/">http://www.servlets.com/</a>.
+He works at <a href="http://www.collab.net">CollabNet</a>.
+</p>
+
+            <p>
+                <b>Justyna Horwat</b> (horwat at apache.org)
+<br/>
+</p>
+
+            <p>
+                <b>Arun Jamwal</b>
+<br/>
+</p>
+
+            <p>
+                <b>Arnout J. Kuiper</b> (ajkuiper at planet.nl)
+<br/>
+
+Arnout J. Kuiper is a Java Architect with the Sun Java Center at Sun
+Microsystems. His main focus is web-related technologies on the Java
+platform (J2EE, XML, ...).
+</p>
+
+<p>
+                <b>Stefano Mazzocchi</b> (stefano at apache.org)
+<br/>
+Stefano is addicted to software design, Java programming and
+open development. In the last 4 years, he has contributed way too much
+time to Apache, expecially on JServ, JMeter, Avalon, JAMES, Ant, Cocoon
+and helping to bring more projects into Apache-land, such as FOP, Batik,
+POI and Xindice. The problem is that he's too picky to be satisfied :-)
+</p>
+
+            <p>
+                <b>Glenn McAllister</b> (glenn at somanetworks.com)
+<br/>
+Glenn McAllister is a software developer at SOMA Networks, was formerly
+the same at IBM (plus tech writer plus build guy), and does some writing
+on the side for the VADD Technical Journal.
+</p>
+
+           <p>
+                <b>Craig McClanahan</b> (Craig.McClanahan at eng.sun.com)
+<br/>
+Craig was involved in the Apache JServ project, focused on implementing
+a next generation architecture and feature set for the core servlet
+engine.  He has recently joined Sun as technical lead for the servlet
+and JSP reference implementation.
+          </p>
+
+            <p>
+                <b>Adam Murdoch</b>
+<br/>
+</p>
+
+            <p>
+                <b>Harish Prabhandham</b> (harishp at onebox.com)
+<br/>
+Harish is an engineer with the J2EE team at Sun, primarily responsible
+for implementing security in the J2EE Reference Implementation
+(RI). He integrated various technologies including servlet/JSP
+implementations from Tomcat into the J2EE RI. These days, he hacks PHP
+code during the day.
+</p>
+
+            <p>
+                <b>Nico Seessle</b><br/>
+            </p>
+
+            <p>
+                <b>Gal Shachor</b> (shachor at il.ibm.com)
+<br/>
+Gal Shachor is a research staff member at IBM. He wrote his first
+Servlet container (ServletExpress) at the beginning of 1997. Later on
+ServletExpress (and Gal) merged into WebSphere, and Gal participated
+in the development of WebSphere 1, 2 and 3.
+</p>
+
+            <p>
+                <b>Jon S. Stevens</b> (jon at collab.net)
+<br/>
+
+Jon is a Co-Founder of <a href="http://www.clearink.com/">Clear Ink
+Corp</a> and recently left to work on <a href="http://scarab.tigris.org/">Scarab</a> a next generation Open
+Source Java Servlet based Issue/Bug tracking system for <a href="http://www.collab.net/">CollabNet</a>. He is an active developer
+of the <a href="http://java.apache.org/jserv/">Apache JServ Servlet
+Engine</a> for the Apache Web Server and Co-Author of the <a href="http://java.apache.org/ecs/">Element Construction Set</a> as
+well as the web application framework, <a href="http://java.apache.org/turbine/">Turbine</a>.
+</p>
+
+            <p>
+                <b>Jesse Stockall</b><br/>
+            </p>
+
+            <p>
+                <b>James Todd</b> (jwtodd at pacbell.net)
+<br/>
+James has developed real time customer oriented apps for roughly 10
+years the last 5 of which have predominately been fully integrated,
+front and back, extraNet implementations which have been based on
+Apache, Java and Tcl.
+</p>
+
+          <p>
+                <b>Anil Vijendran</b> (akv at eng.sun.com)
+<br/>
+Anil Vijendran is the principal developer of the JSP engine in
+Tomcat. He's done some pretty scary things in his past life --
+implementing the CORBA IDL to C++ 2.0 mapping, skydiving, IDL to Java
+compilers, Object Databases (SIGSEV, you da man!) for C++, Java ORB
+and EJB runtime environments -- in that order.
+</p>
+
+      </subsection>
+    </section>
+
+    <section name="Logo">
+      <p>Ant's logo is the result of a logo contest, it has been
+        designed by</p>
+
+            <p>
+                <b>Nick King</b>
+<br/>
+</p>
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/external.xml b/trunk/xdocs/external.xml
new file mode 100644
index 0000000..c2d2944
--- /dev/null
+++ b/trunk/xdocs/external.xml
@@ -0,0 +1,3958 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="bodewig@apache.org">Stefan Bodewig</author>
+    <title>External Tools and Tasks</title>
+  </properties>
+
+  <body>
+
+    <section name="External Tools and Tasks">
+
+      <p>This page lists external resources for Apache Ant: <a
+      href="#Tasks">Tasks</a>, <a
+      href="#Compiler%20Implementations">Compiler Implementations</a>,
+      <a href="#IDE%20and%20Editor%20Integration">IDE integration
+      tools</a>, <a href="#Source%20Control%20ystems">Source Control
+      Systems</a>, loggers, you name it. If you've written
+      something that should be included, please post all relevant
+      information to one of the mailing lists.  For details, see the
+      <a href="faq.html#adding-external-tasks">FAQ</a>.</p>
+
+      <p>Nothing listed here is directly supported by the Ant
+      developers (therefore '<i>external</i> tools and tasks'),
+      if you encounter any problems with them, please use
+      the contact information.</p>
+
+    </section>
+
+    <section name="Tasks">
+      <subsection name="AJC">
+
+        <p><a href="http://www.eclipse.org/aspectj/">AspectJ</a> is an
+          aspect-oriented extension to Java.  This task compiles a
+          source tree using the AspectJ compiler -- AJC.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.eclipse.org/aspectj/">http://www.eclipse.org/aspectj/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.eclipse.org/aspectj/">project mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Anakia">
+
+        <p>Actually, Anakia is more than just an Ant task, it is a an
+        XML transformation tool based on JDOM, Velocity and Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jakarta.apache.org/velocity/anakia.html">http://jakarta.apache.org/velocity/anakia.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://jakarta.apache.org/site/mail2.html">Velocity mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Andariel">
+
+        <p>Andariel is a set of tasks designed to help the generation of HTML
+        (and other markup languages) pages from Ant. Includes a XPath processor,
+        an image information retriever, and others.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.4 and newer</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://andariel.uworks.net/">http://andariel.uworks.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>josep DOT rio AT uworks DOT net</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License 1.1</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant2Svg">
+
+        <p>Ant2Svg creates a graphical representation of an Ant build file.
+        The graphical representation is in the form of a Scalable Vector
+        Graphics (SVG) file that can be displayed in a web browser. This
+        simplified SVG depiction helps the developer understand build file
+        structure and identify extraneous or missing dependencies.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.1 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.spiritedsw.com/ant2svg/">http://www.spiritedsw.com/ant2svg/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>loney &lt;at&gt; spiritedsw &lt;dot&gt; com</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>The Apache Software License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="ant4eclipse">
+
+        <p>ant4eclipse provides a set of Ant tasks to make several
+                configurations from the Eclipse IDE available in Ant
+                buildscripts. The tasks are aimed to avoid redundancy between
+                Eclipse and Ant configurations in order to build small but
+                powerful build systems for the continuous integration
+                process</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.1 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ant4eclipse.sf.net">http://ant4eclipse.sf.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=137377">
+              ant4eclipse user mailing list</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Sun Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antcount">
+        <p>Antcount is a set of filters that can be used to gather statistics
+           from files or resources. It is mainly used for log files analysis.
+           It allows to:<ul>
+             <li>count inputs (lines, strings)</li>
+             <li>count occurrences of each input</li>
+             <li>calculate average, max and min values of floats in input</li>
+           </ul>
+           Antcount also includes some useful filters to:<ul>
+             <li>stop filtering: read everything but write nothing</li>
+             <li>echo input to the console or to a file. This allows users to create
+                 several files at once</li>
+             <li>split the stream in two for parallel processing</li>
+           </ul>
+        </p>
+        <table class="externals">
+        <tr>
+          <th>Compatibility:</th>
+          <td>Ant 1.6.2 and higher</td>
+        </tr>
+        <tr>
+          <th>URL:</th>
+          <td><a href="http://antcount.sourceforge.net/">http://antcount.sourceforge.net/</a></td>
+        </tr>
+        <tr>
+          <th>Contact:</th>
+          <td><a href="http://antcount.sourceforge.net/contacts.html">Patrick Martin</a></td>
+        </tr>
+        <tr>
+          <th>License:</th>
+          <td>LGPL</td>
+        </tr>
+      </table>
+    </subsection>
+
+      <subsection name="AntDoc">
+
+        <p>AntDoc is a tool that generates HTML documentation from Ant
+        buildfiles; the generated HTML is inspired from what javadoc
+        yields.  AntDocGUI offers a simple Ant target launcher named
+        AntDoc GUI. Ant targets may be launched from the generated
+        AntDoc HTML pages. Integration to various IDEs is in
+        progress.</p>
+
+        <p>AntDoc can be run via an Ant task, AntDoc GUI can be run
+        via an Ant task, or via a JVM launch.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antdoc.free.fr/">http://antdoc.free.fr/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>Edouard Mercier</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>The Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntDoclet">
+
+        <p>AntDoclet is a tool to automatically generate documentation out of
+        your Ant Tasks' source code.</p>
+
+        <p>It is implemented as a Javadoc doclet, and generates reference
+        documentation and other deliverables from the source code of your
+        custom Ant Tasks/Types.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6+ (not tested on earlier versions)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antdoclet.neuroning.com/">http://antdoclet.neuroning.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://neuroning.com/">Fernando Dobladez</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Anteater">
+
+        <p>Anteater is a set of Ant tasks for the functional testing of websites
+          and web services (functional testing being; hit a URL and ensure the
+          response meets certain criteria). Can test HTTP params, response
+          codes, XPath, regexp and Relax NG expressions. Includes HTML reporting
+          (based on junitreport) and a hierarchical grouping system for quickly
+          configuring large test scripts.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://aft.sourceforge.net/">http://aft.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://lists.sourceforge.net/lists/listinfo/aft-devel">developer
+                mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntForm">
+
+        <p>Provides a java/swing form-based input scheme for
+        configuring ant properties and launching ant targets.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.2.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antforms.sourceforge.net/">http://antforms.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:rene_ghosh@yahoo.com">Ren&#233; Ghosh</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antmerge">
+
+        <p>Provides simple inheritance between ant files</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with 1.5. Should work with all versions.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.russet.org.uk/antmerge.html">http://www.russet.org.uk/antmerge.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:antmerge@russet.org.uk">Phillip Lord</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Lesser General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+      
+
+      <subsection name="Antomology">
+        <p>Antomology is an analysis tool suite for Ant. It includes:<ul>
+          <li><b>StatisticsListener</b> - an Ant BuildListener which can be used to gather
+              statistics while an Ant build is executed. Statistics on the targets
+              and tasks executed are written to the console after the build completes. </li>
+        </ul></p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td> <i>unknown</i> </td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antomology.codehaus.org">http://antomology.codehaus.org</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://xircles.codehaus.org/projects/antomology/lists">contact page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License V2.0</td>
+          </tr>
+        </table>
+      </subsection>
+        
+      
+      <subsection name="AntPrettyBuild">
+         <p>
+          Ant Pretty Build is a tool to easily show and run Ant buildfiles directly from
+        within a browser window. It consists of a single XSL file that will generate,
+        on the fly, in the browser, from the .xml buildfile, a pretty interface showing
+        project name, description, properties and targets, etc. sorted or unsorted,
+          allowing to load/modify/add properties, run the whole project, or run selected
+        set of targets in a specific order, with the ability to modify logger/logfile,
+        mode and add more libs or command line arguments.
+        </p>
+         <table class="externals">
+              <tr>
+                   <th>Compatibility:</th>
+                   <td>All Ant versions</td>
+              </tr>
+              <tr>
+                   <th>URL:</th>
+                   <td><a href="http://antprettybuild.sourceforge.net/">Ant Pretty Build Homepage</a></td>
+              </tr>
+              <tr>
+                   <th>Contact:</th>
+                   <td><a href="http://antprettybuild.sourceforge.net">Charbel BITAR</a></td>
+              </tr>
+              <tr>
+                   <th>License:</th>
+                   <td>Apache License V2.0</td>
+              </tr>
+         </table>
+      </subsection>
+
+      <subsection name="AntSpaces">
+
+        <p>AntSpaces provides Ant integration with JavaSpaces. This
+        allows you to coordinate Ant tasks via JavaSpaces, pull out
+        work units from a JavaSpace for distributed Ant tasks to work
+        on, and so forth.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.oopsconsultancy.com/software/antspaces/">http://www.oopsconsultancy.com/software/antspaces/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>antspaces at oopsconsultancy.com</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntTimerTask">
+        <p><a href="http://www.jeckle.de/freeStuff/AntTimerTask/index.html">Timer</a>
+        is task for measuring the time elapsed to complete other
+        tasks</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.jeckle.de/freeStuff/AntTimerTask/index.html">http://www.jeckle.de/freeStuff/AntTimerTask/index.html</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:mario@jeckle.de">mario@jeckle.de</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Lesser GNU Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant Web Start Task">
+
+        <p>Ant Web Start Task is an Ant task allowing developers to
+        package a desktop application as a WAR (Web Application
+        Archive) to be distributed over the net via Java Web Start</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ant-jnlp-war.sourceforge.net/">http://ant-jnlp-war.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntXtras">
+
+        <p>A collection of powerful Ant extensions components
+        organized into five categories: fixture-control,
+        execution-rules, flow-control, feedback, and helpers.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antxtras.sourceforge.net/">AntXtras Home</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://antxtras.sourceforge.net">SSMC</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Lesser General Public License (LGPL 2.1)</td>
+          </tr>
+        </table>
+      </subsection>
+
+
+      <subsection name="Build Number">
+        <p> Build Number is a tool to track software artifacts such as files and automatically assign
+        proper version/build numbers to them. It ensures that two different artifacts will have different
+        version/build numbers, but identical artifacts/builds will be assigned the same number. It doesn't
+        take version management away from you and doesn't replace your build process, but rather plugs
+        into the process and introduces version/build number governance by defining who is in charge of
+        which part of version number. With Build Number you are still in charge of the head of the version
+        number. E.g. you may decide to have 4 numbers in your version (major, minor, interface, implementation)
+        and you want to manage the two first numbers (major and minor). Build Number will take care of the
+        tedium of managing the last two numbers (interface and implementation). </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with Ant 1.5.4 and 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.hammurapi.biz/products/buildnumber">http://www.hammurapi.biz/products/buildnumber</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Checkstyle">
+
+        <p>Checkstyle is a development tool to help programmers write
+        Java code that adheres to a coding standard. Its purpose is to
+        automate the process of checking Java code, and to spare
+        humans of this boring (but important) task.</p>
+
+        <p>Checkstyle can be run via an Ant task or a command line
+        utility.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://checkstyle.sourceforge.net/">http://checkstyle.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:checkstyle@puppycrawl.com">Oliver Burn</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Starting with release 2.0 the license is the GNU
+            Lesser General Public License.  Prior releases were under
+            the GNU General Public License.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="ChownTask">
+
+        <p>ChownTask is an Ant task to change ownership of files on
+        Unix.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3 and up</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://sourceforge.net/projects/chowntask/">http://sourceforge.net/projects/chowntask/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:chowntask-users@lists.sourceforge.net">Wilfred Springer</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="CleanImports">
+        <p>Removes unneeded imports. Formats your import
+        sections. Flags ambiguous imports.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3 and up</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.cleanimports.tombrus.nl">http://www.cleanimports.tombrus.nl</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:cleanimports@tombrus.nl">Tom Brus</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Clover">
+
+        <p>Clover is an Ant-based Code Coverage tool. It can be used
+        seamlessly with Ant-based projects. It provides method,
+        statement, and branch coverage analysis, and has rich
+        reporting in XML, HTML or via a Swing GUI.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1 or greater</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.cenqua.com/clover/">http://www.cenqua.com/clover/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:clover-support@cenqua.com">clover-support@cenqua.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial, free licenses available for open source
+            projects.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="CMSDeploy">
+
+        <p><a href="http://cmsdeploy.sourceforge.net">CMSDeploy</a> is
+        an Apache Ant Task to submit files and templates to Vignette
+        CMS.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://cmsdeploy.sourceforge.net">http://cmsdeploy.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:masogato@users.sourceforge.net">masogato@users.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Lesser General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Cocoon Task">
+        <p>This task allows the generation of static web pages and
+        sites using Apache Cocoon in off-line mode.</p>
+        <p>It allows the configuration information for Cocoon to be
+        included within the Ant build file, and is thus
+        able to take advantage of Ant properties.</p>
+        <p>The task shares its code with the Cocoon Command Line, which
+        means that this task will instantly take
+        advantage of any new functionality added there.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.3 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://cocoon.apache.org/2.1/">http://cocoon.apache.org/2.1/</a></td>
+         </tr>
+          <tr>
+            <th>Documentation:</th>
+            <td><a href="http://cocoon.apache.org/2.1/userdocs/offiline/ant.html">http://cocoon.apache.org/2.1/userdocs/offline/ant.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:users.at.cocoon.apache.org">users at cocoon.apache.org</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+       </table>
+     </subsection>
+
+     <subsection name="Configure">
+
+        <p>Recursive build support (call ant on every package level,
+        and only build files in that package or in that package and
+        everything below) with seperation of source and output.</p>
+
+        <p>The task generates build files in any subdirectory (except
+        for CVS-directories) for you. Only place one build.xml file in
+        the top and call target &apos;setup&apos; or
+        &apos;rescan&apos;.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and 1.3</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.dsdelft.nl/~lemval/ant/">http://www.dsdelft.nl/~lemval/ant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:lemval@dsdelft.nl">M.J.P. van Leeuwen</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>License derived from Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="CVSGrab">
+
+        <p>A little CVS client that can be useful when people are
+        behind corporate firewall that blocks any cvs
+        communications. It uses the ViewCVS web interface to access
+        the CVS repository via standard http, and downloads all the
+        files present in it.</p>
+
+        <p>It works from the command line or as an Ant task.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://cvsgrab.sourceforge.net/">http://cvsgrab.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:cvsgrab-users@lists.sourceforge.net">CVSGrab
+            user mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Dependencies">
+          <p>The dependencies task manages a set of external dependencies which
+            may be downloaded from a remote repository,
+             such as ibiblio.org. Uses a local cache to avoid repeated
+            downloads.</p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Tested with 1.5.1, should work with 1.4+.</td>
+           </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a href="http://www.httpunit.org/doc/dependencies.html">http://www.httpunit.org/doc/dependencies.html</a></td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:russgold@httpunit.org">Russell Gold</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>MIT License</td>
+            </tr>
+          </table>
+    </subsection>
+
+      <subsection name="Dependency Finder">
+        <p>Dependency Finder extracts dependencies and OO metrics from
+        Java class files produced by most Java compilers. It can compute
+        API differences between versions;  no sources needed. It includes
+        Ant tasks, web, Swing, and command-line interfaces, with XSL
+        stylesheets for formatting output.</p>
+
+        <p>You can use it to extract dependencies between packages, classes,
+        or even methods, or any combination thereof.  You can use Perl
+        regular expressions to filter the information and pinpoint only
+        what you need.  There is even a Web Application version (WAR file)
+        so a whole group of developers can share a common view.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with 1.5.3, should work with 1.4+.</td>
+         </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://depfind.sourceforge.net/">http://depfind.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jeantessier@users.sourceforge.net">Jean Tessier</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD-like License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Doxygen task">
+        <p>There are two Ant tasks for running the Doxygen
+        documentation system.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.bgw.org/projects/java/ant/">http://www.bgw.org/projects/java/ant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:mortis@voicenet.com">Kyle R. Burton</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+
+        <p>and</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ant-doxygen.sourceforge.net/">http://ant-doxygen.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:akkumar@users.sourceforge.net">Karthik A Kumar</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="DTDDoc">
+        <p>DTDDoc is here to help you to document your DTD's efficiently. It is a
+        straightforward extension of the javadoc concept to the DTD file format.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://dtddoc.sourceforge.net/">http://dtddoc.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=53704">Project Mailing List</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>X11 (Open Source)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="EnvGen">
+        <p>
+          <a href="http://www.basilv.com/psd/software">EnvGen</a> is an Ant task for generating 
+          different versions of the same file parameterized for different environments (i.e. 
+          development, test, and production). File generation is done using 
+          <a href="http://freemarker.org/">FreeMarker</a>, a template engine with a full-featured 
+          templating language.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5 or higher (not tested on earlier versions)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.basilv.com/psd/software">http://www.basilv.com/software</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.basilv.com/psd/software/feedback">EnvGen Feedback Page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="EMMA">
+        <p>EMMA is an open-source toolkit for measuring and reporting
+        Java code coverage. EMMA distinguishes itself from other tools
+        by going after a unique feature combination: support large-scale
+        enterprise software development while keeping individual developers
+        work fast and iterative at the same time.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://emma.sourceforge.net/">http://emma.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:emma-users@lists.sourceforge.net">Mailinglist</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Common Public License 1.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="FMPP">
+        <p>FMPP is a general-purpose text file preprocessor tool that
+        uses FreeMarker templates. It is particularly designed for
+        HTML preprocessor, for the generation of complete (static)
+        homepages: directory structure that contains HTML-s, image
+        files, etc. But of course it can be used to generate source
+        code or whatever text files. FMPP is extendable with Java
+        classes to pull data from any data sources (XML file,
+        database, etc.) and embed the data into the generated
+        files.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://fmpp.sourceforge.net/">http://fmpp.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="GenJar">
+        <p>Builds a JAR file based on class dependencies rather than simply the contents of a directory</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 alpha (built after 2001/08/04) and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://genjar.sourceforge.net/">http://genjar.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jesse_dev@yahoo.com">Jesse Stockall</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Grand">
+        <p>Grand is a set of tools to create a visual representation of Ant target
+          dependencies. It works by taking an Ant build file and creating a "dot" file. It
+          differs from the existing tools by relying on the Ant API rather than XML parsing to
+          get the dependencies. It includes many advanced features such as filtering or
+          rendering depending on the target's nature. Also features a SWT based GUI.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.ggtools.net/grand/">http://www.ggtools.net/grand/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>Christophe Labouisse</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Greebo">
+
+        <p>Greebo is an Ant-task for downloading dependency files
+        (currently only jars) from a network to a specified directory,
+        much like Maven. It supports multiple local and remote
+        repositories with either flat or maven-like structures. It can
+        read the dependency list from a Maven project file, a
+        maven-like dependency file, or directly from the build.xml
+        file.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://greebo.sourceforge.net/">http://greebo.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=73733">project mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="GroboUtils CodeCoverage">
+
+        <p>The CodeCoverage sub-project of GroboUtils provides a 100%
+        pure Java code coverage tool.  It uses pre-execution class file
+        recompilation, and generates XML files containing the coverage
+        statistics.  It does not require any advanced VM setup to generate
+        coverage numbers.
+        </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://groboutils.sourceforge.net/codecoverage/">http://groboutils.sourceforge.net/codecoverage/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=22594">project mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>MIT License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Hammurapi">
+        <p>Java code review tool. Performs automated code
+        review. Contains 111 inspectors which check different aspects
+        of code quality including coding standards, EJB, threading,
+        ...</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with Ant 1.5.x and 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.hammurapi.biz/products/hammurapi">http://www.hammurapi.biz/products/hammurapi</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License (GPL)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="HelpStudioAnt">
+        <p>This task allows for HelpStudio projects to be created via Ant.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.0 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://helpstudioant.sourceforge.net">http://helpstudioant.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+      
+      <subsection name="IDLDepend">
+        <p>idldepend is a task that (re)generates Java sources to be
+        created from CORBA/IDL files.</p>
+
+        <p>It parses the IDL file and determines the Java files that
+        must be generated, taking in account the modifications that
+        can happen due to command line parameters.  If any of the Java
+        files are missing or older than the source IDL specification,
+        it launches the specified compiler.  The compilers of Orbacus,
+        Jacorb, OpenORB, Orbix2k and Sun'JDK distributions are
+        supported.</p>
+
+        <p>To speed up the process and avoid unnecesary re-parsing, it
+        keeps the dependencies in intermediate files.  This task does
+        not launch the javac compiler as well, that is, its output are
+        Java files and not the final bytecode.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 or later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.byteslooser.com/idldepend/">http://www.byteslooser.com/idldepend</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:byteslooser@gmail.com">byteslooser@gmail.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>free source, no license restrictions</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Image">
+        <p>Image task generates and transforms images. It exposes the
+        imaging capability available in Java2D, Java Advanced Imaging,
+        ImageIO, etc., as set of nested elements.</p>
+
+        <p>Image transformations such as &quot;resize&quot;
+        (scale),&quot;overlay&quot; (one image on another),
+        &quot;border&quot; (add a border), &quot;text&quot; (text on
+        image), &quot;crop&quot; (a sub-image of a bigger image),
+        &quot;rotate&quot;, &quot;grayscale&quot; (change a color
+        image to shades of gray).<br/>
+        Now it supports transparency (making images translucent), a
+        bestfit option for Resize, simple support for images within
+        a security-constraint, a preliminary support (if pjatools.jar
+        is available) for saving files as GIF and some other fixes.</p>
+
+        <p>IMPORTANT: You will need the PMIW (Poor Man's Imaging Wrapper) jar
+        for all the operations and the pjatools jar for GIF encoding/ saving
+        support.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a
+                href="http://www.mullassery.com/software/ANT/">http://www.mullassery.com/software/ANT/</a></td>
+          </tr>
+          <tr>
+            <th>pmiw jar</th>
+            <td><a
+                href="http://www.mullassery.com/software/PMIW/">http://www.mullassery.com/software/PMIW/</a>
+                (Poor Man's Imaging Wrapper)</td>
+          </tr>
+          <tr>
+            <th>pjatools jar</th>
+            <td><a
+                href="http://www.eteks.com/pja/en/">http://www.eteks.com/pja/en/</a>
+                (pjatools for GIF encoding support)</td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.mullassery.com">Abey Mullassery</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Importscrubber">
+        <p>Removes unnecessary import statements from a Java source code file.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://importscrubber.sourceforge.net/">http://importscrubber.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:tomcopeland@users.sourceforge.net">Tom Copeland</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="ImTask">
+
+        <p>ImTask is a task to allow one to send an Instant
+        Message. Currently supports yahoo!, AIM, and Jabber</p>
+
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://imtask.sourceforge.net/">http://imtask.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:djallstar@users.sourceforge.net">Jon Madison</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Incanto">
+
+        <p>Ant tasks to provide support for Oracle database tools
+        (such as SQL*Plus, Import, Export)</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://incanto.sourceforge.net/">http://incanto.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:alexrk@users.sourceforge.net">Alexander Karnstedt</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License, Version 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="IsDirValidator">
+
+        <p>Checks whether a given directory structure conforms to
+        certain rules that are defined via nested elements of the
+        task.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://isvalidator.sourceforge.net/en/isDirValidator.htm">http://isvalidator.sourceforge.net/en/isDirValidator.htm</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:news@inigoserrano.com">I&#xF1;igo Serrano</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ivy">
+
+        <p>Ivy is a simple yet powerful dependency manager featuring
+        continuous integration, dependencies of dependencies
+        management, multiple repositories including ibiblio and high
+        performance (use of a local cache).</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.5.1 (1.6.5 or 1.7.0 recommended)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://incubator.apache.org/ivy/">http://incubator.apache.org/ivy/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>ivy-user (at) incubator (dot) apache (dot) org [User Mailinglist]</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="J2ME Ant Tasks">
+
+        <p>There are different sets of tasks to help build <a
+        href="http://java.sun.com/j2me/">Java 2 Platform, Micro
+        Edition</a> (J2ME) applications.</p>
+
+        <subsubsection name="Antenna">
+          <p>Antenna provides a set of Ant tasks suitable for developing
+          wireless Java applications targeted at the Mobile Information
+          Device Profile (MIDP). With Antenna, you can compile,
+          preverify, package, obfuscate, and run your MIDP applications
+          (aka MIDlets), manipulate Java Application Descriptor (JAD)
+          files, as well as convert JAR files to PRC files designed to
+          run on MIDP for Palm OS. Deployment is supported via a
+          deployment task and a corresponding HTTP servlet for
+          Over-the-Air (OTA) provisioning. A small preprocessor allows
+          to generate different variants of a MIDlet from a single
+          source.</p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Ant 1.4.1 or later</td>
+            </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a href="http://antenna.sourceforge.net/">http://antenna.sourceforge.net/</a></td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:joerg@pleumann.de">J&#xF6;rg Pleumann</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>GNU Lesser General Public License</td>
+            </tr>
+          </table>
+        </subsubsection>
+
+        <subsubsection name="Antic">
+          <p>Antic is a freely available task for packaging J2ME
+          applications. It produces both the Jar and Jad files in a
+          single step. This allows *all* entries to be correclty set in
+          the jad file, including the size of the jar file that is
+          produced. This task has been used and tested extensively with
+          Sun's Wireless Toolkit and also the Nokia SDK and
+          emulators.</p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Ant 1.5</td>
+            </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a href="http://www.smartkey.co.uk/tools/antic/antic.html">http://www.smartkey.co.uk/tools/antic/antic.html</a>
+              </td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:support@smartkey.co.uk">smartkey.co.uk</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>GNU General Public License</td>
+            </tr>
+          </table>
+        </subsubsection>
+
+        <subsubsection name="Dave's J2ME Tasks">
+          <p>This set supports CLDC and the K Virtual Machine (KVM):</p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Ant 1.3</td>
+            </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a href="http://www.dribin.org/dave/j2me_ant/">http://www.dribin.org/dave/j2me_ant/</a></td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:drib@enteract.com">Dave Dribin</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>Apache Software License</td>
+            </tr>
+          </table>
+        </subsubsection>
+
+        <subsubsection name="J2ME Polish">
+          <p>J2ME Polish is an Ant-based tool for the creation of
+          MIDP applications. It covers the whole circle of preprocessing, compiling,
+          obfuscation, preverifying, packaging and JAD-creation. J2ME Polish is
+          ideal for creating device optimized applications with its powerful
+          preprocessing capabilities and the integrated device database.
+          With J2ME Polish no hardcoded values are needed and the portability of an
+          application is not sacrificed, even though highly optimized applications are
+          created from a single source.
+          <br/>
+          It contains a logging framework and an optional MIDP-compatible GUI
+          which can be designed using the web-standard CSS. With the J2ME Polish GUI
+          you can even use MIDP/2.0 features on MIDP/1.0 phones.
+          </p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Ant 1.4.1 or later</td>
+            </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a
+              href="http://www.j2mepolish.org/">http://www.j2mepolish.org/</a></td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:j2mepolish@enough.de">Enough Software</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>GNU General Public License; commercial licenses available</td>
+             </tr>
+           </table>
+        </subsubsection>
+
+        <subsubsection name="Stampysoft's J2ME Tasks">
+          <p>And this set works with the J2ME Wireless Toolkit and MIDP
+          for PalmOS:</p>
+
+          <table class="externals">
+            <tr>
+              <th>Compatibility:</th>
+              <td>Ant 1.3</td>
+            </tr>
+            <tr>
+              <th>URL:</th>
+              <td><a href="http://www.stampysoft.com/ant/">http://www.stampysoft.com/ant/</a></td>
+            </tr>
+            <tr>
+              <th>Contact:</th>
+              <td><a href="mailto:jeckels@stampysoft.com">Josh Eckels</a></td>
+            </tr>
+            <tr>
+              <th>License:</th>
+              <td>MIT License</td>
+            </tr>
+          </table>
+        </subsubsection>
+      </subsection>
+
+      <subsection name="Jacson">
+
+        <p>Jacson is a configurable and plugable tool (much like Ant
+        itself) to create filters for text (line based) files without
+        programming.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Jacson has been used and tested with 1.5.1, should
+            work with 1.4+</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jacson.sourceforge.net/">http://jacson.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jacson-user@lists.sourceforge.de">jacson-user@lists.sourceforge.de</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Library or Lesser General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Jalopy">
+
+        <p>An Ant Plug-in for the Java Source Code Formatter
+        Jalopy.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 (or higher)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jalopy.sourceforge.net/">http://jalopy.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://jalopy.sf.net/contact.html">http://jalopy.sf.net/contact.html</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Starting with release 1.0 Beta 6 the license is the
+            BSD License.  Prior releases were under the GNU General
+            Public License.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JarBundler">
+
+        <p>JarBundler is a task that generates Mac OS X native Java
+        Application Bundles.  It is fully configurable and can be used
+        to generate Mac OS X application bundles from any supported
+        Java platform, making it ideal for targeting multiple
+        platforms with one build.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.loomcom.com/jarbundler/">http://www.loomcom.com/jarbundler/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:sethm@loomcom.com">Seth Morabito</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JarPatch">
+
+        <p>JarPatch is a task that generates a zip file resulting of
+        the diff between the content of 2 jar files.</p>
+
+        <p>The resulting diff file can be use as a patch for a
+        previous installation (just ensure that the generated
+        patch.zip file is located on the CLASSPATH before the patched
+        oldJar jar file)</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a
+                href="http://perso.club-internet.fr/sjobic/ant/">http://perso.club-internet.fr/sjobic/ant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:norbert.barbosa@laposte.net">Norbert Barbosa</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Java+ Precompile Task">
+
+        <p>Java+ is an open source Java preprocessor that adds these
+        features to any Java compiler:</p>
+
+        <ul>
+          <li>Multi-line strings with executable inclusions like Perl
+          and Ruby. It eliminates the need for JSP or ASP and their
+          need for Java compilers on deployment servers (a security
+          concern) while adding no overhead in either space or
+          time. </li>
+
+          <li>Optionally supports localization by segregating Java+
+          strings into ResourceBundle files with invarient keys based
+          on the hash code of the strings's value. This is handled
+          automatically and transparently; no intervention is
+          required.</li>
+
+          <li>Fast. Negligible impact on build times. By default,
+          skips inputs whose outputs are up to date to avoid
+          triggering recompilations.</li>
+
+          <li>Pure Java code, portable to any platform, with
+          graphical, shell and ant interfaces.</li>
+
+          <li>Simple, general, recursive, digraph-driven string
+          syntax. Digraph characters are user-selectable.</li>
+        </ul>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://virtualschool.edu/java+/">http://virtualschool.edu/java+/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:bcox@virtualschool.edu">Brad Cox</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD-like License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Java2Html">
+
+        <p>There are two different tools both named Java2HTML that
+        process Java source code and generate syntax highlighted
+        documentation from it.  Both include Ant tasks to run
+        them.</p>
+
+        <p>Java2Html library for converting java source files
+        or snipplets to syntax highlighted html, rtf, tex and
+        others.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.java2html.de/">http://www.java2html.de/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:java2html@jave.de">java2html@jave.de</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+
+        <p>Java2HTML is a simple-to-use tool which converts a bunch of
+        Java Source Code into a colourized and browsable HTML
+        representation.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.5.1 onwards</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.java2html.com/java2html_ant_task.html">http://www.java2html.com/java2html_ant_task.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:support@java2html.com">support@java2html.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>FreeWare</td>
+          </tr>
+        </table>
+
+      </subsection>
+
+      <subsection name="Javamake">
+
+        <p>A task to compile Java sources and manage class file
+        dependencies. Functionality is equivalent to that of standard
+        Javac and Depend tasks combined, with improved dependency
+        checking.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.experimentalstuff.com/Technologies/JavaMake/index.html">http://www.experimentalstuff.com/Technologies/JavaMake/index.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:Mikhail.Dmitriev@eng.sun.com">Mikhail Dmitriev</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD-like License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="javarec">
+
+        <p>Ant tasks that generate record classes for VisualAge for
+        Java from Cobol copy books.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://glezen.org/javarec/">http://glezen.org/javarec/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:pglezen@us.ibm.com">Paul Glezen</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JCSC">
+
+        <p>JCSC is a Java Coding Standard Checker which also features
+        the generation of some code metrics. It is a command line tool
+        with an Ant task to scan whole package trees. The result can
+        viewed in an JavaDoc style web page.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant &gt;= 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jcsc.sourceforge.net/">http://jcsc.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:rjocham72@netscape.net">Ralph Jocham</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Jdiff">
+
+        <p>A task that generates an HTML report of all the packages, classes,
+        constructors, methods, and fields which have been removed, added or
+        changed in any way, including their documentation, when two APIs are
+        compared. </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+            <a href="http://javadiff.sourceforge.net/" >
+            http://javadiff.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Task Documentation:</th>
+            <td>
+            <a
+            href="http://cvs.sourceforge.net/viewcvs.py/*checkout*/javadiff/jdiff/jdiff.html?rev=HEAD&amp;content-type=text/html#JDiffAntTask"
+            >
+            (in CVS)</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JFlex">
+
+        <p>JFlex is a lexical analyzer generator (also known as
+        scanner generator) for Java, written in Java.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jflex.de/">http://jflex.de/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.jflex.de/mailing.html">jflex-users mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License (GPL)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JindentTask">
+
+        <p>JindentTask is a very straightforward wrapping of the
+        Jindent tool, a vendor code beautifier. It enables to use
+        Jindent natively from Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://the.edouard.mercier.free.fr/Jindent_content.php">http://the.edouard.mercier.free.fr/Jindent_content.php</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>Edouard Mercier</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Jing Task">
+
+        <p> Validates XML files against the RELAX NG alternative to XML Schema.
+        The Jing task for Ant allows you to efficiently validate
+        multiple files against multiple RELAX NG patterns and integrate
+        RELAX NG validation with other XML processing.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.thaiopensource.com/relaxng/jing-ant.html">
+            http://www.thaiopensource.com/relaxng/jing-ant.html</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD-like</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="jMetra">
+
+        <p>jMetra is a tool for collecting code metrics across a
+        project lifecycle and compiling the results into
+        JavaDoc-styled documentation to analyze project metrics over
+        time.  jMetra is best utilized by integrating it with your
+        project's scheduled build process.</p>
+
+        <p>It works from the command line or using several provided
+        Ant tasks.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.jmetra.com/">http://www.jmetra.com/</a
+                >
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:tnewton@hypercisioninc.com">R Todd Newton
+              </a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial, free licenses for open source projects and
+            evaluations.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JMX4Ant">
+
+        <p>JMX4Ant provides tasks for integration with JMX (Java Management
+        Extensions). It provides tasks for getting and setting attributes
+        of MBeans, invoking their methods and much more.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://jmx4ant.sourceforge.net/">http://jmx4ant.sourceforge.net/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:bdueck@yahoo.com">Brian Dueck</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License 1.1</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JNI">
+
+        <p>
+
+          JNI is a free toolkit that makes easy work of
+          integrating Java and C through the Java Native
+          Interface (JNI). It includes a code generator that
+          generates both Java "proxy" classes to access C
+          "peer" classes, and C "proxy" classes to access
+          Java "peer" classes or interfaces. It also
+          includes a core library with a simplified JVM
+          interface as well as "helper" classes to ease
+          working with the JNI data types. The code
+          generation is driven by an XML project file that
+          can be created with the assistance of the GUI
+          Project Manager. The code generation can be
+          invoked either from Ant or from the
+          GUI. Includes a comprehensive printable PDF User
+          Guide and plenty of examples.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jnipp.sf.net/">http://jnipp.sf.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:ptrewhella@users.sf.net">Phillip E. Trewhella</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JPP">
+        <p>
+          <a href="http://www.javapreprocessor.com">JPP</a> is a preprocessor for Ant supporting
+          many different file types that allows you to include / exclude contents based on 
+          build-time parameters.  It is completely invisible to other tools and takes the hassle 
+          out of maintaining customised code or content.  It is free, is provided as an Ant task, 
+          and very simple to use.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.javapreprocessor.com">http://www.javapreprocessor.com</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto://info@javapreprocessor.com">info@javapreprocessor.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JReleaseInfo">
+        <p>Sometimes you are interested at runtime to have information
+        from build time. This may be the build date, a build number or
+        the version.  The JReleaseInfo Ant Task generates a java
+        source file with getter methods for any desired and provided
+        properties.  Furthermore, it can automatically generate a
+        viewer (which can e.g.  be used as main-class in a library jar
+        file) that shows the included release information.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jreleaseinfo.sourceforge.net/">HomePage on SourceForge</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a
+                href="http://sourceforge.net/projects/jreleaseinfo/">Forums/Tracker on SourceForge</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JRun Ant Tasks">
+
+        <p>JRun 4 SP1 ships with lib/jrun-ant-tasks.jar, which defines
+        three Ant tasks: jrun, jrunapp, and jrunjmx.  Documentation
+        for the tasks can be found in JRun under
+        docs/ant/jrun.html.</p>
+
+        <p>Note that the service pack must be installed on top of an
+        existing JRun 4 installation.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://dynamic.macromedia.com/bin/MM/software/trial/hwswrec.jsp?product=jrun_sp">http://dynamic.macromedia.com/bin/MM/software/trial/hwswrec.jsp?product=jrun_sp</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:bdeitte@macromedia.com">Brian Deitte</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JSMin Ant Task">
+
+        <p>The JSMin Ant task can be used for the automated minification of javascript files
+          in your build and deploy processes.</p>
+        <p>JSMin is a filter which removes comments and unnecessary whitespace from javascript
+          files. It typically reduces filesize by half, resulting in faster downloads.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://code.google.com/p/jsmin-ant-task/">http://code.google.com/p/jsmin-ant-task/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:matt_at_matthaynes_dot_net">M. Haynes</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JudoScript Ant Task">
+
+        <p>The &lt;judoscript&gt; task is an easy way to embed JudoScript
+           code in the Ant build script. The tag format is quite simple. You can
+           either embed code directly, or can specify an external JudoScript program
+           file as the <code>src</code> attribute value. Parameters can be specified
+           as the <code>params</code> attribute; this is applicable to both embedded
+           code and external files.
+        </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a
+              href="http://www.judoscript.com/articles/ant.html">http://www.judoscript.com/articles/ant.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:judoscript@hotmail.com">James Jianbo Huang</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Lesser GNU Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Just4log Ant Task">
+
+        <p>Just4log is a ant task to optimize JVM bytecode with regards
+        for Logs ( be it, Log4j, Apache Commons or JDK 1.4 )
+        It depends on apache BCEL for Bytecode engineering.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.2 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://just4log.sourceforge.net">http://just4log.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:lbruand@wanadoo.fr">Lucas Bruand</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License 1.1.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Kanaputs">
+
+        <p>Kanaputs is a parser for java based scripting. It is an
+        interpreter for Java. With Kanaputs you can use Java as an
+        interpreted language: no more compilation, each instruction is
+        executed when you write it.  It is a small programmation
+        language to make script files above Java.</p>
+
+        <p>Kanaputs Ant Task provides a way to add any kind of
+        programmatic features in your Ant script. The code you insert
+        stays OS independent (because Kanaputs uses Java) and is
+        completely integrated with Ant as you can give Ant properties
+        to the Kanaputs code and get back the results in other
+        properties.</p>
+
+        <p>Moreover, as you can invoke any kind of Java code with
+        Kanaputs, you can popup windows from your Ant file to ask the
+        user to do a choice.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.kanaputs.org/">http://www.kanaputs.org/</a> <br/>
+              <a href="http://www.kanaputs.org/ant.html">http://www.kanaputs.org/ant.html</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:kfra@kanaputs.org">kfra@kanaputs.org</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="LaTeX Task">
+
+        <p>Simple Task to use (PDF)LaTeX, BibTeX, Makeindex and GlossTeX to
+        create your documentation.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.2 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.dokutransdata.de/">http://www.dokutransdata.de/</a><br/>
+              <a href="http://www.dokutransdata.de/ant_latex/">http://www.dokutransdata.de/ant_latex/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:jaloma@dokutransdata.de">jaloma@dokutransdata.de</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+        </table>
+      </subsection>
+
+     <subsection name="Macker">
+
+        <p>A build-time architectural testing tool, designed
+        to maintain clean layering / tiering / modularity.
+        Macker works against compiled class files, checking
+        dependencies between classes against a set of
+        pattern-based access rules you specify for your
+        project in an XML rules file.  Macker doesn't presume
+        anything about your architecture -- you write the
+        rules, and Macker keeps you honest about them.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and higher (1.4 untested but may work)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://innig.net/macker/">http://innig.net/macker/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://innig.net/macker/contact.html">Paul Cantrell</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU GPL 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+      
+     <subsection name="MakeRunScript">
+
+        <p>MakeRunScript creates a run script for your application.  Even if you are developing on windows,
+        you can make a run script for *nix and vice versa.  If you've used the built-in java task before, you
+        already know how to use 90% of MakeRunScript.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.7 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/makerunscript/">http://sourceforge.net/projects/makerunscript/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/forum/?group_id=210204">MakeRunScript forums</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache 2.0</td>
+          </tr>
+        </table>
+      </subsection>      
+
+      <subsection name="mtxslt">
+
+        <p>The mtxslt (Multi-XSLT) extends the standard Ant "xslt/style" task
+        to make it easy to use multiple XSLT engines during the same build.
+        This is useful for regression testing of XSLT scripts against several
+        engines.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://mtxslt.sourceforge.net/">http://mtxslt.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:abcoates@theOffice.net">Anthony B. Coates</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="nsd2LaTeX Task">
+
+        <p>Simple Task to use nsd2ltx to build your Nassi-Shneiderman diagrams.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.2 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.dokutransdata.de/">http://www.dokutransdata.de/</a><br/>
+              <a href="http://www.dokutransdata.de/ant_nsd2ltx/">http://www.dokutransdata.de/ant_nsd2ltx/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:jaloma@dokutransdata.de">jaloma@dokutransdata.de</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Nurflugel AntScript Visualizer">
+
+        <p>The Nurflugel AntScript Visualizer takes your build file,
+        finds any imported build files, and shows all relationships
+        between targets, taskdefs, macrodefs, Ant and Antcalls; output
+        options include PDF, SVG, and PNG.  Many options including
+        grouping by build file, inclusion/exclusion of targets,
+        taskdefs, imports, etc.  Installation is via Java WebStart, so
+        you'll always have the freshest version available.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.nurflugel.com/webstart/AntScriptVisualizer/">http://www.nurflugel.com/webstart/AntScriptVisualizer/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>dbullard &lt;at&gt; nurflugel &lt;dot&gt; com (email
+            will receive a challenge to weed out spam)</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Orangevolt Ant Tasks">
+
+        <p>Orangevolt ANT Tasks is a collection of Tasks for Apache
+        Ant.</p>
+
+        <p>The Orangevolt Ant Tasks collections provides a bunch of
+        Appplication Deployment related Tasks from windows specific
+        tasks (registry access, executable generation), *nix specific
+        tasks (kde/gnome shortcut generation) to many useful utility
+        tasks like jnlp generation.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 or above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/ovanttasks">http://sourceforge.net/projects/ovanttasks</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:info@roxes.com">info@roxes.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License (GPL)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="pack">
+
+        <p>pack is a task to build the smallest possible JAR to link
+        and run one or more classes.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sadun-util.sourceforge.net/pack.html">http://sadun-util.sourceforge.net/pack.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:cristiano@xtractor.com">Cristiano Sadun</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Lesser General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="PCT">
+        <p>PCT is a task to compile Progress code, and in a more general
+        way, to deal with Progress procedures and databases.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://pct.sourceforge.net">http://pct.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:justus_phenix@users.sourceforge.net">Gilles QUERRET</a></td>
+          </tr>
+          <tr>
+            <th>Licence:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="PesterCat Ant Toolkit">
+         <p>PesterCat is a web testing tool that was designed to
+           perform functional testing for web applications. The PesterCat
+           Ant Toolkit contains tasks to playback test scripts and create
+           HTML reports.
+         </p>
+         <table class="externals">
+           <tr>
+             <th>Compatibility:</th>
+             <td>Ant 1.6 and later</td>
+           </tr>
+           <tr>
+             <th>URL:</th>
+             <td><a href="http://www.pestercat.com/">http://www.pestercat.com/</a></td>
+           </tr>
+           <tr>
+             <th>License:</th>
+             <td>Commercial</td>
+           </tr>
+         </table>
+       </subsection>
+
+      <subsection name="PMD">
+
+        <p>PMD checks Java source code for unused variables,
+        unnecessary object creation, etc</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://pmd.sf.net/">http://pmd.sf.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:tcopeland@apache.org">Tom Copeland</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="PRes">
+        <p>PRes is short for Property Resources and will generate a Java source
+           file from name=value pair .property files which can be compiled like any
+           other class.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later (may work with earlier)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://mseries.sourceforge.net">http://mseries.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://web.ukonline.co.uk/mseries/contact.html">MSeries</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="ProGuard">
+        <p><a href="http://proguard.sourceforge.net/">ProGuard</a> is
+        a free Java class file shrinker and obfuscator.  It can detect
+        and remove unused classes, fields, methods, and attributes. It
+        can then rename the remaining classes, fields, and methods
+        using short meaningless names.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with 1.5. Should work with all versions.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://proguard.sourceforge.net/">http://proguard.sourceforge.net/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="http://proguard.sourceforge.net/feedback.html">Feedback Page</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="properties2java">
+
+        <p>Properties2Java is an Ant task for automatic conversion of
+        java ".properties" files to ".java" files extending the
+        java.util.ListResourceBundle.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6 or above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://properties2java.jayefem.de/">http://properties2java.jayefem.de/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:properties2java@jayefem.de">Jan-Friedrich Mutter</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Purge">
+
+        <p>Purge deletes all but the most recent few files from a fileset.
+        For example: if you have generated files (logs, .ear, .war, .jar
+        etc) accumulating in a directory, the purge task will allow you
+        to delete the older files, keeping just the most recent ones.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 or above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.dallaway.com/ant/">http://www.dallaway.com/ant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:purge@dallaway.com">Richard Dallaway</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="RefactorIT">
+
+        <p>RefactorIT includes an Ant task for metrics and audits.
+        RefactorIT is a Java refactoring, audit and metrics tool.
+        It plugs into major Java IDEs, also runs stand-alone with
+        a GUI and a command line interface.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.refactorit.com/">http://www.refactorit.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:support@refactorit.com">support@refactorit.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial. (Free for accredited open source products, see
+            <a href="http://www.refactorit.com/osc">http://www.refactorit.com/osc</a>.)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Reflectant Task">
+
+        <p>This is a task for reflection invocation from within ant build file.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 or above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/reflectant/">http://sourceforge.net/projects/reflectant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:sv_ant@mail.bg">sv_ant@mail.bg</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>The Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="rundoc">
+        <p>A task designed to help with the single-sourcing of program
+        documentation. Rundoc replaces special commands
+        (in the format <i>@@rundoc:command param1 param2...@@</i>) embedded
+        within text files with their output in a
+        specified format. Currently, only Docbook format is supported.</p>
+
+        <p>Rundoc was written to keep sample code output in program
+        documentation synchronized with the actual output
+        of the current code, by running the referenced code when the
+        documentation is built.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with 1.6  Should work with all versions.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.martiansoftware.com/lab/index.html#rundoc">http://www.martiansoftware.com/lab/index.html#rundoc</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Revised BSD</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="SerialVer">
+
+        <p>SerialVer adds the Java serialver functionality to Apache
+        Ant.  This project adds Tasks and FilterReaders to get, to
+        insert and to modify the serialVersionUID in the source code
+        of a serializable class.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://serialver.sourceforge.net/">http://serialver.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="https://lists.sourceforge.net/lists/listinfo/serialver-development">developer mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Simian">
+
+        <p>Simian (Similarity Analyser) identifies duplication in Java,
+        C#, C, CPP, COBOL, JSP, HTML source code and even plain text files.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.redhillconsulting.com.au/products/simian/">
+            http://www.redhillconsulting.com.au/products/simian/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:simian-user-subscribe@redhillconsulting.com.au">
+            simian-user-subscribe@redhillconsulting.com.au (User Mailinglist)
+            </a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial, Free Licenses available for Non-Commercial Projects</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="SmartAnalyzer">
+
+        <p>Powerful analysis of dependencies between Java classes.
+        Only affected classes will be recompiled and it can be used
+        with any bytecode compiler.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Apache Ant version 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://smartanalyzer.sourceforge.net/">http://smartanalyzer.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/projects/smartanalyzer">support at sourceforge project page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public Licence (GPL)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="snip">
+        <p>A task designed to help with the single-sourcing of program documentation.
+        Snip extracts snippets of text from files, placing them into properties in the Ant project.
+        These properties can then be used by any other Ant task, and are particularly useful when
+        referenced by &lt;filter&gt;s within the &lt;copy&gt; task.</p>
+
+        <p>Snip was originally written to keep snippets of sample code in API documentation synchronized
+        with the actual sample classes.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with 1.5.1.  Should work with all versions.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.martiansoftware.com/lab/index.html#snip">http://www.martiansoftware.com/lab/index.html#snip</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.martiansoftware.com/contact.html">Marty Lamb</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Revised BSD</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="spell">
+        <p>Spell Check checks the spelling of all files in a directory. Code is broken into
+        single words and compared to a dictionary. If the words are not in the dictionary
+        they are written to a file.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td> <!-- JHM: asked Rob for that; he'll ping me if he is back at home --> </td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://robmayhew.com/antspell/antspelltask.html">http://robmayhew.com/antspell/antspelltask.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.robmayhew.com/">Rob Mayhew</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td> <!-- same as above --> </td>
+          </tr>
+        </table>
+      </subsection>
+      
+      <subsection name="SQL Compiler (SQLC)">
+        <p>SQL Compiler (SQLC) compiles database metadata and SQL statements into data access and data transfer classes.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with Ant 1.5.4 and 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.hammurapi.biz/products/sqlc">http://www.hammurapi.biz/products/sqlc</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="SQLUnit">
+         <p>SQLUnit is a regression and unit testing harness for testing
+         database stored procedures. The test suite is written as an XML file.
+         The SQLUnit harness itself is written in Java and uses the JUnit unit
+         testing framework to convert the XML test specifications to JDBC calls
+         and compare the results generated from the calls with the specified
+         results. It also provides the &lt;sqlunit&gt; task to run the tests
+         from a build script.</p>
+         <table class="externals">
+           <tr>
+             <th>Compatibility:</th>
+             <td>Tested with Ant 1.6</td>
+           </tr>
+           <tr>
+             <th>URL:</th>
+             <td><a href="http://sqlunit.sourceforge.net">http://sqlunit.sourceforge.net</a></td>
+           </tr>
+           <tr>
+             <th>Contact:</th>
+             <td><a href="http://sourceforge.net/forum/?group_id=77832">Project forums</a></td>
+           </tr>
+           <tr>
+             <th>License:</th>
+             <td>GNU General Public License (GPL)</td>
+           </tr>
+         </table>
+       </subsection>
+
+      <subsection name="Styler">
+
+        <p>The styler task makes useful combinations of XSLT transformations
+        easy to specify in an Ant build file. Like the built-in Ant task
+        style, styler can apply a single transformation to a set of XML files.
+        But it can also:</p>
+        <ul>
+          <li>handle multiple transformations, in parallel or pipelined.</li>
+          <li>enable transformations that split or merge files</li>
+          <li>process non-XML files, especially HTML (based on JTidy)</li>
+          <li>apply non-XSLT transformation, especially "regular
+          fragmentations"</li>
+          <li>use any custom XMLReader or XMLFilter class to handle new file
+          formats and transformation techniques.</li>
+        </ul>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.langdale.com.au/styler/">http://www.langdale.com.au/styler/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:adv@langdale.com.au">Arnold deVos</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Syntax">
+
+        <p>Transforms source files into HTML documents with syntax
+        highlighting. It can handle a variety of source files
+        including Java, HTML, C/C++, SQL, and Java properties.  Colors
+        for elements are specified using cascading style sheets.  The
+        output can be templated for easy integration with a site's
+        look and feel.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ostermiller.org/syntax/ant.html">http://ostermiller.org/syntax/ant.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://ostermiller.org/contact.pl?regarding=Syntax+Highlighting">Stephen Ostermiller</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License (GPL)</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="TestSetGenerator">
+
+        <p>The TestSetGenerator is an ant task for generating property files with
+        testsets based on the results of SQL queries and validation plug-ins. Very
+        usefull when building unit tests that make use of changing datasets. This
+        task is an extension of the Ant SQL task. Hsqldb is used for both the
+        examples and the unittests.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>ANT 1.4 (or later)</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://anttestsetgen.sourceforge.net/">http://anttestsetgen.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:m.c.jansen@planet.nl">m.c.jansen@planet.nl</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Tidy Imports (Tim)">
+
+        <p>Tim is a handy utility that can be executed on the command
+        line or via Ant that automatically formats your import
+        declarations. Tim is capable of removing unused imports,
+        expanding or collapsing imports and even organising them into
+        pre-determined groups.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.chive.com/tim.htm">http://www.chive.com/tim.htm</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:support@chive.com">support@chive.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="TiniAnt">
+
+        <p>TiniAnt is an Ant task to support building applications for
+        the <a href="http://www.ibutton.com/TINI/">TINI</a>.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 to 1.4.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://tiniant.sourceforge.net/">http://tiniant.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:kelly@ad1440.net">Sean Kelly</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD-like license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Transformica">
+        <p>Transformica is a versatile and extensible code generator.
+           Supports multiple source models including database metadata, Java source files, grammar
+           files and custom models.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with Ant 1.5.x and 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.hammurapi.biz/products/transformica">http://www.hammurapi.biz/products/transformica</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/contact.html">Project Contact Page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Venus Application Publisher's (Vamp) Ant Task Suite">
+
+        <p>Venus Application Publisher's (Vamp) Ant Task Suite allows
+        you to sign and package your applications into relocatable Web
+        Archives that you can drop into your web server for
+        single-click launching using Java Web Start or into single
+        Java Archive installers that serve up their content through a
+        built-in, multi-threaded, ultra light-weight web server.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and 1.3</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.geocities.com/vamp201/ant.html">http://www.geocities.com/vamp201/ant.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:vamp201@yahoo.com">Gerald Bauer</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Version_Tool">
+        <p>A versioning tool for Ant.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ant.ryangrier.com/">http://ant.ryangrier.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:version_tool@ryangrier.com">version_tool@ryangrier.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="VPP">
+
+        <p>VPP provides general file preprocessing support based on
+        the Velocity Template Engine.  The core functionality is
+        provided as a filter for use with tasks that supports filter
+        chains.  Also included are replacement tasks for &lt;copy&gt; and
+        &lt;javac&gt; that integrate support for preprocessing.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.5.1 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://vpp.sourceforge.net/">http://vpp.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:vpp-user@lists.sourceforge.net">vpp-user@lists.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="WOProject">
+
+        <p>WOProject provides a set of tools to work with
+        <a href="http://webobjects.com/">WebObjects 5.1</a>
+        independent from platform and IDE. It significantly
+        improves developer productivity
+        and makes complex project structures more flexible compared to
+        traditional Makefile-based approach.
+        </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://objectstyle.org/woproject/">http://objectstyle.org/woproject/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:andrus@objectstyle.org">Andrus Adamchik</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="WSDLValidate">
+        <p>WSDLValidate is, as it sounds, a tool to validate WSDL files.
+        <a href="http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/wsvt-home/docs/articles/wsdl20Validator/wsdlvalidateant.html">WSDLValidate</a>
+        is similar in configuration to the optional Ant task <a href="http://ant.apache.org/manual/OptionalTasks/xmlvalidate.html">XMLValidate</a>.
+        WSDLValidate can optionally validate a WSDL document against the <a href="http://www.ws-i.org">WS-I Basic Profile</a>.
+        </p>
+        <p>WSDLValidate is available as an Ant task, an Eclipse plug-in and a
+        command line utility.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 or later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.eclipse.org/wsvt">http://www.eclipse.org/wsvt</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.eclipse.org/wsvt">Project newsgroup and
+            mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td><a href="http://www-124.ibm.com/developerworks/oss/CPLv1.0.htm">Common Public
+            License (CPL)</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Xcluder">
+        <p>xcluder is an XML Inclusions (XInclude) task for Apache Ant.
+        Offers the choice of using Xerces or Elliotte Rusty Harold's XOM API.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 or later. XInclude compliance depends on the
+            underlying Xerces or XOM used. Xerces 2.5.0 and above works fine,
+            but please note that 2.6.1 and 2.6.2 processed the
+            http://www.w3.org/2003/XInclude, now obsolete by
+            http://www.w3.org/2001/XInclude used by the latest
+            Candidate Recommendation (13 April 2004).
+            </td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/xcluder">http://sourceforge.net/projects/xcluder</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:mbatsis@users.sf.net">mbatsis@users.sf.net</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License (GPL), GNU Library or Lesser
+            General Public License (LGPL)
+            </td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="XDoclet">
+
+        <p>XDoclet is an extended Javadoc Doclet engine for use in Ant.
+           It lets you create custom Javadoc @tags and based on those tags
+           generates source code or other files (such as xml-ish deployment
+           descriptors). Templates and matching tasks are provided to generate
+           EJB and web application deployment descriptors.
+           </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/xdoclet/">http://sourceforge.net/projects/xdoclet/</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="XInclude">
+        <p><a href="http://www.jeckle.de/freeStuff/xia/index.html">XInclude</a> is
+          a W3C standardized vocabulary for including arbitrary text or XML
+          documents in other XML documents. This task performes the inclusion
+          using an existing XInclude implementation</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.2</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.jeckle.de/freeStuff/xia/index.html">http://www.jeckle.de/freeStuff/xia/index.html</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:mario@jeckle.de">mario@jeckle.de</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Lesser GNU Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="XML Directory Listing Ant Task">
+
+        <p>The XML Directory Listing task can recurse through a directory structure and produce an 
+        XML representation. The resulting file can then be transformed further with Ant. </p>
+        <p>The XML output is configurable through various options. The SAX parsing is fast and has a 
+        low memory footprint.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5 or higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://code.google.com/p/xml-dir-listing/">http://code.google.com/p/xml-dir-listing/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:matt_at_matthaynes_dot_net">M. Haynes</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License 2.0</td>
+          </tr>
+        </table>      
+	  </subsection>
+
+      <subsection name="XMLReleaseNotes (XRN)">
+
+        <p>This framework is a release notes framework that enables to
+        generate textual release notes from an XML file. This is an
+        open framework that enables to integrate the information
+        coming from VSC and bug tracking solutions, for instance.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://xmlreleasenotes.free.fr/">http://xmlreleasenotes.free.fr/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>Edouard Mercier</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="XmlTask">
+
+        <p>XmlTask provides a simple means to modify XML documents
+        without having to learn XSLT. A simple path reference to an
+        XML node specifies the node you want to change, and how you
+        want to allow XML insertion and removal, or attribute
+        changes. The emphasis is on providing the simplest means to
+        perform common XML replacements</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.oopsconsultancy.com/software/xmltask/">http://www.oopsconsultancy.com/software/xmltask/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:xmltask-users@lists.sourceforge.net">xmltask-users at lists.sourceforge.net</a> </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="yGuard">
+
+        <p>yGuard is a free Java(TM) Bytecode Obfuscator Task that
+        needs no external script or project files. It can completely
+        be configured and run through the Ant build script. The task
+        supports multiple Jar files at once and makes use of
+        patternsets and regular expressions to specify elements, which
+        should be left unobfuscated.  Additionally it can be used to
+        produce patches for obfuscated applications that have already
+        been deployed.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.yworks.com/en/products_yguard_about.htm">http://www.yworks.com/en/products_yguard_about.htm</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:yguard@yworks.com">yGuard@yWorks.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Library: LGPL, Task: Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Zelix KlassMaster">
+
+        <p>The task ZKMTask allows the Zelix KlassMaster Java obfuscator to be integrated into an Ant build.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.zelix.com/klassmaster/docs/buildToolApi.html">http://www.zelix.com/klassmaster/docs/buildToolApi.html</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+    </section>
+
+
+
+    <section name="Build Listeners">
+
+      <subsection name="AntUtility">
+
+        <p>
+          Wondering why your Ant build is slow? Is your continuous integration server taking too 
+          long to produce your project builds? This project may help. This project includes a small 
+          number of classes for use with Ant that can help you to analyze your build in a 
+          non-intrusive manner.
+        </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="https://antutility.dev.java.net/">https://antutility.dev.java.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:dgreen@dev.java.net">David Green</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td><a href="http://www.apache.org/licenses/LICENSE-2.0">Apache Software License</a></td>
+          </tr>
+        </table>
+      </subsection>
+    </section>
+
+
+
+    <section name="Compiler Implementations">
+
+      <subsection name="Generics (JSR14) Early-Access Compiler Adapter">
+
+        <p>This is an Ant compiler-adapter that allows you to use the
+        normal <code>&lt;javac&gt;</code> task plus Sun's early-access
+        compiler to compile Generics-enabled Java code.  (This is only
+        necessary until JDK1.5 is released.)</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.madbean.com/blog/3/">http://www.madbean.com/blog/3/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>Matt Quail &lt;spud[at]madbean[dot]com&gt;</td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Public Domain</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="miniRMI &lt;code&gt;&amp;lt;rmic&amp;gt;&lt;/code&gt; implementation">
+
+        <p>miniRMI is a freeware opensource library that serves as a
+        lightweight replacement for the original java.rmi packages and
+        is suitable especially for applets. Ant 1.4+
+        <code>&lt;rmic&gt;</code> adapter included.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://dione.zcu.cz/~toman40/miniRMI/">http://dione.zcu.cz/~toman40/miniRMI/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:Petr.Toman@pinknet.cz">Petr Toman</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Gnu Lesser Public License</td>
+          </tr>
+        </table>
+
+      </subsection>
+    </section>
+
+    <section name="IDE and Editor Integration">
+
+      <subsection name="AntFarm">
+
+        <p>A plugin that integrates Ant into the jEdit editor.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://plugins.jedit.org/plugins/?AntFarm">http://plugins.jedit.org/plugins/?AntFarm</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jedit-devel@lists.sourceforge.net">jEdit developers mailinglist</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntRunner">
+
+        <p>An OpenTool that integrates Ant into the JBuilder IDE
+        (version 5 and later).</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antrunner.sourceforge.net/">http://antrunner.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:dirk.schnelle@web.de">Dirk Schnelle</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="CAPlex">
+        <p>CA Plex is an architected RAD tool that combines the techniques of
+        model-driven development, code generation and patterns to create
+        business applications for multiple platforms, including Java, .NET and
+        IBM System i. In its 6.0 release, CA Plex includes integrated support
+        for building generated Java code with Ant.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://wiki.plexinfo.net/index.php?title=Customizing_Plex_6.0_ANT_builds">http://wiki.plexinfo.net/index.php?title=Customizing_Plex_6.0_ANT_builds</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.ca.com/us/products/product.aspx?ID=258">http://www.ca.com/us/products/product.aspx?ID=258</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Eclipse">
+
+        <p>Eclipse is a universal tool platform with Ant integration.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>
+              Ant 1.3 and higher <br/>
+              Bundles Ant 1.6.2 as of Eclipse 3.0.1 (tested with Ant 1.5.4 - 1.6.2) <br/>
+              Eclipse 3.2 bundles Ant 1.6.5 <br/>
+              Eclipse 3.3 bundles Ant 1.7.0 
+            </td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.eclipse.org/">http://www.eclipse.org/</a>
+              or
+              <a href="http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ant-home/index.html">
+                http://dev.eclipse.org/viewcvs/index.cgi/~checkout~/platform-ant-home/index.html
+              </a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="news://news.eclipse.org/eclipse.platform">news://news.eclipse.org/eclipse.platform</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Common Public License Version 1.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Gel">
+
+        <p>Java IDE with support for Ant.  Gel is a native Microsoft
+        Windows software.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.gexperts.com/gel.html">http://www.gexperts.com/gel.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://groups.yahoo.com/group/gelide/">Project Mailing List</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+        </table>
+      </subsection>
+
+
+      <subsection name="IntelliJ IDEA 5.0">
+      <p>Java IDE with refactoring support and Ant integration.
+      The IDE has special editing and navigation support for Ant.
+      </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.intellij.com/idea/">http://www.intellij.com/idea/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:support@intellij.com">support@intellij.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial; Academic and OpenSource licenses available.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JBuilder">
+
+        <p>Borland JBuilder
+        comes with built-in Ant support, including build file editing.
+        Some versions come with Ant debugging support.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Bundles Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.codegear.com/en/products/jbuilder">http://www.codegear.com/en/products/jbuilder</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://support.codegear.com/en">http://support.codegear.com/en</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial; Turbo JBuilder 2007 is free.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JDEE">
+
+        <p>The Java Development Environment for Emacs (JDEE) supports
+        Apache Ant as one of three built-in ways to build your
+        applications.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jdee.sunsite.dk/">http://jdee.sunsite.dk/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jde-subscribe@sunsite.auc.dk">JDEE Mailing list.</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="NetBeans">
+
+        <p>A module that integrates Ant into the NetBeans IDE, as well as derivative products such as Sun Java
+        Studio (formerly Forte for Java and Sun ONE Studio) and Sun Java Studio Creator.
+        This IDE uses Ant as its <i>sole</i> means of building applications,
+        with custom tasks and an Ant-aware editor.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles 1.6.5 for NetBeans 5.0 and 5.5; 1.7.0 for NetBeans 6.0</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.netbeans.org/">http://www.netbeans.org/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:nbdev@netbeans.org">nbdev@netbeans.org</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Common Development and Distribution License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Optistic IDX Java IDE">
+        <p>Java IDE with deep Ant integration. IDX is a native Microsoft Windows program.</p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.optistic.com/idx">http://optistic.com/idx</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:support@optistic.com">support@optistic.com</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial; Academic and OpenSource licenses available.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Oracle JDeveloper 10i">
+
+        <p>Java IDE with support for Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.oracle.com/technology/products/jdev/index.html">http://www.oracle.com/technology/products/jdev/index.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://forums.oracle.com/forums/forum.jspa?forumID=83">JDeveloper Forum</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Virtual Ant">
+        <p>
+          Instead of manually creating build scripts in XML, Virtual Ant provides a fully virtual file system
+          where you can run your tasks in real time and see the results. Everything that you do is recorded and
+          turned into an Ant build script.
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>
+              Ant 1.6.5 onwards
+            </td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.placidsystems.com/virtualant/">http://www.placidsystems.com/virtualant/</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td>
+              <a href="mailto:support@placidsystems.com">support@placidsystems.com</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial; OpenSource licenses available too.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="WebSphere Studio Application Developer">
+
+        <p>WSAD features Ant integrate by virtue of being built on the Eclipse tools platform.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.4.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.ibm.com/developerworks/websphere/">http://www.ibm.com/developerworks/websphere/</a></td>
+          </tr>
+          <tr>
+            <th>Article:</th>
+            <td>Using Ant with WebSphere Studio Application Developer<ul>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle1.html">Part 1</a></li>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle2.html">Part 2</a></li>
+              <li><a href="http://www-128.ibm.com/developerworks/websphere/library/techarticles/0203_searle/searle3.html">Part 3</a></li>
+            </ul></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+    </section>
+
+
+
+    <section name="Source Control Systems">
+      <p>There are several integration with SCM systems. Some are
+      <a href="manual/tasksoverview.html#scm">built in</a>. But some are available as
+      external libraries. Here a list of task libraries we are aware of:</p>
+
+
+      <subsection name="clearAntLib">
+
+         <p>This library is a collection of "value-add" Ant tasks for integrating 
+         IBM Rational ClearCase with Apache Ant. The integration makes full use 
+         of the power and capabilities of Ant, with support for nested elements 
+         (such as filesets) and also supports conditions. There are a number of 
+         tasks for creating XML reports on both ClearCase baselines and labels as 
+         well as a task for "staging" ClearCase objects.</p>
+
+         <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.1 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://clearantlib.sourceforge.net/">
+            http://clearantlib.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/forum/?group_id=123764">Forum</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>The Apache Software License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Surround SCM">
+
+         <p>These are tasks that allow users to access Surround SCM
+         functionality from within Ant build scripts.</p>
+
+         <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.seapine.com/scmresources.php#integration">
+            Surround SCM Resource Center</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:support@seapine.com">Seapine Support</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU Lesser General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+    </section>
+
+  </body>
+</document>
diff --git a/trunk/xdocs/faq.xml b/trunk/xdocs/faq.xml
new file mode 100644
index 0000000..ea174fd
--- /dev/null
+++ b/trunk/xdocs/faq.xml
@@ -0,0 +1,1838 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="bodewig@apache.org">Stefan Bodewig</author>
+    <title>Frequently Asked Questions</title>
+  </properties>
+
+  <faqsection title="About this FAQ">
+    <faq id="latest-version">
+      <question>Where do I find the latest version of this
+        document?</question>
+      <answer>
+        <p>The latest version can always be found at Ant&apos;s homepage
+          <a href="http://ant.apache.org/faq.html">http://ant.apache.org/faq.html</a>.</p>
+      </answer>
+    </faq>
+
+    <faq id="adding-faqs">
+      <question>How can I contribute to this FAQ?</question>
+      <answer>
+        <p>The page you are looking it is generated from
+          <a href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/faq.xml">this</a>
+          document.  If you want to add a new question, please submit
+          a patch against this document to one of Ant&apos;s mailing lists;
+          hopefully, the structure is self-explanatory.</p>
+
+        <p>If you don&apos;t know how to create a patch, see the patches
+          section of <a href="http://jakarta.apache.org/site/source.html">this
+          page</a>.</p>
+      </answer>
+    </faq>
+
+    <faq id="creating-faq">
+      <question>How do you create the HTML version of this
+        FAQ?</question>
+
+      <answer>
+        <p>We use
+        <a href="http://jakarta.apache.org/velocity/anakia.html">Anakia</a>
+        to render the HTML version from the original XML file.</p>
+
+        <p>The Velocity stylesheets used to process the XML files can
+        be found in the <code>xdocs/stylesheets</code> subdirectory of
+        Ant&apos;s SVN repository - the build file
+        <code>docs.xml</code> at the top level of the ant SVN
+        module (trunk) is used to drive Anakia.</p>
+
+        <p>This file assumes that you have the
+        <code>jakarta-site2</code> CVS module checked out as well, but
+        if you follow the instruction from Anakia&apos;s homepage, you
+        should get it to work without that.  Just make sure all
+        required jars are in the task&apos;s classpath.</p>
+      </answer>
+    </faq>
+
+  </faqsection>
+
+  <faqsection title="General">
+    <faq id="what-is-ant">
+      <question>What is Apache Ant?</question>
+      <answer>
+        <p> Ant is a Java-based build tool. In theory, it is kind of
+        like Make, without Make&apos;s wrinkles and with the full
+        portability of pure Java code.</p>
+      </answer>
+    </faq>
+
+    <faq id="ant-name">
+      <question>Why do you call it Ant?</question>
+      <answer>
+
+        <p>According to Ant&apos;s original author, James Duncan
+        Davidson, the name is an acronym for &quot;Another Neat
+        Tool&quot;.</p>
+
+        <p>Later explanations go along the lines of &quot;ants
+        do an extremely good job at building things&quot;, or
+        &quot;ants are very small and can carry a weight dozens of times
+        their own&quot; - describing what Ant is intended to
+        be.</p>
+      </answer>
+    </faq>
+
+    <faq id="history">
+      <question>Tell us a little bit about Ant&apos;s history.</question>
+      <answer>
+
+        <p>Initially, Ant was part of the Tomcat code base, when it was
+        donated to the Apache Software Foundation. It was
+        created by James Duncan Davidson, who is also the original
+        author of Tomcat. Ant was there to build Tomcat, nothing
+        else.</p>
+
+        <p>Soon thereafter, several open source Java projects realized
+        that Ant could solve the problems they had with Makefiles.
+        Starting with the projects hosted at Jakarta and the old Java
+        Apache project, Ant spread like a virus and is now the build
+        tool of choice for a lot of projects.</p>
+
+        <p>In January 2000, Ant was moved to a separate CVS module and
+        was promoted to a project of its own, independent of
+        Tomcat, and became Apache Ant.</p>
+
+        <p>The first version of Ant that was exposed to a larger audience
+        was the one that shipped with Tomcat&apos;s 3.1 release on 19 April
+        2000.  This version has later been referred to as Ant
+        0.3.1.</p>
+
+        <p>The first official release of Ant as a stand-alone product was
+        Ant 1.1, released on 19 July 2000.  The complete release
+        history:</p>
+
+        <table>
+          <tr>
+            <th>Ant Version</th>
+            <th>Release Date</th>
+          </tr>
+
+          <tr>
+            <td>1.1</td>
+            <td>19 July 2000</td>
+          </tr>
+
+          <tr>
+            <td>1.2</td>
+            <td>24 October 2000</td>
+          </tr>
+
+          <tr>
+            <td>1.3</td>
+            <td>3 March 2001</td>
+          </tr>
+
+          <tr>
+            <td>1.4</td>
+            <td>3 September 2001</td>
+          </tr>
+
+          <tr>
+            <td>1.4.1</td>
+            <td>11 October 2001</td>
+          </tr>
+
+          <tr>
+            <td>1.5</td>
+            <td>10 July 2002</td>
+          </tr>
+
+          <tr>
+            <td>1.5.1</td>
+            <td>3 October 2002</td>
+          </tr>
+
+          <tr>
+            <td>1.5.2</td>
+            <td>3 March 2003</td>
+          </tr>
+
+          <tr>
+            <td>1.5.3</td>
+            <td>9 April 2003</td>
+          </tr>
+
+          <tr>
+            <td>1.5.4</td>
+            <td>12 August 2003</td>
+          </tr>
+
+          <tr>
+            <td>1.6.0</td>
+            <td>18 December 2003</td>
+          </tr>
+
+          <tr>
+            <td>1.6.1</td>
+            <td>12 February 2004</td>
+          </tr>
+
+          <tr>
+            <td>1.6.2</td>
+            <td>16 July 2004</td>
+          </tr>
+
+          <tr>
+            <td>1.6.3</td>
+            <td>28 April 2005</td>
+          </tr>
+
+          <tr>
+            <td>1.6.4</td>
+            <td>19 May 2005</td>
+          </tr>
+
+          <tr>
+            <td>1.6.5</td>
+            <td>2 June 2005</td>
+          </tr>
+
+          <tr>
+            <td>1.7.0</td>
+            <td>19 December 2006</td>
+          </tr>
+        </table>
+      </answer>
+    </faq>
+
+  </faqsection>
+
+  <faqsection title="Installation">
+    <faq id="no-gnu-tar">
+      <question>I get checksum errors when I try to extract the
+      <code>tar.gz</code> distribution file. Why?</question>
+      <answer>
+        <p>Ant&apos;s distribution contains file names that are longer
+        than 100 characters, which is not supported by the standard
+        tar file format. Several different implementations of tar use
+        different and incompatible ways to work around this
+        restriction.</p>
+
+        <p>Ant&apos;s &lt;tar&gt; task can create tar archives that use
+        the GNU tar extension, and this has been used when putting
+        together the distribution. If you are using a different
+        version of tar (for example, the one shipping with Solaris),
+        you cannot use it to extract the archive.</p>
+
+        <p>The solution is to either install GNU tar, which can be
+        found <a href="http://www.gnu.org/software/tar/tar.html">here</a>,
+        or use the zip archive instead (you can extract it using
+        <code>jar xf</code>).</p>
+      </answer>
+    </faq>
+
+    <faq id="RedHat_ES_3">
+      <question>How do you get ant-1.6.x (or any version later than
+      1.5.2) to work on on RedHat ES 3?</question>
+      <answer>
+        <p>Redhat ES 3.0 comes installed with ant 1.5.2. Even if you
+        have your PATH and ANT_HOME variables set correctly to a later
+        version of ant, you will always be forced to use the
+        preinstalled version.</p>
+
+        <p>To use a later version of ant on this OS you could do the
+        following:</p>
+
+        <source><![CDATA[
+$ ant -version
+Apache Ant version 1.5.2-23 compiled on November 12 2003
+$ su -
+# rpm -e ant ant-libs
+# exit
+$ hash -r
+$ ant -version
+Apache Ant version 1.6.2 compiled on July 16 2004
+]]></source></answer>
+    </faq>
+  </faqsection>
+
+  <faqsection title="How do I ...">
+    <faq id="implement-os-specific-configuration">
+      <question>How do I realize os--specific configurations?</question>
+      <answer>
+        <p>The core idea is using property files which name accords to the
+        os-name. Then simply use the build-in property <tt>os.name</tt>.</p>
+        <p>For better use you should also provide a file with defaul values.
+        But be careful with the correct os-names. For test simply &lt;echo&gt;
+        the ${os.name} on all machines and you can be sure to use the right
+        file names.</p>
+        <source><![CDATA[
+          <property file="${os.name}.properties"/>
+          <property file="default.properties"/>
+]]></source>
+      </answer>
+    </faq>
+
+
+    <faq id="adding-external-tasks">
+      <question>How do I add an external task that I&apos;ve written to the
+      page &quot;External Tools and Tasks&quot;?</question>
+      <answer>
+
+        <p>Join and post a message to the dev or user mailing
+        list (one list is enough), including the following
+        information:</p>
+
+        <ul>
+          <li>the name of the task/tool</li>
+          <li>a short description of the task/tool</li>
+          <li>a Compatibility: entry stating with which version(s) of
+          Ant the tool/task is compatible to</li>
+          <li>a URL: entry linking to the main page of the tool/task</li>
+          <li>a Contact: entry containing the email address or the URL
+          of a webpage for the person or list to contact for issues
+          related to the tool/task.  <strong>Note that we&apos;ll add a
+          link on the page, so any email address added there is not
+          obfuscated and can (and probably will) be abused by robots
+          harvesting websites for addresses to spam.</strong></li>
+          <li>a License: entry containing the type of license for the
+          tool/task</li>
+        </ul>
+
+        <p>The preferred format for this information is a patch to <a
+        href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/external.xml">this</a>
+        document.</p>
+
+        <p>If you have written something bigger than a 'simple plugin' to Ant it
+        may be better to add the link to <a href="projects.html">projects.html</a>.
+        The procedure to add it is the same. The file to patch is <a
+        href="http://svn.apache.org/repos/asf/ant/core/trunk/xdocs/projects.xml">this</a>
+        document. The syntax of that file is the same.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="create-extensions">
+      <question>How do I create new tasks?</question>
+      <answer>
+        <p>Apart from a lot of information on using Ant, the
+        <a href="manual/index.html">Manual</a> also contains information
+        on how to extend Ant with new tasks. This information
+        can be found under &quot;Developing with Ant&quot;.</p>
+
+        <p>Chances are that someone else already created the task you
+        want to create, it may be wise to see
+        <a href="external.html">External Tools and Tasks</a> and
+        <a href="projects.html">Related Projects</a> first.</p>
+      </answer>
+    </faq>
+
+    <faq id="passing-cli-args">
+      <question>How do I pass parameters from the command line to my
+        build file?</question>
+      <answer>
+
+        <p>Use properties. Using <code>ant
+        -D<em>name</em>=<em>value</em></code> lets you define values for
+        properties on the Ant command line. These properties can then be
+        used within your build file as
+        any normal property: <code>${<em>name</em>}</code> will put in
+        <code><em>value</em></code>.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="jikes-switches">
+      <question>How can I use Jikes-specific command-line
+        switches?</question>
+
+      <answer>
+
+        <p>A couple of switches are supported via &quot;magic&quot;
+          properties:</p>
+
+        <table>
+          <tr>
+            <th>switch</th>
+            <th>property</th>
+            <th>default</th>
+          </tr>
+
+          <tr>
+            <td>+E</td>
+            <td>build.compiler.emacs</td>
+            <td>false == not set</td>
+          </tr>
+
+          <tr>
+            <td>+P</td>
+            <td>build.compiler.pedantic</td>
+            <td>false == not set</td>
+          </tr>
+
+          <tr>
+            <td>+F</td>
+            <td>build.compiler.fulldepend</td>
+            <td>false == not set</td>
+          </tr>
+
+          <tr>
+            <td><strong>(Only for Ant &lt; 1.4; replaced by the
+                <code><strong>nowarn</strong></code>
+                attribute of the <code><strong>&lt;javac&gt;</strong></code>
+                task after that.)</strong><br></br>-nowarn</td>
+            <td>build.compiler.warnings</td>
+            <td>true == not set</td>
+          </tr>
+
+        </table>
+
+        <p>With Ant &gt;= 1.5, you can also use nested
+          <code>&lt;compilerarg&gt;</code> elements with the
+          <code>&lt;javac&gt;</code> task.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="shell-redirect-1">
+      <question>How do I include a &lt; character in my command-line arguments?</question>
+      <answer>
+        <p>The short answer is "Use: <code>&amp;lt;</code>".</p>
+
+        <p>The long answer is that this probably won&apos;t do what you
+        want anyway (see <a href="#shell-redirect-2">the next
+        section</a>).</p>
+      </answer>
+    </faq>
+
+    <faq id="shell-redirect-2">
+      <question>How do I redirect standard input or standard output
+        in the <code>&lt;exec&gt;</code> task?</question>
+      <answer>
+        <p>Say you want to redirect the standard output stream of the
+        <code>m4</code> command to write to a file, something
+        like:</p>
+
+        <source><![CDATA[
+shell-prompt> m4 foo.m4 > foo
+]]></source>
+
+        <p>and try to translate it into</p>
+
+        <source><![CDATA[
+<exec executable="m4">
+  <arg value="foo.m4"/>
+  <arg value="&gt;"/>
+  <arg value="foo"/>
+</exec>
+]]></source>
+
+        <p>This will not do what you expect.  The output redirection is
+        performed by your shell, not the command itself, so this
+        should read:</p>
+
+        <source><![CDATA[
+<exec executable="/bin/sh">
+  <arg value="-c" />
+  <arg value="m4 foo.m4 &gt; foo" />
+</exec>
+]]></source>
+
+        <p>Note that you must use the <code>value</code> attribute of
+        <code>&lt;arg&gt;</code> in the last element, in order to have
+        the command passed as a single, quoted argument. Alternatively,
+        you can use:</p>
+        <source><![CDATA[
+<exec executable="/bin/sh">
+  <arg line='-c "m4 foo.m4 &gt; foo"'/>
+</exec>
+]]></source>
+
+        <p>Note the double-quotes nested inside the single-quotes.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="batch-shell-execute">
+      <question>How do I execute a batch file or shell script from Ant?</question>
+      <answer>
+
+        <p>On native Unix systems, you should be able to run shell scripts
+           directly. On systems running a Unix-type shell (for example, Cygwin
+           on Windows) execute the (command) shell instead - <code>cmd</code>
+           for batch files, <code>sh</code> for shell scripts - then pass the
+           batch file or shell script (plus any arguments to the script)
+           as a single command, using the <code>/c</code> or
+           <code>-c</code> switch, respectively. See
+           <a href="#shell-redirect-2">the above section</a>
+           for example <code>&lt;exec&gt;</code> tasks
+           executing <code>sh</code>. For batch files, use something like:</p>
+        <source><![CDATA[
+<exec dir="." executable="cmd" os="Windows NT">
+  <arg line="/c test.bat"/>
+</exec>
+]]></source>
+
+      </answer>
+    </faq>
+
+    <faq id="multi-conditions">
+      <question>I want to execute a particular target only if
+        multiple conditions are true.</question>
+
+      <answer>
+        <p>There are actually several answers to this question.</p>
+
+        <p>If you have only one set and one unset property to test,
+        you can specify both an <code>if</code> and an <code>unless</code>
+        attribute for the target, and they will act as if they
+        are &quot;anded&quot; together.</p>
+
+        <p>If you are using a version of Ant 1.3 or earlier, the
+        way to work with all other cases is to chain targets together
+        to determine the specific state you want to test for.</p>
+
+        <p>To see how this works, assume you have three properties:
+        <code>prop1</code>, <code>prop2</code>, and <code>prop3</code>.
+        You want to test that <code>prop1</code> and <code>prop2</code>
+        are set, and that <code>prop3</code> is not. If the condition
+        holds true you want to echo &quot;yes&quot;.</p>
+
+        <p>Here is the implementation in Ant 1.3 and earlier:</p>
+
+        <source><![CDATA[
+<target name="cond" depends="cond-if"/>
+
+<target name="cond-if" if="prop1">
+  <antcall target="cond-if-2"/>
+</target>
+
+<target name="cond-if-2" if="prop2">
+  <antcall target="cond-if-3"/>
+</target>
+
+<target name="cond-if-3" unless="prop3">
+  <echo message="yes"/>
+</target>
+]]></source>
+
+        <p>Note: <code>&lt;antcall&gt;</code> tasks do <em>not</em> pass
+        property changes back up to the environment they were called
+        from, so you wouldn&apos;t be able to, for example, set a
+        <code>result</code> property in the <code>cond-if-3</code> target,
+        then do
+        <code>&lt;echo message=&quot;result is ${result}&quot;/&gt;</code>
+        in the <code>cond</code> target.</p>
+
+        <p>Starting with Ant 1.4, you can use the
+        <code>&lt;condition&gt;</code> task.</p>
+
+        <source><![CDATA[
+<target name="cond" depends="cond-if,cond-else"/>
+
+<target name="check-cond">
+  <condition property="cond-is-true">
+    <and>
+      <not>
+        <equals arg1="${prop1}" arg2="$${prop1}" />
+      </not>
+      <not>
+        <equals arg1="${prop2}" arg2="$${prop2}" />
+      </not>
+      <equals arg1="${prop3}" arg2="$${prop3}" />
+    </and>
+  </condition>
+</target>
+
+<target name="cond-if" depends="check-cond" if="cond-is-true">
+  <echo message="yes"/>
+</target>
+
+<target name="cond-else" depends="check-cond" unless="cond-is-true">
+  <echo message="no"/>
+</target>
+]]></source>
+
+        <p>This version takes advantage of two things:</p>
+
+        <ul>
+          <li>If a property <code>a</code> has not been set,
+          <code>${a}</code> will evaluate to <code>${a}</code>.</li>
+
+          <li>To get a literal <code>$</code> in Ant, you have to
+          escape it with another <code>$</code> - this will also break
+          the special treatment of the <code>${</code> sequence.</li>
+        </ul>
+
+        <p>Because testing for a literal <code>${property}</code> string
+        isn&apos;t all that readable or easy to understand,
+        post-1.4.1 Ant introduces the <code>&lt;isset&gt;</code> element
+        to the <code>&lt;condition&gt;</code> task.</p>
+
+        <p>Here is the previous example done using
+        <code>&lt;isset&gt;</code>:</p>
+
+        <source><![CDATA[
+<target name="check-cond">
+  <condition property="cond-is-true">
+    <and>
+      <isset property="prop1"/>
+      <isset property="prop2"/>
+      <not>
+        <isset property="prop3"/>
+      </not>
+    </and>
+  </condition>
+</target>
+]]></source>
+
+        <p>The last option is to use a scripting language to set the
+        properties. This can be particularly handy when you need much
+        finer control than the simple conditions shown here but, of
+        course, comes with the overhead of adding JAR files to support
+        the language, to say nothing of the added maintenance in requiring
+        two languages to implement a single system. See the
+        <a href="manual/OptionalTasks/script.html">
+        <code>&lt;script&gt;</code> task documentation</a> for more
+        details.</p>
+      </answer>
+    </faq>
+
+    <faq id="encoding">
+      <question>How can I include national characters like German
+        umlauts in my build file?</question>
+
+      <answer>
+        <p>You need to tell the XML parser which character encoding
+        your build file uses, this is done inside the <a
+        href="http://www.w3.org/TR/2000/REC-xml-20001006#sec-prolog-dtd">XML
+        declaration</a>.</p>
+
+        <p>By default the parser assumes you are using the UTF-8
+        encoding instead of your platform&apos;s default.  For most Western
+        European countries you should set the encoding to
+        <code>ISO-8859-1</code>.  To do so, make the very first line
+        of you build file read like</p>
+
+        <source><![CDATA[
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+]]></source>
+      </answer>
+    </faq>
+
+    <faq id="use-zip-instead-of-jar">
+      <question>How do I use <code>jar</code>&apos;s <code>M</code> switch?
+      I don&apos;t want a MANIFEST.</question>
+
+      <answer>
+        <p>A JAR archive is a ZIP file, so if you don&apos;t want a
+        MANIFEST you can simply use <code>&lt;zip&gt;</code>.</p>
+
+        <p>If your file names contain national characters you should
+        know that Sun&apos;s <code>jar</code> utility like Ant&apos;s
+        <code>&lt;jar&gt;</code> uses UTF-8 to encode their names while
+        <code>&lt;zip&gt;</code> uses your platforms default encoding.
+        Use the encoding attribute of <code>&lt;zip&gt;</code> if
+        necessary.</p>
+      </answer>
+    </faq>
+
+    <faq id="propertyvalue-as-name-for-property">
+      <question>How can I do something like <code>&lt;property name="prop"
+      value="${${anotherprop}}"/&gt;</code> (double expanding the property)?</question>
+
+      <answer>
+        <p>Without any external help you can not.</p>
+        <p>With &lt;script/&gt;, which needs external libraries, you can do</p>
+        <source><![CDATA[
+<script language="javascript">
+    propname = project.getProperty("anotherprop");
+    project.setNewProperty("prop", propname);
+</script>
+]]></source>
+         <p>With AntContrib (external task library) you can do <code>
+         &lt;propertycopy name="prop" from="${anotherprop}"/&gt;</code>.</p>
+         <p>With Ant 1.6 you can simulate the AntContribs &lt;propertycopy&gt;
+         and avoid the need of an external library:</p>
+        <source><![CDATA[
+<macrodef name="propertycopy">
+  <attribute name="name"/>
+  <attribute name="from"/>
+  <sequential>
+    <property name="@{name}" value="${@{from}}"/>
+  </sequential>
+</macrodef>
+]]></source>
+      </answer>
+    </faq>
+
+    <faq id="delete-directory-children-only">
+      <question>How can I delete everything beneath a particular directory,
+    preserving the directory itself?</question>
+      <answer>
+<p>Most users who go down this path have no problem figuring out that
+  <code>&lt;delete includeemptydirs="true" /&gt;</code> will help them.  The
+  seemingly tricky part is preserving the base directory itself,
+  which Ant includes in the directory scan. Fortunately the answer is simple:
+</p>
+        <source><![CDATA[
+<delete includeemptydirs="true">
+  <fileset dir="dirtokeep" includes="**/*" />
+</delete>
+]]></source>
+      </answer>
+    </faq>
+  </faqsection>
+
+  <faqsection title="It doesn&apos;t work (as expected)">
+    <faq id="general-advice">
+      <question>General Advice</question>
+      <answer>
+
+        <p>There are many reasons why Ant doesn&apos;t behave as
+        expected, not all of them are due to Ant bugs.  See our <a
+        href="problems.html">Having Problems?</a> page for hints that
+        may help pinning down the reasons for your problem.</p>
+      </answer>
+    </faq>
+
+    <faq id="always-recompiles">
+      <question>Why does Ant always recompile all my Java files?</question>
+      <answer>
+
+        <p>In order to find out which files should be compiled, Ant
+        compares the timestamps of the source files to those of the
+        resulting <code>.class</code> files.  Opening all source files
+        to find out which package they belong to would be very
+        inefficient. Instead, Ant expects you to place your
+        source files in a directory hierarchy that mirrors your
+        package hierarchy and to point Ant to the root of this
+        directory tree with the <code>srcdir</code> attribute.</p>
+
+        <p>Say you have <code>&lt;javac srcdir=&quot;src&quot;
+        destdir=&quot;dest&quot;/&gt;</code>.  If Ant finds a file
+        <code>src/a/b/C.java</code>, it expects it to be in package
+        <code>a.b</code> so that the resulting <code>.class</code>
+        file is going to be <code>dest/a/b/C.class</code>.</p>
+
+        <p>If your source-tree directory structure does not match your
+        package structure, Ant&apos;s heuristic won&apos;t work, and
+        it will recompile classes that are up-to-date.  Ant is not the
+        only tool that expects a source-tree layout like this.</p>
+
+        <p>If you have Java source files that aren&apos;t declared to
+        be part of any package, you can still use the <code>&lt;javac&gt;</code>
+        task to compile these files correctly - just set the
+        <code>srcdir</code> and <code>destdir</code> attributes to
+        the actual directory the source
+        files live in and the directory the class files should go into,
+        respectively.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="defaultexcludes">
+
+      <question>I&apos;ve used a <code>&lt;delete&gt;</code> task to
+      delete unwanted SourceSafe control files (CVS files, editor
+      backup files, etc.), but it doesn&apos;t seem to work; the files
+      never get deleted. What&apos;s wrong?</question>
+
+      <answer>
+        <p>This is probably happening because, by default, Ant excludes
+        SourceSafe control files (<code>vssver.scc</code>) and certain other
+        files from FileSets.</p>
+
+        <p>Here&apos;s what you probably did:</p>
+
+
+        <source><![CDATA[
+<delete>
+  <fileset dir="${build.src}" includes="**/vssver.scc"/>
+</delete>
+]]></source>
+
+        <p>You need to switch off the default exclusions,
+           and it will work:</p>
+        <source><![CDATA[
+<delete>
+  <fileset dir="${build.src}" includes="**/vssver.scc"
+           defaultexcludes="no"/>
+</delete>
+]]></source>
+
+        <p>For a complete listing of the patterns that are excluded
+        by default, see <a href="manual/dirtasks.html#defaultexcludes">the user
+        manual</a>.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="stop-dependency">
+      <question>I have a target I want to skip if a property is set,
+      so I have <code>unless=&quot;property&quot;</code> as an attribute
+      of the target, but all the targets this target
+      depends on are still executed. Why?</question>
+
+      <answer>
+        <p>The list of dependencies is generated by Ant before any of the
+        targets are run. This allows dependent targets, such as an
+        <code>init</code> target, to set properties that can control the
+               execution of the targets higher in the dependency graph. This
+              is a good thing.</p>
+
+        <p>However, when your dependencies break down the
+        higher-level task
+        into several smaller steps, this behaviour becomes
+        counter-intuitive. There are a couple of solutions available:
+        </p>
+
+        <ol>
+          <li>Put the same condition on each of the dependent targets.</li>
+
+          <li>Execute the steps using <code>&lt;antcall&gt;</code>,
+          instead of specifying them inside the <code>depends</code>
+          attribute.</li>
+        </ol>
+
+      </answer>
+    </faq>
+
+    <faq id="include-order">
+      <question>In my <code>&lt;fileset&gt;</code>, I&apos;ve put in an
+      <code>&lt;exclude&gt;</code> of all files followed by an
+      <code>&lt;include&gt;</code> of just the files I want, but it
+      isn&apos;t giving me any files at all. What&apos;s wrong?
+      </question>
+
+      <answer>
+        <p>The order of the <code>&lt;include&gt;</code> and
+        <code>&lt;exclude&gt;</code> tags within a <code>&lt;fileset&gt;</code>
+        is ignored when the FileSet is created. Instead, all of the
+        <code>&lt;include&gt;</code> elements are processed together,
+        followed by all of the <code>&lt;exclude&gt;</code>
+        elements. This means that the <code>&lt;exclude&gt;</code>
+        elements only apply to the file list produced by the
+        <code>&lt;include&gt;</code> elements.</p>
+
+        <p>To get the files you want, focus on just the
+        <code>&lt;include&gt;</code> patterns that would be necessary
+        to get them. If you find you need to trim the list that the
+        <code>&lt;include&gt;</code> elements produce, then use
+        <code>&lt;exclude&gt;</code> elements.</p>
+      </answer>
+    </faq>
+
+    <faq id="properties-not-trimmed">
+      <question><code>ant</code> failed to build my program via javac
+      even when I put the needed jars in an external
+      <code>build.properties</code> file and reference them by
+      <code>pathelement</code> or <code>classpath refid</code>.</question>
+
+      <answer>
+
+        <p>When <code>ant</code> loads properties from an external
+        file it doesn&apos;t touch the value of properties, trailing blanks
+        will not be trimmed for example.</p>
+
+        <p>If the value represents a file path, like a jar needed to
+        compile, the task which requires the value, javac for example
+        would fail to compile since it can&apos;t find the file due to
+        trailing spaces.</p>
+      </answer>
+    </faq>
+
+    <faq id="winzip-lies">
+      <question>Ant creates WAR files with a lower-case
+        <code>web-inf</code> or JAR files with a lower-case
+        <code>meta-inf</code> directory.</question>
+
+      <answer>
+        <p>No it doesn&apos;t.</p>
+
+        <p>You may have seen these lower-case directory names in
+        WinZIP, but WinZIP is trying to be helpful (and fails).  If
+        WinZIP encounters a filename that is all upper-case, it
+        assumes it has come from an old DOS box and changes the case to
+        all lower-case for you.</p>
+
+        <p>If you extract (or just check) the archive with jar, you
+        will see that the names have the correct case.</p>
+
+        <p>With WinZIP (version 8.1 at least), this can be corrected in the
+        configuration.  In the Options/Configuration menu, in the View tab, General
+        section, check the "Allow all upper case files names" box.  The META-INF and
+        WEB-INF will look correct.</p>
+      </answer>
+    </faq>
+
+    <faq id="NoClassDefFoundError">
+      <question>I installed Ant 1.6.x and now get
+        <code>Exception in thread "main" java.lang.NoClassDefFoundError:
+        </code>
+      </question>
+      <answer>
+        <p>
+          The cause of this is that there is an old version of ant somewhere in the
+          class path or configuration.
+        </p>
+        <p>
+          A version of this problem happens with jars that are in the classpath
+          that include an embedded copy of ant classes.
+          An example of this is some copies of weblogic.jar.
+        </p>
+        <p>
+        One can check if this is the case by doing (on unix/sh):
+        <code><pre>
+        unset CLASSPATH
+        ant -version
+        </pre>
+        </code>
+        </p>
+      </answer>
+    </faq>
+
+    <faq id="InstantiationException">
+      <question>I installed Ant 1.6.x and now get
+        <code>java.lang.InstantiationException: org.apache.tools.ant.Main</code>
+      </question>
+      <answer>
+        <p>
+          The cause of this is that there is an old version of ant somewhere in the
+          class path or configuration.
+        </p>
+        <p>
+          A version of this problem may be seen on some linux systems.
+          Some linux systems (Fedora Core 2 for example), comes with a version
+          of ant pre-installed. There is a configuration file called
+          <code>/etc/ant.conf</code> which if present, the ant shell
+          script will 'dot' include. On Fedora Core 2, the /etc/ant.conf
+          file resets the <code>ANT_HOME</code> environment variable to
+          <code>/usr/share/ant</code>. This causes the problem that
+          an old version of ant (1.5.x in this cause) will be used
+          with a new version of the ant script file.
+        </p>
+        <p>
+          One can check if this is the case by doing
+          <code>ant --noconfig -version</code>.
+        </p>
+      </answer>
+    </faq>
+    <faq id="mangled-manifest">
+      <question>
+        Whenever I use the Ant jar or manifest related tasks, long lines in
+        my manifest are wrapped at 70 characters and the resulting jar does
+        not work in my application server. Why does Ant do this?
+      </question>
+
+      <answer>
+        <p>
+          Ant implements the Java
+          <a href="http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html">Jar
+          file specification</a>. Please refer to the notes section where it
+          discusses the maximum allowable length of a line and the concept of
+          continuation characters.
+        </p>
+
+        <p>
+          If a jar file produced by Ant does not work in your appserver, and
+          that failure is due to the wrapped manifest, then you need
+          to consult your appserver provider, as it is a bug in their
+          appserver. Far more likely, however, is a problem in your
+          specification of your classpath. It is not Ant's wrapping of your
+          classpath that is the problem.
+        </p>
+
+        <p>
+          Do not raise a bug about this issue until you have checked to ensure
+          that the problem is not due to your classpath specification.
+        </p>
+      </answer>
+    </faq>
+
+  </faqsection>
+
+  <faqsection title="Ant and IDEs/Editors">
+    <faq id="integration">
+      <question>Is Ant supported by my IDE/Editor?</question>
+      <answer>
+        <p>See the <a href="external.html#IDE and Editor Integration">section
+        on IDE integration</a> on our External Tools and Tasks page.</p>
+      </answer>
+    </faq>
+
+    <faq id="emacs-mode">
+      <question>Why doesn&apos;t (X)Emacs/vi/MacOS X&apos;s project builder
+      correctly parse the error messages generated by Ant?</question>
+      <answer>
+
+        <p>Ant adds a &quot;banner&quot; with the name of the current
+        task in front of all logging messages - and there are no built-in
+        regular expressions in your editor that would account for
+        this.</p>
+
+        <p>You can disable this banner by invoking Ant with the
+        <code>-emacs</code> switch.  To make Ant autodetect
+        Emacs&apos; compile mode, put this into your
+        <code>.antrc</code> (contributed by Ville Skytt&#228;).</p>
+
+        <source><![CDATA[
+# Detect (X)Emacs compile mode
+if [ "$EMACS" = "t" ] ; then
+  ANT_ARGS="$ANT_ARGS -emacs"
+  ANT_OPTS="$ANT_OPTS -Dbuild.compiler.emacs=true"
+fi
+]]></source>
+
+        <p>Alternatively, you can add the following snippet to your
+        <code>.emacs</code> to make Emacs understand Ant&apos;s
+        output.</p>
+
+        <source><![CDATA[
+(require 'compile)
+(setq compilation-error-regexp-alist
+  (append (list
+     ;; works for jikes
+     '("^\\s-*\\[[^]]*\\]\\s-*\\(.+\\):\\([0-9]+\\):\\([0-9]+\\):[0-9]+:[0-9]+:" 1 2 3)
+     ;; works for javac
+     '("^\\s-*\\[[^]]*\\]\\s-*\\(.+\\):\\([0-9]+\\):" 1 2))
+  compilation-error-regexp-alist))
+]]></source>
+
+        <p>Yet another alternative that preserves most of Ant&apos;s
+        formatting is to pipe Ant&apos;s output through the following Perl
+        script by Dirk-Willem van Gulik:</p>
+
+        <source><![CDATA[
+#!/usr/bin/perl
+#
+# May 2001 dirkx@apache.org - remove any
+# [foo] lines from the output; keeping
+# spacing more or less there.
+#
+$|=1;
+while(<STDIN>) {
+        if (s/^(\s+)\[(\w+)\]//) {
+                if ($2 ne $last) {
+                        print "$1\[$2\]";
+                        $s = ' ' x length($2);
+                } else {
+                        print "$1 $s ";
+                };
+                $last = $2;
+        };
+        print;
+};
+]]></source>
+
+      </answer>
+    </faq>
+  </faqsection>
+
+  <faqsection title="Advanced Issues">
+    <faq id="dtd">
+      <question>Is there a DTD that I can use to validate my build
+      files?</question>
+
+      <answer>
+
+        <p>An incomplete DTD can be created by the
+          <code>&lt;antstructure&gt;</code> task - but this one
+          has a few problems:</p>
+
+          <ul>
+            <li>It doesn&apos;t know about required attributes.  Only
+            manual tweaking of this file can help here.</li>
+
+            <li>It is not complete - if you add new tasks via
+            <code>&lt;taskdef&gt;</code> it won&apos;t know about it.  See
+            <a href="http://www.sdv.fr/pages/casa/html/ant-dtd.en.html">this
+            page</a> by Michel Casabianca for a solution to this
+            problem.  Note that the DTD you can download at this page
+            is based on Ant 0.3.1.</li>
+
+            <li>It may even be an invalid DTD.  As Ant allows tasks
+            writers to define arbitrary elements, name collisions will
+            happen quite frequently - if your version of Ant contains
+            the optional <code>&lt;test&gt;</code> and
+            <code>&lt;junit&gt;</code> tasks, there are two XML
+            elements named <code>test</code> (the task and the nested child
+            element of <code>&lt;junit&gt;</code>) with different attribute
+            lists.  This problem cannot be solved; DTDs don&apos;t give a
+            syntax rich enough to support this.</li>
+          </ul>
+      </answer>
+    </faq>
+
+    <faq id="xml-entity-include">
+      <question>How do I include an XML snippet in my build file?</question>
+      <answer>
+        <p>You can use XML&apos;s way of including external files and let
+        the parser do the job for Ant:</p>
+
+        <source><![CDATA[
+<?xml version="1.0"?>
+
+<!DOCTYPE project [
+       <!ENTITY common SYSTEM "common.xml">
+]>
+
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+    ...
+  </target>
+
+  &common;
+
+  ...
+
+</project>
+]]></source>
+
+        <p>will literally include the contents of <code>common.xml</code> where
+        you&apos;ve placed the <code>&amp;common;</code> entity.</p>
+
+        <p>(The filename <code>common.xml</code> in this example is resolved
+        relative to the containing XML file by the XML parser. You may also use
+        an absolute <code>file:</code> protocol URI.)</p>
+
+        <p>In combination with a DTD, this would look like this:</p>
+
+        <source><![CDATA[
+<!DOCTYPE project PUBLIC "-//ANT//DTD project//EN" "ant.dtd" [
+   <!ENTITY include SYSTEM "header.xml">
+]>
+]]></source>
+
+        <p>Starting with Ant 1.6, there is a new
+        <code>&lt;import&gt;</code> task that can (also) be used to
+        include build file fragments.  Unlike the snippets used with
+        entity includes, the referenced files have to be complete Ant
+        build files, though.</p>
+
+        <p>The example above would become:</p>
+        <source><![CDATA[
+<?xml version="1.0"?>
+<project name="test" default="test" basedir=".">
+
+  <target name="setup">
+    ...
+  </target>
+
+  <import file="./common.xml"/>
+
+  ...
+
+</project>
+]]></source>
+
+        <p>Unlike entity includes, <code>&lt;import&gt;</code> will
+        let you use Ant properties in the file name.</p>
+      </answer>
+    </faq>
+
+    <faq id="mail-logger">
+      <question>How do I send an email with the result of my build
+        process?</question>
+
+      <answer>
+
+        <p>If you are using a nightly build of Ant 1.5 after
+        2001-12-14, you can use the built-in MailLogger:</p>
+
+        <source><![CDATA[
+         ant -logger org.apache.tools.ant.listener.MailLogger
+]]></source>
+
+        <p>See the <a href="http://svn.apache.org/repos/asf/ant/core/trunk/docs/manual/listeners.html">Listeners
+        &amp; Loggers</a> documentation for details on the properties
+        required.</p>
+
+        <p>For older versions of Ant, you can use a custom
+        BuildListener that sends out an email
+        in the buildFinished() method.  Will Glozer
+        &lt;will.glozer@jda.com&gt; has written such a listener based
+        on <a href="http://java.sun.com/products/javamail/">JavaMail</a>.
+        The source is:</p>
+
+        <source><![CDATA[
+import java.io.*;
+import java.util.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import org.apache.tools.ant.*;
+
+/**
+ * A simple listener that waits for a build to finish and sends an email
+ * of the results.  The settings are stored in "monitor.properties" and
+ * are fairly self explanatory.
+ *
+ * @author      Will Glozer
+ * @version     1.05a 09/06/2000
+ */
+public class BuildMonitor implements BuildListener {
+    protected Properties props;
+
+    /**
+     * Create a new BuildMonitor.
+     */
+    public BuildMonitor() throws Exception {
+        props = new Properties();
+        InputStream is = getClass().getResourceAsStream("monitor.properties");
+        props.load(is);
+        is.close();
+    }
+
+    public void buildStarted(BuildEvent e) {
+    }
+
+    /**
+     * Determine the status of the build and the actions to follow, now that
+     * the build has completed.
+     *
+     * @param       e       Event describing the build status.
+     */
+    public void buildFinished(BuildEvent e) {
+        Throwable th = e.getException();
+        String status = (th != null) ? "failed" : "succeeded";
+
+        try {
+            String key = "build." + status;
+            if (props.getProperty(key + ".notify").equalsIgnoreCase("false")) {
+                    return;
+            }
+
+            Session session = Session.getDefaultInstance(props, null);
+
+            MimeMessage message = new MimeMessage(session);
+            message.addRecipients(Message.RecipientType.TO, parseAddresses(
+                props.getProperty(key + ".email.to")));
+            message.setSubject(props.getProperty(key + ".email.subject"));
+
+            BufferedReader br = new BufferedReader(new FileReader(
+                props.getProperty("build.log")));
+            StringWriter sw = new StringWriter();
+
+            String line = br.readLine();
+            while (line != null) {
+                sw.write(line);
+                sw.write("\n");
+                line = br.readLine();
+            }
+            br.close();
+
+            message.setText(sw.toString(), "UTF-8");
+            sw.close();
+
+            Transport transport = session.getTransport();
+            transport.connect();
+            transport.send(message);
+            transport.close();
+        } catch (Exception ex) {
+            System.out.println("BuildMonitor failed to send email!");
+            ex.printStackTrace();
+        }
+    }
+
+    /**
+     * Parse a comma separated list of internet email addresses.
+     *
+     * @param       s       The list of addresses.
+     * @return      Array of Addresses.
+     */
+    protected Address[] parseAddresses(String s) throws Exception {
+        StringTokenizer st = new StringTokenizer(s, ",");
+        Address[] addrs = new Address[st.countTokens()];
+
+        for (int i = 0; i < addrs.length; i++) {
+            addrs[i] = new InternetAddress(st.nextToken());
+        }
+        return addrs;
+    }
+
+    public void messageLogged(BuildEvent e) {
+    }
+
+    public void targetStarted(BuildEvent e) {
+    }
+
+    public void targetFinished(BuildEvent e) {
+    }
+
+    public void taskStarted(BuildEvent e) {
+    }
+
+    public void taskFinished(BuildEvent e) {
+    }
+}
+]]></source>
+
+      <p>With a <code>monitor.properties</code> like this:</p>
+
+        <source><![CDATA[
+# configuration for build monitor
+
+mail.transport.protocol=smtp
+mail.smtp.host=<host>
+mail.from=Will Glozer <will.glozer@jda.com>
+
+build.log=build.log
+
+build.failed.notify=true
+build.failed.email.to=will.glozer@jda.com
+build.failed.email.subject=Nightly build failed!
+
+build.succeeded.notify=true
+build.succeeded.email.to=will.glozer@jda.com
+build.succeeded.email.subject=Nightly build succeeded!
+]]></source>
+
+        <p><code>monitor.properties</code> should be placed right next
+        to your compiled <code>BuildMonitor.class</code>.  To use it,
+        invoke Ant like:</p>
+
+        <source><![CDATA[
+ant -listener BuildMonitor -logfile build.log
+]]></source>
+
+        <p>Make sure that <code>mail.jar</code> from JavaMail and
+        <code>activation.jar</code> from the
+        <a href="http://java.sun.com/products/javabeans/glasgow/jaf.html">Java
+        Beans Activation Framework</a> are in your <code>CLASSPATH</code>.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="listener-properties">
+      <question>How do I get at the properties that Ant was running
+      with from inside BuildListener?</question>
+
+      <answer>
+        <p>You can get at a hashtable with all the properties that Ant
+        has been using through the BuildEvent parameter. For
+        example:</p>
+
+        <source><![CDATA[
+public void buildFinished(BuildEvent e) {
+    Hashtable table = e.getProject().getProperties();
+    String buildpath = (String)table.get("build.path");
+    ...
+}
+]]></source>
+
+        <p>This is more accurate than just reading the same property
+        files that your project does, since it will give the correct
+        results for properties that were specified on the Ant command line.</p>
+      </answer>
+    </faq>
+
+  </faqsection>
+
+  <faqsection title="Known Problems">
+    <faq id="170-requires-junit">
+      <question>Ant 1.7.0 doesn't build from sources without
+        JUnit</question>
+
+      <answer>
+
+        <p>When building Ant 1.7.0 from the source release without
+        junit.jar the build fails with the message "We cannot build
+        the test jar unless JUnit is present".</p>
+
+        <p>With Ant 1.7.0 we've started to add ant-testutil.jar as
+        part of the distribution and this causes a hard dependency on
+        JUnit - at least in version 1.7.0.  Unfortunately the
+        installation docs don't say so.</p>
+
+        <p>There are two workarounds:</p>
+
+        <ol>
+
+          <li>Add junit.jar to your CLASSPATH when building Ant.</li>
+
+          <li>Change Ant's buildfile and remove test-jar from the
+          depends list of the dist-lite target.</li>
+
+        </ol>
+
+      </answer>
+    </faq>
+
+    <faq id="remove-cr">
+      <question>&lt;chmod&gt; or &lt;exec&gt; doesn&apos;t work in Ant
+        1.3 on Unix</question>
+      <answer>
+
+        <p>The <code>antRun</code> script in <code>ANT_HOME/bin</code>
+        has DOS instead of Unix line endings; you must remove the
+        carriage-return characters from this file.  This can be done by
+        using Ant&apos;s <code>&lt;fixcrlf&gt;</code> task
+        or something like:</p>
+
+        <source><![CDATA[
+tr -d '\r' < $ANT_HOME/bin/antRun > /tmp/foo
+mv /tmp/foo $ANT_HOME/bin/antRun
+]]></source>
+      </answer>
+    </faq>
+
+    <faq id="javadoc-cannot-execute">
+      <question>JavaDoc failed: java.io.IOException: javadoc: cannot execute</question>
+      <answer>
+        <p>There is a bug in the Solaris reference implementation of
+        the JDK (see <a href="http://developer.java.sun.com/developer/bugParade/bugs/4230399.html">http://developer.java.sun.com/developer/bugParade/bugs/4230399.html</a>).
+        This also appears to be true under Linux. Moving the JDK to
+        the front of the PATH fixes the problem.</p>
+      </answer>
+    </faq>
+
+    <faq id="delegating-classloader">
+      <question>&lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt;</question>
+
+      <answer>
+        <p>Starting with Ant 1.7.0, &lt;junit&gt; will honor your
+        nested &lt;classpath&gt;.</p>
+
+        <p>These tasks don&apos;t ignore your classpath setting, you
+        are facing a common problem with delegating classloaders.</p>
+
+        <p>This question collects a common type of problem: A task
+        needs an external library and it has a nested classpath
+        element so that you can point it to this external library, but
+        that doesn&apos;t work unless you put the external library
+        into the <code>CLASSPATH</code> or place it in
+        <code>ANT_HOME/lib</code>.</p>
+
+        <p>Some background is necessary before we can discuss
+        solutions for <a href="#delegating-classloader-1.5">Ant
+        1.5.x</a> and <a href="#delegating-classloader-1.6">Ant
+        1.6.x</a>.</p>
+
+        <p>When you specify a nested <code>&lt;classpath&gt;</code> in
+        Ant, Ant creates a new class loader that uses the path you
+        have specified.  It then tries to load additional classes from
+        this classloader.</p>
+
+        <p>In most cases - for example using &lt;style&gt; or
+        &lt;junit&gt; - Ant doesn&apos;t load the external library
+        directly, it is the loaded class that does so.</p>
+
+        <p>In the case of <code>&lt;junit&gt;</code> it is the task
+        implementation itself and in the case of
+        <code>&lt;style&gt;</code> it is the implementation of the
+        <code>org.apache.tools.ant.taskdefs.XSLTLiaison</code>
+        class.</p>
+
+        <p><em>As of Ant 1.7</em> <code>&lt;junit&gt;</code> no longer
+        requires you to have <code>junit.jar</code> in Ant's startup
+        classpath even if <code>ant-junit.jar</code> is present there.</p>
+
+        <p>Ant&apos;s class loader implementation uses Java&apos;s
+        delegation model, see <a
+        href="http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html">http://java.sun.com/products/jdk/1.2/docs/api/java/lang/ClassLoader.html</a>
+        the paragraph</p>
+
+        <blockquote>The <code>ClassLoader</code> class uses a
+        delegation model to search for classes and resources. Each
+        instance of <code>ClassLoader</code> has an associated parent
+        class loader.  When called upon to find a class or resource, a
+        <code>ClassLoader</code> instance will delegate the search for
+        the class or resource to its parent class loader before
+        attempting to find the class or resource itself. The virtual
+        machine&apos;s built-in class loader, called the bootstrap
+        class loader, does not itself have a parent but may serve as
+        the parent of a <code>ClassLoader</code>
+        instance.</blockquote>
+
+        <p>The possible solutions depend on the version of Ant you
+        use, see the next sections.</p>
+      </answer>
+    </faq>
+
+    <faq id="delegating-classloader-1.5">
+      <question>&lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.5.x version</question>
+
+      <answer>
+
+        <p>Please read <a href="#delegating-classloader">the previous
+        entry</a> before you go ahead.</p>
+
+        <p>First of all let&apos;s state that Ant's wrapper script
+        (<code>ant</code> or <code>ant.bat</code>) adds all
+        <code>.jar</code> files from <code>ANT_HOME/lib</code> to
+        <code>CLASSPATH</code>, therefore &quot;in
+        <code>CLASSPATH</code>&quot; shall mean &quot;either in your
+        <code>CLASSPATH</code> environment variable or
+        <code>ANT_HOME/lib</code>&quot; for the rest of this
+        answer.</p>
+
+        <p>The root of the problem is that the class that needs the
+        external library is on the <code>CLASSPATH</code>.</p>
+
+        <p>Let's see what happens when you load the &lt;junit&gt;
+        task.  Ant&apos;s class loader will consult the
+        bootstrap class loader first, which tries to load classes from
+        <code>CLASSPATH</code>.  The bootstrap class loader
+        doesn&apos;t know anything about Ant&apos;s class loader or
+        even the path you have specified.</p>
+
+        <p>If the bootstrap class loader can load the class Ant has
+        asked it to load (which it can if <code>optional.jar</code> is
+        part of <code>CLASSPATH</code>), this class will try to load
+        the external library from <code>CLASSPATH</code> as well - it
+        doesn&apos;t know anything else - and will not find it unless
+        the library is in <code>CLASSPATH</code> as well.</p>
+
+        <p>To solve this, you have two major options:</p>
+
+        <ol>
+          <li>put all external libraries you need in
+          <code>CLASSPATH</code> as well this is not what you want,
+          otherwise you wouldn&apos;t have found this FAQ entry.</li>
+
+          <li>remove the class that loads the external library from
+          the <code>CLASSPATH</code>.</li>
+        </ol>
+
+        <p>The easiest way to do this is to remove
+        <code>optional.jar</code> from <code>ANT_HOME/lib</code>.  If
+        you do so, you will have to <code>&lt;taskdef&gt;</code> all
+        optional tasks and use nested <code>&lt;classpath&gt;</code>
+        elements in the <code>&lt;taskdef&gt;</code> tasks that point
+        to the new location of <code>optional.jar</code>.  Also,
+        don&apos;t forget to add the new location of
+        <code>optional.jar</code> to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code>
+        task.</p>
+
+        <p>If you want to avoid to <code>&lt;taskdef&gt;</code> all
+        optional tasks you need, the only other option is to remove
+        the classes that should not be loaded via the bootstrap class
+        loader from <code>optional.jar</code> and put them into a
+        separate archive. Add this separate archive to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code> task
+        - and make sure the separate archive is not in
+        <code>CLASSPATH</code>.</p>
+
+        <p>In the case of <code>&lt;junit&gt;</code> you&apos;d have
+        to remove all classes that are in the
+        <code>org/apache/tools/ant/taskdefs/optional/junit</code>
+        directory, in the <code>&lt;style&gt;</code> case it is one of
+        the <code>*Liaison</code> classes in
+        <code>org/apache/tools/ant/taskdefs/optional</code>.</p>
+
+        <p>If you use the option to break up <code>optional.jar</code>
+        for <code>&lt;junit&gt;</code> or remove
+        <code>ant-junit.jar</code>, you still have to use a
+        <code>&lt;taskdef&gt;</code> with a nested
+        <code>&lt;classpath&gt;</code> to define the junit task.</p>
+      </answer>
+    </faq>
+
+    <faq id="delegating-classloader-1.6">
+      <question>&lt;style&gt; or &lt;junit&gt; ignores my
+      &lt;classpath&gt; - Ant 1.6.x version</question>
+
+      <answer>
+        <p>Please read <a href="#delegating-classloader">the general
+        entry</a> before you go ahead.</p>
+
+        <p>The wrapper script of Ant 1.6.x no longer adds the contents
+        of <code>ANT_HOME/lib</code> to <code>CLASSPATH</code>,
+        instead Ant will create a classloader on top of the bootstrap
+        classloader - let's call it the coreloader for the rest of
+        this answer - which holds the contents of
+        <code>ANT_HOME/lib</code>.  Ant's core and its tasks will be
+        loaded through this classloader and not the bootstrap
+        classloader.</p>
+
+        <p>This causes some small but notable differences between Ant
+        1.5.x and 1.6.x.  Most importantly, a third-party task that is
+        part of <code>CLASSPATH</code> will no longer work in Ant
+        1.6.x since the task now can't find Ant's classes.  In a sense
+        this is the same problem this entry is about, only
+        <code>ant.jar</code> has become the external library in
+        question now.</p>
+
+        <p>This coreloader also holds the contents of
+        <code>~/.ant/lib</code> and any file or directory that has
+        been specified using Ant's <code>-lib</code> command line
+        argument.</p>
+
+        <p>Let's see what happens when you load the &lt;junit&gt;
+        task.  Ant&apos;s class loader will consult the bootstrap
+        class loader first, which tries to load classes from
+        <code>CLASSPATH</code>.  The bootstrap class loader
+        doesn&apos;t know anything about Ant&apos;s class loader or
+        even the path you have specified.  If it fails to find the
+        class using the bootstrap classloader it will try the
+        coreloader next.  Again, the coreloader doesn't know anything
+        about your path.</p>
+
+        <p>If the coreloader can load the class Ant has asked it to
+        load (which it can if <code>ant-junit.jar</code> is in
+        <code>ANT_HOME/lib</code>), this class will try to load the
+        external library from coreloader as well - it doesn&apos;t
+        know anything else - and will not find it unless the library
+        is in <code>CLASSPATH</code> or the coreloader as well.</p>
+
+        <p>To solve this, you have the following major options:</p>
+
+        <ol>
+          <li>put all external libraries you need in
+          <code>CLASSPATH</code> as well this is not what you want,
+          otherwise you wouldn&apos;t have found this FAQ entry.</li>
+
+          <li>put all external libraries you need in
+          <code>ANT_HOME/lib</code> or <code>.ant/lib</code>.  This
+          probably still isn't what you want, but you might reconsider
+          the <code>.ant/lib</code> option.</li>
+
+          <li>Always start Ant with the <code>-lib</code> command line
+          switch and point to your external libraries (or the
+          directories holding them).</li>
+
+          <li>remove the class that loads the external library from
+          the coreloader.</li>
+        </ol>
+
+        <p>In Ant 1.6 <code>optional.jar</code> has been split into
+        multiple jars, each one containing classes with the same
+        dependencies on external libraries.  You can move the
+        "offending" jar out of <code>ANT_HOME/lib</code>.  For the
+        <code>&lt;junit&gt;</code> task it would be
+        <code>ant-junit.jar</code> and for <code>&lt;style&gt;</code>
+        it would be <code>ant-trax.jar</code>
+        or <code>ant-xslp.jar</code> - 
+        depending on the processor you use.</p>
+
+        <p>If you do so, you will have to <code>&lt;taskdef&gt;</code>
+        all optional tasks that need the external library and use
+        nested <code>&lt;classpath&gt;</code> elements in the
+        <code>&lt;taskdef&gt;</code> tasks that point to the new
+        location of <code>ant-*.jar</code>.  Also, don&apos;t forget
+        to add the new location of <code>ant-*.jar</code> to the
+        <code>&lt;classpath&gt;</code> of your
+        <code>&lt;style&gt;</code> or <code>&lt;junit&gt;</code>
+        task.</p>
+
+        <p>For example</p>
+        <source><![CDATA[
+    <taskdef name="junit"
+            class="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask">
+      <classpath>
+        <pathelement location="HOME-OF/junit.jar"/>
+        <pathelement location="NEW-HOME-OF/ant-junit.jar"/>
+      </classpath>
+    </taskdef>
+]]></source>
+      </answer>
+    </faq>
+
+    <faq id="winxp-jdk14-ant14">
+      <question>When running Ant 1.4 on Windows XP and JDK 1.4, I get
+      various errors when trying to <code>&lt;exec&gt;</code>, fork
+      <code>&lt;java&gt;</code> or access environment
+      variables.</question>
+
+      <answer>
+
+        <p>Ant &lt; 1.5 doesn&apos;t recognize Windows XP as a flavor
+        of Windows that runs <code>CMD.EXE</code> instead of
+        <code>COMMAND.COM</code>.  JDK 1.3 will tell Ant that Windows
+        XP is Windows 2000 so the problem doesn&apos;t show up
+        there.</p>
+
+        <p>Apart from upgrading to Ant 1.5 or better, setting the
+        environment variable <code>ANT_OPTS</code> to
+        <code>-Dos.name=Windows_NT</code> prior to invoking Ant has
+        been confirmed as a workaround.</p>
+      </answer>
+    </faq>
+
+    <faq id="1.5-cygwin-sh">
+      <question>The <code>ant</code> wrapper script of Ant 1.5 fails
+      for Cygwin if <code>ANT_HOME</code> is set to a Windows style
+      path.</question>
+      <answer>
+
+        <p>This problem has been reported only hours after Ant 1.5 has
+        been released, see <a
+        href="http://issues.apache.org/bugzilla/show_bug.cgi?id=10664">Bug
+        10664</a> and all its duplicates.</p>
+
+        <p>A fixed version of the wrapper script can be found <a
+        href="http://ant.apache.org/old-releases/v1.5/errata/">here</a>.
+        Simply replace your script with this version.</p>
+      </answer>
+    </faq>
+
+    <faq id="1.5.2-zip-broken">
+      <question><code>&lt;zip&gt;</code> is broken in Ant 1.5.2.</question>
+      <answer>
+
+        <p>Yes, it is.</p>
+
+        <p>The problem reported by most people - see <a
+        href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17648">Bug
+        17648</a> and all its duplicates - is that Ant creates
+        archives that a partially unreadable by WinZIP.  Luckily
+        <code>jar</code> deals with the archives and so the generated
+        jars/wars/ears will most likely work for you anyway.</p>
+
+        <p>There are additional problems, see bugs <a
+        href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17780">Bug
+        17780</a>, <a
+        href="http://issues.apache.org/bugzilla/show_bug.cgi?id=17871">Bug
+        17871</a> and <a
+        href="http://issues.apache.org/bugzilla/show_bug.cgi?id=18403">Bug
+        18403</a>.  All of them are supposed to be fixed with Ant
+        1.5.3 (and only 18403 should exist in 1.5.3beta1).</p>
+      </answer>
+    </faq>
+
+    <faq id="unknownelement.taskcontainer">
+      <question>
+        Why do my custom task containers see Unknown Elements in Ant 1.6
+        - they worked in Ant 1.5?
+      </question>
+      <answer>
+        <p>
+          The objects added in TaskContainer.addTask(Task task)
+          have changed from  Tasks to UnknownElements.
+        </p>
+        <p>
+          There was a number of valid reasons for this change. But the backward
+          compatibility problems were not noticed until after Ant 1.6.0 was
+          released.
+        </p>
+        <p>
+          Your container class will need to be modified to check if the Task
+          is an UnknownElement and call perform on it to
+          convert it to a Task and to execute it.
+          (see apache.tools.ant.taskdefs.Sequential)
+        </p>
+        <p>
+          If you want to do more processing on the task,
+          you need to use the techniques in apache.tools.ant.taskdefs.Antlib#execute()
+          This does make use of one 1.6 method call (UE#getRealObject()),
+          you need to use UE#getTask() instead - this will
+          return null for non tasks (types like fileset id=x).
+        </p>
+        <p>
+          So.. iterate over the tasks, if they are UEs, convert them to
+          tasks, using UE#maybeConfigure and UE#getTask()
+        </p>
+        <source><![CDATA[
+        for (Iterator i = tasks.iterator(); i.hasNext();) {
+           Task t = (Task) i.next();
+           if (t instanceof UnknownElement) {
+              ((UnknownElement) t).maybeConfigure();
+              t = ((UnknownElement) t).getTask();
+              if (t == null) {
+                  continue;
+              }
+           }
+           // .... original Custom code
+        }
+        ]]></source>
+        <p>
+          This approach should work for ant1.5 and ant1.6.
+        </p>
+      </answer>
+    </faq>
+
+    <faq id="java.exception.stacktrace">
+      <question>
+        The program I run via &lt;java&gt; throws an exception but I
+        can't seem to get the full stack trace.
+      </question>
+      <answer>
+        <p>This is a know bug that has been fixed after the release of
+        Ant 1.6.1.</p>
+
+        <p>As a workaround, run your &lt;java&gt; task with
+        <code>fork="true"</code> and Ant will display the full
+        trace.</p>
+      </answer>
+    </faq>
+
+    <faq id="junit-no-runtime-xml">
+      <question>
+        Using format=&quot;xml&quot;, &lt;junit&gt; fails with a
+        <code>NoClassDefFoundError</code> if forked.
+      </question>
+      <answer>
+
+        <p>The XML formatter needs the <a
+        href="http://www.w3.org/DOM/">DOM classes</a> to work.  If you
+        are using JDK 1.4 or later they are included with your Java
+        Runtime and this problem won't occur.  If you are running JDK
+        1.3 or earlier, the DOM classes have to be on your
+        &lt;junit&gt; task's &lt;classpath&gt;.</p>
+
+        <p>Prior to Ant 1.6.0 Ant would include the DOM classes from
+        the XML parser that is used by Ant itself if you set the
+        includeAntRuntime attribute to true (the default).  With Ant
+        1.6.0 this has been changed as this behavior made it
+        impossible to use a different XML parser in your tests.</p>
+
+        <p>This means that you have to take care of the DOM classes
+        explicitly starting with Ant 1.6.0.  If you don't need to set
+        up a different XML parser for your tests, the easiest solution
+        is to add</p>
+
+        <source><![CDATA[
+<pathelement path="${ant.home}/lib/xml-apis.jar:${ant.home}/lib/xercesImpl.jar"/>
+]]></source>
+
+        <p>to your task's &lt;classpath&gt;.</p>
+
+      </answer>
+    </faq>
+
+    <faq id="xalan-jdk1.5">
+      <question>
+        <code>&lt;junitreport&gt;</code> doesn't work with JDK 1.5 but
+        worked fine with JDK 1.4.
+      </question>
+      <answer>
+
+        <p>While JDK 1.4.x contains a version of Xalan-J 2, JDK 1.5
+        (and later?) have <a
+        href="http://java.sun.com/j2se/1.5.0/compatibility.html#4959783">moved
+        to XSLTC</a>.  Since this task uses Xalan's redirect
+        extensions for its internal stylesheet, Ant prior to 1.6.2 didn't support
+        XSLTC.  This means that you have to install <a
+        href="http://xml.apache.org/xalan-j/">Xalan-J 2</a> in order
+        to use this task with JDK 1.5 in older versions of Ant.</p>
+
+        <p>Starting with Ant 1.6.2 <code>&lt;junitreport&gt;</code>
+        supports JDK 1.5.</p>
+
+      </answer>
+    </faq>
+  </faqsection>
+
+</document>
diff --git a/trunk/xdocs/index.xml b/trunk/xdocs/index.xml
new file mode 100644
index 0000000..1f0cd92
--- /dev/null
+++ b/trunk/xdocs/index.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="">Conor MacNeill</author>
+    <author email="stefan.bodewig@freenet.de">Stefan Bodewig</author>
+    <title>Welcome</title>
+  </properties>
+
+<body>
+  <section name="Apache Ivy is an Ant Sub-Project Now!">
+    <h3>October 11, 2007 - Apache Ivy is an Ant Sub-Project Now!</h3>
+
+    <p>Apache Ivy, "A Java based tool for tracking, resolving and
+    managing project dependencies.", just finished <a
+    href="http://incubator.apache.org/">Incubation</a> and has joined
+    the Ant project.  More information will be available from the Ant
+    site soon.</p>
+
+    <p>Until we've finished the migration, you can learn more about
+    Ivy from its <a href="http://incubator.apache.org/ivy/">Incubator
+    website</a>.</p>
+  </section>
+
+   <section name="Ant 1.7.0">
+    <h3>December 19, 2006 - Ant 1.7.0 Available</h3>
+    <p>Apache Ant 1.7.0 is now available for <a
+    href="http://ant.apache.org/bindownload.cgi">download</a>.</p>
+
+    <p>Ant 1.7 introduces a resource framework. Some of the core ant 
+    tasks such as &lt;copy/&gt; are now able to process not only file 
+    system resources but also zip entries, tar entries, paths, ... 
+    Resource collections group resources, and can be further 
+    combined with operators such as union and intersection. This 
+    can be extended by custom resources and custom tasks using resources.</p>
+
+    <p>
+    Ant 1.7 starts outsourcing of optional tasks to Antlibs. 
+    The .NET antlib in preparation will replace the .NET optional tasks which ship in Ant.
+    Support for the version control system Subversion will be only provided as an antlib to
+    be released shortly. 
+    </p>
+
+    <p>Ant 1.7 fixes also a large number of bugs.</p>
+
+    <p>Ant 1.7 has some initial support for Java6 features.</p>
+  </section>
+
+  <section name="AntUnit 1.0">
+    <h3>January 8, 2007 - Apache AntUnit 1.0 Available</h3>
+    <p>Apache AntUnit 1.0 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains tasks to test Ant tasks using Ant
+    instead of JUnit.  For more information see the <a
+    href="antlibs/antunit/">AntUnit home page</a>.</p>
+  </section>
+
+  <section name=".NET Ant Library 1.0">
+    <h3>November 6, 2006 - Apache .NET Ant Library 1.0 Available</h3>
+    <p>Apache .NET Ant Library 1.0 is now available for <a
+    href="http://ant.apache.org/antlibs/bindownload.cgi">download</a>.</p>
+
+    <p>This Ant Library contains support for tools like NUnit as well
+    as the "old .NET tasks of Ant's core.  It has been tested
+    Microsoft's frameworks as well as Mono.</p>
+
+    <p>For more information see the <a href="antlibs/dotnet/">Antlib's
+    home page</a></p>
+  </section>
+
+  <section name="Apache Ant">
+
+<p>
+Apache Ant is a Java-based build tool. In theory, it is kind of like
+Make, but without Make's wrinkles.
+</p>
+
+<p>
+Why another build tool when there is already <em>make</em>, <em>gnumake</em>,
+<em>nmake</em>, <em>jam</em>, and
+others? Because all those tools have limitations that Ant's original author
+couldn't live with when developing software across multiple platforms. Make-like
+tools are inherently shell-based -- they evaluate a set of dependencies, then
+execute commands not unlike what you would issue in a shell. This means that you
+can easily extend these tools by using or writing any program for the OS that
+you are working on. However, this also means that you limit yourself to the OS,
+or at least the OS type such as Unix, that you are working on.
+</p>
+
+<p>
+Makefiles are inherently evil as well. Anybody who has worked on them for any
+time has run into the dreaded tab problem. &quot;Is my command not executing
+because I have a space in front of my tab!!!&quot; said the original author of
+Ant way too many times. Tools like Jam took care of this to a great degree, but
+still have yet another format to use and remember.
+</p>
+
+<p>
+Ant is different. Instead of a model where it is extended with shell-based
+commands, Ant is extended using Java classes. Instead of writing shell commands,
+the configuration files are XML-based, calling out a target tree where various
+tasks get executed. Each task is run by an object that implements a particular
+Task interface.
+</p>
+
+<p>
+Granted, this removes some of the expressive power that is inherent by being
+able to construct a shell command such as
+<code>`find . -name foo -exec rm {}`</code>, but it
+gives you the ability to be cross platform -- to work anywhere and everywhere.
+And hey, if you really need to execute a shell command, Ant has an
+<code>&lt;exec&gt;</code> task that
+allows different commands to be executed based on the OS that it is executing
+on.
+</p>
+
+  </section>
+
+  <section name="Documentation">
+
+<p>
+You can view the documentation for the current release (Apache Ant 1.7.0)
+<a href="manual/index.html">online</a>
+</p>
+
+<p>
+Comprehensive documentation is included in the source and binary distributions.
+</p>
+
+  </section>
+
+  <!--section name="Nightly Builds">
+    <p>
+    If you wish to use the latest Ant features, you can try downloading a nightly
+    build from <a href="http://brutus.apache.org/~nightlybuild/builds/ant/">here</a>
+    </p>
+
+  </section-->
+
+  <section name="Get Involved">
+<ul>
+<li><a href="http://jakarta.apache.org/getinvolved/getinvolvedindex.html">Get Involved</a></li>
+<li><a href="mail.html">Join Mailing Lists</a></li>
+<li><a href="http://marc.theaimsgroup.com/?l=ant-dev&amp;r=1&amp;w=2">Search the Dev Mailing List</a>
+</li>
+<li><a href="http://marc.theaimsgroup.com/?l=ant-user&amp;r=1&amp;w=2">Search the User Mailing List</a>
+</li>
+</ul>
+
+
+
+  </section>
+
+</body>
+</document>
+
diff --git a/trunk/xdocs/legal.xml b/trunk/xdocs/legal.xml
new file mode 100644
index 0000000..ca34677
--- /dev/null
+++ b/trunk/xdocs/legal.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+  
+  <properties>
+    <author email="jon@latchkey.com">Jon S. Stevens</author>
+    <title>Legal</title>
+  </properties>
+  
+  <body>
+    
+    <section name="Legal Stuff They Make Us Say">
+
+      <p>All material on this website is Copyright &#169; 1999-2008,
+      The Apache Software Foundation.</p>
+
+      <p>Sun, Sun Microsystems, Solaris, Java, JavaServer Web
+      Development Kit, and JavaServer Pages are trademarks or
+      registered trademarks of Sun Microsystems, Inc. UNIX is a
+      registered trademark in the United States and other countries,
+      exclusively licensed through X/Open Company, Ltd.  Windows,
+      WindowsNT, and Win32 are registered trademarks of Microsoft
+      Corp. All other product names mentioned herein and throughout
+      the entire web site are trademarks of their respective
+      owners.</p>
+
+    </section>
+
+  </body>
+</document>
+
diff --git a/trunk/xdocs/license.xml b/trunk/xdocs/license.xml
new file mode 100644
index 0000000..e9bcaf2
--- /dev/null
+++ b/trunk/xdocs/license.xml
@@ -0,0 +1,314 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>License</title>
+    <author email="">The Apache Software Foundation</author>
+  </properties>
+
+<body>
+
+  <section name="The Apache Software License Version 2.0">
+    <p>The Apache Software License Version 2.0 applies 
+    to all releases of Ant starting with ant 1.6.1</p>
+
+    <source>/*
+ *                                 Apache License
+ *                           Version 2.0, January 2004
+ *                        http://www.apache.org/licenses/
+ *
+ *   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+ *
+ *   1. Definitions.
+ *
+ *      "License" shall mean the terms and conditions for use, reproduction,
+ *      and distribution as defined by Sections 1 through 9 of this document.
+ *
+ *      "Licensor" shall mean the copyright owner or entity authorized by
+ *      the copyright owner that is granting the License.
+ *
+ *      "Legal Entity" shall mean the union of the acting entity and all
+ *      other entities that control, are controlled by, or are under common
+ *      control with that entity. For the purposes of this definition,
+ *      "control" means (i) the power, direct or indirect, to cause the
+ *      direction or management of such entity, whether by contract or
+ *      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ *      outstanding shares, or (iii) beneficial ownership of such entity.
+ *
+ *      "You" (or "Your") shall mean an individual or Legal Entity
+ *      exercising permissions granted by this License.
+ *
+ *      "Source" form shall mean the preferred form for making modifications,
+ *      including but not limited to software source code, documentation
+ *      source, and configuration files.
+ *
+ *      "Object" form shall mean any form resulting from mechanical
+ *      transformation or translation of a Source form, including but
+ *      not limited to compiled object code, generated documentation,
+ *      and conversions to other media types.
+ *
+ *      "Work" shall mean the work of authorship, whether in Source or
+ *      Object form, made available under the License, as indicated by a
+ *      copyright notice that is included in or attached to the work
+ *      (an example is provided in the Appendix below).
+ *
+ *      "Derivative Works" shall mean any work, whether in Source or Object
+ *      form, that is based on (or derived from) the Work and for which the
+ *      editorial revisions, annotations, elaborations, or other modifications
+ *      represent, as a whole, an original work of authorship. For the purposes
+ *      of this License, Derivative Works shall not include works that remain
+ *      separable from, or merely link (or bind by name) to the interfaces of,
+ *      the Work and Derivative Works thereof.
+ *
+ *      "Contribution" shall mean any work of authorship, including
+ *      the original version of the Work and any modifications or additions
+ *      to that Work or Derivative Works thereof, that is intentionally
+ *      submitted to Licensor for inclusion in the Work by the copyright owner
+ *      or by an individual or Legal Entity authorized to submit on behalf of
+ *      the copyright owner. For the purposes of this definition, "submitted"
+ *      means any form of electronic, verbal, or written communication sent
+ *      to the Licensor or its representatives, including but not limited to
+ *      communication on electronic mailing lists, source code control systems,
+ *      and issue tracking systems that are managed by, or on behalf of, the
+ *      Licensor for the purpose of discussing and improving the Work, but
+ *      excluding communication that is conspicuously marked or otherwise
+ *      designated in writing by the copyright owner as "Not a Contribution."
+ *
+ *      "Contributor" shall mean Licensor and any individual or Legal Entity
+ *      on behalf of whom a Contribution has been received by Licensor and
+ *      subsequently incorporated within the Work.
+ *
+ *   2. Grant of Copyright License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      copyright license to reproduce, prepare Derivative Works of,
+ *      publicly display, publicly perform, sublicense, and distribute the
+ *      Work and such Derivative Works in Source or Object form.
+ *
+ *   3. Grant of Patent License. Subject to the terms and conditions of
+ *      this License, each Contributor hereby grants to You a perpetual,
+ *      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ *      (except as stated in this section) patent license to make, have made,
+ *      use, offer to sell, sell, import, and otherwise transfer the Work,
+ *      where such license applies only to those patent claims licensable
+ *      by such Contributor that are necessarily infringed by their
+ *      Contribution(s) alone or by combination of their Contribution(s)
+ *      with the Work to which such Contribution(s) was submitted. If You
+ *      institute patent litigation against any entity (including a
+ *      cross-claim or counterclaim in a lawsuit) alleging that the Work
+ *      or a Contribution incorporated within the Work constitutes direct
+ *      or contributory patent infringement, then any patent licenses
+ *      granted to You under this License for that Work shall terminate
+ *      as of the date such litigation is filed.
+ *
+ *   4. Redistribution. You may reproduce and distribute copies of the
+ *      Work or Derivative Works thereof in any medium, with or without
+ *      modifications, and in Source or Object form, provided that You
+ *      meet the following conditions:
+ *
+ *      (a) You must give any other recipients of the Work or
+ *          Derivative Works a copy of this License; and
+ *
+ *      (b) You must cause any modified files to carry prominent notices
+ *          stating that You changed the files; and
+ *
+ *      (c) You must retain, in the Source form of any Derivative Works
+ *          that You distribute, all copyright, patent, trademark, and
+ *          attribution notices from the Source form of the Work,
+ *          excluding those notices that do not pertain to any part of
+ *          the Derivative Works; and
+ *
+ *      (d) If the Work includes a "NOTICE" text file as part of its
+ *          distribution, then any Derivative Works that You distribute must
+ *          include a readable copy of the attribution notices contained
+ *          within such NOTICE file, excluding those notices that do not
+ *          pertain to any part of the Derivative Works, in at least one
+ *          of the following places: within a NOTICE text file distributed
+ *          as part of the Derivative Works; within the Source form or
+ *          documentation, if provided along with the Derivative Works; or,
+ *          within a display generated by the Derivative Works, if and
+ *          wherever such third-party notices normally appear. The contents
+ *          of the NOTICE file are for informational purposes only and
+ *          do not modify the License. You may add Your own attribution
+ *          notices within Derivative Works that You distribute, alongside
+ *          or as an addendum to the NOTICE text from the Work, provided
+ *          that such additional attribution notices cannot be construed
+ *          as modifying the License.
+ *
+ *      You may add Your own copyright statement to Your modifications and
+ *      may provide additional or different license terms and conditions
+ *      for use, reproduction, or distribution of Your modifications, or
+ *      for any such Derivative Works as a whole, provided Your use,
+ *      reproduction, and distribution of the Work otherwise complies with
+ *      the conditions stated in this License.
+ *
+ *   5. Submission of Contributions. Unless You explicitly state otherwise,
+ *      any Contribution intentionally submitted for inclusion in the Work
+ *      by You to the Licensor shall be under the terms and conditions of
+ *      this License, without any additional terms or conditions.
+ *      Notwithstanding the above, nothing herein shall supersede or modify
+ *      the terms of any separate license agreement you may have executed
+ *      with Licensor regarding such Contributions.
+ *
+ *   6. Trademarks. This License does not grant permission to use the trade
+ *      names, trademarks, service marks, or product names of the Licensor,
+ *      except as required for reasonable and customary use in describing the
+ *      origin of the Work and reproducing the content of the NOTICE file.
+ *
+ *   7. Disclaimer of Warranty. Unless required by applicable law or
+ *      agreed to in writing, Licensor provides the Work (and each
+ *      Contributor provides its Contributions) on an "AS IS" BASIS,
+ *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ *      implied, including, without limitation, any warranties or conditions
+ *      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ *      PARTICULAR PURPOSE. You are solely responsible for determining the
+ *      appropriateness of using or redistributing the Work and assume any
+ *      risks associated with Your exercise of permissions under this License.
+ *
+ *   8. Limitation of Liability. In no event and under no legal theory,
+ *      whether in tort (including negligence), contract, or otherwise,
+ *      unless required by applicable law (such as deliberate and grossly
+ *      negligent acts) or agreed to in writing, shall any Contributor be
+ *      liable to You for damages, including any direct, indirect, special,
+ *      incidental, or consequential damages of any character arising as a
+ *      result of this License or out of the use or inability to use the
+ *      Work (including but not limited to damages for loss of goodwill,
+ *      work stoppage, computer failure or malfunction, or any and all
+ *      other commercial damages or losses), even if such Contributor
+ *      has been advised of the possibility of such damages.
+ *
+ *   9. Accepting Warranty or Additional Liability. While redistributing
+ *      the Work or Derivative Works thereof, You may choose to offer,
+ *      and charge a fee for, acceptance of support, warranty, indemnity,
+ *      or other liability obligations and/or rights consistent with this
+ *      License. However, in accepting such obligations, You may act only
+ *      on Your own behalf and on Your sole responsibility, not on behalf
+ *      of any other Contributor, and only if You agree to indemnify,
+ *      defend, and hold each Contributor harmless for any liability
+ *      incurred by, or claims asserted against, such Contributor by reason
+ *      of your accepting any such warranty or additional liability.
+ *
+ *   END OF TERMS AND CONDITIONS
+ *
+ *   APPENDIX: How to apply the Apache License to your work.
+ *
+ *      To apply the Apache License to your work, attach the following
+ *      boilerplate notice, with the fields enclosed by brackets "[]"
+ *      replaced with your own identifying information. (Don't include
+ *      the brackets!)  The text should be enclosed in the appropriate
+ *      comment syntax for the file format. We also recommend that a
+ *      file or class name and description of purpose be included on the
+ *      same "printed page" as the copyright notice for easier
+ *      identification within third-party archives.
+ *
+ *   Copyright [yyyy] Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ */
+    </source>
+  <p>You can download the original license file <a href="./LICENSE" target="_new">here.</a></p>
+<p>The License is accompanied by a NOTICE</p>
+<source>
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Ant distribution.                      ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   This product includes also software developed by :
+     - the W3C consortium (http://www.w3c.org) ,
+     - the SAX project (http://www.saxproject.org)
+
+   Please read the different LICENSE files present in the root directory of
+   this distribution.
+
+   The names "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.
+</source>
+</section>
+  <section name="The Apache Software License, Version 1.1">
+<p> The Apache Software License, Version 1.1, applies to all versions of up to ant 1.6.0 included.</p>
+    <source>/*
+ * ============================================================================
+ *                   The Apache Software License, Version 1.1
+ * ============================================================================
+ * 
+ *    Copyright (C) 2000-2003 The Apache Software Foundation. All
+ *    rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, 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  acknowledgment:  "This product includes  software
+ *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+ *    Alternately, this  acknowledgment may  appear in the software itself,  if
+ *    and wherever such third-party acknowledgments normally appear.
+ * 
+ * 4. The names "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 name,  without prior written permission  of the
+ *    Apache Software Foundation.
+ * 
+ * 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 (INCLU-
+ * DING, 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 &lt;http://www.apache.org/&gt;.
+ *
+ */
+</source>
+  </section>
+</body>
+</document>
diff --git a/trunk/xdocs/mail.xml b/trunk/xdocs/mail.xml
new file mode 100644
index 0000000..f72e66c
--- /dev/null
+++ b/trunk/xdocs/mail.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Mailing Lists</title>
+    <author email="">Apache Ant PMC</author>
+  </properties>
+
+<body>
+
+    <section name="Mailing Lists">
+
+      <p>Please read the <a
+      href="http://jakarta.apache.org/site/mail.html">guidelines of
+      the Jakarta Project</a> before subscribing and posting to any of
+      the lists below.  They apply to Ant's lists as well.</p>
+
+      <p>The user and dev list are subscriber only lists, this means
+      you have to subscribe before you can post to the list.  Please
+      note that any HTML parts sent to the lists will be removed by our
+      mailing list software - you shouldn&apos;t be sending HTML mails
+      anyway.</p>
+
+      <p>To subscribe to a mailinglist use the links below. In your first email you will get some
+      information about working with the list manager <a href="http://www.ezmlm.org/">EZMLM</a>.</p>
+
+      <subsection name="User List: user@ant.apache.org">
+        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:user-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:user-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-user/">ASF Archive</a>
+          <a href="http://marc.theaimsgroup.com/?l=ant-user&amp;r=1&amp;w=2">Third Party Archive</a>
+        </p>
+
+        <p>This list is for developers that are using Ant in their own
+        projects to ask questions, share knowledge, and discuss issues
+        related to using Ant as a build tool.</p>
+      </subsection>
+
+      <subsection name="Ivy User List: ivy-user@ant.apache.org">
+        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:ivy-user-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:ivy-user-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-ivy-user/">ASF Archive</a>
+        </p>
+
+        <p>This list is for developers that are using Ivy or IvyDE in
+        their own projects to ask questions, share knowledge, and
+        discuss issues related to using Ivy with or without Ant.</p>
+      </subsection>
+
+      <subsection name="Developer List: dev@ant.apache.org">
+        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:dev-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:dev-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-dev/">ASF Archive</a>
+          <a href="http://marc.theaimsgroup.com/?l=ant-dev&amp;r=1&amp;w=2">Third Party Archive</a>
+        </p>
+
+        <p>This is the list where participating developers of the Ant
+        build tool, Ivy or the Ant libraries developed by the Ant team
+        meet and discuss issues, code changes/additions, etc.</p>
+      </subsection>
+
+      <subsection name="Notifications List: notifications@ant.apache.org">
+        <p>
+          <b>Medium Traffic</b>
+          <a href="mailto:notifications-subscribe@ant.apache.org">Subscribe</a>
+          <a href="mailto:notifications-unsubscribe@ant.apache.org">Unsubscribe</a>
+          <a href="http://mail-archives.apache.org/mod_mbox/ant-notifications/">ASF Archive</a>
+        </p>
+
+        <p>Subscribers to this list get notices of each and every
+        code change, build results, testing notices, etc.</p>
+      </subsection>
+
+      <subsection name="How to unsubscribe your old email address">
+        <p>
+        First, find out the particular email adress to which ezmlm is sending.
+        The email headers are visible in Microsoft Outlook via the messages menu
+        "View | Options".
+        <pre>
+        Microsoft Mail Internet Headers Version 2.0
+        ...
+        List-Unsubscribe: &lt;mailto:user-unsubscribe@ant.apache.org&gt;
+        List-Help: &lt;mailto:user-help@ant.apache.org&gt;
+        List-Post: &lt;mailto:user@ant.apache.org&gt;
+        List-Id: "Ant Users List" &lt;user.ant.apache.org&gt;
+        Reply-To: "Ant Users List" &lt;user@ant.apache.org&gt;
+        Delivered-To: mailing list user@ant.apache.org
+        ...
+        Return-Path: user-return-12345-<i>john=host.domain</i>@ant.apache.org
+        ...
+        </pre>
+        The <i>Return-Path</i> header contains the email address which is subscribed. 
+        </p>      
+        <p> To stop subscription for the address john@host.domain , send an email to <pre>dev-unsubscribe-john=host.domain@ant.apache.org</pre>
+          or to  <pre>user-unsubscribe-john=host.domain@ant.apache.org</pre>.
+        </p>  
+      </subsection>
+    </section>
+    <section name="Archives">
+
+      <p>These lists are archived at</p>
+
+        <ul>
+          <li><a href="http://mail-archives.apache.org/mod_mbox/">List Index on mail-archives.apache.org</a></li>
+          <li><a href="http://ant.apache.org/mail/">Full mbox archives of all lists</a></li>
+          <li><a href="http://marc.theaimsgroup.com/">Mailing list Archives</a></li>
+          <li><a href="http://news.gmane.org/gmane.comp.jakarta.ant.devel/">Ant Developer List on gmane</a></li>
+          <li><a href="http://news.gmane.org/gmane.comp.jakarta.ant.user/">Ant User List on gmane</a></li>
+          <li><a href="http://www.nabble.com/Ant---Dev-f108.html">Ant Developer List on nabble</a></li>
+          <li><a href="http://www.nabble.com/Ant---Users-f107.html">Ant User List on nabble</a></li>
+          <li><a href="http://ant.markmail.org/">Mailing List Archive at MarkMail</a></li>
+        </ul>
+
+
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/mission.xml b/trunk/xdocs/mission.xml
new file mode 100644
index 0000000..4032aeb
--- /dev/null
+++ b/trunk/xdocs/mission.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Apache Ant Mission</title>
+    <author email="">Apache Ant PMC</author>
+  </properties>
+
+<body>
+  <section name="Board Resolution">
+    
+    <p>Apache Ant is a project of the <a
+    href="http://www.apache.org/">Apache Software Foundation</a>.  It
+    started as a subproject of the <a
+    href="http://jakarta.apache.org/">Apache Jakarta Project</a>.</p>
+
+    <p>This is the board resolution (from the <a href="http://www.apache.org/foundation/records/minutes/2002/board_minutes_2002_11_18.txt">minutes</a>)
+    that created the Apache Ant project:</p>
+
+    <source>
+7.D. Resolution [R3] to create the Ant PMC
+
+WHEREAS, the Board of Directors deems it to be in the best
+interests of the Foundation and consistent with the
+Foundation's purpose to establish a Project Management
+Committee charged with the creation and maintenance of
+open-source software related to the Apache Ant build tool, for
+distribution at no charge to the public.
+
+NOW, THEREFORE, BE IT RESOLVED, that a Project Management
+Committee (PMC), to be known as the "Apache Ant PMC", be and
+hereby is established pursuant to Bylaws of the Foundation; and
+be it further
+
+RESOLVED, that the Apache Ant PMC be and hereby is responsible
+for the creation and maintenance of the Ant build system and
+related software components, based on software licensed to the
+Foundation; and be it further
+
+RESOLVED, that the office of "Vice President, Apache Ant" be
+and hereby is created, the person holding such office to serve
+at the direction of the Board of Directors as the chair of the
+Apache Ant PMC, and to have primary responsibility for
+management of the projects within the scope of responsibility
+of the Apache Ant PMC; and be it further
+
+RESOLVED, that the persons listed immediately below be and
+hereby are appointed to serve as the initial members of the
+Apache Ant PMC:
+
+   Bruce Atherton
+   Stephane Bailliez
+   Stefan Bodewig
+   Erik Hatcher
+   Diane Holt
+   Donald Leslie
+   Steve Loughran
+   Conor MacNeill
+   Costin Manolache
+   Sam Ruby
+   Jon Skeet
+   Magesh Umasankar
+   Christoph Wilhelms
+
+NOW, THEREFORE, BE IT FURTHER RESOLVED, that Conor MacNeill be
+and hereby is appointed to the office of Vice President, Apache
+Ant, to serve in accordance with and subject to the direction
+of the Board of Directors and the Bylaws of the Foundation
+until death, resignation, retirement, removal or
+disqualification, or until a successor is appointed; and be it
+further
+
+RESOLVED, that the initial Apache Ant PMC be and hereby is
+tasked with the creation of a set of bylaws intended to
+encourage open development and increased participation in the
+Apache Ant Project.
+
+By Unanimous Vote, Resolution R3 was approved. The Ant PMC is
+hereby created.
+    </source>
+
+  </section>
+</body>
+</document>
diff --git a/trunk/xdocs/nightlies.xml b/trunk/xdocs/nightlies.xml
new file mode 100644
index 0000000..65edc7d
--- /dev/null
+++ b/trunk/xdocs/nightlies.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Nightly Builds</title>
+    <base/>
+  </properties>
+
+<body>
+
+<section name="Nightly Builds">
+
+<p>If you wish to use the latest Ant features, you can try downloading a
+<a href="http://people.apache.org/builds/ant/nightly/">nightly build</a>.
+</p>
+
+<p>If you want to build Ant from sources, you can use a <a
+href="http://svn.apache.org/snapshots/ant/">Subversion snapshot</a>.</p>
+
+</section>
+
+</body>
+
+</document>
diff --git a/trunk/xdocs/problems.xml b/trunk/xdocs/problems.xml
new file mode 100644
index 0000000..316efbb
--- /dev/null
+++ b/trunk/xdocs/problems.xml
@@ -0,0 +1,196 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="">Conor MacNeill</author>
+    <title>Having Problems?</title>
+  </properties>
+
+  <body>
+    <section name="Having Problems?">
+        <p>
+           This page details some steps you can take to try and resolve
+           any problems you may be having with Ant. If you find you can't
+           resolve the problem, then this page will help you collect some of
+           the relevant information to provide in a bug report. This information
+           will help the Ant developers understand and resolve the problem.
+           Of course, not all the steps here will make sense for every problem
+           you may encounter - these are just some suggestions to point
+           you in the right direction.
+        </p>
+
+      <subsection name="Ensure that you are actually running the version of Ant that you think you do">
+        <p>Many tools include a version of Ant and some Operating
+        Systems even install it by default now, so you may have a
+        version of Ant installed that you haven't been aware of.</p>
+
+        <p>One of the first things to do is to run
+          <br></br><br></br>
+          <font face="verdana" size="-1">ant -version</font>
+          <br></br><br></br>
+          and
+          <br></br><br></br>
+          <font face="verdana" size="-1">ant -diagnostics</font>
+          <br></br><br></br>
+          to be sure.  Also, we highly recommend that you run Ant with
+          an empty CLASSPATH.  If any other version of Ant can be
+          loaded from the CLASSPATH, many types of errors may happen
+          because of incompatible classes being loaded.</p>
+
+        <p>See <a href="faq.html">the FAQ</a> for <a
+        href="faq.html#NoClassDefFoundError">some</a> <a
+        href="faq.html#InstantiationException">examples</a>, but many
+        other problems are a result of an old version of Ant on your
+        system as well.</p>
+
+      </subsection>
+
+      <subsection name="Read the Manual">
+         <p>
+            The first step to take when you have a problem with Ant is to read
+            the <a href="manual/index.html">manual</a> entry for the task or
+            concept that is giving you trouble. In particular, check the
+            meaning of a task's attributes and nested elements. Perhaps an
+            attribute is available that would provide the behavior you require.
+            If you have problems with the manual itself, you can submit a
+            documentation bug report (see below) to help us improve the Ant
+            documentation.
+         </p>
+      </subsection>
+      <subsection name="Examine Debug Output">
+         <p>
+            If you're still having a problem, the next step is to try and
+            gather additional information about what Ant is doing.
+            Try running Ant with the <code>verbose</code> flag:
+            <br></br><br></br>
+            <font face="verdana" size="-1">ant -verbose</font>
+            <br></br><br></br>
+            or
+            <br></br><br></br>
+            <font face="verdana" size="-1">ant -v</font>
+            <br></br><br></br>
+
+            This will produce output that starts like the following:</p>
+<table>
+<tr>
+<td>
+Ant version 1.4.1 compiled on October 11 2001<br></br>
+Buildfile: build.xml<br></br>
+Detected Java version: 1.3 in: D:\usr\local\java\jdk13\jre<br></br>
+Detected OS: Windows NT<br></br>
+parsing buildfile D:\ant\build.xml
+with URI = file:D:/ant/build.xml<br></br>
+Project base dir set to: D:\ant<br></br>
+&#160;&#160;[property] Loading Environment env.<br></br>
+&#160;&#160;[property] Loading D:\ant\conf.properties<br></br>
+Build sequence for target &#39;debug&#39; is [debug]<br></br>
+Complete build sequence is [debug, gensrc, compile, jar, test]<br></br>
+. . .<br></br>
+</td>
+</tr>
+</table>
+           <p>
+              You should be able to see from the trace more about what Ant
+              is doing and why it's taking a particular course of action.
+              If you need even more information, you can use the
+              <code>-debug</code> flag rather than
+              <code>-verbose</code>.
+              This will generally produce so much
+              output that you may want to save the output to a file and
+              analyze it in an editor. You can save the output using the
+              <code>-logfile &lt;filename&gt;</code> flag, or
+              using redirection.
+           </p>
+           <p>
+              Once you have all this debug information, how can you use it
+              to solve your problem?  That will depend on the task in question
+              and the nature of your problem. Each task logs different aspects
+              of its operation, but it should give you an idea of what is going
+              on. For example, the <code>&lt;javac&gt;</code> task logs the
+              reasons why it
+              chooses to compile particular class files and not others, along
+              with which compiler it is using and the arguments it will pass
+              to that compiler. The following partial trace shows why
+              <code>&lt;javac&gt;</code> is adding one class file but
+              skipping another.
+              This is followed by which compiler it will be using, the
+              arguments that will get passed to the compiler,
+              and a list of all the class files to be compiled.
+           </p>
+<table>
+<tr>
+<td>
+[javac] Test.java omitted as D:\classes\Test.class is up to date.<br></br>
+[javac] Unset.java added as D:\classes\Unset.class is outdated.<br></br>
+[javac] Compiling 1 source file to D:\classes<br></br>
+[javac] Using classic compiler<br></br>
+[javac] Compilation args: -d D:\classes -classpath D:\classes;<br></br>
+D:\jdk118\classes.zip; -sourcepath D:\src\java -g:none<br></br>
+[javac] File to be compiled:<br></br>
+D:\src\java\Unset.java<br></br>
+</td>
+</tr>
+</table>
+
+           <p>
+              In many cases, Ant tasks are wrappers around OS commands or
+              other Java classes. In debug mode, many of these tasks will
+              print out the equivalent command line, as the
+              <code>&lt;javac&gt;</code> task
+              output does. If you are having a problem, it is often useful to
+              run the command directly from the command line, in the same way
+              Ant is running it, and see if the problem occurs from there
+              as well. The problem may be in the command that is being run,
+              or it may be in the way the Ant task is running the command.
+              You can also see the effect of changing attribute values on the
+              generated command line. This can help you to understand whether
+              you are using the correct attributes and values.
+            </p>
+      </subsection>
+
+      <subsection name="Has It Been Fixed?">
+         <p>
+            After examining the debug output, if you still believe that the
+            problem you are having is caused by Ant, chances are that someone
+            else may have already encountered this problem, and perhaps it has
+            been fixed. The next step, therefore, would be to download the
+            sources of ant, see <a href="svn.html">svn</a>.
+        </p>
+        <p>
+          <a href="http://vmgump.apache.org/gump/public/index.html">Gump</a>
+          is building ant every night and using the ant built from the
+          latest source to build a long list of open source projects. However,
+          the version of ant built by gump is not available for download. Even
+          if it were, it would not include most of the optional tasks.
+        </p>
+        <p>
+            We currently do not have nightly builds including the optional tasks.
+        </p>
+      </subsection>
+      
+
+         
+    </section>
+    <section name="bugs">
+      <p>If you are convinced that you have identified an unfixed bug, please turn to
+      our document concerning the <a href="bugs.html">bug database</a>.</p>
+    </section>
+    
+  </body>
+</document>
diff --git a/trunk/xdocs/projects.xml b/trunk/xdocs/projects.xml
new file mode 100644
index 0000000..ca430dc
--- /dev/null
+++ b/trunk/xdocs/projects.xml
@@ -0,0 +1,674 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="bodewig@apache.org">Stefan Bodewig</author>
+    <title>Related Projects</title>
+  </properties>
+
+  <body>
+
+    <section name="Related Projects">
+
+      <p>Nothing listed here is directly supported by the Ant
+      developers, if you encounter any problems with them, please use
+      the contact information.</p>
+
+      <subsection name="AndroMDA">
+
+        <p>AndroMDA is a code generator tool that follows the Model
+        Driven Architecture (MDA) paradigm. It takes a UML model from
+        a CASE-tool and generates classes and deployable components
+        (J2EE or other) specific for your application
+        architecture.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.4.1 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.andromda.org/">http://www.AndroMDA.org/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=73047">project mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>BSD license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntContrib">
+
+        <p>The Ant-Contrib project is a collection of user supplied
+        task (like an <code>&lt;if&gt;</code> task) and a development
+        playground for experimental tasks like a C/C++ compilation
+        task for different compilers.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.4.1 and above</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://ant-contrib.sourceforge.net/">http://ant-contrib.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=36177">project mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antelope">
+
+        <p>A GUI for running Ant and editing build files, can run as
+        stand-alone or as a plugin to jEdit. In addition to running
+        targets, Antelope can generate performance statistics and can
+        trace/display a target's execution path without actually
+        executing the target.</p>
+
+        <p>Includes several additional tasks: Assert, If/Else,
+        Try/Catch/Finally, Switch, Variable, Stopwatch, Limit, Math,
+        Post, SSH, SCP, AntFetch, AntCallBack.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and higher.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antelope.tigris.org/">http://antelope.tigris.org/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:daleanson@users.sourceforge.net">Dale Anson</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntHill">
+
+        <p>Anthill is a build tool that promotes a controlled build
+        process by ensuring that every build reflects the source
+        repository contents and tagging the repository with a unique
+        build number after every build. Anthill also encourages the
+        sharing of knowledge within an organization by automatically
+        updating a project intranet site with artifacts from the
+        latest build.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.3, is compatible with Ant 1.3 to 1.4.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.urbancode.com/projects/anthill/">http://www.urbancode.com/projects/anthill/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='mailto:mbz@urbancode.com'>Maciej Zawadzki</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Mozilla-like license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antigen">
+
+        <p>Antigen (Ant Installer Generator) is a tool to take an Ant build script, combine it with a GUI
+        and wrap it up as an executable jar file. Its main use is for creating graphical, ant-based installers.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>bundles Ant 1.6.2</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antigen.sourceforge.net/">http://antigen.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='mailto:johndavidtaylor@users.sourceforge.net'>Jon Tayler</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Academic Free License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntInstaller">
+        <p>Builds MSI style installers (with command line option)
+        using Ant as Back end. UI developed by writing an XML install
+        descriptor.  Runtime launched from scripts or an all inclusive
+        Jar.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.1 others not tested</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antinstaller.sf.net/">http://antinstaller.sf.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href='mailto:teknopaul@users.sourceforge.net'>teknopaul@users.sourceforge.net</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL but in the process of of moving to Apache2.0 on request</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antlion">
+
+        <p>The Antlion Project adds value to Ant build scripts by providing
+        tasks which centralizes the library dependencies, and enables
+        projects to define dependencies upon other projects.</p>
+
+        <p>External dependencies may be loaded from a custom local
+        repository or Maven-like remote repositories. Antlion handles
+        the generation of properties, filesets, and paths.</p>
+
+        <p>Inter-project dependencies allow for building the other
+        project's files if they aren't already built.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antlion.sourceforge.net/">http://antlion.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='https://sourceforge.net/mail/?group_id=93410'>Project mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache License, Version 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="AntShellExt (Ant Shell Extension)">
+
+        <p>Ant Shell Extension is a Windows Explorer enhancement that adds a contextual 
+        menu when you right click over an Ant xml file, so you can execute all the actions 
+        defined in that file without going to a command console or starting your favourite 
+        IDE to make a simple clean.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Tested with Ant 1.6 and later, should work with all versions</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.elpagestion.com/os_ant_en.shtml">
+                http://www.elpagestion.com/os_ant_en.shtml</a>
+            </td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='mailto:opensource@elpagestion.com'>Project mail</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Antworks">
+
+        <p>The antworks project is a set of tools and standardized targets that
+        greatly simplifies using ant in your project.</p>
+        <p>
+            The driver behind antworks is Importer. Importer is an extension to the
+            ant import task that will download and
+            cache an ant build.xml file and it's associated resources called
+            antlets.  Antlets are available for Java compiling
+            and packaging,  JUnit, Forrest, J2EE and
+            <a href="http://antworks.sourceforge.net/antlets/">more</a>.
+            </p>
+            <p>
+            See the <a href="http://antworks.sourceforge.net/start.html ">Getting Started</a>
+            guide for more information.
+            </p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>1.6 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://antworks.sourceforge.net/">http://antworks.sourceforge.net/index.html</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ="http://lists.sourceforge.net/lists/listinfo/antworks-developers">Antworks Developers mailing lists</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>The Apache License 2.0</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="BuildMonkey">
+
+        <p>BuildMonkey is a Web-based automated build dashboard, with upload
+           capability and google web search. It schedules the running of Ant
+           build scripts - checking sources out of CM - and makes the results
+           available centrally.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5.4 or later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.buildmonkey.com/">http://www.buildmonkey.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:jb@buildmonkey.com">jb@buildmonkey.com</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware, commercial/support licences available</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="CruiseControl">
+
+        <p>CruiseControl is a tool for setting up a continuous build
+        process.  CruiseControl provides an Ant wrapper and a set of
+        tasks to automate the checkout/build/test cycle. CruiseControl
+        also comes bundled with a servlet for viewing the status of
+        the current build, as well as previous build results.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.2 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://cruisecontrol.sourceforge.net/">http://cruisecontrol.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='http://cruisecontrol.sourceforge.net/contact.html'>Project Mailing Lists and Administrators</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Release 1.0 has been licensed under the GNU General Public
+            License.  Starting with release 1.1 the license has been
+            changed to a BSD-like license.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Invicta">
+
+        <p>Invicta is a build management tool. Using simple project definition files,
+        it generates powerful build scripts (such as ANT) while hiding their
+        complexity. Invicta is a modular framework that allows developing additional
+        components and output types.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.5 and higher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://invicta.sf.net/">http://invicta.sf.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ="http://invicta.sf.net/contact.html">Project Mailing Lists and Administrators</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="JAM - JavaGen Ant Modules">
+
+        <p>JAM is a modular Ant toolkit for developing and testing Java/J2EE
+        applications. JAM supports EJB and Servlet/JSP development using XDoclet,
+        JUnit, Cactus, Maven, Castor and MDA/UML code generation on various J2EE
+        servers including JBoss.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.javagen.com/jam.jsp">http://www.javagen.com/jam.jsp</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.javagen.com/feedback.do">Feedback</a> <br/>
+                <a href="http://www.javagen.com/bugs.do">Bug Reports</a>
+            </td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Krysalis Centipede">
+        <p>The Centipede admin told us, that that project
+           "is no more" and that "Antworks has taken it place."
+        </p>
+      </subsection>
+
+      <subsection name="Leafcutter">
+        <p>Leafcutter is an API which allows you to execute Ant tasks from Java code. <br/>
+           Leafcutter is useful as: <ul>
+           <li>A way of integrating Ant tasks into existing Java programs. </li>
+           <li>A wholesale alternative to standard Ant for process automation. </li>
+           </ul>
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td><i>unknown</i></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="https://leafcutter.dev.java.net/">https://leafcutter.dev.java.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="https://leafcutter.dev.java.net/servlets/ProjectForumView">Discussion Forum</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache Software Foundation License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="luntbuild">
+
+        <p>Luntbuild is an open source build automation and management
+        tool based on Apache Ant. Builds are setup through concepts of
+        projects, views, schedules, modules, etc. All configurations
+        and monitoring tasks is performed from a clean web
+        interface. It supports schedules builds, force builds,
+        rebuilds, clean build, increment build, etc.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.x</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sourceforge.net/projects/luntbuild/">http://www.sourceforge.net/projects/luntbuild/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ='http://sourceforge.net/projects/luntbuild/'>luntbuild project page</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Opensource</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="NAnt">
+
+        <p>NAnt is a .NET based build tool. In theory it is kind of
+        like make without make's wrinkles. In practice it's a lot like
+        Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>compatible in spirit.</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://nant.sourceforge.net/">http://nant.sourceforge.net/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://sourceforge.net/mail/?group_id=31650">project mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Parabuild">
+
+        <p>Parabuild is an automated multiplatform build management server.
+        Parabuild helps software teams and organizations of all sizes reduce
+        risks of project failures and increase productivity by providing provides
+        automatic continuous integration builds and stable scheduled builds.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.3 and later</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.viewtier.com/products/parabuild.htm">http://www.viewtier.com/products/parabuild.htm</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.viewtier.com/about_us.htm">http://www.viewtier.com/about_us.htm</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Commercial</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Rant">
+
+        <p>Rant stands for Remote Ant. It is a distributed build
+        system that allows an Ant build file to launch builds on other
+        systems and receive exceptions should they occur.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://sourceforge.net/projects/remoteant/">http://sourceforge.net/projects/remoteant/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="mailto:cnelson@einnovation.com">Chris Nelson</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>MIT License</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Savant">
+
+        <p>Savant helps simplify builds and codebases by handling the
+        resolution of project dependencies automatically. Savant supports
+        Maven style dependency downloads and various other methods of
+        retrieving dependencies, including fetching files from CVS modules.
+        Savant goes a step further than other dependency solutions and provides
+        the means for multiple internal projects to build each other in order
+        to resolve inter-project dependencies.</p>
+
+        <p>Savant can be used via various Ant types and tasks as well as used
+        from any Java application including those that do not make use of Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.1</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.inversoft.com/">http://www.inversoft.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://www.inversoft.com/contact.html">http://www.inversoft.com/contact.html</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>LGPL</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="WebTest">
+
+        <p>WebTest is a free open source tool for automated testing of web applications.
+        It is a set of powerful Ant tasks allowing to call web pages, mimic user actions
+        (clicking links, filling forms, ...) and verify the results.
+        The generated reports give comprehensive information on success and failure of the test steps.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.6.5</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://webtest.canoo.com/">http://webtest.canoo.com/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href="http://lists.canoo.com/mailman/listinfo/webtest/">project mailing list</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Apache like license</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="XML Publication">
+
+        <p>XML Publication is a set of tools to generate Web pages
+        from desktop documents or other structured documents using
+        XSLT and Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+            <td>Ant 1.4</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://XMLpublication.org/">http://XMLpublication.org/</a></td>
+          </tr>
+          <tr>
+            <th>Contact:</th>
+            <td><a href ="mailto:jmvanel@free.fr">Jean-Marc Vanel</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>GNU General Public License.</td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="yEd">
+
+        <p>yEd is a freeware multi-purpose graph and diagram editor
+        that runs on the Java 2 platform. It provides an import filter
+        for Ant build scripts that makes it possible to conveniently
+        display and browse the dependencies between the different targets
+        of the build file. This is especially useful for debugging and
+        understanding large build files.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Compatibility:</th>
+
+            <td>Ant 1.x</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.yworks.com/products/yed/">http://www.yworks.com/products/yed/</a></td>
+          </tr>
+          <tr>
+
+            <th>Contact:</th>
+            <td><a href ='http://www.yworks.com/en/company_contact.htm'>yWorks Support</a></td>
+          </tr>
+          <tr>
+            <th>License:</th>
+            <td>Freeware</td>
+          </tr>
+
+        </table>
+      </subsection>
+    </section>
+
+  </body>
+</document>
diff --git a/trunk/xdocs/projects/index.xml b/trunk/xdocs/projects/index.xml
new file mode 100644
index 0000000..1a37022
--- /dev/null
+++ b/trunk/xdocs/projects/index.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <index value="1"/>
+    <author email="christoph.wilhelms@t-online.de">Christoph Wilhelms</author>
+    <title>Welcome</title>
+  </properties>
+
+<body>
+
+  <section name="Welcome to the Ant Projects Area">
+    <h3>This is where the Ant sub-projects live!</h3>
+
+    <p>Now, that Ant has become an Apache Top-Level Project it is time to make space on this
+    Web-Page for Ant sub-projects.</p>
+    <p>To make sure you do not miss anything: Stay tuned and visit this page from time to time :)!
+    </p>
+  </section>
+
+</body>
+</document>
+
diff --git a/trunk/xdocs/projects/ivy.xml b/trunk/xdocs/projects/ivy.xml
new file mode 100644
index 0000000..b82636c
--- /dev/null
+++ b/trunk/xdocs/projects/ivy.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>

+<!--

+   Licensed to the Apache Software Foundation (ASF) under one or more

+   contributor license agreements.  See the NOTICE file distributed with

+   this work for additional information regarding copyright ownership.

+   The ASF licenses this file to You under the Apache License, Version 2.0

+   (the "License"); you may not use this file except in compliance with

+   the License.  You may obtain a copy of the License at

+

+       http://www.apache.org/licenses/LICENSE-2.0

+

+   Unless required by applicable law or agreed to in writing, software

+   distributed under the License is distributed on an "AS IS" BASIS,

+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+   See the License for the specific language governing permissions and

+   limitations under the License.

+-->

+<document>

+

+  <properties>

+    <index value="1"/>

+    <title>The Ivy Subproject</title>

+  </properties>

+

+  <body>

+

+    <section name="The Ivy Subproject">

+      <h3>Apache Ivy</h3>

+

+      <p>Ivy is a simple yet powerful dependency manager featuring continuous integration,

+      dependencies of dependencies management, multiple repositories including ibiblio and

+      high performance (use of a local cache).</p>

+

+    </section>

+

+  </body>

+</document>

+

diff --git a/trunk/xdocs/resources.xml b/trunk/xdocs/resources.xml
new file mode 100644
index 0000000..77e7ab4
--- /dev/null
+++ b/trunk/xdocs/resources.xml
@@ -0,0 +1,763 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <author email="bodewig@apache.org">Stefan Bodewig</author>
+    <title>Resources</title>
+  </properties>
+
+  <body>
+    <section name="FAQs">
+      <subsection name="At Ant's website">
+
+        <p>Starting with the release of Ant 1.4 the Ant's FAQ is
+        bundled with the distribution, the most recent version can
+        always be found at the website.</p>
+
+        <table class="externals">
+          <tr>
+            <th>FAQ:</th>
+            <td><a href="faq.html">http://ant.apache.org/faq.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="jGuru">
+        <p>jGuru hosts an interactive Ant discussion forum and FAQ system</p>
+
+        <table class="externals">
+          <tr>
+            <th>Forum:</th>
+            <td><a href="http://www.jguru.com/forums/home.jsp?topic=Ant">http://www.jguru.com/forums/home.jsp?topic=Ant</a></td>
+          </tr>
+          <tr>
+            <th>FAQ:</th>
+            <td><a href="http://www.jguru.com/faq/home.jsp?topic=Ant">http://www.jguru.com/faq/home.jsp?topic=Ant</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="FAQ about Borland Application Server tasks">
+        <p>Benoit Moussaud, the original author of the Borland
+        Application Server specific <a
+        href="manual/OptionalTasks/ejb.html#ejbtasks">EJB tasks</a> has put
+        together a FAQ for this specific subtask.</p>
+
+        <table class="externals">
+          <tr>
+            <th>FAQ:</th>
+            <td><a href="http://www.moussaud.org/ejbjar.html">http://www.moussaud.org/ejbjar.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+    </section>
+
+    <section name="WIKIs">
+      <subsection name="Apache">
+
+        <p>The ASF provides a Wiki farm for Apache projects.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Main page:</th>
+            <td><a href="http://wiki.apache.org/general">Apache Wiki Farm</a></td>
+          </tr>
+          <tr>
+            <th>Ant Wiki:</th>
+            <td><a href="http://wiki.apache.org/ant/">Ant Wiki</a></td>
+          </tr>
+        </table>
+      </subsection>
+    </section>
+
+
+
+
+    <section name="Books">
+      <p>The most recent books come first</p>
+      <subsection name="Ant in Action"
+          isbn="193239480X">
+        <p>Published April/May 2007, and covering Ant 1.7.</p>
+
+        <p>This is a major rewrite of the first edition; still 600 pages long.
+        </p>
+
+        <p>
+          This book moves up from Ant1.5 to Java1.5 and 1.7, with a near-complete
+          rewrite of the applied-ant section, covering new topics such as
+          antlibs, repository management with Ivy, Xml Schema validation,
+          EJB3.0/Java EE development and advanced deployment using SmartFrog.
+          The ant coding section looks at AntUnit, antlib authoring and
+          scripting languages, while the beginners chapters, the first third
+          of the book, still shows developers how to build, test, package and
+          redistribute a Java application.
+        </p>
+        <p>
+          If you are one of the 20,000+ owners of the first edition, it is now
+          obsolete. Sorry :)
+        </p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Steve Loughran and Erik Hatcher</td>
+          </tr>
+          <tr>
+            <th>Publisher URL:</th>
+            <td>
+              <a href="http://www.manning.com/loughran/">
+                http://www.manning.com/loughran/
+              </a>
+            </td>
+          </tr>
+          <tr>
+            <th>Book URL</th>
+            <td>
+              <a href="http://antbook.org/">
+                http://antbook.org/
+              </a>
+            </td>
+          </tr>
+          <tr>
+            <th>Source code repository</th>
+            <td>
+              <a href="http://sourceforge.net/projects/antbook">
+                http://sourceforge.net/projects/antbook
+              </a>
+            </td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant: The Definitive Guide, 2nd edition" isbn="0596006098">
+        <p>Published April 2005, and covers Ant release 1.6.1.</p>
+
+        <p>This is a complete rewrite of the first edition; this book is
+        now 290 pages and so covers Ant in more depth than its predecessor.
+        </p>
+
+        <p>It also mixes reference information (tables) with text explanation
+        on how to use the tasks. Contents includes JUnit, CVS, execution, basic
+        deployment, Web application development and XDoclet. There is also coverage
+        of XDoclet, and a chapter on how to extend Ant in Java.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Steve Holzner</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.oreilly.com/catalog/anttdg2/">http://www.oreilly.com/catalog/anttdg2/</a>
+            </td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Pragmatic Project Automation" isbn="0974514039">
+        <p>
+
+        How to Build, Deploy, and Monitor Java Applications.
+        Published: July 2004 ISBN:        0-9745140-3-9
+        </p>
+        <p>
+          This is not a reference guide to Ant, but a book on how to automate the build process.
+          The core build, continuous integration, reporting and release management
+          are all covered. Ant is of course central to this. This is a fun read!
+        </p>
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Mike Clark</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>
+              <a href="http://www.pragmaticprogrammer.com/sk/auto/">http://www.pragmaticprogrammer.com/sk/auto//</a>
+            </td>
+          </tr>
+        </table>
+      </subsection>
+
+
+
+      <subsection name="Extreme Programming with Ant" isbn="0672325624">
+         <p> This book shows how to implement an XP project using Ant 1.5.3, and many other 3rd party tools.  Covers:</p>
+            <ul>
+               <li>The fundamentals of Ant: concepts, core and optional tasks</li>
+               <li>How to write custom Ant components, including custom Tasks, Loggers, Listeners, Input Handlers, Selectors, Filters, Mappers and Data Types</li>
+               <li>Mitigating risks by creating spike tests with Ant buildfiles</li>
+               <li>Add CVS version control and testing with JUnit</li>
+               <li>Automate nightly builds and reporting</li>
+               <li>Deploy applications dynamically using XDoclet</li>
+               <li>Enforcing Code Standards with Jalopy, PMD, CheckStyle, iContract, JDepend</li>
+               <li>Using Remote Ant (Rant) and CruiseControl</li>
+               <li>Generating project documentation</li>
+               <li>Adapting an XP process for use by other teams or across an enterprise</li>
+               <li>Custom Task examples to generating UML diagrams, creating reports and metrics on-the-fly</li>
+               <li>Follows a case-study of a team that implements an XP Project</li>
+            </ul>
+         <table class="externals">
+          <tr>
+            <th>Authors:</th>
+            <td>Glenn Niemeyer and Jeremy Poteet</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sams.com/catalog/product.asp?product_id=%7BFB825A48-BC04-4C55-BD8C-DF93C6BBF920%7D">http://www.sams.com/catalog/product.asp?product_id=%7BFB825A48-BC04-4C55-BD8C-DF93C6BBF920%7D</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant. Das Java-Build-Tool in der Praxis" isbn="3827320666">
+        <p>A German language book on Ant that covers Ant 1.5.
+        This is the original description:</p>
+        <source>
+        Das Build-Tool Ant ist das Open-Source-Werkzeug, das den Entwicklungsprozess einer Java-
+        oder J2EE-Anwendung wesentlich vereinfacht. Gesteuert durch XML-basierte Skripte f�hrt es
+        nahezu alle Aufgaben aus, die nach dem Kodieren einer Anwendung anfallen.</source>
+        <p>Some topics:</p>
+            <ul>
+                <li>creating archives (zip, jar)</li>
+                <li>call the java compiler</li>
+                <li>edit property files</li>
+                <li>file operation</li>
+                <li>source code control systems</li>
+            </ul>
+        <p>The book is available in English as "Ant: The Java Build Tool in Practice"</p>
+        <table class="externals">
+          <tr>
+            <th>Authors:</th>
+            <td>Bernd Matzke</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.addison-wesley.de/main/main.asp?page=home/bookdetails&amp;ProductID=13459">http://www.addison-wesley.de/main/main.asp?page=home/bookdetails&amp;ProductID=13459</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Java Development with Ant" isbn="1930110588">
+        <p>Published 2002. This book covers Ant 1.5, including:</p>
+            <ul>
+                <li>The new Ant 1.5 features</li>
+                <li>Ant's datatypes and property handling</li>
+                <li>JUnit testing and reporting</li>
+                <li>Continuous integration techniques</li>
+                <li>XDoclet for attribute-oriented programming</li>
+                <li>EJB generation, building, and packaging</li>
+                <li>Writing and testing native code</li>
+                <li>Building Web Services with Apache Axis</li>
+                <li>Deploying your system to multiple remote servers</li>
+                <li>Using and writing
+                    <ul>
+                        <li>Loggers</li>
+                        <li>Listeners</li>
+                        <li>Selectors</li>
+                        <li>Custom tasks</li>
+                    </ul>
+                </li>
+            </ul>
+        <p>Also available in Korean and German editions</p>
+
+        <table class="externals">
+          <tr>
+            <th>Authors:</th>
+            <td>Erik Hatcher and Steve Loughran</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.manning.com/antbook/">http://www.manning.com/antbook/</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant: The Definitive Guide, 1st edition" isbn="0596001843">
+          <!-- a soon as somebody submits a description, let's add it -->
+        <p>Published 2002, Covers Ant release 1.4.1.</p>
+        <table class="externals">
+          <tr>
+            <th>Authors:</th>
+            <td>Jesse E. Tilly and Eric M. Burke</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.oreilly.com/catalog/anttdg/">http://www.oreilly.com/catalog/anttdg/</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant. Kurz und Gut." isbn="3897212412">
+
+        <p>A German language short reference for Ant that covers Ant
+        1.4.  This is the original description:</p>
+
+        <source>
+  Ant kurz &amp; gut enth&#xe4;lt eine vollst&#xe4;ndige Referenz der Built-in Tasks
+  und ihrer jeweiligen Attribute sowie kurze Beispiele f&#xfc;r ihre Verwendung.
+  Daneben bietet das Buch eine knappe Einf&#xfc;hrung in die Arbeit mit Ant und
+  eine Erl&#xe4;uterung der Ant-Basiselemente (Projekte, Properties, Targets und Tasks).
+  Behandelt werden au&#xdf;erdem grundlegende Konzepte wie Filesets, Patternsets und
+  Pfadstrukturen, das Schreiben eigener Tasks, die Aufruf-Syntax und Optional Tasks. </source>
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Stefan Edlich</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.amazon.de/exec/obidos/ASIN/3897212412/">http://www.amazon.de/exec/obidos/ASIN/3897212412/</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Java Tools for eXtreme Programming" isbn="047120708X">
+        <p>This book covers the following XP subjects:</p>
+            <ul>
+                <li>Automated unit and functional testing</li>
+                <li>Continuous integration through build and deployment automation</li>
+                <li>The value of refactoring and continuous integration</li>
+                <li>How Ant, JUnit, JUnitPerf, Cactus, HTTPUnit, and JMeter
+                can be used to achieve the goals of the XP methodology</li>
+            </ul>
+
+        <table class="externals">
+          <tr>
+            <th>Authors:</th>
+            <td>Richard Hightower and Nicholas Lesiecki</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.wiley.com/cda/product/0,,047120708X,00.html">http://www.wiley.com/cda/product/0,,047120708X,00.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+    </section>
+
+    <section name="Articles and Presentations">
+
+      <p>The following sections list articles and presentations
+      written about Apache Ant.  If you've written something that
+      should be included, please post it to one of the mailing
+      lists.</p>
+
+    </section>
+
+    <section name="Articles">
+
+       <subsection name="Extending Ant Input Abilities">
+         <p>The contents of this document is the following:<ul>
+           <li>Section 2 provides a simple example how InputHandlers are created,</li>
+           <li>Section 3 develops an inputhandler that masks the passwords typed on the command line,</li>
+           <li>Section 4 gives two handlers, whose input is typed in graphical components,</li>
+           <li>Section 5 extends Input task so that we can use dierent input handlers on different uses of &lt;input&gt;,</li>
+           <li>Section 6 describes a problem found while writing this document,</li>
+           <li>Section 7 summarizes some dark corners the author do not understand.</li>
+         </ul></p>
+
+         <table class="externals">
+           <tr>
+             <th>Author:</th>
+             <td>Ivan Ivanov</td>
+           </tr>
+           <tr>
+             <th>URL:</th>
+             <td><a href="https://sourceforge.net/project/showfiles.php?group_id=103509">https://sourceforge.net/project/showfiles.php?group_id=103509 (Download ZIP+PDF from Sourceforge)</a></td>
+           </tr>
+         </table>
+       </subsection>
+
+
+
+      <subsection name="Keep the Ant, Hold the XML">
+        <p>Key G. Gauthier talks about writing "buildfiles" in Java.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Key G. Gauthier</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.ftponline.com/javapro/2004_06/magazine/features/kgauthier/">http://www.ftponline.com/javapro/2004_06/magazine/features/kgauthier/</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant 1.6 for Task Writers">
+        <p>This article talks about XML namespace handling, Ant
+        libraries and the newly introduced type polymorphism.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Stefan Bodewig</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://otn.oracle.com/pub/articles/bodewig_taskwriters.html">http://otn.oracle.com/pub/articles/bodewig_taskwriters.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Managing Build Complexity with Apache Ant 1.6">
+
+        <p>As Apache Ant is applied to increasingly difficult tasks,
+        its users are creating more complex and less legible build
+        files. This is due, in part, to the limited tools for
+        decomposition and code reuse within previous versions of
+        Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Geoffrey Wiseman</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sys-con.com/story/?storyid=45078&amp;DE=1">http://www.sys-con.com/story/?storyid=45078&amp;DE=1</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="New Ant 1.6 Features for Big Projects">
+        <p>This article describes the &lt;macrodef&gt;, &lt;import&gt;
+          and &lt;subant&gt; tasks in detail and shows how they help in
+          building bigger systems.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Stefan Bodewig</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://otn.oracle.com/pub/articles/bodewig_ant1.6.html">http://otn.oracle.com/pub/articles/bodewig_ant1.6.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Programmieren für Ant">
+        <p>This article describes the main topics of programming your own tasks.
+        Description is done on five examples.</p>
+        <p>This article is written in German and published in
+        <a href="http://www.sigs-datacom.de/sd/publications/js/index.htm">Java-Spektrum</a>
+        5/2004.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Bernd Matzke</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sigs-datacom.de/sd/news/document?PID=216">http://www.sigs-datacom.de/sd/news/document?PID=216</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant in Anger: Using Ant in a Production Development System">
+        <p>This document describes strategies and some basic examples of how to
+        use Ant in larger team development projects.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Steve Loughran</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="ant_in_anger.html">http://ant.apache.org/ant_in_anger.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant Task Guidelines">
+        <p>This document describes how to write custom Ant tasks, and how to submit
+        them to potentially be included in Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Steve Loughran</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="ant_task_guidelines.html">http://ant.apache.org/ant_task_guidelines.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Build a Better Robot with Ant">
+        <p>This article describes the gory details of writing custom
+           Ant tasks.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Erik Hatcher</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.fawcette.com/javapro/2003_02/magazine/features/ehatcher/">http://www.fawcette.com/javapro/2003_02/magazine/features/ehatcher/l</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Automating the build and test process">
+        <p>This article demonstrates an approach to the automated build and test process. Working with Ant 1.3 and the JUnit test framework, it shows how to automate a process that captures pertinent information about each test suite run, generates an attractive report, and e-mails the report.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:ehatcher@apache.org">Erik Hatcher</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.ibm.com/developerworks/java/library/j-junitmail/">http://www.ibm.com/developerworks/java/library/j-junitmail/</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Incremental development with Ant and JUnit">
+        <p>This article explores the benefits of unit testing with Ant and
+        JUnit, detailing how to develop automated unit tests and integrate them
+        into your build process.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:malcolm@nuearth.com">Malcolm Davis</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www-106.ibm.com/developerworks/library/j-ant/?dwzone=java">http://www-106.ibm.com/developerworks/library/j-ant/?dwzone=java</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Automate your build process using Java and Ant">
+        <p>This article provides an introduction to using Ant with some basic
+        examples and by highlighting some of the important tasks.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:michael.cymerman@javaworld.com">Michael Cymerman</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.javaworld.com/javaworld/jw-10-2000/jw-1020-ant.html">http://www.javaworld.com/javaworld/jw-10-2000/jw-1020-ant.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Short tutorial in Cactus&apos; (formerly J2EEUnit)
+      documentation">
+        <p>There is a short tutorial on how to use Ant in Cactus&apos;
+        documentation.  It has a slant towards build files that will be used
+        with Cactus.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Cactus development team</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://jakarta.apache.org/cactus/howto_ant_primer.html">http://jakarta.apache.org/cactus/howto_ant_primer.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Developing custom Ant tasks with VisualAge for Java">
+        <p>This article outlines how to integrate Ant into VisualAge for Java,
+        and how to write and debug custom tasks using the IDE and the
+        integrated debugger.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:glenn@somanetworks.com">Glenn McAllister</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www7.software.ibm.com/vad.nsf/data/document2366?OpenDocument&amp;p=1&amp;BCT=1&amp;Footer=1">http://www7.software.ibm.com/vad.nsf/data/document2366?OpenDocument&amp;p=1&amp;BCT=1&amp;Footer=1</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Automated builds with VisualAge for Java and Ant">
+        <p>This article shows how you can perform command line builds with a
+        VisualAge for Java repository.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:glenn@somanetworks.com">Glenn McAllister</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www7.software.ibm.com/vad.nsf/Data/Document4366?OpenDocument&amp;p=1&amp;BCT=3&amp;Footer=1">http://www7.software.ibm.com/vad.nsf/Data/Document4366?OpenDocument&amp;p=1&amp;BCT=3&amp;Footer=1</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant: A Build Tool from the Jakarta Project">
+        <p>This article is from the &quot;Best Practices&quot; section of
+        Sun&apos;s Dot-Com Builder Site.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Laura Geele Wang</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://dcb.sun.com/practices/profiles/ant.jsp">http://dcb.sun.com/practices/profiles/ant.jsp</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Making a Mountain Out of an Anthill">
+        <p>This article is from the June 2001 issue of the Java Developer&apos;
+        Journal.  You need to be a registered JDJ subscriber to view this
+        article.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Neal Ford</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sys-con.com/java/archivesa.cfm?volume=06&amp;issue=06">http://www.sys-con.com/java/archivesa.cfm?volume=06&amp;issue=06</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Using Ant and Weblogic EJBs">
+        <p>This article describes how to use Ant to create Weblogic EJBs, and
+        some workarounds for issues you may encounter.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Jesse E. Tilly</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.onjava.com/pub/a/onjava/2001/06/25/antejb.html">http://www.onjava.com/pub/a/onjava/2001/06/25/antejb.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Using JavaScript with Ant">
+        <p>A tutorial about using JavaScript and XSLT with Ant.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Dylan Schiemann</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.sitepen.com/ant/javascript.html">http://www.sitepen.com/ant/javascript.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Building with Ant">
+        <p>Series of articles that describe a framework for web
+        application development based on Ant and JUnit.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:alexc@purpletech.com">Alex Chaffee</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td>Introduction: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12065_989631,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12065_989631,00.html</a><br/>
+                Directory Structure: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12082_994991,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12082_994991,00.html</a><br/>
+                Deployment and Distribution: <a href="http://softwaredev.earthweb.com/sdtech/article/0,,12077_998241,00.html">http://softwaredev.earthweb.com/sdtech/article/0,,12077_998241,00.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Developing with JAXB and Ant">
+        <p>Series of articles that shows how to use Ant together with
+        the Java API for XML Binding (JAXB).</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Joseph Shelby</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.onjava.com/pub/a/onjava/2002/03/06/jaxant1.html">http://www.onjava.com/pub/a/onjava/2002/03/06/jaxant1.html</a><br/>
+                <a href="http://www.onjava.com/pub/a/onjava/2002/03/13/jaxbant2.html">http://www.onjava.com/pub/a/onjava/2002/03/13/jaxbant2.html</a></td>
+          </tr>
+        </table>
+      </subsection>
+    </section>
+
+    <section name="Presentations">
+
+      <subsection name="Ant Build Tool">
+        <p>A PowerPoint presentation on Ant 1.2.  It provides a basic overview
+        of Ant&apos;s capabilities.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td><a href="mailto:chanezon@netscape.com">Patrick Chanezon</a></td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://people.netscape.com/chanezon/tech/ant/ant_preso.ppt">http://people.netscape.com/chanezon/tech/ant/ant_preso.ppt</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+      <subsection name="Ant">
+        <p>A detailed Ant 1.3 PowerPoint presentation, made at the St. Louis Java Users Group
+        meeting in March 2001.  Includes a detailed build file and basic
+        descriptions of all the built in and optional tasks.  Updated for Ant 1.4 in October 2001.
+        Available in PDF format now.</p>
+
+        <table class="externals">
+          <tr>
+            <th>Author:</th>
+            <td>Mark Volkmann</td>
+          </tr>
+          <tr>
+            <th>URL:</th>
+            <td><a href="http://www.ociweb.com/jnb/files/Ant.pdf">http://www.ociweb.com/jnb/files/Ant.pdf</a></td>
+          </tr>
+        </table>
+      </subsection>
+
+
+    </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/srcdownload.xml b/trunk/xdocs/srcdownload.xml
new file mode 100644
index 0000000..5d91795
--- /dev/null
+++ b/trunk/xdocs/srcdownload.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>Source Distributions</title>
+    <base/>
+  </properties>
+
+<body>
+
+<section name="Downloading Ant">
+
+<p>Use the links below to download a source distribution of Ant from
+one of our mirrors.  It is good practice to
+<a href="[location]#Verify Releases">verify the integrity</a>
+of the distribution files, especially if you are using one of our
+mirror sites.  In order to do this you must use the signatures from
+our <a href="http://www.apache.org/dist/ant/">main distribution
+directory</a>.</p>
+
+<p>Ant is distributed as <code>zip</code>, <code>tar.gz</code> and
+<code>tar.bz2</code> archives - the contents are the same.  Please
+note that the <code>tar.*</code> archives contain file names longer
+than 100 characters and have been created using GNU tar extensions.
+Thus they must be untarred with a GNU compatible version of
+<code>tar</code>.</p>
+
+<p>If you do not see the file you need in the links below, please see
+the <a href="http://www.apache.org/dist/ant/">master distribution
+directory</a> or, preferably, its <a href="[preferred]/ant/">mirror</a>.</p>
+
+</section>
+
+<section name="Mirror">
+
+<p>You are currently using <b>[preferred]</b>.  If you encounter a
+problem with this mirror, please select another mirror.  If all
+mirrors are failing, there are <i>backup</i> mirrors (at the end of
+the mirrors list) that should be available.</p>
+
+<form action="[location]" method="get" id="SelectMirror">
+Other mirrors: <select name="Preferred">
+[if-any http]
+  [for http]<option value="[http]">[http]</option>[end]
+[end]
+[if-any ftp]
+  [for ftp]<option value="[ftp]">[ftp]</option>[end]
+[end]
+[if-any backup]
+  [for backup]<option value="[backup]">[backup] (backup)</option>[end]
+[end]
+</select>
+<input type="submit" value="Change" />
+</form>
+</section>
+
+<section name="Current Release of Ant">
+
+<p>Currently, Apache Ant 1.7.0 is the best available version, see the
+<a href="[preferred]/ant/README.html">release notes</a>.</p>
+
+<div class="warning">
+<div class="label">Note</div>
+<div class="content">Ant 1.7.0 has been released on 19-Dec-2006 and
+may not be available on all mirrors for a few days.</div>
+</div>
+<br></br>
+<div class="warning">
+<div class="label">Tar files may require gnu tar to extract</div>
+<div class="content">Tar files in the distribution contain long file names, and may
+ require gnu tar to do the extraction.</div>
+</div>
+
+<ul>
+<li><code>.zip</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.zip">apache-ant-1.7.0-src.zip</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.zip.md5">MD5</a>]</li>
+
+<li><code>.tar.gz</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.tar.gz">apache-ant-1.7.0-src.tar.gz</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.gz.md5">MD5</a>]</li>
+
+<li><code>.tar.bz2</code> archive:
+<a href="[preferred]/ant/source/apache-ant-1.7.0-src.tar.bz2">apache-ant-1.7.0-src.tar.bz2</a>
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.asc">PGP</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.sha1">SHA1</a>]
+[<a href="http://www.apache.org/dist/ant/source/apache-ant-1.7.0-src.tar.bz2.md5">MD5</a>]</li>
+</ul>
+</section>
+
+
+<section name="Old Ant Releases">
+
+<p>Older releases of Ant can be found <a
+href="http://archive.apache.org/dist/ant/source/">here</a>.  Those
+releases are only provided as <code>zip</code> archives that can be
+extracted by <code>jar xf </code><em>archive.zip</em> - we highly
+recommend to not use those releases but upgrade to Ant's <a
+href="[location]#Current Release of Ant">latest</a> release.</p>
+
+</section>
+
+<section name="Verify Releases">
+
+<p>It is essential that you verify the integrity of the downloaded
+files using the PGP signature or the SHA1 or MD5 checksums.  The
+checksums are not as strong indicators as the PGP signature.</p>
+
+<p>The PGP signatures can be verified using PGP or GPG.  First
+download the <a href="http://www.apache.org/dist/ant/KEYS">KEYS</a>
+as well as the <code>asc</code> signature file for the particular
+distribution.  Make sure you get these files from the <a
+href="http://www.apache.org/dist/ant/">main distribution
+directory</a>, rather than from a mirror. Then verify the signatures
+using</p>
+
+<p><code>
+% pgpk -a KEYS<br />
+% pgpv apache-ant-1.7.0-src.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% pgp -ka KEYS<br />
+% pgp apache-ant-1.7.0-src.tar.gz.asc<br />
+</code>
+<em>or</em><br />
+<code>
+% gpg --import KEYS<br />
+% gpg --verify apache-ant-1.7.0-src.tar.gz.asc
+</code></p>
+
+<p>Alternatively, you can verify the checksums on the files.  Unix
+programs called <code>md5</code>/<code>sha1</code> or
+<code>md5sum</code>/<code>sha1sum</code> are included in many unix
+distributions.  <code>*sum</code> is also available as part of <a
+href="http://www.gnu.org/software/textutils/textutils.html">GNU
+Textutils</a>.  Windows users can get binary md5 programs from <a
+href="http://www.fourmilab.ch/md5/">here</a>, <a
+href="http://www.pc-tools.net/win32/freeware/console/">here</a>.  <a
+href="http://www.slavasoft.com/fsum/">fsum</a> supports MD5 and
+SHA1.</p>
+
+<p>We highly recommend to verify the PGP signature, though.</p>
+
+</section>
+
+</body>
+</document>
diff --git a/trunk/xdocs/stylesheets/project.xml b/trunk/xdocs/stylesheets/project.xml
new file mode 100644
index 0000000..d839eb7
--- /dev/null
+++ b/trunk/xdocs/stylesheets/project.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project name="Apache Ant" href="http://ant.apache.org/">
+
+    <title>Apache Ant</title>
+    <logo href="images/ant_logo_large.gif">Apache Ant</logo>
+
+    <body>
+       <menusection name="Home" index="0"         href="/index.html">
+            <menu name="Apache Ant">
+                <item name="Welcome"               href="/index.html"/>
+                <item name="License"               href="/license.html"/>
+                <item name="News"                  href="/antnews.html"/>
+            </menu>
+
+            <menu name="Documentation">
+                <item name="Manual"
+                      href="/manual/index.html"/>
+                <item name="Related Projects"
+                      href="/projects.html"/>
+                <item name="External Tools and Tasks"
+                      href="/external.html"/>
+                <item name="Resources"
+                      href="/resources.html"/>
+                <item name="Frequently Asked Questions"
+                      href="/faq.html"/>
+                <item name="Wiki"
+                      href="http://wiki.apache.org/ant/FrontPage"/>
+                <item name="Having Problems?"
+                      href="/problems.html"/>
+            </menu>
+
+            <menu name="Download">
+                <item name="Binary Distributions" href="http://ant.apache.org/bindownload.cgi"/>
+                <item name="Source Distributions" href="http://ant.apache.org/srcdownload.cgi"/>
+            </menu>
+
+            <menu name="Contributing">
+                <item name="Mailing Lists"         href="/mail.html"/>
+                <item name="Subversion Repositories"      href="/svn.html"/>
+                <item name="Nightly Builds"      href="/nightlies.html"/>
+                <item name="Bug Database"          href="/bugs.html"/>
+            </menu>
+
+            <menu name="Sponsorship">
+                <item name="Thanks"                href="http://www.apache.org/foundation/thanks.html"/>
+                <item name="Sponsorship"           href="http://www.apache.org/foundation/sponsorship.html"/>
+                <item name="Donations"             href="http://www.apache.org/foundation/contributing.html"/>
+            </menu>
+
+            <menu name="Project Management">
+                <item name="Contributors"          href="/contributors.html"/>
+                <item name="Apache Ant Mission"    href="/mission.html"/>
+                <item name="Project Bylaws"        href="/bylaws.html"/>
+                <item name="Legal"                 href="/legal.html"/>
+            </menu>
+        </menusection>
+
+        <menusection name="Projects" index="1"     href="/projects/index.html">
+            <menu name="Projects">
+                <item name="Welcome"               href="/projects/index.html"/>
+            </menu>
+            <menu name="Ant Libraries">
+                <item name="Introduction"          href="/antlibs/index.html"/>
+                <item name="Charter"               href="/antlibs/charter.html"/>
+                <item name="Ant Libraries"         href="/antlibs/proper.html"/>
+                <item name="Sandbox Ant Libraries" href="/antlibs/sandbox.html"/>
+                <item name="Binary Distributions" href="http://ant.apache.org/antlibs/bindownload.cgi"/>
+                <item name="Source Distributions" href="http://ant.apache.org/antlibs/srcdownload.cgi"/>
+            </menu>
+            <menu name="Ivy">
+                <item name="Introduction"         href="/projects/ivy.html"/>
+                <item name="Homepage"             href="http://ant.apache.org/ivy/"/>
+                <item name="Distributions"        href="http://ant.apache.org/ivy/download.cgi"/>
+                <item name="Wiki"                 href="http://wiki.apache.org/ivy/"/>
+            </menu>
+        </menusection>
+    </body>
+</project>
diff --git a/trunk/xdocs/stylesheets/site.vsl b/trunk/xdocs/stylesheets/site.vsl
new file mode 100644
index 0000000..3ba5523
--- /dev/null
+++ b/trunk/xdocs/stylesheets/site.vsl
@@ -0,0 +1,196 @@
+#*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *#
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+## Content Stylesheet for Site
+    ## Defined variables
+    #set ($lightbg = "#ffffff")
+    #set ($lightfg = "#ffffff")
+    #set ($darkfg = "#000000")
+    #set ($active = "#ffcc00")
+    #set ($blue4 = "#B2C4E0")
+    #set ($blue3 = "#294563")
+    #set ($blue2 = "#4C6C8F")
+    #set ($blue1 = "#CFDCED")
+    #set ($sourceborder = "#023264")
+    #set ($pound = "#" )
+    #set ($ssi = "include virtual=")
+    #set ($adsurl = "/ads/buttonbar.html")
+## start the processing
+#document()
+## end the processing
+
+## This is where the common page macro's live
+
+#macro ( isbn $isbn)
+<p><b>Available from:</b><br>
+    <a href="http://www.amazon.com/exec/obidos/tg/detail/-/$!isbn/apachesoftwar-20/" target="_blank">Amazon.com</a>
+  | <a href="http://service.bfast.com/bfast/click?bfmid=2181&amp;bfmtype=book&amp;sourceid=41462544&amp;bfpid=$!isbn" target="_blank">Barnes &amp; Noble</a>
+  | <a href="http://www.booksense.com/product/info.jsp?affiliateId=Apache&amp;isbn=$!isbn" target="_blank">Book Sense</a>
+  | <a href="http://www.powells.com/cgi-bin/biblio?isbn=$!isbn&amp;partner_id=29693" target="_blank">Powells.com</a>
+<br></p>
+#end
+
+#macro ( subsection $subsection)
+      <h4 class="subsection">
+        <a name="$escape.getText($subsection.getAttributeValue("name"))"></a>
+        $subsection.getAttributeValue("name")
+      </h4>
+      #foreach ( $items in $subsection.getChildren() )
+        #if ($items.getName().equals("img"))
+          #image ($items)
+        #elseif ($items.getName().equals("source"))
+          #source ($items)
+        #elseif ($items.getName().equals("table"))
+          #table ($items)
+        #elseif ($items.getName().equals("subsubsection"))
+          #subsubsection ($items)
+        #else
+          $xmlout.outputString($items)
+        #end
+      #end
+      #if ($subsection.getAttributeValue("isbn"))
+        #set ($isbn = $subsection.getAttributeValue("isbn"))
+        #isbn ($isbn)
+      #end
+#end
+
+#macro ( subsubsection $subsubsection)
+      <h5 class="subsection">
+        <a name="$escape.getText($subsubsection.getAttributeValue("name"))"></a>
+        *** $subsubsection.getAttributeValue("name") ***
+      </h5>
+      #foreach ( $items in $subsubsection.getChildren() )
+        #if ($items.getName().equals("img"))
+          #image ($items)
+        #elseif ($items.getName().equals("source"))
+          #source ($items)
+        #elseif ($items.getName().equals("table"))
+          #table ($items)
+        #else
+          $xmlout.outputString($items)
+        #end
+      #end
+#end
+
+#macro ( section $section)
+    <h3 class="section">
+      <a name="$escape.getText($section.getAttributeValue("name"))"></a>
+      $section.getAttributeValue("name")
+    </h3>
+      #foreach ( $items in $section.getChildren() )
+        #if ($items.getName().equals("img"))
+          #image ($items)
+        #elseif ($items.getName().equals("source"))
+          #source ($items)
+        #elseif ($items.getName().equals("table"))
+          #table ($items)
+        #elseif ($items.getName().equals("subsection"))
+          #subsection ($items)
+        #else
+          $xmlout.outputString($items)
+        #end
+      #end
+#end
+
+## This is where the FAQ specific macro's live
+
+#macro (toc $section)
+      <h4 class="toc">$section.getAttributeValue("title")</h4>
+        <ul>
+    #foreach ($faq in $section.getChildren("faq") )
+      #subtoc ($faq)
+    #end
+        </ul>
+#end
+
+#macro (subtoc $faq)
+  #set ($id = $faq.getAttributeValue("id"))
+      <li><a href="$pound$id">
+  $xmlout.outputString($faq.getChild("question"), true)
+      </a></li>
+#end
+
+#macro (answers $section)
+  #foreach ($faq in $section.getChildren("faq") )
+    #faq ($faq)
+  #end
+#end
+
+#macro (faq $faq)
+  #set ($id = $faq.getAttributeValue("id"))
+    <p class="faq">
+      <a name="$id"></a>
+      $xmlout.outputString($faq.getChild("question"), true)
+    </p>
+    #foreach ($item in $faq.getChild("answer").getChildren())
+      #if ($item.getName().equals("img"))
+        #image ($item)
+      #elseif ($item.getName().equals("source"))
+        #source ($item)
+      #elseif ($item.getName().equals("table"))
+        #table ($item)
+      #else
+        $xmlout.outputString($item)
+      #end
+    #end
+#end
+
+#macro (document)
+  #header()
+  <div class="main">
+  <div class="content">
+    <h1 class="title">$root.getChild("properties").getChild("title").getText()</h1>
+  #set ($allSections = $root.getChild("body").getChildren("section"))
+  #foreach ( $section in $allSections )
+    #section ($section)
+  #end
+
+  #if ($root.getChildren("faqsection").size() > 0)
+    #set ($allFaqSections = $root.getChildren("faqsection"))
+      <h3 class="section">Questions</h3>
+    #foreach ( $faqSection in $allFaqSections )
+      #toc ($faqSection)
+    #end
+
+      <h3 class="section">Answers</h3>
+    #foreach ( $faqSection in $allFaqSections )
+      #answers ($faqSection)
+    #end
+  #end
+  </div>
+  </div>
+
+  #footer()
+#end
diff --git a/trunk/xdocs/stylesheets/templates.vm b/trunk/xdocs/stylesheets/templates.vm
new file mode 100644
index 0000000..ac3e03b
--- /dev/null
+++ b/trunk/xdocs/stylesheets/templates.vm
@@ -0,0 +1,295 @@
+#*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *#
+
+## This is where the common macro's live
+
+#macro ( table $table)
+  #if ($table.getAttributeValue("class"))
+    #set ($class = $table.getAttributeValue("class"))
+  #else
+    #set ($class = "ForrestTable")
+  #end
+  <table class="$!class" cellspacing="1" cellpadding="4">
+  #foreach ( $items in $table.getChildren() )
+    #if ($items.getName().equals("tr"))
+      #tr ($items)
+    #end
+  #end
+  #if ($table.getParent().getAttributeValue("isbn"))
+    #set ($isbn = $table.getParent().getAttributeValue("isbn"))
+    <tr><th>ISBN:</th><td>$!isbn</td></tr>
+  #end
+  </table>
+#end
+
+#macro ( tr $tr)
+  <tr>
+  #foreach ( $items in $tr.getChildren() )
+    #if ($items.getName().equals("td"))
+      #td ($items)
+    #elseif ($items.getName().equals("th"))
+      #th ($items)
+    #end
+  #end
+</tr>
+#end
+
+#macro ( td $value)
+  #if ($value.getAttributeValue("colspan"))
+    #set ($colspan = $value.getAttributeValue("colspan"))
+  #else
+    #set ($colspan = 1)
+  #end
+  #if ($value.getAttributeValue("rowspan"))
+    #set ($rowspan = $value.getAttributeValue("rowspan"))
+  #else
+    #set ($rowspan = 1)
+  #end
+  <td colspan="$!colspan" rowspan="$!rowspan"
+      valign="top" align="left">
+    #if ($value.getText().length() != 0 || $value.hasChildren())
+      $xmlout.outputString($value, true)
+    #else
+      &nbsp;
+    #end
+  </td>
+#end
+
+#macro ( th $value)
+  #if ($value.getAttributeValue("colspan"))
+    #set ($colspan = $value.getAttributeValue("colspan"))
+  #else
+    #set ($colspan = 1)
+  #end
+  #if ($value.getAttributeValue("rowspan"))
+    #set ($rowspan = $value.getAttributeValue("rowspan"))
+  #else
+    #set ($rowspan = 1)
+  #end
+  <th colspan="$!colspan" rowspan="$!rowspan"
+      valign="top" align="left">
+    #if ($value.getText().length() != 0 || $value.hasChildren())
+      $xmlout.outputString($value, true)
+    #else
+      &nbsp;
+    #end
+  </th>
+#end
+
+#macro ( projectanchor $name $value )
+  #if ($value.startsWith("http://"))
+    <a href="$value">$name</a>
+  #elseif ($value.startsWith("/site"))
+    <a href="http://jakarta.apache.org$value">$name</a>
+  #else
+    <a href="$relativePath$value">$name</a>
+  #end
+#end
+
+#macro ( metaauthor $author $email )
+  <meta name="author" content="$author">
+  <meta name="email" content="$email">
+#end
+
+#macro ( image $value )
+  #if ($value.getAttributeValue("width"))
+    #set ($width=$value.getAttributeValue("width"))
+  #end
+  #if ($value.getAttributeValue("height"))
+    #set ($height=$value.getAttributeValue("height"))
+  #end
+  #if ($value.getAttributeValue("align"))
+    #set ($align=$value.getAttributeValue("align"))
+  #end
+  #if ($value.getAttributeValue("alt"))
+    #set ($align=$value.getAttributeValue("alt"))
+  #end
+  <img src="$relativePath$value.getAttributeValue("src")"
+       width="$!width" height="$!height" align="$!align" alt="$!alt">
+#end
+
+#macro ( source $value)
+<pre class="code">$escape.getText($value.getText())</pre>
+#end
+
+#macro ( makeTabs )
+            <div class="tab">
+              <table summary="tab bar" border="0" cellpadding="0" cellspacing="0">
+                <tr>
+  #set ( $tabs = $project.getChild("body").getChildren("menusection"))
+  #if ( $project.getChild("body").getChild("menusection") )
+    #foreach ( $tab in $tabs )
+      #set ($currentIndex = $root.getChild("properties").getChild("index").getAttributeValue("value") )
+      #set ($index = $tab.getAttributeValue("index"))
+      #set ($name = $tab.getAttributeValue("name"))
+      #set ($link = $tab.getAttributeValue("href"))
+      #if ( ($currentIndex && $currentIndex.trim().equals( $index )) || ((!$currentIndex) && $velocityCount == 1) )
+                    <td width="8"><img alt="" height="5" width="8" src="$relativePath/images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="$blue2"><img height="5" width="5" alt="" src="$relativePath/images/tabSel-left.gif"></td><td valign="middle" bgcolor="$blue2"><font color="$lightfg" size="2" face="Arial, Helvetica, Sans-serif"><b>$name</b></font></td><td valign="top" width="5" bgcolor="$blue2"><img height="5" width="5" alt="" src="$relativePath/images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+      #else
+                    <td width="5"><img alt="" height="8" width="8" src="$relativePath/images/spacer.gif"></td><td valign="bottom">
+                      <table summary="non selected tab" style="height: 1.4em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                          <td valign="top" width="5" bgcolor="$blue4"><img height="5" width="5" alt="" src="$relativePath/images/tab-left.gif"></td><td valign="middle" bgcolor="$blue4"><a href="$relativePath$link"><font size="2" face="Arial, Helvetica, Sans-serif">$name</font></a></td><td valign="top" width="5" bgcolor="$blue4"><img height="5" width="5" alt="" src="$relativePath/images/tab-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+      #end
+    #end
+  #else
+                    <td width="8"><img alt="" height="5" width="8" src="$relativePath/images/spacer.gif"></td><td valign="bottom">
+                      <table summary="selected tab" style="height: 1.5em" border="0" cellpadding="0" cellspacing="0">
+                        <tr>
+                        <td valign="top" width="5" bgcolor="$blue2"><img height="5" width="5" alt="" src="$relativePath/images/tabSel-left.gif"></td><td valign="middle" bgcolor="$blue2"><font color="$lightfg" size="2" face="Arial, Helvetica, Sans-serif"><b>Home</b></font></td><td valign="top" width="5" bgcolor="$blue2"><img height="5" width="5" alt="" src="$relativePath/images/tabSel-right.gif"></td>
+                        </tr>
+                      </table>
+                    </td>
+  #end
+                </tr>
+              </table>
+            </div>
+#end
+
+
+#macro ( makeMainNavigation )
+  #set ( $tabs = $project.getChild("body").getChildren("menusection"))
+  #if ( $project.getChild("body").getChild("menusection") )
+    #set ( $currentIndex = $root.getChild("properties").getChild("index").getAttributeValue("value") )
+    #if ( $currentIndex )
+      #foreach ( $tab in $tabs )
+        #set ($index = $tab.getAttributeValue("index"))
+        #if ( $currentIndex.trim().equals( $index ) )
+          #set ($menus = $tab.getChildren("menu"))
+        #end
+      #end
+    #else
+      #set ($menus = $project.getChild("body").getChild("menusection").getChildren("menu"))
+    #end
+  #else
+    #set ($menus = $project.getChild("body").getChildren("menu"))
+  #end
+  #makeProject ( $menus )
+#end
+
+#macro (makeProject $menus)
+
+  <div class="menucontainer">
+    <div class="menu">
+      <ul>
+      #foreach ( $menu in $menus )
+        <li class="menuheader">$menu.getAttributeValue("name")
+          <ul>
+            #foreach ( $item in $menu.getChildren() )
+              #set ($name = $item.getAttributeValue("name"))
+              #set ($current = $root.getChild("properties").getChild("title").getText() )
+                <li>
+              #if ( $current.trim().equals( $name ) )
+                <span class="sel">$name</span>
+              #else
+                #projectanchor($name $item.getAttributeValue("href"))
+              #end
+                </li>
+            #end
+          </ul>
+        </li>
+      #end
+      </ul>
+    </div>
+    <center>
+    <!--$pound$ssi"$adsurl" -->
+    </center>
+    <img style="float: left" height="10" width="10" border="0" alt="" src="$relativePath/images/menu-left.gif">
+    <img style="float: right" height="10" width="10" border="0" alt="" src="$relativePath/images/menu-right.gif">
+  </div>
+#end
+
+#macro (header)
+  <html lang="en">
+    <!-- GENERATED FILE, DO NOT EDIT, EDIT THE XML FILE IN xdocs INSTEAD! -->
+    <head>
+      <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+        <title>$project.getChild("title").getText() - $root.getChild("properties").getChild("title").getText()</title>
+        <link type="text/css" href="$relativePath/page.css" rel="stylesheet">
+  #set ($authors = $root.getChild("properties").getChildren("author"))
+  #foreach ( $au in $authors )
+    #metaauthor ( $au.getText() $au.getAttributeValue("email") )
+  #end
+    </head>
+
+    <body>
+      <p class="navpath">
+        <script src="$relativePath/breadcrumbs.js" language="JavaScript" type="text/javascript"></script>
+      </p>
+
+      <div class="logobar">
+        <table width="100%" border="0" cellspacing="0" cellpadding="0">
+          <tr>
+            <td align="left"><img border="0" alt="Apache Ant site" src="$relativePath/images/group-logo.gif"></td>
+            <td align="center" width="100%"><img alt="Apache Ant logo" border="0" src="$relativePath/images/project-logo.gif"></td>
+            <td align="right">
+              <form target="_blank" onsubmit="q.value = query.value + ' site:ant.apache.org'" action="http://www.google.com/search" method="get">
+                <table summary="search" border="0" cellspacing="0" cellpadding="0" bgcolor="$blue2">
+                  <tr>
+                    <td colspan="3"><img height="10" width="1" alt="" src="$relativePath/images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img height="1" width="1" alt="" src="$relativePath/images/spacer.gif"></td>
+                    <td nowrap="nowrap" class="searchcaption">
+                      <input name="q" type="hidden">
+                      <input size="15" id="query" type="text">
+                      <img height="1" width="5" alt="" src="$relativePath/images/spacer.gif">
+                      <input name="Search" value="Search" type="submit">
+                      <br>
+                      the Apache Ant site
+                    </td>
+                    <td><img height="1" width="1" alt="" src="$relativePath/images/spacer.gif"></td>
+                  </tr>
+                  <tr>
+                    <td><img alt="" border="0" height="10" width="9" src="$relativePath/images/search-left.gif"></td>
+                    <td><img height="1" width="1" alt="" src="$relativePath/images/spacer.gif"></td>
+                    <td><img alt="" border="0" height="10" width="9" src="$relativePath/images/search-right.gif"></td>
+                  </tr>
+                </table>
+              </form>
+            </td>
+          </tr>
+        </table>
+      </div>
+
+      #makeTabs()
+
+      <div class="bluebar"></div>
+      #makeMainNavigation()
+      <div class="lightbluebar">&nbsp;</div>
+#end
+
+#macro (footer)
+      <p class="copyright">
+        <script type="text/javascript" language="JavaScript"><!--
+                document.write(" - "+"Last Published: " + document.lastModified);
+              //  -->
+        </script>
+      </p>
+    </body>
+  </html>
+#end
diff --git a/trunk/xdocs/svn.xml b/trunk/xdocs/svn.xml
new file mode 100644
index 0000000..9af75b4
--- /dev/null
+++ b/trunk/xdocs/svn.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!--
+     Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<document>
+
+  <properties>
+    <title>SVN Repositories</title>
+    <author email="">Antoine Levy-Lambert</author>
+  </properties>
+
+<body>
+
+    <section name="Access the Source Tree (Subversion)">
+
+      <p>Anyone can checkout source code from our public Subversion repository. To do so,
+         simply use the following command (if you are using a GUI client, configure it
+         appropriately):</p>
+
+      <source>
+svn co http://svn.apache.org/repos/asf/ant/[project]/trunk/ ant-[project]</source>
+
+      <p>Modules available for access are:</p>
+
+      <ul>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/core/trunk/">ant</a> - The &quot;main&quot; Ant module.<br/>
+         http://svn.apache.org/repos/asf/ant/core/trunk/
+        </li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/antunit/trunk/">antunit</a> Test framework for Ant.<br/>
+            http://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/dotnet/trunk/">Dotnet antlib</a> Contains Nant, Nunit, ...<br/>
+            http://svn.apache.org/repos/asf/ant/antlibs/dotnet/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/antlibs/svn/trunk/">svn antlib</a> Contains tasks to interact with Subversion repositories.<br/>
+            http://svn.apache.org/repos/asf/ant/antlibs/svn/trunk/</li>
+        <li><a href="http://svn.apache.org/viewcvs.cgi/ant/sandbox/">sandbox</a> - New developments. Contains currently gendoc.<br/>
+            http://svn.apache.org/repos/asf/ant/sandbox/
+        </li>
+      </ul>
+
+      <p>If you are not familiar with Subversion, <a
+      href="http://jakarta.apache.org/site/cvsindex.html">Jakarta's
+      source repositories page</a> may hold many helpful hints.</p>
+
+      <p>Nightly snapshots of the SVN tree are available at
+        <a href="http://svn.apache.org/snapshots/ant/">http://svn.apache.org/snapshots/ant/</a>.</p>
+
+      <p>A nice view of the source history is available through
+      <a href="http://fisheye3.cenqua.com/browse/ant/">Cenqua's Fisheye instance</a>.</p>
+         
+
+  </section>
+  </body>
+</document>
diff --git a/trunk/xdocs/velocity.properties b/trunk/xdocs/velocity.properties
new file mode 100644
index 0000000..da7924d
--- /dev/null
+++ b/trunk/xdocs/velocity.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+file.resource.loader.path=xdocs/stylesheets
+velocimacro.library=templates.vm